diff --git a/.travis.yml b/.travis.yml index 87db5e046..67404d750 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,9 @@ sudo: false env: - TOX_ENV=py27-lint - TOX_ENV=py27-docs + - TOX_ENV=py35-django19 + - TOX_ENV=py34-django19 + - TOX_ENV=py27-django19 - TOX_ENV=py34-django18 - TOX_ENV=py33-django18 - TOX_ENV=py32-django18 @@ -13,28 +16,12 @@ env: - TOX_ENV=py33-django17 - TOX_ENV=py32-django17 - TOX_ENV=py27-django17 - - TOX_ENV=py34-django16 - - TOX_ENV=py33-django16 - - TOX_ENV=py32-django16 - - TOX_ENV=py27-django16 - - TOX_ENV=py26-django16 - - TOX_ENV=py34-django15 - - TOX_ENV=py33-django15 - - TOX_ENV=py32-django15 - - TOX_ENV=py27-django15 - - TOX_ENV=py26-django15 - - TOX_ENV=py27-djangomaster - - TOX_ENV=py32-djangomaster - - TOX_ENV=py33-djangomaster - - TOX_ENV=py34-djangomaster matrix: + # Python 3.5 not yet available on travis, watch this to see when it is. fast_finish: true allow_failures: - - env: TOX_ENV=py27-djangomaster - - env: TOX_ENV=py32-djangomaster - - env: TOX_ENV=py33-djangomaster - - env: TOX_ENV=py34-djangomaster + - env: TOX_ENV=py35-django19 install: - pip install tox @@ -44,4 +31,4 @@ script: after_success: - pip install codecov - - codecov + - codecov -e TOX_ENV diff --git a/README.md b/README.md index b183e14df..f9bd1f439 100644 --- a/README.md +++ b/README.md @@ -36,8 +36,8 @@ There is a live example API for testing purposes, [available here][sandbox]. # Requirements -* Python (2.6.5+, 2.7, 3.2, 3.3, 3.4) -* Django (1.5.6+, 1.6.3+, 1.7, 1.8) +* Python (2.7, 3.2, 3.3, 3.4, 3.5) +* Django (1.7, 1.8, 1.9) # Installation diff --git a/docs/api-guide/authentication.md b/docs/api-guide/authentication.md index 7fda98e67..3ade3a661 100644 --- a/docs/api-guide/authentication.md +++ b/docs/api-guide/authentication.md @@ -360,6 +360,10 @@ HTTP Signature (currently a [IETF draft][http-signature-ietf-draft]) provides a [Django-rest-auth][django-rest-auth] library provides a set of REST API endpoints for registration, authentication (including social media authentication), password reset, retrieve and update user details, etc. By having these API endpoints, your client apps such as AngularJS, iOS, Android, and others can communicate to your Django backend site independently via REST APIs for user management. +## django-rest-framework-social-oauth2 + +[Django-rest-framework-social-oauth2][django-rest-framework-social-oauth2] library provides an easy way to integrate social plugins (facebook, twitter, google, etc.) to your authentication system and an easy oauth2 setup. With this library, you will be able to authenticate users based on external tokens (e.g. facebook access token), convert these tokens to "in-house" oauth2 tokens and use and generate oauth2 tokens to authenticate your users. + ## django-rest-knox [Django-rest-knox][django-rest-knox] library provides models and views to handle token based authentication in a more secure and extensible way than the built-in TokenAuthentication scheme - with Single Page Applications and Mobile clients in mind. It provides per-client tokens, and views to generate them when provided some other authentication (usually basic authentication), to delete the token (providing a server enforced logout) and to delete all tokens (logs out all clients that a user is logged into). @@ -404,4 +408,5 @@ HTTP Signature (currently a [IETF draft][http-signature-ietf-draft]) provides a [mac]: http://tools.ietf.org/html/draft-hammer-oauth-v2-mac-token-05 [djoser]: https://github.com/sunscrapers/djoser [django-rest-auth]: https://github.com/Tivix/django-rest-auth +[django-rest-framework-social-oauth2]: https://github.com/PhilipGarnero/django-rest-framework-social-oauth2 [django-rest-knox]: https://github.com/James1345/django-rest-knox diff --git a/docs/api-guide/fields.md b/docs/api-guide/fields.md index 2fbb84c03..377fe983f 100644 --- a/docs/api-guide/fields.md +++ b/docs/api-guide/fields.md @@ -57,7 +57,7 @@ Note that setting a `default` value implies that the field is not required. Incl ### `source` -The name of the attribute that will be used to populate the field. May be a method that only takes a `self` argument, such as `URLField('get_absolute_url')`, or may use dotted notation to traverse attributes, such as `EmailField(source='user.email')`. +The name of the attribute that will be used to populate the field. May be a method that only takes a `self` argument, such as `URLField(source='get_absolute_url')`, or may use dotted notation to traverse attributes, such as `EmailField(source='user.email')`. The value `source='*'` has a special meaning, and is used to indicate that the entire object should be passed through to the field. This can be useful for creating nested representations, or for fields which require access to the complete object in order to determine the output representation. @@ -459,6 +459,14 @@ You can also use the declarative style, as with `ListField`. For example: class DocumentField(DictField): child = CharField() +## JSONField + +A field class that validates that the incoming data structure consists of valid JSON primitives. In its alternate binary mode, it will represent and validate JSON-encoded binary strings. + +**Signature**: `JSONField(binary)` + +- `binary` - If set to `True` then the field will output and validate a JSON encoded string, rather that a primitive data structure. Defaults to `False`. + --- # Miscellaneous fields diff --git a/docs/api-guide/format-suffixes.md b/docs/api-guide/format-suffixes.md index 35dbcd39c..13717b05f 100644 --- a/docs/api-guide/format-suffixes.md +++ b/docs/api-guide/format-suffixes.md @@ -69,6 +69,16 @@ If using the `i18n_patterns` function provided by Django, as well as `format_suf --- +## Query parameter formats + +An alternative to the format suffixes is to include the requested format in a query parameter. REST framework provides this option by default, and it is used in the browsable API to switch between differing available representations. + +To select a representation using its short format, use the `format` query parameter. For example: `http://example.com/organizations/?format=csv`. + +The name of this query parameter can be modified using the `URL_FORMAT_OVERRIDE` setting. Set the value to `None` to disable this behavior. + +--- + ## Accept headers vs. format suffixes There seems to be a view among some of the Web community that filename extensions are not a RESTful pattern, and that `HTTP Accept` headers should always be used instead. diff --git a/docs/api-guide/serializers.md b/docs/api-guide/serializers.md index ca540a13b..95703033a 100644 --- a/docs/api-guide/serializers.md +++ b/docs/api-guide/serializers.md @@ -287,7 +287,7 @@ Similarly if a nested representation should be a list of items, you should pass ## Writable nested representations -When dealing with nested representations that support deserializing the data, an errors with nested objects will be nested under the field name of the nested object. +When dealing with nested representations that support deserializing the data, any errors with nested objects will be nested under the field name of the nested object. serializer = CommentSerializer(data={'user': {'email': 'foobar', 'username': 'doe'}, 'content': 'baz'}) serializer.is_valid() @@ -356,7 +356,7 @@ It is possible that a third party package, providing automatic support some kind #### Handling saving related instances in model manager classes -An alternative to saving multiple related instances in the serializer is to write custom model manager classes handle creating the correct instances. +An alternative to saving multiple related instances in the serializer is to write custom model manager classes that handle creating the correct instances. For example, suppose we wanted to ensure that `User` instances and `Profile` instances are always created together as a pair. We might write a custom manager class that looks something like this: @@ -438,6 +438,7 @@ Declaring a `ModelSerializer` looks like this: class AccountSerializer(serializers.ModelSerializer): class Meta: model = Account + fields = ('id', 'account_name', 'users', 'created') By default, all the model fields on the class will be mapped to a corresponding serializer fields. @@ -459,7 +460,7 @@ To do so, open the Django shell, using `python manage.py shell`, then import the ## Specifying which fields to include -If you only want a subset of the default fields to be used in a model serializer, you can do so using `fields` or `exclude` options, just as you would with a `ModelForm`. +If you only want a subset of the default fields to be used in a model serializer, you can do so using `fields` or `exclude` options, just as you would with a `ModelForm`. It is strongly recommended that you explicitly set all fields that should be serialized using the `fields` attribute. This will make it less likely to result in unintentionally exposing data when your models change. For example: @@ -468,7 +469,27 @@ For example: model = Account fields = ('id', 'account_name', 'users', 'created') -The names in the `fields` option will normally map to model fields on the model class. +You can also set the `fields` attribute to the special value `'__all__'` to indicate that all fields in the model should be used. + +For example: + + class AccountSerializer(serializers.ModelSerializer): + class Meta: + model = Account + fields = '__all__' + +You can set the `exclude` attribute to a list of fields to be excluded from the serializer. + +For example: + + class AccountSerializer(serializers.ModelSerializer): + class Meta: + model = Account + exclude = ('users',) + +In the example above, if the `Account` model had 3 fields `account_name`, `users`, and `created`, this will result in the fields `account_name` and `created` to be serialized. + +The names in the `fields` and `exclude` attributes will normally map to model fields on the model class. Alternatively names in the `fields` options can map to properties or methods which take no arguments that exist on the model class. @@ -530,7 +551,7 @@ Please review the [Validators Documentation](/api-guide/validators/) for details ## Additional keyword arguments -There is also a shortcut allowing you to specify arbitrary additional keyword arguments on fields, using the `extra_kwargs` option. Similarly to `read_only_fields` this means you do not need to explicitly declare the field on the serializer. +There is also a shortcut allowing you to specify arbitrary additional keyword arguments on fields, using the `extra_kwargs` option. As in the case of `read_only_fields`, this means you do not need to explicitly declare the field on the serializer. This option is a dictionary, mapping field names to a dictionary of keyword arguments. For example: @@ -811,7 +832,7 @@ This class implements the same basic API as the `Serializer` class: * `.data` - Returns the outgoing primitive representation. * `.is_valid()` - Deserializes and validates incoming data. * `.validated_data` - Returns the validated incoming data. -* `.errors` - Returns an errors during validation. +* `.errors` - Returns any errors during validation. * `.save()` - Persists the validated data into an object instance. There are four methods that can be overridden, depending on what functionality you want the serializer class to support: diff --git a/docs/api-guide/settings.md b/docs/api-guide/settings.md index 13d23a69e..23691dec1 100644 --- a/docs/api-guide/settings.md +++ b/docs/api-guide/settings.md @@ -249,47 +249,23 @@ Default: --- -## Browser overrides - -*The following settings provide URL or form-based overrides of the default browser behavior.* - -#### FORM_METHOD_OVERRIDE - -The name of a form field that may be used to override the HTTP method of the form. - -If the value of this setting is `None` then form method overloading will be disabled. - -Default: `'_method'` - -#### FORM_CONTENT_OVERRIDE - -The name of a form field that may be used to override the content of the form payload. Must be used together with `FORM_CONTENTTYPE_OVERRIDE`. - -If either setting is `None` then form content overloading will be disabled. - -Default: `'_content'` - -#### FORM_CONTENTTYPE_OVERRIDE - -The name of a form field that may be used to override the content type of the form payload. Must be used together with `FORM_CONTENT_OVERRIDE`. - -If either setting is `None` then form content overloading will be disabled. - -Default: `'_content_type'` - -#### URL_ACCEPT_OVERRIDE - -The name of a URL parameter that may be used to override the HTTP `Accept` header. - -If the value of this setting is `None` then URL accept overloading will be disabled. - -Default: `'accept'` +## Content type controls #### URL_FORMAT_OVERRIDE -The name of a URL parameter that may be used to override the default `Accept` header based content negotiation. +The name of a URL parameter that may be used to override the default content negotiation `Accept` header behavior, by using a `format=…` query parameter in the request URL. -If the value of this setting is `None` then URL format overloading will be disabled. +For example: `http://example.com/organizations/?format=csv` + +If the value of this setting is `None` then URL format overrides will be disabled. + +Default: `'format'` + +#### FORMAT_SUFFIX_KWARG + +The name of a parameter in the URL conf that may be used to provide a format suffix. This setting is applied when using `format_suffix_patterns` to include suffixed URL patterns. + +For example: `http://example.com/organizations.csv/` Default: `'format'` @@ -451,12 +427,6 @@ A string representing the key that should be used for the URL fields generated b Default: `'url'` -#### FORMAT_SUFFIX_KWARG - -The name of a parameter in the URL conf that may be used to provide a format suffix. - -Default: `'format'` - #### NUM_PROXIES An integer of 0 or more, that may be used to specify the number of application proxies that the API runs behind. This allows throttling to more accurately identify client IP addresses. If set to `None` then less strict IP matching will be used by the throttle classes. diff --git a/docs/api-guide/throttling.md b/docs/api-guide/throttling.md index 57bce54e7..36753aafc 100644 --- a/docs/api-guide/throttling.md +++ b/docs/api-guide/throttling.md @@ -184,7 +184,7 @@ If the `.wait()` method is implemented and the request is throttled, then a `Ret The following is an example of a rate throttle, that will randomly throttle 1 in every 10 requests. - class RandomRateThrottle(throttles.BaseThrottle): + class RandomRateThrottle(throttling.BaseThrottle): def allow_request(self, request, view): return random.randint(1, 10) == 1 diff --git a/docs/api-guide/versioning.md b/docs/api-guide/versioning.md index 482943b86..06b0056a4 100644 --- a/docs/api-guide/versioning.md +++ b/docs/api-guide/versioning.md @@ -72,7 +72,7 @@ The following settings keys are also used to control versioning: * `DEFAULT_VERSION`. The value that should be used for `request.version` when no versioning information is present. Defaults to `None`. * `ALLOWED_VERSIONS`. If set, this value will restrict the set of versions that may be returned by the versioning scheme, and will raise an error if the provided version if not in this set. Note that the value used for the `DEFAULT_VERSION` setting is always considered to be part of the `ALLOWED_VERSIONS` set. Defaults to `None`. -* `VERSION_PARAMETER`. The string that should used for any versioning parameters, such as in the media type or URL query parameters. Defaults to `'version'`. +* `VERSION_PARAM`. The string that should used for any versioning parameters, such as in the media type or URL query parameters. Defaults to `'version'`. You can also set your versioning class plus those three values on a per-view or a per-viewset basis by defining your own versioning scheme and using the `default_version`, `allowed_versions` and `version_param` class variables. For example, if you want to use `URLPathVersioning`: diff --git a/docs/index.md b/docs/index.md index 37f192094..4617d0bcc 100644 --- a/docs/index.md +++ b/docs/index.md @@ -52,8 +52,8 @@ Some reasons you might want to use REST framework: REST framework requires the following: -* Python (2.6.5+, 2.7, 3.2, 3.3, 3.4) -* Django (1.5.6+, 1.6.3+, 1.7+, 1.8) +* Python (2.6.5+, 2.7, 3.2, 3.3, 3.4, 3.5) +* Django (1.7+, 1.8, 1.9) The following packages are optional: diff --git a/docs/topics/browser-enhancements.md b/docs/topics/browser-enhancements.md index 5a1726201..e1977e826 100644 --- a/docs/topics/browser-enhancements.md +++ b/docs/topics/browser-enhancements.md @@ -4,58 +4,36 @@ > > — [RESTful Web Services][cite], Leonard Richardson & Sam Ruby. +In order to allow the browsable API to function, there are a couple of browser enhancements that REST framework needs to provide. + +As of version 3.3.0 onwards these are enabled with javascript, using the [ajax-form][ajax-form] library. + ## Browser based PUT, DELETE, etc... -REST framework supports browser-based `PUT`, `DELETE` and other methods, by -overloading `POST` requests using a hidden form field. +The [AJAX form library][ajax-form] supports browser-based `PUT`, `DELETE` and other methods on HTML forms. -Note that this is the same strategy as is used in [Ruby on Rails][rails]. +After including the library, use the `data-method` attribute on the form, like so: -For example, given the following form: - -
- + + + ...
-`request.method` would return `"DELETE"`. - -## HTTP header based method overriding - -REST framework also supports method overriding via the semi-standard `X-HTTP-Method-Override` header. This can be useful if you are working with non-form content such as JSON and are working with an older web server and/or hosting provider that doesn't recognise particular HTTP methods such as `PATCH`. For example [Amazon Web Services ELB][aws_elb]. - -To use it, make a `POST` request, setting the `X-HTTP-Method-Override` header. - -For example, making a `PATCH` request via `POST` in jQuery: - - $.ajax({ - url: '/myresource/', - method: 'POST', - headers: {'X-HTTP-Method-Override': 'PATCH'}, - ... - }); +Note that prior to 3.3.0, this support was server-side rather than javascript based. The method overloading style (as used in [Ruby on Rails][rails]) is no longer supported due to subtle issues that it introduces in request parsing. ## Browser based submission of non-form content -Browser-based submission of content types other than form are supported by -using form fields named `_content` and `_content_type`: +Browser-based submission of content types such as JSON are supported by the [AJAX form library][ajax-form], using form fields with `data-override='content-type'` and `data-override='content'` attributes. -For example, given the following form: +For example: -
- - -
+
+ + + +
-`request.content_type` would return `"application/json"`, and -`request.stream` would return `"{'count': 1}"` - -## URL based accept headers - -REST framework can take `?accept=application/json` style URL parameters, -which allow the `Accept` header to be overridden. - -This can be useful for testing the API from a web browser, where you don't -have any control over what is sent in the `Accept` header. +Note that prior to 3.3.0, this support was server-side rather than javascript based. ## URL based format suffixes @@ -63,8 +41,37 @@ REST framework can take `?format=json` style URL parameters, which can be a useful shortcut for determining which content type should be returned from the view. -This is a more concise than using the `accept` override, but it also gives -you less control. (For example you can't specify any media type parameters) +This behavior is controlled using the `URL_FORMAT_OVERRIDE` setting. + +## HTTP header based method overriding + +Prior to version 3.3.0 the semi extension header `X-HTTP-Method-Override` was supported for overriding the request method. This behavior is no longer in core, but can be adding if needed using middleware. + +For example: + + METHOD_OVERRIDE_HEADER = 'HTTP_X_HTTP_METHOD_OVERRIDE' + + class MethodOverrideMiddleware(object): + def process_view(self, request, callback, callback_args, callback_kwargs): + if request.method != 'POST': + return + if METHOD_OVERRIDE_HEADER not in request.META: + return + request.method = request.META[METHOD_OVERRIDE_HEADER] + +## URL based accept headers + +Until version 3.3.0 REST framework included built-in support for `?accept=application/json` style URL parameters, which would allow the `Accept` header to be overridden. + +Since the introduction of the content negotiation API this behavior is no longer included in core, but may be added using a custom content negotiation class, if needed. + +For example: + + class AcceptQueryParamOverride() + def get_accept_list(self, request): + header = request.META.get('HTTP_ACCEPT', '*/*') + header = request.query_params.get('_accept', header) + return [token.strip() for token in header.split(',')] ## Doesn't HTML5 support PUT and DELETE forms? @@ -74,7 +81,7 @@ was later [dropped from the spec][html5]. There remains as well as how to support content types other than form-encoded data. [cite]: http://www.amazon.com/Restful-Web-Services-Leonard-Richardson/dp/0596529260 +[ajax-form]: https://github.com/tomchristie/ajax-form [rails]: http://guides.rubyonrails.org/form_helpers.html#how-do-forms-with-put-or-delete-methods-work [html5]: http://www.w3.org/TR/html5-diff/#changes-2010-06-24 [put_delete]: http://amundsen.com/examples/put-delete-forms/ -[aws_elb]: https://forums.aws.amazon.com/thread.jspa?messageID=400724 diff --git a/docs/topics/release-notes.md b/docs/topics/release-notes.md index 260dc476c..cb4a17ef7 100644 --- a/docs/topics/release-notes.md +++ b/docs/topics/release-notes.md @@ -38,6 +38,14 @@ You can determine your currently installed version using `pip freeze`: --- +## 3.3.x series + +### 3.3.0 + +**Date**: NOT YET RELEASED + +* Removed support for Django Versions 1.5 & 1.6 ([#3421][gh3421], [#3429][gh3429]) + ## 3.2.x series ### 3.2.4 @@ -533,3 +541,7 @@ For older release notes, [please see the version 2.x documentation][old-release- [gh3361]: https://github.com/tomchristie/django-rest-framework/issues/3361 [gh3364]: https://github.com/tomchristie/django-rest-framework/issues/3364 [gh3415]: https://github.com/tomchristie/django-rest-framework/issues/3415 + + +[gh3421]: https://github.com/tomchristie/django-rest-framework/pulls/3421 +[gh3429]: https://github.com/tomchristie/django-rest-framework/pull/3429 diff --git a/docs/topics/third-party-resources.md b/docs/topics/third-party-resources.md index 9c302f77e..a4f1eefcb 100644 --- a/docs/topics/third-party-resources.md +++ b/docs/topics/third-party-resources.md @@ -237,6 +237,7 @@ To submit new content, [open an issue][drf-create-issue] or [create a pull reque ### Misc +* [cookiecutter-django-rest][cookiecutter-django-rest] - A cookiecutter template that takes care of the setup and configuration so you can focus on making your REST apis awesome. * [djangorestrelationalhyperlink][djangorestrelationalhyperlink] - A hyperlinked serialiser that can can be used to alter relationships via hyperlinks, but otherwise like a hyperlink model serializer. * [django-rest-swagger][django-rest-swagger] - An API documentation generator for Swagger UI. * [django-rest-framework-proxy][django-rest-framework-proxy] - Proxy to redirect incoming request to another API server. @@ -246,6 +247,7 @@ To submit new content, [open an issue][drf-create-issue] or [create a pull reque * [django-versatileimagefield][django-versatileimagefield] - Provides a drop-in replacement for Django's stock `ImageField` that makes it easy to serve images in multiple sizes/renditions from a single field. For DRF-specific implementation docs, [click here][django-versatileimagefield-drf-docs]. * [drf-tracking][drf-tracking] - Utilities to track requests to DRF API views. * [django-rest-framework-braces][django-rest-framework-braces] - Collection of utilities for working with Django Rest Framework. The most notable ones are [FormSerializer](https://django-rest-framework-braces.readthedocs.org/en/latest/overview.html#formserializer) and [SerializerForm](https://django-rest-framework-braces.readthedocs.org/en/latest/overview.html#serializerform), which are adapters between DRF serializers and Django forms. +* [drf-haystack][drf-haystack] - Haystack search for Django Rest Framework ## Other Resources @@ -345,3 +347,5 @@ To submit new content, [open an issue][drf-create-issue] or [create a pull reque [django-rest-framework-braces]: https://github.com/dealertrack/django-rest-framework-braces [dry-rest-permissions]: https://github.com/Helioscene/dry-rest-permissions [django-url-filter]: https://github.com/miki725/django-url-filter +[cookiecutter-django-rest]: https://github.com/agconti/cookiecutter-django-rest +[drf-haystack]: http://drf-haystack.readthedocs.org/en/latest/ diff --git a/docs_theme/base.html b/docs_theme/base.html index 93b687cfc..369927b41 100644 --- a/docs_theme/base.html +++ b/docs_theme/base.html @@ -136,7 +136,7 @@ diff --git a/rest_framework/authtoken/serializers.py b/rest_framework/authtoken/serializers.py index 597aeed22..8a295c03e 100644 --- a/rest_framework/authtoken/serializers.py +++ b/rest_framework/authtoken/serializers.py @@ -1,7 +1,7 @@ from django.contrib.auth import authenticate from django.utils.translation import ugettext_lazy as _ -from rest_framework import exceptions, serializers +from rest_framework import serializers class AuthTokenSerializer(serializers.Serializer): @@ -18,13 +18,13 @@ class AuthTokenSerializer(serializers.Serializer): if user: if not user.is_active: msg = _('User account is disabled.') - raise exceptions.ValidationError(msg) + raise serializers.ValidationError(msg) else: msg = _('Unable to log in with provided credentials.') - raise exceptions.ValidationError(msg) + raise serializers.ValidationError(msg) else: msg = _('Must include "username" and "password".') - raise exceptions.ValidationError(msg) + raise serializers.ValidationError(msg) attrs['user'] = user return attrs diff --git a/rest_framework/authtoken/south_migrations/0001_initial.py b/rest_framework/authtoken/south_migrations/0001_initial.py deleted file mode 100644 index 5b927f3e5..000000000 --- a/rest_framework/authtoken/south_migrations/0001_initial.py +++ /dev/null @@ -1,60 +0,0 @@ -# -*- coding: utf-8 -*- -from south.db import db -from south.v2 import SchemaMigration - -try: - from django.contrib.auth import get_user_model -except ImportError: # django < 1.5 - from django.contrib.auth.models import User -else: - User = get_user_model() - - -class Migration(SchemaMigration): - - def forwards(self, orm): - # Adding model 'Token' - db.create_table('authtoken_token', ( - ('key', self.gf('django.db.models.fields.CharField')(max_length=40, primary_key=True)), - ('user', self.gf('django.db.models.fields.related.OneToOneField')(related_name='auth_token', unique=True, to=orm['%s.%s' % (User._meta.app_label, User._meta.object_name)])), - ('created', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)), - )) - db.send_create_signal('authtoken', ['Token']) - - def backwards(self, orm): - # Deleting model 'Token' - db.delete_table('authtoken_token') - - models = { - 'auth.group': { - 'Meta': {'object_name': 'Group'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - "%s.%s" % (User._meta.app_label, User._meta.module_name): { - 'Meta': {'object_name': User._meta.module_name, 'db_table': repr(User._meta.db_table)}, - }, - 'authtoken.token': { - 'Meta': {'object_name': 'Token'}, - 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'primary_key': 'True'}), - 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'auth_token'", 'unique': 'True', 'to': "orm['%s.%s']" % (User._meta.app_label, User._meta.object_name)}) - }, - 'contenttypes.contenttype': { - 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - } - } - - complete_apps = ['authtoken'] diff --git a/rest_framework/authtoken/south_migrations/__init__.py b/rest_framework/authtoken/south_migrations/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/rest_framework/compat.py b/rest_framework/compat.py index 8d80f066d..636d4f849 100644 --- a/rest_framework/compat.py +++ b/rest_framework/compat.py @@ -62,16 +62,6 @@ def distinct(queryset, base): return queryset.distinct() -# OrderedDict only available in Python 2.7. -# This will always be the case in Django 1.7 and above, as these versions -# no longer support Python 2.6. -# For Django <= 1.6 and Python 2.6 fall back to SortedDict. -try: - from collections import OrderedDict -except ImportError: - from django.utils.datastructures import SortedDict as OrderedDict - - # contrib.postgres only supported from 1.8 onwards. try: from django.contrib.postgres import fields as postgres_fields @@ -79,41 +69,30 @@ except ImportError: postgres_fields = None +# JSONField is only supported from 1.9 onwards +try: + from django.contrib.postgres.fields import JSONField +except ImportError: + JSONField = None + + # django-filter is optional try: import django_filters except ImportError: django_filters = None -if django.VERSION >= (1, 6): - def clean_manytomany_helptext(text): - return text -else: - # Up to version 1.5 many to many fields automatically suffix - # the `help_text` attribute with hardcoded text. - def clean_manytomany_helptext(text): - if text.endswith(' Hold down "Control", or "Command" on a Mac, to select more than one.'): - text = text[:-69] - return text - # Django-guardian is optional. Import only if guardian is in INSTALLED_APPS # Fixes (#1712). We keep the try/except for the test suite. guardian = None try: - import guardian - import guardian.shortcuts # Fixes #1624 + if 'guardian' in settings.INSTALLED_APPS: + import guardian + import guardian.shortcuts # Fixes #1624 except ImportError: pass -def get_model_name(model_cls): - try: - return model_cls._meta.model_name - except AttributeError: - # < 1.6 used module_name instead of model_name - return model_cls._meta.module_name - - class CustomValidatorMessage(object): def __init__(self, *args, **kwargs): self.message = kwargs.pop('message', self.message) @@ -136,32 +115,6 @@ class MaxLengthValidator(CustomValidatorMessage, MaxLengthValidator): pass -# URLValidator only accepts `message` in 1.6+ -if django.VERSION >= (1, 6): - from django.core.validators import URLValidator -else: - from django.core.validators import URLValidator as DjangoURLValidator - - - class URLValidator(DjangoURLValidator): - def __init__(self, *args, **kwargs): - self.message = kwargs.pop('message', self.message) - super(URLValidator, self).__init__(*args, **kwargs) - - -# EmailValidator requires explicit regex prior to 1.6+ -if django.VERSION >= (1, 6): - from django.core.validators import EmailValidator -else: - from django.core.validators import EmailValidator as DjangoEmailValidator - from django.core.validators import email_re - - - class EmailValidator(DjangoEmailValidator): - def __init__(self, *args, **kwargs): - super(EmailValidator, self).__init__(email_re, *args, **kwargs) - - # PATCH method is not implemented by Django if 'patch' not in View.http_method_names: View.http_method_names = View.http_method_names + ['patch'] diff --git a/rest_framework/exceptions.py b/rest_framework/exceptions.py index 236087bde..8447a9ded 100644 --- a/rest_framework/exceptions.py +++ b/rest_framework/exceptions.py @@ -30,10 +30,10 @@ def _force_text_recursive(data): return ReturnList(ret, serializer=data.serializer) return data elif isinstance(data, dict): - ret = dict([ - (key, _force_text_recursive(value)) + ret = { + key: _force_text_recursive(value) for key, value in data.items() - ]) + } if isinstance(data, ReturnDict): return ReturnDict(ret, serializer=data.serializer) return data diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 240d32cb0..1455801e8 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -5,13 +5,17 @@ import copy import datetime import decimal import inspect +import json import re import uuid +from collections import OrderedDict from django.conf import settings from django.core.exceptions import ValidationError as DjangoValidationError from django.core.exceptions import ObjectDoesNotExist -from django.core.validators import RegexValidator, ip_address_validators +from django.core.validators import ( + EmailValidator, RegexValidator, URLValidator, ip_address_validators +) from django.forms import FilePathField as DjangoFilePathField from django.forms import ImageField as DjangoImageField from django.utils import six, timezone @@ -23,9 +27,9 @@ from django.utils.translation import ugettext_lazy as _ from rest_framework import ISO_8601 from rest_framework.compat import ( - EmailValidator, MaxLengthValidator, MaxValueValidator, MinLengthValidator, - MinValueValidator, OrderedDict, URLValidator, duration_string, - parse_duration, unicode_repr, unicode_to_repr + MaxLengthValidator, MaxValueValidator, MinLengthValidator, + MinValueValidator, duration_string, parse_duration, unicode_repr, + unicode_to_repr ) from rest_framework.exceptions import ValidationError from rest_framework.settings import api_settings @@ -600,8 +604,8 @@ class BooleanField(Field): } default_empty_html = False initial = False - TRUE_VALUES = set(('t', 'T', 'true', 'True', 'TRUE', '1', 1, True)) - FALSE_VALUES = set(('f', 'F', 'false', 'False', 'FALSE', '0', 0, 0.0, False)) + TRUE_VALUES = {'t', 'T', 'true', 'True', 'TRUE', '1', 1, True} + FALSE_VALUES = {'f', 'F', 'false', 'False', 'FALSE', '0', 0, 0.0, False} def __init__(self, **kwargs): assert 'allow_null' not in kwargs, '`allow_null` is not a valid option. Use `NullBooleanField` instead.' @@ -630,9 +634,9 @@ class NullBooleanField(Field): 'invalid': _('"{input}" is not a valid boolean.') } initial = None - TRUE_VALUES = set(('t', 'T', 'true', 'True', 'TRUE', '1', 1, True)) - FALSE_VALUES = set(('f', 'F', 'false', 'False', 'FALSE', '0', 0, 0.0, False)) - NULL_VALUES = set(('n', 'N', 'null', 'Null', 'NULL', '', None)) + TRUE_VALUES = {'t', 'T', 'true', 'True', 'TRUE', '1', 1, True} + FALSE_VALUES = {'f', 'F', 'false', 'False', 'FALSE', '0', 0, 0.0, False} + NULL_VALUES = {'n', 'N', 'null', 'Null', 'NULL', '', None} def __init__(self, **kwargs): assert 'allow_null' not in kwargs, '`allow_null` is not a valid option.' @@ -885,12 +889,11 @@ class DecimalField(Field): } MAX_STRING_LENGTH = 1000 # Guard against malicious string inputs. - coerce_to_string = api_settings.COERCE_DECIMAL_TO_STRING - def __init__(self, max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None, **kwargs): self.max_digits = max_digits self.decimal_places = decimal_places - self.coerce_to_string = coerce_to_string if (coerce_to_string is not None) else self.coerce_to_string + if coerce_to_string is not None: + self.coerce_to_string = coerce_to_string self.max_value = max_value self.min_value = min_value @@ -970,12 +973,14 @@ class DecimalField(Field): return value def to_representation(self, value): + coerce_to_string = getattr(self, 'coerce_to_string', api_settings.COERCE_DECIMAL_TO_STRING) + if not isinstance(value, decimal.Decimal): value = decimal.Decimal(six.text_type(value).strip()) quantized = self.quantize(value) - if not self.coerce_to_string: + if not coerce_to_string: return quantized return '{0:f}'.format(quantized) @@ -997,15 +1002,15 @@ class DateTimeField(Field): 'invalid': _('Datetime has wrong format. Use one of these formats instead: {format}.'), 'date': _('Expected a datetime but got a date.'), } - format = api_settings.DATETIME_FORMAT - input_formats = api_settings.DATETIME_INPUT_FORMATS - default_timezone = timezone.get_default_timezone() if settings.USE_TZ else None datetime_parser = datetime.datetime.strptime def __init__(self, format=empty, input_formats=None, default_timezone=None, *args, **kwargs): - self.format = format if format is not empty else self.format - self.input_formats = input_formats if input_formats is not None else self.input_formats - self.default_timezone = default_timezone if default_timezone is not None else self.default_timezone + if format is not empty: + self.format = format + if input_formats is not None: + self.input_formats = input_formats + if default_timezone is not None: + self.timezone = default_timezone super(DateTimeField, self).__init__(*args, **kwargs) def enforce_timezone(self, value): @@ -1013,21 +1018,28 @@ class DateTimeField(Field): When `self.default_timezone` is `None`, always return naive datetimes. When `self.default_timezone` is not `None`, always return aware datetimes. """ - if (self.default_timezone is not None) and not timezone.is_aware(value): - return timezone.make_aware(value, self.default_timezone) - elif (self.default_timezone is None) and timezone.is_aware(value): + field_timezone = getattr(self, 'timezone', self.default_timezone()) + + if (field_timezone is not None) and not timezone.is_aware(value): + return timezone.make_aware(value, field_timezone) + elif (field_timezone is None) and timezone.is_aware(value): return timezone.make_naive(value, timezone.UTC()) return value + def default_timezone(self): + return timezone.get_default_timezone() if settings.USE_TZ else None + def to_internal_value(self, value): + input_formats = getattr(self, 'input_formats', api_settings.DATETIME_INPUT_FORMATS) + if isinstance(value, datetime.date) and not isinstance(value, datetime.datetime): self.fail('date') if isinstance(value, datetime.datetime): return self.enforce_timezone(value) - for format in self.input_formats: - if format.lower() == ISO_8601: + for input_format in input_formats: + if input_format.lower() == ISO_8601: try: parsed = parse_datetime(value) except (ValueError, TypeError): @@ -1037,25 +1049,27 @@ class DateTimeField(Field): return self.enforce_timezone(parsed) else: try: - parsed = self.datetime_parser(value, format) + parsed = self.datetime_parser(value, input_format) except (ValueError, TypeError): pass else: return self.enforce_timezone(parsed) - humanized_format = humanize_datetime.datetime_formats(self.input_formats) + humanized_format = humanize_datetime.datetime_formats(input_formats) self.fail('invalid', format=humanized_format) def to_representation(self, value): - if self.format is None: + output_format = getattr(self, 'format', api_settings.DATETIME_FORMAT) + + if output_format is None: return value - if self.format.lower() == ISO_8601: + if output_format.lower() == ISO_8601: value = value.isoformat() if value.endswith('+00:00'): value = value[:-6] + 'Z' return value - return value.strftime(self.format) + return value.strftime(output_format) class DateField(Field): @@ -1063,24 +1077,26 @@ class DateField(Field): 'invalid': _('Date has wrong format. Use one of these formats instead: {format}.'), 'datetime': _('Expected a date but got a datetime.'), } - format = api_settings.DATE_FORMAT - input_formats = api_settings.DATE_INPUT_FORMATS datetime_parser = datetime.datetime.strptime def __init__(self, format=empty, input_formats=None, *args, **kwargs): - self.format = format if format is not empty else self.format - self.input_formats = input_formats if input_formats is not None else self.input_formats + if format is not empty: + self.format = format + if input_formats is not None: + self.input_formats = input_formats super(DateField, self).__init__(*args, **kwargs) def to_internal_value(self, value): + input_formats = getattr(self, 'input_formats', api_settings.DATE_INPUT_FORMATS) + if isinstance(value, datetime.datetime): self.fail('datetime') if isinstance(value, datetime.date): return value - for format in self.input_formats: - if format.lower() == ISO_8601: + for input_format in input_formats: + if input_format.lower() == ISO_8601: try: parsed = parse_date(value) except (ValueError, TypeError): @@ -1090,20 +1106,22 @@ class DateField(Field): return parsed else: try: - parsed = self.datetime_parser(value, format) + parsed = self.datetime_parser(value, input_format) except (ValueError, TypeError): pass else: return parsed.date() - humanized_format = humanize_datetime.date_formats(self.input_formats) + humanized_format = humanize_datetime.date_formats(input_formats) self.fail('invalid', format=humanized_format) def to_representation(self, value): + output_format = getattr(self, 'format', api_settings.DATE_FORMAT) + if not value: return None - if self.format is None: + if output_format is None: return value # Applying a `DateField` to a datetime value is almost always @@ -1115,33 +1133,35 @@ class DateField(Field): 'read-only field and deal with timezone issues explicitly.' ) - if self.format.lower() == ISO_8601: + if output_format.lower() == ISO_8601: if (isinstance(value, str)): value = datetime.datetime.strptime(value, '%Y-%m-%d').date() return value.isoformat() - return value.strftime(self.format) + return value.strftime(output_format) class TimeField(Field): default_error_messages = { 'invalid': _('Time has wrong format. Use one of these formats instead: {format}.'), } - format = api_settings.TIME_FORMAT - input_formats = api_settings.TIME_INPUT_FORMATS datetime_parser = datetime.datetime.strptime def __init__(self, format=empty, input_formats=None, *args, **kwargs): - self.format = format if format is not empty else self.format - self.input_formats = input_formats if input_formats is not None else self.input_formats + if format is not empty: + self.format = format + if input_formats is not None: + self.input_formats = input_formats super(TimeField, self).__init__(*args, **kwargs) def to_internal_value(self, value): + input_formats = getattr(self, 'input_formats', api_settings.TIME_INPUT_FORMATS) + if isinstance(value, datetime.time): return value - for format in self.input_formats: - if format.lower() == ISO_8601: + for input_format in input_formats: + if input_format.lower() == ISO_8601: try: parsed = parse_time(value) except (ValueError, TypeError): @@ -1151,17 +1171,19 @@ class TimeField(Field): return parsed else: try: - parsed = self.datetime_parser(value, format) + parsed = self.datetime_parser(value, input_format) except (ValueError, TypeError): pass else: return parsed.time() - humanized_format = humanize_datetime.time_formats(self.input_formats) + humanized_format = humanize_datetime.time_formats(input_formats) self.fail('invalid', format=humanized_format) def to_representation(self, value): - if self.format is None: + output_format = getattr(self, 'format', api_settings.TIME_FORMAT) + + if output_format is None: return value # Applying a `TimeField` to a datetime value is almost always @@ -1173,9 +1195,9 @@ class TimeField(Field): 'read-only field and deal with timezone issues explicitly.' ) - if self.format.lower() == ISO_8601: + if output_format.lower() == ISO_8601: return value.isoformat() - return value.strftime(self.format) + return value.strftime(output_format) class DurationField(Field): @@ -1219,9 +1241,9 @@ class ChoiceField(Field): # Map the string representation of choices to the underlying value. # Allows us to deal with eg. integer choices while supporting either # integer or string input, but still get the correct datatype out. - self.choice_strings_to_values = dict([ - (six.text_type(key), key) for key in self.choices.keys() - ]) + self.choice_strings_to_values = { + six.text_type(key): key for key in self.choices.keys() + } self.allow_blank = kwargs.pop('allow_blank', False) @@ -1280,15 +1302,15 @@ class MultipleChoiceField(ChoiceField): if not self.allow_empty and len(data) == 0: self.fail('empty') - return set([ + return { super(MultipleChoiceField, self).to_internal_value(item) for item in data - ]) + } def to_representation(self, value): - return set([ + return { self.choice_strings_to_values.get(six.text_type(item), item) for item in value - ]) + } class FilePathField(ChoiceField): @@ -1318,12 +1340,12 @@ class FileField(Field): 'empty': _('The submitted file is empty.'), 'max_length': _('Ensure this filename has at most {max_length} characters (it has {length}).'), } - use_url = api_settings.UPLOADED_FILES_USE_URL def __init__(self, *args, **kwargs): self.max_length = kwargs.pop('max_length', None) self.allow_empty_file = kwargs.pop('allow_empty_file', False) - self.use_url = kwargs.pop('use_url', self.use_url) + if 'use_url' in kwargs: + self.use_url = kwargs.pop('use_url') super(FileField, self).__init__(*args, **kwargs) def to_internal_value(self, data): @@ -1344,10 +1366,12 @@ class FileField(Field): return data def to_representation(self, value): + use_url = getattr(self, 'use_url', api_settings.UPLOADED_FILES_USE_URL) + if not value: return None - if self.use_url: + if use_url: if not getattr(value, 'url', None): # If the file has not been saved it may not have a URL. return None @@ -1484,19 +1508,50 @@ class DictField(Field): data = html.parse_html_dict(data) if not isinstance(data, dict): self.fail('not_a_dict', input_type=type(data).__name__) - return dict([ - (six.text_type(key), self.child.run_validation(value)) + return { + six.text_type(key): self.child.run_validation(value) for key, value in data.items() - ]) + } def to_representation(self, value): """ List of object instances -> List of dicts of primitive datatypes. """ - return dict([ - (six.text_type(key), self.child.to_representation(val)) + return { + six.text_type(key): self.child.to_representation(val) for key, val in value.items() - ]) + } + + +class JSONField(Field): + default_error_messages = { + 'invalid': _('Value must be valid JSON.') + } + + def __init__(self, *args, **kwargs): + self.binary = kwargs.pop('binary', False) + super(JSONField, self).__init__(*args, **kwargs) + + def to_internal_value(self, data): + try: + if self.binary: + if isinstance(data, six.binary_type): + data = data.decode('utf-8') + return json.loads(data) + else: + json.dumps(data) + except (TypeError, ValueError): + self.fail('invalid') + return data + + def to_representation(self, value): + if self.binary: + value = json.dumps(value) + # On python 2.x the return type for json.dumps() is underspecified. + # On python 3.x json.dumps() returns unicode strings. + if isinstance(value, six.text_type): + value = bytes(value.encode('utf-8')) + return value # Miscellaneous field types... diff --git a/rest_framework/filters.py b/rest_framework/filters.py index 90c19aba0..c1e0ae054 100644 --- a/rest_framework/filters.py +++ b/rest_framework/filters.py @@ -11,9 +11,7 @@ from django.core.exceptions import ImproperlyConfigured from django.db import models from django.utils import six -from rest_framework.compat import ( - distinct, django_filters, get_model_name, guardian -) +from rest_framework.compat import distinct, django_filters, guardian from rest_framework.settings import api_settings FilterSet = django_filters and django_filters.FilterSet or None @@ -202,7 +200,7 @@ class DjangoObjectPermissionsFilter(BaseFilterBackend): model_cls = queryset.model kwargs = { 'app_label': model_cls._meta.app_label, - 'model_name': get_model_name(model_cls) + 'model_name': model_cls._meta.model_name } permission = self.perm_format % kwargs if guardian.VERSION >= (1, 3): diff --git a/rest_framework/metadata.py b/rest_framework/metadata.py index 5058422f2..6c4f17692 100644 --- a/rest_framework/metadata.py +++ b/rest_framework/metadata.py @@ -8,12 +8,13 @@ to return this information in a more standardized way. """ from __future__ import unicode_literals +from collections import OrderedDict + from django.core.exceptions import PermissionDenied from django.http import Http404 from django.utils.encoding import force_text from rest_framework import exceptions, serializers -from rest_framework.compat import OrderedDict from rest_framework.request import clone_request from rest_framework.utils.field_mapping import ClassLookupDict @@ -76,7 +77,7 @@ class SimpleMetadata(BaseMetadata): the fields that are accepted for 'PUT' and 'POST' methods. """ actions = {} - for method in set(['PUT', 'POST']) & set(view.allowed_methods): + for method in {'PUT', 'POST'} & set(view.allowed_methods): view.request = clone_request(request, method) try: # Test global permissions diff --git a/rest_framework/negotiation.py b/rest_framework/negotiation.py index b9263c447..2a2b6f168 100644 --- a/rest_framework/negotiation.py +++ b/rest_framework/negotiation.py @@ -92,9 +92,6 @@ class DefaultContentNegotiation(BaseContentNegotiation): """ Given the incoming request, return a tokenised list of media type strings. - - Allows URL style accept override. eg. "?accept=application/json" """ header = request.META.get('HTTP_ACCEPT', '*/*') - header = request.query_params.get(self.settings.URL_ACCEPT_OVERRIDE, header) return [token.strip() for token in header.split(',')] diff --git a/rest_framework/pagination.py b/rest_framework/pagination.py index bf72ef4fc..45b5b29c5 100644 --- a/rest_framework/pagination.py +++ b/rest_framework/pagination.py @@ -7,7 +7,7 @@ from __future__ import unicode_literals import warnings from base64 import b64decode, b64encode -from collections import namedtuple +from collections import OrderedDict, namedtuple from django.core.paginator import Paginator as DjangoPaginator from django.core.paginator import InvalidPage @@ -16,7 +16,6 @@ from django.utils import six from django.utils.six.moves.urllib import parse as urlparse from django.utils.translation import ugettext_lazy as _ -from rest_framework.compat import OrderedDict from rest_framework.exceptions import NotFound from rest_framework.response import Response from rest_framework.settings import api_settings @@ -80,11 +79,7 @@ def _get_displayed_page_numbers(current, final): # We always include the first two pages, last two pages, and # two pages either side of the current page. - included = set(( - 1, - current - 1, current, current + 1, - final - )) + included = {1, current - 1, current, current + 1, final} # If the break would only exclude a single page number then we # may as well include the page number instead of the break. diff --git a/rest_framework/permissions.py b/rest_framework/permissions.py index 628538903..292952cfa 100644 --- a/rest_framework/permissions.py +++ b/rest_framework/permissions.py @@ -5,8 +5,6 @@ from __future__ import unicode_literals from django.http import Http404 -from rest_framework.compat import get_model_name - SAFE_METHODS = ('GET', 'HEAD', 'OPTIONS') @@ -104,7 +102,7 @@ class DjangoModelPermissions(BasePermission): """ kwargs = { 'app_label': model_cls._meta.app_label, - 'model_name': get_model_name(model_cls) + 'model_name': model_cls._meta.model_name } return [perm % kwargs for perm in self.perms_map[method]] @@ -166,7 +164,7 @@ class DjangoObjectPermissions(DjangoModelPermissions): def get_required_object_permissions(self, method, model_cls): kwargs = { 'app_label': model_cls._meta.app_label, - 'model_name': get_model_name(model_cls) + 'model_name': model_cls._meta.model_name } return [perm % kwargs for perm in self.perms_map[method]] diff --git a/rest_framework/relations.py b/rest_framework/relations.py index 56af657d9..24800a758 100644 --- a/rest_framework/relations.py +++ b/rest_framework/relations.py @@ -1,6 +1,8 @@ # coding: utf-8 from __future__ import unicode_literals +from collections import OrderedDict + from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist from django.core.urlresolvers import ( NoReverseMatch, Resolver404, get_script_prefix, resolve @@ -12,7 +14,6 @@ from django.utils.encoding import smart_text from django.utils.six.moves.urllib import parse as urlparse from django.utils.translation import ugettext_lazy as _ -from rest_framework.compat import OrderedDict from rest_framework.fields import ( Field, empty, get_attribute, is_simple_callable, iter_options ) diff --git a/rest_framework/renderers.py b/rest_framework/renderers.py index fb0dfcbd8..c5b0aeb3c 100644 --- a/rest_framework/renderers.py +++ b/rest_framework/renderers.py @@ -4,7 +4,7 @@ Renderers are used to serialize a response into specific media types. They give us a generic way of being able to handle various media types on the response, such as JSON encoded data or HTML output. -REST framework also provides an HTML renderer the renders the browsable API. +REST framework also provides an HTML renderer that renders the browsable API. """ from __future__ import unicode_literals @@ -420,9 +420,6 @@ class BrowsableAPIRenderer(BaseRenderer): if method not in view.allowed_methods: return # Not a valid method - if not api_settings.FORM_METHOD_OVERRIDE: - return # Cannot use form overloading - try: view.check_permissions(request) if obj is not None: @@ -530,13 +527,6 @@ class BrowsableAPIRenderer(BaseRenderer): instance = None with override_method(view, request, method) as request: - # If we're not using content overloading there's no point in - # supplying a generic form, as the view won't treat the form's - # value as the content of the request. - if not (api_settings.FORM_CONTENT_OVERRIDE and - api_settings.FORM_CONTENTTYPE_OVERRIDE): - return None - # Check permissions if not self.show_form_for_method(view, method, request, instance): return @@ -564,28 +554,22 @@ class BrowsableAPIRenderer(BaseRenderer): # Generate a generic form that includes a content type field, # and a content field. - content_type_field = api_settings.FORM_CONTENTTYPE_OVERRIDE - content_field = api_settings.FORM_CONTENT_OVERRIDE - media_types = [parser.media_type for parser in view.parser_classes] choices = [(media_type, media_type) for media_type in media_types] initial = media_types[0] - # NB. http://jacobian.org/writing/dynamic-form-generation/ class GenericContentForm(forms.Form): - def __init__(self): - super(GenericContentForm, self).__init__() - - self.fields[content_type_field] = forms.ChoiceField( - label='Media type', - choices=choices, - initial=initial - ) - self.fields[content_field] = forms.CharField( - label='Content', - widget=forms.Textarea, - initial=content - ) + _content_type = forms.ChoiceField( + label='Media type', + choices=choices, + initial=initial, + widget=forms.Select(attrs={'data-override': 'content-type'}) + ) + _content = forms.CharField( + label='Content', + widget=forms.Textarea(attrs={'data-override': 'content'}), + initial=content + ) return GenericContentForm() diff --git a/rest_framework/request.py b/rest_framework/request.py index 7b583485b..76bf496ce 100644 --- a/rest_framework/request.py +++ b/rest_framework/request.py @@ -86,7 +86,7 @@ def clone_request(request, method): ret._full_data = request._full_data ret._content_type = request._content_type ret._stream = request._stream - ret._method = method + ret.method = method if hasattr(request, '_user'): ret._user = request._user if hasattr(request, '_auth'): @@ -129,11 +129,6 @@ class Request(object): - authentication_classes(list/tuple). The authentications used to try authenticating the request's user. """ - - _METHOD_PARAM = api_settings.FORM_METHOD_OVERRIDE - _CONTENT_PARAM = api_settings.FORM_CONTENT_OVERRIDE - _CONTENTTYPE_PARAM = api_settings.FORM_CONTENTTYPE_OVERRIDE - def __init__(self, request, parsers=None, authenticators=None, negotiator=None, parser_context=None): self._request = request @@ -144,7 +139,6 @@ class Request(object): self._data = Empty self._files = Empty self._full_data = Empty - self._method = Empty self._content_type = Empty self._stream = Empty @@ -162,30 +156,10 @@ class Request(object): def _default_negotiator(self): return api_settings.DEFAULT_CONTENT_NEGOTIATION_CLASS() - @property - def method(self): - """ - Returns the HTTP method. - - This allows the `method` to be overridden by using a hidden `form` - field on a form POST request. - """ - if not _hasattr(self, '_method'): - self._load_method_and_content_type() - return self._method - @property def content_type(self): - """ - Returns the content type header. - - This should be used instead of `request.META.get('HTTP_CONTENT_TYPE')`, - as it allows the content type to be overridden by using a hidden form - field on a form POST request. - """ - if not _hasattr(self, '_content_type'): - self._load_method_and_content_type() - return self._content_type + meta = self._request.META + return meta.get('CONTENT_TYPE', meta.get('HTTP_CONTENT_TYPE', '')) @property def stream(self): @@ -265,9 +239,6 @@ class Request(object): """ Parses the request content into `self.data`. """ - if not _hasattr(self, '_content_type'): - self._load_method_and_content_type() - if not _hasattr(self, '_data'): self._data, self._files = self._parse() if self._files: @@ -276,32 +247,14 @@ class Request(object): else: self._full_data = self._data - def _load_method_and_content_type(self): - """ - Sets the method and content_type, and then check if they've - been overridden. - """ - self._content_type = self.META.get('HTTP_CONTENT_TYPE', - self.META.get('CONTENT_TYPE', '')) - - self._perform_form_overloading() - - if not _hasattr(self, '_method'): - self._method = self._request.method - - # Allow X-HTTP-METHOD-OVERRIDE header - if 'HTTP_X_HTTP_METHOD_OVERRIDE' in self.META: - self._method = self.META['HTTP_X_HTTP_METHOD_OVERRIDE'].upper() - def _load_stream(self): """ Return the content body of the request, as a stream. """ + meta = self._request.META try: content_length = int( - self.META.get( - 'CONTENT_LENGTH', self.META.get('HTTP_CONTENT_LENGTH') - ) + meta.get('CONTENT_LENGTH', meta.get('HTTP_CONTENT_LENGTH', 0)) ) except (ValueError, TypeError): content_length = 0 @@ -313,50 +266,6 @@ class Request(object): else: self._stream = six.BytesIO(self.raw_post_data) - def _perform_form_overloading(self): - """ - If this is a form POST request, then we need to check if the method and - content/content_type have been overridden by setting them in hidden - form fields or not. - """ - - USE_FORM_OVERLOADING = ( - self._METHOD_PARAM or - (self._CONTENT_PARAM and self._CONTENTTYPE_PARAM) - ) - - # We only need to use form overloading on form POST requests. - if ( - self._request.method != 'POST' or - not USE_FORM_OVERLOADING or - not is_form_media_type(self._content_type) - ): - return - - # At this point we're committed to parsing the request as form data. - self._data = self._request.POST - self._files = self._request.FILES - self._full_data = self._data.copy() - self._full_data.update(self._files) - - # Method overloading - change the method and remove the param from the content. - if ( - self._METHOD_PARAM and - self._METHOD_PARAM in self._data - ): - self._method = self._data[self._METHOD_PARAM].upper() - - # Content overloading - modify the content type, and force re-parse. - if ( - self._CONTENT_PARAM and - self._CONTENTTYPE_PARAM and - self._CONTENT_PARAM in self._data and - self._CONTENTTYPE_PARAM in self._data - ): - self._content_type = self._data[self._CONTENTTYPE_PARAM] - self._stream = six.BytesIO(self._data[self._CONTENT_PARAM].encode(self.parser_context['encoding'])) - self._data, self._files, self._full_data = (Empty, Empty, Empty) - def _parse(self): """ Parse the request content, returning a two-tuple of (data, files) diff --git a/rest_framework/response.py b/rest_framework/response.py index 3f038e3b5..0e97668eb 100644 --- a/rest_framework/response.py +++ b/rest_framework/response.py @@ -98,7 +98,7 @@ class Response(SimpleTemplateResponse): state = super(Response, self).__getstate__() for key in ( 'accepted_renderer', 'renderer_context', 'resolver_match', - 'client', 'request', 'wsgi_request' + 'client', 'request', 'json', 'wsgi_request' ): if key in state: del state[key] diff --git a/rest_framework/reverse.py b/rest_framework/reverse.py index af7c5e949..5a7ba09a8 100644 --- a/rest_framework/reverse.py +++ b/rest_framework/reverse.py @@ -22,7 +22,6 @@ def preserve_builtin_query_params(url, request=None): overrides = [ api_settings.URL_FORMAT_OVERRIDE, - api_settings.URL_ACCEPT_OVERRIDE ] for param in overrides: diff --git a/rest_framework/routers.py b/rest_framework/routers.py index b96100ec2..39605923d 100644 --- a/rest_framework/routers.py +++ b/rest_framework/routers.py @@ -16,14 +16,13 @@ For example, you might have a `urls.py` that looks something like this: from __future__ import unicode_literals import itertools -from collections import namedtuple +from collections import OrderedDict, namedtuple from django.conf.urls import url from django.core.exceptions import ImproperlyConfigured from django.core.urlresolvers import NoReverseMatch from rest_framework import views -from rest_framework.compat import OrderedDict from rest_framework.response import Response from rest_framework.reverse import reverse from rest_framework.urlpatterns import format_suffix_patterns @@ -175,7 +174,7 @@ class SimpleRouter(BaseRouter): url_path = initkwargs.pop("url_path", None) or methodname ret.append(Route( url=replace_methodname(route.url, url_path), - mapping=dict((httpmethod, methodname) for httpmethod in httpmethods), + mapping={httpmethod: methodname for httpmethod in httpmethods}, name=replace_methodname(route.name, url_path), initkwargs=initkwargs, )) diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index 037939e31..d505d8d3a 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -12,6 +12,8 @@ response content is handled by parsers and renderers. """ from __future__ import unicode_literals +import warnings + from django.db import models from django.db.models.fields import Field as DjangoModelField from django.db.models.fields import FieldDoesNotExist @@ -19,6 +21,7 @@ from django.utils.functional import cached_property from django.utils.translation import ugettext_lazy as _ from rest_framework.compat import DurationField as ModelDurationField +from rest_framework.compat import JSONField as ModelJSONField from rest_framework.compat import postgres_fields, unicode_to_repr from rest_framework.utils import model_meta from rest_framework.utils.field_mapping import ( @@ -51,6 +54,8 @@ LIST_SERIALIZER_KWARGS = ( 'instance', 'data', 'partial', 'context', 'allow_null' ) +ALL_FIELDS = '__all__' + # BaseSerializer # -------------- @@ -120,10 +125,10 @@ class BaseSerializer(Field): } if allow_empty is not None: list_kwargs['allow_empty'] = allow_empty - list_kwargs.update(dict([ - (key, value) for key, value in kwargs.items() + list_kwargs.update({ + key: value for key, value in kwargs.items() if key in LIST_SERIALIZER_KWARGS - ])) + }) meta = getattr(cls, 'Meta', None) list_serializer_class = getattr(meta, 'list_serializer_class', ListSerializer) return list_serializer_class(*args, **list_kwargs) @@ -166,6 +171,12 @@ class BaseSerializer(Field): "For example: 'serializer.save(owner=request.user)'.'" ) + assert not hasattr(self, '_data'), ( + "You cannot call `.save()` after accessing `serializer.data`." + "If you need to access data before committing to the database then " + "inspect 'serializer.validated_data' instead. " + ) + validated_data = dict( list(self.validated_data.items()) + list(kwargs.items()) @@ -294,10 +305,10 @@ def get_validation_error_detail(exc): elif isinstance(exc.detail, dict): # If errors may be a dict we use the standard {key: list of values}. # Here we ensure that all the values are *lists* of errors. - return dict([ - (key, value if isinstance(value, list) else [value]) + return { + key: value if isinstance(value, list) else [value] for key, value in exc.detail.items() - ]) + } elif isinstance(exc.detail, list): # Errors raised as a list are non-field errors. return { @@ -780,6 +791,8 @@ class ModelSerializer(Serializer): } if ModelDurationField is not None: serializer_field_mapping[ModelDurationField] = DurationField + if ModelJSONField is not None: + serializer_field_mapping[ModelJSONField] = JSONField serializer_related_field = PrimaryKeyRelatedField serializer_url_field = HyperlinkedIdentityField serializer_choice_field = ChoiceField @@ -791,7 +804,7 @@ class ModelSerializer(Serializer): # you'll also need to ensure you update the `create` method on any generic # views, to correctly handle the 'Location' response header for # "HTTP 201 Created" responses. - url_field_name = api_settings.URL_FIELD_NAME + url_field_name = None # Default `create` and `update` behavior... def create(self, validated_data): @@ -874,6 +887,9 @@ class ModelSerializer(Serializer): Return the dict of field names -> field instances that should be used for `self.fields` when instantiating the serializer. """ + if self.url_field_name is None: + self.url_field_name = api_settings.URL_FIELD_NAME + assert hasattr(self, 'Meta'), ( 'Class {serializer_class} missing "Meta" attribute'.format( serializer_class=self.__class__.__name__ @@ -948,10 +964,10 @@ class ModelSerializer(Serializer): fields = getattr(self.Meta, 'fields', None) exclude = getattr(self.Meta, 'exclude', None) - if fields and not isinstance(fields, (list, tuple)): + if fields and fields != ALL_FIELDS and not isinstance(fields, (list, tuple)): raise TypeError( - 'The `fields` option must be a list or tuple. Got %s.' % - type(fields).__name__ + 'The `fields` option must be a list or tuple or "__all__". ' + 'Got %s.' % type(fields).__name__ ) if exclude and not isinstance(exclude, (list, tuple)): @@ -967,6 +983,20 @@ class ModelSerializer(Serializer): ) ) + if fields is None and exclude is None: + warnings.warn( + "Creating a ModelSerializer without either the 'fields' " + "attribute or the 'exclude' attribute is pending deprecation " + "since 3.3.0. Add an explicit fields = '__all__' to the " + "{serializer_class} serializer.".format( + serializer_class=self.__class__.__name__ + ), + PendingDeprecationWarning + ) + + if fields == ALL_FIELDS: + fields = None + if fields is not None: # Ensure that all declared fields have also been included in the # `Meta.fields` option. @@ -1207,13 +1237,10 @@ class ModelSerializer(Serializer): for model_field in model_fields.values(): # Include each of the `unique_for_*` field names. - unique_constraint_names |= set([ - model_field.unique_for_date, - model_field.unique_for_month, - model_field.unique_for_year - ]) + unique_constraint_names |= {model_field.unique_for_date, model_field.unique_for_month, + model_field.unique_for_year} - unique_constraint_names -= set([None]) + unique_constraint_names -= {None} # Include each of the `unique_together` field names, # so long as all the field names are included on the serializer. @@ -1327,10 +1354,10 @@ class ModelSerializer(Serializer): # which may map onto a model field. Any dotted field name lookups # cannot map to a field, and must be a traversal, so we're not # including those. - field_names = set([ + field_names = { field.source for field in self.fields.values() if (field.source != '*') and ('.' not in field.source) - ]) + } # Note that we make sure to check `unique_together` both on the # base model class, but also on any parent classes. diff --git a/rest_framework/settings.py b/rest_framework/settings.py index e20e51287..9d834c125 100644 --- a/rest_framework/settings.py +++ b/rest_framework/settings.py @@ -26,8 +26,6 @@ from django.utils import six from rest_framework import ISO_8601 from rest_framework.compat import importlib -USER_SETTINGS = getattr(settings, 'REST_FRAMEWORK', None) - DEFAULTS = { # Base API policies 'DEFAULT_RENDERER_CLASSES': ( @@ -93,13 +91,8 @@ DEFAULTS = { ), 'TEST_REQUEST_DEFAULT_FORMAT': 'multipart', - # Browser enhancements - 'FORM_METHOD_OVERRIDE': '_method', - 'FORM_CONTENT_OVERRIDE': '_content', - 'FORM_CONTENTTYPE_OVERRIDE': '_content_type', - 'URL_ACCEPT_OVERRIDE': 'accept', + # Hyperlink settings 'URL_FORMAT_OVERRIDE': 'format', - 'FORMAT_SUFFIX_KWARG': 'format', 'URL_FIELD_NAME': 'url', @@ -188,10 +181,17 @@ class APISettings(object): and return the class, rather than the string literal. """ def __init__(self, user_settings=None, defaults=None, import_strings=None): - self.user_settings = user_settings or {} + if user_settings: + self._user_settings = user_settings self.defaults = defaults or DEFAULTS self.import_strings = import_strings or IMPORT_STRINGS + @property + def user_settings(self): + if not hasattr(self, '_user_settings'): + self._user_settings = getattr(settings, 'REST_FRAMEWORK', {}) + return self._user_settings + def __getattr__(self, attr): if attr not in self.defaults.keys(): raise AttributeError("Invalid API setting: '%s'" % attr) @@ -212,7 +212,7 @@ class APISettings(object): return val -api_settings = APISettings(USER_SETTINGS, DEFAULTS, IMPORT_STRINGS) +api_settings = APISettings(None, DEFAULTS, IMPORT_STRINGS) def reload_api_settings(*args, **kwargs): diff --git a/rest_framework/static/rest_framework/js/ajax-form.js b/rest_framework/static/rest_framework/js/ajax-form.js new file mode 100644 index 000000000..db07fd8fb --- /dev/null +++ b/rest_framework/static/rest_framework/js/ajax-form.js @@ -0,0 +1,97 @@ +function replaceDocument(docString) { + var doc = document.open("text/html"); + doc.write(docString); + doc.close(); +} + + +function doAjaxSubmit(e) { + var form = $(this); + var btn = $(this.clk); + var method = btn.data('method') || form.data('method') || form.attr('method') || 'GET'; + method = method.toUpperCase() + if (method === 'GET') { + // GET requests can always use standard form submits. + return; + } + + var contentType = + form.find('input[data-override="content-type"]').val() || + form.find('select[data-override="content-type"] option:selected').text(); + if (method === 'POST' && !contentType) { + // POST requests can use standard form submits, unless we have + // overridden the content type. + return; + } + + // At this point we need to make an AJAX form submission. + e.preventDefault(); + + var url = form.attr('action'); + var data; + if (contentType) { + data = form.find('[data-override="content"]').val() || '' + } else { + contentType = form.attr('enctype') || form.attr('encoding') + if (contentType === 'multipart/form-data') { + if (!window.FormData) { + alert('Your browser does not support AJAX multipart form submissions'); + return; + } + // Use the FormData API and allow the content type to be set automatically, + // so it includes the boundary string. + // See https://developer.mozilla.org/en-US/docs/Web/API/FormData/Using_FormData_Objects + contentType = false; + data = new FormData(form[0]); + } else { + contentType = 'application/x-www-form-urlencoded; charset=UTF-8' + data = form.serialize(); + } + } + + var ret = $.ajax({ + url: url, + method: method, + data: data, + contentType: contentType, + processData: false, + headers: {'Accept': 'text/html; q=1.0, */*'}, + }); + ret.always(function(data, textStatus, jqXHR) { + if (textStatus != 'success') { + jqXHR = data; + } + var responseContentType = jqXHR.getResponseHeader("content-type") || ""; + if (responseContentType.toLowerCase().indexOf('text/html') === 0) { + replaceDocument(jqXHR.responseText); + try { + // Modify the location and scroll to top, as if after page load. + history.replaceState({}, '', url); + scroll(0,0); + } catch(err) { + // History API not supported, so redirect. + window.location = url; + } + } else { + // Not HTML content. We can't open this directly, so redirect. + window.location = url; + } + }); + return ret; +} + + +function captureSubmittingElement(e) { + var target = e.target; + var form = this; + form.clk = target; +} + + +$.fn.ajaxForm = function() { + var options = {} + return this + .unbind('submit.form-plugin click.form-plugin') + .bind('submit.form-plugin', options, doAjaxSubmit) + .bind('click.form-plugin', options, captureSubmittingElement); +}; diff --git a/rest_framework/static/rest_framework/js/csrf.js b/rest_framework/static/rest_framework/js/csrf.js new file mode 100644 index 000000000..4e8da0de5 --- /dev/null +++ b/rest_framework/static/rest_framework/js/csrf.js @@ -0,0 +1,47 @@ +function getCookie(name) { + var cookieValue = null; + if (document.cookie && document.cookie != '') { + var cookies = document.cookie.split(';'); + for (var i = 0; i < cookies.length; i++) { + var cookie = jQuery.trim(cookies[i]); + // Does this cookie string begin with the name we want? + if (cookie.substring(0, name.length + 1) == (name + '=')) { + cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); + break; + } + } + } + return cookieValue; +} + +function csrfSafeMethod(method) { + // these HTTP methods do not require CSRF protection + return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); +} + +function sameOrigin(url) { + // test that a given url is a same-origin URL + // url could be relative or scheme relative or absolute + var host = document.location.host; // host + port + var protocol = document.location.protocol; + var sr_origin = '//' + host; + var origin = protocol + sr_origin; + // Allow absolute or scheme relative URLs to same origin + return (url == origin || url.slice(0, origin.length + 1) == origin + '/') || + (url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') || + // or any other URL that isn't scheme relative or absolute i.e relative. + !(/^(\/\/|http:|https:).*/.test(url)); +} + +var csrftoken = getCookie('csrftoken'); + +$.ajaxSetup({ + beforeSend: function(xhr, settings) { + if (!csrfSafeMethod(settings.type) && sameOrigin(settings.url)) { + // Send the token to same-origin, relative URLs only. + // Send the token only if the method warrants CSRF protection + // Using the CSRFToken value acquired earlier + xhr.setRequestHeader("X-CSRFToken", csrftoken); + } + } +}); diff --git a/rest_framework/static/rest_framework/js/jquery-1.11.3.min.js b/rest_framework/static/rest_framework/js/jquery-1.11.3.min.js new file mode 100644 index 000000000..0f60b7bd0 --- /dev/null +++ b/rest_framework/static/rest_framework/js/jquery-1.11.3.min.js @@ -0,0 +1,5 @@ +/*! jQuery v1.11.3 | (c) 2005, 2015 jQuery Foundation, Inc. | jquery.org/license */ +!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l="1.11.3",m=function(a,b){return new m.fn.init(a,b)},n=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,o=/^-ms-/,p=/-([\da-z])/gi,q=function(a,b){return b.toUpperCase()};m.fn=m.prototype={jquery:l,constructor:m,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=m.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return m.each(this,a,b)},map:function(a){return this.pushStack(m.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},m.extend=m.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||m.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(m.isPlainObject(c)||(b=m.isArray(c)))?(b?(b=!1,f=a&&m.isArray(a)?a:[]):f=a&&m.isPlainObject(a)?a:{},g[d]=m.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},m.extend({expando:"jQuery"+(l+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===m.type(a)},isArray:Array.isArray||function(a){return"array"===m.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return!m.isArray(a)&&a-parseFloat(a)+1>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==m.type(a)||a.nodeType||m.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(k.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&m.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(o,"ms-").replace(p,q)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=r(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(n,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(r(Object(a))?m.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=r(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),m.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||m.guid++,e):void 0},now:function(){return+new Date},support:k}),m.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function r(a){var b="length"in a&&a.length,c=m.type(a);return"function"===c||m.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var s=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ha(),z=ha(),A=ha(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N=M.replace("w","w#"),O="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+N+"))|)"+L+"*\\]",P=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+O+")*)|.*)\\)|)",Q=new RegExp(L+"+","g"),R=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),S=new RegExp("^"+L+"*,"+L+"*"),T=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),U=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),V=new RegExp(P),W=new RegExp("^"+N+"$"),X={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+O),PSEUDO:new RegExp("^"+P),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,aa=/[+~]/,ba=/'|\\/g,ca=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),da=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},ea=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(fa){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function ga(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],k=b.nodeType,"string"!=typeof a||!a||1!==k&&9!==k&&11!==k)return d;if(!e&&p){if(11!==k&&(f=_.exec(a)))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return H.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName)return H.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=1!==k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(ba,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+ra(o[l]);w=aa.test(a)&&pa(b.parentNode)||b,x=o.join(",")}if(x)try{return H.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function ha(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ia(a){return a[u]=!0,a}function ja(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ka(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function la(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function na(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function oa(a){return ia(function(b){return b=+b,ia(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function pa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=ga.support={},f=ga.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=ga.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=g.documentElement,e=g.defaultView,e&&e!==e.top&&(e.addEventListener?e.addEventListener("unload",ea,!1):e.attachEvent&&e.attachEvent("onunload",ea)),p=!f(g),c.attributes=ja(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ja(function(a){return a.appendChild(g.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(g.getElementsByClassName),c.getById=ja(function(a){return o.appendChild(a).id=u,!g.getElementsByName||!g.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ca,da);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ca,da);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(g.querySelectorAll))&&(ja(function(a){o.appendChild(a).innerHTML="",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ja(function(a){var b=g.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ja(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",P)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===g||a.ownerDocument===v&&t(v,a)?-1:b===g||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,h=[a],i=[b];if(!e||!f)return a===g?-1:b===g?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return la(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?la(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},g):n},ga.matches=function(a,b){return ga(a,null,null,b)},ga.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return ga(b,n,null,[a]).length>0},ga.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},ga.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},ga.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},ga.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=ga.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=ga.selectors={cacheLength:50,createPseudo:ia,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ca,da),a[3]=(a[3]||a[4]||a[5]||"").replace(ca,da),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||ga.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&ga.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ca,da).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=ga.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(Q," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||ga.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ia(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ia(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?ia(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ia(function(a){return function(b){return ga(a,b).length>0}}),contains:ia(function(a){return a=a.replace(ca,da),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ia(function(a){return W.test(a||"")||ga.error("unsupported lang: "+a),a=a.replace(ca,da).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:oa(function(){return[0]}),last:oa(function(a,b){return[b-1]}),eq:oa(function(a,b,c){return[0>c?c+b:c]}),even:oa(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:oa(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:oa(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:oa(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function sa(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function ta(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ua(a,b,c){for(var d=0,e=b.length;e>d;d++)ga(a,b[d],c);return c}function va(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function wa(a,b,c,d,e,f){return d&&!d[u]&&(d=wa(d)),e&&!e[u]&&(e=wa(e,f)),ia(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ua(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:va(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=va(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=va(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function xa(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=sa(function(a){return a===b},h,!0),l=sa(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[sa(ta(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return wa(i>1&&ta(m),i>1&&ra(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&xa(a.slice(i,e)),f>e&&xa(a=a.slice(e)),f>e&&ra(a))}m.push(c)}return ta(m)}function ya(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=F.call(i));s=va(s)}H.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&ga.uniqueSort(i)}return k&&(w=v,j=t),r};return c?ia(f):f}return h=ga.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=xa(b[c]),f[u]?d.push(f):e.push(f);f=A(a,ya(e,d)),f.selector=a}return f},i=ga.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(ca,da),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(ca,da),aa.test(j[0].type)&&pa(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&ra(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,aa.test(a)&&pa(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ja(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ja(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||ka("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ja(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ka("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ja(function(a){return null==a.getAttribute("disabled")})||ka(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),ga}(a);m.find=s,m.expr=s.selectors,m.expr[":"]=m.expr.pseudos,m.unique=s.uniqueSort,m.text=s.getText,m.isXMLDoc=s.isXML,m.contains=s.contains;var t=m.expr.match.needsContext,u=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,v=/^.[^:#\[\.,]*$/;function w(a,b,c){if(m.isFunction(b))return m.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return m.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(v.test(b))return m.filter(b,a,c);b=m.filter(b,a)}return m.grep(a,function(a){return m.inArray(a,b)>=0!==c})}m.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?m.find.matchesSelector(d,a)?[d]:[]:m.find.matches(a,m.grep(b,function(a){return 1===a.nodeType}))},m.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(m(a).filter(function(){for(b=0;e>b;b++)if(m.contains(d[b],this))return!0}));for(b=0;e>b;b++)m.find(a,d[b],c);return c=this.pushStack(e>1?m.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(w(this,a||[],!1))},not:function(a){return this.pushStack(w(this,a||[],!0))},is:function(a){return!!w(this,"string"==typeof a&&t.test(a)?m(a):a||[],!1).length}});var x,y=a.document,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=m.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||x).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof m?b[0]:b,m.merge(this,m.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:y,!0)),u.test(c[1])&&m.isPlainObject(b))for(c in b)m.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=y.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return x.find(a);this.length=1,this[0]=d}return this.context=y,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):m.isFunction(a)?"undefined"!=typeof x.ready?x.ready(a):a(m):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),m.makeArray(a,this))};A.prototype=m.fn,x=m(y);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};m.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!m(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),m.fn.extend({has:function(a){var b,c=m(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(m.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=t.test(a)||"string"!=typeof a?m(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&m.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?m.unique(f):f)},index:function(a){return a?"string"==typeof a?m.inArray(this[0],m(a)):m.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(m.unique(m.merge(this.get(),m(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}m.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return m.dir(a,"parentNode")},parentsUntil:function(a,b,c){return m.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return m.dir(a,"nextSibling")},prevAll:function(a){return m.dir(a,"previousSibling")},nextUntil:function(a,b,c){return m.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return m.dir(a,"previousSibling",c)},siblings:function(a){return m.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return m.sibling(a.firstChild)},contents:function(a){return m.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:m.merge([],a.childNodes)}},function(a,b){m.fn[a]=function(c,d){var e=m.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=m.filter(d,e)),this.length>1&&(C[a]||(e=m.unique(e)),B.test(a)&&(e=e.reverse())),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return m.each(a.match(E)||[],function(a,c){b[c]=!0}),b}m.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):m.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){m.each(b,function(b,c){var d=m.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&m.each(arguments,function(a,c){var d;while((d=m.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?m.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},m.extend({Deferred:function(a){var b=[["resolve","done",m.Callbacks("once memory"),"resolved"],["reject","fail",m.Callbacks("once memory"),"rejected"],["notify","progress",m.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return m.Deferred(function(c){m.each(b,function(b,f){var g=m.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&m.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?m.extend(a,d):d}},e={};return d.pipe=d.then,m.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&m.isFunction(a.promise)?e:0,g=1===f?a:m.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&m.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;m.fn.ready=function(a){return m.ready.promise().done(a),this},m.extend({isReady:!1,readyWait:1,holdReady:function(a){a?m.readyWait++:m.ready(!0)},ready:function(a){if(a===!0?!--m.readyWait:!m.isReady){if(!y.body)return setTimeout(m.ready);m.isReady=!0,a!==!0&&--m.readyWait>0||(H.resolveWith(y,[m]),m.fn.triggerHandler&&(m(y).triggerHandler("ready"),m(y).off("ready")))}}});function I(){y.addEventListener?(y.removeEventListener("DOMContentLoaded",J,!1),a.removeEventListener("load",J,!1)):(y.detachEvent("onreadystatechange",J),a.detachEvent("onload",J))}function J(){(y.addEventListener||"load"===event.type||"complete"===y.readyState)&&(I(),m.ready())}m.ready.promise=function(b){if(!H)if(H=m.Deferred(),"complete"===y.readyState)setTimeout(m.ready);else if(y.addEventListener)y.addEventListener("DOMContentLoaded",J,!1),a.addEventListener("load",J,!1);else{y.attachEvent("onreadystatechange",J),a.attachEvent("onload",J);var c=!1;try{c=null==a.frameElement&&y.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!m.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}I(),m.ready()}}()}return H.promise(b)};var K="undefined",L;for(L in m(k))break;k.ownLast="0"!==L,k.inlineBlockNeedsLayout=!1,m(function(){var a,b,c,d;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",k.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(d))}),function(){var a=y.createElement("div");if(null==k.deleteExpando){k.deleteExpando=!0;try{delete a.test}catch(b){k.deleteExpando=!1}}a=null}(),m.acceptData=function(a){var b=m.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var M=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,N=/([A-Z])/g;function O(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(N,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:M.test(c)?m.parseJSON(c):c}catch(e){}m.data(a,b,c)}else c=void 0}return c}function P(a){var b;for(b in a)if(("data"!==b||!m.isEmptyObject(a[b]))&&"toJSON"!==b)return!1; + +return!0}function Q(a,b,d,e){if(m.acceptData(a)){var f,g,h=m.expando,i=a.nodeType,j=i?m.cache:a,k=i?a[h]:a[h]&&h;if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||m.guid++:h),j[k]||(j[k]=i?{}:{toJSON:m.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=m.extend(j[k],b):j[k].data=m.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[m.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[m.camelCase(b)])):f=g,f}}function R(a,b,c){if(m.acceptData(a)){var d,e,f=a.nodeType,g=f?m.cache:a,h=f?a[m.expando]:m.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){m.isArray(b)?b=b.concat(m.map(b,m.camelCase)):b in d?b=[b]:(b=m.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!P(d):!m.isEmptyObject(d))return}(c||(delete g[h].data,P(g[h])))&&(f?m.cleanData([a],!0):k.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}m.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?m.cache[a[m.expando]]:a[m.expando],!!a&&!P(a)},data:function(a,b,c){return Q(a,b,c)},removeData:function(a,b){return R(a,b)},_data:function(a,b,c){return Q(a,b,c,!0)},_removeData:function(a,b){return R(a,b,!0)}}),m.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=m.data(f),1===f.nodeType&&!m._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=m.camelCase(d.slice(5)),O(f,d,e[d])));m._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){m.data(this,a)}):arguments.length>1?this.each(function(){m.data(this,a,b)}):f?O(f,a,m.data(f,a)):void 0},removeData:function(a){return this.each(function(){m.removeData(this,a)})}}),m.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=m._data(a,b),c&&(!d||m.isArray(c)?d=m._data(a,b,m.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=m.queue(a,b),d=c.length,e=c.shift(),f=m._queueHooks(a,b),g=function(){m.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return m._data(a,c)||m._data(a,c,{empty:m.Callbacks("once memory").add(function(){m._removeData(a,b+"queue"),m._removeData(a,c)})})}}),m.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthh;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},W=/^(?:checkbox|radio)$/i;!function(){var a=y.createElement("input"),b=y.createElement("div"),c=y.createDocumentFragment();if(b.innerHTML="
a",k.leadingWhitespace=3===b.firstChild.nodeType,k.tbody=!b.getElementsByTagName("tbody").length,k.htmlSerialize=!!b.getElementsByTagName("link").length,k.html5Clone="<:nav>"!==y.createElement("nav").cloneNode(!0).outerHTML,a.type="checkbox",a.checked=!0,c.appendChild(a),k.appendChecked=a.checked,b.innerHTML="",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,c.appendChild(b),b.innerHTML="",k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,k.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){k.noCloneEvent=!1}),b.cloneNode(!0).click()),null==k.deleteExpando){k.deleteExpando=!0;try{delete b.test}catch(d){k.deleteExpando=!1}}}(),function(){var b,c,d=y.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(k[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),k[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var X=/^(?:input|select|textarea)$/i,Y=/^key/,Z=/^(?:mouse|pointer|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=/^([^.]*)(?:\.(.+)|)$/;function aa(){return!0}function ba(){return!1}function ca(){try{return y.activeElement}catch(a){}}m.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=m.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof m===K||a&&m.event.triggered===a.type?void 0:m.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(E)||[""],h=b.length;while(h--)f=_.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=m.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=m.event.special[o]||{},l=m.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&m.expr.match.needsContext.test(e),namespace:p.join(".")},i),(n=g[o])||(n=g[o]=[],n.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?n.splice(n.delegateCount++,0,l):n.push(l),m.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m.hasData(a)&&m._data(a);if(r&&(k=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=_.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=m.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,n=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=n.length;while(f--)g=n[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(n.splice(f,1),g.selector&&n.delegateCount--,l.remove&&l.remove.call(a,g));i&&!n.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||m.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)m.event.remove(a,o+b[j],c,d,!0);m.isEmptyObject(k)&&(delete r.handle,m._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,o=[d||y],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||y,3!==d.nodeType&&8!==d.nodeType&&!$.test(p+m.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[m.expando]?b:new m.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:m.makeArray(c,[b]),k=m.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!m.isWindow(d)){for(i=k.delegateType||p,$.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||y)&&o.push(l.defaultView||l.parentWindow||a)}n=0;while((h=o[n++])&&!b.isPropagationStopped())b.type=n>1?i:k.bindType||p,f=(m._data(h,"events")||{})[b.type]&&m._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&m.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&m.acceptData(d)&&g&&d[p]&&!m.isWindow(d)){l=d[g],l&&(d[g]=null),m.event.triggered=p;try{d[p]()}catch(r){}m.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=m.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(m._data(this,"events")||{})[a.type]||[],k=m.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=m.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((m.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?m(c,this).index(i)>=0:m.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h]","i"),ha=/^\s+/,ia=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,ja=/<([\w:]+)/,ka=/\s*$/g,ra={option:[1,""],legend:[1,"
","
"],area:[1,"",""],param:[1,"",""],thead:[1,"","
"],tr:[2,"","
"],col:[2,"","
"],td:[3,"","
"],_default:k.htmlSerialize?[0,"",""]:[1,"X
","
"]},sa=da(y),ta=sa.appendChild(y.createElement("div"));ra.optgroup=ra.option,ra.tbody=ra.tfoot=ra.colgroup=ra.caption=ra.thead,ra.th=ra.td;function ua(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==K?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==K?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||m.nodeName(d,b)?f.push(d):m.merge(f,ua(d,b));return void 0===b||b&&m.nodeName(a,b)?m.merge([a],f):f}function va(a){W.test(a.type)&&(a.defaultChecked=a.checked)}function wa(a,b){return m.nodeName(a,"table")&&m.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function xa(a){return a.type=(null!==m.find.attr(a,"type"))+"/"+a.type,a}function ya(a){var b=pa.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function za(a,b){for(var c,d=0;null!=(c=a[d]);d++)m._data(c,"globalEval",!b||m._data(b[d],"globalEval"))}function Aa(a,b){if(1===b.nodeType&&m.hasData(a)){var c,d,e,f=m._data(a),g=m._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)m.event.add(b,c,h[c][d])}g.data&&(g.data=m.extend({},g.data))}}function Ba(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!k.noCloneEvent&&b[m.expando]){e=m._data(b);for(d in e.events)m.removeEvent(b,d,e.handle);b.removeAttribute(m.expando)}"script"===c&&b.text!==a.text?(xa(b).text=a.text,ya(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),k.html5Clone&&a.innerHTML&&!m.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&W.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}m.extend({clone:function(a,b,c){var d,e,f,g,h,i=m.contains(a.ownerDocument,a);if(k.html5Clone||m.isXMLDoc(a)||!ga.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(ta.innerHTML=a.outerHTML,ta.removeChild(f=ta.firstChild)),!(k.noCloneEvent&&k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||m.isXMLDoc(a)))for(d=ua(f),h=ua(a),g=0;null!=(e=h[g]);++g)d[g]&&Ba(e,d[g]);if(b)if(c)for(h=h||ua(a),d=d||ua(f),g=0;null!=(e=h[g]);g++)Aa(e,d[g]);else Aa(a,f);return d=ua(f,"script"),d.length>0&&za(d,!i&&ua(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,l,n=a.length,o=da(b),p=[],q=0;n>q;q++)if(f=a[q],f||0===f)if("object"===m.type(f))m.merge(p,f.nodeType?[f]:f);else if(la.test(f)){h=h||o.appendChild(b.createElement("div")),i=(ja.exec(f)||["",""])[1].toLowerCase(),l=ra[i]||ra._default,h.innerHTML=l[1]+f.replace(ia,"<$1>")+l[2],e=l[0];while(e--)h=h.lastChild;if(!k.leadingWhitespace&&ha.test(f)&&p.push(b.createTextNode(ha.exec(f)[0])),!k.tbody){f="table"!==i||ka.test(f)?""!==l[1]||ka.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)m.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}m.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),k.appendChecked||m.grep(ua(p,"input"),va),q=0;while(f=p[q++])if((!d||-1===m.inArray(f,d))&&(g=m.contains(f.ownerDocument,f),h=ua(o.appendChild(f),"script"),g&&za(h),c)){e=0;while(f=h[e++])oa.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=m.expando,j=m.cache,l=k.deleteExpando,n=m.event.special;null!=(d=a[h]);h++)if((b||m.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)n[e]?m.event.remove(d,e):m.removeEvent(d,e,g.handle);j[f]&&(delete j[f],l?delete d[i]:typeof d.removeAttribute!==K?d.removeAttribute(i):d[i]=null,c.push(f))}}}),m.fn.extend({text:function(a){return V(this,function(a){return void 0===a?m.text(this):this.empty().append((this[0]&&this[0].ownerDocument||y).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wa(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wa(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?m.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||m.cleanData(ua(c)),c.parentNode&&(b&&m.contains(c.ownerDocument,c)&&za(ua(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&m.cleanData(ua(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&m.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return m.clone(this,a,b)})},html:function(a){return V(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(fa,""):void 0;if(!("string"!=typeof a||ma.test(a)||!k.htmlSerialize&&ga.test(a)||!k.leadingWhitespace&&ha.test(a)||ra[(ja.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(ia,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(m.cleanData(ua(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,m.cleanData(ua(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,n=this,o=l-1,p=a[0],q=m.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&na.test(p))return this.each(function(c){var d=n.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(i=m.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=m.map(ua(i,"script"),xa),f=g.length;l>j;j++)d=i,j!==o&&(d=m.clone(d,!0,!0),f&&m.merge(g,ua(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,m.map(g,ya),j=0;f>j;j++)d=g[j],oa.test(d.type||"")&&!m._data(d,"globalEval")&&m.contains(h,d)&&(d.src?m._evalUrl&&m._evalUrl(d.src):m.globalEval((d.text||d.textContent||d.innerHTML||"").replace(qa,"")));i=c=null}return this}}),m.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){m.fn[a]=function(a){for(var c,d=0,e=[],g=m(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),m(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Ca,Da={};function Ea(b,c){var d,e=m(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:m.css(e[0],"display");return e.detach(),f}function Fa(a){var b=y,c=Da[a];return c||(c=Ea(a,b),"none"!==c&&c||(Ca=(Ca||m("