Merge ~ahasenack/ubuntu/+source/python-maxminddb:focal-python-maxminddb-1.5.2-update into ubuntu/+source/python-maxminddb:ubuntu/devel

Proposed by Andreas Hasenack
Status: Merged
Approved by: Andreas Hasenack
Approved revision: 21f19875d091eecd13074ff3e7fbed52e3000507
Merge reported by: Andreas Hasenack
Merged at revision: 21f19875d091eecd13074ff3e7fbed52e3000507
Proposed branch: ~ahasenack/ubuntu/+source/python-maxminddb:focal-python-maxminddb-1.5.2-update
Merge into: ubuntu/+source/python-maxminddb:ubuntu/devel
Diff against target: 69325 lines (+16657/-798)
42 files modified
HISTORY.rst (+29/-4)
PKG-INFO (+140/-0)
README.rst (+14/-5)
debian/changelog (+16/-0)
debian/control (+3/-1)
debian/copyright (+1/-1)
debian/patches/rebuild-sphinx-docs.patch (+283/-0)
debian/patches/series (+1/-0)
debian/rules (+5/-4)
dev/null (+0/-528)
docs/html/.buildinfo (+4/-0)
docs/html/_sources/index.rst.txt (+1/-1)
docs/html/_static/basic.css (+768/-0)
docs/html/_static/doctools.js (+314/-0)
docs/html/_static/documentation_options.js (+11/-0)
docs/html/_static/jquery-3.4.1.js (+10598/-0)
docs/html/_static/jquery.js (+2/-0)
docs/html/_static/language_data.js (+297/-0)
docs/html/_static/pygments.css (+69/-0)
docs/html/_static/searchtools.js (+506/-0)
docs/html/_static/sphinxdoc.css (+345/-0)
docs/html/_static/underscore-1.3.1.js (+999/-0)
docs/html/_static/underscore.js (+31/-0)
docs/html/genindex.html (+218/-0)
docs/html/index.html (+439/-0)
docs/html/py-modindex.html (+105/-0)
docs/html/search.html (+91/-0)
docs/html/searchindex.js (+1/-0)
extension/maxminddb.c (+759/-0)
maxminddb.egg-info/PKG-INFO (+140/-0)
maxminddb.egg-info/SOURCES.txt (+74/-0)
maxminddb.egg-info/dependency_links.txt (+1/-0)
maxminddb.egg-info/top_level.txt (+1/-0)
maxminddb/__init__.py (+3/-3)
maxminddb/compat.py (+0/-3)
maxminddb/decoder.py (+64/-51)
maxminddb/file.py (+3/-5)
maxminddb/reader.py (+45/-28)
setup.cfg (+5/-1)
setup.py (+51/-61)
tests/decoder_test.py (+3/-6)
tests/reader_test.py (+217/-96)
Reviewer Review Type Date Requested Status
Christian Ehrhardt  (community) Approve
Canonical Server Pending
Review via email: mp+380854@code.launchpad.net

Description of the change

Update to version 1.5.2, going ahead of debian.

Long description because this is for a MIR. FFe bug linked.

PPA: https://launchpad.net/~ahasenack/+archive/ubuntu/python-maxminddb-update/

Long explanation for the single patch I added.

TL;DR we don't want to ship duplicates of javascript files in the doc package, like jquery, which has its own deb package already.

There are two places for upstream releases:
- https://github.com/maxmind/MaxMind-DB-Reader-python/releases: basically a git checkout
- https://pypi.org/project/maxminddb/ a trimmed down tarball, and this is where d/watch points at. This is the tarball I used.

The github tarballs lack the test files, so tests fail to run. But they have the doc source directory, which means sphinx can be used to rebuild the docs.

The pypi tarball has the sphinx docs already built, and has the test files. Looks like a winner!

The problem with sphinx docs being already built, despite making lintian unhappy, is that it means some javascript files will be shipped with the doc package, files for which we have packages in ubuntu already. Duplication. Security (potential) nightmare.

dh_sphinxdoc can be used to detect this, and replace those files with symlinks to /usr/share/javascript/**, where they are installed by their respective packages. Nice.

To do that, dh_sphinxdoc checks the md5 hash of the files in /usr/share/javascript/** and compares it to the md5 hash of the files shipped in the python-maxminddb source. For jquery, they don't match, because that tarball was generated on a system with jquery 3.4.1, and ubuntu has 3.3.1. Oops.

dh_sphinxdoc is also not happy with the built documentation, and complains about unknown javascript files, and has a bug[1] which was fixed in debian already, but not Ubuntu.

I thought it would be easier to rebuild the sphinx doc in this package than to copy over from some other git repo the binary database files used for the tests. After all, the "source" of the documentation is a simple index.rst file that is shipped in the tarball, despite the docs being pre-built.

For the other changes:
- didn't cherry-pick https://salsa.debian.org/debian/python-maxminddb/-/commit/f94b9331c12093b12ea9dfa781dc4e566ec54963 because the examples/ directory is gone from the pypi (d/watch) tarball
- lintian fix for R³
- clean up the clean (hah) d/rules override

Let's talk about lintian:
$ lintian -I --pedantic
E: python-maxminddb source: source-is-missing docs/html/_static/jquery.js line length is 32683 characters (>512)
E: python-maxminddb source: source-is-missing docs/html/_static/underscore.js line length is 519 characters (>512)
I: python-maxminddb source: out-of-date-standards-version 4.4.0 (released 2019-07-07) (current is 4.5.0)
P: python-maxminddb source: source-contains-prebuilt-javascript-object docs/html/_static/jquery.js line length is 32683 characters (>512)
P: python-maxminddb source: source-contains-prebuilt-javascript-object docs/html/_static/underscore.js line length is 519 characters (>512)
P: python-maxminddb source: source-contains-prebuilt-sphinx-documentation docs/html/
P: python-maxminddb source: very-long-line-length-in-source-file docs/html/_static/jquery.js line length is 32683 characters (>512)
P: python-maxminddb source: very-long-line-length-in-source-file docs/html/_static/underscore.js line length is 519 characters (>512)

Lintian is definitely upset with the built sphinx docs. Since we are rebuilding the docs, there isn't really much to do about the above. Perhaps the "E:" tags could be fixed by this, as suggested by lintian:

N: Please repack your package to include the source or add it to
N: "debian/missing-sources" directory.

I mean the debian/missing-sources directory. If you want me to try something about that, let me know.

1. https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=953567

To post a comment you must log in.
Revision history for this message
Christian Ehrhardt  (paelzer) wrote :

I came up with a bunch of questions on review, but re-reading the statement above answered all of them. Thanks for explaining the background and decisions taking while working on this!

Rebuilding the docs was the right choice, that way if ever someone patches the doc-src it will actually have an impact to the results - otherwise people might wonder when entertaining this.
So it is the right choice not only to silence lintian :-)

The doc build tries to access "http://docs.python.org/objects.inv" - it gladly fails and goes on. Just saying this is a dynamic we might not want to have in the build, but not a blocker for now.

I also know that mdeslaur asked for the tests to work, and I found at least those to run properly at build:
  Ran 231 tests in 3.925s

You could open a salsa MP as well (or chime in on 953567) to complete this. Just to help Debian as well as increasing the chance to later on be able to make this a sync again.

+1 overall, thanks!

review: Approve
Revision history for this message
Andreas Hasenack (ahasenack) wrote :

> I also know that mdeslaur asked for the tests to work, and I found at least those to run properly > at build:
> Ran 231 tests in 3.925s

That was for libcbor, of the openssh fido mir

Revision history for this message
Andreas Hasenack (ahasenack) wrote :

Thanks for the review. I'll upload this, so we can close the MIR, and then check with debian.

Revision history for this message
Andreas Hasenack (ahasenack) wrote :

Taggina and uploading 21f19875d091eecd13074ff3e7fbed52e3000507

$ git push pkg upload/1.5.2-0ubuntu1
Enumerating objects: 153, done.
Counting objects: 100% (153/153), done.
Delta compression using up to 4 threads
Compressing objects: 100% (102/102), done.
Writing objects: 100% (109/109), 273.36 KiB | 283.00 KiB/s, done.
Total 109 (delta 33), reused 1 (delta 0)
remote: Resolving deltas: 100% (33/33), completed with 15 local objects.
To ssh://git.launchpad.net/~usd-import-team/ubuntu/+source/python-maxminddb
 * [new tag] upload/1.5.2-0ubuntu1 -> upload/1.5.2-0ubuntu1

$ dput ubuntu ../python-maxminddb_1.5.2-0ubuntu1_source.changes
Checking signature on .changes
gpg: ../python-maxminddb_1.5.2-0ubuntu1_source.changes: Valid signature from AC983EB5BF6BCBA9
Checking signature on .dsc
gpg: ../python-maxminddb_1.5.2-0ubuntu1.dsc: Valid signature from AC983EB5BF6BCBA9
Uploading to ubuntu (via ftp to upload.ubuntu.com):
  Uploading python-maxminddb_1.5.2-0ubuntu1.dsc: done.
  Uploading python-maxminddb_1.5.2.orig.tar.gz: done.
  Uploading python-maxminddb_1.5.2-0ubuntu1.debian.tar.xz: done.
  Uploading python-maxminddb_1.5.2-0ubuntu1_source.buildinfo: done.
  Uploading python-maxminddb_1.5.2-0ubuntu1_source.changes: done.
Successfully uploaded packages.

Revision history for this message
Andreas Hasenack (ahasenack) wrote :

This migrated into focal release.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/.gitignore b/.gitignore
0deleted file mode 1006440deleted file mode 100644
index 7c72610..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,20 +0,0 @@
1*.egg
2*.iml
3*.pyc
4*.so
5*.sw?
6*~
7.coverage
8.eggs
9.idea
10build
11core
12dist
13docs/_build
14docs/html
15env/
16MANIFEST
17maxminddb.egg-info/
18pylint.txt
19valgrind-python.supp
20violations.pyflakes.txt
diff --git a/.gitmodules b/.gitmodules
21deleted file mode 1006440deleted file mode 100644
index 9cf24ec..0000000
--- a/.gitmodules
+++ /dev/null
@@ -1,3 +0,0 @@
1[submodule "tests/data"]
2 path = tests/data
3 url = git://github.com/maxmind/MaxMind-DB.git
diff --git a/.pylintrc b/.pylintrc
4deleted file mode 1006440deleted file mode 100644
index 19353df..0000000
--- a/.pylintrc
+++ /dev/null
@@ -1,6 +0,0 @@
1[MESSAGES CONTROL]
2disable=R0201,W0105
3
4[BASIC]
5
6no-docstring-rgx=_.*
diff --git a/.travis-yapf.sh b/.travis-yapf.sh
7deleted file mode 1007550deleted file mode 100755
index eb9f613..0000000
--- a/.travis-yapf.sh
+++ /dev/null
@@ -1,14 +0,0 @@
1#!/bin/bash
2
3diff=$(yapf -rd maxminddb tests)
4
5if [[ $? != 0 ]]; then
6 echo "yapf failed to run."
7 echo "$diff"
8 exit $?
9elif [[ $diff ]]; then
10 echo "$diff"
11 exit 1
12else
13 exit 0
14fi
diff --git a/.travis.yml b/.travis.yml
15deleted file mode 1006440deleted file mode 100644
index 3e8e174..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,55 +0,0 @@
1language: python
2
3python:
4 - 2.6
5 - 2.7
6 - 3.3
7 - 3.4
8 - 3.5
9 - 3.6
10 - 3.7-dev
11 - pypy
12
13before_install:
14 - git submodule update --init --recursive
15 - git clone --recursive git://github.com/maxmind/libmaxminddb
16 - cd libmaxminddb
17 - ./bootstrap
18 - ./configure
19 - make
20 - sudo make install
21 - sudo ldconfig
22 - cd ..
23 - pip install coverage coveralls
24 - if [[ $TRAVIS_PYTHON_VERSION == '3.6' ]]; then pip install pylint yapf; fi
25 - if [[ $TRAVIS_PYTHON_VERSION == '2.6' ]]; then pip install unittest2; fi
26
27script:
28 - if [[ $TRAVIS_PYTHON_VERSION != 'pypy' ]]; then export MM_FORCE_EXT_TESTS=1; fi
29 - CFLAGS="-Werror -Wall -Wextra" coverage run --source maxminddb setup.py test
30 - if [[ $TRAVIS_PYTHON_VERSION == '3.6' ]]; then pylint --rcfile .pylintrc maxminddb/*.py; fi
31 - if [[ $TRAVIS_PYTHON_VERSION == '3.6' ]]; then ./.travis-yapf.sh; fi
32
33after_success:
34 - coveralls
35
36notifications:
37 email:
38 recipients:
39 - dev-ci@maxmind.com
40 on_success: change
41 on_failure: always
42
43env:
44 global:
45 - secure: "pVcpV/al5Q607TbRzl/sbkdsx5hUjxehaJm6t5tgWrFn45icwdZrPw3JWcpt0R57NhPvXHxcJdm4WBtcGElWoDtR52QOW3yYh+gRw23y1MJg+5qHIbh5R1sOC/fLJ9TzQzvvRH5QQ5bKIe1hRQW9Cpqm7nX5Zhq6SqnAzcG1emE="
46
47addons:
48 coverity_scan:
49 project:
50 name: "maxmind/MaxMind-DB-Reader-python"
51 description: "Build submitted via Travis CI"
52 notification_email: dev-ci@maxmind.com
53 build_command_prepend: "python setup.py clean"
54 build_command: "python setup.py build"
55 branch_pattern: .*coverity.*
diff --git a/.uncrustify.cfg b/.uncrustify.cfg
56deleted file mode 1006440deleted file mode 100644
index 46b4428..0000000
--- a/.uncrustify.cfg
+++ /dev/null
@@ -1,78 +0,0 @@
1#
2# based on uncrustify config file for the linux kernel
3#
4
5code_width = 80
6indent_case_brace = 4
7indent_columns = 4
8indent_label = 2 # pos: absolute col, neg: relative column
9indent_with_tabs = 0
10
11#
12# inter-symbol newlines
13#
14nl_brace_else = remove # "} else" vs "} \n else" - cuddle else
15nl_brace_while = remove # "} while" vs "} \n while" - cuddle while
16nl_do_brace = remove # "do {" vs "do \n {"
17nl_else_brace = remove # "else {" vs "else \n {"
18nl_enum_brace = remove # "enum {" vs "enum \n {"
19nl_fcall_brace = remove # "list_for_each() {" vs "list_for_each()\n{"
20nl_fdef_brace = force # "int foo() {" vs "int foo()\n{"
21nl_for_brace = remove # "for () {" vs "for () \n {"
22nl_func_var_def_blk = 0 # don't add newlines after a block of var declarations
23nl_if_brace = remove # "if () {" vs "if () \n {"
24nl_multi_line_define = true
25nl_struct_brace = remove # "struct {" vs "struct \n {"
26nl_switch_brace = remove # "switch () {" vs "switch () \n {"
27nl_union_brace = remove # "union {" vs "union \n {"
28nl_while_brace = remove # "while () {" vs "while () \n {"
29
30
31#
32# Source code modifications
33#
34mod_full_brace_do = force # "do a--; while ();" vs "do { a--; } while ();"
35mod_full_brace_for = force # "for () a--;" vs "for () { a--; }"
36mod_full_brace_if = force # "if (a) a--;" vs "if (a) { a--; }"
37mod_full_brace_nl = 3 # don't remove if more than 3 newlines
38mod_full_brace_while = force # "while (a) a--;" vs "while (a) { a--; }"
39mod_paren_on_return = remove # "return 1;" vs "return (1);"
40
41
42#
43# inter-character spacing options
44#
45sp_after_cast = remove # "(int) a" vs "(int)a"
46sp_after_comma = force
47sp_after_sparen = force # "if () {" vs "if (){"
48sp_arith = force
49sp_assign = force
50sp_assign = force
51sp_before_comma = remove
52sp_before_ptr_star = force # "char *foo" vs "char* foo
53sp_before_sparen = force # "if (" vs "if("
54sp_between_ptr_star = remove # "char * *foo" vs "char **foo"
55sp_bool = force
56sp_compare = force
57sp_func_call_paren = remove # "foo (" vs "foo("
58sp_func_def_paren = remove # "int foo (){" vs "int foo(){"
59sp_func_proto_paren = remove # "int foo ();" vs "int foo();"
60sp_inside_braces = force # "{ 1 }" vs "{1}"
61sp_inside_braces_enum = force # "{ 1 }" vs "{1}"
62sp_inside_braces_struct = force # "{ 1 }" vs "{1}"
63sp_inside_sparen = remove
64sp_paren_brace = force
65sp_sizeof_paren = remove # "sizeof (int)" vs "sizeof(int)"
66
67#
68# Aligning stuff
69#
70align_enum_equ_span = 4 # '=' in enum definition
71align_nl_cont = true
72align_on_tabstop = FALSE # align on tabstops
73align_right_cmt_span = 3
74align_struct_init_span = 1
75align_struct_init_span = 3 # align stuff in a structure init '= { }'
76align_var_def_star_style = 2 # void *foo;
77align_var_struct_span = 0
78align_with_tabs = FALSE # use tabs to align
diff --git a/HISTORY.rst b/HISTORY.rst
index 390f5f0..5784604 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -3,6 +3,31 @@
3History3History
4-------4-------
55
61.5.2 (2019-12-20)
7++++++++++++++++++
8
9* Minor performance improvements in the pure Python reader.
10
111.5.1 (2019-09-27)
12++++++++++++++++++
13
14* Fix a possible segfault due to not correctly incrementing the reference
15 on a returned object.
16
171.5.0 (2019-09-27)
18++++++++++++++++++
19
20* Python 3.3 and 3.4 are no longer supported.
21* The extension source directory was moved to prevent an ``ImportWarning``
22 when importing the module on Python 2 with ``-Wdefault`` set. Reported by
23 David Szotten and Craig de Stigter. GitHub #31.
24* The ``get`` method now accepts ``ipaddress.IPv4Address`` and
25 ``ipaddress.IPv6Address`` objects in addition to strings. This works with
26 both the pure Python implementation as well as the extension. Based on a
27 pull request #48 by Eric Pruitt. GitHub #50.
28* A new method, ``get_with_prefix_len``, was added. This method returns a
29 tuple containing the record and the prefix length.
30
61.4.1 (2018-06-22)311.4.1 (2018-06-22)
7++++++++++++++++++32++++++++++++++++++
833
@@ -12,13 +37,13 @@ History
12++++++++++++++++++37++++++++++++++++++
1338
14* IMPORTANT: Previously, the pure Python reader would allow39* IMPORTANT: Previously, the pure Python reader would allow
15 `ipaddress.IPv4Address` and `ipaddress.IPv6Address` objects when calling40 ``ipaddress.IPv4Address`` and ``ipaddress.IPv6Address`` objects when calling
16 `.get()`. This would fail with the C extension. The fact that these objects41 ``.get()``. This would fail with the C extension. The fact that these objects
17 worked at all was an implementation detail and has varied with different42 worked at all was an implementation detail and has varied with different
18 releases. This release makes the pure Python implementation consistent43 releases. This release makes the pure Python implementation consistent
19 with the extension. A `TypeError` will now be thrown if you attempt to44 with the extension. A ``TypeError`` will now be thrown if you attempt to
20 use these types with either the pure Python implementation or the45 use these types with either the pure Python implementation or the
21 extension. The IP address passed to `.get()` should be a string type.46 extension. The IP address passed to ``.get()`` should be a string type.
22* Fix issue where incorrect size was used when unpacking some types with the47* Fix issue where incorrect size was used when unpacking some types with the
23 pure Python reader. Reported by Lee Symes. GitHub #30.48 pure Python reader. Reported by Lee Symes. GitHub #30.
24* You may now pass in the database via a file descriptor rather than a file49* You may now pass in the database via a file descriptor rather than a file
diff --git a/PKG-INFO b/PKG-INFO
25new file mode 10064450new file mode 100644
index 0000000..1a961e9
--- /dev/null
+++ b/PKG-INFO
@@ -0,0 +1,140 @@
1Metadata-Version: 1.2
2Name: maxminddb
3Version: 1.5.2
4Summary: Reader for the MaxMind DB format
5Home-page: http://www.maxmind.com/
6Author: Gregory Oschwald
7Author-email: goschwald@maxmind.com
8License: Apache License, Version 2.0
9Description: ========================
10 MaxMind DB Python Module
11 ========================
12
13 Description
14 -----------
15
16 This is a Python module for reading MaxMind DB files. The module includes both
17 a pure Python reader and an optional C extension.
18
19 MaxMind DB is a binary file format that stores data indexed by IP address
20 subnets (IPv4 or IPv6).
21
22 Installation
23 ------------
24
25 If you want to use the C extension, you must first install `libmaxminddb
26 <https://github.com/maxmind/libmaxminddb>`_ C library installed before
27 installing this extension. If the library is not available, the module will
28 fall-back to a pure Python implementation.
29
30 To install maxminddb, type:
31
32 .. code-block:: bash
33
34 $ pip install maxminddb
35
36 If you are not able to use pip, you may also use easy_install from the
37 source directory:
38
39 .. code-block:: bash
40
41 $ easy_install .
42
43 Usage
44 -----
45
46 To use this module, you must first download or create a MaxMind DB file. We
47 provide `free GeoLite2 databases
48 <https://dev.maxmind.com/geoip/geoip2/geolite2>`_. These files must be
49 decompressed with ``gunzip``.
50
51 After you have obtained a database and imported the module, call
52 ``open_database`` with a path, or file descriptor (in the case of MODE_FD),
53 to the database as the first argument. Optionally, you may pass a mode as the
54 second argument. The modes are exported from ``maxminddb``. Valid modes are:
55
56 * MODE_MMAP_EXT - use the C extension with memory map.
57 * MODE_MMAP - read from memory map. Pure Python.
58 * MODE_FILE - read database as standard file. Pure Python.
59 * MODE_MEMORY - load database into memory. Pure Python.
60 * MODE_FD - load database into memory from a file descriptor. Pure Python.
61 * MODE_AUTO - try MODE_MMAP_EXT, MODE_MMAP, MODE_FILE in that order. Default.
62
63 **NOTE**: When using ``MODE_FD``, it is the *caller's* responsibility to be
64 sure that the file descriptor gets closed properly. The caller may close the
65 file descriptor immediately after the ``Reader`` object is created.
66
67 The ``open_database`` function returns a ``Reader`` object. To look up an IP
68 address, use the ``get`` method on this object. The method will return the
69 corresponding values for the IP address from the database (e.g., a dictionary
70 for GeoIP2/GeoLite2 databases). If the database does not contain a record for
71 that IP address, the method will return ``None``.
72
73 If you wish to also retrieve the prefix length for the record, use the
74 ``get_with_prefix_len`` method. This returns a tuple containing the record
75 followed by the network prefix length associated with the record.
76
77 Example
78 -------
79
80 .. code-block:: pycon
81
82 >>> import maxminddb
83 >>>
84 >>> reader = maxminddb.open_database('GeoLite2-City.mmdb')
85 >>>
86 >>> reader.get('1.1.1.1')
87 {'country': ... }
88 >>>
89 >>> reader.get_with_prefix_len('1.1.1.1')
90 ({'country': ... }, 24)
91 >>>
92 >>> reader.close()
93
94 Exceptions
95 ----------
96
97 The module will return an ``InvalidDatabaseError`` if the database is corrupt
98 or otherwise invalid. A ``ValueError`` will be thrown if you look up an
99 invalid IP address or an IPv6 address in an IPv4 database.
100
101 Requirements
102 ------------
103
104 This code requires Python 2.7+ or 3.5+. Older versions are not supported. The C
105 extension requires CPython. The pure Python implementation has been tested with
106 PyPy.
107
108 On Python 2, the `ipaddress module <https://pypi.python.org/pypi/ipaddress>`_ is
109 required.
110
111 Versioning
112 ----------
113
114 The MaxMind DB Python module uses `Semantic Versioning <https://semver.org/>`_.
115
116 Support
117 -------
118
119 Please report all issues with this code using the `GitHub issue tracker
120 <https://github.com/maxmind/MaxMind-DB-Reader-python/issues>`_
121
122 If you are having an issue with a MaxMind service that is not specific to this
123 API, please contact `MaxMind support <https://www.maxmind.com/en/support>`_ for
124 assistance.
125
126Platform: UNKNOWN
127Classifier: Development Status :: 5 - Production/Stable
128Classifier: Environment :: Web Environment
129Classifier: Intended Audience :: Developers
130Classifier: Intended Audience :: System Administrators
131Classifier: License :: OSI Approved :: Apache Software License
132Classifier: Programming Language :: Python :: 2.7
133Classifier: Programming Language :: Python :: 3
134Classifier: Programming Language :: Python :: 3.5
135Classifier: Programming Language :: Python :: 3.6
136Classifier: Programming Language :: Python :: 3.7
137Classifier: Programming Language :: Python
138Classifier: Topic :: Internet :: Proxy Servers
139Classifier: Topic :: Internet
140Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*
diff --git a/README.rst b/README.rst
index aa2eaab..e905493 100644
--- a/README.rst
+++ b/README.rst
@@ -37,7 +37,7 @@ Usage
3737
38To use this module, you must first download or create a MaxMind DB file. We38To use this module, you must first download or create a MaxMind DB file. We
39provide `free GeoLite2 databases39provide `free GeoLite2 databases
40<http://dev.maxmind.com/geoip/geoip2/geolite2>`_. These files must be40<https://dev.maxmind.com/geoip/geoip2/geolite2>`_. These files must be
41decompressed with ``gunzip``.41decompressed with ``gunzip``.
4242
43After you have obtained a database and imported the module, call43After you have obtained a database and imported the module, call
@@ -62,6 +62,10 @@ corresponding values for the IP address from the database (e.g., a dictionary
62for GeoIP2/GeoLite2 databases). If the database does not contain a record for62for GeoIP2/GeoLite2 databases). If the database does not contain a record for
63that IP address, the method will return ``None``.63that IP address, the method will return ``None``.
6464
65If you wish to also retrieve the prefix length for the record, use the
66``get_with_prefix_len`` method. This returns a tuple containing the record
67followed by the network prefix length associated with the record.
68
65Example69Example
66-------70-------
6771
@@ -70,9 +74,13 @@ Example
70 >>> import maxminddb74 >>> import maxminddb
71 >>>75 >>>
72 >>> reader = maxminddb.open_database('GeoLite2-City.mmdb')76 >>> reader = maxminddb.open_database('GeoLite2-City.mmdb')
77 >>>
73 >>> reader.get('1.1.1.1')78 >>> reader.get('1.1.1.1')
74 {'country': ... }79 {'country': ... }
75 >>>80 >>>
81 >>> reader.get_with_prefix_len('1.1.1.1')
82 ({'country': ... }, 24)
83 >>>
76 >>> reader.close()84 >>> reader.close()
7785
78Exceptions86Exceptions
@@ -85,8 +93,9 @@ invalid IP address or an IPv6 address in an IPv4 database.
85Requirements93Requirements
86------------94------------
8795
88This code requires Python 2.6+ or 3.3+. The C extension requires CPython. The96This code requires Python 2.7+ or 3.5+. Older versions are not supported. The C
89pure Python implementation has been tested with PyPy.97extension requires CPython. The pure Python implementation has been tested with
98PyPy.
9099
91On Python 2, the `ipaddress module <https://pypi.python.org/pypi/ipaddress>`_ is100On Python 2, the `ipaddress module <https://pypi.python.org/pypi/ipaddress>`_ is
92required.101required.
@@ -94,7 +103,7 @@ required.
94Versioning103Versioning
95----------104----------
96105
97The MaxMind DB Python module uses `Semantic Versioning <http://semver.org/>`_.106The MaxMind DB Python module uses `Semantic Versioning <https://semver.org/>`_.
98107
99Support108Support
100-------109-------
@@ -103,5 +112,5 @@ Please report all issues with this code using the `GitHub issue tracker
103<https://github.com/maxmind/MaxMind-DB-Reader-python/issues>`_112<https://github.com/maxmind/MaxMind-DB-Reader-python/issues>`_
104113
105If you are having an issue with a MaxMind service that is not specific to this114If you are having an issue with a MaxMind service that is not specific to this
106API, please contact `MaxMind support <http://www.maxmind.com/en/support>`_ for115API, please contact `MaxMind support <https://www.maxmind.com/en/support>`_ for
107assistance.116assistance.
diff --git a/debian/changelog b/debian/changelog
index ff5ce3d..d333eda 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,19 @@
1python-maxminddb (1.5.2-0ubuntu1) focal; urgency=medium
2
3 * New upstream release: 1.5.2 (LP: #1867919)
4 * Rebuild sphinx docs to avoid shipping other copies of several
5 javascript files, like jquery.js, in the doc package:
6 - d/p/rebuild-sphinx-docs.patch: pull in upstream's sphinx-build conf.py
7 - d/rules: use docs-source for building docs
8 - d/rules: remove the index.rst file from docs-source during clean
9 * d/control: add Rules-Requires-Root: no
10 * d/rules: update dh_auto_clean override
11
12 [ Faidon Liambotis]
13 * d/copyright: Switch the copyright format URI to https
14
15 -- Andreas Hasenack <andreas@canonical.com> Wed, 18 Mar 2020 17:57:58 -0300
16
1python-maxminddb (1.4.1-2build2) focal; urgency=medium17python-maxminddb (1.4.1-2build2) focal; urgency=medium
218
3 * No-change rebuild to drop python3.7.19 * No-change rebuild to drop python3.7.
diff --git a/debian/control b/debian/control
index 390ce71..1c9fa11 100644
--- a/debian/control
+++ b/debian/control
@@ -1,5 +1,6 @@
1Source: python-maxminddb1Source: python-maxminddb
2Maintainer: Faidon Liambotis <paravoid@debian.org>2Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
3XSBC-Original-Maintainer: Faidon Liambotis <paravoid@debian.org>
3Section: python4Section: python
4Priority: optional5Priority: optional
5Build-Depends:6Build-Depends:
@@ -17,6 +18,7 @@ Homepage: https://github.com/maxmind/MaxMind-DB-Reader-python
17Vcs-Browser: https://salsa.debian.org/debian/python-maxminddb18Vcs-Browser: https://salsa.debian.org/debian/python-maxminddb
18Vcs-Git: https://salsa.debian.org/debian/python-maxminddb.git19Vcs-Git: https://salsa.debian.org/debian/python-maxminddb.git
19Testsuite: autopkgtest-pkg-python20Testsuite: autopkgtest-pkg-python
21Rules-Requires-Root: no
2022
21Package: python3-maxminddb23Package: python3-maxminddb
22Architecture: any24Architecture: any
diff --git a/debian/copyright b/debian/copyright
index 7d6c0ba..365443a 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -1,4 +1,4 @@
1Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/1Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
2Upstream-Name: MaxMind-DB-Reader-python2Upstream-Name: MaxMind-DB-Reader-python
3Source: https://github.com/maxmind/MaxMind-DB-Reader-python3Source: https://github.com/maxmind/MaxMind-DB-Reader-python
44
diff --git a/debian/patches/rebuild-sphinx-docs.patch b/debian/patches/rebuild-sphinx-docs.patch
5new file mode 1006445new file mode 100644
index 0000000..bbce8e6
--- /dev/null
+++ b/debian/patches/rebuild-sphinx-docs.patch
@@ -0,0 +1,283 @@
1Description: Allow rebuilding the docs with sphinx
2 The upstream tarball at https://pypi.org/project/maxminddb/ has the sphinx
3 docs already built, but using jquery 3.4.1. Since Ubuntu has 3.3.1 at this
4 time, dh_sphinxdoc won't symlink the jquery.js file to the sphinx copy in
5 /usr/share/javascript/sphinxdoc/1.0/jquery.js, which will result in us
6 shipping another jquery.js file in a debian package.
7 .
8 The easiest solution is to rebuild the docs at package build time, but that
9 upstream tarball does not have the conf.py file needed by sphinx-build. That
10 is available in the upstream git repo at
11 https://github.com/maxmind/MaxMind-DB-Reader-python/blob/master/docs/conf.py
12 or in the github tarball releases at
13 https://github.com/maxmind/MaxMind-DB-Reader-python/releases
14 .
15 The github tarball release, on the other hand, do not have the datafiles used
16 for the tests: they come from another remote (see the "data" directory in
17 https://github.com/maxmind/MaxMind-DB-Reader-python/tree/master/tests). If we
18 use the github tarball releases, we don't get to run the tests.
19 .
20 I believe the simplest solution is to copy over the docs/conf.py file from the
21 github 1.5.2 release tarball, and this is what this patch does:
22 .
23 https://github.com/maxmind/MaxMind-DB-Reader-python/archive/v1.5.2.tar.gz
24 SHA256: d60742040d99cbe75ca049dc901b57867b4ff07df7058af640768d51d92a82a3
25Author: Andreas Hasenack <andreas@canonical.com)
26Forwarded: not-needed
27Last-Update: 2020-03-18
28---
29This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
30diff --git a/docs-source/conf.py b/docs-source/conf.py
31new file mode 100644
32index 0000000..f0ae2c9
33--- /dev/null
34+++ b/docs-source/conf.py
35@@ -0,0 +1,248 @@
36+#!/usr/bin/env python3
37+# -*- coding: utf-8 -*-
38+#
39+# maxminddb documentation build configuration file, created by
40+# sphinx-quickstart on Tue Apr 9 13:34:57 2013.
41+#
42+# This file is execfile()d with the current directory set to its containing dir.
43+#
44+# Note that not all possible configuration values are present in this
45+# autogenerated file.
46+#
47+# All configuration values have a default; values that are commented out
48+# serve to show the default.
49+
50+import sys
51+import os
52+
53+sys.path.insert(0, os.path.abspath('..'))
54+import maxminddb
55+
56+__version__ = maxminddb.__version__
57+
58+# If extensions (or modules to document with autodoc) are in another directory,
59+# add these directories to sys.path here. If the directory is relative to the
60+# documentation root, use os.path.abspath to make it absolute, like shown here.
61+sys.path.insert(0, os.path.abspath('..'))
62+
63+# -- General configuration -----------------------------------------------
64+
65+# If your documentation needs a minimal Sphinx version, state it here.
66+#needs_sphinx = '1.0'
67+
68+# Add any Sphinx extension module names here, as strings. They can be extensions
69+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
70+extensions = [
71+ 'sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.intersphinx',
72+ 'sphinx.ext.coverage'
73+]
74+
75+# Add any paths that contain templates here, relative to this directory.
76+templates_path = ['_templates']
77+
78+# The suffix of source filenames.
79+source_suffix = '.rst'
80+
81+# The encoding of source files.
82+#source_encoding = 'utf-8-sig'
83+
84+# The master toctree document.
85+master_doc = 'index'
86+
87+# General information about the project.
88+project = 'maxminddb'
89+copyright = '2013-2019, MaxMind, Inc.'
90+
91+# The version info for the project you're documenting, acts as replacement for
92+# |version| and |release|, also used in various other places throughout the
93+# built documents.
94+#
95+# The short X.Y version.
96+version = __version__
97+# The full version, including alpha/beta/rc tags.
98+release = __version__
99+
100+# The language for content autogenerated by Sphinx. Refer to documentation
101+# for a list of supported languages.
102+#language = None
103+
104+# There are two options for replacing |today|: either, you set today to some
105+# non-false value, then it is used:
106+#today = ''
107+# Else, today_fmt is used as the format for a strftime call.
108+#today_fmt = '%B %d, %Y'
109+
110+# List of patterns, relative to source directory, that match files and
111+# directories to ignore when looking for source files.
112+exclude_patterns = ['_build']
113+
114+# The reST default role (used for this markup: `text`) to use for all documents.
115+#default_role = None
116+
117+# If true, '()' will be appended to :func: etc. cross-reference text.
118+#add_function_parentheses = True
119+
120+# If true, the current module name will be prepended to all description
121+# unit titles (such as .. function::).
122+#add_module_names = True
123+
124+# If true, sectionauthor and moduleauthor directives will be shown in the
125+# output. They are ignored by default.
126+#show_authors = False
127+
128+# The name of the Pygments (syntax highlighting) style to use.
129+pygments_style = 'sphinx'
130+
131+# A list of ignored prefixes for module index sorting.
132+#modindex_common_prefix = []
133+
134+# -- Options for HTML output ---------------------------------------------
135+
136+# The theme to use for HTML and HTML Help pages. See the documentation for
137+# a list of builtin themes.
138+html_theme = 'sphinxdoc'
139+
140+# Theme options are theme-specific and customize the look and feel of a theme
141+# further. For a list of options available for each theme, see the
142+# documentation.
143+#html_theme_options = {}
144+
145+# Add any paths that contain custom themes here, relative to this directory.
146+#html_theme_path = []
147+
148+# The name for this set of Sphinx documents. If None, it defaults to
149+# "<project> v<release> documentation".
150+#html_title = None
151+
152+# A shorter title for the navigation bar. Default is the same as html_title.
153+#html_short_title = None
154+
155+# The name of an image file (relative to this directory) to place at the top
156+# of the sidebar.
157+#html_logo = None
158+
159+# The name of an image file (within the static path) to use as favicon of the
160+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
161+# pixels large.
162+#html_favicon = None
163+
164+# Add any paths that contain custom static files (such as style sheets) here,
165+# relative to this directory. They are copied after the builtin static files,
166+# so a file named "default.css" will overwrite the builtin "default.css".
167+html_static_path = ['_static']
168+
169+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
170+# using the given strftime format.
171+#html_last_updated_fmt = '%b %d, %Y'
172+
173+# If true, SmartyPants will be used to convert quotes and dashes to
174+# typographically correct entities.
175+#html_use_smartypants = True
176+
177+# Custom sidebar templates, maps document names to template names.
178+#html_sidebars = {}
179+
180+# Additional templates that should be rendered to pages, maps page names to
181+# template names.
182+#html_additional_pages = {}
183+
184+# If false, no module index is generated.
185+#html_domain_indices = True
186+
187+# If false, no index is generated.
188+#html_use_index = True
189+
190+# If true, the index is split into individual pages for each letter.
191+#html_split_index = False
192+
193+# If true, links to the reST sources are added to the pages.
194+#html_show_sourcelink = True
195+
196+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
197+#html_show_sphinx = True
198+
199+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
200+#html_show_copyright = True
201+
202+# If true, an OpenSearch description file will be output, and all pages will
203+# contain a <link> tag referring to it. The value of this option must be the
204+# base URL from which the finished HTML is served.
205+#html_use_opensearch = ''
206+
207+# This is the file name suffix for HTML files (e.g. ".xhtml").
208+#html_file_suffix = None
209+
210+# Output file base name for HTML help builder.
211+htmlhelp_basename = 'maxminddbdoc'
212+
213+# -- Options for LaTeX output --------------------------------------------
214+
215+latex_elements = {
216+ # The paper size ('letterpaper' or 'a4paper').
217+ #'papersize': 'letterpaper',
218+
219+ # The font size ('10pt', '11pt' or '12pt').
220+ #'pointsize': '10pt',
221+
222+ # Additional stuff for the LaTeX preamble.
223+ #'preamble': '',
224+}
225+
226+# Grouping the document tree into LaTeX files. List of tuples
227+# (source start file, target name, title, author, documentclass [howto/manual]).
228+latex_documents = [
229+ ('index', 'maxminddb.tex', 'maxminddb Documentation', 'Gregory Oschwald',
230+ 'manual'),
231+]
232+
233+# The name of an image file (relative to this directory) to place at the top of
234+# the title page.
235+#latex_logo = None
236+
237+# For "manual" documents, if this is true, then toplevel headings are parts,
238+# not chapters.
239+#latex_use_parts = False
240+
241+# If true, show page references after internal links.
242+#latex_show_pagerefs = False
243+
244+# If true, show URL addresses after external links.
245+#latex_show_urls = False
246+
247+# Documents to append as an appendix to all manuals.
248+#latex_appendices = []
249+
250+# If false, no module index is generated.
251+#latex_domain_indices = True
252+
253+# -- Options for manual page output --------------------------------------
254+
255+# One entry per manual page. List of tuples
256+# (source start file, name, description, authors, manual section).
257+man_pages = [('index', 'maxminddb', 'maxminddb Documentation',
258+ ['Gregory Oschwald'], 1)]
259+
260+# If true, show URL addresses after external links.
261+#man_show_urls = False
262+
263+# -- Options for Texinfo output ------------------------------------------
264+
265+# Grouping the document tree into Texinfo files. List of tuples
266+# (source start file, target name, title, author,
267+# dir menu entry, description, category)
268+texinfo_documents = [
269+ ('index', 'maxminddb', 'maxminddb Documentation', 'Gregory Oschwald',
270+ 'maxminddb', 'MaxMind DB Reader', 'Miscellaneous'),
271+]
272+
273+# Documents to append as an appendix to all manuals.
274+#texinfo_appendices = []
275+
276+# If false, no module index is generated.
277+#texinfo_domain_indices = True
278+
279+# How to display URL addresses: 'footnote', 'no', or 'inline'.
280+#texinfo_show_urls = 'footnote'
281+
282+# Example configuration for intersphinx: refer to the Python standard library.
283+intersphinx_mapping = {'http://docs.python.org/': None}
diff --git a/debian/patches/series b/debian/patches/series
0new file mode 100644284new file mode 100644
index 0000000..f8a9263
--- /dev/null
+++ b/debian/patches/series
@@ -0,0 +1 @@
1rebuild-sphinx-docs.patch
diff --git a/debian/rules b/debian/rules
index 3774142..ac48e30 100755
--- a/debian/rules
+++ b/debian/rules
@@ -7,13 +7,14 @@ export PYBUILD_NAME=maxminddb
7 dh $@ --with python3,sphinxdoc --buildsystem=pybuild7 dh $@ --with python3,sphinxdoc --buildsystem=pybuild
88
9override_dh_auto_build:9override_dh_auto_build:
10 PYTHONPATH=.:$$PYTHONPATH sphinx-build -b html -d .build/.doctrees -N docs .build/html10 cp docs/html/_sources/index.rst.txt docs-source/index.rst
11 PYTHONPATH=.:$$PYTHONPATH sphinx-build -b html -d .build/.doctrees -N docs-source .build/html
11 dh_auto_build12 dh_auto_build
1213
13override_dh_auto_clean:14override_dh_auto_clean:
14 dh_auto_clean15 dh_auto_clean --buildsystem=pybuild
15 rm -f maxminddb/extension.so maxminddb/extension.*.so16 rm -rf .build/
16 rm -rf .build/ maxminddb.egg-info/17 rm -f docs-source/index.rst
1718
18override_dh_auto_test:19override_dh_auto_test:
19 dh_auto_test -- --before-test "ln -sf {dir}/README.rst {build_dir}/" \20 dh_auto_test -- --before-test "ln -sf {dir}/README.rst {build_dir}/" \
diff --git a/dev-bin/release.sh b/dev-bin/release.sh
20deleted file mode 10075521deleted file mode 100755
index bd0060a..0000000
--- a/dev-bin/release.sh
+++ /dev/null
@@ -1,66 +0,0 @@
1#!/bin/bash
2
3set -eu -o pipefail
4
5changelog=$(cat HISTORY.rst)
6
7regex='
8([0-9]+\.[0-9]+\.[0-9]+) \(([0-9]{4}-[0-9]{2}-[0-9]{2})\)
9\+*
10
11((.|
12)*)
13'
14
15if [[ ! $changelog =~ $regex ]]; then
16 echo "Could not find date line in change log!"
17 exit 1
18fi
19
20version="${BASH_REMATCH[1]}"
21date="${BASH_REMATCH[2]}"
22notes="$(echo "${BASH_REMATCH[3]}" | sed -n -e '/^[0-9]\+\.[0-9]\+\.[0-9]\+/,$!p')"
23
24if [[ "$date" -ne $(date +"%Y-%m-%d") ]]; then
25 echo "$date is not today!"
26 exit 1
27fi
28
29tag="v$version"
30
31if [ -n "$(git status --porcelain)" ]; then
32 echo ". is not clean." >&2
33 exit 1
34fi
35
36perl -pi -e "s/(?<=__version__ = ').+?(?=')/$version/gsm" maxminddb/__init__.py
37
38echo $"Test results:"
39python setup.py test
40
41echo $'\nDiff:'
42git diff
43
44echo $'\nRelease notes:'
45echo "$notes"
46
47read -e -p "Commit changes and push to origin? " should_push
48
49if [ "$should_push" != "y" ]; then
50 echo "Aborting"
51 exit 1
52fi
53
54git commit -m "Update for $tag" -a
55
56git push
57
58message="$version
59
60$notes"
61
62hub release create -m "$message" "$tag"
63
64git push --tags
65
66python setup.py release
diff --git a/docs/Makefile b/docs/Makefile
67deleted file mode 1006440deleted file mode 100644
index 316a75a..0000000
--- a/docs/Makefile
+++ /dev/null
@@ -1,153 +0,0 @@
1# Makefile for Sphinx documentation
2#
3
4# You can set these variables from the command line.
5SPHINXOPTS =
6SPHINXBUILD = sphinx-build
7PAPER =
8BUILDDIR = _build
9
10# Internal variables.
11PAPEROPT_a4 = -D latex_paper_size=a4
12PAPEROPT_letter = -D latex_paper_size=letter
13ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
14# the i18n builder cannot share the environment and doctrees with the others
15I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
16
17.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
18
19help:
20 @echo "Please use \`make <target>' where <target> is one of"
21 @echo " html to make standalone HTML files"
22 @echo " dirhtml to make HTML files named index.html in directories"
23 @echo " singlehtml to make a single large HTML file"
24 @echo " pickle to make pickle files"
25 @echo " json to make JSON files"
26 @echo " htmlhelp to make HTML files and a HTML help project"
27 @echo " qthelp to make HTML files and a qthelp project"
28 @echo " devhelp to make HTML files and a Devhelp project"
29 @echo " epub to make an epub"
30 @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
31 @echo " latexpdf to make LaTeX files and run them through pdflatex"
32 @echo " text to make text files"
33 @echo " man to make manual pages"
34 @echo " texinfo to make Texinfo files"
35 @echo " info to make Texinfo files and run them through makeinfo"
36 @echo " gettext to make PO message catalogs"
37 @echo " changes to make an overview of all changed/added/deprecated items"
38 @echo " linkcheck to check all external links for integrity"
39 @echo " doctest to run all doctests embedded in the documentation (if enabled)"
40
41clean:
42 -rm -rf $(BUILDDIR)/*
43
44html:
45 $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
46 @echo
47 @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
48
49dirhtml:
50 $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
51 @echo
52 @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
53
54singlehtml:
55 $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
56 @echo
57 @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
58
59pickle:
60 $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
61 @echo
62 @echo "Build finished; now you can process the pickle files."
63
64json:
65 $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
66 @echo
67 @echo "Build finished; now you can process the JSON files."
68
69htmlhelp:
70 $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
71 @echo
72 @echo "Build finished; now you can run HTML Help Workshop with the" \
73 ".hhp project file in $(BUILDDIR)/htmlhelp."
74
75qthelp:
76 $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
77 @echo
78 @echo "Build finished; now you can run "qcollectiongenerator" with the" \
79 ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
80 @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/maxminddb.qhcp"
81 @echo "To view the help file:"
82 @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/maxminddb.qhc"
83
84devhelp:
85 $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
86 @echo
87 @echo "Build finished."
88 @echo "To view the help file:"
89 @echo "# mkdir -p $$HOME/.local/share/devhelp/maxminddb"
90 @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/maxminddb"
91 @echo "# devhelp"
92
93epub:
94 $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
95 @echo
96 @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
97
98latex:
99 $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
100 @echo
101 @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
102 @echo "Run \`make' in that directory to run these through (pdf)latex" \
103 "(use \`make latexpdf' here to do that automatically)."
104
105latexpdf:
106 $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
107 @echo "Running LaTeX files through pdflatex..."
108 $(MAKE) -C $(BUILDDIR)/latex all-pdf
109 @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
110
111text:
112 $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
113 @echo
114 @echo "Build finished. The text files are in $(BUILDDIR)/text."
115
116man:
117 $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
118 @echo
119 @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
120
121texinfo:
122 $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
123 @echo
124 @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
125 @echo "Run \`make' in that directory to run these through makeinfo" \
126 "(use \`make info' here to do that automatically)."
127
128info:
129 $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
130 @echo "Running Texinfo files through makeinfo..."
131 make -C $(BUILDDIR)/texinfo info
132 @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
133
134gettext:
135 $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
136 @echo
137 @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
138
139changes:
140 $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
141 @echo
142 @echo "The overview file is in $(BUILDDIR)/changes."
143
144linkcheck:
145 $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
146 @echo
147 @echo "Link check complete; look for any errors in the above output " \
148 "or in $(BUILDDIR)/linkcheck/output.txt."
149
150doctest:
151 $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
152 @echo "Testing of doctests in the sources finished, look at the " \
153 "results in $(BUILDDIR)/doctest/output.txt."
diff --git a/docs/conf.py b/docs/conf.py
154deleted file mode 1006440deleted file mode 100644
index 9b107b4..0000000
--- a/docs/conf.py
+++ /dev/null
@@ -1,248 +0,0 @@
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3#
4# maxminddb documentation build configuration file, created by
5# sphinx-quickstart on Tue Apr 9 13:34:57 2013.
6#
7# This file is execfile()d with the current directory set to its containing dir.
8#
9# Note that not all possible configuration values are present in this
10# autogenerated file.
11#
12# All configuration values have a default; values that are commented out
13# serve to show the default.
14
15import sys
16import os
17
18sys.path.insert(0, os.path.abspath('..'))
19import maxminddb
20
21__version__ = maxminddb.__version__
22
23# If extensions (or modules to document with autodoc) are in another directory,
24# add these directories to sys.path here. If the directory is relative to the
25# documentation root, use os.path.abspath to make it absolute, like shown here.
26sys.path.insert(0, os.path.abspath('..'))
27
28# -- General configuration -----------------------------------------------
29
30# If your documentation needs a minimal Sphinx version, state it here.
31#needs_sphinx = '1.0'
32
33# Add any Sphinx extension module names here, as strings. They can be extensions
34# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
35extensions = [
36 'sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.intersphinx',
37 'sphinx.ext.coverage'
38]
39
40# Add any paths that contain templates here, relative to this directory.
41templates_path = ['_templates']
42
43# The suffix of source filenames.
44source_suffix = '.rst'
45
46# The encoding of source files.
47#source_encoding = 'utf-8-sig'
48
49# The master toctree document.
50master_doc = 'index'
51
52# General information about the project.
53project = 'maxminddb'
54copyright = '2013-2018, MaxMind, Inc.'
55
56# The version info for the project you're documenting, acts as replacement for
57# |version| and |release|, also used in various other places throughout the
58# built documents.
59#
60# The short X.Y version.
61version = __version__
62# The full version, including alpha/beta/rc tags.
63release = __version__
64
65# The language for content autogenerated by Sphinx. Refer to documentation
66# for a list of supported languages.
67#language = None
68
69# There are two options for replacing |today|: either, you set today to some
70# non-false value, then it is used:
71#today = ''
72# Else, today_fmt is used as the format for a strftime call.
73#today_fmt = '%B %d, %Y'
74
75# List of patterns, relative to source directory, that match files and
76# directories to ignore when looking for source files.
77exclude_patterns = ['_build']
78
79# The reST default role (used for this markup: `text`) to use for all documents.
80#default_role = None
81
82# If true, '()' will be appended to :func: etc. cross-reference text.
83#add_function_parentheses = True
84
85# If true, the current module name will be prepended to all description
86# unit titles (such as .. function::).
87#add_module_names = True
88
89# If true, sectionauthor and moduleauthor directives will be shown in the
90# output. They are ignored by default.
91#show_authors = False
92
93# The name of the Pygments (syntax highlighting) style to use.
94pygments_style = 'sphinx'
95
96# A list of ignored prefixes for module index sorting.
97#modindex_common_prefix = []
98
99# -- Options for HTML output ---------------------------------------------
100
101# The theme to use for HTML and HTML Help pages. See the documentation for
102# a list of builtin themes.
103html_theme = 'sphinxdoc'
104
105# Theme options are theme-specific and customize the look and feel of a theme
106# further. For a list of options available for each theme, see the
107# documentation.
108#html_theme_options = {}
109
110# Add any paths that contain custom themes here, relative to this directory.
111#html_theme_path = []
112
113# The name for this set of Sphinx documents. If None, it defaults to
114# "<project> v<release> documentation".
115#html_title = None
116
117# A shorter title for the navigation bar. Default is the same as html_title.
118#html_short_title = None
119
120# The name of an image file (relative to this directory) to place at the top
121# of the sidebar.
122#html_logo = None
123
124# The name of an image file (within the static path) to use as favicon of the
125# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
126# pixels large.
127#html_favicon = None
128
129# Add any paths that contain custom static files (such as style sheets) here,
130# relative to this directory. They are copied after the builtin static files,
131# so a file named "default.css" will overwrite the builtin "default.css".
132html_static_path = ['_static']
133
134# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
135# using the given strftime format.
136#html_last_updated_fmt = '%b %d, %Y'
137
138# If true, SmartyPants will be used to convert quotes and dashes to
139# typographically correct entities.
140#html_use_smartypants = True
141
142# Custom sidebar templates, maps document names to template names.
143#html_sidebars = {}
144
145# Additional templates that should be rendered to pages, maps page names to
146# template names.
147#html_additional_pages = {}
148
149# If false, no module index is generated.
150#html_domain_indices = True
151
152# If false, no index is generated.
153#html_use_index = True
154
155# If true, the index is split into individual pages for each letter.
156#html_split_index = False
157
158# If true, links to the reST sources are added to the pages.
159#html_show_sourcelink = True
160
161# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
162#html_show_sphinx = True
163
164# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
165#html_show_copyright = True
166
167# If true, an OpenSearch description file will be output, and all pages will
168# contain a <link> tag referring to it. The value of this option must be the
169# base URL from which the finished HTML is served.
170#html_use_opensearch = ''
171
172# This is the file name suffix for HTML files (e.g. ".xhtml").
173#html_file_suffix = None
174
175# Output file base name for HTML help builder.
176htmlhelp_basename = 'maxminddbdoc'
177
178# -- Options for LaTeX output --------------------------------------------
179
180latex_elements = {
181 # The paper size ('letterpaper' or 'a4paper').
182 #'papersize': 'letterpaper',
183
184 # The font size ('10pt', '11pt' or '12pt').
185 #'pointsize': '10pt',
186
187 # Additional stuff for the LaTeX preamble.
188 #'preamble': '',
189}
190
191# Grouping the document tree into LaTeX files. List of tuples
192# (source start file, target name, title, author, documentclass [howto/manual]).
193latex_documents = [
194 ('index', 'maxminddb.tex', 'maxminddb Documentation', 'Gregory Oschwald',
195 'manual'),
196]
197
198# The name of an image file (relative to this directory) to place at the top of
199# the title page.
200#latex_logo = None
201
202# For "manual" documents, if this is true, then toplevel headings are parts,
203# not chapters.
204#latex_use_parts = False
205
206# If true, show page references after internal links.
207#latex_show_pagerefs = False
208
209# If true, show URL addresses after external links.
210#latex_show_urls = False
211
212# Documents to append as an appendix to all manuals.
213#latex_appendices = []
214
215# If false, no module index is generated.
216#latex_domain_indices = True
217
218# -- Options for manual page output --------------------------------------
219
220# One entry per manual page. List of tuples
221# (source start file, name, description, authors, manual section).
222man_pages = [('index', 'maxminddb', 'maxminddb Documentation',
223 ['Gregory Oschwald'], 1)]
224
225# If true, show URL addresses after external links.
226#man_show_urls = False
227
228# -- Options for Texinfo output ------------------------------------------
229
230# Grouping the document tree into Texinfo files. List of tuples
231# (source start file, target name, title, author,
232# dir menu entry, description, category)
233texinfo_documents = [
234 ('index', 'maxminddb', 'maxminddb Documentation', 'Gregory Oschwald',
235 'maxminddb', 'MaxMind DB Reader', 'Miscellaneous'),
236]
237
238# Documents to append as an appendix to all manuals.
239#texinfo_appendices = []
240
241# If false, no module index is generated.
242#texinfo_domain_indices = True
243
244# How to display URL addresses: 'footnote', 'no', or 'inline'.
245#texinfo_show_urls = 'footnote'
246
247# Example configuration for intersphinx: refer to the Python standard library.
248intersphinx_mapping = {'http://docs.python.org/': None}
diff --git a/docs/html/.buildinfo b/docs/html/.buildinfo
249new file mode 1006440new file mode 100644
index 0000000..5e0172d
--- /dev/null
+++ b/docs/html/.buildinfo
@@ -0,0 +1,4 @@
1# Sphinx build info version 1
2# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
3config: f4b35ba4b456e07a1fe93fc0f298d57b
4tags: 645f666f9bcd5a90fca523b33c5a78b7
diff --git a/docs/index.rst b/docs/html/_sources/index.rst.txt
0similarity index 96%5similarity index 96%
1rename from docs/index.rst6rename from docs/index.rst
2rename to docs/html/_sources/index.rst.txt7rename to docs/html/_sources/index.rst.txt
index a003c74..20fdb5a 100644
--- a/docs/index.rst
+++ b/docs/html/_sources/index.rst.txt
@@ -35,6 +35,6 @@ Indices and tables
35* :ref:`modindex`35* :ref:`modindex`
36* :ref:`search`36* :ref:`search`
3737
38:copyright: (c) 2013-2018 by MaxMind, Inc.38:copyright: (c) 2013-2019 by MaxMind, Inc.
39:license: Apache License, Version 2.039:license: Apache License, Version 2.0
4040
diff --git a/docs/html/_static/basic.css b/docs/html/_static/basic.css
41new file mode 10064441new file mode 100644
index 0000000..b04360d
--- /dev/null
+++ b/docs/html/_static/basic.css
@@ -0,0 +1,768 @@
1/*
2 * basic.css
3 * ~~~~~~~~~
4 *
5 * Sphinx stylesheet -- basic theme.
6 *
7 * :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS.
8 * :license: BSD, see LICENSE for details.
9 *
10 */
11
12/* -- main layout ----------------------------------------------------------- */
13
14div.clearer {
15 clear: both;
16}
17
18/* -- relbar ---------------------------------------------------------------- */
19
20div.related {
21 width: 100%;
22 font-size: 90%;
23}
24
25div.related h3 {
26 display: none;
27}
28
29div.related ul {
30 margin: 0;
31 padding: 0 0 0 10px;
32 list-style: none;
33}
34
35div.related li {
36 display: inline;
37}
38
39div.related li.right {
40 float: right;
41 margin-right: 5px;
42}
43
44/* -- sidebar --------------------------------------------------------------- */
45
46div.sphinxsidebarwrapper {
47 padding: 10px 5px 0 10px;
48}
49
50div.sphinxsidebar {
51 float: left;
52 width: 230px;
53 margin-left: -100%;
54 font-size: 90%;
55 word-wrap: break-word;
56 overflow-wrap : break-word;
57}
58
59div.sphinxsidebar ul {
60 list-style: none;
61}
62
63div.sphinxsidebar ul ul,
64div.sphinxsidebar ul.want-points {
65 margin-left: 20px;
66 list-style: square;
67}
68
69div.sphinxsidebar ul ul {
70 margin-top: 0;
71 margin-bottom: 0;
72}
73
74div.sphinxsidebar form {
75 margin-top: 10px;
76}
77
78div.sphinxsidebar input {
79 border: 1px solid #98dbcc;
80 font-family: sans-serif;
81 font-size: 1em;
82}
83
84div.sphinxsidebar #searchbox form.search {
85 overflow: hidden;
86}
87
88div.sphinxsidebar #searchbox input[type="text"] {
89 float: left;
90 width: 80%;
91 padding: 0.25em;
92 box-sizing: border-box;
93}
94
95div.sphinxsidebar #searchbox input[type="submit"] {
96 float: left;
97 width: 20%;
98 border-left: none;
99 padding: 0.25em;
100 box-sizing: border-box;
101}
102
103
104img {
105 border: 0;
106 max-width: 100%;
107}
108
109/* -- search page ----------------------------------------------------------- */
110
111ul.search {
112 margin: 10px 0 0 20px;
113 padding: 0;
114}
115
116ul.search li {
117 padding: 5px 0 5px 20px;
118 background-image: url(file.png);
119 background-repeat: no-repeat;
120 background-position: 0 7px;
121}
122
123ul.search li a {
124 font-weight: bold;
125}
126
127ul.search li div.context {
128 color: #888;
129 margin: 2px 0 0 30px;
130 text-align: left;
131}
132
133ul.keywordmatches li.goodmatch a {
134 font-weight: bold;
135}
136
137/* -- index page ------------------------------------------------------------ */
138
139table.contentstable {
140 width: 90%;
141 margin-left: auto;
142 margin-right: auto;
143}
144
145table.contentstable p.biglink {
146 line-height: 150%;
147}
148
149a.biglink {
150 font-size: 1.3em;
151}
152
153span.linkdescr {
154 font-style: italic;
155 padding-top: 5px;
156 font-size: 90%;
157}
158
159/* -- general index --------------------------------------------------------- */
160
161table.indextable {
162 width: 100%;
163}
164
165table.indextable td {
166 text-align: left;
167 vertical-align: top;
168}
169
170table.indextable ul {
171 margin-top: 0;
172 margin-bottom: 0;
173 list-style-type: none;
174}
175
176table.indextable > tbody > tr > td > ul {
177 padding-left: 0em;
178}
179
180table.indextable tr.pcap {
181 height: 10px;
182}
183
184table.indextable tr.cap {
185 margin-top: 10px;
186 background-color: #f2f2f2;
187}
188
189img.toggler {
190 margin-right: 3px;
191 margin-top: 3px;
192 cursor: pointer;
193}
194
195div.modindex-jumpbox {
196 border-top: 1px solid #ddd;
197 border-bottom: 1px solid #ddd;
198 margin: 1em 0 1em 0;
199 padding: 0.4em;
200}
201
202div.genindex-jumpbox {
203 border-top: 1px solid #ddd;
204 border-bottom: 1px solid #ddd;
205 margin: 1em 0 1em 0;
206 padding: 0.4em;
207}
208
209/* -- domain module index --------------------------------------------------- */
210
211table.modindextable td {
212 padding: 2px;
213 border-collapse: collapse;
214}
215
216/* -- general body styles --------------------------------------------------- */
217
218div.body {
219 min-width: 450px;
220 max-width: 800px;
221}
222
223div.body p, div.body dd, div.body li, div.body blockquote {
224 -moz-hyphens: auto;
225 -ms-hyphens: auto;
226 -webkit-hyphens: auto;
227 hyphens: auto;
228}
229
230a.headerlink {
231 visibility: hidden;
232}
233
234a.brackets:before,
235span.brackets > a:before{
236 content: "[";
237}
238
239a.brackets:after,
240span.brackets > a:after {
241 content: "]";
242}
243
244h1:hover > a.headerlink,
245h2:hover > a.headerlink,
246h3:hover > a.headerlink,
247h4:hover > a.headerlink,
248h5:hover > a.headerlink,
249h6:hover > a.headerlink,
250dt:hover > a.headerlink,
251caption:hover > a.headerlink,
252p.caption:hover > a.headerlink,
253div.code-block-caption:hover > a.headerlink {
254 visibility: visible;
255}
256
257div.body p.caption {
258 text-align: inherit;
259}
260
261div.body td {
262 text-align: left;
263}
264
265.first {
266 margin-top: 0 !important;
267}
268
269p.rubric {
270 margin-top: 30px;
271 font-weight: bold;
272}
273
274img.align-left, .figure.align-left, object.align-left {
275 clear: left;
276 float: left;
277 margin-right: 1em;
278}
279
280img.align-right, .figure.align-right, object.align-right {
281 clear: right;
282 float: right;
283 margin-left: 1em;
284}
285
286img.align-center, .figure.align-center, object.align-center {
287 display: block;
288 margin-left: auto;
289 margin-right: auto;
290}
291
292img.align-default, .figure.align-default {
293 display: block;
294 margin-left: auto;
295 margin-right: auto;
296}
297
298.align-left {
299 text-align: left;
300}
301
302.align-center {
303 text-align: center;
304}
305
306.align-default {
307 text-align: center;
308}
309
310.align-right {
311 text-align: right;
312}
313
314/* -- sidebars -------------------------------------------------------------- */
315
316div.sidebar {
317 margin: 0 0 0.5em 1em;
318 border: 1px solid #ddb;
319 padding: 7px 7px 0 7px;
320 background-color: #ffe;
321 width: 40%;
322 float: right;
323}
324
325p.sidebar-title {
326 font-weight: bold;
327}
328
329/* -- topics ---------------------------------------------------------------- */
330
331div.topic {
332 border: 1px solid #ccc;
333 padding: 7px 7px 0 7px;
334 margin: 10px 0 10px 0;
335}
336
337p.topic-title {
338 font-size: 1.1em;
339 font-weight: bold;
340 margin-top: 10px;
341}
342
343/* -- admonitions ----------------------------------------------------------- */
344
345div.admonition {
346 margin-top: 10px;
347 margin-bottom: 10px;
348 padding: 7px;
349}
350
351div.admonition dt {
352 font-weight: bold;
353}
354
355div.admonition dl {
356 margin-bottom: 0;
357}
358
359p.admonition-title {
360 margin: 0px 10px 5px 0px;
361 font-weight: bold;
362}
363
364div.body p.centered {
365 text-align: center;
366 margin-top: 25px;
367}
368
369/* -- tables ---------------------------------------------------------------- */
370
371table.docutils {
372 border: 0;
373 border-collapse: collapse;
374}
375
376table.align-center {
377 margin-left: auto;
378 margin-right: auto;
379}
380
381table.align-default {
382 margin-left: auto;
383 margin-right: auto;
384}
385
386table caption span.caption-number {
387 font-style: italic;
388}
389
390table caption span.caption-text {
391}
392
393table.docutils td, table.docutils th {
394 padding: 1px 8px 1px 5px;
395 border-top: 0;
396 border-left: 0;
397 border-right: 0;
398 border-bottom: 1px solid #aaa;
399}
400
401table.footnote td, table.footnote th {
402 border: 0 !important;
403}
404
405th {
406 text-align: left;
407 padding-right: 5px;
408}
409
410table.citation {
411 border-left: solid 1px gray;
412 margin-left: 1px;
413}
414
415table.citation td {
416 border-bottom: none;
417}
418
419th > p:first-child,
420td > p:first-child {
421 margin-top: 0px;
422}
423
424th > p:last-child,
425td > p:last-child {
426 margin-bottom: 0px;
427}
428
429/* -- figures --------------------------------------------------------------- */
430
431div.figure {
432 margin: 0.5em;
433 padding: 0.5em;
434}
435
436div.figure p.caption {
437 padding: 0.3em;
438}
439
440div.figure p.caption span.caption-number {
441 font-style: italic;
442}
443
444div.figure p.caption span.caption-text {
445}
446
447/* -- field list styles ----------------------------------------------------- */
448
449table.field-list td, table.field-list th {
450 border: 0 !important;
451}
452
453.field-list ul {
454 margin: 0;
455 padding-left: 1em;
456}
457
458.field-list p {
459 margin: 0;
460}
461
462.field-name {
463 -moz-hyphens: manual;
464 -ms-hyphens: manual;
465 -webkit-hyphens: manual;
466 hyphens: manual;
467}
468
469/* -- hlist styles ---------------------------------------------------------- */
470
471table.hlist td {
472 vertical-align: top;
473}
474
475
476/* -- other body styles ----------------------------------------------------- */
477
478ol.arabic {
479 list-style: decimal;
480}
481
482ol.loweralpha {
483 list-style: lower-alpha;
484}
485
486ol.upperalpha {
487 list-style: upper-alpha;
488}
489
490ol.lowerroman {
491 list-style: lower-roman;
492}
493
494ol.upperroman {
495 list-style: upper-roman;
496}
497
498li > p:first-child {
499 margin-top: 0px;
500}
501
502li > p:last-child {
503 margin-bottom: 0px;
504}
505
506dl.footnote > dt,
507dl.citation > dt {
508 float: left;
509}
510
511dl.footnote > dd,
512dl.citation > dd {
513 margin-bottom: 0em;
514}
515
516dl.footnote > dd:after,
517dl.citation > dd:after {
518 content: "";
519 clear: both;
520}
521
522dl.field-list {
523 display: grid;
524 grid-template-columns: fit-content(30%) auto;
525}
526
527dl.field-list > dt {
528 font-weight: bold;
529 word-break: break-word;
530 padding-left: 0.5em;
531 padding-right: 5px;
532}
533
534dl.field-list > dt:after {
535 content: ":";
536}
537
538dl.field-list > dd {
539 padding-left: 0.5em;
540 margin-top: 0em;
541 margin-left: 0em;
542 margin-bottom: 0em;
543}
544
545dl {
546 margin-bottom: 15px;
547}
548
549dd > p:first-child {
550 margin-top: 0px;
551}
552
553dd ul, dd table {
554 margin-bottom: 10px;
555}
556
557dd {
558 margin-top: 3px;
559 margin-bottom: 10px;
560 margin-left: 30px;
561}
562
563dt:target, span.highlighted {
564 background-color: #fbe54e;
565}
566
567rect.highlighted {
568 fill: #fbe54e;
569}
570
571dl.glossary dt {
572 font-weight: bold;
573 font-size: 1.1em;
574}
575
576.optional {
577 font-size: 1.3em;
578}
579
580.sig-paren {
581 font-size: larger;
582}
583
584.versionmodified {
585 font-style: italic;
586}
587
588.system-message {
589 background-color: #fda;
590 padding: 5px;
591 border: 3px solid red;
592}
593
594.footnote:target {
595 background-color: #ffa;
596}
597
598.line-block {
599 display: block;
600 margin-top: 1em;
601 margin-bottom: 1em;
602}
603
604.line-block .line-block {
605 margin-top: 0;
606 margin-bottom: 0;
607 margin-left: 1.5em;
608}
609
610.guilabel, .menuselection {
611 font-family: sans-serif;
612}
613
614.accelerator {
615 text-decoration: underline;
616}
617
618.classifier {
619 font-style: oblique;
620}
621
622.classifier:before {
623 font-style: normal;
624 margin: 0.5em;
625 content: ":";
626}
627
628abbr, acronym {
629 border-bottom: dotted 1px;
630 cursor: help;
631}
632
633/* -- code displays --------------------------------------------------------- */
634
635pre {
636 overflow: auto;
637 overflow-y: hidden; /* fixes display issues on Chrome browsers */
638}
639
640span.pre {
641 -moz-hyphens: none;
642 -ms-hyphens: none;
643 -webkit-hyphens: none;
644 hyphens: none;
645}
646
647td.linenos pre {
648 padding: 5px 0px;
649 border: 0;
650 background-color: transparent;
651 color: #aaa;
652}
653
654table.highlighttable {
655 margin-left: 0.5em;
656}
657
658table.highlighttable td {
659 padding: 0 0.5em 0 0.5em;
660}
661
662div.code-block-caption {
663 padding: 2px 5px;
664 font-size: small;
665}
666
667div.code-block-caption code {
668 background-color: transparent;
669}
670
671div.code-block-caption + div > div.highlight > pre {
672 margin-top: 0;
673}
674
675div.doctest > div.highlight span.gp { /* gp: Generic.Prompt */
676 user-select: none;
677}
678
679div.code-block-caption span.caption-number {
680 padding: 0.1em 0.3em;
681 font-style: italic;
682}
683
684div.code-block-caption span.caption-text {
685}
686
687div.literal-block-wrapper {
688 padding: 1em 1em 0;
689}
690
691div.literal-block-wrapper div.highlight {
692 margin: 0;
693}
694
695code.descname {
696 background-color: transparent;
697 font-weight: bold;
698 font-size: 1.2em;
699}
700
701code.descclassname {
702 background-color: transparent;
703}
704
705code.xref, a code {
706 background-color: transparent;
707 font-weight: bold;
708}
709
710h1 code, h2 code, h3 code, h4 code, h5 code, h6 code {
711 background-color: transparent;
712}
713
714.viewcode-link {
715 float: right;
716}
717
718.viewcode-back {
719 float: right;
720 font-family: sans-serif;
721}
722
723div.viewcode-block:target {
724 margin: -1px -10px;
725 padding: 0 10px;
726}
727
728/* -- math display ---------------------------------------------------------- */
729
730img.math {
731 vertical-align: middle;
732}
733
734div.body div.math p {
735 text-align: center;
736}
737
738span.eqno {
739 float: right;
740}
741
742span.eqno a.headerlink {
743 position: relative;
744 left: 0px;
745 z-index: 1;
746}
747
748div.math:hover a.headerlink {
749 visibility: visible;
750}
751
752/* -- printout stylesheet --------------------------------------------------- */
753
754@media print {
755 div.document,
756 div.documentwrapper,
757 div.bodywrapper {
758 margin: 0 !important;
759 width: 100%;
760 }
761
762 div.sphinxsidebar,
763 div.related,
764 div.footer,
765 #top-link {
766 display: none;
767 }
768}
0\ No newline at end of file769\ No newline at end of file
diff --git a/docs/html/_static/contents.png b/docs/html/_static/contents.png
1new file mode 100644770new file mode 100644
index 0000000..6c59aa1
2Binary files /dev/null and b/docs/html/_static/contents.png differ771Binary files /dev/null and b/docs/html/_static/contents.png differ
diff --git a/docs/html/_static/doctools.js b/docs/html/_static/doctools.js
3new file mode 100644772new file mode 100644
index 0000000..b33f87f
--- /dev/null
+++ b/docs/html/_static/doctools.js
@@ -0,0 +1,314 @@
1/*
2 * doctools.js
3 * ~~~~~~~~~~~
4 *
5 * Sphinx JavaScript utilities for all documentation.
6 *
7 * :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS.
8 * :license: BSD, see LICENSE for details.
9 *
10 */
11
12/**
13 * select a different prefix for underscore
14 */
15$u = _.noConflict();
16
17/**
18 * make the code below compatible with browsers without
19 * an installed firebug like debugger
20if (!window.console || !console.firebug) {
21 var names = ["log", "debug", "info", "warn", "error", "assert", "dir",
22 "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace",
23 "profile", "profileEnd"];
24 window.console = {};
25 for (var i = 0; i < names.length; ++i)
26 window.console[names[i]] = function() {};
27}
28 */
29
30/**
31 * small helper function to urldecode strings
32 */
33jQuery.urldecode = function(x) {
34 return decodeURIComponent(x).replace(/\+/g, ' ');
35};
36
37/**
38 * small helper function to urlencode strings
39 */
40jQuery.urlencode = encodeURIComponent;
41
42/**
43 * This function returns the parsed url parameters of the
44 * current request. Multiple values per key are supported,
45 * it will always return arrays of strings for the value parts.
46 */
47jQuery.getQueryParameters = function(s) {
48 if (typeof s === 'undefined')
49 s = document.location.search;
50 var parts = s.substr(s.indexOf('?') + 1).split('&');
51 var result = {};
52 for (var i = 0; i < parts.length; i++) {
53 var tmp = parts[i].split('=', 2);
54 var key = jQuery.urldecode(tmp[0]);
55 var value = jQuery.urldecode(tmp[1]);
56 if (key in result)
57 result[key].push(value);
58 else
59 result[key] = [value];
60 }
61 return result;
62};
63
64/**
65 * highlight a given string on a jquery object by wrapping it in
66 * span elements with the given class name.
67 */
68jQuery.fn.highlightText = function(text, className) {
69 function highlight(node, addItems) {
70 if (node.nodeType === 3) {
71 var val = node.nodeValue;
72 var pos = val.toLowerCase().indexOf(text);
73 if (pos >= 0 &&
74 !jQuery(node.parentNode).hasClass(className) &&
75 !jQuery(node.parentNode).hasClass("nohighlight")) {
76 var span;
77 var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg");
78 if (isInSVG) {
79 span = document.createElementNS("http://www.w3.org/2000/svg", "tspan");
80 } else {
81 span = document.createElement("span");
82 span.className = className;
83 }
84 span.appendChild(document.createTextNode(val.substr(pos, text.length)));
85 node.parentNode.insertBefore(span, node.parentNode.insertBefore(
86 document.createTextNode(val.substr(pos + text.length)),
87 node.nextSibling));
88 node.nodeValue = val.substr(0, pos);
89 if (isInSVG) {
90 var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
91 var bbox = node.parentElement.getBBox();
92 rect.x.baseVal.value = bbox.x;
93 rect.y.baseVal.value = bbox.y;
94 rect.width.baseVal.value = bbox.width;
95 rect.height.baseVal.value = bbox.height;
96 rect.setAttribute('class', className);
97 addItems.push({
98 "parent": node.parentNode,
99 "target": rect});
100 }
101 }
102 }
103 else if (!jQuery(node).is("button, select, textarea")) {
104 jQuery.each(node.childNodes, function() {
105 highlight(this, addItems);
106 });
107 }
108 }
109 var addItems = [];
110 var result = this.each(function() {
111 highlight(this, addItems);
112 });
113 for (var i = 0; i < addItems.length; ++i) {
114 jQuery(addItems[i].parent).before(addItems[i].target);
115 }
116 return result;
117};
118
119/*
120 * backward compatibility for jQuery.browser
121 * This will be supported until firefox bug is fixed.
122 */
123if (!jQuery.browser) {
124 jQuery.uaMatch = function(ua) {
125 ua = ua.toLowerCase();
126
127 var match = /(chrome)[ \/]([\w.]+)/.exec(ua) ||
128 /(webkit)[ \/]([\w.]+)/.exec(ua) ||
129 /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) ||
130 /(msie) ([\w.]+)/.exec(ua) ||
131 ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) ||
132 [];
133
134 return {
135 browser: match[ 1 ] || "",
136 version: match[ 2 ] || "0"
137 };
138 };
139 jQuery.browser = {};
140 jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true;
141}
142
143/**
144 * Small JavaScript module for the documentation.
145 */
146var Documentation = {
147
148 init : function() {
149 this.fixFirefoxAnchorBug();
150 this.highlightSearchWords();
151 this.initIndexTable();
152 if (DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) {
153 this.initOnKeyListeners();
154 }
155 },
156
157 /**
158 * i18n support
159 */
160 TRANSLATIONS : {},
161 PLURAL_EXPR : function(n) { return n === 1 ? 0 : 1; },
162 LOCALE : 'unknown',
163
164 // gettext and ngettext don't access this so that the functions
165 // can safely bound to a different name (_ = Documentation.gettext)
166 gettext : function(string) {
167 var translated = Documentation.TRANSLATIONS[string];
168 if (typeof translated === 'undefined')
169 return string;
170 return (typeof translated === 'string') ? translated : translated[0];
171 },
172
173 ngettext : function(singular, plural, n) {
174 var translated = Documentation.TRANSLATIONS[singular];
175 if (typeof translated === 'undefined')
176 return (n == 1) ? singular : plural;
177 return translated[Documentation.PLURALEXPR(n)];
178 },
179
180 addTranslations : function(catalog) {
181 for (var key in catalog.messages)
182 this.TRANSLATIONS[key] = catalog.messages[key];
183 this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')');
184 this.LOCALE = catalog.locale;
185 },
186
187 /**
188 * add context elements like header anchor links
189 */
190 addContextElements : function() {
191 $('div[id] > :header:first').each(function() {
192 $('<a class="headerlink">\u00B6</a>').
193 attr('href', '#' + this.id).
194 attr('title', _('Permalink to this headline')).
195 appendTo(this);
196 });
197 $('dt[id]').each(function() {
198 $('<a class="headerlink">\u00B6</a>').
199 attr('href', '#' + this.id).
200 attr('title', _('Permalink to this definition')).
201 appendTo(this);
202 });
203 },
204
205 /**
206 * workaround a firefox stupidity
207 * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075
208 */
209 fixFirefoxAnchorBug : function() {
210 if (document.location.hash && $.browser.mozilla)
211 window.setTimeout(function() {
212 document.location.href += '';
213 }, 10);
214 },
215
216 /**
217 * highlight the search words provided in the url in the text
218 */
219 highlightSearchWords : function() {
220 var params = $.getQueryParameters();
221 var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : [];
222 if (terms.length) {
223 var body = $('div.body');
224 if (!body.length) {
225 body = $('body');
226 }
227 window.setTimeout(function() {
228 $.each(terms, function() {
229 body.highlightText(this.toLowerCase(), 'highlighted');
230 });
231 }, 10);
232 $('<p class="highlight-link"><a href="javascript:Documentation.' +
233 'hideSearchWords()">' + _('Hide Search Matches') + '</a></p>')
234 .appendTo($('#searchbox'));
235 }
236 },
237
238 /**
239 * init the domain index toggle buttons
240 */
241 initIndexTable : function() {
242 var togglers = $('img.toggler').click(function() {
243 var src = $(this).attr('src');
244 var idnum = $(this).attr('id').substr(7);
245 $('tr.cg-' + idnum).toggle();
246 if (src.substr(-9) === 'minus.png')
247 $(this).attr('src', src.substr(0, src.length-9) + 'plus.png');
248 else
249 $(this).attr('src', src.substr(0, src.length-8) + 'minus.png');
250 }).css('display', '');
251 if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) {
252 togglers.click();
253 }
254 },
255
256 /**
257 * helper function to hide the search marks again
258 */
259 hideSearchWords : function() {
260 $('#searchbox .highlight-link').fadeOut(300);
261 $('span.highlighted').removeClass('highlighted');
262 },
263
264 /**
265 * make the url absolute
266 */
267 makeURL : function(relativeURL) {
268 return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL;
269 },
270
271 /**
272 * get the current relative url
273 */
274 getCurrentURL : function() {
275 var path = document.location.pathname;
276 var parts = path.split(/\//);
277 $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() {
278 if (this === '..')
279 parts.pop();
280 });
281 var url = parts.join('/');
282 return path.substring(url.lastIndexOf('/') + 1, path.length - 1);
283 },
284
285 initOnKeyListeners: function() {
286 $(document).keyup(function(event) {
287 var activeElementType = document.activeElement.tagName;
288 // don't navigate when in search box or textarea
289 if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT') {
290 switch (event.keyCode) {
291 case 37: // left
292 var prevHref = $('link[rel="prev"]').prop('href');
293 if (prevHref) {
294 window.location.href = prevHref;
295 return false;
296 }
297 case 39: // right
298 var nextHref = $('link[rel="next"]').prop('href');
299 if (nextHref) {
300 window.location.href = nextHref;
301 return false;
302 }
303 }
304 }
305 });
306 }
307};
308
309// quick alias for translations
310_ = Documentation.gettext;
311
312$(document).ready(function() {
313 Documentation.init();
314});
diff --git a/docs/html/_static/documentation_options.js b/docs/html/_static/documentation_options.js
0new file mode 100644315new file mode 100644
index 0000000..375482b
--- /dev/null
+++ b/docs/html/_static/documentation_options.js
@@ -0,0 +1,11 @@
1var DOCUMENTATION_OPTIONS = {
2 URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'),
3 VERSION: '1.5.2',
4 LANGUAGE: 'None',
5 COLLAPSE_INDEX: false,
6 BUILDER: 'html',
7 FILE_SUFFIX: '.html',
8 HAS_SOURCE: true,
9 SOURCELINK_SUFFIX: '.txt',
10 NAVIGATION_WITH_KEYS: false
11};
0\ No newline at end of file12\ No newline at end of file
diff --git a/docs/html/_static/file.png b/docs/html/_static/file.png
1new file mode 10064413new file mode 100644
index 0000000..a858a41
2Binary files /dev/null and b/docs/html/_static/file.png differ14Binary files /dev/null and b/docs/html/_static/file.png differ
diff --git a/docs/html/_static/jquery-3.4.1.js b/docs/html/_static/jquery-3.4.1.js
3new file mode 10064415new file mode 100644
index 0000000..773ad95
--- /dev/null
+++ b/docs/html/_static/jquery-3.4.1.js
@@ -0,0 +1,10598 @@
1/*!
2 * jQuery JavaScript Library v3.4.1
3 * https://jquery.com/
4 *
5 * Includes Sizzle.js
6 * https://sizzlejs.com/
7 *
8 * Copyright JS Foundation and other contributors
9 * Released under the MIT license
10 * https://jquery.org/license
11 *
12 * Date: 2019-05-01T21:04Z
13 */
14( function( global, factory ) {
15
16 "use strict";
17
18 if ( typeof module === "object" && typeof module.exports === "object" ) {
19
20 // For CommonJS and CommonJS-like environments where a proper `window`
21 // is present, execute the factory and get jQuery.
22 // For environments that do not have a `window` with a `document`
23 // (such as Node.js), expose a factory as module.exports.
24 // This accentuates the need for the creation of a real `window`.
25 // e.g. var jQuery = require("jquery")(window);
26 // See ticket #14549 for more info.
27 module.exports = global.document ?
28 factory( global, true ) :
29 function( w ) {
30 if ( !w.document ) {
31 throw new Error( "jQuery requires a window with a document" );
32 }
33 return factory( w );
34 };
35 } else {
36 factory( global );
37 }
38
39// Pass this if window is not defined yet
40} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
41
42// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1
43// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode
44// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common
45// enough that all such attempts are guarded in a try block.
46"use strict";
47
48var arr = [];
49
50var document = window.document;
51
52var getProto = Object.getPrototypeOf;
53
54var slice = arr.slice;
55
56var concat = arr.concat;
57
58var push = arr.push;
59
60var indexOf = arr.indexOf;
61
62var class2type = {};
63
64var toString = class2type.toString;
65
66var hasOwn = class2type.hasOwnProperty;
67
68var fnToString = hasOwn.toString;
69
70var ObjectFunctionString = fnToString.call( Object );
71
72var support = {};
73
74var isFunction = function isFunction( obj ) {
75
76 // Support: Chrome <=57, Firefox <=52
77 // In some browsers, typeof returns "function" for HTML <object> elements
78 // (i.e., `typeof document.createElement( "object" ) === "function"`).
79 // We don't want to classify *any* DOM node as a function.
80 return typeof obj === "function" && typeof obj.nodeType !== "number";
81 };
82
83
84var isWindow = function isWindow( obj ) {
85 return obj != null && obj === obj.window;
86 };
87
88
89
90
91 var preservedScriptAttributes = {
92 type: true,
93 src: true,
94 nonce: true,
95 noModule: true
96 };
97
98 function DOMEval( code, node, doc ) {
99 doc = doc || document;
100
101 var i, val,
102 script = doc.createElement( "script" );
103
104 script.text = code;
105 if ( node ) {
106 for ( i in preservedScriptAttributes ) {
107
108 // Support: Firefox 64+, Edge 18+
109 // Some browsers don't support the "nonce" property on scripts.
110 // On the other hand, just using `getAttribute` is not enough as
111 // the `nonce` attribute is reset to an empty string whenever it
112 // becomes browsing-context connected.
113 // See https://github.com/whatwg/html/issues/2369
114 // See https://html.spec.whatwg.org/#nonce-attributes
115 // The `node.getAttribute` check was added for the sake of
116 // `jQuery.globalEval` so that it can fake a nonce-containing node
117 // via an object.
118 val = node[ i ] || node.getAttribute && node.getAttribute( i );
119 if ( val ) {
120 script.setAttribute( i, val );
121 }
122 }
123 }
124 doc.head.appendChild( script ).parentNode.removeChild( script );
125 }
126
127
128function toType( obj ) {
129 if ( obj == null ) {
130 return obj + "";
131 }
132
133 // Support: Android <=2.3 only (functionish RegExp)
134 return typeof obj === "object" || typeof obj === "function" ?
135 class2type[ toString.call( obj ) ] || "object" :
136 typeof obj;
137}
138/* global Symbol */
139// Defining this global in .eslintrc.json would create a danger of using the global
140// unguarded in another place, it seems safer to define global only for this module
141
142
143
144var
145 version = "3.4.1",
146
147 // Define a local copy of jQuery
148 jQuery = function( selector, context ) {
149
150 // The jQuery object is actually just the init constructor 'enhanced'
151 // Need init if jQuery is called (just allow error to be thrown if not included)
152 return new jQuery.fn.init( selector, context );
153 },
154
155 // Support: Android <=4.0 only
156 // Make sure we trim BOM and NBSP
157 rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;
158
159jQuery.fn = jQuery.prototype = {
160
161 // The current version of jQuery being used
162 jquery: version,
163
164 constructor: jQuery,
165
166 // The default length of a jQuery object is 0
167 length: 0,
168
169 toArray: function() {
170 return slice.call( this );
171 },
172
173 // Get the Nth element in the matched element set OR
174 // Get the whole matched element set as a clean array
175 get: function( num ) {
176
177 // Return all the elements in a clean array
178 if ( num == null ) {
179 return slice.call( this );
180 }
181
182 // Return just the one element from the set
183 return num < 0 ? this[ num + this.length ] : this[ num ];
184 },
185
186 // Take an array of elements and push it onto the stack
187 // (returning the new matched element set)
188 pushStack: function( elems ) {
189
190 // Build a new jQuery matched element set
191 var ret = jQuery.merge( this.constructor(), elems );
192
193 // Add the old object onto the stack (as a reference)
194 ret.prevObject = this;
195
196 // Return the newly-formed element set
197 return ret;
198 },
199
200 // Execute a callback for every element in the matched set.
201 each: function( callback ) {
202 return jQuery.each( this, callback );
203 },
204
205 map: function( callback ) {
206 return this.pushStack( jQuery.map( this, function( elem, i ) {
207 return callback.call( elem, i, elem );
208 } ) );
209 },
210
211 slice: function() {
212 return this.pushStack( slice.apply( this, arguments ) );
213 },
214
215 first: function() {
216 return this.eq( 0 );
217 },
218
219 last: function() {
220 return this.eq( -1 );
221 },
222
223 eq: function( i ) {
224 var len = this.length,
225 j = +i + ( i < 0 ? len : 0 );
226 return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );
227 },
228
229 end: function() {
230 return this.prevObject || this.constructor();
231 },
232
233 // For internal use only.
234 // Behaves like an Array's method, not like a jQuery method.
235 push: push,
236 sort: arr.sort,
237 splice: arr.splice
238};
239
240jQuery.extend = jQuery.fn.extend = function() {
241 var options, name, src, copy, copyIsArray, clone,
242 target = arguments[ 0 ] || {},
243 i = 1,
244 length = arguments.length,
245 deep = false;
246
247 // Handle a deep copy situation
248 if ( typeof target === "boolean" ) {
249 deep = target;
250
251 // Skip the boolean and the target
252 target = arguments[ i ] || {};
253 i++;
254 }
255
256 // Handle case when target is a string or something (possible in deep copy)
257 if ( typeof target !== "object" && !isFunction( target ) ) {
258 target = {};
259 }
260
261 // Extend jQuery itself if only one argument is passed
262 if ( i === length ) {
263 target = this;
264 i--;
265 }
266
267 for ( ; i < length; i++ ) {
268
269 // Only deal with non-null/undefined values
270 if ( ( options = arguments[ i ] ) != null ) {
271
272 // Extend the base object
273 for ( name in options ) {
274 copy = options[ name ];
275
276 // Prevent Object.prototype pollution
277 // Prevent never-ending loop
278 if ( name === "__proto__" || target === copy ) {
279 continue;
280 }
281
282 // Recurse if we're merging plain objects or arrays
283 if ( deep && copy && ( jQuery.isPlainObject( copy ) ||
284 ( copyIsArray = Array.isArray( copy ) ) ) ) {
285 src = target[ name ];
286
287 // Ensure proper type for the source value
288 if ( copyIsArray && !Array.isArray( src ) ) {
289 clone = [];
290 } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) {
291 clone = {};
292 } else {
293 clone = src;
294 }
295 copyIsArray = false;
296
297 // Never move original objects, clone them
298 target[ name ] = jQuery.extend( deep, clone, copy );
299
300 // Don't bring in undefined values
301 } else if ( copy !== undefined ) {
302 target[ name ] = copy;
303 }
304 }
305 }
306 }
307
308 // Return the modified object
309 return target;
310};
311
312jQuery.extend( {
313
314 // Unique for each copy of jQuery on the page
315 expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),
316
317 // Assume jQuery is ready without the ready module
318 isReady: true,
319
320 error: function( msg ) {
321 throw new Error( msg );
322 },
323
324 noop: function() {},
325
326 isPlainObject: function( obj ) {
327 var proto, Ctor;
328
329 // Detect obvious negatives
330 // Use toString instead of jQuery.type to catch host objects
331 if ( !obj || toString.call( obj ) !== "[object Object]" ) {
332 return false;
333 }
334
335 proto = getProto( obj );
336
337 // Objects with no prototype (e.g., `Object.create( null )`) are plain
338 if ( !proto ) {
339 return true;
340 }
341
342 // Objects with prototype are plain iff they were constructed by a global Object function
343 Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor;
344 return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString;
345 },
346
347 isEmptyObject: function( obj ) {
348 var name;
349
350 for ( name in obj ) {
351 return false;
352 }
353 return true;
354 },
355
356 // Evaluates a script in a global context
357 globalEval: function( code, options ) {
358 DOMEval( code, { nonce: options && options.nonce } );
359 },
360
361 each: function( obj, callback ) {
362 var length, i = 0;
363
364 if ( isArrayLike( obj ) ) {
365 length = obj.length;
366 for ( ; i < length; i++ ) {
367 if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
368 break;
369 }
370 }
371 } else {
372 for ( i in obj ) {
373 if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
374 break;
375 }
376 }
377 }
378
379 return obj;
380 },
381
382 // Support: Android <=4.0 only
383 trim: function( text ) {
384 return text == null ?
385 "" :
386 ( text + "" ).replace( rtrim, "" );
387 },
388
389 // results is for internal usage only
390 makeArray: function( arr, results ) {
391 var ret = results || [];
392
393 if ( arr != null ) {
394 if ( isArrayLike( Object( arr ) ) ) {
395 jQuery.merge( ret,
396 typeof arr === "string" ?
397 [ arr ] : arr
398 );
399 } else {
400 push.call( ret, arr );
401 }
402 }
403
404 return ret;
405 },
406
407 inArray: function( elem, arr, i ) {
408 return arr == null ? -1 : indexOf.call( arr, elem, i );
409 },
410
411 // Support: Android <=4.0 only, PhantomJS 1 only
412 // push.apply(_, arraylike) throws on ancient WebKit
413 merge: function( first, second ) {
414 var len = +second.length,
415 j = 0,
416 i = first.length;
417
418 for ( ; j < len; j++ ) {
419 first[ i++ ] = second[ j ];
420 }
421
422 first.length = i;
423
424 return first;
425 },
426
427 grep: function( elems, callback, invert ) {
428 var callbackInverse,
429 matches = [],
430 i = 0,
431 length = elems.length,
432 callbackExpect = !invert;
433
434 // Go through the array, only saving the items
435 // that pass the validator function
436 for ( ; i < length; i++ ) {
437 callbackInverse = !callback( elems[ i ], i );
438 if ( callbackInverse !== callbackExpect ) {
439 matches.push( elems[ i ] );
440 }
441 }
442
443 return matches;
444 },
445
446 // arg is for internal usage only
447 map: function( elems, callback, arg ) {
448 var length, value,
449 i = 0,
450 ret = [];
451
452 // Go through the array, translating each of the items to their new values
453 if ( isArrayLike( elems ) ) {
454 length = elems.length;
455 for ( ; i < length; i++ ) {
456 value = callback( elems[ i ], i, arg );
457
458 if ( value != null ) {
459 ret.push( value );
460 }
461 }
462
463 // Go through every key on the object,
464 } else {
465 for ( i in elems ) {
466 value = callback( elems[ i ], i, arg );
467
468 if ( value != null ) {
469 ret.push( value );
470 }
471 }
472 }
473
474 // Flatten any nested arrays
475 return concat.apply( [], ret );
476 },
477
478 // A global GUID counter for objects
479 guid: 1,
480
481 // jQuery.support is not used in Core but other projects attach their
482 // properties to it so it needs to exist.
483 support: support
484} );
485
486if ( typeof Symbol === "function" ) {
487 jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ];
488}
489
490// Populate the class2type map
491jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ),
492function( i, name ) {
493 class2type[ "[object " + name + "]" ] = name.toLowerCase();
494} );
495
496function isArrayLike( obj ) {
497
498 // Support: real iOS 8.2 only (not reproducible in simulator)
499 // `in` check used to prevent JIT error (gh-2145)
500 // hasOwn isn't used here due to false negatives
501 // regarding Nodelist length in IE
502 var length = !!obj && "length" in obj && obj.length,
503 type = toType( obj );
504
505 if ( isFunction( obj ) || isWindow( obj ) ) {
506 return false;
507 }
508
509 return type === "array" || length === 0 ||
510 typeof length === "number" && length > 0 && ( length - 1 ) in obj;
511}
512var Sizzle =
513/*!
514 * Sizzle CSS Selector Engine v2.3.4
515 * https://sizzlejs.com/
516 *
517 * Copyright JS Foundation and other contributors
518 * Released under the MIT license
519 * https://js.foundation/
520 *
521 * Date: 2019-04-08
522 */
523(function( window ) {
524
525var i,
526 support,
527 Expr,
528 getText,
529 isXML,
530 tokenize,
531 compile,
532 select,
533 outermostContext,
534 sortInput,
535 hasDuplicate,
536
537 // Local document vars
538 setDocument,
539 document,
540 docElem,
541 documentIsHTML,
542 rbuggyQSA,
543 rbuggyMatches,
544 matches,
545 contains,
546
547 // Instance-specific data
548 expando = "sizzle" + 1 * new Date(),
549 preferredDoc = window.document,
550 dirruns = 0,
551 done = 0,
552 classCache = createCache(),
553 tokenCache = createCache(),
554 compilerCache = createCache(),
555 nonnativeSelectorCache = createCache(),
556 sortOrder = function( a, b ) {
557 if ( a === b ) {
558 hasDuplicate = true;
559 }
560 return 0;
561 },
562
563 // Instance methods
564 hasOwn = ({}).hasOwnProperty,
565 arr = [],
566 pop = arr.pop,
567 push_native = arr.push,
568 push = arr.push,
569 slice = arr.slice,
570 // Use a stripped-down indexOf as it's faster than native
571 // https://jsperf.com/thor-indexof-vs-for/5
572 indexOf = function( list, elem ) {
573 var i = 0,
574 len = list.length;
575 for ( ; i < len; i++ ) {
576 if ( list[i] === elem ) {
577 return i;
578 }
579 }
580 return -1;
581 },
582
583 booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
584
585 // Regular expressions
586
587 // http://www.w3.org/TR/css3-selectors/#whitespace
588 whitespace = "[\\x20\\t\\r\\n\\f]",
589
590 // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
591 identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+",
592
593 // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
594 attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace +
595 // Operator (capture 2)
596 "*([*^$|!~]?=)" + whitespace +
597 // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
598 "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace +
599 "*\\]",
600
601 pseudos = ":(" + identifier + ")(?:\\((" +
602 // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:
603 // 1. quoted (capture 3; capture 4 or capture 5)
604 "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
605 // 2. simple (capture 6)
606 "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" +
607 // 3. anything else (capture 2)
608 ".*" +
609 ")\\)|)",
610
611 // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
612 rwhitespace = new RegExp( whitespace + "+", "g" ),
613 rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
614
615 rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
616 rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
617 rdescend = new RegExp( whitespace + "|>" ),
618
619 rpseudo = new RegExp( pseudos ),
620 ridentifier = new RegExp( "^" + identifier + "$" ),
621
622 matchExpr = {
623 "ID": new RegExp( "^#(" + identifier + ")" ),
624 "CLASS": new RegExp( "^\\.(" + identifier + ")" ),
625 "TAG": new RegExp( "^(" + identifier + "|[*])" ),
626 "ATTR": new RegExp( "^" + attributes ),
627 "PSEUDO": new RegExp( "^" + pseudos ),
628 "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
629 "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
630 "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
631 "bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
632 // For use in libraries implementing .is()
633 // We use this for POS matching in `select`
634 "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
635 whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
636 },
637
638 rhtml = /HTML$/i,
639 rinputs = /^(?:input|select|textarea|button)$/i,
640 rheader = /^h\d$/i,
641
642 rnative = /^[^{]+\{\s*\[native \w/,
643
644 // Easily-parseable/retrievable ID or TAG or CLASS selectors
645 rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
646
647 rsibling = /[+~]/,
648
649 // CSS escapes
650 // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
651 runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
652 funescape = function( _, escaped, escapedWhitespace ) {
653 var high = "0x" + escaped - 0x10000;
654 // NaN means non-codepoint
655 // Support: Firefox<24
656 // Workaround erroneous numeric interpretation of +"0x"
657 return high !== high || escapedWhitespace ?
658 escaped :
659 high < 0 ?
660 // BMP codepoint
661 String.fromCharCode( high + 0x10000 ) :
662 // Supplemental Plane codepoint (surrogate pair)
663 String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
664 },
665
666 // CSS string/identifier serialization
667 // https://drafts.csswg.org/cssom/#common-serializing-idioms
668 rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,
669 fcssescape = function( ch, asCodePoint ) {
670 if ( asCodePoint ) {
671
672 // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER
673 if ( ch === "\0" ) {
674 return "\uFFFD";
675 }
676
677 // Control characters and (dependent upon position) numbers get escaped as code points
678 return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " ";
679 }
680
681 // Other potentially-special ASCII characters get backslash-escaped
682 return "\\" + ch;
683 },
684
685 // Used for iframes
686 // See setDocument()
687 // Removing the function wrapper causes a "Permission Denied"
688 // error in IE
689 unloadHandler = function() {
690 setDocument();
691 },
692
693 inDisabledFieldset = addCombinator(
694 function( elem ) {
695 return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset";
696 },
697 { dir: "parentNode", next: "legend" }
698 );
699
700// Optimize for push.apply( _, NodeList )
701try {
702 push.apply(
703 (arr = slice.call( preferredDoc.childNodes )),
704 preferredDoc.childNodes
705 );
706 // Support: Android<4.0
707 // Detect silently failing push.apply
708 arr[ preferredDoc.childNodes.length ].nodeType;
709} catch ( e ) {
710 push = { apply: arr.length ?
711
712 // Leverage slice if possible
713 function( target, els ) {
714 push_native.apply( target, slice.call(els) );
715 } :
716
717 // Support: IE<9
718 // Otherwise append directly
719 function( target, els ) {
720 var j = target.length,
721 i = 0;
722 // Can't trust NodeList.length
723 while ( (target[j++] = els[i++]) ) {}
724 target.length = j - 1;
725 }
726 };
727}
728
729function Sizzle( selector, context, results, seed ) {
730 var m, i, elem, nid, match, groups, newSelector,
731 newContext = context && context.ownerDocument,
732
733 // nodeType defaults to 9, since context defaults to document
734 nodeType = context ? context.nodeType : 9;
735
736 results = results || [];
737
738 // Return early from calls with invalid selector or context
739 if ( typeof selector !== "string" || !selector ||
740 nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {
741
742 return results;
743 }
744
745 // Try to shortcut find operations (as opposed to filters) in HTML documents
746 if ( !seed ) {
747
748 if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
749 setDocument( context );
750 }
751 context = context || document;
752
753 if ( documentIsHTML ) {
754
755 // If the selector is sufficiently simple, try using a "get*By*" DOM method
756 // (excepting DocumentFragment context, where the methods don't exist)
757 if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) {
758
759 // ID selector
760 if ( (m = match[1]) ) {
761
762 // Document context
763 if ( nodeType === 9 ) {
764 if ( (elem = context.getElementById( m )) ) {
765
766 // Support: IE, Opera, Webkit
767 // TODO: identify versions
768 // getElementById can match elements by name instead of ID
769 if ( elem.id === m ) {
770 results.push( elem );
771 return results;
772 }
773 } else {
774 return results;
775 }
776
777 // Element context
778 } else {
779
780 // Support: IE, Opera, Webkit
781 // TODO: identify versions
782 // getElementById can match elements by name instead of ID
783 if ( newContext && (elem = newContext.getElementById( m )) &&
784 contains( context, elem ) &&
785 elem.id === m ) {
786
787 results.push( elem );
788 return results;
789 }
790 }
791
792 // Type selector
793 } else if ( match[2] ) {
794 push.apply( results, context.getElementsByTagName( selector ) );
795 return results;
796
797 // Class selector
798 } else if ( (m = match[3]) && support.getElementsByClassName &&
799 context.getElementsByClassName ) {
800
801 push.apply( results, context.getElementsByClassName( m ) );
802 return results;
803 }
804 }
805
806 // Take advantage of querySelectorAll
807 if ( support.qsa &&
808 !nonnativeSelectorCache[ selector + " " ] &&
809 (!rbuggyQSA || !rbuggyQSA.test( selector )) &&
810
811 // Support: IE 8 only
812 // Exclude object elements
813 (nodeType !== 1 || context.nodeName.toLowerCase() !== "object") ) {
814
815 newSelector = selector;
816 newContext = context;
817
818 // qSA considers elements outside a scoping root when evaluating child or
819 // descendant combinators, which is not what we want.
820 // In such cases, we work around the behavior by prefixing every selector in the
821 // list with an ID selector referencing the scope context.
822 // Thanks to Andrew Dupont for this technique.
823 if ( nodeType === 1 && rdescend.test( selector ) ) {
824
825 // Capture the context ID, setting it first if necessary
826 if ( (nid = context.getAttribute( "id" )) ) {
827 nid = nid.replace( rcssescape, fcssescape );
828 } else {
829 context.setAttribute( "id", (nid = expando) );
830 }
831
832 // Prefix every selector in the list
833 groups = tokenize( selector );
834 i = groups.length;
835 while ( i-- ) {
836 groups[i] = "#" + nid + " " + toSelector( groups[i] );
837 }
838 newSelector = groups.join( "," );
839
840 // Expand context for sibling selectors
841 newContext = rsibling.test( selector ) && testContext( context.parentNode ) ||
842 context;
843 }
844
845 try {
846 push.apply( results,
847 newContext.querySelectorAll( newSelector )
848 );
849 return results;
850 } catch ( qsaError ) {
851 nonnativeSelectorCache( selector, true );
852 } finally {
853 if ( nid === expando ) {
854 context.removeAttribute( "id" );
855 }
856 }
857 }
858 }
859 }
860
861 // All others
862 return select( selector.replace( rtrim, "$1" ), context, results, seed );
863}
864
865/**
866 * Create key-value caches of limited size
867 * @returns {function(string, object)} Returns the Object data after storing it on itself with
868 * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
869 * deleting the oldest entry
870 */
871function createCache() {
872 var keys = [];
873
874 function cache( key, value ) {
875 // Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
876 if ( keys.push( key + " " ) > Expr.cacheLength ) {
877 // Only keep the most recent entries
878 delete cache[ keys.shift() ];
879 }
880 return (cache[ key + " " ] = value);
881 }
882 return cache;
883}
884
885/**
886 * Mark a function for special use by Sizzle
887 * @param {Function} fn The function to mark
888 */
889function markFunction( fn ) {
890 fn[ expando ] = true;
891 return fn;
892}
893
894/**
895 * Support testing using an element
896 * @param {Function} fn Passed the created element and returns a boolean result
897 */
898function assert( fn ) {
899 var el = document.createElement("fieldset");
900
901 try {
902 return !!fn( el );
903 } catch (e) {
904 return false;
905 } finally {
906 // Remove from its parent by default
907 if ( el.parentNode ) {
908 el.parentNode.removeChild( el );
909 }
910 // release memory in IE
911 el = null;
912 }
913}
914
915/**
916 * Adds the same handler for all of the specified attrs
917 * @param {String} attrs Pipe-separated list of attributes
918 * @param {Function} handler The method that will be applied
919 */
920function addHandle( attrs, handler ) {
921 var arr = attrs.split("|"),
922 i = arr.length;
923
924 while ( i-- ) {
925 Expr.attrHandle[ arr[i] ] = handler;
926 }
927}
928
929/**
930 * Checks document order of two siblings
931 * @param {Element} a
932 * @param {Element} b
933 * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
934 */
935function siblingCheck( a, b ) {
936 var cur = b && a,
937 diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
938 a.sourceIndex - b.sourceIndex;
939
940 // Use IE sourceIndex if available on both nodes
941 if ( diff ) {
942 return diff;
943 }
944
945 // Check if b follows a
946 if ( cur ) {
947 while ( (cur = cur.nextSibling) ) {
948 if ( cur === b ) {
949 return -1;
950 }
951 }
952 }
953
954 return a ? 1 : -1;
955}
956
957/**
958 * Returns a function to use in pseudos for input types
959 * @param {String} type
960 */
961function createInputPseudo( type ) {
962 return function( elem ) {
963 var name = elem.nodeName.toLowerCase();
964 return name === "input" && elem.type === type;
965 };
966}
967
968/**
969 * Returns a function to use in pseudos for buttons
970 * @param {String} type
971 */
972function createButtonPseudo( type ) {
973 return function( elem ) {
974 var name = elem.nodeName.toLowerCase();
975 return (name === "input" || name === "button") && elem.type === type;
976 };
977}
978
979/**
980 * Returns a function to use in pseudos for :enabled/:disabled
981 * @param {Boolean} disabled true for :disabled; false for :enabled
982 */
983function createDisabledPseudo( disabled ) {
984
985 // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable
986 return function( elem ) {
987
988 // Only certain elements can match :enabled or :disabled
989 // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled
990 // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled
991 if ( "form" in elem ) {
992
993 // Check for inherited disabledness on relevant non-disabled elements:
994 // * listed form-associated elements in a disabled fieldset
995 // https://html.spec.whatwg.org/multipage/forms.html#category-listed
996 // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled
997 // * option elements in a disabled optgroup
998 // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled
999 // All such elements have a "form" property.
1000 if ( elem.parentNode && elem.disabled === false ) {
1001
1002 // Option elements defer to a parent optgroup if present
1003 if ( "label" in elem ) {
1004 if ( "label" in elem.parentNode ) {
1005 return elem.parentNode.disabled === disabled;
1006 } else {
1007 return elem.disabled === disabled;
1008 }
1009 }
1010
1011 // Support: IE 6 - 11
1012 // Use the isDisabled shortcut property to check for disabled fieldset ancestors
1013 return elem.isDisabled === disabled ||
1014
1015 // Where there is no isDisabled, check manually
1016 /* jshint -W018 */
1017 elem.isDisabled !== !disabled &&
1018 inDisabledFieldset( elem ) === disabled;
1019 }
1020
1021 return elem.disabled === disabled;
1022
1023 // Try to winnow out elements that can't be disabled before trusting the disabled property.
1024 // Some victims get caught in our net (label, legend, menu, track), but it shouldn't
1025 // even exist on them, let alone have a boolean value.
1026 } else if ( "label" in elem ) {
1027 return elem.disabled === disabled;
1028 }
1029
1030 // Remaining elements are neither :enabled nor :disabled
1031 return false;
1032 };
1033}
1034
1035/**
1036 * Returns a function to use in pseudos for positionals
1037 * @param {Function} fn
1038 */
1039function createPositionalPseudo( fn ) {
1040 return markFunction(function( argument ) {
1041 argument = +argument;
1042 return markFunction(function( seed, matches ) {
1043 var j,
1044 matchIndexes = fn( [], seed.length, argument ),
1045 i = matchIndexes.length;
1046
1047 // Match elements found at the specified indexes
1048 while ( i-- ) {
1049 if ( seed[ (j = matchIndexes[i]) ] ) {
1050 seed[j] = !(matches[j] = seed[j]);
1051 }
1052 }
1053 });
1054 });
1055}
1056
1057/**
1058 * Checks a node for validity as a Sizzle context
1059 * @param {Element|Object=} context
1060 * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
1061 */
1062function testContext( context ) {
1063 return context && typeof context.getElementsByTagName !== "undefined" && context;
1064}
1065
1066// Expose support vars for convenience
1067support = Sizzle.support = {};
1068
1069/**
1070 * Detects XML nodes
1071 * @param {Element|Object} elem An element or a document
1072 * @returns {Boolean} True iff elem is a non-HTML XML node
1073 */
1074isXML = Sizzle.isXML = function( elem ) {
1075 var namespace = elem.namespaceURI,
1076 docElem = (elem.ownerDocument || elem).documentElement;
1077
1078 // Support: IE <=8
1079 // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes
1080 // https://bugs.jquery.com/ticket/4833
1081 return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" );
1082};
1083
1084/**
1085 * Sets document-related variables once based on the current document
1086 * @param {Element|Object} [doc] An element or document object to use to set the document
1087 * @returns {Object} Returns the current document
1088 */
1089setDocument = Sizzle.setDocument = function( node ) {
1090 var hasCompare, subWindow,
1091 doc = node ? node.ownerDocument || node : preferredDoc;
1092
1093 // Return early if doc is invalid or already selected
1094 if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
1095 return document;
1096 }
1097
1098 // Update global variables
1099 document = doc;
1100 docElem = document.documentElement;
1101 documentIsHTML = !isXML( document );
1102
1103 // Support: IE 9-11, Edge
1104 // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936)
1105 if ( preferredDoc !== document &&
1106 (subWindow = document.defaultView) && subWindow.top !== subWindow ) {
1107
1108 // Support: IE 11, Edge
1109 if ( subWindow.addEventListener ) {
1110 subWindow.addEventListener( "unload", unloadHandler, false );
1111
1112 // Support: IE 9 - 10 only
1113 } else if ( subWindow.attachEvent ) {
1114 subWindow.attachEvent( "onunload", unloadHandler );
1115 }
1116 }
1117
1118 /* Attributes
1119 ---------------------------------------------------------------------- */
1120
1121 // Support: IE<8
1122 // Verify that getAttribute really returns attributes and not properties
1123 // (excepting IE8 booleans)
1124 support.attributes = assert(function( el ) {
1125 el.className = "i";
1126 return !el.getAttribute("className");
1127 });
1128
1129 /* getElement(s)By*
1130 ---------------------------------------------------------------------- */
1131
1132 // Check if getElementsByTagName("*") returns only elements
1133 support.getElementsByTagName = assert(function( el ) {
1134 el.appendChild( document.createComment("") );
1135 return !el.getElementsByTagName("*").length;
1136 });
1137
1138 // Support: IE<9
1139 support.getElementsByClassName = rnative.test( document.getElementsByClassName );
1140
1141 // Support: IE<10
1142 // Check if getElementById returns elements by name
1143 // The broken getElementById methods don't pick up programmatically-set names,
1144 // so use a roundabout getElementsByName test
1145 support.getById = assert(function( el ) {
1146 docElem.appendChild( el ).id = expando;
1147 return !document.getElementsByName || !document.getElementsByName( expando ).length;
1148 });
1149
1150 // ID filter and find
1151 if ( support.getById ) {
1152 Expr.filter["ID"] = function( id ) {
1153 var attrId = id.replace( runescape, funescape );
1154 return function( elem ) {
1155 return elem.getAttribute("id") === attrId;
1156 };
1157 };
1158 Expr.find["ID"] = function( id, context ) {
1159 if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
1160 var elem = context.getElementById( id );
1161 return elem ? [ elem ] : [];
1162 }
1163 };
1164 } else {
1165 Expr.filter["ID"] = function( id ) {
1166 var attrId = id.replace( runescape, funescape );
1167 return function( elem ) {
1168 var node = typeof elem.getAttributeNode !== "undefined" &&
1169 elem.getAttributeNode("id");
1170 return node && node.value === attrId;
1171 };
1172 };
1173
1174 // Support: IE 6 - 7 only
1175 // getElementById is not reliable as a find shortcut
1176 Expr.find["ID"] = function( id, context ) {
1177 if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
1178 var node, i, elems,
1179 elem = context.getElementById( id );
1180
1181 if ( elem ) {
1182
1183 // Verify the id attribute
1184 node = elem.getAttributeNode("id");
1185 if ( node && node.value === id ) {
1186 return [ elem ];
1187 }
1188
1189 // Fall back on getElementsByName
1190 elems = context.getElementsByName( id );
1191 i = 0;
1192 while ( (elem = elems[i++]) ) {
1193 node = elem.getAttributeNode("id");
1194 if ( node && node.value === id ) {
1195 return [ elem ];
1196 }
1197 }
1198 }
1199
1200 return [];
1201 }
1202 };
1203 }
1204
1205 // Tag
1206 Expr.find["TAG"] = support.getElementsByTagName ?
1207 function( tag, context ) {
1208 if ( typeof context.getElementsByTagName !== "undefined" ) {
1209 return context.getElementsByTagName( tag );
1210
1211 // DocumentFragment nodes don't have gEBTN
1212 } else if ( support.qsa ) {
1213 return context.querySelectorAll( tag );
1214 }
1215 } :
1216
1217 function( tag, context ) {
1218 var elem,
1219 tmp = [],
1220 i = 0,
1221 // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too
1222 results = context.getElementsByTagName( tag );
1223
1224 // Filter out possible comments
1225 if ( tag === "*" ) {
1226 while ( (elem = results[i++]) ) {
1227 if ( elem.nodeType === 1 ) {
1228 tmp.push( elem );
1229 }
1230 }
1231
1232 return tmp;
1233 }
1234 return results;
1235 };
1236
1237 // Class
1238 Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
1239 if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) {
1240 return context.getElementsByClassName( className );
1241 }
1242 };
1243
1244 /* QSA/matchesSelector
1245 ---------------------------------------------------------------------- */
1246
1247 // QSA and matchesSelector support
1248
1249 // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
1250 rbuggyMatches = [];
1251
1252 // qSa(:focus) reports false when true (Chrome 21)
1253 // We allow this because of a bug in IE8/9 that throws an error
1254 // whenever `document.activeElement` is accessed on an iframe
1255 // So, we allow :focus to pass through QSA all the time to avoid the IE error
1256 // See https://bugs.jquery.com/ticket/13378
1257 rbuggyQSA = [];
1258
1259 if ( (support.qsa = rnative.test( document.querySelectorAll )) ) {
1260 // Build QSA regex
1261 // Regex strategy adopted from Diego Perini
1262 assert(function( el ) {
1263 // Select is set to empty string on purpose
1264 // This is to test IE's treatment of not explicitly
1265 // setting a boolean content attribute,
1266 // since its presence should be enough
1267 // https://bugs.jquery.com/ticket/12359
1268 docElem.appendChild( el ).innerHTML = "<a id='" + expando + "'></a>" +
1269 "<select id='" + expando + "-\r\\' msallowcapture=''>" +
1270 "<option selected=''></option></select>";
1271
1272 // Support: IE8, Opera 11-12.16
1273 // Nothing should be selected when empty strings follow ^= or $= or *=
1274 // The test attribute must be unknown in Opera but "safe" for WinRT
1275 // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
1276 if ( el.querySelectorAll("[msallowcapture^='']").length ) {
1277 rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
1278 }
1279
1280 // Support: IE8
1281 // Boolean attributes and "value" are not treated correctly
1282 if ( !el.querySelectorAll("[selected]").length ) {
1283 rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
1284 }
1285
1286 // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+
1287 if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) {
1288 rbuggyQSA.push("~=");
1289 }
1290
1291 // Webkit/Opera - :checked should return selected option elements
1292 // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
1293 // IE8 throws error here and will not see later tests
1294 if ( !el.querySelectorAll(":checked").length ) {
1295 rbuggyQSA.push(":checked");
1296 }
1297
1298 // Support: Safari 8+, iOS 8+
1299 // https://bugs.webkit.org/show_bug.cgi?id=136851
1300 // In-page `selector#id sibling-combinator selector` fails
1301 if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) {
1302 rbuggyQSA.push(".#.+[+~]");
1303 }
1304 });
1305
1306 assert(function( el ) {
1307 el.innerHTML = "<a href='' disabled='disabled'></a>" +
1308 "<select disabled='disabled'><option/></select>";
1309
1310 // Support: Windows 8 Native Apps
1311 // The type and name attributes are restricted during .innerHTML assignment
1312 var input = document.createElement("input");
1313 input.setAttribute( "type", "hidden" );
1314 el.appendChild( input ).setAttribute( "name", "D" );
1315
1316 // Support: IE8
1317 // Enforce case-sensitivity of name attribute
1318 if ( el.querySelectorAll("[name=d]").length ) {
1319 rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
1320 }
1321
1322 // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
1323 // IE8 throws error here and will not see later tests
1324 if ( el.querySelectorAll(":enabled").length !== 2 ) {
1325 rbuggyQSA.push( ":enabled", ":disabled" );
1326 }
1327
1328 // Support: IE9-11+
1329 // IE's :disabled selector does not pick up the children of disabled fieldsets
1330 docElem.appendChild( el ).disabled = true;
1331 if ( el.querySelectorAll(":disabled").length !== 2 ) {
1332 rbuggyQSA.push( ":enabled", ":disabled" );
1333 }
1334
1335 // Opera 10-11 does not throw on post-comma invalid pseudos
1336 el.querySelectorAll("*,:x");
1337 rbuggyQSA.push(",.*:");
1338 });
1339 }
1340
1341 if ( (support.matchesSelector = rnative.test( (matches = docElem.matches ||
1342 docElem.webkitMatchesSelector ||
1343 docElem.mozMatchesSelector ||
1344 docElem.oMatchesSelector ||
1345 docElem.msMatchesSelector) )) ) {
1346
1347 assert(function( el ) {
1348 // Check to see if it's possible to do matchesSelector
1349 // on a disconnected node (IE 9)
1350 support.disconnectedMatch = matches.call( el, "*" );
1351
1352 // This should fail with an exception
1353 // Gecko does not error, returns false instead
1354 matches.call( el, "[s!='']:x" );
1355 rbuggyMatches.push( "!=", pseudos );
1356 });
1357 }
1358
1359 rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
1360 rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
1361
1362 /* Contains
1363 ---------------------------------------------------------------------- */
1364 hasCompare = rnative.test( docElem.compareDocumentPosition );
1365
1366 // Element contains another
1367 // Purposefully self-exclusive
1368 // As in, an element does not contain itself
1369 contains = hasCompare || rnative.test( docElem.contains ) ?
1370 function( a, b ) {
1371 var adown = a.nodeType === 9 ? a.documentElement : a,
1372 bup = b && b.parentNode;
1373 return a === bup || !!( bup && bup.nodeType === 1 && (
1374 adown.contains ?
1375 adown.contains( bup ) :
1376 a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
1377 ));
1378 } :
1379 function( a, b ) {
1380 if ( b ) {
1381 while ( (b = b.parentNode) ) {
1382 if ( b === a ) {
1383 return true;
1384 }
1385 }
1386 }
1387 return false;
1388 };
1389
1390 /* Sorting
1391 ---------------------------------------------------------------------- */
1392
1393 // Document order sorting
1394 sortOrder = hasCompare ?
1395 function( a, b ) {
1396
1397 // Flag for duplicate removal
1398 if ( a === b ) {
1399 hasDuplicate = true;
1400 return 0;
1401 }
1402
1403 // Sort on method existence if only one input has compareDocumentPosition
1404 var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
1405 if ( compare ) {
1406 return compare;
1407 }
1408
1409 // Calculate position if both inputs belong to the same document
1410 compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?
1411 a.compareDocumentPosition( b ) :
1412
1413 // Otherwise we know they are disconnected
1414 1;
1415
1416 // Disconnected nodes
1417 if ( compare & 1 ||
1418 (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
1419
1420 // Choose the first element that is related to our preferred document
1421 if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {
1422 return -1;
1423 }
1424 if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {
1425 return 1;
1426 }
1427
1428 // Maintain original order
1429 return sortInput ?
1430 ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
1431 0;
1432 }
1433
1434 return compare & 4 ? -1 : 1;
1435 } :
1436 function( a, b ) {
1437 // Exit early if the nodes are identical
1438 if ( a === b ) {
1439 hasDuplicate = true;
1440 return 0;
1441 }
1442
1443 var cur,
1444 i = 0,
1445 aup = a.parentNode,
1446 bup = b.parentNode,
1447 ap = [ a ],
1448 bp = [ b ];
1449
1450 // Parentless nodes are either documents or disconnected
1451 if ( !aup || !bup ) {
1452 return a === document ? -1 :
1453 b === document ? 1 :
1454 aup ? -1 :
1455 bup ? 1 :
1456 sortInput ?
1457 ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
1458 0;
1459
1460 // If the nodes are siblings, we can do a quick check
1461 } else if ( aup === bup ) {
1462 return siblingCheck( a, b );
1463 }
1464
1465 // Otherwise we need full lists of their ancestors for comparison
1466 cur = a;
1467 while ( (cur = cur.parentNode) ) {
1468 ap.unshift( cur );
1469 }
1470 cur = b;
1471 while ( (cur = cur.parentNode) ) {
1472 bp.unshift( cur );
1473 }
1474
1475 // Walk down the tree looking for a discrepancy
1476 while ( ap[i] === bp[i] ) {
1477 i++;
1478 }
1479
1480 return i ?
1481 // Do a sibling check if the nodes have a common ancestor
1482 siblingCheck( ap[i], bp[i] ) :
1483
1484 // Otherwise nodes in our document sort first
1485 ap[i] === preferredDoc ? -1 :
1486 bp[i] === preferredDoc ? 1 :
1487 0;
1488 };
1489
1490 return document;
1491};
1492
1493Sizzle.matches = function( expr, elements ) {
1494 return Sizzle( expr, null, null, elements );
1495};
1496
1497Sizzle.matchesSelector = function( elem, expr ) {
1498 // Set document vars if needed
1499 if ( ( elem.ownerDocument || elem ) !== document ) {
1500 setDocument( elem );
1501 }
1502
1503 if ( support.matchesSelector && documentIsHTML &&
1504 !nonnativeSelectorCache[ expr + " " ] &&
1505 ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
1506 ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) {
1507
1508 try {
1509 var ret = matches.call( elem, expr );
1510
1511 // IE 9's matchesSelector returns false on disconnected nodes
1512 if ( ret || support.disconnectedMatch ||
1513 // As well, disconnected nodes are said to be in a document
1514 // fragment in IE 9
1515 elem.document && elem.document.nodeType !== 11 ) {
1516 return ret;
1517 }
1518 } catch (e) {
1519 nonnativeSelectorCache( expr, true );
1520 }
1521 }
1522
1523 return Sizzle( expr, document, null, [ elem ] ).length > 0;
1524};
1525
1526Sizzle.contains = function( context, elem ) {
1527 // Set document vars if needed
1528 if ( ( context.ownerDocument || context ) !== document ) {
1529 setDocument( context );
1530 }
1531 return contains( context, elem );
1532};
1533
1534Sizzle.attr = function( elem, name ) {
1535 // Set document vars if needed
1536 if ( ( elem.ownerDocument || elem ) !== document ) {
1537 setDocument( elem );
1538 }
1539
1540 var fn = Expr.attrHandle[ name.toLowerCase() ],
1541 // Don't get fooled by Object.prototype properties (jQuery #13807)
1542 val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
1543 fn( elem, name, !documentIsHTML ) :
1544 undefined;
1545
1546 return val !== undefined ?
1547 val :
1548 support.attributes || !documentIsHTML ?
1549 elem.getAttribute( name ) :
1550 (val = elem.getAttributeNode(name)) && val.specified ?
1551 val.value :
1552 null;
1553};
1554
1555Sizzle.escape = function( sel ) {
1556 return (sel + "").replace( rcssescape, fcssescape );
1557};
1558
1559Sizzle.error = function( msg ) {
1560 throw new Error( "Syntax error, unrecognized expression: " + msg );
1561};
1562
1563/**
1564 * Document sorting and removing duplicates
1565 * @param {ArrayLike} results
1566 */
1567Sizzle.uniqueSort = function( results ) {
1568 var elem,
1569 duplicates = [],
1570 j = 0,
1571 i = 0;
1572
1573 // Unless we *know* we can detect duplicates, assume their presence
1574 hasDuplicate = !support.detectDuplicates;
1575 sortInput = !support.sortStable && results.slice( 0 );
1576 results.sort( sortOrder );
1577
1578 if ( hasDuplicate ) {
1579 while ( (elem = results[i++]) ) {
1580 if ( elem === results[ i ] ) {
1581 j = duplicates.push( i );
1582 }
1583 }
1584 while ( j-- ) {
1585 results.splice( duplicates[ j ], 1 );
1586 }
1587 }
1588
1589 // Clear input after sorting to release objects
1590 // See https://github.com/jquery/sizzle/pull/225
1591 sortInput = null;
1592
1593 return results;
1594};
1595
1596/**
1597 * Utility function for retrieving the text value of an array of DOM nodes
1598 * @param {Array|Element} elem
1599 */
1600getText = Sizzle.getText = function( elem ) {
1601 var node,
1602 ret = "",
1603 i = 0,
1604 nodeType = elem.nodeType;
1605
1606 if ( !nodeType ) {
1607 // If no nodeType, this is expected to be an array
1608 while ( (node = elem[i++]) ) {
1609 // Do not traverse comment nodes
1610 ret += getText( node );
1611 }
1612 } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
1613 // Use textContent for elements
1614 // innerText usage removed for consistency of new lines (jQuery #11153)
1615 if ( typeof elem.textContent === "string" ) {
1616 return elem.textContent;
1617 } else {
1618 // Traverse its children
1619 for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
1620 ret += getText( elem );
1621 }
1622 }
1623 } else if ( nodeType === 3 || nodeType === 4 ) {
1624 return elem.nodeValue;
1625 }
1626 // Do not include comment or processing instruction nodes
1627
1628 return ret;
1629};
1630
1631Expr = Sizzle.selectors = {
1632
1633 // Can be adjusted by the user
1634 cacheLength: 50,
1635
1636 createPseudo: markFunction,
1637
1638 match: matchExpr,
1639
1640 attrHandle: {},
1641
1642 find: {},
1643
1644 relative: {
1645 ">": { dir: "parentNode", first: true },
1646 " ": { dir: "parentNode" },
1647 "+": { dir: "previousSibling", first: true },
1648 "~": { dir: "previousSibling" }
1649 },
1650
1651 preFilter: {
1652 "ATTR": function( match ) {
1653 match[1] = match[1].replace( runescape, funescape );
1654
1655 // Move the given value to match[3] whether quoted or unquoted
1656 match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape );
1657
1658 if ( match[2] === "~=" ) {
1659 match[3] = " " + match[3] + " ";
1660 }
1661
1662 return match.slice( 0, 4 );
1663 },
1664
1665 "CHILD": function( match ) {
1666 /* matches from matchExpr["CHILD"]
1667 1 type (only|nth|...)
1668 2 what (child|of-type)
1669 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
1670 4 xn-component of xn+y argument ([+-]?\d*n|)
1671 5 sign of xn-component
1672 6 x of xn-component
1673 7 sign of y-component
1674 8 y of y-component
1675 */
1676 match[1] = match[1].toLowerCase();
1677
1678 if ( match[1].slice( 0, 3 ) === "nth" ) {
1679 // nth-* requires argument
1680 if ( !match[3] ) {
1681 Sizzle.error( match[0] );
1682 }
1683
1684 // numeric x and y parameters for Expr.filter.CHILD
1685 // remember that false/true cast respectively to 0/1
1686 match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
1687 match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
1688
1689 // other types prohibit arguments
1690 } else if ( match[3] ) {
1691 Sizzle.error( match[0] );
1692 }
1693
1694 return match;
1695 },
1696
1697 "PSEUDO": function( match ) {
1698 var excess,
1699 unquoted = !match[6] && match[2];
1700
1701 if ( matchExpr["CHILD"].test( match[0] ) ) {
1702 return null;
1703 }
1704
1705 // Accept quoted arguments as-is
1706 if ( match[3] ) {
1707 match[2] = match[4] || match[5] || "";
1708
1709 // Strip excess characters from unquoted arguments
1710 } else if ( unquoted && rpseudo.test( unquoted ) &&
1711 // Get excess from tokenize (recursively)
1712 (excess = tokenize( unquoted, true )) &&
1713 // advance to the next closing parenthesis
1714 (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
1715
1716 // excess is a negative index
1717 match[0] = match[0].slice( 0, excess );
1718 match[2] = unquoted.slice( 0, excess );
1719 }
1720
1721 // Return only captures needed by the pseudo filter method (type and argument)
1722 return match.slice( 0, 3 );
1723 }
1724 },
1725
1726 filter: {
1727
1728 "TAG": function( nodeNameSelector ) {
1729 var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
1730 return nodeNameSelector === "*" ?
1731 function() { return true; } :
1732 function( elem ) {
1733 return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
1734 };
1735 },
1736
1737 "CLASS": function( className ) {
1738 var pattern = classCache[ className + " " ];
1739
1740 return pattern ||
1741 (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
1742 classCache( className, function( elem ) {
1743 return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" );
1744 });
1745 },
1746
1747 "ATTR": function( name, operator, check ) {
1748 return function( elem ) {
1749 var result = Sizzle.attr( elem, name );
1750
1751 if ( result == null ) {
1752 return operator === "!=";
1753 }
1754 if ( !operator ) {
1755 return true;
1756 }
1757
1758 result += "";
1759
1760 return operator === "=" ? result === check :
1761 operator === "!=" ? result !== check :
1762 operator === "^=" ? check && result.indexOf( check ) === 0 :
1763 operator === "*=" ? check && result.indexOf( check ) > -1 :
1764 operator === "$=" ? check && result.slice( -check.length ) === check :
1765 operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 :
1766 operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
1767 false;
1768 };
1769 },
1770
1771 "CHILD": function( type, what, argument, first, last ) {
1772 var simple = type.slice( 0, 3 ) !== "nth",
1773 forward = type.slice( -4 ) !== "last",
1774 ofType = what === "of-type";
1775
1776 return first === 1 && last === 0 ?
1777
1778 // Shortcut for :nth-*(n)
1779 function( elem ) {
1780 return !!elem.parentNode;
1781 } :
1782
1783 function( elem, context, xml ) {
1784 var cache, uniqueCache, outerCache, node, nodeIndex, start,
1785 dir = simple !== forward ? "nextSibling" : "previousSibling",
1786 parent = elem.parentNode,
1787 name = ofType && elem.nodeName.toLowerCase(),
1788 useCache = !xml && !ofType,
1789 diff = false;
1790
1791 if ( parent ) {
1792
1793 // :(first|last|only)-(child|of-type)
1794 if ( simple ) {
1795 while ( dir ) {
1796 node = elem;
1797 while ( (node = node[ dir ]) ) {
1798 if ( ofType ?
1799 node.nodeName.toLowerCase() === name :
1800 node.nodeType === 1 ) {
1801
1802 return false;
1803 }
1804 }
1805 // Reverse direction for :only-* (if we haven't yet done so)
1806 start = dir = type === "only" && !start && "nextSibling";
1807 }
1808 return true;
1809 }
1810
1811 start = [ forward ? parent.firstChild : parent.lastChild ];
1812
1813 // non-xml :nth-child(...) stores cache data on `parent`
1814 if ( forward && useCache ) {
1815
1816 // Seek `elem` from a previously-cached index
1817
1818 // ...in a gzip-friendly way
1819 node = parent;
1820 outerCache = node[ expando ] || (node[ expando ] = {});
1821
1822 // Support: IE <9 only
1823 // Defend against cloned attroperties (jQuery gh-1709)
1824 uniqueCache = outerCache[ node.uniqueID ] ||
1825 (outerCache[ node.uniqueID ] = {});
1826
1827 cache = uniqueCache[ type ] || [];
1828 nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
1829 diff = nodeIndex && cache[ 2 ];
1830 node = nodeIndex && parent.childNodes[ nodeIndex ];
1831
1832 while ( (node = ++nodeIndex && node && node[ dir ] ||
1833
1834 // Fallback to seeking `elem` from the start
1835 (diff = nodeIndex = 0) || start.pop()) ) {
1836
1837 // When found, cache indexes on `parent` and break
1838 if ( node.nodeType === 1 && ++diff && node === elem ) {
1839 uniqueCache[ type ] = [ dirruns, nodeIndex, diff ];
1840 break;
1841 }
1842 }
1843
1844 } else {
1845 // Use previously-cached element index if available
1846 if ( useCache ) {
1847 // ...in a gzip-friendly way
1848 node = elem;
1849 outerCache = node[ expando ] || (node[ expando ] = {});
1850
1851 // Support: IE <9 only
1852 // Defend against cloned attroperties (jQuery gh-1709)
1853 uniqueCache = outerCache[ node.uniqueID ] ||
1854 (outerCache[ node.uniqueID ] = {});
1855
1856 cache = uniqueCache[ type ] || [];
1857 nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
1858 diff = nodeIndex;
1859 }
1860
1861 // xml :nth-child(...)
1862 // or :nth-last-child(...) or :nth(-last)?-of-type(...)
1863 if ( diff === false ) {
1864 // Use the same loop as above to seek `elem` from the start
1865 while ( (node = ++nodeIndex && node && node[ dir ] ||
1866 (diff = nodeIndex = 0) || start.pop()) ) {
1867
1868 if ( ( ofType ?
1869 node.nodeName.toLowerCase() === name :
1870 node.nodeType === 1 ) &&
1871 ++diff ) {
1872
1873 // Cache the index of each encountered element
1874 if ( useCache ) {
1875 outerCache = node[ expando ] || (node[ expando ] = {});
1876
1877 // Support: IE <9 only
1878 // Defend against cloned attroperties (jQuery gh-1709)
1879 uniqueCache = outerCache[ node.uniqueID ] ||
1880 (outerCache[ node.uniqueID ] = {});
1881
1882 uniqueCache[ type ] = [ dirruns, diff ];
1883 }
1884
1885 if ( node === elem ) {
1886 break;
1887 }
1888 }
1889 }
1890 }
1891 }
1892
1893 // Incorporate the offset, then check against cycle size
1894 diff -= last;
1895 return diff === first || ( diff % first === 0 && diff / first >= 0 );
1896 }
1897 };
1898 },
1899
1900 "PSEUDO": function( pseudo, argument ) {
1901 // pseudo-class names are case-insensitive
1902 // http://www.w3.org/TR/selectors/#pseudo-classes
1903 // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
1904 // Remember that setFilters inherits from pseudos
1905 var args,
1906 fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
1907 Sizzle.error( "unsupported pseudo: " + pseudo );
1908
1909 // The user may use createPseudo to indicate that
1910 // arguments are needed to create the filter function
1911 // just as Sizzle does
1912 if ( fn[ expando ] ) {
1913 return fn( argument );
1914 }
1915
1916 // But maintain support for old signatures
1917 if ( fn.length > 1 ) {
1918 args = [ pseudo, pseudo, "", argument ];
1919 return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
1920 markFunction(function( seed, matches ) {
1921 var idx,
1922 matched = fn( seed, argument ),
1923 i = matched.length;
1924 while ( i-- ) {
1925 idx = indexOf( seed, matched[i] );
1926 seed[ idx ] = !( matches[ idx ] = matched[i] );
1927 }
1928 }) :
1929 function( elem ) {
1930 return fn( elem, 0, args );
1931 };
1932 }
1933
1934 return fn;
1935 }
1936 },
1937
1938 pseudos: {
1939 // Potentially complex pseudos
1940 "not": markFunction(function( selector ) {
1941 // Trim the selector passed to compile
1942 // to avoid treating leading and trailing
1943 // spaces as combinators
1944 var input = [],
1945 results = [],
1946 matcher = compile( selector.replace( rtrim, "$1" ) );
1947
1948 return matcher[ expando ] ?
1949 markFunction(function( seed, matches, context, xml ) {
1950 var elem,
1951 unmatched = matcher( seed, null, xml, [] ),
1952 i = seed.length;
1953
1954 // Match elements unmatched by `matcher`
1955 while ( i-- ) {
1956 if ( (elem = unmatched[i]) ) {
1957 seed[i] = !(matches[i] = elem);
1958 }
1959 }
1960 }) :
1961 function( elem, context, xml ) {
1962 input[0] = elem;
1963 matcher( input, null, xml, results );
1964 // Don't keep the element (issue #299)
1965 input[0] = null;
1966 return !results.pop();
1967 };
1968 }),
1969
1970 "has": markFunction(function( selector ) {
1971 return function( elem ) {
1972 return Sizzle( selector, elem ).length > 0;
1973 };
1974 }),
1975
1976 "contains": markFunction(function( text ) {
1977 text = text.replace( runescape, funescape );
1978 return function( elem ) {
1979 return ( elem.textContent || getText( elem ) ).indexOf( text ) > -1;
1980 };
1981 }),
1982
1983 // "Whether an element is represented by a :lang() selector
1984 // is based solely on the element's language value
1985 // being equal to the identifier C,
1986 // or beginning with the identifier C immediately followed by "-".
1987 // The matching of C against the element's language value is performed case-insensitively.
1988 // The identifier C does not have to be a valid language name."
1989 // http://www.w3.org/TR/selectors/#lang-pseudo
1990 "lang": markFunction( function( lang ) {
1991 // lang value must be a valid identifier
1992 if ( !ridentifier.test(lang || "") ) {
1993 Sizzle.error( "unsupported lang: " + lang );
1994 }
1995 lang = lang.replace( runescape, funescape ).toLowerCase();
1996 return function( elem ) {
1997 var elemLang;
1998 do {
1999 if ( (elemLang = documentIsHTML ?
2000 elem.lang :
2001 elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
2002
2003 elemLang = elemLang.toLowerCase();
2004 return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
2005 }
2006 } while ( (elem = elem.parentNode) && elem.nodeType === 1 );
2007 return false;
2008 };
2009 }),
2010
2011 // Miscellaneous
2012 "target": function( elem ) {
2013 var hash = window.location && window.location.hash;
2014 return hash && hash.slice( 1 ) === elem.id;
2015 },
2016
2017 "root": function( elem ) {
2018 return elem === docElem;
2019 },
2020
2021 "focus": function( elem ) {
2022 return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
2023 },
2024
2025 // Boolean properties
2026 "enabled": createDisabledPseudo( false ),
2027 "disabled": createDisabledPseudo( true ),
2028
2029 "checked": function( elem ) {
2030 // In CSS3, :checked should return both checked and selected elements
2031 // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
2032 var nodeName = elem.nodeName.toLowerCase();
2033 return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
2034 },
2035
2036 "selected": function( elem ) {
2037 // Accessing this property makes selected-by-default
2038 // options in Safari work properly
2039 if ( elem.parentNode ) {
2040 elem.parentNode.selectedIndex;
2041 }
2042
2043 return elem.selected === true;
2044 },
2045
2046 // Contents
2047 "empty": function( elem ) {
2048 // http://www.w3.org/TR/selectors/#empty-pseudo
2049 // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
2050 // but not by others (comment: 8; processing instruction: 7; etc.)
2051 // nodeType < 6 works because attributes (2) do not appear as children
2052 for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
2053 if ( elem.nodeType < 6 ) {
2054 return false;
2055 }
2056 }
2057 return true;
2058 },
2059
2060 "parent": function( elem ) {
2061 return !Expr.pseudos["empty"]( elem );
2062 },
2063
2064 // Element/input types
2065 "header": function( elem ) {
2066 return rheader.test( elem.nodeName );
2067 },
2068
2069 "input": function( elem ) {
2070 return rinputs.test( elem.nodeName );
2071 },
2072
2073 "button": function( elem ) {
2074 var name = elem.nodeName.toLowerCase();
2075 return name === "input" && elem.type === "button" || name === "button";
2076 },
2077
2078 "text": function( elem ) {
2079 var attr;
2080 return elem.nodeName.toLowerCase() === "input" &&
2081 elem.type === "text" &&
2082
2083 // Support: IE<8
2084 // New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
2085 ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" );
2086 },
2087
2088 // Position-in-collection
2089 "first": createPositionalPseudo(function() {
2090 return [ 0 ];
2091 }),
2092
2093 "last": createPositionalPseudo(function( matchIndexes, length ) {
2094 return [ length - 1 ];
2095 }),
2096
2097 "eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
2098 return [ argument < 0 ? argument + length : argument ];
2099 }),
2100
2101 "even": createPositionalPseudo(function( matchIndexes, length ) {
2102 var i = 0;
2103 for ( ; i < length; i += 2 ) {
2104 matchIndexes.push( i );
2105 }
2106 return matchIndexes;
2107 }),
2108
2109 "odd": createPositionalPseudo(function( matchIndexes, length ) {
2110 var i = 1;
2111 for ( ; i < length; i += 2 ) {
2112 matchIndexes.push( i );
2113 }
2114 return matchIndexes;
2115 }),
2116
2117 "lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
2118 var i = argument < 0 ?
2119 argument + length :
2120 argument > length ?
2121 length :
2122 argument;
2123 for ( ; --i >= 0; ) {
2124 matchIndexes.push( i );
2125 }
2126 return matchIndexes;
2127 }),
2128
2129 "gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
2130 var i = argument < 0 ? argument + length : argument;
2131 for ( ; ++i < length; ) {
2132 matchIndexes.push( i );
2133 }
2134 return matchIndexes;
2135 })
2136 }
2137};
2138
2139Expr.pseudos["nth"] = Expr.pseudos["eq"];
2140
2141// Add button/input type pseudos
2142for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
2143 Expr.pseudos[ i ] = createInputPseudo( i );
2144}
2145for ( i in { submit: true, reset: true } ) {
2146 Expr.pseudos[ i ] = createButtonPseudo( i );
2147}
2148
2149// Easy API for creating new setFilters
2150function setFilters() {}
2151setFilters.prototype = Expr.filters = Expr.pseudos;
2152Expr.setFilters = new setFilters();
2153
2154tokenize = Sizzle.tokenize = function( selector, parseOnly ) {
2155 var matched, match, tokens, type,
2156 soFar, groups, preFilters,
2157 cached = tokenCache[ selector + " " ];
2158
2159 if ( cached ) {
2160 return parseOnly ? 0 : cached.slice( 0 );
2161 }
2162
2163 soFar = selector;
2164 groups = [];
2165 preFilters = Expr.preFilter;
2166
2167 while ( soFar ) {
2168
2169 // Comma and first run
2170 if ( !matched || (match = rcomma.exec( soFar )) ) {
2171 if ( match ) {
2172 // Don't consume trailing commas as valid
2173 soFar = soFar.slice( match[0].length ) || soFar;
2174 }
2175 groups.push( (tokens = []) );
2176 }
2177
2178 matched = false;
2179
2180 // Combinators
2181 if ( (match = rcombinators.exec( soFar )) ) {
2182 matched = match.shift();
2183 tokens.push({
2184 value: matched,
2185 // Cast descendant combinators to space
2186 type: match[0].replace( rtrim, " " )
2187 });
2188 soFar = soFar.slice( matched.length );
2189 }
2190
2191 // Filters
2192 for ( type in Expr.filter ) {
2193 if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
2194 (match = preFilters[ type ]( match ))) ) {
2195 matched = match.shift();
2196 tokens.push({
2197 value: matched,
2198 type: type,
2199 matches: match
2200 });
2201 soFar = soFar.slice( matched.length );
2202 }
2203 }
2204
2205 if ( !matched ) {
2206 break;
2207 }
2208 }
2209
2210 // Return the length of the invalid excess
2211 // if we're just parsing
2212 // Otherwise, throw an error or return tokens
2213 return parseOnly ?
2214 soFar.length :
2215 soFar ?
2216 Sizzle.error( selector ) :
2217 // Cache the tokens
2218 tokenCache( selector, groups ).slice( 0 );
2219};
2220
2221function toSelector( tokens ) {
2222 var i = 0,
2223 len = tokens.length,
2224 selector = "";
2225 for ( ; i < len; i++ ) {
2226 selector += tokens[i].value;
2227 }
2228 return selector;
2229}
2230
2231function addCombinator( matcher, combinator, base ) {
2232 var dir = combinator.dir,
2233 skip = combinator.next,
2234 key = skip || dir,
2235 checkNonElements = base && key === "parentNode",
2236 doneName = done++;
2237
2238 return combinator.first ?
2239 // Check against closest ancestor/preceding element
2240 function( elem, context, xml ) {
2241 while ( (elem = elem[ dir ]) ) {
2242 if ( elem.nodeType === 1 || checkNonElements ) {
2243 return matcher( elem, context, xml );
2244 }
2245 }
2246 return false;
2247 } :
2248
2249 // Check against all ancestor/preceding elements
2250 function( elem, context, xml ) {
2251 var oldCache, uniqueCache, outerCache,
2252 newCache = [ dirruns, doneName ];
2253
2254 // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching
2255 if ( xml ) {
2256 while ( (elem = elem[ dir ]) ) {
2257 if ( elem.nodeType === 1 || checkNonElements ) {
2258 if ( matcher( elem, context, xml ) ) {
2259 return true;
2260 }
2261 }
2262 }
2263 } else {
2264 while ( (elem = elem[ dir ]) ) {
2265 if ( elem.nodeType === 1 || checkNonElements ) {
2266 outerCache = elem[ expando ] || (elem[ expando ] = {});
2267
2268 // Support: IE <9 only
2269 // Defend against cloned attroperties (jQuery gh-1709)
2270 uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {});
2271
2272 if ( skip && skip === elem.nodeName.toLowerCase() ) {
2273 elem = elem[ dir ] || elem;
2274 } else if ( (oldCache = uniqueCache[ key ]) &&
2275 oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
2276
2277 // Assign to newCache so results back-propagate to previous elements
2278 return (newCache[ 2 ] = oldCache[ 2 ]);
2279 } else {
2280 // Reuse newcache so results back-propagate to previous elements
2281 uniqueCache[ key ] = newCache;
2282
2283 // A match means we're done; a fail means we have to keep checking
2284 if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {
2285 return true;
2286 }
2287 }
2288 }
2289 }
2290 }
2291 return false;
2292 };
2293}
2294
2295function elementMatcher( matchers ) {
2296 return matchers.length > 1 ?
2297 function( elem, context, xml ) {
2298 var i = matchers.length;
2299 while ( i-- ) {
2300 if ( !matchers[i]( elem, context, xml ) ) {
2301 return false;
2302 }
2303 }
2304 return true;
2305 } :
2306 matchers[0];
2307}
2308
2309function multipleContexts( selector, contexts, results ) {
2310 var i = 0,
2311 len = contexts.length;
2312 for ( ; i < len; i++ ) {
2313 Sizzle( selector, contexts[i], results );
2314 }
2315 return results;
2316}
2317
2318function condense( unmatched, map, filter, context, xml ) {
2319 var elem,
2320 newUnmatched = [],
2321 i = 0,
2322 len = unmatched.length,
2323 mapped = map != null;
2324
2325 for ( ; i < len; i++ ) {
2326 if ( (elem = unmatched[i]) ) {
2327 if ( !filter || filter( elem, context, xml ) ) {
2328 newUnmatched.push( elem );
2329 if ( mapped ) {
2330 map.push( i );
2331 }
2332 }
2333 }
2334 }
2335
2336 return newUnmatched;
2337}
2338
2339function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
2340 if ( postFilter && !postFilter[ expando ] ) {
2341 postFilter = setMatcher( postFilter );
2342 }
2343 if ( postFinder && !postFinder[ expando ] ) {
2344 postFinder = setMatcher( postFinder, postSelector );
2345 }
2346 return markFunction(function( seed, results, context, xml ) {
2347 var temp, i, elem,
2348 preMap = [],
2349 postMap = [],
2350 preexisting = results.length,
2351
2352 // Get initial elements from seed or context
2353 elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
2354
2355 // Prefilter to get matcher input, preserving a map for seed-results synchronization
2356 matcherIn = preFilter && ( seed || !selector ) ?
2357 condense( elems, preMap, preFilter, context, xml ) :
2358 elems,
2359
2360 matcherOut = matcher ?
2361 // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
2362 postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
2363
2364 // ...intermediate processing is necessary
2365 [] :
2366
2367 // ...otherwise use results directly
2368 results :
2369 matcherIn;
2370
2371 // Find primary matches
2372 if ( matcher ) {
2373 matcher( matcherIn, matcherOut, context, xml );
2374 }
2375
2376 // Apply postFilter
2377 if ( postFilter ) {
2378 temp = condense( matcherOut, postMap );
2379 postFilter( temp, [], context, xml );
2380
2381 // Un-match failing elements by moving them back to matcherIn
2382 i = temp.length;
2383 while ( i-- ) {
2384 if ( (elem = temp[i]) ) {
2385 matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
2386 }
2387 }
2388 }
2389
2390 if ( seed ) {
2391 if ( postFinder || preFilter ) {
2392 if ( postFinder ) {
2393 // Get the final matcherOut by condensing this intermediate into postFinder contexts
2394 temp = [];
2395 i = matcherOut.length;
2396 while ( i-- ) {
2397 if ( (elem = matcherOut[i]) ) {
2398 // Restore matcherIn since elem is not yet a final match
2399 temp.push( (matcherIn[i] = elem) );
2400 }
2401 }
2402 postFinder( null, (matcherOut = []), temp, xml );
2403 }
2404
2405 // Move matched elements from seed to results to keep them synchronized
2406 i = matcherOut.length;
2407 while ( i-- ) {
2408 if ( (elem = matcherOut[i]) &&
2409 (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) {
2410
2411 seed[temp] = !(results[temp] = elem);
2412 }
2413 }
2414 }
2415
2416 // Add elements to results, through postFinder if defined
2417 } else {
2418 matcherOut = condense(
2419 matcherOut === results ?
2420 matcherOut.splice( preexisting, matcherOut.length ) :
2421 matcherOut
2422 );
2423 if ( postFinder ) {
2424 postFinder( null, results, matcherOut, xml );
2425 } else {
2426 push.apply( results, matcherOut );
2427 }
2428 }
2429 });
2430}
2431
2432function matcherFromTokens( tokens ) {
2433 var checkContext, matcher, j,
2434 len = tokens.length,
2435 leadingRelative = Expr.relative[ tokens[0].type ],
2436 implicitRelative = leadingRelative || Expr.relative[" "],
2437 i = leadingRelative ? 1 : 0,
2438
2439 // The foundational matcher ensures that elements are reachable from top-level context(s)
2440 matchContext = addCombinator( function( elem ) {
2441 return elem === checkContext;
2442 }, implicitRelative, true ),
2443 matchAnyContext = addCombinator( function( elem ) {
2444 return indexOf( checkContext, elem ) > -1;
2445 }, implicitRelative, true ),
2446 matchers = [ function( elem, context, xml ) {
2447 var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
2448 (checkContext = context).nodeType ?
2449 matchContext( elem, context, xml ) :
2450 matchAnyContext( elem, context, xml ) );
2451 // Avoid hanging onto element (issue #299)
2452 checkContext = null;
2453 return ret;
2454 } ];
2455
2456 for ( ; i < len; i++ ) {
2457 if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
2458 matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
2459 } else {
2460 matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
2461
2462 // Return special upon seeing a positional matcher
2463 if ( matcher[ expando ] ) {
2464 // Find the next relative operator (if any) for proper handling
2465 j = ++i;
2466 for ( ; j < len; j++ ) {
2467 if ( Expr.relative[ tokens[j].type ] ) {
2468 break;
2469 }
2470 }
2471 return setMatcher(
2472 i > 1 && elementMatcher( matchers ),
2473 i > 1 && toSelector(
2474 // If the preceding token was a descendant combinator, insert an implicit any-element `*`
2475 tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
2476 ).replace( rtrim, "$1" ),
2477 matcher,
2478 i < j && matcherFromTokens( tokens.slice( i, j ) ),
2479 j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
2480 j < len && toSelector( tokens )
2481 );
2482 }
2483 matchers.push( matcher );
2484 }
2485 }
2486
2487 return elementMatcher( matchers );
2488}
2489
2490function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
2491 var bySet = setMatchers.length > 0,
2492 byElement = elementMatchers.length > 0,
2493 superMatcher = function( seed, context, xml, results, outermost ) {
2494 var elem, j, matcher,
2495 matchedCount = 0,
2496 i = "0",
2497 unmatched = seed && [],
2498 setMatched = [],
2499 contextBackup = outermostContext,
2500 // We must always have either seed elements or outermost context
2501 elems = seed || byElement && Expr.find["TAG"]( "*", outermost ),
2502 // Use integer dirruns iff this is the outermost matcher
2503 dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),
2504 len = elems.length;
2505
2506 if ( outermost ) {
2507 outermostContext = context === document || context || outermost;
2508 }
2509
2510 // Add elements passing elementMatchers directly to results
2511 // Support: IE<9, Safari
2512 // Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches