[rhq] 4 commits - modules/enterprise
by mike thompson
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/Table.java | 30
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/AbstractD3GraphListView.java | 8
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/graph/AbstractMetricGraph.java | 2
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/graph/ButtonBarDateTimeRangeEditor.java | 6
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/graph/RedrawGraphs.java | 29
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/graph/Refreshable.java | 30
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/detail/D3GroupGraphListView.java | 2
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/detail/monitoring/table/CompositeGroupD3GraphListView.java | 6
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/detail/monitoring/table/GroupMeasurementTableView.java | 58
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/D3GraphListView.java | 2
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/MetricD3Graph.java | 8
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/table/MetricsResourceView.java | 2
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/table/MetricsTableView.java | 12
modules/enterprise/gui/coregui/src/main/webapp/CoreGUI.html | 23
modules/enterprise/gui/coregui/src/main/webapp/js/jquery-1.9.1.js | 9597 ----------
modules/enterprise/gui/coregui/src/main/webapp/js/jquery-1.9.1.min.js | 5
modules/enterprise/gui/coregui/src/main/webapp/js/rhq.js | 20
17 files changed, 170 insertions(+), 9670 deletions(-)
New commits:
commit 90eb9a6955114a062f36f78b19e3564d479c4fa8
Merge: fdd7821 1ad43fd
Author: Mike Thompson <mithomps(a)redhat.com>
Date: Thu Aug 8 15:15:07 2013 -0700
Merge branch 'mtho11/pre4.9'
commit fdd78210fe1675588c8e57bf7580f056a7cd581b
Author: Mike Thompson <mithomps(a)redhat.com>
Date: Thu Aug 8 10:47:22 2013 -0700
IE UI fixes
diff --git a/modules/enterprise/gui/coregui/src/main/webapp/CoreGUI.html b/modules/enterprise/gui/coregui/src/main/webapp/CoreGUI.html
index 96e50de..32c5789 100644
--- a/modules/enterprise/gui/coregui/src/main/webapp/CoreGUI.html
+++ b/modules/enterprise/gui/coregui/src/main/webapp/CoreGUI.html
@@ -27,6 +27,29 @@
}
</script>
+ <script type="text/javascript">
+ (function() {
+ var method;
+ var noop = function () {};
+ var methods = [
+ 'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error',
+ 'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log',
+ 'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd',
+ 'timeStamp', 'trace', 'warn'
+ ];
+ var length = methods.length;
+ var console = (window.console = window.console || {});
+
+ while (length--) {
+ method = methods[length];
+
+ // Only stub undefined methods.
+ if (!console[method]) {
+ console[method] = noop;
+ }
+ }
+ }());
+ </script>
<title>RHQ</title>
<link rel="icon" type="image/png" href="/images/favicon.png" />
diff --git a/modules/enterprise/gui/coregui/src/main/webapp/js/jquery-1.9.1.js b/modules/enterprise/gui/coregui/src/main/webapp/js/jquery-1.9.1.js
deleted file mode 100644
index bc8f36a..0000000
--- a/modules/enterprise/gui/coregui/src/main/webapp/js/jquery-1.9.1.js
+++ /dev/null
@@ -1,9597 +0,0 @@
-/*!
- * jQuery JavaScript Library v1.9.1
- * http://jquery.com/
- *
- * Includes Sizzle.js
- * http://sizzlejs.com/
- *
- * Copyright 2005, 2012 jQuery Foundation, Inc. and other contributors
- * Released under the MIT license
- * http://jquery.org/license
- *
- * Date: 2013-2-4
- */
-(function( window, undefined ) {
-
-// 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+
-//"use strict";
- var
- // The deferred used on DOM ready
- readyList,
-
- // A central reference to the root jQuery(document)
- rootjQuery,
-
- // Support: IE<9
- // For `typeof node.method` instead of `node.method !== undefined`
- core_strundefined = typeof undefined,
-
- // Use the correct document accordingly with window argument (sandbox)
- document = window.document,
- location = window.location,
-
- // Map over jQuery in case of overwrite
- _jQuery = window.jQuery,
-
- // Map over the $ in case of overwrite
- _$ = window.$,
-
- // [[Class]] -> type pairs
- class2type = {},
-
- // List of deleted data cache ids, so we can reuse them
- core_deletedIds = [],
-
- core_version = "1.9.1",
-
- // Save a reference to some core methods
- core_concat = core_deletedIds.concat,
- core_push = core_deletedIds.push,
- core_slice = core_deletedIds.slice,
- core_indexOf = core_deletedIds.indexOf,
- core_toString = class2type.toString,
- core_hasOwn = class2type.hasOwnProperty,
- core_trim = core_version.trim,
-
- // Define a local copy of jQuery
- jQuery = function( selector, context ) {
- // The jQuery object is actually just the init constructor 'enhanced'
- return new jQuery.fn.init( selector, context, rootjQuery );
- },
-
- // Used for matching numbers
- core_pnum = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,
-
- // Used for splitting on whitespace
- core_rnotwhite = /\S+/g,
-
- // Make sure we trim BOM and NBSP (here's looking at you, Safari 5.0 and IE)
- rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
-
- // 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 = /^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/,
-
- // Match a standalone tag
- rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/,
-
- // JSON RegExp
- rvalidchars = /^[\],:{}\s]*$/,
- rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
- rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,
- rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/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();
- },
-
- // The ready event handler
- completed = function( event ) {
-
- // 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();
- }
- },
- // Clean-up method for dom ready events
- detach = function() {
- if ( document.addEventListener ) {
- document.removeEventListener( "DOMContentLoaded", completed, false );
- window.removeEventListener( "load", completed, false );
-
- } else {
- document.detachEvent( "onreadystatechange", completed );
- window.detachEvent( "onload", completed );
- }
- };
-
- jQuery.fn = jQuery.prototype = {
- // The current version of jQuery being used
- jquery: core_version,
-
- constructor: jQuery,
- init: function( selector, context, rootjQuery ) {
- 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
- 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 rootjQuery.ready( selector );
- }
-
- if ( selector.selector !== undefined ) {
- this.selector = selector.selector;
- this.context = selector.context;
- }
-
- return jQuery.makeArray( selector, this );
- },
-
- // Start with an empty selector
- selector: "",
-
- // The default length of a jQuery object is 0
- length: 0,
-
- // The number of elements contained in the matched element set
- size: function() {
- return this.length;
- },
-
- toArray: function() {
- return core_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 a 'clean' array
- this.toArray() :
-
- // Return just the object
- ( num < 0 ? this[ this.length + num ] : this[ num ] );
- },
-
- // 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 );
- },
-
- ready: function( fn ) {
- // Add the callback
- jQuery.ready.promise().done( fn );
-
- return this;
- },
-
- slice: function() {
- return this.pushStack( core_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] ] : [] );
- },
-
- map: function( callback ) {
- return this.pushStack( jQuery.map(this, function( elem, i ) {
- return callback.call( elem, i, elem );
- }));
- },
-
- end: function() {
- return this.prevObject || this.constructor(null);
- },
-
- // For internal use only.
- // Behaves like an Array's method, not like a jQuery method.
- push: core_push,
- sort: [].sort,
- splice: [].splice
- };
-
-// Give the init function the jQuery prototype for later instantiation
- jQuery.fn.init.prototype = jQuery.fn;
-
- 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;
- 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" && !jQuery.isFunction(target) ) {
- target = {};
- }
-
- // extend jQuery itself if only one argument is passed
- if ( length === i ) {
- 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({
- noConflict: function( deep ) {
- if ( window.$ === jQuery ) {
- window.$ = _$;
- }
-
- if ( deep && window.jQuery === jQuery ) {
- window.jQuery = _jQuery;
- }
-
- return jQuery;
- },
-
- // 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.trigger ) {
- jQuery( document ).trigger("ready").off("ready");
- }
- },
-
- // 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 ) {
- return obj != null && obj == obj.window;
- },
-
- isNumeric: function( obj ) {
- return !isNaN( parseFloat(obj) ) && isFinite( obj );
- },
-
- type: function( obj ) {
- if ( obj == null ) {
- return String( obj );
- }
- return typeof obj === "object" || typeof obj === "function" ?
- class2type[ core_toString.call(obj) ] || "object" :
- typeof obj;
- },
-
- isPlainObject: function( obj ) {
- // 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 &&
- !core_hasOwn.call(obj, "constructor") &&
- !core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
- return false;
- }
- } catch ( e ) {
- // IE8,9 Will throw exceptions on certain host objects #9897
- return false;
- }
-
- // Own properties are enumerated firstly, so to speed up,
- // if last one is own, then all properties are own.
-
- var key;
- for ( key in obj ) {}
-
- return key === undefined || core_hasOwn.call( obj, key );
- },
-
- isEmptyObject: function( obj ) {
- var name;
- for ( name in obj ) {
- return false;
- }
- return true;
- },
-
- error: function( msg ) {
- throw new Error( msg );
- },
-
- // 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
- 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 ) {
- jQuery( scripts ).remove();
- }
- return jQuery.merge( [], parsed.childNodes );
- },
-
- parseJSON: function( data ) {
- // Attempt to parse using the native JSON parser first
- if ( window.JSON && window.JSON.parse ) {
- return window.JSON.parse( data );
- }
-
- if ( data === null ) {
- return data;
- }
-
- if ( typeof data === "string" ) {
-
- // Make sure leading/trailing whitespace is removed (IE can't handle it)
- data = jQuery.trim( data );
-
- if ( data ) {
- // Make sure the incoming data is actual JSON
- // Logic borrowed from http://json.org/json2.js
- if ( rvalidchars.test( data.replace( rvalidescape, "@" )
- .replace( rvalidtokens, "]" )
- .replace( rvalidbraces, "")) ) {
-
- return ( new Function( "return " + data ) )();
- }
- }
- }
-
- jQuery.error( "Invalid JSON: " + data );
- },
-
- // Cross-browser xml parsing
- 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;
- },
-
- noop: function() {},
-
- // 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-...
- 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;
- },
-
- // Use native String.trim function wherever possible
- trim: core_trim && !core_trim.call("\uFEFF\xA0") ?
- function( text ) {
- return text == null ?
- "" :
- core_trim.call( text );
- } :
-
- // Otherwise use our own trimming functionality
- 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 {
- core_push.call( ret, arr );
- }
- }
-
- return ret;
- },
-
- inArray: function( elem, arr, i ) {
- var len;
-
- if ( arr ) {
- if ( core_indexOf ) {
- return core_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 l = second.length,
- i = first.length,
- j = 0;
-
- if ( typeof l === "number" ) {
- for ( ; j < l; j++ ) {
- first[ i++ ] = second[ j ];
- }
- } else {
- while ( second[j] !== undefined ) {
- first[ i++ ] = second[ j++ ];
- }
- }
-
- first.length = i;
-
- return first;
- },
-
- grep: function( elems, callback, inv ) {
- var retVal,
- ret = [],
- i = 0,
- length = elems.length;
- inv = !!inv;
-
- // Go through the array, only saving the items
- // that pass the validator function
- for ( ; i < length; i++ ) {
- retVal = !!callback( elems[ i ], i );
- if ( inv !== retVal ) {
- ret.push( elems[ i ] );
- }
- }
-
- return ret;
- },
-
- // 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
- if ( isArray ) {
- for ( ; i < length; i++ ) {
- value = callback( elems[ i ], i, arg );
-
- if ( value != null ) {
- ret[ ret.length ] = value;
- }
- }
-
- // Go through every key on the object,
- } else {
- for ( i in elems ) {
- value = callback( elems[ i ], i, arg );
-
- if ( value != null ) {
- ret[ ret.length ] = value;
- }
- }
- }
-
- // Flatten any nested arrays
- return core_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 = core_slice.call( arguments, 2 );
- proxy = function() {
- return fn.apply( context || this, args.concat( core_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;
- },
-
- // Multifunctional method to get and set values of a collection
- // The value/s can optionally be executed if it's a function
- 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;
- },
-
- now: function() {
- return ( new Date() ).getTime();
- }
- });
-
- 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 );
- };
-
-// 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 ( jQuery.isWindow( obj ) ) {
- return false;
- }
-
- if ( obj.nodeType === 1 && length ) {
- return true;
- }
-
- return type === "array" || type !== "function" &&
- ( length === 0 ||
- typeof length === "number" && length > 0 && ( length - 1 ) in obj );
- }
-
-// All jQuery objects should point back to these
- rootjQuery = jQuery(document);
-// 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( core_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 = [];
- 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 ) {
- args = args || [];
- args = [ context, args.slice ? args.slice() : args ];
- if ( list && ( !fired || stack ) ) {
- 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 action = tuple[ 0 ],
- 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[ action + "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 = core_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 ? core_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();
- }
- });
- jQuery.support = (function() {
-
- var support, all, a,
- input, select, fragment,
- opt, eventName, isSupported, i,
- div = document.createElement("div");
-
- // Setup
- div.setAttribute( "className", "t" );
- div.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
-
- // Support tests won't run in some limited or non-browser environments
- all = div.getElementsByTagName("*");
- a = div.getElementsByTagName("a")[ 0 ];
- if ( !all || !a || !all.length ) {
- return {};
- }
-
- // First batch of tests
- select = document.createElement("select");
- opt = select.appendChild( document.createElement("option") );
- input = div.getElementsByTagName("input")[ 0 ];
-
- a.style.cssText = "top:1px;float:left;opacity:.5";
- support = {
- // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
- getSetAttribute: div.className !== "t",
-
- // IE strips leading whitespace when .innerHTML is used
- leadingWhitespace: div.firstChild.nodeType === 3,
-
- // Make sure that tbody elements aren't automatically inserted
- // IE will insert them into empty tables
- tbody: !div.getElementsByTagName("tbody").length,
-
- // Make sure that link elements get serialized correctly by innerHTML
- // This requires a wrapper element in IE
- htmlSerialize: !!div.getElementsByTagName("link").length,
-
- // Get the style information from getAttribute
- // (IE uses .cssText instead)
- style: /top/.test( a.getAttribute("style") ),
-
- // Make sure that URLs aren't manipulated
- // (IE normalizes it by default)
- hrefNormalized: a.getAttribute("href") === "/a",
-
- // Make sure that element opacity exists
- // (IE uses filter instead)
- // Use a regex to work around a WebKit issue. See #5145
- opacity: /^0.5/.test( a.style.opacity ),
-
- // Verify style float existence
- // (IE uses styleFloat instead of cssFloat)
- cssFloat: !!a.style.cssFloat,
-
- // Check the default checkbox/radio value ("" on WebKit; "on" elsewhere)
- 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)
- optSelected: opt.selected,
-
- // Tests for enctype support on a form (#6743)
- enctype: !!document.createElement("form").enctype,
-
- // Makes sure cloning an html5 element does not cause problems
- // Where outerHTML is undefined, this still works
- html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav></:nav>",
-
- // jQuery.support.boxModel DEPRECATED in 1.8 since we don't support Quirks Mode
- boxModel: document.compatMode === "CSS1Compat",
-
- // Will be defined later
- deleteExpando: true,
- noCloneEvent: true,
- inlineBlockNeedsLayout: false,
- shrinkWrapBlocks: false,
- reliableMarginRight: true,
- boxSizingReliable: true,
- pixelPosition: false
- };
-
- // Make sure checked status is properly cloned
- input.checked = true;
- support.noCloneChecked = input.cloneNode( true ).checked;
-
- // 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: IE<9
- try {
- delete div.test;
- } catch( e ) {
- support.deleteExpando = false;
- }
-
- // 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";
-
- // #11217 - WebKit loses check when the name is after the checked attribute
- input.setAttribute( "checked", "t" );
- input.setAttribute( "name", "t" );
-
- fragment = document.createDocumentFragment();
- fragment.appendChild( input );
-
- // Check if a disconnected checkbox will retain its checked
- // value of true after appended to the DOM (IE6/7)
- support.appendChecked = input.checked;
-
- // WebKit doesn't clone checked state correctly in fragments
- support.checkClone = fragment.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()
- if ( div.attachEvent ) {
- div.attachEvent( "onclick", function() {
- support.noCloneEvent = false;
- });
-
- div.cloneNode( true ).click();
- }
-
- // Support: IE<9 (lack submit/change bubble), Firefox 17+ (lack focusin event)
- // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP), test/csp.php
- for ( i in { submit: true, change: true, focusin: true }) {
- div.setAttribute( eventName = "on" + i, "t" );
-
- support[ i + "Bubbles" ] = eventName in window || div.attributes[ eventName ].expando === false;
- }
-
- div.style.backgroundClip = "content-box";
- div.cloneNode( true ).style.backgroundClip = "";
- support.clearCloneStyle = div.style.backgroundClip === "content-box";
-
- // Run tests that need a body at doc ready
- jQuery(function() {
- var container, marginDiv, tds,
- divReset = "padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",
- body = document.getElementsByTagName("body")[0];
-
- if ( !body ) {
- // Return for frameset docs that don't have a body
- return;
- }
-
- container = document.createElement("div");
- container.style.cssText = "border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px";
-
- body.appendChild( container ).appendChild( div );
-
- // 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>";
- tds = div.getElementsByTagName("td");
- tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none";
- isSupported = ( tds[ 0 ].offsetHeight === 0 );
-
- tds[ 0 ].style.display = "";
- tds[ 1 ].style.display = "none";
-
- // Support: IE8
- // Check if empty table cells still have offsetWidth/Height
- support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
-
- // Check box-sizing and margin behavior
- div.innerHTML = "";
- div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;";
- support.boxSizing = ( div.offsetWidth === 4 );
- support.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== 1 );
-
- // Use window.getComputedStyle because jsdom on node.js will break without it.
- if ( window.getComputedStyle ) {
- support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%";
- support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px";
-
- // Check if div with explicit width and no margin-right incorrectly
- // gets computed margin-right based on width of container. (#3333)
- // Fails in WebKit before Feb 2011 nightlies
- // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
- marginDiv = div.appendChild( document.createElement("div") );
- marginDiv.style.cssText = div.style.cssText = divReset;
- marginDiv.style.marginRight = marginDiv.style.width = "0";
- div.style.width = "1px";
-
- support.reliableMarginRight =
- !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight );
- }
-
- if ( typeof div.style.zoom !== core_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.innerHTML = "";
- div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1";
- support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 );
-
- // Support: IE6
- // Check if elements with layout shrink-wrap their children
- div.style.display = "block";
- div.innerHTML = "<div></div>";
- div.firstChild.style.width = "5px";
- support.shrinkWrapBlocks = ( div.offsetWidth !== 3 );
-
- if ( support.inlineBlockNeedsLayout ) {
- // 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 );
-
- // Null elements to avoid leaks in IE
- container = div = tds = marginDiv = null;
- });
-
- // Null elements to avoid leaks in IE
- all = select = fragment = opt = a = input = null;
-
- return support;
- })();
-
- var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/,
- rmultiDash = /([A-Z])/g;
-
- function internalData( elem, name, data, pvt /* Internal Use Only */ ){
- if ( !jQuery.acceptData( elem ) ) {
- return;
- }
-
- var thisCache, ret,
- internalKey = jQuery.expando,
- getByName = typeof name === "string",
-
- // 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)) && getByName && data === undefined ) {
- 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 ) {
- elem[ internalKey ] = id = core_deletedIds.pop() || jQuery.guid++;
- } else {
- id = internalKey;
- }
- }
-
- if ( !cache[ id ] ) {
- cache[ id ] = {};
-
- // Avoids exposing jQuery metadata on plain JS objects when the object
- // is serialized using JSON.stringify
- if ( !isNode ) {
- cache[ id ].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 ( getByName ) {
-
- // 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 i, l, thisCache,
- 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 ) );
- }
-
- for ( i = 0, l = name.length; i < l; 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 : 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)
- } else if ( jQuery.support.deleteExpando || cache != cache.window ) {
- delete cache[ id ];
-
- // When all else fails, null
- } else {
- cache[ id ] = null;
- }
- }
-
- jQuery.extend({
- cache: {},
-
- // Unique for each copy of jQuery on the page
- // Non-digits removed to match rinlinejQuery
- expando: "jQuery" + ( core_version + Math.random() ).replace( /\D/g, "" ),
-
- // The following elements throw uncatchable exceptions if you
- // attempt to add expando properties to them.
- noData: {
- "embed": true,
- // Ban all objects except for Flash (which handle expandos)
- "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",
- "applet": true
- },
-
- 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 );
- },
-
- // A method for determining if a DOM node can handle the data expando
- acceptData: function( elem ) {
- // Do not set data on non-element because it will not be cleared (#8335).
- if ( elem.nodeType && elem.nodeType !== 1 && elem.nodeType !== 9 ) {
- return false;
- }
-
- var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ];
-
- // nodes accept data unless otherwise specified; rejection can be conditional
- return !noData || noData !== true && elem.getAttribute("classid") === noData;
- }
- });
-
- jQuery.fn.extend({
- data: function( key, value ) {
- var attrs, name,
- elem = this[0],
- i = 0,
- data = null;
-
- // Gets all values
- if ( key === undefined ) {
- if ( this.length ) {
- data = jQuery.data( elem );
-
- if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
- attrs = elem.attributes;
- for ( ; i < attrs.length; i++ ) {
- name = attrs[i].name;
-
- if ( !name.indexOf( "data-" ) ) {
- 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 jQuery.access( this, function( value ) {
-
- if ( value === undefined ) {
- // Try to fetch any internally stored data first
- return elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : null;
- }
-
- this.each(function() {
- jQuery.data( this, key, value );
- });
- }, null, value, arguments.length > 1, null, true );
- },
-
- removeData: function( key ) {
- return this.each(function() {
- jQuery.removeData( this, key );
- });
- }
- });
-
- 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;
- }
- 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--;
- }
-
- hooks.cur = fn;
- 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 );
- });
- },
- // Based off of the plugin by Clint Helfers, with permission.
- // http://blindsignals.com/index.php/2009/07/jquery-delay/
- 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 );
- };
- });
- },
- 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 nodeHook, boolHook,
- rclass = /[\t\r\n]/g,
- rreturn = /\r/g,
- rfocusable = /^(?:input|select|textarea|button|object)$/i,
- rclickable = /^(?:a|area)$/i,
- rboolean = /^(?:checked|selected|autofocus|autoplay|async|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped)$/i,
- ruseDefault = /^(?:checked|selected)$/i,
- getSetAttribute = jQuery.support.getSetAttribute,
- getSetInput = jQuery.support.input;
-
- jQuery.fn.extend({
- attr: function( name, value ) {
- return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
- },
-
- removeAttr: function( name ) {
- return this.each(function() {
- jQuery.removeAttr( this, name );
- });
- },
-
- prop: function( name, value ) {
- return jQuery.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 ) {}
- });
- },
-
- addClass: function( value ) {
- var classes, elem, cur, clazz, j,
- 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( core_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 + " ";
- }
- }
- elem.className = jQuery.trim( cur );
-
- }
- }
- }
-
- return this;
- },
-
- removeClass: function( value ) {
- var classes, elem, cur, clazz, j,
- 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( core_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 + " ", " " );
- }
- }
- elem.className = value ? jQuery.trim( cur ) : "";
- }
- }
- }
-
- return this;
- },
-
- toggleClass: function( value, stateVal ) {
- var type = typeof value,
- isBool = typeof stateVal === "boolean";
-
- 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 ),
- state = stateVal,
- classNames = value.match( core_rnotwhite ) || [];
-
- while ( (className = classNames[ i++ ]) ) {
- // check each className given, space separated list
- state = isBool ? state : !self.hasClass( className );
- self[ state ? "addClass" : "removeClass" ]( className );
- }
-
- // Toggle whole class name
- } else if ( type === core_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;
- },
-
- val: function( value ) {
- var ret, hooks, 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,
- self = jQuery(this);
-
- if ( this.nodeType !== 1 ) {
- return;
- }
-
- if ( isFunction ) {
- val = value.call( this, i, self.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 ) {
- // attributes.value is undefined in Blackberry 4.7 but
- // uses .value. See #6932
- var val = elem.attributes.value;
- return !val || val.specified ? elem.value : elem.text;
- }
- },
- 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
- ( jQuery.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 values = jQuery.makeArray( value );
-
- jQuery(elem).find("option").each(function() {
- this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
- });
-
- if ( !values.length ) {
- elem.selectedIndex = -1;
- }
- return values;
- }
- }
- },
-
- attr: function( elem, name, value ) {
- var hooks, notxml, 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 === core_strundefined ) {
- return jQuery.prop( elem, name, value );
- }
-
- notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
-
- // All attributes are lowercase
- // Grab necessary hook if one is defined
- if ( notxml ) {
- name = name.toLowerCase();
- hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook );
- }
-
- if ( value !== undefined ) {
-
- if ( value === null ) {
- jQuery.removeAttr( elem, name );
-
- } else if ( hooks && notxml && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
- return ret;
-
- } else {
- elem.setAttribute( name, value + "" );
- return value;
- }
-
- } else if ( hooks && notxml && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
- return ret;
-
- } else {
-
- // In IE9+, Flash objects don't have .getAttribute (#12945)
- // Support: IE9+
- if ( typeof elem.getAttribute !== core_strundefined ) {
- ret = elem.getAttribute( 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( core_rnotwhite );
-
- if ( attrNames && elem.nodeType === 1 ) {
- while ( (name = attrNames[i++]) ) {
- propName = jQuery.propFix[ name ] || name;
-
- // Boolean attributes get special treatment (#10870)
- if ( rboolean.test( name ) ) {
- // Set corresponding property to false for boolean attributes
- // Also clear defaultChecked/defaultSelected (if appropriate) for IE<8
- if ( !getSetAttribute && ruseDefault.test( name ) ) {
- elem[ jQuery.camelCase( "default-" + name ) ] =
- elem[ propName ] = false;
- } else {
- 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 ( !jQuery.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;
- }
- }
- }
- },
-
- propFix: {
- tabindex: "tabIndex",
- readonly: "readOnly",
- "for": "htmlFor",
- "class": "className",
- maxlength: "maxLength",
- cellspacing: "cellSpacing",
- cellpadding: "cellPadding",
- rowspan: "rowSpan",
- colspan: "colSpan",
- usemap: "useMap",
- frameborder: "frameBorder",
- contenteditable: "contentEditable"
- },
-
- 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 ) {
- if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
- return ret;
-
- } else {
- return ( elem[ name ] = value );
- }
-
- } else {
- if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
- return ret;
-
- } else {
- return 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-tabi...
- var attributeNode = elem.getAttributeNode("tabindex");
-
- return attributeNode && attributeNode.specified ?
- parseInt( attributeNode.value, 10 ) :
- rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
- 0 :
- undefined;
- }
- }
- }
- });
-
-// Hook for boolean attributes
- boolHook = {
- get: function( elem, name ) {
- var
- // Use .prop to determine if this attribute is understood as boolean
- prop = jQuery.prop( elem, name ),
-
- // Fetch it accordingly
- attr = typeof prop === "boolean" && elem.getAttribute( name ),
- detail = typeof prop === "boolean" ?
-
- getSetInput && getSetAttribute ?
- attr != null :
- // oldIE fabricates an empty string for missing boolean attributes
- // and conflates checked/selected into attroperties
- ruseDefault.test( name ) ?
- elem[ jQuery.camelCase( "default-" + name ) ] :
- !!attr :
-
- // fetch an attribute node for properties not recognized as boolean
- elem.getAttributeNode( name );
-
- return detail && detail.value !== false ?
- name.toLowerCase() :
- undefined;
- },
- 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;
- }
- };
-
-// fix oldIE value attroperty
- if ( !getSetInput || !getSetAttribute ) {
- jQuery.attrHooks.value = {
- get: function( elem, name ) {
- var ret = elem.getAttributeNode( name );
- return jQuery.nodeName( elem, "input" ) ?
-
- // Ignore the value *property* by using defaultValue
- elem.defaultValue :
-
- ret && ret.specified ? ret.value : undefined;
- },
- 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 = jQuery.valHooks.button = {
- get: function( elem, name ) {
- var ret = elem.getAttributeNode( name );
- return ret && ( name === "id" || name === "name" || name === "coords" ? ret.value !== "" : ret.specified ) ?
- ret.value :
- undefined;
- },
- 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)
- return name === "value" || value === elem.getAttribute( name ) ?
- value :
- undefined;
- }
- };
-
- // Set contenteditable to false on removals(#10429)
- // Setting to empty string throws an error as an invalid value
- jQuery.attrHooks.contenteditable = {
- get: nodeHook.get,
- 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 ] = jQuery.extend( jQuery.attrHooks[ name ], {
- set: function( elem, value ) {
- if ( value === "" ) {
- elem.setAttribute( name, "auto" );
- return value;
- }
- }
- });
- });
- }
-
-
-// Some attributes require a special call on IE
-// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
- if ( !jQuery.support.hrefNormalized ) {
- jQuery.each([ "href", "src", "width", "height" ], function( i, name ) {
- jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
- get: function( elem ) {
- var ret = elem.getAttribute( name, 2 );
- return ret == null ? undefined : ret;
- }
- });
- });
-
- // 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 );
- }
- };
- });
- }
-
- if ( !jQuery.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 + "" );
- }
- };
- }
-
-// Safari mis-reports the default selected property of an option
-// Accessing the parent's selectedIndex property fixes it
- if ( !jQuery.support.optSelected ) {
- jQuery.propHooks.selected = jQuery.extend( 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;
- }
- });
- }
-
-// IE6/7 call enctype encoding
- if ( !jQuery.support.enctype ) {
- jQuery.propFix.enctype = "encoding";
- }
-
-// Radios and checkboxes getter/setter
- if ( !jQuery.support.checkOn ) {
- jQuery.each([ "radio", "checkbox" ], function() {
- jQuery.valHooks[ this ] = {
- get: function( elem ) {
- // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
- return elem.getAttribute("value") === null ? "on" : elem.value;
- }
- };
- });
- }
- jQuery.each([ "radio", "checkbox" ], function() {
- jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], {
- set: function( elem, value ) {
- if ( jQuery.isArray( value ) ) {
- return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
- }
- }
- });
- });
- var rformElems = /^(?:input|select|textarea)$/i,
- rkeyEvent = /^key/,
- rmouseEvent = /^(?:mouse|contextmenu)|click/,
- rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
- rtypenamespace = /^([^.]*)(?:\.(.+)|)$/;
-
- function returnTrue() {
- return true;
- }
-
- function returnFalse() {
- return false;
- }
-
- /*
- * 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 !== core_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
- // jQuery(...).bind("mouseover mouseout", fn);
- types = ( types || "" ).match( core_rnotwhite ) || [""];
- t = types.length;
- while ( t-- ) {
- tmp = rtypenamespace.exec( types[t] ) || [];
- type = origType = tmp[1];
- namespaces = ( tmp[2] || "" ).split( "." ).sort();
-
- // 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( core_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 = core_hasOwn.call( event, "type" ) ? event.type : event,
- namespaces = core_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 );
-
- event.isTrigger = true;
- 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 && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === 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( elem.ownerDocument, data ) === false) &&
- !(type === "click" && jQuery.nodeName( elem, "a" )) && 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 = core_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") ) {
-
- for ( ; cur != this; cur = cur.parentNode || this ) {
-
- // 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
- },
- 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;
- }
- }
- },
- focus: {
- // Fire native event if possible so blur/focus sequence is correct
- trigger: function() {
- if ( this !== document.activeElement && 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 === document.activeElement && this.blur ) {
- this.blur();
- return false;
- }
- },
- delegateType: "focusout"
- },
-
- beforeunload: {
- postDispatch: function( event ) {
-
- // Even when returnValue equals to undefined Firefox will still show alert
- if ( event.result !== undefined ) {
- 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 ] === core_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.returnValue === false ||
- src.getPreventDefault && src.getPreventDefault() ) ? 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-bind...
- 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() {
- this.isImmediatePropagationStopped = returnTrue;
- this.stopPropagation();
- }
- };
-
-// Create mouseenter/leave events using mouseover/out and event-time checks
- jQuery.each({
- mouseenter: "mouseover",
- mouseleave: "mouseout"
- }, 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 ( !jQuery.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 ( !jQuery.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 ( !jQuery.support.focusinBubbles ) {
- jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
-
- // Attach a single capturing handler while someone wants focusin/focusout
- var attaches = 0,
- handler = function( event ) {
- jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
- };
-
- jQuery.event.special[ fix ] = {
- setup: function() {
- if ( attaches++ === 0 ) {
- document.addEventListener( orig, handler, true );
- }
- },
- teardown: function() {
- if ( --attaches === 0 ) {
- document.removeEventListener( orig, handler, true );
- }
- }
- };
- });
- }
-
- 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 );
- });
- },
-
- 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 );
- },
-
- 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 );
- }
- }
- });
- /*!
- * Sizzle CSS Selector Engine
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license
- * http://sizzlejs.com/
- */
- (function( window, undefined ) {
-
- var i,
- cachedruns,
- Expr,
- getText,
- isXML,
- compile,
- hasDuplicate,
- outermostContext,
-
- // Local document vars
- setDocument,
- document,
- docElem,
- documentIsXML,
- rbuggyQSA,
- rbuggyMatches,
- matches,
- contains,
- sortOrder,
-
- // Instance-specific data
- expando = "sizzle" + -(new Date()),
- preferredDoc = window.document,
- support = {},
- dirruns = 0,
- done = 0,
- classCache = createCache(),
- tokenCache = createCache(),
- compilerCache = createCache(),
-
- // General-purpose constants
- strundefined = typeof undefined,
- MAX_NEGATIVE = 1 << 31,
-
- // Array methods
- arr = [],
- pop = arr.pop,
- push = arr.push,
- slice = arr.slice,
- // Use a stripped-down indexOf if we can't use a native one
- indexOf = arr.indexOf || function( elem ) {
- var i = 0,
- len = this.length;
- for ( ; i < len; i++ ) {
- if ( this[i] === elem ) {
- return i;
- }
- }
- return -1;
- },
-
-
- // 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#" ),
-
- // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors
- operators = "([*^$|!~]?=)",
- attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace +
- "*(?:" + operators + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]",
-
- // Prefer arguments quoted,
- // then not containing pseudos/brackets,
- // then attribute selectors/non-parenthetical expressions,
- // then anything else
- // These preferences are here to reduce the number of selectors
- // needing tokenize in the PSEUDO preFilter
- pseudos = ":(" + characterEncoding + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes.replace( 3, 8 ) + ")*)|.*)\\)|)",
-
- // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
- rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
-
- rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
- rcombinators = new RegExp( "^" + whitespace + "*([\\x20\\t\\r\\n\\f>+~])" + whitespace + "*" ),
- rpseudo = new RegExp( pseudos ),
- ridentifier = new RegExp( "^" + identifier + "$" ),
-
- matchExpr = {
- "ID": new RegExp( "^#(" + characterEncoding + ")" ),
- "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
- "NAME": new RegExp( "^\\[name=['\"]?(" + 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" ),
- // 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" )
- },
-
- rsibling = /[\x20\t\r\n\f]*[+~]/,
-
- rnative = /^[^{]+\{\s*\[native code/,
-
- // Easily-parseable/retrievable ID or TAG or CLASS selectors
- rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
-
- rinputs = /^(?:input|select|textarea|button)$/i,
- rheader = /^h\d$/i,
-
- rescape = /'|\\/g,
- rattributeQuotes = /\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,
-
- // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
- runescape = /\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g,
- funescape = function( _, escaped ) {
- var high = "0x" + escaped - 0x10000;
- // NaN means non-codepoint
- return high !== high ?
- escaped :
- // BMP codepoint
- high < 0 ?
- String.fromCharCode( high + 0x10000 ) :
- // Supplemental Plane codepoint (surrogate pair)
- String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
- };
-
-// Use a stripped-down slice if we can't use a native one
- try {
- slice.call( preferredDoc.documentElement.childNodes, 0 )[0].nodeType;
- } catch ( e ) {
- slice = function( i ) {
- var elem,
- results = [];
- while ( (elem = this[i++]) ) {
- results.push( elem );
- }
- return results;
- };
- }
-
- /**
- * For feature detection
- * @param {Function} fn The function to test for native support
- */
- function isNative( fn ) {
- return rnative.test( fn + "" );
- }
-
- /**
- * 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 cache,
- keys = [];
-
- return (cache = function( 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);
- });
- }
-
- /**
- * 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 {
- // release memory in IE
- div = null;
- }
- }
-
- function Sizzle( selector, context, results, seed ) {
- var match, elem, m, nodeType,
- // QSA vars
- i, groups, old, nid, newContext, newSelector;
-
- if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
- setDocument( context );
- }
-
- context = context || document;
- results = results || [];
-
- if ( !selector || typeof selector !== "string" ) {
- return results;
- }
-
- if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {
- return [];
- }
-
- if ( !documentIsXML && !seed ) {
-
- // Shortcuts
- if ( (match = rquickExpr.exec( selector )) ) {
- // Speed-up: Sizzle("#ID")
- if ( (m = match[1]) ) {
- if ( nodeType === 9 ) {
- elem = context.getElementById( m );
- // Check parentNode to catch when Blackberry 4.6 returns
- // nodes that are no longer in the document #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, slice.call(context.getElementsByTagName( selector ), 0) );
- return results;
-
- // Speed-up: Sizzle(".CLASS")
- } else if ( (m = match[3]) && support.getByClassName && context.getElementsByClassName ) {
- push.apply( results, slice.call(context.getElementsByClassName( m ), 0) );
- return results;
- }
- }
-
- // QSA path
- if ( support.qsa && !rbuggyQSA.test(selector) ) {
- old = true;
- nid = expando;
- newContext = context;
- newSelector = nodeType === 9 && selector;
-
- // qSA works strangely on Element-rooted queries
- // We can work around this by specifying an extra ID on the root
- // and working up from there (Thanks to Andrew Dupont for the technique)
- // IE 8 doesn't work on object elements
- if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
- groups = tokenize( selector );
-
- if ( (old = context.getAttribute("id")) ) {
- nid = old.replace( rescape, "\\$&" );
- } else {
- context.setAttribute( "id", nid );
- }
- nid = "[id='" + nid + "'] ";
-
- i = groups.length;
- while ( i-- ) {
- groups[i] = nid + toSelector( groups[i] );
- }
- newContext = rsibling.test( selector ) && context.parentNode || context;
- newSelector = groups.join(",");
- }
-
- if ( newSelector ) {
- try {
- push.apply( results, slice.call( newContext.querySelectorAll(
- newSelector
- ), 0 ) );
- return results;
- } catch(qsaError) {
- } finally {
- if ( !old ) {
- context.removeAttribute("id");
- }
- }
- }
- }
- }
-
- // All others
- return select( selector.replace( rtrim, "$1" ), context, results, seed );
- }
-
- /**
- * Detect xml
- * @param {Element|Object} elem An element or a document
- */
- 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 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;
-
- // Support tests
- documentIsXML = isXML( doc );
-
- // Check if getElementsByTagName("*") returns only elements
- support.tagNameNoComments = assert(function( div ) {
- div.appendChild( doc.createComment("") );
- return !div.getElementsByTagName("*").length;
- });
-
- // Check if attributes should be retrieved by attribute nodes
- support.attributes = assert(function( div ) {
- div.innerHTML = "<select></select>";
- var type = typeof div.lastChild.getAttribute("multiple");
- // IE8 returns a string for some attributes even when not present
- return type !== "boolean" && type !== "string";
- });
-
- // Check if getElementsByClassName can be trusted
- support.getByClassName = assert(function( div ) {
- // Opera can't find a second classname (in 9.6)
- div.innerHTML = "<div class='hidden e'></div><div class='hidden'></div>";
- if ( !div.getElementsByClassName || !div.getElementsByClassName("e").length ) {
- return false;
- }
-
- // Safari 3.2 caches class attributes and doesn't catch changes
- div.lastChild.className = "e";
- return div.getElementsByClassName("e").length === 2;
- });
-
- // Check if getElementById returns elements by name
- // Check if getElementsByName privileges form controls or returns elements by ID
- support.getByName = assert(function( div ) {
- // Inject content
- div.id = expando + 0;
- div.innerHTML = "<a name='" + expando + "'></a><div name='" + expando + "'></div>";
- docElem.insertBefore( div, docElem.firstChild );
-
- // Test
- var pass = doc.getElementsByName &&
- // buggy browsers will return fewer than the correct 2
- doc.getElementsByName( expando ).length === 2 +
- // buggy browsers will return more than the correct 0
- doc.getElementsByName( expando + 0 ).length;
- support.getIdNotName = !doc.getElementById( expando );
-
- // Cleanup
- docElem.removeChild( div );
-
- return pass;
- });
-
- // IE6/7 return modified attributes
- Expr.attrHandle = assert(function( div ) {
- div.innerHTML = "<a href='#'></a>";
- return div.firstChild && typeof div.firstChild.getAttribute !== strundefined &&
- div.firstChild.getAttribute("href") === "#";
- }) ?
- {} :
- {
- "href": function( elem ) {
- return elem.getAttribute( "href", 2 );
- },
- "type": function( elem ) {
- return elem.getAttribute("type");
- }
- };
-
- // ID find and filter
- if ( support.getIdNotName ) {
- Expr.find["ID"] = function( id, context ) {
- if ( typeof context.getElementById !== strundefined && !documentIsXML ) {
- 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 {
- Expr.find["ID"] = function( id, context ) {
- if ( typeof context.getElementById !== strundefined && !documentIsXML ) {
- var m = context.getElementById( id );
-
- return m ?
- m.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode("id").value === id ?
- [m] :
- undefined :
- [];
- }
- };
- Expr.filter["ID"] = function( id ) {
- var attrId = id.replace( runescape, funescape );
- return function( elem ) {
- var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
- return node && node.value === attrId;
- };
- };
- }
-
- // Tag
- Expr.find["TAG"] = support.tagNameNoComments ?
- function( tag, context ) {
- if ( typeof context.getElementsByTagName !== strundefined ) {
- return context.getElementsByTagName( tag );
- }
- } :
- function( tag, context ) {
- var elem,
- tmp = [],
- i = 0,
- results = context.getElementsByTagName( tag );
-
- // Filter out possible comments
- if ( tag === "*" ) {
- while ( (elem = results[i++]) ) {
- if ( elem.nodeType === 1 ) {
- tmp.push( elem );
- }
- }
-
- return tmp;
- }
- return results;
- };
-
- // Name
- Expr.find["NAME"] = support.getByName && function( tag, context ) {
- if ( typeof context.getElementsByName !== strundefined ) {
- return context.getElementsByName( name );
- }
- };
-
- // Class
- Expr.find["CLASS"] = support.getByClassName && function( className, context ) {
- if ( typeof context.getElementsByClassName !== strundefined && !documentIsXML ) {
- return context.getElementsByClassName( className );
- }
- };
-
- // QSA and matchesSelector support
-
- // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
- rbuggyMatches = [];
-
- // qSa(:focus) reports false when true (Chrome 21),
- // no need to also add to buggyMatches since matches checks buggyQSA
- // A support test would require too much code (would include document ready)
- rbuggyQSA = [ ":focus" ];
-
- if ( (support.qsa = isNative(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 explictly
- // setting a boolean content attribute,
- // since its presence should be enough
- // http://bugs.jquery.com/ticket/12359
- div.innerHTML = "<select><option selected=''></option></select>";
-
- // IE8 - Some boolean attributes are not treated correctly
- if ( !div.querySelectorAll("[selected]").length ) {
- rbuggyQSA.push( "\\[" + whitespace + "*(?:checked|disabled|ismap|multiple|readonly|selected|value)" );
- }
-
- // Webkit/Opera - :checked should return selected option elements
- // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
- // IE8 throws error here and will not see later tests
- if ( !div.querySelectorAll(":checked").length ) {
- rbuggyQSA.push(":checked");
- }
- });
-
- assert(function( div ) {
-
- // Opera 10-12/IE8 - ^= $= *= and empty values
- // Should not select anything
- div.innerHTML = "<input type='hidden' i=''/>";
- if ( div.querySelectorAll("[i^='']").length ) {
- rbuggyQSA.push( "[*^$]=" + 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 = isNative( (matches = docElem.matchesSelector ||
- docElem.mozMatchesSelector ||
- docElem.webkitMatchesSelector ||
- 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 = new RegExp( rbuggyQSA.join("|") );
- rbuggyMatches = new RegExp( rbuggyMatches.join("|") );
-
- // Element contains another
- // Purposefully does not implement inclusive descendent
- // As in, an element does not contain itself
- contains = isNative(docElem.contains) || docElem.compareDocumentPosition ?
- 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;
- };
-
- // Document order sorting
- sortOrder = docElem.compareDocumentPosition ?
- function( a, b ) {
- var compare;
-
- if ( a === b ) {
- hasDuplicate = true;
- return 0;
- }
-
- if ( (compare = b.compareDocumentPosition && a.compareDocumentPosition && a.compareDocumentPosition( b )) ) {
- if ( compare & 1 || a.parentNode && a.parentNode.nodeType === 11 ) {
- if ( a === doc || contains( preferredDoc, a ) ) {
- return -1;
- }
- if ( b === doc || contains( preferredDoc, b ) ) {
- return 1;
- }
- return 0;
- }
- return compare & 4 ? -1 : 1;
- }
-
- return a.compareDocumentPosition ? -1 : 1;
- } :
- function( a, b ) {
- var cur,
- i = 0,
- aup = a.parentNode,
- bup = b.parentNode,
- ap = [ a ],
- bp = [ b ];
-
- // Exit early if the nodes are identical
- if ( a === b ) {
- hasDuplicate = true;
- return 0;
-
- // Parentless nodes are either documents or disconnected
- } else if ( !aup || !bup ) {
- return a === doc ? -1 :
- b === doc ? 1 :
- aup ? -1 :
- bup ? 1 :
- 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;
- };
-
- // Always assume the presence of duplicates if sort doesn't
- // pass them to our comparison function (as in Google Chrome).
- hasDuplicate = false;
- [0, 0].sort( sortOrder );
- support.detectDuplicates = hasDuplicate;
-
- return document;
- };
-
- 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']" );
-
- // rbuggyQSA always contains :focus, so no need for an existence check
- if ( support.matchesSelector && !documentIsXML && (!rbuggyMatches || !rbuggyMatches.test(expr)) && !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 ) {
- var val;
-
- // Set document vars if needed
- if ( ( elem.ownerDocument || elem ) !== document ) {
- setDocument( elem );
- }
-
- if ( !documentIsXML ) {
- name = name.toLowerCase();
- }
- if ( (val = Expr.attrHandle[ name ]) ) {
- return val( elem );
- }
- if ( documentIsXML || support.attributes ) {
- return elem.getAttribute( name );
- }
- return ( (val = elem.getAttributeNode( name )) || elem.getAttribute( name ) ) && elem[ name ] === true ?
- name :
- val && val.specified ? val.value : null;
- };
-
- Sizzle.error = function( msg ) {
- throw new Error( "Syntax error, unrecognized expression: " + msg );
- };
-
-// Document sorting and removing duplicates
- Sizzle.uniqueSort = function( results ) {
- var elem,
- duplicates = [],
- i = 1,
- j = 0;
-
- // Unless we *know* we can detect duplicates, assume their presence
- hasDuplicate = !support.detectDuplicates;
- results.sort( sortOrder );
-
- if ( hasDuplicate ) {
- for ( ; (elem = results[i]); i++ ) {
- if ( elem === results[ i - 1 ] ) {
- j = duplicates.push( i );
- }
- }
- while ( j-- ) {
- results.splice( duplicates[ j ], 1 );
- }
- }
-
- return results;
- };
-
- function siblingCheck( a, b ) {
- var cur = b && a,
- diff = cur && ( ~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
- 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
- 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
- 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]);
- }
- }
- });
- });
- }
-
- /**
- * 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
- for ( ; (node = elem[i]); 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 (see #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,
-
- 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[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[5] && match[2];
-
- if ( matchExpr["CHILD"].test( match[0] ) ) {
- return null;
- }
-
- // Accept quoted arguments as-is
- if ( match[4] ) {
- match[2] = match[4];
-
- // 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( nodeName ) {
- if ( nodeName === "*" ) {
- return function() { return true; };
- }
-
- nodeName = nodeName.replace( runescape, funescape ).toLowerCase();
- return 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( elem.className || (typeof elem.getAttribute !== strundefined && elem.getAttribute("class")) || "" );
- });
- },
-
- "ATTR": function( name, operator, check ) {
- return function( elem ) {
- var result = Sizzle.attr( elem, name );
-
- if ( result == null ) {
- return operator === "!=";
- }
- if ( !operator ) {
- return true;
- }
-
- result += "";
-
- return operator === "=" ? result === check :
- operator === "!=" ? result !== check :
- operator === "^=" ? check && result.indexOf( check ) === 0 :
- operator === "*=" ? check && result.indexOf( check ) > -1 :
- operator === "$=" ? check && result.slice( -check.length ) === check :
- operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
- operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
- false;
- };
- },
-
- "CHILD": function( type, what, argument, first, last ) {
- var simple = type.slice( 0, 3 ) !== "nth",
- forward = type.slice( -4 ) !== "last",
- ofType = what === "of-type";
-
- return first === 1 && last === 0 ?
-
- // Shortcut for :nth-*(n)
- function( elem ) {
- return !!elem.parentNode;
- } :
-
- function( elem, context, xml ) {
- var cache, outerCache, node, diff, nodeIndex, start,
- dir = simple !== forward ? "nextSibling" : "previousSibling",
- parent = elem.parentNode,
- name = ofType && elem.nodeName.toLowerCase(),
- useCache = !xml && !ofType;
-
- if ( parent ) {
-
- // :(first|last|only)-(child|of-type)
- if ( simple ) {
- while ( dir ) {
- node = elem;
- while ( (node = node[ dir ]) ) {
- if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {
- return false;
- }
- }
- // Reverse direction for :only-* (if we haven't yet done so)
- start = dir = type === "only" && !start && "nextSibling";
- }
- return true;
- }
-
- start = [ forward ? parent.firstChild : parent.lastChild ];
-
- // non-xml :nth-child(...) stores cache data on `parent`
- if ( forward && useCache ) {
- // Seek `elem` from a previously-cached index
- outerCache = parent[ expando ] || (parent[ expando ] = {});
- cache = outerCache[ type ] || [];
- nodeIndex = cache[0] === dirruns && cache[1];
- diff = cache[0] === dirruns && cache[2];
- node = nodeIndex && parent.childNodes[ nodeIndex ];
-
- while ( (node = ++nodeIndex && node && node[ dir ] ||
-
- // Fallback to seeking `elem` from the start
- (diff = nodeIndex = 0) || start.pop()) ) {
-
- // When found, cache indexes on `parent` and break
- if ( node.nodeType === 1 && ++diff && node === elem ) {
- outerCache[ type ] = [ dirruns, nodeIndex, diff ];
- break;
- }
- }
-
- // Use previously-cached element index if available
- } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {
- diff = cache[1];
-
- // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)
- } else {
- // Use the same loop as above to seek `elem` from the start
- while ( (node = ++nodeIndex && node && node[ dir ] ||
- (diff = nodeIndex = 0) || start.pop()) ) {
-
- if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {
- // Cache the index of each encountered element
- if ( useCache ) {
- (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];
- }
-
- if ( node === elem ) {
- break;
- }
- }
- }
- }
-
- // Incorporate the offset, then check against cycle size
- diff -= last;
- return diff === first || ( diff % first === 0 && diff / first >= 0 );
- }
- };
- },
-
- "PSEUDO": function( pseudo, argument ) {
- // pseudo-class names are case-insensitive
- // http://www.w3.org/TR/selectors/#pseudo-classes
- // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
- // Remember that setFilters inherits from pseudos
- var args,
- fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
- Sizzle.error( "unsupported pseudo: " + pseudo );
-
- // The user may use createPseudo to indicate that
- // arguments are needed to create the filter function
- // just as Sizzle does
- if ( fn[ expando ] ) {
- return fn( argument );
- }
-
- // But maintain support for old signatures
- if ( fn.length > 1 ) {
- args = [ pseudo, pseudo, "", argument ];
- return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
- markFunction(function( seed, matches ) {
- var idx,
- matched = fn( seed, argument ),
- i = matched.length;
- while ( i-- ) {
- idx = indexOf.call( seed, matched[i] );
- seed[ idx ] = !( matches[ idx ] = matched[i] );
- }
- }) :
- function( elem ) {
- return fn( elem, 0, args );
- };
- }
-
- return fn;
- }
- },
-
- pseudos: {
- // Potentially complex pseudos
- "not": markFunction(function( selector ) {
- // Trim the selector passed to compile
- // to avoid treating leading and trailing
- // spaces as combinators
- var input = [],
- results = [],
- matcher = compile( selector.replace( rtrim, "$1" ) );
-
- return matcher[ expando ] ?
- markFunction(function( seed, matches, context, xml ) {
- var elem,
- unmatched = matcher( seed, null, xml, [] ),
- i = seed.length;
-
- // Match elements unmatched by `matcher`
- while ( i-- ) {
- if ( (elem = unmatched[i]) ) {
- seed[i] = !(matches[i] = elem);
- }
- }
- }) :
- function( elem, context, xml ) {
- input[0] = elem;
- matcher( input, null, xml, results );
- return !results.pop();
- };
- }),
-
- "has": markFunction(function( selector ) {
- return function( elem ) {
- return Sizzle( selector, elem ).length > 0;
- };
- }),
-
- "contains": markFunction(function( text ) {
- return function( elem ) {
- return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
- };
- }),
-
- // "Whether an element is represented by a :lang() selector
- // is based solely on the element's language value
- // being equal to the identifier C,
- // or beginning with the identifier C immediately followed by "-".
- // The matching of C against the element's language value is performed case-insensitively.
- // The identifier C does not have to be a valid language name."
- // http://www.w3.org/TR/selectors/#lang-pseudo
- "lang": markFunction( function( lang ) {
- // lang value must be a valid identifider
- if ( !ridentifier.test(lang || "") ) {
- Sizzle.error( "unsupported lang: " + lang );
- }
- lang = lang.replace( runescape, funescape ).toLowerCase();
- return function( elem ) {
- var elemLang;
- do {
- if ( (elemLang = documentIsXML ?
- elem.getAttribute("xml:lang") || elem.getAttribute("lang") :
- elem.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 only affected by element nodes and content nodes(including text(3), cdata(4)),
- // not comment, processing instructions, or others
- // Thanks to Diego Perini for the nodeName shortcut
- // Greater than "@" means alpha characters (specifically not starting with "#" or "?")
- for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
- if ( elem.nodeName > "@" || elem.nodeType === 3 || elem.nodeType === 4 ) {
- 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;
- // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
- // use getAttribute instead to test this case
- return elem.nodeName.toLowerCase() === "input" &&
- elem.type === "text" &&
- ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === elem.type );
- },
-
- // 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;
- })
- }
- };
-
-// 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 );
- }
-
- function tokenize( 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 data, cache, outerCache,
- dirkey = 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 ( (cache = outerCache[ dir ]) && cache[0] === dirkey ) {
- if ( (data = cache[1]) === true || data === cachedruns ) {
- return data === true;
- }
- } else {
- cache = outerCache[ dir ] = [ dirkey ];
- cache[1] = matcher( elem, context, xml ) || cachedruns;
- if ( cache[1] === true ) {
- 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 condense( unmatched, map, filter, context, xml ) {
- var elem,
- newUnmatched = [],
- i = 0,
- len = unmatched.length,
- mapped = map != null;
-
- for ( ; i < len; i++ ) {
- if ( (elem = unmatched[i]) ) {
- if ( !filter || filter( elem, context, xml ) ) {
- newUnmatched.push( elem );
- if ( mapped ) {
- map.push( i );
- }
- }
- }
- }
-
- return newUnmatched;
- }
-
- function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
- if ( postFilter && !postFilter[ expando ] ) {
- postFilter = setMatcher( postFilter );
- }
- if ( postFinder && !postFinder[ expando ] ) {
- postFinder = setMatcher( postFinder, postSelector );
- }
- return markFunction(function( seed, results, context, xml ) {
- var temp, i, elem,
- preMap = [],
- postMap = [],
- preexisting = results.length,
-
- // Get initial elements from seed or context
- elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
-
- // Prefilter to get matcher input, preserving a map for seed-results synchronization
- matcherIn = preFilter && ( seed || !selector ) ?
- condense( elems, preMap, preFilter, context, xml ) :
- elems,
-
- matcherOut = matcher ?
- // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
- postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
-
- // ...intermediate processing is necessary
- [] :
-
- // ...otherwise use results directly
- results :
- matcherIn;
-
- // Find primary matches
- if ( matcher ) {
- matcher( matcherIn, matcherOut, context, xml );
- }
-
- // Apply postFilter
- if ( postFilter ) {
- temp = condense( matcherOut, postMap );
- postFilter( temp, [], context, xml );
-
- // Un-match failing elements by moving them back to matcherIn
- i = temp.length;
- while ( i-- ) {
- if ( (elem = temp[i]) ) {
- matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
- }
- }
- }
-
- if ( seed ) {
- if ( postFinder || preFilter ) {
- if ( postFinder ) {
- // Get the final matcherOut by condensing this intermediate into postFinder contexts
- temp = [];
- i = matcherOut.length;
- while ( i-- ) {
- if ( (elem = matcherOut[i]) ) {
- // Restore matcherIn since elem is not yet a final match
- temp.push( (matcherIn[i] = elem) );
- }
- }
- postFinder( null, (matcherOut = []), temp, xml );
- }
-
- // Move matched elements from seed to results to keep them synchronized
- i = matcherOut.length;
- while ( i-- ) {
- if ( (elem = matcherOut[i]) &&
- (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
-
- seed[temp] = !(results[temp] = elem);
- }
- }
- }
-
- // Add elements to results, through postFinder if defined
- } else {
- matcherOut = condense(
- matcherOut === results ?
- matcherOut.splice( preexisting, matcherOut.length ) :
- matcherOut
- );
- if ( postFinder ) {
- postFinder( null, results, matcherOut, xml );
- } else {
- push.apply( results, matcherOut );
- }
- }
- });
- }
-
- function matcherFromTokens( tokens ) {
- var checkContext, matcher, j,
- len = tokens.length,
- leadingRelative = Expr.relative[ tokens[0].type ],
- implicitRelative = leadingRelative || Expr.relative[" "],
- i = leadingRelative ? 1 : 0,
-
- // The foundational matcher ensures that elements are reachable from top-level context(s)
- matchContext = addCombinator( function( elem ) {
- return elem === checkContext;
- }, implicitRelative, true ),
- matchAnyContext = addCombinator( function( elem ) {
- return indexOf.call( checkContext, elem ) > -1;
- }, implicitRelative, true ),
- matchers = [ function( elem, context, xml ) {
- return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
- (checkContext = context).nodeType ?
- matchContext( elem, context, xml ) :
- matchAnyContext( elem, context, xml ) );
- } ];
-
- for ( ; i < len; i++ ) {
- if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
- matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
- } else {
- matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
-
- // Return special upon seeing a positional matcher
- if ( matcher[ expando ] ) {
- // Find the next relative operator (if any) for proper handling
- j = ++i;
- for ( ; j < len; j++ ) {
- if ( Expr.relative[ tokens[j].type ] ) {
- break;
- }
- }
- return setMatcher(
- i > 1 && elementMatcher( matchers ),
- i > 1 && toSelector( tokens.slice( 0, i - 1 ) ).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 ) {
- // A counter to specify which element is currently being matched
- var matcherCachedRuns = 0,
- bySet = setMatchers.length > 0,
- byElement = elementMatchers.length > 0,
- superMatcher = function( seed, context, xml, results, expandContext ) {
- var elem, j, matcher,
- setMatched = [],
- matchedCount = 0,
- i = "0",
- unmatched = seed && [],
- outermost = expandContext != null,
- contextBackup = outermostContext,
- // We must always have either seed elements or context
- elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ),
- // Use integer dirruns iff this is the outermost matcher
- dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1);
-
- if ( outermost ) {
- outermostContext = context !== document && context;
- cachedruns = matcherCachedRuns;
- }
-
- // Add elements passing elementMatchers directly to results
- // Keep `i` a string if there are no elements so `matchedCount` will be "00" below
- for ( ; (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;
- cachedruns = ++matcherCachedRuns;
- }
- }
-
- // 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, group /* 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 ( !group ) {
- group = tokenize( selector );
- }
- i = group.length;
- while ( i-- ) {
- cached = matcherFromTokens( group[i] );
- if ( cached[ expando ] ) {
- setMatchers.push( cached );
- } else {
- elementMatchers.push( cached );
- }
- }
-
- // Cache the compiled function
- cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
- }
- return cached;
- };
-
- function multipleContexts( selector, contexts, results ) {
- var i = 0,
- len = contexts.length;
- for ( ; i < len; i++ ) {
- Sizzle( selector, contexts[i], results );
- }
- return results;
- }
-
- function select( selector, context, results, seed ) {
- var i, tokens, token, type, find,
- match = tokenize( selector );
-
- if ( !seed ) {
- // Try to minimize operations if there is 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" &&
- context.nodeType === 9 && !documentIsXML &&
- Expr.relative[ tokens[1].type ] ) {
-
- context = Expr.find["ID"]( token.matches[0].replace( runescape, funescape ), context )[0];
- if ( !context ) {
- return results;
- }
-
- 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 ) && 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, slice.call( seed, 0 ) );
- return results;
- }
-
- break;
- }
- }
- }
- }
- }
-
- // Compile and execute a filtering function
- // Provide `match` to avoid retokenization if we modified the selector above
- compile( selector, match )(
- seed,
- context,
- documentIsXML,
- results,
- rsibling.test( selector )
- );
- return results;
- }
-
-// Deprecated
- Expr.pseudos["nth"] = Expr.pseudos["eq"];
-
-// Easy API for creating new setFilters
- function setFilters() {}
- Expr.filters = setFilters.prototype = Expr.pseudos;
- Expr.setFilters = new setFilters();
-
-// Initialize with the default document
- setDocument();
-
-// Override sizzle attribute retrieval
- Sizzle.attr = jQuery.attr;
- 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;
-
-
- })( window );
- var runtil = /Until$/,
- rparentsprev = /^(?:parents|prev(?:Until|All))/,
- isSimple = /^.[^:#\[\.,]*$/,
- rneedsContext = jQuery.expr.match.needsContext,
- // methods guaranteed to produce a unique set when starting from a unique set
- guaranteedUnique = {
- children: true,
- contents: true,
- next: true,
- prev: true
- };
-
- jQuery.fn.extend({
- find: function( selector ) {
- var i, ret, self,
- len = this.length;
-
- if ( typeof selector !== "string" ) {
- self = this;
- return this.pushStack( jQuery( selector ).filter(function() {
- for ( i = 0; i < len; i++ ) {
- if ( jQuery.contains( self[ i ], this ) ) {
- return true;
- }
- }
- }) );
- }
-
- ret = [];
- for ( i = 0; i < len; i++ ) {
- jQuery.find( selector, this[ 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;
- return ret;
- },
-
- 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;
- }
- }
- });
- },
-
- not: function( selector ) {
- return this.pushStack( winnow(this, selector, false) );
- },
-
- filter: function( selector ) {
- return this.pushStack( winnow(this, selector, true) );
- },
-
- is: function( selector ) {
- return !!selector && (
- typeof selector === "string" ?
- // 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".
- rneedsContext.test( selector ) ?
- jQuery( selector, this.context ).index( this[0] ) >= 0 :
- jQuery.filter( selector, this ).length > 0 :
- this.filter( selector ).length > 0 );
- },
-
- closest: function( selectors, context ) {
- var cur,
- i = 0,
- l = this.length,
- ret = [],
- pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
- jQuery( selectors, context || this.context ) :
- 0;
-
- for ( ; i < l; i++ ) {
- cur = this[i];
-
- while ( cur && cur.ownerDocument && cur !== context && cur.nodeType !== 11 ) {
- if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {
- ret.push( cur );
- break;
- }
- cur = cur.parentNode;
- }
- }
-
- return this.pushStack( ret.length > 1 ? jQuery.unique( ret ) : ret );
- },
-
- // 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 ) {
- var set = typeof selector === "string" ?
- jQuery( selector, context ) :
- jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
- all = jQuery.merge( this.get(), set );
-
- return this.pushStack( jQuery.unique(all) );
- },
-
- addBack: function( selector ) {
- return this.add( selector == null ?
- this.prevObject : this.prevObject.filter(selector)
- );
- }
- });
-
- jQuery.fn.andSelf = jQuery.fn.addBack;
-
- 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 ( !runtil.test( name ) ) {
- selector = until;
- }
-
- if ( selector && typeof selector === "string" ) {
- ret = jQuery.filter( selector, ret );
- }
-
- ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
-
- if ( this.length > 1 && rparentsprev.test( name ) ) {
- ret = ret.reverse();
- }
-
- return this.pushStack( ret );
- };
- });
-
- jQuery.extend({
- filter: function( expr, elems, not ) {
- if ( not ) {
- expr = ":not(" + expr + ")";
- }
-
- return elems.length === 1 ?
- jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :
- jQuery.find.matches(expr, elems);
- },
-
- 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;
- }
- });
-
-// Implement the identical functionality for filter and not
- function winnow( elements, qualifier, keep ) {
-
- // Can't pass null or undefined to indexOf in Firefox 4
- // Set to 0 to skip string check
- qualifier = qualifier || 0;
-
- if ( jQuery.isFunction( qualifier ) ) {
- return jQuery.grep(elements, function( elem, i ) {
- var retVal = !!qualifier.call( elem, i, elem );
- return retVal === keep;
- });
-
- } else if ( qualifier.nodeType ) {
- return jQuery.grep(elements, function( elem ) {
- return ( elem === qualifier ) === keep;
- });
-
- } else if ( typeof qualifier === "string" ) {
- var filtered = jQuery.grep(elements, function( elem ) {
- return elem.nodeType === 1;
- });
-
- if ( isSimple.test( qualifier ) ) {
- return jQuery.filter(qualifier, filtered, !keep);
- } else {
- qualifier = jQuery.filter( qualifier, filtered );
- }
- }
-
- return jQuery.grep(elements, function( elem ) {
- return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep;
- });
- }
- 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,
- manipulation_rcheckableType = /^(?:checkbox|radio)$/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: jQuery.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;
-
- jQuery.fn.extend({
- text: function( value ) {
- return jQuery.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 );
- },
-
- 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();
- },
-
- append: function() {
- return this.domManip(arguments, true, function( elem ) {
- if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
- this.appendChild( elem );
- }
- });
- },
-
- prepend: function() {
- return this.domManip(arguments, true, function( elem ) {
- if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
- this.insertBefore( elem, this.firstChild );
- }
- });
- },
-
- before: function() {
- return this.domManip( arguments, false, function( elem ) {
- if ( this.parentNode ) {
- this.parentNode.insertBefore( elem, this );
- }
- });
- },
-
- after: function() {
- return this.domManip( arguments, false, function( elem ) {
- if ( this.parentNode ) {
- this.parentNode.insertBefore( elem, this.nextSibling );
- }
- });
- },
-
- // keepData is for internal use only--do not document
- remove: function( selector, keepData ) {
- var elem,
- i = 0;
-
- for ( ; (elem = this[i]) != null; i++ ) {
- if ( !selector || jQuery.filter( selector, [ elem ] ).length > 0 ) {
- 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 jQuery.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 ) &&
- ( jQuery.support.htmlSerialize || !rnoshimcache.test( value ) ) &&
- ( jQuery.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( value ) {
- var isFunc = jQuery.isFunction( value );
-
- // Make sure that the elements are removed from the DOM before they are inserted
- // this can help fix replacing a parent with child elements
- if ( !isFunc && typeof value !== "string" ) {
- value = jQuery( value ).not( this ).detach();
- }
-
- return this.domManip( [ value ], true, function( elem ) {
- var next = this.nextSibling,
- parent = this.parentNode;
-
- if ( parent ) {
- jQuery( this ).remove();
- parent.insertBefore( elem, next );
- }
- });
- },
-
- detach: function( selector ) {
- return this.remove( selector, true );
- },
-
- domManip: function( args, table, callback ) {
-
- // Flatten any nested arrays
- args = core_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" || jQuery.support.checkClone || !rchecked.test( value ) ) ) {
- return this.each(function( index ) {
- var self = set.eq( index );
- if ( isFunction ) {
- args[0] = value.call( this, index, table ? self.html() : undefined );
- }
- self.domManip( args, table, callback );
- });
- }
-
- if ( l ) {
- fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this );
- first = fragment.firstChild;
-
- if ( fragment.childNodes.length === 1 ) {
- fragment = first;
- }
-
- if ( first ) {
- table = table && jQuery.nodeName( first, "tr" );
- 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(
- table && jQuery.nodeName( this[i], "table" ) ?
- findOrAppend( this[i], "tbody" ) :
- 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 ) {
- // Hope ajax is available...
- jQuery.ajax({
- url: node.src,
- type: "GET",
- dataType: "script",
- async: false,
- global: false,
- "throws": true
- });
- } else {
- jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) );
- }
- }
- }
- }
-
- // Fix #11809: Avoid leaking memory
- fragment = first = null;
- }
- }
-
- return this;
- }
- });
-
- function findOrAppend( elem, tag ) {
- return elem.getElementsByTagName( tag )[0] || elem.appendChild( elem.ownerDocument.createElement( tag ) );
- }
-
-// Replace/restore the type attribute of script elements for safe DOM manipulation
- function disableScript( elem ) {
- var attr = elem.getAttributeNode("type");
- elem.type = ( attr && attr.specified ) + "/" + 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 ( !jQuery.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 ( jQuery.support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) {
- dest.innerHTML = src.innerHTML;
- }
-
- } else if ( nodeName === "input" && manipulation_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.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()
- core_push.apply( ret, elems.get() );
- }
-
- return this.pushStack( ret );
- };
- });
-
- function getAll( context, tag ) {
- var elems, elem,
- i = 0,
- found = typeof context.getElementsByTagName !== core_strundefined ? context.getElementsByTagName( tag || "*" ) :
- typeof context.querySelectorAll !== core_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 ( manipulation_rcheckableType.test( elem.type ) ) {
- elem.defaultChecked = elem.checked;
- }
- }
-
- jQuery.extend({
- clone: function( elem, dataAndEvents, deepDataAndEvents ) {
- var destElements, node, clone, i, srcElements,
- inPage = jQuery.contains( elem.ownerDocument, elem );
-
- if ( jQuery.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 ( (!jQuery.support.noCloneEvent || !jQuery.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 ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
- nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) );
- }
-
- // Remove IE's autoinserted <tbody> from table fragments
- if ( !jQuery.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 ( !jQuery.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 = jQuery.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 !== core_strundefined ) {
- elem.removeAttribute( internalKey );
-
- } else {
- elem[ internalKey ] = null;
- }
-
- core_deletedIds.push( id );
- }
- }
- }
- }
- }
- });
- var iframe, getStyles, curCSS,
- ralpha = /alpha\([^)]*\)/i,
- ropacity = /opacity\s*=\s*([^)]*)/,
- rposition = /^(top|right|bottom|left)$/,
- // 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]).+)/,
- rmargin = /^margin/,
- rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ),
- rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ),
- rrelNum = new RegExp( "^([+-])=(" + core_pnum + ")", "i" ),
- elemdisplay = { BODY: "block" },
-
- cssShow = { position: "absolute", visibility: "hidden", display: "block" },
- cssNormalTransform = {
- letterSpacing: 0,
- fontWeight: 400
- },
-
- cssExpand = [ "Top", "Right", "Bottom", "Left" ],
- 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 isHidden( 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 );
- }
-
- 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", css_defaultDisplay(elem.nodeName) );
- }
- } else {
-
- if ( !values[ index ] ) {
- 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;
- }
-
- jQuery.fn.extend({
- css: function( name, value ) {
- return jQuery.access( this, function( elem, name, value ) {
- var len, styles,
- 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 ) {
- var bool = typeof state === "boolean";
-
- return this.each(function() {
- if ( bool ? state : isHidden( this ) ) {
- jQuery( this ).show();
- } else {
- jQuery( this ).hide();
- }
- });
- }
- });
-
- 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;
- }
- }
- }
- },
-
- // Exclude the following css properties to add px
- cssNumber: {
- "columnCount": true,
- "fillOpacity": true,
- "fontWeight": true,
- "lineHeight": true,
- "opacity": 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": jQuery.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 NaN and null values aren't set. See: #7116
- if ( value == null || type === "number" && isNaN( 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 ( !jQuery.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 ) {
-
- // Wrapped to prevent IE from throwing errors when 'invalid' values are provided
- // Fixes bug #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;
- },
-
- // A method for quickly swapping in/out CSS properties to get correct calculations
- 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;
- }
- });
-
-// NOTE: we've included the "window" in window.getComputedStyle
-// because jsdom on node.js will break without it.
- if ( window.getComputedStyle ) {
- getStyles = function( elem ) {
- return window.getComputedStyle( elem, null );
- };
-
- curCSS = function( elem, name, _computed ) {
- var width, minWidth, maxWidth,
- computed = _computed || getStyles( elem ),
-
- // getPropertyValue is only needed for .css('filter') in IE9, see #12537
- ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined,
- style = elem.style;
-
- 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;
- }
- }
-
- return ret;
- };
- } else if ( document.documentElement.currentStyle ) {
- getStyles = function( elem ) {
- return elem.currentStyle;
- };
-
- curCSS = function( elem, name, _computed ) {
- var left, rs, rsLeft,
- computed = _computed || getStyles( elem ),
- ret = computed ? computed[ name ] : undefined,
- style = elem.style;
-
- // 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;
- }
- }
-
- return ret === "" ? "auto" : ret;
- };
- }
-
- 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 = jQuery.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 && ( jQuery.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";
- }
-
-// Try to determine the default display value of an element
- function css_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'/>")
- .css( "cssText", "display:block !important" )
- ).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;
- doc.write("<!doctype html><html><body>");
- doc.close();
-
- display = actualDisplay( nodeName, doc );
- iframe.detach();
- }
-
- // Store the correct default display
- elemdisplay[ nodeName ] = display;
- }
-
- return display;
- }
-
-// Called ONLY from within css_defaultDisplay
- function actualDisplay( name, doc ) {
- var elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),
- display = jQuery.css( elem[0], "display" );
- elem.remove();
- return display;
- }
-
- 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 elem.offsetWidth === 0 && rdisplayswap.test( jQuery.css( elem, "display" ) ) ?
- 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,
- jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
- styles
- ) : 0
- );
- }
- };
- });
-
- if ( !jQuery.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;
- }
- };
- }
-
-// These hooks cannot be added until DOM ready because the support test
-// for it is not run until after DOM ready
- jQuery(function() {
- if ( !jQuery.support.reliableMarginRight ) {
- jQuery.cssHooks.marginRight = {
- get: 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" ] );
- }
- }
- };
- }
-
- // 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
- if ( !jQuery.support.pixelPosition && jQuery.fn.position ) {
- jQuery.each( [ "top", "left" ], function( i, prop ) {
- jQuery.cssHooks[ prop ] = {
- get: 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;
- }
- }
- };
- });
- }
-
- });
-
- if ( jQuery.expr && jQuery.expr.filters ) {
- 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 ||
- (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none");
- };
-
- jQuery.expr.filters.visible = function( elem ) {
- return !jQuery.expr.filters.hidden( elem );
- };
- }
-
-// 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;
- }
- });
- var r20 = /%20/g,
- rbracket = /\[\]$/,
- rCRLF = /\r?\n/g,
- rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
- rsubmittable = /^(?:input|select|textarea|keygen)/i;
-
- 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 || !manipulation_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();
- }
- });
-
-//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, "+" );
- };
-
- 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 );
- }
- }
- 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.hover = function( fnOver, fnOut ) {
- return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
- };
- var
- // Document location
- ajaxLocParts,
- ajaxLocation,
- ajax_nonce = jQuery.now(),
-
- ajax_rquery = /\?/,
- 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+)|)|)/,
-
- // Keep a copy of the old load method
- _load = jQuery.fn.load,
-
- /* 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( core_rnotwhite ) || [];
-
- if ( jQuery.isFunction( func ) ) {
- // For each dataType in the dataTypeExpression
- while ( (dataType = dataTypes[i++]) ) {
- // Prepend if requested
- if ( dataType[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;
- }
-
- 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 = 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.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.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"
- },
-
- // Data converters
- // Keys separate source (or catchall "*") and destination types with a single space
- converters: {
-
- // Convert anything to text
- "* text": window.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( core_rnotwhite ) || [""];
-
- // A cross-domain request is in order when we have a protocol:host:port mismatch
- if ( s.crossDomain == null ) {
- parts = rurl.exec( s.url.toLowerCase() );
- s.crossDomain = !!( parts &&
- ( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
- ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) !=
- ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) )
- );
- }
-
- // Convert data if not already a string
- if ( s.data && s.processData && typeof s.data !== "string" ) {
- s.data = jQuery.param( s.data, s.traditional );
- }
-
- // Apply prefilters
- inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
-
- // If request was aborted inside a prefilter, stop there
- if ( state === 2 ) {
- return jqXHR;
- }
-
- // We can fire global events as of now if asked to
- fireGlobals = s.global;
-
- // Watch for a new set of requests
- if ( fireGlobals && jQuery.active++ === 0 ) {
- jQuery.event.trigger("ajaxStart");
- }
-
- // Uppercase the type
- s.type = s.type.toUpperCase();
-
- // Determine if request has content
- s.hasContent = !rnoContent.test( s.type );
-
- // Save the URL in case we're toying with the If-Modified-Since
- // and/or If-None-Match header later on
- cacheURL = s.url;
-
- // More options handling for requests with no content
- if ( !s.hasContent ) {
-
- // If data is available, append data to url
- if ( s.data ) {
- cacheURL = ( s.url += ( ajax_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_=" + ajax_nonce++ ) :
-
- // Otherwise add one to the end
- cacheURL + ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ajax_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;
-
- // Get response data
- if ( responses ) {
- response = ajaxHandleResponses( s, jqXHR, responses );
- }
-
- // If successful, handle type chaining
- if ( status >= 200 && status < 300 || status === 304 ) {
-
- // 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 ) {
- isSuccess = true;
- statusText = "nocontent";
-
- // if not modified
- } else if ( status === 304 ) {
- isSuccess = true;
- statusText = "notmodified";
-
- // If we have data, let's convert it
- } else {
- isSuccess = ajaxConvert( s, response );
- statusText = isSuccess.state;
- success = isSuccess.data;
- error = isSuccess.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;
- },
-
- getScript: function( url, callback ) {
- return jQuery.get( url, undefined, callback, "script" );
- },
-
- getJSON: function( url, data, callback ) {
- return jQuery.get( url, data, callback, "json" );
- }
- });
-
- /* Handles responses to an ajax request:
- * - sets all responseXXX fields accordingly
- * - 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,
- responseFields = s.responseFields;
-
- // Fill responseXXX fields
- for ( type in responseFields ) {
- if ( type in responses ) {
- jqXHR[ responseFields[type] ] = responses[ type ];
- }
- }
-
- // 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
- function ajaxConvert( s, response ) {
- var conv2, current, conv, tmp,
- converters = {},
- i = 0,
- // Work with a copy of dataTypes in case we need to modify it for conversion
- dataTypes = s.dataTypes.slice(),
- prev = dataTypes[ 0 ];
-
- // Apply the dataFilter if provided
- if ( s.dataFilter ) {
- response = s.dataFilter( response, s.dataType );
- }
-
- // Create converters map with lowercased keys
- if ( dataTypes[ 1 ] ) {
- for ( conv in s.converters ) {
- converters[ conv.toLowerCase() ] = s.converters[ conv ];
- }
- }
-
- // Convert to each sequential dataType, tolerating list modification
- for ( ; (current = dataTypes[++i]); ) {
-
- // There's only work to do if current dataType is non-auto
- if ( current !== "*" ) {
-
- // Convert response if prev dataType is non-auto and differs from current
- 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.splice( i--, 0, current );
- }
-
- 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 };
- }
- }
- }
- }
-
- // Update prev for next iteration
- prev = current;
- }
- }
-
- return { state: "success", data: response };
- }
-// 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 + "_" + ( ajax_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 += ( ajax_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";
- }
- });
- var xhrCallbacks, xhrSupported,
- xhrId = 0,
- // #5280: Internet Explorer will keep connections alive if we don't abort on unload
- xhrOnUnloadAbort = window.ActiveXObject && function() {
- // Abort all pending requests
- var key;
- for ( key in xhrCallbacks ) {
- xhrCallbacks[ key ]( 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 ) {}
- }
-
-// Create the request object
-// (This is still attached to ajaxSettings for backward compatibility)
- jQuery.ajaxSettings.xhr = window.ActiveXObject ?
- /* Microsoft failed to properly
- * implement the XMLHttpRequest in IE7 (can't request local files),
- * so we use the ActiveXObject when it is available
- * Additionally XMLHttpRequest can be disabled in IE7/IE8 so
- * we need a fallback.
- */
- function() {
- return !this.isLocal && createStandardXHR() || createActiveXHR();
- } :
- // For all other browsers, use the standard XMLHttpRequest object
- createStandardXHR;
-
-// Determine support properties
- xhrSupported = jQuery.ajaxSettings.xhr();
- jQuery.support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
- xhrSupported = jQuery.support.ajax = !!xhrSupported;
-
-// Create transport if the browser can provide an xhr
- if ( xhrSupported ) {
-
- jQuery.ajaxTransport(function( s ) {
- // Cross domain only allowed if supported through XMLHttpRequest
- if ( !s.crossDomain || jQuery.support.cors ) {
-
- var callback;
-
- return {
- send: function( headers, complete ) {
-
- // Get a new xhr
- var handle, i,
- xhr = s.xhr();
-
- // Open the socket
- // Passing null username, generates a login popup on Opera (#2865)
- if ( s.username ) {
- xhr.open( s.type, s.url, s.async, s.username, s.password );
- } else {
- xhr.open( s.type, s.url, s.async );
- }
-
- // Apply custom fields if provided
- if ( s.xhrFields ) {
- for ( i in s.xhrFields ) {
- xhr[ i ] = s.xhrFields[ i ];
- }
- }
-
- // Override mime type if needed
- if ( s.mimeType && xhr.overrideMimeType ) {
- xhr.overrideMimeType( s.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 ( !s.crossDomain && !headers["X-Requested-With"] ) {
- headers["X-Requested-With"] = "XMLHttpRequest";
- }
-
- // Need an extra try/catch for cross domain requests in Firefox 3
- try {
- for ( i in headers ) {
- xhr.setRequestHeader( i, headers[ i ] );
- }
- } catch( err ) {}
-
- // Do send the request
- // This may raise an exception which is actually
- // handled in jQuery.ajax (so no try/catch here)
- xhr.send( ( s.hasContent && s.data ) || null );
-
- // Listener
- callback = function( _, isAbort ) {
- var status, responseHeaders, statusText, responses;
-
- // Firefox throws exceptions when accessing properties
- // of an xhr when a network error occurred
- // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:...
- try {
-
- // Was never called and is aborted or complete
- if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
-
- // Only called once
- callback = undefined;
-
- // Do not keep as active anymore
- if ( handle ) {
- xhr.onreadystatechange = jQuery.noop;
- if ( xhrOnUnloadAbort ) {
- delete xhrCallbacks[ handle ];
- }
- }
-
- // If it's an abort
- if ( isAbort ) {
- // Abort it manually if needed
- if ( xhr.readyState !== 4 ) {
- xhr.abort();
- }
- } else {
- responses = {};
- status = xhr.status;
- responseHeaders = xhr.getAllResponseHeaders();
-
- // When requesting binary data, IE6-9 will throw an exception
- // on any attempt to access responseText (#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 && s.isLocal && !s.crossDomain ) {
- status = responses.text ? 200 : 404;
- // IE - #1450: sometimes returns 1223 when it should be 204
- } else if ( status === 1223 ) {
- status = 204;
- }
- }
- }
- } catch( firefoxAccessException ) {
- if ( !isAbort ) {
- complete( -1, firefoxAccessException );
- }
- }
-
- // Call complete if needed
- if ( responses ) {
- complete( status, statusText, responses, responseHeaders );
- }
- };
-
- if ( !s.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 {
- handle = ++xhrId;
- if ( xhrOnUnloadAbort ) {
- // Create the active xhrs callbacks list if needed
- // and attach the unload handler
- if ( !xhrCallbacks ) {
- xhrCallbacks = {};
- jQuery( window ).unload( xhrOnUnloadAbort );
- }
- // Add to list of active xhrs callbacks
- xhrCallbacks[ handle ] = callback;
- }
- xhr.onreadystatechange = callback;
- }
- },
-
- abort: function() {
- if ( callback ) {
- callback( undefined, true );
- }
- }
- };
- }
- });
- }
- var fxNow, timerId,
- rfxtypes = /^(?:toggle|show|hide)$/,
- rfxnum = new RegExp( "^(?:([+-])=|)(" + core_pnum + ")([a-z%]*)$", "i" ),
- rrun = /queueHooks$/,
- animationPrefilters = [ defaultPrefilter ],
- tweeners = {
- "*": [function( prop, value ) {
- var end, unit,
- tween = this.createTween( prop, value ),
- parts = rfxnum.exec( value ),
- target = tween.cur(),
- start = +target || 0,
- scale = 1,
- maxIterations = 20;
-
- if ( parts ) {
- end = +parts[2];
- unit = parts[3] || ( jQuery.cssNumber[ prop ] ? "" : "px" );
-
- // We need to compute starting value
- if ( unit !== "px" && start ) {
- // Iteratively approximate from a nonzero starting point
- // Prefer the current property, because this process will be trivial if it uses the same units
- // Fallback to end or a simple constant
- start = jQuery.css( tween.elem, prop, true ) || end || 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 );
- }
-
- tween.unit = unit;
- tween.start = start;
- // If a +=/-= token was provided, we're doing a relative animation
- tween.end = parts[1] ? start + ( parts[1] + 1 ) * end : end;
- }
- return tween;
- }]
- };
-
-// Animations created synchronously will run synchronously
- function createFxNow() {
- setTimeout(function() {
- fxNow = undefined;
- });
- return ( fxNow = jQuery.now() );
- }
-
- function createTweens( animation, props ) {
- jQuery.each( props, function( prop, value ) {
- var collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
- index = 0,
- length = collection.length;
- for ( ; index < length; index++ ) {
- if ( collection[ index ].call( animation, prop, value ) ) {
-
- // we're done with this property
- return;
- }
- }
- });
- }
-
- 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;
- }
- }
-
- createTweens( animation, props );
-
- 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 );
- }
-
- function propFilter( props, specialEasing ) {
- var value, name, index, easing, 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;
- }
- }
- }
-
- 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 );
- }
- }
- });
-
- function defaultPrefilter( elem, props, opts ) {
- /*jshint validthis:true */
- var prop, index, length,
- value, dataShow, toggle,
- tween, hooks, oldfire,
- anim = this,
- style = elem.style,
- orig = {},
- handled = [],
- hidden = elem.nodeType && isHidden( elem );
-
- // 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
- if ( jQuery.css( elem, "display" ) === "inline" &&
- jQuery.css( elem, "float" ) === "none" ) {
-
- // inline-level elements accept inline-block;
- // block-level elements need to be inline with layout
- if ( !jQuery.support.inlineBlockNeedsLayout || css_defaultDisplay( elem.nodeName ) === "inline" ) {
- style.display = "inline-block";
-
- } else {
- style.zoom = 1;
- }
- }
- }
-
- if ( opts.overflow ) {
- style.overflow = "hidden";
- if ( !jQuery.support.shrinkWrapBlocks ) {
- anim.always(function() {
- style.overflow = opts.overflow[ 0 ];
- style.overflowX = opts.overflow[ 1 ];
- style.overflowY = opts.overflow[ 2 ];
- });
- }
- }
-
-
- // show/hide pass
- for ( index in props ) {
- value = props[ index ];
- if ( rfxtypes.exec( value ) ) {
- delete props[ index ];
- toggle = toggle || value === "toggle";
- if ( value === ( hidden ? "hide" : "show" ) ) {
- continue;
- }
- handled.push( index );
- }
- }
-
- length = handled.length;
- if ( length ) {
- dataShow = jQuery._data( elem, "fxshow" ) || jQuery._data( elem, "fxshow", {} );
- if ( "hidden" in dataShow ) {
- hidden = dataShow.hidden;
- }
-
- // 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 ( index = 0 ; index < length ; index++ ) {
- prop = handled[ index ];
- tween = anim.createTween( prop, hidden ? dataShow[ prop ] : 0 );
- orig[ prop ] = dataShow[ prop ] || jQuery.style( elem, prop );
-
- if ( !( prop in dataShow ) ) {
- dataShow[ prop ] = tween.start;
- if ( hidden ) {
- tween.end = tween.start;
- tween.start = prop === "width" || prop === "height" ? 1 : 0;
- }
- }
- }
- }
- }
-
- 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;
- }
- }
- }
- };
-
-// Remove in 2.0 - this supports IE8's 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.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 );
- };
- });
-
- 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 );
- doAnimation.finish = function() {
- anim.stop( true );
- };
- // 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.cur && hooks.cur.finish ) {
- hooks.cur.finish.call( this );
- }
-
- // 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;
- });
- }
- });
-
-// 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;
- }
-
-// 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.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.easing = {
- linear: function( p ) {
- return p;
- },
- swing: function( p ) {
- return 0.5 - Math.cos( p*Math.PI ) / 2;
- }
- };
-
- jQuery.timers = [];
- jQuery.fx = Tween.prototype.init;
- 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 ) {
- if ( timer() && jQuery.timers.push( timer ) ) {
- jQuery.fx.start();
- }
- };
-
- 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
- };
-
-// Back Compat <1.8 extension point
- jQuery.fx.step = {};
-
- if ( jQuery.expr && jQuery.expr.filters ) {
- jQuery.expr.filters.animated = function( elem ) {
- return jQuery.grep(jQuery.timers, function( fn ) {
- return elem === fn.elem;
- }).length;
- };
- }
- jQuery.fn.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 !== core_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 )
- };
- };
-
- jQuery.offset = {
-
- setOffset: function( elem, options, i ) {
- var position = jQuery.css( elem, "position" );
-
- // set position first, in-case top/left are set even on static elem
- if ( position === "static" ) {
- elem.style.position = "relative";
- }
-
- var curElem = jQuery( elem ),
- curOffset = curElem.offset(),
- curCSSTop = jQuery.css( elem, "top" ),
- curCSSLeft = jQuery.css( elem, "left" ),
- calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1,
- props = {}, curPosition = {}, curTop, curLeft;
-
- // 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({
-
- 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 it's 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 || document.documentElement;
- while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) && jQuery.css( offsetParent, "position") === "static" ) ) {
- offsetParent = offsetParent.offsetParent;
- }
- return offsetParent || document.documentElement;
- });
- }
- });
-
-
-// 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 jQuery.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 );
- };
- });
-
- function getWindow( elem ) {
- return jQuery.isWindow( elem ) ?
- elem :
- elem.nodeType === 9 ?
- elem.defaultView || elem.parentWindow :
- false;
- }
-// 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 jQuery.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 );
- };
- });
- });
-// Limit scope pollution from any deprecated API
-// (function() {
-
-// })();
-// Expose jQuery to the global object
- window.jQuery = window.$ = jQuery;
-
-// Expose jQuery as an AMD module, but only for AMD loaders that
-// understand the issues with loading multiple versions of jQuery
-// in a page that all might call define(). The loader will indicate
-// they have special allowances for multiple jQuery versions by
-// specifying define.amd.jQuery = true. Register as a named module,
-// since jQuery can be concatenated with other files that may use define,
-// but not use 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.
- if ( typeof define === "function" && define.amd && define.amd.jQuery ) {
- define( "jquery", [], function () { return jQuery; } );
- }
-
-})( window );
\ No newline at end of file
diff --git a/modules/enterprise/gui/coregui/src/main/webapp/js/jquery-1.9.1.min.js b/modules/enterprise/gui/coregui/src/main/webapp/js/jquery-1.9.1.min.js
deleted file mode 100644
index 5d9ee08..0000000
--- a/modules/enterprise/gui/coregui/src/main/webapp/js/jquery-1.9.1.min.js
+++ /dev/null
@@ -1,5 +0,0 @@
-/*! jQuery v1.9.1 | (c) 2005, 2012 jQuery Foundation, Inc. | jquery.org/license
- //@ sourceMappingURL=jquery.min.map
- */(function(e,t){var n,r,i=typeof t,o=e.document,a=e.location,s=e.jQuery,u=e.$,l={},c=[],p="1.9.1",f=c.concat,d=c.push,h=c.slice,g=c.indexOf,m=l.toString,y=l.hasOwnProperty,v=p.trim,b=function(e,t){return new b.fn.init(e,t,r)},x=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,w=/\S+/g,T=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,N=/^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,k=/^[\],:{}\s]*$/,E=/(?:^|:|,)(?:\s*\[)+/g,S=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,A=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,j=/^-ms-/,D=/-([\da-z])/gi,L=function(e,t){return t.toUpperCase()},H=function(e){(o.addEventListener||"load"===e.type||"complete"===o.readyState)&&(q(),b.ready())},q=function(){o.addEventListener?(o.removeEventListener("DOMContentLoaded",H,!1),e.removeEventListener("load",H,!1)):(o.detachEvent("onreadystatechange",H),e.detachEvent("onload",H))};b.fn=b.prototype={jquery:p,constructor:b,init:function(e,n,r){var i,a;if(!e)return this;if("string"==
typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:N.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof b?n[0]:n,b.merge(this,b.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:o,!0)),C.test(i[1])&&b.isPlainObject(n))for(i in n)b.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(a=o.getElementById(i[2]),a&&a.parentNode){if(a.id!==i[2])return r.find(e);this.length=1,this[0]=a}return this.context=o,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):b.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),b.makeArray(e,this))},selector:"",length:0,size:function(){return this.length},toArray:function(){return h.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=b.merge(this.constructor(),e);return t.prevObject=this,t.context=this.cont
ext,t},each:function(e,t){return b.each(this,e,t)},ready:function(e){return b.ready.promise().done(e),this},slice:function(){return this.pushStack(h.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(b.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:d,sort:[].sort,splice:[].splice},b.fn.init.prototype=b.fn,b.extend=b.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},u=1,l=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},u=2),"object"==typeof s||b.isFunction(s)||(s={}),l===u&&(s=this,--u);l>u;u++)if(null!=(o=arguments[u]))for(i in o)e=s[i],r=o[i],s!==r&&(c&&r&&(b.isPlainObject(r)||(n=b.isArray(r)))?(n?(n=!1,a=e&&b.isArray(e)?e:[]):a=e&&b.isPlainObject(e)?e:{},s[i]=b.extend(c,a,r)):r!==t&&(s[i]=r));return s}
,b.extend({noConflict:function(t){return e.$===b&&(e.$=u),t&&e.jQuery===b&&(e.jQuery=s),b},isReady:!1,readyWait:1,holdReady:function(e){e?b.readyWait++:b.ready(!0)},ready:function(e){if(e===!0?!--b.readyWait:!b.isReady){if(!o.body)return setTimeout(b.ready);b.isReady=!0,e!==!0&&--b.readyWait>0||(n.resolveWith(o,[b]),b.fn.trigger&&b(o).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===b.type(e)},isArray:Array.isArray||function(e){return"array"===b.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[m.call(e)]||"object":typeof e},isPlainObject:function(e){if(!e||"object"!==b.type(e)||e.nodeType||b.isWindow(e))return!1;try{if(e.constructor&&!y.call(e,"constructor")&&!y.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||y.call(e,r)},isEmptyObject:functi
on(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||o;var r=C.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=b.buildFragment([e],t,i),i&&b(i).remove(),b.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=b.trim(n),n&&k.test(n.replace(S,"@").replace(A,"]").replace(E,"")))?Function("return "+n)():(b.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||b.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&b.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){ret
urn e.replace(j,"ms-").replace(D,L)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,a=M(e);if(n){if(a){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(a){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:v&&!v.call("\ufeff\u00a0")?function(e){return null==e?"":v.call(e)}:function(e){return null==e?"":(e+"").replace(T,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(M(Object(e))?b.merge(n,"string"==typeof e?[e]:e):d.call(n,e)),n},inArray:function(e,t,n){var r;if(t){if(g)return g.call(t,e,n);for(r=t.length,n=n?0>n?Math.max(0,r+n):n:0;r>n;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,o=0;if("number"==typeof r)for(;r>o;o++)e[i++]=n[o];else while(n[o]!==t)e[i++]=n[o++];return e.length=i,e},grep:function(e,t,n){var r,i=[],o=0
,a=e.length;for(n=!!n;a>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,a=M(e),s=[];if(a)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(s[s.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(s[s.length]=r);return f.apply([],s)},guid:1,proxy:function(e,n){var r,i,o;return"string"==typeof n&&(o=e[n],n=e,e=o),b.isFunction(e)?(r=h.call(arguments,2),i=function(){return e.apply(n||this,r.concat(h.call(arguments)))},i.guid=e.guid=e.guid||b.guid++,i):t},access:function(e,n,r,i,o,a,s){var u=0,l=e.length,c=null==r;if("object"===b.type(r)){o=!0;for(u in r)b.access(e,n,u,r[u],!0,a,s)}else if(i!==t&&(o=!0,b.isFunction(i)||(s=!0),c&&(s?(n.call(e,i),n=null):(c=n,n=function(e,t,n){return c.call(b(e),n)})),n))for(;l>u;u++)n(e[u],r,s?i:i.call(e[u],u,n(e[u],r)));return o?e:c?n.call(e):l?n(e[0],r):a},now:function(){return(new Date).getTime()}}),b.ready.promise=function(t){if(!n)if(n=b.Deferred(),"complete"===o.readyState)setTimeout(b.ready);else if(o.addEventLis
tener)o.addEventListener("DOMContentLoaded",H,!1),e.addEventListener("load",H,!1);else{o.attachEvent("onreadystatechange",H),e.attachEvent("onload",H);var r=!1;try{r=null==e.frameElement&&o.documentElement}catch(i){}r&&r.doScroll&&function a(){if(!b.isReady){try{r.doScroll("left")}catch(e){return setTimeout(a,50)}q(),b.ready()}}()}return n.promise(t)},b.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){l["[object "+t+"]"]=t.toLowerCase()});function M(e){var t=e.length,n=b.type(e);return b.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}r=b(o);var _={};function F(e){var t=_[e]={};return b.each(e.match(w)||[],function(e,n){t[n]=!0}),t}b.Callbacks=function(e){e="string"==typeof e?_[e]||F(e):b.extend({},e);var n,r,i,o,a,s,u=[],l=!e.once&&[],c=function(t){for(r=e.memory&&t,i=!0,a=s||0,s=0,o=u.length,n=!0;u&&o>a;a++)if(u[a].apply(t[0],t[1])===!1&&e.stopOnFalse){r=!1;break}n=!1,u
&&(l?l.length&&c(l.shift()):r?u=[]:p.disable())},p={add:function(){if(u){var t=u.length;(function i(t){b.each(t,function(t,n){var r=b.type(n);"function"===r?e.unique&&p.has(n)||u.push(n):n&&n.length&&"string"!==r&&i(n)})})(arguments),n?o=u.length:r&&(s=t,c(r))}return this},remove:function(){return u&&b.each(arguments,function(e,t){var r;while((r=b.inArray(t,u,r))>-1)u.splice(r,1),n&&(o>=r&&o--,a>=r&&a--)}),this},has:function(e){return e?b.inArray(e,u)>-1:!(!u||!u.length)},empty:function(){return u=[],this},disable:function(){return u=l=r=t,this},disabled:function(){return!u},lock:function(){return l=t,r||p.disable(),this},locked:function(){return!l},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],!u||i&&!l||(n?l.push(t):c(t)),this},fire:function(){return p.fireWith(this,arguments),this},fired:function(){return!!i}};return p},b.extend({Deferred:function(e){var t=[["resolve","done",b.Callbacks("once memory"),"resolved"],["reject","fail",b.Callbacks("once memory
"),"rejected"],["notify","progress",b.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return b.Deferred(function(n){b.each(t,function(t,o){var a=o[0],s=b.isFunction(e[t])&&e[t];i[o[1]](function(){var e=s&&s.apply(this,arguments);e&&b.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[a+"With"](this===r?n.promise():this,s?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?b.extend(e,r):r}},i={};return r.pipe=r.then,b.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=h.call(arguments),r=n.length,i=1!==r||e&&b.isFunction(e.promise)?r:0,o=1===i?e:b.Deferred(),a=function(e,t,n){return function(r)
{t[e]=this,n[e]=arguments.length>1?h.call(arguments):r,n===s?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},s,u,l;if(r>1)for(s=Array(r),u=Array(r),l=Array(r);r>t;t++)n[t]&&b.isFunction(n[t].promise)?n[t].promise().done(a(t,l,n)).fail(o.reject).progress(a(t,u,s)):--i;return i||o.resolveWith(l,n),o.promise()}}),b.support=function(){var t,n,r,a,s,u,l,c,p,f,d=o.createElement("div");if(d.setAttribute("className","t"),d.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",n=d.getElementsByTagName("*"),r=d.getElementsByTagName("a")[0],!n||!r||!n.length)return{};s=o.createElement("select"),l=s.appendChild(o.createElement("option")),a=d.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t={getSetAttribute:"t"!==d.className,leadingWhitespace:3===d.firstChild.nodeType,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/top/.test(r.getAttribute("style")),hrefNormalized:"/a"===r.ge
tAttribute("href"),opacity:/^0.5/.test(r.style.opacity),cssFloat:!!r.style.cssFloat,checkOn:!!a.value,optSelected:l.selected,enctype:!!o.createElement("form").enctype,html5Clone:"<:nav></:nav>"!==o.createElement("nav").cloneNode(!0).outerHTML,boxModel:"CSS1Compat"===o.compatMode,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},a.checked=!0,t.noCloneChecked=a.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!l.disabled;try{delete d.test}catch(h){t.deleteExpando=!1}a=o.createElement("input"),a.setAttribute("value",""),t.input=""===a.getAttribute("value"),a.value="t",a.setAttribute("type","radio"),t.radioValue="t"===a.value,a.setAttribute("checked","t"),a.setAttribute("name","t"),u=o.createDocumentFragment(),u.appendChild(a),t.appendChecked=a.checked,t.checkClone=u.cloneNode(!0).cloneNode(!0).lastChild.checked,d.attachEvent&&(d.attachEvent("onclick",function(){t.noCloneEvent=!1}),d.clon
eNode(!0).click());for(f in{submit:!0,change:!0,focusin:!0})d.setAttribute(c="on"+f,"t"),t[f+"Bubbles"]=c in e||d.attributes[c].expando===!1;return d.style.backgroundClip="content-box",d.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===d.style.backgroundClip,b(function(){var n,r,a,s="padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",u=o.getElementsByTagName("body")[0];u&&(n=o.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",u.appendChild(n).appendChild(d),d.innerHTML="<table><tr><td></td><td>t</td></tr></table>",a=d.getElementsByTagName("td"),a[0].style.cssText="padding:0;margin:0;border:0;display:none",p=0===a[0].offsetHeight,a[0].style.display="",a[1].style.display="none",t.reliableHiddenOffsets=p&&0===a[0].offsetHeight,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-b
ox-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",t.boxSizing=4===d.offsetWidth,t.doesNotIncludeMarginInBodyOffset=1!==u.offsetTop,e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(d,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(d,null)||{width:"4px"}).width,r=d.appendChild(o.createElement("div")),r.style.cssText=d.style.cssText=s,r.style.marginRight=r.style.width="0",d.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),typeof d.style.zoom!==i&&(d.innerHTML="",d.style.cssText=s+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=3===d.offsetWidth,d.style.display="block",d.innerHTML="<div></div>",d.firstChild.style.width="5px",t.shrinkWrapBlocks=3!==d.offsetWidth,t.inlineBlockNeedsLayout&&(u.style.zoom=1)),u.removeChild(n),n=d=a=r=null)}),n=s=u=l=r=a=null,t}();var O=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,B=/([A-Z])/g;function P(e
,n,r,i){if(b.acceptData(e)){var o,a,s=b.expando,u="string"==typeof n,l=e.nodeType,p=l?b.cache:e,f=l?e[s]:e[s]&&s;if(f&&p[f]&&(i||p[f].data)||!u||r!==t)return f||(l?e[s]=f=c.pop()||b.guid++:f=s),p[f]||(p[f]={},l||(p[f].toJSON=b.noop)),("object"==typeof n||"function"==typeof n)&&(i?p[f]=b.extend(p[f],n):p[f].data=b.extend(p[f].data,n)),o=p[f],i||(o.data||(o.data={}),o=o.data),r!==t&&(o[b.camelCase(n)]=r),u?(a=o[n],null==a&&(a=o[b.camelCase(n)])):a=o,a}}function R(e,t,n){if(b.acceptData(e)){var r,i,o,a=e.nodeType,s=a?b.cache:e,u=a?e[b.expando]:b.expando;if(s[u]){if(t&&(o=n?s[u]:s[u].data)){b.isArray(t)?t=t.concat(b.map(t,b.camelCase)):t in o?t=[t]:(t=b.camelCase(t),t=t in o?[t]:t.split(" "));for(r=0,i=t.length;i>r;r++)delete o[t[r]];if(!(n?$:b.isEmptyObject)(o))return}(n||(delete s[u].data,$(s[u])))&&(a?b.cleanData([e],!0):b.support.deleteExpando||s!=s.window?delete s[u]:s[u]=null)}}}b.extend({cache:{},expando:"jQuery"+(p+Math.random()).replace(/\D/g,""),noData:{embed:!0,object
:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?b.cache[e[b.expando]]:e[b.expando],!!e&&!$(e)},data:function(e,t,n){return P(e,t,n)},removeData:function(e,t){return R(e,t)},_data:function(e,t,n){return P(e,t,n,!0)},_removeData:function(e,t){return R(e,t,!0)},acceptData:function(e){if(e.nodeType&&1!==e.nodeType&&9!==e.nodeType)return!1;var t=e.nodeName&&b.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),b.fn.extend({data:function(e,n){var r,i,o=this[0],a=0,s=null;if(e===t){if(this.length&&(s=b.data(o),1===o.nodeType&&!b._data(o,"parsedAttrs"))){for(r=o.attributes;r.length>a;a++)i=r[a].name,i.indexOf("data-")||(i=b.camelCase(i.slice(5)),W(o,i,s[i]));b._data(o,"parsedAttrs",!0)}return s}return"object"==typeof e?this.each(function(){b.data(this,e)}):b.access(this,function(n){return n===t?o?W(o,e,b.data(o,e)):null:(this.each(function(){b.data(this,e,n)}),t)},null,n,arguments.length>1,null,!0)},rem
oveData:function(e){return this.each(function(){b.removeData(this,e)})}});function W(e,n,r){if(r===t&&1===e.nodeType){var i="data-"+n.replace(B,"-$1").toLowerCase();if(r=e.getAttribute(i),"string"==typeof r){try{r="true"===r?!0:"false"===r?!1:"null"===r?null:+r+""===r?+r:O.test(r)?b.parseJSON(r):r}catch(o){}b.data(e,n,r)}else r=t}return r}function $(e){var t;for(t in e)if(("data"!==t||!b.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}b.extend({queue:function(e,n,r){var i;return e?(n=(n||"fx")+"queue",i=b._data(e,n),r&&(!i||b.isArray(r)?i=b._data(e,n,b.makeArray(r)):i.push(r)),i||[]):t},dequeue:function(e,t){t=t||"fx";var n=b.queue(e,t),r=n.length,i=n.shift(),o=b._queueHooks(e,t),a=function(){b.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),o.cur=i,i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return b._data(e,n)||b._data(e,n,{empty:b.Callbacks("once memory").add(function(){b._
removeData(e,t+"queue"),b._removeData(e,n)})})}}),b.fn.extend({queue:function(e,n){var r=2;return"string"!=typeof e&&(n=e,e="fx",r--),r>arguments.length?b.queue(this[0],e):n===t?this:this.each(function(){var t=b.queue(this,e,n);b._queueHooks(this,e),"fx"===e&&"inprogress"!==t[0]&&b.dequeue(this,e)})},dequeue:function(e){return this.each(function(){b.dequeue(this,e)})},delay:function(e,t){return e=b.fx?b.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,o=b.Deferred(),a=this,s=this.length,u=function(){--i||o.resolveWith(a,[a])};"string"!=typeof e&&(n=e,e=t),e=e||"fx";while(s--)r=b._data(a[s],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(u));return u(),o.promise(n)}});var I,z,X=/[\t\r\n]/g,U=/\r/g,V=/^(?:input|select|textarea|button|object)$/i,Y=/^(?:a|area)$/i,J=/^(?:checked|selected|autofocus|autoplay|async|controls|defer|disab
led|hidden|loop|multiple|open|readonly|required|scoped)$/i,G=/^(?:checked|selected)$/i,Q=b.support.getSetAttribute,K=b.support.input;b.fn.extend({attr:function(e,t){return b.access(this,b.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){b.removeAttr(this,e)})},prop:function(e,t){return b.access(this,b.prop,e,t,arguments.length>1)},removeProp:function(e){return e=b.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,o,a=0,s=this.length,u="string"==typeof e&&e;if(b.isFunction(e))return this.each(function(t){b(this).addClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(X," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=b.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,a=0,s=this.length,u=0===arguments.length||"string"==typeof e&&e;if(b.isFunction(e))
return this.each(function(t){b(this).removeClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(X," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?b.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e,r="boolean"==typeof t;return b.isFunction(e)?this.each(function(n){b(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var o,a=0,s=b(this),u=t,l=e.match(w)||[];while(o=l[a++])u=r?u:!s.hasClass(o),s[u?"addClass":"removeClass"](o)}else(n===i||"boolean"===n)&&(this.className&&b._data(this,"__className__",this.className),this.className=this.className||e===!1?"":b._data(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(X," ").indexOf(t)>=0)return!0;return!1},val:function(e
){var n,r,i,o=this[0];{if(arguments.length)return i=b.isFunction(e),this.each(function(n){var o,a=b(this);1===this.nodeType&&(o=i?e.call(this,n,a.val()):e,null==o?o="":"number"==typeof o?o+="":b.isArray(o)&&(o=b.map(o,function(e){return null==e?"":e+""})),r=b.valHooks[this.type]||b.valHooks[this.nodeName.toLowerCase()],r&&"set"in r&&r.set(this,o,"value")!==t||(this.value=o))});if(o)return r=b.valHooks[o.type]||b.valHooks[o.nodeName.toLowerCase()],r&&"get"in r&&(n=r.get(o,"value"))!==t?n:(n=o.value,"string"==typeof n?n.replace(U,""):null==n?"":n)}}}),b.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,a=o?null:[],s=o?i+1:r.length,u=0>i?s:o?i:0;for(;s>u;u++)if(n=r[u],!(!n.selected&&u!==i||(b.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&b.nodeName(n.parentNode,"optgroup"))){if(t=b(n).val()
,o)return t;a.push(t)}return a},set:function(e,t){var n=b.makeArray(t);return b(e).find("option").each(function(){this.selected=b.inArray(b(this).val(),n)>=0}),n.length||(e.selectedIndex=-1),n}}},attr:function(e,n,r){var o,a,s,u=e.nodeType;if(e&&3!==u&&8!==u&&2!==u)return typeof e.getAttribute===i?b.prop(e,n,r):(a=1!==u||!b.isXMLDoc(e),a&&(n=n.toLowerCase(),o=b.attrHooks[n]||(J.test(n)?z:I)),r===t?o&&a&&"get"in o&&null!==(s=o.get(e,n))?s:(typeof e.getAttribute!==i&&(s=e.getAttribute(n)),null==s?t:s):null!==r?o&&a&&"set"in o&&(s=o.set(e,r,n))!==t?s:(e.setAttribute(n,r+""),r):(b.removeAttr(e,n),t))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(w);if(o&&1===e.nodeType)while(n=o[i++])r=b.propFix[n]||n,J.test(n)?!Q&&G.test(n)?e[b.camelCase("default-"+n)]=e[r]=!1:e[r]=!1:b.attr(e,n,""),e.removeAttribute(Q?n:r)},attrHooks:{type:{set:function(e,t){if(!b.support.radioValue&&"radio"===t&&b.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},pro
pFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(e,n,r){var i,o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return a=1!==s||!b.isXMLDoc(e),a&&(n=b.propFix[n]||n,o=b.propHooks[n]),r!==t?o&&"set"in o&&(i=o.set(e,r,n))!==t?i:e[n]=r:o&&"get"in o&&null!==(i=o.get(e,n))?i:e[n]},propHooks:{tabIndex:{get:function(e){var n=e.getAttributeNode("tabindex");return n&&n.specified?parseInt(n.value,10):V.test(e.nodeName)||Y.test(e.nodeName)&&e.href?0:t}}}}),z={get:function(e,n){var r=b.prop(e,n),i="boolean"==typeof r&&e.getAttribute(n),o="boolean"==typeof r?K&&Q?null!=i:G.test(n)?e[b.camelCase("default-"+n)]:!!i:e.getAttributeNode(n);return o&&o.value!==!1?n.toLowerCase():t},set:function(e,t,n){return t===!1?b.removeAttr(e,n):K&&Q||!G.test(n)?e.setAttribute(!Q&&b.
propFix[n]||n,n):e[b.camelCase("default-"+n)]=e[n]=!0,n}},K&&Q||(b.attrHooks.value={get:function(e,n){var r=e.getAttributeNode(n);return b.nodeName(e,"input")?e.defaultValue:r&&r.specified?r.value:t},set:function(e,n,r){return b.nodeName(e,"input")?(e.defaultValue=n,t):I&&I.set(e,n,r)}}),Q||(I=b.valHooks.button={get:function(e,n){var r=e.getAttributeNode(n);return r&&("id"===n||"name"===n||"coords"===n?""!==r.value:r.specified)?r.value:t},set:function(e,n,r){var i=e.getAttributeNode(r);return i||e.setAttributeNode(i=e.ownerDocument.createAttribute(r)),i.value=n+="","value"===r||n===e.getAttribute(r)?n:t}},b.attrHooks.contenteditable={get:I.get,set:function(e,t,n){I.set(e,""===t?!1:t,n)}},b.each(["width","height"],function(e,n){b.attrHooks[n]=b.extend(b.attrHooks[n],{set:function(e,r){return""===r?(e.setAttribute(n,"auto"),r):t}})})),b.support.hrefNormalized||(b.each(["href","src","width","height"],function(e,n){b.attrHooks[n]=b.extend(b.attrHooks[n],{get:function(e){var r=e.
getAttribute(n,2);return null==r?t:r}})}),b.each(["href","src"],function(e,t){b.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}})),b.support.style||(b.attrHooks.style={get:function(e){return e.style.cssText||t},set:function(e,t){return e.style.cssText=t+""}}),b.support.optSelected||(b.propHooks.selected=b.extend(b.propHooks.selected,{get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}})),b.support.enctype||(b.propFix.enctype="encoding"),b.support.checkOn||b.each(["radio","checkbox"],function(){b.valHooks[this]={get:function(e){return null===e.getAttribute("value")?"on":e.value}}}),b.each(["radio","checkbox"],function(){b.valHooks[this]=b.extend(b.valHooks[this],{set:function(e,n){return b.isArray(n)?e.checked=b.inArray(b(e).val(),n)>=0:t}})});var Z=/^(?:input|select|textarea)$/i,et=/^key/,tt=/^(?:mouse|contextmenu)|click/,nt=/^(?:focusinfocus|focusoutblur)$/,rt=/^([^.]*)(?:\.(.+)|)$/;function it(){return!0}
function ot(){return!1}b.event={global:{},add:function(e,n,r,o,a){var s,u,l,c,p,f,d,h,g,m,y,v=b._data(e);if(v){r.handler&&(c=r,r=c.handler,a=c.selector),r.guid||(r.guid=b.guid++),(u=v.events)||(u=v.events={}),(f=v.handle)||(f=v.handle=function(e){return typeof b===i||e&&b.event.triggered===e.type?t:b.event.dispatch.apply(f.elem,arguments)},f.elem=e),n=(n||"").match(w)||[""],l=n.length;while(l--)s=rt.exec(n[l])||[],g=y=s[1],m=(s[2]||"").split(".").sort(),p=b.event.special[g]||{},g=(a?p.delegateType:p.bindType)||g,p=b.event.special[g]||{},d=b.extend({type:g,origType:y,data:o,handler:r,guid:r.guid,selector:a,needsContext:a&&b.expr.match.needsContext.test(a),namespace:m.join(".")},c),(h=u[g])||(h=u[g]=[],h.delegateCount=0,p.setup&&p.setup.call(e,o,m,f)!==!1||(e.addEventListener?e.addEventListener(g,f,!1):e.attachEvent&&e.attachEvent("on"+g,f))),p.add&&(p.add.call(e,d),d.handler.guid||(d.handler.guid=r.guid)),a?h.splice(h.delegateCount++,0,d):h.push(d),b.event.global[g]=!0;e=null
}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,p,f,d,h,g,m=b.hasData(e)&&b._data(e);if(m&&(c=m.events)){t=(t||"").match(w)||[""],l=t.length;while(l--)if(s=rt.exec(t[l])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){p=b.event.special[d]||{},d=(r?p.delegateType:p.bindType)||d,f=c[d]||[],s=s[2]&&RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),u=o=f.length;while(o--)a=f[o],!i&&g!==a.origType||n&&n.guid!==a.guid||s&&!s.test(a.namespace)||r&&r!==a.selector&&("**"!==r||!a.selector)||(f.splice(o,1),a.selector&&f.delegateCount--,p.remove&&p.remove.call(e,a));u&&!f.length&&(p.teardown&&p.teardown.call(e,h,m.handle)!==!1||b.removeEvent(e,d,m.handle),delete c[d])}else for(d in c)b.event.remove(e,d+t[l],n,r,!0);b.isEmptyObject(c)&&(delete m.handle,b._removeData(e,"events"))}},trigger:function(n,r,i,a){var s,u,l,c,p,f,d,h=[i||o],g=y.call(n,"type")?n.type:n,m=y.call(n,"namespace")?n.namespace.split("."):[];if(l=f=i=i||o,3!==i.nodeType&&8!==i.nodeType&&!nt.test(g+b.event.triggered)&&(g.
indexOf(".")>=0&&(m=g.split("."),g=m.shift(),m.sort()),u=0>g.indexOf(":")&&"on"+g,n=n[b.expando]?n:new b.Event(g,"object"==typeof n&&n),n.isTrigger=!0,n.namespace=m.join("."),n.namespace_re=n.namespace?RegExp("(^|\\.)"+m.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,n.result=t,n.target||(n.target=i),r=null==r?[n]:b.makeArray(r,[n]),p=b.event.special[g]||{},a||!p.trigger||p.trigger.apply(i,r)!==!1)){if(!a&&!p.noBubble&&!b.isWindow(i)){for(c=p.delegateType||g,nt.test(c+g)||(l=l.parentNode);l;l=l.parentNode)h.push(l),f=l;f===(i.ownerDocument||o)&&h.push(f.defaultView||f.parentWindow||e)}d=0;while((l=h[d++])&&!n.isPropagationStopped())n.type=d>1?c:p.bindType||g,s=(b._data(l,"events")||{})[n.type]&&b._data(l,"handle"),s&&s.apply(l,r),s=u&&l[u],s&&b.acceptData(l)&&s.apply&&s.apply(l,r)===!1&&n.preventDefault();if(n.type=g,!(a||n.isDefaultPrevented()||p._default&&p._default.apply(i.ownerDocument,r)!==!1||"click"===g&&b.nodeName(i,"a")||!b.acceptData(i)||!u||!i[g]||b.isWindow(i))){f=i[u],f&
&(i[u]=null),b.event.triggered=g;try{i[g]()}catch(v){}b.event.triggered=t,f&&(i[u]=f)}return n.result}},dispatch:function(e){e=b.event.fix(e);var n,r,i,o,a,s=[],u=h.call(arguments),l=(b._data(this,"events")||{})[e.type]||[],c=b.event.special[e.type]||{};if(u[0]=e,e.delegateTarget=this,!c.preDispatch||c.preDispatch.call(this,e)!==!1){s=b.event.handlers.call(this,e,l),n=0;while((o=s[n++])&&!e.isPropagationStopped()){e.currentTarget=o.elem,a=0;while((i=o.handlers[a++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(i.namespace))&&(e.handleObj=i,e.data=i.data,r=((b.event.special[i.origType]||{}).handle||i.handler).apply(o.elem,u),r!==t&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,e),e.result}},handlers:function(e,n){var r,i,o,a,s=[],u=n.delegateCount,l=e.target;if(u&&l.nodeType&&(!e.button||"click"!==e.type))for(;l!=this;l=l.parentNode||this)if(1===l.nodeType&&(l.disabled!==!0||"click"!==
e.type)){for(o=[],a=0;u>a;a++)i=n[a],r=i.selector+" ",o[r]===t&&(o[r]=i.needsContext?b(r,this).index(l)>=0:b.find(r,this,null,[l]).length),o[r]&&o.push(i);o.length&&s.push({elem:l,handlers:o})}return n.length>u&&s.push({elem:this,handlers:n.slice(u)}),s},fix:function(e){if(e[b.expando])return e;var t,n,r,i=e.type,a=e,s=this.fixHooks[i];s||(this.fixHooks[i]=s=tt.test(i)?this.mouseHooks:et.test(i)?this.keyHooks:{}),r=s.props?this.props.concat(s.props):this.props,e=new b.Event(a),t=r.length;while(t--)n=r[t],e[n]=a[n];return e.target||(e.target=a.srcElement||o),3===e.target.nodeType&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,a):e},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(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"butto
n buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,i,a,s=n.button,u=n.fromElement;return null==e.pageX&&null!=n.clientX&&(i=e.target.ownerDocument||o,a=i.documentElement,r=i.body,e.pageX=n.clientX+(a&&a.scrollLeft||r&&r.scrollLeft||0)-(a&&a.clientLeft||r&&r.clientLeft||0),e.pageY=n.clientY+(a&&a.scrollTop||r&&r.scrollTop||0)-(a&&a.clientTop||r&&r.clientTop||0)),!e.relatedTarget&&u&&(e.relatedTarget=u===e.target?n.toElement:u),e.which||s===t||(e.which=1&s?1:2&s?3:4&s?2:0),e}},special:{load:{noBubble:!0},click:{trigger:function(){return b.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):t}},focus:{trigger:function(){if(this!==o.activeElement&&this.focus)try{return this.focus(),!1}catch(e){}},delegateType:"focusin"},blur:{trigger:function(){return this===o.activeElement&&this.blur?(this.blur(),!1):t},delegateType:"focusout"},beforeunload:{postDispatch:function(e){e.result
!==t&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=b.extend(new b.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?b.event.trigger(i,null,t):b.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},b.removeEvent=o.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]===i&&(e[r]=null),e.detachEvent(r,n))},b.Event=function(e,n){return this instanceof b.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?it:ot):this.type=e,n&&b.extend(this,n),this.timeStamp=e&&e.timeStamp||b.now(),this[b.expando]=!0,t):new b.Event(e,n)},b.Event.prototype={isDefaultPrevented:ot,isPropagationStopped:ot,isImmediatePropagationStopped:ot,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=it,e&&(e.preventDefault?e.preventDefault(
):e.returnValue=!1)},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=it,e&&(e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=it,this.stopPropagation()}},b.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){b.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;
- return(!i||i!==r&&!b.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),b.support.submitBubbles||(b.event.special.submit={setup:function(){return b.nodeName(this,"form")?!1:(b.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=b.nodeName(n,"input")||b.nodeName(n,"button")?n.form:t;r&&!b._data(r,"submitBubbles")&&(b.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),b._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&b.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return b.nodeName(this,"form")?!1:(b.event.remove(this,"._submit"),t)}}),b.support.changeBubbles||(b.event.special.change={setup:function(){return Z.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(b.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)})
,b.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),b.event.simulate("change",this,e,!0)})),!1):(b.event.add(this,"beforeactivate._change",function(e){var t=e.target;Z.test(t.nodeName)&&!b._data(t,"changeBubbles")&&(b.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||b.event.simulate("change",this.parentNode,e,!0)}),b._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return b.event.remove(this,"._change"),!Z.test(this.nodeName)}}),b.support.focusinBubbles||b.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){b.event.simulate(t,e.target,b.event.fix(e),!0)};b.event.special[t]={setup:function(){0===n++&&o.addEventListener(e,r,!0)},teardown:function(){0===--n&&o.removeEventListener(e,r,!0)}}}),b.fn.exten
d({on:function(e,n,r,i,o){var a,s;if("object"==typeof e){"string"!=typeof n&&(r=r||n,n=t);for(a in e)this.on(a,n,r,e[a],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=ot;else if(!i)return this;return 1===o&&(s=i,i=function(e){return b().off(e),s.apply(this,arguments)},i.guid=s.guid||(s.guid=b.guid++)),this.each(function(){b.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,b(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=ot),this.each(function(){b.event.remove(this,e,r,n)})},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate
:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},trigger:function(e,t){return this.each(function(){b.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?b.event.trigger(e,n,r,!0):t}}),function(e,t){var n,r,i,o,a,s,u,l,c,p,f,d,h,g,m,y,v,x="sizzle"+-new Date,w=e.document,T={},N=0,C=0,k=it(),E=it(),S=it(),A=typeof t,j=1<<31,D=[],L=D.pop,H=D.push,q=D.slice,M=D.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},_="[\\x20\\t\\r\\n\\f]",F="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=F.replace("w","w#"),B="([*^$|!~]?=)",P="\\["+_+"*("+F+")"+_+"*(?:"+B+_+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+O+")|)|)"+_+"*\\]",R=":("+F+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+P.replace(3,8)+")*)|.*)\\)|)",W=RegExp("^"+_+"+|((?:^|[^\\\\])(?:\\\\.)*)"+_+"+$","g"),$=RegExp("^"+_+"*,"+_+"*"),I=RegExp("^"+_+"*([\\x20\\t\\r\\n\\f>+~])"+_+"*"),z=RegExp(R),X=RegExp("^"+O+"$"),U={ID:RegExp
("^#("+F+")"),CLASS:RegExp("^\\.("+F+")"),NAME:RegExp("^\\[name=['\"]?("+F+")['\"]?\\]"),TAG:RegExp("^("+F.replace("w","w*")+")"),ATTR:RegExp("^"+P),PSEUDO:RegExp("^"+R),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+_+"*(even|odd|(([+-]|)(\\d*)n|)"+_+"*(?:([+-]|)"+_+"*(\\d+)|))"+_+"*\\)|)","i"),needsContext:RegExp("^"+_+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+_+"*((?:-\\d)?\\d*)"+_+"*\\)|)(?=[^-]|$)","i")},V=/[\x20\t\r\n\f]*[+~]/,Y=/^[^{]+\{\s*\[native code/,J=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,G=/^(?:input|select|textarea|button)$/i,Q=/^h\d$/i,K=/'|\\/g,Z=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,et=/\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g,tt=function(e,t){var n="0x"+t-65536;return n!==n?t:0>n?String.fromCharCode(n+65536):String.fromCharCode(55296|n>>10,56320|1023&n)};try{q.call(w.documentElement.childNodes,0)[0].nodeType}catch(nt){q=function(e){var t,n=[];while(t=this[e++])n.push(t);return n}}function rt(e){return Y.test(e+"")}functi
on it(){var e,t=[];return e=function(n,r){return t.push(n+=" ")>i.cacheLength&&delete e[t.shift()],e[n]=r}}function ot(e){return e[x]=!0,e}function at(e){var t=p.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}}function st(e,t,n,r){var i,o,a,s,u,l,f,g,m,v;if((t?t.ownerDocument||t:w)!==p&&c(t),t=t||p,n=n||[],!e||"string"!=typeof e)return n;if(1!==(s=t.nodeType)&&9!==s)return[];if(!d&&!r){if(i=J.exec(e))if(a=i[1]){if(9===s){if(o=t.getElementById(a),!o||!o.parentNode)return n;if(o.id===a)return n.push(o),n}else if(t.ownerDocument&&(o=t.ownerDocument.getElementById(a))&&y(t,o)&&o.id===a)return n.push(o),n}else{if(i[2])return H.apply(n,q.call(t.getElementsByTagName(e),0)),n;if((a=i[3])&&T.getByClassName&&t.getElementsByClassName)return H.apply(n,q.call(t.getElementsByClassName(a),0)),n}if(T.qsa&&!h.test(e)){if(f=!0,g=x,m=t,v=9===s&&e,1===s&&"object"!==t.nodeName.toLowerCase()){l=ft(e),(f=t.getAttribute("id"))?g=f.replace(K,"\\$&"):t.setAttribute("id",g),g="[
id='"+g+"'] ",u=l.length;while(u--)l[u]=g+dt(l[u]);m=V.test(e)&&t.parentNode||t,v=l.join(",")}if(v)try{return H.apply(n,q.call(m.querySelectorAll(v),0)),n}catch(b){}finally{f||t.removeAttribute("id")}}}return wt(e.replace(W,"$1"),t,n,r)}a=st.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},c=st.setDocument=function(e){var n=e?e.ownerDocument||e:w;return n!==p&&9===n.nodeType&&n.documentElement?(p=n,f=n.documentElement,d=a(n),T.tagNameNoComments=at(function(e){return e.appendChild(n.createComment("")),!e.getElementsByTagName("*").length}),T.attributes=at(function(e){e.innerHTML="<select></select>";var t=typeof e.lastChild.getAttribute("multiple");return"boolean"!==t&&"string"!==t}),T.getByClassName=at(function(e){return e.innerHTML="<div class='hidden e'></div><div class='hidden'></div>",e.getElementsByClassName&&e.getElementsByClassName("e").length?(e.lastChild.className="e",2===e.getElementsByClassName("e").length):!1}),T.getB
yName=at(function(e){e.id=x+0,e.innerHTML="<a name='"+x+"'></a><div name='"+x+"'></div>",f.insertBefore(e,f.firstChild);var t=n.getElementsByName&&n.getElementsByName(x).length===2+n.getElementsByName(x+0).length;return T.getIdNotName=!n.getElementById(x),f.removeChild(e),t}),i.attrHandle=at(function(e){return e.innerHTML="<a href='#'></a>",e.firstChild&&typeof e.firstChild.getAttribute!==A&&"#"===e.firstChild.getAttribute("href")})?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},T.getIdNotName?(i.find.ID=function(e,t){if(typeof t.getElementById!==A&&!d){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},i.filter.ID=function(e){var t=e.replace(et,tt);return function(e){return e.getAttribute("id")===t}}):(i.find.ID=function(e,n){if(typeof n.getElementById!==A&&!d){var r=n.getElementById(e);return r?r.id===e||typeof r.getAttributeNode!==A&&r.getAttributeNode("id").value===e?[r]:t:[]}},i.filter.ID=function(e){var t=e
.replace(et,tt);return function(e){var n=typeof e.getAttributeNode!==A&&e.getAttributeNode("id");return n&&n.value===t}}),i.find.TAG=T.tagNameNoComments?function(e,n){return typeof n.getElementsByTagName!==A?n.getElementsByTagName(e):t}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},i.find.NAME=T.getByName&&function(e,n){return typeof n.getElementsByName!==A?n.getElementsByName(name):t},i.find.CLASS=T.getByClassName&&function(e,n){return typeof n.getElementsByClassName===A||d?t:n.getElementsByClassName(e)},g=[],h=[":focus"],(T.qsa=rt(n.querySelectorAll))&&(at(function(e){e.innerHTML="<select><option selected=''></option></select>",e.querySelectorAll("[selected]").length||h.push("\\["+_+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||h.push(":checked")}),at(function(e){e.innerHTML="<input type='hidden' i=''/>",e.querySelectorAll("[i^='']").l
ength&&h.push("[*^$]="+_+"*(?:\"\"|'')"),e.querySelectorAll(":enabled").length||h.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),h.push(",.*:")})),(T.matchesSelector=rt(m=f.matchesSelector||f.mozMatchesSelector||f.webkitMatchesSelector||f.oMatchesSelector||f.msMatchesSelector))&&at(function(e){T.disconnectedMatch=m.call(e,"div"),m.call(e,"[s!='']:x"),g.push("!=",R)}),h=RegExp(h.join("|")),g=RegExp(g.join("|")),y=rt(f.contains)||f.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},v=f.compareDocumentPosition?function(e,t){var r;return e===t?(u=!0,0):(r=t.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(t))?1&r||e.parentNode&&11===e.parentNode.nodeType?e===n||y(w,e)?-1:t===n||y(w,t)?1:0:4&r?-1:1:e.compare
DocumentPosition?-1:1}:function(e,t){var r,i=0,o=e.parentNode,a=t.parentNode,s=[e],l=[t];if(e===t)return u=!0,0;if(!o||!a)return e===n?-1:t===n?1:o?-1:a?1:0;if(o===a)return ut(e,t);r=e;while(r=r.parentNode)s.unshift(r);r=t;while(r=r.parentNode)l.unshift(r);while(s[i]===l[i])i++;return i?ut(s[i],l[i]):s[i]===w?-1:l[i]===w?1:0},u=!1,[0,0].sort(v),T.detectDuplicates=u,p):p},st.matches=function(e,t){return st(e,null,null,t)},st.matchesSelector=function(e,t){if((e.ownerDocument||e)!==p&&c(e),t=t.replace(Z,"='$1']"),!(!T.matchesSelector||d||g&&g.test(t)||h.test(t)))try{var n=m.call(e,t);if(n||T.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(r){}return st(t,p,null,[e]).length>0},st.contains=function(e,t){return(e.ownerDocument||e)!==p&&c(e),y(e,t)},st.attr=function(e,t){var n;return(e.ownerDocument||e)!==p&&c(e),d||(t=t.toLowerCase()),(n=i.attrHandle[t])?n(e):d||T.attributes?e.getAttribute(t):((n=e.getAttributeNode(t))||e.getAttribute(t))&&e[t]===!0?t:n&&n.s
pecified?n.value:null},st.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},st.uniqueSort=function(e){var t,n=[],r=1,i=0;if(u=!T.detectDuplicates,e.sort(v),u){for(;t=e[r];r++)t===e[r-1]&&(i=n.push(r));while(i--)e.splice(n[i],1)}return e};function ut(e,t){var n=t&&e,r=n&&(~t.sourceIndex||j)-(~e.sourceIndex||j);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function lt(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function ct(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function pt(e){return ot(function(t){return t=+t,ot(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}o=st.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}
else for(;t=e[r];r++)n+=o(t);return n},i=st.selectors={cacheLength:50,createPseudo:ot,match:U,find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(et,tt),e[3]=(e[4]||e[5]||"").replace(et,tt),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||st.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&st.error(e[0]),e},PSEUDO:function(e){var t,n=!e[5]&&e[2];return U.CHILD.test(e[0])?null:(e[4]?e[2]=e[4]:n&&z.test(n)&&(t=ft(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){return"*"===e?function(){return!0}:(e=e.replace(et,tt).toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=k[e+" "];
return t||(t=RegExp("(^|"+_+")"+e+"("+_+"|$)"))&&k(e,function(e){return t.test(e.className||typeof e.getAttribute!==A&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=st.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,p,f,d,h,g=o!==a?"nextSibling":"previousSibling",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!u&&!s;if(m){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){c=m[x]||(m[x]={}),l=c[e]||[],d=l[0]===N&&l[1],f=l[0]===N&&l[2],p=d&&m.childNodes[d];
while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[N,d,f];break}}else if(v&&(l=(t[x]||(t[x]={}))[e])&&l[0]===N)f=l[1];else while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(v&&((p[x]||(p[x]={}))[e]=[N,f]),p===t))break;return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||st.error("unsupported pseudo: "+e);return r[x]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?ot(function(e,n){var i,o=r(e,t),a=o.length;while(a--)i=M.call(e,o[a]),e[i]=!(n[i]=o[a])}):function(e){return r(e,0,n)}):r}},pseudos:{not:ot(function(e){var t=[],n=[],r=s(e.replace(W,"$1"));return r[x]?ot(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:ot(function(e){return function(t){return st(e,t).length>0}}),contains:ot(function(e){return function(t){return
(t.textContent||t.innerText||o(t)).indexOf(e)>-1}}),lang:ot(function(e){return X.test(e||"")||st.error("unsupported lang: "+e),e=e.replace(et,tt).toLowerCase(),function(t){var n;do if(n=d?t.getAttribute("xml:lang")||t.getAttribute("lang"):t.lang)return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===f},focus:function(e){return e===p.activeElement&&(!p.hasFocus||p.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:
function(e){return!i.pseudos.empty(e)},header:function(e){return Q.test(e.nodeName)},input:function(e){return G.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:pt(function(){return[0]}),last:pt(function(e,t){return[t-1]}),eq:pt(function(e,t,n){return[0>n?n+t:n]}),even:pt(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:pt(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:pt(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:pt(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}};for(n in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})i.pseudos[n]=lt(n);for(n in{submit:!0,reset:!0})i.pseudos[n]=ct(n);function ft(e,t){var n,r,o,a,s,u,l,c=E[e+" "];if(c)return t?0:c.slice(0);s=e,u=[],l=i.preFilter;while(
s){(!n||(r=$.exec(s)))&&(r&&(s=s.slice(r[0].length)||s),u.push(o=[])),n=!1,(r=I.exec(s))&&(n=r.shift(),o.push({value:n,type:r[0].replace(W," ")}),s=s.slice(n.length));for(a in i.filter)!(r=U[a].exec(s))||l[a]&&!(r=l[a](r))||(n=r.shift(),o.push({value:n,type:a,matches:r}),s=s.slice(n.length));if(!n)break}return t?s.length:s?st.error(e):E(e,u).slice(0)}function dt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function ht(e,t,n){var i=t.dir,o=n&&"parentNode"===i,a=C++;return t.first?function(t,n,r){while(t=t[i])if(1===t.nodeType||o)return e(t,n,r)}:function(t,n,s){var u,l,c,p=N+" "+a;if(s){while(t=t[i])if((1===t.nodeType||o)&&e(t,n,s))return!0}else while(t=t[i])if(1===t.nodeType||o)if(c=t[x]||(t[x]={}),(l=c[i])&&l[0]===p){if((u=l[1])===!0||u===r)return u===!0}else if(l=c[i]=[p],l[1]=e(t,n,s)||r,l[1]===!0)return!0}}function gt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function mt(e,t,n,r,i){var o,a=[],s
=0,u=e.length,l=null!=t;for(;u>s;s++)(o=e[s])&&(!n||n(o,r,i))&&(a.push(o),l&&t.push(s));return a}function yt(e,t,n,r,i,o){return r&&!r[x]&&(r=yt(r)),i&&!i[x]&&(i=yt(i,o)),ot(function(o,a,s,u){var l,c,p,f=[],d=[],h=a.length,g=o||xt(t||"*",s.nodeType?[s]:s,[]),m=!e||!o&&t?g:mt(g,f,e,s,u),y=n?i||(o?e:h||r)?[]:a:m;if(n&&n(m,y,s,u),r){l=mt(y,d),r(l,[],s,u),c=l.length;while(c--)(p=l[c])&&(y[d[c]]=!(m[d[c]]=p))}if(o){if(i||e){if(i){l=[],c=y.length;while(c--)(p=y[c])&&l.push(m[c]=p);i(null,y=[],l,u)}c=y.length;while(c--)(p=y[c])&&(l=i?M.call(o,p):f[c])>-1&&(o[l]=!(a[l]=p))}}else y=mt(y===a?y.splice(h,y.length):y),i?i(null,a,y,u):H.apply(a,y)})}function vt(e){var t,n,r,o=e.length,a=i.relative[e[0].type],s=a||i.relative[" "],u=a?1:0,c=ht(function(e){return e===t},s,!0),p=ht(function(e){return M.call(t,e)>-1},s,!0),f=[function(e,n,r){return!a&&(r||n!==l)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;o>u;u++)if(n=i.relative[e[u].type])f=[ht(gt(f),n)];else{if(n=i.filter[e[u].type].apply(nul
l,e[u].matches),n[x]){for(r=++u;o>r;r++)if(i.relative[e[r].type])break;return yt(u>1&>(f),u>1&&dt(e.slice(0,u-1)).replace(W,"$1"),n,r>u&&vt(e.slice(u,r)),o>r&&vt(e=e.slice(r)),o>r&&dt(e))}f.push(n)}return gt(f)}function bt(e,t){var n=0,o=t.length>0,a=e.length>0,s=function(s,u,c,f,d){var h,g,m,y=[],v=0,b="0",x=s&&[],w=null!=d,T=l,C=s||a&&i.find.TAG("*",d&&u.parentNode||u),k=N+=null==T?1:Math.random()||.1;for(w&&(l=u!==p&&u,r=n);null!=(h=C[b]);b++){if(a&&h){g=0;while(m=e[g++])if(m(h,u,c)){f.push(h);break}w&&(N=k,r=++n)}o&&((h=!m&&h)&&v--,s&&x.push(h))}if(v+=b,o&&b!==v){g=0;while(m=t[g++])m(x,y,u,c);if(s){if(v>0)while(b--)x[b]||y[b]||(y[b]=L.call(f));y=mt(y)}H.apply(f,y),w&&!s&&y.length>0&&v+t.length>1&&st.uniqueSort(f)}return w&&(N=k,l=T),x};return o?ot(s):s}s=st.compile=function(e,t){var n,r=[],i=[],o=S[e+" "];if(!o){t||(t=ft(e)),n=t.length;while(n--)o=vt(t[n]),o[x]?r.push(o):i.push(o);o=S(e,bt(i,r))}return o};function xt(e,t,n){var r=0,i=t.length;for(;i>r;r++)st(e,t[r],n);
return n}function wt(e,t,n,r){var o,a,u,l,c,p=ft(e);if(!r&&1===p.length){if(a=p[0]=p[0].slice(0),a.length>2&&"ID"===(u=a[0]).type&&9===t.nodeType&&!d&&i.relative[a[1].type]){if(t=i.find.ID(u.matches[0].replace(et,tt),t)[0],!t)return n;e=e.slice(a.shift().value.length)}o=U.needsContext.test(e)?0:a.length;while(o--){if(u=a[o],i.relative[l=u.type])break;if((c=i.find[l])&&(r=c(u.matches[0].replace(et,tt),V.test(a[0].type)&&t.parentNode||t))){if(a.splice(o,1),e=r.length&&dt(a),!e)return H.apply(n,q.call(r,0)),n;break}}}return s(e,p)(r,t,d,n,V.test(e)),n}i.pseudos.nth=i.pseudos.eq;function Tt(){}i.filters=Tt.prototype=i.pseudos,i.setFilters=new Tt,c(),st.attr=b.attr,b.find=st,b.expr=st.selectors,b.expr[":"]=b.expr.pseudos,b.unique=st.uniqueSort,b.text=st.getText,b.isXMLDoc=st.isXML,b.contains=st.contains}(e);var at=/Until$/,st=/^(?:parents|prev(?:Until|All))/,ut=/^.[^:#\[\.,]*$/,lt=b.expr.match.needsContext,ct={children:!0,contents:!0,next:!0,prev:!0};b.fn.extend({find:function(e)
{var t,n,r,i=this.length;if("string"!=typeof e)return r=this,this.pushStack(b(e).filter(function(){for(t=0;i>t;t++)if(b.contains(r[t],this))return!0}));for(n=[],t=0;i>t;t++)b.find(e,this[t],n);return n=this.pushStack(i>1?b.unique(n):n),n.selector=(this.selector?this.selector+" ":"")+e,n},has:function(e){var t,n=b(e,this),r=n.length;return this.filter(function(){for(t=0;r>t;t++)if(b.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e,!1))},filter:function(e){return this.pushStack(ft(this,e,!0))},is:function(e){return!!e&&("string"==typeof e?lt.test(e)?b(e,this.context).index(this[0])>=0:b.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n,r=0,i=this.length,o=[],a=lt.test(e)||"string"!=typeof e?b(e,t||this.context):0;for(;i>r;r++){n=this[r];while(n&&n.ownerDocument&&n!==t&&11!==n.nodeType){if(a?a.index(n)>-1:b.find.matchesSelector(n,e)){o.push(n);break}n=n.parentNode}}return this.pushStack(o.length>1?b.unique(o):o)},index:
function(e){return e?"string"==typeof e?b.inArray(this[0],b(e)):b.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?b(e,t):b.makeArray(e&&e.nodeType?[e]:e),r=b.merge(this.get(),n);return this.pushStack(b.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),b.fn.andSelf=b.fn.addBack;function pt(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}b.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return b.dir(e,"parentNode")},parentsUntil:function(e,t,n){return b.dir(e,"parentNode",n)},next:function(e){return pt(e,"nextSibling")},prev:function(e){return pt(e,"previousSibling")},nextAll:function(e){return b.dir(e,"nextSibling")},prevAll:function(e){return b.dir(e,"previousSibling")},nextUntil:function(e,t,n){return b.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return b.dir(e,"previousSibling",n)
},siblings:function(e){return b.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return b.sibling(e.firstChild)},contents:function(e){return b.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:b.merge([],e.childNodes)}},function(e,t){b.fn[e]=function(n,r){var i=b.map(this,t,n);return at.test(e)||(r=n),r&&"string"==typeof r&&(i=b.filter(r,i)),i=this.length>1&&!ct[e]?b.unique(i):i,this.length>1&&st.test(e)&&(i=i.reverse()),this.pushStack(i)}}),b.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),1===t.length?b.find.matchesSelector(t[0],e)?[t[0]]:[]:b.find.matches(e,t)},dir:function(e,n,r){var i=[],o=e[n];while(o&&9!==o.nodeType&&(r===t||1!==o.nodeType||!b(o).is(r)))1===o.nodeType&&i.push(o),o=o[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function ft(e,t,n){if(t=t||0,b.isFunction(t))return b.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return b.gre
p(e,function(e){return e===t===n});if("string"==typeof t){var r=b.grep(e,function(e){return 1===e.nodeType});if(ut.test(t))return b.filter(t,r,!n);t=b.filter(t,r)}return b.grep(e,function(e){return b.inArray(e,t)>=0===n})}function dt(e){var t=ht.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}var ht="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",gt=/ jQuery\d+="(?:null|\d+)"/g,mt=RegExp("<(?:"+ht+")[\\s/>]","i"),yt=/^\s+/,vt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bt=/<([\w:]+)/,xt=/<tbody/i,wt=/<|&#?\w+;/,Tt=/<(?:script|style|link)/i,Nt=/^(?:checkbox|radio)$/i,Ct=/checked\s*(?:[^=]|=\s*.checked.)/i,kt=/^$|\/(?:java|ecma)script/i,Et=/^true\/(.*)/,St=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,At={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>"],_default:b.support.htmlSerialize?[0,"",""]:[1,"X<div>","</div>"]},jt=dt(o),Dt=jt.appendChild(o.createElement("div"));At.optgroup=At.option,At.tbody=At.tfoot=At.colgroup=At.caption=At.thead,At.th=At.td,b.fn.extend({text:function(e){return b.access(this,function(e){return e===t?b.text(this):this.empty().append((this[0]&&this[0].ownerDocument||o).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(b.isFunction(e))return this.each(function(t){b(this).wrapAll(e.call(this,t))});if(this[0]){var t=b(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&1===e.firstChild.nodeType)e=e.firstChild;return e}).append(this)}return this},wr
apInner:function(e){return b.isFunction(e)?this.each(function(t){b(this).wrapInner(e.call(this,t))}):this.each(function(){var t=b(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=b.isFunction(e);return this.each(function(n){b(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){b.nodeName(this,"body")||b(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&this.insertBefore(e,this.firstChild)})},before:function(){return this.domManip(arguments,!1,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,!1,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},rem
ove:function(e,t){var n,r=0;for(;null!=(n=this[r]);r++)(!e||b.filter(e,[n]).length>0)&&(t||1!==n.nodeType||b.cleanData(Ot(n)),n.parentNode&&(t&&b.contains(n.ownerDocument,n)&&Mt(Ot(n,"script")),n.parentNode.removeChild(n)));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++){1===e.nodeType&&b.cleanData(Ot(e,!1));while(e.firstChild)e.removeChild(e.firstChild);e.options&&b.nodeName(e,"select")&&(e.options.length=0)}return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return b.clone(this,e,t)})},html:function(e){return b.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return 1===n.nodeType?n.innerHTML.replace(gt,""):t;if(!("string"!=typeof e||Tt.test(e)||!b.support.htmlSerialize&&mt.test(e)||!b.support.leadingWhitespace&&yt.test(e)||At[(bt.exec(e)||["",""])[1].toLowerCase()])){e=e.replace(vt,"<$1></$2>");try{for(;i>r;r++)n=this[r]||{},1===n.nodeType&&(b.cleanData(Ot(n,!1)),n.innerHTML=e);n=0}catch(o){}}n&&
this.empty().append(e)},null,e,arguments.length)},replaceWith:function(e){var t=b.isFunction(e);return t||"string"==typeof e||(e=b(e).not(this).detach()),this.domManip([e],!0,function(e){var t=this.nextSibling,n=this.parentNode;n&&(b(this).remove(),n.insertBefore(e,t))})},detach:function(e){return this.remove(e,!0)},domManip:function(e,n,r){e=f.apply([],e);var i,o,a,s,u,l,c=0,p=this.length,d=this,h=p-1,g=e[0],m=b.isFunction(g);if(m||!(1>=p||"string"!=typeof g||b.support.checkClone)&&Ct.test(g))return this.each(function(i){var o=d.eq(i);m&&(e[0]=g.call(this,i,n?o.html():t)),o.domManip(e,n,r)});if(p&&(l=b.buildFragment(e,this[0].ownerDocument,!1,this),i=l.firstChild,1===l.childNodes.length&&(l=i),i)){for(n=n&&b.nodeName(i,"tr"),s=b.map(Ot(l,"script"),Ht),a=s.length;p>c;c++)o=l,c!==h&&(o=b.clone(o,!0,!0),a&&b.merge(s,Ot(o,"script"))),r.call(n&&b.nodeName(this[c],"table")?Lt(this[c],"tbody"):this[c],o,c);if(a)for(u=s[s.length-1].ownerDocument,b.map(s,qt),c=0;a>c;c++)o=s[c],kt.te
st(o.type||"")&&!b._data(o,"globalEval")&&b.contains(u,o)&&(o.src?b.ajax({url:o.src,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0}):b.globalEval((o.text||o.textContent||o.innerHTML||"").replace(St,"")));l=i=null}return this}});function Lt(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function Ht(e){var t=e.getAttributeNode("type");return e.type=(t&&t.specified)+"/"+e.type,e}function qt(e){var t=Et.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function Mt(e,t){var n,r=0;for(;null!=(n=e[r]);r++)b._data(n,"globalEval",!t||b._data(t[r],"globalEval"))}function _t(e,t){if(1===t.nodeType&&b.hasData(e)){var n,r,i,o=b._data(e),a=b._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;i>r;r++)b.event.add(t,n,s[n][r])}a.data&&(a.data=b.extend({},a.data))}}function Ft(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!b.support.noCloneEvent&&t[b.expando]){i=b._data(
t);for(r in i.events)b.removeEvent(t,r,i.handle);t.removeAttribute(b.expando)}"script"===n&&t.text!==e.text?(Ht(t).text=e.text,qt(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),b.support.html5Clone&&e.innerHTML&&!b.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&Nt.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}}b.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){b.fn[e]=function(e){var n,r=0,i=[],o=b(e),a=o.length-1;for(;a>=r;r++)n=r===a?this:this.clone(!0),b(o[r])[t](n),d.apply(i,n.get());return this.pushStack(i)}});function Ot(e,n){var r,o,a=0,s=typeof e.getElementsByTagName!==i?e.getElementsByTagName(n||"*"):typeof e.querySelectorAll!==i?e.querySelectorAll(n||"*"):t;if(!s)for(s=[],r=e.childNodes||e;null!=(o=r[a])
;a++)!n||b.nodeName(o,n)?s.push(o):b.merge(s,Ot(o,n));return n===t||n&&b.nodeName(e,n)?b.merge([e],s):s}function Bt(e){Nt.test(e.type)&&(e.defaultChecked=e.checked)}b.extend({clone:function(e,t,n){var r,i,o,a,s,u=b.contains(e.ownerDocument,e);if(b.support.html5Clone||b.isXMLDoc(e)||!mt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(Dt.innerHTML=e.outerHTML,Dt.removeChild(o=Dt.firstChild)),!(b.support.noCloneEvent&&b.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||b.isXMLDoc(e)))for(r=Ot(o),s=Ot(e),a=0;null!=(i=s[a]);++a)r[a]&&Ft(i,r[a]);if(t)if(n)for(s=s||Ot(e),r=r||Ot(o),a=0;null!=(i=s[a]);a++)_t(i,r[a]);else _t(e,o);return r=Ot(o,"script"),r.length>0&&Mt(r,!u&&Ot(e,"script")),r=s=i=null,o},buildFragment:function(e,t,n,r){var i,o,a,s,u,l,c,p=e.length,f=dt(t),d=[],h=0;for(;p>h;h++)if(o=e[h],o||0===o)if("object"===b.type(o))b.merge(d,o.nodeType?[o]:o);else if(wt.test(o)){s=s||f.appendChild(t.createElement("div")),u=(bt.exec(o)||["",""])[1].toLowerCase(),c=At[u]||At._def
ault,s.innerHTML=c[1]+o.replace(vt,"<$1></$2>")+c[2],i=c[0];while(i--)s=s.lastChild;if(!b.support.leadingWhitespace&&yt.test(o)&&d.push(t.createTextNode(yt.exec(o)[0])),!b.support.tbody){o="table"!==u||xt.test(o)?"<table>"!==c[1]||xt.test(o)?0:s:s.firstChild,i=o&&o.childNodes.length;while(i--)b.nodeName(l=o.childNodes[i],"tbody")&&!l.childNodes.length&&o.removeChild(l)
-}b.merge(d,s.childNodes),s.textContent="";while(s.firstChild)s.removeChild(s.firstChild);s=f.lastChild}else d.push(t.createTextNode(o));s&&f.removeChild(s),b.support.appendChecked||b.grep(Ot(d,"input"),Bt),h=0;while(o=d[h++])if((!r||-1===b.inArray(o,r))&&(a=b.contains(o.ownerDocument,o),s=Ot(f.appendChild(o),"script"),a&&Mt(s),n)){i=0;while(o=s[i++])kt.test(o.type||"")&&n.push(o)}return s=null,f},cleanData:function(e,t){var n,r,o,a,s=0,u=b.expando,l=b.cache,p=b.support.deleteExpando,f=b.event.special;for(;null!=(n=e[s]);s++)if((t||b.acceptData(n))&&(o=n[u],a=o&&l[o])){if(a.events)for(r in a.events)f[r]?b.event.remove(n,r):b.removeEvent(n,r,a.handle);l[o]&&(delete l[o],p?delete n[u]:typeof n.removeAttribute!==i?n.removeAttribute(u):n[u]=null,c.push(o))}}});var Pt,Rt,Wt,$t=/alpha\([^)]*\)/i,It=/opacity\s*=\s*([^)]*)/,zt=/^(top|right|bottom|left)$/,Xt=/^(none|table(?!-c[ea]).+)/,Ut=/^margin/,Vt=RegExp("^("+x+")(.*)$","i"),Yt=RegExp("^("+x+")(?!px)[a-z%]+$","i"),Jt=RegExp("^([+-
])=("+x+")","i"),Gt={BODY:"block"},Qt={position:"absolute",visibility:"hidden",display:"block"},Kt={letterSpacing:0,fontWeight:400},Zt=["Top","Right","Bottom","Left"],en=["Webkit","O","Moz","ms"];function tn(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=en.length;while(i--)if(t=en[i]+n,t in e)return t;return r}function nn(e,t){return e=t||e,"none"===b.css(e,"display")||!b.contains(e.ownerDocument,e)}function rn(e,t){var n,r,i,o=[],a=0,s=e.length;for(;s>a;a++)r=e[a],r.style&&(o[a]=b._data(r,"olddisplay"),n=r.style.display,t?(o[a]||"none"!==n||(r.style.display=""),""===r.style.display&&nn(r)&&(o[a]=b._data(r,"olddisplay",un(r.nodeName)))):o[a]||(i=nn(r),(n&&"none"!==n||!i)&&b._data(r,"olddisplay",i?n:b.css(r,"display"))));for(a=0;s>a;a++)r=e[a],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[a]||"":"none"));return e}b.fn.extend({css:function(e,n){return b.access(this,function(e,n,r){var i,o,a={},s=0;if(b.isArray(n)){
for(o=Rt(e),i=n.length;i>s;s++)a[n[s]]=b.css(e,n[s],!1,o);return a}return r!==t?b.style(e,n,r):b.css(e,n)},e,n,arguments.length>1)},show:function(){return rn(this,!0)},hide:function(){return rn(this)},toggle:function(e){var t="boolean"==typeof e;return this.each(function(){(t?e:nn(this))?b(this).show():b(this).hide()})}}),b.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Wt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":b.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,u=b.camelCase(n),l=e.style;if(n=b.cssProps[u]||(b.cssProps[u]=tn(l,u)),s=b.cssHooks[n]||b.cssHooks[u],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:l[n];if(a=typeof r,"string"===a&&(o=Jt.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(b.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||
b.cssNumber[u]||(r+="px"),b.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(l[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{l[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,u=b.camelCase(n);return n=b.cssProps[u]||(b.cssProps[u]=tn(e.style,u)),s=b.cssHooks[n]||b.cssHooks[u],s&&"get"in s&&(a=s.get(e,!0,r)),a===t&&(a=Wt(e,n,i)),"normal"===a&&n in Kt&&(a=Kt[n]),""===r||r?(o=parseFloat(a),r===!0||b.isNumeric(o)?o||0:a):a},swap:function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i}}),e.getComputedStyle?(Rt=function(t){return e.getComputedStyle(t,null)},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),u=s?s.getPropertyValue(n)||s[n]:t,l=e.style;return s&&(""!==u||b.contains(e.ownerDocument,e)||(u=b.style(e,n)),Yt.test(u)&&Ut.test(n)&&(i=l.width,o=l.minWidth,a=l.maxWidth,l.minWidth=l.maxWidth=l.width=u,u=s.width,l.width=i,l.minWidth=o,l.maxWidth=a)),u}):o.documentElement.currentStyle&&(Rt=f
unction(e){return e.currentStyle},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),u=s?s[n]:t,l=e.style;return null==u&&l&&l[n]&&(u=l[n]),Yt.test(u)&&!zt.test(n)&&(i=l.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),l.left="fontSize"===n?"1em":u,u=l.pixelLeft+"px",l.left=i,a&&(o.left=a)),""===u?"auto":u});function on(e,t,n){var r=Vt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function an(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;for(;4>o;o+=2)"margin"===n&&(a+=b.css(e,n+Zt[o],!0,i)),r?("content"===n&&(a-=b.css(e,"padding"+Zt[o],!0,i)),"margin"!==n&&(a-=b.css(e,"border"+Zt[o]+"Width",!0,i))):(a+=b.css(e,"padding"+Zt[o],!0,i),"padding"!==n&&(a+=b.css(e,"border"+Zt[o]+"Width",!0,i)));return a}function sn(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Rt(e),a=b.support.boxSizing&&"border-box"===b.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=Wt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Yt.test(i))return i;r=a&&(b.support.bo
xSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+an(e,t,n||(a?"border":"content"),r,o)+"px"}function un(e){var t=o,n=Gt[e];return n||(n=ln(e,t),"none"!==n&&n||(Pt=(Pt||b("<iframe frameborder='0' width='0' height='0'/>").css("cssText","display:block !important")).appendTo(t.documentElement),t=(Pt[0].contentWindow||Pt[0].contentDocument).document,t.write("<!doctype html><html><body>"),t.close(),n=ln(e,t),Pt.detach()),Gt[e]=n),n}function ln(e,t){var n=b(t.createElement(e)).appendTo(t.body),r=b.css(n[0],"display");return n.remove(),r}b.each(["height","width"],function(e,n){b.cssHooks[n]={get:function(e,r,i){return r?0===e.offsetWidth&&Xt.test(b.css(e,"display"))?b.swap(e,Qt,function(){return sn(e,n,i)}):sn(e,n,i):t},set:function(e,t,r){var i=r&&Rt(e);return on(e,t,r?an(e,n,r,b.support.boxSizing&&"border-box"===b.css(e,"boxSizing",!1,i),i):0)}}}),b.support.opacity||(b.cssHooks.opacity={get:function(e,t){return It.test((t&&e.currentStyle?e.currentStyle.filter:e.style.f
ilter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=b.isNumeric(t)?"alpha(opacity="+100*t+")":"",o=r&&r.filter||n.filter||"";n.zoom=1,(t>=1||""===t)&&""===b.trim(o.replace($t,""))&&n.removeAttribute&&(n.removeAttribute("filter"),""===t||r&&!r.filter)||(n.filter=$t.test(o)?o.replace($t,i):o+" "+i)}}),b(function(){b.support.reliableMarginRight||(b.cssHooks.marginRight={get:function(e,n){return n?b.swap(e,{display:"inline-block"},Wt,[e,"marginRight"]):t}}),!b.support.pixelPosition&&b.fn.position&&b.each(["top","left"],function(e,n){b.cssHooks[n]={get:function(e,r){return r?(r=Wt(e,n),Yt.test(r)?b(e).position()[n]+"px":r):t}}})}),b.expr&&b.expr.filters&&(b.expr.filters.hidden=function(e){return 0>=e.offsetWidth&&0>=e.offsetHeight||!b.support.reliableHiddenOffsets&&"none"===(e.style&&e.style.display||b.css(e,"display"))},b.expr.filters.visible=function(e){return!b.expr.filters.hidden(e)}),b.each({margin:"",padding:"",border:"Width
"},function(e,t){b.cssHooks[e+t]={expand:function(n){var r=0,i={},o="string"==typeof n?n.split(" "):[n];for(;4>r;r++)i[e+Zt[r]+t]=o[r]||o[r-2]||o[0];return i}},Ut.test(e)||(b.cssHooks[e+t].set=on)});var cn=/%20/g,pn=/\[\]$/,fn=/\r?\n/g,dn=/^(?:submit|button|image|reset|file)$/i,hn=/^(?:input|select|textarea|keygen)/i;b.fn.extend({serialize:function(){return b.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=b.prop(this,"elements");return e?b.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!b(this).is(":disabled")&&hn.test(this.nodeName)&&!dn.test(e)&&(this.checked||!Nt.test(e))}).map(function(e,t){var n=b(this).val();return null==n?null:b.isArray(n)?b.map(n,function(e){return{name:t.name,value:e.replace(fn,"\r\n")}}):{name:t.name,value:n.replace(fn,"\r\n")}}).get()}}),b.param=function(e,n){var r,i=[],o=function(e,t){t=b.isFunction(t)?t():null==t?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};i
f(n===t&&(n=b.ajaxSettings&&b.ajaxSettings.traditional),b.isArray(e)||e.jquery&&!b.isPlainObject(e))b.each(e,function(){o(this.name,this.value)});else for(r in e)gn(r,e[r],n,o);return i.join("&").replace(cn,"+")};function gn(e,t,n,r){var i;if(b.isArray(t))b.each(t,function(t,i){n||pn.test(e)?r(e,i):gn(e+"["+("object"==typeof i?t:"")+"]",i,n,r)});else if(n||"object"!==b.type(t))r(e,t);else for(i in t)gn(e+"["+i+"]",t[i],n,r)}b.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(e,t){b.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),b.fn.hover=function(e,t){return this.mouseenter(e).mouseleave(t||e)};var mn,yn,vn=b.now(),bn=/\?/,xn=/#.*$/,wn=/([?&])_=[^&]*/,Tn=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Nn=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Cn=/^(?:GET|HEA
D)$/,kn=/^\/\//,En=/^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,Sn=b.fn.load,An={},jn={},Dn="*/".concat("*");try{yn=a.href}catch(Ln){yn=o.createElement("a"),yn.href="",yn=yn.href}mn=En.exec(yn.toLowerCase())||[];function Hn(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(w)||[];if(b.isFunction(n))while(r=o[i++])"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function qn(e,n,r,i){var o={},a=e===jn;function s(u){var l;return o[u]=!0,b.each(e[u]||[],function(e,u){var c=u(n,r,i);return"string"!=typeof c||a||o[c]?a?!(l=c):t:(n.dataTypes.unshift(c),s(c),!1)}),l}return s(n.dataTypes[0])||!o["*"]&&s("*")}function Mn(e,n){var r,i,o=b.ajaxSettings.flatOptions||{};for(i in n)n[i]!==t&&((o[i]?e:r||(r={}))[i]=n[i]);return r&&b.extend(!0,e,r),e}b.fn.load=function(e,n,r){if("string"!=typeof e&&Sn)return Sn.apply(this,arguments);var i,o,a,s=this,u=e.indexOf(" ");return u>=0&&(i=e.slice(u,e.length),e=e.slice(0,u)),
b.isFunction(n)?(r=n,n=t):n&&"object"==typeof n&&(a="POST"),s.length>0&&b.ajax({url:e,type:a,dataType:"html",data:n}).done(function(e){o=arguments,s.html(i?b("<div>").append(b.parseHTML(e)).find(i):e)}).complete(r&&function(e,t){s.each(r,o||[e.responseText,t,e])}),this},b.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){b.fn[t]=function(e){return this.on(t,e)}}),b.each(["get","post"],function(e,n){b[n]=function(e,r,i,o){return b.isFunction(r)&&(o=o||i,i=r,r=t),b.ajax({url:e,type:n,dataType:o,data:r,success:i})}}),b.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:yn,type:"GET",isLocal:Nn.test(mn[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Dn,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"},con
verters:{"* text":e.String,"text html":!0,"text json":b.parseJSON,"text xml":b.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?Mn(Mn(e,b.ajaxSettings),t):Mn(b.ajaxSettings,e)},ajaxPrefilter:Hn(An),ajaxTransport:Hn(jn),ajax:function(e,n){"object"==typeof e&&(n=e,e=t),n=n||{};var r,i,o,a,s,u,l,c,p=b.ajaxSetup({},n),f=p.context||p,d=p.context&&(f.nodeType||f.jquery)?b(f):b.event,h=b.Deferred(),g=b.Callbacks("once memory"),m=p.statusCode||{},y={},v={},x=0,T="canceled",N={readyState:0,getResponseHeader:function(e){var t;if(2===x){if(!c){c={};while(t=Tn.exec(a))c[t[1].toLowerCase()]=t[2]}t=c[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return 2===x?a:null},setRequestHeader:function(e,t){var n=e.toLowerCase();return x||(e=v[n]=v[n]||e,y[e]=t),this},overrideMimeType:function(e){return x||(p.mimeType=e),this},statusCode:function(e){var t;if(e)if(2>x)for(t in e)m[t]=[m[t],e[t]];else N.always(e[N.status]);return this},abort:functi
on(e){var t=e||T;return l&&l.abort(t),k(0,t),this}};if(h.promise(N).complete=g.add,N.success=N.done,N.error=N.fail,p.url=((e||p.url||yn)+"").replace(xn,"").replace(kn,mn[1]+"//"),p.type=n.method||n.type||p.method||p.type,p.dataTypes=b.trim(p.dataType||"*").toLowerCase().match(w)||[""],null==p.crossDomain&&(r=En.exec(p.url.toLowerCase()),p.crossDomain=!(!r||r[1]===mn[1]&&r[2]===mn[2]&&(r[3]||("http:"===r[1]?80:443))==(mn[3]||("http:"===mn[1]?80:443)))),p.data&&p.processData&&"string"!=typeof p.data&&(p.data=b.param(p.data,p.traditional)),qn(An,p,n,N),2===x)return N;u=p.global,u&&0===b.active++&&b.event.trigger("ajaxStart"),p.type=p.type.toUpperCase(),p.hasContent=!Cn.test(p.type),o=p.url,p.hasContent||(p.data&&(o=p.url+=(bn.test(o)?"&":"?")+p.data,delete p.data),p.cache===!1&&(p.url=wn.test(o)?o.replace(wn,"$1_="+vn++):o+(bn.test(o)?"&":"?")+"_="+vn++)),p.ifModified&&(b.lastModified[o]&&N.setRequestHeader("If-Modified-Since",b.lastModified[o]),b.etag[o]&&N.setRequestHeader("I
f-None-Match",b.etag[o])),(p.data&&p.hasContent&&p.contentType!==!1||n.contentType)&&N.setRequestHeader("Content-Type",p.contentType),N.setRequestHeader("Accept",p.dataTypes[0]&&p.accepts[p.dataTypes[0]]?p.accepts[p.dataTypes[0]]+("*"!==p.dataTypes[0]?", "+Dn+"; q=0.01":""):p.accepts["*"]);for(i in p.headers)N.setRequestHeader(i,p.headers[i]);if(p.beforeSend&&(p.beforeSend.call(f,N,p)===!1||2===x))return N.abort();T="abort";for(i in{success:1,error:1,complete:1})N[i](p[i]);if(l=qn(jn,p,n,N)){N.readyState=1,u&&d.trigger("ajaxSend",[N,p]),p.async&&p.timeout>0&&(s=setTimeout(function(){N.abort("timeout")},p.timeout));try{x=1,l.send(y,k)}catch(C){if(!(2>x))throw C;k(-1,C)}}else k(-1,"No Transport");function k(e,n,r,i){var c,y,v,w,T,C=n;2!==x&&(x=2,s&&clearTimeout(s),l=t,a=i||"",N.readyState=e>0?4:0,r&&(w=_n(p,N,r)),e>=200&&300>e||304===e?(p.ifModified&&(T=N.getResponseHeader("Last-Modified"),T&&(b.lastModified[o]=T),T=N.getResponseHeader("etag"),T&&(b.etag[o]=T)),204===e?(c=!0,C
="nocontent"):304===e?(c=!0,C="notmodified"):(c=Fn(p,w),C=c.state,y=c.data,v=c.error,c=!v)):(v=C,(e||!C)&&(C="error",0>e&&(e=0))),N.status=e,N.statusText=(n||C)+"",c?h.resolveWith(f,[y,C,N]):h.rejectWith(f,[N,C,v]),N.statusCode(m),m=t,u&&d.trigger(c?"ajaxSuccess":"ajaxError",[N,p,c?y:v]),g.fireWith(f,[N,C]),u&&(d.trigger("ajaxComplete",[N,p]),--b.active||b.event.trigger("ajaxStop")))}return N},getScript:function(e,n){return b.get(e,t,n,"script")},getJSON:function(e,t,n){return b.get(e,t,n,"json")}});function _n(e,n,r){var i,o,a,s,u=e.contents,l=e.dataTypes,c=e.responseFields;for(s in c)s in r&&(n[c[s]]=r[s]);while("*"===l[0])l.shift(),o===t&&(o=e.mimeType||n.getResponseHeader("Content-Type"));if(o)for(s in u)if(u[s]&&u[s].test(o)){l.unshift(s);break}if(l[0]in r)a=l[0];else{for(s in r){if(!l[0]||e.converters[s+" "+l[0]]){a=s;break}i||(i=s)}a=a||i}return a?(a!==l[0]&&l.unshift(a),r[a]):t}function Fn(e,t){var n,r,i,o,a={},s=0,u=e.dataTypes.slice(),l=u[0];if(e.dataFilter&&(t=e.d
ataFilter(t,e.dataType)),u[1])for(i in e.converters)a[i.toLowerCase()]=e.converters[i];for(;r=u[++s];)if("*"!==r){if("*"!==l&&l!==r){if(i=a[l+" "+r]||a["* "+r],!i)for(n in a)if(o=n.split(" "),o[1]===r&&(i=a[l+" "+o[0]]||a["* "+o[0]])){i===!0?i=a[n]:a[n]!==!0&&(r=o[0],u.splice(s--,0,r));break}if(i!==!0)if(i&&e["throws"])t=i(t);else try{t=i(t)}catch(c){return{state:"parsererror",error:i?c:"No conversion from "+l+" to "+r}}}l=r}return{state:"success",data:t}}b.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(e){return b.globalEval(e),e}}}),b.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),b.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=o.head||b("head")[0]||o.documentElement;return{send:function(t,i){n=o.createElement("script"),n.async=!0,e.scriptCharset&&(n.chars
et=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,t){(t||!n.readyState||/loaded|complete/.test(n.readyState))&&(n.onload=n.onreadystatechange=null,n.parentNode&&n.parentNode.removeChild(n),n=null,t||i(200,"success"))},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(t,!0)}}}});var On=[],Bn=/(=)\?(?=&|$)|\?\?/;b.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=On.pop()||b.expando+"_"+vn++;return this[e]=!0,e}}),b.ajaxPrefilter("json jsonp",function(n,r,i){var o,a,s,u=n.jsonp!==!1&&(Bn.test(n.url)?"url":"string"==typeof n.data&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Bn.test(n.data)&&"data");return u||"jsonp"===n.dataTypes[0]?(o=n.jsonpCallback=b.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,u?n[u]=n[u].replace(Bn,"$1"+o):n.jsonp!==!1&&(n.url+=(bn.test(n.url)?"&":"?")+n.jsonp+"="+o),n.converters["script json"]=function(){return s||b.error(o+" was not called"),s[0]},n.dataTypes[0]="json",a=e
[o],e[o]=function(){s=arguments},i.always(function(){e[o]=a,n[o]&&(n.jsonpCallback=r.jsonpCallback,On.push(o)),s&&b.isFunction(a)&&a(s[0]),s=a=t}),"script"):t});var Pn,Rn,Wn=0,$n=e.ActiveXObject&&function(){var e;for(e in Pn)Pn[e](t,!0)};function In(){try{return new e.XMLHttpRequest}catch(t){}}function zn(){try{return new e.ActiveXObject("Microsoft.XMLHTTP")}catch(t){}}b.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&In()||zn()}:In,Rn=b.ajaxSettings.xhr(),b.support.cors=!!Rn&&"withCredentials"in Rn,Rn=b.support.ajax=!!Rn,Rn&&b.ajaxTransport(function(n){if(!n.crossDomain||b.support.cors){var r;return{send:function(i,o){var a,s,u=n.xhr();if(n.username?u.open(n.type,n.url,n.async,n.username,n.password):u.open(n.type,n.url,n.async),n.xhrFields)for(s in n.xhrFields)u[s]=n.xhrFields[s];n.mimeType&&u.overrideMimeType&&u.overrideMimeType(n.mimeType),n.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest");try{for(s in i)u.setRequestHeader(s,i[
s])}catch(l){}u.send(n.hasContent&&n.data||null),r=function(e,i){var s,l,c,p;try{if(r&&(i||4===u.readyState))if(r=t,a&&(u.onreadystatechange=b.noop,$n&&delete Pn[a]),i)4!==u.readyState&&u.abort();else{p={},s=u.status,l=u.getAllResponseHeaders(),"string"==typeof u.responseText&&(p.text=u.responseText);try{c=u.statusText}catch(f){c=""}s||!n.isLocal||n.crossDomain?1223===s&&(s=204):s=p.text?200:404}}catch(d){i||o(-1,d)}p&&o(s,c,p,l)},n.async?4===u.readyState?setTimeout(r):(a=++Wn,$n&&(Pn||(Pn={},b(e).unload($n)),Pn[a]=r),u.onreadystatechange=r):r()},abort:function(){r&&r(t,!0)}}}});var Xn,Un,Vn=/^(?:toggle|show|hide)$/,Yn=RegExp("^(?:([+-])=|)("+x+")([a-z%]*)$","i"),Jn=/queueHooks$/,Gn=[nr],Qn={"*":[function(e,t){var n,r,i=this.createTween(e,t),o=Yn.exec(t),a=i.cur(),s=+a||0,u=1,l=20;if(o){if(n=+o[2],r=o[3]||(b.cssNumber[e]?"":"px"),"px"!==r&&s){s=b.css(i.elem,e,!0)||n||1;do u=u||".5",s/=u,b.style(i.elem,e,s+r);while(u!==(u=i.cur()/a)&&1!==u&&--l)}i.unit=r,i.start=s,i.end=o[1]?
s+(o[1]+1)*n:n}return i}]};function Kn(){return setTimeout(function(){Xn=t}),Xn=b.now()}function Zn(e,t){b.each(t,function(t,n){var r=(Qn[t]||[]).concat(Qn["*"]),i=0,o=r.length;for(;o>i;i++)if(r[i].call(e,t,n))return})}function er(e,t,n){var r,i,o=0,a=Gn.length,s=b.Deferred().always(function(){delete u.elem}),u=function(){if(i)return!1;var t=Xn||Kn(),n=Math.max(0,l.startTime+l.duration-t),r=n/l.duration||0,o=1-r,a=0,u=l.tweens.length;for(;u>a;a++)l.tweens[a].run(o);return s.notifyWith(e,[l,o,n]),1>o&&u?n:(s.resolveWith(e,[l]),!1)},l=s.promise({elem:e,props:b.extend({},t),opts:b.extend(!0,{specialEasing:{}},n),originalProperties:t,originalOptions:n,startTime:Xn||Kn(),duration:n.duration,tweens:[],createTween:function(t,n){var r=b.Tween(e,l.opts,t,n,l.opts.specialEasing[t]||l.opts.easing);return l.tweens.push(r),r},stop:function(t){var n=0,r=t?l.tweens.length:0;if(i)return this;for(i=!0;r>n;n++)l.tweens[n].run(1);return t?s.resolveWith(e,[l,t]):s.rejectWith(e,[l,t]),this}}),c=
l.props;for(tr(c,l.opts.specialEasing);a>o;o++)if(r=Gn[o].call(l,e,c,l.opts))return r;return Zn(l,c),b.isFunction(l.opts.start)&&l.opts.start.call(e,l),b.fx.timer(b.extend(u,{elem:e,anim:l,queue:l.opts.queue})),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always)}function tr(e,t){var n,r,i,o,a;for(i in e)if(r=b.camelCase(i),o=t[r],n=e[i],b.isArray(n)&&(o=n[1],n=e[i]=n[0]),i!==r&&(e[r]=n,delete e[i]),a=b.cssHooks[r],a&&"expand"in a){n=a.expand(n),delete e[r];for(i in n)i in e||(e[i]=n[i],t[i]=o)}else t[r]=o}b.Animation=b.extend(er,{tweener:function(e,t){b.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;i>r;r++)n=e[r],Qn[n]=Qn[n]||[],Qn[n].unshift(t)},prefilter:function(e,t){t?Gn.unshift(e):Gn.push(e)}});function nr(e,t,n){var r,i,o,a,s,u,l,c,p,f=this,d=e.style,h={},g=[],m=e.nodeType&&nn(e);n.queue||(c=b._queueHooks(e,"fx"),null==c.unqueued&&(c.unqueued=0,p=c.empty.fire,c.empty.fire=function(){c.unqueued||p(
)}),c.unqueued++,f.always(function(){f.always(function(){c.unqueued--,b.queue(e,"fx").length||c.empty.fire()})})),1===e.nodeType&&("height"in t||"width"in t)&&(n.overflow=[d.overflow,d.overflowX,d.overflowY],"inline"===b.css(e,"display")&&"none"===b.css(e,"float")&&(b.support.inlineBlockNeedsLayout&&"inline"!==un(e.nodeName)?d.zoom=1:d.display="inline-block")),n.overflow&&(d.overflow="hidden",b.support.shrinkWrapBlocks||f.always(function(){d.overflow=n.overflow[0],d.overflowX=n.overflow[1],d.overflowY=n.overflow[2]}));for(i in t)if(a=t[i],Vn.exec(a)){if(delete t[i],u=u||"toggle"===a,a===(m?"hide":"show"))continue;g.push(i)}if(o=g.length){s=b._data(e,"fxshow")||b._data(e,"fxshow",{}),"hidden"in s&&(m=s.hidden),u&&(s.hidden=!m),m?b(e).show():f.done(function(){b(e).hide()}),f.done(function(){var t;b._removeData(e,"fxshow");for(t in h)b.style(e,t,h[t])});for(i=0;o>i;i++)r=g[i],l=f.createTween(r,m?s[r]:0),h[r]=s[r]||b.style(e,r),r in s||(s[r]=l.start,m&&(l.end=l.start,l.start="wi
dth"===r||"height"===r?1:0))}}function rr(e,t,n,r,i){return new rr.prototype.init(e,t,n,r,i)}b.Tween=rr,rr.prototype={constructor:rr,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||"swing",this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(b.cssNumber[n]?"":"px")},cur:function(){var e=rr.propHooks[this.prop];return e&&e.get?e.get(this):rr.propHooks._default.get(this)},run:function(e){var t,n=rr.propHooks[this.prop];return this.pos=t=this.options.duration?b.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):rr.propHooks._default.set(this),this}},rr.prototype.init.prototype=rr.prototype,rr.propHooks={_default:{get:function(e){var t;return null==e.elem[e.prop]||e.elem.style&&null!=e.elem.style[e.prop]?(t=b.css(e.elem,e.prop,""),t&&"auto"!==t?t:0):e.elem[e.prop]},set:function(e){b.fx.step
[e.prop]?b.fx.step[e.prop](e):e.elem.style&&(null!=e.elem.style[b.cssProps[e.prop]]||b.cssHooks[e.prop])?b.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}},rr.propHooks.scrollTop=rr.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},b.each(["toggle","show","hide"],function(e,t){var n=b.fn[t];b.fn[t]=function(e,r,i){return null==e||"boolean"==typeof e?n.apply(this,arguments):this.animate(ir(t,!0),e,r,i)}}),b.fn.extend({fadeTo:function(e,t,n,r){return this.filter(nn).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=b.isEmptyObject(e),o=b.speed(t,n,r),a=function(){var t=er(this,b.extend({},e),o);a.finish=function(){t.stop(!0)},(i||b._data(this,"finish"))&&t.stop(!0)};return a.finish=a,i||o.queue===!1?this.each(a):this.queue(o.queue,a)},stop:function(e,n,r){var i=function(e){var t=e.stop;delete e.stop,t(r)};return"string"!=typeof e&&(r=n,n=e,e=t),n&&e!==!1&&this.queue(e||"fx",[]),th
is.each(function(){var t=!0,n=null!=e&&e+"queueHooks",o=b.timers,a=b._data(this);if(n)a[n]&&a[n].stop&&i(a[n]);else for(n in a)a[n]&&a[n].stop&&Jn.test(n)&&i(a[n]);for(n=o.length;n--;)o[n].elem!==this||null!=e&&o[n].queue!==e||(o[n].anim.stop(r),t=!1,o.splice(n,1));(t||!r)&&b.dequeue(this,e)})},finish:function(e){return e!==!1&&(e=e||"fx"),this.each(function(){var t,n=b._data(this),r=n[e+"queue"],i=n[e+"queueHooks"],o=b.timers,a=r?r.length:0;for(n.finish=!0,b.queue(this,e,[]),i&&i.cur&&i.cur.finish&&i.cur.finish.call(this),t=o.length;t--;)o[t].elem===this&&o[t].queue===e&&(o[t].anim.stop(!0),o.splice(t,1));for(t=0;a>t;t++)r[t]&&r[t].finish&&r[t].finish.call(this);delete n.finish})}});function ir(e,t){var n,r={height:e},i=0;for(t=t?1:0;4>i;i+=2-t)n=Zt[i],r["margin"+n]=r["padding"+n]=e;return t&&(r.opacity=r.width=e),r}b.each({slideDown:ir("show"),slideUp:ir("hide"),slideToggle:ir("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},functio
n(e,t){b.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),b.speed=function(e,t,n){var r=e&&"object"==typeof e?b.extend({},e):{complete:n||!n&&t||b.isFunction(e)&&e,duration:e,easing:n&&t||t&&!b.isFunction(t)&&t};return r.duration=b.fx.off?0:"number"==typeof r.duration?r.duration:r.duration in b.fx.speeds?b.fx.speeds[r.duration]:b.fx.speeds._default,(null==r.queue||r.queue===!0)&&(r.queue="fx"),r.old=r.complete,r.complete=function(){b.isFunction(r.old)&&r.old.call(this),r.queue&&b.dequeue(this,r.queue)},r},b.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2}},b.timers=[],b.fx=rr.prototype.init,b.fx.tick=function(){var e,n=b.timers,r=0;for(Xn=b.now();n.length>r;r++)e=n[r],e()||n[r]!==e||n.splice(r--,1);n.length||b.fx.stop(),Xn=t},b.fx.timer=function(e){e()&&b.timers.push(e)&&b.fx.start()},b.fx.interval=13,b.fx.start=function(){Un||(Un=setInterval(b.fx.tick,b.fx.interval))},b.fx.stop=function(){clearInterval(Un),Un=null},b.fx.speeds={slo
w:600,fast:200,_default:400},b.fx.step={},b.expr&&b.expr.filters&&(b.expr.filters.animated=function(e){return b.grep(b.timers,function(t){return e===t.elem}).length}),b.fn.offset=function(e){if(arguments.length)return e===t?this:this.each(function(t){b.offset.setOffset(this,e,t)});var n,r,o={top:0,left:0},a=this[0],s=a&&a.ownerDocument;if(s)return n=s.documentElement,b.contains(n,a)?(typeof a.getBoundingClientRect!==i&&(o=a.getBoundingClientRect()),r=or(s),{top:o.top+(r.pageYOffset||n.scrollTop)-(n.clientTop||0),left:o.left+(r.pageXOffset||n.scrollLeft)-(n.clientLeft||0)}):o},b.offset={setOffset:function(e,t,n){var r=b.css(e,"position");"static"===r&&(e.style.position="relative");var i=b(e),o=i.offset(),a=b.css(e,"top"),s=b.css(e,"left"),u=("absolute"===r||"fixed"===r)&&b.inArray("auto",[a,s])>-1,l={},c={},p,f;u?(c=i.position(),p=c.top,f=c.left):(p=parseFloat(a)||0,f=parseFloat(s)||0),b.isFunction(t)&&(t=t.call(e,n,o)),null!=t.top&&(l.top=t.top-o.top+p),null!=t.left&&(l.left
=t.left-o.left+f),"using"in t?t.using.call(e,l):i.css(l)}},b.fn.extend({position:function(){if(this[0]){var e,t,n={top:0,left:0},r=this[0];return"fixed"===b.css(r,"position")?t=r.getBoundingClientRect():(e=this.offsetParent(),t=this.offset(),b.nodeName(e[0],"html")||(n=e.offset()),n.top+=b.css(e[0],"borderTopWidth",!0),n.left+=b.css(e[0],"borderLeftWidth",!0)),{top:t.top-n.top-b.css(r,"marginTop",!0),left:t.left-n.left-b.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||o.documentElement;while(e&&!b.nodeName(e,"html")&&"static"===b.css(e,"position"))e=e.offsetParent;return e||o.documentElement})}}),b.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);b.fn[e]=function(i){return b.access(this,function(e,i,o){var a=or(e);return o===t?a?n in a?a[n]:a.document.documentElement[i]:e[i]:(a?a.scrollTo(r?b(a).scrollLeft():o,r?o:b(a).scrollTop()):e[i]=o,t)},e,i,arguments.length,null)}});function or
(e){return b.isWindow(e)?e:9===e.nodeType?e.defaultView||e.parentWindow:!1}b.each({Height:"height",Width:"width"},function(e,n){b.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){b.fn[i]=function(i,o){var a=arguments.length&&(r||"boolean"!=typeof i),s=r||(i===!0||o===!0?"margin":"border");return b.access(this,function(n,r,i){var o;return b.isWindow(n)?n.document.documentElement["client"+e]:9===n.nodeType?(o=n.documentElement,Math.max(n.body["scroll"+e],o["scroll"+e],n.body["offset"+e],o["offset"+e],o["client"+e])):i===t?b.css(n,r,s):b.style(n,r,i,s)},n,a?i:t,a,null)}})}),e.jQuery=e.$=b,"function"==typeof define&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return b})})(window);
\ No newline at end of file
diff --git a/modules/enterprise/gui/coregui/src/main/webapp/js/rhq.js b/modules/enterprise/gui/coregui/src/main/webapp/js/rhq.js
index ef65e69..7e89bb1 100644
--- a/modules/enterprise/gui/coregui/src/main/webapp/js/rhq.js
+++ b/modules/enterprise/gui/coregui/src/main/webapp/js/rhq.js
@@ -1,12 +1,7 @@
/**
- * Charting Javascript Functions.
+ * RHQ Charting Javascript Functions.
*/
-// Handle browsers not supporting console object
-if (!window.console) window.console = {};
-if (!window.console.log) window.console.log = function () {
-};
-
/**
* ChartContext Constructor Object
* Contains all of the data required to render a chart.
@@ -38,13 +33,13 @@ if (!window.console.log) window.console.log = function () {
* @param singleValueLabel
* @param chartXaxisTimeFormatHours
* @param chartXaxisTimeFormatHoursMinutes
- * @param showLegend
+ * @param hideLegend
* @constructor
*/
var ChartContext = function (chartId, chartHeight, metricsData, xAxisLabel, chartTitle, yAxisUnits, minChartTitle, avgChartTitle, peakChartTitle, dateLabel, timeLabel, downLabel, unknownLabel, noDataLabel, hoverStartLabel, hoverEndLabel, hoverPeriodLabel, hoverBarLabel, chartHoverTimeFormat, chartHoverDateFormat, isPortalGraph, portalId, buttonBarDateTimeFormat, singleValueLabel, chartXaxisTimeFormatHours, chartXaxisTimeFormatHoursMinutes, hideLegend) {
"use strict";
if (!(this instanceof ChartContext)) {
- throw new Error("ChartContext function cannot be called as a function.")
+ throw new Error("ChartContext function cannot be called as a function.");
}
this.chartId = chartId;
this.chartHeight = chartHeight;
@@ -103,7 +98,7 @@ var ChartContext = function (chartId, chartHeight, metricsData, xAxisLabel, char
AvailChartContext = function (chartId, availData, dateLabel, timeLabel, hoverStartLabel, hoverBarLabel, availabilityLabel, chartHoverTimeFormat, chartHoverDateFormat, chartTitle, chartUpLabel, chartDownLabel, chartXaxisTimeFormatHours, chartXaxisTimeFormatHoursMinutes) {
"use strict";
if (!(this instanceof AvailChartContext)) {
- throw new Error("AvailChartContext function cannot be called as a function.")
+ throw new Error("AvailChartContext function cannot be called as a function.");
}
this.chartId = chartId;
this.chartHandle = "#availChart-" + this.chartId;
@@ -133,12 +128,13 @@ var ChartContext = function (chartId, chartHeight, metricsData, xAxisLabel, char
GraphDateContext = function (startDate, endDate) {
"use strict";
if (!(this instanceof GraphDateContext)) {
- throw new Error("GraphDateContext function cannot be called as a function.")
+ throw new Error("GraphDateContext function cannot be called as a function.");
}
this.startDate = startDate;
this.endDate = endDate;
},
rhqCommon = (function () {
+ "use strict";
var timeFormat = function (formats) {
@@ -146,7 +142,7 @@ var ChartContext = function (chartId, chartHeight, metricsData, xAxisLabel, char
var i = formats.length - 1, f = formats[i];
while (!f[1](date)) f = formats[--i];
return f[0](date);
- }
+ };
};
return {
@@ -179,7 +175,7 @@ var ChartContext = function (chartId, chartHeight, metricsData, xAxisLabel, char
]);
}
- }
+ };
})();
commit 1ad43fd38d868509ce6a2bc4d3919435fa136e73
Author: Mike Thompson <mithomps(a)redhat.com>
Date: Thu Aug 8 15:07:07 2013 -0700
Replaced UserPreferencesMeasurementRangeEditor with ButtonBarDateTimeRangeEditor in Group --> Monitoring --> Metrics tab. Altered RedrawGraphs to a more general Refreshable so it can be used with tables and not just graphs.
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/Table.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/Table.java
index 4ce05d2..0036dfc 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/Table.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/Table.java
@@ -143,8 +143,10 @@ public class Table<DS extends RPCDataSource> extends EnhancedHLayout implements
private DoubleClickHandler doubleClickHandler;
private List<TableActionInfo> tableActions = new ArrayList<TableActionInfo>();
private boolean tableActionDisableOverride = false;
+ protected List<Canvas> extraWidgetsAtTop = new ArrayList<Canvas>();
protected List<Canvas> extraWidgetsAboveFooter = new ArrayList<Canvas>();
protected List<Canvas> extraWidgetsInMainFooter = new ArrayList<Canvas>();
+ private EnhancedToolStrip topExtraWidgets;
private EnhancedToolStrip footer;
private EnhancedToolStrip footerExtraWidgets;
private EnhancedIButton refreshButton;
@@ -415,6 +417,15 @@ public class Table<DS extends RPCDataSource> extends EnhancedHLayout implements
contents.removeChild(child);
}
+ // add a toolstrip at the top of screen for navigation, date range controls, etc...
+ this.topExtraWidgets = new EnhancedToolStrip();
+ topExtraWidgets.setPadding(5);
+ topExtraWidgets.setWidth100();
+ topExtraWidgets.setMembersMargin(15);
+ topExtraWidgets.hide();
+ contents.addMember(topExtraWidgets);
+
+
// Title
this.titleCanvas = new HTMLFlow();
updateTitleCanvas(this.titleString);
@@ -537,6 +548,16 @@ public class Table<DS extends RPCDataSource> extends EnhancedHLayout implements
}
private void drawHeader() {
+
+ // add toolstrip to the top of screen
+ topExtraWidgets.removeMembers(topExtraWidgets.getMembers());
+ if (!extraWidgetsAtTop.isEmpty()) {
+ for (Canvas extraWidgetCanvas : extraWidgetsAtTop) {
+ topExtraWidgets.addMember(extraWidgetCanvas);
+ }
+ topExtraWidgets.show();
+ }
+
// just use the first icon (not sure use case for multiple icons in title)
titleBar = new TitleBar(titleString);
if (titleIcon != null) {
@@ -1038,6 +1059,14 @@ public class Table<DS extends RPCDataSource> extends EnhancedHLayout implements
}
}
+ /**
+ * Add any widgets to the top of the table for filtering, etc...
+ * @param widget
+ */
+ public void addTopWidget(Canvas widget ) {
+ this.extraWidgetsAtTop.add(widget);
+ }
+
public void setHeaderIcon(String headerIcon) {
if (this.headerIcons.size() > 0) {
this.headerIcons.clear();
@@ -1080,7 +1109,6 @@ public class Table<DS extends RPCDataSource> extends EnhancedHLayout implements
this.listGrid.setSelectionType(getDefaultSelectionStyle());
}
- //int selectionCount = this.listGrid.getSelectedRecords().length;
for (TableActionInfo tableAction : this.tableActions) {
if (tableAction.actionCanvas != null) { // if null, we haven't initialized our buttons yet, so skip this
boolean enabled = (!this.tableActionDisableOverride && tableAction.action.isEnabled(this.listGrid
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/AbstractD3GraphListView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/AbstractD3GraphListView.java
index 2ce63aa..a81f1ca 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/AbstractD3GraphListView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/AbstractD3GraphListView.java
@@ -32,7 +32,7 @@ import org.rhq.enterprise.gui.coregui.client.components.measurement.AbstractMeas
import org.rhq.enterprise.gui.coregui.client.dashboard.AutoRefreshUtil;
import org.rhq.enterprise.gui.coregui.client.inventory.AutoRefresh;
import org.rhq.enterprise.gui.coregui.client.inventory.common.graph.ButtonBarDateTimeRangeEditor;
-import org.rhq.enterprise.gui.coregui.client.inventory.common.graph.RedrawGraphs;
+import org.rhq.enterprise.gui.coregui.client.inventory.common.graph.Refreshable;
import org.rhq.enterprise.gui.coregui.client.inventory.resource.detail.monitoring.avail.AvailabilityD3GraphView;
import org.rhq.enterprise.gui.coregui.client.util.async.CountDownLatch;
import org.rhq.enterprise.gui.coregui.client.util.enhanced.EnhancedVLayout;
@@ -42,7 +42,7 @@ import org.rhq.enterprise.gui.coregui.client.util.preferences.MeasurementUserPre
* Provide the shared stuff for create GraphListViews like Availability graphs
* and User Preferences pickers for the date range.
*/
-public abstract class AbstractD3GraphListView extends EnhancedVLayout implements AutoRefresh,RedrawGraphs {
+public abstract class AbstractD3GraphListView extends EnhancedVLayout implements AutoRefresh,Refreshable {
protected final static int SINGLE_CHART_HEIGHT = 225;
protected final static int MULTI_CHART_HEIGHT = 210;
protected static final Label loadingLabel = new Label(MSG.common_msg_loading());
@@ -61,7 +61,7 @@ public abstract class AbstractD3GraphListView extends EnhancedVLayout implements
startRefreshCycle();
}
- public abstract void redrawGraphs();
+ public abstract void refreshData();
protected abstract void queryAvailability(final EntityContext context, Long startTime, Long endTime,
final CountDownLatch countDownLatch);
@@ -95,7 +95,7 @@ public abstract class AbstractD3GraphListView extends EnhancedVLayout implements
buttonBarDateTimeRangeEditor.updateDateTimeRangeDisplay(newStartDate, now);
buttonBarDateTimeRangeEditor.saveDateRange(newStartDate.getTime(), now.getTime());
- redrawGraphs();
+ refreshData();
}
}
}
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/graph/AbstractMetricGraph.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/graph/AbstractMetricGraph.java
index ace6154..7855545 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/graph/AbstractMetricGraph.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/graph/AbstractMetricGraph.java
@@ -235,6 +235,6 @@ public abstract class AbstractMetricGraph extends VLayout implements HasD3Metric
}
public void redrawGraphs(){
- graphListView.redrawGraphs();
+ graphListView.refreshData();
}
}
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/graph/ButtonBarDateTimeRangeEditor.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/graph/ButtonBarDateTimeRangeEditor.java
index b4f1354..e6578ed 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/graph/ButtonBarDateTimeRangeEditor.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/graph/ButtonBarDateTimeRangeEditor.java
@@ -59,7 +59,7 @@ public class ButtonBarDateTimeRangeEditor extends EnhancedVLayout {
static final int BUTTON_WIDTH = 28;
private MeasurementUserPreferences measurementUserPreferences;
- private RedrawGraphs d3GraphListView;
+ private Refreshable d3GraphListView;
private static final Messages MSG = CoreGUI.getMessages();
private Label dateRangeLabel;
private static final DateTimeFormat fmt = DateTimeFormat.getFormat(MSG.common_buttonbar_datetime_format());
@@ -68,7 +68,7 @@ public class ButtonBarDateTimeRangeEditor extends EnhancedVLayout {
final private ButtonBarDateTimeRangeEditor self;
public ButtonBarDateTimeRangeEditor(MeasurementUserPreferences measurementUserPrefs,
- RedrawGraphs d3GraphListView) {
+ Refreshable d3GraphListView) {
this.self = this;
this.measurementUserPreferences = measurementUserPrefs;
this.d3GraphListView = d3GraphListView;
@@ -128,7 +128,7 @@ public class ButtonBarDateTimeRangeEditor extends EnhancedVLayout {
}
public void redrawGraphs() {
- d3GraphListView.redrawGraphs();
+ d3GraphListView.refreshData();
}
@Override
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/graph/RedrawGraphs.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/graph/RedrawGraphs.java
deleted file mode 100644
index e590281..0000000
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/graph/RedrawGraphs.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2013 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-package org.rhq.enterprise.gui.coregui.client.inventory.common.graph;
-
-/**
- * Define the capability to Redraw a Graph.
- * @author Mike Thompson
- */
-public interface RedrawGraphs {
-
- void redrawGraphs();
-
-}
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/graph/Refreshable.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/graph/Refreshable.java
new file mode 100644
index 0000000..e170b44
--- /dev/null
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/graph/Refreshable.java
@@ -0,0 +1,30 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2013 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+package org.rhq.enterprise.gui.coregui.client.inventory.common.graph;
+
+/**
+ * Define the capability to Refresh data in a grid or Redraw a Graph.
+ *
+ * @author Mike Thompson
+ */
+public interface Refreshable {
+
+ void refreshData();
+
+}
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/detail/D3GroupGraphListView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/detail/D3GroupGraphListView.java
index 16670aa..bcb223a 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/detail/D3GroupGraphListView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/detail/D3GroupGraphListView.java
@@ -84,7 +84,7 @@ public final class D3GroupGraphListView extends AbstractD3GraphListView implemen
addMember(graphsVLayout);
}
- public void redrawGraphs() {
+ public void refreshData() {
this.onDraw();
}
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/detail/monitoring/table/CompositeGroupD3GraphListView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/detail/monitoring/table/CompositeGroupD3GraphListView.java
index 204d2ec..274354a 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/detail/monitoring/table/CompositeGroupD3GraphListView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/detail/monitoring/table/CompositeGroupD3GraphListView.java
@@ -45,7 +45,7 @@ import org.rhq.enterprise.gui.coregui.client.UserSessionManager;
import org.rhq.enterprise.gui.coregui.client.gwt.GWTServiceLookup;
import org.rhq.enterprise.gui.coregui.client.gwt.ResourceGroupGWTServiceAsync;
import org.rhq.enterprise.gui.coregui.client.inventory.common.graph.ButtonBarDateTimeRangeEditor;
-import org.rhq.enterprise.gui.coregui.client.inventory.common.graph.RedrawGraphs;
+import org.rhq.enterprise.gui.coregui.client.inventory.common.graph.Refreshable;
import org.rhq.enterprise.gui.coregui.client.inventory.resource.type.ResourceTypeRepository;
import org.rhq.enterprise.gui.coregui.client.util.Log;
import org.rhq.enterprise.gui.coregui.client.util.MeasurementConverterClient;
@@ -62,7 +62,7 @@ import org.rhq.enterprise.gui.coregui.client.util.preferences.MeasurementUserPre
*
* @author Mike Thompson
*/
-public abstract class CompositeGroupD3GraphListView extends EnhancedVLayout implements JsonMetricProducer, RedrawGraphs {
+public abstract class CompositeGroupD3GraphListView extends EnhancedVLayout implements JsonMetricProducer, Refreshable {
static protected final Messages MSG = CoreGUI.getMessages();
// string labels
@@ -250,7 +250,7 @@ public abstract class CompositeGroupD3GraphListView extends EnhancedVLayout impl
}
@Override
- public void redrawGraphs() {
+ public void refreshData() {
populateData();
drawGraph();
}
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/detail/monitoring/table/GroupMeasurementTableView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/detail/monitoring/table/GroupMeasurementTableView.java
index efb7b72..50a8819 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/detail/monitoring/table/GroupMeasurementTableView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/detail/monitoring/table/GroupMeasurementTableView.java
@@ -20,27 +20,40 @@
package org.rhq.enterprise.gui.coregui.client.inventory.groups.detail.monitoring.table;
import java.util.ArrayList;
+import java.util.Date;
+import com.google.gwt.user.client.Timer;
import com.smartgwt.client.data.Record;
import com.smartgwt.client.widgets.grid.ListGridField;
import com.smartgwt.client.widgets.grid.events.CellClickEvent;
import com.smartgwt.client.widgets.grid.events.CellClickHandler;
import org.rhq.core.domain.resource.group.composite.ResourceGroupComposite;
+import org.rhq.enterprise.gui.coregui.client.UserSessionManager;
+import org.rhq.enterprise.gui.coregui.client.components.measurement.AbstractMeasurementRangeEditor;
import org.rhq.enterprise.gui.coregui.client.components.measurement.UserPreferencesMeasurementRangeEditor;
import org.rhq.enterprise.gui.coregui.client.components.table.Table;
+import org.rhq.enterprise.gui.coregui.client.dashboard.AutoRefreshUtil;
+import org.rhq.enterprise.gui.coregui.client.inventory.AutoRefresh;
import org.rhq.enterprise.gui.coregui.client.inventory.common.detail.summary.AbstractActivityView.ChartViewWindow;
+import org.rhq.enterprise.gui.coregui.client.inventory.common.graph.ButtonBarDateTimeRangeEditor;
+import org.rhq.enterprise.gui.coregui.client.inventory.common.graph.Refreshable;
+import org.rhq.enterprise.gui.coregui.client.util.preferences.MeasurementUserPreferences;
/**
* Views a resource's measurements in a tabular view.
*
* @author John Mazzitelli
* @author Simeon Pinder
+ * @author Mike Thompson
*/
-public class GroupMeasurementTableView extends Table<GroupMetricsTableDataSource> {
+public class GroupMeasurementTableView extends Table<GroupMetricsTableDataSource> implements AutoRefresh, Refreshable {
private final int groupId;
private final boolean isAutogroup;
+ protected final MeasurementUserPreferences measurementUserPrefs;
+ protected final ButtonBarDateTimeRangeEditor buttonBarDateTimeRangeEditor;
+ protected Timer refreshTimer;
public GroupMeasurementTableView(ResourceGroupComposite groupComposite, int groupId) {
super();
@@ -50,10 +63,52 @@ public class GroupMeasurementTableView extends Table<GroupMetricsTableDataSource
//disable fields used when is full screen
setShowFooterRefresh(true);
setTitle(MSG.common_title_numeric_metrics());
+
+ measurementUserPrefs = new MeasurementUserPreferences(UserSessionManager.getUserPreferences());
+ buttonBarDateTimeRangeEditor = new ButtonBarDateTimeRangeEditor(measurementUserPrefs,this);
+ }
+
+ @Override
+ public void refreshData() {
+
+ }
+
+ @Override
+ public void startRefreshCycle() {
+ refreshTimer = AutoRefreshUtil.startRefreshCycle(this, this, refreshTimer);
+ }
+
+ @Override
+ protected void onDestroy() {
+ AutoRefreshUtil.onDestroy( refreshTimer);
+
+ super.onDestroy();
+ }
+
+ @Override
+ public boolean isRefreshing() {
+ return false;
+ }
+
+ //Custom refresh operation as we are not directly extending Table
+ @Override
+ public void refresh() {
+ if (isVisible() && !isRefreshing()) {
+ Date now = new Date();
+ AbstractMeasurementRangeEditor.MetricRangePreferences metricRangePreferences = measurementUserPrefs.getMetricRangePreferences();
+ long timeRange = metricRangePreferences.end - metricRangePreferences.begin;
+ Date newStartDate = new Date(now.getTime() - timeRange);
+ buttonBarDateTimeRangeEditor.updateDateTimeRangeDisplay(newStartDate, now);
+ buttonBarDateTimeRangeEditor.saveDateRange(newStartDate.getTime(), now.getTime());
+
+ refreshData();
+ }
}
@Override
protected void configureTable() {
+ addTopWidget(buttonBarDateTimeRangeEditor);
+
ArrayList<ListGridField> fields = getDataSource().getListGridFields();
//add cell click handler to execute on Table data entries.
@@ -72,7 +127,6 @@ public class GroupMeasurementTableView extends Table<GroupMetricsTableDataSource
}
});
setListGridFields(fields.toArray(new ListGridField[getDataSource().getListGridFields().size()]));
- addExtraWidget(new UserPreferencesMeasurementRangeEditor(), true);
}
}
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/D3GraphListView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/D3GraphListView.java
index 5635d88..6eab1e9 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/D3GraphListView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/D3GraphListView.java
@@ -134,7 +134,7 @@ public class D3GraphListView extends AbstractD3GraphListView {
addMember(vLayout);
}
- public void redrawGraphs() {
+ public void refreshData() {
this.onDraw();
}
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/MetricD3Graph.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/MetricD3Graph.java
index 65807f9..4dad9b1 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/MetricD3Graph.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/MetricD3Graph.java
@@ -22,7 +22,7 @@ import com.google.gwt.user.client.Timer;
import com.smartgwt.client.widgets.HTMLFlow;
import org.rhq.enterprise.gui.coregui.client.inventory.common.AbstractD3GraphListView;
-import org.rhq.enterprise.gui.coregui.client.inventory.common.graph.RedrawGraphs;
+import org.rhq.enterprise.gui.coregui.client.inventory.common.graph.Refreshable;
import org.rhq.enterprise.gui.coregui.client.inventory.common.graph.graphtype.StackedBarMetricGraphImpl;
import org.rhq.enterprise.gui.coregui.client.util.Log;
import org.rhq.enterprise.gui.coregui.client.util.enhanced.EnhancedVLayout;
@@ -31,7 +31,7 @@ import org.rhq.enterprise.gui.coregui.client.util.enhanced.EnhancedVLayout;
* A D3 graph implementation for graphing Resource metrics.
* Just the graph only. No avail graph no buttons just he graph.
*/
-public class MetricD3Graph<T extends AbstractD3GraphListView> extends EnhancedVLayout implements RedrawGraphs{
+public class MetricD3Graph<T extends AbstractD3GraphListView> extends EnhancedVLayout implements Refreshable {
protected StackedBarMetricGraphImpl graph;
private HTMLFlow graphDiv = null;
@@ -205,8 +205,8 @@ public class MetricD3Graph<T extends AbstractD3GraphListView> extends EnhancedVL
/**
* Allow the graph to refresh the whole d3GraphListView.
*/
- public void redrawGraphs(){
- d3GraphListView.redrawGraphs();
+ public void refreshData(){
+ d3GraphListView.refreshData();
}
}
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/table/MetricsResourceView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/table/MetricsResourceView.java
index bcea825..d856410 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/table/MetricsResourceView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/table/MetricsResourceView.java
@@ -68,7 +68,7 @@ public class MetricsResourceView extends AbstractD3GraphListView {
}
- public void redrawGraphs() {
+ public void refreshData() {
this.onDraw();
}
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/table/MetricsTableView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/table/MetricsTableView.java
index bb67587..db9abd4 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/table/MetricsTableView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/table/MetricsTableView.java
@@ -64,7 +64,7 @@ import org.rhq.enterprise.gui.coregui.client.components.table.TableAction;
import org.rhq.enterprise.gui.coregui.client.gwt.GWTServiceLookup;
import org.rhq.enterprise.gui.coregui.client.inventory.common.AbstractD3GraphListView;
import org.rhq.enterprise.gui.coregui.client.inventory.common.graph.MetricGraphData;
-import org.rhq.enterprise.gui.coregui.client.inventory.common.graph.RedrawGraphs;
+import org.rhq.enterprise.gui.coregui.client.inventory.common.graph.Refreshable;
import org.rhq.enterprise.gui.coregui.client.inventory.common.graph.graphtype.StackedBarMetricGraphImpl;
import org.rhq.enterprise.gui.coregui.client.inventory.resource.detail.monitoring.MetricD3Graph;
import org.rhq.enterprise.gui.coregui.client.util.BrowserUtility;
@@ -78,7 +78,7 @@ import org.rhq.enterprise.gui.coregui.client.util.preferences.MeasurementUserPre
* @author John Mazzitelli
* @author Mike Thompson
*/
-public class MetricsTableView extends Table<MetricsViewDataSource> implements RedrawGraphs {
+public class MetricsTableView extends Table<MetricsViewDataSource> implements Refreshable {
private final Resource resource;
private final AbstractD3GraphListView abstractD3GraphListView;
@@ -248,7 +248,7 @@ public class MetricsTableView extends Table<MetricsViewDataSource> implements Re
/**
* Redraw Graphs in this context means to refresh the table and redraw open graphs.
*/
- public void redrawGraphs() {
+ public void refreshData() {
Log.debug("MetricsView.redrawGraphs.");
new Timer() {
@@ -281,7 +281,7 @@ public class MetricsTableView extends Table<MetricsViewDataSource> implements Re
public void onRecordExpand(RecordExpandEvent recordExpandEvent) {
metricsTableView.expandedRows.add(recordExpandEvent.getRecord().getAttributeAsInt(
MetricsViewDataSource.FIELD_METRIC_DEF_ID));
- redrawGraphs();
+ refreshData();
}
});
@@ -290,13 +290,13 @@ public class MetricsTableView extends Table<MetricsViewDataSource> implements Re
public void onRecordCollapse(RecordCollapseEvent recordCollapseEvent) {
metricsTableView.expandedRows.remove(recordCollapseEvent.getRecord().getAttributeAsInt(
MetricsViewDataSource.FIELD_METRIC_DEF_ID));
- redrawGraphs();
+ refreshData();
}
});
addSortChangedHandler(new SortChangedHandler() {
@Override
public void onSortChanged(SortEvent sortEvent) {
- redrawGraphs();
+ refreshData();
}
});
addDataArrivedHandler(new DataArrivedHandler() {
commit 19f1069afd4e9bf4d049893ddd742be335c1a9bc
Author: Mike Thompson <mithomps(a)redhat.com>
Date: Thu Aug 8 10:47:22 2013 -0700
IE UI fixes
diff --git a/modules/enterprise/gui/coregui/src/main/webapp/CoreGUI.html b/modules/enterprise/gui/coregui/src/main/webapp/CoreGUI.html
index 96e50de..32c5789 100644
--- a/modules/enterprise/gui/coregui/src/main/webapp/CoreGUI.html
+++ b/modules/enterprise/gui/coregui/src/main/webapp/CoreGUI.html
@@ -27,6 +27,29 @@
}
</script>
+ <script type="text/javascript">
+ (function() {
+ var method;
+ var noop = function () {};
+ var methods = [
+ 'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error',
+ 'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log',
+ 'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd',
+ 'timeStamp', 'trace', 'warn'
+ ];
+ var length = methods.length;
+ var console = (window.console = window.console || {});
+
+ while (length--) {
+ method = methods[length];
+
+ // Only stub undefined methods.
+ if (!console[method]) {
+ console[method] = noop;
+ }
+ }
+ }());
+ </script>
<title>RHQ</title>
<link rel="icon" type="image/png" href="/images/favicon.png" />
diff --git a/modules/enterprise/gui/coregui/src/main/webapp/js/jquery-1.9.1.js b/modules/enterprise/gui/coregui/src/main/webapp/js/jquery-1.9.1.js
deleted file mode 100644
index bc8f36a..0000000
--- a/modules/enterprise/gui/coregui/src/main/webapp/js/jquery-1.9.1.js
+++ /dev/null
@@ -1,9597 +0,0 @@
-/*!
- * jQuery JavaScript Library v1.9.1
- * http://jquery.com/
- *
- * Includes Sizzle.js
- * http://sizzlejs.com/
- *
- * Copyright 2005, 2012 jQuery Foundation, Inc. and other contributors
- * Released under the MIT license
- * http://jquery.org/license
- *
- * Date: 2013-2-4
- */
-(function( window, undefined ) {
-
-// 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+
-//"use strict";
- var
- // The deferred used on DOM ready
- readyList,
-
- // A central reference to the root jQuery(document)
- rootjQuery,
-
- // Support: IE<9
- // For `typeof node.method` instead of `node.method !== undefined`
- core_strundefined = typeof undefined,
-
- // Use the correct document accordingly with window argument (sandbox)
- document = window.document,
- location = window.location,
-
- // Map over jQuery in case of overwrite
- _jQuery = window.jQuery,
-
- // Map over the $ in case of overwrite
- _$ = window.$,
-
- // [[Class]] -> type pairs
- class2type = {},
-
- // List of deleted data cache ids, so we can reuse them
- core_deletedIds = [],
-
- core_version = "1.9.1",
-
- // Save a reference to some core methods
- core_concat = core_deletedIds.concat,
- core_push = core_deletedIds.push,
- core_slice = core_deletedIds.slice,
- core_indexOf = core_deletedIds.indexOf,
- core_toString = class2type.toString,
- core_hasOwn = class2type.hasOwnProperty,
- core_trim = core_version.trim,
-
- // Define a local copy of jQuery
- jQuery = function( selector, context ) {
- // The jQuery object is actually just the init constructor 'enhanced'
- return new jQuery.fn.init( selector, context, rootjQuery );
- },
-
- // Used for matching numbers
- core_pnum = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,
-
- // Used for splitting on whitespace
- core_rnotwhite = /\S+/g,
-
- // Make sure we trim BOM and NBSP (here's looking at you, Safari 5.0 and IE)
- rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
-
- // 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 = /^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/,
-
- // Match a standalone tag
- rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/,
-
- // JSON RegExp
- rvalidchars = /^[\],:{}\s]*$/,
- rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
- rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,
- rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/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();
- },
-
- // The ready event handler
- completed = function( event ) {
-
- // 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();
- }
- },
- // Clean-up method for dom ready events
- detach = function() {
- if ( document.addEventListener ) {
- document.removeEventListener( "DOMContentLoaded", completed, false );
- window.removeEventListener( "load", completed, false );
-
- } else {
- document.detachEvent( "onreadystatechange", completed );
- window.detachEvent( "onload", completed );
- }
- };
-
- jQuery.fn = jQuery.prototype = {
- // The current version of jQuery being used
- jquery: core_version,
-
- constructor: jQuery,
- init: function( selector, context, rootjQuery ) {
- 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
- 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 rootjQuery.ready( selector );
- }
-
- if ( selector.selector !== undefined ) {
- this.selector = selector.selector;
- this.context = selector.context;
- }
-
- return jQuery.makeArray( selector, this );
- },
-
- // Start with an empty selector
- selector: "",
-
- // The default length of a jQuery object is 0
- length: 0,
-
- // The number of elements contained in the matched element set
- size: function() {
- return this.length;
- },
-
- toArray: function() {
- return core_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 a 'clean' array
- this.toArray() :
-
- // Return just the object
- ( num < 0 ? this[ this.length + num ] : this[ num ] );
- },
-
- // 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 );
- },
-
- ready: function( fn ) {
- // Add the callback
- jQuery.ready.promise().done( fn );
-
- return this;
- },
-
- slice: function() {
- return this.pushStack( core_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] ] : [] );
- },
-
- map: function( callback ) {
- return this.pushStack( jQuery.map(this, function( elem, i ) {
- return callback.call( elem, i, elem );
- }));
- },
-
- end: function() {
- return this.prevObject || this.constructor(null);
- },
-
- // For internal use only.
- // Behaves like an Array's method, not like a jQuery method.
- push: core_push,
- sort: [].sort,
- splice: [].splice
- };
-
-// Give the init function the jQuery prototype for later instantiation
- jQuery.fn.init.prototype = jQuery.fn;
-
- 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;
- 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" && !jQuery.isFunction(target) ) {
- target = {};
- }
-
- // extend jQuery itself if only one argument is passed
- if ( length === i ) {
- 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({
- noConflict: function( deep ) {
- if ( window.$ === jQuery ) {
- window.$ = _$;
- }
-
- if ( deep && window.jQuery === jQuery ) {
- window.jQuery = _jQuery;
- }
-
- return jQuery;
- },
-
- // 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.trigger ) {
- jQuery( document ).trigger("ready").off("ready");
- }
- },
-
- // 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 ) {
- return obj != null && obj == obj.window;
- },
-
- isNumeric: function( obj ) {
- return !isNaN( parseFloat(obj) ) && isFinite( obj );
- },
-
- type: function( obj ) {
- if ( obj == null ) {
- return String( obj );
- }
- return typeof obj === "object" || typeof obj === "function" ?
- class2type[ core_toString.call(obj) ] || "object" :
- typeof obj;
- },
-
- isPlainObject: function( obj ) {
- // 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 &&
- !core_hasOwn.call(obj, "constructor") &&
- !core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
- return false;
- }
- } catch ( e ) {
- // IE8,9 Will throw exceptions on certain host objects #9897
- return false;
- }
-
- // Own properties are enumerated firstly, so to speed up,
- // if last one is own, then all properties are own.
-
- var key;
- for ( key in obj ) {}
-
- return key === undefined || core_hasOwn.call( obj, key );
- },
-
- isEmptyObject: function( obj ) {
- var name;
- for ( name in obj ) {
- return false;
- }
- return true;
- },
-
- error: function( msg ) {
- throw new Error( msg );
- },
-
- // 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
- 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 ) {
- jQuery( scripts ).remove();
- }
- return jQuery.merge( [], parsed.childNodes );
- },
-
- parseJSON: function( data ) {
- // Attempt to parse using the native JSON parser first
- if ( window.JSON && window.JSON.parse ) {
- return window.JSON.parse( data );
- }
-
- if ( data === null ) {
- return data;
- }
-
- if ( typeof data === "string" ) {
-
- // Make sure leading/trailing whitespace is removed (IE can't handle it)
- data = jQuery.trim( data );
-
- if ( data ) {
- // Make sure the incoming data is actual JSON
- // Logic borrowed from http://json.org/json2.js
- if ( rvalidchars.test( data.replace( rvalidescape, "@" )
- .replace( rvalidtokens, "]" )
- .replace( rvalidbraces, "")) ) {
-
- return ( new Function( "return " + data ) )();
- }
- }
- }
-
- jQuery.error( "Invalid JSON: " + data );
- },
-
- // Cross-browser xml parsing
- 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;
- },
-
- noop: function() {},
-
- // 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-...
- 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;
- },
-
- // Use native String.trim function wherever possible
- trim: core_trim && !core_trim.call("\uFEFF\xA0") ?
- function( text ) {
- return text == null ?
- "" :
- core_trim.call( text );
- } :
-
- // Otherwise use our own trimming functionality
- 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 {
- core_push.call( ret, arr );
- }
- }
-
- return ret;
- },
-
- inArray: function( elem, arr, i ) {
- var len;
-
- if ( arr ) {
- if ( core_indexOf ) {
- return core_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 l = second.length,
- i = first.length,
- j = 0;
-
- if ( typeof l === "number" ) {
- for ( ; j < l; j++ ) {
- first[ i++ ] = second[ j ];
- }
- } else {
- while ( second[j] !== undefined ) {
- first[ i++ ] = second[ j++ ];
- }
- }
-
- first.length = i;
-
- return first;
- },
-
- grep: function( elems, callback, inv ) {
- var retVal,
- ret = [],
- i = 0,
- length = elems.length;
- inv = !!inv;
-
- // Go through the array, only saving the items
- // that pass the validator function
- for ( ; i < length; i++ ) {
- retVal = !!callback( elems[ i ], i );
- if ( inv !== retVal ) {
- ret.push( elems[ i ] );
- }
- }
-
- return ret;
- },
-
- // 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
- if ( isArray ) {
- for ( ; i < length; i++ ) {
- value = callback( elems[ i ], i, arg );
-
- if ( value != null ) {
- ret[ ret.length ] = value;
- }
- }
-
- // Go through every key on the object,
- } else {
- for ( i in elems ) {
- value = callback( elems[ i ], i, arg );
-
- if ( value != null ) {
- ret[ ret.length ] = value;
- }
- }
- }
-
- // Flatten any nested arrays
- return core_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 = core_slice.call( arguments, 2 );
- proxy = function() {
- return fn.apply( context || this, args.concat( core_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;
- },
-
- // Multifunctional method to get and set values of a collection
- // The value/s can optionally be executed if it's a function
- 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;
- },
-
- now: function() {
- return ( new Date() ).getTime();
- }
- });
-
- 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 );
- };
-
-// 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 ( jQuery.isWindow( obj ) ) {
- return false;
- }
-
- if ( obj.nodeType === 1 && length ) {
- return true;
- }
-
- return type === "array" || type !== "function" &&
- ( length === 0 ||
- typeof length === "number" && length > 0 && ( length - 1 ) in obj );
- }
-
-// All jQuery objects should point back to these
- rootjQuery = jQuery(document);
-// 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( core_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 = [];
- 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 ) {
- args = args || [];
- args = [ context, args.slice ? args.slice() : args ];
- if ( list && ( !fired || stack ) ) {
- 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 action = tuple[ 0 ],
- 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[ action + "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 = core_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 ? core_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();
- }
- });
- jQuery.support = (function() {
-
- var support, all, a,
- input, select, fragment,
- opt, eventName, isSupported, i,
- div = document.createElement("div");
-
- // Setup
- div.setAttribute( "className", "t" );
- div.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
-
- // Support tests won't run in some limited or non-browser environments
- all = div.getElementsByTagName("*");
- a = div.getElementsByTagName("a")[ 0 ];
- if ( !all || !a || !all.length ) {
- return {};
- }
-
- // First batch of tests
- select = document.createElement("select");
- opt = select.appendChild( document.createElement("option") );
- input = div.getElementsByTagName("input")[ 0 ];
-
- a.style.cssText = "top:1px;float:left;opacity:.5";
- support = {
- // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
- getSetAttribute: div.className !== "t",
-
- // IE strips leading whitespace when .innerHTML is used
- leadingWhitespace: div.firstChild.nodeType === 3,
-
- // Make sure that tbody elements aren't automatically inserted
- // IE will insert them into empty tables
- tbody: !div.getElementsByTagName("tbody").length,
-
- // Make sure that link elements get serialized correctly by innerHTML
- // This requires a wrapper element in IE
- htmlSerialize: !!div.getElementsByTagName("link").length,
-
- // Get the style information from getAttribute
- // (IE uses .cssText instead)
- style: /top/.test( a.getAttribute("style") ),
-
- // Make sure that URLs aren't manipulated
- // (IE normalizes it by default)
- hrefNormalized: a.getAttribute("href") === "/a",
-
- // Make sure that element opacity exists
- // (IE uses filter instead)
- // Use a regex to work around a WebKit issue. See #5145
- opacity: /^0.5/.test( a.style.opacity ),
-
- // Verify style float existence
- // (IE uses styleFloat instead of cssFloat)
- cssFloat: !!a.style.cssFloat,
-
- // Check the default checkbox/radio value ("" on WebKit; "on" elsewhere)
- 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)
- optSelected: opt.selected,
-
- // Tests for enctype support on a form (#6743)
- enctype: !!document.createElement("form").enctype,
-
- // Makes sure cloning an html5 element does not cause problems
- // Where outerHTML is undefined, this still works
- html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav></:nav>",
-
- // jQuery.support.boxModel DEPRECATED in 1.8 since we don't support Quirks Mode
- boxModel: document.compatMode === "CSS1Compat",
-
- // Will be defined later
- deleteExpando: true,
- noCloneEvent: true,
- inlineBlockNeedsLayout: false,
- shrinkWrapBlocks: false,
- reliableMarginRight: true,
- boxSizingReliable: true,
- pixelPosition: false
- };
-
- // Make sure checked status is properly cloned
- input.checked = true;
- support.noCloneChecked = input.cloneNode( true ).checked;
-
- // 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: IE<9
- try {
- delete div.test;
- } catch( e ) {
- support.deleteExpando = false;
- }
-
- // 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";
-
- // #11217 - WebKit loses check when the name is after the checked attribute
- input.setAttribute( "checked", "t" );
- input.setAttribute( "name", "t" );
-
- fragment = document.createDocumentFragment();
- fragment.appendChild( input );
-
- // Check if a disconnected checkbox will retain its checked
- // value of true after appended to the DOM (IE6/7)
- support.appendChecked = input.checked;
-
- // WebKit doesn't clone checked state correctly in fragments
- support.checkClone = fragment.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()
- if ( div.attachEvent ) {
- div.attachEvent( "onclick", function() {
- support.noCloneEvent = false;
- });
-
- div.cloneNode( true ).click();
- }
-
- // Support: IE<9 (lack submit/change bubble), Firefox 17+ (lack focusin event)
- // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP), test/csp.php
- for ( i in { submit: true, change: true, focusin: true }) {
- div.setAttribute( eventName = "on" + i, "t" );
-
- support[ i + "Bubbles" ] = eventName in window || div.attributes[ eventName ].expando === false;
- }
-
- div.style.backgroundClip = "content-box";
- div.cloneNode( true ).style.backgroundClip = "";
- support.clearCloneStyle = div.style.backgroundClip === "content-box";
-
- // Run tests that need a body at doc ready
- jQuery(function() {
- var container, marginDiv, tds,
- divReset = "padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",
- body = document.getElementsByTagName("body")[0];
-
- if ( !body ) {
- // Return for frameset docs that don't have a body
- return;
- }
-
- container = document.createElement("div");
- container.style.cssText = "border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px";
-
- body.appendChild( container ).appendChild( div );
-
- // 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>";
- tds = div.getElementsByTagName("td");
- tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none";
- isSupported = ( tds[ 0 ].offsetHeight === 0 );
-
- tds[ 0 ].style.display = "";
- tds[ 1 ].style.display = "none";
-
- // Support: IE8
- // Check if empty table cells still have offsetWidth/Height
- support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
-
- // Check box-sizing and margin behavior
- div.innerHTML = "";
- div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;";
- support.boxSizing = ( div.offsetWidth === 4 );
- support.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== 1 );
-
- // Use window.getComputedStyle because jsdom on node.js will break without it.
- if ( window.getComputedStyle ) {
- support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%";
- support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px";
-
- // Check if div with explicit width and no margin-right incorrectly
- // gets computed margin-right based on width of container. (#3333)
- // Fails in WebKit before Feb 2011 nightlies
- // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
- marginDiv = div.appendChild( document.createElement("div") );
- marginDiv.style.cssText = div.style.cssText = divReset;
- marginDiv.style.marginRight = marginDiv.style.width = "0";
- div.style.width = "1px";
-
- support.reliableMarginRight =
- !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight );
- }
-
- if ( typeof div.style.zoom !== core_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.innerHTML = "";
- div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1";
- support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 );
-
- // Support: IE6
- // Check if elements with layout shrink-wrap their children
- div.style.display = "block";
- div.innerHTML = "<div></div>";
- div.firstChild.style.width = "5px";
- support.shrinkWrapBlocks = ( div.offsetWidth !== 3 );
-
- if ( support.inlineBlockNeedsLayout ) {
- // 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 );
-
- // Null elements to avoid leaks in IE
- container = div = tds = marginDiv = null;
- });
-
- // Null elements to avoid leaks in IE
- all = select = fragment = opt = a = input = null;
-
- return support;
- })();
-
- var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/,
- rmultiDash = /([A-Z])/g;
-
- function internalData( elem, name, data, pvt /* Internal Use Only */ ){
- if ( !jQuery.acceptData( elem ) ) {
- return;
- }
-
- var thisCache, ret,
- internalKey = jQuery.expando,
- getByName = typeof name === "string",
-
- // 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)) && getByName && data === undefined ) {
- 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 ) {
- elem[ internalKey ] = id = core_deletedIds.pop() || jQuery.guid++;
- } else {
- id = internalKey;
- }
- }
-
- if ( !cache[ id ] ) {
- cache[ id ] = {};
-
- // Avoids exposing jQuery metadata on plain JS objects when the object
- // is serialized using JSON.stringify
- if ( !isNode ) {
- cache[ id ].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 ( getByName ) {
-
- // 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 i, l, thisCache,
- 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 ) );
- }
-
- for ( i = 0, l = name.length; i < l; 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 : 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)
- } else if ( jQuery.support.deleteExpando || cache != cache.window ) {
- delete cache[ id ];
-
- // When all else fails, null
- } else {
- cache[ id ] = null;
- }
- }
-
- jQuery.extend({
- cache: {},
-
- // Unique for each copy of jQuery on the page
- // Non-digits removed to match rinlinejQuery
- expando: "jQuery" + ( core_version + Math.random() ).replace( /\D/g, "" ),
-
- // The following elements throw uncatchable exceptions if you
- // attempt to add expando properties to them.
- noData: {
- "embed": true,
- // Ban all objects except for Flash (which handle expandos)
- "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",
- "applet": true
- },
-
- 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 );
- },
-
- // A method for determining if a DOM node can handle the data expando
- acceptData: function( elem ) {
- // Do not set data on non-element because it will not be cleared (#8335).
- if ( elem.nodeType && elem.nodeType !== 1 && elem.nodeType !== 9 ) {
- return false;
- }
-
- var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ];
-
- // nodes accept data unless otherwise specified; rejection can be conditional
- return !noData || noData !== true && elem.getAttribute("classid") === noData;
- }
- });
-
- jQuery.fn.extend({
- data: function( key, value ) {
- var attrs, name,
- elem = this[0],
- i = 0,
- data = null;
-
- // Gets all values
- if ( key === undefined ) {
- if ( this.length ) {
- data = jQuery.data( elem );
-
- if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
- attrs = elem.attributes;
- for ( ; i < attrs.length; i++ ) {
- name = attrs[i].name;
-
- if ( !name.indexOf( "data-" ) ) {
- 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 jQuery.access( this, function( value ) {
-
- if ( value === undefined ) {
- // Try to fetch any internally stored data first
- return elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : null;
- }
-
- this.each(function() {
- jQuery.data( this, key, value );
- });
- }, null, value, arguments.length > 1, null, true );
- },
-
- removeData: function( key ) {
- return this.each(function() {
- jQuery.removeData( this, key );
- });
- }
- });
-
- 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;
- }
- 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--;
- }
-
- hooks.cur = fn;
- 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 );
- });
- },
- // Based off of the plugin by Clint Helfers, with permission.
- // http://blindsignals.com/index.php/2009/07/jquery-delay/
- 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 );
- };
- });
- },
- 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 nodeHook, boolHook,
- rclass = /[\t\r\n]/g,
- rreturn = /\r/g,
- rfocusable = /^(?:input|select|textarea|button|object)$/i,
- rclickable = /^(?:a|area)$/i,
- rboolean = /^(?:checked|selected|autofocus|autoplay|async|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped)$/i,
- ruseDefault = /^(?:checked|selected)$/i,
- getSetAttribute = jQuery.support.getSetAttribute,
- getSetInput = jQuery.support.input;
-
- jQuery.fn.extend({
- attr: function( name, value ) {
- return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
- },
-
- removeAttr: function( name ) {
- return this.each(function() {
- jQuery.removeAttr( this, name );
- });
- },
-
- prop: function( name, value ) {
- return jQuery.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 ) {}
- });
- },
-
- addClass: function( value ) {
- var classes, elem, cur, clazz, j,
- 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( core_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 + " ";
- }
- }
- elem.className = jQuery.trim( cur );
-
- }
- }
- }
-
- return this;
- },
-
- removeClass: function( value ) {
- var classes, elem, cur, clazz, j,
- 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( core_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 + " ", " " );
- }
- }
- elem.className = value ? jQuery.trim( cur ) : "";
- }
- }
- }
-
- return this;
- },
-
- toggleClass: function( value, stateVal ) {
- var type = typeof value,
- isBool = typeof stateVal === "boolean";
-
- 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 ),
- state = stateVal,
- classNames = value.match( core_rnotwhite ) || [];
-
- while ( (className = classNames[ i++ ]) ) {
- // check each className given, space separated list
- state = isBool ? state : !self.hasClass( className );
- self[ state ? "addClass" : "removeClass" ]( className );
- }
-
- // Toggle whole class name
- } else if ( type === core_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;
- },
-
- val: function( value ) {
- var ret, hooks, 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,
- self = jQuery(this);
-
- if ( this.nodeType !== 1 ) {
- return;
- }
-
- if ( isFunction ) {
- val = value.call( this, i, self.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 ) {
- // attributes.value is undefined in Blackberry 4.7 but
- // uses .value. See #6932
- var val = elem.attributes.value;
- return !val || val.specified ? elem.value : elem.text;
- }
- },
- 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
- ( jQuery.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 values = jQuery.makeArray( value );
-
- jQuery(elem).find("option").each(function() {
- this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
- });
-
- if ( !values.length ) {
- elem.selectedIndex = -1;
- }
- return values;
- }
- }
- },
-
- attr: function( elem, name, value ) {
- var hooks, notxml, 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 === core_strundefined ) {
- return jQuery.prop( elem, name, value );
- }
-
- notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
-
- // All attributes are lowercase
- // Grab necessary hook if one is defined
- if ( notxml ) {
- name = name.toLowerCase();
- hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook );
- }
-
- if ( value !== undefined ) {
-
- if ( value === null ) {
- jQuery.removeAttr( elem, name );
-
- } else if ( hooks && notxml && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
- return ret;
-
- } else {
- elem.setAttribute( name, value + "" );
- return value;
- }
-
- } else if ( hooks && notxml && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
- return ret;
-
- } else {
-
- // In IE9+, Flash objects don't have .getAttribute (#12945)
- // Support: IE9+
- if ( typeof elem.getAttribute !== core_strundefined ) {
- ret = elem.getAttribute( 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( core_rnotwhite );
-
- if ( attrNames && elem.nodeType === 1 ) {
- while ( (name = attrNames[i++]) ) {
- propName = jQuery.propFix[ name ] || name;
-
- // Boolean attributes get special treatment (#10870)
- if ( rboolean.test( name ) ) {
- // Set corresponding property to false for boolean attributes
- // Also clear defaultChecked/defaultSelected (if appropriate) for IE<8
- if ( !getSetAttribute && ruseDefault.test( name ) ) {
- elem[ jQuery.camelCase( "default-" + name ) ] =
- elem[ propName ] = false;
- } else {
- 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 ( !jQuery.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;
- }
- }
- }
- },
-
- propFix: {
- tabindex: "tabIndex",
- readonly: "readOnly",
- "for": "htmlFor",
- "class": "className",
- maxlength: "maxLength",
- cellspacing: "cellSpacing",
- cellpadding: "cellPadding",
- rowspan: "rowSpan",
- colspan: "colSpan",
- usemap: "useMap",
- frameborder: "frameBorder",
- contenteditable: "contentEditable"
- },
-
- 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 ) {
- if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
- return ret;
-
- } else {
- return ( elem[ name ] = value );
- }
-
- } else {
- if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
- return ret;
-
- } else {
- return 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-tabi...
- var attributeNode = elem.getAttributeNode("tabindex");
-
- return attributeNode && attributeNode.specified ?
- parseInt( attributeNode.value, 10 ) :
- rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
- 0 :
- undefined;
- }
- }
- }
- });
-
-// Hook for boolean attributes
- boolHook = {
- get: function( elem, name ) {
- var
- // Use .prop to determine if this attribute is understood as boolean
- prop = jQuery.prop( elem, name ),
-
- // Fetch it accordingly
- attr = typeof prop === "boolean" && elem.getAttribute( name ),
- detail = typeof prop === "boolean" ?
-
- getSetInput && getSetAttribute ?
- attr != null :
- // oldIE fabricates an empty string for missing boolean attributes
- // and conflates checked/selected into attroperties
- ruseDefault.test( name ) ?
- elem[ jQuery.camelCase( "default-" + name ) ] :
- !!attr :
-
- // fetch an attribute node for properties not recognized as boolean
- elem.getAttributeNode( name );
-
- return detail && detail.value !== false ?
- name.toLowerCase() :
- undefined;
- },
- 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;
- }
- };
-
-// fix oldIE value attroperty
- if ( !getSetInput || !getSetAttribute ) {
- jQuery.attrHooks.value = {
- get: function( elem, name ) {
- var ret = elem.getAttributeNode( name );
- return jQuery.nodeName( elem, "input" ) ?
-
- // Ignore the value *property* by using defaultValue
- elem.defaultValue :
-
- ret && ret.specified ? ret.value : undefined;
- },
- 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 = jQuery.valHooks.button = {
- get: function( elem, name ) {
- var ret = elem.getAttributeNode( name );
- return ret && ( name === "id" || name === "name" || name === "coords" ? ret.value !== "" : ret.specified ) ?
- ret.value :
- undefined;
- },
- 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)
- return name === "value" || value === elem.getAttribute( name ) ?
- value :
- undefined;
- }
- };
-
- // Set contenteditable to false on removals(#10429)
- // Setting to empty string throws an error as an invalid value
- jQuery.attrHooks.contenteditable = {
- get: nodeHook.get,
- 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 ] = jQuery.extend( jQuery.attrHooks[ name ], {
- set: function( elem, value ) {
- if ( value === "" ) {
- elem.setAttribute( name, "auto" );
- return value;
- }
- }
- });
- });
- }
-
-
-// Some attributes require a special call on IE
-// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
- if ( !jQuery.support.hrefNormalized ) {
- jQuery.each([ "href", "src", "width", "height" ], function( i, name ) {
- jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
- get: function( elem ) {
- var ret = elem.getAttribute( name, 2 );
- return ret == null ? undefined : ret;
- }
- });
- });
-
- // 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 );
- }
- };
- });
- }
-
- if ( !jQuery.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 + "" );
- }
- };
- }
-
-// Safari mis-reports the default selected property of an option
-// Accessing the parent's selectedIndex property fixes it
- if ( !jQuery.support.optSelected ) {
- jQuery.propHooks.selected = jQuery.extend( 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;
- }
- });
- }
-
-// IE6/7 call enctype encoding
- if ( !jQuery.support.enctype ) {
- jQuery.propFix.enctype = "encoding";
- }
-
-// Radios and checkboxes getter/setter
- if ( !jQuery.support.checkOn ) {
- jQuery.each([ "radio", "checkbox" ], function() {
- jQuery.valHooks[ this ] = {
- get: function( elem ) {
- // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
- return elem.getAttribute("value") === null ? "on" : elem.value;
- }
- };
- });
- }
- jQuery.each([ "radio", "checkbox" ], function() {
- jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], {
- set: function( elem, value ) {
- if ( jQuery.isArray( value ) ) {
- return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
- }
- }
- });
- });
- var rformElems = /^(?:input|select|textarea)$/i,
- rkeyEvent = /^key/,
- rmouseEvent = /^(?:mouse|contextmenu)|click/,
- rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
- rtypenamespace = /^([^.]*)(?:\.(.+)|)$/;
-
- function returnTrue() {
- return true;
- }
-
- function returnFalse() {
- return false;
- }
-
- /*
- * 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 !== core_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
- // jQuery(...).bind("mouseover mouseout", fn);
- types = ( types || "" ).match( core_rnotwhite ) || [""];
- t = types.length;
- while ( t-- ) {
- tmp = rtypenamespace.exec( types[t] ) || [];
- type = origType = tmp[1];
- namespaces = ( tmp[2] || "" ).split( "." ).sort();
-
- // 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( core_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 = core_hasOwn.call( event, "type" ) ? event.type : event,
- namespaces = core_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 );
-
- event.isTrigger = true;
- 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 && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === 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( elem.ownerDocument, data ) === false) &&
- !(type === "click" && jQuery.nodeName( elem, "a" )) && 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 = core_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") ) {
-
- for ( ; cur != this; cur = cur.parentNode || this ) {
-
- // 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
- },
- 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;
- }
- }
- },
- focus: {
- // Fire native event if possible so blur/focus sequence is correct
- trigger: function() {
- if ( this !== document.activeElement && 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 === document.activeElement && this.blur ) {
- this.blur();
- return false;
- }
- },
- delegateType: "focusout"
- },
-
- beforeunload: {
- postDispatch: function( event ) {
-
- // Even when returnValue equals to undefined Firefox will still show alert
- if ( event.result !== undefined ) {
- 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 ] === core_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.returnValue === false ||
- src.getPreventDefault && src.getPreventDefault() ) ? 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-bind...
- 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() {
- this.isImmediatePropagationStopped = returnTrue;
- this.stopPropagation();
- }
- };
-
-// Create mouseenter/leave events using mouseover/out and event-time checks
- jQuery.each({
- mouseenter: "mouseover",
- mouseleave: "mouseout"
- }, 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 ( !jQuery.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 ( !jQuery.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 ( !jQuery.support.focusinBubbles ) {
- jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
-
- // Attach a single capturing handler while someone wants focusin/focusout
- var attaches = 0,
- handler = function( event ) {
- jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
- };
-
- jQuery.event.special[ fix ] = {
- setup: function() {
- if ( attaches++ === 0 ) {
- document.addEventListener( orig, handler, true );
- }
- },
- teardown: function() {
- if ( --attaches === 0 ) {
- document.removeEventListener( orig, handler, true );
- }
- }
- };
- });
- }
-
- 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 );
- });
- },
-
- 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 );
- },
-
- 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 );
- }
- }
- });
- /*!
- * Sizzle CSS Selector Engine
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license
- * http://sizzlejs.com/
- */
- (function( window, undefined ) {
-
- var i,
- cachedruns,
- Expr,
- getText,
- isXML,
- compile,
- hasDuplicate,
- outermostContext,
-
- // Local document vars
- setDocument,
- document,
- docElem,
- documentIsXML,
- rbuggyQSA,
- rbuggyMatches,
- matches,
- contains,
- sortOrder,
-
- // Instance-specific data
- expando = "sizzle" + -(new Date()),
- preferredDoc = window.document,
- support = {},
- dirruns = 0,
- done = 0,
- classCache = createCache(),
- tokenCache = createCache(),
- compilerCache = createCache(),
-
- // General-purpose constants
- strundefined = typeof undefined,
- MAX_NEGATIVE = 1 << 31,
-
- // Array methods
- arr = [],
- pop = arr.pop,
- push = arr.push,
- slice = arr.slice,
- // Use a stripped-down indexOf if we can't use a native one
- indexOf = arr.indexOf || function( elem ) {
- var i = 0,
- len = this.length;
- for ( ; i < len; i++ ) {
- if ( this[i] === elem ) {
- return i;
- }
- }
- return -1;
- },
-
-
- // 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#" ),
-
- // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors
- operators = "([*^$|!~]?=)",
- attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace +
- "*(?:" + operators + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]",
-
- // Prefer arguments quoted,
- // then not containing pseudos/brackets,
- // then attribute selectors/non-parenthetical expressions,
- // then anything else
- // These preferences are here to reduce the number of selectors
- // needing tokenize in the PSEUDO preFilter
- pseudos = ":(" + characterEncoding + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes.replace( 3, 8 ) + ")*)|.*)\\)|)",
-
- // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
- rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
-
- rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
- rcombinators = new RegExp( "^" + whitespace + "*([\\x20\\t\\r\\n\\f>+~])" + whitespace + "*" ),
- rpseudo = new RegExp( pseudos ),
- ridentifier = new RegExp( "^" + identifier + "$" ),
-
- matchExpr = {
- "ID": new RegExp( "^#(" + characterEncoding + ")" ),
- "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
- "NAME": new RegExp( "^\\[name=['\"]?(" + 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" ),
- // 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" )
- },
-
- rsibling = /[\x20\t\r\n\f]*[+~]/,
-
- rnative = /^[^{]+\{\s*\[native code/,
-
- // Easily-parseable/retrievable ID or TAG or CLASS selectors
- rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
-
- rinputs = /^(?:input|select|textarea|button)$/i,
- rheader = /^h\d$/i,
-
- rescape = /'|\\/g,
- rattributeQuotes = /\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,
-
- // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
- runescape = /\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g,
- funescape = function( _, escaped ) {
- var high = "0x" + escaped - 0x10000;
- // NaN means non-codepoint
- return high !== high ?
- escaped :
- // BMP codepoint
- high < 0 ?
- String.fromCharCode( high + 0x10000 ) :
- // Supplemental Plane codepoint (surrogate pair)
- String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
- };
-
-// Use a stripped-down slice if we can't use a native one
- try {
- slice.call( preferredDoc.documentElement.childNodes, 0 )[0].nodeType;
- } catch ( e ) {
- slice = function( i ) {
- var elem,
- results = [];
- while ( (elem = this[i++]) ) {
- results.push( elem );
- }
- return results;
- };
- }
-
- /**
- * For feature detection
- * @param {Function} fn The function to test for native support
- */
- function isNative( fn ) {
- return rnative.test( fn + "" );
- }
-
- /**
- * 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 cache,
- keys = [];
-
- return (cache = function( 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);
- });
- }
-
- /**
- * 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 {
- // release memory in IE
- div = null;
- }
- }
-
- function Sizzle( selector, context, results, seed ) {
- var match, elem, m, nodeType,
- // QSA vars
- i, groups, old, nid, newContext, newSelector;
-
- if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
- setDocument( context );
- }
-
- context = context || document;
- results = results || [];
-
- if ( !selector || typeof selector !== "string" ) {
- return results;
- }
-
- if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {
- return [];
- }
-
- if ( !documentIsXML && !seed ) {
-
- // Shortcuts
- if ( (match = rquickExpr.exec( selector )) ) {
- // Speed-up: Sizzle("#ID")
- if ( (m = match[1]) ) {
- if ( nodeType === 9 ) {
- elem = context.getElementById( m );
- // Check parentNode to catch when Blackberry 4.6 returns
- // nodes that are no longer in the document #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, slice.call(context.getElementsByTagName( selector ), 0) );
- return results;
-
- // Speed-up: Sizzle(".CLASS")
- } else if ( (m = match[3]) && support.getByClassName && context.getElementsByClassName ) {
- push.apply( results, slice.call(context.getElementsByClassName( m ), 0) );
- return results;
- }
- }
-
- // QSA path
- if ( support.qsa && !rbuggyQSA.test(selector) ) {
- old = true;
- nid = expando;
- newContext = context;
- newSelector = nodeType === 9 && selector;
-
- // qSA works strangely on Element-rooted queries
- // We can work around this by specifying an extra ID on the root
- // and working up from there (Thanks to Andrew Dupont for the technique)
- // IE 8 doesn't work on object elements
- if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
- groups = tokenize( selector );
-
- if ( (old = context.getAttribute("id")) ) {
- nid = old.replace( rescape, "\\$&" );
- } else {
- context.setAttribute( "id", nid );
- }
- nid = "[id='" + nid + "'] ";
-
- i = groups.length;
- while ( i-- ) {
- groups[i] = nid + toSelector( groups[i] );
- }
- newContext = rsibling.test( selector ) && context.parentNode || context;
- newSelector = groups.join(",");
- }
-
- if ( newSelector ) {
- try {
- push.apply( results, slice.call( newContext.querySelectorAll(
- newSelector
- ), 0 ) );
- return results;
- } catch(qsaError) {
- } finally {
- if ( !old ) {
- context.removeAttribute("id");
- }
- }
- }
- }
- }
-
- // All others
- return select( selector.replace( rtrim, "$1" ), context, results, seed );
- }
-
- /**
- * Detect xml
- * @param {Element|Object} elem An element or a document
- */
- 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 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;
-
- // Support tests
- documentIsXML = isXML( doc );
-
- // Check if getElementsByTagName("*") returns only elements
- support.tagNameNoComments = assert(function( div ) {
- div.appendChild( doc.createComment("") );
- return !div.getElementsByTagName("*").length;
- });
-
- // Check if attributes should be retrieved by attribute nodes
- support.attributes = assert(function( div ) {
- div.innerHTML = "<select></select>";
- var type = typeof div.lastChild.getAttribute("multiple");
- // IE8 returns a string for some attributes even when not present
- return type !== "boolean" && type !== "string";
- });
-
- // Check if getElementsByClassName can be trusted
- support.getByClassName = assert(function( div ) {
- // Opera can't find a second classname (in 9.6)
- div.innerHTML = "<div class='hidden e'></div><div class='hidden'></div>";
- if ( !div.getElementsByClassName || !div.getElementsByClassName("e").length ) {
- return false;
- }
-
- // Safari 3.2 caches class attributes and doesn't catch changes
- div.lastChild.className = "e";
- return div.getElementsByClassName("e").length === 2;
- });
-
- // Check if getElementById returns elements by name
- // Check if getElementsByName privileges form controls or returns elements by ID
- support.getByName = assert(function( div ) {
- // Inject content
- div.id = expando + 0;
- div.innerHTML = "<a name='" + expando + "'></a><div name='" + expando + "'></div>";
- docElem.insertBefore( div, docElem.firstChild );
-
- // Test
- var pass = doc.getElementsByName &&
- // buggy browsers will return fewer than the correct 2
- doc.getElementsByName( expando ).length === 2 +
- // buggy browsers will return more than the correct 0
- doc.getElementsByName( expando + 0 ).length;
- support.getIdNotName = !doc.getElementById( expando );
-
- // Cleanup
- docElem.removeChild( div );
-
- return pass;
- });
-
- // IE6/7 return modified attributes
- Expr.attrHandle = assert(function( div ) {
- div.innerHTML = "<a href='#'></a>";
- return div.firstChild && typeof div.firstChild.getAttribute !== strundefined &&
- div.firstChild.getAttribute("href") === "#";
- }) ?
- {} :
- {
- "href": function( elem ) {
- return elem.getAttribute( "href", 2 );
- },
- "type": function( elem ) {
- return elem.getAttribute("type");
- }
- };
-
- // ID find and filter
- if ( support.getIdNotName ) {
- Expr.find["ID"] = function( id, context ) {
- if ( typeof context.getElementById !== strundefined && !documentIsXML ) {
- 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 {
- Expr.find["ID"] = function( id, context ) {
- if ( typeof context.getElementById !== strundefined && !documentIsXML ) {
- var m = context.getElementById( id );
-
- return m ?
- m.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode("id").value === id ?
- [m] :
- undefined :
- [];
- }
- };
- Expr.filter["ID"] = function( id ) {
- var attrId = id.replace( runescape, funescape );
- return function( elem ) {
- var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
- return node && node.value === attrId;
- };
- };
- }
-
- // Tag
- Expr.find["TAG"] = support.tagNameNoComments ?
- function( tag, context ) {
- if ( typeof context.getElementsByTagName !== strundefined ) {
- return context.getElementsByTagName( tag );
- }
- } :
- function( tag, context ) {
- var elem,
- tmp = [],
- i = 0,
- results = context.getElementsByTagName( tag );
-
- // Filter out possible comments
- if ( tag === "*" ) {
- while ( (elem = results[i++]) ) {
- if ( elem.nodeType === 1 ) {
- tmp.push( elem );
- }
- }
-
- return tmp;
- }
- return results;
- };
-
- // Name
- Expr.find["NAME"] = support.getByName && function( tag, context ) {
- if ( typeof context.getElementsByName !== strundefined ) {
- return context.getElementsByName( name );
- }
- };
-
- // Class
- Expr.find["CLASS"] = support.getByClassName && function( className, context ) {
- if ( typeof context.getElementsByClassName !== strundefined && !documentIsXML ) {
- return context.getElementsByClassName( className );
- }
- };
-
- // QSA and matchesSelector support
-
- // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
- rbuggyMatches = [];
-
- // qSa(:focus) reports false when true (Chrome 21),
- // no need to also add to buggyMatches since matches checks buggyQSA
- // A support test would require too much code (would include document ready)
- rbuggyQSA = [ ":focus" ];
-
- if ( (support.qsa = isNative(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 explictly
- // setting a boolean content attribute,
- // since its presence should be enough
- // http://bugs.jquery.com/ticket/12359
- div.innerHTML = "<select><option selected=''></option></select>";
-
- // IE8 - Some boolean attributes are not treated correctly
- if ( !div.querySelectorAll("[selected]").length ) {
- rbuggyQSA.push( "\\[" + whitespace + "*(?:checked|disabled|ismap|multiple|readonly|selected|value)" );
- }
-
- // Webkit/Opera - :checked should return selected option elements
- // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
- // IE8 throws error here and will not see later tests
- if ( !div.querySelectorAll(":checked").length ) {
- rbuggyQSA.push(":checked");
- }
- });
-
- assert(function( div ) {
-
- // Opera 10-12/IE8 - ^= $= *= and empty values
- // Should not select anything
- div.innerHTML = "<input type='hidden' i=''/>";
- if ( div.querySelectorAll("[i^='']").length ) {
- rbuggyQSA.push( "[*^$]=" + 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 = isNative( (matches = docElem.matchesSelector ||
- docElem.mozMatchesSelector ||
- docElem.webkitMatchesSelector ||
- 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 = new RegExp( rbuggyQSA.join("|") );
- rbuggyMatches = new RegExp( rbuggyMatches.join("|") );
-
- // Element contains another
- // Purposefully does not implement inclusive descendent
- // As in, an element does not contain itself
- contains = isNative(docElem.contains) || docElem.compareDocumentPosition ?
- 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;
- };
-
- // Document order sorting
- sortOrder = docElem.compareDocumentPosition ?
- function( a, b ) {
- var compare;
-
- if ( a === b ) {
- hasDuplicate = true;
- return 0;
- }
-
- if ( (compare = b.compareDocumentPosition && a.compareDocumentPosition && a.compareDocumentPosition( b )) ) {
- if ( compare & 1 || a.parentNode && a.parentNode.nodeType === 11 ) {
- if ( a === doc || contains( preferredDoc, a ) ) {
- return -1;
- }
- if ( b === doc || contains( preferredDoc, b ) ) {
- return 1;
- }
- return 0;
- }
- return compare & 4 ? -1 : 1;
- }
-
- return a.compareDocumentPosition ? -1 : 1;
- } :
- function( a, b ) {
- var cur,
- i = 0,
- aup = a.parentNode,
- bup = b.parentNode,
- ap = [ a ],
- bp = [ b ];
-
- // Exit early if the nodes are identical
- if ( a === b ) {
- hasDuplicate = true;
- return 0;
-
- // Parentless nodes are either documents or disconnected
- } else if ( !aup || !bup ) {
- return a === doc ? -1 :
- b === doc ? 1 :
- aup ? -1 :
- bup ? 1 :
- 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;
- };
-
- // Always assume the presence of duplicates if sort doesn't
- // pass them to our comparison function (as in Google Chrome).
- hasDuplicate = false;
- [0, 0].sort( sortOrder );
- support.detectDuplicates = hasDuplicate;
-
- return document;
- };
-
- 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']" );
-
- // rbuggyQSA always contains :focus, so no need for an existence check
- if ( support.matchesSelector && !documentIsXML && (!rbuggyMatches || !rbuggyMatches.test(expr)) && !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 ) {
- var val;
-
- // Set document vars if needed
- if ( ( elem.ownerDocument || elem ) !== document ) {
- setDocument( elem );
- }
-
- if ( !documentIsXML ) {
- name = name.toLowerCase();
- }
- if ( (val = Expr.attrHandle[ name ]) ) {
- return val( elem );
- }
- if ( documentIsXML || support.attributes ) {
- return elem.getAttribute( name );
- }
- return ( (val = elem.getAttributeNode( name )) || elem.getAttribute( name ) ) && elem[ name ] === true ?
- name :
- val && val.specified ? val.value : null;
- };
-
- Sizzle.error = function( msg ) {
- throw new Error( "Syntax error, unrecognized expression: " + msg );
- };
-
-// Document sorting and removing duplicates
- Sizzle.uniqueSort = function( results ) {
- var elem,
- duplicates = [],
- i = 1,
- j = 0;
-
- // Unless we *know* we can detect duplicates, assume their presence
- hasDuplicate = !support.detectDuplicates;
- results.sort( sortOrder );
-
- if ( hasDuplicate ) {
- for ( ; (elem = results[i]); i++ ) {
- if ( elem === results[ i - 1 ] ) {
- j = duplicates.push( i );
- }
- }
- while ( j-- ) {
- results.splice( duplicates[ j ], 1 );
- }
- }
-
- return results;
- };
-
- function siblingCheck( a, b ) {
- var cur = b && a,
- diff = cur && ( ~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
- 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
- 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
- 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]);
- }
- }
- });
- });
- }
-
- /**
- * 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
- for ( ; (node = elem[i]); 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 (see #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,
-
- 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[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[5] && match[2];
-
- if ( matchExpr["CHILD"].test( match[0] ) ) {
- return null;
- }
-
- // Accept quoted arguments as-is
- if ( match[4] ) {
- match[2] = match[4];
-
- // 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( nodeName ) {
- if ( nodeName === "*" ) {
- return function() { return true; };
- }
-
- nodeName = nodeName.replace( runescape, funescape ).toLowerCase();
- return 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( elem.className || (typeof elem.getAttribute !== strundefined && elem.getAttribute("class")) || "" );
- });
- },
-
- "ATTR": function( name, operator, check ) {
- return function( elem ) {
- var result = Sizzle.attr( elem, name );
-
- if ( result == null ) {
- return operator === "!=";
- }
- if ( !operator ) {
- return true;
- }
-
- result += "";
-
- return operator === "=" ? result === check :
- operator === "!=" ? result !== check :
- operator === "^=" ? check && result.indexOf( check ) === 0 :
- operator === "*=" ? check && result.indexOf( check ) > -1 :
- operator === "$=" ? check && result.slice( -check.length ) === check :
- operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
- operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
- false;
- };
- },
-
- "CHILD": function( type, what, argument, first, last ) {
- var simple = type.slice( 0, 3 ) !== "nth",
- forward = type.slice( -4 ) !== "last",
- ofType = what === "of-type";
-
- return first === 1 && last === 0 ?
-
- // Shortcut for :nth-*(n)
- function( elem ) {
- return !!elem.parentNode;
- } :
-
- function( elem, context, xml ) {
- var cache, outerCache, node, diff, nodeIndex, start,
- dir = simple !== forward ? "nextSibling" : "previousSibling",
- parent = elem.parentNode,
- name = ofType && elem.nodeName.toLowerCase(),
- useCache = !xml && !ofType;
-
- if ( parent ) {
-
- // :(first|last|only)-(child|of-type)
- if ( simple ) {
- while ( dir ) {
- node = elem;
- while ( (node = node[ dir ]) ) {
- if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {
- return false;
- }
- }
- // Reverse direction for :only-* (if we haven't yet done so)
- start = dir = type === "only" && !start && "nextSibling";
- }
- return true;
- }
-
- start = [ forward ? parent.firstChild : parent.lastChild ];
-
- // non-xml :nth-child(...) stores cache data on `parent`
- if ( forward && useCache ) {
- // Seek `elem` from a previously-cached index
- outerCache = parent[ expando ] || (parent[ expando ] = {});
- cache = outerCache[ type ] || [];
- nodeIndex = cache[0] === dirruns && cache[1];
- diff = cache[0] === dirruns && cache[2];
- node = nodeIndex && parent.childNodes[ nodeIndex ];
-
- while ( (node = ++nodeIndex && node && node[ dir ] ||
-
- // Fallback to seeking `elem` from the start
- (diff = nodeIndex = 0) || start.pop()) ) {
-
- // When found, cache indexes on `parent` and break
- if ( node.nodeType === 1 && ++diff && node === elem ) {
- outerCache[ type ] = [ dirruns, nodeIndex, diff ];
- break;
- }
- }
-
- // Use previously-cached element index if available
- } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {
- diff = cache[1];
-
- // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)
- } else {
- // Use the same loop as above to seek `elem` from the start
- while ( (node = ++nodeIndex && node && node[ dir ] ||
- (diff = nodeIndex = 0) || start.pop()) ) {
-
- if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {
- // Cache the index of each encountered element
- if ( useCache ) {
- (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];
- }
-
- if ( node === elem ) {
- break;
- }
- }
- }
- }
-
- // Incorporate the offset, then check against cycle size
- diff -= last;
- return diff === first || ( diff % first === 0 && diff / first >= 0 );
- }
- };
- },
-
- "PSEUDO": function( pseudo, argument ) {
- // pseudo-class names are case-insensitive
- // http://www.w3.org/TR/selectors/#pseudo-classes
- // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
- // Remember that setFilters inherits from pseudos
- var args,
- fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
- Sizzle.error( "unsupported pseudo: " + pseudo );
-
- // The user may use createPseudo to indicate that
- // arguments are needed to create the filter function
- // just as Sizzle does
- if ( fn[ expando ] ) {
- return fn( argument );
- }
-
- // But maintain support for old signatures
- if ( fn.length > 1 ) {
- args = [ pseudo, pseudo, "", argument ];
- return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
- markFunction(function( seed, matches ) {
- var idx,
- matched = fn( seed, argument ),
- i = matched.length;
- while ( i-- ) {
- idx = indexOf.call( seed, matched[i] );
- seed[ idx ] = !( matches[ idx ] = matched[i] );
- }
- }) :
- function( elem ) {
- return fn( elem, 0, args );
- };
- }
-
- return fn;
- }
- },
-
- pseudos: {
- // Potentially complex pseudos
- "not": markFunction(function( selector ) {
- // Trim the selector passed to compile
- // to avoid treating leading and trailing
- // spaces as combinators
- var input = [],
- results = [],
- matcher = compile( selector.replace( rtrim, "$1" ) );
-
- return matcher[ expando ] ?
- markFunction(function( seed, matches, context, xml ) {
- var elem,
- unmatched = matcher( seed, null, xml, [] ),
- i = seed.length;
-
- // Match elements unmatched by `matcher`
- while ( i-- ) {
- if ( (elem = unmatched[i]) ) {
- seed[i] = !(matches[i] = elem);
- }
- }
- }) :
- function( elem, context, xml ) {
- input[0] = elem;
- matcher( input, null, xml, results );
- return !results.pop();
- };
- }),
-
- "has": markFunction(function( selector ) {
- return function( elem ) {
- return Sizzle( selector, elem ).length > 0;
- };
- }),
-
- "contains": markFunction(function( text ) {
- return function( elem ) {
- return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
- };
- }),
-
- // "Whether an element is represented by a :lang() selector
- // is based solely on the element's language value
- // being equal to the identifier C,
- // or beginning with the identifier C immediately followed by "-".
- // The matching of C against the element's language value is performed case-insensitively.
- // The identifier C does not have to be a valid language name."
- // http://www.w3.org/TR/selectors/#lang-pseudo
- "lang": markFunction( function( lang ) {
- // lang value must be a valid identifider
- if ( !ridentifier.test(lang || "") ) {
- Sizzle.error( "unsupported lang: " + lang );
- }
- lang = lang.replace( runescape, funescape ).toLowerCase();
- return function( elem ) {
- var elemLang;
- do {
- if ( (elemLang = documentIsXML ?
- elem.getAttribute("xml:lang") || elem.getAttribute("lang") :
- elem.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 only affected by element nodes and content nodes(including text(3), cdata(4)),
- // not comment, processing instructions, or others
- // Thanks to Diego Perini for the nodeName shortcut
- // Greater than "@" means alpha characters (specifically not starting with "#" or "?")
- for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
- if ( elem.nodeName > "@" || elem.nodeType === 3 || elem.nodeType === 4 ) {
- 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;
- // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
- // use getAttribute instead to test this case
- return elem.nodeName.toLowerCase() === "input" &&
- elem.type === "text" &&
- ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === elem.type );
- },
-
- // 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;
- })
- }
- };
-
-// 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 );
- }
-
- function tokenize( 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 data, cache, outerCache,
- dirkey = 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 ( (cache = outerCache[ dir ]) && cache[0] === dirkey ) {
- if ( (data = cache[1]) === true || data === cachedruns ) {
- return data === true;
- }
- } else {
- cache = outerCache[ dir ] = [ dirkey ];
- cache[1] = matcher( elem, context, xml ) || cachedruns;
- if ( cache[1] === true ) {
- 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 condense( unmatched, map, filter, context, xml ) {
- var elem,
- newUnmatched = [],
- i = 0,
- len = unmatched.length,
- mapped = map != null;
-
- for ( ; i < len; i++ ) {
- if ( (elem = unmatched[i]) ) {
- if ( !filter || filter( elem, context, xml ) ) {
- newUnmatched.push( elem );
- if ( mapped ) {
- map.push( i );
- }
- }
- }
- }
-
- return newUnmatched;
- }
-
- function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
- if ( postFilter && !postFilter[ expando ] ) {
- postFilter = setMatcher( postFilter );
- }
- if ( postFinder && !postFinder[ expando ] ) {
- postFinder = setMatcher( postFinder, postSelector );
- }
- return markFunction(function( seed, results, context, xml ) {
- var temp, i, elem,
- preMap = [],
- postMap = [],
- preexisting = results.length,
-
- // Get initial elements from seed or context
- elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
-
- // Prefilter to get matcher input, preserving a map for seed-results synchronization
- matcherIn = preFilter && ( seed || !selector ) ?
- condense( elems, preMap, preFilter, context, xml ) :
- elems,
-
- matcherOut = matcher ?
- // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
- postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
-
- // ...intermediate processing is necessary
- [] :
-
- // ...otherwise use results directly
- results :
- matcherIn;
-
- // Find primary matches
- if ( matcher ) {
- matcher( matcherIn, matcherOut, context, xml );
- }
-
- // Apply postFilter
- if ( postFilter ) {
- temp = condense( matcherOut, postMap );
- postFilter( temp, [], context, xml );
-
- // Un-match failing elements by moving them back to matcherIn
- i = temp.length;
- while ( i-- ) {
- if ( (elem = temp[i]) ) {
- matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
- }
- }
- }
-
- if ( seed ) {
- if ( postFinder || preFilter ) {
- if ( postFinder ) {
- // Get the final matcherOut by condensing this intermediate into postFinder contexts
- temp = [];
- i = matcherOut.length;
- while ( i-- ) {
- if ( (elem = matcherOut[i]) ) {
- // Restore matcherIn since elem is not yet a final match
- temp.push( (matcherIn[i] = elem) );
- }
- }
- postFinder( null, (matcherOut = []), temp, xml );
- }
-
- // Move matched elements from seed to results to keep them synchronized
- i = matcherOut.length;
- while ( i-- ) {
- if ( (elem = matcherOut[i]) &&
- (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
-
- seed[temp] = !(results[temp] = elem);
- }
- }
- }
-
- // Add elements to results, through postFinder if defined
- } else {
- matcherOut = condense(
- matcherOut === results ?
- matcherOut.splice( preexisting, matcherOut.length ) :
- matcherOut
- );
- if ( postFinder ) {
- postFinder( null, results, matcherOut, xml );
- } else {
- push.apply( results, matcherOut );
- }
- }
- });
- }
-
- function matcherFromTokens( tokens ) {
- var checkContext, matcher, j,
- len = tokens.length,
- leadingRelative = Expr.relative[ tokens[0].type ],
- implicitRelative = leadingRelative || Expr.relative[" "],
- i = leadingRelative ? 1 : 0,
-
- // The foundational matcher ensures that elements are reachable from top-level context(s)
- matchContext = addCombinator( function( elem ) {
- return elem === checkContext;
- }, implicitRelative, true ),
- matchAnyContext = addCombinator( function( elem ) {
- return indexOf.call( checkContext, elem ) > -1;
- }, implicitRelative, true ),
- matchers = [ function( elem, context, xml ) {
- return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
- (checkContext = context).nodeType ?
- matchContext( elem, context, xml ) :
- matchAnyContext( elem, context, xml ) );
- } ];
-
- for ( ; i < len; i++ ) {
- if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
- matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
- } else {
- matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
-
- // Return special upon seeing a positional matcher
- if ( matcher[ expando ] ) {
- // Find the next relative operator (if any) for proper handling
- j = ++i;
- for ( ; j < len; j++ ) {
- if ( Expr.relative[ tokens[j].type ] ) {
- break;
- }
- }
- return setMatcher(
- i > 1 && elementMatcher( matchers ),
- i > 1 && toSelector( tokens.slice( 0, i - 1 ) ).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 ) {
- // A counter to specify which element is currently being matched
- var matcherCachedRuns = 0,
- bySet = setMatchers.length > 0,
- byElement = elementMatchers.length > 0,
- superMatcher = function( seed, context, xml, results, expandContext ) {
- var elem, j, matcher,
- setMatched = [],
- matchedCount = 0,
- i = "0",
- unmatched = seed && [],
- outermost = expandContext != null,
- contextBackup = outermostContext,
- // We must always have either seed elements or context
- elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ),
- // Use integer dirruns iff this is the outermost matcher
- dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1);
-
- if ( outermost ) {
- outermostContext = context !== document && context;
- cachedruns = matcherCachedRuns;
- }
-
- // Add elements passing elementMatchers directly to results
- // Keep `i` a string if there are no elements so `matchedCount` will be "00" below
- for ( ; (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;
- cachedruns = ++matcherCachedRuns;
- }
- }
-
- // 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, group /* 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 ( !group ) {
- group = tokenize( selector );
- }
- i = group.length;
- while ( i-- ) {
- cached = matcherFromTokens( group[i] );
- if ( cached[ expando ] ) {
- setMatchers.push( cached );
- } else {
- elementMatchers.push( cached );
- }
- }
-
- // Cache the compiled function
- cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
- }
- return cached;
- };
-
- function multipleContexts( selector, contexts, results ) {
- var i = 0,
- len = contexts.length;
- for ( ; i < len; i++ ) {
- Sizzle( selector, contexts[i], results );
- }
- return results;
- }
-
- function select( selector, context, results, seed ) {
- var i, tokens, token, type, find,
- match = tokenize( selector );
-
- if ( !seed ) {
- // Try to minimize operations if there is 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" &&
- context.nodeType === 9 && !documentIsXML &&
- Expr.relative[ tokens[1].type ] ) {
-
- context = Expr.find["ID"]( token.matches[0].replace( runescape, funescape ), context )[0];
- if ( !context ) {
- return results;
- }
-
- 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 ) && 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, slice.call( seed, 0 ) );
- return results;
- }
-
- break;
- }
- }
- }
- }
- }
-
- // Compile and execute a filtering function
- // Provide `match` to avoid retokenization if we modified the selector above
- compile( selector, match )(
- seed,
- context,
- documentIsXML,
- results,
- rsibling.test( selector )
- );
- return results;
- }
-
-// Deprecated
- Expr.pseudos["nth"] = Expr.pseudos["eq"];
-
-// Easy API for creating new setFilters
- function setFilters() {}
- Expr.filters = setFilters.prototype = Expr.pseudos;
- Expr.setFilters = new setFilters();
-
-// Initialize with the default document
- setDocument();
-
-// Override sizzle attribute retrieval
- Sizzle.attr = jQuery.attr;
- 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;
-
-
- })( window );
- var runtil = /Until$/,
- rparentsprev = /^(?:parents|prev(?:Until|All))/,
- isSimple = /^.[^:#\[\.,]*$/,
- rneedsContext = jQuery.expr.match.needsContext,
- // methods guaranteed to produce a unique set when starting from a unique set
- guaranteedUnique = {
- children: true,
- contents: true,
- next: true,
- prev: true
- };
-
- jQuery.fn.extend({
- find: function( selector ) {
- var i, ret, self,
- len = this.length;
-
- if ( typeof selector !== "string" ) {
- self = this;
- return this.pushStack( jQuery( selector ).filter(function() {
- for ( i = 0; i < len; i++ ) {
- if ( jQuery.contains( self[ i ], this ) ) {
- return true;
- }
- }
- }) );
- }
-
- ret = [];
- for ( i = 0; i < len; i++ ) {
- jQuery.find( selector, this[ 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;
- return ret;
- },
-
- 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;
- }
- }
- });
- },
-
- not: function( selector ) {
- return this.pushStack( winnow(this, selector, false) );
- },
-
- filter: function( selector ) {
- return this.pushStack( winnow(this, selector, true) );
- },
-
- is: function( selector ) {
- return !!selector && (
- typeof selector === "string" ?
- // 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".
- rneedsContext.test( selector ) ?
- jQuery( selector, this.context ).index( this[0] ) >= 0 :
- jQuery.filter( selector, this ).length > 0 :
- this.filter( selector ).length > 0 );
- },
-
- closest: function( selectors, context ) {
- var cur,
- i = 0,
- l = this.length,
- ret = [],
- pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
- jQuery( selectors, context || this.context ) :
- 0;
-
- for ( ; i < l; i++ ) {
- cur = this[i];
-
- while ( cur && cur.ownerDocument && cur !== context && cur.nodeType !== 11 ) {
- if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {
- ret.push( cur );
- break;
- }
- cur = cur.parentNode;
- }
- }
-
- return this.pushStack( ret.length > 1 ? jQuery.unique( ret ) : ret );
- },
-
- // 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 ) {
- var set = typeof selector === "string" ?
- jQuery( selector, context ) :
- jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
- all = jQuery.merge( this.get(), set );
-
- return this.pushStack( jQuery.unique(all) );
- },
-
- addBack: function( selector ) {
- return this.add( selector == null ?
- this.prevObject : this.prevObject.filter(selector)
- );
- }
- });
-
- jQuery.fn.andSelf = jQuery.fn.addBack;
-
- 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 ( !runtil.test( name ) ) {
- selector = until;
- }
-
- if ( selector && typeof selector === "string" ) {
- ret = jQuery.filter( selector, ret );
- }
-
- ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
-
- if ( this.length > 1 && rparentsprev.test( name ) ) {
- ret = ret.reverse();
- }
-
- return this.pushStack( ret );
- };
- });
-
- jQuery.extend({
- filter: function( expr, elems, not ) {
- if ( not ) {
- expr = ":not(" + expr + ")";
- }
-
- return elems.length === 1 ?
- jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :
- jQuery.find.matches(expr, elems);
- },
-
- 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;
- }
- });
-
-// Implement the identical functionality for filter and not
- function winnow( elements, qualifier, keep ) {
-
- // Can't pass null or undefined to indexOf in Firefox 4
- // Set to 0 to skip string check
- qualifier = qualifier || 0;
-
- if ( jQuery.isFunction( qualifier ) ) {
- return jQuery.grep(elements, function( elem, i ) {
- var retVal = !!qualifier.call( elem, i, elem );
- return retVal === keep;
- });
-
- } else if ( qualifier.nodeType ) {
- return jQuery.grep(elements, function( elem ) {
- return ( elem === qualifier ) === keep;
- });
-
- } else if ( typeof qualifier === "string" ) {
- var filtered = jQuery.grep(elements, function( elem ) {
- return elem.nodeType === 1;
- });
-
- if ( isSimple.test( qualifier ) ) {
- return jQuery.filter(qualifier, filtered, !keep);
- } else {
- qualifier = jQuery.filter( qualifier, filtered );
- }
- }
-
- return jQuery.grep(elements, function( elem ) {
- return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep;
- });
- }
- 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,
- manipulation_rcheckableType = /^(?:checkbox|radio)$/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: jQuery.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;
-
- jQuery.fn.extend({
- text: function( value ) {
- return jQuery.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 );
- },
-
- 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();
- },
-
- append: function() {
- return this.domManip(arguments, true, function( elem ) {
- if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
- this.appendChild( elem );
- }
- });
- },
-
- prepend: function() {
- return this.domManip(arguments, true, function( elem ) {
- if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
- this.insertBefore( elem, this.firstChild );
- }
- });
- },
-
- before: function() {
- return this.domManip( arguments, false, function( elem ) {
- if ( this.parentNode ) {
- this.parentNode.insertBefore( elem, this );
- }
- });
- },
-
- after: function() {
- return this.domManip( arguments, false, function( elem ) {
- if ( this.parentNode ) {
- this.parentNode.insertBefore( elem, this.nextSibling );
- }
- });
- },
-
- // keepData is for internal use only--do not document
- remove: function( selector, keepData ) {
- var elem,
- i = 0;
-
- for ( ; (elem = this[i]) != null; i++ ) {
- if ( !selector || jQuery.filter( selector, [ elem ] ).length > 0 ) {
- 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 jQuery.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 ) &&
- ( jQuery.support.htmlSerialize || !rnoshimcache.test( value ) ) &&
- ( jQuery.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( value ) {
- var isFunc = jQuery.isFunction( value );
-
- // Make sure that the elements are removed from the DOM before they are inserted
- // this can help fix replacing a parent with child elements
- if ( !isFunc && typeof value !== "string" ) {
- value = jQuery( value ).not( this ).detach();
- }
-
- return this.domManip( [ value ], true, function( elem ) {
- var next = this.nextSibling,
- parent = this.parentNode;
-
- if ( parent ) {
- jQuery( this ).remove();
- parent.insertBefore( elem, next );
- }
- });
- },
-
- detach: function( selector ) {
- return this.remove( selector, true );
- },
-
- domManip: function( args, table, callback ) {
-
- // Flatten any nested arrays
- args = core_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" || jQuery.support.checkClone || !rchecked.test( value ) ) ) {
- return this.each(function( index ) {
- var self = set.eq( index );
- if ( isFunction ) {
- args[0] = value.call( this, index, table ? self.html() : undefined );
- }
- self.domManip( args, table, callback );
- });
- }
-
- if ( l ) {
- fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this );
- first = fragment.firstChild;
-
- if ( fragment.childNodes.length === 1 ) {
- fragment = first;
- }
-
- if ( first ) {
- table = table && jQuery.nodeName( first, "tr" );
- 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(
- table && jQuery.nodeName( this[i], "table" ) ?
- findOrAppend( this[i], "tbody" ) :
- 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 ) {
- // Hope ajax is available...
- jQuery.ajax({
- url: node.src,
- type: "GET",
- dataType: "script",
- async: false,
- global: false,
- "throws": true
- });
- } else {
- jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) );
- }
- }
- }
- }
-
- // Fix #11809: Avoid leaking memory
- fragment = first = null;
- }
- }
-
- return this;
- }
- });
-
- function findOrAppend( elem, tag ) {
- return elem.getElementsByTagName( tag )[0] || elem.appendChild( elem.ownerDocument.createElement( tag ) );
- }
-
-// Replace/restore the type attribute of script elements for safe DOM manipulation
- function disableScript( elem ) {
- var attr = elem.getAttributeNode("type");
- elem.type = ( attr && attr.specified ) + "/" + 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 ( !jQuery.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 ( jQuery.support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) {
- dest.innerHTML = src.innerHTML;
- }
-
- } else if ( nodeName === "input" && manipulation_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.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()
- core_push.apply( ret, elems.get() );
- }
-
- return this.pushStack( ret );
- };
- });
-
- function getAll( context, tag ) {
- var elems, elem,
- i = 0,
- found = typeof context.getElementsByTagName !== core_strundefined ? context.getElementsByTagName( tag || "*" ) :
- typeof context.querySelectorAll !== core_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 ( manipulation_rcheckableType.test( elem.type ) ) {
- elem.defaultChecked = elem.checked;
- }
- }
-
- jQuery.extend({
- clone: function( elem, dataAndEvents, deepDataAndEvents ) {
- var destElements, node, clone, i, srcElements,
- inPage = jQuery.contains( elem.ownerDocument, elem );
-
- if ( jQuery.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 ( (!jQuery.support.noCloneEvent || !jQuery.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 ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
- nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) );
- }
-
- // Remove IE's autoinserted <tbody> from table fragments
- if ( !jQuery.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 ( !jQuery.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 = jQuery.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 !== core_strundefined ) {
- elem.removeAttribute( internalKey );
-
- } else {
- elem[ internalKey ] = null;
- }
-
- core_deletedIds.push( id );
- }
- }
- }
- }
- }
- });
- var iframe, getStyles, curCSS,
- ralpha = /alpha\([^)]*\)/i,
- ropacity = /opacity\s*=\s*([^)]*)/,
- rposition = /^(top|right|bottom|left)$/,
- // 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]).+)/,
- rmargin = /^margin/,
- rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ),
- rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ),
- rrelNum = new RegExp( "^([+-])=(" + core_pnum + ")", "i" ),
- elemdisplay = { BODY: "block" },
-
- cssShow = { position: "absolute", visibility: "hidden", display: "block" },
- cssNormalTransform = {
- letterSpacing: 0,
- fontWeight: 400
- },
-
- cssExpand = [ "Top", "Right", "Bottom", "Left" ],
- 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 isHidden( 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 );
- }
-
- 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", css_defaultDisplay(elem.nodeName) );
- }
- } else {
-
- if ( !values[ index ] ) {
- 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;
- }
-
- jQuery.fn.extend({
- css: function( name, value ) {
- return jQuery.access( this, function( elem, name, value ) {
- var len, styles,
- 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 ) {
- var bool = typeof state === "boolean";
-
- return this.each(function() {
- if ( bool ? state : isHidden( this ) ) {
- jQuery( this ).show();
- } else {
- jQuery( this ).hide();
- }
- });
- }
- });
-
- 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;
- }
- }
- }
- },
-
- // Exclude the following css properties to add px
- cssNumber: {
- "columnCount": true,
- "fillOpacity": true,
- "fontWeight": true,
- "lineHeight": true,
- "opacity": 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": jQuery.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 NaN and null values aren't set. See: #7116
- if ( value == null || type === "number" && isNaN( 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 ( !jQuery.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 ) {
-
- // Wrapped to prevent IE from throwing errors when 'invalid' values are provided
- // Fixes bug #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;
- },
-
- // A method for quickly swapping in/out CSS properties to get correct calculations
- 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;
- }
- });
-
-// NOTE: we've included the "window" in window.getComputedStyle
-// because jsdom on node.js will break without it.
- if ( window.getComputedStyle ) {
- getStyles = function( elem ) {
- return window.getComputedStyle( elem, null );
- };
-
- curCSS = function( elem, name, _computed ) {
- var width, minWidth, maxWidth,
- computed = _computed || getStyles( elem ),
-
- // getPropertyValue is only needed for .css('filter') in IE9, see #12537
- ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined,
- style = elem.style;
-
- 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;
- }
- }
-
- return ret;
- };
- } else if ( document.documentElement.currentStyle ) {
- getStyles = function( elem ) {
- return elem.currentStyle;
- };
-
- curCSS = function( elem, name, _computed ) {
- var left, rs, rsLeft,
- computed = _computed || getStyles( elem ),
- ret = computed ? computed[ name ] : undefined,
- style = elem.style;
-
- // 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;
- }
- }
-
- return ret === "" ? "auto" : ret;
- };
- }
-
- 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 = jQuery.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 && ( jQuery.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";
- }
-
-// Try to determine the default display value of an element
- function css_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'/>")
- .css( "cssText", "display:block !important" )
- ).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;
- doc.write("<!doctype html><html><body>");
- doc.close();
-
- display = actualDisplay( nodeName, doc );
- iframe.detach();
- }
-
- // Store the correct default display
- elemdisplay[ nodeName ] = display;
- }
-
- return display;
- }
-
-// Called ONLY from within css_defaultDisplay
- function actualDisplay( name, doc ) {
- var elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),
- display = jQuery.css( elem[0], "display" );
- elem.remove();
- return display;
- }
-
- 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 elem.offsetWidth === 0 && rdisplayswap.test( jQuery.css( elem, "display" ) ) ?
- 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,
- jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
- styles
- ) : 0
- );
- }
- };
- });
-
- if ( !jQuery.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;
- }
- };
- }
-
-// These hooks cannot be added until DOM ready because the support test
-// for it is not run until after DOM ready
- jQuery(function() {
- if ( !jQuery.support.reliableMarginRight ) {
- jQuery.cssHooks.marginRight = {
- get: 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" ] );
- }
- }
- };
- }
-
- // 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
- if ( !jQuery.support.pixelPosition && jQuery.fn.position ) {
- jQuery.each( [ "top", "left" ], function( i, prop ) {
- jQuery.cssHooks[ prop ] = {
- get: 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;
- }
- }
- };
- });
- }
-
- });
-
- if ( jQuery.expr && jQuery.expr.filters ) {
- 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 ||
- (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none");
- };
-
- jQuery.expr.filters.visible = function( elem ) {
- return !jQuery.expr.filters.hidden( elem );
- };
- }
-
-// 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;
- }
- });
- var r20 = /%20/g,
- rbracket = /\[\]$/,
- rCRLF = /\r?\n/g,
- rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
- rsubmittable = /^(?:input|select|textarea|keygen)/i;
-
- 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 || !manipulation_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();
- }
- });
-
-//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, "+" );
- };
-
- 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 );
- }
- }
- 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.hover = function( fnOver, fnOut ) {
- return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
- };
- var
- // Document location
- ajaxLocParts,
- ajaxLocation,
- ajax_nonce = jQuery.now(),
-
- ajax_rquery = /\?/,
- 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+)|)|)/,
-
- // Keep a copy of the old load method
- _load = jQuery.fn.load,
-
- /* 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( core_rnotwhite ) || [];
-
- if ( jQuery.isFunction( func ) ) {
- // For each dataType in the dataTypeExpression
- while ( (dataType = dataTypes[i++]) ) {
- // Prepend if requested
- if ( dataType[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;
- }
-
- 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 = 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.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.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"
- },
-
- // Data converters
- // Keys separate source (or catchall "*") and destination types with a single space
- converters: {
-
- // Convert anything to text
- "* text": window.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( core_rnotwhite ) || [""];
-
- // A cross-domain request is in order when we have a protocol:host:port mismatch
- if ( s.crossDomain == null ) {
- parts = rurl.exec( s.url.toLowerCase() );
- s.crossDomain = !!( parts &&
- ( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
- ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) !=
- ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) )
- );
- }
-
- // Convert data if not already a string
- if ( s.data && s.processData && typeof s.data !== "string" ) {
- s.data = jQuery.param( s.data, s.traditional );
- }
-
- // Apply prefilters
- inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
-
- // If request was aborted inside a prefilter, stop there
- if ( state === 2 ) {
- return jqXHR;
- }
-
- // We can fire global events as of now if asked to
- fireGlobals = s.global;
-
- // Watch for a new set of requests
- if ( fireGlobals && jQuery.active++ === 0 ) {
- jQuery.event.trigger("ajaxStart");
- }
-
- // Uppercase the type
- s.type = s.type.toUpperCase();
-
- // Determine if request has content
- s.hasContent = !rnoContent.test( s.type );
-
- // Save the URL in case we're toying with the If-Modified-Since
- // and/or If-None-Match header later on
- cacheURL = s.url;
-
- // More options handling for requests with no content
- if ( !s.hasContent ) {
-
- // If data is available, append data to url
- if ( s.data ) {
- cacheURL = ( s.url += ( ajax_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_=" + ajax_nonce++ ) :
-
- // Otherwise add one to the end
- cacheURL + ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ajax_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;
-
- // Get response data
- if ( responses ) {
- response = ajaxHandleResponses( s, jqXHR, responses );
- }
-
- // If successful, handle type chaining
- if ( status >= 200 && status < 300 || status === 304 ) {
-
- // 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 ) {
- isSuccess = true;
- statusText = "nocontent";
-
- // if not modified
- } else if ( status === 304 ) {
- isSuccess = true;
- statusText = "notmodified";
-
- // If we have data, let's convert it
- } else {
- isSuccess = ajaxConvert( s, response );
- statusText = isSuccess.state;
- success = isSuccess.data;
- error = isSuccess.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;
- },
-
- getScript: function( url, callback ) {
- return jQuery.get( url, undefined, callback, "script" );
- },
-
- getJSON: function( url, data, callback ) {
- return jQuery.get( url, data, callback, "json" );
- }
- });
-
- /* Handles responses to an ajax request:
- * - sets all responseXXX fields accordingly
- * - 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,
- responseFields = s.responseFields;
-
- // Fill responseXXX fields
- for ( type in responseFields ) {
- if ( type in responses ) {
- jqXHR[ responseFields[type] ] = responses[ type ];
- }
- }
-
- // 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
- function ajaxConvert( s, response ) {
- var conv2, current, conv, tmp,
- converters = {},
- i = 0,
- // Work with a copy of dataTypes in case we need to modify it for conversion
- dataTypes = s.dataTypes.slice(),
- prev = dataTypes[ 0 ];
-
- // Apply the dataFilter if provided
- if ( s.dataFilter ) {
- response = s.dataFilter( response, s.dataType );
- }
-
- // Create converters map with lowercased keys
- if ( dataTypes[ 1 ] ) {
- for ( conv in s.converters ) {
- converters[ conv.toLowerCase() ] = s.converters[ conv ];
- }
- }
-
- // Convert to each sequential dataType, tolerating list modification
- for ( ; (current = dataTypes[++i]); ) {
-
- // There's only work to do if current dataType is non-auto
- if ( current !== "*" ) {
-
- // Convert response if prev dataType is non-auto and differs from current
- 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.splice( i--, 0, current );
- }
-
- 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 };
- }
- }
- }
- }
-
- // Update prev for next iteration
- prev = current;
- }
- }
-
- return { state: "success", data: response };
- }
-// 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 + "_" + ( ajax_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 += ( ajax_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";
- }
- });
- var xhrCallbacks, xhrSupported,
- xhrId = 0,
- // #5280: Internet Explorer will keep connections alive if we don't abort on unload
- xhrOnUnloadAbort = window.ActiveXObject && function() {
- // Abort all pending requests
- var key;
- for ( key in xhrCallbacks ) {
- xhrCallbacks[ key ]( 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 ) {}
- }
-
-// Create the request object
-// (This is still attached to ajaxSettings for backward compatibility)
- jQuery.ajaxSettings.xhr = window.ActiveXObject ?
- /* Microsoft failed to properly
- * implement the XMLHttpRequest in IE7 (can't request local files),
- * so we use the ActiveXObject when it is available
- * Additionally XMLHttpRequest can be disabled in IE7/IE8 so
- * we need a fallback.
- */
- function() {
- return !this.isLocal && createStandardXHR() || createActiveXHR();
- } :
- // For all other browsers, use the standard XMLHttpRequest object
- createStandardXHR;
-
-// Determine support properties
- xhrSupported = jQuery.ajaxSettings.xhr();
- jQuery.support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
- xhrSupported = jQuery.support.ajax = !!xhrSupported;
-
-// Create transport if the browser can provide an xhr
- if ( xhrSupported ) {
-
- jQuery.ajaxTransport(function( s ) {
- // Cross domain only allowed if supported through XMLHttpRequest
- if ( !s.crossDomain || jQuery.support.cors ) {
-
- var callback;
-
- return {
- send: function( headers, complete ) {
-
- // Get a new xhr
- var handle, i,
- xhr = s.xhr();
-
- // Open the socket
- // Passing null username, generates a login popup on Opera (#2865)
- if ( s.username ) {
- xhr.open( s.type, s.url, s.async, s.username, s.password );
- } else {
- xhr.open( s.type, s.url, s.async );
- }
-
- // Apply custom fields if provided
- if ( s.xhrFields ) {
- for ( i in s.xhrFields ) {
- xhr[ i ] = s.xhrFields[ i ];
- }
- }
-
- // Override mime type if needed
- if ( s.mimeType && xhr.overrideMimeType ) {
- xhr.overrideMimeType( s.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 ( !s.crossDomain && !headers["X-Requested-With"] ) {
- headers["X-Requested-With"] = "XMLHttpRequest";
- }
-
- // Need an extra try/catch for cross domain requests in Firefox 3
- try {
- for ( i in headers ) {
- xhr.setRequestHeader( i, headers[ i ] );
- }
- } catch( err ) {}
-
- // Do send the request
- // This may raise an exception which is actually
- // handled in jQuery.ajax (so no try/catch here)
- xhr.send( ( s.hasContent && s.data ) || null );
-
- // Listener
- callback = function( _, isAbort ) {
- var status, responseHeaders, statusText, responses;
-
- // Firefox throws exceptions when accessing properties
- // of an xhr when a network error occurred
- // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:...
- try {
-
- // Was never called and is aborted or complete
- if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
-
- // Only called once
- callback = undefined;
-
- // Do not keep as active anymore
- if ( handle ) {
- xhr.onreadystatechange = jQuery.noop;
- if ( xhrOnUnloadAbort ) {
- delete xhrCallbacks[ handle ];
- }
- }
-
- // If it's an abort
- if ( isAbort ) {
- // Abort it manually if needed
- if ( xhr.readyState !== 4 ) {
- xhr.abort();
- }
- } else {
- responses = {};
- status = xhr.status;
- responseHeaders = xhr.getAllResponseHeaders();
-
- // When requesting binary data, IE6-9 will throw an exception
- // on any attempt to access responseText (#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 && s.isLocal && !s.crossDomain ) {
- status = responses.text ? 200 : 404;
- // IE - #1450: sometimes returns 1223 when it should be 204
- } else if ( status === 1223 ) {
- status = 204;
- }
- }
- }
- } catch( firefoxAccessException ) {
- if ( !isAbort ) {
- complete( -1, firefoxAccessException );
- }
- }
-
- // Call complete if needed
- if ( responses ) {
- complete( status, statusText, responses, responseHeaders );
- }
- };
-
- if ( !s.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 {
- handle = ++xhrId;
- if ( xhrOnUnloadAbort ) {
- // Create the active xhrs callbacks list if needed
- // and attach the unload handler
- if ( !xhrCallbacks ) {
- xhrCallbacks = {};
- jQuery( window ).unload( xhrOnUnloadAbort );
- }
- // Add to list of active xhrs callbacks
- xhrCallbacks[ handle ] = callback;
- }
- xhr.onreadystatechange = callback;
- }
- },
-
- abort: function() {
- if ( callback ) {
- callback( undefined, true );
- }
- }
- };
- }
- });
- }
- var fxNow, timerId,
- rfxtypes = /^(?:toggle|show|hide)$/,
- rfxnum = new RegExp( "^(?:([+-])=|)(" + core_pnum + ")([a-z%]*)$", "i" ),
- rrun = /queueHooks$/,
- animationPrefilters = [ defaultPrefilter ],
- tweeners = {
- "*": [function( prop, value ) {
- var end, unit,
- tween = this.createTween( prop, value ),
- parts = rfxnum.exec( value ),
- target = tween.cur(),
- start = +target || 0,
- scale = 1,
- maxIterations = 20;
-
- if ( parts ) {
- end = +parts[2];
- unit = parts[3] || ( jQuery.cssNumber[ prop ] ? "" : "px" );
-
- // We need to compute starting value
- if ( unit !== "px" && start ) {
- // Iteratively approximate from a nonzero starting point
- // Prefer the current property, because this process will be trivial if it uses the same units
- // Fallback to end or a simple constant
- start = jQuery.css( tween.elem, prop, true ) || end || 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 );
- }
-
- tween.unit = unit;
- tween.start = start;
- // If a +=/-= token was provided, we're doing a relative animation
- tween.end = parts[1] ? start + ( parts[1] + 1 ) * end : end;
- }
- return tween;
- }]
- };
-
-// Animations created synchronously will run synchronously
- function createFxNow() {
- setTimeout(function() {
- fxNow = undefined;
- });
- return ( fxNow = jQuery.now() );
- }
-
- function createTweens( animation, props ) {
- jQuery.each( props, function( prop, value ) {
- var collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
- index = 0,
- length = collection.length;
- for ( ; index < length; index++ ) {
- if ( collection[ index ].call( animation, prop, value ) ) {
-
- // we're done with this property
- return;
- }
- }
- });
- }
-
- 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;
- }
- }
-
- createTweens( animation, props );
-
- 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 );
- }
-
- function propFilter( props, specialEasing ) {
- var value, name, index, easing, 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;
- }
- }
- }
-
- 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 );
- }
- }
- });
-
- function defaultPrefilter( elem, props, opts ) {
- /*jshint validthis:true */
- var prop, index, length,
- value, dataShow, toggle,
- tween, hooks, oldfire,
- anim = this,
- style = elem.style,
- orig = {},
- handled = [],
- hidden = elem.nodeType && isHidden( elem );
-
- // 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
- if ( jQuery.css( elem, "display" ) === "inline" &&
- jQuery.css( elem, "float" ) === "none" ) {
-
- // inline-level elements accept inline-block;
- // block-level elements need to be inline with layout
- if ( !jQuery.support.inlineBlockNeedsLayout || css_defaultDisplay( elem.nodeName ) === "inline" ) {
- style.display = "inline-block";
-
- } else {
- style.zoom = 1;
- }
- }
- }
-
- if ( opts.overflow ) {
- style.overflow = "hidden";
- if ( !jQuery.support.shrinkWrapBlocks ) {
- anim.always(function() {
- style.overflow = opts.overflow[ 0 ];
- style.overflowX = opts.overflow[ 1 ];
- style.overflowY = opts.overflow[ 2 ];
- });
- }
- }
-
-
- // show/hide pass
- for ( index in props ) {
- value = props[ index ];
- if ( rfxtypes.exec( value ) ) {
- delete props[ index ];
- toggle = toggle || value === "toggle";
- if ( value === ( hidden ? "hide" : "show" ) ) {
- continue;
- }
- handled.push( index );
- }
- }
-
- length = handled.length;
- if ( length ) {
- dataShow = jQuery._data( elem, "fxshow" ) || jQuery._data( elem, "fxshow", {} );
- if ( "hidden" in dataShow ) {
- hidden = dataShow.hidden;
- }
-
- // 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 ( index = 0 ; index < length ; index++ ) {
- prop = handled[ index ];
- tween = anim.createTween( prop, hidden ? dataShow[ prop ] : 0 );
- orig[ prop ] = dataShow[ prop ] || jQuery.style( elem, prop );
-
- if ( !( prop in dataShow ) ) {
- dataShow[ prop ] = tween.start;
- if ( hidden ) {
- tween.end = tween.start;
- tween.start = prop === "width" || prop === "height" ? 1 : 0;
- }
- }
- }
- }
- }
-
- 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;
- }
- }
- }
- };
-
-// Remove in 2.0 - this supports IE8's 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.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 );
- };
- });
-
- 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 );
- doAnimation.finish = function() {
- anim.stop( true );
- };
- // 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.cur && hooks.cur.finish ) {
- hooks.cur.finish.call( this );
- }
-
- // 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;
- });
- }
- });
-
-// 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;
- }
-
-// 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.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.easing = {
- linear: function( p ) {
- return p;
- },
- swing: function( p ) {
- return 0.5 - Math.cos( p*Math.PI ) / 2;
- }
- };
-
- jQuery.timers = [];
- jQuery.fx = Tween.prototype.init;
- 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 ) {
- if ( timer() && jQuery.timers.push( timer ) ) {
- jQuery.fx.start();
- }
- };
-
- 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
- };
-
-// Back Compat <1.8 extension point
- jQuery.fx.step = {};
-
- if ( jQuery.expr && jQuery.expr.filters ) {
- jQuery.expr.filters.animated = function( elem ) {
- return jQuery.grep(jQuery.timers, function( fn ) {
- return elem === fn.elem;
- }).length;
- };
- }
- jQuery.fn.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 !== core_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 )
- };
- };
-
- jQuery.offset = {
-
- setOffset: function( elem, options, i ) {
- var position = jQuery.css( elem, "position" );
-
- // set position first, in-case top/left are set even on static elem
- if ( position === "static" ) {
- elem.style.position = "relative";
- }
-
- var curElem = jQuery( elem ),
- curOffset = curElem.offset(),
- curCSSTop = jQuery.css( elem, "top" ),
- curCSSLeft = jQuery.css( elem, "left" ),
- calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1,
- props = {}, curPosition = {}, curTop, curLeft;
-
- // 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({
-
- 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 it's 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 || document.documentElement;
- while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) && jQuery.css( offsetParent, "position") === "static" ) ) {
- offsetParent = offsetParent.offsetParent;
- }
- return offsetParent || document.documentElement;
- });
- }
- });
-
-
-// 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 jQuery.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 );
- };
- });
-
- function getWindow( elem ) {
- return jQuery.isWindow( elem ) ?
- elem :
- elem.nodeType === 9 ?
- elem.defaultView || elem.parentWindow :
- false;
- }
-// 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 jQuery.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 );
- };
- });
- });
-// Limit scope pollution from any deprecated API
-// (function() {
-
-// })();
-// Expose jQuery to the global object
- window.jQuery = window.$ = jQuery;
-
-// Expose jQuery as an AMD module, but only for AMD loaders that
-// understand the issues with loading multiple versions of jQuery
-// in a page that all might call define(). The loader will indicate
-// they have special allowances for multiple jQuery versions by
-// specifying define.amd.jQuery = true. Register as a named module,
-// since jQuery can be concatenated with other files that may use define,
-// but not use 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.
- if ( typeof define === "function" && define.amd && define.amd.jQuery ) {
- define( "jquery", [], function () { return jQuery; } );
- }
-
-})( window );
\ No newline at end of file
diff --git a/modules/enterprise/gui/coregui/src/main/webapp/js/jquery-1.9.1.min.js b/modules/enterprise/gui/coregui/src/main/webapp/js/jquery-1.9.1.min.js
deleted file mode 100644
index 5d9ee08..0000000
--- a/modules/enterprise/gui/coregui/src/main/webapp/js/jquery-1.9.1.min.js
+++ /dev/null
@@ -1,5 +0,0 @@
-/*! jQuery v1.9.1 | (c) 2005, 2012 jQuery Foundation, Inc. | jquery.org/license
- //@ sourceMappingURL=jquery.min.map
- */(function(e,t){var n,r,i=typeof t,o=e.document,a=e.location,s=e.jQuery,u=e.$,l={},c=[],p="1.9.1",f=c.concat,d=c.push,h=c.slice,g=c.indexOf,m=l.toString,y=l.hasOwnProperty,v=p.trim,b=function(e,t){return new b.fn.init(e,t,r)},x=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,w=/\S+/g,T=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,N=/^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,k=/^[\],:{}\s]*$/,E=/(?:^|:|,)(?:\s*\[)+/g,S=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,A=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,j=/^-ms-/,D=/-([\da-z])/gi,L=function(e,t){return t.toUpperCase()},H=function(e){(o.addEventListener||"load"===e.type||"complete"===o.readyState)&&(q(),b.ready())},q=function(){o.addEventListener?(o.removeEventListener("DOMContentLoaded",H,!1),e.removeEventListener("load",H,!1)):(o.detachEvent("onreadystatechange",H),e.detachEvent("onload",H))};b.fn=b.prototype={jquery:p,constructor:b,init:function(e,n,r){var i,a;if(!e)return this;if("string"==
typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:N.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof b?n[0]:n,b.merge(this,b.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:o,!0)),C.test(i[1])&&b.isPlainObject(n))for(i in n)b.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(a=o.getElementById(i[2]),a&&a.parentNode){if(a.id!==i[2])return r.find(e);this.length=1,this[0]=a}return this.context=o,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):b.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),b.makeArray(e,this))},selector:"",length:0,size:function(){return this.length},toArray:function(){return h.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=b.merge(this.constructor(),e);return t.prevObject=this,t.context=this.cont
ext,t},each:function(e,t){return b.each(this,e,t)},ready:function(e){return b.ready.promise().done(e),this},slice:function(){return this.pushStack(h.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(b.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:d,sort:[].sort,splice:[].splice},b.fn.init.prototype=b.fn,b.extend=b.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},u=1,l=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},u=2),"object"==typeof s||b.isFunction(s)||(s={}),l===u&&(s=this,--u);l>u;u++)if(null!=(o=arguments[u]))for(i in o)e=s[i],r=o[i],s!==r&&(c&&r&&(b.isPlainObject(r)||(n=b.isArray(r)))?(n?(n=!1,a=e&&b.isArray(e)?e:[]):a=e&&b.isPlainObject(e)?e:{},s[i]=b.extend(c,a,r)):r!==t&&(s[i]=r));return s}
,b.extend({noConflict:function(t){return e.$===b&&(e.$=u),t&&e.jQuery===b&&(e.jQuery=s),b},isReady:!1,readyWait:1,holdReady:function(e){e?b.readyWait++:b.ready(!0)},ready:function(e){if(e===!0?!--b.readyWait:!b.isReady){if(!o.body)return setTimeout(b.ready);b.isReady=!0,e!==!0&&--b.readyWait>0||(n.resolveWith(o,[b]),b.fn.trigger&&b(o).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===b.type(e)},isArray:Array.isArray||function(e){return"array"===b.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[m.call(e)]||"object":typeof e},isPlainObject:function(e){if(!e||"object"!==b.type(e)||e.nodeType||b.isWindow(e))return!1;try{if(e.constructor&&!y.call(e,"constructor")&&!y.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||y.call(e,r)},isEmptyObject:functi
on(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||o;var r=C.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=b.buildFragment([e],t,i),i&&b(i).remove(),b.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=b.trim(n),n&&k.test(n.replace(S,"@").replace(A,"]").replace(E,"")))?Function("return "+n)():(b.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||b.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&b.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){ret
urn e.replace(j,"ms-").replace(D,L)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,a=M(e);if(n){if(a){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(a){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:v&&!v.call("\ufeff\u00a0")?function(e){return null==e?"":v.call(e)}:function(e){return null==e?"":(e+"").replace(T,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(M(Object(e))?b.merge(n,"string"==typeof e?[e]:e):d.call(n,e)),n},inArray:function(e,t,n){var r;if(t){if(g)return g.call(t,e,n);for(r=t.length,n=n?0>n?Math.max(0,r+n):n:0;r>n;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,o=0;if("number"==typeof r)for(;r>o;o++)e[i++]=n[o];else while(n[o]!==t)e[i++]=n[o++];return e.length=i,e},grep:function(e,t,n){var r,i=[],o=0
,a=e.length;for(n=!!n;a>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,a=M(e),s=[];if(a)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(s[s.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(s[s.length]=r);return f.apply([],s)},guid:1,proxy:function(e,n){var r,i,o;return"string"==typeof n&&(o=e[n],n=e,e=o),b.isFunction(e)?(r=h.call(arguments,2),i=function(){return e.apply(n||this,r.concat(h.call(arguments)))},i.guid=e.guid=e.guid||b.guid++,i):t},access:function(e,n,r,i,o,a,s){var u=0,l=e.length,c=null==r;if("object"===b.type(r)){o=!0;for(u in r)b.access(e,n,u,r[u],!0,a,s)}else if(i!==t&&(o=!0,b.isFunction(i)||(s=!0),c&&(s?(n.call(e,i),n=null):(c=n,n=function(e,t,n){return c.call(b(e),n)})),n))for(;l>u;u++)n(e[u],r,s?i:i.call(e[u],u,n(e[u],r)));return o?e:c?n.call(e):l?n(e[0],r):a},now:function(){return(new Date).getTime()}}),b.ready.promise=function(t){if(!n)if(n=b.Deferred(),"complete"===o.readyState)setTimeout(b.ready);else if(o.addEventLis
tener)o.addEventListener("DOMContentLoaded",H,!1),e.addEventListener("load",H,!1);else{o.attachEvent("onreadystatechange",H),e.attachEvent("onload",H);var r=!1;try{r=null==e.frameElement&&o.documentElement}catch(i){}r&&r.doScroll&&function a(){if(!b.isReady){try{r.doScroll("left")}catch(e){return setTimeout(a,50)}q(),b.ready()}}()}return n.promise(t)},b.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){l["[object "+t+"]"]=t.toLowerCase()});function M(e){var t=e.length,n=b.type(e);return b.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}r=b(o);var _={};function F(e){var t=_[e]={};return b.each(e.match(w)||[],function(e,n){t[n]=!0}),t}b.Callbacks=function(e){e="string"==typeof e?_[e]||F(e):b.extend({},e);var n,r,i,o,a,s,u=[],l=!e.once&&[],c=function(t){for(r=e.memory&&t,i=!0,a=s||0,s=0,o=u.length,n=!0;u&&o>a;a++)if(u[a].apply(t[0],t[1])===!1&&e.stopOnFalse){r=!1;break}n=!1,u
&&(l?l.length&&c(l.shift()):r?u=[]:p.disable())},p={add:function(){if(u){var t=u.length;(function i(t){b.each(t,function(t,n){var r=b.type(n);"function"===r?e.unique&&p.has(n)||u.push(n):n&&n.length&&"string"!==r&&i(n)})})(arguments),n?o=u.length:r&&(s=t,c(r))}return this},remove:function(){return u&&b.each(arguments,function(e,t){var r;while((r=b.inArray(t,u,r))>-1)u.splice(r,1),n&&(o>=r&&o--,a>=r&&a--)}),this},has:function(e){return e?b.inArray(e,u)>-1:!(!u||!u.length)},empty:function(){return u=[],this},disable:function(){return u=l=r=t,this},disabled:function(){return!u},lock:function(){return l=t,r||p.disable(),this},locked:function(){return!l},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],!u||i&&!l||(n?l.push(t):c(t)),this},fire:function(){return p.fireWith(this,arguments),this},fired:function(){return!!i}};return p},b.extend({Deferred:function(e){var t=[["resolve","done",b.Callbacks("once memory"),"resolved"],["reject","fail",b.Callbacks("once memory
"),"rejected"],["notify","progress",b.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return b.Deferred(function(n){b.each(t,function(t,o){var a=o[0],s=b.isFunction(e[t])&&e[t];i[o[1]](function(){var e=s&&s.apply(this,arguments);e&&b.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[a+"With"](this===r?n.promise():this,s?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?b.extend(e,r):r}},i={};return r.pipe=r.then,b.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=h.call(arguments),r=n.length,i=1!==r||e&&b.isFunction(e.promise)?r:0,o=1===i?e:b.Deferred(),a=function(e,t,n){return function(r)
{t[e]=this,n[e]=arguments.length>1?h.call(arguments):r,n===s?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},s,u,l;if(r>1)for(s=Array(r),u=Array(r),l=Array(r);r>t;t++)n[t]&&b.isFunction(n[t].promise)?n[t].promise().done(a(t,l,n)).fail(o.reject).progress(a(t,u,s)):--i;return i||o.resolveWith(l,n),o.promise()}}),b.support=function(){var t,n,r,a,s,u,l,c,p,f,d=o.createElement("div");if(d.setAttribute("className","t"),d.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",n=d.getElementsByTagName("*"),r=d.getElementsByTagName("a")[0],!n||!r||!n.length)return{};s=o.createElement("select"),l=s.appendChild(o.createElement("option")),a=d.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t={getSetAttribute:"t"!==d.className,leadingWhitespace:3===d.firstChild.nodeType,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/top/.test(r.getAttribute("style")),hrefNormalized:"/a"===r.ge
tAttribute("href"),opacity:/^0.5/.test(r.style.opacity),cssFloat:!!r.style.cssFloat,checkOn:!!a.value,optSelected:l.selected,enctype:!!o.createElement("form").enctype,html5Clone:"<:nav></:nav>"!==o.createElement("nav").cloneNode(!0).outerHTML,boxModel:"CSS1Compat"===o.compatMode,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},a.checked=!0,t.noCloneChecked=a.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!l.disabled;try{delete d.test}catch(h){t.deleteExpando=!1}a=o.createElement("input"),a.setAttribute("value",""),t.input=""===a.getAttribute("value"),a.value="t",a.setAttribute("type","radio"),t.radioValue="t"===a.value,a.setAttribute("checked","t"),a.setAttribute("name","t"),u=o.createDocumentFragment(),u.appendChild(a),t.appendChecked=a.checked,t.checkClone=u.cloneNode(!0).cloneNode(!0).lastChild.checked,d.attachEvent&&(d.attachEvent("onclick",function(){t.noCloneEvent=!1}),d.clon
eNode(!0).click());for(f in{submit:!0,change:!0,focusin:!0})d.setAttribute(c="on"+f,"t"),t[f+"Bubbles"]=c in e||d.attributes[c].expando===!1;return d.style.backgroundClip="content-box",d.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===d.style.backgroundClip,b(function(){var n,r,a,s="padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",u=o.getElementsByTagName("body")[0];u&&(n=o.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",u.appendChild(n).appendChild(d),d.innerHTML="<table><tr><td></td><td>t</td></tr></table>",a=d.getElementsByTagName("td"),a[0].style.cssText="padding:0;margin:0;border:0;display:none",p=0===a[0].offsetHeight,a[0].style.display="",a[1].style.display="none",t.reliableHiddenOffsets=p&&0===a[0].offsetHeight,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-b
ox-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",t.boxSizing=4===d.offsetWidth,t.doesNotIncludeMarginInBodyOffset=1!==u.offsetTop,e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(d,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(d,null)||{width:"4px"}).width,r=d.appendChild(o.createElement("div")),r.style.cssText=d.style.cssText=s,r.style.marginRight=r.style.width="0",d.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),typeof d.style.zoom!==i&&(d.innerHTML="",d.style.cssText=s+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=3===d.offsetWidth,d.style.display="block",d.innerHTML="<div></div>",d.firstChild.style.width="5px",t.shrinkWrapBlocks=3!==d.offsetWidth,t.inlineBlockNeedsLayout&&(u.style.zoom=1)),u.removeChild(n),n=d=a=r=null)}),n=s=u=l=r=a=null,t}();var O=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,B=/([A-Z])/g;function P(e
,n,r,i){if(b.acceptData(e)){var o,a,s=b.expando,u="string"==typeof n,l=e.nodeType,p=l?b.cache:e,f=l?e[s]:e[s]&&s;if(f&&p[f]&&(i||p[f].data)||!u||r!==t)return f||(l?e[s]=f=c.pop()||b.guid++:f=s),p[f]||(p[f]={},l||(p[f].toJSON=b.noop)),("object"==typeof n||"function"==typeof n)&&(i?p[f]=b.extend(p[f],n):p[f].data=b.extend(p[f].data,n)),o=p[f],i||(o.data||(o.data={}),o=o.data),r!==t&&(o[b.camelCase(n)]=r),u?(a=o[n],null==a&&(a=o[b.camelCase(n)])):a=o,a}}function R(e,t,n){if(b.acceptData(e)){var r,i,o,a=e.nodeType,s=a?b.cache:e,u=a?e[b.expando]:b.expando;if(s[u]){if(t&&(o=n?s[u]:s[u].data)){b.isArray(t)?t=t.concat(b.map(t,b.camelCase)):t in o?t=[t]:(t=b.camelCase(t),t=t in o?[t]:t.split(" "));for(r=0,i=t.length;i>r;r++)delete o[t[r]];if(!(n?$:b.isEmptyObject)(o))return}(n||(delete s[u].data,$(s[u])))&&(a?b.cleanData([e],!0):b.support.deleteExpando||s!=s.window?delete s[u]:s[u]=null)}}}b.extend({cache:{},expando:"jQuery"+(p+Math.random()).replace(/\D/g,""),noData:{embed:!0,object
:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?b.cache[e[b.expando]]:e[b.expando],!!e&&!$(e)},data:function(e,t,n){return P(e,t,n)},removeData:function(e,t){return R(e,t)},_data:function(e,t,n){return P(e,t,n,!0)},_removeData:function(e,t){return R(e,t,!0)},acceptData:function(e){if(e.nodeType&&1!==e.nodeType&&9!==e.nodeType)return!1;var t=e.nodeName&&b.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),b.fn.extend({data:function(e,n){var r,i,o=this[0],a=0,s=null;if(e===t){if(this.length&&(s=b.data(o),1===o.nodeType&&!b._data(o,"parsedAttrs"))){for(r=o.attributes;r.length>a;a++)i=r[a].name,i.indexOf("data-")||(i=b.camelCase(i.slice(5)),W(o,i,s[i]));b._data(o,"parsedAttrs",!0)}return s}return"object"==typeof e?this.each(function(){b.data(this,e)}):b.access(this,function(n){return n===t?o?W(o,e,b.data(o,e)):null:(this.each(function(){b.data(this,e,n)}),t)},null,n,arguments.length>1,null,!0)},rem
oveData:function(e){return this.each(function(){b.removeData(this,e)})}});function W(e,n,r){if(r===t&&1===e.nodeType){var i="data-"+n.replace(B,"-$1").toLowerCase();if(r=e.getAttribute(i),"string"==typeof r){try{r="true"===r?!0:"false"===r?!1:"null"===r?null:+r+""===r?+r:O.test(r)?b.parseJSON(r):r}catch(o){}b.data(e,n,r)}else r=t}return r}function $(e){var t;for(t in e)if(("data"!==t||!b.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}b.extend({queue:function(e,n,r){var i;return e?(n=(n||"fx")+"queue",i=b._data(e,n),r&&(!i||b.isArray(r)?i=b._data(e,n,b.makeArray(r)):i.push(r)),i||[]):t},dequeue:function(e,t){t=t||"fx";var n=b.queue(e,t),r=n.length,i=n.shift(),o=b._queueHooks(e,t),a=function(){b.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),o.cur=i,i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return b._data(e,n)||b._data(e,n,{empty:b.Callbacks("once memory").add(function(){b._
removeData(e,t+"queue"),b._removeData(e,n)})})}}),b.fn.extend({queue:function(e,n){var r=2;return"string"!=typeof e&&(n=e,e="fx",r--),r>arguments.length?b.queue(this[0],e):n===t?this:this.each(function(){var t=b.queue(this,e,n);b._queueHooks(this,e),"fx"===e&&"inprogress"!==t[0]&&b.dequeue(this,e)})},dequeue:function(e){return this.each(function(){b.dequeue(this,e)})},delay:function(e,t){return e=b.fx?b.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,o=b.Deferred(),a=this,s=this.length,u=function(){--i||o.resolveWith(a,[a])};"string"!=typeof e&&(n=e,e=t),e=e||"fx";while(s--)r=b._data(a[s],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(u));return u(),o.promise(n)}});var I,z,X=/[\t\r\n]/g,U=/\r/g,V=/^(?:input|select|textarea|button|object)$/i,Y=/^(?:a|area)$/i,J=/^(?:checked|selected|autofocus|autoplay|async|controls|defer|disab
led|hidden|loop|multiple|open|readonly|required|scoped)$/i,G=/^(?:checked|selected)$/i,Q=b.support.getSetAttribute,K=b.support.input;b.fn.extend({attr:function(e,t){return b.access(this,b.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){b.removeAttr(this,e)})},prop:function(e,t){return b.access(this,b.prop,e,t,arguments.length>1)},removeProp:function(e){return e=b.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,o,a=0,s=this.length,u="string"==typeof e&&e;if(b.isFunction(e))return this.each(function(t){b(this).addClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(X," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=b.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,a=0,s=this.length,u=0===arguments.length||"string"==typeof e&&e;if(b.isFunction(e))
return this.each(function(t){b(this).removeClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(X," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?b.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e,r="boolean"==typeof t;return b.isFunction(e)?this.each(function(n){b(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var o,a=0,s=b(this),u=t,l=e.match(w)||[];while(o=l[a++])u=r?u:!s.hasClass(o),s[u?"addClass":"removeClass"](o)}else(n===i||"boolean"===n)&&(this.className&&b._data(this,"__className__",this.className),this.className=this.className||e===!1?"":b._data(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(X," ").indexOf(t)>=0)return!0;return!1},val:function(e
){var n,r,i,o=this[0];{if(arguments.length)return i=b.isFunction(e),this.each(function(n){var o,a=b(this);1===this.nodeType&&(o=i?e.call(this,n,a.val()):e,null==o?o="":"number"==typeof o?o+="":b.isArray(o)&&(o=b.map(o,function(e){return null==e?"":e+""})),r=b.valHooks[this.type]||b.valHooks[this.nodeName.toLowerCase()],r&&"set"in r&&r.set(this,o,"value")!==t||(this.value=o))});if(o)return r=b.valHooks[o.type]||b.valHooks[o.nodeName.toLowerCase()],r&&"get"in r&&(n=r.get(o,"value"))!==t?n:(n=o.value,"string"==typeof n?n.replace(U,""):null==n?"":n)}}}),b.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,a=o?null:[],s=o?i+1:r.length,u=0>i?s:o?i:0;for(;s>u;u++)if(n=r[u],!(!n.selected&&u!==i||(b.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&b.nodeName(n.parentNode,"optgroup"))){if(t=b(n).val()
,o)return t;a.push(t)}return a},set:function(e,t){var n=b.makeArray(t);return b(e).find("option").each(function(){this.selected=b.inArray(b(this).val(),n)>=0}),n.length||(e.selectedIndex=-1),n}}},attr:function(e,n,r){var o,a,s,u=e.nodeType;if(e&&3!==u&&8!==u&&2!==u)return typeof e.getAttribute===i?b.prop(e,n,r):(a=1!==u||!b.isXMLDoc(e),a&&(n=n.toLowerCase(),o=b.attrHooks[n]||(J.test(n)?z:I)),r===t?o&&a&&"get"in o&&null!==(s=o.get(e,n))?s:(typeof e.getAttribute!==i&&(s=e.getAttribute(n)),null==s?t:s):null!==r?o&&a&&"set"in o&&(s=o.set(e,r,n))!==t?s:(e.setAttribute(n,r+""),r):(b.removeAttr(e,n),t))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(w);if(o&&1===e.nodeType)while(n=o[i++])r=b.propFix[n]||n,J.test(n)?!Q&&G.test(n)?e[b.camelCase("default-"+n)]=e[r]=!1:e[r]=!1:b.attr(e,n,""),e.removeAttribute(Q?n:r)},attrHooks:{type:{set:function(e,t){if(!b.support.radioValue&&"radio"===t&&b.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},pro
pFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(e,n,r){var i,o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return a=1!==s||!b.isXMLDoc(e),a&&(n=b.propFix[n]||n,o=b.propHooks[n]),r!==t?o&&"set"in o&&(i=o.set(e,r,n))!==t?i:e[n]=r:o&&"get"in o&&null!==(i=o.get(e,n))?i:e[n]},propHooks:{tabIndex:{get:function(e){var n=e.getAttributeNode("tabindex");return n&&n.specified?parseInt(n.value,10):V.test(e.nodeName)||Y.test(e.nodeName)&&e.href?0:t}}}}),z={get:function(e,n){var r=b.prop(e,n),i="boolean"==typeof r&&e.getAttribute(n),o="boolean"==typeof r?K&&Q?null!=i:G.test(n)?e[b.camelCase("default-"+n)]:!!i:e.getAttributeNode(n);return o&&o.value!==!1?n.toLowerCase():t},set:function(e,t,n){return t===!1?b.removeAttr(e,n):K&&Q||!G.test(n)?e.setAttribute(!Q&&b.
propFix[n]||n,n):e[b.camelCase("default-"+n)]=e[n]=!0,n}},K&&Q||(b.attrHooks.value={get:function(e,n){var r=e.getAttributeNode(n);return b.nodeName(e,"input")?e.defaultValue:r&&r.specified?r.value:t},set:function(e,n,r){return b.nodeName(e,"input")?(e.defaultValue=n,t):I&&I.set(e,n,r)}}),Q||(I=b.valHooks.button={get:function(e,n){var r=e.getAttributeNode(n);return r&&("id"===n||"name"===n||"coords"===n?""!==r.value:r.specified)?r.value:t},set:function(e,n,r){var i=e.getAttributeNode(r);return i||e.setAttributeNode(i=e.ownerDocument.createAttribute(r)),i.value=n+="","value"===r||n===e.getAttribute(r)?n:t}},b.attrHooks.contenteditable={get:I.get,set:function(e,t,n){I.set(e,""===t?!1:t,n)}},b.each(["width","height"],function(e,n){b.attrHooks[n]=b.extend(b.attrHooks[n],{set:function(e,r){return""===r?(e.setAttribute(n,"auto"),r):t}})})),b.support.hrefNormalized||(b.each(["href","src","width","height"],function(e,n){b.attrHooks[n]=b.extend(b.attrHooks[n],{get:function(e){var r=e.
getAttribute(n,2);return null==r?t:r}})}),b.each(["href","src"],function(e,t){b.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}})),b.support.style||(b.attrHooks.style={get:function(e){return e.style.cssText||t},set:function(e,t){return e.style.cssText=t+""}}),b.support.optSelected||(b.propHooks.selected=b.extend(b.propHooks.selected,{get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}})),b.support.enctype||(b.propFix.enctype="encoding"),b.support.checkOn||b.each(["radio","checkbox"],function(){b.valHooks[this]={get:function(e){return null===e.getAttribute("value")?"on":e.value}}}),b.each(["radio","checkbox"],function(){b.valHooks[this]=b.extend(b.valHooks[this],{set:function(e,n){return b.isArray(n)?e.checked=b.inArray(b(e).val(),n)>=0:t}})});var Z=/^(?:input|select|textarea)$/i,et=/^key/,tt=/^(?:mouse|contextmenu)|click/,nt=/^(?:focusinfocus|focusoutblur)$/,rt=/^([^.]*)(?:\.(.+)|)$/;function it(){return!0}
function ot(){return!1}b.event={global:{},add:function(e,n,r,o,a){var s,u,l,c,p,f,d,h,g,m,y,v=b._data(e);if(v){r.handler&&(c=r,r=c.handler,a=c.selector),r.guid||(r.guid=b.guid++),(u=v.events)||(u=v.events={}),(f=v.handle)||(f=v.handle=function(e){return typeof b===i||e&&b.event.triggered===e.type?t:b.event.dispatch.apply(f.elem,arguments)},f.elem=e),n=(n||"").match(w)||[""],l=n.length;while(l--)s=rt.exec(n[l])||[],g=y=s[1],m=(s[2]||"").split(".").sort(),p=b.event.special[g]||{},g=(a?p.delegateType:p.bindType)||g,p=b.event.special[g]||{},d=b.extend({type:g,origType:y,data:o,handler:r,guid:r.guid,selector:a,needsContext:a&&b.expr.match.needsContext.test(a),namespace:m.join(".")},c),(h=u[g])||(h=u[g]=[],h.delegateCount=0,p.setup&&p.setup.call(e,o,m,f)!==!1||(e.addEventListener?e.addEventListener(g,f,!1):e.attachEvent&&e.attachEvent("on"+g,f))),p.add&&(p.add.call(e,d),d.handler.guid||(d.handler.guid=r.guid)),a?h.splice(h.delegateCount++,0,d):h.push(d),b.event.global[g]=!0;e=null
}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,p,f,d,h,g,m=b.hasData(e)&&b._data(e);if(m&&(c=m.events)){t=(t||"").match(w)||[""],l=t.length;while(l--)if(s=rt.exec(t[l])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){p=b.event.special[d]||{},d=(r?p.delegateType:p.bindType)||d,f=c[d]||[],s=s[2]&&RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),u=o=f.length;while(o--)a=f[o],!i&&g!==a.origType||n&&n.guid!==a.guid||s&&!s.test(a.namespace)||r&&r!==a.selector&&("**"!==r||!a.selector)||(f.splice(o,1),a.selector&&f.delegateCount--,p.remove&&p.remove.call(e,a));u&&!f.length&&(p.teardown&&p.teardown.call(e,h,m.handle)!==!1||b.removeEvent(e,d,m.handle),delete c[d])}else for(d in c)b.event.remove(e,d+t[l],n,r,!0);b.isEmptyObject(c)&&(delete m.handle,b._removeData(e,"events"))}},trigger:function(n,r,i,a){var s,u,l,c,p,f,d,h=[i||o],g=y.call(n,"type")?n.type:n,m=y.call(n,"namespace")?n.namespace.split("."):[];if(l=f=i=i||o,3!==i.nodeType&&8!==i.nodeType&&!nt.test(g+b.event.triggered)&&(g.
indexOf(".")>=0&&(m=g.split("."),g=m.shift(),m.sort()),u=0>g.indexOf(":")&&"on"+g,n=n[b.expando]?n:new b.Event(g,"object"==typeof n&&n),n.isTrigger=!0,n.namespace=m.join("."),n.namespace_re=n.namespace?RegExp("(^|\\.)"+m.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,n.result=t,n.target||(n.target=i),r=null==r?[n]:b.makeArray(r,[n]),p=b.event.special[g]||{},a||!p.trigger||p.trigger.apply(i,r)!==!1)){if(!a&&!p.noBubble&&!b.isWindow(i)){for(c=p.delegateType||g,nt.test(c+g)||(l=l.parentNode);l;l=l.parentNode)h.push(l),f=l;f===(i.ownerDocument||o)&&h.push(f.defaultView||f.parentWindow||e)}d=0;while((l=h[d++])&&!n.isPropagationStopped())n.type=d>1?c:p.bindType||g,s=(b._data(l,"events")||{})[n.type]&&b._data(l,"handle"),s&&s.apply(l,r),s=u&&l[u],s&&b.acceptData(l)&&s.apply&&s.apply(l,r)===!1&&n.preventDefault();if(n.type=g,!(a||n.isDefaultPrevented()||p._default&&p._default.apply(i.ownerDocument,r)!==!1||"click"===g&&b.nodeName(i,"a")||!b.acceptData(i)||!u||!i[g]||b.isWindow(i))){f=i[u],f&
&(i[u]=null),b.event.triggered=g;try{i[g]()}catch(v){}b.event.triggered=t,f&&(i[u]=f)}return n.result}},dispatch:function(e){e=b.event.fix(e);var n,r,i,o,a,s=[],u=h.call(arguments),l=(b._data(this,"events")||{})[e.type]||[],c=b.event.special[e.type]||{};if(u[0]=e,e.delegateTarget=this,!c.preDispatch||c.preDispatch.call(this,e)!==!1){s=b.event.handlers.call(this,e,l),n=0;while((o=s[n++])&&!e.isPropagationStopped()){e.currentTarget=o.elem,a=0;while((i=o.handlers[a++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(i.namespace))&&(e.handleObj=i,e.data=i.data,r=((b.event.special[i.origType]||{}).handle||i.handler).apply(o.elem,u),r!==t&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,e),e.result}},handlers:function(e,n){var r,i,o,a,s=[],u=n.delegateCount,l=e.target;if(u&&l.nodeType&&(!e.button||"click"!==e.type))for(;l!=this;l=l.parentNode||this)if(1===l.nodeType&&(l.disabled!==!0||"click"!==
e.type)){for(o=[],a=0;u>a;a++)i=n[a],r=i.selector+" ",o[r]===t&&(o[r]=i.needsContext?b(r,this).index(l)>=0:b.find(r,this,null,[l]).length),o[r]&&o.push(i);o.length&&s.push({elem:l,handlers:o})}return n.length>u&&s.push({elem:this,handlers:n.slice(u)}),s},fix:function(e){if(e[b.expando])return e;var t,n,r,i=e.type,a=e,s=this.fixHooks[i];s||(this.fixHooks[i]=s=tt.test(i)?this.mouseHooks:et.test(i)?this.keyHooks:{}),r=s.props?this.props.concat(s.props):this.props,e=new b.Event(a),t=r.length;while(t--)n=r[t],e[n]=a[n];return e.target||(e.target=a.srcElement||o),3===e.target.nodeType&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,a):e},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(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"butto
n buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,i,a,s=n.button,u=n.fromElement;return null==e.pageX&&null!=n.clientX&&(i=e.target.ownerDocument||o,a=i.documentElement,r=i.body,e.pageX=n.clientX+(a&&a.scrollLeft||r&&r.scrollLeft||0)-(a&&a.clientLeft||r&&r.clientLeft||0),e.pageY=n.clientY+(a&&a.scrollTop||r&&r.scrollTop||0)-(a&&a.clientTop||r&&r.clientTop||0)),!e.relatedTarget&&u&&(e.relatedTarget=u===e.target?n.toElement:u),e.which||s===t||(e.which=1&s?1:2&s?3:4&s?2:0),e}},special:{load:{noBubble:!0},click:{trigger:function(){return b.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):t}},focus:{trigger:function(){if(this!==o.activeElement&&this.focus)try{return this.focus(),!1}catch(e){}},delegateType:"focusin"},blur:{trigger:function(){return this===o.activeElement&&this.blur?(this.blur(),!1):t},delegateType:"focusout"},beforeunload:{postDispatch:function(e){e.result
!==t&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=b.extend(new b.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?b.event.trigger(i,null,t):b.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},b.removeEvent=o.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]===i&&(e[r]=null),e.detachEvent(r,n))},b.Event=function(e,n){return this instanceof b.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?it:ot):this.type=e,n&&b.extend(this,n),this.timeStamp=e&&e.timeStamp||b.now(),this[b.expando]=!0,t):new b.Event(e,n)},b.Event.prototype={isDefaultPrevented:ot,isPropagationStopped:ot,isImmediatePropagationStopped:ot,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=it,e&&(e.preventDefault?e.preventDefault(
):e.returnValue=!1)},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=it,e&&(e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=it,this.stopPropagation()}},b.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){b.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;
- return(!i||i!==r&&!b.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),b.support.submitBubbles||(b.event.special.submit={setup:function(){return b.nodeName(this,"form")?!1:(b.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=b.nodeName(n,"input")||b.nodeName(n,"button")?n.form:t;r&&!b._data(r,"submitBubbles")&&(b.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),b._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&b.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return b.nodeName(this,"form")?!1:(b.event.remove(this,"._submit"),t)}}),b.support.changeBubbles||(b.event.special.change={setup:function(){return Z.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(b.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)})
,b.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),b.event.simulate("change",this,e,!0)})),!1):(b.event.add(this,"beforeactivate._change",function(e){var t=e.target;Z.test(t.nodeName)&&!b._data(t,"changeBubbles")&&(b.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||b.event.simulate("change",this.parentNode,e,!0)}),b._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return b.event.remove(this,"._change"),!Z.test(this.nodeName)}}),b.support.focusinBubbles||b.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){b.event.simulate(t,e.target,b.event.fix(e),!0)};b.event.special[t]={setup:function(){0===n++&&o.addEventListener(e,r,!0)},teardown:function(){0===--n&&o.removeEventListener(e,r,!0)}}}),b.fn.exten
d({on:function(e,n,r,i,o){var a,s;if("object"==typeof e){"string"!=typeof n&&(r=r||n,n=t);for(a in e)this.on(a,n,r,e[a],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=ot;else if(!i)return this;return 1===o&&(s=i,i=function(e){return b().off(e),s.apply(this,arguments)},i.guid=s.guid||(s.guid=b.guid++)),this.each(function(){b.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,b(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=ot),this.each(function(){b.event.remove(this,e,r,n)})},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate
:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},trigger:function(e,t){return this.each(function(){b.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?b.event.trigger(e,n,r,!0):t}}),function(e,t){var n,r,i,o,a,s,u,l,c,p,f,d,h,g,m,y,v,x="sizzle"+-new Date,w=e.document,T={},N=0,C=0,k=it(),E=it(),S=it(),A=typeof t,j=1<<31,D=[],L=D.pop,H=D.push,q=D.slice,M=D.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},_="[\\x20\\t\\r\\n\\f]",F="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=F.replace("w","w#"),B="([*^$|!~]?=)",P="\\["+_+"*("+F+")"+_+"*(?:"+B+_+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+O+")|)|)"+_+"*\\]",R=":("+F+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+P.replace(3,8)+")*)|.*)\\)|)",W=RegExp("^"+_+"+|((?:^|[^\\\\])(?:\\\\.)*)"+_+"+$","g"),$=RegExp("^"+_+"*,"+_+"*"),I=RegExp("^"+_+"*([\\x20\\t\\r\\n\\f>+~])"+_+"*"),z=RegExp(R),X=RegExp("^"+O+"$"),U={ID:RegExp
("^#("+F+")"),CLASS:RegExp("^\\.("+F+")"),NAME:RegExp("^\\[name=['\"]?("+F+")['\"]?\\]"),TAG:RegExp("^("+F.replace("w","w*")+")"),ATTR:RegExp("^"+P),PSEUDO:RegExp("^"+R),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+_+"*(even|odd|(([+-]|)(\\d*)n|)"+_+"*(?:([+-]|)"+_+"*(\\d+)|))"+_+"*\\)|)","i"),needsContext:RegExp("^"+_+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+_+"*((?:-\\d)?\\d*)"+_+"*\\)|)(?=[^-]|$)","i")},V=/[\x20\t\r\n\f]*[+~]/,Y=/^[^{]+\{\s*\[native code/,J=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,G=/^(?:input|select|textarea|button)$/i,Q=/^h\d$/i,K=/'|\\/g,Z=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,et=/\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g,tt=function(e,t){var n="0x"+t-65536;return n!==n?t:0>n?String.fromCharCode(n+65536):String.fromCharCode(55296|n>>10,56320|1023&n)};try{q.call(w.documentElement.childNodes,0)[0].nodeType}catch(nt){q=function(e){var t,n=[];while(t=this[e++])n.push(t);return n}}function rt(e){return Y.test(e+"")}functi
on it(){var e,t=[];return e=function(n,r){return t.push(n+=" ")>i.cacheLength&&delete e[t.shift()],e[n]=r}}function ot(e){return e[x]=!0,e}function at(e){var t=p.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}}function st(e,t,n,r){var i,o,a,s,u,l,f,g,m,v;if((t?t.ownerDocument||t:w)!==p&&c(t),t=t||p,n=n||[],!e||"string"!=typeof e)return n;if(1!==(s=t.nodeType)&&9!==s)return[];if(!d&&!r){if(i=J.exec(e))if(a=i[1]){if(9===s){if(o=t.getElementById(a),!o||!o.parentNode)return n;if(o.id===a)return n.push(o),n}else if(t.ownerDocument&&(o=t.ownerDocument.getElementById(a))&&y(t,o)&&o.id===a)return n.push(o),n}else{if(i[2])return H.apply(n,q.call(t.getElementsByTagName(e),0)),n;if((a=i[3])&&T.getByClassName&&t.getElementsByClassName)return H.apply(n,q.call(t.getElementsByClassName(a),0)),n}if(T.qsa&&!h.test(e)){if(f=!0,g=x,m=t,v=9===s&&e,1===s&&"object"!==t.nodeName.toLowerCase()){l=ft(e),(f=t.getAttribute("id"))?g=f.replace(K,"\\$&"):t.setAttribute("id",g),g="[
id='"+g+"'] ",u=l.length;while(u--)l[u]=g+dt(l[u]);m=V.test(e)&&t.parentNode||t,v=l.join(",")}if(v)try{return H.apply(n,q.call(m.querySelectorAll(v),0)),n}catch(b){}finally{f||t.removeAttribute("id")}}}return wt(e.replace(W,"$1"),t,n,r)}a=st.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},c=st.setDocument=function(e){var n=e?e.ownerDocument||e:w;return n!==p&&9===n.nodeType&&n.documentElement?(p=n,f=n.documentElement,d=a(n),T.tagNameNoComments=at(function(e){return e.appendChild(n.createComment("")),!e.getElementsByTagName("*").length}),T.attributes=at(function(e){e.innerHTML="<select></select>";var t=typeof e.lastChild.getAttribute("multiple");return"boolean"!==t&&"string"!==t}),T.getByClassName=at(function(e){return e.innerHTML="<div class='hidden e'></div><div class='hidden'></div>",e.getElementsByClassName&&e.getElementsByClassName("e").length?(e.lastChild.className="e",2===e.getElementsByClassName("e").length):!1}),T.getB
yName=at(function(e){e.id=x+0,e.innerHTML="<a name='"+x+"'></a><div name='"+x+"'></div>",f.insertBefore(e,f.firstChild);var t=n.getElementsByName&&n.getElementsByName(x).length===2+n.getElementsByName(x+0).length;return T.getIdNotName=!n.getElementById(x),f.removeChild(e),t}),i.attrHandle=at(function(e){return e.innerHTML="<a href='#'></a>",e.firstChild&&typeof e.firstChild.getAttribute!==A&&"#"===e.firstChild.getAttribute("href")})?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},T.getIdNotName?(i.find.ID=function(e,t){if(typeof t.getElementById!==A&&!d){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},i.filter.ID=function(e){var t=e.replace(et,tt);return function(e){return e.getAttribute("id")===t}}):(i.find.ID=function(e,n){if(typeof n.getElementById!==A&&!d){var r=n.getElementById(e);return r?r.id===e||typeof r.getAttributeNode!==A&&r.getAttributeNode("id").value===e?[r]:t:[]}},i.filter.ID=function(e){var t=e
.replace(et,tt);return function(e){var n=typeof e.getAttributeNode!==A&&e.getAttributeNode("id");return n&&n.value===t}}),i.find.TAG=T.tagNameNoComments?function(e,n){return typeof n.getElementsByTagName!==A?n.getElementsByTagName(e):t}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},i.find.NAME=T.getByName&&function(e,n){return typeof n.getElementsByName!==A?n.getElementsByName(name):t},i.find.CLASS=T.getByClassName&&function(e,n){return typeof n.getElementsByClassName===A||d?t:n.getElementsByClassName(e)},g=[],h=[":focus"],(T.qsa=rt(n.querySelectorAll))&&(at(function(e){e.innerHTML="<select><option selected=''></option></select>",e.querySelectorAll("[selected]").length||h.push("\\["+_+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||h.push(":checked")}),at(function(e){e.innerHTML="<input type='hidden' i=''/>",e.querySelectorAll("[i^='']").l
ength&&h.push("[*^$]="+_+"*(?:\"\"|'')"),e.querySelectorAll(":enabled").length||h.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),h.push(",.*:")})),(T.matchesSelector=rt(m=f.matchesSelector||f.mozMatchesSelector||f.webkitMatchesSelector||f.oMatchesSelector||f.msMatchesSelector))&&at(function(e){T.disconnectedMatch=m.call(e,"div"),m.call(e,"[s!='']:x"),g.push("!=",R)}),h=RegExp(h.join("|")),g=RegExp(g.join("|")),y=rt(f.contains)||f.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},v=f.compareDocumentPosition?function(e,t){var r;return e===t?(u=!0,0):(r=t.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(t))?1&r||e.parentNode&&11===e.parentNode.nodeType?e===n||y(w,e)?-1:t===n||y(w,t)?1:0:4&r?-1:1:e.compare
DocumentPosition?-1:1}:function(e,t){var r,i=0,o=e.parentNode,a=t.parentNode,s=[e],l=[t];if(e===t)return u=!0,0;if(!o||!a)return e===n?-1:t===n?1:o?-1:a?1:0;if(o===a)return ut(e,t);r=e;while(r=r.parentNode)s.unshift(r);r=t;while(r=r.parentNode)l.unshift(r);while(s[i]===l[i])i++;return i?ut(s[i],l[i]):s[i]===w?-1:l[i]===w?1:0},u=!1,[0,0].sort(v),T.detectDuplicates=u,p):p},st.matches=function(e,t){return st(e,null,null,t)},st.matchesSelector=function(e,t){if((e.ownerDocument||e)!==p&&c(e),t=t.replace(Z,"='$1']"),!(!T.matchesSelector||d||g&&g.test(t)||h.test(t)))try{var n=m.call(e,t);if(n||T.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(r){}return st(t,p,null,[e]).length>0},st.contains=function(e,t){return(e.ownerDocument||e)!==p&&c(e),y(e,t)},st.attr=function(e,t){var n;return(e.ownerDocument||e)!==p&&c(e),d||(t=t.toLowerCase()),(n=i.attrHandle[t])?n(e):d||T.attributes?e.getAttribute(t):((n=e.getAttributeNode(t))||e.getAttribute(t))&&e[t]===!0?t:n&&n.s
pecified?n.value:null},st.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},st.uniqueSort=function(e){var t,n=[],r=1,i=0;if(u=!T.detectDuplicates,e.sort(v),u){for(;t=e[r];r++)t===e[r-1]&&(i=n.push(r));while(i--)e.splice(n[i],1)}return e};function ut(e,t){var n=t&&e,r=n&&(~t.sourceIndex||j)-(~e.sourceIndex||j);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function lt(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function ct(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function pt(e){return ot(function(t){return t=+t,ot(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}o=st.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}
else for(;t=e[r];r++)n+=o(t);return n},i=st.selectors={cacheLength:50,createPseudo:ot,match:U,find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(et,tt),e[3]=(e[4]||e[5]||"").replace(et,tt),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||st.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&st.error(e[0]),e},PSEUDO:function(e){var t,n=!e[5]&&e[2];return U.CHILD.test(e[0])?null:(e[4]?e[2]=e[4]:n&&z.test(n)&&(t=ft(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){return"*"===e?function(){return!0}:(e=e.replace(et,tt).toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=k[e+" "];
return t||(t=RegExp("(^|"+_+")"+e+"("+_+"|$)"))&&k(e,function(e){return t.test(e.className||typeof e.getAttribute!==A&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=st.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,p,f,d,h,g=o!==a?"nextSibling":"previousSibling",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!u&&!s;if(m){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){c=m[x]||(m[x]={}),l=c[e]||[],d=l[0]===N&&l[1],f=l[0]===N&&l[2],p=d&&m.childNodes[d];
while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[N,d,f];break}}else if(v&&(l=(t[x]||(t[x]={}))[e])&&l[0]===N)f=l[1];else while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(v&&((p[x]||(p[x]={}))[e]=[N,f]),p===t))break;return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||st.error("unsupported pseudo: "+e);return r[x]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?ot(function(e,n){var i,o=r(e,t),a=o.length;while(a--)i=M.call(e,o[a]),e[i]=!(n[i]=o[a])}):function(e){return r(e,0,n)}):r}},pseudos:{not:ot(function(e){var t=[],n=[],r=s(e.replace(W,"$1"));return r[x]?ot(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:ot(function(e){return function(t){return st(e,t).length>0}}),contains:ot(function(e){return function(t){return
(t.textContent||t.innerText||o(t)).indexOf(e)>-1}}),lang:ot(function(e){return X.test(e||"")||st.error("unsupported lang: "+e),e=e.replace(et,tt).toLowerCase(),function(t){var n;do if(n=d?t.getAttribute("xml:lang")||t.getAttribute("lang"):t.lang)return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===f},focus:function(e){return e===p.activeElement&&(!p.hasFocus||p.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:
function(e){return!i.pseudos.empty(e)},header:function(e){return Q.test(e.nodeName)},input:function(e){return G.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:pt(function(){return[0]}),last:pt(function(e,t){return[t-1]}),eq:pt(function(e,t,n){return[0>n?n+t:n]}),even:pt(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:pt(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:pt(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:pt(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}};for(n in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})i.pseudos[n]=lt(n);for(n in{submit:!0,reset:!0})i.pseudos[n]=ct(n);function ft(e,t){var n,r,o,a,s,u,l,c=E[e+" "];if(c)return t?0:c.slice(0);s=e,u=[],l=i.preFilter;while(
s){(!n||(r=$.exec(s)))&&(r&&(s=s.slice(r[0].length)||s),u.push(o=[])),n=!1,(r=I.exec(s))&&(n=r.shift(),o.push({value:n,type:r[0].replace(W," ")}),s=s.slice(n.length));for(a in i.filter)!(r=U[a].exec(s))||l[a]&&!(r=l[a](r))||(n=r.shift(),o.push({value:n,type:a,matches:r}),s=s.slice(n.length));if(!n)break}return t?s.length:s?st.error(e):E(e,u).slice(0)}function dt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function ht(e,t,n){var i=t.dir,o=n&&"parentNode"===i,a=C++;return t.first?function(t,n,r){while(t=t[i])if(1===t.nodeType||o)return e(t,n,r)}:function(t,n,s){var u,l,c,p=N+" "+a;if(s){while(t=t[i])if((1===t.nodeType||o)&&e(t,n,s))return!0}else while(t=t[i])if(1===t.nodeType||o)if(c=t[x]||(t[x]={}),(l=c[i])&&l[0]===p){if((u=l[1])===!0||u===r)return u===!0}else if(l=c[i]=[p],l[1]=e(t,n,s)||r,l[1]===!0)return!0}}function gt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function mt(e,t,n,r,i){var o,a=[],s
=0,u=e.length,l=null!=t;for(;u>s;s++)(o=e[s])&&(!n||n(o,r,i))&&(a.push(o),l&&t.push(s));return a}function yt(e,t,n,r,i,o){return r&&!r[x]&&(r=yt(r)),i&&!i[x]&&(i=yt(i,o)),ot(function(o,a,s,u){var l,c,p,f=[],d=[],h=a.length,g=o||xt(t||"*",s.nodeType?[s]:s,[]),m=!e||!o&&t?g:mt(g,f,e,s,u),y=n?i||(o?e:h||r)?[]:a:m;if(n&&n(m,y,s,u),r){l=mt(y,d),r(l,[],s,u),c=l.length;while(c--)(p=l[c])&&(y[d[c]]=!(m[d[c]]=p))}if(o){if(i||e){if(i){l=[],c=y.length;while(c--)(p=y[c])&&l.push(m[c]=p);i(null,y=[],l,u)}c=y.length;while(c--)(p=y[c])&&(l=i?M.call(o,p):f[c])>-1&&(o[l]=!(a[l]=p))}}else y=mt(y===a?y.splice(h,y.length):y),i?i(null,a,y,u):H.apply(a,y)})}function vt(e){var t,n,r,o=e.length,a=i.relative[e[0].type],s=a||i.relative[" "],u=a?1:0,c=ht(function(e){return e===t},s,!0),p=ht(function(e){return M.call(t,e)>-1},s,!0),f=[function(e,n,r){return!a&&(r||n!==l)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;o>u;u++)if(n=i.relative[e[u].type])f=[ht(gt(f),n)];else{if(n=i.filter[e[u].type].apply(nul
l,e[u].matches),n[x]){for(r=++u;o>r;r++)if(i.relative[e[r].type])break;return yt(u>1&>(f),u>1&&dt(e.slice(0,u-1)).replace(W,"$1"),n,r>u&&vt(e.slice(u,r)),o>r&&vt(e=e.slice(r)),o>r&&dt(e))}f.push(n)}return gt(f)}function bt(e,t){var n=0,o=t.length>0,a=e.length>0,s=function(s,u,c,f,d){var h,g,m,y=[],v=0,b="0",x=s&&[],w=null!=d,T=l,C=s||a&&i.find.TAG("*",d&&u.parentNode||u),k=N+=null==T?1:Math.random()||.1;for(w&&(l=u!==p&&u,r=n);null!=(h=C[b]);b++){if(a&&h){g=0;while(m=e[g++])if(m(h,u,c)){f.push(h);break}w&&(N=k,r=++n)}o&&((h=!m&&h)&&v--,s&&x.push(h))}if(v+=b,o&&b!==v){g=0;while(m=t[g++])m(x,y,u,c);if(s){if(v>0)while(b--)x[b]||y[b]||(y[b]=L.call(f));y=mt(y)}H.apply(f,y),w&&!s&&y.length>0&&v+t.length>1&&st.uniqueSort(f)}return w&&(N=k,l=T),x};return o?ot(s):s}s=st.compile=function(e,t){var n,r=[],i=[],o=S[e+" "];if(!o){t||(t=ft(e)),n=t.length;while(n--)o=vt(t[n]),o[x]?r.push(o):i.push(o);o=S(e,bt(i,r))}return o};function xt(e,t,n){var r=0,i=t.length;for(;i>r;r++)st(e,t[r],n);
return n}function wt(e,t,n,r){var o,a,u,l,c,p=ft(e);if(!r&&1===p.length){if(a=p[0]=p[0].slice(0),a.length>2&&"ID"===(u=a[0]).type&&9===t.nodeType&&!d&&i.relative[a[1].type]){if(t=i.find.ID(u.matches[0].replace(et,tt),t)[0],!t)return n;e=e.slice(a.shift().value.length)}o=U.needsContext.test(e)?0:a.length;while(o--){if(u=a[o],i.relative[l=u.type])break;if((c=i.find[l])&&(r=c(u.matches[0].replace(et,tt),V.test(a[0].type)&&t.parentNode||t))){if(a.splice(o,1),e=r.length&&dt(a),!e)return H.apply(n,q.call(r,0)),n;break}}}return s(e,p)(r,t,d,n,V.test(e)),n}i.pseudos.nth=i.pseudos.eq;function Tt(){}i.filters=Tt.prototype=i.pseudos,i.setFilters=new Tt,c(),st.attr=b.attr,b.find=st,b.expr=st.selectors,b.expr[":"]=b.expr.pseudos,b.unique=st.uniqueSort,b.text=st.getText,b.isXMLDoc=st.isXML,b.contains=st.contains}(e);var at=/Until$/,st=/^(?:parents|prev(?:Until|All))/,ut=/^.[^:#\[\.,]*$/,lt=b.expr.match.needsContext,ct={children:!0,contents:!0,next:!0,prev:!0};b.fn.extend({find:function(e)
{var t,n,r,i=this.length;if("string"!=typeof e)return r=this,this.pushStack(b(e).filter(function(){for(t=0;i>t;t++)if(b.contains(r[t],this))return!0}));for(n=[],t=0;i>t;t++)b.find(e,this[t],n);return n=this.pushStack(i>1?b.unique(n):n),n.selector=(this.selector?this.selector+" ":"")+e,n},has:function(e){var t,n=b(e,this),r=n.length;return this.filter(function(){for(t=0;r>t;t++)if(b.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e,!1))},filter:function(e){return this.pushStack(ft(this,e,!0))},is:function(e){return!!e&&("string"==typeof e?lt.test(e)?b(e,this.context).index(this[0])>=0:b.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n,r=0,i=this.length,o=[],a=lt.test(e)||"string"!=typeof e?b(e,t||this.context):0;for(;i>r;r++){n=this[r];while(n&&n.ownerDocument&&n!==t&&11!==n.nodeType){if(a?a.index(n)>-1:b.find.matchesSelector(n,e)){o.push(n);break}n=n.parentNode}}return this.pushStack(o.length>1?b.unique(o):o)},index:
function(e){return e?"string"==typeof e?b.inArray(this[0],b(e)):b.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?b(e,t):b.makeArray(e&&e.nodeType?[e]:e),r=b.merge(this.get(),n);return this.pushStack(b.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),b.fn.andSelf=b.fn.addBack;function pt(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}b.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return b.dir(e,"parentNode")},parentsUntil:function(e,t,n){return b.dir(e,"parentNode",n)},next:function(e){return pt(e,"nextSibling")},prev:function(e){return pt(e,"previousSibling")},nextAll:function(e){return b.dir(e,"nextSibling")},prevAll:function(e){return b.dir(e,"previousSibling")},nextUntil:function(e,t,n){return b.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return b.dir(e,"previousSibling",n)
},siblings:function(e){return b.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return b.sibling(e.firstChild)},contents:function(e){return b.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:b.merge([],e.childNodes)}},function(e,t){b.fn[e]=function(n,r){var i=b.map(this,t,n);return at.test(e)||(r=n),r&&"string"==typeof r&&(i=b.filter(r,i)),i=this.length>1&&!ct[e]?b.unique(i):i,this.length>1&&st.test(e)&&(i=i.reverse()),this.pushStack(i)}}),b.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),1===t.length?b.find.matchesSelector(t[0],e)?[t[0]]:[]:b.find.matches(e,t)},dir:function(e,n,r){var i=[],o=e[n];while(o&&9!==o.nodeType&&(r===t||1!==o.nodeType||!b(o).is(r)))1===o.nodeType&&i.push(o),o=o[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function ft(e,t,n){if(t=t||0,b.isFunction(t))return b.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return b.gre
p(e,function(e){return e===t===n});if("string"==typeof t){var r=b.grep(e,function(e){return 1===e.nodeType});if(ut.test(t))return b.filter(t,r,!n);t=b.filter(t,r)}return b.grep(e,function(e){return b.inArray(e,t)>=0===n})}function dt(e){var t=ht.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}var ht="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",gt=/ jQuery\d+="(?:null|\d+)"/g,mt=RegExp("<(?:"+ht+")[\\s/>]","i"),yt=/^\s+/,vt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bt=/<([\w:]+)/,xt=/<tbody/i,wt=/<|&#?\w+;/,Tt=/<(?:script|style|link)/i,Nt=/^(?:checkbox|radio)$/i,Ct=/checked\s*(?:[^=]|=\s*.checked.)/i,kt=/^$|\/(?:java|ecma)script/i,Et=/^true\/(.*)/,St=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,At={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>"],_default:b.support.htmlSerialize?[0,"",""]:[1,"X<div>","</div>"]},jt=dt(o),Dt=jt.appendChild(o.createElement("div"));At.optgroup=At.option,At.tbody=At.tfoot=At.colgroup=At.caption=At.thead,At.th=At.td,b.fn.extend({text:function(e){return b.access(this,function(e){return e===t?b.text(this):this.empty().append((this[0]&&this[0].ownerDocument||o).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(b.isFunction(e))return this.each(function(t){b(this).wrapAll(e.call(this,t))});if(this[0]){var t=b(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&1===e.firstChild.nodeType)e=e.firstChild;return e}).append(this)}return this},wr
apInner:function(e){return b.isFunction(e)?this.each(function(t){b(this).wrapInner(e.call(this,t))}):this.each(function(){var t=b(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=b.isFunction(e);return this.each(function(n){b(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){b.nodeName(this,"body")||b(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&this.insertBefore(e,this.firstChild)})},before:function(){return this.domManip(arguments,!1,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,!1,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},rem
ove:function(e,t){var n,r=0;for(;null!=(n=this[r]);r++)(!e||b.filter(e,[n]).length>0)&&(t||1!==n.nodeType||b.cleanData(Ot(n)),n.parentNode&&(t&&b.contains(n.ownerDocument,n)&&Mt(Ot(n,"script")),n.parentNode.removeChild(n)));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++){1===e.nodeType&&b.cleanData(Ot(e,!1));while(e.firstChild)e.removeChild(e.firstChild);e.options&&b.nodeName(e,"select")&&(e.options.length=0)}return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return b.clone(this,e,t)})},html:function(e){return b.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return 1===n.nodeType?n.innerHTML.replace(gt,""):t;if(!("string"!=typeof e||Tt.test(e)||!b.support.htmlSerialize&&mt.test(e)||!b.support.leadingWhitespace&&yt.test(e)||At[(bt.exec(e)||["",""])[1].toLowerCase()])){e=e.replace(vt,"<$1></$2>");try{for(;i>r;r++)n=this[r]||{},1===n.nodeType&&(b.cleanData(Ot(n,!1)),n.innerHTML=e);n=0}catch(o){}}n&&
this.empty().append(e)},null,e,arguments.length)},replaceWith:function(e){var t=b.isFunction(e);return t||"string"==typeof e||(e=b(e).not(this).detach()),this.domManip([e],!0,function(e){var t=this.nextSibling,n=this.parentNode;n&&(b(this).remove(),n.insertBefore(e,t))})},detach:function(e){return this.remove(e,!0)},domManip:function(e,n,r){e=f.apply([],e);var i,o,a,s,u,l,c=0,p=this.length,d=this,h=p-1,g=e[0],m=b.isFunction(g);if(m||!(1>=p||"string"!=typeof g||b.support.checkClone)&&Ct.test(g))return this.each(function(i){var o=d.eq(i);m&&(e[0]=g.call(this,i,n?o.html():t)),o.domManip(e,n,r)});if(p&&(l=b.buildFragment(e,this[0].ownerDocument,!1,this),i=l.firstChild,1===l.childNodes.length&&(l=i),i)){for(n=n&&b.nodeName(i,"tr"),s=b.map(Ot(l,"script"),Ht),a=s.length;p>c;c++)o=l,c!==h&&(o=b.clone(o,!0,!0),a&&b.merge(s,Ot(o,"script"))),r.call(n&&b.nodeName(this[c],"table")?Lt(this[c],"tbody"):this[c],o,c);if(a)for(u=s[s.length-1].ownerDocument,b.map(s,qt),c=0;a>c;c++)o=s[c],kt.te
st(o.type||"")&&!b._data(o,"globalEval")&&b.contains(u,o)&&(o.src?b.ajax({url:o.src,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0}):b.globalEval((o.text||o.textContent||o.innerHTML||"").replace(St,"")));l=i=null}return this}});function Lt(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function Ht(e){var t=e.getAttributeNode("type");return e.type=(t&&t.specified)+"/"+e.type,e}function qt(e){var t=Et.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function Mt(e,t){var n,r=0;for(;null!=(n=e[r]);r++)b._data(n,"globalEval",!t||b._data(t[r],"globalEval"))}function _t(e,t){if(1===t.nodeType&&b.hasData(e)){var n,r,i,o=b._data(e),a=b._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;i>r;r++)b.event.add(t,n,s[n][r])}a.data&&(a.data=b.extend({},a.data))}}function Ft(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!b.support.noCloneEvent&&t[b.expando]){i=b._data(
t);for(r in i.events)b.removeEvent(t,r,i.handle);t.removeAttribute(b.expando)}"script"===n&&t.text!==e.text?(Ht(t).text=e.text,qt(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),b.support.html5Clone&&e.innerHTML&&!b.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&Nt.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}}b.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){b.fn[e]=function(e){var n,r=0,i=[],o=b(e),a=o.length-1;for(;a>=r;r++)n=r===a?this:this.clone(!0),b(o[r])[t](n),d.apply(i,n.get());return this.pushStack(i)}});function Ot(e,n){var r,o,a=0,s=typeof e.getElementsByTagName!==i?e.getElementsByTagName(n||"*"):typeof e.querySelectorAll!==i?e.querySelectorAll(n||"*"):t;if(!s)for(s=[],r=e.childNodes||e;null!=(o=r[a])
;a++)!n||b.nodeName(o,n)?s.push(o):b.merge(s,Ot(o,n));return n===t||n&&b.nodeName(e,n)?b.merge([e],s):s}function Bt(e){Nt.test(e.type)&&(e.defaultChecked=e.checked)}b.extend({clone:function(e,t,n){var r,i,o,a,s,u=b.contains(e.ownerDocument,e);if(b.support.html5Clone||b.isXMLDoc(e)||!mt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(Dt.innerHTML=e.outerHTML,Dt.removeChild(o=Dt.firstChild)),!(b.support.noCloneEvent&&b.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||b.isXMLDoc(e)))for(r=Ot(o),s=Ot(e),a=0;null!=(i=s[a]);++a)r[a]&&Ft(i,r[a]);if(t)if(n)for(s=s||Ot(e),r=r||Ot(o),a=0;null!=(i=s[a]);a++)_t(i,r[a]);else _t(e,o);return r=Ot(o,"script"),r.length>0&&Mt(r,!u&&Ot(e,"script")),r=s=i=null,o},buildFragment:function(e,t,n,r){var i,o,a,s,u,l,c,p=e.length,f=dt(t),d=[],h=0;for(;p>h;h++)if(o=e[h],o||0===o)if("object"===b.type(o))b.merge(d,o.nodeType?[o]:o);else if(wt.test(o)){s=s||f.appendChild(t.createElement("div")),u=(bt.exec(o)||["",""])[1].toLowerCase(),c=At[u]||At._def
ault,s.innerHTML=c[1]+o.replace(vt,"<$1></$2>")+c[2],i=c[0];while(i--)s=s.lastChild;if(!b.support.leadingWhitespace&&yt.test(o)&&d.push(t.createTextNode(yt.exec(o)[0])),!b.support.tbody){o="table"!==u||xt.test(o)?"<table>"!==c[1]||xt.test(o)?0:s:s.firstChild,i=o&&o.childNodes.length;while(i--)b.nodeName(l=o.childNodes[i],"tbody")&&!l.childNodes.length&&o.removeChild(l)
-}b.merge(d,s.childNodes),s.textContent="";while(s.firstChild)s.removeChild(s.firstChild);s=f.lastChild}else d.push(t.createTextNode(o));s&&f.removeChild(s),b.support.appendChecked||b.grep(Ot(d,"input"),Bt),h=0;while(o=d[h++])if((!r||-1===b.inArray(o,r))&&(a=b.contains(o.ownerDocument,o),s=Ot(f.appendChild(o),"script"),a&&Mt(s),n)){i=0;while(o=s[i++])kt.test(o.type||"")&&n.push(o)}return s=null,f},cleanData:function(e,t){var n,r,o,a,s=0,u=b.expando,l=b.cache,p=b.support.deleteExpando,f=b.event.special;for(;null!=(n=e[s]);s++)if((t||b.acceptData(n))&&(o=n[u],a=o&&l[o])){if(a.events)for(r in a.events)f[r]?b.event.remove(n,r):b.removeEvent(n,r,a.handle);l[o]&&(delete l[o],p?delete n[u]:typeof n.removeAttribute!==i?n.removeAttribute(u):n[u]=null,c.push(o))}}});var Pt,Rt,Wt,$t=/alpha\([^)]*\)/i,It=/opacity\s*=\s*([^)]*)/,zt=/^(top|right|bottom|left)$/,Xt=/^(none|table(?!-c[ea]).+)/,Ut=/^margin/,Vt=RegExp("^("+x+")(.*)$","i"),Yt=RegExp("^("+x+")(?!px)[a-z%]+$","i"),Jt=RegExp("^([+-
])=("+x+")","i"),Gt={BODY:"block"},Qt={position:"absolute",visibility:"hidden",display:"block"},Kt={letterSpacing:0,fontWeight:400},Zt=["Top","Right","Bottom","Left"],en=["Webkit","O","Moz","ms"];function tn(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=en.length;while(i--)if(t=en[i]+n,t in e)return t;return r}function nn(e,t){return e=t||e,"none"===b.css(e,"display")||!b.contains(e.ownerDocument,e)}function rn(e,t){var n,r,i,o=[],a=0,s=e.length;for(;s>a;a++)r=e[a],r.style&&(o[a]=b._data(r,"olddisplay"),n=r.style.display,t?(o[a]||"none"!==n||(r.style.display=""),""===r.style.display&&nn(r)&&(o[a]=b._data(r,"olddisplay",un(r.nodeName)))):o[a]||(i=nn(r),(n&&"none"!==n||!i)&&b._data(r,"olddisplay",i?n:b.css(r,"display"))));for(a=0;s>a;a++)r=e[a],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[a]||"":"none"));return e}b.fn.extend({css:function(e,n){return b.access(this,function(e,n,r){var i,o,a={},s=0;if(b.isArray(n)){
for(o=Rt(e),i=n.length;i>s;s++)a[n[s]]=b.css(e,n[s],!1,o);return a}return r!==t?b.style(e,n,r):b.css(e,n)},e,n,arguments.length>1)},show:function(){return rn(this,!0)},hide:function(){return rn(this)},toggle:function(e){var t="boolean"==typeof e;return this.each(function(){(t?e:nn(this))?b(this).show():b(this).hide()})}}),b.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Wt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":b.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,u=b.camelCase(n),l=e.style;if(n=b.cssProps[u]||(b.cssProps[u]=tn(l,u)),s=b.cssHooks[n]||b.cssHooks[u],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:l[n];if(a=typeof r,"string"===a&&(o=Jt.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(b.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||
b.cssNumber[u]||(r+="px"),b.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(l[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{l[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,u=b.camelCase(n);return n=b.cssProps[u]||(b.cssProps[u]=tn(e.style,u)),s=b.cssHooks[n]||b.cssHooks[u],s&&"get"in s&&(a=s.get(e,!0,r)),a===t&&(a=Wt(e,n,i)),"normal"===a&&n in Kt&&(a=Kt[n]),""===r||r?(o=parseFloat(a),r===!0||b.isNumeric(o)?o||0:a):a},swap:function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i}}),e.getComputedStyle?(Rt=function(t){return e.getComputedStyle(t,null)},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),u=s?s.getPropertyValue(n)||s[n]:t,l=e.style;return s&&(""!==u||b.contains(e.ownerDocument,e)||(u=b.style(e,n)),Yt.test(u)&&Ut.test(n)&&(i=l.width,o=l.minWidth,a=l.maxWidth,l.minWidth=l.maxWidth=l.width=u,u=s.width,l.width=i,l.minWidth=o,l.maxWidth=a)),u}):o.documentElement.currentStyle&&(Rt=f
unction(e){return e.currentStyle},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),u=s?s[n]:t,l=e.style;return null==u&&l&&l[n]&&(u=l[n]),Yt.test(u)&&!zt.test(n)&&(i=l.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),l.left="fontSize"===n?"1em":u,u=l.pixelLeft+"px",l.left=i,a&&(o.left=a)),""===u?"auto":u});function on(e,t,n){var r=Vt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function an(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;for(;4>o;o+=2)"margin"===n&&(a+=b.css(e,n+Zt[o],!0,i)),r?("content"===n&&(a-=b.css(e,"padding"+Zt[o],!0,i)),"margin"!==n&&(a-=b.css(e,"border"+Zt[o]+"Width",!0,i))):(a+=b.css(e,"padding"+Zt[o],!0,i),"padding"!==n&&(a+=b.css(e,"border"+Zt[o]+"Width",!0,i)));return a}function sn(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Rt(e),a=b.support.boxSizing&&"border-box"===b.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=Wt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Yt.test(i))return i;r=a&&(b.support.bo
xSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+an(e,t,n||(a?"border":"content"),r,o)+"px"}function un(e){var t=o,n=Gt[e];return n||(n=ln(e,t),"none"!==n&&n||(Pt=(Pt||b("<iframe frameborder='0' width='0' height='0'/>").css("cssText","display:block !important")).appendTo(t.documentElement),t=(Pt[0].contentWindow||Pt[0].contentDocument).document,t.write("<!doctype html><html><body>"),t.close(),n=ln(e,t),Pt.detach()),Gt[e]=n),n}function ln(e,t){var n=b(t.createElement(e)).appendTo(t.body),r=b.css(n[0],"display");return n.remove(),r}b.each(["height","width"],function(e,n){b.cssHooks[n]={get:function(e,r,i){return r?0===e.offsetWidth&&Xt.test(b.css(e,"display"))?b.swap(e,Qt,function(){return sn(e,n,i)}):sn(e,n,i):t},set:function(e,t,r){var i=r&&Rt(e);return on(e,t,r?an(e,n,r,b.support.boxSizing&&"border-box"===b.css(e,"boxSizing",!1,i),i):0)}}}),b.support.opacity||(b.cssHooks.opacity={get:function(e,t){return It.test((t&&e.currentStyle?e.currentStyle.filter:e.style.f
ilter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=b.isNumeric(t)?"alpha(opacity="+100*t+")":"",o=r&&r.filter||n.filter||"";n.zoom=1,(t>=1||""===t)&&""===b.trim(o.replace($t,""))&&n.removeAttribute&&(n.removeAttribute("filter"),""===t||r&&!r.filter)||(n.filter=$t.test(o)?o.replace($t,i):o+" "+i)}}),b(function(){b.support.reliableMarginRight||(b.cssHooks.marginRight={get:function(e,n){return n?b.swap(e,{display:"inline-block"},Wt,[e,"marginRight"]):t}}),!b.support.pixelPosition&&b.fn.position&&b.each(["top","left"],function(e,n){b.cssHooks[n]={get:function(e,r){return r?(r=Wt(e,n),Yt.test(r)?b(e).position()[n]+"px":r):t}}})}),b.expr&&b.expr.filters&&(b.expr.filters.hidden=function(e){return 0>=e.offsetWidth&&0>=e.offsetHeight||!b.support.reliableHiddenOffsets&&"none"===(e.style&&e.style.display||b.css(e,"display"))},b.expr.filters.visible=function(e){return!b.expr.filters.hidden(e)}),b.each({margin:"",padding:"",border:"Width
"},function(e,t){b.cssHooks[e+t]={expand:function(n){var r=0,i={},o="string"==typeof n?n.split(" "):[n];for(;4>r;r++)i[e+Zt[r]+t]=o[r]||o[r-2]||o[0];return i}},Ut.test(e)||(b.cssHooks[e+t].set=on)});var cn=/%20/g,pn=/\[\]$/,fn=/\r?\n/g,dn=/^(?:submit|button|image|reset|file)$/i,hn=/^(?:input|select|textarea|keygen)/i;b.fn.extend({serialize:function(){return b.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=b.prop(this,"elements");return e?b.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!b(this).is(":disabled")&&hn.test(this.nodeName)&&!dn.test(e)&&(this.checked||!Nt.test(e))}).map(function(e,t){var n=b(this).val();return null==n?null:b.isArray(n)?b.map(n,function(e){return{name:t.name,value:e.replace(fn,"\r\n")}}):{name:t.name,value:n.replace(fn,"\r\n")}}).get()}}),b.param=function(e,n){var r,i=[],o=function(e,t){t=b.isFunction(t)?t():null==t?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};i
f(n===t&&(n=b.ajaxSettings&&b.ajaxSettings.traditional),b.isArray(e)||e.jquery&&!b.isPlainObject(e))b.each(e,function(){o(this.name,this.value)});else for(r in e)gn(r,e[r],n,o);return i.join("&").replace(cn,"+")};function gn(e,t,n,r){var i;if(b.isArray(t))b.each(t,function(t,i){n||pn.test(e)?r(e,i):gn(e+"["+("object"==typeof i?t:"")+"]",i,n,r)});else if(n||"object"!==b.type(t))r(e,t);else for(i in t)gn(e+"["+i+"]",t[i],n,r)}b.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(e,t){b.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),b.fn.hover=function(e,t){return this.mouseenter(e).mouseleave(t||e)};var mn,yn,vn=b.now(),bn=/\?/,xn=/#.*$/,wn=/([?&])_=[^&]*/,Tn=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Nn=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Cn=/^(?:GET|HEA
D)$/,kn=/^\/\//,En=/^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,Sn=b.fn.load,An={},jn={},Dn="*/".concat("*");try{yn=a.href}catch(Ln){yn=o.createElement("a"),yn.href="",yn=yn.href}mn=En.exec(yn.toLowerCase())||[];function Hn(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(w)||[];if(b.isFunction(n))while(r=o[i++])"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function qn(e,n,r,i){var o={},a=e===jn;function s(u){var l;return o[u]=!0,b.each(e[u]||[],function(e,u){var c=u(n,r,i);return"string"!=typeof c||a||o[c]?a?!(l=c):t:(n.dataTypes.unshift(c),s(c),!1)}),l}return s(n.dataTypes[0])||!o["*"]&&s("*")}function Mn(e,n){var r,i,o=b.ajaxSettings.flatOptions||{};for(i in n)n[i]!==t&&((o[i]?e:r||(r={}))[i]=n[i]);return r&&b.extend(!0,e,r),e}b.fn.load=function(e,n,r){if("string"!=typeof e&&Sn)return Sn.apply(this,arguments);var i,o,a,s=this,u=e.indexOf(" ");return u>=0&&(i=e.slice(u,e.length),e=e.slice(0,u)),
b.isFunction(n)?(r=n,n=t):n&&"object"==typeof n&&(a="POST"),s.length>0&&b.ajax({url:e,type:a,dataType:"html",data:n}).done(function(e){o=arguments,s.html(i?b("<div>").append(b.parseHTML(e)).find(i):e)}).complete(r&&function(e,t){s.each(r,o||[e.responseText,t,e])}),this},b.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){b.fn[t]=function(e){return this.on(t,e)}}),b.each(["get","post"],function(e,n){b[n]=function(e,r,i,o){return b.isFunction(r)&&(o=o||i,i=r,r=t),b.ajax({url:e,type:n,dataType:o,data:r,success:i})}}),b.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:yn,type:"GET",isLocal:Nn.test(mn[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Dn,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"},con
verters:{"* text":e.String,"text html":!0,"text json":b.parseJSON,"text xml":b.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?Mn(Mn(e,b.ajaxSettings),t):Mn(b.ajaxSettings,e)},ajaxPrefilter:Hn(An),ajaxTransport:Hn(jn),ajax:function(e,n){"object"==typeof e&&(n=e,e=t),n=n||{};var r,i,o,a,s,u,l,c,p=b.ajaxSetup({},n),f=p.context||p,d=p.context&&(f.nodeType||f.jquery)?b(f):b.event,h=b.Deferred(),g=b.Callbacks("once memory"),m=p.statusCode||{},y={},v={},x=0,T="canceled",N={readyState:0,getResponseHeader:function(e){var t;if(2===x){if(!c){c={};while(t=Tn.exec(a))c[t[1].toLowerCase()]=t[2]}t=c[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return 2===x?a:null},setRequestHeader:function(e,t){var n=e.toLowerCase();return x||(e=v[n]=v[n]||e,y[e]=t),this},overrideMimeType:function(e){return x||(p.mimeType=e),this},statusCode:function(e){var t;if(e)if(2>x)for(t in e)m[t]=[m[t],e[t]];else N.always(e[N.status]);return this},abort:functi
on(e){var t=e||T;return l&&l.abort(t),k(0,t),this}};if(h.promise(N).complete=g.add,N.success=N.done,N.error=N.fail,p.url=((e||p.url||yn)+"").replace(xn,"").replace(kn,mn[1]+"//"),p.type=n.method||n.type||p.method||p.type,p.dataTypes=b.trim(p.dataType||"*").toLowerCase().match(w)||[""],null==p.crossDomain&&(r=En.exec(p.url.toLowerCase()),p.crossDomain=!(!r||r[1]===mn[1]&&r[2]===mn[2]&&(r[3]||("http:"===r[1]?80:443))==(mn[3]||("http:"===mn[1]?80:443)))),p.data&&p.processData&&"string"!=typeof p.data&&(p.data=b.param(p.data,p.traditional)),qn(An,p,n,N),2===x)return N;u=p.global,u&&0===b.active++&&b.event.trigger("ajaxStart"),p.type=p.type.toUpperCase(),p.hasContent=!Cn.test(p.type),o=p.url,p.hasContent||(p.data&&(o=p.url+=(bn.test(o)?"&":"?")+p.data,delete p.data),p.cache===!1&&(p.url=wn.test(o)?o.replace(wn,"$1_="+vn++):o+(bn.test(o)?"&":"?")+"_="+vn++)),p.ifModified&&(b.lastModified[o]&&N.setRequestHeader("If-Modified-Since",b.lastModified[o]),b.etag[o]&&N.setRequestHeader("I
f-None-Match",b.etag[o])),(p.data&&p.hasContent&&p.contentType!==!1||n.contentType)&&N.setRequestHeader("Content-Type",p.contentType),N.setRequestHeader("Accept",p.dataTypes[0]&&p.accepts[p.dataTypes[0]]?p.accepts[p.dataTypes[0]]+("*"!==p.dataTypes[0]?", "+Dn+"; q=0.01":""):p.accepts["*"]);for(i in p.headers)N.setRequestHeader(i,p.headers[i]);if(p.beforeSend&&(p.beforeSend.call(f,N,p)===!1||2===x))return N.abort();T="abort";for(i in{success:1,error:1,complete:1})N[i](p[i]);if(l=qn(jn,p,n,N)){N.readyState=1,u&&d.trigger("ajaxSend",[N,p]),p.async&&p.timeout>0&&(s=setTimeout(function(){N.abort("timeout")},p.timeout));try{x=1,l.send(y,k)}catch(C){if(!(2>x))throw C;k(-1,C)}}else k(-1,"No Transport");function k(e,n,r,i){var c,y,v,w,T,C=n;2!==x&&(x=2,s&&clearTimeout(s),l=t,a=i||"",N.readyState=e>0?4:0,r&&(w=_n(p,N,r)),e>=200&&300>e||304===e?(p.ifModified&&(T=N.getResponseHeader("Last-Modified"),T&&(b.lastModified[o]=T),T=N.getResponseHeader("etag"),T&&(b.etag[o]=T)),204===e?(c=!0,C
="nocontent"):304===e?(c=!0,C="notmodified"):(c=Fn(p,w),C=c.state,y=c.data,v=c.error,c=!v)):(v=C,(e||!C)&&(C="error",0>e&&(e=0))),N.status=e,N.statusText=(n||C)+"",c?h.resolveWith(f,[y,C,N]):h.rejectWith(f,[N,C,v]),N.statusCode(m),m=t,u&&d.trigger(c?"ajaxSuccess":"ajaxError",[N,p,c?y:v]),g.fireWith(f,[N,C]),u&&(d.trigger("ajaxComplete",[N,p]),--b.active||b.event.trigger("ajaxStop")))}return N},getScript:function(e,n){return b.get(e,t,n,"script")},getJSON:function(e,t,n){return b.get(e,t,n,"json")}});function _n(e,n,r){var i,o,a,s,u=e.contents,l=e.dataTypes,c=e.responseFields;for(s in c)s in r&&(n[c[s]]=r[s]);while("*"===l[0])l.shift(),o===t&&(o=e.mimeType||n.getResponseHeader("Content-Type"));if(o)for(s in u)if(u[s]&&u[s].test(o)){l.unshift(s);break}if(l[0]in r)a=l[0];else{for(s in r){if(!l[0]||e.converters[s+" "+l[0]]){a=s;break}i||(i=s)}a=a||i}return a?(a!==l[0]&&l.unshift(a),r[a]):t}function Fn(e,t){var n,r,i,o,a={},s=0,u=e.dataTypes.slice(),l=u[0];if(e.dataFilter&&(t=e.d
ataFilter(t,e.dataType)),u[1])for(i in e.converters)a[i.toLowerCase()]=e.converters[i];for(;r=u[++s];)if("*"!==r){if("*"!==l&&l!==r){if(i=a[l+" "+r]||a["* "+r],!i)for(n in a)if(o=n.split(" "),o[1]===r&&(i=a[l+" "+o[0]]||a["* "+o[0]])){i===!0?i=a[n]:a[n]!==!0&&(r=o[0],u.splice(s--,0,r));break}if(i!==!0)if(i&&e["throws"])t=i(t);else try{t=i(t)}catch(c){return{state:"parsererror",error:i?c:"No conversion from "+l+" to "+r}}}l=r}return{state:"success",data:t}}b.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(e){return b.globalEval(e),e}}}),b.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),b.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=o.head||b("head")[0]||o.documentElement;return{send:function(t,i){n=o.createElement("script"),n.async=!0,e.scriptCharset&&(n.chars
et=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,t){(t||!n.readyState||/loaded|complete/.test(n.readyState))&&(n.onload=n.onreadystatechange=null,n.parentNode&&n.parentNode.removeChild(n),n=null,t||i(200,"success"))},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(t,!0)}}}});var On=[],Bn=/(=)\?(?=&|$)|\?\?/;b.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=On.pop()||b.expando+"_"+vn++;return this[e]=!0,e}}),b.ajaxPrefilter("json jsonp",function(n,r,i){var o,a,s,u=n.jsonp!==!1&&(Bn.test(n.url)?"url":"string"==typeof n.data&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Bn.test(n.data)&&"data");return u||"jsonp"===n.dataTypes[0]?(o=n.jsonpCallback=b.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,u?n[u]=n[u].replace(Bn,"$1"+o):n.jsonp!==!1&&(n.url+=(bn.test(n.url)?"&":"?")+n.jsonp+"="+o),n.converters["script json"]=function(){return s||b.error(o+" was not called"),s[0]},n.dataTypes[0]="json",a=e
[o],e[o]=function(){s=arguments},i.always(function(){e[o]=a,n[o]&&(n.jsonpCallback=r.jsonpCallback,On.push(o)),s&&b.isFunction(a)&&a(s[0]),s=a=t}),"script"):t});var Pn,Rn,Wn=0,$n=e.ActiveXObject&&function(){var e;for(e in Pn)Pn[e](t,!0)};function In(){try{return new e.XMLHttpRequest}catch(t){}}function zn(){try{return new e.ActiveXObject("Microsoft.XMLHTTP")}catch(t){}}b.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&In()||zn()}:In,Rn=b.ajaxSettings.xhr(),b.support.cors=!!Rn&&"withCredentials"in Rn,Rn=b.support.ajax=!!Rn,Rn&&b.ajaxTransport(function(n){if(!n.crossDomain||b.support.cors){var r;return{send:function(i,o){var a,s,u=n.xhr();if(n.username?u.open(n.type,n.url,n.async,n.username,n.password):u.open(n.type,n.url,n.async),n.xhrFields)for(s in n.xhrFields)u[s]=n.xhrFields[s];n.mimeType&&u.overrideMimeType&&u.overrideMimeType(n.mimeType),n.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest");try{for(s in i)u.setRequestHeader(s,i[
s])}catch(l){}u.send(n.hasContent&&n.data||null),r=function(e,i){var s,l,c,p;try{if(r&&(i||4===u.readyState))if(r=t,a&&(u.onreadystatechange=b.noop,$n&&delete Pn[a]),i)4!==u.readyState&&u.abort();else{p={},s=u.status,l=u.getAllResponseHeaders(),"string"==typeof u.responseText&&(p.text=u.responseText);try{c=u.statusText}catch(f){c=""}s||!n.isLocal||n.crossDomain?1223===s&&(s=204):s=p.text?200:404}}catch(d){i||o(-1,d)}p&&o(s,c,p,l)},n.async?4===u.readyState?setTimeout(r):(a=++Wn,$n&&(Pn||(Pn={},b(e).unload($n)),Pn[a]=r),u.onreadystatechange=r):r()},abort:function(){r&&r(t,!0)}}}});var Xn,Un,Vn=/^(?:toggle|show|hide)$/,Yn=RegExp("^(?:([+-])=|)("+x+")([a-z%]*)$","i"),Jn=/queueHooks$/,Gn=[nr],Qn={"*":[function(e,t){var n,r,i=this.createTween(e,t),o=Yn.exec(t),a=i.cur(),s=+a||0,u=1,l=20;if(o){if(n=+o[2],r=o[3]||(b.cssNumber[e]?"":"px"),"px"!==r&&s){s=b.css(i.elem,e,!0)||n||1;do u=u||".5",s/=u,b.style(i.elem,e,s+r);while(u!==(u=i.cur()/a)&&1!==u&&--l)}i.unit=r,i.start=s,i.end=o[1]?
s+(o[1]+1)*n:n}return i}]};function Kn(){return setTimeout(function(){Xn=t}),Xn=b.now()}function Zn(e,t){b.each(t,function(t,n){var r=(Qn[t]||[]).concat(Qn["*"]),i=0,o=r.length;for(;o>i;i++)if(r[i].call(e,t,n))return})}function er(e,t,n){var r,i,o=0,a=Gn.length,s=b.Deferred().always(function(){delete u.elem}),u=function(){if(i)return!1;var t=Xn||Kn(),n=Math.max(0,l.startTime+l.duration-t),r=n/l.duration||0,o=1-r,a=0,u=l.tweens.length;for(;u>a;a++)l.tweens[a].run(o);return s.notifyWith(e,[l,o,n]),1>o&&u?n:(s.resolveWith(e,[l]),!1)},l=s.promise({elem:e,props:b.extend({},t),opts:b.extend(!0,{specialEasing:{}},n),originalProperties:t,originalOptions:n,startTime:Xn||Kn(),duration:n.duration,tweens:[],createTween:function(t,n){var r=b.Tween(e,l.opts,t,n,l.opts.specialEasing[t]||l.opts.easing);return l.tweens.push(r),r},stop:function(t){var n=0,r=t?l.tweens.length:0;if(i)return this;for(i=!0;r>n;n++)l.tweens[n].run(1);return t?s.resolveWith(e,[l,t]):s.rejectWith(e,[l,t]),this}}),c=
l.props;for(tr(c,l.opts.specialEasing);a>o;o++)if(r=Gn[o].call(l,e,c,l.opts))return r;return Zn(l,c),b.isFunction(l.opts.start)&&l.opts.start.call(e,l),b.fx.timer(b.extend(u,{elem:e,anim:l,queue:l.opts.queue})),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always)}function tr(e,t){var n,r,i,o,a;for(i in e)if(r=b.camelCase(i),o=t[r],n=e[i],b.isArray(n)&&(o=n[1],n=e[i]=n[0]),i!==r&&(e[r]=n,delete e[i]),a=b.cssHooks[r],a&&"expand"in a){n=a.expand(n),delete e[r];for(i in n)i in e||(e[i]=n[i],t[i]=o)}else t[r]=o}b.Animation=b.extend(er,{tweener:function(e,t){b.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;i>r;r++)n=e[r],Qn[n]=Qn[n]||[],Qn[n].unshift(t)},prefilter:function(e,t){t?Gn.unshift(e):Gn.push(e)}});function nr(e,t,n){var r,i,o,a,s,u,l,c,p,f=this,d=e.style,h={},g=[],m=e.nodeType&&nn(e);n.queue||(c=b._queueHooks(e,"fx"),null==c.unqueued&&(c.unqueued=0,p=c.empty.fire,c.empty.fire=function(){c.unqueued||p(
)}),c.unqueued++,f.always(function(){f.always(function(){c.unqueued--,b.queue(e,"fx").length||c.empty.fire()})})),1===e.nodeType&&("height"in t||"width"in t)&&(n.overflow=[d.overflow,d.overflowX,d.overflowY],"inline"===b.css(e,"display")&&"none"===b.css(e,"float")&&(b.support.inlineBlockNeedsLayout&&"inline"!==un(e.nodeName)?d.zoom=1:d.display="inline-block")),n.overflow&&(d.overflow="hidden",b.support.shrinkWrapBlocks||f.always(function(){d.overflow=n.overflow[0],d.overflowX=n.overflow[1],d.overflowY=n.overflow[2]}));for(i in t)if(a=t[i],Vn.exec(a)){if(delete t[i],u=u||"toggle"===a,a===(m?"hide":"show"))continue;g.push(i)}if(o=g.length){s=b._data(e,"fxshow")||b._data(e,"fxshow",{}),"hidden"in s&&(m=s.hidden),u&&(s.hidden=!m),m?b(e).show():f.done(function(){b(e).hide()}),f.done(function(){var t;b._removeData(e,"fxshow");for(t in h)b.style(e,t,h[t])});for(i=0;o>i;i++)r=g[i],l=f.createTween(r,m?s[r]:0),h[r]=s[r]||b.style(e,r),r in s||(s[r]=l.start,m&&(l.end=l.start,l.start="wi
dth"===r||"height"===r?1:0))}}function rr(e,t,n,r,i){return new rr.prototype.init(e,t,n,r,i)}b.Tween=rr,rr.prototype={constructor:rr,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||"swing",this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(b.cssNumber[n]?"":"px")},cur:function(){var e=rr.propHooks[this.prop];return e&&e.get?e.get(this):rr.propHooks._default.get(this)},run:function(e){var t,n=rr.propHooks[this.prop];return this.pos=t=this.options.duration?b.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):rr.propHooks._default.set(this),this}},rr.prototype.init.prototype=rr.prototype,rr.propHooks={_default:{get:function(e){var t;return null==e.elem[e.prop]||e.elem.style&&null!=e.elem.style[e.prop]?(t=b.css(e.elem,e.prop,""),t&&"auto"!==t?t:0):e.elem[e.prop]},set:function(e){b.fx.step
[e.prop]?b.fx.step[e.prop](e):e.elem.style&&(null!=e.elem.style[b.cssProps[e.prop]]||b.cssHooks[e.prop])?b.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}},rr.propHooks.scrollTop=rr.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},b.each(["toggle","show","hide"],function(e,t){var n=b.fn[t];b.fn[t]=function(e,r,i){return null==e||"boolean"==typeof e?n.apply(this,arguments):this.animate(ir(t,!0),e,r,i)}}),b.fn.extend({fadeTo:function(e,t,n,r){return this.filter(nn).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=b.isEmptyObject(e),o=b.speed(t,n,r),a=function(){var t=er(this,b.extend({},e),o);a.finish=function(){t.stop(!0)},(i||b._data(this,"finish"))&&t.stop(!0)};return a.finish=a,i||o.queue===!1?this.each(a):this.queue(o.queue,a)},stop:function(e,n,r){var i=function(e){var t=e.stop;delete e.stop,t(r)};return"string"!=typeof e&&(r=n,n=e,e=t),n&&e!==!1&&this.queue(e||"fx",[]),th
is.each(function(){var t=!0,n=null!=e&&e+"queueHooks",o=b.timers,a=b._data(this);if(n)a[n]&&a[n].stop&&i(a[n]);else for(n in a)a[n]&&a[n].stop&&Jn.test(n)&&i(a[n]);for(n=o.length;n--;)o[n].elem!==this||null!=e&&o[n].queue!==e||(o[n].anim.stop(r),t=!1,o.splice(n,1));(t||!r)&&b.dequeue(this,e)})},finish:function(e){return e!==!1&&(e=e||"fx"),this.each(function(){var t,n=b._data(this),r=n[e+"queue"],i=n[e+"queueHooks"],o=b.timers,a=r?r.length:0;for(n.finish=!0,b.queue(this,e,[]),i&&i.cur&&i.cur.finish&&i.cur.finish.call(this),t=o.length;t--;)o[t].elem===this&&o[t].queue===e&&(o[t].anim.stop(!0),o.splice(t,1));for(t=0;a>t;t++)r[t]&&r[t].finish&&r[t].finish.call(this);delete n.finish})}});function ir(e,t){var n,r={height:e},i=0;for(t=t?1:0;4>i;i+=2-t)n=Zt[i],r["margin"+n]=r["padding"+n]=e;return t&&(r.opacity=r.width=e),r}b.each({slideDown:ir("show"),slideUp:ir("hide"),slideToggle:ir("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},functio
n(e,t){b.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),b.speed=function(e,t,n){var r=e&&"object"==typeof e?b.extend({},e):{complete:n||!n&&t||b.isFunction(e)&&e,duration:e,easing:n&&t||t&&!b.isFunction(t)&&t};return r.duration=b.fx.off?0:"number"==typeof r.duration?r.duration:r.duration in b.fx.speeds?b.fx.speeds[r.duration]:b.fx.speeds._default,(null==r.queue||r.queue===!0)&&(r.queue="fx"),r.old=r.complete,r.complete=function(){b.isFunction(r.old)&&r.old.call(this),r.queue&&b.dequeue(this,r.queue)},r},b.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2}},b.timers=[],b.fx=rr.prototype.init,b.fx.tick=function(){var e,n=b.timers,r=0;for(Xn=b.now();n.length>r;r++)e=n[r],e()||n[r]!==e||n.splice(r--,1);n.length||b.fx.stop(),Xn=t},b.fx.timer=function(e){e()&&b.timers.push(e)&&b.fx.start()},b.fx.interval=13,b.fx.start=function(){Un||(Un=setInterval(b.fx.tick,b.fx.interval))},b.fx.stop=function(){clearInterval(Un),Un=null},b.fx.speeds={slo
w:600,fast:200,_default:400},b.fx.step={},b.expr&&b.expr.filters&&(b.expr.filters.animated=function(e){return b.grep(b.timers,function(t){return e===t.elem}).length}),b.fn.offset=function(e){if(arguments.length)return e===t?this:this.each(function(t){b.offset.setOffset(this,e,t)});var n,r,o={top:0,left:0},a=this[0],s=a&&a.ownerDocument;if(s)return n=s.documentElement,b.contains(n,a)?(typeof a.getBoundingClientRect!==i&&(o=a.getBoundingClientRect()),r=or(s),{top:o.top+(r.pageYOffset||n.scrollTop)-(n.clientTop||0),left:o.left+(r.pageXOffset||n.scrollLeft)-(n.clientLeft||0)}):o},b.offset={setOffset:function(e,t,n){var r=b.css(e,"position");"static"===r&&(e.style.position="relative");var i=b(e),o=i.offset(),a=b.css(e,"top"),s=b.css(e,"left"),u=("absolute"===r||"fixed"===r)&&b.inArray("auto",[a,s])>-1,l={},c={},p,f;u?(c=i.position(),p=c.top,f=c.left):(p=parseFloat(a)||0,f=parseFloat(s)||0),b.isFunction(t)&&(t=t.call(e,n,o)),null!=t.top&&(l.top=t.top-o.top+p),null!=t.left&&(l.left
=t.left-o.left+f),"using"in t?t.using.call(e,l):i.css(l)}},b.fn.extend({position:function(){if(this[0]){var e,t,n={top:0,left:0},r=this[0];return"fixed"===b.css(r,"position")?t=r.getBoundingClientRect():(e=this.offsetParent(),t=this.offset(),b.nodeName(e[0],"html")||(n=e.offset()),n.top+=b.css(e[0],"borderTopWidth",!0),n.left+=b.css(e[0],"borderLeftWidth",!0)),{top:t.top-n.top-b.css(r,"marginTop",!0),left:t.left-n.left-b.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||o.documentElement;while(e&&!b.nodeName(e,"html")&&"static"===b.css(e,"position"))e=e.offsetParent;return e||o.documentElement})}}),b.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);b.fn[e]=function(i){return b.access(this,function(e,i,o){var a=or(e);return o===t?a?n in a?a[n]:a.document.documentElement[i]:e[i]:(a?a.scrollTo(r?b(a).scrollLeft():o,r?o:b(a).scrollTop()):e[i]=o,t)},e,i,arguments.length,null)}});function or
(e){return b.isWindow(e)?e:9===e.nodeType?e.defaultView||e.parentWindow:!1}b.each({Height:"height",Width:"width"},function(e,n){b.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){b.fn[i]=function(i,o){var a=arguments.length&&(r||"boolean"!=typeof i),s=r||(i===!0||o===!0?"margin":"border");return b.access(this,function(n,r,i){var o;return b.isWindow(n)?n.document.documentElement["client"+e]:9===n.nodeType?(o=n.documentElement,Math.max(n.body["scroll"+e],o["scroll"+e],n.body["offset"+e],o["offset"+e],o["client"+e])):i===t?b.css(n,r,s):b.style(n,r,i,s)},n,a?i:t,a,null)}})}),e.jQuery=e.$=b,"function"==typeof define&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return b})})(window);
\ No newline at end of file
diff --git a/modules/enterprise/gui/coregui/src/main/webapp/js/rhq.js b/modules/enterprise/gui/coregui/src/main/webapp/js/rhq.js
index ef65e69..7e89bb1 100644
--- a/modules/enterprise/gui/coregui/src/main/webapp/js/rhq.js
+++ b/modules/enterprise/gui/coregui/src/main/webapp/js/rhq.js
@@ -1,12 +1,7 @@
/**
- * Charting Javascript Functions.
+ * RHQ Charting Javascript Functions.
*/
-// Handle browsers not supporting console object
-if (!window.console) window.console = {};
-if (!window.console.log) window.console.log = function () {
-};
-
/**
* ChartContext Constructor Object
* Contains all of the data required to render a chart.
@@ -38,13 +33,13 @@ if (!window.console.log) window.console.log = function () {
* @param singleValueLabel
* @param chartXaxisTimeFormatHours
* @param chartXaxisTimeFormatHoursMinutes
- * @param showLegend
+ * @param hideLegend
* @constructor
*/
var ChartContext = function (chartId, chartHeight, metricsData, xAxisLabel, chartTitle, yAxisUnits, minChartTitle, avgChartTitle, peakChartTitle, dateLabel, timeLabel, downLabel, unknownLabel, noDataLabel, hoverStartLabel, hoverEndLabel, hoverPeriodLabel, hoverBarLabel, chartHoverTimeFormat, chartHoverDateFormat, isPortalGraph, portalId, buttonBarDateTimeFormat, singleValueLabel, chartXaxisTimeFormatHours, chartXaxisTimeFormatHoursMinutes, hideLegend) {
"use strict";
if (!(this instanceof ChartContext)) {
- throw new Error("ChartContext function cannot be called as a function.")
+ throw new Error("ChartContext function cannot be called as a function.");
}
this.chartId = chartId;
this.chartHeight = chartHeight;
@@ -103,7 +98,7 @@ var ChartContext = function (chartId, chartHeight, metricsData, xAxisLabel, char
AvailChartContext = function (chartId, availData, dateLabel, timeLabel, hoverStartLabel, hoverBarLabel, availabilityLabel, chartHoverTimeFormat, chartHoverDateFormat, chartTitle, chartUpLabel, chartDownLabel, chartXaxisTimeFormatHours, chartXaxisTimeFormatHoursMinutes) {
"use strict";
if (!(this instanceof AvailChartContext)) {
- throw new Error("AvailChartContext function cannot be called as a function.")
+ throw new Error("AvailChartContext function cannot be called as a function.");
}
this.chartId = chartId;
this.chartHandle = "#availChart-" + this.chartId;
@@ -133,12 +128,13 @@ var ChartContext = function (chartId, chartHeight, metricsData, xAxisLabel, char
GraphDateContext = function (startDate, endDate) {
"use strict";
if (!(this instanceof GraphDateContext)) {
- throw new Error("GraphDateContext function cannot be called as a function.")
+ throw new Error("GraphDateContext function cannot be called as a function.");
}
this.startDate = startDate;
this.endDate = endDate;
},
rhqCommon = (function () {
+ "use strict";
var timeFormat = function (formats) {
@@ -146,7 +142,7 @@ var ChartContext = function (chartId, chartHeight, metricsData, xAxisLabel, char
var i = formats.length - 1, f = formats[i];
while (!f[1](date)) f = formats[--i];
return f[0](date);
- }
+ };
};
return {
@@ -179,7 +175,7 @@ var ChartContext = function (chartId, chartHeight, metricsData, xAxisLabel, char
]);
}
- }
+ };
})();
10 years, 10 months
[rhq] 2 commits - modules/common modules/core modules/enterprise modules/helpers modules/plugins
by lkrejci
modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/AntLauncher.java | 39 +
modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/BundleAntProject.java | 12
modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/DeploymentUnitType.java | 68 +-
modules/common/ant-bundle/src/test/java/org/rhq/bundle/ant/AntLauncherTest.java | 194 +++++-
modules/common/ant-bundle/src/test/resources/legacy-test-bundle-audit.xml | 39 +
modules/common/ant-bundle/src/test/resources/legacy-test-bundle-compressed-archives-with-replace.xml | 21
modules/common/ant-bundle/src/test/resources/legacy-test-bundle-compressed-archives.xml | 14
modules/common/ant-bundle/src/test/resources/legacy-test-bundle-subdir.xml | 26
modules/common/ant-bundle/src/test/resources/legacy-test-bundle-url.xml | 26
modules/common/ant-bundle/src/test/resources/legacy-test-bundle-v1.xml | 45 +
modules/common/ant-bundle/src/test/resources/legacy-test-bundle-v2-noManageRootDir.xml | 46 +
modules/common/ant-bundle/src/test/resources/legacy-test-bundle-v2.xml | 45 +
modules/common/ant-bundle/src/test/resources/test-bundle-audit.xml | 23
modules/common/ant-bundle/src/test/resources/test-bundle-compressed-archives-with-replace.xml | 23
modules/common/ant-bundle/src/test/resources/test-bundle-compressed-archives.xml | 23
modules/common/ant-bundle/src/test/resources/test-bundle-no-manage-root-dir-nor-compliance.xml | 64 ++
modules/common/ant-bundle/src/test/resources/test-bundle-subdir.xml | 23
modules/common/ant-bundle/src/test/resources/test-bundle-url.xml | 23
modules/common/ant-bundle/src/test/resources/test-bundle-v1.xml | 23
modules/common/ant-bundle/src/test/resources/test-bundle-v2-filesAndDirectories.xml | 65 ++
modules/common/ant-bundle/src/test/resources/test-bundle-v2-noManageRootDir.xml | 46 -
modules/common/ant-bundle/src/test/resources/test-bundle-v2.xml | 23
modules/common/ant-bundle/src/test/resources/test-bundle-with-manage-root-dir.xml | 64 ++
modules/common/filetemplate-bundle/src/main/java/org/rhq/bundle/filetemplate/recipe/BundleRecipeCommand.java | 4
modules/core/util/src/main/java/org/rhq/core/util/updater/Deployer.java | 16
modules/core/util/src/main/java/org/rhq/core/util/updater/DeploymentData.java | 78 ++
modules/core/util/src/main/java/org/rhq/core/util/updater/DeploymentProperties.java | 105 +++
modules/core/util/src/main/java/org/rhq/core/util/updater/DestinationComplianceMode.java | 87 ++
modules/core/util/src/test/java/org/rhq/core/util/updater/DeploymentPropertiesTest.java | 17
modules/core/util/src/test/java/org/rhq/core/util/updater/DeploymentsMetadataTest.java | 1
modules/core/util/src/test/java/org/rhq/core/util/updater/ManageRootDirTest.java | 4
modules/enterprise/server/itests-2/pom.xml | 10
modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/bundle/BundleManagerBeanTest.java | 12
modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/bundle/TestBundlePluginComponent.java | 84 ++
modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/bundle/TestBundleServerPluginService.java | 50 -
modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/plugins/ant/RecipeValidationTest.java | 292 ++++++++++
modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/resource/metadata/MetadataBeanTest.java | 3
modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/tagging/TagManagerBeanTest.java | 3
modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/test/AbstractEJB3Test.java | 3
modules/enterprise/server/itests-2/src/test/resources/org/rhq/enterprise/server/plugins/ant/recipe-no-manageRootDir.xml | 34 +
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CoreServerMBean.java | 2
modules/enterprise/server/plugins/ant-bundle/src/main/java/org/rhq/enterprise/server/plugins/ant/AntBundleServerPluginComponent.java | 5
modules/helpers/perftest-support/pom.xml | 8
modules/plugins/ant-bundle/src/main/java/org/rhq/plugins/ant/AntBundlePluginComponent.java | 8
44 files changed, 1618 insertions(+), 183 deletions(-)
New commits:
commit 711b389b559b1cd9fb2f8e728ad1abef9c7ac7e7
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Fri Aug 2 10:24:02 2013 +0200
Updating the test recipes for the new names of compliance.
diff --git a/modules/common/ant-bundle/src/test/java/org/rhq/bundle/ant/AntLauncherTest.java b/modules/common/ant-bundle/src/test/java/org/rhq/bundle/ant/AntLauncherTest.java
index 22aa418..6073be9 100644
--- a/modules/common/ant-bundle/src/test/java/org/rhq/bundle/ant/AntLauncherTest.java
+++ b/modules/common/ant-bundle/src/test/java/org/rhq/bundle/ant/AntLauncherTest.java
@@ -303,7 +303,7 @@ public class AntLauncherTest {
}
public void testUpgradeNoManageRootDir() throws Exception {
- testUpgradeNoManageRootDir(true, "test-bundle-v2-commonSubdirectories.xml");
+ testUpgradeNoManageRootDir(true, "test-bundle-v2-filesAndDirectories.xml");
}
private void testUpgradeNoManageRootDir(boolean validate, String recipeFile) throws Exception {
diff --git a/modules/common/ant-bundle/src/test/resources/test-bundle-v2-commonSubdirectories.xml b/modules/common/ant-bundle/src/test/resources/test-bundle-v2-commonSubdirectories.xml
deleted file mode 100644
index 3a82a3d..0000000
--- a/modules/common/ant-bundle/src/test/resources/test-bundle-v2-commonSubdirectories.xml
+++ /dev/null
@@ -1,65 +0,0 @@
-<?xml version="1.0"?>
-
-<!--
- ~ RHQ Management Platform
- ~ Copyright (C) 2013 Red Hat, Inc.
- ~ All rights reserved.
- ~
- ~ This program is free software; you can redistribute it and/or modify
- ~ it under the terms of the GNU General Public License as published by
- ~ the Free Software Foundation version 2 of the License.
- ~
- ~ This program is distributed in the hope that it will be useful,
- ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
- ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ~ GNU General Public License for more details.
- ~
- ~ You should have received a copy of the GNU General Public License
- ~ along with this program; if not, write to the Free Software
- ~ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- -->
-
-<project name="test-bundle" default="main" xmlns:rhq="antlib:org.rhq.bundle">
-
- <rhq:bundle name="example.com (JBoss EAP 4.3)" version="2.5"
- description="updated bundle">
-
- <rhq:input-property
- name="listener.port"
- description="This is where the product will listen for incoming messages"
- required="true"
- defaultValue="9090"
- type="integer"/>
-
- <rhq:deployment-unit name="appserver" preinstallTarget="preinstall" postinstallTarget="postinstall"
- compliance="commonDirectories"> <!-- this is the only difference with test-bundle-v2.xml -->
- <rhq:system-service name="foo" scriptFile="foo-script"
- configFile="foo-config" overwriteScript="true"
- startLevels="3,4,5" startPriority="80" stopPriority="20" root="root"/>
- <rhq:file name="test-v2.properties" destinationFile="subdir/test.properties" replace="true"/>
- <rhq:archive name="file.zip">
- <rhq:replace>
- <rhq:fileset includes="**/*.properties"/>
- </rhq:replace>
- </rhq:archive>
- <!-- the files that should be ignored during upgrades -->
- <rhq:ignore>
- <rhq:fileset includes="*.log"/>
- </rhq:ignore>
- </rhq:deployment-unit>
-
- </rhq:bundle>
-
- <target name="main"/>
-
- <target name="preinstall">
- <echo>Deploying Test Bundle v2.5 to ${rhq.deploy.dir}...</echo>
- <property name="preinstallTargetExecuted" value="2a"/>
- </target>
-
- <target name="postinstall">
- <echo>Done deploying Test Bundle v2.5 to ${rhq.deploy.dir}.</echo>
- <property name="postinstallTargetExecuted" value="2b"/>
- </target>
-
-</project>
diff --git a/modules/common/ant-bundle/src/test/resources/test-bundle-v2-filesAndDirectories.xml b/modules/common/ant-bundle/src/test/resources/test-bundle-v2-filesAndDirectories.xml
new file mode 100644
index 0000000..b82da55
--- /dev/null
+++ b/modules/common/ant-bundle/src/test/resources/test-bundle-v2-filesAndDirectories.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0"?>
+
+<!--
+ ~ RHQ Management Platform
+ ~ Copyright (C) 2013 Red Hat, Inc.
+ ~ All rights reserved.
+ ~
+ ~ This program is free software; you can redistribute it and/or modify
+ ~ it under the terms of the GNU General Public License as published by
+ ~ the Free Software Foundation version 2 of the License.
+ ~
+ ~ This program is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ~ GNU General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU General Public License
+ ~ along with this program; if not, write to the Free Software
+ ~ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ -->
+
+<project name="test-bundle" default="main" xmlns:rhq="antlib:org.rhq.bundle">
+
+ <rhq:bundle name="example.com (JBoss EAP 4.3)" version="2.5"
+ description="updated bundle">
+
+ <rhq:input-property
+ name="listener.port"
+ description="This is where the product will listen for incoming messages"
+ required="true"
+ defaultValue="9090"
+ type="integer"/>
+
+ <rhq:deployment-unit name="appserver" preinstallTarget="preinstall" postinstallTarget="postinstall"
+ compliance="filesAndDirectories"> <!-- this is the only difference with test-bundle-v2.xml -->
+ <rhq:system-service name="foo" scriptFile="foo-script"
+ configFile="foo-config" overwriteScript="true"
+ startLevels="3,4,5" startPriority="80" stopPriority="20" root="root"/>
+ <rhq:file name="test-v2.properties" destinationFile="subdir/test.properties" replace="true"/>
+ <rhq:archive name="file.zip">
+ <rhq:replace>
+ <rhq:fileset includes="**/*.properties"/>
+ </rhq:replace>
+ </rhq:archive>
+ <!-- the files that should be ignored during upgrades -->
+ <rhq:ignore>
+ <rhq:fileset includes="*.log"/>
+ </rhq:ignore>
+ </rhq:deployment-unit>
+
+ </rhq:bundle>
+
+ <target name="main"/>
+
+ <target name="preinstall">
+ <echo>Deploying Test Bundle v2.5 to ${rhq.deploy.dir}...</echo>
+ <property name="preinstallTargetExecuted" value="2a"/>
+ </target>
+
+ <target name="postinstall">
+ <echo>Done deploying Test Bundle v2.5 to ${rhq.deploy.dir}.</echo>
+ <property name="postinstallTargetExecuted" value="2b"/>
+ </target>
+
+</project>
commit 4e54703565e946030da436aa96d01bc7cb8d0dc2
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Fri Aug 2 00:54:49 2013 +0200
[BZ 801926] - manageRootDir deprecated, supeseded by "compliance".
The compliance has now 2 possible values:
* full (corresponds to manageRootDir=true, i.e. the default),
* filesAndDirectories (corresponds to manageRootDir=false)
The name "full" should convey the fact that the deployment directory is in
full compliance with the contents of the bundle.
The name "filesAndDirectories" should convey the behavior of
manageRootDir=false - i.e. the files and directories in the root dir that
are not present in the bundle are left intact. When there is a directory or
file in the root directory that is both in the deployment directory and
the bundle, the file or directory is made compliant to the contents in the
bundle.
The other two proposed deployment behaviors are "rootDirectoryAndFiles"
and "files", but those are commented out for the moment, because we don't
plan to add support for them in RHQ 4.9.
diff --git a/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/AntLauncher.java b/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/AntLauncher.java
index e26a7da..baf981c 100644
--- a/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/AntLauncher.java
+++ b/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/AntLauncher.java
@@ -71,6 +71,37 @@ public class AntLauncher {
// TODO (ips, 04/28/10): Figure out a way to avoid assuming the prefix is "rhq".
private static final String BUNDLE_TASK_NAME = "rhq:bundle";
+ private boolean requireExplicitCompliance;
+
+ /**
+ * For backwards compatibility reasons, this calls {@link #AntLauncher(boolean) AntLauncher(false)}.
+ * Note that this might change in the future, because we are <b>requiring</b> the explicit declaration of the
+ * destination directory's compliance mode starting with RHQ 4.9.0.
+ * <p/>
+ * Nevertheless this constructor is behaving as it was before RHQ 4.9.0 so that users of it aren't surprised
+ * by its behavior.
+ *
+ * @deprecated since 4.9.0. You can keep using this constructor but be aware that it might change behavior in some
+ * future version of RHQ. It will NOT be removed though.
+ */
+ @Deprecated
+ public AntLauncher() {
+ this(false);
+ }
+
+ /**
+ * @since 4.9.0
+ * @param requireExplicitCompliance whether or not to enforce the presence of {@code compliance} attribute in the
+ * deployment unit definitions. Before RHQ 4.9.0 a similar deprecated attribute
+ * called {@code manageRootDir} was optional and defaulted to {@code true}. Since
+ * RHQ 4.9.0 we require the user to explicitly specify the compliance of the
+ * destination directory. But to keep backwards compatibility with the older
+ * bundle recipes already deployed on the agents, we make this behavior optional.
+ */
+ public AntLauncher(boolean requireExplicitCompliance) {
+ this.requireExplicitCompliance = requireExplicitCompliance;
+ }
+
/**
* Executes the specified bundle deploy Ant build file (i.e. rhq-deploy.xml).
*
@@ -241,6 +272,14 @@ public class AntLauncher {
"The bundle task must contain exactly one rhq:deploymentUnit child element.");
}
DeploymentUnitType deployment = deployments.iterator().next();
+
+ if (requireExplicitCompliance && deployment.getCompliance() == null) {
+ throw new InvalidBuildFileException(
+ "The deployment unit must specifically declare compliance mode of the destination directory.");
+ }
+
+ project.setDestinationCompliance(deployment.getCompliance());
+
Map<File, String> files = deployment.getLocalFileNames();
for (String file : files.values()) {
project.getBundleFileNames().add(file);
diff --git a/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/BundleAntProject.java b/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/BundleAntProject.java
index 3c7921d..41b31d8 100644
--- a/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/BundleAntProject.java
+++ b/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/BundleAntProject.java
@@ -32,6 +32,7 @@ import org.apache.tools.ant.Project;
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.configuration.definition.ConfigurationDefinition;
import org.rhq.core.util.updater.DeployDifferences;
+import org.rhq.core.util.updater.DestinationComplianceMode;
/**
* This is the Ant project object that is used when processing bundle Ant scripts
@@ -71,6 +72,9 @@ public class BundleAntProject extends Project {
private DeploymentPhase deploymentPhase;
private boolean dryRun;
+ //note that this will have to change once we start supporting multiple deployment units.
+ private DestinationComplianceMode destinationCompliance;
+
// results of project execution
private DeployDifferences deployDiffs = new DeployDifferences();
private Set<File> downloadedFiles = new HashSet<File>();
@@ -165,6 +169,14 @@ public class BundleAntProject extends Project {
return deployDiffs;
}
+ public DestinationComplianceMode getDestinationCompliance() {
+ return destinationCompliance;
+ }
+
+ public void setDestinationCompliance(DestinationComplianceMode destinationCompliance) {
+ this.destinationCompliance = destinationCompliance;
+ }
+
/**
* If there were url-file or url-archives, this returns the set of files
* that were downloaded from the URLs.
diff --git a/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/DeploymentUnitType.java b/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/DeploymentUnitType.java
index 62956ef..f4a05a8 100644
--- a/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/DeploymentUnitType.java
+++ b/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/DeploymentUnitType.java
@@ -37,6 +37,7 @@ import org.apache.tools.ant.Project;
import org.apache.tools.ant.Target;
import org.rhq.bundle.ant.BundleAntProject.AuditStatus;
+import org.rhq.core.util.updater.DestinationComplianceMode;
import org.rhq.bundle.ant.DeployPropertyNames;
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.configuration.PropertySimple;
@@ -56,7 +57,8 @@ import org.rhq.core.util.updater.DeploymentProperties;
*/
public class DeploymentUnitType extends AbstractBundleType {
private String name;
- private String manageRootDir = Boolean.TRUE.toString();
+
+ private DestinationComplianceMode compliance;
private Map<File, File> files = new LinkedHashMap<File, File>();
private Map<URL, File> urlFiles = new LinkedHashMap<URL, File>();
@@ -103,13 +105,14 @@ public class DeploymentUnitType extends AbstractBundleType {
try {
boolean dryRun = getProject().isDryRun();
- boolean willManageRootDir = Boolean.parseBoolean(this.manageRootDir);
+
+ DestinationComplianceMode complianceToUse = DestinationComplianceMode.instanceOrDefault(this.compliance);
+
File deployDir = getProject().getDeployDir();
TemplateEngine templateEngine = createTemplateEngine(getProject().getUserProperties());
int deploymentId = getProject().getDeploymentId();
DeploymentProperties deploymentProps = new DeploymentProperties(deploymentId, getProject().getBundleName(),
- getProject().getBundleVersion(), getProject().getBundleDescription());
- deploymentProps.setManageRootDir(willManageRootDir);
+ getProject().getBundleVersion(), getProject().getBundleDescription(), complianceToUse);
if (this.preinstallTarget != null) {
getProject().auditLog(AuditStatus.SUCCESS, "Pre-Install Started", "The pre install target will start",
@@ -156,23 +159,28 @@ public class DeploymentUnitType extends AbstractBundleType {
"You must specify at least one file to deploy via nested file, archive, url-file, url-archive types in your recipe");
}
- if (willManageRootDir) {
- log("Managing the root directory of this deployment unit - unrelated files found will be removed",
- Project.MSG_VERBOSE);
- // don't send an audit message on this unless we are really going to move files out of the way (i.e. !dryrun)
+ log("Destination compliance set to '" + complianceToUse + "'.", Project.MSG_VERBOSE);
+ switch (complianceToUse) {
+ case full:
if (!dryRun) {
getProject()
.auditLog(
AuditStatus.INFO,
"Managing Top Level Deployment Directory",
"The top level deployment directory will be managed - files found there will be backed up and removed!",
- "The bundle recipe has requested that the top level deployment directory be fully managed by RHQ."
- + "This means any files currently located in the top level deployment directory will be removed and backed up",
+ "The bundle recipe has requested that the top level deployment directory be fully managed by RHQ." +
+ "This means any files currently located in the top level deployment directory will be removed and backed up",
null);
}
- } else {
- log("Not managing the root directory of this deployment unit - unrelated files will remain intact",
- Project.MSG_VERBOSE);
+ break;
+ case filesAndDirectories:
+ log("Files and directories in the destination directory not contained in the bundle will be kept intact.\n" +
+ "Note that the contents of the directories that ARE contained in the bundle will be synced with " +
+ "the contents as specified in the bundle. I.e. the subdirectories in the destination that are also " +
+ "contained in the bundle are made compliant with the bundle.", Project.MSG_VERBOSE);
+ break;
+ default:
+ throw new IllegalStateException("Unhandled destination compliance mode: " + complianceToUse.toString());
}
Set<File> allArchives = new HashSet<File>(this.archives);
@@ -186,7 +194,7 @@ public class DeploymentUnitType extends AbstractBundleType {
try {
DeploymentData deploymentData = new DeploymentData(deploymentProps, allArchives, allFiles, getProject()
.getBaseDir(), deployDir, allArchiveReplacePatterns, allRawFilesToReplace, templateEngine,
- this.ignorePattern, willManageRootDir, allArchivesExploded);
+ this.ignorePattern, allArchivesExploded);
Deployer deployer = new Deployer(deploymentData);
DeployDifferences diffs = getProject().getDeployDifferences();
@@ -392,16 +400,42 @@ public class DeploymentUnitType extends AbstractBundleType {
this.name = name;
}
+ /**
+ * @deprecated since RHQ 4.9.0, use {@link #getCompliance()}
+ */
public String getManageRootDir() {
- return manageRootDir;
+ return Boolean.toString(getCompliance() == DestinationComplianceMode.full);
}
+ /**
+ * @deprecated since RHQ 4.9.0, use {@link #setCompliance(org.rhq.core.util.updater.DestinationComplianceMode)}
+ */
public void setManageRootDir(String booleanString) {
if (!Boolean.TRUE.toString().equalsIgnoreCase(booleanString)
&& !Boolean.FALSE.toString().equalsIgnoreCase(booleanString)) {
throw new BuildException("manageRootDir attribute must be 'true' or 'false': " + booleanString);
}
- this.manageRootDir = booleanString;
+
+ log("The deprecated 'manageRootDir' attribute was detected. Please consider replacing it with the 'compliance' attribute.",
+ Project.MSG_INFO);
+
+ boolean val = Boolean.parseBoolean(booleanString);
+
+ setCompliance(val ? DestinationComplianceMode.full : DestinationComplianceMode.filesAndDirectories);
+ }
+
+ /**
+ * @since 4.9.0
+ */
+ public DestinationComplianceMode getCompliance() {
+ return compliance;
+ }
+
+ /**
+ * @since 4.9.0
+ */
+ public void setCompliance(DestinationComplianceMode value) {
+ this.compliance = value;
}
/**
@@ -565,4 +599,4 @@ public class DeploymentUnitType extends AbstractBundleType {
getProject().getProperty(DeployPropertyNames.DEPLOY_DIR));
return templateEngine;
}
-}
\ No newline at end of file
+}
diff --git a/modules/common/ant-bundle/src/test/java/org/rhq/bundle/ant/AntLauncherTest.java b/modules/common/ant-bundle/src/test/java/org/rhq/bundle/ant/AntLauncherTest.java
index bd2d35d..22aa418 100644
--- a/modules/common/ant-bundle/src/test/java/org/rhq/bundle/ant/AntLauncherTest.java
+++ b/modules/common/ant-bundle/src/test/java/org/rhq/bundle/ant/AntLauncherTest.java
@@ -31,6 +31,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.Set;
+import java.util.Vector;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
@@ -38,10 +39,17 @@ import java.util.zip.ZipOutputStream;
import org.apache.tools.ant.BuildListener;
import org.apache.tools.ant.DefaultLogger;
import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Target;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.UnknownElement;
+import org.apache.tools.ant.helper.AntXMLContext;
+import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
+import org.rhq.bundle.ant.task.BundleTask;
+import org.rhq.bundle.ant.type.DeploymentUnitType;
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.configuration.definition.ConfigurationDefinition;
import org.rhq.core.domain.configuration.definition.PropertyDefinitionSimple;
@@ -49,6 +57,7 @@ import org.rhq.core.domain.configuration.definition.PropertySimpleType;
import org.rhq.core.util.ZipUtil;
import org.rhq.core.util.file.FileUtil;
import org.rhq.core.util.updater.DeploymentsMetadata;
+import org.rhq.core.util.updater.DestinationComplianceMode;
import org.rhq.core.util.updater.FileHashcodeMap;
/**
@@ -73,13 +82,21 @@ public class AntLauncherTest {
FileUtil.purge(DEPLOY_DIR, true);
}
+ public void testParse_legacy() throws Exception {
+ testParse(false, "legacy-test-bundle-v1.xml");
+ }
+
public void testParse() throws Exception {
+ testParse(true, "test-bundle-v1.xml");
+ }
+
+ private void testParse(boolean validate, String recipeFile) throws Exception {
// We want to test with an empty deploy dir to ensure nothing gets installed there after a parse
FileUtil.purge(DEPLOY_DIR, true);
- AntLauncher ant = new AntLauncher();
+ AntLauncher ant = new AntLauncher(validate);
- BundleAntProject project = ant.parseBundleDeployFile(getBuildXml("test-bundle-v1.xml"), null);
+ BundleAntProject project = ant.parseBundleDeployFile(getBuildXml(recipeFile), null);
assert project != null;
Set<String> bundleFiles = project.getBundleFileNames();
assert bundleFiles != null;
@@ -106,7 +123,49 @@ public class AntLauncherTest {
assert !DEPLOY_DIR.exists() : "Nothing should have been installed to the deploy dir";
}
+ public void testParseWithNoDestinationComplianceCheck() throws Exception {
+ // We want to test with an empty deploy dir to ensure nothing gets installed there after a parse
+ FileUtil.purge(DEPLOY_DIR, true);
+
+ //instantiate the launcher in the new validating mode (new as of RHQ 4.9.0)
+ AntLauncher ant = new AntLauncher(true);
+
+ try {
+ ant.parseBundleDeployFile(getBuildXml("test-bundle-no-manage-root-dir-nor-compliance.xml"), null);
+ Assert.fail("Parsing a bundle with no explicit manageRootDir should have failed.");
+ } catch (InvalidBuildFileException e) {
+ assert "The deployment unit must specifically declare compliance mode of the destination directory.".equals(
+ e.getMessage());
+ }
+
+ BundleAntProject project = ant.parseBundleDeployFile(getBuildXml(
+ "test-bundle-with-manage-root-dir.xml"), null);
+ assert project != null;
+ BundleTask bundleTask = findBundleTask(project);
+ assert bundleTask != null;
+ assert bundleTask.getDeploymentUnits() != null;
+ assert bundleTask.getDeploymentUnits().size() == 1;
+ DeploymentUnitType deploymentUnit = bundleTask.getDeploymentUnits().values().iterator().next();
+ assert deploymentUnit != null;
+
+ //assert the compatibility with the legacy attribute
+ assert "false".equals(deploymentUnit.getManageRootDir());
+ assert DestinationComplianceMode.filesAndDirectories == deploymentUnit.getCompliance();
+
+ // all we did was parse, nothing should really have been extracted or installed
+ assert !DEPLOY_DIR.exists() : "Nothing should have been installed to the deploy dir";
+ }
+
+ public void testInstall_legacy() throws Exception {
+ testInstall(false, "legacy-test-bundle-v1.xml");
+ }
+
+ @Test(dependsOnMethods = "testUpgrade_legacy")
public void testInstall() throws Exception {
+ testInstall(true, "test-bundle-v1.xml");
+ }
+
+ private void testInstall(boolean validate, String recipeFile) throws Exception {
if (skipNonRHLinux("testInstall"))
return;
@@ -117,11 +176,11 @@ public class AntLauncherTest {
// but we do want to add an unrelated file to see that it goes away - since we have manageRootDir=true
File unrelatedFile = writeFile("unrelated content", DEPLOY_DIR, "unrelated-file.txt");
- AntLauncher ant = new AntLauncher();
+ AntLauncher ant = new AntLauncher(validate);
Properties inputProps = createInputProperties("/test-bundle-v1-input.properties");
List<BuildListener> buildListeners = createBuildListeners();
- BundleAntProject project = ant.executeBundleDeployFile(getBuildXml("test-bundle-v1.xml"), inputProps,
+ BundleAntProject project = ant.executeBundleDeployFile(getBuildXml(recipeFile), inputProps,
buildListeners);
assert project != null;
Set<String> bundleFiles = project.getBundleFileNames();
@@ -173,8 +232,17 @@ public class AntLauncherTest {
return false;
}
+ @Test(dependsOnMethods = "testInstall_legacy")
+ public void testUpgrade_legacy() throws Exception {
+ testUpgrade(false, "legacy-test-bundle-v2.xml");
+ }
+
@Test(dependsOnMethods = "testInstall")
public void testUpgrade() throws Exception {
+ testUpgrade(true, "test-bundle-v2.xml");
+ }
+
+ private void testUpgrade(boolean validate, String recipeFile) throws Exception {
if (skipNonRHLinux("testUpgrade"))
return;
@@ -182,11 +250,11 @@ public class AntLauncherTest {
// add an unrelated file to see that it gets deleted as part of the upgrade
File unrelatedFile = writeFile("unrelated content", DEPLOY_DIR, "unrelated-file.txt");
- AntLauncher ant = new AntLauncher();
+ AntLauncher ant = new AntLauncher(validate);
Properties inputProps = createInputProperties("/test-bundle-v2-input.properties");
List<BuildListener> buildListeners = createBuildListeners();
- BundleAntProject project = ant.executeBundleDeployFile(getBuildXml("test-bundle-v2.xml"), inputProps,
+ BundleAntProject project = ant.executeBundleDeployFile(getBuildXml(recipeFile), inputProps,
buildListeners);
assert project != null;
Set<String> bundleFiles = project.getBundleFileNames();
@@ -230,7 +298,15 @@ public class AntLauncherTest {
"templatized.variable").equals("20000");
}
+ public void testUpgradeNoManageRootDir_legacy() throws Exception {
+ testUpgradeNoManageRootDir(false, "legacy-test-bundle-v2-noManageRootDir.xml");
+ }
+
public void testUpgradeNoManageRootDir() throws Exception {
+ testUpgradeNoManageRootDir(true, "test-bundle-v2-commonSubdirectories.xml");
+ }
+
+ private void testUpgradeNoManageRootDir(boolean validate, String recipeFile) throws Exception {
if (skipNonRHLinux("testInstall"))
return;
@@ -243,11 +319,11 @@ public class AntLauncherTest {
File unrelatedFile = writeFile("unrelated content", DEPLOY_DIR, "unrelated-file.txt");
assert unrelatedFile.exists() : "our initial install test method should have prepared an unmanaged file";
- AntLauncher ant = new AntLauncher();
+ AntLauncher ant = new AntLauncher(validate);
Properties inputProps = createInputProperties("/test-bundle-v2-input.properties");
List<BuildListener> buildListeners = createBuildListeners();
- BundleAntProject project = ant.executeBundleDeployFile(getBuildXml("test-bundle-v2-noManageRootDir.xml"),
+ BundleAntProject project = ant.executeBundleDeployFile(getBuildXml(recipeFile),
inputProps, buildListeners);
assert project != null;
Set<String> bundleFiles = project.getBundleFileNames();
@@ -291,23 +367,31 @@ public class AntLauncherTest {
"templatized.variable").equals("20000");
}
+ public void testInstallCompressedZipNoDryRun_legacy() throws Exception {
+ testInstallCompressedZip(false, false, "legacy-test-bundle-compressed-archives.xml");
+ }
+
public void testInstallCompressedZipNoDryRun() throws Exception {
- testInstallCompressedZip(false);
+ testInstallCompressedZip(false, true, "test-bundle-compressed-archives.xml");
+ }
+
+ public void testInstallCompressedZipDryRun_legacy() throws Exception {
+ testInstallCompressedZip(true, false, "legacy-test-bundle-compressed-archives.xml");
}
public void testInstallCompressedZipDryRun() throws Exception {
- testInstallCompressedZip(true);
+ testInstallCompressedZip(true, true, "test-bundle-compressed-archives.xml");
}
- private void testInstallCompressedZip(boolean dryRun) throws Exception {
+ private void testInstallCompressedZip(boolean dryRun, boolean validate, String recipeFile) throws Exception {
// We want to test a fresh install, so make sure the deploy dir doesn't pre-exist.
FileUtil.purge(DEPLOY_DIR, true);
- AntLauncher ant = new AntLauncher();
+ AntLauncher ant = new AntLauncher(validate);
Properties inputProps = createInputProperties("/test-bundle-compressed-archives-input.properties", dryRun);
List<BuildListener> buildListeners = createBuildListeners();
- BundleAntProject project = ant.executeBundleDeployFile(getBuildXml("test-bundle-compressed-archives.xml"),
+ BundleAntProject project = ant.executeBundleDeployFile(getBuildXml(recipeFile),
inputProps, buildListeners);
assert project != null;
Set<String> bundleFiles = project.getBundleFileNames();
@@ -371,24 +455,34 @@ public class AntLauncherTest {
}
}
+ public void testInstallCompressedZipWithTemplatizedFilesNoDryRun_legacy() throws Exception {
+ testInstallCompressedZipWithTemplatizedFiles(false, false,
+ "legacy-test-bundle-compressed-archives-with-replace.xml");
+ }
+
public void testInstallCompressedZipWithTemplatizedFilesNoDryRun() throws Exception {
- testInstallCompressedZipWithTemplatizedFiles(false);
+ testInstallCompressedZipWithTemplatizedFiles(false, true, "test-bundle-compressed-archives-with-replace.xml");
+ }
+
+ public void testInstallCompressedZipWithTemplatizedFilesDryRun_legacy() throws Exception {
+ testInstallCompressedZipWithTemplatizedFiles(true, false,
+ "legacy-test-bundle-compressed-archives-with-replace.xml");
}
public void testInstallCompressedZipWithTemplatizedFilesDryRun() throws Exception {
- testInstallCompressedZipWithTemplatizedFiles(true);
+ testInstallCompressedZipWithTemplatizedFiles(true, true, "test-bundle-compressed-archives-with-replace.xml");
}
- private void testInstallCompressedZipWithTemplatizedFiles(boolean dryRun) throws Exception {
+ private void testInstallCompressedZipWithTemplatizedFiles(boolean dryRun, boolean validate, String recipeFile) throws Exception {
// We want to test a fresh install, so make sure the deploy dir doesn't pre-exist.
FileUtil.purge(DEPLOY_DIR, true);
- AntLauncher ant = new AntLauncher();
+ AntLauncher ant = new AntLauncher(validate);
Properties inputProps = createInputProperties("/test-bundle-compressed-archives-input.properties", dryRun);
List<BuildListener> buildListeners = createBuildListeners();
BundleAntProject project = ant.executeBundleDeployFile(
- getBuildXml("test-bundle-compressed-archives-with-replace.xml"), inputProps, buildListeners);
+ getBuildXml(recipeFile), inputProps, buildListeners);
assert project != null;
Set<String> bundleFiles = project.getBundleFileNames();
assert bundleFiles != null;
@@ -454,20 +548,28 @@ public class AntLauncherTest {
}
}
+ public void testAuditMessages_legacy() throws Exception {
+ testAuditMessages(false, "legacy-test-bundle-audit.xml");
+ }
+
+ public void testAuditMessages() throws Exception {
+ testAuditMessages(true, "test-bundle-audit.xml");
+ }
+
// this doesn't verify the audit messages getting emitted are correct
// but it does verify the audit tag getting processed correctly.
// you have to look at the test logs to see the audit messages
// TODO: write a ant build listener to listen for this messages, parse them and verify they are correct
// this test should then ask the listener at the end if everything was OK and assert false if not
- public void testAuditMessages() throws Exception {
+ private void testAuditMessages(boolean validate, String recipeFile) throws Exception {
// We want to test a fresh install, so make sure the deploy dir doesn't pre-exist.
FileUtil.purge(DEPLOY_DIR, true);
- AntLauncher ant = new AntLauncher();
+ AntLauncher ant = new AntLauncher(validate);
Properties inputProps = createInputProperties("/test-audit-input.properties");
List<BuildListener> buildListeners = createBuildListeners();
- BundleAntProject project = ant.executeBundleDeployFile(getBuildXml("test-bundle-audit.xml"), inputProps,
+ BundleAntProject project = ant.executeBundleDeployFile(getBuildXml(recipeFile), inputProps,
buildListeners);
assert project != null;
Set<String> bundleFiles = project.getBundleFileNames();
@@ -496,7 +598,15 @@ public class AntLauncherTest {
"777");
}
+ public void testSubdirectoriesInRecipe_legacy() throws Exception {
+ testSubdirectoriesInRecipe(false, "legacy-test-bundle-subdir.xml");
+ }
+
public void testSubdirectoriesInRecipe() throws Exception {
+ testSubdirectoriesInRecipe(true, "test-bundle-subdir.xml");
+ }
+
+ private void testSubdirectoriesInRecipe(boolean validate, String origRecipeFile) throws Exception {
// We want to test a fresh install, so make sure the deploy dir doesn't pre-exist.
FileUtil.purge(DEPLOY_DIR, true);
@@ -513,9 +623,9 @@ public class AntLauncherTest {
createZip(new String[] { "3", "4" }, subdir, "test-explode.zip", new String[] { "three.txt", "four.txt" });
createZip(new String[] { "X=@@X@@\n" }, subdir, "test-replace.zip", new String[] { "template.txt" }); // will be exploded then recompressed
File recipeFile = new File(antBasedir, "deploy.xml");
- FileUtil.copyFile(new File(ANT_BASEDIR, "test-bundle-subdir.xml"), recipeFile);
+ FileUtil.copyFile(new File(ANT_BASEDIR, origRecipeFile), recipeFile);
- AntLauncher ant = new AntLauncher();
+ AntLauncher ant = new AntLauncher(validate);
Properties inputProps = new Properties();
inputProps.setProperty(DeployPropertyNames.DEPLOY_DIR, DEPLOY_DIR.getPath());
inputProps.setProperty(DeployPropertyNames.DEPLOY_ID, String.valueOf(++this.deploymentId));
@@ -564,7 +674,15 @@ public class AntLauncherTest {
}
}
+ public void testUrlFilesAndArchives_legacy() throws Exception {
+ testUrlFilesAndArchives(false, "legacy-test-bundle-url.xml");
+ }
+
public void testUrlFilesAndArchives() throws Exception {
+ testUrlFilesAndArchives(true, "test-bundle-url.xml");
+ }
+
+ private void testUrlFilesAndArchives(boolean validate, String recipeFile) throws Exception {
// We want to test a fresh install, so make sure the deploy dir doesn't pre-exist.
FileUtil.purge(DEPLOY_DIR, true);
@@ -582,12 +700,12 @@ public class AntLauncherTest {
createZip(new String[] { "3", "4" }, subdir, "test-explode.zip", new String[] { "three.txt", "four.txt" });
createZip(new String[] { "X=@@X@@\n" }, subdir, "test-replace.zip", new String[] { "template.txt" }); // will be exploded then recompressed
- AntLauncher ant = new AntLauncher();
+ AntLauncher ant = new AntLauncher(validate);
Properties inputProps = createInputProperties("/test-bundle-url-input.properties");
inputProps.setProperty("rhq.test.url.dir", tmpUrlLocation.toURI().toURL().toString()); // we use this so our recipe can use URLs
List<BuildListener> buildListeners = createBuildListeners();
- BundleAntProject project = ant.executeBundleDeployFile(getBuildXml("test-bundle-url.xml"), inputProps,
+ BundleAntProject project = ant.executeBundleDeployFile(getBuildXml(recipeFile), inputProps,
buildListeners);
assert project != null;
@@ -753,4 +871,30 @@ public class AntLauncherTest {
}
}
}
+
+ private BundleTask findBundleTask(BundleAntProject project) {
+ AntXMLContext antParsingContext = (AntXMLContext) project.getReference("ant.parsing.context");
+ Vector targets = antParsingContext.getTargets();
+ for (Object targetObj : targets) {
+ Target target = (Target) targetObj;
+ Task[] tasks = target.getTasks();
+ for (Task task : tasks) {
+ if ("rhq:bundle".equals(task.getTaskName())) {
+ return (BundleTask) preconfigureTask(task);
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private static Task preconfigureTask(Task task) {
+ if (task instanceof UnknownElement) {
+ task.maybeConfigure();
+ Task resolvedTask = ((UnknownElement) task).getTask();
+ return (resolvedTask != null) ? resolvedTask : task;
+ } else {
+ return task;
+ }
+ }
}
diff --git a/modules/common/ant-bundle/src/test/resources/legacy-test-bundle-audit.xml b/modules/common/ant-bundle/src/test/resources/legacy-test-bundle-audit.xml
new file mode 100644
index 0000000..687c4ba
--- /dev/null
+++ b/modules/common/ant-bundle/src/test/resources/legacy-test-bundle-audit.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0"?>
+
+<project name="test-bundle" default="main" xmlns:rhq="antlib:org.rhq.bundle">
+
+ <rhq:bundle name="audit-test" version="1">
+
+ <rhq:input-property name="listener.port" type="integer"/>
+
+ <rhq:deployment-unit name="test" preinstallTarget="preinstall" postinstallTarget="postinstall">
+ <rhq:file name="test-audit.properties" destinationFile="test-audit.properties" replace="true"/>
+ </rhq:deployment-unit>
+
+ </rhq:bundle>
+
+ <target name="main"/>
+
+ <target name="preinstall">
+ <property name="preinstallTargetExecuted" value="1a"/>
+ <rhq:audit status="success" action="action1" info="info1" message="message1">
+ preinstall successful message with port "${listener.port}" !
+ </rhq:audit>
+ <rhq:audit status="failure" action="action2" info="info2" message="message2">
+ preinstall failure message here!
+ </rhq:audit>
+ <rhq:audit status="warn" action="action3" info="info3" message="message3">
+ preinstall warn message here!
+ </rhq:audit>
+ </target>
+
+ <target name="postinstall">
+ <property name="postinstallTargetExecuted" value="1b"/>
+ <rhq:audit />
+ <rhq:audit status="SUCCESS" />
+ <rhq:audit status="WARN" action="actionA" />
+ <rhq:audit status="FAILURE" action="actionB" info="infoB" />
+ <rhq:audit status="SUCCESS" action="actionC" info="infoC" message="messageC" />
+ </target>
+
+</project>
\ No newline at end of file
diff --git a/modules/common/ant-bundle/src/test/resources/legacy-test-bundle-compressed-archives-with-replace.xml b/modules/common/ant-bundle/src/test/resources/legacy-test-bundle-compressed-archives-with-replace.xml
new file mode 100644
index 0000000..ea4255a
--- /dev/null
+++ b/modules/common/ant-bundle/src/test/resources/legacy-test-bundle-compressed-archives-with-replace.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+
+<project name="test-bundle" default="main" xmlns:rhq="antlib:org.rhq.bundle">
+
+ <rhq:bundle name="test compressed archive files" version="1.0">
+
+ <rhq:input-property name="listener.port" type="integer"/>
+
+ <rhq:deployment-unit name="appserver">
+ <rhq:archive name="file.zip" exploded="false">
+ <rhq:replace>
+ <rhq:fileset includes="**/*.foo"/>
+ <rhq:fileset includes="**/*.properties"/>
+ </rhq:replace>
+ </rhq:archive>
+ </rhq:deployment-unit>
+
+ </rhq:bundle>
+
+ <target name="main"/>
+</project>
\ No newline at end of file
diff --git a/modules/common/ant-bundle/src/test/resources/legacy-test-bundle-compressed-archives.xml b/modules/common/ant-bundle/src/test/resources/legacy-test-bundle-compressed-archives.xml
new file mode 100644
index 0000000..a35b6ac
--- /dev/null
+++ b/modules/common/ant-bundle/src/test/resources/legacy-test-bundle-compressed-archives.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+
+<project name="test-bundle" default="main" xmlns:rhq="antlib:org.rhq.bundle">
+
+ <rhq:bundle name="test compressed archive files" version="1.0">
+
+ <rhq:deployment-unit name="appserver">
+ <rhq:archive name="file.zip" exploded="false"/>
+ </rhq:deployment-unit>
+
+ </rhq:bundle>
+
+ <target name="main"/>
+</project>
\ No newline at end of file
diff --git a/modules/common/ant-bundle/src/test/resources/legacy-test-bundle-subdir.xml b/modules/common/ant-bundle/src/test/resources/legacy-test-bundle-subdir.xml
new file mode 100644
index 0000000..af3dbd2
--- /dev/null
+++ b/modules/common/ant-bundle/src/test/resources/legacy-test-bundle-subdir.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+
+<project name="test-bundle" default="main" xmlns:rhq="antlib:org.rhq.bundle">
+
+ <rhq:bundle name="test" version="1">
+
+ <rhq:input-property name="X" />
+
+ <rhq:deployment-unit name="appserver">
+ <rhq:file name="subdir/test0.txt" replace="false" />
+ <rhq:file name="subdir/test1.txt" destinationFile="another/foo.txt" replace="false"/>
+ <rhq:file name="subdir/test2.txt" destinationDir="second.dir" replace="false"/>
+ <rhq:archive name="subdir/test.zip" exploded="false" />
+ <rhq:archive name="subdir/test-explode.zip" exploded="true" />
+ <rhq:archive name="subdir/test-replace.zip" exploded="false">
+ <rhq:replace>
+ <rhq:fileset includes="template.txt"/>
+ </rhq:replace>
+ </rhq:archive>
+ </rhq:deployment-unit>
+
+ </rhq:bundle>
+
+ <target name="main"/>
+
+</project>
\ No newline at end of file
diff --git a/modules/common/ant-bundle/src/test/resources/legacy-test-bundle-url.xml b/modules/common/ant-bundle/src/test/resources/legacy-test-bundle-url.xml
new file mode 100644
index 0000000..ebfdd81
--- /dev/null
+++ b/modules/common/ant-bundle/src/test/resources/legacy-test-bundle-url.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+
+<project name="test-bundle" default="main" xmlns:rhq="antlib:org.rhq.bundle">
+
+ <rhq:bundle name="test" version="1">
+
+ <rhq:input-property name="X" />
+
+ <rhq:deployment-unit name="appserver">
+ <rhq:url-file url="${rhq.test.url.dir}/subdir/test0.txt" replace="false" />
+ <rhq:url-file url="${rhq.test.url.dir}/subdir/test1.txt" destinationFile="another/foo.txt" replace="false" />
+ <rhq:url-file url="${rhq.test.url.dir}/subdir/test2.txt" destinationDir="second.dir" replace="true" />
+ <rhq:url-archive url="${rhq.test.url.dir}/subdir/test.zip" exploded="false" />
+ <rhq:url-archive url="${rhq.test.url.dir}/subdir/test-explode.zip" exploded="true" />
+ <rhq:url-archive url="${rhq.test.url.dir}/subdir/test-replace.zip" exploded="false">
+ <rhq:replace>
+ <rhq:fileset includes="template.txt"/>
+ </rhq:replace>
+ </rhq:url-archive>
+ </rhq:deployment-unit>
+
+ </rhq:bundle>
+
+ <target name="main"/>
+
+</project>
\ No newline at end of file
diff --git a/modules/common/ant-bundle/src/test/resources/legacy-test-bundle-v1.xml b/modules/common/ant-bundle/src/test/resources/legacy-test-bundle-v1.xml
new file mode 100644
index 0000000..6fbcf33
--- /dev/null
+++ b/modules/common/ant-bundle/src/test/resources/legacy-test-bundle-v1.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0"?>
+
+<project name="test-bundle" default="main" xmlns:rhq="antlib:org.rhq.bundle">
+
+ <rhq:bundle name="example.com (JBoss EAP 4.3)" version="1.0"
+ description="example.com corporate website hosted on JBoss EAP 4.3">
+
+ <rhq:input-property
+ name="listener.port"
+ description="This is where the product will listen for incoming messages"
+ required="true"
+ defaultValue="8080"
+ type="integer"/>
+
+ <rhq:deployment-unit name="appserver" preinstallTarget="preinstall" postinstallTarget="postinstall">
+ <rhq:system-service name="foo" scriptFile="foo-script"
+ configFile="foo-config" overwriteScript="true"
+ startLevels="3,4,5" startPriority="80" stopPriority="20" root="root"/>
+ <rhq:file name="test-v1.properties" destinationFile="subdir/test.properties" replace="true"/>
+ <rhq:archive name="file.zip">
+ <rhq:replace>
+ <rhq:fileset includes="**/*.properties"/>
+ </rhq:replace>
+ </rhq:archive>
+ <!-- the files that should be ignored during upgrades -->
+ <rhq:ignore>
+ <rhq:fileset includes="*.log"/>
+ </rhq:ignore>
+ </rhq:deployment-unit>
+
+ </rhq:bundle>
+
+ <target name="main"/>
+
+ <target name="preinstall">
+ <echo>Deploying Test Bundle v1.0 to ${rhq.deploy.dir}...</echo>
+ <property name="preinstallTargetExecuted" value="1a"/>
+ </target>
+
+ <target name="postinstall">
+ <echo>Done deploying Test Bundle v1.0 to ${rhq.deploy.dir}.</echo>
+ <property name="postinstallTargetExecuted" value="1b"/>
+ </target>
+
+</project>
diff --git a/modules/common/ant-bundle/src/test/resources/legacy-test-bundle-v2-noManageRootDir.xml b/modules/common/ant-bundle/src/test/resources/legacy-test-bundle-v2-noManageRootDir.xml
new file mode 100644
index 0000000..defcdef
--- /dev/null
+++ b/modules/common/ant-bundle/src/test/resources/legacy-test-bundle-v2-noManageRootDir.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+
+<project name="test-bundle" default="main" xmlns:rhq="antlib:org.rhq.bundle">
+
+ <rhq:bundle name="example.com (JBoss EAP 4.3)" version="2.5"
+ description="updated bundle">
+
+ <rhq:input-property
+ name="listener.port"
+ description="This is where the product will listen for incoming messages"
+ required="true"
+ defaultValue="9090"
+ type="integer"/>
+
+ <rhq:deployment-unit name="appserver" preinstallTarget="preinstall" postinstallTarget="postinstall"
+ manageRootDir="false"> <!-- this is the only difference with legacy-test-bundle-v2.xml -->
+ <rhq:system-service name="foo" scriptFile="foo-script"
+ configFile="foo-config" overwriteScript="true"
+ startLevels="3,4,5" startPriority="80" stopPriority="20" root="root"/>
+ <rhq:file name="test-v2.properties" destinationFile="subdir/test.properties" replace="true"/>
+ <rhq:archive name="file.zip">
+ <rhq:replace>
+ <rhq:fileset includes="**/*.properties"/>
+ </rhq:replace>
+ </rhq:archive>
+ <!-- the files that should be ignored during upgrades -->
+ <rhq:ignore>
+ <rhq:fileset includes="*.log"/>
+ </rhq:ignore>
+ </rhq:deployment-unit>
+
+ </rhq:bundle>
+
+ <target name="main"/>
+
+ <target name="preinstall">
+ <echo>Deploying Test Bundle v2.5 to ${rhq.deploy.dir}...</echo>
+ <property name="preinstallTargetExecuted" value="2a"/>
+ </target>
+
+ <target name="postinstall">
+ <echo>Done deploying Test Bundle v2.5 to ${rhq.deploy.dir}.</echo>
+ <property name="postinstallTargetExecuted" value="2b"/>
+ </target>
+
+</project>
diff --git a/modules/common/ant-bundle/src/test/resources/legacy-test-bundle-v2.xml b/modules/common/ant-bundle/src/test/resources/legacy-test-bundle-v2.xml
new file mode 100644
index 0000000..e625bc1
--- /dev/null
+++ b/modules/common/ant-bundle/src/test/resources/legacy-test-bundle-v2.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0"?>
+
+<project name="test-bundle" default="main" xmlns:rhq="antlib:org.rhq.bundle">
+
+ <rhq:bundle name="example.com (JBoss EAP 4.3)" version="2.5"
+ description="updated bundle">
+
+ <rhq:input-property
+ name="listener.port"
+ description="This is where the product will listen for incoming messages"
+ required="true"
+ defaultValue="9090"
+ type="integer"/>
+
+ <rhq:deployment-unit name="appserver" preinstallTarget="preinstall" postinstallTarget="postinstall">
+ <rhq:system-service name="foo" scriptFile="foo-script"
+ configFile="foo-config" overwriteScript="true"
+ startLevels="3,4,5" startPriority="80" stopPriority="20" root="root"/>
+ <rhq:file name="test-v2.properties" destinationFile="subdir/test.properties" replace="true"/>
+ <rhq:archive name="file.zip">
+ <rhq:replace>
+ <rhq:fileset includes="**/*.properties"/>
+ </rhq:replace>
+ </rhq:archive>
+ <!-- the files that should be ignored during upgrades -->
+ <rhq:ignore>
+ <rhq:fileset includes="*.log"/>
+ </rhq:ignore>
+ </rhq:deployment-unit>
+
+ </rhq:bundle>
+
+ <target name="main"/>
+
+ <target name="preinstall">
+ <echo>Deploying Test Bundle v2.5 to ${rhq.deploy.dir}...</echo>
+ <property name="preinstallTargetExecuted" value="2a"/>
+ </target>
+
+ <target name="postinstall">
+ <echo>Done deploying Test Bundle v2.5 to ${rhq.deploy.dir}.</echo>
+ <property name="postinstallTargetExecuted" value="2b"/>
+ </target>
+
+</project>
diff --git a/modules/common/ant-bundle/src/test/resources/test-bundle-audit.xml b/modules/common/ant-bundle/src/test/resources/test-bundle-audit.xml
index 687c4ba..d7cfbff 100644
--- a/modules/common/ant-bundle/src/test/resources/test-bundle-audit.xml
+++ b/modules/common/ant-bundle/src/test/resources/test-bundle-audit.xml
@@ -1,12 +1,31 @@
<?xml version="1.0"?>
+<!--
+ ~ RHQ Management Platform
+ ~ Copyright (C) 2013 Red Hat, Inc.
+ ~ All rights reserved.
+ ~
+ ~ This program is free software; you can redistribute it and/or modify
+ ~ it under the terms of the GNU General Public License as published by
+ ~ the Free Software Foundation version 2 of the License.
+ ~
+ ~ This program is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ~ GNU General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU General Public License
+ ~ along with this program; if not, write to the Free Software
+ ~ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ -->
+
<project name="test-bundle" default="main" xmlns:rhq="antlib:org.rhq.bundle">
<rhq:bundle name="audit-test" version="1">
<rhq:input-property name="listener.port" type="integer"/>
- <rhq:deployment-unit name="test" preinstallTarget="preinstall" postinstallTarget="postinstall">
+ <rhq:deployment-unit name="test" preinstallTarget="preinstall" postinstallTarget="postinstall" compliance="full">
<rhq:file name="test-audit.properties" destinationFile="test-audit.properties" replace="true"/>
</rhq:deployment-unit>
@@ -36,4 +55,4 @@
<rhq:audit status="SUCCESS" action="actionC" info="infoC" message="messageC" />
</target>
-</project>
\ No newline at end of file
+</project>
diff --git a/modules/common/ant-bundle/src/test/resources/test-bundle-compressed-archives-with-replace.xml b/modules/common/ant-bundle/src/test/resources/test-bundle-compressed-archives-with-replace.xml
index ea4255a..97bda67 100644
--- a/modules/common/ant-bundle/src/test/resources/test-bundle-compressed-archives-with-replace.xml
+++ b/modules/common/ant-bundle/src/test/resources/test-bundle-compressed-archives-with-replace.xml
@@ -1,12 +1,31 @@
<?xml version="1.0"?>
+<!--
+ ~ RHQ Management Platform
+ ~ Copyright (C) 2013 Red Hat, Inc.
+ ~ All rights reserved.
+ ~
+ ~ This program is free software; you can redistribute it and/or modify
+ ~ it under the terms of the GNU General Public License as published by
+ ~ the Free Software Foundation version 2 of the License.
+ ~
+ ~ This program is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ~ GNU General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU General Public License
+ ~ along with this program; if not, write to the Free Software
+ ~ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ -->
+
<project name="test-bundle" default="main" xmlns:rhq="antlib:org.rhq.bundle">
<rhq:bundle name="test compressed archive files" version="1.0">
<rhq:input-property name="listener.port" type="integer"/>
- <rhq:deployment-unit name="appserver">
+ <rhq:deployment-unit name="appserver" compliance="full">
<rhq:archive name="file.zip" exploded="false">
<rhq:replace>
<rhq:fileset includes="**/*.foo"/>
@@ -18,4 +37,4 @@
</rhq:bundle>
<target name="main"/>
-</project>
\ No newline at end of file
+</project>
diff --git a/modules/common/ant-bundle/src/test/resources/test-bundle-compressed-archives.xml b/modules/common/ant-bundle/src/test/resources/test-bundle-compressed-archives.xml
index a35b6ac..c9c0e58 100644
--- a/modules/common/ant-bundle/src/test/resources/test-bundle-compressed-archives.xml
+++ b/modules/common/ant-bundle/src/test/resources/test-bundle-compressed-archives.xml
@@ -1,14 +1,33 @@
<?xml version="1.0"?>
+<!--
+ ~ RHQ Management Platform
+ ~ Copyright (C) 2013 Red Hat, Inc.
+ ~ All rights reserved.
+ ~
+ ~ This program is free software; you can redistribute it and/or modify
+ ~ it under the terms of the GNU General Public License as published by
+ ~ the Free Software Foundation version 2 of the License.
+ ~
+ ~ This program is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ~ GNU General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU General Public License
+ ~ along with this program; if not, write to the Free Software
+ ~ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ -->
+
<project name="test-bundle" default="main" xmlns:rhq="antlib:org.rhq.bundle">
<rhq:bundle name="test compressed archive files" version="1.0">
- <rhq:deployment-unit name="appserver">
+ <rhq:deployment-unit name="appserver" compliance="full">
<rhq:archive name="file.zip" exploded="false"/>
</rhq:deployment-unit>
</rhq:bundle>
<target name="main"/>
-</project>
\ No newline at end of file
+</project>
diff --git a/modules/common/ant-bundle/src/test/resources/test-bundle-no-manage-root-dir-nor-compliance.xml b/modules/common/ant-bundle/src/test/resources/test-bundle-no-manage-root-dir-nor-compliance.xml
new file mode 100644
index 0000000..1c51912
--- /dev/null
+++ b/modules/common/ant-bundle/src/test/resources/test-bundle-no-manage-root-dir-nor-compliance.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0"?>
+
+<!--
+ ~ RHQ Management Platform
+ ~ Copyright (C) 2013 Red Hat, Inc.
+ ~ All rights reserved.
+ ~
+ ~ This program is free software; you can redistribute it and/or modify
+ ~ it under the terms of the GNU General Public License as published by
+ ~ the Free Software Foundation version 2 of the License.
+ ~
+ ~ This program is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ~ GNU General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU General Public License
+ ~ along with this program; if not, write to the Free Software
+ ~ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ -->
+
+<project name="test-bundle" default="main" xmlns:rhq="antlib:org.rhq.bundle">
+
+ <rhq:bundle name="example.com (JBoss EAP 4.3)" version="1.0"
+ description="example.com corporate website hosted on JBoss EAP 4.3">
+
+ <rhq:input-property
+ name="listener.port"
+ description="This is where the product will listen for incoming messages"
+ required="true"
+ defaultValue="8080"
+ type="integer"/>
+
+ <rhq:deployment-unit name="appserver" preinstallTarget="preinstall" postinstallTarget="postinstall">
+ <rhq:system-service name="foo" scriptFile="foo-script"
+ configFile="foo-config" overwriteScript="true"
+ startLevels="3,4,5" startPriority="80" stopPriority="20" root="root"/>
+ <rhq:file name="test-v1.properties" destinationFile="subdir/test.properties" replace="true"/>
+ <rhq:archive name="file.zip">
+ <rhq:replace>
+ <rhq:fileset includes="**/*.properties"/>
+ </rhq:replace>
+ </rhq:archive>
+ <!-- the files that should be ignored during upgrades -->
+ <rhq:ignore>
+ <rhq:fileset includes="*.log"/>
+ </rhq:ignore>
+ </rhq:deployment-unit>
+
+ </rhq:bundle>
+
+ <target name="main"/>
+
+ <target name="preinstall">
+ <echo>Deploying Test Bundle v1.0 to ${rhq.deploy.dir}...</echo>
+ <property name="preinstallTargetExecuted" value="1a"/>
+ </target>
+
+ <target name="postinstall">
+ <echo>Done deploying Test Bundle v1.0 to ${rhq.deploy.dir}.</echo>
+ <property name="postinstallTargetExecuted" value="1b"/>
+ </target>
+
+</project>
diff --git a/modules/common/ant-bundle/src/test/resources/test-bundle-subdir.xml b/modules/common/ant-bundle/src/test/resources/test-bundle-subdir.xml
index af3dbd2..6d3c36a 100644
--- a/modules/common/ant-bundle/src/test/resources/test-bundle-subdir.xml
+++ b/modules/common/ant-bundle/src/test/resources/test-bundle-subdir.xml
@@ -1,12 +1,31 @@
<?xml version="1.0"?>
+<!--
+ ~ RHQ Management Platform
+ ~ Copyright (C) 2013 Red Hat, Inc.
+ ~ All rights reserved.
+ ~
+ ~ This program is free software; you can redistribute it and/or modify
+ ~ it under the terms of the GNU General Public License as published by
+ ~ the Free Software Foundation version 2 of the License.
+ ~
+ ~ This program is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ~ GNU General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU General Public License
+ ~ along with this program; if not, write to the Free Software
+ ~ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ -->
+
<project name="test-bundle" default="main" xmlns:rhq="antlib:org.rhq.bundle">
<rhq:bundle name="test" version="1">
<rhq:input-property name="X" />
- <rhq:deployment-unit name="appserver">
+ <rhq:deployment-unit name="appserver" compliance="full">
<rhq:file name="subdir/test0.txt" replace="false" />
<rhq:file name="subdir/test1.txt" destinationFile="another/foo.txt" replace="false"/>
<rhq:file name="subdir/test2.txt" destinationDir="second.dir" replace="false"/>
@@ -23,4 +42,4 @@
<target name="main"/>
-</project>
\ No newline at end of file
+</project>
diff --git a/modules/common/ant-bundle/src/test/resources/test-bundle-url.xml b/modules/common/ant-bundle/src/test/resources/test-bundle-url.xml
index ebfdd81..578400d 100644
--- a/modules/common/ant-bundle/src/test/resources/test-bundle-url.xml
+++ b/modules/common/ant-bundle/src/test/resources/test-bundle-url.xml
@@ -1,12 +1,31 @@
<?xml version="1.0"?>
+<!--
+ ~ RHQ Management Platform
+ ~ Copyright (C) 2013 Red Hat, Inc.
+ ~ All rights reserved.
+ ~
+ ~ This program is free software; you can redistribute it and/or modify
+ ~ it under the terms of the GNU General Public License as published by
+ ~ the Free Software Foundation version 2 of the License.
+ ~
+ ~ This program is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ~ GNU General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU General Public License
+ ~ along with this program; if not, write to the Free Software
+ ~ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ -->
+
<project name="test-bundle" default="main" xmlns:rhq="antlib:org.rhq.bundle">
<rhq:bundle name="test" version="1">
<rhq:input-property name="X" />
- <rhq:deployment-unit name="appserver">
+ <rhq:deployment-unit name="appserver" compliance="full">
<rhq:url-file url="${rhq.test.url.dir}/subdir/test0.txt" replace="false" />
<rhq:url-file url="${rhq.test.url.dir}/subdir/test1.txt" destinationFile="another/foo.txt" replace="false" />
<rhq:url-file url="${rhq.test.url.dir}/subdir/test2.txt" destinationDir="second.dir" replace="true" />
@@ -23,4 +42,4 @@
<target name="main"/>
-</project>
\ No newline at end of file
+</project>
diff --git a/modules/common/ant-bundle/src/test/resources/test-bundle-v1.xml b/modules/common/ant-bundle/src/test/resources/test-bundle-v1.xml
index a6dcfec..2d38f1d 100644
--- a/modules/common/ant-bundle/src/test/resources/test-bundle-v1.xml
+++ b/modules/common/ant-bundle/src/test/resources/test-bundle-v1.xml
@@ -1,5 +1,24 @@
<?xml version="1.0"?>
+<!--
+ ~ RHQ Management Platform
+ ~ Copyright (C) 2013 Red Hat, Inc.
+ ~ All rights reserved.
+ ~
+ ~ This program is free software; you can redistribute it and/or modify
+ ~ it under the terms of the GNU General Public License as published by
+ ~ the Free Software Foundation version 2 of the License.
+ ~
+ ~ This program is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ~ GNU General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU General Public License
+ ~ along with this program; if not, write to the Free Software
+ ~ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ -->
+
<project name="test-bundle" default="main" xmlns:rhq="antlib:org.rhq.bundle">
<rhq:bundle name="example.com (JBoss EAP 4.3)" version="1.0"
@@ -12,7 +31,7 @@
defaultValue="8080"
type="integer"/>
- <rhq:deployment-unit name="appserver" preinstallTarget="preinstall" postinstallTarget="postinstall">
+ <rhq:deployment-unit name="appserver" preinstallTarget="preinstall" postinstallTarget="postinstall" compliance="full">
<rhq:system-service name="foo" scriptFile="foo-script"
configFile="foo-config" overwriteScript="true"
startLevels="3,4,5" startPriority="80" stopPriority="20" root="root"/>
@@ -42,4 +61,4 @@
<property name="postinstallTargetExecuted" value="1b"/>
</target>
-</project>
\ No newline at end of file
+</project>
diff --git a/modules/common/ant-bundle/src/test/resources/test-bundle-v2-commonSubdirectories.xml b/modules/common/ant-bundle/src/test/resources/test-bundle-v2-commonSubdirectories.xml
new file mode 100644
index 0000000..3a82a3d
--- /dev/null
+++ b/modules/common/ant-bundle/src/test/resources/test-bundle-v2-commonSubdirectories.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0"?>
+
+<!--
+ ~ RHQ Management Platform
+ ~ Copyright (C) 2013 Red Hat, Inc.
+ ~ All rights reserved.
+ ~
+ ~ This program is free software; you can redistribute it and/or modify
+ ~ it under the terms of the GNU General Public License as published by
+ ~ the Free Software Foundation version 2 of the License.
+ ~
+ ~ This program is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ~ GNU General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU General Public License
+ ~ along with this program; if not, write to the Free Software
+ ~ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ -->
+
+<project name="test-bundle" default="main" xmlns:rhq="antlib:org.rhq.bundle">
+
+ <rhq:bundle name="example.com (JBoss EAP 4.3)" version="2.5"
+ description="updated bundle">
+
+ <rhq:input-property
+ name="listener.port"
+ description="This is where the product will listen for incoming messages"
+ required="true"
+ defaultValue="9090"
+ type="integer"/>
+
+ <rhq:deployment-unit name="appserver" preinstallTarget="preinstall" postinstallTarget="postinstall"
+ compliance="commonDirectories"> <!-- this is the only difference with test-bundle-v2.xml -->
+ <rhq:system-service name="foo" scriptFile="foo-script"
+ configFile="foo-config" overwriteScript="true"
+ startLevels="3,4,5" startPriority="80" stopPriority="20" root="root"/>
+ <rhq:file name="test-v2.properties" destinationFile="subdir/test.properties" replace="true"/>
+ <rhq:archive name="file.zip">
+ <rhq:replace>
+ <rhq:fileset includes="**/*.properties"/>
+ </rhq:replace>
+ </rhq:archive>
+ <!-- the files that should be ignored during upgrades -->
+ <rhq:ignore>
+ <rhq:fileset includes="*.log"/>
+ </rhq:ignore>
+ </rhq:deployment-unit>
+
+ </rhq:bundle>
+
+ <target name="main"/>
+
+ <target name="preinstall">
+ <echo>Deploying Test Bundle v2.5 to ${rhq.deploy.dir}...</echo>
+ <property name="preinstallTargetExecuted" value="2a"/>
+ </target>
+
+ <target name="postinstall">
+ <echo>Done deploying Test Bundle v2.5 to ${rhq.deploy.dir}.</echo>
+ <property name="postinstallTargetExecuted" value="2b"/>
+ </target>
+
+</project>
diff --git a/modules/common/ant-bundle/src/test/resources/test-bundle-v2-noManageRootDir.xml b/modules/common/ant-bundle/src/test/resources/test-bundle-v2-noManageRootDir.xml
deleted file mode 100644
index 0b07e9e..0000000
--- a/modules/common/ant-bundle/src/test/resources/test-bundle-v2-noManageRootDir.xml
+++ /dev/null
@@ -1,46 +0,0 @@
-<?xml version="1.0"?>
-
-<project name="test-bundle" default="main" xmlns:rhq="antlib:org.rhq.bundle">
-
- <rhq:bundle name="example.com (JBoss EAP 4.3)" version="2.5"
- description="updated bundle">
-
- <rhq:input-property
- name="listener.port"
- description="This is where the product will listen for incoming messages"
- required="true"
- defaultValue="9090"
- type="integer"/>
-
- <rhq:deployment-unit name="appserver" preinstallTarget="preinstall" postinstallTarget="postinstall"
- manageRootDir="false"> <!-- this is the only difference with test-bundle-v2.xml -->
- <rhq:system-service name="foo" scriptFile="foo-script"
- configFile="foo-config" overwriteScript="true"
- startLevels="3,4,5" startPriority="80" stopPriority="20" root="root"/>
- <rhq:file name="test-v2.properties" destinationFile="subdir/test.properties" replace="true"/>
- <rhq:archive name="file.zip">
- <rhq:replace>
- <rhq:fileset includes="**/*.properties"/>
- </rhq:replace>
- </rhq:archive>
- <!-- the files that should be ignored during upgrades -->
- <rhq:ignore>
- <rhq:fileset includes="*.log"/>
- </rhq:ignore>
- </rhq:deployment-unit>
-
- </rhq:bundle>
-
- <target name="main"/>
-
- <target name="preinstall">
- <echo>Deploying Test Bundle v2.5 to ${rhq.deploy.dir}...</echo>
- <property name="preinstallTargetExecuted" value="2a"/>
- </target>
-
- <target name="postinstall">
- <echo>Done deploying Test Bundle v2.5 to ${rhq.deploy.dir}.</echo>
- <property name="postinstallTargetExecuted" value="2b"/>
- </target>
-
-</project>
\ No newline at end of file
diff --git a/modules/common/ant-bundle/src/test/resources/test-bundle-v2.xml b/modules/common/ant-bundle/src/test/resources/test-bundle-v2.xml
index 1bbe0d1..4d40213 100644
--- a/modules/common/ant-bundle/src/test/resources/test-bundle-v2.xml
+++ b/modules/common/ant-bundle/src/test/resources/test-bundle-v2.xml
@@ -1,5 +1,24 @@
<?xml version="1.0"?>
+<!--
+ ~ RHQ Management Platform
+ ~ Copyright (C) 2013 Red Hat, Inc.
+ ~ All rights reserved.
+ ~
+ ~ This program is free software; you can redistribute it and/or modify
+ ~ it under the terms of the GNU General Public License as published by
+ ~ the Free Software Foundation version 2 of the License.
+ ~
+ ~ This program is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ~ GNU General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU General Public License
+ ~ along with this program; if not, write to the Free Software
+ ~ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ -->
+
<project name="test-bundle" default="main" xmlns:rhq="antlib:org.rhq.bundle">
<rhq:bundle name="example.com (JBoss EAP 4.3)" version="2.5"
@@ -12,7 +31,7 @@
defaultValue="9090"
type="integer"/>
- <rhq:deployment-unit name="appserver" preinstallTarget="preinstall" postinstallTarget="postinstall">
+ <rhq:deployment-unit name="appserver" preinstallTarget="preinstall" postinstallTarget="postinstall" compliance="full">
<rhq:system-service name="foo" scriptFile="foo-script"
configFile="foo-config" overwriteScript="true"
startLevels="3,4,5" startPriority="80" stopPriority="20" root="root"/>
@@ -42,4 +61,4 @@
<property name="postinstallTargetExecuted" value="2b"/>
</target>
-</project>
\ No newline at end of file
+</project>
diff --git a/modules/common/ant-bundle/src/test/resources/test-bundle-with-manage-root-dir.xml b/modules/common/ant-bundle/src/test/resources/test-bundle-with-manage-root-dir.xml
new file mode 100644
index 0000000..68fdcc0
--- /dev/null
+++ b/modules/common/ant-bundle/src/test/resources/test-bundle-with-manage-root-dir.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0"?>
+
+<!--
+ ~ RHQ Management Platform
+ ~ Copyright (C) 2013 Red Hat, Inc.
+ ~ All rights reserved.
+ ~
+ ~ This program is free software; you can redistribute it and/or modify
+ ~ it under the terms of the GNU General Public License as published by
+ ~ the Free Software Foundation version 2 of the License.
+ ~
+ ~ This program is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ~ GNU General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU General Public License
+ ~ along with this program; if not, write to the Free Software
+ ~ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ -->
+
+<project name="test-bundle" default="main" xmlns:rhq="antlib:org.rhq.bundle">
+
+ <rhq:bundle name="example.com (JBoss EAP 4.3)" version="1.0"
+ description="example.com corporate website hosted on JBoss EAP 4.3">
+
+ <rhq:input-property
+ name="listener.port"
+ description="This is where the product will listen for incoming messages"
+ required="true"
+ defaultValue="8080"
+ type="integer"/>
+
+ <rhq:deployment-unit name="appserver" preinstallTarget="preinstall" postinstallTarget="postinstall" manageRootDir="false">
+ <rhq:system-service name="foo" scriptFile="foo-script"
+ configFile="foo-config" overwriteScript="true"
+ startLevels="3,4,5" startPriority="80" stopPriority="20" root="root"/>
+ <rhq:file name="test-v1.properties" destinationFile="subdir/test.properties" replace="true"/>
+ <rhq:archive name="file.zip">
+ <rhq:replace>
+ <rhq:fileset includes="**/*.properties"/>
+ </rhq:replace>
+ </rhq:archive>
+ <!-- the files that should be ignored during upgrades -->
+ <rhq:ignore>
+ <rhq:fileset includes="*.log"/>
+ </rhq:ignore>
+ </rhq:deployment-unit>
+
+ </rhq:bundle>
+
+ <target name="main"/>
+
+ <target name="preinstall">
+ <echo>Deploying Test Bundle v1.0 to ${rhq.deploy.dir}...</echo>
+ <property name="preinstallTargetExecuted" value="1a"/>
+ </target>
+
+ <target name="postinstall">
+ <echo>Done deploying Test Bundle v1.0 to ${rhq.deploy.dir}.</echo>
+ <property name="postinstallTargetExecuted" value="1b"/>
+ </target>
+
+</project>
diff --git a/modules/common/filetemplate-bundle/src/main/java/org/rhq/bundle/filetemplate/recipe/BundleRecipeCommand.java b/modules/common/filetemplate-bundle/src/main/java/org/rhq/bundle/filetemplate/recipe/BundleRecipeCommand.java
index fc65162..7fe02b7 100644
--- a/modules/common/filetemplate-bundle/src/main/java/org/rhq/bundle/filetemplate/recipe/BundleRecipeCommand.java
+++ b/modules/common/filetemplate-bundle/src/main/java/org/rhq/bundle/filetemplate/recipe/BundleRecipeCommand.java
@@ -27,6 +27,7 @@ import gnu.getopt.Getopt;
import gnu.getopt.LongOpt;
import org.rhq.core.util.updater.DeploymentProperties;
+import org.rhq.core.util.updater.DestinationComplianceMode;
public class BundleRecipeCommand implements RecipeCommand {
@@ -100,6 +101,9 @@ public class BundleRecipeCommand implements RecipeCommand {
}
props.setDeploymentId(0);
+ //file templates don't support destination compliance, so let's just provide something dummy
+ props.setDestinationCompliance(DestinationComplianceMode.full);
+
return;
}
}
diff --git a/modules/core/util/src/main/java/org/rhq/core/util/updater/Deployer.java b/modules/core/util/src/main/java/org/rhq/core/util/updater/Deployer.java
index a5eadea..0f1f266 100644
--- a/modules/core/util/src/main/java/org/rhq/core/util/updater/Deployer.java
+++ b/modules/core/util/src/main/java/org/rhq/core/util/updater/Deployer.java
@@ -319,12 +319,15 @@ public class Deployer {
}
private FileHashcodeMap performInitialDeployment(DeployDifferences diff, boolean dryRun) throws Exception {
- if (this.deploymentData.isManageRootDir()) {
+ switch (deploymentData.getDeploymentProps().getDestinationCompliance()) {
+ case full: {
// We are to fully manage the deployment dir, so we need to delete everything we find there.
// Any old files do not belong here - only our bundle files should live here now.
File dir = this.deploymentData.getDestinationDir();
backupAndPurgeDirectory(diff, dir, dryRun, null);
- } else {
+ }
+ break;
+ case filesAndDirectories: {
// We are not to manage files in the root deployment directory. However, we always manage
// subdirectories that the bundle wants to deploy. So look in subdirectories that our bundles
// plan to use and remove files that found there.
@@ -336,6 +339,10 @@ public class Deployer {
backupAndPurgeDirectory(diff, dir, dryRun, managedSubdir.getPath() + File.separatorChar);
}
}
+ break;
+ default:
+ throw new IllegalStateException("Unsupported destination compliance mode.");
+ }
FileHashcodeMap newFileHashcodeMap = extractZipAndRawFiles(new HashMap<String, String>(0), diff, dryRun);
@@ -359,10 +366,11 @@ public class Deployer {
// * if a current file is ignored in the latest rescan
// * if a file is realized on the filesystem before its stored on the file system
// * if a current file is backed up
-
+ boolean reportNewRootFilesAsNew =
+ this.deploymentData.getDeploymentProps().getDestinationCompliance() == DestinationComplianceMode.full;
FileHashcodeMap original = this.deploymentsMetadata.getCurrentDeploymentFileHashcodes();
ChangesFileHashcodeMap current = original.rescan(this.deploymentData.getDestinationDir(),
- this.deploymentData.getIgnoreRegex(), this.deploymentData.isManageRootDir());
+ this.deploymentData.getIgnoreRegex(), reportNewRootFilesAsNew);
FileHashcodeMap newFiles = getNewDeploymentFileHashcodeMap();
if (current.getUnknownContent() != null) {
diff --git a/modules/core/util/src/main/java/org/rhq/core/util/updater/DeploymentData.java b/modules/core/util/src/main/java/org/rhq/core/util/updater/DeploymentData.java
index 2431332..fee90bc 100644
--- a/modules/core/util/src/main/java/org/rhq/core/util/updater/DeploymentData.java
+++ b/modules/core/util/src/main/java/org/rhq/core/util/updater/DeploymentData.java
@@ -50,13 +50,16 @@ public class DeploymentData {
private final Set<File> rawFilesToRealize;
private final TemplateEngine templateEngine;
private final Pattern ignoreRegex;
- private final boolean manageRootDir;
private final Map<File, Boolean> zipsExploded;
/**
* Constructors that prepares this object with the data that is necessary in order to deploy archive/file content
* a destination directory.
- *
+ *
+ * Note that as of RHQ 4.9.0 the {@code manageRootDir} attribute actually writes through to the similar attribute
+ * in {@code deploymentProps}. It was previously possible for {@link #isManageRootDir()} to have different value
+ * from {@link org.rhq.core.util.updater.DeploymentProperties#getManageRootDir()} on the {@code deploymentProps}.
+ *
* @param deploymentProps metadata about this deployment
* @param zipFiles the archives containing the content to be deployed
* @param rawFiles files that are to be copied into the destination directory - the keys are the current
@@ -85,11 +88,62 @@ public class DeploymentData {
* @param zipsExploded if not <code>null</code>, this is a map keyed on zip files whose values indicate
* if the zips should be exploded (true) or remain compressed after the deployment
* is finished (false). If a zip file is not found in this map, true is the default.
+ *
+ * @deprecated The {@code manageRootDir} parameter is deprecated and this constructor should not be used. The need
+ * for that parameter was superseded by the {@link org.rhq.core.util.updater.DeploymentProperties#getDestinationCompliance()}
+ * property.
*/
+ @Deprecated
public DeploymentData(DeploymentProperties deploymentProps, Set<File> zipFiles, Map<File, File> rawFiles,
File sourceDir, File destinationDir, Map<File, Pattern> zipEntriesToRealizeRegex, Set<File> rawFilesToRealize,
TemplateEngine templateEngine, Pattern ignoreRegex, boolean manageRootDir, Map<File, Boolean> zipsExploded) {
+ this(deploymentProps, zipFiles, rawFiles, sourceDir, destinationDir, zipEntriesToRealizeRegex,
+ rawFilesToRealize,
+ templateEngine, ignoreRegex, zipsExploded);
+
+ deploymentProps.setManageRootDir(manageRootDir);
+ }
+
+ /**
+ * Constructors that prepares this object with the data that is necessary in order to deploy archive/file content
+ * a destination directory.
+ *
+ * @param deploymentProps metadata about this deployment
+ * @param zipFiles the archives containing the content to be deployed
+ * @param rawFiles files that are to be copied into the destination directory - the keys are the
+ * current
+ * locations of the files, the values are where the files should be copied (the
+ * values may be relative
+ * in which case they are relative to destDir and can have subdirectories and/or a
+ * different filename
+ * than what the file is named currently)
+ * @param destinationDir the root directory where the content is to be deployed
+ * @param sourceDir the root directory where the source files (zips and raw files) are located
+ * @param zipEntriesToRealizeRegex the patterns of files (whose paths are relative to destDir) that
+ * must have replacement variables within them replaced with values
+ * obtained via the given template engine. The key is the name of the zip file
+ * that the regex must be applied to - in other words, the regex value is only
+ * applied
+ * to relative file names as found in their associated zip file.
+ * @param rawFilesToRealize identifies the raw files that need to be realized; note that each item in this
+ * set
+ * must match a key to a <code>rawFiles</code> entry
+ * @param templateEngine if one or more filesToRealize are specified, this template engine is used to
+ * determine
+ * the values that should replace all replacement variables found in those files
+ * @param ignoreRegex the files/directories to ignore when updating an existing deployment
+ * @param zipsExploded if not <code>null</code>, this is a map keyed on zip files whose values indicate
+ * if the zips should be exploded (true) or remain compressed after the deployment
+ * is finished (false). If a zip file is not found in this map, true is the
+ * default.
+ *
+ * @since 4.9.0
+ */
+ public DeploymentData(DeploymentProperties deploymentProps, Set<File> zipFiles, Map<File, File> rawFiles,
+ File sourceDir, File destinationDir, Map<File, Pattern> zipEntriesToRealizeRegex, Set<File> rawFilesToRealize,
+ TemplateEngine templateEngine, Pattern ignoreRegex, Map<File, Boolean> zipsExploded) {
+
if (deploymentProps == null) {
throw new IllegalArgumentException("deploymentProps == null");
}
@@ -130,7 +184,6 @@ public class DeploymentData {
this.sourceDir = sourceDir;
this.ignoreRegex = ignoreRegex;
- this.manageRootDir = manageRootDir;
this.zipsExploded = zipsExploded;
// if there is nothing to realize or we have no template engine to obtain replacement values, then we null things out
@@ -157,7 +210,8 @@ public class DeploymentData {
File rawFile = entry.getValue();
String rawFilePath = rawFile.getPath();
- boolean doubledot = rawFilePath.replace('\\', '/').matches(".*((/\\.\\.)|(\\.\\./)).*"); // finds "/.." or "../" in the string
+ boolean doubledot = rawFilePath.replace('\\', '/')
+ .matches(".*((/\\.\\.)|(\\.\\./)).*"); // finds "/.." or "../" in the string
if (doubledot) {
File fileToNormalize;
@@ -171,7 +225,8 @@ public class DeploymentData {
// determine if the windows rawFile relative path specified a drive (e.g. C:foobar.txt)
StringBuilder rawFilePathBuilder = new StringBuilder(rawFilePath);
- String rawFileDriveLetter = FileUtil.stripDriveLetter(rawFilePathBuilder); // rawFilePathBuilder now has drive letter stripped
+ String rawFileDriveLetter = FileUtil
+ .stripDriveLetter(rawFilePathBuilder); // rawFilePathBuilder now has drive letter stripped
// determine what, if any, drive letter is specified in the destination directory
StringBuilder destDirAbsPathBuilder = new StringBuilder(this.destinationDir.getAbsolutePath());
@@ -197,7 +252,8 @@ public class DeploymentData {
// we can keep rawFile path relative, but we need to normalize out the ".." paths
String baseDir = this.destinationDir.getAbsolutePath();
String absRawFilePath = fileToNormalize.getAbsolutePath();
- String relativePath = absRawFilePath.substring(baseDir.length() + 1); // should always return a valid path; if not, let it throw exception (which likely means there is a bug here)
+ String relativePath = absRawFilePath.substring(baseDir.length() +
+ 1); // should always return a valid path; if not, let it throw exception (which likely means there is a bug here)
entry.setValue(new File(relativePath));
} else {
// raw file path has ".." such that the file is really above destination dir - use an absolute, canonical path
@@ -205,8 +261,6 @@ public class DeploymentData {
}
}
}
-
- return;
}
private static File getNormalizedFile(File fileToNormalize) {
@@ -249,8 +303,14 @@ public class DeploymentData {
return ignoreRegex;
}
+ /**
+ * As of RHQ 4.9.0, this calls {@link #getDeploymentProps()}.{@link DeploymentProperties#getManageRootDir() getManageRootDir()}
+ *
+ * @deprecated use {@link #getDeploymentProps()}.{@link org.rhq.core.util.updater.DeploymentProperties#getDestinationCompliance() getDestinationCompliance()}.
+ */
+ @Deprecated
public boolean isManageRootDir() {
- return manageRootDir;
+ return deploymentProps.getManageRootDir();
}
public Map<File, Boolean> getZipsExploded() {
diff --git a/modules/core/util/src/main/java/org/rhq/core/util/updater/DeploymentProperties.java b/modules/core/util/src/main/java/org/rhq/core/util/updater/DeploymentProperties.java
index 3553413..eb7aff4 100644
--- a/modules/core/util/src/main/java/org/rhq/core/util/updater/DeploymentProperties.java
+++ b/modules/core/util/src/main/java/org/rhq/core/util/updater/DeploymentProperties.java
@@ -39,8 +39,16 @@ public class DeploymentProperties extends Properties {
private static final String BUNDLE_NAME = "bundle.name";
private static final String BUNDLE_VERSION = "bundle.version";
private static final String BUNDLE_DESCRIPTION = "bundle.description";
+ //note that this really does not make sense as a generic deployment property once we support multiple deployment
+ //units in a bundle.
+ private static final String DESTINATION_COMPLIANCE = "bundle.destination.compliance";
// optional properties
+
+ /**
+ * @deprecated superseded by destination compliance
+ */
+ @Deprecated
private static final String MANAGE_ROOT_DIR = "manage.root.dir";
public static DeploymentProperties loadFromFile(File file) throws Exception {
@@ -51,6 +59,13 @@ public class DeploymentProperties extends Properties {
} finally {
is.close();
}
+
+ //Backwards compatibility handling - manageRootDir wasn't required but compliance is.. We need to make the
+ //previously valid files valid now, too, with the original behavior
+ if (props.get(DESTINATION_COMPLIANCE) == null) {
+ props.setDestinationCompliance(DestinationComplianceMode.BACKWARDS_COMPATIBLE_DEFAULT);
+ }
+
props.validate();
return props;
}
@@ -71,13 +86,32 @@ public class DeploymentProperties extends Properties {
* @param bundleName see {@link #getBundleName()}
* @param bundleVersion see {@link #getBundleVersion()}
* @param description see {@link #getDescription()}
+ *
+ * @deprecated use {@link #DeploymentProperties(int, String, String, String, DestinationComplianceMode)}.
+ * This constructor sets the compliance mode to {@link DestinationComplianceMode#full}.
*/
+ @Deprecated
public DeploymentProperties(int deploymentId, String bundleName, String bundleVersion, String description) {
- super();
+ this(deploymentId, bundleName, bundleVersion, description, DestinationComplianceMode.full);
+ }
+
+ /**
+ * Convenience constructor whose parameters are all the required values that
+ * this object needs.
+ *
+ * @param deploymentId see {@link #getDeploymentId()}
+ * @param bundleName see {@link #getBundleName()}
+ * @param bundleVersion see {@link #getBundleVersion()}
+ * @param description see {@link #getDescription()}
+ * @param destinationCompliance see {@link #getDestinationCompliance()}
+ */
+ public DeploymentProperties(int deploymentId, String bundleName, String bundleVersion, String description, DestinationComplianceMode destinationCompliance) {
setDeploymentId(deploymentId);
setBundleName(bundleName);
setBundleVersion(bundleVersion);
setDescription(description);
+ setDestinationCompliance(destinationCompliance);
+
try {
validate();
} catch (Exception e) {
@@ -119,6 +153,7 @@ public class DeploymentProperties extends Properties {
getBundleName();
getBundleVersion();
getDescription();
+ getDestinationCompliance();
} catch (Exception e) {
throw new Exception("Deployment properties are invalid: " + e.getMessage());
}
@@ -196,18 +231,76 @@ public class DeploymentProperties extends Properties {
}
/**
+ * Note that as of RHQ 4.9.0, this attribute is deprecated.
+ * There is an attempt made to handle reading the old version of the attribute:
+ * <ol>
+ * <li>if "bundle.destination.compliance" attribute is set, base the value on it. If the compliance is "full"
+ * this method returns true, otherwise it returns false.</li>
+ * <li>if "manage.root.dir" attribute is set, base the return value on it (this handles the previous
+ * behavior).</li>
+ * <li>if none of the above attributes is set, return the default value of the deprecated manageRootDir attribute,
+ * which is true.</li>
+ * </ol>
+ *
* @return the flag to indicate if the entire root directory content is to be managed.
* If there is no property, this method returns a default of <code>true</code>
+ *
+ * @deprecated use {@link #getDestinationCompliance()}
*/
+ @Deprecated
public boolean getManageRootDir() {
- String str = getProperty(MANAGE_ROOT_DIR);
- if (str == null) {
- return true;
+ DestinationComplianceMode mode = getDestinationComplianceNoException();
+ if (mode == null) {
+ String str = getProperty(MANAGE_ROOT_DIR);
+ if (str == null) {
+ return true;
+ }
+ return Boolean.parseBoolean(str);
}
- return Boolean.parseBoolean(str);
+
+ return mode == DestinationComplianceMode.full;
}
+ /**
+ * As of RHQ 4.9.0, this is equivalent to {@link #setDestinationCompliance(DestinationComplianceMode)
+ * setDestinationCompliance(willManageRootDir ? DestinationComplianceMode.full :
+ * DestinationComplianceMode.filesAndDirectories)}.
+ *
+ * @param willManageRootDir whether to manage the root directory
+ *
+ * @deprecated use {@link #setDestinationCompliance(DestinationComplianceMode)} instead
+ */
+ @Deprecated
public void setManageRootDir(boolean willManageRootDir) {
- setProperty(MANAGE_ROOT_DIR, Boolean.toString(willManageRootDir));
+ setDestinationCompliance(
+ willManageRootDir ? DestinationComplianceMode.full : DestinationComplianceMode.filesAndDirectories);
+ }
+
+ /**
+ * Returns the compliance mode of the destination. This is a required attribute.
+ *
+ * @since 4.9.0
+ */
+ public DestinationComplianceMode getDestinationCompliance() {
+ DestinationComplianceMode mode = getDestinationComplianceNoException();
+ if (mode == null) {
+ throw new IllegalStateException("Destination compliance not specified");
+ }
+
+ return mode;
+ }
+
+ public void setDestinationCompliance(DestinationComplianceMode compliance) {
+ String str = compliance == null ? null : compliance.name();
+ setProperty(DESTINATION_COMPLIANCE, str);
+ }
+
+ private DestinationComplianceMode getDestinationComplianceNoException() {
+ String str = getProperty(DESTINATION_COMPLIANCE);
+ if (str == null) {
+ return null;
+ }
+
+ return Enum.valueOf(DestinationComplianceMode.class, str);
}
}
diff --git a/modules/core/util/src/main/java/org/rhq/core/util/updater/DestinationComplianceMode.java b/modules/core/util/src/main/java/org/rhq/core/util/updater/DestinationComplianceMode.java
new file mode 100644
index 0000000..8ddc7d8
--- /dev/null
+++ b/modules/core/util/src/main/java/org/rhq/core/util/updater/DestinationComplianceMode.java
@@ -0,0 +1,87 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2013 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.core.util.updater;
+
+/**
+ * Lists the compliance modes of the bundle deployment destinations. See the comments at the individual enum elements
+ * to see what they mean.
+ *
+ * @author Lukas Krejci
+ * @since 4.9
+ */
+public enum DestinationComplianceMode {
+ //NOTE: the below violation of our coding guidelines is because of ANT's requirement for direct usage of enum's
+ //constant names in the build files. Because this enum is used generally in all bundle handlers we need to ensure
+ //it works for all of them. For readability reasons in ANT bundle recipes, I opted for breaking our guidelines here
+ //instead of creating some kind of 'bridge' ant-specific enum.
+
+ /**
+ * The full compliance means that the deployment destination is completely wiped before the bundle contents are
+ * deployed into it. In another words the destination contains no other files than those contained in the bundle
+ * and
+ * is therefore in full compliance with the bundle.
+ */
+ full,
+
+ /**
+ * This compliance mode makes sure that files and directories that are NOT contained in the bundle are kept in the
+ * destination directory. However the contents of files <b>and directories</b> that ARE present in the bundle are
+ * made completely compliant with the bundle.
+ */
+ filesAndDirectories
+
+ //NOTE: the below two modes are going to be supported in the future, but NOT as of RHQ 4.9.0 */
+
+ /**
+ * This compliance mode means that the root directory of the deployment will only contain files and directories from
+ * the bundle. The content of the directories is not required to be compliant with the bundle - i.e. the directories
+ * and files "under" some directory, that already existed in the deployment, are kept.
+ */
+ //, rootDirectoryAndFiles
+
+ /**
+ * This compliance mode means that all files from a bundle is copied into the deployment (preserving directory
+ * structure) (i.e. such files are compliant with the bundle). All other contents of the deployment directory is
+ * kept intact (i.e. this is the RPM-like behavior).
+ */
+ //, files
+
+ ;
+
+ /**
+ * This is the default compliance mode to be used in the legacy bundle recipes which do not explicitly set neither
+ * the compliance nor the legacy {@code manageRootDir} attribute.
+ */
+ public static final DestinationComplianceMode BACKWARDS_COMPATIBLE_DEFAULT = full;
+
+ /**
+ * Use this method to get either the supplied compliance mode or the {@link #BACKWARDS_COMPATIBLE_DEFAULT default}
+ * compliance.
+ * <p/>
+ * Only use this method if you need to handle the legacy recipes.
+ *
+ * @param compliance the compliance to return or null if not known
+ *
+ * @return the supplied {@code compliance} or the default compliance mode, never null.
+ */
+ public static DestinationComplianceMode instanceOrDefault(DestinationComplianceMode compliance) {
+ return compliance == null ? BACKWARDS_COMPATIBLE_DEFAULT : compliance;
+ }
+}
diff --git a/modules/core/util/src/test/java/org/rhq/core/util/updater/DeploymentPropertiesTest.java b/modules/core/util/src/test/java/org/rhq/core/util/updater/DeploymentPropertiesTest.java
index dcdac65..e72bf23 100644
--- a/modules/core/util/src/test/java/org/rhq/core/util/updater/DeploymentPropertiesTest.java
+++ b/modules/core/util/src/test/java/org/rhq/core/util/updater/DeploymentPropertiesTest.java
@@ -34,6 +34,8 @@ public class DeploymentPropertiesTest {
props.setBundleName("test-bundle-name");
props.setBundleVersion("1.0");
props.setDescription("This is a description\nof a bundle");
+ props.setDestinationCompliance(DestinationComplianceMode.full);
+
File tmpFile = File.createTempFile("deploymentPropertiesTest", ".properties");
try {
props.saveToFile(tmpFile);
@@ -83,6 +85,13 @@ public class DeploymentPropertiesTest {
// this is expected and ok
}
+ try {
+ props.setDestinationCompliance(null);
+ assert false : "Should have thrown an exception due to null value";
+ } catch (Exception ok) {
+ // this is expected and ok
+ }
+
File tmpFile = File.createTempFile("deploymentPropertiesTest", ".properties");
try {
try {
@@ -109,6 +118,14 @@ public class DeploymentPropertiesTest {
}
props.setBundleVersion("1");
+ try {
+ props.saveToFile(tmpFile);
+ assert false : "Should have thrown an exception since it was not valid";
+ } catch (Exception ok) {
+ // this is expected and ok
+ }
+
+ props.setDestinationCompliance(DestinationComplianceMode.filesAndDirectories);
// we set all properties we need, it should be valid and we should be able to save it now
props.saveToFile(tmpFile);
diff --git a/modules/core/util/src/test/java/org/rhq/core/util/updater/DeploymentsMetadataTest.java b/modules/core/util/src/test/java/org/rhq/core/util/updater/DeploymentsMetadataTest.java
index 6145837..7fc23b8 100644
--- a/modules/core/util/src/test/java/org/rhq/core/util/updater/DeploymentsMetadataTest.java
+++ b/modules/core/util/src/test/java/org/rhq/core/util/updater/DeploymentsMetadataTest.java
@@ -45,6 +45,7 @@ public class DeploymentsMetadataTest {
deploymentProps.setBundleName("test-bundle-name");
deploymentProps.setBundleVersion("1.0");
deploymentProps.setDescription("test bundle description");
+ deploymentProps.setDestinationCompliance(DestinationComplianceMode.full);
FileHashcodeMap map = metadata.snapshotLiveDeployment(deploymentProps, null, null);
assert metadata.isManaged() : "this should be managed now : " + metadata;
assert map.size() == 5 : map; // there are 5 files in our test bundle zip
diff --git a/modules/core/util/src/test/java/org/rhq/core/util/updater/ManageRootDirTest.java b/modules/core/util/src/test/java/org/rhq/core/util/updater/ManageRootDirTest.java
index 4ef558b..1e7bbce 100644
--- a/modules/core/util/src/test/java/org/rhq/core/util/updater/ManageRootDirTest.java
+++ b/modules/core/util/src/test/java/org/rhq/core/util/updater/ManageRootDirTest.java
@@ -107,7 +107,7 @@ public class ManageRootDirTest {
this.originalFileHashcodeMap = deployer.deploy(null);
this.currentFile = new File(deployDir, originalFileName);
- this.newDeployProps = new DeploymentProperties(2, "simple", "2.0", "new test deployment");
+ this.newDeployProps = new DeploymentProperties(2, "simple", "2.0", "new test deployment", DestinationComplianceMode.filesAndDirectories);
this.diff = new DeployDifferences();
this.metadata = new DeploymentsMetadata(this.deployDir);
@@ -252,7 +252,7 @@ public class ManageRootDirTest {
assert unrelated2.exists() : "the deployment removed unrelated file2";
// deploy new content
- this.newDeployProps = new DeploymentProperties(2, "simple", "2.0", "new test deployment");
+ this.newDeployProps = new DeploymentProperties(2, "simple", "2.0", "new test deployment", DestinationComplianceMode.filesAndDirectories);
this.diff = new DeployDifferences();
this.metadata = new DeploymentsMetadata(this.deployDir);
String newFileName1 = "new-file1.txt";
diff --git a/modules/enterprise/server/itests-2/pom.xml b/modules/enterprise/server/itests-2/pom.xml
index a3e9c7b..63eb166 100644
--- a/modules/enterprise/server/itests-2/pom.xml
+++ b/modules/enterprise/server/itests-2/pom.xml
@@ -21,10 +21,11 @@
</scm>
<properties>
+ <rhq.ant-bundle.serverplugin.path>${settings.localRepository}/org/rhq/rhq-serverplugin-ant-bundle/${project.version}/rhq-serverplugin-ant-bundle-${project.version}.jar</rhq.ant-bundle.serverplugin.path>
<jboss.zip>${settings.localRepository}/org/jboss/as/jboss-as-dist/${jboss.version}/jboss-as-dist-${jboss.version}.zip</jboss.zip>
<jboss.unzip.location>${basedir}/target/${jboss.eap.version}</jboss.unzip.location>
<jboss.vm.args>-Xmx700m -XX:MaxPermSize=200m -Djava.security.manager
- -Djava.security.policy==${jboss.unzip.location}/security.policy</jboss.vm.args>
+ -Djava.security.policy==${jboss.unzip.location}/security.policy -Drhq.ant-bundle.serverplugin.path=${rhq.ant-bundle.serverplugin.path}</jboss.vm.args>
<jboss.vm.args.debug></jboss.vm.args.debug> <!-- -Ditest.debug can override this, see below -->
<!-- These properties guide which datasources are used for integration tests. Only one should be true. The default is
Postgres, specify -Pitest.oracle to use Oracle -->
@@ -604,6 +605,13 @@
<!-- Note, the test dep ordering can be important. Maven orders the [test] classpath in the order listed in the pom. -->
<dependency>
+ <groupId>org.rhq</groupId>
+ <artifactId>rhq-serverplugin-ant-bundle</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
<groupId>org.jboss.as</groupId>
<artifactId>jboss-as-dist</artifactId>
<type>zip</type>
diff --git a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/bundle/BundleManagerBeanTest.java b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/bundle/BundleManagerBeanTest.java
index 2085a4d..cfb5cc1 100644
--- a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/bundle/BundleManagerBeanTest.java
+++ b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/bundle/BundleManagerBeanTest.java
@@ -120,6 +120,7 @@ public class BundleManagerBeanTest extends AbstractEJB3Test {
private static final boolean DISABLED = false;
private TestBundleServerPluginService ps;
+ private TestBundlePluginComponent bpc;
private MasterServerPluginContainer pc;
private Subject overlord;
TestServerCommunicationsService agentServiceContainer;
@@ -129,7 +130,8 @@ public class BundleManagerBeanTest extends AbstractEJB3Test {
agentServiceContainer = prepareForTestAgents();
agentServiceContainer.bundleService = new TestAgentClient(null, agentServiceContainer);
- this.ps = new TestBundleServerPluginService(getTempDir());
+ this.bpc = new TestBundlePluginComponent();
+ this.ps = new TestBundleServerPluginService(getTempDir(), bpc);
prepareCustomServerPluginService(this.ps);
bundleManager = LookupUtil.getBundleManager();
resourceManager = LookupUtil.getResourceManager();
@@ -368,11 +370,11 @@ public class BundleManagerBeanTest extends AbstractEJB3Test {
BundleType bt1 = createBundleType("one");
// prepare our mock bundle PC
- ps.parseRecipe_returnValue = new RecipeParseResults(bundleMetadata, configDef, new HashSet<String>(
+ bpc.parseRecipe_returnValue = new RecipeParseResults(bundleMetadata, configDef, new HashSet<String>(
bundleFiles.keySet()));
- ps.processBundleDistributionFile_returnValue = new BundleDistributionInfo(recipe,
- ps.parseRecipe_returnValue, bundleFiles);
- ps.processBundleDistributionFile_returnValue.setBundleTypeName(bt1.getName());
+ bpc.processBundleDistributionFile_returnValue = new BundleDistributionInfo(recipe,
+ bpc.parseRecipe_returnValue, bundleFiles);
+ bpc.processBundleDistributionFile_returnValue.setBundleTypeName(bt1.getName());
// now ask the SLSB to persist our bundle data given our mock distribution
BundleVersion bv1 = bundleManager.createBundleVersionViaURL(overlord, bundleDistroFile.toURI().toURL()
diff --git a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/bundle/TestBundlePluginComponent.java b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/bundle/TestBundlePluginComponent.java
new file mode 100644
index 0000000..269ee73
--- /dev/null
+++ b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/bundle/TestBundlePluginComponent.java
@@ -0,0 +1,84 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2013 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.enterprise.server.bundle;
+
+import java.io.File;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.rhq.core.domain.configuration.definition.ConfigurationDefinition;
+import org.rhq.core.domain.configuration.definition.PropertyDefinitionSimple;
+import org.rhq.core.domain.configuration.definition.PropertySimpleType;
+import org.rhq.core.util.updater.DeploymentProperties;
+import org.rhq.enterprise.server.plugin.pc.bundle.BundleServerPluginFacet;
+import org.rhq.enterprise.server.plugin.pc.bundle.UnknownRecipeException;
+import org.rhq.enterprise.server.test.AbstractEJB3Test;
+
+/**
+ * @author Lukas Krejci
+ */
+public class TestBundlePluginComponent implements BundleServerPluginFacet {
+ public RecipeParseResults parseRecipe_returnValue;
+ public BundleDistributionInfo processBundleDistributionFile_returnValue;
+
+ @Override
+ public RecipeParseResults parseRecipe(String recipe) throws UnknownRecipeException, Exception {
+
+ if (parseRecipe_returnValue != null) {
+ return parseRecipe_returnValue;
+ }
+
+ return doParseRecipe(recipe);
+ }
+
+ protected RecipeParseResults doParseRecipe(String recipe) throws UnknownRecipeException, Exception {
+
+ ConfigurationDefinition configDef;
+ Set<String> bundleFileNames;
+ DeploymentProperties metadata;
+
+ metadata = new DeploymentProperties(0, "bundletest", "1.0", "bundle test description");
+
+ configDef = new ConfigurationDefinition("bundletest-configdef", "Test Config Def for testing BundleVersion");
+ configDef.put(new PropertyDefinitionSimple("bundletest.property",
+ "Test property for BundleVersion Config Def testing", true, PropertySimpleType.STRING));
+
+ bundleFileNames = new HashSet<String>();
+ for (int i = 0; i < AbstractEJB3Test.DEFAULT_CRITERIA_PAGE_SIZE + 2; i++) {
+ bundleFileNames.add("bundletest-bundlefile-" + i);
+ }
+
+ return new RecipeParseResults(metadata, configDef, bundleFileNames);
+ }
+
+ @Override
+ public BundleDistributionInfo processBundleDistributionFile(File distributionFile)
+ throws UnknownRecipeException, Exception {
+ if (processBundleDistributionFile_returnValue != null) {
+ return processBundleDistributionFile_returnValue;
+ }
+
+ return doProcessBundleDistributionFile(distributionFile);
+ }
+
+ protected BundleDistributionInfo doProcessBundleDistributionFile(File distributionFile) {
+ throw new UnsupportedOperationException("this mock object cannot do this");
+ }
+}
diff --git a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/bundle/TestBundleServerPluginService.java b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/bundle/TestBundleServerPluginService.java
index 7c95cb5..3bfc8c4 100644
--- a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/bundle/TestBundleServerPluginService.java
+++ b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/bundle/TestBundleServerPluginService.java
@@ -64,12 +64,12 @@ public class TestBundleServerPluginService extends ServerPluginService implement
public TestBundleServerPluginContainer bundlePC;
public MasterServerPluginContainerConfiguration masterConfig;
- public RecipeParseResults parseRecipe_returnValue = null;
- public BundleDistributionInfo processBundleDistributionFile_returnValue;
+ private BundleServerPluginFacet bundlePlugin;
- public TestBundleServerPluginService(File tmpdir) {
+ public TestBundleServerPluginService(File tmpdir, BundleServerPluginFacet bundlePlugin) {
// build the config at constructor time so tests have it even before the PC is initialized
this.masterConfig = new MasterServerPluginContainerConfiguration(tmpdir, tmpdir, tmpdir, null);
+ this.bundlePlugin = bundlePlugin;
}
@Override
@@ -196,50 +196,12 @@ public class TestBundleServerPluginService extends ServerPluginService implement
@Override
public RecipeParseResults parseRecipe(String bundleTypeName, String recipe) throws Exception {
- return new TestBundlePluginComponent().parseRecipe(recipe);
+ return bundlePlugin.parseRecipe(recipe);
}
@Override
public BundleDistributionInfo processBundleDistributionFile(File distributionFile) throws Exception {
- return new TestBundlePluginComponent().processBundleDistributionFile(distributionFile);
+ return bundlePlugin.processBundleDistributionFile(distributionFile);
}
}
-
- class TestBundlePluginComponent implements BundleServerPluginFacet {
-
- public TestBundlePluginComponent() {
- };
-
- public RecipeParseResults parseRecipe(String recipe) throws Exception {
-
- if (parseRecipe_returnValue != null) {
- return parseRecipe_returnValue;
- }
-
- ConfigurationDefinition configDef;
- Set<String> bundleFileNames;
- DeploymentProperties metadata;
-
- metadata = new DeploymentProperties(0, "bundletest", "1.0", "bundle test description");
-
- configDef = new ConfigurationDefinition("bundletest-configdef", "Test Config Def for testing BundleVersion");
- configDef.put(new PropertyDefinitionSimple("bundletest.property",
- "Test property for BundleVersion Config Def testing", true, PropertySimpleType.STRING));
-
- bundleFileNames = new HashSet<String>();
- for (int i = 0; i < AbstractEJB3Test.DEFAULT_CRITERIA_PAGE_SIZE + 2; i++) {
- bundleFileNames.add("bundletest-bundlefile-" + i);
- }
-
- return new RecipeParseResults(metadata, configDef, bundleFileNames);
- }
-
- public BundleDistributionInfo processBundleDistributionFile(File uberBundleFile) throws Exception {
- if (processBundleDistributionFile_returnValue != null) {
- return processBundleDistributionFile_returnValue;
- }
-
- throw new UnsupportedOperationException("this mock object cannot do this");
- }
- }
-}
\ No newline at end of file
+}
diff --git a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/plugins/ant/RecipeValidationTest.java b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/plugins/ant/RecipeValidationTest.java
new file mode 100644
index 0000000..502ab03
--- /dev/null
+++ b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/plugins/ant/RecipeValidationTest.java
@@ -0,0 +1,292 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2013 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.enterprise.server.plugins.ant;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URISyntaxException;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+import javax.persistence.Query;
+import javax.transaction.TransactionManager;
+
+import org.testng.annotations.Test;
+
+import org.rhq.core.domain.auth.Subject;
+import org.rhq.core.domain.bundle.BundleType;
+import org.rhq.core.domain.resource.ResourceCategory;
+import org.rhq.core.domain.resource.ResourceType;
+import org.rhq.core.util.file.FileUtil;
+import org.rhq.core.util.stream.StreamUtil;
+import org.rhq.enterprise.server.bundle.BundleManagerLocal;
+import org.rhq.enterprise.server.core.CoreServer;
+import org.rhq.enterprise.server.core.CoreServerMBean;
+import org.rhq.enterprise.server.core.plugin.PluginDeploymentScanner;
+import org.rhq.enterprise.server.core.plugin.PluginDeploymentScannerMBean;
+import org.rhq.enterprise.server.plugin.pc.MasterServerPluginContainer;
+import org.rhq.enterprise.server.plugin.pc.ServerPluginService;
+import org.rhq.enterprise.server.test.AbstractEJB3Test;
+import org.rhq.enterprise.server.test.TestAgentClient;
+import org.rhq.enterprise.server.test.TestServerCommunicationsService;
+import org.rhq.enterprise.server.util.LookupUtil;
+
+/**
+ * @author Lukas Krejci
+ */
+public class RecipeValidationTest extends AbstractEJB3Test {
+
+ public static final String ITESTS = "itests";
+ private static final String ENTITY_NAME_PREFIX = "recipeValidationTest";
+ private static final String FAKE_RESOURCE_TYPE_NAME = "recipeValidationTest-antbundle-resourcetype";
+ private static final String ANT_BUNDLE_TYPE_NAME = "Ant Bundle";
+
+ private TestServerCommunicationsService agentServiceContainer;
+ private MasterServerPluginContainer pc;
+ private ServerPluginService ps;
+ private BundleManagerLocal bundleManager;
+ private File serverPluginsDir;
+
+ @Override
+ protected void beforeMethod() throws Exception {
+ // try and clean up any junk that may be lying around from a failed run
+ cleanupDatabase();
+
+ bundleManager = LookupUtil.getBundleManager();
+ createAntBundleType();
+
+ prepareCustomServerService(new CoreServer(), CoreServerMBean.OBJECT_NAME);
+ prepareCustomServerService(new PluginDeploymentScanner(), PluginDeploymentScannerMBean.OBJECT_NAME);
+
+ prepareCustomServerPluginService(new ServerPluginService());
+
+ agentServiceContainer = prepareForTestAgents();
+ agentServiceContainer.bundleService = new TestAgentClient(null, agentServiceContainer);
+
+ ps = new ServerPluginService();
+ serverPluginsDir = ps.getServerPluginsDirectory();
+ serverPluginsDir.mkdirs();
+ File agentPluginsDir = new File(serverPluginsDir.getParentFile(), "agentplugins");
+ agentPluginsDir.mkdirs();
+
+ File antBundlePlugin = new File(System.getProperty("rhq.ant-bundle.serverplugin.path"));
+
+ PluginDeploymentScannerMBean scanner = LookupUtil.getPluginDeploymentScanner();
+
+ //needed by server plugin lifecycle
+ prepareScheduler();
+
+ File targetFile = new File(serverPluginsDir, antBundlePlugin.getName());
+ //touch the file so that the plugin scanner picks it up again
+ targetFile.setLastModified(System.currentTimeMillis());
+
+ FileUtil.copyFile(antBundlePlugin, targetFile);
+
+ scanner.setAgentPluginDir(agentPluginsDir.getAbsolutePath());
+ scanner.setServerPluginDir(serverPluginsDir.getAbsolutePath());
+
+ //actually, this is resetting the plugin service to the real thing, because we need to deploy the
+ //real ant bundle server plugin
+ prepareCustomServerPluginService(ps);
+// resourceManager = LookupUtil.getResourceManager();
+// overlord = c
+ ps.startMasterPluginContainer();
+
+ LookupUtil.getPluginDeploymentScanner().startDeployment();
+ LookupUtil.getPluginDeploymentScanner().scanAndRegister();
+ }
+
+ @Override
+ protected void afterMethod() throws Exception {
+ FileUtil.purge(serverPluginsDir.getParentFile(), true);
+
+ unprepareForTestAgents();
+ unprepareScheduler();
+
+ try {
+ cleanupDatabase();
+ } finally {
+ unprepareServerPluginService();
+ unprepareCustomServerService(CoreServerMBean.OBJECT_NAME);
+ unprepareCustomServerService(PluginDeploymentScannerMBean.OBJECT_NAME);
+ }
+ }
+
+ private void cleanupDatabase() throws Exception {
+ try {
+ getTransactionManager().begin();
+
+ Query q;
+ List<?> doomed;
+
+ // remove ResourceTypes which cascade remove BundleTypes
+ q = em.createQuery("SELECT rt FROM ResourceType rt WHERE rt.deleted = false and rt.name = '"
+ + FAKE_RESOURCE_TYPE_NAME + "'");
+ doomed = q.getResultList();
+ for (Object removeMe : doomed) {
+ em.remove(em.getReference(ResourceType.class, ((ResourceType) removeMe).getId()));
+ }
+ em.flush();
+ // remove any orphaned BundleTypes
+ q = em.createQuery("SELECT bt FROM BundleType bt WHERE bt.name = '" + ANT_BUNDLE_TYPE_NAME + "'");
+ doomed = q.getResultList();
+ for (Object removeMe : doomed) {
+ em.remove(em.getReference(BundleType.class, ((BundleType) removeMe).getId()));
+ }
+ getTransactionManager().commit();
+ } catch (Exception e) {
+ try {
+ System.out.println("CANNOT CLEAN UP TEST: Cause: " + e);
+ getTransactionManager().rollback();
+ } catch (Exception ignore) {
+ }
+ }
+ }
+
+ @Test(groups = RecipeValidationTest.ITESTS)
+ public void testManageRootDirMandatoryOnBundleVersionCreation() throws Exception {
+ File root = FileUtil.createTempDirectory(getClass().getName(), null, null);
+ copyFromClasspath("recipe-no-manageRootDir.xml", "deploy.xml", root);
+
+ File bundleZip = createDistributionZip(root);
+
+ try {
+ bundleManager.createBundleVersionViaURL(getFreshOverlord(), bundleZip.toURI().toURL().toString());
+ fail("A recipe without explicit managerRootDir should not have been created");
+ } catch (Exception e) {
+ //expected
+ checkForExpectedException(e, "org.rhq.bundle.ant.InvalidBuildFileException", "The deployment unit must specifically declare compliance mode of the destination directory.");
+ } finally {
+ FileUtil.purge(root, true);
+ }
+ }
+
+ @Test(groups = RecipeValidationTest.ITESTS)
+ public void testManageRootDirAbsenceToleratedDuringUpdate() {
+ // TODO does this even make sense?
+ }
+
+ @Test(groups = RecipeValidationTest.ITESTS)
+ public void testManageRootDirAbsenceToleratedDuringRevert() {
+ // TODO implement
+ }
+
+ private Subject getFreshOverlord() {
+ return LookupUtil.getSubjectManager().getOverlord();
+ }
+
+ private File createDistributionZip(File root) throws IOException {
+ File ret = File.createTempFile(getClass().getName(),
+ "zip");
+ ZipOutputStream distribFile = new ZipOutputStream(new FileOutputStream(ret));
+
+ for (File f : getAllFilesRelativeToRoot(root, root)) {
+ distribFile.putNextEntry(new ZipEntry(f.getPath()));
+
+ File resultFile = new File(root, f.getPath());
+
+ FileInputStream in = new FileInputStream(resultFile);
+
+ try {
+ StreamUtil.copy(in, distribFile, false);
+ } finally {
+ in.close();
+ }
+
+ distribFile.closeEntry();
+ }
+
+ distribFile.close();
+
+ return ret;
+ }
+
+ private static Set<File> getAllFilesRelativeToRoot(File parent, File root) {
+ HashSet<File> ret = new HashSet<File>();
+ getAllFilesRelativeToRoot(parent, root, ret);
+ return ret;
+ }
+
+ private static void getAllFilesRelativeToRoot(File parent, File root, Set<File> out) {
+ for (File f : parent.listFiles()) {
+ if (f.isDirectory()) {
+ getAllFilesRelativeToRoot(f, root, out);
+ } else {
+ //getRelativePath always prefixes the path with './'. We don't need that.
+ String path = FileUtil.getRelativePath(f, root).substring(2);
+ out.add(new File(path));
+ }
+ }
+ }
+
+ private void copyFromClasspath(String resourceUrl, String filename, File target)
+ throws FileNotFoundException, URISyntaxException {
+ target.getParentFile().mkdirs();
+ InputStream content = getClass().getResourceAsStream(resourceUrl);
+
+ FileOutputStream out = new FileOutputStream(new File(target, filename));
+
+ StreamUtil.copy(content, out, true);
+ }
+
+ private void createAntBundleType() throws Exception {
+ ResourceType rt = createResourceTypeForBundleType();
+ Subject overlord = LookupUtil.getSubjectManager().getOverlord();
+ BundleType bt = bundleManager.createBundleType(overlord, ANT_BUNDLE_TYPE_NAME, rt.getId());
+
+ assert bt.getId() > 0;
+ }
+
+ private ResourceType createResourceTypeForBundleType() throws Exception {
+ final String fullName = FAKE_RESOURCE_TYPE_NAME;
+ ResourceType rt = new ResourceType(fullName, RecipeValidationTest.class.getSimpleName(),
+ ResourceCategory.PLATFORM, null);
+
+ TransactionManager txMgr = getTransactionManager();
+ txMgr.begin();
+ em.persist(rt);
+ txMgr.commit();
+ return rt;
+ }
+
+ private void checkForExpectedException(Throwable t, String expectedExceptionClassName,
+ String expectedMessage) {
+ Throwable test = t;
+ do {
+ if (expectedExceptionClassName.equals(test.getClass().getName()) &&
+ (expectedMessage == null || expectedMessage.equals(test.getMessage()))) {
+ return;
+ }
+
+ test = test.getCause();
+ } while (test != null);
+
+ fail("Exception " + expectedExceptionClassName +
+ (expectedMessage == null ? "" : " with message [" + expectedMessage + "]") +
+ " not detected in the thrown exception " + t);
+ }
+}
diff --git a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/resource/metadata/MetadataBeanTest.java b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/resource/metadata/MetadataBeanTest.java
index 1664c9f..a0b6620 100644
--- a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/resource/metadata/MetadataBeanTest.java
+++ b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/resource/metadata/MetadataBeanTest.java
@@ -38,6 +38,7 @@ import org.rhq.core.domain.resource.ResourceType;
import org.rhq.core.util.MessageDigestGenerator;
import org.rhq.core.util.stream.StreamUtil;
import org.rhq.enterprise.server.auth.SubjectManagerLocal;
+import org.rhq.enterprise.server.bundle.TestBundlePluginComponent;
import org.rhq.enterprise.server.bundle.TestBundleServerPluginService;
import org.rhq.enterprise.server.resource.ResourceTypeManagerLocal;
import org.rhq.enterprise.server.scheduler.jobs.PurgePluginsJob;
@@ -79,7 +80,7 @@ public class MetadataBeanTest extends AbstractEJB3Test {
setupDB();
- TestBundleServerPluginService bundleService = new TestBundleServerPluginService(getTempDir());
+ TestBundleServerPluginService bundleService = new TestBundleServerPluginService(getTempDir(), new TestBundlePluginComponent());
prepareCustomServerPluginService(bundleService);
bundleService.startMasterPluginContainerWithoutSchedulingJobs();
prepareScheduler();
diff --git a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/tagging/TagManagerBeanTest.java b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/tagging/TagManagerBeanTest.java
index bef8921..01c58a0 100644
--- a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/tagging/TagManagerBeanTest.java
+++ b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/tagging/TagManagerBeanTest.java
@@ -45,6 +45,7 @@ import org.rhq.core.domain.tagging.Tag;
import org.rhq.core.domain.util.PageList;
import org.rhq.enterprise.server.auth.SubjectManagerLocal;
import org.rhq.enterprise.server.bundle.BundleManagerLocal;
+import org.rhq.enterprise.server.bundle.TestBundlePluginComponent;
import org.rhq.enterprise.server.bundle.TestBundleServerPluginService;
import org.rhq.enterprise.server.test.AbstractEJB3Test;
import org.rhq.enterprise.server.test.TransactionCallback;
@@ -75,7 +76,7 @@ public class TagManagerBeanTest extends AbstractEJB3Test {
SubjectManagerLocal subjectManager = LookupUtil.getSubjectManager();
bundleManager = LookupUtil.getBundleManager();
overlord = subjectManager.getOverlord();
- TestBundleServerPluginService bundleServerPluginService = new TestBundleServerPluginService(getTempDir());
+ TestBundleServerPluginService bundleServerPluginService = new TestBundleServerPluginService(getTempDir(), new TestBundlePluginComponent());
prepareCustomServerPluginService(bundleServerPluginService);
bundleServerPluginService.startMasterPluginContainer();
}
diff --git a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/test/AbstractEJB3Test.java b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/test/AbstractEJB3Test.java
index af01136..d13fddb 100644
--- a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/test/AbstractEJB3Test.java
+++ b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/test/AbstractEJB3Test.java
@@ -40,6 +40,7 @@ import java.util.regex.Pattern;
import javax.ejb.EJB;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
+import javax.management.ObjectInstance;
import javax.management.ObjectName;
import javax.naming.Context;
import javax.naming.InitialContext;
@@ -330,6 +331,8 @@ public abstract class AbstractEJB3Test extends Arquillian {
testClassesJar.addAsResource("test/metadata/resource-type/updateResourceTypeBundleTarget-v1.xml");
testClassesJar.addAsResource("test/metadata/resource-type/updateResourceTypeBundleTarget-v2.xml");
+ testClassesJar.addAsResource("org/rhq/enterprise/server/plugins/ant/recipe-no-manageRootDir.xml");
+
// create test ear by starting with rhq.ear and thinning it
String projectVersion = System.getProperty("project.version");
MavenResolverSystem earResolver = Resolvers.use(MavenResolverSystem.class);
diff --git a/modules/enterprise/server/itests-2/src/test/resources/org/rhq/enterprise/server/plugins/ant/recipe-no-manageRootDir.xml b/modules/enterprise/server/itests-2/src/test/resources/org/rhq/enterprise/server/plugins/ant/recipe-no-manageRootDir.xml
new file mode 100644
index 0000000..5fb564c
--- /dev/null
+++ b/modules/enterprise/server/itests-2/src/test/resources/org/rhq/enterprise/server/plugins/ant/recipe-no-manageRootDir.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0"?>
+<!--
+ ~ RHQ Management Platform
+ ~ Copyright (C) 2013 Red Hat, Inc.
+ ~ All rights reserved.
+ ~
+ ~ This program is free software; you can redistribute it and/or modify
+ ~ it under the terms of the GNU General Public License as published by
+ ~ the Free Software Foundation version 2 of the License.
+ ~
+ ~ This program is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ~ GNU General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU General Public License
+ ~ along with this program; if not, write to the Free Software
+ ~ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ -->
+
+<project name="simple-build" default="main"
+ xmlns:rhq="antlib:org.rhq.bundle">
+
+ <rhq:bundle name="testNoManageRootDirBundle" version="1.0">
+ <rhq:deployment-unit name="simulated-war">
+ <rhq:file name="zero.properties" destinationFile="zero.properties"/>
+ <rhq:file name="one.properties" destinationFile="subdir1/one.properties"/>
+ <rhq:file name="two.properties" destinationFile="subdir2/two.properties"/>
+ </rhq:deployment-unit>
+ </rhq:bundle>
+
+ <target name="main"/>
+
+</project>
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CoreServerMBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CoreServerMBean.java
index 6396f6e..fc112ea 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CoreServerMBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CoreServerMBean.java
@@ -98,4 +98,4 @@ public interface CoreServerMBean {
* @return product information - the product name, homepage URL, docs URL, etc.
*/
ProductInfo getProductInfo();
-}
\ No newline at end of file
+}
diff --git a/modules/enterprise/server/plugins/ant-bundle/src/main/java/org/rhq/enterprise/server/plugins/ant/AntBundleServerPluginComponent.java b/modules/enterprise/server/plugins/ant-bundle/src/main/java/org/rhq/enterprise/server/plugins/ant/AntBundleServerPluginComponent.java
index 82354b6..be72042 100644
--- a/modules/enterprise/server/plugins/ant-bundle/src/main/java/org/rhq/enterprise/server/plugins/ant/AntBundleServerPluginComponent.java
+++ b/modules/enterprise/server/plugins/ant-bundle/src/main/java/org/rhq/enterprise/server/plugins/ant/AntBundleServerPluginComponent.java
@@ -105,12 +105,13 @@ public class AntBundleServerPluginComponent implements ServerPluginComponent, Bu
StreamUtil.copy(in, out);
// parse, but do not execute, the Ant script
- AntLauncher antLauncher = new AntLauncher();
+ AntLauncher antLauncher = new AntLauncher(true);
BundleAntProject project = antLauncher.parseBundleDeployFile(recipeFile, null);
// obtain the parse results
deploymentProps = new DeploymentProperties(0, project.getBundleName(), project.getBundleVersion(), project
- .getBundleDescription());
+ .getBundleDescription(), project.getDestinationCompliance());
+
bundleFiles = project.getBundleFileNames();
configDef = project.getConfigurationDefinition();
} catch (Throwable t) {
diff --git a/modules/helpers/perftest-support/pom.xml b/modules/helpers/perftest-support/pom.xml
index 80bdc15..1ea35be 100644
--- a/modules/helpers/perftest-support/pom.xml
+++ b/modules/helpers/perftest-support/pom.xml
@@ -14,14 +14,14 @@
</description>
<dependencies>
<dependency>
- <groupId>ant</groupId>
+ <groupId>org.apache.ant</groupId>
<artifactId>ant</artifactId>
- <version>1.6.5</version>
+ <version>1.8.0</version>
</dependency>
<dependency>
- <groupId>ant</groupId>
+ <groupId>org.apache.ant</groupId>
<artifactId>ant-launcher</artifactId>
- <version>1.6.5</version>
+ <version>1.8.0</version>
<scope>runtime</scope>
</dependency>
<dependency>
diff --git a/modules/plugins/ant-bundle/src/main/java/org/rhq/plugins/ant/AntBundlePluginComponent.java b/modules/plugins/ant-bundle/src/main/java/org/rhq/plugins/ant/AntBundlePluginComponent.java
index cd34fb0..c723ae2 100644
--- a/modules/plugins/ant-bundle/src/main/java/org/rhq/plugins/ant/AntBundlePluginComponent.java
+++ b/modules/plugins/ant-bundle/src/main/java/org/rhq/plugins/ant/AntBundlePluginComponent.java
@@ -64,6 +64,7 @@ import org.rhq.core.util.file.FileUtil;
import org.rhq.core.util.stream.StreamUtil;
import org.rhq.core.util.updater.DeployDifferences;
import org.rhq.core.util.updater.DeploymentsMetadata;
+import org.rhq.core.util.updater.DestinationComplianceMode;
import org.rhq.core.util.updater.FileHashcodeMap;
/**
@@ -190,7 +191,12 @@ public class AntBundlePluginComponent implements ResourceComponent, BundleFacet
DeploymentsMetadata metadata = new DeploymentsMetadata(deployDir);
if (metadata.isManaged()) {
metadataDirectoryToPurge = metadata.getMetadataDirectory();
- manageAllDeployDir = metadata.getCurrentDeploymentProperties().getManageRootDir();
+
+ //as of RHQ 4.9.0, we only only support "full" and "filesAndDirectories" destination compliance modes
+ //which we used to describe by boolean "manageRootDir"... Let's not use the deprecated API's but not
+ // change the code too much...
+ manageAllDeployDir = metadata.getCurrentDeploymentProperties().getDestinationCompliance() == DestinationComplianceMode.full;
+
int totalExternalFiles = 0;
ArrayList<String> externalDeleteSuccesses = new ArrayList<String>(0);
ArrayList<String> externalDeleteFailures = new ArrayList<String>(0);
10 years, 10 months
[rhq] modules/enterprise modules/integration-tests
by Heiko W. Rupp
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/AbstractRestBean.java | 6
modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/ResourcesTest.java | 116 ++++++++++
2 files changed, 119 insertions(+), 3 deletions(-)
New commits:
commit 1ccc454cc2716228818b44304e1a85152002ea25
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Thu Aug 8 22:13:03 2013 +0200
BZ 994537 correctly compute the 'lastPage' in paging.
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/AbstractRestBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/AbstractRestBean.java
index 62a85ca..7f0eea3 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/AbstractRestBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/AbstractRestBean.java
@@ -379,7 +379,7 @@ public class AbstractRestBean {
// A link to the last page
if (!pc.isUnlimited()) {
- int lastPage = resultList.getTotalSize() / pc.getPageSize();
+ int lastPage = (resultList.getTotalSize() / pc.getPageSize() ) -1;
uriBuilder = uriInfo.getRequestUriBuilder(); // adds ?q, ?ps and ?category if needed
uriBuilder.replaceQueryParam("page",lastPage);
builder.header("Link", new Link("last",uriBuilder.build().toString()).rfc5988String());
@@ -409,7 +409,8 @@ public class AbstractRestBean {
pColl.setPageSize(pageControl.getPageSize());
int page = pageControl.getPageNumber();
pColl.setCurrentPage(page);
- pColl.setLastPage(originalList.getTotalSize()/pageControl.getPageSize());
+ int lastPage = (originalList.getTotalSize() / pageControl.getPageSize()) -1 ; // -1 as page # is 0 based
+ pColl.setLastPage(lastPage);
UriBuilder uriBuilder;
if (originalList.getTotalSize() > (page +1 ) * pageControl.getPageSize()) {
@@ -427,7 +428,6 @@ public class AbstractRestBean {
// A link to the last page
if (!pageControl.isUnlimited()) {
- int lastPage = originalList.getTotalSize() / pageControl.getPageSize();
uriBuilder = uriInfo.getRequestUriBuilder(); // adds ?q, ?ps and ?category if needed
uriBuilder.replaceQueryParam("page",lastPage);
pColl.addLink( new Link("last",uriBuilder.build().toString()));
diff --git a/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/ResourcesTest.java b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/ResourcesTest.java
index bb7e2c2..a5c888f 100644
--- a/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/ResourcesTest.java
+++ b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/ResourcesTest.java
@@ -30,11 +30,14 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import com.jayway.restassured.http.ContentType;
import com.jayway.restassured.path.json.JsonPath;
import com.jayway.restassured.path.xml.XmlPath;
import com.jayway.restassured.path.xml.element.Node;
+import com.jayway.restassured.response.Headers;
import com.jayway.restassured.response.Response;
import org.apache.http.HttpStatus;
@@ -328,6 +331,119 @@ public class ResourcesTest extends AbstractBase {
}
@Test
+ public void testPagingWrappingCorrectness() throws Exception {
+
+ // First get the lastPage from the paging side
+
+ JsonPath path =
+ given()
+ .header("Accept", "application/vnd.rhq.wrapped+json")
+ .with()
+ .queryParam("page", 0)
+ .queryParam("ps", 5) // Unusually small to provoke having more than 1 page
+ .queryParam("status","COMMITTED")
+ .expect()
+ .statusCode(200)
+ .log().ifError()
+ .when()
+ .get("/resource")
+ .jsonPath();
+
+ int pagingLastPage = path.getInt("lastPage");
+ int pagingTotalSize = path.getInt("totalSize");
+
+ // Now get resource counts from status
+
+ JsonPath statusPath =
+ given()
+ .header(acceptJson)
+ .expect()
+ .statusCode(200)
+ .log().ifError()
+ .when()
+ .get("/status")
+ .jsonPath();
+
+ int platforms = statusPath.getInt("values.PlatformCount");
+ int servers = statusPath.getInt("values.ServerCount");
+ int services = statusPath.getInt("values.ServiceCount");
+
+ int resources = platforms + servers + services;
+
+ assert resources == pagingTotalSize;
+
+ int statusLastPage = (resources/5)-1; // Page numbers start at 0
+
+ assert statusLastPage == pagingLastPage : statusLastPage + " != " + pagingLastPage;
+ }
+
+ @Test
+ public void testPagingHeaderCorrectness() throws Exception {
+
+ // First get the lastPage from the paging headers
+
+ Response response =
+ given()
+ .header(acceptJson)
+ .with()
+ .queryParam("page", 0)
+ .queryParam("ps", 5) // Unusually small to provoke having more than 1 page
+ .queryParam("status", "COMMITTED")
+ .expect()
+ .statusCode(200)
+ .log().everything()
+ .when()
+ .get("/resource");
+
+ String tmp = response.getHeader("X-collection-size");
+ int pagingTotalSize = Integer.parseInt(tmp);
+
+ Headers responseHeaders = response.getHeaders();
+ List<String> headers = responseHeaders.getValues("Link");
+ tmp = null;
+ for (String header : headers) {
+ if (header.contains("rel=\"last\"")) {
+ tmp = header;
+ break;
+ }
+ }
+ assert tmp != null : "Found no Link header for rel=last";
+
+ Matcher m = Pattern.compile(".*page=([0-9]+).*").matcher(tmp);
+ assert m.matches();
+
+ tmp = m.group(1);
+
+ System.out.println(tmp);
+ System.out.flush();
+ int pagingLastPage = Integer.parseInt(tmp);
+
+ // Now get resource counts from status
+
+ JsonPath statusPath =
+ given()
+ .header(acceptJson)
+ .expect()
+ .statusCode(200)
+ .log().ifError()
+ .when()
+ .get("/status")
+ .jsonPath();
+
+ int platforms = statusPath.getInt("values.PlatformCount");
+ int servers = statusPath.getInt("values.ServerCount");
+ int services = statusPath.getInt("values.ServiceCount");
+
+ int resources = platforms + servers + services;
+
+ assert resources == pagingTotalSize;
+
+ int statusLastPage = (resources/5)-1; // Page numbers start at 0
+
+ assert statusLastPage == pagingLastPage : statusLastPage + " != " + pagingLastPage;
+ }
+
+ @Test
public void testGetResourcesWithPagingAndWrapping() throws Exception {
given()
10 years, 10 months
[rhq] modules/enterprise
by Jiri Kremser
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeConfigurationEditor.java | 205 ++++++++++
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDetailView.java | 115 +++--
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeLoadComponent.java | 167 --------
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/configuration/ConfigurationEditor.java | 7
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/form/ValueWithUnitsItem.java | 133 ++++++
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/StorageGWTService.java | 3
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/configuration/ConfigurationFilter.java | 32 +
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/configuration/ResourceConfigurationEditView.java | 9
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/StorageGWTServiceImpl.java | 12
9 files changed, 484 insertions(+), 199 deletions(-)
New commits:
commit f5f25f9a139868b9f7453a9aeef04560086a0470
Author: Jirka Kremser <jkremser(a)redhat.com>
Date: Thu Aug 8 21:04:29 2013 +0200
New component for editing the storage node properties. Adding the retrieveConfiguration() to GWT service impl class.
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeConfigurationEditor.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeConfigurationEditor.java
new file mode 100644
index 0000000..15bb412
--- /dev/null
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeConfigurationEditor.java
@@ -0,0 +1,205 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2013 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+package org.rhq.enterprise.gui.coregui.client.admin.storage;
+
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+import com.smartgwt.client.types.Alignment;
+import com.smartgwt.client.types.Overflow;
+import com.smartgwt.client.widgets.events.ClickEvent;
+import com.smartgwt.client.widgets.events.ClickHandler;
+import com.smartgwt.client.widgets.form.fields.FormItem;
+import com.smartgwt.client.widgets.form.fields.StaticTextItem;
+import com.smartgwt.client.widgets.form.fields.TextItem;
+import com.smartgwt.client.widgets.layout.LayoutSpacer;
+
+import org.rhq.core.domain.cloud.StorageNodeConfigurationComposite;
+import org.rhq.core.domain.measurement.MeasurementUnits;
+import org.rhq.enterprise.gui.coregui.client.RefreshableView;
+import org.rhq.enterprise.gui.coregui.client.components.configuration.PropertyValueChangeEvent;
+import org.rhq.enterprise.gui.coregui.client.components.configuration.PropertyValueChangeListener;
+import org.rhq.enterprise.gui.coregui.client.components.form.EnhancedDynamicForm;
+import org.rhq.enterprise.gui.coregui.client.components.form.ValueWithUnitsItem;
+import org.rhq.enterprise.gui.coregui.client.util.enhanced.EnhancedIButton;
+import org.rhq.enterprise.gui.coregui.client.util.enhanced.EnhancedToolStrip;
+import org.rhq.enterprise.gui.coregui.client.util.enhanced.EnhancedVLayout;
+
+/**
+ * The component for editing the storage node configuration
+ *
+ * @author Jirka Kremser
+ */
+public class StorageNodeConfigurationEditor extends EnhancedVLayout implements PropertyValueChangeListener,
+ RefreshableView {
+
+ private EnhancedDynamicForm form;
+ private EnhancedToolStrip toolStrip;
+ private boolean oddRow;
+ private final StorageNodeConfigurationComposite configuration;
+
+ public StorageNodeConfigurationEditor(final StorageNodeConfigurationComposite configuration) {
+ super();
+ this.configuration = configuration;
+
+ }
+
+ private void save() {
+
+ }
+
+ private List<FormItem> buildOneFormRow(String name, String title, String value, String description,
+ boolean unitsDropdown) {
+ List<FormItem> fields = new ArrayList<FormItem>();
+ StaticTextItem nameItem = new StaticTextItem();
+ nameItem.setStartRow(true);
+ nameItem.setValue("<b>" + title + "</b>");
+ nameItem.setShowTitle(false);
+ nameItem.setCellStyle(oddRow ? "OddRow" : "EvenRow");
+ fields.add(nameItem);
+
+ FormItem valueItem = null;
+ if (unitsDropdown) {
+ valueItem = buildJMXMemoryItem(name, value);
+ } else {
+ valueItem = new TextItem();
+ valueItem.setName(name);
+ valueItem.setValue(value);
+ valueItem.setWidth(220);
+ }
+ valueItem.setAlign(Alignment.CENTER);
+ valueItem.setShowTitle(false);
+ valueItem.setRequired(true);
+ valueItem.setCellStyle(oddRow ? "OddRow" : "EvenRow");
+ fields.add(valueItem);
+
+ StaticTextItem descriptionItem = new StaticTextItem();
+ descriptionItem.setValue(description);
+ descriptionItem.setShowTitle(false);
+ descriptionItem.setEndRow(true);
+ descriptionItem.setCellStyle(oddRow ? "OddRow" : "EvenRow");
+ fields.add(descriptionItem);
+
+ oddRow = !oddRow;
+ return fields;
+ }
+
+ private FormItem buildJMXMemoryItem(String name, String value) {
+ Set<MeasurementUnits> supportedUnits = new LinkedHashSet<MeasurementUnits>();
+ supportedUnits.add(MeasurementUnits.MEGABYTES);
+ supportedUnits.add(MeasurementUnits.GIGABYTES);
+
+ ValueWithUnitsItem valueItem = new ValueWithUnitsItem(name, null, supportedUnits);
+ if (value != null && !value.isEmpty()) {
+ boolean megs = value.trim().substring(value.trim().length() - 1).equalsIgnoreCase("m");
+ MeasurementUnits units = megs ? MeasurementUnits.MEGABYTES : MeasurementUnits.GIGABYTES;
+ try {
+ int intVal = Integer.parseInt(value.substring(0, value.toLowerCase().indexOf(megs ? "m" : "g")));
+ valueItem.setValue(intVal, units);
+ } catch (StringIndexOutOfBoundsException e) {
+ //nothing
+ }
+ }
+ return valueItem;
+ }
+
+ private List<FormItem> buildHeaderItems() {
+ List<FormItem> fields = new ArrayList<FormItem>();
+ fields.add(createHeaderTextItem(MSG.view_configEdit_property()));
+ fields.add(createHeaderTextItem(MSG.common_title_value()));
+ fields.add(createHeaderTextItem(MSG.common_title_description()));
+ return fields;
+ }
+
+ private StaticTextItem createHeaderTextItem(String value) {
+ StaticTextItem unsetHeader = new StaticTextItem();
+ unsetHeader.setValue(value);
+ unsetHeader.setShowTitle(false);
+ unsetHeader.setCellStyle("configurationEditorHeaderCell");
+ return unsetHeader;
+ }
+
+ @Override
+ protected void onDraw() {
+ super.onDraw();
+ refresh();
+ }
+
+ @Override
+ public void refresh() {
+ form = new EnhancedDynamicForm();
+ form.setHiliteRequiredFields(true);
+ form.setNumCols(3);
+ form.setCellPadding(5);
+ form.setColWidths(190, 220, "*");
+ form.setIsGroup(true);
+ form.setGroupTitle("Storage Node Specific Settings");
+ form.setBorder("1px solid #AAA");
+ oddRow = true;
+
+ List<FormItem> items = buildHeaderItems();
+ items
+ .addAll(buildOneFormRow(
+ "foo2",
+ "Max Heap Size",
+ configuration.getHeapSize(),
+ "The maximum heap size. This value will be used with the -Xmx JVM option. The value should be an integer with a suffix of M or G to indicate megabytes or gigabytes.",
+ true));
+ items
+ .addAll(buildOneFormRow(
+ "foo",
+ "Heap New Size",
+ configuration.getHeapNewSize(),
+ "The size of the new generation portion of the heap. This value will be used with the -Xmn JVM option. The value should be an integer with a suffix of M or G to indicate megabytes or gigabytes.",
+ true));
+
+ items.addAll(buildOneFormRow("foo3", "Thread Stack Size", configuration.getThreadStackSize(),
+ "asdfsdfffa df sdbla", false));
+ items.addAll(buildOneFormRow("foo4", "JMX Port", String.valueOf(configuration.getJmxPort()),
+ "sdfla ffa blsdfa", false));
+ form.setFields(items.toArray(new FormItem[items.size()]));
+ form.validate();
+
+ EnhancedIButton saveButton = new EnhancedIButton(MSG.common_button_save());
+ saveButton.addClickHandler(new ClickHandler() {
+ public void onClick(ClickEvent clickEvent) {
+ save();
+ }
+ });
+ toolStrip = new EnhancedToolStrip();
+ toolStrip.setWidth100();
+ toolStrip.setMembersMargin(5);
+ toolStrip.setLayoutMargin(5);
+ toolStrip.addMember(saveButton);
+ form.setWidth100();
+ form.setOverflow(Overflow.VISIBLE);
+ setWidth100();
+ LayoutSpacer spacer = new LayoutSpacer();
+ spacer.setWidth100();
+ setMembers(form, spacer, toolStrip);
+ markForRedraw();
+ }
+
+ @Override
+ public void propertyValueChanged(PropertyValueChangeEvent event) {
+
+ }
+}
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDetailView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDetailView.java
index 7d0b3a9..e395b2b 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDetailView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDetailView.java
@@ -29,38 +29,32 @@ import static org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDat
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.Set;
+import java.util.Map.Entry;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.smartgwt.client.types.Alignment;
-import com.smartgwt.client.types.ContentsType;
import com.smartgwt.client.types.Overflow;
-import com.smartgwt.client.types.VerticalAlignment;
import com.smartgwt.client.types.VisibilityMode;
import com.smartgwt.client.widgets.HTMLFlow;
import com.smartgwt.client.widgets.form.DynamicForm;
-import com.smartgwt.client.widgets.form.fields.CanvasItem;
import com.smartgwt.client.widgets.form.fields.FormItem;
-import com.smartgwt.client.widgets.form.fields.LinkItem;
import com.smartgwt.client.widgets.form.fields.StaticTextItem;
-import com.smartgwt.client.widgets.form.fields.events.ClickEvent;
-import com.smartgwt.client.widgets.form.fields.events.ClickHandler;
import com.smartgwt.client.widgets.layout.LayoutSpacer;
import com.smartgwt.client.widgets.layout.SectionStack;
import com.smartgwt.client.widgets.layout.SectionStackSection;
import org.rhq.core.domain.cloud.StorageNode;
+import org.rhq.core.domain.cloud.StorageNodeConfigurationComposite;
+import org.rhq.core.domain.configuration.definition.ConfigurationDefinition;
+import org.rhq.core.domain.configuration.definition.PropertyDefinition;
+import org.rhq.core.domain.configuration.definition.PropertyGroupDefinition;
import org.rhq.core.domain.criteria.ResourceCriteria;
import org.rhq.core.domain.criteria.StorageNodeCriteria;
-import org.rhq.core.domain.measurement.MeasurementDefinition;
import org.rhq.core.domain.measurement.composite.MeasurementDataNumericHighLowComposite;
import org.rhq.core.domain.resource.Resource;
-import org.rhq.core.domain.resource.ResourceType;
import org.rhq.core.domain.resource.composite.ResourceComposite;
import org.rhq.core.domain.util.PageList;
import org.rhq.enterprise.gui.coregui.client.BookmarkableView;
@@ -70,13 +64,11 @@ import org.rhq.enterprise.gui.coregui.client.ViewPath;
import org.rhq.enterprise.gui.coregui.client.components.table.TimestampCellFormatter;
import org.rhq.enterprise.gui.coregui.client.gwt.GWTServiceLookup;
import org.rhq.enterprise.gui.coregui.client.inventory.InventoryView;
-import org.rhq.enterprise.gui.coregui.client.inventory.common.detail.summary.AbstractActivityView;
import org.rhq.enterprise.gui.coregui.client.inventory.common.detail.summary.AbstractActivityView.ChartViewWindow;
+import org.rhq.enterprise.gui.coregui.client.inventory.resource.detail.configuration.ConfigurationFilter;
import org.rhq.enterprise.gui.coregui.client.inventory.resource.detail.configuration.ResourceConfigurationEditView;
import org.rhq.enterprise.gui.coregui.client.inventory.resource.detail.monitoring.D3GraphListView;
import org.rhq.enterprise.gui.coregui.client.inventory.resource.detail.operation.history.ResourceOperationHistoryListView;
-import org.rhq.enterprise.gui.coregui.client.inventory.resource.type.ResourceTypeRepository;
-import org.rhq.enterprise.gui.coregui.client.util.BrowserUtility;
import org.rhq.enterprise.gui.coregui.client.util.Log;
import org.rhq.enterprise.gui.coregui.client.util.MeasurementUtility;
import org.rhq.enterprise.gui.coregui.client.util.StringUtility;
@@ -150,13 +142,14 @@ public class StorageNodeDetailView extends EnhancedVLayout implements Bookmarkab
+ node.getAddress() + ")</div>");
Resource res = node.getResource();
if (res != null) {
- fetchResourceComposite(res.getId());
+// fetchResourceComposite(res.getId());
} else {
// skip this if the resource id is not there
initSectionCount++;
}
- prepareDetailsSection(sectionStack, node);
- fetchSparkLineDataForLoadComponent(sectionStack, node);
+ fetchStorageNodeConfigurationComposite(node);
+ prepareDetailsSection(node);
+ fetchSparkLineDataForLoadComponent(node);
}
@@ -170,33 +163,51 @@ public class StorageNodeDetailView extends EnhancedVLayout implements Bookmarkab
fetchUnackAlerts(storageNodeId);
}
- private void fetchResourceComposite(final int resourceId) {
- ResourceCriteria resourceCriteria = new ResourceCriteria();
- resourceCriteria.addFilterId(resourceId);
- GWTServiceLookup.getResourceService().findResourceCompositesByCriteria(resourceCriteria,
- new AsyncCallback<PageList<ResourceComposite>>() {
+
+ private void fetchStorageNodeConfigurationComposite(final StorageNode node) {
+ GWTServiceLookup.getStorageService().retrieveConfiguration(node,
+ new AsyncCallback<StorageNodeConfigurationComposite>() {
@Override
public void onFailure(Throwable caught) {
- Message message = new Message(MSG.view_inventory_resource_loadFailed(String.valueOf(resourceId)),
+ Message message = new Message(MSG.view_configurationHistoryDetails_error_loadFailure(),
Message.Severity.Warning);
- CoreGUI.goToView(InventoryView.VIEW_ID.getName(), message);
initSectionCount = SECTION_COUNT;
}
@Override
- public void onSuccess(PageList<ResourceComposite> result) {
- if (result.isEmpty()) {
- onFailure(new Exception("Resource with id [" + resourceId + "] does not exist."));
- } else {
- final ResourceComposite resourceComposite = result.get(0);
-// prepareOperationHistory(resourceComposite);
- prepareResourceConfigEditor(resourceComposite);
- }
+ public void onSuccess(StorageNodeConfigurationComposite result) {
+ prepareResourceConfigEditor(result);
}
});
}
- private void fetchSparkLineDataForLoadComponent(final SectionStack stack, final StorageNode storageNode) {
+// private void fetchResourceComposite(final int resourceId) {
+// ResourceCriteria resourceCriteria = new ResourceCriteria();
+// resourceCriteria.addFilterId(resourceId);
+// GWTServiceLookup.getResourceService().findResourceCompositesByCriteria(resourceCriteria,
+// new AsyncCallback<PageList<ResourceComposite>>() {
+// @Override
+// public void onFailure(Throwable caught) {
+// Message message = new Message(MSG.view_inventory_resource_loadFailed(String.valueOf(resourceId)),
+// Message.Severity.Warning);
+// CoreGUI.goToView(InventoryView.VIEW_ID.getName(), message);
+// initSectionCount = SECTION_COUNT;
+// }
+//
+// @Override
+// public void onSuccess(PageList<ResourceComposite> result) {
+// if (result.isEmpty()) {
+// onFailure(new Exception("Resource with id [" + resourceId + "] does not exist."));
+// } else {
+// final ResourceComposite resourceComposite = result.get(0);
+//// prepareOperationHistory(resourceComposite);
+// prepareResourceConfigEditor(resourceComposite);
+// }
+// }
+// });
+// }
+
+ private void fetchSparkLineDataForLoadComponent(final StorageNode storageNode) {
GWTServiceLookup.getStorageService().findStorageNodeLoadDataForLast(storageNode, 8, MeasurementUtility.UNIT_HOURS,
60, new AsyncCallback<Map<String, List<MeasurementDataNumericHighLowComposite>>>() {
@@ -287,7 +298,7 @@ public class StorageNodeDetailView extends EnhancedVLayout implements Bookmarkab
}.run(); // fire the timer immediately
}
- private void prepareDetailsSection(SectionStack stack, final StorageNode storageNode) {
+ private void prepareDetailsSection(final StorageNode storageNode) {
final DynamicForm form = new DynamicForm();
form.setMargin(10);
form.setWidth100();
@@ -388,8 +399,40 @@ public class StorageNodeDetailView extends EnhancedVLayout implements Bookmarkab
initSectionCount++;
}
- private void prepareResourceConfigEditor(ResourceComposite resourceComposite) {
- ResourceConfigurationEditView editorView = new ResourceConfigurationEditView(resourceComposite);
+// private void prepareResourceConfigEditor(ResourceComposite resourceComposite) {
+ private void prepareResourceConfigEditor(final StorageNodeConfigurationComposite configuration) {
+
+ StorageNodeConfigurationEditor editorView = new StorageNodeConfigurationEditor(configuration);
+
+// ResourceConfigurationEditView editorView = new ResourceConfigurationEditView(resourceComposite);
+// ConfigurationFilter filter = new ConfigurationFilter() {
+// @Override
+// public ConfigurationDefinition filter(ConfigurationDefinition definition) {
+// Map<String, PropertyDefinition> filteredConfigurationDefinition = new HashMap<String, PropertyDefinition>();
+// PropertyGroupDefinition groupDef = null;
+// for (Entry<String, PropertyDefinition> propertyDefinitionEntry : definition.getPropertyDefinitions().entrySet()) {
+// PropertyDefinition propertyDefinition = propertyDefinitionEntry.getValue();
+// if (propertyDefinition.getPropertyGroupDefinition() != null) {
+// if (groupDef == null) {
+// groupDef = propertyDefinition.getPropertyGroupDefinition();
+//// groupDef.setName("Storage Node Settings");
+// }
+// propertyDefinition.setPropertyGroupDefinition(groupDef);
+// }
+// if (!"heapDumpOnOOMError".equals(propertyDefinition.getName())
+// && !"heapDumpDir".equals(propertyDefinition.getName())
+// && !"minHeapSize".equals(propertyDefinition.getName())
+// && !"gossipPort".equals(propertyDefinition.getName())
+// && !"cqlPort".equals(propertyDefinition.getName())) {
+// filteredConfigurationDefinition.put(propertyDefinitionEntry.getKey(),
+// propertyDefinitionEntry.getValue());
+// }
+// }
+// definition.setPropertyDefinitions(filteredConfigurationDefinition);
+// return definition;
+// }
+// };
+// editorView.setFilter(filter);
SectionStackSection section = new SectionStackSection("Configuration");
section.setItems(editorView);
section.setExpanded(true);
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeLoadComponent.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeLoadComponent.java
index 7cfb278..d1b94a1 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeLoadComponent.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeLoadComponent.java
@@ -21,29 +21,16 @@ package org.rhq.enterprise.gui.coregui.client.admin.storage;
import static org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDatasource.DONT_MISS_ME_COLOR;
import static org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDatasource.OK_COLOR;
import static org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDatasource.WARN_COLOR;
-import static org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDatasourceField.FIELD_ALERTS;
-import java.util.ArrayList;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import com.google.gwt.user.client.Timer;
-import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.smartgwt.client.types.Alignment;
import com.smartgwt.client.types.Autofit;
-import com.smartgwt.client.types.ContentsType;
-import com.smartgwt.client.types.Overflow;
-import com.smartgwt.client.types.VerticalAlignment;
-import com.smartgwt.client.widgets.HTMLFlow;
import com.smartgwt.client.widgets.IButton;
import com.smartgwt.client.widgets.events.ClickEvent;
import com.smartgwt.client.widgets.events.ClickHandler;
-import com.smartgwt.client.widgets.form.DynamicForm;
-import com.smartgwt.client.widgets.form.fields.CanvasItem;
-import com.smartgwt.client.widgets.form.fields.LinkItem;
-import com.smartgwt.client.widgets.form.fields.StaticTextItem;
import com.smartgwt.client.widgets.grid.ListGrid;
import com.smartgwt.client.widgets.grid.ListGridField;
import com.smartgwt.client.widgets.grid.ListGridRecord;
@@ -51,15 +38,9 @@ import com.smartgwt.client.widgets.grid.events.DataArrivedEvent;
import com.smartgwt.client.widgets.grid.events.DataArrivedHandler;
import com.smartgwt.client.widgets.toolbar.ToolStrip;
-import org.rhq.core.domain.measurement.MeasurementDefinition;
import org.rhq.core.domain.measurement.composite.MeasurementDataNumericHighLowComposite;
import org.rhq.enterprise.gui.coregui.client.CoreGUI;
-import org.rhq.enterprise.gui.coregui.client.LinkManager;
import org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDatasource.StorageNodeLoadCompositeDatasource;
-import org.rhq.enterprise.gui.coregui.client.gwt.GWTServiceLookup;
-import org.rhq.enterprise.gui.coregui.client.inventory.common.detail.summary.AbstractActivityView;
-import org.rhq.enterprise.gui.coregui.client.inventory.common.detail.summary.AbstractActivityView.ChartViewWindow;
-import org.rhq.enterprise.gui.coregui.client.inventory.resource.detail.monitoring.D3GraphListView;
import org.rhq.enterprise.gui.coregui.client.util.BrowserUtility;
import org.rhq.enterprise.gui.coregui.client.util.enhanced.EnhancedVLayout;
@@ -115,7 +96,7 @@ public class StorageNodeLoadComponent extends EnhancedVLayout {
StorageNodeLoadCompositeDatasource datasource = StorageNodeLoadCompositeDatasource.getInstance(storageNodeId);
List<ListGridField> fields = datasource.getListGridFields();
if (showSparkLine) {
- fields.add(new ListGridField("sparkline", 90));
+ fields.add(0, new ListGridField("sparkline", "Chart", 75));
}
loadGrid.setFields(fields.toArray(new ListGridField[fields.size()]));
loadGrid.setAutoFetchData(true);
@@ -184,149 +165,19 @@ public class StorageNodeLoadComponent extends EnhancedVLayout {
someChartedData = lastValue != -1;
if (someChartedData && records.length > i) {
- String contents = "<span id='sparkline_" + entry.getKey() + "' class='dynamicsparkline' width='0' "
+ String contents = "<span id='sparkline_" + entry.getKey() + "' class='dynamicsparkline' width='70' "
+ "values='" + commaDelimitedList + "'>...</span>";
records[i].setAttribute("sparkline", contents);
}
i++;
}
loadGrid.setData(records);
-
-
-
-
-
-//
-//
-//
-//
-//
-// if (!results.isEmpty()) {
-//
-// //iterate over the retrieved charting data
-// for (int index = 0; index < displayOrder.length; index++) {
-// //retrieve the correct measurement definition
-// final MeasurementDefinition md = measurementDefMap
-// .get(displayOrder[index]);
-//
-// //load the data results for the given metric definition
-// List<MeasurementDataNumericHighLowComposite> data = results
-// .get(index);
-//
-// //locate last and minimum values.
-// double lastValue = -1;
-// double minValue = Double.MAX_VALUE;//
-// for (MeasurementDataNumericHighLowComposite d : data) {
-// if ((!Double.isNaN(d.getValue()))
-// && (!String.valueOf(d.getValue()).contains("NaN"))) {
-// if (d.getValue() < minValue) {
-// minValue = d.getValue();
-// }
-// lastValue = d.getValue();
-// }
-// }
-//
-// //collapse the data into comma delimited list for consumption by third party javascript library(jquery.sparkline)
-// String commaDelimitedList = "";
-//
-// for (MeasurementDataNumericHighLowComposite d : data) {
-// if ((!Double.isNaN(d.getValue()))
-// && (!String.valueOf(d.getValue()).contains("NaN"))) {
-// commaDelimitedList += d.getValue() + ",";
-// }
-// }
-// DynamicForm row = new DynamicForm();
-// row.setNumCols(3);
-// row.setColWidths(65, "*", 100);
-// row.setWidth100();
-// row.setAutoHeight();
-// row.setOverflow(Overflow.VISIBLE);
-// HTMLFlow sparklineGraph = new HTMLFlow();
-// String contents = "<span id='sparkline_" + index
-// + "' class='dynamicsparkline' width='0' " + "values='"
-// + commaDelimitedList + "'>...</span>";
-// sparklineGraph.setContents(contents);
-// sparklineGraph.setContentsType(ContentsType.PAGE);
-// //disable scrollbars on span
-// sparklineGraph.setScrollbarSize(0);
-//
-// CanvasItem sparklineContainer = new CanvasItem();
-// sparklineContainer.setShowTitle(false);
-// sparklineContainer.setHeight(16);
-// sparklineContainer.setWidth(60);
-// sparklineContainer.setCanvas(sparklineGraph);
-//
-// //Link/title element
-// final String title = md.getDisplayName();
-// LinkItem link = AbstractActivityView.newLinkItem(title, null);
-// link.setTooltip(title);
-// link.setTitleVAlign(VerticalAlignment.TOP);
-// link.setAlign(Alignment.LEFT);
-// link.setClipValue(true);
-// link.setWrap(true);
-// link.setHeight(26);
-// link.setWidth("100%");
-// if (!BrowserUtility.isBrowserPreIE9()){
-// link.addClickHandler(new ClickHandler() {
-// @Override
-// public void onClick(ClickEvent event) {
-// window = new ChartViewWindow(title);
-//
-// graphView = D3GraphListView
-// .createSingleGraph(resourceComposite.getResource(),
-// md.getId(), true);
-//
-// window.addItem(graphView);
-// window.show();
-// }
-// });
-// } else{
-// link.disable();
-// }
-//
-//
-// //Value
-// String convertedValue;
-// convertedValue = AbstractActivityView.convertLastValueForDisplay(
-// lastValue, md);
-// StaticTextItem value = AbstractActivityView
-// .newTextItem(convertedValue);
-// value.setVAlign(VerticalAlignment.TOP);
-// value.setAlign(Alignment.RIGHT);
-//
-// row.setItems(sparklineContainer, link, value);
-// row.setWidth100();
-//
-// //if graph content returned
-// if ((!md.getName().trim().contains("Trait.")) && (lastValue != -1)) {
-// column.addMember(row);
-// someChartedData = true;
-// }
-// }
-// if (!someChartedData) {// when there are results but no chartable entries.
-// DynamicForm row = AbstractActivityView.createEmptyDisplayRow(
-//
-// AbstractActivityView.RECENT_MEASUREMENTS_NONE);
-// column.addMember(row);
-// } else {
-// //insert see more link
-// DynamicForm row = new DynamicForm();
-// String link = LinkManager
-// .getResourceMonitoringGraphsLink(resourceId);
-// AbstractActivityView.addSeeMoreLink(row, link, column);
-// }
-// //call out to 3rd party javascript lib
-// new Timer(){
-// @Override
-// public void run() {
-// BrowserUtility.graphSparkLines();
-// }
-// }.schedule(200);
-// } else {
-// DynamicForm row = AbstractActivityView
-// .createEmptyDisplayRow(AbstractActivityView.RECENT_MEASUREMENTS_NONE);
-// column.addMember(row);
-// }
-// setRefreshing(false);
+ new Timer() {
+ @Override
+ public void run() {
+ BrowserUtility.graphSparkLines();
+ scheduleRepeating(5000);
+ }
+ }.schedule(150);
}
}
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/configuration/ConfigurationEditor.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/configuration/ConfigurationEditor.java
index 4423623..7019d77 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/configuration/ConfigurationEditor.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/configuration/ConfigurationEditor.java
@@ -454,10 +454,8 @@ public class ConfigurationEditor extends EnhancedVLayout {
sectionStack.addSection(buildGroupSection(definition));
}
-// if (groupDefinitions.size() > 1) {
- this.toolStrip = buildToolStrip(layout, sectionStack);
- layout.addMember(toolStrip);
-// }
+ this.toolStrip = buildToolStrip(layout, sectionStack);
+ layout.addMember(toolStrip);
layout.addMember(sectionStack);
}
@@ -569,6 +567,7 @@ public class ConfigurationEditor extends EnhancedVLayout {
form.setNumCols(4);
form.setCellPadding(5);
form.setColWidths(190, 28, 210);
+
List<FormItem> fields = new ArrayList<FormItem>();
addHeaderItems(fields);
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/form/ValueWithUnitsItem.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/form/ValueWithUnitsItem.java
new file mode 100644
index 0000000..a49600e
--- /dev/null
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/form/ValueWithUnitsItem.java
@@ -0,0 +1,133 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2011 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation, and/or the GNU Lesser
+ * General Public License, version 2.1, also as published by the Free
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License and the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.rhq.enterprise.gui.coregui.client.components.form;
+
+import java.util.LinkedHashMap;
+import java.util.Set;
+
+import com.smartgwt.client.widgets.form.DynamicForm;
+import com.smartgwt.client.widgets.form.fields.CanvasItem;
+import com.smartgwt.client.widgets.form.fields.FormItem;
+import com.smartgwt.client.widgets.form.fields.IntegerItem;
+import com.smartgwt.client.widgets.form.fields.SelectItem;
+import com.smartgwt.client.widgets.form.validator.IntegerRangeValidator;
+
+import org.rhq.core.domain.measurement.MeasurementUnits;
+import org.rhq.enterprise.gui.coregui.client.CoreGUI;
+import org.rhq.enterprise.gui.coregui.client.Messages;
+import org.rhq.enterprise.gui.coregui.client.util.FormUtility;
+
+/**
+ * A form item for entering a n arbitrary value - consists of an IntegerItem for entering the value and a
+ * ComboBoxItem for entering the units.
+ *
+ * @author Jirka Kremser
+ */
+public class ValueWithUnitsItem extends CanvasItem {
+
+ private static final Messages MSG = CoreGUI.getMessages();
+
+ private static final String FIELD_VALUE = "value";
+ private static final String FIELD_UNITS = "units";
+
+ private final DynamicForm form;
+ private Set<MeasurementUnits> supportedUnits;
+ private MeasurementUnits valueUnit;
+
+ public ValueWithUnitsItem(String name, String title, Set<MeasurementUnits> supportedUnits) {
+ super(name, title);
+
+ if (supportedUnits != null && !supportedUnits.isEmpty()) {
+ this.supportedUnits = supportedUnits;
+ if (null == this.valueUnit) {
+ this.valueUnit = supportedUnits.iterator().next();
+ }
+ }
+
+ this.form = new EnhancedDynamicForm(false, false);
+ this.form.setNumCols(2);
+ this.form.setColWidths("126", "60");
+
+ final IntegerItem valueItem = new IntegerItem(FIELD_VALUE, title);
+ valueItem.setShowTitle(getShowTitle());
+ valueItem.setValue(getValue());
+ IntegerRangeValidator integerRangeValidator = new IntegerRangeValidator();
+ integerRangeValidator.setMin(1);
+ integerRangeValidator.setMax(Integer.MAX_VALUE);
+ valueItem.setValidators(integerRangeValidator);
+ valueItem.setValidateOnChange(true);
+
+ SelectItem unitsItem = new SelectItem(FIELD_UNITS);
+ unitsItem.setShowTitle(false);
+
+ LinkedHashMap<String, String> valueMap = new LinkedHashMap<String, String>();
+ for (MeasurementUnits unit : supportedUnits) {
+ valueMap.put(unit.name().toLowerCase(), unit.toString());
+ }
+ unitsItem.setValueMap(valueMap);
+ unitsItem.setDefaultToFirstOption(true);
+
+ this.form.setFields(valueItem, unitsItem);
+ valueItem.setWidth(126);
+ unitsItem.setWidth(60);
+
+ setCanvas(this.form);
+ }
+
+ @Override
+ public void setValidateOnChange(Boolean validateOnChange) {
+ form.setValidateOnChange(validateOnChange);
+ }
+
+ @Override
+ public void setValidateOnExit(Boolean validateOnExit) {
+ form.setValidateOnChange(validateOnExit);
+ }
+
+ public void setValue(Integer value, MeasurementUnits unitType) {
+ if (!this.supportedUnits.contains(unitType)) {
+ throw new IllegalArgumentException(MSG.widget_durationItem_unitTypeNotSupported(unitType.name()));
+ }
+ if (value != null) {
+ this.form.setValue(FIELD_VALUE, value);
+ } else {
+ this.form.setValue(FIELD_VALUE, (String) null);
+ }
+ this.form.setValue(FIELD_UNITS, this.valueUnit.name().toLowerCase());
+
+ setValue(value);
+ }
+
+ @Override
+ public Boolean validate() {
+ return this.form.validate();
+ }
+
+ public void setContextualHelp(String contextualHelp) {
+ if (contextualHelp != null) {
+ FormItem item;
+ item = this.form.getItem(FIELD_UNITS);
+ FormUtility.addContextualHelp(item, contextualHelp);
+ }
+ }
+}
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/StorageGWTService.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/StorageGWTService.java
index 1e3376c..abe759c 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/StorageGWTService.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/StorageGWTService.java
@@ -28,6 +28,7 @@ import java.util.Map;
import com.google.gwt.user.client.rpc.RemoteService;
import org.rhq.core.domain.cloud.StorageNode;
+import org.rhq.core.domain.cloud.StorageNodeConfigurationComposite;
import org.rhq.core.domain.cloud.StorageNodeLoadComposite;
import org.rhq.core.domain.criteria.StorageNodeCriteria;
import org.rhq.core.domain.measurement.composite.MeasurementDataNumericHighLowComposite;
@@ -80,4 +81,6 @@ public interface StorageGWTService extends RemoteService {
List<Integer> findNotAcknowledgedStorageNodeAlertsCounts(List<Integer> storageNodeIds) throws RuntimeException;
Map<String, List<MeasurementDataNumericHighLowComposite>> findStorageNodeLoadDataForLast(StorageNode node, int lastN, int unit, int numPoints) throws RuntimeException;
+
+ StorageNodeConfigurationComposite retrieveConfiguration(StorageNode storageNode) throws RuntimeException;
}
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/configuration/ConfigurationFilter.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/configuration/ConfigurationFilter.java
new file mode 100644
index 0000000..2bca203
--- /dev/null
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/configuration/ConfigurationFilter.java
@@ -0,0 +1,32 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2013 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+package org.rhq.enterprise.gui.coregui.client.inventory.resource.detail.configuration;
+
+import org.rhq.core.domain.configuration.definition.ConfigurationDefinition;
+
+/**
+ * Simple interface encapsulating the filter operation
+ * for restricting the fields to be passed to ConfigurationEditor
+ *
+ * @author Jirka Kremser
+ *
+ */
+public interface ConfigurationFilter {
+ ConfigurationDefinition filter(ConfigurationDefinition definition);
+}
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/configuration/ResourceConfigurationEditView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/configuration/ResourceConfigurationEditView.java
index e3b119c..6a51e3d 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/configuration/ResourceConfigurationEditView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/configuration/ResourceConfigurationEditView.java
@@ -67,6 +67,7 @@ public class ResourceConfigurationEditView extends EnhancedVLayout implements Pr
private ToolStrip buttonbar;
private IButton saveButton;
private boolean refreshing = false;
+ private ConfigurationFilter filter;
public ResourceConfigurationEditView(ResourceComposite resourceComposite) {
super();
@@ -91,7 +92,7 @@ public class ResourceConfigurationEditView extends EnhancedVLayout implements Pr
private ToolStrip createButtonBar() {
this.buttonbar = new ToolStrip();
buttonbar.setWidth100();
- buttonbar.setExtraSpace(10);
+// buttonbar.setExtraSpace(10);
buttonbar.setMembersMargin(5);
buttonbar.setLayoutMargin(5);
@@ -153,6 +154,9 @@ public class ResourceConfigurationEditView extends EnhancedVLayout implements Pr
@Override
public void onSuccess(ConfigurationDefinition configurationDefinition) {
Configuration configuration = configurationUpdate.getConfiguration();
+ if (filter != null) {
+ configurationDefinition = filter.filter(configurationDefinition);
+ }
editor = new ConfigurationEditor(configurationDefinition, configuration);
editor.setOverflow(Overflow.AUTO);
editor.addPropertyValueChangeListener(ResourceConfigurationEditView.this);
@@ -229,4 +233,7 @@ public class ResourceConfigurationEditView extends EnhancedVLayout implements Pr
}
}
+ public void setFilter(ConfigurationFilter filter) {
+ this.filter = filter;
+ }
}
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/StorageGWTServiceImpl.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/StorageGWTServiceImpl.java
index 7f3093b..28ea78e 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/StorageGWTServiceImpl.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/StorageGWTServiceImpl.java
@@ -26,7 +26,9 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import org.rhq.core.domain.auth.Subject;
import org.rhq.core.domain.cloud.StorageNode;
+import org.rhq.core.domain.cloud.StorageNodeConfigurationComposite;
import org.rhq.core.domain.cloud.StorageNodeLoadComposite;
import org.rhq.core.domain.criteria.ResourceCriteria;
import org.rhq.core.domain.criteria.StorageNodeCriteria;
@@ -150,4 +152,14 @@ public class StorageGWTServiceImpl extends AbstractGWTServiceImpl implements Sto
throw getExceptionToThrowToClient(t);
}
}
+
+ @Override
+ public StorageNodeConfigurationComposite retrieveConfiguration(StorageNode storageNode) throws RuntimeException {
+ try {
+ return SerialUtility.prepare(storageNodeManager.retrieveConfiguration(getSessionSubject(), storageNode),
+ "StorageGWTServiceImpl.retrieveConfiguration");
+ } catch (Throwable t) {
+ throw getExceptionToThrowToClient(t);
+ }
+ }
}
10 years, 10 months
[rhq] modules/core modules/plugins
by Thomas Segismont
modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/inventory/DiscoveredResourceDetails.java | 23 +--
modules/plugins/postfix/src/main/java/org/rhq/plugins/postfix/PostfixServerComponent.java | 61 +++-------
modules/plugins/postfix/src/main/java/org/rhq/plugins/postfix/PostfixServerDiscoveryComponent.java | 41 ++++--
modules/plugins/postfix/src/main/resources/META-INF/rhq-plugin.xml | 4
modules/plugins/postfix/src/test/java/org/rhq/plugins/postfix/PostfixComponentTest.java | 8 -
5 files changed, 72 insertions(+), 65 deletions(-)
New commits:
commit abc2065d98ddcfc1dde13f116190c63db70d9122
Author: Thomas Segismont <tsegismo(a)redhat.com>
Date: Thu Aug 8 17:02:15 2013 +0200
Bug 994640 - Postfix Server's Banner basic configuration property "default" value is empty
Banner property is no longer required
Additionally, Postfix server resource type now has a process scan (component and discovery component updated). This allows Postfix resources:
* to be discovered only if a server is running
* to give a real availability value (always answered UP before)
diff --git a/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/inventory/DiscoveredResourceDetails.java b/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/inventory/DiscoveredResourceDetails.java
index f04c757..25d4d1f 100644
--- a/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/inventory/DiscoveredResourceDetails.java
+++ b/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/inventory/DiscoveredResourceDetails.java
@@ -1,29 +1,26 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2012 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, version 2, as
- * published by the Free Software Foundation, and/or the GNU Lesser
- * General Public License, version 2.1, also as published by the Free
- * Software Foundation.
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License and the GNU Lesser General Public License
- * for more details.
+ * GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * and the GNU Lesser General Public License along with this program;
- * if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
package org.rhq.core.pluginapi.inventory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.configuration.definition.ConfigurationDefinition;
import org.rhq.core.domain.configuration.definition.ConfigurationTemplate;
@@ -276,6 +273,10 @@ public class DiscoveredResourceDetails {
return processInfo;
}
+ public void setProcessInfo(ProcessInfo processInfo) {
+ this.processInfo = processInfo;
+ }
+
/**
* Defines the discovered resource's plugin configuration. You normally call {@link #getPluginConfiguration()} first
* to get a copy of the resource's default plugin configuration, and then modify that default configuration with
@@ -359,4 +360,4 @@ public class DiscoveredResourceDetails {
// There is no default plugin config template defined - return an empty one.
return new Configuration();
}
-}
\ No newline at end of file
+}
diff --git a/modules/plugins/postfix/src/main/java/org/rhq/plugins/postfix/PostfixServerComponent.java b/modules/plugins/postfix/src/main/java/org/rhq/plugins/postfix/PostfixServerComponent.java
index 7a91c24..484b0cd 100644
--- a/modules/plugins/postfix/src/main/java/org/rhq/plugins/postfix/PostfixServerComponent.java
+++ b/modules/plugins/postfix/src/main/java/org/rhq/plugins/postfix/PostfixServerComponent.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,11 +13,14 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
package org.rhq.plugins.postfix;
+import static org.rhq.core.domain.measurement.AvailabilityType.DOWN;
+import static org.rhq.core.domain.measurement.AvailabilityType.UP;
+
import net.augeas.Augeas;
import org.rhq.core.domain.configuration.Configuration;
@@ -27,24 +30,38 @@ import org.rhq.core.domain.configuration.definition.PropertySimpleType;
import org.rhq.core.domain.measurement.AvailabilityType;
import org.rhq.core.pluginapi.configuration.ConfigurationUpdateReport;
import org.rhq.core.pluginapi.inventory.ResourceContext;
+import org.rhq.core.system.ProcessInfo;
+import org.rhq.core.system.ProcessInfo.ProcessInfoSnapshot;
import org.rhq.plugins.augeas.AugeasConfigurationComponent;
import org.rhq.plugins.augeas.helper.AugeasNode;
-/**
- * TODO
- */
public class PostfixServerComponent extends AugeasConfigurationComponent {
+ private ProcessInfo processInfo;
+
public void start(ResourceContext resourceContext) throws Exception {
super.start(resourceContext);
+ processInfo = resourceContext.getNativeProcess();
}
public void stop() {
+ processInfo = null;
super.stop();
}
public AvailabilityType getAvailability() {
- return super.getAvailability();
+ ProcessInfoSnapshot processInfoSnapshot = getProcessInfoSnapshot();
+ return (processInfoSnapshot != null && processInfoSnapshot.isRunning()) ? UP : DOWN;
+ }
+
+ private ProcessInfoSnapshot getProcessInfoSnapshot() {
+ ProcessInfoSnapshot processInfoSnapshot = (processInfo == null) ? null : processInfo.freshSnapshot();
+ if (processInfoSnapshot == null || !processInfoSnapshot.isRunning()) {
+ processInfo = getResourceContext().getNativeProcess();
+ // Safe to get prior snapshot here, we've just recreated the process info instance
+ processInfoSnapshot = (processInfo == null) ? null : processInfo.priorSnaphot();
+ }
+ return processInfoSnapshot;
}
public Configuration loadResourceConfiguration() throws Exception {
@@ -74,34 +91,4 @@ public class PostfixServerComponent extends AugeasConfigurationComponent {
return super.toNodeValue(augeas, node, propDefSimple, propSimple);
}
- /*
-
- @Override
- public CreateResourceReport createResource(CreateResourceReport reportIn) {
- CreateResourceReport report = reportIn;
- Configuration config = report.getResourceConfiguration();
- String name = config.getSimple(SambaShareComponent.NAME_RESOURCE_CONFIG_PROP).getStringValue();
- report.setResourceKey(name);
- report.setResourceName(name);
- return super.createResource(report);
- }
- @Override
- protected String getChildResourceConfigurationRootPath(ResourceType resourceType, Configuration resourceConfig) {
- if (resourceType.getName().equals(SambaShareComponent.RESOURCE_TYPE_NAME)) {
- String targetName = resourceConfig.getSimple(SambaShareComponent.NAME_RESOURCE_CONFIG_PROP).getStringValue();
- return "/files/etc/samba/smb.conf/target[.='" + targetName + "']";
- } else {
- throw new IllegalArgumentException("Unsupported child Resource type: " + resourceType);
- }
- }
- @Override
- protected String getChildResourceConfigurationRootLabel(ResourceType resourceType, Configuration resourceConfig) {
- if (resourceType.getName().equals(SambaShareComponent.RESOURCE_TYPE_NAME)) {
- return resourceConfig.getSimple(SambaShareComponent.NAME_RESOURCE_CONFIG_PROP).getStringValue();
- } else {
- throw new IllegalArgumentException("Unsupported child Resource type: " + resourceType);
- }
- }
- */
-
}
diff --git a/modules/plugins/postfix/src/main/java/org/rhq/plugins/postfix/PostfixServerDiscoveryComponent.java b/modules/plugins/postfix/src/main/java/org/rhq/plugins/postfix/PostfixServerDiscoveryComponent.java
index 91490c0..3f42da5 100644
--- a/modules/plugins/postfix/src/main/java/org/rhq/plugins/postfix/PostfixServerDiscoveryComponent.java
+++ b/modules/plugins/postfix/src/main/java/org/rhq/plugins/postfix/PostfixServerDiscoveryComponent.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,34 +13,50 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
package org.rhq.plugins.postfix;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStreamReader;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails;
import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException;
+import org.rhq.core.pluginapi.inventory.ProcessScanResult;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext;
import org.rhq.core.util.stream.StreamUtil;
import org.rhq.plugins.augeas.AugeasConfigurationComponent;
import org.rhq.plugins.augeas.AugeasConfigurationDiscoveryComponent;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.InputStreamReader;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
public class PostfixServerDiscoveryComponent extends AugeasConfigurationDiscoveryComponent {
+ private static final Log LOG = LogFactory.getLog(PostfixServerDiscoveryComponent.class);
+
private static final Pattern HOSTNAME_PATTERN = Pattern.compile("[\\s]*myhostname[\\s]*=[\\s]*([^$].*)[\\s]*");
public Set discoverResources(ResourceDiscoveryContext resourceDiscoveryContext)
- throws InvalidPluginConfigurationException, Exception {
+ throws InvalidPluginConfigurationException, Exception {
+ List discoveredProcesses = resourceDiscoveryContext.getAutoDiscoveredProcesses();
+ if (discoveredProcesses.isEmpty()) {
+ return Collections.emptySet();
+ }
+ if (discoveredProcesses.size() != 1) {
+ LOG.warn("Found more than one Postfix process running");
+ return Collections.emptySet();
+ }
Set<DiscoveredResourceDetails> resources = super.discoverResources(resourceDiscoveryContext);
for (DiscoveredResourceDetails detail : resources) {
Configuration config = detail.getPluginConfiguration();
@@ -54,6 +70,7 @@ public class PostfixServerDiscoveryComponent extends AugeasConfigurationDiscover
resourceName = resourceDiscoveryContext.getSystemInformation().getHostname();
}
detail.setResourceName(resourceName);
+ detail.setProcessInfo(((ProcessScanResult) discoveredProcesses.get(0)).getProcessInfo());
}
return resources;
}
diff --git a/modules/plugins/postfix/src/main/resources/META-INF/rhq-plugin.xml b/modules/plugins/postfix/src/main/resources/META-INF/rhq-plugin.xml
index 00366ff..3831fa8 100644
--- a/modules/plugins/postfix/src/main/resources/META-INF/rhq-plugin.xml
+++ b/modules/plugins/postfix/src/main/resources/META-INF/rhq-plugin.xml
@@ -28,6 +28,8 @@
default="/files/etc/postfix/main.cf"/>
</plugin-configuration>
+ <process-scan query="process|name|match=.*postfix/master.*" />
+
<resource-configuration>
<c:group name="Basic Configurations">
<c:simple-property displayName="Hostname" name="myhostname" description="Server's fully qualified domain name" required="false"/>
@@ -35,7 +37,7 @@
<c:simple-property displayName="Networks" name="mynetworks" description="List of clients that can relay mail" required="false"/>
<c:simple-property displayName="Destinations" name="mydestination" description="Space delimited list of domains for which server will accept delivered. Postfix must be restarted." required="false"/>
<c:simple-property displayName="Interfaces" name="inet_interfaces" description="Network interfaces that Postfix will bind to" required="false"/>
- <c:simple-property displayName="Banner" name="smtpd_banner" description="SMTP Banner (RFC requires hostname and ESMTP prompt)" default="$myhostname ESMTP" required="true"/>
+ <c:simple-property displayName="Banner" name="smtpd_banner" description="SMTP Banner (RFC requires hostname and ESMTP prompt)" default="$myhostname ESMTP" required="false"/>
</c:group>
<c:group name="Security">
<c:simple-property displayName="Suppress VRFY" name="disable_vrfy_command" type="boolean" default="true" required="false" description="Supress Response to SMTP VRFY requests by default"/>
diff --git a/modules/plugins/postfix/src/test/java/org/rhq/plugins/postfix/PostfixComponentTest.java b/modules/plugins/postfix/src/test/java/org/rhq/plugins/postfix/PostfixComponentTest.java
index 6724673..da271b2 100644
--- a/modules/plugins/postfix/src/test/java/org/rhq/plugins/postfix/PostfixComponentTest.java
+++ b/modules/plugins/postfix/src/test/java/org/rhq/plugins/postfix/PostfixComponentTest.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,8 +13,8 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
package org.rhq.plugins.postfix;
@@ -23,7 +23,7 @@ import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.plugins.augeas.test.AbstractAugeasConfigurationComponentTest;
/**
- * An integration test for {@link PostfixComponent}.
+ * An integration test for {@link PostfixServerComponent}.
*/
public class PostfixComponentTest extends AbstractAugeasConfigurationComponentTest {
@Override
10 years, 10 months
[rhq] 3 commits - modules/core modules/enterprise
by snegrea
modules/core/domain/src/main/java/org/rhq/core/domain/cloud/Server.java | 43 ++-
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/topology/ServerTableView.java | 8
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/TopologyGWTService.java | 2
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/TopologyGWTServiceImpl.java | 6
modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/ha/ListServersUIBean.java | 20 +
modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/test/AbstractEJB3Test.java | 2
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerBean.java | 75 ++---
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/TopologyManagerBean.java | 27 +-
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/TopologyManagerLocal.java | 13 -
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/instance/ServerManagerBean.java | 67 +++--
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/StartupBean.java | 11
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/storage/StorageClientManagerBean.java | 22 +
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/storage/StorageClusterHeartBeatJob.java | 126 ----------
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/storage/StorageClusterMonitor.java | 39 ---
modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/Commands.java | 2
modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Restart.java | 69 +++++
modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/StorageSession.java | 8
17 files changed, 271 insertions(+), 269 deletions(-)
New commits:
commit 261efe8c0dd989e2dfda61a496d37d6ae23acbab
Author: Stefan Negrea <snegrea(a)redhat.com>
Date: Thu Aug 8 00:48:47 2013 -0500
Fix rebase issues due to git merge tree.
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerBean.java
index 423218a..ba94bb7 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerBean.java
@@ -28,8 +28,8 @@ import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Date;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@@ -46,15 +46,11 @@ import javax.persistence.TypedQuery;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.quartz.JobDataMap;
-import org.quartz.SimpleTrigger;
-import org.quartz.Trigger;
import org.rhq.cassandra.schema.SchemaManager;
import org.rhq.core.domain.alert.Alert;
import org.rhq.core.domain.auth.Subject;
import org.rhq.core.domain.authz.Permission;
-import org.rhq.core.domain.cloud.Server;
import org.rhq.core.domain.cloud.StorageNode;
import org.rhq.core.domain.cloud.StorageNode.OperationMode;
import org.rhq.core.domain.cloud.StorageNodeConfigurationComposite;
@@ -69,6 +65,7 @@ import org.rhq.core.domain.criteria.ResourceOperationHistoryCriteria;
import org.rhq.core.domain.criteria.StorageNodeCriteria;
import org.rhq.core.domain.measurement.MeasurementAggregate;
import org.rhq.core.domain.measurement.MeasurementUnits;
+import org.rhq.core.domain.measurement.composite.MeasurementDataNumericHighLowComposite;
import org.rhq.core.domain.operation.OperationRequestStatus;
import org.rhq.core.domain.operation.ResourceOperationHistory;
import org.rhq.core.domain.operation.bean.GroupOperationSchedule;
@@ -85,7 +82,6 @@ import org.rhq.enterprise.server.alert.AlertManagerLocal;
import org.rhq.enterprise.server.auth.SubjectManagerLocal;
import org.rhq.enterprise.server.authz.RequiredPermission;
import org.rhq.enterprise.server.authz.RequiredPermissions;
-import org.rhq.enterprise.server.cloud.instance.ServerManagerLocal;
import org.rhq.enterprise.server.configuration.ConfigurationManagerLocal;
import org.rhq.enterprise.server.measurement.MeasurementDataManagerLocal;
import org.rhq.enterprise.server.operation.OperationManagerLocal;
@@ -94,8 +90,8 @@ import org.rhq.enterprise.server.resource.ResourceTypeManagerLocal;
import org.rhq.enterprise.server.resource.group.ResourceGroupManagerLocal;
import org.rhq.enterprise.server.rest.reporting.MeasurementConverter;
import org.rhq.enterprise.server.scheduler.SchedulerLocal;
-import org.rhq.enterprise.server.scheduler.jobs.StorageNodeMaintenanceJob;
-import org.rhq.enterprise.server.storage.StorageConfigurationException;
+import org.rhq.enterprise.server.storage.StorageClusterSettings;
+import org.rhq.enterprise.server.storage.StorageClusterSettingsManagerBean;
import org.rhq.enterprise.server.util.CriteriaQueryGenerator;
import org.rhq.enterprise.server.util.CriteriaQueryRunner;
import org.rhq.enterprise.server.util.LookupUtil;
@@ -118,6 +114,7 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
private final static String SEEDS_LIST = "seedsList";
private static final String RHQ_STORAGE_CQL_PORT_PROPERTY = "nativeTransportPort";
+ private static final String RHQ_STORAGE_GOSSIP_PORT_PROPERTY = "storagePort";
private static final String RHQ_STORAGE_JMX_PORT_PROPERTY = "jmxPort";
private static final String RHQ_STORAGE_ADDRESS_PROPERTY = "host";
@@ -126,6 +123,18 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
private static final String UPDATE_CONFIGURATION_OPERATION = "updateConfiguration";
private static final String RESTART_OPERATION = "restart";
+ // metric names on Storage Service resource
+ private static final String METRIC_TOKENS = "Tokens", METRIC_OWNERSHIP = "Ownership";
+ private static final String METRIC_DATA_DISK_USED_PERCENTAGE = "Calculated.DataDiskUsedPercentage";
+ private static final String METRIC_TOTAL_DISK_USED_PERCENTAGE = "Calculated.TotalDiskUsedPercentage";
+ private static final String METRIC_FREE_DISK_TO_DATA_RATIO = "Calculated.FreeDiskToDataSizeRatio";
+ private static final String METRIC_LOAD = "Load", METRIC_KEY_CACHE_SIZE = "KeyCacheSize",
+ METRIC_ROW_CACHE_SIZE = "RowCacheSize", METRIC_TOTAL_COMMIT_LOG_SIZE = "TotalCommitlogSize";
+
+ //metric names on Memory Subsystem resource
+ private static final String METRIC_HEAP_COMMITED = "{HeapMemoryUsage.committed}",
+ METRIC_HEAP_USED = "{HeapMemoryUsage.used}", METRIC_HEAP_USED_PERCENTAGE = "Calculated.HeapUsagePercentage";
+
@PersistenceContext(unitName = RHQConstants.PERSISTENCE_UNIT_NAME)
private EntityManager entityManager;
@@ -159,10 +168,13 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
@EJB
private ResourceManagerLocal resourceManager;
+ @EJB
+ private StorageClusterSettingsManagerBean storageClusterSettingsManager;
+
@Override
public void linkResource(Resource resource) {
- Configuration resourceConfig = resource.getPluginConfiguration();
- String address = resourceConfig.getSimpleValue(RHQ_STORAGE_ADDRESS_PROPERTY);
+ Configuration pluginConfig = resource.getPluginConfiguration();
+ String address = pluginConfig.getSimpleValue(RHQ_STORAGE_ADDRESS_PROPERTY);
if (log.isInfoEnabled()) {
log.info("Linking " + resource + " to storage node at " + address);
@@ -176,12 +188,13 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
}
storageNode.setResource(resource);
storageNode.setOperationMode(OperationMode.NORMAL);
+ initClusterSettingsIfNecessary(pluginConfig);
addStorageNodeToGroup(resource);
} else {
storageNode = new StorageNode();
storageNode.setAddress(address);
- storageNode.setCqlPort(Integer.parseInt(resourceConfig.getSimpleValue(RHQ_STORAGE_CQL_PORT_PROPERTY)));
- storageNode.setJmxPort(Integer.parseInt(resourceConfig.getSimpleValue(RHQ_STORAGE_JMX_PORT_PROPERTY)));
+ storageNode.setCqlPort(Integer.parseInt(pluginConfig.getSimpleValue(RHQ_STORAGE_CQL_PORT_PROPERTY)));
+ storageNode.setJmxPort(Integer.parseInt(pluginConfig.getSimpleValue(RHQ_STORAGE_JMX_PORT_PROPERTY)));
storageNode.setResource(resource);
storageNode.setOperationMode(OperationMode.INSTALLED);
@@ -200,6 +213,31 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
}
}
+ private void initClusterSettingsIfNecessary(Configuration pluginConfig) {
+ // TODO Need to handle non-repeatable reads here (probably a post 4.9 task)
+ //
+ // If a user deploys two storage nodes prior to installing the RHQ server, then we
+ // could end up in this method concurrently for both storage nodes. The settings
+ // would be committed for each node with the second commit winning. The problem is
+ // that is the cluster settings differ for the two nodes, it will be silently
+ // ignored. This scenario will happen infrequently so it should be sufficient to
+ // resolve it with optimistic locking. The second writer should fail with an
+ // OptimisticLockException.
+
+ log.info("Initializing storage cluster settings");
+
+ StorageClusterSettings clusterSettings = storageClusterSettingsManager.getClusterSettings(subjectManager
+ .getOverlord());
+ if (clusterSettings != null) {
+ log.info("Cluster settings have already been set. Skipping initialization.");
+ return;
+ }
+ clusterSettings = new StorageClusterSettings();
+ clusterSettings.setCqlPort(Integer.parseInt(pluginConfig.getSimpleValue(RHQ_STORAGE_CQL_PORT_PROPERTY)));
+ clusterSettings.setGossipPort(Integer.parseInt(pluginConfig.getSimpleValue(RHQ_STORAGE_GOSSIP_PORT_PROPERTY)));
+ storageClusterSettingsManager.setClusterSettings(subjectManager.getOverlord(), clusterSettings);
+ }
+
private void announceNewNode(StorageNode newStorageNode) {
if (log.isInfoEnabled()) {
log.info("Announcing " + newStorageNode + " to storage node cluster.");
@@ -321,106 +359,90 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
int resourceId = getResourceIdFromStorageNode(node);
Map<String, Integer> scheduleIdsMap = new HashMap<String, Integer>();
- // get the schedule ids for Storage Service resource
- final String tokensMetric = "Tokens", ownershipMetric = "Ownership";
- final String dataDiskUsedPercentageMetric = "Calculated.DataDiskUsedPercentage";
- final String totalDiskUsedPercentageMetric = "Calculated.TotalDiskUsedPercentage";
- final String freeDiskToDataRatioMetric = "Calculated.FreeDiskToDataSizeRatio";
- final String loadMetric = "Load", keyCacheSize = "KeyCacheSize", rowCacheSize = "RowCacheSize", totalCommitLogSize = "TotalCommitlogSize";
- TypedQuery<Object[]> query = entityManager.<Object[]> createNamedQuery(
- StorageNode.QUERY_FIND_SCHEDULE_IDS_BY_PARENT_RESOURCE_ID_AND_MEASUREMENT_DEFINITION_NAMES, Object[].class);
- query.setParameter("parrentId", resourceId).setParameter("metricNames",
- Arrays.asList(tokensMetric, ownershipMetric, loadMetric, keyCacheSize, rowCacheSize, totalCommitLogSize,
- dataDiskUsedPercentageMetric, totalDiskUsedPercentageMetric, freeDiskToDataRatioMetric));
- for (Object[] pair : query.getResultList()) {
- scheduleIdsMap.put((String) pair[0], (Integer) pair[1]);
+ for (Object[] tupple : getStorageServiceScheduleIds(resourceId)) {
+ String definitionName = (String) tupple[0];
+ Integer scheduleId = (Integer) tupple[2];
+ scheduleIdsMap.put(definitionName, scheduleId);
}
-
- // get the schedule ids for Memory Subsystem resource
- final String heapCommittedMetric = "{HeapMemoryUsage.committed}", heapUsedMetric = "{HeapMemoryUsage.used}", heapUsedPercentageMetric = "Calculated.HeapUsagePercentage";
- query = entityManager.<Object[]> createNamedQuery(
- StorageNode.QUERY_FIND_SCHEDULE_IDS_BY_GRANDPARENT_RESOURCE_ID_AND_MEASUREMENT_DEFINITION_NAMES,
- Object[].class);
- query.setParameter("grandparrentId", resourceId).setParameter("metricNames",
- Arrays.asList(heapCommittedMetric, heapUsedMetric, heapUsedPercentageMetric));
- for (Object[] pair : query.getResultList()) {
- scheduleIdsMap.put((String) pair[0], (Integer) pair[1]);
+ for (Object[] tupple : getMemorySubsystemScheduleIds(resourceId)) {
+ String definitionName = (String) tupple[0];
+ Integer scheduleId = (Integer) tupple[2];
+ scheduleIdsMap.put(definitionName, scheduleId);
}
-
StorageNodeLoadComposite result = new StorageNodeLoadComposite(node, beginTime, endTime);
- MeasurementAggregate totalDiskUsedaggregate = new MeasurementAggregate(0d, 0d, 0d);
+ MeasurementAggregate totalDiskUsedAggregate = new MeasurementAggregate(0d, 0d, 0d);
Integer scheduleId = null;
// find the aggregates and enrich the result instance
if (!scheduleIdsMap.isEmpty()) {
- if ((scheduleId = scheduleIdsMap.get(tokensMetric)) != null) {
+ if ((scheduleId = scheduleIdsMap.get(METRIC_TOKENS)) != null) {
MeasurementAggregate tokensAggregate = measurementManager.getAggregate(subject, scheduleId, beginTime,
endTime);
result.setTokens(tokensAggregate);
}
- if ((scheduleId = scheduleIdsMap.get(ownershipMetric)) != null) {
+ if ((scheduleId = scheduleIdsMap.get(METRIC_OWNERSHIP)) != null) {
StorageNodeLoadComposite.MeasurementAggregateWithUnits ownershipAggregateWithUnits = getMeasurementAggregateWithUnits(
subject, scheduleId, MeasurementUnits.PERCENTAGE, beginTime, endTime);
result.setActuallyOwns(ownershipAggregateWithUnits);
}
//calculated disk space related metrics
- if ((scheduleId = scheduleIdsMap.get(dataDiskUsedPercentageMetric)) != null) {
+ if ((scheduleId = scheduleIdsMap.get(METRIC_DATA_DISK_USED_PERCENTAGE)) != null) {
StorageNodeLoadComposite.MeasurementAggregateWithUnits dataDiskUsedPercentageAggregateWithUnits = getMeasurementAggregateWithUnits(
subject, scheduleId, MeasurementUnits.PERCENTAGE, beginTime, endTime);
result.setDataDiskUsedPercentage(dataDiskUsedPercentageAggregateWithUnits);
}
- if ((scheduleId = scheduleIdsMap.get(totalDiskUsedPercentageMetric)) != null) {
+ if ((scheduleId = scheduleIdsMap.get(METRIC_TOTAL_DISK_USED_PERCENTAGE)) != null) {
StorageNodeLoadComposite.MeasurementAggregateWithUnits totalDiskUsedPercentageAggregateWithUnits = getMeasurementAggregateWithUnits(
subject, scheduleId, MeasurementUnits.PERCENTAGE, beginTime, endTime);
result.setTotalDiskUsedPercentage(totalDiskUsedPercentageAggregateWithUnits);
}
- if ((scheduleId = scheduleIdsMap.get(freeDiskToDataRatioMetric)) != null) {
+ if ((scheduleId = scheduleIdsMap.get(METRIC_FREE_DISK_TO_DATA_RATIO)) != null) {
MeasurementAggregate freeDiskToDataRatioAggregate = measurementManager.getAggregate(subject,
scheduleId, beginTime, endTime);
result.setFreeDiskToDataSizeRatio(freeDiskToDataRatioAggregate);
}
- if ((scheduleId = scheduleIdsMap.get(loadMetric)) != null) {
+ if ((scheduleId = scheduleIdsMap.get(METRIC_LOAD)) != null) {
StorageNodeLoadComposite.MeasurementAggregateWithUnits loadAggregateWithUnits = getMeasurementAggregateWithUnits(
subject, scheduleId, MeasurementUnits.BYTES, beginTime, endTime);
result.setLoad(loadAggregateWithUnits);
- updateAggregateTotal(totalDiskUsedaggregate, loadAggregateWithUnits.getAggregate());
- }
- if ((scheduleId = scheduleIdsMap.get(keyCacheSize)) != null) {
- updateAggregateTotal(totalDiskUsedaggregate,
- measurementManager.getAggregate(subject, scheduleId, beginTime, endTime));
- }
- if ((scheduleId = scheduleIdsMap.get(rowCacheSize)) != null) {
- updateAggregateTotal(totalDiskUsedaggregate,
- measurementManager.getAggregate(subject, scheduleId, beginTime, endTime));
+ updateAggregateTotal(totalDiskUsedAggregate, loadAggregateWithUnits.getAggregate());
}
- if ((scheduleId = scheduleIdsMap.get(totalCommitLogSize)) != null) {
- updateAggregateTotal(totalDiskUsedaggregate,
- measurementManager.getAggregate(subject, scheduleId, beginTime, endTime));
- }
-
- if (totalDiskUsedaggregate.getMax() > 0) {
+ // if ((scheduleId = scheduleIdsMap.get(METRIC_KEY_CACHE_SIZE)) != null) {
+ // updateAggregateTotal(totalDiskUsedAggregate,
+ // measurementManager.getAggregate(subject, scheduleId, beginTime, endTime));
+ // }
+ // if ((scheduleId = scheduleIdsMap.get(METRIC_ROW_CACHE_SIZE)) != null) {
+ // updateAggregateTotal(totalDiskUsedAggregate,
+ // measurementManager.getAggregate(subject, scheduleId, beginTime, endTime));
+ // }
+ // if ((scheduleId = scheduleIdsMap.get(METRIC_TOTAL_COMMIT_LOG_SIZE)) != null) {
+ // updateAggregateTotal(totalDiskUsedAggregate,
+ // measurementManager.getAggregate(subject, scheduleId, beginTime, endTime));
+ // }
+
+ if (totalDiskUsedAggregate.getMax() > 0) {
StorageNodeLoadComposite.MeasurementAggregateWithUnits totalDiskUsedAggregateWithUnits = new StorageNodeLoadComposite.MeasurementAggregateWithUnits(
- totalDiskUsedaggregate, MeasurementUnits.BYTES);
- totalDiskUsedAggregateWithUnits.setFormattedValue(getSummaryString(totalDiskUsedaggregate,
+ totalDiskUsedAggregate, MeasurementUnits.BYTES);
+ totalDiskUsedAggregateWithUnits.setFormattedValue(getSummaryString(totalDiskUsedAggregate,
MeasurementUnits.BYTES));
result.setDataDiskUsed(totalDiskUsedAggregateWithUnits);
}
- if ((scheduleId = scheduleIdsMap.get(heapCommittedMetric)) != null) {
+ if ((scheduleId = scheduleIdsMap.get(METRIC_HEAP_COMMITED)) != null) {
StorageNodeLoadComposite.MeasurementAggregateWithUnits heapCommittedAggregateWithUnits = getMeasurementAggregateWithUnits(
subject, scheduleId, MeasurementUnits.BYTES, beginTime, endTime);
result.setHeapCommitted(heapCommittedAggregateWithUnits);
}
- if ((scheduleId = scheduleIdsMap.get(heapUsedMetric)) != null) {
+ if ((scheduleId = scheduleIdsMap.get(METRIC_HEAP_USED)) != null) {
StorageNodeLoadComposite.MeasurementAggregateWithUnits heapUsedAggregateWithUnits = getMeasurementAggregateWithUnits(
subject, scheduleId, MeasurementUnits.BYTES, beginTime, endTime);
result.setHeapUsed(heapUsedAggregateWithUnits);
}
- if ((scheduleId = scheduleIdsMap.get(heapUsedPercentageMetric)) != null) {
+ if ((scheduleId = scheduleIdsMap.get(METRIC_HEAP_USED_PERCENTAGE)) != null) {
StorageNodeLoadComposite.MeasurementAggregateWithUnits heapUsedPercentageAggregateWithUnits = getMeasurementAggregateWithUnits(
subject, scheduleId, MeasurementUnits.PERCENTAGE, beginTime,
endTime);
@@ -431,6 +453,28 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
return result;
}
+ private List<Object[]> getStorageServiceScheduleIds(int storageNodeResourceId) {
+ // get the schedule ids for Storage Service resource
+ TypedQuery<Object[]> query = entityManager.<Object[]> createNamedQuery(
+ StorageNode.QUERY_FIND_SCHEDULE_IDS_BY_PARENT_RESOURCE_ID_AND_MEASUREMENT_DEFINITION_NAMES, Object[].class);
+ query.setParameter("parrentId", storageNodeResourceId).setParameter(
+ "metricNames",
+ Arrays.asList(METRIC_TOKENS, METRIC_OWNERSHIP,
+ METRIC_LOAD/*, METRIC_KEY_CACHE_SIZE, METRIC_ROW_CACHE_SIZE, METRIC_TOTAL_COMMIT_LOG_SIZE*/,
+ METRIC_DATA_DISK_USED_PERCENTAGE, METRIC_TOTAL_DISK_USED_PERCENTAGE, METRIC_FREE_DISK_TO_DATA_RATIO));
+ return query.getResultList();
+ }
+
+ private List<Object[]> getMemorySubsystemScheduleIds(int storageNodeResourceId) {
+ // get the schedule ids for Memory Subsystem resource
+ TypedQuery<Object[]> query = entityManager.<Object[]> createNamedQuery(
+ StorageNode.QUERY_FIND_SCHEDULE_IDS_BY_GRANDPARENT_RESOURCE_ID_AND_MEASUREMENT_DEFINITION_NAMES,
+ Object[].class);
+ query.setParameter("grandparrentId", storageNodeResourceId).setParameter("metricNames",
+ Arrays.asList(METRIC_HEAP_COMMITED, METRIC_HEAP_USED, METRIC_HEAP_USED_PERCENTAGE));
+ return query.getResultList();
+ }
+
/**
* @param accumulator
* @param input
@@ -453,6 +497,21 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
return query.getResultList();
}
+ @Override
+ public PageList<StorageNodeLoadComposite> getStorageNodeComposites() {
+ List<StorageNode> nodes = getStorageNodes();
+ PageList<StorageNodeLoadComposite> result = new PageList<StorageNodeLoadComposite>();
+ long endTime = System.currentTimeMillis();
+ long beginTime = endTime - (8 * 60 * 60 * 1000);
+ for (StorageNode node : nodes) {
+ StorageNodeLoadComposite composite = getLoad(subjectManager.getOverlord(), node, beginTime, endTime);
+ int unackAlerts = findNotAcknowledgedStorageNodeAlerts(subjectManager.getOverlord(), node).size();
+ composite.setUnackAlerts(unackAlerts);
+ result.add(composite);
+ }
+ return result;
+ }
+
private List<StorageNode> getClusteredStorageNodes() {
return entityManager.createNamedQuery(StorageNode.QUERY_FIND_ALL_BY_MODE, StorageNode.class)
.setParameter("operationMode", OperationMode.NORMAL).getResultList();
@@ -485,12 +544,7 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
@RequiredPermission(Permission.MANAGE_INVENTORY) })
public void prepareNodeForUpgrade(Subject subject, StorageNode storageNode) {
int storageNodeResourceId = getResourceIdFromStorageNode(storageNode);
- TopologyManagerLocal topologyManager = LookupUtil.getTopologyManager();
- ServerManagerLocal serverManager = LookupUtil.getServerManager();
OperationManagerLocal operationManager = LookupUtil.getOperationManager();
- Server server = serverManager.getServer();
- // setting the server mode to maintenance
- topologyManager.updateServerMode(subject, new Integer[] { server.getId() }, Server.OperationMode.MAINTENANCE);
Configuration parameters = new Configuration();
parameters.setSimpleValue("snapshotName", String.valueOf(System.currentTimeMillis()));
@@ -617,12 +671,8 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
if (storageNode == null) {
initialStorageNodes = getStorageNodes();
} else {
- int index = initialStorageNodes.indexOf(storageNode);
- if (index >= 0) {
- initialStorageNodes = Arrays.asList(initialStorageNodes.get(index));
- } else {
- initialStorageNodes = new ArrayList<StorageNode>();
- }
+ initialStorageNodes = Arrays.asList(storageNode.getResource() == null ? entityManager.find(
+ StorageNode.class, storageNode.getId()) : storageNode);
}
Queue<Resource> unvisitedResources = new LinkedList<Resource>();
@@ -740,6 +790,55 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
operationManager.scheduleResourceOperation(subject, schedule);
}
+ @Override
+ @RequiredPermissions({ @RequiredPermission(Permission.MANAGE_SETTINGS),
+ @RequiredPermission(Permission.MANAGE_INVENTORY) })
+ public Map<String, List<MeasurementDataNumericHighLowComposite>> findStorageNodeLoadDataForLast(Subject subject,
+ StorageNode node, long beginTime, long endTime, int numPoints) {
+ int storageNodeResourceId = getResourceIdFromStorageNode(node);
+ Map<String, List<MeasurementDataNumericHighLowComposite>> result = new LinkedHashMap<String, List<MeasurementDataNumericHighLowComposite>>();
+
+ List<Object[]> tupples = getStorageServiceScheduleIds(storageNodeResourceId);
+ List<String> defNames = new ArrayList<String>();
+ int[] definitionIds = new int[tupples.size()];
+ int resId = -1;
+ int index = 0;
+ for (Object[] tupple : tupples) {
+ String defName = (String) tupple[0];
+ int definitionId = (Integer) tupple[1];
+ resId = (Integer) tupple[3];
+ defNames.add(defName);
+ definitionIds[index++] = definitionId;
+ }
+ List<List<MeasurementDataNumericHighLowComposite>> storageServiceData = measurementManager.findDataForResource(
+ subject, resId, definitionIds, beginTime, endTime, numPoints);
+ for (int i = 0; i < storageServiceData.size(); i++) {
+ List<MeasurementDataNumericHighLowComposite> oneRecord = storageServiceData.get(i);
+ result.put(defNames.get(i), oneRecord);
+ }
+
+ tupples = getMemorySubsystemScheduleIds(storageNodeResourceId);
+ defNames = new ArrayList<String>();
+ definitionIds = new int[tupples.size()];
+ resId = -1;
+ index = 0;
+ for (Object[] tupple : tupples) {
+ String defName = (String) tupple[0];
+ int definitionId = (Integer) tupple[1];
+ resId = (Integer) tupple[3];
+ defNames.add(defName);
+ definitionIds[index++] = definitionId;
+ }
+ List<List<MeasurementDataNumericHighLowComposite>> memorySubsystemData = measurementManager
+ .findDataForResource(subject, resId, definitionIds, beginTime, endTime, numPoints);
+ for (int i = 0; i < memorySubsystemData.size(); i++) {
+ List<MeasurementDataNumericHighLowComposite> oneRecord = memorySubsystemData.get(i);
+ result.put(defNames.get(i), oneRecord);
+ }
+
+ return result;
+ }
+
private boolean runOperationAndWaitForResult(Subject subject, Resource storageNodeResource, String operationToRun,
Configuration parameters) {
@@ -807,17 +906,17 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
log.info("Preparing to bootstrap " + storageNode + " into cluster...");
}
- List<StorageNode> existingStorageNodes = getClusteredStorageNodes();
-
ResourceOperationSchedule schedule = new ResourceOperationSchedule();
schedule.setResource(storageNode.getResource());
schedule.setJobTrigger(JobTrigger.createNowTrigger());
schedule.setSubject(subjectManager.getOverlord());
schedule.setOperationName("prepareForBootstrap");
+ StorageClusterSettings clusterSettings = storageClusterSettingsManager.getClusterSettings(subjectManager
+ .getOverlord());
Configuration parameters = new Configuration();
- parameters.put(new PropertySimple("cqlPort", existingStorageNodes.get(0).getCqlPort()));
- parameters.put(new PropertySimple("gossipPort", getGossipPort(storageNode, existingStorageNodes)));
+ parameters.put(new PropertySimple("cqlPort", clusterSettings.getCqlPort()));
+ parameters.put(new PropertySimple("gossipPort", clusterSettings.getGossipPort()));
parameters.put(createPropertyListOfAddresses("storageNodeIPAddresses", getClusteredStorageNodes()));
schedule.setParameters(parameters);
@@ -825,44 +924,6 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
operationManager.scheduleResourceOperation(subjectManager.getOverlord(), schedule);
}
- private Integer getGossipPort(StorageNode newStorageNode, List<StorageNode> storageNodes) {
- if (log.isInfoEnabled()) {
- log.info("Looking up gossip port for new storage node " + newStorageNode);
- }
- try {
- StorageNode node = null;
- Configuration resourceConfig = null;
- for (StorageNode storageNode : storageNodes) {
- resourceConfig = configurationManager.getLiveResourceConfiguration(subjectManager.getOverlord(),
- storageNode.getResource().getId(), false);
- if (resourceConfig == null) {
- log.warn("Failed to load resource configuration for storage node " + newStorageNode.getResource());
- } else {
- node = storageNode;
- break;
- }
- }
- if (resourceConfig == null) {
- log.error("Failed to obtain gossip port from existing storage nodes");
- throw new StorageConfigurationException("Failed to obtain gossip port from existing storage nodes");
- }
-
- PropertySimple property = resourceConfig.getSimple("gossipPort");
- if (property == null) {
- throw new StorageConfigurationException("The resource configuration for " + node.getResource() +
- "did not include the required property [gossipPort]");
- }
- Integer port = property.getIntegerValue();
- log.info("Found gossip port set to " + port);
- return property.getIntegerValue();
- } catch (Exception e) {
- if (e instanceof StorageConfigurationException) {
- throw (StorageConfigurationException) e;
- }
- throw new RuntimeException("An error occurred while trying to obtain the gossip port", e);
- }
- }
-
@Override
public void runAddNodeMaintenance() {
log.info("Preparing to schedule addNodeMaintenance on the storage cluster...");
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/storage/StorageClientManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/storage/StorageClientManagerBean.java
index 83ef02c..ce3a6bd 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/storage/StorageClientManagerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/storage/StorageClientManagerBean.java
@@ -41,11 +41,9 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.rhq.cassandra.util.ClusterBuilder;
-import org.rhq.core.domain.cloud.Server;
import org.rhq.core.domain.cloud.StorageNode;
import org.rhq.core.util.StringUtil;
import org.rhq.enterprise.server.cloud.StorageNodeManagerLocal;
-import org.rhq.enterprise.server.cloud.instance.ServerManagerLocal;
import org.rhq.server.metrics.DateTimeService;
import org.rhq.server.metrics.MetricsConfiguration;
import org.rhq.server.metrics.MetricsDAO;
@@ -66,9 +64,6 @@ public class StorageClientManagerBean {
private static final String RHQ_KEYSPACE = "rhq";
@EJB
- private ServerManagerLocal serverManager;
-
- @EJB
private StorageNodeManagerLocal storageNodeManager;
private StorageSession session;
@@ -149,6 +144,10 @@ public class StorageClientManagerBean {
return this.metricsConfiguration;
}
+ public boolean isClusterAvailable() {
+ return storageClusterMonitor != null && storageClusterMonitor.isClusterAvailable();
+ }
+
private Session createSession(String username, String password, List<StorageNode> storageNodes) {
if (log.isDebugEnabled()) {
log.debug("Initializing session to connect to storage node cluster");
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/storage/StorageClusterMonitor.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/storage/StorageClusterMonitor.java
index 98d40cb..190bfe0 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/storage/StorageClusterMonitor.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/storage/StorageClusterMonitor.java
@@ -8,13 +8,6 @@ import com.datastax.driver.core.exceptions.NoHostAvailableException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.rhq.core.domain.cloud.Server;
-import org.rhq.core.domain.cloud.StorageNode;
-import org.rhq.enterprise.server.auth.SubjectManagerLocal;
-import org.rhq.enterprise.server.cloud.StorageNodeManagerLocal;
-import org.rhq.enterprise.server.cloud.TopologyManagerLocal;
-import org.rhq.enterprise.server.cloud.instance.ServerManagerLocal;
-import org.rhq.enterprise.server.util.LookupUtil;
import org.rhq.server.metrics.StorageStateListener;
/**
@@ -24,10 +17,10 @@ public class StorageClusterMonitor implements StorageStateListener {
private Log log = LogFactory.getLog(StorageClusterMonitor.class);
- private AtomicBoolean isClusterDown = new AtomicBoolean(false);
+ private AtomicBoolean isClusterAvailable = new AtomicBoolean(false);
- public boolean isClusterDown() {
- return isClusterDown.get();
+ public boolean isClusterAvailable() {
+ return isClusterAvailable.get();
}
@Override
@@ -46,7 +39,7 @@ public class StorageClusterMonitor implements StorageStateListener {
log.info("Adding " + newClusterNode + " to storage cluster and scheduling cluster maintenance...");
storageNodeManager.addToStorageNodeGroup(newClusterNode);
storageNodeManager.runAddNodeMaintenance();
- }
+ }*/
}
@Override
commit a4b78eb6e1adeffaa519115a9ef07b3f00025168
Author: Stefan Negrea <snegrea(a)redhat.com>
Date: Wed Aug 7 23:51:04 2013 -0500
Update the operation mode for servers to correctly use storage node cluster information:
1) The maintenance mode set by the user (via UI or properties file) is now stored in the server status bitmask
2) The transition between Maintenance and Normal operation modes is done automatically.
3) The transition between Maintenance and Normal operation modes depends on storage node cluster availability and set user maintenance mode status.
4) Cleanup the lifecycles and state transitions for the storage node client manager, server manager bean, and startup bean.
5) Updated the UI to make use newly added methods that control only the user set maintenance mode status.
Also included various other updates....
diff --git a/modules/core/domain/src/main/java/org/rhq/core/domain/cloud/Server.java b/modules/core/domain/src/main/java/org/rhq/core/domain/cloud/Server.java
index e755597..c43a234 100644
--- a/modules/core/domain/src/main/java/org/rhq/core/domain/cloud/Server.java
+++ b/modules/core/domain/src/main/java/org/rhq/core/domain/cloud/Server.java
@@ -235,20 +235,26 @@ public class Server implements Serializable {
public enum OperationMode {
- DOWN("This server is down member of the HA server cloud"), //
- INSTALLED("This server is newly installed but not yet fully operating"), //
- MAINTENANCE("This server is a Maintenance Mode member of the HA server cloud"), //
- NORMAL("This server is a Normal Member of the HA server cloud");
+ DOWN("This server is down member of the HA server cloud", true), //
+ INSTALLED("This server is newly installed but not yet fully operating", true), //
+ MAINTENANCE("This server is a Maintenance Mode member of the HA server cloud", false), //
+ NORMAL("This server is a Normal Member of the HA server cloud", true);
public final String message;
+ private final boolean configurable;
- private OperationMode(String message) {
+ private OperationMode(String message, boolean configurable) {
this.message = message;
+ this.configurable = configurable;
}
public String getMessage() {
return message;
}
+
+ public boolean isConfigurable() {
+ return configurable;
+ }
}
public List<Agent> getAgents() {
@@ -279,13 +285,22 @@ public class Server implements Serializable {
}
/**
- * If this status was non-zero, some scheduled job would have had to come along to perform
- * some work on behalf of this server. After that work is complete, the status can be reset
- * (set to 0) signifying that no further work needs to be done on this server (as long as the
- * status remains 0).
+ * Verifies if bitmask status is set.
+ *
+ * @param queryStatus status
+ * @return true if status set, false otherwise
+ */
+ public boolean hasStatus(Status queryStatus) {
+ return (this.status & queryStatus.mask) == queryStatus.mask;
+ }
+
+ /**
+ * Clears the specified bitmask status.
+ *
+ * @param removeStatus status to be removed
*/
- public void clearStatus() {
- status = 0;
+ public void clearStatus(Status removeStatus) {
+ this.status &= ~removeStatus.mask;
}
/**
@@ -298,6 +313,9 @@ public class Server implements Serializable {
this.status |= newStatus.mask;
}
+ /**
+ * @return list all messages for the status mask
+ */
public List<String> getStatusMessages() {
return Status.getMessages(status);
}
@@ -305,7 +323,8 @@ public class Server implements Serializable {
public enum Status {
RESOURCE_HIERARCHY_UPDATED(1, "The resource hierarchy has been updated"), //
- ALERT_DEFINITION(2, "Some alert definition with a global condition category was updated");
+ ALERT_DEFINITION(2, "Some alert definition with a global condition category was updated"),
+ MANUAL_MAINTENANCE_MODE(4,"Manual Maintenance mode setup by the user either via UI or properties file.");
public final int mask;
public final String message;
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/topology/ServerTableView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/topology/ServerTableView.java
index c46c925..77aee3d 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/topology/ServerTableView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/topology/ServerTableView.java
@@ -153,11 +153,6 @@ public class ServerTableView extends
return new ServerDetailView(id);
}
- // @Override
- // public abstract void showDetails(ID id) {
- //
- // }
-
private void showCommonActions() {
addChangeOperationModeAction(OperationMode.NORMAL, MSG.view_adminTopology_server_setNormal());
addChangeOperationModeAction(OperationMode.MAINTENANCE, MSG.view_adminTopology_server_setMaintenance());
@@ -204,7 +199,8 @@ public class ServerTableView extends
public void execute(Boolean confirmed) {
if (confirmed) {
int[] selectedIds = getSelectedIds(selections);
- GWTServiceLookup.getTopologyService().updateServerMode(selectedIds, mode,
+ boolean manualMaintenance = mode == OperationMode.MAINTENANCE;
+ GWTServiceLookup.getTopologyService().updateServerManualMaintenance(selectedIds, manualMaintenance,
new AsyncCallback<Void>() {
public void onSuccess(Void result) {
Message msg = new Message(MSG.view_adminTopology_message_setMode(
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/TopologyGWTService.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/TopologyGWTService.java
index 8fa364d..ef193da 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/TopologyGWTService.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/TopologyGWTService.java
@@ -72,7 +72,7 @@ public interface TopologyGWTService extends RemoteService {
* @param mode the new operation mode
* @throws RuntimeException
*/
- void updateServerMode(int[] serverIds, Server.OperationMode mode) throws RuntimeException;
+ void updateServerManualMaintenance(int[] serverIds, boolean manualMaintenance) throws RuntimeException;
/**
* Updates the server.
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/TopologyGWTServiceImpl.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/TopologyGWTServiceImpl.java
index 06108a0..34d42f9 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/TopologyGWTServiceImpl.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/TopologyGWTServiceImpl.java
@@ -32,7 +32,6 @@ import org.rhq.core.domain.cloud.PartitionEvent;
import org.rhq.core.domain.cloud.PartitionEventDetails;
import org.rhq.core.domain.cloud.PartitionEventType;
import org.rhq.core.domain.cloud.Server;
-import org.rhq.core.domain.cloud.Server.OperationMode;
import org.rhq.core.domain.cloud.composite.AffinityGroupCountComposite;
import org.rhq.core.domain.cloud.composite.ServerWithAgentCountComposite;
import org.rhq.core.domain.criteria.AgentCriteria;
@@ -84,9 +83,10 @@ public class TopologyGWTServiceImpl extends AbstractGWTServiceImpl implements To
}
@Override
- public void updateServerMode(int[] serverIds, OperationMode mode) throws RuntimeException {
+ public void updateServerManualMaintenance(int[] serverIds, boolean manualMaintenance) throws RuntimeException {
try {
- topologyManager.updateServerMode(getSessionSubject(), ArrayUtils.toObject(serverIds), mode);
+ topologyManager.updateServerManualMaintenance(getSessionSubject(), ArrayUtils.toObject(serverIds),
+ manualMaintenance);
} catch (Throwable t) {
throw getExceptionToThrowToClient(t);
}
diff --git a/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/ha/ListServersUIBean.java b/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/ha/ListServersUIBean.java
index cc85b4d..9f5801a 100644
--- a/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/ha/ListServersUIBean.java
+++ b/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/ha/ListServersUIBean.java
@@ -22,7 +22,6 @@ import javax.faces.application.FacesMessage;
import javax.faces.model.DataModel;
import org.rhq.core.domain.auth.Subject;
-import org.rhq.core.domain.cloud.Server;
import org.rhq.core.domain.cloud.composite.ServerWithAgentCountComposite;
import org.rhq.core.domain.util.PageControl;
import org.rhq.core.domain.util.PageList;
@@ -63,17 +62,24 @@ public class ListServersUIBean extends PagedDataTableUIBean {
return "success";
}
- public String setSelectedServersMode(Server.OperationMode mode) {
+ public String updateServerManualMaintenance(boolean manualMaintenance) {
// Subject subject = EnterpriseFacesContextUtility.getSubject();
String[] selected = getSelectedServers();
Integer[] ids = getIntegerArray(selected);
if (ids.length > 0) {
try {
- topologyManager.updateServerMode(EnterpriseFacesContextUtility.getSubject(), ids, mode);
+ topologyManager.updateServerManualMaintenance(EnterpriseFacesContextUtility.getSubject(), ids,
+ manualMaintenance);
+
+ if (manualMaintenance) {
+ FacesContextUtility.addMessage(FacesMessage.SEVERITY_INFO, "Set [" + ids.length
+ + "] servers' manual maintenance status.");
+ } else {
+ FacesContextUtility.addMessage(FacesMessage.SEVERITY_INFO, "Removed [" + ids.length
+ + "] servers' manual maintenance status.");
+ }
- FacesContextUtility.addMessage(FacesMessage.SEVERITY_INFO, "Set [" + ids.length + "] servers to mode "
- + mode);
} catch (Exception e) {
FacesContextUtility.addMessage(FacesMessage.SEVERITY_ERROR, "Failed to set selected server modes", e);
}
@@ -83,11 +89,11 @@ public class ListServersUIBean extends PagedDataTableUIBean {
}
public String setSelectedServersModeMaintenance() {
- return setSelectedServersMode(Server.OperationMode.MAINTENANCE);
+ return updateServerManualMaintenance(true);
}
public String setSelectedServersModeNormal() {
- return setSelectedServersMode(Server.OperationMode.NORMAL);
+ return updateServerManualMaintenance(false);
}
@Override
diff --git a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/test/AbstractEJB3Test.java b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/test/AbstractEJB3Test.java
index 8010c2b..af01136 100644
--- a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/test/AbstractEJB3Test.java
+++ b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/test/AbstractEJB3Test.java
@@ -524,7 +524,7 @@ public abstract class AbstractEJB3Test extends Arquillian {
}
}
}
- storageClientManager.init();
+ storageClientManager.init(System.currentTimeMillis() - 100000);
beforeMethod();
beforeMethod(method);
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerBean.java
index ae1e69a..423218a 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerBean.java
@@ -28,8 +28,8 @@ import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Date;
import java.util.HashMap;
-import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@@ -44,9 +44,11 @@ import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
-import org.apache.commons.collections.map.LinkedMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.quartz.JobDataMap;
+import org.quartz.SimpleTrigger;
+import org.quartz.Trigger;
import org.rhq.cassandra.schema.SchemaManager;
import org.rhq.core.domain.alert.Alert;
@@ -67,7 +69,6 @@ import org.rhq.core.domain.criteria.ResourceOperationHistoryCriteria;
import org.rhq.core.domain.criteria.StorageNodeCriteria;
import org.rhq.core.domain.measurement.MeasurementAggregate;
import org.rhq.core.domain.measurement.MeasurementUnits;
-import org.rhq.core.domain.measurement.composite.MeasurementDataNumericHighLowComposite;
import org.rhq.core.domain.operation.OperationRequestStatus;
import org.rhq.core.domain.operation.ResourceOperationHistory;
import org.rhq.core.domain.operation.bean.GroupOperationSchedule;
@@ -93,8 +94,8 @@ import org.rhq.enterprise.server.resource.ResourceTypeManagerLocal;
import org.rhq.enterprise.server.resource.group.ResourceGroupManagerLocal;
import org.rhq.enterprise.server.rest.reporting.MeasurementConverter;
import org.rhq.enterprise.server.scheduler.SchedulerLocal;
-import org.rhq.enterprise.server.storage.StorageClusterSettings;
-import org.rhq.enterprise.server.storage.StorageClusterSettingsManagerBean;
+import org.rhq.enterprise.server.scheduler.jobs.StorageNodeMaintenanceJob;
+import org.rhq.enterprise.server.storage.StorageConfigurationException;
import org.rhq.enterprise.server.util.CriteriaQueryGenerator;
import org.rhq.enterprise.server.util.CriteriaQueryRunner;
import org.rhq.enterprise.server.util.LookupUtil;
@@ -117,7 +118,6 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
private final static String SEEDS_LIST = "seedsList";
private static final String RHQ_STORAGE_CQL_PORT_PROPERTY = "nativeTransportPort";
- private static final String RHQ_STORAGE_GOSSIP_PORT_PROPERTY = "storagePort";
private static final String RHQ_STORAGE_JMX_PORT_PROPERTY = "jmxPort";
private static final String RHQ_STORAGE_ADDRESS_PROPERTY = "host";
@@ -125,19 +125,6 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
private static final int MAX_ITERATIONS = 10;
private static final String UPDATE_CONFIGURATION_OPERATION = "updateConfiguration";
private static final String RESTART_OPERATION = "restart";
-
- // metric names on Storage Service resource
- private static final String METRIC_TOKENS = "Tokens", METRIC_OWNERSHIP = "Ownership";
- private static final String METRIC_DATA_DISK_USED_PERCENTAGE = "Calculated.DataDiskUsedPercentage";
- private static final String METRIC_TOTAL_DISK_USED_PERCENTAGE = "Calculated.TotalDiskUsedPercentage";
- private static final String METRIC_FREE_DISK_TO_DATA_RATIO = "Calculated.FreeDiskToDataSizeRatio";
- private static final String METRIC_LOAD = "Load", METRIC_KEY_CACHE_SIZE = "KeyCacheSize",
- METRIC_ROW_CACHE_SIZE = "RowCacheSize", METRIC_TOTAL_COMMIT_LOG_SIZE = "TotalCommitlogSize";
-
- //metric names on Memory Subsystem resource
- private static final String METRIC_HEAP_COMMITED = "{HeapMemoryUsage.committed}",
- METRIC_HEAP_USED = "{HeapMemoryUsage.used}", METRIC_HEAP_USED_PERCENTAGE = "Calculated.HeapUsagePercentage";
-
@PersistenceContext(unitName = RHQConstants.PERSISTENCE_UNIT_NAME)
private EntityManager entityManager;
@@ -172,13 +159,10 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
@EJB
private ResourceManagerLocal resourceManager;
- @EJB
- private StorageClusterSettingsManagerBean storageClusterSettingsManager;
-
@Override
public void linkResource(Resource resource) {
- Configuration pluginConfig = resource.getPluginConfiguration();
- String address = pluginConfig.getSimpleValue(RHQ_STORAGE_ADDRESS_PROPERTY);
+ Configuration resourceConfig = resource.getPluginConfiguration();
+ String address = resourceConfig.getSimpleValue(RHQ_STORAGE_ADDRESS_PROPERTY);
if (log.isInfoEnabled()) {
log.info("Linking " + resource + " to storage node at " + address);
@@ -192,13 +176,12 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
}
storageNode.setResource(resource);
storageNode.setOperationMode(OperationMode.NORMAL);
- initClusterSettingsIfNecessary(pluginConfig);
addStorageNodeToGroup(resource);
} else {
storageNode = new StorageNode();
storageNode.setAddress(address);
- storageNode.setCqlPort(Integer.parseInt(pluginConfig.getSimpleValue(RHQ_STORAGE_CQL_PORT_PROPERTY)));
- storageNode.setJmxPort(Integer.parseInt(pluginConfig.getSimpleValue(RHQ_STORAGE_JMX_PORT_PROPERTY)));
+ storageNode.setCqlPort(Integer.parseInt(resourceConfig.getSimpleValue(RHQ_STORAGE_CQL_PORT_PROPERTY)));
+ storageNode.setJmxPort(Integer.parseInt(resourceConfig.getSimpleValue(RHQ_STORAGE_JMX_PORT_PROPERTY)));
storageNode.setResource(resource);
storageNode.setOperationMode(OperationMode.INSTALLED);
@@ -217,31 +200,6 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
}
}
- private void initClusterSettingsIfNecessary(Configuration pluginConfig) {
- // TODO Need to handle non-repeatable reads here (probably a post 4.9 task)
- //
- // If a user deploys two storage nodes prior to installing the RHQ server, then we
- // could end up in this method concurrently for both storage nodes. The settings
- // would be committed for each node with the second commit winning. The problem is
- // that is the cluster settings differ for the two nodes, it will be silently
- // ignored. This scenario will happen infrequently so it should be sufficient to
- // resolve it with optimistic locking. The second writer should fail with an
- // OptimisticLockException.
-
- log.info("Initializing storage cluster settings");
-
- StorageClusterSettings clusterSettings = storageClusterSettingsManager.getClusterSettings(
- subjectManager.getOverlord());
- if (clusterSettings != null) {
- log.info("Cluster settings have already been set. Skipping initialization.");
- return;
- }
- clusterSettings = new StorageClusterSettings();
- clusterSettings.setCqlPort(Integer.parseInt(pluginConfig.getSimpleValue(RHQ_STORAGE_CQL_PORT_PROPERTY)));
- clusterSettings.setGossipPort(Integer.parseInt(pluginConfig.getSimpleValue(RHQ_STORAGE_GOSSIP_PORT_PROPERTY)));
- storageClusterSettingsManager.setClusterSettings(subjectManager.getOverlord(), clusterSettings);
- }
-
private void announceNewNode(StorageNode newStorageNode) {
if (log.isInfoEnabled()) {
log.info("Announcing " + newStorageNode + " to storage node cluster.");
@@ -363,90 +321,106 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
int resourceId = getResourceIdFromStorageNode(node);
Map<String, Integer> scheduleIdsMap = new HashMap<String, Integer>();
- for (Object[] tupple : getStorageServiceScheduleIds(resourceId)) {
- String definitionName = (String) tupple[0];
- Integer scheduleId = (Integer) tupple[2];
- scheduleIdsMap.put(definitionName, scheduleId);
+ // get the schedule ids for Storage Service resource
+ final String tokensMetric = "Tokens", ownershipMetric = "Ownership";
+ final String dataDiskUsedPercentageMetric = "Calculated.DataDiskUsedPercentage";
+ final String totalDiskUsedPercentageMetric = "Calculated.TotalDiskUsedPercentage";
+ final String freeDiskToDataRatioMetric = "Calculated.FreeDiskToDataSizeRatio";
+ final String loadMetric = "Load", keyCacheSize = "KeyCacheSize", rowCacheSize = "RowCacheSize", totalCommitLogSize = "TotalCommitlogSize";
+ TypedQuery<Object[]> query = entityManager.<Object[]> createNamedQuery(
+ StorageNode.QUERY_FIND_SCHEDULE_IDS_BY_PARENT_RESOURCE_ID_AND_MEASUREMENT_DEFINITION_NAMES, Object[].class);
+ query.setParameter("parrentId", resourceId).setParameter("metricNames",
+ Arrays.asList(tokensMetric, ownershipMetric, loadMetric, keyCacheSize, rowCacheSize, totalCommitLogSize,
+ dataDiskUsedPercentageMetric, totalDiskUsedPercentageMetric, freeDiskToDataRatioMetric));
+ for (Object[] pair : query.getResultList()) {
+ scheduleIdsMap.put((String) pair[0], (Integer) pair[1]);
}
- for (Object[] tupple : getMemorySubsystemScheduleIds(resourceId)) {
- String definitionName = (String) tupple[0];
- Integer scheduleId = (Integer) tupple[2];
- scheduleIdsMap.put(definitionName, scheduleId);
+
+ // get the schedule ids for Memory Subsystem resource
+ final String heapCommittedMetric = "{HeapMemoryUsage.committed}", heapUsedMetric = "{HeapMemoryUsage.used}", heapUsedPercentageMetric = "Calculated.HeapUsagePercentage";
+ query = entityManager.<Object[]> createNamedQuery(
+ StorageNode.QUERY_FIND_SCHEDULE_IDS_BY_GRANDPARENT_RESOURCE_ID_AND_MEASUREMENT_DEFINITION_NAMES,
+ Object[].class);
+ query.setParameter("grandparrentId", resourceId).setParameter("metricNames",
+ Arrays.asList(heapCommittedMetric, heapUsedMetric, heapUsedPercentageMetric));
+ for (Object[] pair : query.getResultList()) {
+ scheduleIdsMap.put((String) pair[0], (Integer) pair[1]);
}
+
StorageNodeLoadComposite result = new StorageNodeLoadComposite(node, beginTime, endTime);
- MeasurementAggregate totalDiskUsedAggregate = new MeasurementAggregate(0d, 0d, 0d);
+ MeasurementAggregate totalDiskUsedaggregate = new MeasurementAggregate(0d, 0d, 0d);
Integer scheduleId = null;
// find the aggregates and enrich the result instance
if (!scheduleIdsMap.isEmpty()) {
- if ((scheduleId = scheduleIdsMap.get(METRIC_TOKENS)) != null) {
+ if ((scheduleId = scheduleIdsMap.get(tokensMetric)) != null) {
MeasurementAggregate tokensAggregate = measurementManager.getAggregate(subject, scheduleId, beginTime,
endTime);
result.setTokens(tokensAggregate);
}
- if ((scheduleId = scheduleIdsMap.get(METRIC_OWNERSHIP)) != null) {
+ if ((scheduleId = scheduleIdsMap.get(ownershipMetric)) != null) {
StorageNodeLoadComposite.MeasurementAggregateWithUnits ownershipAggregateWithUnits = getMeasurementAggregateWithUnits(
subject, scheduleId, MeasurementUnits.PERCENTAGE, beginTime, endTime);
result.setActuallyOwns(ownershipAggregateWithUnits);
}
//calculated disk space related metrics
- if ((scheduleId = scheduleIdsMap.get(METRIC_DATA_DISK_USED_PERCENTAGE)) != null) {
+ if ((scheduleId = scheduleIdsMap.get(dataDiskUsedPercentageMetric)) != null) {
StorageNodeLoadComposite.MeasurementAggregateWithUnits dataDiskUsedPercentageAggregateWithUnits = getMeasurementAggregateWithUnits(
subject, scheduleId, MeasurementUnits.PERCENTAGE, beginTime, endTime);
result.setDataDiskUsedPercentage(dataDiskUsedPercentageAggregateWithUnits);
}
- if ((scheduleId = scheduleIdsMap.get(METRIC_TOTAL_DISK_USED_PERCENTAGE)) != null) {
+ if ((scheduleId = scheduleIdsMap.get(totalDiskUsedPercentageMetric)) != null) {
StorageNodeLoadComposite.MeasurementAggregateWithUnits totalDiskUsedPercentageAggregateWithUnits = getMeasurementAggregateWithUnits(
subject, scheduleId, MeasurementUnits.PERCENTAGE, beginTime, endTime);
result.setTotalDiskUsedPercentage(totalDiskUsedPercentageAggregateWithUnits);
}
- if ((scheduleId = scheduleIdsMap.get(METRIC_FREE_DISK_TO_DATA_RATIO)) != null) {
+ if ((scheduleId = scheduleIdsMap.get(freeDiskToDataRatioMetric)) != null) {
MeasurementAggregate freeDiskToDataRatioAggregate = measurementManager.getAggregate(subject,
scheduleId, beginTime, endTime);
result.setFreeDiskToDataSizeRatio(freeDiskToDataRatioAggregate);
}
- if ((scheduleId = scheduleIdsMap.get(METRIC_LOAD)) != null) {
+ if ((scheduleId = scheduleIdsMap.get(loadMetric)) != null) {
StorageNodeLoadComposite.MeasurementAggregateWithUnits loadAggregateWithUnits = getMeasurementAggregateWithUnits(
subject, scheduleId, MeasurementUnits.BYTES, beginTime, endTime);
result.setLoad(loadAggregateWithUnits);
- updateAggregateTotal(totalDiskUsedAggregate, loadAggregateWithUnits.getAggregate());
+ updateAggregateTotal(totalDiskUsedaggregate, loadAggregateWithUnits.getAggregate());
+ }
+ if ((scheduleId = scheduleIdsMap.get(keyCacheSize)) != null) {
+ updateAggregateTotal(totalDiskUsedaggregate,
+ measurementManager.getAggregate(subject, scheduleId, beginTime, endTime));
+ }
+ if ((scheduleId = scheduleIdsMap.get(rowCacheSize)) != null) {
+ updateAggregateTotal(totalDiskUsedaggregate,
+ measurementManager.getAggregate(subject, scheduleId, beginTime, endTime));
+ }
+ if ((scheduleId = scheduleIdsMap.get(totalCommitLogSize)) != null) {
+ updateAggregateTotal(totalDiskUsedaggregate,
+ measurementManager.getAggregate(subject, scheduleId, beginTime, endTime));
}
-// if ((scheduleId = scheduleIdsMap.get(METRIC_KEY_CACHE_SIZE)) != null) {
-// updateAggregateTotal(totalDiskUsedAggregate,
-// measurementManager.getAggregate(subject, scheduleId, beginTime, endTime));
-// }
-// if ((scheduleId = scheduleIdsMap.get(METRIC_ROW_CACHE_SIZE)) != null) {
-// updateAggregateTotal(totalDiskUsedAggregate,
-// measurementManager.getAggregate(subject, scheduleId, beginTime, endTime));
-// }
-// if ((scheduleId = scheduleIdsMap.get(METRIC_TOTAL_COMMIT_LOG_SIZE)) != null) {
-// updateAggregateTotal(totalDiskUsedAggregate,
-// measurementManager.getAggregate(subject, scheduleId, beginTime, endTime));
-// }
-
- if (totalDiskUsedAggregate.getMax() > 0) {
+
+ if (totalDiskUsedaggregate.getMax() > 0) {
StorageNodeLoadComposite.MeasurementAggregateWithUnits totalDiskUsedAggregateWithUnits = new StorageNodeLoadComposite.MeasurementAggregateWithUnits(
- totalDiskUsedAggregate, MeasurementUnits.BYTES);
- totalDiskUsedAggregateWithUnits.setFormattedValue(getSummaryString(totalDiskUsedAggregate,
+ totalDiskUsedaggregate, MeasurementUnits.BYTES);
+ totalDiskUsedAggregateWithUnits.setFormattedValue(getSummaryString(totalDiskUsedaggregate,
MeasurementUnits.BYTES));
result.setDataDiskUsed(totalDiskUsedAggregateWithUnits);
}
- if ((scheduleId = scheduleIdsMap.get(METRIC_HEAP_COMMITED)) != null) {
+ if ((scheduleId = scheduleIdsMap.get(heapCommittedMetric)) != null) {
StorageNodeLoadComposite.MeasurementAggregateWithUnits heapCommittedAggregateWithUnits = getMeasurementAggregateWithUnits(
subject, scheduleId, MeasurementUnits.BYTES, beginTime, endTime);
result.setHeapCommitted(heapCommittedAggregateWithUnits);
}
- if ((scheduleId = scheduleIdsMap.get(METRIC_HEAP_USED)) != null) {
+ if ((scheduleId = scheduleIdsMap.get(heapUsedMetric)) != null) {
StorageNodeLoadComposite.MeasurementAggregateWithUnits heapUsedAggregateWithUnits = getMeasurementAggregateWithUnits(
subject, scheduleId, MeasurementUnits.BYTES, beginTime, endTime);
result.setHeapUsed(heapUsedAggregateWithUnits);
}
- if ((scheduleId = scheduleIdsMap.get(METRIC_HEAP_USED_PERCENTAGE)) != null) {
+ if ((scheduleId = scheduleIdsMap.get(heapUsedPercentageMetric)) != null) {
StorageNodeLoadComposite.MeasurementAggregateWithUnits heapUsedPercentageAggregateWithUnits = getMeasurementAggregateWithUnits(
subject, scheduleId, MeasurementUnits.PERCENTAGE, beginTime,
endTime);
@@ -456,26 +430,6 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
return result;
}
-
- private List<Object[]> getStorageServiceScheduleIds(int storageNodeResourceId) {
- // get the schedule ids for Storage Service resource
- TypedQuery<Object[]> query = entityManager.<Object[]> createNamedQuery(
- StorageNode.QUERY_FIND_SCHEDULE_IDS_BY_PARENT_RESOURCE_ID_AND_MEASUREMENT_DEFINITION_NAMES, Object[].class);
- query.setParameter("parrentId", storageNodeResourceId).setParameter("metricNames",
- Arrays.asList(METRIC_TOKENS, METRIC_OWNERSHIP, METRIC_LOAD/*, METRIC_KEY_CACHE_SIZE, METRIC_ROW_CACHE_SIZE, METRIC_TOTAL_COMMIT_LOG_SIZE*/,
- METRIC_DATA_DISK_USED_PERCENTAGE, METRIC_TOTAL_DISK_USED_PERCENTAGE, METRIC_FREE_DISK_TO_DATA_RATIO));
- return query.getResultList();
- }
-
- private List<Object[]> getMemorySubsystemScheduleIds(int storageNodeResourceId) {
- // get the schedule ids for Memory Subsystem resource
- TypedQuery<Object[]> query = entityManager.<Object[]> createNamedQuery(
- StorageNode.QUERY_FIND_SCHEDULE_IDS_BY_GRANDPARENT_RESOURCE_ID_AND_MEASUREMENT_DEFINITION_NAMES,
- Object[].class);
- query.setParameter("grandparrentId", storageNodeResourceId).setParameter("metricNames",
- Arrays.asList(METRIC_HEAP_COMMITED, METRIC_HEAP_USED, METRIC_HEAP_USED_PERCENTAGE));
- return query.getResultList();
- }
/**
* @param accumulator
@@ -498,21 +452,6 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
StorageNode.class);
return query.getResultList();
}
-
- @Override
- public PageList<StorageNodeLoadComposite> getStorageNodeComposites() {
- List<StorageNode> nodes = getStorageNodes();
- PageList<StorageNodeLoadComposite> result = new PageList<StorageNodeLoadComposite>();
- long endTime = System.currentTimeMillis();
- long beginTime = endTime - (8 * 60 * 60 * 1000);
- for (StorageNode node : nodes) {
- StorageNodeLoadComposite composite = getLoad(subjectManager.getOverlord(), node, beginTime, endTime);
- int unackAlerts = findNotAcknowledgedStorageNodeAlerts(subjectManager.getOverlord(), node).size();
- composite.setUnackAlerts(unackAlerts);
- result.add(composite);
- }
- return result;
- }
private List<StorageNode> getClusteredStorageNodes() {
return entityManager.createNamedQuery(StorageNode.QUERY_FIND_ALL_BY_MODE, StorageNode.class)
@@ -678,10 +617,14 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
if (storageNode == null) {
initialStorageNodes = getStorageNodes();
} else {
- initialStorageNodes = Arrays.asList(storageNode.getResource() == null ? entityManager.find(
- StorageNode.class, storageNode.getId()) : storageNode);
+ int index = initialStorageNodes.indexOf(storageNode);
+ if (index >= 0) {
+ initialStorageNodes = Arrays.asList(initialStorageNodes.get(index));
+ } else {
+ initialStorageNodes = new ArrayList<StorageNode>();
+ }
}
-
+
Queue<Resource> unvisitedResources = new LinkedList<Resource>();
for (StorageNode initialStorageNode : initialStorageNodes) {
if (initialStorageNode.getResource() != null) {
@@ -796,55 +739,6 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
public void scheduleOperationInNewTransaction(Subject subject, ResourceOperationSchedule schedule) {
operationManager.scheduleResourceOperation(subject, schedule);
}
-
- @Override
- @RequiredPermissions({ @RequiredPermission(Permission.MANAGE_SETTINGS),
- @RequiredPermission(Permission.MANAGE_INVENTORY) })
- public Map<String, List<MeasurementDataNumericHighLowComposite>> findStorageNodeLoadDataForLast(Subject subject,
- StorageNode node, long beginTime, long endTime, int numPoints) {
- int storageNodeResourceId = getResourceIdFromStorageNode(node);
- Map<String, List<MeasurementDataNumericHighLowComposite>> result = new LinkedHashMap<String, List<MeasurementDataNumericHighLowComposite>>();
-
- List<Object[]> tupples = getStorageServiceScheduleIds(storageNodeResourceId);
- List<String> defNames = new ArrayList<String>();
- int[] definitionIds = new int[tupples.size()];
- int resId = -1;
- int index = 0;
- for (Object[] tupple : tupples) {
- String defName = (String) tupple[0];
- int definitionId = (Integer) tupple[1];
- resId = (Integer) tupple[3];
- defNames.add(defName);
- definitionIds[index++] = definitionId;
- }
- List<List<MeasurementDataNumericHighLowComposite>> storageServiceData = measurementManager.findDataForResource(
- subject, resId, definitionIds, beginTime, endTime, numPoints);
- for (int i = 0; i < storageServiceData.size(); i ++) {
- List<MeasurementDataNumericHighLowComposite> oneRecord = storageServiceData.get(i);
- result.put(defNames.get(i), oneRecord);
- }
-
- tupples = getMemorySubsystemScheduleIds(storageNodeResourceId);
- defNames = new ArrayList<String>();
- definitionIds = new int[tupples.size()];
- resId = -1;
- index = 0;
- for (Object[] tupple : tupples) {
- String defName = (String) tupple[0];
- int definitionId = (Integer) tupple[1];
- resId = (Integer) tupple[3];
- defNames.add(defName);
- definitionIds[index++] = definitionId;
- }
- List<List<MeasurementDataNumericHighLowComposite>> memorySubsystemData = measurementManager.findDataForResource(
- subject, resId, definitionIds, beginTime, endTime, numPoints);
- for (int i = 0; i < memorySubsystemData.size(); i ++) {
- List<MeasurementDataNumericHighLowComposite> oneRecord = memorySubsystemData.get(i);
- result.put(defNames.get(i), oneRecord);
- }
-
- return result;
- }
private boolean runOperationAndWaitForResult(Subject subject, Resource storageNodeResource, String operationToRun,
Configuration parameters) {
@@ -913,17 +807,17 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
log.info("Preparing to bootstrap " + storageNode + " into cluster...");
}
+ List<StorageNode> existingStorageNodes = getClusteredStorageNodes();
+
ResourceOperationSchedule schedule = new ResourceOperationSchedule();
schedule.setResource(storageNode.getResource());
schedule.setJobTrigger(JobTrigger.createNowTrigger());
schedule.setSubject(subjectManager.getOverlord());
schedule.setOperationName("prepareForBootstrap");
- StorageClusterSettings clusterSettings = storageClusterSettingsManager.getClusterSettings(
- subjectManager.getOverlord());
Configuration parameters = new Configuration();
- parameters.put(new PropertySimple("cqlPort", clusterSettings.getCqlPort()));
- parameters.put(new PropertySimple("gossipPort", clusterSettings.getGossipPort()));
+ parameters.put(new PropertySimple("cqlPort", existingStorageNodes.get(0).getCqlPort()));
+ parameters.put(new PropertySimple("gossipPort", getGossipPort(storageNode, existingStorageNodes)));
parameters.put(createPropertyListOfAddresses("storageNodeIPAddresses", getClusteredStorageNodes()));
schedule.setParameters(parameters);
@@ -931,6 +825,44 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
operationManager.scheduleResourceOperation(subjectManager.getOverlord(), schedule);
}
+ private Integer getGossipPort(StorageNode newStorageNode, List<StorageNode> storageNodes) {
+ if (log.isInfoEnabled()) {
+ log.info("Looking up gossip port for new storage node " + newStorageNode);
+ }
+ try {
+ StorageNode node = null;
+ Configuration resourceConfig = null;
+ for (StorageNode storageNode : storageNodes) {
+ resourceConfig = configurationManager.getLiveResourceConfiguration(subjectManager.getOverlord(),
+ storageNode.getResource().getId(), false);
+ if (resourceConfig == null) {
+ log.warn("Failed to load resource configuration for storage node " + newStorageNode.getResource());
+ } else {
+ node = storageNode;
+ break;
+ }
+ }
+ if (resourceConfig == null) {
+ log.error("Failed to obtain gossip port from existing storage nodes");
+ throw new StorageConfigurationException("Failed to obtain gossip port from existing storage nodes");
+ }
+
+ PropertySimple property = resourceConfig.getSimple("gossipPort");
+ if (property == null) {
+ throw new StorageConfigurationException("The resource configuration for " + node.getResource() +
+ "did not include the required property [gossipPort]");
+ }
+ Integer port = property.getIntegerValue();
+ log.info("Found gossip port set to " + port);
+ return property.getIntegerValue();
+ } catch (Exception e) {
+ if (e instanceof StorageConfigurationException) {
+ throw (StorageConfigurationException) e;
+ }
+ throw new RuntimeException("An error occurred while trying to obtain the gossip port", e);
+ }
+ }
+
@Override
public void runAddNodeMaintenance() {
log.info("Preparing to schedule addNodeMaintenance on the storage cluster...");
@@ -1018,4 +950,4 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
return value;
}
-}
+}
\ No newline at end of file
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/TopologyManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/TopologyManagerBean.java
index 98aa9e6..4db1697 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/TopologyManagerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/TopologyManagerBean.java
@@ -35,10 +35,8 @@ import org.rhq.core.domain.authz.Permission;
import org.rhq.core.domain.cloud.FailoverListDetails;
import org.rhq.core.domain.cloud.PartitionEventType;
import org.rhq.core.domain.cloud.Server;
-import org.rhq.core.domain.cloud.StorageNode;
import org.rhq.core.domain.cloud.composite.ServerWithAgentCountComposite;
import org.rhq.core.domain.criteria.ServerCriteria;
-import org.rhq.core.domain.criteria.StorageNodeCriteria;
import org.rhq.core.domain.resource.Agent;
import org.rhq.core.domain.server.PersistenceUtility;
import org.rhq.core.domain.util.PageControl;
@@ -216,13 +214,36 @@ public class TopologyManagerBean implements TopologyManagerLocal {
@RequiredPermissions({ @RequiredPermission(Permission.MANAGE_SETTINGS),
@RequiredPermission(Permission.MANAGE_INVENTORY) })
+ public void updateServerManualMaintenance(Subject subject, Integer[] serverIds, boolean manualMaintenance) {
+ if (serverIds.length > 0) {
+ try {
+ for (Integer id : serverIds) {
+ Server server = entityManager.find(Server.class, id);
+ if (manualMaintenance) {
+ server.addStatus(Server.Status.MANUAL_MAINTENANCE_MODE);
+ } else {
+ server.clearStatus(Server.Status.MANUAL_MAINTENANCE_MODE);
+ }
+ }
+ } catch (Exception e) {
+ log.debug("Failed to update HA server modes: " + e);
+ }
+ }
+ }
+
+ @RequiredPermissions({ @RequiredPermission(Permission.MANAGE_SETTINGS),
+ @RequiredPermission(Permission.MANAGE_INVENTORY) })
public void updateServerMode(Subject subject, Integer[] serverIds, Server.OperationMode mode) {
if (serverIds == null) {
return;
}
if (mode == null) {
- throw new IllegalArgumentException("mode can not be null");
+ throw new IllegalArgumentException("Mode cannot be null.");
+ }
+ if (!mode.isConfigurable()) {
+ throw new IllegalArgumentException("Cannot directly set a mode that is not configurable. Mode "
+ + mode.name() + " is not configurable.");
}
if (serverIds.length > 0) {
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/TopologyManagerLocal.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/TopologyManagerLocal.java
index 7d5f76a..11b9f95 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/TopologyManagerLocal.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/TopologyManagerLocal.java
@@ -25,10 +25,8 @@ import javax.ejb.Local;
import org.rhq.core.domain.auth.Subject;
import org.rhq.core.domain.cloud.FailoverListDetails;
import org.rhq.core.domain.cloud.Server;
-import org.rhq.core.domain.cloud.StorageNode;
import org.rhq.core.domain.cloud.composite.ServerWithAgentCountComposite;
import org.rhq.core.domain.criteria.ServerCriteria;
-import org.rhq.core.domain.criteria.StorageNodeCriteria;
import org.rhq.core.domain.resource.Agent;
import org.rhq.core.domain.util.PageControl;
import org.rhq.core.domain.util.PageList;
@@ -121,6 +119,17 @@ public interface TopologyManagerLocal {
void updateServerMode(Subject subject, Integer[] serverIds, Server.OperationMode mode);
/**
+ * Updates the manual maintenance flag for multiple servers.
+ *
+ * the subject needs to have MANAGE_INVENTORY and MANAGE_SETTINGS permissions.
+ *
+ * @param subject the caller
+ * @param serverIds
+ * @param manualMaintenance manual maintenance
+ */
+ void updateServerManualMaintenance(Subject subject, Integer[] serverIds, boolean manualMainatenance);
+
+ /**
* Updates the server.
*
* the subject needs to have MANAGE_INVENTORY and MANAGE_SETTINGS permissions.
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/instance/ServerManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/instance/ServerManagerBean.java
index 4300313..44bd557 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/instance/ServerManagerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/instance/ServerManagerBean.java
@@ -41,6 +41,8 @@ import org.apache.commons.logging.LogFactory;
import org.rhq.core.domain.cloud.PartitionEventType;
import org.rhq.core.domain.cloud.Server;
+import org.rhq.core.domain.cloud.Server.OperationMode;
+import org.rhq.core.domain.cloud.Server.Status;
import org.rhq.core.domain.resource.Agent;
import org.rhq.core.util.exception.ThrowableUtil;
import org.rhq.enterprise.communications.GlobalSuspendCommandListener;
@@ -50,6 +52,7 @@ import org.rhq.enterprise.server.cloud.PartitionEventManagerLocal;
import org.rhq.enterprise.server.cloud.StatusManagerLocal;
import org.rhq.enterprise.server.cloud.TopologyManagerLocal;
import org.rhq.enterprise.server.core.comm.ServerCommunicationsServiceUtil;
+import org.rhq.enterprise.server.storage.StorageClientManagerBean;
/**
* If you want to manipulate or report on the {@link Server} instance that
@@ -82,6 +85,9 @@ public class ServerManagerBean implements ServerManagerLocal {
private TopologyManagerLocal topologyManager;
@EJB
+ private StorageClientManagerBean storageClientManager;
+
+ @EJB
private StatusManagerLocal agentStatusManager;
@EJB
@@ -156,8 +162,10 @@ public class ServerManagerBean implements ServerManagerLocal {
if (server == null) {
return false; // don't reload caches if we don't know who we are
}
- boolean hadStatus = (server.getStatus() != 0);
- server.clearStatus();
+ boolean hadStatus = (server.hasStatus(Status.ALERT_DEFINITION) || server
+ .hasStatus(Status.RESOURCE_HIERARCHY_UPDATED));
+ server.clearStatus(Status.ALERT_DEFINITION);
+ server.clearStatus(Status.RESOURCE_HIERARCHY_UPDATED);
return hadStatus;
}
@@ -182,7 +190,9 @@ public class ServerManagerBean implements ServerManagerLocal {
public void establishCurrentServerMode() {
Server server = getServer();
- Server.OperationMode serverMode = server.getOperationMode();
+ Server.OperationMode serverMode = determineServerOperationMode(
+ server.hasStatus(Server.Status.MANUAL_MAINTENANCE_MODE), storageClientManager.isClusterAvailable(),
+ server.getOperationMode());
// no state change means no work
if (serverMode == lastEstablishedServerMode)
@@ -221,31 +231,25 @@ public class ServerManagerBean implements ServerManagerLocal {
log.info("Notified communication layer of server operation mode " + serverMode);
- } else if (Server.OperationMode.INSTALLED == serverMode) {
-
+ } else if (Server.OperationMode.INSTALLED == serverMode
// The server must have just been installed and must be coming for the first time
- // up as of this call. So, update the mode to NORMAL and update mtime as an initial heart beat.
+ // up as of this call. So, attempt to update the mode to NORMAL.
// This will prevent a running CloudManagerJob from resetting to DOWN before the real
// ServerManagerJob starts updating the heart beat regularly.
- lastEstablishedServerMode = serverMode;
- serverMode = Server.OperationMode.NORMAL;
- server.setOperationMode(serverMode);
- server.setMtime(System.currentTimeMillis());
-
- } else if (Server.OperationMode.DOWN == serverMode) {
+ || Server.OperationMode.DOWN == serverMode) {
// The server can't be DOWN if this code is executing, it means the server must be coming
- // up as of this call. So, update the mode to NORMAL and update mtime as an initial heart beat.
+ // up as of this call. So, attempt to update the mode to NORMAL.
// This will prevent a running CloudManagerJob from resetting to DOWN before the real
// ServerManagerJob starts updating the heart beat regularly.
+
lastEstablishedServerMode = serverMode;
- serverMode = Server.OperationMode.NORMAL;
- server.setOperationMode(serverMode);
- server.setMtime(System.currentTimeMillis());
+ serverMode = determineServerOperationMode(server.hasStatus(Server.Status.MANUAL_MAINTENANCE_MODE),
+ storageClientManager.isClusterAvailable(), OperationMode.NORMAL);
}
- // If this server just transitioned from INSTALLED to NORMAL operation mode then it
- // has just been added to the cloud. Changing the number of servers in the cloud requires agent
+ // If this server just transitioned from INSTALLED to NORMAL operation mode then it
+ // has just been added to the cloud. Changing the number of servers in the cloud requires agent
// distribution work, even if this is a 1-Server cloud. Generate a request for a repartitioning
// of agent load, it will be executed on the next invocation of the cluster manager job.
// Otherwise, audit the operation mode change as a partition event of interest.
@@ -264,7 +268,8 @@ public class ServerManagerBean implements ServerManagerLocal {
}
lastEstablishedServerMode = serverMode;
-
+ server.setOperationMode(lastEstablishedServerMode);
+ server.setMtime(System.currentTimeMillis());
} catch (Exception e) {
log.error("Unable to change HA Server Mode from " + lastEstablishedServerMode + " to " + serverMode + ": "
+ e);
@@ -310,4 +315,28 @@ public class ServerManagerBean implements ServerManagerLocal {
establishCurrentServerMode();
}
+ /**
+ * @param manualMaintenance
+ * @param storageNodeUp
+ * @param currentOperationMode
+ */
+ private Server.OperationMode determineServerOperationMode(boolean isManualMaintenance,
+ boolean isStorageClusterAvailable, Server.OperationMode requestedOperationMode) {
+
+ if (Server.OperationMode.DOWN == requestedOperationMode
+ || Server.OperationMode.INSTALLED == requestedOperationMode) {
+ return requestedOperationMode;
+ }
+
+ if (Server.OperationMode.NORMAL == requestedOperationMode
+ || Server.OperationMode.MAINTENANCE == requestedOperationMode) {
+ if (!isManualMaintenance && isStorageClusterAvailable) {
+ return OperationMode.NORMAL;
+ } else {
+ return OperationMode.MAINTENANCE;
+ }
+ }
+
+ throw new RuntimeException("Unable to determine new server operation mode.");
+ }
}
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/StartupBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/StartupBean.java
index fa88263..646a9fd 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/StartupBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/StartupBean.java
@@ -53,7 +53,6 @@ import org.quartz.SchedulerException;
import org.rhq.core.db.DatabaseTypeFactory;
import org.rhq.core.domain.auth.Subject;
import org.rhq.core.domain.cloud.Server;
-import org.rhq.core.domain.cloud.Server.OperationMode;
import org.rhq.core.domain.common.ProductInfo;
import org.rhq.core.domain.resource.Agent;
import org.rhq.core.util.ObjectNameFactory;
@@ -91,7 +90,6 @@ import org.rhq.enterprise.server.scheduler.jobs.SavedSearchResultCountRecalculat
import org.rhq.enterprise.server.scheduler.jobs.StorageClusterReadRepairJob;
import org.rhq.enterprise.server.scheduler.jobs.StorageNodeMaintenanceJob;
import org.rhq.enterprise.server.storage.StorageClientManagerBean;
-import org.rhq.enterprise.server.storage.StorageClusterHeartBeatJob;
import org.rhq.enterprise.server.system.SystemManagerLocal;
import org.rhq.enterprise.server.util.LookupUtil;
import org.rhq.enterprise.server.util.concurrent.AlertSerializer;
@@ -144,9 +142,6 @@ public class StartupBean implements StartupLocal {
@EJB
private StorageClientManagerBean storageClientManager;
- @EJB
- private StorageClusterHeartBeatJob storageClusterHeartBeatJob;
-
@Resource
private TimerService timerService; // needed to schedule our plugin scanner
@@ -275,8 +270,7 @@ public class StartupBean implements StartupLocal {
log.info("Server is configured to start up in MAINTENANCE mode.");
Server server = serverManager.getServer();
Integer[] serverId = new Integer[] { server.getId() };
- topologyManager.updateServerMode(LookupUtil.getSubjectManager().getOverlord(), serverId,
- OperationMode.MAINTENANCE);
+ topologyManager.updateServerManualMaintenance(LookupUtil.getSubjectManager().getOverlord(), serverId, true);
}
// Establish the current server mode for the server. This will move the server to NORMAL
@@ -449,7 +443,8 @@ public class StartupBean implements StartupLocal {
log.error("Cannot create storage node maintenance job.", e);
}
- storageClientManager.init();
+ storageClientManager.init(serverManager.getServer().getCtime());
+ serverManager.establishCurrentServerMode();
}
/**
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/storage/StorageClientManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/storage/StorageClientManagerBean.java
index 3f1943d..83ef02c 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/storage/StorageClientManagerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/storage/StorageClientManagerBean.java
@@ -76,8 +76,9 @@ public class StorageClientManagerBean {
private MetricsDAO metricsDAO;
private MetricsServer metricsServer;
private boolean initialized;
+ private StorageClusterMonitor storageClusterMonitor;
- public synchronized void init() {
+ public synchronized void init(long ctime) {
if (initialized) {
if (log.isDebugEnabled()) {
log.debug("Storage client subsystem is already initialized. Skipping initialization.");
@@ -103,11 +104,15 @@ public class StorageClientManagerBean {
+ "result of running dbsetup or deleting rows from rhq_storage_node table. Please re-install the "
+ "storage node to fix this issue.");
}
- session = createSession(username, password, storageNodes);
+ Session wrappedSession = createSession(username, password, storageNodeManager.getStorageNodes());
+ session = new StorageSession(wrappedSession);
+
+ storageClusterMonitor = new StorageClusterMonitor();
+ session.addStorageStateListener(storageClusterMonitor);
+
metricsDAO = new MetricsDAO(session, metricsConfiguration);
- Server server = serverManager.getServer();
- initMetricsServer(isNewServerInstall, server.getCtime());
+ initMetricsServer(isNewServerInstall, ctime);
initialized = true;
log.info("Storage client subsystem is now initialized");
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/storage/StorageClusterHeartBeatJob.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/storage/StorageClusterHeartBeatJob.java
deleted file mode 100644
index 6f58a06..0000000
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/storage/StorageClusterHeartBeatJob.java
+++ /dev/null
@@ -1,126 +0,0 @@
-package org.rhq.enterprise.server.storage;
-
-import static org.rhq.core.domain.cloud.Server.OperationMode.MAINTENANCE;
-import static org.rhq.core.domain.cloud.Server.OperationMode.NORMAL;
-
-import java.util.List;
-
-import javax.annotation.Resource;
-import javax.ejb.EJB;
-import javax.ejb.Singleton;
-import javax.ejb.Timeout;
-import javax.ejb.TimerConfig;
-import javax.ejb.TimerService;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import org.rhq.cassandra.ClusterInitService;
-import org.rhq.core.domain.cloud.Server;
-import org.rhq.core.domain.cloud.StorageNode;
-import org.rhq.enterprise.server.auth.SubjectManagerLocal;
-import org.rhq.enterprise.server.cloud.StorageNodeManagerLocal;
-import org.rhq.enterprise.server.cloud.TopologyManagerLocal;
-import org.rhq.enterprise.server.cloud.instance.ServerManagerLocal;
-
-/**
- * This job runs periodically to verify that the server can connect to the storage cluster.
- * If the server cannot connect to any nodes in the cluster, the server will be put into
- * maintenance mode until it is able to connect to the cluster. See
- * {@link #checkClusterHeartBeat()} for more details.
- *
- * @author John Sanda
- */
-@Singleton
-public class StorageClusterHeartBeatJob {
-
- private final Log log = LogFactory.getLog(StorageClusterHeartBeatJob.class);
-
- @EJB
- private ServerManagerLocal serverManager;
-
- @EJB
- private StorageNodeManagerLocal storageNodeManager;
-
- @EJB
- private TopologyManagerLocal topologyManager;
-
- @EJB
- private SubjectManagerLocal subjectManager;
-
- @EJB
- private StorageClientManagerBean storageClientManager;
-
- @Resource
- private TimerService timerService;
-
- public void scheduleJob() {
- long initialDelay = 3000;
- long interval = 1000 * 60;
-
- timerService.createIntervalTimer(initialDelay, interval, new TimerConfig(null, false));
- }
-
- /**
- * <p>
- * Runs periodically to verify that the server can connect to the storage cluster. If
- * the server cannot connect to any nodes in the cluster, the server will be put into
- * maintenance mode until a connection can be made to the cluster.
- * </p>
- * <p>
- * While client requests are made using CQL commands going over the native transport
- * layer introduced in Cassandra 1.2, connectivity is checked via JMX. The JMX call
- * is made to determine whether or not the native transport is running. Trying to do
- * the check using the CQL driver gets complicated and introduces some non-trivial
- * overhead due to the fact that the driver is async.
- * </p>
- */
- @Timeout
- public void checkClusterHeartBeat() {
- ClusterInitService clusterInitService = new ClusterInitService();
- Server server = serverManager.getServer();
- List<StorageNode> storageNodes = storageNodeManager.getStorageNodes();
-
- if (storageNodes.isEmpty()) {
- log.error("No storage nodes were found in the RHQ database. If this is your only RHQ server make sure " +
- "that the rhq.cassandra.seeds property in <rhq-server-basedir>/bin/rhq-server.properties is " +
- "properly configured. If you edit this property, you will have to restart the server for the change " +
- "to take effect. The server will now go into maintenance mode since connectivity to storage " +
- "nodes cannot be verified.");
- putServerInMaintenanceMode(server);
- } else {
- boolean pingable = clusterInitService.ping(storageNodes, 1);
- if (pingable) {
- if (server.getOperationMode() != NORMAL) {
- changeServerMode(server, NORMAL);
- log.info("Restarting storage client subsystem...");
- storageClientManager.init();
- }
- return;
- }
-
- if (log.isWarnEnabled()) {
- log.warn(server + " is unable to connect to any Cassandra node. Server will go into maintenance mode.");
- }
- putServerInMaintenanceMode(server);
- }
- }
-
- private void putServerInMaintenanceMode(Server rhqServer) {
- changeServerMode(rhqServer, MAINTENANCE);
- log.info("Preparing to shut down storage client subsystem");
- storageClientManager.shutdown();
- }
-
- private void changeServerMode(Server rhqServer, Server.OperationMode mode) {
- if (rhqServer.getOperationMode() == mode) {
- return;
- }
-
- if (log.isInfoEnabled()) {
- log.info("Moving " + rhqServer + " from " + rhqServer.getOperationMode() + " to " + mode);
- }
- topologyManager.updateServerMode(subjectManager.getOverlord(), new Integer[] {rhqServer.getId()}, mode);
- }
-
-}
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/storage/StorageClusterMonitor.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/storage/StorageClusterMonitor.java
index 543036e..98d40cb 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/storage/StorageClusterMonitor.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/storage/StorageClusterMonitor.java
@@ -33,13 +33,10 @@ public class StorageClusterMonitor implements StorageStateListener {
@Override
public void onStorageNodeUp(InetAddress address) {
log.info("Storage node at " + address.getHostAddress() + " is up");
+ isClusterAvailable.set(true);
- if (isClusterDown.compareAndSet(true, false)) {
- log.info("Taking server out of maintenance mode");
- updateServerMode(Server.OperationMode.NORMAL);
- }
-
- StorageNodeManagerLocal storageNodeManager = LookupUtil.getStorageNodeManager();
+ //TODO: Add these back at a later time
+ /*StorageNodeManagerLocal storageNodeManager = LookupUtil.getStorageNodeManager();
StorageNode newClusterNode = storageNodeManager.findStorageNodeByAddress(address);
if (newClusterNode == null) {
@@ -64,19 +61,6 @@ public class StorageClusterMonitor implements StorageStateListener {
@Override
public void onStorageClusterDown(NoHostAvailableException e) {
- if (isClusterDown.compareAndSet(false, true)) {
- log.error("The server cannot connect to any storage nodes. The server will now go into maintenance mode.");
- updateServerMode(Server.OperationMode.MAINTENANCE);
- }
- }
-
- private void updateServerMode(Server.OperationMode mode) {
- ServerManagerLocal serverManager = LookupUtil.getServerManager();
- TopologyManagerLocal topologyManager = LookupUtil.getTopologyManager();
- SubjectManagerLocal subjectManager = LookupUtil.getSubjectManager();
-
- Server server = serverManager.getServer();
-
- topologyManager.updateServerMode(subjectManager.getOverlord(), new Integer[] {server.getId()}, mode);
+ isClusterAvailable.set(false);
}
}
diff --git a/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/StorageSession.java b/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/StorageSession.java
index 3f7af3f..c8f44d9 100644
--- a/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/StorageSession.java
+++ b/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/StorageSession.java
@@ -29,6 +29,14 @@ public class StorageSession implements Host.StateListener {
public void addStorageStateListener(StorageStateListener listener) {
listeners.add(listener);
+
+ for (Host host : wrappedSession.getCluster().getMetadata().getAllHosts()) {
+ if(host.getMonitor().isUp()){
+ listener.onStorageNodeUp(host.getAddress());
+ } else {
+ listener.onStorageNodeUp(host.getAddress());
+ }
+ }
}
public ResultSet execute(String query) {
commit 70318f445dde4c57ce7f9aacc0fdd22dbc336c2a
Author: Stefan Negrea <snegrea(a)redhat.com>
Date: Mon Aug 5 19:02:16 2013 -0500
Add restart to the set of rhqctl commands.
diff --git a/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/Commands.java b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/Commands.java
index ddee088..60dc67c 100644
--- a/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/Commands.java
+++ b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/Commands.java
@@ -36,6 +36,7 @@ import org.apache.commons.cli.Options;
import org.rhq.server.control.command.Console;
import org.rhq.server.control.command.Install;
import org.rhq.server.control.command.Remove;
+import org.rhq.server.control.command.Restart;
import org.rhq.server.control.command.Start;
import org.rhq.server.control.command.Status;
import org.rhq.server.control.command.Stop;
@@ -57,6 +58,7 @@ public class Commands {
registerCommand(new Install());
registerCommand(new Start());
registerCommand(new Stop());
+ registerCommand(new Restart());
registerCommand(new Status());
registerCommand(new Console());
// Add the service removal command only on windows
diff --git a/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Restart.java b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Restart.java
new file mode 100644
index 0000000..dbf53c5
--- /dev/null
+++ b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Restart.java
@@ -0,0 +1,69 @@
+/*
+ *
+ * * RHQ Management Platform
+ * * Copyright (C) 2005-2013 Red Hat, Inc.
+ * * All rights reserved.
+ * *
+ * * This program is free software; you can redistribute it and/or modify
+ * * it under the terms of the GNU General Public License, version 2, as
+ * * published by the Free Software Foundation, and/or the GNU Lesser
+ * * General Public License, version 2.1, also as published by the Free
+ * * Software Foundation.
+ * *
+ * * This program is distributed in the hope that it will be useful,
+ * * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * * GNU General Public License and the GNU Lesser General Public License
+ * * for more details.
+ * *
+ * * You should have received a copy of the GNU General Public License
+ * * and the GNU Lesser General Public License along with this program;
+ * * if not, write to the Free Software Foundation, Inc.,
+ * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+package org.rhq.server.control.command;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Options;
+
+import org.rhq.server.control.ControlCommand;
+
+/**
+ * @author Stefan Negrea
+ */
+public class Restart extends ControlCommand {
+
+ private Options options;
+
+ public Restart() {
+ options = new Options().addOption(null, STORAGE_OPTION, false, "Restart RHQ storage node")
+ .addOption(null, SERVER_OPTION, false, "Restart RHQ server")
+ .addOption(null, AGENT_OPTION, false, "Restart RHQ agent");
+ }
+
+ @Override
+ public String getName() {
+ return "restart";
+ }
+
+ @Override
+ public String getDescription() {
+ return "Restarts RHQ services.";
+ }
+
+ @Override
+ public Options getOptions() {
+ return options;
+ }
+
+ @Override
+ protected void exec(CommandLine commandLine) {
+ Stop stop = new Stop();
+ stop.exec(commandLine);
+
+ Start start = new Start();
+ start.exec(commandLine);
+ }
+}
10 years, 10 months
[rhq] modules/core modules/enterprise
by Jay Shaughnessy
modules/core/dbutils/src/main/scripts/dbsetup/authz-data.xml | 22 ---
modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml | 22 ---
modules/core/domain/src/main/java/org/rhq/core/domain/authz/Permission.java | 4
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/ImageManager.java | 5
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/roles/PermissionsEditor.java | 73 +++++-----
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/roles/RoleEditView.java | 2
modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages.properties | 28 ++-
modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_cs.properties | 26 +--
modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_de.properties | 26 +--
modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_ja.properties | 16 +-
modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_ko.properties | 16 +-
modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_pt.properties | 16 +-
modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_ru.properties | 16 +-
modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_zh.properties | 16 +-
modules/enterprise/gui/coregui/src/main/webapp/images/subsystems/bundle/BundleGroup_16.png |binary
modules/enterprise/gui/coregui/src/main/webapp/images/subsystems/bundle/BundleGroup_24.png |binary
modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/bundle/BundleManagerBeanTest.java | 49 ++++++
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/authz/RoleManagerBean.java | 15 ++
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/bundle/BundleManagerBean.java | 56 ++++---
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/bundle/BundleManagerRemote.java | 58 ++-----
20 files changed, 264 insertions(+), 202 deletions(-)
New commits:
commit 0d897752fbe25a2aa946aea419392917b87b2075
Author: Jay Shaughnessy <jshaughn(a)redhat.com>
Date: Wed Aug 7 17:31:11 2013 -0400
- Update MANAGE_BUNDLE_GROUPS perm handling to grany VIEW_BUNDLES and
to allow assign/unassign of bundles to bundle groups, as per design
- add testcode
- Change MANAGE_BUNDLE to grant only the new global bundle perms, which
should be sufficient for all bundle tasks
- update dbsetup and dbupgrade appropriately
- Fix Rolemanager.updateRole to apply permission grants for MANAGE_BUNDLE and
MANAGE_BUNDLE_GROUPS
- Review and update bundle perm I18N descriptions
- Add new bundlegroup icons
- make a few changes to permissions editor in gui as suggested by UX
- fix some jdoc formatting
diff --git a/modules/core/dbutils/src/main/scripts/dbsetup/authz-data.xml b/modules/core/dbutils/src/main/scripts/dbsetup/authz-data.xml
index ecc7d4a..75c3042 100644
--- a/modules/core/dbutils/src/main/scripts/dbsetup/authz-data.xml
+++ b/modules/core/dbutils/src/main/scripts/dbsetup/authz-data.xml
@@ -44,7 +44,7 @@
<table name="RHQ_PERMISSION">
<!-- give super-user-role all permissions
(explicitly add resource perms, even though they are implied by MANAGE_INVENTORY)
- (explicitly add bundle perms, even though they are implied by MANAGE_BUNDLE) -->
+ (explicitly add global bundle perms, even though they are implied by MANAGE_BUNDLE) -->
<data ROLE_ID="1" OPERATION="0"/> <!-- Permission.MANAGE_SECURITY -->
<data ROLE_ID="1" OPERATION="1"/> <!-- Permission.MANAGE_INVENTORY -->
<data ROLE_ID="1" OPERATION="2"/> <!-- Permission.MANAGE_SETTINGS -->
@@ -69,18 +69,14 @@
<data ROLE_ID="1" OPERATION="13"/> <!-- Permission.CONFIGURE_READ -->
<data ROLE_ID="1" OPERATION="14"/> <!-- Permission.MANAGE_EVENTS -->
<data ROLE_ID="1" OPERATION="16"/> <!-- Permission.MANAGE_DRIFT -->
- <!-- bundle permissions start here-->
- <data ROLE_ID="1" OPERATION="23"/> <!-- Permission.ASSIGN_BUNDLES_TO_GROUP -->
- <data ROLE_ID="1" OPERATION="24"/> <!-- Permission.UNASSIGN_BUNDLES_FROM_GROUP -->
- <data ROLE_ID="1" OPERATION="25"/> <!-- Permission.CREATE_BUNDLES_IN_GROUP -->
- <data ROLE_ID="1" OPERATION="26"/> <!-- Permission.DELETE_BUNDLES_FROM_GROUP -->
- <data ROLE_ID="1" OPERATION="27"/> <!-- Permission.VIEW_BUNDLES_IN_GROUP -->
- <!-- give all-resources-role MANAGE_INVENTORY and all bundle permissions other than MANAGE_BUNDLE_GROUPS
- (explicitly add resource perms as well, even though they are implied by MANAGE_INVENTORY) -->
+ <!-- give all-resources-role MANAGE_INVENTORY
+ (explicitly add resource perms as well, even though they are implied by MANAGE_INVENTORY)
+ (explicitly add global bundle perms, even though they are implied by MANAGE_BUNDLE) -->
<data ROLE_ID="2" OPERATION="1"/> <!-- Permission.MANAGE_INVENTORY -->
<data ROLE_ID="2" OPERATION="12"/> <!-- Permission.MANAGE_BUNDLE -->
<data ROLE_ID="2" OPERATION="17"/> <!-- Permission.VIEW_USERS -->
+ <data ROLE_ID="2" OPERATION="18"/> <!-- Permission.MANAGE_BUNDLE_GROUPS -->
<data ROLE_ID="2" OPERATION="19"/> <!-- Permission.CREATE_BUNDLES -->
<data ROLE_ID="2" OPERATION="20"/> <!-- Permission.DELETE_BUNDLES -->
<data ROLE_ID="2" OPERATION="21"/> <!-- Permission.DEPLOY_BUNDLES -->
@@ -97,13 +93,7 @@
<data ROLE_ID="2" OPERATION="11"/> <!-- Permission.CONFIGURE_WRITE -->
<data ROLE_ID="2" OPERATION="13"/> <!-- Permission.CONFIGURE_READ -->
<data ROLE_ID="2" OPERATION="14"/> <!-- Permission.MANAGE_EVENTS -->
- <data ROLE_ID="2" OPERATION="16"/> <!-- Permission.MANAGE_DRIFT -->
- <!-- bundle permissions start here-->
- <data ROLE_ID="2" OPERATION="23"/> <!-- Permission.ASSIGN_BUNDLES_TO_GROUP -->
- <data ROLE_ID="2" OPERATION="24"/> <!-- Permission.UNASSIGN_BUNDLES_FROM_GROUP -->
- <data ROLE_ID="2" OPERATION="25"/> <!-- Permission.CREATE_BUNDLES_IN_GROUP -->
- <data ROLE_ID="2" OPERATION="26"/> <!-- Permission.DELETE_BUNDLES_FROM_GROUP -->
- <data ROLE_ID="2" OPERATION="27"/> <!-- Permission.VIEW_BUNDLES_IN_GROUP -->
+ <data ROLE_ID="2" OPERATION="16"/> <!-- Permission.MANAGE_DRIFT -->
</table>
</dbsetup>
diff --git a/modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml b/modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml
index 9f8d018..341f0b2 100644
--- a/modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml
+++ b/modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml
@@ -2084,10 +2084,9 @@
<!-- Add new perms to superuser/all-resources roles -->
<schema-directSQL>
- <statement desc="Inserting MANAGE_BUNDLE_GROUPS permission for 'Super User' role only">
- INSERT INTO RHQ_PERMISSION (ROLE_ID, OPERATION) VALUES (1, 18)
- </statement>
-
+ <statement desc="Inserting MANAGE_BUNDLE_GROUPS permission for all MANAGE_BUNDLE (12) roles">
+ INSERT INTO rhq_permission (role_id, operation) SELECT role_id, 18 FROM rhq_permission p where p.operation = 12
+ </statement>
<statement desc="Inserting CREATE_BUNDLES permission for all MANAGE_BUNDLE (12) roles">
INSERT INTO rhq_permission (role_id, operation) SELECT role_id, 19 FROM rhq_permission p where p.operation = 12
</statement>
@@ -2100,21 +2099,6 @@
<statement desc="Inserting VIEW_BUNDLES permission for all MANAGE_BUNDLE roles">
INSERT INTO rhq_permission (role_id, operation) SELECT role_id, 22 FROM rhq_permission p where p.operation = 12
</statement>
- <statement desc="Inserting ASSIGN_BUNDLES_TO_GROUP permission for all MANAGE_BUNDLE roles">
- INSERT INTO rhq_permission (role_id, operation) SELECT role_id, 23 FROM rhq_permission p where p.operation = 12
- </statement>
- <statement desc="Inserting UNASSIGN_BUNDLES_FROM_GROUP permission for all MANAGE_BUNDLE roles">
- INSERT INTO rhq_permission (role_id, operation) SELECT role_id, 24 FROM rhq_permission p where p.operation = 12
- </statement>
- <statement desc="Inserting CREATE_BUNDLES_IN_GROUP permission for all MANAGE_BUNDLE roles">
- INSERT INTO rhq_permission (role_id, operation) SELECT role_id, 25 FROM rhq_permission p where p.operation = 12
- </statement>
- <statement desc="Inserting DELETE_BUNDLES_FROM_GROUP permission for all MANAGE_BUNDLE roles">
- INSERT INTO rhq_permission (role_id, operation) SELECT role_id, 26 FROM rhq_permission p where p.operation = 12
- </statement>
- <statement desc="Inserting VIEW_BUNDLES_IN_GROUP permission for all MANAGE_BUNDLE roles">
- INSERT INTO rhq_permission (role_id, operation) SELECT role_id, 27 FROM rhq_permission p where p.operation = 12
- </statement>
</schema-directSQL>
<!-- RHQ_BUNDLE_GROUP -->
diff --git a/modules/core/domain/src/main/java/org/rhq/core/domain/authz/Permission.java b/modules/core/domain/src/main/java/org/rhq/core/domain/authz/Permission.java
index 77f66fc..373c369 100644
--- a/modules/core/domain/src/main/java/org/rhq/core/domain/authz/Permission.java
+++ b/modules/core/domain/src/main/java/org/rhq/core/domain/authz/Permission.java
@@ -242,8 +242,8 @@ public enum Permission {
case RESOURCE:
RESOURCE_ALL.add(permission);
break;
- case BUNDLE:
- BUNDLE_ALL.add(permission);
+ default:
+ // bundle level perms do not need any aggregation
break;
}
}
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/ImageManager.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/ImageManager.java
index 76ee6ae..cf2655c 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/ImageManager.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/ImageManager.java
@@ -579,9 +579,12 @@ public class ImageManager {
public static String getBundleIcon() {
- return "subsystems/content/Content_16.png";
+ return "subsystems/bundle/Bundle_16.png";
}
+ public static String getBundleGroupIcon() {
+ return "subsystems/bundle/BundleGroup_16.png";
+ }
public static String getConfigureIcon() {
return "subsystems/configure/Configure_16.png";
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/roles/PermissionsEditor.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/roles/PermissionsEditor.java
index 77beefb..d270844 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/roles/PermissionsEditor.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/roles/PermissionsEditor.java
@@ -101,8 +101,10 @@ public class PermissionsEditor extends EnhancedVStack {
this.resourcePermissionsGrid = createResourcePermissionsGrid();
addMember(this.resourcePermissionsGrid);
- Label bundleGroupPermissionsHeader = new Label("<h4>"
- + MSG.view_adminRoles_permissions_bundleGroupPermissions() + "</h4>");
+ addMember(spacer);
+
+ Label bundleGroupPermissionsHeader = new Label("<h4>" + MSG.view_adminRoles_permissions_bundlePermissions()
+ + "</h4>");
bundleGroupPermissionsHeader.setHeight(17);
addMember(bundleGroupPermissionsHeader);
@@ -204,30 +206,10 @@ public class PermissionsEditor extends EnhancedVStack {
records.add(record);
record = createPermissionRecord(MSG.view_adminRoles_permissions_perm_manageBundleGroups(),
- "subsystems/content/Content", Permission.MANAGE_BUNDLE_GROUPS,
+ "subsystems/bundle/BundleGroup", Permission.MANAGE_BUNDLE_GROUPS,
MSG.view_adminRoles_permissions_permDesc_manageBundleGroups());
records.add(record);
- record = createPermissionRecord(MSG.view_adminRoles_permissions_perm_createBundles(),
- "subsystems/content/Content", Permission.CREATE_BUNDLES,
- MSG.view_adminRoles_permissions_permDesc_createBundles());
- records.add(record);
-
- record = createPermissionRecord(MSG.view_adminRoles_permissions_perm_deleteBundles(),
- "subsystems/content/Content", Permission.DELETE_BUNDLES,
- MSG.view_adminRoles_permissions_permDesc_deleteBundles());
- records.add(record);
-
- record = createPermissionRecord(MSG.view_adminRoles_permissions_perm_viewBundles(),
- "subsystems/content/Content", Permission.VIEW_BUNDLES,
- MSG.view_adminRoles_permissions_permDesc_viewBundles());
- records.add(record);
-
- record = createPermissionRecord(MSG.view_adminRoles_permissions_perm_deployBundles(),
- "subsystems/content/Content", Permission.DEPLOY_BUNDLES,
- MSG.view_adminRoles_permissions_permDesc_deployBundles());
- records.add(record);
-
record = createPermissionRecord(MSG.view_adminRoles_permissions_perm_viewUsers(), "global/User",
Permission.VIEW_USERS, MSG.view_adminRoles_permissions_permDesc_viewUsers());
records.add(record);
@@ -340,28 +322,48 @@ public class PermissionsEditor extends EnhancedVStack {
List<ListGridRecord> records = new ArrayList<ListGridRecord>();
- ListGridRecord record = createPermissionRecord(MSG.view_adminRoles_permissions_perm_assignBundlesToGroup(),
- "subsystems/bundle/Bundle", Permission.ASSIGN_BUNDLES_TO_GROUP,
+ ListGridRecord record = createPermissionRecord(MSG.view_adminRoles_permissions_perm_createBundles(),
+ "subsystems/content/Content", Permission.CREATE_BUNDLES,
+ MSG.view_adminRoles_permissions_permDesc_createBundles());
+ records.add(record);
+
+ record = createPermissionRecord(MSG.view_adminRoles_permissions_perm_deleteBundles(),
+ "subsystems/content/Content", Permission.DELETE_BUNDLES,
+ MSG.view_adminRoles_permissions_permDesc_deleteBundles());
+ records.add(record);
+
+ record = createPermissionRecord(MSG.view_adminRoles_permissions_perm_viewBundles(),
+ "subsystems/content/Content", Permission.VIEW_BUNDLES,
+ MSG.view_adminRoles_permissions_permDesc_viewBundles());
+ records.add(record);
+
+ record = createPermissionRecord(MSG.view_adminRoles_permissions_perm_deployBundles(),
+ "subsystems/content/Content", Permission.DEPLOY_BUNDLES,
+ MSG.view_adminRoles_permissions_permDesc_deployBundles());
+ records.add(record);
+
+ record = createPermissionRecord(MSG.view_adminRoles_permissions_perm_assignBundlesToGroup(),
+ "subsystems/bundle/BundleGroup", Permission.ASSIGN_BUNDLES_TO_GROUP,
MSG.view_adminRoles_permissions_permDesc_assignBundlesToGroup());
records.add(record);
record = createPermissionRecord(MSG.view_adminRoles_permissions_perm_unassignBundlesFromGroup(),
- "subsystems/bundle/Bundle", Permission.UNASSIGN_BUNDLES_FROM_GROUP,
+ "subsystems/bundle/BundleGroup", Permission.UNASSIGN_BUNDLES_FROM_GROUP,
MSG.view_adminRoles_permissions_permDesc_unassignBundlesFromGroup());
records.add(record);
record = createPermissionRecord(MSG.view_adminRoles_permissions_perm_createBundlesInGroup(),
- "subsystems/bundle/Bundle", Permission.CREATE_BUNDLES_IN_GROUP,
+ "subsystems/bundle/BundleGroup", Permission.CREATE_BUNDLES_IN_GROUP,
MSG.view_adminRoles_permissions_permDesc_createBundlesInGroup());
records.add(record);
record = createPermissionRecord(MSG.view_adminRoles_permissions_perm_deleteBundlesFromGroup(),
- "subsystems/bundle/Bundle", Permission.DELETE_BUNDLES_FROM_GROUP,
+ "subsystems/bundle/BundleGroup", Permission.DELETE_BUNDLES_FROM_GROUP,
MSG.view_adminRoles_permissions_permDesc_deleteBundlesFromGroup());
records.add(record);
record = createPermissionRecord(MSG.view_adminRoles_permissions_perm_viewBundlesInGroup(),
- "subsystems/bundle/Bundle", Permission.VIEW_BUNDLES_IN_GROUP,
+ "subsystems/bundle/BundleGroup", Permission.VIEW_BUNDLES_IN_GROUP,
MSG.view_adminRoles_permissions_permDesc_viewBundlesInGroup());
records.add(record);
@@ -451,10 +453,15 @@ public class PermissionsEditor extends EnhancedVStack {
.view_adminRoles_permissions_illegalDeselectionDueToCorrespondingWritePermSelection(permissionDisplayName);
handleIllegalPermissionSelection(event, messageString);
} else if (!authorized && selectedPermissions.contains(Permission.MANAGE_BUNDLE)
- && Permission.BUNDLE_ALL.contains(permission)) {
+ && permission != Permission.MANAGE_BUNDLE && Permission.BUNDLE_ALL.contains(permission)) {
String messageString = MSG
.view_adminRoles_permissions_illegalDeselectionDueToManageBundleSelection(permissionDisplayName);
handleIllegalPermissionSelection(event, messageString);
+ } else if (!authorized && selectedPermissions.contains(Permission.MANAGE_BUNDLE_GROUPS)
+ && permission == Permission.VIEW_BUNDLES) {
+ String messageString = MSG
+ .view_adminRoles_permissions_illegalDeselectionDueToManageBundleGroupsSelection(permissionDisplayName);
+ handleIllegalPermissionSelection(event, messageString);
} else {
updatePermissions(authorized, permission);
@@ -504,6 +511,12 @@ public class PermissionsEditor extends EnhancedVStack {
messageString = MSG.view_adminRoles_permissions_autoselecting_manageBundle_implied();
redrawRequired = true;
}
+ } else if (permission == Permission.MANAGE_BUNDLE_GROUPS) {
+ // MANAGE_BUNDLE_GROUPS implies VIEW_BUNDLES
+ if (this.selectedPermissions.add(Permission.VIEW_BUNDLES)) {
+ messageString = MSG.view_adminRoles_permissions_autoselecting_manageBundleGroups_implied();
+ redrawRequired = true;
+ }
}
} else {
this.selectedPermissions.remove(permission);
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/roles/RoleEditView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/roles/RoleEditView.java
index 9c2dc96..ee2073b 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/roles/RoleEditView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/roles/RoleEditView.java
@@ -197,7 +197,7 @@ public class RoleEditView extends AbstractRecordEditor<RolesDataSource> implemen
}
private Tab buildBundleGroupsTab(TabSet tabSet) {
- Tab tab = new Tab(MSG.common_title_bundleGroups(), ImageManager.getBundleIcon());
+ Tab tab = new Tab(MSG.common_title_bundleGroups(), ImageManager.getBundleGroupIcon());
// NOTE: We will set the tab content to the bundle group selector later once the Role has been fetched.
return tab;
diff --git a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages.properties b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages.properties
index 8555ca2..67ec087 100644
--- a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages.properties
+++ b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages.properties
@@ -20,11 +20,11 @@ chart_hover_period_label = Period
chart_hover_start_label = Start
chart_hover_time_format = %I:%M:%S %p
chart_ie_not_supported = Charting is not available for this browser.
-chart_metrics= Metrics
-chart_metrics_add_to_dashboard_label= Dashboards
-chart_metrics_collapse_tooltip= Click here to see additional tabular availability data.
-chart_metrics_expand_tooltip= Click here to collapse additional availability detail.
-chart_metrics_sparkline_header= Chart
+chart_metrics = Metrics
+chart_metrics_add_to_dashboard_label = Dashboards
+chart_metrics_collapse_tooltip = Click here to see additional tabular availability data.
+chart_metrics_expand_tooltip = Click here to collapse additional availability detail.
+chart_metrics_sparkline_header = Chart
chart_no_data_label = No Data
chart_single_value_label = Value
chart_slider_button_bar_day = Day
@@ -512,12 +512,14 @@ view_adminRoles_ldapGroupsReadOnly = LDAP group data is read only
view_adminRoles_noLdap = The LDAP security integration is not configured. To configure LDAP, go to <a {0}>{1}</a>.
view_adminRoles_permissions_autoselecting_configureRead_implied = Autodeselected CONFIGURE_WRITE permission, since lack of CONFIGURE_READ implies lack of it...
view_adminRoles_permissions_autoselecting_configureWrite_implied = Autoselected CONFIGURE_READ permission, since CONFIGURE_WRITE implies it...
-view_adminRoles_permissions_autoselecting_manageBundle_implied = Autoselected unselected permissions, since MANAGE_BUNDLE implies all other bundle permissions...
+view_adminRoles_permissions_autoselecting_manageBundleGroups_implied = Autoselected View Bundles, which is granted by Manage Bundle Groups...
+view_adminRoles_permissions_autoselecting_manageBundle_implied = Autoselected unselected permissions, since Manage Bundle permission grants Manage Bundle Groups, Create Bundles, Delete Bundles, View Bundles and Deploy_Bundles permissions...
view_adminRoles_permissions_autoselecting_manageInventory_implied = Autoselected unselected Resource permissions, since MANAGE_INVENTORY implies all Resource permissions...
view_adminRoles_permissions_autoselecting_manageSecurity_implied = Autoselected unselected permissions, since MANAGE_SECURITY implies all other permissions...
-view_adminRoles_permissions_bundleGroupPermissions = Bundle Group Permissions
+view_adminRoles_permissions_bundlePermissions = Bundle Permissions
view_adminRoles_permissions_globalPermissions = Global Permissions
view_adminRoles_permissions_illegalDeselectionDueToCorrespondingWritePermSelection = {0} read permission cannot be deselected, unless the {0} write permission, which implies the read permission, is deselected first.
+view_adminRoles_permissions_illegalDeselectionDueToManageBundleGroupsSelection = {0} permission cannot be deselected, unless Manage Bundle Groups, which implies {0} permission, is deselected first.
view_adminRoles_permissions_illegalDeselectionDueToManageBundleSelection = {0} permission cannot be deselected, unless Manage Bundle, which implies all Bundle permissions, is deselected first.
view_adminRoles_permissions_illegalDeselectionDueToManageInventorySelection = {0} permission cannot be deselected, unless Manage Inventory, which implies all Resource permissions, is deselected first.
view_adminRoles_permissions_illegalDeselectionDueToManageSecuritySelection = {0} permission cannot be deselected, unless the Manage Security permission, which implies all other permissions, is deselected first.
@@ -525,20 +527,20 @@ view_adminRoles_permissions_isAuthorized = Authorized?
view_adminRoles_permissions_isRead = Read?
view_adminRoles_permissions_isWrite = Write?
view_adminRoles_permissions_permDesc_assignBundlesToGroup = can copy a viewable bundle to the bundle group
-view_adminRoles_permissions_permDesc_createBundles = can create new bundle [version]s. can copy existing bundles between viewable groups
+view_adminRoles_permissions_permDesc_createBundles = can create new bundle [version]s. can assign viewable bundles to viewable groups
view_adminRoles_permissions_permDesc_createBundlesInGroup = can create new bundle [version]s for the bundle group. can copy a viewable bundle to the bundle group.
view_adminRoles_permissions_permDesc_deleteBundles = can delete or unassign viewable bundle [version]s
view_adminRoles_permissions_permDesc_deleteBundlesFromGroup = can delete bundle [version]s from the bundle group (implicitly deleting then from other assigned groups)
view_adminRoles_permissions_permDesc_deployBundles = can deploy any viewable bundle version to any viewable, deployable, compatible, resource group
-view_adminRoles_permissions_permDesc_manageBundleGroups = can create, update, or delete bundle groups
-view_adminRoles_permissions_permDesc_manageBundles = can create, update, or delete provisioning bundles (viewing is implied for everyone)
+view_adminRoles_permissions_permDesc_manageBundleGroups = can create and delete bundle groups. can assign bundles to bundle groups. grants View Bundles permissions
+view_adminRoles_permissions_permDesc_manageBundles = can perform any bundle task. a convenience permission that grants Manage Bundle Groups, Create Bundles, Delete Bundles, Deploy Bundles and View Bundles permissions.
view_adminRoles_permissions_permDesc_manageInventory = has all Resource permissions, as described below, for all Resources; can create, update, and delete groups; and can import auto-discovered or manually discovered Resources
view_adminRoles_permissions_permDesc_manageRepositories = can create, update, or delete repositories of any user (everyone can create their own repositories), can associate content sources to repositories.
view_adminRoles_permissions_permDesc_manageSecurity = can create, update, or delete users and roles - implies all other permissions
view_adminRoles_permissions_permDesc_manageSettings = can modify the {0} Server configuration and perform any Server-related functionality
view_adminRoles_permissions_permDesc_unassignBundlesFromGroup = can unassign (not delete) a bundle from the bundle group
-view_adminRoles_permissions_permDesc_viewBundles = can view any bundle including global bundles (those not assigned to any bundle group)
-view_adminRoles_permissions_permDesc_viewBundlesInGroup = can view any bundle in the group
+view_adminRoles_permissions_permDesc_viewBundles = can view bundle details, deployments, etc for any bundle, including unassigned bundles (those not assigned to any bundle group)
+view_adminRoles_permissions_permDesc_viewBundlesInGroup = (IMPLIED) can view bundle details, deployments, etc for any bundle in bundle groups associated with the relevant roles.
view_adminRoles_permissions_permDesc_viewUsers = can view other users, with the exception of their assigned roles
view_adminRoles_permissions_permReadDesc_configure = view Resource configuration and Resource configuration revision history
view_adminRoles_permissions_permReadDesc_control = (IMPLIED) view available operations and operation execution history
@@ -2255,8 +2257,8 @@ widget_resourceFactoryWizard_importWizardTitle = Import Resource of Type [{0}]
widget_resourceFactoryWizard_importWizardWindowTitle = Resource Import Wizard
widget_resourceFactoryWizard_infoStepName = Resource Information
widget_resourceFactoryWizard_infoStep_loadFail = Failed to get available Architectures
-widget_resourceFactoryWizard_namePrompt = New Resource Name
widget_resourceFactoryWizard_nameComment = Not all management plug-ins or their managed resources allow the agent to set the name for a new resource. This value will only be used by agent plug-ins that support the capability. For plug-ins that do not support the capability, the resource may receive a generic or different name when it is discovered.
+widget_resourceFactoryWizard_namePrompt = New Resource Name
widget_resourceFactoryWizard_templatePrompt = Connection Settings Template
widget_resourceFactoryWizard_timeoutFailure = Timed out
widget_resourceFactoryWizard_timeoutHelp = A timeout duration that if specified will override the default timeout for child resource creation (on the {0} Agent). The default timeout is set to 60 seconds. A higher value may be useful for particularly long create actions, like deployment of a large application. Usually used if a previous attempt suffered a timeout failure. Note that if there is a timeout failure, it is still possible that the resource deployment succeeded. In the event of a timeout you may want to execute a discovery scan before attempting to redeploy the resource.
diff --git a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_cs.properties b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_cs.properties
index c43817d..2c97c84 100644
--- a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_cs.properties
+++ b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_cs.properties
@@ -48,11 +48,11 @@ chart_hover_date_format = %d.%m.%y
##chart_hover_start_label = Start
chart_hover_time_format = %H:%M:%S
##chart_ie_not_supported = Charting is not available for this browser.
-##chart_metrics= Metrics
-##chart_metrics_add_to_dashboard_label= Dashboards
-##chart_metrics_collapse_tooltip= Click here to see additional tabular availability data.
-##chart_metrics_expand_tooltip= Click here to collapse additional availability detail.
-##chart_metrics_sparkline_header= Chart
+##chart_metrics = Metrics
+##chart_metrics_add_to_dashboard_label = Dashboards
+##chart_metrics_collapse_tooltip = Click here to see additional tabular availability data.
+##chart_metrics_expand_tooltip = Click here to collapse additional availability detail.
+##chart_metrics_sparkline_header = Chart
##chart_no_data_label = No Data
##chart_single_value_label = Value
##chart_slider_button_bar_day = Day
@@ -531,12 +531,14 @@ view_adminRoles_ldapGroupsReadOnly = data LDAP skupiny jsou jen pro čtení
view_adminRoles_noLdap = Integrace LDAP není nakonfigurována. K nastavení řízení bezpečnosti přes LDAP prosím navštivte <a {0}>{1}</a>.
view_adminRoles_permissions_autoselecting_configureRead_implied = Automaticky odoznačeno CONFIGURE_WRITE povolení, protože absence CONFIGURE_READ to implikuje...
view_adminRoles_permissions_autoselecting_configureWrite_implied = Automaticky označeno CONFIGURE_READ povolení, protože CONFIGURE_WRITE jej implikuje...
-##view_adminRoles_permissions_autoselecting_manageBundle_implied = Autoselected unselected permissions, since MANAGE_BUNDLE implies all other bundle permissions...
+##view_adminRoles_permissions_autoselecting_manageBundleGroups_implied = Autoselected View Bundles, which is granted by Manage Bundle Groups...
+##view_adminRoles_permissions_autoselecting_manageBundle_implied = Autoselected unselected permissions, since Manage Bundle permission grants Manage Bundle Groups, Create Bundles, Delete Bundles, View Bundles and Deploy_Bundles permissions...
view_adminRoles_permissions_autoselecting_manageInventory_implied = Automaticky označeny neoznačené zdroje, protože MANAGE_INVENTORY implikuje povolení na všech zdrojích...
view_adminRoles_permissions_autoselecting_manageSecurity_implied = Automaticky označeny neoznačená povolení, protože MANAGE_SECURITY implikuje povolení na všech práv...
-view_adminRoles_permissions_bundleGroupPermissions = Bundle Group Permissions
+##view_adminRoles_permissions_bundlePermissions = Bundle Permissions
view_adminRoles_permissions_globalPermissions = Globální povolení
##view_adminRoles_permissions_illegalDeselectionDueToCorrespondingWritePermSelection = {0} read permission cannot be deselected, unless the {0} write permission, which implies the read permission, is deselected first.
+##view_adminRoles_permissions_illegalDeselectionDueToManageBundleGroupsSelection = {0} permission cannot be deselected, unless Manage Bundle Groups, which implies {0} permission, is deselected first.
##view_adminRoles_permissions_illegalDeselectionDueToManageBundleSelection = {0} permission cannot be deselected, unless Manage Bundle, which implies all Bundle permissions, is deselected first.
##view_adminRoles_permissions_illegalDeselectionDueToManageInventorySelection = {0} permission cannot be deselected, unless Manage Inventory, which implies all Resource permissions, is deselected first.
##view_adminRoles_permissions_illegalDeselectionDueToManageSecuritySelection = {0} permission cannot be deselected, unless the Manage Security permission, which implies all other permissions, is deselected first.
@@ -544,20 +546,20 @@ view_adminRoles_permissions_isAuthorized = Autorizován?
view_adminRoles_permissions_isRead = Čtení?
view_adminRoles_permissions_isWrite = Zápis?
##view_adminRoles_permissions_permDesc_assignBundlesToGroup = can copy a viewable bundle to the bundle group
-##view_adminRoles_permissions_permDesc_createBundles = can create new bundle [version]s. can copy existing bundles between viewable groups
+##view_adminRoles_permissions_permDesc_createBundles = can create new bundle [version]s. can assign viewable bundles to viewable groups
##view_adminRoles_permissions_permDesc_createBundlesInGroup = can create new bundle [version]s for the bundle group. can copy a viewable bundle to the bundle group.
##view_adminRoles_permissions_permDesc_deleteBundles = can delete or unassign viewable bundle [version]s
##view_adminRoles_permissions_permDesc_deleteBundlesFromGroup = can delete bundle [version]s from the bundle group (implicitly deleting then from other assigned groups)
##view_adminRoles_permissions_permDesc_deployBundles = can deploy any viewable bundle version to any viewable, deployable, compatible, resource group
-##view_adminRoles_permissions_permDesc_manageBundleGroups = can create, update, or delete bundle groups
-view_adminRoles_permissions_permDesc_manageBundles = může vytvářet, měnit, mazat balíky (zobrazovat může kdokoli)
+##view_adminRoles_permissions_permDesc_manageBundleGroups = can create and delete bundle groups. can assign bundles to bundle groups. grants View Bundles permissions
+##view_adminRoles_permissions_permDesc_manageBundles = can perform any bundle task. a convenience permission that grants Manage Bundle Groups, Create Bundles, Delete Bundles, Deploy Bundles and View Bundles permissions.
view_adminRoles_permissions_permDesc_manageInventory = má všechna práva zdroje: může vytvářet, měnit, mazat skupiny, může importovat automaticky nebo manuálně nalezené zdroje
view_adminRoles_permissions_permDesc_manageRepositories = může vytvářet, měnit, mazat repozitáře jakýchkoli uživatelů (každý může vytvářet své repozitáře), může asociovat zdroje obsahů s repozitáři
view_adminRoles_permissions_permDesc_manageSecurity = může vytvářet, měnit, mazat uživatele a role - implikuje všechna ostatní povolení
view_adminRoles_permissions_permDesc_manageSettings = může modifikovat {0} serverovou konfiguraci a provozovat jakékoli operace související se serverem
##view_adminRoles_permissions_permDesc_unassignBundlesFromGroup = can unassign (not delete) a bundle from the bundle group
-##view_adminRoles_permissions_permDesc_viewBundles = can view any bundle including global bundles (those not assigned to any bundle group)
-##view_adminRoles_permissions_permDesc_viewBundlesInGroup = can view any bundle in the group
+##view_adminRoles_permissions_permDesc_viewBundles = can view bundle details, deployments, etc for any bundle, including unassigned bundles (those not assigned to any bundle group)
+##view_adminRoles_permissions_permDesc_viewBundlesInGroup = (IMPLIED) can view bundle details, deployments, etc for any bundle in bundle groups associated with the relevant roles.
view_adminRoles_permissions_permDesc_viewUsers = může zobrazovat ostatní uživatele s výjimkou jejich přiřazených rolí
view_adminRoles_permissions_permReadDesc_configure = zobrazí konfiguraci zdroje a historii konfigurace zdroje
view_adminRoles_permissions_permReadDesc_control = (VÝCHOZÍ) zobrazí dostupné operace a historii spouštění operací
diff --git a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_de.properties b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_de.properties
index 7159f03..d4f053b 100644
--- a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_de.properties
+++ b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_de.properties
@@ -23,11 +23,11 @@ chart_hover_period_label = Zeitraum
chart_hover_start_label = Start
chart_hover_time_format = %H:%M:%S
chart_ie_not_supported = Charting ist bei diesem Browser nicht unterstützt
-##chart_metrics= Metrics
-##chart_metrics_collapse_tooltip= Click here to see additional tabular availability data.
-##chart_metrics_expand_tooltip= Click here to collapse additional availability detail.
-##chart_metrics_sparkline_header= Chart
-##chart_metrics_add_to_dashboard_label= Dashboards
+##chart_metrics = Metrics
+##chart_metrics_add_to_dashboard_label = Dashboards
+##chart_metrics_collapse_tooltip = Click here to see additional tabular availability data.
+##chart_metrics_expand_tooltip = Click here to collapse additional availability detail.
+##chart_metrics_sparkline_header = Chart
chart_no_data_label = Keine Daten vorhanden
##chart_single_value_label = Value
chart_slider_button_bar_day = Tag
@@ -510,12 +510,14 @@ view_adminRoles_ldapGroupsReadOnly = LDAP Gruppendaten können nur gelesen werde
view_adminRoles_noLdap = Die LDAP-Integration ist nicht konfiguriert. Um LDAP zu konfigurieren, wechseln sie zu <a {0}>{1}</a>.
##view_adminRoles_permissions_autoselecting_configureRead_implied = Autodeselected CONFIGURE_WRITE permission, since lack of CONFIGURE_READ implies lack of it...
##view_adminRoles_permissions_autoselecting_configureWrite_implied = Autoselected CONFIGURE_READ permission, since CONFIGURE_WRITE implies it...
-##view_adminRoles_permissions_autoselecting_manageBundle_implied = Autoselected unselected permissions, since MANAGE_BUNDLE implies all other bundle permissions...
+##view_adminRoles_permissions_autoselecting_manageBundleGroups_implied = Autoselected View Bundles, which is granted by Manage Bundle Groups...
+##view_adminRoles_permissions_autoselecting_manageBundle_implied = Autoselected unselected permissions, since Manage Bundle permission grants Manage Bundle Groups, Create Bundles, Delete Bundles, View Bundles and Deploy_Bundles permissions...
##view_adminRoles_permissions_autoselecting_manageInventory_implied = Autoselected unselected Resource permissions, since MANAGE_INVENTORY implies all Resource permissions...
##view_adminRoles_permissions_autoselecting_manageSecurity_implied = Autoselected unselected permissions, since MANAGE_SECURITY implies all other permissions...
-view_adminRoles_permissions_bundleGroupPermissions = Bundle Group Permissions
+##view_adminRoles_permissions_bundlePermissions = Bundle Permissions
view_adminRoles_permissions_globalPermissions = Globale Rechte
##view_adminRoles_permissions_illegalDeselectionDueToCorrespondingWritePermSelection = {0} read permission cannot be deselected, unless the {0} write permission, which implies the read permission, is deselected first.
+##view_adminRoles_permissions_illegalDeselectionDueToManageBundleGroupsSelection = {0} permission cannot be deselected, unless Manage Bundle Groups, which implies {0} permission, is deselected first.
##view_adminRoles_permissions_illegalDeselectionDueToManageBundleSelection = {0} permission cannot be deselected, unless Manage Bundle, which implies all Bundle permissions, is deselected first.
##view_adminRoles_permissions_illegalDeselectionDueToManageInventorySelection = {0} permission cannot be deselected, unless Manage Inventory, which implies all Resource permissions, is deselected first.
##view_adminRoles_permissions_illegalDeselectionDueToManageSecuritySelection = {0} permission cannot be deselected, unless the Manage Security permission, which implies all other permissions, is deselected first.
@@ -523,20 +525,20 @@ view_adminRoles_permissions_isAuthorized = Berechtigt?
view_adminRoles_permissions_isRead = Lesen?
view_adminRoles_permissions_isWrite = Schreiben?
##view_adminRoles_permissions_permDesc_assignBundlesToGroup = can copy a viewable bundle to the bundle group
-##view_adminRoles_permissions_permDesc_createBundles = can create new bundle [version]s. can copy existing bundles between viewable groups
+##view_adminRoles_permissions_permDesc_createBundles = can create new bundle [version]s. can assign viewable bundles to viewable groups
##view_adminRoles_permissions_permDesc_createBundlesInGroup = can create new bundle [version]s for the bundle group. can copy a viewable bundle to the bundle group.
##view_adminRoles_permissions_permDesc_deleteBundles = can delete or unassign viewable bundle [version]s
##view_adminRoles_permissions_permDesc_deleteBundlesFromGroup = can delete bundle [version]s from the bundle group (implicitly deleting then from other assigned groups)
##view_adminRoles_permissions_permDesc_deployBundles = can deploy any viewable bundle version to any viewable, deployable, compatible, resource group
-##view_adminRoles_permissions_permDesc_manageBundleGroups = can create, update, or delete bundle groups
-view_adminRoles_permissions_permDesc_manageBundles = Kann Bundles anlegen, aktualisieren und löschen (Ansehen ist für alle implizit erlaubt).
+##view_adminRoles_permissions_permDesc_manageBundleGroups = can create and delete bundle groups. can assign bundles to bundle groups. grants View Bundles permissions
+##view_adminRoles_permissions_permDesc_manageBundles = can perform any bundle task. a convenience permission that grants Manage Bundle Groups, Create Bundles, Delete Bundles, Deploy Bundles and View Bundles permissions.
view_adminRoles_permissions_permDesc_manageInventory = Hat alle Rechte auf alle Ressourcen, wie unten beschrieben. Kann Gruppen anlegen, aktualisieren und löschen. Kann Ressourcen in das Inventar aufnehmen.
##view_adminRoles_permissions_permDesc_manageRepositories = can create, update, or delete repositories of any user (everyone can create their own repositories), can associate content sources to repositories.
view_adminRoles_permissions_permDesc_manageSecurity = Kann Benutzer und Rollen anlegen, aktualisieren oder löschen (Anschauen ist für alle implizit erlaubt)
view_adminRoles_permissions_permDesc_manageSettings = Kann die Konfiguration des {0}-Servers ändern und jegliche Server-bezogene Funktionalität ausführen.
##view_adminRoles_permissions_permDesc_unassignBundlesFromGroup = can unassign (not delete) a bundle from the bundle group
-##view_adminRoles_permissions_permDesc_viewBundles = can view any bundle including global bundles (those not assigned to any bundle group)
-##view_adminRoles_permissions_permDesc_viewBundlesInGroup = can view any bundle in the group
+##view_adminRoles_permissions_permDesc_viewBundles = can view bundle details, deployments, etc for any bundle, including unassigned bundles (those not assigned to any bundle group)
+##view_adminRoles_permissions_permDesc_viewBundlesInGroup = (IMPLIED) can view bundle details, deployments, etc for any bundle in bundle groups associated with the relevant roles.
##view_adminRoles_permissions_permDesc_viewUsers = can view other users, with the exception of their assigned roles
view_adminRoles_permissions_permReadDesc_configure = Ansehen der Ressourcen-Konfiguration und des Verlaufs derselben.
view_adminRoles_permissions_permReadDesc_control = (IMPLIZIT) Ansehen der verfügbaren Operationen und des Verlaufs der ausgeführen Operationen
diff --git a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_ja.properties b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_ja.properties
index 10dd2d1..c7c1f0a 100644
--- a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_ja.properties
+++ b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_ja.properties
@@ -509,12 +509,14 @@ view_adminRoles_ldapGroupsReadOnly = LDAPグループデータは読み出し専
view_adminRoles_noLdap = LDAPセキュリティの統合は構成されていません。LDAPを構成するには、 <a {0}>{1}</a>に行ってください。
view_adminRoles_permissions_autoselecting_configureRead_implied = CONFIGURE_WRITE権限が自動的に選択されました。なぜなら、CONFIGURE_READが無いことがそれを暗示しているからです。
view_adminRoles_permissions_autoselecting_configureWrite_implied = CONFIGURE_READ権限が自動的に選択されました。なぜなら、CONFIGURE_WRITEがそれを暗示しているからです。
-##view_adminRoles_permissions_autoselecting_manageBundle_implied = Autoselected unselected permissions, since MANAGE_BUNDLE implies all other bundle permissions...
+##view_adminRoles_permissions_autoselecting_manageBundleGroups_implied = Autoselected View Bundles, which is granted by Manage Bundle Groups...
+##view_adminRoles_permissions_autoselecting_manageBundle_implied = Autoselected unselected permissions, since Manage Bundle permission grants Manage Bundle Groups, Create Bundles, Delete Bundles, View Bundles and Deploy_Bundles permissions...
view_adminRoles_permissions_autoselecting_manageInventory_implied = 未選択のリソース権限が自動的に選択されました。なぜなら、MANAGE_INVENTORYはすべてのリソース権限を暗示しているからです。
view_adminRoles_permissions_autoselecting_manageSecurity_implied = 未選択の権限が自動的に選択されました。なぜなら、MANAGE_SECURITYは他のすべての権限を暗示しているからです。
-view_adminRoles_permissions_bundleGroupPermissions = Bundle Group Permissions
+##view_adminRoles_permissions_bundlePermissions = Bundle Permissions
view_adminRoles_permissions_globalPermissions = グローバル権限
view_adminRoles_permissions_illegalDeselectionDueToCorrespondingWritePermSelection = {0} 読み取り権限は選択解除できませんでした。読み取り権限を暗示する {0} 書き込み権限が最初に選択解除されなければそれはできません。
+##view_adminRoles_permissions_illegalDeselectionDueToManageBundleGroupsSelection = {0} permission cannot be deselected, unless Manage Bundle Groups, which implies {0} permission, is deselected first.
##view_adminRoles_permissions_illegalDeselectionDueToManageBundleSelection = {0} permission cannot be deselected, unless Manage Bundle, which implies all Bundle permissions, is deselected first.
view_adminRoles_permissions_illegalDeselectionDueToManageInventorySelection = {0} 権限は選択解除できませんでした。他のすべてのリソースを暗示する管理インベントリが最初に選択解除されなければそれはできません。
view_adminRoles_permissions_illegalDeselectionDueToManageSecuritySelection = {0} 権限は選択解除できませんでした。他のすべての権限を暗示する管理セキュリティ権限が最初に選択解除されなければそれはできません。
@@ -522,20 +524,20 @@ view_adminRoles_permissions_isAuthorized = 権限があるか?
view_adminRoles_permissions_isRead = 読み出しですか?
view_adminRoles_permissions_isWrite = 書き込みですか?
##view_adminRoles_permissions_permDesc_assignBundlesToGroup = can copy a viewable bundle to the bundle group
-##view_adminRoles_permissions_permDesc_createBundles = can create new bundle [version]s. can copy existing bundles between viewable groups
+##view_adminRoles_permissions_permDesc_createBundles = can create new bundle [version]s. can assign viewable bundles to viewable groups
##view_adminRoles_permissions_permDesc_createBundlesInGroup = can create new bundle [version]s for the bundle group. can copy a viewable bundle to the bundle group.
##view_adminRoles_permissions_permDesc_deleteBundles = can delete or unassign viewable bundle [version]s
##view_adminRoles_permissions_permDesc_deleteBundlesFromGroup = can delete bundle [version]s from the bundle group (implicitly deleting then from other assigned groups)
##view_adminRoles_permissions_permDesc_deployBundles = can deploy any viewable bundle version to any viewable, deployable, compatible, resource group
-##view_adminRoles_permissions_permDesc_manageBundleGroups = can create, update, or delete bundle groups
-view_adminRoles_permissions_permDesc_manageBundles = プロビジョニングバンドルの作成、更新、削除が可能です(誰でも暗黙的に閲覧可能です)
+##view_adminRoles_permissions_permDesc_manageBundleGroups = can create and delete bundle groups. can assign bundles to bundle groups. grants View Bundles permissions
+##view_adminRoles_permissions_permDesc_manageBundles = can perform any bundle task. a convenience permission that grants Manage Bundle Groups, Create Bundles, Delete Bundles, Deploy Bundles and View Bundles permissions.
view_adminRoles_permissions_permDesc_manageInventory = すべてのリソースについてすべてのリソース権限を持ちます。つまり、グループの作成、更新、削除、そして自動検出された、または手動で検出されたリソースのインポートが可能です
view_adminRoles_permissions_permDesc_manageRepositories = ユーザーのリポジトリの作成、更新、削除が可能(誰でもリポジトリを作成可能)で、コンテントソースとリポジトリも関連づけができます。
view_adminRoles_permissions_permDesc_manageSecurity = ユーザーとロールの作成、更新、削除、その他すべての権限が可能です
view_adminRoles_permissions_permDesc_manageSettings = {0}サーバーの修正と任意のサーバー関連の機能の実行ができます
##view_adminRoles_permissions_permDesc_unassignBundlesFromGroup = can unassign (not delete) a bundle from the bundle group
-##view_adminRoles_permissions_permDesc_viewBundles = can view any bundle including global bundles (those not assigned to any bundle group)
-##view_adminRoles_permissions_permDesc_viewBundlesInGroup = can view any bundle in the group
+##view_adminRoles_permissions_permDesc_viewBundles = can view bundle details, deployments, etc for any bundle, including unassigned bundles (those not assigned to any bundle group)
+##view_adminRoles_permissions_permDesc_viewBundlesInGroup = (IMPLIED) can view bundle details, deployments, etc for any bundle in bundle groups associated with the relevant roles.
view_adminRoles_permissions_permDesc_viewUsers = 他のユーザーを閲覧できます。しかし、それらに割り当てられたロールは見えません。
view_adminRoles_permissions_permReadDesc_configure = リソース構成とリソース構成リビジョン履歴の閲覧
view_adminRoles_permissions_permReadDesc_control = 利用可能オペレーション; オペレーション実行履歴の(暗黙的な)閲覧
diff --git a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_ko.properties b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_ko.properties
index 9e4f7b2..0213540 100644
--- a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_ko.properties
+++ b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_ko.properties
@@ -460,12 +460,14 @@ view_adminRoles_ldapGroups = LDAP 그룹
view_adminRoles_noLdap = LDAP 보안 통합이 설정되지 않았습니다. LDAP을 구성하려면 <a {0}>{1}</a>로 가십시요.
##view_adminRoles_permissions_autoselecting_configureRead_implied = Autodeselected CONFIGURE_WRITE permission, since lack of CONFIGURE_READ implies lack of it...
##view_adminRoles_permissions_autoselecting_configureWrite_implied = Autoselected CONFIGURE_READ permission, since CONFIGURE_WRITE implies it...
-##view_adminRoles_permissions_autoselecting_manageBundle_implied = Autoselected unselected permissions, since MANAGE_BUNDLE implies all other bundle permissions...
+##view_adminRoles_permissions_autoselecting_manageBundleGroups_implied = Autoselected View Bundles, which is granted by Manage Bundle Groups...
+##view_adminRoles_permissions_autoselecting_manageBundle_implied = Autoselected unselected permissions, since Manage Bundle permission grants Manage Bundle Groups, Create Bundles, Delete Bundles, View Bundles and Deploy_Bundles permissions...
##view_adminRoles_permissions_autoselecting_manageInventory_implied = Autoselected unselected Resource permissions, since MANAGE_INVENTORY implies all Resource permissions...
##view_adminRoles_permissions_autoselecting_manageSecurity_implied = Autoselected unselected permissions, since MANAGE_SECURITY implies all other permissions...
-view_adminRoles_permissions_bundleGroupPermissions = Bundle Group Permissions
+##view_adminRoles_permissions_bundlePermissions = Bundle Permissions
view_adminRoles_permissions_globalPermissions = 글로벌 권한
view_adminRoles_permissions_illegalDeselectionDueToCorrespondingWritePermSelection = {0} 읽기 권한은 선택 해제 할 수 없습니다. 읽기 권한을 암시하는 {0} 쓰기 권한이 먼저 선택 해제되어야 그것은 수행할 수 있습니다.
+##view_adminRoles_permissions_illegalDeselectionDueToManageBundleGroupsSelection = {0} permission cannot be deselected, unless Manage Bundle Groups, which implies {0} permission, is deselected first.
##view_adminRoles_permissions_illegalDeselectionDueToManageBundleSelection = {0} permission cannot be deselected, unless Manage Bundle, which implies all Bundle permissions, is deselected first.
view_adminRoles_permissions_illegalDeselectionDueToManageInventorySelection = {0} 권한은 선택 해제 할 수 없습니다. 다른 모든 자원을 암시하는 관리 인벤토리가 먼저 선택 해제되어야 그것은 수행할 수 있습니다.
view_adminRoles_permissions_illegalDeselectionDueToManageSecuritySelection = {0} 권한은 선택 해제 할 수 없습니다. 다른 모든 권한을 암시하는 관리 보안 권한이 먼저 선택 해제되어야 그것은 수행할 수 있습니다.
@@ -473,20 +475,20 @@ view_adminRoles_permissions_isAuthorized = 권한이 있습니까?
##view_adminRoles_permissions_isRead = Read?
##view_adminRoles_permissions_isWrite = Write?
##view_adminRoles_permissions_permDesc_assignBundlesToGroup = can copy a viewable bundle to the bundle group
-##view_adminRoles_permissions_permDesc_createBundles = can create new bundle [version]s. can copy existing bundles between viewable groups
+##view_adminRoles_permissions_permDesc_createBundles = can create new bundle [version]s. can assign viewable bundles to viewable groups
##view_adminRoles_permissions_permDesc_createBundlesInGroup = can create new bundle [version]s for the bundle group. can copy a viewable bundle to the bundle group.
##view_adminRoles_permissions_permDesc_deleteBundles = can delete or unassign viewable bundle [version]s
##view_adminRoles_permissions_permDesc_deleteBundlesFromGroup = can delete bundle [version]s from the bundle group (implicitly deleting then from other assigned groups)
##view_adminRoles_permissions_permDesc_deployBundles = can deploy any viewable bundle version to any viewable, deployable, compatible, resource group
-##view_adminRoles_permissions_permDesc_manageBundleGroups = can create, update, or delete bundle groups
-##view_adminRoles_permissions_permDesc_manageBundles = can create, update, or delete provisioning bundles (viewing is implied for everyone)
+##view_adminRoles_permissions_permDesc_manageBundleGroups = can create and delete bundle groups. can assign bundles to bundle groups. grants View Bundles permissions
+##view_adminRoles_permissions_permDesc_manageBundles = can perform any bundle task. a convenience permission that grants Manage Bundle Groups, Create Bundles, Delete Bundles, Deploy Bundles and View Bundles permissions.
view_adminRoles_permissions_permDesc_manageInventory = 모든 자원의 모든 자원 권한을 갖습니다. 즉, 그룹의 생성, 삭제, 자동감지 또는 수동으로 검출된 자원을 가져올수 있습니다.
##view_adminRoles_permissions_permDesc_manageRepositories = can create, update, or delete repositories of any user (everyone can create their own repositories), can associate content sources to repositories.
##view_adminRoles_permissions_permDesc_manageSecurity = can create, update, or delete users and roles - implies all other permissions
view_adminRoles_permissions_permDesc_manageSettings = {0} 서버의 수정 및 모든 서버 관련 기능을 수행할 수 있습니다.
##view_adminRoles_permissions_permDesc_unassignBundlesFromGroup = can unassign (not delete) a bundle from the bundle group
-##view_adminRoles_permissions_permDesc_viewBundles = can view any bundle including global bundles (those not assigned to any bundle group)
-##view_adminRoles_permissions_permDesc_viewBundlesInGroup = can view any bundle in the group
+##view_adminRoles_permissions_permDesc_viewBundles = can view bundle details, deployments, etc for any bundle, including unassigned bundles (those not assigned to any bundle group)
+##view_adminRoles_permissions_permDesc_viewBundlesInGroup = (IMPLIED) can view bundle details, deployments, etc for any bundle in bundle groups associated with the relevant roles.
view_adminRoles_permissions_permDesc_viewUsers = 다른 사용자를 볼 수 있습니다. 그러나 그들에게 할당된 역할은 보이지 않습니다.
view_adminRoles_permissions_permReadDesc_configure = 자원 설정 및 자원 설정 수정 기록 보기
##view_adminRoles_permissions_permReadDesc_control = (IMPLIED) view available operations and operation execution history
diff --git a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_pt.properties b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_pt.properties
index 2369cf4..952b01f 100644
--- a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_pt.properties
+++ b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_pt.properties
@@ -514,12 +514,14 @@ view_adminRoles_ldapGroupsReadOnly = Informa\u00E7\u00F5es do grupo LDAP com per
view_adminRoles_noLdap = A integra\u00E7\u00E3o com o LDAP ainda n\u00E3o foi configurada. Para configurar o LDAP acesse <a {0}>{1}</a>.
view_adminRoles_permissions_autoselecting_configureRead_implied = Permiss\u00E3o CONFIGURE_WRITE desmarcada automaticamente devida a aus\u00EAncia da permiss\u00E3o CONFIGURE_READ...
view_adminRoles_permissions_autoselecting_configureWrite_implied = Permiss\u00E3o CONFIGURE_READ marcada automaticamente devida a marca\u00E7\u00E3o de CONFIGURE_WRITE...
-##view_adminRoles_permissions_autoselecting_manageBundle_implied = Autoselected unselected permissions, since MANAGE_BUNDLE implies all other bundle permissions...
+##view_adminRoles_permissions_autoselecting_manageBundleGroups_implied = Autoselected View Bundles, which is granted by Manage Bundle Groups...
+##view_adminRoles_permissions_autoselecting_manageBundle_implied = Autoselected unselected permissions, since Manage Bundle permission grants Manage Bundle Groups, Create Bundles, Delete Bundles, View Bundles and Deploy_Bundles permissions...
view_adminRoles_permissions_autoselecting_manageInventory_implied = Autoselected unselected Resource permissions, since MANAGE_INVENTORY implies all Resource permissions...
view_adminRoles_permissions_autoselecting_manageSecurity_implied = Autoselected unselected permissions, since MANAGE_SECURITY implies all other permissions...
-view_adminRoles_permissions_bundleGroupPermissions = Bundle Group Permissions
+##view_adminRoles_permissions_bundlePermissions = Bundle Permissions
view_adminRoles_permissions_globalPermissions = Permiss\u00F5es Globais
view_adminRoles_permissions_illegalDeselectionDueToCorrespondingWritePermSelection = {0} permiss\u00E3o de leitura n\u00E3 pode ser desmarcada, a menos que {0} permiss\u00E3o de escrita, que implica na permiss\u00E3o de leitura, seja desmarcada primeiro.
+##view_adminRoles_permissions_illegalDeselectionDueToManageBundleGroupsSelection = {0} permission cannot be deselected, unless Manage Bundle Groups, which implies {0} permission, is deselected first.
##view_adminRoles_permissions_illegalDeselectionDueToManageBundleSelection = {0} permission cannot be deselected, unless Manage Bundle, which implies all Bundle permissions, is deselected first.
view_adminRoles_permissions_illegalDeselectionDueToManageInventorySelection = {0} permiss\u00E3o n\u00E3o pode ser desmarcada, a menos que Gerenciar Invent\u00E1rio, que implica todas as permiss\u00F5es de Recurso, seja desmarcada primeiro.
view_adminRoles_permissions_illegalDeselectionDueToManageSecuritySelection = {0} permiss\u00E3o n\u00E3o pode ser desmarcada, a menos que a permiss\u00E3 Gerenciar SeguranÁa, que implica em todas outras permissıes, seja desmarcada primeiro.
@@ -527,20 +529,20 @@ view_adminRoles_permissions_isAuthorized = Autorizado?
view_adminRoles_permissions_isRead = Leitura?
view_adminRoles_permissions_isWrite = Escrita?
##view_adminRoles_permissions_permDesc_assignBundlesToGroup = can copy a viewable bundle to the bundle group
-##view_adminRoles_permissions_permDesc_createBundles = can create new bundle [version]s. can copy existing bundles between viewable groups
+##view_adminRoles_permissions_permDesc_createBundles = can create new bundle [version]s. can assign viewable bundles to viewable groups
##view_adminRoles_permissions_permDesc_createBundlesInGroup = can create new bundle [version]s for the bundle group. can copy a viewable bundle to the bundle group.
##view_adminRoles_permissions_permDesc_deleteBundles = can delete or unassign viewable bundle [version]s
##view_adminRoles_permissions_permDesc_deleteBundlesFromGroup = can delete bundle [version]s from the bundle group (implicitly deleting then from other assigned groups)
##view_adminRoles_permissions_permDesc_deployBundles = can deploy any viewable bundle version to any viewable, deployable, compatible, resource group
-##view_adminRoles_permissions_permDesc_manageBundleGroups = can create, update, or delete bundle groups
-view_adminRoles_permissions_permDesc_manageBundles = pode criar, atualizar, ou excluir o provisionamento de bundles (a visualiza\u00E7\u00E3 \u00E9 implicita para todos)
+##view_adminRoles_permissions_permDesc_manageBundleGroups = can create and delete bundle groups. can assign bundles to bundle groups. grants View Bundles permissions
+##view_adminRoles_permissions_permDesc_manageBundles = can perform any bundle task. a convenience permission that grants Manage Bundle Groups, Create Bundles, Delete Bundles, Deploy Bundles and View Bundles permissions.
view_adminRoles_permissions_permDesc_manageInventory = possui todas as permiss\u00F5es de Recurso, como descrito abaixo, pode criar, atualizar, excluir grupos e importar Recursos descobertos automaticamente ou manualmente.
view_adminRoles_permissions_permDesc_manageRepositories = pode criar, atualizar, ou excluir reposit\u00F3rios de qualquer usu\u00E1rio (todos podem criar seus pr\u00F3prios reposit\u00F3rios), pode associar fontes de conte\u00FAdos a reposit\u00F3rios.
view_adminRoles_permissions_permDesc_manageSecurity = pode criar, atualizar, ou excluir usu\u00E1rios e perfis (visualiza\u00E7\u00E3o \u00E9 padr\u00E3o para todos)
##view_adminRoles_permissions_permDesc_manageSettings = pode modificar a configura\u00E7\u00E3o do RHQ Server e utilizar qualquer funcionalidade relacionada ao Servidor
##view_adminRoles_permissions_permDesc_unassignBundlesFromGroup = can unassign (not delete) a bundle from the bundle group
-##view_adminRoles_permissions_permDesc_viewBundles = can view any bundle including global bundles (those not assigned to any bundle group)
-##view_adminRoles_permissions_permDesc_viewBundlesInGroup = can view any bundle in the group
+##view_adminRoles_permissions_permDesc_viewBundles = can view bundle details, deployments, etc for any bundle, including unassigned bundles (those not assigned to any bundle group)
+##view_adminRoles_permissions_permDesc_viewBundlesInGroup = (IMPLIED) can view bundle details, deployments, etc for any bundle in bundle groups associated with the relevant roles.
##view_adminRoles_permissions_permDesc_viewUsers = can view other users, with the exception of their assigned roles
view_adminRoles_permissions_permReadDesc_configure = view Resource configuration and Resource configuration revision history
view_adminRoles_permissions_permReadDesc_control = (IMPL\u00CDCITO) visualizar opera\u00E7\u00F5es dispon\u00EDveis e o hist\u00F3rico da execu\u00E7\u00E3o de opera\u00E7\u00F5es
diff --git a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_ru.properties b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_ru.properties
index 795892a..4fbef12 100644
--- a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_ru.properties
+++ b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_ru.properties
@@ -2596,12 +2596,14 @@ view_adminRoles_ldapGroupsReadOnly = данные LDAP групп доступн
##view_adminRoles_noLdap = The LDAP security integration is not configured. To configure LDAP, go to <a {0}>{1}</a>.
view_adminRoles_permissions_autoselecting_configureRead_implied = Автоматически отключено CONFIGURE_WRITE полномочие, поскольку отсутствует CONFIGURE_READ...
view_adminRoles_permissions_autoselecting_configureWrite_implied = Автоматически выбрано CONFIGURE_READ полномочие, поскольку CONFIGURE_WRITE подразумевает, что ...
-##view_adminRoles_permissions_autoselecting_manageBundle_implied = Autoselected unselected permissions, since MANAGE_BUNDLE implies all other bundle permissions...
+##view_adminRoles_permissions_autoselecting_manageBundleGroups_implied = Autoselected View Bundles, which is granted by Manage Bundle Groups...
+##view_adminRoles_permissions_autoselecting_manageBundle_implied = Autoselected unselected permissions, since Manage Bundle permission grants Manage Bundle Groups, Create Bundles, Delete Bundles, View Bundles and Deploy_Bundles permissions...
view_adminRoles_permissions_autoselecting_manageInventory_implied = Автоматически установлены не выбранные полномочия реусурсов, поскольку MANAGE_INVENTORY предполагает все полномочия ресурса...
view_adminRoles_permissions_autoselecting_manageSecurity_implied = Автоматически установлены невыбранные полномочия, поскольку MANAGE_SECURITY включает все другие полномочия...
-view_adminRoles_permissions_bundleGroupPermissions = Bundle Group Permissions
+##view_adminRoles_permissions_bundlePermissions = Bundle Permissions
view_adminRoles_permissions_globalPermissions = Глобальные полномчия
view_adminRoles_permissions_illegalDeselectionDueToCorrespondingWritePermSelection = {0} полномочия на чтение не могут быть отключены, пока предварительно {0} полномочия записи, которые включают полномочия на чтение, не будут отключены.
+##view_adminRoles_permissions_illegalDeselectionDueToManageBundleGroupsSelection = {0} permission cannot be deselected, unless Manage Bundle Groups, which implies {0} permission, is deselected first.
##view_adminRoles_permissions_illegalDeselectionDueToManageBundleSelection = {0} permission cannot be deselected, unless Manage Bundle, which implies all Bundle permissions, is deselected first.
view_adminRoles_permissions_illegalDeselectionDueToManageInventorySelection = {0} полномочия не могут быть отключены, пока предварительно Manage Inventory, которая включает все полномочия ресурса, не будет отключено.
view_adminRoles_permissions_illegalDeselectionDueToManageSecuritySelection = {0} полномочия не могут быть отключены, пока предватильно Manage Security полномочие, которое включает все другие полномочия, не будет отключено.
@@ -2609,20 +2611,20 @@ view_adminRoles_permissions_isAuthorized = Авторизованы?
view_adminRoles_permissions_isRead = Читать?
view_adminRoles_permissions_isWrite = Запись?
##view_adminRoles_permissions_permDesc_assignBundlesToGroup = can copy a viewable bundle to the bundle group
-##view_adminRoles_permissions_permDesc_createBundles = can create new bundle [version]s. can copy existing bundles between viewable groups
+##view_adminRoles_permissions_permDesc_createBundles = can create new bundle [version]s. can assign viewable bundles to viewable groups
##view_adminRoles_permissions_permDesc_createBundlesInGroup = can create new bundle [version]s for the bundle group. can copy a viewable bundle to the bundle group.
##view_adminRoles_permissions_permDesc_deleteBundles = can delete or unassign viewable bundle [version]s
##view_adminRoles_permissions_permDesc_deleteBundlesFromGroup = can delete bundle [version]s from the bundle group (implicitly deleting then from other assigned groups)
##view_adminRoles_permissions_permDesc_deployBundles = can deploy any viewable bundle version to any viewable, deployable, compatible, resource group
-##view_adminRoles_permissions_permDesc_manageBundleGroups = can create, update, or delete bundle groups
-view_adminRoles_permissions_permDesc_manageBundles = Можно создавать, обновлять и удалять узлы предоставления (просмотр предоставляется всем)
+##view_adminRoles_permissions_permDesc_manageBundleGroups = can create and delete bundle groups. can assign bundles to bundle groups. grants View Bundles permissions
+##view_adminRoles_permissions_permDesc_manageBundles = can perform any bundle task. a convenience permission that grants Manage Bundle Groups, Create Bundles, Delete Bundles, Deploy Bundles and View Bundles permissions.
##view_adminRoles_permissions_permDesc_manageInventory = has all Resource permissions, as described below, for all Resources; can create, update, and delete groups; and can import auto-discovered or manually discovered Resources
view_adminRoles_permissions_permDesc_manageRepositories = можно создавать, обновлять или удалять репозитории любого пользователя (каждый может создавать свои собственные репозитории), можно ассоциировать источники контента с резпозиториями.
view_adminRoles_permissions_permDesc_manageSecurity = можно создавать, обновлять или удалять пользователей и роли - включает все другие полномочия
##view_adminRoles_permissions_permDesc_manageSettings = can modify the {0} Server configuration and perform any Server-related functionality
##view_adminRoles_permissions_permDesc_unassignBundlesFromGroup = can unassign (not delete) a bundle from the bundle group
-##view_adminRoles_permissions_permDesc_viewBundles = can view any bundle including global bundles (those not assigned to any bundle group)
-##view_adminRoles_permissions_permDesc_viewBundlesInGroup = can view any bundle in the group
+##view_adminRoles_permissions_permDesc_viewBundles = can view bundle details, deployments, etc for any bundle, including unassigned bundles (those not assigned to any bundle group)
+##view_adminRoles_permissions_permDesc_viewBundlesInGroup = (IMPLIED) can view bundle details, deployments, etc for any bundle in bundle groups associated with the relevant roles.
##view_adminRoles_permissions_permDesc_viewUsers = can view other users, with the exception of their assigned roles
view_adminRoles_permissions_permReadDesc_configure = просмотр конфигурации ресурса и историю версий конфигурации ресурса
##view_adminRoles_permissions_permReadDesc_control = (IMPLIED) view available operations and operation execution history
diff --git a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_zh.properties b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_zh.properties
index 0d0f267..24ea681 100644
--- a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_zh.properties
+++ b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_zh.properties
@@ -503,12 +503,14 @@ view_adminRoles_ldapGroupsReadOnly = LDAP\u7ec4\u6570\u636e\u4e3a\u53ea\u8bfb
view_adminRoles_noLdap = \u6ca1\u6709\u96c6\u6210LDAP\u5b89\u5168, \u5230<a {0}>{1}</a>.
##view_adminRoles_permissions_autoselecting_configureRead_implied = Autodeselected CONFIGURE_WRITE permission, since lack of CONFIGURE_READ implies lack of it...
##view_adminRoles_permissions_autoselecting_configureWrite_implied = Autoselected CONFIGURE_READ permission, since CONFIGURE_WRITE implies it...
-##view_adminRoles_permissions_autoselecting_manageBundle_implied = Autoselected unselected permissions, since MANAGE_BUNDLE implies all other bundle permissions...
+##view_adminRoles_permissions_autoselecting_manageBundleGroups_implied = Autoselected View Bundles, which is granted by Manage Bundle Groups...
+##view_adminRoles_permissions_autoselecting_manageBundle_implied = Autoselected unselected permissions, since Manage Bundle permission grants Manage Bundle Groups, Create Bundles, Delete Bundles, View Bundles and Deploy_Bundles permissions...
##view_adminRoles_permissions_autoselecting_manageInventory_implied = Autoselected unselected Resource permissions, since MANAGE_INVENTORY implies all Resource permissions...
##view_adminRoles_permissions_autoselecting_manageSecurity_implied = Autoselected unselected permissions, since MANAGE_SECURITY implies all other permissions...
-view_adminRoles_permissions_bundleGroupPermissions = Bundle Group Permissions
+##view_adminRoles_permissions_bundlePermissions = Bundle Permissions
view_adminRoles_permissions_globalPermissions = \u5168\u5c40\u6388\u6743
##view_adminRoles_permissions_illegalDeselectionDueToCorrespondingWritePermSelection = {0} read permission cannot be deselected, unless the {0} write permission, which implies the read permission, is deselected first.
+##view_adminRoles_permissions_illegalDeselectionDueToManageBundleGroupsSelection = {0} permission cannot be deselected, unless Manage Bundle Groups, which implies {0} permission, is deselected first.
##view_adminRoles_permissions_illegalDeselectionDueToManageBundleSelection = {0} permission cannot be deselected, unless Manage Bundle, which implies all Bundle permissions, is deselected first.
##view_adminRoles_permissions_illegalDeselectionDueToManageInventorySelection = {0} permission cannot be deselected, unless Manage Inventory, which implies all Resource permissions, is deselected first.
##view_adminRoles_permissions_illegalDeselectionDueToManageSecuritySelection = {0} permission cannot be deselected, unless the Manage Security permission, which implies all other permissions, is deselected first.
@@ -516,20 +518,20 @@ view_adminRoles_permissions_isAuthorized = \u6388\u6743?
view_adminRoles_permissions_isRead = \u8bfb?
view_adminRoles_permissions_isWrite = \u5199?
##view_adminRoles_permissions_permDesc_assignBundlesToGroup = can copy a viewable bundle to the bundle group
-##view_adminRoles_permissions_permDesc_createBundles = can create new bundle [version]s. can copy existing bundles between viewable groups
+##view_adminRoles_permissions_permDesc_createBundles = can create new bundle [version]s. can assign viewable bundles to viewable groups
##view_adminRoles_permissions_permDesc_createBundlesInGroup = can create new bundle [version]s for the bundle group. can copy a viewable bundle to the bundle group.
##view_adminRoles_permissions_permDesc_deleteBundles = can delete or unassign viewable bundle [version]s
##view_adminRoles_permissions_permDesc_deleteBundlesFromGroup = can delete bundle [version]s from the bundle group (implicitly deleting then from other assigned groups)
##view_adminRoles_permissions_permDesc_deployBundles = can deploy any viewable bundle version to any viewable, deployable, compatible, resource group
-##view_adminRoles_permissions_permDesc_manageBundleGroups = can create, update, or delete bundle groups
-view_adminRoles_permissions_permDesc_manageBundles = \u80fd\u521b\u5efa,\u66f4\u65b0\u6216\u8005\u5220\u9664\u63d0\u4f9b\u7684bundles(\u4efb\u4f55\u4eba\u90fd\u80fd\u67e5\u770b)
+##view_adminRoles_permissions_permDesc_manageBundleGroups = can create and delete bundle groups. can assign bundles to bundle groups. grants View Bundles permissions
+##view_adminRoles_permissions_permDesc_manageBundles = can perform any bundle task. a convenience permission that grants Manage Bundle Groups, Create Bundles, Delete Bundles, Deploy Bundles and View Bundles permissions.
view_adminRoles_permissions_permDesc_manageInventory = \u62e5\u6709\u6240\u6709\u8d44\u6e90\u6743\u9650, \u5982\u4e0b\u6240\u8ff0, \u5bf9\u6240\u6709\u8d44\u6e90; \u5177\u6709\u521b\u5efa, \u66f4\u65b0, \u5220\u9664\u7ec4; \u80fd\u5bfc\u5165\u81ea\u52a8\u53d1\u73b0\u6216\u624b\u52a8\u53d1\u73b0\u7684\u8d44\u6e90
view_adminRoles_permissions_permDesc_manageRepositories = can create, update, or delete repositories of any user (everyone can create their own repositories), can associate content sources to repositories.
view_adminRoles_permissions_permDesc_manageSecurity = \u80fd\u521b\u5efa,\u66f4\u65b0,\u6216\u5220\u9664\u7528\u6237\u548c\u89d2\u8272 (\u4efb\u4f55\u4eba\u90fd\u6709\u67e5\u770b\u6743\u9650)
##view_adminRoles_permissions_permDesc_manageSettings = \u80fd\u4fee\u6539RHQ\u670d\u52a1\u5668\u914d\u7f6e\u800c\u4e14\u80fd\u64cd\u4f5c\u4efb\u4f55\u76f8\u5173\u7684\u670d\u52a1\u5668\u529f\u80fd
##view_adminRoles_permissions_permDesc_unassignBundlesFromGroup = can unassign (not delete) a bundle from the bundle group
-##view_adminRoles_permissions_permDesc_viewBundles = can view any bundle including global bundles (those not assigned to any bundle group)
-##view_adminRoles_permissions_permDesc_viewBundlesInGroup = can view any bundle in the group
+##view_adminRoles_permissions_permDesc_viewBundles = can view bundle details, deployments, etc for any bundle, including unassigned bundles (those not assigned to any bundle group)
+##view_adminRoles_permissions_permDesc_viewBundlesInGroup = (IMPLIED) can view bundle details, deployments, etc for any bundle in bundle groups associated with the relevant roles.
##view_adminRoles_permissions_permDesc_viewUsers = can view other users, with the exception of their assigned roles
view_adminRoles_permissions_permReadDesc_configure = \u67e5\u770b\u8d44\u6e90\u914d\u7f6e\u548c\u8d44\u6e90\u914d\u7f6e\u4fee\u8ba2\u5386\u53f2
view_adminRoles_permissions_permReadDesc_control = (IMPLIED) \u67e5\u770b\u53ef\u7528\u64cd\u4f5c\u548c\u64cd\u4f5c\u6267\u884c\u5386\u53f2
diff --git a/modules/enterprise/gui/coregui/src/main/webapp/images/subsystems/bundle/BundleGroup_16.png b/modules/enterprise/gui/coregui/src/main/webapp/images/subsystems/bundle/BundleGroup_16.png
new file mode 100644
index 0000000..4a73421
Binary files /dev/null and b/modules/enterprise/gui/coregui/src/main/webapp/images/subsystems/bundle/BundleGroup_16.png differ
diff --git a/modules/enterprise/gui/coregui/src/main/webapp/images/subsystems/bundle/BundleGroup_24.png b/modules/enterprise/gui/coregui/src/main/webapp/images/subsystems/bundle/BundleGroup_24.png
new file mode 100644
index 0000000..59faacf
Binary files /dev/null and b/modules/enterprise/gui/coregui/src/main/webapp/images/subsystems/bundle/BundleGroup_24.png differ
diff --git a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/bundle/BundleManagerBeanTest.java b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/bundle/BundleManagerBeanTest.java
index 55fce08..2085a4d 100644
--- a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/bundle/BundleManagerBeanTest.java
+++ b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/bundle/BundleManagerBeanTest.java
@@ -1363,6 +1363,7 @@ public class BundleManagerBeanTest extends AbstractEJB3Test {
// allow bundle group delete
bundleManager.deleteBundleGroups(subject, new int[] { bundleGroup.getId() });
+ removeRolePermissions(role, Permission.MANAGE_BUNDLE_GROUPS);
// deny unassigned bundle create (no global create or view)
try {
@@ -1409,7 +1410,10 @@ public class BundleManagerBeanTest extends AbstractEJB3Test {
assertEquals("Should be able to see unassigned bundle", 1, bundles.size());
// deny global perm bundle assign
+ addRolePermissions(role, Permission.MANAGE_BUNDLE_GROUPS);
bundleGroup = bundleManager.createBundleGroup(subject, TEST_BUNDLE_GROUP_NAME, "test");
+ removeRolePermissions(role, Permission.MANAGE_BUNDLE_GROUPS);
+
try {
bundleManager.assignBundlesToBundleGroup(subject, bundleGroup.getId(), new int[] { bundle.getId() });
fail("Should have thrown PermissionException");
@@ -1417,12 +1421,47 @@ public class BundleManagerBeanTest extends AbstractEJB3Test {
// expected
}
- // allow global perm bundle assign
+ // allow bundle assign via global manage_bundle_groups
+ addRolePermissions(role, Permission.MANAGE_BUNDLE_GROUPS);
+ bundleManager.assignBundlesToBundleGroup(subject, bundleGroup.getId(), new int[] { bundle.getId() });
+
+ // allow bundle unassign via global manage_bundle_groups
+ bundleManager.unassignBundlesFromBundleGroup(subject, bundleGroup.getId(), new int[] { bundle.getId() });
+
+ // allow bundle assign via global create
+ removeRolePermissions(role, Permission.MANAGE_BUNDLE_GROUPS);
addRolePermissions(role, Permission.CREATE_BUNDLES);
bundleManager.assignBundlesToBundleGroup(subject, bundleGroup.getId(), new int[] { bundle.getId() });
+ // deny bundle unassign via global create
+ try {
+ bundleManager.unassignBundlesFromBundleGroup(subject, bundleGroup.getId(), new int[] { bundle.getId() });
+ fail("Should have thrown PermissionException");
+ } catch (PermissionException e) {
+ // expected
+ }
+
+ // allow bundle unassign via global delete
+ addRolePermissions(role, Permission.DELETE_BUNDLES);
+ bundleManager.unassignBundlesFromBundleGroup(subject, bundleGroup.getId(), new int[] { bundle.getId() });
+ removeRolePermissions(role, Permission.DELETE_BUNDLES);
+
+ // deny bundle assign with global create but no view
+ removeRolePermissions(role, Permission.VIEW_BUNDLES);
+ try {
+ bundleManager.assignBundlesToBundleGroup(subject, bundleGroup.getId(), new int[] { bundle.getId() });
+ fail("Should have thrown PermissionException");
+ } catch (PermissionException e) {
+ // expected
+ }
+
+ // go back and again assign via global create and view
+ addRolePermissions(role, Permission.VIEW_BUNDLES);
+ bundleManager.assignBundlesToBundleGroup(subject, bundleGroup.getId(), new int[] { bundle.getId() });
+
// deny assigned, unassociated-bundle-group bundle view
- removeRolePermissions(role, Permission.CREATE_BUNDLES, Permission.VIEW_BUNDLES);
+ removeRolePermissions(role, Permission.MANAGE_BUNDLE_GROUPS);
+ removeRolePermissions(role, Permission.VIEW_BUNDLES);
bundles = bundleManager.findBundlesByCriteria(subject, bCriteria);
assertNotNull(bundles);
assert bundles.isEmpty() : "Should not be able to see assigned bundle";
@@ -1498,6 +1537,7 @@ public class BundleManagerBeanTest extends AbstractEJB3Test {
// create bundle group
addRolePermissions(role, Permission.MANAGE_BUNDLE_GROUPS);
BundleGroup bundleGroup1 = bundleManager.createBundleGroup(subject, TEST_BUNDLE_GROUP_NAME + "_1", "bg-1");
+ removeRolePermissions(role, Permission.MANAGE_BUNDLE_GROUPS);
// add bg1 to the role, but no perms
addRoleBundleGroup(role, bundleGroup1);
@@ -1535,7 +1575,9 @@ public class BundleManagerBeanTest extends AbstractEJB3Test {
addRolePermissions(role2, Permission.CREATE_BUNDLES_IN_GROUP);
// create second bundle group
+ addRolePermissions(role, Permission.MANAGE_BUNDLE_GROUPS);
BundleGroup bundleGroup2 = bundleManager.createBundleGroup(subject, TEST_BUNDLE_GROUP_NAME + "_2", "bg-2");
+ removeRolePermissions(role, Permission.MANAGE_BUNDLE_GROUPS);
// deny bundle create in bg2 (not associated with role)
try {
@@ -1633,6 +1675,7 @@ public class BundleManagerBeanTest extends AbstractEJB3Test {
// create bundle group
addRolePermissions(role, Permission.MANAGE_BUNDLE_GROUPS);
BundleGroup bundleGroup1 = bundleManager.createBundleGroup(subject, TEST_BUNDLE_GROUP_NAME + "_1", "bg-1");
+ removeRolePermissions(role, Permission.MANAGE_BUNDLE_GROUPS);
// add bg1 to the role with group create
addRoleBundleGroup(role, bundleGroup1);
@@ -1675,6 +1718,7 @@ public class BundleManagerBeanTest extends AbstractEJB3Test {
// create bundle group
addRolePermissions(role, Permission.MANAGE_BUNDLE_GROUPS);
BundleGroup bundleGroup = bundleManager.createBundleGroup(subject, TEST_BUNDLE_GROUP_NAME, "bg");
+ removeRolePermissions(role, Permission.MANAGE_BUNDLE_GROUPS);
// add bg to the role with group create
addRoleBundleGroup(role, bundleGroup);
@@ -1765,6 +1809,7 @@ public class BundleManagerBeanTest extends AbstractEJB3Test {
// create bundle group
addRolePermissions(role, Permission.MANAGE_BUNDLE_GROUPS);
BundleGroup bundleGroup = bundleManager.createBundleGroup(subject, TEST_BUNDLE_GROUP_NAME, "bg");
+ removeRolePermissions(role, Permission.MANAGE_BUNDLE_GROUPS);
// add bg to the role with group create
addRoleBundleGroup(role, bundleGroup);
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/authz/RoleManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/authz/RoleManagerBean.java
index 96d44de..c2f6048 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/authz/RoleManagerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/authz/RoleManagerBean.java
@@ -758,6 +758,21 @@ public class RoleManagerBean implements RoleManagerLocal, RoleManagerRemote {
if (!role.getPermissions().contains(Permission.CONFIGURE_READ)) {
role.getPermissions().remove(Permission.CONFIGURE_WRITE);
}
+
+ /*
+ * and MANAGE_BUNDLE implies all Bundle perms
+ */
+ if (role.getPermissions().contains(Permission.MANAGE_BUNDLE)) {
+ role.getPermissions().addAll(Permission.BUNDLE_ALL);
+ }
+
+ /*
+ * and MANAGE_BUNDLE_GROUPS implies global bundle view
+ */
+ if (role.getPermissions().contains(Permission.MANAGE_BUNDLE_GROUPS)) {
+ role.getPermissions().add(Permission.VIEW_BUNDLES);
+ }
+
}
@Override
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/bundle/BundleManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/bundle/BundleManagerBean.java
index 621a54c..986b080 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/bundle/BundleManagerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/bundle/BundleManagerBean.java
@@ -2058,11 +2058,12 @@ public class BundleManagerBean implements BundleManagerLocal, BundleManagerRemot
}
/**
+ * <pre>
* Required Permissions: Either:
* - Global.CREATE_BUNDLES and Global.VIEW_BUNDLES
* - Global.CREATE_BUNDLES and BundleGroup.VIEW_BUNDLES_IN_GROUP for bundle group BG
* - BundleGroup.CREATE_BUNDLES_IN_GROUP for bundle group BG
- *
+ * </pre>
* @param subject
* @param bundleGroupId null or 0 for unassigned initial bundle version creation
* @throws PermissionException
@@ -2101,11 +2102,12 @@ public class BundleManagerBean implements BundleManagerLocal, BundleManagerRemot
}
/**
+ * <pre>
* Required Permissions: Either:
* - Global.CREATE_BUNDLES and Global.VIEW_BUNDLES
* - Global.CREATE_BUNDLES and BundleGroup.VIEW_BUNDLES_IN_GROUP for bundle group BG and the relevant bundle is assigned to BG
* - BundleGroup.CREATE_BUNDLES_IN_GROUP for bundle group BG and the relevant bundle is assigned to BG
- *
+ * </pre>
* @param subject
* @param bundleId required, bundleId of bundle in which bundle version is being created/updated
* @throws PermissionException
@@ -2142,10 +2144,13 @@ public class BundleManagerBean implements BundleManagerLocal, BundleManagerRemot
}
/**
- * Requires VIEW permission for the relevant bundle and either:
+ * <pre>
+ * Requires VIEW permission for the relevant bundle and one of:
+ * - Global.MANAGE_BUNDLE_GROUPS
* - Global.CREATE_BUNDLE
- * - BundleGroup.CREATE_BUNDLES_IN_GROUP or BundleGroup.ASSIGN_BUNDLES_TO_GROUP for the relevant bundle group
- *
+ * - BundleGroup.ASSIGN_BUNDLES_TO_GROUP for the relevant bundle group
+ * - BundleGroup.CREATE_BUNDLES_IN_GROUP for the relevant bundle group
+ * </pre>
* @param subject
* @param bundleGroupId an existing bundle group
* @param bundleIds existing bundles
@@ -2155,24 +2160,25 @@ public class BundleManagerBean implements BundleManagerLocal, BundleManagerRemot
throws PermissionException {
Set<Permission> globalPerms = authorizationManager.getExplicitGlobalPermissions(subject);
+ boolean hasGlobalManageBundleGroups = globalPerms.contains(Permission.MANAGE_BUNDLE_GROUPS);
boolean hasGlobalCreateBundles = globalPerms.contains(Permission.CREATE_BUNDLES);
boolean hasGlobalViewBundles = globalPerms.contains(Permission.VIEW_BUNDLES);
- if (hasGlobalCreateBundles && hasGlobalViewBundles) {
+ if ((hasGlobalManageBundleGroups || hasGlobalCreateBundles) && hasGlobalViewBundles) {
return;
}
- boolean hasBundleGroupCreate = hasGlobalCreateBundles
+ boolean canAssign = hasGlobalManageBundleGroups
+ || hasGlobalCreateBundles
|| authorizationManager
- .hasBundleGroupPermission(subject, Permission.CREATE_BUNDLES_IN_GROUP, bundleGroupId);
- boolean hasBundleGroupAssign = hasBundleGroupCreate
+ .hasBundleGroupPermission(subject, Permission.CREATE_BUNDLES_IN_GROUP, bundleGroupId)
|| authorizationManager
.hasBundleGroupPermission(subject, Permission.ASSIGN_BUNDLES_TO_GROUP, bundleGroupId);
- if (!hasBundleGroupAssign) {
+ if (!canAssign) {
String msg = "Subject ["
+ subject.getName()
- + "] requires one of Global.CREATE_BUNDLES, BundleGroup.CREATE_BUNDLES_IN_GROUP, or BundleGroup.ASSIGN_BUNDLES_TO_GROUP to assign a bundle to undle group ["
+ + "] requires one of Global.MANAGE_BUNDLE_GROUPS, Global.CREATE_BUNDLES, BundleGroup.CREATE_BUNDLES_IN_GROUP, or BundleGroup.ASSIGN_BUNDLES_TO_GROUP to assign a bundle to bundle group ["
+ bundleGroupId + "].";
throw new PermissionException(msg);
}
@@ -2194,9 +2200,13 @@ public class BundleManagerBean implements BundleManagerLocal, BundleManagerRemot
}
/**
- * Requires VIEW permission for the relevant bundles and either:
+ * <pre>
+ * Requires VIEW permission for the relevant bundles and one of:
+ * - Global.MANAGE_BUNDLE_GROUPS
* - Global.DELETE_BUNDLE
- * - BundleGroup.DELETE_BUNDLES_FROM_GROUP or BundleGroup.UNASSIGN_BUNDLES_FROM_GROUP for the relevant bundle group
+ * - BundleGroup.UNASSIGN_BUNDLES_FROM_GROUP for the relevant bundle group
+ * - BundleGroup.DELETE_BUNDLES_FROM_GROUP for the relevant bundle group
+ * </pre>
*
* @param subject
* @param bundleGroupId an existing bundle group
@@ -2207,24 +2217,25 @@ public class BundleManagerBean implements BundleManagerLocal, BundleManagerRemot
throws PermissionException {
Set<Permission> globalPerms = authorizationManager.getExplicitGlobalPermissions(subject);
+ boolean hasGlobalManageBundleGroups = globalPerms.contains(Permission.MANAGE_BUNDLE_GROUPS);
boolean hasGlobalDeleteBundles = globalPerms.contains(Permission.DELETE_BUNDLES);
boolean hasGlobalViewBundles = globalPerms.contains(Permission.VIEW_BUNDLES);
- if (hasGlobalDeleteBundles && hasGlobalViewBundles) {
+ if ((hasGlobalManageBundleGroups || hasGlobalDeleteBundles) && hasGlobalViewBundles) {
return;
}
- boolean hasBundleGroupDelete = hasGlobalDeleteBundles
+ boolean canUnassign = hasGlobalManageBundleGroups
+ || hasGlobalDeleteBundles
|| authorizationManager.hasBundleGroupPermission(subject, Permission.DELETE_BUNDLES_FROM_GROUP,
- bundleGroupId);
- boolean hasBundleGroupUnassign = hasBundleGroupDelete
+ bundleGroupId)
|| authorizationManager.hasBundleGroupPermission(subject, Permission.UNASSIGN_BUNDLES_FROM_GROUP,
bundleGroupId);
- if (!hasBundleGroupUnassign) {
+ if (!canUnassign) {
String msg = "Subject ["
+ subject.getName()
- + "] requires one of Global.DELETE_BUNDLES, BundleGroup.DELETE_BUNDLES_FROM_GROUP, or BundleGroup.UNASSIGN_BUNDLES_FROM_GROUP to unassign a bundle to undle group ["
+ + "] requires one of Global.MANAGE_BUNDLE_GROUPS, Global.DELETE_BUNDLES, BundleGroup.DELETE_BUNDLES_FROM_GROUP, or BundleGroup.UNASSIGN_BUNDLES_FROM_GROUP to unassign a bundle from bundle group ["
+ bundleGroupId + "].";
throw new PermissionException(msg);
}
@@ -2237,7 +2248,7 @@ public class BundleManagerBean implements BundleManagerLocal, BundleManagerRemot
if (!authorizationManager.canViewBundle(subject, bundleId)) {
String msg = "Subject [" + subject.getName()
+ "] requires either Global.VIEW_BUNDLES or BundleGroup.VIEW_BUNDLES_IN_GROUP to unassign bundle ["
- + bundleId + "] to bundle group [" + bundleGroupId + "]";
+ + bundleId + "] from bundle group [" + bundleGroupId + "]";
throw new PermissionException(msg);
}
}
@@ -2246,9 +2257,11 @@ public class BundleManagerBean implements BundleManagerLocal, BundleManagerRemot
}
/**
+ * <pre>
* Required Permissions: Either:
* - Global.DEPLOY_BUNDLES and a view of the relevant bundle and a view of the relevant resource group (may involve multiple roles)
* - Resource.DEPLOY_BUNDLES_TO_GROUP and a view of the relevant bundle and a view of the relevant resource group (may involve multiple roles)
+ * </pre>
*/
private void checkDeployBundleAuthz(Subject subject, int bundleId, int resourceGroupId) throws PermissionException {
@@ -2283,11 +2296,12 @@ public class BundleManagerBean implements BundleManagerLocal, BundleManagerRemot
}
/**
+ * <pre>
* Required Permissions: Either:
* - Global.DELETE_BUNDLES and Global.VIEW_BUNDLES
* - Global.DELETE_BUNDLES and BundleGroup.VIEW_BUNDLES_IN_GROUP for bundle group BG and the relevant bundle is assigned to BG
* - BundleGroup.DELETE_BUNDLES_FROM_GROUP for bundle group BG and the relevant bundle is assigned to BG
- *
+ * </pre>
* @param subject
* @param bundleId required, bundleId of bundle, or the bundle version, being deleted
* @throws PermissionException
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/bundle/BundleManagerRemote.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/bundle/BundleManagerRemote.java
index c1b9eef..ee023e8 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/bundle/BundleManagerRemote.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/bundle/BundleManagerRemote.java
@@ -78,7 +78,6 @@ public interface BundleManagerRemote {
* - Global.CREATE_BUNDLES and BundleGroup.VIEW_BUNDLES_IN_GROUP for bundle group BG and the relevant bundle is assigned to BG
* - BundleGroup.CREATE_BUNDLES_IN_GROUP for bundle group BG and the relevant bundle is assigned to BG
* </pre>
- *
* @param subject user that must have proper permissions
* @param bundleVersionId id of the BundleVersion incorporating this BundleFile
* @param name name of the BundleFile (and the resulting Package)
@@ -101,7 +100,6 @@ public interface BundleManagerRemote {
* - Global.CREATE_BUNDLES and BundleGroup.VIEW_BUNDLES_IN_GROUP for bundle group BG and the relevant bundle is assigned to BG
* - BundleGroup.CREATE_BUNDLES_IN_GROUP for bundle group BG and the relevant bundle is assigned to BG
* </pre>
- *
* @see {@link #addBundleFile(Subject, int, String, String, Architecture, InputStream)}
*/
BundleFile addBundleFileViaByteArray(Subject subject, int bundleVersionId, String name, String version,
@@ -115,7 +113,6 @@ public interface BundleManagerRemote {
* - Global.CREATE_BUNDLES and BundleGroup.VIEW_BUNDLES_IN_GROUP for bundle group BG and the relevant bundle is assigned to BG
* - BundleGroup.CREATE_BUNDLES_IN_GROUP for bundle group BG and the relevant bundle is assigned to BG
* </pre>
- *
* @see #addBundleFile(Subject, int, String, String, Architecture, InputStream)
*/
BundleFile addBundleFileViaURL(Subject subject, int bundleVersionId, String name, String version,
@@ -130,7 +127,6 @@ public interface BundleManagerRemote {
* - Global.CREATE_BUNDLES and BundleGroup.VIEW_BUNDLES_IN_GROUP for bundle group BG and the relevant bundle is assigned to BG
* - BundleGroup.CREATE_BUNDLES_IN_GROUP for bundle group BG and the relevant bundle is assigned to BG
* </pre>
- *
* @see #addBundleFileViaURL(Subject, int, String, String, Architecture, String)
*/
BundleFile addBundleFileViaURL(Subject subject, int bundleVersionId, String name, String version,
@@ -144,7 +140,6 @@ public interface BundleManagerRemote {
* - Global.CREATE_BUNDLES and BundleGroup.VIEW_BUNDLES_IN_GROUP for bundle group BG and the relevant bundle is assigned to BG
* - BundleGroup.CREATE_BUNDLES_IN_GROUP for bundle group BG and the relevant bundle is assigned to BG
* </pre>
- *
* @see {@link #addBundleFile(Subject, int, String, String, Architecture, InputStream)}
*/
BundleFile addBundleFileViaPackageVersion(Subject subject, int bundleVersionId, String name, int packageVersionId)
@@ -153,11 +148,12 @@ public interface BundleManagerRemote {
/**
* Assign the specified bundles to the specified bundle group.
* <pre>
- * Requires VIEW permission for the relevant bundle and either:
+ * Requires VIEW permission for the relevant bundle and one of:
+ * - Global.MANAGE_BUNDLE_GROUPS
* - Global.CREATE_BUNDLE
- * - BundleGroup.CREATE_BUNDLES_IN_GROUP or BundleGroup.ASSIGN_BUNDLES_TO_GROUP for the relevant bundle group
+ * - BundleGroup.ASSIGN_BUNDLES_TO_GROUP for the relevant bundle group
+ * - BundleGroup.CREATE_BUNDLES_IN_GROUP for the relevant bundle group
* </pre>
- *
* @param subject
* @param bundleGroupId
* @param bundleIds
@@ -174,7 +170,6 @@ public interface BundleManagerRemote {
* - Global.DEPLOY_BUNDLES and a view of the relevant bundle and a view of the relevant resource group (may involve multiple roles)
* - Resource.DEPLOY_BUNDLES_TO_GROUP and a view of the relevant bundle and a view of the relevant resource group (may involve multiple roles)
* </pre>
- *
* @param subject user that must have proper permissions
* @param bundleVersionId the BundleVersion being deployed by this deployment
* @param bundleDestinationId the BundleDestination for the deployment
@@ -194,7 +189,6 @@ public interface BundleManagerRemote {
* - Global.DEPLOY_BUNDLES and a view of the relevant bundle and a view of the relevant resource group (may involve multiple roles)
* - Resource.DEPLOY_BUNDLES_TO_GROUP and a view of the relevant bundle and a view of the relevant resource group (may involve multiple roles)
* </pre>
- *
* @param subject user must have MANAGE_INVENTORY permission
* @param bundleId the Bundle to be deployed to this Destination
* @param name a name for this destination. not null or empty
@@ -213,10 +207,10 @@ public interface BundleManagerRemote {
/**
* Create a new bundle group.
- * <p/>
+ * <pre>
* Require Permissions:
* - Global.MANAGE_BUNDLE_GROUPS
- *
+ * </pre>
* @param subject user that must have proper permissions
* @param name the unique bundle group name
* @param description an optional description
@@ -239,7 +233,6 @@ public interface BundleManagerRemote {
* - Global.CREATE_BUNDLES and BundleGroup.VIEW_BUNDLES_IN_GROUP for bundle group BG and the relevant bundle is assigned to BG
* - BundleGroup.CREATE_BUNDLES_IN_GROUP for bundle group BG and the relevant bundle is assigned to BG
* </pre>
- *
* @param subject user that must have proper permissions
* @param recipe the recipe that defines the bundle version to be created
* @return the persisted BundleVersion with alot of the internal relationships filled in to help the caller
@@ -259,7 +252,6 @@ public interface BundleManagerRemote {
* - Global.CREATE_BUNDLES and BundleGroup.VIEW_BUNDLES_IN_GROUP for bundle group BG
* - BundleGroup.CREATE_BUNDLES_IN_GROUP for bundle group BG
* </pre>
- *
* @param subject user that must have proper permissions
* @param bundleGroupId identifies the bundle group that the new bundle will be associated with; 0 if no group
* @param recipe the recipe that defines the bundle version to be created
@@ -284,7 +276,6 @@ public interface BundleManagerRemote {
* - Global.CREATE_BUNDLES and BundleGroup.VIEW_BUNDLES_IN_GROUP for bundle group BG and the relevant bundle is assigned to BG
* - BundleGroup.CREATE_BUNDLES_IN_GROUP for bundle group BG and the relevant bundle is assigned to BG
* </pre>
- *
* @param subject user that must have proper permissions
* @param distributionFile a local Bundle Distribution file. It must be read accessible by the RHQ server process.
* @return the persisted BundleVersion with alot of the internal relationships filled in to help the caller
@@ -304,7 +295,6 @@ public interface BundleManagerRemote {
* - Global.CREATE_BUNDLES and BundleGroup.VIEW_BUNDLES_IN_GROUP for bundle group BG
* - BundleGroup.CREATE_BUNDLES_IN_GROUP for bundle group BG
* </pre>
- *
* @param subject user that must have proper permissions
* @param bundleGroupId identifies the bundle group that the new bundle will be associated with; 0 if no group
* @param distributionFile a local Bundle Distribution file. It must be read accessible by the RHQ server process.
@@ -330,7 +320,6 @@ public interface BundleManagerRemote {
* - Global.CREATE_BUNDLES and BundleGroup.VIEW_BUNDLES_IN_GROUP for bundle group BG and the relevant bundle is assigned to BG
* - BundleGroup.CREATE_BUNDLES_IN_GROUP for bundle group BG and the relevant bundle is assigned to BG
* </pre>
- *
* @param subject user that must have proper permissions
* @param fileBytes the file bits that make up the entire bundle distribution file
* @return the persisted BundleVersion with a lot of the internal relationships filled in to help the caller
@@ -349,8 +338,7 @@ public interface BundleManagerRemote {
* - Global.CREATE_BUNDLES and Global.VIEW_BUNDLES
* - Global.CREATE_BUNDLES and BundleGroup.VIEW_BUNDLES_IN_GROUP for bundle group BG
* - BundleGroup.CREATE_BUNDLES_IN_GROUP for bundle group BG
- * </pre>
- *
+ * </pre>
* @param subject user that must have proper permissions
* @param bundleGroupId identifies the bundle group that the new bundle will be associated with; 0 if no group
* @param fileBytes the file bits that make up the entire bundle distribution file
@@ -378,7 +366,6 @@ public interface BundleManagerRemote {
* - Global.CREATE_BUNDLES and BundleGroup.VIEW_BUNDLES_IN_GROUP for bundle group BG and the relevant bundle is assigned to BG
* - BundleGroup.CREATE_BUNDLES_IN_GROUP for bundle group BG and the relevant bundle is assigned to BG
* </pre>
- *
* @param subject user that must have proper permissions
* @param distributionFileUrl a URL String to the Bundle Distribution file. It must be live, resolvable and read accessible
* by the RHQ server process.
@@ -400,7 +387,6 @@ public interface BundleManagerRemote {
* - Global.CREATE_BUNDLES and BundleGroup.VIEW_BUNDLES_IN_GROUP for bundle group BG
* - BundleGroup.CREATE_BUNDLES_IN_GROUP for bundle group BG
* </pre>
- *
* @param subject user that must have proper permissions
* @param bundleGroupId identifies the bundle group that the new bundle will be associated with; 0 if no group
* @param distributionFileUrl a URL String to the Bundle Distribution file. It must be live, resolvable and read accessible
@@ -424,7 +410,6 @@ public interface BundleManagerRemote {
* - Global.CREATE_BUNDLES and BundleGroup.VIEW_BUNDLES_IN_GROUP for bundle group BG and the relevant bundle is assigned to BG
* - BundleGroup.CREATE_BUNDLES_IN_GROUP for bundle group BG and the relevant bundle is assigned to BG
* </pre>
- *
* @see #createBundleVersionViaURL(org.rhq.core.domain.auth.Subject, String)
*/
BundleVersion createBundleVersionViaURL(Subject subject, String distributionFileUrl, String username,
@@ -442,7 +427,6 @@ public interface BundleManagerRemote {
* - Global.CREATE_BUNDLES and BundleGroup.VIEW_BUNDLES_IN_GROUP for bundle group BG
* - BundleGroup.CREATE_BUNDLES_IN_GROUP for bundle group BG
* </pre>
- *
* @see #createBundleVersionViaURL(org.rhq.core.domain.auth.Subject, String)
*/
BundleVersion createInitialBundleVersionViaURL(Subject subject, int bundleGroupId, String distributionFileUrl,
@@ -459,7 +443,6 @@ public interface BundleManagerRemote {
* - Global.DELETE_BUNDLES and BundleGroup.VIEW_BUNDLES_IN_GROUP for bundle group BG and the relevant bundle is assigned to BG
* - BundleGroup.DELETE_BUNDLES_FROM_GROUP for bundle group BG and the relevant bundle is assigned to BG
* </pre>
- *
* @param subject user that must have proper permissions
* @param bundleIds IDs of all bundles to be deleted
* @throws Exception if any part of the removal fails.
@@ -477,7 +460,6 @@ public interface BundleManagerRemote {
* - Global.DELETE_BUNDLES and BundleGroup.VIEW_BUNDLES_IN_GROUP for bundle group BG and the relevant bundle is assigned to BG
* - BundleGroup.DELETE_BUNDLES_FROM_GROUP for bundle group BG and the relevant bundle is assigned to BG
* </pre>
- *
* @param subject user that must have proper permissions
* @param bundleId the id of the bundle to remove
* @throws Exception if any part of the removal fails.
@@ -486,10 +468,10 @@ public interface BundleManagerRemote {
/**
* Delete a bundle group. Any currently assigned bundles will be removed but are not deleted.
- * <p/>
+ * <pre>
* Required Permissions:
* - Global.MANAGE_BUNDLE_GROUPS
- *
+ * </pre>
* @param subject user that must have proper permissions
* @param ids the bundle group id
* @throws Exception
@@ -507,7 +489,6 @@ public interface BundleManagerRemote {
* - Global.DELETE_BUNDLES and BundleGroup.VIEW_BUNDLES_IN_GROUP for bundle group BG and the relevant bundle is assigned to BG
* - BundleGroup.DELETE_BUNDLES_FROM_GROUP for bundle group BG and the relevant bundle is assigned to BG
* </pre>
- *
* @param subject user that must have proper permissions
* @param bundleVersionId the id of the bundle version to remove
* @param deleteBundleIfEmpty if <code>true</code> and if this method deletes the last bundle version for its
@@ -573,8 +554,7 @@ public interface BundleManagerRemote {
* - Global.CREATE_BUNDLES and Global.VIEW_BUNDLES
* - Global.CREATE_BUNDLES and BundleGroup.VIEW_BUNDLES_IN_GROUP for bundle group BG and the relevant bundle is assigned to BG
* - BundleGroup.CREATE_BUNDLES_IN_GROUP for bundle group BG and the relevant bundle is assigned to BG
- * </pre>
- *
+ * </pre>
* @param subject user that must have proper permissions
* @param bundleVersionId the BundleVersion being queried
* @param withoutBundleFileOnly if true omit any filenames that already have a corresponding BundleFile for
@@ -587,11 +567,11 @@ public interface BundleManagerRemote {
/**
* Purges the destination's live deployment content from the remote platforms.
- * </pre>
+ * <pre>
* Required Permissions: Either:
* - Global.DEPLOY_BUNDLES and a view of the relevant bundle and a view of the relevant resource group (may involve multiple roles)
* - Resource.DEPLOY_BUNDLES_TO_GROUP and a view of the relevant bundle and a view of the relevant resource group (may involve multiple roles)
- *
+ * </pre>
* @param subject user that must have proper permissions
* @param bundleDestinationId the ID of the destination that is to be purged of bundle content
*/
@@ -603,11 +583,11 @@ public interface BundleManagerRemote {
* complete. The returned BundleDeployment can be used to track the history of the individual deployments.
* <br/><br/>
* TODO: Add the scheduling capability, currently it's Immediate.
- * </pre>
+ * <pre>
* Required Permissions: Either:
* - Global.DEPLOY_BUNDLES and a view of the relevant bundle and a view of the relevant resource group (may involve multiple roles)
* - Resource.DEPLOY_BUNDLES_TO_GROUP and a view of the relevant bundle and a view of the relevant resource group (may involve multiple roles)
- *
+ * </pre>
* @param subject user that must have proper permissions
* @param bundleDeploymentId the BundleDeployment being used to guide the deployments
* @param isCleanDeployment if true perform a wipe of the deploy directory prior to the deployment. If false
@@ -645,11 +625,13 @@ public interface BundleManagerRemote {
/**
* Unassign the specified bundles from the specified bundle group.
- * </pre>
- * Requires VIEW permission for the relevant bundles and either:
+ * <pre>
+ * Requires VIEW permission for the relevant bundles and one of:
+ * - Global.MANAGE_BUNDLE_GROUPS
* - Global.DELETE_BUNDLE
- * - BundleGroup.DELETE_BUNDLES_FROM_GROUP or BundleGroup.UNASSIGN_BUNDLES_FROM_GROUP for the relevant bundle group
- *
+ * - BundleGroup.UNASSIGN_BUNDLES_FROM_GROUP for the relevant bundle group
+ * - BundleGroup.DELETE_BUNDLES_FROM_GROUP for the relevant bundle group
+ * </pre>
* @param subject
* @param bundleGroupId
* @param bundleIds
10 years, 10 months
[rhq] 19 commits - .gitignore modules/core modules/enterprise
by Jiri Kremser
.gitignore | 2
modules/core/domain/src/main/java/org/rhq/core/domain/cloud/StorageNode.java | 4
modules/core/domain/src/main/java/org/rhq/core/domain/cloud/StorageNodeLoadComposite.java | 15
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/AdministrationView.java | 6
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeAdminView.java | 458 ++++------
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDatasource.java | 210 ++--
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDatasourceField.java | 6
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDetailView.java | 246 +++--
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeLoadComponent.java | 273 +++++
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeTableView.java | 125 +-
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/alert/AlertDataSource.java | 2
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/alert/AlertHistoryView.java | 20
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/configuration/ConfigurationEditor.java | 13
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/AbstractTableSection.java | 21
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/StorageGWTService.java | 14
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/StorageGWTServiceImpl.java | 59 +
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerBean.java | 198 +++-
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerLocal.java | 6
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementDataManagerBean.java | 2
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementDataManagerRemote.java | 3
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/storage/StorageClientManagerBean.java | 14
21 files changed, 1106 insertions(+), 591 deletions(-)
New commits:
commit 9bed24f209aca673c69f62ee2a4fa33771df6943
Author: Jirka Kremser <jkremser(a)redhat.com>
Date: Mon Aug 5 16:00:35 2013 +0200
squashed commit: Added method in the GWT impl class returning the data
for sparkline graph for storage nodes. Another iteration of Storage Node
UI: sparkline small graphs support. Fetching also definition ids. It is
needed in order to get the data for sparkline graphs.
diff --git a/modules/core/domain/src/main/java/org/rhq/core/domain/cloud/StorageNode.java b/modules/core/domain/src/main/java/org/rhq/core/domain/cloud/StorageNode.java
index f4d3934..a1010b5 100644
--- a/modules/core/domain/src/main/java/org/rhq/core/domain/cloud/StorageNode.java
+++ b/modules/core/domain/src/main/java/org/rhq/core/domain/cloud/StorageNode.java
@@ -63,7 +63,7 @@ import org.rhq.core.domain.resource.Resource;
@NamedQuery(name = StorageNode.QUERY_DELETE_BY_ID, query = "" //
+ "DELETE FROM StorageNode s WHERE s.id = :storageNodeId "),
@NamedQuery(name = StorageNode.QUERY_FIND_SCHEDULE_IDS_BY_PARENT_RESOURCE_ID_AND_MEASUREMENT_DEFINITION_NAMES, query = "" //
- + " SELECT def.name, ms.id FROM MeasurementSchedule ms " //
+ + " SELECT def.name, def.id, ms.id, res.id FROM MeasurementSchedule ms " //
+ " JOIN ms.definition def " //
+ " JOIN ms.resource res " //
+ " WHERE ms.definition = def " //
@@ -72,7 +72,7 @@ import org.rhq.core.domain.resource.Resource;
+ " AND def.name IN (:metricNames)"), //
@NamedQuery(name = StorageNode.QUERY_FIND_SCHEDULE_IDS_BY_GRANDPARENT_RESOURCE_ID_AND_MEASUREMENT_DEFINITION_NAMES, query = "" //
- + " SELECT def.name, ms.id FROM MeasurementSchedule ms " //
+ + " SELECT def.name, def.id, ms.id, res.id FROM MeasurementSchedule ms " //
+ " JOIN ms.definition def " //
+ " JOIN ms.resource res " //
+ " WHERE ms.definition = def " //
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeAdminView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeAdminView.java
index 7cc2ef1..5538db5 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeAdminView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeAdminView.java
@@ -44,6 +44,7 @@ import org.rhq.enterprise.gui.coregui.client.components.view.ViewName;
import org.rhq.enterprise.gui.coregui.client.gwt.GWTServiceLookup;
import org.rhq.enterprise.gui.coregui.client.inventory.groups.detail.configuration.GroupResourceConfigurationEditView;
import org.rhq.enterprise.gui.coregui.client.inventory.resource.type.ResourceTypeRepository;
+import org.rhq.enterprise.gui.coregui.client.util.Log;
import org.rhq.enterprise.gui.coregui.client.util.enhanced.EnhancedVLayout;
import org.rhq.enterprise.gui.coregui.client.util.message.Message;
@@ -190,8 +191,9 @@ public class StorageNodeAdminView extends EnhancedVLayout implements/* HasViewNa
GWTServiceLookup.getStorageService().findNotAcknowledgedStorageNodeAlertsCount(new AsyncCallback<Integer>() {
@Override
public void onSuccess(Integer result) {
+ Log.info("Running the job fetching the number of ALL unack alerts...");
alerts.setTitle(StorageNodeAdminView.getAlertsString(alerts.getTitle(), result));
- schedule(5 * 1000);
+ schedule(15 * 1000);
}
@Override
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDatasource.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDatasource.java
index a7058d7..7a777b1 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDatasource.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDatasource.java
@@ -358,7 +358,7 @@ public class StorageNodeDatasource extends RPCDataSource<StorageNodeLoadComposit
recordsList.add(makeListGridRecord(loadComposite.getHeapPercentageUsed(), "Heap Percent Used", "This value is calculated by dividing Heap Used by Heap Maximum.", HEAP_PERCENTAGE_KEY));
// disk related metrics
- recordsList.add(makeListGridRecord(loadComposite.getDataDiskUsed(), "Total Disk Space Used", "Total space used on disk by all data files, commit logs, and saved caches.", "totaldisk"));
+ recordsList.add(makeListGridRecord(loadComposite.getDataDiskUsed(), "Disk Space Used by Storage Node", "Total space used on disk by all data files, commit logs, and saved caches.", "totaldisk"));
recordsList.add(makeListGridRecord(loadComposite.getTotalDiskUsedPercentage(),"Total Disk Space Percent Used", "Percentage of total disk space used (system and Storage Node) on the partitions that contain the data files. If multiple data locations are specified then the aggregate accross all the partitions that contain data files is reported.", TOTAL_DISK_SPACE_PERCENTAGE_KEY));
recordsList.add(makeListGridRecord(loadComposite.getDataDiskUsedPercentage(), "Data Disk Space Percent Used","Percentage of disk space used by data files on the partitions that contain the data files. If multiple data locations are specified then the aggregate accross all the partitions that contain data files is reported.", DATA_DISK_SPACE_PERCENTAGE_KEY));
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDetailView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDetailView.java
index db0aeee..7d0b3a9 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDetailView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDetailView.java
@@ -29,16 +29,27 @@ import static org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDat
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.rpc.AsyncCallback;
+import com.smartgwt.client.types.Alignment;
+import com.smartgwt.client.types.ContentsType;
import com.smartgwt.client.types.Overflow;
+import com.smartgwt.client.types.VerticalAlignment;
import com.smartgwt.client.types.VisibilityMode;
import com.smartgwt.client.widgets.HTMLFlow;
import com.smartgwt.client.widgets.form.DynamicForm;
+import com.smartgwt.client.widgets.form.fields.CanvasItem;
import com.smartgwt.client.widgets.form.fields.FormItem;
+import com.smartgwt.client.widgets.form.fields.LinkItem;
import com.smartgwt.client.widgets.form.fields.StaticTextItem;
+import com.smartgwt.client.widgets.form.fields.events.ClickEvent;
+import com.smartgwt.client.widgets.form.fields.events.ClickHandler;
import com.smartgwt.client.widgets.layout.LayoutSpacer;
import com.smartgwt.client.widgets.layout.SectionStack;
import com.smartgwt.client.widgets.layout.SectionStackSection;
@@ -46,7 +57,10 @@ import com.smartgwt.client.widgets.layout.SectionStackSection;
import org.rhq.core.domain.cloud.StorageNode;
import org.rhq.core.domain.criteria.ResourceCriteria;
import org.rhq.core.domain.criteria.StorageNodeCriteria;
+import org.rhq.core.domain.measurement.MeasurementDefinition;
+import org.rhq.core.domain.measurement.composite.MeasurementDataNumericHighLowComposite;
import org.rhq.core.domain.resource.Resource;
+import org.rhq.core.domain.resource.ResourceType;
import org.rhq.core.domain.resource.composite.ResourceComposite;
import org.rhq.core.domain.util.PageList;
import org.rhq.enterprise.gui.coregui.client.BookmarkableView;
@@ -56,9 +70,15 @@ import org.rhq.enterprise.gui.coregui.client.ViewPath;
import org.rhq.enterprise.gui.coregui.client.components.table.TimestampCellFormatter;
import org.rhq.enterprise.gui.coregui.client.gwt.GWTServiceLookup;
import org.rhq.enterprise.gui.coregui.client.inventory.InventoryView;
+import org.rhq.enterprise.gui.coregui.client.inventory.common.detail.summary.AbstractActivityView;
+import org.rhq.enterprise.gui.coregui.client.inventory.common.detail.summary.AbstractActivityView.ChartViewWindow;
import org.rhq.enterprise.gui.coregui.client.inventory.resource.detail.configuration.ResourceConfigurationEditView;
+import org.rhq.enterprise.gui.coregui.client.inventory.resource.detail.monitoring.D3GraphListView;
import org.rhq.enterprise.gui.coregui.client.inventory.resource.detail.operation.history.ResourceOperationHistoryListView;
+import org.rhq.enterprise.gui.coregui.client.inventory.resource.type.ResourceTypeRepository;
+import org.rhq.enterprise.gui.coregui.client.util.BrowserUtility;
import org.rhq.enterprise.gui.coregui.client.util.Log;
+import org.rhq.enterprise.gui.coregui.client.util.MeasurementUtility;
import org.rhq.enterprise.gui.coregui.client.util.StringUtility;
import org.rhq.enterprise.gui.coregui.client.util.enhanced.EnhancedHLayout;
import org.rhq.enterprise.gui.coregui.client.util.enhanced.EnhancedVLayout;
@@ -84,6 +104,8 @@ public class StorageNodeDetailView extends EnhancedVLayout implements Bookmarkab
private StaticTextItem alertsItem;
private int expandedSection = -1;
private HTMLFlow header;
+ private ChartViewWindow window;
+ private D3GraphListView graphView;
private volatile int initSectionCount = 0;
private int unackAlerts = -1;
@@ -134,7 +156,8 @@ public class StorageNodeDetailView extends EnhancedVLayout implements Bookmarkab
initSectionCount++;
}
prepareDetailsSection(sectionStack, node);
- prepareLoadSection(sectionStack, node);
+ fetchSparkLineDataForLoadComponent(sectionStack, node);
+
}
public void onFailure(Throwable caught) {
@@ -168,12 +191,28 @@ public class StorageNodeDetailView extends EnhancedVLayout implements Bookmarkab
final ResourceComposite resourceComposite = result.get(0);
// prepareOperationHistory(resourceComposite);
prepareResourceConfigEditor(resourceComposite);
-
}
}
});
}
+ private void fetchSparkLineDataForLoadComponent(final SectionStack stack, final StorageNode storageNode) {
+
+ GWTServiceLookup.getStorageService().findStorageNodeLoadDataForLast(storageNode, 8, MeasurementUtility.UNIT_HOURS,
+ 60, new AsyncCallback<Map<String, List<MeasurementDataNumericHighLowComposite>>>() {
+ @Override
+ public void onFailure(Throwable caught) {
+
+ }
+
+ @Override
+ public void onSuccess(Map<String, List<MeasurementDataNumericHighLowComposite>> result) {
+ prepareLoadSection(sectionStack, storageNode, result);
+ }
+
+ });
+ }
+
private void fetchUnackAlerts(final int storageNodeId) {
GWTServiceLookup.getStorageService().findNotAcknowledgedStorageNodeAlertsCounts(Arrays.asList(storageNodeId),
new AsyncCallback<List<Integer>>() {
@@ -318,8 +357,9 @@ public class StorageNodeDetailView extends EnhancedVLayout implements Bookmarkab
initSectionCount++;
}
- private void prepareLoadSection(SectionStack stack, final StorageNode storageNode) {
- StorageNodeLoadComponent loadDataComponent = new StorageNodeLoadComponent(storageNode.getId());
+ private void prepareLoadSection(SectionStack stack, final StorageNode storageNode,
+ final Map<String, List<MeasurementDataNumericHighLowComposite>> sparkLineData) {
+ StorageNodeLoadComponent loadDataComponent = new StorageNodeLoadComponent(storageNode.getId(), sparkLineData);
loadDataComponent.setExtraSpace(5);
loadLayout = new EnhancedVLayout();
loadLayout.setWidth100();
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeLoadComponent.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeLoadComponent.java
index db54108..7cfb278 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeLoadComponent.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeLoadComponent.java
@@ -21,22 +21,46 @@ package org.rhq.enterprise.gui.coregui.client.admin.storage;
import static org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDatasource.DONT_MISS_ME_COLOR;
import static org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDatasource.OK_COLOR;
import static org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDatasource.WARN_COLOR;
+import static org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDatasourceField.FIELD_ALERTS;
+import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import com.google.gwt.user.client.Timer;
+import com.google.gwt.user.client.rpc.AsyncCallback;
+import com.smartgwt.client.types.Alignment;
import com.smartgwt.client.types.Autofit;
+import com.smartgwt.client.types.ContentsType;
+import com.smartgwt.client.types.Overflow;
+import com.smartgwt.client.types.VerticalAlignment;
+import com.smartgwt.client.widgets.HTMLFlow;
import com.smartgwt.client.widgets.IButton;
import com.smartgwt.client.widgets.events.ClickEvent;
import com.smartgwt.client.widgets.events.ClickHandler;
+import com.smartgwt.client.widgets.form.DynamicForm;
+import com.smartgwt.client.widgets.form.fields.CanvasItem;
+import com.smartgwt.client.widgets.form.fields.LinkItem;
+import com.smartgwt.client.widgets.form.fields.StaticTextItem;
import com.smartgwt.client.widgets.grid.ListGrid;
import com.smartgwt.client.widgets.grid.ListGridField;
import com.smartgwt.client.widgets.grid.ListGridRecord;
+import com.smartgwt.client.widgets.grid.events.DataArrivedEvent;
+import com.smartgwt.client.widgets.grid.events.DataArrivedHandler;
import com.smartgwt.client.widgets.toolbar.ToolStrip;
+import org.rhq.core.domain.measurement.MeasurementDefinition;
+import org.rhq.core.domain.measurement.composite.MeasurementDataNumericHighLowComposite;
import org.rhq.enterprise.gui.coregui.client.CoreGUI;
+import org.rhq.enterprise.gui.coregui.client.LinkManager;
import org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDatasource.StorageNodeLoadCompositeDatasource;
import org.rhq.enterprise.gui.coregui.client.gwt.GWTServiceLookup;
-import org.rhq.enterprise.gui.coregui.client.util.MeasurementUtility;
+import org.rhq.enterprise.gui.coregui.client.inventory.common.detail.summary.AbstractActivityView;
+import org.rhq.enterprise.gui.coregui.client.inventory.common.detail.summary.AbstractActivityView.ChartViewWindow;
+import org.rhq.enterprise.gui.coregui.client.inventory.resource.detail.monitoring.D3GraphListView;
+import org.rhq.enterprise.gui.coregui.client.util.BrowserUtility;
import org.rhq.enterprise.gui.coregui.client.util.enhanced.EnhancedVLayout;
/**
@@ -46,15 +70,15 @@ import org.rhq.enterprise.gui.coregui.client.util.enhanced.EnhancedVLayout;
*/
public class StorageNodeLoadComponent extends EnhancedVLayout {
private final ListGrid loadGrid;
+ private Map<String, List<MeasurementDataNumericHighLowComposite>> sparkLineData;
- public StorageNodeLoadComponent(int storageNodeId) {
- this(storageNodeId, null, null);
- }
-
- public StorageNodeLoadComponent(final int storageNodeId, final ListGrid parentGrid, final ListGridRecord record) {
+ public StorageNodeLoadComponent(final int storageNodeId,
+ Map<String, List<MeasurementDataNumericHighLowComposite>> sparkLineData) {
super(5);
setPadding(5);
setBackgroundColor("#ffffff");
+ this.sparkLineData = sparkLineData;
+ final boolean showSparkLine = sparkLineData != null && !sparkLineData.isEmpty();
loadGrid = new ListGrid() {
@Override
protected String getCellCSSText(ListGridRecord record, int rowNum, int colNum) {
@@ -90,11 +114,13 @@ public class StorageNodeLoadComponent extends EnhancedVLayout {
loadGrid.setAutoFitData(Autofit.VERTICAL);
StorageNodeLoadCompositeDatasource datasource = StorageNodeLoadCompositeDatasource.getInstance(storageNodeId);
List<ListGridField> fields = datasource.getListGridFields();
+ if (showSparkLine) {
+ fields.add(new ListGridField("sparkline", 90));
+ }
loadGrid.setFields(fields.toArray(new ListGridField[fields.size()]));
loadGrid.setAutoFetchData(true);
loadGrid.setHoverWidth(300);
-
ToolStrip toolStrip = new ToolStrip();
IButton settingsButton = new IButton("Settings");
settingsButton.addClickHandler(new ClickHandler() {
@@ -113,10 +139,194 @@ public class StorageNodeLoadComponent extends EnhancedVLayout {
});
refreshButton.setExtraSpace(5);
toolStrip.addMember(refreshButton);
-
loadGrid.setDataSource(datasource);
+ if (showSparkLine) {
+ loadGrid.addDataArrivedHandler(new DataArrivedHandler() {
+ @Override
+ public void onDataArrived(DataArrivedEvent event) {
+ showSparkLineGraphs();
+ }
+ });
+ }
addMember(loadGrid);
-
+
}
+ private void showSparkLineGraphs() {
+ ListGridRecord[] records = loadGrid.getRecords();
+ int i = 0;
+ for (Entry<String, List<MeasurementDataNumericHighLowComposite>> entry : sparkLineData.entrySet()) {
+ boolean someChartedData = false;
+ List<MeasurementDataNumericHighLowComposite> data = entry.getValue();
+ //locate last and minimum values.
+ double lastValue = -1;
+ double minValue = Double.MAX_VALUE;//
+ for (MeasurementDataNumericHighLowComposite d : data) {
+ if ((!Double.isNaN(d.getValue()))
+ && (!String.valueOf(d.getValue()).contains("NaN"))) {
+ if (d.getValue() < minValue) {
+ minValue = d.getValue();
+ }
+ lastValue = d.getValue();
+ }
+ }
+
+ //collapse the data into comma delimited list for consumption by third party javascript library(jquery.sparkline)
+ String commaDelimitedList = "";
+ for (MeasurementDataNumericHighLowComposite d : data) {
+ if ((!Double.isNaN(d.getValue()))
+ && (!String.valueOf(d.getValue()).contains("NaN"))) {
+ commaDelimitedList += d.getValue() + ",";
+ }
+ }
+
+ //if graph content returned
+ someChartedData = lastValue != -1;
+
+ if (someChartedData && records.length > i) {
+ String contents = "<span id='sparkline_" + entry.getKey() + "' class='dynamicsparkline' width='0' "
+ + "values='" + commaDelimitedList + "'>...</span>";
+ records[i].setAttribute("sparkline", contents);
+ }
+ i++;
+ }
+ loadGrid.setData(records);
+
+
+
+
+
+//
+//
+//
+//
+//
+// if (!results.isEmpty()) {
+//
+// //iterate over the retrieved charting data
+// for (int index = 0; index < displayOrder.length; index++) {
+// //retrieve the correct measurement definition
+// final MeasurementDefinition md = measurementDefMap
+// .get(displayOrder[index]);
+//
+// //load the data results for the given metric definition
+// List<MeasurementDataNumericHighLowComposite> data = results
+// .get(index);
+//
+// //locate last and minimum values.
+// double lastValue = -1;
+// double minValue = Double.MAX_VALUE;//
+// for (MeasurementDataNumericHighLowComposite d : data) {
+// if ((!Double.isNaN(d.getValue()))
+// && (!String.valueOf(d.getValue()).contains("NaN"))) {
+// if (d.getValue() < minValue) {
+// minValue = d.getValue();
+// }
+// lastValue = d.getValue();
+// }
+// }
+//
+// //collapse the data into comma delimited list for consumption by third party javascript library(jquery.sparkline)
+// String commaDelimitedList = "";
+//
+// for (MeasurementDataNumericHighLowComposite d : data) {
+// if ((!Double.isNaN(d.getValue()))
+// && (!String.valueOf(d.getValue()).contains("NaN"))) {
+// commaDelimitedList += d.getValue() + ",";
+// }
+// }
+// DynamicForm row = new DynamicForm();
+// row.setNumCols(3);
+// row.setColWidths(65, "*", 100);
+// row.setWidth100();
+// row.setAutoHeight();
+// row.setOverflow(Overflow.VISIBLE);
+// HTMLFlow sparklineGraph = new HTMLFlow();
+// String contents = "<span id='sparkline_" + index
+// + "' class='dynamicsparkline' width='0' " + "values='"
+// + commaDelimitedList + "'>...</span>";
+// sparklineGraph.setContents(contents);
+// sparklineGraph.setContentsType(ContentsType.PAGE);
+// //disable scrollbars on span
+// sparklineGraph.setScrollbarSize(0);
+//
+// CanvasItem sparklineContainer = new CanvasItem();
+// sparklineContainer.setShowTitle(false);
+// sparklineContainer.setHeight(16);
+// sparklineContainer.setWidth(60);
+// sparklineContainer.setCanvas(sparklineGraph);
+//
+// //Link/title element
+// final String title = md.getDisplayName();
+// LinkItem link = AbstractActivityView.newLinkItem(title, null);
+// link.setTooltip(title);
+// link.setTitleVAlign(VerticalAlignment.TOP);
+// link.setAlign(Alignment.LEFT);
+// link.setClipValue(true);
+// link.setWrap(true);
+// link.setHeight(26);
+// link.setWidth("100%");
+// if (!BrowserUtility.isBrowserPreIE9()){
+// link.addClickHandler(new ClickHandler() {
+// @Override
+// public void onClick(ClickEvent event) {
+// window = new ChartViewWindow(title);
+//
+// graphView = D3GraphListView
+// .createSingleGraph(resourceComposite.getResource(),
+// md.getId(), true);
+//
+// window.addItem(graphView);
+// window.show();
+// }
+// });
+// } else{
+// link.disable();
+// }
+//
+//
+// //Value
+// String convertedValue;
+// convertedValue = AbstractActivityView.convertLastValueForDisplay(
+// lastValue, md);
+// StaticTextItem value = AbstractActivityView
+// .newTextItem(convertedValue);
+// value.setVAlign(VerticalAlignment.TOP);
+// value.setAlign(Alignment.RIGHT);
+//
+// row.setItems(sparklineContainer, link, value);
+// row.setWidth100();
+//
+// //if graph content returned
+// if ((!md.getName().trim().contains("Trait.")) && (lastValue != -1)) {
+// column.addMember(row);
+// someChartedData = true;
+// }
+// }
+// if (!someChartedData) {// when there are results but no chartable entries.
+// DynamicForm row = AbstractActivityView.createEmptyDisplayRow(
+//
+// AbstractActivityView.RECENT_MEASUREMENTS_NONE);
+// column.addMember(row);
+// } else {
+// //insert see more link
+// DynamicForm row = new DynamicForm();
+// String link = LinkManager
+// .getResourceMonitoringGraphsLink(resourceId);
+// AbstractActivityView.addSeeMoreLink(row, link, column);
+// }
+// //call out to 3rd party javascript lib
+// new Timer(){
+// @Override
+// public void run() {
+// BrowserUtility.graphSparkLines();
+// }
+// }.schedule(200);
+// } else {
+// DynamicForm row = AbstractActivityView
+// .createEmptyDisplayRow(AbstractActivityView.RECENT_MEASUREMENTS_NONE);
+// column.addMember(row);
+// }
+// setRefreshing(false);
+ }
}
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeTableView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeTableView.java
index bb90929..328545a 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeTableView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeTableView.java
@@ -27,7 +27,7 @@ import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
-
+import org.rhq.enterprise.gui.coregui.client.util.Log;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.smartgwt.client.data.Criteria;
@@ -140,6 +140,7 @@ public class StorageNodeTableView extends TableSection<StorageNodeDatasource> {
private void scheduleUnacknowledgedAlertsPollingJob(final ListGrid listGrid) {
new Timer() {
public void run() {
+ Log.info("Running the job fetching the number of unack alerts for particular storage nodes...");
final ListGridRecord[] records = listGrid.getRecords();
List<Integer> storageNodeIds = new ArrayList<Integer>(records.length);
for (ListGridRecord record : records) {
@@ -156,16 +157,19 @@ public class StorageNodeTableView extends TableSection<StorageNodeDatasource> {
StorageNodeAdminView.getAlertsString("New Alerts", value));
listGrid.setData(records);
}
- schedule(10 * 1000);
+ schedule(15 * 1000);
}
@Override
public void onFailure(Throwable caught) {
schedule(60 * 1000);
+ // todo:
+ SC.say("fooo");
}
});
}
- }.schedule(5 * 1000);
+ }.schedule(15 * 1000);
+ Log.info("Polling job fetching the number of unack alerts for particular storage nodes has been scheduled");
}
@Override
@@ -174,7 +178,7 @@ public class StorageNodeTableView extends TableSection<StorageNodeDatasource> {
@Override
protected Canvas getExpansionComponent(final ListGridRecord record) {
int id = record.getAttributeAsInt(FIELD_ID);
- return new StorageNodeLoadComponent(id, this, record);
+ return new StorageNodeLoadComponent(id, null);
}
};
listGrid.setCanExpandRecords(true);
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/StorageGWTService.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/StorageGWTService.java
index 69c875e..1e3376c 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/StorageGWTService.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/StorageGWTService.java
@@ -23,12 +23,14 @@
package org.rhq.enterprise.gui.coregui.client.gwt;
import java.util.List;
+import java.util.Map;
import com.google.gwt.user.client.rpc.RemoteService;
import org.rhq.core.domain.cloud.StorageNode;
import org.rhq.core.domain.cloud.StorageNodeLoadComposite;
import org.rhq.core.domain.criteria.StorageNodeCriteria;
+import org.rhq.core.domain.measurement.composite.MeasurementDataNumericHighLowComposite;
import org.rhq.core.domain.util.PageList;
/**
@@ -76,4 +78,6 @@ public interface StorageGWTService extends RemoteService {
int findNotAcknowledgedStorageNodeAlertsCount() throws RuntimeException;
List<Integer> findNotAcknowledgedStorageNodeAlertsCounts(List<Integer> storageNodeIds) throws RuntimeException;
+
+ Map<String, List<MeasurementDataNumericHighLowComposite>> findStorageNodeLoadDataForLast(StorageNode node, int lastN, int unit, int numPoints) throws RuntimeException;
}
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/StorageGWTServiceImpl.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/StorageGWTServiceImpl.java
index 624953c..7f3093b 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/StorageGWTServiceImpl.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/StorageGWTServiceImpl.java
@@ -24,11 +24,13 @@ package org.rhq.enterprise.gui.coregui.server.gwt;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
import org.rhq.core.domain.cloud.StorageNode;
import org.rhq.core.domain.cloud.StorageNodeLoadComposite;
import org.rhq.core.domain.criteria.ResourceCriteria;
import org.rhq.core.domain.criteria.StorageNodeCriteria;
+import org.rhq.core.domain.measurement.composite.MeasurementDataNumericHighLowComposite;
import org.rhq.core.domain.resource.Resource;
import org.rhq.core.domain.util.PageList;
import org.rhq.enterprise.gui.coregui.client.gwt.StorageGWTService;
@@ -137,4 +139,15 @@ public class StorageGWTServiceImpl extends AbstractGWTServiceImpl implements Sto
throw getExceptionToThrowToClient(t);
}
}
+
+ @Override
+ public Map<String, List<MeasurementDataNumericHighLowComposite>> findStorageNodeLoadDataForLast(StorageNode node, int lastN, int unit, int numPoints) throws RuntimeException {
+ try {
+ List<Long> beginEnd = MeasurementUtils.calculateTimeFrame(lastN, unit);
+ return SerialUtility.prepare(storageNodeManager.findStorageNodeLoadDataForLast(getSessionSubject(), node,
+ beginEnd.get(0), beginEnd.get(1), numPoints), "StorageGWTServiceImpl.findStorageNodeLoadDataForLast");
+ } catch (Throwable t) {
+ throw getExceptionToThrowToClient(t);
+ }
+ }
}
commit 6fe092021521e4ea752f27a0578b864938bf13b7
Author: Jirka Kremser <jkremser(a)redhat.com>
Date: Mon Aug 5 15:58:54 2013 +0200
New method on server jar for sparkline graphs for storage node.
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerBean.java
index 0cf45e4..ae1e69a 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerBean.java
@@ -29,6 +29,7 @@ import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@@ -43,6 +44,7 @@ import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
+import org.apache.commons.collections.map.LinkedMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -65,6 +67,7 @@ import org.rhq.core.domain.criteria.ResourceOperationHistoryCriteria;
import org.rhq.core.domain.criteria.StorageNodeCriteria;
import org.rhq.core.domain.measurement.MeasurementAggregate;
import org.rhq.core.domain.measurement.MeasurementUnits;
+import org.rhq.core.domain.measurement.composite.MeasurementDataNumericHighLowComposite;
import org.rhq.core.domain.operation.OperationRequestStatus;
import org.rhq.core.domain.operation.ResourceOperationHistory;
import org.rhq.core.domain.operation.bean.GroupOperationSchedule;
@@ -122,6 +125,19 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
private static final int MAX_ITERATIONS = 10;
private static final String UPDATE_CONFIGURATION_OPERATION = "updateConfiguration";
private static final String RESTART_OPERATION = "restart";
+
+ // metric names on Storage Service resource
+ private static final String METRIC_TOKENS = "Tokens", METRIC_OWNERSHIP = "Ownership";
+ private static final String METRIC_DATA_DISK_USED_PERCENTAGE = "Calculated.DataDiskUsedPercentage";
+ private static final String METRIC_TOTAL_DISK_USED_PERCENTAGE = "Calculated.TotalDiskUsedPercentage";
+ private static final String METRIC_FREE_DISK_TO_DATA_RATIO = "Calculated.FreeDiskToDataSizeRatio";
+ private static final String METRIC_LOAD = "Load", METRIC_KEY_CACHE_SIZE = "KeyCacheSize",
+ METRIC_ROW_CACHE_SIZE = "RowCacheSize", METRIC_TOTAL_COMMIT_LOG_SIZE = "TotalCommitlogSize";
+
+ //metric names on Memory Subsystem resource
+ private static final String METRIC_HEAP_COMMITED = "{HeapMemoryUsage.committed}",
+ METRIC_HEAP_USED = "{HeapMemoryUsage.used}", METRIC_HEAP_USED_PERCENTAGE = "Calculated.HeapUsagePercentage";
+
@PersistenceContext(unitName = RHQConstants.PERSISTENCE_UNIT_NAME)
private EntityManager entityManager;
@@ -347,106 +363,90 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
int resourceId = getResourceIdFromStorageNode(node);
Map<String, Integer> scheduleIdsMap = new HashMap<String, Integer>();
- // get the schedule ids for Storage Service resource
- final String tokensMetric = "Tokens", ownershipMetric = "Ownership";
- final String dataDiskUsedPercentageMetric = "Calculated.DataDiskUsedPercentage";
- final String totalDiskUsedPercentageMetric = "Calculated.TotalDiskUsedPercentage";
- final String freeDiskToDataRatioMetric = "Calculated.FreeDiskToDataSizeRatio";
- final String loadMetric = "Load", keyCacheSize = "KeyCacheSize", rowCacheSize = "RowCacheSize", totalCommitLogSize = "TotalCommitlogSize";
- TypedQuery<Object[]> query = entityManager.<Object[]> createNamedQuery(
- StorageNode.QUERY_FIND_SCHEDULE_IDS_BY_PARENT_RESOURCE_ID_AND_MEASUREMENT_DEFINITION_NAMES, Object[].class);
- query.setParameter("parrentId", resourceId).setParameter("metricNames",
- Arrays.asList(tokensMetric, ownershipMetric, loadMetric, keyCacheSize, rowCacheSize, totalCommitLogSize,
- dataDiskUsedPercentageMetric, totalDiskUsedPercentageMetric, freeDiskToDataRatioMetric));
- for (Object[] pair : query.getResultList()) {
- scheduleIdsMap.put((String) pair[0], (Integer) pair[1]);
+ for (Object[] tupple : getStorageServiceScheduleIds(resourceId)) {
+ String definitionName = (String) tupple[0];
+ Integer scheduleId = (Integer) tupple[2];
+ scheduleIdsMap.put(definitionName, scheduleId);
}
-
- // get the schedule ids for Memory Subsystem resource
- final String heapCommittedMetric = "{HeapMemoryUsage.committed}", heapUsedMetric = "{HeapMemoryUsage.used}", heapUsedPercentageMetric = "Calculated.HeapUsagePercentage";
- query = entityManager.<Object[]> createNamedQuery(
- StorageNode.QUERY_FIND_SCHEDULE_IDS_BY_GRANDPARENT_RESOURCE_ID_AND_MEASUREMENT_DEFINITION_NAMES,
- Object[].class);
- query.setParameter("grandparrentId", resourceId).setParameter("metricNames",
- Arrays.asList(heapCommittedMetric, heapUsedMetric, heapUsedPercentageMetric));
- for (Object[] pair : query.getResultList()) {
- scheduleIdsMap.put((String) pair[0], (Integer) pair[1]);
+ for (Object[] tupple : getMemorySubsystemScheduleIds(resourceId)) {
+ String definitionName = (String) tupple[0];
+ Integer scheduleId = (Integer) tupple[2];
+ scheduleIdsMap.put(definitionName, scheduleId);
}
-
StorageNodeLoadComposite result = new StorageNodeLoadComposite(node, beginTime, endTime);
- MeasurementAggregate totalDiskUsedaggregate = new MeasurementAggregate(0d, 0d, 0d);
+ MeasurementAggregate totalDiskUsedAggregate = new MeasurementAggregate(0d, 0d, 0d);
Integer scheduleId = null;
// find the aggregates and enrich the result instance
if (!scheduleIdsMap.isEmpty()) {
- if ((scheduleId = scheduleIdsMap.get(tokensMetric)) != null) {
+ if ((scheduleId = scheduleIdsMap.get(METRIC_TOKENS)) != null) {
MeasurementAggregate tokensAggregate = measurementManager.getAggregate(subject, scheduleId, beginTime,
endTime);
result.setTokens(tokensAggregate);
}
- if ((scheduleId = scheduleIdsMap.get(ownershipMetric)) != null) {
+ if ((scheduleId = scheduleIdsMap.get(METRIC_OWNERSHIP)) != null) {
StorageNodeLoadComposite.MeasurementAggregateWithUnits ownershipAggregateWithUnits = getMeasurementAggregateWithUnits(
subject, scheduleId, MeasurementUnits.PERCENTAGE, beginTime, endTime);
result.setActuallyOwns(ownershipAggregateWithUnits);
}
//calculated disk space related metrics
- if ((scheduleId = scheduleIdsMap.get(dataDiskUsedPercentageMetric)) != null) {
+ if ((scheduleId = scheduleIdsMap.get(METRIC_DATA_DISK_USED_PERCENTAGE)) != null) {
StorageNodeLoadComposite.MeasurementAggregateWithUnits dataDiskUsedPercentageAggregateWithUnits = getMeasurementAggregateWithUnits(
subject, scheduleId, MeasurementUnits.PERCENTAGE, beginTime, endTime);
result.setDataDiskUsedPercentage(dataDiskUsedPercentageAggregateWithUnits);
}
- if ((scheduleId = scheduleIdsMap.get(totalDiskUsedPercentageMetric)) != null) {
+ if ((scheduleId = scheduleIdsMap.get(METRIC_TOTAL_DISK_USED_PERCENTAGE)) != null) {
StorageNodeLoadComposite.MeasurementAggregateWithUnits totalDiskUsedPercentageAggregateWithUnits = getMeasurementAggregateWithUnits(
subject, scheduleId, MeasurementUnits.PERCENTAGE, beginTime, endTime);
result.setTotalDiskUsedPercentage(totalDiskUsedPercentageAggregateWithUnits);
}
- if ((scheduleId = scheduleIdsMap.get(freeDiskToDataRatioMetric)) != null) {
+ if ((scheduleId = scheduleIdsMap.get(METRIC_FREE_DISK_TO_DATA_RATIO)) != null) {
MeasurementAggregate freeDiskToDataRatioAggregate = measurementManager.getAggregate(subject,
scheduleId, beginTime, endTime);
result.setFreeDiskToDataSizeRatio(freeDiskToDataRatioAggregate);
}
- if ((scheduleId = scheduleIdsMap.get(loadMetric)) != null) {
+ if ((scheduleId = scheduleIdsMap.get(METRIC_LOAD)) != null) {
StorageNodeLoadComposite.MeasurementAggregateWithUnits loadAggregateWithUnits = getMeasurementAggregateWithUnits(
subject, scheduleId, MeasurementUnits.BYTES, beginTime, endTime);
result.setLoad(loadAggregateWithUnits);
- updateAggregateTotal(totalDiskUsedaggregate, loadAggregateWithUnits.getAggregate());
- }
- if ((scheduleId = scheduleIdsMap.get(keyCacheSize)) != null) {
- updateAggregateTotal(totalDiskUsedaggregate,
- measurementManager.getAggregate(subject, scheduleId, beginTime, endTime));
- }
- if ((scheduleId = scheduleIdsMap.get(rowCacheSize)) != null) {
- updateAggregateTotal(totalDiskUsedaggregate,
- measurementManager.getAggregate(subject, scheduleId, beginTime, endTime));
+ updateAggregateTotal(totalDiskUsedAggregate, loadAggregateWithUnits.getAggregate());
}
- if ((scheduleId = scheduleIdsMap.get(totalCommitLogSize)) != null) {
- updateAggregateTotal(totalDiskUsedaggregate,
- measurementManager.getAggregate(subject, scheduleId, beginTime, endTime));
- }
-
- if (totalDiskUsedaggregate.getMax() > 0) {
+// if ((scheduleId = scheduleIdsMap.get(METRIC_KEY_CACHE_SIZE)) != null) {
+// updateAggregateTotal(totalDiskUsedAggregate,
+// measurementManager.getAggregate(subject, scheduleId, beginTime, endTime));
+// }
+// if ((scheduleId = scheduleIdsMap.get(METRIC_ROW_CACHE_SIZE)) != null) {
+// updateAggregateTotal(totalDiskUsedAggregate,
+// measurementManager.getAggregate(subject, scheduleId, beginTime, endTime));
+// }
+// if ((scheduleId = scheduleIdsMap.get(METRIC_TOTAL_COMMIT_LOG_SIZE)) != null) {
+// updateAggregateTotal(totalDiskUsedAggregate,
+// measurementManager.getAggregate(subject, scheduleId, beginTime, endTime));
+// }
+
+ if (totalDiskUsedAggregate.getMax() > 0) {
StorageNodeLoadComposite.MeasurementAggregateWithUnits totalDiskUsedAggregateWithUnits = new StorageNodeLoadComposite.MeasurementAggregateWithUnits(
- totalDiskUsedaggregate, MeasurementUnits.BYTES);
- totalDiskUsedAggregateWithUnits.setFormattedValue(getSummaryString(totalDiskUsedaggregate,
+ totalDiskUsedAggregate, MeasurementUnits.BYTES);
+ totalDiskUsedAggregateWithUnits.setFormattedValue(getSummaryString(totalDiskUsedAggregate,
MeasurementUnits.BYTES));
result.setDataDiskUsed(totalDiskUsedAggregateWithUnits);
}
- if ((scheduleId = scheduleIdsMap.get(heapCommittedMetric)) != null) {
+ if ((scheduleId = scheduleIdsMap.get(METRIC_HEAP_COMMITED)) != null) {
StorageNodeLoadComposite.MeasurementAggregateWithUnits heapCommittedAggregateWithUnits = getMeasurementAggregateWithUnits(
subject, scheduleId, MeasurementUnits.BYTES, beginTime, endTime);
result.setHeapCommitted(heapCommittedAggregateWithUnits);
}
- if ((scheduleId = scheduleIdsMap.get(heapUsedMetric)) != null) {
+ if ((scheduleId = scheduleIdsMap.get(METRIC_HEAP_USED)) != null) {
StorageNodeLoadComposite.MeasurementAggregateWithUnits heapUsedAggregateWithUnits = getMeasurementAggregateWithUnits(
subject, scheduleId, MeasurementUnits.BYTES, beginTime, endTime);
result.setHeapUsed(heapUsedAggregateWithUnits);
}
- if ((scheduleId = scheduleIdsMap.get(heapUsedPercentageMetric)) != null) {
+ if ((scheduleId = scheduleIdsMap.get(METRIC_HEAP_USED_PERCENTAGE)) != null) {
StorageNodeLoadComposite.MeasurementAggregateWithUnits heapUsedPercentageAggregateWithUnits = getMeasurementAggregateWithUnits(
subject, scheduleId, MeasurementUnits.PERCENTAGE, beginTime,
endTime);
@@ -456,6 +456,26 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
return result;
}
+
+ private List<Object[]> getStorageServiceScheduleIds(int storageNodeResourceId) {
+ // get the schedule ids for Storage Service resource
+ TypedQuery<Object[]> query = entityManager.<Object[]> createNamedQuery(
+ StorageNode.QUERY_FIND_SCHEDULE_IDS_BY_PARENT_RESOURCE_ID_AND_MEASUREMENT_DEFINITION_NAMES, Object[].class);
+ query.setParameter("parrentId", storageNodeResourceId).setParameter("metricNames",
+ Arrays.asList(METRIC_TOKENS, METRIC_OWNERSHIP, METRIC_LOAD/*, METRIC_KEY_CACHE_SIZE, METRIC_ROW_CACHE_SIZE, METRIC_TOTAL_COMMIT_LOG_SIZE*/,
+ METRIC_DATA_DISK_USED_PERCENTAGE, METRIC_TOTAL_DISK_USED_PERCENTAGE, METRIC_FREE_DISK_TO_DATA_RATIO));
+ return query.getResultList();
+ }
+
+ private List<Object[]> getMemorySubsystemScheduleIds(int storageNodeResourceId) {
+ // get the schedule ids for Memory Subsystem resource
+ TypedQuery<Object[]> query = entityManager.<Object[]> createNamedQuery(
+ StorageNode.QUERY_FIND_SCHEDULE_IDS_BY_GRANDPARENT_RESOURCE_ID_AND_MEASUREMENT_DEFINITION_NAMES,
+ Object[].class);
+ query.setParameter("grandparrentId", storageNodeResourceId).setParameter("metricNames",
+ Arrays.asList(METRIC_HEAP_COMMITED, METRIC_HEAP_USED, METRIC_HEAP_USED_PERCENTAGE));
+ return query.getResultList();
+ }
/**
* @param accumulator
@@ -776,6 +796,55 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
public void scheduleOperationInNewTransaction(Subject subject, ResourceOperationSchedule schedule) {
operationManager.scheduleResourceOperation(subject, schedule);
}
+
+ @Override
+ @RequiredPermissions({ @RequiredPermission(Permission.MANAGE_SETTINGS),
+ @RequiredPermission(Permission.MANAGE_INVENTORY) })
+ public Map<String, List<MeasurementDataNumericHighLowComposite>> findStorageNodeLoadDataForLast(Subject subject,
+ StorageNode node, long beginTime, long endTime, int numPoints) {
+ int storageNodeResourceId = getResourceIdFromStorageNode(node);
+ Map<String, List<MeasurementDataNumericHighLowComposite>> result = new LinkedHashMap<String, List<MeasurementDataNumericHighLowComposite>>();
+
+ List<Object[]> tupples = getStorageServiceScheduleIds(storageNodeResourceId);
+ List<String> defNames = new ArrayList<String>();
+ int[] definitionIds = new int[tupples.size()];
+ int resId = -1;
+ int index = 0;
+ for (Object[] tupple : tupples) {
+ String defName = (String) tupple[0];
+ int definitionId = (Integer) tupple[1];
+ resId = (Integer) tupple[3];
+ defNames.add(defName);
+ definitionIds[index++] = definitionId;
+ }
+ List<List<MeasurementDataNumericHighLowComposite>> storageServiceData = measurementManager.findDataForResource(
+ subject, resId, definitionIds, beginTime, endTime, numPoints);
+ for (int i = 0; i < storageServiceData.size(); i ++) {
+ List<MeasurementDataNumericHighLowComposite> oneRecord = storageServiceData.get(i);
+ result.put(defNames.get(i), oneRecord);
+ }
+
+ tupples = getMemorySubsystemScheduleIds(storageNodeResourceId);
+ defNames = new ArrayList<String>();
+ definitionIds = new int[tupples.size()];
+ resId = -1;
+ index = 0;
+ for (Object[] tupple : tupples) {
+ String defName = (String) tupple[0];
+ int definitionId = (Integer) tupple[1];
+ resId = (Integer) tupple[3];
+ defNames.add(defName);
+ definitionIds[index++] = definitionId;
+ }
+ List<List<MeasurementDataNumericHighLowComposite>> memorySubsystemData = measurementManager.findDataForResource(
+ subject, resId, definitionIds, beginTime, endTime, numPoints);
+ for (int i = 0; i < memorySubsystemData.size(); i ++) {
+ List<MeasurementDataNumericHighLowComposite> oneRecord = memorySubsystemData.get(i);
+ result.put(defNames.get(i), oneRecord);
+ }
+
+ return result;
+ }
private boolean runOperationAndWaitForResult(Subject subject, Resource storageNodeResource, String operationToRun,
Configuration parameters) {
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerLocal.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerLocal.java
index 63e8e3e..0c86152 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerLocal.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerLocal.java
@@ -20,6 +20,7 @@ package org.rhq.enterprise.server.cloud;
import java.net.InetAddress;
import java.util.List;
+import java.util.Map;
import javax.ejb.Local;
@@ -30,6 +31,7 @@ import org.rhq.core.domain.cloud.StorageNodeConfigurationComposite;
import org.rhq.core.domain.cloud.StorageNodeLoadComposite;
import org.rhq.core.domain.criteria.StorageNodeCriteria;
import org.rhq.core.domain.operation.bean.ResourceOperationSchedule;
+import org.rhq.core.domain.measurement.composite.MeasurementDataNumericHighLowComposite;
import org.rhq.core.domain.resource.Resource;
import org.rhq.core.domain.resource.group.ResourceGroup;
import org.rhq.core.domain.util.PageList;
@@ -185,6 +187,7 @@ public interface StorageNodeManagerLocal {
* @throws IllegalStateException if the group is not found or does not exist.
*/
ResourceGroup getStorageNodeGroup();
+
void scheduleOperationInNewTransaction(Subject subject, ResourceOperationSchedule schedule);
@@ -192,4 +195,5 @@ public interface StorageNodeManagerLocal {
void runAddNodeMaintenance();
+ Map<String, List<MeasurementDataNumericHighLowComposite>> findStorageNodeLoadDataForLast(Subject subject, StorageNode node, long beginTime, long endTime, int numPoints);
}
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementDataManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementDataManagerBean.java
index 90ed917..09133ae 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementDataManagerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementDataManagerBean.java
@@ -778,7 +778,7 @@ public class MeasurementDataManagerBean implements MeasurementDataManagerLocal,
false);
List<MeasurementDataNumericHighLowComposite> tempList = new ArrayList<MeasurementDataNumericHighLowComposite>();
- for(MeasurementDataNumericHighLowComposite object :metricsManager.findDataForResource(schedule.getId(), beginTime, endTime,numDataPoints) ){
+ for(MeasurementDataNumericHighLowComposite object : metricsManager.findDataForResource(schedule.getId(), beginTime, endTime,numDataPoints) ){
tempList.add(object);
}
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementDataManagerRemote.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementDataManagerRemote.java
index fb50541..116c82a 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementDataManagerRemote.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementDataManagerRemote.java
@@ -112,8 +112,7 @@ public interface MeasurementDataManagerRemote {
*
* @param subject
* @param resourceId
- * @param definitionIds measurement definition id for numeric metric associated with the given compatible
- * group
+ * @param definitionIds measurement definition id for numeric metric associated with the given resource
* @param beginTime
* @param endTime
* @param numPoints
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/storage/StorageClientManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/storage/StorageClientManagerBean.java
index ae80e50..3f1943d 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/storage/StorageClientManagerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/storage/StorageClientManagerBean.java
@@ -96,12 +96,14 @@ public class StorageClientManagerBean {
String password = getRequiredStorageProperty(PASSWORD_PROP);
metricsConfiguration = new MetricsConfiguration();
-
- Session wrappedSession = createSession(username, password, storageNodeManager.getStorageNodes());
- session = new StorageSession(wrappedSession);
-
- session.addStorageStateListener(new StorageClusterMonitor());
-
+ List<StorageNode> storageNodes = storageNodeManager.getStorageNodes();
+ if (storageNodes.isEmpty()) {
+ throw new IllegalStateException(
+ "There is no storage node metadata stored in the relational database. This may have happened as a "
+ + "result of running dbsetup or deleting rows from rhq_storage_node table. Please re-install the "
+ + "storage node to fix this issue.");
+ }
+ session = createSession(username, password, storageNodes);
metricsDAO = new MetricsDAO(session, metricsConfiguration);
Server server = serverManager.getServer();
commit 979ebb45e7b478f83d3cfe3a46c25b0db291a36c
Author: Jirka Kremser <jkremser(a)redhat.com>
Date: Fri Aug 2 13:04:23 2013 +0200
Adding the header next to the "Back to List" clickable arrow. This required to change AbstractTableSection to support additional canvas to save some place on the screen.
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDatasource.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDatasource.java
index b98697b..a7058d7 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDatasource.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDatasource.java
@@ -133,11 +133,11 @@ public class StorageNodeDatasource extends RPCDataSource<StorageNodeLoadComposit
});
fields.add(field);
- fields.add(FIELD_JMX_PORT.getListGridField("90"));
+// fields.add(FIELD_JMX_PORT.getListGridField("90"));
// ListGridField cqlField = FIELD_CQL_PORT.getListGridField("90");
// cqlField.setHidden(true);
// fields.add(cqlField);
-// fields.add(FIELD_OPERATION_MODE.getListGridField("90"));
+ fields.add(FIELD_OPERATION_MODE.getListGridField("90"));
ListGridField createdTimeField = FIELD_CTIME.getListGridField("120");
TimestampCellFormatter.prepareDateField(createdTimeField);
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDetailView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDetailView.java
index 942a184..db0aeee 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDetailView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDetailView.java
@@ -83,13 +83,15 @@ public class StorageNodeDetailView extends EnhancedVLayout implements Bookmarkab
private SectionStackSection detailsAndLoadSection;
private StaticTextItem alertsItem;
private int expandedSection = -1;
+ private HTMLFlow header;
private volatile int initSectionCount = 0;
private int unackAlerts = -1;
- public StorageNodeDetailView(int storageNodeId) {
+ public StorageNodeDetailView(int storageNodeId, HTMLFlow header) {
super();
this.storageNodeId = storageNodeId;
+ this.header = header;
setHeight100();
setWidth100();
setOverflow(Overflow.AUTO);
@@ -102,10 +104,10 @@ public class StorageNodeDetailView extends EnhancedVLayout implements Bookmarkab
// sectionStack.setOverflow(Overflow.VISIBLE);
}
- public StorageNodeDetailView(int storageNodeId, int expandedSection) {
- this(storageNodeId);
- this.expandedSection = expandedSection;
- }
+// public StorageNodeDetailView(int storageNodeId, int expandedSection) {
+// this(storageNodeId);
+// this.expandedSection = expandedSection;
+// }
@Override
protected void onInit() {
@@ -122,6 +124,8 @@ public class StorageNodeDetailView extends EnhancedVLayout implements Bookmarkab
initSectionCount = SECTION_COUNT;
}
final StorageNode node = storageNodes.get(0);
+ header.setContents("<div style='text-align: center; font-weight: bold; font-size: medium;'> Storage Node ("
+ + node.getAddress() + ")</div>");
Resource res = node.getResource();
if (res != null) {
fetchResourceComposite(res.getId());
@@ -254,6 +258,9 @@ public class StorageNodeDetailView extends EnhancedVLayout implements Bookmarkab
final StaticTextItem nameItem = new StaticTextItem(FIELD_ADDRESS.propertyName(), FIELD_ADDRESS.title());
nameItem.setValue("<b>" + storageNode.getAddress() + "</b>");
+ final StaticTextItem cqlPortItem = new StaticTextItem(FIELD_CQL_PORT.propertyName(), FIELD_CQL_PORT.title());
+ cqlPortItem.setValue(storageNode.getCqlPort());
+
final StaticTextItem jmxPortItem = new StaticTextItem(FIELD_JMX_PORT.propertyName(), FIELD_JMX_PORT.title());
jmxPortItem.setValue(storageNode.getJmxPort());
@@ -261,9 +268,6 @@ public class StorageNodeDetailView extends EnhancedVLayout implements Bookmarkab
// MSG.view_adminTopology_storageNode_jmxConnectionUrl());
// jmxConnectionUrlItem.setValue(storageNode.getJMXConnectionURL());
- final StaticTextItem cqlPortItem = new StaticTextItem(FIELD_CQL_PORT.propertyName(), FIELD_CQL_PORT.title());
- cqlPortItem.setValue(storageNode.getCqlPort());
-
final StaticTextItem operationModeItem = new StaticTextItem(FIELD_OPERATION_MODE.propertyName(), MSG.view_adminTopology_serverDetail_operationMode());
operationModeItem.setValue(storageNode.getOperationMode());
@@ -300,7 +304,7 @@ public class StorageNodeDetailView extends EnhancedVLayout implements Bookmarkab
diskStatusItem.setValue("No action needed");
List<FormItem> formItems = new ArrayList<FormItem>(6);
- formItems.addAll(Arrays.asList(nameItem, resourceItem, jmxPortItem, cqlPortItem/*, jmxConnectionUrlItem*/));
+ formItems.addAll(Arrays.asList(nameItem, resourceItem,cqlPortItem, jmxPortItem/*, jmxConnectionUrlItem*/));
if (!CoreGUI.isDebugMode()) formItems.add(operationModeItem); // debug mode fails if this item is added
formItems.addAll(Arrays.asList(installationDateItem, lastUpdateItem, alertsItem, memoryStatusItem, diskStatusItem));
form.setItems(formItems.toArray(new FormItem[]{}));
@@ -355,8 +359,6 @@ public class StorageNodeDetailView extends EnhancedVLayout implements Bookmarkab
initSectionCount++;
}
-
-
@Override
public void renderView(ViewPath viewPath) {
if (viewPath.toString().endsWith("/Config")) {
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeLoadComponent.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeLoadComponent.java
index 556e591..db54108 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeLoadComponent.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeLoadComponent.java
@@ -35,6 +35,8 @@ import com.smartgwt.client.widgets.toolbar.ToolStrip;
import org.rhq.enterprise.gui.coregui.client.CoreGUI;
import org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDatasource.StorageNodeLoadCompositeDatasource;
+import org.rhq.enterprise.gui.coregui.client.gwt.GWTServiceLookup;
+import org.rhq.enterprise.gui.coregui.client.util.MeasurementUtility;
import org.rhq.enterprise.gui.coregui.client.util.enhanced.EnhancedVLayout;
/**
@@ -112,20 +114,9 @@ public class StorageNodeLoadComponent extends EnhancedVLayout {
refreshButton.setExtraSpace(5);
toolStrip.addMember(refreshButton);
- if (parentGrid != null && record != null) {
- IButton closeButton = new IButton(MSG.common_button_close());
- closeButton.addClickHandler(new ClickHandler() {
- public void onClick(ClickEvent event) {
- parentGrid.collapseRecord(record);
- }
- });
- toolStrip.addMember(closeButton);
-
-
- }
loadGrid.setDataSource(datasource);
addMember(loadGrid);
-// addMember(toolStrip);
}
+
}
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeTableView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeTableView.java
index c0fdd85..bb90929 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeTableView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeTableView.java
@@ -35,6 +35,7 @@ import com.smartgwt.client.types.SortDirection;
import com.smartgwt.client.util.BooleanCallback;
import com.smartgwt.client.util.SC;
import com.smartgwt.client.widgets.Canvas;
+import com.smartgwt.client.widgets.HTMLFlow;
import com.smartgwt.client.widgets.grid.CellFormatter;
import com.smartgwt.client.widgets.grid.ListGrid;
import com.smartgwt.client.widgets.grid.ListGridField;
@@ -184,7 +185,9 @@ public class StorageNodeTableView extends TableSection<StorageNodeDatasource> {
@Override
public Canvas getDetailsView(Integer id) {
- return new StorageNodeDetailView(id);
+ HTMLFlow header = new HTMLFlow("id = " + id);
+ setHeader(header);
+ return new StorageNodeDetailView(id, header);
}
private void showCommonActions() {
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/AbstractTableSection.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/AbstractTableSection.java
index a8befa7..cfd097f 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/AbstractTableSection.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/AbstractTableSection.java
@@ -34,6 +34,8 @@ import com.smartgwt.client.widgets.grid.CellFormatter;
import com.smartgwt.client.widgets.grid.ListGrid;
import com.smartgwt.client.widgets.grid.ListGridField;
import com.smartgwt.client.widgets.grid.ListGridRecord;
+import com.smartgwt.client.widgets.layout.HLayout;
+import com.smartgwt.client.widgets.layout.LayoutSpacer;
import com.smartgwt.client.widgets.layout.VLayout;
import org.rhq.enterprise.gui.coregui.client.BookmarkableView;
@@ -46,8 +48,9 @@ import org.rhq.enterprise.gui.coregui.client.components.buttons.BackButton;
import org.rhq.enterprise.gui.coregui.client.util.Log;
import org.rhq.enterprise.gui.coregui.client.util.RPCDataSource;
import org.rhq.enterprise.gui.coregui.client.util.StringUtility;
-import org.rhq.enterprise.gui.coregui.client.util.enhanced.EnhancedVLayout;
+import org.rhq.enterprise.gui.coregui.client.util.enhanced.EnhancedHLayout;
import org.rhq.enterprise.gui.coregui.client.util.enhanced.EnhancedUtility;
+import org.rhq.enterprise.gui.coregui.client.util.enhanced.EnhancedVLayout;
/**
* Provides the typical table view with the additional ability of traversing to a "details" view
@@ -65,6 +68,7 @@ public abstract class AbstractTableSection<DS extends RPCDataSource, ID> extends
private VLayout detailsHolder;
private Canvas detailsView;
+ private Canvas header;
private String basePath;
private boolean escapeHtmlInDetailsLinkColumn;
private boolean initialDisplay;
@@ -388,8 +392,15 @@ public abstract class AbstractTableSection<DS extends RPCDataSource, ID> extends
// Only add the "Back to List" button if the details are definitely not editable, because if they are
// editable, a Cancel button should already be provided by the details view.
BackButton backButton = new BackButton(MSG.view_tableSection_backButton(), basePath);
- detailsHolder.addMember(backButton);
- VLayout verticalSpacer = new EnhancedVLayout();
+ HLayout hlayout = new EnhancedHLayout();
+ hlayout.addMember(backButton);
+ if (header != null) {
+ header.setWidth100();
+ header.setAlign(com.smartgwt.client.types.Alignment.CENTER);
+ hlayout.addMember(header);
+ }
+ detailsHolder.addMember(hlayout);
+ LayoutSpacer verticalSpacer = new LayoutSpacer();
verticalSpacer.setHeight(8);
detailsHolder.addMember(verticalSpacer);
}
@@ -431,5 +442,9 @@ public abstract class AbstractTableSection<DS extends RPCDataSource, ID> extends
}
}
}
+
+ public void setHeader(Canvas header) {
+ this.header = header;
+ }
}
commit 37c0b0dccd4574851c193074f9f7517a6286ec78
Author: Jirka Kremser <jkremser(a)redhat.com>
Date: Thu Jul 25 14:57:37 2013 +0200
squashed commit: UI work
* Another iteration of Storage Node UI: added polling mechanism to fetch the number of unack alerts; new metric (FreeDiskToDataSizeRatio) was added.
* Another iteration of Storage Node UI: changes to storage node detail page; the load table and the details section are next to each other to save some place on the screen; also removed the top label/toolstrip.A
* Another iteration of Storage Node UI: colors and discretication of FreeDiskToDataSizeRatio metric to human readable form.
* Removed unused code, formatting.
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeAdminView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeAdminView.java
index bfdbcc9..7cc2ef1 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeAdminView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeAdminView.java
@@ -52,7 +52,7 @@ import org.rhq.enterprise.gui.coregui.client.util.message.Message;
*
* @author Jirka Kremser
*/
-public class StorageNodeAdminView extends EnhancedVLayout implements HasViewName, BookmarkableView {
+public class StorageNodeAdminView extends EnhancedVLayout implements/* HasViewName,*/ BookmarkableView {
public static final ViewName VIEW_ID = new ViewName("StorageNodes", MSG.view_adminTopology_storageNodes(),
IconEnum.STORAGE_NODE);
@@ -190,9 +190,7 @@ public class StorageNodeAdminView extends EnhancedVLayout implements HasViewName
GWTServiceLookup.getStorageService().findNotAcknowledgedStorageNodeAlertsCount(new AsyncCallback<Integer>() {
@Override
public void onSuccess(Integer result) {
- alerts.setTitle(alerts.getTitle()
- + (result != 0 ? " <font color='#CC0000;'>(" + result + ")</font>" : " (" + result
- + ")"));
+ alerts.setTitle(StorageNodeAdminView.getAlertsString(alerts.getTitle(), result));
schedule(5 * 1000);
}
@@ -205,9 +203,15 @@ public class StorageNodeAdminView extends EnhancedVLayout implements HasViewName
}.run();
}
- @Override
- public ViewName getViewName() {
- return VIEW_ID;
+// @Override
+// public ViewName getViewName() {
+// return VIEW_ID;
+// }
+
+ public static String getAlertsString(String prefix, int numOfUnackAlerts) {
+ return prefix
+ + (numOfUnackAlerts != 0 ? " <font color='#CC0000;'>(" + numOfUnackAlerts + ")</font>" : " ("
+ + numOfUnackAlerts + ")");
}
private static final class TabInfo {
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDatasource.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDatasource.java
index 542afb5..b98697b 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDatasource.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDatasource.java
@@ -31,7 +31,6 @@ import static org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDat
import static org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDatasourceField.FIELD_RESOURCE_ID;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
import com.google.gwt.i18n.client.NumberFormat;
@@ -70,6 +69,10 @@ import org.rhq.enterprise.server.measurement.util.MeasurementUtils;
* @author Jirka Kremser
*/
public class StorageNodeDatasource extends RPCDataSource<StorageNodeLoadComposite, StorageNodeCriteria> {
+ public static final String OK_COLOR = "color: #26aa26;";
+ public static final String WARN_COLOR = "color: #ed9b26;";
+ public static final String DONT_MISS_ME_COLOR = "font-weight: bold; color: #d64949;";
+
// filters
public static final String FILTER_ADDRESS = FIELD_ADDRESS.propertyName();
public static final String FILTER_OPERATION_MODE = FIELD_OPERATION_MODE.propertyName();
@@ -213,38 +216,23 @@ public class StorageNodeDatasource extends RPCDataSource<StorageNodeLoadComposit
}
int value = from.getUnackAlerts();
record.setAttribute(FIELD_ALERTS.propertyName(), "New Alerts"
- + (value != 0 ? " <font color='#CC0000;'>(" + value + ")</font>" : " (" + value + ")"));
+ + (value != 0 ? " <span style='color: #CC0000;'>(" + value + ")</span>" : " (" + value + ")"));
String memory = null;
if (from.getHeapPercentageUsed() != null && from.getHeapPercentageUsed().getAggregate().getAvg() != null)
memory = MeasurementConverterClient.format(from.getHeapPercentageUsed().getAggregate().getAvg(), from
.getHeapPercentageUsed().getUnits(), true);
record.setAttribute(FIELD_MEMORY.propertyName(), memory);
- String disk = from.getFreeDiskToDataSizeRatio() != null ? NumberFormat.getFormat("0.0").format(
- from.getFreeDiskToDataSizeRatio().getAvg()) : MSG.view_measure_nan();
- record.setAttribute(FIELD_DISK.propertyName(), disk);
- return record;
- }
-
-
- private ListGridRecord makeListGridRecord(MeasurementAggregateWithUnits aggregateWithUnits, String name,
- String hover, String id) {
- ListGridRecord record = new ListGridRecord();
- record.setAttribute("id", id);
- record.setAttribute(StorageNodeLoadCompositeDatasourceField.FIELD_NAME.propertyName(), name);
- record.setAttribute(
- StorageNodeLoadCompositeDatasourceField.FIELD_MIN.propertyName(),
- MeasurementConverterClient.format(aggregateWithUnits.getAggregate().getMin(),
- aggregateWithUnits.getUnits(), true));
- record.setAttribute("avgFloat", aggregateWithUnits.getAggregate().getAvg());
- record.setAttribute(
- StorageNodeLoadCompositeDatasourceField.FIELD_AVG.propertyName(),
- MeasurementConverterClient.format(aggregateWithUnits.getAggregate().getAvg(),
- aggregateWithUnits.getUnits(), true));
- record.setAttribute(
- StorageNodeLoadCompositeDatasourceField.FIELD_MAX.propertyName(),
- MeasurementConverterClient.format(aggregateWithUnits.getAggregate().getMax(),
- aggregateWithUnits.getUnits(), true));
- record.setAttribute("hover", hover);
+ if (from.getFreeDiskToDataSizeRatio() != null) {
+ if (from.getFreeDiskToDataSizeRatio().getMax() < 0.7) {
+ record.setAttribute(FIELD_DISK.propertyName(),
+ "<span style='" + DONT_MISS_ME_COLOR + "'>Insufficient</span>");
+ } else if (from.getFreeDiskToDataSizeRatio().getMax() < 1.5) {
+ record.setAttribute(FIELD_DISK.propertyName(), "<span style='" + WARN_COLOR + "'>Warning</span>");
+ } else {
+ record.setAttribute(FIELD_DISK.propertyName(),
+ "<span style='" + OK_COLOR + "'>Sufficient</span>");
+ }
+ }
return record;
}
@@ -349,54 +337,31 @@ public class StorageNodeDatasource extends RPCDataSource<StorageNodeLoadComposit
}
private static void executeFetch(final StorageNode node, final AsyncCallback<StorageNodeLoadComposite> callback) {
- GWTServiceLookup.getStorageService().getLoad(node, 1, MeasurementUtils.UNIT_HOURS, callback);
+ GWTServiceLookup.getStorageService().getLoad(node, 8, MeasurementUtils.UNIT_HOURS, callback);
}
private ListGridRecord[] makeListGridRecords(StorageNodeLoadComposite loadComposite) {
- List<ListGridRecord> recordsList = new ArrayList<ListGridRecord>(6);
- List<List<Object>> loadFields = Arrays
- .<List<Object>> asList(
- Arrays.<Object> asList(loadComposite.getHeapCommitted(), "Heap Maximum",
- "The limit the RHQ storage node was started with. This corresponds with the -Xmx JVM option.",
- "heapMax"),
- Arrays.<Object> asList(loadComposite.getHeapUsed(), "Heap Used",
- "Amount of memory actually used by the RHQ storage node", "heapUsed"),
- Arrays.<Object> asList(loadComposite.getHeapPercentageUsed(), "Heap Percent Used",
- "This value is calculated by dividing Heap Used by Heap Maximum.", HEAP_PERCENTAGE_KEY),
- Arrays.<Object> asList(loadComposite.getLoad(), "Load", "Data stored on the node", "load"),
- Arrays.<Object> asList(
- loadComposite.getDataDiskUsedPercentage(),
- "Data Disk Space Percent Used",
- "Percentage of disk space used by data files on the partitions that contain the data files. If multiple data locations are specified then the aggregate accross all the partitions that contain data files is reported.",
- DATA_DISK_SPACE_PERCENTAGE_KEY),
- Arrays.<Object> asList(
- loadComposite.getTotalDiskUsedPercentage(),
- "Total Disk Space Percent Used",
- "Percentage of total disk space used (system and Storage Node) on the partitions that contain the data files. If multiple data locations are specified then the aggregate accross all the partitions that contain data files is reported.",
- TOTAL_DISK_SPACE_PERCENTAGE_KEY), Arrays.<Object> asList(loadComposite.getDataDiskUsed(),
- "Total Disk Space Used",
- "Total space used on disk by all data files, commit logs, and saved caches.", "totaldisk"),
- Arrays.<Object> asList(loadComposite.getActuallyOwns(), "Ownership",
- "Refers to the percentage of keys that a node owns.", "ownership"));
- for (List<Object> aggregateWithUnitsList : loadFields) {
- if (aggregateWithUnitsList.get(0) != null) {
- recordsList.add(makeListGridRecord((MeasurementAggregateWithUnits) aggregateWithUnitsList.get(0),
- (String) aggregateWithUnitsList.get(1), (String) aggregateWithUnitsList.get(2),
- (String) aggregateWithUnitsList.get(3)));
- }
- }
- if (loadComposite.getTokens() != null) {
- ListGridRecord tokens = new ListGridRecord();
- tokens.setAttribute("id", "tokens");
- tokens.setAttribute("name", "Number of Tokens");
- tokens.setAttribute("hover", "Number of partitions of the ring that a node owns.");
- tokens.setAttribute("min", loadComposite.getTokens().getMin());
- tokens.setAttribute("avg", loadComposite.getTokens().getAvg());
- tokens.setAttribute("max", loadComposite.getTokens().getMax());
- recordsList.add(tokens);
- }
-
+ List<ListGridRecord> recordsList = new ArrayList<ListGridRecord>(6) {
+ private static final long serialVersionUID = 1L;
+ @Override
+ public boolean add(ListGridRecord record) {
+ if (record != null)
+ return super.add(record);
+ return false;
+ }
+ };
+
+ // heap related metrics
+// recordsList.add(makeListGridRecord(loadComposite.getHeapCommitted(), "Heap Maximum", "The limit the RHQ storage node was started with. This corresponds with the -Xmx JVM option.", "heapMax"));
+ recordsList.add(makeListGridRecord(loadComposite.getHeapUsed(), "Heap Used", "Amount of memory actually used by the RHQ storage node", "heapUsed"));
+ recordsList.add(makeListGridRecord(loadComposite.getHeapPercentageUsed(), "Heap Percent Used", "This value is calculated by dividing Heap Used by Heap Maximum.", HEAP_PERCENTAGE_KEY));
+
+ // disk related metrics
+ recordsList.add(makeListGridRecord(loadComposite.getDataDiskUsed(), "Total Disk Space Used", "Total space used on disk by all data files, commit logs, and saved caches.", "totaldisk"));
+ recordsList.add(makeListGridRecord(loadComposite.getTotalDiskUsedPercentage(),"Total Disk Space Percent Used", "Percentage of total disk space used (system and Storage Node) on the partitions that contain the data files. If multiple data locations are specified then the aggregate accross all the partitions that contain data files is reported.", TOTAL_DISK_SPACE_PERCENTAGE_KEY));
+ recordsList.add(makeListGridRecord(loadComposite.getDataDiskUsedPercentage(), "Data Disk Space Percent Used","Percentage of disk space used by data files on the partitions that contain the data files. If multiple data locations are specified then the aggregate accross all the partitions that contain data files is reported.", DATA_DISK_SPACE_PERCENTAGE_KEY));
+
if (loadComposite.getFreeDiskToDataSizeRatio() != null){
MeasurementAggregate aggregate = loadComposite.getFreeDiskToDataSizeRatio();
NumberFormat nf = NumberFormat.getFormat("0.0");
@@ -408,9 +373,22 @@ public class StorageNodeDatasource extends RPCDataSource<StorageNodeLoadComposit
record.setAttribute("avg", nf.format(aggregate.getAvg()));
record.setAttribute("avgFloat", aggregate.getAvg());
record.setAttribute("max", nf.format(aggregate.getMax()));
-
recordsList.add(record);
}
+// recordsList.add(makeListGridRecord(loadComposite.getLoad(), "Load", "Data stored on the node", "load"));
+
+ // other metrics
+ recordsList.add(makeListGridRecord(loadComposite.getActuallyOwns(), "Ownership", "Refers to the percentage of keys that a node owns.", "ownership"));
+ if (loadComposite.getTokens() != null) {
+ ListGridRecord tokens = new ListGridRecord();
+ tokens.setAttribute("id", "tokens");
+ tokens.setAttribute("name", "Number of Tokens");
+ tokens.setAttribute("hover", "Number of partitions of the ring that a node owns.");
+ tokens.setAttribute("min", loadComposite.getTokens().getMin());
+ tokens.setAttribute("avg", loadComposite.getTokens().getAvg());
+ tokens.setAttribute("max", loadComposite.getTokens().getMax());
+ recordsList.add(tokens);
+ }
ListGridRecord[] records = recordsList.toArray(new ListGridRecord[recordsList.size()]);
return records;
@@ -418,6 +396,7 @@ public class StorageNodeDatasource extends RPCDataSource<StorageNodeLoadComposit
private ListGridRecord makeListGridRecord(MeasurementAggregateWithUnits aggregateWithUnits, String name,
String hover, String id) {
+ if (aggregateWithUnits == null) return null;
ListGridRecord record = new ListGridRecord();
record.setAttribute("id", id);
record.setAttribute(StorageNodeLoadCompositeDatasourceField.FIELD_NAME.propertyName(), name);
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDetailView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDetailView.java
index f6f08b4..942a184 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDetailView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDetailView.java
@@ -20,6 +20,7 @@
package org.rhq.enterprise.gui.coregui.client.admin.storage;
import static org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDatasourceField.FIELD_ADDRESS;
+import static org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDatasourceField.FIELD_ALERTS;
import static org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDatasourceField.FIELD_CQL_PORT;
import static org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDatasourceField.FIELD_CTIME;
import static org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDatasourceField.FIELD_JMX_PORT;
@@ -34,18 +35,15 @@ import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.smartgwt.client.types.Overflow;
import com.smartgwt.client.types.VisibilityMode;
-import com.smartgwt.client.util.SC;
-import com.smartgwt.client.widgets.IButton;
-import com.smartgwt.client.widgets.events.ClickEvent;
-import com.smartgwt.client.widgets.events.ClickHandler;
+import com.smartgwt.client.widgets.HTMLFlow;
import com.smartgwt.client.widgets.form.DynamicForm;
import com.smartgwt.client.widgets.form.fields.FormItem;
import com.smartgwt.client.widgets.form.fields.StaticTextItem;
+import com.smartgwt.client.widgets.layout.LayoutSpacer;
import com.smartgwt.client.widgets.layout.SectionStack;
import com.smartgwt.client.widgets.layout.SectionStackSection;
import org.rhq.core.domain.cloud.StorageNode;
-import org.rhq.core.domain.cloud.StorageNode.OperationMode;
import org.rhq.core.domain.criteria.ResourceCriteria;
import org.rhq.core.domain.criteria.StorageNodeCriteria;
import org.rhq.core.domain.resource.Resource;
@@ -62,7 +60,7 @@ import org.rhq.enterprise.gui.coregui.client.inventory.resource.detail.configura
import org.rhq.enterprise.gui.coregui.client.inventory.resource.detail.operation.history.ResourceOperationHistoryListView;
import org.rhq.enterprise.gui.coregui.client.util.Log;
import org.rhq.enterprise.gui.coregui.client.util.StringUtility;
-import org.rhq.enterprise.gui.coregui.client.util.enhanced.EnhancedToolStrip;
+import org.rhq.enterprise.gui.coregui.client.util.enhanced.EnhancedHLayout;
import org.rhq.enterprise.gui.coregui.client.util.enhanced.EnhancedVLayout;
import org.rhq.enterprise.gui.coregui.client.util.message.Message;
@@ -77,12 +75,17 @@ public class StorageNodeDetailView extends EnhancedVLayout implements Bookmarkab
private static final int SECTION_COUNT = 3;
private final SectionStack sectionStack;
- private SectionStackSection detailsSection;
- private SectionStackSection loadSection;
- private SectionStackSection historySection;
+ private EnhancedVLayout detailsLayout;
+ private EnhancedHLayout detailsAndLoadLayout;
+ private EnhancedVLayout loadLayout;
+ private SectionStackSection configurationSection;
+ private SectionStackSection operationSection;
+ private SectionStackSection detailsAndLoadSection;
+ private StaticTextItem alertsItem;
private int expandedSection = -1;
private volatile int initSectionCount = 0;
+ private int unackAlerts = -1;
public StorageNodeDetailView(int storageNodeId) {
super();
@@ -95,8 +98,8 @@ public class StorageNodeDetailView extends EnhancedVLayout implements Bookmarkab
sectionStack.setVisibilityMode(VisibilityMode.MULTIPLE);
sectionStack.setWidth100();
sectionStack.setHeight100();
- sectionStack.setMargin(5);
- sectionStack.setOverflow(Overflow.VISIBLE);
+// sectionStack.setMargin(5);
+// sectionStack.setOverflow(Overflow.VISIBLE);
}
public StorageNodeDetailView(int storageNodeId, int expandedSection) {
@@ -121,7 +124,7 @@ public class StorageNodeDetailView extends EnhancedVLayout implements Bookmarkab
final StorageNode node = storageNodes.get(0);
Resource res = node.getResource();
if (res != null) {
- fetchResourceComposite(node.getResource().getId());
+ fetchResourceComposite(res.getId());
} else {
// skip this if the resource id is not there
initSectionCount++;
@@ -137,6 +140,7 @@ public class StorageNodeDetailView extends EnhancedVLayout implements Bookmarkab
initSectionCount = SECTION_COUNT;
}
});
+ fetchUnackAlerts(storageNodeId);
}
private void fetchResourceComposite(final int resourceId) {
@@ -156,7 +160,6 @@ public class StorageNodeDetailView extends EnhancedVLayout implements Bookmarkab
public void onSuccess(PageList<ResourceComposite> result) {
if (result.isEmpty()) {
onFailure(new Exception("Resource with id [" + resourceId + "] does not exist."));
- initSectionCount = SECTION_COUNT;
} else {
final ResourceComposite resourceComposite = result.get(0);
// prepareOperationHistory(resourceComposite);
@@ -166,6 +169,31 @@ public class StorageNodeDetailView extends EnhancedVLayout implements Bookmarkab
}
});
}
+
+ private void fetchUnackAlerts(final int storageNodeId) {
+ GWTServiceLookup.getStorageService().findNotAcknowledgedStorageNodeAlertsCounts(Arrays.asList(storageNodeId),
+ new AsyncCallback<List<Integer>>() {
+ @Override
+ public void onFailure(Throwable caught) {
+ Message message = new Message(MSG.view_inventory_resource_loadFailed(String.valueOf(storageNodeId)),
+ Message.Severity.Warning);
+ CoreGUI.goToView(InventoryView.VIEW_ID.getName(), message);
+ initSectionCount = SECTION_COUNT;
+ }
+
+ @Override
+ public void onSuccess(List<Integer> result) {
+ if (result.isEmpty()) {
+ onFailure(new Exception("Resource with id [" + storageNodeId + "] does not exist."));
+ } else {
+ unackAlerts = result.get(0);
+ if (alertsItem != null) {
+ alertsItem.setValue(StorageNodeAdminView.getAlertsString("New Alerts", unackAlerts));
+ }
+ }
+ }
+ });
+ }
public boolean isInitialized() {
return initSectionCount >= SECTION_COUNT;
@@ -182,14 +210,18 @@ public class StorageNodeDetailView extends EnhancedVLayout implements Bookmarkab
public void run() {
if (isInitialized()) {
- if (null != detailsSection) {
- sectionStack.addSection(detailsSection);
- }
- if (null != loadSection) {
- sectionStack.addSection(loadSection);
+ if (null != detailsAndLoadLayout) {
+ LayoutSpacer spacer = new LayoutSpacer();
+ spacer.setWidth(30);
+ detailsAndLoadLayout.setMembers(detailsLayout, spacer, loadLayout);
+ detailsAndLoadLayout.setHeight(220);
+ detailsAndLoadSection = new SectionStackSection("Storage Node Information");
+ detailsAndLoadSection.setExpanded(true);
+ detailsAndLoadSection.setItems(detailsAndLoadLayout);
+ sectionStack.addSection(detailsAndLoadSection);
}
- if (null != historySection) {
- sectionStack.addSection(historySection);
+ if (null != configurationSection) {
+ sectionStack.addSection(configurationSection);
}
// if (expandedSection != -1) {
// for (int i = 1; i < SECTION_COUNT; i++) {
@@ -222,13 +254,12 @@ public class StorageNodeDetailView extends EnhancedVLayout implements Bookmarkab
final StaticTextItem nameItem = new StaticTextItem(FIELD_ADDRESS.propertyName(), FIELD_ADDRESS.title());
nameItem.setValue("<b>" + storageNode.getAddress() + "</b>");
-// final TextItem jmxPortItem = new TextItem(FIELD_JMX_PORT.propertyName(), FIELD_JMX_PORT.title());
final StaticTextItem jmxPortItem = new StaticTextItem(FIELD_JMX_PORT.propertyName(), FIELD_JMX_PORT.title());
jmxPortItem.setValue(storageNode.getJmxPort());
- final StaticTextItem jmxConnectionUrlItem = new StaticTextItem("jmxConnectionUrl",
- MSG.view_adminTopology_storageNode_jmxConnectionUrl());
- jmxConnectionUrlItem.setValue(storageNode.getJMXConnectionURL());
+// final StaticTextItem jmxConnectionUrlItem = new StaticTextItem("jmxConnectionUrl",
+// MSG.view_adminTopology_storageNode_jmxConnectionUrl());
+// jmxConnectionUrlItem.setValue(storageNode.getJMXConnectionURL());
final StaticTextItem cqlPortItem = new StaticTextItem(FIELD_CQL_PORT.propertyName(), FIELD_CQL_PORT.title());
cqlPortItem.setValue(storageNode.getCqlPort());
@@ -256,47 +287,50 @@ public class StorageNodeDetailView extends EnhancedVLayout implements Bookmarkab
StaticTextItem lastUpdateItem = new StaticTextItem(FIELD_MTIME.propertyName(), FIELD_MTIME.title());
lastUpdateItem.setValue(TimestampCellFormatter.format(Long.valueOf(storageNode.getMtime()),
TimestampCellFormatter.DATE_TIME_FORMAT_LONG));
-
- IButton saveButton = new IButton();
- saveButton.setOverflow(Overflow.VISIBLE);
- saveButton.setTitle(MSG.common_button_save());
- saveButton.addClickHandler(new ClickHandler() {
- public void onClick(ClickEvent event) {
- if (form.validate()) {
-// storageNode.setOperationMode(OperationMode.valueOf(operationModeItem.getValueAsString()));
- storageNode.setOperationMode(OperationMode.valueOf((String) operationModeItem.getValue()));
- SC.say(storageNode.toString());
- // TODO: logic
- }
- }
- });
- List<FormItem> formItems = new ArrayList<FormItem>(8);
- formItems.addAll(Arrays.asList(nameItem, jmxPortItem, cqlPortItem, jmxConnectionUrlItem));
+
+ alertsItem = new StaticTextItem(FIELD_ALERTS.propertyName(), FIELD_ALERTS.title());
+ if (unackAlerts != -1) {
+ alertsItem.setValue(StorageNodeAdminView.getAlertsString("New Alerts", unackAlerts));
+ }
+
+ StaticTextItem memoryStatusItem = new StaticTextItem("memoryStatus", "Memory");
+ memoryStatusItem.setValue("No action needed");
+
+ StaticTextItem diskStatusItem = new StaticTextItem("mdiskStatus", "Disk");
+ diskStatusItem.setValue("No action needed");
+
+ List<FormItem> formItems = new ArrayList<FormItem>(6);
+ formItems.addAll(Arrays.asList(nameItem, resourceItem, jmxPortItem, cqlPortItem/*, jmxConnectionUrlItem*/));
if (!CoreGUI.isDebugMode()) formItems.add(operationModeItem); // debug mode fails if this item is added
- formItems.addAll(Arrays.asList(resourceItem, installationDateItem, lastUpdateItem));
+ formItems.addAll(Arrays.asList(installationDateItem, lastUpdateItem, alertsItem, memoryStatusItem, diskStatusItem));
form.setItems(formItems.toArray(new FormItem[]{}));
-
- EnhancedToolStrip footer = new EnhancedToolStrip();
- footer.setPadding(5);
- footer.setWidth100();
- footer.setMembersMargin(15);
- footer.addMember(saveButton);
-
- SectionStackSection section = new SectionStackSection(MSG.common_title_details());
- section.setExpanded(expandedSection != -1 ? expandedSection == 0 : true);
- section.setItems(form);
- detailsSection = section;
+ detailsLayout = new EnhancedVLayout();
+ detailsLayout.setWidth(450);
+ detailsLayout.addMember(form);
+ if (detailsAndLoadLayout == null) {
+ detailsAndLoadLayout = new EnhancedHLayout(0);
+ }
initSectionCount++;
}
private void prepareLoadSection(SectionStack stack, final StorageNode storageNode) {
StorageNodeLoadComponent loadDataComponent = new StorageNodeLoadComponent(storageNode.getId());
- SectionStackSection section = new SectionStackSection("Load");
- section.setItems(loadDataComponent);
- section.setExpanded(expandedSection != -1 ? expandedSection == 1 : true);
-
- loadSection = section;
+ loadDataComponent.setExtraSpace(5);
+ loadLayout = new EnhancedVLayout();
+ loadLayout.setWidth100();
+ LayoutSpacer spacer = new LayoutSpacer();
+ spacer.setHeight(10);
+// HTMLFlow loadLabel = new HTMLFlow("<span style='font-weight:bold'>Status</span>");
+ HTMLFlow loadLabel = new HTMLFlow("Status");
+ loadLabel.addStyleName("formTitle");
+ loadLabel.setTooltip("Contains selected metrics collected for last 8 hours.");
+ loadLabel.setHoverWidth(300);
+ loadLayout.setMembers(spacer, loadLabel, loadDataComponent);
+
+ if (detailsAndLoadLayout == null) {
+ detailsAndLoadLayout = new EnhancedHLayout();
+ }
initSectionCount++;
}
@@ -306,7 +340,7 @@ public class StorageNodeDetailView extends EnhancedVLayout implements Bookmarkab
section.setItems(historyView);
section.setExpanded(false);
- historySection = section;
+ operationSection = section;
initSectionCount++;
}
@@ -314,9 +348,10 @@ public class StorageNodeDetailView extends EnhancedVLayout implements Bookmarkab
ResourceConfigurationEditView editorView = new ResourceConfigurationEditView(resourceComposite);
SectionStackSection section = new SectionStackSection("Configuration");
section.setItems(editorView);
- section.setExpanded(expandedSection != -1 && expandedSection == 2);
+ section.setExpanded(true);
+ section.setCanCollapse(false);
- historySection = section;
+ configurationSection = section;
initSectionCount++;
}
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeLoadComponent.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeLoadComponent.java
index eddca2f..556e591 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeLoadComponent.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeLoadComponent.java
@@ -18,8 +18,13 @@
*/
package org.rhq.enterprise.gui.coregui.client.admin.storage;
+import static org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDatasource.DONT_MISS_ME_COLOR;
+import static org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDatasource.OK_COLOR;
+import static org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDatasource.WARN_COLOR;
+
import java.util.List;
+import com.smartgwt.client.types.Autofit;
import com.smartgwt.client.widgets.IButton;
import com.smartgwt.client.widgets.events.ClickEvent;
import com.smartgwt.client.widgets.events.ClickHandler;
@@ -39,9 +44,6 @@ import org.rhq.enterprise.gui.coregui.client.util.enhanced.EnhancedVLayout;
*/
public class StorageNodeLoadComponent extends EnhancedVLayout {
private final ListGrid loadGrid;
- private static final String OK_COLOR = "color:#26aa26;";
- private static final String WARN_COLOR = "color:#ed9b26;";
- private static final String DONT_MISS_ME_COLOR = "font-weight:bold; color:#d64949;";
public StorageNodeLoadComponent(int storageNodeId) {
this(storageNodeId, null, null);
@@ -65,10 +67,10 @@ public class StorageNodeLoadComponent extends EnhancedVLayout {
} else {
return OK_COLOR;
}
- } else if ("avg".equals(getFieldName(colNum))
+ } else if ("max".equals(getFieldName(colNum))
&& StorageNodeLoadCompositeDatasource.FREE_DISK_TO_DATA_SIZE_RATIO_KEY.equals(record
.getAttribute("id"))) {
- if (record.getAttributeAsFloat("avgFloat") < 1) {
+ if (record.getAttributeAsFloat("avgFloat") < .7) {
return DONT_MISS_ME_COLOR;
} else if (record.getAttributeAsFloat("avgFloat") < 1.5) {
return WARN_COLOR;
@@ -82,7 +84,8 @@ public class StorageNodeLoadComponent extends EnhancedVLayout {
}
};
loadGrid.setWidth100();
- loadGrid.setHeight(230);
+ loadGrid.setHeight(200);
+ loadGrid.setAutoFitData(Autofit.VERTICAL);
StorageNodeLoadCompositeDatasource datasource = StorageNodeLoadCompositeDatasource.getInstance(storageNodeId);
List<ListGridField> fields = datasource.getListGridFields();
loadGrid.setFields(fields.toArray(new ListGridField[fields.size()]));
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeTableView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeTableView.java
index 3370c87..c0fdd85 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeTableView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeTableView.java
@@ -151,9 +151,8 @@ public class StorageNodeTableView extends TableSection<StorageNodeDatasource> {
public void onSuccess(List<Integer> result) {
for (int i = 0; i < records.length; i++) {
int value = result.get(i);
- records[i].setAttribute(FIELD_ALERTS.propertyName(), "New Alerts"
- + (value != 0 ? " <font color='#CC0000;'>(" + value + ")</font>" : " (" + value
- + ")"));
+ records[i].setAttribute(FIELD_ALERTS.propertyName(),
+ StorageNodeAdminView.getAlertsString("New Alerts", value));
listGrid.setData(records);
}
schedule(10 * 1000);
commit 495c35d7681ba12df56c7500bb110caf19fc4aff
Author: Jirka Kremser <jkremser(a)redhat.com>
Date: Mon Jul 29 14:38:14 2013 +0200
squashed commit: If there is just one group definition in
ConfigurationEditor, normal form is used instead SectionStack component.
If there are more than 3 items the combo-box component is used (instead
5).
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/configuration/ConfigurationEditor.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/configuration/ConfigurationEditor.java
index 02d25eb..4423623 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/configuration/ConfigurationEditor.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/configuration/ConfigurationEditor.java
@@ -427,8 +427,8 @@ public class ConfigurationEditor extends EnhancedVLayout {
layout.addMember(form);
}
if (groupDefinitions.size() == 1) {
- propertyDefinitions.addAll(configurationDefinition.getPropertiesInGroup(groupDefinitions.get(0)
- .getName()));
+ propertyDefinitions = new ArrayList<PropertyDefinition>(
+ configurationDefinition.getPropertiesInGroup(groupDefinitions.get(0).getName()));
DynamicForm groupForm = buildPropertiesForm(propertyDefinitions, configuration);
groupForm.setIsGroup(true);
groupForm.setGroupTitle(groupDefinitions.get(0).getDisplayName());
@@ -454,10 +454,10 @@ public class ConfigurationEditor extends EnhancedVLayout {
sectionStack.addSection(buildGroupSection(definition));
}
- if (groupDefinitions.size() > 1) {
+// if (groupDefinitions.size() > 1) {
this.toolStrip = buildToolStrip(layout, sectionStack);
layout.addMember(toolStrip);
- }
+// }
layout.addMember(sectionStack);
}
@@ -1331,7 +1331,7 @@ public class ConfigurationEditor extends EnhancedVLayout {
valueItem = new ComboBoxItem();
((ComboBoxItem) valueItem).setAddUnknownValues(true);
} else {
- if (valueOptions.size() > 5) {
+ if (valueOptions.size() > 3) {
valueItem = new SelectItem();
} else {
valueItem = new RadioGroupItem();
commit 527a00bdbf6851edea11e547d30945985144ac3e
Author: Jirka Kremser <jkremser(a)redhat.com>
Date: Thu Jul 25 14:57:37 2013 +0200
Another iteration of Storage Node UI: added polling mechanism to fetch the number of unack alerts; new metric (FreeDiskToDataSizeRatio) was added.
diff --git a/modules/core/domain/src/main/java/org/rhq/core/domain/cloud/StorageNodeLoadComposite.java b/modules/core/domain/src/main/java/org/rhq/core/domain/cloud/StorageNodeLoadComposite.java
index 2c0b8f8..e00a25c 100644
--- a/modules/core/domain/src/main/java/org/rhq/core/domain/cloud/StorageNodeLoadComposite.java
+++ b/modules/core/domain/src/main/java/org/rhq/core/domain/cloud/StorageNodeLoadComposite.java
@@ -36,6 +36,7 @@ public class StorageNodeLoadComposite implements Serializable {
private StorageNode storageNode;
private long beginTime;
private long endTime;
+ private int unackAlerts;
private MeasurementAggregateWithUnits heapCommitted;
private MeasurementAggregateWithUnits heapUsed;
@@ -84,6 +85,14 @@ public class StorageNodeLoadComposite implements Serializable {
this.endTime = endTime;
}
+ public int getUnackAlerts() {
+ return unackAlerts;
+ }
+
+ public void setUnackAlerts(int unackAlerts) {
+ this.unackAlerts = unackAlerts;
+ }
+
/**
* @return heapCommitted A computed metric for the amount of memory that is committed for the JVM to use.
*/
@@ -219,14 +228,12 @@ public class StorageNodeLoadComposite implements Serializable {
this.actuallyOwns = actuallyOwns;
}
- /* (non-Javadoc)
- * @see java.lang.Object#toString()
- */
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("storageNode.addresss=").append(storageNode.getAddress()).append(", ");
builder.append("beginTime=").append(beginTime).append(", ");
- builder.append("heapCommitted=").append(heapCommitted).append(", ");
+ builder.append("beginTime=").append(beginTime).append(", ");
+ builder.append("unackAlerts=").append(unackAlerts).append(", ");
builder.append("heapUsed=").append(heapUsed).append(", ");
builder.append("heapPercentageUsed=").append(heapPercentageUsed).append(", ");
builder.append("load=").append(load).append(", ");
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeAdminView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeAdminView.java
index 31378f1..bfdbcc9 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeAdminView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeAdminView.java
@@ -106,7 +106,7 @@ public class StorageNodeAdminView extends EnhancedVLayout implements HasViewName
}
});
- tabset.setTabs(table, settings, alerts, backup);
+ tabset.setTabs(table, settings, alerts/*, backup*/);
addMember(tabset);
}
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDatasource.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDatasource.java
index e9e81f3..542afb5 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDatasource.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDatasource.java
@@ -19,6 +19,7 @@
package org.rhq.enterprise.gui.coregui.client.admin.storage;
import static org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDatasourceField.FIELD_ADDRESS;
+import static org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDatasourceField.FIELD_ALERTS;
import static org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDatasourceField.FIELD_CQL_PORT;
import static org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDatasourceField.FIELD_CTIME;
import static org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDatasourceField.FIELD_DISK;
@@ -33,6 +34,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.smartgwt.client.data.DSRequest;
import com.smartgwt.client.data.DSResponse;
@@ -72,7 +74,7 @@ public class StorageNodeDatasource extends RPCDataSource<StorageNodeLoadComposit
public static final String FILTER_ADDRESS = FIELD_ADDRESS.propertyName();
public static final String FILTER_OPERATION_MODE = FIELD_OPERATION_MODE.propertyName();
private static StorageNodeDatasource instance;
-
+
private StorageNodeDatasource() {
super();
setID("storageNode");
@@ -105,33 +107,38 @@ public class StorageNodeDatasource extends RPCDataSource<StorageNodeLoadComposit
fields.add(idField);
fields.add(FIELD_ADDRESS.getListGridField("*"));
- fields.add(FIELD_JMX_PORT.getListGridField("90"));
- ListGridField cqlField = FIELD_CQL_PORT.getListGridField("90");
- cqlField.setHidden(true);
- fields.add(cqlField);
- fields.add(FIELD_OPERATION_MODE.getListGridField("90"));
+ fields.add(FIELD_ALERTS.getListGridField("120"));
- ListGridField createdTimeField = FIELD_CTIME.getListGridField("120");
- TimestampCellFormatter.prepareDateField(createdTimeField);
- fields.add(createdTimeField);
-
- ListGridField field = FIELD_MEMORY.getListGridField("90");
+ ListGridField field = FIELD_MEMORY.getListGridField("120");
field.setShowHover(true);
field.setHoverCustomizer(new HoverCustomizer() {
public String hoverHTML(Object value, ListGridRecord record, int rowNum, int colNum) {
- return "Average memory taken for last one hour.";
+ return "Average memory taken for last 8 hours.";
}
});
fields.add(field);
-
- field = FIELD_DISK.getListGridField("90");
+
+ field = FIELD_DISK.getListGridField("120");
field.setShowHover(true);
field.setHoverCustomizer(new HoverCustomizer() {
public String hoverHTML(Object value, ListGridRecord record, int rowNum, int colNum) {
- return "Average disk space taken for last one hour.";
+ return "Average disk Ratio of (Free Disk)/(Data File Size) for last 8 hours. A value below 1 is not "
+ + "recommended since a compaction or repair process could double the amount of disk "
+ + "space used by data files. If multiple data locations are specified then the "
+ + "aggregate accross all the partitions that contain data files is reported.";
}
});
fields.add(field);
+
+ fields.add(FIELD_JMX_PORT.getListGridField("90"));
+// ListGridField cqlField = FIELD_CQL_PORT.getListGridField("90");
+// cqlField.setHidden(true);
+// fields.add(cqlField);
+// fields.add(FIELD_OPERATION_MODE.getListGridField("90"));
+
+ ListGridField createdTimeField = FIELD_CTIME.getListGridField("120");
+ TimestampCellFormatter.prepareDateField(createdTimeField);
+ fields.add(createdTimeField);
ListGridField resourceIdField = FIELD_RESOURCE_ID.getListGridField("120");
// resourceIdField.setHidden(true);
@@ -204,11 +211,16 @@ public class StorageNodeDatasource extends RPCDataSource<StorageNodeLoadComposit
record.setAttribute(FIELD_RESOURCE_ID.propertyName(), node.getResource().getId());
}
}
- String memory = MeasurementConverterClient.format(from.getHeapPercentageUsed().getAggregate().getAvg(),
- from.getHeapPercentageUsed().getUnits(), true);
+ int value = from.getUnackAlerts();
+ record.setAttribute(FIELD_ALERTS.propertyName(), "New Alerts"
+ + (value != 0 ? " <font color='#CC0000;'>(" + value + ")</font>" : " (" + value + ")"));
+ String memory = null;
+ if (from.getHeapPercentageUsed() != null && from.getHeapPercentageUsed().getAggregate().getAvg() != null)
+ memory = MeasurementConverterClient.format(from.getHeapPercentageUsed().getAggregate().getAvg(), from
+ .getHeapPercentageUsed().getUnits(), true);
record.setAttribute(FIELD_MEMORY.propertyName(), memory);
- String disk = MeasurementConverterClient.format(from.getPartitionDiskUsedPercentage().getAggregate().getAvg(),
- from.getPartitionDiskUsedPercentage().getUnits(), true);
+ String disk = from.getFreeDiskToDataSizeRatio() != null ? NumberFormat.getFormat("0.0").format(
+ from.getFreeDiskToDataSizeRatio().getAvg()) : MSG.view_measure_nan();
record.setAttribute(FIELD_DISK.propertyName(), disk);
return record;
}
@@ -258,6 +270,8 @@ public class StorageNodeDatasource extends RPCDataSource<StorageNodeLoadComposit
public static final String HEAP_PERCENTAGE_KEY = "heapPercentage";
public static final String DATA_DISK_SPACE_PERCENTAGE_KEY = "dataDiskSpacePercentage";
public static final String TOTAL_DISK_SPACE_PERCENTAGE_KEY = "totalDiskSpacePercentage";
+ public static final String FREE_DISK_TO_DATA_SIZE_RATIO_KEY = "freeDiskToDataSizeRatio";
+
private int id;
public static StorageNodeLoadCompositeDatasource getInstance(int id) {
@@ -359,14 +373,11 @@ public class StorageNodeDatasource extends RPCDataSource<StorageNodeLoadComposit
loadComposite.getTotalDiskUsedPercentage(),
"Total Disk Space Percent Used",
"Percentage of total disk space used (system and Storage Node) on the partitions that contain the data files. If multiple data locations are specified then the aggregate accross all the partitions that contain data files is reported.",
- TOTAL_DISK_SPACE_PERCENTAGE_KEY),
- Arrays.<Object> asList(
- loadComposite.getDataDiskUsed(),
+ TOTAL_DISK_SPACE_PERCENTAGE_KEY), Arrays.<Object> asList(loadComposite.getDataDiskUsed(),
"Total Disk Space Used",
- "Total space used on disk by all data files, commit logs, and saved caches.",
- "totaldisk"),
- Arrays.<Object> asList(loadComposite.getActuallyOwns(),
- "Ownership", "Refers to the percentage of keys that a node owns.", "ownership"));
+ "Total space used on disk by all data files, commit logs, and saved caches.", "totaldisk"),
+ Arrays.<Object> asList(loadComposite.getActuallyOwns(), "Ownership",
+ "Refers to the percentage of keys that a node owns.", "ownership"));
for (List<Object> aggregateWithUnitsList : loadFields) {
if (aggregateWithUnitsList.get(0) != null) {
recordsList.add(makeListGridRecord((MeasurementAggregateWithUnits) aggregateWithUnitsList.get(0),
@@ -388,14 +399,15 @@ public class StorageNodeDatasource extends RPCDataSource<StorageNodeLoadComposit
if (loadComposite.getFreeDiskToDataSizeRatio() != null){
MeasurementAggregate aggregate = loadComposite.getFreeDiskToDataSizeRatio();
-
+ NumberFormat nf = NumberFormat.getFormat("0.0");
ListGridRecord record = new ListGridRecord();
- record.setAttribute("id", "freeDiskToDataSizeRatio");
+ record.setAttribute("id", FREE_DISK_TO_DATA_SIZE_RATIO_KEY);
record.setAttribute("name", "Free Disk To Data Size Ratio");
record.setAttribute("hover", "Ratio of (Free Disk)/(Data File Size). A value below 1 is not recommended since a compaction or repair process could double the amount of disk space used by data files. If multiple data locations are specified then the aggregate accross all the partitions that contain data files is reported.");
- record.setAttribute("min", aggregate.getMin());
- record.setAttribute("avg", aggregate.getAvg());
- record.setAttribute("max", aggregate.getMax());
+ record.setAttribute("min", nf.format(aggregate.getMin()));
+ record.setAttribute("avg", nf.format(aggregate.getAvg()));
+ record.setAttribute("avgFloat", aggregate.getAvg());
+ record.setAttribute("max", nf.format(aggregate.getMax()));
recordsList.add(record);
}
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDatasourceField.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDatasourceField.java
index ca69076..19ba5ee 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDatasourceField.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDatasourceField.java
@@ -34,6 +34,8 @@ public enum StorageNodeDatasourceField {
FIELD_JMX_PORT("jmxPort", "JMX Port"),
+ FIELD_ALERTS("alerts", "Alerts"),
+
FIELD_CQL_PORT("cqlPort", "CQL Port"),
FIELD_OPERATION_MODE("operationMode", CoreGUI.getMessages().view_adminTopology_server_mode()),
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeLoadComponent.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeLoadComponent.java
index b0522b1..eddca2f 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeLoadComponent.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeLoadComponent.java
@@ -39,6 +39,9 @@ import org.rhq.enterprise.gui.coregui.client.util.enhanced.EnhancedVLayout;
*/
public class StorageNodeLoadComponent extends EnhancedVLayout {
private final ListGrid loadGrid;
+ private static final String OK_COLOR = "color:#26aa26;";
+ private static final String WARN_COLOR = "color:#ed9b26;";
+ private static final String DONT_MISS_ME_COLOR = "font-weight:bold; color:#d64949;";
public StorageNodeLoadComponent(int storageNodeId) {
this(storageNodeId, null, null);
@@ -51,28 +54,40 @@ public class StorageNodeLoadComponent extends EnhancedVLayout {
loadGrid = new ListGrid() {
@Override
protected String getCellCSSText(ListGridRecord record, int rowNum, int colNum) {
- if ("avg".equals(getFieldName(colNum))
+ if ("avg".equals(getFieldName(colNum))
&& (StorageNodeLoadCompositeDatasource.HEAP_PERCENTAGE_KEY.equals(record.getAttribute("id")) ||
StorageNodeLoadCompositeDatasource.DATA_DISK_SPACE_PERCENTAGE_KEY.equals(record.getAttribute("id")) ||
StorageNodeLoadCompositeDatasource.TOTAL_DISK_SPACE_PERCENTAGE_KEY.equals(record.getAttribute("id")))) {
if (record.getAttributeAsFloat("avgFloat") > .85) {
- return "font-weight:bold; color:#d64949;";
+ return DONT_MISS_ME_COLOR;
} else if (record.getAttributeAsFloat("avgFloat") > .7) {
- return "color:#ed9b26;";
+ return WARN_COLOR;
} else {
- return "color:#26aa26;";
+ return OK_COLOR;
}
- } else {
+ } else if ("avg".equals(getFieldName(colNum))
+ && StorageNodeLoadCompositeDatasource.FREE_DISK_TO_DATA_SIZE_RATIO_KEY.equals(record
+ .getAttribute("id"))) {
+ if (record.getAttributeAsFloat("avgFloat") < 1) {
+ return DONT_MISS_ME_COLOR;
+ } else if (record.getAttributeAsFloat("avgFloat") < 1.5) {
+ return WARN_COLOR;
+ } else {
+ return OK_COLOR;
+ }
+ }
+ else {
return super.getCellCSSText(record, rowNum, colNum);
}
}
};
loadGrid.setWidth100();
- loadGrid.setHeight(200);
+ loadGrid.setHeight(230);
StorageNodeLoadCompositeDatasource datasource = StorageNodeLoadCompositeDatasource.getInstance(storageNodeId);
List<ListGridField> fields = datasource.getListGridFields();
loadGrid.setFields(fields.toArray(new ListGridField[fields.size()]));
loadGrid.setAutoFetchData(true);
+ loadGrid.setHoverWidth(300);
ToolStrip toolStrip = new ToolStrip();
@@ -107,7 +122,7 @@ public class StorageNodeLoadComponent extends EnhancedVLayout {
}
loadGrid.setDataSource(datasource);
addMember(loadGrid);
- addMember(toolStrip);
+// addMember(toolStrip);
}
}
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeTableView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeTableView.java
index 46dd734..3370c87 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeTableView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeTableView.java
@@ -19,6 +19,7 @@
package org.rhq.enterprise.gui.coregui.client.admin.storage;
import static org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDatasourceField.FIELD_ADDRESS;
+import static org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDatasourceField.FIELD_ALERTS;
import static org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDatasourceField.FIELD_RESOURCE_ID;
import java.util.ArrayList;
@@ -27,6 +28,7 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.smartgwt.client.data.Criteria;
import com.smartgwt.client.types.SortDirection;
@@ -78,12 +80,20 @@ public class StorageNodeTableView extends TableSection<StorageNodeDatasource> {
}
@Override
+ protected void doOnDraw() {
+ super.doOnDraw();
+ scheduleUnacknowledgedAlertsPollingJob(getListGrid());
+ }
+
+ @Override
protected void configureTable() {
super.configureTable();
List<ListGridField> fields = getDataSource().getListGridFields();
ListGrid listGrid = getListGrid();
+ listGrid.setAutoSaveEdits(false);
listGrid.setFields(fields.toArray(new ListGridField[fields.size()]));
listGrid.sort(FIELD_ADDRESS.propertyName(), SortDirection.ASCENDING);
+ listGrid.setHoverWidth(200);
showCommonActions();
for (ListGridField field : fields) {
@@ -126,6 +136,38 @@ public class StorageNodeTableView extends TableSection<StorageNodeDatasource> {
}
}
+ private void scheduleUnacknowledgedAlertsPollingJob(final ListGrid listGrid) {
+ new Timer() {
+ public void run() {
+ final ListGridRecord[] records = listGrid.getRecords();
+ List<Integer> storageNodeIds = new ArrayList<Integer>(records.length);
+ for (ListGridRecord record : records) {
+ // todo: get the resource ids and create a method on SLSB that accepts resource ids to make it faster
+ storageNodeIds.add(record.getAttributeAsInt(FIELD_ID));
+ }
+ GWTServiceLookup.getStorageService().findNotAcknowledgedStorageNodeAlertsCounts(storageNodeIds,
+ new AsyncCallback<List<Integer>>() {
+ @Override
+ public void onSuccess(List<Integer> result) {
+ for (int i = 0; i < records.length; i++) {
+ int value = result.get(i);
+ records[i].setAttribute(FIELD_ALERTS.propertyName(), "New Alerts"
+ + (value != 0 ? " <font color='#CC0000;'>(" + value + ")</font>" : " (" + value
+ + ")"));
+ listGrid.setData(records);
+ }
+ schedule(10 * 1000);
+ }
+
+ @Override
+ public void onFailure(Throwable caught) {
+ schedule(60 * 1000);
+ }
+ });
+ }
+ }.schedule(5 * 1000);
+ }
+
@Override
protected ListGrid createListGrid() {
ListGrid listGrid = new ListGrid() {
@@ -136,7 +178,7 @@ public class StorageNodeTableView extends TableSection<StorageNodeDatasource> {
}
};
listGrid.setCanExpandRecords(true);
-// listGrid.setAutoFetchData(true);
+ // listGrid.setAutoFetchData(true);
return listGrid;
}
@@ -148,38 +190,6 @@ public class StorageNodeTableView extends TableSection<StorageNodeDatasource> {
private void showCommonActions() {
addInvokeOperationsAction();
-
- // addTableAction(MSG.view_adminTopology_server_removeSelected(), null, new AuthorizedTableAction(this,
- // TableActionEnablement.ANY, Permission.MANAGE_SETTINGS) {
- // public void executeAction(final ListGridRecord[] selections, Object actionValue) {
- // final List<String> selectedAddresses = getSelectedAddresses(selections);
- // String message = MSG.view_adminTopology_message_removeServerConfirm(selectedAddresses.toString());
- // SC.ask(message, new BooleanCallback() {
- // public void execute(Boolean confirmed) {
- // if (confirmed) {
- // SC.say("You've selected:\n\n" + selectedAddresses);
- //// int[] selectedIds = getSelectedIds(selections);
- //// GWTServiceLookup.getTopologyService().deleteServers(selectedIds, new AsyncCallback<Void>() {
- //// public void onSuccess(Void arg0) {
- //// Message msg = new Message(MSG.view_adminTopology_message_removedServer(String
- //// .valueOf(selections.length)), Message.Severity.Info);
- //// CoreGUI.getMessageCenter().notify(msg);
- //// refresh();
- //// }
- ////
- //// public void onFailure(Throwable caught) {
- //// CoreGUI.getErrorHandler().handleError(
- //// MSG.view_adminTopology_message_removeServerFail(String
- //// .valueOf(selections.length)) + " " + caught.getMessage(), caught);
- //// refreshTableInfo();
- //// }
- ////
- //// });
- // }
- // }
- // });
- // }
- // });
}
private void addInvokeOperationsAction() {
@@ -263,26 +273,6 @@ public class StorageNodeTableView extends TableSection<StorageNodeDatasource> {
});
}
}
-
- // int[] selectedIds = getSelectedIds(selections);
- // GWTServiceLookup.getTopologyService().updateServerMode(selectedIds, mode,
- // new AsyncCallback<Void>() {
- // public void onSuccess(Void result) {
- // Message msg = new Message(MSG.view_adminTopology_message_setMode(
- // String.valueOf(selections.length), mode.name()), Message.Severity.Info);
- // CoreGUI.getMessageCenter().notify(msg);
- // refresh();
- // }
- //
- // public void onFailure(Throwable caught) {
- // CoreGUI.getErrorHandler().handleError(
- // MSG.view_adminTopology_message_setModeFail(
- // String.valueOf(selections.length), mode.name())
- // + " " + caught.getMessage(), caught);
- // refreshTableInfo();
- // }
- //
- // });
} else {
refreshTableInfo();
}
commit 24fa639a78ca9a9f66b93080087a50b95b0bff40
Author: Jirka Kremser <jkremser(a)redhat.com>
Date: Thu Jul 25 14:53:22 2013 +0200
Hiding the "Jump to Section" navigation if there is only one section in the ConfigurationEditor component.
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/configuration/ConfigurationEditor.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/configuration/ConfigurationEditor.java
index 418300f..02d25eb 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/configuration/ConfigurationEditor.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/configuration/ConfigurationEditor.java
@@ -453,8 +453,11 @@ public class ConfigurationEditor extends EnhancedVLayout {
// com.allen_sauer.gwt.log.client.Log.info("building: " + definition.getDisplayName());
sectionStack.addSection(buildGroupSection(definition));
}
- this.toolStrip = buildToolStrip(layout, sectionStack);
- layout.addMember(toolStrip);
+
+ if (groupDefinitions.size() > 1) {
+ this.toolStrip = buildToolStrip(layout, sectionStack);
+ layout.addMember(toolStrip);
+ }
layout.addMember(sectionStack);
}
commit ad9620a5be6b6d3264969d7b6ba612b11173df5c
Author: Jirka Kremser <jkremser(a)redhat.com>
Date: Thu Jul 25 14:51:04 2013 +0200
Fetching all the fields of StorageNode entity if only instance with id is passed to StorageNodeManagerBean.findResourcesWithAlertDefinitions() method.
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerBean.java
index 9afe497..0cf45e4 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerBean.java
@@ -658,12 +658,8 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
if (storageNode == null) {
initialStorageNodes = getStorageNodes();
} else {
- int index = initialStorageNodes.indexOf(storageNode);
- if (index >= 0) {
- initialStorageNodes = Arrays.asList(initialStorageNodes.get(index));
- } else {
- initialStorageNodes = new ArrayList<StorageNode>();
- }
+ initialStorageNodes = Arrays.asList(storageNode.getResource() == null ? entityManager.find(
+ StorageNode.class, storageNode.getId()) : storageNode);
}
Queue<Resource> unvisitedResources = new LinkedList<Resource>();
commit e29314881365fe1c7147eb58bd3111840968a973
Author: Jirka Kremser <jkremser(a)redhat.com>
Date: Wed Jul 24 12:44:44 2013 +0200
GWT service impl layer method for finding the unacked alerts, also fetching the # of unack alerts in getStorageNodeComposites() and making 8 hours the default time value for aggregated metrics.
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/StorageGWTService.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/StorageGWTService.java
index dd7f009..69c875e 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/StorageGWTService.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/StorageGWTService.java
@@ -22,6 +22,8 @@
*/
package org.rhq.enterprise.gui.coregui.client.gwt;
+import java.util.List;
+
import com.google.gwt.user.client.rpc.RemoteService;
import org.rhq.core.domain.cloud.StorageNode;
@@ -72,4 +74,6 @@ public interface StorageGWTService extends RemoteService {
Integer[] findResourcesWithAlertDefinitions() throws RuntimeException;
int findNotAcknowledgedStorageNodeAlertsCount() throws RuntimeException;
+
+ List<Integer> findNotAcknowledgedStorageNodeAlertsCounts(List<Integer> storageNodeIds) throws RuntimeException;
}
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/StorageGWTServiceImpl.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/StorageGWTServiceImpl.java
index 74837b3..624953c 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/StorageGWTServiceImpl.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/StorageGWTServiceImpl.java
@@ -22,16 +22,15 @@
*/
package org.rhq.enterprise.gui.coregui.server.gwt;
+import java.util.ArrayList;
import java.util.List;
-import org.rhq.core.clientapi.util.ArrayUtil;
import org.rhq.core.domain.cloud.StorageNode;
import org.rhq.core.domain.cloud.StorageNodeLoadComposite;
import org.rhq.core.domain.criteria.ResourceCriteria;
import org.rhq.core.domain.criteria.StorageNodeCriteria;
import org.rhq.core.domain.resource.Resource;
import org.rhq.core.domain.util.PageList;
-import org.rhq.core.domain.util.collection.ArrayUtils;
import org.rhq.enterprise.gui.coregui.client.gwt.StorageGWTService;
import org.rhq.enterprise.gui.coregui.server.util.SerialUtility;
import org.rhq.enterprise.server.cloud.StorageNodeManagerLocal;
@@ -121,4 +120,21 @@ public class StorageGWTServiceImpl extends AbstractGWTServiceImpl implements Sto
throw getExceptionToThrowToClient(t);
}
}
+
+ @Override
+ public List<Integer> findNotAcknowledgedStorageNodeAlertsCounts(List<Integer> storageNodeIds) throws RuntimeException {
+ try {
+ List<Integer> unackAlertCounts = new ArrayList<Integer>(storageNodeIds.size());
+ for (int storageNodeId : storageNodeIds) {
+ StorageNode node = new StorageNode();
+ node.setId(storageNodeId);
+ int num = storageNodeManager.findNotAcknowledgedStorageNodeAlerts(getSessionSubject(), node).size();
+ unackAlertCounts.add(num);
+ }
+ assert storageNodeIds.size() == unackAlertCounts.size();
+ return unackAlertCounts;
+ } catch (Throwable t) {
+ throw getExceptionToThrowToClient(t);
+ }
+ }
}
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerBean.java
index 74a4713..9afe497 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerBean.java
@@ -484,9 +484,12 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
List<StorageNode> nodes = getStorageNodes();
PageList<StorageNodeLoadComposite> result = new PageList<StorageNodeLoadComposite>();
long endTime = System.currentTimeMillis();
- long beginTime = endTime - (1 * 60 * 60 * 1000);
+ long beginTime = endTime - (8 * 60 * 60 * 1000);
for (StorageNode node : nodes) {
- result.add(getLoad(subjectManager.getOverlord(), node, beginTime, endTime));
+ StorageNodeLoadComposite composite = getLoad(subjectManager.getOverlord(), node, beginTime, endTime);
+ int unackAlerts = findNotAcknowledgedStorageNodeAlerts(subjectManager.getOverlord(), node).size();
+ composite.setUnackAlerts(unackAlerts);
+ result.add(composite);
}
return result;
}
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerLocal.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerLocal.java
index a22666e..63e8e3e 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerLocal.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerLocal.java
@@ -185,8 +185,6 @@ public interface StorageNodeManagerLocal {
* @throws IllegalStateException if the group is not found or does not exist.
*/
ResourceGroup getStorageNodeGroup();
-
- Integer[] findResourcesWithAlertDefinitions();
void scheduleOperationInNewTransaction(Subject subject, ResourceOperationSchedule schedule);
commit 168e6c071c841789caae5b96a8ca15537058ba5a
Author: Jirka Kremser <jkremser(a)redhat.com>
Date: Wed Jul 24 12:40:01 2013 +0200
Considering FILTER_RESOURCE_IDS in the AlertDatasource.getFetchCriteria().
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/alert/AlertDataSource.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/alert/AlertDataSource.java
index d66baea..90ac315 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/alert/AlertDataSource.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/alert/AlertDataSource.java
@@ -83,6 +83,7 @@ public class AlertDataSource extends RPCDataSource<Alert, AlertCriteria> {
public static final String PRIORITY_ICON_LOW = ImageManager.getAlertIcon(AlertPriority.LOW);
public static final String FILTER_PRIORITIES = "priorities";
+ public static final String FILTER_RESOURCE_IDS = "resourceIds";
private AlertGWTServiceAsync alertService = GWTServiceLookup.getAlertService();
@@ -360,6 +361,7 @@ public class AlertDataSource extends RPCDataSource<Alert, AlertCriteria> {
Date endOfDay = DateFilterItem.adjustTimeToEndOfDay(endDateFilter);
criteria.addFilterEndTime(endOfDay.getTime());
}
+ criteria.addFilterResourceIds(getArrayFilter(request, FILTER_RESOURCE_IDS, Integer.class));
criteria.addFilterEntityContext(entityContext);
criteria.fetchConditionLogs(true);
// criteria.fetchGroupAlertDefinition(true);
commit f34eb24c2ebf04f9cdb0a7517554bb2be51e4941
Author: Jirka Kremser <jkremser(a)redhat.com>
Date: Tue Jul 23 13:02:37 2013 +0200
Number of unack alerts is now displayed on the alert tab title.
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeAdminView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeAdminView.java
index b9d2335..31378f1 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeAdminView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeAdminView.java
@@ -20,6 +20,7 @@ package org.rhq.enterprise.gui.coregui.client.admin.storage;
import java.util.EnumSet;
+import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.smartgwt.client.widgets.Label;
import com.smartgwt.client.widgets.tab.events.TabSelectedEvent;
@@ -60,12 +61,11 @@ public class StorageNodeAdminView extends EnhancedVLayout implements HasViewName
+ AdministrationView.SECTION_TOPOLOGY_VIEW_ID + "/" + VIEW_ID;
private static final String GROUP_NAME = "RHQ Storage Nodes";
-// private static final String GROUP_NAME = "storage services";
private final NamedTabSet tabset;
private TabInfo tableTabInfo = new TabInfo(0, new ViewName("Nodes"));
- private TabInfo settingsTabInfo = new TabInfo(1, new ViewName("Settings", "Global Settings"));
- private TabInfo alertsTabInfo = new TabInfo(2, new ViewName("Alerts", "Global Alerts"));
+ private TabInfo settingsTabInfo = new TabInfo(1, new ViewName("Settings", "Cluster Settings"));
+ private TabInfo alertsTabInfo = new TabInfo(2, new ViewName("Alerts", "Cluster Alerts"));
private TabInfo backupTabInfo = new TabInfo(3, new ViewName("Backup"));
private StorageNodeTableView table;
@@ -97,6 +97,7 @@ public class StorageNodeAdminView extends EnhancedVLayout implements HasViewName
CoreGUI.goToView(VIEW_PATH + "/" + alertsTabInfo.name);
}
});
+ scheduleUnacknowledgedAlertsPollingJob(alerts);
final NamedTab backup = new NamedTab(backupTabInfo.name);
backup.addTabSelectedHandler(new TabSelectedHandler() {
@@ -182,6 +183,27 @@ public class StorageNodeAdminView extends EnhancedVLayout implements HasViewName
}
});
}
+
+ private void scheduleUnacknowledgedAlertsPollingJob(final NamedTab alerts) {
+ new Timer() {
+ public void run() {
+ GWTServiceLookup.getStorageService().findNotAcknowledgedStorageNodeAlertsCount(new AsyncCallback<Integer>() {
+ @Override
+ public void onSuccess(Integer result) {
+ alerts.setTitle(alerts.getTitle()
+ + (result != 0 ? " <font color='#CC0000;'>(" + result + ")</font>" : " (" + result
+ + ")"));
+ schedule(5 * 1000);
+ }
+
+ @Override
+ public void onFailure(Throwable caught) {
+ schedule(60 * 1000);
+ }
+ });
+ }
+ }.run();
+ }
@Override
public ViewName getViewName() {
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/StorageGWTService.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/StorageGWTService.java
index df0e4cf..dd7f009 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/StorageGWTService.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/StorageGWTService.java
@@ -70,4 +70,6 @@ public interface StorageGWTService extends RemoteService {
PageList<StorageNodeLoadComposite> getStorageNodeComposites() throws RuntimeException;
Integer[] findResourcesWithAlertDefinitions() throws RuntimeException;
+
+ int findNotAcknowledgedStorageNodeAlertsCount() throws RuntimeException;
}
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/StorageGWTServiceImpl.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/StorageGWTServiceImpl.java
index 45508c7..74837b3 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/StorageGWTServiceImpl.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/StorageGWTServiceImpl.java
@@ -112,4 +112,13 @@ public class StorageGWTServiceImpl extends AbstractGWTServiceImpl implements Sto
throw getExceptionToThrowToClient(t);
}
}
+
+ @Override
+ public int findNotAcknowledgedStorageNodeAlertsCount() throws RuntimeException {
+ try {
+ return storageNodeManager.findNotAcknowledgedStorageNodeAlerts(getSessionSubject()).size();
+ } catch (Throwable t) {
+ throw getExceptionToThrowToClient(t);
+ }
+ }
}
commit f0c55dc98a3ed17f6b28344ba73e6bf3efc2d23d
Author: Jirka Kremser <jkremser(a)redhat.com>
Date: Wed Jul 17 14:14:45 2013 +0200
Making things more consistent - now, one hour aggregate are used for both the load sub-table and for the Memory and Disk columns.
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDatasource.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDatasource.java
index 65314f4..e9e81f3 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDatasource.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDatasource.java
@@ -119,7 +119,7 @@ public class StorageNodeDatasource extends RPCDataSource<StorageNodeLoadComposit
field.setShowHover(true);
field.setHoverCustomizer(new HoverCustomizer() {
public String hoverHTML(Object value, ListGridRecord record, int rowNum, int colNum) {
- return "Average disk space taken for last one hour.";
+ return "Average memory taken for last one hour.";
}
});
fields.add(field);
@@ -128,7 +128,7 @@ public class StorageNodeDatasource extends RPCDataSource<StorageNodeLoadComposit
field.setShowHover(true);
field.setHoverCustomizer(new HoverCustomizer() {
public String hoverHTML(Object value, ListGridRecord record, int rowNum, int colNum) {
- return "Average memory taken for last one hour.";
+ return "Average disk space taken for last one hour.";
}
});
fields.add(field);
@@ -335,7 +335,7 @@ public class StorageNodeDatasource extends RPCDataSource<StorageNodeLoadComposit
}
private static void executeFetch(final StorageNode node, final AsyncCallback<StorageNodeLoadComposite> callback) {
- GWTServiceLookup.getStorageService().getLoad(node, 8, MeasurementUtils.UNIT_HOURS, callback);
+ GWTServiceLookup.getStorageService().getLoad(node, 1, MeasurementUtils.UNIT_HOURS, callback);
}
private ListGridRecord[] makeListGridRecords(StorageNodeLoadComposite loadComposite) {
commit 1c5d4ff8f5c03bb1c86c9a4af0c9099d80097a62
Author: Jirka Kremser <jkremser(a)redhat.com>
Date: Wed Jul 17 14:10:12 2013 +0200
New storage node ui, containing Alerts, Configuration and the table with storage nodes.
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/AdministrationView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/AdministrationView.java
index da01888..9a7e75f 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/AdministrationView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/AdministrationView.java
@@ -32,7 +32,7 @@ import org.rhq.enterprise.gui.coregui.client.CoreGUI;
import org.rhq.enterprise.gui.coregui.client.IconEnum;
import org.rhq.enterprise.gui.coregui.client.admin.agent.install.RemoteAgentInstallView;
import org.rhq.enterprise.gui.coregui.client.admin.roles.RolesView;
-import org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeTableView;
+import org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeAdminView;
import org.rhq.enterprise.gui.coregui.client.admin.templates.AlertDefinitionTemplateTypeView;
import org.rhq.enterprise.gui.coregui.client.admin.templates.DriftDefinitionTemplateTypeView;
import org.rhq.enterprise.gui.coregui.client.admin.templates.IgnoreResourceTypesView;
@@ -145,9 +145,9 @@ public class AdministrationView extends AbstractSectionedLeftNavigationView {
}
}, getGlobalPermissions().contains(Permission.MANAGE_SETTINGS));
- NavigationItem storageNodesItem = new NavigationItem(StorageNodeTableView.VIEW_ID, new ViewFactory() {
+ NavigationItem storageNodesItem = new NavigationItem(StorageNodeAdminView.VIEW_ID, new ViewFactory() {
public Canvas createView() {
- return new StorageNodeTableView();
+ return new StorageNodeAdminView();
}
}, getGlobalPermissions().contains(Permission.MANAGE_SETTINGS));
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeAdminView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeAdminView.java
index c9bdc0d..b9d2335 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeAdminView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeAdminView.java
@@ -18,328 +18,224 @@
*/
package org.rhq.enterprise.gui.coregui.client.admin.storage;
-import static org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDatasourceField.FIELD_ADDRESS;
-import static org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDatasourceField.FIELD_RESOURCE_ID;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.EnumSet;
import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.smartgwt.client.data.Criteria;
-import com.smartgwt.client.types.SortDirection;
-import com.smartgwt.client.util.BooleanCallback;
-import com.smartgwt.client.util.SC;
-import com.smartgwt.client.widgets.Canvas;
-import com.smartgwt.client.widgets.grid.CellFormatter;
-import com.smartgwt.client.widgets.grid.ListGrid;
-import com.smartgwt.client.widgets.grid.ListGridField;
-import com.smartgwt.client.widgets.grid.ListGridRecord;
-
-import org.rhq.core.domain.authz.Permission;
-import org.rhq.core.domain.cloud.StorageNode.OperationMode;
+import com.smartgwt.client.widgets.Label;
+import com.smartgwt.client.widgets.tab.events.TabSelectedEvent;
+import com.smartgwt.client.widgets.tab.events.TabSelectedHandler;
+
+import org.rhq.core.domain.criteria.ResourceGroupCriteria;
+import org.rhq.core.domain.resource.ResourceType;
+import org.rhq.core.domain.resource.group.composite.ResourceGroupComposite;
+import org.rhq.core.domain.util.PageList;
+import org.rhq.core.domain.util.collection.ArrayUtils;
+import org.rhq.enterprise.gui.coregui.client.BookmarkableView;
import org.rhq.enterprise.gui.coregui.client.CoreGUI;
import org.rhq.enterprise.gui.coregui.client.IconEnum;
-import org.rhq.enterprise.gui.coregui.client.LinkManager;
+import org.rhq.enterprise.gui.coregui.client.ViewPath;
import org.rhq.enterprise.gui.coregui.client.admin.AdministrationView;
-import org.rhq.enterprise.gui.coregui.client.components.table.AuthorizedTableAction;
-import org.rhq.enterprise.gui.coregui.client.components.table.TableActionEnablement;
-import org.rhq.enterprise.gui.coregui.client.components.table.TableSection;
+import org.rhq.enterprise.gui.coregui.client.alert.AlertHistoryView;
+import org.rhq.enterprise.gui.coregui.client.components.tab.NamedTab;
+import org.rhq.enterprise.gui.coregui.client.components.tab.NamedTabSet;
import org.rhq.enterprise.gui.coregui.client.components.view.HasViewName;
import org.rhq.enterprise.gui.coregui.client.components.view.ViewName;
import org.rhq.enterprise.gui.coregui.client.gwt.GWTServiceLookup;
-import org.rhq.enterprise.gui.coregui.client.util.StringUtility;
-import org.rhq.enterprise.gui.coregui.client.util.async.Command;
-import org.rhq.enterprise.gui.coregui.client.util.async.CountDownLatch;
+import org.rhq.enterprise.gui.coregui.client.inventory.groups.detail.configuration.GroupResourceConfigurationEditView;
+import org.rhq.enterprise.gui.coregui.client.inventory.resource.type.ResourceTypeRepository;
+import org.rhq.enterprise.gui.coregui.client.util.enhanced.EnhancedVLayout;
import org.rhq.enterprise.gui.coregui.client.util.message.Message;
/**
- * Shows the table of all storage nodes.
+ * The main view for managing storage nodes.
*
* @author Jirka Kremser
*/
-public class StorageNodeAdminView extends TableSection<StorageNodeDatasource> implements HasViewName {
+public class StorageNodeAdminView extends EnhancedVLayout implements HasViewName, BookmarkableView {
public static final ViewName VIEW_ID = new ViewName("StorageNodes", MSG.view_adminTopology_storageNodes(),
IconEnum.STORAGE_NODE);
public static final String VIEW_PATH = AdministrationView.VIEW_ID + "/"
+ AdministrationView.SECTION_TOPOLOGY_VIEW_ID + "/" + VIEW_ID;
+
+ private static final String GROUP_NAME = "RHQ Storage Nodes";
+// private static final String GROUP_NAME = "storage services";
+
+ private final NamedTabSet tabset;
+ private TabInfo tableTabInfo = new TabInfo(0, new ViewName("Nodes"));
+ private TabInfo settingsTabInfo = new TabInfo(1, new ViewName("Settings", "Global Settings"));
+ private TabInfo alertsTabInfo = new TabInfo(2, new ViewName("Alerts", "Global Alerts"));
+ private TabInfo backupTabInfo = new TabInfo(3, new ViewName("Backup"));
+ private StorageNodeTableView table;
+
+ private int[] resIds;
public StorageNodeAdminView() {
- super(null);
+ super();
setHeight100();
setWidth100();
- Criteria criteria = new Criteria();
- String[] modes = new String[OperationMode.values().length];
- int i = 0;
- for (OperationMode value : OperationMode.values()) {
- modes[i++] = value.name();
- }
- criteria.addCriteria(StorageNodeDatasource.FILTER_OPERATION_MODE, modes);
- setInitialCriteria(criteria);
- setDataSource(new StorageNodeDatasource());
+ setLayoutTopMargin(8);
+ tabset = new NamedTabSet();
+ NamedTab table = new NamedTab(tableTabInfo.name);
+ table.addTabSelectedHandler(new TabSelectedHandler() {
+ public void onTabSelected(TabSelectedEvent event) {
+ CoreGUI.goToView(VIEW_PATH);
+ }
+ });
+
+ NamedTab settings = new NamedTab(settingsTabInfo.name);
+ settings.addTabSelectedHandler(new TabSelectedHandler() {
+ public void onTabSelected(TabSelectedEvent event) {
+ CoreGUI.goToView(VIEW_PATH + "/" + settingsTabInfo.name);
+ }
+ });
+
+ final NamedTab alerts = new NamedTab(alertsTabInfo.name);
+ alerts.addTabSelectedHandler(new TabSelectedHandler() {
+ public void onTabSelected(TabSelectedEvent event) {
+ CoreGUI.goToView(VIEW_PATH + "/" + alertsTabInfo.name);
+ }
+ });
+
+ final NamedTab backup = new NamedTab(backupTabInfo.name);
+ backup.addTabSelectedHandler(new TabSelectedHandler() {
+ public void onTabSelected(TabSelectedEvent event) {
+ CoreGUI.goToView(VIEW_PATH + "/" + backupTabInfo.name);
+ }
+ });
+
+ tabset.setTabs(table, settings, alerts, backup);
+ addMember(tabset);
}
- @Override
- protected void configureTable() {
- super.configureTable();
- List<ListGridField> fields = getDataSource().getListGridFields();
- ListGrid listGrid = getListGrid();
- listGrid.setFields(fields.toArray(new ListGridField[fields.size()]));
- listGrid.sort(FIELD_ADDRESS.propertyName(), SortDirection.ASCENDING);
- showCommonActions();
+ private void showTab(final TabInfo tabInfo) {
+ if (tabInfo.equals(tableTabInfo)) {
+ table = new StorageNodeTableView();
+ tabset.getTabByName(tabInfo.name.getName()).setPane(table);
+ tabset.selectTab(tabInfo.index);
+ } else if (tabInfo.equals(backupTabInfo)) {
+ tabset.getTabByName(tabInfo.name.getName()).setPane(new Label("in progress.."));
+ } else if (tabInfo.equals(alertsTabInfo)) {
+ if (resIds != null) {
+ tabset.getTabByName(tabInfo.name.getName()).setPane(new AlertHistoryView("storageNodesAlerts", resIds));
+ } else {
+ GWTServiceLookup.getStorageService().findResourcesWithAlertDefinitions(new AsyncCallback<Integer[]>() {
+ @Override
+ public void onFailure(Throwable caught) {
+ Message message = new Message("foobar",
+ Message.Severity.Warning);
+ CoreGUI.goToView(VIEW_ID.getName(), message);
+ }
- for (ListGridField field : fields) {
- // adding the cell formatter for name field (clickable link)
- if (field.getName() == FIELD_ADDRESS.propertyName()) {
- field.setCellFormatter(new CellFormatter() {
@Override
- public String format(Object value, ListGridRecord record, int rowNum, int colNum) {
- if (value == null) {
- return "";
+ public void onSuccess(Integer[] result) {
+ if (result == null || result.length == 0) {
+ onFailure(new Exception("foobaz"));
+ } else {
+ resIds = ArrayUtils.unwrapArray(result);
+ tabset.getTabByName(tabInfo.name.getName()).setPane(
+ new AlertHistoryView("storageNodesAlerts", resIds));
+ tabset.selectTab(tabInfo.index);
}
- String detailsUrl = "#" + VIEW_PATH + "/" + getId(record);
- String formattedValue = StringUtility.escapeHtml(value.toString());
- return LinkManager.getHref(detailsUrl, formattedValue);
-
}
});
- } else if (field.getName() == FIELD_RESOURCE_ID.propertyName()) {
- // adding the cell formatter for resource id field (clickable link)
- field.setCellFormatter(new CellFormatter() {
+ }
+ } else if (tabInfo.equals(settingsTabInfo)) {
+ ResourceGroupCriteria criteria = new ResourceGroupCriteria();
+ criteria.addFilterName(GROUP_NAME);
+ criteria.setStrict(true);
+ GWTServiceLookup.getResourceGroupService().findResourceGroupCompositesByCriteria(criteria,
+ new AsyncCallback<PageList<ResourceGroupComposite>>() {
@Override
- public String format(Object value, ListGridRecord record, int rowNum, int colNum) {
- if (value == null || value.toString().isEmpty()) {
- return "";
- }
- String rawUrl = null;
- try {
- rawUrl = LinkManager.getResourceLink(record.getAttributeAsInt(FIELD_RESOURCE_ID
- .propertyName()));
- } catch (NumberFormatException nfe) {
- rawUrl = MSG.common_label_none();
- }
+ public void onFailure(Throwable caught) {
+ Message message = new Message(MSG.view_group_detail_failLoadComp(String.valueOf(GROUP_NAME)),
+ Message.Severity.Warning);
+ CoreGUI.goToView(VIEW_ID.getName(), message);
+ }
- String formattedValue = StringUtility.escapeHtml(rawUrl);
- String label = StringUtility.escapeHtml("Link to Resource");
- return LinkManager.getHref(formattedValue, label);
+ @Override
+ public void onSuccess(PageList<ResourceGroupComposite> result) {
+ if (result.isEmpty()) {
+ onFailure(new Exception("Group with name [" + GROUP_NAME + "] does not exist."));
+ } else {
+ ResourceGroupComposite groupComposite = result.get(0);
+ loadResourceType(groupComposite.getResourceGroup().getResourceType().getId());
+ tabset.getTabByName(tabInfo.name.getName()).setPane(
+ new GroupResourceConfigurationEditView(groupComposite));
+ tabset.selectTab(tabInfo.index);
+ }
}
});
- }
}
}
-
- @Override
- protected ListGrid createListGrid() {
- ListGrid listGrid = new ListGrid() {
- @Override
- protected Canvas getExpansionComponent(final ListGridRecord record) {
- int id = record.getAttributeAsInt(FIELD_ID);
- return new StorageNodeLoadComponent(id, this, record);
- }
- };
- listGrid.setCanExpandRecords(true);
-// listGrid.setAutoFetchData(true);
-
- return listGrid;
+
+ private void loadResourceType(int resourceTypeId) {
+ ResourceTypeRepository.Cache.getInstance().getResourceTypes(
+ resourceTypeId,
+ EnumSet.of(ResourceTypeRepository.MetadataType.content, ResourceTypeRepository.MetadataType.operations,
+ ResourceTypeRepository.MetadataType.measurements, ResourceTypeRepository.MetadataType.events,
+ ResourceTypeRepository.MetadataType.resourceConfigurationDefinition),
+ new ResourceTypeRepository.TypeLoadedCallback() {
+ public void onTypesLoaded(ResourceType type) {
+
+ }
+ });
}
@Override
- public Canvas getDetailsView(Integer id) {
- return new StorageNodeDetailView(id);
- }
-
- private void showCommonActions() {
- addInvokeOperationsAction();
-
- // addTableAction(MSG.view_adminTopology_server_removeSelected(), null, new AuthorizedTableAction(this,
- // TableActionEnablement.ANY, Permission.MANAGE_SETTINGS) {
- // public void executeAction(final ListGridRecord[] selections, Object actionValue) {
- // final List<String> selectedAddresses = getSelectedAddresses(selections);
- // String message = MSG.view_adminTopology_message_removeServerConfirm(selectedAddresses.toString());
- // SC.ask(message, new BooleanCallback() {
- // public void execute(Boolean confirmed) {
- // if (confirmed) {
- // SC.say("You've selected:\n\n" + selectedAddresses);
- //// int[] selectedIds = getSelectedIds(selections);
- //// GWTServiceLookup.getTopologyService().deleteServers(selectedIds, new AsyncCallback<Void>() {
- //// public void onSuccess(Void arg0) {
- //// Message msg = new Message(MSG.view_adminTopology_message_removedServer(String
- //// .valueOf(selections.length)), Message.Severity.Info);
- //// CoreGUI.getMessageCenter().notify(msg);
- //// refresh();
- //// }
- ////
- //// public void onFailure(Throwable caught) {
- //// CoreGUI.getErrorHandler().handleError(
- //// MSG.view_adminTopology_message_removeServerFail(String
- //// .valueOf(selections.length)) + " " + caught.getMessage(), caught);
- //// refreshTableInfo();
- //// }
- ////
- //// });
- // }
- // }
- // });
- // }
- // });
- }
-
- private void addInvokeOperationsAction() {
- Map<String, Object> operationsMap = new LinkedHashMap<String, Object>();
- operationsMap.put("Start", "start");
- operationsMap.put("Shutdown", "shutdown");
- operationsMap.put("Restart", "restart");
- operationsMap.put("Disable Debug Mode", "stopRPCServer");
- operationsMap.put("Enable Debug Mode", "startRPCServer");
- // operationsMap.put("Decommission", "decommission");
-
- addTableAction(MSG.common_title_operation(), null, operationsMap, new AuthorizedTableAction(this,
- TableActionEnablement.ANY, Permission.MANAGE_SETTINGS) {
-
- @Override
- public boolean isEnabled(ListGridRecord[] selection) {
- return StorageNodeAdminView.this.isEnabled(super.isEnabled(selection), selection);
- };
-
- @Override
- public void executeAction(final ListGridRecord[] selections, Object actionValue) {
- final String operationName = (String) actionValue;
- final List<String> selectedAddresses = getSelectedAddresses(selections);
- // String message = MSG.view_adminTopology_message_setModeConfirm(selectedAddresses.toString(), mode.name());
- SC.ask("Are you sure, you want to run operation " + operationName + "?", new BooleanCallback() {
- public void execute(Boolean confirmed) {
- if (confirmed) {
- final CountDownLatch latch = CountDownLatch.create(selections.length, new Command() {
- @Override
- public void execute() {
- // Message msg = new Message(MSG.view_adminTopology_message_setMode(
- // String.valueOf(selections.length), mode.name()), Message.Severity.Info);
- Message msg = new Message("Operation" + operationName
- + " was successfully scheduled for resources with ids"
- + Arrays.asList(getSelectedIds(selections)), Message.Severity.Info);
- CoreGUI.getMessageCenter().notify(msg);
- refreshTableInfo();
- }
- });
- boolean isStopStartOrRestart = Arrays.asList("start", "shutdown", "restart").contains(
- operationName);
- for (ListGridRecord storageNodeRecord : selections) {
- // NFE should never happen, because of the condition for table action enablement
- int resourceId = storageNodeRecord.getAttributeAsInt(FIELD_RESOURCE_ID.propertyName());
- if (isStopStartOrRestart) {
- // start, stop or restart the storage node
- GWTServiceLookup.getOperationService().scheduleResourceOperation(resourceId,
- operationName, null, "Run by Storage Node Administrations UI", 0,
- new AsyncCallback<Void>() {
- public void onSuccess(Void result) {
- latch.countDown();
- }
-
- public void onFailure(Throwable caught) {
- CoreGUI.getErrorHandler().handleError(
- "Scheduling operation " + operationName
- + " failed for resources with ids"
- + Arrays.asList(getSelectedIds(selections)) + " "
- + caught.getMessage(), caught);
- latch.countDown();
- refreshTableInfo();
- }
- });
- } else {
- // invoke the operation on the storage service resource
- GWTServiceLookup.getStorageService().invokeOperationOnStorageService(resourceId,
- operationName, new AsyncCallback<Void>() {
- public void onSuccess(Void result) {
- latch.countDown();
- }
-
- public void onFailure(Throwable caught) {
- CoreGUI.getErrorHandler().handleError(
- "Scheduling operation " + operationName
- + " failed for resources with ids"
- + Arrays.asList(getSelectedIds(selections)) + " "
- + caught.getMessage(), caught);
- latch.countDown();
- refreshTableInfo();
- }
- });
- }
- }
-
- // int[] selectedIds = getSelectedIds(selections);
- // GWTServiceLookup.getTopologyService().updateServerMode(selectedIds, mode,
- // new AsyncCallback<Void>() {
- // public void onSuccess(Void result) {
- // Message msg = new Message(MSG.view_adminTopology_message_setMode(
- // String.valueOf(selections.length), mode.name()), Message.Severity.Info);
- // CoreGUI.getMessageCenter().notify(msg);
- // refresh();
- // }
- //
- // public void onFailure(Throwable caught) {
- // CoreGUI.getErrorHandler().handleError(
- // MSG.view_adminTopology_message_setModeFail(
- // String.valueOf(selections.length), mode.name())
- // + " " + caught.getMessage(), caught);
- // refreshTableInfo();
- // }
- //
- // });
- } else {
- refreshTableInfo();
- }
- }
- });
- }
- });
+ public ViewName getViewName() {
+ return VIEW_ID;
}
-
- private int[] getSelectedIds(ListGridRecord[] selections) {
- if (selections == null) {
- return new int[0];
- }
- int[] ids = new int[selections.length];
- int i = 0;
- for (ListGridRecord selection : selections) {
- ids[i++] = selection.getAttributeAsInt(FIELD_ID);
+
+ private static final class TabInfo {
+ private int index;
+ private ViewName name;
+
+ private TabInfo(int index, ViewName name) {
+ this.index = index;
+ this.name = name;
}
- return ids;
- }
- private List<String> getSelectedAddresses(ListGridRecord[] selections) {
- if (selections == null) {
- return new ArrayList<String>(0);
- }
- List<String> ids = new ArrayList<String>(selections.length);
- for (ListGridRecord selection : selections) {
- ids.add(selection.getAttributeAsString(FIELD_ADDRESS.propertyName()));
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + index;
+ return result;
}
- return ids;
- }
- private boolean isEnabled(boolean parentsOpinion, ListGridRecord[] selection) {
- if (!parentsOpinion) {
- return false;
- }
- for (ListGridRecord storageNodeRecord : selection) {
- if (storageNodeRecord.getAttribute(FIELD_RESOURCE_ID.propertyName()) == null) {
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
return false;
- }
+ if (getClass() != obj.getClass())
+ return false;
+ TabInfo other = (TabInfo) obj;
+ if (index != other.index)
+ return false;
+ return true;
}
- return true;
- }
-
- @Override
- public ViewName getViewName() {
- return VIEW_ID;
}
@Override
- protected String getBasePath() {
- return VIEW_PATH;
+ public void renderView(ViewPath viewPath) {
+ if (viewPath.getViewPath().size() == 3) {
+ showTab(tableTabInfo);
+ } else {
+ String viewId = viewPath.getCurrent().getPath();
+ if (settingsTabInfo.name.getName().equals(viewId)) {
+ showTab(settingsTabInfo);
+ } else if (alertsTabInfo.name.getName().equals(viewId)) {
+ showTab(alertsTabInfo);
+ } else if (backupTabInfo.name.getName().equals(viewId)) {
+ showTab(backupTabInfo);
+ } else {
+ showTab(tableTabInfo);
+ table.renderView(viewPath);
+ }
+ }
}
}
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDetailView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDetailView.java
index 3fd90c7..f6f08b4 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDetailView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDetailView.java
@@ -58,6 +58,7 @@ import org.rhq.enterprise.gui.coregui.client.ViewPath;
import org.rhq.enterprise.gui.coregui.client.components.table.TimestampCellFormatter;
import org.rhq.enterprise.gui.coregui.client.gwt.GWTServiceLookup;
import org.rhq.enterprise.gui.coregui.client.inventory.InventoryView;
+import org.rhq.enterprise.gui.coregui.client.inventory.resource.detail.configuration.ResourceConfigurationEditView;
import org.rhq.enterprise.gui.coregui.client.inventory.resource.detail.operation.history.ResourceOperationHistoryListView;
import org.rhq.enterprise.gui.coregui.client.util.Log;
import org.rhq.enterprise.gui.coregui.client.util.StringUtility;
@@ -79,6 +80,7 @@ public class StorageNodeDetailView extends EnhancedVLayout implements Bookmarkab
private SectionStackSection detailsSection;
private SectionStackSection loadSection;
private SectionStackSection historySection;
+ private int expandedSection = -1;
private volatile int initSectionCount = 0;
@@ -96,6 +98,11 @@ public class StorageNodeDetailView extends EnhancedVLayout implements Bookmarkab
sectionStack.setMargin(5);
sectionStack.setOverflow(Overflow.VISIBLE);
}
+
+ public StorageNodeDetailView(int storageNodeId, int expandedSection) {
+ this(storageNodeId);
+ this.expandedSection = expandedSection;
+ }
@Override
protected void onInit() {
@@ -152,7 +159,9 @@ public class StorageNodeDetailView extends EnhancedVLayout implements Bookmarkab
initSectionCount = SECTION_COUNT;
} else {
final ResourceComposite resourceComposite = result.get(0);
- prepareOperationHistory(resourceComposite);
+// prepareOperationHistory(resourceComposite);
+ prepareResourceConfigEditor(resourceComposite);
+
}
}
});
@@ -182,6 +191,12 @@ public class StorageNodeDetailView extends EnhancedVLayout implements Bookmarkab
if (null != historySection) {
sectionStack.addSection(historySection);
}
+// if (expandedSection != -1) {
+// for (int i = 1; i < SECTION_COUNT; i++) {
+// sectionStack.collapseSection(i);
+// }
+// sectionStack.expandSection(expandedSection);
+// }
addMember(sectionStack);
markForRedraw();
@@ -268,7 +283,7 @@ public class StorageNodeDetailView extends EnhancedVLayout implements Bookmarkab
footer.addMember(saveButton);
SectionStackSection section = new SectionStackSection(MSG.common_title_details());
- section.setExpanded(true);
+ section.setExpanded(expandedSection != -1 ? expandedSection == 0 : true);
section.setItems(form);
detailsSection = section;
@@ -279,7 +294,7 @@ public class StorageNodeDetailView extends EnhancedVLayout implements Bookmarkab
StorageNodeLoadComponent loadDataComponent = new StorageNodeLoadComponent(storageNode.getId());
SectionStackSection section = new SectionStackSection("Load");
section.setItems(loadDataComponent);
- section.setExpanded(true);
+ section.setExpanded(expandedSection != -1 ? expandedSection == 1 : true);
loadSection = section;
initSectionCount++;
@@ -294,9 +309,31 @@ public class StorageNodeDetailView extends EnhancedVLayout implements Bookmarkab
historySection = section;
initSectionCount++;
}
+
+ private void prepareResourceConfigEditor(ResourceComposite resourceComposite) {
+ ResourceConfigurationEditView editorView = new ResourceConfigurationEditView(resourceComposite);
+ SectionStackSection section = new SectionStackSection("Configuration");
+ section.setItems(editorView);
+ section.setExpanded(expandedSection != -1 && expandedSection == 2);
+
+ historySection = section;
+ initSectionCount++;
+ }
+
+
@Override
public void renderView(ViewPath viewPath) {
+ if (viewPath.toString().endsWith("/Config")) {
+// for (int i = 1; i < SECTION_COUNT; i++) {
+// sectionStack.collapseSection(i);
+// }
+ expandedSection = 2;
+// sectionStack.expandSection(expandedSection);
+// detailsSection.setExpanded(false);
+// loadSection.setExpanded(false);
+// historySection.setExpanded(true);
+ }
Log.debug("StorageNodeDetailView: " + viewPath);
}
}
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeLoadComponent.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeLoadComponent.java
index e044e4e..b0522b1 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeLoadComponent.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeLoadComponent.java
@@ -28,6 +28,7 @@ import com.smartgwt.client.widgets.grid.ListGridField;
import com.smartgwt.client.widgets.grid.ListGridRecord;
import com.smartgwt.client.widgets.toolbar.ToolStrip;
+import org.rhq.enterprise.gui.coregui.client.CoreGUI;
import org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDatasource.StorageNodeLoadCompositeDatasource;
import org.rhq.enterprise.gui.coregui.client.util.enhanced.EnhancedVLayout;
@@ -43,7 +44,7 @@ public class StorageNodeLoadComponent extends EnhancedVLayout {
this(storageNodeId, null, null);
}
- public StorageNodeLoadComponent(int storageNodeId, final ListGrid parentGrid, final ListGridRecord record) {
+ public StorageNodeLoadComponent(final int storageNodeId, final ListGrid parentGrid, final ListGridRecord record) {
super(5);
setPadding(5);
setBackgroundColor("#ffffff");
@@ -73,13 +74,24 @@ public class StorageNodeLoadComponent extends EnhancedVLayout {
loadGrid.setFields(fields.toArray(new ListGridField[fields.size()]));
loadGrid.setAutoFetchData(true);
+
+ ToolStrip toolStrip = new ToolStrip();
+ IButton settingsButton = new IButton("Settings");
+ settingsButton.addClickHandler(new ClickHandler() {
+ public void onClick(ClickEvent event) {
+ CoreGUI.goToView(StorageNodeAdminView.VIEW_PATH + "/" + storageNodeId + "/Config");
+ }
+ });
+ settingsButton.setExtraSpace(5);
+ toolStrip.addMember(settingsButton);
+
IButton refreshButton = new IButton(MSG.common_button_refresh());
refreshButton.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
loadGrid.fetchData();
}
});
- ToolStrip toolStrip = new ToolStrip();
+ refreshButton.setExtraSpace(5);
toolStrip.addMember(refreshButton);
if (parentGrid != null && record != null) {
@@ -90,6 +102,8 @@ public class StorageNodeLoadComponent extends EnhancedVLayout {
}
});
toolStrip.addMember(closeButton);
+
+
}
loadGrid.setDataSource(datasource);
addMember(loadGrid);
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeTableView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeTableView.java
index 9b21970..46dd734 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeTableView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeTableView.java
@@ -41,14 +41,11 @@ import com.smartgwt.client.widgets.grid.ListGridRecord;
import org.rhq.core.domain.authz.Permission;
import org.rhq.core.domain.cloud.StorageNode.OperationMode;
import org.rhq.enterprise.gui.coregui.client.CoreGUI;
-import org.rhq.enterprise.gui.coregui.client.IconEnum;
import org.rhq.enterprise.gui.coregui.client.LinkManager;
import org.rhq.enterprise.gui.coregui.client.admin.AdministrationView;
import org.rhq.enterprise.gui.coregui.client.components.table.AuthorizedTableAction;
import org.rhq.enterprise.gui.coregui.client.components.table.TableActionEnablement;
import org.rhq.enterprise.gui.coregui.client.components.table.TableSection;
-import org.rhq.enterprise.gui.coregui.client.components.view.HasViewName;
-import org.rhq.enterprise.gui.coregui.client.components.view.ViewName;
import org.rhq.enterprise.gui.coregui.client.gwt.GWTServiceLookup;
import org.rhq.enterprise.gui.coregui.client.util.StringUtility;
import org.rhq.enterprise.gui.coregui.client.util.async.Command;
@@ -60,13 +57,10 @@ import org.rhq.enterprise.gui.coregui.client.util.message.Message;
*
* @author Jirka Kremser
*/
-public class StorageNodeTableView extends TableSection<StorageNodeDatasource> implements HasViewName {
-
- public static final ViewName VIEW_ID = new ViewName("StorageNodes", MSG.view_adminTopology_storageNodes(),
- IconEnum.STORAGE_NODE);
+public class StorageNodeTableView extends TableSection<StorageNodeDatasource> {
public static final String VIEW_PATH = AdministrationView.VIEW_ID + "/"
- + AdministrationView.SECTION_TOPOLOGY_VIEW_ID + "/" + VIEW_ID;
+ + AdministrationView.SECTION_TOPOLOGY_VIEW_ID + "/" + StorageNodeAdminView.VIEW_ID;
public StorageNodeTableView() {
super(null);
@@ -80,7 +74,7 @@ public class StorageNodeTableView extends TableSection<StorageNodeDatasource> im
}
criteria.addCriteria(StorageNodeDatasource.FILTER_OPERATION_MODE, modes);
setInitialCriteria(criteria);
- setDataSource(new StorageNodeDatasource());
+ setDataSource(StorageNodeDatasource.instance());
}
@Override
@@ -334,11 +328,6 @@ public class StorageNodeTableView extends TableSection<StorageNodeDatasource> im
}
@Override
- public ViewName getViewName() {
- return VIEW_ID;
- }
-
- @Override
protected String getBasePath() {
return VIEW_PATH;
}
commit 9edd541f204058f645f81c176e84b93a316f75c5
Author: Jirka Kremser <jkremser(a)redhat.com>
Date: Wed Jul 17 14:08:53 2013 +0200
adding ".externalToolBuilders" dir to .gitignore
diff --git a/.gitignore b/.gitignore
index 359687a..83bbeec 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,6 +11,8 @@ dev-agent/
dev-cli/
modules/enterprise/gui/portal-war/build/classes/
modules/enterprise/gui/coregui/build/classes/
+#eclipse specific
+modules/enterprise/gui/coregui/.externalToolBuilders/
modules/enterprise/gui/content_http-war/build/classes/
#created by rhq-enterprise-server's unit tests
commit 300f6aac60f0e2cf60d3cc3a836e3369873ca5b3
Author: Jirka Kremser <jkremser(a)redhat.com>
Date: Wed Jul 17 13:45:39 2013 +0200
Adding two new methods to StorageGWTService.
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/StorageGWTService.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/StorageGWTService.java
index e746d41..df0e4cf 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/StorageGWTService.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/StorageGWTService.java
@@ -66,4 +66,8 @@ public interface StorageGWTService extends RemoteService {
* @return instance of {@link StorageNodeLoadComposite} with the aggregate measurement data of selected metrics
*/
StorageNodeLoadComposite getLoad(StorageNode node, int lastN, int unit) throws RuntimeException;
+
+ PageList<StorageNodeLoadComposite> getStorageNodeComposites() throws RuntimeException;
+
+ Integer[] findResourcesWithAlertDefinitions() throws RuntimeException;
}
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/StorageGWTServiceImpl.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/StorageGWTServiceImpl.java
index c6dc16c..45508c7 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/StorageGWTServiceImpl.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/StorageGWTServiceImpl.java
@@ -24,12 +24,14 @@ package org.rhq.enterprise.gui.coregui.server.gwt;
import java.util.List;
+import org.rhq.core.clientapi.util.ArrayUtil;
import org.rhq.core.domain.cloud.StorageNode;
import org.rhq.core.domain.cloud.StorageNodeLoadComposite;
import org.rhq.core.domain.criteria.ResourceCriteria;
import org.rhq.core.domain.criteria.StorageNodeCriteria;
import org.rhq.core.domain.resource.Resource;
import org.rhq.core.domain.util.PageList;
+import org.rhq.core.domain.util.collection.ArrayUtils;
import org.rhq.enterprise.gui.coregui.client.gwt.StorageGWTService;
import org.rhq.enterprise.gui.coregui.server.util.SerialUtility;
import org.rhq.enterprise.server.cloud.StorageNodeManagerLocal;
@@ -91,4 +93,23 @@ public class StorageGWTServiceImpl extends AbstractGWTServiceImpl implements Sto
throw getExceptionToThrowToClient(t);
}
}
+
+ @Override
+ public PageList<StorageNodeLoadComposite> getStorageNodeComposites() throws RuntimeException {
+ try {
+ return SerialUtility.prepare(storageNodeManager.getStorageNodeComposites(),
+ "StorageGWTServiceImpl.getStorageNodeComposites");
+ } catch (Throwable t) {
+ throw getExceptionToThrowToClient(t);
+ }
+ }
+
+ @Override
+ public Integer[] findResourcesWithAlertDefinitions() throws RuntimeException {
+ try {
+ return storageNodeManager.findResourcesWithAlertDefinitions();
+ } catch (Throwable t) {
+ throw getExceptionToThrowToClient(t);
+ }
+ }
}
commit 14a1802c30ef6b0287fa7e5ed4f3533b2e8986cb
Author: Jirka Kremser <jkremser(a)redhat.com>
Date: Wed Jul 17 13:44:16 2013 +0200
Adding new method for fetching all instances of class StorageNodeLoadComposite.
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerBean.java
index 1f4220b..74a4713 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerBean.java
@@ -478,6 +478,18 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
StorageNode.class);
return query.getResultList();
}
+
+ @Override
+ public PageList<StorageNodeLoadComposite> getStorageNodeComposites() {
+ List<StorageNode> nodes = getStorageNodes();
+ PageList<StorageNodeLoadComposite> result = new PageList<StorageNodeLoadComposite>();
+ long endTime = System.currentTimeMillis();
+ long beginTime = endTime - (1 * 60 * 60 * 1000);
+ for (StorageNode node : nodes) {
+ result.add(getLoad(subjectManager.getOverlord(), node, beginTime, endTime));
+ }
+ return result;
+ }
private List<StorageNode> getClusteredStorageNodes() {
return entityManager.createNamedQuery(StorageNode.QUERY_FIND_ALL_BY_MODE, StorageNode.class)
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerLocal.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerLocal.java
index 238dd32..a22666e 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerLocal.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerLocal.java
@@ -43,6 +43,8 @@ public interface StorageNodeManagerLocal {
String STORAGE_NODE_PLUGIN_NAME = "RHQStorage";
List<StorageNode> getStorageNodes();
+
+ PageList<StorageNodeLoadComposite> getStorageNodeComposites();
void linkResource(Resource resource);
commit 4e19b0a2cab798a0f10d5165abdc2ed8a26ede51
Author: Jirka Kremser <jkremser(a)redhat.com>
Date: Wed Jul 17 13:43:13 2013 +0200
Exposing (making it public) the method findResourcesWithAlertDefinitions() on StorageNodeManager.
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerBean.java
index 327f064..1f4220b 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerBean.java
@@ -650,7 +650,7 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
initialStorageNodes = new ArrayList<StorageNode>();
}
}
-
+
Queue<Resource> unvisitedResources = new LinkedList<Resource>();
for (StorageNode initialStorageNode : initialStorageNodes) {
if (initialStorageNode.getResource() != null) {
@@ -938,4 +938,4 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
return value;
}
-}
\ No newline at end of file
+}
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerLocal.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerLocal.java
index 00ba9e7..238dd32 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerLocal.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerLocal.java
@@ -183,6 +183,8 @@ public interface StorageNodeManagerLocal {
* @throws IllegalStateException if the group is not found or does not exist.
*/
ResourceGroup getStorageNodeGroup();
+
+ Integer[] findResourcesWithAlertDefinitions();
void scheduleOperationInNewTransaction(Subject subject, ResourceOperationSchedule schedule);
commit 44caa82fe1515aeb1bb1dec49aefa36714bced53
Author: Jirka Kremser <jkremser(a)redhat.com>
Date: Wed Jul 17 13:18:10 2013 +0200
StorageNodeDatasource now fetches also the avg heap usage and avg disk space usage, because we show these aggregated metrics in the storage node table.
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDatasource.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDatasource.java
index 07064b7..65314f4 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDatasource.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDatasource.java
@@ -21,8 +21,10 @@ package org.rhq.enterprise.gui.coregui.client.admin.storage;
import static org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDatasourceField.FIELD_ADDRESS;
import static org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDatasourceField.FIELD_CQL_PORT;
import static org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDatasourceField.FIELD_CTIME;
+import static org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDatasourceField.FIELD_DISK;
import static org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDatasourceField.FIELD_ID;
import static org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDatasourceField.FIELD_JMX_PORT;
+import static org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDatasourceField.FIELD_MEMORY;
import static org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDatasourceField.FIELD_MTIME;
import static org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDatasourceField.FIELD_OPERATION_MODE;
import static org.rhq.enterprise.gui.coregui.client.admin.storage.StorageNodeDatasourceField.FIELD_RESOURCE_ID;
@@ -61,22 +63,29 @@ import org.rhq.enterprise.gui.coregui.client.util.RPCDataSource;
import org.rhq.enterprise.server.measurement.util.MeasurementUtils;
/**
- * Datasource for @see StorageNode.
+ * Datasource for @see StorageNodeDatasource + heap and disk usage.
*
* @author Jirka Kremser
*/
-public class StorageNodeDatasource extends RPCDataSource<StorageNode, StorageNodeCriteria> {
-
+public class StorageNodeDatasource extends RPCDataSource<StorageNodeLoadComposite, StorageNodeCriteria> {
// filters
public static final String FILTER_ADDRESS = FIELD_ADDRESS.propertyName();
public static final String FILTER_OPERATION_MODE = FIELD_OPERATION_MODE.propertyName();
-
- public StorageNodeDatasource() {
+ private static StorageNodeDatasource instance;
+
+ private StorageNodeDatasource() {
super();
setID("storageNode");
List<DataSourceField> fields = addDataSourceFields();
addFields(fields);
}
+
+ public static StorageNodeDatasource instance() {
+ if (instance == null) {
+ instance = new StorageNodeDatasource();
+ }
+ return instance;
+ }
@Override
protected List<DataSourceField> addDataSourceFields() {
@@ -105,10 +114,24 @@ public class StorageNodeDatasource extends RPCDataSource<StorageNode, StorageNod
ListGridField createdTimeField = FIELD_CTIME.getListGridField("120");
TimestampCellFormatter.prepareDateField(createdTimeField);
fields.add(createdTimeField);
-
- ListGridField lastUpdateTimeField = FIELD_MTIME.getListGridField("120");
- TimestampCellFormatter.prepareDateField(lastUpdateTimeField);
- fields.add(lastUpdateTimeField);
+
+ ListGridField field = FIELD_MEMORY.getListGridField("90");
+ field.setShowHover(true);
+ field.setHoverCustomizer(new HoverCustomizer() {
+ public String hoverHTML(Object value, ListGridRecord record, int rowNum, int colNum) {
+ return "Average disk space taken for last one hour.";
+ }
+ });
+ fields.add(field);
+
+ field = FIELD_DISK.getListGridField("90");
+ field.setShowHover(true);
+ field.setHoverCustomizer(new HoverCustomizer() {
+ public String hoverHTML(Object value, ListGridRecord record, int rowNum, int colNum) {
+ return "Average memory taken for last one hour.";
+ }
+ });
+ fields.add(field);
ListGridField resourceIdField = FIELD_RESOURCE_ID.getListGridField("120");
// resourceIdField.setHidden(true);
@@ -119,8 +142,8 @@ public class StorageNodeDatasource extends RPCDataSource<StorageNode, StorageNod
@Override
protected void executeFetch(final DSRequest request, final DSResponse response, StorageNodeCriteria criteria) {
- GWTServiceLookup.getStorageService().findStorageNodesByCriteria(criteria, new AsyncCallback<PageList<StorageNode>>() {
- public void onSuccess(PageList<StorageNode> result) {
+ GWTServiceLookup.getStorageService().getStorageNodeComposites(new AsyncCallback<PageList<StorageNodeLoadComposite>>() {
+ public void onSuccess(PageList<StorageNodeLoadComposite> result) {
response.setData(buildRecords(result));
response.setTotalRows(result.size());
processResponse(request.getRequestId(), response);
@@ -161,23 +184,55 @@ public class StorageNodeDatasource extends RPCDataSource<StorageNode, StorageNod
}
@Override
- public StorageNode copyValues(Record from) {
+ public StorageNodeLoadComposite copyValues(Record from) {
throw new UnsupportedOperationException("StorageNodeDatasource.copyValues(Record from)");
}
@Override
- public ListGridRecord copyValues(StorageNode from) {
+ public ListGridRecord copyValues(StorageNodeLoadComposite from) {
ListGridRecord record = new ListGridRecord();
- record.setAttribute(FIELD_ID.propertyName(), from.getId());
- record.setAttribute(FIELD_ADDRESS.propertyName(), from.getAddress());
- record.setAttribute(FIELD_JMX_PORT.propertyName(), from.getJmxPort());
- record.setAttribute(FIELD_CQL_PORT.propertyName(), from.getCqlPort());
- record.setAttribute(FIELD_OPERATION_MODE.propertyName(), from.getOperationMode());
- record.setAttribute(FIELD_CTIME.propertyName(), from.getCtime());
- record.setAttribute(FIELD_MTIME.propertyName(), from.getMtime());
- if (from.getResource() != null) {
- record.setAttribute(FIELD_RESOURCE_ID.propertyName(), from.getResource().getId());
+ StorageNode node = from.getStorageNode();
+ if (node != null) {
+ record.setAttribute(FIELD_ID.propertyName(), node.getId());
+ record.setAttribute(FIELD_ADDRESS.propertyName(), node.getAddress());
+ record.setAttribute(FIELD_JMX_PORT.propertyName(), node.getJmxPort());
+ record.setAttribute(FIELD_CQL_PORT.propertyName(), node.getCqlPort());
+ record.setAttribute(FIELD_OPERATION_MODE.propertyName(), node.getOperationMode());
+ record.setAttribute(FIELD_CTIME.propertyName(), node.getCtime());
+ record.setAttribute(FIELD_MTIME.propertyName(), node.getMtime());
+ if (node.getResource() != null) {
+ record.setAttribute(FIELD_RESOURCE_ID.propertyName(), node.getResource().getId());
+ }
}
+ String memory = MeasurementConverterClient.format(from.getHeapPercentageUsed().getAggregate().getAvg(),
+ from.getHeapPercentageUsed().getUnits(), true);
+ record.setAttribute(FIELD_MEMORY.propertyName(), memory);
+ String disk = MeasurementConverterClient.format(from.getPartitionDiskUsedPercentage().getAggregate().getAvg(),
+ from.getPartitionDiskUsedPercentage().getUnits(), true);
+ record.setAttribute(FIELD_DISK.propertyName(), disk);
+ return record;
+ }
+
+
+ private ListGridRecord makeListGridRecord(MeasurementAggregateWithUnits aggregateWithUnits, String name,
+ String hover, String id) {
+ ListGridRecord record = new ListGridRecord();
+ record.setAttribute("id", id);
+ record.setAttribute(StorageNodeLoadCompositeDatasourceField.FIELD_NAME.propertyName(), name);
+ record.setAttribute(
+ StorageNodeLoadCompositeDatasourceField.FIELD_MIN.propertyName(),
+ MeasurementConverterClient.format(aggregateWithUnits.getAggregate().getMin(),
+ aggregateWithUnits.getUnits(), true));
+ record.setAttribute("avgFloat", aggregateWithUnits.getAggregate().getAvg());
+ record.setAttribute(
+ StorageNodeLoadCompositeDatasourceField.FIELD_AVG.propertyName(),
+ MeasurementConverterClient.format(aggregateWithUnits.getAggregate().getAvg(),
+ aggregateWithUnits.getUnits(), true));
+ record.setAttribute(
+ StorageNodeLoadCompositeDatasourceField.FIELD_MAX.propertyName(),
+ MeasurementConverterClient.format(aggregateWithUnits.getAggregate().getMax(),
+ aggregateWithUnits.getUnits(), true));
+ record.setAttribute("hover", hover);
return record;
}
@@ -206,11 +261,7 @@ public class StorageNodeDatasource extends RPCDataSource<StorageNode, StorageNod
private int id;
public static StorageNodeLoadCompositeDatasource getInstance(int id) {
-// if (instance == null) {
- // instance =
- return new StorageNodeLoadCompositeDatasource(id);
-// }
-// return instance;
+ return new StorageNodeLoadCompositeDatasource(id);
}
public StorageNodeLoadCompositeDatasource(int id) {
@@ -264,11 +315,9 @@ public class StorageNodeDatasource extends RPCDataSource<StorageNode, StorageNod
@Override
protected void executeFetch(final DSRequest request, final DSResponse response, StorageNodeCriteria criteria) {
-// Integer id = getFilter(request, FIELD_ID.propertyName(), Integer.class);
final StorageNode node = new StorageNode();
node.setId(id);
- GWTServiceLookup.getStorageService().getLoad(node, 8, MeasurementUtils.UNIT_HOURS,
- new AsyncCallback<StorageNodeLoadComposite>() {
+ executeFetch(node, new AsyncCallback<StorageNodeLoadComposite>() {
public void onSuccess(final StorageNodeLoadComposite loadComposite) {
ListGridRecord[] records = makeListGridRecords(loadComposite);
response.setData(records);
@@ -285,6 +334,10 @@ public class StorageNodeDatasource extends RPCDataSource<StorageNode, StorageNod
});
}
+ private static void executeFetch(final StorageNode node, final AsyncCallback<StorageNodeLoadComposite> callback) {
+ GWTServiceLookup.getStorageService().getLoad(node, 8, MeasurementUtils.UNIT_HOURS, callback);
+ }
+
private ListGridRecord[] makeListGridRecords(StorageNodeLoadComposite loadComposite) {
List<ListGridRecord> recordsList = new ArrayList<ListGridRecord>(6);
List<List<Object>> loadFields = Arrays
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDatasourceField.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDatasourceField.java
index 0382f13..ca69076 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDatasourceField.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/storage/StorageNodeDatasourceField.java
@@ -37,6 +37,10 @@ public enum StorageNodeDatasourceField {
FIELD_CQL_PORT("cqlPort", "CQL Port"),
FIELD_OPERATION_MODE("operationMode", CoreGUI.getMessages().view_adminTopology_server_mode()),
+
+ FIELD_MEMORY("memory", "Memory"),
+
+ FIELD_DISK("disk", "Disk"),
FIELD_CTIME("ctime", CoreGUI.getMessages().view_adminTopology_serverDetail_installationDate()),
commit b228fcd4ddc2a1bb032e4ba9e4096f23922fe22c
Author: Jirka Kremser <jkremser(a)redhat.com>
Date: Wed Jul 17 13:16:09 2013 +0200
Modifying the AlertHistoryView to allow display alerts of various resources (not necessarily forming a group).
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/alert/AlertHistoryView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/alert/AlertHistoryView.java
index 4c4c41f..bc74a83 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/alert/AlertHistoryView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/alert/AlertHistoryView.java
@@ -114,6 +114,26 @@ public class AlertHistoryView extends TableSection<AlertDataSource> implements H
setInitialCriteriaFixed(false);
setDataSource(new AlertDataSource(context));
}
+
+ public AlertHistoryView(String tableTitle, int[] resourceIds) {
+ super(tableTitle, new SortSpecifier[] { DEFAULT_SORT_SPECIFIER });
+
+ Criteria initialCriteria = new Criteria();
+ AlertPriority[] priorityValues = AlertPriority.values();
+ String[] priorityNames = new String[priorityValues.length];
+ for (int i = 0, priorityValuesLength = priorityValues.length; i < priorityValuesLength; i++) {
+ priorityNames[i] = priorityValues[i].name();
+ }
+ initialCriteria.addCriteria(AlertDataSource.FILTER_PRIORITIES, priorityNames);
+ initialCriteria.setAttribute("resourceIds", resourceIds);
+ setInitialCriteria(initialCriteria);
+
+ this.context = new EntityContext();
+ this.context.type = EntityContext.Type.SubsystemView;
+ this.hasWriteAccess = false;
+
+ setDataSource(new AlertDataSource(context));
+ }
@Override
protected void configureTableFilters() {
10 years, 10 months
[rhq] modules/plugins
by Thomas Segismont
modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/ConnectorComponent.java | 67 ++++---
modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/ConnectorDiscoveryComponent.java | 85 ++++++----
2 files changed, 87 insertions(+), 65 deletions(-)
New commits:
commit 089d80191b85565760a5097e2cc5336fe4e9e6bd
Author: Thomas Segismont <tsegismo(a)redhat.com>
Date: Wed Aug 7 18:53:44 2013 +0200
Bug 980639 - JBoss Web connectors are not discovered if host name contains dash/hyphen (-)
Simplified the regular expression matching connector components.
Side fix: servers started with -b [hostname] instead of -b [ip address] have connector with composed names: (myserver.com%2F127.0.0.1). It was not taken into account when trying to find the thread pool associated with it (in order to collect thread pool metrics).
Tested with EAP 5.1.2 and 5.2.0
diff --git a/modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/ConnectorComponent.java b/modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/ConnectorComponent.java
index 6b7a68f..1bb0aa9 100644
--- a/modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/ConnectorComponent.java
+++ b/modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/ConnectorComponent.java
@@ -1,24 +1,20 @@
/*
- * Jopr Management Platform
- * Copyright (C) 2005-2009 Red Hat, Inc.
+ * RHQ Management Platform
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, version 2, as
- * published by the Free Software Foundation, and/or the GNU Lesser
- * General Public License, version 2.1, also as published by the Free
- * Software Foundation.
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License and the GNU Lesser General Public License
- * for more details.
+ * GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * and the GNU Lesser General Public License along with this program;
- * if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
package org.rhq.plugins.jbossas5;
@@ -28,16 +24,16 @@ import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.rhq.core.domain.configuration.Configuration;
-import org.rhq.core.domain.measurement.MeasurementReport;
-import org.rhq.core.domain.measurement.MeasurementScheduleRequest;
-import org.rhq.plugins.jbossas5.helper.MoreKnownComponentTypes;
-import org.rhq.plugins.jbossas5.util.ResourceComponentUtils;
import org.jboss.deployers.spi.management.ManagementView;
import org.jboss.managed.api.ComponentType;
import org.jboss.managed.api.ManagedComponent;
+import org.rhq.core.domain.configuration.Configuration;
+import org.rhq.core.domain.measurement.MeasurementReport;
+import org.rhq.core.domain.measurement.MeasurementScheduleRequest;
+import org.rhq.plugins.jbossas5.helper.MoreKnownComponentTypes;
+
/**
* A ResourceComponent for managing a JBoss Web connector.
*
@@ -45,29 +41,21 @@ import org.jboss.managed.api.ManagedComponent;
*/
public class ConnectorComponent extends ManagedComponentComponent
{
- static final String PROTOCOL_PROPERTY = "protocol";
- static final String ADDRESS_PROPERTY = "address";
- static final String PORT_PROPERTY = "port";
+ private static final Log LOG = LogFactory.getLog(ConnectorComponent.class);
private static final String THREAD_POOL_METRIC_PREFIX = "ThreadPool" + PREFIX_DELIMITER;
- // A regex for the name of a particular MBean:WebThreadPool component,
- // e.g. "jboss.web:name=http-127.0.0.1-8080,type=ThreadPool"
- private static final String WEB_THREAD_POOL_COMPONENT_NAME_TEMPLATE =
- "jboss.web:name=%" + PROTOCOL_PROPERTY + "%-%" + ADDRESS_PROPERTY + "%-%" + PORT_PROPERTY + "%,"
- + "type=ThreadPool";
-
- private final Log log = LogFactory.getLog(this.getClass());
+ static final String PROTOCOL_PROPERTY = "protocol";
+ static final String HOST_PROPERTY = "host";
+ static final String ADDRESS_PROPERTY = "address";
+ static final String PORT_PROPERTY = "port";
@Override
public void getValues(MeasurementReport report, Set<MeasurementScheduleRequest> requests)
throws Exception
{
Set<MeasurementScheduleRequest> remainingRequests = new LinkedHashSet();
- Configuration pluginConfig = getResourceContext().getPluginConfiguration();
- String webThreadPoolComponentName =
- ResourceComponentUtils.replacePropertyExpressionsInTemplate(WEB_THREAD_POOL_COMPONENT_NAME_TEMPLATE,
- pluginConfig);
+ String webThreadPoolComponentName = getWebThreadPoolComponentName(getResourceContext().getPluginConfiguration());
ComponentType webThreadPoolComponentType = MoreKnownComponentTypes.MBean.WebThreadPool.getType();
ManagementView managementView = getConnection().getManagementView();
ManagedComponent webThreadPoolComponent = managementView.getComponent(webThreadPoolComponentName,
@@ -90,10 +78,25 @@ public class ConnectorComponent extends ManagedComponentComponent
catch (Exception e)
{
// Don't let one bad apple spoil the barrel.
- log.error("Failed to collect metric '" + metricName + "' for " + getResourceContext().getResourceType()
+ LOG.error("Failed to collect metric '" + metricName + "' for " + getResourceContext().getResourceType()
+ " Resource with key " + getResourceContext().getResourceKey() + ".", e);
}
}
super.getValues(report, remainingRequests);
}
-}
\ No newline at end of file
+
+ private String getWebThreadPoolComponentName(Configuration pluginConfig) {
+ StringBuilder webThreadPoolComponentNameBuilder = new StringBuilder("jboss.web:name=") //
+ .append(pluginConfig.getSimpleValue(PROTOCOL_PROPERTY)) //
+ .append("-");
+ if (pluginConfig.getSimpleValue(HOST_PROPERTY) != null) {
+ webThreadPoolComponentNameBuilder.append(pluginConfig.getSimpleValue(HOST_PROPERTY)) //
+ .append("%2F");
+ }
+ webThreadPoolComponentNameBuilder.append(pluginConfig.getSimpleValue(ADDRESS_PROPERTY)) //
+ .append("-") //
+ .append(pluginConfig.getSimpleValue(PORT_PROPERTY)) //
+ .append(",type=ThreadPool");
+ return webThreadPoolComponentNameBuilder.toString();
+ }
+}
diff --git a/modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/ConnectorDiscoveryComponent.java b/modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/ConnectorDiscoveryComponent.java
index ce63947..165e490 100644
--- a/modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/ConnectorDiscoveryComponent.java
+++ b/modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/ConnectorDiscoveryComponent.java
@@ -1,28 +1,30 @@
/*
- * Jopr Management Platform
- * Copyright (C) 2005-2009 Red Hat, Inc.
+ * RHQ Management Platform
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, version 2, as
- * published by the Free Software Foundation, and/or the GNU Lesser
- * General Public License, version 2.1, also as published by the Free
- * Software Foundation.
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License and the GNU Lesser General Public License
- * for more details.
+ * GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * and the GNU Lesser General Public License along with this program;
- * if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
package org.rhq.plugins.jbossas5;
+import static org.rhq.plugins.jbossas5.ConnectorComponent.ADDRESS_PROPERTY;
+import static org.rhq.plugins.jbossas5.ConnectorComponent.HOST_PROPERTY;
+import static org.rhq.plugins.jbossas5.ConnectorComponent.PORT_PROPERTY;
+import static org.rhq.plugins.jbossas5.ConnectorComponent.PROTOCOL_PROPERTY;
+import static org.rhq.plugins.jbossas5.ManagedComponentComponent.Config.COMPONENT_NAME;
+
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.regex.Matcher;
@@ -30,6 +32,11 @@ import java.util.regex.Pattern;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
+import org.jboss.deployers.spi.management.ManagementView;
+import org.jboss.managed.api.ComponentType;
+import org.jboss.managed.api.ManagedComponent;
+
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.domain.resource.ResourceType;
@@ -37,12 +44,8 @@ import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryComponent;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext;
import org.rhq.plugins.jbossas5.helper.MoreKnownComponentTypes;
-import org.rhq.plugins.jbossas5.util.RegularExpressionNameMatcher;
import org.rhq.plugins.jbossas5.util.ManagedComponentUtils;
-
-import org.jboss.deployers.spi.management.ManagementView;
-import org.jboss.managed.api.ComponentType;
-import org.jboss.managed.api.ManagedComponent;
+import org.rhq.plugins.jbossas5.util.RegularExpressionNameMatcher;
/**
* A component for discovering JBoss Web connectors.
@@ -52,18 +55,24 @@ import org.jboss.managed.api.ManagedComponent;
public class ConnectorDiscoveryComponent
implements ResourceDiscoveryComponent<JBossWebComponent>
{
+ private static final Log LOG = LogFactory.getLog(ConnectorDiscoveryComponent.class);
+
// A regex for the names of all MBean:WebRequestProcessor components,
// e.g. "jboss.web:name=http-127.0.0.1-8080,type=GlobalRequestProcessor"
private static final String WEB_REQUEST_PROCESSOR_COMPONENT_NAMES_REGEX =
- "jboss.web:name=([^\\-]+)-([^\\-]+)-([0-9]+),type=GlobalRequestProcessor";
+ "jboss.web:name=([^\\-]+)-(.+)-([0-9]+),type=GlobalRequestProcessor";
- private final Log log = LogFactory.getLog(this.getClass());
+ private static final Pattern WEB_REQUEST_PROCESSOR_COMPONENT_NAMES_PATTERN = Pattern
+ .compile(WEB_REQUEST_PROCESSOR_COMPONENT_NAMES_REGEX);
+
+ private static final Pattern HOSTADRESS_PATTERN = Pattern
+ .compile("(.*)(%2F)(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})");
public Set<DiscoveredResourceDetails> discoverResources(
ResourceDiscoveryContext<JBossWebComponent> discoveryContext) throws Exception
{
ResourceType resourceType = discoveryContext.getResourceType();
- log.trace("Discovering " + resourceType.getName() + " Resources...");
+ LOG.trace("Discovering " + resourceType.getName() + " Resources...");
JBossWebComponent jbossWebComponent = discoveryContext.getParentResourceComponent();
ManagementView managementView = jbossWebComponent.getConnection().getManagementView();
@@ -78,16 +87,28 @@ public class ConnectorDiscoveryComponent
{
// Parse the component name, e.g. "jboss.web:name=http-127.0.0.1-8080,type=GlobalRequestProcessor", to
// figure out the protocol, address, and port.
- Pattern pattern = Pattern.compile(WEB_REQUEST_PROCESSOR_COMPONENT_NAMES_REGEX);
- Matcher matcher = pattern.matcher(webRequestProcessorComponent.getName());
+ Matcher matcher = WEB_REQUEST_PROCESSOR_COMPONENT_NAMES_PATTERN.matcher(webRequestProcessorComponent
+ .getName());
if (!matcher.matches())
{
- log.error("Component name '" + webRequestProcessorComponent.getName() + "' does not match regex '"
- + pattern + "'.");
+ LOG.error("Component name '" + webRequestProcessorComponent.getName() + "' does not match regex '"
+ + WEB_REQUEST_PROCESSOR_COMPONENT_NAMES_PATTERN + "'.");
continue;
}
String protocol = matcher.group(1);
- String address = matcher.group(2);
+ String host = null;
+ String address = null;
+ String hostAddress = matcher.group(2);
+ Matcher hostAddressMatcher = HOSTADRESS_PATTERN.matcher(hostAddress);
+ if (hostAddressMatcher.matches()) {
+ // We have a composed host address string: my-server.com%2F127.0.0.98
+ host = hostAddressMatcher.group(1);
+ address = hostAddressMatcher.group(3);
+ } else {
+ // We only have an IP address
+ address = hostAddress;
+ }
+
int port = Integer.valueOf(matcher.group(3));
String resourceKey = protocol + "://" + address + ":" + port;
@@ -96,11 +117,11 @@ public class ConnectorDiscoveryComponent
String resourceVersion = null;
Configuration pluginConfig = discoveryContext.getDefaultPluginConfiguration();
- pluginConfig.put(new PropertySimple(ManagedComponentComponent.Config.COMPONENT_NAME,
- webRequestProcessorComponent.getName()));
- pluginConfig.put(new PropertySimple(ConnectorComponent.PROTOCOL_PROPERTY, protocol));
- pluginConfig.put(new PropertySimple(ConnectorComponent.ADDRESS_PROPERTY, address));
- pluginConfig.put(new PropertySimple(ConnectorComponent.PORT_PROPERTY, port));
+ pluginConfig.put(new PropertySimple(COMPONENT_NAME, webRequestProcessorComponent.getName()));
+ pluginConfig.put(new PropertySimple(PROTOCOL_PROPERTY, protocol));
+ pluginConfig.put(new PropertySimple(HOST_PROPERTY, host));
+ pluginConfig.put(new PropertySimple(ADDRESS_PROPERTY, address));
+ pluginConfig.put(new PropertySimple(PORT_PROPERTY, port));
DiscoveredResourceDetails resource =
new DiscoveredResourceDetails(resourceType,
@@ -114,7 +135,7 @@ public class ConnectorDiscoveryComponent
discoveredResources.add(resource);
}
- log.trace("Discovered " + discoveredResources.size() + " " + resourceType.getName() + " Resources.");
+ LOG.trace("Discovered " + discoveredResources.size() + " " + resourceType.getName() + " Resources.");
return discoveredResources;
}
@@ -122,9 +143,7 @@ public class ConnectorDiscoveryComponent
throws Exception
{
ComponentType webRequestProcessorComponentType = MoreKnownComponentTypes.MBean.WebRequestProcessor.getType();
- //return managementView.getMatchingComponents(WEB_REQUEST_PROCESSOR_COMPONENT_NAMES_REGEX,
- // webRequestProcessorComponentType, new RegularExpressionNameMatcher());
return ManagedComponentUtils.getManagedComponents(managementView, webRequestProcessorComponentType,
WEB_REQUEST_PROCESSOR_COMPONENT_NAMES_REGEX, new RegularExpressionNameMatcher());
}
-}
\ No newline at end of file
+}
10 years, 10 months
[rhq] modules/core modules/enterprise
by John Sanda
modules/core/domain/src/main/java/org/rhq/core/domain/common/composite/SystemSetting.java | 50 +++
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerBean.java | 140 ++--------
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/storage/StorageClusterSettings.java | 56 ++++
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/storage/StorageClusterSettingsManagerBean.java | 49 +++
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/system/SystemManagerBean.java | 31 +-
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/system/SystemManagerLocal.java | 11
6 files changed, 232 insertions(+), 105 deletions(-)
New commits:
commit b4cf20f66b562fb7cc911ea83e68387683468adc
Author: John Sanda <jsanda(a)redhat.com>
Date: Wed Aug 7 11:31:52 2013 -0400
store storage cluster settings in the system settings
The cluster settings are stored as read-only properties in the system settings
because they should be updated through the storage subsystem.
diff --git a/modules/core/domain/src/main/java/org/rhq/core/domain/common/composite/SystemSetting.java b/modules/core/domain/src/main/java/org/rhq/core/domain/common/composite/SystemSetting.java
index 1c2f5b9..0f2f27c 100644
--- a/modules/core/domain/src/main/java/org/rhq/core/domain/common/composite/SystemSetting.java
+++ b/modules/core/domain/src/main/java/org/rhq/core/domain/common/composite/SystemSetting.java
@@ -110,6 +110,14 @@ public enum SystemSetting {
/** The length of CoreGUI inactivity (no call to UserSessionManager.refresh()) before a CoreGUI session timeout, Default: 1 hour */
RHQ_SESSION_TIMEOUT("RHQ_SESSION_TIMEOUT", PropertySimpleType.LONG, false, true),
+ /**
+ * The STORAGE settings are all read-only and deal with shared, cluster-wide settings
+ * among storage nodes. They are read-only because they should only be updated through
+ * the storage subsystem.
+ */
+ STORAGE_CQL_PORT("STORAGE_CQL_PORT", PropertySimpleType.INTEGER, true, true),
+ STORAGE_GOSSIP_PORT("STORAGE_GOSSIP_PORT", PropertySimpleType.INTEGER, true, true),
+
//these seem to be unused yet still present in the database...
@Deprecated
HELP_USER("CAM_HELP_USER", PropertySimpleType.STRING, true, false),
@@ -162,6 +170,12 @@ public enum SystemSetting {
return isBoolean(value);
case LONG:
return isLong(value);
+ case INTEGER:
+ return isInteger(value);
+ case FLOAT:
+ return isFloat(value);
+ case DOUBLE:
+ return isDouble(value);
default:
throw new IllegalStateException("A system property '" + internalName
+ "' doesn't know how to validate its value which should have type '" + type + "'.");
@@ -199,6 +213,42 @@ public enum SystemSetting {
}
}
+ private static boolean isInteger(String value) {
+ if (value == null) {
+ return true;
+ }
+ try {
+ Integer.parseInt(value);
+ return true;
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
+
+ private static boolean isFloat(String value) {
+ if (value == null) {
+ return true;
+ }
+ try {
+ Float.parseFloat(value);
+ return true;
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
+
+ private static boolean isDouble(String value) {
+ if (value == null) {
+ return true;
+ }
+ try {
+ Double.parseDouble(value);
+ return true;
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
+
private static boolean isBoolean(String value) {
//be more strict about the values than Boolean.valueOf or Boolean.parseBoolean
return value == null || Boolean.toString(true).equalsIgnoreCase(value)
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerBean.java
index f17f006..327f064 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerBean.java
@@ -28,7 +28,6 @@ import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
@@ -46,9 +45,6 @@ import javax.persistence.TypedQuery;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.quartz.JobDataMap;
-import org.quartz.SimpleTrigger;
-import org.quartz.Trigger;
import org.rhq.cassandra.schema.SchemaManager;
import org.rhq.core.domain.alert.Alert;
@@ -94,8 +90,8 @@ import org.rhq.enterprise.server.resource.ResourceTypeManagerLocal;
import org.rhq.enterprise.server.resource.group.ResourceGroupManagerLocal;
import org.rhq.enterprise.server.rest.reporting.MeasurementConverter;
import org.rhq.enterprise.server.scheduler.SchedulerLocal;
-import org.rhq.enterprise.server.scheduler.jobs.StorageNodeMaintenanceJob;
-import org.rhq.enterprise.server.storage.StorageConfigurationException;
+import org.rhq.enterprise.server.storage.StorageClusterSettings;
+import org.rhq.enterprise.server.storage.StorageClusterSettingsManagerBean;
import org.rhq.enterprise.server.util.CriteriaQueryGenerator;
import org.rhq.enterprise.server.util.CriteriaQueryRunner;
import org.rhq.enterprise.server.util.LookupUtil;
@@ -118,6 +114,7 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
private final static String SEEDS_LIST = "seedsList";
private static final String RHQ_STORAGE_CQL_PORT_PROPERTY = "nativeTransportPort";
+ private static final String RHQ_STORAGE_GOSSIP_PORT_PROPERTY = "storagePort";
private static final String RHQ_STORAGE_JMX_PORT_PROPERTY = "jmxPort";
private static final String RHQ_STORAGE_ADDRESS_PROPERTY = "host";
@@ -159,10 +156,13 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
@EJB
private ResourceManagerLocal resourceManager;
+ @EJB
+ private StorageClusterSettingsManagerBean storageClusterSettingsManager;
+
@Override
public void linkResource(Resource resource) {
- Configuration resourceConfig = resource.getPluginConfiguration();
- String address = resourceConfig.getSimpleValue(RHQ_STORAGE_ADDRESS_PROPERTY);
+ Configuration pluginConfig = resource.getPluginConfiguration();
+ String address = pluginConfig.getSimpleValue(RHQ_STORAGE_ADDRESS_PROPERTY);
if (log.isInfoEnabled()) {
log.info("Linking " + resource + " to storage node at " + address);
@@ -176,12 +176,13 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
}
storageNode.setResource(resource);
storageNode.setOperationMode(OperationMode.NORMAL);
+ initClusterSettingsIfNecessary(pluginConfig);
addStorageNodeToGroup(resource);
} else {
storageNode = new StorageNode();
storageNode.setAddress(address);
- storageNode.setCqlPort(Integer.parseInt(resourceConfig.getSimpleValue(RHQ_STORAGE_CQL_PORT_PROPERTY)));
- storageNode.setJmxPort(Integer.parseInt(resourceConfig.getSimpleValue(RHQ_STORAGE_JMX_PORT_PROPERTY)));
+ storageNode.setCqlPort(Integer.parseInt(pluginConfig.getSimpleValue(RHQ_STORAGE_CQL_PORT_PROPERTY)));
+ storageNode.setJmxPort(Integer.parseInt(pluginConfig.getSimpleValue(RHQ_STORAGE_JMX_PORT_PROPERTY)));
storageNode.setResource(resource);
storageNode.setOperationMode(OperationMode.INSTALLED);
@@ -200,6 +201,31 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
}
}
+ private void initClusterSettingsIfNecessary(Configuration pluginConfig) {
+ // TODO Need to handle non-repeatable reads here (probably a post 4.9 task)
+ //
+ // If a user deploys two storage nodes prior to installing the RHQ server, then we
+ // could end up in this method concurrently for both storage nodes. The settings
+ // would be committed for each node with the second commit winning. The problem is
+ // that is the cluster settings differ for the two nodes, it will be silently
+ // ignored. This scenario will happen infrequently so it should be sufficient to
+ // resolve it with optimistic locking. The second writer should fail with an
+ // OptimisticLockException.
+
+ log.info("Initializing storage cluster settings");
+
+ StorageClusterSettings clusterSettings = storageClusterSettingsManager.getClusterSettings(
+ subjectManager.getOverlord());
+ if (clusterSettings != null) {
+ log.info("Cluster settings have already been set. Skipping initialization.");
+ return;
+ }
+ clusterSettings = new StorageClusterSettings();
+ clusterSettings.setCqlPort(Integer.parseInt(pluginConfig.getSimpleValue(RHQ_STORAGE_CQL_PORT_PROPERTY)));
+ clusterSettings.setGossipPort(Integer.parseInt(pluginConfig.getSimpleValue(RHQ_STORAGE_GOSSIP_PORT_PROPERTY)));
+ storageClusterSettingsManager.setClusterSettings(subjectManager.getOverlord(), clusterSettings);
+ }
+
private void announceNewNode(StorageNode newStorageNode) {
if (log.isInfoEnabled()) {
log.info("Announcing " + newStorageNode + " to storage node cluster.");
@@ -506,54 +532,6 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
return formattedValue;
}
- private List<StorageNode> parseSeedsProperty(String seedsProperty) {
- String[] seeds = seedsProperty.split(",");
- List<StorageNode> storageNodes = new ArrayList<StorageNode>();
- for (String seed : seeds) {
- StorageNode node = new StorageNode();
- node.setOperationMode(OperationMode.INSTALLED);
- node.parseNodeInformation(seed);
- storageNodes.add(node);
- }
- return storageNodes;
- }
-
- private void scheduleQuartzJob(int clusterSize) {
- String jobName = StorageNodeMaintenanceJob.class.getName();
- String jobGroupName = StorageNodeMaintenanceJob.class.getName();
- String triggerName = StorageNodeMaintenanceJob.class.getName();
- Date jobTime = new Date(System.currentTimeMillis() + 30000);
-
- Trigger trigger = new SimpleTrigger(triggerName, jobGroupName, jobTime);
- trigger.setJobName(jobName);
- trigger.setJobGroup(jobGroupName);
- try {
- JobDataMap jobDataMap = new JobDataMap();
- jobDataMap.put(StorageNodeMaintenanceJob.JOB_DATA_PROPERTY_CLUSTER_SIZE, Integer.toString(clusterSize));
- trigger.setJobDataMap(jobDataMap);
-
- quartzScheduler.scheduleJob(trigger);
- } catch (Throwable t) {
- log.warn("Unable to schedule storage node maintenance job", t);
- }
- }
-
- private void updateStorageNodes(Map<String, StorageNode> storageNodeMap) {
- for (Map.Entry<String, StorageNode> storageNodeEntry : storageNodeMap.entrySet()) {
- TypedQuery<StorageNode> query = entityManager.<StorageNode> createNamedQuery(
- StorageNode.QUERY_FIND_BY_ADDRESS, StorageNode.class);
- query.setParameter("address", storageNodeEntry.getKey());
- List<StorageNode> result = query.getResultList();
- if (!result.isEmpty()) {
- storageNodeEntry.getValue().setId(result.get(0).getId());
- entityManager.merge(storageNodeEntry.getValue());
- } else {
- entityManager.persist(storageNodeEntry.getValue());
- }
- }
- entityManager.flush();
- }
-
private StorageNodeLoadComposite.MeasurementAggregateWithUnits getMeasurementAggregateWithUnits(Subject subject,
int schedId, MeasurementUnits units, long beginTime, long endTime) {
MeasurementAggregate measurementAggregate = measurementManager.getAggregate(subject, schedId, beginTime,
@@ -855,17 +833,17 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
log.info("Preparing to bootstrap " + storageNode + " into cluster...");
}
- List<StorageNode> existingStorageNodes = getClusteredStorageNodes();
-
ResourceOperationSchedule schedule = new ResourceOperationSchedule();
schedule.setResource(storageNode.getResource());
schedule.setJobTrigger(JobTrigger.createNowTrigger());
schedule.setSubject(subjectManager.getOverlord());
schedule.setOperationName("prepareForBootstrap");
+ StorageClusterSettings clusterSettings = storageClusterSettingsManager.getClusterSettings(
+ subjectManager.getOverlord());
Configuration parameters = new Configuration();
- parameters.put(new PropertySimple("cqlPort", existingStorageNodes.get(0).getCqlPort()));
- parameters.put(new PropertySimple("gossipPort", getGossipPort(storageNode, existingStorageNodes)));
+ parameters.put(new PropertySimple("cqlPort", clusterSettings.getCqlPort()));
+ parameters.put(new PropertySimple("gossipPort", clusterSettings.getGossipPort()));
parameters.put(createPropertyListOfAddresses("storageNodeIPAddresses", getClusteredStorageNodes()));
schedule.setParameters(parameters);
@@ -873,44 +851,6 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
operationManager.scheduleResourceOperation(subjectManager.getOverlord(), schedule);
}
- private Integer getGossipPort(StorageNode newStorageNode, List<StorageNode> storageNodes) {
- if (log.isInfoEnabled()) {
- log.info("Looking up gossip port for new storage node " + newStorageNode);
- }
- try {
- StorageNode node = null;
- Configuration resourceConfig = null;
- for (StorageNode storageNode : storageNodes) {
- resourceConfig = configurationManager.getLiveResourceConfiguration(subjectManager.getOverlord(),
- storageNode.getResource().getId(), false);
- if (resourceConfig == null) {
- log.warn("Failed to load resource configuration for storage node " + newStorageNode.getResource());
- } else {
- node = storageNode;
- break;
- }
- }
- if (resourceConfig == null) {
- log.error("Failed to obtain gossip port from existing storage nodes");
- throw new StorageConfigurationException("Failed to obtain gossip port from existing storage nodes");
- }
-
- PropertySimple property = resourceConfig.getSimple("gossipPort");
- if (property == null) {
- throw new StorageConfigurationException("The resource configuration for " + node.getResource() +
- "did not include the required property [gossipPort]");
- }
- Integer port = property.getIntegerValue();
- log.info("Found gossip port set to " + port);
- return property.getIntegerValue();
- } catch (Exception e) {
- if (e instanceof StorageConfigurationException) {
- throw (StorageConfigurationException) e;
- }
- throw new RuntimeException("An error occurred while trying to obtain the gossip port", e);
- }
- }
-
@Override
public void runAddNodeMaintenance() {
log.info("Preparing to schedule addNodeMaintenance on the storage cluster...");
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/storage/StorageClusterSettings.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/storage/StorageClusterSettings.java
new file mode 100644
index 0000000..2098acd
--- /dev/null
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/storage/StorageClusterSettings.java
@@ -0,0 +1,56 @@
+package org.rhq.enterprise.server.storage;
+
+import java.io.Serializable;
+
+/**
+ * @author John Sanda
+ */
+public class StorageClusterSettings implements Serializable {
+
+ private static final long serialVersionUID = 1;
+
+ private int cqlPort;
+
+ private int gossipPort;
+
+ public int getCqlPort() {
+ return cqlPort;
+ }
+
+ public void setCqlPort(int cqlPort) {
+ this.cqlPort = cqlPort;
+ }
+
+ public int getGossipPort() {
+ return gossipPort;
+ }
+
+ public void setGossipPort(int gossipPort) {
+ this.gossipPort = gossipPort;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ StorageClusterSettings that = (StorageClusterSettings) o;
+
+ if (cqlPort != that.cqlPort) return false;
+ if (gossipPort != that.gossipPort) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = cqlPort;
+ result = 29 * result + gossipPort;
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "StorageClusterSettings[cqlPort=" + cqlPort + ", gossipPort=" + gossipPort + "]";
+ }
+}
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/storage/StorageClusterSettingsManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/storage/StorageClusterSettingsManagerBean.java
new file mode 100644
index 0000000..e6b1fb7
--- /dev/null
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/storage/StorageClusterSettingsManagerBean.java
@@ -0,0 +1,49 @@
+package org.rhq.enterprise.server.storage;
+
+import java.util.Map;
+
+import javax.ejb.EJB;
+import javax.ejb.Singleton;
+
+import org.rhq.core.domain.auth.Subject;
+import org.rhq.core.domain.common.composite.SystemSetting;
+import org.rhq.core.domain.common.composite.SystemSettings;
+import org.rhq.enterprise.server.system.SystemManagerLocal;
+
+/**
+ * @author John Sanda
+ */
+@Singleton
+public class StorageClusterSettingsManagerBean {
+
+ @EJB
+ private SystemManagerLocal systemManager;
+
+ public StorageClusterSettings getClusterSettings(Subject subject) {
+ SystemSettings settings = systemManager.getSystemSettings(subject);
+ Map<String, String> settingsMap = settings.toMap();
+ StorageClusterSettings clusterSettings = new StorageClusterSettings();
+
+ if (!settingsMap.containsKey(SystemSetting.STORAGE_CQL_PORT)) {
+ return null;
+ } else {
+ clusterSettings.setCqlPort(Integer.parseInt(settingsMap.get(SystemSetting.STORAGE_CQL_PORT)));
+ }
+
+ if (!settingsMap.containsKey(SystemSetting.STORAGE_GOSSIP_PORT)) {
+ return null;
+ } else {
+ clusterSettings.setGossipPort(Integer.parseInt(settingsMap.get(SystemSetting.STORAGE_GOSSIP_PORT)));
+ }
+
+ return clusterSettings;
+ }
+
+ public void setClusterSettings(Subject subject, StorageClusterSettings clusterSettings) {
+ SystemSettings settings = new SystemSettings();
+ settings.put(SystemSetting.STORAGE_CQL_PORT, Integer.toString(clusterSettings.getCqlPort()));
+ settings.put(SystemSetting.STORAGE_GOSSIP_PORT, Integer.toString(clusterSettings.getGossipPort()));
+ systemManager.setStorageClusterSettings(subject, settings);
+ }
+
+}
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/system/SystemManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/system/SystemManagerBean.java
index dcc81d5..aabd62b 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/system/SystemManagerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/system/SystemManagerBean.java
@@ -200,10 +200,22 @@ public class SystemManagerBean implements SystemManagerLocal, SystemManagerRemot
@RequiredPermission(Permission.MANAGE_SETTINGS)
public void setSystemSettings(Subject subject, SystemSettings settings) {
- setSystemSettings(settings, false);
+ setSystemSettings(settings, false, false);
}
- private void setSystemSettings(SystemSettings settings, boolean skipValidation) {
+ @RequiredPermission(Permission.MANAGE_SETTINGS)
+ @Override
+ public void setStorageClusterSettings(Subject subject, SystemSettings settings) {
+ for (SystemSetting setting : settings.keySet()) {
+ if (!isStorageSetting(setting)) {
+ throw new IllegalArgumentException(setting + " cannot be updated through this method. This method " +
+ "only allows updating of storage cluster settings.");
+ }
+ }
+ setSystemSettings(settings, false, true);
+ }
+
+ private void setSystemSettings(SystemSettings settings, boolean skipValidation, boolean updateStorageSettings) {
// first, we need to get the current settings so we'll know if we need to persist or merge the new ones
@SuppressWarnings("unchecked")
List<SystemConfiguration> configs = entityManager.createNamedQuery(SystemConfiguration.QUERY_FIND_ALL)
@@ -246,8 +258,9 @@ public class SystemManagerBean implements SystemManagerLocal, SystemManagerRemot
if ((existingValue == null && value != null) || !existingValue.equals(value)) {
//SystemSetting#isReadOnly should be a superset of the "fReadOnly" field in the database
//but let's just be super paranoid here...
- if (prop.isReadOnly()
- || (existingConfig.getFreadOnly() != null && existingConfig.getFreadOnly().booleanValue())) {
+ if ((prop.isReadOnly()
+ || (existingConfig.getFreadOnly() != null && existingConfig.getFreadOnly().booleanValue())) &&
+ !(isStorageSetting(prop) || updateStorageSettings)) {
throw new IllegalArgumentException("The setting [" + prop.getInternalName()
+ "] is read-only - you cannot change its current value! Current value is ["
+ existingConfig.getPropertyValue() + "] while the new value was [" + value + "].");
@@ -269,6 +282,14 @@ public class SystemManagerBean implements SystemManagerLocal, SystemManagerRemot
cachedSystemSettings = null;
}
+ private boolean isStorageSetting(SystemSetting setting) {
+ switch (setting) {
+ case STORAGE_CQL_PORT: return true;
+ case STORAGE_GOSSIP_PORT: return true;
+ default: return false;
+ }
+ }
+
private Map<String, String> toMap(Properties props) {
HashMap<String, String> map = new HashMap<String, String>(props.size());
for (Map.Entry<Object, Object> entry : props.entrySet()) {
@@ -367,7 +388,7 @@ public class SystemManagerBean implements SystemManagerLocal, SystemManagerRemot
SystemSettings settings = SystemSettings.fromMap(map);
- setSystemSettings(settings, skipValidation);
+ setSystemSettings(settings, skipValidation, false);
}
@RequiredPermission(Permission.MANAGE_SETTINGS)
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/system/SystemManagerLocal.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/system/SystemManagerLocal.java
index 1c5dc83..9f48985 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/system/SystemManagerLocal.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/system/SystemManagerLocal.java
@@ -24,6 +24,7 @@ import javax.ejb.Local;
import org.rhq.core.db.DatabaseType;
import org.rhq.core.domain.auth.Subject;
+import org.rhq.core.domain.common.composite.SystemSettings;
/**
* Provides access to the server cloud's system configuration as well as some methods
@@ -141,4 +142,14 @@ public interface SystemManagerLocal extends SystemManagerRemote {
void dumpSystemInfo(Subject subject);
+ /**
+ * The storage cluster settings are stored as read-only system settings. They should be updated through the storage
+ * subsystem. This API is provided for use ONLY by the storage subsystem.
+ *
+ * @param subject The user who wants to change the settings
+ * @param settings The new storage cluster settings
+ * @throws IllegalArgumentException If the settings contain anything other than storage cluster settings.
+ */
+ void setStorageClusterSettings(Subject subject, SystemSettings settings);
+
}
\ No newline at end of file
10 years, 10 months