diff --git a/.bumpversion.cfg b/.bumpversion.cfg deleted file mode 100644 index 5f8196e9..00000000 --- a/.bumpversion.cfg +++ /dev/null @@ -1,16 +0,0 @@ -[bumpversion] -current_version = 2.3.0 -parse = (?P\d+)\.(?P\d+)\.(?P\d+) -serialize = {major}.{minor}.{patch} -commit = False -tag = False -allow_dirty = True - -[bumpversion:file:src/adminactions/__init__.py] - -[bumpversion:part:release] -optional_value = final -values = - dev - rc - final diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..f69be8eb --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,48 @@ +name: Release to PyPI +on: + push: + tags: ["*"] + +env: + dists-artifact-name: python-package-distributions + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Install the latest version of uv + uses: astral-sh/setup-uv@v5 + with: + enable-cache: true + cache-dependency-glob: "pyproject.toml" + github-token: ${{ secrets.GITHUB_TOKEN }} + - name: Build package + run: uv build --python 3.13 --python-preference only-managed --sdist --wheel . --out-dir dist + - name: Store the distribution packages + uses: actions/upload-artifact@v4 + with: + name: ${{ env.dists-artifact-name }} + path: dist/* + + release: + needs: + - build + runs-on: ubuntu-latest + environment: + name: release + url: https://pypi.org/project/pytest-echo/${{ github.ref_name }} + permissions: + id-token: write + steps: + - name: Download all the dists + uses: actions/download-artifact@v4 + with: + name: ${{ env.dists-artifact-name }} + path: dist/ + - name: Publish to PyPI + uses: pypa/gh-action-pypi-publish@v1.12.4 + with: + attestations: true diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 75aa4a30..9d9d449a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,11 +1,13 @@ name: Test on: + workflow_dispatch: push: - branches: - - master - - develop + branches: [ "develop" ] + tags-ignore: [ "**" ] pull_request: + schedule: + - cron: "0 8 * * *" jobs: lint: @@ -30,31 +32,45 @@ jobs: strategy: fail-fast: false matrix: - python-version: [ "3.9", "3.10", "3.11" ] - django-version: [ "3.2", "4.2" ] + python-version: [ "311", "312", "313" ] + django-version: [ "32", "42", "51" ] env: PY_VER: ${{ matrix.python-version}} DJ_VER: ${{ matrix.django-version}} CELERY_BROKER_URL: redis://redis:6379/0 CELERY_ALWAYS_EAGER: true steps: - - uses: actions/checkout@v2 - - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Install the latest version of uv + uses: astral-sh/setup-uv@v5 with: - python-version: ${{ matrix.python-version }} + enable-cache: true + cache-dependency-glob: "pyproject.toml" + github-token: ${{ secrets.GITHUB_TOKEN }} - - name: Install dependencies - run: python -m pip install --upgrade pip .[test] "django==${DJ_VER}.*" + - name: Install tox + run: uv tool install --python-preference only-managed --python 3.13 tox --with tox-uv + + - name: Install Python + if: matrix.python-version != '3.13' + run: uv python install --python-preference only-managed ${{ matrix.python-version}} - - name: Test with - run: py.test tests/ -v + - name: Setup test suite ${{ env.DJ_VER }}-${{ env.PY_VER }} + run: tox run -vv --notest --skip-missing-interpreters false -e d${{ env.DJ_VER }}-py${{ env.PY_VER }} - - uses: codecov/codecov-action@v1 + - name: Run test suite +# COV_CMD=$(if [ ${{ env.DJ_VER }}-${{ env.PY_VER }} == 51-312 ]; then echo "--cov=pytest_echo --cov-report=xml"; else echo ; fi) + run: | + tox run --skip-pkg-install -e d${{ env.DJ_VER }}-py${{ env.PY_VER }} + env: + PYTEST_ADDOPTS: "-vv --durations=20" + DIFF_AGAINST: HEAD + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v5 + if: ${{ success() && matrix.python-version == 3.13 }} with: -# files: ./coverage1.xml,./coverage2.xml # optional -# flags: unittests # optional -# name: codecov-umbrella # optional -# fail_ci_if_error: true # optional (default = false) - verbose: true # optional (default = false) + env_vars: OS + name: codecov-pytest-order + token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.gitignore b/.gitignore index 706cdcf2..2d0f92bb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,22 +1,19 @@ -.DS_Store +.* ~* *.log *.pot *.pyc *.egg-info *.sqlite -.idea -.tox -.cache -.coverage +src/adminactions/version.py /dist /build /docs/build /MANIFEST coverage.xml -sonar-project.properties -.scannerwork -Pipfile -Pipfile.lock -poetry.lock .venv/ +uv.lock +!.pre-commit-config.yaml +!.github +!.gitignore +!.coveragerc diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 21df7fb2..8a00b0a7 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,21 +1,35 @@ repos: -- repo: local - hooks: - # Configuration for black exists in pyproject.toml, - # but we let pre-commit take care of the file filtering. - - id: black - name: black - entry: black - language: python - types: [python] - require_serial: true - - id: isort - name: isort - entry: isort - language: python - types: [python] - - id: flake8 - name: flake8 - entry: flake8 - language: python - types: [python] + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: + - id: end-of-file-fixer + - id: trailing-whitespace + - repo: https://github.com/python-jsonschema/check-jsonschema + rev: 0.31.0 + hooks: + - id: check-github-workflows + args: [ "--verbose" ] + - repo: https://github.com/tox-dev/tox-ini-fmt + rev: "1.5.0" + hooks: + - id: tox-ini-fmt + args: [ "-p", "lint" ] + - repo: https://github.com/tox-dev/pyproject-fmt + rev: "v2.5.0" + hooks: + - id: pyproject-fmt + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: "v0.9.4" + hooks: + - id: ruff-format + - id: ruff + args: [ "--fix", "--unsafe-fixes", "--exit-non-zero-on-fix" ] + - repo: https://github.com/adamchainz/djade-pre-commit + rev: "1.3.2" + hooks: + - id: djade + args: [ --target-version, "5.1" ] # Replace with Django version + - repo: meta + hooks: + - id: check-hooks-apply + - id: check-useless-excludes diff --git a/AUTHORS.rst b/AUTHORS.rst index d5679886..cad54afe 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -44,4 +44,3 @@ Contributors .. _`@asfaltboy`: https://github.com/asfaltboy .. _`@int-ua`: https://github.com/int-ua .. _`@Djailla`: https://github.com/Djailla - diff --git a/CHANGES b/CHANGES index 7aa0c180..270bd1d1 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,9 @@ +Release 2.4 +=========== +* fixes #227 +* add ability to asynchronously mass_update M2M + + Release 2.3 =========== * Add support to foreignkeys to bulk updates ( @see https://github.com/saxix/django-adminactions/pull/224/files) diff --git a/MANIFEST.in b/MANIFEST.in index 61e5f1de..2905cc8a 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,29 +1,27 @@ -include README.rst +graft docs +include CHANGELOG +include LICENSE +include src/*.py +include README.md + +include README.md include MANIFEST.in include AUTHORS.rst include CHANGES include LICENSE -include setup.py -include setup.cfg -include tox.ini include *.py -include Makefile -exclude .bumpversion.cfg exclude .editorconfig exclude manage.py exclude .* +exclude .act +exclude * -recursive-include docs * -recursive-include src *.css -recursive-include src *.js -recursive-include src *.pip -recursive-include src *.po -recursive-include src *.txt -recursive-include src/adminactions *.py -recursive-include src/adminactions *.html -recursive-include tests * +recursive-include src/adminactions *.* +recursive-exclude .act * global-exclude *.pyc global-exclude __pycache__ +global-exclude ~* global-exclude *~ +global-exclude .* diff --git a/Makefile b/Makefile index b591735d..7fc7bdc7 100644 --- a/Makefile +++ b/Makefile @@ -33,8 +33,7 @@ demo: PYTHONPATH=${PWD}:${PWD}/tests:${PWD}/src django-admin.py runserver --settings=demo.settings lint: - @flake8 src/ tests/ - @isort -c src/ + pre-commit run --all clean: diff --git a/README.md b/README.md index 6e3cfe0d..7f397784 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ -django-adminactions -=================== - +# django-adminactions [![Pypi](https://badge.fury.io/py/django-adminactions.svg)](https://badge.fury.io/py/django-adminactions) [![coverage](https://codecov.io/github/saxix/django-adminactions/coverage.svg?branch=develop)](https://codecov.io/github/saxix/django-adminactions?branch=develop) [![Test](https://github.com/saxix/django-adminactions/actions/workflows/test.yml/badge.svg)](https://github.com/saxix/django-adminactions/actions/workflows/test.yml) [![Docs](https://readthedocs.org/projects/django-adminactions/badge/?version=latest)](https://django-adminactions.readthedocs.io/en/latest/) +[![Django](https://img.shields.io/pypi/frameworkversions/django/django-adminactions)](https://pypi.org/project/django-adminactions/) + Collection of useful actions to use with django.contrib.admin.ModelAdmin and/or django.contrib.admin.AdminSite @@ -14,21 +14,19 @@ Please see the changelog at http://django-adminactions.readthedocs.org/en/latest #### Actions -* Export as CSV -* Export as Excel -* Export as fixture -* Export delete tree -* Mass update records -* Graph queryset -* Merge records -* Find Duplicates -* Bulk Update - +- Export as CSV +- Export as Excel +- Export as fixture +- Export delete tree +- Mass update records +- Graph queryset +- Merge records +- Find Duplicates +- Bulk Update #### Project Links - -- Code: https://github.com/saxix/django-adminactions -- Documentation: https://django-adminactions.readthedocs.org/en/latest/ -- Issue Tracker: https://github.com/saxix/django-adminactions/issues?sort -- Download Package: https://pypi.org/project/django-adminactions/ +- Code: https://github.com/saxix/django-adminactions +- Documentation: https://django-adminactions.readthedocs.org/en/latest/ +- Issue Tracker: https://github.com/saxix/django-adminactions/issues?sort +- Download Package: https://pypi.org/project/django-adminactions/ diff --git a/docs/source/_ext/djangodocs.py b/docs/source/_ext/djangodocs.py index 5579940d..8e698905 100644 --- a/docs/source/_ext/djangodocs.py +++ b/docs/source/_ext/djangodocs.py @@ -1,6 +1,7 @@ -""" -Sphinx plugins for Django documentation. -""" +"""Sphinx plugins for Django documentation.""" + +from __future__ import annotations + import json import os import re @@ -16,7 +17,7 @@ simple_option_desc_re = re.compile(r"([-_a-zA-Z0-9]+)(\s*.*?)(?=,\s+(?:/|-|--)|$)") -def setup(app): +def setup(app) -> None: app.add_crossref_type( directivename="setting", rolename="setting", @@ -77,39 +78,37 @@ def run(self): node.extend(inodes) if self.content: self.state.nested_parse(self.content, self.content_offset, node) - ret = ret + messages + ret += messages env.note_versionchange(node["type"], node["version"], node, self.lineno) return ret class DjangoHTMLTranslator(SmartyPantsHTMLTranslator): - """ - Django-specific reST to HTML tweaks. - """ + """Django-specific reST to HTML tweaks.""" # Don't use border=1, which docutils does by default. - def visit_table(self, node): + def visit_table(self, node) -> None: self._table_row_index = 0 # Needed by Sphinx self.body.append(self.starttag(node, "table", CLASS="docutils")) # ? Really? - def visit_desc_parameterlist(self, node): + def visit_desc_parameterlist(self, node) -> None: self.body.append("(") self.first_param = 1 self.param_separator = node.child_text_separator - def depart_desc_parameterlist(self, node): + def depart_desc_parameterlist(self, node) -> None: self.body.append(")") if sphinx_ver < "1.0.8": # # Don't apply smartypants to literal blocks # - def visit_literal_block(self, node): + def visit_literal_block(self, node) -> None: self.no_smarty += 1 SmartyPantsHTMLTranslator.visit_literal_block(self, node) - def depart_literal_block(self, node): + def depart_literal_block(self, node) -> None: SmartyPantsHTMLTranslator.depart_literal_block(self, node) self.no_smarty -= 1 @@ -128,19 +127,19 @@ def depart_literal_block(self, node): "versionadded": "New in Django %s", } - def visit_versionmodified(self, node): + def visit_versionmodified(self, node) -> None: self.body.append(self.starttag(node, "div", CLASS=node["type"])) - title = "%s%s" % ( + title = "{}{}".format( self.version_text[node["type"]] % node["version"], - len(node) and ":" or ".", + (len(node) and ":") or ".", ) - self.body.append('%s ' % title) + self.body.append(f'{title} ') - def depart_versionmodified(self, node): + def depart_versionmodified(self, node) -> None: self.body.append("\n") # Give each section a unique ID -- nice for custom CSS hooks - def visit_section(self, node): + def visit_section(self, node) -> None: old_ids = node.get("ids", []) node["ids"] = ["s-" + i for i in old_ids] node["ids"].extend(old_ids) @@ -151,13 +150,13 @@ def visit_section(self, node): def parse_django_admin_node(env, sig, signode): command = sig.split(" ")[0] env._django_curr_admin_command = command - title = "django-admin.py %s" % sig + title = f"django-admin.py {sig}" signode += addnodes.desc_name(title, title) return sig def parse_django_adminopt_node(env, sig, signode): - """A copy of sphinx.directives.CmdoptionDesc.parse_signature()""" + """A copy of sphinx.directives.CmdoptionDesc.parse_signature().""" from sphinx.domains.std import option_desc_re count = 0 @@ -187,13 +186,11 @@ def parse_django_adminopt_node(env, sig, signode): class DjangoStandaloneHTMLBuilder(StandaloneHTMLBuilder): - """ - Subclass to add some extra things we need. - """ + """Subclass to add some extra things we need.""" name = "djangohtml" - def finish(self): + def finish(self) -> None: super().finish() self.info(bold("writing templatebuiltins.js...")) xrefs = self.env.domaindata["std"]["objects"] @@ -201,12 +198,12 @@ def finish(self): "ttags": [ n for ((t, n), (l, a)) in xrefs.items() # noqa - if t == "templatetag" and l == "ref/templates/builtins" # noqa + if t == "templatetag" and l == "ref/templates/builtins" ], "tfilters": [ n for ((t, n), (l, a)) in xrefs.items() # noqa - if t == "templatefilter" and l == "ref/templates/builtins" # noqa + if t == "templatefilter" and l == "ref/templates/builtins" ], } outfilename = os.path.join(self.outdir, "templatebuiltins.js") diff --git a/docs/source/_ext/github.py b/docs/source/_ext/github.py index 184067ad..70cd0867 100644 --- a/docs/source/_ext/github.py +++ b/docs/source/_ext/github.py @@ -1,4 +1,5 @@ -"""Define text roles for GitHub +""" +Define text roles for GitHub. * ghissue - Issue * ghpull - Pull Request @@ -13,16 +14,19 @@ * Doug Hellmann * Min RK """ + # # Original Copyright (c) 2010 Doug Hellmann. All rights reserved. # +from __future__ import annotations from docutils import nodes, utils from docutils.parsers.rst.roles import set_classes def make_link_node(rawtext, app, type, slug, options): - """Create a link to a github resource. + """ + Create a link to a github resource. :param rawtext: Text being replaced with link node. :param app: Sphinx application context @@ -30,7 +34,6 @@ def make_link_node(rawtext, app, type, slug, options): :param slug: ID of the thing to link to :param options: Options dictionary passed to role func. """ - try: base = app.config.github_project_url if not base: @@ -38,19 +41,20 @@ def make_link_node(rawtext, app, type, slug, options): if not base.endswith("/"): base += "/" except AttributeError as err: - raise ValueError("github_project_url configuration value is not set (%s)" % str(err)) + msg = f"github_project_url configuration value is not set ({err!s})" + raise ValueError(msg) ref = base + type + "/" + slug + "/" set_classes(options) prefix = "#" if type == "pull": prefix = "PR " + prefix - node = nodes.reference(rawtext, prefix + utils.unescape(slug), refuri=ref, **options) - return node + return nodes.reference(rawtext, prefix + utils.unescape(slug), refuri=ref, **options) -def ghissue_role(name, rawtext, text, lineno, inliner, options={}, content=[]): - """Link to a GitHub issue. +def ghissue_role(name, rawtext, text, lineno, inliner, options=None, content=None): + """ + Link to a GitHub issue. Returns 2 part tuple containing list of nodes to insert into the document and a list of system messages. Both are allowed to be @@ -64,14 +68,17 @@ def ghissue_role(name, rawtext, text, lineno, inliner, options={}, content=[]): :param options: Directive options for customization. :param content: The directive content for customization. """ - + if content is None: + content = [] + if options is None: + options = {} try: issue_num = int(text) if issue_num <= 0: raise ValueError except ValueError: msg = inliner.reporter.error( - "GitHub issue number must be a number greater than or equal to 1; " '"%s" is invalid.' % text, + f'GitHub issue number must be a number greater than or equal to 1; "{text}" is invalid.', line=lineno, ) prb = inliner.problematic(rawtext, rawtext, msg) @@ -84,7 +91,7 @@ def ghissue_role(name, rawtext, text, lineno, inliner, options={}, content=[]): category = "issues" else: msg = inliner.reporter.error( - 'GitHub roles include "ghpull" and "ghissue", ' '"%s" is invalid.' % name, + f'GitHub roles include "ghpull" and "ghissue", "{name}" is invalid.', line=lineno, ) prb = inliner.problematic(rawtext, rawtext, msg) @@ -93,8 +100,9 @@ def ghissue_role(name, rawtext, text, lineno, inliner, options={}, content=[]): return [node], [] -def ghuser_role(name, rawtext, text, lineno, inliner, options={}, content=[]): - """Link to a GitHub user. +def ghuser_role(name, rawtext, text, lineno, inliner, options=None, content=None): + """ + Link to a GitHub user. Returns 2 part tuple containing list of nodes to insert into the document and a list of system messages. Both are allowed to be @@ -110,13 +118,18 @@ def ghuser_role(name, rawtext, text, lineno, inliner, options={}, content=[]): """ # app = inliner.document.settings.env.app # app.info('user link %r' % text) + if content is None: + content = [] + if options is None: + options = {} ref = "https://www.github.com/" + text node = nodes.reference(rawtext, text, refuri=ref, **options) return [node], [] -def ghcommit_role(name, rawtext, text, lineno, inliner, options={}, content=[]): - """Link to a GitHub commit. +def ghcommit_role(name, rawtext, text, lineno, inliner, options=None, content=None): + """ + Link to a GitHub commit. Returns 2 part tuple containing list of nodes to insert into the document and a list of system messages. Both are allowed to be @@ -130,6 +143,10 @@ def ghcommit_role(name, rawtext, text, lineno, inliner, options={}, content=[]): :param options: Directive options for customization. :param content: The directive content for customization. """ + if content is None: + content = [] + if options is None: + options = {} app = inliner.document.settings.env.app # app.info('user link %r' % text) try: @@ -139,15 +156,17 @@ def ghcommit_role(name, rawtext, text, lineno, inliner, options={}, content=[]): if not base.endswith("/"): base += "/" except AttributeError as err: - raise ValueError("github_project_url configuration value is not set (%s)" % str(err)) + msg = f"github_project_url configuration value is not set ({err!s})" + raise ValueError(msg) ref = base + text node = nodes.reference(rawtext, text[:6], refuri=ref, **options) return [node], [] -def setup(app): - """Install the plugin. +def setup(app) -> None: + """ + Install the plugin. :param app: Sphinx application context. """ @@ -156,4 +175,3 @@ def setup(app): app.add_role("ghuser", ghuser_role) app.add_role("ghcommit", ghcommit_role) app.add_config_value("github_project_url", None, "env") - return diff --git a/docs/source/_ext/version.py b/docs/source/_ext/version.py index 908ccddc..51b7d7d7 100644 --- a/docs/source/_ext/version.py +++ b/docs/source/_ext/version.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import re from sphinx import addnodes, roles @@ -6,7 +8,7 @@ simple_option_desc_re = re.compile(r"([-_a-zA-Z0-9]+)(\s*.*?)(?=,\s+(?:/|-|--)|$)") -def setup(app): +def setup(app) -> None: app.add_crossref_type( directivename="setting", rolename="setting", @@ -62,13 +64,13 @@ def run(self): link = None else: version = arg0 - link = "release-%s" % arg0 + link = f"release-{arg0}" node["version"] = version # inodes, messages = self.state.inline_text(self.version_text[self.name] % version, self.lineno+1) # node.extend(inodes) if link: - text = " Please see the changelog <%s>" % link + text = f" Please see the changelog <{link}>" xrefs = roles.XRefRole()("std:ref", text, text, self.lineno, self.state) node.extend(xrefs[0]) env.note_versionchange(node["type"], node["version"], node, self.lineno) diff --git a/docs/source/changes.rst b/docs/source/changes.rst index d88f0b7c..49a64b5d 100644 --- a/docs/source/changes.rst +++ b/docs/source/changes.rst @@ -14,4 +14,3 @@ This sections lists the biggest changes done on each release. :local: .. include:: ../../CHANGES - diff --git a/docs/source/conf.py b/docs/source/conf.py index 84b4d6fe..603bdd15 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -8,12 +8,18 @@ # # All configuration values have a default; values that are commented out # serve to show the default. +from __future__ import annotations import os import sys here = os.path.abspath(os.path.join(os.path.dirname(__file__))) -up = lambda base, level: os.path.abspath(os.path.join(base, *([os.pardir] * level))) + + +def up(base, level): + return os.path.abspath(os.path.join(base, *([os.pardir] * level))) + + sys.path.insert(0, up(here, 2)) from django.conf import settings diff --git a/docs/source/exceptions.rst b/docs/source/exceptions.rst index 1fd8a57a..b5e2a47e 100644 --- a/docs/source/exceptions.rst +++ b/docs/source/exceptions.rst @@ -10,4 +10,3 @@ Exceptions --------------------- Exception raised to interrupt an action. - diff --git a/docs/source/faq.rst b/docs/source/faq.rst index 97f9571c..cc6b0d29 100644 --- a/docs/source/faq.rst +++ b/docs/source/faq.rst @@ -95,6 +95,3 @@ here the partial code:: :func:`export_delete_tree` will dump only ``Rome`` :func:`export_as_fixture` will dump the whole tree - - - diff --git a/docs/source/howto.rst b/docs/source/howto.rst index 5f38f2fc..1ac746bc 100644 --- a/docs/source/howto.rst +++ b/docs/source/howto.rst @@ -92,4 +92,3 @@ Limit Massupdate hints to certain fields mass_update_hints = ['name'] admin.register(MyModel, MyModelAdmin) - diff --git a/docs/source/install.rst b/docs/source/install.rst index 8dc3cd0a..065ada09 100644 --- a/docs/source/install.rst +++ b/docs/source/install.rst @@ -68,7 +68,7 @@ Add defaults for the Export to CSV to the Django Config. See all available settings at :ref:`_export_as_csv`.:: import csv - + ADMINACTIONS_CSV_OPTIONS_DEFAULT = { 'date_format': 'Y-m-d', 'datetime_format': 'Y-m-d G:i:s O', diff --git a/docs/source/permissions.rst b/docs/source/permissions.rst index 3308d4ac..b5f38d2c 100644 --- a/docs/source/permissions.rst +++ b/docs/source/permissions.rst @@ -34,4 +34,3 @@ adminactions_merge ================== Required to execute :ref:`merge` - diff --git a/manage.py b/manage.py index 259b26f0..badc1fb0 100755 --- a/manage.py +++ b/manage.py @@ -1,9 +1,15 @@ #!/usr/bin/env python +from __future__ import annotations + import os import sys here = os.path.abspath(os.path.join(os.path.dirname(__file__))) -rel = lambda *args: os.path.join(here, *args) + + +def rel(*args): + return os.path.join(here, *args) + sys.path.insert(0, rel(os.pardir)) sys.path.insert(0, rel("src")) diff --git a/pyproject.toml b/pyproject.toml index 0417f724..c96a75a0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,11 +1,208 @@ -[tool.black] -line-length = 110 -target-version = ['py39'] +[build-system] +build-backend = "hatchling.build" +requires = [ + "hatch-vcs>=0.4", + "hatchling>=1.25", +] +[project] +name = "django-adminactions" +description = "Collections of useful actions to use with django.contrib.admin.ModelAdmin" +readme = "README.md" +license.file = "LICENSE" +maintainers = [ + { name = "Stefano Apostolico", email = "s.apostolico@gmail.com" }, +] +authors = [ + { name = "sax", email = "s.apostolico@gmail.com" }, +] +requires-python = ">=3.9" +classifiers = [ + "Environment :: Web Environment", + "Framework :: Django", + "Framework :: Django :: 3.2", + "Framework :: Django :: 4.2", + "Framework :: Django :: 5.1", + "Intended Audience :: Developers", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", +] -[tool.isort] -profile = "black" -line_length = 110 -lines_between_sections = 1 -known_first_party = "adminactions" -skip = "migrations" +dynamic = [ + "version", +] +dependencies = [ + "pytz", + "xlrd>=0.9.2", + "xlwt", +] +optional-dependencies.dev = [ +] +urls.Downloads = "https://github.com/saxix/django-adminactions" +urls.Homepage = "https://github.com/saxix/django-adminactions" + +[dependency-groups] +dev = [ + "celery", + "check-manifest", + "covdefaults>=2.3", + "django-admin-extra-urls", + "django-dynamic-fixture", + "django-environ", + "django-webtest", + "mock", + "modernize", + "mypy", + "pillow", + "psycopg2", + "pytest", + "pytest-cache", + "pytest-cov", + "pytest-django", + "pytest-echo", + "readme>=0.7.1", + "redis>=5.2.1", + "ruff>=0.9.4", + "selenium>=2.42", + "setuptools>=15", + "tox>=4.2", +] + +[tool.hatch] +build.hooks.vcs.version-file = "src/adminactions/version.py" +version.source = "vcs" + +[tool.hatch.build.targets.sdist] +ignore-vcs = true +include = [ + "src/adminactions/**/*.*", +] +exclude = [ + ".gitignore", +] +packages = [ "src/adminactions" ] + +[tool.hatch.build.targets.wheel] +packages = [ "src/adminactions" ] +only-packages = true + +[tool.ruff] +target-version = "py311" +line-length = 120 +exclude = [ + "docs", + "manage.py", + "tests", +] +format.preview = true +format.docstring-code-line-length = 100 +format.docstring-code-format = true +lint.select = [ + "ALL", +] +lint.ignore = [ + # "A", + # "ANN", + "ANN401", + "ARG", + "B", + "BLE", + "C", + "COM", + "CPY", + "D", + "DOC", + "DTZ", + "E", + "EM", + "ERA", + "F", + "FBT", + "FURB", + "N", + "PERF", + "PGH", + "PLC", + "PLR", + "PLW", + "RET", + "RUF", + "S", + "SIM", + "SLF", + "TRY", + "UP", +] +lint.per-file-ignores."docs/conf.py" = [ + "A001", # + "D100", # + "ERA001", # + "INP001", # +] +lint.per-file-ignores."tests/**/*.py" = [ + "D", # don"t care about documentation in tests + "FBT", # don"t care about booleans as positional arguments in tests + "INP001", # no implicit namespace + "PLR2004", # Magic value used in comparison, consider replacing with a constant variable + "PT", + "S101", # asserts allowed in tests... + "S603", # `subprocess` call: check for execution of untrusted input +] +lint.isort = { known-first-party = [ "pytest_echo" ] } + +lint.preview = true + +[tool.pyproject-fmt] +max_supported_python = "3.13" + +[tool.pytest.ini_options] +django_find_project = false +norecursedirs = [ "demo", ".tox" ] +addopts = "--doctest-modules --echo-attr=django.conf.settings.DATABASES.default.ENGINE --tb=short --reuse-db --capture=no --doctest-glob=adminactions/*.py" +python_files = "tests/test_*.py tests/**/test_*.py src/*.py" +markers = [ + "functional: mark a test as functional", + "selenium: selenium test", + "skip: skip test", +] +testpaths = [ + "src", + "tests", +] + +[tool.coverage] +run.source = [ + "adminactions", +] +run.dynamic_context = "test_function" +run.branch = true +run.parallel = true +run.omit = [ + "**/create_extra_permissions.py", +] +run.plugins = [ + "covdefaults", +] +report.fail_under = 80 +report.show_missing = true +report.exclude_lines = [ + "pragma: no cover", +] +html.show_contexts = true +html.skip_covered = false +paths.source = [ + "src", + ".tox*/*/lib/python*/site-packages", + ".tox*/pypy*/site-packages", + ".tox*\\*\\Lib\\site-packages", + "*/src", + "*\\src", +] + +[tool.uv] +package = true diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 529e5e97..00000000 --- a/setup.cfg +++ /dev/null @@ -1,43 +0,0 @@ -[isort] -combine_as_imports = true -default_section = THIRDPARTY -include_trailing_comma = true -line_length=80 -known_third_party = django -known_first_party = adminactions,demo -multi_line_output = 0 -sections=FUTURE,STDLIB,THIRDPARTY,FIRSTPARTY,LOCALFOLDER - -[wheel] -universal = 1 - -[egg_info] -tag_build = -tag_date = 0 -tag_svn_revision = 0 - -[devpi:upload] -formats=bdist_wheel,sdist.tgz - -[pylama] -format = pylint -skip = */.tox/*,*/.env/* -linters = pylint,mccabe -ignore = F0401,C0111,E731 - - -[flake8] -# File filtering is taken care of in pre-commit. -# E203 false positive, see https://github.com/PyCQA/pycodestyle/issues/373 -# B011 We don't use PYTHONOPTIMIZE. - -# XXX: E501 is ignored, which disables line length checking. -# Currently, the black formatter doesn't wrap long strings: https://github.com/psf/black/issues/182#issuecomment-385325274 -# We already have a lot of E501's - these are lines black didn't wrap. -# But rather than append # noqa: E501 to all of them, we just ignore E501 for now. -extend-ignore = E203,E501,E402,E731,B007,B009,B010,B011,B020,B023,B024,B026,B027 - -per-file-ignores = - # these scripts must have minimal dependencies so opt out of the usual sentry rules - tools/*: S - .github/*: S diff --git a/setup.py b/setup.py deleted file mode 100755 index 075db12a..00000000 --- a/setup.py +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/env python -import ast -import codecs -import os -import re - -from setuptools import find_packages, setup - -ROOT = os.path.realpath(os.path.join(os.path.dirname(__file__))) -init = os.path.join(ROOT, "src", "adminactions", "__init__.py") - - -def read(*parts): - with codecs.open(os.path.join(ROOT, "src", "requirements", *parts), "r") as fp: - return fp.read() - - -_version_re = re.compile(r"__version__\s+=\s+(.*)") - -with open(init, "rb") as f: - version = str(ast.literal_eval(_version_re.search(f.read().decode("utf-8")).group(1))) - -requirements = read("install.pip") -tests_require = read("testing.pip") -dev_require = read("develop.pip") -docs_require = read("rtd.pip") - -setup( - name="django-adminactions", - version=version, - url="https://github.com/saxix/django-adminactions", - download_url="https://github.com/saxix/django-adminactions", - author="sax", - author_email="s.apostolico@gmail.com", - description="Collections of useful actions to use with django.contrib.admin.ModelAdmin", - license="MIT", - package_dir={"": "src"}, - packages=find_packages("src"), - include_package_data=True, - install_requires=requirements, - tests_require=tests_require, - extras_require={ - "test": requirements + tests_require, - "dev": dev_require + tests_require, - "docs": dev_require + docs_require, - }, - zip_safe=False, - platforms=["any"], - classifiers=[ - "Environment :: Web Environment", - "Framework :: Django", - "Operating System :: OS Independent", - "Framework :: Django :: 2.2", - "Framework :: Django :: 3.2", - "Framework :: Django :: 4.0", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Intended Audience :: Developers", - ], - long_description=open("README.md").read(), - long_description_content_type="text/markdown", -) diff --git a/src/adminactions/__init__.py b/src/adminactions/__init__.py index 791f2d72..8eda015b 100644 --- a/src/adminactions/__init__.py +++ b/src/adminactions/__init__.py @@ -1,3 +1,8 @@ -VERSION = __version__ = "2.3.0" -NAME = "django-adminactions" -default_app_config = "adminactions.apps.Config" +# VERSION = __version__ = "2.3.0" +# NAME = "django-adminactions" +# default_app_config = "adminactions.apps.Config" +from .version import __version__ + +__all__ = [ + "__version__", +] diff --git a/src/adminactions/actions.py b/src/adminactions/actions.py index 7e232376..b35df6c6 100644 --- a/src/adminactions/actions.py +++ b/src/adminactions/actions.py @@ -1,3 +1,7 @@ +from typing import Optional + +from django.contrib.admin import AdminSite + from .bulk_update import bulk_update from .byrows_update import byrows_update from .duplicates import find_duplicates_action @@ -20,7 +24,7 @@ ] -def add_to_site(site, exclude=None, include=None): +def add_to_site(site: AdminSite, exclude: Optional[list[str]] = None, include: Optional[list[str]] = None) -> None: """ Register all the adminactions into passed site @@ -37,7 +41,7 @@ def add_to_site(site, exclude=None, include=None): >>> add_to_site(site) >>> from django.contrib.admin import site - >>> add_to_site(site, exclude=['merge']) + >>> add_to_site(site, exclude=["merge"]) """ exclude = exclude or [] diff --git a/src/adminactions/api.py b/src/adminactions/api.py index d4c1ea23..124c7e7d 100644 --- a/src/adminactions/api.py +++ b/src/adminactions/api.py @@ -1,13 +1,16 @@ +from __future__ import annotations + import collections import csv import datetime import itertools from io import BytesIO +from typing import TYPE_CHECKING, Any, Generator import xlwt from django.conf import settings from django.core.exceptions import FieldDoesNotExist, ObjectDoesNotExist -from django.db.models import FileField +from django.db.models import FileField, Model from django.db.models.fields.related import ManyToManyField, OneToOneField from django.db.transaction import atomic from django.http import HttpResponse, StreamingHttpResponse @@ -19,6 +22,15 @@ from .utils import clone_instance, get_field_by_path, get_field_value, get_ignored_fields +if TYPE_CHECKING: + from collections.abc import Iterable + + from django.contrib.admin.options import ModelAdmin + from django.core.files.base import File + from django.db.models.query import QuerySet + + from .forms import CSVOptions, XLSOptions + csv_options_default = { "date_format": "d/m/Y", "datetime_format": "N j, Y, P", @@ -36,7 +48,14 @@ ALL_FIELDS = -999 -def merge(master, other, fields=None, commit=False, m2m=None, related=None): # noqa +def merge( + master: Model, + other: Model, + fields: Iterable[str] | None = None, + commit: bool = False, + m2m: Iterable[str] | None = None, + related: Iterable[str] | None = None, +) -> Model: """ Merge 'other' into master. @@ -62,10 +81,10 @@ def merge(master, other, fields=None, commit=False, m2m=None, related=None): # if m2m == ALL_FIELDS: m2m = set() - for field in master._meta.get_fields(): + for field in master._meta.get_fields(): # noqa: SLF001 if getattr(field, "many_to_many", None): if isinstance(field, ManyToManyField): - if not field.remote_field.through._meta.auto_created: + if not field.remote_field.through._meta.auto_created: # noqa: SLF001 continue m2m.add(field.name) else: @@ -109,9 +128,9 @@ def merge(master, other, fields=None, commit=False, m2m=None, related=None): # setattr(element, rel_fieldname, master) element.save() other.delete() - ignored_fields = get_ignored_fields(result._meta.model, "MERGE_ACTION_IGNORED_FIELDS") + ignored_fields = get_ignored_fields(result._meta.model, "MERGE_ACTION_IGNORED_FIELDS") # noqa: SLF001 for ig_field in ignored_fields: - setattr(result, ig_field, result._meta.get_field(ig_field).get_default()) + setattr(result, ig_field, result._meta.get_field(ig_field).get_default()) # noqa: SLF001 result.save() for fieldname, elements in list(all_m2m.items()): dest_m2m = getattr(result, fieldname) @@ -125,20 +144,20 @@ class Echo: interface. """ - def write(self, value): + def write(self, value: Any) -> Any: """Write the value by returning it, instead of storing in a buffer.""" return value -def export_as_csv( # noqa: max-complexity: 20 - queryset, - fields=None, - header=None, - filename=None, - options=None, - out=None, - modeladmin=None, -): # noqa +def export_as_csv( + queryset: QuerySet, + fields: list[str] | None = None, + header: bool = False, + filename: str | None = None, + options: CSVOptions | None = None, + out: File | None = None, + modeladmin: ModelAdmin = None, +) -> HttpResponse: """ Exports a queryset as csv from a queryset with the given fields. @@ -162,9 +181,7 @@ def export_as_csv( # noqa: max-complexity: 20 filename = "%s.csv" % queryset.model._meta.verbose_name_plural.lower().replace(" ", "_") response = response_class(content_type="text/csv") - response["Content-Disposition"] = ('attachment;filename="%s"' % filename).encode( - "us-ascii", "replace" - ) + response["Content-Disposition"] = ('attachment;filename="%s"' % filename).encode("us-ascii", "replace") else: response = out @@ -194,7 +211,7 @@ def export_as_csv( # noqa: max-complexity: 20 settingstime_zone = get_default_timezone() - def yield_header(): + def yield_header() -> Generator[str, None, None]: if bool(header): if isinstance(header, (list, tuple)): yield writer.writerow(header) @@ -202,7 +219,7 @@ def yield_header(): yield writer.writerow([f for f in fields]) yield "" - def yield_rows(): + def yield_rows() -> Generator[str, None, None]: for obj in queryset: row = [] for fieldname in fields: @@ -253,9 +270,15 @@ def yield_rows(): } -def export_as_xls2( # noqa: max-complexity: 24 - queryset, fields=None, header=None, filename=None, options=None, out=None, modeladmin=None # noqa -): +def export_as_xls2( + queryset: "QuerySet", + fields: list[str] = None, + header: bool = False, + filename: str | None = None, + options: "XLSOptions" | None = None, + out: File | None = None, + modeladmin: ModelAdmin | None = None, # noqa +) -> HttpResponse: # sheet_name=None, header_alt=None, # formatting=None, out=None): """ @@ -270,7 +293,7 @@ def export_as_xls2( # noqa: max-complexity: 24 :return: HttpResponse instance if out not supplied, otherwise out """ - def _get_qs_formats(queryset): + def _get_qs_formats(queryset: "QuerySet") -> HttpResponse: formats = {} if hasattr(queryset, "model"): for i, fieldname in enumerate(fields): @@ -281,9 +304,7 @@ def _get_qs_formats(queryset): __, __, ) = utils.get_field_by_name(queryset.model, fieldname) - fmt = xls_options_default.get( - f.name, xls_options_default.get(f.__class__.__name__, "general") - ) + fmt = xls_options_default.get(f.name, xls_options_default.get(f.__class__.__name__, "general")) formats[i] = fmt except FieldDoesNotExist: pass @@ -295,9 +316,7 @@ def _get_qs_formats(queryset): filename = "%s.xls" % queryset.model._meta.verbose_name_plural.lower().replace(" ", "_") response = HttpResponse(content_type="application/vnd.ms-excel") - response["Content-Disposition"] = ('attachment;filename="%s"' % filename).encode( - "us-ascii", "replace" - ) + response["Content-Disposition"] = ('attachment;filename="%s"' % filename).encode("us-ascii", "replace") else: response = out @@ -306,7 +325,7 @@ def _get_qs_formats(queryset): config.update(options) if fields is None: - fields = [f.name for f in queryset.model._meta.fields + queryset.model._meta.many_to_many] + fields = [f.name for f in queryset.model._meta.fields + queryset.model._meta.many_to_many] # noqa: SLF001 book = xlwt.Workbook(encoding="utf-8", style_compression=2) sheet_name = config.pop("sheet_name") @@ -321,7 +340,7 @@ def _get_qs_formats(queryset): if not isinstance(header, (list, tuple)): header = [ force_str(f.verbose_name) - for f in queryset.model._meta.fields + queryset.model._meta.many_to_many + for f in queryset.model._meta.fields + queryset.model._meta.many_to_many # noqa: SLF001 if f.name in fields ] @@ -332,7 +351,7 @@ def _get_qs_formats(queryset): sheet.row(row).height = 500 formats = _get_qs_formats(queryset) - _styles = {} + styles_ = {} for rownum, row in enumerate(queryset): sheet.write(rownum + 1, 0, rownum + 1) @@ -344,24 +363,24 @@ def _get_qs_formats(queryset): ) if callable(fmt): value = xlwt.Formula(fmt(value)) - if hash(fmt) not in _styles: + if hash(fmt) not in styles_: if callable(fmt): - _styles[hash(fmt)] = xlwt.easyxf(num_format_str="formula") + styles_[hash(fmt)] = xlwt.easyxf(num_format_str="formula") elif isinstance(value, datetime.datetime): - _styles[hash(fmt)] = xlwt.easyxf(num_format_str=config["datetime_format"]) + styles_[hash(fmt)] = xlwt.easyxf(num_format_str=config["datetime_format"]) elif isinstance(value, datetime.date): - _styles[hash(fmt)] = xlwt.easyxf(num_format_str=config["date_format"]) + styles_[hash(fmt)] = xlwt.easyxf(num_format_str=config["date_format"]) elif isinstance(value, datetime.datetime): - _styles[hash(fmt)] = xlwt.easyxf(num_format_str=config["time_format"]) + styles_[hash(fmt)] = xlwt.easyxf(num_format_str=config["time_format"]) else: - _styles[hash(fmt)] = xlwt.easyxf(num_format_str=fmt) + styles_[hash(fmt)] = xlwt.easyxf(num_format_str=fmt) if isinstance(value, (list, tuple)): value = "".join(value) - sheet.write(rownum + 1, col_idx + 1, value, _styles[hash(fmt)]) + sheet.write(rownum + 1, col_idx + 1, value, styles_[hash(fmt)]) except Exception as e: - sheet.write(rownum + 1, col_idx + 1, smart_str(e), _styles[hash(fmt)]) + sheet.write(rownum + 1, col_idx + 1, smart_str(e), styles_[hash(fmt)]) book.save(response) return response @@ -388,9 +407,15 @@ def _get_qs_formats(queryset): } -def export_as_xls3( # noqa: max-complexity: 23 - queryset, fields=None, header=None, filename=None, options=None, out=None, modeladmin=None # noqa -): # pragma: no cover +def export_as_xls3( + queryset: "QuerySet", + fields: list[str] | None = None, + header: bool = False, + filename: str | None = None, + options: "XLSOptions | None" = None, + out: File | None = None, + modeladmin: ModelAdmin | None = None, # noqa +) -> HttpResponse: # pragma: no cover # sheet_name=None, header_alt=None, # formatting=None, out=None): """ @@ -406,7 +431,7 @@ def export_as_xls3( # noqa: max-complexity: 23 """ import xlsxwriter - def _get_qs_formats(queryset): + def _get_qs_formats(queryset: "QuerySet") -> HttpResponse: formats = {"_general_": book.add_format()} if hasattr(queryset, "model"): for i, fieldname in enumerate(fields): @@ -416,10 +441,8 @@ def _get_qs_formats(queryset): __, __, __, - ) = queryset.model._meta.get_field_by_name(fieldname) - pattern = xlsxwriter_options.get( - f.name, xlsxwriter_options.get(f.__class__.__name__, "general") - ) + ) = queryset.model._meta.get_field_by_name(fieldname) # noqa: SLF001 + pattern = xlsxwriter_options.get(f.name, xlsxwriter_options.get(f.__class__.__name__, "general")) fmt = book.add_format({"num_format": pattern}) formats[fieldname] = fmt except FieldDoesNotExist: @@ -435,7 +458,7 @@ def _get_qs_formats(queryset): config.update(options) if fields is None: - fields = [f.name for f in queryset.model._meta.fields + queryset.model._meta.many_to_many] + fields = [f.name for f in queryset.model._meta.fields + queryset.model._meta.many_to_many] # noqa: SLF001 book = xlsxwriter.Workbook(out, {"in_memory": True}) sheet_name = config.pop("sheet_name") @@ -450,7 +473,7 @@ def _get_qs_formats(queryset): if not isinstance(header, (list, tuple)): header = [ force_str(f.verbose_name) - for f in queryset.model._meta.fields + queryset.model._meta.many_to_many + for f in queryset.model._meta.fields + queryset.model._meta.many_to_many # noqa: SLF001 if f.name in fields ] @@ -491,7 +514,7 @@ def _get_qs_formats(queryset): out.seek(0) if http_response: if filename is None: - filename = "%s.xls" % queryset.model._meta.verbose_name_plural.lower().replace(" ", "_") + filename = "%s.xls" % queryset.model._meta.verbose_name_plural.lower().replace(" ", "_") # noqa: SLF001 response = HttpResponse( out.read(), content_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", diff --git a/src/adminactions/apps.py b/src/adminactions/apps.py index fb9b6f5e..20eca9d6 100644 --- a/src/adminactions/apps.py +++ b/src/adminactions/apps.py @@ -6,7 +6,7 @@ class Config(AppConfig): name = "adminactions" - def ready(self): + def ready(self) -> None: from adminactions import consts from . import checks # noqa diff --git a/src/adminactions/bulk_update.py b/src/adminactions/bulk_update.py index 2aef6d58..6b974345 100644 --- a/src/adminactions/bulk_update.py +++ b/src/adminactions/bulk_update.py @@ -1,8 +1,10 @@ +from __future__ import annotations + import codecs import csv import logging from pathlib import Path -from typing import Dict, Optional, Sequence +from typing import TYPE_CHECKING, Any, Dict, Optional, Sequence from django import forms from django.contrib import messages @@ -14,6 +16,7 @@ from django.db.transaction import atomic from django.forms import Media from django.http import HttpResponseRedirect +from django.http.request import HttpRequest from django.shortcuts import render from django.utils.encoding import smart_str from django.utils.safestring import mark_safe @@ -24,6 +27,13 @@ from adminactions.perms import get_permission_codename from adminactions.signals import adminaction_end, adminaction_requested, adminaction_start +if TYPE_CHECKING: + from django.contrib.admin import ModelAdmin + from django.db.models import QuerySet + from django.db.models.fields import Field + from django.http.request import HttpRequest + from django.http.response import HttpResponse + logger = logging.getLogger(__name__) @@ -56,7 +66,7 @@ class BulkUpdateForm(forms.Form): ) @property - def media(self): + def media(self) -> Media: """Return all media required to render the widgets on this form.""" media = Media( js=["adminactions/js/bulkupdate.js"], @@ -70,7 +80,7 @@ def media(self): class BulkUpdateMappingForm(forms.Form): index_field = forms.MultipleChoiceField(choices=[], widget=forms.CheckboxSelectMultiple) - def __init__(self, *args, **kwargs): + def __init__(self, *args: Any, **kwargs: Any) -> None: self.model = kwargs.pop("model") super().__init__(*args, **kwargs) # self._errors = None @@ -83,7 +93,7 @@ def __init__(self, *args, **kwargs): # self.initial[f[0]] = f[0] # self.fields[f[0]].widget.initial = f[0] - def _clean_fields(self): + def _clean_fields(self) -> None: for name, field in self.fields.items(): value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name)) self.cleaned_data[name] = value @@ -93,10 +103,10 @@ def _clean_fields(self): ValidationError(_("Please select one or more index fields")), ) - def _post_clean(self): + def _post_clean(self) -> None: pass - def get_mapping(self): + def get_mapping(self) -> dict[str, str]: mapping = self.cleaned_data.copy() mapping.pop("index_field") return {k: v for k, v in mapping.items() if v.strip()} @@ -146,9 +156,7 @@ def bulk_update(modeladmin, request, queryset): # noqa if "apply" in request.POST: form = bulk_update_form(request.POST, request.FILES, initial=form_initial) csv_form = CSVConfigForm(request.POST, initial=csv_initial, prefix="csv") - map_form = BulkUpdateMappingForm( - request.POST, initial=map_initial, model=modeladmin.model, prefix="fld" - ) + map_form = BulkUpdateMappingForm(request.POST, initial=map_initial, model=modeladmin.model, prefix="fld") if form.is_valid() and csv_form.is_valid() and map_form.is_valid(): header = csv_form.cleaned_data.pop("header") @@ -233,18 +241,18 @@ def bulk_update(modeladmin, request, queryset): # noqa bulk_update.base_permission = "adminactions_bulkupdate" -def _bulk_update( # noqa: max-complexity: 18 - queryset, - file_name_or_object, +def _bulk_update( + queryset: "QuerySet", + file_name_or_object: str | Field, *, - mapping: Dict, + mapping: dict, indexes: Sequence[str], - clean=False, + clean: bool = False, header: bool = True, csv_options: Optional[Dict] = None, - request=None, + request: HttpRequest | None = None, dry_run: bool = False, -): +) -> dict[str, list[str]]: results = { "updated": [], "errors": [], @@ -281,9 +289,7 @@ def _bulk_update( # noqa: max-complexity: 18 model_field = queryset.model._meta.get_field(field) if model_field.is_relation and model_field.many_to_one: related_model = model_field.related_model - related_field_name = ( - model_field.to_fields[0] if model_field.to_fields else "pk" - ) + related_field_name = model_field.to_fields[0] if model_field.to_fields else "pk" related_field = related_model._meta.get_field(related_field_name) if isinstance(related_field, models.UUIDField): diff --git a/src/adminactions/byrows_update.py b/src/adminactions/byrows_update.py index 6ae65100..1cb32c7f 100644 --- a/src/adminactions/byrows_update.py +++ b/src/adminactions/byrows_update.py @@ -1,5 +1,10 @@ +from typing import Any + +from django import forms from django.contrib import messages from django.contrib.admin import helpers +from django.contrib.admin.options import ModelAdmin +from django.db.models import fields as django_fields from django.forms.models import modelform_factory, modelformset_factory from django.http import HttpResponseRedirect from django.shortcuts import render @@ -30,12 +35,10 @@ def byrows_update(modeladmin, request, queryset): # noqa return class modelform(modeladmin.form): - def __init__(self, *args, **kwargs): + def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) if self.instance: - readonly_fields = (modeladmin.model._meta.pk.name,) + tuple( - modeladmin.get_readonly_fields(request) - ) + readonly_fields = (modeladmin.model._meta.pk.name,) + tuple(modeladmin.get_readonly_fields(request)) for fname in readonly_fields: if fname in self.fields: self.fields[fname].widget.attrs["readonly"] = "readonly" @@ -43,7 +46,7 @@ def __init__(self, *args, **kwargs): fields = byrows_update_get_fields(modeladmin) - def formfield_callback(field, **kwargs): + def formfield_callback(field: django_fields.Field, **kwargs: Any) -> forms.Field: return modeladmin.formfield_for_dbfield(field, request=request, **kwargs) ActionForm = modelform_factory( @@ -77,9 +80,7 @@ def formfield_callback(field, **kwargs): actionform = ActionForm(initial=action_form_initial, instance=None) formset = MFormSet(queryset=queryset) - adminform = helpers.AdminForm( - actionform, modeladmin.get_fieldsets(request), {}, [], model_admin=modeladmin - ) + adminform = helpers.AdminForm(actionform, modeladmin.get_fieldsets(request), {}, [], model_admin=modeladmin) tpl = "adminactions/byrows_update.html" ctx = { @@ -103,7 +104,7 @@ def formfield_callback(field, **kwargs): byrows_update.base_permission = "adminactions_byrowsupdate" -def byrows_update_get_fields(modeladmin): +def byrows_update_get_fields(modeladmin: ModelAdmin) -> list[str]: """ Get fields names to be shown of the model rows formset considering the admin option: diff --git a/src/adminactions/checks.py b/src/adminactions/checks.py index 5eb7e7d6..04ad8216 100644 --- a/src/adminactions/checks.py +++ b/src/adminactions/checks.py @@ -1,8 +1,11 @@ +from typing import Any + +from django.apps.config import AppConfig from django.core.checks import Error, register @register() -def check_adminactions_settings(app_configs, **kwargs): +def check_adminactions_settings(app_configs: AppConfig, **kwargs: Any) -> None: errors = [] from .config import AA_PERMISSION_HANDLER from .consts import ( diff --git a/src/adminactions/compat.py b/src/adminactions/compat.py index 0cd65777..2ebed27e 100644 --- a/src/adminactions/compat.py +++ b/src/adminactions/compat.py @@ -1,12 +1,21 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING + import django.db.transaction as t +if TYPE_CHECKING: + from types import TracebackType + class NoCommit(t.Atomic): - def __exit__(self, exc_type, exc_value, traceback): - super().__exit__(Exception, Exception(), None) + def __exit__( + self, exc_type: type[BaseException] | None, exc_value: BaseException | None, traceback: TracebackType | None + ) -> None: + super().__exit__(Exception, Exception(), traceback) -def nocommit(using=None, savepoint=True, durable=False): +def nocommit(using: str | None = None, savepoint: bool = True, durable: bool = False) -> NoCommit: return NoCommit(using, savepoint, durable) diff --git a/src/adminactions/duplicates.py b/src/adminactions/duplicates.py index bd2d8fc6..5c5a556d 100644 --- a/src/adminactions/duplicates.py +++ b/src/adminactions/duplicates.py @@ -1,3 +1,7 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING, Any + from django import forms from django.contrib import messages from django.contrib.admin import helpers @@ -11,6 +15,13 @@ from adminactions.signals import adminaction_end, adminaction_requested, adminaction_start from adminactions.utils import get_common_context +if TYPE_CHECKING: + from django.contrib.admin import ModelAdmin + from django.db.models import QuerySet + from django.db.models.fields import Field + from django.http.request import HttpRequest + from django.http.response import HttpResponse + class DuplicatesForm(forms.Form): _selected_action = forms.CharField(widget=forms.MultipleHiddenInput) @@ -24,7 +35,7 @@ class DuplicatesForm(forms.Form): min = forms.IntegerField(required=True, initial=2) max = forms.IntegerField(required=False) - def __init__(self, *args, **kwargs): + def __init__(self, *args: Any, **kwargs: Any) -> None: self.model = kwargs.pop("model") self.field_names = [] super().__init__(*args, **kwargs) @@ -35,14 +46,14 @@ def __init__(self, *args, **kwargs): self.field_names.append(field.name) self.fields[field.name] = forms.BooleanField(label=label, required=False) - def clean(self): + def clean(self) -> dict[str, Any]: checked = [fname for fname in self.field_names if self.cleaned_data[fname]] if not checked: raise ValidationError("Select at least one field") return self.cleaned_data @property - def media(self): + def media(self) -> forms.Media: return super().media + forms.Media( css={ "screen": ("adminactions/css/adminactions.css",), @@ -50,7 +61,9 @@ def media(self): ) -def find_duplicates(qs, fields, min_dupe=1, max_dupe=None): +def find_duplicates( + qs: "QuerySet", fields: "list[Field]", min_dupe: int = 1, max_dupe: int | None = None +) -> "QuerySet": qs = qs.order_by() qs = qs.values(*fields) qs = qs.annotate(count_id=Count("id")) @@ -60,7 +73,7 @@ def find_duplicates(qs, fields, min_dupe=1, max_dupe=None): return qs -def find_duplicates_action(modeladmin, request, queryset): +def find_duplicates_action(modeladmin: "ModelAdmin", request: "HttpRequest", queryset: "QuerySet") -> "HttpResponse": opts = modeladmin.model._meta perm = "{0}.{1}".format( opts.app_label, diff --git a/src/adminactions/export.py b/src/adminactions/export.py index 4eaca560..bc56a7cb 100644 --- a/src/adminactions/export.py +++ b/src/adminactions/export.py @@ -1,5 +1,6 @@ import logging from itertools import chain +from typing import TYPE_CHECKING, Any from django.conf import settings from django.contrib import messages @@ -7,8 +8,12 @@ from django.core import serializers as ser from django.db import router from django.db.models import ForeignKey, ManyToManyField +from django.db.models.base import Model from django.db.models.deletion import Collector +from django.db.models.query import QuerySet +from django.forms.forms import Form from django.http import HttpResponse, HttpResponseRedirect +from django.http.request import HttpRequest from django.shortcuts import render from django.utils.safestring import mark_safe from django.utils.translation import gettext_lazy as _ @@ -20,10 +25,13 @@ from .perms import get_permission_codename from .signals import adminaction_end, adminaction_requested, adminaction_start +if TYPE_CHECKING: + from django.contrib.admin import ModelAdmin + logger = logging.getLogger(__name__) -def get_action(request): +def get_action(request: HttpRequest) -> list[str]: try: action_index = int(request.POST.get("index", 0)) except ValueError: @@ -32,16 +40,16 @@ def get_action(request): def base_export( - modeladmin, - request, - queryset, - title, - impl, # noqa - name, - action_short_description, - template, - form_class, -): + modeladmin: "ModelAdmin", + request: "HttpRequest", + queryset: QuerySet, + title: str, + impl: callable, # noqa + name: str, + action_short_description: str, + template: str, + form_class: type[Form], +) -> "HttpResponse": """ export a queryset to csv file """ @@ -65,9 +73,7 @@ def base_export( if hasattr(modeladmin, "get_exportable_columns"): cols = modeladmin.get_exportable_columns(request, form_class) else: - cols = [ - (f.name, f.verbose_name) for f in queryset.model._meta.fields + queryset.model._meta.many_to_many - ] + cols = [(f.name, f.verbose_name) for f in queryset.model._meta.fields + queryset.model._meta.many_to_many] initial = { "_selected_action": request.POST.getlist(helpers.ACTION_CHECKBOX_NAME), "select_across": request.POST.get("select_across") == "1", @@ -149,7 +155,7 @@ def base_export( base_export.base_permission = "adminactions_export" -def export_as_csv(modeladmin, request, queryset): +def export_as_csv(modeladmin: "ModelAdmin", request: HttpRequest, queryset: QuerySet) -> HttpResponse: if hasattr(modeladmin, "get_aa_export_form"): form_class = modeladmin.get_aa_export_form(request, "csv") or CSVOptions else: @@ -175,7 +181,7 @@ def export_as_csv(modeladmin, request, queryset): export_as_csv.base_permission = "adminactions_export" -def export_as_xls(modeladmin, request, queryset): +def export_as_xls(modeladmin: "ModelAdmin", request: HttpRequest, queryset: QuerySet) -> HttpResponse: if hasattr(modeladmin, "get_aa_export_form"): form_class = modeladmin.get_aa_export_form(request, "xls") or XLSOptions else: @@ -202,21 +208,21 @@ def export_as_xls(modeladmin, request, queryset): class FlatCollector: - def __init__(self, using): + def __init__(self, using: str) -> None: self._visited = [] super().__init__() - def collect(self, objs): + def collect(self, objs: list[Model]) -> None: self.data = objs self.models = set([o.__class__ for o in self.data]) class ForeignKeysCollector: - def __init__(self, using): + def __init__(self, using: str) -> None: self._visited = [] super().__init__() - def _collect(self, objs): + def _collect(self, objs: list[Model]) -> None: objects = [] for obj in objs: if obj and obj not in self._visited: @@ -235,16 +241,16 @@ def _collect(self, objs): objects.extend(self._collect([target])) return objects - def collect(self, objs): + def collect(self, objs: list[Model]) -> None: self._visited = [] self.data = self._collect(objs) self.models = set([o.__class__ for o in self.data]) - def __str__(self): + def __str__(self) -> str: return mark_safe(self.data) -def _dump_qs(form, queryset, data, filename): +def _dump_qs(form: Form, queryset: QuerySet, data: dict[str, Any], filename: str) -> None: fmt = form.cleaned_data.get("serializer") json = ser.get_serializer(fmt)() @@ -261,14 +267,12 @@ def _dump_qs(form, queryset, data, filename): queryset.model._meta.verbose_name_plural.lower().replace(" ", "_"), fmt, ) - response["Content-Disposition"] = ('attachment;filename="%s"' % filename).encode( - "us-ascii", "replace" - ) + response["Content-Disposition"] = ('attachment;filename="%s"' % filename).encode("us-ascii", "replace") response.content = ret return response -def export_as_fixture(modeladmin, request, queryset): +def export_as_fixture(modeladmin: "ModelAdmin", request: HttpRequest, queryset: QuerySet) -> "HttpResponse": initial = { "_selected_action": request.POST.getlist(helpers.ACTION_CHECKBOX_NAME), "select_across": request.POST.get("select_across") == "1", @@ -314,9 +318,7 @@ def export_as_fixture(modeladmin, request, queryset): messages.error(request, str(e)) return try: - _collector = ( - ForeignKeysCollector if form.cleaned_data.get("add_foreign_keys") else FlatCollector - ) + _collector = ForeignKeysCollector if form.cleaned_data.get("add_foreign_keys") else FlatCollector c = _collector(None) c.collect(queryset) adminaction_end.send( @@ -369,7 +371,7 @@ def export_as_fixture(modeladmin, request, queryset): export_as_fixture.base_permission = "adminactions_export" -def export_delete_tree(modeladmin, request, queryset): # noqa +def export_delete_tree(modeladmin: "ModelAdmin", request: HttpRequest, queryset: QuerySet) -> "HttpResponse": # noqa """ Export as fixture selected queryset and all the records that belong to. That mean that dump what will be deleted if the queryset was deleted diff --git a/src/adminactions/forms.py b/src/adminactions/forms.py index ee475c67..a98d15d0 100644 --- a/src/adminactions/forms.py +++ b/src/adminactions/forms.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import csv from django import forms @@ -22,11 +24,11 @@ class GenericActionForm(ModelForm): ) action = forms.CharField(label="", required=True, initial="", widget=forms.HiddenInput()) - def configured_fields(self): + def configured_fields(self) -> list[forms.Field]: return [field for field in self if not field.is_hidden and field.name.startswith("_")] @cached_property - def model_field_names(self): + def model_field_names(self) -> list[str]: ignored_fields = { "select_accross", "action", @@ -34,16 +36,14 @@ def model_field_names(self): } return [f.name for f in self._meta.model._meta.get_fields() if f.name not in ignored_fields] - def model_fields(self): + def model_fields(self) -> list[forms.Field]: # field_names = [f.name for f in self._meta.model._meta.get_fields() if f.name not in self.model_field_names] return [field for field in self if field.name in self.model_field_names] class CSVConfigForm(forms.Form): header = forms.BooleanField(label=_("Header"), required=False) - delimiter = forms.ChoiceField( - label=_("Delimiter"), choices=list(zip(delimiters, delimiters)), initial="," - ) + delimiter = forms.ChoiceField(label=_("Delimiter"), choices=list(zip(delimiters, delimiters)), initial=",") quotechar = forms.ChoiceField(label=_("Quotechar"), choices=list(zip(quotes, quotes)), initial="'") quoting = forms.TypedChoiceField( coerce=int, @@ -59,10 +59,10 @@ class CSVConfigForm(forms.Form): escapechar = forms.ChoiceField(label=_("Escapechar"), choices=(("", ""), ("\\", "\\")), required=False) - def clean_escapechar(self): + def clean_escapechar(self) -> str | None: return self.cleaned_data["escapechar"] or None - def csv_fields(self): + def csv_fields(self) -> list[forms.Field]: return [ field for field in self @@ -87,9 +87,7 @@ class CSVOptions(CSVConfigForm): ) action = forms.CharField(label="", required=True, initial="", widget=forms.HiddenInput()) - datetime_format = forms.CharField( - label=_("Datetime format"), initial=formats.get_format("DATETIME_FORMAT") - ) + datetime_format = forms.CharField(label=_("Datetime format"), initial=formats.get_format("DATETIME_FORMAT")) date_format = forms.CharField(label=_("Date format"), initial=formats.get_format("DATE_FORMAT")) time_format = forms.CharField(label=_("Time format"), initial=formats.get_format("TIME_FORMAT")) columns = forms.MultipleChoiceField(label=_("Columns"), widget=SelectMultiple(attrs={"size": 20})) diff --git a/src/adminactions/graph.py b/src/adminactions/graph.py index 5eba4af0..77c64ae9 100644 --- a/src/adminactions/graph.py +++ b/src/adminactions/graph.py @@ -1,8 +1,10 @@ import json +from typing import TYPE_CHECKING from django.contrib import messages from django.contrib.admin import helpers from django.db.models.aggregates import Count +from django.db.models.base import Model from django.db.models.fields.related import ForeignKey from django.forms.fields import BooleanField, CharField, ChoiceField from django.forms.forms import DeclarativeFieldsMetaclass, Form @@ -16,8 +18,13 @@ from .signals import adminaction_end, adminaction_requested, adminaction_start from .utils import get_field_by_name +if TYPE_CHECKING: + from django.contrib.admin import ModelAdmin + from django.http.request import HttpRequest + from django.http.response import HttpResponse -def graph_form_factory(model): + +def graph_form_factory(model: Model) -> Form: app_name = model._meta.app_label model_name = model.__name__ @@ -38,7 +45,7 @@ def graph_form_factory(model): return DeclarativeFieldsMetaclass(str(class_name), (Form,), attrs) -def graph_queryset(modeladmin, request, queryset): # noqa +def graph_queryset(modeladmin: "ModelAdmin", request: "HttpRequest", queryset: "QuerySet") -> "HTTPResponse": # noqa opts = modeladmin.model._meta perm = "{0}.{1}".format( opts.app_label.lower(), @@ -122,7 +129,7 @@ def graph_queryset(modeladmin, request, queryset): # noqa json.dumps(data_labels), json.dumps(data_labels), ) - elif graph_type == "PieChart": + else: # graph_type == "PieChart": table = [list(zip(list(map(str, data_labels)), list(map(str, data))))] extra = """{seriesDefaults: {renderer: jQuery.jqplot.PieRenderer, rendererOptions: {fill: true, @@ -142,13 +149,7 @@ def graph_queryset(modeladmin, request, queryset): # noqa modeladmin=modeladmin, form=form, ) - elif request.method == "POST": - initial = { - helpers.ACTION_CHECKBOX_NAME: request.POST.getlist(helpers.ACTION_CHECKBOX_NAME), - "select_across": request.POST.get("select_across", 0), - } - form = MForm(initial=initial) - else: + else: # if request.method == "POST": initial = { helpers.ACTION_CHECKBOX_NAME: request.POST.getlist(helpers.ACTION_CHECKBOX_NAME), "select_across": request.POST.get("select_across", 0), diff --git a/src/adminactions/helpers.py b/src/adminactions/helpers.py index 08d0ca55..5d779fcb 100644 --- a/src/adminactions/helpers.py +++ b/src/adminactions/helpers.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING, Any + from django import forms from django.contrib import messages from django.core import serializers @@ -6,6 +8,11 @@ from .perms import get_permission_codename +if TYPE_CHECKING: + from django.contrib.admin.options import ModelAdmin + from django.http.request import HttpRequest + from django.http.response import HttpResponse + class ImportFixtureForm(forms.Form): fixture_file = forms.FileField(required=False) @@ -14,12 +21,12 @@ class ImportFixtureForm(forms.Form): use_natural_foreign_keys = forms.BooleanField(required=False) use_natural_primary_keys = forms.BooleanField(required=False) - def clean(self): + def clean(self) -> None: if not (self.cleaned_data["fixture_file"] or self.cleaned_data["fixture_content"]): raise ValidationError("You must provide file or content") -def import_fixture(modeladmin, request): +def import_fixture(modeladmin: "ModelAdmin", request: "HttpRequest") -> "HttpResponse": context = modeladmin.get_common_context(request) if request.method == "POST": form = ImportFixtureForm(data=request.POST) @@ -45,7 +52,7 @@ def import_fixture(modeladmin, request): obj.save() imported += 1 - modeladmin.message_user(request, imported, messages.SUCCESS) + modeladmin.message_user(request, f"{imported} objects imported", messages.SUCCESS) except Exception as e: modeladmin.message_user(request, f"{e.__class__.__name__}: {e}", messages.ERROR) @@ -57,7 +64,9 @@ def import_fixture(modeladmin, request): class AdminActionPermMixin: - def _filter_actions_by_permissions(self, request, actions): + def _filter_actions_by_permissions( + self, request: "HttpRequest", actions: list[tuple[callable, Any]] + ) -> list[tuple[callable, Any]]: opts = self.model._meta filtered_actions = [] actions = super()._filter_actions_by_permissions(request, actions) diff --git a/src/adminactions/management/commands/create_extra_permissions.py b/src/adminactions/management/commands/create_extra_permissions.py index 775f8516..7ebfaff1 100644 --- a/src/adminactions/management/commands/create_extra_permissions.py +++ b/src/adminactions/management/commands/create_extra_permissions.py @@ -1,8 +1,10 @@ +from typing import Any + from django.core.management import BaseCommand class Command(BaseCommand): - def handle(self, *args, **options): + def handle(self, *args: Any, **options: Any) -> None: from adminactions.perms import create_extra_permissions create_extra_permissions() diff --git a/src/adminactions/mass_update.py b/src/adminactions/mass_update.py index 6f182198..e296200c 100644 --- a/src/adminactions/mass_update.py +++ b/src/adminactions/mass_update.py @@ -1,7 +1,10 @@ +from __future__ import annotations + import logging import re from collections import OrderedDict as SortedDict from collections import defaultdict +from typing import TYPE_CHECKING, Any from django import forms from django.conf import settings @@ -11,6 +14,7 @@ from django.core.files import File from django.db.models import FileField, ForeignKey from django.db.models import fields as df +from django.db.models.query import QuerySet from django.db.transaction import atomic from django.forms import fields as ff from django.forms.models import ( @@ -34,6 +38,10 @@ from .signals import adminaction_end, adminaction_requested, adminaction_start from .utils import curry, get_field_by_name +if TYPE_CHECKING: + from django.http.request import HttpRequest + + logger = logging.getLogger(__name__) DO_NOT_MASS_UPDATE = "do_NOT_mass_UPDATE" @@ -74,82 +82,80 @@ class OperationManager: ("set null", (lambda old_value: None, False, disable_if_not_nullable, "")), ] - def __init__(self, _dict): + def __init__(self, _dict: dict[type[df.Field], tuple[str, Any]]) -> None: self._dict = defaultdict(SortedDict) self.operations = dict() self.register_operations(df.Field, self.COMMON) for field_class, args in _dict.items(): self.register_operations(field_class, args) - def register_operations(self, field_class, operations): + def register_operations( + self, field_class: type[df.Field], operations: list[tuple[str, tuple[Any, bool, callable, str]]] + ) -> None: for label, operation in operations: self._dict[field_class][label] = operation if operation: self.operations[label] = operation[0] - def get_function(self, name): + def get_function(self, name: str) -> callable: return self.operations.get(name, None) - def get(self, field_class: type): + def get(self, field_class: type[df.Field]) -> dict[type[df.Field]]: data = SortedDict() # reversed to make the most specific overrule the more general ones for typ in reversed(field_class.__mro__): data |= self._dict.get(typ, ()) return data - def operation_enabled(self, field, operation): + def operation_enabled(self, field: df.Field, operation: tuple[Any, Any, Any]) -> bool: if operation: enabler = operation[2] return enabler is True or (callable(enabler) and enabler(field)) return False - def get_for_field(self, field): + def get_for_field(self, field: df.Field) -> dict[str, callable]: """returns valid functions for passed field :param field Field django Model Field :return list of (label, (__, param, enabler, help)) """ - return SortedDict( - [ - (label, operation) - for label, operation in self.get(field.__class__).items() - if self.operation_enabled(field, operation) - ] - ) + return SortedDict([ + (label, operation) + for label, operation in self.get(field.__class__).items() + if self.operation_enabled(field, operation) + ]) - def __getitem__(self, field_class): + def __getitem__(self, field_class: type[df.Field]) -> dict[type[df.Field]]: return self.get(field_class) -OPERATIONS = OperationManager( - { - df.CharField: [ - ("upper", (str.upper, False, True, _("convert to uppercase"))), - ("lower", (str.lower, False, True, _("convert to lowercase"))), - ( - "capitalize", - (str.capitalize, False, True, _("capitalize first character")), - ), - ("trim", (str.strip, False, True, _("leading and trailing whitespace"))), - ], - df.IntegerField: [ - ( - "add percent", - (add_percent, True, True, _("add percent to existing value")), - ), - ("sub percent", (sub_percent, True, True, "")), - ("sub", (sub_percent, True, True, "")), - ("add", (add, True, True, "")), - ], - df.BooleanField: [("toggle", (negate, False, True, ""))], - # df.NullBooleanField: [("toggle", (negate, False, True, ""))], - df.EmailField: [ - ("change domain", (change_domain, True, True, "")), - ("upper", (str.upper, False, True, _("convert to uppercase"))), - ("lower", (str.lower, False, True, _("convert to lowercase"))), - ], - df.URLField: [("change protocol", (change_protocol, True, True, ""))], - } -) +OPERATIONS = OperationManager({ + df.CharField: [ + ("upper", (str.upper, False, True, _("convert to uppercase"))), + ("lower", (str.lower, False, True, _("convert to lowercase"))), + ( + "capitalize", + (str.capitalize, False, True, _("capitalize first character")), + ), + ("trim", (str.strip, False, True, _("leading and trailing whitespace"))), + ], + df.IntegerField: [ + ( + "add percent", + (add_percent, True, True, _("add percent to existing value")), + ), + ("sub percent", (sub_percent, True, True, "")), + ("sub", (sub_percent, True, True, "")), + ("add", (add, True, True, "")), + ], + df.BooleanField: [("toggle", (negate, False, True, ""))], + # df.NullBooleanField: [("toggle", (negate, False, True, ""))], + df.EmailField: [ + ("change domain", (change_domain, True, True, "")), + ("upper", (str.upper, False, True, _("convert to uppercase"))), + ("lower", (str.lower, False, True, _("convert to lowercase"))), + ], + df.URLField: [("change protocol", (change_protocol, True, True, ""))], +}) class MassUpdateForm(GenericActionForm): @@ -167,7 +173,7 @@ class MassUpdateForm(GenericActionForm): ) sort_fields = True - def __init__(self, *args, **kwargs): + def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) self._errors = None self.update_using_queryset_allowed = True @@ -177,7 +183,7 @@ def __init__(self, *args, **kwargs): if self.sort_fields: self.fields = {k: v for k, v in sorted(self.fields.items(), key=lambda item: item[1].label or "")} - def _get_validation_exclusions(self): + def _get_validation_exclusions(self) -> list[str]: exclude = list(super()._get_validation_exclusions()) for name, field in list(self.fields.items()): function = self.data.get("func_id_%s" % name, False) @@ -185,7 +191,7 @@ def _get_validation_exclusions(self): exclude.append(name) return exclude - def _post_clean(self): + def _post_clean(self) -> None: # must be overriden to bypass instance.clean() if self.cleaned_data.get("_clean", False): opts = self._meta @@ -200,12 +206,19 @@ def _post_clean(self): except ValidationError as e: self._update_errors(e.message_dict) - def full_clean(self): + def full_clean(self) -> None: super().full_clean() + + def _is_field_name(n: str) -> bool: + return not (n.startswith(("chk_id_", "func_id_"))) + + def _is_enabled(n: str) -> bool: + return self.cleaned_data[f"chk_id_{n}"] + if not self.is_bound: # Stop further processing. return for field_name, value in list(self.cleaned_data.items()): - if isinstance(self.fields.get(field_name, ""), forms.FileField): + if _is_field_name(field_name) and isinstance(self.fields.get(field_name, ""), forms.FileField): if self.cleaned_data["_async"] and self.cleaned_data.get(field_name, None): self.add_error(field_name, _("Cannot use Async with FileField")) @@ -214,26 +227,30 @@ def full_clean(self): self.add_error(None, "Cannot use operators without 'validate'") else: for field_name, value in list(self.cleaned_data.items()): - if isinstance(self.fields.get(field_name, ""), ModelMultipleChoiceField): + if ( + _is_field_name(field_name) + and _is_enabled(field_name) + and isinstance(self.fields.get(field_name, ""), ModelMultipleChoiceField) + ): self.add_error( field_name, - _("Unable no mass update ManyToManyField" " without 'validate'"), + _("Unable no mass update ManyToManyField without 'validate'"), ) - def _clean_fields(self): + def _clean_fields(self) -> None: self.update_using_queryset_allowed = True for name, field in list(self.fields.items()): raw_value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name)) try: value = raw_value initial = self.initial.get(name, field.initial) + enabler = "chk_id_%s" % name + apply = self.data.get(enabler, "") == "on" + self.cleaned_data[enabler] = apply if isinstance(field, ff.FileField): value = field.clean(raw_value, initial) else: - enabler = "chk_id_%s" % name function = self.data.get("func_id_%s" % name, "") - apply = self.data.get(enabler, "") == "on" - self.cleaned_data[enabler] = apply self.cleaned_data["func_id_%s" % name] = function # self.cleaned_data[name] = field.clean(raw_value) if apply: @@ -248,7 +265,7 @@ def _clean_fields(self): value = curry(func, value) else: value = func - self.cleaned_data[name] = value + # self.cleaned_data[name] = value if hasattr(self, "clean_%s" % name): value = getattr(self, "clean_%s" % name)() self.cleaned_data[name] = value @@ -257,17 +274,17 @@ def _clean_fields(self): if name in self.cleaned_data: del self.cleaned_data[name] - def clean__validate(self): + def clean__validate(self) -> bool: return bool(self.data.get("_validate", 0)) - def clean__async(self): + def clean__async(self) -> bool: return bool(self.data.get("_async", 0)) - def clean__clean(self): + def clean__clean(self) -> bool: return bool(self.data.get("_clean", 0)) @property - def media(self): + def media(self) -> forms.Media: extra = "" if settings.DEBUG else ".min" return super().media + forms.Media( js=( @@ -279,13 +296,20 @@ def media(self): }, ) - def fix_json(self): + def fix_json(self) -> None: for label, field in self.fields.items(): if isinstance(field, forms.JSONField): field.disabled = label not in self.data -def mass_update_execute(queryset, rules, validate, clean, user_pk, request=None): +def mass_update_execute( + queryset: "QuerySet", + rules: dict[str, tuple[callable, Any]], + validate: bool, + clean: bool, + user_pk: Any, + request: "HttpRequest" | None = None, +) -> tuple[int, list[str]]: errors = {} updated = 0 opts = queryset.model._meta @@ -347,14 +371,14 @@ def mass_update(modeladmin, request, queryset): # noqa mass update queryset """ - def not_required(field, **kwargs): + def not_required(field: df.Field, **kwargs: Any) -> forms.Field: """force all fields as not required""" kwargs["required"] = False kwargs["request"] = request return modeladmin.formfield_for_dbfield(field, **kwargs) - def _get_sample(): - grouped = defaultdict(lambda: []) + def _get_sample() -> dict[str, list[tuple[Any, str] | dict[str, Any]]]: + grouped = defaultdict(list) for f in mass_update_hints: if isinstance(f, ForeignKey): # Filter by queryset so we only get results without our @@ -441,7 +465,10 @@ def _get_sample(): op = form.data.get("func_id_%s" % field_name) if callable(value): value = None - rules[field_name] = (op, value) + if isinstance(value, QuerySet): + rules[field_name] = (op, list(value.values_list("pk", flat=True))) + else: + rules[field_name] = (op, value) if use_celery: from .tasks import mass_update_task diff --git a/src/adminactions/merge.py b/src/adminactions/merge.py index 92e81c6a..478d0902 100644 --- a/src/adminactions/merge.py +++ b/src/adminactions/merge.py @@ -1,20 +1,24 @@ from datetime import datetime +from typing import Any, Generator from django import forms from django.contrib import messages from django.contrib.admin import helpers from django.db import models +from django.db.models.base import Model from django.forms import HiddenInput, TextInput +from django.forms.fields import Field from django.forms.formsets import formset_factory from django.forms.models import model_to_dict, modelform_factory from django.http import HttpResponseRedirect +from django.http.request import HttpRequest from django.shortcuts import render from django.utils.encoding import smart_str from django.utils.safestring import mark_safe from django.utils.translation import gettext as _ from . import api -from . import compat as transaction +from .compat import nocommit from .forms import GenericActionForm from .perms import get_permission_codename from .signals import adminaction_end, adminaction_requested, adminaction_start @@ -39,29 +43,20 @@ class MergeFormBase(forms.Form): other_pk = forms.CharField(widget=HiddenInput) field_names = forms.CharField(required=False, widget=HiddenInput) - def action_fields(self): + def action_fields(self) -> Generator[HiddenInput, None, None]: for field_name in ["dependencies", "master_pk", "other_pk", "field_names"]: bf = self[field_name] yield HiddenInput().render(field_name, bf.value()) - def clean_dependencies(self): + def clean_dependencies(self) -> int: return int(self.cleaned_data["dependencies"]) - def clean_field_names(self): + def clean_field_names(self) -> Any: if self.cleaned_data["field_names"]: return self.cleaned_data["field_names"].split(",") else: return None - def full_clean(self): - super().full_clean() - - def clean(self): - return super().clean() - - def is_valid(self): - return super().is_valid() - class Media: js = [ "admin/js/vendor/jquery/jquery.js", @@ -75,8 +70,7 @@ class MergeForm(GenericActionForm, MergeFormBase): pass -# noinspection PyProtectedMember -def merge(modeladmin, request, queryset): # noqa +def merge(modeladmin: "ModelAdmin", request: "HttpRequest", queryset: "QuerySet"): # noqa """ Merge two model instances. Move all foreign keys. @@ -88,7 +82,7 @@ def merge(modeladmin, request, queryset): # noqa messages.error(request, _("Sorry you do not have rights to execute this action")) return - def raw_widget(field, **kwargs): + def raw_widget(field: models.Field, **kwargs: Any) -> Field: """force all fields as not required""" kwargs["widget"] = TextInput({"class": "raw-value"}) if isinstance(field, models.FileField): @@ -105,11 +99,11 @@ def raw_widget(field, **kwargs): ) OForm = modelform_factory(modeladmin.model, exclude=("pk",), formfield_callback=raw_widget) - def validate(v_request, v_master, v_other): + def validate(v_request: HttpRequest, v_master: Model, v_other: Model) -> None: """Validate the model is still valid after the merge""" v_merge_kwargs = {} - with transaction.nocommit(): + with nocommit(): merge_form_base = MergeFormBase(v_request.POST) if merge_form_base.is_valid(): @@ -141,9 +135,7 @@ def validate(v_request, v_master, v_other): "select_across": request.POST.get("select_across") == "1", "action": request.POST.get("action"), "fields": [ - f - for f in queryset.model._meta.fields - if not f.primary_key and f.editable and f.name not in ignored_fields + f for f in queryset.model._meta.fields if not f.primary_key and f.editable and f.name not in ignored_fields ], "app_label": queryset.model._meta.app_label, "result": "", @@ -236,21 +228,19 @@ def validate(v_request, v_master, v_other): adminForm = helpers.AdminForm(form, modeladmin.get_fieldsets(request), {}, [], model_admin=modeladmin) media = modeladmin.media + adminForm.media - ctx.update( - { - "adminform": adminForm, - "formset": formset, - "media": mark_safe(media), - "action_short_description": merge.short_description, - "title": "%s (%s)" - % ( - merge.short_description.capitalize(), - smart_str(modeladmin.opts.verbose_name_plural), - ), - "master": master, - "other": other, - } - ) + ctx.update({ + "adminform": adminForm, + "formset": formset, + "media": mark_safe(media), + "action_short_description": merge.short_description, + "title": "%s (%s)" + % ( + merge.short_description.capitalize(), + smart_str(modeladmin.opts.verbose_name_plural), + ), + "master": master, + "other": other, + }) ctx.update(modeladmin.admin_site.each_context(request)) return render(request, tpl, context=ctx) diff --git a/src/adminactions/models.py b/src/adminactions/models.py index 63e6a6da..2c94f2c1 100644 --- a/src/adminactions/models.py +++ b/src/adminactions/models.py @@ -1,9 +1,12 @@ +from typing import Any + +from django.db.models.base import Model from django.db.models.signals import post_migrate from . import config, consts, perms -def create_extra_permissions_handler(sender, **kwargs): +def create_extra_permissions_handler(sender: Model, **kwargs: Any) -> None: global TOTAL_MODELS, COUNTER if config.AA_PERMISSION_HANDLER == consts.AA_PERMISSION_CREATE_USE_SIGNAL: perms.create_extra_permissions() diff --git a/src/adminactions/perms.py b/src/adminactions/perms.py index 278c5eca..42394964 100644 --- a/src/adminactions/perms.py +++ b/src/adminactions/perms.py @@ -1,13 +1,21 @@ +from typing import TYPE_CHECKING + from django.apps import apps +from django.db.models.options import Options + +if TYPE_CHECKING: + from django.contrib.contenttypes.models import ContentType __all__ = ["create_extra_permissions", "get_permission_codename"] +from django.db.models.base import Model + -def get_permission_codename(action, opts): +def get_permission_codename(action: str, opts: Options) -> str: return "%s_%s" % (action, opts.object_name.lower()) -def get_contenttype_for_model(model): +def get_contenttype_for_model(model: Model) -> "ContentType": from django.contrib.contenttypes.models import ContentType model = model._meta.concrete_model @@ -19,7 +27,7 @@ def get_contenttype_for_model(model): return ct -def create_extra_permissions(): +def create_extra_permissions() -> None: from django.contrib.auth.models import Permission from django.contrib.contenttypes.models import ContentType diff --git a/src/adminactions/requirements/install.py2.pip b/src/adminactions/py.typed similarity index 100% rename from src/adminactions/requirements/install.py2.pip rename to src/adminactions/py.typed diff --git a/src/adminactions/requirements/develop.pip b/src/adminactions/requirements/develop.pip deleted file mode 100644 index d0e52ea6..00000000 --- a/src/adminactions/requirements/develop.pip +++ /dev/null @@ -1,6 +0,0 @@ -autopep8 -ipython -isort -pdbpp -virtualenv==12.0.2 # do not upgrade. unable to create py3 -wheel diff --git a/src/adminactions/requirements/install.py3.pip b/src/adminactions/requirements/install.py3.pip deleted file mode 100644 index e69de29b..00000000 diff --git a/src/adminactions/static/adminactions/css/adminactions.css b/src/adminactions/static/adminactions/css/adminactions.css index 05085076..163a9e25 100644 --- a/src/adminactions/static/adminactions/css/adminactions.css +++ b/src/adminactions/static/adminactions/css/adminactions.css @@ -1 +1,50 @@ -.mergetable{width:100%;border:1px solid #000}p.display{width:300px;overflow:hidden;white-space:nowrap}.mergetable tr.header th{font-weight:bold;text-align:center}.mergetable td{vertical-align:middle;border-right:1px solid #000}.mergetable .label{font-weight:bold}.mergetable .selected{background-color:#81b10c}.mergetable .changed{background-color:#f9adaf}.mergetable input.raw-value{border:0px transparent;background-color:transparent;display:none}div.duplicates{display:flex}div.duplicates table{width:100%}div.duplicates table tr th{white-space:nowrap}div.duplicates .left{flex-shrink:initial}div.duplicates .right{border:1px solid #c9c9c9;margin-left:40px;padding:5px;flex-grow:initial;width:100%}/*# sourceMappingURL=adminactions.css.map */ +.mergetable { + width: 100%; + border: 1px solid #000; +} +p.display { + width: 300px; + overflow: hidden; + white-space: nowrap; +} +.mergetable tr.header th { + font-weight: bold; + text-align: center; +} +.mergetable td { + vertical-align: middle; + border-right: 1px solid #000; +} +.mergetable .label { + font-weight: bold; +} +.mergetable .selected { + background-color: #81b10c; +} +.mergetable .changed { + background-color: #f9adaf; +} +.mergetable input.raw-value { + border: 0px transparent; + background-color: transparent; + display: none; +} +div.duplicates { + display: flex; +} +div.duplicates table { + width: 100%; +} +div.duplicates table tr th { + white-space: nowrap; +} +div.duplicates .left { + flex-shrink: initial; +} +div.duplicates .right { + border: 1px solid #c9c9c9; + margin-left: 40px; + padding: 5px; + flex-grow: initial; + width: 100%; +} /*# sourceMappingURL=adminactions.css.map */ diff --git a/src/adminactions/static/adminactions/css/adminactions.css.map b/src/adminactions/static/adminactions/css/adminactions.css.map index 1ecf7128..9ca85c6d 100644 --- a/src/adminactions/static/adminactions/css/adminactions.css.map +++ b/src/adminactions/static/adminactions/css/adminactions.css.map @@ -1 +1 @@ -{"version":3,"sourceRoot":"","sources":["adminactions.scss"],"names":[],"mappings":"AAAA,YACI,WACA,sBAEJ,UACI,YACA,gBACA,mBAIJ,yBACI,iBACA,kBAGJ,eAEI,sBACA,4BAaJ,mBAEI,iBAGJ,sBACI,yBAGJ,qBACI,yBAGJ,4BAEI,uBACA,6BACA,aAGJ,eAOI,aANA,qBACI,WACA,2BACI,mBAIR,qBACI,oBAEJ,sBACI,yBACA,iBACA,YACA,kBACA","file":"adminactions.css"} \ No newline at end of file +{"version":3,"sourceRoot":"","sources":["adminactions.scss"],"names":[],"mappings":"AAAA,YACI,WACA,sBAEJ,UACI,YACA,gBACA,mBAIJ,yBACI,iBACA,kBAGJ,eAEI,sBACA,4BAaJ,mBAEI,iBAGJ,sBACI,yBAGJ,qBACI,yBAGJ,4BAEI,uBACA,6BACA,aAGJ,eAOI,aANA,qBACI,WACA,2BACI,mBAIR,qBACI,oBAEJ,sBACI,yBACA,iBACA,YACA,kBACA","file":"adminactions.css"} diff --git a/src/adminactions/static/adminactions/css/adminactions.scss b/src/adminactions/static/adminactions/css/adminactions.scss index 1aa757cf..2defd8a4 100644 --- a/src/adminactions/static/adminactions/css/adminactions.scss +++ b/src/adminactions/static/adminactions/css/adminactions.scss @@ -21,10 +21,11 @@ p.display { } .mergetable .column { - /*width: 30%;*/ + /*width: 30%;*/ } -.mergetable .origin *, .mergetable .result * { +.mergetable .origin *, +.mergetable .result * { /*width: 30%;*/ /*word-wrap: break-word;*/ /*white-space:pre-line;*/ @@ -50,18 +51,18 @@ p.display { display: none; } -div.duplicates{ - table{ +div.duplicates { + table { width: 100%; tr th { white-space: nowrap; } } display: flex; - .left{ + .left { flex-shrink: initial; } - .right{ + .right { border: 1px solid #c9c9c9; margin-left: 40px; padding: 5px; diff --git a/src/adminactions/static/adminactions/css/bulkupdate.css b/src/adminactions/static/adminactions/css/bulkupdate.css index 1a40f7d8..354b1357 100644 --- a/src/adminactions/static/adminactions/css/bulkupdate.css +++ b/src/adminactions/static/adminactions/css/bulkupdate.css @@ -1 +1,29 @@ -table th.title{background-color:var(--header-bg)}table.bulk-update{border:1px solid #c9c9c9}table.bulk-update td{border-left:1px solid #c9c9c9}table.bulk-update select.func_select{min-width:100px}#col1{float:left;width:70%}#col1 table{width:90%}#col2{float:right;width:30%}#col2 table{width:90%}#col2 select{width:100%}/*# sourceMappingURL=bulkupdate.css.map */ +table th.title { + background-color: var(--header-bg); +} +table.bulk-update { + border: 1px solid #c9c9c9; +} +table.bulk-update td { + border-left: 1px solid #c9c9c9; +} +table.bulk-update select.func_select { + min-width: 100px; +} +#col1 { + float: left; + width: 70%; +} +#col1 table { + width: 90%; +} +#col2 { + float: right; + width: 30%; +} +#col2 table { + width: 90%; +} +#col2 select { + width: 100%; +} /*# sourceMappingURL=bulkupdate.css.map */ diff --git a/src/adminactions/static/adminactions/css/bulkupdate.css.map b/src/adminactions/static/adminactions/css/bulkupdate.css.map index 8469433a..108a6e20 100644 --- a/src/adminactions/static/adminactions/css/bulkupdate.css.map +++ b/src/adminactions/static/adminactions/css/bulkupdate.css.map @@ -1 +1 @@ -{"version":3,"sourceRoot":"","sources":["bulkupdate.scss"],"names":[],"mappings":"AACI,eACI,kCAGJ,kBACI,yBAEA,qBACI,8BAGJ,qCACI,gBASZ,MACI,WAEA,UAEA,YACI,UAIR,MACI,YACA,UAEA,YACI,UAIR,aACI","file":"bulkupdate.css"} \ No newline at end of file +{"version":3,"sourceRoot":"","sources":["bulkupdate.scss"],"names":[],"mappings":"AACI,eACI,kCAGJ,kBACI,yBAEA,qBACI,8BAGJ,qCACI,gBASZ,MACI,WAEA,UAEA,YACI,UAIR,MACI,YACA,UAEA,YACI,UAIR,aACI","file":"bulkupdate.css"} diff --git a/src/adminactions/static/adminactions/css/bulkupdate.scss b/src/adminactions/static/adminactions/css/bulkupdate.scss index 82e4dd4c..2b34af9b 100644 --- a/src/adminactions/static/adminactions/css/bulkupdate.scss +++ b/src/adminactions/static/adminactions/css/bulkupdate.scss @@ -14,10 +14,8 @@ table { min-width: 100px; } } - &.bulk-update-results { - - } - + &.bulk-update-results { + } } #col1 { diff --git a/src/adminactions/static/adminactions/css/massupdate.css b/src/adminactions/static/adminactions/css/massupdate.css index 13f726dc..0191bb49 100644 --- a/src/adminactions/static/adminactions/css/massupdate.css +++ b/src/adminactions/static/adminactions/css/massupdate.css @@ -1 +1,20 @@ -table.mass-update{border:1px solid #c9c9c9}table.mass-update td{border-left:1px solid #c9c9c9}table.mass-update select.func_select{min-width:100px}#col1{float:left;width:70%}#col2{float:right;width:30%}#col2 select{width:100%}/*# sourceMappingURL=massupdate.css.map */ +table.mass-update { + border: 1px solid #c9c9c9; +} +table.mass-update td { + border-left: 1px solid #c9c9c9; +} +table.mass-update select.func_select { + min-width: 100px; +} +#col1 { + float: left; + width: 70%; +} +#col2 { + float: right; + width: 30%; +} +#col2 select { + width: 100%; +} /*# sourceMappingURL=massupdate.css.map */ diff --git a/src/adminactions/static/adminactions/css/massupdate.css.map b/src/adminactions/static/adminactions/css/massupdate.css.map index 7456d113..6b628184 100644 --- a/src/adminactions/static/adminactions/css/massupdate.css.map +++ b/src/adminactions/static/adminactions/css/massupdate.css.map @@ -1 +1 @@ -{"version":3,"sourceRoot":"","sources":["massupdate.scss"],"names":[],"mappings":"AACA,kBACI,yBAEA,qBACI,8BAGJ,qCACI,gBAIR,MACI,WACA,UAGJ,MACI,YACA,UAGJ,aACI","file":"massupdate.css"} \ No newline at end of file +{"version":3,"sourceRoot":"","sources":["massupdate.scss"],"names":[],"mappings":"AACA,kBACI,yBAEA,qBACI,8BAGJ,qCACI,gBAIR,MACI,WACA,UAGJ,MACI,YACA,UAGJ,aACI","file":"massupdate.css"} diff --git a/src/adminactions/static/adminactions/css/massupdate.scss b/src/adminactions/static/adminactions/css/massupdate.scss index 7a0361d2..c6a6cb8d 100644 --- a/src/adminactions/static/adminactions/css/massupdate.scss +++ b/src/adminactions/static/adminactions/css/massupdate.scss @@ -1,4 +1,3 @@ - table.mass-update { border: 1px solid #c9c9c9; diff --git a/src/adminactions/static/adminactions/js/bulkupdate.js b/src/adminactions/static/adminactions/js/bulkupdate.js index b210eaab..4370e4e6 100644 --- a/src/adminactions/static/adminactions/js/bulkupdate.js +++ b/src/adminactions/static/adminactions/js/bulkupdate.js @@ -15,19 +15,18 @@ var data = localStorage.getItem(model); if (data) { $.each(formData, function (i, pair) { - $("input[name='" + pair.name + "']").val(pair.value); + $("input[name='" + pair.name + "']").val(pair.value); // $("td.col_field.field-" + pair.name + "-value input").val(pair.value); }); } $("#sel-cmd").val(""); } else if (this.value === "default") { - $('td.col_field').each(function () { - $(this).find('input').val($(this).data('col')) + $("td.col_field").each(function () { + $(this).find("input").val($(this).data("col")); }); $("#sel-cmd").val(""); - } - }) + }); // console.log(formData); }); diff --git a/src/adminactions/static/adminactions/js/jqplot/MIT-LICENSE.txt b/src/adminactions/static/adminactions/js/jqplot/MIT-LICENSE.txt index f8111b9c..5d43e39a 100644 --- a/src/adminactions/static/adminactions/js/jqplot/MIT-LICENSE.txt +++ b/src/adminactions/static/adminactions/js/jqplot/MIT-LICENSE.txt @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. \ No newline at end of file +THE SOFTWARE. diff --git a/src/adminactions/static/adminactions/js/jqplot/README.txt b/src/adminactions/static/adminactions/js/jqplot/README.txt index 8777a20c..359832a8 100644 --- a/src/adminactions/static/adminactions/js/jqplot/README.txt +++ b/src/adminactions/static/adminactions/js/jqplot/README.txt @@ -21,8 +21,8 @@ Bugs, issues, feature requests: @@ -36,23 +36,23 @@ For usage instructions, see in usage.txt. For available options, Building from source: If you've cloned the repository, you can build a distribution from source. -You need to have ant installed. You can simply -type "ant" from the jqplot directory to build the default "all" target. +You need to have ant installed. You can simply +type "ant" from the jqplot directory to build the default "all" target. There are 6 pertinent targets: clean, dist, min, docs, compress and all. Use: > ant -p -to get a description of the various build targets. +to get a description of the various build targets. Legal Notices: Copyright (c) 2009-2013 Chris Leonello -jqPlot is currently available for use in all personal or commercial projects -under both the MIT and GPL version 2.0 licenses. This means that you can -choose the license that best suits your project and use it accordingly. +jqPlot is currently available for use in all personal or commercial projects +under both the MIT and GPL version 2.0 licenses. This means that you can +choose the license that best suits your project and use it accordingly. -Although not required, the author would appreciate an email letting him -know of any substantial use of jqPlot. You can reach the author at: +Although not required, the author would appreciate an email letting him +know of any substantial use of jqPlot. You can reach the author at: chris at jqplot or see http://www.jqplot.com/info.php . If you are feeling kind and generous, consider supporting the project by @@ -64,7 +64,7 @@ Date instance methods: author Ken Snyder (ken d snyder at gmail dot com) date 2008-09-10 - version 2.0.2 (http://kendsnyder.com/sandbox/date/) + version 2.0.2 (http://kendsnyder.com/sandbox/date/) license Creative Commons Attribution License 3.0 (http://creativecommons.org/licenses/by/3.0/) JavaScript printf/sprintf functions. diff --git a/src/adminactions/static/adminactions/js/jqplot/jquery.jqplot.css b/src/adminactions/static/adminactions/js/jqplot/jquery.jqplot.css index f6768a6a..f2f35003 100644 --- a/src/adminactions/static/adminactions/js/jqplot/jquery.jqplot.css +++ b/src/adminactions/static/adminactions/js/jqplot/jquery.jqplot.css @@ -4,7 +4,7 @@ color: #666666; font-family: "Trebuchet MS", Arial, Helvetica, sans-serif; font-size: 1em; -/* height: 300px; + /* height: 300px; width: 400px;*/ } @@ -25,23 +25,42 @@ margin-right: 10px; } -.jqplot-y2axis, .jqplot-y3axis, .jqplot-y4axis, .jqplot-y5axis, .jqplot-y6axis, .jqplot-y7axis, .jqplot-y8axis, .jqplot-y9axis, .jqplot-yMidAxis { +.jqplot-y2axis, +.jqplot-y3axis, +.jqplot-y4axis, +.jqplot-y5axis, +.jqplot-y6axis, +.jqplot-y7axis, +.jqplot-y8axis, +.jqplot-y9axis, +.jqplot-yMidAxis { margin-left: 10px; margin-right: 10px; } /*rules applied to all axis tick divs*/ -.jqplot-axis-tick, .jqplot-xaxis-tick, .jqplot-yaxis-tick, .jqplot-x2axis-tick, .jqplot-y2axis-tick, .jqplot-y3axis-tick, .jqplot-y4axis-tick, .jqplot-y5axis-tick, .jqplot-y6axis-tick, .jqplot-y7axis-tick, .jqplot-y8axis-tick, .jqplot-y9axis-tick, .jqplot-yMidAxis-tick { +.jqplot-axis-tick, +.jqplot-xaxis-tick, +.jqplot-yaxis-tick, +.jqplot-x2axis-tick, +.jqplot-y2axis-tick, +.jqplot-y3axis-tick, +.jqplot-y4axis-tick, +.jqplot-y5axis-tick, +.jqplot-y6axis-tick, +.jqplot-y7axis-tick, +.jqplot-y8axis-tick, +.jqplot-y9axis-tick, +.jqplot-yMidAxis-tick { position: absolute; white-space: pre; } - .jqplot-xaxis-tick { top: 0px; /* initial position untill tick is drawn in proper place */ left: 15px; -/* padding-top: 10px;*/ + /* padding-top: 10px;*/ vertical-align: top; } @@ -49,7 +68,7 @@ bottom: 0px; /* initial position untill tick is drawn in proper place */ left: 15px; -/* padding-bottom: 10px;*/ + /* padding-bottom: 10px;*/ vertical-align: bottom; } @@ -57,25 +76,32 @@ right: 0px; /* initial position untill tick is drawn in proper place */ top: 15px; -/* padding-right: 10px;*/ + /* padding-right: 10px;*/ text-align: right; } .jqplot-yaxis-tick.jqplot-breakTick { right: -20px; margin-right: 0px; - padding:1px 5px 1px 5px; + padding: 1px 5px 1px 5px; /*background-color: white;*/ z-index: 2; font-size: 1.5em; } -.jqplot-y2axis-tick, .jqplot-y3axis-tick, .jqplot-y4axis-tick, .jqplot-y5axis-tick, .jqplot-y6axis-tick, .jqplot-y7axis-tick, .jqplot-y8axis-tick, .jqplot-y9axis-tick { +.jqplot-y2axis-tick, +.jqplot-y3axis-tick, +.jqplot-y4axis-tick, +.jqplot-y5axis-tick, +.jqplot-y6axis-tick, +.jqplot-y7axis-tick, +.jqplot-y8axis-tick, +.jqplot-y9axis-tick { left: 0px; /* initial position untill tick is drawn in proper place */ top: 15px; -/* padding-left: 10px;*/ -/* padding-right: 15px;*/ + /* padding-left: 10px;*/ + /* padding-right: 15px;*/ text-align: left; } @@ -98,7 +124,7 @@ .jqplot-yaxis-label { margin-right: 10px; -/* text-align: center;*/ + /* text-align: center;*/ font-size: 11pt; position: absolute; } @@ -108,8 +134,15 @@ position: absolute; } -.jqplot-y2axis-label, .jqplot-y3axis-label, .jqplot-y4axis-label, .jqplot-y5axis-label, .jqplot-y6axis-label, .jqplot-y7axis-label, .jqplot-y8axis-label, .jqplot-y9axis-label { -/* text-align: center;*/ +.jqplot-y2axis-label, +.jqplot-y3axis-label, +.jqplot-y4axis-label, +.jqplot-y5axis-label, +.jqplot-y6axis-label, +.jqplot-y7axis-label, +.jqplot-y8axis-label, +.jqplot-y9axis-label { + /* text-align: center;*/ font-size: 11pt; margin-left: 10px; position: absolute; @@ -132,15 +165,16 @@ table.jqplot-table-legend { margin-right: 12px; } -table.jqplot-table-legend, table.jqplot-cursor-legend { - background-color: rgba(255,255,255,0.6); +table.jqplot-table-legend, +table.jqplot-cursor-legend { + background-color: rgba(255, 255, 255, 0.6); border: 1px solid #cccccc; position: absolute; font-size: 0.75em; } td.jqplot-table-legend { - vertical-align:middle; + vertical-align: middle; } /* @@ -159,7 +193,8 @@ tr.jqplot-table-legend:first td.jqplot-table-legend-swatch { } */ -td.jqplot-seriesToggle:hover, td.jqplot-seriesToggle:active { +td.jqplot-seriesToggle:hover, +td.jqplot-seriesToggle:active { cursor: pointer; } @@ -169,12 +204,12 @@ td.jqplot-seriesToggle:hover, td.jqplot-seriesToggle:active { div.jqplot-table-legend-swatch-outline { border: 1px solid #cccccc; - padding:1px; + padding: 1px; } div.jqplot-table-legend-swatch { - width:0px; - height:0px; + width: 0px; + height: 0px; border-top-width: 5px; border-bottom-width: 5px; border-left-width: 6px; @@ -197,20 +232,20 @@ table.jqplot-cursor-tooltip { font-size: 0.75em; } - .jqplot-cursor-tooltip { border: 1px solid #cccccc; font-size: 0.75em; white-space: nowrap; - background: rgba(208,208,208,0.5); + background: rgba(208, 208, 208, 0.5); padding: 1px; } -.jqplot-highlighter-tooltip, .jqplot-canvasOverlay-tooltip { +.jqplot-highlighter-tooltip, +.jqplot-canvasOverlay-tooltip { border: 1px solid #cccccc; font-size: 0.75em; white-space: nowrap; - background: rgba(208,208,208,0.5); + background: rgba(208, 208, 208, 0.5); padding: 1px; } @@ -218,7 +253,7 @@ table.jqplot-cursor-tooltip { font-size: 0.75em; z-index: 2; } - + td.jqplot-cursor-legend-swatch { vertical-align: middle; text-align: center; @@ -230,12 +265,12 @@ div.jqplot-cursor-legend-swatch { } .jqplot-error { -/* Styles added to the plot target container when there is an error go here.*/ + /* Styles added to the plot target container when there is an error go here.*/ text-align: center; } .jqplot-error-message { -/* Styling of the custom error message div goes here.*/ + /* Styling of the custom error message div goes here.*/ position: relative; top: 46%; display: inline-block; @@ -243,7 +278,7 @@ div.jqplot-cursor-legend-swatch { div.jqplot-bubble-label { font-size: 0.8em; -/* background: rgba(90%, 90%, 90%, 0.15);*/ + /* background: rgba(90%, 90%, 90%, 0.15);*/ padding-left: 2px; padding-right: 2px; color: rgb(20%, 20%, 20%); diff --git a/src/adminactions/static/adminactions/js/jqplot/jquery.jqplot.min.css b/src/adminactions/static/adminactions/js/jqplot/jquery.jqplot.min.css index 0f84835b..d80dd94b 100644 --- a/src/adminactions/static/adminactions/js/jqplot/jquery.jqplot.min.css +++ b/src/adminactions/static/adminactions/js/jqplot/jquery.jqplot.min.css @@ -1 +1,220 @@ -.jqplot-target{position:relative;color:#666;font-family:"Trebuchet MS",Arial,Helvetica,sans-serif;font-size:1em}.jqplot-axis{font-size:.75em}.jqplot-xaxis{margin-top:10px}.jqplot-x2axis{margin-bottom:10px}.jqplot-yaxis{margin-right:10px}.jqplot-y2axis,.jqplot-y3axis,.jqplot-y4axis,.jqplot-y5axis,.jqplot-y6axis,.jqplot-y7axis,.jqplot-y8axis,.jqplot-y9axis,.jqplot-yMidAxis{margin-left:10px;margin-right:10px}.jqplot-axis-tick,.jqplot-xaxis-tick,.jqplot-yaxis-tick,.jqplot-x2axis-tick,.jqplot-y2axis-tick,.jqplot-y3axis-tick,.jqplot-y4axis-tick,.jqplot-y5axis-tick,.jqplot-y6axis-tick,.jqplot-y7axis-tick,.jqplot-y8axis-tick,.jqplot-y9axis-tick,.jqplot-yMidAxis-tick{position:absolute;white-space:pre}.jqplot-xaxis-tick{top:0;left:15px;vertical-align:top}.jqplot-x2axis-tick{bottom:0;left:15px;vertical-align:bottom}.jqplot-yaxis-tick{right:0;top:15px;text-align:right}.jqplot-yaxis-tick.jqplot-breakTick{right:-20px;margin-right:0;padding:1px 5px 1px 5px;z-index:2;font-size:1.5em}.jqplot-y2axis-tick,.jqplot-y3axis-tick,.jqplot-y4axis-tick,.jqplot-y5axis-tick,.jqplot-y6axis-tick,.jqplot-y7axis-tick,.jqplot-y8axis-tick,.jqplot-y9axis-tick{left:0;top:15px;text-align:left}.jqplot-yMidAxis-tick{text-align:center;white-space:nowrap}.jqplot-xaxis-label{margin-top:10px;font-size:11pt;position:absolute}.jqplot-x2axis-label{margin-bottom:10px;font-size:11pt;position:absolute}.jqplot-yaxis-label{margin-right:10px;font-size:11pt;position:absolute}.jqplot-yMidAxis-label{font-size:11pt;position:absolute}.jqplot-y2axis-label,.jqplot-y3axis-label,.jqplot-y4axis-label,.jqplot-y5axis-label,.jqplot-y6axis-label,.jqplot-y7axis-label,.jqplot-y8axis-label,.jqplot-y9axis-label{font-size:11pt;margin-left:10px;position:absolute}.jqplot-meterGauge-tick{font-size:.75em;color:#999}.jqplot-meterGauge-label{font-size:1em;color:#999}table.jqplot-table-legend{margin-top:12px;margin-bottom:12px;margin-left:12px;margin-right:12px}table.jqplot-table-legend,table.jqplot-cursor-legend{background-color:rgba(255,255,255,0.6);border:1px solid #ccc;position:absolute;font-size:.75em}td.jqplot-table-legend{vertical-align:middle}td.jqplot-seriesToggle:hover,td.jqplot-seriesToggle:active{cursor:pointer}.jqplot-table-legend .jqplot-series-hidden{text-decoration:line-through}div.jqplot-table-legend-swatch-outline{border:1px solid #ccc;padding:1px}div.jqplot-table-legend-swatch{width:0;height:0;border-top-width:5px;border-bottom-width:5px;border-left-width:6px;border-right-width:6px;border-top-style:solid;border-bottom-style:solid;border-left-style:solid;border-right-style:solid}.jqplot-title{top:0;left:0;padding-bottom:.5em;font-size:1.2em}table.jqplot-cursor-tooltip{border:1px solid #ccc;font-size:.75em}.jqplot-cursor-tooltip{border:1px solid #ccc;font-size:.75em;white-space:nowrap;background:rgba(208,208,208,0.5);padding:1px}.jqplot-highlighter-tooltip,.jqplot-canvasOverlay-tooltip{border:1px solid #ccc;font-size:.75em;white-space:nowrap;background:rgba(208,208,208,0.5);padding:1px}.jqplot-point-label{font-size:.75em;z-index:2}td.jqplot-cursor-legend-swatch{vertical-align:middle;text-align:center}div.jqplot-cursor-legend-swatch{width:1.2em;height:.7em}.jqplot-error{text-align:center}.jqplot-error-message{position:relative;top:46%;display:inline-block}div.jqplot-bubble-label{font-size:.8em;padding-left:2px;padding-right:2px;color:rgb(20%,20%,20%)}div.jqplot-bubble-label.jqplot-bubble-label-highlight{background:rgba(90%,90%,90%,0.7)}div.jqplot-noData-container{text-align:center;background-color:rgba(96%,96%,96%,0.3)} \ No newline at end of file +.jqplot-target { + position: relative; + color: #666; + font-family: "Trebuchet MS", Arial, Helvetica, sans-serif; + font-size: 1em; +} +.jqplot-axis { + font-size: 0.75em; +} +.jqplot-xaxis { + margin-top: 10px; +} +.jqplot-x2axis { + margin-bottom: 10px; +} +.jqplot-yaxis { + margin-right: 10px; +} +.jqplot-y2axis, +.jqplot-y3axis, +.jqplot-y4axis, +.jqplot-y5axis, +.jqplot-y6axis, +.jqplot-y7axis, +.jqplot-y8axis, +.jqplot-y9axis, +.jqplot-yMidAxis { + margin-left: 10px; + margin-right: 10px; +} +.jqplot-axis-tick, +.jqplot-xaxis-tick, +.jqplot-yaxis-tick, +.jqplot-x2axis-tick, +.jqplot-y2axis-tick, +.jqplot-y3axis-tick, +.jqplot-y4axis-tick, +.jqplot-y5axis-tick, +.jqplot-y6axis-tick, +.jqplot-y7axis-tick, +.jqplot-y8axis-tick, +.jqplot-y9axis-tick, +.jqplot-yMidAxis-tick { + position: absolute; + white-space: pre; +} +.jqplot-xaxis-tick { + top: 0; + left: 15px; + vertical-align: top; +} +.jqplot-x2axis-tick { + bottom: 0; + left: 15px; + vertical-align: bottom; +} +.jqplot-yaxis-tick { + right: 0; + top: 15px; + text-align: right; +} +.jqplot-yaxis-tick.jqplot-breakTick { + right: -20px; + margin-right: 0; + padding: 1px 5px 1px 5px; + z-index: 2; + font-size: 1.5em; +} +.jqplot-y2axis-tick, +.jqplot-y3axis-tick, +.jqplot-y4axis-tick, +.jqplot-y5axis-tick, +.jqplot-y6axis-tick, +.jqplot-y7axis-tick, +.jqplot-y8axis-tick, +.jqplot-y9axis-tick { + left: 0; + top: 15px; + text-align: left; +} +.jqplot-yMidAxis-tick { + text-align: center; + white-space: nowrap; +} +.jqplot-xaxis-label { + margin-top: 10px; + font-size: 11pt; + position: absolute; +} +.jqplot-x2axis-label { + margin-bottom: 10px; + font-size: 11pt; + position: absolute; +} +.jqplot-yaxis-label { + margin-right: 10px; + font-size: 11pt; + position: absolute; +} +.jqplot-yMidAxis-label { + font-size: 11pt; + position: absolute; +} +.jqplot-y2axis-label, +.jqplot-y3axis-label, +.jqplot-y4axis-label, +.jqplot-y5axis-label, +.jqplot-y6axis-label, +.jqplot-y7axis-label, +.jqplot-y8axis-label, +.jqplot-y9axis-label { + font-size: 11pt; + margin-left: 10px; + position: absolute; +} +.jqplot-meterGauge-tick { + font-size: 0.75em; + color: #999; +} +.jqplot-meterGauge-label { + font-size: 1em; + color: #999; +} +table.jqplot-table-legend { + margin-top: 12px; + margin-bottom: 12px; + margin-left: 12px; + margin-right: 12px; +} +table.jqplot-table-legend, +table.jqplot-cursor-legend { + background-color: rgba(255, 255, 255, 0.6); + border: 1px solid #ccc; + position: absolute; + font-size: 0.75em; +} +td.jqplot-table-legend { + vertical-align: middle; +} +td.jqplot-seriesToggle:hover, +td.jqplot-seriesToggle:active { + cursor: pointer; +} +.jqplot-table-legend .jqplot-series-hidden { + text-decoration: line-through; +} +div.jqplot-table-legend-swatch-outline { + border: 1px solid #ccc; + padding: 1px; +} +div.jqplot-table-legend-swatch { + width: 0; + height: 0; + border-top-width: 5px; + border-bottom-width: 5px; + border-left-width: 6px; + border-right-width: 6px; + border-top-style: solid; + border-bottom-style: solid; + border-left-style: solid; + border-right-style: solid; +} +.jqplot-title { + top: 0; + left: 0; + padding-bottom: 0.5em; + font-size: 1.2em; +} +table.jqplot-cursor-tooltip { + border: 1px solid #ccc; + font-size: 0.75em; +} +.jqplot-cursor-tooltip { + border: 1px solid #ccc; + font-size: 0.75em; + white-space: nowrap; + background: rgba(208, 208, 208, 0.5); + padding: 1px; +} +.jqplot-highlighter-tooltip, +.jqplot-canvasOverlay-tooltip { + border: 1px solid #ccc; + font-size: 0.75em; + white-space: nowrap; + background: rgba(208, 208, 208, 0.5); + padding: 1px; +} +.jqplot-point-label { + font-size: 0.75em; + z-index: 2; +} +td.jqplot-cursor-legend-swatch { + vertical-align: middle; + text-align: center; +} +div.jqplot-cursor-legend-swatch { + width: 1.2em; + height: 0.7em; +} +.jqplot-error { + text-align: center; +} +.jqplot-error-message { + position: relative; + top: 46%; + display: inline-block; +} +div.jqplot-bubble-label { + font-size: 0.8em; + padding-left: 2px; + padding-right: 2px; + color: rgb(20%, 20%, 20%); +} +div.jqplot-bubble-label.jqplot-bubble-label-highlight { + background: rgba(90%, 90%, 90%, 0.7); +} +div.jqplot-noData-container { + text-align: center; + background-color: rgba(96%, 96%, 96%, 0.3); +} diff --git a/src/adminactions/static/adminactions/js/jqplot/jquery.jqplot.min.js b/src/adminactions/static/adminactions/js/jqplot/jquery.jqplot.min.js index d015388d..b72a38ca 100644 --- a/src/adminactions/static/adminactions/js/jqplot/jquery.jqplot.min.js +++ b/src/adminactions/static/adminactions/js/jqplot/jquery.jqplot.min.js @@ -1 +1,9968 @@ -(function(L){var u;L.fn.emptyForce=function(){for(var ah=0,ai;(ai=L(this)[ah])!=null;ah++){if(ai.nodeType===1){L.cleanData(ai.getElementsByTagName("*"))}if(L.jqplot.use_excanvas){ai.outerHTML=""}else{while(ai.firstChild){ai.removeChild(ai.firstChild)}}ai=null}return L(this)};L.fn.removeChildForce=function(ah){while(ah.firstChild){this.removeChildForce(ah.firstChild);ah.removeChild(ah.firstChild)}};L.fn.jqplot=function(){var ah=[];var aj=[];for(var ak=0,ai=arguments.length;ak'+ao+"");L("#"+an).addClass("jqplot-error");document.getElementById(an).style.background=L.jqplot.config.errorBackground;document.getElementById(an).style.border=L.jqplot.config.errorBorder;document.getElementById(an).style.fontFamily=L.jqplot.config.errorFontFamily;document.getElementById(an).style.fontSize=L.jqplot.config.errorFontSize;document.getElementById(an).style.fontStyle=L.jqplot.config.errorFontStyle;document.getElementById(an).style.fontWeight=L.jqplot.config.errorFontWeight}}else{am.init(an,aj,ah);am.draw();am.themeEngine.init.call(am);return am}};L.jqplot.version="1.0.8";L.jqplot.revision="1250";L.jqplot.targetCounter=1;L.jqplot.CanvasManager=function(){if(typeof L.jqplot.CanvasManager.canvases=="undefined"){L.jqplot.CanvasManager.canvases=[];L.jqplot.CanvasManager.free=[]}var ah=[];this.getCanvas=function(){var ak;var aj=true;if(!L.jqplot.use_excanvas){for(var al=0,ai=L.jqplot.CanvasManager.canvases.length;al887){L.jqplot.support_canvas_text.result=true}else{L.jqplot.support_canvas_text.result=!!(document.createElement("canvas").getContext&&typeof document.createElement("canvas").getContext("2d").fillText=="function")}}return L.jqplot.support_canvas_text.result};L.jqplot.use_excanvas=((!L.support.boxModel||!L.support.objectAll||!$support.leadingWhitespace)&&!L.jqplot.support_canvas())?true:false;L.jqplot.preInitHooks=[];L.jqplot.postInitHooks=[];L.jqplot.preParseOptionsHooks=[];L.jqplot.postParseOptionsHooks=[];L.jqplot.preDrawHooks=[];L.jqplot.postDrawHooks=[];L.jqplot.preDrawSeriesHooks=[];L.jqplot.postDrawSeriesHooks=[];L.jqplot.preDrawLegendHooks=[];L.jqplot.addLegendRowHooks=[];L.jqplot.preSeriesInitHooks=[];L.jqplot.postSeriesInitHooks=[];L.jqplot.preParseSeriesOptionsHooks=[];L.jqplot.postParseSeriesOptionsHooks=[];L.jqplot.eventListenerHooks=[];L.jqplot.preDrawSeriesShadowHooks=[];L.jqplot.postDrawSeriesShadowHooks=[];L.jqplot.ElemContainer=function(){this._elem;this._plotWidth;this._plotHeight;this._plotDimensions={height:null,width:null}};L.jqplot.ElemContainer.prototype.createElement=function(ak,am,ai,aj,an){this._offsets=am;var ah=ai||"jqplot";var al=document.createElement(ak);this._elem=L(al);this._elem.addClass(ah);this._elem.css(aj);this._elem.attr(an);al=null;return this._elem};L.jqplot.ElemContainer.prototype.getWidth=function(){if(this._elem){return this._elem.outerWidth(true)}else{return null}};L.jqplot.ElemContainer.prototype.getHeight=function(){if(this._elem){return this._elem.outerHeight(true)}else{return null}};L.jqplot.ElemContainer.prototype.getPosition=function(){if(this._elem){return this._elem.position()}else{return{top:null,left:null,bottom:null,right:null}}};L.jqplot.ElemContainer.prototype.getTop=function(){return this.getPosition().top};L.jqplot.ElemContainer.prototype.getLeft=function(){return this.getPosition().left};L.jqplot.ElemContainer.prototype.getBottom=function(){return this._elem.css("bottom")};L.jqplot.ElemContainer.prototype.getRight=function(){return this._elem.css("right")};function w(ah){L.jqplot.ElemContainer.call(this);this.name=ah;this._series=[];this.show=false;this.tickRenderer=L.jqplot.AxisTickRenderer;this.tickOptions={};this.labelRenderer=L.jqplot.AxisLabelRenderer;this.labelOptions={};this.label=null;this.showLabel=true;this.min=null;this.max=null;this.autoscale=false;this.pad=1.2;this.padMax=null;this.padMin=null;this.ticks=[];this.numberTicks;this.tickInterval;this.renderer=L.jqplot.LinearAxisRenderer;this.rendererOptions={};this.showTicks=true;this.showTickMarks=true;this.showMinorTicks=true;this.drawMajorGridlines=true;this.drawMinorGridlines=false;this.drawMajorTickMarks=true;this.drawMinorTickMarks=true;this.useSeriesColor=false;this.borderWidth=null;this.borderColor=null;this.scaleToHiddenSeries=false;this._dataBounds={min:null,max:null};this._intervalStats=[];this._offsets={min:null,max:null};this._ticks=[];this._label=null;this.syncTicks=null;this.tickSpacing=75;this._min=null;this._max=null;this._tickInterval=null;this._numberTicks=null;this.__ticks=null;this._options={}}w.prototype=new L.jqplot.ElemContainer();w.prototype.constructor=w;w.prototype.init=function(){if(L.isFunction(this.renderer)){this.renderer=new this.renderer()}this.tickOptions.axis=this.name;if(this.tickOptions.showMark==null){this.tickOptions.showMark=this.showTicks}if(this.tickOptions.showMark==null){this.tickOptions.showMark=this.showTickMarks}if(this.tickOptions.showLabel==null){this.tickOptions.showLabel=this.showTicks}if(this.label==null||this.label==""){this.showLabel=false}else{this.labelOptions.label=this.label}if(this.showLabel==false){this.labelOptions.show=false}if(this.pad==0){this.pad=1}if(this.padMax==0){this.padMax=1}if(this.padMin==0){this.padMin=1}if(this.padMax==null){this.padMax=(this.pad-1)/2+1}if(this.padMin==null){this.padMin=(this.pad-1)/2+1}this.pad=this.padMax+this.padMin-1;if(this.min!=null||this.max!=null){this.autoscale=false}if(this.syncTicks==null&&this.name.indexOf("y")>-1){this.syncTicks=true}else{if(this.syncTicks==null){this.syncTicks=false}}this.renderer.init.call(this,this.rendererOptions)};w.prototype.draw=function(ah,ai){if(this.__ticks){this.__ticks=null}return this.renderer.draw.call(this,ah,ai)};w.prototype.set=function(){this.renderer.set.call(this)};w.prototype.pack=function(ai,ah){if(this.show){this.renderer.pack.call(this,ai,ah)}if(this._min==null){this._min=this.min;this._max=this.max;this._tickInterval=this.tickInterval;this._numberTicks=this.numberTicks;this.__ticks=this._ticks}};w.prototype.reset=function(){this.renderer.reset.call(this)};w.prototype.resetScale=function(ah){L.extend(true,this,{min:null,max:null,numberTicks:null,tickInterval:null,_ticks:[],ticks:[]},ah);this.resetDataBounds()};w.prototype.resetDataBounds=function(){var ao=this._dataBounds;ao.min=null;ao.max=null;var ai,ap,am;var aj=(this.show)?true:false;for(var al=0;alao.max)||ao.max==null){ao.max=am[ak][0]}}else{if((am[ak][ah]!=null&&am[ak][ah]ao.max)||ao.max==null){ao.max=am[ak][an]}}}if(aj&&ap.renderer.constructor!==L.jqplot.BarRenderer){aj=false}else{if(aj&&this._options.hasOwnProperty("forceTickAt0")&&this._options.forceTickAt0==false){aj=false}else{if(aj&&ap.renderer.constructor===L.jqplot.BarRenderer){if(ap.barDirection=="vertical"&&this.name!="xaxis"&&this.name!="x2axis"){if(this._options.pad!=null||this._options.padMin!=null){aj=false}}else{if(ap.barDirection=="horizontal"&&(this.name=="xaxis"||this.name=="x2axis")){if(this._options.pad!=null||this._options.padMin!=null){aj=false}}}}}}}}if(aj&&this.renderer.constructor===L.jqplot.LinearAxisRenderer&&ao.min>=0){this.padMin=1;this.forceTickAt0=true}};function q(ah){L.jqplot.ElemContainer.call(this);this.show=false;this.location="ne";this.labels=[];this.showLabels=true;this.showSwatches=true;this.placement="insideGrid";this.xoffset=0;this.yoffset=0;this.border;this.background;this.textColor;this.fontFamily;this.fontSize;this.rowSpacing="0.5em";this.renderer=L.jqplot.TableLegendRenderer;this.rendererOptions={};this.preDraw=false;this.marginTop=null;this.marginRight=null;this.marginBottom=null;this.marginLeft=null;this.escapeHtml=false;this._series=[];L.extend(true,this,ah)}q.prototype=new L.jqplot.ElemContainer();q.prototype.constructor=q;q.prototype.setOptions=function(ah){L.extend(true,this,ah);if(this.placement=="inside"){this.placement="insideGrid"}if(this.xoffset>0){if(this.placement=="insideGrid"){switch(this.location){case"nw":case"w":case"sw":if(this.marginLeft==null){this.marginLeft=this.xoffset+"px"}this.marginRight="0px";break;case"ne":case"e":case"se":default:if(this.marginRight==null){this.marginRight=this.xoffset+"px"}this.marginLeft="0px";break}}else{if(this.placement=="outside"){switch(this.location){case"nw":case"w":case"sw":if(this.marginRight==null){this.marginRight=this.xoffset+"px"}this.marginLeft="0px";break;case"ne":case"e":case"se":default:if(this.marginLeft==null){this.marginLeft=this.xoffset+"px"}this.marginRight="0px";break}}}this.xoffset=0}if(this.yoffset>0){if(this.placement=="outside"){switch(this.location){case"sw":case"s":case"se":if(this.marginTop==null){this.marginTop=this.yoffset+"px"}this.marginBottom="0px";break;case"ne":case"n":case"nw":default:if(this.marginBottom==null){this.marginBottom=this.yoffset+"px"}this.marginTop="0px";break}}else{if(this.placement=="insideGrid"){switch(this.location){case"sw":case"s":case"se":if(this.marginBottom==null){this.marginBottom=this.yoffset+"px"}this.marginTop="0px";break;case"ne":case"n":case"nw":default:if(this.marginTop==null){this.marginTop=this.yoffset+"px"}this.marginBottom="0px";break}}}this.yoffset=0}};q.prototype.init=function(){if(L.isFunction(this.renderer)){this.renderer=new this.renderer()}this.renderer.init.call(this,this.rendererOptions)};q.prototype.draw=function(ai,aj){for(var ah=0;ah');this.target.append(az);az.height(aD);az.width(aA);az.css("top",this.eventCanvas._offsets.top);az.css("left",this.eventCanvas._offsets.left);var aC=L('
');az.append(aC);aC.html(this.noDataIndicator.indicator);var aB=aC.height();var ax=aC.width();aC.height(aB);aC.width(ax);aC.css("top",(aD-aB)/2+"px")})}}this.data=L.extend(true,[],ar);this.parseOptions(ay);if(this.textColor){this.target.css("color",this.textColor)}if(this.fontFamily){this.target.css("font-family",this.fontFamily)}if(this.fontSize){this.target.css("font-size",this.fontSize)}this.title.init();this.legend.init();this._sumy=0;this._sumx=0;this.computePlotData();for(var at=0;at0){for(var aq=au;aq--;){var an=this._plotData[aq][ap][av];if(aw*an>=0){this._plotData[au][ap][av]+=an;this._stackData[au][ap][av]+=an;break}}}}}else{for(var ar=0;ar0){at._prevPlotData=this.series[au-1]._plotData}at._sumy=0;at._sumx=0;for(ar=at.data.length-1;ar>-1;ar--){at._sumy+=at.data[ar][1];at._sumx+=at.data[ar][0]}}};this.populatePlotData=function(au,av){this._plotData=[];this._stackData=[];au._stackData=[];au._plotData=[];var ay={x:[],y:[]};if(this.stackSeries&&!au.disableStack){au._stack=true;var ax=(au._stackAxis==="x")?0:1;var az=L.extend(true,[],au.data);var aA=L.extend(true,[],au.data);var an,am,ao,aw,al;for(var ar=0;ar=0){aA[aq][ax]+=aw}}}for(var at=0;at0){au._prevPlotData=this.series[av-1]._plotData}au._sumy=0;au._sumx=0;for(at=au.data.length-1;at>-1;at--){au._sumy+=au.data[at][1];au._sumx+=au.data[at][0]}};this.getNextSeriesColor=(function(am){var al=0;var an=am.seriesColors;return function(){if(al=0&&an>=0){al.top+=aK;al.bottom+=aK;al.left+=an;al.right+=an}}var am=["top","bottom","left","right"];for(var aB in am){if(this._gridPadding[am[aB]]==null&&al[am[aB]]>0){this._gridPadding[am[aB]]=al[am[aB]]}else{if(this._gridPadding[am[aB]]==null){this._gridPadding[am[aB]]=this._defaultGridPadding[am[aB]]}}}var aA=this._gridPadding;if(this.legend.placement==="outsideGrid"){aA={top:this.title.getHeight(),left:0,right:0,bottom:0};if(this.legend.location==="s"){aA.left=this._gridPadding.left;aA.right=this._gridPadding.right}}ar.xaxis.pack({position:"absolute",bottom:this._gridPadding.bottom-ar.xaxis.getHeight(),left:0,width:this._width},{min:this._gridPadding.left,max:this._width-this._gridPadding.right});ar.yaxis.pack({position:"absolute",top:0,left:this._gridPadding.left-ar.yaxis.getWidth(),height:this._height},{min:this._height-this._gridPadding.bottom,max:this._gridPadding.top});ar.x2axis.pack({position:"absolute",top:this._gridPadding.top-ar.x2axis.getHeight(),left:0,width:this._width},{min:this._gridPadding.left,max:this._width-this._gridPadding.right});for(aH=8;aH>0;aH--){ar[aG[aH-1]].pack({position:"absolute",top:0,right:this._gridPadding.right-az[aH-1]},{min:this._height-this._gridPadding.bottom,max:this._gridPadding.top})}var au=(this._width-this._gridPadding.left-this._gridPadding.right)/2+this._gridPadding.left-ar.yMidAxis.getWidth()/2;ar.yMidAxis.pack({position:"absolute",top:0,left:au,zIndex:9,textAlign:"center"},{min:this._height-this._gridPadding.bottom,max:this._gridPadding.top});this.target.append(this.grid.createElement(this._gridPadding,this));this.grid.draw();var aq=this.series;var aJ=aq.length;for(aH=0,aE=aJ;aHax)?av:ax;var ar=this.series[aw];var aq=this.series[au];if(aq.renderer.smooth){var ap=aq.renderer._smoothedData.slice(0).reverse()}else{var ap=aq.gridData.slice(0).reverse()}if(ar.renderer.smooth){var at=ar.renderer._smoothedData.concat(ap)}else{var at=ar.gridData.concat(ap)}var ao=(an.color!==null)?an.color:this.series[ax].fillColor;var ay=(an.baseSeries!==null)?an.baseSeries:aw;var am=this.series[ay].renderer.shapeRenderer;var al={fillStyle:ao,fill:true,closePath:true};am.draw(ar.shadowCanvas._ctx,at,al)};this.bindCustomEvents=function(){this.eventCanvas._elem.bind("click",{plot:this},this.onClick);this.eventCanvas._elem.bind("dblclick",{plot:this},this.onDblClick);this.eventCanvas._elem.bind("mousedown",{plot:this},this.onMouseDown);this.eventCanvas._elem.bind("mousemove",{plot:this},this.onMouseMove);this.eventCanvas._elem.bind("mouseenter",{plot:this},this.onMouseEnter);this.eventCanvas._elem.bind("mouseleave",{plot:this},this.onMouseLeave);if(this.captureRightClick){this.eventCanvas._elem.bind("mouseup",{plot:this},this.onRightClick);this.eventCanvas._elem.get(0).oncontextmenu=function(){return false}}else{this.eventCanvas._elem.bind("mouseup",{plot:this},this.onMouseUp)}};function ai(av){var au=av.data.plot;var ap=au.eventCanvas._elem.offset();var at={x:av.pageX-ap.left,y:av.pageY-ap.top};var aq={xaxis:null,yaxis:null,x2axis:null,y2axis:null,y3axis:null,y4axis:null,y5axis:null,y6axis:null,y7axis:null,y8axis:null,y9axis:null,yMidAxis:null};var ar=["xaxis","yaxis","x2axis","y2axis","y3axis","y4axis","y5axis","y6axis","y7axis","y8axis","y9axis","yMidAxis"];var al=au.axes;var am,ao;for(am=11;am>0;am--){ao=ar[am-1];if(al[ao].show){aq[ao]=al[ao].series_p2u(at[ao.charAt(0)])}}return{offsets:ap,gridPos:at,dataPos:aq}}function ak(al,am){var aq=am.series;var aW,aU,aT,aO,aP,aJ,aI,aw,au,az,aA,aK;var aS,aX,aQ,ar,aH,aM,aV;var an,aN;for(aT=am.seriesStack.length-1;aT>=0;aT--){aW=am.seriesStack[aT];aO=aq[aW];aV=aO._highlightThreshold;switch(aO.renderer.constructor){case L.jqplot.BarRenderer:aJ=al.x;aI=al.y;for(aU=0;aUaH[0][0]&&aJaH[2][1]&&aIaH[0][0]+aV[0][0]&&aJaH[2][1]&&aI0&&-aI>=0){aw=2*Math.PI-Math.atan(-aI/aJ)}else{if(aJ>0&&-aI<0){aw=-Math.atan(-aI/aJ)}else{if(aJ<0){aw=Math.PI-Math.atan(-aI/aJ)}else{if(aJ==0&&-aI>0){aw=3*Math.PI/2}else{if(aJ==0&&-aI<0){aw=Math.PI/2}else{if(aJ==0&&aI==0){aw=0}}}}}}if(az){aw-=az;if(aw<0){aw+=2*Math.PI}else{if(aw>2*Math.PI){aw-=2*Math.PI}}}au=aO.sliceMargin/180*Math.PI;if(aPaO._innerRadius){for(aU=0;aU0)?aO.gridData[aU-1][1]+au:au;aK=aO.gridData[aU][1];if(aw>aA&&aw0&&-aI>=0){aw=2*Math.PI-Math.atan(-aI/aJ)}else{if(aJ>0&&-aI<0){aw=-Math.atan(-aI/aJ)}else{if(aJ<0){aw=Math.PI-Math.atan(-aI/aJ)}else{if(aJ==0&&-aI>0){aw=3*Math.PI/2}else{if(aJ==0&&-aI<0){aw=Math.PI/2}else{if(aJ==0&&aI==0){aw=0}}}}}}if(az){aw-=az;if(aw<0){aw+=2*Math.PI}else{if(aw>2*Math.PI){aw-=2*Math.PI}}}au=aO.sliceMargin/180*Math.PI;if(aP0)?aO.gridData[aU-1][1]+au:au;aK=aO.gridData[aU][1];if(aw>aA&&aw=ay[0][1]&&aI<=ay[3][1]&&aJ>=at[0]&&aJ<=aE[0]){return{seriesIndex:aO.index,pointIndex:aU,gridData:null,data:aO.data[aU]}}}break;case L.jqplot.LineRenderer:aJ=al.x;aI=al.y;aP=aO.renderer;if(aO.show){if((aO.fill||(aO.renderer.bands.show&&aO.renderer.bands.fill))&&(!am.plugins.highlighter||!am.plugins.highlighter.show)){var ax=false;if(aJ>aO._boundingBox[0][0]&&aJaO._boundingBox[1][1]&&aI=aI||aB[1]=aI){if(aC[0]+(aI-aC[1])/(aB[1]-aC[1])*(aB[0]-aC[0])0)?aN:0;for(var aU=0;aU=aQ[0]-aP._bodyWidth/2&&aJ<=aQ[0]+aP._bodyWidth/2&&aI>=av(aO.data[aU][2])&&aI<=av(aO.data[aU][3])){return{seriesIndex:aW,pointIndex:aU,gridData:aQ,data:aO.data[aU]}}}else{if(!aP.hlc){var av=aO._yaxis.series_u2p;if(aJ>=aQ[0]-aP._tickLength&&aJ<=aQ[0]+aP._tickLength&&aI>=av(aO.data[aU][2])&&aI<=av(aO.data[aU][3])){return{seriesIndex:aW,pointIndex:aU,gridData:aQ,data:aO.data[aU]}}}else{var av=aO._yaxis.series_u2p;if(aJ>=aQ[0]-aP._tickLength&&aJ<=aQ[0]+aP._tickLength&&aI>=av(aO.data[aU][1])&&aI<=av(aO.data[aU][2])){return{seriesIndex:aW,pointIndex:aU,gridData:aQ,data:aO.data[aU]}}}}}else{if(aQ[0]!=null&&aQ[1]!=null){aX=Math.sqrt((aJ-aQ[0])*(aJ-aQ[0])+(aI-aQ[1])*(aI-aQ[1]));if(aX<=an&&(aX<=aS||aS==null)){aS=aX;return{seriesIndex:aW,pointIndex:aU,gridData:aQ,data:aO.data[aU]}}}}}}}break;default:aJ=al.x;aI=al.y;aP=aO.renderer;if(aO.show){aN=aO.markerRenderer.size/2+aO.neighborThreshold;an=(aN>0)?aN:0;for(var aU=0;aU=aQ[0]-aP._bodyWidth/2&&aJ<=aQ[0]+aP._bodyWidth/2&&aI>=av(aO.data[aU][2])&&aI<=av(aO.data[aU][3])){return{seriesIndex:aW,pointIndex:aU,gridData:aQ,data:aO.data[aU]}}}else{if(!aP.hlc){var av=aO._yaxis.series_u2p;if(aJ>=aQ[0]-aP._tickLength&&aJ<=aQ[0]+aP._tickLength&&aI>=av(aO.data[aU][2])&&aI<=av(aO.data[aU][3])){return{seriesIndex:aW,pointIndex:aU,gridData:aQ,data:aO.data[aU]}}}else{var av=aO._yaxis.series_u2p;if(aJ>=aQ[0]-aP._tickLength&&aJ<=aQ[0]+aP._tickLength&&aI>=av(aO.data[aU][1])&&aI<=av(aO.data[aU][2])){return{seriesIndex:aW,pointIndex:aU,gridData:aQ,data:aO.data[aU]}}}}}else{aX=Math.sqrt((aJ-aQ[0])*(aJ-aQ[0])+(aI-aQ[1])*(aI-aQ[1]));if(aX<=an&&(aX<=aS||aS==null)){aS=aX;return{seriesIndex:aW,pointIndex:aU,gridData:aQ,data:aO.data[aU]}}}}}break}}return null}this.onClick=function(an){var am=ai(an);var ap=an.data.plot;var ao=ak(am.gridPos,ap);var al=L.Event("jqplotClick");al.pageX=an.pageX;al.pageY=an.pageY;L(this).trigger(al,[am.gridPos,am.dataPos,ao,ap])};this.onDblClick=function(an){var am=ai(an);var ap=an.data.plot;var ao=ak(am.gridPos,ap);var al=L.Event("jqplotDblClick");al.pageX=an.pageX;al.pageY=an.pageY;L(this).trigger(al,[am.gridPos,am.dataPos,ao,ap])};this.onMouseDown=function(an){var am=ai(an);var ap=an.data.plot;var ao=ak(am.gridPos,ap);var al=L.Event("jqplotMouseDown");al.pageX=an.pageX;al.pageY=an.pageY;L(this).trigger(al,[am.gridPos,am.dataPos,ao,ap])};this.onMouseUp=function(an){var am=ai(an);var al=L.Event("jqplotMouseUp");al.pageX=an.pageX;al.pageY=an.pageY;L(this).trigger(al,[am.gridPos,am.dataPos,null,an.data.plot])};this.onRightClick=function(an){var am=ai(an);var ap=an.data.plot;var ao=ak(am.gridPos,ap);if(ap.captureRightClick){if(an.which==3){var al=L.Event("jqplotRightClick");al.pageX=an.pageX;al.pageY=an.pageY;L(this).trigger(al,[am.gridPos,am.dataPos,ao,ap])}else{var al=L.Event("jqplotMouseUp");al.pageX=an.pageX;al.pageY=an.pageY;L(this).trigger(al,[am.gridPos,am.dataPos,ao,ap])}}};this.onMouseMove=function(an){var am=ai(an);var ap=an.data.plot;var ao=ak(am.gridPos,ap);var al=L.Event("jqplotMouseMove");al.pageX=an.pageX;al.pageY=an.pageY;L(this).trigger(al,[am.gridPos,am.dataPos,ao,ap])};this.onMouseEnter=function(an){var am=ai(an);var ao=an.data.plot;var al=L.Event("jqplotMouseEnter");al.pageX=an.pageX;al.pageY=an.pageY;al.relatedTarget=an.relatedTarget;L(this).trigger(al,[am.gridPos,am.dataPos,null,ao])};this.onMouseLeave=function(an){var am=ai(an);var ao=an.data.plot;var al=L.Event("jqplotMouseLeave");al.pageX=an.pageX;al.pageY=an.pageY;al.relatedTarget=an.relatedTarget;L(this).trigger(al,[am.gridPos,am.dataPos,null,ao])};this.drawSeries=function(an,al){var ap,ao,am;al=(typeof(an)==="number"&&al==null)?an:al;an=(typeof(an)==="object")?an:{};if(al!=u){ao=this.series[al];am=ao.shadowCanvas._ctx;am.clearRect(0,0,am.canvas.width,am.canvas.height);ao.drawShadow(am,an,this);am=ao.canvas._ctx;am.clearRect(0,0,am.canvas.width,am.canvas.height);ao.draw(am,an,this);if(ao.renderer.constructor==L.jqplot.BezierCurveRenderer){if(al660)?ah[aj]*0.85:0.73*ah[aj]+90;ah[aj]=parseInt(ah[aj],10);(ah[aj]>255)?255:ah[aj]}ah[3]=0.3+0.35*al[3];ak.push("rgba("+ah[0]+","+ah[1]+","+ah[2]+","+ah[3]+")")}}else{var al=L.jqplot.getColorComponents(ai);var ah=[al[0],al[1],al[2]];var an=ah[0]+ah[1]+ah[2];for(var aj=0;aj<3;aj++){ah[aj]=(an>660)?ah[aj]*0.85:0.73*ah[aj]+90;ah[aj]=parseInt(ah[aj],10);(ah[aj]>255)?255:ah[aj]}ah[3]=0.3+0.35*al[3];ak="rgba("+ah[0]+","+ah[1]+","+ah[2]+","+ah[3]+")"}return ak};L.jqplot.ColorGenerator=function(ai){ai=ai||L.jqplot.config.defaultColors;var ah=0;this.next=function(){if(ah0){return ai[ah--]}else{ah=ai.length-1;return ai[ah]}};this.get=function(ak){var aj=ak-ai.length*Math.floor(ak/ai.length);return ai[aj]};this.setColors=function(aj){ai=aj};this.reset=function(){ah=0};this.getIndex=function(){return ah};this.setIndex=function(aj){ah=aj}};L.jqplot.hex2rgb=function(aj,ah){aj=aj.replace("#","");if(aj.length==3){aj=aj.charAt(0)+aj.charAt(0)+aj.charAt(1)+aj.charAt(1)+aj.charAt(2)+aj.charAt(2)}var ai;ai="rgba("+parseInt(aj.slice(0,2),16)+", "+parseInt(aj.slice(2,4),16)+", "+parseInt(aj.slice(4,6),16);if(ah){ai+=", "+ah}ai+=")";return ai};L.jqplot.rgb2hex=function(am){var aj=/rgba?\( *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *(?:, *[0-9.]*)?\)/;var ah=am.match(aj);var al="#";for(var ak=1;ak<4;ak++){var ai;if(ah[ak].search(/%/)!=-1){ai=parseInt(255*ah[ak]/100,10).toString(16);if(ai.length==1){ai="0"+ai}}else{ai=parseInt(ah[ak],10).toString(16);if(ai.length==1){ai="0"+ai}}al+=ai}return al};L.jqplot.normalize2rgb=function(ai,ah){if(ai.search(/^ *rgba?\(/)!=-1){return ai}else{if(ai.search(/^ *#?[0-9a-fA-F]?[0-9a-fA-F]/)!=-1){return L.jqplot.hex2rgb(ai,ah)}else{throw new Error("Invalid color spec")}}};L.jqplot.getColorComponents=function(am){am=L.jqplot.colorKeywordMap[am]||am;var ak=L.jqplot.normalize2rgb(am);var aj=/rgba?\( *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *,? *([0-9.]* *)?\)/;var ah=ak.match(aj);var ai=[];for(var al=1;al<4;al++){if(ah[al].search(/%/)!=-1){ai[al-1]=parseInt(255*ah[al]/100,10)}else{ai[al-1]=parseInt(ah[al],10)}}ai[3]=parseFloat(ah[4])?parseFloat(ah[4]):1;return ai};L.jqplot.colorKeywordMap={aliceblue:"rgb(240, 248, 255)",antiquewhite:"rgb(250, 235, 215)",aqua:"rgb( 0, 255, 255)",aquamarine:"rgb(127, 255, 212)",azure:"rgb(240, 255, 255)",beige:"rgb(245, 245, 220)",bisque:"rgb(255, 228, 196)",black:"rgb( 0, 0, 0)",blanchedalmond:"rgb(255, 235, 205)",blue:"rgb( 0, 0, 255)",blueviolet:"rgb(138, 43, 226)",brown:"rgb(165, 42, 42)",burlywood:"rgb(222, 184, 135)",cadetblue:"rgb( 95, 158, 160)",chartreuse:"rgb(127, 255, 0)",chocolate:"rgb(210, 105, 30)",coral:"rgb(255, 127, 80)",cornflowerblue:"rgb(100, 149, 237)",cornsilk:"rgb(255, 248, 220)",crimson:"rgb(220, 20, 60)",cyan:"rgb( 0, 255, 255)",darkblue:"rgb( 0, 0, 139)",darkcyan:"rgb( 0, 139, 139)",darkgoldenrod:"rgb(184, 134, 11)",darkgray:"rgb(169, 169, 169)",darkgreen:"rgb( 0, 100, 0)",darkgrey:"rgb(169, 169, 169)",darkkhaki:"rgb(189, 183, 107)",darkmagenta:"rgb(139, 0, 139)",darkolivegreen:"rgb( 85, 107, 47)",darkorange:"rgb(255, 140, 0)",darkorchid:"rgb(153, 50, 204)",darkred:"rgb(139, 0, 0)",darksalmon:"rgb(233, 150, 122)",darkseagreen:"rgb(143, 188, 143)",darkslateblue:"rgb( 72, 61, 139)",darkslategray:"rgb( 47, 79, 79)",darkslategrey:"rgb( 47, 79, 79)",darkturquoise:"rgb( 0, 206, 209)",darkviolet:"rgb(148, 0, 211)",deeppink:"rgb(255, 20, 147)",deepskyblue:"rgb( 0, 191, 255)",dimgray:"rgb(105, 105, 105)",dimgrey:"rgb(105, 105, 105)",dodgerblue:"rgb( 30, 144, 255)",firebrick:"rgb(178, 34, 34)",floralwhite:"rgb(255, 250, 240)",forestgreen:"rgb( 34, 139, 34)",fuchsia:"rgb(255, 0, 255)",gainsboro:"rgb(220, 220, 220)",ghostwhite:"rgb(248, 248, 255)",gold:"rgb(255, 215, 0)",goldenrod:"rgb(218, 165, 32)",gray:"rgb(128, 128, 128)",grey:"rgb(128, 128, 128)",green:"rgb( 0, 128, 0)",greenyellow:"rgb(173, 255, 47)",honeydew:"rgb(240, 255, 240)",hotpink:"rgb(255, 105, 180)",indianred:"rgb(205, 92, 92)",indigo:"rgb( 75, 0, 130)",ivory:"rgb(255, 255, 240)",khaki:"rgb(240, 230, 140)",lavender:"rgb(230, 230, 250)",lavenderblush:"rgb(255, 240, 245)",lawngreen:"rgb(124, 252, 0)",lemonchiffon:"rgb(255, 250, 205)",lightblue:"rgb(173, 216, 230)",lightcoral:"rgb(240, 128, 128)",lightcyan:"rgb(224, 255, 255)",lightgoldenrodyellow:"rgb(250, 250, 210)",lightgray:"rgb(211, 211, 211)",lightgreen:"rgb(144, 238, 144)",lightgrey:"rgb(211, 211, 211)",lightpink:"rgb(255, 182, 193)",lightsalmon:"rgb(255, 160, 122)",lightseagreen:"rgb( 32, 178, 170)",lightskyblue:"rgb(135, 206, 250)",lightslategray:"rgb(119, 136, 153)",lightslategrey:"rgb(119, 136, 153)",lightsteelblue:"rgb(176, 196, 222)",lightyellow:"rgb(255, 255, 224)",lime:"rgb( 0, 255, 0)",limegreen:"rgb( 50, 205, 50)",linen:"rgb(250, 240, 230)",magenta:"rgb(255, 0, 255)",maroon:"rgb(128, 0, 0)",mediumaquamarine:"rgb(102, 205, 170)",mediumblue:"rgb( 0, 0, 205)",mediumorchid:"rgb(186, 85, 211)",mediumpurple:"rgb(147, 112, 219)",mediumseagreen:"rgb( 60, 179, 113)",mediumslateblue:"rgb(123, 104, 238)",mediumspringgreen:"rgb( 0, 250, 154)",mediumturquoise:"rgb( 72, 209, 204)",mediumvioletred:"rgb(199, 21, 133)",midnightblue:"rgb( 25, 25, 112)",mintcream:"rgb(245, 255, 250)",mistyrose:"rgb(255, 228, 225)",moccasin:"rgb(255, 228, 181)",navajowhite:"rgb(255, 222, 173)",navy:"rgb( 0, 0, 128)",oldlace:"rgb(253, 245, 230)",olive:"rgb(128, 128, 0)",olivedrab:"rgb(107, 142, 35)",orange:"rgb(255, 165, 0)",orangered:"rgb(255, 69, 0)",orchid:"rgb(218, 112, 214)",palegoldenrod:"rgb(238, 232, 170)",palegreen:"rgb(152, 251, 152)",paleturquoise:"rgb(175, 238, 238)",palevioletred:"rgb(219, 112, 147)",papayawhip:"rgb(255, 239, 213)",peachpuff:"rgb(255, 218, 185)",peru:"rgb(205, 133, 63)",pink:"rgb(255, 192, 203)",plum:"rgb(221, 160, 221)",powderblue:"rgb(176, 224, 230)",purple:"rgb(128, 0, 128)",red:"rgb(255, 0, 0)",rosybrown:"rgb(188, 143, 143)",royalblue:"rgb( 65, 105, 225)",saddlebrown:"rgb(139, 69, 19)",salmon:"rgb(250, 128, 114)",sandybrown:"rgb(244, 164, 96)",seagreen:"rgb( 46, 139, 87)",seashell:"rgb(255, 245, 238)",sienna:"rgb(160, 82, 45)",silver:"rgb(192, 192, 192)",skyblue:"rgb(135, 206, 235)",slateblue:"rgb(106, 90, 205)",slategray:"rgb(112, 128, 144)",slategrey:"rgb(112, 128, 144)",snow:"rgb(255, 250, 250)",springgreen:"rgb( 0, 255, 127)",steelblue:"rgb( 70, 130, 180)",tan:"rgb(210, 180, 140)",teal:"rgb( 0, 128, 128)",thistle:"rgb(216, 191, 216)",tomato:"rgb(255, 99, 71)",turquoise:"rgb( 64, 224, 208)",violet:"rgb(238, 130, 238)",wheat:"rgb(245, 222, 179)",white:"rgb(255, 255, 255)",whitesmoke:"rgb(245, 245, 245)",yellow:"rgb(255, 255, 0)",yellowgreen:"rgb(154, 205, 50)"};L.jqplot.AxisLabelRenderer=function(ah){L.jqplot.ElemContainer.call(this);this.axis;this.show=true;this.label="";this.fontFamily=null;this.fontSize=null;this.textColor=null;this._elem;this.escapeHTML=false;L.extend(true,this,ah)};L.jqplot.AxisLabelRenderer.prototype=new L.jqplot.ElemContainer();L.jqplot.AxisLabelRenderer.prototype.constructor=L.jqplot.AxisLabelRenderer;L.jqplot.AxisLabelRenderer.prototype.init=function(ah){L.extend(true,this,ah)};L.jqplot.AxisLabelRenderer.prototype.draw=function(ah,ai){if(this._elem){this._elem.emptyForce();this._elem=null}this._elem=L('
');if(Number(this.label)){this._elem.css("white-space","nowrap")}if(!this.escapeHTML){this._elem.html(this.label)}else{this._elem.text(this.label)}if(this.fontFamily){this._elem.css("font-family",this.fontFamily)}if(this.fontSize){this._elem.css("font-size",this.fontSize)}if(this.textColor){this._elem.css("color",this.textColor)}return this._elem};L.jqplot.AxisLabelRenderer.prototype.pack=function(){};L.jqplot.AxisTickRenderer=function(ah){L.jqplot.ElemContainer.call(this);this.mark="outside";this.axis;this.showMark=true;this.showGridline=true;this.isMinorTick=false;this.size=4;this.markSize=6;this.show=true;this.showLabel=true;this.label=null;this.value=null;this._styles={};this.formatter=L.jqplot.DefaultTickFormatter;this.prefix="";this.suffix="";this.formatString="";this.fontFamily;this.fontSize;this.textColor;this.escapeHTML=false;this._elem;this._breakTick=false;L.extend(true,this,ah)};L.jqplot.AxisTickRenderer.prototype.init=function(ah){L.extend(true,this,ah)};L.jqplot.AxisTickRenderer.prototype=new L.jqplot.ElemContainer();L.jqplot.AxisTickRenderer.prototype.constructor=L.jqplot.AxisTickRenderer;L.jqplot.AxisTickRenderer.prototype.setTick=function(ah,aj,ai){this.value=ah;this.axis=aj;if(ai){this.isMinorTick=true}return this};L.jqplot.AxisTickRenderer.prototype.draw=function(){if(this.label===null){this.label=this.prefix+this.formatter(this.formatString,this.value)+this.suffix}var ai={position:"absolute"};if(Number(this.label)){ai.whitSpace="nowrap"}if(this._elem){this._elem.emptyForce();this._elem=null}this._elem=L(document.createElement("div"));this._elem.addClass("jqplot-"+this.axis+"-tick");if(!this.escapeHTML){this._elem.html(this.label)}else{this._elem.text(this.label)}this._elem.css(ai);for(var ah in this._styles){this._elem.css(ah,this._styles[ah])}if(this.fontFamily){this._elem.css("font-family",this.fontFamily)}if(this.fontSize){this._elem.css("font-size",this.fontSize)}if(this.textColor){this._elem.css("color",this.textColor)}if(this._breakTick){this._elem.addClass("jqplot-breakTick")}return this._elem};L.jqplot.DefaultTickFormatter=function(ah,ai){if(typeof ai=="number"){if(!ah){ah=L.jqplot.config.defaultTickFormatString}return L.jqplot.sprintf(ah,ai)}else{return String(ai)}};L.jqplot.PercentTickFormatter=function(ah,ai){if(typeof ai=="number"){ai=100*ai;if(!ah){ah=L.jqplot.config.defaultTickFormatString}return L.jqplot.sprintf(ah,ai)}else{return String(ai)}};L.jqplot.AxisTickRenderer.prototype.pack=function(){};L.jqplot.CanvasGridRenderer=function(){this.shadowRenderer=new L.jqplot.ShadowRenderer()};L.jqplot.CanvasGridRenderer.prototype.init=function(ai){this._ctx;L.extend(true,this,ai);var ah={lineJoin:"miter",lineCap:"round",fill:false,isarc:false,angle:this.shadowAngle,offset:this.shadowOffset,alpha:this.shadowAlpha,depth:this.shadowDepth,lineWidth:this.shadowWidth,closePath:false,strokeStyle:this.shadowColor};this.renderer.shadowRenderer.init(ah)};L.jqplot.CanvasGridRenderer.prototype.createElement=function(ak){var aj;if(this._elem){if(L.jqplot.use_excanvas&&window.G_vmlCanvasManager.uninitElement!==u){aj=this._elem.get(0);window.G_vmlCanvasManager.uninitElement(aj);aj=null}this._elem.emptyForce();this._elem=null}aj=ak.canvasManager.getCanvas();var ah=this._plotDimensions.width;var ai=this._plotDimensions.height;aj.width=ah;aj.height=ai;this._elem=L(aj);this._elem.addClass("jqplot-grid-canvas");this._elem.css({position:"absolute",left:0,top:0});aj=ak.canvasManager.initCanvas(aj);this._top=this._offsets.top;this._bottom=ai-this._offsets.bottom;this._left=this._offsets.left;this._right=ah-this._offsets.right;this._width=this._right-this._left;this._height=this._bottom-this._top;aj=null;return this._elem};L.jqplot.CanvasGridRenderer.prototype.draw=function(){this._ctx=this._elem.get(0).getContext("2d");var at=this._ctx;var aw=this._axes;at.save();at.clearRect(0,0,this._plotDimensions.width,this._plotDimensions.height);at.fillStyle=this.backgroundColor||this.background;at.fillRect(this._left,this._top,this._width,this._height);at.save();at.lineJoin="miter";at.lineCap="butt";at.lineWidth=this.gridLineWidth;at.strokeStyle=this.gridLineColor;var aA,az,ap,aq;var am=["xaxis","yaxis","x2axis","y2axis"];for(var ay=4;ay>0;ay--){var aD=am[ay-1];var ah=aw[aD];var aB=ah._ticks;var ar=aB.length;if(ah.show){if(ah.drawBaseline){var aC={};if(ah.baselineWidth!==null){aC.lineWidth=ah.baselineWidth}if(ah.baselineColor!==null){aC.strokeStyle=ah.baselineColor}switch(aD){case"xaxis":ao(this._left,this._bottom,this._right,this._bottom,aC);break;case"yaxis":ao(this._left,this._bottom,this._left,this._top,aC);break;case"x2axis":ao(this._left,this._bottom,this._right,this._bottom,aC);break;case"y2axis":ao(this._right,this._bottom,this._right,this._top,aC);break}}for(var au=ar;au>0;au--){var an=aB[au-1];if(an.show){var ak=Math.round(ah.u2p(an.value))+0.5;switch(aD){case"xaxis":if(an.showGridline&&this.drawGridlines&&((!an.isMinorTick&&ah.drawMajorGridlines)||(an.isMinorTick&&ah.drawMinorGridlines))){ao(ak,this._top,ak,this._bottom)}if(an.showMark&&an.mark&&((!an.isMinorTick&&ah.drawMajorTickMarks)||(an.isMinorTick&&ah.drawMinorTickMarks))){ap=an.markSize;aq=an.mark;var ak=Math.round(ah.u2p(an.value))+0.5;switch(aq){case"outside":aA=this._bottom;az=this._bottom+ap;break;case"inside":aA=this._bottom-ap;az=this._bottom;break;case"cross":aA=this._bottom-ap;az=this._bottom+ap;break;default:aA=this._bottom;az=this._bottom+ap;break}if(this.shadow){this.renderer.shadowRenderer.draw(at,[[ak,aA],[ak,az]],{lineCap:"butt",lineWidth:this.gridLineWidth,offset:this.gridLineWidth*0.75,depth:2,fill:false,closePath:false})}ao(ak,aA,ak,az)}break;case"yaxis":if(an.showGridline&&this.drawGridlines&&((!an.isMinorTick&&ah.drawMajorGridlines)||(an.isMinorTick&&ah.drawMinorGridlines))){ao(this._right,ak,this._left,ak)}if(an.showMark&&an.mark&&((!an.isMinorTick&&ah.drawMajorTickMarks)||(an.isMinorTick&&ah.drawMinorTickMarks))){ap=an.markSize;aq=an.mark;var ak=Math.round(ah.u2p(an.value))+0.5;switch(aq){case"outside":aA=this._left-ap;az=this._left;break;case"inside":aA=this._left;az=this._left+ap;break;case"cross":aA=this._left-ap;az=this._left+ap;break;default:aA=this._left-ap;az=this._left;break}if(this.shadow){this.renderer.shadowRenderer.draw(at,[[aA,ak],[az,ak]],{lineCap:"butt",lineWidth:this.gridLineWidth*1.5,offset:this.gridLineWidth*0.75,fill:false,closePath:false})}ao(aA,ak,az,ak,{strokeStyle:ah.borderColor})}break;case"x2axis":if(an.showGridline&&this.drawGridlines&&((!an.isMinorTick&&ah.drawMajorGridlines)||(an.isMinorTick&&ah.drawMinorGridlines))){ao(ak,this._bottom,ak,this._top)}if(an.showMark&&an.mark&&((!an.isMinorTick&&ah.drawMajorTickMarks)||(an.isMinorTick&&ah.drawMinorTickMarks))){ap=an.markSize;aq=an.mark;var ak=Math.round(ah.u2p(an.value))+0.5;switch(aq){case"outside":aA=this._top-ap;az=this._top;break;case"inside":aA=this._top;az=this._top+ap;break;case"cross":aA=this._top-ap;az=this._top+ap;break;default:aA=this._top-ap;az=this._top;break}if(this.shadow){this.renderer.shadowRenderer.draw(at,[[ak,aA],[ak,az]],{lineCap:"butt",lineWidth:this.gridLineWidth,offset:this.gridLineWidth*0.75,depth:2,fill:false,closePath:false})}ao(ak,aA,ak,az)}break;case"y2axis":if(an.showGridline&&this.drawGridlines&&((!an.isMinorTick&&ah.drawMajorGridlines)||(an.isMinorTick&&ah.drawMinorGridlines))){ao(this._left,ak,this._right,ak)}if(an.showMark&&an.mark&&((!an.isMinorTick&&ah.drawMajorTickMarks)||(an.isMinorTick&&ah.drawMinorTickMarks))){ap=an.markSize;aq=an.mark;var ak=Math.round(ah.u2p(an.value))+0.5;switch(aq){case"outside":aA=this._right;az=this._right+ap;break;case"inside":aA=this._right-ap;az=this._right;break;case"cross":aA=this._right-ap;az=this._right+ap;break;default:aA=this._right;az=this._right+ap;break}if(this.shadow){this.renderer.shadowRenderer.draw(at,[[aA,ak],[az,ak]],{lineCap:"butt",lineWidth:this.gridLineWidth*1.5,offset:this.gridLineWidth*0.75,fill:false,closePath:false})}ao(aA,ak,az,ak,{strokeStyle:ah.borderColor})}break;default:break}}}an=null}ah=null;aB=null}am=["y3axis","y4axis","y5axis","y6axis","y7axis","y8axis","y9axis","yMidAxis"];for(var ay=7;ay>0;ay--){var ah=aw[am[ay-1]];var aB=ah._ticks;if(ah.show){var ai=aB[ah.numberTicks-1];var al=aB[0];var aj=ah.getLeft();var av=[[aj,ai.getTop()+ai.getHeight()/2],[aj,al.getTop()+al.getHeight()/2+1]];if(this.shadow){this.renderer.shadowRenderer.draw(at,av,{lineCap:"butt",fill:false,closePath:false})}ao(av[0][0],av[0][1],av[1][0],av[1][1],{lineCap:"butt",strokeStyle:ah.borderColor,lineWidth:ah.borderWidth});for(var au=aB.length;au>0;au--){var an=aB[au-1];ap=an.markSize;aq=an.mark;var ak=Math.round(ah.u2p(an.value))+0.5;if(an.showMark&&an.mark){switch(aq){case"outside":aA=aj;az=aj+ap;break;case"inside":aA=aj-ap;az=aj;break;case"cross":aA=aj-ap;az=aj+ap;break;default:aA=aj;az=aj+ap;break}av=[[aA,ak],[az,ak]];if(this.shadow){this.renderer.shadowRenderer.draw(at,av,{lineCap:"butt",lineWidth:this.gridLineWidth*1.5,offset:this.gridLineWidth*0.75,fill:false,closePath:false})}ao(aA,ak,az,ak,{strokeStyle:ah.borderColor})}an=null}al=null}ah=null;aB=null}at.restore();function ao(aH,aG,aE,ax,aF){at.save();aF=aF||{};if(aF.lineWidth==null||aF.lineWidth!=0){L.extend(true,at,aF);at.beginPath();at.moveTo(aH,aG);at.lineTo(aE,ax);at.stroke();at.restore()}}if(this.shadow){var av=[[this._left,this._bottom],[this._right,this._bottom],[this._right,this._top]];this.renderer.shadowRenderer.draw(at,av)}if(this.borderWidth!=0&&this.drawBorder){ao(this._left,this._top,this._right,this._top,{lineCap:"round",strokeStyle:aw.x2axis.borderColor,lineWidth:aw.x2axis.borderWidth});ao(this._right,this._top,this._right,this._bottom,{lineCap:"round",strokeStyle:aw.y2axis.borderColor,lineWidth:aw.y2axis.borderWidth});ao(this._right,this._bottom,this._left,this._bottom,{lineCap:"round",strokeStyle:aw.xaxis.borderColor,lineWidth:aw.xaxis.borderWidth});ao(this._left,this._bottom,this._left,this._top,{lineCap:"round",strokeStyle:aw.yaxis.borderColor,lineWidth:aw.yaxis.borderWidth})}at.restore();at=null;aw=null};L.jqplot.DivTitleRenderer=function(){};L.jqplot.DivTitleRenderer.prototype.init=function(ah){L.extend(true,this,ah)};L.jqplot.DivTitleRenderer.prototype.draw=function(){if(this._elem){this._elem.emptyForce();this._elem=null}var ak=this.renderer;var aj=document.createElement("div");this._elem=L(aj);this._elem.addClass("jqplot-title");if(!this.text){this.show=false;this._elem.height(0);this._elem.width(0)}else{if(this.text){var ah;if(this.color){ah=this.color}else{if(this.textColor){ah=this.textColor}}var ai={position:"absolute",top:"0px",left:"0px"};if(this._plotWidth){ai.width=this._plotWidth+"px"}if(this.fontSize){ai.fontSize=this.fontSize}if(typeof this.textAlign==="string"){ai.textAlign=this.textAlign}else{ai.textAlign="center"}if(ah){ai.color=ah}if(this.paddingBottom){ai.paddingBottom=this.paddingBottom}if(this.fontFamily){ai.fontFamily=this.fontFamily}this._elem.css(ai);if(this.escapeHtml){this._elem.text(this.text)}else{this._elem.html(this.text)}}}aj=null;return this._elem};L.jqplot.DivTitleRenderer.prototype.pack=function(){};var r=0.1;L.jqplot.LinePattern=function(aw,aq){var ap={dotted:[r,L.jqplot.config.dotGapLength],dashed:[L.jqplot.config.dashLength,L.jqplot.config.gapLength],solid:null};if(typeof aq==="string"){if(aq[0]==="."||aq[0]==="-"){var ax=aq;aq=[];for(var ao=0,al=ax.length;ao0)&&(aC>0)){aA/=aB;az/=aB;while(true){var aD=aC*ar;if(aD=aq.length){ak=0}ar=aq[ak]}else{au=ay;at=aE;if((ak&1)==0){aw.lineTo(au,at)}else{aw.moveTo(au,at)}ar-=aB/aC;break}}}};var ai=function(){aw.beginPath()};var am=function(){aj(an,ah)};return{moveTo:av,lineTo:aj,beginPath:ai,closePath:am}};L.jqplot.LineRenderer=function(){this.shapeRenderer=new L.jqplot.ShapeRenderer();this.shadowRenderer=new L.jqplot.ShadowRenderer()};L.jqplot.LineRenderer.prototype.init=function(ai,an){ai=ai||{};this._type="line";this.renderer.animation={show:false,direction:"left",speed:2500,_supported:true};this.renderer.smooth=false;this.renderer.tension=null;this.renderer.constrainSmoothing=true;this.renderer._smoothedData=[];this.renderer._smoothedPlotData=[];this.renderer._hiBandGridData=[];this.renderer._lowBandGridData=[];this.renderer._hiBandSmoothedData=[];this.renderer._lowBandSmoothedData=[];this.renderer.bandData=[];this.renderer.bands={show:false,hiData:[],lowData:[],color:this.color,showLines:false,fill:true,fillColor:null,_min:null,_max:null,interval:"3%"};var al={highlightMouseOver:ai.highlightMouseOver,highlightMouseDown:ai.highlightMouseDown,highlightColor:ai.highlightColor};delete (ai.highlightMouseOver);delete (ai.highlightMouseDown);delete (ai.highlightColor);L.extend(true,this.renderer,ai);this.renderer.options=ai;if(this.renderer.bandData.length>1&&(!ai.bands||ai.bands.show==null)){this.renderer.bands.show=true}else{if(ai.bands&&ai.bands.show==null&&ai.bands.interval!=null){this.renderer.bands.show=true}}if(this.fill){this.renderer.bands.show=false}if(this.renderer.bands.show){this.renderer.initBands.call(this,this.renderer.options,an)}if(this._stack){this.renderer.smooth=false}var am={lineJoin:this.lineJoin,lineCap:this.lineCap,fill:this.fill,isarc:false,strokeStyle:this.color,fillStyle:this.fillColor,lineWidth:this.lineWidth,linePattern:this.linePattern,closePath:this.fill};this.renderer.shapeRenderer.init(am);var aj=ai.shadowOffset;if(aj==null){if(this.lineWidth>2.5){aj=1.25*(1+(Math.atan((this.lineWidth/2.5))/0.785398163-1)*0.6)}else{aj=1.25*Math.atan((this.lineWidth/2.5))/0.785398163}}var ah={lineJoin:this.lineJoin,lineCap:this.lineCap,fill:this.fill,isarc:false,angle:this.shadowAngle,offset:aj,alpha:this.shadowAlpha,depth:this.shadowDepth,lineWidth:this.lineWidth,linePattern:this.linePattern,closePath:this.fill};this.renderer.shadowRenderer.init(ah);this._areaPoints=[];this._boundingBox=[[],[]];if(!this.isTrendline&&this.fill||this.renderer.bands.show){this.highlightMouseOver=true;this.highlightMouseDown=false;this.highlightColor=null;if(al.highlightMouseDown&&al.highlightMouseOver==null){al.highlightMouseOver=false}L.extend(true,this,{highlightMouseOver:al.highlightMouseOver,highlightMouseDown:al.highlightMouseDown,highlightColor:al.highlightColor});if(!this.highlightColor){var ak=(this.renderer.bands.show)?this.renderer.bands.fillColor:this.fillColor;this.highlightColor=L.jqplot.computeHighlightColors(ak)}if(this.highlighter){this.highlighter.show=false}}if(!this.isTrendline&&an){an.plugins.lineRenderer={};an.postInitHooks.addOnce(z);an.postDrawHooks.addOnce(af);an.eventListenerHooks.addOnce("jqplotMouseMove",h);an.eventListenerHooks.addOnce("jqplotMouseDown",e);an.eventListenerHooks.addOnce("jqplotMouseUp",ad);an.eventListenerHooks.addOnce("jqplotClick",g);an.eventListenerHooks.addOnce("jqplotRightClick",s)}};L.jqplot.LineRenderer.prototype.initBands=function(ak,av){var al=ak.bandData||[];var an=this.renderer.bands;an.hiData=[];an.lowData=[];var aB=this.data;an._max=null;an._min=null;if(al.length==2){if(L.isArray(al[0][0])){var ao;var ah=0,ar=0;for(var aw=0,at=al[0].length;awan._max)||an._max==null){an._max=ao[1]}if((ao[1]!=null&&ao[1]an._max)||an._max==null){an._max=ao[1];ar=1}if((ao[1]!=null&&ao[1]al[1][0])?0:1;var aC=(aj)?0:1;for(var aw=0,at=aB.length;aw2&&!L.isArray(al[0][0])){var aj=(al[0][0]>al[0][1])?0:1;var aC=(aj)?0:1;for(var aw=0,at=al.length;awan._max)||an._max==null){an._max=am[aw][1]}}for(var aw=0,at=ap.length;aw0){aR=Math.abs((ap[aQ][1]-ap[aQ-1][1])/(ap[aQ][0]-ap[aQ-1][0]))}am=aR/aG+aE;aM=aF*A(am)-aF*A(aE)+aS;aT=(aO+aM)/2}else{aT=aU}for(aK=0;aK2){var ao;if(this.renderer.constrainSmoothing){ao=J.call(this,this.gridData);this.renderer._smoothedData=ao[0];this.renderer._smoothedPlotData=ao[1];if(ak.show){ao=J.call(this,this.renderer._hiBandGridData);this.renderer._hiBandSmoothedData=ao[0];ao=J.call(this,this.renderer._lowBandGridData);this.renderer._lowBandSmoothedData=ao[0]}ao=null}else{ao=F.call(this,this.gridData);this.renderer._smoothedData=ao[0];this.renderer._smoothedPlotData=ao[1];if(ak.show){ao=F.call(this,this.renderer._hiBandGridData);this.renderer._hiBandSmoothedData=ao[0];ao=F.call(this,this.renderer._lowBandGridData);this.renderer._lowBandSmoothedData=ao[0]}ao=null}}};L.jqplot.LineRenderer.prototype.makeGridData=function(ao,aq){var am=this._xaxis.series_u2p;var ah=this._yaxis.series_u2p;var ar=[];var aj=[];this.renderer._smoothedData=[];this.renderer._smoothedPlotData=[];this.renderer._hiBandGridData=[];this.renderer._lowBandGridData=[];this.renderer._hiBandSmoothedData=[];this.renderer._lowBandSmoothedData=[];var al=this.renderer.bands;var ai=false;for(var an=0;an2){var ap;if(this.renderer.constrainSmoothing){ap=J.call(this,ar);this.renderer._smoothedData=ap[0];this.renderer._smoothedPlotData=ap[1];if(al.show){ap=J.call(this,this.renderer._hiBandGridData);this.renderer._hiBandSmoothedData=ap[0];ap=J.call(this,this.renderer._lowBandGridData);this.renderer._lowBandSmoothedData=ap[0]}ap=null}else{ap=F.call(this,ar);this.renderer._smoothedData=ap[0];this.renderer._smoothedPlotData=ap[1];if(al.show){ap=F.call(this,this.renderer._hiBandGridData);this.renderer._hiBandSmoothedData=ap[0];ap=F.call(this,this.renderer._lowBandGridData);this.renderer._lowBandSmoothedData=ap[0]}ap=null}}return ar};L.jqplot.LineRenderer.prototype.draw=function(ax,aI,ai,aB){var aC;var aq=L.extend(true,{},ai);var ak=(aq.shadow!=u)?aq.shadow:this.shadow;var aJ=(aq.showLine!=u)?aq.showLine:this.showLine;var aA=(aq.fill!=u)?aq.fill:this.fill;var ah=(aq.fillAndStroke!=u)?aq.fillAndStroke:this.fillAndStroke;var ar,ay,av,aE;ax.save();if(aI.length){if(aJ){if(aA){if(this.fillToZero){var aF=this.negativeColor;if(!this.useNegativeColors){aF=aq.fillStyle}var ao=false;var ap=aq.fillStyle;if(ah){var aH=aI.slice(0)}if(this.index==0||!this._stack){var aw=[];var aL=(this.renderer.smooth)?this.renderer._smoothedPlotData:this._plotData;this._areaPoints=[];var aG=this._yaxis.series_u2p(this.fillToValue);var aj=this._xaxis.series_u2p(this.fillToValue);aq.closePath=true;if(this.fillAxis=="y"){aw.push([aI[0][0],aG]);this._areaPoints.push([aI[0][0],aG]);for(var aC=0;aC0;aC--){aI.push(au[aC-1])}if(ak){this.renderer.shadowRenderer.draw(ax,aI,aq)}this._areaPoints=aI;this.renderer.shapeRenderer.draw(ax,aI,aq)}}else{if(ah){var aH=aI.slice(0)}if(this.index==0||!this._stack){var al=ax.canvas.height;aI.unshift([aI[0][0],al]);var aD=aI.length;aI.push([aI[aD-1][0],al])}else{var au=this._prevGridData;for(var aC=au.length;aC>0;aC--){aI.push(au[aC-1])}}this._areaPoints=aI;if(ak){this.renderer.shadowRenderer.draw(ax,aI,aq)}this.renderer.shapeRenderer.draw(ax,aI,aq)}if(ah){var az=L.extend(true,{},aq,{fill:false,closePath:false});this.renderer.shapeRenderer.draw(ax,aH,az);if(this.markerRenderer.show){if(this.renderer.smooth){aH=this.gridData}for(aC=0;aCat[0]||ar==null){ar=at[0]}if(aEat[1]||ay==null){ay=at[1]}}if(this.type==="line"&&this.renderer.bands.show){aE=this._yaxis.series_u2p(this.renderer.bands._min);ay=this._yaxis.series_u2p(this.renderer.bands._max)}this._boundingBox=[[ar,aE],[av,ay]];if(this.markerRenderer.show&&!aA){if(this.renderer.smooth){aI=this.gridData}for(aC=0;aCao){ao=aj}}}al=null;am=null;if(ah){ai=this._label._elem.outerWidth(true);an=this._label._elem.outerHeight(true)}if(this.name=="xaxis"){ao=ao+an;this._elem.css({height:ao+"px",left:"0px",bottom:"0px"})}else{if(this.name=="x2axis"){ao=ao+an;this._elem.css({height:ao+"px",left:"0px",top:"0px"})}else{if(this.name=="yaxis"){ao=ao+ai;this._elem.css({width:ao+"px",left:"0px",top:"0px"});if(ah&&this._label.constructor==L.jqplot.AxisLabelRenderer){this._label._elem.css("width",ai+"px")}}else{ao=ao+ai;this._elem.css({width:ao+"px",right:"0px",top:"0px"});if(ah&&this._label.constructor==L.jqplot.AxisLabelRenderer){this._label._elem.css("width",ai+"px")}}}}}};L.jqplot.LinearAxisRenderer.prototype.createTicks=function(aj){var aT=this._ticks;var aK=this.ticks;var az=this.name;var aB=this._dataBounds;var ah=(this.name.charAt(0)==="x")?this._plotDimensions.width:this._plotDimensions.height;var an;var a6,aI;var ap,ao;var a4,a0;var aH=this.min;var a5=this.max;var aW=this.numberTicks;var ba=this.tickInterval;var am=30;this._scalefact=(Math.max(ah,am+1)-am)/300;if(aK.length){for(a0=0;a0this.breakPoints[0]&&aO[0]<=this.breakPoints[1]){aU.show=false;aU.showGridline=false;aU.label=aO[1]}else{aU.label=aO[1]}}}else{aU.label=aO[1]}aU.setTick(aO[0],this.name);this._ticks.push(aU)}else{if(L.isPlainObject(aO)){L.extend(true,aU,aO);aU.axis=this.name;this._ticks.push(aU)}else{aU.value=aO;if(this.breakPoints){if(aO==this.breakPoints[0]){aU.label=this.breakTickLabel;aU._breakTick=true;aU.showGridline=false;aU.showMark=false}else{if(aO>this.breakPoints[0]&&aO<=this.breakPoints[1]){aU.show=false;aU.showGridline=false}}}aU.setTick(aO,this.name);this._ticks.push(aU)}}}this.numberTicks=aK.length;this.min=this._ticks[0].value;this.max=this._ticks[this.numberTicks-1].value;this.tickInterval=(this.max-this.min)/(this.numberTicks-1)}else{if(az=="xaxis"||az=="x2axis"){ah=this._plotDimensions.width}else{ah=this._plotDimensions.height}var ax=this.numberTicks;if(this.alignTicks){if(this.name==="x2axis"&&aj.axes.xaxis.show){ax=aj.axes.xaxis.numberTicks}else{if(this.name.charAt(0)==="y"&&this.name!=="yaxis"&&this.name!=="yMidAxis"&&aj.axes.yaxis.show){ax=aj.axes.yaxis.numberTicks}}}a6=((this.min!=null)?this.min:aB.min);aI=((this.max!=null)?this.max:aB.max);var av=aI-a6;var aS,ay;var at;if(this.tickOptions==null||!this.tickOptions.formatString){this._overrideFormatString=true}if(this.min==null||this.max==null&&this.tickInterval==null&&!this.autoscale){if(this.forceTickAt0){if(a6>0){a6=0}if(aI<0){aI=0}}if(this.forceTickAt100){if(a6>100){a6=100}if(aI<100){aI=100}}var aE=false,a1=false;if(this.min!=null){aE=true}else{if(this.max!=null){a1=true}}var aP=L.jqplot.LinearTickGenerator(a6,aI,this._scalefact,ax,aE,a1);var aw=(this.min!=null)?a6:a6+av*(this.padMin-1);var aQ=(this.max!=null)?aI:aI-av*(this.padMax-1);if(a6aQ){aw=(this.min!=null)?a6:a6-av*(this.padMin-1);aQ=(this.max!=null)?aI:aI+av*(this.padMax-1);aP=L.jqplot.LinearTickGenerator(aw,aQ,this._scalefact,ax,aE,a1)}this.min=aP[0];this.max=aP[1];this.numberTicks=aP[2];this._autoFormatString=aP[3];this.tickInterval=aP[4]}else{if(a6==aI){var ai=0.05;if(a6>0){ai=Math.max(Math.log(a6)/Math.LN10,0.05)}a6-=ai;aI+=ai}if(this.autoscale&&this.min==null&&this.max==null){var ak,al,ar;var aC=false;var aN=false;var aA={min:null,max:null,average:null,stddev:null};for(var a0=0;a0a2){a2=aR[aZ]}}}var au=(a2-aG)/a2;if(aV.renderer.constructor==L.jqplot.BarRenderer){if(aG>=0&&(aV.fillToZero||au>0.1)){aC=true}else{aC=false;if(aV.fill&&aV.fillToZero&&aG<0&&a2>0){aN=true}else{aN=false}}}else{if(aV.fill){if(aG>=0&&(aV.fillToZero||au>0.1)){aC=true}else{if(aG<0&&a2>0&&aV.fillToZero){aC=false;aN=true}else{aC=false;aN=false}}}else{if(aG<0){aC=false}}}}}if(aC){this.numberTicks=2+Math.ceil((ah-(this.tickSpacing-1))/this.tickSpacing);this.min=0;aH=0;al=aI/(this.numberTicks-1);at=Math.pow(10,Math.abs(Math.floor(Math.log(al)/Math.LN10)));if(al/at==parseInt(al/at,10)){al+=at}this.tickInterval=Math.ceil(al/at)*at;this.max=this.tickInterval*(this.numberTicks-1)}else{if(aN){this.numberTicks=2+Math.ceil((ah-(this.tickSpacing-1))/this.tickSpacing);var aJ=Math.ceil(Math.abs(a6)/av*(this.numberTicks-1));var a9=this.numberTicks-1-aJ;al=Math.max(Math.abs(a6/aJ),Math.abs(aI/a9));at=Math.pow(10,Math.abs(Math.floor(Math.log(al)/Math.LN10)));this.tickInterval=Math.ceil(al/at)*at;this.max=this.tickInterval*a9;this.min=-this.tickInterval*aJ}else{if(this.numberTicks==null){if(this.tickInterval){this.numberTicks=3+Math.ceil(av/this.tickInterval)}else{this.numberTicks=2+Math.ceil((ah-(this.tickSpacing-1))/this.tickSpacing)}}if(this.tickInterval==null){al=av/(this.numberTicks-1);if(al<1){at=Math.pow(10,Math.abs(Math.floor(Math.log(al)/Math.LN10)))}else{at=1}this.tickInterval=Math.ceil(al*at*this.pad)/at}else{at=1/this.tickInterval}ak=this.tickInterval*(this.numberTicks-1);ar=(ak-av)/2;if(this.min==null){this.min=Math.floor(at*(a6-ar))/at}if(this.max==null){this.max=this.min+ak}}}var aF=L.jqplot.getSignificantFigures(this.tickInterval);var aM;if(aF.digitsLeft>=aF.significantDigits){aM="%d"}else{var at=Math.max(0,5-aF.digitsLeft);at=Math.min(at,aF.digitsRight);aM="%."+at+"f"}this._autoFormatString=aM}else{aS=(this.min!=null)?this.min:a6-av*(this.padMin-1);ay=(this.max!=null)?this.max:aI+av*(this.padMax-1);av=ay-aS;if(this.numberTicks==null){if(this.tickInterval!=null){this.numberTicks=Math.ceil((ay-aS)/this.tickInterval)+1}else{if(ah>100){this.numberTicks=parseInt(3+(ah-100)/75,10)}else{this.numberTicks=2}}}if(this.tickInterval==null){this.tickInterval=av/(this.numberTicks-1)}if(this.max==null){ay=aS+this.tickInterval*(this.numberTicks-1)}if(this.min==null){aS=ay-this.tickInterval*(this.numberTicks-1)}var aF=L.jqplot.getSignificantFigures(this.tickInterval);var aM;if(aF.digitsLeft>=aF.significantDigits){aM="%d"}else{var at=Math.max(0,5-aF.digitsLeft);at=Math.min(at,aF.digitsRight);aM="%."+at+"f"}this._autoFormatString=aM;this.min=aS;this.max=ay}if(this.renderer.constructor==L.jqplot.LinearAxisRenderer&&this._autoFormatString==""){av=this.max-this.min;var a7=new this.tickRenderer(this.tickOptions);var aL=a7.formatString||L.jqplot.config.defaultTickFormatString;var aL=aL.match(L.jqplot.sprintf.regex)[0];var a3=0;if(aL){if(aL.search(/[fFeEgGpP]/)>-1){var aY=aL.match(/\%\.(\d{0,})?[eEfFgGpP]/);if(aY){a3=parseInt(aY[1],10)}else{a3=6}}else{if(aL.search(/[di]/)>-1){a3=0}}var aq=Math.pow(10,-a3);if(this.tickIntervalthis.breakPoints[0]&&aAthis.breakPoints[0]&&aAthis.breakPoints[0]&&aA=this.breakPoints[1]){return(aA-au)*ak/al}else{return(aA+this.breakPoints[1]-this.breakPoints[0]-au)*ak/al}};this.series_p2u=function(aA){return aA*al/ak+au}}}else{this.p2u=function(aA){return(aA-am)*al/ak+at};this.u2p=function(aA){return(aA-at)*ak/al+am};if(this.name=="xaxis"||this.name=="x2axis"){this.series_u2p=function(aA){return(aA-at)*ak/al};this.series_p2u=function(aA){return aA*al/ak+at}}else{this.series_u2p=function(aA){return(aA-au)*ak/al};this.series_p2u=function(aA){return aA*al/ak+au}}}if(this.show){if(this.name=="xaxis"||this.name=="x2axis"){for(var av=0;av0){ah=-ap._textRenderer.height*Math.cos(-ap._textRenderer.angle)/2}else{ah=-ap.getHeight()+ap._textRenderer.height*Math.cos(ap._textRenderer.angle)/2}break;case"middle":ah=-ap.getHeight()/2;break;default:ah=-ap.getHeight()/2;break}}else{ah=-ap.getHeight()/2}var az=this.u2p(ap.value)+ah+"px";ap._elem.css("top",az);ap.pack()}}if(aq){var aw=this._label._elem.outerHeight(true);this._label._elem.css("top",ao-ak/2-aw/2+"px");if(this.name=="yaxis"){this._label._elem.css("left","0px")}else{this._label._elem.css("right","0px")}this._label.pack()}}}ay=null};function i(ai){var ah;ai=Math.abs(ai);if(ai>=10){ah="%d"}else{if(ai>1){if(ai===parseInt(ai,10)){ah="%d"}else{ah="%.1f"}}else{var aj=-Math.floor(Math.log(ai)/Math.LN10);ah="%."+aj+"f"}}return ah}var b=[0.1,0.2,0.3,0.4,0.5,0.8,1,2,3,4,5];var c=function(ai){var ah=b.indexOf(ai);if(ah>0){return b[ah-1]}else{return b[b.length-1]/100}};var k=function(ai){var ah=b.indexOf(ai);if(ah5){ah=10*aj}else{if(am>2){ah=5*aj}else{if(am>1){ah=2*aj}else{ah=aj}}}}else{if(am>5){ah=10*aj}else{if(am>4){ah=5*aj}else{if(am>3){ah=4*aj}else{if(am>2){ah=3*aj}else{if(am>1){ah=2*aj}else{ah=aj}}}}}}return ah}function Q(ai,ah){ah=ah||1;var ak=Math.floor(Math.log(ai)/Math.LN10);var am=Math.pow(10,ak);var al=ai/am;var aj;al=al/ah;if(al<=0.38){aj=0.1}else{if(al<=1.6){aj=0.2}else{if(al<=4){aj=0.5}else{if(al<=8){aj=1}else{if(al<=16){aj=2}else{aj=5}}}}}return aj*am}function x(aj,ai){var al=Math.floor(Math.log(aj)/Math.LN10);var an=Math.pow(10,al);var am=aj/an;var ah;var ak;am=am/ai;if(am<=0.38){ak=0.1}else{if(am<=1.6){ak=0.2}else{if(am<=4){ak=0.5}else{if(am<=8){ak=1}else{if(am<=16){ak=2}else{ak=5}}}}}ah=ak*an;return[ah,ak,an]}L.jqplot.LinearTickGenerator=function(an,aq,aj,ak,ao,ar){ao=(ao===null)?false:ao;ar=(ar===null||ao)?false:ar;if(an===aq){aq=(aq)?0:1}aj=aj||1;if(aqat){at=aB}if(ai>aA){aA=ai}})}an.width=at+Number(av);an.height=aA+Number(ax);var ak=an.getContext("2d");ak.save();ak.fillStyle=al;ak.fillRect(0,0,an.width,an.height);ak.restore();ak.translate(au,ar);ak.textAlign="left";ak.textBaseline="top";function aC(aE){var aF=parseInt(L(aE).css("line-height"),10);if(isNaN(aF)){aF=parseInt(L(aE).css("font-size"),10)*1.2}return aF}function aD(aF,aE,aS,aG,aO,aH){var aQ=aC(aF);var aK=L(aF).innerWidth();var aL=L(aF).innerHeight();var aN=aS.split(/\s+/);var aR=aN.length;var aP="";var aM=[];var aU=aO;var aT=aG;for(var aJ=0;aJaK){aM.push(aJ);aP="";aJ--}}if(aM.length===0){if(L(aF).css("textAlign")==="center"){aT=aG+(aH-aE.measureText(aP).width)/2-au}aE.fillText(aS,aT,aO)}else{aP=aN.slice(0,aM[0]).join(" ");if(L(aF).css("textAlign")==="center"){aT=aG+(aH-aE.measureText(aP).width)/2-au}aE.fillText(aP,aT,aU);aU+=aQ;for(var aJ=1,aI=aM.length;aJ0){ak.strokeRect(aI,aL,L(aG).innerWidth(),L(aG).innerHeight())}L(aG).find("div.jqplot-table-legend-swatch-outline").each(function(){var aU=L(this);ak.strokeStyle=aU.css("border-top-color");var aQ=aI+aU.position().left;var aR=aL+aU.position().top;ak.strokeRect(aQ,aR,aU.innerWidth(),aU.innerHeight());aQ+=parseInt(aU.css("padding-left"),10);aR+=parseInt(aU.css("padding-top"),10);var aT=aU.innerHeight()-2*parseInt(aU.css("padding-top"),10);var aP=aU.innerWidth()-2*parseInt(aU.css("padding-left"),10);var aS=aU.children("div.jqplot-table-legend-swatch");ak.fillStyle=aS.css("background-color");ak.fillRect(aQ,aR,aP,aT)});L(aG).find("td.jqplot-table-legend-label").each(function(){var aR=L(this);var aP=aI+aR.position().left;var aQ=aL+aR.position().top+parseInt(aR.css("padding-top"),10);ak.font=aR.jqplotGetComputedFontStyle();ak.fillStyle=aR.css("color");aD(aR,ak,aR.text(),aP,aQ,aM)});var aH=null}else{if(aN=="canvas"){ak.drawImage(aG,aI,aL)}}}}L(this).children().each(function(){aw(this,av,ax)});return an};L.fn.jqplotToImageStr=function(ai){var ah=L(this).jqplotToImageCanvas(ai);if(ah){return ah.toDataURL("image/png")}else{return null}};L.fn.jqplotToImageElem=function(ah){var ai=document.createElement("img");var aj=L(this).jqplotToImageStr(ah);ai.src=aj;return ai};L.fn.jqplotToImageElemStr=function(ah){var ai="";return ai};L.fn.jqplotSaveImage=function(){var ah=L(this).jqplotToImageStr({});if(ah){window.location.href=ah.replace("image/png","image/octet-stream")}};L.fn.jqplotViewImage=function(){var ai=L(this).jqplotToImageElemStr({});var aj=L(this).jqplotToImageStr({});if(ai){var ah=window.open("");ah.document.open("image/png");ah.document.write(ai);ah.document.close();ah=null}};var ag=function(){this.syntax=ag.config.syntax;this._type="jsDate";this.proxy=new Date();this.options={};this.locale=ag.regional.getLocale();this.formatString="";this.defaultCentury=ag.config.defaultCentury;switch(arguments.length){case 0:break;case 1:if(l(arguments[0])=="[object Object]"&&arguments[0]._type!="jsDate"){var aj=this.options=arguments[0];this.syntax=aj.syntax||this.syntax;this.defaultCentury=aj.defaultCentury||this.defaultCentury;this.proxy=ag.createDate(aj.date)}else{this.proxy=ag.createDate(arguments[0])}break;default:var ah=[];for(var ai=0;ai0?"floor":"ceil"](ak))};ag.prototype.getAbbrDayName=function(){return ag.regional[this.locale]["dayNamesShort"][this.proxy.getDay()]};ag.prototype.getAbbrMonthName=function(){return ag.regional[this.locale]["monthNamesShort"][this.proxy.getMonth()]};ag.prototype.getAMPM=function(){return this.proxy.getHours()>=12?"PM":"AM"};ag.prototype.getAmPm=function(){return this.proxy.getHours()>=12?"pm":"am"};ag.prototype.getCentury=function(){return parseInt(this.proxy.getFullYear()/100,10)};ag.prototype.getDate=function(){return this.proxy.getDate()};ag.prototype.getDay=function(){return this.proxy.getDay()};ag.prototype.getDayOfWeek=function(){var ah=this.proxy.getDay();return ah===0?7:ah};ag.prototype.getDayOfYear=function(){var ai=this.proxy;var ah=ai-new Date(""+ai.getFullYear()+"/1/1 GMT");ah+=ai.getTimezoneOffset()*60000;ai=null;return parseInt(ah/60000/60/24,10)+1};ag.prototype.getDayName=function(){return ag.regional[this.locale]["dayNames"][this.proxy.getDay()]};ag.prototype.getFullWeekOfYear=function(){var ak=this.proxy;var ah=this.getDayOfYear();var aj=6-ak.getDay();var ai=parseInt((ah+aj)/7,10);return ai};ag.prototype.getFullYear=function(){return this.proxy.getFullYear()};ag.prototype.getGmtOffset=function(){var ah=this.proxy.getTimezoneOffset()/60;var ai=ah<0?"+":"-";ah=Math.abs(ah);return ai+N(Math.floor(ah),2)+":"+N((ah%1)*60,2)};ag.prototype.getHours=function(){return this.proxy.getHours()};ag.prototype.getHours12=function(){var ah=this.proxy.getHours();return ah>12?ah-12:(ah==0?12:ah)};ag.prototype.getIsoWeek=function(){var ak=this.proxy;var aj=this.getWeekOfYear();var ah=(new Date(""+ak.getFullYear()+"/1/1")).getDay();var ai=aj+(ah>4||ah<=1?0:1);if(ai==53&&(new Date(""+ak.getFullYear()+"/12/31")).getDay()<4){ai=1}else{if(ai===0){ak=new ag(new Date(""+(ak.getFullYear()-1)+"/12/31"));ai=ak.getIsoWeek()}}ak=null;return ai};ag.prototype.getMilliseconds=function(){return this.proxy.getMilliseconds()};ag.prototype.getMinutes=function(){return this.proxy.getMinutes()};ag.prototype.getMonth=function(){return this.proxy.getMonth()};ag.prototype.getMonthName=function(){return ag.regional[this.locale]["monthNames"][this.proxy.getMonth()]};ag.prototype.getMonthNumber=function(){return this.proxy.getMonth()+1};ag.prototype.getSeconds=function(){return this.proxy.getSeconds()};ag.prototype.getShortYear=function(){return this.proxy.getYear()%100};ag.prototype.getTime=function(){return this.proxy.getTime()};ag.prototype.getTimezoneAbbr=function(){return this.proxy.toString().replace(/^.*\(([^)]+)\)$/,"$1")};ag.prototype.getTimezoneName=function(){var ah=/(?:\((.+)\)$| ([A-Z]{3}) )/.exec(this.toString());return ah[1]||ah[2]||"GMT"+this.getGmtOffset()};ag.prototype.getTimezoneOffset=function(){return this.proxy.getTimezoneOffset()};ag.prototype.getWeekOfYear=function(){var ah=this.getDayOfYear();var aj=7-this.getDayOfWeek();var ai=parseInt((ah+aj)/7,10);return ai};ag.prototype.getUnix=function(){return Math.round(this.proxy.getTime()/1000,0)};ag.prototype.getYear=function(){return this.proxy.getYear()};ag.prototype.next=function(ah){ah=ah||"day";return this.clone().add(1,ah)};ag.prototype.set=function(){switch(arguments.length){case 0:this.proxy=new Date();break;case 1:if(l(arguments[0])=="[object Object]"&&arguments[0]._type!="jsDate"){var aj=this.options=arguments[0];this.syntax=aj.syntax||this.syntax;this.defaultCentury=aj.defaultCentury||this.defaultCentury;this.proxy=ag.createDate(aj.date)}else{this.proxy=ag.createDate(arguments[0])}break;default:var ah=[];for(var ai=0;ai0?"floor":"ceil"](ah/12));var ai=aj.getMonth()+(ah%12);if(ai==12){ai=0;aj.setYear(aj.getFullYear()+1)}else{if(ai==-1){ai=11;aj.setYear(aj.getFullYear()-1)}}aj.setMonth(ai)},diff:function(al,aj){var ah=al.getFullYear()-aj.getFullYear();var ai=al.getMonth()-aj.getMonth()+(ah*12);var ak=al.getDate()-aj.getDate();return ai+(ak/30)}},year:{add:function(ai,ah){ai.setYear(ai.getFullYear()+Math[ah>0?"floor":"ceil"](ah))},diff:function(ai,ah){return E.month.diff(ai,ah)/12}}};for(var Y in E){if(Y.substring(Y.length-1)!="s"){E[Y+"s"]=E[Y]}}var H=function(al,ak,ai){if(ag.formats[ai]["shortcuts"][ak]){return ag.strftime(al,ag.formats[ai]["shortcuts"][ak],ai)}else{var ah=(ag.formats[ai]["codes"][ak]||"").split(".");var aj=al["get"+ah[0]]?al["get"+ah[0]]():"";if(ah[1]){aj=N(aj,ah[1])}return aj}};ag.strftime=function(an,ak,aj,ao){var ai="perl";var am=ag.regional.getLocale();if(aj&&ag.formats.hasOwnProperty(aj)){ai=aj}else{if(aj&&ag.regional.hasOwnProperty(aj)){am=aj}}if(ao&&ag.formats.hasOwnProperty(ao)){ai=ao}else{if(ao&&ag.regional.hasOwnProperty(ao)){am=ao}}if(l(an)!="[object Object]"||an._type!="jsDate"){an=new ag(an);an.locale=am}if(!ak){ak=an.formatString||ag.regional[am]["formatString"]}var ah=ak||"%Y-%m-%d",ap="",al;while(ah.length>0){if(al=ah.match(ag.formats[ai].codes.matcher)){ap+=ah.slice(0,al.index);ap+=(al[1]||"")+H(an,al[2],ai);ah=ah.slice(al.index+al[0].length)}else{ap+=ah;ah=""}}return ap};ag.formats={ISO:"%Y-%m-%dT%H:%M:%S.%N%G",SQL:"%Y-%m-%d %H:%M:%S"};ag.formats.perl={codes:{matcher:/()%(#?(%|[a-z]))/i,Y:"FullYear",y:"ShortYear.2",m:"MonthNumber.2","#m":"MonthNumber",B:"MonthName",b:"AbbrMonthName",d:"Date.2","#d":"Date",e:"Date",A:"DayName",a:"AbbrDayName",w:"Day",H:"Hours.2","#H":"Hours",I:"Hours12.2","#I":"Hours12",p:"AMPM",M:"Minutes.2","#M":"Minutes",S:"Seconds.2","#S":"Seconds",s:"Unix",N:"Milliseconds.3","#N":"Milliseconds",O:"TimezoneOffset",Z:"TimezoneName",G:"GmtOffset"},shortcuts:{F:"%Y-%m-%d",T:"%H:%M:%S",X:"%H:%M:%S",x:"%m/%d/%y",D:"%m/%d/%y","#c":"%a %b %e %H:%M:%S %Y",v:"%e-%b-%Y",R:"%H:%M",r:"%I:%M:%S %p",t:"\t",n:"\n","%":"%"}};ag.formats.php={codes:{matcher:/()%((%|[a-z]))/i,a:"AbbrDayName",A:"DayName",d:"Date.2",e:"Date",j:"DayOfYear.3",u:"DayOfWeek",w:"Day",U:"FullWeekOfYear.2",V:"IsoWeek.2",W:"WeekOfYear.2",b:"AbbrMonthName",B:"MonthName",m:"MonthNumber.2",h:"AbbrMonthName",C:"Century.2",y:"ShortYear.2",Y:"FullYear",H:"Hours.2",I:"Hours12.2",l:"Hours12",p:"AMPM",P:"AmPm",M:"Minutes.2",S:"Seconds.2",s:"Unix",O:"TimezoneOffset",z:"GmtOffset",Z:"TimezoneAbbr"},shortcuts:{D:"%m/%d/%y",F:"%Y-%m-%d",T:"%H:%M:%S",X:"%H:%M:%S",x:"%m/%d/%y",R:"%H:%M",r:"%I:%M:%S %p",t:"\t",n:"\n","%":"%"}};ag.createDate=function(aj){if(aj==null){return new Date()}if(aj instanceof Date){return aj}if(typeof aj=="number"){return new Date(aj)}var ao=String(aj).replace(/^\s*(.+)\s*$/g,"$1");ao=ao.replace(/^([0-9]{1,4})-([0-9]{1,2})-([0-9]{1,4})/,"$1/$2/$3");ao=ao.replace(/^(3[01]|[0-2]?\d)[-\/]([a-z]{3,})[-\/](\d{4})/i,"$1 $2 $3");var an=ao.match(/^(3[01]|[0-2]?\d)[-\/]([a-z]{3,})[-\/](\d{2})\D*/i);if(an&&an.length>3){var at=parseFloat(an[3]);var am=ag.config.defaultCentury+at;am=String(am);ao=ao.replace(/^(3[01]|[0-2]?\d)[-\/]([a-z]{3,})[-\/](\d{2})\D*/i,an[1]+" "+an[2]+" "+am)}an=ao.match(/^([0-9]{1,2})[-\/]([0-9]{1,2})[-\/]([0-9]{1,2})[^0-9]/);function ar(ax,aw){var aC=parseFloat(aw[1]);var aB=parseFloat(aw[2]);var aA=parseFloat(aw[3]);var az=ag.config.defaultCentury;var av,au,aD,ay;if(aC>31){au=aA;aD=aB;av=az+aC}else{au=aB;aD=aC;av=az+aA}ay=aD+"/"+au+"/"+av;return ax.replace(/^([0-9]{1,2})[-\/]([0-9]{1,2})[-\/]([0-9]{1,2})/,ay)}if(an&&an.length>3){ao=ar(ao,an)}var an=ao.match(/^([0-9]{1,2})[-\/]([0-9]{1,2})[-\/]([0-9]{1,2})$/);if(an&&an.length>3){ao=ar(ao,an)}var al=0;var ai=ag.matchers.length;var aq,ah,ap=ao,ak;while(al31){ah=an;ai=am+ao}else{ah=ao;ai=am+an}var ap=ab(aj[2],ag.regional[ag.regional.getLocale()]["monthNamesShort"]);if(ap==-1){ap=ab(aj[2],ag.regional[ag.regional.getLocale()]["monthNames"])}ak.setFullYear(ai,ap,ah);ak.setHours(0,0,0,0);return ak}else{return al}}];function ab(aj,ak){if(ak.indexOf){return ak.indexOf(aj)}for(var ah=0,ai=ak.length;ah=ap)?"":Array(1+ap-au.length>>>0).join(aq);return at?au+ar:ar+au}function ak(ar){var aq=new String(ar);for(var ap=10;ap>0;ap--){if(aq==(aq=aq.replace(/^(\d+)(\d{3})/,"$1"+L.jqplot.sprintf.thousandsSeparator+"$2"))){break}}return aq}function aj(av,au,ax,ar,at,aq){var aw=ar-av.length;if(aw>0){var ap=" ";if(aq){ap=" "}if(ax||!at){av=an(av,ar,ap,ax)}else{av=av.slice(0,au.length)+an("",aw,"0",true)+av.slice(au.length)}}return av}function ao(ay,aq,aw,ar,ap,av,ax,au){var at=ay>>>0;aw=aw&&at&&{"2":"0b","8":"0","16":"0x"}[aq]||"";ay=aw+an(at.toString(aq),av||0,"0",false);return aj(ay,aw,ar,ap,ax,au)}function ah(au,av,ar,ap,at,aq){if(ap!=null){au=au.slice(0,ap)}return aj(au,"",av,ar,at,aq)}var ai=arguments,al=0,am=ai[al++];return am.replace(L.jqplot.sprintf.regex,function(aM,ax,ay,aB,aO,aJ,av){if(aM=="%%"){return"%"}var aD=false,az="",aA=false,aL=false,aw=false,au=false;for(var aI=0;ay&&aI-1?6:(av=="d")?0:void (0)}else{if(aJ=="*"){aJ=+ai[al++]}else{if(aJ.charAt(0)=="*"){aJ=+ai[aJ.slice(1,-1)]}else{aJ=+aJ}}}var aF=ax?ai[ax.slice(0,-1)]:ai[al++];switch(av){case"s":if(aF==null){return""}return ah(String(aF),aD,aB,aJ,aA,aw);case"c":return ah(String.fromCharCode(+aF),aD,aB,aJ,aA,aw);case"b":return ao(aF,2,aL,aD,aB,aJ,aA,aw);case"o":return ao(aF,8,aL,aD,aB,aJ,aA,aw);case"x":return ao(aF,16,aL,aD,aB,aJ,aA,aw);case"X":return ao(aF,16,aL,aD,aB,aJ,aA,aw).toUpperCase();case"u":return ao(aF,10,aL,aD,aB,aJ,aA,aw);case"i":var ar=parseInt(+aF,10);if(isNaN(ar)){return""}var aH=ar<0?"-":az;var aK=au?ak(String(Math.abs(ar))):String(Math.abs(ar));aF=aH+an(aK,aJ,"0",false);return aj(aF,aH,aD,aB,aA,aw);case"d":var ar=Math.round(+aF);if(isNaN(ar)){return""}var aH=ar<0?"-":az;var aK=au?ak(String(Math.abs(ar))):String(Math.abs(ar));aF=aH+an(aK,aJ,"0",false);return aj(aF,aH,aD,aB,aA,aw);case"e":case"E":case"f":case"F":case"g":case"G":var ar=+aF;if(isNaN(ar)){return""}var aH=ar<0?"-":az;var at=["toExponential","toFixed","toPrecision"]["efg".indexOf(av.toLowerCase())];var aN=["toString","toUpperCase"]["eEfFgG".indexOf(av)%2];var aK=Math.abs(ar)[at](aJ);var aE=aK.toString().split(".");aE[0]=au?ak(aE[0]):aE[0];aK=aE.join(L.jqplot.sprintf.decimalMark);aF=aH+aK;var aC=aj(aF,aH,aD,aB,aA,aw)[aN]();return aC;case"p":case"P":var ar=+aF;if(isNaN(ar)){return""}var aH=ar<0?"-":az;var aE=String(Number(Math.abs(ar)).toExponential()).split(/e|E/);var aq=(aE[0].indexOf(".")!=-1)?aE[0].length-1:String(ar).length;var aG=(aE[1]<0)?-aE[1]-1:0;if(Math.abs(ar)<1){if(aq+aG<=aJ){aF=aH+Math.abs(ar).toPrecision(aq)}else{if(aq<=aJ-1){aF=aH+Math.abs(ar).toExponential(aq-1)}else{aF=aH+Math.abs(ar).toExponential(aJ-1)}}}else{var ap=(aq<=aJ)?aq:aJ;aF=aH+Math.abs(ar).toPrecision(ap)}var aN=["toString","toUpperCase"]["pP".indexOf(av)%2];return aj(aF,aH,aD,aB,aA,aw)[aN]();case"n":return"";default:return aM}})};L.jqplot.sprintf.thousandsSeparator=",";L.jqplot.sprintf.decimalMark=".";L.jqplot.sprintf.regex=/%%|%(\d+\$)?([-+#0&\' ]*)(\*\d+\$|\*|\d+)?(\.(\*\d+\$|\*|\d+))?([nAscboxXuidfegpEGP])/g;L.jqplot.getSignificantFigures=function(al){var an=String(Number(Math.abs(al)).toExponential()).split(/e|E/);var am=(an[0].indexOf(".")!=-1)?an[0].length-1:an[0].length;var ai=(an[1]<0)?-an[1]-1:0;var ah=parseInt(an[1],10);var aj=(ah+1>0)?ah+1:0;var ak=(am<=aj)?0:am-ah-1;return{significantDigits:am,digitsLeft:aj,digitsRight:ak,zeros:ai,exponent:ah}};L.jqplot.getPrecision=function(ah){return L.jqplot.getSignificantFigures(ah).digitsRight};var X=L.uiBackCompat!==false;L.jqplot.effects={effect:{}};var m="jqplot.storage.";L.extend(L.jqplot.effects,{version:"1.9pre",save:function(ai,aj){for(var ah=0;ah").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}),ah={width:ai.width(),height:ai.height()},ak=document.activeElement;ai.wrap(al);if(ai[0]===ak||L.contains(ai[0],ak)){L(ak).focus()}al=ai.parent();if(ai.css("position")==="static"){al.css({position:"relative"});ai.css({position:"relative"})}else{L.extend(aj,{position:ai.css("position"),zIndex:ai.css("z-index")});L.each(["top","left","bottom","right"],function(am,an){aj[an]=ai.css(an);if(isNaN(parseInt(aj[an],10))){aj[an]="auto"}});ai.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})}ai.css(ah);return al.css(aj).show()},removeWrapper:function(ah){var ai=document.activeElement;if(ah.parent().is(".ui-effects-wrapper")){ah.parent().replaceWith(ah);if(ah[0]===ai||L.contains(ah[0],ai)){L(ai).focus()}}return ah}});function j(ai,ah,aj,ak){if(L.isPlainObject(ai)){return ai}ai={effect:ai};if(ah===u){ah={}}if(L.isFunction(ah)){ak=ah;aj=null;ah={}}if(L.type(ah)==="number"||L.fx.speeds[ah]){ak=aj;aj=ah;ah={}}if(L.isFunction(aj)){ak=aj;aj=null}if(ah){L.extend(ai,ah)}aj=aj||ah.duration;ai.duration=L.fx.off?0:typeof aj==="number"?aj:aj in L.fx.speeds?L.fx.speeds[aj]:L.fx.speeds._default;ai.complete=ak||ah.complete;return ai}function ae(ah){if(!ah||typeof ah==="number"||L.fx.speeds[ah]){return true}if(typeof ah==="string"&&!L.jqplot.effects.effect[ah]){if(X&&L.jqplot.effects[ah]){return false}return true}return false}L.fn.extend({jqplotEffect:function(ap,aq,ai,ao){var an=j.apply(this,arguments),ak=an.mode,al=an.queue,am=L.jqplot.effects.effect[an.effect],ah=!am&&X&&L.jqplot.effects[an.effect];if(L.fx.off||!(am||ah)){if(ak){return this[ak](an.duration,an.complete)}else{return this.each(function(){if(an.complete){an.complete.call(this)}})}}function aj(au){var av=L(this),at=an.complete,aw=an.mode;function ar(){if(L.isFunction(at)){at.call(av[0])}if(L.isFunction(au)){au()}}if(av.is(":hidden")?aw==="hide":aw==="show"){ar()}else{am.call(av[0],an,ar)}}if(am){return al===false?this.each(aj):this.queue(al||"fx",aj)}else{return ah.call(this,{options:an,duration:an.duration,callback:an.complete,mode:an.mode})}}});var a=/up|down|vertical/,v=/up|left|vertical|horizontal/;L.jqplot.effects.effect.blind=function(aj,ao){var ak=L(this),ar=["position","top","bottom","left","right","height","width"],ap=L.jqplot.effects.setMode(ak,aj.mode||"hide"),au=aj.direction||"up",am=a.test(au),al=am?"height":"width",aq=am?"top":"left",aw=v.test(au),an={},av=ap==="show",ai,ah,at;if(ak.parent().is(".ui-effects-wrapper")){L.jqplot.effects.save(ak.parent(),ar)}else{L.jqplot.effects.save(ak,ar)}ak.show();at=parseInt(ak.css("top"),10);ai=L.jqplot.effects.createWrapper(ak).css({overflow:"hidden"});ah=am?ai[al]()+at:ai[al]();an[al]=av?String(ah):"0";if(!aw){ak.css(am?"bottom":"right",0).css(am?"top":"left","").css({position:"absolute"});an[aq]=av?"0":String(ah)}if(av){ai.css(al,0);if(!aw){ai.css(aq,ah)}}ai.animate(an,{duration:aj.duration,easing:aj.easing,queue:false,complete:function(){if(ap==="hide"){ak.hide()}L.jqplot.effects.restore(ak,ar);L.jqplot.effects.removeWrapper(ak);ao()}})}})(jQuery); \ No newline at end of file +(function (L) { + var u; + L.fn.emptyForce = function () { + for (var ah = 0, ai; (ai = L(this)[ah]) != null; ah++) { + if (ai.nodeType === 1) { + L.cleanData(ai.getElementsByTagName("*")); + } + if (L.jqplot.use_excanvas) { + ai.outerHTML = ""; + } else { + while (ai.firstChild) { + ai.removeChild(ai.firstChild); + } + } + ai = null; + } + return L(this); + }; + L.fn.removeChildForce = function (ah) { + while (ah.firstChild) { + this.removeChildForce(ah.firstChild); + ah.removeChild(ah.firstChild); + } + }; + L.fn.jqplot = function () { + var ah = []; + var aj = []; + for (var ak = 0, ai = arguments.length; ak < ai; ak++) { + if (L.isArray(arguments[ak])) { + ah.push(arguments[ak]); + } else { + if (L.isPlainObject(arguments[ak])) { + aj.push(arguments[ak]); + } + } + } + return this.each(function (an) { + var at, + ar, + aq = L(this), + am = ah.length, + al = aj.length, + ap, + ao; + if (an < am) { + ap = ah[an]; + } else { + ap = am ? ah[am - 1] : null; + } + if (an < al) { + ao = aj[an]; + } else { + ao = al ? aj[al - 1] : null; + } + at = aq.attr("id"); + if (at === u) { + at = "jqplot_target_" + L.jqplot.targetCounter++; + aq.attr("id", at); + } + ar = L.jqplot(at, ap, ao); + aq.data("jqplot", ar); + }); + }; + L.jqplot = function (an, ak, ai) { + var aj = null, + ah = null; + if (arguments.length === 3) { + aj = ak; + ah = ai; + } else { + if (arguments.length === 2) { + if (L.isArray(ak)) { + aj = ak; + } else { + if (L.isPlainObject(ak)) { + ah = ak; + } + } + } + } + if (aj === null && ah !== null && ah.data) { + aj = ah.data; + } + var am = new R(); + L("#" + an).removeClass("jqplot-error"); + if (L.jqplot.config.catchErrors) { + try { + am.init(an, aj, ah); + am.draw(); + am.themeEngine.init.call(am); + return am; + } catch (al) { + var ao = L.jqplot.config.errorMessage || al.message; + L("#" + an).append( + '
' + ao + "
", + ); + L("#" + an).addClass("jqplot-error"); + document.getElementById(an).style.background = + L.jqplot.config.errorBackground; + document.getElementById(an).style.border = + L.jqplot.config.errorBorder; + document.getElementById(an).style.fontFamily = + L.jqplot.config.errorFontFamily; + document.getElementById(an).style.fontSize = + L.jqplot.config.errorFontSize; + document.getElementById(an).style.fontStyle = + L.jqplot.config.errorFontStyle; + document.getElementById(an).style.fontWeight = + L.jqplot.config.errorFontWeight; + } + } else { + am.init(an, aj, ah); + am.draw(); + am.themeEngine.init.call(am); + return am; + } + }; + L.jqplot.version = "1.0.8"; + L.jqplot.revision = "1250"; + L.jqplot.targetCounter = 1; + L.jqplot.CanvasManager = function () { + if (typeof L.jqplot.CanvasManager.canvases == "undefined") { + L.jqplot.CanvasManager.canvases = []; + L.jqplot.CanvasManager.free = []; + } + var ah = []; + this.getCanvas = function () { + var ak; + var aj = true; + if (!L.jqplot.use_excanvas) { + for ( + var al = 0, ai = L.jqplot.CanvasManager.canvases.length; + al < ai; + al++ + ) { + if (L.jqplot.CanvasManager.free[al] === true) { + aj = false; + ak = L.jqplot.CanvasManager.canvases[al]; + L.jqplot.CanvasManager.free[al] = false; + ah.push(al); + break; + } + } + } + if (aj) { + ak = document.createElement("canvas"); + ah.push(L.jqplot.CanvasManager.canvases.length); + L.jqplot.CanvasManager.canvases.push(ak); + L.jqplot.CanvasManager.free.push(false); + } + return ak; + }; + this.initCanvas = function (ai) { + if (L.jqplot.use_excanvas) { + return window.G_vmlCanvasManager.initElement(ai); + } + return ai; + }; + this.freeAllCanvases = function () { + for (var aj = 0, ai = ah.length; aj < ai; aj++) { + this.freeCanvas(ah[aj]); + } + ah = []; + }; + this.freeCanvas = function (ai) { + if ( + L.jqplot.use_excanvas && + window.G_vmlCanvasManager.uninitElement !== u + ) { + window.G_vmlCanvasManager.uninitElement( + L.jqplot.CanvasManager.canvases[ai], + ); + L.jqplot.CanvasManager.canvases[ai] = null; + } else { + var aj = L.jqplot.CanvasManager.canvases[ai]; + aj.getContext("2d").clearRect(0, 0, aj.width, aj.height); + L(aj).unbind().removeAttr("class").removeAttr("style"); + L(aj).css({ left: "", top: "", position: "" }); + aj.width = 0; + aj.height = 0; + L.jqplot.CanvasManager.free[ai] = true; + } + }; + }; + L.jqplot.log = function () { + if (window.console) { + window.console.log.apply(window.console, arguments); + } + }; + L.jqplot.config = { + addDomReference: false, + enablePlugins: false, + defaultHeight: 300, + defaultWidth: 400, + UTCAdjust: false, + timezoneOffset: new Date(new Date().getTimezoneOffset() * 60000), + errorMessage: "", + errorBackground: "", + errorBorder: "", + errorFontFamily: "", + errorFontSize: "", + errorFontStyle: "", + errorFontWeight: "", + catchErrors: false, + defaultTickFormatString: "%.1f", + defaultColors: [ + "#4bb2c5", + "#EAA228", + "#c5b47f", + "#579575", + "#839557", + "#958c12", + "#953579", + "#4b5de4", + "#d8b83f", + "#ff5800", + "#0085cc", + "#c747a3", + "#cddf54", + "#FBD178", + "#26B4E3", + "#bd70c7", + ], + defaultNegativeColors: [ + "#498991", + "#C08840", + "#9F9274", + "#546D61", + "#646C4A", + "#6F6621", + "#6E3F5F", + "#4F64B0", + "#A89050", + "#C45923", + "#187399", + "#945381", + "#959E5C", + "#C7AF7B", + "#478396", + "#907294", + ], + dashLength: 4, + gapLength: 4, + dotGapLength: 2.5, + srcLocation: "jqplot/src/", + pluginLocation: "jqplot/src/plugins/", + }; + L.jqplot.arrayMax = function (ah) { + return Math.max.apply(Math, ah); + }; + L.jqplot.arrayMin = function (ah) { + return Math.min.apply(Math, ah); + }; + L.jqplot.enablePlugins = L.jqplot.config.enablePlugins; + L.jqplot.support_canvas = function () { + if (typeof L.jqplot.support_canvas.result == "undefined") { + L.jqplot.support_canvas.result = + !!document.createElement("canvas").getContext; + } + return L.jqplot.support_canvas.result; + }; + L.jqplot.support_canvas_text = function () { + if (typeof L.jqplot.support_canvas_text.result == "undefined") { + if ( + window.G_vmlCanvasManager !== u && + window.G_vmlCanvasManager._version > 887 + ) { + L.jqplot.support_canvas_text.result = true; + } else { + L.jqplot.support_canvas_text.result = !!( + document.createElement("canvas").getContext && + typeof document.createElement("canvas").getContext("2d") + .fillText == "function" + ); + } + } + return L.jqplot.support_canvas_text.result; + }; + L.jqplot.use_excanvas = + (!L.support.boxModel || + !L.support.objectAll || + !$support.leadingWhitespace) && + !L.jqplot.support_canvas() + ? true + : false; + L.jqplot.preInitHooks = []; + L.jqplot.postInitHooks = []; + L.jqplot.preParseOptionsHooks = []; + L.jqplot.postParseOptionsHooks = []; + L.jqplot.preDrawHooks = []; + L.jqplot.postDrawHooks = []; + L.jqplot.preDrawSeriesHooks = []; + L.jqplot.postDrawSeriesHooks = []; + L.jqplot.preDrawLegendHooks = []; + L.jqplot.addLegendRowHooks = []; + L.jqplot.preSeriesInitHooks = []; + L.jqplot.postSeriesInitHooks = []; + L.jqplot.preParseSeriesOptionsHooks = []; + L.jqplot.postParseSeriesOptionsHooks = []; + L.jqplot.eventListenerHooks = []; + L.jqplot.preDrawSeriesShadowHooks = []; + L.jqplot.postDrawSeriesShadowHooks = []; + L.jqplot.ElemContainer = function () { + this._elem; + this._plotWidth; + this._plotHeight; + this._plotDimensions = { height: null, width: null }; + }; + L.jqplot.ElemContainer.prototype.createElement = function ( + ak, + am, + ai, + aj, + an, + ) { + this._offsets = am; + var ah = ai || "jqplot"; + var al = document.createElement(ak); + this._elem = L(al); + this._elem.addClass(ah); + this._elem.css(aj); + this._elem.attr(an); + al = null; + return this._elem; + }; + L.jqplot.ElemContainer.prototype.getWidth = function () { + if (this._elem) { + return this._elem.outerWidth(true); + } else { + return null; + } + }; + L.jqplot.ElemContainer.prototype.getHeight = function () { + if (this._elem) { + return this._elem.outerHeight(true); + } else { + return null; + } + }; + L.jqplot.ElemContainer.prototype.getPosition = function () { + if (this._elem) { + return this._elem.position(); + } else { + return { top: null, left: null, bottom: null, right: null }; + } + }; + L.jqplot.ElemContainer.prototype.getTop = function () { + return this.getPosition().top; + }; + L.jqplot.ElemContainer.prototype.getLeft = function () { + return this.getPosition().left; + }; + L.jqplot.ElemContainer.prototype.getBottom = function () { + return this._elem.css("bottom"); + }; + L.jqplot.ElemContainer.prototype.getRight = function () { + return this._elem.css("right"); + }; + function w(ah) { + L.jqplot.ElemContainer.call(this); + this.name = ah; + this._series = []; + this.show = false; + this.tickRenderer = L.jqplot.AxisTickRenderer; + this.tickOptions = {}; + this.labelRenderer = L.jqplot.AxisLabelRenderer; + this.labelOptions = {}; + this.label = null; + this.showLabel = true; + this.min = null; + this.max = null; + this.autoscale = false; + this.pad = 1.2; + this.padMax = null; + this.padMin = null; + this.ticks = []; + this.numberTicks; + this.tickInterval; + this.renderer = L.jqplot.LinearAxisRenderer; + this.rendererOptions = {}; + this.showTicks = true; + this.showTickMarks = true; + this.showMinorTicks = true; + this.drawMajorGridlines = true; + this.drawMinorGridlines = false; + this.drawMajorTickMarks = true; + this.drawMinorTickMarks = true; + this.useSeriesColor = false; + this.borderWidth = null; + this.borderColor = null; + this.scaleToHiddenSeries = false; + this._dataBounds = { min: null, max: null }; + this._intervalStats = []; + this._offsets = { min: null, max: null }; + this._ticks = []; + this._label = null; + this.syncTicks = null; + this.tickSpacing = 75; + this._min = null; + this._max = null; + this._tickInterval = null; + this._numberTicks = null; + this.__ticks = null; + this._options = {}; + } + w.prototype = new L.jqplot.ElemContainer(); + w.prototype.constructor = w; + w.prototype.init = function () { + if (L.isFunction(this.renderer)) { + this.renderer = new this.renderer(); + } + this.tickOptions.axis = this.name; + if (this.tickOptions.showMark == null) { + this.tickOptions.showMark = this.showTicks; + } + if (this.tickOptions.showMark == null) { + this.tickOptions.showMark = this.showTickMarks; + } + if (this.tickOptions.showLabel == null) { + this.tickOptions.showLabel = this.showTicks; + } + if (this.label == null || this.label == "") { + this.showLabel = false; + } else { + this.labelOptions.label = this.label; + } + if (this.showLabel == false) { + this.labelOptions.show = false; + } + if (this.pad == 0) { + this.pad = 1; + } + if (this.padMax == 0) { + this.padMax = 1; + } + if (this.padMin == 0) { + this.padMin = 1; + } + if (this.padMax == null) { + this.padMax = (this.pad - 1) / 2 + 1; + } + if (this.padMin == null) { + this.padMin = (this.pad - 1) / 2 + 1; + } + this.pad = this.padMax + this.padMin - 1; + if (this.min != null || this.max != null) { + this.autoscale = false; + } + if (this.syncTicks == null && this.name.indexOf("y") > -1) { + this.syncTicks = true; + } else { + if (this.syncTicks == null) { + this.syncTicks = false; + } + } + this.renderer.init.call(this, this.rendererOptions); + }; + w.prototype.draw = function (ah, ai) { + if (this.__ticks) { + this.__ticks = null; + } + return this.renderer.draw.call(this, ah, ai); + }; + w.prototype.set = function () { + this.renderer.set.call(this); + }; + w.prototype.pack = function (ai, ah) { + if (this.show) { + this.renderer.pack.call(this, ai, ah); + } + if (this._min == null) { + this._min = this.min; + this._max = this.max; + this._tickInterval = this.tickInterval; + this._numberTicks = this.numberTicks; + this.__ticks = this._ticks; + } + }; + w.prototype.reset = function () { + this.renderer.reset.call(this); + }; + w.prototype.resetScale = function (ah) { + L.extend( + true, + this, + { + min: null, + max: null, + numberTicks: null, + tickInterval: null, + _ticks: [], + ticks: [], + }, + ah, + ); + this.resetDataBounds(); + }; + w.prototype.resetDataBounds = function () { + var ao = this._dataBounds; + ao.min = null; + ao.max = null; + var ai, ap, am; + var aj = this.show ? true : false; + for (var al = 0; al < this._series.length; al++) { + ap = this._series[al]; + if (ap.show || this.scaleToHiddenSeries) { + am = ap._plotData; + if ( + ap._type === "line" && + ap.renderer.bands.show && + this.name.charAt(0) !== "x" + ) { + am = [ + [0, ap.renderer.bands._min], + [1, ap.renderer.bands._max], + ]; + } + var ah = 1, + an = 1; + if (ap._type != null && ap._type == "ohlc") { + ah = 3; + an = 2; + } + for (var ak = 0, ai = am.length; ak < ai; ak++) { + if (this.name == "xaxis" || this.name == "x2axis") { + if ( + (am[ak][0] != null && am[ak][0] < ao.min) || + ao.min == null + ) { + ao.min = am[ak][0]; + } + if ( + (am[ak][0] != null && am[ak][0] > ao.max) || + ao.max == null + ) { + ao.max = am[ak][0]; + } + } else { + if ( + (am[ak][ah] != null && am[ak][ah] < ao.min) || + ao.min == null + ) { + ao.min = am[ak][ah]; + } + if ( + (am[ak][an] != null && am[ak][an] > ao.max) || + ao.max == null + ) { + ao.max = am[ak][an]; + } + } + } + if (aj && ap.renderer.constructor !== L.jqplot.BarRenderer) { + aj = false; + } else { + if ( + aj && + this._options.hasOwnProperty("forceTickAt0") && + this._options.forceTickAt0 == false + ) { + aj = false; + } else { + if ( + aj && + ap.renderer.constructor === L.jqplot.BarRenderer + ) { + if ( + ap.barDirection == "vertical" && + this.name != "xaxis" && + this.name != "x2axis" + ) { + if ( + this._options.pad != null || + this._options.padMin != null + ) { + aj = false; + } + } else { + if ( + ap.barDirection == "horizontal" && + (this.name == "xaxis" || + this.name == "x2axis") + ) { + if ( + this._options.pad != null || + this._options.padMin != null + ) { + aj = false; + } + } + } + } + } + } + } + } + if ( + aj && + this.renderer.constructor === L.jqplot.LinearAxisRenderer && + ao.min >= 0 + ) { + this.padMin = 1; + this.forceTickAt0 = true; + } + }; + function q(ah) { + L.jqplot.ElemContainer.call(this); + this.show = false; + this.location = "ne"; + this.labels = []; + this.showLabels = true; + this.showSwatches = true; + this.placement = "insideGrid"; + this.xoffset = 0; + this.yoffset = 0; + this.border; + this.background; + this.textColor; + this.fontFamily; + this.fontSize; + this.rowSpacing = "0.5em"; + this.renderer = L.jqplot.TableLegendRenderer; + this.rendererOptions = {}; + this.preDraw = false; + this.marginTop = null; + this.marginRight = null; + this.marginBottom = null; + this.marginLeft = null; + this.escapeHtml = false; + this._series = []; + L.extend(true, this, ah); + } + q.prototype = new L.jqplot.ElemContainer(); + q.prototype.constructor = q; + q.prototype.setOptions = function (ah) { + L.extend(true, this, ah); + if (this.placement == "inside") { + this.placement = "insideGrid"; + } + if (this.xoffset > 0) { + if (this.placement == "insideGrid") { + switch (this.location) { + case "nw": + case "w": + case "sw": + if (this.marginLeft == null) { + this.marginLeft = this.xoffset + "px"; + } + this.marginRight = "0px"; + break; + case "ne": + case "e": + case "se": + default: + if (this.marginRight == null) { + this.marginRight = this.xoffset + "px"; + } + this.marginLeft = "0px"; + break; + } + } else { + if (this.placement == "outside") { + switch (this.location) { + case "nw": + case "w": + case "sw": + if (this.marginRight == null) { + this.marginRight = this.xoffset + "px"; + } + this.marginLeft = "0px"; + break; + case "ne": + case "e": + case "se": + default: + if (this.marginLeft == null) { + this.marginLeft = this.xoffset + "px"; + } + this.marginRight = "0px"; + break; + } + } + } + this.xoffset = 0; + } + if (this.yoffset > 0) { + if (this.placement == "outside") { + switch (this.location) { + case "sw": + case "s": + case "se": + if (this.marginTop == null) { + this.marginTop = this.yoffset + "px"; + } + this.marginBottom = "0px"; + break; + case "ne": + case "n": + case "nw": + default: + if (this.marginBottom == null) { + this.marginBottom = this.yoffset + "px"; + } + this.marginTop = "0px"; + break; + } + } else { + if (this.placement == "insideGrid") { + switch (this.location) { + case "sw": + case "s": + case "se": + if (this.marginBottom == null) { + this.marginBottom = this.yoffset + "px"; + } + this.marginTop = "0px"; + break; + case "ne": + case "n": + case "nw": + default: + if (this.marginTop == null) { + this.marginTop = this.yoffset + "px"; + } + this.marginBottom = "0px"; + break; + } + } + } + this.yoffset = 0; + } + }; + q.prototype.init = function () { + if (L.isFunction(this.renderer)) { + this.renderer = new this.renderer(); + } + this.renderer.init.call(this, this.rendererOptions); + }; + q.prototype.draw = function (ai, aj) { + for (var ah = 0; ah < L.jqplot.preDrawLegendHooks.length; ah++) { + L.jqplot.preDrawLegendHooks[ah].call(this, ai); + } + return this.renderer.draw.call(this, ai, aj); + }; + q.prototype.pack = function (ah) { + this.renderer.pack.call(this, ah); + }; + function y(ah) { + L.jqplot.ElemContainer.call(this); + this.text = ah; + this.show = true; + this.fontFamily; + this.fontSize; + this.textAlign; + this.textColor; + this.renderer = L.jqplot.DivTitleRenderer; + this.rendererOptions = {}; + this.escapeHtml = false; + } + y.prototype = new L.jqplot.ElemContainer(); + y.prototype.constructor = y; + y.prototype.init = function () { + if (L.isFunction(this.renderer)) { + this.renderer = new this.renderer(); + } + this.renderer.init.call(this, this.rendererOptions); + }; + y.prototype.draw = function (ah) { + return this.renderer.draw.call(this, ah); + }; + y.prototype.pack = function () { + this.renderer.pack.call(this); + }; + function S(ah) { + ah = ah || {}; + L.jqplot.ElemContainer.call(this); + this.show = true; + this.xaxis = "xaxis"; + this._xaxis; + this.yaxis = "yaxis"; + this._yaxis; + this.gridBorderWidth = 2; + this.renderer = L.jqplot.LineRenderer; + this.rendererOptions = {}; + this.data = []; + this.gridData = []; + this.label = ""; + this.showLabel = true; + this.color; + this.negativeColor; + this.lineWidth = 2.5; + this.lineJoin = "round"; + this.lineCap = "round"; + this.linePattern = "solid"; + this.shadow = true; + this.shadowAngle = 45; + this.shadowOffset = 1.25; + this.shadowDepth = 3; + this.shadowAlpha = "0.1"; + this.breakOnNull = false; + this.markerRenderer = L.jqplot.MarkerRenderer; + this.markerOptions = {}; + this.showLine = true; + this.showMarker = true; + this.index; + this.fill = false; + this.fillColor; + this.fillAlpha; + this.fillAndStroke = false; + this.disableStack = false; + this._stack = false; + this.neighborThreshold = 4; + this.fillToZero = false; + this.fillToValue = 0; + this.fillAxis = "y"; + this.useNegativeColors = true; + this._stackData = []; + this._plotData = []; + this._plotValues = { x: [], y: [] }; + this._intervals = { x: {}, y: {} }; + this._prevPlotData = []; + this._prevGridData = []; + this._stackAxis = "y"; + this._primaryAxis = "_xaxis"; + this.canvas = new L.jqplot.GenericCanvas(); + this.shadowCanvas = new L.jqplot.GenericCanvas(); + this.plugins = {}; + this._sumy = 0; + this._sumx = 0; + this._type = ""; + } + S.prototype = new L.jqplot.ElemContainer(); + S.prototype.constructor = S; + S.prototype.init = function (ak, ao, am) { + this.index = ak; + this.gridBorderWidth = ao; + var an = this.data; + var aj = [], + al, + ah; + for (al = 0, ah = an.length; al < ah; al++) { + if (!this.breakOnNull) { + if (an[al] == null || an[al][0] == null || an[al][1] == null) { + continue; + } else { + aj.push(an[al]); + } + } else { + aj.push(an[al]); + } + } + this.data = aj; + if (!this.color) { + this.color = am.colorGenerator.get(this.index); + } + if (!this.negativeColor) { + this.negativeColor = am.negativeColorGenerator.get(this.index); + } + if (!this.fillColor) { + this.fillColor = this.color; + } + if (this.fillAlpha) { + var ai = L.jqplot.normalize2rgb(this.fillColor); + var ai = L.jqplot.getColorComponents(ai); + this.fillColor = + "rgba(" + + ai[0] + + "," + + ai[1] + + "," + + ai[2] + + "," + + this.fillAlpha + + ")"; + } + if (L.isFunction(this.renderer)) { + this.renderer = new this.renderer(); + } + this.renderer.init.call(this, this.rendererOptions, am); + this.markerRenderer = new this.markerRenderer(); + if (!this.markerOptions.color) { + this.markerOptions.color = this.color; + } + if (this.markerOptions.show == null) { + this.markerOptions.show = this.showMarker; + } + this.showMarker = this.markerOptions.show; + this.markerRenderer.init(this.markerOptions); + }; + S.prototype.draw = function (an, ak, am) { + var ai = ak == u ? {} : ak; + an = an == u ? this.canvas._ctx : an; + var ah, al, aj; + for (ah = 0; ah < L.jqplot.preDrawSeriesHooks.length; ah++) { + L.jqplot.preDrawSeriesHooks[ah].call(this, an, ai); + } + if (this.show) { + this.renderer.setGridData.call(this, am); + if (!ai.preventJqPlotSeriesDrawTrigger) { + L(an.canvas).trigger("jqplotSeriesDraw", [ + this.data, + this.gridData, + ]); + } + al = []; + if (ai.data) { + al = ai.data; + } else { + if (!this._stack) { + al = this.data; + } else { + al = this._plotData; + } + } + aj = ai.gridData || this.renderer.makeGridData.call(this, al, am); + if ( + this._type === "line" && + this.renderer.smooth && + this.renderer._smoothedData.length + ) { + aj = this.renderer._smoothedData; + } + this.renderer.draw.call(this, an, aj, ai, am); + } + for (ah = 0; ah < L.jqplot.postDrawSeriesHooks.length; ah++) { + L.jqplot.postDrawSeriesHooks[ah].call(this, an, ai, am); + } + an = ak = am = ah = al = aj = null; + }; + S.prototype.drawShadow = function (an, ak, am) { + var ai = ak == u ? {} : ak; + an = an == u ? this.shadowCanvas._ctx : an; + var ah, al, aj; + for (ah = 0; ah < L.jqplot.preDrawSeriesShadowHooks.length; ah++) { + L.jqplot.preDrawSeriesShadowHooks[ah].call(this, an, ai); + } + if (this.shadow) { + this.renderer.setGridData.call(this, am); + al = []; + if (ai.data) { + al = ai.data; + } else { + if (!this._stack) { + al = this.data; + } else { + al = this._plotData; + } + } + aj = ai.gridData || this.renderer.makeGridData.call(this, al, am); + this.renderer.drawShadow.call(this, an, aj, ai, am); + } + for (ah = 0; ah < L.jqplot.postDrawSeriesShadowHooks.length; ah++) { + L.jqplot.postDrawSeriesShadowHooks[ah].call(this, an, ai); + } + an = ak = am = ah = al = aj = null; + }; + S.prototype.toggleDisplay = function (ai, ak) { + var ah, aj; + if (ai.data.series) { + ah = ai.data.series; + } else { + ah = this; + } + if (ai.data.speed) { + aj = ai.data.speed; + } + if (aj) { + if (ah.canvas._elem.is(":hidden") || !ah.show) { + ah.show = true; + ah.canvas._elem.removeClass("jqplot-series-hidden"); + if (ah.shadowCanvas._elem) { + ah.shadowCanvas._elem.fadeIn(aj); + } + ah.canvas._elem.fadeIn(aj, ak); + ah.canvas._elem + .nextAll(".jqplot-point-label.jqplot-series-" + ah.index) + .fadeIn(aj); + } else { + ah.show = false; + ah.canvas._elem.addClass("jqplot-series-hidden"); + if (ah.shadowCanvas._elem) { + ah.shadowCanvas._elem.fadeOut(aj); + } + ah.canvas._elem.fadeOut(aj, ak); + ah.canvas._elem + .nextAll(".jqplot-point-label.jqplot-series-" + ah.index) + .fadeOut(aj); + } + } else { + if (ah.canvas._elem.is(":hidden") || !ah.show) { + ah.show = true; + ah.canvas._elem.removeClass("jqplot-series-hidden"); + if (ah.shadowCanvas._elem) { + ah.shadowCanvas._elem.show(); + } + ah.canvas._elem.show(0, ak); + ah.canvas._elem + .nextAll(".jqplot-point-label.jqplot-series-" + ah.index) + .show(); + } else { + ah.show = false; + ah.canvas._elem.addClass("jqplot-series-hidden"); + if (ah.shadowCanvas._elem) { + ah.shadowCanvas._elem.hide(); + } + ah.canvas._elem.hide(0, ak); + ah.canvas._elem + .nextAll(".jqplot-point-label.jqplot-series-" + ah.index) + .hide(); + } + } + }; + function M() { + L.jqplot.ElemContainer.call(this); + this.drawGridlines = true; + this.gridLineColor = "#cccccc"; + this.gridLineWidth = 1; + this.background = "#fffdf6"; + this.borderColor = "#999999"; + this.borderWidth = 2; + this.drawBorder = true; + this.shadow = true; + this.shadowAngle = 45; + this.shadowOffset = 1.5; + this.shadowWidth = 3; + this.shadowDepth = 3; + this.shadowColor = null; + this.shadowAlpha = "0.07"; + this._left; + this._top; + this._right; + this._bottom; + this._width; + this._height; + this._axes = []; + this.renderer = L.jqplot.CanvasGridRenderer; + this.rendererOptions = {}; + this._offsets = { top: null, bottom: null, left: null, right: null }; + } + M.prototype = new L.jqplot.ElemContainer(); + M.prototype.constructor = M; + M.prototype.init = function () { + if (L.isFunction(this.renderer)) { + this.renderer = new this.renderer(); + } + this.renderer.init.call(this, this.rendererOptions); + }; + M.prototype.createElement = function (ah, ai) { + this._offsets = ah; + return this.renderer.createElement.call(this, ai); + }; + M.prototype.draw = function () { + this.renderer.draw.call(this); + }; + L.jqplot.GenericCanvas = function () { + L.jqplot.ElemContainer.call(this); + this._ctx; + }; + L.jqplot.GenericCanvas.prototype = new L.jqplot.ElemContainer(); + L.jqplot.GenericCanvas.prototype.constructor = L.jqplot.GenericCanvas; + L.jqplot.GenericCanvas.prototype.createElement = function (al, aj, ai, am) { + this._offsets = al; + var ah = "jqplot"; + if (aj != u) { + ah = aj; + } + var ak; + ak = am.canvasManager.getCanvas(); + if (ai != null) { + this._plotDimensions = ai; + } + ak.width = + this._plotDimensions.width - + this._offsets.left - + this._offsets.right; + ak.height = + this._plotDimensions.height - + this._offsets.top - + this._offsets.bottom; + this._elem = L(ak); + this._elem.css({ + position: "absolute", + left: this._offsets.left, + top: this._offsets.top, + }); + this._elem.addClass(ah); + ak = am.canvasManager.initCanvas(ak); + ak = null; + return this._elem; + }; + L.jqplot.GenericCanvas.prototype.setContext = function () { + this._ctx = this._elem.get(0).getContext("2d"); + return this._ctx; + }; + L.jqplot.GenericCanvas.prototype.resetCanvas = function () { + if (this._elem) { + if ( + L.jqplot.use_excanvas && + window.G_vmlCanvasManager.uninitElement !== u + ) { + window.G_vmlCanvasManager.uninitElement(this._elem.get(0)); + } + this._elem.emptyForce(); + } + this._ctx = null; + }; + L.jqplot.HooksManager = function () { + this.hooks = []; + this.args = []; + }; + L.jqplot.HooksManager.prototype.addOnce = function (ak, ai) { + ai = ai || []; + var al = false; + for (var aj = 0, ah = this.hooks.length; aj < ah; aj++) { + if (this.hooks[aj] == ak) { + al = true; + } + } + if (!al) { + this.hooks.push(ak); + this.args.push(ai); + } + }; + L.jqplot.HooksManager.prototype.add = function (ai, ah) { + ah = ah || []; + this.hooks.push(ai); + this.args.push(ah); + }; + L.jqplot.EventListenerManager = function () { + this.hooks = []; + }; + L.jqplot.EventListenerManager.prototype.addOnce = function (al, ak) { + var am = false, + aj, + ai; + for (var ai = 0, ah = this.hooks.length; ai < ah; ai++) { + aj = this.hooks[ai]; + if (aj[0] == al && aj[1] == ak) { + am = true; + } + } + if (!am) { + this.hooks.push([al, ak]); + } + }; + L.jqplot.EventListenerManager.prototype.add = function (ai, ah) { + this.hooks.push([ai, ah]); + }; + var U = [ + "yMidAxis", + "xaxis", + "yaxis", + "x2axis", + "y2axis", + "y3axis", + "y4axis", + "y5axis", + "y6axis", + "y7axis", + "y8axis", + "y9axis", + ]; + function R() { + this.animate = false; + this.animateReplot = false; + this.axes = { + xaxis: new w("xaxis"), + yaxis: new w("yaxis"), + x2axis: new w("x2axis"), + y2axis: new w("y2axis"), + y3axis: new w("y3axis"), + y4axis: new w("y4axis"), + y5axis: new w("y5axis"), + y6axis: new w("y6axis"), + y7axis: new w("y7axis"), + y8axis: new w("y8axis"), + y9axis: new w("y9axis"), + yMidAxis: new w("yMidAxis"), + }; + this.baseCanvas = new L.jqplot.GenericCanvas(); + this.captureRightClick = false; + this.data = []; + this.dataRenderer; + this.dataRendererOptions; + this.defaults = { + axesDefaults: {}, + axes: { + xaxis: {}, + yaxis: {}, + x2axis: {}, + y2axis: {}, + y3axis: {}, + y4axis: {}, + y5axis: {}, + y6axis: {}, + y7axis: {}, + y8axis: {}, + y9axis: {}, + yMidAxis: {}, + }, + seriesDefaults: {}, + series: [], + }; + this.defaultAxisStart = 1; + this.drawIfHidden = false; + this.eventCanvas = new L.jqplot.GenericCanvas(); + this.fillBetween = { + series1: null, + series2: null, + color: null, + baseSeries: 0, + fill: true, + }; + this.fontFamily; + this.fontSize; + this.grid = new M(); + this.legend = new q(); + this.noDataIndicator = { + show: false, + indicator: "Loading Data...", + axes: { + xaxis: { min: 0, max: 10, tickInterval: 2, show: true }, + yaxis: { min: 0, max: 12, tickInterval: 3, show: true }, + }, + }; + this.negativeSeriesColors = L.jqplot.config.defaultNegativeColors; + this.options = {}; + this.previousSeriesStack = []; + this.plugins = {}; + this.series = []; + this.seriesStack = []; + this.seriesColors = L.jqplot.config.defaultColors; + this.sortData = true; + this.stackSeries = false; + this.syncXTicks = true; + this.syncYTicks = true; + this.target = null; + this.targetId = null; + this.textColor; + this.title = new y(); + this._drawCount = 0; + this._sumy = 0; + this._sumx = 0; + this._stackData = []; + this._plotData = []; + this._width = null; + this._height = null; + this._plotDimensions = { height: null, width: null }; + this._gridPadding = { + top: null, + right: null, + bottom: null, + left: null, + }; + this._defaultGridPadding = { top: 10, right: 10, bottom: 23, left: 10 }; + this._addDomReference = L.jqplot.config.addDomReference; + this.preInitHooks = new L.jqplot.HooksManager(); + this.postInitHooks = new L.jqplot.HooksManager(); + this.preParseOptionsHooks = new L.jqplot.HooksManager(); + this.postParseOptionsHooks = new L.jqplot.HooksManager(); + this.preDrawHooks = new L.jqplot.HooksManager(); + this.postDrawHooks = new L.jqplot.HooksManager(); + this.preDrawSeriesHooks = new L.jqplot.HooksManager(); + this.postDrawSeriesHooks = new L.jqplot.HooksManager(); + this.preDrawLegendHooks = new L.jqplot.HooksManager(); + this.addLegendRowHooks = new L.jqplot.HooksManager(); + this.preSeriesInitHooks = new L.jqplot.HooksManager(); + this.postSeriesInitHooks = new L.jqplot.HooksManager(); + this.preParseSeriesOptionsHooks = new L.jqplot.HooksManager(); + this.postParseSeriesOptionsHooks = new L.jqplot.HooksManager(); + this.eventListenerHooks = new L.jqplot.EventListenerManager(); + this.preDrawSeriesShadowHooks = new L.jqplot.HooksManager(); + this.postDrawSeriesShadowHooks = new L.jqplot.HooksManager(); + this.colorGenerator = new L.jqplot.ColorGenerator(); + this.negativeColorGenerator = new L.jqplot.ColorGenerator(); + this.canvasManager = new L.jqplot.CanvasManager(); + this.themeEngine = new L.jqplot.ThemeEngine(); + var aj = 0; + this.init = function (av, ar, ay) { + ay = ay || {}; + for (var at = 0; at < L.jqplot.preInitHooks.length; at++) { + L.jqplot.preInitHooks[at].call(this, av, ar, ay); + } + for (var at = 0; at < this.preInitHooks.hooks.length; at++) { + this.preInitHooks.hooks[at].call(this, av, ar, ay); + } + this.targetId = "#" + av; + this.target = L("#" + av); + if (this._addDomReference) { + this.target.data("jqplot", this); + } + this.target.removeClass("jqplot-error"); + if (!this.target.get(0)) { + throw new Error("No plot target specified"); + } + if (this.target.css("position") == "static") { + this.target.css("position", "relative"); + } + if (!this.target.hasClass("jqplot-target")) { + this.target.addClass("jqplot-target"); + } + if (!this.target.height()) { + var au; + if (ay && ay.height) { + au = parseInt(ay.height, 10); + } else { + if (this.target.attr("data-height")) { + au = parseInt(this.target.attr("data-height"), 10); + } else { + au = parseInt(L.jqplot.config.defaultHeight, 10); + } + } + this._height = au; + this.target.css("height", au + "px"); + } else { + this._height = au = this.target.height(); + } + if (!this.target.width()) { + var aw; + if (ay && ay.width) { + aw = parseInt(ay.width, 10); + } else { + if (this.target.attr("data-width")) { + aw = parseInt(this.target.attr("data-width"), 10); + } else { + aw = parseInt(L.jqplot.config.defaultWidth, 10); + } + } + this._width = aw; + this.target.css("width", aw + "px"); + } else { + this._width = aw = this.target.width(); + } + for (var at = 0, ap = U.length; at < ap; at++) { + this.axes[U[at]] = new w(U[at]); + } + this._plotDimensions.height = this._height; + this._plotDimensions.width = this._width; + this.grid._plotDimensions = this._plotDimensions; + this.title._plotDimensions = this._plotDimensions; + this.baseCanvas._plotDimensions = this._plotDimensions; + this.eventCanvas._plotDimensions = this._plotDimensions; + this.legend._plotDimensions = this._plotDimensions; + if ( + this._height <= 0 || + this._width <= 0 || + !this._height || + !this._width + ) { + throw new Error("Canvas dimension not set"); + } + if (ay.dataRenderer && L.isFunction(ay.dataRenderer)) { + if (ay.dataRendererOptions) { + this.dataRendererOptions = ay.dataRendererOptions; + } + this.dataRenderer = ay.dataRenderer; + ar = this.dataRenderer(ar, this, this.dataRendererOptions); + } + if (ay.noDataIndicator && L.isPlainObject(ay.noDataIndicator)) { + L.extend(true, this.noDataIndicator, ay.noDataIndicator); + } + if ( + ar == null || + L.isArray(ar) == false || + ar.length == 0 || + L.isArray(ar[0]) == false || + ar[0].length == 0 + ) { + if (this.noDataIndicator.show == false) { + throw new Error("No data specified"); + } else { + for (var al in this.noDataIndicator.axes) { + for (var an in this.noDataIndicator.axes[al]) { + this.axes[al][an] = + this.noDataIndicator.axes[al][an]; + } + } + this.postDrawHooks.add(function () { + var aD = this.eventCanvas.getHeight(); + var aA = this.eventCanvas.getWidth(); + var az = L( + '
', + ); + this.target.append(az); + az.height(aD); + az.width(aA); + az.css("top", this.eventCanvas._offsets.top); + az.css("left", this.eventCanvas._offsets.left); + var aC = L( + '
', + ); + az.append(aC); + aC.html(this.noDataIndicator.indicator); + var aB = aC.height(); + var ax = aC.width(); + aC.height(aB); + aC.width(ax); + aC.css("top", (aD - aB) / 2 + "px"); + }); + } + } + this.data = L.extend(true, [], ar); + this.parseOptions(ay); + if (this.textColor) { + this.target.css("color", this.textColor); + } + if (this.fontFamily) { + this.target.css("font-family", this.fontFamily); + } + if (this.fontSize) { + this.target.css("font-size", this.fontSize); + } + this.title.init(); + this.legend.init(); + this._sumy = 0; + this._sumx = 0; + this.computePlotData(); + for (var at = 0; at < this.series.length; at++) { + this.seriesStack.push(at); + this.previousSeriesStack.push(at); + this.series[at].shadowCanvas._plotDimensions = + this._plotDimensions; + this.series[at].canvas._plotDimensions = this._plotDimensions; + for ( + var aq = 0; + aq < L.jqplot.preSeriesInitHooks.length; + aq++ + ) { + L.jqplot.preSeriesInitHooks[aq].call( + this.series[at], + av, + this.data, + this.options.seriesDefaults, + this.options.series[at], + this, + ); + } + for ( + var aq = 0; + aq < this.preSeriesInitHooks.hooks.length; + aq++ + ) { + this.preSeriesInitHooks.hooks[aq].call( + this.series[at], + av, + this.data, + this.options.seriesDefaults, + this.options.series[at], + this, + ); + } + this.series[at]._plotDimensions = this._plotDimensions; + this.series[at].init(at, this.grid.borderWidth, this); + for ( + var aq = 0; + aq < L.jqplot.postSeriesInitHooks.length; + aq++ + ) { + L.jqplot.postSeriesInitHooks[aq].call( + this.series[at], + av, + this.data, + this.options.seriesDefaults, + this.options.series[at], + this, + ); + } + for ( + var aq = 0; + aq < this.postSeriesInitHooks.hooks.length; + aq++ + ) { + this.postSeriesInitHooks.hooks[aq].call( + this.series[at], + av, + this.data, + this.options.seriesDefaults, + this.options.series[at], + this, + ); + } + this._sumy += this.series[at]._sumy; + this._sumx += this.series[at]._sumx; + } + var am, ao; + for (var at = 0, ap = U.length; at < ap; at++) { + am = U[at]; + ao = this.axes[am]; + ao._plotDimensions = this._plotDimensions; + ao.init(); + if (this.axes[am].borderColor == null) { + if ( + am.charAt(0) !== "x" && + ao.useSeriesColor === true && + ao.show + ) { + ao.borderColor = ao._series[0].color; + } else { + ao.borderColor = this.grid.borderColor; + } + } + } + if (this.sortData) { + ah(this.series); + } + this.grid.init(); + this.grid._axes = this.axes; + this.legend._series = this.series; + for (var at = 0; at < L.jqplot.postInitHooks.length; at++) { + L.jqplot.postInitHooks[at].call(this, av, this.data, ay); + } + for (var at = 0; at < this.postInitHooks.hooks.length; at++) { + this.postInitHooks.hooks[at].call(this, av, this.data, ay); + } + }; + this.resetAxesScale = function (aq, am) { + var ao = am || {}; + var ap = aq || this.axes; + if (ap === true) { + ap = this.axes; + } + if (L.isArray(ap)) { + for (var an = 0; an < ap.length; an++) { + this.axes[ap[an]].resetScale(ao[ap[an]]); + } + } else { + if (typeof ap === "object") { + for (var al in ap) { + this.axes[al].resetScale(ao[al]); + } + } + } + }; + this.reInitialize = function (au, al) { + var ay = L.extend(true, {}, this.options, al); + var aw = this.targetId.substr(1); + var ar = au == null ? this.data : au; + for (var av = 0; av < L.jqplot.preInitHooks.length; av++) { + L.jqplot.preInitHooks[av].call(this, aw, ar, ay); + } + for (var av = 0; av < this.preInitHooks.hooks.length; av++) { + this.preInitHooks.hooks[av].call(this, aw, ar, ay); + } + this._height = this.target.height(); + this._width = this.target.width(); + if ( + this._height <= 0 || + this._width <= 0 || + !this._height || + !this._width + ) { + throw new Error("Target dimension not set"); + } + this._plotDimensions.height = this._height; + this._plotDimensions.width = this._width; + this.grid._plotDimensions = this._plotDimensions; + this.title._plotDimensions = this._plotDimensions; + this.baseCanvas._plotDimensions = this._plotDimensions; + this.eventCanvas._plotDimensions = this._plotDimensions; + this.legend._plotDimensions = this._plotDimensions; + var am, ax, at, ao; + for (var av = 0, aq = U.length; av < aq; av++) { + am = U[av]; + ao = this.axes[am]; + ax = ao._ticks; + for (var at = 0, ap = ax.length; at < ap; at++) { + var an = ax[at]._elem; + if (an) { + if ( + L.jqplot.use_excanvas && + window.G_vmlCanvasManager.uninitElement !== u + ) { + window.G_vmlCanvasManager.uninitElement(an.get(0)); + } + an.emptyForce(); + an = null; + ax._elem = null; + } + } + ax = null; + delete ao.ticks; + delete ao._ticks; + this.axes[am] = new w(am); + this.axes[am]._plotWidth = this._width; + this.axes[am]._plotHeight = this._height; + } + if (au) { + if (ay.dataRenderer && L.isFunction(ay.dataRenderer)) { + if (ay.dataRendererOptions) { + this.dataRendererOptions = ay.dataRendererOptions; + } + this.dataRenderer = ay.dataRenderer; + au = this.dataRenderer(au, this, this.dataRendererOptions); + } + this.data = L.extend(true, [], au); + } + if (al) { + this.parseOptions(ay); + } + this.title._plotWidth = this._width; + if (this.textColor) { + this.target.css("color", this.textColor); + } + if (this.fontFamily) { + this.target.css("font-family", this.fontFamily); + } + if (this.fontSize) { + this.target.css("font-size", this.fontSize); + } + this.title.init(); + this.legend.init(); + this._sumy = 0; + this._sumx = 0; + this.seriesStack = []; + this.previousSeriesStack = []; + this.computePlotData(); + for (var av = 0, aq = this.series.length; av < aq; av++) { + this.seriesStack.push(av); + this.previousSeriesStack.push(av); + this.series[av].shadowCanvas._plotDimensions = + this._plotDimensions; + this.series[av].canvas._plotDimensions = this._plotDimensions; + for ( + var at = 0; + at < L.jqplot.preSeriesInitHooks.length; + at++ + ) { + L.jqplot.preSeriesInitHooks[at].call( + this.series[av], + aw, + this.data, + this.options.seriesDefaults, + this.options.series[av], + this, + ); + } + for ( + var at = 0; + at < this.preSeriesInitHooks.hooks.length; + at++ + ) { + this.preSeriesInitHooks.hooks[at].call( + this.series[av], + aw, + this.data, + this.options.seriesDefaults, + this.options.series[av], + this, + ); + } + this.series[av]._plotDimensions = this._plotDimensions; + this.series[av].init(av, this.grid.borderWidth, this); + for ( + var at = 0; + at < L.jqplot.postSeriesInitHooks.length; + at++ + ) { + L.jqplot.postSeriesInitHooks[at].call( + this.series[av], + aw, + this.data, + this.options.seriesDefaults, + this.options.series[av], + this, + ); + } + for ( + var at = 0; + at < this.postSeriesInitHooks.hooks.length; + at++ + ) { + this.postSeriesInitHooks.hooks[at].call( + this.series[av], + aw, + this.data, + this.options.seriesDefaults, + this.options.series[av], + this, + ); + } + this._sumy += this.series[av]._sumy; + this._sumx += this.series[av]._sumx; + } + for (var av = 0, aq = U.length; av < aq; av++) { + am = U[av]; + ao = this.axes[am]; + ao._plotDimensions = this._plotDimensions; + ao.init(); + if (ao.borderColor == null) { + if ( + am.charAt(0) !== "x" && + ao.useSeriesColor === true && + ao.show + ) { + ao.borderColor = ao._series[0].color; + } else { + ao.borderColor = this.grid.borderColor; + } + } + } + if (this.sortData) { + ah(this.series); + } + this.grid.init(); + this.grid._axes = this.axes; + this.legend._series = this.series; + for ( + var av = 0, aq = L.jqplot.postInitHooks.length; + av < aq; + av++ + ) { + L.jqplot.postInitHooks[av].call(this, aw, this.data, ay); + } + for ( + var av = 0, aq = this.postInitHooks.hooks.length; + av < aq; + av++ + ) { + this.postInitHooks.hooks[av].call(this, aw, this.data, ay); + } + }; + this.quickInit = function () { + this._height = this.target.height(); + this._width = this.target.width(); + if ( + this._height <= 0 || + this._width <= 0 || + !this._height || + !this._width + ) { + throw new Error("Target dimension not set"); + } + this._plotDimensions.height = this._height; + this._plotDimensions.width = this._width; + this.grid._plotDimensions = this._plotDimensions; + this.title._plotDimensions = this._plotDimensions; + this.baseCanvas._plotDimensions = this._plotDimensions; + this.eventCanvas._plotDimensions = this._plotDimensions; + this.legend._plotDimensions = this._plotDimensions; + for (var aq in this.axes) { + this.axes[aq]._plotWidth = this._width; + this.axes[aq]._plotHeight = this._height; + } + this.title._plotWidth = this._width; + if (this.textColor) { + this.target.css("color", this.textColor); + } + if (this.fontFamily) { + this.target.css("font-family", this.fontFamily); + } + if (this.fontSize) { + this.target.css("font-size", this.fontSize); + } + this._sumy = 0; + this._sumx = 0; + this.computePlotData(); + for (var ao = 0; ao < this.series.length; ao++) { + if ( + this.series[ao]._type === "line" && + this.series[ao].renderer.bands.show + ) { + this.series[ao].renderer.initBands.call( + this.series[ao], + this.series[ao].renderer.options, + this, + ); + } + this.series[ao]._plotDimensions = this._plotDimensions; + this.series[ao].canvas._plotDimensions = this._plotDimensions; + this._sumy += this.series[ao]._sumy; + this._sumx += this.series[ao]._sumx; + } + var am; + for (var al = 0; al < 12; al++) { + am = U[al]; + var an = this.axes[am]._ticks; + for (var ao = 0; ao < an.length; ao++) { + var ap = an[ao]._elem; + if (ap) { + if ( + L.jqplot.use_excanvas && + window.G_vmlCanvasManager.uninitElement !== u + ) { + window.G_vmlCanvasManager.uninitElement(ap.get(0)); + } + ap.emptyForce(); + ap = null; + an._elem = null; + } + } + an = null; + this.axes[am]._plotDimensions = this._plotDimensions; + this.axes[am]._ticks = []; + } + if (this.sortData) { + ah(this.series); + } + this.grid._axes = this.axes; + this.legend._series = this.series; + }; + function ah(ap) { + var au, av, aw, al, at; + for (var aq = 0; aq < ap.length; aq++) { + var am; + var ar = [ + ap[aq].data, + ap[aq]._stackData, + ap[aq]._plotData, + ap[aq]._prevPlotData, + ]; + for (var an = 0; an < 4; an++) { + am = true; + au = ar[an]; + if (ap[aq]._stackAxis == "x") { + for (var ao = 0; ao < au.length; ao++) { + if (typeof au[ao][1] != "number") { + am = false; + break; + } + } + if (am) { + au.sort(function (ay, ax) { + return ay[1] - ax[1]; + }); + } + } else { + for (var ao = 0; ao < au.length; ao++) { + if (typeof au[ao][0] != "number") { + am = false; + break; + } + } + if (am) { + au.sort(function (ay, ax) { + return ay[0] - ax[0]; + }); + } + } + } + } + } + this.computePlotData = function () { + this._plotData = []; + this._stackData = []; + var at, au, ao; + for (au = 0, ao = this.series.length; au < ao; au++) { + at = this.series[au]; + this._plotData.push([]); + this._stackData.push([]); + var am = at.data; + this._plotData[au] = L.extend(true, [], am); + this._stackData[au] = L.extend(true, [], am); + at._plotData = this._plotData[au]; + at._stackData = this._stackData[au]; + var ax = { x: [], y: [] }; + if (this.stackSeries && !at.disableStack) { + at._stack = true; + var av = at._stackAxis === "x" ? 0 : 1; + for (var ap = 0, al = am.length; ap < al; ap++) { + var aw = am[ap][av]; + if (aw == null) { + aw = 0; + } + this._plotData[au][ap][av] = aw; + this._stackData[au][ap][av] = aw; + if (au > 0) { + for (var aq = au; aq--; ) { + var an = this._plotData[aq][ap][av]; + if (aw * an >= 0) { + this._plotData[au][ap][av] += an; + this._stackData[au][ap][av] += an; + break; + } + } + } + } + } else { + for (var ar = 0; ar < at.data.length; ar++) { + ax.x.push(at.data[ar][0]); + ax.y.push(at.data[ar][1]); + } + this._stackData.push(at.data); + this.series[au]._stackData = at.data; + this._plotData.push(at.data); + at._plotData = at.data; + at._plotValues = ax; + } + if (au > 0) { + at._prevPlotData = this.series[au - 1]._plotData; + } + at._sumy = 0; + at._sumx = 0; + for (ar = at.data.length - 1; ar > -1; ar--) { + at._sumy += at.data[ar][1]; + at._sumx += at.data[ar][0]; + } + } + }; + this.populatePlotData = function (au, av) { + this._plotData = []; + this._stackData = []; + au._stackData = []; + au._plotData = []; + var ay = { x: [], y: [] }; + if (this.stackSeries && !au.disableStack) { + au._stack = true; + var ax = au._stackAxis === "x" ? 0 : 1; + var az = L.extend(true, [], au.data); + var aA = L.extend(true, [], au.data); + var an, am, ao, aw, al; + for (var ar = 0; ar < av; ar++) { + var ap = this.series[ar].data; + for (var aq = 0; aq < ap.length; aq++) { + ao = ap[aq]; + an = ao[0] != null ? ao[0] : 0; + am = ao[1] != null ? ao[1] : 0; + az[aq][0] += an; + az[aq][1] += am; + aw = ax ? am : an; + if (au.data[aq][ax] * aw >= 0) { + aA[aq][ax] += aw; + } + } + } + for (var at = 0; at < aA.length; at++) { + ay.x.push(aA[at][0]); + ay.y.push(aA[at][1]); + } + this._plotData.push(aA); + this._stackData.push(az); + au._stackData = az; + au._plotData = aA; + au._plotValues = ay; + } else { + for (var at = 0; at < au.data.length; at++) { + ay.x.push(au.data[at][0]); + ay.y.push(au.data[at][1]); + } + this._stackData.push(au.data); + this.series[av]._stackData = au.data; + this._plotData.push(au.data); + au._plotData = au.data; + au._plotValues = ay; + } + if (av > 0) { + au._prevPlotData = this.series[av - 1]._plotData; + } + au._sumy = 0; + au._sumx = 0; + for (at = au.data.length - 1; at > -1; at--) { + au._sumy += au.data[at][1]; + au._sumx += au.data[at][0]; + } + }; + this.getNextSeriesColor = (function (am) { + var al = 0; + var an = am.seriesColors; + return function () { + if (al < an.length) { + return an[al++]; + } else { + al = 0; + return an[al++]; + } + }; + })(this); + this.parseOptions = function (ay) { + for ( + var at = 0; + at < this.preParseOptionsHooks.hooks.length; + at++ + ) { + this.preParseOptionsHooks.hooks[at].call(this, ay); + } + for (var at = 0; at < L.jqplot.preParseOptionsHooks.length; at++) { + L.jqplot.preParseOptionsHooks[at].call(this, ay); + } + this.options = L.extend(true, {}, this.defaults, ay); + var am = this.options; + this.animate = am.animate; + this.animateReplot = am.animateReplot; + this.stackSeries = am.stackSeries; + if (L.isPlainObject(am.fillBetween)) { + var ax = ["series1", "series2", "color", "baseSeries", "fill"], + au; + for (var at = 0, aq = ax.length; at < aq; at++) { + au = ax[at]; + if (am.fillBetween[au] != null) { + this.fillBetween[au] = am.fillBetween[au]; + } + } + } + if (am.seriesColors) { + this.seriesColors = am.seriesColors; + } + if (am.negativeSeriesColors) { + this.negativeSeriesColors = am.negativeSeriesColors; + } + if (am.captureRightClick) { + this.captureRightClick = am.captureRightClick; + } + this.defaultAxisStart = + ay && ay.defaultAxisStart != null + ? ay.defaultAxisStart + : this.defaultAxisStart; + this.colorGenerator.setColors(this.seriesColors); + this.negativeColorGenerator.setColors(this.negativeSeriesColors); + L.extend(true, this._gridPadding, am.gridPadding); + this.sortData = am.sortData != null ? am.sortData : this.sortData; + for (var at = 0; at < 12; at++) { + var an = U[at]; + var ap = this.axes[an]; + ap._options = L.extend(true, {}, am.axesDefaults, am.axes[an]); + L.extend(true, ap, am.axesDefaults, am.axes[an]); + ap._plotWidth = this._width; + ap._plotHeight = this._height; + } + var aw = function (aD, aB, aE) { + var aA = []; + var aC, az; + aB = aB || "vertical"; + if (!L.isArray(aD[0])) { + for (aC = 0, az = aD.length; aC < az; aC++) { + if (aB == "vertical") { + aA.push([aE + aC, aD[aC]]); + } else { + aA.push([aD[aC], aE + aC]); + } + } + } else { + L.extend(true, aA, aD); + } + return aA; + }; + var av = 0; + this.series = []; + for (var at = 0; at < this.data.length; at++) { + var al = L.extend( + true, + { index: at }, + { + seriesColors: this.seriesColors, + negativeSeriesColors: this.negativeSeriesColors, + }, + this.options.seriesDefaults, + this.options.series[at], + { rendererOptions: { animation: { show: this.animate } } }, + ); + var ax = new S(al); + for ( + var ar = 0; + ar < L.jqplot.preParseSeriesOptionsHooks.length; + ar++ + ) { + L.jqplot.preParseSeriesOptionsHooks[ar].call( + ax, + this.options.seriesDefaults, + this.options.series[at], + ); + } + for ( + var ar = 0; + ar < this.preParseSeriesOptionsHooks.hooks.length; + ar++ + ) { + this.preParseSeriesOptionsHooks.hooks[ar].call( + ax, + this.options.seriesDefaults, + this.options.series[at], + ); + } + L.extend(true, ax, al); + var ao = "vertical"; + if ( + ax.renderer === L.jqplot.BarRenderer && + ax.rendererOptions && + ax.rendererOptions.barDirection == "horizontal" + ) { + ao = "horizontal"; + ax._stackAxis = "x"; + ax._primaryAxis = "_yaxis"; + } + ax.data = aw(this.data[at], ao, this.defaultAxisStart); + switch (ax.xaxis) { + case "xaxis": + ax._xaxis = this.axes.xaxis; + break; + case "x2axis": + ax._xaxis = this.axes.x2axis; + break; + default: + break; + } + ax._yaxis = this.axes[ax.yaxis]; + ax._xaxis._series.push(ax); + ax._yaxis._series.push(ax); + if (ax.show) { + ax._xaxis.show = true; + ax._yaxis.show = true; + } else { + if (ax._xaxis.scaleToHiddenSeries) { + ax._xaxis.show = true; + } + if (ax._yaxis.scaleToHiddenSeries) { + ax._yaxis.show = true; + } + } + if (!ax.label) { + ax.label = "Series " + (at + 1).toString(); + } + this.series.push(ax); + for ( + var ar = 0; + ar < L.jqplot.postParseSeriesOptionsHooks.length; + ar++ + ) { + L.jqplot.postParseSeriesOptionsHooks[ar].call( + this.series[at], + this.options.seriesDefaults, + this.options.series[at], + ); + } + for ( + var ar = 0; + ar < this.postParseSeriesOptionsHooks.hooks.length; + ar++ + ) { + this.postParseSeriesOptionsHooks.hooks[ar].call( + this.series[at], + this.options.seriesDefaults, + this.options.series[at], + ); + } + } + L.extend(true, this.grid, this.options.grid); + for (var at = 0, aq = U.length; at < aq; at++) { + var an = U[at]; + var ap = this.axes[an]; + if (ap.borderWidth == null) { + ap.borderWidth = this.grid.borderWidth; + } + } + if (typeof this.options.title == "string") { + this.title.text = this.options.title; + } else { + if (typeof this.options.title == "object") { + L.extend(true, this.title, this.options.title); + } + } + this.title._plotWidth = this._width; + this.legend.setOptions(this.options.legend); + for (var at = 0; at < L.jqplot.postParseOptionsHooks.length; at++) { + L.jqplot.postParseOptionsHooks[at].call(this, ay); + } + for ( + var at = 0; + at < this.postParseOptionsHooks.hooks.length; + at++ + ) { + this.postParseOptionsHooks.hooks[at].call(this, ay); + } + }; + this.destroy = function () { + this.canvasManager.freeAllCanvases(); + if (this.eventCanvas && this.eventCanvas._elem) { + this.eventCanvas._elem.unbind(); + } + this.target.empty(); + this.target[0].innerHTML = ""; + }; + this.replot = function (am) { + var an = am || {}; + var ap = an.data || null; + var al = an.clear === false ? false : true; + var ao = an.resetAxes || false; + delete an.data; + delete an.clear; + delete an.resetAxes; + this.target.trigger("jqplotPreReplot"); + if (al) { + this.destroy(); + } + if (ap || !L.isEmptyObject(an)) { + this.reInitialize(ap, an); + } else { + this.quickInit(); + } + if (ao) { + this.resetAxesScale(ao, an.axes); + } + this.draw(); + this.target.trigger("jqplotPostReplot"); + }; + this.redraw = function (al) { + al = al != null ? al : true; + this.target.trigger("jqplotPreRedraw"); + if (al) { + this.canvasManager.freeAllCanvases(); + this.eventCanvas._elem.unbind(); + this.target.empty(); + } + for (var an in this.axes) { + this.axes[an]._ticks = []; + } + this.computePlotData(); + this._sumy = 0; + this._sumx = 0; + for (var am = 0, ao = this.series.length; am < ao; am++) { + this._sumy += this.series[am]._sumy; + this._sumx += this.series[am]._sumx; + } + this.draw(); + this.target.trigger("jqplotPostRedraw"); + }; + this.draw = function () { + if (this.drawIfHidden || this.target.is(":visible")) { + this.target.trigger("jqplotPreDraw"); + var aH, aF, aE, ao; + for (aH = 0, aE = L.jqplot.preDrawHooks.length; aH < aE; aH++) { + L.jqplot.preDrawHooks[aH].call(this); + } + for ( + aH = 0, aE = this.preDrawHooks.hooks.length; + aH < aE; + aH++ + ) { + this.preDrawHooks.hooks[aH].apply( + this, + this.preDrawSeriesHooks.args[aH], + ); + } + this.target.append( + this.baseCanvas.createElement( + { left: 0, right: 0, top: 0, bottom: 0 }, + "jqplot-base-canvas", + null, + this, + ), + ); + this.baseCanvas.setContext(); + this.target.append(this.title.draw()); + this.title.pack({ top: 0, left: 0 }); + var aL = this.legend.draw({}, this); + var al = { top: 0, left: 0, bottom: 0, right: 0 }; + if (this.legend.placement == "outsideGrid") { + this.target.append(aL); + switch (this.legend.location) { + case "n": + al.top += this.legend.getHeight(); + break; + case "s": + al.bottom += this.legend.getHeight(); + break; + case "ne": + case "e": + case "se": + al.right += this.legend.getWidth(); + break; + case "nw": + case "w": + case "sw": + al.left += this.legend.getWidth(); + break; + default: + al.right += this.legend.getWidth(); + break; + } + aL = aL.detach(); + } + var ar = this.axes; + var aM; + for (aH = 0; aH < 12; aH++) { + aM = U[aH]; + this.target.append(ar[aM].draw(this.baseCanvas._ctx, this)); + ar[aM].set(); + } + if (ar.yaxis.show) { + al.left += ar.yaxis.getWidth(); + } + var aG = [ + "y2axis", + "y3axis", + "y4axis", + "y5axis", + "y6axis", + "y7axis", + "y8axis", + "y9axis", + ]; + var az = [0, 0, 0, 0, 0, 0, 0, 0]; + var aC = 0; + var aB; + for (aB = 0; aB < 8; aB++) { + if (ar[aG[aB]].show) { + aC += ar[aG[aB]].getWidth(); + az[aB] = aC; + } + } + al.right += aC; + if (ar.x2axis.show) { + al.top += ar.x2axis.getHeight(); + } + if (this.title.show) { + al.top += this.title.getHeight(); + } + if (ar.xaxis.show) { + al.bottom += ar.xaxis.getHeight(); + } + if ( + this.options.gridDimensions && + L.isPlainObject(this.options.gridDimensions) + ) { + var at = + parseInt(this.options.gridDimensions.width, 10) || 0; + var aI = + parseInt(this.options.gridDimensions.height, 10) || 0; + var an = (this._width - al.left - al.right - at) / 2; + var aK = (this._height - al.top - al.bottom - aI) / 2; + if (aK >= 0 && an >= 0) { + al.top += aK; + al.bottom += aK; + al.left += an; + al.right += an; + } + } + var am = ["top", "bottom", "left", "right"]; + for (var aB in am) { + if (this._gridPadding[am[aB]] == null && al[am[aB]] > 0) { + this._gridPadding[am[aB]] = al[am[aB]]; + } else { + if (this._gridPadding[am[aB]] == null) { + this._gridPadding[am[aB]] = + this._defaultGridPadding[am[aB]]; + } + } + } + var aA = this._gridPadding; + if (this.legend.placement === "outsideGrid") { + aA = { + top: this.title.getHeight(), + left: 0, + right: 0, + bottom: 0, + }; + if (this.legend.location === "s") { + aA.left = this._gridPadding.left; + aA.right = this._gridPadding.right; + } + } + ar.xaxis.pack( + { + position: "absolute", + bottom: this._gridPadding.bottom - ar.xaxis.getHeight(), + left: 0, + width: this._width, + }, + { + min: this._gridPadding.left, + max: this._width - this._gridPadding.right, + }, + ); + ar.yaxis.pack( + { + position: "absolute", + top: 0, + left: this._gridPadding.left - ar.yaxis.getWidth(), + height: this._height, + }, + { + min: this._height - this._gridPadding.bottom, + max: this._gridPadding.top, + }, + ); + ar.x2axis.pack( + { + position: "absolute", + top: this._gridPadding.top - ar.x2axis.getHeight(), + left: 0, + width: this._width, + }, + { + min: this._gridPadding.left, + max: this._width - this._gridPadding.right, + }, + ); + for (aH = 8; aH > 0; aH--) { + ar[aG[aH - 1]].pack( + { + position: "absolute", + top: 0, + right: this._gridPadding.right - az[aH - 1], + }, + { + min: this._height - this._gridPadding.bottom, + max: this._gridPadding.top, + }, + ); + } + var au = + (this._width - + this._gridPadding.left - + this._gridPadding.right) / + 2 + + this._gridPadding.left - + ar.yMidAxis.getWidth() / 2; + ar.yMidAxis.pack( + { + position: "absolute", + top: 0, + left: au, + zIndex: 9, + textAlign: "center", + }, + { + min: this._height - this._gridPadding.bottom, + max: this._gridPadding.top, + }, + ); + this.target.append( + this.grid.createElement(this._gridPadding, this), + ); + this.grid.draw(); + var aq = this.series; + var aJ = aq.length; + for (aH = 0, aE = aJ; aH < aE; aH++) { + aF = this.seriesStack[aH]; + this.target.append( + aq[aF].shadowCanvas.createElement( + this._gridPadding, + "jqplot-series-shadowCanvas", + null, + this, + ), + ); + aq[aF].shadowCanvas.setContext(); + aq[aF].shadowCanvas._elem.data("seriesIndex", aF); + } + for (aH = 0, aE = aJ; aH < aE; aH++) { + aF = this.seriesStack[aH]; + this.target.append( + aq[aF].canvas.createElement( + this._gridPadding, + "jqplot-series-canvas", + null, + this, + ), + ); + aq[aF].canvas.setContext(); + aq[aF].canvas._elem.data("seriesIndex", aF); + } + this.target.append( + this.eventCanvas.createElement( + this._gridPadding, + "jqplot-event-canvas", + null, + this, + ), + ); + this.eventCanvas.setContext(); + this.eventCanvas._ctx.fillStyle = "rgba(0,0,0,0)"; + this.eventCanvas._ctx.fillRect( + 0, + 0, + this.eventCanvas._ctx.canvas.width, + this.eventCanvas._ctx.canvas.height, + ); + this.bindCustomEvents(); + if (this.legend.preDraw) { + this.eventCanvas._elem.before(aL); + this.legend.pack(aA); + if (this.legend._elem) { + this.drawSeries({ + legendInfo: { + location: this.legend.location, + placement: this.legend.placement, + width: this.legend.getWidth(), + height: this.legend.getHeight(), + xoffset: this.legend.xoffset, + yoffset: this.legend.yoffset, + }, + }); + } else { + this.drawSeries(); + } + } else { + this.drawSeries(); + if (aJ) { + L(aq[aJ - 1].canvas._elem).after(aL); + } + this.legend.pack(aA); + } + for ( + var aH = 0, aE = L.jqplot.eventListenerHooks.length; + aH < aE; + aH++ + ) { + this.eventCanvas._elem.bind( + L.jqplot.eventListenerHooks[aH][0], + { plot: this }, + L.jqplot.eventListenerHooks[aH][1], + ); + } + for ( + var aH = 0, aE = this.eventListenerHooks.hooks.length; + aH < aE; + aH++ + ) { + this.eventCanvas._elem.bind( + this.eventListenerHooks.hooks[aH][0], + { plot: this }, + this.eventListenerHooks.hooks[aH][1], + ); + } + var ay = this.fillBetween; + if ( + ay.fill && + ay.series1 !== ay.series2 && + ay.series1 < aJ && + ay.series2 < aJ && + aq[ay.series1]._type === "line" && + aq[ay.series2]._type === "line" + ) { + this.doFillBetweenLines(); + } + for ( + var aH = 0, aE = L.jqplot.postDrawHooks.length; + aH < aE; + aH++ + ) { + L.jqplot.postDrawHooks[aH].call(this); + } + for ( + var aH = 0, aE = this.postDrawHooks.hooks.length; + aH < aE; + aH++ + ) { + this.postDrawHooks.hooks[aH].apply( + this, + this.postDrawHooks.args[aH], + ); + } + if (this.target.is(":visible")) { + this._drawCount += 1; + } + var av, aw, aD, ap; + for (aH = 0, aE = aJ; aH < aE; aH++) { + av = aq[aH]; + aw = av.renderer; + aD = ".jqplot-point-label.jqplot-series-" + aH; + if ( + aw.animation && + aw.animation._supported && + aw.animation.show && + (this._drawCount < 2 || this.animateReplot) + ) { + ap = this.target.find(aD); + ap.stop(true, true).hide(); + av.canvas._elem.stop(true, true).hide(); + av.shadowCanvas._elem.stop(true, true).hide(); + av.canvas._elem.jqplotEffect( + "blind", + { mode: "show", direction: aw.animation.direction }, + aw.animation.speed, + ); + av.shadowCanvas._elem.jqplotEffect( + "blind", + { mode: "show", direction: aw.animation.direction }, + aw.animation.speed, + ); + ap.fadeIn(aw.animation.speed * 0.8); + } + } + ap = null; + this.target.trigger("jqplotPostDraw", [this]); + } + }; + R.prototype.doFillBetweenLines = function () { + var an = this.fillBetween; + var ax = an.series1; + var av = an.series2; + var aw = ax < av ? ax : av; + var au = av > ax ? av : ax; + var ar = this.series[aw]; + var aq = this.series[au]; + if (aq.renderer.smooth) { + var ap = aq.renderer._smoothedData.slice(0).reverse(); + } else { + var ap = aq.gridData.slice(0).reverse(); + } + if (ar.renderer.smooth) { + var at = ar.renderer._smoothedData.concat(ap); + } else { + var at = ar.gridData.concat(ap); + } + var ao = an.color !== null ? an.color : this.series[ax].fillColor; + var ay = an.baseSeries !== null ? an.baseSeries : aw; + var am = this.series[ay].renderer.shapeRenderer; + var al = { fillStyle: ao, fill: true, closePath: true }; + am.draw(ar.shadowCanvas._ctx, at, al); + }; + this.bindCustomEvents = function () { + this.eventCanvas._elem.bind("click", { plot: this }, this.onClick); + this.eventCanvas._elem.bind( + "dblclick", + { plot: this }, + this.onDblClick, + ); + this.eventCanvas._elem.bind( + "mousedown", + { plot: this }, + this.onMouseDown, + ); + this.eventCanvas._elem.bind( + "mousemove", + { plot: this }, + this.onMouseMove, + ); + this.eventCanvas._elem.bind( + "mouseenter", + { plot: this }, + this.onMouseEnter, + ); + this.eventCanvas._elem.bind( + "mouseleave", + { plot: this }, + this.onMouseLeave, + ); + if (this.captureRightClick) { + this.eventCanvas._elem.bind( + "mouseup", + { plot: this }, + this.onRightClick, + ); + this.eventCanvas._elem.get(0).oncontextmenu = function () { + return false; + }; + } else { + this.eventCanvas._elem.bind( + "mouseup", + { plot: this }, + this.onMouseUp, + ); + } + }; + function ai(av) { + var au = av.data.plot; + var ap = au.eventCanvas._elem.offset(); + var at = { x: av.pageX - ap.left, y: av.pageY - ap.top }; + var aq = { + xaxis: null, + yaxis: null, + x2axis: null, + y2axis: null, + y3axis: null, + y4axis: null, + y5axis: null, + y6axis: null, + y7axis: null, + y8axis: null, + y9axis: null, + yMidAxis: null, + }; + var ar = [ + "xaxis", + "yaxis", + "x2axis", + "y2axis", + "y3axis", + "y4axis", + "y5axis", + "y6axis", + "y7axis", + "y8axis", + "y9axis", + "yMidAxis", + ]; + var al = au.axes; + var am, ao; + for (am = 11; am > 0; am--) { + ao = ar[am - 1]; + if (al[ao].show) { + aq[ao] = al[ao].series_p2u(at[ao.charAt(0)]); + } + } + return { offsets: ap, gridPos: at, dataPos: aq }; + } + function ak(al, am) { + var aq = am.series; + var aW, aU, aT, aO, aP, aJ, aI, aw, au, az, aA, aK; + var aS, aX, aQ, ar, aH, aM, aV; + var an, aN; + for (aT = am.seriesStack.length - 1; aT >= 0; aT--) { + aW = am.seriesStack[aT]; + aO = aq[aW]; + aV = aO._highlightThreshold; + switch (aO.renderer.constructor) { + case L.jqplot.BarRenderer: + aJ = al.x; + aI = al.y; + for (aU = 0; aU < aO._barPoints.length; aU++) { + aH = aO._barPoints[aU]; + aQ = aO.gridData[aU]; + if ( + aJ > aH[0][0] && + aJ < aH[2][0] && + aI > aH[2][1] && + aI < aH[0][1] + ) { + return { + seriesIndex: aO.index, + pointIndex: aU, + gridData: aQ, + data: aO.data[aU], + points: aO._barPoints[aU], + }; + } + } + break; + case L.jqplot.PyramidRenderer: + aJ = al.x; + aI = al.y; + for (aU = 0; aU < aO._barPoints.length; aU++) { + aH = aO._barPoints[aU]; + aQ = aO.gridData[aU]; + if ( + aJ > aH[0][0] + aV[0][0] && + aJ < aH[2][0] + aV[2][0] && + aI > aH[2][1] && + aI < aH[0][1] + ) { + return { + seriesIndex: aO.index, + pointIndex: aU, + gridData: aQ, + data: aO.data[aU], + points: aO._barPoints[aU], + }; + } + } + break; + case L.jqplot.DonutRenderer: + az = (aO.startAngle / 180) * Math.PI; + aJ = al.x - aO._center[0]; + aI = al.y - aO._center[1]; + aP = Math.sqrt(Math.pow(aJ, 2) + Math.pow(aI, 2)); + if (aJ > 0 && -aI >= 0) { + aw = 2 * Math.PI - Math.atan(-aI / aJ); + } else { + if (aJ > 0 && -aI < 0) { + aw = -Math.atan(-aI / aJ); + } else { + if (aJ < 0) { + aw = Math.PI - Math.atan(-aI / aJ); + } else { + if (aJ == 0 && -aI > 0) { + aw = (3 * Math.PI) / 2; + } else { + if (aJ == 0 && -aI < 0) { + aw = Math.PI / 2; + } else { + if (aJ == 0 && aI == 0) { + aw = 0; + } + } + } + } + } + } + if (az) { + aw -= az; + if (aw < 0) { + aw += 2 * Math.PI; + } else { + if (aw > 2 * Math.PI) { + aw -= 2 * Math.PI; + } + } + } + au = (aO.sliceMargin / 180) * Math.PI; + if (aP < aO._radius && aP > aO._innerRadius) { + for (aU = 0; aU < aO.gridData.length; aU++) { + aA = aU > 0 ? aO.gridData[aU - 1][1] + au : au; + aK = aO.gridData[aU][1]; + if (aw > aA && aw < aK) { + return { + seriesIndex: aO.index, + pointIndex: aU, + gridData: [al.x, al.y], + data: aO.data[aU], + }; + } + } + } + break; + case L.jqplot.PieRenderer: + az = (aO.startAngle / 180) * Math.PI; + aJ = al.x - aO._center[0]; + aI = al.y - aO._center[1]; + aP = Math.sqrt(Math.pow(aJ, 2) + Math.pow(aI, 2)); + if (aJ > 0 && -aI >= 0) { + aw = 2 * Math.PI - Math.atan(-aI / aJ); + } else { + if (aJ > 0 && -aI < 0) { + aw = -Math.atan(-aI / aJ); + } else { + if (aJ < 0) { + aw = Math.PI - Math.atan(-aI / aJ); + } else { + if (aJ == 0 && -aI > 0) { + aw = (3 * Math.PI) / 2; + } else { + if (aJ == 0 && -aI < 0) { + aw = Math.PI / 2; + } else { + if (aJ == 0 && aI == 0) { + aw = 0; + } + } + } + } + } + } + if (az) { + aw -= az; + if (aw < 0) { + aw += 2 * Math.PI; + } else { + if (aw > 2 * Math.PI) { + aw -= 2 * Math.PI; + } + } + } + au = (aO.sliceMargin / 180) * Math.PI; + if (aP < aO._radius) { + for (aU = 0; aU < aO.gridData.length; aU++) { + aA = aU > 0 ? aO.gridData[aU - 1][1] + au : au; + aK = aO.gridData[aU][1]; + if (aw > aA && aw < aK) { + return { + seriesIndex: aO.index, + pointIndex: aU, + gridData: [al.x, al.y], + data: aO.data[aU], + }; + } + } + } + break; + case L.jqplot.BubbleRenderer: + aJ = al.x; + aI = al.y; + var aF = null; + if (aO.show) { + for (var aU = 0; aU < aO.gridData.length; aU++) { + aQ = aO.gridData[aU]; + aX = Math.sqrt( + (aJ - aQ[0]) * (aJ - aQ[0]) + + (aI - aQ[1]) * (aI - aQ[1]), + ); + if (aX <= aQ[2] && (aX <= aS || aS == null)) { + aS = aX; + aF = { + seriesIndex: aW, + pointIndex: aU, + gridData: aQ, + data: aO.data[aU], + }; + } + } + if (aF != null) { + return aF; + } + } + break; + case L.jqplot.FunnelRenderer: + aJ = al.x; + aI = al.y; + var aL = aO._vertices, + ap = aL[0], + ao = aL[aL.length - 1], + at, + aE, + ay; + function aR(a0, a2, a1) { + var aZ = (a2[1] - a1[1]) / (a2[0] - a1[0]); + var aY = a2[1] - aZ * a2[0]; + var a3 = a0 + a2[1]; + return [(a3 - aY) / aZ, a3]; + } + at = aR(aI, ap[0], ao[3]); + aE = aR(aI, ap[1], ao[2]); + for (aU = 0; aU < aL.length; aU++) { + ay = aL[aU]; + if ( + aI >= ay[0][1] && + aI <= ay[3][1] && + aJ >= at[0] && + aJ <= aE[0] + ) { + return { + seriesIndex: aO.index, + pointIndex: aU, + gridData: null, + data: aO.data[aU], + }; + } + } + break; + case L.jqplot.LineRenderer: + aJ = al.x; + aI = al.y; + aP = aO.renderer; + if (aO.show) { + if ( + (aO.fill || + (aO.renderer.bands.show && + aO.renderer.bands.fill)) && + (!am.plugins.highlighter || + !am.plugins.highlighter.show) + ) { + var ax = false; + if ( + aJ > aO._boundingBox[0][0] && + aJ < aO._boundingBox[1][0] && + aI > aO._boundingBox[1][1] && + aI < aO._boundingBox[0][1] + ) { + var aD = aO._areaPoints.length; + var aG; + var aU = aD - 1; + for (var aG = 0; aG < aD; aG++) { + var aC = [ + aO._areaPoints[aG][0], + aO._areaPoints[aG][1], + ]; + var aB = [ + aO._areaPoints[aU][0], + aO._areaPoints[aU][1], + ]; + if ( + (aC[1] < aI && aB[1] >= aI) || + (aB[1] < aI && aC[1] >= aI) + ) { + if ( + aC[0] + + ((aI - aC[1]) / + (aB[1] - aC[1])) * + (aB[0] - aC[0]) < + aJ + ) { + ax = !ax; + } + } + aU = aG; + } + } + if (ax) { + return { + seriesIndex: aW, + pointIndex: null, + gridData: aO.gridData, + data: aO.data, + points: aO._areaPoints, + }; + } + break; + } else { + aN = + aO.markerRenderer.size / 2 + + aO.neighborThreshold; + an = aN > 0 ? aN : 0; + for ( + var aU = 0; + aU < aO.gridData.length; + aU++ + ) { + aQ = aO.gridData[aU]; + if ( + aP.constructor == L.jqplot.OHLCRenderer + ) { + if (aP.candleStick) { + var av = aO._yaxis.series_u2p; + if ( + aJ >= + aQ[0] - aP._bodyWidth / 2 && + aJ <= + aQ[0] + aP._bodyWidth / 2 && + aI >= av(aO.data[aU][2]) && + aI <= av(aO.data[aU][3]) + ) { + return { + seriesIndex: aW, + pointIndex: aU, + gridData: aQ, + data: aO.data[aU], + }; + } + } else { + if (!aP.hlc) { + var av = aO._yaxis.series_u2p; + if ( + aJ >= + aQ[0] - + aP._tickLength && + aJ <= + aQ[0] + + aP._tickLength && + aI >= av(aO.data[aU][2]) && + aI <= av(aO.data[aU][3]) + ) { + return { + seriesIndex: aW, + pointIndex: aU, + gridData: aQ, + data: aO.data[aU], + }; + } + } else { + var av = aO._yaxis.series_u2p; + if ( + aJ >= + aQ[0] - + aP._tickLength && + aJ <= + aQ[0] + + aP._tickLength && + aI >= av(aO.data[aU][1]) && + aI <= av(aO.data[aU][2]) + ) { + return { + seriesIndex: aW, + pointIndex: aU, + gridData: aQ, + data: aO.data[aU], + }; + } + } + } + } else { + if (aQ[0] != null && aQ[1] != null) { + aX = Math.sqrt( + (aJ - aQ[0]) * (aJ - aQ[0]) + + (aI - aQ[1]) * (aI - aQ[1]), + ); + if ( + aX <= an && + (aX <= aS || aS == null) + ) { + aS = aX; + return { + seriesIndex: aW, + pointIndex: aU, + gridData: aQ, + data: aO.data[aU], + }; + } + } + } + } + } + } + break; + default: + aJ = al.x; + aI = al.y; + aP = aO.renderer; + if (aO.show) { + aN = + aO.markerRenderer.size / 2 + + aO.neighborThreshold; + an = aN > 0 ? aN : 0; + for (var aU = 0; aU < aO.gridData.length; aU++) { + aQ = aO.gridData[aU]; + if (aP.constructor == L.jqplot.OHLCRenderer) { + if (aP.candleStick) { + var av = aO._yaxis.series_u2p; + if ( + aJ >= aQ[0] - aP._bodyWidth / 2 && + aJ <= aQ[0] + aP._bodyWidth / 2 && + aI >= av(aO.data[aU][2]) && + aI <= av(aO.data[aU][3]) + ) { + return { + seriesIndex: aW, + pointIndex: aU, + gridData: aQ, + data: aO.data[aU], + }; + } + } else { + if (!aP.hlc) { + var av = aO._yaxis.series_u2p; + if ( + aJ >= aQ[0] - aP._tickLength && + aJ <= aQ[0] + aP._tickLength && + aI >= av(aO.data[aU][2]) && + aI <= av(aO.data[aU][3]) + ) { + return { + seriesIndex: aW, + pointIndex: aU, + gridData: aQ, + data: aO.data[aU], + }; + } + } else { + var av = aO._yaxis.series_u2p; + if ( + aJ >= aQ[0] - aP._tickLength && + aJ <= aQ[0] + aP._tickLength && + aI >= av(aO.data[aU][1]) && + aI <= av(aO.data[aU][2]) + ) { + return { + seriesIndex: aW, + pointIndex: aU, + gridData: aQ, + data: aO.data[aU], + }; + } + } + } + } else { + aX = Math.sqrt( + (aJ - aQ[0]) * (aJ - aQ[0]) + + (aI - aQ[1]) * (aI - aQ[1]), + ); + if (aX <= an && (aX <= aS || aS == null)) { + aS = aX; + return { + seriesIndex: aW, + pointIndex: aU, + gridData: aQ, + data: aO.data[aU], + }; + } + } + } + } + break; + } + } + return null; + } + this.onClick = function (an) { + var am = ai(an); + var ap = an.data.plot; + var ao = ak(am.gridPos, ap); + var al = L.Event("jqplotClick"); + al.pageX = an.pageX; + al.pageY = an.pageY; + L(this).trigger(al, [am.gridPos, am.dataPos, ao, ap]); + }; + this.onDblClick = function (an) { + var am = ai(an); + var ap = an.data.plot; + var ao = ak(am.gridPos, ap); + var al = L.Event("jqplotDblClick"); + al.pageX = an.pageX; + al.pageY = an.pageY; + L(this).trigger(al, [am.gridPos, am.dataPos, ao, ap]); + }; + this.onMouseDown = function (an) { + var am = ai(an); + var ap = an.data.plot; + var ao = ak(am.gridPos, ap); + var al = L.Event("jqplotMouseDown"); + al.pageX = an.pageX; + al.pageY = an.pageY; + L(this).trigger(al, [am.gridPos, am.dataPos, ao, ap]); + }; + this.onMouseUp = function (an) { + var am = ai(an); + var al = L.Event("jqplotMouseUp"); + al.pageX = an.pageX; + al.pageY = an.pageY; + L(this).trigger(al, [am.gridPos, am.dataPos, null, an.data.plot]); + }; + this.onRightClick = function (an) { + var am = ai(an); + var ap = an.data.plot; + var ao = ak(am.gridPos, ap); + if (ap.captureRightClick) { + if (an.which == 3) { + var al = L.Event("jqplotRightClick"); + al.pageX = an.pageX; + al.pageY = an.pageY; + L(this).trigger(al, [am.gridPos, am.dataPos, ao, ap]); + } else { + var al = L.Event("jqplotMouseUp"); + al.pageX = an.pageX; + al.pageY = an.pageY; + L(this).trigger(al, [am.gridPos, am.dataPos, ao, ap]); + } + } + }; + this.onMouseMove = function (an) { + var am = ai(an); + var ap = an.data.plot; + var ao = ak(am.gridPos, ap); + var al = L.Event("jqplotMouseMove"); + al.pageX = an.pageX; + al.pageY = an.pageY; + L(this).trigger(al, [am.gridPos, am.dataPos, ao, ap]); + }; + this.onMouseEnter = function (an) { + var am = ai(an); + var ao = an.data.plot; + var al = L.Event("jqplotMouseEnter"); + al.pageX = an.pageX; + al.pageY = an.pageY; + al.relatedTarget = an.relatedTarget; + L(this).trigger(al, [am.gridPos, am.dataPos, null, ao]); + }; + this.onMouseLeave = function (an) { + var am = ai(an); + var ao = an.data.plot; + var al = L.Event("jqplotMouseLeave"); + al.pageX = an.pageX; + al.pageY = an.pageY; + al.relatedTarget = an.relatedTarget; + L(this).trigger(al, [am.gridPos, am.dataPos, null, ao]); + }; + this.drawSeries = function (an, al) { + var ap, ao, am; + al = typeof an === "number" && al == null ? an : al; + an = typeof an === "object" ? an : {}; + if (al != u) { + ao = this.series[al]; + am = ao.shadowCanvas._ctx; + am.clearRect(0, 0, am.canvas.width, am.canvas.height); + ao.drawShadow(am, an, this); + am = ao.canvas._ctx; + am.clearRect(0, 0, am.canvas.width, am.canvas.height); + ao.draw(am, an, this); + if (ao.renderer.constructor == L.jqplot.BezierCurveRenderer) { + if (al < this.series.length - 1) { + this.drawSeries(al + 1); + } + } + } else { + for (ap = 0; ap < this.series.length; ap++) { + ao = this.series[ap]; + am = ao.shadowCanvas._ctx; + am.clearRect(0, 0, am.canvas.width, am.canvas.height); + ao.drawShadow(am, an, this); + am = ao.canvas._ctx; + am.clearRect(0, 0, am.canvas.width, am.canvas.height); + ao.draw(am, an, this); + } + } + an = al = ap = ao = am = null; + }; + this.moveSeriesToFront = function (am) { + am = parseInt(am, 10); + var ap = L.inArray(am, this.seriesStack); + if (ap == -1) { + return; + } + if (ap == this.seriesStack.length - 1) { + this.previousSeriesStack = this.seriesStack.slice(0); + return; + } + var al = this.seriesStack[this.seriesStack.length - 1]; + var ao = this.series[am].canvas._elem.detach(); + var an = this.series[am].shadowCanvas._elem.detach(); + this.series[al].shadowCanvas._elem.after(an); + this.series[al].canvas._elem.after(ao); + this.previousSeriesStack = this.seriesStack.slice(0); + this.seriesStack.splice(ap, 1); + this.seriesStack.push(am); + }; + this.moveSeriesToBack = function (am) { + am = parseInt(am, 10); + var ap = L.inArray(am, this.seriesStack); + if (ap == 0 || ap == -1) { + return; + } + var al = this.seriesStack[0]; + var ao = this.series[am].canvas._elem.detach(); + var an = this.series[am].shadowCanvas._elem.detach(); + this.series[al].shadowCanvas._elem.before(an); + this.series[al].canvas._elem.before(ao); + this.previousSeriesStack = this.seriesStack.slice(0); + this.seriesStack.splice(ap, 1); + this.seriesStack.unshift(am); + }; + this.restorePreviousSeriesOrder = function () { + var ar, aq, ap, ao, an, al, am; + if (this.seriesStack == this.previousSeriesStack) { + return; + } + for (ar = 1; ar < this.previousSeriesStack.length; ar++) { + al = this.previousSeriesStack[ar]; + am = this.previousSeriesStack[ar - 1]; + ap = this.series[al].canvas._elem.detach(); + ao = this.series[al].shadowCanvas._elem.detach(); + this.series[am].shadowCanvas._elem.after(ao); + this.series[am].canvas._elem.after(ap); + } + an = this.seriesStack.slice(0); + this.seriesStack = this.previousSeriesStack.slice(0); + this.previousSeriesStack = an; + }; + this.restoreOriginalSeriesOrder = function () { + var ap, + ao, + al = [], + an, + am; + for (ap = 0; ap < this.series.length; ap++) { + al.push(ap); + } + if (this.seriesStack == al) { + return; + } + this.previousSeriesStack = this.seriesStack.slice(0); + this.seriesStack = al; + for (ap = 1; ap < this.seriesStack.length; ap++) { + an = this.series[ap].canvas._elem.detach(); + am = this.series[ap].shadowCanvas._elem.detach(); + this.series[ap - 1].shadowCanvas._elem.after(am); + this.series[ap - 1].canvas._elem.after(an); + } + }; + this.activateTheme = function (al) { + this.themeEngine.activate(this, al); + }; + } + L.jqplot.computeHighlightColors = function (ai) { + var ak; + if (L.isArray(ai)) { + ak = []; + for (var am = 0; am < ai.length; am++) { + var al = L.jqplot.getColorComponents(ai[am]); + var ah = [al[0], al[1], al[2]]; + var an = ah[0] + ah[1] + ah[2]; + for (var aj = 0; aj < 3; aj++) { + ah[aj] = an > 660 ? ah[aj] * 0.85 : 0.73 * ah[aj] + 90; + ah[aj] = parseInt(ah[aj], 10); + ah[aj] > 255 ? 255 : ah[aj]; + } + ah[3] = 0.3 + 0.35 * al[3]; + ak.push( + "rgba(" + + ah[0] + + "," + + ah[1] + + "," + + ah[2] + + "," + + ah[3] + + ")", + ); + } + } else { + var al = L.jqplot.getColorComponents(ai); + var ah = [al[0], al[1], al[2]]; + var an = ah[0] + ah[1] + ah[2]; + for (var aj = 0; aj < 3; aj++) { + ah[aj] = an > 660 ? ah[aj] * 0.85 : 0.73 * ah[aj] + 90; + ah[aj] = parseInt(ah[aj], 10); + ah[aj] > 255 ? 255 : ah[aj]; + } + ah[3] = 0.3 + 0.35 * al[3]; + ak = + "rgba(" + ah[0] + "," + ah[1] + "," + ah[2] + "," + ah[3] + ")"; + } + return ak; + }; + L.jqplot.ColorGenerator = function (ai) { + ai = ai || L.jqplot.config.defaultColors; + var ah = 0; + this.next = function () { + if (ah < ai.length) { + return ai[ah++]; + } else { + ah = 0; + return ai[ah++]; + } + }; + this.previous = function () { + if (ah > 0) { + return ai[ah--]; + } else { + ah = ai.length - 1; + return ai[ah]; + } + }; + this.get = function (ak) { + var aj = ak - ai.length * Math.floor(ak / ai.length); + return ai[aj]; + }; + this.setColors = function (aj) { + ai = aj; + }; + this.reset = function () { + ah = 0; + }; + this.getIndex = function () { + return ah; + }; + this.setIndex = function (aj) { + ah = aj; + }; + }; + L.jqplot.hex2rgb = function (aj, ah) { + aj = aj.replace("#", ""); + if (aj.length == 3) { + aj = + aj.charAt(0) + + aj.charAt(0) + + aj.charAt(1) + + aj.charAt(1) + + aj.charAt(2) + + aj.charAt(2); + } + var ai; + ai = + "rgba(" + + parseInt(aj.slice(0, 2), 16) + + ", " + + parseInt(aj.slice(2, 4), 16) + + ", " + + parseInt(aj.slice(4, 6), 16); + if (ah) { + ai += ", " + ah; + } + ai += ")"; + return ai; + }; + L.jqplot.rgb2hex = function (am) { + var aj = + /rgba?\( *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *(?:, *[0-9.]*)?\)/; + var ah = am.match(aj); + var al = "#"; + for (var ak = 1; ak < 4; ak++) { + var ai; + if (ah[ak].search(/%/) != -1) { + ai = parseInt((255 * ah[ak]) / 100, 10).toString(16); + if (ai.length == 1) { + ai = "0" + ai; + } + } else { + ai = parseInt(ah[ak], 10).toString(16); + if (ai.length == 1) { + ai = "0" + ai; + } + } + al += ai; + } + return al; + }; + L.jqplot.normalize2rgb = function (ai, ah) { + if (ai.search(/^ *rgba?\(/) != -1) { + return ai; + } else { + if (ai.search(/^ *#?[0-9a-fA-F]?[0-9a-fA-F]/) != -1) { + return L.jqplot.hex2rgb(ai, ah); + } else { + throw new Error("Invalid color spec"); + } + } + }; + L.jqplot.getColorComponents = function (am) { + am = L.jqplot.colorKeywordMap[am] || am; + var ak = L.jqplot.normalize2rgb(am); + var aj = + /rgba?\( *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *,? *([0-9.]* *)?\)/; + var ah = ak.match(aj); + var ai = []; + for (var al = 1; al < 4; al++) { + if (ah[al].search(/%/) != -1) { + ai[al - 1] = parseInt((255 * ah[al]) / 100, 10); + } else { + ai[al - 1] = parseInt(ah[al], 10); + } + } + ai[3] = parseFloat(ah[4]) ? parseFloat(ah[4]) : 1; + return ai; + }; + L.jqplot.colorKeywordMap = { + aliceblue: "rgb(240, 248, 255)", + antiquewhite: "rgb(250, 235, 215)", + aqua: "rgb( 0, 255, 255)", + aquamarine: "rgb(127, 255, 212)", + azure: "rgb(240, 255, 255)", + beige: "rgb(245, 245, 220)", + bisque: "rgb(255, 228, 196)", + black: "rgb( 0, 0, 0)", + blanchedalmond: "rgb(255, 235, 205)", + blue: "rgb( 0, 0, 255)", + blueviolet: "rgb(138, 43, 226)", + brown: "rgb(165, 42, 42)", + burlywood: "rgb(222, 184, 135)", + cadetblue: "rgb( 95, 158, 160)", + chartreuse: "rgb(127, 255, 0)", + chocolate: "rgb(210, 105, 30)", + coral: "rgb(255, 127, 80)", + cornflowerblue: "rgb(100, 149, 237)", + cornsilk: "rgb(255, 248, 220)", + crimson: "rgb(220, 20, 60)", + cyan: "rgb( 0, 255, 255)", + darkblue: "rgb( 0, 0, 139)", + darkcyan: "rgb( 0, 139, 139)", + darkgoldenrod: "rgb(184, 134, 11)", + darkgray: "rgb(169, 169, 169)", + darkgreen: "rgb( 0, 100, 0)", + darkgrey: "rgb(169, 169, 169)", + darkkhaki: "rgb(189, 183, 107)", + darkmagenta: "rgb(139, 0, 139)", + darkolivegreen: "rgb( 85, 107, 47)", + darkorange: "rgb(255, 140, 0)", + darkorchid: "rgb(153, 50, 204)", + darkred: "rgb(139, 0, 0)", + darksalmon: "rgb(233, 150, 122)", + darkseagreen: "rgb(143, 188, 143)", + darkslateblue: "rgb( 72, 61, 139)", + darkslategray: "rgb( 47, 79, 79)", + darkslategrey: "rgb( 47, 79, 79)", + darkturquoise: "rgb( 0, 206, 209)", + darkviolet: "rgb(148, 0, 211)", + deeppink: "rgb(255, 20, 147)", + deepskyblue: "rgb( 0, 191, 255)", + dimgray: "rgb(105, 105, 105)", + dimgrey: "rgb(105, 105, 105)", + dodgerblue: "rgb( 30, 144, 255)", + firebrick: "rgb(178, 34, 34)", + floralwhite: "rgb(255, 250, 240)", + forestgreen: "rgb( 34, 139, 34)", + fuchsia: "rgb(255, 0, 255)", + gainsboro: "rgb(220, 220, 220)", + ghostwhite: "rgb(248, 248, 255)", + gold: "rgb(255, 215, 0)", + goldenrod: "rgb(218, 165, 32)", + gray: "rgb(128, 128, 128)", + grey: "rgb(128, 128, 128)", + green: "rgb( 0, 128, 0)", + greenyellow: "rgb(173, 255, 47)", + honeydew: "rgb(240, 255, 240)", + hotpink: "rgb(255, 105, 180)", + indianred: "rgb(205, 92, 92)", + indigo: "rgb( 75, 0, 130)", + ivory: "rgb(255, 255, 240)", + khaki: "rgb(240, 230, 140)", + lavender: "rgb(230, 230, 250)", + lavenderblush: "rgb(255, 240, 245)", + lawngreen: "rgb(124, 252, 0)", + lemonchiffon: "rgb(255, 250, 205)", + lightblue: "rgb(173, 216, 230)", + lightcoral: "rgb(240, 128, 128)", + lightcyan: "rgb(224, 255, 255)", + lightgoldenrodyellow: "rgb(250, 250, 210)", + lightgray: "rgb(211, 211, 211)", + lightgreen: "rgb(144, 238, 144)", + lightgrey: "rgb(211, 211, 211)", + lightpink: "rgb(255, 182, 193)", + lightsalmon: "rgb(255, 160, 122)", + lightseagreen: "rgb( 32, 178, 170)", + lightskyblue: "rgb(135, 206, 250)", + lightslategray: "rgb(119, 136, 153)", + lightslategrey: "rgb(119, 136, 153)", + lightsteelblue: "rgb(176, 196, 222)", + lightyellow: "rgb(255, 255, 224)", + lime: "rgb( 0, 255, 0)", + limegreen: "rgb( 50, 205, 50)", + linen: "rgb(250, 240, 230)", + magenta: "rgb(255, 0, 255)", + maroon: "rgb(128, 0, 0)", + mediumaquamarine: "rgb(102, 205, 170)", + mediumblue: "rgb( 0, 0, 205)", + mediumorchid: "rgb(186, 85, 211)", + mediumpurple: "rgb(147, 112, 219)", + mediumseagreen: "rgb( 60, 179, 113)", + mediumslateblue: "rgb(123, 104, 238)", + mediumspringgreen: "rgb( 0, 250, 154)", + mediumturquoise: "rgb( 72, 209, 204)", + mediumvioletred: "rgb(199, 21, 133)", + midnightblue: "rgb( 25, 25, 112)", + mintcream: "rgb(245, 255, 250)", + mistyrose: "rgb(255, 228, 225)", + moccasin: "rgb(255, 228, 181)", + navajowhite: "rgb(255, 222, 173)", + navy: "rgb( 0, 0, 128)", + oldlace: "rgb(253, 245, 230)", + olive: "rgb(128, 128, 0)", + olivedrab: "rgb(107, 142, 35)", + orange: "rgb(255, 165, 0)", + orangered: "rgb(255, 69, 0)", + orchid: "rgb(218, 112, 214)", + palegoldenrod: "rgb(238, 232, 170)", + palegreen: "rgb(152, 251, 152)", + paleturquoise: "rgb(175, 238, 238)", + palevioletred: "rgb(219, 112, 147)", + papayawhip: "rgb(255, 239, 213)", + peachpuff: "rgb(255, 218, 185)", + peru: "rgb(205, 133, 63)", + pink: "rgb(255, 192, 203)", + plum: "rgb(221, 160, 221)", + powderblue: "rgb(176, 224, 230)", + purple: "rgb(128, 0, 128)", + red: "rgb(255, 0, 0)", + rosybrown: "rgb(188, 143, 143)", + royalblue: "rgb( 65, 105, 225)", + saddlebrown: "rgb(139, 69, 19)", + salmon: "rgb(250, 128, 114)", + sandybrown: "rgb(244, 164, 96)", + seagreen: "rgb( 46, 139, 87)", + seashell: "rgb(255, 245, 238)", + sienna: "rgb(160, 82, 45)", + silver: "rgb(192, 192, 192)", + skyblue: "rgb(135, 206, 235)", + slateblue: "rgb(106, 90, 205)", + slategray: "rgb(112, 128, 144)", + slategrey: "rgb(112, 128, 144)", + snow: "rgb(255, 250, 250)", + springgreen: "rgb( 0, 255, 127)", + steelblue: "rgb( 70, 130, 180)", + tan: "rgb(210, 180, 140)", + teal: "rgb( 0, 128, 128)", + thistle: "rgb(216, 191, 216)", + tomato: "rgb(255, 99, 71)", + turquoise: "rgb( 64, 224, 208)", + violet: "rgb(238, 130, 238)", + wheat: "rgb(245, 222, 179)", + white: "rgb(255, 255, 255)", + whitesmoke: "rgb(245, 245, 245)", + yellow: "rgb(255, 255, 0)", + yellowgreen: "rgb(154, 205, 50)", + }; + L.jqplot.AxisLabelRenderer = function (ah) { + L.jqplot.ElemContainer.call(this); + this.axis; + this.show = true; + this.label = ""; + this.fontFamily = null; + this.fontSize = null; + this.textColor = null; + this._elem; + this.escapeHTML = false; + L.extend(true, this, ah); + }; + L.jqplot.AxisLabelRenderer.prototype = new L.jqplot.ElemContainer(); + L.jqplot.AxisLabelRenderer.prototype.constructor = + L.jqplot.AxisLabelRenderer; + L.jqplot.AxisLabelRenderer.prototype.init = function (ah) { + L.extend(true, this, ah); + }; + L.jqplot.AxisLabelRenderer.prototype.draw = function (ah, ai) { + if (this._elem) { + this._elem.emptyForce(); + this._elem = null; + } + this._elem = L( + '
', + ); + if (Number(this.label)) { + this._elem.css("white-space", "nowrap"); + } + if (!this.escapeHTML) { + this._elem.html(this.label); + } else { + this._elem.text(this.label); + } + if (this.fontFamily) { + this._elem.css("font-family", this.fontFamily); + } + if (this.fontSize) { + this._elem.css("font-size", this.fontSize); + } + if (this.textColor) { + this._elem.css("color", this.textColor); + } + return this._elem; + }; + L.jqplot.AxisLabelRenderer.prototype.pack = function () {}; + L.jqplot.AxisTickRenderer = function (ah) { + L.jqplot.ElemContainer.call(this); + this.mark = "outside"; + this.axis; + this.showMark = true; + this.showGridline = true; + this.isMinorTick = false; + this.size = 4; + this.markSize = 6; + this.show = true; + this.showLabel = true; + this.label = null; + this.value = null; + this._styles = {}; + this.formatter = L.jqplot.DefaultTickFormatter; + this.prefix = ""; + this.suffix = ""; + this.formatString = ""; + this.fontFamily; + this.fontSize; + this.textColor; + this.escapeHTML = false; + this._elem; + this._breakTick = false; + L.extend(true, this, ah); + }; + L.jqplot.AxisTickRenderer.prototype.init = function (ah) { + L.extend(true, this, ah); + }; + L.jqplot.AxisTickRenderer.prototype = new L.jqplot.ElemContainer(); + L.jqplot.AxisTickRenderer.prototype.constructor = L.jqplot.AxisTickRenderer; + L.jqplot.AxisTickRenderer.prototype.setTick = function (ah, aj, ai) { + this.value = ah; + this.axis = aj; + if (ai) { + this.isMinorTick = true; + } + return this; + }; + L.jqplot.AxisTickRenderer.prototype.draw = function () { + if (this.label === null) { + this.label = + this.prefix + + this.formatter(this.formatString, this.value) + + this.suffix; + } + var ai = { position: "absolute" }; + if (Number(this.label)) { + ai.whitSpace = "nowrap"; + } + if (this._elem) { + this._elem.emptyForce(); + this._elem = null; + } + this._elem = L(document.createElement("div")); + this._elem.addClass("jqplot-" + this.axis + "-tick"); + if (!this.escapeHTML) { + this._elem.html(this.label); + } else { + this._elem.text(this.label); + } + this._elem.css(ai); + for (var ah in this._styles) { + this._elem.css(ah, this._styles[ah]); + } + if (this.fontFamily) { + this._elem.css("font-family", this.fontFamily); + } + if (this.fontSize) { + this._elem.css("font-size", this.fontSize); + } + if (this.textColor) { + this._elem.css("color", this.textColor); + } + if (this._breakTick) { + this._elem.addClass("jqplot-breakTick"); + } + return this._elem; + }; + L.jqplot.DefaultTickFormatter = function (ah, ai) { + if (typeof ai == "number") { + if (!ah) { + ah = L.jqplot.config.defaultTickFormatString; + } + return L.jqplot.sprintf(ah, ai); + } else { + return String(ai); + } + }; + L.jqplot.PercentTickFormatter = function (ah, ai) { + if (typeof ai == "number") { + ai = 100 * ai; + if (!ah) { + ah = L.jqplot.config.defaultTickFormatString; + } + return L.jqplot.sprintf(ah, ai); + } else { + return String(ai); + } + }; + L.jqplot.AxisTickRenderer.prototype.pack = function () {}; + L.jqplot.CanvasGridRenderer = function () { + this.shadowRenderer = new L.jqplot.ShadowRenderer(); + }; + L.jqplot.CanvasGridRenderer.prototype.init = function (ai) { + this._ctx; + L.extend(true, this, ai); + var ah = { + lineJoin: "miter", + lineCap: "round", + fill: false, + isarc: false, + angle: this.shadowAngle, + offset: this.shadowOffset, + alpha: this.shadowAlpha, + depth: this.shadowDepth, + lineWidth: this.shadowWidth, + closePath: false, + strokeStyle: this.shadowColor, + }; + this.renderer.shadowRenderer.init(ah); + }; + L.jqplot.CanvasGridRenderer.prototype.createElement = function (ak) { + var aj; + if (this._elem) { + if ( + L.jqplot.use_excanvas && + window.G_vmlCanvasManager.uninitElement !== u + ) { + aj = this._elem.get(0); + window.G_vmlCanvasManager.uninitElement(aj); + aj = null; + } + this._elem.emptyForce(); + this._elem = null; + } + aj = ak.canvasManager.getCanvas(); + var ah = this._plotDimensions.width; + var ai = this._plotDimensions.height; + aj.width = ah; + aj.height = ai; + this._elem = L(aj); + this._elem.addClass("jqplot-grid-canvas"); + this._elem.css({ position: "absolute", left: 0, top: 0 }); + aj = ak.canvasManager.initCanvas(aj); + this._top = this._offsets.top; + this._bottom = ai - this._offsets.bottom; + this._left = this._offsets.left; + this._right = ah - this._offsets.right; + this._width = this._right - this._left; + this._height = this._bottom - this._top; + aj = null; + return this._elem; + }; + L.jqplot.CanvasGridRenderer.prototype.draw = function () { + this._ctx = this._elem.get(0).getContext("2d"); + var at = this._ctx; + var aw = this._axes; + at.save(); + at.clearRect( + 0, + 0, + this._plotDimensions.width, + this._plotDimensions.height, + ); + at.fillStyle = this.backgroundColor || this.background; + at.fillRect(this._left, this._top, this._width, this._height); + at.save(); + at.lineJoin = "miter"; + at.lineCap = "butt"; + at.lineWidth = this.gridLineWidth; + at.strokeStyle = this.gridLineColor; + var aA, az, ap, aq; + var am = ["xaxis", "yaxis", "x2axis", "y2axis"]; + for (var ay = 4; ay > 0; ay--) { + var aD = am[ay - 1]; + var ah = aw[aD]; + var aB = ah._ticks; + var ar = aB.length; + if (ah.show) { + if (ah.drawBaseline) { + var aC = {}; + if (ah.baselineWidth !== null) { + aC.lineWidth = ah.baselineWidth; + } + if (ah.baselineColor !== null) { + aC.strokeStyle = ah.baselineColor; + } + switch (aD) { + case "xaxis": + ao( + this._left, + this._bottom, + this._right, + this._bottom, + aC, + ); + break; + case "yaxis": + ao( + this._left, + this._bottom, + this._left, + this._top, + aC, + ); + break; + case "x2axis": + ao( + this._left, + this._bottom, + this._right, + this._bottom, + aC, + ); + break; + case "y2axis": + ao( + this._right, + this._bottom, + this._right, + this._top, + aC, + ); + break; + } + } + for (var au = ar; au > 0; au--) { + var an = aB[au - 1]; + if (an.show) { + var ak = Math.round(ah.u2p(an.value)) + 0.5; + switch (aD) { + case "xaxis": + if ( + an.showGridline && + this.drawGridlines && + ((!an.isMinorTick && + ah.drawMajorGridlines) || + (an.isMinorTick && + ah.drawMinorGridlines)) + ) { + ao(ak, this._top, ak, this._bottom); + } + if ( + an.showMark && + an.mark && + ((!an.isMinorTick && + ah.drawMajorTickMarks) || + (an.isMinorTick && + ah.drawMinorTickMarks)) + ) { + ap = an.markSize; + aq = an.mark; + var ak = Math.round(ah.u2p(an.value)) + 0.5; + switch (aq) { + case "outside": + aA = this._bottom; + az = this._bottom + ap; + break; + case "inside": + aA = this._bottom - ap; + az = this._bottom; + break; + case "cross": + aA = this._bottom - ap; + az = this._bottom + ap; + break; + default: + aA = this._bottom; + az = this._bottom + ap; + break; + } + if (this.shadow) { + this.renderer.shadowRenderer.draw( + at, + [ + [ak, aA], + [ak, az], + ], + { + lineCap: "butt", + lineWidth: this.gridLineWidth, + offset: + this.gridLineWidth * 0.75, + depth: 2, + fill: false, + closePath: false, + }, + ); + } + ao(ak, aA, ak, az); + } + break; + case "yaxis": + if ( + an.showGridline && + this.drawGridlines && + ((!an.isMinorTick && + ah.drawMajorGridlines) || + (an.isMinorTick && + ah.drawMinorGridlines)) + ) { + ao(this._right, ak, this._left, ak); + } + if ( + an.showMark && + an.mark && + ((!an.isMinorTick && + ah.drawMajorTickMarks) || + (an.isMinorTick && + ah.drawMinorTickMarks)) + ) { + ap = an.markSize; + aq = an.mark; + var ak = Math.round(ah.u2p(an.value)) + 0.5; + switch (aq) { + case "outside": + aA = this._left - ap; + az = this._left; + break; + case "inside": + aA = this._left; + az = this._left + ap; + break; + case "cross": + aA = this._left - ap; + az = this._left + ap; + break; + default: + aA = this._left - ap; + az = this._left; + break; + } + if (this.shadow) { + this.renderer.shadowRenderer.draw( + at, + [ + [aA, ak], + [az, ak], + ], + { + lineCap: "butt", + lineWidth: + this.gridLineWidth * 1.5, + offset: + this.gridLineWidth * 0.75, + fill: false, + closePath: false, + }, + ); + } + ao(aA, ak, az, ak, { + strokeStyle: ah.borderColor, + }); + } + break; + case "x2axis": + if ( + an.showGridline && + this.drawGridlines && + ((!an.isMinorTick && + ah.drawMajorGridlines) || + (an.isMinorTick && + ah.drawMinorGridlines)) + ) { + ao(ak, this._bottom, ak, this._top); + } + if ( + an.showMark && + an.mark && + ((!an.isMinorTick && + ah.drawMajorTickMarks) || + (an.isMinorTick && + ah.drawMinorTickMarks)) + ) { + ap = an.markSize; + aq = an.mark; + var ak = Math.round(ah.u2p(an.value)) + 0.5; + switch (aq) { + case "outside": + aA = this._top - ap; + az = this._top; + break; + case "inside": + aA = this._top; + az = this._top + ap; + break; + case "cross": + aA = this._top - ap; + az = this._top + ap; + break; + default: + aA = this._top - ap; + az = this._top; + break; + } + if (this.shadow) { + this.renderer.shadowRenderer.draw( + at, + [ + [ak, aA], + [ak, az], + ], + { + lineCap: "butt", + lineWidth: this.gridLineWidth, + offset: + this.gridLineWidth * 0.75, + depth: 2, + fill: false, + closePath: false, + }, + ); + } + ao(ak, aA, ak, az); + } + break; + case "y2axis": + if ( + an.showGridline && + this.drawGridlines && + ((!an.isMinorTick && + ah.drawMajorGridlines) || + (an.isMinorTick && + ah.drawMinorGridlines)) + ) { + ao(this._left, ak, this._right, ak); + } + if ( + an.showMark && + an.mark && + ((!an.isMinorTick && + ah.drawMajorTickMarks) || + (an.isMinorTick && + ah.drawMinorTickMarks)) + ) { + ap = an.markSize; + aq = an.mark; + var ak = Math.round(ah.u2p(an.value)) + 0.5; + switch (aq) { + case "outside": + aA = this._right; + az = this._right + ap; + break; + case "inside": + aA = this._right - ap; + az = this._right; + break; + case "cross": + aA = this._right - ap; + az = this._right + ap; + break; + default: + aA = this._right; + az = this._right + ap; + break; + } + if (this.shadow) { + this.renderer.shadowRenderer.draw( + at, + [ + [aA, ak], + [az, ak], + ], + { + lineCap: "butt", + lineWidth: + this.gridLineWidth * 1.5, + offset: + this.gridLineWidth * 0.75, + fill: false, + closePath: false, + }, + ); + } + ao(aA, ak, az, ak, { + strokeStyle: ah.borderColor, + }); + } + break; + default: + break; + } + } + } + an = null; + } + ah = null; + aB = null; + } + am = [ + "y3axis", + "y4axis", + "y5axis", + "y6axis", + "y7axis", + "y8axis", + "y9axis", + "yMidAxis", + ]; + for (var ay = 7; ay > 0; ay--) { + var ah = aw[am[ay - 1]]; + var aB = ah._ticks; + if (ah.show) { + var ai = aB[ah.numberTicks - 1]; + var al = aB[0]; + var aj = ah.getLeft(); + var av = [ + [aj, ai.getTop() + ai.getHeight() / 2], + [aj, al.getTop() + al.getHeight() / 2 + 1], + ]; + if (this.shadow) { + this.renderer.shadowRenderer.draw(at, av, { + lineCap: "butt", + fill: false, + closePath: false, + }); + } + ao(av[0][0], av[0][1], av[1][0], av[1][1], { + lineCap: "butt", + strokeStyle: ah.borderColor, + lineWidth: ah.borderWidth, + }); + for (var au = aB.length; au > 0; au--) { + var an = aB[au - 1]; + ap = an.markSize; + aq = an.mark; + var ak = Math.round(ah.u2p(an.value)) + 0.5; + if (an.showMark && an.mark) { + switch (aq) { + case "outside": + aA = aj; + az = aj + ap; + break; + case "inside": + aA = aj - ap; + az = aj; + break; + case "cross": + aA = aj - ap; + az = aj + ap; + break; + default: + aA = aj; + az = aj + ap; + break; + } + av = [ + [aA, ak], + [az, ak], + ]; + if (this.shadow) { + this.renderer.shadowRenderer.draw(at, av, { + lineCap: "butt", + lineWidth: this.gridLineWidth * 1.5, + offset: this.gridLineWidth * 0.75, + fill: false, + closePath: false, + }); + } + ao(aA, ak, az, ak, { strokeStyle: ah.borderColor }); + } + an = null; + } + al = null; + } + ah = null; + aB = null; + } + at.restore(); + function ao(aH, aG, aE, ax, aF) { + at.save(); + aF = aF || {}; + if (aF.lineWidth == null || aF.lineWidth != 0) { + L.extend(true, at, aF); + at.beginPath(); + at.moveTo(aH, aG); + at.lineTo(aE, ax); + at.stroke(); + at.restore(); + } + } + if (this.shadow) { + var av = [ + [this._left, this._bottom], + [this._right, this._bottom], + [this._right, this._top], + ]; + this.renderer.shadowRenderer.draw(at, av); + } + if (this.borderWidth != 0 && this.drawBorder) { + ao(this._left, this._top, this._right, this._top, { + lineCap: "round", + strokeStyle: aw.x2axis.borderColor, + lineWidth: aw.x2axis.borderWidth, + }); + ao(this._right, this._top, this._right, this._bottom, { + lineCap: "round", + strokeStyle: aw.y2axis.borderColor, + lineWidth: aw.y2axis.borderWidth, + }); + ao(this._right, this._bottom, this._left, this._bottom, { + lineCap: "round", + strokeStyle: aw.xaxis.borderColor, + lineWidth: aw.xaxis.borderWidth, + }); + ao(this._left, this._bottom, this._left, this._top, { + lineCap: "round", + strokeStyle: aw.yaxis.borderColor, + lineWidth: aw.yaxis.borderWidth, + }); + } + at.restore(); + at = null; + aw = null; + }; + L.jqplot.DivTitleRenderer = function () {}; + L.jqplot.DivTitleRenderer.prototype.init = function (ah) { + L.extend(true, this, ah); + }; + L.jqplot.DivTitleRenderer.prototype.draw = function () { + if (this._elem) { + this._elem.emptyForce(); + this._elem = null; + } + var ak = this.renderer; + var aj = document.createElement("div"); + this._elem = L(aj); + this._elem.addClass("jqplot-title"); + if (!this.text) { + this.show = false; + this._elem.height(0); + this._elem.width(0); + } else { + if (this.text) { + var ah; + if (this.color) { + ah = this.color; + } else { + if (this.textColor) { + ah = this.textColor; + } + } + var ai = { position: "absolute", top: "0px", left: "0px" }; + if (this._plotWidth) { + ai.width = this._plotWidth + "px"; + } + if (this.fontSize) { + ai.fontSize = this.fontSize; + } + if (typeof this.textAlign === "string") { + ai.textAlign = this.textAlign; + } else { + ai.textAlign = "center"; + } + if (ah) { + ai.color = ah; + } + if (this.paddingBottom) { + ai.paddingBottom = this.paddingBottom; + } + if (this.fontFamily) { + ai.fontFamily = this.fontFamily; + } + this._elem.css(ai); + if (this.escapeHtml) { + this._elem.text(this.text); + } else { + this._elem.html(this.text); + } + } + } + aj = null; + return this._elem; + }; + L.jqplot.DivTitleRenderer.prototype.pack = function () {}; + var r = 0.1; + L.jqplot.LinePattern = function (aw, aq) { + var ap = { + dotted: [r, L.jqplot.config.dotGapLength], + dashed: [L.jqplot.config.dashLength, L.jqplot.config.gapLength], + solid: null, + }; + if (typeof aq === "string") { + if (aq[0] === "." || aq[0] === "-") { + var ax = aq; + aq = []; + for (var ao = 0, al = ax.length; ao < al; ao++) { + if (ax[ao] === ".") { + aq.push(r); + } else { + if (ax[ao] === "-") { + aq.push(L.jqplot.config.dashLength); + } else { + continue; + } + } + aq.push(L.jqplot.config.gapLength); + } + } else { + aq = ap[aq]; + } + } + if (!(aq && aq.length)) { + return aw; + } + var ak = 0; + var ar = aq[0]; + var au = 0; + var at = 0; + var an = 0; + var ah = 0; + var av = function (ay, az) { + aw.moveTo(ay, az); + au = ay; + at = az; + an = ay; + ah = az; + }; + var aj = function (ay, aE) { + var aC = aw.lineWidth; + var aA = ay - au; + var az = aE - at; + var aB = Math.sqrt(aA * aA + az * az); + if (aB > 0 && aC > 0) { + aA /= aB; + az /= aB; + while (true) { + var aD = aC * ar; + if (aD < aB) { + au += aD * aA; + at += aD * az; + if ((ak & 1) == 0) { + aw.lineTo(au, at); + } else { + aw.moveTo(au, at); + } + aB -= aD; + ak++; + if (ak >= aq.length) { + ak = 0; + } + ar = aq[ak]; + } else { + au = ay; + at = aE; + if ((ak & 1) == 0) { + aw.lineTo(au, at); + } else { + aw.moveTo(au, at); + } + ar -= aB / aC; + break; + } + } + } + }; + var ai = function () { + aw.beginPath(); + }; + var am = function () { + aj(an, ah); + }; + return { moveTo: av, lineTo: aj, beginPath: ai, closePath: am }; + }; + L.jqplot.LineRenderer = function () { + this.shapeRenderer = new L.jqplot.ShapeRenderer(); + this.shadowRenderer = new L.jqplot.ShadowRenderer(); + }; + L.jqplot.LineRenderer.prototype.init = function (ai, an) { + ai = ai || {}; + this._type = "line"; + this.renderer.animation = { + show: false, + direction: "left", + speed: 2500, + _supported: true, + }; + this.renderer.smooth = false; + this.renderer.tension = null; + this.renderer.constrainSmoothing = true; + this.renderer._smoothedData = []; + this.renderer._smoothedPlotData = []; + this.renderer._hiBandGridData = []; + this.renderer._lowBandGridData = []; + this.renderer._hiBandSmoothedData = []; + this.renderer._lowBandSmoothedData = []; + this.renderer.bandData = []; + this.renderer.bands = { + show: false, + hiData: [], + lowData: [], + color: this.color, + showLines: false, + fill: true, + fillColor: null, + _min: null, + _max: null, + interval: "3%", + }; + var al = { + highlightMouseOver: ai.highlightMouseOver, + highlightMouseDown: ai.highlightMouseDown, + highlightColor: ai.highlightColor, + }; + delete ai.highlightMouseOver; + delete ai.highlightMouseDown; + delete ai.highlightColor; + L.extend(true, this.renderer, ai); + this.renderer.options = ai; + if ( + this.renderer.bandData.length > 1 && + (!ai.bands || ai.bands.show == null) + ) { + this.renderer.bands.show = true; + } else { + if ( + ai.bands && + ai.bands.show == null && + ai.bands.interval != null + ) { + this.renderer.bands.show = true; + } + } + if (this.fill) { + this.renderer.bands.show = false; + } + if (this.renderer.bands.show) { + this.renderer.initBands.call(this, this.renderer.options, an); + } + if (this._stack) { + this.renderer.smooth = false; + } + var am = { + lineJoin: this.lineJoin, + lineCap: this.lineCap, + fill: this.fill, + isarc: false, + strokeStyle: this.color, + fillStyle: this.fillColor, + lineWidth: this.lineWidth, + linePattern: this.linePattern, + closePath: this.fill, + }; + this.renderer.shapeRenderer.init(am); + var aj = ai.shadowOffset; + if (aj == null) { + if (this.lineWidth > 2.5) { + aj = + 1.25 * + (1 + + (Math.atan(this.lineWidth / 2.5) / 0.785398163 - 1) * + 0.6); + } else { + aj = (1.25 * Math.atan(this.lineWidth / 2.5)) / 0.785398163; + } + } + var ah = { + lineJoin: this.lineJoin, + lineCap: this.lineCap, + fill: this.fill, + isarc: false, + angle: this.shadowAngle, + offset: aj, + alpha: this.shadowAlpha, + depth: this.shadowDepth, + lineWidth: this.lineWidth, + linePattern: this.linePattern, + closePath: this.fill, + }; + this.renderer.shadowRenderer.init(ah); + this._areaPoints = []; + this._boundingBox = [[], []]; + if ((!this.isTrendline && this.fill) || this.renderer.bands.show) { + this.highlightMouseOver = true; + this.highlightMouseDown = false; + this.highlightColor = null; + if (al.highlightMouseDown && al.highlightMouseOver == null) { + al.highlightMouseOver = false; + } + L.extend(true, this, { + highlightMouseOver: al.highlightMouseOver, + highlightMouseDown: al.highlightMouseDown, + highlightColor: al.highlightColor, + }); + if (!this.highlightColor) { + var ak = this.renderer.bands.show + ? this.renderer.bands.fillColor + : this.fillColor; + this.highlightColor = L.jqplot.computeHighlightColors(ak); + } + if (this.highlighter) { + this.highlighter.show = false; + } + } + if (!this.isTrendline && an) { + an.plugins.lineRenderer = {}; + an.postInitHooks.addOnce(z); + an.postDrawHooks.addOnce(af); + an.eventListenerHooks.addOnce("jqplotMouseMove", h); + an.eventListenerHooks.addOnce("jqplotMouseDown", e); + an.eventListenerHooks.addOnce("jqplotMouseUp", ad); + an.eventListenerHooks.addOnce("jqplotClick", g); + an.eventListenerHooks.addOnce("jqplotRightClick", s); + } + }; + L.jqplot.LineRenderer.prototype.initBands = function (ak, av) { + var al = ak.bandData || []; + var an = this.renderer.bands; + an.hiData = []; + an.lowData = []; + var aB = this.data; + an._max = null; + an._min = null; + if (al.length == 2) { + if (L.isArray(al[0][0])) { + var ao; + var ah = 0, + ar = 0; + for (var aw = 0, at = al[0].length; aw < at; aw++) { + ao = al[0][aw]; + if ((ao[1] != null && ao[1] > an._max) || an._max == null) { + an._max = ao[1]; + } + if ((ao[1] != null && ao[1] < an._min) || an._min == null) { + an._min = ao[1]; + } + } + for (var aw = 0, at = al[1].length; aw < at; aw++) { + ao = al[1][aw]; + if ((ao[1] != null && ao[1] > an._max) || an._max == null) { + an._max = ao[1]; + ar = 1; + } + if ((ao[1] != null && ao[1] < an._min) || an._min == null) { + an._min = ao[1]; + ah = 1; + } + } + if (ar === ah) { + an.show = false; + } + an.hiData = al[ar]; + an.lowData = al[ah]; + } else { + if (al[0].length === aB.length && al[1].length === aB.length) { + var aj = al[0][0] > al[1][0] ? 0 : 1; + var aC = aj ? 0 : 1; + for (var aw = 0, at = aB.length; aw < at; aw++) { + an.hiData.push([aB[aw][0], al[aj][aw]]); + an.lowData.push([aB[aw][0], al[aC][aw]]); + } + } else { + an.show = false; + } + } + } else { + if (al.length > 2 && !L.isArray(al[0][0])) { + var aj = al[0][0] > al[0][1] ? 0 : 1; + var aC = aj ? 0 : 1; + for (var aw = 0, at = al.length; aw < at; aw++) { + an.hiData.push([aB[aw][0], al[aw][aj]]); + an.lowData.push([aB[aw][0], al[aw][aC]]); + } + } else { + var aq = an.interval; + var aA = null; + var az = null; + var ai = null; + var au = null; + if (L.isArray(aq)) { + aA = aq[0]; + az = aq[1]; + } else { + aA = aq; + } + if (isNaN(aA)) { + if (aA.charAt(aA.length - 1) === "%") { + ai = "multiply"; + aA = parseFloat(aA) / 100 + 1; + } + } else { + aA = parseFloat(aA); + ai = "add"; + } + if (az !== null && isNaN(az)) { + if (az.charAt(az.length - 1) === "%") { + au = "multiply"; + az = parseFloat(az) / 100 + 1; + } + } else { + if (az !== null) { + az = parseFloat(az); + au = "add"; + } + } + if (aA !== null) { + if (az === null) { + az = -aA; + au = ai; + if (au === "multiply") { + az += 2; + } + } + if (aA < az) { + var ax = aA; + aA = az; + az = ax; + ax = ai; + ai = au; + au = ax; + } + for (var aw = 0, at = aB.length; aw < at; aw++) { + switch (ai) { + case "add": + an.hiData.push([aB[aw][0], aB[aw][1] + aA]); + break; + case "multiply": + an.hiData.push([aB[aw][0], aB[aw][1] * aA]); + break; + } + switch (au) { + case "add": + an.lowData.push([aB[aw][0], aB[aw][1] + az]); + break; + case "multiply": + an.lowData.push([aB[aw][0], aB[aw][1] * az]); + break; + } + } + } else { + an.show = false; + } + } + } + var am = an.hiData; + var ap = an.lowData; + for (var aw = 0, at = am.length; aw < at; aw++) { + if ((am[aw][1] != null && am[aw][1] > an._max) || an._max == null) { + an._max = am[aw][1]; + } + } + for (var aw = 0, at = ap.length; aw < at; aw++) { + if ((ap[aw][1] != null && ap[aw][1] < an._min) || an._min == null) { + an._min = ap[aw][1]; + } + } + if (an.fillColor === null) { + var ay = L.jqplot.getColorComponents(an.color); + ay[3] = ay[3] * 0.5; + an.fillColor = + "rgba(" + + ay[0] + + ", " + + ay[1] + + ", " + + ay[2] + + ", " + + ay[3] + + ")"; + } + }; + function K(ai, ah) { + return (3.4182054 + ah) * Math.pow(ai, -0.3534992); + } + function n(aj, ai) { + var ah = Math.sqrt( + Math.pow(ai[0] - aj[0], 2) + Math.pow(ai[1] - aj[1], 2), + ); + return 5.7648 * Math.log(ah) + 7.4456; + } + function A(ah) { + var ai = (Math.exp(2 * ah) - 1) / (Math.exp(2 * ah) + 1); + return ai; + } + function J(aJ) { + var at = this.renderer.smooth; + var aD = this.canvas.getWidth(); + var an = this._xaxis.series_p2u; + var aG = this._yaxis.series_p2u; + var aF = null; + var am = null; + var az = aJ.length / aD; + var aj = []; + var ay = []; + if (!isNaN(parseFloat(at))) { + aF = parseFloat(at); + } else { + aF = K(az, 0.5); + } + var aw = []; + var ak = []; + for (var aE = 0, aA = aJ.length; aE < aA; aE++) { + aw.push(aJ[aE][1]); + ak.push(aJ[aE][0]); + } + function av(aK, aL) { + if (aK - aL == 0) { + return Math.pow(10, 10); + } else { + return aK - aL; + } + } + var ax, ar, aq, ap; + var ah = aJ.length - 1; + for (var al = 1, aB = aJ.length; al < aB; al++) { + var ai = []; + var au = []; + for (var aC = 0; aC < 2; aC++) { + var aE = al - 1 + aC; + if (aE == 0 || aE == ah) { + ai[aC] = Math.pow(10, 10); + } else { + if (aw[aE + 1] - aw[aE] == 0 || aw[aE] - aw[aE - 1] == 0) { + ai[aC] = 0; + } else { + if ( + (ak[aE + 1] - ak[aE]) / (aw[aE + 1] - aw[aE]) + + (ak[aE] - ak[aE - 1]) / (aw[aE] - aw[aE - 1]) == + 0 + ) { + ai[aC] = 0; + } else { + if ( + (aw[aE + 1] - aw[aE]) * (aw[aE] - aw[aE - 1]) < + 0 + ) { + ai[aC] = 0; + } else { + ai[aC] = + 2 / + (av(ak[aE + 1], ak[aE]) / + (aw[aE + 1] - aw[aE]) + + av(ak[aE], ak[aE - 1]) / + (aw[aE] - aw[aE - 1])); + } + } + } + } + } + if (al == 1) { + ai[0] = + ((3 / 2) * (aw[1] - aw[0])) / av(ak[1], ak[0]) - ai[1] / 2; + } else { + if (al == ah) { + ai[1] = + ((3 / 2) * (aw[ah] - aw[ah - 1])) / + av(ak[ah], ak[ah - 1]) - + ai[0] / 2; + } + } + au[0] = + (-2 * (ai[1] + 2 * ai[0])) / av(ak[al], ak[al - 1]) + + (6 * (aw[al] - aw[al - 1])) / + Math.pow(av(ak[al], ak[al - 1]), 2); + au[1] = + (2 * (2 * ai[1] + ai[0])) / av(ak[al], ak[al - 1]) - + (6 * (aw[al] - aw[al - 1])) / + Math.pow(av(ak[al], ak[al - 1]), 2); + ap = ((1 / 6) * (au[1] - au[0])) / av(ak[al], ak[al - 1]); + aq = + ((1 / 2) * (ak[al] * au[0] - ak[al - 1] * au[1])) / + av(ak[al], ak[al - 1]); + ar = + (aw[al] - + aw[al - 1] - + aq * (Math.pow(ak[al], 2) - Math.pow(ak[al - 1], 2)) - + ap * (Math.pow(ak[al], 3) - Math.pow(ak[al - 1], 3))) / + av(ak[al], ak[al - 1]); + ax = + aw[al - 1] - + ar * ak[al - 1] - + aq * Math.pow(ak[al - 1], 2) - + ap * Math.pow(ak[al - 1], 3); + var aI = (ak[al] - ak[al - 1]) / aF; + var aH, ao; + for (var aC = 0, aA = aF; aC < aA; aC++) { + aH = []; + ao = ak[al - 1] + aC * aI; + aH.push(ao); + aH.push( + ax + ar * ao + aq * Math.pow(ao, 2) + ap * Math.pow(ao, 3), + ); + aj.push(aH); + ay.push([an(aH[0]), aG(aH[1])]); + } + } + aj.push(aJ[aE]); + ay.push([an(aJ[aE][0]), aG(aJ[aE][1])]); + return [aj, ay]; + } + function F(ap) { + var ao = this.renderer.smooth; + var aU = this.renderer.tension; + var ah = this.canvas.getWidth(); + var aH = this._xaxis.series_p2u; + var aq = this._yaxis.series_p2u; + var aI = null; + var aJ = null; + var aT = null; + var aO = null; + var aM = null; + var at = null; + var aR = null; + var am = null; + var aK, aL, aD, aC, aA, ay; + var ak, ai, av, au; + var aB, az, aN; + var aw = []; + var aj = []; + var al = ap.length / ah; + var aS, ax, aF, aG, aE; + var ar = []; + var an = []; + if (!isNaN(parseFloat(ao))) { + aI = parseFloat(ao); + } else { + aI = K(al, 0.5); + } + if (!isNaN(parseFloat(aU))) { + aU = parseFloat(aU); + } + for (var aQ = 0, aP = ap.length - 1; aQ < aP; aQ++) { + if (aU === null) { + at = Math.abs( + (ap[aQ + 1][1] - ap[aQ][1]) / (ap[aQ + 1][0] - ap[aQ][0]), + ); + aS = 0.3; + ax = 0.6; + aF = (ax - aS) / 2; + aG = 2.5; + aE = -1.4; + am = at / aG + aE; + aO = aF * A(am) - aF * A(aE) + aS; + if (aQ > 0) { + aR = Math.abs( + (ap[aQ][1] - ap[aQ - 1][1]) / + (ap[aQ][0] - ap[aQ - 1][0]), + ); + } + am = aR / aG + aE; + aM = aF * A(am) - aF * A(aE) + aS; + aT = (aO + aM) / 2; + } else { + aT = aU; + } + for (aK = 0; aK < aI; aK++) { + aL = aK / aI; + aD = (1 + 2 * aL) * Math.pow(1 - aL, 2); + aC = aL * Math.pow(1 - aL, 2); + aA = Math.pow(aL, 2) * (3 - 2 * aL); + ay = Math.pow(aL, 2) * (aL - 1); + if (ap[aQ - 1]) { + ak = aT * (ap[aQ + 1][0] - ap[aQ - 1][0]); + ai = aT * (ap[aQ + 1][1] - ap[aQ - 1][1]); + } else { + ak = aT * (ap[aQ + 1][0] - ap[aQ][0]); + ai = aT * (ap[aQ + 1][1] - ap[aQ][1]); + } + if (ap[aQ + 2]) { + av = aT * (ap[aQ + 2][0] - ap[aQ][0]); + au = aT * (ap[aQ + 2][1] - ap[aQ][1]); + } else { + av = aT * (ap[aQ + 1][0] - ap[aQ][0]); + au = aT * (ap[aQ + 1][1] - ap[aQ][1]); + } + aB = aD * ap[aQ][0] + aA * ap[aQ + 1][0] + aC * ak + ay * av; + az = aD * ap[aQ][1] + aA * ap[aQ + 1][1] + aC * ai + ay * au; + aN = [aB, az]; + ar.push(aN); + an.push([aH(aB), aq(az)]); + } + } + ar.push(ap[aP]); + an.push([aH(ap[aP][0]), aq(ap[aP][1])]); + return [ar, an]; + } + L.jqplot.LineRenderer.prototype.setGridData = function (ap) { + var al = this._xaxis.series_u2p; + var ah = this._yaxis.series_u2p; + var am = this._plotData; + var aq = this._prevPlotData; + this.gridData = []; + this._prevGridData = []; + this.renderer._smoothedData = []; + this.renderer._smoothedPlotData = []; + this.renderer._hiBandGridData = []; + this.renderer._lowBandGridData = []; + this.renderer._hiBandSmoothedData = []; + this.renderer._lowBandSmoothedData = []; + var ak = this.renderer.bands; + var ai = false; + for (var an = 0, aj = am.length; an < aj; an++) { + if (am[an][0] != null && am[an][1] != null) { + this.gridData.push([ + al.call(this._xaxis, am[an][0]), + ah.call(this._yaxis, am[an][1]), + ]); + } else { + if (am[an][0] == null) { + ai = true; + this.gridData.push([null, ah.call(this._yaxis, am[an][1])]); + } else { + if (am[an][1] == null) { + ai = true; + this.gridData.push([ + al.call(this._xaxis, am[an][0]), + null, + ]); + } + } + } + if (aq[an] != null && aq[an][0] != null && aq[an][1] != null) { + this._prevGridData.push([ + al.call(this._xaxis, aq[an][0]), + ah.call(this._yaxis, aq[an][1]), + ]); + } else { + if (aq[an] != null && aq[an][0] == null) { + this._prevGridData.push([ + null, + ah.call(this._yaxis, aq[an][1]), + ]); + } else { + if ( + aq[an] != null && + aq[an][0] != null && + aq[an][1] == null + ) { + this._prevGridData.push([ + al.call(this._xaxis, aq[an][0]), + null, + ]); + } + } + } + } + if (ai) { + this.renderer.smooth = false; + if (this._type === "line") { + ak.show = false; + } + } + if (this._type === "line" && ak.show) { + for (var an = 0, aj = ak.hiData.length; an < aj; an++) { + this.renderer._hiBandGridData.push([ + al.call(this._xaxis, ak.hiData[an][0]), + ah.call(this._yaxis, ak.hiData[an][1]), + ]); + } + for (var an = 0, aj = ak.lowData.length; an < aj; an++) { + this.renderer._lowBandGridData.push([ + al.call(this._xaxis, ak.lowData[an][0]), + ah.call(this._yaxis, ak.lowData[an][1]), + ]); + } + } + if ( + this._type === "line" && + this.renderer.smooth && + this.gridData.length > 2 + ) { + var ao; + if (this.renderer.constrainSmoothing) { + ao = J.call(this, this.gridData); + this.renderer._smoothedData = ao[0]; + this.renderer._smoothedPlotData = ao[1]; + if (ak.show) { + ao = J.call(this, this.renderer._hiBandGridData); + this.renderer._hiBandSmoothedData = ao[0]; + ao = J.call(this, this.renderer._lowBandGridData); + this.renderer._lowBandSmoothedData = ao[0]; + } + ao = null; + } else { + ao = F.call(this, this.gridData); + this.renderer._smoothedData = ao[0]; + this.renderer._smoothedPlotData = ao[1]; + if (ak.show) { + ao = F.call(this, this.renderer._hiBandGridData); + this.renderer._hiBandSmoothedData = ao[0]; + ao = F.call(this, this.renderer._lowBandGridData); + this.renderer._lowBandSmoothedData = ao[0]; + } + ao = null; + } + } + }; + L.jqplot.LineRenderer.prototype.makeGridData = function (ao, aq) { + var am = this._xaxis.series_u2p; + var ah = this._yaxis.series_u2p; + var ar = []; + var aj = []; + this.renderer._smoothedData = []; + this.renderer._smoothedPlotData = []; + this.renderer._hiBandGridData = []; + this.renderer._lowBandGridData = []; + this.renderer._hiBandSmoothedData = []; + this.renderer._lowBandSmoothedData = []; + var al = this.renderer.bands; + var ai = false; + for (var an = 0; an < ao.length; an++) { + if (ao[an][0] != null && ao[an][1] != null) { + ar.push([ + am.call(this._xaxis, ao[an][0]), + ah.call(this._yaxis, ao[an][1]), + ]); + } else { + if (ao[an][0] == null) { + ai = true; + ar.push([null, ah.call(this._yaxis, ao[an][1])]); + } else { + if (ao[an][1] == null) { + ai = true; + ar.push([am.call(this._xaxis, ao[an][0]), null]); + } + } + } + } + if (ai) { + this.renderer.smooth = false; + if (this._type === "line") { + al.show = false; + } + } + if (this._type === "line" && al.show) { + for (var an = 0, ak = al.hiData.length; an < ak; an++) { + this.renderer._hiBandGridData.push([ + am.call(this._xaxis, al.hiData[an][0]), + ah.call(this._yaxis, al.hiData[an][1]), + ]); + } + for (var an = 0, ak = al.lowData.length; an < ak; an++) { + this.renderer._lowBandGridData.push([ + am.call(this._xaxis, al.lowData[an][0]), + ah.call(this._yaxis, al.lowData[an][1]), + ]); + } + } + if (this._type === "line" && this.renderer.smooth && ar.length > 2) { + var ap; + if (this.renderer.constrainSmoothing) { + ap = J.call(this, ar); + this.renderer._smoothedData = ap[0]; + this.renderer._smoothedPlotData = ap[1]; + if (al.show) { + ap = J.call(this, this.renderer._hiBandGridData); + this.renderer._hiBandSmoothedData = ap[0]; + ap = J.call(this, this.renderer._lowBandGridData); + this.renderer._lowBandSmoothedData = ap[0]; + } + ap = null; + } else { + ap = F.call(this, ar); + this.renderer._smoothedData = ap[0]; + this.renderer._smoothedPlotData = ap[1]; + if (al.show) { + ap = F.call(this, this.renderer._hiBandGridData); + this.renderer._hiBandSmoothedData = ap[0]; + ap = F.call(this, this.renderer._lowBandGridData); + this.renderer._lowBandSmoothedData = ap[0]; + } + ap = null; + } + } + return ar; + }; + L.jqplot.LineRenderer.prototype.draw = function (ax, aI, ai, aB) { + var aC; + var aq = L.extend(true, {}, ai); + var ak = aq.shadow != u ? aq.shadow : this.shadow; + var aJ = aq.showLine != u ? aq.showLine : this.showLine; + var aA = aq.fill != u ? aq.fill : this.fill; + var ah = aq.fillAndStroke != u ? aq.fillAndStroke : this.fillAndStroke; + var ar, ay, av, aE; + ax.save(); + if (aI.length) { + if (aJ) { + if (aA) { + if (this.fillToZero) { + var aF = this.negativeColor; + if (!this.useNegativeColors) { + aF = aq.fillStyle; + } + var ao = false; + var ap = aq.fillStyle; + if (ah) { + var aH = aI.slice(0); + } + if (this.index == 0 || !this._stack) { + var aw = []; + var aL = this.renderer.smooth + ? this.renderer._smoothedPlotData + : this._plotData; + this._areaPoints = []; + var aG = this._yaxis.series_u2p(this.fillToValue); + var aj = this._xaxis.series_u2p(this.fillToValue); + aq.closePath = true; + if (this.fillAxis == "y") { + aw.push([aI[0][0], aG]); + this._areaPoints.push([aI[0][0], aG]); + for (var aC = 0; aC < aI.length - 1; aC++) { + aw.push(aI[aC]); + this._areaPoints.push(aI[aC]); + if (aL[aC][1] * aL[aC + 1][1] <= 0) { + if (aL[aC][1] < 0) { + ao = true; + aq.fillStyle = aF; + } else { + ao = false; + aq.fillStyle = ap; + } + var an = + aI[aC][0] + + ((aI[aC + 1][0] - aI[aC][0]) * + (aG - aI[aC][1])) / + (aI[aC + 1][1] - aI[aC][1]); + aw.push([an, aG]); + this._areaPoints.push([an, aG]); + if (ak) { + this.renderer.shadowRenderer.draw( + ax, + aw, + aq, + ); + } + this.renderer.shapeRenderer.draw( + ax, + aw, + aq, + ); + aw = [[an, aG]]; + } + } + if (aL[aI.length - 1][1] < 0) { + ao = true; + aq.fillStyle = aF; + } else { + ao = false; + aq.fillStyle = ap; + } + aw.push(aI[aI.length - 1]); + this._areaPoints.push(aI[aI.length - 1]); + aw.push([aI[aI.length - 1][0], aG]); + this._areaPoints.push([ + aI[aI.length - 1][0], + aG, + ]); + } + if (ak) { + this.renderer.shadowRenderer.draw(ax, aw, aq); + } + this.renderer.shapeRenderer.draw(ax, aw, aq); + } else { + var au = this._prevGridData; + for (var aC = au.length; aC > 0; aC--) { + aI.push(au[aC - 1]); + } + if (ak) { + this.renderer.shadowRenderer.draw(ax, aI, aq); + } + this._areaPoints = aI; + this.renderer.shapeRenderer.draw(ax, aI, aq); + } + } else { + if (ah) { + var aH = aI.slice(0); + } + if (this.index == 0 || !this._stack) { + var al = ax.canvas.height; + aI.unshift([aI[0][0], al]); + var aD = aI.length; + aI.push([aI[aD - 1][0], al]); + } else { + var au = this._prevGridData; + for (var aC = au.length; aC > 0; aC--) { + aI.push(au[aC - 1]); + } + } + this._areaPoints = aI; + if (ak) { + this.renderer.shadowRenderer.draw(ax, aI, aq); + } + this.renderer.shapeRenderer.draw(ax, aI, aq); + } + if (ah) { + var az = L.extend(true, {}, aq, { + fill: false, + closePath: false, + }); + this.renderer.shapeRenderer.draw(ax, aH, az); + if (this.markerRenderer.show) { + if (this.renderer.smooth) { + aH = this.gridData; + } + for (aC = 0; aC < aH.length; aC++) { + this.markerRenderer.draw( + aH[aC][0], + aH[aC][1], + ax, + aq.markerOptions, + ); + } + } + } + } else { + if (this.renderer.bands.show) { + var am; + var aK = L.extend(true, {}, aq); + if (this.renderer.bands.showLines) { + am = this.renderer.smooth + ? this.renderer._hiBandSmoothedData + : this.renderer._hiBandGridData; + this.renderer.shapeRenderer.draw(ax, am, aq); + am = this.renderer.smooth + ? this.renderer._lowBandSmoothedData + : this.renderer._lowBandGridData; + this.renderer.shapeRenderer.draw(ax, am, aK); + } + if (this.renderer.bands.fill) { + if (this.renderer.smooth) { + am = this.renderer._hiBandSmoothedData.concat( + this.renderer._lowBandSmoothedData.reverse(), + ); + } else { + am = this.renderer._hiBandGridData.concat( + this.renderer._lowBandGridData.reverse(), + ); + } + this._areaPoints = am; + aK.closePath = true; + aK.fill = true; + aK.fillStyle = this.renderer.bands.fillColor; + this.renderer.shapeRenderer.draw(ax, am, aK); + } + } + if (ak) { + this.renderer.shadowRenderer.draw(ax, aI, aq); + } + this.renderer.shapeRenderer.draw(ax, aI, aq); + } + } + var ar = (av = ay = aE = null); + for (aC = 0; aC < this._areaPoints.length; aC++) { + var at = this._areaPoints[aC]; + if (ar > at[0] || ar == null) { + ar = at[0]; + } + if (aE < at[1] || aE == null) { + aE = at[1]; + } + if (av < at[0] || av == null) { + av = at[0]; + } + if (ay > at[1] || ay == null) { + ay = at[1]; + } + } + if (this.type === "line" && this.renderer.bands.show) { + aE = this._yaxis.series_u2p(this.renderer.bands._min); + ay = this._yaxis.series_u2p(this.renderer.bands._max); + } + this._boundingBox = [ + [ar, aE], + [av, ay], + ]; + if (this.markerRenderer.show && !aA) { + if (this.renderer.smooth) { + aI = this.gridData; + } + for (aC = 0; aC < aI.length; aC++) { + if (aI[aC][0] != null && aI[aC][1] != null) { + this.markerRenderer.draw( + aI[aC][0], + aI[aC][1], + ax, + aq.markerOptions, + ); + } + } + } + } + ax.restore(); + }; + L.jqplot.LineRenderer.prototype.drawShadow = function (ah, aj, ai) {}; + function z(ak, aj, ah) { + for (var ai = 0; ai < this.series.length; ai++) { + if (this.series[ai].renderer.constructor == L.jqplot.LineRenderer) { + if (this.series[ai].highlightMouseOver) { + this.series[ai].highlightMouseDown = false; + } + } + } + } + function af() { + if ( + this.plugins.lineRenderer && + this.plugins.lineRenderer.highlightCanvas + ) { + this.plugins.lineRenderer.highlightCanvas.resetCanvas(); + this.plugins.lineRenderer.highlightCanvas = null; + } + this.plugins.lineRenderer.highlightedSeriesIndex = null; + this.plugins.lineRenderer.highlightCanvas = + new L.jqplot.GenericCanvas(); + this.eventCanvas._elem.before( + this.plugins.lineRenderer.highlightCanvas.createElement( + this._gridPadding, + "jqplot-lineRenderer-highlight-canvas", + this._plotDimensions, + this, + ), + ); + this.plugins.lineRenderer.highlightCanvas.setContext(); + this.eventCanvas._elem.bind( + "mouseleave", + { plot: this }, + function (ah) { + aa(ah.data.plot); + }, + ); + } + function ac(an, am, ak, aj) { + var ai = an.series[am]; + var ah = an.plugins.lineRenderer.highlightCanvas; + ah._ctx.clearRect(0, 0, ah._ctx.canvas.width, ah._ctx.canvas.height); + ai._highlightedPoint = ak; + an.plugins.lineRenderer.highlightedSeriesIndex = am; + var al = { fillStyle: ai.highlightColor }; + if (ai.type === "line" && ai.renderer.bands.show) { + al.fill = true; + al.closePath = true; + } + ai.renderer.shapeRenderer.draw(ah._ctx, aj, al); + ah = null; + } + function aa(aj) { + var ah = aj.plugins.lineRenderer.highlightCanvas; + ah._ctx.clearRect(0, 0, ah._ctx.canvas.width, ah._ctx.canvas.height); + for (var ai = 0; ai < aj.series.length; ai++) { + aj.series[ai]._highlightedPoint = null; + } + aj.plugins.lineRenderer.highlightedSeriesIndex = null; + aj.target.trigger("jqplotDataUnhighlight"); + ah = null; + } + function h(al, ak, ao, an, am) { + if (an) { + var aj = [an.seriesIndex, an.pointIndex, an.data]; + var ai = jQuery.Event("jqplotDataMouseOver"); + ai.pageX = al.pageX; + ai.pageY = al.pageY; + am.target.trigger(ai, aj); + if ( + am.series[aj[0]].highlightMouseOver && + !(aj[0] == am.plugins.lineRenderer.highlightedSeriesIndex) + ) { + var ah = jQuery.Event("jqplotDataHighlight"); + ah.which = al.which; + ah.pageX = al.pageX; + ah.pageY = al.pageY; + am.target.trigger(ah, aj); + ac(am, an.seriesIndex, an.pointIndex, an.points); + } + } else { + if (an == null) { + aa(am); + } + } + } + function e(ak, aj, an, am, al) { + if (am) { + var ai = [am.seriesIndex, am.pointIndex, am.data]; + if ( + al.series[ai[0]].highlightMouseDown && + !(ai[0] == al.plugins.lineRenderer.highlightedSeriesIndex) + ) { + var ah = jQuery.Event("jqplotDataHighlight"); + ah.which = ak.which; + ah.pageX = ak.pageX; + ah.pageY = ak.pageY; + al.target.trigger(ah, ai); + ac(al, am.seriesIndex, am.pointIndex, am.points); + } + } else { + if (am == null) { + aa(al); + } + } + } + function ad(aj, ai, am, al, ak) { + var ah = ak.plugins.lineRenderer.highlightedSeriesIndex; + if (ah != null && ak.series[ah].highlightMouseDown) { + aa(ak); + } + } + function g(ak, aj, an, am, al) { + if (am) { + var ai = [am.seriesIndex, am.pointIndex, am.data]; + var ah = jQuery.Event("jqplotDataClick"); + ah.which = ak.which; + ah.pageX = ak.pageX; + ah.pageY = ak.pageY; + al.target.trigger(ah, ai); + } + } + function s(al, ak, ao, an, am) { + if (an) { + var aj = [an.seriesIndex, an.pointIndex, an.data]; + var ah = am.plugins.lineRenderer.highlightedSeriesIndex; + if (ah != null && am.series[ah].highlightMouseDown) { + aa(am); + } + var ai = jQuery.Event("jqplotDataRightClick"); + ai.which = al.which; + ai.pageX = al.pageX; + ai.pageY = al.pageY; + am.target.trigger(ai, aj); + } + } + L.jqplot.LinearAxisRenderer = function () {}; + L.jqplot.LinearAxisRenderer.prototype.init = function (ah) { + this.breakPoints = null; + this.breakTickLabel = "≈"; + this.drawBaseline = true; + this.baselineWidth = null; + this.baselineColor = null; + this.forceTickAt0 = false; + this.forceTickAt100 = false; + this.tickInset = 0; + this.minorTicks = 0; + this.alignTicks = false; + this._autoFormatString = ""; + this._overrideFormatString = false; + this._scalefact = 1; + L.extend(true, this, ah); + if (this.breakPoints) { + if (!L.isArray(this.breakPoints)) { + this.breakPoints = null; + } else { + if ( + this.breakPoints.length < 2 || + this.breakPoints[1] <= this.breakPoints[0] + ) { + this.breakPoints = null; + } + } + } + if (this.numberTicks != null && this.numberTicks < 2) { + this.numberTicks = 2; + } + this.resetDataBounds(); + }; + L.jqplot.LinearAxisRenderer.prototype.draw = function (ah, ao) { + if (this.show) { + this.renderer.createTicks.call(this, ao); + var an = 0; + var ai; + if (this._elem) { + this._elem.emptyForce(); + this._elem = null; + } + this._elem = L(document.createElement("div")); + this._elem.addClass("jqplot-axis jqplot-" + this.name); + this._elem.css("position", "absolute"); + if (this.name == "xaxis" || this.name == "x2axis") { + this._elem.width(this._plotDimensions.width); + } else { + this._elem.height(this._plotDimensions.height); + } + this.labelOptions.axis = this.name; + this._label = new this.labelRenderer(this.labelOptions); + if (this._label.show) { + var am = this._label.draw(ah, ao); + am.appendTo(this._elem); + am = null; + } + var al = this._ticks; + var ak; + for (var aj = 0; aj < al.length; aj++) { + ak = al[aj]; + if ( + ak.show && + ak.showLabel && + (!ak.isMinorTick || this.showMinorTicks) + ) { + this._elem.append(ak.draw(ah, ao)); + } + } + ak = null; + al = null; + } + return this._elem; + }; + L.jqplot.LinearAxisRenderer.prototype.reset = function () { + this.min = this._options.min; + this.max = this._options.max; + this.tickInterval = this._options.tickInterval; + this.numberTicks = this._options.numberTicks; + this._autoFormatString = ""; + if ( + this._overrideFormatString && + this.tickOptions && + this.tickOptions.formatString + ) { + this.tickOptions.formatString = ""; + } + }; + L.jqplot.LinearAxisRenderer.prototype.set = function () { + var ao = 0; + var aj; + var ai = 0; + var an = 0; + var ah = this._label == null ? false : this._label.show; + if (this.show) { + var am = this._ticks; + var al; + for (var ak = 0; ak < am.length; ak++) { + al = am[ak]; + if ( + !al._breakTick && + al.show && + al.showLabel && + (!al.isMinorTick || this.showMinorTicks) + ) { + if (this.name == "xaxis" || this.name == "x2axis") { + aj = al._elem.outerHeight(true); + } else { + aj = al._elem.outerWidth(true); + } + if (aj > ao) { + ao = aj; + } + } + } + al = null; + am = null; + if (ah) { + ai = this._label._elem.outerWidth(true); + an = this._label._elem.outerHeight(true); + } + if (this.name == "xaxis") { + ao = ao + an; + this._elem.css({ + height: ao + "px", + left: "0px", + bottom: "0px", + }); + } else { + if (this.name == "x2axis") { + ao = ao + an; + this._elem.css({ + height: ao + "px", + left: "0px", + top: "0px", + }); + } else { + if (this.name == "yaxis") { + ao = ao + ai; + this._elem.css({ + width: ao + "px", + left: "0px", + top: "0px", + }); + if ( + ah && + this._label.constructor == + L.jqplot.AxisLabelRenderer + ) { + this._label._elem.css("width", ai + "px"); + } + } else { + ao = ao + ai; + this._elem.css({ + width: ao + "px", + right: "0px", + top: "0px", + }); + if ( + ah && + this._label.constructor == + L.jqplot.AxisLabelRenderer + ) { + this._label._elem.css("width", ai + "px"); + } + } + } + } + } + }; + L.jqplot.LinearAxisRenderer.prototype.createTicks = function (aj) { + var aT = this._ticks; + var aK = this.ticks; + var az = this.name; + var aB = this._dataBounds; + var ah = + this.name.charAt(0) === "x" + ? this._plotDimensions.width + : this._plotDimensions.height; + var an; + var a6, aI; + var ap, ao; + var a4, a0; + var aH = this.min; + var a5 = this.max; + var aW = this.numberTicks; + var ba = this.tickInterval; + var am = 30; + this._scalefact = (Math.max(ah, am + 1) - am) / 300; + if (aK.length) { + for (a0 = 0; a0 < aK.length; a0++) { + var aO = aK[a0]; + var aU = new this.tickRenderer(this.tickOptions); + if (L.isArray(aO)) { + aU.value = aO[0]; + if (this.breakPoints) { + if (aO[0] == this.breakPoints[0]) { + aU.label = this.breakTickLabel; + aU._breakTick = true; + aU.showGridline = false; + aU.showMark = false; + } else { + if ( + aO[0] > this.breakPoints[0] && + aO[0] <= this.breakPoints[1] + ) { + aU.show = false; + aU.showGridline = false; + aU.label = aO[1]; + } else { + aU.label = aO[1]; + } + } + } else { + aU.label = aO[1]; + } + aU.setTick(aO[0], this.name); + this._ticks.push(aU); + } else { + if (L.isPlainObject(aO)) { + L.extend(true, aU, aO); + aU.axis = this.name; + this._ticks.push(aU); + } else { + aU.value = aO; + if (this.breakPoints) { + if (aO == this.breakPoints[0]) { + aU.label = this.breakTickLabel; + aU._breakTick = true; + aU.showGridline = false; + aU.showMark = false; + } else { + if ( + aO > this.breakPoints[0] && + aO <= this.breakPoints[1] + ) { + aU.show = false; + aU.showGridline = false; + } + } + } + aU.setTick(aO, this.name); + this._ticks.push(aU); + } + } + } + this.numberTicks = aK.length; + this.min = this._ticks[0].value; + this.max = this._ticks[this.numberTicks - 1].value; + this.tickInterval = (this.max - this.min) / (this.numberTicks - 1); + } else { + if (az == "xaxis" || az == "x2axis") { + ah = this._plotDimensions.width; + } else { + ah = this._plotDimensions.height; + } + var ax = this.numberTicks; + if (this.alignTicks) { + if (this.name === "x2axis" && aj.axes.xaxis.show) { + ax = aj.axes.xaxis.numberTicks; + } else { + if ( + this.name.charAt(0) === "y" && + this.name !== "yaxis" && + this.name !== "yMidAxis" && + aj.axes.yaxis.show + ) { + ax = aj.axes.yaxis.numberTicks; + } + } + } + a6 = this.min != null ? this.min : aB.min; + aI = this.max != null ? this.max : aB.max; + var av = aI - a6; + var aS, ay; + var at; + if (this.tickOptions == null || !this.tickOptions.formatString) { + this._overrideFormatString = true; + } + if ( + this.min == null || + (this.max == null && + this.tickInterval == null && + !this.autoscale) + ) { + if (this.forceTickAt0) { + if (a6 > 0) { + a6 = 0; + } + if (aI < 0) { + aI = 0; + } + } + if (this.forceTickAt100) { + if (a6 > 100) { + a6 = 100; + } + if (aI < 100) { + aI = 100; + } + } + var aE = false, + a1 = false; + if (this.min != null) { + aE = true; + } else { + if (this.max != null) { + a1 = true; + } + } + var aP = L.jqplot.LinearTickGenerator( + a6, + aI, + this._scalefact, + ax, + aE, + a1, + ); + var aw = this.min != null ? a6 : a6 + av * (this.padMin - 1); + var aQ = this.max != null ? aI : aI - av * (this.padMax - 1); + if (a6 < aw || aI > aQ) { + aw = this.min != null ? a6 : a6 - av * (this.padMin - 1); + aQ = this.max != null ? aI : aI + av * (this.padMax - 1); + aP = L.jqplot.LinearTickGenerator( + aw, + aQ, + this._scalefact, + ax, + aE, + a1, + ); + } + this.min = aP[0]; + this.max = aP[1]; + this.numberTicks = aP[2]; + this._autoFormatString = aP[3]; + this.tickInterval = aP[4]; + } else { + if (a6 == aI) { + var ai = 0.05; + if (a6 > 0) { + ai = Math.max(Math.log(a6) / Math.LN10, 0.05); + } + a6 -= ai; + aI += ai; + } + if (this.autoscale && this.min == null && this.max == null) { + var ak, al, ar; + var aC = false; + var aN = false; + var aA = { + min: null, + max: null, + average: null, + stddev: null, + }; + for (var a0 = 0; a0 < this._series.length; a0++) { + var aV = this._series[a0]; + var aD = + aV.fillAxis == "x" + ? aV._xaxis.name + : aV._yaxis.name; + if (this.name == aD) { + var aR = aV._plotValues[aV.fillAxis]; + var aG = aR[0]; + var a2 = aR[0]; + for (var aZ = 1; aZ < aR.length; aZ++) { + if (aR[aZ] < aG) { + aG = aR[aZ]; + } else { + if (aR[aZ] > a2) { + a2 = aR[aZ]; + } + } + } + var au = (a2 - aG) / a2; + if ( + aV.renderer.constructor == L.jqplot.BarRenderer + ) { + if (aG >= 0 && (aV.fillToZero || au > 0.1)) { + aC = true; + } else { + aC = false; + if ( + aV.fill && + aV.fillToZero && + aG < 0 && + a2 > 0 + ) { + aN = true; + } else { + aN = false; + } + } + } else { + if (aV.fill) { + if ( + aG >= 0 && + (aV.fillToZero || au > 0.1) + ) { + aC = true; + } else { + if (aG < 0 && a2 > 0 && aV.fillToZero) { + aC = false; + aN = true; + } else { + aC = false; + aN = false; + } + } + } else { + if (aG < 0) { + aC = false; + } + } + } + } + } + if (aC) { + this.numberTicks = + 2 + + Math.ceil( + (ah - (this.tickSpacing - 1)) / + this.tickSpacing, + ); + this.min = 0; + aH = 0; + al = aI / (this.numberTicks - 1); + at = Math.pow( + 10, + Math.abs(Math.floor(Math.log(al) / Math.LN10)), + ); + if (al / at == parseInt(al / at, 10)) { + al += at; + } + this.tickInterval = Math.ceil(al / at) * at; + this.max = this.tickInterval * (this.numberTicks - 1); + } else { + if (aN) { + this.numberTicks = + 2 + + Math.ceil( + (ah - (this.tickSpacing - 1)) / + this.tickSpacing, + ); + var aJ = Math.ceil( + (Math.abs(a6) / av) * (this.numberTicks - 1), + ); + var a9 = this.numberTicks - 1 - aJ; + al = Math.max(Math.abs(a6 / aJ), Math.abs(aI / a9)); + at = Math.pow( + 10, + Math.abs(Math.floor(Math.log(al) / Math.LN10)), + ); + this.tickInterval = Math.ceil(al / at) * at; + this.max = this.tickInterval * a9; + this.min = -this.tickInterval * aJ; + } else { + if (this.numberTicks == null) { + if (this.tickInterval) { + this.numberTicks = + 3 + Math.ceil(av / this.tickInterval); + } else { + this.numberTicks = + 2 + + Math.ceil( + (ah - (this.tickSpacing - 1)) / + this.tickSpacing, + ); + } + } + if (this.tickInterval == null) { + al = av / (this.numberTicks - 1); + if (al < 1) { + at = Math.pow( + 10, + Math.abs( + Math.floor( + Math.log(al) / Math.LN10, + ), + ), + ); + } else { + at = 1; + } + this.tickInterval = + Math.ceil(al * at * this.pad) / at; + } else { + at = 1 / this.tickInterval; + } + ak = this.tickInterval * (this.numberTicks - 1); + ar = (ak - av) / 2; + if (this.min == null) { + this.min = Math.floor(at * (a6 - ar)) / at; + } + if (this.max == null) { + this.max = this.min + ak; + } + } + } + var aF = L.jqplot.getSignificantFigures(this.tickInterval); + var aM; + if (aF.digitsLeft >= aF.significantDigits) { + aM = "%d"; + } else { + var at = Math.max(0, 5 - aF.digitsLeft); + at = Math.min(at, aF.digitsRight); + aM = "%." + at + "f"; + } + this._autoFormatString = aM; + } else { + aS = + this.min != null + ? this.min + : a6 - av * (this.padMin - 1); + ay = + this.max != null + ? this.max + : aI + av * (this.padMax - 1); + av = ay - aS; + if (this.numberTicks == null) { + if (this.tickInterval != null) { + this.numberTicks = + Math.ceil((ay - aS) / this.tickInterval) + 1; + } else { + if (ah > 100) { + this.numberTicks = parseInt( + 3 + (ah - 100) / 75, + 10, + ); + } else { + this.numberTicks = 2; + } + } + } + if (this.tickInterval == null) { + this.tickInterval = av / (this.numberTicks - 1); + } + if (this.max == null) { + ay = aS + this.tickInterval * (this.numberTicks - 1); + } + if (this.min == null) { + aS = ay - this.tickInterval * (this.numberTicks - 1); + } + var aF = L.jqplot.getSignificantFigures(this.tickInterval); + var aM; + if (aF.digitsLeft >= aF.significantDigits) { + aM = "%d"; + } else { + var at = Math.max(0, 5 - aF.digitsLeft); + at = Math.min(at, aF.digitsRight); + aM = "%." + at + "f"; + } + this._autoFormatString = aM; + this.min = aS; + this.max = ay; + } + if ( + this.renderer.constructor == L.jqplot.LinearAxisRenderer && + this._autoFormatString == "" + ) { + av = this.max - this.min; + var a7 = new this.tickRenderer(this.tickOptions); + var aL = + a7.formatString || + L.jqplot.config.defaultTickFormatString; + var aL = aL.match(L.jqplot.sprintf.regex)[0]; + var a3 = 0; + if (aL) { + if (aL.search(/[fFeEgGpP]/) > -1) { + var aY = aL.match(/\%\.(\d{0,})?[eEfFgGpP]/); + if (aY) { + a3 = parseInt(aY[1], 10); + } else { + a3 = 6; + } + } else { + if (aL.search(/[di]/) > -1) { + a3 = 0; + } + } + var aq = Math.pow(10, -a3); + if (this.tickInterval < aq) { + if (aW == null && ba == null) { + this.tickInterval = aq; + if (a5 == null && aH == null) { + this.min = + Math.floor(this._dataBounds.min / aq) * + aq; + if (this.min == this._dataBounds.min) { + this.min = + this._dataBounds.min - + this.tickInterval; + } + this.max = + Math.ceil(this._dataBounds.max / aq) * + aq; + if (this.max == this._dataBounds.max) { + this.max = + this._dataBounds.max + + this.tickInterval; + } + var aX = + (this.max - this.min) / + this.tickInterval; + aX = aX.toFixed(11); + aX = Math.ceil(aX); + this.numberTicks = aX + 1; + } else { + if (a5 == null) { + var aX = + (this._dataBounds.max - this.min) / + this.tickInterval; + aX = aX.toFixed(11); + this.numberTicks = Math.ceil(aX) + 2; + this.max = + this.min + + this.tickInterval * + (this.numberTicks - 1); + } else { + if (aH == null) { + var aX = + (this.max - + this._dataBounds.min) / + this.tickInterval; + aX = aX.toFixed(11); + this.numberTicks = + Math.ceil(aX) + 2; + this.min = + this.max - + this.tickInterval * + (this.numberTicks - 1); + } else { + this.numberTicks = + Math.ceil( + (a5 - aH) / + this.tickInterval, + ) + 1; + this.min = + Math.floor( + aH * Math.pow(10, a3), + ) / Math.pow(10, a3); + this.max = + Math.ceil( + a5 * Math.pow(10, a3), + ) / Math.pow(10, a3); + this.numberTicks = + Math.ceil( + (this.max - this.min) / + this.tickInterval, + ) + 1; + } + } + } + } + } + } + } + } + if (this._overrideFormatString && this._autoFormatString != "") { + this.tickOptions = this.tickOptions || {}; + this.tickOptions.formatString = this._autoFormatString; + } + var aU, a8; + for (var a0 = 0; a0 < this.numberTicks; a0++) { + a4 = this.min + a0 * this.tickInterval; + aU = new this.tickRenderer(this.tickOptions); + aU.setTick(a4, this.name); + this._ticks.push(aU); + if (a0 < this.numberTicks - 1) { + for (var aZ = 0; aZ < this.minorTicks; aZ++) { + a4 += this.tickInterval / (this.minorTicks + 1); + a8 = L.extend(true, {}, this.tickOptions, { + name: this.name, + value: a4, + label: "", + isMinorTick: true, + }); + aU = new this.tickRenderer(a8); + this._ticks.push(aU); + } + } + aU = null; + } + } + if (this.tickInset) { + this.min = this.min - this.tickInset * this.tickInterval; + this.max = this.max + this.tickInset * this.tickInterval; + } + aT = null; + }; + L.jqplot.LinearAxisRenderer.prototype.resetTickValues = function (aj) { + if (L.isArray(aj) && aj.length == this._ticks.length) { + var ai; + for (var ah = 0; ah < aj.length; ah++) { + ai = this._ticks[ah]; + ai.value = aj[ah]; + ai.label = ai.formatter(ai.formatString, aj[ah]); + ai.label = ai.prefix + ai.label; + ai._elem.html(ai.label); + } + ai = null; + this.min = L.jqplot.arrayMin(aj); + this.max = L.jqplot.arrayMax(aj); + this.pack(); + } + }; + L.jqplot.LinearAxisRenderer.prototype.pack = function (aj, ai) { + aj = aj || {}; + ai = ai || this._offsets; + var ay = this._ticks; + var au = this.max; + var at = this.min; + var ao = ai.max; + var am = ai.min; + var aq = this._label == null ? false : this._label.show; + for (var ar in aj) { + this._elem.css(ar, aj[ar]); + } + this._offsets = ai; + var ak = ao - am; + var al = au - at; + if (this.breakPoints) { + al = al - this.breakPoints[1] + this.breakPoints[0]; + this.p2u = function (aA) { + return ((aA - am) * al) / ak + at; + }; + this.u2p = function (aA) { + if (aA > this.breakPoints[0] && aA < this.breakPoints[1]) { + aA = this.breakPoints[0]; + } + if (aA <= this.breakPoints[0]) { + return ((aA - at) * ak) / al + am; + } else { + return ( + ((aA - this.breakPoints[1] + this.breakPoints[0] - at) * + ak) / + al + + am + ); + } + }; + if (this.name.charAt(0) == "x") { + this.series_u2p = function (aA) { + if (aA > this.breakPoints[0] && aA < this.breakPoints[1]) { + aA = this.breakPoints[0]; + } + if (aA <= this.breakPoints[0]) { + return ((aA - at) * ak) / al; + } else { + return ( + ((aA - + this.breakPoints[1] + + this.breakPoints[0] - + at) * + ak) / + al + ); + } + }; + this.series_p2u = function (aA) { + return (aA * al) / ak + at; + }; + } else { + this.series_u2p = function (aA) { + if (aA > this.breakPoints[0] && aA < this.breakPoints[1]) { + aA = this.breakPoints[0]; + } + if (aA >= this.breakPoints[1]) { + return ((aA - au) * ak) / al; + } else { + return ( + ((aA + + this.breakPoints[1] - + this.breakPoints[0] - + au) * + ak) / + al + ); + } + }; + this.series_p2u = function (aA) { + return (aA * al) / ak + au; + }; + } + } else { + this.p2u = function (aA) { + return ((aA - am) * al) / ak + at; + }; + this.u2p = function (aA) { + return ((aA - at) * ak) / al + am; + }; + if (this.name == "xaxis" || this.name == "x2axis") { + this.series_u2p = function (aA) { + return ((aA - at) * ak) / al; + }; + this.series_p2u = function (aA) { + return (aA * al) / ak + at; + }; + } else { + this.series_u2p = function (aA) { + return ((aA - au) * ak) / al; + }; + this.series_p2u = function (aA) { + return (aA * al) / ak + au; + }; + } + } + if (this.show) { + if (this.name == "xaxis" || this.name == "x2axis") { + for (var av = 0; av < ay.length; av++) { + var ap = ay[av]; + if (ap.show && ap.showLabel) { + var ah; + if ( + ap.constructor == L.jqplot.CanvasAxisTickRenderer && + ap.angle + ) { + var ax = this.name == "xaxis" ? 1 : -1; + switch (ap.labelPosition) { + case "auto": + if (ax * ap.angle < 0) { + ah = + -ap.getWidth() + + (ap._textRenderer.height * + Math.sin( + -ap._textRenderer.angle, + )) / + 2; + } else { + ah = + (-ap._textRenderer.height * + Math.sin( + ap._textRenderer.angle, + )) / + 2; + } + break; + case "end": + ah = + -ap.getWidth() + + (ap._textRenderer.height * + Math.sin(-ap._textRenderer.angle)) / + 2; + break; + case "start": + ah = + (-ap._textRenderer.height * + Math.sin(ap._textRenderer.angle)) / + 2; + break; + case "middle": + ah = + -ap.getWidth() / 2 + + (ap._textRenderer.height * + Math.sin(-ap._textRenderer.angle)) / + 2; + break; + default: + ah = + -ap.getWidth() / 2 + + (ap._textRenderer.height * + Math.sin(-ap._textRenderer.angle)) / + 2; + break; + } + } else { + ah = -ap.getWidth() / 2; + } + var az = this.u2p(ap.value) + ah + "px"; + ap._elem.css("left", az); + ap.pack(); + } + } + if (aq) { + var an = this._label._elem.outerWidth(true); + this._label._elem.css("left", am + ak / 2 - an / 2 + "px"); + if (this.name == "xaxis") { + this._label._elem.css("bottom", "0px"); + } else { + this._label._elem.css("top", "0px"); + } + this._label.pack(); + } + } else { + for (var av = 0; av < ay.length; av++) { + var ap = ay[av]; + if (ap.show && ap.showLabel) { + var ah; + if ( + ap.constructor == L.jqplot.CanvasAxisTickRenderer && + ap.angle + ) { + var ax = this.name == "yaxis" ? 1 : -1; + switch (ap.labelPosition) { + case "auto": + case "end": + if (ax * ap.angle < 0) { + ah = + (-ap._textRenderer.height * + Math.cos( + -ap._textRenderer.angle, + )) / + 2; + } else { + ah = + -ap.getHeight() + + (ap._textRenderer.height * + Math.cos( + ap._textRenderer.angle, + )) / + 2; + } + break; + case "start": + if (ap.angle > 0) { + ah = + (-ap._textRenderer.height * + Math.cos( + -ap._textRenderer.angle, + )) / + 2; + } else { + ah = + -ap.getHeight() + + (ap._textRenderer.height * + Math.cos( + ap._textRenderer.angle, + )) / + 2; + } + break; + case "middle": + ah = -ap.getHeight() / 2; + break; + default: + ah = -ap.getHeight() / 2; + break; + } + } else { + ah = -ap.getHeight() / 2; + } + var az = this.u2p(ap.value) + ah + "px"; + ap._elem.css("top", az); + ap.pack(); + } + } + if (aq) { + var aw = this._label._elem.outerHeight(true); + this._label._elem.css("top", ao - ak / 2 - aw / 2 + "px"); + if (this.name == "yaxis") { + this._label._elem.css("left", "0px"); + } else { + this._label._elem.css("right", "0px"); + } + this._label.pack(); + } + } + } + ay = null; + }; + function i(ai) { + var ah; + ai = Math.abs(ai); + if (ai >= 10) { + ah = "%d"; + } else { + if (ai > 1) { + if (ai === parseInt(ai, 10)) { + ah = "%d"; + } else { + ah = "%.1f"; + } + } else { + var aj = -Math.floor(Math.log(ai) / Math.LN10); + ah = "%." + aj + "f"; + } + } + return ah; + } + var b = [0.1, 0.2, 0.3, 0.4, 0.5, 0.8, 1, 2, 3, 4, 5]; + var c = function (ai) { + var ah = b.indexOf(ai); + if (ah > 0) { + return b[ah - 1]; + } else { + return b[b.length - 1] / 100; + } + }; + var k = function (ai) { + var ah = b.indexOf(ai); + if (ah < b.length - 1) { + return b[ah + 1]; + } else { + return b[0] * 100; + } + }; + function d(al, au, at) { + var aq = Math.floor(at / 2); + var ai = Math.ceil(at * 1.5); + var ak = Number.MAX_VALUE; + var ah = au - al; + var ax; + var ap; + var ar; + var ay = L.jqplot.getSignificantFigures; + var aw; + var an; + var ao; + var av; + for (var am = 0, aj = ai - aq + 1; am < aj; am++) { + ao = aq + am; + ax = ah / (ao - 1); + ap = ay(ax); + ax = Math.abs(at - ao) + ap.digitsRight; + if (ax < ak) { + ak = ax; + ar = ao; + av = ap.digitsRight; + } else { + if (ax === ak) { + if (ap.digitsRight < av) { + ar = ao; + av = ap.digitsRight; + } + } + } + } + aw = Math.max(av, Math.max(ay(al).digitsRight, ay(au).digitsRight)); + if (aw === 0) { + an = "%d"; + } else { + an = "%." + aw + "f"; + } + ax = ah / (ar - 1); + return [al, au, ar, an, ax]; + } + function W(ai, al) { + al = al || 7; + var ak = ai / (al - 1); + var aj = Math.pow(10, Math.floor(Math.log(ak) / Math.LN10)); + var am = ak / aj; + var ah; + if (aj < 1) { + if (am > 5) { + ah = 10 * aj; + } else { + if (am > 2) { + ah = 5 * aj; + } else { + if (am > 1) { + ah = 2 * aj; + } else { + ah = aj; + } + } + } + } else { + if (am > 5) { + ah = 10 * aj; + } else { + if (am > 4) { + ah = 5 * aj; + } else { + if (am > 3) { + ah = 4 * aj; + } else { + if (am > 2) { + ah = 3 * aj; + } else { + if (am > 1) { + ah = 2 * aj; + } else { + ah = aj; + } + } + } + } + } + } + return ah; + } + function Q(ai, ah) { + ah = ah || 1; + var ak = Math.floor(Math.log(ai) / Math.LN10); + var am = Math.pow(10, ak); + var al = ai / am; + var aj; + al = al / ah; + if (al <= 0.38) { + aj = 0.1; + } else { + if (al <= 1.6) { + aj = 0.2; + } else { + if (al <= 4) { + aj = 0.5; + } else { + if (al <= 8) { + aj = 1; + } else { + if (al <= 16) { + aj = 2; + } else { + aj = 5; + } + } + } + } + } + return aj * am; + } + function x(aj, ai) { + var al = Math.floor(Math.log(aj) / Math.LN10); + var an = Math.pow(10, al); + var am = aj / an; + var ah; + var ak; + am = am / ai; + if (am <= 0.38) { + ak = 0.1; + } else { + if (am <= 1.6) { + ak = 0.2; + } else { + if (am <= 4) { + ak = 0.5; + } else { + if (am <= 8) { + ak = 1; + } else { + if (am <= 16) { + ak = 2; + } else { + ak = 5; + } + } + } + } + } + ah = ak * an; + return [ah, ak, an]; + } + L.jqplot.LinearTickGenerator = function (an, aq, aj, ak, ao, ar) { + ao = ao === null ? false : ao; + ar = ar === null || ao ? false : ar; + if (an === aq) { + aq = aq ? 0 : 1; + } + aj = aj || 1; + if (aq < an) { + var at = aq; + aq = an; + an = at; + } + var ai = []; + var aw = Q(aq - an, aj); + var av = L.jqplot.getSignificantFigures; + if (ak == null) { + if (!ao && !ar) { + ai[0] = Math.floor(an / aw) * aw; + ai[1] = Math.ceil(aq / aw) * aw; + ai[2] = Math.round((ai[1] - ai[0]) / aw + 1); + ai[3] = i(aw); + ai[4] = aw; + } else { + if (ao) { + ai[0] = an; + ai[2] = Math.ceil((aq - an) / aw + 1); + ai[1] = an + (ai[2] - 1) * aw; + var au = av(an).digitsRight; + var ap = av(aw).digitsRight; + if (au < ap) { + ai[3] = i(aw); + } else { + ai[3] = "%." + au + "f"; + } + ai[4] = aw; + } else { + if (ar) { + ai[1] = aq; + ai[2] = Math.ceil((aq - an) / aw + 1); + ai[0] = aq - (ai[2] - 1) * aw; + var al = av(aq).digitsRight; + var ap = av(aw).digitsRight; + if (al < ap) { + ai[3] = i(aw); + } else { + ai[3] = "%." + al + "f"; + } + ai[4] = aw; + } + } + } + } else { + var am = []; + am[0] = Math.floor(an / aw) * aw; + am[1] = Math.ceil(aq / aw) * aw; + am[2] = Math.round((am[1] - am[0]) / aw + 1); + am[3] = i(aw); + am[4] = aw; + if (am[2] === ak) { + ai = am; + } else { + var ah = W(am[1] - am[0], ak); + ai[0] = am[0]; + ai[2] = ak; + ai[4] = ah; + ai[3] = i(ah); + ai[1] = ai[0] + (ai[2] - 1) * ai[4]; + } + } + return ai; + }; + L.jqplot.LinearTickGenerator.bestLinearInterval = Q; + L.jqplot.LinearTickGenerator.bestInterval = W; + L.jqplot.LinearTickGenerator.bestLinearComponents = x; + L.jqplot.LinearTickGenerator.bestConstrainedInterval = d; + L.jqplot.MarkerRenderer = function (ah) { + this.show = true; + this.style = "filledCircle"; + this.lineWidth = 2; + this.size = 9; + this.color = "#666666"; + this.shadow = true; + this.shadowAngle = 45; + this.shadowOffset = 1; + this.shadowDepth = 3; + this.shadowAlpha = "0.07"; + this.shadowRenderer = new L.jqplot.ShadowRenderer(); + this.shapeRenderer = new L.jqplot.ShapeRenderer(); + L.extend(true, this, ah); + }; + L.jqplot.MarkerRenderer.prototype.init = function (ah) { + L.extend(true, this, ah); + var aj = { + angle: this.shadowAngle, + offset: this.shadowOffset, + alpha: this.shadowAlpha, + lineWidth: this.lineWidth, + depth: this.shadowDepth, + closePath: true, + }; + if (this.style.indexOf("filled") != -1) { + aj.fill = true; + } + if (this.style.indexOf("ircle") != -1) { + aj.isarc = true; + aj.closePath = false; + } + this.shadowRenderer.init(aj); + var ai = { + fill: false, + isarc: false, + strokeStyle: this.color, + fillStyle: this.color, + lineWidth: this.lineWidth, + closePath: true, + }; + if (this.style.indexOf("filled") != -1) { + ai.fill = true; + } + if (this.style.indexOf("ircle") != -1) { + ai.isarc = true; + ai.closePath = false; + } + this.shapeRenderer.init(ai); + }; + L.jqplot.MarkerRenderer.prototype.drawDiamond = function ( + aj, + ai, + am, + al, + ao, + ) { + var ah = 1.2; + var ap = this.size / 2 / ah; + var an = (this.size / 2) * ah; + var ak = [ + [aj - ap, ai], + [aj, ai + an], + [aj + ap, ai], + [aj, ai - an], + ]; + if (this.shadow) { + this.shadowRenderer.draw(am, ak); + } + this.shapeRenderer.draw(am, ak, ao); + }; + L.jqplot.MarkerRenderer.prototype.drawPlus = function (ak, aj, an, am, aq) { + var ai = 1; + var ar = (this.size / 2) * ai; + var ao = (this.size / 2) * ai; + var ap = [ + [ak, aj - ao], + [ak, aj + ao], + ]; + var al = [ + [ak + ar, aj], + [ak - ar, aj], + ]; + var ah = L.extend(true, {}, this.options, { closePath: false }); + if (this.shadow) { + this.shadowRenderer.draw(an, ap, { closePath: false }); + this.shadowRenderer.draw(an, al, { closePath: false }); + } + this.shapeRenderer.draw(an, ap, ah); + this.shapeRenderer.draw(an, al, ah); + }; + L.jqplot.MarkerRenderer.prototype.drawX = function (ak, aj, an, am, aq) { + var ai = 1; + var ar = (this.size / 2) * ai; + var ao = (this.size / 2) * ai; + var ah = L.extend(true, {}, this.options, { closePath: false }); + var ap = [ + [ak - ar, aj - ao], + [ak + ar, aj + ao], + ]; + var al = [ + [ak - ar, aj + ao], + [ak + ar, aj - ao], + ]; + if (this.shadow) { + this.shadowRenderer.draw(an, ap, { closePath: false }); + this.shadowRenderer.draw(an, al, { closePath: false }); + } + this.shapeRenderer.draw(an, ap, ah); + this.shapeRenderer.draw(an, al, ah); + }; + L.jqplot.MarkerRenderer.prototype.drawDash = function (aj, ai, am, al, ao) { + var ah = 1; + var ap = (this.size / 2) * ah; + var an = (this.size / 2) * ah; + var ak = [ + [aj - ap, ai], + [aj + ap, ai], + ]; + if (this.shadow) { + this.shadowRenderer.draw(am, ak); + } + this.shapeRenderer.draw(am, ak, ao); + }; + L.jqplot.MarkerRenderer.prototype.drawLine = function (am, al, ah, ak, ai) { + var aj = [am, al]; + if (this.shadow) { + this.shadowRenderer.draw(ah, aj); + } + this.shapeRenderer.draw(ah, aj, ai); + }; + L.jqplot.MarkerRenderer.prototype.drawSquare = function ( + aj, + ai, + am, + al, + ao, + ) { + var ah = 1; + var ap = this.size / 2 / ah; + var an = (this.size / 2) * ah; + var ak = [ + [aj - ap, ai - an], + [aj - ap, ai + an], + [aj + ap, ai + an], + [aj + ap, ai - an], + ]; + if (this.shadow) { + this.shadowRenderer.draw(am, ak); + } + this.shapeRenderer.draw(am, ak, ao); + }; + L.jqplot.MarkerRenderer.prototype.drawCircle = function ( + ai, + ao, + ak, + an, + al, + ) { + var ah = this.size / 2; + var aj = 2 * Math.PI; + var am = [ai, ao, ah, 0, aj, true]; + if (this.shadow) { + this.shadowRenderer.draw(ak, am); + } + this.shapeRenderer.draw(ak, am, al); + }; + L.jqplot.MarkerRenderer.prototype.draw = function (ah, ak, ai, aj) { + aj = aj || {}; + if (aj.show == null || aj.show != false) { + if (aj.color && !aj.fillStyle) { + aj.fillStyle = aj.color; + } + if (aj.color && !aj.strokeStyle) { + aj.strokeStyle = aj.color; + } + switch (this.style) { + case "diamond": + this.drawDiamond(ah, ak, ai, false, aj); + break; + case "filledDiamond": + this.drawDiamond(ah, ak, ai, true, aj); + break; + case "circle": + this.drawCircle(ah, ak, ai, false, aj); + break; + case "filledCircle": + this.drawCircle(ah, ak, ai, true, aj); + break; + case "square": + this.drawSquare(ah, ak, ai, false, aj); + break; + case "filledSquare": + this.drawSquare(ah, ak, ai, true, aj); + break; + case "x": + this.drawX(ah, ak, ai, true, aj); + break; + case "plus": + this.drawPlus(ah, ak, ai, true, aj); + break; + case "dash": + this.drawDash(ah, ak, ai, true, aj); + break; + case "line": + this.drawLine(ah, ak, ai, false, aj); + break; + default: + this.drawDiamond(ah, ak, ai, false, aj); + break; + } + } + }; + L.jqplot.ShadowRenderer = function (ah) { + this.angle = 45; + this.offset = 1; + this.alpha = 0.07; + this.lineWidth = 1.5; + this.lineJoin = "miter"; + this.lineCap = "round"; + this.closePath = false; + this.fill = false; + this.depth = 3; + this.strokeStyle = "rgba(0,0,0,0.1)"; + this.isarc = false; + L.extend(true, this, ah); + }; + L.jqplot.ShadowRenderer.prototype.init = function (ah) { + L.extend(true, this, ah); + }; + L.jqplot.ShadowRenderer.prototype.draw = function (av, at, ax) { + av.save(); + var ah = ax != null ? ax : {}; + var au = ah.fill != null ? ah.fill : this.fill; + var ap = ah.fillRect != null ? ah.fillRect : this.fillRect; + var ao = ah.closePath != null ? ah.closePath : this.closePath; + var al = ah.offset != null ? ah.offset : this.offset; + var aj = ah.alpha != null ? ah.alpha : this.alpha; + var an = ah.depth != null ? ah.depth : this.depth; + var aw = ah.isarc != null ? ah.isarc : this.isarc; + var aq = ah.linePattern != null ? ah.linePattern : this.linePattern; + av.lineWidth = ah.lineWidth != null ? ah.lineWidth : this.lineWidth; + av.lineJoin = ah.lineJoin != null ? ah.lineJoin : this.lineJoin; + av.lineCap = ah.lineCap != null ? ah.lineCap : this.lineCap; + av.strokeStyle = + ah.strokeStyle || this.strokeStyle || "rgba(0,0,0," + aj + ")"; + av.fillStyle = + ah.fillStyle || this.fillStyle || "rgba(0,0,0," + aj + ")"; + for (var ak = 0; ak < an; ak++) { + var ar = L.jqplot.LinePattern(av, aq); + av.translate( + Math.cos((this.angle * Math.PI) / 180) * al, + Math.sin((this.angle * Math.PI) / 180) * al, + ); + ar.beginPath(); + if (aw) { + av.arc(at[0], at[1], at[2], at[3], at[4], true); + } else { + if (ap) { + if (ap) { + av.fillRect(at[0], at[1], at[2], at[3]); + } + } else { + if (at && at.length) { + var ai = true; + for (var am = 0; am < at.length; am++) { + if (at[am][0] != null && at[am][1] != null) { + if (ai) { + ar.moveTo(at[am][0], at[am][1]); + ai = false; + } else { + ar.lineTo(at[am][0], at[am][1]); + } + } else { + ai = true; + } + } + } + } + } + if (ao) { + ar.closePath(); + } + if (au) { + av.fill(); + } else { + av.stroke(); + } + } + av.restore(); + }; + L.jqplot.ShapeRenderer = function (ah) { + this.lineWidth = 1.5; + this.linePattern = "solid"; + this.lineJoin = "miter"; + this.lineCap = "round"; + this.closePath = false; + this.fill = false; + this.isarc = false; + this.fillRect = false; + this.strokeRect = false; + this.clearRect = false; + this.strokeStyle = "#999999"; + this.fillStyle = "#999999"; + L.extend(true, this, ah); + }; + L.jqplot.ShapeRenderer.prototype.init = function (ah) { + L.extend(true, this, ah); + }; + L.jqplot.ShapeRenderer.prototype.draw = function (at, aq, av) { + at.save(); + var ah = av != null ? av : {}; + var ar = ah.fill != null ? ah.fill : this.fill; + var am = ah.closePath != null ? ah.closePath : this.closePath; + var an = ah.fillRect != null ? ah.fillRect : this.fillRect; + var ak = ah.strokeRect != null ? ah.strokeRect : this.strokeRect; + var ai = ah.clearRect != null ? ah.clearRect : this.clearRect; + var au = ah.isarc != null ? ah.isarc : this.isarc; + var ao = ah.linePattern != null ? ah.linePattern : this.linePattern; + var ap = L.jqplot.LinePattern(at, ao); + at.lineWidth = ah.lineWidth || this.lineWidth; + at.lineJoin = ah.lineJoin || this.lineJoin; + at.lineCap = ah.lineCap || this.lineCap; + at.strokeStyle = ah.strokeStyle || ah.color || this.strokeStyle; + at.fillStyle = ah.fillStyle || this.fillStyle; + at.beginPath(); + if (au) { + at.arc(aq[0], aq[1], aq[2], aq[3], aq[4], true); + if (am) { + at.closePath(); + } + if (ar) { + at.fill(); + } else { + at.stroke(); + } + at.restore(); + return; + } else { + if (ai) { + at.clearRect(aq[0], aq[1], aq[2], aq[3]); + at.restore(); + return; + } else { + if (an || ak) { + if (an) { + at.fillRect(aq[0], aq[1], aq[2], aq[3]); + } + if (ak) { + at.strokeRect(aq[0], aq[1], aq[2], aq[3]); + at.restore(); + return; + } + } else { + if (aq && aq.length) { + var aj = true; + for (var al = 0; al < aq.length; al++) { + if (aq[al][0] != null && aq[al][1] != null) { + if (aj) { + ap.moveTo(aq[al][0], aq[al][1]); + aj = false; + } else { + ap.lineTo(aq[al][0], aq[al][1]); + } + } else { + aj = true; + } + } + if (am) { + ap.closePath(); + } + if (ar) { + at.fill(); + } else { + at.stroke(); + } + } + } + } + } + at.restore(); + }; + L.jqplot.TableLegendRenderer = function () {}; + L.jqplot.TableLegendRenderer.prototype.init = function (ah) { + L.extend(true, this, ah); + }; + L.jqplot.TableLegendRenderer.prototype.addrow = function (aq, ak, ah, ao) { + var al = ah ? this.rowSpacing + "px" : "0px"; + var ap; + var aj; + var ai; + var an; + var am; + ai = document.createElement("tr"); + ap = L(ai); + ap.addClass("jqplot-table-legend"); + ai = null; + if (ao) { + ap.prependTo(this._elem); + } else { + ap.appendTo(this._elem); + } + if (this.showSwatches) { + aj = L(document.createElement("td")); + aj.addClass("jqplot-table-legend jqplot-table-legend-swatch"); + aj.css({ textAlign: "center", paddingTop: al }); + an = L(document.createElement("div")); + an.addClass("jqplot-table-legend-swatch-outline"); + am = L(document.createElement("div")); + am.addClass("jqplot-table-legend-swatch"); + am.css({ backgroundColor: ak, borderColor: ak }); + ap.append(aj.append(an.append(am))); + } + if (this.showLabels) { + aj = L(document.createElement("td")); + aj.addClass("jqplot-table-legend jqplot-table-legend-label"); + aj.css("paddingTop", al); + ap.append(aj); + if (this.escapeHtml) { + aj.text(aq); + } else { + aj.html(aq); + } + } + aj = null; + an = null; + am = null; + ap = null; + ai = null; + }; + L.jqplot.TableLegendRenderer.prototype.draw = function () { + if (this._elem) { + this._elem.emptyForce(); + this._elem = null; + } + if (this.show) { + var am = this._series; + var ai = document.createElement("table"); + this._elem = L(ai); + this._elem.addClass("jqplot-table-legend"); + var ar = { position: "absolute" }; + if (this.background) { + ar.background = this.background; + } + if (this.border) { + ar.border = this.border; + } + if (this.fontSize) { + ar.fontSize = this.fontSize; + } + if (this.fontFamily) { + ar.fontFamily = this.fontFamily; + } + if (this.textColor) { + ar.textColor = this.textColor; + } + if (this.marginTop != null) { + ar.marginTop = this.marginTop; + } + if (this.marginBottom != null) { + ar.marginBottom = this.marginBottom; + } + if (this.marginLeft != null) { + ar.marginLeft = this.marginLeft; + } + if (this.marginRight != null) { + ar.marginRight = this.marginRight; + } + var ah = false, + ao = false, + aq; + for (var an = 0; an < am.length; an++) { + aq = am[an]; + if ( + aq._stack || + aq.renderer.constructor == L.jqplot.BezierCurveRenderer + ) { + ao = true; + } + if (aq.show && aq.showLabel) { + var al = this.labels[an] || aq.label.toString(); + if (al) { + var aj = aq.color; + if (ao && an < am.length - 1) { + ah = true; + } else { + if (ao && an == am.length - 1) { + ah = false; + } + } + this.renderer.addrow.call(this, al, aj, ah, ao); + ah = true; + } + for ( + var ak = 0; + ak < L.jqplot.addLegendRowHooks.length; + ak++ + ) { + var ap = L.jqplot.addLegendRowHooks[ak].call(this, aq); + if (ap) { + this.renderer.addrow.call( + this, + ap.label, + ap.color, + ah, + ); + ah = true; + } + } + al = null; + } + } + } + return this._elem; + }; + L.jqplot.TableLegendRenderer.prototype.pack = function (aj) { + if (this.show) { + if (this.placement == "insideGrid") { + switch (this.location) { + case "nw": + var ai = aj.left; + var ah = aj.top; + this._elem.css("left", ai); + this._elem.css("top", ah); + break; + case "n": + var ai = + (aj.left + + (this._plotDimensions.width - aj.right)) / + 2 - + this.getWidth() / 2; + var ah = aj.top; + this._elem.css("left", ai); + this._elem.css("top", ah); + break; + case "ne": + var ai = aj.right; + var ah = aj.top; + this._elem.css({ right: ai, top: ah }); + break; + case "e": + var ai = aj.right; + var ah = + (aj.top + + (this._plotDimensions.height - aj.bottom)) / + 2 - + this.getHeight() / 2; + this._elem.css({ right: ai, top: ah }); + break; + case "se": + var ai = aj.right; + var ah = aj.bottom; + this._elem.css({ right: ai, bottom: ah }); + break; + case "s": + var ai = + (aj.left + + (this._plotDimensions.width - aj.right)) / + 2 - + this.getWidth() / 2; + var ah = aj.bottom; + this._elem.css({ left: ai, bottom: ah }); + break; + case "sw": + var ai = aj.left; + var ah = aj.bottom; + this._elem.css({ left: ai, bottom: ah }); + break; + case "w": + var ai = aj.left; + var ah = + (aj.top + + (this._plotDimensions.height - aj.bottom)) / + 2 - + this.getHeight() / 2; + this._elem.css({ left: ai, top: ah }); + break; + default: + var ai = aj.right; + var ah = aj.bottom; + this._elem.css({ right: ai, bottom: ah }); + break; + } + } else { + if (this.placement == "outside") { + switch (this.location) { + case "nw": + var ai = this._plotDimensions.width - aj.left; + var ah = aj.top; + this._elem.css("right", ai); + this._elem.css("top", ah); + break; + case "n": + var ai = + (aj.left + + (this._plotDimensions.width - aj.right)) / + 2 - + this.getWidth() / 2; + var ah = this._plotDimensions.height - aj.top; + this._elem.css("left", ai); + this._elem.css("bottom", ah); + break; + case "ne": + var ai = this._plotDimensions.width - aj.right; + var ah = aj.top; + this._elem.css({ left: ai, top: ah }); + break; + case "e": + var ai = this._plotDimensions.width - aj.right; + var ah = + (aj.top + + (this._plotDimensions.height - aj.bottom)) / + 2 - + this.getHeight() / 2; + this._elem.css({ left: ai, top: ah }); + break; + case "se": + var ai = this._plotDimensions.width - aj.right; + var ah = aj.bottom; + this._elem.css({ left: ai, bottom: ah }); + break; + case "s": + var ai = + (aj.left + + (this._plotDimensions.width - aj.right)) / + 2 - + this.getWidth() / 2; + var ah = this._plotDimensions.height - aj.bottom; + this._elem.css({ left: ai, top: ah }); + break; + case "sw": + var ai = this._plotDimensions.width - aj.left; + var ah = aj.bottom; + this._elem.css({ right: ai, bottom: ah }); + break; + case "w": + var ai = this._plotDimensions.width - aj.left; + var ah = + (aj.top + + (this._plotDimensions.height - aj.bottom)) / + 2 - + this.getHeight() / 2; + this._elem.css({ right: ai, top: ah }); + break; + default: + var ai = aj.right; + var ah = aj.bottom; + this._elem.css({ right: ai, bottom: ah }); + break; + } + } else { + switch (this.location) { + case "nw": + this._elem.css({ left: 0, top: aj.top }); + break; + case "n": + var ai = + (aj.left + + (this._plotDimensions.width - aj.right)) / + 2 - + this.getWidth() / 2; + this._elem.css({ left: ai, top: aj.top }); + break; + case "ne": + this._elem.css({ right: 0, top: aj.top }); + break; + case "e": + var ah = + (aj.top + + (this._plotDimensions.height - aj.bottom)) / + 2 - + this.getHeight() / 2; + this._elem.css({ right: aj.right, top: ah }); + break; + case "se": + this._elem.css({ + right: aj.right, + bottom: aj.bottom, + }); + break; + case "s": + var ai = + (aj.left + + (this._plotDimensions.width - aj.right)) / + 2 - + this.getWidth() / 2; + this._elem.css({ left: ai, bottom: aj.bottom }); + break; + case "sw": + this._elem.css({ + left: aj.left, + bottom: aj.bottom, + }); + break; + case "w": + var ah = + (aj.top + + (this._plotDimensions.height - aj.bottom)) / + 2 - + this.getHeight() / 2; + this._elem.css({ left: aj.left, top: ah }); + break; + default: + this._elem.css({ + right: aj.right, + bottom: aj.bottom, + }); + break; + } + } + } + } + }; + L.jqplot.ThemeEngine = function () { + this.themes = {}; + this.activeTheme = null; + }; + L.jqplot.ThemeEngine.prototype.init = function () { + var ak = new L.jqplot.Theme({ _name: "Default" }); + var an, ai, am; + for (an in ak.target) { + if (an == "textColor") { + ak.target[an] = this.target.css("color"); + } else { + ak.target[an] = this.target.css(an); + } + } + if (this.title.show && this.title._elem) { + for (an in ak.title) { + if (an == "textColor") { + ak.title[an] = this.title._elem.css("color"); + } else { + ak.title[an] = this.title._elem.css(an); + } + } + } + for (an in ak.grid) { + ak.grid[an] = this.grid[an]; + } + if (ak.grid.backgroundColor == null && this.grid.background != null) { + ak.grid.backgroundColor = this.grid.background; + } + if (this.legend.show && this.legend._elem) { + for (an in ak.legend) { + if (an == "textColor") { + ak.legend[an] = this.legend._elem.css("color"); + } else { + ak.legend[an] = this.legend._elem.css(an); + } + } + } + var aj; + for (ai = 0; ai < this.series.length; ai++) { + aj = this.series[ai]; + if (aj.renderer.constructor == L.jqplot.LineRenderer) { + ak.series.push(new p()); + } else { + if (aj.renderer.constructor == L.jqplot.BarRenderer) { + ak.series.push(new T()); + } else { + if (aj.renderer.constructor == L.jqplot.PieRenderer) { + ak.series.push(new f()); + } else { + if (aj.renderer.constructor == L.jqplot.DonutRenderer) { + ak.series.push(new G()); + } else { + if ( + aj.renderer.constructor == + L.jqplot.FunnelRenderer + ) { + ak.series.push(new Z()); + } else { + if ( + aj.renderer.constructor == + L.jqplot.MeterGaugeRenderer + ) { + ak.series.push(new D()); + } else { + ak.series.push({}); + } + } + } + } + } + } + for (an in ak.series[ai]) { + ak.series[ai][an] = aj[an]; + } + } + var ah, al; + for (an in this.axes) { + al = this.axes[an]; + ah = ak.axes[an] = new P(); + ah.borderColor = al.borderColor; + ah.borderWidth = al.borderWidth; + if (al._ticks && al._ticks[0]) { + for (am in ah.ticks) { + if (al._ticks[0].hasOwnProperty(am)) { + ah.ticks[am] = al._ticks[0][am]; + } else { + if (al._ticks[0]._elem) { + ah.ticks[am] = al._ticks[0]._elem.css(am); + } + } + } + } + if (al._label && al._label.show) { + for (am in ah.label) { + if (al._label[am]) { + ah.label[am] = al._label[am]; + } else { + if (al._label._elem) { + if (am == "textColor") { + ah.label[am] = al._label._elem.css("color"); + } else { + ah.label[am] = al._label._elem.css(am); + } + } + } + } + } + } + this.themeEngine._add(ak); + this.themeEngine.activeTheme = this.themeEngine.themes[ak._name]; + }; + L.jqplot.ThemeEngine.prototype.get = function (ah) { + if (!ah) { + return this.activeTheme; + } else { + return this.themes[ah]; + } + }; + function O(ai, ah) { + return ai - ah; + } + L.jqplot.ThemeEngine.prototype.getThemeNames = function () { + var ah = []; + for (var ai in this.themes) { + ah.push(ai); + } + return ah.sort(O); + }; + L.jqplot.ThemeEngine.prototype.getThemes = function () { + var ai = []; + var ah = []; + for (var ak in this.themes) { + ai.push(ak); + } + ai.sort(O); + for (var aj = 0; aj < ai.length; aj++) { + ah.push(this.themes[ai[aj]]); + } + return ah; + }; + L.jqplot.ThemeEngine.prototype.activate = function (av, aB) { + var ah = false; + if (!aB && this.activeTheme && this.activeTheme._name) { + aB = this.activeTheme._name; + } + if (!this.themes.hasOwnProperty(aB)) { + throw new Error("No theme of that name"); + } else { + var am = this.themes[aB]; + this.activeTheme = am; + var aA, + at = false, + ar = false; + var ai = ["xaxis", "x2axis", "yaxis", "y2axis"]; + for (aw = 0; aw < ai.length; aw++) { + var an = ai[aw]; + if (am.axesStyles.borderColor != null) { + av.axes[an].borderColor = am.axesStyles.borderColor; + } + if (am.axesStyles.borderWidth != null) { + av.axes[an].borderWidth = am.axesStyles.borderWidth; + } + } + for (var az in av.axes) { + var ak = av.axes[az]; + if (ak.show) { + var aq = am.axes[az] || {}; + var ao = am.axesStyles; + var al = L.jqplot.extend(true, {}, aq, ao); + aA = + am.axesStyles.borderColor != null + ? am.axesStyles.borderColor + : al.borderColor; + if (al.borderColor != null) { + ak.borderColor = al.borderColor; + ah = true; + } + aA = + am.axesStyles.borderWidth != null + ? am.axesStyles.borderWidth + : al.borderWidth; + if (al.borderWidth != null) { + ak.borderWidth = al.borderWidth; + ah = true; + } + if (ak._ticks && ak._ticks[0]) { + for (var aj in al.ticks) { + aA = al.ticks[aj]; + if (aA != null) { + ak.tickOptions[aj] = aA; + ak._ticks = []; + ah = true; + } + } + } + if (ak._label && ak._label.show) { + for (var aj in al.label) { + aA = al.label[aj]; + if (aA != null) { + ak.labelOptions[aj] = aA; + ah = true; + } + } + } + } + } + for (var au in am.grid) { + if (am.grid[au] != null) { + av.grid[au] = am.grid[au]; + } + } + if (!ah) { + av.grid.draw(); + } + if (av.legend.show) { + for (au in am.legend) { + if (am.legend[au] != null) { + av.legend[au] = am.legend[au]; + } + } + } + if (av.title.show) { + for (au in am.title) { + if (am.title[au] != null) { + av.title[au] = am.title[au]; + } + } + } + var aw; + for (aw = 0; aw < am.series.length; aw++) { + var ap = {}; + var ay = false; + for (au in am.series[aw]) { + aA = + am.seriesStyles[au] != null + ? am.seriesStyles[au] + : am.series[aw][au]; + if (aA != null) { + ap[au] = aA; + if (au == "color") { + av.series[aw].renderer.shapeRenderer.fillStyle = aA; + av.series[aw].renderer.shapeRenderer.strokeStyle = + aA; + av.series[aw][au] = aA; + } else { + if (au == "lineWidth" || au == "linePattern") { + av.series[aw].renderer.shapeRenderer[au] = aA; + av.series[aw][au] = aA; + } else { + if (au == "markerOptions") { + V(av.series[aw].markerOptions, aA); + V(av.series[aw].markerRenderer, aA); + } else { + av.series[aw][au] = aA; + } + } + } + ah = true; + } + } + } + if (ah) { + av.target.empty(); + av.draw(); + } + for (au in am.target) { + if (am.target[au] != null) { + av.target.css(au, am.target[au]); + } + } + } + }; + L.jqplot.ThemeEngine.prototype._add = function (ai, ah) { + if (ah) { + ai._name = ah; + } + if (!ai._name) { + ai._name = Date.parse(new Date()); + } + if (!this.themes.hasOwnProperty(ai._name)) { + this.themes[ai._name] = ai; + } else { + throw new Error("jqplot.ThemeEngine Error: Theme already in use"); + } + }; + L.jqplot.ThemeEngine.prototype.remove = function (ah) { + if (ah == "Default") { + return false; + } + return delete this.themes[ah]; + }; + L.jqplot.ThemeEngine.prototype.newTheme = function (ah, aj) { + if (typeof ah == "object") { + aj = aj || ah; + ah = null; + } + if (aj && aj._name) { + ah = aj._name; + } else { + ah = ah || Date.parse(new Date()); + } + var ai = this.copy(this.themes.Default._name, ah); + L.jqplot.extend(ai, aj); + return ai; + }; + function B(aj) { + if (aj == null || typeof aj != "object") { + return aj; + } + var ah = new aj.constructor(); + for (var ai in aj) { + ah[ai] = B(aj[ai]); + } + return ah; + } + L.jqplot.clone = B; + function V(aj, ai) { + if (ai == null || typeof ai != "object") { + return; + } + for (var ah in ai) { + if (ah == "highlightColors") { + aj[ah] = B(ai[ah]); + } + if (ai[ah] != null && typeof ai[ah] == "object") { + if (!aj.hasOwnProperty(ah)) { + aj[ah] = {}; + } + V(aj[ah], ai[ah]); + } else { + aj[ah] = ai[ah]; + } + } + } + L.jqplot.merge = V; + L.jqplot.extend = function () { + var am = arguments[0] || {}, + ak = 1, + al = arguments.length, + ah = false, + aj; + if (typeof am === "boolean") { + ah = am; + am = arguments[1] || {}; + ak = 2; + } + if ( + typeof am !== "object" && + !toString.call(am) === "[object Function]" + ) { + am = {}; + } + for (; ak < al; ak++) { + if ((aj = arguments[ak]) != null) { + for (var ai in aj) { + var an = am[ai], + ao = aj[ai]; + if (am === ao) { + continue; + } + if (ah && ao && typeof ao === "object" && !ao.nodeType) { + am[ai] = L.jqplot.extend( + ah, + an || (ao.length != null ? [] : {}), + ao, + ); + } else { + if (ao !== u) { + am[ai] = ao; + } + } + } + } + } + return am; + }; + L.jqplot.ThemeEngine.prototype.rename = function (ai, ah) { + if (ai == "Default" || ah == "Default") { + throw new Error( + "jqplot.ThemeEngine Error: Cannot rename from/to Default", + ); + } + if (this.themes.hasOwnProperty(ah)) { + throw new Error( + "jqplot.ThemeEngine Error: New name already in use.", + ); + } else { + if (this.themes.hasOwnProperty(ai)) { + var aj = this.copy(ai, ah); + this.remove(ai); + return aj; + } + } + throw new Error( + "jqplot.ThemeEngine Error: Old name or new name invalid", + ); + }; + L.jqplot.ThemeEngine.prototype.copy = function (ah, aj, al) { + if (aj == "Default") { + throw new Error( + "jqplot.ThemeEngine Error: Cannot copy over Default theme", + ); + } + if (!this.themes.hasOwnProperty(ah)) { + var ai = "jqplot.ThemeEngine Error: Source name invalid"; + throw new Error(ai); + } + if (this.themes.hasOwnProperty(aj)) { + var ai = "jqplot.ThemeEngine Error: Target name invalid"; + throw new Error(ai); + } else { + var ak = B(this.themes[ah]); + ak._name = aj; + L.jqplot.extend(true, ak, al); + this._add(ak); + return ak; + } + }; + L.jqplot.Theme = function (ah, ai) { + if (typeof ah == "object") { + ai = ai || ah; + ah = null; + } + ah = ah || Date.parse(new Date()); + this._name = ah; + this.target = { backgroundColor: null }; + this.legend = { + textColor: null, + fontFamily: null, + fontSize: null, + border: null, + background: null, + }; + this.title = { + textColor: null, + fontFamily: null, + fontSize: null, + textAlign: null, + }; + this.seriesStyles = {}; + this.series = []; + this.grid = { + drawGridlines: null, + gridLineColor: null, + gridLineWidth: null, + backgroundColor: null, + borderColor: null, + borderWidth: null, + shadow: null, + }; + this.axesStyles = { label: {}, ticks: {} }; + this.axes = {}; + if (typeof ai == "string") { + this._name = ai; + } else { + if (typeof ai == "object") { + L.jqplot.extend(true, this, ai); + } + } + }; + var P = function () { + this.borderColor = null; + this.borderWidth = null; + this.ticks = new o(); + this.label = new t(); + }; + var o = function () { + this.show = null; + this.showGridline = null; + this.showLabel = null; + this.showMark = null; + this.size = null; + this.textColor = null; + this.whiteSpace = null; + this.fontSize = null; + this.fontFamily = null; + }; + var t = function () { + this.textColor = null; + this.whiteSpace = null; + this.fontSize = null; + this.fontFamily = null; + this.fontWeight = null; + }; + var p = function () { + this.color = null; + this.lineWidth = null; + this.linePattern = null; + this.shadow = null; + this.fillColor = null; + this.showMarker = null; + this.markerOptions = new I(); + }; + var I = function () { + this.show = null; + this.style = null; + this.lineWidth = null; + this.size = null; + this.color = null; + this.shadow = null; + }; + var T = function () { + this.color = null; + this.seriesColors = null; + this.lineWidth = null; + this.shadow = null; + this.barPadding = null; + this.barMargin = null; + this.barWidth = null; + this.highlightColors = null; + }; + var f = function () { + this.seriesColors = null; + this.padding = null; + this.sliceMargin = null; + this.fill = null; + this.shadow = null; + this.startAngle = null; + this.lineWidth = null; + this.highlightColors = null; + }; + var G = function () { + this.seriesColors = null; + this.padding = null; + this.sliceMargin = null; + this.fill = null; + this.shadow = null; + this.startAngle = null; + this.lineWidth = null; + this.innerDiameter = null; + this.thickness = null; + this.ringMargin = null; + this.highlightColors = null; + }; + var Z = function () { + this.color = null; + this.lineWidth = null; + this.shadow = null; + this.padding = null; + this.sectionMargin = null; + this.seriesColors = null; + this.highlightColors = null; + }; + var D = function () { + this.padding = null; + this.backgroundColor = null; + this.ringColor = null; + this.tickColor = null; + this.ringWidth = null; + this.intervalColors = null; + this.intervalInnerRadius = null; + this.intervalOuterRadius = null; + this.hubRadius = null; + this.needleThickness = null; + this.needlePad = null; + }; + L.fn.jqplotChildText = function () { + return L(this) + .contents() + .filter(function () { + return this.nodeType == 3; + }) + .text(); + }; + L.fn.jqplotGetComputedFontStyle = function () { + var ak = window.getComputedStyle + ? window.getComputedStyle(this[0], "") + : this[0].currentStyle; + var ai = ak["font-style"] + ? ["font-style", "font-weight", "font-size", "font-family"] + : ["fontStyle", "fontWeight", "fontSize", "fontFamily"]; + var al = []; + for (var aj = 0; aj < ai.length; ++aj) { + var ah = String(ak[ai[aj]]); + if (ah && ah != "normal") { + al.push(ah); + } + } + return al.join(" "); + }; + L.fn.jqplotToImageCanvas = function (aj) { + aj = aj || {}; + var av = aj.x_offset == null ? 0 : aj.x_offset; + var ax = aj.y_offset == null ? 0 : aj.y_offset; + var al = + aj.backgroundColor == null + ? "rgb(255,255,255)" + : aj.backgroundColor; + if (L(this).width() == 0 || L(this).height() == 0) { + return null; + } + if (L.jqplot.use_excanvas) { + return null; + } + var an = document.createElement("canvas"); + var aA = L(this).outerHeight(true); + var at = L(this).outerWidth(true); + var am = L(this).offset(); + var ao = am.left; + var aq = am.top; + var au = 0, + ar = 0; + var ay = [ + "jqplot-table-legend", + "jqplot-xaxis-tick", + "jqplot-x2axis-tick", + "jqplot-yaxis-tick", + "jqplot-y2axis-tick", + "jqplot-y3axis-tick", + "jqplot-y4axis-tick", + "jqplot-y5axis-tick", + "jqplot-y6axis-tick", + "jqplot-y7axis-tick", + "jqplot-y8axis-tick", + "jqplot-y9axis-tick", + "jqplot-xaxis-label", + "jqplot-x2axis-label", + "jqplot-yaxis-label", + "jqplot-y2axis-label", + "jqplot-y3axis-label", + "jqplot-y4axis-label", + "jqplot-y5axis-label", + "jqplot-y6axis-label", + "jqplot-y7axis-label", + "jqplot-y8axis-label", + "jqplot-y9axis-label", + ]; + var ap, ah, ai, aB; + for (var az = 0; az < ay.length; az++) { + L(this) + .find("." + ay[az]) + .each(function () { + ap = L(this).offset().top - aq; + ah = L(this).offset().left - ao; + aB = ah + L(this).outerWidth(true) + au; + ai = ap + L(this).outerHeight(true) + ar; + if (ah < -au) { + at = at - au - ah; + au = -ah; + } + if (ap < -ar) { + aA = aA - ar - ap; + ar = -ap; + } + if (aB > at) { + at = aB; + } + if (ai > aA) { + aA = ai; + } + }); + } + an.width = at + Number(av); + an.height = aA + Number(ax); + var ak = an.getContext("2d"); + ak.save(); + ak.fillStyle = al; + ak.fillRect(0, 0, an.width, an.height); + ak.restore(); + ak.translate(au, ar); + ak.textAlign = "left"; + ak.textBaseline = "top"; + function aC(aE) { + var aF = parseInt(L(aE).css("line-height"), 10); + if (isNaN(aF)) { + aF = parseInt(L(aE).css("font-size"), 10) * 1.2; + } + return aF; + } + function aD(aF, aE, aS, aG, aO, aH) { + var aQ = aC(aF); + var aK = L(aF).innerWidth(); + var aL = L(aF).innerHeight(); + var aN = aS.split(/\s+/); + var aR = aN.length; + var aP = ""; + var aM = []; + var aU = aO; + var aT = aG; + for (var aJ = 0; aJ < aR; aJ++) { + aP += aN[aJ]; + if (aE.measureText(aP).width > aK) { + aM.push(aJ); + aP = ""; + aJ--; + } + } + if (aM.length === 0) { + if (L(aF).css("textAlign") === "center") { + aT = aG + (aH - aE.measureText(aP).width) / 2 - au; + } + aE.fillText(aS, aT, aO); + } else { + aP = aN.slice(0, aM[0]).join(" "); + if (L(aF).css("textAlign") === "center") { + aT = aG + (aH - aE.measureText(aP).width) / 2 - au; + } + aE.fillText(aP, aT, aU); + aU += aQ; + for (var aJ = 1, aI = aM.length; aJ < aI; aJ++) { + aP = aN.slice(aM[aJ - 1], aM[aJ]).join(" "); + if (L(aF).css("textAlign") === "center") { + aT = aG + (aH - aE.measureText(aP).width) / 2 - au; + } + aE.fillText(aP, aT, aU); + aU += aQ; + } + aP = aN.slice(aM[aJ - 1], aN.length).join(" "); + if (L(aF).css("textAlign") === "center") { + aT = aG + (aH - aE.measureText(aP).width) / 2 - au; + } + aE.fillText(aP, aT, aU); + } + } + function aw(aG, aJ, aE) { + var aN = aG.tagName.toLowerCase(); + var aF = L(aG).position(); + var aK = window.getComputedStyle + ? window.getComputedStyle(aG, "") + : aG.currentStyle; + var aI = + aJ + + aF.left + + parseInt(aK.marginLeft, 10) + + parseInt(aK.borderLeftWidth, 10) + + parseInt(aK.paddingLeft, 10); + var aL = + aE + + aF.top + + parseInt(aK.marginTop, 10) + + parseInt(aK.borderTopWidth, 10) + + parseInt(aK.paddingTop, 10); + var aM = an.width; + if ( + (aN == "div" || aN == "span") && + !L(aG).hasClass("jqplot-highlighter-tooltip") + ) { + L(aG) + .children() + .each(function () { + aw(this, aI, aL); + }); + var aO = L(aG).jqplotChildText(); + if (aO) { + ak.font = L(aG).jqplotGetComputedFontStyle(); + ak.fillStyle = L(aG).css("color"); + aD(aG, ak, aO, aI, aL, aM); + } + } else { + if (aN === "table" && L(aG).hasClass("jqplot-table-legend")) { + ak.strokeStyle = L(aG).css("border-top-color"); + ak.fillStyle = L(aG).css("background-color"); + ak.fillRect( + aI, + aL, + L(aG).innerWidth(), + L(aG).innerHeight(), + ); + if (parseInt(L(aG).css("border-top-width"), 10) > 0) { + ak.strokeRect( + aI, + aL, + L(aG).innerWidth(), + L(aG).innerHeight(), + ); + } + L(aG) + .find("div.jqplot-table-legend-swatch-outline") + .each(function () { + var aU = L(this); + ak.strokeStyle = aU.css("border-top-color"); + var aQ = aI + aU.position().left; + var aR = aL + aU.position().top; + ak.strokeRect( + aQ, + aR, + aU.innerWidth(), + aU.innerHeight(), + ); + aQ += parseInt(aU.css("padding-left"), 10); + aR += parseInt(aU.css("padding-top"), 10); + var aT = + aU.innerHeight() - + 2 * parseInt(aU.css("padding-top"), 10); + var aP = + aU.innerWidth() - + 2 * parseInt(aU.css("padding-left"), 10); + var aS = aU.children( + "div.jqplot-table-legend-swatch", + ); + ak.fillStyle = aS.css("background-color"); + ak.fillRect(aQ, aR, aP, aT); + }); + L(aG) + .find("td.jqplot-table-legend-label") + .each(function () { + var aR = L(this); + var aP = aI + aR.position().left; + var aQ = + aL + + aR.position().top + + parseInt(aR.css("padding-top"), 10); + ak.font = aR.jqplotGetComputedFontStyle(); + ak.fillStyle = aR.css("color"); + aD(aR, ak, aR.text(), aP, aQ, aM); + }); + var aH = null; + } else { + if (aN == "canvas") { + ak.drawImage(aG, aI, aL); + } + } + } + } + L(this) + .children() + .each(function () { + aw(this, av, ax); + }); + return an; + }; + L.fn.jqplotToImageStr = function (ai) { + var ah = L(this).jqplotToImageCanvas(ai); + if (ah) { + return ah.toDataURL("image/png"); + } else { + return null; + } + }; + L.fn.jqplotToImageElem = function (ah) { + var ai = document.createElement("img"); + var aj = L(this).jqplotToImageStr(ah); + ai.src = aj; + return ai; + }; + L.fn.jqplotToImageElemStr = function (ah) { + var ai = ""; + return ai; + }; + L.fn.jqplotSaveImage = function () { + var ah = L(this).jqplotToImageStr({}); + if (ah) { + window.location.href = ah.replace( + "image/png", + "image/octet-stream", + ); + } + }; + L.fn.jqplotViewImage = function () { + var ai = L(this).jqplotToImageElemStr({}); + var aj = L(this).jqplotToImageStr({}); + if (ai) { + var ah = window.open(""); + ah.document.open("image/png"); + ah.document.write(ai); + ah.document.close(); + ah = null; + } + }; + var ag = function () { + this.syntax = ag.config.syntax; + this._type = "jsDate"; + this.proxy = new Date(); + this.options = {}; + this.locale = ag.regional.getLocale(); + this.formatString = ""; + this.defaultCentury = ag.config.defaultCentury; + switch (arguments.length) { + case 0: + break; + case 1: + if ( + l(arguments[0]) == "[object Object]" && + arguments[0]._type != "jsDate" + ) { + var aj = (this.options = arguments[0]); + this.syntax = aj.syntax || this.syntax; + this.defaultCentury = + aj.defaultCentury || this.defaultCentury; + this.proxy = ag.createDate(aj.date); + } else { + this.proxy = ag.createDate(arguments[0]); + } + break; + default: + var ah = []; + for (var ai = 0; ai < arguments.length; ai++) { + ah.push(arguments[ai]); + } + this.proxy = new Date(); + this.proxy.setFullYear.apply(this.proxy, ah.slice(0, 3)); + if (ah.slice(3).length) { + this.proxy.setHours.apply(this.proxy, ah.slice(3)); + } + break; + } + }; + ag.config = { defaultLocale: "en", syntax: "perl", defaultCentury: 1900 }; + ag.prototype.add = function (aj, ai) { + var ah = E[ai] || E.day; + if (typeof ah == "number") { + this.proxy.setTime(this.proxy.getTime() + ah * aj); + } else { + ah.add(this, aj); + } + return this; + }; + ag.prototype.clone = function () { + return new ag(this.proxy.getTime()); + }; + ag.prototype.getUtcOffset = function () { + return this.proxy.getTimezoneOffset() * 60000; + }; + ag.prototype.diff = function (ai, al, ah) { + ai = new ag(ai); + if (ai === null) { + return null; + } + var aj = E[al] || E.day; + if (typeof aj == "number") { + var ak = (this.proxy.getTime() - ai.proxy.getTime()) / aj; + } else { + var ak = aj.diff(this.proxy, ai.proxy); + } + return ah ? ak : Math[ak > 0 ? "floor" : "ceil"](ak); + }; + ag.prototype.getAbbrDayName = function () { + return ag.regional[this.locale]["dayNamesShort"][this.proxy.getDay()]; + }; + ag.prototype.getAbbrMonthName = function () { + return ag.regional[this.locale]["monthNamesShort"][ + this.proxy.getMonth() + ]; + }; + ag.prototype.getAMPM = function () { + return this.proxy.getHours() >= 12 ? "PM" : "AM"; + }; + ag.prototype.getAmPm = function () { + return this.proxy.getHours() >= 12 ? "pm" : "am"; + }; + ag.prototype.getCentury = function () { + return parseInt(this.proxy.getFullYear() / 100, 10); + }; + ag.prototype.getDate = function () { + return this.proxy.getDate(); + }; + ag.prototype.getDay = function () { + return this.proxy.getDay(); + }; + ag.prototype.getDayOfWeek = function () { + var ah = this.proxy.getDay(); + return ah === 0 ? 7 : ah; + }; + ag.prototype.getDayOfYear = function () { + var ai = this.proxy; + var ah = ai - new Date("" + ai.getFullYear() + "/1/1 GMT"); + ah += ai.getTimezoneOffset() * 60000; + ai = null; + return parseInt(ah / 60000 / 60 / 24, 10) + 1; + }; + ag.prototype.getDayName = function () { + return ag.regional[this.locale]["dayNames"][this.proxy.getDay()]; + }; + ag.prototype.getFullWeekOfYear = function () { + var ak = this.proxy; + var ah = this.getDayOfYear(); + var aj = 6 - ak.getDay(); + var ai = parseInt((ah + aj) / 7, 10); + return ai; + }; + ag.prototype.getFullYear = function () { + return this.proxy.getFullYear(); + }; + ag.prototype.getGmtOffset = function () { + var ah = this.proxy.getTimezoneOffset() / 60; + var ai = ah < 0 ? "+" : "-"; + ah = Math.abs(ah); + return ai + N(Math.floor(ah), 2) + ":" + N((ah % 1) * 60, 2); + }; + ag.prototype.getHours = function () { + return this.proxy.getHours(); + }; + ag.prototype.getHours12 = function () { + var ah = this.proxy.getHours(); + return ah > 12 ? ah - 12 : ah == 0 ? 12 : ah; + }; + ag.prototype.getIsoWeek = function () { + var ak = this.proxy; + var aj = this.getWeekOfYear(); + var ah = new Date("" + ak.getFullYear() + "/1/1").getDay(); + var ai = aj + (ah > 4 || ah <= 1 ? 0 : 1); + if ( + ai == 53 && + new Date("" + ak.getFullYear() + "/12/31").getDay() < 4 + ) { + ai = 1; + } else { + if (ai === 0) { + ak = new ag(new Date("" + (ak.getFullYear() - 1) + "/12/31")); + ai = ak.getIsoWeek(); + } + } + ak = null; + return ai; + }; + ag.prototype.getMilliseconds = function () { + return this.proxy.getMilliseconds(); + }; + ag.prototype.getMinutes = function () { + return this.proxy.getMinutes(); + }; + ag.prototype.getMonth = function () { + return this.proxy.getMonth(); + }; + ag.prototype.getMonthName = function () { + return ag.regional[this.locale]["monthNames"][this.proxy.getMonth()]; + }; + ag.prototype.getMonthNumber = function () { + return this.proxy.getMonth() + 1; + }; + ag.prototype.getSeconds = function () { + return this.proxy.getSeconds(); + }; + ag.prototype.getShortYear = function () { + return this.proxy.getYear() % 100; + }; + ag.prototype.getTime = function () { + return this.proxy.getTime(); + }; + ag.prototype.getTimezoneAbbr = function () { + return this.proxy.toString().replace(/^.*\(([^)]+)\)$/, "$1"); + }; + ag.prototype.getTimezoneName = function () { + var ah = /(?:\((.+)\)$| ([A-Z]{3}) )/.exec(this.toString()); + return ah[1] || ah[2] || "GMT" + this.getGmtOffset(); + }; + ag.prototype.getTimezoneOffset = function () { + return this.proxy.getTimezoneOffset(); + }; + ag.prototype.getWeekOfYear = function () { + var ah = this.getDayOfYear(); + var aj = 7 - this.getDayOfWeek(); + var ai = parseInt((ah + aj) / 7, 10); + return ai; + }; + ag.prototype.getUnix = function () { + return Math.round(this.proxy.getTime() / 1000, 0); + }; + ag.prototype.getYear = function () { + return this.proxy.getYear(); + }; + ag.prototype.next = function (ah) { + ah = ah || "day"; + return this.clone().add(1, ah); + }; + ag.prototype.set = function () { + switch (arguments.length) { + case 0: + this.proxy = new Date(); + break; + case 1: + if ( + l(arguments[0]) == "[object Object]" && + arguments[0]._type != "jsDate" + ) { + var aj = (this.options = arguments[0]); + this.syntax = aj.syntax || this.syntax; + this.defaultCentury = + aj.defaultCentury || this.defaultCentury; + this.proxy = ag.createDate(aj.date); + } else { + this.proxy = ag.createDate(arguments[0]); + } + break; + default: + var ah = []; + for (var ai = 0; ai < arguments.length; ai++) { + ah.push(arguments[ai]); + } + this.proxy = new Date(); + this.proxy.setFullYear.apply(this.proxy, ah.slice(0, 3)); + if (ah.slice(3).length) { + this.proxy.setHours.apply(this.proxy, ah.slice(3)); + } + break; + } + return this; + }; + ag.prototype.setDate = function (ah) { + this.proxy.setDate(ah); + return this; + }; + ag.prototype.setFullYear = function () { + this.proxy.setFullYear.apply(this.proxy, arguments); + return this; + }; + ag.prototype.setHours = function () { + this.proxy.setHours.apply(this.proxy, arguments); + return this; + }; + ag.prototype.setMilliseconds = function (ah) { + this.proxy.setMilliseconds(ah); + return this; + }; + ag.prototype.setMinutes = function () { + this.proxy.setMinutes.apply(this.proxy, arguments); + return this; + }; + ag.prototype.setMonth = function () { + this.proxy.setMonth.apply(this.proxy, arguments); + return this; + }; + ag.prototype.setSeconds = function () { + this.proxy.setSeconds.apply(this.proxy, arguments); + return this; + }; + ag.prototype.setTime = function (ah) { + this.proxy.setTime(ah); + return this; + }; + ag.prototype.setYear = function () { + this.proxy.setYear.apply(this.proxy, arguments); + return this; + }; + ag.prototype.strftime = function (ah) { + ah = + ah || this.formatString || ag.regional[this.locale]["formatString"]; + return ag.strftime(this, ah, this.syntax); + }; + ag.prototype.toString = function () { + return this.proxy.toString(); + }; + ag.prototype.toYmdInt = function () { + return ( + this.proxy.getFullYear() * 10000 + + this.getMonthNumber() * 100 + + this.proxy.getDate() + ); + }; + ag.regional = { + en: { + monthNames: [ + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December", + ], + monthNamesShort: [ + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec", + ], + dayNames: [ + "Sunday", + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday", + ], + dayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], + formatString: "%Y-%m-%d %H:%M:%S", + }, + fr: { + monthNames: [ + "Janvier", + "Février", + "Mars", + "Avril", + "Mai", + "Juin", + "Juillet", + "Août", + "Septembre", + "Octobre", + "Novembre", + "Décembre", + ], + monthNamesShort: [ + "Jan", + "Fév", + "Mar", + "Avr", + "Mai", + "Jun", + "Jul", + "Aoû", + "Sep", + "Oct", + "Nov", + "Déc", + ], + dayNames: [ + "Dimanche", + "Lundi", + "Mardi", + "Mercredi", + "Jeudi", + "Vendredi", + "Samedi", + ], + dayNamesShort: ["Dim", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam"], + formatString: "%Y-%m-%d %H:%M:%S", + }, + de: { + monthNames: [ + "Januar", + "Februar", + "März", + "April", + "Mai", + "Juni", + "Juli", + "August", + "September", + "Oktober", + "November", + "Dezember", + ], + monthNamesShort: [ + "Jan", + "Feb", + "Mär", + "Apr", + "Mai", + "Jun", + "Jul", + "Aug", + "Sep", + "Okt", + "Nov", + "Dez", + ], + dayNames: [ + "Sonntag", + "Montag", + "Dienstag", + "Mittwoch", + "Donnerstag", + "Freitag", + "Samstag", + ], + dayNamesShort: ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"], + formatString: "%Y-%m-%d %H:%M:%S", + }, + es: { + monthNames: [ + "Enero", + "Febrero", + "Marzo", + "Abril", + "Mayo", + "Junio", + "Julio", + "Agosto", + "Septiembre", + "Octubre", + "Noviembre", + "Diciembre", + ], + monthNamesShort: [ + "Ene", + "Feb", + "Mar", + "Abr", + "May", + "Jun", + "Jul", + "Ago", + "Sep", + "Oct", + "Nov", + "Dic", + ], + dayNames: [ + "Domingo", + "Lunes", + "Martes", + "Miércoles", + "Jueves", + "Viernes", + "Sábado", + ], + dayNamesShort: [ + "Dom", + "Lun", + "Mar", + "Mié", + "Juv", + "Vie", + "Sáb", + ], + formatString: "%Y-%m-%d %H:%M:%S", + }, + ru: { + monthNames: [ + "Январь", + "Февраль", + "Март", + "Апрель", + "Май", + "Июнь", + "Июль", + "Август", + "Сентябрь", + "Октябрь", + "Ноябрь", + "Декабрь", + ], + monthNamesShort: [ + "Янв", + "Фев", + "Мар", + "Апр", + "Май", + "Июн", + "Июл", + "Авг", + "Сен", + "Окт", + "Ноя", + "Дек", + ], + dayNames: [ + "воскресенье", + "понедельник", + "вторник", + "среда", + "четверг", + "пятница", + "суббота", + ], + dayNamesShort: ["вск", "пнд", "втр", "срд", "чтв", "птн", "сбт"], + formatString: "%Y-%m-%d %H:%M:%S", + }, + ar: { + monthNames: [ + "كانون الثاني", + "شباط", + "آذار", + "نيسان", + "آذار", + "حزيران", + "تموز", + "آب", + "أيلول", + "تشرين الأول", + "تشرين الثاني", + "كانون الأول", + ], + monthNamesShort: [ + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "10", + "11", + "12", + ], + dayNames: [ + "السبت", + "الأحد", + "الاثنين", + "الثلاثاء", + "الأربعاء", + "الخميس", + "الجمعة", + ], + dayNamesShort: [ + "سبت", + "أحد", + "اثنين", + "ثلاثاء", + "أربعاء", + "خميس", + "جمعة", + ], + formatString: "%Y-%m-%d %H:%M:%S", + }, + pt: { + monthNames: [ + "Janeiro", + "Fevereiro", + "Março", + "Abril", + "Maio", + "Junho", + "Julho", + "Agosto", + "Setembro", + "Outubro", + "Novembro", + "Dezembro", + ], + monthNamesShort: [ + "Jan", + "Fev", + "Mar", + "Abr", + "Mai", + "Jun", + "Jul", + "Ago", + "Set", + "Out", + "Nov", + "Dez", + ], + dayNames: [ + "Domingo", + "Segunda-feira", + "Terça-feira", + "Quarta-feira", + "Quinta-feira", + "Sexta-feira", + "Sábado", + ], + dayNamesShort: [ + "Dom", + "Seg", + "Ter", + "Qua", + "Qui", + "Sex", + "Sáb", + ], + formatString: "%Y-%m-%d %H:%M:%S", + }, + "pt-BR": { + monthNames: [ + "Janeiro", + "Fevereiro", + "Março", + "Abril", + "Maio", + "Junho", + "Julho", + "Agosto", + "Setembro", + "Outubro", + "Novembro", + "Dezembro", + ], + monthNamesShort: [ + "Jan", + "Fev", + "Mar", + "Abr", + "Mai", + "Jun", + "Jul", + "Ago", + "Set", + "Out", + "Nov", + "Dez", + ], + dayNames: [ + "Domingo", + "Segunda-feira", + "Terça-feira", + "Quarta-feira", + "Quinta-feira", + "Sexta-feira", + "Sábado", + ], + dayNamesShort: [ + "Dom", + "Seg", + "Ter", + "Qua", + "Qui", + "Sex", + "Sáb", + ], + formatString: "%Y-%m-%d %H:%M:%S", + }, + pl: { + monthNames: [ + "Styczeń", + "Luty", + "Marzec", + "Kwiecień", + "Maj", + "Czerwiec", + "Lipiec", + "Sierpień", + "Wrzesień", + "Październik", + "Listopad", + "Grudzień", + ], + monthNamesShort: [ + "Sty", + "Lut", + "Mar", + "Kwi", + "Maj", + "Cze", + "Lip", + "Sie", + "Wrz", + "Paź", + "Lis", + "Gru", + ], + dayNames: [ + "Niedziela", + "Poniedziałek", + "Wtorek", + "Środa", + "Czwartek", + "Piątek", + "Sobota", + ], + dayNamesShort: ["Ni", "Pn", "Wt", "Śr", "Cz", "Pt", "Sb"], + formatString: "%Y-%m-%d %H:%M:%S", + }, + nl: { + monthNames: [ + "Januari", + "Februari", + "Maart", + "April", + "Mei", + "Juni", + "July", + "Augustus", + "September", + "Oktober", + "November", + "December", + ], + monthNamesShort: [ + "Jan", + "Feb", + "Mar", + "Apr", + "Mei", + "Jun", + "Jul", + "Aug", + "Sep", + "Okt", + "Nov", + "Dec", + ], + dayNames: ","[ + ("Zondag", + "Maandag", + "Dinsdag", + "Woensdag", + "Donderdag", + "Vrijdag", + "Zaterdag") + ], + dayNamesShort: ["Zo", "Ma", "Di", "Wo", "Do", "Vr", "Za"], + formatString: "%Y-%m-%d %H:%M:%S", + }, + sv: { + monthNames: [ + "januari", + "februari", + "mars", + "april", + "maj", + "juni", + "juli", + "augusti", + "september", + "oktober", + "november", + "december", + ], + monthNamesShort: [ + "jan", + "feb", + "mar", + "apr", + "maj", + "jun", + "jul", + "aug", + "sep", + "okt", + "nov", + "dec", + ], + dayNames: [ + "söndag", + "måndag", + "tisdag", + "onsdag", + "torsdag", + "fredag", + "lördag", + ], + dayNamesShort: ["sön", "mån", "tis", "ons", "tor", "fre", "lör"], + formatString: "%Y-%m-%d %H:%M:%S", + }, + }; + ag.regional["en-US"] = ag.regional["en-GB"] = ag.regional.en; + ag.regional.getLocale = function () { + var ah = ag.config.defaultLocale; + if ( + document && + document.getElementsByTagName("html") && + document.getElementsByTagName("html")[0].lang + ) { + ah = document.getElementsByTagName("html")[0].lang; + if (!ag.regional.hasOwnProperty(ah)) { + ah = ag.config.defaultLocale; + } + } + return ah; + }; + var C = 24 * 60 * 60 * 1000; + var N = function (ah, ak) { + ah = String(ah); + var ai = ak - ah.length; + var aj = String(Math.pow(10, ai)).slice(1); + return aj.concat(ah); + }; + var E = { + millisecond: 1, + second: 1000, + minute: 60 * 1000, + hour: 60 * 60 * 1000, + day: C, + week: 7 * C, + month: { + add: function (aj, ah) { + E.year.add(aj, Math[ah > 0 ? "floor" : "ceil"](ah / 12)); + var ai = aj.getMonth() + (ah % 12); + if (ai == 12) { + ai = 0; + aj.setYear(aj.getFullYear() + 1); + } else { + if (ai == -1) { + ai = 11; + aj.setYear(aj.getFullYear() - 1); + } + } + aj.setMonth(ai); + }, + diff: function (al, aj) { + var ah = al.getFullYear() - aj.getFullYear(); + var ai = al.getMonth() - aj.getMonth() + ah * 12; + var ak = al.getDate() - aj.getDate(); + return ai + ak / 30; + }, + }, + year: { + add: function (ai, ah) { + ai.setYear( + ai.getFullYear() + Math[ah > 0 ? "floor" : "ceil"](ah), + ); + }, + diff: function (ai, ah) { + return E.month.diff(ai, ah) / 12; + }, + }, + }; + for (var Y in E) { + if (Y.substring(Y.length - 1) != "s") { + E[Y + "s"] = E[Y]; + } + } + var H = function (al, ak, ai) { + if (ag.formats[ai]["shortcuts"][ak]) { + return ag.strftime(al, ag.formats[ai]["shortcuts"][ak], ai); + } else { + var ah = (ag.formats[ai]["codes"][ak] || "").split("."); + var aj = al["get" + ah[0]] ? al["get" + ah[0]]() : ""; + if (ah[1]) { + aj = N(aj, ah[1]); + } + return aj; + } + }; + ag.strftime = function (an, ak, aj, ao) { + var ai = "perl"; + var am = ag.regional.getLocale(); + if (aj && ag.formats.hasOwnProperty(aj)) { + ai = aj; + } else { + if (aj && ag.regional.hasOwnProperty(aj)) { + am = aj; + } + } + if (ao && ag.formats.hasOwnProperty(ao)) { + ai = ao; + } else { + if (ao && ag.regional.hasOwnProperty(ao)) { + am = ao; + } + } + if (l(an) != "[object Object]" || an._type != "jsDate") { + an = new ag(an); + an.locale = am; + } + if (!ak) { + ak = an.formatString || ag.regional[am]["formatString"]; + } + var ah = ak || "%Y-%m-%d", + ap = "", + al; + while (ah.length > 0) { + if ((al = ah.match(ag.formats[ai].codes.matcher))) { + ap += ah.slice(0, al.index); + ap += (al[1] || "") + H(an, al[2], ai); + ah = ah.slice(al.index + al[0].length); + } else { + ap += ah; + ah = ""; + } + } + return ap; + }; + ag.formats = { ISO: "%Y-%m-%dT%H:%M:%S.%N%G", SQL: "%Y-%m-%d %H:%M:%S" }; + ag.formats.perl = { + codes: { + matcher: /()%(#?(%|[a-z]))/i, + Y: "FullYear", + y: "ShortYear.2", + m: "MonthNumber.2", + "#m": "MonthNumber", + B: "MonthName", + b: "AbbrMonthName", + d: "Date.2", + "#d": "Date", + e: "Date", + A: "DayName", + a: "AbbrDayName", + w: "Day", + H: "Hours.2", + "#H": "Hours", + I: "Hours12.2", + "#I": "Hours12", + p: "AMPM", + M: "Minutes.2", + "#M": "Minutes", + S: "Seconds.2", + "#S": "Seconds", + s: "Unix", + N: "Milliseconds.3", + "#N": "Milliseconds", + O: "TimezoneOffset", + Z: "TimezoneName", + G: "GmtOffset", + }, + shortcuts: { + F: "%Y-%m-%d", + T: "%H:%M:%S", + X: "%H:%M:%S", + x: "%m/%d/%y", + D: "%m/%d/%y", + "#c": "%a %b %e %H:%M:%S %Y", + v: "%e-%b-%Y", + R: "%H:%M", + r: "%I:%M:%S %p", + t: "\t", + n: "\n", + "%": "%", + }, + }; + ag.formats.php = { + codes: { + matcher: /()%((%|[a-z]))/i, + a: "AbbrDayName", + A: "DayName", + d: "Date.2", + e: "Date", + j: "DayOfYear.3", + u: "DayOfWeek", + w: "Day", + U: "FullWeekOfYear.2", + V: "IsoWeek.2", + W: "WeekOfYear.2", + b: "AbbrMonthName", + B: "MonthName", + m: "MonthNumber.2", + h: "AbbrMonthName", + C: "Century.2", + y: "ShortYear.2", + Y: "FullYear", + H: "Hours.2", + I: "Hours12.2", + l: "Hours12", + p: "AMPM", + P: "AmPm", + M: "Minutes.2", + S: "Seconds.2", + s: "Unix", + O: "TimezoneOffset", + z: "GmtOffset", + Z: "TimezoneAbbr", + }, + shortcuts: { + D: "%m/%d/%y", + F: "%Y-%m-%d", + T: "%H:%M:%S", + X: "%H:%M:%S", + x: "%m/%d/%y", + R: "%H:%M", + r: "%I:%M:%S %p", + t: "\t", + n: "\n", + "%": "%", + }, + }; + ag.createDate = function (aj) { + if (aj == null) { + return new Date(); + } + if (aj instanceof Date) { + return aj; + } + if (typeof aj == "number") { + return new Date(aj); + } + var ao = String(aj).replace(/^\s*(.+)\s*$/g, "$1"); + ao = ao.replace(/^([0-9]{1,4})-([0-9]{1,2})-([0-9]{1,4})/, "$1/$2/$3"); + ao = ao.replace( + /^(3[01]|[0-2]?\d)[-\/]([a-z]{3,})[-\/](\d{4})/i, + "$1 $2 $3", + ); + var an = ao.match(/^(3[01]|[0-2]?\d)[-\/]([a-z]{3,})[-\/](\d{2})\D*/i); + if (an && an.length > 3) { + var at = parseFloat(an[3]); + var am = ag.config.defaultCentury + at; + am = String(am); + ao = ao.replace( + /^(3[01]|[0-2]?\d)[-\/]([a-z]{3,})[-\/](\d{2})\D*/i, + an[1] + " " + an[2] + " " + am, + ); + } + an = ao.match(/^([0-9]{1,2})[-\/]([0-9]{1,2})[-\/]([0-9]{1,2})[^0-9]/); + function ar(ax, aw) { + var aC = parseFloat(aw[1]); + var aB = parseFloat(aw[2]); + var aA = parseFloat(aw[3]); + var az = ag.config.defaultCentury; + var av, au, aD, ay; + if (aC > 31) { + au = aA; + aD = aB; + av = az + aC; + } else { + au = aB; + aD = aC; + av = az + aA; + } + ay = aD + "/" + au + "/" + av; + return ax.replace( + /^([0-9]{1,2})[-\/]([0-9]{1,2})[-\/]([0-9]{1,2})/, + ay, + ); + } + if (an && an.length > 3) { + ao = ar(ao, an); + } + var an = ao.match(/^([0-9]{1,2})[-\/]([0-9]{1,2})[-\/]([0-9]{1,2})$/); + if (an && an.length > 3) { + ao = ar(ao, an); + } + var al = 0; + var ai = ag.matchers.length; + var aq, + ah, + ap = ao, + ak; + while (al < ai) { + ah = Date.parse(ap); + if (!isNaN(ah)) { + return new Date(ah); + } + aq = ag.matchers[al]; + if (typeof aq == "function") { + ak = aq.call(ag, ap); + if (ak instanceof Date) { + return ak; + } + } else { + ap = ao.replace(aq[0], aq[1]); + } + al++; + } + return NaN; + }; + ag.daysInMonth = function (ah, ai) { + if (ai == 2) { + return new Date(ah, 1, 29).getDate() == 29 ? 29 : 28; + } + return [u, 31, u, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][ai]; + }; + ag.matchers = [ + [/(3[01]|[0-2]\d)\s*\.\s*(1[0-2]|0\d)\s*\.\s*([1-9]\d{3})/, "$2/$1/$3"], + [/([1-9]\d{3})\s*-\s*(1[0-2]|0\d)\s*-\s*(3[01]|[0-2]\d)/, "$2/$3/$1"], + function (ak) { + var ai = ak.match( + /^(?:(.+)\s+)?([012]?\d)(?:\s*\:\s*(\d\d))?(?:\s*\:\s*(\d\d(\.\d*)?))?\s*(am|pm)?\s*$/i, + ); + if (ai) { + if (ai[1]) { + var aj = this.createDate(ai[1]); + if (isNaN(aj)) { + return; + } + } else { + var aj = new Date(); + aj.setMilliseconds(0); + } + var ah = parseFloat(ai[2]); + if (ai[6]) { + ah = + ai[6].toLowerCase() == "am" + ? ah == 12 + ? 0 + : ah + : ah == 12 + ? 12 + : ah + 12; + } + aj.setHours( + ah, + parseInt(ai[3] || 0, 10), + parseInt(ai[4] || 0, 10), + (parseFloat(ai[5] || 0) || 0) * 1000, + ); + return aj; + } else { + return ak; + } + }, + function (ak) { + var ai = ak.match( + /^(?:(.+))[T|\s+]([012]\d)(?:\:(\d\d))(?:\:(\d\d))(?:\.\d+)([\+\-]\d\d\:\d\d)$/i, + ); + if (ai) { + if (ai[1]) { + var aj = this.createDate(ai[1]); + if (isNaN(aj)) { + return; + } + } else { + var aj = new Date(); + aj.setMilliseconds(0); + } + var ah = parseFloat(ai[2]); + aj.setHours( + ah, + parseInt(ai[3], 10), + parseInt(ai[4], 10), + parseFloat(ai[5]) * 1000, + ); + return aj; + } else { + return ak; + } + }, + function (al) { + var aj = al.match( + /^([0-3]?\d)\s*[-\/.\s]{1}\s*([a-zA-Z]{3,9})\s*[-\/.\s]{1}\s*([0-3]?\d)$/, + ); + if (aj) { + var ak = new Date(); + var am = ag.config.defaultCentury; + var ao = parseFloat(aj[1]); + var an = parseFloat(aj[3]); + var ai, ah, ap; + if (ao > 31) { + ah = an; + ai = am + ao; + } else { + ah = ao; + ai = am + an; + } + var ap = ab( + aj[2], + ag.regional[ag.regional.getLocale()]["monthNamesShort"], + ); + if (ap == -1) { + ap = ab( + aj[2], + ag.regional[ag.regional.getLocale()]["monthNames"], + ); + } + ak.setFullYear(ai, ap, ah); + ak.setHours(0, 0, 0, 0); + return ak; + } else { + return al; + } + }, + ]; + function ab(aj, ak) { + if (ak.indexOf) { + return ak.indexOf(aj); + } + for (var ah = 0, ai = ak.length; ah < ai; ah++) { + if (ak[ah] === aj) { + return ah; + } + } + return -1; + } + function l(ah) { + if (ah === null) { + return "[object Null]"; + } + return Object.prototype.toString.call(ah); + } + L.jsDate = ag; + L.jqplot.sprintf = function () { + function an(au, ap, aq, at) { + var ar = + au.length >= ap + ? "" + : Array((1 + ap - au.length) >>> 0).join(aq); + return at ? au + ar : ar + au; + } + function ak(ar) { + var aq = new String(ar); + for (var ap = 10; ap > 0; ap--) { + if ( + aq == + (aq = aq.replace( + /^(\d+)(\d{3})/, + "$1" + L.jqplot.sprintf.thousandsSeparator + "$2", + )) + ) { + break; + } + } + return aq; + } + function aj(av, au, ax, ar, at, aq) { + var aw = ar - av.length; + if (aw > 0) { + var ap = " "; + if (aq) { + ap = " "; + } + if (ax || !at) { + av = an(av, ar, ap, ax); + } else { + av = + av.slice(0, au.length) + + an("", aw, "0", true) + + av.slice(au.length); + } + } + return av; + } + function ao(ay, aq, aw, ar, ap, av, ax, au) { + var at = ay >>> 0; + aw = (aw && at && { 2: "0b", 8: "0", 16: "0x" }[aq]) || ""; + ay = aw + an(at.toString(aq), av || 0, "0", false); + return aj(ay, aw, ar, ap, ax, au); + } + function ah(au, av, ar, ap, at, aq) { + if (ap != null) { + au = au.slice(0, ap); + } + return aj(au, "", av, ar, at, aq); + } + var ai = arguments, + al = 0, + am = ai[al++]; + return am.replace( + L.jqplot.sprintf.regex, + function (aM, ax, ay, aB, aO, aJ, av) { + if (aM == "%%") { + return "%"; + } + var aD = false, + az = "", + aA = false, + aL = false, + aw = false, + au = false; + for (var aI = 0; ay && aI < ay.length; aI++) { + switch (ay.charAt(aI)) { + case " ": + az = " "; + break; + case "+": + az = "+"; + break; + case "-": + aD = true; + break; + case "0": + aA = true; + break; + case "#": + aL = true; + break; + case "&": + aw = true; + break; + case "'": + au = true; + break; + } + } + if (!aB) { + aB = 0; + } else { + if (aB == "*") { + aB = +ai[al++]; + } else { + if (aB.charAt(0) == "*") { + aB = +ai[aB.slice(1, -1)]; + } else { + aB = +aB; + } + } + } + if (aB < 0) { + aB = -aB; + aD = true; + } + if (!isFinite(aB)) { + throw new Error( + "$.jqplot.sprintf: (minimum-)width must be finite", + ); + } + if (!aJ) { + aJ = "fFeE".indexOf(av) > -1 ? 6 : av == "d" ? 0 : void 0; + } else { + if (aJ == "*") { + aJ = +ai[al++]; + } else { + if (aJ.charAt(0) == "*") { + aJ = +ai[aJ.slice(1, -1)]; + } else { + aJ = +aJ; + } + } + } + var aF = ax ? ai[ax.slice(0, -1)] : ai[al++]; + switch (av) { + case "s": + if (aF == null) { + return ""; + } + return ah(String(aF), aD, aB, aJ, aA, aw); + case "c": + return ah(String.fromCharCode(+aF), aD, aB, aJ, aA, aw); + case "b": + return ao(aF, 2, aL, aD, aB, aJ, aA, aw); + case "o": + return ao(aF, 8, aL, aD, aB, aJ, aA, aw); + case "x": + return ao(aF, 16, aL, aD, aB, aJ, aA, aw); + case "X": + return ao(aF, 16, aL, aD, aB, aJ, aA, aw).toUpperCase(); + case "u": + return ao(aF, 10, aL, aD, aB, aJ, aA, aw); + case "i": + var ar = parseInt(+aF, 10); + if (isNaN(ar)) { + return ""; + } + var aH = ar < 0 ? "-" : az; + var aK = au + ? ak(String(Math.abs(ar))) + : String(Math.abs(ar)); + aF = aH + an(aK, aJ, "0", false); + return aj(aF, aH, aD, aB, aA, aw); + case "d": + var ar = Math.round(+aF); + if (isNaN(ar)) { + return ""; + } + var aH = ar < 0 ? "-" : az; + var aK = au + ? ak(String(Math.abs(ar))) + : String(Math.abs(ar)); + aF = aH + an(aK, aJ, "0", false); + return aj(aF, aH, aD, aB, aA, aw); + case "e": + case "E": + case "f": + case "F": + case "g": + case "G": + var ar = +aF; + if (isNaN(ar)) { + return ""; + } + var aH = ar < 0 ? "-" : az; + var at = ["toExponential", "toFixed", "toPrecision"][ + "efg".indexOf(av.toLowerCase()) + ]; + var aN = ["toString", "toUpperCase"][ + "eEfFgG".indexOf(av) % 2 + ]; + var aK = Math.abs(ar)[at](aJ); + var aE = aK.toString().split("."); + aE[0] = au ? ak(aE[0]) : aE[0]; + aK = aE.join(L.jqplot.sprintf.decimalMark); + aF = aH + aK; + var aC = aj(aF, aH, aD, aB, aA, aw)[aN](); + return aC; + case "p": + case "P": + var ar = +aF; + if (isNaN(ar)) { + return ""; + } + var aH = ar < 0 ? "-" : az; + var aE = String( + Number(Math.abs(ar)).toExponential(), + ).split(/e|E/); + var aq = + aE[0].indexOf(".") != -1 + ? aE[0].length - 1 + : String(ar).length; + var aG = aE[1] < 0 ? -aE[1] - 1 : 0; + if (Math.abs(ar) < 1) { + if (aq + aG <= aJ) { + aF = aH + Math.abs(ar).toPrecision(aq); + } else { + if (aq <= aJ - 1) { + aF = + aH + Math.abs(ar).toExponential(aq - 1); + } else { + aF = + aH + Math.abs(ar).toExponential(aJ - 1); + } + } + } else { + var ap = aq <= aJ ? aq : aJ; + aF = aH + Math.abs(ar).toPrecision(ap); + } + var aN = ["toString", "toUpperCase"][ + "pP".indexOf(av) % 2 + ]; + return aj(aF, aH, aD, aB, aA, aw)[aN](); + case "n": + return ""; + default: + return aM; + } + }, + ); + }; + L.jqplot.sprintf.thousandsSeparator = ","; + L.jqplot.sprintf.decimalMark = "."; + L.jqplot.sprintf.regex = + /%%|%(\d+\$)?([-+#0&\' ]*)(\*\d+\$|\*|\d+)?(\.(\*\d+\$|\*|\d+))?([nAscboxXuidfegpEGP])/g; + L.jqplot.getSignificantFigures = function (al) { + var an = String(Number(Math.abs(al)).toExponential()).split(/e|E/); + var am = an[0].indexOf(".") != -1 ? an[0].length - 1 : an[0].length; + var ai = an[1] < 0 ? -an[1] - 1 : 0; + var ah = parseInt(an[1], 10); + var aj = ah + 1 > 0 ? ah + 1 : 0; + var ak = am <= aj ? 0 : am - ah - 1; + return { + significantDigits: am, + digitsLeft: aj, + digitsRight: ak, + zeros: ai, + exponent: ah, + }; + }; + L.jqplot.getPrecision = function (ah) { + return L.jqplot.getSignificantFigures(ah).digitsRight; + }; + var X = L.uiBackCompat !== false; + L.jqplot.effects = { effect: {} }; + var m = "jqplot.storage."; + L.extend(L.jqplot.effects, { + version: "1.9pre", + save: function (ai, aj) { + for (var ah = 0; ah < aj.length; ah++) { + if (aj[ah] !== null) { + ai.data(m + aj[ah], ai[0].style[aj[ah]]); + } + } + }, + restore: function (ai, aj) { + for (var ah = 0; ah < aj.length; ah++) { + if (aj[ah] !== null) { + ai.css(aj[ah], ai.data(m + aj[ah])); + } + } + }, + setMode: function (ah, ai) { + if (ai === "toggle") { + ai = ah.is(":hidden") ? "show" : "hide"; + } + return ai; + }, + createWrapper: function (ai) { + if (ai.parent().is(".ui-effects-wrapper")) { + return ai.parent(); + } + var aj = { + width: ai.outerWidth(true), + height: ai.outerHeight(true), + float: ai.css("float"), + }, + al = L("
").addClass("ui-effects-wrapper").css({ + fontSize: "100%", + background: "transparent", + border: "none", + margin: 0, + padding: 0, + }), + ah = { width: ai.width(), height: ai.height() }, + ak = document.activeElement; + ai.wrap(al); + if (ai[0] === ak || L.contains(ai[0], ak)) { + L(ak).focus(); + } + al = ai.parent(); + if (ai.css("position") === "static") { + al.css({ position: "relative" }); + ai.css({ position: "relative" }); + } else { + L.extend(aj, { + position: ai.css("position"), + zIndex: ai.css("z-index"), + }); + L.each(["top", "left", "bottom", "right"], function (am, an) { + aj[an] = ai.css(an); + if (isNaN(parseInt(aj[an], 10))) { + aj[an] = "auto"; + } + }); + ai.css({ + position: "relative", + top: 0, + left: 0, + right: "auto", + bottom: "auto", + }); + } + ai.css(ah); + return al.css(aj).show(); + }, + removeWrapper: function (ah) { + var ai = document.activeElement; + if (ah.parent().is(".ui-effects-wrapper")) { + ah.parent().replaceWith(ah); + if (ah[0] === ai || L.contains(ah[0], ai)) { + L(ai).focus(); + } + } + return ah; + }, + }); + function j(ai, ah, aj, ak) { + if (L.isPlainObject(ai)) { + return ai; + } + ai = { effect: ai }; + if (ah === u) { + ah = {}; + } + if (L.isFunction(ah)) { + ak = ah; + aj = null; + ah = {}; + } + if (L.type(ah) === "number" || L.fx.speeds[ah]) { + ak = aj; + aj = ah; + ah = {}; + } + if (L.isFunction(aj)) { + ak = aj; + aj = null; + } + if (ah) { + L.extend(ai, ah); + } + aj = aj || ah.duration; + ai.duration = L.fx.off + ? 0 + : typeof aj === "number" + ? aj + : aj in L.fx.speeds + ? L.fx.speeds[aj] + : L.fx.speeds._default; + ai.complete = ak || ah.complete; + return ai; + } + function ae(ah) { + if (!ah || typeof ah === "number" || L.fx.speeds[ah]) { + return true; + } + if (typeof ah === "string" && !L.jqplot.effects.effect[ah]) { + if (X && L.jqplot.effects[ah]) { + return false; + } + return true; + } + return false; + } + L.fn.extend({ + jqplotEffect: function (ap, aq, ai, ao) { + var an = j.apply(this, arguments), + ak = an.mode, + al = an.queue, + am = L.jqplot.effects.effect[an.effect], + ah = !am && X && L.jqplot.effects[an.effect]; + if (L.fx.off || !(am || ah)) { + if (ak) { + return this[ak](an.duration, an.complete); + } else { + return this.each(function () { + if (an.complete) { + an.complete.call(this); + } + }); + } + } + function aj(au) { + var av = L(this), + at = an.complete, + aw = an.mode; + function ar() { + if (L.isFunction(at)) { + at.call(av[0]); + } + if (L.isFunction(au)) { + au(); + } + } + if (av.is(":hidden") ? aw === "hide" : aw === "show") { + ar(); + } else { + am.call(av[0], an, ar); + } + } + if (am) { + return al === false + ? this.each(aj) + : this.queue(al || "fx", aj); + } else { + return ah.call(this, { + options: an, + duration: an.duration, + callback: an.complete, + mode: an.mode, + }); + } + }, + }); + var a = /up|down|vertical/, + v = /up|left|vertical|horizontal/; + L.jqplot.effects.effect.blind = function (aj, ao) { + var ak = L(this), + ar = [ + "position", + "top", + "bottom", + "left", + "right", + "height", + "width", + ], + ap = L.jqplot.effects.setMode(ak, aj.mode || "hide"), + au = aj.direction || "up", + am = a.test(au), + al = am ? "height" : "width", + aq = am ? "top" : "left", + aw = v.test(au), + an = {}, + av = ap === "show", + ai, + ah, + at; + if (ak.parent().is(".ui-effects-wrapper")) { + L.jqplot.effects.save(ak.parent(), ar); + } else { + L.jqplot.effects.save(ak, ar); + } + ak.show(); + at = parseInt(ak.css("top"), 10); + ai = L.jqplot.effects.createWrapper(ak).css({ overflow: "hidden" }); + ah = am ? ai[al]() + at : ai[al](); + an[al] = av ? String(ah) : "0"; + if (!aw) { + ak.css(am ? "bottom" : "right", 0) + .css(am ? "top" : "left", "") + .css({ position: "absolute" }); + an[aq] = av ? "0" : String(ah); + } + if (av) { + ai.css(al, 0); + if (!aw) { + ai.css(aq, ah); + } + } + ai.animate(an, { + duration: aj.duration, + easing: aj.easing, + queue: false, + complete: function () { + if (ap === "hide") { + ak.hide(); + } + L.jqplot.effects.restore(ak, ar); + L.jqplot.effects.removeWrapper(ak); + ao(); + }, + }); + }; +})(jQuery); diff --git a/src/adminactions/static/adminactions/js/jqplot/plugins/jqplot.barRenderer.js b/src/adminactions/static/adminactions/js/jqplot/plugins/jqplot.barRenderer.js index db8707e3..81fe1eee 100644 --- a/src/adminactions/static/adminactions/js/jqplot/plugins/jqplot.barRenderer.js +++ b/src/adminactions/static/adminactions/js/jqplot/plugins/jqplot.barRenderer.js @@ -6,13 +6,13 @@ * Revision: 1250 * * Copyright (c) 2009-2013 Chris Leonello - * jqPlot is currently available for use in all personal or commercial projects - * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL - * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can - * choose the license that best suits your project and use it accordingly. + * jqPlot is currently available for use in all personal or commercial projects + * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL + * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can + * choose the license that best suits your project and use it accordingly. * - * Although not required, the author would appreciate an email letting him - * know of any substantial use of jqPlot. You can reach the author at: + * Although not required, the author would appreciate an email letting him + * know of any substantial use of jqPlot. You can reach the author at: * chris at jqplot dot com or see http://www.jqplot.com/info.php . * * If you are feeling kind and generous, consider supporting the project by @@ -26,23 +26,22 @@ * http://hexmen.com/js/sprintf.js * The author (Ash Searle) has placed this code in the public domain: * "This code is unrestricted: you are free to use it however you like." - * + * */ -(function($) { - +(function ($) { // Class: $.jqplot.BarRenderer // A plugin renderer for jqPlot to draw a bar plot. // Draws series as a line. - - $.jqplot.BarRenderer = function(){ + + $.jqplot.BarRenderer = function () { $.jqplot.LineRenderer.call(this); }; - + $.jqplot.BarRenderer.prototype = new $.jqplot.LineRenderer(); $.jqplot.BarRenderer.prototype.constructor = $.jqplot.BarRenderer; - + // called with scope of series. - $.jqplot.BarRenderer.prototype.init = function(options, plot) { + $.jqplot.BarRenderer.prototype.init = function (options, plot) { // Group: Properties // // prop: barPadding @@ -53,16 +52,16 @@ this.barMargin = 10; // prop: barDirection // 'vertical' = up and down bars, 'horizontal' = side to side bars - this.barDirection = 'vertical'; + this.barDirection = "vertical"; // prop: barWidth // Width of the bar in pixels (auto by devaul). null = calculated automatically. this.barWidth = null; // prop: shadowOffset - // offset of the shadow from the slice and offset of + // offset of the shadow from the slice and offset of // each successive stroke of the shadow from the last. this.shadowOffset = 2; // prop: shadowDepth - // number of strokes to apply to the shadow, + // number of strokes to apply to the shadow, // each stroke offset shadowOffset from the last. this.shadowDepth = 5; // prop: shadowAlpha @@ -94,30 +93,30 @@ // an array of colors to use when highlighting a bar. this.highlightColors = []; // prop: transposedData - // NOT IMPLEMENTED YET. True if this is a horizontal bar plot and - // x and y values are "transposed". Tranposed, or "swapped", data is - // required prior to rev. 894 builds of jqPlot with horizontal bars. - // Allows backward compatability of bar renderer horizontal bars with + // NOT IMPLEMENTED YET. True if this is a horizontal bar plot and + // x and y values are "transposed". Tranposed, or "swapped", data is + // required prior to rev. 894 builds of jqPlot with horizontal bars. + // Allows backward compatability of bar renderer horizontal bars with // old style data sets. this.transposedData = true; this.renderer.animation = { show: false, - direction: 'down', + direction: "down", speed: 3000, - _supported: true + _supported: true, }; - this._type = 'bar'; - + this._type = "bar"; + // if user has passed in highlightMouseDown option and not set highlightMouseOver, disable highlightMouseOver if (options.highlightMouseDown && options.highlightMouseOver == null) { options.highlightMouseOver = false; } - + ////// // This is probably wrong here. // After going back and forth on whether renderer should be the thing // or extend the thing, it seems that it it best if it is a property - // on the thing. This should be something that is commonized + // on the thing. This should be something that is commonized // among series renderers in the future. ////// $.extend(true, this, options); @@ -129,24 +128,27 @@ this.fill = true; // if horizontal bar and animating, reset the default direction - if (this.barDirection === 'horizontal' && this.rendererOptions.animation && this.rendererOptions.animation.direction == null) { - this.renderer.animation.direction = 'left'; + if ( + this.barDirection === "horizontal" && + this.rendererOptions.animation && + this.rendererOptions.animation.direction == null + ) { + this.renderer.animation.direction = "left"; } - + if (this.waterfall) { this.fillToZero = false; this.disableStack = true; } - - if (this.barDirection == 'vertical' ) { - this._primaryAxis = '_xaxis'; - this._stackAxis = 'y'; - this.fillAxis = 'y'; - } - else { - this._primaryAxis = '_yaxis'; - this._stackAxis = 'x'; - this.fillAxis = 'x'; + + if (this.barDirection == "vertical") { + this._primaryAxis = "_xaxis"; + this._stackAxis = "y"; + this.fillAxis = "y"; + } else { + this._primaryAxis = "_yaxis"; + this._stackAxis = "x"; + this.fillAxis = "x"; } // index of the currently highlighted point, if any this._highlightedPoint = null; @@ -155,78 +157,106 @@ // Array of actual data colors used for each data point. this._dataColors = []; this._barPoints = []; - + // set the shape renderer options - var opts = {lineJoin:'miter', lineCap:'round', fill:true, isarc:false, strokeStyle:this.color, fillStyle:this.color, closePath:this.fill}; + var opts = { + lineJoin: "miter", + lineCap: "round", + fill: true, + isarc: false, + strokeStyle: this.color, + fillStyle: this.color, + closePath: this.fill, + }; this.renderer.shapeRenderer.init(opts); // set the shadow renderer options - var sopts = {lineJoin:'miter', lineCap:'round', fill:true, isarc:false, angle:this.shadowAngle, offset:this.shadowOffset, alpha:this.shadowAlpha, depth:this.shadowDepth, closePath:this.fill}; + var sopts = { + lineJoin: "miter", + lineCap: "round", + fill: true, + isarc: false, + angle: this.shadowAngle, + offset: this.shadowOffset, + alpha: this.shadowAlpha, + depth: this.shadowDepth, + closePath: this.fill, + }; this.renderer.shadowRenderer.init(sopts); - + plot.postInitHooks.addOnce(postInit); plot.postDrawHooks.addOnce(postPlotDraw); - plot.eventListenerHooks.addOnce('jqplotMouseMove', handleMove); - plot.eventListenerHooks.addOnce('jqplotMouseDown', handleMouseDown); - plot.eventListenerHooks.addOnce('jqplotMouseUp', handleMouseUp); - plot.eventListenerHooks.addOnce('jqplotClick', handleClick); - plot.eventListenerHooks.addOnce('jqplotRightClick', handleRightClick); + plot.eventListenerHooks.addOnce("jqplotMouseMove", handleMove); + plot.eventListenerHooks.addOnce("jqplotMouseDown", handleMouseDown); + plot.eventListenerHooks.addOnce("jqplotMouseUp", handleMouseUp); + plot.eventListenerHooks.addOnce("jqplotClick", handleClick); + plot.eventListenerHooks.addOnce("jqplotRightClick", handleRightClick); }; - + // called with scope of series function barPreInit(target, data, seriesDefaults, options) { - if (this.rendererOptions.barDirection == 'horizontal') { - this._stackAxis = 'x'; - this._primaryAxis = '_yaxis'; + if (this.rendererOptions.barDirection == "horizontal") { + this._stackAxis = "x"; + this._primaryAxis = "_yaxis"; } if (this.rendererOptions.waterfall == true) { this._data = $.extend(true, [], this.data); var sum = 0; - var pos = (!this.rendererOptions.barDirection || this.rendererOptions.barDirection === 'vertical' || this.transposedData === false) ? 1 : 0; - for(var i=0; i0) { - this.data[i][pos] += this.data[i-1][pos]; + if (i > 0) { + this.data[i][pos] += this.data[i - 1][pos]; } } - this.data[this.data.length] = (pos == 1) ? [this.data.length+1, sum] : [sum, this.data.length+1]; - this._data[this._data.length] = (pos == 1) ? [this._data.length+1, sum] : [sum, this._data.length+1]; + this.data[this.data.length] = + pos == 1 + ? [this.data.length + 1, sum] + : [sum, this.data.length + 1]; + this._data[this._data.length] = + pos == 1 + ? [this._data.length + 1, sum] + : [sum, this._data.length + 1]; } if (this.rendererOptions.groups > 1) { this.breakOnNull = true; var l = this.data.length; - var skip = parseInt(l/this.rendererOptions.groups, 10); + var skip = parseInt(l / this.rendererOptions.groups, 10); var count = 0; - for (var i=skip; i 570) ? newrgb[j] * 0.8 : newrgb[j] + 0.3 * (255 - newrgb[j]); + newrgb[j] = + sum > 570 + ? newrgb[j] * 0.8 + : newrgb[j] + 0.3 * (255 - newrgb[j]); newrgb[j] = parseInt(newrgb[j], 10); } - ret.push('rgb('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+')'); + ret.push( + "rgb(" + newrgb[0] + "," + newrgb[1] + "," + newrgb[2] + ")", + ); } return ret; } @@ -298,14 +345,14 @@ prevSeriesIndex = sidx - 1, start, prevVal, - aidx = (axis === 'x') ? 0 : 1; + aidx = axis === "x" ? 0 : 1; // is this not the first series? if (seriesIndex > 0) { prevVal = plot.series[prevSeriesIndex]._plotData[didx][aidx]; // is there a sign change - if ((comp * prevVal) < 0) { + if (comp * prevVal < 0) { start = getStart(prevSeriesIndex, didx, comp, plot, axis); } @@ -313,26 +360,32 @@ else { start = plot.series[prevSeriesIndex].gridData[didx][aidx]; } - } // if first series, return value at 0 else { - - start = (aidx === 0) ? plot.series[seriesIndex]._xaxis.series_u2p(0) : plot.series[seriesIndex]._yaxis.series_u2p(0); + start = + aidx === 0 + ? plot.series[seriesIndex]._xaxis.series_u2p(0) + : plot.series[seriesIndex]._yaxis.series_u2p(0); } return start; } - - $.jqplot.BarRenderer.prototype.draw = function(ctx, gridData, options, plot) { + $.jqplot.BarRenderer.prototype.draw = function ( + ctx, + gridData, + options, + plot, + ) { var i; // Ughhh, have to make a copy of options b/c it may be modified later. var opts = $.extend({}, options); - var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow; - var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine; - var fill = (opts.fill != undefined) ? opts.fill : this.fill; + var shadow = opts.shadow != undefined ? opts.shadow : this.shadow; + var showLine = + opts.showLine != undefined ? opts.showLine : this.showLine; + var fill = opts.fill != undefined ? opts.fill : this.fill; var xaxis = this.xaxis; var yaxis = this.yaxis; var xp = this._xaxis.series_u2p; @@ -341,116 +394,128 @@ // clear out data colors. this._dataColors = []; this._barPoints = []; - + if (this.barWidth == null) { this.renderer.setBarWidth.call(this); } - - var temp = this._plotSeriesInfo = this.renderer.calcSeriesNumbers.call(this); + + var temp = (this._plotSeriesInfo = + this.renderer.calcSeriesNumbers.call(this)); var nvals = temp[0]; var nseries = temp[1]; var pos = temp[2]; var points = []; - + if (this._stack) { this._barNudge = 0; - } - else { - this._barNudge = (-Math.abs(nseries/2 - 0.5) + pos) * (this.barWidth + this.barPadding); + } else { + this._barNudge = + (-Math.abs(nseries / 2 - 0.5) + pos) * + (this.barWidth + this.barPadding); } if (showLine) { - var negativeColors = new $.jqplot.ColorGenerator(this.negativeSeriesColors); + var negativeColors = new $.jqplot.ColorGenerator( + this.negativeSeriesColors, + ); var positiveColors = new $.jqplot.ColorGenerator(this.seriesColors); var negativeColor = negativeColors.get(this.index); - if (! this.useNegativeColors) { + if (!this.useNegativeColors) { negativeColor = opts.fillStyle; } var positiveColor = opts.fillStyle; var base; - var xstart; + var xstart; var ystart; - - if (this.barDirection == 'vertical') { - for (var i=0; i 0 && i < this.gridData.length-1) { - ystart = this.gridData[i-1][1]; - } - else if (this.waterfall && i == 0 && i < this.gridData.length-1) { + } else if ( + this.waterfall && + i > 0 && + i < this.gridData.length - 1 + ) { + ystart = this.gridData[i - 1][1]; + } else if ( + this.waterfall && + i == 0 && + i < this.gridData.length - 1 + ) { if (this._yaxis.min <= 0 && this._yaxis.max >= 0) { ystart = this._yaxis.series_u2p(0); - } - else if (this._yaxis.min > 0) { + } else if (this._yaxis.min > 0) { ystart = ctx.canvas.height; - } - else { + } else { ystart = 0; } - } - else if (this.waterfall && i == this.gridData.length - 1) { + } else if ( + this.waterfall && + i == this.gridData.length - 1 + ) { if (this._yaxis.min <= 0 && this._yaxis.max >= 0) { ystart = this._yaxis.series_u2p(0); - } - else if (this._yaxis.min > 0) { + } else if (this._yaxis.min > 0) { ystart = ctx.canvas.height; - } - else { + } else { ystart = 0; } - } - else { + } else { ystart = ctx.canvas.height; } } - if ((this.fillToZero && this._plotData[i][1] < 0) || (this.waterfall && this._data[i][1] < 0)) { + if ( + (this.fillToZero && this._plotData[i][1] < 0) || + (this.waterfall && this._data[i][1] < 0) + ) { if (this.varyBarColor && !this._stack) { if (this.useNegativeColors) { opts.fillStyle = negativeColors.next(); - } - else { + } else { opts.fillStyle = positiveColors.next(); } - } - else { + } else { opts.fillStyle = negativeColor; } - } - else { + } else { if (this.varyBarColor && !this._stack) { opts.fillStyle = positiveColors.next(); - } - else { + } else { opts.fillStyle = positiveColor; } } - - if (!this.fillToZero || this._plotData[i][1] >= 0) { - points.push([base-this.barWidth/2, ystart]); - points.push([base-this.barWidth/2, gridData[i][1]]); - points.push([base+this.barWidth/2, gridData[i][1]]); - points.push([base+this.barWidth/2, ystart]); + + if (!this.fillToZero || this._plotData[i][1] >= 0) { + points.push([base - this.barWidth / 2, ystart]); + points.push([base - this.barWidth / 2, gridData[i][1]]); + points.push([base + this.barWidth / 2, gridData[i][1]]); + points.push([base + this.barWidth / 2, ystart]); } // for negative bars make sure points are always ordered clockwise - else { - points.push([base-this.barWidth/2, gridData[i][1]]); - points.push([base-this.barWidth/2, ystart]); - points.push([base+this.barWidth/2, ystart]); - points.push([base+this.barWidth/2, gridData[i][1]]); + else { + points.push([base - this.barWidth / 2, gridData[i][1]]); + points.push([base - this.barWidth / 2, ystart]); + points.push([base + this.barWidth / 2, ystart]); + points.push([base + this.barWidth / 2, gridData[i][1]]); } this._barPoints.push(points); // now draw the shadows if not stacked. @@ -463,86 +528,90 @@ } var clr = opts.fillStyle || this.color; this._dataColors.push(clr); - this.renderer.shapeRenderer.draw(ctx, points, opts); + this.renderer.shapeRenderer.draw(ctx, points, opts); } - } - - else if (this.barDirection == 'horizontal'){ - for (var i=0; i 0 && i < this.gridData.length-1) { - xstart = this.gridData[i-1][0]; - } - else if (this.waterfall && i == 0 && i < this.gridData.length-1) { + } else if ( + this.waterfall && + i > 0 && + i < this.gridData.length - 1 + ) { + xstart = this.gridData[i - 1][0]; + } else if ( + this.waterfall && + i == 0 && + i < this.gridData.length - 1 + ) { if (this._xaxis.min <= 0 && this._xaxis.max >= 0) { xstart = this._xaxis.series_u2p(0); - } - else if (this._xaxis.min > 0) { + } else if (this._xaxis.min > 0) { xstart = 0; - } - else { + } else { xstart = 0; } - } - else if (this.waterfall && i == this.gridData.length - 1) { + } else if ( + this.waterfall && + i == this.gridData.length - 1 + ) { if (this._xaxis.min <= 0 && this._xaxis.max >= 0) { xstart = this._xaxis.series_u2p(0); - } - else if (this._xaxis.min > 0) { + } else if (this._xaxis.min > 0) { xstart = 0; - } - else { + } else { xstart = ctx.canvas.width; } - } - else { + } else { xstart = 0; } } - if ((this.fillToZero && this._plotData[i][0] < 0) || (this.waterfall && this._data[i][0] < 0)) { + if ( + (this.fillToZero && this._plotData[i][0] < 0) || + (this.waterfall && this._data[i][0] < 0) + ) { if (this.varyBarColor && !this._stack) { if (this.useNegativeColors) { opts.fillStyle = negativeColors.next(); - } - else { + } else { opts.fillStyle = positiveColors.next(); } - } - else { + } else { opts.fillStyle = negativeColor; } - } - else { + } else { if (this.varyBarColor && !this._stack) { opts.fillStyle = positiveColors.next(); - } - else { + } else { opts.fillStyle = positiveColor; - } + } } - if (!this.fillToZero || this._plotData[i][0] >= 0) { points.push([xstart, base + this.barWidth / 2]); points.push([xstart, base - this.barWidth / 2]); points.push([gridData[i][0], base - this.barWidth / 2]); points.push([gridData[i][0], base + this.barWidth / 2]); - } - else { + } else { points.push([gridData[i][0], base + this.barWidth / 2]); points.push([gridData[i][0], base - this.barWidth / 2]); points.push([xstart, base - this.barWidth / 2]); @@ -560,120 +629,130 @@ var clr = opts.fillStyle || this.color; this._dataColors.push(clr); this.renderer.shapeRenderer.draw(ctx, points, opts); - } + } } - } - - if (this.highlightColors.length == 0) { - this.highlightColors = $.jqplot.computeHighlightColors(this._dataColors); } - - else if (typeof(this.highlightColors) == 'string') { + + if (this.highlightColors.length == 0) { + this.highlightColors = $.jqplot.computeHighlightColors( + this._dataColors, + ); + } else if (typeof this.highlightColors == "string") { var temp = this.highlightColors; this.highlightColors = []; - for (var i=0; i0){this.data[q][u]+=this.data[q-1][u]}}this.data[this.data.length]=(u==1)?[this.data.length+1,s]:[s,this.data.length+1];this._data[this._data.length]=(u==1)?[this._data.length+1,s]:[s,this._data.length+1]}if(this.rendererOptions.groups>1){this.breakOnNull=true;var n=this.data.length;var v=parseInt(n/this.rendererOptions.groups,10);var r=0;for(var q=v;q570)?n[p]*0.8:n[p]+0.3*(255-n[p]);n[p]=parseInt(n[p],10)}q.push("rgb("+n[0]+","+n[1]+","+n[2]+")")}return q}function i(v,u,s,t,o){var q=v,w=v-1,n,p,r=(o==="x")?0:1;if(q>0){p=t.series[w]._plotData[u][r];if((s*p)<0){n=i(w,u,s,t,o)}else{n=t.series[w].gridData[u][r]}}else{n=(r===0)?t.series[q]._xaxis.series_u2p(0):t.series[q]._yaxis.series_u2p(0)}return n}d.jqplot.BarRenderer.prototype.draw=function(E,L,q,G){var I;var A=d.extend({},q);var w=(A.shadow!=undefined)?A.shadow:this.shadow;var O=(A.showLine!=undefined)?A.showLine:this.showLine;var F=(A.fill!=undefined)?A.fill:this.fill;var p=this.xaxis;var J=this.yaxis;var y=this._xaxis.series_u2p;var K=this._yaxis.series_u2p;var D,C;this._dataColors=[];this._barPoints=[];if(this.barWidth==null){this.renderer.setBarWidth.call(this)}var N=this._plotSeriesInfo=this.renderer.calcSeriesNumbers.call(this);var x=N[0];var v=N[1];var s=N[2];var H=[];if(this._stack){this._barNudge=0}else{this._barNudge=(-Math.abs(v/2-0.5)+s)*(this.barWidth+this.barPadding)}if(O){var u=new d.jqplot.ColorGenerator(this.negativeSeriesColors);var B=new d.jqplot.ColorGenerator(this.seriesColors);var M=u.get(this.index);if(!this.useNegativeColors){M=A.fillStyle}var t=A.fillStyle;var r;var P;var o;if(this.barDirection=="vertical"){for(var I=0;I0&&I=0){o=this._yaxis.series_u2p(0)}else{if(this._yaxis.min>0){o=E.canvas.height}else{o=0}}}else{if(this.waterfall&&I==this.gridData.length-1){if(this._yaxis.min<=0&&this._yaxis.max>=0){o=this._yaxis.series_u2p(0)}else{if(this._yaxis.min>0){o=E.canvas.height}else{o=0}}}else{o=E.canvas.height}}}}}if((this.fillToZero&&this._plotData[I][1]<0)||(this.waterfall&&this._data[I][1]<0)){if(this.varyBarColor&&!this._stack){if(this.useNegativeColors){A.fillStyle=u.next()}else{A.fillStyle=B.next()}}else{A.fillStyle=M}}else{if(this.varyBarColor&&!this._stack){A.fillStyle=B.next()}else{A.fillStyle=t}}if(!this.fillToZero||this._plotData[I][1]>=0){H.push([r-this.barWidth/2,o]);H.push([r-this.barWidth/2,L[I][1]]);H.push([r+this.barWidth/2,L[I][1]]);H.push([r+this.barWidth/2,o])}else{H.push([r-this.barWidth/2,L[I][1]]);H.push([r-this.barWidth/2,o]);H.push([r+this.barWidth/2,o]);H.push([r+this.barWidth/2,L[I][1]])}this._barPoints.push(H);if(w&&!this._stack){var z=d.extend(true,{},A);delete z.fillStyle;this.renderer.shadowRenderer.draw(E,H,z)}var n=A.fillStyle||this.color;this._dataColors.push(n);this.renderer.shapeRenderer.draw(E,H,A)}}else{if(this.barDirection=="horizontal"){for(var I=0;I0&&I=0){P=this._xaxis.series_u2p(0)}else{if(this._xaxis.min>0){P=0}else{P=0}}}else{if(this.waterfall&&I==this.gridData.length-1){if(this._xaxis.min<=0&&this._xaxis.max>=0){P=this._xaxis.series_u2p(0)}else{if(this._xaxis.min>0){P=0}else{P=E.canvas.width}}}else{P=0}}}}}if((this.fillToZero&&this._plotData[I][0]<0)||(this.waterfall&&this._data[I][0]<0)){if(this.varyBarColor&&!this._stack){if(this.useNegativeColors){A.fillStyle=u.next()}else{A.fillStyle=B.next()}}else{A.fillStyle=M}}else{if(this.varyBarColor&&!this._stack){A.fillStyle=B.next()}else{A.fillStyle=t}}if(!this.fillToZero||this._plotData[I][0]>=0){H.push([P,r+this.barWidth/2]);H.push([P,r-this.barWidth/2]);H.push([L[I][0],r-this.barWidth/2]);H.push([L[I][0],r+this.barWidth/2])}else{H.push([L[I][0],r+this.barWidth/2]);H.push([L[I][0],r-this.barWidth/2]);H.push([P,r-this.barWidth/2]);H.push([P,r+this.barWidth/2])}this._barPoints.push(H);if(w&&!this._stack){var z=d.extend(true,{},A);delete z.fillStyle;this.renderer.shadowRenderer.draw(E,H,z)}var n=A.fillStyle||this.color;this._dataColors.push(n);this.renderer.shapeRenderer.draw(E,H,A)}}}}if(this.highlightColors.length==0){this.highlightColors=d.jqplot.computeHighlightColors(this._dataColors)}else{if(typeof(this.highlightColors)=="string"){var N=this.highlightColors;this.highlightColors=[];for(var I=0;I 0) { + this.data[q][u] += this.data[q - 1][u]; + } + } + this.data[this.data.length] = + u == 1 ? [this.data.length + 1, s] : [s, this.data.length + 1]; + this._data[this._data.length] = + u == 1 + ? [this._data.length + 1, s] + : [s, this._data.length + 1]; + } + if (this.rendererOptions.groups > 1) { + this.breakOnNull = true; + var n = this.data.length; + var v = parseInt(n / this.rendererOptions.groups, 10); + var r = 0; + for (var q = v; q < n; q += v) { + this.data.splice(q + r, 0, [null, null]); + this._plotData.splice(q + r, 0, [null, null]); + this._stackData.splice(q + r, 0, [null, null]); + r++; + } + for (q = 0; q < this.data.length; q++) { + if (this._primaryAxis == "_xaxis") { + this.data[q][0] = q + 1; + this._plotData[q][0] = q + 1; + this._stackData[q][0] = q + 1; + } else { + this.data[q][1] = q + 1; + this._plotData[q][1] = q + 1; + this._stackData[q][1] = q + 1; + } + } + } + } + d.jqplot.preSeriesInitHooks.push(g); + d.jqplot.BarRenderer.prototype.calcSeriesNumbers = function () { + var r = 0; + var t = 0; + var q = this[this._primaryAxis]; + var p, o, u; + for (var n = 0; n < q._series.length; n++) { + o = q._series[n]; + if (o === this) { + u = n; + } + if (o.renderer.constructor == d.jqplot.BarRenderer) { + r += o.data.length; + t += 1; + } + } + return [r, t, u]; + }; + d.jqplot.BarRenderer.prototype.setBarWidth = function () { + var q; + var n = 0; + var o = 0; + var t = this[this._primaryAxis]; + var x, r, v; + var w = (this._plotSeriesInfo = + this.renderer.calcSeriesNumbers.call(this)); + n = w[0]; + o = w[1]; + var u = t.numberTicks; + var p = (u - 1) / 2; + if (t.name == "xaxis" || t.name == "x2axis") { + if (this._stack) { + this.barWidth = + ((t._offsets.max - t._offsets.min) / n) * o - + this.barMargin; + } else { + this.barWidth = + ((t._offsets.max - t._offsets.min) / p - + this.barPadding * (o - 1) - + this.barMargin * 2) / + o; + } + } else { + if (this._stack) { + this.barWidth = + ((t._offsets.min - t._offsets.max) / n) * o - + this.barMargin; + } else { + this.barWidth = + ((t._offsets.min - t._offsets.max) / p - + this.barPadding * (o - 1) - + this.barMargin * 2) / + o; + } + } + return [n, o]; + }; + function f(o) { + var q = []; + for (var s = 0; s < o.length; s++) { + var r = d.jqplot.getColorComponents(o[s]); + var n = [r[0], r[1], r[2]]; + var t = n[0] + n[1] + n[2]; + for (var p = 0; p < 3; p++) { + n[p] = t > 570 ? n[p] * 0.8 : n[p] + 0.3 * (255 - n[p]); + n[p] = parseInt(n[p], 10); + } + q.push("rgb(" + n[0] + "," + n[1] + "," + n[2] + ")"); + } + return q; + } + function i(v, u, s, t, o) { + var q = v, + w = v - 1, + n, + p, + r = o === "x" ? 0 : 1; + if (q > 0) { + p = t.series[w]._plotData[u][r]; + if (s * p < 0) { + n = i(w, u, s, t, o); + } else { + n = t.series[w].gridData[u][r]; + } + } else { + n = + r === 0 + ? t.series[q]._xaxis.series_u2p(0) + : t.series[q]._yaxis.series_u2p(0); + } + return n; + } + d.jqplot.BarRenderer.prototype.draw = function (E, L, q, G) { + var I; + var A = d.extend({}, q); + var w = A.shadow != undefined ? A.shadow : this.shadow; + var O = A.showLine != undefined ? A.showLine : this.showLine; + var F = A.fill != undefined ? A.fill : this.fill; + var p = this.xaxis; + var J = this.yaxis; + var y = this._xaxis.series_u2p; + var K = this._yaxis.series_u2p; + var D, C; + this._dataColors = []; + this._barPoints = []; + if (this.barWidth == null) { + this.renderer.setBarWidth.call(this); + } + var N = (this._plotSeriesInfo = + this.renderer.calcSeriesNumbers.call(this)); + var x = N[0]; + var v = N[1]; + var s = N[2]; + var H = []; + if (this._stack) { + this._barNudge = 0; + } else { + this._barNudge = + (-Math.abs(v / 2 - 0.5) + s) * + (this.barWidth + this.barPadding); + } + if (O) { + var u = new d.jqplot.ColorGenerator(this.negativeSeriesColors); + var B = new d.jqplot.ColorGenerator(this.seriesColors); + var M = u.get(this.index); + if (!this.useNegativeColors) { + M = A.fillStyle; + } + var t = A.fillStyle; + var r; + var P; + var o; + if (this.barDirection == "vertical") { + for (var I = 0; I < L.length; I++) { + if (!this._stack && this.data[I][1] == null) { + continue; + } + H = []; + r = L[I][0] + this._barNudge; + if (this._stack && this._prevGridData.length) { + o = i(this.index, I, this._plotData[I][1], G, "y"); + } else { + if (this.fillToZero) { + o = this._yaxis.series_u2p(0); + } else { + if ( + this.waterfall && + I > 0 && + I < this.gridData.length - 1 + ) { + o = this.gridData[I - 1][1]; + } else { + if ( + this.waterfall && + I == 0 && + I < this.gridData.length - 1 + ) { + if ( + this._yaxis.min <= 0 && + this._yaxis.max >= 0 + ) { + o = this._yaxis.series_u2p(0); + } else { + if (this._yaxis.min > 0) { + o = E.canvas.height; + } else { + o = 0; + } + } + } else { + if ( + this.waterfall && + I == this.gridData.length - 1 + ) { + if ( + this._yaxis.min <= 0 && + this._yaxis.max >= 0 + ) { + o = this._yaxis.series_u2p(0); + } else { + if (this._yaxis.min > 0) { + o = E.canvas.height; + } else { + o = 0; + } + } + } else { + o = E.canvas.height; + } + } + } + } + } + if ( + (this.fillToZero && this._plotData[I][1] < 0) || + (this.waterfall && this._data[I][1] < 0) + ) { + if (this.varyBarColor && !this._stack) { + if (this.useNegativeColors) { + A.fillStyle = u.next(); + } else { + A.fillStyle = B.next(); + } + } else { + A.fillStyle = M; + } + } else { + if (this.varyBarColor && !this._stack) { + A.fillStyle = B.next(); + } else { + A.fillStyle = t; + } + } + if (!this.fillToZero || this._plotData[I][1] >= 0) { + H.push([r - this.barWidth / 2, o]); + H.push([r - this.barWidth / 2, L[I][1]]); + H.push([r + this.barWidth / 2, L[I][1]]); + H.push([r + this.barWidth / 2, o]); + } else { + H.push([r - this.barWidth / 2, L[I][1]]); + H.push([r - this.barWidth / 2, o]); + H.push([r + this.barWidth / 2, o]); + H.push([r + this.barWidth / 2, L[I][1]]); + } + this._barPoints.push(H); + if (w && !this._stack) { + var z = d.extend(true, {}, A); + delete z.fillStyle; + this.renderer.shadowRenderer.draw(E, H, z); + } + var n = A.fillStyle || this.color; + this._dataColors.push(n); + this.renderer.shapeRenderer.draw(E, H, A); + } + } else { + if (this.barDirection == "horizontal") { + for (var I = 0; I < L.length; I++) { + if (!this._stack && this.data[I][0] == null) { + continue; + } + H = []; + r = L[I][1] - this._barNudge; + P; + if (this._stack && this._prevGridData.length) { + P = i(this.index, I, this._plotData[I][0], G, "x"); + } else { + if (this.fillToZero) { + P = this._xaxis.series_u2p(0); + } else { + if ( + this.waterfall && + I > 0 && + I < this.gridData.length - 1 + ) { + P = this.gridData[I - 1][0]; + } else { + if ( + this.waterfall && + I == 0 && + I < this.gridData.length - 1 + ) { + if ( + this._xaxis.min <= 0 && + this._xaxis.max >= 0 + ) { + P = this._xaxis.series_u2p(0); + } else { + if (this._xaxis.min > 0) { + P = 0; + } else { + P = 0; + } + } + } else { + if ( + this.waterfall && + I == this.gridData.length - 1 + ) { + if ( + this._xaxis.min <= 0 && + this._xaxis.max >= 0 + ) { + P = this._xaxis.series_u2p(0); + } else { + if (this._xaxis.min > 0) { + P = 0; + } else { + P = E.canvas.width; + } + } + } else { + P = 0; + } + } + } + } + } + if ( + (this.fillToZero && this._plotData[I][0] < 0) || + (this.waterfall && this._data[I][0] < 0) + ) { + if (this.varyBarColor && !this._stack) { + if (this.useNegativeColors) { + A.fillStyle = u.next(); + } else { + A.fillStyle = B.next(); + } + } else { + A.fillStyle = M; + } + } else { + if (this.varyBarColor && !this._stack) { + A.fillStyle = B.next(); + } else { + A.fillStyle = t; + } + } + if (!this.fillToZero || this._plotData[I][0] >= 0) { + H.push([P, r + this.barWidth / 2]); + H.push([P, r - this.barWidth / 2]); + H.push([L[I][0], r - this.barWidth / 2]); + H.push([L[I][0], r + this.barWidth / 2]); + } else { + H.push([L[I][0], r + this.barWidth / 2]); + H.push([L[I][0], r - this.barWidth / 2]); + H.push([P, r - this.barWidth / 2]); + H.push([P, r + this.barWidth / 2]); + } + this._barPoints.push(H); + if (w && !this._stack) { + var z = d.extend(true, {}, A); + delete z.fillStyle; + this.renderer.shadowRenderer.draw(E, H, z); + } + var n = A.fillStyle || this.color; + this._dataColors.push(n); + this.renderer.shapeRenderer.draw(E, H, A); + } + } + } + } + if (this.highlightColors.length == 0) { + this.highlightColors = d.jqplot.computeHighlightColors( + this._dataColors, + ); + } else { + if (typeof this.highlightColors == "string") { + var N = this.highlightColors; + this.highlightColors = []; + for (var I = 0; I < this._dataColors.length; I++) { + this.highlightColors.push(N); + } + } + } + }; + d.jqplot.BarRenderer.prototype.drawShadow = function (z, G, p, B) { + var D; + var w = p != undefined ? p : {}; + var t = w.shadow != undefined ? w.shadow : this.shadow; + var I = w.showLine != undefined ? w.showLine : this.showLine; + var A = w.fill != undefined ? w.fill : this.fill; + var o = this.xaxis; + var E = this.yaxis; + var v = this._xaxis.series_u2p; + var F = this._yaxis.series_u2p; + var y, C, x, u, s, r; + if (this._stack && this.shadow) { + if (this.barWidth == null) { + this.renderer.setBarWidth.call(this); + } + var H = (this._plotSeriesInfo = + this.renderer.calcSeriesNumbers.call(this)); + u = H[0]; + s = H[1]; + r = H[2]; + if (this._stack) { + this._barNudge = 0; + } else { + this._barNudge = + (-Math.abs(s / 2 - 0.5) + r) * + (this.barWidth + this.barPadding); + } + if (I) { + if (this.barDirection == "vertical") { + for (var D = 0; D < G.length; D++) { + if (this.data[D][1] == null) { + continue; + } + C = []; + var q = G[D][0] + this._barNudge; + var n; + if (this._stack && this._prevGridData.length) { + n = i(this.index, D, this._plotData[D][1], B, "y"); + } else { + if (this.fillToZero) { + n = this._yaxis.series_u2p(0); + } else { + n = z.canvas.height; + } + } + C.push([q - this.barWidth / 2, n]); + C.push([q - this.barWidth / 2, G[D][1]]); + C.push([q + this.barWidth / 2, G[D][1]]); + C.push([q + this.barWidth / 2, n]); + this.renderer.shadowRenderer.draw(z, C, w); + } + } else { + if (this.barDirection == "horizontal") { + for (var D = 0; D < G.length; D++) { + if (this.data[D][0] == null) { + continue; + } + C = []; + var q = G[D][1] - this._barNudge; + var J; + if (this._stack && this._prevGridData.length) { + J = i( + this.index, + D, + this._plotData[D][0], + B, + "x", + ); + } else { + if (this.fillToZero) { + J = this._xaxis.series_u2p(0); + } else { + J = 0; + } + } + C.push([J, q + this.barWidth / 2]); + C.push([G[D][0], q + this.barWidth / 2]); + C.push([G[D][0], q - this.barWidth / 2]); + C.push([J, q - this.barWidth / 2]); + this.renderer.shadowRenderer.draw(z, C, w); + } + } + } + } + } + }; + function h(q, p, n) { + for (var o = 0; o < this.series.length; o++) { + if (this.series[o].renderer.constructor == d.jqplot.BarRenderer) { + if (this.series[o].highlightMouseOver) { + this.series[o].highlightMouseDown = false; + } + } + } + } + function j() { + if ( + this.plugins.barRenderer && + this.plugins.barRenderer.highlightCanvas + ) { + this.plugins.barRenderer.highlightCanvas.resetCanvas(); + this.plugins.barRenderer.highlightCanvas = null; + } + this.plugins.barRenderer = { highlightedSeriesIndex: null }; + this.plugins.barRenderer.highlightCanvas = new d.jqplot.GenericCanvas(); + this.eventCanvas._elem.before( + this.plugins.barRenderer.highlightCanvas.createElement( + this._gridPadding, + "jqplot-barRenderer-highlight-canvas", + this._plotDimensions, + this, + ), + ); + this.plugins.barRenderer.highlightCanvas.setContext(); + this.eventCanvas._elem.bind("mouseleave", { plot: this }, function (n) { + k(n.data.plot); + }); + } + function c(u, t, q, p) { + var o = u.series[t]; + var n = u.plugins.barRenderer.highlightCanvas; + n._ctx.clearRect(0, 0, n._ctx.canvas.width, n._ctx.canvas.height); + o._highlightedPoint = q; + u.plugins.barRenderer.highlightedSeriesIndex = t; + var r = { fillStyle: o.highlightColors[q] }; + o.renderer.shapeRenderer.draw(n._ctx, p, r); + n = null; + } + function k(p) { + var n = p.plugins.barRenderer.highlightCanvas; + n._ctx.clearRect(0, 0, n._ctx.canvas.width, n._ctx.canvas.height); + for (var o = 0; o < p.series.length; o++) { + p.series[o]._highlightedPoint = null; + } + p.plugins.barRenderer.highlightedSeriesIndex = null; + p.target.trigger("jqplotDataUnhighlight"); + n = null; + } + function b(r, q, u, t, s) { + if (t) { + var p = [t.seriesIndex, t.pointIndex, t.data]; + var o = jQuery.Event("jqplotDataMouseOver"); + o.pageX = r.pageX; + o.pageY = r.pageY; + s.target.trigger(o, p); + if ( + s.series[p[0]].show && + s.series[p[0]].highlightMouseOver && + !( + p[0] == s.plugins.barRenderer.highlightedSeriesIndex && + p[1] == s.series[p[0]]._highlightedPoint + ) + ) { + var n = jQuery.Event("jqplotDataHighlight"); + n.which = r.which; + n.pageX = r.pageX; + n.pageY = r.pageY; + s.target.trigger(n, p); + c(s, t.seriesIndex, t.pointIndex, t.points); + } + } else { + if (t == null) { + k(s); + } + } + } + function a(q, p, t, s, r) { + if (s) { + var o = [s.seriesIndex, s.pointIndex, s.data]; + if ( + r.series[o[0]].highlightMouseDown && + !( + o[0] == r.plugins.barRenderer.highlightedSeriesIndex && + o[1] == r.series[o[0]]._highlightedPoint + ) + ) { + var n = jQuery.Event("jqplotDataHighlight"); + n.which = q.which; + n.pageX = q.pageX; + n.pageY = q.pageY; + r.target.trigger(n, o); + c(r, s.seriesIndex, s.pointIndex, s.points); + } + } else { + if (s == null) { + k(r); + } + } + } + function l(p, o, s, r, q) { + var n = q.plugins.barRenderer.highlightedSeriesIndex; + if (n != null && q.series[n].highlightMouseDown) { + k(q); + } + } + function e(q, p, t, s, r) { + if (s) { + var o = [s.seriesIndex, s.pointIndex, s.data]; + var n = jQuery.Event("jqplotDataClick"); + n.which = q.which; + n.pageX = q.pageX; + n.pageY = q.pageY; + r.target.trigger(n, o); + } + } + function m(r, q, u, t, s) { + if (t) { + var p = [t.seriesIndex, t.pointIndex, t.data]; + var n = s.plugins.barRenderer.highlightedSeriesIndex; + if (n != null && s.series[n].highlightMouseDown) { + k(s); + } + var o = jQuery.Event("jqplotDataRightClick"); + o.which = r.which; + o.pageX = r.pageX; + o.pageY = r.pageY; + s.target.trigger(o, p); + } + } +})(jQuery); diff --git a/src/adminactions/static/adminactions/js/jqplot/plugins/jqplot.categoryAxisRenderer.js b/src/adminactions/static/adminactions/js/jqplot/plugins/jqplot.categoryAxisRenderer.js index 8b0968b1..e0c21947 100644 --- a/src/adminactions/static/adminactions/js/jqplot/plugins/jqplot.categoryAxisRenderer.js +++ b/src/adminactions/static/adminactions/js/jqplot/plugins/jqplot.categoryAxisRenderer.js @@ -6,13 +6,13 @@ * Revision: 1250 * * Copyright (c) 2009-2013 Chris Leonello - * jqPlot is currently available for use in all personal or commercial projects - * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL - * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can - * choose the license that best suits your project and use it accordingly. + * jqPlot is currently available for use in all personal or commercial projects + * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL + * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can + * choose the license that best suits your project and use it accordingly. * - * Although not required, the author would appreciate an email letting him - * know of any substantial use of jqPlot. You can reach the author at: + * Although not required, the author would appreciate an email letting him + * know of any substantial use of jqPlot. You can reach the author at: * chris at jqplot dot com or see http://www.jqplot.com/info.php . * * If you are feeling kind and generous, consider supporting the project by @@ -26,21 +26,21 @@ * http://hexmen.com/js/sprintf.js * The author (Ash Searle) has placed this code in the public domain: * "This code is unrestricted: you are free to use it however you like." - * + * */ -(function($) { +(function ($) { /** - * class: $.jqplot.CategoryAxisRenderer - * A plugin for jqPlot to render a category style axis, with equal pixel spacing between y data values of a series. - * - * To use this renderer, include the plugin in your source - * > - * - * and supply the appropriate options to your plot - * - * > {axes:{xaxis:{renderer:$.jqplot.CategoryAxisRenderer}}} - **/ - $.jqplot.CategoryAxisRenderer = function(options) { + * class: $.jqplot.CategoryAxisRenderer + * A plugin for jqPlot to render a category style axis, with equal pixel spacing between y data values of a series. + * + * To use this renderer, include the plugin in your source + * > + * + * and supply the appropriate options to your plot + * + * > {axes:{xaxis:{renderer:$.jqplot.CategoryAxisRenderer}}} + **/ + $.jqplot.CategoryAxisRenderer = function (options) { $.jqplot.LinearAxisRenderer.call(this); // prop: sortMergedLabels // True to sort tick labels when labels are created by merging @@ -55,16 +55,17 @@ // With sortMergedLabels set to false, tick labels will be: // > [2006, 2008, 2009, 2007] // - // Note, this property is specified on the renderOptions for the + // Note, this property is specified on the renderOptions for the // axes when creating a plot: // > axes:{xaxis:{renderer:$.jqplot.CategoryAxisRenderer, rendererOptions:{sortMergedLabels:true}}} this.sortMergedLabels = false; }; - + $.jqplot.CategoryAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer(); - $.jqplot.CategoryAxisRenderer.prototype.constructor = $.jqplot.CategoryAxisRenderer; - - $.jqplot.CategoryAxisRenderer.prototype.init = function(options){ + $.jqplot.CategoryAxisRenderer.prototype.constructor = + $.jqplot.CategoryAxisRenderer; + + $.jqplot.CategoryAxisRenderer.prototype.init = function (options) { this.groups = 1; this.groupLabels = []; this._groupLabels = []; @@ -72,48 +73,46 @@ this._barsPerGroup = null; this.reverse = false; // prop: tickRenderer - // A class of a rendering engine for creating the ticks labels displayed on the plot, + // A class of a rendering engine for creating the ticks labels displayed on the plot, // See <$.jqplot.AxisTickRenderer>. // this.tickRenderer = $.jqplot.AxisTickRenderer; // this.labelRenderer = $.jqplot.AxisLabelRenderer; - $.extend(true, this, {tickOptions:{formatString:'%d'}}, options); + $.extend(true, this, { tickOptions: { formatString: "%d" } }, options); var db = this._dataBounds; // Go through all the series attached to this axis and find // the min/max bounds for this axis. - for (var i=0; i db.max || db.max == null) { db.max = d[j][0]; } - } - else { + } else { if (d[j][1] < db.min || db.min == null) { db.min = d[j][1]; } if (d[j][1] > db.max || db.max == null) { db.max = d[j][1]; } - } + } } } - + if (this.groupLabels.length) { this.groups = this.groupLabels.length; } }; - - $.jqplot.CategoryAxisRenderer.prototype.createTicks = function() { + $.jqplot.CategoryAxisRenderer.prototype.createTicks = function () { // we're are operating on an axis here var ticks = this._ticks; var userTicks = this.ticks; @@ -130,10 +129,10 @@ // adjust with blanks if we have groups if (this.groups > 1 && !this._grouped) { var l = userTicks.length; - var skip = parseInt(l/this.groups, 10); + var skip = parseInt(l / this.groups, 10); var count = 0; - for (var i=skip; i 1 && !this._grouped) { var l = labels.length; - var skip = parseInt(l/this.groups, 10); + var skip = parseInt(l / this.groups, 10); var count = 0; - for (var i=skip; i0 && track 0 && track < skip) { t.showLabel = false; track += 1; - } - else { + } else { t.showLabel = true; track = 0; - } - t.label = t.formatter(t.formatString, labels[(i-1)/2]); + } + t.label = t.formatter(t.formatString, labels[(i - 1) / 2]); t.showMark = false; t.showGridline = false; } @@ -299,11 +303,10 @@ this._ticks.push(t); } } - }; - + // called with scope of axis - $.jqplot.CategoryAxisRenderer.prototype.draw = function(ctx, plot) { + $.jqplot.CategoryAxisRenderer.prototype.draw = function (ctx, plot) { if (this.show) { // populate the axis label and value properties. // createTicks is a method on the renderer, but @@ -312,7 +315,7 @@ // fill a div with axes labels in the right direction. // Need to pregenerate each axis to get its bounds and // position it and the labels correctly on the plot. - var dim=0; + var dim = 0; var temp; // Added for theming. if (this._elem) { @@ -321,15 +324,20 @@ this._elem.emptyForce(); } - this._elem = this._elem || $('
'); - - if (this.name == 'xaxis' || this.name == 'x2axis') { + this._elem = + this._elem || + $( + '
', + ); + + if (this.name == "xaxis" || this.name == "x2axis") { this._elem.width(this._plotDimensions.width); - } - else { + } else { this._elem.height(this._plotDimensions.height); } - + // create a _label object. this.labelOptions.axis = this.name; this._label = new this.labelRenderer(this.labelOptions); @@ -337,21 +345,27 @@ var elem = this._label.draw(ctx, plot); elem.appendTo(this._elem); } - + var t = this._ticks; - for (var i=0; i'); + for (var i = 0; i < this.groupLabels.length; i++) { + var elem = $( + '
', + ); elem.html(this.groupLabels[i]); this._groupLabels.push(elem); elem.appendTo(this._elem); @@ -359,23 +373,25 @@ } return this._elem; }; - + // called with scope of axis - $.jqplot.CategoryAxisRenderer.prototype.set = function() { + $.jqplot.CategoryAxisRenderer.prototype.set = function () { var dim = 0; var temp; var w = 0; var h = 0; - var lshow = (this._label == null) ? false : this._label.show; + var lshow = this._label == null ? false : this._label.show; if (this.show) { var t = this._ticks; - for (var i=0; i dim) { @@ -383,297 +399,368 @@ } } } - + var dim2 = 0; - for (var i=0; i dim2) { dim2 = temp; } } - + if (lshow) { w = this._label._elem.outerWidth(true); - h = this._label._elem.outerHeight(true); + h = this._label._elem.outerHeight(true); } - if (this.name == 'xaxis') { + if (this.name == "xaxis") { dim += dim2 + h; - this._elem.css({'height':dim+'px', left:'0px', bottom:'0px'}); - } - else if (this.name == 'x2axis') { + this._elem.css({ + height: dim + "px", + left: "0px", + bottom: "0px", + }); + } else if (this.name == "x2axis") { dim += dim2 + h; - this._elem.css({'height':dim+'px', left:'0px', top:'0px'}); - } - else if (this.name == 'yaxis') { + this._elem.css({ height: dim + "px", left: "0px", top: "0px" }); + } else if (this.name == "yaxis") { dim += dim2 + w; - this._elem.css({'width':dim+'px', left:'0px', top:'0px'}); - if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) { - this._label._elem.css('width', w+'px'); + this._elem.css({ width: dim + "px", left: "0px", top: "0px" }); + if ( + lshow && + this._label.constructor == $.jqplot.AxisLabelRenderer + ) { + this._label._elem.css("width", w + "px"); } - } - else { + } else { dim += dim2 + w; - this._elem.css({'width':dim+'px', right:'0px', top:'0px'}); - if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) { - this._label._elem.css('width', w+'px'); + this._elem.css({ width: dim + "px", right: "0px", top: "0px" }); + if ( + lshow && + this._label.constructor == $.jqplot.AxisLabelRenderer + ) { + this._label._elem.css("width", w + "px"); } } - } + } }; - + // called with scope of axis - $.jqplot.CategoryAxisRenderer.prototype.pack = function(pos, offsets) { + $.jqplot.CategoryAxisRenderer.prototype.pack = function (pos, offsets) { var ticks = this._ticks; var max = this.max; var min = this.min; var offmax = offsets.max; var offmin = offsets.min; - var lshow = (this._label == null) ? false : this._label.show; + var lshow = this._label == null ? false : this._label.show; var i; for (var p in pos) { this._elem.css(p, pos[p]); } - + this._offsets = offsets; // pixellength will be + for x axes and - for y axes becasue pixels always measured from top left. var pixellength = offmax - offmin; var unitlength = max - min; - + if (!this.reverse) { // point to unit and unit to point conversions references to Plot DOM element top left corner. - - this.u2p = function(u){ - return (u - min) * pixellength / unitlength + offmin; + + this.u2p = function (u) { + return ((u - min) * pixellength) / unitlength + offmin; }; - this.p2u = function(p){ - return (p - offmin) * unitlength / pixellength + min; + this.p2u = function (p) { + return ((p - offmin) * unitlength) / pixellength + min; }; - - if (this.name == 'xaxis' || this.name == 'x2axis'){ - this.series_u2p = function(u){ - return (u - min) * pixellength / unitlength; + + if (this.name == "xaxis" || this.name == "x2axis") { + this.series_u2p = function (u) { + return ((u - min) * pixellength) / unitlength; }; - this.series_p2u = function(p){ - return p * unitlength / pixellength + min; + this.series_p2u = function (p) { + return (p * unitlength) / pixellength + min; }; - } - - else { - this.series_u2p = function(u){ - return (u - max) * pixellength / unitlength; + } else { + this.series_u2p = function (u) { + return ((u - max) * pixellength) / unitlength; }; - this.series_p2u = function(p){ - return p * unitlength / pixellength + max; + this.series_p2u = function (p) { + return (p * unitlength) / pixellength + max; }; } - } - - else { + } else { // point to unit and unit to point conversions references to Plot DOM element top left corner. - - this.u2p = function(u){ - return offmin + (max - u) * pixellength / unitlength; + + this.u2p = function (u) { + return offmin + ((max - u) * pixellength) / unitlength; }; - this.p2u = function(p){ - return min + (p - offmin) * unitlength / pixellength; + this.p2u = function (p) { + return min + ((p - offmin) * unitlength) / pixellength; }; - - if (this.name == 'xaxis' || this.name == 'x2axis'){ - this.series_u2p = function(u){ - return (max - u) * pixellength / unitlength; + + if (this.name == "xaxis" || this.name == "x2axis") { + this.series_u2p = function (u) { + return ((max - u) * pixellength) / unitlength; }; - this.series_p2u = function(p){ - return p * unitlength / pixellength + max; + this.series_p2u = function (p) { + return (p * unitlength) / pixellength + max; }; - } - - else { - this.series_u2p = function(u){ - return (min - u) * pixellength / unitlength; + } else { + this.series_u2p = function (u) { + return ((min - u) * pixellength) / unitlength; }; - this.series_p2u = function(p){ - return p * unitlength / pixellength + min; + this.series_p2u = function (p) { + return (p * unitlength) / pixellength + min; }; } - } - - + if (this.show) { - if (this.name == 'xaxis' || this.name == 'x2axis') { - for (i=0; i= this._ticks.length-1) continue; // the last tick does not exist as there is no other group in order to have an empty one. - if (this._ticks[j]._elem && this._ticks[j].label != " ") { + for (var j = i * step; j < (i + 1) * step; j++) { + if (j >= this._ticks.length - 1) continue; // the last tick does not exist as there is no other group in order to have an empty one. + if ( + this._ticks[j]._elem && + this._ticks[j].label != " " + ) { var t = this._ticks[j]._elem; var p = t.position(); - mid += p.left + t.outerWidth(true)/2; + mid += p.left + t.outerWidth(true) / 2; count++; } } - mid = mid/count; - this._groupLabels[i].css({'left':(mid - this._groupLabels[i].outerWidth(true)/2)}); + mid = mid / count; + this._groupLabels[i].css({ + left: mid - this._groupLabels[i].outerWidth(true) / 2, + }); this._groupLabels[i].css(labeledge[0], labeledge[1]); } - } - else { - for (i=0; i 0) { - shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2; - } - else { - shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2; + shim = + (-t._textRenderer.height * + Math.cos( + -t._textRenderer.angle, + )) / + 2; + } else { + shim = + -t.getHeight() + + (t._textRenderer.height * + Math.cos( + t._textRenderer.angle, + )) / + 2; } break; - case 'middle': + case "middle": // if (t.angle > 0) { // shim = -t.getHeight()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; // } // else { // shim = -t.getHeight()/2 - t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2; // } - shim = -t.getHeight()/2; + shim = -t.getHeight() / 2; break; default: - shim = -t.getHeight()/2; + shim = -t.getHeight() / 2; break; } + } else { + shim = -t.getHeight() / 2; } - else { - shim = -t.getHeight()/2; - } - - var val = this.u2p(t.value) + shim + 'px'; - t._elem.css('top', val); + + var val = this.u2p(t.value) + shim + "px"; + t._elem.css("top", val); t.pack(); } } - - var labeledge=['left', 0]; + + var labeledge = ["left", 0]; if (lshow) { var h = this._label._elem.outerHeight(true); - this._label._elem.css('top', offmax - pixellength/2 - h/2 + 'px'); - if (this.name == 'yaxis') { - this._label._elem.css('left', '0px'); - labeledge = ['left', this._label._elem.outerWidth(true)]; + this._label._elem.css( + "top", + offmax - pixellength / 2 - h / 2 + "px", + ); + if (this.name == "yaxis") { + this._label._elem.css("left", "0px"); + labeledge = [ + "left", + this._label._elem.outerWidth(true), + ]; + } else { + this._label._elem.css("right", "0px"); + labeledge = [ + "right", + this._label._elem.outerWidth(true), + ]; } - else { - this._label._elem.css('right', '0px'); - labeledge = ['right', this._label._elem.outerWidth(true)]; - } this._label.pack(); } - + // draw the group labels, position top here, do left after label position. - var step = parseInt(this._ticks.length/this.groups, 10) + 1; // step is one more than before as we don't want to have overlaps in loops - for (i=0; i= this._ticks.length-1) continue; // the last tick does not exist as there is no other group in order to have an empty one. - if (this._ticks[j]._elem && this._ticks[j].label != " ") { + for (var j = i * step; j < (i + 1) * step; j++) { + // j must never reach (i+1)*step as we don't want to have overlap between loops + if (j >= this._ticks.length - 1) continue; // the last tick does not exist as there is no other group in order to have an empty one. + if ( + this._ticks[j]._elem && + this._ticks[j].label != " " + ) { var t = this._ticks[j]._elem; var p = t.position(); - mid += p.top + t.outerHeight()/2; + mid += p.top + t.outerHeight() / 2; count++; } } - mid = mid/count; - this._groupLabels[i].css({'top':mid - this._groupLabels[i].outerHeight()/2}); + mid = mid / count; + this._groupLabels[i].css({ + top: mid - this._groupLabels[i].outerHeight() / 2, + }); this._groupLabels[i].css(labeledge[0], labeledge[1]); - } } } - }; - - + }; })(jQuery); diff --git a/src/adminactions/static/adminactions/js/jqplot/plugins/jqplot.categoryAxisRenderer.min.js b/src/adminactions/static/adminactions/js/jqplot/plugins/jqplot.categoryAxisRenderer.min.js index 606b2846..653bd49c 100644 --- a/src/adminactions/static/adminactions/js/jqplot/plugins/jqplot.categoryAxisRenderer.min.js +++ b/src/adminactions/static/adminactions/js/jqplot/plugins/jqplot.categoryAxisRenderer.min.js @@ -1 +1,602 @@ -(function(a){a.jqplot.CategoryAxisRenderer=function(b){a.jqplot.LinearAxisRenderer.call(this);this.sortMergedLabels=false};a.jqplot.CategoryAxisRenderer.prototype=new a.jqplot.LinearAxisRenderer();a.jqplot.CategoryAxisRenderer.prototype.constructor=a.jqplot.CategoryAxisRenderer;a.jqplot.CategoryAxisRenderer.prototype.init=function(e){this.groups=1;this.groupLabels=[];this._groupLabels=[];this._grouped=false;this._barsPerGroup=null;this.reverse=false;a.extend(true,this,{tickOptions:{formatString:"%d"}},e);var b=this._dataBounds;for(var f=0;fb.max||b.max==null){b.max=h[c][0]}}else{if(h[c][1]b.max||b.max==null){b.max=h[c][1]}}}}if(this.groupLabels.length){this.groups=this.groupLabels.length}};a.jqplot.CategoryAxisRenderer.prototype.createTicks=function(){var D=this._ticks;var z=this.ticks;var F=this.name;var C=this._dataBounds;var v,A;var q,w;var d,c;var b,x;if(z.length){if(this.groups>1&&!this._grouped){var r=z.length;var p=parseInt(r/this.groups,10);var e=0;for(var x=p;x1&&!this._grouped){var r=y.length;var p=parseInt(r/this.groups,10);var e=0;for(var x=p;x0&&o');if(this.name=="xaxis"||this.name=="x2axis"){this._elem.width(this._plotDimensions.width)}else{this._elem.height(this._plotDimensions.height)}this.labelOptions.axis=this.name;this._label=new this.labelRenderer(this.labelOptions);if(this._label.show){var g=this._label.draw(b,j);g.appendTo(this._elem)}var f=this._ticks;for(var e=0;e');g.html(this.groupLabels[e]);this._groupLabels.push(g);g.appendTo(this._elem)}}return this._elem};a.jqplot.CategoryAxisRenderer.prototype.set=function(){var e=0;var m;var k=0;var f=0;var d=(this._label==null)?false:this._label.show;if(this.show){var n=this._ticks;for(var c=0;ce){e=m}}}var j=0;for(var c=0;cj){j=m}}if(d){k=this._label._elem.outerWidth(true);f=this._label._elem.outerHeight(true)}if(this.name=="xaxis"){e+=j+f;this._elem.css({height:e+"px",left:"0px",bottom:"0px"})}else{if(this.name=="x2axis"){e+=j+f;this._elem.css({height:e+"px",left:"0px",top:"0px"})}else{if(this.name=="yaxis"){e+=j+k;this._elem.css({width:e+"px",left:"0px",top:"0px"});if(d&&this._label.constructor==a.jqplot.AxisLabelRenderer){this._label._elem.css("width",k+"px")}}else{e+=j+k;this._elem.css({width:e+"px",right:"0px",top:"0px"});if(d&&this._label.constructor==a.jqplot.AxisLabelRenderer){this._label._elem.css("width",k+"px")}}}}}};a.jqplot.CategoryAxisRenderer.prototype.pack=function(e,c){var C=this._ticks;var v=this.max;var s=this.min;var n=c.max;var l=c.min;var q=(this._label==null)?false:this._label.show;var x;for(var r in e){this._elem.css(r,e[r])}this._offsets=c;var g=n-l;var k=v-s;if(!this.reverse){this.u2p=function(h){return(h-s)*g/k+l};this.p2u=function(h){return(h-l)*k/g+s};if(this.name=="xaxis"||this.name=="x2axis"){this.series_u2p=function(h){return(h-s)*g/k};this.series_p2u=function(h){return h*k/g+s}}else{this.series_u2p=function(h){return(h-v)*g/k};this.series_p2u=function(h){return h*k/g+v}}}else{this.u2p=function(h){return l+(v-h)*g/k};this.p2u=function(h){return s+(h-l)*k/g};if(this.name=="xaxis"||this.name=="x2axis"){this.series_u2p=function(h){return(v-h)*g/k};this.series_p2u=function(h){return h*k/g+v}}else{this.series_u2p=function(h){return(s-h)*g/k};this.series_p2u=function(h){return h*k/g+s}}}if(this.show){if(this.name=="xaxis"||this.name=="x2axis"){for(x=0;x=this._ticks.length-1){continue}if(this._ticks[u]._elem&&this._ticks[u].label!=" "){var o=this._ticks[u]._elem;var r=o.position();B+=r.left+o.outerWidth(true)/2;f++}}B=B/f;this._groupLabels[x].css({left:(B-this._groupLabels[x].outerWidth(true)/2)});this._groupLabels[x].css(z[0],z[1])}}else{for(x=0;x0){b=-o._textRenderer.height*Math.cos(-o._textRenderer.angle)/2}else{b=-o.getHeight()+o._textRenderer.height*Math.cos(o._textRenderer.angle)/2}break;case"middle":b=-o.getHeight()/2;break;default:b=-o.getHeight()/2;break}}else{b=-o.getHeight()/2}var D=this.u2p(o.value)+b+"px";o._elem.css("top",D);o.pack()}}var z=["left",0];if(q){var y=this._label._elem.outerHeight(true);this._label._elem.css("top",n-g/2-y/2+"px");if(this.name=="yaxis"){this._label._elem.css("left","0px");z=["left",this._label._elem.outerWidth(true)]}else{this._label._elem.css("right","0px");z=["right",this._label._elem.outerWidth(true)]}this._label.pack()}var d=parseInt(this._ticks.length/this.groups,10)+1;for(x=0;x=this._ticks.length-1){continue}if(this._ticks[u]._elem&&this._ticks[u].label!=" "){var o=this._ticks[u]._elem;var r=o.position();B+=r.top+o.outerHeight()/2;f++}}B=B/f;this._groupLabels[x].css({top:B-this._groupLabels[x].outerHeight()/2});this._groupLabels[x].css(z[0],z[1])}}}}})(jQuery); \ No newline at end of file +(function (a) { + a.jqplot.CategoryAxisRenderer = function (b) { + a.jqplot.LinearAxisRenderer.call(this); + this.sortMergedLabels = false; + }; + a.jqplot.CategoryAxisRenderer.prototype = new a.jqplot.LinearAxisRenderer(); + a.jqplot.CategoryAxisRenderer.prototype.constructor = + a.jqplot.CategoryAxisRenderer; + a.jqplot.CategoryAxisRenderer.prototype.init = function (e) { + this.groups = 1; + this.groupLabels = []; + this._groupLabels = []; + this._grouped = false; + this._barsPerGroup = null; + this.reverse = false; + a.extend(true, this, { tickOptions: { formatString: "%d" } }, e); + var b = this._dataBounds; + for (var f = 0; f < this._series.length; f++) { + var g = this._series[f]; + if (g.groups) { + this.groups = g.groups; + } + var h = g.data; + for (var c = 0; c < h.length; c++) { + if (this.name == "xaxis" || this.name == "x2axis") { + if (h[c][0] < b.min || b.min == null) { + b.min = h[c][0]; + } + if (h[c][0] > b.max || b.max == null) { + b.max = h[c][0]; + } + } else { + if (h[c][1] < b.min || b.min == null) { + b.min = h[c][1]; + } + if (h[c][1] > b.max || b.max == null) { + b.max = h[c][1]; + } + } + } + } + if (this.groupLabels.length) { + this.groups = this.groupLabels.length; + } + }; + a.jqplot.CategoryAxisRenderer.prototype.createTicks = function () { + var D = this._ticks; + var z = this.ticks; + var F = this.name; + var C = this._dataBounds; + var v, A; + var q, w; + var d, c; + var b, x; + if (z.length) { + if (this.groups > 1 && !this._grouped) { + var r = z.length; + var p = parseInt(r / this.groups, 10); + var e = 0; + for (var x = p; x < r; x += p) { + z.splice(x + e, 0, " "); + e++; + } + this._grouped = true; + } + this.min = 0.5; + this.max = z.length + 0.5; + var m = this.max - this.min; + this.numberTicks = 2 * z.length + 1; + for (x = 0; x < z.length; x++) { + b = this.min + (2 * x * m) / (this.numberTicks - 1); + var h = new this.tickRenderer(this.tickOptions); + h.showLabel = false; + h.setTick(b, this.name); + this._ticks.push(h); + var h = new this.tickRenderer(this.tickOptions); + h.label = z[x]; + h.showMark = false; + h.showGridline = false; + h.setTick(b + 0.5, this.name); + this._ticks.push(h); + } + var h = new this.tickRenderer(this.tickOptions); + h.showLabel = false; + h.setTick(b + 1, this.name); + this._ticks.push(h); + } else { + if (F == "xaxis" || F == "x2axis") { + v = this._plotDimensions.width; + } else { + v = this._plotDimensions.height; + } + if ( + this.min != null && + this.max != null && + this.numberTicks != null + ) { + this.tickInterval = null; + } + if ( + this.min != null && + this.max != null && + this.tickInterval != null + ) { + if ( + parseInt((this.max - this.min) / this.tickInterval, 10) != + (this.max - this.min) / this.tickInterval + ) { + this.tickInterval = null; + } + } + var y = []; + var B = 0; + var q = 0.5; + var w, E; + var f = false; + for (var x = 0; x < this._series.length; x++) { + var k = this._series[x]; + for (var u = 0; u < k.data.length; u++) { + if (this.name == "xaxis" || this.name == "x2axis") { + E = k.data[u][0]; + } else { + E = k.data[u][1]; + } + if (a.inArray(E, y) == -1) { + f = true; + B += 1; + y.push(E); + } + } + } + if (f && this.sortMergedLabels) { + if (typeof y[0] == "string") { + y.sort(); + } else { + y.sort(function (j, i) { + return j - i; + }); + } + } + this.ticks = y; + for (var x = 0; x < this._series.length; x++) { + var k = this._series[x]; + for (var u = 0; u < k.data.length; u++) { + if (this.name == "xaxis" || this.name == "x2axis") { + E = k.data[u][0]; + } else { + E = k.data[u][1]; + } + var n = a.inArray(E, y) + 1; + if (this.name == "xaxis" || this.name == "x2axis") { + k.data[u][0] = n; + } else { + k.data[u][1] = n; + } + } + } + if (this.groups > 1 && !this._grouped) { + var r = y.length; + var p = parseInt(r / this.groups, 10); + var e = 0; + for (var x = p; x < r; x += p + 1) { + y[x] = " "; + } + this._grouped = true; + } + w = B + 0.5; + if (this.numberTicks == null) { + this.numberTicks = 2 * B + 1; + } + var m = w - q; + this.min = q; + this.max = w; + var o = 0; + var g = parseInt(3 + v / 10, 10); + var p = parseInt(B / g, 10); + if (this.tickInterval == null) { + this.tickInterval = m / (this.numberTicks - 1); + } + for (var x = 0; x < this.numberTicks; x++) { + b = this.min + x * this.tickInterval; + var h = new this.tickRenderer(this.tickOptions); + if (x / 2 == parseInt(x / 2, 10)) { + h.showLabel = false; + h.showMark = true; + } else { + if (p > 0 && o < p) { + h.showLabel = false; + o += 1; + } else { + h.showLabel = true; + o = 0; + } + h.label = h.formatter(h.formatString, y[(x - 1) / 2]); + h.showMark = false; + h.showGridline = false; + } + h.setTick(b, this.name); + this._ticks.push(h); + } + } + }; + a.jqplot.CategoryAxisRenderer.prototype.draw = function (b, j) { + if (this.show) { + this.renderer.createTicks.call(this); + var h = 0; + var c; + if (this._elem) { + this._elem.emptyForce(); + } + this._elem = + this._elem || + a( + '
', + ); + if (this.name == "xaxis" || this.name == "x2axis") { + this._elem.width(this._plotDimensions.width); + } else { + this._elem.height(this._plotDimensions.height); + } + this.labelOptions.axis = this.name; + this._label = new this.labelRenderer(this.labelOptions); + if (this._label.show) { + var g = this._label.draw(b, j); + g.appendTo(this._elem); + } + var f = this._ticks; + for (var e = 0; e < f.length; e++) { + var d = f[e]; + if (d.showLabel && (!d.isMinorTick || this.showMinorTicks)) { + var g = d.draw(b, j); + g.appendTo(this._elem); + } + } + this._groupLabels = []; + for (var e = 0; e < this.groupLabels.length; e++) { + var g = a( + '
', + ); + g.html(this.groupLabels[e]); + this._groupLabels.push(g); + g.appendTo(this._elem); + } + } + return this._elem; + }; + a.jqplot.CategoryAxisRenderer.prototype.set = function () { + var e = 0; + var m; + var k = 0; + var f = 0; + var d = this._label == null ? false : this._label.show; + if (this.show) { + var n = this._ticks; + for (var c = 0; c < n.length; c++) { + var g = n[c]; + if (g.showLabel && (!g.isMinorTick || this.showMinorTicks)) { + if (this.name == "xaxis" || this.name == "x2axis") { + m = g._elem.outerHeight(true); + } else { + m = g._elem.outerWidth(true); + } + if (m > e) { + e = m; + } + } + } + var j = 0; + for (var c = 0; c < this._groupLabels.length; c++) { + var b = this._groupLabels[c]; + if (this.name == "xaxis" || this.name == "x2axis") { + m = b.outerHeight(true); + } else { + m = b.outerWidth(true); + } + if (m > j) { + j = m; + } + } + if (d) { + k = this._label._elem.outerWidth(true); + f = this._label._elem.outerHeight(true); + } + if (this.name == "xaxis") { + e += j + f; + this._elem.css({ + height: e + "px", + left: "0px", + bottom: "0px", + }); + } else { + if (this.name == "x2axis") { + e += j + f; + this._elem.css({ + height: e + "px", + left: "0px", + top: "0px", + }); + } else { + if (this.name == "yaxis") { + e += j + k; + this._elem.css({ + width: e + "px", + left: "0px", + top: "0px", + }); + if ( + d && + this._label.constructor == + a.jqplot.AxisLabelRenderer + ) { + this._label._elem.css("width", k + "px"); + } + } else { + e += j + k; + this._elem.css({ + width: e + "px", + right: "0px", + top: "0px", + }); + if ( + d && + this._label.constructor == + a.jqplot.AxisLabelRenderer + ) { + this._label._elem.css("width", k + "px"); + } + } + } + } + } + }; + a.jqplot.CategoryAxisRenderer.prototype.pack = function (e, c) { + var C = this._ticks; + var v = this.max; + var s = this.min; + var n = c.max; + var l = c.min; + var q = this._label == null ? false : this._label.show; + var x; + for (var r in e) { + this._elem.css(r, e[r]); + } + this._offsets = c; + var g = n - l; + var k = v - s; + if (!this.reverse) { + this.u2p = function (h) { + return ((h - s) * g) / k + l; + }; + this.p2u = function (h) { + return ((h - l) * k) / g + s; + }; + if (this.name == "xaxis" || this.name == "x2axis") { + this.series_u2p = function (h) { + return ((h - s) * g) / k; + }; + this.series_p2u = function (h) { + return (h * k) / g + s; + }; + } else { + this.series_u2p = function (h) { + return ((h - v) * g) / k; + }; + this.series_p2u = function (h) { + return (h * k) / g + v; + }; + } + } else { + this.u2p = function (h) { + return l + ((v - h) * g) / k; + }; + this.p2u = function (h) { + return s + ((h - l) * k) / g; + }; + if (this.name == "xaxis" || this.name == "x2axis") { + this.series_u2p = function (h) { + return ((v - h) * g) / k; + }; + this.series_p2u = function (h) { + return (h * k) / g + v; + }; + } else { + this.series_u2p = function (h) { + return ((s - h) * g) / k; + }; + this.series_p2u = function (h) { + return (h * k) / g + s; + }; + } + } + if (this.show) { + if (this.name == "xaxis" || this.name == "x2axis") { + for (x = 0; x < C.length; x++) { + var o = C[x]; + if (o.show && o.showLabel) { + var b; + if ( + o.constructor == a.jqplot.CanvasAxisTickRenderer && + o.angle + ) { + var A = this.name == "xaxis" ? 1 : -1; + switch (o.labelPosition) { + case "auto": + if (A * o.angle < 0) { + b = + -o.getWidth() + + (o._textRenderer.height * + Math.sin( + -o._textRenderer.angle, + )) / + 2; + } else { + b = + (-o._textRenderer.height * + Math.sin( + o._textRenderer.angle, + )) / + 2; + } + break; + case "end": + b = + -o.getWidth() + + (o._textRenderer.height * + Math.sin(-o._textRenderer.angle)) / + 2; + break; + case "start": + b = + (-o._textRenderer.height * + Math.sin(o._textRenderer.angle)) / + 2; + break; + case "middle": + b = + -o.getWidth() / 2 + + (o._textRenderer.height * + Math.sin(-o._textRenderer.angle)) / + 2; + break; + default: + b = + -o.getWidth() / 2 + + (o._textRenderer.height * + Math.sin(-o._textRenderer.angle)) / + 2; + break; + } + } else { + b = -o.getWidth() / 2; + } + var D = this.u2p(o.value) + b + "px"; + o._elem.css("left", D); + o.pack(); + } + } + var z = ["bottom", 0]; + if (q) { + var m = this._label._elem.outerWidth(true); + this._label._elem.css("left", l + g / 2 - m / 2 + "px"); + if (this.name == "xaxis") { + this._label._elem.css("bottom", "0px"); + z = ["bottom", this._label._elem.outerHeight(true)]; + } else { + this._label._elem.css("top", "0px"); + z = ["top", this._label._elem.outerHeight(true)]; + } + this._label.pack(); + } + var d = parseInt(this._ticks.length / this.groups, 10) + 1; + for (x = 0; x < this._groupLabels.length; x++) { + var B = 0; + var f = 0; + for (var u = x * d; u < (x + 1) * d; u++) { + if (u >= this._ticks.length - 1) { + continue; + } + if ( + this._ticks[u]._elem && + this._ticks[u].label != " " + ) { + var o = this._ticks[u]._elem; + var r = o.position(); + B += r.left + o.outerWidth(true) / 2; + f++; + } + } + B = B / f; + this._groupLabels[x].css({ + left: B - this._groupLabels[x].outerWidth(true) / 2, + }); + this._groupLabels[x].css(z[0], z[1]); + } + } else { + for (x = 0; x < C.length; x++) { + var o = C[x]; + if (o.show && o.showLabel) { + var b; + if ( + o.constructor == a.jqplot.CanvasAxisTickRenderer && + o.angle + ) { + var A = this.name == "yaxis" ? 1 : -1; + switch (o.labelPosition) { + case "auto": + case "end": + if (A * o.angle < 0) { + b = + (-o._textRenderer.height * + Math.cos( + -o._textRenderer.angle, + )) / + 2; + } else { + b = + -o.getHeight() + + (o._textRenderer.height * + Math.cos( + o._textRenderer.angle, + )) / + 2; + } + break; + case "start": + if (o.angle > 0) { + b = + (-o._textRenderer.height * + Math.cos( + -o._textRenderer.angle, + )) / + 2; + } else { + b = + -o.getHeight() + + (o._textRenderer.height * + Math.cos( + o._textRenderer.angle, + )) / + 2; + } + break; + case "middle": + b = -o.getHeight() / 2; + break; + default: + b = -o.getHeight() / 2; + break; + } + } else { + b = -o.getHeight() / 2; + } + var D = this.u2p(o.value) + b + "px"; + o._elem.css("top", D); + o.pack(); + } + } + var z = ["left", 0]; + if (q) { + var y = this._label._elem.outerHeight(true); + this._label._elem.css("top", n - g / 2 - y / 2 + "px"); + if (this.name == "yaxis") { + this._label._elem.css("left", "0px"); + z = ["left", this._label._elem.outerWidth(true)]; + } else { + this._label._elem.css("right", "0px"); + z = ["right", this._label._elem.outerWidth(true)]; + } + this._label.pack(); + } + var d = parseInt(this._ticks.length / this.groups, 10) + 1; + for (x = 0; x < this._groupLabels.length; x++) { + var B = 0; + var f = 0; + for (var u = x * d; u < (x + 1) * d; u++) { + if (u >= this._ticks.length - 1) { + continue; + } + if ( + this._ticks[u]._elem && + this._ticks[u].label != " " + ) { + var o = this._ticks[u]._elem; + var r = o.position(); + B += r.top + o.outerHeight() / 2; + f++; + } + } + B = B / f; + this._groupLabels[x].css({ + top: B - this._groupLabels[x].outerHeight() / 2, + }); + this._groupLabels[x].css(z[0], z[1]); + } + } + } + }; +})(jQuery); diff --git a/src/adminactions/static/adminactions/js/jqplot/plugins/jqplot.pieRenderer.js b/src/adminactions/static/adminactions/js/jqplot/plugins/jqplot.pieRenderer.js index 20eb797f..3171833c 100644 --- a/src/adminactions/static/adminactions/js/jqplot/plugins/jqplot.pieRenderer.js +++ b/src/adminactions/static/adminactions/js/jqplot/plugins/jqplot.pieRenderer.js @@ -6,13 +6,13 @@ * Revision: 1250 * * Copyright (c) 2009-2013 Chris Leonello - * jqPlot is currently available for use in all personal or commercial projects - * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL - * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can - * choose the license that best suits your project and use it accordingly. + * jqPlot is currently available for use in all personal or commercial projects + * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL + * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can + * choose the license that best suits your project and use it accordingly. * - * Although not required, the author would appreciate an email letting him - * know of any substantial use of jqPlot. You can reach the author at: + * Although not required, the author would appreciate an email letting him + * know of any substantial use of jqPlot. You can reach the author at: * chris at jqplot dot com or see http://www.jqplot.com/info.php . * * If you are feeling kind and generous, consider supporting the project by @@ -26,23 +26,23 @@ * http://hexmen.com/js/sprintf.js * The author (Ash Searle) has placed this code in the public domain: * "This code is unrestricted: you are free to use it however you like." - * + * */ -(function($) { +(function ($) { /** * Class: $.jqplot.PieRenderer * Plugin renderer to draw a pie chart. * x values, if present, will be used as slice labels. * y values give slice size. - * - * To use this renderer, you need to include the + * + * To use this renderer, you need to include the * pie renderer plugin, for example: - * + * * > - * + * * Properties described here are passed into the $.jqplot function * as options on the series renderer. For example: - * + * * > plot2 = $.jqplot('chart2', [s1, s2], { * > seriesDefaults: { * > renderer:$.jqplot.PieRenderer, @@ -52,12 +52,12 @@ * > } * > } * > }); - * + * * A pie plot will trigger events on the plot target * according to user interaction. All events return the event object, - * the series index, the point (slice) index, and the point data for + * the series index, the point (slice) index, and the point data for * the appropriate slice. - * + * * 'jqplotDataMouseOver' - triggered when user mouseing over a slice. * 'jqplotDataHighlight' - triggered the first time user mouses over a slice, * if highlighting is enabled. @@ -67,15 +67,15 @@ * 'jqplotDataRightClick' - tiggered when the user right clicks on a slice if * the "captureRightClick" option is set to true on the plot. */ - $.jqplot.PieRenderer = function(){ + $.jqplot.PieRenderer = function () { $.jqplot.LineRenderer.call(this); }; - + $.jqplot.PieRenderer.prototype = new $.jqplot.LineRenderer(); $.jqplot.PieRenderer.prototype.constructor = $.jqplot.PieRenderer; - + // called with scope of a series - $.jqplot.PieRenderer.prototype.init = function(options, plot) { + $.jqplot.PieRenderer.prototype.init = function (options, plot) { // Group: Properties // // prop: diameter @@ -91,14 +91,14 @@ // true or false, whether to fil the slices. this.fill = true; // prop: shadowOffset - // offset of the shadow from the slice and offset of + // offset of the shadow from the slice and offset of // each successive stroke of the shadow from the last. this.shadowOffset = 2; // prop: shadowAlpha // transparency of the shadow (0 = transparent, 1 = opaque) this.shadowAlpha = 0.07; // prop: shadowDepth - // number of strokes to apply to the shadow, + // number of strokes to apply to the shadow, // each stroke offset shadowOffset from the last. this.shadowDepth = 5; // prop: highlightMouseOver @@ -115,7 +115,7 @@ // prop: dataLabels // Either 'label', 'value', 'percent' or an array of labels to place on the pie slices. // Defaults to percentage of each pie slice. - this.dataLabels = 'percent'; + this.dataLabels = "percent"; // prop: showDataLabels // true to show data labels on slices. this.showDataLabels = false; @@ -138,7 +138,7 @@ // False to set the inside facing edge of the label at its position. this.dataLabelCenterOn = true; // prop: startAngle - // Angle to start drawing pie in degrees. + // Angle to start drawing pie in degrees. // According to orientation of canvas coordinate system: // 0 = on the positive x axis // -90 = on the positive y axis. @@ -148,13 +148,13 @@ this.tickRenderer = $.jqplot.PieTickRenderer; // Used as check for conditions where pie shouldn't be drawn. this._drawData = true; - this._type = 'pie'; - + this._type = "pie"; + // if user has passed in highlightMouseDown option and not set highlightMouseOver, disable highlightMouseOver if (options.highlightMouseDown && options.highlightMouseOver == null) { options.highlightMouseOver = false; } - + $.extend(true, this, options); if (this.sliceMargin < 0) { @@ -167,93 +167,106 @@ this._sliceAngles = []; // index of the currently highlighted point, if any this._highlightedPoint = null; - + // set highlight colors if none provided if (this.highlightColors.length == 0) { - for (var i=0; i 570) ? newrgb[j] * 0.8 : newrgb[j] + 0.3 * (255 - newrgb[j]); + newrgb[j] = + sum > 570 + ? newrgb[j] * 0.8 + : newrgb[j] + 0.3 * (255 - newrgb[j]); newrgb[j] = parseInt(newrgb[j], 10); } - this.highlightColors.push('rgb('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+')'); + this.highlightColors.push( + "rgb(" + + newrgb[0] + + "," + + newrgb[1] + + "," + + newrgb[2] + + ")", + ); } } - - this.highlightColorGenerator = new $.jqplot.ColorGenerator(this.highlightColors); - + + this.highlightColorGenerator = new $.jqplot.ColorGenerator( + this.highlightColors, + ); + plot.postParseOptionsHooks.addOnce(postParseOptions); plot.postInitHooks.addOnce(postInit); - plot.eventListenerHooks.addOnce('jqplotMouseMove', handleMove); - plot.eventListenerHooks.addOnce('jqplotMouseDown', handleMouseDown); - plot.eventListenerHooks.addOnce('jqplotMouseUp', handleMouseUp); - plot.eventListenerHooks.addOnce('jqplotClick', handleClick); - plot.eventListenerHooks.addOnce('jqplotRightClick', handleRightClick); + plot.eventListenerHooks.addOnce("jqplotMouseMove", handleMove); + plot.eventListenerHooks.addOnce("jqplotMouseDown", handleMouseDown); + plot.eventListenerHooks.addOnce("jqplotMouseUp", handleMouseUp); + plot.eventListenerHooks.addOnce("jqplotClick", handleClick); + plot.eventListenerHooks.addOnce("jqplotRightClick", handleRightClick); plot.postDrawHooks.addOnce(postPlotDraw); }; - - $.jqplot.PieRenderer.prototype.setGridData = function(plot) { + + $.jqplot.PieRenderer.prototype.setGridData = function (plot) { // set gridData property. This will hold angle in radians of each data point. var stack = []; var td = []; - var sa = this.startAngle/180*Math.PI; + var sa = (this.startAngle / 180) * Math.PI; var tot = 0; // don't know if we have any valid data yet, so set plot to not draw. this._drawData = false; - for (var i=0; i0) { - stack[i] += stack[i-1]; + if (i > 0) { + stack[i] += stack[i - 1]; } tot += this.data[i][1]; } - var fact = Math.PI*2/stack[stack.length - 1]; - - for (var i=0; i0) { - stack[i] += stack[i-1]; + if (i > 0) { + stack[i] += stack[i - 1]; } tot += data[i][1]; } - var fact = Math.PI*2/stack[stack.length - 1]; - - for (var i=0; i 6.282 + this.startAngle) { + if (ang2 > 6.282 + this.startAngle) { ang2 = 6.282 + this.startAngle; if (ang1 > ang2) { ang1 = 6.281 + this.startAngle; @@ -329,62 +356,64 @@ // ugly line on unfilled pies. if (ang1 >= ang2) { return; - } - - ctx.beginPath(); + } + + ctx.beginPath(); ctx.fillStyle = color; ctx.strokeStyle = color; ctx.lineWidth = lineWidth; ctx.arc(0, 0, rad, ang1, ang2, false); - ctx.lineTo(0,0); + ctx.lineTo(0, 0); ctx.closePath(); - + if (fill) { ctx.fill(); - } - else { + } else { ctx.stroke(); } } }; - + // called with scope of series $.jqplot.PieRenderer.prototype.draw = function (ctx, gd, options, plot) { var i; - var opts = (options != undefined) ? options : {}; + var opts = options != undefined ? options : {}; // offset and direction of offset due to legend placement var offx = 0; var offy = 0; var trans = 1; var colorGenerator = new $.jqplot.ColorGenerator(this.seriesColors); - if (options.legendInfo && options.legendInfo.placement == 'insideGrid') { + if ( + options.legendInfo && + options.legendInfo.placement == "insideGrid" + ) { var li = options.legendInfo; switch (li.location) { - case 'nw': + case "nw": offx = li.width + li.xoffset; break; - case 'w': + case "w": offx = li.width + li.xoffset; break; - case 'sw': + case "sw": offx = li.width + li.xoffset; break; - case 'ne': + case "ne": offx = li.width + li.xoffset; trans = -1; break; - case 'e': + case "e": offx = li.width + li.xoffset; trans = -1; break; - case 'se': + case "se": offx = li.width + li.xoffset; trans = -1; break; - case 'n': + case "n": offy = li.height + li.yoffset; break; - case 's': + case "s": offy = li.height + li.yoffset; trans = -1; break; @@ -392,16 +421,16 @@ break; } } - - var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow; - var fill = (opts.fill != undefined) ? opts.fill : this.fill; + + var shadow = opts.shadow != undefined ? opts.shadow : this.shadow; + var fill = opts.fill != undefined ? opts.fill : this.fill; var cw = ctx.canvas.width; var ch = ctx.canvas.height; var w = cw - offx - 2 * this.padding; var h = ch - offy - 2 * this.padding; - var mindim = Math.min(w,h); + var mindim = Math.min(w, h); var d = mindim; - + // Fixes issue #272. Thanks hugwijst! // reset slice angles array. this._sliceAngles = []; @@ -410,109 +439,144 @@ if (this.fill == false) { sm += this.lineWidth; } - + var rprime; var maxrprime = 0; var ang, ang1, ang2, shadowColor; - var sa = this.startAngle / 180 * Math.PI; + var sa = (this.startAngle / 180) * Math.PI; // have to pre-draw shadows, so loop throgh here and calculate some values also. - for (var i=0, l=gd.length; i Math.PI) { - maxrprime = Math.max(rprime, maxrprime); + if (Math.abs(ang2 - ang1) > Math.PI) { + maxrprime = Math.max(rprime, maxrprime); } } if (this.diameter != null && this.diameter > 0) { - this._diameter = this.diameter - 2*maxrprime; - } - else { - this._diameter = d - 2*maxrprime; + this._diameter = this.diameter - 2 * maxrprime; + } else { + this._diameter = d - 2 * maxrprime; } // Need to check for undersized pie. This can happen if // plot area too small and legend is too big. if (this._diameter < 6) { - $.jqplot.log('Diameter of pie too small, not rendering.'); + $.jqplot.log("Diameter of pie too small, not rendering."); return; } - var r = this._radius = this._diameter/2; + var r = (this._radius = this._diameter / 2); - this._center = [(cw - trans * offx)/2 + trans * offx + maxrprime * Math.cos(sa), (ch - trans*offy)/2 + trans * offy + maxrprime * Math.sin(sa)]; + this._center = [ + (cw - trans * offx) / 2 + trans * offx + maxrprime * Math.cos(sa), + (ch - trans * offy) / 2 + trans * offy + maxrprime * Math.sin(sa), + ]; if (this.shadow) { - for (var i=0, l=gd.length; i= this.dataLabelThreshold) { - var fstr, avgang = (this._sliceAngles[i][0] + this._sliceAngles[i][1])/2, label; - - if (this.dataLabels == 'label') { - fstr = this.dataLabelFormatString || '%s'; + + for (var i = 0; i < gd.length; i++) { + this.renderer.drawSlice.call( + this, + ctx, + this._sliceAngles[i][0], + this._sliceAngles[i][1], + colorGenerator.next(), + false, + ); + + if ( + this.showDataLabels && + gd[i][2] * 100 >= this.dataLabelThreshold + ) { + var fstr, + avgang = + (this._sliceAngles[i][0] + this._sliceAngles[i][1]) / 2, + label; + + if (this.dataLabels == "label") { + fstr = this.dataLabelFormatString || "%s"; label = $.jqplot.sprintf(fstr, gd[i][0]); - } - else if (this.dataLabels == 'value') { - fstr = this.dataLabelFormatString || '%d'; + } else if (this.dataLabels == "value") { + fstr = this.dataLabelFormatString || "%d"; label = $.jqplot.sprintf(fstr, this.data[i][1]); - } - else if (this.dataLabels == 'percent') { - fstr = this.dataLabelFormatString || '%d%%'; - label = $.jqplot.sprintf(fstr, gd[i][2]*100); - } - else if (this.dataLabels.constructor == Array) { - fstr = this.dataLabelFormatString || '%s'; + } else if (this.dataLabels == "percent") { + fstr = this.dataLabelFormatString || "%d%%"; + label = $.jqplot.sprintf(fstr, gd[i][2] * 100); + } else if (this.dataLabels.constructor == Array) { + fstr = this.dataLabelFormatString || "%s"; label = $.jqplot.sprintf(fstr, this.dataLabels[i]); } - - var fact = (this._radius ) * this.dataLabelPositionFactor + this.sliceMargin + this.dataLabelNudge; - - var x = this._center[0] + Math.cos(avgang) * fact + this.canvas._offsets.left; - var y = this._center[1] + Math.sin(avgang) * fact + this.canvas._offsets.top; - - var labelelem = $('
' + label + '
').insertBefore(plot.eventCanvas._elem); + + var fact = + this._radius * this.dataLabelPositionFactor + + this.sliceMargin + + this.dataLabelNudge; + + var x = + this._center[0] + + Math.cos(avgang) * fact + + this.canvas._offsets.left; + var y = + this._center[1] + + Math.sin(avgang) * fact + + this.canvas._offsets.top; + + var labelelem = $( + '
' + + label + + "
", + ).insertBefore(plot.eventCanvas._elem); if (this.dataLabelCenterOn) { - x -= labelelem.width()/2; - y -= labelelem.height()/2; - } - else { - x -= labelelem.width() * Math.sin(avgang/2); - y -= labelelem.height()/2; + x -= labelelem.width() / 2; + y -= labelelem.height() / 2; + } else { + x -= labelelem.width() * Math.sin(avgang / 2); + y -= labelelem.height() / 2; } x = Math.round(x); y = Math.round(y); - labelelem.css({left: x, top: y}); + labelelem.css({ left: x, top: y }); } - } + } }; - - $.jqplot.PieAxisRenderer = function() { + + $.jqplot.PieAxisRenderer = function () { $.jqplot.LinearAxisRenderer.call(this); }; - + $.jqplot.PieAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer(); $.jqplot.PieAxisRenderer.prototype.constructor = $.jqplot.PieAxisRenderer; - - + // There are no traditional axes on a pie chart. We just need to provide // dummy objects with properties so the plot will render. // called with scope of axis object. - $.jqplot.PieAxisRenderer.prototype.init = function(options){ + $.jqplot.PieAxisRenderer.prototype.init = function (options) { // this.tickRenderer = $.jqplot.PieTickRenderer; $.extend(true, this, options); @@ -521,31 +585,29 @@ // and provide u2p and p2u functionality for mouse cursor, etc. // for convenience set _dataBounds to 0 and 100 and // set min/max to 0 and 100. - this._dataBounds = {min:0, max:100}; + this._dataBounds = { min: 0, max: 100 }; this.min = 0; this.max = 100; this.showTicks = false; this.ticks = []; this.showMark = false; - this.show = false; + this.show = false; }; - - - - - $.jqplot.PieLegendRenderer = function(){ + + $.jqplot.PieLegendRenderer = function () { $.jqplot.TableLegendRenderer.call(this); }; - + $.jqplot.PieLegendRenderer.prototype = new $.jqplot.TableLegendRenderer(); - $.jqplot.PieLegendRenderer.prototype.constructor = $.jqplot.PieLegendRenderer; - + $.jqplot.PieLegendRenderer.prototype.constructor = + $.jqplot.PieLegendRenderer; + /** * Class: $.jqplot.PieLegendRenderer * Legend Renderer specific to pie plots. Set by default * when user creates a pie plot. */ - $.jqplot.PieLegendRenderer.prototype.init = function(options) { + $.jqplot.PieLegendRenderer.prototype.init = function (options) { // Group: Properties // // prop: numberRows @@ -556,176 +618,184 @@ this.numberColumns = null; $.extend(true, this, options); }; - + // called with context of legend - $.jqplot.PieLegendRenderer.prototype.draw = function() { + $.jqplot.PieLegendRenderer.prototype.draw = function () { var legend = this; if (this.show) { var series = this._series; + this._elem = $(document.createElement("table")); + this._elem.addClass("jqplot-table-legend"); - this._elem = $(document.createElement('table')); - this._elem.addClass('jqplot-table-legend'); - - var ss = {position:'absolute'}; + var ss = { position: "absolute" }; if (this.background) { - ss['background'] = this.background; + ss["background"] = this.background; } if (this.border) { - ss['border'] = this.border; + ss["border"] = this.border; } if (this.fontSize) { - ss['fontSize'] = this.fontSize; + ss["fontSize"] = this.fontSize; } if (this.fontFamily) { - ss['fontFamily'] = this.fontFamily; + ss["fontFamily"] = this.fontFamily; } if (this.textColor) { - ss['textColor'] = this.textColor; + ss["textColor"] = this.textColor; } if (this.marginTop != null) { - ss['marginTop'] = this.marginTop; + ss["marginTop"] = this.marginTop; } if (this.marginBottom != null) { - ss['marginBottom'] = this.marginBottom; + ss["marginBottom"] = this.marginBottom; } if (this.marginLeft != null) { - ss['marginLeft'] = this.marginLeft; + ss["marginLeft"] = this.marginLeft; } if (this.marginRight != null) { - ss['marginRight'] = this.marginRight; + ss["marginRight"] = this.marginRight; } this._elem.css(ss); // Pie charts legends don't go by number of series, but by number of data points // in the series. Refactor things here for that. - - var pad = false, + + var pad = false, reverse = false, - nr, + nr, nc; var s = series[0]; var colorGenerator = new $.jqplot.ColorGenerator(s.seriesColors); - + if (s.show) { var pd = s.data; if (this.numberRows) { nr = this.numberRows; - if (!this.numberColumns){ - nc = Math.ceil(pd.length/nr); - } - else{ + if (!this.numberColumns) { + nc = Math.ceil(pd.length / nr); + } else { nc = this.numberColumns; } - } - else if (this.numberColumns) { + } else if (this.numberColumns) { nc = this.numberColumns; - nr = Math.ceil(pd.length/this.numberColumns); - } - else { + nr = Math.ceil(pd.length / this.numberColumns); + } else { nr = pd.length; nc = 1; } - + var i, j; - var tr, td1, td2; + var tr, td1, td2; var lt, rs, color; - var idx = 0; - var div0, div1; - - for (i=0; i0){ + if (!reverse) { + if (i > 0) { pad = true; - } - else{ + } else { pad = false; } - } - else{ - if (i == nr -1){ + } else { + if (i == nr - 1) { pad = false; - } - else{ + } else { pad = true; } } - rs = (pad) ? this.rowSpacing : '0'; - - + rs = pad ? this.rowSpacing : "0"; - td1 = $(document.createElement('td')); - td1.addClass('jqplot-table-legend jqplot-table-legend-swatch'); - td1.css({textAlign: 'center', paddingTop: rs}); + td1 = $(document.createElement("td")); + td1.addClass( + "jqplot-table-legend jqplot-table-legend-swatch", + ); + td1.css({ textAlign: "center", paddingTop: rs }); - div0 = $(document.createElement('div')); - div0.addClass('jqplot-table-legend-swatch-outline'); - div1 = $(document.createElement('div')); - div1.addClass('jqplot-table-legend-swatch'); - div1.css({backgroundColor: color, borderColor: color}); + div0 = $(document.createElement("div")); + div0.addClass("jqplot-table-legend-swatch-outline"); + div1 = $(document.createElement("div")); + div1.addClass("jqplot-table-legend-swatch"); + div1.css({ + backgroundColor: color, + borderColor: color, + }); td1.append(div0.append(div1)); - td2 = $(document.createElement('td')); - td2.addClass('jqplot-table-legend jqplot-table-legend-label'); - td2.css('paddingTop', rs); + td2 = $(document.createElement("td")); + td2.addClass( + "jqplot-table-legend jqplot-table-legend-label", + ); + td2.css("paddingTop", rs); - if (this.escapeHtml){ + if (this.escapeHtml) { td2.text(lt); - } - else { + } else { td2.html(lt); } if (reverse) { td2.prependTo(tr); td1.prependTo(tr); - } - else { + } else { td1.appendTo(tr); td2.appendTo(tr); } pad = true; } idx++; - } + } } } } - return this._elem; + return this._elem; }; - - $.jqplot.PieRenderer.prototype.handleMove = function(ev, gridpos, datapos, neighbor, plot) { + + $.jqplot.PieRenderer.prototype.handleMove = function ( + ev, + gridpos, + datapos, + neighbor, + plot, + ) { if (neighbor) { - var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; - plot.target.trigger('jqplotDataMouseOver', ins); - if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.pieRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) { - plot.target.trigger('jqplotDataHighlight', ins); - highlight (plot, ins[0], ins[1]); + var ins = [ + neighbor.seriesIndex, + neighbor.pointIndex, + neighbor.data, + ]; + plot.target.trigger("jqplotDataMouseOver", ins); + if ( + plot.series[ins[0]].highlightMouseOver && + !( + ins[0] == plot.plugins.pieRenderer.highlightedSeriesIndex && + ins[1] == plot.series[ins[0]]._highlightedPoint + ) + ) { + plot.target.trigger("jqplotDataHighlight", ins); + highlight(plot, ins[0], ins[1]); } - } - else if (neighbor == null) { - unhighlight (plot); + } else if (neighbor == null) { + unhighlight(plot); } }; - - + // this.eventCanvas._elem.bind($.jqplot.eventListenerHooks[i][0], {plot:this}, $.jqplot.eventListenerHooks[i][1]); - + // setup default renderers for axes and legend so user doesn't have to // called with scope of plot function preInit(target, data, options) { @@ -737,25 +807,24 @@ var setopts = false; if (options.seriesDefaults.renderer == $.jqplot.PieRenderer) { setopts = true; - } - else if (options.series) { - for (var i=0; i < options.series.length; i++) { + } else if (options.series) { + for (var i = 0; i < options.series.length; i++) { if (options.series[i].renderer == $.jqplot.PieRenderer) { setopts = true; } } } - + if (setopts) { options.axesDefaults.renderer = $.jqplot.PieAxisRenderer; options.legend.renderer = $.jqplot.PieLegendRenderer; options.legend.preDraw = true; - options.seriesDefaults.pointLabels = {show: false}; + options.seriesDefaults.pointLabels = { show: false }; } } - + function postInit(target, data, options) { - for (var i=0; i570)?o[p]*0.8:o[p]+0.3*(255-o[p]);o[p]=parseInt(o[p],10)}this.highlightColors.push("rgb("+o[0]+","+o[1]+","+o[2]+")")}}this.highlightColorGenerator=new e.jqplot.ColorGenerator(this.highlightColors);u.postParseOptionsHooks.addOnce(m);u.postInitHooks.addOnce(g);u.eventListenerHooks.addOnce("jqplotMouseMove",b);u.eventListenerHooks.addOnce("jqplotMouseDown",a);u.eventListenerHooks.addOnce("jqplotMouseUp",l);u.eventListenerHooks.addOnce("jqplotClick",f);u.eventListenerHooks.addOnce("jqplotRightClick",n);u.postDrawHooks.addOnce(i)};e.jqplot.PieRenderer.prototype.setGridData=function(t){var p=[];var u=[];var o=this.startAngle/180*Math.PI;var s=0;this._drawData=false;for(var r=0;r0){p[r]+=p[r-1]}s+=this.data[r][1]}var q=Math.PI*2/p[p.length-1];for(var r=0;r0){p[r]+=p[r-1]}s+=t[r][1]}var q=Math.PI*2/p[p.length-1];for(var r=0;r0&&s>0.01&&s<6.282){w=parseFloat(p)/2/h(q)}return w}e.jqplot.PieRenderer.prototype.drawSlice=function(B,z,y,u,w){if(this._drawData){var p=this._radius;var A=this.fill;var x=this.lineWidth;var s=this.sliceMargin;if(this.fill==false){s+=this.lineWidth}B.save();B.translate(this._center[0],this._center[1]);var D=j(z,y,this.sliceMargin,this.fill,this.lineWidth);var o=D*Math.cos((z+y)/2);var C=D*Math.sin((z+y)/2);if((y-z)<=Math.PI){p-=D}else{p+=D}B.translate(o,C);if(w){for(var v=0,t=this.shadowDepth;v6.282+this.startAngle){y=6.282+this.startAngle;if(z>y){z=6.281+this.startAngle}}if(z>=y){return}B.beginPath();B.fillStyle=u;B.strokeStyle=u;B.lineWidth=x;B.arc(0,0,r,z,y,false);B.lineTo(0,0);B.closePath();if(A){B.fill()}else{B.stroke()}}};e.jqplot.PieRenderer.prototype.draw=function(B,z,E,o){var W;var H=(E!=undefined)?E:{};var t=0;var s=0;var N=1;var L=new e.jqplot.ColorGenerator(this.seriesColors);if(E.legendInfo&&E.legendInfo.placement=="insideGrid"){var J=E.legendInfo;switch(J.location){case"nw":t=J.width+J.xoffset;break;case"w":t=J.width+J.xoffset;break;case"sw":t=J.width+J.xoffset;break;case"ne":t=J.width+J.xoffset;N=-1;break;case"e":t=J.width+J.xoffset;N=-1;break;case"se":t=J.width+J.xoffset;N=-1;break;case"n":s=J.height+J.yoffset;break;case"s":s=J.height+J.yoffset;N=-1;break;default:break}}var K=(H.shadow!=undefined)?H.shadow:this.shadow;var A=(H.fill!=undefined)?H.fill:this.fill;var C=B.canvas.width;var I=B.canvas.height;var Q=C-t-2*this.padding;var X=I-s-2*this.padding;var M=Math.min(Q,X);var Y=M;this._sliceAngles=[];var v=this.sliceMargin;if(this.fill==false){v+=this.lineWidth}var q;var G=0;var R,aa,Z,ab;var D=this.startAngle/180*Math.PI;for(var W=0,V=z.length;WMath.PI){G=Math.max(q,G)}}if(this.diameter!=null&&this.diameter>0){this._diameter=this.diameter-2*G}else{this._diameter=Y-2*G}if(this._diameter<6){e.jqplot.log("Diameter of pie too small, not rendering.");return}var S=this._radius=this._diameter/2;this._center=[(C-N*t)/2+N*t+G*Math.cos(D),(I-N*s)/2+N*s+G*Math.sin(D)];if(this.shadow){for(var W=0,V=z.length;W=this.dataLabelThreshold){var F,U=(this._sliceAngles[W][0]+this._sliceAngles[W][1])/2,T;if(this.dataLabels=="label"){F=this.dataLabelFormatString||"%s";T=e.jqplot.sprintf(F,z[W][0])}else{if(this.dataLabels=="value"){F=this.dataLabelFormatString||"%d";T=e.jqplot.sprintf(F,this.data[W][1])}else{if(this.dataLabels=="percent"){F=this.dataLabelFormatString||"%d%%";T=e.jqplot.sprintf(F,z[W][2]*100)}else{if(this.dataLabels.constructor==Array){F=this.dataLabelFormatString||"%s";T=e.jqplot.sprintf(F,this.dataLabels[W])}}}}var p=(this._radius)*this.dataLabelPositionFactor+this.sliceMargin+this.dataLabelNudge;var P=this._center[0]+Math.cos(U)*p+this.canvas._offsets.left;var O=this._center[1]+Math.sin(U)*p+this.canvas._offsets.top;var u=e('
'+T+"
").insertBefore(o.eventCanvas._elem);if(this.dataLabelCenterOn){P-=u.width()/2;O-=u.height()/2}else{P-=u.width()*Math.sin(U/2);O-=u.height()/2}P=Math.round(P);O=Math.round(O);u.css({left:P,top:O})}}};e.jqplot.PieAxisRenderer=function(){e.jqplot.LinearAxisRenderer.call(this)};e.jqplot.PieAxisRenderer.prototype=new e.jqplot.LinearAxisRenderer();e.jqplot.PieAxisRenderer.prototype.constructor=e.jqplot.PieAxisRenderer;e.jqplot.PieAxisRenderer.prototype.init=function(o){this.tickRenderer=e.jqplot.PieTickRenderer;e.extend(true,this,o);this._dataBounds={min:0,max:100};this.min=0;this.max=100;this.showTicks=false;this.ticks=[];this.showMark=false;this.show=false};e.jqplot.PieLegendRenderer=function(){e.jqplot.TableLegendRenderer.call(this)};e.jqplot.PieLegendRenderer.prototype=new e.jqplot.TableLegendRenderer();e.jqplot.PieLegendRenderer.prototype.constructor=e.jqplot.PieLegendRenderer;e.jqplot.PieLegendRenderer.prototype.init=function(o){this.numberRows=null;this.numberColumns=null;e.extend(true,this,o)};e.jqplot.PieLegendRenderer.prototype.draw=function(){var r=this;if(this.show){var B=this._series;this._elem=e(document.createElement("table"));this._elem.addClass("jqplot-table-legend");var E={position:"absolute"};if(this.background){E.background=this.background}if(this.border){E.border=this.border}if(this.fontSize){E.fontSize=this.fontSize}if(this.fontFamily){E.fontFamily=this.fontFamily}if(this.textColor){E.textColor=this.textColor}if(this.marginTop!=null){E.marginTop=this.marginTop}if(this.marginBottom!=null){E.marginBottom=this.marginBottom}if(this.marginLeft!=null){E.marginLeft=this.marginLeft}if(this.marginRight!=null){E.marginRight=this.marginRight}this._elem.css(E);var I=false,A=false,o,y;var C=B[0];var p=new e.jqplot.ColorGenerator(C.seriesColors);if(C.show){var J=C.data;if(this.numberRows){o=this.numberRows;if(!this.numberColumns){y=Math.ceil(J.length/o)}else{y=this.numberColumns}}else{if(this.numberColumns){y=this.numberColumns;o=Math.ceil(J.length/this.numberColumns)}else{o=J.length;y=1}}var H,G;var q,w,v;var x,z,F;var D=0;var u,t;for(H=0;H0){I=true}else{I=false}}else{if(H==o-1){I=false}else{I=true}}z=(I)?this.rowSpacing:"0";w=e(document.createElement("td"));w.addClass("jqplot-table-legend jqplot-table-legend-swatch");w.css({textAlign:"center",paddingTop:z});u=e(document.createElement("div"));u.addClass("jqplot-table-legend-swatch-outline");t=e(document.createElement("div"));t.addClass("jqplot-table-legend-swatch");t.css({backgroundColor:F,borderColor:F});w.append(u.append(t));v=e(document.createElement("td"));v.addClass("jqplot-table-legend jqplot-table-legend-label");v.css("paddingTop",z);if(this.escapeHtml){v.text(x)}else{v.html(x)}if(A){v.prependTo(q);w.prependTo(q)}else{w.appendTo(q);v.appendTo(q)}I=true}D++}}}}return this._elem};e.jqplot.PieRenderer.prototype.handleMove=function(q,p,t,s,r){if(s){var o=[s.seriesIndex,s.pointIndex,s.data];r.target.trigger("jqplotDataMouseOver",o);if(r.series[o[0]].highlightMouseOver&&!(o[0]==r.plugins.pieRenderer.highlightedSeriesIndex&&o[1]==r.series[o[0]]._highlightedPoint)){r.target.trigger("jqplotDataHighlight",o);d(r,o[0],o[1])}}else{if(s==null){k(r)}}};function c(s,r,p){p=p||{};p.axesDefaults=p.axesDefaults||{};p.legend=p.legend||{};p.seriesDefaults=p.seriesDefaults||{};var o=false;if(p.seriesDefaults.renderer==e.jqplot.PieRenderer){o=true}else{if(p.series){for(var q=0;q 570 ? o[p] * 0.8 : o[p] + 0.3 * (255 - o[p]); + o[p] = parseInt(o[p], 10); + } + this.highlightColors.push( + "rgb(" + o[0] + "," + o[1] + "," + o[2] + ")", + ); + } + } + this.highlightColorGenerator = new e.jqplot.ColorGenerator( + this.highlightColors, + ); + u.postParseOptionsHooks.addOnce(m); + u.postInitHooks.addOnce(g); + u.eventListenerHooks.addOnce("jqplotMouseMove", b); + u.eventListenerHooks.addOnce("jqplotMouseDown", a); + u.eventListenerHooks.addOnce("jqplotMouseUp", l); + u.eventListenerHooks.addOnce("jqplotClick", f); + u.eventListenerHooks.addOnce("jqplotRightClick", n); + u.postDrawHooks.addOnce(i); + }; + e.jqplot.PieRenderer.prototype.setGridData = function (t) { + var p = []; + var u = []; + var o = (this.startAngle / 180) * Math.PI; + var s = 0; + this._drawData = false; + for (var r = 0; r < this.data.length; r++) { + if (this.data[r][1] != 0) { + this._drawData = true; + } + p.push(this.data[r][1]); + u.push([this.data[r][0]]); + if (r > 0) { + p[r] += p[r - 1]; + } + s += this.data[r][1]; + } + var q = (Math.PI * 2) / p[p.length - 1]; + for (var r = 0; r < p.length; r++) { + u[r][1] = p[r] * q; + u[r][2] = this.data[r][1] / s; + } + this.gridData = u; + }; + e.jqplot.PieRenderer.prototype.makeGridData = function (t, u) { + var p = []; + var v = []; + var s = 0; + var o = (this.startAngle / 180) * Math.PI; + this._drawData = false; + for (var r = 0; r < t.length; r++) { + if (this.data[r][1] != 0) { + this._drawData = true; + } + p.push(t[r][1]); + v.push([t[r][0]]); + if (r > 0) { + p[r] += p[r - 1]; + } + s += t[r][1]; + } + var q = (Math.PI * 2) / p[p.length - 1]; + for (var r = 0; r < p.length; r++) { + v[r][1] = p[r] * q; + v[r][2] = t[r][1] / s; + } + return v; + }; + function h(o) { + return Math.sin((o - (o - Math.PI) / 8 / Math.PI) / 2); + } + function j(u, t, o, v, r) { + var w = 0; + var q = t - u; + var s = Math.abs(q); + var p = o; + if (v == false) { + p += r; + } + if (p > 0 && s > 0.01 && s < 6.282) { + w = parseFloat(p) / 2 / h(q); + } + return w; + } + e.jqplot.PieRenderer.prototype.drawSlice = function (B, z, y, u, w) { + if (this._drawData) { + var p = this._radius; + var A = this.fill; + var x = this.lineWidth; + var s = this.sliceMargin; + if (this.fill == false) { + s += this.lineWidth; + } + B.save(); + B.translate(this._center[0], this._center[1]); + var D = j(z, y, this.sliceMargin, this.fill, this.lineWidth); + var o = D * Math.cos((z + y) / 2); + var C = D * Math.sin((z + y) / 2); + if (y - z <= Math.PI) { + p -= D; + } else { + p += D; + } + B.translate(o, C); + if (w) { + for (var v = 0, t = this.shadowDepth; v < t; v++) { + B.save(); + B.translate( + this.shadowOffset * + Math.cos((this.shadowAngle / 180) * Math.PI), + this.shadowOffset * + Math.sin((this.shadowAngle / 180) * Math.PI), + ); + q(p); + } + for (var v = 0, t = this.shadowDepth; v < t; v++) { + B.restore(); + } + } else { + q(p); + } + B.restore(); + } + function q(r) { + if (y > 6.282 + this.startAngle) { + y = 6.282 + this.startAngle; + if (z > y) { + z = 6.281 + this.startAngle; + } + } + if (z >= y) { + return; + } + B.beginPath(); + B.fillStyle = u; + B.strokeStyle = u; + B.lineWidth = x; + B.arc(0, 0, r, z, y, false); + B.lineTo(0, 0); + B.closePath(); + if (A) { + B.fill(); + } else { + B.stroke(); + } + } + }; + e.jqplot.PieRenderer.prototype.draw = function (B, z, E, o) { + var W; + var H = E != undefined ? E : {}; + var t = 0; + var s = 0; + var N = 1; + var L = new e.jqplot.ColorGenerator(this.seriesColors); + if (E.legendInfo && E.legendInfo.placement == "insideGrid") { + var J = E.legendInfo; + switch (J.location) { + case "nw": + t = J.width + J.xoffset; + break; + case "w": + t = J.width + J.xoffset; + break; + case "sw": + t = J.width + J.xoffset; + break; + case "ne": + t = J.width + J.xoffset; + N = -1; + break; + case "e": + t = J.width + J.xoffset; + N = -1; + break; + case "se": + t = J.width + J.xoffset; + N = -1; + break; + case "n": + s = J.height + J.yoffset; + break; + case "s": + s = J.height + J.yoffset; + N = -1; + break; + default: + break; + } + } + var K = H.shadow != undefined ? H.shadow : this.shadow; + var A = H.fill != undefined ? H.fill : this.fill; + var C = B.canvas.width; + var I = B.canvas.height; + var Q = C - t - 2 * this.padding; + var X = I - s - 2 * this.padding; + var M = Math.min(Q, X); + var Y = M; + this._sliceAngles = []; + var v = this.sliceMargin; + if (this.fill == false) { + v += this.lineWidth; + } + var q; + var G = 0; + var R, aa, Z, ab; + var D = (this.startAngle / 180) * Math.PI; + for (var W = 0, V = z.length; W < V; W++) { + aa = W == 0 ? D : z[W - 1][1] + D; + Z = z[W][1] + D; + this._sliceAngles.push([aa, Z]); + q = j(aa, Z, this.sliceMargin, this.fill, this.lineWidth); + if (Math.abs(Z - aa) > Math.PI) { + G = Math.max(q, G); + } + } + if (this.diameter != null && this.diameter > 0) { + this._diameter = this.diameter - 2 * G; + } else { + this._diameter = Y - 2 * G; + } + if (this._diameter < 6) { + e.jqplot.log("Diameter of pie too small, not rendering."); + return; + } + var S = (this._radius = this._diameter / 2); + this._center = [ + (C - N * t) / 2 + N * t + G * Math.cos(D), + (I - N * s) / 2 + N * s + G * Math.sin(D), + ]; + if (this.shadow) { + for (var W = 0, V = z.length; W < V; W++) { + ab = "rgba(0,0,0," + this.shadowAlpha + ")"; + this.renderer.drawSlice.call( + this, + B, + this._sliceAngles[W][0], + this._sliceAngles[W][1], + ab, + true, + ); + } + } + for (var W = 0; W < z.length; W++) { + this.renderer.drawSlice.call( + this, + B, + this._sliceAngles[W][0], + this._sliceAngles[W][1], + L.next(), + false, + ); + if ( + this.showDataLabels && + z[W][2] * 100 >= this.dataLabelThreshold + ) { + var F, + U = (this._sliceAngles[W][0] + this._sliceAngles[W][1]) / 2, + T; + if (this.dataLabels == "label") { + F = this.dataLabelFormatString || "%s"; + T = e.jqplot.sprintf(F, z[W][0]); + } else { + if (this.dataLabels == "value") { + F = this.dataLabelFormatString || "%d"; + T = e.jqplot.sprintf(F, this.data[W][1]); + } else { + if (this.dataLabels == "percent") { + F = this.dataLabelFormatString || "%d%%"; + T = e.jqplot.sprintf(F, z[W][2] * 100); + } else { + if (this.dataLabels.constructor == Array) { + F = this.dataLabelFormatString || "%s"; + T = e.jqplot.sprintf(F, this.dataLabels[W]); + } + } + } + } + var p = + this._radius * this.dataLabelPositionFactor + + this.sliceMargin + + this.dataLabelNudge; + var P = + this._center[0] + + Math.cos(U) * p + + this.canvas._offsets.left; + var O = + this._center[1] + + Math.sin(U) * p + + this.canvas._offsets.top; + var u = e( + '
' + + T + + "
", + ).insertBefore(o.eventCanvas._elem); + if (this.dataLabelCenterOn) { + P -= u.width() / 2; + O -= u.height() / 2; + } else { + P -= u.width() * Math.sin(U / 2); + O -= u.height() / 2; + } + P = Math.round(P); + O = Math.round(O); + u.css({ left: P, top: O }); + } + } + }; + e.jqplot.PieAxisRenderer = function () { + e.jqplot.LinearAxisRenderer.call(this); + }; + e.jqplot.PieAxisRenderer.prototype = new e.jqplot.LinearAxisRenderer(); + e.jqplot.PieAxisRenderer.prototype.constructor = e.jqplot.PieAxisRenderer; + e.jqplot.PieAxisRenderer.prototype.init = function (o) { + this.tickRenderer = e.jqplot.PieTickRenderer; + e.extend(true, this, o); + this._dataBounds = { min: 0, max: 100 }; + this.min = 0; + this.max = 100; + this.showTicks = false; + this.ticks = []; + this.showMark = false; + this.show = false; + }; + e.jqplot.PieLegendRenderer = function () { + e.jqplot.TableLegendRenderer.call(this); + }; + e.jqplot.PieLegendRenderer.prototype = new e.jqplot.TableLegendRenderer(); + e.jqplot.PieLegendRenderer.prototype.constructor = + e.jqplot.PieLegendRenderer; + e.jqplot.PieLegendRenderer.prototype.init = function (o) { + this.numberRows = null; + this.numberColumns = null; + e.extend(true, this, o); + }; + e.jqplot.PieLegendRenderer.prototype.draw = function () { + var r = this; + if (this.show) { + var B = this._series; + this._elem = e(document.createElement("table")); + this._elem.addClass("jqplot-table-legend"); + var E = { position: "absolute" }; + if (this.background) { + E.background = this.background; + } + if (this.border) { + E.border = this.border; + } + if (this.fontSize) { + E.fontSize = this.fontSize; + } + if (this.fontFamily) { + E.fontFamily = this.fontFamily; + } + if (this.textColor) { + E.textColor = this.textColor; + } + if (this.marginTop != null) { + E.marginTop = this.marginTop; + } + if (this.marginBottom != null) { + E.marginBottom = this.marginBottom; + } + if (this.marginLeft != null) { + E.marginLeft = this.marginLeft; + } + if (this.marginRight != null) { + E.marginRight = this.marginRight; + } + this._elem.css(E); + var I = false, + A = false, + o, + y; + var C = B[0]; + var p = new e.jqplot.ColorGenerator(C.seriesColors); + if (C.show) { + var J = C.data; + if (this.numberRows) { + o = this.numberRows; + if (!this.numberColumns) { + y = Math.ceil(J.length / o); + } else { + y = this.numberColumns; + } + } else { + if (this.numberColumns) { + y = this.numberColumns; + o = Math.ceil(J.length / this.numberColumns); + } else { + o = J.length; + y = 1; + } + } + var H, G; + var q, w, v; + var x, z, F; + var D = 0; + var u, t; + for (H = 0; H < o; H++) { + q = e(document.createElement("tr")); + q.addClass("jqplot-table-legend"); + if (A) { + q.prependTo(this._elem); + } else { + q.appendTo(this._elem); + } + for (G = 0; G < y; G++) { + if (D < J.length) { + x = this.labels[D] || J[D][0].toString(); + F = p.next(); + if (!A) { + if (H > 0) { + I = true; + } else { + I = false; + } + } else { + if (H == o - 1) { + I = false; + } else { + I = true; + } + } + z = I ? this.rowSpacing : "0"; + w = e(document.createElement("td")); + w.addClass( + "jqplot-table-legend jqplot-table-legend-swatch", + ); + w.css({ textAlign: "center", paddingTop: z }); + u = e(document.createElement("div")); + u.addClass("jqplot-table-legend-swatch-outline"); + t = e(document.createElement("div")); + t.addClass("jqplot-table-legend-swatch"); + t.css({ backgroundColor: F, borderColor: F }); + w.append(u.append(t)); + v = e(document.createElement("td")); + v.addClass( + "jqplot-table-legend jqplot-table-legend-label", + ); + v.css("paddingTop", z); + if (this.escapeHtml) { + v.text(x); + } else { + v.html(x); + } + if (A) { + v.prependTo(q); + w.prependTo(q); + } else { + w.appendTo(q); + v.appendTo(q); + } + I = true; + } + D++; + } + } + } + } + return this._elem; + }; + e.jqplot.PieRenderer.prototype.handleMove = function (q, p, t, s, r) { + if (s) { + var o = [s.seriesIndex, s.pointIndex, s.data]; + r.target.trigger("jqplotDataMouseOver", o); + if ( + r.series[o[0]].highlightMouseOver && + !( + o[0] == r.plugins.pieRenderer.highlightedSeriesIndex && + o[1] == r.series[o[0]]._highlightedPoint + ) + ) { + r.target.trigger("jqplotDataHighlight", o); + d(r, o[0], o[1]); + } + } else { + if (s == null) { + k(r); + } + } + }; + function c(s, r, p) { + p = p || {}; + p.axesDefaults = p.axesDefaults || {}; + p.legend = p.legend || {}; + p.seriesDefaults = p.seriesDefaults || {}; + var o = false; + if (p.seriesDefaults.renderer == e.jqplot.PieRenderer) { + o = true; + } else { + if (p.series) { + for (var q = 0; q < p.series.length; q++) { + if (p.series[q].renderer == e.jqplot.PieRenderer) { + o = true; + } + } + } + } + if (o) { + p.axesDefaults.renderer = e.jqplot.PieAxisRenderer; + p.legend.renderer = e.jqplot.PieLegendRenderer; + p.legend.preDraw = true; + p.seriesDefaults.pointLabels = { show: false }; + } + } + function g(r, q, o) { + for (var p = 0; p < this.series.length; p++) { + if (this.series[p].renderer.constructor == e.jqplot.PieRenderer) { + if (this.series[p].highlightMouseOver) { + this.series[p].highlightMouseDown = false; + } + } + } + } + function m(o) { + for (var p = 0; p < this.series.length; p++) { + this.series[p].seriesColors = this.seriesColors; + this.series[p].colorGenerator = e.jqplot.colorGenerator; + } + } + function d(t, r, q) { + var p = t.series[r]; + var o = t.plugins.pieRenderer.highlightCanvas; + o._ctx.clearRect(0, 0, o._ctx.canvas.width, o._ctx.canvas.height); + p._highlightedPoint = q; + t.plugins.pieRenderer.highlightedSeriesIndex = r; + p.renderer.drawSlice.call( + p, + o._ctx, + p._sliceAngles[q][0], + p._sliceAngles[q][1], + p.highlightColorGenerator.get(q), + false, + ); + } + function k(q) { + var o = q.plugins.pieRenderer.highlightCanvas; + o._ctx.clearRect(0, 0, o._ctx.canvas.width, o._ctx.canvas.height); + for (var p = 0; p < q.series.length; p++) { + q.series[p]._highlightedPoint = null; + } + q.plugins.pieRenderer.highlightedSeriesIndex = null; + q.target.trigger("jqplotDataUnhighlight"); + } + function b(s, r, v, u, t) { + if (u) { + var q = [u.seriesIndex, u.pointIndex, u.data]; + var p = jQuery.Event("jqplotDataMouseOver"); + p.pageX = s.pageX; + p.pageY = s.pageY; + t.target.trigger(p, q); + if ( + t.series[q[0]].highlightMouseOver && + !( + q[0] == t.plugins.pieRenderer.highlightedSeriesIndex && + q[1] == t.series[q[0]]._highlightedPoint + ) + ) { + var o = jQuery.Event("jqplotDataHighlight"); + o.which = s.which; + o.pageX = s.pageX; + o.pageY = s.pageY; + t.target.trigger(o, q); + d(t, q[0], q[1]); + } + } else { + if (u == null) { + k(t); + } + } + } + function a(r, q, u, t, s) { + if (t) { + var p = [t.seriesIndex, t.pointIndex, t.data]; + if ( + s.series[p[0]].highlightMouseDown && + !( + p[0] == s.plugins.pieRenderer.highlightedSeriesIndex && + p[1] == s.series[p[0]]._highlightedPoint + ) + ) { + var o = jQuery.Event("jqplotDataHighlight"); + o.which = r.which; + o.pageX = r.pageX; + o.pageY = r.pageY; + s.target.trigger(o, p); + d(s, p[0], p[1]); + } + } else { + if (t == null) { + k(s); + } + } + } + function l(q, p, t, s, r) { + var o = r.plugins.pieRenderer.highlightedSeriesIndex; + if (o != null && r.series[o].highlightMouseDown) { + k(r); + } + } + function f(r, q, u, t, s) { + if (t) { + var p = [t.seriesIndex, t.pointIndex, t.data]; + var o = jQuery.Event("jqplotDataClick"); + o.which = r.which; + o.pageX = r.pageX; + o.pageY = r.pageY; + s.target.trigger(o, p); + } + } + function n(s, r, v, u, t) { + if (u) { + var q = [u.seriesIndex, u.pointIndex, u.data]; + var o = t.plugins.pieRenderer.highlightedSeriesIndex; + if (o != null && t.series[o].highlightMouseDown) { + k(t); + } + var p = jQuery.Event("jqplotDataRightClick"); + p.which = s.which; + p.pageX = s.pageX; + p.pageY = s.pageY; + t.target.trigger(p, q); + } + } + function i() { + if ( + this.plugins.pieRenderer && + this.plugins.pieRenderer.highlightCanvas + ) { + this.plugins.pieRenderer.highlightCanvas.resetCanvas(); + this.plugins.pieRenderer.highlightCanvas = null; + } + this.plugins.pieRenderer = { highlightedSeriesIndex: null }; + this.plugins.pieRenderer.highlightCanvas = new e.jqplot.GenericCanvas(); + var p = e(this.targetId + " .jqplot-data-label"); + if (p.length) { + e(p[0]).before( + this.plugins.pieRenderer.highlightCanvas.createElement( + this._gridPadding, + "jqplot-pieRenderer-highlight-canvas", + this._plotDimensions, + this, + ), + ); + } else { + this.eventCanvas._elem.before( + this.plugins.pieRenderer.highlightCanvas.createElement( + this._gridPadding, + "jqplot-pieRenderer-highlight-canvas", + this._plotDimensions, + this, + ), + ); + } + var o = this.plugins.pieRenderer.highlightCanvas.setContext(); + this.eventCanvas._elem.bind("mouseleave", { plot: this }, function (q) { + k(q.data.plot); + }); + } + e.jqplot.preInitHooks.push(c); + e.jqplot.PieTickRenderer = function () { + e.jqplot.AxisTickRenderer.call(this); + }; + e.jqplot.PieTickRenderer.prototype = new e.jqplot.AxisTickRenderer(); + e.jqplot.PieTickRenderer.prototype.constructor = e.jqplot.PieTickRenderer; +})(jQuery); diff --git a/src/adminactions/static/adminactions/js/massupdate.js b/src/adminactions/static/adminactions/js/massupdate.js index 67b6a0b7..1890ce84 100644 --- a/src/adminactions/static/adminactions/js/massupdate.js +++ b/src/adminactions/static/adminactions/js/massupdate.js @@ -1,46 +1,74 @@ - "use strict"; +"use strict"; (function ($) { $(function () { - $('.func_select').change(function () { - var $option = $(this).find(':selected'); - var target = $(this).parent().parent().find('.col_field input, .col_field select .col_field textarea'); - if ($option.hasClass('noparam')) { - $(target).attr('disabled', 'disabled'); + $(".func_select").change(function () { + var $option = $(this).find(":selected"); + var target = $(this) + .parent() + .parent() + .find( + ".col_field input, .col_field select .col_field textarea", + ); + if ($option.hasClass("noparam")) { + $(target).attr("disabled", "disabled"); } else { - $(target).removeAttr('disabled'); + $(target).removeAttr("disabled"); } }); - $('.col_field input, .col_field select, .col_field textarea, .col_func select').each(function () { - if (!$(this).parent().parent().find('.col_enabler input[type=checkbox]').is(':checked')) { - $(this).attr('disabled', 'disabled'); + $( + ".col_field input, .col_field select, .col_field textarea, .col_func select", + ).each(function () { + if ( + !$(this) + .parent() + .parent() + .find(".col_enabler input[type=checkbox]") + .is(":checked") + ) { + $(this).attr("disabled", "disabled"); } }); - $('.fastfieldvalue').click(function () { - var check = $(this).parent().parent().find('.enabler'); - var selection = $(this).data('value'); - $(check).attr('checked', true); - var target = $(this).parent().parent().find('.col_field input, .col_field select, .col_field textarea').not('.enabler'); - $(this).parent().parent().find('.col_func select').removeAttr('disabled'); - $(target).removeAttr('disabled'); - if ($(target).is('select')) { - $('option', target).each(function (i, selected) { + $(".fastfieldvalue").click(function () { + var check = $(this).parent().parent().find(".enabler"); + var selection = $(this).data("value"); + $(check).attr("checked", true); + var target = $(this) + .parent() + .parent() + .find( + ".col_field input, .col_field select, .col_field textarea", + ) + .not(".enabler"); + $(this) + .parent() + .parent() + .find(".col_func select") + .removeAttr("disabled"); + $(target).removeAttr("disabled"); + if ($(target).is("select")) { + $("option", target).each(function (i, selected) { if ($(this).val().toString() === selection.toString()) { - $(this).attr('selected', true); + $(this).attr("selected", true); } }); - } else if ($(target).is('input[type=checkbox]')) { - $(target).attr('checked', selection === 'True'); + } else if ($(target).is("input[type=checkbox]")) { + $(target).attr("checked", selection === "True"); } else { $(target).val(selection); } }); - $('.enabler').click(function () { - var target = $(this).parent().parent().find('.col_field input, .col_field select, .col_field textarea, .col_func select'); - if ($(this).is(':checked')) { - $(target).removeAttr('disabled'); + $(".enabler").click(function () { + var target = $(this) + .parent() + .parent() + .find( + ".col_field input, .col_field select, .col_field textarea, .col_func select", + ); + if ($(this).is(":checked")) { + $(target).removeAttr("disabled"); } else { - $(target).attr('disabled', 'disabled'); + $(target).attr("disabled", "disabled"); } - }) + }); }); })(django.jQuery); diff --git a/src/adminactions/static/adminactions/js/massupdate.min.js b/src/adminactions/static/adminactions/js/massupdate.min.js index 7332580d..1890ce84 100644 --- a/src/adminactions/static/adminactions/js/massupdate.min.js +++ b/src/adminactions/static/adminactions/js/massupdate.min.js @@ -1 +1,74 @@ -"use strict";(function($){$(function(){$(".func_select").change(function(){var $option=$(this).find(":selected");var target=$(this).parent().parent().find(".col_field input, .col_field select .col_field textarea");if($option.hasClass("noparam")){$(target).attr("disabled","disabled")}else{$(target).removeAttr("disabled")}});$(".col_field input, .col_field select, .col_field textarea, .col_func select").each(function(){if(!$(this).parent().parent().find(".col_enabler input[type=checkbox]").is(":checked")){$(this).attr("disabled","disabled")}});$(".fastfieldvalue").click(function(){var check=$(this).parent().parent().find(".enabler");var selection=$(this).data("value");$(check).attr("checked",true);var target=$(this).parent().parent().find(".col_field input, .col_field select, .col_field textarea").not(".enabler");$(this).parent().parent().find(".col_func select").removeAttr("disabled");$(target).removeAttr("disabled");if($(target).is("select")){$("option",target).each(function(i,selected){if($(this).val().toString()===selection.toString()){$(this).attr("selected",true)}})}else if($(target).is("input[type=checkbox]")){$(target).attr("checked",selection==="True")}else{$(target).val(selection)}});$(".enabler").click(function(){var target=$(this).parent().parent().find(".col_field input, .col_field select, .col_field textarea, .col_func select");if($(this).is(":checked")){$(target).removeAttr("disabled")}else{$(target).attr("disabled","disabled")}})})})(django.jQuery); \ No newline at end of file +"use strict"; +(function ($) { + $(function () { + $(".func_select").change(function () { + var $option = $(this).find(":selected"); + var target = $(this) + .parent() + .parent() + .find( + ".col_field input, .col_field select .col_field textarea", + ); + if ($option.hasClass("noparam")) { + $(target).attr("disabled", "disabled"); + } else { + $(target).removeAttr("disabled"); + } + }); + $( + ".col_field input, .col_field select, .col_field textarea, .col_func select", + ).each(function () { + if ( + !$(this) + .parent() + .parent() + .find(".col_enabler input[type=checkbox]") + .is(":checked") + ) { + $(this).attr("disabled", "disabled"); + } + }); + $(".fastfieldvalue").click(function () { + var check = $(this).parent().parent().find(".enabler"); + var selection = $(this).data("value"); + $(check).attr("checked", true); + var target = $(this) + .parent() + .parent() + .find( + ".col_field input, .col_field select, .col_field textarea", + ) + .not(".enabler"); + $(this) + .parent() + .parent() + .find(".col_func select") + .removeAttr("disabled"); + $(target).removeAttr("disabled"); + if ($(target).is("select")) { + $("option", target).each(function (i, selected) { + if ($(this).val().toString() === selection.toString()) { + $(this).attr("selected", true); + } + }); + } else if ($(target).is("input[type=checkbox]")) { + $(target).attr("checked", selection === "True"); + } else { + $(target).val(selection); + } + }); + $(".enabler").click(function () { + var target = $(this) + .parent() + .parent() + .find( + ".col_field input, .col_field select, .col_field textarea, .col_func select", + ); + if ($(this).is(":checked")) { + $(target).removeAttr("disabled"); + } else { + $(target).attr("disabled", "disabled"); + } + }); + }); +})(django.jQuery); diff --git a/src/adminactions/static/adminactions/js/merge.js b/src/adminactions/static/adminactions/js/merge.js index bceaba6e..0616ba6c 100644 --- a/src/adminactions/static/adminactions/js/merge.js +++ b/src/adminactions/static/adminactions/js/merge.js @@ -1,68 +1,84 @@ (function ($) { $(function () { var select = function (from) { - return function ( event ) { + return function (event) { event.preventDefault(); var $row = $(this).parent().parent(); var $sel = $row.find(from); - $('.result input', $row).val($('input.raw-value', $sel).val()); + $(".result input", $row).val($("input.raw-value", $sel).val()); highlight(); }; }; var highlight = function () { var RIGHT = []; - $('.mergetable tr.merge-row').each(function () { + $(".mergetable tr.merge-row").each(function () { + var $result = $(this).find("td.result"); + var $left = $(this).find("td.origin"); + var $right = $(this).find("td.other"); + var field_name = $(this).find("td:first").attr("data-content"); - var $result = $(this).find('td.result'); - var $left = $(this).find('td.origin'); - var $right = $(this).find('td.other'); - var field_name = $(this).find('td:first').attr('data-content'); + $("td", this).removeClass("selected"); - $('td', this).removeClass("selected"); - - if ($('input.raw-value', $right).val() === $('input.raw-value', $left).val()) { - $('p.display', $result).text($('p.display', $left).text()); - } else if ($('input.raw-value', $result).val() === $('input.raw-value', $left).val()) { - $(this).find('td.origin').addClass("selected"); - $('p.display', $result).text($('p.display', $left).text()); - } else if ($('input.raw-value', $result).val() === $('input.raw-value', $right).val()) { - $(this).find('td.other').addClass("selected"); - $('p.display', $result).text($('p.display', $right).text()); + if ( + $("input.raw-value", $right).val() === + $("input.raw-value", $left).val() + ) { + $("p.display", $result).text($("p.display", $left).text()); + } else if ( + $("input.raw-value", $result).val() === + $("input.raw-value", $left).val() + ) { + $(this).find("td.origin").addClass("selected"); + $("p.display", $result).text($("p.display", $left).text()); + } else if ( + $("input.raw-value", $result).val() === + $("input.raw-value", $right).val() + ) { + $(this).find("td.other").addClass("selected"); + $("p.display", $result).text($("p.display", $right).text()); RIGHT.push(field_name); } - $('input[name=field_names]').val(RIGHT); + $("input[name=field_names]").val(RIGHT); }); - $('.mergetable tr.preview-row').each(function () { - - var $result = $(this).find('td.result'); - var $left = $(this).find('td.origin'); - var $right = $(this).find('td.other'); - var field_name = $(this).find('td:first').attr('data-content'); + $(".mergetable tr.preview-row").each(function () { + var $result = $(this).find("td.result"); + var $left = $(this).find("td.origin"); + var $right = $(this).find("td.other"); + var field_name = $(this).find("td:first").attr("data-content"); - $('td', this).removeClass("selected"); + $("td", this).removeClass("selected"); - if ($('.original .display', this).text() !== $('.result .display', this).text()){ + if ( + $(".original .display", this).text() !== + $(".result .display", this).text() + ) { $(this).addClass("changed"); } }); }; - $('a.origin').click(select("td.origin")); - $('a.other').click(select("td.other")); + $("a.origin").click(select("td.origin")); + $("a.other").click(select("td.other")); - $('a.swap').click(function ( event ) { + $("a.swap").click(function (event) { event.preventDefault(); var left = []; var right = []; var $master = $('input[name="master_pk"]'); var $other = $('input[name="other_pk"]'); - $('.column.origin').each(function () { - left.push([$('input.raw-value', this).val(), $('.display', this).text()]); + $(".column.origin").each(function () { + left.push([ + $("input.raw-value", this).val(), + $(".display", this).text(), + ]); }); - $('.column.other').each(function () { - right.push([$('input.raw-value', this).val(), $('.display', this).text()]); + $(".column.other").each(function () { + right.push([ + $("input.raw-value", this).val(), + $(".display", this).text(), + ]); }); left.push($master.val()); @@ -74,15 +90,15 @@ $('span[id="master_pk"]').text($master.val()); $('span[id="other_pk"]').text($other.val()); - $($('.column.origin').get().reverse()).each(function () { + $($(".column.origin").get().reverse()).each(function () { var entry = right.pop(); - $('input.raw-value', this).val(entry[0]); - $('.display', this).text(entry[1]); + $("input.raw-value", this).val(entry[0]); + $(".display", this).text(entry[1]); }); - $($('.column.other').get().reverse()).each(function () { + $($(".column.other").get().reverse()).each(function () { var entry = left.pop(); - $('input.raw-value', this).val(entry[0]); - $('.display', this).text(entry[1]); + $("input.raw-value", this).val(entry[0]); + $(".display", this).text(entry[1]); }); highlight(); }); diff --git a/src/adminactions/static/adminactions/js/merge.min.js b/src/adminactions/static/adminactions/js/merge.min.js index 98194325..f9a9d067 100644 --- a/src/adminactions/static/adminactions/js/merge.min.js +++ b/src/adminactions/static/adminactions/js/merge.min.js @@ -1 +1,95 @@ -(function($){$(function(){var select=function(from){return function(event){event.preventDefault();var $row=$(this).parent().parent();var $sel=$row.find(from);$(".result input",$row).val($("input.raw-value",$sel).val());highlight()}};var highlight=function(){var RIGHT=[];$(".mergetable tr.merge-row").each(function(){var $result=$(this).find("td.result");var $left=$(this).find("td.origin");var $right=$(this).find("td.other");var field_name=$(this).find("td:first").attr("data-content");$("td",this).removeClass("selected");if($("input.raw-value",$right).val()===$("input.raw-value",$left).val()){$("p.display",$result).text($("p.display",$left).text())}else if($("input.raw-value",$result).val()===$("input.raw-value",$left).val()){$(this).find("td.origin").addClass("selected");$("p.display",$result).text($("p.display",$left).text())}else if($("input.raw-value",$result).val()===$("input.raw-value",$right).val()){$(this).find("td.other").addClass("selected");$("p.display",$result).text($("p.display",$right).text());RIGHT.push(field_name)}$("input[name=field_names]").val(RIGHT)});$(".mergetable tr.preview-row").each(function(){var $result=$(this).find("td.result");var $left=$(this).find("td.origin");var $right=$(this).find("td.other");var field_name=$(this).find("td:first").attr("data-content");$("td",this).removeClass("selected");if($(".original .display",this).text()!==$(".result .display",this).text()){$(this).addClass("changed")}})};$("a.origin").click(select("td.origin"));$("a.other").click(select("td.other"));$("a.swap").click(function(event){event.preventDefault();var left=[];var right=[];var $master=$('input[name="master_pk"]');var $other=$('input[name="other_pk"]');$(".column.origin").each(function(){left.push([$("input.raw-value",this).val(),$(".display",this).text()])});$(".column.other").each(function(){right.push([$("input.raw-value",this).val(),$(".display",this).text()])});left.push($master.val());right.push($other.val());$master.val(right.pop());$other.val(left.pop());$('span[id="master_pk"]').text($master.val());$('span[id="other_pk"]').text($other.val());$($(".column.origin").get().reverse()).each(function(){var entry=right.pop();$("input.raw-value",this).val(entry[0]);$(".display",this).text(entry[1])});$($(".column.other").get().reverse()).each(function(){var entry=left.pop();$("input.raw-value",this).val(entry[0]);$(".display",this).text(entry[1])});highlight()});highlight()})})(django.jQuery); \ No newline at end of file +(function ($) { + $(function () { + var select = function (from) { + return function (event) { + event.preventDefault(); + var $row = $(this).parent().parent(); + var $sel = $row.find(from); + $(".result input", $row).val($("input.raw-value", $sel).val()); + highlight(); + }; + }; + var highlight = function () { + var RIGHT = []; + $(".mergetable tr.merge-row").each(function () { + var $result = $(this).find("td.result"); + var $left = $(this).find("td.origin"); + var $right = $(this).find("td.other"); + var field_name = $(this).find("td:first").attr("data-content"); + $("td", this).removeClass("selected"); + if ( + $("input.raw-value", $right).val() === + $("input.raw-value", $left).val() + ) { + $("p.display", $result).text($("p.display", $left).text()); + } else if ( + $("input.raw-value", $result).val() === + $("input.raw-value", $left).val() + ) { + $(this).find("td.origin").addClass("selected"); + $("p.display", $result).text($("p.display", $left).text()); + } else if ( + $("input.raw-value", $result).val() === + $("input.raw-value", $right).val() + ) { + $(this).find("td.other").addClass("selected"); + $("p.display", $result).text($("p.display", $right).text()); + RIGHT.push(field_name); + } + $("input[name=field_names]").val(RIGHT); + }); + $(".mergetable tr.preview-row").each(function () { + var $result = $(this).find("td.result"); + var $left = $(this).find("td.origin"); + var $right = $(this).find("td.other"); + var field_name = $(this).find("td:first").attr("data-content"); + $("td", this).removeClass("selected"); + if ( + $(".original .display", this).text() !== + $(".result .display", this).text() + ) { + $(this).addClass("changed"); + } + }); + }; + $("a.origin").click(select("td.origin")); + $("a.other").click(select("td.other")); + $("a.swap").click(function (event) { + event.preventDefault(); + var left = []; + var right = []; + var $master = $('input[name="master_pk"]'); + var $other = $('input[name="other_pk"]'); + $(".column.origin").each(function () { + left.push([ + $("input.raw-value", this).val(), + $(".display", this).text(), + ]); + }); + $(".column.other").each(function () { + right.push([ + $("input.raw-value", this).val(), + $(".display", this).text(), + ]); + }); + left.push($master.val()); + right.push($other.val()); + $master.val(right.pop()); + $other.val(left.pop()); + $('span[id="master_pk"]').text($master.val()); + $('span[id="other_pk"]').text($other.val()); + $($(".column.origin").get().reverse()).each(function () { + var entry = right.pop(); + $("input.raw-value", this).val(entry[0]); + $(".display", this).text(entry[1]); + }); + $($(".column.other").get().reverse()).each(function () { + var entry = left.pop(); + $("input.raw-value", this).val(entry[0]); + $(".display", this).text(entry[1]); + }); + highlight(); + }); + highlight(); + }); +})(django.jQuery); diff --git a/src/adminactions/tasks.py b/src/adminactions/tasks.py index 2f578fea..bdf04218 100644 --- a/src/adminactions/tasks.py +++ b/src/adminactions/tasks.py @@ -1,13 +1,17 @@ import logging +from typing import Any from celery import shared_task # noqa from django.apps import apps +from django.db.models.base import Model logger = logging.getLogger(__name__) @shared_task() -def mass_update_task(model, ids, rules, validate, clean, user_pk): +def mass_update_task( + model: Model, ids: list[Any], rules: dict[str, tuple[callable, Any]], validate: bool, clean: bool, user_pk: Any +) -> None: from adminactions.mass_update import mass_update_execute try: diff --git a/src/adminactions/templates/500.html b/src/adminactions/templates/500.html index bd9b6e65..89a80883 100644 --- a/src/adminactions/templates/500.html +++ b/src/adminactions/templates/500.html @@ -1,10 +1,7 @@ - + - + - - - - + + diff --git a/src/adminactions/templates/adminactions/any_model.html b/src/adminactions/templates/adminactions/any_model.html index d3776a98..567d53d5 100644 --- a/src/adminactions/templates/adminactions/any_model.html +++ b/src/adminactions/templates/adminactions/any_model.html @@ -1,5 +1,5 @@ {% extends "admin/change_form.html" %} -{% load i18n admin_modify static %} +{% load admin_modify i18n static %} {% block extrahead %}{{ block.super }} - - -{% endblock %} +{% extends "admin/change_form.html" %} {% load actions admin_modify i18n static %} {% block extrahead %}{{ block.super }} + + + +{% endblock extrahead %} {% block breadcrumbs %}{% if not is_popup %} - -{% endif %}{% endblock %} + +{% endif %}{% endblock breadcrumbs %} -{% block content %} - {% if formset.errors %} -

- {% if formset.errors|length == 1 %}{% trans "Please correct the error below." %}{% else %}{% trans "Please correct the errors below." %}{% endif %} -

- {{ adminform.form.non_field_errors }} - {% endif %} -
- {% csrf_token %} - {{ formset.non_form_errors.as_ul }} -
- - {% for form in formset.forms %} - {% if forloop.first %} - - - {% for field in form.visible_fields %} - - {% endfor %} - - - {% endif %} - - {% for field in form.visible_fields %} - - {% endfor %} - - {% endfor %} -
- {# Include the hidden fields in the form #} - {% if forloop.first %} - {% for hidden in form.hidden_fields %} - {{ hidden }} - {% endfor %} - {% endif %} - {{ field.errors.as_ul }} - {{ field }} -
-
- {{ formset.management_form }} - {% for hidden in actionform.hidden_fields %} - {{ hidden }} +{% block content %} {% if formset.errors %} +

+ {% if formset.errors|length == 1 %}{% translate "Please correct the error below." %}{% else %}{% translate "Please correct the errors below." %}{% endif %} +

+{{ adminform.form.non_field_errors }} {% endif %} + + {% csrf_token %} {{ formset.non_form_errors.as_ul }} +
+ + {% for form in formset.forms %} {% if forloop.first %} + + + {% for field in form.visible_fields %} + + {% endfor %} + + + {% endif %} + + {% for field in form.visible_fields %} + {% endfor %} - - -{% endblock %} + + {% endfor %} +
+ +
+ {% if forloop.first %} {% for hidden in form.hidden_fields %} {{ hidden }} {% endfor %} {% endif %} {{ field.errors.as_ul }} {{ field }} +
+
+ {{ formset.management_form }} {% for hidden in actionform.hidden_fields %} + {{ hidden }} {% endfor %} + + +{% endblock content %} diff --git a/src/adminactions/templates/adminactions/charts.html b/src/adminactions/templates/adminactions/charts.html index 773fbb06..c3c3e30d 100644 --- a/src/adminactions/templates/adminactions/charts.html +++ b/src/adminactions/templates/adminactions/charts.html @@ -1,47 +1,62 @@ -{% extends "admin/change_form.html" %}{% load i18n static admin_modify admin_urls %}{% load url from aa_compat %} -{% block extrahead %} - {{ block.super }} - - - - - - +{% extends "admin/change_form.html" %}{% load admin_modify admin_urls i18n static %}{% load url from aa_compat %} {% block extrahead %} {{ block.super }} + + + + + + - -{% endblock %} +{% endblock extrahead %} {% block breadcrumbs %}{% if not is_popup %} - -{% endif %} -{% endblock %} + +{% endif %} {% endblock breadcrumbs %} {% block content %} -
-
-{% csrf_token %}= - - {{ adminform.form }} -
- - -
-
- {% if graph_type %} -
-
- {% endif %} - -{% endblock %} +
+
+ -{% csrf_token %}= + + {{ adminform.form }} +
+ + +
+
+{% if graph_type %} +
+
+{% endif %} + +{% endblock content %} diff --git a/src/adminactions/templates/adminactions/duplicates.html b/src/adminactions/templates/adminactions/duplicates.html index 3069023b..19ecc9ad 100644 --- a/src/adminactions/templates/adminactions/duplicates.html +++ b/src/adminactions/templates/adminactions/duplicates.html @@ -1,42 +1,58 @@ -{% extends "admin/change_form.html" %}{% load i18n admin_modify actions static %} +{% extends "admin/change_form.html" %}{% load actions admin_modify i18n static %} {% block extrahead %}{{ block.super }}{{ form.media }}{% endblock %} {% block breadcrumbs %}{% if not is_popup %} - -{% endif %}{% endblock %} + +{% endif %} {% endblock breadcrumbs %} + {% block coltype %}{% endblock %} {% block content %} -
-
- {% if form %} -
- {% csrf_token %} - - {{ form }} -
- -
- {% endif %} -
-
- {% if checked and results %} - - {% for k in checked%}{% endfor %} - - - {% for result in results %} - {% for k,v in result.items %} - {% endfor %} - {% endfor %} -
{{ k }}duplicates
{{ v }}
- {% endif %} -
+
+
+ {% if form %} +
+ {% csrf_token %} + + {{ form }} +
+ +
+ {% endif %} +
+
+ {% if checked and results %} + + + {% for k in checked %} + + {% endfor %} + + + {% for result in results %} + + {% for k,v in result.items %} + + {% endfor %} + + {% endfor %} +
{{ k }}duplicates
{{ v }}
+ {% endif %}
- {# #} -{% endblock %} +
+{# +#} {% endblock content %} diff --git a/src/adminactions/templates/adminactions/export_csv.html b/src/adminactions/templates/adminactions/export_csv.html index 739ec7a7..d3894f54 100644 --- a/src/adminactions/templates/adminactions/export_csv.html +++ b/src/adminactions/templates/adminactions/export_csv.html @@ -1,338 +1,426 @@ -{% extends "admin/change_form.html" %} -{% load i18n admin_modify admin_urls %}{% load url from aa_compat %} -{% block extrahead %}{{ block.super }} - - {% url 'adminactions.format_date' as url_format_date %} - {% if url_format_date %} - - {% endif %} -{% endblock %} +{% extends "admin/change_form.html" %} {% load admin_modify admin_urls i18n %}{% load url from aa_compat %} {% block extrahead %}{{ block.super }} + +{% url 'adminactions.format_date' as url_format_date %} {% if url_format_date %} + +{% endif %} {% endblock extrahead %} {% block breadcrumbs %}{% if not is_popup %} - -{% endif %}{% endblock %} - -{% block content %} - {% if adminform.form.subject.errors %} -
    - {% for error in adminform.form.subject.errors %} -
  1. {{ error|escape }}
  2. - {% endfor %} -
- {% endif %} -
-
- {% csrf_token %} - - {{ adminform.form }} -
-{# #} - -
-
- {% url 'adminactions.format_date' as url_format_date %} - {% if url_format_date %} -
- - - + +{% endif %}{% endblock breadcrumbs %} + +{% block content %} {% if adminform.form.subject.errors %} +
    + {% for error in adminform.form.subject.errors %} +
  1. {{ error|escape }}
  2. + {% endfor %} +
+{% endif %} +
+
+ {% csrf_token %} +
The following characters are recognized in the - format parameter string
+ {{ adminform.form }} +
+ + +
+{% url 'adminactions.format_date' as url_format_date %} {% if url_format_date %} +
+ + - - - - - - + + + + + - - + + - + - + - - - + + + - + - - - + + + - + - - - + + + - + - - - + + + - - - + + + - + - - + + - + - - - + + + - + - - - + + + - - + + - + - + - - - + + + - - + + - + - + - - - + + + - + - - - + + + - + - - - + + + - + - - - + + + - + - - - + + + - - + + - + - + - - - + + + - - - + + + - + - - - + + + - + - - - + + + - - + + - + - + - - - + + + - + - - - + + + - + - - - + + + - + - - - + + + - + - - - + + + - + - - - + + + - + - - - + + + - + - - - + + + - + - - - + + + - - + + - + - - - - - + + + + + - + - - - + + + - + - - - + + + - + - - - + + + - - + + - + - + - + - - + + - + - - - - - + + - -
+ The following characters are recognized in theformat + parameter string +
{% trans "character" %}{% trans "Description" %}{% trans "Example returned values" %}
{% translate "character" %}{% translate "Description" %}{% translate "Example returned values" %}
{% trans "Day" %}
{% translate "Day" %} --- ---
d{% trans "Day of the month, 2 digits with leading zeros" %}01 {% trans "to" %} 31
+ {% translate "Day of the month, 2 digits with leading zeros" %} + 01 {% translate "to" %} 31
D{% trans "A textual representation of a day, three letters" %}{% trans "Mon" %}{% trans "through" %}{% trans "Sun" %}
+ {% translate "A textual representation of a day, three letters" %} + + {% translate "Mon" %}{% translate "through" %}{% translate "Sun" %} +
j{% trans "Day of the month without leading zeros" %}1 {% trans "to" %}31
+ {% translate "Day of the month without leading zeros" %} + 1 {% translate "to" %}31
l (lowercase 'L'){% trans "A full textual representation of the day of the week" %}{% trans "Sunday" %}{% trans "through" %}{% trans "Saturday" %}
+ {% translate "A full textual representation of the day of the week" %} + + {% translate "Sunday" %}{% translate "through" %}{% translate "Saturday" %} +
1{% trans "for Monday through" %}7{% trans "for Sunday"%}
+ 1{% translate "for Monday through" %}7{% translate "for Sunday" %} +
S{% trans "English ordinal suffix for the day of the month, 2 characters" %} - st, nd, rd or - th.{% trans "Works well with" %} j + {% translate "English ordinal suffix for the day of the month, 2 characters" %}
+ st, nd, rd or th.{% translate "Works well with" %} j +
w{% trans "Numeric representation of the day of the week" %}0{% trans "(for Sunday) through" %}6{% trans "(for Saturday)" %}
+ {% translate "Numeric representation of the day of the week" %} + + 0{% translate "(for Sunday) through" %}6{% translate "(for Saturday)" %} +
z{% trans "The day of the year (starting from 0)" %}0{% trans "through" %}365
+ {% translate "The day of the year (starting from 0)" %} + 0{% translate "through" %}365
{% trans "Week" %}
{% translate "Week" %} --- ---
W{% trans "ISO-8601 week number of year, weeks starting on Monday (added in PHP 4.1.0)"%}{% trans "Example:" %} 42 {% trans "(the 42nd week in the year)" %}
+ {% translate "ISO-8601 week number of year, weeks starting on Monday (added in PHP 4.1.0)" %} + + {% translate "Example:" %} 42 {% translate "(the 42nd week in the year)" %} +
{% trans "Month" %}
+ {% translate "Month" %} + --- ---
F{% trans "A full textual representation of a month, such as January or March" %}{% trans "January" %} {% trans "through" %}{% trans "December" %}
+ {% translate "A full textual representation of a month, such as January or March" %} + + {% translate "January" %} {% translate "through" %}{% translate "December" %} +
m{% trans "Numeric representation of a month, with leading zeros" %}01{% trans " through" %} 12
+ {% translate "Numeric representation of a month, with leading zeros" %} + 01{% translate " through" %} 12
M{% trans "A short textual representation of a month, three letters" %}{% trans "Jan" %}{% trans " through" %}{% trans "Dec" %}
+ {% translate "A short textual representation of a month, three letters" %} + + {% translate "Jan" %}{% translate " through" %}{% translate "Dec" %} +
n{% trans "Numeric representation of a month, without leading zeros" %}1{% trans " through" %}12
+ {% translate "Numeric representation of a month, without leading zeros" %} + 1{% translate " through" %}12
t{% trans "Number of days in the given month" %}28{% trans " through" %} 31
+ {% translate "Number of days in the given month" %} + 28{% translate " through" %} 31
{% trans "Year" %}
{% translate "Year" %} --- ---
L{% trans "Whether it's a leap year"%}1{% trans " if it is a leap year, "%}0 {% trans "otherwise."%}
{% translate "Whether it's a leap year" %} + 1{% translate " if it is a leap year, " %}0 {% translate "otherwise." %} +
{% trans "Examples:" %}{% trans "1999" %}{% trans " or" %} {% trans "2003" %}
+ {% translate "Examples:" %}{% translate "1999" %}{% translate "or" %} + {% translate "2003" %} +
Y{% trans "A full numeric representation of a year, 4 digits"%}{% trans "Examples: "%}{% trans "1999"%} {% trans "or" %} 2003
+ {% translate "A full numeric representation of a year, 4 digits" %} + + {% translate "Examples: " %}{% translate "1999" %} {% translate "or" %} + 2003 +
y{% trans "A two digit representation of a year" %}{% trans "Examples: 99 or 03
+ {% translate "A two digit representation of a year" %} + {% translate "Examples: 99 or 03" %}
{% trans "Time" %}
{% translate "Time" %} --- ---
a{% trans "Lowercase Ante meridiem and Post meridiem" %}am {% trans "or " %}pm
+ {% translate "Lowercase Ante meridiem and Post meridiem" %} + am {% translate "or " %}pm
A{% trans "Uppercase Ante meridiem and Post meridiem" %}AM{% trans " or " %}PM
+ {% translate "Uppercase Ante meridiem and Post meridiem" %} + AM{% translate " or " %}PM
B{% trans "Swatch Internet time" %}000{% trans " through " %}999
{% translate "Swatch Internet time" %}000{% translate " through " %}999
g{% trans "12-hour format of an hour without leading zeros" %}1{% trans " through " %}12
+ {% translate "12-hour format of an hour without leading zeros" %} + 1{% translate " through " %}12
G{% trans "24-hour format of an hour without leading zeros" %}0{% trans " through " %}23
+ {% translate "24-hour format of an hour without leading zeros" %} + 0{% translate " through " %}23
h{% trans "12-hour format of an hour with leading zeros" %}01{% trans " through " %}12
+ {% translate "12-hour format of an hour with leading zeros" %} + 01{% translate " through " %}12
H{% trans "24-hour format of an hour with leading zeros" %}00{% trans " through " %}23
+ {% translate "24-hour format of an hour with leading zeros" %} + 00{% translate " through " %}23
i{% trans "Minutes with leading zeros" %}00{% trans " to " %}59
{% translate "Minutes with leading zeros" %}00{% translate " to " %}59
s{% trans "Seconds, with leading zeros" %}00{% trans " through" %} 59
{% translate "Seconds, with leading zeros" %}00{% translate " through" %} 59
{% trans "Timezone" %}
+ {% translate "Timezone" %} + --- ---
I{% trans " (capital i)" %}{% trans "Whether or not the date is in daylight saving time" %}1{% trans " if Daylight Saving Time, 0 otherwise." %}
I{% translate " (capital i)" %} + {% translate "Whether or not the date is in daylight saving time" %} + + 1{% translate " if Daylight Saving Time, 0 otherwise." %} +
O{% trans "Difference to Greenwich time (GMT) in hours" %}{% trans "Example: " %}+0200
+ {% translate "Difference to Greenwich time (GMT) in hours" %} + {% translate "Example: " %}+0200
T{% trans "Timezone abbreviation" %}{% trans "Examples: " %}EST, MDT ...
{% translate "Timezone abbreviation" %} + {% translate "Examples: " %}EST, MDT ... +
Z{% trans "Timezone offset in seconds. The offset for timezones west of UTC is always negative, and for those east of UTC is always positive." %}-43200{% trans "through " %}50400
+ {% translate "Timezone offset in seconds. The offset for timezones west of UTC is always negative, and for those east of UTC is always positive." %} + + -43200{% translate "through " %}50400 +
{% trans "Full Date/Time" %}
+ {% translate "Full Date/Time" %} + --- ---
r» RFC 2822{% trans "formatted date" %} + » RFC 2822{% translate "formatted date" %} + {% trans "Example: " %}{% trans "Thu, 21 Dec 2000 16:01:07 +0200" %}
+ {% translate "Example: " %}{% translate "Thu, 21 Dec 2000 16:01:07 +0200" %} +
U{% trans "Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT)" %}{% trans "See also" %} - time() + + {% translate "Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT)" %}
+ {% translate "See also" %} + + time() +
- -
- {% endif %} -{% endblock %} + +
+{% endif %} {% endblock content %} diff --git a/src/adminactions/templates/adminactions/export_fixture.html b/src/adminactions/templates/adminactions/export_fixture.html index b8e98328..3324b1ae 100644 --- a/src/adminactions/templates/adminactions/export_fixture.html +++ b/src/adminactions/templates/adminactions/export_fixture.html @@ -1,32 +1,26 @@ -{% extends "admin/change_form.html" %} -{% load i18n admin_modify admin_urls %}{% load url from aa_compat %} +{% extends "admin/change_form.html" %} {% load admin_modify admin_urls i18n %}{% load url from aa_compat %} {% block breadcrumbs %}{% if not is_popup %} + +{% endif %}{% endblock breadcrumbs %} -{% block breadcrumbs %}{% if not is_popup %} - -{% endif %}{% endblock %} +{% block content %} {% if form.subject.errors %} +
    + {% for error in form.subject.errors %} +
  1. {{ error|escape }}
  2. + {% endfor %} +
+{% endif %} {{ data }} +
+
+ {% csrf_token %} + + {{ adminform.form }} +
+ +
+
-{% block content %} - {% if form.subject.errors %} -
    - {% for error in form.subject.errors %} -
  1. {{ error|escape }}
  2. - {% endfor %} -
- {% endif %} - {{ data }} -
-
- {% csrf_token %} - - {{ adminform.form }} -
- -
-
- -{% endblock %} +{% endblock content %} diff --git a/src/adminactions/templates/adminactions/export_xls.html b/src/adminactions/templates/adminactions/export_xls.html index 13c3afa9..7f918ff8 100644 --- a/src/adminactions/templates/adminactions/export_xls.html +++ b/src/adminactions/templates/adminactions/export_xls.html @@ -1,44 +1,41 @@ -{% extends "admin/change_form.html" %} -{% load i18n admin_modify admin_urls %}{% load url from aa_compat %} -{% block extrahead %}{{ block.super }} - -{% endblock %} + #legend { + float: left; + width: 60%; + } + +{% endblock extrahead %} {% block breadcrumbs %}{% if not is_popup %} - -{% endif %}{% endblock %} + +{% endif %}{% endblock breadcrumbs %} -{% block content %} - {% if adminform.form.subject.errors %} -
    - {% for error in adminform.form.subject.errors %} -
  1. {{ error|escape }}
  2. - {% endfor %} -
- {% endif %} -
-
- {% csrf_token %} - - {{ adminform.form }} -
- -
-
-{% endblock %} +{% block content %} {% if adminform.form.subject.errors %} +
    + {% for error in adminform.form.subject.errors %} +
  1. {{ error|escape }}
  2. + {% endfor %} +
+{% endif %} +
+
+ {% csrf_token %} + + {{ adminform.form }} +
+ +
+
+{% endblock content %} diff --git a/src/adminactions/templates/adminactions/helpers/import_fixture.html b/src/adminactions/templates/adminactions/helpers/import_fixture.html index 59e2e3d6..267d9d57 100644 --- a/src/adminactions/templates/adminactions/helpers/import_fixture.html +++ b/src/adminactions/templates/adminactions/helpers/import_fixture.html @@ -1,22 +1,20 @@ -{% extends "admin_extra_urls/action_page.html" %}{% load i18n static admin_list admin_urls %} -{% block breadcrumbs-items %} - {% trans 'Home' %} - › {{ opts.app_config.verbose_name }} - › {{ opts.verbose_name_plural|capfirst }} - {% if original %} +{% extends "admin_extra_urls/action_page.html" %}{% load admin_list admin_urls i18n static %} {% block breadcrumbs-items %} +{% translate 'Home' %} +› {{ opts.app_config.verbose_name }} +› {{ opts.verbose_name_plural|capfirst }} +{% if original %} › {{ original }} - {% endif %} - {% block breadcrumbs-active %}› {{ action|default_if_none:title }}{% endblock breadcrumbs-active %} +{% endif %} +{% block breadcrumbs-active %}› {{ action|default_if_none:title }} {% endblock %} {% endblock breadcrumbs-items %} {% block action-content %} -
- {% csrf_token %} - + + {% csrf_token %} +
{{ form }} -
- -
+ + + - -{% endblock %} +{% endblock action-content %} diff --git a/src/adminactions/templates/adminactions/mass_update.html b/src/adminactions/templates/adminactions/mass_update.html index a800ccec..7edbbf3f 100644 --- a/src/adminactions/templates/adminactions/mass_update.html +++ b/src/adminactions/templates/adminactions/mass_update.html @@ -1,78 +1,81 @@ -{% extends "admin/change_form.html" %} -{% load i18n admin_modify actions massupdate static %} -{#{% block extrahead %}{{ block.super }}#} -{# {{ media }}#} -{#{% endblock %}#} +{% extends "admin/change_form.html" %} {% load actions admin_modify i18n massupdate static %} {% block breadcrumbs %}{% if not is_popup %} + +{% endif %}{% endblock breadcrumbs %} -{% block breadcrumbs %}{% if not is_popup %} - -{% endif %}{% endblock %} - -{% block content %} - {% if form.subject.errors %} -
    - {% for error in form.subject.errors %} -
  1. {{ error|escape }}
  2. - {% endfor %} -
- {% endif %} - {{ form.non_field_errors }} -
-
- {% csrf_token %} - - {% for field in adminform.form.configured_fields %} - - - - - {% endfor %} - - - - - - - - - {% if grouped %} - - {% endif %} - - {% for field in adminform.form.model_fields %} - - - - - - {% if grouped %} - - {% endif %} - - - {% endfor %} -
{{ field.label_tag }} - {{ field.errors }} - {{ field }} {{ field.help_text }} -
-{#
#} -
field nameupdatefunctionnew valueexisting values - (sample) -
{% if field.field.required %} - {% endif %} {{ field.label_tag }}{% if field.field.required %}{% endif %} {% checkbox_enabler field %} - {% field_function adminform.model_admin.model field %} {{ field.errors }} - {{ field }}  - {% link_fields_values grouped field.name %} -
- {% for hidden in form.hidden_fields %} - {{ hidden }} - {% endfor %} - -
-
-{% endblock %} +{% block content %} {% if form.subject.errors %} +
    + {% for error in form.subject.errors %} +
  1. {{ error|escape }}
  2. + {% endfor %} +
+{% endif %} {{ form.non_field_errors }} +
+
+ {% csrf_token %} + + {% for field in adminform.form.configured_fields %} + + + + + {% endfor %} + + + + + + + + + {% if grouped %} + + {% endif %} + + {% for field in adminform.form.model_fields %} + + + + + + {% if grouped %} + + {% endif %} + + {% endfor %} +
{{ field.label_tag }} + {{ field.errors }} {{ field }} {{ field.help_text }} +
field nameupdatefunctionnew value + existing values + (sample) +
+ {% if field.field.required %} + {% endif %} {{ field.label_tag }}{% if field.field.required %}{% endif %} + {% checkbox_enabler field %} + {% field_function adminform.model_admin.model field %}  + + {{ field.errors }} {{ field }}  + + {% link_fields_values grouped field.name %} +
+ {% for hidden in form.hidden_fields %} {{ hidden }} {% endfor %} + +
+
+{% endblock content %} diff --git a/src/adminactions/templates/adminactions/merge.html b/src/adminactions/templates/adminactions/merge.html index 42adbdf5..ec637215 100644 --- a/src/adminactions/templates/adminactions/merge.html +++ b/src/adminactions/templates/adminactions/merge.html @@ -1,13 +1,14 @@ {% extends "admin/change_form.html" %} -{% load i18n actions static merge %} +{% load actions i18n merge static %} {% block breadcrumbs %}{% if not is_popup %} -{% endif %}{% endblock %} +{% endif %}{% endblock breadcrumbs %} + {% block content %} {% if not transaction_supported %}
Warning: your database does not support transactios. Merge cannot be validated and/or undone
@@ -31,14 +32,14 @@ - - + - - + + - {% for field in fields %} @@ -47,13 +48,13 @@ @@ -66,7 +67,7 @@ {% endfor %}
{% trans "Field" %}{% trans "Master" %} #{{ master.pk }} ({% trans "This will be preserved" %}) + {% translate "Field" %}{% translate "Master" %} #{{ master.pk }} ({% translate "This will be preserved" %}) {% trans "swap" %}{% trans "Result" %}{% translate "swap" %}{% translate "Result" %} {% trans "Other" %} #{{ other.pk }} ({% trans "This will be removed" %}) - {# {{ adminform.form.other_pk.value }}#} + {% translate "Other" %} #{{ other.pk }} ({% translate "This will be removed" %}) + {# {{ adminform.form.other_pk.value }} #}
{{ formset.0|widget:field.name }} -

{{ master|field_display:field}}

+

{{ master|field_display:field }}

>> {{ adminform.form|widget:field.name }} -

+

{{ adminform.form|errors:field.name }}
- + {% endif %} -{% endblock %} +{% endblock content %} diff --git a/src/adminactions/templates/adminactions/merge_preview.html b/src/adminactions/templates/adminactions/merge_preview.html index 435cd822..4cdcc97a 100644 --- a/src/adminactions/templates/adminactions/merge_preview.html +++ b/src/adminactions/templates/adminactions/merge_preview.html @@ -1,41 +1,40 @@ -{% extends "admin/change_form.html" %} -{% load i18n actions static merge %} -{% block breadcrumbs %}{% if not is_popup %} - -{% endif %}{% endblock %} -{% block content %} -
{% csrf_token %} - {% for f in adminform.form.hidden_fields %}{{ f }}{% endfor %} - {% for f in adminform.form.action_fields %}{{ f }}{% endfor %} - - - - - - - - - - - {% for field in fields %} - - - - - {% endfor %} -
{% trans "Key" %}{{ master.pk }}
{% trans "Original" %}{% trans "After Merging" %}
{{ master|verbose_name:field.name }} - {{ original|field_display:field.name }} - - {{ adminform.form|widget:field.name }} - {{ master|field_display:field.name }} +{% extends "admin/change_form.html" %} {% load actions i18n merge static %} {% block breadcrumbs %}{% if not is_popup %} + +{% endif %}{% endblock breadcrumbs %} -
- -
-{% endblock %} +{% block content %} +
+ {% csrf_token %} {% for f in adminform.form.hidden_fields %}{{ f }}{% endfor %} + {% for f in adminform.form.action_fields %}{{ f }}{% endfor %} + + + + + + + + + + + {% for field in fields %} + + + + + {% endfor %} + +
{% translate "Key" %}{{ master.pk }}
{% translate "Original" %}{% translate "After Merging" %}
{{ master|verbose_name:field.name }} + {{ original|field_display:field.name }} + + {{ adminform.form|widget:field.name }} + {{ master|field_display:field.name }} +
+ +
+{% endblock content %} diff --git a/src/adminactions/templatetags/aa_compat.py b/src/adminactions/templatetags/aa_compat.py index 2a65e697..129d6d98 100644 --- a/src/adminactions/templatetags/aa_compat.py +++ b/src/adminactions/templatetags/aa_compat.py @@ -1,10 +1,11 @@ from django.template import Library +from django.template.base import Parser, Token register = Library() @register.tag -def url(parser, token): +def url(parser: Parser, token: Token) -> str: from django.template.defaulttags import url as _url return _url(parser, token) diff --git a/src/adminactions/templatetags/actions.py b/src/adminactions/templatetags/actions.py index 25f29bb0..0a0312aa 100644 --- a/src/adminactions/templatetags/actions.py +++ b/src/adminactions/templatetags/actions.py @@ -1,12 +1,21 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING, Any + from django.template import Library from adminactions.utils import get_field_value, get_verbose_name +if TYPE_CHECKING: + from django.db.models.base import Model + from django.db.models.fields import Field + from django.db.models.query import QuerySet + register = Library() @register.filter() -def field_display(obj, field): +def field_display(obj: Model, field: Field) -> Any: """ returns the representation (value or ``get_FIELD_display()``) of a field @@ -16,7 +25,7 @@ def field_display(obj, field): @register.filter -def verbose_name(model_or_queryset, field): +def verbose_name(model_or_queryset: Model | QuerySet, field: Field) -> str: """ templatetag wrapper to `adminactions.utils.get_verbose_name`_ """ diff --git a/src/adminactions/templatetags/massupdate.py b/src/adminactions/templatetags/massupdate.py index a38223e3..6172aaa6 100644 --- a/src/adminactions/templatetags/massupdate.py +++ b/src/adminactions/templatetags/massupdate.py @@ -1,5 +1,8 @@ +from django.db.models.base import Model from django.forms import widgets +from django.forms.fields import Field from django.template import Library +from django.template.context import Context from django.utils.safestring import mark_safe from adminactions.utils import get_field_by_name @@ -8,10 +11,13 @@ @register.simple_tag -def fields_values(d, k): +def fields_values(d: dict[str, list[str]], k: str) -> str: """ - >>> data = {'name1': ['value1.1', 'value1.2'], 'name2': ['value2.1', 'value2.2'], } - >>> print(fields_values(data, 'name1')) + >>> data = { + ... "name1": ["value1.1", "value1.2"], + ... "name2": ["value2.1", "value2.2"], + ... } + >>> print(fields_values(data, "name1")) value1.1,value1.2 """ values = d.get(k, []) @@ -19,7 +25,7 @@ def fields_values(d, k): @register.simple_tag -def link_fields_values(d, field_name): +def link_fields_values(d: dict[str, list[tuple[int, str]]], field_name: str) -> str: """ >>> data = {'name1': [(1, 'value1.1'), (11, 'value1.2')], ... 'name2': [(2, 'value2.1'), (22, 'value2.2')], } @@ -39,7 +45,7 @@ def link_fields_values(d, field_name): value, label = el, el if label == "": # ignore empty - continue + continue # pragma: no cover ret.append( ' str: form = context["adminform"].form name = "chk_id_%s" % field.name checked = "" @@ -62,7 +68,7 @@ def checkbox_enabler(context, field): @register.simple_tag(takes_context=True) -def field_function(context, model, form_field): +def field_function(context: Context, model: Model, form_field: Field) -> widgets.Select: from adminactions.mass_update import OPERATIONS model_field, model, direct, m2m = get_field_by_name(model, form_field.name) diff --git a/src/adminactions/templatetags/merge.py b/src/adminactions/templatetags/merge.py index 6d2a9f36..f41913bd 100644 --- a/src/adminactions/templatetags/merge.py +++ b/src/adminactions/templatetags/merge.py @@ -1,10 +1,15 @@ +from typing import Any + +from django.forms.forms import Form +from django.forms.utils import ErrorList +from django.forms.widgets import Widget from django.template import Library register = Library() @register.filter(name="widget") -def form_widget(form, fieldname): +def form_widget(form: Form, fieldname: str) -> Widget: """ >>> from django.forms import ModelForm, modelform_factory >>> from django.contrib.auth.models import User @@ -16,19 +21,19 @@ def form_widget(form, fieldname): @register.filter(name="errors") -def form_widget_error(form, fieldname): +def form_widget_error(form: Form, fieldname: str) -> list[str]: """ >>> from django.forms import ModelForm, modelform_factory >>> from django.contrib.auth.models import User >>> f = modelform_factory(User, fields=["username"])({}, instance=User()) - >>> form_widget_error(f, "username") == ['This field is required.'] + >>> form_widget_error(f, "username") == ["This field is required."] True """ return form[fieldname].errors @register.filter(name="value") -def form_widget_value(form, fieldname): +def form_widget_value(form: Form, fieldname: str) -> Any: """ >>> from django.forms import ModelForm, modelform_factory >>> from django.contrib.auth.models import User diff --git a/src/adminactions/utils.py b/src/adminactions/utils.py index 1b624a01..d0a6e72e 100644 --- a/src/adminactions/utils.py +++ b/src/adminactions/utils.py @@ -1,21 +1,27 @@ +from __future__ import annotations + from functools import partial +from typing import TYPE_CHECKING, Any, Iterable, Union from django.conf import settings from django.db import models from django.db.models.query import QuerySet from django.utils.encoding import smart_str +if TYPE_CHECKING: + from django.contrib.admin.options import ModelAdmin + from django.db.models.base import Model + from django.db.models.fields import Field + -def get_ignored_fields(model, setting_var_name): +def get_ignored_fields(model: Model, setting_var_name: str) -> Iterable[str]: """ returns list of ignored fields which must not be modified """ - return ( - getattr(settings, setting_var_name, {}).get(model._meta.app_label, {}).get(model._meta.model_name, ()) - ) + return getattr(settings, setting_var_name, {}).get(model._meta.app_label, {}).get(model._meta.model_name, ()) -def clone_instance(instance, fieldnames=None): +def clone_instance(instance: Model, fieldnames: list[str] = None) -> Model: """ returns a copy of the passed instance. @@ -35,19 +41,20 @@ def clone_instance(instance, fieldnames=None): # return instance.__class__.objects.get(pk=instance.pk) -def get_attr(obj, attr, default=None): +def get_attr(obj: Any, attr: str, default: Any | None = None) -> Any: """Recursive get object's attribute. May use dot notation. - >>> class C: pass + >>> class C: + ... pass >>> a = C() >>> a.b = C() >>> a.b.c = 4 - >>> get_attr(a, 'b.c') + >>> get_attr(a, "b.c") 4 - >>> get_attr(a, 'b.c.y', None) + >>> get_attr(a, "b.c.y", None) - >>> get_attr(a, 'b.c.y', 1) + >>> get_attr(a, "b.c.y", 1) 1 """ if "." not in attr: @@ -61,7 +68,7 @@ def get_attr(obj, attr, default=None): return ret -def getattr_or_item(obj, name): +def getattr_or_item(obj: Any, name: str) -> Any: """ works indifferently on dict or objects, retrieving the 'name' attribute or item @@ -70,11 +77,11 @@ def getattr_or_item(obj, name): :param name: attribute or item name :return: >>> from django.contrib.auth.models import Permission - >>> p = Permission(name='perm') - >>> d ={'one': 1, 'two': 2} - >>> getattr_or_item(d, 'one') + >>> p = Permission(name="perm") + >>> d = {"one": 1, "two": 2} + >>> getattr_or_item(d, "one") 1 - >>> print(getattr_or_item(p, 'name')) + >>> print(getattr_or_item(p, "name")) perm """ # this change type from type to dict in python3.9 @@ -92,7 +99,9 @@ def getattr_or_item(obj, name): return ret -def get_field_value(obj, field, usedisplay=True, raw_callable=False, modeladmin=None): +def get_field_value( + obj: Model, field: Field, usedisplay: bool = True, raw_callable: bool = False, modeladmin: ModelAdmin = None +) -> Any: """ returns the field value or field representation if get_FIELD_display exists @@ -102,8 +111,8 @@ def get_field_value(obj, field, usedisplay=True, raw_callable=False, modeladmin= :return: field value >>> from django.contrib.auth.models import Permission - >>> p = Permission(name='perm') - >>> get_field_value(p, 'name') == 'perm' + >>> p = Permission(name="perm") + >>> get_field_value(p, "name") == "perm" True >>> get_field_value(p, None) Traceback (most recent call last): @@ -138,7 +147,7 @@ def get_field_value(obj, field, usedisplay=True, raw_callable=False, modeladmin= return value -def get_field_by_path(model, field_path): +def get_field_by_path(model: Model, field_path: str) -> Field: """ get a Model class or instance and a path to a attribute, returns the field object @@ -149,11 +158,11 @@ def get_field_by_path(model, field_path): >>> from django.contrib.auth.models import Permission - >>> p = Permission(name='perm') - >>> get_field_by_path(Permission, 'content_type').name + >>> p = Permission(name="perm") + >>> get_field_by_path(Permission, "content_type").name 'content_type' - >>> p = Permission(name='perm') - >>> get_field_by_path(p, 'content_type.app_label').name + >>> p = Permission(name="perm") + >>> get_field_by_path(p, "content_type.app_label").name 'app_label' """ parts = field_path.split(".") @@ -170,7 +179,7 @@ def get_field_by_path(model, field_path): return None -def get_verbose_name(model_or_queryset, field): +def get_verbose_name(model_or_queryset: Union[Model, QuerySet], field: Field) -> str: """ returns the value of the ``verbose_name`` of a field @@ -190,17 +199,17 @@ def get_verbose_name(model_or_queryset, field): >>> from django.contrib.auth.models import User, Permission >>> user = User() >>> p = Permission() - >>> get_verbose_name(user, 'username') == 'username' + >>> get_verbose_name(user, "username") == "username" True - >>> get_verbose_name(User, 'username') == 'username' + >>> get_verbose_name(User, "username") == "username" True - >>> get_verbose_name(User.objects.all(), 'username') == 'username' + >>> get_verbose_name(User.objects.all(), "username") == "username" True - >>> get_verbose_name(User.objects, 'username') == 'username' + >>> get_verbose_name(User.objects, "username") == "username" True - >>> get_verbose_name(User.objects, user._meta.fields[0]) == 'ID' + >>> get_verbose_name(User.objects, user._meta.fields[0]) == "ID" True - >>> get_verbose_name(p, 'content_type.model') == 'python model class name' + >>> get_verbose_name(p, "content_type.model") == "python model class name" True """ @@ -228,7 +237,7 @@ def get_verbose_name(model_or_queryset, field): return field.verbose_name -def flatten(iterable): +def flatten(iterable: Iterable) -> list[Any]: """ flatten(sequence) -> list @@ -242,10 +251,10 @@ def flatten(iterable): Examples: >>> from adminactions.utils import flatten - >>> [1, 2, [3,4], (5,6)] + >>> [1, 2, [3, 4], (5, 6)] [1, 2, [3, 4], (5, 6)] - >>> flatten([[[1,2,3], (42,None)], [4,5], [6], 7, (8,9,10)]) + >>> flatten([[[1, 2, 3], (42, None)], [4, 5], [6], 7, (8, 9, 10)]) [1, 2, 3, 42, None, 4, 5, 6, 7, 8, 9, 10]""" result = list() @@ -257,21 +266,21 @@ def flatten(iterable): return list(result) -def get_field_by_name(model, name): +def get_field_by_name(model: Model, name: str) -> (Field, Model, bool, bool): field = model._meta.get_field(name) direct = not field.auto_created or field.concrete return field, field.model, direct, field.many_to_many -def model_has_field(model, field_name): +def model_has_field(model: Model, field_name: str) -> bool: return field_name in [f.name for f in model._meta.get_fields()] -def get_all_related_objects(model): +def get_all_related_objects(model: Model) -> list[str]: return [f for f in model._meta.get_fields() if (f.one_to_many or f.one_to_one) and f.auto_created] -def get_all_field_names(model): +def get_all_field_names(model: Model) -> list[str]: from itertools import chain return list( @@ -285,11 +294,11 @@ def get_all_field_names(model): ) -def curry(func, *a, **kw): +def curry(func: callable, *a: Any, **kw: Any) -> callable: return partial(func, *a, **kw) -def get_common_context(modeladmin, **kwargs): +def get_common_context(modeladmin: ModelAdmin, **kwargs: Any) -> dict[str, Any]: ctx = { "change": True, "is_popup": False, diff --git a/src/adminactions/views.py b/src/adminactions/views.py index 088693c5..44b6d4f8 100644 --- a/src/adminactions/views.py +++ b/src/adminactions/views.py @@ -1,9 +1,10 @@ from datetime import datetime from django.http import HttpResponse +from django.http.request import HttpRequest from django.utils import dateformat -def format_date(request): +def format_date(request: HttpRequest) -> HttpResponse: d = datetime.now() return HttpResponse(dateformat.format(d, request.GET.get("fmt", ""))) diff --git a/src/requirements/develop.pip b/src/requirements/develop.pip deleted file mode 100644 index 5d10e631..00000000 --- a/src/requirements/develop.pip +++ /dev/null @@ -1,7 +0,0 @@ -black -django<4 -pdbpp -virtualenv -wheel -check-manifest -docutils diff --git a/src/requirements/install.pip b/src/requirements/install.pip deleted file mode 100644 index 8441c092..00000000 --- a/src/requirements/install.pip +++ /dev/null @@ -1,3 +0,0 @@ -pytz -xlrd>=0.9.2 -xlwt diff --git a/src/requirements/rtd.pip b/src/requirements/rtd.pip deleted file mode 100644 index 61645a09..00000000 --- a/src/requirements/rtd.pip +++ /dev/null @@ -1,3 +0,0 @@ -django -sphinx -sphinx_rtd_theme diff --git a/src/requirements/testing.pip b/src/requirements/testing.pip deleted file mode 100644 index 58e83dfd..00000000 --- a/src/requirements/testing.pip +++ /dev/null @@ -1,24 +0,0 @@ -check-manifest -celery -django-dynamic-fixture -django-webtest>1.9.6 -django-admin-extra-urls -django-environ -flake8 -flake8-isort -mock>=1.0.1 -modernize -pillow -pytest -pytest-cache -pytest-cov -pytest-django -pytest-echo -redis -readme -selenium>=2.42.0 -setuptools>=15.0 -tox<4 -isort -black - diff --git a/tests/.coveragerc b/tests/.coveragerc deleted file mode 100644 index a71476cb..00000000 --- a/tests/.coveragerc +++ /dev/null @@ -1,30 +0,0 @@ -[run] -branch = True -source = adminactions -#include = -# adminactions/** - -omit = src/adminactions/__init__.py - src/adminactions/compat.py - tests/** - -[report] -# Regexes for lines to exclude from consideration -exclude_lines = - # Have to re-enable the standard pragma - pragma: no cover - # Don't complain about missing debug-only code: - def __repr__ - if self\.debug - # Don't complain if tests don't hit defensive assertion code: - raise AssertionError - raise NotImplementedError - except ImportError - # Don't complain if non-runnable code isn't run: - #if 0: - if __name__ == .__main__.: - -ignore_errors = True - -[html] -directory = ~build/coverage diff --git a/tests/conftest.py b/tests/conftest.py index 79038abb..35f8a047 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,12 +1,21 @@ +from __future__ import annotations + import logging import os import shutil import sys import tempfile from pathlib import Path +from typing import TYPE_CHECKING, Protocol -import django_webtest import pytest +from django_webtest import DjangoTestApp + +if TYPE_CHECKING: + + class AppFactory(Protocol): + def __call__(self, csrf_checks: bool, extra_environ: dict | None = None) -> DjangoTestApp: ... + logger = logging.getLogger("test") @@ -27,7 +36,7 @@ } -def pytest_addoption(parser): +def pytest_addoption(parser) -> None: group = parser.getgroup("selenium", "Selenium Web Browser Automation") group.addoption( "--selenium-enable", @@ -62,7 +71,7 @@ def pytest_addoption(parser): ) -def pytest_configure(config): +def pytest_configure(config) -> None: here = Path(__file__).parent sys.path.insert(0, here) sys.path.insert(0, here.parent / "src") @@ -74,9 +83,8 @@ def pytest_configure(config): config.option.markexpr.find("selenium") < 0 and not config.option.keyword and config.option.keyword.find("selenium") < 0 - ): - if not config.option.selenium_enable: - setattr(config.option, "markexpr", "not selenium") + ) and not config.option.selenium_enable: + config.option.markexpr = "not selenium" os.environ["CELERY_ALWAYS_EAGER"] = "1" os.environ["MEDIA_ROOT"] = "/tmp/media/" settings.MEDIA_ROOT = tempfile.TemporaryDirectory().name @@ -87,7 +95,7 @@ def pytest_configure(config): import logging level = config.option.log_level.upper() - assert level in levelNames.keys() + assert level in levelNames format = "%(levelname)-7s %(name)-30s %(funcName)-20s:%(lineno)3s %(message)s" formatter = logging.Formatter(format) @@ -108,22 +116,18 @@ def pytest_configure(config): @pytest.fixture(autouse=True) -def create_aa_permissions(db): +def create_aa_permissions(db) -> None: from adminactions.perms import create_extra_permissions create_extra_permissions() -@pytest.fixture(scope="function") -def app(request): - wtm = django_webtest.WebTestMixin() - wtm.csrf_checks = False - wtm._patch_settings() - request.addfinalizer(wtm._unpatch_settings) - return django_webtest.DjangoTestApp() +@pytest.fixture +def app(request, django_app_factory: "AppFactory") -> DjangoTestApp: + return django_app_factory(csrf_checks=False) -@pytest.fixture(scope="function") +@pytest.fixture def users(): from django.contrib.auth.models import User from django_dynamic_fixture import G @@ -131,7 +135,7 @@ def users(): return G(User, n=2, is_staff=False, is_active=False) -@pytest.fixture(scope="function") +@pytest.fixture def demomodels(): from demo.models import DemoModel from django_dynamic_fixture import G @@ -139,7 +143,7 @@ def demomodels(): return G(DemoModel, n=20) -@pytest.fixture(scope="function") +@pytest.fixture def admin(): from django.contrib.auth.models import User from django_dynamic_fixture import G @@ -147,10 +151,9 @@ def admin(): return G(User, is_staff=True, is_active=True) -@pytest.fixture(scope="function") +@pytest.fixture def administrator(): from django.contrib.auth.models import User from utils import ADMIN, PWD - superuser = User._default_manager.create_superuser(username=ADMIN, password=PWD, email="sax@noreply.org") - return superuser + return User._default_manager.create_superuser(username=ADMIN, password=PWD, email="sax@noreply.org") diff --git a/tests/demo/apps.py b/tests/demo/apps.py index 43f0e376..f43130b0 100644 --- a/tests/demo/apps.py +++ b/tests/demo/apps.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from django.apps import AppConfig @@ -5,7 +7,7 @@ class Config(AppConfig): name = "demo" default = True - def ready(self): + def ready(self) -> None: try: from .celery import app # noqa except ImportError: diff --git a/tests/demo/backends.py b/tests/demo/backends.py index bcdaed97..c4fad072 100644 --- a/tests/demo/backends.py +++ b/tests/demo/backends.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from django.contrib.auth.backends import ModelBackend from django.contrib.auth.models import User @@ -7,11 +9,12 @@ def authenticate(self, request, username=None, password=None, **kwargs): if username: user, __ = User.objects.update_or_create( username=username, - defaults=dict( - is_staff=True, - is_active=True, - is_superuser=True, - email=f"{username}@demo.org", - ), + defaults={ + "is_staff": True, + "is_active": True, + "is_superuser": True, + "email": f"{username}@demo.org", + }, ) return user + return None diff --git a/tests/demo/celery.py b/tests/demo/celery.py index b6cd270f..04aa2841 100644 --- a/tests/demo/celery.py +++ b/tests/demo/celery.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os try: diff --git a/tests/demo/fixtures/adminactions.json b/tests/demo/fixtures/adminactions.json index 5db84a5b..8889025c 100644 --- a/tests/demo/fixtures/adminactions.json +++ b/tests/demo/fixtures/adminactions.json @@ -1,236 +1,235 @@ [ - { - "pk":1, - "model":"auth.user", - "fields":{ - "username":"sax", - "first_name":"", - "last_name":"", - "is_active":true, - "is_superuser":true, - "is_staff":true, - "last_login":"2011-07-07T17:00:00Z", - "groups":[], - "user_permissions":[], - "password":"sha1$eec82$d1cebb645395e1ea755e57e5eeda6d192128ad6b", - "email":"sax@os4d.org", - "date_joined":"2011-07-01T17:00:00Z" - } - }, - { - "pk":2, - "model":"auth.user", - "fields":{ - "username":"user_00", - "first_name":"FirstName 0", - "last_name":"LastName 0", - "is_active":true, - "is_superuser":false, - "is_staff":true, - "last_login": "2020-01-01T17:00:00Z", - "groups":[], - "user_permissions":[], - "password":"sha1$eec82$d1cebb645395e1ea755e57e5eeda6d192128ad6b", - "email":"user_0@test.org", - "date_joined": "2020-01-01T17:00:00Z" - } - }, - { - "pk":3, - "model":"auth.user", - "fields":{ - "username":"user_01", - "first_name":"FirstName 1", - "last_name":"LastName 1", - "is_active":true, - "is_superuser":false, - "is_staff":false, - "last_login":"2011-07-07T17:00:00Z", - "groups":[], - "user_permissions":[], - "password":"sha1$eec82$d1cebb645395e1ea755e57e5eeda6d192128ad6b", - "email":"user_1@test.org", - "date_joined":"2011-07-01T17:00:00Z" - } - }, - { - "pk":4, - "model":"auth.user", - "fields":{ - "username":"user_02", - "first_name":"FirstName 2", - "last_name":"LastName 2", - "is_active":true, - "is_superuser":false, - "is_staff":false, - "last_login":"2011-07-07T17:00:00Z", - "groups":[], - "user_permissions":[], - "password":"", - "email":"user_2@test.org", - "date_joined":"2011-07-01T17:00:00Z" - } - }, - { - "pk":5, - "model":"auth.user", - "fields":{ - "username":"user_03", - "first_name":"FirstName 3", - "last_name":"LastName 3", - "is_active":true, - "is_superuser":false, - "is_staff":false, - "last_login":"2011-07-07T17:00:00Z", - "groups":[], - "user_permissions":[], - "password":"", - "email":"user_3@test.org", - "date_joined":"2011-07-01T17:00:00Z" - } - }, - { - "pk":6, - "model":"auth.user", - "fields":{ - "username":"user_04", - "first_name":"FirstName 4", - "last_name":"LastName 4", - "is_active":true, - "is_superuser":false, - "is_staff":false, - "last_login":"2011-07-07T17:00:00Z", - "groups":[], - "user_permissions":[], - "password":"", - "email":"user_4@test.org", - "date_joined":"2011-07-01T17:00:00Z" - } - }, - { - "pk":7, - "model":"auth.user", - "fields":{ - "username":"user_05", - "first_name":"FirstName 5", - "last_name":"LastName 5", - "is_active":true, - "is_superuser":false, - "is_staff":false, - "last_login":"2011-07-07T17:00:00Z", - "groups":[], - "user_permissions":[], - "password":"", - "email":"user_5@test.org", - "date_joined":"2011-07-01T17:00:00Z" - } - }, - { - "pk":8, - "model":"auth.user", - "fields":{ - "username":"user_06", - "first_name":"FirstName 6", - "last_name":"LastName 6", - "is_active":true, - "is_superuser":false, - "is_staff":false, - "last_login":"2011-07-07T17:00:00Z", - "groups":[], - "user_permissions":[], - "password":"", - "email":"user_6@test.org", - "date_joined":"2011-07-01T17:00:00Z" - } - }, - { - "pk":9, - "model":"auth.user", - "fields":{ - "username":"user_07", - "first_name":"FirstName 7", - "last_name":"LastName 7", - "is_active":true, - "is_superuser":false, - "is_staff":false, - "last_login":"2011-07-07T17:00:00Z", - "groups":[], - "user_permissions":[], - "password":"", - "email":"user_7@test.org", - "date_joined":"2011-07-01T17:00:00Z" - } - }, - { - "pk":10, - "model":"auth.user", - "fields":{ - "username":"user_08", - "first_name":"FirstName 8", - "last_name":"LastName 8", - "is_active":true, - "is_superuser":false, - "is_staff":false, - "last_login":"2011-07-07T17:00:00Z", - "groups":[], - "user_permissions":[], - "password":"", - "email":"user_8@test.org", - "date_joined":"2011-07-01T17:00:00Z" - } - }, - { - "pk":11, - "model":"auth.user", - "fields":{ - "username":"user_09", - "first_name":"FirstName 9", - "last_name":"LastName 9", - "is_active":true, - "is_superuser":false, - "is_staff":false, - "last_login":"2011-07-07T17:00:00Z", - "groups":[], - "user_permissions":[], - "password":"", - "email":"user_9@test.org", - "date_joined":"2011-07-01T17:00:00Z" - } - }, - { - "pk":12, - "model":"auth.user", - "fields":{ - "username":"user_10", - "first_name":"FirstName 10", - "last_name":"LastName 10", - "is_active":true, - "is_superuser":false, - "is_staff":false, - "last_login":"2011-07-07T17:00:00Z", - "groups":[], - "user_permissions":[], - "password":"", - "email":"user_10@test.org", - "date_joined":"2011-07-01T17:00:00Z" - } - }, - - { - "pk":2, - "model":"auth.group", - "fields":{ - "name":"admin", - "permissions":[] - } - }, - { - "pk":1, - "model":"auth.group", - "fields":{ - "name":"guest", - "permissions":[] - } + { + "pk": 1, + "model": "auth.user", + "fields": { + "username": "sax", + "first_name": "", + "last_name": "", + "is_active": true, + "is_superuser": true, + "is_staff": true, + "last_login": "2011-07-07T17:00:00Z", + "groups": [], + "user_permissions": [], + "password": "sha1$eec82$d1cebb645395e1ea755e57e5eeda6d192128ad6b", + "email": "sax@os4d.org", + "date_joined": "2011-07-01T17:00:00Z" + } + }, + { + "pk": 2, + "model": "auth.user", + "fields": { + "username": "user_00", + "first_name": "FirstName 0", + "last_name": "LastName 0", + "is_active": true, + "is_superuser": false, + "is_staff": true, + "last_login": "2020-01-01T17:00:00Z", + "groups": [], + "user_permissions": [], + "password": "sha1$eec82$d1cebb645395e1ea755e57e5eeda6d192128ad6b", + "email": "user_0@test.org", + "date_joined": "2020-01-01T17:00:00Z" + } + }, + { + "pk": 3, + "model": "auth.user", + "fields": { + "username": "user_01", + "first_name": "FirstName 1", + "last_name": "LastName 1", + "is_active": true, + "is_superuser": false, + "is_staff": false, + "last_login": "2011-07-07T17:00:00Z", + "groups": [], + "user_permissions": [], + "password": "sha1$eec82$d1cebb645395e1ea755e57e5eeda6d192128ad6b", + "email": "user_1@test.org", + "date_joined": "2011-07-01T17:00:00Z" + } + }, + { + "pk": 4, + "model": "auth.user", + "fields": { + "username": "user_02", + "first_name": "FirstName 2", + "last_name": "LastName 2", + "is_active": true, + "is_superuser": false, + "is_staff": false, + "last_login": "2011-07-07T17:00:00Z", + "groups": [], + "user_permissions": [], + "password": "", + "email": "user_2@test.org", + "date_joined": "2011-07-01T17:00:00Z" + } + }, + { + "pk": 5, + "model": "auth.user", + "fields": { + "username": "user_03", + "first_name": "FirstName 3", + "last_name": "LastName 3", + "is_active": true, + "is_superuser": false, + "is_staff": false, + "last_login": "2011-07-07T17:00:00Z", + "groups": [], + "user_permissions": [], + "password": "", + "email": "user_3@test.org", + "date_joined": "2011-07-01T17:00:00Z" + } + }, + { + "pk": 6, + "model": "auth.user", + "fields": { + "username": "user_04", + "first_name": "FirstName 4", + "last_name": "LastName 4", + "is_active": true, + "is_superuser": false, + "is_staff": false, + "last_login": "2011-07-07T17:00:00Z", + "groups": [], + "user_permissions": [], + "password": "", + "email": "user_4@test.org", + "date_joined": "2011-07-01T17:00:00Z" + } + }, + { + "pk": 7, + "model": "auth.user", + "fields": { + "username": "user_05", + "first_name": "FirstName 5", + "last_name": "LastName 5", + "is_active": true, + "is_superuser": false, + "is_staff": false, + "last_login": "2011-07-07T17:00:00Z", + "groups": [], + "user_permissions": [], + "password": "", + "email": "user_5@test.org", + "date_joined": "2011-07-01T17:00:00Z" } + }, + { + "pk": 8, + "model": "auth.user", + "fields": { + "username": "user_06", + "first_name": "FirstName 6", + "last_name": "LastName 6", + "is_active": true, + "is_superuser": false, + "is_staff": false, + "last_login": "2011-07-07T17:00:00Z", + "groups": [], + "user_permissions": [], + "password": "", + "email": "user_6@test.org", + "date_joined": "2011-07-01T17:00:00Z" + } + }, + { + "pk": 9, + "model": "auth.user", + "fields": { + "username": "user_07", + "first_name": "FirstName 7", + "last_name": "LastName 7", + "is_active": true, + "is_superuser": false, + "is_staff": false, + "last_login": "2011-07-07T17:00:00Z", + "groups": [], + "user_permissions": [], + "password": "", + "email": "user_7@test.org", + "date_joined": "2011-07-01T17:00:00Z" + } + }, + { + "pk": 10, + "model": "auth.user", + "fields": { + "username": "user_08", + "first_name": "FirstName 8", + "last_name": "LastName 8", + "is_active": true, + "is_superuser": false, + "is_staff": false, + "last_login": "2011-07-07T17:00:00Z", + "groups": [], + "user_permissions": [], + "password": "", + "email": "user_8@test.org", + "date_joined": "2011-07-01T17:00:00Z" + } + }, + { + "pk": 11, + "model": "auth.user", + "fields": { + "username": "user_09", + "first_name": "FirstName 9", + "last_name": "LastName 9", + "is_active": true, + "is_superuser": false, + "is_staff": false, + "last_login": "2011-07-07T17:00:00Z", + "groups": [], + "user_permissions": [], + "password": "", + "email": "user_9@test.org", + "date_joined": "2011-07-01T17:00:00Z" + } + }, + { + "pk": 12, + "model": "auth.user", + "fields": { + "username": "user_10", + "first_name": "FirstName 10", + "last_name": "LastName 10", + "is_active": true, + "is_superuser": false, + "is_staff": false, + "last_login": "2011-07-07T17:00:00Z", + "groups": [], + "user_permissions": [], + "password": "", + "email": "user_10@test.org", + "date_joined": "2011-07-01T17:00:00Z" + } + }, + { + "pk": 2, + "model": "auth.group", + "fields": { + "name": "admin", + "permissions": [] + } + }, + { + "pk": 1, + "model": "auth.group", + "fields": { + "name": "guest", + "permissions": [] + } + } ] diff --git a/tests/demo/fixtures/demoproject.json b/tests/demo/fixtures/demoproject.json index 0a616eae..747291d9 100644 --- a/tests/demo/fixtures/demoproject.json +++ b/tests/demo/fixtures/demoproject.json @@ -1,80 +1,80 @@ [ - { - "pk": 1, - "model": "demo.demomodel", - "fields": { - "nullable": "aaaa", - "float": 10.1, - "generic_ip": "192.168.10.1", - "url": "https://github.com/saxix/django-adminactions", - "decimal": "10.1", - "time": "09:18:35", - "blank": "", - "datetime": "2012-10-06T02:18:33Z", - "char": "bbb", - "not_editable": null, - "bigint": 1111, - "text": "sddd", - "logic": false, - "date": "2012-10-06", - "integer": 90000, - "unique": "unique 1", - "email": "s.apostolico@gmail.com", - "choices": 2, - "image": "second.png", - "subclassed_image": false - } - }, - { - "pk": 2, - "model": "demo.demomodel", - "fields": { - "nullable": "bbbb", - "float": 10.1, - "generic_ip": "192.168.10.2", - "url": "https://github.com/saxix/django-adminactions", - "decimal": "22.2", - "time": "19:00:35", - "blank": "", - "datetime": "2013-01-01T02:18:33Z", - "char": "ccccc", - "not_editable": null, - "bigint": 333333333, - "text": "lorem ipsum", - "logic": false, - "date": "2013-01-29", - "integer": 888888, - "unique": "unique 2", - "email": "s.apostolico@gmail.com", - "choices": 2, - "image": "first.png", - "subclassed_image": "subclassed_first.png" - } - }, - { - "pk": 3, - "model": "demo.demomodel", - "fields": { - "nullable": "dddd", - "float": 10.1, - "generic_ip": "192.168.10.2", - "url": "https://github.com/saxix/django-adminactions", - "decimal": "22.2", - "time": "19:00:35", - "blank": "", - "datetime": "2013-01-01T02:18:33Z", - "char": "Pizzä ïs Gööd", - "not_editable": null, - "bigint": 333333333, - "text": "lorem ipsum", - "logic": false, - "date": "2013-01-29", - "integer": 888888, - "unique": "unique 3", - "email": "s.apostolico@gmail.com", - "choices": 2, - "image": null, - "subclassed_image": "subclassed_second.png" - } + { + "pk": 1, + "model": "demo.demomodel", + "fields": { + "nullable": "aaaa", + "float": 10.1, + "generic_ip": "192.168.10.1", + "url": "https://github.com/saxix/django-adminactions", + "decimal": "10.1", + "time": "09:18:35", + "blank": "", + "datetime": "2012-10-06T02:18:33Z", + "char": "bbb", + "not_editable": null, + "bigint": 1111, + "text": "sddd", + "logic": false, + "date": "2012-10-06", + "integer": 90000, + "unique": "unique 1", + "email": "s.apostolico@gmail.com", + "choices": 2, + "image": "second.png", + "subclassed_image": false } + }, + { + "pk": 2, + "model": "demo.demomodel", + "fields": { + "nullable": "bbbb", + "float": 10.1, + "generic_ip": "192.168.10.2", + "url": "https://github.com/saxix/django-adminactions", + "decimal": "22.2", + "time": "19:00:35", + "blank": "", + "datetime": "2013-01-01T02:18:33Z", + "char": "ccccc", + "not_editable": null, + "bigint": 333333333, + "text": "lorem ipsum", + "logic": false, + "date": "2013-01-29", + "integer": 888888, + "unique": "unique 2", + "email": "s.apostolico@gmail.com", + "choices": 2, + "image": "first.png", + "subclassed_image": "subclassed_first.png" + } + }, + { + "pk": 3, + "model": "demo.demomodel", + "fields": { + "nullable": "dddd", + "float": 10.1, + "generic_ip": "192.168.10.2", + "url": "https://github.com/saxix/django-adminactions", + "decimal": "22.2", + "time": "19:00:35", + "blank": "", + "datetime": "2013-01-01T02:18:33Z", + "char": "Pizzä ïs Gööd", + "not_editable": null, + "bigint": 333333333, + "text": "lorem ipsum", + "logic": false, + "date": "2013-01-29", + "integer": 888888, + "unique": "unique 3", + "email": "s.apostolico@gmail.com", + "choices": 2, + "image": null, + "subclassed_image": "subclassed_second.png" + } + } ] diff --git a/tests/demo/migrations/0001_initial.py b/tests/demo/migrations/0001_initial.py deleted file mode 100644 index 615c1f5a..00000000 --- a/tests/demo/migrations/0001_initial.py +++ /dev/null @@ -1,136 +0,0 @@ -# Generated by Django 2.0.1 on 2018-01-29 00:00 - -import uuid - -import demo.models -import django.db.models.deletion -from django.conf import settings -from django.db import migrations, models - - -class Migration(migrations.Migration): - initial = True - - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.CreateModel( - name="DemoModel", - fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("char", models.CharField(max_length=255, verbose_name="Chäř")), - ("integer", models.IntegerField()), - ("logic", models.BooleanField(default=False)), - ("date", models.DateField()), - ("datetime", models.DateTimeField()), - ("time", models.TimeField()), - ("decimal", models.DecimalField(decimal_places=3, max_digits=10)), - ("email", models.EmailField(max_length=254)), - ("float", models.FloatField()), - ("bigint", models.BigIntegerField()), - ("generic_ip", models.GenericIPAddressField()), - ("url", models.URLField()), - ("text", models.TextField()), - ( - "uuid", - models.UUIDField(default=uuid.uuid4, editable=False, unique=True), - ), - ("unique", models.CharField(max_length=255, unique=True)), - ("nullable", models.CharField(max_length=255, null=True)), - ("blank", models.CharField(blank=True, max_length=255, null=True)), - ( - "not_editable", - models.CharField(blank=True, editable=False, max_length=255, null=True), - ), - ( - "choices", - models.IntegerField(choices=[(1, "Choice 1"), (2, "Choice 2"), (3, "Choice 3")]), - ), - ("image", models.ImageField(blank=True, null=True, upload_to="")), - ( - "subclassed_image", - demo.models.SubclassedImageField(blank=True, null=True, upload_to=""), - ), - ], - options={ - "ordering": ("-id",), - }, - ), - migrations.CreateModel( - name="DemoOneToOne", - fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "demo", - models.OneToOneField( - on_delete=django.db.models.deletion.CASCADE, - related_name="onetoone", - to="demo.DemoModel", - ), - ), - ], - ), - migrations.CreateModel( - name="DemoRelated", - fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "demo", - models.ForeignKey( - on_delete=models.deletion.CASCADE, - to="demo.DemoModel", - related_name="related", - to_field="uuid", - ), - ), - ], - ), - migrations.CreateModel( - name="UserDetail", - fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("note", models.CharField(blank=True, max_length=10)), - ( - "user", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to=settings.AUTH_USER_MODEL, - ), - ), - ], - ), - ] diff --git a/tests/demo/models.py b/tests/demo/models.py index c0a20372..55085b1c 100644 --- a/tests/demo/models.py +++ b/tests/demo/models.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import uuid from admin_extra_urls.api import button @@ -42,6 +44,8 @@ class DemoModel(models.Model): image = models.ImageField(blank=True, null=True) subclassed_image = SubclassedImageField(blank=True, null=True) + m2m = models.ManyToManyField("self", blank=True) + class Meta: app_label = "demo" ordering = ("-id",) @@ -90,7 +94,7 @@ def import_fixture(self, request): return _import_fixture(self, request) - def get_custom_field(self, instance): + def get_custom_field(self, instance) -> str: return f"model-attribute-{instance.pk}" diff --git a/tests/demo/settings.py b/tests/demo/settings.py index 87c22d62..9b4fed3c 100644 --- a/tests/demo/settings.py +++ b/tests/demo/settings.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os from environ import Env @@ -15,78 +17,81 @@ "django.core.files.uploadhandler.MemoryFileUploadHandler", "django.core.files.uploadhandler.TemporaryFileUploadHandler", ] - -db = os.environ.get("DBENGINE", None) -if db == "pg": - DATABASES = { - "default": { - "ENGINE": "django.db.backends.postgresql_psycopg2", - "NAME": "adminactions", - "HOST": os.environ.get("PG_HOST", "127.0.0.1"), - "PORT": os.environ.get("PG_PORT", ""), - "USER": os.environ.get("PG_USER", "postgres"), - "PASSWORD": os.environ.get("PG_PASSWORD", ""), - } - } -elif db == "mysql": - DATABASES = { - "default": { - "ENGINE": "django.db.backends.mysql", - "NAME": "adminactions", - "HOST": os.environ.get("MYSQL_HOST", "127.0.0.1"), - "PORT": os.environ.get("MYSQL_PORT", ""), - "USER": os.environ.get("MYSQL_USER", "root"), - "PASSWORD": os.environ.get("MYSQL_PASSWORD", ""), - "CHARSET": "utf8", - "COLLATION": "utf8_general_ci", - "TEST": { - "CHARSET": "utf8", - "COLLATION": "utf8_general_ci", - }, - "TEST_CHARSET": "utf8", - "TEST_COLLATION": "utf8_general_ci", - } - } -elif db == "myisam": - DATABASES = { - "default": { - "ENGINE": "django.db.backends.mysql", - "NAME": "adminactions", - "HOST": os.environ.get("MYSQL_HOST", "127.0.0.1"), - "PORT": os.environ.get("MYSQL_PORT", ""), - "USER": os.environ.get("MYSQL_USER", "root"), - "PASSWORD": os.environ.get("MYSQL_PASSWORD", ""), - "CHARSET": "utf8", - "OPTIONS": {"init_command": "SET storage_engine=MyISAM"}, - "COLLATION": "utf8_general_ci", - "TEST": { - "CHARSET": "utf8", - "COLLATION": "utf8_general_ci", - }, - "TEST_CHARSET": "utf8", - "TEST_COLLATION": "utf8_general_ci", - } - } -else: - DATABASES = { - "default": { - "ENGINE": "django.db.backends.sqlite3", - "NAME": "adminactions.sqlite", - "TEST": { - "NAME": ":memory:", - }, - "TEST_NAME": ":memory:", - "HOST": "", - "PORT": "", - "ATOMIC_REQUESTS": True, - } - } +env = Env() +DATABASES = {"default": env.db("DATABASE_URL")} + +# +# db = os.environ.get("DBENGINE", None) +# if db == "pg": +# DATABASES = { +# "default": { +# "ENGINE": "django.db.backends.postgresql_psycopg2", +# "NAME": "adminactions", +# "HOST": os.environ.get("PG_HOST", "127.0.0.1"), +# "PORT": os.environ.get("PG_PORT", ""), +# "USER": os.environ.get("PG_USER", "postgres"), +# "PASSWORD": os.environ.get("PG_PASSWORD", ""), +# } +# } +# elif db == "mysql": +# DATABASES = { +# "default": { +# "ENGINE": "django.db.backends.mysql", +# "NAME": "adminactions", +# "HOST": os.environ.get("MYSQL_HOST", "127.0.0.1"), +# "PORT": os.environ.get("MYSQL_PORT", ""), +# "USER": os.environ.get("MYSQL_USER", "root"), +# "PASSWORD": os.environ.get("MYSQL_PASSWORD", ""), +# "CHARSET": "utf8", +# "COLLATION": "utf8_general_ci", +# "TEST": { +# "CHARSET": "utf8", +# "COLLATION": "utf8_general_ci", +# }, +# "TEST_CHARSET": "utf8", +# "TEST_COLLATION": "utf8_general_ci", +# } +# } +# elif db == "myisam": +# DATABASES = { +# "default": { +# "ENGINE": "django.db.backends.mysql", +# "NAME": "adminactions", +# "HOST": os.environ.get("MYSQL_HOST", "127.0.0.1"), +# "PORT": os.environ.get("MYSQL_PORT", ""), +# "USER": os.environ.get("MYSQL_USER", "root"), +# "PASSWORD": os.environ.get("MYSQL_PASSWORD", ""), +# "CHARSET": "utf8", +# "OPTIONS": {"init_command": "SET storage_engine=MyISAM"}, +# "COLLATION": "utf8_general_ci", +# "TEST": { +# "CHARSET": "utf8", +# "COLLATION": "utf8_general_ci", +# }, +# "TEST_CHARSET": "utf8", +# "TEST_COLLATION": "utf8_general_ci", +# } +# } +# else: +# DATABASES = { +# "default": { +# "ENGINE": "django.db.backends.sqlite3", +# "NAME": "adminactions.sqlite", +# "TEST": { +# "NAME": ":memory:", +# }, +# "TEST_NAME": ":memory:", +# "HOST": "", +# "PORT": "", +# "ATOMIC_REQUESTS": True, +# } +# } TIME_ZONE = "Asia/Bangkok" LANGUAGE_CODE = "en-us" SITE_ID = 1 USE_I18N = True -USE_L10N = True +# USE_L10N = True USE_TZ = True MEDIA_ROOT = os.environ.get("MEDIA_ROOT", os.path.join(DEMO_DIR, "media")) MEDIA_URL = "" @@ -193,3 +198,4 @@ # CELERY_RESULT_SERIALIZER = "json" # CELERY_TIMEZONE = TIME_ZONE # CELERY_BEAT_SCHEDULER = "django_celery_beat.schedulers:DatabaseScheduler" +DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" diff --git a/tests/demo/storage.py b/tests/demo/storage.py index 238cf08a..7e4d62ef 100644 --- a/tests/demo/storage.py +++ b/tests/demo/storage.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import json from django.conf import settings @@ -60,7 +62,7 @@ class PlainCookieStorage(BaseStorage): not_finished = "__messagesnotfinished__" key_salt = "django.contrib.messages" - def __init__(self, *args, **kwargs): + def __init__(self, *args, **kwargs) -> None: super().__init__(*args, **kwargs) self.signer = signing.get_cookie_signer(salt=self.key_salt) @@ -79,7 +81,7 @@ def _get(self, *args, **kwargs): messages.pop() return messages, all_retrieved - def _update_cookie(self, encoded_data, response): + def _update_cookie(self, encoded_data, response) -> None: """ Either set the cookie with the encoded data if there is any data to store, or delete the cookie. @@ -119,7 +121,7 @@ def stored_length(val): unstored_messages.append(messages.pop(0)) else: unstored_messages.insert(0, messages.pop()) - encoded_data = self._encode(messages + [self.not_finished], encode_empty=unstored_messages) + encoded_data = self._encode([*messages, self.not_finished], encode_empty=unstored_messages) self._update_cookie(encoded_data, response) return unstored_messages @@ -147,6 +149,7 @@ def _encode(self, messages, encode_empty=False): encoder = MessageEncoder(separators=(",", ":")) value = encoder.encode(messages) return self.signer.sign(value) + return None def _decode(self, data): """ diff --git a/tests/demo/urls.py b/tests/demo/urls.py index ad76f244..46c2ce45 100644 --- a/tests/demo/urls.py +++ b/tests/demo/urls.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from django.contrib import admin from django.urls import include, re_path @@ -8,7 +10,6 @@ admin.site.enable_nav_sidebar = False urlpatterns = ( - re_path(r"admin/", admin.site.urls), re_path(r"as/", include("adminactions.urls")), re_path(r"", admin.site.urls), ) diff --git a/tests/selenium_tests/conftest.py b/tests/selenium_tests/conftest.py index cfed99bb..39e7e681 100644 --- a/tests/selenium_tests/conftest.py +++ b/tests/selenium_tests/conftest.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import types @@ -33,9 +35,9 @@ def go(self, url): self._last_url = url return self.get(self.live_server.url + url) - def dump(self, filename=None): + def dump(self, filename=None) -> None: dest = filename or self._last_url.replace("/", "_").replace("#", "~") - self.get_screenshot_as_file("./{}.jpg".format(dest)) + self.get_screenshot_as_file(f"./{dest}.jpg") b = driver b.live_server = live_server @@ -64,7 +66,7 @@ def login(browser): return browser -@pytest.fixture(scope="function") +@pytest.fixture def admin_site(browser, administrator): from demo.models import DemoModel, UserDetail diff --git a/tests/selenium_tests/test_export_csv.py b/tests/selenium_tests/test_export_csv.py index 79374f9f..9f2d51a2 100644 --- a/tests/selenium_tests/test_export_csv.py +++ b/tests/selenium_tests/test_export_csv.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import datetime from time import sleep @@ -10,7 +12,7 @@ @pytest.fixture -def now(monkeypatch): +def now(monkeypatch) -> None: class FixedDateTime: @classmethod def now(cls): @@ -19,8 +21,8 @@ def now(cls): monkeypatch.setattr("adminactions.views.datetime", FixedDateTime) -def test_export_as_csv(admin_site): - browser, administrator = admin_site +def test_export_as_csv(admin_site) -> None: + browser, _administrator = admin_site browser.find_element_by_link_text("Demo models").click() browser.find_element_by_id("action-toggle").click() Select(browser.find_element_by_name("action")).select_by_visible_text("Export as CSV") @@ -39,19 +41,19 @@ def export_csv_page(admin_site): return browser, administrator -def _test(browser, target, format, sample_num, expected_value): +def _test(browser, target, format, sample_num, expected_value) -> None: fmt = browser.find_element_by_id(target) fmt.clear() fmt.send_keys(format) sleep(1) sample = browser.find_elements_by_css_selector("span.sample")[sample_num] # expected_value = dateformat.format(datetime.datetime.now(), format) - assert sample.text == expected_value, "Failed Ajax call on %s" % target + assert sample.text == expected_value, f"Failed Ajax call on {target}" # @pytest.mark.skipif('django.VERSION[:2]==(1,8)') -def test_datetime_format_ajax(export_csv_page, now): - browser, administrator = export_csv_page +def test_datetime_format_ajax(export_csv_page, now) -> None: + browser, _administrator = export_csv_page _test(browser, "id_datetime_format", "l, d F Y", 0, "Friday, 25 December 2020") _test(browser, "id_date_format", "d F Y", 1, "25 December 2020") _test(browser, "id_time_format", "H:i", 2, "17:05") diff --git a/tests/selenium_tests/test_export_xls.py b/tests/selenium_tests/test_export_xls.py index 13348606..3c7f06fb 100644 --- a/tests/selenium_tests/test_export_xls.py +++ b/tests/selenium_tests/test_export_xls.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pytest from selenium.webdriver.support.select import Select diff --git a/tests/selenium_tests/test_mass_update.py b/tests/selenium_tests/test_mass_update.py index 16b81307..c89ccce7 100644 --- a/tests/selenium_tests/test_mass_update.py +++ b/tests/selenium_tests/test_mass_update.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pytest from django.contrib.auth.models import User from selenium.webdriver.support.select import Select @@ -5,19 +7,17 @@ pytestmark = pytest.mark.selenium -def test_mass_update_1(admin_site): +def test_mass_update_1(admin_site) -> None: """ Check Boolean Field. Common values are not filled in boolean fields ( there is no reason to do that ). """ assert User.objects.filter(is_active=True).count() > 1 # sanity check sax = User.objects.get(username="sax") - browser, administrator = admin_site + browser, _administrator = admin_site browser.find_element_by_link_text("Users").click() browser.find_element_by_id("action-toggle").click() - browser.find_element_by_xpath( - "//input[@name='_selected_action' and @value='%s']" % sax.pk - ).click() # unselect sax + browser.find_element_by_xpath(f"//input[@name='_selected_action' and @value='{sax.pk}']").click() # unselect sax Select(browser.find_element_by_name("action")).select_by_visible_text("Mass update") browser.find_element_by_name("index").click() # execute diff --git a/tests/test_api.py b/tests/test_api.py index 32860bdb..0a851a6d 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import csv import io import unittest @@ -13,32 +15,26 @@ class TestExportQuerySetAsCsv(TestCase): - def test_default_params(self): + def test_default_params(self) -> None: with self.assertNumQueries(1): qs = Permission.objects.select_related().filter(codename="add_user") ret = export_as_csv(queryset=qs) - self.assertIsInstance(ret, HttpResponse) + assert isinstance(ret, HttpResponse) if django.VERSION[0] == 2: - self.assertEqual( - ret.content.decode("utf8"), - '"%s";"Can add user";"user";"add_user"\r\n' % qs[0].pk, - ) + assert ret.content.decode("utf8") == f'"{qs[0].pk}";"Can add user";"user";"add_user"\r\n' elif django.VERSION[0] == 3: - self.assertEqual( - ret.content.decode("utf8"), - '"%s";"Can add user";"auth | user";"add_user"\r\n' % qs[0].pk, - ) + assert ret.content.decode("utf8") == f'"{qs[0].pk}";"Can add user";"auth | user";"add_user"\r\n' - def test_header_is_true(self): + def test_header_is_true(self) -> None: mem = io.StringIO() with self.assertNumQueries(1): qs = Permission.objects.select_related().filter(codename="add_user") export_as_csv(queryset=qs, header=True, out=mem) mem.seek(0) csv_reader = csv.reader(mem) - self.assertEqual(next(csv_reader), ['id;"name";"content_type";"codename"']) + assert next(csv_reader) == ['id;"name";"content_type";"codename"'] - def test_queryset_values(self): + def test_queryset_values(self) -> None: fields = ["codename", "content_type__app_label"] header = ["Name", "Application"] mem = io.StringIO() @@ -47,9 +43,9 @@ def test_queryset_values(self): export_as_csv(queryset=qs, fields=fields, header=header, out=mem) mem.seek(0) csv_dump = mem.read() - self.assertEqual(csv_dump, '"Name";"Application"\r\n"add_user";"auth"\r\n') + assert csv_dump == '"Name";"Application"\r\n"add_user";"auth"\r\n' - def test_callable_method(self): + def test_callable_method(self) -> None: fields = ["codename", "natural_key"] mem = io.StringIO() with self.assertNumQueries(2): @@ -57,9 +53,9 @@ def test_callable_method(self): export_as_csv(queryset=qs, fields=fields, out=mem) mem.seek(0) csv_dump = mem.read() - self.assertEqual(csv_dump, "\"add_user\";\"('add_user', 'auth', 'user')\"\r\n") + assert csv_dump == "\"add_user\";\"('add_user', 'auth', 'user')\"\r\n" - def test_deep_attr(self): + def test_deep_attr(self) -> None: fields = ["codename", "content_type.app_label"] mem = io.StringIO() with self.assertNumQueries(1): @@ -67,11 +63,11 @@ def test_deep_attr(self): export_as_csv(queryset=qs, fields=fields, out=mem) mem.seek(0) csv_dump = mem.read() - self.assertEqual(csv_dump, '"add_user";"auth"\r\n') + assert csv_dump == '"add_user";"auth"\r\n' class TestExportAsCsv(unittest.TestCase): - def test_export_as_csv(self): + def test_export_as_csv(self) -> None: fields = ["field1", "field2"] header = ["Field 1", "Field 2"] Row = namedtuple("Row", fields) @@ -80,9 +76,9 @@ def test_export_as_csv(self): export_as_csv(queryset=rows, fields=fields, header=header, out=mem) mem.seek(0) csv_dump = mem.read() - self.assertEqual(csv_dump, '"Field 1";"Field 2"\r\n"1";"4"\r\n"2";"5"\r\n"3";"ӼӳӬԖԊ"\r\n') + assert csv_dump == '"Field 1";"Field 2"\r\n"1";"4"\r\n"2";"5"\r\n"3";"ӼӳӬԖԊ"\r\n' - def test_dialect(self): + def test_dialect(self) -> None: fields = ["field1", "field2"] header = ["Field 1", "Field 2"] Row = namedtuple("Row", fields) @@ -97,17 +93,17 @@ def test_dialect(self): ) mem.seek(0) csv_dump = mem.read() - self.assertEqual(csv_dump, "Field 1,Field 2\r\n1,4\r\n2,5\r\n3,ӼӳӬԖԊ\r\n") + assert csv_dump == "Field 1,Field 2\r\n1,4\r\n2,5\r\n3,ӼӳӬԖԊ\r\n" class TestExportAsExcel(TestCase): - def test_default_params(self): + def test_default_params(self) -> None: with self.assertNumQueries(1): qs = Permission.objects.select_related().filter(codename="add_user") ret = export_as_xls(queryset=qs) - self.assertIsInstance(ret, HttpResponse) + assert isinstance(ret, HttpResponse) - def test_header_is_true(self): + def test_header_is_true(self) -> None: mem = io.BytesIO() with self.assertNumQueries(1): qs = Permission.objects.select_related().filter(codename="add_user") @@ -115,9 +111,9 @@ def test_header_is_true(self): mem.seek(0) xls_workbook = xlrd.open_workbook(file_contents=mem.read()) xls_sheet = xls_workbook.sheet_by_index(0) - self.assertEqual(xls_sheet.row_values(0)[:], ["#", "ID", "name", "content type", "codename"]) + assert xls_sheet.row_values(0)[:] == ["#", "ID", "name", "content type", "codename"] - def test_export_as_xls(self): + def test_export_as_xls(self) -> None: fields = ["field1", "field2"] header = ["Field 1", "Field 2"] Row = namedtuple("Row", fields) @@ -128,14 +124,14 @@ def test_export_as_xls(self): xls_workbook = xlrd.open_workbook(file_contents=mem.read()) xls_sheet = xls_workbook.sheet_by_index(0) - self.assertEqual(xls_sheet.row_values(0)[:], ["#", "Field 1", "Field 2"]) - self.assertEqual(xls_sheet.row_values(1)[:], [1.0, 111.0, 222.0]) - self.assertEqual(xls_sheet.row_values(2)[:], [2.0, 333.0, 444.0]) - self.assertEqual(xls_sheet.row_values(3)[:], [3.0, 555.0, "ӼӳӬԖԊ"]) + assert xls_sheet.row_values(0)[:] == ["#", "Field 1", "Field 2"] + assert xls_sheet.row_values(1)[:] == [1.0, 111.0, 222.0] + assert xls_sheet.row_values(2)[:] == [2.0, 333.0, 444.0] + assert xls_sheet.row_values(3)[:] == [3.0, 555.0, "ӼӳӬԖԊ"] class TestExportQuerySetAsExcel(TestCase): - def test_queryset_values(self): + def test_queryset_values(self) -> None: fields = ["codename", "content_type__app_label"] header = ["Name", "Application"] qs = Permission.objects.filter(codename="add_user").values("codename", "content_type__app_label") @@ -144,10 +140,10 @@ def test_queryset_values(self): mem.seek(0) w = xlrd.open_workbook(file_contents=mem.read()) sheet = w.sheet_by_index(0) - self.assertEqual(sheet.cell_value(1, 1), "add_user") - self.assertEqual(sheet.cell_value(1, 2), "auth") + assert sheet.cell_value(1, 1) == "add_user" + assert sheet.cell_value(1, 2) == "auth" - def test_callable_method(self): + def test_callable_method(self) -> None: fields = ["codename", "natural_key"] qs = Permission.objects.filter(codename="add_user") mem = io.BytesIO() @@ -156,5 +152,5 @@ def test_callable_method(self): content = mem.read() w = xlrd.open_workbook(file_contents=content) sheet = w.sheet_by_index(0) - self.assertEqual(sheet.cell_value(1, 1), "add_user") - self.assertEqual(sheet.cell_value(1, 2), "add_userauthuser") + assert sheet.cell_value(1, 1) == "add_user" + assert sheet.cell_value(1, 2) == "add_userauthuser" diff --git a/tests/test_bulk_update.py b/tests/test_bulk_update.py index 2a71c1f4..dde3e238 100644 --- a/tests/test_bulk_update.py +++ b/tests/test_bulk_update.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import csv from pathlib import Path @@ -30,7 +32,7 @@ class BulkUpdate(SelectRowsMixin, CheckSignalsMixin, WebTestMixin): action_name = "bulk_update" sender_model = DemoModel - def setUp(self): + def setUp(self) -> None: super().setUp() self._url = reverse("admin:demo_demomodel_changelist") self.user = G(User, username="user", is_staff=True, is_active=True) @@ -84,9 +86,7 @@ def _run_action_related_model(self, steps=2, **kwargs): self._select_rows(form, selected_rows) res = form.submit() if steps >= 2: - res.forms["bulk-update"]["_file"] = Upload( - str(Path(__file__).parent / "related_model_bulk_update.csv") - ) + res.forms["bulk-update"]["_file"] = Upload(str(Path(__file__).parent / "related_model_bulk_update.csv")) res.forms["bulk-update"]["fld-id"] = "id" res.forms["bulk-update"]["fld-index_field"] = ["id"] res.forms["bulk-update"]["fld-demo"] = "demo_uuid" @@ -98,30 +98,28 @@ def _run_action_related_model(self, steps=2, **kwargs): res = res.forms["bulk-update"].submit("apply") return res - def test_simulate(self): - res = self._run_action( - **{ - "_clean": 1, - "_validate": 1, - "select_across": 1, - "csv-header": False, - "_file": Upload( - "data.csv", - b"1,aaa,111\n2,bbb,222\n3,ccc,333", - "text/csv", - ), - "_dry_run": True, - "fld-id": "1", - "fld-char": "2", - "fld-integer": "3", - } - ) + def test_simulate(self) -> None: + res = self._run_action(**{ + "_clean": 1, + "_validate": 1, + "select_across": 1, + "csv-header": False, + "_file": Upload( + "data.csv", + b"1,aaa,111\n2,bbb,222\n3,ccc,333", + "text/csv", + ), + "_dry_run": True, + "fld-id": "1", + "fld-char": "2", + "fld-integer": "3", + }) # no changes saved on the DB assert not DemoModel.objects.filter(char="aaa", integer=111).exists() assert not DemoModel.objects.filter(char="bbb", integer=222).exists() assert res.status_code == 200 - def test_no_permission(self): + def test_no_permission(self) -> None: with user_grant_permission(self.user, ["demo.change_demomodel"]): res = self.app.get("/", user="user") res = res.click("Demo models") @@ -131,133 +129,117 @@ def test_no_permission(self): res = form.submit().follow() assert "Sorry you do not have rights to execute this action" in str(res.body) - def test_no_header(self): - self._run_action( - **{ - "_clean": 1, - "_validate": 1, - "select_across": 1, - "csv-header": False, - "_file": Upload( - "data.csv", - b"1,aaa,111\n2,bbb,222\n3,ccc,333", - "text/csv", - ), - "fld-id": "1", - "fld-char": "2", - "fld-integer": "3", - } - ) + def test_no_header(self) -> None: + self._run_action(**{ + "_clean": 1, + "_validate": 1, + "select_across": 1, + "csv-header": False, + "_file": Upload( + "data.csv", + b"1,aaa,111\n2,bbb,222\n3,ccc,333", + "text/csv", + ), + "fld-id": "1", + "fld-char": "2", + "fld-integer": "3", + }) assert DemoModel.objects.filter(char="aaa", integer=111).exists() assert DemoModel.objects.filter(char="bbb", integer=222).exists() - def test_clean_on(self): - self._run_action( - **{ - "_clean": 1, - "_validate": 1, - "select_across": 1, - "_file": Upload( - "data.csv", - b"pk,name,number\n1,aaa,111\n2,bbb,222\n3,ccc,333", - "text/csv", - ), - "fld-char": "name", - "fld-integer": "number", - } - ) + def test_clean_on(self) -> None: + self._run_action(**{ + "_clean": 1, + "_validate": 1, + "select_across": 1, + "_file": Upload( + "data.csv", + b"pk,name,number\n1,aaa,111\n2,bbb,222\n3,ccc,333", + "text/csv", + ), + "fld-char": "name", + "fld-integer": "number", + }) assert DemoModel.objects.filter(char="aaa").exists() assert DemoModel.objects.filter(char="bbb").exists() - def test_messages(self): + def test_messages(self) -> None: with user_grant_permission( self.user, ["demo.change_demomodel", "demo.adminactions_bulkupdate_demomodel"], ): - res = self._run_action( - **{ - "select_across": 1, - "_file": Upload( - "data.csv", - b"pk,name,number\n1,aaa,111\n2,bbb,222\n3,ccc,333", - "text/csv", - ), - "fld-char": "name", - "fld-integer": "number", - } - ) + res = self._run_action(**{ + "select_across": 1, + "_file": Upload( + "data.csv", + b"pk,name,number\n1,aaa,111\n2,bbb,222\n3,ccc,333", + "text/csv", + ), + "fld-char": "name", + "fld-integer": "number", + }) messages = [m.message for m in list(res.context["messages"])] - self.assertTrue(messages) + assert messages assert "Updated" in messages[0] res = self._run_action(selected_rows=[1]) messages = [m.message for m in list(res.context["messages"])] - self.assertTrue(messages) + assert messages assert "Updated" in messages[0] - def test_index_required(self): + def test_index_required(self) -> None: res = self._run_action(**{"_validate": 0, "fld-index_field": []}) assert res.status_code == 200 assert res.context["map_form"].errors == {"index_field": ["Please select one or more index fields"]} - def test_wrong_mapping(self): - res = self._run_action( - **{ - "_file": Upload( - "data.csv", - b"pk,name,number\n1,aaa,111\n2,bbb,222\n3,ccc,333", - "text/csv", - ), - "fld-index_field": ["id"], - "fld-id": "miss", - } - ) + def test_wrong_mapping(self) -> None: + res = self._run_action(**{ + "_file": Upload( + "data.csv", + b"pk,name,number\n1,aaa,111\n2,bbb,222\n3,ccc,333", + "text/csv", + ), + "fld-index_field": ["id"], + "fld-id": "miss", + }) assert res.status_code == 200 messages = [m.message for m in list(res.context["messages"])] assert messages[0] == "['miss column is not present in the file']" - def test_bulk_update_with_one_to_one_field(self): + def test_bulk_update_with_one_to_one_field(self) -> None: demo_model_instance = G(DemoModel, char="InitialValue", integer=123) demo_one_to_one_instance = G(DemoOneToOne, demo=demo_model_instance) csv_data = f"pk,one_to_one_id\n{demo_model_instance.pk},{demo_one_to_one_instance.pk}" - res = self._run_action( - **{ - "_file": Upload( - "data.csv", - csv_data.encode(), - "text/csv", - ), - "fld-onetoone": "one_to_one_id", - } - ) - self.assertTrue( - DemoModel.objects.filter(pk=demo_model_instance.pk, onetoone=demo_one_to_one_instance).exists() - ) - self.assertEqual(res.status_code, 200) + res = self._run_action(**{ + "_file": Upload( + "data.csv", + csv_data.encode(), + "text/csv", + ), + "fld-onetoone": "one_to_one_id", + }) + assert DemoModel.objects.filter(pk=demo_model_instance.pk, onetoone=demo_one_to_one_instance).exists() + assert res.status_code == 200 - def test_bulk_update_with_foreign_key(self): + def test_bulk_update_with_foreign_key(self) -> None: demo_model_instance = G(DemoModel, char="InitialValue", integer=123) demo_related_instance = G(DemoRelated, demo=demo_model_instance) new_demo_model_instance = G(DemoModel, char="NewValue", integer=456) csv_data = f"id,demo_uuid\n{demo_related_instance.pk},{new_demo_model_instance.uuid}" - res = self._run_action_related_model( - **{ - "_file": Upload( - "data.csv", - csv_data.encode(), - "text/csv", - ), - "fld-demo": "demo_uuid", - } - ) + res = self._run_action_related_model(**{ + "_file": Upload( + "data.csv", + csv_data.encode(), + "text/csv", + ), + "fld-demo": "demo_uuid", + }) - self.assertTrue( - DemoRelated.objects.filter(pk=demo_related_instance.pk, demo=new_demo_model_instance).exists() - ) - self.assertEqual(res.status_code, 200) + assert DemoRelated.objects.filter(pk=demo_related_instance.pk, demo=new_demo_model_instance).exists() + assert res.status_code == 200 class BulkUpdateMemoryFileUploadHandlerTest(BulkUpdate, TestCase): diff --git a/tests/test_byrows_update.py b/tests/test_byrows_update.py index 7516298e..a0f4725f 100644 --- a/tests/test_byrows_update.py +++ b/tests/test_byrows_update.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from demo.models import DemoModel from django.contrib.admin.options import ModelAdmin from django.contrib.admin.sites import AdminSite @@ -23,7 +25,7 @@ class TestByRowsUpdateAction(WebTestMixin, SelectRowsMixin, TestCase): _selected_rows = [0, 1] csrf_checks = False - def setUp(self): + def setUp(self) -> None: super().setUp() self._url = reverse("admin:demo_demomodel_changelist") self.user = G(User, username="user", is_staff=True, is_active=True) @@ -32,16 +34,14 @@ def setUp(self): def _get_changelist_form_response(self): res = self.app.get("/", user="user") - res = res.click("Demo models") - return res + return res.click("Demo models") def _get_action_form_response(self, change_list_response=None): form = change_list_response.forms["changelist-form"] form["action"] = "byrows_update" - res = form.submit() - return res + return form.submit() - def test_no_permission(self): + def test_no_permission(self) -> None: with user_grant_permission(self.user, ["demo.change_demomodel"]): res = self._get_changelist_form_response() @@ -51,7 +51,7 @@ def test_no_permission(self): res = form.submit().follow() assert "Sorry you do not have rights to execute this action" in str(res.body) - def test_form_rows_count(self): + def test_form_rows_count(self) -> None: """ Count the selected items appear in the action form """ @@ -65,12 +65,9 @@ def test_form_rows_count(self): form = res.forms["changelist-form"] self._select_rows(form, selected_rows=self._selected_rows) res = self._get_action_form_response(change_list_response=res) - self.assertEqual( - len(res.html.find(id="formset").find_all(class_="row")), - len(self._selected_rows), - ) + assert len(res.html.find(id="formset").find_all(class_="row")) == len(self._selected_rows) - def test_form_rows_fields_exists(self): + def test_form_rows_fields_exists(self) -> None: """ Check model fields appear in action form for each selected models """ @@ -84,7 +81,7 @@ def test_form_rows_fields_exists(self): self._select_rows(form, selected_rows=self._selected_rows) res = self._get_action_form_response(change_list_response=res) byrows_update_get_fields(ModelAdmin(DemoModel, self.site)) - for r, value in enumerate(self._selected_values): + for r, _value in enumerate(self._selected_values): for fname in byrows_update_get_fields(ModelAdmin(DemoModel, self.site)): fname = "form-%d-%s" % (r, fname) @@ -96,7 +93,7 @@ def test_form_rows_fields_exists(self): # field name upon errors assert res.forms["update-form"][fname] - def test_form_rows_edit(self): + def test_form_rows_edit(self) -> None: """ Modify a value in action form and see if its stored upon form submit """ @@ -117,4 +114,4 @@ def test_form_rows_edit(self): res.forms["update-form"].submit("apply") obj = DemoModel.objects.get(id=self._selected_values[row_to_modify]) for k, v in new_values.items(): - self.assertEqual(v, getattr(obj, k)) + assert v == getattr(obj, k) diff --git a/tests/test_checks.py b/tests/test_checks.py new file mode 100644 index 00000000..b377de3d --- /dev/null +++ b/tests/test_checks.py @@ -0,0 +1,8 @@ +from unittest.mock import Mock + + +def test_checks(): + from adminactions.checks import check_adminactions_settings + + errs = check_adminactions_settings(Mock()) + assert errs == [] diff --git a/tests/test_create_extra_permissions_handler.py b/tests/test_create_extra_permissions_handler.py new file mode 100644 index 00000000..257cdd7c --- /dev/null +++ b/tests/test_create_extra_permissions_handler.py @@ -0,0 +1,23 @@ +from unittest import mock +from unittest.mock import Mock + +import pytest +from django.apps import apps + +from adminactions import consts +from adminactions.apps import Config +from adminactions.models import create_extra_permissions_handler + + +@pytest.mark.parametrize("value", [consts.AA_PERMISSION_CREATE_USE_SIGNAL, consts.AA_PERMISSION_CREATE_USE_APPCONFIG]) +def test_post_migrate(value): + with mock.patch("adminactions.config.AA_PERMISSION_HANDLER", value): + create_extra_permissions_handler(Mock()) + + +def test_app_config(): + with mock.patch("adminactions.config.AA_PERMISSION_HANDLER", consts.AA_PERMISSION_CREATE_USE_APPCONFIG): + with mock.patch("adminactions.perms.create_extra_permissions") as m: + apps.get_app_config('adminactions').ready() + + assert m.call_count == 1 diff --git a/tests/test_duplicates.py b/tests/test_duplicates.py index 3b8093ee..ac06f391 100644 --- a/tests/test_duplicates.py +++ b/tests/test_duplicates.py @@ -1,4 +1,6 @@ # from adminactions.signals import adminaction_requested, adminaction_start, adminaction_end +from __future__ import annotations + from demo.models import DemoModel from django.contrib.auth.models import User from django.test import TestCase @@ -22,7 +24,7 @@ class FindDuplicatesTest(SelectRowsMixin, CheckSignalsMixin, WebTestMixin, TestC action_name = "find_duplicates_action" sender_model = DemoModel - def setUp(self): + def setUp(self) -> None: super().setUp() self._url = reverse("admin:demo_demomodel_changelist") self.user = G(User, username="user", is_staff=True, is_active=True) @@ -51,7 +53,7 @@ def _run_action(self, steps=2, **kwargs): res = res.form.submit("apply") return res - def test_no_permission(self): + def test_no_permission(self) -> None: with user_grant_permission(self.user, ["demo.change_demomodel"]): res = self.app.get("/", user="user") res = res.click("Demo models") @@ -61,7 +63,7 @@ def test_no_permission(self): res = form.submit().follow() assert "Sorry you do not have rights to execute this action" in str(res.body) - def test_validate_on(self): + def test_validate_on(self) -> None: self._run_action() # diff --git a/tests/test_exports.py b/tests/test_exports.py index 9f62fe30..89b368cc 100644 --- a/tests/test_exports.py +++ b/tests/test_exports.py @@ -1,24 +1,31 @@ +from __future__ import annotations + import csv import io import time import unittest +from unittest import mock from unittest.mock import Mock -import mock import xlrd from django.contrib.auth.models import User from django.test.utils import override_settings from django.utils.encoding import smart_str from django_dynamic_fixture import G from django_webtest import WebTest -from utils import CheckSignalsMixin, SelectRowsMixin, admin_register, user_grant_permission +from utils import ( + CheckSignalsMixin, + SelectRowsMixin, + admin_register, + user_grant_permission, +) __all__ = [ "ExportAsCsvTest", - "ExportAsFixtureTest", "ExportAsCsvTest", - "ExportDeleteTreeTest", + "ExportAsFixtureTest", "ExportAsXlsTest", + "ExportDeleteTreeTest", ] @@ -27,7 +34,7 @@ class ExportMixin: urls = "demo.urls" csrf_checks = True - def setUp(self): + def setUp(self) -> None: super().setUp() self.user = G(User, username="user", is_staff=True, is_active=True) @@ -37,7 +44,7 @@ class ExportAsFixtureTest(ExportMixin, SelectRowsMixin, CheckSignalsMixin, WebTe action_name = "export_as_fixture" _selected_rows = [0, 1, 2] - def test_no_permission(self): + def test_no_permission(self) -> None: with user_grant_permission(self.user, ["auth.change_user"]): res = self.app.get("/", user="user") res = res.click("Users") @@ -47,7 +54,7 @@ def test_no_permission(self): res = form.submit().follow() assert b"Sorry you do not have rights to execute this action" in res.body - def test_success(self): + def test_success(self) -> None: with user_grant_permission(self.user, ["auth.change_user", "auth.adminactions_export_user"]): res = self.app.get("/", user="user") res = res.click("Users") @@ -61,7 +68,7 @@ def test_success(self): res = res.forms["export-form"].submit("apply") assert res.json[0]["pk"] == 1 - def test_add_foreign_keys(self): + def test_add_foreign_keys(self) -> None: with user_grant_permission(self.user, ["auth.change_user", "auth.adminactions_export_user"]): res = self.app.get("/", user="user") res = res.click("Users") @@ -95,7 +102,7 @@ class ExportDeleteTreeTest(ExportMixin, SelectRowsMixin, CheckSignalsMixin, WebT action_name = "export_delete_tree" _selected_rows = [0, 1, 2] - def test_no_permission(self): + def test_no_permission(self) -> None: with user_grant_permission(self.user, ["auth.change_user"]): res = self.app.get("/", user="user") res = res.click("Users") @@ -105,7 +112,7 @@ def test_no_permission(self): res = form.submit().follow() assert b"Sorry you do not have rights to execute this action" in res.body - def test_success(self): + def test_success(self) -> None: with user_grant_permission(self.user, ["auth.change_user", "auth.adminactions_export_user"]): res = self.app.get("/", user="user") res = res.click("Users") @@ -130,28 +137,30 @@ def _run_action(self, steps=2): res = res.forms["export-form"].submit("apply") return res - def test_custom_filename(self): + def test_custom_filename(self) -> None: """ if the ModelAdmin has `get_export_as_csv_filename()` use that method to get the attachment filename """ with user_grant_permission(self.user, ["auth.change_user", "auth.adminactions_export_user"]): res = self.app.get("/", user="user") - with admin_register(User) as md: - with mock.patch.object( + with ( + admin_register(User) as md, + mock.patch.object( md, "get_export_delete_tree_filename", lambda r, q: "new.test", create=True, - ): - res = res.click("Users") - form = res.forms["changelist-form"] - form["action"] = self.action_name - form.set("_selected_action", True, 0) - form["select_across"] = 1 - res = form.submit() - res = res.forms["export-form"].submit("apply") - self.assertEqual(res.content_disposition, 'attachment;filename="new.test"') + ), + ): + res = res.click("Users") + form = res.forms["changelist-form"] + form["action"] = self.action_name + form.set("_selected_action", True, 0) + form["select_across"] = 1 + res = form.submit() + res = res.forms["export-form"].submit("apply") + assert res.content_disposition == 'attachment;filename="new.test"' class ExportAsCsvTest(ExportMixin, SelectRowsMixin, CheckSignalsMixin, WebTest): @@ -159,7 +168,7 @@ class ExportAsCsvTest(ExportMixin, SelectRowsMixin, CheckSignalsMixin, WebTest): action_name = "export_as_csv" _selected_rows = [0, 1] - def test_no_permission(self): + def test_no_permission(self) -> None: with user_grant_permission(self.user, ["auth.change_user"]): res = self.app.get("/", user="user") res = res.click("Users") @@ -169,10 +178,8 @@ def test_no_permission(self): res = form.submit().follow() assert b"Sorry you do not have rights to execute this action" in res.body - def test_success(self): - with user_grant_permission( - self.user, ["demo.change_demomodel", "demo.adminactions_export_demomodel"] - ): + def test_success(self) -> None: + with user_grant_permission(self.user, ["demo.change_demomodel", "demo.adminactions_export_demomodel"]): res = self.app.get("/", user="user") res = res.click("Demo models") form = res.forms["changelist-form"] @@ -184,30 +191,32 @@ def test_success(self): buff = io.StringIO(smart_str(res.body)) csv_reader = csv.reader(buff) - self.assertEqual(len(list(csv_reader)), 2) + assert len(list(csv_reader)) == 2 - def test_custom_filename(self): + def test_custom_filename(self) -> None: """ if the ModelAdmin has `get_export_as_csv_filename()` use that method to get the attachment filename """ with user_grant_permission(self.user, ["auth.change_user", "auth.adminactions_export_user"]): res = self.app.get("/", user="user") - with admin_register(User) as md: - with mock.patch.object( + with ( + admin_register(User) as md, + mock.patch.object( md, "get_export_as_csv_filename", lambda r, q: "new.test", create=True, - ): - res = res.click("Users") - form = res.forms["changelist-form"] - form["action"] = "export_as_csv" - form.set("_selected_action", True, 0) - form["select_across"] = 1 - res = form.submit() - res = res.forms["export-form"].submit("apply") - self.assertEqual(res.content_disposition, 'attachment;filename="new.test"') + ), + ): + res = res.click("Users") + form = res.forms["changelist-form"] + form["action"] = "export_as_csv" + form.set("_selected_action", True, 0) + form["select_across"] = 1 + res = form.submit() + res = res.forms["export-form"].submit("apply") + assert res.content_disposition == 'attachment;filename="new.test"' def _run_action(self, steps=2): with user_grant_permission(self.user, ["auth.change_user", "auth.adminactions_export_user"]): @@ -223,12 +232,12 @@ def _run_action(self, steps=2): return res @override_settings(ADMINACTIONS_STREAM_CSV=True) - def test_streaming_export(self): + def test_streaming_export(self) -> None: res = self._run_action() buff = io.StringIO(smart_str(res.body)) csv_reader = csv.reader(buff) - self.assertEqual(len(list(csv_reader)), 2) + assert len(list(csv_reader)) == 2 class ExportAsXlsTest(ExportMixin, SelectRowsMixin, CheckSignalsMixin, WebTest): @@ -250,7 +259,7 @@ def _run_action(self, step=3): res = res.forms["export-form"].submit("apply") return res - def test_no_permission(self): + def test_no_permission(self) -> None: with user_grant_permission(self.user, ["auth.change_user"]): res = self.app.get("/", user="user") res = res.click("Users") @@ -260,7 +269,7 @@ def test_no_permission(self): res = form.submit().follow() assert b"Sorry you do not have rights to execute this action" in res.body - def test_success(self): + def test_success(self) -> None: with user_grant_permission(self.user, ["auth.change_user", "auth.adminactions_export_user"]): res = self.app.get("/", user="user") res = res.click("Users") @@ -272,26 +281,24 @@ def test_success(self): self._select_rows(form) res = form.submit() res.forms["export-form"]["header"] = 1 - res.forms["export-form"]["columns"] = ["id", "username", "first_name" ""] + res.forms["export-form"]["columns"] = ["id", "username", "first_name"] res = res.forms["export-form"].submit("apply") buff = io.BytesIO(res.body) buff.seek(0) w = xlrd.open_workbook(file_contents=buff.read()) sheet = w.sheet_by_index(0) - self.assertEqual(sheet.cell_value(0, 0), "#") - self.assertEqual(sheet.cell_value(0, 1), "ID") - self.assertEqual(sheet.cell_value(0, 2), "username") - self.assertEqual(sheet.cell_value(0, 3), "first name") - self.assertEqual(sheet.cell_value(1, 1), 1.0) - self.assertEqual(sheet.cell_value(1, 2), "sax") - self.assertEqual(sheet.cell_value(2, 2), "user") + assert sheet.cell_value(0, 0) == "#" + assert sheet.cell_value(0, 1) == "ID" + assert sheet.cell_value(0, 2) == "username" + assert sheet.cell_value(0, 3) == "first name" + assert sheet.cell_value(1, 1) == 1.0 + assert sheet.cell_value(1, 2) == "sax" + assert sheet.cell_value(2, 2) == "user" # self.assertEqual(sheet.cell_value(3, 2), u'user_00') - def test_use_display_ok(self): - with user_grant_permission( - self.user, ["demo.change_demomodel", "demo.adminactions_export_demomodel"] - ): + def test_use_display_ok(self) -> None: + with user_grant_permission(self.user, ["demo.change_demomodel", "demo.adminactions_export_demomodel"]): res = self.app.get("/", user="user") res = res.click("Demo models") form = res.forms["changelist-form"] @@ -304,7 +311,7 @@ def test_use_display_ok(self): "char", "text", "bigint", - "choices" "", + "choices", ] res = res.forms["export-form"].submit("apply") buff = io.BytesIO(res.body) @@ -312,19 +319,17 @@ def test_use_display_ok(self): buff.seek(0) w = xlrd.open_workbook(file_contents=buff.read()) sheet = w.sheet_by_index(0) - self.assertEqual(sheet.cell_value(0, 1), "Chäř") - self.assertEqual(sheet.cell_value(0, 2), "bigint") - self.assertEqual(sheet.cell_value(0, 3), "text") - self.assertEqual(sheet.cell_value(0, 4), "choices") - self.assertEqual(sheet.cell_value(1, 1), "Pizzä ïs Gööd") - self.assertEqual(sheet.cell_value(1, 2), 333333333.0) - self.assertEqual(sheet.cell_value(1, 3), "lorem ipsum") - self.assertEqual(sheet.cell_value(1, 4), "Choice 2") - - def test_use_display_ko(self): - with user_grant_permission( - self.user, ["demo.change_demomodel", "demo.adminactions_export_demomodel"] - ): + assert sheet.cell_value(0, 1) == "Chäř" + assert sheet.cell_value(0, 2) == "bigint" + assert sheet.cell_value(0, 3) == "text" + assert sheet.cell_value(0, 4) == "choices" + assert sheet.cell_value(1, 1) == "Pizzä ïs Gööd" + assert sheet.cell_value(1, 2) == 333333333.0 + assert sheet.cell_value(1, 3) == "lorem ipsum" + assert sheet.cell_value(1, 4) == "Choice 2" + + def test_use_display_ko(self) -> None: + with user_grant_permission(self.user, ["demo.change_demomodel", "demo.adminactions_export_demomodel"]): res = self.app.get("/", user="user") res = res.click("Demo models") form = res.forms["changelist-form"] @@ -336,7 +341,7 @@ def test_use_display_ko(self): "char", "text", "bigint", - "choices" "", + "choices", ] res = res.forms["export-form"].submit("apply") buff = io.BytesIO(res.body) @@ -344,19 +349,17 @@ def test_use_display_ko(self): buff.seek(0) w = xlrd.open_workbook(file_contents=buff.read()) sheet = w.sheet_by_index(0) - self.assertEqual(sheet.cell_value(0, 1), "Chäř") - self.assertEqual(sheet.cell_value(0, 2), "bigint") - self.assertEqual(sheet.cell_value(0, 3), "text") - self.assertEqual(sheet.cell_value(0, 4), "choices") - self.assertEqual(sheet.cell_value(1, 1), "Pizzä ïs Gööd") - self.assertEqual(sheet.cell_value(1, 2), 333333333.0) - self.assertEqual(sheet.cell_value(1, 3), "lorem ipsum") - self.assertEqual(sheet.cell_value(1, 4), 2.0) - - def test_unicode(self): - with user_grant_permission( - self.user, ["demo.change_demomodel", "demo.adminactions_export_demomodel"] - ): + assert sheet.cell_value(0, 1) == "Chäř" + assert sheet.cell_value(0, 2) == "bigint" + assert sheet.cell_value(0, 3) == "text" + assert sheet.cell_value(0, 4) == "choices" + assert sheet.cell_value(1, 1) == "Pizzä ïs Gööd" + assert sheet.cell_value(1, 2) == 333333333.0 + assert sheet.cell_value(1, 3) == "lorem ipsum" + assert sheet.cell_value(1, 4) == 2.0 + + def test_unicode(self) -> None: + with user_grant_permission(self.user, ["demo.change_demomodel", "demo.adminactions_export_demomodel"]): res = self.app.get("/", user="user") res = res.click("Demo models") form = res.forms["changelist-form"] @@ -373,14 +376,12 @@ def test_unicode(self): buff.seek(0) w = xlrd.open_workbook(file_contents=buff.read()) sheet = w.sheet_by_index(0) - self.assertEqual(sheet.cell_value(0, 1), "Chäř") - self.assertEqual(sheet.cell_value(1, 1), "Pizzä ïs Gööd") + assert sheet.cell_value(0, 1) == "Chäř" + assert sheet.cell_value(1, 1) == "Pizzä ïs Gööd" - def test_issue_93(self): + def test_issue_93(self) -> None: # default date(time) format in XLS export doesn't import well on excel - with user_grant_permission( - self.user, ["demo.change_demomodel", "demo.adminactions_export_demomodel"] - ): + with user_grant_permission(self.user, ["demo.change_demomodel", "demo.adminactions_export_demomodel"]): res = self.app.get("/", user="user") res = res.click("Demo models") form = res.forms["changelist-form"] @@ -403,18 +404,18 @@ def test_issue_93(self): format_key = fmt.format_key format = w.format_map[format_key] # gets a Format object - self.assertEqual(cell.value, 41303.0) - self.assertEqual(cell.ctype, 3) - self.assertEqual(format.format_str, "d/m/Y") + assert cell.value == 41303.0 + assert cell.ctype == 3 + assert format.format_str == "d/m/Y" @unittest.skip("Impossible to reliably time different machine runs") - def test_faster_export(self): + def test_faster_export(self) -> None: # generate 3k users start = time.time() user_count = User.objects.count() - User.objects.bulk_create([User(username="bulk_user_%s" % i) for i in range(3000)]) + User.objects.bulk_create([User(username=f"bulk_user_{i}") for i in range(3000)]) # print('created 3k users in %.1f seconds' % (time.time() - start)) - self.assertEqual(User.objects.count(), 3000 + user_count) + assert User.objects.count() == 3000 + user_count start = time.time() with user_grant_permission(self.user, ["auth.change_user", "auth.adminactions_export_user"]): @@ -437,14 +438,10 @@ def test_faster_export(self): w = xlrd.open_workbook(file_contents=buff.read()) sheet = w.sheet_by_index(0) - self.assertEqual(sheet.nrows, 3000 + user_count + 1) - self.assertLessEqual( - res_time, - 6.5, - "Response should return under 6.5 " "seconds, was %.2f" % res_time, - ) + assert sheet.nrows == 3000 + user_count + 1 + assert res_time <= 6.5, f"Response should return under 6.5 seconds, was {res_time:.2f}" - def test_modeladmin_attributes(self): + def test_modeladmin_attributes(self) -> None: from demo.models import DemoModel from django.contrib.admin import site diff --git a/tests/test_graph.py b/tests/test_graph.py index ab891e20..eee109f7 100644 --- a/tests/test_graph.py +++ b/tests/test_graph.py @@ -1,4 +1,9 @@ +from __future__ import annotations + +from pathlib import Path + from django.contrib.auth.models import User +from django.core.management import call_command from django.urls import reverse from django_dynamic_fixture import G from django_webtest import WebTest @@ -12,7 +17,7 @@ class TestGraph(SelectRowsMixin, CheckSignalsMixin, WebTest): action_name = "graph_queryset" _selected_rows = [0, 1] - def setUp(self): + def setUp(self) -> None: super().setUp() self.user = G(User, username="user", is_staff=True, is_active=True) @@ -33,26 +38,81 @@ def _run_action(self, steps=2): return res - def test_graph_apply(self): + def test_piegraph_configure(self) -> None: url = reverse("admin:auth_user_changelist") res = self.app.get(url, user="sax") form = res.forms["changelist-form"] form["action"] = "graph_queryset" - for i in range(0, 11): + for i in range(11): form.set("_selected_action", True, i) res = form.submit() res.forms["charts-form"]["graph_type"] = "PieChart" res.forms["charts-form"]["axes_x"] = "is_staff" - res = res.forms["charts-form"].submit("apply") + res = res.forms["charts-form"].submit() - def test_graph_post(self): + def test_piegraph_apply(self) -> None: url = reverse("admin:auth_user_changelist") res = self.app.get(url, user="sax") form = res.forms["changelist-form"] form["action"] = "graph_queryset" - for i in range(0, 11): + for i in range(11): form.set("_selected_action", True, i) res = form.submit() res.forms["charts-form"]["graph_type"] = "PieChart" res.forms["charts-form"]["axes_x"] = "is_staff" + res = res.forms["charts-form"].submit("apply") + + def test_bargraph_configure(self) -> None: + url = reverse("admin:auth_user_changelist") + res = self.app.get(url, user="sax") + form = res.forms["changelist-form"] + form["action"] = "graph_queryset" + for i in range(11): + form.set("_selected_action", True, i) + res = form.submit() + res.forms["charts-form"]["graph_type"] = "BarChart" + res.forms["charts-form"]["axes_x"] = "is_staff" res = res.forms["charts-form"].submit() + + def test_bargraph_apply(self) -> None: + url = reverse("admin:auth_user_changelist") + res = self.app.get(url, user="sax") + form = res.forms["changelist-form"] + form["action"] = "graph_queryset" + for i in range(11): + form.set("_selected_action", True, i) + res = form.submit() + res.forms["charts-form"]["graph_type"] = "BarChart" + res.forms["charts-form"]["axes_x"] = "is_staff" + res = res.forms["charts-form"].submit("apply") + + def test_bargraph_invalid(self) -> None: + url = reverse("admin:auth_user_changelist") + res = self.app.get(url, user="sax") + form = res.forms["changelist-form"] + form["action"] = "graph_queryset" + for i in range(11): + form.set("_selected_action", True, i) + res = form.submit() + res.forms["charts-form"]["graph_type"] = "BarChart" + # res.forms["charts-form"]["axes_x"] = "is_staff" + res = res.forms["charts-form"].submit("apply") + assert res.status_code == 200 + + +# +# +# def test_graph_foreignkey(django_db_setup, django_db_blocker, app, admin_user: User) -> None: +# with django_db_blocker.unblock(): +# call_command("loaddata", str(Path(__file__).parent / "demo" / "fixtures" / "demoproject.json")) +# url = reverse("admin:demo_demomodel_changelist") +# res = app.get(url, user=admin_user) +# form = res.forms["changelist-form"] +# form["action"] = "graph_queryset" +# for i in range(3): +# form.set("_selected_action", True, i) +# res = form.submit() +# res.forms["charts-form"]["graph_type"] = "PieChart" +# res.forms["charts-form"]["axes_x"] = "logic" +# res = res.forms["charts-form"].submit("apply") +# res.showbrowser() diff --git a/tests/test_helpers.py b/tests/test_helpers.py new file mode 100644 index 00000000..5c827057 --- /dev/null +++ b/tests/test_helpers.py @@ -0,0 +1,28 @@ +from pathlib import Path + +import pytest +from django.contrib.auth.models import User +from django.urls.base import reverse +from django_webtest import DjangoTestApp +from webtest import Upload + + +def test_import_fixture_by_content(app: DjangoTestApp, admin_user: User) -> None: + fixtures = Path(__file__).parent / "demo" / "fixtures" / "demoproject.json" + url = reverse("admin:demo_demomodel_changelist") + res = app.get(url, user=admin_user) + res = res.click("Import Fixture") + res.forms["import-form"]["fixture_content"] = fixtures.read_text() + res = res.forms["import-form"].submit() + assert "3 objects imported" in res.text + + +@pytest.mark.xfail(raises=AssertionError) +def test_import_fixture_by_file(app: DjangoTestApp, admin_user: User) -> None: + fixtures = Path(__file__).parent / "demo" / "fixtures" / "demoproject.json" + url = reverse("admin:demo_demomodel_changelist") + res = app.get(url, user=admin_user) + res = res.click("Import Fixture") + res.forms["import-form"]["fixture_file"] = Upload(str(fixtures)) + res = res.forms["import-form"].submit().follow() + assert "3 objects imported" in res.text diff --git a/tests/test_mass_update.py b/tests/test_mass_update.py index e55133eb..0287d74f 100644 --- a/tests/test_mass_update.py +++ b/tests/test_mass_update.py @@ -1,9 +1,15 @@ -# from adminactions.signals import adminaction_requested, adminaction_start, adminaction_end +from __future__ import annotations + from pathlib import Path from unittest import skipIf from unittest.mock import patch -from demo.models import DemoModel, DemoModelAdmin, DemoModelMassUpdateForm, TestMassUpdateForm +from demo.models import ( + DemoModel, + DemoModelAdmin, + DemoModelMassUpdateForm, + TestMassUpdateForm, +) from django.conf import settings from django.contrib.auth.models import User from django.db.models import fields @@ -24,12 +30,12 @@ ] -def test_operationmanager_get(): +def test_operationmanager_get() -> None: assert OPERATIONS[fields.IntegerField] == OPERATIONS[fields.BigIntegerField] assert OPERATIONS[fields.BooleanField] == OPERATIONS[fields.NullBooleanField] -def test_operationmanager_get_for_field(): +def test_operationmanager_get_for_field() -> None: assert list(OPERATIONS[fields.CharField].keys()) == [ "set", "set null", @@ -58,7 +64,7 @@ class MassUpdateTest(SelectRowsMixin, CheckSignalsMixin, WebTestMixin, TestCase) action_name = "mass_update" sender_model = DemoModel - def setUp(self): + def setUp(self) -> None: super().setUp() self._url = reverse("admin:demo_demomodel_changelist") self.user = G(User, username="user", is_staff=True, is_active=True) @@ -67,7 +73,7 @@ def _run_action(self, steps=2, **kwargs): selected_rows = kwargs.pop("selected_rows", self._selected_rows) with user_grant_permission( self.user, - ["demo.change_demomodel", "demo.adminactions_massupdate_demomodel"], + ["demo.change_demomodel", "demo.adminactions_massupdate_demomodel", "demo.view_demomodel",], ): res = self.app.get("/", user="user") res = res.click("Demo models") @@ -87,7 +93,7 @@ def _run_action(self, steps=2, **kwargs): res = res.forms["mass-update-form"].submit("apply") return res - def test_no_permission(self): + def test_no_permission(self) -> None: with user_grant_permission(self.user, ["demo.change_demomodel"]): res = self.app.get("/", user="user") res = res.click("Demo models") @@ -97,11 +103,11 @@ def test_no_permission(self): res = form.submit().follow() assert "Sorry you do not have rights to execute this action" in str(res.body) - def test_custom_modeladmin_form(self): + def test_custom_modeladmin_form(self) -> None: DemoModelAdmin.mass_update_form = DemoModelMassUpdateForm with user_grant_permission( self.user, - ["demo.change_demomodel", "demo.adminactions_massupdate_demomodel"], + ["demo.change_demomodel", "demo.adminactions_massupdate_demomodel", "demo.view_demomodel",], ): res = self.app.get("/", user="user") res = res.click("Demo models") @@ -112,7 +118,7 @@ def test_custom_modeladmin_form(self): assert isinstance(res.context["adminform"].form, DemoModelMassUpdateForm) - def test_custom_form(self): + def test_custom_form(self) -> None: with override_settings(AA_MASSUPDATE_FORM="demo.models.TestMassUpdateForm"): config.AA_MASSUPDATE_FORM = settings.AA_MASSUPDATE_FORM with user_grant_permission( @@ -129,80 +135,80 @@ def test_custom_form(self): config.AA_MASSUPDATE_FORM = "adminactions.mass_update.MassUpdateForm" assert isinstance(res.context["adminform"].form, TestMassUpdateForm) - def test_validate_on(self): - self._run_action(**{"_validate": 1}) + def test_validate_on(self) -> None: + self._run_action(_validate=1) assert DemoModel.objects.filter(char="CCCCC").exists() assert not DemoModel.objects.filter(char="ccccc").exists() - def test_validate_off(self): - res = self._run_action(**{"_validate": 0}) + def test_validate_off(self) -> None: + res = self._run_action(_validate=0) assert res.status_code == 200 form = res.context["adminform"].form assert form.errors["__all__"] == ["Cannot use operators without 'validate'"] - def test_clean_on(self): - self._run_action(**{"_clean": 1}) + def test_clean_on(self) -> None: + self._run_action(_clean=1) assert DemoModel.objects.filter(char="CCCCC").exists() assert not DemoModel.objects.filter(char="ccccc").exists() - def test_messages(self): + def test_messages(self) -> None: with user_grant_permission( self.user, ["demo.change_demomodel", "demo.adminactions_massupdate_demomodel"], ): - res = self._run_action(**{"_clean": 1}) + res = self._run_action(_clean=1) res = res.follow() messages = [m.message for m in list(res.context["messages"])] - self.assertTrue(messages) - self.assertEqual("Updated 2 records", messages[0]) + assert messages + assert messages[0] == "Updated 2 records" res = self._run_action(selected_rows=[1]).follow() messages = [m.message for m in list(res.context["messages"])] - self.assertTrue(messages) - self.assertEqual("Updated 1 records", messages[0]) + assert messages + assert messages[0] == "Updated 1 records" @skipIf(not celery_present, "Celery not installed") - def test_async_qs(self): + def test_async_qs(self) -> None: # Create handler - res = self._run_action(**{"_async": 1, "_validate": 0, "chk_id_char": False}) - assert res.status_code == 302 + res = self._run_action(_async=1, _validate=0, chk_id_char=False) + assert res.status_code == 302, res.showbrowser() assert DemoModel.objects.filter(choices=1).exists() @patch("adminactions.mass_update.adminaction_end.send") @patch("adminactions.mass_update.adminaction_start.send") @patch("adminactions.mass_update.adminaction_requested.send") @skipIf(not celery_present, "Celery not installed") - def test_async_single(self, req, start, end): - res = self._run_action(**{"_async": 1, "_validate": 1}) - assert res.status_code == 302 + def test_async_single(self, req, start, end) -> None: + res = self._run_action(_async=1, _validate=1) + assert res.status_code == 302, res.showbrowser() assert req.called assert start.called assert end.called assert DemoModel.objects.filter(char="CCCCC").exists() assert not DemoModel.objects.filter(char="ccccc").exists() - def test_file_field(self): + def test_file_field(self) -> None: self._run_action( - **{ - "_validate": 1, - "select_across": 1, - "chk_id_image": True, - "image": Upload(str(Path(__file__).parent / "test.jpeg")), - } + _validate=1, select_across=1, chk_id_image=True, image=Upload(str(Path(__file__).parent / "test.jpeg")) ) obj1 = DemoModel.objects.get(pk=1) obj2 = DemoModel.objects.get(pk=2) assert obj1.image.read() == obj2.image.read() - def test_file_field_prevent_async(self): + + def test_file_field_prevent_async(self) -> None: res = self._run_action( - **{ - "_async": 1, - "select_across": 1, - "chk_id_image": True, - "image": Upload(str(Path(__file__).parent / "test.jpeg")), - } + _async=1, select_across=1, chk_id_image=True, image=Upload(str(Path(__file__).parent / "test.jpeg")) ) assert res.status_code == 200 + + + def test_m2m_sync(self) -> None: + self._run_action(_async=0, select_across=1, chk_id_m2m=True, m2m=[1]) + assert DemoModel.objects.filter(m2m__id=1).exists() + + def test_m2m_async(self) -> None: + self._run_action(_async=1, select_across=1, chk_id_m2m=True, m2m=[1]) + assert DemoModel.objects.filter(m2m__id=1).exists() diff --git a/tests/test_merge.py b/tests/test_merge.py index e92bdfe9..aa3c9312 100644 --- a/tests/test_merge.py +++ b/tests/test_merge.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os from demo.models import DemoModel, DemoOneToOne, UserDetail @@ -22,58 +24,58 @@ def get_profile(user): class MergeTestApi(BaseTestCaseMixin, TestCase): fixtures = ["adminactions.json", "demoproject.json"] - def setUp(self): + def setUp(self) -> None: super().setUp() self.master_pk = 2 self.other_pk = 3 - def tearDown(self): + def tearDown(self) -> None: super().tearDown() - def test_merge_success_no_commit(self): + def test_merge_success_no_commit(self) -> None: master = User.objects.get(pk=self.master_pk) other = User.objects.get(pk=self.other_pk) result = merge(master, other) - self.assertTrue(User.objects.filter(pk=master.pk).exists()) - self.assertTrue(User.objects.filter(pk=other.pk).exists()) + assert User.objects.filter(pk=master.pk).exists() + assert User.objects.filter(pk=other.pk).exists() - self.assertEqual(result.pk, master.pk) - self.assertEqual(result.first_name, master.first_name) - self.assertEqual(result.last_name, master.last_name) - self.assertEqual(result.password, master.password) + assert result.pk == master.pk + assert result.first_name == master.first_name + assert result.last_name == master.last_name + assert result.password == master.password - def test_merge_success_fields_no_commit(self): + def test_merge_success_fields_no_commit(self) -> None: master = User.objects.get(pk=self.master_pk) other = User.objects.get(pk=self.other_pk) result = merge(master, other, ["password", "last_login"]) master = User.objects.get(pk=master.pk) - self.assertTrue(User.objects.filter(pk=master.pk).exists()) - self.assertTrue(User.objects.filter(pk=other.pk).exists()) + assert User.objects.filter(pk=master.pk).exists() + assert User.objects.filter(pk=other.pk).exists() - self.assertNotEqual(result.last_login, master.last_login) - self.assertEqual(result.last_login, other.last_login) - self.assertEqual(result.password, other.password) + assert result.last_login != master.last_login + assert result.last_login == other.last_login + assert result.password == other.password - self.assertNotEqual(result.last_name, other.last_name) + assert result.last_name != other.last_name - def test_merge_success_commit(self): + def test_merge_success_commit(self) -> None: old_master = User.objects.get(pk=self.master_pk) other = User.objects.get(pk=self.other_pk) result = merge(old_master, other, commit=True) master = User.objects.get(pk=result.pk) # reload - self.assertTrue(User.objects.filter(pk=master.pk).exists()) - self.assertFalse(User.objects.filter(pk=other.pk).exists()) + assert User.objects.filter(pk=master.pk).exists() + assert not User.objects.filter(pk=other.pk).exists() - self.assertEqual(result.pk, master.pk) - self.assertEqual(master.first_name, old_master.first_name) - self.assertEqual(master.last_name, old_master.last_name) - self.assertEqual(master.password, old_master.password) + assert result.pk == master.pk + assert master.first_name == old_master.first_name + assert master.last_name == old_master.last_name + assert master.password == old_master.password - def test_merge_success_m2m(self): + def test_merge_success_m2m(self) -> None: master = User.objects.get(pk=self.master_pk) other = User.objects.get(pk=self.other_pk) group = Group.objects.get_or_create(name="G1")[0] @@ -84,7 +86,7 @@ def test_merge_success_m2m(self): master = User.objects.get(pk=result.pk) # reload self.assertSequenceEqual(master.groups.all(), [group]) - def test_merge_success_m2m_all(self): + def test_merge_success_m2m_all(self) -> None: master = User.objects.get(pk=self.master_pk) other = User.objects.get(pk=self.other_pk) group = Group.objects.get_or_create(name="G1")[0] @@ -98,7 +100,7 @@ def test_merge_success_m2m_all(self): self.assertSequenceEqual(master.groups.all(), [group]) self.assertSequenceEqual(master.user_permissions.all(), [perm]) - def test_merge_success_related_all(self): + def test_merge_success_related_all(self) -> None: master = User.objects.get(pk=self.master_pk) other = User.objects.get(pk=self.other_pk) entry = other.logentry_set.get_or_create(object_repr="test", action_flag=1)[0] @@ -107,9 +109,9 @@ def test_merge_success_related_all(self): master = User.objects.get(pk=result.pk) # reload self.assertSequenceEqual(master.logentry_set.all(), [entry]) - self.assertTrue(LogEntry.objects.filter(pk=entry.pk).exists()) + assert LogEntry.objects.filter(pk=entry.pk).exists() - def test_merge_one_to_one_move_single(self): + def test_merge_one_to_one_move_single(self) -> None: master = DemoModel.objects.get(pk=1) other = DemoModel.objects.get(pk=2) related_one = DemoOneToOne(demo=other) @@ -118,12 +120,12 @@ def test_merge_one_to_one_move_single(self): result = merge(master, other, commit=True, related=ALL_FIELDS) master = DemoModel.objects.get(pk=result.pk) # reload - self.assertEqual(master.onetoone, related_one) - self.assertTrue(DemoOneToOne.objects.filter(pk=related_one.pk).exists()) - self.assertEqual(os.path.basename(master.image.file.name), "second.png") + assert master.onetoone == related_one + assert DemoOneToOne.objects.filter(pk=related_one.pk).exists() + assert os.path.basename(master.image.file.name) == "second.png" # @skipIf(not hasattr(settings, 'AUTH_PROFILE_MODULE'), "") - def test_merge_one_to_one_field(self): + def test_merge_one_to_one_field(self) -> None: master = User.objects.get(pk=self.master_pk) other = User.objects.get(pk=self.other_pk) profile = get_profile(other) @@ -134,11 +136,11 @@ def test_merge_one_to_one_field(self): master = User.objects.get(pk=result.pk) # reload self.assertSequenceEqual(master.logentry_set.all(), [entry]) - self.assertTrue(LogEntry.objects.filter(pk=entry.pk).exists()) - self.assertEqual(get_profile(result), profile) + assert LogEntry.objects.filter(pk=entry.pk).exists() + assert get_profile(result) == profile # self.assertEqual(master.get_profile(), profile) - def test_merge_ignore_related(self): + def test_merge_ignore_related(self) -> None: master = User.objects.get(pk=self.master_pk) other = User.objects.get(pk=self.other_pk) entry = other.logentry_set.get_or_create(object_repr="test", action_flag=1)[0] @@ -146,10 +148,10 @@ def test_merge_ignore_related(self): master = User.objects.get(pk=result.pk) # reload self.assertSequenceEqual(master.logentry_set.all(), []) - self.assertFalse(User.objects.filter(pk=other.pk).exists()) - self.assertFalse(LogEntry.objects.filter(pk=entry.pk).exists()) + assert not User.objects.filter(pk=other.pk).exists() + assert not LogEntry.objects.filter(pk=entry.pk).exists() - def test_merge_image(self): + def test_merge_image(self) -> None: master = DemoModel.objects.get(pk=3) other = DemoModel.objects.get(pk=1) img1 = other.image @@ -167,9 +169,9 @@ def test_merge_image(self): ) master = DemoModel.objects.get(pk=result.pk) # reload - self.assertFalse(DemoModel.objects.filter(pk=other.pk).exists()) - self.assertEqual(master.image, img1) - self.assertEqual(master.subclassed_image, img2) + assert not DemoModel.objects.filter(pk=other.pk).exists() + assert master.image == img1 + assert master.subclassed_image == img2 class TestMergeAction(SelectRowsMixin, WebTestMixin, TestCase): @@ -180,7 +182,7 @@ class TestMergeAction(SelectRowsMixin, WebTestMixin, TestCase): action_name = "merge" _selected_rows = [1, 2] - def setUp(self): + def setUp(self) -> None: super().setUp() self.url = reverse("admin:auth_user_changelist") self.user = G(User, username="user", is_staff=True, is_active=True) @@ -212,7 +214,7 @@ def _run_action(self, steps=3, page_start=None): res = res.forms["merge-form"].submit("apply") return res - def test_no_permission(self): + def test_no_permission(self) -> None: with user_grant_permission(self.user, ["auth.change_user"]): res = self.app.get("/", user="user") res = res.click("Users") @@ -223,7 +225,7 @@ def test_no_permission(self): assert "Sorry you do not have rights to execute this action" in str(res.body) # noinspection PyTypeChecker - def test_success(self): + def test_success(self) -> None: res = self._run_action(1) preserved = User.objects.get(pk=self._selected_values[0]) removed = User.objects.get(pk=self._selected_values[1]) @@ -232,14 +234,14 @@ def test_success(self): self._run_action([2, 3], res) - self.assertFalse(User.objects.filter(pk=removed.pk).exists()) - self.assertTrue(User.objects.filter(pk=preserved.pk).exists()) + assert not User.objects.filter(pk=removed.pk).exists() + assert User.objects.filter(pk=preserved.pk).exists() preserved_after = User.objects.get(pk=self._selected_values[0]) - self.assertEqual(preserved_after.email, removed.email) - self.assertFalse(LogEntry.objects.filter(pk=removed.pk).exists()) + assert preserved_after.email == removed.email + assert not LogEntry.objects.filter(pk=removed.pk).exists() - def test_error_if_too_many_records(self): + def test_error_if_too_many_records(self) -> None: with user_grant_permission(self.user, ["auth.change_user", "auth.adminactions_merge_user"]): res = self.app.get("/", user="user") res = res.click("Users") @@ -249,7 +251,7 @@ def test_error_if_too_many_records(self): res = form.submit().follow() self.assertContains(res, "Please select exactly 2 records") - def test_swap(self): + def test_swap(self) -> None: with user_grant_permission(self.user, ["auth.change_user", "auth.adminactions_merge_user"]): # removed = User.objects.get(pk=self._selected_rows[0]) # preserved = User.objects.get(pk=self._selected_rows[1]) @@ -279,13 +281,13 @@ def test_swap(self): res = res.forms["merge-form"].submit("apply") preserved_after = User.objects.get(pk=self._selected_values[1]) - self.assertFalse(User.objects.filter(pk=removed.pk).exists()) - self.assertTrue(User.objects.filter(pk=preserved.pk).exists()) + assert not User.objects.filter(pk=removed.pk).exists() + assert User.objects.filter(pk=preserved.pk).exists() - self.assertEqual(preserved_after.email, removed.email) - self.assertFalse(LogEntry.objects.filter(pk=removed.pk).exists()) + assert preserved_after.email == removed.email + assert not LogEntry.objects.filter(pk=removed.pk).exists() - def test_merge_move_detail(self): + def test_merge_move_detail(self) -> None: from adminactions.merge import MergeForm with user_grant_permission(self.user, ["auth.change_user", "auth.adminactions_merge_user"]): @@ -318,10 +320,10 @@ def test_merge_move_detail(self): res = res.forms["merge-form"].submit("apply") preserved_after = User.objects.get(pk=self._selected_values[1]) - self.assertEqual(preserved_after.userdetail_set.count(), 2) - self.assertFalse(User.objects.filter(pk=removed.pk).exists()) + assert preserved_after.userdetail_set.count() == 2 + assert not User.objects.filter(pk=removed.pk).exists() - def test_merge_delete_detail(self): + def test_merge_delete_detail(self) -> None: from adminactions.merge import MergeForm with user_grant_permission(self.user, ["auth.change_user", "auth.adminactions_merge_user"]): @@ -354,8 +356,8 @@ def test_merge_delete_detail(self): res = res.forms["merge-form"].submit("apply") preserved_after = User.objects.get(pk=self._selected_values[1]) - self.assertEqual(preserved_after.userdetail_set.count(), 1) - self.assertFalse(User.objects.filter(pk=removed.pk).exists()) + assert preserved_after.userdetail_set.count() == 1 + assert not User.objects.filter(pk=removed.pk).exists() class TestMergeImageAction(SelectRowsMixin, WebTestMixin, TestCase): @@ -366,7 +368,7 @@ class TestMergeImageAction(SelectRowsMixin, WebTestMixin, TestCase): action_name = "merge" _selected_rows = [0, 2] - def setUp(self): + def setUp(self) -> None: super().setUp() self.url = reverse("admin:demo_demomodel_changelist") self.user = G(User, username="user", is_staff=True, is_active=True) @@ -398,7 +400,7 @@ def _run_action(self, steps=3, page_start=None): return res # noinspection PyTypeChecker - def test_success(self): + def test_success(self) -> None: res = self._run_action(1) preserved = DemoModel.objects.get(pk=self._selected_values[0]) removed = DemoModel.objects.get(pk=self._selected_values[1]) @@ -413,8 +415,8 @@ def test_success(self): self._run_action([2, 3], res) - self.assertFalse(DemoModel.objects.filter(pk=removed.pk).exists()) - self.assertTrue(DemoModel.objects.filter(pk=preserved.pk).exists()) + assert not DemoModel.objects.filter(pk=removed.pk).exists() + assert DemoModel.objects.filter(pk=preserved.pk).exists() preserved_after = DemoModel.objects.get(pk=preserved.pk) diff --git a/tests/test_permissions.py b/tests/test_permissions.py index 36da5c7b..45822fd5 100644 --- a/tests/test_permissions.py +++ b/tests/test_permissions.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import logging import pytest @@ -20,8 +22,8 @@ "mass_update", ], ) -@pytest.mark.django_db() -def test_permission_needed(app, admin, demomodels, action): +@pytest.mark.django_db +def test_permission_needed(app, admin, demomodels, action) -> None: permission_mapping = { "export_as_csv": "adminactions_export", "export_as_fixture": "adminactions_export", @@ -31,7 +33,7 @@ def test_permission_needed(app, admin, demomodels, action): "merge": "adminactions_merge", "graph_queryset": "adminactions_chart", } - perm = "demo.{}_demomodel".format(permission_mapping[action]) + perm = f"demo.{permission_mapping[action]}_demomodel" url = reverse("admin:demo_demomodel_changelist") pks = [demomodels[0].pk, demomodels[1].pk] with user_grant_permission(admin, ["demo.change_demomodel"]): @@ -44,9 +46,7 @@ def test_permission_needed(app, admin, demomodels, action): ) assert res.status_code == 302 res = res.follow() - assert "Sorry you do not have rights to execute this action" in [ - str(m) for m in res.context["messages"] - ] + assert "Sorry you do not have rights to execute this action" in [str(m) for m in res.context["messages"]] with user_grant_permission(admin, [perm]): res = app.post( @@ -59,9 +59,9 @@ def test_permission_needed(app, admin, demomodels, action): assert res.status_code == 200 -@pytest.mark.django_db() -def test_permissions(admin): +@pytest.mark.django_db +def test_permissions(admin) -> None: assert Permission.objects.filter(codename__startswith="adminactions").count() == 70 with user_grant_permission(admin, ["demo.adminactions_export_demomodel"]): - assert admin.get_all_permissions() == set(["demo.adminactions_export_demomodel"]) + assert admin.get_all_permissions() == {"demo.adminactions_export_demomodel"} diff --git a/tests/test_templatetags.py b/tests/test_templatetags.py index 75f4bbe3..a80b7485 100644 --- a/tests/test_templatetags.py +++ b/tests/test_templatetags.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pytest from adminactions.templatetags.massupdate import fields_values, link_fields_values @@ -12,11 +14,11 @@ ], ids=("list", "str", "int"), ) -def test_link_fields_values(data): +def test_link_fields_values(data) -> None: assert link_fields_values(data, "field1") -def test_fields_values(): +def test_fields_values() -> None: data = { "name1": ["value1.1", "value1.2"], "name2": ["value2.1", "value2.2"], diff --git a/tests/test_transaction.py b/tests/test_transaction.py index aa8b7a1d..78a38a2b 100644 --- a/tests/test_transaction.py +++ b/tests/test_transaction.py @@ -1,28 +1,34 @@ -import mock +from __future__ import annotations + +from typing import NoReturn +from unittest import mock + import pytest from django.contrib.auth.models import Group, User from django.db import IntegrityError from django.db.transaction import atomic from django.test import TransactionTestCase +from django.urls.base import reverse from django_dynamic_fixture import G from adminactions import compat from adminactions.api import merge +from adminactions.compat import nocommit from adminactions.exceptions import ActionInterrupted from adminactions.signals import adminaction_end pytestmarker = pytest.mark.skip -@pytest.mark.django_db() -def test_nocommit(): - with compat.nocommit(): +@pytest.mark.django_db +def test_nocommit() -> None: + with nocommit(): G(Group, name="name") assert not Group.objects.filter(name="name").exists() -@pytest.mark.django_db() -def test_transaction_merge(users): +@pytest.mark.django_db +def test_transaction_merge(users) -> None: master, other = users with atomic(): with mock.patch("django.contrib.auth.models.User.delete", side_effect=IntegrityError): @@ -35,15 +41,15 @@ def test_transaction_merge(users): assert master.first_name != other.first_name -@pytest.mark.django_db() -def test_transaction_mass_update(app, users, administrator): +@pytest.mark.django_db +def test_transaction_mass_update(app, users, administrator) -> None: assert User.objects.filter(is_staff=True).count() == 1 # sanity check - def _handler(*args, **kwargs): - raise ActionInterrupted() + def _handler(*args, **kwargs) -> NoReturn: + raise ActionInterrupted with atomic(): - res = app.get("/admin/", user=administrator.username) + res = app.get(reverse("admin:index"), user=administrator.username) res = res.click("Users") form = res.forms["changelist-form"] form["action"] = "mass_update" @@ -69,5 +75,5 @@ def _handler(*args, **kwargs): class TestIsLibero(TransactionTestCase): - def test_true(self): - self.assertTrue(True) + def test_true(self) -> None: + assert True diff --git a/tests/test_utils.py b/tests/test_utils.py index b3322f7f..9db0503f 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,9 +1,11 @@ +from __future__ import annotations + import pytest from adminactions.utils import get_field_by_name, get_verbose_name -def test_get_verbose_name(): +def test_get_verbose_name() -> None: from django.contrib.auth.models import Permission, User user = User() @@ -27,7 +29,7 @@ def test_get_verbose_name(): get_verbose_name(p, None) -def test_flatten(): +def test_flatten() -> None: from adminactions.utils import flatten assert flatten([[[1, 2, 3], (42, None)], [4, 5], [6], 7, (8, 9, 10)]) == [ diff --git a/tests/test_version.py b/tests/test_version.py new file mode 100644 index 00000000..e580f9d9 --- /dev/null +++ b/tests/test_version.py @@ -0,0 +1,7 @@ +from __future__ import annotations + +import adminactions + + +def test_version() -> None: + assert adminactions.__version__ is not None diff --git a/tests/test_views.py b/tests/test_views.py index 2aeffb74..cde23929 100644 --- a/tests/test_views.py +++ b/tests/test_views.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import datetime import pytest @@ -6,15 +8,15 @@ from django.utils.encoding import smart_str -@pytest.mark.django_db() -def test_format_date(app): +@pytest.mark.django_db +def test_format_date(app) -> None: d = datetime.datetime.now() url = reverse("adminactions.format_date") fmt = "d-m-Y" - res = app.get("{}?fmt={}".format(url, fmt)) + res = app.get(f"{url}?fmt={fmt}") assert smart_str(res.body) == dateformat.format(d, fmt) fmt = "d mm Y" - res = app.get("{}?fmt={}".format(url, fmt)) + res = app.get(f"{url}?fmt={fmt}") assert smart_str(res.body) == dateformat.format(d, fmt) diff --git a/tests/utils.py b/tests/utils.py index ab0015ef..3fc2e220 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -1,6 +1,9 @@ +from __future__ import annotations + import os import string from random import choice, randrange, shuffle +from typing import NoReturn from django.conf import global_settings from django.contrib import admin @@ -13,11 +16,15 @@ from django_dynamic_fixture.fixture_algorithms.random_fixture import RandomDataFixture from adminactions.exceptions import ActionInterrupted -from adminactions.signals import adminaction_end, adminaction_requested, adminaction_start +from adminactions.signals import ( + adminaction_end, + adminaction_requested, + adminaction_start, +) class admin_register: - def __init__(self, model, model_admin=None, unregister=False): + def __init__(self, model, model_admin=None, unregister=False) -> None: self.model = model self.model_admin = model_admin self.unregister = unregister @@ -36,8 +43,7 @@ def __exit__(self, *exc_info): def start(self): """Activate a patch, returning any created mock.""" - result = self.__enter__() - return result + return self.__enter__() def stop(self): """Stop an active patch.""" @@ -63,7 +69,8 @@ def get_group(name=None, permissions=None): try: app_label, codename = permission_name.split(".") except ValueError: - raise ValueError("Invalid permission name `{0}`".format(permission_name)) + msg = f"Invalid permission name `{permission_name}`" + raise ValueError(msg) __, model_name = codename.rsplit("_", 1) ct = ContentType.objects.get(app_label__iexact=app_label, model__iexact=model_name) permission = Permission.objects.get(content_type=ct, codename=codename) @@ -72,7 +79,7 @@ def get_group(name=None, permissions=None): class user_grant_permission: - def __init__(self, user, permissions=None): + def __init__(self, user, permissions=None) -> None: self.user = user self.permissions = permissions self.group = None @@ -92,8 +99,7 @@ def __exit__(self, *exc_info): def start(self): """Activate a patch, returning any created mock.""" - result = self.__enter__() - return result + return self.__enter__() def stop(self): """Stop an active patch.""" @@ -105,7 +111,7 @@ class SelectRowsMixin: _selected_values = [] csrf_checks = False - def _select_rows(self, form, selected_rows=None): + def _select_rows(self, form, selected_rows=None) -> None: if selected_rows is None: selected_rows = self._selected_rows @@ -120,11 +126,11 @@ def _select_rows(self, form, selected_rows=None): class CheckSignalsMixin: MESSAGE = "Action Interrupted Test" - def test_signal_sent(self): + def test_signal_sent(self) -> None: def handler_factory(name): - def myhandler(sender, action, request, queryset, **kwargs): + def myhandler(sender, action, request, queryset, **kwargs) -> None: handler_factory.invoked[name] = True - self.assertEqual(action, self.action_name) + assert action == self.action_name self.assertSequenceEqual( queryset.order_by("id").values_list("id", flat=True), sorted(self._selected_values), @@ -145,21 +151,21 @@ def myhandler(sender, action, request, queryset, **kwargs): adminaction_end.connect(m3, sender=self.sender_model) self._run_action() - self.assertIn("adminaction_requested", handler_factory.invoked) - self.assertIn("adminaction_start", handler_factory.invoked) - self.assertIn("adminaction_end", handler_factory.invoked) + assert "adminaction_requested" in handler_factory.invoked + assert "adminaction_start" in handler_factory.invoked + assert "adminaction_end" in handler_factory.invoked finally: adminaction_requested.disconnect(m1, sender=self.sender_model) adminaction_start.disconnect(m2, sender=self.sender_model) adminaction_end.disconnect(m3, sender=self.sender_model) - def test_signal_requested(self): + def test_signal_requested(self) -> None: # test if adminaction_requested Signal can stop the action - def myhandler(sender, action, request, queryset, **kwargs): + def myhandler(sender, action, request, queryset, **kwargs) -> NoReturn: myhandler.invoked = True - self.assertEqual(action, self.action_name) + assert action == self.action_name self.assertSequenceEqual( queryset.order_by("id").values_list("id", flat=True), sorted(self._selected_values), @@ -171,17 +177,17 @@ def myhandler(sender, action, request, queryset, **kwargs): try: adminaction_requested.connect(myhandler, sender=self.sender_model) self._run_action(1) - self.assertTrue(myhandler.invoked) - self.assertIn(self.MESSAGE, self.app.cookies["messages"]) + assert myhandler.invoked + assert self.MESSAGE in self.app.cookies["messages"] finally: adminaction_requested.disconnect(myhandler, sender=self.sender_model) - def test_signal_start(self): + def test_signal_start(self) -> None: # test if adminaction_start Signal can stop the action - def myhandler(sender, action, request, queryset, **kwargs): + def myhandler(sender, action, request, queryset, **kwargs) -> NoReturn: myhandler.invoked = True - self.assertEqual(action, self.action_name) + assert action == self.action_name self.assertSequenceEqual( queryset.order_by("id").values_list("id", flat=True), sorted(self._selected_values), @@ -191,17 +197,17 @@ def myhandler(sender, action, request, queryset, **kwargs): try: adminaction_start.connect(myhandler, sender=self.sender_model) self._run_action(2) - self.assertTrue(myhandler.invoked) - self.assertIn(self.MESSAGE, self.app.cookies["messages"]) + assert myhandler.invoked + assert self.MESSAGE in self.app.cookies["messages"] finally: adminaction_start.disconnect(myhandler, sender=self.sender_model) - def test_signal_end(self): + def test_signal_end(self) -> None: # test if adminaction_start Signal can stop the action - def myhandler(sender, action, request, queryset, **kwargs): + def myhandler(sender, action, request, queryset, **kwargs) -> None: myhandler.invoked = True - self.assertEqual(action, self.action_name) + assert action == self.action_name self.assertSequenceEqual( queryset.order_by("id").values_list("id", flat=True), sorted(self._selected_values), @@ -211,7 +217,7 @@ def myhandler(sender, action, request, queryset, **kwargs): try: adminaction_end.connect(myhandler, sender=self.sender_model) self._run_action(2) - self.assertTrue(myhandler.invoked) + assert myhandler.invoked finally: adminaction_end.disconnect(myhandler, sender=self.sender_model) @@ -228,14 +234,12 @@ def ipaddress(not_valid=None): shuffle(class_a) first = class_a.pop() - return ".".join( - [ - str(first), - str(randrange(1, 256)), - str(randrange(1, 256)), - str(randrange(1, 256)), - ] - ) + return ".".join([ + str(first), + str(randrange(1, 256)), + str(randrange(1, 256)), + str(randrange(1, 256)), + ]) class DataFixtureClass(RandomDataFixture): # it can inherit of SequentialDataFixture, RandomDataFixture etc. @@ -278,16 +282,16 @@ class BaseTestCaseMixin: "adminactions.json", ] - def setUp(self): + def setUp(self) -> None: super().setUp() self.sett = self.settings(**SETTINGS) self.sett.enable() self.login() - def tearDown(self): + def tearDown(self) -> None: self.sett.disable() - def login(self, username="user_00", password="123"): + def login(self, username="user_00", password="123") -> None: user = User.objects.get(username=username) try: self.client.force_login(user) @@ -296,7 +300,7 @@ def login(self, username="user_00", password="123"): assert logged, "Unable login with credentials" self._user = authenticate(username=username, password=password) - def add_permission(self, *perms, **kwargs): + def add_permission(self, *perms, **kwargs) -> None: """add the right permission to the user""" target = kwargs.pop("user", self._user) if hasattr(target, "_perm_cache"): diff --git a/tox.ini b/tox.ini index ed0dd7fc..80f76f30 100644 --- a/tox.ini +++ b/tox.ini @@ -1,82 +1,66 @@ [tox] -# as per https://docs.djangoproject.com/en/1.11/faq/install/#what-python-version-can-i-use-with-django -envlist = d{32,42}-py{39,310,311} -; -;skip_missing_interpreters = true -; -[pytest] -;DJANGO_SETTINGS_MODULE = demo.settings -django_find_project = false -norecursedirs = demo .tox -addopts = - -v - --doctest-modules - --tb=short - --reuse-db - --cov=adminactions - --cov-report=html - --cov-config=tests/.coveragerc - --capture=no - --doctest-glob=adminactions/*.py - --echo-version django - -doctest_optionflags = -python_files = tests/test_*.py tests/**/test_*.py -markers = - functional: mark a test as functional - selenium: selenium test - skip: skip test +requires = + tox>=4.2 + tox-uv>=1.20.2 +env_list = + lint + pkg_meta + d{51, 42, 32}-py{313, 312, 311, 310} [testenv] -passenv = - DISPLAY - CELERY_BROKER_URL - -setenv = - PYTHONDONTWRITEBYTECODE=true - CRYPTOGRAPHY_DONT_BUILD_RUST=1 - PYTHONPATH=./src:./tests - CELERY_ALWAYS_EAGER=1 - -whitelist_externals = mkdir - +description = run the tests with pytest +package = wheel +wheel_build_env = .pkg deps = - -rsrc/requirements/testing.pip - pypy: psycopg2cffi + celery d32: django==3.2.* d42: django==4.2.* - -; only for local development - dev: git+https://github.com/django/django.git - - + d51: django==5.1.* + pypy: psycopg2cffi +pass_env = + CELERY_BROKER_URL + DISPLAY +set_env = + CELERY_ALWAYS_EAGER = 1 + CRYPTOGRAPHY_DONT_BUILD_RUST = 1 + DATABASE_URL = sqlite:///adminactions.sqlite + PYTHONDONTWRITEBYTECODE = true + PYTHONPATH = ./src:./tests commands = - {posargs:py.test tests/ src --doctest-modules --create-db} + coverage erase + coverage run -m pytest --junitxml {toxworkdir}{/}junit.{envname}.xml {posargs:tests} + coverage combine + coverage report + coverage html -d {envtmpdir}{/}htmlcov +dependency_groups = dev [testenv:lint] -envdir = {toxworkdir}/d32-py39/ +description = run static analysis and style check using flake8 skip_install = true deps = - black - flake8 - isort - pre-commit - + pre-commit-uv>=4.1.1 +pass_env = + HOMEPATH + PROGRAMDATA commands = - pre-commit run --all + pre-commit run --all-files --show-diff-on-failure -[testenv:package] +[testenv:pkg_meta] +description = check that the long description is valid +skip_install = true deps = - build - twine - -setenv = - TWINE_USERNAME = {env:TWINE_TEST_USERNAME:__token__} - TWINE_PASSWORD = {env:TWINE_TEST_PASSWORD} - + check-wheel-contents>=0.6 + twine>=5.1.1 + uv>=0.5 commands = - python -c "import shutil; shutil.rmtree('dist', ignore_errors=True)" - python -m build - python -m twine check dist/* - python -m twine upload --repository-url https://test.pypi.org/legacy/ dist/* + uv build --sdist --wheel --out-dir {env_tmp_dir} . + twine check {env_tmp_dir}{/}* + check-wheel-contents --no-config {env_tmp_dir} +[testenv:type] +description = run type check on code base +deps = + mypy==1.11.2 +commands = + mypy --strict src + mypy --strict tests diff --git a/uv.lock b/uv.lock new file mode 100644 index 00000000..16b241e1 --- /dev/null +++ b/uv.lock @@ -0,0 +1,1301 @@ +version = 1 +requires-python = ">=3.9" +resolution-markers = [ + "python_full_version >= '3.13'", + "python_full_version < '3.13'", +] + +[[package]] +name = "amqp" +version = "5.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "vine" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/79/fc/ec94a357dfc6683d8c86f8b4cfa5416a4c36b28052ec8260c77aca96a443/amqp-5.3.1.tar.gz", hash = "sha256:cddc00c725449522023bad949f70fff7b48f0b1ade74d170a6f10ab044739432", size = 129013 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/26/99/fc813cd978842c26c82534010ea849eee9ab3a13ea2b74e95cb9c99e747b/amqp-5.3.1-py3-none-any.whl", hash = "sha256:43b3319e1b4e7d1251833a93d672b4af1e40f3d632d479b98661a95f117880a2", size = 50944 }, +] + +[[package]] +name = "appdirs" +version = "1.4.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/d8/05696357e0311f5b5c316d7b95f46c669dd9c15aaeecbb48c7d0aeb88c40/appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41", size = 13470 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3b/00/2344469e2084fb287c2e0b57b72910309874c3245463acd6cf5e3db69324/appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128", size = 9566 }, +] + +[[package]] +name = "async-timeout" +version = "5.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a5/ae/136395dfbfe00dfc94da3f3e136d0b13f394cba8f4841120e34226265780/async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3", size = 9274 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", size = 6233 }, +] + +[[package]] +name = "attrs" +version = "25.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/49/7c/fdf464bcc51d23881d110abd74b512a42b3d5d376a55a831b44c603ae17f/attrs-25.1.0.tar.gz", hash = "sha256:1c97078a80c814273a76b2a298a932eb681c87415c11dee0a6921de7f1b02c3e", size = 810562 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fc/30/d4986a882011f9df997a55e6becd864812ccfcd821d64aac8570ee39f719/attrs-25.1.0-py3-none-any.whl", hash = "sha256:c75a69e28a550a7e93789579c22aa26b0f5b83b75dc4e08fe092980051e1090a", size = 63152 }, +] + +[[package]] +name = "beautifulsoup4" +version = "4.13.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "soupsieve" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f0/3c/adaf39ce1fb4afdd21b611e3d530b183bb7759c9b673d60db0e347fd4439/beautifulsoup4-4.13.3.tar.gz", hash = "sha256:1bd32405dacc920b42b83ba01644747ed77456a65760e285fbc47633ceddaf8b", size = 619516 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f9/49/6abb616eb3cbab6a7cca303dc02fdf3836de2e0b834bf966a7f5271a34d8/beautifulsoup4-4.13.3-py3-none-any.whl", hash = "sha256:99045d7d3f08f91f0d656bc9b7efbae189426cd913d830294a15eefa0ea4df16", size = 186015 }, +] + +[[package]] +name = "billiard" +version = "4.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7c/58/1546c970afcd2a2428b1bfafecf2371d8951cc34b46701bea73f4280989e/billiard-4.2.1.tar.gz", hash = "sha256:12b641b0c539073fc8d3f5b8b7be998956665c4233c7c1fcd66a7e677c4fb36f", size = 155031 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/30/da/43b15f28fe5f9e027b41c539abc5469052e9d48fd75f8ff094ba2a0ae767/billiard-4.2.1-py3-none-any.whl", hash = "sha256:40b59a4ac8806ba2c2369ea98d876bc6108b051c227baffd928c644d15d8f3cb", size = 86766 }, +] + +[[package]] +name = "build" +version = "1.2.2.post1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "os_name == 'nt'" }, + { name = "importlib-metadata", marker = "python_full_version < '3.10.2'" }, + { name = "packaging" }, + { name = "pyproject-hooks" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7d/46/aeab111f8e06793e4f0e421fcad593d547fb8313b50990f31681ee2fb1ad/build-1.2.2.post1.tar.gz", hash = "sha256:b36993e92ca9375a219c99e606a122ff365a760a2d4bba0caa09bd5278b608b7", size = 46701 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/84/c2/80633736cd183ee4a62107413def345f7e6e3c01563dbca1417363cf957e/build-1.2.2.post1-py3-none-any.whl", hash = "sha256:1d61c0887fa860c01971625baae8bdd338e517b836a2f70dd1f7aa3a6b2fc5b5", size = 22950 }, +] + +[[package]] +name = "cachetools" +version = "5.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d9/74/57df1ab0ce6bc5f6fa868e08de20df8ac58f9c44330c7671ad922d2bbeae/cachetools-5.5.1.tar.gz", hash = "sha256:70f238fbba50383ef62e55c6aff6d9673175fe59f7c6782c7a0b9e38f4a9df95", size = 28044 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/4e/de4ff18bcf55857ba18d3a4bd48c8a9fde6bb0980c9d20b263f05387fd88/cachetools-5.5.1-py3-none-any.whl", hash = "sha256:b76651fdc3b24ead3c648bbdeeb940c1b04d365b38b4af66788f9ec4a81d42bb", size = 9530 }, +] + +[[package]] +name = "celery" +version = "5.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "billiard" }, + { name = "click" }, + { name = "click-didyoumean" }, + { name = "click-plugins" }, + { name = "click-repl" }, + { name = "kombu" }, + { name = "python-dateutil" }, + { name = "tzdata" }, + { name = "vine" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8a/9c/cf0bce2cc1c8971bf56629d8f180e4ca35612c7e79e6e432e785261a8be4/celery-5.4.0.tar.gz", hash = "sha256:504a19140e8d3029d5acad88330c541d4c3f64c789d85f94756762d8bca7e706", size = 1575692 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/90/c4/6a4d3772e5407622feb93dd25c86ce3c0fee746fa822a777a627d56b4f2a/celery-5.4.0-py3-none-any.whl", hash = "sha256:369631eb580cf8c51a82721ec538684994f8277637edde2dfc0dacd73ed97f64", size = 425983 }, +] + +[[package]] +name = "certifi" +version = "2025.1.31" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1c/ab/c9f1e32b7b1bf505bf26f0ef697775960db7932abeb7b516de930ba2705f/certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651", size = 167577 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/38/fc/bce832fd4fd99766c04d1ee0eead6b0ec6486fb100ae5e74c1d91292b982/certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe", size = 166393 }, +] + +[[package]] +name = "cffi" +version = "1.17.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f8/fe/4d41c2f200c4a457933dbd98d3cf4e911870877bd94d9656cc0fcb390681/cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c", size = 171804 }, + { url = "https://files.pythonhosted.org/packages/d1/b6/0b0f5ab93b0df4acc49cae758c81fe4e5ef26c3ae2e10cc69249dfd8b3ab/cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15", size = 181299 }, + { url = "https://files.pythonhosted.org/packages/34/33/e1b8a1ba29025adbdcda5fb3a36f94c03d771c1b7b12f726ff7fef2ebe36/cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655", size = 171727 }, + { url = "https://files.pythonhosted.org/packages/3d/97/50228be003bb2802627d28ec0627837ac0bf35c90cf769812056f235b2d1/cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0", size = 181400 }, + { url = "https://files.pythonhosted.org/packages/86/c5/28b2d6f799ec0bdecf44dced2ec5ed43e0eb63097b0f58c293583b406582/cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", size = 172448 }, + { url = "https://files.pythonhosted.org/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976 }, + { url = "https://files.pythonhosted.org/packages/bf/ee/f94057fa6426481d663b88637a9a10e859e492c73d0384514a17d78ee205/cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", size = 172475 }, + { url = "https://files.pythonhosted.org/packages/7c/fc/6a8cb64e5f0324877d503c854da15d76c1e50eb722e320b15345c4d0c6de/cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", size = 182009 }, + { url = "https://files.pythonhosted.org/packages/cb/b5/fd9f8b5a84010ca169ee49f4e4ad6f8c05f4e3545b72ee041dbbcb159882/cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7", size = 171820 }, + { url = "https://files.pythonhosted.org/packages/8c/52/b08750ce0bce45c143e1b5d7357ee8c55341b52bdef4b0f081af1eb248c2/cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662", size = 181290 }, +] + +[[package]] +name = "chardet" +version = "5.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/0d/f7b6ab21ec75897ed80c17d79b15951a719226b9fababf1e40ea74d69079/chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7", size = 2069618 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/38/6f/f5fbc992a329ee4e0f288c1fe0e2ad9485ed064cac731ed2fe47dcc38cbf/chardet-5.2.0-py3-none-any.whl", hash = "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970", size = 199385 }, +] + +[[package]] +name = "check-manifest" +version = "0.50" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "build" }, + { name = "setuptools" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a8/ab/7607952f2c8d34c4124309dd3ea17c256fd3420a4ade01322daf9402b0b5/check_manifest-0.50.tar.gz", hash = "sha256:d300f9f292986aa1a30424af44eb45c5644e0a810e392e62d553b24bb3393494", size = 44827 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/71/55/92207fa9b92ac2ade5593b1280f804f2590a680b7fe96775eb26074eec6b/check_manifest-0.50-py3-none-any.whl", hash = "sha256:6ab3e3aa72a008da3314b432f4c768c9647b4d6d8032f9e1a4672a572118e48c", size = 20385 }, +] + +[[package]] +name = "click" +version = "8.1.8" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188 }, +] + +[[package]] +name = "click-didyoumean" +version = "0.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/30/ce/217289b77c590ea1e7c24242d9ddd6e249e52c795ff10fac2c50062c48cb/click_didyoumean-0.3.1.tar.gz", hash = "sha256:4f82fdff0dbe64ef8ab2279bd6aa3f6a99c3b28c05aa09cbfc07c9d7fbb5a463", size = 3089 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1b/5b/974430b5ffdb7a4f1941d13d83c64a0395114503cc357c6b9ae4ce5047ed/click_didyoumean-0.3.1-py3-none-any.whl", hash = "sha256:5c4bb6007cfea5f2fd6583a2fb6701a22a41eb98957e63d0fac41c10e7c3117c", size = 3631 }, +] + +[[package]] +name = "click-plugins" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5f/1d/45434f64ed749540af821fd7e42b8e4d23ac04b1eda7c26613288d6cd8a8/click-plugins-1.1.1.tar.gz", hash = "sha256:46ab999744a9d831159c3411bb0c79346d94a444df9a3a3742e9ed63645f264b", size = 8164 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/da/824b92d9942f4e472702488857914bdd50f73021efea15b4cad9aca8ecef/click_plugins-1.1.1-py2.py3-none-any.whl", hash = "sha256:5d262006d3222f5057fd81e1623d4443e41dcda5dc815c06b442aa3c02889fc8", size = 7497 }, +] + +[[package]] +name = "click-repl" +version = "0.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "prompt-toolkit" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cb/a2/57f4ac79838cfae6912f997b4d1a64a858fb0c86d7fcaae6f7b58d267fca/click-repl-0.3.0.tar.gz", hash = "sha256:17849c23dba3d667247dc4defe1757fff98694e90fe37474f3feebb69ced26a9", size = 10449 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/52/40/9d857001228658f0d59e97ebd4c346fe73e138c6de1bce61dc568a57c7f8/click_repl-0.3.0-py3-none-any.whl", hash = "sha256:fb7e06deb8da8de86180a33a9da97ac316751c094c6899382da7feeeeb51b812", size = 10289 }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, +] + +[[package]] +name = "covdefaults" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "coverage" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/44/ee/9a6f2611f72e4c5657ae5542a510cf4164d2c673687c0ea73bb1cbd85b4d/covdefaults-2.3.0.tar.gz", hash = "sha256:4e99f679f12d792bc62e5510fa3eb59546ed47bd569e36e4fddc4081c9c3ebf7", size = 4835 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/4c/823bc951445aa97e5a1b7e337690db3abf85212c8d138e170922e7916ac8/covdefaults-2.3.0-py2.py3-none-any.whl", hash = "sha256:2832961f6ffcfe4b57c338bc3418a3526f495c26fb9c54565409c5532f7c41be", size = 5144 }, +] + +[[package]] +name = "coverage" +version = "7.6.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f7/08/7e37f82e4d1aead42a7443ff06a1e406aabf7302c4f00a546e4b320b994c/coverage-7.6.1.tar.gz", hash = "sha256:953510dfb7b12ab69d20135a0662397f077c59b1e6379a768e97c59d852ee51d", size = 798791 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/61/eb7ce5ed62bacf21beca4937a90fe32545c91a3c8a42a30c6616d48fc70d/coverage-7.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b06079abebbc0e89e6163b8e8f0e16270124c154dc6e4a47b413dd538859af16", size = 206690 }, + { url = "https://files.pythonhosted.org/packages/7d/73/041928e434442bd3afde5584bdc3f932fb4562b1597629f537387cec6f3d/coverage-7.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cf4b19715bccd7ee27b6b120e7e9dd56037b9c0681dcc1adc9ba9db3d417fa36", size = 207127 }, + { url = "https://files.pythonhosted.org/packages/c7/c8/6ca52b5147828e45ad0242388477fdb90df2c6cbb9a441701a12b3c71bc8/coverage-7.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61c0abb4c85b095a784ef23fdd4aede7a2628478e7baba7c5e3deba61070a02", size = 235654 }, + { url = "https://files.pythonhosted.org/packages/d5/da/9ac2b62557f4340270942011d6efeab9833648380109e897d48ab7c1035d/coverage-7.6.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd21f6ae3f08b41004dfb433fa895d858f3f5979e7762d052b12aef444e29afc", size = 233598 }, + { url = "https://files.pythonhosted.org/packages/53/23/9e2c114d0178abc42b6d8d5281f651a8e6519abfa0ef460a00a91f80879d/coverage-7.6.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f59d57baca39b32db42b83b2a7ba6f47ad9c394ec2076b084c3f029b7afca23", size = 234732 }, + { url = "https://files.pythonhosted.org/packages/0f/7e/a0230756fb133343a52716e8b855045f13342b70e48e8ad41d8a0d60ab98/coverage-7.6.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a1ac0ae2b8bd743b88ed0502544847c3053d7171a3cff9228af618a068ed9c34", size = 233816 }, + { url = "https://files.pythonhosted.org/packages/28/7c/3753c8b40d232b1e5eeaed798c875537cf3cb183fb5041017c1fdb7ec14e/coverage-7.6.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e6a08c0be454c3b3beb105c0596ebdc2371fab6bb90c0c0297f4e58fd7e1012c", size = 232325 }, + { url = "https://files.pythonhosted.org/packages/57/e3/818a2b2af5b7573b4b82cf3e9f137ab158c90ea750a8f053716a32f20f06/coverage-7.6.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f5796e664fe802da4f57a168c85359a8fbf3eab5e55cd4e4569fbacecc903959", size = 233418 }, + { url = "https://files.pythonhosted.org/packages/c8/fb/4532b0b0cefb3f06d201648715e03b0feb822907edab3935112b61b885e2/coverage-7.6.1-cp310-cp310-win32.whl", hash = "sha256:7bb65125fcbef8d989fa1dd0e8a060999497629ca5b0efbca209588a73356232", size = 209343 }, + { url = "https://files.pythonhosted.org/packages/5a/25/af337cc7421eca1c187cc9c315f0a755d48e755d2853715bfe8c418a45fa/coverage-7.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:3115a95daa9bdba70aea750db7b96b37259a81a709223c8448fa97727d546fe0", size = 210136 }, + { url = "https://files.pythonhosted.org/packages/ad/5f/67af7d60d7e8ce61a4e2ddcd1bd5fb787180c8d0ae0fbd073f903b3dd95d/coverage-7.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7dea0889685db8550f839fa202744652e87c60015029ce3f60e006f8c4462c93", size = 206796 }, + { url = "https://files.pythonhosted.org/packages/e1/0e/e52332389e057daa2e03be1fbfef25bb4d626b37d12ed42ae6281d0a274c/coverage-7.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed37bd3c3b063412f7620464a9ac1314d33100329f39799255fb8d3027da50d3", size = 207244 }, + { url = "https://files.pythonhosted.org/packages/aa/cd/766b45fb6e090f20f8927d9c7cb34237d41c73a939358bc881883fd3a40d/coverage-7.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d85f5e9a5f8b73e2350097c3756ef7e785f55bd71205defa0bfdaf96c31616ff", size = 239279 }, + { url = "https://files.pythonhosted.org/packages/70/6c/a9ccd6fe50ddaf13442a1e2dd519ca805cbe0f1fcd377fba6d8339b98ccb/coverage-7.6.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bc572be474cafb617672c43fe989d6e48d3c83af02ce8de73fff1c6bb3c198d", size = 236859 }, + { url = "https://files.pythonhosted.org/packages/14/6f/8351b465febb4dbc1ca9929505202db909c5a635c6fdf33e089bbc3d7d85/coverage-7.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0420b573964c760df9e9e86d1a9a622d0d27f417e1a949a8a66dd7bcee7bc6", size = 238549 }, + { url = "https://files.pythonhosted.org/packages/68/3c/289b81fa18ad72138e6d78c4c11a82b5378a312c0e467e2f6b495c260907/coverage-7.6.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1f4aa8219db826ce6be7099d559f8ec311549bfc4046f7f9fe9b5cea5c581c56", size = 237477 }, + { url = "https://files.pythonhosted.org/packages/ed/1c/aa1efa6459d822bd72c4abc0b9418cf268de3f60eeccd65dc4988553bd8d/coverage-7.6.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:fc5a77d0c516700ebad189b587de289a20a78324bc54baee03dd486f0855d234", size = 236134 }, + { url = "https://files.pythonhosted.org/packages/fb/c8/521c698f2d2796565fe9c789c2ee1ccdae610b3aa20b9b2ef980cc253640/coverage-7.6.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b48f312cca9621272ae49008c7f613337c53fadca647d6384cc129d2996d1133", size = 236910 }, + { url = "https://files.pythonhosted.org/packages/7d/30/033e663399ff17dca90d793ee8a2ea2890e7fdf085da58d82468b4220bf7/coverage-7.6.1-cp311-cp311-win32.whl", hash = "sha256:1125ca0e5fd475cbbba3bb67ae20bd2c23a98fac4e32412883f9bcbaa81c314c", size = 209348 }, + { url = "https://files.pythonhosted.org/packages/20/05/0d1ccbb52727ccdadaa3ff37e4d2dc1cd4d47f0c3df9eb58d9ec8508ca88/coverage-7.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:8ae539519c4c040c5ffd0632784e21b2f03fc1340752af711f33e5be83a9d6c6", size = 210230 }, + { url = "https://files.pythonhosted.org/packages/7e/d4/300fc921dff243cd518c7db3a4c614b7e4b2431b0d1145c1e274fd99bd70/coverage-7.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:95cae0efeb032af8458fc27d191f85d1717b1d4e49f7cb226cf526ff28179778", size = 206983 }, + { url = "https://files.pythonhosted.org/packages/e1/ab/6bf00de5327ecb8db205f9ae596885417a31535eeda6e7b99463108782e1/coverage-7.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5621a9175cf9d0b0c84c2ef2b12e9f5f5071357c4d2ea6ca1cf01814f45d2391", size = 207221 }, + { url = "https://files.pythonhosted.org/packages/92/8f/2ead05e735022d1a7f3a0a683ac7f737de14850395a826192f0288703472/coverage-7.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:260933720fdcd75340e7dbe9060655aff3af1f0c5d20f46b57f262ab6c86a5e8", size = 240342 }, + { url = "https://files.pythonhosted.org/packages/0f/ef/94043e478201ffa85b8ae2d2c79b4081e5a1b73438aafafccf3e9bafb6b5/coverage-7.6.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e2ca0ad381b91350c0ed49d52699b625aab2b44b65e1b4e02fa9df0e92ad2d", size = 237371 }, + { url = "https://files.pythonhosted.org/packages/1f/0f/c890339dd605f3ebc269543247bdd43b703cce6825b5ed42ff5f2d6122c7/coverage-7.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c44fee9975f04b33331cb8eb272827111efc8930cfd582e0320613263ca849ca", size = 239455 }, + { url = "https://files.pythonhosted.org/packages/d1/04/7fd7b39ec7372a04efb0f70c70e35857a99b6a9188b5205efb4c77d6a57a/coverage-7.6.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:877abb17e6339d96bf08e7a622d05095e72b71f8afd8a9fefc82cf30ed944163", size = 238924 }, + { url = "https://files.pythonhosted.org/packages/ed/bf/73ce346a9d32a09cf369f14d2a06651329c984e106f5992c89579d25b27e/coverage-7.6.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3e0cadcf6733c09154b461f1ca72d5416635e5e4ec4e536192180d34ec160f8a", size = 237252 }, + { url = "https://files.pythonhosted.org/packages/86/74/1dc7a20969725e917b1e07fe71a955eb34bc606b938316bcc799f228374b/coverage-7.6.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c3c02d12f837d9683e5ab2f3d9844dc57655b92c74e286c262e0fc54213c216d", size = 238897 }, + { url = "https://files.pythonhosted.org/packages/b6/e9/d9cc3deceb361c491b81005c668578b0dfa51eed02cd081620e9a62f24ec/coverage-7.6.1-cp312-cp312-win32.whl", hash = "sha256:e05882b70b87a18d937ca6768ff33cc3f72847cbc4de4491c8e73880766718e5", size = 209606 }, + { url = "https://files.pythonhosted.org/packages/47/c8/5a2e41922ea6740f77d555c4d47544acd7dc3f251fe14199c09c0f5958d3/coverage-7.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:b5d7b556859dd85f3a541db6a4e0167b86e7273e1cdc973e5b175166bb634fdb", size = 210373 }, + { url = "https://files.pythonhosted.org/packages/8c/f9/9aa4dfb751cb01c949c990d136a0f92027fbcc5781c6e921df1cb1563f20/coverage-7.6.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a4acd025ecc06185ba2b801f2de85546e0b8ac787cf9d3b06e7e2a69f925b106", size = 207007 }, + { url = "https://files.pythonhosted.org/packages/b9/67/e1413d5a8591622a46dd04ff80873b04c849268831ed5c304c16433e7e30/coverage-7.6.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a6d3adcf24b624a7b778533480e32434a39ad8fa30c315208f6d3e5542aeb6e9", size = 207269 }, + { url = "https://files.pythonhosted.org/packages/14/5b/9dec847b305e44a5634d0fb8498d135ab1d88330482b74065fcec0622224/coverage-7.6.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0c212c49b6c10e6951362f7c6df3329f04c2b1c28499563d4035d964ab8e08c", size = 239886 }, + { url = "https://files.pythonhosted.org/packages/7b/b7/35760a67c168e29f454928f51f970342d23cf75a2bb0323e0f07334c85f3/coverage-7.6.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e81d7a3e58882450ec4186ca59a3f20a5d4440f25b1cff6f0902ad890e6748a", size = 237037 }, + { url = "https://files.pythonhosted.org/packages/f7/95/d2fd31f1d638df806cae59d7daea5abf2b15b5234016a5ebb502c2f3f7ee/coverage-7.6.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78b260de9790fd81e69401c2dc8b17da47c8038176a79092a89cb2b7d945d060", size = 239038 }, + { url = "https://files.pythonhosted.org/packages/6e/bd/110689ff5752b67924efd5e2aedf5190cbbe245fc81b8dec1abaffba619d/coverage-7.6.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a78d169acd38300060b28d600344a803628c3fd585c912cacc9ea8790fe96862", size = 238690 }, + { url = "https://files.pythonhosted.org/packages/d3/a8/08d7b38e6ff8df52331c83130d0ab92d9c9a8b5462f9e99c9f051a4ae206/coverage-7.6.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2c09f4ce52cb99dd7505cd0fc8e0e37c77b87f46bc9c1eb03fe3bc9991085388", size = 236765 }, + { url = "https://files.pythonhosted.org/packages/d6/6a/9cf96839d3147d55ae713eb2d877f4d777e7dc5ba2bce227167d0118dfe8/coverage-7.6.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6878ef48d4227aace338d88c48738a4258213cd7b74fd9a3d4d7582bb1d8a155", size = 238611 }, + { url = "https://files.pythonhosted.org/packages/74/e4/7ff20d6a0b59eeaab40b3140a71e38cf52547ba21dbcf1d79c5a32bba61b/coverage-7.6.1-cp313-cp313-win32.whl", hash = "sha256:44df346d5215a8c0e360307d46ffaabe0f5d3502c8a1cefd700b34baf31d411a", size = 209671 }, + { url = "https://files.pythonhosted.org/packages/35/59/1812f08a85b57c9fdb6d0b383d779e47b6f643bc278ed682859512517e83/coverage-7.6.1-cp313-cp313-win_amd64.whl", hash = "sha256:8284cf8c0dd272a247bc154eb6c95548722dce90d098c17a883ed36e67cdb129", size = 210368 }, + { url = "https://files.pythonhosted.org/packages/9c/15/08913be1c59d7562a3e39fce20661a98c0a3f59d5754312899acc6cb8a2d/coverage-7.6.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d3296782ca4eab572a1a4eca686d8bfb00226300dcefdf43faa25b5242ab8a3e", size = 207758 }, + { url = "https://files.pythonhosted.org/packages/c4/ae/b5d58dff26cade02ada6ca612a76447acd69dccdbb3a478e9e088eb3d4b9/coverage-7.6.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:502753043567491d3ff6d08629270127e0c31d4184c4c8d98f92c26f65019962", size = 208035 }, + { url = "https://files.pythonhosted.org/packages/b8/d7/62095e355ec0613b08dfb19206ce3033a0eedb6f4a67af5ed267a8800642/coverage-7.6.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a89ecca80709d4076b95f89f308544ec8f7b4727e8a547913a35f16717856cb", size = 250839 }, + { url = "https://files.pythonhosted.org/packages/7c/1e/c2967cb7991b112ba3766df0d9c21de46b476d103e32bb401b1b2adf3380/coverage-7.6.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a318d68e92e80af8b00fa99609796fdbcdfef3629c77c6283566c6f02c6d6704", size = 246569 }, + { url = "https://files.pythonhosted.org/packages/8b/61/a7a6a55dd266007ed3b1df7a3386a0d760d014542d72f7c2c6938483b7bd/coverage-7.6.1-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13b0a73a0896988f053e4fbb7de6d93388e6dd292b0d87ee51d106f2c11b465b", size = 248927 }, + { url = "https://files.pythonhosted.org/packages/c8/fa/13a6f56d72b429f56ef612eb3bc5ce1b75b7ee12864b3bd12526ab794847/coverage-7.6.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4421712dbfc5562150f7554f13dde997a2e932a6b5f352edcce948a815efee6f", size = 248401 }, + { url = "https://files.pythonhosted.org/packages/75/06/0429c652aa0fb761fc60e8c6b291338c9173c6aa0f4e40e1902345b42830/coverage-7.6.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:166811d20dfea725e2e4baa71fffd6c968a958577848d2131f39b60043400223", size = 246301 }, + { url = "https://files.pythonhosted.org/packages/52/76/1766bb8b803a88f93c3a2d07e30ffa359467810e5cbc68e375ebe6906efb/coverage-7.6.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:225667980479a17db1048cb2bf8bfb39b8e5be8f164b8f6628b64f78a72cf9d3", size = 247598 }, + { url = "https://files.pythonhosted.org/packages/66/8b/f54f8db2ae17188be9566e8166ac6df105c1c611e25da755738025708d54/coverage-7.6.1-cp313-cp313t-win32.whl", hash = "sha256:170d444ab405852903b7d04ea9ae9b98f98ab6d7e63e1115e82620807519797f", size = 210307 }, + { url = "https://files.pythonhosted.org/packages/9f/b0/e0dca6da9170aefc07515cce067b97178cefafb512d00a87a1c717d2efd5/coverage-7.6.1-cp313-cp313t-win_amd64.whl", hash = "sha256:b9f222de8cded79c49bf184bdbc06630d4c58eec9459b939b4a690c82ed05657", size = 211453 }, + { url = "https://files.pythonhosted.org/packages/19/d3/d54c5aa83268779d54c86deb39c1c4566e5d45c155369ca152765f8db413/coverage-7.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:abd5fd0db5f4dc9289408aaf34908072f805ff7792632250dcb36dc591d24255", size = 206688 }, + { url = "https://files.pythonhosted.org/packages/a5/fe/137d5dca72e4a258b1bc17bb04f2e0196898fe495843402ce826a7419fe3/coverage-7.6.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:547f45fa1a93154bd82050a7f3cddbc1a7a4dd2a9bf5cb7d06f4ae29fe94eaf8", size = 207120 }, + { url = "https://files.pythonhosted.org/packages/78/5b/a0a796983f3201ff5485323b225d7c8b74ce30c11f456017e23d8e8d1945/coverage-7.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:645786266c8f18a931b65bfcefdbf6952dd0dea98feee39bd188607a9d307ed2", size = 235249 }, + { url = "https://files.pythonhosted.org/packages/4e/e1/76089d6a5ef9d68f018f65411fcdaaeb0141b504587b901d74e8587606ad/coverage-7.6.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e0b2df163b8ed01d515807af24f63de04bebcecbd6c3bfeff88385789fdf75a", size = 233237 }, + { url = "https://files.pythonhosted.org/packages/9a/6f/eef79b779a540326fee9520e5542a8b428cc3bfa8b7c8f1022c1ee4fc66c/coverage-7.6.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:609b06f178fe8e9f89ef676532760ec0b4deea15e9969bf754b37f7c40326dbc", size = 234311 }, + { url = "https://files.pythonhosted.org/packages/75/e1/656d65fb126c29a494ef964005702b012f3498db1a30dd562958e85a4049/coverage-7.6.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:702855feff378050ae4f741045e19a32d57d19f3e0676d589df0575008ea5004", size = 233453 }, + { url = "https://files.pythonhosted.org/packages/68/6a/45f108f137941a4a1238c85f28fd9d048cc46b5466d6b8dda3aba1bb9d4f/coverage-7.6.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:2bdb062ea438f22d99cba0d7829c2ef0af1d768d1e4a4f528087224c90b132cb", size = 231958 }, + { url = "https://files.pythonhosted.org/packages/9b/e7/47b809099168b8b8c72ae311efc3e88c8d8a1162b3ba4b8da3cfcdb85743/coverage-7.6.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9c56863d44bd1c4fe2abb8a4d6f5371d197f1ac0ebdee542f07f35895fc07f36", size = 232938 }, + { url = "https://files.pythonhosted.org/packages/52/80/052222ba7058071f905435bad0ba392cc12006380731c37afaf3fe749b88/coverage-7.6.1-cp39-cp39-win32.whl", hash = "sha256:6e2cd258d7d927d09493c8df1ce9174ad01b381d4729a9d8d4e38670ca24774c", size = 209352 }, + { url = "https://files.pythonhosted.org/packages/b8/d8/1b92e0b3adcf384e98770a00ca095da1b5f7b483e6563ae4eb5e935d24a1/coverage-7.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:06a737c882bd26d0d6ee7269b20b12f14a8704807a01056c80bb881a4b2ce6ca", size = 210153 }, + { url = "https://files.pythonhosted.org/packages/a5/2b/0354ed096bca64dc8e32a7cbcae28b34cb5ad0b1fe2125d6d99583313ac0/coverage-7.6.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:e9a6e0eb86070e8ccaedfbd9d38fec54864f3125ab95419970575b42af7541df", size = 198926 }, +] + +[package.optional-dependencies] +toml = [ + { name = "tomli", marker = "python_full_version <= '3.11'" }, +] + +[[package]] +name = "distlib" +version = "0.3.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0d/dd/1bec4c5ddb504ca60fc29472f3d27e8d4da1257a854e1d96742f15c1d02d/distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403", size = 613923 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/91/a1/cf2472db20f7ce4a6be1253a81cfdf85ad9c7885ffbed7047fb72c24cf87/distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87", size = 468973 }, +] + +[[package]] +name = "django-admin-extra-urls" +version = "4.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/25/4afe0b88b91b49611437f4ae5d37b9ea4e907728a730e6b8e2ef970db4eb/django-admin-extra-urls-4.1.1.tar.gz", hash = "sha256:b896eebc24779081f5bb5015c41fb12a741c61d520eec88688749e4991f7cbf5", size = 108613 } + +[[package]] +name = "django-adminactions" +version = "2.4.dev12+g308f833.d20250210" +source = { editable = "." } +dependencies = [ + { name = "pytz" }, + { name = "xlrd" }, + { name = "xlwt" }, +] + +[package.dev-dependencies] +dev = [ + { name = "celery" }, + { name = "check-manifest" }, + { name = "covdefaults" }, + { name = "django-admin-extra-urls" }, + { name = "django-dynamic-fixture" }, + { name = "django-environ" }, + { name = "django-webtest" }, + { name = "mock" }, + { name = "modernize" }, + { name = "mypy" }, + { name = "pillow" }, + { name = "psycopg2" }, + { name = "pytest" }, + { name = "pytest-cache" }, + { name = "pytest-cov" }, + { name = "pytest-django" }, + { name = "pytest-echo" }, + { name = "readme" }, + { name = "redis" }, + { name = "ruff" }, + { name = "selenium" }, + { name = "setuptools" }, + { name = "tox" }, +] + +[package.metadata] +requires-dist = [ + { name = "pytz" }, + { name = "xlrd", specifier = ">=0.9.2" }, + { name = "xlwt" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "celery" }, + { name = "check-manifest" }, + { name = "covdefaults", specifier = ">=2.3.0" }, + { name = "django-admin-extra-urls" }, + { name = "django-dynamic-fixture" }, + { name = "django-environ" }, + { name = "django-webtest" }, + { name = "mock" }, + { name = "modernize" }, + { name = "mypy" }, + { name = "pillow" }, + { name = "psycopg2" }, + { name = "pytest" }, + { name = "pytest-cache" }, + { name = "pytest-cov" }, + { name = "pytest-django" }, + { name = "pytest-echo" }, + { name = "readme", specifier = ">=0.7.1" }, + { name = "redis", specifier = ">=5.2.1" }, + { name = "ruff", specifier = ">=0.9.4" }, + { name = "selenium", specifier = ">=2.42" }, + { name = "setuptools", specifier = ">=15" }, + { name = "tox", specifier = ">=4.2" }, +] + +[[package]] +name = "django-dynamic-fixture" +version = "4.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/47/62/d7ca06aece37b7c651b7ffe1aff15e89dfc18653e266af203c5ae9d5212b/django-dynamic-fixture-4.0.1.tar.gz", hash = "sha256:2a2197578b7702db8f5eed9ad704f6be33bac8bf0111c7c92f6063c2a4d02933", size = 44278 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5f/ca/f77782903f93a4ba42204dce89682c5de734d88002cefa6071f805697620/django_dynamic_fixture-4.0.1-py3-none-any.whl", hash = "sha256:d0611b6dc594fb1bccad1fd94dade89cc8deca12385bc2763baded3e48322547", size = 58712 }, +] + +[[package]] +name = "django-environ" +version = "0.11.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/0b/f2c024529ee4bbf8b95176eebeb86c6e695192a9ce0e91059cb83a33c1d3/django-environ-0.11.2.tar.gz", hash = "sha256:f32a87aa0899894c27d4e1776fa6b477e8164ed7f6b3e410a62a6d72caaf64be", size = 54326 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c4/f1/468b49cccba3b42dda571063a14c668bb0b53a1d5712426d18e36663bd53/django_environ-0.11.2-py2.py3-none-any.whl", hash = "sha256:0ff95ab4344bfeff693836aa978e6840abef2e2f1145adff7735892711590c05", size = 19141 }, +] + +[[package]] +name = "django-webtest" +version = "1.9.12" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "webtest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/47/e3/e087630e62bcf29ed1c3560ae98b12c45e0ac07b4899ab3b8ef6a1967dde/django_webtest-1.9.12.tar.gz", hash = "sha256:5012c30665e7a6e585a1544eda75045d07d5b3f5ccccd4d0fe144c4555884095", size = 28848 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/97/0b/c7e6c3a59ea001ca51a966477eafd2746e63b6ff2fce7dcf3c3b3c0ad765/django_webtest-1.9.12-py3-none-any.whl", hash = "sha256:de5c988c20eef7abbb3d0508494d9e576af08087d0fb6109b1d54f15ef4d78fa", size = 16583 }, +] + +[[package]] +name = "docutils" +version = "0.20.1" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.13'", +] +sdist = { url = "https://files.pythonhosted.org/packages/1f/53/a5da4f2c5739cf66290fac1431ee52aff6851c7c8ffd8264f13affd7bcdd/docutils-0.20.1.tar.gz", hash = "sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b", size = 2058365 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/26/87/f238c0670b94533ac0353a4e2a1a771a0cc73277b88bff23d3ae35a256c1/docutils-0.20.1-py3-none-any.whl", hash = "sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6", size = 572666 }, +] + +[[package]] +name = "docutils" +version = "0.21.2" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.13'", +] +sdist = { url = "https://files.pythonhosted.org/packages/ae/ed/aefcc8cd0ba62a0560c3c18c33925362d46c6075480bfa4df87b28e169a9/docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f", size = 2204444 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8f/d7/9322c609343d929e75e7e5e6255e614fcc67572cfd083959cdef3b7aad79/docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2", size = 587408 }, +] + +[[package]] +name = "exceptiongroup" +version = "1.2.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/09/35/2495c4ac46b980e4ca1f6ad6db102322ef3ad2410b79fdde159a4b0f3b92/exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc", size = 28883 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/02/cc/b7e31358aac6ed1ef2bb790a9746ac2c69bcb3c8588b41616914eb106eaf/exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", size = 16453 }, +] + +[[package]] +name = "execnet" +version = "2.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bb/ff/b4c0dc78fbe20c3e59c0c7334de0c27eb4001a2b2017999af398bf730817/execnet-2.1.1.tar.gz", hash = "sha256:5189b52c6121c24feae288166ab41b32549c7e2348652736540b9e6e7d4e72e3", size = 166524 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/09/2aea36ff60d16dd8879bdb2f5b3ee0ba8d08cbbdcdfe870e695ce3784385/execnet-2.1.1-py3-none-any.whl", hash = "sha256:26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc", size = 40612 }, +] + +[[package]] +name = "filelock" +version = "3.16.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9d/db/3ef5bb276dae18d6ec2124224403d1d67bccdbefc17af4cc8f553e341ab1/filelock-3.16.1.tar.gz", hash = "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435", size = 18037 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b9/f8/feced7779d755758a52d1f6635d990b8d98dc0a29fa568bbe0625f18fdf3/filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0", size = 16163 }, +] + +[[package]] +name = "fissix" +version = "24.4.24" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "appdirs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/11/fb/174b49419d4f4d057e65cecba8107a8074a67a3aea59bc80f4e50875b479/fissix-24.4.24.tar.gz", hash = "sha256:7e8f1e448d1ebc1c8be68be8bf71123650710076ea9dcecb7801804b04f43547", size = 160270 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b4/c9/7d293a9ea42ef05d6260714f8cf641ba64fab438be55312b1c719d4e7cc6/fissix-24.4.24-py3-none-any.whl", hash = "sha256:be7f5c66e9e212bd9b3365c9e8f2453e973d0a645f31c8eba842724adb4c0c50", size = 188533 }, +] + +[[package]] +name = "h11" +version = "0.14.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f5/38/3af3d3633a34a3316095b39c8e8fb4853a28a536e55d347bd8d8e9a14b03/h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", size = 100418 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761", size = 58259 }, +] + +[[package]] +name = "idna" +version = "3.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 }, +] + +[[package]] +name = "importlib-metadata" +version = "8.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "zipp", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cd/12/33e59336dca5be0c398a7482335911a33aa0e20776128f038019f1a95f1b/importlib_metadata-8.5.0.tar.gz", hash = "sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7", size = 55304 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl", hash = "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b", size = 26514 }, +] + +[[package]] +name = "iniconfig" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", size = 4646 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 }, +] + +[[package]] +name = "kombu" +version = "5.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "amqp" }, + { name = "typing-extensions", marker = "python_full_version < '3.10'" }, + { name = "tzdata" }, + { name = "vine" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/38/4d/b93fcb353d279839cc35d0012bee805ed0cf61c07587916bfc35dbfddaf1/kombu-5.4.2.tar.gz", hash = "sha256:eef572dd2fd9fc614b37580e3caeafdd5af46c1eff31e7fba89138cdb406f2cf", size = 442858 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/87/ec/7811a3cf9fdfee3ee88e54d08fcbc3fabe7c1b6e4059826c59d7b795651c/kombu-5.4.2-py3-none-any.whl", hash = "sha256:14212f5ccf022fc0a70453bb025a1dcc32782a588c49ea866884047d66e14763", size = 201349 }, +] + +[[package]] +name = "legacy-cgi" +version = "2.6.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ad/2e/e1860989bc6cfdecba66db37f2f783636b97a1248ac25fbe864b6e931c22/legacy_cgi-2.6.2.tar.gz", hash = "sha256:9952471ceb304043b104c22d00b4f333cac27a6abe446d8a528fc437cf13c85f", size = 24794 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4c/cd/54d1fd92d7f6aca9523d8583052e00b273bdfe28aa7fd54a3a5759dab05e/legacy_cgi-2.6.2-py3-none-any.whl", hash = "sha256:a7b83afb1baf6ebeb56522537c5943ef9813cf933f6715e88a803f7edbce0bff", size = 19572 }, +] + +[[package]] +name = "mock" +version = "5.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/66/ab/41d09a46985ead5839d8be987acda54b5bb93f713b3969cc0be4f81c455b/mock-5.1.0.tar.gz", hash = "sha256:5e96aad5ccda4718e0a229ed94b2024df75cc2d55575ba5762d31f5767b8767d", size = 80232 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6b/20/471f41173930550f279ccb65596a5ac19b9ac974a8d93679bcd3e0c31498/mock-5.1.0-py3-none-any.whl", hash = "sha256:18c694e5ae8a208cdb3d2c20a993ca1a7b0efa258c247a1e565150f477f83744", size = 30938 }, +] + +[[package]] +name = "modernize" +version = "0.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "fissix" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e5/97/b7bb97eda53d8784b01dee37aa84dbb2212d89a465a913cd53284568c921/modernize-0.8.0.tar.gz", hash = "sha256:1672b4bb19a060a53dd0518cc8f70fc83591c7246e532223459f85d338c60f55", size = 21304 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/73/6d/c381a4b811a3c529626268276512d1b5abef601e45bc04f0e797284b49bc/modernize-0.8.0-py2.py3-none-any.whl", hash = "sha256:b51f930ac9d726903f2c7f9038146d6061a14509140d6e4498827b19b5610120", size = 27243 }, +] + +[[package]] +name = "mypy" +version = "1.14.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mypy-extensions" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b9/eb/2c92d8ea1e684440f54fa49ac5d9a5f19967b7b472a281f419e69a8d228e/mypy-1.14.1.tar.gz", hash = "sha256:7ec88144fe9b510e8475ec2f5f251992690fcf89ccb4500b214b4226abcd32d6", size = 3216051 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9b/7a/87ae2adb31d68402da6da1e5f30c07ea6063e9f09b5e7cfc9dfa44075e74/mypy-1.14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:52686e37cf13d559f668aa398dd7ddf1f92c5d613e4f8cb262be2fb4fedb0fcb", size = 11211002 }, + { url = "https://files.pythonhosted.org/packages/e1/23/eada4c38608b444618a132be0d199b280049ded278b24cbb9d3fc59658e4/mypy-1.14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1fb545ca340537d4b45d3eecdb3def05e913299ca72c290326be19b3804b39c0", size = 10358400 }, + { url = "https://files.pythonhosted.org/packages/43/c9/d6785c6f66241c62fd2992b05057f404237deaad1566545e9f144ced07f5/mypy-1.14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:90716d8b2d1f4cd503309788e51366f07c56635a3309b0f6a32547eaaa36a64d", size = 12095172 }, + { url = "https://files.pythonhosted.org/packages/c3/62/daa7e787770c83c52ce2aaf1a111eae5893de9e004743f51bfcad9e487ec/mypy-1.14.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ae753f5c9fef278bcf12e1a564351764f2a6da579d4a81347e1d5a15819997b", size = 12828732 }, + { url = "https://files.pythonhosted.org/packages/1b/a2/5fb18318a3637f29f16f4e41340b795da14f4751ef4f51c99ff39ab62e52/mypy-1.14.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e0fe0f5feaafcb04505bcf439e991c6d8f1bf8b15f12b05feeed96e9e7bf1427", size = 13012197 }, + { url = "https://files.pythonhosted.org/packages/28/99/e153ce39105d164b5f02c06c35c7ba958aaff50a2babba7d080988b03fe7/mypy-1.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:7d54bd85b925e501c555a3227f3ec0cfc54ee8b6930bd6141ec872d1c572f81f", size = 9780836 }, + { url = "https://files.pythonhosted.org/packages/da/11/a9422850fd506edbcdc7f6090682ecceaf1f87b9dd847f9df79942da8506/mypy-1.14.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f995e511de847791c3b11ed90084a7a0aafdc074ab88c5a9711622fe4751138c", size = 11120432 }, + { url = "https://files.pythonhosted.org/packages/b6/9e/47e450fd39078d9c02d620545b2cb37993a8a8bdf7db3652ace2f80521ca/mypy-1.14.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d64169ec3b8461311f8ce2fd2eb5d33e2d0f2c7b49116259c51d0d96edee48d1", size = 10279515 }, + { url = "https://files.pythonhosted.org/packages/01/b5/6c8d33bd0f851a7692a8bfe4ee75eb82b6983a3cf39e5e32a5d2a723f0c1/mypy-1.14.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ba24549de7b89b6381b91fbc068d798192b1b5201987070319889e93038967a8", size = 12025791 }, + { url = "https://files.pythonhosted.org/packages/f0/4c/e10e2c46ea37cab5c471d0ddaaa9a434dc1d28650078ac1b56c2d7b9b2e4/mypy-1.14.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:183cf0a45457d28ff9d758730cd0210419ac27d4d3f285beda038c9083363b1f", size = 12749203 }, + { url = "https://files.pythonhosted.org/packages/88/55/beacb0c69beab2153a0f57671ec07861d27d735a0faff135a494cd4f5020/mypy-1.14.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f2a0ecc86378f45347f586e4163d1769dd81c5a223d577fe351f26b179e148b1", size = 12885900 }, + { url = "https://files.pythonhosted.org/packages/a2/75/8c93ff7f315c4d086a2dfcde02f713004357d70a163eddb6c56a6a5eff40/mypy-1.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:ad3301ebebec9e8ee7135d8e3109ca76c23752bac1e717bc84cd3836b4bf3eae", size = 9777869 }, + { url = "https://files.pythonhosted.org/packages/43/1b/b38c079609bb4627905b74fc6a49849835acf68547ac33d8ceb707de5f52/mypy-1.14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:30ff5ef8519bbc2e18b3b54521ec319513a26f1bba19a7582e7b1f58a6e69f14", size = 11266668 }, + { url = "https://files.pythonhosted.org/packages/6b/75/2ed0d2964c1ffc9971c729f7a544e9cd34b2cdabbe2d11afd148d7838aa2/mypy-1.14.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cb9f255c18052343c70234907e2e532bc7e55a62565d64536dbc7706a20b78b9", size = 10254060 }, + { url = "https://files.pythonhosted.org/packages/a1/5f/7b8051552d4da3c51bbe8fcafffd76a6823779101a2b198d80886cd8f08e/mypy-1.14.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b4e3413e0bddea671012b063e27591b953d653209e7a4fa5e48759cda77ca11", size = 11933167 }, + { url = "https://files.pythonhosted.org/packages/04/90/f53971d3ac39d8b68bbaab9a4c6c58c8caa4d5fd3d587d16f5927eeeabe1/mypy-1.14.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:553c293b1fbdebb6c3c4030589dab9fafb6dfa768995a453d8a5d3b23784af2e", size = 12864341 }, + { url = "https://files.pythonhosted.org/packages/03/d2/8bc0aeaaf2e88c977db41583559319f1821c069e943ada2701e86d0430b7/mypy-1.14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fad79bfe3b65fe6a1efaed97b445c3d37f7be9fdc348bdb2d7cac75579607c89", size = 12972991 }, + { url = "https://files.pythonhosted.org/packages/6f/17/07815114b903b49b0f2cf7499f1c130e5aa459411596668267535fe9243c/mypy-1.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:8fa2220e54d2946e94ab6dbb3ba0a992795bd68b16dc852db33028df2b00191b", size = 9879016 }, + { url = "https://files.pythonhosted.org/packages/9e/15/bb6a686901f59222275ab228453de741185f9d54fecbaacec041679496c6/mypy-1.14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:92c3ed5afb06c3a8e188cb5da4984cab9ec9a77ba956ee419c68a388b4595255", size = 11252097 }, + { url = "https://files.pythonhosted.org/packages/f8/b3/8b0f74dfd072c802b7fa368829defdf3ee1566ba74c32a2cb2403f68024c/mypy-1.14.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:dbec574648b3e25f43d23577309b16534431db4ddc09fda50841f1e34e64ed34", size = 10239728 }, + { url = "https://files.pythonhosted.org/packages/c5/9b/4fd95ab20c52bb5b8c03cc49169be5905d931de17edfe4d9d2986800b52e/mypy-1.14.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8c6d94b16d62eb3e947281aa7347d78236688e21081f11de976376cf010eb31a", size = 11924965 }, + { url = "https://files.pythonhosted.org/packages/56/9d/4a236b9c57f5d8f08ed346914b3f091a62dd7e19336b2b2a0d85485f82ff/mypy-1.14.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d4b19b03fdf54f3c5b2fa474c56b4c13c9dbfb9a2db4370ede7ec11a2c5927d9", size = 12867660 }, + { url = "https://files.pythonhosted.org/packages/40/88/a61a5497e2f68d9027de2bb139c7bb9abaeb1be1584649fa9d807f80a338/mypy-1.14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0c911fde686394753fff899c409fd4e16e9b294c24bfd5e1ea4675deae1ac6fd", size = 12969198 }, + { url = "https://files.pythonhosted.org/packages/54/da/3d6fc5d92d324701b0c23fb413c853892bfe0e1dbe06c9138037d459756b/mypy-1.14.1-cp313-cp313-win_amd64.whl", hash = "sha256:8b21525cb51671219f5307be85f7e646a153e5acc656e5cebf64bfa076c50107", size = 9885276 }, + { url = "https://files.pythonhosted.org/packages/ca/1f/186d133ae2514633f8558e78cd658070ba686c0e9275c5a5c24a1e1f0d67/mypy-1.14.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3888a1816d69f7ab92092f785a462944b3ca16d7c470d564165fe703b0970c35", size = 11200493 }, + { url = "https://files.pythonhosted.org/packages/af/fc/4842485d034e38a4646cccd1369f6b1ccd7bc86989c52770d75d719a9941/mypy-1.14.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:46c756a444117c43ee984bd055db99e498bc613a70bbbc120272bd13ca579fbc", size = 10357702 }, + { url = "https://files.pythonhosted.org/packages/b4/e6/457b83f2d701e23869cfec013a48a12638f75b9d37612a9ddf99072c1051/mypy-1.14.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:27fc248022907e72abfd8e22ab1f10e903915ff69961174784a3900a8cba9ad9", size = 12091104 }, + { url = "https://files.pythonhosted.org/packages/f1/bf/76a569158db678fee59f4fd30b8e7a0d75bcbaeef49edd882a0d63af6d66/mypy-1.14.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:499d6a72fb7e5de92218db961f1a66d5f11783f9ae549d214617edab5d4dbdbb", size = 12830167 }, + { url = "https://files.pythonhosted.org/packages/43/bc/0bc6b694b3103de9fed61867f1c8bd33336b913d16831431e7cb48ef1c92/mypy-1.14.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:57961db9795eb566dc1d1b4e9139ebc4c6b0cb6e7254ecde69d1552bf7613f60", size = 13013834 }, + { url = "https://files.pythonhosted.org/packages/b0/79/5f5ec47849b6df1e6943d5fd8e6632fbfc04b4fd4acfa5a5a9535d11b4e2/mypy-1.14.1-cp39-cp39-win_amd64.whl", hash = "sha256:07ba89fdcc9451f2ebb02853deb6aaaa3d2239a236669a63ab3801bbf923ef5c", size = 9781231 }, + { url = "https://files.pythonhosted.org/packages/a0/b5/32dd67b69a16d088e533962e5044e51004176a9952419de0370cdaead0f8/mypy-1.14.1-py3-none-any.whl", hash = "sha256:b66a60cc4073aeb8ae00057f9c1f64d49e90f918fbcef9a977eb121da8b8f1d1", size = 2752905 }, +] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/98/a4/1ab47638b92648243faf97a5aeb6ea83059cc3624972ab6b8d2316078d3f/mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782", size = 4433 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/e2/5d3f6ada4297caebe1a2add3b126fe800c96f56dbe5d1988a2cbe0b267aa/mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d", size = 4695 }, +] + +[[package]] +name = "nh3" +version = "0.2.20" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/46/f2/eb781d94c7855e9129cbbdd3ab09a470441e4176a82a396ae1df270a7333/nh3-0.2.20.tar.gz", hash = "sha256:9705c42d7ff88a0bea546c82d7fe5e59135e3d3f057e485394f491248a1f8ed5", size = 17489 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/65/d31d93b6d1e5fe80d0cc18f0b96eaa561edfa0a15a6ef6b0fce50202a931/nh3-0.2.20-cp313-cp313t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:e1061a4ab6681f6bdf72b110eea0c4e1379d57c9de937db3be4202f7ad6043db", size = 1202187 }, + { url = "https://files.pythonhosted.org/packages/b4/ae/5b03bf198e06921454012e4b9a51e676d26fd37d9fdc1f29371a0b380487/nh3-0.2.20-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb4254b1dac4a1ee49919a5b3f1caf9803ea8dada1816d9e8289e63d3cd0dd9a", size = 737822 }, + { url = "https://files.pythonhosted.org/packages/0a/53/a12dffb6ee3772deba82eb5997667fc835afd2e813d1f4080d8738f29eec/nh3-0.2.20-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0ae9cbd713524cdb81e64663d0d6aae26f678db9f2cd9db0bf162606f1f9f20c", size = 756643 }, + { url = "https://files.pythonhosted.org/packages/d0/0c/6cd2c5ac3e6e31f2a28721e8e2a924cb6b05ad054bf787bd1816ffd40b96/nh3-0.2.20-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:e1f7370b4e14cc03f5ae141ef30a1caf81fa5787711f80be9081418dd9eb79d2", size = 923415 }, + { url = "https://files.pythonhosted.org/packages/64/f0/229a6c8b81b86ba22d8e7f27ade62cb2fcfb987e570f49944fdd8490a76a/nh3-0.2.20-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:ac4d27dc836a476efffc6eb661994426b8b805c951b29c9cf2ff36bc9ad58bc5", size = 994959 }, + { url = "https://files.pythonhosted.org/packages/75/e3/62ae3d3b658739ee15b129356fe6d4c4bc8ab235d7bf2e0d2794d64f7bc6/nh3-0.2.20-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:4fd2e9248725ebcedac3997a8d3da0d90a12a28c9179c6ba51f1658938ac30d0", size = 915777 }, + { url = "https://files.pythonhosted.org/packages/45/bd/8405d03371e335f02eb72e09dcf73307f8fd3095e4165cec6836346fe3db/nh3-0.2.20-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f7d564871833ddbe54df3aa59053b1110729d3a800cb7628ae8f42adb3d75208", size = 908614 }, + { url = "https://files.pythonhosted.org/packages/ee/f8/5d977f09cf82c1f22a864375f471db111530fc79c88efdf0659fe6d3d6bc/nh3-0.2.20-cp313-cp313t-win32.whl", hash = "sha256:d2a176fd4306b6f0f178a3f67fac91bd97a3a8d8fafb771c9b9ef675ba5c8886", size = 540482 }, + { url = "https://files.pythonhosted.org/packages/c5/f4/e34afe5fd8bed1920eac2974c9c853f548b4b65c139444285ffd2a68495d/nh3-0.2.20-cp313-cp313t-win_amd64.whl", hash = "sha256:6ed834c68452a600f517dd3e1534dbfaff1f67f98899fecf139a055a25d99150", size = 541302 }, + { url = "https://files.pythonhosted.org/packages/92/08/5e3b61eed1bc0efeb330ddc5cf5194f28a0b7be7943aa20bd44cfe14650b/nh3-0.2.20-cp38-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:76e2f603b30c02ff6456b233a83fc377dedab6a50947b04e960a6b905637b776", size = 1202141 }, + { url = "https://files.pythonhosted.org/packages/29/d2/3377f8006c71e95e007b07b5bfcac22c9de4744ca3efb23b396d3deb9581/nh3-0.2.20-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:181063c581defe683bd4bb78188ac9936d208aebbc74c7f7c16b6a32ae2ebb38", size = 760699 }, + { url = "https://files.pythonhosted.org/packages/37/d7/7077f925d7d680d53dcb6e18a4af13d1a7da59761c06c193bfa249a7470a/nh3-0.2.20-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:231addb7643c952cd6d71f1c8702d703f8fe34afcb20becb3efb319a501a12d7", size = 747353 }, + { url = "https://files.pythonhosted.org/packages/cb/59/6b2f32af477aae81f1454a7f6ef490ebc3c22dd9e1370e73fcfe243dc07a/nh3-0.2.20-cp38-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:1b9a8340a0aab991c68a5ca938d35ef4a8a3f4bf1b455da8855a40bee1fa0ace", size = 854125 }, + { url = "https://files.pythonhosted.org/packages/5b/f2/c3d2f7b801477b8b387b51fbefd16dc7ade888aeac547f18ba0558fd6f48/nh3-0.2.20-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:10317cd96fe4bbd4eb6b95f3920b71c902157ad44fed103fdcde43e3b8ee8be6", size = 817453 }, + { url = "https://files.pythonhosted.org/packages/42/4d/f7e3a35506a0eba6eedafc21ad52773985511eb838812e9f96354831ad3c/nh3-0.2.20-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8698db4c04b140800d1a1cd3067fda399e36e1e2b8fc1fe04292a907350a3e9b", size = 891694 }, + { url = "https://files.pythonhosted.org/packages/e6/0e/c499453c296fb40366e3069cd68fde77a10f0a30a17b9d3b491eb3ebc5bf/nh3-0.2.20-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3eb04b9c3deb13c3a375ea39fd4a3c00d1f92e8fb2349f25f1e3e4506751774b", size = 744388 }, + { url = "https://files.pythonhosted.org/packages/18/67/c3de8022ba2719bdbbdd3704d1e32dbc7d3f8ac8646247711645fc90d051/nh3-0.2.20-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:92f3f1c4f47a2c6f3ca7317b1d5ced05bd29556a75d3a4e2715652ae9d15c05d", size = 764831 }, + { url = "https://files.pythonhosted.org/packages/f0/14/a4ea40e2439717d11c3104fc2dc0ac412301b7aeb81d6a3d0e6505c77e7d/nh3-0.2.20-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ddefa9fd6794a87e37d05827d299d4b53a3ec6f23258101907b96029bfef138a", size = 923334 }, + { url = "https://files.pythonhosted.org/packages/ed/ae/e8ee8afaf67903dd304f390056d1ea620327524e2ad66127a331b14d5d98/nh3-0.2.20-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:ce3731c8f217685d33d9268362e5b4f770914e922bba94d368ab244a59a6c397", size = 994873 }, + { url = "https://files.pythonhosted.org/packages/20/b5/02122cfe3b36cf0ba0fcd73a04fd462e1f7a9d91b456f6e0b70e46df21c7/nh3-0.2.20-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:09f037c02fc2c43b211ff1523de32801dcfb0918648d8e651c36ef890f1731ec", size = 915707 }, + { url = "https://files.pythonhosted.org/packages/47/d3/5df43cc3570cdc9eb1dc79a39191f89fedf8bcefd8d30a161ff1dffb146c/nh3-0.2.20-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:813f1c8012dd64c990514b795508abb90789334f76a561fa0fd4ca32d2275330", size = 908539 }, + { url = "https://files.pythonhosted.org/packages/4f/fd/aa000f6c76a832c488eac26f20d2e8a221ba2b965efce692f14ebc4290bf/nh3-0.2.20-cp38-abi3-win32.whl", hash = "sha256:47b2946c0e13057855209daeffb45dc910bd0c55daf10190bb0b4b60e2999784", size = 540439 }, + { url = "https://files.pythonhosted.org/packages/19/31/d65594efd3b42b1de2335d576eb77525691fc320dbf8617948ee05c008e5/nh3-0.2.20-cp38-abi3-win_amd64.whl", hash = "sha256:da87573f03084edae8eb87cfe811ec338606288f81d333c07d2a9a0b9b976c0b", size = 541249 }, +] + +[[package]] +name = "outcome" +version = "1.3.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/98/df/77698abfac98571e65ffeb0c1fba8ffd692ab8458d617a0eed7d9a8d38f2/outcome-1.3.0.post0.tar.gz", hash = "sha256:9dcf02e65f2971b80047b377468e72a268e15c0af3cf1238e6ff14f7f91143b8", size = 21060 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/55/8b/5ab7257531a5d830fc8000c476e63c935488d74609b50f9384a643ec0a62/outcome-1.3.0.post0-py2.py3-none-any.whl", hash = "sha256:e771c5ce06d1415e356078d3bdd68523f284b4ce5419828922b6871e65eda82b", size = 10692 }, +] + +[[package]] +name = "packaging" +version = "24.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451 }, +] + +[[package]] +name = "pillow" +version = "10.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/74/ad3d526f3bf7b6d3f408b73fde271ec69dfac8b81341a318ce825f2b3812/pillow-10.4.0.tar.gz", hash = "sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06", size = 46555059 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0e/69/a31cccd538ca0b5272be2a38347f8839b97a14be104ea08b0db92f749c74/pillow-10.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e", size = 3509271 }, + { url = "https://files.pythonhosted.org/packages/9a/9e/4143b907be8ea0bce215f2ae4f7480027473f8b61fcedfda9d851082a5d2/pillow-10.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:543f3dc61c18dafb755773efc89aae60d06b6596a63914107f75459cf984164d", size = 3375658 }, + { url = "https://files.pythonhosted.org/packages/8a/25/1fc45761955f9359b1169aa75e241551e74ac01a09f487adaaf4c3472d11/pillow-10.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7928ecbf1ece13956b95d9cbcfc77137652b02763ba384d9ab508099a2eca856", size = 4332075 }, + { url = "https://files.pythonhosted.org/packages/5e/dd/425b95d0151e1d6c951f45051112394f130df3da67363b6bc75dc4c27aba/pillow-10.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4d49b85c4348ea0b31ea63bc75a9f3857869174e2bf17e7aba02945cd218e6f", size = 4444808 }, + { url = "https://files.pythonhosted.org/packages/b1/84/9a15cc5726cbbfe7f9f90bfb11f5d028586595907cd093815ca6644932e3/pillow-10.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:6c762a5b0997f5659a5ef2266abc1d8851ad7749ad9a6a5506eb23d314e4f46b", size = 4356290 }, + { url = "https://files.pythonhosted.org/packages/b5/5b/6651c288b08df3b8c1e2f8c1152201e0b25d240e22ddade0f1e242fc9fa0/pillow-10.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a985e028fc183bf12a77a8bbf36318db4238a3ded7fa9df1b9a133f1cb79f8fc", size = 4525163 }, + { url = "https://files.pythonhosted.org/packages/07/8b/34854bf11a83c248505c8cb0fcf8d3d0b459a2246c8809b967963b6b12ae/pillow-10.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:812f7342b0eee081eaec84d91423d1b4650bb9828eb53d8511bcef8ce5aecf1e", size = 4463100 }, + { url = "https://files.pythonhosted.org/packages/78/63/0632aee4e82476d9cbe5200c0cdf9ba41ee04ed77887432845264d81116d/pillow-10.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ac1452d2fbe4978c2eec89fb5a23b8387aba707ac72810d9490118817d9c0b46", size = 4592880 }, + { url = "https://files.pythonhosted.org/packages/df/56/b8663d7520671b4398b9d97e1ed9f583d4afcbefbda3c6188325e8c297bd/pillow-10.4.0-cp310-cp310-win32.whl", hash = "sha256:bcd5e41a859bf2e84fdc42f4edb7d9aba0a13d29a2abadccafad99de3feff984", size = 2235218 }, + { url = "https://files.pythonhosted.org/packages/f4/72/0203e94a91ddb4a9d5238434ae6c1ca10e610e8487036132ea9bf806ca2a/pillow-10.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:ecd85a8d3e79cd7158dec1c9e5808e821feea088e2f69a974db5edf84dc53141", size = 2554487 }, + { url = "https://files.pythonhosted.org/packages/bd/52/7e7e93d7a6e4290543f17dc6f7d3af4bd0b3dd9926e2e8a35ac2282bc5f4/pillow-10.4.0-cp310-cp310-win_arm64.whl", hash = "sha256:ff337c552345e95702c5fde3158acb0625111017d0e5f24bf3acdb9cc16b90d1", size = 2243219 }, + { url = "https://files.pythonhosted.org/packages/a7/62/c9449f9c3043c37f73e7487ec4ef0c03eb9c9afc91a92b977a67b3c0bbc5/pillow-10.4.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:0a9ec697746f268507404647e531e92889890a087e03681a3606d9b920fbee3c", size = 3509265 }, + { url = "https://files.pythonhosted.org/packages/f4/5f/491dafc7bbf5a3cc1845dc0430872e8096eb9e2b6f8161509d124594ec2d/pillow-10.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfe91cb65544a1321e631e696759491ae04a2ea11d36715eca01ce07284738be", size = 3375655 }, + { url = "https://files.pythonhosted.org/packages/73/d5/c4011a76f4207a3c151134cd22a1415741e42fa5ddecec7c0182887deb3d/pillow-10.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dc6761a6efc781e6a1544206f22c80c3af4c8cf461206d46a1e6006e4429ff3", size = 4340304 }, + { url = "https://files.pythonhosted.org/packages/ac/10/c67e20445a707f7a610699bba4fe050583b688d8cd2d202572b257f46600/pillow-10.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e84b6cc6a4a3d76c153a6b19270b3526a5a8ed6b09501d3af891daa2a9de7d6", size = 4452804 }, + { url = "https://files.pythonhosted.org/packages/a9/83/6523837906d1da2b269dee787e31df3b0acb12e3d08f024965a3e7f64665/pillow-10.4.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:bbc527b519bd3aa9d7f429d152fea69f9ad37c95f0b02aebddff592688998abe", size = 4365126 }, + { url = "https://files.pythonhosted.org/packages/ba/e5/8c68ff608a4203085158cff5cc2a3c534ec384536d9438c405ed6370d080/pillow-10.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:76a911dfe51a36041f2e756b00f96ed84677cdeb75d25c767f296c1c1eda1319", size = 4533541 }, + { url = "https://files.pythonhosted.org/packages/f4/7c/01b8dbdca5bc6785573f4cee96e2358b0918b7b2c7b60d8b6f3abf87a070/pillow-10.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:59291fb29317122398786c2d44427bbd1a6d7ff54017075b22be9d21aa59bd8d", size = 4471616 }, + { url = "https://files.pythonhosted.org/packages/c8/57/2899b82394a35a0fbfd352e290945440e3b3785655a03365c0ca8279f351/pillow-10.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:416d3a5d0e8cfe4f27f574362435bc9bae57f679a7158e0096ad2beb427b8696", size = 4600802 }, + { url = "https://files.pythonhosted.org/packages/4d/d7/a44f193d4c26e58ee5d2d9db3d4854b2cfb5b5e08d360a5e03fe987c0086/pillow-10.4.0-cp311-cp311-win32.whl", hash = "sha256:7086cc1d5eebb91ad24ded9f58bec6c688e9f0ed7eb3dbbf1e4800280a896496", size = 2235213 }, + { url = "https://files.pythonhosted.org/packages/c1/d0/5866318eec2b801cdb8c82abf190c8343d8a1cd8bf5a0c17444a6f268291/pillow-10.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cbed61494057c0f83b83eb3a310f0bf774b09513307c434d4366ed64f4128a91", size = 2554498 }, + { url = "https://files.pythonhosted.org/packages/d4/c8/310ac16ac2b97e902d9eb438688de0d961660a87703ad1561fd3dfbd2aa0/pillow-10.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:f5f0c3e969c8f12dd2bb7e0b15d5c468b51e5017e01e2e867335c81903046a22", size = 2243219 }, + { url = "https://files.pythonhosted.org/packages/05/cb/0353013dc30c02a8be34eb91d25e4e4cf594b59e5a55ea1128fde1e5f8ea/pillow-10.4.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:673655af3eadf4df6b5457033f086e90299fdd7a47983a13827acf7459c15d94", size = 3509350 }, + { url = "https://files.pythonhosted.org/packages/e7/cf/5c558a0f247e0bf9cec92bff9b46ae6474dd736f6d906315e60e4075f737/pillow-10.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:866b6942a92f56300012f5fbac71f2d610312ee65e22f1aa2609e491284e5597", size = 3374980 }, + { url = "https://files.pythonhosted.org/packages/84/48/6e394b86369a4eb68b8a1382c78dc092245af517385c086c5094e3b34428/pillow-10.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29dbdc4207642ea6aad70fbde1a9338753d33fb23ed6956e706936706f52dd80", size = 4343799 }, + { url = "https://files.pythonhosted.org/packages/3b/f3/a8c6c11fa84b59b9df0cd5694492da8c039a24cd159f0f6918690105c3be/pillow-10.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf2342ac639c4cf38799a44950bbc2dfcb685f052b9e262f446482afaf4bffca", size = 4459973 }, + { url = "https://files.pythonhosted.org/packages/7d/1b/c14b4197b80150fb64453585247e6fb2e1d93761fa0fa9cf63b102fde822/pillow-10.4.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:f5b92f4d70791b4a67157321c4e8225d60b119c5cc9aee8ecf153aace4aad4ef", size = 4370054 }, + { url = "https://files.pythonhosted.org/packages/55/77/40daddf677897a923d5d33329acd52a2144d54a9644f2a5422c028c6bf2d/pillow-10.4.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:86dcb5a1eb778d8b25659d5e4341269e8590ad6b4e8b44d9f4b07f8d136c414a", size = 4539484 }, + { url = "https://files.pythonhosted.org/packages/40/54/90de3e4256b1207300fb2b1d7168dd912a2fb4b2401e439ba23c2b2cabde/pillow-10.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:780c072c2e11c9b2c7ca37f9a2ee8ba66f44367ac3e5c7832afcfe5104fd6d1b", size = 4477375 }, + { url = "https://files.pythonhosted.org/packages/13/24/1bfba52f44193860918ff7c93d03d95e3f8748ca1de3ceaf11157a14cf16/pillow-10.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:37fb69d905be665f68f28a8bba3c6d3223c8efe1edf14cc4cfa06c241f8c81d9", size = 4608773 }, + { url = "https://files.pythonhosted.org/packages/55/04/5e6de6e6120451ec0c24516c41dbaf80cce1b6451f96561235ef2429da2e/pillow-10.4.0-cp312-cp312-win32.whl", hash = "sha256:7dfecdbad5c301d7b5bde160150b4db4c659cee2b69589705b6f8a0c509d9f42", size = 2235690 }, + { url = "https://files.pythonhosted.org/packages/74/0a/d4ce3c44bca8635bd29a2eab5aa181b654a734a29b263ca8efe013beea98/pillow-10.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:1d846aea995ad352d4bdcc847535bd56e0fd88d36829d2c90be880ef1ee4668a", size = 2554951 }, + { url = "https://files.pythonhosted.org/packages/b5/ca/184349ee40f2e92439be9b3502ae6cfc43ac4b50bc4fc6b3de7957563894/pillow-10.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:e553cad5179a66ba15bb18b353a19020e73a7921296a7979c4a2b7f6a5cd57f9", size = 2243427 }, + { url = "https://files.pythonhosted.org/packages/c3/00/706cebe7c2c12a6318aabe5d354836f54adff7156fd9e1bd6c89f4ba0e98/pillow-10.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8bc1a764ed8c957a2e9cacf97c8b2b053b70307cf2996aafd70e91a082e70df3", size = 3525685 }, + { url = "https://files.pythonhosted.org/packages/cf/76/f658cbfa49405e5ecbfb9ba42d07074ad9792031267e782d409fd8fe7c69/pillow-10.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6209bb41dc692ddfee4942517c19ee81b86c864b626dbfca272ec0f7cff5d9fb", size = 3374883 }, + { url = "https://files.pythonhosted.org/packages/46/2b/99c28c4379a85e65378211971c0b430d9c7234b1ec4d59b2668f6299e011/pillow-10.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bee197b30783295d2eb680b311af15a20a8b24024a19c3a26431ff83eb8d1f70", size = 4339837 }, + { url = "https://files.pythonhosted.org/packages/f1/74/b1ec314f624c0c43711fdf0d8076f82d9d802afd58f1d62c2a86878e8615/pillow-10.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ef61f5dd14c300786318482456481463b9d6b91ebe5ef12f405afbba77ed0be", size = 4455562 }, + { url = "https://files.pythonhosted.org/packages/4a/2a/4b04157cb7b9c74372fa867096a1607e6fedad93a44deeff553ccd307868/pillow-10.4.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:297e388da6e248c98bc4a02e018966af0c5f92dfacf5a5ca22fa01cb3179bca0", size = 4366761 }, + { url = "https://files.pythonhosted.org/packages/ac/7b/8f1d815c1a6a268fe90481232c98dd0e5fa8c75e341a75f060037bd5ceae/pillow-10.4.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:e4db64794ccdf6cb83a59d73405f63adbe2a1887012e308828596100a0b2f6cc", size = 4536767 }, + { url = "https://files.pythonhosted.org/packages/e5/77/05fa64d1f45d12c22c314e7b97398ffb28ef2813a485465017b7978b3ce7/pillow-10.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd2880a07482090a3bcb01f4265f1936a903d70bc740bfcb1fd4e8a2ffe5cf5a", size = 4477989 }, + { url = "https://files.pythonhosted.org/packages/12/63/b0397cfc2caae05c3fb2f4ed1b4fc4fc878f0243510a7a6034ca59726494/pillow-10.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b35b21b819ac1dbd1233317adeecd63495f6babf21b7b2512d244ff6c6ce309", size = 4610255 }, + { url = "https://files.pythonhosted.org/packages/7b/f9/cfaa5082ca9bc4a6de66ffe1c12c2d90bf09c309a5f52b27759a596900e7/pillow-10.4.0-cp313-cp313-win32.whl", hash = "sha256:551d3fd6e9dc15e4c1eb6fc4ba2b39c0c7933fa113b220057a34f4bb3268a060", size = 2235603 }, + { url = "https://files.pythonhosted.org/packages/01/6a/30ff0eef6e0c0e71e55ded56a38d4859bf9d3634a94a88743897b5f96936/pillow-10.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:030abdbe43ee02e0de642aee345efa443740aa4d828bfe8e2eb11922ea6a21ea", size = 2554972 }, + { url = "https://files.pythonhosted.org/packages/48/2c/2e0a52890f269435eee38b21c8218e102c621fe8d8df8b9dd06fabf879ba/pillow-10.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:5b001114dd152cfd6b23befeb28d7aee43553e2402c9f159807bf55f33af8a8d", size = 2243375 }, + { url = "https://files.pythonhosted.org/packages/31/85/955fa5400fa8039921f630372cfe5056eed6e1b8e0430ee4507d7de48832/pillow-10.4.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0ae24a547e8b711ccaaf99c9ae3cd975470e1a30caa80a6aaee9a2f19c05701d", size = 3509283 }, + { url = "https://files.pythonhosted.org/packages/23/9c/343827267eb28d41cd82b4180d33b10d868af9077abcec0af9793aa77d2d/pillow-10.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:298478fe4f77a4408895605f3482b6cc6222c018b2ce565c2b6b9c354ac3229b", size = 3375691 }, + { url = "https://files.pythonhosted.org/packages/60/a3/7ebbeabcd341eab722896d1a5b59a3df98c4b4d26cf4b0385f8aa94296f7/pillow-10.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:134ace6dc392116566980ee7436477d844520a26a4b1bd4053f6f47d096997fd", size = 4328295 }, + { url = "https://files.pythonhosted.org/packages/32/3f/c02268d0c6fb6b3958bdda673c17b315c821d97df29ae6969f20fb49388a/pillow-10.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:930044bb7679ab003b14023138b50181899da3f25de50e9dbee23b61b4de2126", size = 4440810 }, + { url = "https://files.pythonhosted.org/packages/67/5d/1c93c8cc35f2fdd3d6cc7e4ad72d203902859a2867de6ad957d9b708eb8d/pillow-10.4.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:c76e5786951e72ed3686e122d14c5d7012f16c8303a674d18cdcd6d89557fc5b", size = 4352283 }, + { url = "https://files.pythonhosted.org/packages/bc/a8/8655557c9c7202b8abbd001f61ff36711cefaf750debcaa1c24d154ef602/pillow-10.4.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b2724fdb354a868ddf9a880cb84d102da914e99119211ef7ecbdc613b8c96b3c", size = 4521800 }, + { url = "https://files.pythonhosted.org/packages/58/78/6f95797af64d137124f68af1bdaa13b5332da282b86031f6fa70cf368261/pillow-10.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dbc6ae66518ab3c5847659e9988c3b60dc94ffb48ef9168656e0019a93dbf8a1", size = 4459177 }, + { url = "https://files.pythonhosted.org/packages/8a/6d/2b3ce34f1c4266d79a78c9a51d1289a33c3c02833fe294ef0dcbb9cba4ed/pillow-10.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:06b2f7898047ae93fad74467ec3d28fe84f7831370e3c258afa533f81ef7f3df", size = 4589079 }, + { url = "https://files.pythonhosted.org/packages/e3/e0/456258c74da1ff5bf8ef1eab06a95ca994d8b9ed44c01d45c3f8cbd1db7e/pillow-10.4.0-cp39-cp39-win32.whl", hash = "sha256:7970285ab628a3779aecc35823296a7869f889b8329c16ad5a71e4901a3dc4ef", size = 2235247 }, + { url = "https://files.pythonhosted.org/packages/37/f8/bef952bdb32aa53741f58bf21798642209e994edc3f6598f337f23d5400a/pillow-10.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:961a7293b2457b405967af9c77dcaa43cc1a8cd50d23c532e62d48ab6cdd56f5", size = 2554479 }, + { url = "https://files.pythonhosted.org/packages/bb/8e/805201619cad6651eef5fc1fdef913804baf00053461522fabbc5588ea12/pillow-10.4.0-cp39-cp39-win_arm64.whl", hash = "sha256:32cda9e3d601a52baccb2856b8ea1fc213c90b340c542dcef77140dfa3278a9e", size = 2243226 }, + { url = "https://files.pythonhosted.org/packages/38/30/095d4f55f3a053392f75e2eae45eba3228452783bab3d9a920b951ac495c/pillow-10.4.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5b4815f2e65b30f5fbae9dfffa8636d992d49705723fe86a3661806e069352d4", size = 3493889 }, + { url = "https://files.pythonhosted.org/packages/f3/e8/4ff79788803a5fcd5dc35efdc9386af153569853767bff74540725b45863/pillow-10.4.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8f0aef4ef59694b12cadee839e2ba6afeab89c0f39a3adc02ed51d109117b8da", size = 3346160 }, + { url = "https://files.pythonhosted.org/packages/d7/ac/4184edd511b14f760c73f5bb8a5d6fd85c591c8aff7c2229677a355c4179/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f4727572e2918acaa9077c919cbbeb73bd2b3ebcfe033b72f858fc9fbef0026", size = 3435020 }, + { url = "https://files.pythonhosted.org/packages/da/21/1749cd09160149c0a246a81d646e05f35041619ce76f6493d6a96e8d1103/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff25afb18123cea58a591ea0244b92eb1e61a1fd497bf6d6384f09bc3262ec3e", size = 3490539 }, + { url = "https://files.pythonhosted.org/packages/b6/f5/f71fe1888b96083b3f6dfa0709101f61fc9e972c0c8d04e9d93ccef2a045/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dc3e2db6ba09ffd7d02ae9141cfa0ae23393ee7687248d46a7507b75d610f4f5", size = 3476125 }, + { url = "https://files.pythonhosted.org/packages/96/b9/c0362c54290a31866c3526848583a2f45a535aa9d725fd31e25d318c805f/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:02a2be69f9c9b8c1e97cf2713e789d4e398c751ecfd9967c18d0ce304efbf885", size = 3579373 }, + { url = "https://files.pythonhosted.org/packages/52/3b/ce7a01026a7cf46e5452afa86f97a5e88ca97f562cafa76570178ab56d8d/pillow-10.4.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0755ffd4a0c6f267cccbae2e9903d95477ca2f77c4fcf3a3a09570001856c8a5", size = 2554661 }, + { url = "https://files.pythonhosted.org/packages/e1/1f/5a9fcd6ced51633c22481417e11b1b47d723f64fb536dfd67c015eb7f0ab/pillow-10.4.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:a02364621fe369e06200d4a16558e056fe2805d3468350df3aef21e00d26214b", size = 3493850 }, + { url = "https://files.pythonhosted.org/packages/cb/e6/3ea4755ed5320cb62aa6be2f6de47b058c6550f752dd050e86f694c59798/pillow-10.4.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:1b5dea9831a90e9d0721ec417a80d4cbd7022093ac38a568db2dd78363b00908", size = 3346118 }, + { url = "https://files.pythonhosted.org/packages/0a/22/492f9f61e4648422b6ca39268ec8139277a5b34648d28f400faac14e0f48/pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b885f89040bb8c4a1573566bbb2f44f5c505ef6e74cec7ab9068c900047f04b", size = 3434958 }, + { url = "https://files.pythonhosted.org/packages/f9/19/559a48ad4045704bb0547965b9a9345f5cd461347d977a56d178db28819e/pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87dd88ded2e6d74d31e1e0a99a726a6765cda32d00ba72dc37f0651f306daaa8", size = 3490340 }, + { url = "https://files.pythonhosted.org/packages/d9/de/cebaca6fb79905b3a1aa0281d238769df3fb2ede34fd7c0caa286575915a/pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:2db98790afc70118bd0255c2eeb465e9767ecf1f3c25f9a1abb8ffc8cfd1fe0a", size = 3476048 }, + { url = "https://files.pythonhosted.org/packages/71/f0/86d5b2f04693b0116a01d75302b0a307800a90d6c351a8aa4f8ae76cd499/pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f7baece4ce06bade126fb84b8af1c33439a76d8a6fd818970215e0560ca28c27", size = 3579366 }, + { url = "https://files.pythonhosted.org/packages/37/ae/2dbfc38cc4fd14aceea14bc440d5151b21f64c4c3ba3f6f4191610b7ee5d/pillow-10.4.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:cfdd747216947628af7b259d274771d84db2268ca062dd5faf373639d00113a3", size = 2554652 }, +] + +[[package]] +name = "platformdirs" +version = "4.3.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/13/fc/128cc9cb8f03208bdbf93d3aa862e16d376844a14f9a0ce5cf4507372de4/platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907", size = 21302 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/a6/bc1012356d8ece4d66dd75c4b9fc6c1f6650ddd5991e421177d9f8f671be/platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb", size = 18439 }, +] + +[[package]] +name = "pluggy" +version = "1.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 }, +] + +[[package]] +name = "prompt-toolkit" +version = "3.0.50" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "wcwidth" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a1/e1/bd15cb8ffdcfeeb2bdc215de3c3cffca11408d829e4b8416dcfe71ba8854/prompt_toolkit-3.0.50.tar.gz", hash = "sha256:544748f3860a2623ca5cd6d2795e7a14f3d0e1c3c9728359013f79877fc89bab", size = 429087 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e4/ea/d836f008d33151c7a1f62caf3d8dd782e4d15f6a43897f64480c2b8de2ad/prompt_toolkit-3.0.50-py3-none-any.whl", hash = "sha256:9b6427eb19e479d98acff65196a307c555eb567989e6d88ebbb1b509d9779198", size = 387816 }, +] + +[[package]] +name = "psycopg2" +version = "2.9.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/62/51/2007ea29e605957a17ac6357115d0c1a1b60c8c984951c19419b3474cdfd/psycopg2-2.9.10.tar.gz", hash = "sha256:12ec0b40b0273f95296233e8750441339298e6a572f7039da5b260e3c8b60e11", size = 385672 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0a/a9/146b6bdc0d33539a359f5e134ee6dda9173fb8121c5b96af33fa299e50c4/psycopg2-2.9.10-cp310-cp310-win32.whl", hash = "sha256:5df2b672140f95adb453af93a7d669d7a7bf0a56bcd26f1502329166f4a61716", size = 1024527 }, + { url = "https://files.pythonhosted.org/packages/47/50/c509e56f725fd2572b59b69bd964edaf064deebf1c896b2452f6b46fdfb3/psycopg2-2.9.10-cp310-cp310-win_amd64.whl", hash = "sha256:c6f7b8561225f9e711a9c47087388a97fdc948211c10a4bccbf0ba68ab7b3b5a", size = 1163735 }, + { url = "https://files.pythonhosted.org/packages/20/a2/c51ca3e667c34e7852157b665e3d49418e68182081060231d514dd823225/psycopg2-2.9.10-cp311-cp311-win32.whl", hash = "sha256:47c4f9875125344f4c2b870e41b6aad585901318068acd01de93f3677a6522c2", size = 1024538 }, + { url = "https://files.pythonhosted.org/packages/33/39/5a9a229bb5414abeb86e33b8fc8143ab0aecce5a7f698a53e31367d30caa/psycopg2-2.9.10-cp311-cp311-win_amd64.whl", hash = "sha256:0435034157049f6846e95103bd8f5a668788dd913a7c30162ca9503fdf542cb4", size = 1163736 }, + { url = "https://files.pythonhosted.org/packages/3d/16/4623fad6076448df21c1a870c93a9774ad8a7b4dd1660223b59082dd8fec/psycopg2-2.9.10-cp312-cp312-win32.whl", hash = "sha256:65a63d7ab0e067e2cdb3cf266de39663203d38d6a8ed97f5ca0cb315c73fe067", size = 1025113 }, + { url = "https://files.pythonhosted.org/packages/66/de/baed128ae0fc07460d9399d82e631ea31a1f171c0c4ae18f9808ac6759e3/psycopg2-2.9.10-cp312-cp312-win_amd64.whl", hash = "sha256:4a579d6243da40a7b3182e0430493dbd55950c493d8c68f4eec0b302f6bbf20e", size = 1163951 }, + { url = "https://files.pythonhosted.org/packages/ae/49/a6cfc94a9c483b1fa401fbcb23aca7892f60c7269c5ffa2ac408364f80dc/psycopg2-2.9.10-cp313-cp313-win_amd64.whl", hash = "sha256:91fd603a2155da8d0cfcdbf8ab24a2d54bca72795b90d2a3ed2b6da8d979dee2", size = 2569060 }, + { url = "https://files.pythonhosted.org/packages/5f/29/bc9639b9c50abd93a8274fd2deffbf70b2a65aa9e7881e63ea6bc4319e84/psycopg2-2.9.10-cp39-cp39-win32.whl", hash = "sha256:9d5b3b94b79a844a986d029eee38998232451119ad653aea42bb9220a8c5066b", size = 1025259 }, + { url = "https://files.pythonhosted.org/packages/2c/f8/0be7d99d24656b689d83ac167240c3527efb0b161d814fb1dd58329ddf75/psycopg2-2.9.10-cp39-cp39-win_amd64.whl", hash = "sha256:88138c8dedcbfa96408023ea2b0c369eda40fe5d75002c0964c78f46f11fa442", size = 1163878 }, +] + +[[package]] +name = "pycparser" +version = "2.22" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/b2/31537cf4b1ca988837256c910a668b553fceb8f069bedc4b1c826024b52c/pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", size = 172736 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc", size = 117552 }, +] + +[[package]] +name = "pygments" +version = "2.19.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293 }, +] + +[[package]] +name = "pyproject-api" +version = "1.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bb/19/441e0624a8afedd15bbcce96df1b80479dd0ff0d965f5ce8fde4f2f6ffad/pyproject_api-1.8.0.tar.gz", hash = "sha256:77b8049f2feb5d33eefcc21b57f1e279636277a8ac8ad6b5871037b243778496", size = 22340 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ba/f4/3c4ddfcc0c19c217c6de513842d286de8021af2f2ab79bbb86c00342d778/pyproject_api-1.8.0-py3-none-any.whl", hash = "sha256:3d7d347a047afe796fd5d1885b1e391ba29be7169bd2f102fcd378f04273d228", size = 13100 }, +] + +[[package]] +name = "pyproject-hooks" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/82/28175b2414effca1cdac8dc99f76d660e7a4fb0ceefa4b4ab8f5f6742925/pyproject_hooks-1.2.0.tar.gz", hash = "sha256:1e859bd5c40fae9448642dd871adf459e5e2084186e8d2c2a79a824c970da1f8", size = 19228 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bd/24/12818598c362d7f300f18e74db45963dbcb85150324092410c8b49405e42/pyproject_hooks-1.2.0-py3-none-any.whl", hash = "sha256:9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913", size = 10216 }, +] + +[[package]] +name = "pysocks" +version = "1.7.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bd/11/293dd436aea955d45fc4e8a35b6ae7270f5b8e00b53cf6c024c83b657a11/PySocks-1.7.1.tar.gz", hash = "sha256:3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0", size = 284429 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8d/59/b4572118e098ac8e46e399a1dd0f2d85403ce8bbaad9ec79373ed6badaf9/PySocks-1.7.1-py3-none-any.whl", hash = "sha256:2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5", size = 16725 }, +] + +[[package]] +name = "pytest" +version = "8.3.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/05/35/30e0d83068951d90a01852cb1cef56e5d8a09d20c7f511634cc2f7e0372a/pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761", size = 1445919 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/11/92/76a1c94d3afee238333bc0a42b82935dd8f9cf8ce9e336ff87ee14d9e1cf/pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6", size = 343083 }, +] + +[[package]] +name = "pytest-cache" +version = "1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "execnet" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d1/15/082fd0428aab33d2bafa014f3beb241830427ba803a8912a5aaeaf3a5663/pytest-cache-1.0.tar.gz", hash = "sha256:be7468edd4d3d83f1e844959fd6e3fd28e77a481440a7118d430130ea31b07a9", size = 16242 } + +[[package]] +name = "pytest-cov" +version = "5.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "coverage", extra = ["toml"] }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/74/67/00efc8d11b630c56f15f4ad9c7f9223f1e5ec275aaae3fa9118c6a223ad2/pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857", size = 63042 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/3a/af5b4fa5961d9a1e6237b530eb87dd04aea6eb83da09d2a4073d81b54ccf/pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652", size = 21990 }, +] + +[[package]] +name = "pytest-django" +version = "4.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/02/c0/43c8b2528c24d7f1a48a47e3f7381f5ab2ae8c64634b0c3f4bd843063955/pytest_django-4.9.0.tar.gz", hash = "sha256:8bf7bc358c9ae6f6fc51b6cebb190fe20212196e6807121f11bd6a3b03428314", size = 84067 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/47/fe/54f387ee1b41c9ad59e48fb8368a361fad0600fe404315e31a12bacaea7d/pytest_django-4.9.0-py3-none-any.whl", hash = "sha256:1d83692cb39188682dbb419ff0393867e9904094a549a7d38a3154d5731b2b99", size = 23723 }, +] + +[[package]] +name = "pytest-echo" +version = "1.7.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/37/0e/a5dcb4a634dcbdba8a97d1201c8c8a95405e6f504e055e1e9a10e4b939d3/pytest-echo-1.7.3.tar.gz", hash = "sha256:2307af560ebbdc77967579e577f24015467fbcf80cabb9b04d225348bb8d9474", size = 13948 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/af/d2/155f0ffc8d5c1091c9b5aaec93325c4729b2474e00729f1ac320310268cc/pytest_echo-1.7.3-py2.py3-none-any.whl", hash = "sha256:683f4d2fef8dd701aeaf47db834ccc114d43f580abcfea53f3ce2ffe8166c3c0", size = 5744 }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892 }, +] + +[[package]] +name = "pytz" +version = "2025.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5f/57/df1c9157c8d5a05117e455d66fd7cf6dbc46974f832b1058ed4856785d8a/pytz-2025.1.tar.gz", hash = "sha256:c2db42be2a2518b28e65f9207c4d05e6ff547d1efa4086469ef855e4ab70178e", size = 319617 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/eb/38/ac33370d784287baa1c3d538978b5e2ea064d4c1b93ffbd12826c190dd10/pytz-2025.1-py2.py3-none-any.whl", hash = "sha256:89dd22dca55b46eac6eda23b2d72721bf1bdfef212645d81513ef5d03038de57", size = 507930 }, +] + +[[package]] +name = "readme" +version = "0.7.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "readme-renderer" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e2/b5/831f3f29e64107a4222d7156a45f81bfdc6f0f29af9af96f3fe173a5d060/readme-0.7.1.tar.gz", hash = "sha256:32fbe1538a437da160fa4e4477270bfdcd8876e2e364d0d12898302644496231", size = 5914 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/9e/0efa8ecac772ad87a5674f8f8eb8e5939e45e95f48e7efa18415b160cd80/readme-0.7.1-py2.py3-none-any.whl", hash = "sha256:37482f34fc20bff7e4ad8a42f726dc902250d27a52e1196bb8fad4bdcfdcbbe4", size = 2988 }, +] + +[[package]] +name = "readme-renderer" +version = "43.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "docutils", version = "0.20.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13'" }, + { name = "docutils", version = "0.21.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13'" }, + { name = "nh3" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fe/b5/536c775084d239df6345dccf9b043419c7e3308bc31be4c7882196abc62e/readme_renderer-43.0.tar.gz", hash = "sha256:1818dd28140813509eeed8d62687f7cd4f7bad90d4db586001c5dc09d4fde311", size = 31768 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/45/be/3ea20dc38b9db08387cf97997a85a7d51527ea2057d71118feb0aa8afa55/readme_renderer-43.0-py3-none-any.whl", hash = "sha256:19db308d86ecd60e5affa3b2a98f017af384678c63c88e5d4556a380e674f3f9", size = 13301 }, +] + +[[package]] +name = "redis" +version = "5.2.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "async-timeout", marker = "python_full_version < '3.11.3'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/47/da/d283a37303a995cd36f8b92db85135153dc4f7a8e4441aa827721b442cfb/redis-5.2.1.tar.gz", hash = "sha256:16f2e22dff21d5125e8481515e386711a34cbec50f0e44413dd7d9c060a54e0f", size = 4608355 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/5f/fa26b9b2672cbe30e07d9a5bdf39cf16e3b80b42916757c5f92bca88e4ba/redis-5.2.1-py3-none-any.whl", hash = "sha256:ee7e1056b9aea0f04c6c2ed59452947f34c4940ee025f5dd83e6a6418b6989e4", size = 261502 }, +] + +[[package]] +name = "ruff" +version = "0.9.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c0/17/529e78f49fc6f8076f50d985edd9a2cf011d1dbadb1cdeacc1d12afc1d26/ruff-0.9.4.tar.gz", hash = "sha256:6907ee3529244bb0ed066683e075f09285b38dd5b4039370df6ff06041ca19e7", size = 3599458 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b6/f8/3fafb7804d82e0699a122101b5bee5f0d6e17c3a806dcbc527bb7d3f5b7a/ruff-0.9.4-py3-none-linux_armv6l.whl", hash = "sha256:64e73d25b954f71ff100bb70f39f1ee09e880728efb4250c632ceed4e4cdf706", size = 11668400 }, + { url = "https://files.pythonhosted.org/packages/2e/a6/2efa772d335da48a70ab2c6bb41a096c8517ca43c086ea672d51079e3d1f/ruff-0.9.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6ce6743ed64d9afab4fafeaea70d3631b4d4b28b592db21a5c2d1f0ef52934bf", size = 11628395 }, + { url = "https://files.pythonhosted.org/packages/dc/d7/cd822437561082f1c9d7225cc0d0fbb4bad117ad7ac3c41cd5d7f0fa948c/ruff-0.9.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:54499fb08408e32b57360f6f9de7157a5fec24ad79cb3f42ef2c3f3f728dfe2b", size = 11090052 }, + { url = "https://files.pythonhosted.org/packages/9e/67/3660d58e893d470abb9a13f679223368ff1684a4ef40f254a0157f51b448/ruff-0.9.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37c892540108314a6f01f105040b5106aeb829fa5fb0561d2dcaf71485021137", size = 11882221 }, + { url = "https://files.pythonhosted.org/packages/79/d1/757559995c8ba5f14dfec4459ef2dd3fcea82ac43bc4e7c7bf47484180c0/ruff-0.9.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:de9edf2ce4b9ddf43fd93e20ef635a900e25f622f87ed6e3047a664d0e8f810e", size = 11424862 }, + { url = "https://files.pythonhosted.org/packages/c0/96/7915a7c6877bb734caa6a2af424045baf6419f685632469643dbd8eb2958/ruff-0.9.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:87c90c32357c74f11deb7fbb065126d91771b207bf9bfaaee01277ca59b574ec", size = 12626735 }, + { url = "https://files.pythonhosted.org/packages/0e/cc/dadb9b35473d7cb17c7ffe4737b4377aeec519a446ee8514123ff4a26091/ruff-0.9.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:56acd6c694da3695a7461cc55775f3a409c3815ac467279dfa126061d84b314b", size = 13255976 }, + { url = "https://files.pythonhosted.org/packages/5f/c3/ad2dd59d3cabbc12df308cced780f9c14367f0321e7800ca0fe52849da4c/ruff-0.9.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e0c93e7d47ed951b9394cf352d6695b31498e68fd5782d6cbc282425655f687a", size = 12752262 }, + { url = "https://files.pythonhosted.org/packages/c7/17/5f1971e54bd71604da6788efd84d66d789362b1105e17e5ccc53bba0289b/ruff-0.9.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1d4c8772670aecf037d1bf7a07c39106574d143b26cfe5ed1787d2f31e800214", size = 14401648 }, + { url = "https://files.pythonhosted.org/packages/30/24/6200b13ea611b83260501b6955b764bb320e23b2b75884c60ee7d3f0b68e/ruff-0.9.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfc5f1d7afeda8d5d37660eeca6d389b142d7f2b5a1ab659d9214ebd0e025231", size = 12414702 }, + { url = "https://files.pythonhosted.org/packages/34/cb/f5d50d0c4ecdcc7670e348bd0b11878154bc4617f3fdd1e8ad5297c0d0ba/ruff-0.9.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:faa935fc00ae854d8b638c16a5f1ce881bc3f67446957dd6f2af440a5fc8526b", size = 11859608 }, + { url = "https://files.pythonhosted.org/packages/d6/f4/9c8499ae8426da48363bbb78d081b817b0f64a9305f9b7f87eab2a8fb2c1/ruff-0.9.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:a6c634fc6f5a0ceae1ab3e13c58183978185d131a29c425e4eaa9f40afe1e6d6", size = 11485702 }, + { url = "https://files.pythonhosted.org/packages/18/59/30490e483e804ccaa8147dd78c52e44ff96e1c30b5a95d69a63163cdb15b/ruff-0.9.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:433dedf6ddfdec7f1ac7575ec1eb9844fa60c4c8c2f8887a070672b8d353d34c", size = 12067782 }, + { url = "https://files.pythonhosted.org/packages/3d/8c/893fa9551760b2f8eb2a351b603e96f15af167ceaf27e27ad873570bc04c/ruff-0.9.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:d612dbd0f3a919a8cc1d12037168bfa536862066808960e0cc901404b77968f0", size = 12483087 }, + { url = "https://files.pythonhosted.org/packages/23/15/f6751c07c21ca10e3f4a51ea495ca975ad936d780c347d9808bcedbd7182/ruff-0.9.4-py3-none-win32.whl", hash = "sha256:db1192ddda2200671f9ef61d9597fcef89d934f5d1705e571a93a67fb13a4402", size = 9852302 }, + { url = "https://files.pythonhosted.org/packages/12/41/2d2d2c6a72e62566f730e49254f602dfed23019c33b5b21ea8f8917315a1/ruff-0.9.4-py3-none-win_amd64.whl", hash = "sha256:05bebf4cdbe3ef75430d26c375773978950bbf4ee3c95ccb5448940dc092408e", size = 10850051 }, + { url = "https://files.pythonhosted.org/packages/c6/e6/3d6ec3bc3d254e7f005c543a661a41c3e788976d0e52a1ada195bd664344/ruff-0.9.4-py3-none-win_arm64.whl", hash = "sha256:585792f1e81509e38ac5123492f8875fbc36f3ede8185af0a26df348e5154f41", size = 10078251 }, +] + +[[package]] +name = "selenium" +version = "4.27.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "trio" }, + { name = "trio-websocket" }, + { name = "typing-extensions" }, + { name = "urllib3", extra = ["socks"] }, + { name = "websocket-client" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/44/8c/62c47c91072aa03af1c3b7d7f1c59b987db41c9fec0f158fb03a0da51aa6/selenium-4.27.1.tar.gz", hash = "sha256:5296c425a75ff1b44d0d5199042b36a6d1ef76c04fb775b97b40be739a9caae2", size = 973526 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a6/1e/5f1a5dd2a28528c4b3ec6e076b58e4c035810c805328f9936123283ca14e/selenium-4.27.1-py3-none-any.whl", hash = "sha256:b89b1f62b5cfe8025868556fe82360d6b649d464f75d2655cb966c8f8447ea18", size = 9707007 }, +] + +[[package]] +name = "setuptools" +version = "75.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ed/22/a438e0caa4576f8c383fa4d35f1cc01655a46c75be358960d815bfbb12bd/setuptools-75.3.0.tar.gz", hash = "sha256:fba5dd4d766e97be1b1681d98712680ae8f2f26d7881245f2ce9e40714f1a686", size = 1351577 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/90/12/282ee9bce8b58130cb762fbc9beabd531549952cac11fc56add11dcb7ea0/setuptools-75.3.0-py3-none-any.whl", hash = "sha256:f2504966861356aa38616760c0f66568e535562374995367b4e69c7143cf6bcd", size = 1251070 }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050 }, +] + +[[package]] +name = "sniffio" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, +] + +[[package]] +name = "sortedcontainers" +version = "2.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575 }, +] + +[[package]] +name = "soupsieve" +version = "2.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/ce/fbaeed4f9fb8b2daa961f90591662df6a86c1abf25c548329a86920aedfb/soupsieve-2.6.tar.gz", hash = "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb", size = 101569 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/c2/fe97d779f3ef3b15f05c94a2f1e3d21732574ed441687474db9d342a7315/soupsieve-2.6-py3-none-any.whl", hash = "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9", size = 36186 }, +] + +[[package]] +name = "tomli" +version = "2.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/18/87/302344fed471e44a87289cf4967697d07e532f2421fdaf868a303cbae4ff/tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", size = 17175 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/ca/75707e6efa2b37c77dadb324ae7d9571cb424e61ea73fad7c56c2d14527f/tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", size = 131077 }, + { url = "https://files.pythonhosted.org/packages/c7/16/51ae563a8615d472fdbffc43a3f3d46588c264ac4f024f63f01283becfbb/tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6", size = 123429 }, + { url = "https://files.pythonhosted.org/packages/f1/dd/4f6cd1e7b160041db83c694abc78e100473c15d54620083dbd5aae7b990e/tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a", size = 226067 }, + { url = "https://files.pythonhosted.org/packages/a9/6b/c54ede5dc70d648cc6361eaf429304b02f2871a345bbdd51e993d6cdf550/tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee", size = 236030 }, + { url = "https://files.pythonhosted.org/packages/1f/47/999514fa49cfaf7a92c805a86c3c43f4215621855d151b61c602abb38091/tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e", size = 240898 }, + { url = "https://files.pythonhosted.org/packages/73/41/0a01279a7ae09ee1573b423318e7934674ce06eb33f50936655071d81a24/tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4", size = 229894 }, + { url = "https://files.pythonhosted.org/packages/55/18/5d8bc5b0a0362311ce4d18830a5d28943667599a60d20118074ea1b01bb7/tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106", size = 245319 }, + { url = "https://files.pythonhosted.org/packages/92/a3/7ade0576d17f3cdf5ff44d61390d4b3febb8a9fc2b480c75c47ea048c646/tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8", size = 238273 }, + { url = "https://files.pythonhosted.org/packages/72/6f/fa64ef058ac1446a1e51110c375339b3ec6be245af9d14c87c4a6412dd32/tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff", size = 98310 }, + { url = "https://files.pythonhosted.org/packages/6a/1c/4a2dcde4a51b81be3530565e92eda625d94dafb46dbeb15069df4caffc34/tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b", size = 108309 }, + { url = "https://files.pythonhosted.org/packages/52/e1/f8af4c2fcde17500422858155aeb0d7e93477a0d59a98e56cbfe75070fd0/tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea", size = 132762 }, + { url = "https://files.pythonhosted.org/packages/03/b8/152c68bb84fc00396b83e7bbddd5ec0bd3dd409db4195e2a9b3e398ad2e3/tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8", size = 123453 }, + { url = "https://files.pythonhosted.org/packages/c8/d6/fc9267af9166f79ac528ff7e8c55c8181ded34eb4b0e93daa767b8841573/tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192", size = 233486 }, + { url = "https://files.pythonhosted.org/packages/5c/51/51c3f2884d7bab89af25f678447ea7d297b53b5a3b5730a7cb2ef6069f07/tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222", size = 242349 }, + { url = "https://files.pythonhosted.org/packages/ab/df/bfa89627d13a5cc22402e441e8a931ef2108403db390ff3345c05253935e/tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77", size = 252159 }, + { url = "https://files.pythonhosted.org/packages/9e/6e/fa2b916dced65763a5168c6ccb91066f7639bdc88b48adda990db10c8c0b/tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6", size = 237243 }, + { url = "https://files.pythonhosted.org/packages/b4/04/885d3b1f650e1153cbb93a6a9782c58a972b94ea4483ae4ac5cedd5e4a09/tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd", size = 259645 }, + { url = "https://files.pythonhosted.org/packages/9c/de/6b432d66e986e501586da298e28ebeefd3edc2c780f3ad73d22566034239/tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e", size = 244584 }, + { url = "https://files.pythonhosted.org/packages/1c/9a/47c0449b98e6e7d1be6cbac02f93dd79003234ddc4aaab6ba07a9a7482e2/tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98", size = 98875 }, + { url = "https://files.pythonhosted.org/packages/ef/60/9b9638f081c6f1261e2688bd487625cd1e660d0a85bd469e91d8db969734/tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4", size = 109418 }, + { url = "https://files.pythonhosted.org/packages/04/90/2ee5f2e0362cb8a0b6499dc44f4d7d48f8fff06d28ba46e6f1eaa61a1388/tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7", size = 132708 }, + { url = "https://files.pythonhosted.org/packages/c0/ec/46b4108816de6b385141f082ba99e315501ccd0a2ea23db4a100dd3990ea/tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c", size = 123582 }, + { url = "https://files.pythonhosted.org/packages/a0/bd/b470466d0137b37b68d24556c38a0cc819e8febe392d5b199dcd7f578365/tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13", size = 232543 }, + { url = "https://files.pythonhosted.org/packages/d9/e5/82e80ff3b751373f7cead2815bcbe2d51c895b3c990686741a8e56ec42ab/tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281", size = 241691 }, + { url = "https://files.pythonhosted.org/packages/05/7e/2a110bc2713557d6a1bfb06af23dd01e7dde52b6ee7dadc589868f9abfac/tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272", size = 251170 }, + { url = "https://files.pythonhosted.org/packages/64/7b/22d713946efe00e0adbcdfd6d1aa119ae03fd0b60ebed51ebb3fa9f5a2e5/tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140", size = 236530 }, + { url = "https://files.pythonhosted.org/packages/38/31/3a76f67da4b0cf37b742ca76beaf819dca0ebef26d78fc794a576e08accf/tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2", size = 258666 }, + { url = "https://files.pythonhosted.org/packages/07/10/5af1293da642aded87e8a988753945d0cf7e00a9452d3911dd3bb354c9e2/tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744", size = 243954 }, + { url = "https://files.pythonhosted.org/packages/5b/b9/1ed31d167be802da0fc95020d04cd27b7d7065cc6fbefdd2f9186f60d7bd/tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec", size = 98724 }, + { url = "https://files.pythonhosted.org/packages/c7/32/b0963458706accd9afcfeb867c0f9175a741bf7b19cd424230714d722198/tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69", size = 109383 }, + { url = "https://files.pythonhosted.org/packages/6e/c2/61d3e0f47e2b74ef40a68b9e6ad5984f6241a942f7cd3bbfbdbd03861ea9/tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", size = 14257 }, +] + +[[package]] +name = "tox" +version = "4.24.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cachetools" }, + { name = "chardet" }, + { name = "colorama" }, + { name = "filelock" }, + { name = "packaging" }, + { name = "platformdirs" }, + { name = "pluggy" }, + { name = "pyproject-api" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, + { name = "virtualenv" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cf/7b/97f757e159983737bdd8fb513f4c263cd411a846684814ed5433434a1fa9/tox-4.24.1.tar.gz", hash = "sha256:083a720adbc6166fff0b7d1df9d154f9d00bfccb9403b8abf6bc0ee435d6a62e", size = 194742 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ab/04/b0d1c1b44c98583cab9eabb4acdba964fdf6b6c597c53cfb8870fd08cbbf/tox-4.24.1-py3-none-any.whl", hash = "sha256:57ba7df7d199002c6df8c2db9e6484f3de6ca8f42013c083ea2d4d1e5c6bdc75", size = 171829 }, +] + +[[package]] +name = "trio" +version = "0.27.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "cffi", marker = "implementation_name != 'pypy' and os_name == 'nt'" }, + { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, + { name = "idna" }, + { name = "outcome" }, + { name = "sniffio" }, + { name = "sortedcontainers" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/17/d1/a83dee5be404da7afe5a71783a33b8907bacb935a6dc8c69ab785e4a3eed/trio-0.27.0.tar.gz", hash = "sha256:1dcc95ab1726b2da054afea8fd761af74bad79bd52381b84eae408e983c76831", size = 568064 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/83/ec3196c360afffbc5b342ead48d1eb7393dd74fa70bca75d33905a86f211/trio-0.27.0-py3-none-any.whl", hash = "sha256:68eabbcf8f457d925df62da780eff15ff5dc68fd6b367e2dde59f7aaf2a0b884", size = 481734 }, +] + +[[package]] +name = "trio-websocket" +version = "0.11.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, + { name = "trio" }, + { name = "wsproto" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/dd/36/abad2385853077424a11b818d9fd8350d249d9e31d583cb9c11cd4c85eda/trio-websocket-0.11.1.tar.gz", hash = "sha256:18c11793647703c158b1f6e62de638acada927344d534e3c7628eedcb746839f", size = 26511 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/48/be/a9ae5f50cad5b6f85bd2574c2c923730098530096e170c1ce7452394d7aa/trio_websocket-0.11.1-py3-none-any.whl", hash = "sha256:520d046b0d030cf970b8b2b2e00c4c2245b3807853ecd44214acd33d74581638", size = 17408 }, +] + +[[package]] +name = "typing-extensions" +version = "4.12.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 }, +] + +[[package]] +name = "tzdata" +version = "2025.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/0f/fa4723f22942480be4ca9527bbde8d43f6c3f2fe8412f00e7f5f6746bc8b/tzdata-2025.1.tar.gz", hash = "sha256:24894909e88cdb28bd1636c6887801df64cb485bd593f2fd83ef29075a81d694", size = 194950 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0f/dd/84f10e23edd882c6f968c21c2434fe67bd4a528967067515feca9e611e5e/tzdata-2025.1-py2.py3-none-any.whl", hash = "sha256:7e127113816800496f027041c570f50bcd464a020098a3b6b199517772303639", size = 346762 }, +] + +[[package]] +name = "urllib3" +version = "2.2.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ed/63/22ba4ebfe7430b76388e7cd448d5478814d3032121827c12a2cc287e2260/urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9", size = 300677 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac", size = 126338 }, +] + +[package.optional-dependencies] +socks = [ + { name = "pysocks" }, +] + +[[package]] +name = "vine" +version = "5.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bd/e4/d07b5f29d283596b9727dd5275ccbceb63c44a1a82aa9e4bfd20426762ac/vine-5.1.0.tar.gz", hash = "sha256:8b62e981d35c41049211cf62a0a1242d8c1ee9bd15bb196ce38aefd6799e61e0", size = 48980 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/03/ff/7c0c86c43b3cbb927e0ccc0255cb4057ceba4799cd44ae95174ce8e8b5b2/vine-5.1.0-py3-none-any.whl", hash = "sha256:40fdf3c48b2cfe1c38a49e9ae2da6fda88e4794c810050a728bd7413811fb1dc", size = 9636 }, +] + +[[package]] +name = "virtualenv" +version = "20.29.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "distlib" }, + { name = "filelock" }, + { name = "platformdirs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a7/ca/f23dcb02e161a9bba141b1c08aa50e8da6ea25e6d780528f1d385a3efe25/virtualenv-20.29.1.tar.gz", hash = "sha256:b8b8970138d32fb606192cb97f6cd4bb644fa486be9308fb9b63f81091b5dc35", size = 7658028 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/89/9b/599bcfc7064fbe5740919e78c5df18e5dceb0887e676256a1061bb5ae232/virtualenv-20.29.1-py3-none-any.whl", hash = "sha256:4e4cb403c0b0da39e13b46b1b2476e505cb0046b25f242bee80f62bf990b2779", size = 4282379 }, +] + +[[package]] +name = "waitress" +version = "3.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/70/34/cb77e5249c433eb177a11ab7425056b32d3b57855377fa1e38b397412859/waitress-3.0.0.tar.gz", hash = "sha256:005da479b04134cdd9dd602d1ee7c49d79de0537610d653674cc6cbde222b8a1", size = 179393 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5b/a9/485c953a1ac4cb98c28e41fd2c7184072df36bbf99734a51d44d04176878/waitress-3.0.0-py3-none-any.whl", hash = "sha256:2a06f242f4ba0cc563444ca3d1998959447477363a2d7e9b8b4d75d35cfd1669", size = 56698 }, +] + +[[package]] +name = "wcwidth" +version = "0.2.13" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6c/63/53559446a878410fc5a5974feb13d31d78d752eb18aeba59c7fef1af7598/wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5", size = 101301 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859", size = 34166 }, +] + +[[package]] +name = "webob" +version = "1.8.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "legacy-cgi", marker = "python_full_version >= '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/85/0b/1732085540b01f65e4e7999e15864fe14cd18b12a95731a43fd6fd11b26a/webob-1.8.9.tar.gz", hash = "sha256:ad6078e2edb6766d1334ec3dee072ac6a7f95b1e32ce10def8ff7f0f02d56589", size = 279775 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/50/bd/c336448be43d40be28e71f2e0f3caf7ccb28e2755c58f4c02c065bfe3e8e/WebOb-1.8.9-py2.py3-none-any.whl", hash = "sha256:45e34c58ed0c7e2ecd238ffd34432487ff13d9ad459ddfd77895e67abba7c1f9", size = 115364 }, +] + +[[package]] +name = "websocket-client" +version = "1.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e6/30/fba0d96b4b5fbf5948ed3f4681f7da2f9f64512e1d303f94b4cc174c24a5/websocket_client-1.8.0.tar.gz", hash = "sha256:3239df9f44da632f96012472805d40a23281a991027ce11d2f45a6f24ac4c3da", size = 54648 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/84/44687a29792a70e111c5c477230a72c4b957d88d16141199bf9acb7537a3/websocket_client-1.8.0-py3-none-any.whl", hash = "sha256:17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526", size = 58826 }, +] + +[[package]] +name = "webtest" +version = "3.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "beautifulsoup4" }, + { name = "waitress" }, + { name = "webob" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/20/7e/7534c43c97234d0b5c9f228bb9646c4611e0fa33c2cefeb2e968be96d27e/webtest-3.0.1.tar.gz", hash = "sha256:493b5c802f8948a65b5e3a1ad5b2524ee5e1ab60cd713d9a3da3b8da082c06fe", size = 79278 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2b/6d/075023456a2ff8e01ef07afa069563f0d1e1a2fd359d7dbd7672a5bf218a/WebTest-3.0.1-py3-none-any.whl", hash = "sha256:b3bc75d020d0576ee93a5f149666045e58fe2400ea5f0c214d7430d7d213d0d0", size = 32154 }, +] + +[[package]] +name = "wsproto" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c9/4a/44d3c295350d776427904d73c189e10aeae66d7f555bb2feee16d1e4ba5a/wsproto-1.2.0.tar.gz", hash = "sha256:ad565f26ecb92588a3e43bc3d96164de84cd9902482b130d0ddbaa9664a85065", size = 53425 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/58/e860788190eba3bcce367f74d29c4675466ce8dddfba85f7827588416f01/wsproto-1.2.0-py3-none-any.whl", hash = "sha256:b9acddd652b585d75b20477888c56642fdade28bdfd3579aa24a4d2c037dd736", size = 24226 }, +] + +[[package]] +name = "xlrd" +version = "2.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a6/b3/19a2540d21dea5f908304375bd43f5ed7a4c28a370dc9122c565423e6b44/xlrd-2.0.1.tar.gz", hash = "sha256:f72f148f54442c6b056bf931dbc34f986fd0c3b0b6b5a58d013c9aef274d0c88", size = 100259 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a6/0c/c2a72d51fe56e08a08acc85d13013558a2d793028ae7385448a6ccdfae64/xlrd-2.0.1-py2.py3-none-any.whl", hash = "sha256:6a33ee89877bd9abc1158129f6e94be74e2679636b8a205b43b85206c3f0bbdd", size = 96531 }, +] + +[[package]] +name = "xlwt" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/06/97/56a6f56ce44578a69343449aa5a0d98eefe04085d69da539f3034e2cd5c1/xlwt-1.3.0.tar.gz", hash = "sha256:c59912717a9b28f1a3c2a98fd60741014b06b043936dcecbc113eaaada156c88", size = 153929 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/44/48/def306413b25c3d01753603b1a222a011b8621aed27cd7f89cbc27e6b0f4/xlwt-1.3.0-py2.py3-none-any.whl", hash = "sha256:a082260524678ba48a297d922cc385f58278b8aa68741596a87de01a9c628b2e", size = 99981 }, +] + +[[package]] +name = "zipp" +version = "3.20.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/54/bf/5c0000c44ebc80123ecbdddba1f5dcd94a5ada602a9c225d84b5aaa55e86/zipp-3.20.2.tar.gz", hash = "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29", size = 24199 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/8b/5ba542fa83c90e09eac972fc9baca7a88e7e7ca4b221a89251954019308b/zipp-3.20.2-py3-none-any.whl", hash = "sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350", size = 9200 }, +]