diff --git a/.contrib/docker/Dockerfile.gulp b/.contrib/docker/Dockerfile.gulp deleted file mode 100644 index 925a48457..000000000 --- a/.contrib/docker/Dockerfile.gulp +++ /dev/null @@ -1,4 +0,0 @@ -FROM node:16 -WORKDIR /app -VOLUME /app -CMD ["bash","-c", "npm install && npm rebuild node-sass && npx gulp build"] diff --git a/.contrib/docker/Dockerfile.web b/.contrib/docker/Dockerfile.web deleted file mode 100644 index fb973238a..000000000 --- a/.contrib/docker/Dockerfile.web +++ /dev/null @@ -1,27 +0,0 @@ -# This is Dockerfile for development purposes only. -ARG PYTHON_VERSION='3' -FROM python:${PYTHON_VERSION}-slim -RUN pip install 'pip<20' -RUN mkdir /code /code/production -WORKDIR /code - -# Install python dependencies -ENV PYTHONUNBUFFERED 1 -RUN apt-get update \ -&& apt-get install -y --no-install-recommends \ - default-libmysqlclient-dev \ - gcc \ - build-essential \ - git \ - curl \ - gettext libgettextpo-dev wait-for-it \ -&& rm -rf /var/lib/apt/lists/* -COPY requirements/*.txt ./requirements/ -ARG DJANGO_VERSION='==2.22.*' -# TODO: Move to /requirements/base.txt after fixing following bug: -# https://github.com/readthedocs/readthedocs-docker-images/issues/158 -RUN pip install mysqlclient==2.0.3 -RUN bash -c "if [[ "${DJANGO_VERSION}" == 'master' ]]; then \ -pip install --no-cache-dir -r requirements/dev.txt https://github.com/django/django/archive/master.tar.gz; else \ -pip install --no-cache-dir -r requirements/dev.txt \"django${DJANGO_VERSION}\"; fi" -CMD ["bash", "-c", "python manage.py collectstatic --no-input && python manage.py migrate && python manage.py runserver 0.0.0.0:8000"] diff --git a/.do/deploy.template.yaml b/.do/deploy.template.yaml new file mode 100644 index 000000000..837b51842 --- /dev/null +++ b/.do/deploy.template.yaml @@ -0,0 +1,56 @@ +alerts: +- rule: DEPLOYMENT_FAILED +- rule: DOMAIN_FAILED +name: feder +services: +- dockerfile_path: Dockerfile + envs: + - key: DJANGO_SECRET_KEY + scope: RUN_AND_BUILD_TIME + type: SECRET + value: ... + - key: DJANGO_SERVER_EMAIL + scope: RUN_AND_BUILD_TIME + value: x + - key: DATABASE_URL + scope: RUN_AND_BUILD_TIME + type: SECRET + value: ... + - key: EMAILLABS_APP_KEY + scope: RUN_AND_BUILD_TIME + value: x + - key: EMAILLABS_SECRET_KEY + scope: RUN_AND_BUILD_TIME + type: SECRET + value: ... + - key: LETTER_RECEIVE_SECRET + scope: RUN_AND_BUILD_TIME + type: SECRET + value: ... + - key: AWS_S3_ACCESS_KEY_ID + scope: RUN_AND_BUILD_TIME + value: access-key + - key: AWS_S3_SECRET_ACCESS_KEY + scope: RUN_AND_BUILD_TIME + type: SECRET + value: secret-key + - key: AWS_S3_ENDPOINT_URL + scope: RUN_AND_BUILD_TIME + value: http://minio:9000/ + - key: AWS_STORAGE_BUCKET_NAME + scope: RUN_AND_BUILD_TIME + value: 'feder' + github: + branch: do + deploy_on_push: true + repo: watchdogpolska/feder + health_check: + http_path: / + http_port: 8000 + instance_count: 1 + instance_size_slug: basic-xxs + name: feder + routes: + - path: / + source_dir: / +# TODO: add workers diff --git a/.dockerignore b/.dockerignore index a6ab096cc..ed07c9f57 100644 --- a/.dockerignore +++ b/.dockerignore @@ -5,8 +5,10 @@ node_modules **/*.pyc docs **/*.rst +**/__pycache__ **/*.md media feder/media -feder/staticfiles +feder/static +staticfiles htmlcov diff --git a/.github/workflows/frontend.yml b/.github/workflows/frontend.yml index 6f7f6c39f..149670e88 100644 --- a/.github/workflows/frontend.yml +++ b/.github/workflows/frontend.yml @@ -8,7 +8,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: Build frontend - run: make wait_web regenerate_frontend + run: docker-compose up gulp - name: Show git status run: git status - name: Require rebuild content diff --git a/.github/workflows/web.yml b/.github/workflows/web.yml index 5632742c5..de7e003c9 100644 --- a/.github/workflows/web.yml +++ b/.github/workflows/web.yml @@ -9,6 +9,10 @@ on: jobs: django: runs-on: ubuntu-latest + env: + PYTHON_VERSION: ${{ matrix.python }} + DJANGO_VERSION: ${{ matrix.django }} + METADEFENDER_API_KEY: ${{ secrets.METADEFENDER_API_KEY }} strategy: matrix: python: @@ -23,18 +27,12 @@ jobs: lfs: true - name: Build application run: docker-compose build web - env: - PYTHON_VERSION: ${{ matrix.python }} - DJANGO_VERSION: ${{ matrix.django }} - METADEFENDER_API_KEY: ${{ secrets.METADEFENDER_API_KEY }} - - name: Run side services - run: make wait_mysql wait_elasticsearch wait_tika - name: Migration check run: make check - name: Show settings run: make settings - - name: Build test - run: make test + - name: Run test + run: make test-es # - name: Send coverage report # run: make coverage_send # env: @@ -51,4 +49,4 @@ jobs: if: failure() - name: Show docker process run: docker ps - if: always() + if: always() \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..1b7855b90 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,42 @@ +ARG PYTHON_VERSION='3.6' +FROM python:${PYTHON_VERSION}-slim as build +RUN mkdir /code +WORKDIR /code + +# Install python dependencies +ENV PYTHONUNBUFFERED 1 +RUN apt-get update \ +&& apt-get install -y --no-install-recommends \ + default-libmysqlclient-dev \ + gcc \ + build-essential \ + git \ + curl \ + gettext libgettextpo-dev \ +&& rm -rf /var/lib/apt/lists/* +COPY requirements/*.txt ./requirements/ +ARG DJANGO_VERSION='==2.22.*' +FROM build as development +# TODO: Move to /requirements/base.txt after fixing following bug: +# https://github.com/readthedocs/readthedocs-docker-images/issues/158 +RUN pip install mysqlclient==2.0.3 +RUN bash -c "if [[ \"${DJANGO_VERSION}\" == 'master' ]]; then \ +pip install --no-cache-dir -r requirements/dev.txt https://github.com/django/django/archive/master.tar.gz; else \ +pip install --no-cache-dir -r requirements/dev.txt \"django${DJANGO_VERSION}\"; fi" +COPY ./ /code/ +CMD python manage.py runserver 0.0.0.0:8000 +FROM build as production +ENV DJANGO_SETTINGS_MODULE="config.settings.production" +RUN pip install --no-cache-dir mysqlclient==2.0.3 -r requirements/production.txt +COPY ./ /code/ +RUN mkdir -p /code/feder/static && DJANGO_SECRET_KEY=x \ + DJANGO_SERVER_EMAIL=x \ + DATABASE_URL=sqlite:// \ + EMAILLABS_APP_KEY=x \ + EMAILLABS_SECRET_KEY=x \ + LETTER_RECEIVE_SECRET=x \ + AWS_S3_ACCESS_KEY_ID=x \ + AWS_S3_SECRET_ACCESS_KEY=x \ + AWS_STORAGE_BUCKET_NAME=x \ + python manage.py collectstatic --no-input +CMD ["gunicorn", "--worker-tmp-dir", "/dev/shm", "--capture-output", "config.wsgi"] diff --git a/Makefile b/Makefile index b6760a314..91ed83aef 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,6 @@ clean: docker-compose down regenerate_frontend: - docker-compose run web python manage.py collectstatic -c --noinput docker-compose up gulp build: @@ -15,28 +14,17 @@ build: test: docker-compose run web coverage run manage.py test --keepdb --verbosity=2 ${TEST} +test-es: + docker-compose -f docker-compose.yml -f docker-compose.es.yml run python manage.py test --keepdb --verbosity=2 ${TEST} + coverage_html: docker-compose run web coverage html coverage_send: docker-compose run -e GITHUB_ACTIONS -e GITHUB_REF -e GITHUB_SHA -e GITHUB_HEAD_REF -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -e GITHUB_TOKEN -e COVERALLS_REPO_TOKEN web coveralls -wait_web: wait_mysql wait_elasticsearch wait_tika - -wait_mysql: - docker-compose up -d db - docker-compose run web bash -c 'wait-for-it -t 30 db:3306' || (docker-compose logs db; exit -1) - -wait_elasticsearch: - docker-compose up -d elasticsearch - docker-compose run web bash -c 'wait-for-it -t 30 elasticsearch:9200' || (docker-compose logs elasticsearch; exit -1) - -wait_tika: - docker-compose up -d tika - docker-compose run web bash -c 'wait-for-it -t 60 tika:9998' || (docker-compose logs tika; exit -1) - migrate: - docker-compose run web python manage.py migrate + docker-compose up migration lint: # lint currently staged files pre-commit run @@ -44,10 +32,10 @@ lint: # lint currently staged files lint-all: # lint all files in repository pre-commit run --all-files -check: wait_mysql +check: docker-compose run web python manage.py makemigrations --check -migrations: wait_mysql +migrations: docker-compose run web python manage.py makemigrations settings: diff --git a/README.rst b/README.rst index d5b16a001..d0c0b704d 100644 --- a/README.rst +++ b/README.rst @@ -10,6 +10,10 @@ :target: https://david-dm.org/watchdogpolska/feder#info=devDependencies :alt: devDependency Status + .. image:: https://www.deploytodo.com/do-btn-blue.svg + :target: https://cloud.digitalocean.com/apps/new?repo=https://github.com/watchdogpolska/feder/tree/do + :alt: Deploy to DO + Feder ===== diff --git a/config/settings/common.py b/config/settings/common.py index f7cbf50f4..ae69530a5 100644 --- a/config/settings/common.py +++ b/config/settings/common.py @@ -98,6 +98,7 @@ "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", "reversion.middleware.RevisionMiddleware", + "whitenoise.middleware.WhiteNoiseMiddleware", ) # MIGRATIONS CONFIGURATION @@ -316,8 +317,6 @@ INSTALLED_APPS += ("github_revision",) GITHUB_REVISION_REPO_URL = "https://github.com/watchdogpolska/feder" -SENDFILE_BACKEND = "django_sendfile.backends.development" -SENDFILE_ROOT = MEDIA_ROOT DATA_UPLOAD_MAX_MEMORY_SIZE = 200000000 # 200MB @@ -358,3 +357,8 @@ APACHE_TIKA_URL = env("APACHE_TIKA_URL", default="http://localhost:9998/tika") ELASTICSEARCH_SHOW_SIMILAR = env("ELASTICSEARCH_SHOW_SIMILAR", default=False) +DEFAULT_FILE_STORAGE = "storages.backends.s3boto3.S3Boto3Storage" +AWS_ACCESS_KEY_ID = env("AWS_S3_ACCESS_KEY_ID") +AWS_SECRET_ACCESS_KEY = env("AWS_S3_SECRET_ACCESS_KEY") +AWS_STORAGE_BUCKET_NAME = env("AWS_STORAGE_BUCKET_NAME") +AWS_S3_ENDPOINT_URL = env("AWS_S3_ENDPOINT_URL", default=None) diff --git a/config/settings/production.py b/config/settings/production.py index cd9f4d102..d11e256a8 100644 --- a/config/settings/production.py +++ b/config/settings/production.py @@ -40,10 +40,7 @@ # Uploaded Media Files # ------------------------ # See: http://django-storages.readthedocs.org/en/latest/index.html -SENDFILE_BACKEND = "django_sendfile.backends.nginx" MEDIA_URL = "/media_internal/" -SENDFILE_ROOT = MEDIA_ROOT -SENDFILE_URL = MEDIA_URL # EMAIL # ------------------------------------------------------------------------------ diff --git a/docker-compose.es.yml b/docker-compose.es.yml new file mode 100644 index 000000000..0e74f6537 --- /dev/null +++ b/docker-compose.es.yml @@ -0,0 +1,29 @@ +version: '3.1' +# To play with this file use following command: +# $ docker-compose -f docker-compose.yml docker-compose.es.yml up + +services: + web: + environment: &webEnvironment + DATABASE_URL: mysql://root:password@db/feder + ELASTICSEARCH_URL: http://elasticsearch:9200/ + APACHE_TIKA_URL: 'http://tika:9998/' + VIRUSTOTAL_API_KEY: + ATTACHMENTSCANNER_API_KEY: + ATTACHMENTSCANNER_API_URL: + METADEFENDER_API_KEY: + + worker: + command: python manage.py process_tasks + environment: *webEnvironment + + elasticsearch: + image: docker.elastic.co/elasticsearch/elasticsearch:7.6.2 + environment: + discovery.type: single-node + cluster.routing.allocation.disk.threshold_enabled: 'false' + ports: + - "9200:9200" + + tika: + image: quay.io/watchdogpolska/apache-tika \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 6bfc61331..b2a26196b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,12 @@ -version: '2.1' +version: '3.1' # This is application’s services configuration for development purposes only. +x-node: &node + image: node:15 + working_dir: /app + volumes: + - .:/app + services: db: image: mysql:5.7 @@ -12,34 +18,56 @@ services: MYSQL_DATABASE: feder volumes: - mysql-data:/var/lib/mysql - + healthcheck: + test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"] + timeout: 20s + retries: 10 + # Services to regenerate frontend + # Regenerated front-end is stored in project directory on host + npm: + <<: *node + command: sh -c 'id && npm install --unsafe-perm && npm rebuild --unsafe-perm node-sass' gulp: - build: - context: . - dockerfile: .contrib/docker/Dockerfile.gulp + <<: *node + command: npx gulp build ports: - "35729:35729" - volumes: - - .:/app + depends_on: + npm: + condition: service_completed_successfully + collectstatic: + condition: service_completed_successfully + # Services for Django application web: build: &webBuild + target: development context: . - dockerfile: .contrib/docker/Dockerfile.web args: # Match to production environment - PYTHON_VERSION: '${PYTHON_VERSION:-3.6.9}' + PYTHON_VERSION: '${PYTHON_VERSION:-3.7}' DJANGO_VERSION: '${DJANGO_VERSION:-==2.2.*}' volumes: &webVolumes - .:/code environment: &webEnvironment DATABASE_URL: mysql://root:password@db/feder - ELASTICSEARCH_URL: http://elasticsearch:9200/ - APACHE_TIKA_URL: 'http://tika:9998/' VIRUSTOTAL_API_KEY: ATTACHMENTSCANNER_API_KEY: ATTACHMENTSCANNER_API_URL: METADEFENDER_API_KEY: + AWS_S3_ACCESS_KEY_ID: &s3-access access-key + AWS_S3_SECRET_ACCESS_KEY: &s3-secret secret-key + AWS_S3_ENDPOINT_URL: http://minio:9000/ + AWS_STORAGE_BUCKET_NAME: 'feder' + depends_on: + migration: + condition: service_completed_successfully + collectstatic: + condition: service_completed_successfully + db: + condition: service_healthy + minio: + condition: service_healthy ports: - "8000:8000" # Following allows to execute `docker attach feder_web_1` @@ -52,17 +80,35 @@ services: build: *webBuild volumes: *webVolumes environment: *webEnvironment - - elasticsearch: - image: docker.elastic.co/elasticsearch/elasticsearch:7.6.2 + collectstatic: + command: python manage.py collectstatic --no-input + build: *webBuild + volumes: *webVolumes + environment: *webEnvironment + migration: + command: python manage.py migrate + build: *webBuild + volumes: *webVolumes + environment: *webEnvironment + depends_on: + db: + condition: service_healthy + minio: + image: "minio/minio" + entrypoint: sh + # hack to precreate bucket, see https://github.com/minio/minio/issues/4769 + command: -c 'mkdir -p /data/feder && minio server /data' + restart: always environment: - discovery.type: single-node - cluster.routing.allocation.disk.threshold_enabled: 'false' - ports: - - "9200:9200" - - tika: - image: quay.io/watchdogpolska/apache-tika + MINIO_ACCESS_KEY: *s3-access + MINIO_SECRET_KEY: *s3-secret + volumes: + - "minio-data:/data" + healthcheck: + test: ["CMD", "curl" ,"localhost:9000"] + timeout: 20s + retries: 10 volumes: mysql-data: + minio-data: diff --git a/feder/es_search/tests.py b/feder/es_search/tests.py index fa4ef7785..aa208abd9 100644 --- a/feder/es_search/tests.py +++ b/feder/es_search/tests.py @@ -3,20 +3,18 @@ from django.test import TestCase from ..letters.factories import IncomingLetterFactory, AttachmentFactory from .tasks import index_letter -from time import sleep -from elasticsearch_dsl import Search, Index -from elasticsearch_dsl.query import MultiMatch, Match, Q, MoreLikeThis -from elasticsearch_dsl.connections import get_connection, connections -from elasticsearch.exceptions import ElasticsearchException +from elasticsearch_dsl.connections import get_connection from .documents import LetterDocument from django.core.management import call_command -import time from collections.abc import Iterable -from elasticsearch.exceptions import ConflictError from .queries import more_like_this, search_keywords, find_document, delete_document -import time +from unittest import skipIf +from .settings import ELASTICSEARCH_URL +@skipIf( + not ELASTICSEARCH_URL, "Elasticsearch disabled. Set ELASTICSEARCH_URL to enable" +) class ESMixin: connection_alias = "default" _index_suffix = "_test" diff --git a/feder/letters/factories.py b/feder/letters/factories.py index 2f2e5791b..e3c00a4af 100644 --- a/feder/letters/factories.py +++ b/feder/letters/factories.py @@ -43,7 +43,7 @@ class FileTextField(FileField): DEFAULT_FILENAME = "content.txt" def _make_data(self, params): - return params.get("text", get_text()) + return params.get("text", get_text().encode("utf-8")) class LetterFactory(factory.django.DjangoModelFactory): diff --git a/feder/letters/migrations/0027_auto_20211004_0220.py b/feder/letters/migrations/0027_auto_20211004_0220.py new file mode 100644 index 000000000..c8cd17fc1 --- /dev/null +++ b/feder/letters/migrations/0027_auto_20211004_0220.py @@ -0,0 +1,24 @@ +# Generated by Django 2.2.24 on 2021-10-04 02:20 + +from django.db import migrations, models +import feder.letters.models + + +class Migration(migrations.Migration): + + dependencies = [ + ("letters", "0026_auto_20210505_1327"), + ] + + operations = [ + migrations.AlterField( + model_name="letter", + name="eml", + field=models.FileField( + blank=True, + null=True, + upload_to=feder.letters.models.messages_eml, + verbose_name="File", + ), + ), + ] diff --git a/feder/letters/models.py b/feder/letters/models.py index f8f6d6e1d..af93fe6f5 100644 --- a/feder/letters/models.py +++ b/feder/letters/models.py @@ -25,6 +25,7 @@ from django.utils import timezone from ..es_search.queries import more_like_this, find_document from feder.cases.models import enforce_quarantined_queryset +from feder.main.utils import date_random_path logger = logging.getLogger(__name__) @@ -90,6 +91,10 @@ def get_queryset(self): ) +def messages_eml(): + return date_random_path("messages")() + + class Letter(AbstractRecord): SPAM = Choices( (0, "unknown", _("Unknown")), @@ -158,7 +163,10 @@ class Letter(AbstractRecord): max_length=500, ) eml = models.FileField( - upload_to="messages/%Y/%m/%d", verbose_name=_("File"), null=True, blank=True + upload_to=messages_eml, + verbose_name=_("File"), + null=True, + blank=True, ) objects = LetterManager() objects_with_spam = LetterQuerySet.as_manager() diff --git a/feder/letters/tests/test_views.py b/feder/letters/tests/test_views.py index 221dec846..543ea0f7a 100644 --- a/feder/letters/tests/test_views.py +++ b/feder/letters/tests/test_views.py @@ -1,7 +1,7 @@ import codecs import json import os - +import requests from django.core import mail from django.core.files.base import ContentFile from django.core.files.uploadedfile import SimpleUploadedFile @@ -71,7 +71,7 @@ def test_content(self): self.assertContains(response, "Wniosek") -class LetterDetailViewTestCase(ESMixin, ObjectMixin, PermissionStatusMixin, TestCase): +class LetterDetailViewTestCase(ObjectMixin, PermissionStatusMixin, TestCase): status_anonymous = 200 status_no_permission = 200 permission = [] @@ -109,6 +109,21 @@ def test_contains_link_to_attachment(self): self.client.get(self.get_url()), attachment.get_absolute_url() ) + +class IndexLetterDetailViewTestCase(ESMixin, LetterDetailViewTestCase): + def test_contains_link_to_attachment(self): + attachment = AttachmentFactory(letter=self.letter) + self.assertNotContains( + self.client.get(self.get_url()), attachment.get_absolute_url() + ) + AttachmentRequestFactory( + content_object=attachment, + status=ScanRequest.STATUS.not_detected, + ) + self.assertContains( + self.client.get(self.get_url()), attachment.get_absolute_url() + ) + def test_not_contain_link_to_similiar_on_disabled(self): similiar = IncomingLetterFactory(body=self.letter.body) self.index([similiar, self.letter]) @@ -144,9 +159,9 @@ def test_contain_link_to_similiar_on_enabled(self): class LetterMessageXSendFileView(PermissionStatusMixin, TestCase): permission = [] - status_has_permission = 200 - status_anonymous = 200 - status_no_permission = 200 + status_has_permission = 302 + status_anonymous = 302 + status_no_permission = 302 def setUp(self): super().setUp() @@ -200,19 +215,23 @@ class LetterDeleteViewTestCase(ObjectMixin, PermissionStatusMixin, TransactionTe def get_url(self): return reverse("letters:delete", kwargs={"pk": self.from_user.pk}) + def check_url(self, url): + resp = requests.get(url) + return resp.status_code == 200 + def test_remove_eml_file(self): self.login_permitted_user() - self.assertTrue(os.path.isfile(self.from_user.eml.file.name)) + self.assertTrue(self.check_url(self.from_user.eml.url)) self.client.post(self.get_url()) - self.assertFalse(os.path.isfile(self.from_user.eml.file.name)) + self.assertFalse(self.check_url(self.from_user.eml.url)) def test_remove_letter_with_attachment(self): # TransactionTestCase has to be used to test file cleanup feature. self.login_permitted_user() attachment = AttachmentFactory(letter=self.from_user) - self.assertTrue(os.path.isfile(attachment.attachment.file.name)) + self.assertTrue(self.check_url(attachment.attachment.url)) self.client.post(self.get_url()) - self.assertFalse(os.path.isfile(attachment.attachment.file.name)) + self.assertFalse(self.check_url(attachment.attachment.url)) class LetterReplyViewTestCase(ObjectMixin, PermissionStatusMixin, TestCase): @@ -309,7 +328,7 @@ def get_url(self): return reverse("letters:atom") def test_item_enclosure_url(self): - self.from_institution.eml.save("msg.eml", ContentFile("Foo"), save=True) + self.from_institution.eml.save("msg.eml", ContentFile(b"Foo"), save=True) resp = self.client.get(self.get_url()) self.assertContains(resp, self.from_institution.eml.name) @@ -470,9 +489,9 @@ def get_url(self): class StandardAttachmentXSendFileViewTestCase(PermissionStatusMixin, TestCase): permission = [] - status_has_permission = 200 - status_anonymous = 200 - status_no_permission = 200 + status_has_permission = 302 + status_anonymous = 302 + status_no_permission = 302 spam_status = Letter.SPAM.non_spam def setUp(self): diff --git a/feder/letters/views.py b/feder/letters/views.py index c0f297898..adbfc90aa 100644 --- a/feder/letters/views.py +++ b/feder/letters/views.py @@ -1,6 +1,5 @@ import json import uuid -from os import path from atom.ext.django_filters.views import UserKwargFilterSetMixin from atom.views import ( CreateMessageMixin, @@ -45,7 +44,6 @@ from feder.main.mixins import ( AttrPermissionRequiredMixin, RaisePermissionRequiredMixin, - BaseXSendFileView, ) from feder.monitorings.models import Monitoring from feder.records.models import Record @@ -55,20 +53,11 @@ from .models import Letter, Attachment from feder.monitorings.tasks import send_mass_draft from feder.virus_scan.models import Request as ScanRequest +from feder.main.mixins import BaseDetailFileRedirect _("Letters index") -class MixinGzipXSendFile: - def get_sendfile_kwargs(self, context): - kwargs = super().get_sendfile_kwargs(context) - if kwargs["filename"] and kwargs["filename"].endswith(".gz"): - kwargs["encoding"] = "gzip" - filename = path.basename(kwargs["filename"][: -len(".gz")]) - kwargs["attachment_filename"] = filename - return kwargs - - class CaseRequiredMixin: def get_queryset(self): qs = super().get_queryset().exclude(record__case=None) @@ -142,14 +131,10 @@ def get_queryset(self): return qs.for_user(self.request.user) -class LetterMessageXSendFileView(MixinGzipXSendFile, BaseXSendFileView): +class LetterMessageXSendFileView(BaseDetailFileRedirect): + # todo: rename class to modern model = Letter file_field = "eml" - send_as_attachment = True - - def get_queryset(self): - qs = super().get_queryset() - return qs.for_user(self.request.user) class LetterCreateView( @@ -540,32 +525,22 @@ def form_valid(self, form): return super().form_valid(form) -class AttachmentXSendFileView(MixinGzipXSendFile, BaseXSendFileView): +class AttachmentXSendFileView(BaseDetailFileRedirect): model = Attachment file_field = "attachment" - send_as_attachment = True - def get_queryset(self): - return super().get_queryset().for_user(self.request.user) - - def get_sendfile_kwargs(self, context): - kwargs = super().get_sendfile_kwargs(context) - if kwargs["filename"].endswith(".gz"): - kwargs["encoding"] = "gzip" - return kwargs - - def render_to_response(self, context): - if context["object"].is_infected(): + def get(self, *args, **kwargs): + response = super().get(*args, **kwargs) + if self.object.is_infected(): raise PermissionDenied( "You do not have permission to view that file. " "The file was considered dangerous." ) - return super().render_to_response(context) + return response class AttachmentRequestCreateView(ActionMessageMixin, ActionView): template_name_suffix = "_request_scan" - model = Attachment def get_object(self, *args, **kwargs): if not hasattr(self, "object"): diff --git a/feder/main/mixins.py b/feder/main/mixins.py index b76ea4f65..1f84191dc 100644 --- a/feder/main/mixins.py +++ b/feder/main/mixins.py @@ -4,12 +4,11 @@ from braces.views import LoginRequiredMixin from django.core.exceptions import ImproperlyConfigured from django.core.paginator import EmptyPage, Paginator -from django.views.generic.detail import BaseDetailView from guardian.mixins import PermissionRequiredMixin -from django_sendfile import sendfile from django.core.paginator import InvalidPage from rest_framework_csv.renderers import CSVRenderer - +from django.views.generic import RedirectView +from django.shortcuts import get_object_or_404 from .paginator import ModernPerformantPaginator from django.http import Http404 from django.utils.translation import ugettext as _ @@ -152,25 +151,17 @@ def check_enabled(self, form_data): return not any(form_data[field] for field in self.disabled_when) -class BaseXSendFileView(BaseDetailView): - file_field = None - send_as_attachment = None - - def get_file_field(self): - return self.file_field - - def get_file_path(self, object): - return getattr(object, self.get_file_field()).path +class BaseDetailFileRedirect(RedirectView): + model = None + file_field = "attachment" - def get_sendfile_kwargs(self, context): - return dict( - request=self.request, - filename=self.get_file_path(context["object"]), - attachment=self.send_as_attachment, - ) + def get_queryset(self): + return self.model.objects.for_user(self.request.user) - def render_to_response(self, context): - return sendfile(**self.get_sendfile_kwargs(context)) + def get_redirect_url(self, *args, **kwargs): + self.object = get_object_or_404(self.get_queryset(), pk=self.kwargs["pk"]) + fileobj = getattr(self.object, self.file_field) + return fileobj.url class DisableOrderingListViewMixin: diff --git a/feder/main/urls.py b/feder/main/urls.py index dcba2e6c9..b1dcaf471 100644 --- a/feder/main/urls.py +++ b/feder/main/urls.py @@ -96,10 +96,11 @@ ] if settings.DEBUG: - import debug_toolbar - - urlpatterns = [url(r"^__debug__/", include(debug_toolbar.urls))] + urlpatterns - + try: + import debug_toolbar + urlpatterns = [url(r"^__debug__/", include(debug_toolbar.urls))] + urlpatterns + except ImportError: + pass def handler500(request): """500 error handler which includes ``request`` in the context. diff --git a/feder/main/utils.py b/feder/main/utils.py index 9c05cee25..d0a6ca890 100644 --- a/feder/main/utils.py +++ b/feder/main/utils.py @@ -1,5 +1,9 @@ from rest_framework_csv.renderers import CSVStreamingRenderer from django.contrib.sites.shortcuts import get_current_site +import random +import string + +from django.utils.timezone import now def get_full_url_for_context(path, context): @@ -20,3 +24,23 @@ def render(self, data, *args, **kwargs): if not isinstance(data, list): data = data.get(self.results_field, []) return super().render(data, *args, **kwargs) + + +def prefix_gen( + size=10, chars=string.ascii_uppercase + string.digits + string.ascii_lowercase +): + return "".join(random.choice(chars) for _ in range(size)) + + +def date_random_path(prefix): + def helper(instance, filename): + return "{prefix}/{y}/{m}/{d}/{r}/{f}".format( + prefix=prefix, + y=now().year, + m=now().month, + d=now().day, + r=prefix_gen(), + f=filename[-320:], + ) + + return helper diff --git a/feder/parcels/migrations/0003_auto_20211004_0220.py b/feder/parcels/migrations/0003_auto_20211004_0220.py new file mode 100644 index 000000000..59ee86a0b --- /dev/null +++ b/feder/parcels/migrations/0003_auto_20211004_0220.py @@ -0,0 +1,28 @@ +# Generated by Django 2.2.24 on 2021-10-04 02:20 + +from django.db import migrations, models +import feder.parcels.models + + +class Migration(migrations.Migration): + + dependencies = [ + ("parcels", "0002_auto_20181021_0220"), + ] + + operations = [ + migrations.AlterField( + model_name="incomingparcelpost", + name="content", + field=models.FileField( + upload_to=feder.parcels.models.parcel_upload_to, verbose_name="Content" + ), + ), + migrations.AlterField( + model_name="outgoingparcelpost", + name="content", + field=models.FileField( + upload_to=feder.parcels.models.parcel_upload_to, verbose_name="Content" + ), + ), + ] diff --git a/feder/parcels/models.py b/feder/parcels/models.py index 4e511c089..9c75c3940 100644 --- a/feder/parcels/models.py +++ b/feder/parcels/models.py @@ -6,7 +6,7 @@ from django.dispatch import receiver from django.urls import reverse from django.utils.translation import ugettext_lazy as _ - +from feder.main.utils import date_random_path from feder.institutions.models import Institution from feder.records.models import AbstractRecord from feder.cases.models import enforce_quarantined_queryset @@ -17,9 +17,13 @@ def for_user(self, user): return enforce_quarantined_queryset(self, user, "record__case") +def parcel_upload_to(): + return date_random_path("parcel")() + + class AbstractParcelPost(AbstractRecord): title = models.CharField(verbose_name=_("Title"), max_length=200) - content = models.FileField(verbose_name=_("Content")) + content = models.FileField(upload_to=parcel_upload_to, verbose_name=_("Content")) created_by = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.CASCADE, help_text=_("Created by") ) diff --git a/feder/parcels/tests/test_views.py b/feder/parcels/tests/test_views.py index c14a27e9c..d31e01824 100644 --- a/feder/parcels/tests/test_views.py +++ b/feder/parcels/tests/test_views.py @@ -82,8 +82,9 @@ class IncomingAttachmentParcelPostXSendFileViewTestCase( IncomingParcelPostMixin, PermissionStatusMixin, TestCase ): permission = [] - status_anonymous = 200 - status_no_permission = 200 + status_anonymous = 302 + status_no_permission = 302 + status_has_permission = 302 def get_url(self): return reverse("parcels:incoming-download", kwargs={"pk": self.object.pk}) @@ -93,8 +94,9 @@ class OutgoingAttachmentParcelPostXSendFileViewTestCase( OutgoingParcelPostMixin, PermissionStatusMixin, TestCase ): permission = [] - status_anonymous = 200 - status_no_permission = 200 + status_anonymous = 302 + status_no_permission = 302 + status_has_permission = 302 def get_url(self): return reverse("parcels:outgoing-download", kwargs={"pk": self.object.pk}) diff --git a/feder/parcels/views.py b/feder/parcels/views.py index 93ec0597f..0ae8c40f4 100644 --- a/feder/parcels/views.py +++ b/feder/parcels/views.py @@ -11,7 +11,7 @@ from django.utils.translation import ugettext_lazy as _ from feder.cases.models import Case -from feder.main.mixins import RaisePermissionRequiredMixin, BaseXSendFileView +from feder.main.mixins import RaisePermissionRequiredMixin, BaseDetailFileRedirect from feder.parcels.forms import IncomingParcelPostForm, OutgoingParcelPostForm from feder.parcels.models import IncomingParcelPost, OutgoingParcelPost @@ -154,12 +154,8 @@ class OutgoingParcelPostDeleteView(ParcelPostDeleteView): model = OutgoingParcelPost -class AttachmentParcelPostXSendFileView(BaseXSendFileView): +class AttachmentParcelPostXSendFileView(BaseDetailFileRedirect): file_field = "content" - send_as_attachment = True - - def get_queryset(self): - return super().get_queryset().for_user(self.request.user) class OutgoingAttachmentParcelPostXSendFileView(AttachmentParcelPostXSendFileView): diff --git a/feder/static/js/script.js b/feder/static/js/script.js index bfc419e68..5c2b5c7e0 100644 --- a/feder/static/js/script.js +++ b/feder/static/js/script.js @@ -1,15 +1,15 @@ /*! - * jQuery JavaScript Library v3.5.1 + * jQuery JavaScript Library v3.6.0 * https://jquery.com/ * * Includes Sizzle.js * https://sizzlejs.com/ * - * Copyright JS Foundation and other contributors + * Copyright OpenJS Foundation and other contributors * Released under the MIT license * https://jquery.org/license * - * Date: 2020-05-04T22:49Z + * Date: 2021-03-02T17:08Z */ ( function( global, factory ) { @@ -76,12 +76,16 @@ var support = {}; var isFunction = function isFunction( obj ) { - // Support: Chrome <=57, Firefox <=52 - // In some browsers, typeof returns "function" for HTML elements - // (i.e., `typeof document.createElement( "object" ) === "function"`). - // We don't want to classify *any* DOM node as a function. - return typeof obj === "function" && typeof obj.nodeType !== "number"; - }; + // Support: Chrome <=57, Firefox <=52 + // In some browsers, typeof returns "function" for HTML elements + // (i.e., `typeof document.createElement( "object" ) === "function"`). + // We don't want to classify *any* DOM node as a function. + // Support: QtWeb <=3.8.5, WebKit <=534.34, wkhtmltopdf tool <=0.12.5 + // Plus for old WebKit, typeof returns "function" for HTML collections + // (e.g., `typeof document.getElementsByTagName("div") === "function"`). (gh-4756) + return typeof obj === "function" && typeof obj.nodeType !== "number" && + typeof obj.item !== "function"; + }; var isWindow = function isWindow( obj ) { @@ -147,7 +151,7 @@ function toType( obj ) { var - version = "3.5.1", + version = "3.6.0", // Define a local copy of jQuery jQuery = function( selector, context ) { @@ -401,7 +405,7 @@ jQuery.extend( { if ( isArrayLike( Object( arr ) ) ) { jQuery.merge( ret, typeof arr === "string" ? - [ arr ] : arr + [ arr ] : arr ); } else { push.call( ret, arr ); @@ -496,9 +500,9 @@ if ( typeof Symbol === "function" ) { // Populate the class2type map jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), -function( _i, name ) { - class2type[ "[object " + name + "]" ] = name.toLowerCase(); -} ); + function( _i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); + } ); function isArrayLike( obj ) { @@ -518,14 +522,14 @@ function isArrayLike( obj ) { } var Sizzle = /*! - * Sizzle CSS Selector Engine v2.3.5 + * Sizzle CSS Selector Engine v2.3.6 * https://sizzlejs.com/ * * Copyright JS Foundation and other contributors * Released under the MIT license * https://js.foundation/ * - * Date: 2020-03-14 + * Date: 2021-02-16 */ ( function( window ) { var i, @@ -1108,8 +1112,8 @@ support = Sizzle.support = {}; * @returns {Boolean} True iff elem is a non-HTML XML node */ isXML = Sizzle.isXML = function( elem ) { - var namespace = elem.namespaceURI, - docElem = ( elem.ownerDocument || elem ).documentElement; + var namespace = elem && elem.namespaceURI, + docElem = elem && ( elem.ownerDocument || elem ).documentElement; // Support: IE <=8 // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes @@ -3024,9 +3028,9 @@ var rneedsContext = jQuery.expr.match.needsContext; function nodeName( elem, name ) { - return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); -}; +} var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); @@ -3997,8 +4001,8 @@ jQuery.extend( { resolveContexts = Array( i ), resolveValues = slice.call( arguments ), - // the master Deferred - master = jQuery.Deferred(), + // the primary Deferred + primary = jQuery.Deferred(), // subordinate callback factory updateFunc = function( i ) { @@ -4006,30 +4010,30 @@ jQuery.extend( { resolveContexts[ i ] = this; resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; if ( !( --remaining ) ) { - master.resolveWith( resolveContexts, resolveValues ); + primary.resolveWith( resolveContexts, resolveValues ); } }; }; // Single- and empty arguments are adopted like Promise.resolve if ( remaining <= 1 ) { - adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, + adoptValue( singleValue, primary.done( updateFunc( i ) ).resolve, primary.reject, !remaining ); // Use .then() to unwrap secondary thenables (cf. gh-3000) - if ( master.state() === "pending" || + if ( primary.state() === "pending" || isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { - return master.then(); + return primary.then(); } } // Multiple arguments are aggregated like Promise.all array elements while ( i-- ) { - adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); + adoptValue( resolveValues[ i ], updateFunc( i ), primary.reject ); } - return master.promise(); + return primary.promise(); } } ); @@ -4180,8 +4184,8 @@ var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { for ( ; i < len; i++ ) { fn( elems[ i ], key, raw ? - value : - value.call( elems[ i ], i, fn( elems[ i ], key ) ) + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) ); } } @@ -5089,10 +5093,7 @@ function buildFragment( elems, context, scripts, selection, ignored ) { } -var - rkeyEvent = /^key/, - rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, - rtypenamespace = /^([^.]*)(?:\.(.+)|)/; +var rtypenamespace = /^([^.]*)(?:\.(.+)|)/; function returnTrue() { return true; @@ -5387,8 +5388,8 @@ jQuery.event = { event = jQuery.event.fix( nativeEvent ), handlers = ( - dataPriv.get( this, "events" ) || Object.create( null ) - )[ event.type ] || [], + dataPriv.get( this, "events" ) || Object.create( null ) + )[ event.type ] || [], special = jQuery.event.special[ event.type ] || {}; // Use the fix-ed jQuery.Event rather than the (read-only) native event @@ -5512,12 +5513,12 @@ jQuery.event = { get: isFunction( hook ) ? function() { if ( this.originalEvent ) { - return hook( this.originalEvent ); + return hook( this.originalEvent ); } } : function() { if ( this.originalEvent ) { - return this.originalEvent[ name ]; + return this.originalEvent[ name ]; } }, @@ -5656,7 +5657,13 @@ function leverageNative( el, type, expectSync ) { // Cancel the outer synthetic event event.stopImmediatePropagation(); event.preventDefault(); - return result.value; + + // Support: Chrome 86+ + // In Chrome, if an element having a focusout handler is blurred by + // clicking outside of it, it invokes the handler synchronously. If + // that handler calls `.remove()` on the element, the data is cleared, + // leaving `result` undefined. We need to guard against this. + return result && result.value; } // If this is an inner synthetic event for an event with a bubbling surrogate @@ -5821,34 +5828,7 @@ jQuery.each( { targetTouches: true, toElement: true, touches: true, - - which: function( event ) { - var button = event.button; - - // Add which for key events - if ( event.which == null && rkeyEvent.test( event.type ) ) { - return event.charCode != null ? event.charCode : event.keyCode; - } - - // Add which for click: 1 === left; 2 === middle; 3 === right - if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { - if ( button & 1 ) { - return 1; - } - - if ( button & 2 ) { - return 3; - } - - if ( button & 4 ) { - return 2; - } - - return 0; - } - - return event.which; - } + which: true }, jQuery.event.addProp ); jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) { @@ -5874,6 +5854,12 @@ jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateTyp return true; }, + // Suppress native focus or blur as it's already being fired + // in leverageNative. + _default: function() { + return true; + }, + delegateType: delegateType }; } ); @@ -6541,6 +6527,10 @@ var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); // set in CSS while `offset*` properties report correct values. // Behavior in IE 9 is more subtle than in newer versions & it passes // some versions of this test; make sure not to make it pass there! + // + // Support: Firefox 70+ + // Only Firefox includes border widths + // in computed dimensions. (gh-4529) reliableTrDimensions: function() { var table, tr, trChild, trStyle; if ( reliableTrDimensionsVal == null ) { @@ -6548,17 +6538,32 @@ var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); tr = document.createElement( "tr" ); trChild = document.createElement( "div" ); - table.style.cssText = "position:absolute;left:-11111px"; + table.style.cssText = "position:absolute;left:-11111px;border-collapse:separate"; + tr.style.cssText = "border:1px solid"; + + // Support: Chrome 86+ + // Height set through cssText does not get applied. + // Computed height then comes back as 0. tr.style.height = "1px"; trChild.style.height = "9px"; + // Support: Android 8 Chrome 86+ + // In our bodyBackground.html iframe, + // display for all div elements is set to "inline", + // which causes a problem only in Android 8 Chrome 86. + // Ensuring the div is display: block + // gets around this issue. + trChild.style.display = "block"; + documentElement .appendChild( table ) .appendChild( tr ) .appendChild( trChild ); trStyle = window.getComputedStyle( tr ); - reliableTrDimensionsVal = parseInt( trStyle.height ) > 3; + reliableTrDimensionsVal = ( parseInt( trStyle.height, 10 ) + + parseInt( trStyle.borderTopWidth, 10 ) + + parseInt( trStyle.borderBottomWidth, 10 ) ) === tr.offsetHeight; documentElement.removeChild( table ); } @@ -7022,10 +7027,10 @@ jQuery.each( [ "height", "width" ], function( _i, dimension ) { // Running getBoundingClientRect on a disconnected node // in IE throws an error. ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? - swap( elem, cssShow, function() { - return getWidthOrHeight( elem, dimension, extra ); - } ) : - getWidthOrHeight( elem, dimension, extra ); + swap( elem, cssShow, function() { + return getWidthOrHeight( elem, dimension, extra ); + } ) : + getWidthOrHeight( elem, dimension, extra ); } }, @@ -7084,7 +7089,7 @@ jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, swap( elem, { marginLeft: 0 }, function() { return elem.getBoundingClientRect().left; } ) - ) + "px"; + ) + "px"; } } ); @@ -7223,7 +7228,7 @@ Tween.propHooks = { if ( jQuery.fx.step[ tween.prop ] ) { jQuery.fx.step[ tween.prop ]( tween ); } else if ( tween.elem.nodeType === 1 && ( - jQuery.cssHooks[ tween.prop ] || + jQuery.cssHooks[ tween.prop ] || tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) { jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); } else { @@ -7468,7 +7473,7 @@ function defaultPrefilter( elem, props, opts ) { anim.done( function() { - /* eslint-enable no-loop-func */ + /* eslint-enable no-loop-func */ // The final step of a "hide" animation is actually hiding the element if ( !hidden ) { @@ -7588,7 +7593,7 @@ function Animation( elem, properties, options ) { tweens: [], createTween: function( prop, end ) { var tween = jQuery.Tween( elem, animation.opts, prop, end, - animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.opts.specialEasing[ prop ] || animation.opts.easing ); animation.tweens.push( tween ); return tween; }, @@ -7761,7 +7766,8 @@ jQuery.fn.extend( { anim.stop( true ); } }; - doAnimation.finish = doAnimation; + + doAnimation.finish = doAnimation; return empty || optall.queue === false ? this.each( doAnimation ) : @@ -8401,8 +8407,8 @@ jQuery.fn.extend( { if ( this.setAttribute ) { this.setAttribute( "class", className || value === false ? - "" : - dataPriv.get( this, "__className__" ) || "" + "" : + dataPriv.get( this, "__className__" ) || "" ); } } @@ -8417,7 +8423,7 @@ jQuery.fn.extend( { while ( ( elem = this[ i++ ] ) ) { if ( elem.nodeType === 1 && ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { - return true; + return true; } } @@ -8707,9 +8713,7 @@ jQuery.extend( jQuery.event, { special.bindType || type; // jQuery handler - handle = ( - dataPriv.get( cur, "events" ) || Object.create( null ) - )[ event.type ] && + handle = ( dataPriv.get( cur, "events" ) || Object.create( null ) )[ event.type ] && dataPriv.get( cur, "handle" ); if ( handle ) { handle.apply( cur, data ); @@ -8856,7 +8860,7 @@ var rquery = ( /\?/ ); // Cross-browser xml parsing jQuery.parseXML = function( data ) { - var xml; + var xml, parserErrorElem; if ( !data || typeof data !== "string" ) { return null; } @@ -8865,12 +8869,17 @@ jQuery.parseXML = function( data ) { // IE throws on parseFromString with invalid input. try { xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); - } catch ( e ) { - xml = undefined; - } + } catch ( e ) {} - if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { - jQuery.error( "Invalid XML: " + data ); + parserErrorElem = xml && xml.getElementsByTagName( "parsererror" )[ 0 ]; + if ( !xml || parserErrorElem ) { + jQuery.error( "Invalid XML: " + ( + parserErrorElem ? + jQuery.map( parserErrorElem.childNodes, function( el ) { + return el.textContent; + } ).join( "\n" ) : + data + ) ); } return xml; }; @@ -8971,16 +8980,14 @@ jQuery.fn.extend( { // Can add propHook for "elements" to filter or add form elements var elements = jQuery.prop( this, "elements" ); return elements ? jQuery.makeArray( elements ) : this; - } ) - .filter( function() { + } ).filter( function() { var type = this.type; // Use .is( ":disabled" ) so that fieldset[disabled] works return this.name && !jQuery( this ).is( ":disabled" ) && rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && ( this.checked || !rcheckableType.test( type ) ); - } ) - .map( function( _i, elem ) { + } ).map( function( _i, elem ) { var val = jQuery( this ).val(); if ( val == null ) { @@ -9033,7 +9040,8 @@ var // Anchor tag for parsing the document origin originAnchor = document.createElement( "a" ); - originAnchor.href = location.href; + +originAnchor.href = location.href; // Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport function addToPrefiltersOrTransports( structure ) { @@ -9414,8 +9422,8 @@ jQuery.extend( { // Context for global events is callbackContext if it is a DOM node or jQuery collection globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ? - jQuery( callbackContext ) : - jQuery.event, + jQuery( callbackContext ) : + jQuery.event, // Deferreds deferred = jQuery.Deferred(), @@ -9727,8 +9735,10 @@ jQuery.extend( { response = ajaxHandleResponses( s, jqXHR, responses ); } - // Use a noop converter for missing script - if ( !isSuccess && jQuery.inArray( "script", s.dataTypes ) > -1 ) { + // Use a noop converter for missing script but not if jsonp + if ( !isSuccess && + jQuery.inArray( "script", s.dataTypes ) > -1 && + jQuery.inArray( "json", s.dataTypes ) < 0 ) { s.converters[ "text script" ] = function() {}; } @@ -10466,12 +10476,6 @@ jQuery.offset = { options.using.call( elem, props ); } else { - if ( typeof props.top === "number" ) { - props.top += "px"; - } - if ( typeof props.left === "number" ) { - props.left += "px"; - } curElem.css( props ); } } @@ -10640,8 +10644,11 @@ jQuery.each( [ "top", "left" ], function( _i, prop ) { // Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods jQuery.each( { Height: "height", Width: "width" }, function( name, type ) { - jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, - function( defaultExtra, funcName ) { + jQuery.each( { + padding: "inner" + name, + content: type, + "": "outer" + name + }, function( defaultExtra, funcName ) { // Margin is only for outerHeight, outerWidth jQuery.fn[ funcName ] = function( margin, value ) { @@ -10726,7 +10733,8 @@ jQuery.fn.extend( { } } ); -jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " + +jQuery.each( + ( "blur focus focusin focusout resize scroll click dblclick " + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + "change select submit keydown keypress keyup contextmenu" ).split( " " ), function( _i, name ) { @@ -10737,7 +10745,8 @@ jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " + this.on( name, null, data, fn ) : this.trigger( name ); }; - } ); + } +); diff --git a/feder/static/js/script.min.js b/feder/static/js/script.min.js index 8056009fb..aef393871 100644 --- a/feder/static/js/script.min.js +++ b/feder/static/js/script.min.js @@ -1 +1 @@ -!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";function g(e){return null!=e&&e===e.window}var t=[],r=Object.getPrototypeOf,s=t.slice,v=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},l=t.push,i=t.indexOf,n={},o=n.toString,m=n.hasOwnProperty,a=m.toString,u=a.call(Object),y={},b=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function x(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.5.1",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!b(e)&&!g(e)&&("array"===n||0===t||"number"==typeof t&&0>10|55296,1023&n|56320))}function i(){T()}var e,d,x,o,a,h,p,g,w,l,u,T,C,s,E,v,c,m,y,S="sizzle"+1*new Date,b=n.document,k=0,r=0,A=le(),N=le(),D=le(),j=le(),L=function(e,t){return e===t&&(u=!0),0},$={}.hasOwnProperty,t=[],O=t.pop,q=t.push,H=t.push,I=t.slice,P=function(e,t){for(var n=0,r=e.length;n+~]|"+M+")"+M+"*"),X=new RegExp(M+"|>"),Q=new RegExp(B),G=new RegExp("^"+F+"$"),Y={ID:new RegExp("^#("+F+")"),CLASS:new RegExp("^\\.("+F+")"),TAG:new RegExp("^("+F+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+B),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},J=/HTML$/i,K=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,ee=/^[^{]+\{\s*\[native \w/,te=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ne=/[+~]/,re=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ie=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,oe=function(e,t){return t?"\0"===e?"�":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},ae=xe(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=I.call(b.childNodes),b.childNodes),t[b.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){q.apply(e,I.call(t))}:function(e,t){for(var n=e.length,r=0;e[n++]=t[r++];);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,l,u,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(l=te.exec(t)))if(i=l[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(l[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=l[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!j[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(X.test(t)||V.test(t))){for((f=ne.test(t)&&me(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(ie,oe):e.setAttribute("id",s=S)),o=(u=h(t)).length;o--;)u[o]=(s?"#"+s:":scope")+" "+be(u[o]);c=u.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){j(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace(z,"$1"),e,n,r)}function le(){var r=[];return function e(t,n){return r.push(t+" ")>x.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function ue(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){for(var n=e.split("|"),r=n.length;r--;)x.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)for(;n=n.nextSibling;)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return ue(function(o){return o=+o,ue(function(e,t){for(var n,r=a([],e.length,o),i=r.length;i--;)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function me(e){return e&&void 0!==e.getElementsByTagName&&e}for(e in d=se.support={},a=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!J.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:b;return r!=C&&9===r.nodeType&&r.documentElement&&(s=(C=r).documentElement,E=!a(C),b!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",i,!1):n.attachEvent&&n.attachEvent("onunload",i)),d.scope=ce(function(e){return s.appendChild(e).appendChild(C.createElement("div")),void 0!==e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=ee.test(C.getElementsByClassName),d.getById=ce(function(e){return s.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(x.filter.ID=function(e){var t=e.replace(re,f);return function(e){return e.getAttribute("id")===t}},x.find.ID=function(e,t){if(void 0!==t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(x.filter.ID=function(e){var n=e.replace(re,f);return function(e){var t=void 0!==e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},x.find.ID=function(e,t){if(void 0!==t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];for(i=t.getElementsByName(e),r=0;o=i[r++];)if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),x.find.TAG=d.getElementsByTagName?function(e,t){return void 0!==t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"!==e)return o;for(;n=o[i++];)1===n.nodeType&&r.push(n);return r},x.find.CLASS=d.getElementsByClassName&&function(e,t){if(void 0!==t.getElementsByClassName&&E)return t.getElementsByClassName(e)},c=[],v=[],(d.qsa=ee.test(C.querySelectorAll))&&(ce(function(e){var t;s.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),s.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=ee.test(m=s.matches||s.webkitMatchesSelector||s.mozMatchesSelector||s.oMatchesSelector||s.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=m.call(e,"*"),m.call(e,"[s!='']:x"),c.push("!=",B)}),v=v.length&&new RegExp(v.join("|")),c=c.length&&new RegExp(c.join("|")),t=ee.test(s.compareDocumentPosition),y=t||ee.test(s.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)for(;t=t.parentNode;)if(t===e)return!0;return!1},L=t?function(e,t){if(e===t)return u=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==b&&y(b,e)?-1:t==C||t.ownerDocument==b&&y(b,t)?1:l?P(l,e)-P(l,t):0:4&n?-1:1)}:function(e,t){if(e===t)return u=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:l?P(l,e)-P(l,t):0;if(i===o)return pe(e,t);for(n=e;n=n.parentNode;)a.unshift(n);for(n=t;n=n.parentNode;)s.unshift(n);for(;a[r]===s[r];)r++;return r?pe(a[r],s[r]):a[r]==b?-1:s[r]==b?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!j[t+" "]&&(!c||!c.test(t))&&(!v||!v.test(t)))try{var n=m.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){j(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(re,f),e[3]=(e[3]||e[4]||e[5]||"").replace(re,f),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return Y.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&Q.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(re,f).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=A[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&A(e,function(e){return t.test("string"==typeof e.className&&e.className||void 0!==e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function D(e,n,r){return b(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||j,"string"!=typeof e)return e.nodeType?(this[0]=e,this.length=1,this):b(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this);if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:L.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)b(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}).prototype=S.fn,j=S(E);var $=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function q(e,t){for(;(e=e[t])&&1!==e.nodeType;);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n=void 0!==e.getElementsByTagName?e.getElementsByTagName(t||"*"):void 0!==e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function me(e,t){for(var n=0,r=e.length;n",""]);var ye=/<|&#?\w+;/;function be(e,t,n,r,i){for(var o,a,s,l,u,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function Le(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function $e(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Oe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function qe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(G.hasData(e)&&(s=G.get(e).events))for(i in G.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var tn,nn=[],rn=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=nn.pop()||S.expando+"_"+Ot.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(rn.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&rn.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=b(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(rn,"$1"+r):!1!==e.jsonp&&(e.url+=(qt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,nn.push(r)),o&&b(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((tn=E.implementation.createHTMLDocument("").body).innerHTML="
",2===tn.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=be([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,l,u=S.css(e,"position"),c=S(e),f={};"static"===u&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),l=S.css(e,"left"),i=("absolute"===u||"fixed"===u)&&-1<(o+l).indexOf("auto")?(a=(r=c.position()).top,r.left):(a=parseFloat(o)||0,parseFloat(l)||0),b(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):("number"==typeof f.top&&(f.top+="px"),"number"==typeof f.left&&(f.left+="px"),c.css(f))}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{for(t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position");)e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){for(var e=this.offsetParent;e&&"static"===S.css(e,"position");)e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return B(this,function(e,t,n){var r;if(g(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Ke(y.pixelPosition,function(e,t){if(t)return t=Je(e,n),Ve.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return B(this,function(e,t,n){var r;return g(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0 .active"),i=n&&s.support.transition&&(r.length&&r.hasClass("fade")||!!t.find("> .fade").length);function o(){r.removeClass("active").find("> .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),e.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),i?(e[0].offsetWidth,e.addClass("in")):e.removeClass("fade"),e.parent(".dropdown-menu").length&&e.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),n&&n()}r.length&&i?r.one("bsTransitionEnd",o).emulateTransitionEnd(a.TRANSITION_DURATION):o(),r.removeClass("in")};var e=s.fn.tab;s.fn.tab=t,s.fn.tab.Constructor=a,s.fn.tab.noConflict=function(){return s.fn.tab=e,this};function n(e){e.preventDefault(),t.call(s(this),"show")}s(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',n).on("click.bs.tab.data-api",'[data-toggle="pill"]',n)}(jQuery),function(r){"use strict";r.fn.emulateTransitionEnd=function(e){var t=!1,n=this;r(this).one("bsTransitionEnd",function(){t=!0});return setTimeout(function(){t||r(n).trigger(r.support.transition.end)},e),this},r(function(){r.support.transition=function(){var e=document.createElement("bootstrap"),t={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var n in t)if(void 0!==e.style[n])return{end:t[n]};return!1}(),r.support.transition&&(r.event.special.bsTransitionEnd={bindType:r.support.transition.end,delegateType:r.support.transition.end,handle:function(e){if(r(e.target).is(this))return e.handleObj.handler.apply(this,arguments)}})})}(jQuery),function(a){"use strict";function r(e){a(e).on("click.bs.dropdown",this.toggle)}var s='[data-toggle="dropdown"]';function l(e){var t=e.attr("data-target"),n="#"!==(t=t||(t=e.attr("href"))&&/#[A-Za-z]/.test(t)&&t.replace(/.*(?=#[^\s]*$)/,""))?a(document).find(t):null;return n&&n.length?n:e.parent()}function o(r){r&&3===r.which||(a(".dropdown-backdrop").remove(),a(s).each(function(){var e=a(this),t=l(e),n={relatedTarget:this};t.hasClass("open")&&(r&&"click"==r.type&&/input|textarea/i.test(r.target.tagName)&&a.contains(t[0],r.target)||(t.trigger(r=a.Event("hide.bs.dropdown",n)),r.isDefaultPrevented()||(e.attr("aria-expanded","false"),t.removeClass("open").trigger(a.Event("hidden.bs.dropdown",n)))))}))}r.VERSION="3.4.1",r.prototype.toggle=function(e){var t=a(this);if(!t.is(".disabled, :disabled")){var n=l(t),r=n.hasClass("open");if(o(),!r){"ontouchstart"in document.documentElement&&!n.closest(".navbar-nav").length&&a(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(a(this)).on("click",o);var i={relatedTarget:this};if(n.trigger(e=a.Event("show.bs.dropdown",i)),e.isDefaultPrevented())return;t.trigger("focus").attr("aria-expanded","true"),n.toggleClass("open").trigger(a.Event("shown.bs.dropdown",i))}return!1}},r.prototype.keydown=function(e){if(/(38|40|27|32)/.test(e.which)&&!/input|textarea/i.test(e.target.tagName)){var t=a(this);if(e.preventDefault(),e.stopPropagation(),!t.is(".disabled, :disabled")){var n=l(t),r=n.hasClass("open");if(!r&&27!=e.which||r&&27==e.which)return 27==e.which&&n.find(s).trigger("focus"),t.trigger("click");var i=n.find(".dropdown-menu li:not(.disabled):visible a");if(i.length){var o=i.index(e.target);38==e.which&&0
',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0},sanitize:!0,sanitizeFn:null,whiteList:e},v.prototype.init=function(e,t,n){if(this.enabled=!0,this.type=e,this.$element=g(t),this.options=this.getOptions(n),this.$viewport=this.options.viewport&&g(document).find(g.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport),this.inState={click:!1,hover:!1,focus:!1},this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var r=this.options.trigger.split(" "),i=r.length;i--;){var o=r[i];if("click"==o)this.$element.on("click."+this.type,this.options.selector,g.proxy(this.toggle,this));else if("manual"!=o){var a="hover"==o?"mouseenter":"focusin",s="hover"==o?"mouseleave":"focusout";this.$element.on(a+"."+this.type,this.options.selector,g.proxy(this.enter,this)),this.$element.on(s+"."+this.type,this.options.selector,g.proxy(this.leave,this))}}this.options.selector?this._options=g.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},v.prototype.getDefaults=function(){return v.DEFAULTS},v.prototype.getOptions=function(e){var t=this.$element.data();for(var n in t)t.hasOwnProperty(n)&&-1!==g.inArray(n,r)&&delete t[n];return(e=g.extend({},this.getDefaults(),t,e)).delay&&"number"==typeof e.delay&&(e.delay={show:e.delay,hide:e.delay}),e.sanitize&&(e.template=i(e.template,e.whiteList,e.sanitizeFn)),e},v.prototype.getDelegateOptions=function(){var n={},r=this.getDefaults();return this._options&&g.each(this._options,function(e,t){r[e]!=t&&(n[e]=t)}),n},v.prototype.enter=function(e){var t=e instanceof this.constructor?e:g(e.currentTarget).data("bs."+this.type);if(t||(t=new this.constructor(e.currentTarget,this.getDelegateOptions()),g(e.currentTarget).data("bs."+this.type,t)),e instanceof g.Event&&(t.inState["focusin"==e.type?"focus":"hover"]=!0),t.tip().hasClass("in")||"in"==t.hoverState)t.hoverState="in";else{if(clearTimeout(t.timeout),t.hoverState="in",!t.options.delay||!t.options.delay.show)return t.show();t.timeout=setTimeout(function(){"in"==t.hoverState&&t.show()},t.options.delay.show)}},v.prototype.isInStateTrue=function(){for(var e in this.inState)if(this.inState[e])return!0;return!1},v.prototype.leave=function(e){var t=e instanceof this.constructor?e:g(e.currentTarget).data("bs."+this.type);if(t||(t=new this.constructor(e.currentTarget,this.getDelegateOptions()),g(e.currentTarget).data("bs."+this.type,t)),e instanceof g.Event&&(t.inState["focusout"==e.type?"focus":"hover"]=!1),!t.isInStateTrue()){if(clearTimeout(t.timeout),t.hoverState="out",!t.options.delay||!t.options.delay.hide)return t.hide();t.timeout=setTimeout(function(){"out"==t.hoverState&&t.hide()},t.options.delay.hide)}},v.prototype.show=function(){var e=g.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(e);var t=g.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(e.isDefaultPrevented()||!t)return;var n=this,r=this.tip(),i=this.getUID(this.type);this.setContent(),r.attr("id",i),this.$element.attr("aria-describedby",i),this.options.animation&&r.addClass("fade");var o="function"==typeof this.options.placement?this.options.placement.call(this,r[0],this.$element[0]):this.options.placement,a=/\s?auto?\s?/i,s=a.test(o);s&&(o=o.replace(a,"")||"top"),r.detach().css({top:0,left:0,display:"block"}).addClass(o).data("bs."+this.type,this),this.options.container?r.appendTo(g(document).find(this.options.container)):r.insertAfter(this.$element),this.$element.trigger("inserted.bs."+this.type);var l=this.getPosition(),u=r[0].offsetWidth,c=r[0].offsetHeight;if(s){var f=o,p=this.getPosition(this.$viewport);o="bottom"==o&&l.bottom+c>p.bottom?"top":"top"==o&&l.top-cp.width?"left":"left"==o&&l.left-ua.top+a.height&&(i.top=a.top+a.height-l)}else{var u=t.left-o,c=t.left+o+n;ua.right&&(i.left=a.left+a.width-c)}return i},v.prototype.getTitle=function(){var e=this.$element,t=this.options;return e.attr("data-original-title")||("function"==typeof t.title?t.title.call(e[0]):t.title)},v.prototype.getUID=function(e){for(;e+=~~(1e6*Math.random()),document.getElementById(e););return e},v.prototype.tip=function(){if(!this.$tip&&(this.$tip=g(this.options.template),1!=this.$tip.length))throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!");return this.$tip},v.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},v.prototype.enable=function(){this.enabled=!0},v.prototype.disable=function(){this.enabled=!1},v.prototype.toggleEnabled=function(){this.enabled=!this.enabled},v.prototype.toggle=function(e){var t=this;e&&((t=g(e.currentTarget).data("bs."+this.type))||(t=new this.constructor(e.currentTarget,this.getDelegateOptions()),g(e.currentTarget).data("bs."+this.type,t))),e?(t.inState.click=!t.inState.click,t.isInStateTrue()?t.enter(t):t.leave(t)):t.tip().hasClass("in")?t.leave(t):t.enter(t)},v.prototype.destroy=function(){var e=this;clearTimeout(this.timeout),this.hide(function(){e.$element.off("."+e.type).removeData("bs."+e.type),e.$tip&&e.$tip.detach(),e.$tip=null,e.$arrow=null,e.$viewport=null,e.$element=null})},v.prototype.sanitizeHtml=function(e){return i(e,this.options.whiteList,this.options.sanitizeFn)};var t=g.fn.tooltip;g.fn.tooltip=function(r){return this.each(function(){var e=g(this),t=e.data("bs.tooltip"),n="object"==typeof r&&r;!t&&/destroy|hide/.test(r)||(t||e.data("bs.tooltip",t=new v(this,n)),"string"==typeof r&&t[r]())})},g.fn.tooltip.Constructor=v,g.fn.tooltip.noConflict=function(){return g.fn.tooltip=t,this}}(jQuery),function(a){"use strict";var s=function(e,t){this.$element=a(e),this.options=a.extend({},s.DEFAULTS,t),this.$trigger=a('[data-toggle="collapse"][href="#'+e.id+'"],[data-toggle="collapse"][data-target="#'+e.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};function i(e){var t,n=e.attr("data-target")||(t=e.attr("href"))&&t.replace(/.*(?=#[^\s]+$)/,"");return a(document).find(n)}function l(r){return this.each(function(){var e=a(this),t=e.data("bs.collapse"),n=a.extend({},s.DEFAULTS,e.data(),"object"==typeof r&&r);!t&&n.toggle&&/show|hide/.test(r)&&(n.toggle=!1),t||e.data("bs.collapse",t=new s(this,n)),"string"==typeof r&&t[r]()})}s.VERSION="3.4.1",s.TRANSITION_DURATION=350,s.DEFAULTS={toggle:!0},s.prototype.dimension=function(){return this.$element.hasClass("width")?"width":"height"},s.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var e,t=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(t&&t.length&&(e=t.data("bs.collapse"))&&e.transitioning)){var n=a.Event("show.bs.collapse");if(this.$element.trigger(n),!n.isDefaultPrevented()){t&&t.length&&(l.call(t,"hide"),e||t.data("bs.collapse",null));var r=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[r](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var i=function(){this.$element.removeClass("collapsing").addClass("collapse in")[r](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return i.call(this);var o=a.camelCase(["scroll",r].join("-"));this.$element.one("bsTransitionEnd",a.proxy(i,this)).emulateTransitionEnd(s.TRANSITION_DURATION)[r](this.$element[0][o])}}}},s.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var e=a.Event("hide.bs.collapse");if(this.$element.trigger(e),!e.isDefaultPrevented()){var t=this.dimension();this.$element[t](this.$element[t]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var n=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};if(!a.support.transition)return n.call(this);this.$element[t](0).one("bsTransitionEnd",a.proxy(n,this)).emulateTransitionEnd(s.TRANSITION_DURATION)}}},s.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},s.prototype.getParent=function(){return a(document).find(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(e,t){var n=a(t);this.addAriaAndCollapsedClass(i(n),n)},this)).end()},s.prototype.addAriaAndCollapsedClass=function(e,t){var n=e.hasClass("in");e.attr("aria-expanded",n),t.toggleClass("collapsed",!n).attr("aria-expanded",n)};var e=a.fn.collapse;a.fn.collapse=l,a.fn.collapse.Constructor=s,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(e){var t=a(this);t.attr("data-target")||e.preventDefault();var n=i(t),r=n.data("bs.collapse")?"toggle":t.data();l.call(n,r)})}(jQuery),$(function(){$(".checkbox-utils").each(function(e){var t=$(this);t.find("label.control-label:first-child").after(''),$(".checkbox-utils .select-all-btn").click(function(e){t.find('input[type="checkbox"]').prop("checked",!0)}),$(".checkbox-utils .unselect-all-btn").click(function(e){t.find('input[type="checkbox"]').prop("checked",!1)})})}); \ No newline at end of file +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";function g(e){return null!=e&&e===e.window}var t=[],r=Object.getPrototypeOf,s=t.slice,v=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},l=t.push,i=t.indexOf,n={},o=n.toString,m=n.hasOwnProperty,a=m.toString,u=a.call(Object),y={},b=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function x(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!b(e)&&!g(e)&&("array"===n||0===t||"number"==typeof t&&0>10|55296,1023&n|56320))}function i(){T()}var e,d,x,o,a,h,p,g,w,l,u,T,C,s,E,v,c,m,y,S="sizzle"+1*new Date,b=n.document,A=0,r=0,k=le(),N=le(),D=le(),j=le(),L=function(e,t){return e===t&&(u=!0),0},$={}.hasOwnProperty,t=[],O=t.pop,q=t.push,H=t.push,I=t.slice,P=function(e,t){for(var n=0,r=e.length;n+~]|"+M+")"+M+"*"),X=new RegExp(M+"|>"),Q=new RegExp(B),G=new RegExp("^"+F+"$"),Y={ID:new RegExp("^#("+F+")"),CLASS:new RegExp("^\\.("+F+")"),TAG:new RegExp("^("+F+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+B),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},J=/HTML$/i,K=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,ee=/^[^{]+\{\s*\[native \w/,te=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ne=/[+~]/,re=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ie=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,oe=function(e,t){return t?"\0"===e?"�":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},ae=xe(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=I.call(b.childNodes),b.childNodes),t[b.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){q.apply(e,I.call(t))}:function(e,t){for(var n=e.length,r=0;e[n++]=t[r++];);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,l,u,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(l=te.exec(t)))if(i=l[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(l[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=l[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!j[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(X.test(t)||V.test(t))){for((f=ne.test(t)&&me(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(ie,oe):e.setAttribute("id",s=S)),o=(u=h(t)).length;o--;)u[o]=(s?"#"+s:":scope")+" "+be(u[o]);c=u.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){j(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace(z,"$1"),e,n,r)}function le(){var r=[];return function e(t,n){return r.push(t+" ")>x.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function ue(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){for(var n=e.split("|"),r=n.length;r--;)x.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)for(;n=n.nextSibling;)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return ue(function(o){return o=+o,ue(function(e,t){for(var n,r=a([],e.length,o),i=r.length;i--;)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function me(e){return e&&void 0!==e.getElementsByTagName&&e}for(e in d=se.support={},a=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!J.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:b;return r!=C&&9===r.nodeType&&r.documentElement&&(s=(C=r).documentElement,E=!a(C),b!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",i,!1):n.attachEvent&&n.attachEvent("onunload",i)),d.scope=ce(function(e){return s.appendChild(e).appendChild(C.createElement("div")),void 0!==e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=ee.test(C.getElementsByClassName),d.getById=ce(function(e){return s.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(x.filter.ID=function(e){var t=e.replace(re,f);return function(e){return e.getAttribute("id")===t}},x.find.ID=function(e,t){if(void 0!==t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(x.filter.ID=function(e){var n=e.replace(re,f);return function(e){var t=void 0!==e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},x.find.ID=function(e,t){if(void 0!==t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];for(i=t.getElementsByName(e),r=0;o=i[r++];)if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),x.find.TAG=d.getElementsByTagName?function(e,t){return void 0!==t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"!==e)return o;for(;n=o[i++];)1===n.nodeType&&r.push(n);return r},x.find.CLASS=d.getElementsByClassName&&function(e,t){if(void 0!==t.getElementsByClassName&&E)return t.getElementsByClassName(e)},c=[],v=[],(d.qsa=ee.test(C.querySelectorAll))&&(ce(function(e){var t;s.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),s.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=ee.test(m=s.matches||s.webkitMatchesSelector||s.mozMatchesSelector||s.oMatchesSelector||s.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=m.call(e,"*"),m.call(e,"[s!='']:x"),c.push("!=",B)}),v=v.length&&new RegExp(v.join("|")),c=c.length&&new RegExp(c.join("|")),t=ee.test(s.compareDocumentPosition),y=t||ee.test(s.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)for(;t=t.parentNode;)if(t===e)return!0;return!1},L=t?function(e,t){if(e===t)return u=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==b&&y(b,e)?-1:t==C||t.ownerDocument==b&&y(b,t)?1:l?P(l,e)-P(l,t):0:4&n?-1:1)}:function(e,t){if(e===t)return u=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:l?P(l,e)-P(l,t):0;if(i===o)return pe(e,t);for(n=e;n=n.parentNode;)a.unshift(n);for(n=t;n=n.parentNode;)s.unshift(n);for(;a[r]===s[r];)r++;return r?pe(a[r],s[r]):a[r]==b?-1:s[r]==b?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!j[t+" "]&&(!c||!c.test(t))&&(!v||!v.test(t)))try{var n=m.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){j(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(re,f),e[3]=(e[3]||e[4]||e[5]||"").replace(re,f),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return Y.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&Q.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(re,f).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=k[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&k(e,function(e){return t.test("string"==typeof e.className&&e.className||void 0!==e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function D(e,n,r){return b(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||j,"string"!=typeof e)return e.nodeType?(this[0]=e,this.length=1,this):b(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this);if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:L.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)b(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}).prototype=S.fn,j=S(E);var $=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function q(e,t){for(;(e=e[t])&&1!==e.nodeType;);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n=void 0!==e.getElementsByTagName?e.getElementsByTagName(t||"*"):void 0!==e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&k(e,t)?S.merge([e],n):n}function me(e,t){for(var n=0,r=e.length;n",""]);var ye=/<|&#?\w+;/;function be(e,t,n,r,i){for(var o,a,s,l,u,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function De(e,t){return k(e,"table")&&k(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function je(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Le(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function $e(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(G.hasData(e)&&(s=G.get(e).events))for(i in G.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Zt,en=[],tn=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=en.pop()||S.expando+"_"+Lt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(tn.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&tn.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=b(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(tn,"$1"+r):!1!==e.jsonp&&(e.url+=($t.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,en.push(r)),o&&b(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Zt=E.implementation.createHTMLDocument("").body).innerHTML="
",2===Zt.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=be([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,l,u=S.css(e,"position"),c=S(e),f={};"static"===u&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),l=S.css(e,"left"),i=("absolute"===u||"fixed"===u)&&-1<(o+l).indexOf("auto")?(a=(r=c.position()).top,r.left):(a=parseFloat(o)||0,parseFloat(l)||0),b(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{for(t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position");)e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){for(var e=this.offsetParent;e&&"static"===S.css(e,"position");)e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return B(this,function(e,t,n){var r;if(g(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Ye(y.pixelPosition,function(e,t){if(t)return t=Ge(e,n),ze.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return B(this,function(e,t,n){var r;return g(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0 .active"),i=n&&s.support.transition&&(r.length&&r.hasClass("fade")||!!t.find("> .fade").length);function o(){r.removeClass("active").find("> .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),e.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),i?(e[0].offsetWidth,e.addClass("in")):e.removeClass("fade"),e.parent(".dropdown-menu").length&&e.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),n&&n()}r.length&&i?r.one("bsTransitionEnd",o).emulateTransitionEnd(a.TRANSITION_DURATION):o(),r.removeClass("in")};var e=s.fn.tab;s.fn.tab=t,s.fn.tab.Constructor=a,s.fn.tab.noConflict=function(){return s.fn.tab=e,this};function n(e){e.preventDefault(),t.call(s(this),"show")}s(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',n).on("click.bs.tab.data-api",'[data-toggle="pill"]',n)}(jQuery),function(r){"use strict";r.fn.emulateTransitionEnd=function(e){var t=!1,n=this;r(this).one("bsTransitionEnd",function(){t=!0});return setTimeout(function(){t||r(n).trigger(r.support.transition.end)},e),this},r(function(){r.support.transition=function(){var e=document.createElement("bootstrap"),t={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var n in t)if(void 0!==e.style[n])return{end:t[n]};return!1}(),r.support.transition&&(r.event.special.bsTransitionEnd={bindType:r.support.transition.end,delegateType:r.support.transition.end,handle:function(e){if(r(e.target).is(this))return e.handleObj.handler.apply(this,arguments)}})})}(jQuery),function(a){"use strict";function r(e){a(e).on("click.bs.dropdown",this.toggle)}var s='[data-toggle="dropdown"]';function l(e){var t=e.attr("data-target"),n="#"!==(t=t||(t=e.attr("href"))&&/#[A-Za-z]/.test(t)&&t.replace(/.*(?=#[^\s]*$)/,""))?a(document).find(t):null;return n&&n.length?n:e.parent()}function o(r){r&&3===r.which||(a(".dropdown-backdrop").remove(),a(s).each(function(){var e=a(this),t=l(e),n={relatedTarget:this};t.hasClass("open")&&(r&&"click"==r.type&&/input|textarea/i.test(r.target.tagName)&&a.contains(t[0],r.target)||(t.trigger(r=a.Event("hide.bs.dropdown",n)),r.isDefaultPrevented()||(e.attr("aria-expanded","false"),t.removeClass("open").trigger(a.Event("hidden.bs.dropdown",n)))))}))}r.VERSION="3.4.1",r.prototype.toggle=function(e){var t=a(this);if(!t.is(".disabled, :disabled")){var n=l(t),r=n.hasClass("open");if(o(),!r){"ontouchstart"in document.documentElement&&!n.closest(".navbar-nav").length&&a(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(a(this)).on("click",o);var i={relatedTarget:this};if(n.trigger(e=a.Event("show.bs.dropdown",i)),e.isDefaultPrevented())return;t.trigger("focus").attr("aria-expanded","true"),n.toggleClass("open").trigger(a.Event("shown.bs.dropdown",i))}return!1}},r.prototype.keydown=function(e){if(/(38|40|27|32)/.test(e.which)&&!/input|textarea/i.test(e.target.tagName)){var t=a(this);if(e.preventDefault(),e.stopPropagation(),!t.is(".disabled, :disabled")){var n=l(t),r=n.hasClass("open");if(!r&&27!=e.which||r&&27==e.which)return 27==e.which&&n.find(s).trigger("focus"),t.trigger("click");var i=n.find(".dropdown-menu li:not(.disabled):visible a");if(i.length){var o=i.index(e.target);38==e.which&&0
',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0},sanitize:!0,sanitizeFn:null,whiteList:e},v.prototype.init=function(e,t,n){if(this.enabled=!0,this.type=e,this.$element=g(t),this.options=this.getOptions(n),this.$viewport=this.options.viewport&&g(document).find(g.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport),this.inState={click:!1,hover:!1,focus:!1},this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var r=this.options.trigger.split(" "),i=r.length;i--;){var o=r[i];if("click"==o)this.$element.on("click."+this.type,this.options.selector,g.proxy(this.toggle,this));else if("manual"!=o){var a="hover"==o?"mouseenter":"focusin",s="hover"==o?"mouseleave":"focusout";this.$element.on(a+"."+this.type,this.options.selector,g.proxy(this.enter,this)),this.$element.on(s+"."+this.type,this.options.selector,g.proxy(this.leave,this))}}this.options.selector?this._options=g.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},v.prototype.getDefaults=function(){return v.DEFAULTS},v.prototype.getOptions=function(e){var t=this.$element.data();for(var n in t)t.hasOwnProperty(n)&&-1!==g.inArray(n,r)&&delete t[n];return(e=g.extend({},this.getDefaults(),t,e)).delay&&"number"==typeof e.delay&&(e.delay={show:e.delay,hide:e.delay}),e.sanitize&&(e.template=i(e.template,e.whiteList,e.sanitizeFn)),e},v.prototype.getDelegateOptions=function(){var n={},r=this.getDefaults();return this._options&&g.each(this._options,function(e,t){r[e]!=t&&(n[e]=t)}),n},v.prototype.enter=function(e){var t=e instanceof this.constructor?e:g(e.currentTarget).data("bs."+this.type);if(t||(t=new this.constructor(e.currentTarget,this.getDelegateOptions()),g(e.currentTarget).data("bs."+this.type,t)),e instanceof g.Event&&(t.inState["focusin"==e.type?"focus":"hover"]=!0),t.tip().hasClass("in")||"in"==t.hoverState)t.hoverState="in";else{if(clearTimeout(t.timeout),t.hoverState="in",!t.options.delay||!t.options.delay.show)return t.show();t.timeout=setTimeout(function(){"in"==t.hoverState&&t.show()},t.options.delay.show)}},v.prototype.isInStateTrue=function(){for(var e in this.inState)if(this.inState[e])return!0;return!1},v.prototype.leave=function(e){var t=e instanceof this.constructor?e:g(e.currentTarget).data("bs."+this.type);if(t||(t=new this.constructor(e.currentTarget,this.getDelegateOptions()),g(e.currentTarget).data("bs."+this.type,t)),e instanceof g.Event&&(t.inState["focusout"==e.type?"focus":"hover"]=!1),!t.isInStateTrue()){if(clearTimeout(t.timeout),t.hoverState="out",!t.options.delay||!t.options.delay.hide)return t.hide();t.timeout=setTimeout(function(){"out"==t.hoverState&&t.hide()},t.options.delay.hide)}},v.prototype.show=function(){var e=g.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(e);var t=g.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(e.isDefaultPrevented()||!t)return;var n=this,r=this.tip(),i=this.getUID(this.type);this.setContent(),r.attr("id",i),this.$element.attr("aria-describedby",i),this.options.animation&&r.addClass("fade");var o="function"==typeof this.options.placement?this.options.placement.call(this,r[0],this.$element[0]):this.options.placement,a=/\s?auto?\s?/i,s=a.test(o);s&&(o=o.replace(a,"")||"top"),r.detach().css({top:0,left:0,display:"block"}).addClass(o).data("bs."+this.type,this),this.options.container?r.appendTo(g(document).find(this.options.container)):r.insertAfter(this.$element),this.$element.trigger("inserted.bs."+this.type);var l=this.getPosition(),u=r[0].offsetWidth,c=r[0].offsetHeight;if(s){var f=o,p=this.getPosition(this.$viewport);o="bottom"==o&&l.bottom+c>p.bottom?"top":"top"==o&&l.top-cp.width?"left":"left"==o&&l.left-ua.top+a.height&&(i.top=a.top+a.height-l)}else{var u=t.left-o,c=t.left+o+n;ua.right&&(i.left=a.left+a.width-c)}return i},v.prototype.getTitle=function(){var e=this.$element,t=this.options;return e.attr("data-original-title")||("function"==typeof t.title?t.title.call(e[0]):t.title)},v.prototype.getUID=function(e){for(;e+=~~(1e6*Math.random()),document.getElementById(e););return e},v.prototype.tip=function(){if(!this.$tip&&(this.$tip=g(this.options.template),1!=this.$tip.length))throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!");return this.$tip},v.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},v.prototype.enable=function(){this.enabled=!0},v.prototype.disable=function(){this.enabled=!1},v.prototype.toggleEnabled=function(){this.enabled=!this.enabled},v.prototype.toggle=function(e){var t=this;e&&((t=g(e.currentTarget).data("bs."+this.type))||(t=new this.constructor(e.currentTarget,this.getDelegateOptions()),g(e.currentTarget).data("bs."+this.type,t))),e?(t.inState.click=!t.inState.click,t.isInStateTrue()?t.enter(t):t.leave(t)):t.tip().hasClass("in")?t.leave(t):t.enter(t)},v.prototype.destroy=function(){var e=this;clearTimeout(this.timeout),this.hide(function(){e.$element.off("."+e.type).removeData("bs."+e.type),e.$tip&&e.$tip.detach(),e.$tip=null,e.$arrow=null,e.$viewport=null,e.$element=null})},v.prototype.sanitizeHtml=function(e){return i(e,this.options.whiteList,this.options.sanitizeFn)};var t=g.fn.tooltip;g.fn.tooltip=function(r){return this.each(function(){var e=g(this),t=e.data("bs.tooltip"),n="object"==typeof r&&r;!t&&/destroy|hide/.test(r)||(t||e.data("bs.tooltip",t=new v(this,n)),"string"==typeof r&&t[r]())})},g.fn.tooltip.Constructor=v,g.fn.tooltip.noConflict=function(){return g.fn.tooltip=t,this}}(jQuery),function(a){"use strict";var s=function(e,t){this.$element=a(e),this.options=a.extend({},s.DEFAULTS,t),this.$trigger=a('[data-toggle="collapse"][href="#'+e.id+'"],[data-toggle="collapse"][data-target="#'+e.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};function i(e){var t,n=e.attr("data-target")||(t=e.attr("href"))&&t.replace(/.*(?=#[^\s]+$)/,"");return a(document).find(n)}function l(r){return this.each(function(){var e=a(this),t=e.data("bs.collapse"),n=a.extend({},s.DEFAULTS,e.data(),"object"==typeof r&&r);!t&&n.toggle&&/show|hide/.test(r)&&(n.toggle=!1),t||e.data("bs.collapse",t=new s(this,n)),"string"==typeof r&&t[r]()})}s.VERSION="3.4.1",s.TRANSITION_DURATION=350,s.DEFAULTS={toggle:!0},s.prototype.dimension=function(){return this.$element.hasClass("width")?"width":"height"},s.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var e,t=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(t&&t.length&&(e=t.data("bs.collapse"))&&e.transitioning)){var n=a.Event("show.bs.collapse");if(this.$element.trigger(n),!n.isDefaultPrevented()){t&&t.length&&(l.call(t,"hide"),e||t.data("bs.collapse",null));var r=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[r](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var i=function(){this.$element.removeClass("collapsing").addClass("collapse in")[r](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return i.call(this);var o=a.camelCase(["scroll",r].join("-"));this.$element.one("bsTransitionEnd",a.proxy(i,this)).emulateTransitionEnd(s.TRANSITION_DURATION)[r](this.$element[0][o])}}}},s.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var e=a.Event("hide.bs.collapse");if(this.$element.trigger(e),!e.isDefaultPrevented()){var t=this.dimension();this.$element[t](this.$element[t]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var n=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};if(!a.support.transition)return n.call(this);this.$element[t](0).one("bsTransitionEnd",a.proxy(n,this)).emulateTransitionEnd(s.TRANSITION_DURATION)}}},s.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},s.prototype.getParent=function(){return a(document).find(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(e,t){var n=a(t);this.addAriaAndCollapsedClass(i(n),n)},this)).end()},s.prototype.addAriaAndCollapsedClass=function(e,t){var n=e.hasClass("in");e.attr("aria-expanded",n),t.toggleClass("collapsed",!n).attr("aria-expanded",n)};var e=a.fn.collapse;a.fn.collapse=l,a.fn.collapse.Constructor=s,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(e){var t=a(this);t.attr("data-target")||e.preventDefault();var n=i(t),r=n.data("bs.collapse")?"toggle":t.data();l.call(n,r)})}(jQuery),$(function(){$(".checkbox-utils").each(function(e){var t=$(this);t.find("label.control-label:first-child").after(''),$(".checkbox-utils .select-all-btn").click(function(e){t.find('input[type="checkbox"]').prop("checked",!0)}),$(".checkbox-utils .unselect-all-btn").click(function(e){t.find('input[type="checkbox"]').prop("checked",!1)})})}); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 71cdc7bcd..f0fbfa6cc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46,10 +46,6 @@ "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" } }, "node_modules/amdefine": { @@ -459,13 +455,6 @@ }, "engines": { "node": "^10 || ^12 || >=14" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": "^8.1.0" } }, "node_modules/autoprefixer/node_modules/nanocolors": { @@ -698,10 +687,6 @@ }, "engines": { "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" } }, "node_modules/buffer-equal": { @@ -774,9 +759,6 @@ "dependencies": { "function-bind": "^1.1.1", "get-intrinsic": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" } }, "node_modules/camelcase": { @@ -808,10 +790,6 @@ "dev": true, "dependencies": { "nanocolors": "^0.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" } }, "node_modules/caseless": { @@ -840,7 +818,6 @@ "version": "2.1.8", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", - "deprecated": "Chokidar 2 will break on node v14+. Upgrade to chokidar 3 with 15x less dependencies.", "dev": true, "dependencies": { "anymatch": "^2.0.0", @@ -1037,7 +1014,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.2.tgz", "integrity": "sha1-Jgt6meux7f4kdTgXX3gyQ8sZ0Uk=", - "deprecated": "XSS vulnerability fixed in v1.0.3", "dev": true, "engines": { "node": ">=0.8" @@ -1359,7 +1335,6 @@ "version": "3.2.6", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", "dev": true, "dependencies": { "ms": "^2.1.1" @@ -2115,10 +2090,6 @@ "dev": true, "engines": { "node": "*" - }, - "funding": { - "type": "patreon", - "url": "https://www.patreon.com/infusion" } }, "node_modules/fragment-cache": { @@ -2156,7 +2127,6 @@ "version": "1.2.13", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", - "deprecated": "fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.", "dev": true, "hasInstallScript": true, "optional": true, @@ -2226,9 +2196,6 @@ "function-bind": "^1.1.1", "has": "^1.0.3", "has-symbols": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" } }, "node_modules/get-stdin": { @@ -2273,9 +2240,6 @@ }, "engines": { "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" } }, "node_modules/glob-parent": { @@ -2465,21 +2429,7 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] + "dev": true }, "node_modules/gulp-clean-css/node_modules/string_decoder": { "version": "1.3.0", @@ -2704,21 +2654,7 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] + "dev": true }, "node_modules/gulp-livereload/node_modules/string_decoder": { "version": "1.3.0", @@ -2745,7 +2681,6 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/gulp-minify-css/-/gulp-minify-css-1.2.4.tgz", "integrity": "sha1-thZJV2Auon+eWtiCJ2ld0gV3jAY=", - "deprecated": "Please use gulp-clean-css", "dev": true, "dependencies": { "clean-css": "^3.3.3", @@ -2821,9 +2756,6 @@ }, "engines": { "node": "^10 || ^12 || >=14" - }, - "peerDependencies": { - "postcss": "^8.0.0" } }, "node_modules/gulp-rename": { @@ -2959,27 +2891,12 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] + "dev": true }, "node_modules/gulp-util": { "version": "3.0.8", "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz", "integrity": "sha1-AFTh50RQLifATBh8PsxQXdVLu08=", - "deprecated": "gulp-util is deprecated - replace it, following the guidelines at https://medium.com/gulpjs/gulp-util-ca3b1f9f9ac5", "dev": true, "dependencies": { "array-differ": "^1.0.0", @@ -3053,7 +2970,6 @@ "version": "5.1.5", "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "deprecated": "this library is no longer supported", "dev": true, "dependencies": { "ajv": "^6.12.3", @@ -3115,9 +3031,6 @@ "dev": true, "engines": { "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" } }, "node_modules/has-unicode": { @@ -3281,7 +3194,6 @@ "version": "1.3.5", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", - "deprecated": "Please update to ini >=1.3.6 to avoid a prototype pollution issue", "dev": true, "engines": { "node": "*" @@ -3370,9 +3282,6 @@ "dev": true, "dependencies": { "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-data-descriptor": { @@ -3447,9 +3356,6 @@ "dev": true, "engines": { "node": ">=0.10.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/is-fullwidth-code-point": { @@ -4186,7 +4092,6 @@ "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", "dev": true, "dependencies": { "minimist": "0.0.8" @@ -4334,7 +4239,6 @@ "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.14.1.tgz", "integrity": "sha512-sjCuOlvGyCJS40R8BscF5vhVlQjNN069NtQ1gSxyK1u9iqvn6tf7O1R4GNowVZfiZUCRt5MmMs1xd+4V/7Yr0g==", "dev": true, - "hasInstallScript": true, "dependencies": { "async-foreach": "^0.1.3", "chalk": "^1.1.1", @@ -4614,9 +4518,6 @@ }, "engines": { "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" } }, "node_modules/object.defaults": { @@ -4782,9 +4683,6 @@ }, "engines": { "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-locate": { @@ -5000,10 +4898,6 @@ }, "engines": { "node": "^10 || ^12 || >=14" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" } }, "node_modules/postcss-load-config": { @@ -5018,18 +4912,6 @@ }, "engines": { "node": ">= 10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "ts-node": { - "optional": true - } } }, "node_modules/postcss-value-parser": { @@ -5333,7 +5215,6 @@ "version": "2.88.2", "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", "dev": true, "dependencies": { "aws-sign2": "~0.7.0", @@ -5365,21 +5246,7 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] + "dev": true }, "node_modules/require-directory": { "version": "2.1.1", @@ -5404,9 +5271,6 @@ "dependencies": { "is-core-module": "^2.0.0", "path-parse": "^1.0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" } }, "node_modules/resolve-dir": { @@ -5447,7 +5311,6 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "deprecated": "https://github.com/lydell/resolve-url#deprecated", "dev": true }, "node_modules/ret": { @@ -6525,7 +6388,6 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "deprecated": "Please see https://github.com/lydell/urix#deprecated", "dev": true }, "node_modules/use": { @@ -6547,7 +6409,6 @@ "version": "3.4.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", "dev": true, "bin": { "uuid": "bin/uuid" diff --git a/requirements/base.txt b/requirements/base.txt index c98bc6fe7..bfea419ec 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -29,7 +29,6 @@ pytz==2021.1 # Commands lxml==4.6.3 - # Your custom requirements go here cryptography==3.4.8 django-filter==21.1 @@ -50,10 +49,10 @@ tqdm==4.62.3 django-github-revision==0.0.3 django-extensions==3.1.3 django-cleanup==5.2.0 +whitenoise==5.3.0 # Ping commit due missing cached object in <=4.7.1 django-extra-views==0.13.0 -django-sendfile2==0.6.0 virustotal-api==1.1.11 https://github.com/ross/performant-pagination/archive/5b537da95728d622792031071ecc4cb5154ec86f.zip @@ -61,5 +60,9 @@ https://github.com/ross/performant-pagination/archive/5b537da95728d622792031071e django-background-tasks==1.2.5 django-cors-headers==3.8.0 +# Elasticsearch indexing elasticsearch-dsl==7.4.0 tika==1.24 +# S3 storage +boto3==1.18.53 +django-storages==1.11.1