diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 7f37a4ec889..93be4288c29 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -7,6 +7,29 @@ Changelog --------- +v2.3 +==== + +API changes and deprecations +---------------------------- + +* ``helpers.get_action()`` (or ``h.get_action()`` in templates) is deprecated. + + Since action functions raise exceptions and templates cannot catch + exceptions, it's not a good idea to call action functions from templates. + + Instead, have your controller method call the action function and pass the + result to your template using the ``extra_vars`` param of ``render()``. + + Alternatively you can wrap individual action functions in custom template + helper functions that handle any exceptions appropriately, but this is likely + to make your the logic in your templates more complex and templates are + difficult to test and debug. + + Note that logic.get_action() and toolkit.get_action() are *not* deprecated, + core code and plugin code should still use ``get_action()``. + + v2.2 2014-02-04 =============== diff --git a/README.rst b/README.rst index e5024520786..bce027b8506 100644 --- a/README.rst +++ b/README.rst @@ -60,7 +60,7 @@ others, make a new page on the `CKAN wiki`_, and tell us about it on Copying and License ------------------- -This material is copyright (c) 2006-2013 Open Knowledge Foundation. +This material is copyright (c) 2006-2014 Open Knowledge Foundation. It is open and licensed under the GNU Affero General Public License (AGPL) v3.0 whose full text may be found at: diff --git a/ckan/controllers/related.py b/ckan/controllers/related.py index 3bc6b82acb8..ed24857aed1 100644 --- a/ckan/controllers/related.py +++ b/ckan/controllers/related.py @@ -116,6 +116,8 @@ def list(self, id): try: c.pkg_dict = logic.get_action('package_show')(context, data_dict) + c.related_list = logic.get_action('related_list')(context, + data_dict) c.pkg = context['package'] c.resources_json = h.json.dumps(c.pkg_dict.get('resources', [])) except logic.NotFound: diff --git a/ckan/lib/cli.py b/ckan/lib/cli.py index d4bb3655178..ce4997cd4a3 100644 --- a/ckan/lib/cli.py +++ b/ckan/lib/cli.py @@ -147,10 +147,12 @@ def _load_config(self): self.registry.register(pylons.c, c) - self.site_user = logic.get_action('get_site_user')({'ignore_auth': True}, {}) + self.site_user = logic.get_action('get_site_user')({'ignore_auth': True, + 'defer_commit': True}, {}) pylons.c.user = self.site_user['name'] pylons.c.userobj = model.User.get(self.site_user['name']) + model.repo.commit_and_remove() ## give routes enough information to run url_for parsed = urlparse.urlparse(conf.get('ckan.site_url', 'http://0.0.0.0')) diff --git a/ckan/lib/dictization/model_save.py b/ckan/lib/dictization/model_save.py index 086bcf7e8e2..48ddb4cb65d 100644 --- a/ckan/lib/dictization/model_save.py +++ b/ckan/lib/dictization/model_save.py @@ -381,14 +381,13 @@ def group_member_save(context, group_dict, member_table_name): return processed -def group_dict_save(group_dict, context): +def group_dict_save(group_dict, context, prevent_packages_update=False): from ckan.lib.search import rebuild model = context["model"] session = context["session"] group = context.get("group") allow_partial_update = context.get("allow_partial_update", False) - prevent_packages_update = context.get("prevent_packages_update", False) Group = model.Group if group: @@ -418,14 +417,6 @@ def group_dict_save(group_dict, context): 'Groups: %r Tags: %r', pkgs_edited, group_users_changed, group_groups_changed, group_tags_changed) - # We will get a list of packages that we have either added or - # removed from the group, and trigger a re-index. - package_ids = pkgs_edited['removed'] - package_ids.extend( pkgs_edited['added'] ) - if package_ids: - session.commit() - map( rebuild, package_ids ) - extras = group_extras_save(group_dict.get("extras", {}), context) if extras or not allow_partial_update: old_extras = set(group.extras.keys()) @@ -435,6 +426,14 @@ def group_dict_save(group_dict, context): for key in new_extras: group.extras[key] = extras[key] + # We will get a list of packages that we have either added or + # removed from the group, and trigger a re-index. + package_ids = pkgs_edited['removed'] + package_ids.extend( pkgs_edited['added'] ) + if package_ids: + session.commit() + map( rebuild, package_ids ) + return group diff --git a/ckan/lib/helpers.py b/ckan/lib/helpers.py index 29a06df647d..d8676c3a0fe 100644 --- a/ckan/lib/helpers.py +++ b/ckan/lib/helpers.py @@ -737,8 +737,12 @@ def check_access(action, data_dict=None): return authorized +@maintain.deprecated("helpers.get_action() is deprecated and will be removed " + "in a future version of CKAN. Instead, please use the " + "extra_vars param to render() in your controller to pass " + "results from action functions to your templates.") def get_action(action_name, data_dict=None): - '''Calls an action function from a template.''' + '''Calls an action function from a template. Deprecated in CKAN 2.3.''' if data_dict is None: data_dict = {} return logic.get_action(action_name)({}, data_dict) @@ -1923,6 +1927,15 @@ def unified_resource_format(format): def check_config_permission(permission): return new_authz.check_config_permission(permission) + +def get_organization(org=None): + if org is None: + return {} + try: + return logic.get_action('organization_show')({}, {'id': org}) + except (NotFound, ValidationError, NotAuthorized): + return {} + # these are the functions that will end up in `h` template helpers __allowed_functions__ = [ # functions defined in ckan.lib.helpers @@ -2015,6 +2028,7 @@ def check_config_permission(permission): 'list_dict_filter', 'new_activities', 'time_ago_from_timestamp', + 'get_organization', 'has_more_facets', # imported into ckan.lib.helpers 'literal', diff --git a/ckan/logic/action/create.py b/ckan/logic/action/create.py index 7b34a722585..0cbae7ea10f 100644 --- a/ckan/logic/action/create.py +++ b/ckan/logic/action/create.py @@ -1317,7 +1317,8 @@ def _group_or_org_member_create(context, data_dict, is_org=False): member_create_context = { 'model': model, 'user': user, - 'session': session + 'session': session, + 'ignore_auth': context.get('ignore_auth'), } logic.get_action('member_create')(member_create_context, member_dict) diff --git a/ckan/logic/action/get.py b/ckan/logic/action/get.py index 8e2b0349071..def8c14ff17 100644 --- a/ckan/logic/action/get.py +++ b/ckan/logic/action/get.py @@ -2087,6 +2087,16 @@ def term_translation_show(context, data_dict): # Only internal services are allowed to call get_site_user. def get_site_user(context, data_dict): + '''Return the ckan site user + + :param defer_commit: by default (or if set to false) get_site_user will + commit and clean up the current transaction, it will also close and + discard the current session in the context. If set to true, caller + is responsible for commiting transaction after get_site_user is + called. Leaving open connections can cause cli commands to hang! + (optional, default: False) + :type defer_commit: boolean + ''' _check_access('get_site_user', context, data_dict) model = context['model'] site_id = config.get('ckan.site_id', 'ckan_site_user') diff --git a/ckan/logic/action/update.py b/ckan/logic/action/update.py index 74f017f535d..654869e3293 100644 --- a/ckan/logic/action/update.py +++ b/ckan/logic/action/update.py @@ -614,14 +614,8 @@ def _group_or_org_update(context, data_dict, is_org=False): else: rev.message = _(u'REST API: Update object %s') % data.get("name") - # when editing an org we do not want to update the packages if using the - # new templates. - if ((not is_org) - and not converters.asbool( - config.get('ckan.legacy_templates', False)) - and 'api_version' not in context): - context['prevent_packages_update'] = True - group = model_save.group_dict_save(data, context) + group = model_save.group_dict_save(data, context, + prevent_packages_update=is_org) if is_org: plugin_type = plugins.IOrganizationController @@ -708,6 +702,9 @@ def organization_update(context, data_dict): :param id: the name or id of the organization to update :type id: string + :param packages: ignored. use + :py:func:`~ckan.logic.action.update.package_owner_org_update` + to change package ownership :returns: the updated organization :rtype: dictionary diff --git a/ckan/new_tests/helpers.py b/ckan/new_tests/helpers.py index 56695ed9c0b..e6799fe0ece 100644 --- a/ckan/new_tests/helpers.py +++ b/ckan/new_tests/helpers.py @@ -17,6 +17,10 @@ This module is reserved for these very useful functions. ''' +import pylons.config as config +import webtest + +import ckan.config.middleware import ckan.model as model import ckan.logic as logic @@ -120,3 +124,16 @@ def call_auth(auth_name, context, **kwargs): 'context dict') return logic.check_access(auth_name, context, data_dict=kwargs) + + +def _get_test_app(): + '''Return a webtest.TestApp for CKAN, with legacy templates disabled. + + For functional tests that need to request CKAN pages or post to the API. + Unit tests shouldn't need this. + + ''' + config['ckan.legacy_templates'] = False + app = ckan.config.middleware.make_app(config['global_conf'], **config) + app = webtest.TestApp(app) + return app diff --git a/ckan/new_tests/logic/action/test_update.py b/ckan/new_tests/logic/action/test_update.py index 763e773694b..d4939d039fb 100644 --- a/ckan/new_tests/logic/action/test_update.py +++ b/ckan/new_tests/logic/action/test_update.py @@ -101,7 +101,7 @@ def test_user_update_with_invalid_name(self): user = factories.User() invalid_names = ('', 'a', False, 0, -1, 23, 'new', 'edit', 'search', - 'a'*200, 'Hi!', 'i++%') + 'a' * 200, 'Hi!', 'i++%') for name in invalid_names: user['name'] = name nose.tools.assert_raises(logic.ValidationError, diff --git a/ckan/new_tests/logic/test_validators.py b/ckan/new_tests/logic/test_validators.py index 2020afc06c7..e663c58169a 100644 --- a/ckan/new_tests/logic/test_validators.py +++ b/ckan/new_tests/logic/test_validators.py @@ -163,7 +163,7 @@ def test_name_validator_with_invalid_value(self): ('a', 2, False), [13, None, True], {'foo': 'bar'}, - lambda x: x**2, + lambda x: x ** 2, # Certain reserved strings aren't allowed as names. 'new', @@ -241,7 +241,7 @@ def test_user_name_validator_with_non_string_value(self): ('a', 2, False), [13, None, True], {'foo': 'bar'}, - lambda x: x**2, + lambda x: x ** 2, ] # Mock ckan.model. diff --git a/ckan/plugins/interfaces.py b/ckan/plugins/interfaces.py index 1fc964024bb..4e5fc3e6f61 100644 --- a/ckan/plugins/interfaces.py +++ b/ckan/plugins/interfaces.py @@ -180,7 +180,7 @@ def after_rollback(self, session): class IDomainObjectModification(Interface): """ - Receives notification of new, changed and deleted datesets. + Receives notification of new, changed and deleted datasets. """ def notify(self, entity, operation): diff --git a/ckan/public/base/javascript/modules/custom-fields.js b/ckan/public/base/javascript/modules/custom-fields.js index 3bd6daa0646..e26ea01c3c2 100644 --- a/ckan/public/base/javascript/modules/custom-fields.js +++ b/ckan/public/base/javascript/modules/custom-fields.js @@ -90,14 +90,14 @@ this.ckan.module('custom-fields', function (jQuery, _) { */ _onChange: function (event) { if (event.target.value !== '') { - var parent = jQuery(event.target).parents('.control-custom'); + var parent = jQuery(event.target).parents(this.options.fieldSelector); this.newField(parent); } }, /* Event handler called when the remove checkbox is checked */ _onRemove: function (event) { - var parent = jQuery(event.target).parents('.control-custom'); + var parent = jQuery(event.target).parents(this.options.fieldSelector); this.disableField(parent, event.target.checked); } }; diff --git a/ckan/public/base/javascript/modules/image-upload.js b/ckan/public/base/javascript/modules/image-upload.js index 47f38fb240e..e6cb99cd31a 100644 --- a/ckan/public/base/javascript/modules/image-upload.js +++ b/ckan/public/base/javascript/modules/image-upload.js @@ -17,18 +17,8 @@ this.ckan.module('image-upload', function($, _) { remove: _('Remove'), upload_label: _('Image'), upload_tooltip: _('Upload a file on your computer'), - url_tooltip: _('Link to a URL on the internet (you can also link to an API)'), - remove_tooltip: _('Reset this') - }, - template: [ - '' - ].join("\n") - }, - - state: { - attached: 1, - blank: 2, - web: 3 + url_tooltip: _('Link to a URL on the internet (you can also link to an API)') + } }, /* Initialises the module setting up elements and event listeners. @@ -47,6 +37,7 @@ this.ckan.module('image-upload', function($, _) { this.input = $(field_upload, this.el); this.field_url = $(field_url, this.el).parents('.control-group'); this.field_image = this.input.parents('.control-group'); + this.field_url_input = $('input', this.field_url); // Is there a clear checkbox on the form already? var checkbox = $(field_clear, this.el); @@ -69,17 +60,11 @@ this.ckan.module('image-upload', function($, _) { this.button_upload = $(''+this.i18n('upload')+'') .insertAfter(this.input); - // Button to reset the form back to the first from when there is a image uploaded - this.button_remove = $('') - .text(this.i18n('remove')) - .on('click', this._onRemove) - .insertAfter(this.button_upload); - // Button for resetting the form when there is a URL set $('') - .prop('title', this.i18n('remove_tooltip')) + .prop('title', this.i18n('remove')) .on('click', this._onRemove) - .insertBefore($('input', this.field_url)); + .insertBefore(this.field_url_input); // Update the main label $('label[for="field-image-upload"]').text(options.upload_label || this.i18n('upload_label')); @@ -94,49 +79,19 @@ this.ckan.module('image-upload', function($, _) { // Fields storage. Used in this.changeState this.fields = $('') - .add(this.button_remove) .add(this.button_upload) .add(this.button_url) .add(this.input) .add(this.field_url) .add(this.field_image); - // Setup the initial state if (options.is_url) { - this.changeState(this.state.web); + this._showOnlyFieldUrl(); } else if (options.is_upload) { - this.changeState(this.state.attached); + this._showOnlyFieldUrl(); + this.field_url_input.prop('readonly', true); } else { - this.changeState(this.state.blank); - } - - }, - - /* Method to change the display state of the image fields - * - * state - Pseudo constant for passing the state we should be in now - * - * Examples - * - * this.changeState(this.state.web); // Sets the state in URL mode - * - * Returns nothing. - */ - changeState: function(state) { - this.fields.hide(); - if (state == this.state.blank) { - this.button_upload - .add(this.field_image) - .add(this.button_url) - .add(this.input) - .show(); - } else if (state == this.state.attached) { - this.button_remove - .add(this.field_image) - .show(); - } else if (state == this.state.web) { - this.field_url - .show(); + this._showOnlyButtons(); } }, @@ -145,8 +100,8 @@ this.ckan.module('image-upload', function($, _) { * Returns nothing. */ _onFromWeb: function() { - this.changeState(this.state.web); - $('input', this.field_url).focus(); + this._showOnlyFieldUrl(); + this.field_url_input.focus(); if (this.options.is_upload) { this.field_clear.val('true'); } @@ -157,8 +112,9 @@ this.ckan.module('image-upload', function($, _) { * Returns nothing. */ _onRemove: function() { - this.changeState(this.state.blank); - $('input', this.field_url).val(''); + this._showOnlyButtons(); + this.field_url_input.val(''); + this.field_url_input.prop('readonly', false); this.field_clear.val('true'); }, @@ -167,9 +123,33 @@ this.ckan.module('image-upload', function($, _) { * Returns nothing. */ _onInputChange: function() { - this.file_name = this.input.val(); + var file_name = this.input.val().split(/^C:\\fakepath\\/).pop(); + this.field_url_input.val(file_name); + this.field_url_input.prop('readonly', true); this.field_clear.val(''); - this.changeState(this.state.attached); + this._showOnlyFieldUrl(); + }, + + /* Show only the buttons, hiding all others + * + * Returns nothing. + */ + _showOnlyButtons: function() { + this.fields.hide(); + this.button_upload + .add(this.field_image) + .add(this.button_url) + .add(this.input) + .show(); + }, + + /* Show only the URL field, hiding all others + * + * Returns nothing. + */ + _showOnlyFieldUrl: function() { + this.fields.hide(); + this.field_url.show(); }, /* Event listener for when a user mouseovers the hidden file input @@ -188,5 +168,5 @@ this.ckan.module('image-upload', function($, _) { this.button_upload.removeClass('hover'); } - } + }; }); diff --git a/ckan/public/base/less/forms.less b/ckan/public/base/less/forms.less index bf45350340f..e85a25c72ce 100644 --- a/ckan/public/base/less/forms.less +++ b/ckan/public/base/less/forms.less @@ -681,6 +681,9 @@ textarea { } .js .image-upload { + #field-image-url { + padding-right: 29px; + } #field-image-upload { cursor: pointer; position: absolute; diff --git a/ckan/public/base/vendor/jquery.min.js b/ckan/public/base/vendor/jquery.min.js index 64373a7ac36..987d0be2f89 100644 --- a/ckan/public/base/vendor/jquery.min.js +++ b/ckan/public/base/vendor/jquery.min.js @@ -1,612 +1,627 @@ -(function(window,undefined){var document=window.document,navigator=window.navigator,location=window.location;var jQuery=(function(){var jQuery=function(selector,context){return new jQuery.fn.init(selector,context,rootjQuery);},_jQuery=window.jQuery,_$=window.$,rootjQuery,quickExpr=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,rnotwhite=/\S/,trimLeft=/^\s+/,trimRight=/\s+$/,rsingleTag=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,rvalidchars=/^[\],:{}\s]*$/,rvalidescape=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,rvalidtokens=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,rvalidbraces=/(?:^|:|,)(?:\s*\[)+/g,rwebkit=/(webkit)[ \/]([\w.]+)/,ropera=/(opera)(?:.*version)?[ \/]([\w.]+)/,rmsie=/(msie) ([\w.]+)/,rmozilla=/(mozilla)(?:.*? rv:([\w.]+))?/,rdashAlpha=/-([a-z]|[0-9])/ig,rmsPrefix=/^-ms-/,fcamelCase=function(all,letter){return(letter+"").toUpperCase();},userAgent=navigator.userAgent,browserMatch,readyList,DOMContentLoaded,toString=Object.prototype.toString,hasOwn=Object.prototype.hasOwnProperty,push=Array.prototype.push,slice=Array.prototype.slice,trim=String.prototype.trim,indexOf=Array.prototype.indexOf,class2type={};jQuery.fn=jQuery.prototype={constructor:jQuery,init:function(selector,context,rootjQuery){var match,elem,ret,doc;if(!selector){return this;} -if(selector.nodeType){this.context=this[0]=selector;this.length=1;return this;} -if(selector==="body"&&!context&&document.body){this.context=document;this[0]=document.body;this.selector=selector;this.length=1;return this;} -if(typeof selector==="string"){if(selector.charAt(0)==="<"&&selector.charAt(selector.length-1)===">"&&selector.length>=3){match=[null,selector,null];}else{match=quickExpr.exec(selector);} -if(match&&(match[1]||!context)){if(match[1]){context=context instanceof jQuery?context[0]:context;doc=(context?context.ownerDocument||context:document);ret=rsingleTag.exec(selector);if(ret){if(jQuery.isPlainObject(context)){selector=[document.createElement(ret[1])];jQuery.fn.attr.call(selector,context,true);}else{selector=[doc.createElement(ret[1])];}}else{ret=jQuery.buildFragment([match[1]],[doc]);selector=(ret.cacheable?jQuery.clone(ret.fragment):ret.fragment).childNodes;} -return jQuery.merge(this,selector);}else{elem=document.getElementById(match[2]);if(elem&&elem.parentNode){if(elem.id!==match[2]){return rootjQuery.find(selector);} +(function(window,undefined){var +readyList,rootjQuery,core_strundefined=typeof undefined,location=window.location,document=window.document,docElem=document.documentElement,_jQuery=window.jQuery,_$=window.$,class2type={},core_deletedIds=[],core_version="1.10.2",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,jQuery=function(selector,context){return new jQuery.fn.init(selector,context,rootjQuery);},core_pnum=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,core_rnotwhite=/\S+/g,rtrim=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,rquickExpr=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,rsingleTag=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,rvalidchars=/^[\],:{}\s]*$/,rvalidbraces=/(?:^|:|,)(?:\s*\[)+/g,rvalidescape=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,rvalidtokens=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,rmsPrefix=/^-ms-/,rdashAlpha=/-([\da-z])/gi,fcamelCase=function(all,letter){return letter.toUpperCase();},completed=function(event){if(document.addEventListener||event.type==="load"||document.readyState==="complete"){detach();jQuery.ready();}},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={jquery:core_version,constructor:jQuery,init:function(selector,context,rootjQuery){var match,elem;if(!selector){return this;} +if(typeof selector==="string"){if(selector.charAt(0)==="<"&&selector.charAt(selector.length-1)===">"&&selector.length>=3){match=[null,selector,null];}else{match=rquickExpr.exec(selector);} +if(match&&(match[1]||!context)){if(match[1]){context=context instanceof jQuery?context[0]:context;jQuery.merge(this,jQuery.parseHTML(match[1],context&&context.nodeType?context.ownerDocument||context:document,true));if(rsingleTag.test(match[1])&&jQuery.isPlainObject(context)){for(match in context){if(jQuery.isFunction(this[match])){this[match](context[match]);}else{this.attr(match,context[match]);}}} +return this;}else{elem=document.getElementById(match[2]);if(elem&&elem.parentNode){if(elem.id!==match[2]){return rootjQuery.find(selector);} this.length=1;this[0]=elem;} -this.context=document;this.selector=selector;return this;}}else if(!context||context.jquery){return(context||rootjQuery).find(selector);}else{return this.constructor(context).find(selector);}}else if(jQuery.isFunction(selector)){return rootjQuery.ready(selector);} +this.context=document;this.selector=selector;return this;}}else if(!context||context.jquery){return(context||rootjQuery).find(selector);}else{return this.constructor(context).find(selector);}}else if(selector.nodeType){this.context=this[0]=selector;this.length=1;return this;}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);},selector:"",jquery:"1.7.2",length:0,size:function(){return this.length;},toArray:function(){return slice.call(this,0);},get:function(num){return num==null?this.toArray():(num<0?this[this.length+num]:this[num]);},pushStack:function(elems,name,selector){var ret=this.constructor();if(jQuery.isArray(elems)){push.apply(ret,elems);}else{jQuery.merge(ret,elems);} -ret.prevObject=this;ret.context=this.context;if(name==="find"){ret.selector=this.selector+(this.selector?" ":"")+selector;}else if(name){ret.selector=this.selector+"."+name+"("+selector+")";} -return ret;},each:function(callback,args){return jQuery.each(this,callback,args);},ready:function(fn){jQuery.bindReady();readyList.add(fn);return this;},eq:function(i){i=+i;return i===-1?this.slice(i):this.slice(i,i+1);},first:function(){return this.eq(0);},last:function(){return this.eq(-1);},slice:function(){return this.pushStack(slice.apply(this,arguments),"slice",slice.call(arguments).join(","));},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);},push:push,sort:[].sort,splice:[].splice};jQuery.fn.init.prototype=jQuery.fn;jQuery.extend=jQuery.fn.extend=function(){var options,name,src,copy,copyIsArray,clone,target=arguments[0]||{},i=1,length=arguments.length,deep=false;if(typeof target==="boolean"){deep=target;target=arguments[1]||{};i=2;} +return jQuery.makeArray(selector,this);},selector:"",length:0,toArray:function(){return core_slice.call(this);},get:function(num){return num==null?this.toArray():(num<0?this[this.length+num]:this[num]);},pushStack:function(elems){var ret=jQuery.merge(this.constructor(),elems);ret.prevObject=this;ret.context=this.context;return ret;},each:function(callback,args){return jQuery.each(this,callback,args);},ready:function(fn){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&&j0){return;} -readyList.fireWith(document,[jQuery]);if(jQuery.fn.trigger){jQuery(document).trigger("ready").off("ready");}}},bindReady:function(){if(readyList){return;} -readyList=jQuery.Callbacks("once memory");if(document.readyState==="complete"){return setTimeout(jQuery.ready,1);} -if(document.addEventListener){document.addEventListener("DOMContentLoaded",DOMContentLoaded,false);window.addEventListener("load",jQuery.ready,false);}else if(document.attachEvent){document.attachEvent("onreadystatechange",DOMContentLoaded);window.attachEvent("onload",jQuery.ready);var toplevel=false;try{toplevel=window.frameElement==null;}catch(e){} -if(document.documentElement.doScroll&&toplevel){doScrollCheck();}}},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){return obj==null?String(obj):class2type[toString.call(obj)]||"object";},isPlainObject:function(obj){if(!obj||jQuery.type(obj)!=="object"||obj.nodeType||jQuery.isWindow(obj)){return false;} -try{if(obj.constructor&&!hasOwn.call(obj,"constructor")&&!hasOwn.call(obj.constructor.prototype,"isPrototypeOf")){return false;}}catch(e){return false;} -var key;for(key in obj){} -return key===undefined||hasOwn.call(obj,key);},isEmptyObject:function(obj){for(var name in obj){return false;} -return true;},error:function(msg){throw new Error(msg);},parseJSON:function(data){if(typeof data!=="string"||!data){return null;} -data=jQuery.trim(data);if(window.JSON&&window.JSON.parse){return window.JSON.parse(data);} -if(rvalidchars.test(data.replace(rvalidescape,"@").replace(rvalidtokens,"]").replace(rvalidbraces,""))){return(new Function("return "+data))();} -jQuery.error("Invalid JSON: "+data);},parseXML:function(data){if(typeof data!=="string"||!data){return null;} -var xml,tmp;try{if(window.DOMParser){tmp=new DOMParser();xml=tmp.parseFromString(data,"text/xml");}else{xml=new ActiveXObject("Microsoft.XMLDOM");xml.async="false";xml.loadXML(data);}}catch(e){xml=undefined;} +readyList.resolveWith(document,[jQuery]);if(jQuery.fn.trigger){jQuery(document).trigger("ready").off("ready");}},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){var key;if(!obj||jQuery.type(obj)!=="object"||obj.nodeType||jQuery.isWindow(obj)){return false;} +try{if(obj.constructor&&!core_hasOwn.call(obj,"constructor")&&!core_hasOwn.call(obj.constructor.prototype,"isPrototypeOf")){return false;}}catch(e){return false;} +if(jQuery.support.ownLast){for(key in obj){return core_hasOwn.call(obj,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);},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&&[];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){if(window.JSON&&window.JSON.parse){return window.JSON.parse(data);} +if(data===null){return data;} +if(typeof data==="string"){data=jQuery.trim(data);if(data){if(rvalidchars.test(data.replace(rvalidescape,"@").replace(rvalidtokens,"]").replace(rvalidbraces,""))){return(new Function("return "+data))();}}} +jQuery.error("Invalid JSON: "+data);},parseXML:function(data){var xml,tmp;if(!data||typeof data!=="string"){return null;} +try{if(window.DOMParser){tmp=new DOMParser();xml=tmp.parseFromString(data,"text/xml");}else{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(){},globalEval:function(data){if(data&&rnotwhite.test(data)){(window.execScript||function(data){window["eval"].call(window,data);})(data);}},camelCase:function(string){return string.replace(rmsPrefix,"ms-").replace(rdashAlpha,fcamelCase);},nodeName:function(elem,name){return elem.nodeName&&elem.nodeName.toUpperCase()===name.toUpperCase();},each:function(object,callback,args){var name,i=0,length=object.length,isObj=length===undefined||jQuery.isFunction(object);if(args){if(isObj){for(name in object){if(callback.apply(object[name],args)===false){break;}}}else{for(;i0&&elems[0]&&elems[length-1])||length===0||jQuery.isArray(elems));if(isArray){for(;i1?sliceDeferred.call(arguments,0):value;if(!(--count)){deferred.resolveWith(deferred,args);}};} -function progressFunc(i){return function(value){pValues[i]=arguments.length>1?sliceDeferred.call(arguments,0):value;deferred.notifyWith(promise,pValues);};} -if(length>1){for(;i
a";all=div.getElementsByTagName("*");a=div.getElementsByTagName("a")[0];if(!all||!all.length||!a){return{};} -select=document.createElement("select");opt=select.appendChild(document.createElement("option"));input=div.getElementsByTagName("input")[0];support={leadingWhitespace:(div.firstChild.nodeType===3),tbody:!div.getElementsByTagName("tbody").length,htmlSerialize:!!div.getElementsByTagName("link").length,style:/top/.test(a.getAttribute("style")),hrefNormalized:(a.getAttribute("href")==="/a"),opacity:/^0.55/.test(a.style.opacity),cssFloat:!!a.style.cssFloat,checkOn:(input.value==="on"),optSelected:opt.selected,getSetAttribute:div.className!=="t",enctype:!!document.createElement("form").enctype,html5Clone:document.createElement("nav").cloneNode(true).outerHTML!=="<:nav>",submitBubbles:true,changeBubbles:true,focusinBubbles:false,deleteExpando:true,noCloneEvent:true,inlineBlockNeedsLayout:false,shrinkWrapBlocks:false,reliableMarginRight:true,pixelMargin:true};jQuery.boxModel=support.boxModel=(document.compatMode==="CSS1Compat");input.checked=true;support.noCloneChecked=input.cloneNode(true).checked;select.disabled=true;support.optDisabled=!opt.disabled;try{delete div.test;}catch(e){support.deleteExpando=false;} -if(!div.addEventListener&&div.attachEvent&&div.fireEvent){div.attachEvent("onclick",function(){support.noCloneEvent=false;});div.cloneNode(true).fireEvent("onclick");} -input=document.createElement("input");input.value="t";input.setAttribute("type","radio");support.radioValue=input.value==="t";input.setAttribute("checked","checked");input.setAttribute("name","t");div.appendChild(input);fragment=document.createDocumentFragment();fragment.appendChild(div.lastChild);support.checkClone=fragment.cloneNode(true).cloneNode(true).lastChild.checked;support.appendChecked=input.checked;fragment.removeChild(input);fragment.appendChild(div);if(div.attachEvent){for(i in{submit:1,change:1,focusin:1}){eventName="on"+i;isSupported=(eventName in div);if(!isSupported){div.setAttribute(eventName,"return;");isSupported=(typeof div[eventName]==="function");} -support[i+"Bubbles"]=isSupported;}} -fragment.removeChild(div);fragment=select=opt=div=input=null;jQuery(function(){var container,outer,inner,table,td,offsetSupport,marginDiv,conMarginTop,style,html,positionTopLeftWidthHeight,paddingMarginBorderVisibility,paddingMarginBorder,body=document.getElementsByTagName("body")[0];if(!body){return;} -conMarginTop=1;paddingMarginBorder="padding:0;margin:0;border:";positionTopLeftWidthHeight="position:absolute;top:0;left:0;width:1px;height:1px;";paddingMarginBorderVisibility=paddingMarginBorder+"0;visibility:hidden;";style="style='"+positionTopLeftWidthHeight+paddingMarginBorder+"5px solid #000;";html="
"+""+"
";container=document.createElement("div");container.style.cssText=paddingMarginBorderVisibility+"width:0;height:0;position:static;top:0;margin-top:"+conMarginTop+"px";body.insertBefore(container,body.firstChild);div=document.createElement("div");container.appendChild(div);div.innerHTML="
t
";tds=div.getElementsByTagName("td");isSupported=(tds[0].offsetHeight===0);tds[0].style.display="";tds[1].style.display="none";support.reliableHiddenOffsets=isSupported&&(tds[0].offsetHeight===0);if(window.getComputedStyle){div.innerHTML="";marginDiv=document.createElement("div");marginDiv.style.width="0";marginDiv.style.marginRight="0";div.style.width="2px";div.appendChild(marginDiv);support.reliableMarginRight=(parseInt((window.getComputedStyle(marginDiv,null)||{marginRight:0}).marginRight,10)||0)===0;} -if(typeof div.style.zoom!=="undefined"){div.innerHTML="";div.style.width=div.style.padding="1px";div.style.border=0;div.style.overflow="hidden";div.style.display="inline";div.style.zoom=1;support.inlineBlockNeedsLayout=(div.offsetWidth===3);div.style.display="block";div.style.overflow="visible";div.innerHTML="
";support.shrinkWrapBlocks=(div.offsetWidth!==3);} -div.style.cssText=positionTopLeftWidthHeight+paddingMarginBorderVisibility;div.innerHTML=html;outer=div.firstChild;inner=outer.firstChild;td=outer.nextSibling.firstChild.firstChild;offsetSupport={doesNotAddBorder:(inner.offsetTop!==5),doesAddBorderForTableAndCells:(td.offsetTop===5)};inner.style.position="fixed";inner.style.top="20px";offsetSupport.fixedPosition=(inner.offsetTop===20||inner.offsetTop===15);inner.style.position=inner.style.top="";outer.style.overflow="hidden";outer.style.position="relative";offsetSupport.subtractsBorderForOverflowNotVisible=(inner.offsetTop===-5);offsetSupport.doesNotIncludeMarginInBodyOffset=(body.offsetTop!==conMarginTop);if(window.getComputedStyle){div.style.marginTop="1%";support.pixelMargin=(window.getComputedStyle(div,null)||{marginTop:0}).marginTop!=="1%";} -if(typeof container.style.zoom!=="undefined"){container.style.zoom=1;} -body.removeChild(container);marginDiv=div=container=null;jQuery.extend(support,offsetSupport);});return support;})();var rbrace=/^(?:\{.*\}|\[.*\])$/,rmultiDash=/([A-Z])/g;jQuery.extend({cache:{},uuid:0,expando:"jQuery"+(jQuery.fn.jquery+Math.random()).replace(/\D/g,""),noData:{"embed":true,"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,pvt){if(!jQuery.acceptData(elem)){return;} -var privateCache,thisCache,ret,internalKey=jQuery.expando,getByName=typeof name==="string",isNode=elem.nodeType,cache=isNode?jQuery.cache:elem,id=isNode?elem[internalKey]:elem[internalKey]&&internalKey,isEvents=name==="events";if((!id||!cache[id]||(!isEvents&&!pvt&&!cache[id].data))&&getByName&&data===undefined){return;} -if(!id){if(isNode){elem[internalKey]=id=++jQuery.uuid;}else{id=internalKey;}} -if(!cache[id]){cache[id]={};if(!isNode){cache[id].toJSON=jQuery.noop;}} +args=core_slice.call(arguments,2);proxy=function(){return fn.apply(context||this,args.concat(core_slice.call(arguments)));};proxy.guid=fn.guid=fn.guid||jQuery.guid++;return proxy;},access:function(elems,fn,key,value,chainable,emptyGet,raw){var i=0,length=elems.length,bulk=key==null;if(jQuery.type(key)==="object"){chainable=true;for(i in key){jQuery.access(elems,fn,i,key[i],true,emptyGet,raw);}}else if(value!==undefined){chainable=true;if(!jQuery.isFunction(value)){raw=true;} +if(bulk){if(raw){fn.call(elems,value);fn=null;}else{bulk=fn;fn=function(elem,key,value){return bulk.call(jQuery(elem),value);};}} +if(fn){for(;i0&&(length-1)in obj);} +rootjQuery=jQuery(document);(function(window,undefined){var i,support,cachedruns,Expr,getText,isXML,compile,outermostContext,sortInput,setDocument,document,docElem,documentIsHTML,rbuggyQSA,rbuggyMatches,matches,contains,expando="sizzle"+-(new Date()),preferredDoc=window.document,dirruns=0,done=0,classCache=createCache(),tokenCache=createCache(),compilerCache=createCache(),hasDuplicate=false,sortOrder=function(a,b){if(a===b){hasDuplicate=true;return 0;} +return 0;},strundefined=typeof undefined,MAX_NEGATIVE=1<<31,hasOwn=({}).hasOwnProperty,arr=[],pop=arr.pop,push_native=arr.push,push=arr.push,slice=arr.slice,indexOf=arr.indexOf||function(elem){var i=0,len=this.length;for(;i+~]|"+whitespace+")"+whitespace+"*"),rsibling=new RegExp(whitespace+"*[+~]"),rattributeQuotes=new RegExp("="+whitespace+"*([^\\]'\"]*)"+whitespace+"*\\]","g"),rpseudo=new RegExp(pseudos),ridentifier=new RegExp("^"+identifier+"$"),matchExpr={"ID":new RegExp("^#("+characterEncoding+")"),"CLASS":new RegExp("^\\.("+characterEncoding+")"),"TAG":new RegExp("^("+characterEncoding.replace("w","w*")+")"),"ATTR":new RegExp("^"+attributes),"PSEUDO":new RegExp("^"+pseudos),"CHILD":new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+whitespace+"*(even|odd|(([+-]|)(\\d*)n|)"+whitespace+"*(?:([+-]|)"+whitespace+"*(\\d+)|))"+whitespace+"*\\)|)","i"),"bool":new RegExp("^(?:"+booleans+")$","i"),"needsContext":new RegExp("^"+whitespace+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ +whitespace+"*((?:-\\d)?\\d*)"+whitespace+"*\\)|)(?=[^-]|$)","i")},rnative=/^[^{]+\{\s*\[native \w/,rquickExpr=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,rinputs=/^(?:input|select|textarea|button)$/i,rheader=/^h\d$/i,rescape=/'|\\/g,runescape=new RegExp("\\\\([\\da-f]{1,6}"+whitespace+"?|("+whitespace+")|.)","ig"),funescape=function(_,escaped,escapedWhitespace){var high="0x"+escaped-0x10000;return high!==high||escapedWhitespace?escaped:high<0?String.fromCharCode(high+0x10000):String.fromCharCode(high>>10|0xD800,high&0x3FF|0xDC00);};try{push.apply((arr=slice.call(preferredDoc.childNodes)),preferredDoc.childNodes);arr[preferredDoc.childNodes.length].nodeType;}catch(e){push={apply:arr.length?function(target,els){push_native.apply(target,slice.call(els));}:function(target,els){var j=target.length,i=0;while((target[j++]=els[i++])){} +target.length=j-1;}};} +function Sizzle(selector,context,results,seed){var match,elem,m,nodeType,i,groups,old,nid,newContext,newSelector;if((context?context.ownerDocument||context:preferredDoc)!==document){setDocument(context);} +context=context||document;results=results||[];if(!selector||typeof selector!=="string"){return results;} +if((nodeType=context.nodeType)!==1&&nodeType!==9){return[];} +if(documentIsHTML&&!seed){if((match=rquickExpr.exec(selector))){if((m=match[1])){if(nodeType===9){elem=context.getElementById(m);if(elem&&elem.parentNode){if(elem.id===m){results.push(elem);return results;}}else{return results;}}else{if(context.ownerDocument&&(elem=context.ownerDocument.getElementById(m))&&contains(context,elem)&&elem.id===m){results.push(elem);return results;}}}else if(match[2]){push.apply(results,context.getElementsByTagName(selector));return results;}else if((m=match[3])&&support.getElementsByClassName&&context.getElementsByClassName){push.apply(results,context.getElementsByClassName(m));return results;}} +if(support.qsa&&(!rbuggyQSA||!rbuggyQSA.test(selector))){nid=old=expando;newContext=context;newSelector=nodeType===9&&selector;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,newContext.querySelectorAll(newSelector));return results;}catch(qsaError){}finally{if(!old){context.removeAttribute("id");}}}}} +return select(selector.replace(rtrim,"$1"),context,results,seed);} +function createCache(){var keys=[];function cache(key,value){if(keys.push(key+=" ")>Expr.cacheLength){delete cache[keys.shift()];} +return(cache[key]=value);} +return cache;} +function markFunction(fn){fn[expando]=true;return fn;} +function assert(fn){var div=document.createElement("div");try{return!!fn(div);}catch(e){return false;}finally{if(div.parentNode){div.parentNode.removeChild(div);} +div=null;}} +function addHandle(attrs,handler){var arr=attrs.split("|"),i=attrs.length;while(i--){Expr.attrHandle[arr[i]]=handler;}} +function siblingCheck(a,b){var cur=b&&a,diff=cur&&a.nodeType===1&&b.nodeType===1&&(~b.sourceIndex||MAX_NEGATIVE)- +(~a.sourceIndex||MAX_NEGATIVE);if(diff){return diff;} +if(cur){while((cur=cur.nextSibling)){if(cur===b){return-1;}}} +return a?1:-1;} +function createInputPseudo(type){return function(elem){var name=elem.nodeName.toLowerCase();return name==="input"&&elem.type===type;};} +function createButtonPseudo(type){return function(elem){var name=elem.nodeName.toLowerCase();return(name==="input"||name==="button")&&elem.type===type;};} +function createPositionalPseudo(fn){return markFunction(function(argument){argument=+argument;return markFunction(function(seed,matches){var j,matchIndexes=fn([],seed.length,argument),i=matchIndexes.length;while(i--){if(seed[(j=matchIndexes[i])]){seed[j]=!(matches[j]=seed[j]);}}});});} +isXML=Sizzle.isXML=function(elem){var documentElement=elem&&(elem.ownerDocument||elem).documentElement;return documentElement?documentElement.nodeName!=="HTML":false;};support=Sizzle.support={};setDocument=Sizzle.setDocument=function(node){var doc=node?node.ownerDocument||node:preferredDoc,parent=doc.defaultView;if(doc===document||doc.nodeType!==9||!doc.documentElement){return document;} +document=doc;docElem=doc.documentElement;documentIsHTML=!isXML(doc);if(parent&&parent.attachEvent&&parent!==parent.top){parent.attachEvent("onbeforeunload",function(){setDocument();});} +support.attributes=assert(function(div){div.className="i";return!div.getAttribute("className");});support.getElementsByTagName=assert(function(div){div.appendChild(doc.createComment(""));return!div.getElementsByTagName("*").length;});support.getElementsByClassName=assert(function(div){div.innerHTML="
";div.firstChild.className="i";return div.getElementsByClassName("i").length===2;});support.getById=assert(function(div){docElem.appendChild(div).id=expando;return!doc.getElementsByName||!doc.getElementsByName(expando).length;});if(support.getById){Expr.find["ID"]=function(id,context){if(typeof context.getElementById!==strundefined&&documentIsHTML){var m=context.getElementById(id);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{delete Expr.find["ID"];Expr.filter["ID"]=function(id){var attrId=id.replace(runescape,funescape);return function(elem){var node=typeof elem.getAttributeNode!==strundefined&&elem.getAttributeNode("id");return node&&node.value===attrId;};};} +Expr.find["TAG"]=support.getElementsByTagName?function(tag,context){if(typeof context.getElementsByTagName!==strundefined){return context.getElementsByTagName(tag);}}:function(tag,context){var elem,tmp=[],i=0,results=context.getElementsByTagName(tag);if(tag==="*"){while((elem=results[i++])){if(elem.nodeType===1){tmp.push(elem);}} +return tmp;} +return results;};Expr.find["CLASS"]=support.getElementsByClassName&&function(className,context){if(typeof context.getElementsByClassName!==strundefined&&documentIsHTML){return context.getElementsByClassName(className);}};rbuggyMatches=[];rbuggyQSA=[];if((support.qsa=rnative.test(doc.querySelectorAll))){assert(function(div){div.innerHTML="";if(!div.querySelectorAll("[selected]").length){rbuggyQSA.push("\\["+whitespace+"*(?:value|"+booleans+")");} +if(!div.querySelectorAll(":checked").length){rbuggyQSA.push(":checked");}});assert(function(div){var input=doc.createElement("input");input.setAttribute("type","hidden");div.appendChild(input).setAttribute("t","");if(div.querySelectorAll("[t^='']").length){rbuggyQSA.push("[*^$]="+whitespace+"*(?:''|\"\")");} +if(!div.querySelectorAll(":enabled").length){rbuggyQSA.push(":enabled",":disabled");} +div.querySelectorAll("*,:x");rbuggyQSA.push(",.*:");});} +if((support.matchesSelector=rnative.test((matches=docElem.webkitMatchesSelector||docElem.mozMatchesSelector||docElem.oMatchesSelector||docElem.msMatchesSelector)))){assert(function(div){support.disconnectedMatch=matches.call(div,"div");matches.call(div,"[s!='']:x");rbuggyMatches.push("!=",pseudos);});} +rbuggyQSA=rbuggyQSA.length&&new RegExp(rbuggyQSA.join("|"));rbuggyMatches=rbuggyMatches.length&&new RegExp(rbuggyMatches.join("|"));contains=rnative.test(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;};sortOrder=docElem.compareDocumentPosition?function(a,b){if(a===b){hasDuplicate=true;return 0;} +var compare=b.compareDocumentPosition&&a.compareDocumentPosition&&a.compareDocumentPosition(b);if(compare){if(compare&1||(!support.sortDetached&&b.compareDocumentPosition(a)===compare)){if(a===doc||contains(preferredDoc,a)){return-1;} +if(b===doc||contains(preferredDoc,b)){return 1;} +return sortInput?(indexOf.call(sortInput,a)-indexOf.call(sortInput,b)):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];if(a===b){hasDuplicate=true;return 0;}else if(!aup||!bup){return a===doc?-1:b===doc?1:aup?-1:bup?1:sortInput?(indexOf.call(sortInput,a)-indexOf.call(sortInput,b)):0;}else if(aup===bup){return siblingCheck(a,b);} +cur=a;while((cur=cur.parentNode)){ap.unshift(cur);} +cur=b;while((cur=cur.parentNode)){bp.unshift(cur);} +while(ap[i]===bp[i]){i++;} +return i?siblingCheck(ap[i],bp[i]):ap[i]===preferredDoc?-1:bp[i]===preferredDoc?1:0;};return doc;};Sizzle.matches=function(expr,elements){return Sizzle(expr,null,null,elements);};Sizzle.matchesSelector=function(elem,expr){if((elem.ownerDocument||elem)!==document){setDocument(elem);} +expr=expr.replace(rattributeQuotes,"='$1']");if(support.matchesSelector&&documentIsHTML&&(!rbuggyMatches||!rbuggyMatches.test(expr))&&(!rbuggyQSA||!rbuggyQSA.test(expr))){try{var ret=matches.call(elem,expr);if(ret||support.disconnectedMatch||elem.document&&elem.document.nodeType!==11){return ret;}}catch(e){}} +return Sizzle(expr,document,null,[elem]).length>0;};Sizzle.contains=function(context,elem){if((context.ownerDocument||context)!==document){setDocument(context);} +return contains(context,elem);};Sizzle.attr=function(elem,name){if((elem.ownerDocument||elem)!==document){setDocument(elem);} +var fn=Expr.attrHandle[name.toLowerCase()],val=fn&&hasOwn.call(Expr.attrHandle,name.toLowerCase())?fn(elem,name,!documentIsHTML):undefined;return val===undefined?support.attributes||!documentIsHTML?elem.getAttribute(name):(val=elem.getAttributeNode(name))&&val.specified?val.value:null:val;};Sizzle.error=function(msg){throw new Error("Syntax error, unrecognized expression: "+msg);};Sizzle.uniqueSort=function(results){var elem,duplicates=[],j=0,i=0;hasDuplicate=!support.detectDuplicates;sortInput=!support.sortStable&&results.slice(0);results.sort(sortOrder);if(hasDuplicate){while((elem=results[i++])){if(elem===results[i]){j=duplicates.push(i);}} +while(j--){results.splice(duplicates[j],1);}} +return results;};getText=Sizzle.getText=function(elem){var node,ret="",i=0,nodeType=elem.nodeType;if(!nodeType){for(;(node=elem[i]);i++){ret+=getText(node);}}else if(nodeType===1||nodeType===9||nodeType===11){if(typeof elem.textContent==="string"){return elem.textContent;}else{for(elem=elem.firstChild;elem;elem=elem.nextSibling){ret+=getText(elem);}}}else if(nodeType===3||nodeType===4){return elem.nodeValue;} +return ret;};Expr=Sizzle.selectors={cacheLength:50,createPseudo:markFunction,match:matchExpr,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:true}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:true},"~":{dir:"previousSibling"}},preFilter:{"ATTR":function(match){match[1]=match[1].replace(runescape,funescape);match[3]=(match[4]||match[5]||"").replace(runescape,funescape);if(match[2]==="~="){match[3]=" "+match[3]+" ";} +return match.slice(0,4);},"CHILD":function(match){match[1]=match[1].toLowerCase();if(match[1].slice(0,3)==="nth"){if(!match[3]){Sizzle.error(match[0]);} +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");}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;} +if(match[3]&&match[4]!==undefined){match[2]=match[4];}else if(unquoted&&rpseudo.test(unquoted)&&(excess=tokenize(unquoted,true))&&(excess=unquoted.indexOf(")",unquoted.length-excess)-unquoted.length)){match[0]=match[0].slice(0,excess);match[2]=unquoted.slice(0,excess);} +return match.slice(0,3);}},filter:{"TAG":function(nodeNameSelector){var nodeName=nodeNameSelector.replace(runescape,funescape).toLowerCase();return nodeNameSelector==="*"?function(){return true;}:function(elem){return elem.nodeName&&elem.nodeName.toLowerCase()===nodeName;};},"CLASS":function(className){var pattern=classCache[className+" "];return pattern||(pattern=new RegExp("(^|"+whitespace+")"+className+"("+whitespace+"|$)"))&&classCache(className,function(elem){return pattern.test(typeof elem.className==="string"&&elem.className||typeof elem.getAttribute!==strundefined&&elem.getAttribute("class")||"");});},"ATTR":function(name,operator,check){return function(elem){var result=Sizzle.attr(elem,name);if(result==null){return operator==="!=";} +if(!operator){return true;} +result+="";return operator==="="?result===check:operator==="!="?result!==check:operator==="^="?check&&result.indexOf(check)===0:operator==="*="?check&&result.indexOf(check)>-1:operator==="$="?check&&result.slice(-check.length)===check:operator==="~="?(" "+result+" ").indexOf(check)>-1:operator==="|="?result===check||result.slice(0,check.length+1)===check+"-":false;};},"CHILD":function(type,what,argument,first,last){var simple=type.slice(0,3)!=="nth",forward=type.slice(-4)!=="last",ofType=what==="of-type";return first===1&&last===0?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){if(simple){while(dir){node=elem;while((node=node[dir])){if(ofType?node.nodeName.toLowerCase()===name:node.nodeType===1){return false;}} +start=dir=type==="only"&&!start&&"nextSibling";} +return true;} +start=[forward?parent.firstChild:parent.lastChild];if(forward&&useCache){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]||(diff=nodeIndex=0)||start.pop())){if(node.nodeType===1&&++diff&&node===elem){outerCache[type]=[dirruns,nodeIndex,diff];break;}}}else if(useCache&&(cache=(elem[expando]||(elem[expando]={}))[type])&&cache[0]===dirruns){diff=cache[1];}else{while((node=++nodeIndex&&node&&node[dir]||(diff=nodeIndex=0)||start.pop())){if((ofType?node.nodeName.toLowerCase()===name:node.nodeType===1)&&++diff){if(useCache){(node[expando]||(node[expando]={}))[type]=[dirruns,diff];} +if(node===elem){break;}}}} +diff-=last;return diff===first||(diff%first===0&&diff/first>=0);}};},"PSEUDO":function(pseudo,argument){var args,fn=Expr.pseudos[pseudo]||Expr.setFilters[pseudo.toLowerCase()]||Sizzle.error("unsupported pseudo: "+pseudo);if(fn[expando]){return fn(argument);} +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:{"not":markFunction(function(selector){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;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;};}),"lang":markFunction(function(lang){if(!ridentifier.test(lang||"")){Sizzle.error("unsupported lang: "+lang);} +lang=lang.replace(runescape,funescape).toLowerCase();return function(elem){var elemLang;do{if((elemLang=documentIsHTML?elem.lang:elem.getAttribute("xml:lang")||elem.getAttribute("lang"))){elemLang=elemLang.toLowerCase();return elemLang===lang||elemLang.indexOf(lang+"-")===0;}}while((elem=elem.parentNode)&&elem.nodeType===1);return false;};}),"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);},"enabled":function(elem){return elem.disabled===false;},"disabled":function(elem){return elem.disabled===true;},"checked":function(elem){var nodeName=elem.nodeName.toLowerCase();return(nodeName==="input"&&!!elem.checked)||(nodeName==="option"&&!!elem.selected);},"selected":function(elem){if(elem.parentNode){elem.parentNode.selectedIndex;} +return elem.selected===true;},"empty":function(elem){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);},"header":function(elem){return rheader.test(elem.nodeName);},"input":function(elem){return rinputs.test(elem.nodeName);},"button":function(elem){var name=elem.nodeName.toLowerCase();return name==="input"&&elem.type==="button"||name==="button";},"text":function(elem){var attr;return elem.nodeName.toLowerCase()==="input"&&elem.type==="text"&&((attr=elem.getAttribute("type"))==null||attr.toLowerCase()===elem.type);},"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=0;){matchIndexes.push(i);} +return matchIndexes;}),"gt":createPositionalPseudo(function(matchIndexes,length,argument){var i=argument<0?argument+length:argument;for(;++i1?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-1){seed[temp]=!(results[temp]=elem);}}}}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,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(;i1&&elementMatcher(matchers),i>1&&toSelector(tokens.slice(0,i-1).concat({value:tokens[i-2].type===" "?"*":""})).replace(rtrim,"$1"),matcher,i0,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,elems=seed||byElement&&Expr.find["TAG"]("*",expandContext&&context.parentNode||context),dirrunsUnique=(dirruns+=contextBackup==null?1:Math.random()||0.1);if(outermost){outermostContext=context!==document&&context;cachedruns=matcherCachedRuns;} +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;}} +if(bySet){if((elem=!matcher&&elem)){matchedCount--;} +if(seed){unmatched.push(elem);}}} +matchedCount+=i;if(bySet&&i!==matchedCount){j=0;while((matcher=setMatchers[j++])){matcher(unmatched,setMatched,context,xml);} +if(seed){if(matchedCount>0){while(i--){if(!(unmatched[i]||setMatched[i])){setMatched[i]=pop.call(results);}}} +setMatched=condense(setMatched);} +push.apply(results,setMatched);if(outermost&&!seed&&setMatched.length>0&&(matchedCount+setMatchers.length)>1){Sizzle.uniqueSort(results);}} +if(outermost){dirruns=dirrunsUnique;outermostContext=contextBackup;} +return unmatched;};return bySet?markFunction(superMatcher):superMatcher;} +compile=Sizzle.compile=function(selector,group){var i,setMatchers=[],elementMatchers=[],cached=compilerCache[selector+" "];if(!cached){if(!group){group=tokenize(selector);} +i=group.length;while(i--){cached=matcherFromTokens(group[i]);if(cached[expando]){setMatchers.push(cached);}else{elementMatchers.push(cached);}} +cached=compilerCache(selector,matcherFromGroupMatchers(elementMatchers,setMatchers));} +return cached;};function multipleContexts(selector,contexts,results){var i=0,len=contexts.length;for(;i2&&(token=tokens[0]).type==="ID"&&support.getById&&context.nodeType===9&&documentIsHTML&&Expr.relative[tokens[1].type]){context=(Expr.find["ID"](token.matches[0].replace(runescape,funescape),context)||[])[0];if(!context){return results;} +selector=selector.slice(tokens.shift().value.length);} +i=matchExpr["needsContext"].test(selector)?0:tokens.length;while(i--){token=tokens[i];if(Expr.relative[(type=token.type)]){break;} +if((find=Expr.find[type])){if((seed=find(token.matches[0].replace(runescape,funescape),rsibling.test(tokens[0].type)&&context.parentNode||context))){tokens.splice(i,1);selector=seed.length&&toSelector(tokens);if(!selector){push.apply(results,seed);return results;} +break;}}}}} +compile(selector,match)(seed,context,!documentIsHTML,results,rsibling.test(selector));return results;} +support.sortStable=expando.split("").sort(sortOrder).join("")===expando;support.detectDuplicates=hasDuplicate;setDocument();support.sortDetached=assert(function(div1){return div1.compareDocumentPosition(document.createElement("div"))&1;});if(!assert(function(div){div.innerHTML="";return div.firstChild.getAttribute("href")==="#";})){addHandle("type|href|height|width",function(elem,name,isXML){if(!isXML){return elem.getAttribute(name,name.toLowerCase()==="type"?1:2);}});} +if(!support.attributes||!assert(function(div){div.innerHTML="";div.firstChild.setAttribute("value","");return div.firstChild.getAttribute("value")==="";})){addHandle("value",function(elem,name,isXML){if(!isXML&&elem.nodeName.toLowerCase()==="input"){return elem.defaultValue;}});} +if(!assert(function(div){return div.getAttribute("disabled")==null;})){addHandle(booleans,function(elem,name,isXML){var val;if(!isXML){return(val=elem.getAttributeNode(name))&&val.specified?val.value:elem[name]===true?name.toLowerCase():null;}});} +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 optionsCache={};function createOptions(options){var object=optionsCache[options]={};jQuery.each(options.match(core_rnotwhite)||[],function(_,flag){object[flag]=true;});return object;} +jQuery.Callbacks=function(options){options=typeof options==="string"?(optionsCache[options]||createOptions(options)):jQuery.extend({},options);var +firing,memory,fired,firingLength,firingIndex,firingStart,list=[],stack=!options.once&&[],fire=function(data){memory=options.memory&&data;fired=true;firingIndex=firingStart||0;firingStart=0;firingLength=list.length;firing=true;for(;list&&firingIndex-1){list.splice(index,1);if(firing){if(index<=firingLength){firingLength--;} +if(index<=firingIndex){firingIndex--;}}}});} +return this;},has:function(fn){return fn?jQuery.inArray(fn,list)>-1:!!(list&&list.length);},empty:function(){list=[];firingLength=0;return this;},disable:function(){list=stack=memory=undefined;return this;},disabled:function(){return!list;},lock:function(){stack=undefined;if(!memory){self.disable();} +return this;},locked:function(){return!stack;},fireWith:function(context,args){if(list&&(!fired||stack)){args=args||[];args=[context,args.slice?args.slice():args];if(firing){stack.push(args);}else{fire(args);}} +return this;},fire:function(){self.fireWith(this,arguments);return this;},fired:function(){return!!fired;}};return self;};jQuery.extend({Deferred:function(func){var tuples=[["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(){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[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();},promise:function(obj){return obj!=null?jQuery.extend(obj,promise):promise;}},deferred={};promise.pipe=promise.then;jQuery.each(tuples,function(i,tuple){var list=tuple[2],stateString=tuple[3];promise[tuple[1]]=list.add;if(stateString){list.add(function(){state=stateString;},tuples[i^1][2].disable,tuples[2][2].lock);} +deferred[tuple[0]]=function(){deferred[tuple[0]+"With"](this===deferred?promise:this,arguments);return this;};deferred[tuple[0]+"With"]=list.fireWith;});promise.promise(deferred);if(func){func.call(deferred,deferred);} +return deferred;},when:function(subordinate){var i=0,resolveValues=core_slice.call(arguments),length=resolveValues.length,remaining=length!==1||(subordinate&&jQuery.isFunction(subordinate.promise))?length:0,deferred=remaining===1?subordinate:jQuery.Deferred(),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;if(length>1){progressValues=new Array(length);progressContexts=new Array(length);resolveContexts=new Array(length);for(;i
a";all=div.getElementsByTagName("*")||[];a=div.getElementsByTagName("a")[0];if(!a||!a.style||!all.length){return support;} +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.getSetAttribute=div.className!=="t";support.leadingWhitespace=div.firstChild.nodeType===3;support.tbody=!div.getElementsByTagName("tbody").length;support.htmlSerialize=!!div.getElementsByTagName("link").length;support.style=/top/.test(a.getAttribute("style"));support.hrefNormalized=a.getAttribute("href")==="/a";support.opacity=/^0.5/.test(a.style.opacity);support.cssFloat=!!a.style.cssFloat;support.checkOn=!!input.value;support.optSelected=opt.selected;support.enctype=!!document.createElement("form").enctype;support.html5Clone=document.createElement("nav").cloneNode(true).outerHTML!=="<:nav>";support.inlineBlockNeedsLayout=false;support.shrinkWrapBlocks=false;support.pixelPosition=false;support.deleteExpando=true;support.noCloneEvent=true;support.reliableMarginRight=true;support.boxSizingReliable=true;input.checked=true;support.noCloneChecked=input.cloneNode(true).checked;select.disabled=true;support.optDisabled=!opt.disabled;try{delete div.test;}catch(e){support.deleteExpando=false;} +input=document.createElement("input");input.setAttribute("value","");support.input=input.getAttribute("value")==="";input.value="t";input.setAttribute("type","radio");support.radioValue=input.value==="t";input.setAttribute("checked","t");input.setAttribute("name","t");fragment=document.createDocumentFragment();fragment.appendChild(input);support.appendChecked=input.checked;support.checkClone=fragment.cloneNode(true).cloneNode(true).lastChild.checked;if(div.attachEvent){div.attachEvent("onclick",function(){support.noCloneEvent=false;});div.cloneNode(true).click();} +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";for(i in jQuery(support)){break;} +support.ownLast=i!=="0";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;} +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);div.innerHTML="
t
";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.reliableHiddenOffsets=isSupported&&(tds[0].offsetHeight===0);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%;";jQuery.swap(body,body.style.zoom!=null?{zoom:1}:{},function(){support.boxSizing=div.offsetWidth===4;});if(window.getComputedStyle){support.pixelPosition=(window.getComputedStyle(div,null)||{}).top!=="1%";support.boxSizingReliable=(window.getComputedStyle(div,null)||{width:"4px"}).width==="4px";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){div.innerHTML="";div.style.cssText=divReset+"width:1px;padding:1px;display:inline;zoom:1";support.inlineBlockNeedsLayout=(div.offsetWidth===3);div.style.display="block";div.innerHTML="
";div.firstChild.style.width="5px";support.shrinkWrapBlocks=(div.offsetWidth!==3);if(support.inlineBlockNeedsLayout){body.style.zoom=1;}} +body.removeChild(container);container=div=tds=marginDiv=null;});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){if(!jQuery.acceptData(elem)){return;} +var ret,thisCache,internalKey=jQuery.expando,isNode=elem.nodeType,cache=isNode?jQuery.cache:elem,id=isNode?elem[internalKey]:elem[internalKey]&&internalKey;if((!id||!cache[id]||(!pvt&&!cache[id].data))&&data===undefined&&typeof name==="string"){return;} +if(!id){if(isNode){id=elem[internalKey]=core_deletedIds.pop()||jQuery.guid++;}else{id=internalKey;}} +if(!cache[id]){cache[id]=isNode?{}:{toJSON:jQuery.noop};} 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);}} -privateCache=thisCache=cache[id];if(!pvt){if(!thisCache.data){thisCache.data={};} +thisCache=cache[id];if(!pvt){if(!thisCache.data){thisCache.data={};} thisCache=thisCache.data;} if(data!==undefined){thisCache[jQuery.camelCase(name)]=data;} -if(isEvents&&!thisCache[name]){return privateCache.events;} -if(getByName){ret=thisCache[name];if(ret==null){ret=thisCache[jQuery.camelCase(name)];}}else{ret=thisCache;} -return ret;},removeData:function(elem,name,pvt){if(!jQuery.acceptData(elem)){return;} -var thisCache,i,l,internalKey=jQuery.expando,isNode=elem.nodeType,cache=isNode?jQuery.cache:elem,id=isNode?elem[internalKey]:internalKey;if(!cache[id]){return;} -if(name){thisCache=pvt?cache[id]:cache[id].data;if(thisCache){if(!jQuery.isArray(name)){if(name in thisCache){name=[name];}else{name=jQuery.camelCase(name);if(name in thisCache){name=[name];}else{name=name.split(" ");}}} -for(i=0,l=name.length;i1,null,false);},removeData:function(key){return this.each(function(){jQuery.removeData(this,key);});}});function dataAttr(elem,key,data){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:jQuery.isNumeric(data)?+data:rbrace.test(data)?jQuery.parseJSON(data):data;}catch(e){} +return arguments.length>1?this.each(function(){jQuery.data(this,key,value);}):elem?dataAttr(elem,key,jQuery.data(elem,key)):null;},removeData:function(key){return this.each(function(){jQuery.removeData(this,key);});}});function dataAttr(elem,key,data){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:+data+""===data?+data:rbrace.test(data)?jQuery.parseJSON(data):data;}catch(e){} jQuery.data(elem,key,data);}else{data=undefined;}} return data;} -function isEmptyDataObject(obj){for(var name in obj){if(name==="data"&&jQuery.isEmptyObject(obj[name])){continue;} +function isEmptyDataObject(obj){var name;for(name in obj){if(name==="data"&&jQuery.isEmptyObject(obj[name])){continue;} if(name!=="toJSON"){return false;}} return true;} -function handleQueueMarkDefer(elem,type,src){var deferDataKey=type+"defer",queueDataKey=type+"queue",markDataKey=type+"mark",defer=jQuery._data(elem,deferDataKey);if(defer&&(src==="queue"||!jQuery._data(elem,queueDataKey))&&(src==="mark"||!jQuery._data(elem,markDataKey))){setTimeout(function(){if(!jQuery._data(elem,queueDataKey)&&!jQuery._data(elem,markDataKey)){jQuery.removeData(elem,deferDataKey,true);defer.fire();}},0);}} -jQuery.extend({_mark:function(elem,type){if(elem){type=(type||"fx")+"mark";jQuery._data(elem,type,(jQuery._data(elem,type)||0)+1);}},_unmark:function(force,elem,type){if(force!==true){type=elem;elem=force;force=false;} -if(elem){type=type||"fx";var key=type+"mark",count=force?0:((jQuery._data(elem,key)||1)-1);if(count){jQuery._data(elem,key,count);}else{jQuery.removeData(elem,key,true);handleQueueMarkDefer(elem,type,"mark");}}},queue:function(elem,type,data){var q;if(elem){type=(type||"fx")+"queue";q=jQuery._data(elem,type);if(data){if(!q||jQuery.isArray(data)){q=jQuery._data(elem,type,jQuery.makeArray(data));}else{q.push(data);}} -return q||[];}},dequeue:function(elem,type){type=type||"fx";var queue=jQuery.queue(elem,type),fn=queue.shift(),hooks={};if(fn==="inprogress"){fn=queue.shift();} +jQuery.extend({queue:function(elem,type,data){var queue;if(elem){type=(type||"fx")+"queue";queue=jQuery._data(elem,type);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(fn==="inprogress"){fn=queue.shift();startLength--;} if(fn){if(type==="fx"){queue.unshift("inprogress");} -jQuery._data(elem,type+".run",hooks);fn.call(elem,function(){jQuery.dequeue(elem,type);},hooks);} -if(!queue.length){jQuery.removeData(elem,type+"queue "+type+".run",true);handleQueueMarkDefer(elem,type,"queue");}}});jQuery.fn.extend({queue:function(type,data){var setter=2;if(typeof type!=="string"){data=type;type="fx";setter--;} +delete hooks.stop;fn.call(elem,next,hooks);} +if(!startLength&&hooks){hooks.empty.fire();}},_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.length1);},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{this[name]=undefined;delete this[name];}catch(e){}});},addClass:function(value){var classNames,i,l,elem,setClass,c,cl;if(jQuery.isFunction(value)){return this.each(function(j){jQuery(this).addClass(value.call(this,j,this.className));});} -if(value&&typeof value==="string"){classNames=value.split(rspace);for(i=0,l=this.length;i-1){return true;}} -return false;},val:function(value){var hooks,ret,isFunction,elem=this[0];if(!arguments.length){if(elem){hooks=jQuery.valHooks[elem.type]||jQuery.valHooks[elem.nodeName.toLowerCase()];if(hooks&&"get"in hooks&&(ret=hooks.get(elem,"value"))!==undefined){return ret;} +return data===undefined?this:this.each(function(){var queue=jQuery.queue(this,type,data);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);});},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",[]);},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\f]/g,rreturn=/\r/g,rfocusable=/^(?:input|select|textarea|button|object)$/i,rclickable=/^(?:a|area)$/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{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){classes=(value||"").match(core_rnotwhite)||[];for(;i=0){cur=cur.replace(" "+clazz+" "," ");}} +elem.className=value?jQuery.trim(cur):"";}}} +return this;},toggleClass:function(value,stateVal){var type=typeof value;if(typeof stateVal==="boolean"&&type==="string"){return stateVal?this.addClass(value):this.removeClass(value);} +if(jQuery.isFunction(value)){return this.each(function(i){jQuery(this).toggleClass(value.call(this,i,this.className,stateVal),stateVal);});} +return this.each(function(){if(type==="string"){var className,i=0,self=jQuery(this),classNames=value.match(core_rnotwhite)||[];while((className=classNames[i++])){if(self.hasClass(className)){self.removeClass(className);}else{self.addClass(className);}}}else if(type===core_strundefined||type==="boolean"){if(this.className){jQuery._data(this,"__className__",this.className);} +this.className=this.className||value===false?"":jQuery._data(this,"__className__")||"";}});},hasClass:function(selector){var className=" "+selector+" ",i=0,l=this.length;for(;i=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"?ret.replace(rreturn,""):ret==null?"":ret;} return;} -isFunction=jQuery.isFunction(value);return this.each(function(i){var self=jQuery(this),val;if(this.nodeType!==1){return;} -if(isFunction){val=value.call(this,i,self.val());}else{val=value;} +isFunction=jQuery.isFunction(value);return this.each(function(i){var val;if(this.nodeType!==1){return;} +if(isFunction){val=value.call(this,i,jQuery(this).val());}else{val=value;} 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(!hooks||!("set"in hooks)||hooks.set(this,val,"value")===undefined){this.value=val;}});}});jQuery.extend({valHooks:{option:{get:function(elem){var val=elem.attributes.value;return!val||val.specified?elem.value:elem.text;}},select:{get:function(elem){var value,i,max,option,index=elem.selectedIndex,values=[],options=elem.options,one=elem.type==="select-one";if(index<0){return null;} -i=one?index:0;max=one?index+1:options.length;for(;i=0;});if(!values.length){elem.selectedIndex=-1;} -return values;}}},attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(elem,name,value,pass){var ret,hooks,notxml,nType=elem.nodeType;if(!elem||nType===3||nType===8||nType===2){return;} -if(pass&&name in jQuery.attrFn){return jQuery(elem)[name](value);} -if(typeof elem.getAttribute==="undefined"){return jQuery.prop(elem,name,value);} -notxml=nType!==1||!jQuery.isXMLDoc(elem);if(notxml){name=name.toLowerCase();hooks=jQuery.attrHooks[name]||(rboolean.test(name)?boolHook:nodeHook);} -if(value!==undefined){if(value===null){jQuery.removeAttr(elem,name);return;}else if(hooks&&"set"in hooks&¬xml&&(ret=hooks.set(elem,value,name))!==undefined){return ret;}else{elem.setAttribute(name,""+value);return value;}}else if(hooks&&"get"in hooks&¬xml&&(ret=hooks.get(elem,name))!==null){return ret;}else{ret=elem.getAttribute(name);return ret===null?undefined:ret;}},removeAttr:function(elem,value){var propName,attrNames,name,l,isBool,i=0;if(value&&elem.nodeType===1){attrNames=value.toLowerCase().split(rspace);l=attrNames.length;for(;i=0)){optionSet=true;}} +if(!optionSet){elem.selectedIndex=-1;} +return values;}}},attr:function(elem,name,value){var hooks,ret,nType=elem.nodeType;if(!elem||nType===3||nType===8||nType===2){return;} +if(typeof elem.getAttribute===core_strundefined){return jQuery.prop(elem,name,value);} +if(nType!==1||!jQuery.isXMLDoc(elem)){name=name.toLowerCase();hooks=jQuery.attrHooks[name]||(jQuery.expr.match.bool.test(name)?boolHook:nodeHook);} +if(value!==undefined){if(value===null){jQuery.removeAttr(elem,name);}else if(hooks&&"set"in hooks&&(ret=hooks.set(elem,value,name))!==undefined){return ret;}else{elem.setAttribute(name,value+"");return value;}}else if(hooks&&"get"in hooks&&(ret=hooks.get(elem,name))!==null){return ret;}else{ret=jQuery.find.attr(elem,name);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;if(jQuery.expr.match.bool.test(name)){if(getSetInput&&getSetAttribute||!ruseDefault.test(name)){elem[propName]=false;}else{elem[jQuery.camelCase("default-"+name)]=elem[propName]=false;}}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")){var val=elem.value;elem.setAttribute("type",value);if(val){elem.value=val;} +return value;}}}},propFix:{"for":"htmlFor","class":"className"},prop:function(elem,name,value){var ret,hooks,notxml,nType=elem.nodeType;if(!elem||nType===3||nType===8||nType===2){return;} notxml=nType!==1||!jQuery.isXMLDoc(elem);if(notxml){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){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;}}}});jQuery.attrHooks.tabindex=jQuery.propHooks.tabIndex;boolHook={get:function(elem,name){var attrNode,property=jQuery.prop(elem,name);return property===true||typeof property!=="boolean"&&(attrNode=elem.getAttributeNode(name))&&attrNode.nodeValue!==false?name.toLowerCase():undefined;},set:function(elem,value,name){var propName;if(value===false){jQuery.removeAttr(elem,name);}else{propName=jQuery.propFix[name]||name;if(propName in elem){elem[propName]=true;} -elem.setAttribute(name,name.toLowerCase());} -return name;}};if(!getSetAttribute){fixSpecified={name:true,id:true,coords:true};nodeHook=jQuery.valHooks.button={get:function(elem,name){var ret;ret=elem.getAttributeNode(name);return ret&&(fixSpecified[name]?ret.nodeValue!=="":ret.specified)?ret.nodeValue:undefined;},set:function(elem,value,name){var ret=elem.getAttributeNode(name);if(!ret){ret=document.createAttribute(name);elem.setAttributeNode(ret);} -return(ret.nodeValue=value+"");}};jQuery.attrHooks.tabindex.set=nodeHook.set;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;}}});});jQuery.attrHooks.contenteditable={get:nodeHook.get,set:function(elem,value,name){if(value===""){value="false";} -nodeHook.set(elem,value,name);}};} -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;}});});} -if(!jQuery.support.style){jQuery.attrHooks.style={get:function(elem){return elem.style.cssText.toLowerCase()||undefined;},set:function(elem,value){return(elem.style.cssText=""+value);}};} -if(!jQuery.support.optSelected){jQuery.propHooks.selected=jQuery.extend(jQuery.propHooks.selected,{get:function(elem){var parent=elem.parentNode;if(parent){parent.selectedIndex;if(parent.parentNode){parent.parentNode.selectedIndex;}} -return null;}});} -if(!jQuery.support.enctype){jQuery.propFix.enctype="encoding";} -if(!jQuery.support.checkOn){jQuery.each(["radio","checkbox"],function(){jQuery.valHooks[this]={get:function(elem){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=/^(?:textarea|input|select)$/i,rtypenamespace=/^([^\.]*)?(?:\.(.+))?$/,rhoverHack=/(?:^|\s)hover(\.\S+)?\b/,rkeyEvent=/^key/,rmouseEvent=/^(?:mouse|contextmenu)|click/,rfocusMorph=/^(?:focusinfocus|focusoutblur)$/,rquickIs=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,quickParse=function(selector){var quick=rquickIs.exec(selector);if(quick){quick[1]=(quick[1]||"").toLowerCase();quick[3]=quick[3]&&new RegExp("(?:^|\\s)"+quick[3]+"(?:\\s|$)");} -return quick;},quickIs=function(elem,m){var attrs=elem.attributes||{};return((!m[1]||elem.nodeName.toLowerCase()===m[1])&&(!m[2]||(attrs.id||{}).value===m[2])&&(!m[3]||m[3].test((attrs["class"]||{}).value)));},hoverHack=function(events){return jQuery.event.special.hover?events:events.replace(rhoverHack,"mouseenter$1 mouseleave$1");};jQuery.event={add:function(elem,types,handler,data,selector){var elemData,eventHandle,events,t,tns,type,namespaces,handleObj,handleObjIn,quick,handlers,special;if(elem.nodeType===3||elem.nodeType===8||!types||!handler||!(elemData=jQuery._data(elem))){return;} +if(value!==undefined){return hooks&&"set"in hooks&&(ret=hooks.set(elem,value,name))!==undefined?ret:(elem[name]=value);}else{return hooks&&"get"in hooks&&(ret=hooks.get(elem,name))!==null?ret:elem[name];}},propHooks:{tabIndex:{get:function(elem){var tabindex=jQuery.find.attr(elem,"tabindex");return tabindex?parseInt(tabindex,10):rfocusable.test(elem.nodeName)||rclickable.test(elem.nodeName)&&elem.href?0:-1;}}}});boolHook={set:function(elem,value,name){if(value===false){jQuery.removeAttr(elem,name);}else if(getSetInput&&getSetAttribute||!ruseDefault.test(name)){elem.setAttribute(!getSetAttribute&&jQuery.propFix[name]||name,name);}else{elem[jQuery.camelCase("default-"+name)]=elem[name]=true;} +return name;}};jQuery.each(jQuery.expr.match.bool.source.match(/\w+/g),function(i,name){var getter=jQuery.expr.attrHandle[name]||jQuery.find.attr;jQuery.expr.attrHandle[name]=getSetInput&&getSetAttribute||!ruseDefault.test(name)?function(elem,name,isXML){var fn=jQuery.expr.attrHandle[name],ret=isXML?undefined:(jQuery.expr.attrHandle[name]=undefined)!=getter(elem,name,isXML)?name.toLowerCase():null;jQuery.expr.attrHandle[name]=fn;return ret;}:function(elem,name,isXML){return isXML?undefined:elem[jQuery.camelCase("default-"+name)]?name.toLowerCase():null;};});if(!getSetInput||!getSetAttribute){jQuery.attrHooks.value={set:function(elem,value,name){if(jQuery.nodeName(elem,"input")){elem.defaultValue=value;}else{return nodeHook&&nodeHook.set(elem,value,name);}}};} +if(!getSetAttribute){nodeHook={set:function(elem,value,name){var ret=elem.getAttributeNode(name);if(!ret){elem.setAttributeNode((ret=elem.ownerDocument.createAttribute(name)));} +ret.value=value+="";return name==="value"||value===elem.getAttribute(name)?value:undefined;}};jQuery.expr.attrHandle.id=jQuery.expr.attrHandle.name=jQuery.expr.attrHandle.coords=function(elem,name,isXML){var ret;return isXML?undefined:(ret=elem.getAttributeNode(name))&&ret.value!==""?ret.value:null;};jQuery.valHooks.button={get:function(elem,name){var ret=elem.getAttributeNode(name);return ret&&ret.specified?ret.value:undefined;},set:nodeHook.set};jQuery.attrHooks.contenteditable={set:function(elem,value,name){nodeHook.set(elem,value===""?false:value,name);}};jQuery.each(["width","height"],function(i,name){jQuery.attrHooks[name]={set:function(elem,value){if(value===""){elem.setAttribute(name,"auto");return value;}}};});} +if(!jQuery.support.hrefNormalized){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 elem.style.cssText||undefined;},set:function(elem,value){return(elem.style.cssText=value+"");}};} +if(!jQuery.support.optSelected){jQuery.propHooks.selected={get:function(elem){var parent=elem.parentNode;if(parent){parent.selectedIndex;if(parent.parentNode){parent.parentNode.selectedIndex;}} +return null;}};} +jQuery.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){jQuery.propFix[this.toLowerCase()]=this;});if(!jQuery.support.enctype){jQuery.propFix.enctype="encoding";} +jQuery.each(["radio","checkbox"],function(){jQuery.valHooks[this]={set:function(elem,value){if(jQuery.isArray(value)){return(elem.checked=jQuery.inArray(jQuery(elem).val(),value)>=0);}}};if(!jQuery.support.checkOn){jQuery.valHooks[this].get=function(elem){return elem.getAttribute("value")===null?"on":elem.value;};}});var rformElems=/^(?:input|select|textarea)$/i,rkeyEvent=/^key/,rmouseEvent=/^(?:mouse|contextmenu)|click/,rfocusMorph=/^(?:focusinfocus|focusoutblur)$/,rtypenamespace=/^([^.]*)(?:\.(.+)|)$/;function returnTrue(){return true;} +function returnFalse(){return false;} +function safeActiveElement(){try{return document.activeElement;}catch(err){}} +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);if(!elemData){return;} if(handler.handler){handleObjIn=handler;handler=handleObjIn.handler;selector=handleObjIn.selector;} if(!handler.guid){handler.guid=jQuery.guid++;} -events=elemData.events;if(!events){elemData.events=events={};} -eventHandle=elemData.handle;if(!eventHandle){elemData.handle=eventHandle=function(e){return typeof jQuery!=="undefined"&&(!e||jQuery.event.triggered!==e.type)?jQuery.event.dispatch.apply(eventHandle.elem,arguments):undefined;};eventHandle.elem=elem;} -types=jQuery.trim(hoverHack(types)).split(" ");for(t=0;t=0){type=type.slice(0,-1);exclusive=true;} +if(jQuery.isEmptyObject(events)){delete elemData.handle;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;if(elem.nodeType===3||elem.nodeType===8){return;} +if(rfocusMorph.test(type+jQuery.event.triggered)){return;} if(type.indexOf(".")>=0){namespaces=type.split(".");type=namespaces.shift();namespaces.sort();} -if((!elem||jQuery.event.customEvent[type])&&!jQuery.event.global[type]){return;} -event=typeof event==="object"?event[jQuery.expando]?event:new jQuery.Event(type,event):new jQuery.Event(type);event.type=type;event.isTrigger=true;event.exclusive=exclusive;event.namespace=namespaces.join(".");event.namespace_re=event.namespace?new RegExp("(^|\\.)"+namespaces.join("\\.(?:.*\\.)?")+"(\\.|$)"):null;ontype=type.indexOf(":")<0?"on"+type:"";if(!elem){cache=jQuery.cache;for(i in cache){if(cache[i].events&&cache[i].events[type]){jQuery.event.trigger(event,data,cache[i].handle.elem,true);}} -return;} -event.result=undefined;if(!event.target){event.target=elem;} -data=data!=null?jQuery.makeArray(data):[];data.unshift(event);special=jQuery.event.special[type]||{};if(special.trigger&&special.trigger.apply(elem,data)===false){return;} -eventPath=[[elem,special.bindType||type]];if(!onlyHandlers&&!special.noBubble&&!jQuery.isWindow(elem)){bubbleType=special.delegateType||type;cur=rfocusMorph.test(bubbleType+type)?elem:elem.parentNode;old=null;for(;cur;cur=cur.parentNode){eventPath.push([cur,bubbleType]);old=cur;} -if(old&&old===elem.ownerDocument){eventPath.push([old.defaultView||old.parentWindow||window,bubbleType]);}} -for(i=0;idelegateCount){handlerQueue.push({elem:this,matches:handlers.slice(delegateCount)});} -for(i=0;i1?bubbleType:special.bindType||type;handle=(jQuery._data(cur,"events")||{})[event.type]&&jQuery._data(cur,"handle");if(handle){handle.apply(cur,data);} +handle=ontype&&cur[ontype];if(handle&&jQuery.acceptData(cur)&&handle.apply&&handle.apply(cur,data)===false){event.preventDefault();}} +event.type=type;if(!onlyHandlers&&!event.isDefaultPrevented()){if((!special._default||special._default.apply(eventPath.pop(),data)===false)&&jQuery.acceptData(elem)){if(ontype&&elem[type]&&!jQuery.isWindow(elem)){tmp=elem[ontype];if(tmp){elem[ontype]=null;} +jQuery.event.triggered=type;try{elem[type]();}catch(e){} +jQuery.event.triggered=undefined;if(tmp){elem[ontype]=tmp;}}}} +return event.result;},dispatch:function(event){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]||{};args[0]=event;event.delegateTarget=this;if(special.preDispatch&&special.preDispatch.call(this,event)===false){return;} +handlerQueue=jQuery.event.handlers.call(this,event,handlers);i=0;while((matched=handlerQueue[i++])&&!event.isPropagationStopped()){event.currentTarget=matched.elem;j=0;while((handleObj=matched.handlers[j++])&&!event.isImmediatePropagationStopped()){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();}}}}} if(special.postDispatch){special.postDispatch.call(this,event);} -return event.result;},props:"attrChange attrName relatedNode srcElement 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){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 eventDoc,doc,body,button=original.button,fromElement=original.fromElement;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);} -if(!event.relatedTarget&&fromElement){event.relatedTarget=fromElement===event.target?original.toElement:fromElement;} -if(!event.which&&button!==undefined){event.which=(button&1?1:(button&2?3:(button&4?2:0)));} -return event;}},fix:function(event){if(event[jQuery.expando]){return event;} -var i,prop,originalEvent=event,fixHook=jQuery.event.fixHooks[event.type]||{},copy=fixHook.props?this.props.concat(fixHook.props):this.props;event=jQuery.Event(originalEvent);for(i=copy.length;i;){prop=copy[--i];event[prop]=originalEvent[prop];} +return event.result;},handlers:function(event,handlers){var sel,handleObj,matches,i,handlerQueue=[],delegateCount=handlers.delegateCount,cur=event.target;if(delegateCount&&cur.nodeType&&(!event.button||event.type!=="click")){for(;cur!=this;cur=cur.parentNode||this){if(cur.nodeType===1&&(cur.disabled!==true||event.type!=="click")){matches=[];for(i=0;i=0:jQuery.find(sel,this,null,[cur]).length;} +if(matches[sel]){matches.push(handleObj);}} +if(matches.length){handlerQueue.push({elem:cur,handlers:matches});}}}} +if(delegateCount0?this.on(name,null,data,fn):this.trigger(name);};if(jQuery.attrFn){jQuery.attrFn[name]=true;} -if(rkeyEvent.test(name)){jQuery.event.fixHooks[name]=jQuery.event.keyHooks;} -if(rmouseEvent.test(name)){jQuery.event.fixHooks[name]=jQuery.event.mouseHooks;}});(function(){var chunker=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,expando="sizcache"+(Math.random()+'').replace('.',''),done=0,toString=Object.prototype.toString,hasDuplicate=false,baseHasDuplicate=true,rBackslash=/\\/g,rReturn=/\r\n/g,rNonWord=/\W/;[0,0].sort(function(){baseHasDuplicate=false;return 0;});var Sizzle=function(selector,context,results,seed){results=results||[];context=context||document;var origContext=context;if(context.nodeType!==1&&context.nodeType!==9){return[];} -if(!selector||typeof selector!=="string"){return results;} -var m,set,checkSet,extra,ret,cur,pop,i,prune=true,contextXML=Sizzle.isXML(context),parts=[],soFar=selector;do{chunker.exec("");m=chunker.exec(soFar);if(m){soFar=m[3];parts.push(m[1]);if(m[2]){extra=m[3];break;}}}while(m);if(parts.length>1&&origPOS.exec(selector)){if(parts.length===2&&Expr.relative[parts[0]]){set=posProcess(parts[0]+parts[1],context,seed);}else{set=Expr.relative[parts[0]]?[context]:Sizzle(parts.shift(),context);while(parts.length){selector=parts.shift();if(Expr.relative[selector]){selector+=parts.shift();} -set=posProcess(selector,set,seed);}}}else{if(!seed&&parts.length>1&&context.nodeType===9&&!contextXML&&Expr.match.ID.test(parts[0])&&!Expr.match.ID.test(parts[parts.length-1])){ret=Sizzle.find(parts.shift(),context,contextXML);context=ret.expr?Sizzle.filter(ret.expr,ret.set)[0]:ret.set[0];} -if(context){ret=seed?{expr:parts.pop(),set:makeArray(seed)}:Sizzle.find(parts.pop(),parts.length===1&&(parts[0]==="~"||parts[0]==="+")&&context.parentNode?context.parentNode:context,contextXML);set=ret.expr?Sizzle.filter(ret.expr,ret.set):ret.set;if(parts.length>0){checkSet=makeArray(set);}else{prune=false;} -while(parts.length){cur=parts.pop();pop=cur;if(!Expr.relative[cur]){cur="";}else{pop=parts.pop();} -if(pop==null){pop=context;} -Expr.relative[cur](checkSet,pop,contextXML);}}else{checkSet=parts=[];}} -if(!checkSet){checkSet=set;} -if(!checkSet){Sizzle.error(cur||selector);} -if(toString.call(checkSet)==="[object Array]"){if(!prune){results.push.apply(results,checkSet);}else if(context&&context.nodeType===1){for(i=0;checkSet[i]!=null;i++){if(checkSet[i]&&(checkSet[i]===true||checkSet[i].nodeType===1&&Sizzle.contains(context,checkSet[i]))){results.push(set[i]);}}}else{for(i=0;checkSet[i]!=null;i++){if(checkSet[i]&&checkSet[i].nodeType===1){results.push(set[i]);}}}}else{makeArray(checkSet,results);} -if(extra){Sizzle(extra,origContext,results,seed);Sizzle.uniqueSort(results);} -return results;};Sizzle.uniqueSort=function(results){if(sortOrder){hasDuplicate=baseHasDuplicate;results.sort(sortOrder);if(hasDuplicate){for(var i=1;i0;};Sizzle.find=function(expr,context,isXML){var set,i,len,match,type,left;if(!expr){return[];} -for(i=0,len=Expr.order.length;i":function(checkSet,part){var elem,isPartStr=typeof part==="string",i=0,l=checkSet.length;if(isPartStr&&!rNonWord.test(part)){part=part.toLowerCase();for(;i=0)){if(!inplace){result.push(elem);}}else if(inplace){curLoop[i]=false;}}} -return false;},ID:function(match){return match[1].replace(rBackslash,"");},TAG:function(match,curLoop){return match[1].replace(rBackslash,"").toLowerCase();},CHILD:function(match){if(match[1]==="nth"){if(!match[2]){Sizzle.error(match[0]);} -match[2]=match[2].replace(/^\+|\s*/g,'');var test=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(match[2]==="even"&&"2n"||match[2]==="odd"&&"2n+1"||!/\D/.test(match[2])&&"0n+"+match[2]||match[2]);match[2]=(test[1]+(test[2]||1))-0;match[3]=test[3]-0;} -else if(match[2]){Sizzle.error(match[0]);} -match[0]=done++;return match;},ATTR:function(match,curLoop,inplace,result,not,isXML){var name=match[1]=match[1].replace(rBackslash,"");if(!isXML&&Expr.attrMap[name]){match[1]=Expr.attrMap[name];} -match[4]=(match[4]||match[5]||"").replace(rBackslash,"");if(match[2]==="~="){match[4]=" "+match[4]+" ";} -return match;},PSEUDO:function(match,curLoop,inplace,result,not){if(match[1]==="not"){if((chunker.exec(match[3])||"").length>1||/^\w/.test(match[3])){match[3]=Sizzle(match[3],null,null,curLoop);}else{var ret=Sizzle.filter(match[3],curLoop,inplace,true^not);if(!inplace){result.push.apply(result,ret);} -return false;}}else if(Expr.match.POS.test(match[0])||Expr.match.CHILD.test(match[0])){return true;} -return match;},POS:function(match){match.unshift(true);return match;}},filters:{enabled:function(elem){return elem.disabled===false&&elem.type!=="hidden";},disabled:function(elem){return elem.disabled===true;},checked:function(elem){return elem.checked===true;},selected:function(elem){if(elem.parentNode){elem.parentNode.selectedIndex;} -return elem.selected===true;},parent:function(elem){return!!elem.firstChild;},empty:function(elem){return!elem.firstChild;},has:function(elem,i,match){return!!Sizzle(match[3],elem).length;},header:function(elem){return(/h\d/i).test(elem.nodeName);},text:function(elem){var attr=elem.getAttribute("type"),type=elem.type;return elem.nodeName.toLowerCase()==="input"&&"text"===type&&(attr===type||attr===null);},radio:function(elem){return elem.nodeName.toLowerCase()==="input"&&"radio"===elem.type;},checkbox:function(elem){return elem.nodeName.toLowerCase()==="input"&&"checkbox"===elem.type;},file:function(elem){return elem.nodeName.toLowerCase()==="input"&&"file"===elem.type;},password:function(elem){return elem.nodeName.toLowerCase()==="input"&&"password"===elem.type;},submit:function(elem){var name=elem.nodeName.toLowerCase();return(name==="input"||name==="button")&&"submit"===elem.type;},image:function(elem){return elem.nodeName.toLowerCase()==="input"&&"image"===elem.type;},reset:function(elem){var name=elem.nodeName.toLowerCase();return(name==="input"||name==="button")&&"reset"===elem.type;},button:function(elem){var name=elem.nodeName.toLowerCase();return name==="input"&&"button"===elem.type||name==="button";},input:function(elem){return(/input|select|textarea|button/i).test(elem.nodeName);},focus:function(elem){return elem===elem.ownerDocument.activeElement;}},setFilters:{first:function(elem,i){return i===0;},last:function(elem,i,match,array){return i===array.length-1;},even:function(elem,i){return i%2===0;},odd:function(elem,i){return i%2===1;},lt:function(elem,i,match){return imatch[3]-0;},nth:function(elem,i,match){return match[3]-0===i;},eq:function(elem,i,match){return match[3]-0===i;}},filter:{PSEUDO:function(elem,match,i,array){var name=match[1],filter=Expr.filters[name];if(filter){return filter(elem,i,match,array);}else if(name==="contains"){return(elem.textContent||elem.innerText||getText([elem])||"").indexOf(match[3])>=0;}else if(name==="not"){var not=match[3];for(var j=0,l=not.length;j=0);}}},ID:function(elem,match){return elem.nodeType===1&&elem.getAttribute("id")===match;},TAG:function(elem,match){return(match==="*"&&elem.nodeType===1)||!!elem.nodeName&&elem.nodeName.toLowerCase()===match;},CLASS:function(elem,match){return(" "+(elem.className||elem.getAttribute("class"))+" ").indexOf(match)>-1;},ATTR:function(elem,match){var name=match[1],result=Sizzle.attr?Sizzle.attr(elem,name):Expr.attrHandle[name]?Expr.attrHandle[name](elem):elem[name]!=null?elem[name]:elem.getAttribute(name),value=result+"",type=match[2],check=match[4];return result==null?type==="!=":!type&&Sizzle.attr?result!=null:type==="="?value===check:type==="*="?value.indexOf(check)>=0:type==="~="?(" "+value+" ").indexOf(check)>=0:!check?value&&result!==false:type==="!="?value!==check:type==="^="?value.indexOf(check)===0:type==="$="?value.substr(value.length-check.length)===check:type==="|="?value===check||value.substr(0,check.length+1)===check+"-":false;},POS:function(elem,match,i,array){var name=match[2],filter=Expr.setFilters[name];if(filter){return filter(elem,i,match,array);}}}};var origPOS=Expr.match.POS,fescape=function(all,num){return"\\"+(num-0+1);};for(var type in Expr.match){Expr.match[type]=new RegExp(Expr.match[type].source+(/(?![^\[]*\])(?![^\(]*\))/.source));Expr.leftMatch[type]=new RegExp(/(^(?:.|\r|\n)*?)/.source+Expr.match[type].source.replace(/\\(\d+)/g,fescape));} -Expr.match.globalPOS=origPOS;var makeArray=function(array,results){array=Array.prototype.slice.call(array,0);if(results){results.push.apply(results,array);return results;} -return array;};try{Array.prototype.slice.call(document.documentElement.childNodes,0)[0].nodeType;}catch(e){makeArray=function(array,results){var i=0,ret=results||[];if(toString.call(array)==="[object Array]"){Array.prototype.push.apply(ret,array);}else{if(typeof array.length==="number"){for(var l=array.length;i";root.insertBefore(form,root.firstChild);if(document.getElementById(id)){Expr.find.ID=function(match,context,isXML){if(typeof context.getElementById!=="undefined"&&!isXML){var m=context.getElementById(match[1]);return m?m.id===match[1]||typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id").nodeValue===match[1]?[m]:undefined:[];}};Expr.filter.ID=function(elem,match){var node=typeof elem.getAttributeNode!=="undefined"&&elem.getAttributeNode("id");return elem.nodeType===1&&node&&node.nodeValue===match;};} -root.removeChild(form);root=form=null;})();(function(){var div=document.createElement("div");div.appendChild(document.createComment(""));if(div.getElementsByTagName("*").length>0){Expr.find.TAG=function(match,context){var results=context.getElementsByTagName(match[1]);if(match[1]==="*"){var tmp=[];for(var i=0;results[i];i++){if(results[i].nodeType===1){tmp.push(results[i]);}} -results=tmp;} -return results;};} -div.innerHTML="";if(div.firstChild&&typeof div.firstChild.getAttribute!=="undefined"&&div.firstChild.getAttribute("href")!=="#"){Expr.attrHandle.href=function(elem){return elem.getAttribute("href",2);};} -div=null;})();if(document.querySelectorAll){(function(){var oldSizzle=Sizzle,div=document.createElement("div"),id="__sizzle__";div.innerHTML="

";if(div.querySelectorAll&&div.querySelectorAll(".TEST").length===0){return;} -Sizzle=function(query,context,extra,seed){context=context||document;if(!seed&&!Sizzle.isXML(context)){var match=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(query);if(match&&(context.nodeType===1||context.nodeType===9)){if(match[1]){return makeArray(context.getElementsByTagName(query),extra);}else if(match[2]&&Expr.find.CLASS&&context.getElementsByClassName){return makeArray(context.getElementsByClassName(match[2]),extra);}} -if(context.nodeType===9){if(query==="body"&&context.body){return makeArray([context.body],extra);}else if(match&&match[3]){var elem=context.getElementById(match[3]);if(elem&&elem.parentNode){if(elem.id===match[3]){return makeArray([elem],extra);}}else{return makeArray([],extra);}} -try{return makeArray(context.querySelectorAll(query),extra);}catch(qsaError){}}else if(context.nodeType===1&&context.nodeName.toLowerCase()!=="object"){var oldContext=context,old=context.getAttribute("id"),nid=old||id,hasParent=context.parentNode,relativeHierarchySelector=/^\s*[+~]/.test(query);if(!old){context.setAttribute("id",nid);}else{nid=nid.replace(/'/g,"\\$&");} -if(relativeHierarchySelector&&hasParent){context=context.parentNode;} -try{if(!relativeHierarchySelector||hasParent){return makeArray(context.querySelectorAll("[id='"+nid+"'] "+query),extra);}}catch(pseudoError){}finally{if(!old){oldContext.removeAttribute("id");}}}} -return oldSizzle(query,context,extra,seed);};for(var prop in oldSizzle){Sizzle[prop]=oldSizzle[prop];} -div=null;})();} -(function(){var html=document.documentElement,matches=html.matchesSelector||html.mozMatchesSelector||html.webkitMatchesSelector||html.msMatchesSelector;if(matches){var disconnectedMatch=!matches.call(document.createElement("div"),"div"),pseudoWorks=false;try{matches.call(document.documentElement,"[test!='']:sizzle");}catch(pseudoError){pseudoWorks=true;} -Sizzle.matchesSelector=function(node,expr){expr=expr.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!Sizzle.isXML(node)){try{if(pseudoWorks||!Expr.match.PSEUDO.test(expr)&&!/!=/.test(expr)){var ret=matches.call(node,expr);if(ret||!disconnectedMatch||node.document&&node.document.nodeType!==11){return ret;}}}catch(e){}} -return Sizzle(expr,null,null,[node]).length>0;};}})();(function(){var div=document.createElement("div");div.innerHTML="
";if(!div.getElementsByClassName||div.getElementsByClassName("e").length===0){return;} -div.lastChild.className="e";if(div.getElementsByClassName("e").length===1){return;} -Expr.order.splice(1,0,"CLASS");Expr.find.CLASS=function(match,context,isXML){if(typeof context.getElementsByClassName!=="undefined"&&!isXML){return context.getElementsByClassName(match[1]);}};div=null;})();function dirNodeCheck(dir,cur,doneName,checkSet,nodeCheck,isXML){for(var i=0,l=checkSet.length;i0){match=elem;break;}} -elem=elem[dir];} -checkSet[i]=match;}}} -if(document.documentElement.contains){Sizzle.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):true);};}else if(document.documentElement.compareDocumentPosition){Sizzle.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16);};}else{Sizzle.contains=function(){return false;};} -Sizzle.isXML=function(elem){var documentElement=(elem?elem.ownerDocument||elem:0).documentElement;return documentElement?documentElement.nodeName!=="HTML":false;};var posProcess=function(selector,context,seed){var match,tmpSet=[],later="",root=context.nodeType?[context]:context;while((match=Expr.match.PSEUDO.exec(selector))){later+=match[0];selector=selector.replace(Expr.match.PSEUDO,"");} -selector=Expr.relative[selector]?selector+"*":selector;for(var i=0,l=root.length;i0){for(n=length;n=0:jQuery.filter(selector,this).length>0:this.filter(selector).length>0);},closest:function(selectors,context){var ret=[],i,l,cur=this[0];if(jQuery.isArray(selectors)){var level=1;while(cur&&cur.ownerDocument&&cur!==context){for(i=0;i-1:jQuery.find.matchesSelector(cur,selectors)){ret.push(cur);break;}else{cur=cur.parentNode;if(!cur||!cur.ownerDocument||cur===context||cur.nodeType===11){break;}}}} -ret=ret.length>1?jQuery.unique(ret):ret;return this.pushStack(ret,"closest",selectors);},index:function(elem){if(!elem){return(this[0]&&this[0].parentNode)?this.prevAll().length:-1;} +return this.each(function(){jQuery.event.remove(this,types,fn,selector);});},trigger:function(type,data){return this.each(function(){jQuery.event.trigger(type,data,this);});},triggerHandler:function(type,data){var elem=this[0];if(elem){return jQuery.event.trigger(type,data,elem,true);}}});var isSimple=/^.[^:#\[\.,]*$/,rparentsprev=/^(?:parents|prev(?:Until|All))/,rneedsContext=jQuery.expr.match.needsContext,guaranteedUnique={children:true,contents:true,next:true,prev:true};jQuery.fn.extend({find:function(selector){var i,ret=[],self=this,len=self.length;if(typeof selector!=="string"){return this.pushStack(jQuery(selector).filter(function(){for(i=0;i1?jQuery.unique(ret):ret);ret.selector=this.selector?this.selector+" "+selector:selector;return ret;},has:function(target){var i,targets=jQuery(target,this),len=targets.length;return this.filter(function(){for(i=0;i-1:cur.nodeType===1&&jQuery.find.matchesSelector(cur,selectors))){cur=ret.push(cur);break;}}} +return this.pushStack(ret.length>1?jQuery.unique(ret):ret);},index:function(elem){if(!elem){return(this[0]&&this[0].parentNode)?this.first().prevAll().length:-1;} if(typeof elem==="string"){return jQuery.inArray(this[0],jQuery(elem));} -return jQuery.inArray(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(isDisconnected(set[0])||isDisconnected(all[0])?all:jQuery.unique(all));},andSelf:function(){return this.add(this.prevObject);}});function isDisconnected(node){return!node||!node.parentNode||node.parentNode.nodeType===11;} -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 jQuery.nth(elem,2,"nextSibling");},prev:function(elem){return jQuery.nth(elem,2,"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.makeArray(elem.childNodes);}},function(name,fn){jQuery.fn[name]=function(until,selector){var ret=jQuery.map(this,fn,until);if(!runtil.test(name)){selector=until;} +return jQuery.inArray(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));}});function sibling(cur,dir){do{cur=cur[dir];}while(cur&&cur.nodeType!==1);return cur;} +jQuery.each({parent:function(elem){var parent=elem.parentNode;return parent&&parent.nodeType!==11?parent:null;},parents:function(elem){return jQuery.dir(elem,"parentNode");},parentsUntil:function(elem,i,until){return jQuery.dir(elem,"parentNode",until);},next:function(elem){return sibling(elem,"nextSibling");},prev:function(elem){return sibling(elem,"previousSibling");},nextAll:function(elem){return jQuery.dir(elem,"nextSibling");},prevAll:function(elem){return jQuery.dir(elem,"previousSibling");},nextUntil:function(elem,i,until){return jQuery.dir(elem,"nextSibling",until);},prevUntil:function(elem,i,until){return jQuery.dir(elem,"previousSibling",until);},siblings:function(elem){return jQuery.sibling((elem.parentNode||{}).firstChild,elem);},children:function(elem){return jQuery.sibling(elem.firstChild);},contents:function(elem){return jQuery.nodeName(elem,"iframe")?elem.contentDocument||elem.contentWindow.document:jQuery.merge([],elem.childNodes);}},function(name,fn){jQuery.fn[name]=function(until,selector){var ret=jQuery.map(this,fn,until);if(name.slice(-5)!=="Until"){selector=until;} if(selector&&typeof selector==="string"){ret=jQuery.filter(selector,ret);} -ret=this.length>1&&!guaranteedUnique[name]?jQuery.unique(ret):ret;if((this.length>1||rmultiselector.test(selector))&&rparentsprev.test(name)){ret=ret.reverse();} -return this.pushStack(ret,name,slice.call(arguments).join(","));};});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);} +if(this.length>1){if(!guaranteedUnique[name]){ret=jQuery.unique(ret);} +if(rparentsprev.test(name)){ret=ret.reverse();}} +return this.pushStack(ret);};});jQuery.extend({filter:function(expr,elems,not){var elem=elems[0];if(not){expr=":not("+expr+")";} +return elems.length===1&&elem.nodeType===1?jQuery.find.matchesSelector(elem,expr)?[elem]:[]:jQuery.find.matches(expr,jQuery.grep(elems,function(elem){return elem.nodeType===1;}));},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;},nth:function(cur,result,dir,elem){result=result||1;var num=0;for(;cur;cur=cur[dir]){if(cur.nodeType===1&&++num===result){break;}} -return cur;},sibling:function(n,elem){var r=[];for(;n;n=n.nextSibling){if(n.nodeType===1&&n!==elem){r.push(n);}} -return r;}});function winnow(elements,qualifier,keep){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,i){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,i){return(jQuery.inArray(elem,qualifier)>=0)===keep;});} +return matched;},sibling:function(n,elem){var r=[];for(;n;n=n.nextSibling){if(n.nodeType===1&&n!==elem){r.push(n);}} +return r;}});function winnow(elements,qualifier,not){if(jQuery.isFunction(qualifier)){return jQuery.grep(elements,function(elem,i){return!!qualifier.call(elem,i,elem)!==not;});} +if(qualifier.nodeType){return jQuery.grep(elements,function(elem){return(elem===qualifier)!==not;});} +if(typeof qualifier==="string"){if(isSimple.test(qualifier)){return jQuery.filter(qualifier,elements,not);} +qualifier=jQuery.filter(qualifier,elements);} +return jQuery.grep(elements,function(elem){return(jQuery.inArray(elem,qualifier)>=0)!==not;});} 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+="(?:\d+|null)"/g,rleadingWhitespace=/^\s+/,rxhtmlTag=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,rtagName=/<([\w:]+)/,rtbody=/]","i"),rchecked=/checked\s*(?:[^=]|=\s*.checked.)/i,rscriptType=/\/(java|ecma)script/i,rcleanScript=/^\s*",""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]},safeFragment=createSafeFragment(document);wrapMap.optgroup=wrapMap.option;wrapMap.tbody=wrapMap.tfoot=wrapMap.colgroup=wrapMap.caption=wrapMap.thead;wrapMap.th=wrapMap.td;if(!jQuery.support.htmlSerialize){wrapMap._default=[1,"div
","
"];} -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]){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.appendChild(elem);}});},prepend:function(){return this.domManip(arguments,true,function(elem){if(this.nodeType===1){this.insertBefore(elem,this.firstChild);}});},before:function(){if(this[0]&&this[0].parentNode){return this.domManip(arguments,false,function(elem){this.parentNode.insertBefore(elem,this);});}else if(arguments.length){var set=jQuery.clean(arguments);set.push.apply(set,this.toArray());return this.pushStack(set,"before",arguments);}},after:function(){if(this[0]&&this[0].parentNode){return this.domManip(arguments,false,function(elem){this.parentNode.insertBefore(elem,this.nextSibling);});}else if(arguments.length){var set=this.pushStack(this,"after",arguments);set.push.apply(set,jQuery.clean(arguments));return set;}},remove:function(selector,keepData){for(var i=0,elem;(elem=this[i])!=null;i++){if(!selector||jQuery.filter(selector,[elem]).length){if(!keepData&&elem.nodeType===1){jQuery.cleanData(elem.getElementsByTagName("*"));jQuery.cleanData([elem]);} -if(elem.parentNode){elem.parentNode.removeChild(elem);}}} -return this;},empty:function(){for(var i=0,elem;(elem=this[i])!=null;i++){if(elem.nodeType===1){jQuery.cleanData(elem.getElementsByTagName("*"));} -while(elem.firstChild){elem.removeChild(elem.firstChild);}} -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,""):null;} -if(typeof value==="string"&&!rnoInnerhtml.test(value)&&(jQuery.support.leadingWhitespace||!rleadingWhitespace.test(value))&&!wrapMap[(rtagName.exec(value)||["",""])[1].toLowerCase()]){value=value.replace(rxhtmlTag,"<$1>");try{for(;i]","i"),rleadingWhitespace=/^\s+/,rxhtmlTag=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,rtagName=/<([\w:]+)/,rtbody=/\s*$/g,wrapMap={option:[1,""],legend:[1,"
","
"],area:[1,"",""],param:[1,"",""],thead:[1,"","
"],tr:[2,"","
"],col:[2,"","
"],td:[3,"","
"],_default:jQuery.support.htmlSerialize?[0,"",""]:[1,"X
","
"]},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);},append:function(){return this.domManip(arguments,function(elem){if(this.nodeType===1||this.nodeType===11||this.nodeType===9){var target=manipulationTarget(this,elem);target.appendChild(elem);}});},prepend:function(){return this.domManip(arguments,function(elem){if(this.nodeType===1||this.nodeType===11||this.nodeType===9){var target=manipulationTarget(this,elem);target.insertBefore(elem,target.firstChild);}});},before:function(){return this.domManip(arguments,function(elem){if(this.parentNode){this.parentNode.insertBefore(elem,this);}});},after:function(){return this.domManip(arguments,function(elem){if(this.parentNode){this.parentNode.insertBefore(elem,this.nextSibling);}});},remove:function(selector,keepData){var elem,elems=selector?jQuery.filter(selector,this):this,i=0;for(;(elem=elems[i])!=null;i++){if(!keepData&&elem.nodeType===1){jQuery.cleanData(getAll(elem));} +if(elem.parentNode){if(keepData&&jQuery.contains(elem.ownerDocument,elem)){setGlobalEval(getAll(elem,"script"));} +elem.parentNode.removeChild(elem);}} +return this;},empty:function(){var elem,i=0;for(;(elem=this[i])!=null;i++){if(elem.nodeType===1){jQuery.cleanData(getAll(elem,false));} +while(elem.firstChild){elem.removeChild(elem.firstChild);} +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;} +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>");try{for(;i1&&i0?this.clone(true):this).get();jQuery(insert[i])[original](elems);ret=ret.concat(elems);} -return this.pushStack(ret,name,insert.selector);}};});function getAll(elem){if(typeof elem.getElementsByTagName!=="undefined"){return elem.getElementsByTagName("*");}else if(typeof elem.querySelectorAll!=="undefined"){return elem.querySelectorAll("*");}else{return[];}} -function fixDefaultChecked(elem){if(elem.type==="checkbox"||elem.type==="radio"){elem.defaultChecked=elem.checked;}} -function findInputs(elem){var nodeName=(elem.nodeName||"").toLowerCase();if(nodeName==="input"){fixDefaultChecked(elem);}else if(nodeName!=="script"&&typeof elem.getElementsByTagName!=="undefined"){jQuery.grep(elem.getElementsByTagName("input"),fixDefaultChecked);}} -function shimCloneNode(elem){var div=document.createElement("div");safeFragment.appendChild(div);div.innerHTML=elem.outerHTML;return div.firstChild;} -jQuery.extend({clone:function(elem,dataAndEvents,deepDataAndEvents){var srcElements,destElements,i,clone=jQuery.support.html5Clone||jQuery.isXMLDoc(elem)||!rnoshimcache.test("<"+elem.nodeName+">")?elem.cloneNode(true):shimCloneNode(elem);if((!jQuery.support.noCloneEvent||!jQuery.support.noCloneChecked)&&(elem.nodeType===1||elem.nodeType===11)&&!jQuery.isXMLDoc(elem)){cloneFixAttributes(elem,clone);srcElements=getAll(elem);destElements=getAll(clone);for(i=0;srcElements[i];++i){if(destElements[i]){cloneFixAttributes(srcElements[i],destElements[i]);}}} -if(dataAndEvents){cloneCopyEvent(elem,clone);if(deepDataAndEvents){srcElements=getAll(elem);destElements=getAll(clone);for(i=0;srcElements[i];++i){cloneCopyEvent(srcElements[i],destElements[i]);}}} -srcElements=destElements=null;return clone;},clean:function(elems,context,fragment,scripts){var checkScriptType,script,j,ret=[];context=context||document;if(typeof context.createElement==="undefined"){context=context.ownerDocument||context[0]&&context[0].ownerDocument||document;} -for(var i=0,elem;(elem=elems[i])!=null;i++){if(typeof elem==="number"){elem+="";} -if(!elem){continue;} -if(typeof elem==="string"){if(!rhtml.test(elem)){elem=context.createTextNode(elem);}else{elem=elem.replace(rxhtmlTag,"<$1>");var tag=(rtagName.exec(elem)||["",""])[1].toLowerCase(),wrap=wrapMap[tag]||wrapMap._default,depth=wrap[0],div=context.createElement("div"),safeChildNodes=safeFragment.childNodes,remove;if(context===document){safeFragment.appendChild(div);}else{createSafeFragment(context).appendChild(div);} -div.innerHTML=wrap[1]+elem+wrap[2];while(depth--){div=div.lastChild;} -if(!jQuery.support.tbody){var hasBody=rtbody.test(elem),tbody=tag==="table"&&!hasBody?div.firstChild&&div.firstChild.childNodes:wrap[1]===""&&!hasBody?div.childNodes:[];for(j=tbody.length-1;j>=0;--j){if(jQuery.nodeName(tbody[j],"tbody")&&!tbody[j].childNodes.length){tbody[j].parentNode.removeChild(tbody[j]);}}} -if(!jQuery.support.leadingWhitespace&&rleadingWhitespace.test(elem)){div.insertBefore(context.createTextNode(rleadingWhitespace.exec(elem)[0]),div.firstChild);} -elem=div.childNodes;if(div){div.parentNode.removeChild(div);if(safeChildNodes.length>0){remove=safeChildNodes[safeChildNodes.length-1];if(remove&&remove.parentNode){remove.parentNode.removeChild(remove);}}}}} -var len;if(!jQuery.support.appendChecked){if(elem[0]&&typeof(len=elem.length)==="number"){for(j=0;j1);};jQuery.extend({cssHooks:{opacity:{get:function(elem,computed){if(computed){var ret=curCSS(elem,"opacity");return ret===""?"1":ret;}else{return elem.style.opacity;}}}},cssNumber:{"fillOpacity":true,"fontWeight":true,"lineHeight":true,"opacity":true,"orphans":true,"widows":true,"zIndex":true,"zoom":true},cssProps:{"float":jQuery.support.cssFloat?"cssFloat":"styleFloat"},style:function(elem,name,value,extra){if(!elem||elem.nodeType===3||elem.nodeType===8||!elem.style){return;} -var ret,type,origName=jQuery.camelCase(name),style=elem.style,hooks=jQuery.cssHooks[origName];name=jQuery.cssProps[origName]||origName;if(value!==undefined){type=typeof value;if(type==="string"&&(ret=rrelNum.exec(value))){value=(+(ret[1]+1)*+ret[2])+parseFloat(jQuery.css(elem,name));type="number";} +function fixCloneNodeIssues(src,dest){var nodeName,e,data;if(dest.nodeType!==1){return;} +nodeName=dest.nodeName.toLowerCase();if(!jQuery.support.noCloneEvent&&dest[jQuery.expando]){data=jQuery._data(dest);for(e in data.events){jQuery.removeEvent(dest,e,data.handle);} +dest.removeAttribute(jQuery.expando);} +if(nodeName==="script"&&dest.text!==src.text){disableScript(dest).text=src.text;restoreScript(dest);}else if(nodeName==="object"){if(dest.parentNode){dest.outerHTML=src.outerHTML;} +if(jQuery.support.html5Clone&&(src.innerHTML&&!jQuery.trim(dest.innerHTML))){dest.innerHTML=src.innerHTML;}}else if(nodeName==="input"&&manipulation_rcheckableType.test(src.type)){dest.defaultChecked=dest.checked=src.checked;if(dest.value!==src.value){dest.value=src.value;}}else if(nodeName==="option"){dest.defaultSelected=dest.selected=src.defaultSelected;}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);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;} +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);}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)){destElements=getAll(clone);srcElements=getAll(elem);for(i=0;(node=srcElements[i])!=null;++i){if(destElements[i]){fixCloneNodeIssues(node,destElements[i]);}}} +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);}} +destElements=getAll(clone,"script");if(destElements.length>0){setGlobalEval(destElements,!inPage&&getAll(elem,"script"));} +destElements=srcElements=node=null;return clone;},buildFragment:function(elems,context,scripts,selection){var j,elem,contains,tmp,tag,tbody,wrap,l=elems.length,safe=createSafeFragment(context),nodes=[],i=0;for(;i")+wrap[2];j=wrap[0];while(j--){tmp=tmp.lastChild;} +if(!jQuery.support.leadingWhitespace&&rleadingWhitespace.test(elem)){nodes.push(context.createTextNode(rleadingWhitespace.exec(elem)[0]));} +if(!jQuery.support.tbody){elem=tag==="table"&&!rtbody.test(elem)?tmp.firstChild:wrap[1]==="
"&&!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);tmp.textContent="";while(tmp.firstChild){tmp.removeChild(tmp.firstChild);} +tmp=safe.lastChild;}}} +if(tmp){safe.removeChild(tmp);} +if(!jQuery.support.appendChecked){jQuery.grep(getAll(nodes,"input"),fixDefaultChecked);} +i=0;while((elem=nodes[i++])){if(selection&&jQuery.inArray(elem,selection)!==-1){continue;} +contains=jQuery.contains(elem.ownerDocument,elem);tmp=getAll(safe.appendChild(elem),"script");if(contains){setGlobalEval(tmp);} +if(scripts){j=0;while((elem=tmp[j++])){if(rscriptType.test(elem.type||"")){scripts.push(elem);}}}} +tmp=null;return safe;},cleanData:function(elems,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);}else{jQuery.removeEvent(elem,type,data.handle);}}} +if(cache[id]){delete cache[id];if(deleteExpando){delete elem[internalKey];}else if(typeof elem.removeAttribute!==core_strundefined){elem.removeAttribute(internalKey);}else{elem[internalKey]=null;} +core_deletedIds.push(id);}}}}},_evalUrl:function(url){return jQuery.ajax({url:url,type:"GET",dataType:"script",async:false,global:false,"throws":true});}});jQuery.fn.extend({wrapAll:function(html){if(jQuery.isFunction(html)){return this.each(function(i){jQuery(this).wrapAll(html.call(this,i));});} +if(this[0]){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();}});var iframe,getStyles,curCSS,ralpha=/alpha\([^)]*\)/i,ropacity=/opacity\s*=\s*([^)]*)/,rposition=/^(top|right|bottom|left)$/,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"];function vendorPropName(style,name){if(name in style){return name;} +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){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(;index1);},show:function(){return showHide(this,true);},hide:function(){return showHide(this);},toggle:function(state){if(typeof state==="boolean"){return state?this.show():this.hide();} +return this.each(function(){if(isHidden(this)){jQuery(this).show();}else{jQuery(this).hide();}});}});jQuery.extend({cssHooks:{opacity:{get:function(elem,computed){if(computed){var ret=curCSS(elem,"opacity");return ret===""?"1":ret;}}}},cssNumber:{"columnCount":true,"fillOpacity":true,"fontWeight":true,"lineHeight":true,"opacity":true,"order":true,"orphans":true,"widows":true,"zIndex":true,"zoom":true},cssProps:{"float":jQuery.support.cssFloat?"cssFloat":"styleFloat"},style:function(elem,name,value,extra){if(!elem||elem.nodeType===3||elem.nodeType===8||!elem.style){return;} +var ret,type,hooks,origName=jQuery.camelCase(name),style=elem.style;name=jQuery.cssProps[origName]||(jQuery.cssProps[origName]=vendorPropName(style,origName));hooks=jQuery.cssHooks[name]||jQuery.cssHooks[origName];if(value!==undefined){type=typeof value;if(type==="string"&&(ret=rrelNum.exec(value))){value=(ret[1]+1)*ret[2]+parseFloat(jQuery.css(elem,name));type="number";} if(value==null||type==="number"&&isNaN(value)){return;} if(type==="number"&&!jQuery.cssNumber[origName]){value+="px";} -if(!hooks||!("set"in hooks)||(value=hooks.set(elem,value))!==undefined){try{style[name]=value;}catch(e){}}}else{if(hooks&&"get"in hooks&&(ret=hooks.get(elem,false,extra))!==undefined){return ret;} -return style[name];}},css:function(elem,name,extra){var ret,hooks;name=jQuery.camelCase(name);hooks=jQuery.cssHooks[name];name=jQuery.cssProps[name]||name;if(name==="cssFloat"){name="float";} -if(hooks&&"get"in hooks&&(ret=hooks.get(elem,true,extra))!==undefined){return ret;}else if(curCSS){return curCSS(elem,name);}},swap:function(elem,options,callback){var old={},ret,name;for(name in options){old[name]=elem.style[name];elem.style[name]=options[name];} -ret=callback.call(elem);for(name in options){elem.style[name]=old[name];} -return ret;}});jQuery.curCSS=jQuery.css;if(document.defaultView&&document.defaultView.getComputedStyle){getComputedStyle=function(elem,name){var ret,defaultView,computedStyle,width,style=elem.style;name=name.replace(rupper,"-$1").toLowerCase();if((defaultView=elem.ownerDocument.defaultView)&&(computedStyle=defaultView.getComputedStyle(elem,null))){ret=computedStyle.getPropertyValue(name);if(ret===""&&!jQuery.contains(elem.ownerDocument.documentElement,elem)){ret=jQuery.style(elem,name);}} -if(!jQuery.support.pixelMargin&&computedStyle&&rmargin.test(name)&&rnumnonpx.test(ret)){width=style.width;style.width=ret;ret=computedStyle.width;style.width=width;} -return ret;};} -if(document.documentElement.currentStyle){currentStyle=function(elem,name){var left,rsLeft,uncomputed,ret=elem.currentStyle&&elem.currentStyle[name],style=elem.style;if(ret==null&&style&&(uncomputed=style[name])){ret=uncomputed;} -if(rnumnonpx.test(ret)){left=style.left;rsLeft=elem.runtimeStyle&&elem.runtimeStyle.left;if(rsLeft){elem.runtimeStyle.left=elem.currentStyle.left;} -style.left=name==="fontSize"?"1em":ret;ret=style.pixelLeft+"px";style.left=left;if(rsLeft){elem.runtimeStyle.left=rsLeft;}} +if(!jQuery.support.clearCloneStyle&&value===""&&name.indexOf("background")===0){style[name]="inherit";} +if(!hooks||!("set"in hooks)||(value=hooks.set(elem,value,extra))!==undefined){try{style[name]=value;}catch(e){}}}else{if(hooks&&"get"in hooks&&(ret=hooks.get(elem,false,extra))!==undefined){return ret;} +return style[name];}},css:function(elem,name,extra,styles){var num,val,hooks,origName=jQuery.camelCase(name);name=jQuery.cssProps[origName]||(jQuery.cssProps[origName]=vendorPropName(elem.style,origName));hooks=jQuery.cssHooks[name]||jQuery.cssHooks[origName];if(hooks&&"get"in hooks){val=hooks.get(elem,true,extra);} +if(val===undefined){val=curCSS(elem,name,styles);} +if(val==="normal"&&name in cssNormalTransform){val=cssNormalTransform[name];} +if(extra===""||extra){num=parseFloat(val);return extra===true||jQuery.isNumeric(num)?num||0:val;} +return val;}});if(window.getComputedStyle){getStyles=function(elem){return window.getComputedStyle(elem,null);};curCSS=function(elem,name,_computed){var width,minWidth,maxWidth,computed=_computed||getStyles(elem),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);} +if(rnumnonpx.test(ret)&&rmargin.test(name)){width=style.width;minWidth=style.minWidth;maxWidth=style.maxWidth;style.minWidth=style.maxWidth=style.width=ret;ret=computed.width;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;if(ret==null&&style&&style[name]){ret=style[name];} +if(rnumnonpx.test(ret)&&!rposition.test(name)){left=style.left;rs=elem.runtimeStyle;rsLeft=rs&&rs.left;if(rsLeft){rs.left=elem.currentStyle.left;} +style.left=name==="fontSize"?"1em":ret;ret=style.pixelLeft+"px";style.left=left;if(rsLeft){rs.left=rsLeft;}} return ret===""?"auto":ret;};} -curCSS=getComputedStyle||currentStyle;function getWidthOrHeight(elem,name,extra){var val=name==="width"?elem.offsetWidth:elem.offsetHeight,i=name==="width"?1:0,len=4;if(val>0){if(extra!=="border"){for(;i=1&&jQuery.trim(filter.replace(ralpha,""))===""){style.removeAttribute("filter");if(currentStyle&&!currentStyle.filter){return;}} +valueIsBorderBox=isBorderBox&&(jQuery.support.boxSizingReliable||val===elem.style[name]);val=parseFloat(val)||0;} +return(val+ +augmentWidthOrHeight(elem,name,extra||(isBorderBox?"border":"content"),valueIsBorderBox,styles))+"px";} +function css_defaultDisplay(nodeName){var doc=document,display=elemdisplay[nodeName];if(!display){display=actualDisplay(nodeName,doc);if(display==="none"||!display){iframe=(iframe||jQuery("
+
diff --git a/ckan/tests/functional/test_tracking.py b/ckan/tests/functional/test_tracking.py index 44393036f5f..ec95547822d 100644 --- a/ckan/tests/functional/test_tracking.py +++ b/ckan/tests/functional/test_tracking.py @@ -61,14 +61,14 @@ def _post_to_tracking(self, app, url, type_='page', ip='199.204.138.90', ''' params = {'url': url, 'type': type_} - app.post('/_tracking', params=params, - extra_environ={ - # The tracking middleware crashes if these aren't present. - 'HTTP_USER_AGENT': browser, - 'REMOTE_ADDR': ip, - 'HTTP_ACCEPT_LANGUAGE': 'en', - 'HTTP_ACCEPT_ENCODING': 'gzip, deflate', - }) + extra_environ = { + # The tracking middleware crashes if these aren't present. + 'HTTP_USER_AGENT': browser, + 'REMOTE_ADDR': ip, + 'HTTP_ACCEPT_LANGUAGE': 'en', + 'HTTP_ACCEPT_ENCODING': 'gzip, deflate', + } + app.post('/_tracking', params=params, extra_environ=extra_environ) def _update_tracking_summary(self): '''Update CKAN's tracking summary data. diff --git a/ckan/tests/test_coding_standards.py b/ckan/tests/test_coding_standards.py index 19a37aea8f3..eab5d5ae9e2 100644 --- a/ckan/tests/test_coding_standards.py +++ b/ckan/tests/test_coding_standards.py @@ -767,9 +767,7 @@ class TestPep8(object): 'ckan/tests/lib/test_accept.py', 'ckan/tests/lib/test_alphabet_pagination.py', 'ckan/tests/lib/test_cli.py', - 'ckan/tests/lib/test_datapreview.py', 'ckan/tests/lib/test_dictization.py', - 'ckan/tests/lib/test_dictization_schema.py', 'ckan/tests/lib/test_email_notifications.py', 'ckan/tests/lib/test_field_types.py', 'ckan/tests/lib/test_hash.py', @@ -788,7 +786,6 @@ class TestPep8(object): 'ckan/tests/logic/test_action.py', 'ckan/tests/logic/test_auth.py', 'ckan/tests/logic/test_tag.py', - 'ckan/tests/logic/test_tag_vocab.py', 'ckan/tests/logic/test_validators.py', 'ckan/tests/misc/test_format_text.py', 'ckan/tests/misc/test_mock_mail_server.py', @@ -817,9 +814,7 @@ class TestPep8(object): 'ckanext/datastore/bin/datastore_setup.py', 'ckanext/datastore/logic/action.py', 'ckanext/datastore/plugin.py', - 'ckanext/datastore/tests/test_configure.py', 'ckanext/datastore/tests/test_create.py', - 'ckanext/datastore/tests/test_delete.py', 'ckanext/datastore/tests/test_search.py', 'ckanext/datastore/tests/test_upsert.py', 'ckanext/example_idatasetform/plugin.py', @@ -868,12 +863,19 @@ def test_pep8_pass(self): msg = 'The following files passed pep8 but are blacklisted' show_passing(msg, self.passes) - @staticmethod - def find_pep8_errors(filename=None, lines=None): - + @classmethod + def find_pep8_errors(cls, filename=None, lines=None): try: sys.stdout = cStringIO.StringIO() - checker = pep8.Checker(filename=filename, lines=lines) + config = {} + + # Ignore long lines on test files, as the test names can get long + # when following our test naming standards. + if cls._is_test(filename): + config['ignore'] = ['E501'] + + checker = pep8.Checker(filename=filename, lines=lines, + **config) checker.check_all() output = sys.stdout.getvalue() finally: @@ -888,6 +890,10 @@ def find_pep8_errors(filename=None, lines=None): errors.append('%s ln:%s %s' % (error, line_no, desc)) return errors + @classmethod + def _is_test(cls, filename): + return bool(re.search('(^|\W)test_.*\.py$', filename, re.IGNORECASE)) + class TestActionAuth(object): ''' These tests check the logic auth/action functions are compliant. The diff --git a/ckanext/datastore/bin/datastore_setup.py b/ckanext/datastore/bin/datastore_setup.py index 3a5564fbb1a..d27af1cba70 100644 --- a/ckanext/datastore/bin/datastore_setup.py +++ b/ckanext/datastore/bin/datastore_setup.py @@ -21,15 +21,16 @@ def _run_cmd(command_line, inputstring=''): sys.exit(1) -def _run_sql(sql, as_sql_user, database='postgres'): +def _run_sql(sql, as_sql_user, pgport, database='postgres'): logging.debug("Executing: \n#####\n", sql, "\n####\nOn database:", database) - _run_cmd("sudo -u '{username}' psql --dbname='{database}' --no-password --set ON_ERROR_STOP=1".format( + _run_cmd("sudo -u '{username}' psql -p {pgport} --dbname='{database}' --no-password --set ON_ERROR_STOP=1".format( + pgport=pgport or '5432', username=as_sql_user, database=database ), inputstring=sql) -def set_permissions(pguser, ckandb, datastoredb, ckanuser, writeuser, readonlyuser): +def set_permissions(pguser, pgport, ckandb, datastoredb, ckanuser, writeuser, readonlyuser): __dir__ = os.path.dirname(os.path.abspath(__file__)) filepath = os.path.join(__dir__, 'set_permissions.sql') with open(filepath) as f: @@ -44,6 +45,7 @@ def set_permissions(pguser, ckandb, datastoredb, ckanuser, writeuser, readonlyus _run_sql(sql, as_sql_user=pguser, + pgport=pgport, database=datastoredb) @@ -53,6 +55,8 @@ def set_permissions(pguser, ckandb, datastoredb, ckanuser, writeuser, readonlyus description='Set the permissions on the CKAN datastore. ', epilog='"The ships hung in the sky in much the same way that bricks don\'t."') + argparser.add_argument('-P', '--pg_port', dest='pgport', default='5432', type=str, + help="the postgres port") argparser.add_argument('-p', '--pg_super_user', dest='pguser', default='postgres', type=str, help="the postgres super user") @@ -71,6 +75,7 @@ def set_permissions(pguser, ckandb, datastoredb, ckanuser, writeuser, readonlyus set_permissions( pguser=args.pguser, + pgport=args.pgport, ckandb=args.ckandb, datastoredb=args.datastoredb, ckanuser=args.ckanuser, diff --git a/ckanext/datastore/commands.py b/ckanext/datastore/commands.py index 37866cb7ed5..c1171058628 100644 --- a/ckanext/datastore/commands.py +++ b/ckanext/datastore/commands.py @@ -59,6 +59,7 @@ def command(self): if cmd == 'set-permissions': setup.set_permissions( pguser=self.args[1], + pgport=self.db_ckan_url_parts['db_port'], ckandb=self.db_ckan_url_parts['db_name'], datastoredb=self.db_write_url_parts['db_name'], ckanuser=self.db_ckan_url_parts['db_user'], diff --git a/ckanext/datastore/logic/auth.py b/ckanext/datastore/logic/auth.py index d002d106fda..73d78e03b84 100644 --- a/ckanext/datastore/logic/auth.py +++ b/ckanext/datastore/logic/auth.py @@ -4,6 +4,7 @@ def datastore_auth(context, data_dict, privilege='resource_update'): if not 'id' in data_dict: data_dict['id'] = data_dict.get('resource_id') + user = context.get('user') authorized = p.toolkit.check_access(privilege, context, data_dict) @@ -19,7 +20,14 @@ def datastore_auth(context, data_dict, privilege='resource_update'): def datastore_create(context, data_dict): - return datastore_auth(context, data_dict) + + if 'resource' in data_dict and data_dict['resource'].get('package_id'): + data_dict['id'] = data_dict['resource'].get('package_id') + privilege = 'package_update' + else: + privilege = 'resource_update' + + return datastore_auth(context, data_dict, privilege=privilege) def datastore_upsert(context, data_dict): diff --git a/ckanext/datastore/tests/test_create.py b/ckanext/datastore/tests/test_create.py index f2db232af8a..c1f464b48a9 100644 --- a/ckanext/datastore/tests/test_create.py +++ b/ckanext/datastore/tests/test_create.py @@ -538,6 +538,43 @@ def test_create_basic(self): assert res_dict['success'] is True, res_dict + def test_create_datastore_resource_on_dataset(self): + pkg = model.Package.get('annakarenina') + + data = { + 'resource': { + 'package_id': pkg.id, + }, + 'fields': [{'id': 'boo%k', 'type': 'text'}, # column with percent + {'id': 'author', 'type': 'json'}], + 'indexes': [['boo%k', 'author'], 'author'], + 'records': [{'boo%k': 'crime', 'author': ['tolstoy', 'dostoevsky']}, + {'boo%k': 'annakarenina', 'author': ['tolstoy', 'putin']}, + {'boo%k': 'warandpeace'}] # treat author as null + } + + postparams = '%s=1' % json.dumps(data) + auth = {'Authorization': str(self.normal_user.apikey)} + res = self.app.post('/api/action/datastore_create', params=postparams, + extra_environ=auth) + res_dict = json.loads(res.body) + + assert res_dict['success'] is True + res = res_dict['result'] + assert res['fields'] == data['fields'], res['fields'] + assert res['records'] == data['records'] + + # Get resource details + data = { + 'id': res['resource_id'] + } + postparams = '%s=1' % json.dumps(data) + res = self.app.post('/api/action/resource_show', params=postparams) + res_dict = json.loads(res.body) + + assert res_dict['result']['datastore_active'] is True + + def test_guess_types(self): resource = model.Package.get('annakarenina').resources[1] diff --git a/ckanext/example_idatasetform/plugin.py b/ckanext/example_idatasetform/plugin.py index de3aa86692b..12542a3f252 100644 --- a/ckanext/example_idatasetform/plugin.py +++ b/ckanext/example_idatasetform/plugin.py @@ -92,6 +92,10 @@ def _modify_package_schema(self, schema): 'custom_text': [tk.get_validator('ignore_missing'), tk.get_converter('convert_to_extras')] }) + # Add our custom_resource_text metadata field to the schema + schema['resources'].update({ + 'custom_resource_text' : [ tk.get_validator('ignore_missing') ] + }) return schema def create_package_schema(self): @@ -124,6 +128,9 @@ def show_package_schema(self): tk.get_validator('ignore_missing')] }) + schema['resources'].update({ + 'custom_resource_text' : [ tk.get_validator('ignore_missing') ] + }) return schema # These methods just record how many times they're called, for testing diff --git a/ckanext/example_idatasetform/plugin_v1.py b/ckanext/example_idatasetform/plugin_v1.py new file mode 100644 index 00000000000..183e12ff28e --- /dev/null +++ b/ckanext/example_idatasetform/plugin_v1.py @@ -0,0 +1,43 @@ +import ckan.plugins as p +import ckan.plugins.toolkit as tk + + +class ExampleIDatasetFormPlugin(p.SingletonPlugin, tk.DefaultDatasetForm): + p.implements(p.IDatasetForm) + + def create_package_schema(self): + # let's grab the default schema in our plugin + schema = super(ExampleIDatasetFormPlugin, self).create_package_schema() + #our custom field + schema.update({ + 'custom_text': [tk.get_validator('ignore_missing'), + tk.get_converter('convert_to_extras')] + }) + return schema + + def update_package_schema(self): + schema = super(ExampleIDatasetFormPlugin, self).update_package_schema() + #our custom field + schema.update({ + 'custom_text': [tk.get_validator('ignore_missing'), + tk.get_converter('convert_to_extras')] + }) + return schema + + def show_package_schema(self): + schema = super(ExampleIDatasetFormPlugin, self).show_package_schema() + schema.update({ + 'custom_text': [tk.get_converter('convert_from_extras'), + tk.get_validator('ignore_missing')] + }) + return schema + + def is_fallback(self): + # Return True to register this plugin as the default handler for + # package types not handled by any other IDatasetForm plugin. + return True + + def package_types(self): + # This plugin doesn't handle any special package types, it just + # registers itself as the default (above). + return [] diff --git a/ckanext/example_idatasetform/plugin_v2.py b/ckanext/example_idatasetform/plugin_v2.py new file mode 100644 index 00000000000..9741d8be7ff --- /dev/null +++ b/ckanext/example_idatasetform/plugin_v2.py @@ -0,0 +1,50 @@ +import ckan.plugins as p +import ckan.plugins.toolkit as tk + + +class ExampleIDatasetFormPlugin(p.SingletonPlugin, tk.DefaultDatasetForm): + p.implements(p.IDatasetForm) + p.implements(p.IConfigurer) + + def create_package_schema(self): + # let's grab the default schema in our plugin + schema = super(ExampleIDatasetFormPlugin, self).create_package_schema() + #our custom field + schema.update({ + 'custom_text': [tk.get_validator('ignore_missing'), + tk.get_converter('convert_to_extras')] + }) + return schema + + def update_package_schema(self): + schema = super(ExampleIDatasetFormPlugin, self).update_package_schema() + #our custom field + schema.update({ + 'custom_text': [tk.get_validator('ignore_missing'), + tk.get_converter('convert_to_extras')] + }) + return schema + + def show_package_schema(self): + schema = super(ExampleIDatasetFormPlugin, self).show_package_schema() + schema.update({ + 'custom_text': [tk.get_converter('convert_from_extras'), + tk.get_validator('ignore_missing')] + }) + return schema + + #is fall back + def is_fallback(self): + # Return True to register this plugin as the default handler for + # package types not handled by any other IDatasetForm plugin. + return True + + def package_types(self): + # This plugin doesn't handle any special package types, it just + # registers itself as the default (above). + return [] + + def update_config(self, config): + # Add this plugin's templates dir to CKAN's extra_template_paths, so + # that CKAN will use this plugin's custom templates. + tk.add_template_directory(config, 'templates') diff --git a/ckanext/example_idatasetform/plugin_v3.py b/ckanext/example_idatasetform/plugin_v3.py new file mode 100644 index 00000000000..a80d26a46db --- /dev/null +++ b/ckanext/example_idatasetform/plugin_v3.py @@ -0,0 +1,42 @@ +'''Example IDatasetFormPlugin''' +import ckan.plugins as p +import ckan.plugins.toolkit as tk + + +class ExampleIDatasetFormPlugin(p.SingletonPlugin, tk.DefaultDatasetForm): + p.implements(p.IDatasetForm) + + def _modify_package_schema(self, schema): + schema.update({ + 'custom_text': [tk.get_validator('ignore_missing'), + tk.get_converter('convert_to_extras')] + }) + return schema + + def create_package_schema(self): + schema = super(ExampleIDatasetFormPlugin, self).create_package_schema() + schema = self._modify_package_schema(schema) + return schema + + def update_package_schema(self): + schema = super(ExampleIDatasetFormPlugin, self).update_package_schema() + schema = self._modify_package_schema(schema) + return schema + + def show_package_schema(self): + schema = super(ExampleIDatasetFormPlugin, self).show_package_schema() + schema.update({ + 'custom_text': [tk.get_converter('convert_from_extras'), + tk.get_validator('ignore_missing')] + }) + return schema + + def is_fallback(self): + # Return True to register this plugin as the default handler for + # package types not handled by any other IDatasetForm plugin. + return True + + def package_types(self): + # This plugin doesn't handle any special package types, it just + # registers itself as the default (above). + return [] diff --git a/ckanext/example_idatasetform/plugin_v4.py b/ckanext/example_idatasetform/plugin_v4.py new file mode 100644 index 00000000000..01f6ce5c430 --- /dev/null +++ b/ckanext/example_idatasetform/plugin_v4.py @@ -0,0 +1,89 @@ +import ckan.plugins as p +import ckan.plugins.toolkit as tk + + +def create_country_codes(): + user = tk.get_action('get_site_user')({'ignore_auth': True}, {}) + context = {'user': user['name']} + try: + data = {'id': 'country_codes'} + tk.get_action('vocabulary_show')(context, data) + except tk.ObjectNotFound: + data = {'name': 'country_codes'} + vocab = tk.get_action('vocabulary_create')(context, data) + for tag in (u'uk', u'ie', u'de', u'fr', u'es'): + data = {'name': tag, 'vocabulary_id': vocab['id']} + tk.get_action('tag_create')(context, data) + + +def country_codes(): + create_country_codes() + try: + tag_list = tk.get_action('tag_list') + country_codes = tag_list(data_dict={'vocabulary_id': 'country_codes'}) + return country_codes + except tk.ObjectNotFound: + return None + + +class ExampleIDatasetFormPlugin(p.SingletonPlugin, tk.DefaultDatasetForm): + p.implements(p.IDatasetForm) + p.implements(p.IConfigurer) + p.implements(p.ITemplateHelpers) + + def get_helpers(self): + return {'country_codes': country_codes} + + def _modify_package_schema(self, schema): + schema.update({ + 'custom_text': [tk.get_validator('ignore_missing'), + tk.get_converter('convert_to_extras')] + }) + schema.update({ + 'country_code': [ + tk.get_validator('ignore_missing'), + tk.get_converter('convert_to_tags')('country_codes') + ] + }) + return schema + + def show_package_schema(self): + schema = super(ExampleIDatasetFormPlugin, self).show_package_schema() + schema.update({ + 'custom_text': [tk.get_converter('convert_from_extras'), + tk.get_validator('ignore_missing')] + }) + + schema['tags']['__extras'].append(tk.get_converter('free_tags_only')) + schema.update({ + 'country_code': [ + tk.get_converter('convert_from_tags')('country_codes'), + tk.get_validator('ignore_missing')] + }) + return schema + + def create_package_schema(self): + schema = super(ExampleIDatasetFormPlugin, self).create_package_schema() + schema = self._modify_package_schema(schema) + return schema + + def update_package_schema(self): + schema = super(ExampleIDatasetFormPlugin, self).update_package_schema() + schema = self._modify_package_schema(schema) + return schema + + def is_fallback(self): + # Return True to register this plugin as the default handler for + # package types not handled by any other IDatasetForm plugin. + return True + + def package_types(self): + # This plugin doesn't handle any special package types, it just + # registers itself as the default (above). + return [] + + #update config + def update_config(self, config): + # Add this plugin's templates dir to CKAN's extra_template_paths, so + # that CKAN will use this plugin's custom templates. + tk.add_template_directory(config, 'templates') diff --git a/ckanext/example_idatasetform/templates/package/search.html b/ckanext/example_idatasetform/templates/package/search.html new file mode 100644 index 00000000000..67cfe5229f1 --- /dev/null +++ b/ckanext/example_idatasetform/templates/package/search.html @@ -0,0 +1,21 @@ +{% ckan_extends %} + +{% block form %} + {% set facets = { + 'fields': c.fields_grouped, + 'search': c.search_facets, + 'titles': c.facet_titles, + 'translated_fields': c.translated_fields, + 'remove_field': c.remove_field } + %} + {% set sorting = [ + (_('Relevance'), 'score desc, metadata_modified desc'), + (_('Name Ascending'), 'title_string asc'), + (_('Name Descending'), 'title_string desc'), + (_('Last Modified'), 'metadata_modified desc'), + (_('Custom Field Ascending'), 'custom_text asc'), + (_('Custom Field Descending'), 'custom_text desc'), + (_('Popular'), 'views_recent desc') if g.tracking_enabled else (false, false) ] + %} + {% snippet 'snippets/search_form.html', type='dataset', query=c.q, sorting=sorting, sorting_selected=c.sort_by_selected, count=c.page.item_count, facets=facets, show_empty=request.params, error=c.query_error %} +{% endblock %} diff --git a/ckanext/example_idatasetform/templates/package/snippets/additional_info.html b/ckanext/example_idatasetform/templates/package/snippets/additional_info.html new file mode 100644 index 00000000000..c48488e5cc4 --- /dev/null +++ b/ckanext/example_idatasetform/templates/package/snippets/additional_info.html @@ -0,0 +1,10 @@ +{% ckan_extends %} + +{% block extras %} + {% if pkg_dict.custom_text %} +
+ + + + {% endif %} +{% endblock %} diff --git a/ckanext/example_idatasetform/templates/package/snippets/resource_form.html b/ckanext/example_idatasetform/templates/package/snippets/resource_form.html new file mode 100644 index 00000000000..5e36126ac62 --- /dev/null +++ b/ckanext/example_idatasetform/templates/package/snippets/resource_form.html @@ -0,0 +1,7 @@ +{% ckan_extends %} + +{% block basic_fields_url %} +{{ super() }} + + {{ form.input('custom_resource_text', label=_('Custom Text'), id='field-custom_resource_text', placeholder=_('custom resource text'), value=data.custom_resource_text, error=errors.custom_resource_text, classes=['control-medium']) }} +{% endblock %} diff --git a/ckanext/example_idatasetform/tests/__init__.py b/ckanext/example_idatasetform/tests/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ckanext/example_idatasetform/tests/test_example_idatasetform.py b/ckanext/example_idatasetform/tests/test_example_idatasetform.py new file mode 100644 index 00000000000..cbe34059e92 --- /dev/null +++ b/ckanext/example_idatasetform/tests/test_example_idatasetform.py @@ -0,0 +1,248 @@ +import nose.tools as nt + +import pylons.config as config + +import ckan.model as model +import ckan.plugins as plugins +import ckan.new_tests.helpers as helpers +import ckanext.example_idatasetform as idf +import ckan.lib.search + + +class ExampleIDatasetFormPluginBase(object): + '''Version 1, 2 and 3 of the plugin are basically the same, so this class + provides the tests that all three versions of the plugins will run''' + @classmethod + def setup_class(cls): + cls.original_config = config.copy() + + def teardown(self): + model.repo.rebuild_db() + ckan.lib.search.clear() + + @classmethod + def teardown_class(cls): + helpers.reset_db() + model.repo.rebuild_db() + ckan.lib.search.clear() + + config.clear() + config.update(cls.original_config) + + def test_package_create(self): + result = helpers.call_action('package_create', name='test_package', + custom_text='this is my custom text') + nt.assert_equals('this is my custom text', result['custom_text']) + + def test_package_update(self): + helpers.call_action('package_create', name='test_package', + custom_text='this is my custom text') + result = helpers.call_action('package_update', name='test_package', + custom_text='this is my updated text') + nt.assert_equals('this is my updated text', result['custom_text']) + + def test_package_show(self): + helpers.call_action('package_create', name='test_package', + custom_text='this is my custom text') + result = helpers.call_action('package_show', name_or_id='test_package') + nt.assert_equals('this is my custom text', result['custom_text']) + + +class TestVersion1(ExampleIDatasetFormPluginBase): + @classmethod + def setup_class(cls): + super(TestVersion1, cls).setup_class() + plugins.load('example_idatasetform_v1') + + @classmethod + def teardown_class(cls): + plugins.unload('example_idatasetform_v1') + super(TestVersion1, cls).teardown_class() + + +class TestVersion2(ExampleIDatasetFormPluginBase): + @classmethod + def setup_class(cls): + super(TestVersion2, cls).setup_class() + plugins.load('example_idatasetform_v2') + + @classmethod + def teardown_class(cls): + plugins.unload('example_idatasetform_v2') + super(TestVersion2, cls).teardown_class() + + +class TestVersion3(ExampleIDatasetFormPluginBase): + @classmethod + def setup_class(cls): + super(TestVersion3, cls).setup_class() + plugins.load('example_idatasetform_v3') + + @classmethod + def teardown_class(cls): + plugins.unload('example_idatasetform_v3') + super(TestVersion3, cls).teardown_class() + + +class TestIDatasetFormPluginVersion4(object): + @classmethod + def setup_class(cls): + cls.original_config = config.copy() + plugins.load('example_idatasetform_v4') + + def teardown(self): + model.repo.rebuild_db() + + @classmethod + def teardown_class(cls): + plugins.unload('example_idatasetform_v4') + helpers.reset_db() + ckan.lib.search.clear() + + config.clear() + config.update(cls.original_config) + + def test_package_create(self): + idf.plugin_v4.create_country_codes() + result = helpers.call_action('package_create', name='test_package', + custom_text='this is my custom text', + country_code='uk') + nt.assert_equals('this is my custom text', result['custom_text']) + nt.assert_equals([u'uk'], result['country_code']) + + def test_package_create_wrong_country_code(self): + idf.plugin_v4.create_country_codes() + nt.assert_raises(plugins.toolkit.ValidationError, + helpers.call_action, + 'package_create', + name='test_package', + custom_text='this is my custom text', + country_code='notcode') + + def test_package_update(self): + idf.plugin_v4.create_country_codes() + helpers.call_action('package_create', name='test_package', + custom_text='this is my custom text', + country_code='uk') + result = helpers.call_action('package_update', name='test_package', + custom_text='this is my updated text', + country_code='ie') + nt.assert_equals('this is my updated text', result['custom_text']) + nt.assert_equals([u'ie'], result['country_code']) + + +class TestIDatasetFormPlugin(object): + @classmethod + def setup_class(cls): + cls.original_config = config.copy() + plugins.load('example_idatasetform') + + def teardown(self): + model.repo.rebuild_db() + ckan.lib.search.clear() + + @classmethod + def teardown_class(cls): + plugins.unload('example_idatasetform') + helpers.reset_db() + ckan.lib.search.clear() + + config.clear() + config.update(cls.original_config) + + def test_package_create(self): + idf.plugin.create_country_codes() + result = helpers.call_action( + 'package_create', name='test_package', + custom_text='this is my custom text', country_code='uk', + resources=[{ + 'url': 'http://test.com/', + 'custom_resource_text': 'my custom resource', + }]) + nt.assert_equals('my custom resource', + result['resources'][0]['custom_resource_text']) + + def test_package_update(self): + idf.plugin.create_country_codes() + helpers.call_action( + 'package_create', name='test_package', + custom_text='this is my custom text', country_code='uk', + resources=[{ + 'url': 'http://test.com/', + 'custom_resource_text': 'my custom resource', + }]) + result = helpers.call_action( + 'package_update', + name='test_package', + custom_text='this is my updated text', + country_code='ie', + resources=[{ + 'url': 'http://test.com/', + 'custom_resource_text': 'updated custom resource', + }] + ) + nt.assert_equals('this is my updated text', result['custom_text']) + nt.assert_equals([u'ie'], result['country_code']) + nt.assert_equals('updated custom resource', + result['resources'][0]['custom_resource_text']) + + def test_package_show(self): + idf.plugin.create_country_codes() + helpers.call_action( + 'package_create', name='test_package', + custom_text='this is my custom text', country_code='uk', + resources=[{ + 'url': 'http://test.com/', + 'custom_resource_text': 'my custom resource', + }] + ) + result = helpers.call_action('package_show', name_or_id='test_package') + nt.assert_equals('my custom resource', + result['resources'][0]['custom_resource_text']) + nt.assert_equals('my custom resource', + result['resources'][0]['custom_resource_text']) + + +class TestCustomSearch(object): + @classmethod + def setup_class(cls): + cls.original_config = config.copy() + cls.app = helpers._get_test_app() + plugins.load('example_idatasetform') + + def teardown(self): + model.repo.rebuild_db() + ckan.lib.search.clear() + + @classmethod + def teardown_class(cls): + plugins.unload('example_idatasetform') + helpers.reset_db() + ckan.lib.search.clear() + + config.clear() + config.update(cls.original_config) + + def test_custom_search(self): + helpers.call_action('package_create', name='test_package_a', + custom_text='z') + helpers.call_action('package_create', name='test_package_b', + custom_text='y') + + response = self.app.get('/dataset') + + # change the sort by form to our custom_text ascending + response.forms[1].fields['sort'][0].value = 'custom_text asc' + response = response.forms[1].submit() + # check that package_b appears before package a (y < z) + a = response.body.index('test_package_a') + b = response.body.index('test_package_b') + nt.assert_true(b < a) + + response.forms[1].fields['sort'][0].value = 'custom_text desc' + # check that package_a appears before package b (z is first in + # descending order) + response = response.forms[1].submit() + a = response.body.index('test_package_a') + b = response.body.index('test_package_b') + nt.assert_true(a < b) diff --git a/ckanext/resourceproxy/controller.py b/ckanext/resourceproxy/controller.py index 0e8fd9bfd11..c0bd4db47a0 100644 --- a/ckanext/resourceproxy/controller.py +++ b/ckanext/resourceproxy/controller.py @@ -5,6 +5,7 @@ import ckan.logic as logic import ckan.lib.base as base +from ckan.common import _ log = getLogger(__name__) @@ -20,7 +21,11 @@ def proxy_resource(context, data_dict): than the maximum file size. ''' resource_id = data_dict['resource_id'] log.info('Proxify resource {id}'.format(id=resource_id)) - resource = logic.get_action('resource_show')(context, {'id': resource_id}) + try: + resource = logic.get_action('resource_show')(context, {'id': + resource_id}) + except logic.NotFound: + base.abort(404, _('Resource not found')) url = resource['url'] parts = urlparse.urlsplit(url) diff --git a/ckanext/resourceproxy/tests/test_proxy.py b/ckanext/resourceproxy/tests/test_proxy.py index dac7c747606..7de6e965436 100644 --- a/ckanext/resourceproxy/tests/test_proxy.py +++ b/ckanext/resourceproxy/tests/test_proxy.py @@ -170,3 +170,12 @@ def test_resource_url_doesnt_proxy_non_http_or_https_urls_by_default(self): proxied_url = proxy.get_proxified_resource_url(data_dict, scheme) assert non_proxied_url == url, non_proxied_url assert proxied_url != url, proxied_url + + def test_non_existent_resource(self): + self.data_dict = {'package': {'name': 'doesnotexist'}, + 'resource': {'id': 'doesnotexist'}} + + proxied_url = proxy.get_proxified_resource_url(self.data_dict) + result = self.app.get(proxied_url, status='*') + assert result.status == 404, result.status + assert 'Resource not found' in result.body, result.body diff --git a/ckanext/stats/__init__.py b/ckanext/stats/__init__.py index b646540d6be..de40ea7ca05 100644 --- a/ckanext/stats/__init__.py +++ b/ckanext/stats/__init__.py @@ -1 +1 @@ -# empty file needed for pylons to find templates in this directory +__import__('pkg_resources').declare_namespace(__name__) diff --git a/doc/contributing/architecture.rst b/doc/contributing/architecture.rst index 50114ff53d4..be571c13b3a 100644 --- a/doc/contributing/architecture.rst +++ b/doc/contributing/architecture.rst @@ -160,21 +160,32 @@ the helper functions found in ``ckan.lib.helpers.__allowed_functions__``. Deprecation ----------- -- Anything that may be used by extensions (see :doc:`/extensions/index`) needs - to maintain backward compatibility at call-site. ie - template helper - functions and functions defined in the plugins toolkit. +- Anything that may be used by :doc:`extensions `, + :doc:`themes ` or :doc:`API clients ` needs to + maintain backward compatibility at call-site. For example: action functions, + template helper functions and functions defined in the plugins toolkit. - The length of time of deprecation is evaluated on a function-by-function - basis. At minimum, a function should be marked as deprecated during a point + basis. At minimum, a function should be marked as deprecated during a point release. -- To mark a helper function, use the ``deprecated`` decorator found in - ``ckan.lib.maintain`` eg: :: - - @deprecated() - def facet_items(*args, **kwargs): - """ - DEPRECATED: Use the new facet data structure, and `unselected_facet_items()` - """ - # rest of function definition. - +- To deprecate a function use the :py:func:`ckan.lib.maintain.deprecated` + decorator and add "deprecated" to the function's docstring:: + + @maintain.deprecated("helpers.get_action() is deprecated and will be removed " + "in a future version of CKAN. Instead, please use the " + "extra_vars param to render() in your controller to pass " + "results from action functions to your templates.") + def get_action(action_name, data_dict=None): + '''Calls an action function from a template. Deprecated in CKAN 2.3.''' + if data_dict is None: + data_dict = {} + return logic.get_action(action_name)({}, data_dict) + +- Any deprecated functions should be added to an *API changes and deprecations* + section in the :doc:`/changelog` entry for the next release (do this before + merging the deprecation into master) + +- Keep the deprecation messages passed to the decorator short, they appear in + logs. Put longer explanations of why something was deprecated in the + changelog. diff --git a/doc/contributing/pull-requests.rst b/doc/contributing/pull-requests.rst index 6909657b5c3..8452e0a5c53 100644 --- a/doc/contributing/pull-requests.rst +++ b/doc/contributing/pull-requests.rst @@ -64,7 +64,11 @@ This section will walk you through the steps for making a pull request. - Your branch should contain new or changed tests for any new or changed code, and all the CKAN tests should pass on your branch, see - :doc:`test`. + `Testing CKAN `_. + + - Your pull request shouldn't lower our test coverage. You can check it at + our `coveralls page `. If for some + reason you can't avoid lowering it, explain why on the pull request. - Your branch should contain new or updated documentation for any new or updated code, see :doc:`documentation`. diff --git a/doc/extensions/adding-custom-fields.rst b/doc/extensions/adding-custom-fields.rst new file mode 100644 index 00000000000..f7a5131f737 --- /dev/null +++ b/doc/extensions/adding-custom-fields.rst @@ -0,0 +1,316 @@ +=================================================================== +Customizing dataset and resource metadata fields using IDatasetForm +=================================================================== + +Storing additional metadata for a dataset beyond the default metadata in CKAN +is a common use case. CKAN provides a simple way to do this by allowing you to +store arbitrary key/value pairs against a dataset when creating or updating the +dataset. These appear under the "Additional Information" section on the web +interface and in 'extras' field of the JSON when accessed via the API. + +Default extras can only take strings for their keys and values, no +validation is applied to the inputs and you cannot make them mandatory or +restrict the possible values to a defined list. By using CKAN's IDatasetForm +plugin interface, a CKAN plugin can add custom, first-class metadata fields to +CKAN datasets, and can do custom validation of these fields. + +.. seealso:: + In this tutorial we are assuming that you have read the + :doc:`/extensions/tutorial` + +CKAN schemas and validation +--------------------------- +When a dataset is created, updated or viewed, the parameters passed to CKAN +(e.g. via the web form when creating or updating a dataset, or posted to an API +end point) are validated against a schema. For each parameter, the schema will +contain a corresponding list of functions that will be run against the value of +the parameter. Generally these functions are used to validate the value +(and raise an error if the value fails validation) or convert the value to a +different value. + +For example, the schemas can allow optional values by using the +:func:`~ckan.lib.navl.validators.ignore_missing` validator or check that a +dataset exists using :func:`~ckan.logic.validators.package_id_exists`. A list +of available validators and converters can be found at the :doc:`validators` +and :doc:`converters`. You can also define your own validators for custom +validation. + +We will be customizing these schemas to add our additional fields. The +:py:class:`~ckan.plugins.interfaces.IDatasetForm` interface allows us to +override the schemas for creation, updating and displaying of datasets. + +.. autosummary:: + + ~ckan.plugins.interfaces.IDatasetForm.create_package_schema + ~ckan.plugins.interfaces.IDatasetForm.update_package_schema + ~ckan.plugins.interfaces.IDatasetForm.show_package_schema + ~ckan.plugins.interfaces.IDatasetForm.is_fallback + ~ckan.plugins.interfaces.IDatasetForm.package_types + +CKAN allows you to have multiple IDatasetForm plugins, each handling different +dataset types. So you could customize the CKAN web front end, for different +types of datasets. In this tutorial we will be defining our plugin as the +fallback plugin. This plugin is used if no other IDatasetForm plugin is found +that handles that dataset type. + +The IDatasetForm also has other additional functions that allow you to +provide a custom template to be rendered for the CKAN frontend, but we will +not be using them for this tutorial. + +Adding custom fields to datasets +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Create a new plugin named ``ckanext-extrafields`` and create a class named +``ExampleIDatasetFormPlugins`` inside +``ckanext-extrafields/ckanext/extrafields/plugins.py`` that implements the +``IDatasetForm`` interface and inherits from ``SingletonPlugin`` and +``DefaultDatasetForm``. + +.. literalinclude:: ../../ckanext/example_idatasetform/plugin_v1.py + :end-before: def create_package_schema(self): + +Updating the CKAN schema +^^^^^^^^^^^^^^^^^^^^^^^^ + +The :py:meth:`~ckan.plugins.interfaces.IDatasetForm.create_package_schema` +function is used whenever a new dataset is created, we'll want update the +default schema and insert our custom field here. We will fetch the default +schema defined in +:py:func:`~ckan.logic.schema.default_create_package_schema` by running +:py:meth:`~ckan.plugins.interfaces.IDatasetForm.create_package_schema`'s +super function and update it. + +.. literalinclude:: ../../ckanext/example_idatasetform/plugin_v1.py + :pyobject: ExampleIDatasetFormPlugin.create_package_schema + +The CKAN schema is a dictionary where the key is the name of the field and the +value is a list of validators and converters. Here we have a validator to tell +CKAN to not raise a validation error if the value is missing and a converter to +convert the value to and save as an extra. We will want to change the +:py:meth:`~ckan.plugins.interfaces.IDatasetForm.update_package_schema` function +with the same update code. + +.. literalinclude:: ../../ckanext/example_idatasetform/plugin_v1.py + :pyobject: ExampleIDatasetFormPlugin.update_package_schema + +The :py:meth:`~ckan.plugins.interfaces.IDatasetForm.show_package_schema` is used +when the :py:func:`~ckan.logic.action.get.package_show` action is called, we +want the default_show_package_schema to be updated to include our custom field. +This time, instead of converting to an extras field, we want our field to be +converted *from* an extras field. So we want to use the +:py:meth:`~ckan.logic.converters.convert_from_extras` converter. + +.. literalinclude:: ../../ckanext/example_idatasetform/plugin_v1.py + :emphasize-lines: 4 + :pyobject: ExampleIDatasetFormPlugin.show_package_schema + + +Dataset types +^^^^^^^^^^^^^ + +The :py:meth:`~ckan.plugins.interfaces.IDatasetForm.package_types` function +defines a list of dataset types that this plugin handles. Each dataset has a +field containing its type. Plugins can register to handle specific types of +dataset and ignore others. Since our plugin is not for any specific type of +dataset and we want our plugin to be the default handler, we update the plugin +code to contain the following: + +.. literalinclude:: ../../ckanext/example_idatasetform/plugin_v1.py + :lines: 34- + +Updating templates +^^^^^^^^^^^^^^^^^^ + +In order for our new field to be visible on the CKAN front-end, we need to +update the templates. Add an additional line to make the plugin implement the +IConfigurer interface + +.. literalinclude:: ../../ckanext/example_idatasetform/plugin_v2.py + :emphasize-lines: 3 + :start-after: import ckan.plugins.toolkit as tk + :end-before: def create_package_schema(self): + +This interface allows to implement a function +:py:meth:`~ckan.plugins.interfaces.IDatasetForm.update_config` that allows us +to update the CKAN config, in our case we want to add an additional location +for CKAN to look for templates. Add the following code to your plugin. + +.. literalinclude:: ../../ckanext/example_idatasetform/plugin_v2.py + :pyobject: ExampleIDatasetFormPlugin.update_config + +You will also need to add a directory under your extension directory to store +the templates. Create a directory called +``ckanext-extrafields/ckanext/extrafields/templates/`` and the subdirectories +``ckanext-extrafields/ckanext/extrafields/templates/package/snippets/``. + +We need to override a few templates in order to get our custom field rendered. +Firstly we need to remove the default custom field handling. Create a template +file in our templates directory called +``package/snippets/package_metadata_fields.html`` containing + + +.. literalinclude:: ../../ckanext/example_idatasetform/templates/package/snippets/package_metadata_fields.html + :language: jinja + :end-before: {% block package_metadata_fields %} + +This overrides the custom_fields block with an empty block so the default CKAN +custom fields form does not render. Next add a template in our template +directory called ``package/snippets/package_basic_fields.html`` containing + +.. literalinclude:: ../../ckanext/example_idatasetform/templates/package/snippets/package_basic_fields.html + :language: jinja + +This adds our custom_text field to the editing form. Finally we want to display +our custom_text field on the dataset page. Add another file called +``package/snippets/additional_info.html`` containing + + +.. literalinclude:: ../../ckanext/example_idatasetform/templates/package/snippets/additional_info.html + :language: jinja + +This template overrides the default extras rendering on the dataset page +and replaces it to just display our custom field. + +You're done! Make sure you have your plugin installed and setup as in the +`extension/tutorial`. Then run a development server and you should now have +an additional field called "Custom Text" when displaying and adding/editing a +dataset. + +Cleaning up the code +^^^^^^^^^^^^^^^^^^^^ + +Before we continue further, we can clean up the +:py:meth:`~ckan.plugins.interfaces.IDatasetForm.create_package_schema` +and :py:meth:`~ckan.plugins.interfaces.IDatasetForm.update_package_schema`. +There is a bit of duplication that we could remove. Replace the two functions +with: + +.. literalinclude:: ../../ckanext/example_idatasetform/plugin_v3.py + :start-after: p.implements(p.IDatasetForm) + :end-before: def show_package_schema(self): + +Tag vocabularies +---------------- +If you need to add a custom field where the input options are restricted to a +provided list of options, you can use tag vocabularies :doc:`/tag-vocabularies`. +We will need to create our vocabulary first. By calling +:func:`~ckan.logic.action.vocabulary_create`. Add a function to your plugin.py +above your plugin class. + +.. literalinclude:: ../../ckanext/example_idatasetform/plugin_v4.py + :pyobject: create_country_codes + +This code block is taken from the ``example_idatsetform plugin``. +``create_country_codes`` tries to fetch the vocabulary country_codes using +:func:`~ckan.logic.action.get.vocabulary_show`. If it is not found it will +create it and iterate over the list of countries 'uk', 'ie', 'de', 'fr', 'es'. +For each of these a vocabulary tag is created using +:func:`~ckan.logic.action.create.tag_create`, belonging to the vocabulary +``country_code``. + +Although we have only defined five tags here, additional tags can be created +at any point by a sysadmin user by calling +:func:`~ckan.logic.action.create.tag_create` using the API or action functions. +Add a second function below ``create_country_codes`` + +.. literalinclude:: ../../ckanext/example_idatasetform/plugin_v4.py + :pyobject: country_codes + +country_codes will call ``create_country_codes`` so that the ``country_codes`` +vocabulary is created if it does not exist. Then it calls +:func:`~ckan.logic.action.get.tag_list` to return all of our vocabulary tags +together. Now we have a way of retrieving our tag vocabularies and creating +them if they do not exist. We just need our plugin to call this code. + +Adding tags to the schema +^^^^^^^^^^^^^^^^^^^^^^^^^ +Update :py:meth:`~ckan.plugins.interfaces.IDatasetForm._modify_package_schema` +and :py:meth:`~ckan.plugins.interfaces.IDatasetForm.show_package_schema` + +.. literalinclude:: ../../ckanext/example_idatasetform/plugin_v4.py + :start-after: return {'country_codes': country_codes} + :end-before: def create_package_schema(self): + :emphasize-lines: 9,21-26 + +We are adding our tag to our plugin's schema. A converter is required to +convert the field in to our tag in a similar way to how we converted our field +to extras earlier. In +:py:meth:`~ckan.plugins.interfaces.IDatasetForm.show_package_schema` we convert +from the tag back again but we have an additional line with another converter +containing +:py:func:`~ckan.logic.converters.free_tags_only`. We include this line so that +vocab tags are not shown mixed with normal free tags. + +Adding tags to templates +^^^^^^^^^^^^^^^^^^^^^^^^ + +Add an additional plugin.implements line to to your plugin +to implement the :py:class:`~ckan.plugins.interfaces.ITemplateHelpers`, we will +need to add a :py:meth:`~ckan.plugins.interfaces.ITemplateHelpers.get_helpers` +function defined for this interface. + +.. literalinclude:: ../../ckanext/example_idatasetform/plugin_v4.py + :start-after: p.implements(p.IConfigurer) + :end-before: def _modify_package_schema(self, schema): + +Our intention here is to tie our country_code fetching/creation to when they +are used in the templates. Add the code below to +``package/snippets/package_metadata_fields.html`` + +.. literalinclude:: ../../ckanext/example_idatasetform/templates/package/snippets/package_metadata_fields.html + :language: jinja + :start-after: {% endblock %} + + +This adds our country code to our template, here we are using the additional +helper country_codes that we defined in our get_helpers function in our plugin. + +Adding custom fields to resources +--------------------------------- + +In order to customize the fields in a resource the schema for resources needs +to be modified in a similar way to the datasets. The resource schema +is nested in the dataset dict as package['resources']. We modify this dict in +a similar way to the dataset schema. Change ``_modify_package_schema`` to the +following. + +.. literalinclude:: ../../ckanext/example_idatasetform/plugin.py + :pyobject: ExampleIDatasetFormPlugin._modify_package_schema + :emphasize-lines: 14-16 + +Update :py:meth:`~ckan.plugins.interfaces.IDatasetForm.show_package_schema` +similarly + +.. literalinclude:: ../../ckanext/example_idatasetform/plugin.py + :pyobject: ExampleIDatasetFormPlugin.show_package_schema + :emphasize-lines: 20-23 + +Save and reload your development server CKAN will take any additional keys from +the resource schema and save them the its extras field. The templates will +automatically check this field and display them in the resource_read page. + +Sorting by custom fields on the dataset search page +--------------------------------------------------- +Now that we've added our custom field, we can customize the CKAN web front end +search page to sort datasets by our custom field. Add a new file called +``ckanext-extrafields/ckanext/extrafields/templates/package/search.html`` containing: + +.. literalinclude:: ../../ckanext/example_idatasetform/templates/package/search.html + :language: jinja + :emphasize-lines: 16-17 + +This overrides the search ordering drop down code block, the code is the +same as the default dataset search block but we are adding two additional lines +that define the display name of that search ordering (e.g. Custom Field +Ascending) and the SOLR sort ordering (e.g. custom_text asc). If you reload your +development server you should be able to see these two additional sorting options +on the dataset search page. + +The SOLR sort ordering can define arbitrary functions for custom sorting, but +this is beyond the scope of this tutorial for further details see +http://wiki.apache.org/solr/CommonQueryParameters#sort and +http://wiki.apache.org/solr/FunctionQuery + + +You can find the complete source for this tutorial at +https://github.com/ckan/ckan/tree/master/ckanext/example_idatasetform diff --git a/doc/extensions/index.rst b/doc/extensions/index.rst index 4c45c918cf8..c932b4ddd66 100644 --- a/doc/extensions/index.rst +++ b/doc/extensions/index.rst @@ -33,6 +33,7 @@ features by developing your own CKAN extensions. custom-config-settings testing-extensions best-practices + adding-custom-fields plugin-interfaces plugins-toolkit converters diff --git a/doc/images/add_dataset_3.jpg b/doc/images/add_dataset_3.jpg index 4f46594a1b6..eee2f6b3f29 100644 Binary files a/doc/images/add_dataset_3.jpg and b/doc/images/add_dataset_3.jpg differ diff --git a/doc/theming/best-practices.rst b/doc/theming/best-practices.rst index 6ff17d5c044..91b9bc5f44e 100644 --- a/doc/theming/best-practices.rst +++ b/doc/theming/best-practices.rst @@ -9,8 +9,23 @@ Don't use ``c`` --------------- As much as possible, avoid accessing the Pylons template context :py:data:`c` -(or :py:data:`tmpl_context`). Use +(or :py:data:`tmpl_context`). :py:data:`c` is a thread-global variable, which +encourages spaghetti code that's difficult to understand and to debug. + +Instead, have controller methods add variables to the :py:data:`extra_vars` +parameter of :py:func:`~ckan.lib.base.render`, or have the templates +call :doc:`template helper functions ` instead. + +:py:data:`extra_vars` has the advantage that it allows templates, which are +difficult to debug, to be simpler and shifts logic into the easier-to-test and +easier-to-debug Python code. On the other hand, template helper functions are +easier to reuse as they're available to all templates and they avoid +inconsistencies between the namespaces of templates that are rendered by +different controllers (e.g. one controller method passes the package dict as an +extra var named ``package``, another controller method passes the same thing +but calls it ``pkg``, a third calls it ``pkg_dict``). + You can use the :py:class:`~ckan.plugins.interfaces.ITemplateHelpers` plugin interface to add custom helper functions, see :ref:`custom template helper functions`. diff --git a/doc/theming/static-files.rst b/doc/theming/static-files.rst index 271ebd1d8ac..9ce61a7ea38 100644 --- a/doc/theming/static-files.rst +++ b/doc/theming/static-files.rst @@ -25,8 +25,10 @@ First, create a ``public`` directory in your extension with a ``promoted-image.jpg`` file in it:: ckanext-example_theme/ - public/ - promoted-image.jpg + ckanext/ + example_theme/ + public/ + promoted-image.jpg ``promoted-image.jpg`` should be a 420x220px JPEG image file. You could use this image file for example: diff --git a/doc/user-guide.rst b/doc/user-guide.rst index a51180f15ec..997b28e6e62 100644 --- a/doc/user-guide.rst +++ b/doc/user-guide.rst @@ -239,9 +239,6 @@ select "Next: Additional Info". talk to your site administrator about changing the default schema and dataset forms. -* *Group* -- Moderated collection of datasets. You can add the dataset to - an existing group here. - .. image:: /images/add_dataset_3.jpg .. note:: @@ -250,6 +247,11 @@ select "Next: Additional Info". "Visibility" is set correctly. It is also good practice to ensure an Author is named. +.. versionchanged:: 2.2 + Previous versions of CKAN used to allow adding the dataset to existing + groups in this step. This was changed. To add a dataset to an existing group + now, go to the "Group" tab in the Dataset's page. + **Step 8**. Select the 'Finish' button. CKAN creates the dataset and shows you the result. You have finished! diff --git a/setup.py b/setup.py index 21eb8a92fd8..f2047cff5ea 100644 --- a/setup.py +++ b/setup.py @@ -79,6 +79,10 @@ 'recline_map=ckanext.reclinepreview.plugin:ReclineMap', 'example_itemplatehelpers = ckanext.example_itemplatehelpers.plugin:ExampleITemplateHelpersPlugin', 'example_idatasetform = ckanext.example_idatasetform.plugin:ExampleIDatasetFormPlugin', + 'example_idatasetform_v1 = ckanext.example_idatasetform.plugin_v1:ExampleIDatasetFormPlugin', + 'example_idatasetform_v2 = ckanext.example_idatasetform.plugin_v2:ExampleIDatasetFormPlugin', + 'example_idatasetform_v3 = ckanext.example_idatasetform.plugin_v3:ExampleIDatasetFormPlugin', + 'example_idatasetform_v4 = ckanext.example_idatasetform.plugin_v4:ExampleIDatasetFormPlugin', 'example_iauthfunctions_v1 = ckanext.example_iauthfunctions.plugin_v1:ExampleIAuthFunctionsPlugin', 'example_iauthfunctions_v2 = ckanext.example_iauthfunctions.plugin_v2:ExampleIAuthFunctionsPlugin', 'example_iauthfunctions_v3 = ckanext.example_iauthfunctions.plugin_v3:ExampleIAuthFunctionsPlugin',
{{ _("Custom Text") }}{{ pkg_dict.custom_text }}