From d52c611afb0e80d71af203ed0072ae639b1ec8df Mon Sep 17 00:00:00 2001 From: trevor Date: Fri, 13 Jun 2025 21:10:20 +0900 Subject: [PATCH] init commit --- .gitignore | 2 + lottery/.dockerignore | 2 + lottery/.gitignore | 14 + lottery/Dockerfile | 23 + lottery/api_test.py | 37 + lottery/bin/cli | 0 lottery/bin/cli.sh | 3 + lottery/bin/pip3.sh | 3 + lottery/bin/update.sh | 12 + lottery/bot/__init__.py | 0 lottery/bot/admin.py | 13 + lottery/bot/apps.py | 7 + lottery/bot/chat.py | 92 + lottery/bot/handlers.py | 140 + lottery/bot/management/commands/runbot.py | 33 + lottery/bot/migrations/0001_initial.py | 23 + .../0002_botconfig_chat_enabled_and_more.py | 23 + ..._alter_botconfig_options_welcomemessage.py | 38 + ...0004_alter_welcomemessage_welcome_image.py | 18 + ...0005_alter_welcomemessage_welcome_image.py | 18 + lottery/bot/migrations/__init__.py | 0 lottery/bot/models.py | 87 + lottery/bot/notifications.py | 105 + lottery/bot/state.py | 2 + lottery/bot/storage.py | 9 + lottery/bot/tests.py | 3 + lottery/bot/utils.py | 39 + lottery/bot/views.py | 3 + lottery/bot/welcome.py | 82 + lottery/db.sqlite3 | Bin 0 -> 258048 bytes lottery/docker-compose.yaml | 57 + lottery/draw/__init__.py | 0 lottery/draw/admin.py | 479 + lottery/draw/apps.py | 7 + lottery/draw/forms.py | 14 + lottery/draw/migrations/0001_initial.py | 36 + .../migrations/0002_lotteryparticipant.py | 29 + .../migrations/0003_alter_prize_winner.py | 19 + ...ter_lottery_options_alter_prize_options.py | 21 + ...ry_options_alter_prize_options_and_more.py | 56 + ...yparticipant_invoice_alter_prize_winner.py | 25 + ..._options_alter_lottery_options_and_more.py | 25 + .../draw/migrations/0008_lottery_finished.py | 18 + lottery/draw/migrations/__init__.py | 0 lottery/draw/models.py | 113 + lottery/draw/tests.py | 3 + lottery/draw/views.py | 3 + lottery/entrypoint.sh | 5 + lottery/invoices.py | 137 + lottery/lottery/__init__.py | 0 lottery/lottery/asgi.py | 16 + lottery/lottery/settings.py | 212 + lottery/lottery/urls.py | 25 + lottery/lottery/wsgi.py | 16 + lottery/manage.py | 22 + lottery/requirements.txt | 20 + lottery/static/css/custom.css | 5 + lottery/static/js/jquery.min.js | 2 + .../photo_2024-12-17_12-48-31.jpg | Bin 0 -> 103764 bytes .../staticfiles/admin/css/autocomplete.css | 279 + lottery/staticfiles/admin/css/base.css | 1179 ++ lottery/staticfiles/admin/css/changelists.css | 343 + lottery/staticfiles/admin/css/custom.css | 12 + lottery/staticfiles/admin/css/dark_mode.css | 130 + lottery/staticfiles/admin/css/dashboard.css | 29 + lottery/staticfiles/admin/css/forms.css | 512 + lottery/staticfiles/admin/css/login.css | 61 + lottery/staticfiles/admin/css/nav_sidebar.css | 150 + lottery/staticfiles/admin/css/responsive.css | 967 ++ .../staticfiles/admin/css/responsive_rtl.css | 111 + lottery/staticfiles/admin/css/rtl.css | 291 + .../admin/css/unusable_password_field.css | 19 + .../css/vendor/select2/LICENSE-SELECT2.md | 21 + .../admin/css/vendor/select2/select2.css | 481 + .../admin/css/vendor/select2/select2.min.css | 1 + lottery/staticfiles/admin/css/widgets.css | 593 + lottery/staticfiles/admin/img/LICENSE | 20 + lottery/staticfiles/admin/img/README.txt | 7 + .../staticfiles/admin/img/calendar-icons.svg | 63 + .../admin/img/gis/move_vertex_off.svg | 1 + .../admin/img/gis/move_vertex_on.svg | 1 + .../staticfiles/admin/img/icon-addlink.svg | 3 + lottery/staticfiles/admin/img/icon-alert.svg | 3 + .../staticfiles/admin/img/icon-calendar.svg | 9 + .../staticfiles/admin/img/icon-changelink.svg | 3 + lottery/staticfiles/admin/img/icon-clock.svg | 9 + .../staticfiles/admin/img/icon-deletelink.svg | 3 + .../staticfiles/admin/img/icon-hidelink.svg | 3 + lottery/staticfiles/admin/img/icon-no.svg | 3 + .../admin/img/icon-unknown-alt.svg | 3 + .../staticfiles/admin/img/icon-unknown.svg | 3 + .../staticfiles/admin/img/icon-viewlink.svg | 3 + lottery/staticfiles/admin/img/icon-yes.svg | 3 + .../staticfiles/admin/img/inline-delete.svg | 3 + lottery/staticfiles/admin/img/search.svg | 3 + .../staticfiles/admin/img/selector-icons.svg | 34 + .../staticfiles/admin/img/sorting-icons.svg | 19 + lottery/staticfiles/admin/img/tooltag-add.svg | 3 + .../admin/img/tooltag-arrowright.svg | 3 + lottery/staticfiles/admin/js/SelectBox.js | 116 + lottery/staticfiles/admin/js/SelectFilter2.js | 286 + lottery/staticfiles/admin/js/actions.js | 204 + .../admin/js/admin/DateTimeShortcuts.js | 408 + .../admin/js/admin/RelatedObjectLookups.js | 240 + lottery/staticfiles/admin/js/autocomplete.js | 33 + lottery/staticfiles/admin/js/calendar.js | 239 + lottery/staticfiles/admin/js/cancel.js | 17 + lottery/staticfiles/admin/js/change_form.js | 16 + lottery/staticfiles/admin/js/core.js | 184 + lottery/staticfiles/admin/js/filters.js | 30 + lottery/staticfiles/admin/js/inlines.js | 359 + lottery/staticfiles/admin/js/jquery.init.js | 8 + lottery/staticfiles/admin/js/nav_sidebar.js | 79 + .../staticfiles/admin/js/popup_response.js | 44 + lottery/staticfiles/admin/js/prepopulate.js | 43 + .../staticfiles/admin/js/prepopulate_init.js | 15 + lottery/staticfiles/admin/js/theme.js | 51 + .../admin/js/unusable_password_field.js | 29 + lottery/staticfiles/admin/js/urlify.js | 169 + .../admin/js/vendor/jquery/LICENSE.txt | 20 + .../admin/js/vendor/jquery/jquery.js | 10716 ++++++++++++++++ .../admin/js/vendor/jquery/jquery.min.js | 2 + .../admin/js/vendor/select2/LICENSE.md | 21 + .../admin/js/vendor/select2/i18n/af.js | 3 + .../admin/js/vendor/select2/i18n/ar.js | 3 + .../admin/js/vendor/select2/i18n/az.js | 3 + .../admin/js/vendor/select2/i18n/bg.js | 3 + .../admin/js/vendor/select2/i18n/bn.js | 3 + .../admin/js/vendor/select2/i18n/bs.js | 3 + .../admin/js/vendor/select2/i18n/ca.js | 3 + .../admin/js/vendor/select2/i18n/cs.js | 3 + .../admin/js/vendor/select2/i18n/da.js | 3 + .../admin/js/vendor/select2/i18n/de.js | 3 + .../admin/js/vendor/select2/i18n/dsb.js | 3 + .../admin/js/vendor/select2/i18n/el.js | 3 + .../admin/js/vendor/select2/i18n/en.js | 3 + .../admin/js/vendor/select2/i18n/es.js | 3 + .../admin/js/vendor/select2/i18n/et.js | 3 + .../admin/js/vendor/select2/i18n/eu.js | 3 + .../admin/js/vendor/select2/i18n/fa.js | 3 + .../admin/js/vendor/select2/i18n/fi.js | 3 + .../admin/js/vendor/select2/i18n/fr.js | 3 + .../admin/js/vendor/select2/i18n/gl.js | 3 + .../admin/js/vendor/select2/i18n/he.js | 3 + .../admin/js/vendor/select2/i18n/hi.js | 3 + .../admin/js/vendor/select2/i18n/hr.js | 3 + .../admin/js/vendor/select2/i18n/hsb.js | 3 + .../admin/js/vendor/select2/i18n/hu.js | 3 + .../admin/js/vendor/select2/i18n/hy.js | 3 + .../admin/js/vendor/select2/i18n/id.js | 3 + .../admin/js/vendor/select2/i18n/is.js | 3 + .../admin/js/vendor/select2/i18n/it.js | 3 + .../admin/js/vendor/select2/i18n/ja.js | 3 + .../admin/js/vendor/select2/i18n/ka.js | 3 + .../admin/js/vendor/select2/i18n/km.js | 3 + .../admin/js/vendor/select2/i18n/ko.js | 3 + .../admin/js/vendor/select2/i18n/lt.js | 3 + .../admin/js/vendor/select2/i18n/lv.js | 3 + .../admin/js/vendor/select2/i18n/mk.js | 3 + .../admin/js/vendor/select2/i18n/ms.js | 3 + .../admin/js/vendor/select2/i18n/nb.js | 3 + .../admin/js/vendor/select2/i18n/ne.js | 3 + .../admin/js/vendor/select2/i18n/nl.js | 3 + .../admin/js/vendor/select2/i18n/pl.js | 3 + .../admin/js/vendor/select2/i18n/ps.js | 3 + .../admin/js/vendor/select2/i18n/pt-BR.js | 3 + .../admin/js/vendor/select2/i18n/pt.js | 3 + .../admin/js/vendor/select2/i18n/ro.js | 3 + .../admin/js/vendor/select2/i18n/ru.js | 3 + .../admin/js/vendor/select2/i18n/sk.js | 3 + .../admin/js/vendor/select2/i18n/sl.js | 3 + .../admin/js/vendor/select2/i18n/sq.js | 3 + .../admin/js/vendor/select2/i18n/sr-Cyrl.js | 3 + .../admin/js/vendor/select2/i18n/sr.js | 3 + .../admin/js/vendor/select2/i18n/sv.js | 3 + .../admin/js/vendor/select2/i18n/th.js | 3 + .../admin/js/vendor/select2/i18n/tk.js | 3 + .../admin/js/vendor/select2/i18n/tr.js | 3 + .../admin/js/vendor/select2/i18n/uk.js | 3 + .../admin/js/vendor/select2/i18n/vi.js | 3 + .../admin/js/vendor/select2/i18n/zh-CN.js | 3 + .../admin/js/vendor/select2/i18n/zh-TW.js | 3 + .../admin/js/vendor/select2/select2.full.js | 6820 ++++++++++ .../js/vendor/select2/select2.full.min.js | 2 + .../admin/js/vendor/xregexp/LICENSE.txt | 21 + .../admin/js/vendor/xregexp/xregexp.js | 6126 +++++++++ .../admin/js/vendor/xregexp/xregexp.min.js | 17 + lottery/staticfiles/jazzmin/css/main.css | 927 ++ .../jazzmin/img/calendar-icons.svg | 14 + .../staticfiles/jazzmin/img/default-log.svg | 23 + lottery/staticfiles/jazzmin/img/default.jpg | Bin 0 -> 7070 bytes .../staticfiles/jazzmin/img/icon-calendar.svg | 9 + .../jazzmin/img/icon-changelink.svg | 3 + .../jazzmin/img/selector-icons.svg | 34 + lottery/staticfiles/jazzmin/js/change_form.js | 151 + lottery/staticfiles/jazzmin/js/change_list.js | 64 + lottery/staticfiles/jazzmin/js/main.js | 67 + .../staticfiles/jazzmin/js/related-modal.js | 188 + lottery/staticfiles/jazzmin/js/ui-builder.js | 343 + .../bootstrap-show-modal.min.js | 1 + .../vendor/adminlte/css/adminlte.min.css | 12 + .../vendor/adminlte/css/adminlte.min.css.map | 1 + .../vendor/adminlte/img/AdminLTELogo.png | Bin 0 -> 2637 bytes .../staticfiles/vendor/adminlte/img/icons.png | Bin 0 -> 1139 bytes .../vendor/adminlte/img/user2-160x160.jpg | Bin 0 -> 5357 bytes .../vendor/adminlte/js/adminlte.min.js | 7 + .../vendor/adminlte/js/adminlte.min.js.map | 1 + .../vendor/bootstrap/js/bootstrap.min.js | 7 + .../vendor/bootstrap/js/bootstrap.min.js.map | 1 + .../bootswatch/cerulean/bootstrap.min.css | 12 + .../vendor/bootswatch/cosmo/bootstrap.min.css | 12 + .../bootswatch/cyborg/bootstrap.min.css | 12 + .../bootswatch/darkly/bootstrap.min.css | 12 + .../bootswatch/default/bootstrap.min.css | 6 + .../bootswatch/flatly/bootstrap.min.css | 12 + .../bootswatch/journal/bootstrap.min.css | 12 + .../bootswatch/litera/bootstrap.min.css | 12 + .../vendor/bootswatch/lumen/bootstrap.min.css | 12 + .../vendor/bootswatch/lux/bootstrap.min.css | 12 + .../bootswatch/materia/bootstrap.min.css | 12 + .../vendor/bootswatch/minty/bootstrap.min.css | 12 + .../vendor/bootswatch/pulse/bootstrap.min.css | 12 + .../bootswatch/sandstone/bootstrap.min.css | 12 + .../bootswatch/simplex/bootstrap.min.css | 12 + .../bootswatch/sketchy/bootstrap.min.css | 12 + .../vendor/bootswatch/slate/bootstrap.min.css | 12 + .../vendor/bootswatch/solar/bootstrap.min.css | 12 + .../bootswatch/spacelab/bootstrap.min.css | 12 + .../bootswatch/superhero/bootstrap.min.css | 12 + .../bootswatch/united/bootstrap.min.css | 12 + .../vendor/bootswatch/yeti/bootstrap.min.css | 12 + .../vendor/fontawesome-free/css/all.min.css | 9 + .../webfonts/fa-brands-400.ttf | Bin 0 -> 209128 bytes .../webfonts/fa-brands-400.woff2 | Bin 0 -> 117852 bytes .../webfonts/fa-regular-400.ttf | Bin 0 -> 67860 bytes .../webfonts/fa-regular-400.woff2 | Bin 0 -> 25392 bytes .../webfonts/fa-solid-900.ttf | Bin 0 -> 420332 bytes .../webfonts/fa-solid-900.woff2 | Bin 0 -> 156400 bytes .../webfonts/fa-v4compatibility.ttf | Bin 0 -> 10832 bytes .../webfonts/fa-v4compatibility.woff2 | Bin 0 -> 4792 bytes .../vendor/select2/css/select2.min.css | 1 + .../vendor/select2/js/select2.min.js | 2 + lottery/templates/admin/add_participants.html | 86 + .../admin/bindingrequests_change_list.html | 26 + .../templates/admin/clients_change_list.html | 12 + .../draw/lotteryparticipant/change_list.html | 22 + lottery/templates/admin/draw_result.html | 57 + .../templates/admin/invoices_change_list.html | 119 + lottery/templates/static/css/custom.css | 0 lottery/templates/static/js/jquery.min.js | 2 + lottery/wait-for-db.sh | 15 + lottery/webapp/__init__.py | 0 lottery/webapp/admin.py | 89 + lottery/webapp/apps.py | 7 + lottery/webapp/migrations/0001_initial.py | 31 + lottery/webapp/migrations/0002_invoice.py | 42 + ...er_client_options_alter_invoice_options.py | 21 + .../migrations/0004_client_bot_admin.py | 18 + .../webapp/migrations/0005_bindingrequest.py | 28 + .../migrations/0006_bindingrequest_client.py | 19 + .../migrations/0007_client_chat_disabled.py | 18 + .../webapp/migrations/0008_invoice_used.py | 18 + lottery/webapp/migrations/__init__.py | 0 lottery/webapp/models.py | 83 + lottery/webapp/services.py | 184 + lottery/webapp/tests.py | 3 + lottery/webapp/urls.py | 7 + lottery/webapp/views.py | 60 + lottery/лого_2.png | Bin 0 -> 137315 bytes 269 files changed, 37162 insertions(+) create mode 100644 .gitignore create mode 100644 lottery/.dockerignore create mode 100644 lottery/.gitignore create mode 100644 lottery/Dockerfile create mode 100644 lottery/api_test.py create mode 100644 lottery/bin/cli create mode 100755 lottery/bin/cli.sh create mode 100755 lottery/bin/pip3.sh create mode 100755 lottery/bin/update.sh create mode 100644 lottery/bot/__init__.py create mode 100644 lottery/bot/admin.py create mode 100644 lottery/bot/apps.py create mode 100644 lottery/bot/chat.py create mode 100644 lottery/bot/handlers.py create mode 100644 lottery/bot/management/commands/runbot.py create mode 100644 lottery/bot/migrations/0001_initial.py create mode 100644 lottery/bot/migrations/0002_botconfig_chat_enabled_and_more.py create mode 100644 lottery/bot/migrations/0003_alter_botconfig_options_welcomemessage.py create mode 100644 lottery/bot/migrations/0004_alter_welcomemessage_welcome_image.py create mode 100644 lottery/bot/migrations/0005_alter_welcomemessage_welcome_image.py create mode 100644 lottery/bot/migrations/__init__.py create mode 100644 lottery/bot/models.py create mode 100644 lottery/bot/notifications.py create mode 100644 lottery/bot/state.py create mode 100644 lottery/bot/storage.py create mode 100644 lottery/bot/tests.py create mode 100644 lottery/bot/utils.py create mode 100644 lottery/bot/views.py create mode 100644 lottery/bot/welcome.py create mode 100644 lottery/db.sqlite3 create mode 100644 lottery/docker-compose.yaml create mode 100644 lottery/draw/__init__.py create mode 100644 lottery/draw/admin.py create mode 100644 lottery/draw/apps.py create mode 100644 lottery/draw/forms.py create mode 100644 lottery/draw/migrations/0001_initial.py create mode 100644 lottery/draw/migrations/0002_lotteryparticipant.py create mode 100644 lottery/draw/migrations/0003_alter_prize_winner.py create mode 100644 lottery/draw/migrations/0004_alter_lottery_options_alter_prize_options.py create mode 100644 lottery/draw/migrations/0005_alter_lottery_options_alter_prize_options_and_more.py create mode 100644 lottery/draw/migrations/0006_alter_lotteryparticipant_invoice_alter_prize_winner.py create mode 100644 lottery/draw/migrations/0007_alter_drawresult_options_alter_lottery_options_and_more.py create mode 100644 lottery/draw/migrations/0008_lottery_finished.py create mode 100644 lottery/draw/migrations/__init__.py create mode 100644 lottery/draw/models.py create mode 100644 lottery/draw/tests.py create mode 100644 lottery/draw/views.py create mode 100644 lottery/entrypoint.sh create mode 100644 lottery/invoices.py create mode 100644 lottery/lottery/__init__.py create mode 100644 lottery/lottery/asgi.py create mode 100644 lottery/lottery/settings.py create mode 100644 lottery/lottery/urls.py create mode 100644 lottery/lottery/wsgi.py create mode 100755 lottery/manage.py create mode 100644 lottery/requirements.txt create mode 100644 lottery/static/css/custom.css create mode 100644 lottery/static/js/jquery.min.js create mode 100644 lottery/static/upload_image/photo_2024-12-17_12-48-31.jpg create mode 100644 lottery/staticfiles/admin/css/autocomplete.css create mode 100644 lottery/staticfiles/admin/css/base.css create mode 100644 lottery/staticfiles/admin/css/changelists.css create mode 100644 lottery/staticfiles/admin/css/custom.css create mode 100644 lottery/staticfiles/admin/css/dark_mode.css create mode 100644 lottery/staticfiles/admin/css/dashboard.css create mode 100644 lottery/staticfiles/admin/css/forms.css create mode 100644 lottery/staticfiles/admin/css/login.css create mode 100644 lottery/staticfiles/admin/css/nav_sidebar.css create mode 100644 lottery/staticfiles/admin/css/responsive.css create mode 100644 lottery/staticfiles/admin/css/responsive_rtl.css create mode 100644 lottery/staticfiles/admin/css/rtl.css create mode 100644 lottery/staticfiles/admin/css/unusable_password_field.css create mode 100644 lottery/staticfiles/admin/css/vendor/select2/LICENSE-SELECT2.md create mode 100644 lottery/staticfiles/admin/css/vendor/select2/select2.css create mode 100644 lottery/staticfiles/admin/css/vendor/select2/select2.min.css create mode 100644 lottery/staticfiles/admin/css/widgets.css create mode 100644 lottery/staticfiles/admin/img/LICENSE create mode 100644 lottery/staticfiles/admin/img/README.txt create mode 100644 lottery/staticfiles/admin/img/calendar-icons.svg create mode 100644 lottery/staticfiles/admin/img/gis/move_vertex_off.svg create mode 100644 lottery/staticfiles/admin/img/gis/move_vertex_on.svg create mode 100644 lottery/staticfiles/admin/img/icon-addlink.svg create mode 100644 lottery/staticfiles/admin/img/icon-alert.svg create mode 100644 lottery/staticfiles/admin/img/icon-calendar.svg create mode 100644 lottery/staticfiles/admin/img/icon-changelink.svg create mode 100644 lottery/staticfiles/admin/img/icon-clock.svg create mode 100644 lottery/staticfiles/admin/img/icon-deletelink.svg create mode 100644 lottery/staticfiles/admin/img/icon-hidelink.svg create mode 100644 lottery/staticfiles/admin/img/icon-no.svg create mode 100644 lottery/staticfiles/admin/img/icon-unknown-alt.svg create mode 100644 lottery/staticfiles/admin/img/icon-unknown.svg create mode 100644 lottery/staticfiles/admin/img/icon-viewlink.svg create mode 100644 lottery/staticfiles/admin/img/icon-yes.svg create mode 100644 lottery/staticfiles/admin/img/inline-delete.svg create mode 100644 lottery/staticfiles/admin/img/search.svg create mode 100644 lottery/staticfiles/admin/img/selector-icons.svg create mode 100644 lottery/staticfiles/admin/img/sorting-icons.svg create mode 100644 lottery/staticfiles/admin/img/tooltag-add.svg create mode 100644 lottery/staticfiles/admin/img/tooltag-arrowright.svg create mode 100644 lottery/staticfiles/admin/js/SelectBox.js create mode 100644 lottery/staticfiles/admin/js/SelectFilter2.js create mode 100644 lottery/staticfiles/admin/js/actions.js create mode 100644 lottery/staticfiles/admin/js/admin/DateTimeShortcuts.js create mode 100644 lottery/staticfiles/admin/js/admin/RelatedObjectLookups.js create mode 100644 lottery/staticfiles/admin/js/autocomplete.js create mode 100644 lottery/staticfiles/admin/js/calendar.js create mode 100644 lottery/staticfiles/admin/js/cancel.js create mode 100644 lottery/staticfiles/admin/js/change_form.js create mode 100644 lottery/staticfiles/admin/js/core.js create mode 100644 lottery/staticfiles/admin/js/filters.js create mode 100644 lottery/staticfiles/admin/js/inlines.js create mode 100644 lottery/staticfiles/admin/js/jquery.init.js create mode 100644 lottery/staticfiles/admin/js/nav_sidebar.js create mode 100644 lottery/staticfiles/admin/js/popup_response.js create mode 100644 lottery/staticfiles/admin/js/prepopulate.js create mode 100644 lottery/staticfiles/admin/js/prepopulate_init.js create mode 100644 lottery/staticfiles/admin/js/theme.js create mode 100644 lottery/staticfiles/admin/js/unusable_password_field.js create mode 100644 lottery/staticfiles/admin/js/urlify.js create mode 100644 lottery/staticfiles/admin/js/vendor/jquery/LICENSE.txt create mode 100644 lottery/staticfiles/admin/js/vendor/jquery/jquery.js create mode 100644 lottery/staticfiles/admin/js/vendor/jquery/jquery.min.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/LICENSE.md create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/af.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/ar.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/az.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/bg.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/bn.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/bs.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/ca.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/cs.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/da.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/de.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/dsb.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/el.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/en.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/es.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/et.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/eu.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/fa.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/fi.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/fr.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/gl.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/he.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/hi.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/hr.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/hsb.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/hu.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/hy.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/id.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/is.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/it.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/ja.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/ka.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/km.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/ko.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/lt.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/lv.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/mk.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/ms.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/nb.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/ne.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/nl.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/pl.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/ps.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/pt-BR.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/pt.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/ro.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/ru.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/sk.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/sl.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/sq.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/sr-Cyrl.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/sr.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/sv.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/th.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/tk.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/tr.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/uk.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/vi.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/zh-CN.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/i18n/zh-TW.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/select2.full.js create mode 100644 lottery/staticfiles/admin/js/vendor/select2/select2.full.min.js create mode 100644 lottery/staticfiles/admin/js/vendor/xregexp/LICENSE.txt create mode 100644 lottery/staticfiles/admin/js/vendor/xregexp/xregexp.js create mode 100644 lottery/staticfiles/admin/js/vendor/xregexp/xregexp.min.js create mode 100644 lottery/staticfiles/jazzmin/css/main.css create mode 100644 lottery/staticfiles/jazzmin/img/calendar-icons.svg create mode 100644 lottery/staticfiles/jazzmin/img/default-log.svg create mode 100644 lottery/staticfiles/jazzmin/img/default.jpg create mode 100644 lottery/staticfiles/jazzmin/img/icon-calendar.svg create mode 100644 lottery/staticfiles/jazzmin/img/icon-changelink.svg create mode 100644 lottery/staticfiles/jazzmin/img/selector-icons.svg create mode 100644 lottery/staticfiles/jazzmin/js/change_form.js create mode 100644 lottery/staticfiles/jazzmin/js/change_list.js create mode 100644 lottery/staticfiles/jazzmin/js/main.js create mode 100644 lottery/staticfiles/jazzmin/js/related-modal.js create mode 100644 lottery/staticfiles/jazzmin/js/ui-builder.js create mode 100644 lottery/staticfiles/jazzmin/plugins/bootstrap-show-modal/bootstrap-show-modal.min.js create mode 100644 lottery/staticfiles/vendor/adminlte/css/adminlte.min.css create mode 100644 lottery/staticfiles/vendor/adminlte/css/adminlte.min.css.map create mode 100644 lottery/staticfiles/vendor/adminlte/img/AdminLTELogo.png create mode 100644 lottery/staticfiles/vendor/adminlte/img/icons.png create mode 100644 lottery/staticfiles/vendor/adminlte/img/user2-160x160.jpg create mode 100644 lottery/staticfiles/vendor/adminlte/js/adminlte.min.js create mode 100644 lottery/staticfiles/vendor/adminlte/js/adminlte.min.js.map create mode 100644 lottery/staticfiles/vendor/bootstrap/js/bootstrap.min.js create mode 100644 lottery/staticfiles/vendor/bootstrap/js/bootstrap.min.js.map create mode 100644 lottery/staticfiles/vendor/bootswatch/cerulean/bootstrap.min.css create mode 100644 lottery/staticfiles/vendor/bootswatch/cosmo/bootstrap.min.css create mode 100644 lottery/staticfiles/vendor/bootswatch/cyborg/bootstrap.min.css create mode 100644 lottery/staticfiles/vendor/bootswatch/darkly/bootstrap.min.css create mode 100644 lottery/staticfiles/vendor/bootswatch/default/bootstrap.min.css create mode 100644 lottery/staticfiles/vendor/bootswatch/flatly/bootstrap.min.css create mode 100644 lottery/staticfiles/vendor/bootswatch/journal/bootstrap.min.css create mode 100644 lottery/staticfiles/vendor/bootswatch/litera/bootstrap.min.css create mode 100644 lottery/staticfiles/vendor/bootswatch/lumen/bootstrap.min.css create mode 100644 lottery/staticfiles/vendor/bootswatch/lux/bootstrap.min.css create mode 100644 lottery/staticfiles/vendor/bootswatch/materia/bootstrap.min.css create mode 100644 lottery/staticfiles/vendor/bootswatch/minty/bootstrap.min.css create mode 100644 lottery/staticfiles/vendor/bootswatch/pulse/bootstrap.min.css create mode 100644 lottery/staticfiles/vendor/bootswatch/sandstone/bootstrap.min.css create mode 100644 lottery/staticfiles/vendor/bootswatch/simplex/bootstrap.min.css create mode 100644 lottery/staticfiles/vendor/bootswatch/sketchy/bootstrap.min.css create mode 100644 lottery/staticfiles/vendor/bootswatch/slate/bootstrap.min.css create mode 100644 lottery/staticfiles/vendor/bootswatch/solar/bootstrap.min.css create mode 100644 lottery/staticfiles/vendor/bootswatch/spacelab/bootstrap.min.css create mode 100644 lottery/staticfiles/vendor/bootswatch/superhero/bootstrap.min.css create mode 100644 lottery/staticfiles/vendor/bootswatch/united/bootstrap.min.css create mode 100644 lottery/staticfiles/vendor/bootswatch/yeti/bootstrap.min.css create mode 100644 lottery/staticfiles/vendor/fontawesome-free/css/all.min.css create mode 100644 lottery/staticfiles/vendor/fontawesome-free/webfonts/fa-brands-400.ttf create mode 100644 lottery/staticfiles/vendor/fontawesome-free/webfonts/fa-brands-400.woff2 create mode 100644 lottery/staticfiles/vendor/fontawesome-free/webfonts/fa-regular-400.ttf create mode 100644 lottery/staticfiles/vendor/fontawesome-free/webfonts/fa-regular-400.woff2 create mode 100644 lottery/staticfiles/vendor/fontawesome-free/webfonts/fa-solid-900.ttf create mode 100644 lottery/staticfiles/vendor/fontawesome-free/webfonts/fa-solid-900.woff2 create mode 100644 lottery/staticfiles/vendor/fontawesome-free/webfonts/fa-v4compatibility.ttf create mode 100644 lottery/staticfiles/vendor/fontawesome-free/webfonts/fa-v4compatibility.woff2 create mode 100644 lottery/staticfiles/vendor/select2/css/select2.min.css create mode 100644 lottery/staticfiles/vendor/select2/js/select2.min.js create mode 100644 lottery/templates/admin/add_participants.html create mode 100644 lottery/templates/admin/bindingrequests_change_list.html create mode 100644 lottery/templates/admin/clients_change_list.html create mode 100644 lottery/templates/admin/draw/lotteryparticipant/change_list.html create mode 100644 lottery/templates/admin/draw_result.html create mode 100644 lottery/templates/admin/invoices_change_list.html create mode 100644 lottery/templates/static/css/custom.css create mode 100644 lottery/templates/static/js/jquery.min.js create mode 100755 lottery/wait-for-db.sh create mode 100644 lottery/webapp/__init__.py create mode 100644 lottery/webapp/admin.py create mode 100644 lottery/webapp/apps.py create mode 100644 lottery/webapp/migrations/0001_initial.py create mode 100644 lottery/webapp/migrations/0002_invoice.py create mode 100644 lottery/webapp/migrations/0003_alter_client_options_alter_invoice_options.py create mode 100644 lottery/webapp/migrations/0004_client_bot_admin.py create mode 100644 lottery/webapp/migrations/0005_bindingrequest.py create mode 100644 lottery/webapp/migrations/0006_bindingrequest_client.py create mode 100644 lottery/webapp/migrations/0007_client_chat_disabled.py create mode 100644 lottery/webapp/migrations/0008_invoice_used.py create mode 100644 lottery/webapp/migrations/__init__.py create mode 100644 lottery/webapp/models.py create mode 100644 lottery/webapp/services.py create mode 100644 lottery/webapp/tests.py create mode 100644 lottery/webapp/urls.py create mode 100644 lottery/webapp/views.py create mode 100644 lottery/лого_2.png diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3b1659a --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.venv/ +.history/ diff --git a/lottery/.dockerignore b/lottery/.dockerignore new file mode 100644 index 0000000..ffc3c2f --- /dev/null +++ b/lottery/.dockerignore @@ -0,0 +1,2 @@ +var/mysql +var diff --git a/lottery/.gitignore b/lottery/.gitignore new file mode 100644 index 0000000..1d2c49d --- /dev/null +++ b/lottery/.gitignore @@ -0,0 +1,14 @@ +.venv +.env +.history +.__pycache__/ +var + +# Добавьте эти строки в .gitignore +*.pyc +__pycache__/ +var/mysql/ +.sqlite3 +.db +.png + diff --git a/lottery/Dockerfile b/lottery/Dockerfile new file mode 100644 index 0000000..1baa395 --- /dev/null +++ b/lottery/Dockerfile @@ -0,0 +1,23 @@ +FROM python:3.12-alpine + +# Устанавливаем рабочую директорию +WORKDIR /app + +# Копируем файл зависимостей и устанавливаем их +COPY requirements.txt /app/ +RUN set -ex && \ + apk update && \ + apk add --no-cache build-base mariadb-connector-c-dev && \ + pip install --upgrade pip && \ + pip install -r requirements.txt && \ + pip cache purge && \ + apk del build-base + +# Копируем исходный код проекта +COPY . /app + +# Открываем порт 8000 для веб-сервера +EXPOSE 8000 + +# Определяем команду по умолчанию (например, запуск веб-сервера) +CMD ["python3", "manage.py", "runserver", "0.0.0.0:8000"] diff --git a/lottery/api_test.py b/lottery/api_test.py new file mode 100644 index 0000000..9c30628 --- /dev/null +++ b/lottery/api_test.py @@ -0,0 +1,37 @@ +import requests +import json +from dotenv import load_dotenv +import os + +load_dotenv('.env') + +def fetch_clients(api_url, api_key): + """ + Подключаемся к API с использованием заданного X-API-Key + """ + headers = { + "X-API-Key": api_key + } + try: + response = requests.get(api_url, headers=headers) + response.raise_for_status() + return response.json() + except requests.exceptions.RequestException as e: + print(f"Ошибка при запросе к API: {e}") + return None + +if __name__ == '__main__': + api_endpoint = os.getenv("API_URL") + api_key = os.getenv("API_KEY") + + print(api_endpoint, api_key) + if not api_endpoint or not api_key: + print("Необходимо задать API_URL и API_KEY в .env файле.") + exit(1) + + clients = fetch_clients(api_endpoint, api_key) + + if clients is not None: + print(json.dumps(clients, indent=4, ensure_ascii=False)) + else: + print("Не удалось получить данные с API.") diff --git a/lottery/bin/cli b/lottery/bin/cli new file mode 100644 index 0000000..e69de29 diff --git a/lottery/bin/cli.sh b/lottery/bin/cli.sh new file mode 100755 index 0000000..ad3b757 --- /dev/null +++ b/lottery/bin/cli.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +docker compose exec web python3 manage.py "$@" diff --git a/lottery/bin/pip3.sh b/lottery/bin/pip3.sh new file mode 100755 index 0000000..70f6da9 --- /dev/null +++ b/lottery/bin/pip3.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +docker compose exec web pip3 "$@" diff --git a/lottery/bin/update.sh b/lottery/bin/update.sh new file mode 100755 index 0000000..e1902f8 --- /dev/null +++ b/lottery/bin/update.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -e +cd `dirname $0`/.. + +git pull + +docker compose down +docker compose build +docker compose up -d web +sleep 1 +./bin/cli migrate +docker compose up -d diff --git a/lottery/bot/__init__.py b/lottery/bot/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lottery/bot/admin.py b/lottery/bot/admin.py new file mode 100644 index 0000000..1190973 --- /dev/null +++ b/lottery/bot/admin.py @@ -0,0 +1,13 @@ +from django.contrib import admin +from .models import BotConfig, WelcomeMessage + + +@admin.register(BotConfig) +class BotConfigAdmin(admin.ModelAdmin): + list_display = ("bot_name", "channel_id", "bot_token") + search_fields = ("bot_name", "channel_id", "bot_token") + +@admin.register(WelcomeMessage) +class WWelcomeMessageAdmin(admin.ModelAdmin): + list_display = ("bot", "welcome_message", "welcome_image", "admin_contact", "channel_link", "group_link", "custom_link1_name", "custom_link1_url") + \ No newline at end of file diff --git a/lottery/bot/apps.py b/lottery/bot/apps.py new file mode 100644 index 0000000..7211b99 --- /dev/null +++ b/lottery/bot/apps.py @@ -0,0 +1,7 @@ +from django.apps import AppConfig + + +class BotConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'bot' + verbose_name='Telegram Бот' \ No newline at end of file diff --git a/lottery/bot/chat.py b/lottery/bot/chat.py new file mode 100644 index 0000000..da141d8 --- /dev/null +++ b/lottery/bot/chat.py @@ -0,0 +1,92 @@ +# chat.py +import logging +from telegram import Update, InputMediaPhoto +from telegram.ext import ContextTypes +from asgiref.sync import sync_to_async +from bot.state import BINDING_PENDING + +class ChatHandler: + def __init__(self, bot): + self.bot = bot + self.logger = logging.getLogger(__name__) + + @sync_to_async + def get_bot_settings(self): + from bot.models import BotConfig + settings = BotConfig.objects.first() + if settings is None: + settings = BotConfig.objects.create(chat_enabled=True) + return settings + + @sync_to_async + def get_client_by_telegram_id(self, telegram_id: int): + from webapp.models import Client + try: + return Client.objects.get(telegram_id=str(telegram_id)) + except Client.DoesNotExist: + return None + + @sync_to_async + def get_all_clients(self): + from webapp.models import Client + return list(Client.objects.all()) + + async def broadcast_message(self, sender, message_text: str, photo_media: InputMediaPhoto = None): + clients = await self.get_all_clients() + for client in clients: + if client.telegram_id == sender.telegram_id: + continue + try: + if photo_media: + await self.bot.send_photo( + chat_id=client.telegram_id, + photo=photo_media.media, + caption=photo_media.caption, + parse_mode="Markdown" + ) + else: + await self.bot.send_message( + chat_id=client.telegram_id, + text=message_text, + parse_mode="Markdown" + ) + except Exception as e: + self.logger.error(f"Ошибка отправки сообщения пользователю {client.telegram_id}: {e}") + + async def handle_chat_message(self, update: Update, context: ContextTypes.DEFAULT_TYPE): + if not update.message: + return + + bot_settings = await self.get_bot_settings() + if not bot_settings.chat_enabled: + await update.message.reply_text("🚫 Чат временно отключён администрацией.") + return + + chat_id = update.message.chat_id + sender = await self.get_client_by_telegram_id(chat_id) + # Если пользователь не привязан, но находится в pending, обрабатываем как ввод КК + if not sender and chat_id in BINDING_PENDING: + # Импортируем функцию process_binding_input из bot.handlers + from bot.handlers import process_binding_input + await process_binding_input(update, context) + return + # Если пользователь не привязан и не находится в pending, просим привязаться + if not sender: + await update.message.reply_text("🚫 Для участия в чате привяжите свою клиентскую карту с помощью /bind") + return + + # Если у пользователя отключена возможность отправки сообщений + if getattr(sender, "chat_disabled", False): + await update.message.reply_text("🚫 Вы не можете отправлять сообщения. Обратитесь к администратору.") + return + + sender_name = sender.name if sender else "Аноним" + broadcast_text = f"💬 *{sender_name} пишет:*\n{update.message.text or ''}" + + photo_media = None + if update.message.photo: + photo = update.message.photo[-1] + caption = update.message.caption or broadcast_text + photo_media = InputMediaPhoto(photo.file_id, caption=caption) + + await self.broadcast_message(sender, broadcast_text, photo_media) diff --git a/lottery/bot/handlers.py b/lottery/bot/handlers.py new file mode 100644 index 0000000..610cb63 --- /dev/null +++ b/lottery/bot/handlers.py @@ -0,0 +1,140 @@ +# bot/handlers.py +import re +from telegram import Update, InlineKeyboardMarkup, InlineKeyboardButton +from telegram.ext import ContextTypes +from asgiref.sync import sync_to_async +from webapp.models import BindingRequest, Client, Invoice +from draw.models import Lottery, DrawResult, LotteryParticipant +from bot.state import BINDING_PENDING + +@sync_to_async +def get_client_by_telegram_id(telegram_id: int): + try: + return Client.objects.get(telegram_id=str(telegram_id)) + except Client.DoesNotExist: + return None + +@sync_to_async +def get_invoices_for_client(client): + return list(Invoice.objects.filter(client_club_card_number=client.club_card_number)) + +@sync_to_async +def get_draws_for_client(client): + return list( + DrawResult.objects.filter(participant__invoice__client_club_card_number=client.club_card_number) + .select_related('lottery', 'prize', 'participant__invoice') + ) + +@sync_to_async +def create_binding_request(telegram_chat_id, client_card): + return BindingRequest.objects.create( + telegram_chat_id=str(telegram_chat_id), + client_card=client_card + ) + +async def whoami(update: Update, context: ContextTypes.DEFAULT_TYPE): + if not update.message: + return + chat_id = update.message.chat_id + client = await get_client_by_telegram_id(chat_id) + if not client: + await update.message.reply_text( + "❌ Пользователь не найден. Возможно, Вы ещё не привязали свою клубную карту." + ) + return + + invoices = await get_invoices_for_client(client) + draws = await get_draws_for_client(client) + + message_text = f"👤 *Профиль клиента:*\n" \ + f"• *Имя:* {client.name}\n" \ + f"• *Клубная карта:* {client.club_card_number}\n\n" + + message_text += "💳 *Счета:*\n" + if invoices: + show_all = len(invoices) > 5 + displayed_invoices = invoices[:5] if show_all else invoices + for inv in displayed_invoices: + invoice_str = str(inv).split('/')[0].strip() + message_text += f" • {invoice_str} (*{inv.sum}*)\n" + else: + message_text += " _Нет счетов_\n" + + message_text += "\n🎉 *Розыгрыши и выигранные призы:*\n" + if draws: + for draw in draws: + lottery_name = draw.lottery.name if draw.lottery else "неизвестно" + invoice_info = (draw.participant.invoice + if draw.participant and hasattr(draw.participant, 'invoice') + else "неизвестно") + prize_info = (draw.prize.reward + if draw.prize and hasattr(draw.prize, 'reward') + else "неизвестно") + message_text += f" • Лотерея: *{lottery_name}*\n Счет: _{invoice_info}_\n Выигрыш: *{prize_info}*\n\n" + else: + message_text += " _Нет результатов розыгрышей_\n" + + reply_markup = None + if invoices and len(invoices) > 5: + reply_markup = InlineKeyboardMarkup([ + [InlineKeyboardButton("Показать все счета", callback_data="show_all_invoices")] + ]) + + await update.message.reply_text(message_text, parse_mode="Markdown", reply_markup=reply_markup) + +async def handle_client_card(update: Update, context: ContextTypes.DEFAULT_TYPE): + """ + Обработчик команды /bind. + После ввода команды бот запрашивает ввод номера КК и ожидает сообщение с кодом. + Здесь мы просто добавляем ID пользователя в pending. + """ + if not update.message: + return + telegram_chat_id = update.message.chat_id + # Если пользователь уже привязан, сообщаем об этом. + client = await get_client_by_telegram_id(telegram_chat_id) + if client: + await update.message.reply_text("✅ Вы уже привязаны!") + return + + # Добавляем пользователя в список pending и просим ввести номер КК. + BINDING_PENDING.add(telegram_chat_id) + await update.message.reply_text("Введите номер вашей клубной карты (КК):") + +async def process_binding_input(update: Update, context: ContextTypes.DEFAULT_TYPE): + """ + Обрабатывает ввод номера КК от пользователя, который находится в состоянии ожидания. + """ + if not update.message or not update.message.text: + return + client_card = update.message.text.strip() + telegram_chat_id = update.message.chat_id + + if not re.fullmatch(r'\d{3,}', client_card): + await update.message.reply_text("❌ Неверный формат клиентской карты. Пожалуйста, введите корректный код (минимум 3 цифры).") + return + + await create_binding_request(telegram_chat_id, client_card) + if telegram_chat_id in BINDING_PENDING: + BINDING_PENDING.remove(telegram_chat_id) + await update.message.reply_text("✅ Заявка отправлена. После подтверждения вы сможете участвовать в чате.") + +async def show_all_invoices_callback(update: Update, context: ContextTypes.DEFAULT_TYPE): + query = update.callback_query + await query.answer() + chat_id = query.message.chat_id + client = await get_client_by_telegram_id(chat_id) + if not client: + await query.edit_message_text("❌ Пользователь не найден. Возможно, Вы ещё не привязали свою клубную карту.") + return + + invoices = await get_invoices_for_client(client) + message_text = "💳 *Все счета:*\n" + if invoices: + for inv in invoices: + invoice_str = str(inv).split('/')[0].strip() + message_text += f" • {invoice_str} (*{inv.sum}*)\n" + else: + message_text += " _Нет счетов_\n" + + await query.edit_message_text(message_text, parse_mode="Markdown") diff --git a/lottery/bot/management/commands/runbot.py b/lottery/bot/management/commands/runbot.py new file mode 100644 index 0000000..6bcdf28 --- /dev/null +++ b/lottery/bot/management/commands/runbot.py @@ -0,0 +1,33 @@ +# bot/management/commands/runbot.py +from django.core.management.base import BaseCommand, CommandError +from bot.utils import create_bot_instance +from telegram.ext import ApplicationBuilder, CommandHandler, MessageHandler, filters, CallbackQueryHandler +from bot.handlers import whoami, show_all_invoices_callback, handle_client_card +from bot.chat import ChatHandler +from bot.welcome import WelcomeHandler +class Command(BaseCommand): + help = 'Запускает Telegram-бота' + + def handle(self, *args, **options): + try: + bot = create_bot_instance() + except Exception as e: + raise CommandError(f"Ошибка при создании бота: {e}") + + application = ApplicationBuilder().token(bot.token).build() + + async def start_command(update, context): + await update.message.reply_text("Здравствуйте! Используйте команду /bind для привязки клиентской карты.") + + welcome_handler = WelcomeHandler(bot=application.bot) + application.add_handler(CommandHandler("start", welcome_handler.send_welcome)) + application.add_handler(CommandHandler("bind", handle_client_card)) + application.add_handler(CommandHandler("whoami", whoami)) + application.add_handler(CallbackQueryHandler(show_all_invoices_callback, pattern="^show_all_invoices$")) + + chat_handler = ChatHandler(bot=application.bot) + application.add_handler(MessageHandler(filters.TEXT | filters.PHOTO, chat_handler.handle_chat_message)) + + self.stdout.write("Бот запущен. Ожидание обновлений...") + application.run_polling() + self.stdout.write("Бот остановлен.") diff --git a/lottery/bot/migrations/0001_initial.py b/lottery/bot/migrations/0001_initial.py new file mode 100644 index 0000000..1789c30 --- /dev/null +++ b/lottery/bot/migrations/0001_initial.py @@ -0,0 +1,23 @@ +# Generated by Django 5.1.6 on 2025-03-21 03:44 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='BotConfig', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('bot_token', models.CharField(help_text='Токен для подключения к Telegram API', max_length=255)), + ('channel_id', models.CharField(help_text='ID канала/чата, куда бот будет отправлять сообщения', max_length=100)), + ('bot_name', models.CharField(help_text='Отображаемое имя бота', max_length=100)), + ], + ), + ] diff --git a/lottery/bot/migrations/0002_botconfig_chat_enabled_and_more.py b/lottery/bot/migrations/0002_botconfig_chat_enabled_and_more.py new file mode 100644 index 0000000..c8193bf --- /dev/null +++ b/lottery/bot/migrations/0002_botconfig_chat_enabled_and_more.py @@ -0,0 +1,23 @@ +# Generated by Django 5.1.6 on 2025-03-21 12:49 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('bot', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='botconfig', + name='chat_enabled', + field=models.BooleanField(default=True, help_text='Если выключено, то глобально блокируется рассылка сообщений в чате.', verbose_name='Чат включён'), + ), + migrations.AddField( + model_name='botconfig', + name='global_block_message', + field=models.TextField(default='', help_text='Сообщение, которое показывается пользователям, если чат отключён.', verbose_name='Сообщение о глобальном блоке'), + ), + ] diff --git a/lottery/bot/migrations/0003_alter_botconfig_options_welcomemessage.py b/lottery/bot/migrations/0003_alter_botconfig_options_welcomemessage.py new file mode 100644 index 0000000..9f5d386 --- /dev/null +++ b/lottery/bot/migrations/0003_alter_botconfig_options_welcomemessage.py @@ -0,0 +1,38 @@ +# Generated by Django 5.1.6 on 2025-03-23 01:00 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('bot', '0002_botconfig_chat_enabled_and_more'), + ] + + operations = [ + migrations.AlterModelOptions( + name='botconfig', + options={'verbose_name': 'Настройка бота', 'verbose_name_plural': 'Настройки Ботов'}, + ), + migrations.CreateModel( + name='WelcomeMessage', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('welcome_message', models.TextField(blank=True, help_text='Текст, который будет отправлен при запуске команды /start', null=True, verbose_name='Приветственное сообщение')), + ('welcome_image', models.URLField(blank=True, help_text='URL изображения для приветствия', null=True, verbose_name='Ссылка на приветственное изображение')), + ('admin_contact', models.CharField(blank=True, help_text='Ссылка или контакт для связи с администратором', max_length=255, null=True, verbose_name='Контакт администратора')), + ('channel_link', models.URLField(blank=True, help_text='URL канала бота', null=True, verbose_name='Ссылка на канал')), + ('group_link', models.URLField(blank=True, help_text='URL группы бота', null=True, verbose_name='Ссылка на группу')), + ('custom_link1_name', models.CharField(blank=True, max_length=100, null=True, verbose_name='Название кастомной ссылки 1')), + ('custom_link1_url', models.URLField(blank=True, null=True, verbose_name='URL кастомной ссылки 1')), + ('custom_link2_name', models.CharField(blank=True, max_length=100, null=True, verbose_name='Название кастомной ссылки 2')), + ('custom_link2_url', models.URLField(blank=True, null=True, verbose_name='URL кастомной ссылки 2')), + ('bot', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='bot.botconfig', verbose_name='Бот')), + ], + options={ + 'verbose_name': 'Приветственное сообщение', + 'verbose_name_plural': 'Приветственные сообщения', + }, + ), + ] diff --git a/lottery/bot/migrations/0004_alter_welcomemessage_welcome_image.py b/lottery/bot/migrations/0004_alter_welcomemessage_welcome_image.py new file mode 100644 index 0000000..050ad4d --- /dev/null +++ b/lottery/bot/migrations/0004_alter_welcomemessage_welcome_image.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.6 on 2025-03-23 01:05 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('bot', '0003_alter_botconfig_options_welcomemessage'), + ] + + operations = [ + migrations.AlterField( + model_name='welcomemessage', + name='welcome_image', + field=models.ImageField(blank=True, help_text='Загрузите изображение для приветствия', null=True, upload_to='welcome_images/', verbose_name='Приветственное изображение'), + ), + ] diff --git a/lottery/bot/migrations/0005_alter_welcomemessage_welcome_image.py b/lottery/bot/migrations/0005_alter_welcomemessage_welcome_image.py new file mode 100644 index 0000000..6688d50 --- /dev/null +++ b/lottery/bot/migrations/0005_alter_welcomemessage_welcome_image.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.6 on 2025-03-23 01:15 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('bot', '0004_alter_welcomemessage_welcome_image'), + ] + + operations = [ + migrations.AlterField( + model_name='welcomemessage', + name='welcome_image', + field=models.ImageField(blank=True, help_text='Загрузите изображение для приветствия', null=True, upload_to='', verbose_name='Приветственное изображение'), + ), + ] diff --git a/lottery/bot/migrations/__init__.py b/lottery/bot/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lottery/bot/models.py b/lottery/bot/models.py new file mode 100644 index 0000000..127bae1 --- /dev/null +++ b/lottery/bot/models.py @@ -0,0 +1,87 @@ +from django.db import models + +class BotConfig(models.Model): + bot_token = models.CharField(max_length=255, help_text="Токен для подключения к Telegram API") + channel_id = models.CharField(max_length=100, help_text="ID канала/чата, куда бот будет отправлять сообщения") + bot_name = models.CharField(max_length=100, help_text="Отображаемое имя бота") + chat_enabled = models.BooleanField( + default=True, + verbose_name="Чат включён", + help_text="Если выключено, то глобально блокируется рассылка сообщений в чате." + ) + global_block_message = models.TextField( + blank=True, + null=True, + verbose_name="Сообщение о глобальном блоке", + help_text="Сообщение, которое показывается пользователям, если чат отключён." + ) + def __str__(self): + return self.bot_name + class Meta: + verbose_name = "Настройка бота" + verbose_name_plural = "Настройки Ботов" + + +class WelcomeMessage(models.Model): + bot = models.ForeignKey(BotConfig, on_delete=models.CASCADE, verbose_name="Бот") + welcome_message = models.TextField( + verbose_name="Приветственное сообщение", + blank=True, + null=True, + help_text="Текст, который будет отправлен при запуске команды /start" + ) + welcome_image = models.ImageField( + upload_to='static/upload_image/', + verbose_name="Приветственное изображение", + blank=True, + null=True, + help_text="Загрузите изображение для приветствия" + ) + admin_contact = models.CharField( + max_length=255, + verbose_name="Контакт администратора", + blank=True, + null=True, + help_text="Ссылка или контакт для связи с администратором" + ) + channel_link = models.URLField( + verbose_name="Ссылка на канал", + blank=True, + null=True, + help_text="URL канала бота" + ) + group_link = models.URLField( + verbose_name="Ссылка на группу", + blank=True, + null=True, + help_text="URL группы бота" + ) + custom_link1_name = models.CharField( + max_length=100, + verbose_name="Название кастомной ссылки 1", + blank=True, + null=True + ) + custom_link1_url = models.URLField( + verbose_name="URL кастомной ссылки 1", + blank=True, + null=True + ) + custom_link2_name = models.CharField( + max_length=100, + verbose_name="Название кастомной ссылки 2", + blank=True, + null=True + ) + custom_link2_url = models.URLField( + verbose_name="URL кастомной ссылки 2", + blank=True, + null=True + ) + + class Meta: + verbose_name = "Приветственное сообщение" + verbose_name_plural = "Приветственные сообщения" + + def __str__(self): + return f"Приветствие для {self.bot}" \ No newline at end of file diff --git a/lottery/bot/notifications.py b/lottery/bot/notifications.py new file mode 100644 index 0000000..af5d152 --- /dev/null +++ b/lottery/bot/notifications.py @@ -0,0 +1,105 @@ +# notifications.py +import logging +from asgiref.sync import sync_to_async + +class NotificationService: + def __init__(self, bot): + """ + Инициализация сервиса уведомлений. + :param bot: экземпляр telegram.Bot, используемый для отправки сообщений. + """ + self.bot = bot + self.logger = logging.getLogger(__name__) + + @sync_to_async + def _get_all_clients(self): + from webapp.models import Client + # Возвращаем только клиентов, у которых telegram_id заполнен корректно + return list(Client.objects.exclude(telegram_id__in=[None, "", "NULL"])) + + @sync_to_async + def _prepare_results(self, results): + # Принудительно загружаем связанные объекты через select_related + return list(results.select_related('prize', 'participant__invoice')) + + async def notify_draw_start(self, lottery): + """ + Уведомляет всех клиентов о запуске розыгрыша. + :param lottery: объект розыгрыша (например, модель Lottery) + """ + message_text = f"🎉 *Розыгрыш '{lottery.name}' начался!* Следите за обновлениями." + clients = await self._get_all_clients() + for client in clients: + if not client.telegram_id: + continue + try: + await self.bot.send_message( + chat_id=client.telegram_id, + text=message_text, + parse_mode="Markdown" + ) + except Exception as e: + self.logger.error(f"Ошибка отправки уведомления о запуске розыгрыша пользователю {client.telegram_id}: {e}") + + async def notify_draw_results(self, lottery, results): + """ + Отправляет результаты розыгрыша всем клиентам. + :param lottery: объект розыгрыша (Lottery) + :param results: QuerySet с результатами розыгрыша (например, объекты DrawResult) + """ + # Принудительно загружаем связанные объекты + results_list = await self._prepare_results(results) + message_text = f"🎉 *Результаты розыгрыша '{lottery.name}':*\n" + for result in results_list: + status = "✅ Подтвержден" if result.confirmed else "⏳ В ожидании подтверждения" + prize = result.prize.reward if result.prize and hasattr(result.prize, "reward") else "неизвестно" + account = (str(result.participant.invoice).split('/')[0].strip() + if result.participant and hasattr(result.participant, "invoice") else "неизвестно") + message_text += f"• Приз: *{prize}*, Счет: _{account}_, Статус: *{status}*\n" + clients = await self._get_all_clients() + for client in clients: + if not client.telegram_id: + continue + try: + await self.bot.send_message( + chat_id=client.telegram_id, + text=message_text, + parse_mode="Markdown" + ) + except Exception as e: + self.logger.error(f"Ошибка отправки результатов розыгрыша пользователю {client.telegram_id}: {e}") + + async def notify_prize_status_update(self, client, result): + """ + Отправляет конкретному пользователю обновление по статусу подтверждения приза. + :param client: объект клиента (Client) + :param result: объект результата розыгрыша (DrawResult) + """ + status = "✅ Подтвержден" if result.confirmed else "⏳ В ожидании подтверждения" + prize = result.prize.reward if result.prize and hasattr(result.prize, "reward") else "неизвестно" + message_text = f"🎉 *Обновление розыгрыша:*\nВаш приз *{prize}* имеет статус: *{status}*." + try: + if client.telegram_id: + await self.bot.send_message( + chat_id=client.telegram_id, + text=message_text, + parse_mode="Markdown" + ) + except Exception as e: + self.logger.error(f"Ошибка отправки обновления статуса приза пользователю {client.telegram_id}: {e}") + + async def notify_binding_complete(self, client): + """ + Уведомляет пользователя об окончании привязки клубной карты к Telegram ID. + :param client: объект клиента (Client) + """ + message_text = "✅ *Привязка завершена!* Ваша клубная карта успешно привязана к Telegram. Теперь вы можете участвовать в розыгрышах и чате." + try: + if client.telegram_id: + await self.bot.send_message( + chat_id=client.telegram_id, + text=message_text, + parse_mode="Markdown" + ) + except Exception as e: + self.logger.error(f"Ошибка отправки уведомления о привязке пользователю {client.telegram_id}: {e}") diff --git a/lottery/bot/state.py b/lottery/bot/state.py new file mode 100644 index 0000000..de364df --- /dev/null +++ b/lottery/bot/state.py @@ -0,0 +1,2 @@ +# bot/state.py +BINDING_PENDING = set() diff --git a/lottery/bot/storage.py b/lottery/bot/storage.py new file mode 100644 index 0000000..00bf52e --- /dev/null +++ b/lottery/bot/storage.py @@ -0,0 +1,9 @@ +import os +from django.conf import settings +from django.core.files.storage import FileSystemStorage + +# Кастомное хранилище для загрузки изображений в /static/upload_image +static_storage = FileSystemStorage( + location=os.path.join(settings.BASE_DIR, 'static', 'upload_image'), + base_url='/static/upload_image/' +) diff --git a/lottery/bot/tests.py b/lottery/bot/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/lottery/bot/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/lottery/bot/utils.py b/lottery/bot/utils.py new file mode 100644 index 0000000..679cf00 --- /dev/null +++ b/lottery/bot/utils.py @@ -0,0 +1,39 @@ +# bot/utils.py +from telegram import Bot +from django.conf import settings +from telegram import Bot +from bot.models import BotConfig +from django.core.exceptions import ImproperlyConfigured + +def create_bot_instance(): + """ + Получает настройки бота из БД и создаёт экземпляр Telegram Bot. + """ + config = BotConfig.objects.first() # предполагается, что конфигурация одна + if not config: + raise ImproperlyConfigured("Настройки бота (BotConfig) не сконфигурированы в базе данных.") + + # Можно дополнительно использовать config.channel_id и config.bot_name при необходимости. + bot = Bot(token=config.bot_token) + return bot + + +def notify_user(binding_request, approved=True): + bot_token = settings.BOT_CONFIG.bot_token # можно использовать модель BotConfig или настройку из settings + bot = Bot(token=bot_token) + message = "Ваша заявка на привязку успешно подтверждена!" if approved else "Ваша заявка на привязку отклонена." + try: + bot.send_message(chat_id=binding_request.telegram_chat_id, text=message) + except Exception as e: + # Обработка ошибок отправки сообщения + print(f"Ошибка уведомления: {e}") + + +# Пример использования в точке входа приложения: +if __name__ == '__main__': + # Предполагается, что Django уже настроен (например, через manage.py shell или management command) + bot = create_bot_instance() + # Теперь можно использовать объект bot для отправки сообщений, обработки обновлений и т.д. + print(f"Бот {bot.name} успешно создан!") + + \ No newline at end of file diff --git a/lottery/bot/views.py b/lottery/bot/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/lottery/bot/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/lottery/bot/welcome.py b/lottery/bot/welcome.py new file mode 100644 index 0000000..2aa5fbd --- /dev/null +++ b/lottery/bot/welcome.py @@ -0,0 +1,82 @@ +# bot/welcome.py +import logging +from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup +from telegram.ext import ContextTypes +from asgiref.sync import sync_to_async +from bot.models import WelcomeMessage + +class WelcomeHandler: + def __init__(self, bot): + """ + Инициализация обработчика приветственных сообщений. + :param bot: экземпляр telegram.Bot для отправки сообщений. + """ + self.bot = bot + self.logger = logging.getLogger(__name__) + + @sync_to_async + def get_welcome_config(self): + """ + Получает первую запись настроек приветствия. + """ + try: + return WelcomeMessage.objects.select_related("bot").first() + except WelcomeMessage.DoesNotExist: + return None + + async def send_welcome(self, update: Update, context: ContextTypes.DEFAULT_TYPE): + """ + Отправляет приветственное сообщение с inline-кнопками, расположенными в 3 строки: + 1 кнопка, затем 2 и затем 2. + """ + if not update.message: + return + + config = await self.get_welcome_config() + if not config: + await update.message.reply_text("Добро пожаловать!") + return + + # Формируем список всех кнопок + buttons = [] + if config.admin_contact: + buttons.append(InlineKeyboardButton("📞 Связаться с администратором", url=config.admin_contact)) + if config.channel_link: + buttons.append(InlineKeyboardButton(" 📢 Канал", url=config.channel_link)) + if config.group_link: + buttons.append(InlineKeyboardButton("👥 Группа", url=config.group_link)) + if config.custom_link1_name and config.custom_link1_url: + buttons.append(InlineKeyboardButton(config.custom_link1_name, url=config.custom_link1_url)) + if config.custom_link2_name and config.custom_link2_url: + buttons.append(InlineKeyboardButton(config.custom_link2_name, url=config.custom_link2_url)) + + # Распределяем кнопки по рядам: первая строка 1 кнопка, вторая – 2, третья – 2. + row1 = buttons[0:1] if len(buttons) >= 1 else [] + row2 = buttons[1:3] if len(buttons) >= 3 else buttons[1:] if len(buttons) > 1 else [] + row3 = buttons[3:5] if len(buttons) >= 5 else [] + + # Собираем список рядов, исключая пустые строки + keyboard = [] + if row1: + keyboard.append(row1) + if row2: + keyboard.append(row2) + if row3: + keyboard.append(row3) + + reply_markup = InlineKeyboardMarkup(keyboard) if keyboard else None + + # Отправка сообщения с изображением, если задано + if config.welcome_image: + await update.message.reply_photo( + photo=config.welcome_image, + caption=config.welcome_message, + parse_mode="Markdown", + reply_markup=reply_markup + ) + else: + await update.message.reply_text( + text=config.welcome_message, + parse_mode="Markdown", + reply_markup=reply_markup + ) diff --git a/lottery/db.sqlite3 b/lottery/db.sqlite3 new file mode 100644 index 0000000000000000000000000000000000000000..28ffb2a0b3ae4deac1c8e32c5532b5c7ef078723 GIT binary patch literal 258048 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 literal 0 HcmV?d00001 diff --git a/lottery/docker-compose.yaml b/lottery/docker-compose.yaml new file mode 100644 index 0000000..b772b9c --- /dev/null +++ b/lottery/docker-compose.yaml @@ -0,0 +1,57 @@ +services: + db: + image: mariadb:11.6 + restart: unless-stopped + env_file: + - .env + environment: + - MYSQL_ROOT_PASSWORD=${DJANGO_DB_ROOT_PASSWORD:-rootpassword} + - MYSQL_DATABASE=${DJANGO_DB_NAME} + - MYSQL_USER=${DJANGO_DB_USER} + - MYSQL_PASSWORD=${DJANGO_DB_PASSWORD} + ports: + - "${DJANGO_DB_PORT}:3306" + volumes: + - db_data:/var/lib/mysql + networks: + default: + + bot: + image: lottery_py + build: . + restart: unless-stopped + entrypoint: ["./wait-for-db.sh"] + command: ["python3", "manage.py", "runbot"] + depends_on: + - db + env_file: + - .env + volumes: + - .:/app + - ./var:/app/var + networks: + default: + + web: + image: lottery_py + build: . + restart: unless-stopped + entrypoint: ["./wait-for-db.sh"] + command: ["python3", "manage.py", "runserver", "0.0.0.0:8000"] + ports: + - "${DOCKER_HTTP_BIND:-8000}:8000" + depends_on: + - db + env_file: + - .env + volumes: + - .:/app + networks: + default: + +volumes: + db_data: + +networks: + default: + driver: bridge diff --git a/lottery/draw/__init__.py b/lottery/draw/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lottery/draw/admin.py b/lottery/draw/admin.py new file mode 100644 index 0000000..ecbb06d --- /dev/null +++ b/lottery/draw/admin.py @@ -0,0 +1,479 @@ +# import random +# import logging +# from asgiref.sync import async_to_sync +# from django.contrib import admin, messages +# from django.urls import path, reverse +# from django.shortcuts import render, redirect, get_object_or_404 +# from django.utils import timezone +# from django.http import HttpResponseRedirect, HttpResponse +# from django.utils.html import format_html +# from .models import Lottery, Prize, LotteryParticipant, DrawResult +# from .forms import AddParticipantsForm +# from webapp.models import Invoice, Client, BindingRequest +# from bot.notifications import NotificationService +# from bot.utils import create_bot_instance + +# # Настройка логгера +# logger = logging.getLogger(__name__) +# logger.setLevel(logging.DEBUG) +# if not logger.handlers: +# console_handler = logging.StreamHandler() +# console_handler.setLevel(logging.DEBUG) +# formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') +# console_handler.setFormatter(formatter) +# logger.addHandler(console_handler) + + +# def add_participants_view(request): +# lottery_id = request.GET.get("lottery_id") +# if not lottery_id: +# return HttpResponse("Не указан параметр lottery_id", status=400) +# lottery = get_object_or_404(Lottery, id=lottery_id) + +# used_invoice_ids = LotteryParticipant.objects.filter(lottery=lottery).values_list("invoice_id", flat=True) +# qs = Invoice.objects.exclude(id__in=used_invoice_ids) + +# deposit_min = request.GET.get("deposit_min") +# deposit_max = request.GET.get("deposit_max") +# if deposit_min: +# qs = qs.filter(deposit_sum__gte=deposit_min) +# if deposit_max: +# qs = qs.filter(deposit_sum__lte=deposit_max) + +# if request.method == "POST": +# form = AddParticipantsForm(request.POST) +# form.fields["invoices"].queryset = qs +# if form.is_valid(): +# selected_invoices = form.cleaned_data["invoices"] +# for invoice in selected_invoices: +# LotteryParticipant.objects.create(lottery=lottery, invoice=invoice) +# messages.success(request, "Участники успешно добавлены.") +# return redirect("admin:draw_lotteryparticipant_changelist") +# else: +# form = AddParticipantsForm() +# form.fields["invoices"].queryset = qs + +# context = {"form": form, "lottery": lottery} +# return render(request, "admin/add_participants.html", context) + + +# def get_client_by_invoice(invoice): +# """ +# Возвращает клиента, используя значение поля client_club_card_number у счета. +# Предполагается, что у модели Invoice есть поле client_club_card_number. +# """ +# try: +# return Client.objects.get(club_card_number=invoice.client_club_card_number) +# except Client.DoesNotExist: +# return None + + +# def start_draw(request, lottery_id): +# lottery = get_object_or_404(Lottery, id=lottery_id) +# logger.info("Запуск розыгрыша для лотереи: %s", lottery.name) + +# notifier = NotificationService(bot=create_bot_instance()) +# # Используем async_to_sync для уведомления о запуске розыгрыша +# async_to_sync(notifier.notify_draw_start)(lottery) + +# for prize in lottery.prizes.all(): +# logger.info("Обработка приза: %s", prize.prize_place) + +# # Если для приза уже назначен победитель вручную, сохраняем его в таблице результатов +# if prize.winner: +# logger.info("Приз '%s' имеет установленного вручную победителя. Сохраняем в таблице результатов.", prize.prize_place) +# try: +# draw_result = lottery.draw_results.get(prize=prize) +# draw_result.participant = prize.winner +# draw_result.drawn_at = timezone.now() +# draw_result.confirmed = False +# draw_result.save() +# except DrawResult.DoesNotExist: +# DrawResult.objects.create( +# lottery=lottery, +# prize=prize, +# participant=prize.winner, +# confirmed=False, +# drawn_at=timezone.now() +# ) +# continue + +# try: +# draw_result = lottery.draw_results.get(prize=prize) +# if draw_result.confirmed: +# logger.info("Приз '%s' уже подтвержден.", prize.prize_place) +# continue +# except DrawResult.DoesNotExist: +# draw_result = None + +# participants = list(lottery.participants.filter(used=False)) +# logger.info("Найдено свободных участников для приза '%s': %d", prize.prize_place, len(participants)) +# if not participants: +# logger.warning("Нет свободных участников для приза '%s'.", prize.prize_place) +# continue + +# winner_participant = random.choice(participants) +# winner_participant.used = True +# winner_participant.save() +# logger.info("Выбран участник с счетом '%s' для приза '%s'.", winner_participant.invoice.api_id, prize.prize_place) + +# if draw_result: +# draw_result.participant = winner_participant +# draw_result.drawn_at = timezone.now() +# draw_result.confirmed = False +# draw_result.save() +# logger.info("Обновлен результат розыгрыша для приза '%s'.", prize.prize_place) +# else: +# DrawResult.objects.create( +# lottery=lottery, +# prize=prize, +# participant=winner_participant, +# confirmed=False, +# drawn_at=timezone.now() +# ) +# logger.info("Создан результат розыгрыша для приза '%s'.", prize.prize_place) + +# draw_results = lottery.draw_results.all() +# async_to_sync(notifier.notify_draw_results)(lottery, draw_results) +# return render(request, "admin/draw_result.html", {"lottery": lottery, "draw_results": draw_results}) + + +# def confirm_draw_result(request, result_id): +# from django.http import HttpResponseRedirect +# result = get_object_or_404(DrawResult, id=result_id) +# result.confirmed = True +# result.save() + +# prize = result.prize +# prize.winner = result.participant +# prize.save() + +# logger.info("Подтвержден результат розыгрыша для приза '%s'.", prize.prize_place) +# messages.success(request, f"Результат для приза '{prize.prize_place}' подтвержден.") + +# # Получаем клиента по счету участника +# client = get_client_by_invoice(result.participant.invoice) +# notifier = NotificationService(bot=create_bot_instance()) +# if client: +# async_to_sync(notifier.notify_prize_status_update)(client, result) + +# return HttpResponseRedirect(reverse("admin:start_draw", args=[result.lottery.id])) + + +# @admin.register(Lottery) +# class LotteryAdmin(admin.ModelAdmin): +# list_display = ("name", "description", "created_at", "start_draw_button") +# search_fields = ("name", "description") + +# def get_urls(self): +# urls = super().get_urls() +# custom_urls = [ +# path('/start-draw/', self.admin_site.admin_view(start_draw), name='start_draw'), +# path('confirm-draw-result//', self.admin_site.admin_view(confirm_draw_result), name='confirm_draw_result'), +# ] +# return custom_urls + urls + +# def start_draw_button(self, obj): +# url = reverse("admin:start_draw", args=[obj.pk]) +# return format_html('Запуск розыгрыша', url) +# start_draw_button.short_description = "Розыгрыш" + + +# @admin.register(Prize) +# class PrizeAdmin(admin.ModelAdmin): +# list_display = ("lottery", "prize_place", "reward", "winner") +# list_filter = ("lottery",) +# search_fields = ("prize_place", "description") + + +# @admin.register(LotteryParticipant) +# class LotteryParticipantAdmin(admin.ModelAdmin): +# list_display = ("lottery", "invoice", "added_at", "used") +# list_filter = ("lottery", "used") +# search_fields = ("invoice__api_id", "lottery__name") +# change_list_template = "admin/draw/lotteryparticipant/change_list.html" + +# def changelist_view(self, request, extra_context=None): +# extra_context = extra_context or {} +# from draw.models import Lottery +# active_lotteries = Lottery.objects.filter(prizes__winner__isnull=True).distinct() +# extra_context['active_lotteries'] = active_lotteries +# return super().changelist_view(request, extra_context=extra_context) + +# def get_urls(self): +# from django.urls import path +# urls = super().get_urls() +# custom_urls = [ +# path('add-participants/', self.admin_site.admin_view(add_participants_view), name="add_participants"), +# ] +# return custom_urls + urls + + +# @admin.register(DrawResult) +# class DrawResultAdmin(admin.ModelAdmin): +# list_display = ("lottery", "prize", "participant", "confirmed", "drawn_at") +# list_filter = ("lottery", "confirmed") +# search_fields = ("prize__prize_place", "participant__invoice__api_id") + +import random +import logging +from asgiref.sync import async_to_sync +from django.contrib import admin, messages +from django.urls import path, reverse +from django.shortcuts import render, redirect, get_object_or_404 +from django.utils import timezone +from django.http import HttpResponseRedirect, HttpResponse +from django.utils.html import format_html +from .models import Lottery, Prize, LotteryParticipant, DrawResult +from .forms import AddParticipantsForm +from webapp.models import Invoice, Client, BindingRequest +from bot.notifications import NotificationService +from bot.utils import create_bot_instance + +# Настройка логгера +logger = logging.getLogger(__name__) +logger.setLevel(logging.DEBUG) +if not logger.handlers: + console_handler = logging.StreamHandler() + console_handler.setLevel(logging.DEBUG) + formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') + console_handler.setFormatter(formatter) + logger.addHandler(console_handler) + + +def add_participants_view(request): + lottery_id = request.GET.get("lottery_id") + if not lottery_id: + return HttpResponse("Не указан параметр lottery_id", status=400) + lottery = get_object_or_404(Lottery, id=lottery_id) + + # Только счета, у которых used=False, и не добавленные в данную лотерею + used_invoice_ids = LotteryParticipant.objects.filter(lottery=lottery).values_list("invoice_id", flat=True) + qs = Invoice.objects.filter(used=False).exclude(id__in=used_invoice_ids) + + deposit_min = request.GET.get("deposit_min") + deposit_max = request.GET.get("deposit_max") + if deposit_min: + qs = qs.filter(deposit_sum__gte=deposit_min) + if deposit_max: + qs = qs.filter(deposit_sum__lte=deposit_max) + + if request.method == "POST": + form = AddParticipantsForm(request.POST) + form.fields["invoices"].queryset = qs + if form.is_valid(): + selected_invoices = form.cleaned_data["invoices"] + for invoice in selected_invoices: + # При добавлении участника отмечаем счет как использованный + invoice.used = True + invoice.save() + LotteryParticipant.objects.create(lottery=lottery, invoice=invoice) + messages.success(request, "Участники успешно добавлены.") + return redirect("admin:draw_lotteryparticipant_changelist") + else: + form = AddParticipantsForm() + form.fields["invoices"].queryset = qs + + context = {"form": form, "lottery": lottery} + return render(request, "admin/add_participants.html", context) + + +def get_client_by_invoice(invoice): + """ + Возвращает клиента, используя значение поля client_club_card_number у счета. + Предполагается, что у модели Invoice есть поле client_club_card_number. + """ + try: + return Client.objects.get(club_card_number=invoice.client_club_card_number) + except Client.DoesNotExist: + return None + + +def start_draw(request, lottery_id): + lottery = get_object_or_404(Lottery, id=lottery_id) + logger.info("Запуск розыгрыша для лотереи: %s", lottery.name) + + # Если лотерея уже завершена, кнопку запускать не показываем + if lottery.finished: + messages.warning(request, "Розыгрыш уже завершён.") + return redirect("..") + + notifier = NotificationService(bot=create_bot_instance()) + async_to_sync(notifier.notify_draw_start)(lottery) + + for prize in lottery.prizes.all(): + logger.info("Обработка приза: %s", prize.prize_place) + + # Если для приза уже назначен победитель вручную, сохраняем его в таблице результатов + if prize.winner: + logger.info("Приз '%s' имеет установленного вручную победителя. Сохраняем в таблице результатов.", prize.prize_place) + try: + draw_result = lottery.draw_results.get(prize=prize) + draw_result.participant = prize.winner + draw_result.drawn_at = timezone.now() + draw_result.confirmed = False + draw_result.save() + except DrawResult.DoesNotExist: + DrawResult.objects.create( + lottery=lottery, + prize=prize, + participant=prize.winner, + confirmed=False, + drawn_at=timezone.now() + ) + continue + + try: + draw_result = lottery.draw_results.get(prize=prize) + if draw_result.confirmed: + logger.info("Приз '%s' уже подтвержден.", prize.prize_place) + continue + except DrawResult.DoesNotExist: + draw_result = None + + participants = list(lottery.participants.filter(used=False)) + logger.info("Найдено свободных участников для приза '%s': %d", prize.prize_place, len(participants)) + if not participants: + logger.warning("Нет свободных участников для приза '%s'.", prize.prize_place) + continue + + winner_participant = random.choice(participants) + winner_participant.used = True + winner_participant.save() + logger.info("Выбран участник с счетом '%s' для приза '%s'.", winner_participant.invoice.api_id, prize.prize_place) + + if draw_result: + draw_result.participant = winner_participant + draw_result.drawn_at = timezone.now() + draw_result.confirmed = False + draw_result.save() + logger.info("Обновлен результат розыгрыша для приза '%s'.", prize.prize_place) + else: + DrawResult.objects.create( + lottery=lottery, + prize=prize, + participant=winner_participant, + confirmed=False, + drawn_at=timezone.now() + ) + logger.info("Создан результат розыгрыша для приза '%s'.", prize.prize_place) + + draw_results = lottery.draw_results.all() + async_to_sync(notifier.notify_draw_results)(lottery, draw_results) + + # Если все призы розыгрыша подтверждены, устанавливаем флаг завершения лотереи + if not lottery.prizes.filter(winner__isnull=True).exists(): + lottery.finished = True + lottery.save() + + return render(request, "admin/draw_result.html", {"lottery": lottery, "draw_results": draw_results}) + + +def confirm_draw_result(request, result_id): + from django.http import HttpResponseRedirect + result = get_object_or_404(DrawResult, id=result_id) + + # Проверяем, что для результата задан участник и его счет + if not result.participant or not result.participant.invoice: + messages.error(request, "Невозможно подтвердить результат: отсутствует участник или его счет.") + return HttpResponseRedirect(reverse("admin:start_draw", args=[result.lottery.id])) + + result.confirmed = True + result.save() + + prize = result.prize + prize.winner = result.participant + prize.save() + + logger.info("Подтвержден результат розыгрыша для приза '%s'.", prize.prize_place) + messages.success(request, f"Результат для приза '{prize.prize_place}' подтвержден.") + + # Получаем клиента по счету участника + client = get_client_by_invoice(result.participant.invoice) + # Если уведомление вызывает ошибки, можно временно его отключить, + # чтобы проверить базовую функциональность подтверждения. + if client: + try: + # Можно попробовать запуск уведомления в отдельном потоке или отключить его временно: + async_to_sync(NotificationService(bot=create_bot_instance()).notify_prize_status_update)(client, result) + except Exception as e: + logger.error(f"Ошибка отправки уведомления о статусе приза пользователю {client.telegram_id}: {e}") + + return HttpResponseRedirect(reverse("admin:start_draw", args=[result.lottery.id])) + + +@admin.register(Lottery) +class LotteryAdmin(admin.ModelAdmin): + list_display = ("name", "description", "created_at", "finished", "start_draw_button") + search_fields = ("name", "description") + + def get_urls(self): + urls = super().get_urls() + custom_urls = [ + path('/start-draw/', self.admin_site.admin_view(start_draw), name='start_draw'), + path('confirm-draw-result//', self.admin_site.admin_view(confirm_draw_result), name='confirm_draw_result'), + ] + return custom_urls + urls + + def start_draw_button(self, obj): + # Если лотерея завершена, кнопку скрываем + if obj.finished: + return "" + url = reverse("admin:start_draw", args=[obj.pk]) + return format_html('Запуск розыгрыша', url) + start_draw_button.short_description = "Розыгрыш" + + +@admin.register(Prize) +class PrizeAdmin(admin.ModelAdmin): + list_display = ("lottery", "prize_place", "reward", "winner") + list_filter = ("lottery",) + search_fields = ("prize_place", "description") + + def get_form(self, request, obj=None, **kwargs): + form = super().get_form(request, obj, **kwargs) + # При создании нового приза поле winner скрываем, так как участников ещё нет + if obj is None: + form.base_fields.pop('winner', None) + return form + + def formfield_for_foreignkey(self, db_field, request, **kwargs): + if db_field.name == "winner" and request.resolver_match.kwargs.get('object_id'): + obj_id = request.resolver_match.kwargs.get('object_id') + try: + prize_obj = self.model.objects.get(pk=obj_id) + # Ограничиваем выбор участниками данной лотереи + kwargs["queryset"] = prize_obj.lottery.participants.all() + except self.model.DoesNotExist: + kwargs["queryset"] = self.model.objects.none() + return super().formfield_for_foreignkey(db_field, request, **kwargs) + + +@admin.register(LotteryParticipant) +class LotteryParticipantAdmin(admin.ModelAdmin): + list_display = ("lottery", "invoice", "added_at", "used") + list_filter = ("lottery", "used") + search_fields = ("invoice__api_id", "lottery__name") + change_list_template = "admin/draw/lotteryparticipant/change_list.html" + + def changelist_view(self, request, extra_context=None): + extra_context = extra_context or {} + from draw.models import Lottery + active_lotteries = Lottery.objects.filter(prizes__winner__isnull=True).distinct() + extra_context['active_lotteries'] = active_lotteries + return super().changelist_view(request, extra_context=extra_context) + + def get_urls(self): + from django.urls import path + urls = super().get_urls() + custom_urls = [ + path('add-participants/', self.admin_site.admin_view(add_participants_view), name="add_participants"), + ] + return custom_urls + urls + + +@admin.register(DrawResult) +class DrawResultAdmin(admin.ModelAdmin): + list_display = ("lottery", "prize", "participant", "confirmed", "drawn_at") + list_filter = ("lottery", "confirmed") + search_fields = ("prize__prize_place", "participant__invoice__api_id") diff --git a/lottery/draw/apps.py b/lottery/draw/apps.py new file mode 100644 index 0000000..8295cb9 --- /dev/null +++ b/lottery/draw/apps.py @@ -0,0 +1,7 @@ +from django.apps import AppConfig + + +class DrawConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'draw' + verbose_name='Розыгрыш' diff --git a/lottery/draw/forms.py b/lottery/draw/forms.py new file mode 100644 index 0000000..69edc69 --- /dev/null +++ b/lottery/draw/forms.py @@ -0,0 +1,14 @@ +from django import forms +from webapp.models import Invoice + + +class AddParticipantsForm(forms.Form): + deposit_min = forms.DecimalField(label="Минимальный депозит", required=False) + deposit_max = forms.DecimalField(label="Максимальный депозит", required=False) + invoices = forms.ModelMultipleChoiceField( + queryset=Invoice.objects.none(), + widget=forms.CheckboxSelectMultiple, + required=False, + label="Доступные счета" + ) + diff --git a/lottery/draw/migrations/0001_initial.py b/lottery/draw/migrations/0001_initial.py new file mode 100644 index 0000000..57b1c8a --- /dev/null +++ b/lottery/draw/migrations/0001_initial.py @@ -0,0 +1,36 @@ +# Generated by Django 5.1.6 on 2025-03-06 10:42 + +import django.db.models.deletion +from decimal import Decimal +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('webapp', '0002_invoice'), + ] + + operations = [ + migrations.CreateModel( + name='Lottery', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255, verbose_name='Название лотереи')), + ('description', models.TextField(blank=True, verbose_name='Описание')), + ], + ), + migrations.CreateModel( + name='Prize', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('prize_place', models.CharField(help_text='Например, 1 место, 2 место и т.д.', max_length=50, verbose_name='Призовое место')), + ('description', models.TextField(blank=True, verbose_name='Описание приза')), + ('reward', models.DecimalField(decimal_places=2, default=Decimal('0.00'), max_digits=10, verbose_name='Награда')), + ('lottery', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='prizes', to='draw.lottery', verbose_name='Лотерея')), + ('winner', models.ForeignKey(blank=True, help_text='Выберите счет участника лотереи, который выиграл приз', null=True, on_delete=django.db.models.deletion.SET_NULL, to='webapp.invoice', verbose_name='Победитель (счет)')), + ], + ), + ] diff --git a/lottery/draw/migrations/0002_lotteryparticipant.py b/lottery/draw/migrations/0002_lotteryparticipant.py new file mode 100644 index 0000000..bd186a8 --- /dev/null +++ b/lottery/draw/migrations/0002_lotteryparticipant.py @@ -0,0 +1,29 @@ +# Generated by Django 5.1.6 on 2025-03-06 10:47 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('draw', '0001_initial'), + ('webapp', '0002_invoice'), + ] + + operations = [ + migrations.CreateModel( + name='LotteryParticipant', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('added_at', models.DateTimeField(auto_now_add=True, verbose_name='Дата добавления')), + ('invoice', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='webapp.invoice', verbose_name='Счет участника')), + ('lottery', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='participants', to='draw.lottery', verbose_name='Лотерея')), + ], + options={ + 'verbose_name': 'Участник лотереи', + 'verbose_name_plural': 'Участники лотереи', + 'unique_together': {('lottery', 'invoice')}, + }, + ), + ] diff --git a/lottery/draw/migrations/0003_alter_prize_winner.py b/lottery/draw/migrations/0003_alter_prize_winner.py new file mode 100644 index 0000000..25a3669 --- /dev/null +++ b/lottery/draw/migrations/0003_alter_prize_winner.py @@ -0,0 +1,19 @@ +# Generated by Django 5.1.6 on 2025-03-06 10:48 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('draw', '0002_lotteryparticipant'), + ] + + operations = [ + migrations.AlterField( + model_name='prize', + name='winner', + field=models.ForeignKey(blank=True, help_text='Выберите счет участника лотереи, который выиграл приз', null=True, on_delete=django.db.models.deletion.SET_NULL, to='draw.lotteryparticipant', verbose_name='Победитель (счет)'), + ), + ] diff --git a/lottery/draw/migrations/0004_alter_lottery_options_alter_prize_options.py b/lottery/draw/migrations/0004_alter_lottery_options_alter_prize_options.py new file mode 100644 index 0000000..0661a4f --- /dev/null +++ b/lottery/draw/migrations/0004_alter_lottery_options_alter_prize_options.py @@ -0,0 +1,21 @@ +# Generated by Django 5.1.6 on 2025-03-06 10:52 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('draw', '0003_alter_prize_winner'), + ] + + operations = [ + migrations.AlterModelOptions( + name='lottery', + options={'verbose_name': 'Розыгрыш', 'verbose_name_plural': 'Розыгрыши'}, + ), + migrations.AlterModelOptions( + name='prize', + options={'verbose_name': 'Приз', 'verbose_name_plural': 'Призы'}, + ), + ] diff --git a/lottery/draw/migrations/0005_alter_lottery_options_alter_prize_options_and_more.py b/lottery/draw/migrations/0005_alter_lottery_options_alter_prize_options_and_more.py new file mode 100644 index 0000000..a69b85e --- /dev/null +++ b/lottery/draw/migrations/0005_alter_lottery_options_alter_prize_options_and_more.py @@ -0,0 +1,56 @@ +# Generated by Django 5.1.6 on 2025-03-06 11:19 + +import django.db.models.deletion +import django.utils.timezone +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('draw', '0004_alter_lottery_options_alter_prize_options'), + ('webapp', '0003_alter_client_options_alter_invoice_options'), + ] + + operations = [ + migrations.AlterModelOptions( + name='lottery', + options={}, + ), + migrations.AlterModelOptions( + name='prize', + options={}, + ), + migrations.AddField( + model_name='lottery', + name='created_at', + field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now, verbose_name='Дата создания'), + preserve_default=False, + ), + migrations.AddField( + model_name='lotteryparticipant', + name='used', + field=models.BooleanField(default=False, help_text='Отметка, что этот счет уже участвовал в розыгрыше', verbose_name='Использован'), + ), + migrations.AlterField( + model_name='lotteryparticipant', + name='invoice', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='draw.lotteryparticipant', verbose_name='Счет участника'), + ), + migrations.AlterField( + model_name='prize', + name='winner', + field=models.ForeignKey(blank=True, help_text='Выберите счет участника лотереи, который выиграл приз', null=True, on_delete=django.db.models.deletion.SET_NULL, to='webapp.invoice', verbose_name='Победитель (счет)'), + ), + migrations.CreateModel( + name='DrawResult', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('confirmed', models.BooleanField(default=False, verbose_name='Подтвержден')), + ('drawn_at', models.DateTimeField(auto_now_add=True, verbose_name='Время розыгрыша')), + ('lottery', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='draw_results', to='draw.lottery', verbose_name='Лотерея')), + ('participant', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='draw.lotteryparticipant', verbose_name='Победитель')), + ('prize', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='draw.prize', verbose_name='Приз')), + ], + ), + ] diff --git a/lottery/draw/migrations/0006_alter_lotteryparticipant_invoice_alter_prize_winner.py b/lottery/draw/migrations/0006_alter_lotteryparticipant_invoice_alter_prize_winner.py new file mode 100644 index 0000000..01c9dfd --- /dev/null +++ b/lottery/draw/migrations/0006_alter_lotteryparticipant_invoice_alter_prize_winner.py @@ -0,0 +1,25 @@ +# Generated by Django 5.1.6 on 2025-03-06 11:21 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('draw', '0005_alter_lottery_options_alter_prize_options_and_more'), + ('webapp', '0003_alter_client_options_alter_invoice_options'), + ] + + operations = [ + migrations.AlterField( + model_name='lotteryparticipant', + name='invoice', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='webapp.invoice', verbose_name='Счет участника'), + ), + migrations.AlterField( + model_name='prize', + name='winner', + field=models.ForeignKey(blank=True, help_text='Выберите счет участника лотереи, который выиграл приз', null=True, on_delete=django.db.models.deletion.SET_NULL, to='draw.lotteryparticipant', verbose_name='Победитель (счет)'), + ), + ] diff --git a/lottery/draw/migrations/0007_alter_drawresult_options_alter_lottery_options_and_more.py b/lottery/draw/migrations/0007_alter_drawresult_options_alter_lottery_options_and_more.py new file mode 100644 index 0000000..9e10715 --- /dev/null +++ b/lottery/draw/migrations/0007_alter_drawresult_options_alter_lottery_options_and_more.py @@ -0,0 +1,25 @@ +# Generated by Django 5.1.6 on 2025-03-06 11:29 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('draw', '0006_alter_lotteryparticipant_invoice_alter_prize_winner'), + ] + + operations = [ + migrations.AlterModelOptions( + name='drawresult', + options={'verbose_name': 'Результат розыгрыша', 'verbose_name_plural': 'Результаты розыгрыша'}, + ), + migrations.AlterModelOptions( + name='lottery', + options={'verbose_name': 'Лотерея', 'verbose_name_plural': 'Лотереи'}, + ), + migrations.AlterModelOptions( + name='prize', + options={'verbose_name': 'Приз', 'verbose_name_plural': 'Призы'}, + ), + ] diff --git a/lottery/draw/migrations/0008_lottery_finished.py b/lottery/draw/migrations/0008_lottery_finished.py new file mode 100644 index 0000000..0fc1e09 --- /dev/null +++ b/lottery/draw/migrations/0008_lottery_finished.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.6 on 2025-03-22 22:22 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('draw', '0007_alter_drawresult_options_alter_lottery_options_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='lottery', + name='finished', + field=models.BooleanField(default=False, verbose_name='Завершена'), + ), + ] diff --git a/lottery/draw/migrations/__init__.py b/lottery/draw/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lottery/draw/models.py b/lottery/draw/models.py new file mode 100644 index 0000000..1db9cf2 --- /dev/null +++ b/lottery/draw/models.py @@ -0,0 +1,113 @@ +from django.db import models +from decimal import Decimal +from webapp.models import Invoice # Явно импортируем модель Invoice из приложения webapp + +class Lottery(models.Model): + name = models.CharField("Название лотереи", max_length=255) + description = models.TextField("Описание", blank=True) + created_at = models.DateTimeField("Дата создания", auto_now_add=True) + finished = models.BooleanField(default=False, verbose_name="Завершена") + def __str__(self): + return self.name + + class Meta: + verbose_name = "Лотерея" + verbose_name_plural = "Лотереи" + + +class Prize(models.Model): + lottery = models.ForeignKey( + Lottery, + on_delete=models.CASCADE, + related_name="prizes", + verbose_name="Лотерея" + ) + prize_place = models.CharField( + "Призовое место", + max_length=50, + help_text="Например, 1 место, 2 место и т.д." + ) + description = models.TextField("Описание приза", blank=True) + reward = models.DecimalField( + "Награда", + max_digits=10, + decimal_places=2, + default=Decimal("0.00") + ) + # Победитель назначается администратором из списка участников лотереи (LotteryParticipant) + winner = models.ForeignKey( + "draw.LotteryParticipant", + on_delete=models.SET_NULL, + null=True, + blank=True, + verbose_name="Победитель (счет)", + help_text="Выберите счет участника лотереи, который выиграл приз" + ) + + def __str__(self): + return f"{self.prize_place} - {self.lottery.name}" + + class Meta: + verbose_name = "Приз" + verbose_name_plural = "Призы" + + +class LotteryParticipant(models.Model): + lottery = models.ForeignKey( + Lottery, + on_delete=models.CASCADE, + related_name="participants", + verbose_name="Лотерея" + ) + # Ссылка на счет-участник из приложения webapp (модель Invoice) + invoice = models.ForeignKey( + Invoice, + on_delete=models.CASCADE, + verbose_name="Счет участника" + ) + added_at = models.DateTimeField("Дата добавления", auto_now_add=True) + used = models.BooleanField("Использован", default=False, + help_text="Отметка, что этот счет уже участвовал в розыгрыше") + + class Meta: + unique_together = ("lottery", "invoice") + verbose_name = "Участник лотереи" + verbose_name_plural = "Участники лотереи" + + def __str__(self): + return f"{self.invoice} в {self.lottery.name}" + + +class DrawResult(models.Model): + """ + Результат розыгрыша для конкретного приза. + Каждому призу соответствует один активный результат розыгрыша. + """ + lottery = models.ForeignKey( + Lottery, + on_delete=models.CASCADE, + related_name="draw_results", + verbose_name="Лотерея" + ) + prize = models.OneToOneField( + Prize, + on_delete=models.CASCADE, + verbose_name="Приз" + ) + # Ссылка на участника (LotteryParticipant), выбранного в розыгрыше + participant = models.ForeignKey( + LotteryParticipant, + on_delete=models.SET_NULL, + null=True, + blank=True, + verbose_name="Победитель" + ) + confirmed = models.BooleanField("Подтвержден", default=False) + drawn_at = models.DateTimeField("Время розыгрыша", auto_now_add=True) + + def __str__(self): + return f"Результат для {self.prize} — {self.participant}" + + class Meta: + verbose_name = "Результат розыгрыша" + verbose_name_plural = "Результаты розыгрыша" diff --git a/lottery/draw/tests.py b/lottery/draw/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/lottery/draw/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/lottery/draw/views.py b/lottery/draw/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/lottery/draw/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/lottery/entrypoint.sh b/lottery/entrypoint.sh new file mode 100644 index 0000000..a5ff924 --- /dev/null +++ b/lottery/entrypoint.sh @@ -0,0 +1,5 @@ +#!/bin/sh +# Запускаем бота в фоне +python3 manage.py runbot & +# Запускаем веб-сервер +python3 manage.py runserver 0.0.0.0:8000 diff --git a/lottery/invoices.py b/lottery/invoices.py new file mode 100644 index 0000000..96421af --- /dev/null +++ b/lottery/invoices.py @@ -0,0 +1,137 @@ +import requests +import json +import os +from dotenv import load_dotenv + +load_dotenv() + +def fetch_invoices(api_url, api_key=None, params=None): + """ + Запрашивает счета с API по указанному URL. + + Параметры: + api_url (str): URL для получения счетов. + api_key (str, optional): API ключ для авторизации. + params (dict, optional): Параметры запроса. + + Возвращает: + dict: Декодированный JSON-ответ при успешном запросе или None в случае ошибки. + """ + headers = { + "accept": "application/ld+json" + } + if api_key: + headers["X-API-Key"] = api_key + + try: + response = requests.get(api_url, headers=headers, params=params) + response.raise_for_status() + return response.json() + except requests.exceptions.RequestException as e: + print(f"Ошибка при запросе счетов: {e}") + return None + +def print_invoice(invoice): + """ + Выводит информацию об одном счёте. + """ + print("-" * 60) + print(f"Invoice: {invoice.get('@id', 'N/A')}") + print(f" Type: {invoice.get('@type', 'N/A')}") + print(f" Created at: {invoice.get('created_at', 'N/A')}") + print(f" Closed at: {invoice.get('closed_at', 'N/A')}") + print(f" External ID: {invoice.get('ext_id', 'N/A')}") + print(f" External Type: {invoice.get('ext_type', 'N/A')}") + + # Данные клиента + client = invoice.get("client", {}) + print(" Client:") + print(f" ID: {client.get('@id', 'N/A')}") + print(f" Type: {client.get('@type', 'N/A')}") + print(f" Name: {client.get('name', 'N/A')}") + print(f" Club Card Number: {client.get('club_card_num', 'N/A')}") + + # Финансовые данные + print(f" Sum: {invoice.get('sum', 'N/A')}") + print(f" Company Number: {invoice.get('comp_num', 'N/A')}") + print(f" Bonus: {invoice.get('bonus', 'N/A')}") + print(f" Start Bonus: {invoice.get('start_bonus', 'N/A')}") + print(f" Deposit Sum: {invoice.get('deposit_sum', 'N/A')}") + print(f" Notes: {invoice.get('notes', 'N/A')}") + print("-" * 60) + +def print_view(view): + """ + Выводит информацию о навигации (пагинация) коллекции. + """ + print("\nНавигация коллекции:") + print(f" View ID: {view.get('@id', 'N/A')}") + print(f" Type: {view.get('@type', 'N/A')}") + print(f" First page: {view.get('first', 'N/A')}") + print(f" Last page: {view.get('last', 'N/A')}") + print(f" Previous page: {view.get('previous', 'N/A')}") + print(f" Next page: {view.get('next', 'N/A')}") + +def print_search(search): + """ + Выводит информацию о параметрах поиска. + """ + print("\nПараметры поиска:") + print(f" Type: {search.get('@type', 'N/A')}") + print(f" Template: {search.get('template', 'N/A')}") + print(f" Variable Representation: {search.get('variableRepresentation', 'N/A')}") + mapping = search.get('mapping', []) + if mapping: + print(" Mapping:") + for m in mapping: + print(f" Variable: {m.get('variable', 'N/A')}") + print(f" Property: {m.get('property', 'N/A')}") + print(f" Required: {m.get('required', 'N/A')}") + else: + print(" Mapping: N/A") + +def print_invoices_data(data): + """ + Анализирует и выводит всю информацию, полученную от API. + """ + total_items = data.get("totalItems", 0) + print(f"\nОбщее количество счетов: {total_items}\n") + + # Разбор счетов + members = data.get("member", []) + if members: + print("Счета:") + for invoice in members: + print_invoice(invoice) + else: + print("Счета не найдены.") + + # Разбор навигационной информации + view = data.get("view") + if view: + print_view(view) + else: + print("\nИнформация о навигации не предоставлена.") + + # Разбор параметров поиска + search = data.get("search") + if search: + print_search(search) + else: + print("\nИнформация о параметрах поиска не предоставлена.") + +if __name__ == '__main__': + base_url = "http://10.8.0.4:8000/api/invoices" + params = { + "page": 1, + "created_at[before]": "2025-03-05", # можно изменить диапазон дат по необходимости + "created_at[after]": "2025-02-01" + } + api_key = os.getenv("API_KEY") # Если API-ключ не требуется, можно оставить None + + data = fetch_invoices(base_url, api_key, params) + + if data is not None: + print_invoices_data(data) + else: + print("Не удалось получить данные счетов с API.") diff --git a/lottery/lottery/__init__.py b/lottery/lottery/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lottery/lottery/asgi.py b/lottery/lottery/asgi.py new file mode 100644 index 0000000..c641ff5 --- /dev/null +++ b/lottery/lottery/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for lottery project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/5.1/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'lottery.settings') + +application = get_asgi_application() diff --git a/lottery/lottery/settings.py b/lottery/lottery/settings.py new file mode 100644 index 0000000..e205a7b --- /dev/null +++ b/lottery/lottery/settings.py @@ -0,0 +1,212 @@ +""" +Django settings for lottery project. + +Generated by 'django-admin startproject' using Django 5.1.6. + +For more information on this file, see +https://docs.djangoproject.com/en/5.1/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/5.1/ref/settings/ +""" + +from pathlib import Path +import os +from dotenv import load_dotenv + +load_dotenv() +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = os.getenv('DJANGO_SECRET_KEY') + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = os.getenv('DJANGO_DEBUG') + +ALLOWED_HOSTS = [os.getenv('DJANGO_ALLOWED_HOSTS'),] + + +# Application definition + +INSTALLED_APPS = [ + 'jazzmin', + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'webapp', + 'draw', + 'bot', + +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +ROOT_URLCONF = 'lottery.urls' + +import os + + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [os.path.join(BASE_DIR, 'templates')], # Убедитесь, что шаблоны лежат здесь + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', # Для админки + 'django.contrib.auth.context_processors.auth', # Для админки + 'django.contrib.messages.context_processors.messages', # Для админки + ], + }, + }, +] + +WSGI_APPLICATION = 'lottery.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/5.1/ref/settings/#databases + +DB_ENGINE = os.getenv('DJANGO_DB_ENGINE', 'sqlite').lower() + +if DB_ENGINE == 'mariadb' or DB_ENGINE == 'mysql': + DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.mysql', # или 'django.db.backends.mysql' для MariaDB + 'NAME': os.getenv('DJANGO_DB_NAME', 'lottery'), + 'USER': os.getenv('DJANGO_DB_USER', 'your_username'), + 'PASSWORD': os.getenv('DJANGO_DB_PASSWORD', 'your_password'), + 'HOST': os.getenv('DJANGO_DB_HOST', 'localhost'), + 'PORT': os.getenv('DJANGO_DB_PORT', '3306'), + 'OPTIONS': { + 'init_command': "SET sql_mode='STRICT_TRANS_TABLES'", + }, + } + } +else: # по умолчанию SQLite + DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': BASE_DIR / os.getenv('DJANGO_DB_NAME', 'db.sqlite3'), + } + } + + +# Password validation +# https://docs.djangoproject.com/en/5.1/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/5.1/topics/i18n/ + +LANGUAGE_CODE = 'ru-RU' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/5.1/howto/static-files/ + +STATIC_URL = 'static/' +STATICFILES_DIRS = [BASE_DIR / "static",] +STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') +# Default primary key field type +# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + + +JAZZMIN_SETTINGS = { + # Общие настройки + "site_title": "LuckyTicket", + "site_header": "Lucky Ticket", + "site_brand": "EasyPlay", + "welcome_sign": "Добро пожаловать в аLuckyTicket", + "copyright": "© 2025 LuckyTicket", + + # Верхнее меню + "topmenu_links": [ + {"name": "Домой", "url": "admin:index", "permissions": ["auth.view_user"]}, + {"app": "auth", "model": "user"}, + {"app": "draw", "label": "Розыгрыши"}, + ], + + # Меню пользователя (справа сверху) + "usermenu_links": [ + {"name": "Мой профиль", "url": "admin:password_change", "icon": "fas fa-user"}, + {"model": "auth.user"}, + ], + + # Настройка сайдбара + "show_sidebar": True, + "navigation_expanded": False, # развёрнутый сайдбар по умолчанию + "sidebar_nav_styles": { + # Пример: добавляем отступ для вложенных элементов + "default": { + "indent": 20, # отступ в пикселях + } + }, + + # Иконки для моделей + "icons": { + "bot" : "fa-solid fa-robot", + "bot.BotConfig" : "fa-solid fa-wrench", + "bot.WelcomeMessage" : "fa-solid fa-message", + "auth": "fas fa-user", + "auth.user": "fas fa-user", + "auth.Group": "fas fa-users", + "draw" : "fa-solid fa-dice", + "draw.lottery": "fas fa-ticket-alt", + "draw.prize": "fas fa-gift", + "draw.lotteryparticipant": "fas fa-user-check", + "draw.drawresult": "fas fa-trophy", + "webapp" : "fas fa-globe", + "webapp.client": "fas fa-address-card", + "webapp.invoice": "fas fa-file-invoice-dollar", + "webapp.BindingRequest" : "fas fa-link", + }, + + # Формат представления форм (если нужно) + "changeform_format": "horizontal_tabs", + + # Дополнительные настройки (можно добавить свои CSS/JS файлы) + "custom_css": "css/custom.css", + "custom_js": None, + "show_ui_builder": False, +} \ No newline at end of file diff --git a/lottery/lottery/urls.py b/lottery/lottery/urls.py new file mode 100644 index 0000000..29028d5 --- /dev/null +++ b/lottery/lottery/urls.py @@ -0,0 +1,25 @@ +""" +URL configuration for lottery project. + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/5.1/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +from django.contrib import admin +from django.urls import path, include +from django.shortcuts import redirect + +urlpatterns = [ + path('', lambda request: redirect('admin:index')), + path('admin/', admin.site.urls), + path('invoices/', include('webapp.urls')) +] diff --git a/lottery/lottery/wsgi.py b/lottery/lottery/wsgi.py new file mode 100644 index 0000000..c4148ce --- /dev/null +++ b/lottery/lottery/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for lottery project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/5.1/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'lottery.settings') + +application = get_wsgi_application() diff --git a/lottery/manage.py b/lottery/manage.py new file mode 100755 index 0000000..df811de --- /dev/null +++ b/lottery/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'lottery.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main() diff --git a/lottery/requirements.txt b/lottery/requirements.txt new file mode 100644 index 0000000..f6b087e --- /dev/null +++ b/lottery/requirements.txt @@ -0,0 +1,20 @@ +anyio==4.9.0 +asgiref==3.8.1 +certifi==2025.1.31 +charset-normalizer==3.4.1 +Django==5.1.6 +django-jazzmin==3.0.1 +exceptiongroup==1.2.2 +h11==0.14.0 +httpcore==1.0.7 +httpx==0.28.1 +idna==3.10 +pillow==11.1.0 +python-dotenv==1.0.1 +python-telegram-bot==22.0 +requests==2.32.3 +sniffio==1.3.1 +sqlparse==0.5.3 +typing_extensions==4.12.2 +urllib3==2.3.0 +mysqlclient \ No newline at end of file diff --git a/lottery/static/css/custom.css b/lottery/static/css/custom.css new file mode 100644 index 0000000..1f78286 --- /dev/null +++ b/lottery/static/css/custom.css @@ -0,0 +1,5 @@ +.nav-treeview .nav-link { + padding-left: 30px !important; + font-size: 0.9em; + color: #6c757d; +} diff --git a/lottery/static/js/jquery.min.js b/lottery/static/js/jquery.min.js new file mode 100644 index 0000000..7f37b5d --- /dev/null +++ b/lottery/static/js/jquery.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.7.1 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!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(ie,e){"use strict";var oe=[],r=Object.getPrototypeOf,ae=oe.slice,g=oe.flat?function(e){return oe.flat.call(e)}:function(e){return oe.concat.apply([],e)},s=oe.push,se=oe.indexOf,n={},i=n.toString,ue=n.hasOwnProperty,o=ue.toString,a=o.call(Object),le={},v=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},y=function(e){return null!=e&&e===e.window},C=ie.document,u={type:!0,src:!0,nonce:!0,noModule:!0};function m(e,t,n){var r,i,o=(n=n||C).createElement("script");if(o.text=e,t)for(r in u)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[i.call(e)]||"object":typeof e}var t="3.7.1",l=/HTML$/i,ce=function(e,t){return new ce.fn.init(e,t)};function c(e){var t=!!e&&"length"in e&&e.length,n=x(e);return!v(e)&&!y(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+ge+")"+ge+"*"),x=new RegExp(ge+"|>"),j=new RegExp(g),A=new RegExp("^"+t+"$"),D={ID:new RegExp("^#("+t+")"),CLASS:new RegExp("^\\.("+t+")"),TAG:new RegExp("^("+t+"|[*])"),ATTR:new RegExp("^"+p),PSEUDO:new RegExp("^"+g),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ge+"*(even|odd|(([+-]|)(\\d*)n|)"+ge+"*(?:([+-]|)"+ge+"*(\\d+)|))"+ge+"*\\)|)","i"),bool:new RegExp("^(?:"+f+")$","i"),needsContext:new RegExp("^"+ge+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ge+"*((?:-\\d)?\\d*)"+ge+"*\\)|)(?=[^-]|$)","i")},N=/^(?:input|select|textarea|button)$/i,q=/^h\d$/i,L=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,H=/[+~]/,O=new RegExp("\\\\[\\da-fA-F]{1,6}"+ge+"?|\\\\([^\\r\\n\\f])","g"),P=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},M=function(){V()},R=J(function(e){return!0===e.disabled&&fe(e,"fieldset")},{dir:"parentNode",next:"legend"});try{k.apply(oe=ae.call(ye.childNodes),ye.childNodes),oe[ye.childNodes.length].nodeType}catch(e){k={apply:function(e,t){me.apply(e,ae.call(t))},call:function(e){me.apply(e,ae.call(arguments,1))}}}function I(t,e,n,r){var i,o,a,s,u,l,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&&(V(e),e=e||T,C)){if(11!==p&&(u=L.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return k.call(n,a),n}else if(f&&(a=f.getElementById(i))&&I.contains(e,a)&&a.id===i)return k.call(n,a),n}else{if(u[2])return k.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&e.getElementsByClassName)return k.apply(n,e.getElementsByClassName(i)),n}if(!(h[t+" "]||d&&d.test(t))){if(c=t,f=e,1===p&&(x.test(t)||m.test(t))){(f=H.test(t)&&U(e.parentNode)||e)==e&&le.scope||((s=e.getAttribute("id"))?s=ce.escapeSelector(s):e.setAttribute("id",s=S)),o=(l=Y(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+Q(l[o]);c=l.join(",")}try{return k.apply(n,f.querySelectorAll(c)),n}catch(e){h(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return re(t.replace(ve,"$1"),e,n,r)}function W(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function F(e){return e[S]=!0,e}function $(e){var t=T.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function B(t){return function(e){return fe(e,"input")&&e.type===t}}function _(t){return function(e){return(fe(e,"input")||fe(e,"button"))&&e.type===t}}function z(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&&R(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function X(a){return F(function(o){return o=+o,F(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function U(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}function V(e){var t,n=e?e.ownerDocument||e:ye;return n!=T&&9===n.nodeType&&n.documentElement&&(r=(T=n).documentElement,C=!ce.isXMLDoc(T),i=r.matches||r.webkitMatchesSelector||r.msMatchesSelector,r.msMatchesSelector&&ye!=T&&(t=T.defaultView)&&t.top!==t&&t.addEventListener("unload",M),le.getById=$(function(e){return r.appendChild(e).id=ce.expando,!T.getElementsByName||!T.getElementsByName(ce.expando).length}),le.disconnectedMatch=$(function(e){return i.call(e,"*")}),le.scope=$(function(){return T.querySelectorAll(":scope")}),le.cssHas=$(function(){try{return T.querySelector(":has(*,:jqfake)"),!1}catch(e){return!0}}),le.getById?(b.filter.ID=function(e){var t=e.replace(O,P);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(O,P);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):t.querySelectorAll(e)},b.find.CLASS=function(e,t){if("undefined"!=typeof t.getElementsByClassName&&C)return t.getElementsByClassName(e)},d=[],$(function(e){var t;r.appendChild(e).innerHTML="",e.querySelectorAll("[selected]").length||d.push("\\["+ge+"*(?:value|"+f+")"),e.querySelectorAll("[id~="+S+"-]").length||d.push("~="),e.querySelectorAll("a#"+S+"+*").length||d.push(".#.+[+~]"),e.querySelectorAll(":checked").length||d.push(":checked"),(t=T.createElement("input")).setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),r.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&d.push(":enabled",":disabled"),(t=T.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||d.push("\\["+ge+"*name"+ge+"*="+ge+"*(?:''|\"\")")}),le.cssHas||d.push(":has"),d=d.length&&new RegExp(d.join("|")),l=function(e,t){if(e===t)return a=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!le.sortDetached&&t.compareDocumentPosition(e)===n?e===T||e.ownerDocument==ye&&I.contains(ye,e)?-1:t===T||t.ownerDocument==ye&&I.contains(ye,t)?1:o?se.call(o,e)-se.call(o,t):0:4&n?-1:1)}),T}for(e in I.matches=function(e,t){return I(e,null,null,t)},I.matchesSelector=function(e,t){if(V(e),C&&!h[t+" "]&&(!d||!d.test(t)))try{var n=i.call(e,t);if(n||le.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){h(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(O,P),e[3]=(e[3]||e[4]||e[5]||"").replace(O,P),"~="===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]||I.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]&&I.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return D.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&j.test(n)&&(t=Y(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(O,P).toLowerCase();return"*"===e?function(){return!0}:function(e){return fe(e,t)}},CLASS:function(e){var t=s[e+" "];return t||(t=new RegExp("(^|"+ge+")"+e+"("+ge+"|$)"))&&s(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=I.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 T(e,n,r){return v(n)?ce.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?ce.grep(e,function(e){return e===n!==r}):"string"!=typeof n?ce.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(ce.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||k,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:S.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 ce?t[0]:t,ce.merge(this,ce.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:C,!0)),w.test(r[1])&&ce.isPlainObject(t))for(r in t)v(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=C.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):v(e)?void 0!==n.ready?n.ready(e):e(ce):ce.makeArray(e,this)}).prototype=ce.fn,k=ce(C);var E=/^(?:parents|prev(?:Until|All))/,j={children:!0,contents:!0,next:!0,prev:!0};function A(e,t){while((e=e[t])&&1!==e.nodeType);return e}ce.fn.extend({has:function(e){var t=ce(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,Ce=/^$|^module$|\/(?:java|ecma)script/i;xe=C.createDocumentFragment().appendChild(C.createElement("div")),(be=C.createElement("input")).setAttribute("type","radio"),be.setAttribute("checked","checked"),be.setAttribute("name","t"),xe.appendChild(be),le.checkClone=xe.cloneNode(!0).cloneNode(!0).lastChild.checked,xe.innerHTML="",le.noCloneChecked=!!xe.cloneNode(!0).lastChild.defaultValue,xe.innerHTML="",le.option=!!xe.lastChild;var ke={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function Se(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&fe(e,t)?ce.merge([e],n):n}function Ee(e,t){for(var n=0,r=e.length;n",""]);var je=/<|&#?\w+;/;function Ae(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function Re(e,t){return fe(e,"table")&&fe(11!==t.nodeType?t:t.firstChild,"tr")&&ce(e).children("tbody")[0]||e}function Ie(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function We(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Fe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(_.hasData(e)&&(s=_.get(e).events))for(i in _.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)}),C.head.appendChild(r[0])},abort:function(){i&&i()}}});var Jt,Kt=[],Zt=/(=)\?(?=&|$)|\?\?/;ce.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Kt.pop()||ce.expando+"_"+jt.guid++;return this[e]=!0,e}}),ce.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Zt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Zt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=v(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Zt,"$1"+r):!1!==e.jsonp&&(e.url+=(At.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||ce.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=ie[r],ie[r]=function(){o=arguments},n.always(function(){void 0===i?ce(ie).removeProp(r):ie[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Kt.push(r)),o&&v(i)&&i(o[0]),o=i=void 0}),"script"}),le.createHTMLDocument=((Jt=C.implementation.createHTMLDocument("").body).innerHTML="
",2===Jt.childNodes.length),ce.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(le.createHTMLDocument?((r=(t=C.implementation.createHTMLDocument("")).createElement("base")).href=C.location.href,t.head.appendChild(r)):t=C),o=!n&&[],(i=w.exec(e))?[t.createElement(i[1])]:(i=Ae([e],t,o),o&&o.length&&ce(o).remove(),ce.merge([],i.childNodes)));var r,i,o},ce.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(ce.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},ce.expr.pseudos.animated=function(t){return ce.grep(ce.timers,function(e){return t===e.elem}).length},ce.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=ce.css(e,"position"),c=ce(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=ce.css(e,"top"),u=ce.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),v(t)&&(t=t.call(e,n,ce.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)}},ce.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){ce.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"===ce.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===ce.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=ce(e).offset()).top+=ce.css(e,"borderTopWidth",!0),i.left+=ce.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-ce.css(r,"marginTop",!0),left:t.left-i.left-ce.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===ce.css(e,"position"))e=e.offsetParent;return e||J})}}),ce.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;ce.fn[t]=function(e){return M(this,function(e,t,n){var r;if(y(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)}}),ce.each(["top","left"],function(e,n){ce.cssHooks[n]=Ye(le.pixelPosition,function(e,t){if(t)return t=Ge(e,n),_e.test(t)?ce(e).position()[n]+"px":t})}),ce.each({Height:"height",Width:"width"},function(a,s){ce.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){ce.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return M(this,function(e,t,n){var r;return y(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?ce.css(e,t,i):ce.style(e,t,n,i)},s,n?e:void 0,n)}})}),ce.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){ce.fn[t]=function(e){return this.on(t,e)}}),ce.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.on("mouseenter",e).on("mouseleave",t||e)}}),ce.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){ce.fn[n]=function(e,t){return 0#cS4OI35bC7kWfP}3PM6r zl%j(AzL)p=yY~;cd-mC#XJ#{VGIM5j=CgDDUH|tZ0iBVap&kJtAprs5oe=!HMW9VU zL3WS)9vKDsJ#tD)3Mv}r`!v+lG#rdfbj&YN=`vp zS(#t#iOv&6ZCNE{h5s@kq@<*zp{8NKf1h1J@S&i>|L^19F#>vWQUc-;VnRLwB6>n% zdcuFl2{;G{h=>XQQ}_Qnh=>UYNl3}=-6gW!CH!~%e@S@n7fIgUE~O^u|;0!~3U! zTcsyB#pC5_m)Ftpe4w+LY8B4rQ-^W9;5)~4E_NSgVn!ieYql7_FTNYOL&5qTmx%Ar z8aghoc$nmc<>pOyT;4|dfpieOAY(ynfuR6`LO=j&bs`rTf!1mjbq3aQgl~QTU!EM& zzTA6lSvR6x!;2!~(ilrbgba76gq`88`utH{^J}IV9+muhkvPGbt7Bi;+h5kurlZta zcl-%sb7KT{?aAYCr0OS^&PM?WP*js8>IC#1Wv*Yoe2gEjWIJe>fGf?CbSk>b-Zv~C zoN2g@oC@JCRIy*~4Ss3>D-WAjacvHG-nhwL^)8S$7bm@qc>REiYXt|6$$_=c*Tns- zyZi~QK(_<_P-P7}iQKPp`*ISoRxN3?71wv${!}cXrF~`(2A_G_$v7p5BcZ6uYU|{#J`fvtI8v-_`0jUre4gBdtzR(xEbQ=?Ce@;7ejfve~d#p zHkNv~I;_1@M7ZdGfL|YBQCrQfrWMNSCzlwX#mbnCr-gg@z&%%;YxNcfzT+f8a}(uG z#7%Pb0`Aq9FqPOVd>u#81#)O8EZQ21-K!UJiD7A4d9O5omSJQw}-Gg4U_^Pt{&QQ>GdBbI3z7JlMBR~ivH^rJH3iueOmEg``M$7PmR zo`AdteY8C0z~!1XIa7_FzsJCr^K@K8f2wGH;C8%<#NoJi#x8#%wr9|GF+VwQDEsEP z7_P(b?e@KKD)5$J-!IQ4)O6~6$3sEKsV+$_!Rylt(7d%O436zWE#h(IQ0`J!aPHrmjqnrs z=QRhXKY*$Y2VbtZ?sEg)v@3Tz_y@4V8EuJ)4(_%Y9V50+-fff(WNY4=*$ohKrjKA0K}BV4Fd&Q zXMqR{h%iLFC6Z7_PH>xMr)5mo9%mgU$Nu%8Ratr`TB@^*TrA!oc11?aoDb_w<)2mk-Y zA#%~-f@SAitEh>vULUxnU}J`GP!3HU!j5*1(NWCHi#TvpUn~66@Xfbf#k#06)2QulhZNC?wptn3Ivb@Dq?0Z;@+q_752u%T2Brbh z6O)>j-OipY9He@qmijaepVsnLBj-n?Z&S!po-Z}r&7S!%CjHGO~0n9S#6Vw;c=i4f$PCB$~L8P#T*^D|try_3|aPOpLO!@dW z#GM0~*hnWeqe97}0Mbn7OWQRiqv8+(+PTcJ#8&pc#l~h>x_hA zMcQO*1=$)Tmjo zcoxcI;n_&WBAT2?+^4ztII>RrTve8`EnAR*=2XBK0c0U&Z$sEYMHwbZMM*_x1O!){ zAbf{fCsu}{owj!okyH>WWTGLTvEYLqJ%-LCKL
3h_$0W`qdc}ujA3NCC3I#VNs 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 literal 0 HcmV?d00001 diff --git a/lottery/staticfiles/admin/css/autocomplete.css b/lottery/staticfiles/admin/css/autocomplete.css new file mode 100644 index 0000000..7478c2c --- /dev/null +++ b/lottery/staticfiles/admin/css/autocomplete.css @@ -0,0 +1,279 @@ +select.admin-autocomplete { + width: 20em; +} + +.select2-container--admin-autocomplete.select2-container { + min-height: 30px; +} + +.select2-container--admin-autocomplete .select2-selection--single, +.select2-container--admin-autocomplete .select2-selection--multiple { + min-height: 30px; + padding: 0; +} + +.select2-container--admin-autocomplete.select2-container--focus .select2-selection, +.select2-container--admin-autocomplete.select2-container--open .select2-selection { + border-color: var(--body-quiet-color); + min-height: 30px; +} + +.select2-container--admin-autocomplete.select2-container--focus .select2-selection.select2-selection--single, +.select2-container--admin-autocomplete.select2-container--open .select2-selection.select2-selection--single { + padding: 0; +} + +.select2-container--admin-autocomplete.select2-container--focus .select2-selection.select2-selection--multiple, +.select2-container--admin-autocomplete.select2-container--open .select2-selection.select2-selection--multiple { + padding: 0; +} + +.select2-container--admin-autocomplete .select2-selection--single { + background-color: var(--body-bg); + border: 1px solid var(--border-color); + border-radius: 4px; +} + +.select2-container--admin-autocomplete .select2-selection--single .select2-selection__rendered { + color: var(--body-fg); + line-height: 30px; +} + +.select2-container--admin-autocomplete .select2-selection--single .select2-selection__clear { + cursor: pointer; + float: right; + font-weight: bold; +} + +.select2-container--admin-autocomplete .select2-selection--single .select2-selection__placeholder { + color: var(--body-quiet-color); +} + +.select2-container--admin-autocomplete .select2-selection--single .select2-selection__arrow { + height: 26px; + position: absolute; + top: 1px; + right: 1px; + width: 20px; +} + +.select2-container--admin-autocomplete .select2-selection--single .select2-selection__arrow b { + border-color: #888 transparent transparent transparent; + border-style: solid; + border-width: 5px 4px 0 4px; + height: 0; + left: 50%; + margin-left: -4px; + margin-top: -2px; + position: absolute; + top: 50%; + width: 0; +} + +.select2-container--admin-autocomplete[dir="rtl"] .select2-selection--single .select2-selection__clear { + float: left; +} + +.select2-container--admin-autocomplete[dir="rtl"] .select2-selection--single .select2-selection__arrow { + left: 1px; + right: auto; +} + +.select2-container--admin-autocomplete.select2-container--disabled .select2-selection--single { + background-color: var(--darkened-bg); + cursor: default; +} + +.select2-container--admin-autocomplete.select2-container--disabled .select2-selection--single .select2-selection__clear { + display: none; +} + +.select2-container--admin-autocomplete.select2-container--open .select2-selection--single .select2-selection__arrow b { + border-color: transparent transparent #888 transparent; + border-width: 0 4px 5px 4px; +} + +.select2-container--admin-autocomplete .select2-selection--multiple { + background-color: var(--body-bg); + border: 1px solid var(--border-color); + border-radius: 4px; + cursor: text; +} + +.select2-container--admin-autocomplete .select2-selection--multiple .select2-selection__rendered { + box-sizing: border-box; + list-style: none; + margin: 0; + padding: 0 10px 5px 5px; + width: 100%; + display: flex; + flex-wrap: wrap; +} + +.select2-container--admin-autocomplete .select2-selection--multiple .select2-selection__rendered li { + list-style: none; +} + +.select2-container--admin-autocomplete .select2-selection--multiple .select2-selection__placeholder { + color: var(--body-quiet-color); + margin-top: 5px; + float: left; +} + +.select2-container--admin-autocomplete .select2-selection--multiple .select2-selection__clear { + cursor: pointer; + float: right; + font-weight: bold; + margin: 5px; + position: absolute; + right: 0; +} + +.select2-container--admin-autocomplete .select2-selection--multiple .select2-selection__choice { + background-color: var(--darkened-bg); + border: 1px solid var(--border-color); + border-radius: 4px; + cursor: default; + float: left; + margin-right: 5px; + margin-top: 5px; + padding: 0 5px; +} + +.select2-container--admin-autocomplete .select2-selection--multiple .select2-selection__choice__remove { + color: var(--body-quiet-color); + cursor: pointer; + display: inline-block; + font-weight: bold; + margin-right: 2px; +} + +.select2-container--admin-autocomplete .select2-selection--multiple .select2-selection__choice__remove:hover { + color: var(--body-fg); +} + +.select2-container--admin-autocomplete[dir="rtl"] .select2-selection--multiple .select2-selection__choice, .select2-container--admin-autocomplete[dir="rtl"] .select2-selection--multiple .select2-selection__placeholder, .select2-container--admin-autocomplete[dir="rtl"] .select2-selection--multiple .select2-search--inline { + float: right; +} + +.select2-container--admin-autocomplete[dir="rtl"] .select2-selection--multiple .select2-selection__choice { + margin-left: 5px; + margin-right: auto; +} + +.select2-container--admin-autocomplete[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove { + margin-left: 2px; + margin-right: auto; +} + +.select2-container--admin-autocomplete.select2-container--focus .select2-selection--multiple { + border: solid var(--body-quiet-color) 1px; + outline: 0; +} + +.select2-container--admin-autocomplete.select2-container--disabled .select2-selection--multiple { + background-color: var(--darkened-bg); + cursor: default; +} + +.select2-container--admin-autocomplete.select2-container--disabled .select2-selection__choice__remove { + display: none; +} + +.select2-container--admin-autocomplete.select2-container--open.select2-container--above .select2-selection--single, .select2-container--admin-autocomplete.select2-container--open.select2-container--above .select2-selection--multiple { + border-top-left-radius: 0; + border-top-right-radius: 0; +} + +.select2-container--admin-autocomplete.select2-container--open.select2-container--below .select2-selection--single, .select2-container--admin-autocomplete.select2-container--open.select2-container--below .select2-selection--multiple { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; +} + +.select2-container--admin-autocomplete .select2-search--dropdown { + background: var(--darkened-bg); +} + +.select2-container--admin-autocomplete .select2-search--dropdown .select2-search__field { + background: var(--body-bg); + color: var(--body-fg); + border: 1px solid var(--border-color); + border-radius: 4px; +} + +.select2-container--admin-autocomplete .select2-search--inline .select2-search__field { + background: transparent; + color: var(--body-fg); + border: none; + outline: 0; + box-shadow: none; + -webkit-appearance: textfield; +} + +.select2-container--admin-autocomplete .select2-results > .select2-results__options { + max-height: 200px; + overflow-y: auto; + color: var(--body-fg); + background: var(--body-bg); +} + +.select2-container--admin-autocomplete .select2-results__option[role=group] { + padding: 0; +} + +.select2-container--admin-autocomplete .select2-results__option[aria-disabled=true] { + color: var(--body-quiet-color); +} + +.select2-container--admin-autocomplete .select2-results__option[aria-selected=true] { + background-color: var(--selected-bg); + color: var(--body-fg); +} + +.select2-container--admin-autocomplete .select2-results__option .select2-results__option { + padding-left: 1em; +} + +.select2-container--admin-autocomplete .select2-results__option .select2-results__option .select2-results__group { + padding-left: 0; +} + +.select2-container--admin-autocomplete .select2-results__option .select2-results__option .select2-results__option { + margin-left: -1em; + padding-left: 2em; +} + +.select2-container--admin-autocomplete .select2-results__option .select2-results__option .select2-results__option .select2-results__option { + margin-left: -2em; + padding-left: 3em; +} + +.select2-container--admin-autocomplete .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option { + margin-left: -3em; + padding-left: 4em; +} + +.select2-container--admin-autocomplete .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option { + margin-left: -4em; + padding-left: 5em; +} + +.select2-container--admin-autocomplete .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option { + margin-left: -5em; + padding-left: 6em; +} + +.select2-container--admin-autocomplete .select2-results__option--highlighted[aria-selected] { + background-color: var(--primary); + color: var(--primary-fg); +} + +.select2-container--admin-autocomplete .select2-results__group { + cursor: default; + display: block; + padding: 6px; +} + +.errors .select2-selection { + border: 1px solid var(--error-fg); +} diff --git a/lottery/staticfiles/admin/css/base.css b/lottery/staticfiles/admin/css/base.css new file mode 100644 index 0000000..ac28326 --- /dev/null +++ b/lottery/staticfiles/admin/css/base.css @@ -0,0 +1,1179 @@ +/* + DJANGO Admin styles +*/ + +/* VARIABLE DEFINITIONS */ +html[data-theme="light"], +:root { + --primary: #79aec8; + --secondary: #417690; + --accent: #f5dd5d; + --primary-fg: #fff; + + --body-fg: #333; + --body-bg: #fff; + --body-quiet-color: #666; + --body-medium-color: #444; + --body-loud-color: #000; + + --header-color: #ffc; + --header-branding-color: var(--accent); + --header-bg: var(--secondary); + --header-link-color: var(--primary-fg); + + --breadcrumbs-fg: #c4dce8; + --breadcrumbs-link-fg: var(--body-bg); + --breadcrumbs-bg: #264b5d; + + --link-fg: #417893; + --link-hover-color: #036; + --link-selected-fg: var(--secondary); + + --hairline-color: #e8e8e8; + --border-color: #ccc; + + --error-fg: #ba2121; + + --message-success-bg: #dfd; + --message-warning-bg: #ffc; + --message-error-bg: #ffefef; + + --darkened-bg: #f8f8f8; /* A bit darker than --body-bg */ + --selected-bg: #e4e4e4; /* E.g. selected table cells */ + --selected-row: #ffc; + + --button-fg: #fff; + --button-bg: var(--secondary); + --button-hover-bg: #205067; + --default-button-bg: #205067; + --default-button-hover-bg: var(--secondary); + --close-button-bg: #747474; + --close-button-hover-bg: #333; + --delete-button-bg: #ba2121; + --delete-button-hover-bg: #a41515; + + --object-tools-fg: var(--button-fg); + --object-tools-bg: var(--close-button-bg); + --object-tools-hover-bg: var(--close-button-hover-bg); + + --font-family-primary: + "Segoe UI", + system-ui, + Roboto, + "Helvetica Neue", + Arial, + sans-serif, + "Apple Color Emoji", + "Segoe UI Emoji", + "Segoe UI Symbol", + "Noto Color Emoji"; + --font-family-monospace: + ui-monospace, + Menlo, + Monaco, + "Cascadia Mono", + "Segoe UI Mono", + "Roboto Mono", + "Oxygen Mono", + "Ubuntu Monospace", + "Source Code Pro", + "Fira Mono", + "Droid Sans Mono", + "Courier New", + monospace, + "Apple Color Emoji", + "Segoe UI Emoji", + "Segoe UI Symbol", + "Noto Color Emoji"; + + color-scheme: light; +} + +html, body { + height: 100%; +} + +body { + margin: 0; + padding: 0; + font-size: 0.875rem; + font-family: var(--font-family-primary); + color: var(--body-fg); + background: var(--body-bg); +} + +/* LINKS */ + +a:link, a:visited { + color: var(--link-fg); + text-decoration: none; + transition: color 0.15s, background 0.15s; +} + +a:focus, a:hover { + color: var(--link-hover-color); +} + +a:focus { + text-decoration: underline; +} + +a img { + border: none; +} + +a.section:link, a.section:visited { + color: var(--header-link-color); + text-decoration: none; +} + +a.section:focus, a.section:hover { + text-decoration: underline; +} + +/* GLOBAL DEFAULTS */ + +p, ol, ul, dl { + margin: .2em 0 .8em 0; +} + +p { + padding: 0; + line-height: 140%; +} + +h1,h2,h3,h4,h5 { + font-weight: bold; +} + +h1 { + margin: 0 0 20px; + font-weight: 300; + font-size: 1.25rem; +} + +h2 { + font-size: 1rem; + margin: 1em 0 .5em 0; +} + +h2.subhead { + font-weight: normal; + margin-top: 0; +} + +h3 { + font-size: 0.875rem; + margin: .8em 0 .3em 0; + color: var(--body-medium-color); + font-weight: bold; +} + +h4 { + font-size: 0.75rem; + margin: 1em 0 .8em 0; + padding-bottom: 3px; + color: var(--body-medium-color); +} + +h5 { + font-size: 0.625rem; + margin: 1.5em 0 .5em 0; + color: var(--body-quiet-color); + text-transform: uppercase; + letter-spacing: 1px; +} + +ul > li { + list-style-type: square; + padding: 1px 0; +} + +li ul { + margin-bottom: 0; +} + +li, dt, dd { + font-size: 0.8125rem; + line-height: 1.25rem; +} + +dt { + font-weight: bold; + margin-top: 4px; +} + +dd { + margin-left: 0; +} + +form { + margin: 0; + padding: 0; +} + +fieldset { + margin: 0; + min-width: 0; + padding: 0; + border: none; + border-top: 1px solid var(--hairline-color); +} + +details summary { + cursor: pointer; +} + +blockquote { + font-size: 0.6875rem; + color: #777; + margin-left: 2px; + padding-left: 10px; + border-left: 5px solid #ddd; +} + +code, pre { + font-family: var(--font-family-monospace); + color: var(--body-quiet-color); + font-size: 0.75rem; + overflow-x: auto; +} + +pre.literal-block { + margin: 10px; + background: var(--darkened-bg); + padding: 6px 8px; +} + +code strong { + color: #930; +} + +hr { + clear: both; + color: var(--hairline-color); + background-color: var(--hairline-color); + height: 1px; + border: none; + margin: 0; + padding: 0; + line-height: 1px; +} + +/* TEXT STYLES & MODIFIERS */ + +.small { + font-size: 0.6875rem; +} + +.mini { + font-size: 0.625rem; +} + +.help, p.help, form p.help, div.help, form div.help, div.help li { + font-size: 0.6875rem; + color: var(--body-quiet-color); +} + +div.help ul { + margin-bottom: 0; +} + +.help-tooltip { + cursor: help; +} + +p img, h1 img, h2 img, h3 img, h4 img, td img { + vertical-align: middle; +} + +.quiet, a.quiet:link, a.quiet:visited { + color: var(--body-quiet-color); + font-weight: normal; +} + +.clear { + clear: both; +} + +.nowrap { + white-space: nowrap; +} + +.hidden { + display: none !important; +} + +/* TABLES */ + +table { + border-collapse: collapse; + border-color: var(--border-color); +} + +td, th { + font-size: 0.8125rem; + line-height: 1rem; + border-bottom: 1px solid var(--hairline-color); + vertical-align: top; + padding: 8px; +} + +th { + font-weight: 500; + text-align: left; +} + +thead th, +tfoot td { + color: var(--body-quiet-color); + padding: 5px 10px; + font-size: 0.6875rem; + background: var(--body-bg); + border: none; + border-top: 1px solid var(--hairline-color); + border-bottom: 1px solid var(--hairline-color); +} + +tfoot td { + border-bottom: none; + border-top: 1px solid var(--hairline-color); +} + +thead th.required { + font-weight: bold; +} + +tr.alt { + background: var(--darkened-bg); +} + +tr:nth-child(odd), .row-form-errors { + background: var(--body-bg); +} + +tr:nth-child(even), +tr:nth-child(even) .errorlist, +tr:nth-child(odd) + .row-form-errors, +tr:nth-child(odd) + .row-form-errors .errorlist { + background: var(--darkened-bg); +} + +/* SORTABLE TABLES */ + +thead th { + padding: 5px 10px; + line-height: normal; + text-transform: uppercase; + background: var(--darkened-bg); +} + +thead th a:link, thead th a:visited { + color: var(--body-quiet-color); +} + +thead th.sorted { + background: var(--selected-bg); +} + +thead th.sorted .text { + padding-right: 42px; +} + +table thead th .text span { + padding: 8px 10px; + display: block; +} + +table thead th .text a { + display: block; + cursor: pointer; + padding: 8px 10px; +} + +table thead th .text a:focus, table thead th .text a:hover { + background: var(--selected-bg); +} + +thead th.sorted a.sortremove { + visibility: hidden; +} + +table thead th.sorted:hover a.sortremove { + visibility: visible; +} + +table thead th.sorted .sortoptions { + display: block; + padding: 9px 5px 0 5px; + float: right; + text-align: right; +} + +table thead th.sorted .sortpriority { + font-size: .8em; + min-width: 12px; + text-align: center; + vertical-align: 3px; + margin-left: 2px; + margin-right: 2px; +} + +table thead th.sorted .sortoptions a { + position: relative; + width: 14px; + height: 14px; + display: inline-block; + background: url(../img/sorting-icons.svg) 0 0 no-repeat; + background-size: 14px auto; +} + +table thead th.sorted .sortoptions a.sortremove { + background-position: 0 0; +} + +table thead th.sorted .sortoptions a.sortremove:after { + content: '\\'; + position: absolute; + top: -6px; + left: 3px; + font-weight: 200; + font-size: 1.125rem; + color: var(--body-quiet-color); +} + +table thead th.sorted .sortoptions a.sortremove:focus:after, +table thead th.sorted .sortoptions a.sortremove:hover:after { + color: var(--link-fg); +} + +table thead th.sorted .sortoptions a.sortremove:focus, +table thead th.sorted .sortoptions a.sortremove:hover { + background-position: 0 -14px; +} + +table thead th.sorted .sortoptions a.ascending { + background-position: 0 -28px; +} + +table thead th.sorted .sortoptions a.ascending:focus, +table thead th.sorted .sortoptions a.ascending:hover { + background-position: 0 -42px; +} + +table thead th.sorted .sortoptions a.descending { + top: 1px; + background-position: 0 -56px; +} + +table thead th.sorted .sortoptions a.descending:focus, +table thead th.sorted .sortoptions a.descending:hover { + background-position: 0 -70px; +} + +/* FORM DEFAULTS */ + +input, textarea, select, .form-row p, form .button { + margin: 2px 0; + padding: 2px 3px; + vertical-align: middle; + font-family: var(--font-family-primary); + font-weight: normal; + font-size: 0.8125rem; +} +.form-row div.help { + padding: 2px 3px; +} + +textarea { + vertical-align: top; +} + +/* +Minifiers remove the default (text) "type" attribute from "input" HTML tags. +Add input:not([type]) to make the CSS stylesheet work the same. +*/ +input:not([type]), input[type=text], input[type=password], input[type=email], +input[type=url], input[type=number], input[type=tel], textarea, select, +.vTextField { + border: 1px solid var(--border-color); + border-radius: 4px; + padding: 5px 6px; + margin-top: 0; + color: var(--body-fg); + background-color: var(--body-bg); +} + +/* +Minifiers remove the default (text) "type" attribute from "input" HTML tags. +Add input:not([type]) to make the CSS stylesheet work the same. +*/ +input:not([type]):focus, input[type=text]:focus, input[type=password]:focus, +input[type=email]:focus, input[type=url]:focus, input[type=number]:focus, +input[type=tel]:focus, textarea:focus, select:focus, .vTextField:focus { + border-color: var(--body-quiet-color); +} + +select { + height: 1.875rem; +} + +select[multiple] { + /* Allow HTML size attribute to override the height in the rule above. */ + height: auto; + min-height: 150px; +} + +/* FORM BUTTONS */ + +.button, input[type=submit], input[type=button], .submit-row input, a.button { + background: var(--button-bg); + padding: 10px 15px; + border: none; + border-radius: 4px; + color: var(--button-fg); + cursor: pointer; + transition: background 0.15s; +} + +a.button { + padding: 4px 5px; +} + +.button:active, input[type=submit]:active, input[type=button]:active, +.button:focus, input[type=submit]:focus, input[type=button]:focus, +.button:hover, input[type=submit]:hover, input[type=button]:hover { + background: var(--button-hover-bg); +} + +.button[disabled], input[type=submit][disabled], input[type=button][disabled] { + opacity: 0.4; +} + +.button.default, input[type=submit].default, .submit-row input.default { + border: none; + font-weight: 400; + background: var(--default-button-bg); +} + +.button.default:active, input[type=submit].default:active, +.button.default:focus, input[type=submit].default:focus, +.button.default:hover, input[type=submit].default:hover { + background: var(--default-button-hover-bg); +} + +.button[disabled].default, +input[type=submit][disabled].default, +input[type=button][disabled].default { + opacity: 0.4; +} + + +/* MODULES */ + +.module { + border: none; + margin-bottom: 30px; + background: var(--body-bg); +} + +.module p, .module ul, .module h3, .module h4, .module dl, .module pre { + padding-left: 10px; + padding-right: 10px; +} + +.module blockquote { + margin-left: 12px; +} + +.module ul, .module ol { + margin-left: 1.5em; +} + +.module h3 { + margin-top: .6em; +} + +.module h2, .module caption, .inline-group h2 { + margin: 0; + padding: 8px; + font-weight: 400; + font-size: 0.8125rem; + text-align: left; + background: var(--header-bg); + color: var(--header-link-color); +} + +.module caption, +.inline-group h2 { + font-size: 0.75rem; + letter-spacing: 0.5px; + text-transform: uppercase; +} + +.module table { + border-collapse: collapse; +} + +/* MESSAGES & ERRORS */ + +ul.messagelist { + padding: 0; + margin: 0; +} + +ul.messagelist li { + display: block; + font-weight: 400; + font-size: 0.8125rem; + padding: 10px 10px 10px 65px; + margin: 0 0 10px 0; + background: var(--message-success-bg) url(../img/icon-yes.svg) 40px 12px no-repeat; + background-size: 16px auto; + color: var(--body-fg); + word-break: break-word; +} + +ul.messagelist li.warning { + background: var(--message-warning-bg) url(../img/icon-alert.svg) 40px 14px no-repeat; + background-size: 14px auto; +} + +ul.messagelist li.error { + background: var(--message-error-bg) url(../img/icon-no.svg) 40px 12px no-repeat; + background-size: 16px auto; +} + +.errornote { + font-size: 0.875rem; + font-weight: 700; + display: block; + padding: 10px 12px; + margin: 0 0 10px 0; + color: var(--error-fg); + border: 1px solid var(--error-fg); + border-radius: 4px; + background-color: var(--body-bg); + background-position: 5px 12px; + overflow-wrap: break-word; +} + +ul.errorlist { + margin: 0 0 4px; + padding: 0; + color: var(--error-fg); + background: var(--body-bg); +} + +ul.errorlist li { + font-size: 0.8125rem; + display: block; + margin-bottom: 4px; + overflow-wrap: break-word; +} + +ul.errorlist li:first-child { + margin-top: 0; +} + +ul.errorlist li a { + color: inherit; + text-decoration: underline; +} + +td ul.errorlist { + margin: 0; + padding: 0; +} + +td ul.errorlist li { + margin: 0; +} + +.form-row.errors { + margin: 0; + border: none; + border-bottom: 1px solid var(--hairline-color); + background: none; +} + +.form-row.errors ul.errorlist li { + padding-left: 0; +} + +.errors input, .errors select, .errors textarea, +td ul.errorlist + input, td ul.errorlist + select, td ul.errorlist + textarea { + border: 1px solid var(--error-fg); +} + +.description { + font-size: 0.75rem; + padding: 5px 0 0 12px; +} + +/* BREADCRUMBS */ + +div.breadcrumbs { + background: var(--breadcrumbs-bg); + padding: 10px 40px; + border: none; + color: var(--breadcrumbs-fg); + text-align: left; +} + +div.breadcrumbs a { + color: var(--breadcrumbs-link-fg); +} + +div.breadcrumbs a:focus, div.breadcrumbs a:hover { + color: var(--breadcrumbs-fg); +} + +/* ACTION ICONS */ + +.viewlink, .inlineviewlink { + padding-left: 16px; + background: url(../img/icon-viewlink.svg) 0 1px no-repeat; +} + +.hidelink { + padding-left: 16px; + background: url(../img/icon-hidelink.svg) 0 1px no-repeat; +} + +.addlink { + padding-left: 16px; + background: url(../img/icon-addlink.svg) 0 1px no-repeat; +} + +.changelink, .inlinechangelink { + padding-left: 16px; + background: url(../img/icon-changelink.svg) 0 1px no-repeat; +} + +.deletelink { + padding-left: 16px; + background: url(../img/icon-deletelink.svg) 0 1px no-repeat; +} + +a.deletelink:link, a.deletelink:visited { + color: #CC3434; /* XXX Probably unused? */ +} + +a.deletelink:focus, a.deletelink:hover { + color: #993333; /* XXX Probably unused? */ + text-decoration: none; +} + +/* OBJECT TOOLS */ + +.object-tools { + font-size: 0.625rem; + font-weight: bold; + padding-left: 0; + float: right; + position: relative; + margin-top: -48px; +} + +.object-tools li { + display: block; + float: left; + margin-left: 5px; + height: 1rem; +} + +.object-tools a { + border-radius: 15px; +} + +.object-tools a:link, .object-tools a:visited { + display: block; + float: left; + padding: 3px 12px; + background: var(--object-tools-bg); + color: var(--object-tools-fg); + font-weight: 400; + font-size: 0.6875rem; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.object-tools a:focus, .object-tools a:hover { + background-color: var(--object-tools-hover-bg); +} + +.object-tools a:focus{ + text-decoration: none; +} + +.object-tools a.viewsitelink, .object-tools a.addlink { + background-repeat: no-repeat; + background-position: right 7px center; + padding-right: 26px; +} + +.object-tools a.viewsitelink { + background-image: url(../img/tooltag-arrowright.svg); +} + +.object-tools a.addlink { + background-image: url(../img/tooltag-add.svg); +} + +/* OBJECT HISTORY */ + +#change-history table { + width: 100%; +} + +#change-history table tbody th { + width: 16em; +} + +#change-history .paginator { + color: var(--body-quiet-color); + border-bottom: 1px solid var(--hairline-color); + background: var(--body-bg); + overflow: hidden; +} + +/* PAGE STRUCTURE */ + +#container { + position: relative; + width: 100%; + min-width: 980px; + padding: 0; + display: flex; + flex-direction: column; + height: 100%; +} + +#container > .main { + display: flex; + flex: 1 0 auto; +} + +.main > .content { + flex: 1 0; + max-width: 100%; +} + +.skip-to-content-link { + position: absolute; + top: -999px; + margin: 5px; + padding: 5px; + background: var(--body-bg); + z-index: 1; +} + +.skip-to-content-link:focus { + left: 0px; + top: 0px; +} + +#content { + padding: 20px 40px; +} + +.dashboard #content { + width: 600px; +} + +#content-main { + float: left; + width: 100%; +} + +#content-related { + float: right; + width: 260px; + position: relative; + margin-right: -300px; +} + +@media (forced-colors: active) { + #content-related { + border: 1px solid; + } +} + +/* COLUMN TYPES */ + +.colMS { + margin-right: 300px; +} + +.colSM { + margin-left: 300px; +} + +.colSM #content-related { + float: left; + margin-right: 0; + margin-left: -300px; +} + +.colSM #content-main { + float: right; +} + +.popup .colM { + width: auto; +} + +/* HEADER */ + +#header { + width: auto; + height: auto; + display: flex; + justify-content: space-between; + align-items: center; + padding: 10px 40px; + background: var(--header-bg); + color: var(--header-color); +} + +#header a:link, #header a:visited, #logout-form button { + color: var(--header-link-color); +} + +#header a:focus , #header a:hover { + text-decoration: underline; +} + +@media (forced-colors: active) { + #header { + border-bottom: 1px solid; + } +} + +#branding { + display: flex; +} + +#site-name { + padding: 0; + margin: 0; + margin-inline-end: 20px; + font-weight: 300; + font-size: 1.5rem; + color: var(--header-branding-color); +} + +#site-name a:link, #site-name a:visited { + color: var(--accent); +} + +#branding h2 { + padding: 0 10px; + font-size: 0.875rem; + margin: -8px 0 8px 0; + font-weight: normal; + color: var(--header-color); +} + +#branding a:hover { + text-decoration: none; +} + +#logout-form { + display: inline; +} + +#logout-form button { + background: none; + border: 0; + cursor: pointer; + font-family: var(--font-family-primary); +} + +#user-tools { + float: right; + margin: 0 0 0 20px; + text-align: right; +} + +#user-tools, #logout-form button{ + padding: 0; + font-weight: 300; + font-size: 0.6875rem; + letter-spacing: 0.5px; + text-transform: uppercase; +} + +#user-tools a, #logout-form button { + border-bottom: 1px solid rgba(255, 255, 255, 0.25); +} + +#user-tools a:focus, #user-tools a:hover, +#logout-form button:active, #logout-form button:hover { + text-decoration: none; + border-bottom: 0; +} + +#logout-form button:active, #logout-form button:hover { + margin-bottom: 1px; +} + +/* SIDEBAR */ + +#content-related { + background: var(--darkened-bg); +} + +#content-related .module { + background: none; +} + +#content-related h3 { + color: var(--body-quiet-color); + padding: 0 16px; + margin: 0 0 16px; +} + +#content-related h4 { + font-size: 0.8125rem; +} + +#content-related p { + padding-left: 16px; + padding-right: 16px; +} + +#content-related .actionlist { + padding: 0; + margin: 16px; +} + +#content-related .actionlist li { + line-height: 1.2; + margin-bottom: 10px; + padding-left: 18px; +} + +#content-related .module h2 { + background: none; + padding: 16px; + margin-bottom: 16px; + border-bottom: 1px solid var(--hairline-color); + font-size: 1.125rem; + color: var(--body-fg); +} + +.delete-confirmation form input[type="submit"] { + background: var(--delete-button-bg); + border-radius: 4px; + padding: 10px 15px; + color: var(--button-fg); +} + +.delete-confirmation form input[type="submit"]:active, +.delete-confirmation form input[type="submit"]:focus, +.delete-confirmation form input[type="submit"]:hover { + background: var(--delete-button-hover-bg); +} + +.delete-confirmation form .cancel-link { + display: inline-block; + vertical-align: middle; + height: 0.9375rem; + line-height: 0.9375rem; + border-radius: 4px; + padding: 10px 15px; + color: var(--button-fg); + background: var(--close-button-bg); + margin: 0 0 0 10px; +} + +.delete-confirmation form .cancel-link:active, +.delete-confirmation form .cancel-link:focus, +.delete-confirmation form .cancel-link:hover { + background: var(--close-button-hover-bg); +} + +/* POPUP */ +.popup #content { + padding: 20px; +} + +.popup #container { + min-width: 0; +} + +.popup #header { + padding: 10px 20px; +} + +/* PAGINATOR */ + +.paginator { + display: flex; + align-items: center; + gap: 4px; + font-size: 0.8125rem; + padding-top: 10px; + padding-bottom: 10px; + line-height: 22px; + margin: 0; + border-top: 1px solid var(--hairline-color); + width: 100%; +} + +.paginator a:link, .paginator a:visited { + padding: 2px 6px; + background: var(--button-bg); + text-decoration: none; + color: var(--button-fg); +} + +.paginator a.showall { + border: none; + background: none; + color: var(--link-fg); +} + +.paginator a.showall:focus, .paginator a.showall:hover { + background: none; + color: var(--link-hover-color); +} + +.paginator .end { + margin-right: 6px; +} + +.paginator .this-page { + padding: 2px 6px; + font-weight: bold; + font-size: 0.8125rem; + vertical-align: top; +} + +.paginator a:focus, .paginator a:hover { + color: white; + background: var(--link-hover-color); +} + +.paginator input { + margin-left: auto; +} + +.base-svgs { + display: none; +} + +.visually-hidden { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + overflow: hidden; + clip: rect(0,0,0,0); + white-space: nowrap; + border: 0; + color: var(--body-fg); + background-color: var(--body-bg); +} diff --git a/lottery/staticfiles/admin/css/changelists.css b/lottery/staticfiles/admin/css/changelists.css new file mode 100644 index 0000000..005b776 --- /dev/null +++ b/lottery/staticfiles/admin/css/changelists.css @@ -0,0 +1,343 @@ +/* CHANGELISTS */ + +#changelist { + display: flex; + align-items: flex-start; + justify-content: space-between; +} + +#changelist .changelist-form-container { + flex: 1 1 auto; + min-width: 0; +} + +#changelist table { + width: 100%; +} + +.change-list .hiddenfields { display:none; } + +.change-list .filtered table { + border-right: none; +} + +.change-list .filtered { + min-height: 400px; +} + +.change-list .filtered .results, .change-list .filtered .paginator, +.filtered #toolbar, .filtered div.xfull { + width: auto; +} + +.change-list .filtered table tbody th { + padding-right: 1em; +} + +#changelist-form .results { + overflow-x: auto; + width: 100%; +} + +#changelist .toplinks { + border-bottom: 1px solid var(--hairline-color); +} + +#changelist .paginator { + color: var(--body-quiet-color); + border-bottom: 1px solid var(--hairline-color); + background: var(--body-bg); + overflow: hidden; +} + +/* CHANGELIST TABLES */ + +#changelist table thead th { + padding: 0; + white-space: nowrap; + vertical-align: middle; +} + +#changelist table thead th.action-checkbox-column { + width: 1.5em; + text-align: center; +} + +#changelist table tbody td.action-checkbox { + text-align: center; +} + +#changelist table tfoot { + color: var(--body-quiet-color); +} + +/* TOOLBAR */ + +#toolbar { + padding: 8px 10px; + margin-bottom: 15px; + border-top: 1px solid var(--hairline-color); + border-bottom: 1px solid var(--hairline-color); + background: var(--darkened-bg); + color: var(--body-quiet-color); +} + +#toolbar form input { + border-radius: 4px; + font-size: 0.875rem; + padding: 5px; + color: var(--body-fg); +} + +#toolbar #searchbar { + height: 1.1875rem; + border: 1px solid var(--border-color); + padding: 2px 5px; + margin: 0; + vertical-align: top; + font-size: 0.8125rem; + max-width: 100%; +} + +#toolbar #searchbar:focus { + border-color: var(--body-quiet-color); +} + +#toolbar form input[type="submit"] { + border: 1px solid var(--border-color); + font-size: 0.8125rem; + padding: 4px 8px; + margin: 0; + vertical-align: middle; + background: var(--body-bg); + box-shadow: 0 -15px 20px -10px rgba(0, 0, 0, 0.15) inset; + cursor: pointer; + color: var(--body-fg); +} + +#toolbar form input[type="submit"]:focus, +#toolbar form input[type="submit"]:hover { + border-color: var(--body-quiet-color); +} + +#changelist-search img { + vertical-align: middle; + margin-right: 4px; +} + +#changelist-search .help { + word-break: break-word; +} + +/* FILTER COLUMN */ + +#changelist-filter { + flex: 0 0 240px; + order: 1; + background: var(--darkened-bg); + border-left: none; + margin: 0 0 0 30px; +} + +@media (forced-colors: active) { + #changelist-filter { + border: 1px solid; + } +} + +#changelist-filter h2 { + font-size: 0.875rem; + text-transform: uppercase; + letter-spacing: 0.5px; + padding: 5px 15px; + margin-bottom: 12px; + border-bottom: none; +} + +#changelist-filter h3, +#changelist-filter details summary { + font-weight: 400; + padding: 0 15px; + margin-bottom: 10px; +} + +#changelist-filter details summary > * { + display: inline; +} + +#changelist-filter details > summary { + list-style-type: none; +} + +#changelist-filter details > summary::-webkit-details-marker { + display: none; +} + +#changelist-filter details > summary::before { + content: '→'; + font-weight: bold; + color: var(--link-hover-color); +} + +#changelist-filter details[open] > summary::before { + content: '↓'; +} + +#changelist-filter ul { + margin: 5px 0; + padding: 0 15px 15px; + border-bottom: 1px solid var(--hairline-color); +} + +#changelist-filter ul:last-child { + border-bottom: none; +} + +#changelist-filter li { + list-style-type: none; + margin-left: 0; + padding-left: 0; +} + +#changelist-filter a { + display: block; + color: var(--body-quiet-color); + word-break: break-word; +} + +#changelist-filter li.selected { + border-left: 5px solid var(--hairline-color); + padding-left: 10px; + margin-left: -15px; +} + +#changelist-filter li.selected a { + color: var(--link-selected-fg); +} + +#changelist-filter a:focus, #changelist-filter a:hover, +#changelist-filter li.selected a:focus, +#changelist-filter li.selected a:hover { + color: var(--link-hover-color); +} + +#changelist-filter #changelist-filter-extra-actions { + font-size: 0.8125rem; + margin-bottom: 10px; + border-bottom: 1px solid var(--hairline-color); +} + +/* DATE DRILLDOWN */ + +.change-list .toplinks { + display: flex; + padding-bottom: 5px; + flex-wrap: wrap; + gap: 3px 17px; + font-weight: bold; +} + +.change-list .toplinks a { + font-size: 0.8125rem; +} + +.change-list .toplinks .date-back { + color: var(--body-quiet-color); +} + +.change-list .toplinks .date-back:focus, +.change-list .toplinks .date-back:hover { + color: var(--link-hover-color); +} + +/* ACTIONS */ + +.filtered .actions { + border-right: none; +} + +#changelist table input { + margin: 0; + vertical-align: baseline; +} + +/* Once the :has() pseudo-class is supported by all browsers, the tr.selected + selector and the JS adding the class can be removed. */ +#changelist tbody tr.selected { + background-color: var(--selected-row); +} + +#changelist tbody tr:has(.action-select:checked) { + background-color: var(--selected-row); +} + +@media (forced-colors: active) { + #changelist tbody tr.selected { + background-color: SelectedItem; + } + #changelist tbody tr:has(.action-select:checked) { + background-color: SelectedItem; + } +} + +#changelist .actions { + padding: 10px; + background: var(--body-bg); + border-top: none; + border-bottom: none; + line-height: 1.5rem; + color: var(--body-quiet-color); + width: 100%; +} + +#changelist .actions span.all, +#changelist .actions span.action-counter, +#changelist .actions span.clear, +#changelist .actions span.question { + font-size: 0.8125rem; + margin: 0 0.5em; +} + +#changelist .actions:last-child { + border-bottom: none; +} + +#changelist .actions select { + vertical-align: top; + height: 1.5rem; + color: var(--body-fg); + border: 1px solid var(--border-color); + border-radius: 4px; + font-size: 0.875rem; + padding: 0 0 0 4px; + margin: 0; + margin-left: 10px; +} + +#changelist .actions select:focus { + border-color: var(--body-quiet-color); +} + +#changelist .actions label { + display: inline-block; + vertical-align: middle; + font-size: 0.8125rem; +} + +#changelist .actions .button { + font-size: 0.8125rem; + border: 1px solid var(--border-color); + border-radius: 4px; + background: var(--body-bg); + box-shadow: 0 -15px 20px -10px rgba(0, 0, 0, 0.15) inset; + cursor: pointer; + height: 1.5rem; + line-height: 1; + padding: 4px 8px; + margin: 0; + color: var(--body-fg); +} + +#changelist .actions .button:focus, #changelist .actions .button:hover { + border-color: var(--body-quiet-color); +} diff --git a/lottery/staticfiles/admin/css/custom.css b/lottery/staticfiles/admin/css/custom.css new file mode 100644 index 0000000..bebe770 --- /dev/null +++ b/lottery/staticfiles/admin/css/custom.css @@ -0,0 +1,12 @@ +/* custom.css */ + +/* Пример отступа для вложенных пунктов сайдбара */ +.sidebar-nav .nav-child { + padding-left: 50px !important; +} + +/* Дополнительный стиль для более яркого визуального разделения вложенных элементов */ +.sidebar-nav .nav-child > a { + font-size: 0.9em; + color: #6c757d; +} diff --git a/lottery/staticfiles/admin/css/dark_mode.css b/lottery/staticfiles/admin/css/dark_mode.css new file mode 100644 index 0000000..7e12a81 --- /dev/null +++ b/lottery/staticfiles/admin/css/dark_mode.css @@ -0,0 +1,130 @@ +@media (prefers-color-scheme: dark) { + :root { + --primary: #264b5d; + --primary-fg: #f7f7f7; + + --body-fg: #eeeeee; + --body-bg: #121212; + --body-quiet-color: #d0d0d0; + --body-medium-color: #e0e0e0; + --body-loud-color: #ffffff; + + --breadcrumbs-link-fg: #e0e0e0; + --breadcrumbs-bg: var(--primary); + + --link-fg: #81d4fa; + --link-hover-color: #4ac1f7; + --link-selected-fg: #6f94c6; + + --hairline-color: #272727; + --border-color: #353535; + + --error-fg: #e35f5f; + --message-success-bg: #006b1b; + --message-warning-bg: #583305; + --message-error-bg: #570808; + + --darkened-bg: #212121; + --selected-bg: #1b1b1b; + --selected-row: #00363a; + + --close-button-bg: #333333; + --close-button-hover-bg: #666666; + + color-scheme: dark; + } + } + + +html[data-theme="dark"] { + --primary: #264b5d; + --primary-fg: #f7f7f7; + + --body-fg: #eeeeee; + --body-bg: #121212; + --body-quiet-color: #d0d0d0; + --body-medium-color: #e0e0e0; + --body-loud-color: #ffffff; + + --breadcrumbs-link-fg: #e0e0e0; + --breadcrumbs-bg: var(--primary); + + --link-fg: #81d4fa; + --link-hover-color: #4ac1f7; + --link-selected-fg: #6f94c6; + + --hairline-color: #272727; + --border-color: #353535; + + --error-fg: #e35f5f; + --message-success-bg: #006b1b; + --message-warning-bg: #583305; + --message-error-bg: #570808; + + --darkened-bg: #212121; + --selected-bg: #1b1b1b; + --selected-row: #00363a; + + --close-button-bg: #333333; + --close-button-hover-bg: #666666; + + color-scheme: dark; +} + +/* THEME SWITCH */ +.theme-toggle { + cursor: pointer; + border: none; + padding: 0; + background: transparent; + vertical-align: middle; + margin-inline-start: 5px; + margin-top: -1px; +} + +.theme-toggle svg { + vertical-align: middle; + height: 1rem; + width: 1rem; + display: none; +} + +/* +Fully hide screen reader text so we only show the one matching the current +theme. +*/ +.theme-toggle .visually-hidden { + display: none; +} + +html[data-theme="auto"] .theme-toggle .theme-label-when-auto { + display: block; +} + +html[data-theme="dark"] .theme-toggle .theme-label-when-dark { + display: block; +} + +html[data-theme="light"] .theme-toggle .theme-label-when-light { + display: block; +} + +/* ICONS */ +.theme-toggle svg.theme-icon-when-auto, +.theme-toggle svg.theme-icon-when-dark, +.theme-toggle svg.theme-icon-when-light { + fill: var(--header-link-color); + color: var(--header-bg); +} + +html[data-theme="auto"] .theme-toggle svg.theme-icon-when-auto { + display: block; +} + +html[data-theme="dark"] .theme-toggle svg.theme-icon-when-dark { + display: block; +} + +html[data-theme="light"] .theme-toggle svg.theme-icon-when-light { + display: block; +} diff --git a/lottery/staticfiles/admin/css/dashboard.css b/lottery/staticfiles/admin/css/dashboard.css new file mode 100644 index 0000000..242b81a --- /dev/null +++ b/lottery/staticfiles/admin/css/dashboard.css @@ -0,0 +1,29 @@ +/* DASHBOARD */ +.dashboard td, .dashboard th { + word-break: break-word; +} + +.dashboard .module table th { + width: 100%; +} + +.dashboard .module table td { + white-space: nowrap; +} + +.dashboard .module table td a { + display: block; + padding-right: .6em; +} + +/* RECENT ACTIONS MODULE */ + +.module ul.actionlist { + margin-left: 0; +} + +ul.actionlist li { + list-style-type: none; + overflow: hidden; + text-overflow: ellipsis; +} diff --git a/lottery/staticfiles/admin/css/forms.css b/lottery/staticfiles/admin/css/forms.css new file mode 100644 index 0000000..4f49b61 --- /dev/null +++ b/lottery/staticfiles/admin/css/forms.css @@ -0,0 +1,512 @@ +@import url('widgets.css'); + +/* FORM ROWS */ + +.form-row { + overflow: hidden; + padding: 10px; + font-size: 0.8125rem; + border-bottom: 1px solid var(--hairline-color); +} + +.form-row img, .form-row input { + vertical-align: middle; +} + +.form-row label input[type="checkbox"] { + margin-top: 0; + vertical-align: 0; +} + +form .form-row p { + padding-left: 0; +} + +.flex-container { + display: flex; +} + +.form-multiline { + flex-wrap: wrap; +} + +.form-multiline > div { + padding-bottom: 10px; +} + +/* FORM LABELS */ + +label { + font-weight: normal; + color: var(--body-quiet-color); + font-size: 0.8125rem; +} + +.required label, label.required { + font-weight: bold; +} + +/* RADIO BUTTONS */ + +form div.radiolist div { + padding-right: 7px; +} + +form div.radiolist.inline div { + display: inline-block; +} + +form div.radiolist label { + width: auto; +} + +form div.radiolist input[type="radio"] { + margin: -2px 4px 0 0; + padding: 0; +} + +form ul.inline { + margin-left: 0; + padding: 0; +} + +form ul.inline li { + float: left; + padding-right: 7px; +} + +/* FIELDSETS */ + +fieldset .fieldset-heading, +fieldset .inline-heading, +:not(.inline-related) .collapse summary { + border: 1px solid var(--header-bg); + margin: 0; + padding: 8px; + font-weight: 400; + font-size: 0.8125rem; + background: var(--header-bg); + color: var(--header-link-color); +} + +/* ALIGNED FIELDSETS */ + +.aligned label { + display: block; + padding: 4px 10px 0 0; + min-width: 160px; + width: 160px; + word-wrap: break-word; +} + +.aligned label:not(.vCheckboxLabel):after { + content: ''; + display: inline-block; + vertical-align: middle; +} + +.aligned label + p, .aligned .checkbox-row + div.help, .aligned label + div.readonly { + padding: 6px 0; + margin-top: 0; + margin-bottom: 0; + margin-left: 0; + overflow-wrap: break-word; +} + +.aligned ul label { + display: inline; + float: none; + width: auto; +} + +.aligned .form-row input { + margin-bottom: 0; +} + +.colMS .aligned .vLargeTextField, .colMS .aligned .vXMLLargeTextField { + width: 350px; +} + +form .aligned ul { + margin-left: 160px; + padding-left: 10px; +} + +form .aligned div.radiolist { + display: inline-block; + margin: 0; + padding: 0; +} + +form .aligned p.help, +form .aligned div.help { + margin-top: 0; + margin-left: 160px; + padding-left: 10px; +} + +form .aligned p.date div.help.timezonewarning, +form .aligned p.datetime div.help.timezonewarning, +form .aligned p.time div.help.timezonewarning { + margin-left: 0; + padding-left: 0; + font-weight: normal; +} + +form .aligned p.help:last-child, +form .aligned div.help:last-child { + margin-bottom: 0; + padding-bottom: 0; +} + +form .aligned input + p.help, +form .aligned textarea + p.help, +form .aligned select + p.help, +form .aligned input + div.help, +form .aligned textarea + div.help, +form .aligned select + div.help { + margin-left: 160px; + padding-left: 10px; +} + +form .aligned select option:checked { + background-color: var(--selected-row); +} + +form .aligned ul li { + list-style: none; +} + +form .aligned table p { + margin-left: 0; + padding-left: 0; +} + +.aligned .vCheckboxLabel { + padding: 1px 0 0 5px; +} + +.aligned .vCheckboxLabel + p.help, +.aligned .vCheckboxLabel + div.help { + margin-top: -4px; +} + +.colM .aligned .vLargeTextField, .colM .aligned .vXMLLargeTextField { + width: 610px; +} + +fieldset .fieldBox { + margin-right: 20px; +} + +/* WIDE FIELDSETS */ + +.wide label { + width: 200px; +} + +form .wide p.help, +form .wide ul.errorlist, +form .wide div.help { + padding-left: 50px; +} + +form div.help ul { + padding-left: 0; + margin-left: 0; +} + +.colM fieldset.wide .vLargeTextField, .colM fieldset.wide .vXMLLargeTextField { + width: 450px; +} + +/* COLLAPSIBLE FIELDSETS */ + +.collapse summary .fieldset-heading, +.collapse summary .inline-heading { + background: transparent; + border: none; + color: currentColor; + display: inline; + margin: 0; + padding: 0; +} + +/* MONOSPACE TEXTAREAS */ + +fieldset.monospace textarea { + font-family: var(--font-family-monospace); +} + +/* SUBMIT ROW */ + +.submit-row { + padding: 12px 14px 12px; + margin: 0 0 20px; + background: var(--darkened-bg); + border: 1px solid var(--hairline-color); + border-radius: 4px; + overflow: hidden; + display: flex; + gap: 10px; + flex-wrap: wrap; +} + +body.popup .submit-row { + overflow: auto; +} + +.submit-row input { + height: 2.1875rem; + line-height: 0.9375rem; +} + +.submit-row input, .submit-row a { + margin: 0; +} + +.submit-row input.default { + text-transform: uppercase; +} + +.submit-row a.deletelink { + margin-left: auto; +} + +.submit-row a.deletelink { + display: block; + background: var(--delete-button-bg); + border-radius: 4px; + padding: 0.625rem 0.9375rem; + height: 0.9375rem; + line-height: 0.9375rem; + color: var(--button-fg); +} + +.submit-row a.closelink { + display: inline-block; + background: var(--close-button-bg); + border-radius: 4px; + padding: 10px 15px; + height: 0.9375rem; + line-height: 0.9375rem; + color: var(--button-fg); +} + +.submit-row a.deletelink:focus, +.submit-row a.deletelink:hover, +.submit-row a.deletelink:active { + background: var(--delete-button-hover-bg); + text-decoration: none; +} + +.submit-row a.closelink:focus, +.submit-row a.closelink:hover, +.submit-row a.closelink:active { + background: var(--close-button-hover-bg); + text-decoration: none; +} + +/* CUSTOM FORM FIELDS */ + +.vSelectMultipleField { + vertical-align: top; +} + +.vCheckboxField { + border: none; +} + +.vDateField, .vTimeField { + margin-right: 2px; + margin-bottom: 4px; +} + +.vDateField { + min-width: 6.85em; +} + +.vTimeField { + min-width: 4.7em; +} + +.vURLField { + width: 30em; +} + +.vLargeTextField, .vXMLLargeTextField { + width: 48em; +} + +.flatpages-flatpage #id_content { + height: 40.2em; +} + +.module table .vPositiveSmallIntegerField { + width: 2.2em; +} + +.vIntegerField { + width: 5em; +} + +.vBigIntegerField { + width: 10em; +} + +.vForeignKeyRawIdAdminField { + width: 5em; +} + +.vTextField, .vUUIDField { + width: 20em; +} + +/* INLINES */ + +.inline-group { + padding: 0; + margin: 0 0 30px; +} + +.inline-group thead th { + padding: 8px 10px; +} + +.inline-group .aligned label { + width: 160px; +} + +.inline-related { + position: relative; +} + +.inline-related h4, +.inline-related:not(.tabular) .collapse summary { + margin: 0; + color: var(--body-medium-color); + padding: 5px; + font-size: 0.8125rem; + background: var(--darkened-bg); + border: 1px solid var(--hairline-color); + border-left-color: var(--darkened-bg); + border-right-color: var(--darkened-bg); +} + +.inline-related h3 span.delete { + float: right; +} + +.inline-related h3 span.delete label { + margin-left: 2px; + font-size: 0.6875rem; +} + +.inline-related fieldset { + margin: 0; + background: var(--body-bg); + border: none; + width: 100%; +} + +.inline-group .tabular fieldset.module { + border: none; +} + +.inline-related.tabular fieldset.module table { + width: 100%; + overflow-x: scroll; +} + +.last-related fieldset { + border: none; +} + +.inline-group .tabular tr.has_original td { + padding-top: 2em; +} + +.inline-group .tabular tr td.original { + padding: 2px 0 0 0; + width: 0; + _position: relative; +} + +.inline-group .tabular th.original { + width: 0px; + padding: 0; +} + +.inline-group .tabular td.original p { + position: absolute; + left: 0; + height: 1.1em; + padding: 2px 9px; + overflow: hidden; + font-size: 0.5625rem; + font-weight: bold; + color: var(--body-quiet-color); + _width: 700px; +} + +.inline-group ul.tools { + padding: 0; + margin: 0; + list-style: none; +} + +.inline-group ul.tools li { + display: inline; + padding: 0 5px; +} + +.inline-group div.add-row, +.inline-group .tabular tr.add-row td { + color: var(--body-quiet-color); + background: var(--darkened-bg); + padding: 8px 10px; + border-bottom: 1px solid var(--hairline-color); +} + +.inline-group .tabular tr.add-row td { + padding: 8px 10px; + border-bottom: 1px solid var(--hairline-color); +} + +.inline-group ul.tools a.add, +.inline-group div.add-row a, +.inline-group .tabular tr.add-row td a { + background: url(../img/icon-addlink.svg) 0 1px no-repeat; + padding-left: 16px; + font-size: 0.75rem; +} + +.empty-form { + display: none; +} + +/* RELATED FIELD ADD ONE / LOOKUP */ + +.related-lookup { + margin-left: 5px; + display: inline-block; + vertical-align: middle; + background-repeat: no-repeat; + background-size: 14px; +} + +.related-lookup { + width: 1rem; + height: 1rem; + background-image: url(../img/search.svg); +} + +form .related-widget-wrapper ul { + display: inline-block; + margin-left: 0; + padding-left: 0; +} + +.clearable-file-input input { + margin-top: 0; +} diff --git a/lottery/staticfiles/admin/css/login.css b/lottery/staticfiles/admin/css/login.css new file mode 100644 index 0000000..805a34b --- /dev/null +++ b/lottery/staticfiles/admin/css/login.css @@ -0,0 +1,61 @@ +/* LOGIN FORM */ + +.login { + background: var(--darkened-bg); + height: auto; +} + +.login #header { + height: auto; + padding: 15px 16px; + justify-content: center; +} + +.login #header h1 { + font-size: 1.125rem; + margin: 0; +} + +.login #header h1 a { + color: var(--header-link-color); +} + +.login #content { + padding: 20px; +} + +.login #container { + background: var(--body-bg); + border: 1px solid var(--hairline-color); + border-radius: 4px; + overflow: hidden; + width: 28em; + min-width: 300px; + margin: 100px auto; + height: auto; +} + +.login .form-row { + padding: 4px 0; +} + +.login .form-row label { + display: block; + line-height: 2em; +} + +.login .form-row #id_username, .login .form-row #id_password { + padding: 8px; + width: 100%; + box-sizing: border-box; +} + +.login .submit-row { + padding: 1em 0 0 0; + margin: 0; + text-align: center; +} + +.login .password-reset-link { + text-align: center; +} diff --git a/lottery/staticfiles/admin/css/nav_sidebar.css b/lottery/staticfiles/admin/css/nav_sidebar.css new file mode 100644 index 0000000..7eb0de9 --- /dev/null +++ b/lottery/staticfiles/admin/css/nav_sidebar.css @@ -0,0 +1,150 @@ +.sticky { + position: sticky; + top: 0; + max-height: 100vh; +} + +.toggle-nav-sidebar { + z-index: 20; + left: 0; + display: flex; + align-items: center; + justify-content: center; + flex: 0 0 23px; + width: 23px; + border: 0; + border-right: 1px solid var(--hairline-color); + background-color: var(--body-bg); + cursor: pointer; + font-size: 1.25rem; + color: var(--link-fg); + padding: 0; +} + +[dir="rtl"] .toggle-nav-sidebar { + border-left: 1px solid var(--hairline-color); + border-right: 0; +} + +.toggle-nav-sidebar:hover, +.toggle-nav-sidebar:focus { + background-color: var(--darkened-bg); +} + +#nav-sidebar { + z-index: 15; + flex: 0 0 275px; + left: -276px; + margin-left: -276px; + border-top: 1px solid transparent; + border-right: 1px solid var(--hairline-color); + background-color: var(--body-bg); + overflow: auto; +} + +[dir="rtl"] #nav-sidebar { + border-left: 1px solid var(--hairline-color); + border-right: 0; + left: 0; + margin-left: 0; + right: -276px; + margin-right: -276px; +} + +.toggle-nav-sidebar::before { + content: '\00BB'; +} + +.main.shifted .toggle-nav-sidebar::before { + content: '\00AB'; +} + +.main > #nav-sidebar { + visibility: hidden; +} + +.main.shifted > #nav-sidebar { + margin-left: 0; + visibility: visible; +} + +[dir="rtl"] .main.shifted > #nav-sidebar { + margin-right: 0; +} + +#nav-sidebar .module th { + width: 100%; + overflow-wrap: anywhere; +} + +#nav-sidebar .module th, +#nav-sidebar .module caption { + padding-left: 16px; +} + +#nav-sidebar .module td { + white-space: nowrap; +} + +[dir="rtl"] #nav-sidebar .module th, +[dir="rtl"] #nav-sidebar .module caption { + padding-left: 8px; + padding-right: 16px; +} + +#nav-sidebar .current-app .section:link, +#nav-sidebar .current-app .section:visited { + color: var(--header-color); + font-weight: bold; +} + +#nav-sidebar .current-model { + background: var(--selected-row); +} + +@media (forced-colors: active) { + #nav-sidebar .current-model { + background-color: SelectedItem; + } +} + +.main > #nav-sidebar + .content { + max-width: calc(100% - 23px); +} + +.main.shifted > #nav-sidebar + .content { + max-width: calc(100% - 299px); +} + +@media (max-width: 767px) { + #nav-sidebar, #toggle-nav-sidebar { + display: none; + } + + .main > #nav-sidebar + .content, + .main.shifted > #nav-sidebar + .content { + max-width: 100%; + } +} + +#nav-filter { + width: 100%; + box-sizing: border-box; + padding: 2px 5px; + margin: 5px 0; + border: 1px solid var(--border-color); + background-color: var(--darkened-bg); + color: var(--body-fg); +} + +#nav-filter:focus { + border-color: var(--body-quiet-color); +} + +#nav-filter.no-results { + background: var(--message-error-bg); +} + +#nav-sidebar table { + width: 100%; +} diff --git a/lottery/staticfiles/admin/css/responsive.css b/lottery/staticfiles/admin/css/responsive.css new file mode 100644 index 0000000..932e824 --- /dev/null +++ b/lottery/staticfiles/admin/css/responsive.css @@ -0,0 +1,967 @@ +/* Tablets */ + +input[type="submit"], button { + -webkit-appearance: none; + appearance: none; +} + +@media (max-width: 1024px) { + /* Basic */ + + html { + -webkit-text-size-adjust: 100%; + } + + td, th { + padding: 10px; + font-size: 0.875rem; + } + + .small { + font-size: 0.75rem; + } + + /* Layout */ + + #container { + min-width: 0; + } + + #content { + padding: 15px 20px 20px; + } + + div.breadcrumbs { + padding: 10px 30px; + } + + /* Header */ + + #header { + flex-direction: column; + padding: 15px 30px; + justify-content: flex-start; + } + + #site-name { + margin: 0 0 8px; + line-height: 1.2; + } + + #user-tools { + margin: 0; + font-weight: 400; + line-height: 1.85; + text-align: left; + } + + #user-tools a { + display: inline-block; + line-height: 1.4; + } + + /* Dashboard */ + + .dashboard #content { + width: auto; + } + + #content-related { + margin-right: -290px; + } + + .colSM #content-related { + margin-left: -290px; + } + + .colMS { + margin-right: 290px; + } + + .colSM { + margin-left: 290px; + } + + .dashboard .module table td a { + padding-right: 0; + } + + td .changelink, td .addlink { + font-size: 0.8125rem; + } + + /* Changelist */ + + #toolbar { + border: none; + padding: 15px; + } + + #changelist-search > div { + display: flex; + flex-wrap: nowrap; + max-width: 480px; + } + + #changelist-search label { + line-height: 1.375rem; + } + + #toolbar form #searchbar { + flex: 1 0 auto; + width: 0; + height: 1.375rem; + margin: 0 10px 0 6px; + } + + #toolbar form input[type=submit] { + flex: 0 1 auto; + } + + #changelist-search .quiet { + width: 0; + flex: 1 0 auto; + margin: 5px 0 0 25px; + } + + #changelist .actions { + display: flex; + flex-wrap: wrap; + padding: 15px 0; + } + + #changelist .actions label { + display: flex; + } + + #changelist .actions select { + background: var(--body-bg); + } + + #changelist .actions .button { + min-width: 48px; + margin: 0 10px; + } + + #changelist .actions span.all, + #changelist .actions span.clear, + #changelist .actions span.question, + #changelist .actions span.action-counter { + font-size: 0.6875rem; + margin: 0 10px 0 0; + } + + #changelist-filter { + flex-basis: 200px; + } + + .change-list .filtered .results, + .change-list .filtered .paginator, + .filtered #toolbar, + .filtered .actions, + + #changelist .paginator { + border-top-color: var(--hairline-color); /* XXX Is this used at all? */ + } + + #changelist .results + .paginator { + border-top: none; + } + + /* Forms */ + + label { + font-size: 1rem; + } + + /* + Minifiers remove the default (text) "type" attribute from "input" HTML + tags. Add input:not([type]) to make the CSS stylesheet work the same. + */ + .form-row input:not([type]), + .form-row input[type=text], + .form-row input[type=password], + .form-row input[type=email], + .form-row input[type=url], + .form-row input[type=tel], + .form-row input[type=number], + .form-row textarea, + .form-row select, + .form-row .vTextField { + box-sizing: border-box; + margin: 0; + padding: 6px 8px; + min-height: 2.25rem; + font-size: 1rem; + } + + .form-row select { + height: 2.25rem; + } + + .form-row select[multiple] { + height: auto; + min-height: 0; + } + + fieldset .fieldBox + .fieldBox { + margin-top: 10px; + padding-top: 10px; + border-top: 1px solid var(--hairline-color); + } + + textarea { + max-width: 100%; + max-height: 120px; + } + + .aligned label { + padding-top: 6px; + } + + .aligned .related-lookup, + .aligned .datetimeshortcuts, + .aligned .related-lookup + strong { + align-self: center; + margin-left: 15px; + } + + form .aligned div.radiolist { + margin-left: 2px; + } + + .submit-row { + padding: 8px; + } + + .submit-row a.deletelink { + padding: 10px 7px; + } + + .button, input[type=submit], input[type=button], .submit-row input, a.button { + padding: 7px; + } + + /* Selector */ + + .selector { + display: flex; + width: 100%; + } + + .selector .selector-filter { + display: flex; + align-items: center; + } + + .selector .selector-filter label { + margin: 0 8px 0 0; + } + + .selector .selector-filter input { + width: 100%; + min-height: 0; + flex: 1 1; + } + + .selector-available, .selector-chosen { + width: auto; + flex: 1 1; + display: flex; + flex-direction: column; + } + + .selector select { + width: 100%; + flex: 1 0 auto; + margin-bottom: 5px; + } + + .selector ul.selector-chooser { + width: 26px; + height: 52px; + padding: 2px 0; + border-radius: 20px; + transform: translateY(-10px); + } + + .selector-add, .selector-remove { + width: 20px; + height: 20px; + background-size: 20px auto; + } + + .selector-add { + background-position: 0 -120px; + } + + .selector-remove { + background-position: 0 -80px; + } + + a.selector-chooseall, a.selector-clearall { + align-self: center; + } + + .stacked { + flex-direction: column; + max-width: 480px; + } + + .stacked > * { + flex: 0 1 auto; + } + + .stacked select { + margin-bottom: 0; + } + + .stacked .selector-available, .stacked .selector-chosen { + width: auto; + } + + .stacked ul.selector-chooser { + width: 52px; + height: 26px; + padding: 0 2px; + transform: none; + } + + .stacked .selector-chooser li { + padding: 3px; + } + + .stacked .selector-add, .stacked .selector-remove { + background-size: 20px auto; + } + + .stacked .selector-add { + background-position: 0 -40px; + } + + .stacked .active.selector-add { + background-position: 0 -40px; + } + + .active.selector-add:focus, .active.selector-add:hover { + background-position: 0 -140px; + } + + .stacked .active.selector-add:focus, .stacked .active.selector-add:hover { + background-position: 0 -60px; + } + + .stacked .selector-remove { + background-position: 0 0; + } + + .stacked .active.selector-remove { + background-position: 0 0; + } + + .active.selector-remove:focus, .active.selector-remove:hover { + background-position: 0 -100px; + } + + .stacked .active.selector-remove:focus, .stacked .active.selector-remove:hover { + background-position: 0 -20px; + } + + .help-tooltip, .selector .help-icon { + display: none; + } + + .datetime input { + width: 50%; + max-width: 120px; + } + + .datetime span { + font-size: 0.8125rem; + } + + .datetime .timezonewarning { + display: block; + font-size: 0.6875rem; + color: var(--body-quiet-color); + } + + .datetimeshortcuts { + color: var(--border-color); /* XXX Redundant, .datetime span also sets #ccc */ + } + + .form-row .datetime input.vDateField, .form-row .datetime input.vTimeField { + width: 75%; + } + + .inline-group { + overflow: auto; + } + + /* Messages */ + + ul.messagelist li { + padding-left: 55px; + background-position: 30px 12px; + } + + ul.messagelist li.error { + background-position: 30px 12px; + } + + ul.messagelist li.warning { + background-position: 30px 14px; + } + + /* Login */ + + .login #header { + padding: 15px 20px; + } + + .login #site-name { + margin: 0; + } + + /* GIS */ + + div.olMap { + max-width: calc(100vw - 30px); + max-height: 300px; + } + + .olMap + .clear_features { + display: block; + margin-top: 10px; + } + + /* Docs */ + + .module table.xfull { + width: 100%; + } + + pre.literal-block { + overflow: auto; + } +} + +/* Mobile */ + +@media (max-width: 767px) { + /* Layout */ + + #header, #content { + padding: 15px; + } + + div.breadcrumbs { + padding: 10px 15px; + } + + /* Dashboard */ + + .colMS, .colSM { + margin: 0; + } + + #content-related, .colSM #content-related { + width: 100%; + margin: 0; + } + + #content-related .module { + margin-bottom: 0; + } + + #content-related .module h2 { + padding: 10px 15px; + font-size: 1rem; + } + + /* Changelist */ + + #changelist { + align-items: stretch; + flex-direction: column; + } + + #toolbar { + padding: 10px; + } + + #changelist-filter { + margin-left: 0; + } + + #changelist .actions label { + flex: 1 1; + } + + #changelist .actions select { + flex: 1 0; + width: 100%; + } + + #changelist .actions span { + flex: 1 0 100%; + } + + #changelist-filter { + position: static; + width: auto; + margin-top: 30px; + } + + .object-tools { + float: none; + margin: 0 0 15px; + padding: 0; + overflow: hidden; + } + + .object-tools li { + height: auto; + margin-left: 0; + } + + .object-tools li + li { + margin-left: 15px; + } + + /* Forms */ + + .form-row { + padding: 15px 0; + } + + .aligned .form-row, + .aligned .form-row > div { + max-width: 100vw; + } + + .aligned .form-row > div { + width: calc(100vw - 30px); + } + + .flex-container { + flex-flow: column; + } + + .flex-container.checkbox-row { + flex-flow: row; + } + + textarea { + max-width: none; + } + + .vURLField { + width: auto; + } + + fieldset .fieldBox + .fieldBox { + margin-top: 15px; + padding-top: 15px; + } + + .aligned label { + width: 100%; + min-width: auto; + padding: 0 0 10px; + } + + .aligned label:after { + max-height: 0; + } + + .aligned .form-row input, + .aligned .form-row select, + .aligned .form-row textarea { + flex: 1 1 auto; + max-width: 100%; + } + + .aligned .checkbox-row input { + flex: 0 1 auto; + margin: 0; + } + + .aligned .vCheckboxLabel { + flex: 1 0; + padding: 1px 0 0 5px; + } + + .aligned label + p, + .aligned label + div.help, + .aligned label + div.readonly { + padding: 0; + margin-left: 0; + } + + .aligned p.file-upload { + font-size: 0.8125rem; + } + + span.clearable-file-input { + margin-left: 15px; + } + + span.clearable-file-input label { + font-size: 0.8125rem; + padding-bottom: 0; + } + + .aligned .timezonewarning { + flex: 1 0 100%; + margin-top: 5px; + } + + form .aligned .form-row div.help { + width: 100%; + margin: 5px 0 0; + padding: 0; + } + + form .aligned ul, + form .aligned ul.errorlist { + margin-left: 0; + padding-left: 0; + } + + form .aligned div.radiolist { + margin-top: 5px; + margin-right: 15px; + margin-bottom: -3px; + } + + form .aligned div.radiolist:not(.inline) div + div { + margin-top: 5px; + } + + /* Related widget */ + + .related-widget-wrapper { + width: 100%; + display: flex; + align-items: flex-start; + } + + .related-widget-wrapper .selector { + order: 1; + } + + .related-widget-wrapper > a { + order: 2; + } + + .related-widget-wrapper .radiolist ~ a { + align-self: flex-end; + } + + .related-widget-wrapper > select ~ a { + align-self: center; + } + + /* Selector */ + + .selector { + flex-direction: column; + gap: 10px 0; + } + + .selector-available, .selector-chosen { + flex: 1 1 auto; + } + + .selector select { + max-height: 96px; + } + + .selector ul.selector-chooser { + display: block; + width: 52px; + height: 26px; + padding: 0 2px; + transform: none; + } + + .selector ul.selector-chooser li { + float: left; + } + + .selector-remove { + background-position: 0 0; + } + + .active.selector-remove:focus, .active.selector-remove:hover { + background-position: 0 -20px; + } + + .selector-add { + background-position: 0 -40px; + } + + .active.selector-add:focus, .active.selector-add:hover { + background-position: 0 -60px; + } + + /* Inlines */ + + .inline-group[data-inline-type="stacked"] .inline-related { + border: 1px solid var(--hairline-color); + border-radius: 4px; + margin-top: 15px; + overflow: auto; + } + + .inline-group[data-inline-type="stacked"] .inline-related > * { + box-sizing: border-box; + } + + .inline-group[data-inline-type="stacked"] .inline-related .module { + padding: 0 10px; + } + + .inline-group[data-inline-type="stacked"] .inline-related .module .form-row { + border-top: 1px solid var(--hairline-color); + border-bottom: none; + } + + .inline-group[data-inline-type="stacked"] .inline-related .module .form-row:first-child { + border-top: none; + } + + .inline-group[data-inline-type="stacked"] .inline-related h3 { + padding: 10px; + border-top-width: 0; + border-bottom-width: 2px; + display: flex; + flex-wrap: wrap; + align-items: center; + } + + .inline-group[data-inline-type="stacked"] .inline-related h3 .inline_label { + margin-right: auto; + } + + .inline-group[data-inline-type="stacked"] .inline-related h3 span.delete { + float: none; + flex: 1 1 100%; + margin-top: 5px; + } + + .inline-group[data-inline-type="stacked"] .aligned .form-row > div:not([class]) { + width: 100%; + } + + .inline-group[data-inline-type="stacked"] .aligned label { + width: 100%; + } + + .inline-group[data-inline-type="stacked"] div.add-row { + margin-top: 15px; + border: 1px solid var(--hairline-color); + border-radius: 4px; + } + + .inline-group div.add-row, + .inline-group .tabular tr.add-row td { + padding: 0; + } + + .inline-group div.add-row a, + .inline-group .tabular tr.add-row td a { + display: block; + padding: 8px 10px 8px 26px; + background-position: 8px 9px; + } + + /* Submit row */ + + .submit-row { + padding: 10px; + margin: 0 0 15px; + flex-direction: column; + gap: 8px; + } + + .submit-row input, .submit-row input.default, .submit-row a { + text-align: center; + } + + .submit-row a.closelink { + padding: 10px 0; + text-align: center; + } + + .submit-row a.deletelink { + margin: 0; + } + + /* Messages */ + + ul.messagelist li { + padding-left: 40px; + background-position: 15px 12px; + } + + ul.messagelist li.error { + background-position: 15px 12px; + } + + ul.messagelist li.warning { + background-position: 15px 14px; + } + + /* Paginator */ + + .paginator .this-page, .paginator a:link, .paginator a:visited { + padding: 4px 10px; + } + + /* Login */ + + body.login { + padding: 0 15px; + } + + .login #container { + width: auto; + max-width: 480px; + margin: 50px auto; + } + + .login #header, + .login #content { + padding: 15px; + } + + .login #content-main { + float: none; + } + + .login .form-row { + padding: 0; + } + + .login .form-row + .form-row { + margin-top: 15px; + } + + .login .form-row label { + margin: 0 0 5px; + line-height: 1.2; + } + + .login .submit-row { + padding: 15px 0 0; + } + + .login br { + display: none; + } + + .login .submit-row input { + margin: 0; + text-transform: uppercase; + } + + .errornote { + margin: 0 0 20px; + padding: 8px 12px; + font-size: 0.8125rem; + } + + /* Calendar and clock */ + + .calendarbox, .clockbox { + position: fixed !important; + top: 50% !important; + left: 50% !important; + transform: translate(-50%, -50%); + margin: 0; + border: none; + overflow: visible; + } + + .calendarbox:before, .clockbox:before { + content: ''; + position: fixed; + top: 50%; + left: 50%; + width: 100vw; + height: 100vh; + background: rgba(0, 0, 0, 0.75); + transform: translate(-50%, -50%); + } + + .calendarbox > *, .clockbox > * { + position: relative; + z-index: 1; + } + + .calendarbox > div:first-child { + z-index: 2; + } + + .calendarbox .calendar, .clockbox h2 { + border-radius: 4px 4px 0 0; + overflow: hidden; + } + + .calendarbox .calendar-cancel, .clockbox .calendar-cancel { + border-radius: 0 0 4px 4px; + overflow: hidden; + } + + .calendar-shortcuts { + padding: 10px 0; + font-size: 0.75rem; + line-height: 0.75rem; + } + + .calendar-shortcuts a { + margin: 0 4px; + } + + .timelist a { + background: var(--body-bg); + padding: 4px; + } + + .calendar-cancel { + padding: 8px 10px; + } + + .clockbox h2 { + padding: 8px 15px; + } + + .calendar caption { + padding: 10px; + } + + .calendarbox .calendarnav-previous, .calendarbox .calendarnav-next { + z-index: 1; + top: 10px; + } + + /* History */ + + table#change-history tbody th, table#change-history tbody td { + font-size: 0.8125rem; + word-break: break-word; + } + + table#change-history tbody th { + width: auto; + } + + /* Docs */ + + table.model tbody th, table.model tbody td { + font-size: 0.8125rem; + word-break: break-word; + } +} diff --git a/lottery/staticfiles/admin/css/responsive_rtl.css b/lottery/staticfiles/admin/css/responsive_rtl.css new file mode 100644 index 0000000..33b5784 --- /dev/null +++ b/lottery/staticfiles/admin/css/responsive_rtl.css @@ -0,0 +1,111 @@ +/* TABLETS */ + +@media (max-width: 1024px) { + [dir="rtl"] .colMS { + margin-right: 0; + } + + [dir="rtl"] #user-tools { + text-align: right; + } + + [dir="rtl"] #changelist .actions label { + padding-left: 10px; + padding-right: 0; + } + + [dir="rtl"] #changelist .actions select { + margin-left: 0; + margin-right: 15px; + } + + [dir="rtl"] .change-list .filtered .results, + [dir="rtl"] .change-list .filtered .paginator, + [dir="rtl"] .filtered #toolbar, + [dir="rtl"] .filtered div.xfull, + [dir="rtl"] .filtered .actions, + [dir="rtl"] #changelist-filter { + margin-left: 0; + } + + [dir="rtl"] .inline-group ul.tools a.add, + [dir="rtl"] .inline-group div.add-row a, + [dir="rtl"] .inline-group .tabular tr.add-row td a { + padding: 8px 26px 8px 10px; + background-position: calc(100% - 8px) 9px; + } + + [dir="rtl"] .selector .selector-filter label { + margin-right: 0; + margin-left: 8px; + } + + [dir="rtl"] .object-tools li { + float: right; + } + + [dir="rtl"] .object-tools li + li { + margin-left: 0; + margin-right: 15px; + } + + [dir="rtl"] .dashboard .module table td a { + padding-left: 0; + padding-right: 16px; + } + + [dir="rtl"] .selector-add { + background-position: 0 -80px; + } + + [dir="rtl"] .selector-remove { + background-position: 0 -120px; + } + + [dir="rtl"] .active.selector-add:focus, .active.selector-add:hover { + background-position: 0 -100px; + } + + [dir="rtl"] .active.selector-remove:focus, .active.selector-remove:hover { + background-position: 0 -140px; + } +} + +/* MOBILE */ + +@media (max-width: 767px) { + [dir="rtl"] .aligned .related-lookup, + [dir="rtl"] .aligned .datetimeshortcuts { + margin-left: 0; + margin-right: 15px; + } + + [dir="rtl"] .aligned ul, + [dir="rtl"] form .aligned ul.errorlist { + margin-right: 0; + } + + [dir="rtl"] #changelist-filter { + margin-left: 0; + margin-right: 0; + } + [dir="rtl"] .aligned .vCheckboxLabel { + padding: 1px 5px 0 0; + } + + [dir="rtl"] .selector-remove { + background-position: 0 0; + } + + [dir="rtl"] .active.selector-remove:focus, .active.selector-remove:hover { + background-position: 0 -20px; + } + + [dir="rtl"] .selector-add { + background-position: 0 -40px; + } + + [dir="rtl"] .active.selector-add:focus, .active.selector-add:hover { + background-position: 0 -60px; + } +} diff --git a/lottery/staticfiles/admin/css/rtl.css b/lottery/staticfiles/admin/css/rtl.css new file mode 100644 index 0000000..b8f60e0 --- /dev/null +++ b/lottery/staticfiles/admin/css/rtl.css @@ -0,0 +1,291 @@ +/* GLOBAL */ + +th { + text-align: right; +} + +.module h2, .module caption { + text-align: right; +} + +.module ul, .module ol { + margin-left: 0; + margin-right: 1.5em; +} + +.viewlink, .addlink, .changelink, .hidelink { + padding-left: 0; + padding-right: 16px; + background-position: 100% 1px; +} + +.deletelink { + padding-left: 0; + padding-right: 16px; + background-position: 100% 1px; +} + +.object-tools { + float: left; +} + +thead th:first-child, +tfoot td:first-child { + border-left: none; +} + +/* LAYOUT */ + +#user-tools { + right: auto; + left: 0; + text-align: left; +} + +div.breadcrumbs { + text-align: right; +} + +#content-main { + float: right; +} + +#content-related { + float: left; + margin-left: -300px; + margin-right: auto; +} + +.colMS { + margin-left: 300px; + margin-right: 0; +} + +/* SORTABLE TABLES */ + +table thead th.sorted .sortoptions { + float: left; +} + +thead th.sorted .text { + padding-right: 0; + padding-left: 42px; +} + +/* dashboard styles */ + +.dashboard .module table td a { + padding-left: .6em; + padding-right: 16px; +} + +/* changelists styles */ + +.change-list .filtered table { + border-left: none; + border-right: 0px none; +} + +#changelist-filter { + border-left: none; + border-right: none; + margin-left: 0; + margin-right: 30px; +} + +#changelist-filter li.selected { + border-left: none; + padding-left: 10px; + margin-left: 0; + border-right: 5px solid var(--hairline-color); + padding-right: 10px; + margin-right: -15px; +} + +#changelist table tbody td:first-child, #changelist table tbody th:first-child { + border-right: none; + border-left: none; +} + +.paginator .end { + margin-left: 6px; + margin-right: 0; +} + +.paginator input { + margin-left: 0; + margin-right: auto; +} + +/* FORMS */ + +.aligned label { + padding: 0 0 3px 1em; +} + +.submit-row a.deletelink { + margin-left: 0; + margin-right: auto; +} + +.vDateField, .vTimeField { + margin-left: 2px; +} + +.aligned .form-row input { + margin-left: 5px; +} + +form .aligned ul { + margin-right: 163px; + padding-right: 10px; + margin-left: 0; + padding-left: 0; +} + +form ul.inline li { + float: right; + padding-right: 0; + padding-left: 7px; +} + +form .aligned p.help, +form .aligned div.help { + margin-left: 0; + margin-right: 160px; + padding-right: 10px; +} + +form div.help ul, +form .aligned .checkbox-row + .help, +form .aligned p.date div.help.timezonewarning, +form .aligned p.datetime div.help.timezonewarning, +form .aligned p.time div.help.timezonewarning { + margin-right: 0; + padding-right: 0; +} + +form .wide p.help, +form .wide ul.errorlist, +form .wide div.help { + padding-left: 0; + padding-right: 50px; +} + +.submit-row { + text-align: right; +} + +fieldset .fieldBox { + margin-left: 20px; + margin-right: 0; +} + +.errorlist li { + background-position: 100% 12px; + padding: 0; +} + +.errornote { + background-position: 100% 12px; + padding: 10px 12px; +} + +/* WIDGETS */ + +.calendarnav-previous { + top: 0; + left: auto; + right: 10px; + background: url(../img/calendar-icons.svg) 0 -15px no-repeat; +} + +.calendarnav-next { + top: 0; + right: auto; + left: 10px; + background: url(../img/calendar-icons.svg) 0 0 no-repeat; +} + +.calendar caption, .calendarbox h2 { + text-align: center; +} + +.selector { + float: right; +} + +.selector .selector-filter { + text-align: right; +} + +.selector-add { + background: url(../img/selector-icons.svg) 0 -64px no-repeat; +} + +.active.selector-add:focus, .active.selector-add:hover { + background-position: 0 -80px; +} + +.selector-remove { + background: url(../img/selector-icons.svg) 0 -96px no-repeat; +} + +.active.selector-remove:focus, .active.selector-remove:hover { + background-position: 0 -112px; +} + +a.selector-chooseall { + background: url(../img/selector-icons.svg) right -128px no-repeat; +} + +a.active.selector-chooseall:focus, a.active.selector-chooseall:hover { + background-position: 100% -144px; +} + +a.selector-clearall { + background: url(../img/selector-icons.svg) 0 -160px no-repeat; +} + +a.active.selector-clearall:focus, a.active.selector-clearall:hover { + background-position: 0 -176px; +} + +.inline-deletelink { + float: left; +} + +form .form-row p.datetime { + overflow: hidden; +} + +.related-widget-wrapper { + float: right; +} + +/* MISC */ + +.inline-related h2, .inline-group h2 { + text-align: right +} + +.inline-related h3 span.delete { + padding-right: 20px; + padding-left: inherit; + left: 10px; + right: inherit; + float:left; +} + +.inline-related h3 span.delete label { + margin-left: inherit; + margin-right: 2px; +} + +.inline-group .tabular td.original p { + right: 0; +} + +.selector .selector-chooser { + margin: 0; +} diff --git a/lottery/staticfiles/admin/css/unusable_password_field.css b/lottery/staticfiles/admin/css/unusable_password_field.css new file mode 100644 index 0000000..d46eb03 --- /dev/null +++ b/lottery/staticfiles/admin/css/unusable_password_field.css @@ -0,0 +1,19 @@ +/* Hide warnings fields if usable password is selected */ +form:has(#id_usable_password input[value="true"]:checked) .messagelist { + display: none; +} + +/* Hide password fields if unusable password is selected */ +form:has(#id_usable_password input[value="false"]:checked) .field-password1, +form:has(#id_usable_password input[value="false"]:checked) .field-password2 { + display: none; +} + +/* Select appropriate submit button */ +form:has(#id_usable_password input[value="true"]:checked) input[type="submit"].unset-password { + display: none; +} + +form:has(#id_usable_password input[value="false"]:checked) input[type="submit"].set-password { + display: none; +} diff --git a/lottery/staticfiles/admin/css/vendor/select2/LICENSE-SELECT2.md b/lottery/staticfiles/admin/css/vendor/select2/LICENSE-SELECT2.md new file mode 100644 index 0000000..8cb8a2b --- /dev/null +++ b/lottery/staticfiles/admin/css/vendor/select2/LICENSE-SELECT2.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2012-2017 Kevin Brown, Igor Vaynberg, and Select2 contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/lottery/staticfiles/admin/css/vendor/select2/select2.css b/lottery/staticfiles/admin/css/vendor/select2/select2.css new file mode 100644 index 0000000..750b320 --- /dev/null +++ b/lottery/staticfiles/admin/css/vendor/select2/select2.css @@ -0,0 +1,481 @@ +.select2-container { + box-sizing: border-box; + display: inline-block; + margin: 0; + position: relative; + vertical-align: middle; } + .select2-container .select2-selection--single { + box-sizing: border-box; + cursor: pointer; + display: block; + height: 28px; + user-select: none; + -webkit-user-select: none; } + .select2-container .select2-selection--single .select2-selection__rendered { + display: block; + padding-left: 8px; + padding-right: 20px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } + .select2-container .select2-selection--single .select2-selection__clear { + position: relative; } + .select2-container[dir="rtl"] .select2-selection--single .select2-selection__rendered { + padding-right: 8px; + padding-left: 20px; } + .select2-container .select2-selection--multiple { + box-sizing: border-box; + cursor: pointer; + display: block; + min-height: 32px; + user-select: none; + -webkit-user-select: none; } + .select2-container .select2-selection--multiple .select2-selection__rendered { + display: inline-block; + overflow: hidden; + padding-left: 8px; + text-overflow: ellipsis; + white-space: nowrap; } + .select2-container .select2-search--inline { + float: left; } + .select2-container .select2-search--inline .select2-search__field { + box-sizing: border-box; + border: none; + font-size: 100%; + margin-top: 5px; + padding: 0; } + .select2-container .select2-search--inline .select2-search__field::-webkit-search-cancel-button { + -webkit-appearance: none; } + +.select2-dropdown { + background-color: white; + border: 1px solid #aaa; + border-radius: 4px; + box-sizing: border-box; + display: block; + position: absolute; + left: -100000px; + width: 100%; + z-index: 1051; } + +.select2-results { + display: block; } + +.select2-results__options { + list-style: none; + margin: 0; + padding: 0; } + +.select2-results__option { + padding: 6px; + user-select: none; + -webkit-user-select: none; } + .select2-results__option[aria-selected] { + cursor: pointer; } + +.select2-container--open .select2-dropdown { + left: 0; } + +.select2-container--open .select2-dropdown--above { + border-bottom: none; + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; } + +.select2-container--open .select2-dropdown--below { + border-top: none; + border-top-left-radius: 0; + border-top-right-radius: 0; } + +.select2-search--dropdown { + display: block; + padding: 4px; } + .select2-search--dropdown .select2-search__field { + padding: 4px; + width: 100%; + box-sizing: border-box; } + .select2-search--dropdown .select2-search__field::-webkit-search-cancel-button { + -webkit-appearance: none; } + .select2-search--dropdown.select2-search--hide { + display: none; } + +.select2-close-mask { + border: 0; + margin: 0; + padding: 0; + display: block; + position: fixed; + left: 0; + top: 0; + min-height: 100%; + min-width: 100%; + height: auto; + width: auto; + opacity: 0; + z-index: 99; + background-color: #fff; + filter: alpha(opacity=0); } + +.select2-hidden-accessible { + border: 0 !important; + clip: rect(0 0 0 0) !important; + -webkit-clip-path: inset(50%) !important; + clip-path: inset(50%) !important; + height: 1px !important; + overflow: hidden !important; + padding: 0 !important; + position: absolute !important; + width: 1px !important; + white-space: nowrap !important; } + +.select2-container--default .select2-selection--single { + background-color: #fff; + border: 1px solid #aaa; + border-radius: 4px; } + .select2-container--default .select2-selection--single .select2-selection__rendered { + color: #444; + line-height: 28px; } + .select2-container--default .select2-selection--single .select2-selection__clear { + cursor: pointer; + float: right; + font-weight: bold; } + .select2-container--default .select2-selection--single .select2-selection__placeholder { + color: #999; } + .select2-container--default .select2-selection--single .select2-selection__arrow { + height: 26px; + position: absolute; + top: 1px; + right: 1px; + width: 20px; } + .select2-container--default .select2-selection--single .select2-selection__arrow b { + border-color: #888 transparent transparent transparent; + border-style: solid; + border-width: 5px 4px 0 4px; + height: 0; + left: 50%; + margin-left: -4px; + margin-top: -2px; + position: absolute; + top: 50%; + width: 0; } + +.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__clear { + float: left; } + +.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__arrow { + left: 1px; + right: auto; } + +.select2-container--default.select2-container--disabled .select2-selection--single { + background-color: #eee; + cursor: default; } + .select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__clear { + display: none; } + +.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b { + border-color: transparent transparent #888 transparent; + border-width: 0 4px 5px 4px; } + +.select2-container--default .select2-selection--multiple { + background-color: white; + border: 1px solid #aaa; + border-radius: 4px; + cursor: text; } + .select2-container--default .select2-selection--multiple .select2-selection__rendered { + box-sizing: border-box; + list-style: none; + margin: 0; + padding: 0 5px; + width: 100%; } + .select2-container--default .select2-selection--multiple .select2-selection__rendered li { + list-style: none; } + .select2-container--default .select2-selection--multiple .select2-selection__clear { + cursor: pointer; + float: right; + font-weight: bold; + margin-top: 5px; + margin-right: 10px; + padding: 1px; } + .select2-container--default .select2-selection--multiple .select2-selection__choice { + background-color: #e4e4e4; + border: 1px solid #aaa; + border-radius: 4px; + cursor: default; + float: left; + margin-right: 5px; + margin-top: 5px; + padding: 0 5px; } + .select2-container--default .select2-selection--multiple .select2-selection__choice__remove { + color: #999; + cursor: pointer; + display: inline-block; + font-weight: bold; + margin-right: 2px; } + .select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover { + color: #333; } + +.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice, .select2-container--default[dir="rtl"] .select2-selection--multiple .select2-search--inline { + float: right; } + +.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice { + margin-left: 5px; + margin-right: auto; } + +.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove { + margin-left: 2px; + margin-right: auto; } + +.select2-container--default.select2-container--focus .select2-selection--multiple { + border: solid black 1px; + outline: 0; } + +.select2-container--default.select2-container--disabled .select2-selection--multiple { + background-color: #eee; + cursor: default; } + +.select2-container--default.select2-container--disabled .select2-selection__choice__remove { + display: none; } + +.select2-container--default.select2-container--open.select2-container--above .select2-selection--single, .select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple { + border-top-left-radius: 0; + border-top-right-radius: 0; } + +.select2-container--default.select2-container--open.select2-container--below .select2-selection--single, .select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; } + +.select2-container--default .select2-search--dropdown .select2-search__field { + border: 1px solid #aaa; } + +.select2-container--default .select2-search--inline .select2-search__field { + background: transparent; + border: none; + outline: 0; + box-shadow: none; + -webkit-appearance: textfield; } + +.select2-container--default .select2-results > .select2-results__options { + max-height: 200px; + overflow-y: auto; } + +.select2-container--default .select2-results__option[role=group] { + padding: 0; } + +.select2-container--default .select2-results__option[aria-disabled=true] { + color: #999; } + +.select2-container--default .select2-results__option[aria-selected=true] { + background-color: #ddd; } + +.select2-container--default .select2-results__option .select2-results__option { + padding-left: 1em; } + .select2-container--default .select2-results__option .select2-results__option .select2-results__group { + padding-left: 0; } + .select2-container--default .select2-results__option .select2-results__option .select2-results__option { + margin-left: -1em; + padding-left: 2em; } + .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option { + margin-left: -2em; + padding-left: 3em; } + .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option { + margin-left: -3em; + padding-left: 4em; } + .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option { + margin-left: -4em; + padding-left: 5em; } + .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option { + margin-left: -5em; + padding-left: 6em; } + +.select2-container--default .select2-results__option--highlighted[aria-selected] { + background-color: #5897fb; + color: white; } + +.select2-container--default .select2-results__group { + cursor: default; + display: block; + padding: 6px; } + +.select2-container--classic .select2-selection--single { + background-color: #f7f7f7; + border: 1px solid #aaa; + border-radius: 4px; + outline: 0; + background-image: -webkit-linear-gradient(top, white 50%, #eeeeee 100%); + background-image: -o-linear-gradient(top, white 50%, #eeeeee 100%); + background-image: linear-gradient(to bottom, white 50%, #eeeeee 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0); } + .select2-container--classic .select2-selection--single:focus { + border: 1px solid #5897fb; } + .select2-container--classic .select2-selection--single .select2-selection__rendered { + color: #444; + line-height: 28px; } + .select2-container--classic .select2-selection--single .select2-selection__clear { + cursor: pointer; + float: right; + font-weight: bold; + margin-right: 10px; } + .select2-container--classic .select2-selection--single .select2-selection__placeholder { + color: #999; } + .select2-container--classic .select2-selection--single .select2-selection__arrow { + background-color: #ddd; + border: none; + border-left: 1px solid #aaa; + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; + height: 26px; + position: absolute; + top: 1px; + right: 1px; + width: 20px; + background-image: -webkit-linear-gradient(top, #eeeeee 50%, #cccccc 100%); + background-image: -o-linear-gradient(top, #eeeeee 50%, #cccccc 100%); + background-image: linear-gradient(to bottom, #eeeeee 50%, #cccccc 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFCCCCCC', GradientType=0); } + .select2-container--classic .select2-selection--single .select2-selection__arrow b { + border-color: #888 transparent transparent transparent; + border-style: solid; + border-width: 5px 4px 0 4px; + height: 0; + left: 50%; + margin-left: -4px; + margin-top: -2px; + position: absolute; + top: 50%; + width: 0; } + +.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__clear { + float: left; } + +.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__arrow { + border: none; + border-right: 1px solid #aaa; + border-radius: 0; + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; + left: 1px; + right: auto; } + +.select2-container--classic.select2-container--open .select2-selection--single { + border: 1px solid #5897fb; } + .select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow { + background: transparent; + border: none; } + .select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b { + border-color: transparent transparent #888 transparent; + border-width: 0 4px 5px 4px; } + +.select2-container--classic.select2-container--open.select2-container--above .select2-selection--single { + border-top: none; + border-top-left-radius: 0; + border-top-right-radius: 0; + background-image: -webkit-linear-gradient(top, white 0%, #eeeeee 50%); + background-image: -o-linear-gradient(top, white 0%, #eeeeee 50%); + background-image: linear-gradient(to bottom, white 0%, #eeeeee 50%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0); } + +.select2-container--classic.select2-container--open.select2-container--below .select2-selection--single { + border-bottom: none; + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + background-image: -webkit-linear-gradient(top, #eeeeee 50%, white 100%); + background-image: -o-linear-gradient(top, #eeeeee 50%, white 100%); + background-image: linear-gradient(to bottom, #eeeeee 50%, white 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFFFFFFF', GradientType=0); } + +.select2-container--classic .select2-selection--multiple { + background-color: white; + border: 1px solid #aaa; + border-radius: 4px; + cursor: text; + outline: 0; } + .select2-container--classic .select2-selection--multiple:focus { + border: 1px solid #5897fb; } + .select2-container--classic .select2-selection--multiple .select2-selection__rendered { + list-style: none; + margin: 0; + padding: 0 5px; } + .select2-container--classic .select2-selection--multiple .select2-selection__clear { + display: none; } + .select2-container--classic .select2-selection--multiple .select2-selection__choice { + background-color: #e4e4e4; + border: 1px solid #aaa; + border-radius: 4px; + cursor: default; + float: left; + margin-right: 5px; + margin-top: 5px; + padding: 0 5px; } + .select2-container--classic .select2-selection--multiple .select2-selection__choice__remove { + color: #888; + cursor: pointer; + display: inline-block; + font-weight: bold; + margin-right: 2px; } + .select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover { + color: #555; } + +.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice { + float: right; + margin-left: 5px; + margin-right: auto; } + +.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove { + margin-left: 2px; + margin-right: auto; } + +.select2-container--classic.select2-container--open .select2-selection--multiple { + border: 1px solid #5897fb; } + +.select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple { + border-top: none; + border-top-left-radius: 0; + border-top-right-radius: 0; } + +.select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple { + border-bottom: none; + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; } + +.select2-container--classic .select2-search--dropdown .select2-search__field { + border: 1px solid #aaa; + outline: 0; } + +.select2-container--classic .select2-search--inline .select2-search__field { + outline: 0; + box-shadow: none; } + +.select2-container--classic .select2-dropdown { + background-color: white; + border: 1px solid transparent; } + +.select2-container--classic .select2-dropdown--above { + border-bottom: none; } + +.select2-container--classic .select2-dropdown--below { + border-top: none; } + +.select2-container--classic .select2-results > .select2-results__options { + max-height: 200px; + overflow-y: auto; } + +.select2-container--classic .select2-results__option[role=group] { + padding: 0; } + +.select2-container--classic .select2-results__option[aria-disabled=true] { + color: grey; } + +.select2-container--classic .select2-results__option--highlighted[aria-selected] { + background-color: #3875d7; + color: white; } + +.select2-container--classic .select2-results__group { + cursor: default; + display: block; + padding: 6px; } + +.select2-container--classic.select2-container--open .select2-dropdown { + border-color: #5897fb; } diff --git a/lottery/staticfiles/admin/css/vendor/select2/select2.min.css b/lottery/staticfiles/admin/css/vendor/select2/select2.min.css new file mode 100644 index 0000000..7c18ad5 --- /dev/null +++ b/lottery/staticfiles/admin/css/vendor/select2/select2.min.css @@ -0,0 +1 @@ +.select2-container{box-sizing:border-box;display:inline-block;margin:0;position:relative;vertical-align:middle}.select2-container .select2-selection--single{box-sizing:border-box;cursor:pointer;display:block;height:28px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--single .select2-selection__rendered{display:block;padding-left:8px;padding-right:20px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.select2-container .select2-selection--single .select2-selection__clear{position:relative}.select2-container[dir="rtl"] .select2-selection--single .select2-selection__rendered{padding-right:8px;padding-left:20px}.select2-container .select2-selection--multiple{box-sizing:border-box;cursor:pointer;display:block;min-height:32px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--multiple .select2-selection__rendered{display:inline-block;overflow:hidden;padding-left:8px;text-overflow:ellipsis;white-space:nowrap}.select2-container .select2-search--inline{float:left}.select2-container .select2-search--inline .select2-search__field{box-sizing:border-box;border:none;font-size:100%;margin-top:5px;padding:0}.select2-container .select2-search--inline .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-dropdown{background-color:white;border:1px solid #aaa;border-radius:4px;box-sizing:border-box;display:block;position:absolute;left:-100000px;width:100%;z-index:1051}.select2-results{display:block}.select2-results__options{list-style:none;margin:0;padding:0}.select2-results__option{padding:6px;user-select:none;-webkit-user-select:none}.select2-results__option[aria-selected]{cursor:pointer}.select2-container--open .select2-dropdown{left:0}.select2-container--open .select2-dropdown--above{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--open .select2-dropdown--below{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-search--dropdown{display:block;padding:4px}.select2-search--dropdown .select2-search__field{padding:4px;width:100%;box-sizing:border-box}.select2-search--dropdown .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-search--dropdown.select2-search--hide{display:none}.select2-close-mask{border:0;margin:0;padding:0;display:block;position:fixed;left:0;top:0;min-height:100%;min-width:100%;height:auto;width:auto;opacity:0;z-index:99;background-color:#fff;filter:alpha(opacity=0)}.select2-hidden-accessible{border:0 !important;clip:rect(0 0 0 0) !important;-webkit-clip-path:inset(50%) !important;clip-path:inset(50%) !important;height:1px !important;overflow:hidden !important;padding:0 !important;position:absolute !important;width:1px !important;white-space:nowrap !important}.select2-container--default .select2-selection--single{background-color:#fff;border:1px solid #aaa;border-radius:4px}.select2-container--default .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px}.select2-container--default .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold}.select2-container--default .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--default .select2-selection--single .select2-selection__arrow{height:26px;position:absolute;top:1px;right:1px;width:20px}.select2-container--default .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__arrow{left:1px;right:auto}.select2-container--default.select2-container--disabled .select2-selection--single{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__clear{display:none}.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px}.select2-container--default .select2-selection--multiple{background-color:white;border:1px solid #aaa;border-radius:4px;cursor:text}.select2-container--default .select2-selection--multiple .select2-selection__rendered{box-sizing:border-box;list-style:none;margin:0;padding:0 5px;width:100%}.select2-container--default .select2-selection--multiple .select2-selection__rendered li{list-style:none}.select2-container--default .select2-selection--multiple .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;margin-top:5px;margin-right:10px;padding:1px}.select2-container--default .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;cursor:default;float:left;margin-right:5px;margin-top:5px;padding:0 5px}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove{color:#999;cursor:pointer;display:inline-block;font-weight:bold;margin-right:2px}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover{color:#333}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice,.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-search--inline{float:right}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice{margin-left:5px;margin-right:auto}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove{margin-left:2px;margin-right:auto}.select2-container--default.select2-container--focus .select2-selection--multiple{border:solid black 1px;outline:0}.select2-container--default.select2-container--disabled .select2-selection--multiple{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection__choice__remove{display:none}.select2-container--default.select2-container--open.select2-container--above .select2-selection--single,.select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple{border-top-left-radius:0;border-top-right-radius:0}.select2-container--default.select2-container--open.select2-container--below .select2-selection--single,.select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--default .select2-search--dropdown .select2-search__field{border:1px solid #aaa}.select2-container--default .select2-search--inline .select2-search__field{background:transparent;border:none;outline:0;box-shadow:none;-webkit-appearance:textfield}.select2-container--default .select2-results>.select2-results__options{max-height:200px;overflow-y:auto}.select2-container--default .select2-results__option[role=group]{padding:0}.select2-container--default .select2-results__option[aria-disabled=true]{color:#999}.select2-container--default .select2-results__option[aria-selected=true]{background-color:#ddd}.select2-container--default .select2-results__option .select2-results__option{padding-left:1em}.select2-container--default .select2-results__option .select2-results__option .select2-results__group{padding-left:0}.select2-container--default .select2-results__option .select2-results__option .select2-results__option{margin-left:-1em;padding-left:2em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-2em;padding-left:3em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-3em;padding-left:4em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-4em;padding-left:5em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-5em;padding-left:6em}.select2-container--default .select2-results__option--highlighted[aria-selected]{background-color:#5897fb;color:white}.select2-container--default .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic .select2-selection--single{background-color:#f7f7f7;border:1px solid #aaa;border-radius:4px;outline:0;background-image:-webkit-linear-gradient(top, #fff 50%, #eee 100%);background-image:-o-linear-gradient(top, #fff 50%, #eee 100%);background-image:linear-gradient(to bottom, #fff 50%, #eee 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0)}.select2-container--classic .select2-selection--single:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px}.select2-container--classic .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;margin-right:10px}.select2-container--classic .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--classic .select2-selection--single .select2-selection__arrow{background-color:#ddd;border:none;border-left:1px solid #aaa;border-top-right-radius:4px;border-bottom-right-radius:4px;height:26px;position:absolute;top:1px;right:1px;width:20px;background-image:-webkit-linear-gradient(top, #eee 50%, #ccc 100%);background-image:-o-linear-gradient(top, #eee 50%, #ccc 100%);background-image:linear-gradient(to bottom, #eee 50%, #ccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFCCCCCC', GradientType=0)}.select2-container--classic .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__arrow{border:none;border-right:1px solid #aaa;border-radius:0;border-top-left-radius:4px;border-bottom-left-radius:4px;left:1px;right:auto}.select2-container--classic.select2-container--open .select2-selection--single{border:1px solid #5897fb}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow{background:transparent;border:none}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--single{border-top:none;border-top-left-radius:0;border-top-right-radius:0;background-image:-webkit-linear-gradient(top, #fff 0%, #eee 50%);background-image:-o-linear-gradient(top, #fff 0%, #eee 50%);background-image:linear-gradient(to bottom, #fff 0%, #eee 50%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0)}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--single{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0;background-image:-webkit-linear-gradient(top, #eee 50%, #fff 100%);background-image:-o-linear-gradient(top, #eee 50%, #fff 100%);background-image:linear-gradient(to bottom, #eee 50%, #fff 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFFFFFFF', GradientType=0)}.select2-container--classic .select2-selection--multiple{background-color:white;border:1px solid #aaa;border-radius:4px;cursor:text;outline:0}.select2-container--classic .select2-selection--multiple:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--multiple .select2-selection__rendered{list-style:none;margin:0;padding:0 5px}.select2-container--classic .select2-selection--multiple .select2-selection__clear{display:none}.select2-container--classic .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;cursor:default;float:left;margin-right:5px;margin-top:5px;padding:0 5px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove{color:#888;cursor:pointer;display:inline-block;font-weight:bold;margin-right:2px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover{color:#555}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice{float:right;margin-left:5px;margin-right:auto}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove{margin-left:2px;margin-right:auto}.select2-container--classic.select2-container--open .select2-selection--multiple{border:1px solid #5897fb}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--classic .select2-search--dropdown .select2-search__field{border:1px solid #aaa;outline:0}.select2-container--classic .select2-search--inline .select2-search__field{outline:0;box-shadow:none}.select2-container--classic .select2-dropdown{background-color:#fff;border:1px solid transparent}.select2-container--classic .select2-dropdown--above{border-bottom:none}.select2-container--classic .select2-dropdown--below{border-top:none}.select2-container--classic .select2-results>.select2-results__options{max-height:200px;overflow-y:auto}.select2-container--classic .select2-results__option[role=group]{padding:0}.select2-container--classic .select2-results__option[aria-disabled=true]{color:grey}.select2-container--classic .select2-results__option--highlighted[aria-selected]{background-color:#3875d7;color:#fff}.select2-container--classic .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic.select2-container--open .select2-dropdown{border-color:#5897fb} diff --git a/lottery/staticfiles/admin/css/widgets.css b/lottery/staticfiles/admin/css/widgets.css new file mode 100644 index 0000000..cc64811 --- /dev/null +++ b/lottery/staticfiles/admin/css/widgets.css @@ -0,0 +1,593 @@ +/* SELECTOR (FILTER INTERFACE) */ + +.selector { + display: flex; + flex-grow: 1; + gap: 0 10px; +} + +.selector select { + height: 17.2em; + flex: 1 0 auto; + overflow: scroll; + width: 100%; +} + +.selector-available, .selector-chosen { + text-align: center; + display: flex; + flex-direction: column; + flex: 1 1; +} + +.selector-available h2, .selector-chosen h2 { + border: 1px solid var(--border-color); + border-radius: 4px 4px 0 0; +} + +.selector-chosen .list-footer-display { + border: 1px solid var(--border-color); + border-top: none; + border-radius: 0 0 4px 4px; + margin: 0 0 10px; + padding: 8px; + text-align: center; + background: var(--primary); + color: var(--header-link-color); + cursor: pointer; +} +.selector-chosen .list-footer-display__clear { + color: var(--breadcrumbs-fg); +} + +.selector-chosen h2 { + background: var(--secondary); + color: var(--header-link-color); +} + +.selector .selector-available h2 { + background: var(--darkened-bg); + color: var(--body-quiet-color); +} + +.selector .selector-filter { + border: 1px solid var(--border-color); + border-width: 0 1px; + padding: 8px; + color: var(--body-quiet-color); + font-size: 0.625rem; + margin: 0; + text-align: left; + display: flex; +} + +.selector .selector-filter label, +.inline-group .aligned .selector .selector-filter label { + float: left; + margin: 7px 0 0; + width: 18px; + height: 18px; + padding: 0; + overflow: hidden; + line-height: 1; + min-width: auto; +} + +.selector-filter input { + flex-grow: 1; +} + +.selector .selector-available input, +.selector .selector-chosen input { + margin-left: 8px; +} + +.selector ul.selector-chooser { + align-self: center; + width: 22px; + background-color: var(--selected-bg); + border-radius: 10px; + margin: 0; + padding: 0; + transform: translateY(-17px); +} + +.selector-chooser li { + margin: 0; + padding: 3px; + list-style-type: none; +} + +.selector select { + padding: 0 10px; + margin: 0 0 10px; + border-radius: 0 0 4px 4px; +} +.selector .selector-chosen--with-filtered select { + margin: 0; + border-radius: 0; + height: 14em; +} + +.selector .selector-chosen:not(.selector-chosen--with-filtered) .list-footer-display { + display: none; +} + +.selector-add, .selector-remove { + width: 16px; + height: 16px; + display: block; + text-indent: -3000px; + overflow: hidden; + cursor: default; + opacity: 0.55; +} + +.active.selector-add, .active.selector-remove { + opacity: 1; +} + +.active.selector-add:hover, .active.selector-remove:hover { + cursor: pointer; +} + +.selector-add { + background: url(../img/selector-icons.svg) 0 -96px no-repeat; +} + +.active.selector-add:focus, .active.selector-add:hover { + background-position: 0 -112px; +} + +.selector-remove { + background: url(../img/selector-icons.svg) 0 -64px no-repeat; +} + +.active.selector-remove:focus, .active.selector-remove:hover { + background-position: 0 -80px; +} + +a.selector-chooseall, a.selector-clearall { + display: inline-block; + height: 16px; + text-align: left; + margin: 0 auto; + overflow: hidden; + font-weight: bold; + line-height: 16px; + color: var(--body-quiet-color); + text-decoration: none; + opacity: 0.55; +} + +a.active.selector-chooseall:focus, a.active.selector-clearall:focus, +a.active.selector-chooseall:hover, a.active.selector-clearall:hover { + color: var(--link-fg); +} + +a.active.selector-chooseall, a.active.selector-clearall { + opacity: 1; +} + +a.active.selector-chooseall:hover, a.active.selector-clearall:hover { + cursor: pointer; +} + +a.selector-chooseall { + padding: 0 18px 0 0; + background: url(../img/selector-icons.svg) right -160px no-repeat; + cursor: default; +} + +a.active.selector-chooseall:focus, a.active.selector-chooseall:hover { + background-position: 100% -176px; +} + +a.selector-clearall { + padding: 0 0 0 18px; + background: url(../img/selector-icons.svg) 0 -128px no-repeat; + cursor: default; +} + +a.active.selector-clearall:focus, a.active.selector-clearall:hover { + background-position: 0 -144px; +} + +/* STACKED SELECTORS */ + +.stacked { + float: left; + width: 490px; + display: block; +} + +.stacked select { + width: 480px; + height: 10.1em; +} + +.stacked .selector-available, .stacked .selector-chosen { + width: 480px; +} + +.stacked .selector-available { + margin-bottom: 0; +} + +.stacked .selector-available input { + width: 422px; +} + +.stacked ul.selector-chooser { + height: 22px; + width: 50px; + margin: 0 0 10px 40%; + background-color: #eee; + border-radius: 10px; + transform: none; +} + +.stacked .selector-chooser li { + float: left; + padding: 3px 3px 3px 5px; +} + +.stacked .selector-chooseall, .stacked .selector-clearall { + display: none; +} + +.stacked .selector-add { + background: url(../img/selector-icons.svg) 0 -32px no-repeat; + cursor: default; +} + +.stacked .active.selector-add { + background-position: 0 -32px; + cursor: pointer; +} + +.stacked .active.selector-add:focus, .stacked .active.selector-add:hover { + background-position: 0 -48px; + cursor: pointer; +} + +.stacked .selector-remove { + background: url(../img/selector-icons.svg) 0 0 no-repeat; + cursor: default; +} + +.stacked .active.selector-remove { + background-position: 0 0px; + cursor: pointer; +} + +.stacked .active.selector-remove:focus, .stacked .active.selector-remove:hover { + background-position: 0 -16px; + cursor: pointer; +} + +.selector .help-icon { + background: url(../img/icon-unknown.svg) 0 0 no-repeat; + display: inline-block; + vertical-align: middle; + margin: -2px 0 0 2px; + width: 13px; + height: 13px; +} + +.selector .selector-chosen .help-icon { + background: url(../img/icon-unknown-alt.svg) 0 0 no-repeat; +} + +.selector .search-label-icon { + background: url(../img/search.svg) 0 0 no-repeat; + display: inline-block; + height: 1.125rem; + width: 1.125rem; +} + +/* DATE AND TIME */ + +p.datetime { + line-height: 20px; + margin: 0; + padding: 0; + color: var(--body-quiet-color); + font-weight: bold; +} + +.datetime span { + white-space: nowrap; + font-weight: normal; + font-size: 0.6875rem; + color: var(--body-quiet-color); +} + +.datetime input, .form-row .datetime input.vDateField, .form-row .datetime input.vTimeField { + margin-left: 5px; + margin-bottom: 4px; +} + +table p.datetime { + font-size: 0.6875rem; + margin-left: 0; + padding-left: 0; +} + +.datetimeshortcuts .clock-icon, .datetimeshortcuts .date-icon { + position: relative; + display: inline-block; + vertical-align: middle; + height: 16px; + width: 16px; + overflow: hidden; +} + +.datetimeshortcuts .clock-icon { + background: url(../img/icon-clock.svg) 0 0 no-repeat; +} + +.datetimeshortcuts a:focus .clock-icon, +.datetimeshortcuts a:hover .clock-icon { + background-position: 0 -16px; +} + +.datetimeshortcuts .date-icon { + background: url(../img/icon-calendar.svg) 0 0 no-repeat; + top: -1px; +} + +.datetimeshortcuts a:focus .date-icon, +.datetimeshortcuts a:hover .date-icon { + background-position: 0 -16px; +} + +.timezonewarning { + font-size: 0.6875rem; + color: var(--body-quiet-color); +} + +/* URL */ + +p.url { + line-height: 20px; + margin: 0; + padding: 0; + color: var(--body-quiet-color); + font-size: 0.6875rem; + font-weight: bold; +} + +.url a { + font-weight: normal; +} + +/* FILE UPLOADS */ + +p.file-upload { + line-height: 20px; + margin: 0; + padding: 0; + color: var(--body-quiet-color); + font-size: 0.6875rem; + font-weight: bold; +} + +.file-upload a { + font-weight: normal; +} + +.file-upload .deletelink { + margin-left: 5px; +} + +span.clearable-file-input label { + color: var(--body-fg); + font-size: 0.6875rem; + display: inline; + float: none; +} + +/* CALENDARS & CLOCKS */ + +.calendarbox, .clockbox { + margin: 5px auto; + font-size: 0.75rem; + width: 19em; + text-align: center; + background: var(--body-bg); + color: var(--body-fg); + border: 1px solid var(--hairline-color); + border-radius: 4px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15); + overflow: hidden; + position: relative; +} + +.clockbox { + width: auto; +} + +.calendar { + margin: 0; + padding: 0; +} + +.calendar table { + margin: 0; + padding: 0; + border-collapse: collapse; + background: white; + width: 100%; +} + +.calendar caption, .calendarbox h2 { + margin: 0; + text-align: center; + border-top: none; + font-weight: 700; + font-size: 0.75rem; + color: #333; + background: var(--accent); +} + +.calendar th { + padding: 8px 5px; + background: var(--darkened-bg); + border-bottom: 1px solid var(--border-color); + font-weight: 400; + font-size: 0.75rem; + text-align: center; + color: var(--body-quiet-color); +} + +.calendar td { + font-weight: 400; + font-size: 0.75rem; + text-align: center; + padding: 0; + border-top: 1px solid var(--hairline-color); + border-bottom: none; +} + +.calendar td.selected a { + background: var(--secondary); + color: var(--button-fg); +} + +.calendar td.nonday { + background: var(--darkened-bg); +} + +.calendar td.today a { + font-weight: 700; +} + +.calendar td a, .timelist a { + display: block; + font-weight: 400; + padding: 6px; + text-decoration: none; + color: var(--body-quiet-color); +} + +.calendar td a:focus, .timelist a:focus, +.calendar td a:hover, .timelist a:hover { + background: var(--primary); + color: white; +} + +.calendar td a:active, .timelist a:active { + background: var(--header-bg); + color: white; +} + +.calendarnav { + font-size: 0.625rem; + text-align: center; + color: #ccc; + margin: 0; + padding: 1px 3px; +} + +.calendarnav a:link, #calendarnav a:visited, +#calendarnav a:focus, #calendarnav a:hover { + color: var(--body-quiet-color); +} + +.calendar-shortcuts { + background: var(--body-bg); + color: var(--body-quiet-color); + font-size: 0.6875rem; + line-height: 0.6875rem; + border-top: 1px solid var(--hairline-color); + padding: 8px 0; +} + +.calendarbox .calendarnav-previous, .calendarbox .calendarnav-next { + display: block; + position: absolute; + top: 8px; + width: 15px; + height: 15px; + text-indent: -9999px; + padding: 0; +} + +.calendarnav-previous { + left: 10px; + background: url(../img/calendar-icons.svg) 0 0 no-repeat; +} + +.calendarnav-next { + right: 10px; + background: url(../img/calendar-icons.svg) 0 -15px no-repeat; +} + +.calendar-cancel { + margin: 0; + padding: 4px 0; + font-size: 0.75rem; + background: var(--close-button-bg); + border-top: 1px solid var(--border-color); + color: var(--button-fg); +} + +.calendar-cancel:focus, .calendar-cancel:hover { + background: var(--close-button-hover-bg); +} + +.calendar-cancel a { + color: var(--button-fg); + display: block; +} + +ul.timelist, .timelist li { + list-style-type: none; + margin: 0; + padding: 0; +} + +.timelist a { + padding: 2px; +} + +/* EDIT INLINE */ + +.inline-deletelink { + float: right; + text-indent: -9999px; + background: url(../img/inline-delete.svg) 0 0 no-repeat; + width: 16px; + height: 16px; + border: 0px none; +} + +.inline-deletelink:focus, .inline-deletelink:hover { + cursor: pointer; +} + +/* RELATED WIDGET WRAPPER */ +.related-widget-wrapper { + display: flex; + gap: 0 10px; + flex-grow: 1; + flex-wrap: wrap; + margin-bottom: 5px; +} + +.related-widget-wrapper-link { + opacity: .6; + filter: grayscale(1); +} + +.related-widget-wrapper-link:link { + opacity: 1; + filter: grayscale(0); +} + +/* GIS MAPS */ +.dj_map { + width: 600px; + height: 400px; +} diff --git a/lottery/staticfiles/admin/img/LICENSE b/lottery/staticfiles/admin/img/LICENSE new file mode 100644 index 0000000..a4faaa1 --- /dev/null +++ b/lottery/staticfiles/admin/img/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2014 Code Charm Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/lottery/staticfiles/admin/img/README.txt b/lottery/staticfiles/admin/img/README.txt new file mode 100644 index 0000000..bf81f35 --- /dev/null +++ b/lottery/staticfiles/admin/img/README.txt @@ -0,0 +1,7 @@ +All icons are taken from Font Awesome (https://fontawesome.com/) project. +The Font Awesome font is licensed under the SIL OFL 1.1: +- https://scripts.sil.org/OFL + +SVG icons source: https://github.com/encharm/Font-Awesome-SVG-PNG +Font-Awesome-SVG-PNG is licensed under the MIT license (see file license +in current folder). diff --git a/lottery/staticfiles/admin/img/calendar-icons.svg b/lottery/staticfiles/admin/img/calendar-icons.svg new file mode 100644 index 0000000..04c0274 --- /dev/null +++ b/lottery/staticfiles/admin/img/calendar-icons.svg @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + diff --git a/lottery/staticfiles/admin/img/gis/move_vertex_off.svg b/lottery/staticfiles/admin/img/gis/move_vertex_off.svg new file mode 100644 index 0000000..228854f --- /dev/null +++ b/lottery/staticfiles/admin/img/gis/move_vertex_off.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/lottery/staticfiles/admin/img/gis/move_vertex_on.svg b/lottery/staticfiles/admin/img/gis/move_vertex_on.svg new file mode 100644 index 0000000..96b87fd --- /dev/null +++ b/lottery/staticfiles/admin/img/gis/move_vertex_on.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/lottery/staticfiles/admin/img/icon-addlink.svg b/lottery/staticfiles/admin/img/icon-addlink.svg new file mode 100644 index 0000000..8d5c6a3 --- /dev/null +++ b/lottery/staticfiles/admin/img/icon-addlink.svg @@ -0,0 +1,3 @@ + + + diff --git a/lottery/staticfiles/admin/img/icon-alert.svg b/lottery/staticfiles/admin/img/icon-alert.svg new file mode 100644 index 0000000..e51ea83 --- /dev/null +++ b/lottery/staticfiles/admin/img/icon-alert.svg @@ -0,0 +1,3 @@ + + + diff --git a/lottery/staticfiles/admin/img/icon-calendar.svg b/lottery/staticfiles/admin/img/icon-calendar.svg new file mode 100644 index 0000000..97910a9 --- /dev/null +++ b/lottery/staticfiles/admin/img/icon-calendar.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/lottery/staticfiles/admin/img/icon-changelink.svg b/lottery/staticfiles/admin/img/icon-changelink.svg new file mode 100644 index 0000000..592b093 --- /dev/null +++ b/lottery/staticfiles/admin/img/icon-changelink.svg @@ -0,0 +1,3 @@ + + + diff --git a/lottery/staticfiles/admin/img/icon-clock.svg b/lottery/staticfiles/admin/img/icon-clock.svg new file mode 100644 index 0000000..bf9985d --- /dev/null +++ b/lottery/staticfiles/admin/img/icon-clock.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/lottery/staticfiles/admin/img/icon-deletelink.svg b/lottery/staticfiles/admin/img/icon-deletelink.svg new file mode 100644 index 0000000..4059b15 --- /dev/null +++ b/lottery/staticfiles/admin/img/icon-deletelink.svg @@ -0,0 +1,3 @@ + + + diff --git a/lottery/staticfiles/admin/img/icon-hidelink.svg b/lottery/staticfiles/admin/img/icon-hidelink.svg new file mode 100644 index 0000000..2a8b404 --- /dev/null +++ b/lottery/staticfiles/admin/img/icon-hidelink.svg @@ -0,0 +1,3 @@ + + + diff --git a/lottery/staticfiles/admin/img/icon-no.svg b/lottery/staticfiles/admin/img/icon-no.svg new file mode 100644 index 0000000..2e0d383 --- /dev/null +++ b/lottery/staticfiles/admin/img/icon-no.svg @@ -0,0 +1,3 @@ + + + diff --git a/lottery/staticfiles/admin/img/icon-unknown-alt.svg b/lottery/staticfiles/admin/img/icon-unknown-alt.svg new file mode 100644 index 0000000..1c6b99f --- /dev/null +++ b/lottery/staticfiles/admin/img/icon-unknown-alt.svg @@ -0,0 +1,3 @@ + + + diff --git a/lottery/staticfiles/admin/img/icon-unknown.svg b/lottery/staticfiles/admin/img/icon-unknown.svg new file mode 100644 index 0000000..50b4f97 --- /dev/null +++ b/lottery/staticfiles/admin/img/icon-unknown.svg @@ -0,0 +1,3 @@ + + + diff --git a/lottery/staticfiles/admin/img/icon-viewlink.svg b/lottery/staticfiles/admin/img/icon-viewlink.svg new file mode 100644 index 0000000..a1ca1d3 --- /dev/null +++ b/lottery/staticfiles/admin/img/icon-viewlink.svg @@ -0,0 +1,3 @@ + + + diff --git a/lottery/staticfiles/admin/img/icon-yes.svg b/lottery/staticfiles/admin/img/icon-yes.svg new file mode 100644 index 0000000..5883d87 --- /dev/null +++ b/lottery/staticfiles/admin/img/icon-yes.svg @@ -0,0 +1,3 @@ + + + diff --git a/lottery/staticfiles/admin/img/inline-delete.svg b/lottery/staticfiles/admin/img/inline-delete.svg new file mode 100644 index 0000000..17d1ad6 --- /dev/null +++ b/lottery/staticfiles/admin/img/inline-delete.svg @@ -0,0 +1,3 @@ + + + diff --git a/lottery/staticfiles/admin/img/search.svg b/lottery/staticfiles/admin/img/search.svg new file mode 100644 index 0000000..c8c69b2 --- /dev/null +++ b/lottery/staticfiles/admin/img/search.svg @@ -0,0 +1,3 @@ + + + diff --git a/lottery/staticfiles/admin/img/selector-icons.svg b/lottery/staticfiles/admin/img/selector-icons.svg new file mode 100644 index 0000000..926b8e2 --- /dev/null +++ b/lottery/staticfiles/admin/img/selector-icons.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lottery/staticfiles/admin/img/sorting-icons.svg b/lottery/staticfiles/admin/img/sorting-icons.svg new file mode 100644 index 0000000..7c31ec9 --- /dev/null +++ b/lottery/staticfiles/admin/img/sorting-icons.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/lottery/staticfiles/admin/img/tooltag-add.svg b/lottery/staticfiles/admin/img/tooltag-add.svg new file mode 100644 index 0000000..1ca64ae --- /dev/null +++ b/lottery/staticfiles/admin/img/tooltag-add.svg @@ -0,0 +1,3 @@ + + + diff --git a/lottery/staticfiles/admin/img/tooltag-arrowright.svg b/lottery/staticfiles/admin/img/tooltag-arrowright.svg new file mode 100644 index 0000000..b664d61 --- /dev/null +++ b/lottery/staticfiles/admin/img/tooltag-arrowright.svg @@ -0,0 +1,3 @@ + + + diff --git a/lottery/staticfiles/admin/js/SelectBox.js b/lottery/staticfiles/admin/js/SelectBox.js new file mode 100644 index 0000000..3db4ec7 --- /dev/null +++ b/lottery/staticfiles/admin/js/SelectBox.js @@ -0,0 +1,116 @@ +'use strict'; +{ + const SelectBox = { + cache: {}, + init: function(id) { + const box = document.getElementById(id); + SelectBox.cache[id] = []; + const cache = SelectBox.cache[id]; + for (const node of box.options) { + cache.push({value: node.value, text: node.text, displayed: 1}); + } + }, + redisplay: function(id) { + // Repopulate HTML select box from cache + const box = document.getElementById(id); + const scroll_value_from_top = box.scrollTop; + box.innerHTML = ''; + for (const node of SelectBox.cache[id]) { + if (node.displayed) { + const new_option = new Option(node.text, node.value, false, false); + // Shows a tooltip when hovering over the option + new_option.title = node.text; + box.appendChild(new_option); + } + } + box.scrollTop = scroll_value_from_top; + }, + filter: function(id, text) { + // Redisplay the HTML select box, displaying only the choices containing ALL + // the words in text. (It's an AND search.) + const tokens = text.toLowerCase().split(/\s+/); + for (const node of SelectBox.cache[id]) { + node.displayed = 1; + const node_text = node.text.toLowerCase(); + for (const token of tokens) { + if (!node_text.includes(token)) { + node.displayed = 0; + break; // Once the first token isn't found we're done + } + } + } + SelectBox.redisplay(id); + }, + get_hidden_node_count(id) { + const cache = SelectBox.cache[id] || []; + return cache.filter(node => node.displayed === 0).length; + }, + delete_from_cache: function(id, value) { + let delete_index = null; + const cache = SelectBox.cache[id]; + for (const [i, node] of cache.entries()) { + if (node.value === value) { + delete_index = i; + break; + } + } + cache.splice(delete_index, 1); + }, + add_to_cache: function(id, option) { + SelectBox.cache[id].push({value: option.value, text: option.text, displayed: 1}); + }, + cache_contains: function(id, value) { + // Check if an item is contained in the cache + for (const node of SelectBox.cache[id]) { + if (node.value === value) { + return true; + } + } + return false; + }, + move: function(from, to) { + const from_box = document.getElementById(from); + for (const option of from_box.options) { + const option_value = option.value; + if (option.selected && SelectBox.cache_contains(from, option_value)) { + SelectBox.add_to_cache(to, {value: option_value, text: option.text, displayed: 1}); + SelectBox.delete_from_cache(from, option_value); + } + } + SelectBox.redisplay(from); + SelectBox.redisplay(to); + }, + move_all: function(from, to) { + const from_box = document.getElementById(from); + for (const option of from_box.options) { + const option_value = option.value; + if (SelectBox.cache_contains(from, option_value)) { + SelectBox.add_to_cache(to, {value: option_value, text: option.text, displayed: 1}); + SelectBox.delete_from_cache(from, option_value); + } + } + SelectBox.redisplay(from); + SelectBox.redisplay(to); + }, + sort: function(id) { + SelectBox.cache[id].sort(function(a, b) { + a = a.text.toLowerCase(); + b = b.text.toLowerCase(); + if (a > b) { + return 1; + } + if (a < b) { + return -1; + } + return 0; + } ); + }, + select_all: function(id) { + const box = document.getElementById(id); + for (const option of box.options) { + option.selected = true; + } + } + }; + window.SelectBox = SelectBox; +} diff --git a/lottery/staticfiles/admin/js/SelectFilter2.js b/lottery/staticfiles/admin/js/SelectFilter2.js new file mode 100644 index 0000000..6957412 --- /dev/null +++ b/lottery/staticfiles/admin/js/SelectFilter2.js @@ -0,0 +1,286 @@ +/*global SelectBox, gettext, ngettext, interpolate, quickElement, SelectFilter*/ +/* +SelectFilter2 - Turns a multiple-select box into a filter interface. + +Requires core.js and SelectBox.js. +*/ +'use strict'; +{ + window.SelectFilter = { + init: function(field_id, field_name, is_stacked) { + if (field_id.match(/__prefix__/)) { + // Don't initialize on empty forms. + return; + } + const from_box = document.getElementById(field_id); + from_box.id += '_from'; // change its ID + from_box.className = 'filtered'; + + for (const p of from_box.parentNode.getElementsByTagName('p')) { + if (p.classList.contains("info")) { + // Remove

, because it just gets in the way. + from_box.parentNode.removeChild(p); + } else if (p.classList.contains("help")) { + // Move help text up to the top so it isn't below the select + // boxes or wrapped off on the side to the right of the add + // button: + from_box.parentNode.insertBefore(p, from_box.parentNode.firstChild); + } + } + + //

or
+ const selector_div = quickElement('div', from_box.parentNode); + // Make sure the selector div is at the beginning so that the + // add link would be displayed to the right of the widget. + from_box.parentNode.prepend(selector_div); + selector_div.className = is_stacked ? 'selector stacked' : 'selector'; + + //
+ const selector_available = quickElement('div', selector_div); + selector_available.className = 'selector-available'; + const title_available = quickElement('h2', selector_available, interpolate(gettext('Available %s') + ' ', [field_name])); + quickElement( + 'span', title_available, '', + 'class', 'help help-tooltip help-icon', + 'title', interpolate( + gettext( + 'This is the list of available %s. You may choose some by ' + + 'selecting them in the box below and then clicking the ' + + '"Choose" arrow between the two boxes.' + ), + [field_name] + ) + ); + + const filter_p = quickElement('p', selector_available, '', 'id', field_id + '_filter'); + filter_p.className = 'selector-filter'; + + const search_filter_label = quickElement('label', filter_p, '', 'for', field_id + '_input'); + + quickElement( + 'span', search_filter_label, '', + 'class', 'help-tooltip search-label-icon', + 'title', interpolate(gettext("Type into this box to filter down the list of available %s."), [field_name]) + ); + + filter_p.appendChild(document.createTextNode(' ')); + + const filter_input = quickElement('input', filter_p, '', 'type', 'text', 'placeholder', gettext("Filter")); + filter_input.id = field_id + '_input'; + + selector_available.appendChild(from_box); + const choose_all = quickElement('a', selector_available, gettext('Choose all'), 'title', interpolate(gettext('Click to choose all %s at once.'), [field_name]), 'href', '#', 'id', field_id + '_add_all_link'); + choose_all.className = 'selector-chooseall'; + + //
    + const selector_chooser = quickElement('ul', selector_div); + selector_chooser.className = 'selector-chooser'; + const add_link = quickElement('a', quickElement('li', selector_chooser), gettext('Choose'), 'title', gettext('Choose'), 'href', '#', 'id', field_id + '_add_link'); + add_link.className = 'selector-add'; + const remove_link = quickElement('a', quickElement('li', selector_chooser), gettext('Remove'), 'title', gettext('Remove'), 'href', '#', 'id', field_id + '_remove_link'); + remove_link.className = 'selector-remove'; + + //
    + const selector_chosen = quickElement('div', selector_div, '', 'id', field_id + '_selector_chosen'); + selector_chosen.className = 'selector-chosen'; + const title_chosen = quickElement('h2', selector_chosen, interpolate(gettext('Chosen %s') + ' ', [field_name])); + quickElement( + 'span', title_chosen, '', + 'class', 'help help-tooltip help-icon', + 'title', interpolate( + gettext( + 'This is the list of chosen %s. You may remove some by ' + + 'selecting them in the box below and then clicking the ' + + '"Remove" arrow between the two boxes.' + ), + [field_name] + ) + ); + + const filter_selected_p = quickElement('p', selector_chosen, '', 'id', field_id + '_filter_selected'); + filter_selected_p.className = 'selector-filter'; + + const search_filter_selected_label = quickElement('label', filter_selected_p, '', 'for', field_id + '_selected_input'); + + quickElement( + 'span', search_filter_selected_label, '', + 'class', 'help-tooltip search-label-icon', + 'title', interpolate(gettext("Type into this box to filter down the list of selected %s."), [field_name]) + ); + + filter_selected_p.appendChild(document.createTextNode(' ')); + + const filter_selected_input = quickElement('input', filter_selected_p, '', 'type', 'text', 'placeholder', gettext("Filter")); + filter_selected_input.id = field_id + '_selected_input'; + + const to_box = quickElement('select', selector_chosen, '', 'id', field_id + '_to', 'multiple', '', 'size', from_box.size, 'name', from_box.name); + to_box.className = 'filtered'; + + const warning_footer = quickElement('div', selector_chosen, '', 'class', 'list-footer-display'); + quickElement('span', warning_footer, '', 'id', field_id + '_list-footer-display-text'); + quickElement('span', warning_footer, ' (click to clear)', 'class', 'list-footer-display__clear'); + + const clear_all = quickElement('a', selector_chosen, gettext('Remove all'), 'title', interpolate(gettext('Click to remove all chosen %s at once.'), [field_name]), 'href', '#', 'id', field_id + '_remove_all_link'); + clear_all.className = 'selector-clearall'; + + from_box.name = from_box.name + '_old'; + + // Set up the JavaScript event handlers for the select box filter interface + const move_selection = function(e, elem, move_func, from, to) { + if (elem.classList.contains('active')) { + move_func(from, to); + SelectFilter.refresh_icons(field_id); + SelectFilter.refresh_filtered_selects(field_id); + SelectFilter.refresh_filtered_warning(field_id); + } + e.preventDefault(); + }; + choose_all.addEventListener('click', function(e) { + move_selection(e, this, SelectBox.move_all, field_id + '_from', field_id + '_to'); + }); + add_link.addEventListener('click', function(e) { + move_selection(e, this, SelectBox.move, field_id + '_from', field_id + '_to'); + }); + remove_link.addEventListener('click', function(e) { + move_selection(e, this, SelectBox.move, field_id + '_to', field_id + '_from'); + }); + clear_all.addEventListener('click', function(e) { + move_selection(e, this, SelectBox.move_all, field_id + '_to', field_id + '_from'); + }); + warning_footer.addEventListener('click', function(e) { + filter_selected_input.value = ''; + SelectBox.filter(field_id + '_to', ''); + SelectFilter.refresh_filtered_warning(field_id); + SelectFilter.refresh_icons(field_id); + }); + filter_input.addEventListener('keypress', function(e) { + SelectFilter.filter_key_press(e, field_id, '_from', '_to'); + }); + filter_input.addEventListener('keyup', function(e) { + SelectFilter.filter_key_up(e, field_id, '_from'); + }); + filter_input.addEventListener('keydown', function(e) { + SelectFilter.filter_key_down(e, field_id, '_from', '_to'); + }); + filter_selected_input.addEventListener('keypress', function(e) { + SelectFilter.filter_key_press(e, field_id, '_to', '_from'); + }); + filter_selected_input.addEventListener('keyup', function(e) { + SelectFilter.filter_key_up(e, field_id, '_to', '_selected_input'); + }); + filter_selected_input.addEventListener('keydown', function(e) { + SelectFilter.filter_key_down(e, field_id, '_to', '_from'); + }); + selector_div.addEventListener('change', function(e) { + if (e.target.tagName === 'SELECT') { + SelectFilter.refresh_icons(field_id); + } + }); + selector_div.addEventListener('dblclick', function(e) { + if (e.target.tagName === 'OPTION') { + if (e.target.closest('select').id === field_id + '_to') { + SelectBox.move(field_id + '_to', field_id + '_from'); + } else { + SelectBox.move(field_id + '_from', field_id + '_to'); + } + SelectFilter.refresh_icons(field_id); + } + }); + from_box.closest('form').addEventListener('submit', function() { + SelectBox.filter(field_id + '_to', ''); + SelectBox.select_all(field_id + '_to'); + }); + SelectBox.init(field_id + '_from'); + SelectBox.init(field_id + '_to'); + // Move selected from_box options to to_box + SelectBox.move(field_id + '_from', field_id + '_to'); + + // Initial icon refresh + SelectFilter.refresh_icons(field_id); + }, + any_selected: function(field) { + // Temporarily add the required attribute and check validity. + field.required = true; + const any_selected = field.checkValidity(); + field.required = false; + return any_selected; + }, + refresh_filtered_warning: function(field_id) { + const count = SelectBox.get_hidden_node_count(field_id + '_to'); + const selector = document.getElementById(field_id + '_selector_chosen'); + const warning = document.getElementById(field_id + '_list-footer-display-text'); + selector.className = selector.className.replace('selector-chosen--with-filtered', ''); + warning.textContent = interpolate(ngettext( + '%s selected option not visible', + '%s selected options not visible', + count + ), [count]); + if(count > 0) { + selector.className += ' selector-chosen--with-filtered'; + } + }, + refresh_filtered_selects: function(field_id) { + SelectBox.filter(field_id + '_from', document.getElementById(field_id + "_input").value); + SelectBox.filter(field_id + '_to', document.getElementById(field_id + "_selected_input").value); + }, + refresh_icons: function(field_id) { + const from = document.getElementById(field_id + '_from'); + const to = document.getElementById(field_id + '_to'); + // Active if at least one item is selected + document.getElementById(field_id + '_add_link').classList.toggle('active', SelectFilter.any_selected(from)); + document.getElementById(field_id + '_remove_link').classList.toggle('active', SelectFilter.any_selected(to)); + // Active if the corresponding box isn't empty + document.getElementById(field_id + '_add_all_link').classList.toggle('active', from.querySelector('option')); + document.getElementById(field_id + '_remove_all_link').classList.toggle('active', to.querySelector('option')); + SelectFilter.refresh_filtered_warning(field_id); + }, + filter_key_press: function(event, field_id, source, target) { + const source_box = document.getElementById(field_id + source); + // don't submit form if user pressed Enter + if ((event.which && event.which === 13) || (event.keyCode && event.keyCode === 13)) { + source_box.selectedIndex = 0; + SelectBox.move(field_id + source, field_id + target); + source_box.selectedIndex = 0; + event.preventDefault(); + } + }, + filter_key_up: function(event, field_id, source, filter_input) { + const input = filter_input || '_input'; + const source_box = document.getElementById(field_id + source); + const temp = source_box.selectedIndex; + SelectBox.filter(field_id + source, document.getElementById(field_id + input).value); + source_box.selectedIndex = temp; + SelectFilter.refresh_filtered_warning(field_id); + SelectFilter.refresh_icons(field_id); + }, + filter_key_down: function(event, field_id, source, target) { + const source_box = document.getElementById(field_id + source); + // right key (39) or left key (37) + const direction = source === '_from' ? 39 : 37; + // right arrow -- move across + if ((event.which && event.which === direction) || (event.keyCode && event.keyCode === direction)) { + const old_index = source_box.selectedIndex; + SelectBox.move(field_id + source, field_id + target); + SelectFilter.refresh_filtered_selects(field_id); + SelectFilter.refresh_filtered_warning(field_id); + source_box.selectedIndex = (old_index === source_box.length) ? source_box.length - 1 : old_index; + return; + } + // down arrow -- wrap around + if ((event.which && event.which === 40) || (event.keyCode && event.keyCode === 40)) { + source_box.selectedIndex = (source_box.length === source_box.selectedIndex + 1) ? 0 : source_box.selectedIndex + 1; + } + // up arrow -- wrap around + if ((event.which && event.which === 38) || (event.keyCode && event.keyCode === 38)) { + source_box.selectedIndex = (source_box.selectedIndex === 0) ? source_box.length - 1 : source_box.selectedIndex - 1; + } + } + }; + + window.addEventListener('load', function(e) { + document.querySelectorAll('select.selectfilter, select.selectfilterstacked').forEach(function(el) { + const data = el.dataset; + SelectFilter.init(el.id, data.fieldName, parseInt(data.isStacked, 10)); + }); + }); +} diff --git a/lottery/staticfiles/admin/js/actions.js b/lottery/staticfiles/admin/js/actions.js new file mode 100644 index 0000000..04b25e9 --- /dev/null +++ b/lottery/staticfiles/admin/js/actions.js @@ -0,0 +1,204 @@ +/*global gettext, interpolate, ngettext, Actions*/ +'use strict'; +{ + function show(selector) { + document.querySelectorAll(selector).forEach(function(el) { + el.classList.remove('hidden'); + }); + } + + function hide(selector) { + document.querySelectorAll(selector).forEach(function(el) { + el.classList.add('hidden'); + }); + } + + function showQuestion(options) { + hide(options.acrossClears); + show(options.acrossQuestions); + hide(options.allContainer); + } + + function showClear(options) { + show(options.acrossClears); + hide(options.acrossQuestions); + document.querySelector(options.actionContainer).classList.remove(options.selectedClass); + show(options.allContainer); + hide(options.counterContainer); + } + + function reset(options) { + hide(options.acrossClears); + hide(options.acrossQuestions); + hide(options.allContainer); + show(options.counterContainer); + } + + function clearAcross(options) { + reset(options); + const acrossInputs = document.querySelectorAll(options.acrossInput); + acrossInputs.forEach(function(acrossInput) { + acrossInput.value = 0; + }); + document.querySelector(options.actionContainer).classList.remove(options.selectedClass); + } + + function checker(actionCheckboxes, options, checked) { + if (checked) { + showQuestion(options); + } else { + reset(options); + } + actionCheckboxes.forEach(function(el) { + el.checked = checked; + el.closest('tr').classList.toggle(options.selectedClass, checked); + }); + } + + function updateCounter(actionCheckboxes, options) { + const sel = Array.from(actionCheckboxes).filter(function(el) { + return el.checked; + }).length; + const counter = document.querySelector(options.counterContainer); + // data-actions-icnt is defined in the generated HTML + // and contains the total amount of objects in the queryset + const actions_icnt = Number(counter.dataset.actionsIcnt); + counter.textContent = interpolate( + ngettext('%(sel)s of %(cnt)s selected', '%(sel)s of %(cnt)s selected', sel), { + sel: sel, + cnt: actions_icnt + }, true); + const allToggle = document.getElementById(options.allToggleId); + allToggle.checked = sel === actionCheckboxes.length; + if (allToggle.checked) { + showQuestion(options); + } else { + clearAcross(options); + } + } + + const defaults = { + actionContainer: "div.actions", + counterContainer: "span.action-counter", + allContainer: "div.actions span.all", + acrossInput: "div.actions input.select-across", + acrossQuestions: "div.actions span.question", + acrossClears: "div.actions span.clear", + allToggleId: "action-toggle", + selectedClass: "selected" + }; + + window.Actions = function(actionCheckboxes, options) { + options = Object.assign({}, defaults, options); + let list_editable_changed = false; + let lastChecked = null; + let shiftPressed = false; + + document.addEventListener('keydown', (event) => { + shiftPressed = event.shiftKey; + }); + + document.addEventListener('keyup', (event) => { + shiftPressed = event.shiftKey; + }); + + document.getElementById(options.allToggleId).addEventListener('click', function(event) { + checker(actionCheckboxes, options, this.checked); + updateCounter(actionCheckboxes, options); + }); + + document.querySelectorAll(options.acrossQuestions + " a").forEach(function(el) { + el.addEventListener('click', function(event) { + event.preventDefault(); + const acrossInputs = document.querySelectorAll(options.acrossInput); + acrossInputs.forEach(function(acrossInput) { + acrossInput.value = 1; + }); + showClear(options); + }); + }); + + document.querySelectorAll(options.acrossClears + " a").forEach(function(el) { + el.addEventListener('click', function(event) { + event.preventDefault(); + document.getElementById(options.allToggleId).checked = false; + clearAcross(options); + checker(actionCheckboxes, options, false); + updateCounter(actionCheckboxes, options); + }); + }); + + function affectedCheckboxes(target, withModifier) { + const multiSelect = (lastChecked && withModifier && lastChecked !== target); + if (!multiSelect) { + return [target]; + } + const checkboxes = Array.from(actionCheckboxes); + const targetIndex = checkboxes.findIndex(el => el === target); + const lastCheckedIndex = checkboxes.findIndex(el => el === lastChecked); + const startIndex = Math.min(targetIndex, lastCheckedIndex); + const endIndex = Math.max(targetIndex, lastCheckedIndex); + const filtered = checkboxes.filter((el, index) => (startIndex <= index) && (index <= endIndex)); + return filtered; + }; + + Array.from(document.getElementById('result_list').tBodies).forEach(function(el) { + el.addEventListener('change', function(event) { + const target = event.target; + if (target.classList.contains('action-select')) { + const checkboxes = affectedCheckboxes(target, shiftPressed); + checker(checkboxes, options, target.checked); + updateCounter(actionCheckboxes, options); + lastChecked = target; + } else { + list_editable_changed = true; + } + }); + }); + + document.querySelector('#changelist-form button[name=index]').addEventListener('click', function(event) { + if (list_editable_changed) { + const confirmed = confirm(gettext("You have unsaved changes on individual editable fields. If you run an action, your unsaved changes will be lost.")); + if (!confirmed) { + event.preventDefault(); + } + } + }); + + const el = document.querySelector('#changelist-form input[name=_save]'); + // The button does not exist if no fields are editable. + if (el) { + el.addEventListener('click', function(event) { + if (document.querySelector('[name=action]').value) { + const text = list_editable_changed + ? gettext("You have selected an action, but you haven’t saved your changes to individual fields yet. Please click OK to save. You’ll need to re-run the action.") + : gettext("You have selected an action, and you haven’t made any changes on individual fields. You’re probably looking for the Go button rather than the Save button."); + if (!confirm(text)) { + event.preventDefault(); + } + } + }); + } + // Sync counter when navigating to the page, such as through the back + // button. + window.addEventListener('pageshow', (event) => updateCounter(actionCheckboxes, options)); + }; + + // Call function fn when the DOM is loaded and ready. If it is already + // loaded, call the function now. + // http://youmightnotneedjquery.com/#ready + function ready(fn) { + if (document.readyState !== 'loading') { + fn(); + } else { + document.addEventListener('DOMContentLoaded', fn); + } + } + + ready(function() { + const actionsEls = document.querySelectorAll('tr input.action-select'); + if (actionsEls.length > 0) { + Actions(actionsEls); + } + }); +} diff --git a/lottery/staticfiles/admin/js/admin/DateTimeShortcuts.js b/lottery/staticfiles/admin/js/admin/DateTimeShortcuts.js new file mode 100644 index 0000000..aa1cae9 --- /dev/null +++ b/lottery/staticfiles/admin/js/admin/DateTimeShortcuts.js @@ -0,0 +1,408 @@ +/*global Calendar, findPosX, findPosY, get_format, gettext, gettext_noop, interpolate, ngettext, quickElement*/ +// Inserts shortcut buttons after all of the following: +// +// +'use strict'; +{ + const DateTimeShortcuts = { + calendars: [], + calendarInputs: [], + clockInputs: [], + clockHours: { + default_: [ + [gettext_noop('Now'), -1], + [gettext_noop('Midnight'), 0], + [gettext_noop('6 a.m.'), 6], + [gettext_noop('Noon'), 12], + [gettext_noop('6 p.m.'), 18] + ] + }, + dismissClockFunc: [], + dismissCalendarFunc: [], + calendarDivName1: 'calendarbox', // name of calendar
    that gets toggled + calendarDivName2: 'calendarin', // name of
    that contains calendar + calendarLinkName: 'calendarlink', // name of the link that is used to toggle + clockDivName: 'clockbox', // name of clock
    that gets toggled + clockLinkName: 'clocklink', // name of the link that is used to toggle + shortCutsClass: 'datetimeshortcuts', // class of the clock and cal shortcuts + timezoneWarningClass: 'timezonewarning', // class of the warning for timezone mismatch + timezoneOffset: 0, + init: function() { + const serverOffset = document.body.dataset.adminUtcOffset; + if (serverOffset) { + const localOffset = new Date().getTimezoneOffset() * -60; + DateTimeShortcuts.timezoneOffset = localOffset - serverOffset; + } + + for (const inp of document.getElementsByTagName('input')) { + if (inp.type === 'text' && inp.classList.contains('vTimeField')) { + DateTimeShortcuts.addClock(inp); + DateTimeShortcuts.addTimezoneWarning(inp); + } + else if (inp.type === 'text' && inp.classList.contains('vDateField')) { + DateTimeShortcuts.addCalendar(inp); + DateTimeShortcuts.addTimezoneWarning(inp); + } + } + }, + // Return the current time while accounting for the server timezone. + now: function() { + const serverOffset = document.body.dataset.adminUtcOffset; + if (serverOffset) { + const localNow = new Date(); + const localOffset = localNow.getTimezoneOffset() * -60; + localNow.setTime(localNow.getTime() + 1000 * (serverOffset - localOffset)); + return localNow; + } else { + return new Date(); + } + }, + // Add a warning when the time zone in the browser and backend do not match. + addTimezoneWarning: function(inp) { + const warningClass = DateTimeShortcuts.timezoneWarningClass; + let timezoneOffset = DateTimeShortcuts.timezoneOffset / 3600; + + // Only warn if there is a time zone mismatch. + if (!timezoneOffset) { + return; + } + + // Check if warning is already there. + if (inp.parentNode.querySelectorAll('.' + warningClass).length) { + return; + } + + let message; + if (timezoneOffset > 0) { + message = ngettext( + 'Note: You are %s hour ahead of server time.', + 'Note: You are %s hours ahead of server time.', + timezoneOffset + ); + } + else { + timezoneOffset *= -1; + message = ngettext( + 'Note: You are %s hour behind server time.', + 'Note: You are %s hours behind server time.', + timezoneOffset + ); + } + message = interpolate(message, [timezoneOffset]); + + const warning = document.createElement('div'); + warning.classList.add('help', warningClass); + warning.textContent = message; + inp.parentNode.appendChild(warning); + }, + // Add clock widget to a given field + addClock: function(inp) { + const num = DateTimeShortcuts.clockInputs.length; + DateTimeShortcuts.clockInputs[num] = inp; + DateTimeShortcuts.dismissClockFunc[num] = function() { DateTimeShortcuts.dismissClock(num); return true; }; + + // Shortcut links (clock icon and "Now" link) + const shortcuts_span = document.createElement('span'); + shortcuts_span.className = DateTimeShortcuts.shortCutsClass; + inp.parentNode.insertBefore(shortcuts_span, inp.nextSibling); + const now_link = document.createElement('a'); + now_link.href = "#"; + now_link.textContent = gettext('Now'); + now_link.addEventListener('click', function(e) { + e.preventDefault(); + DateTimeShortcuts.handleClockQuicklink(num, -1); + }); + const clock_link = document.createElement('a'); + clock_link.href = '#'; + clock_link.id = DateTimeShortcuts.clockLinkName + num; + clock_link.addEventListener('click', function(e) { + e.preventDefault(); + // avoid triggering the document click handler to dismiss the clock + e.stopPropagation(); + DateTimeShortcuts.openClock(num); + }); + + quickElement( + 'span', clock_link, '', + 'class', 'clock-icon', + 'title', gettext('Choose a Time') + ); + shortcuts_span.appendChild(document.createTextNode('\u00A0')); + shortcuts_span.appendChild(now_link); + shortcuts_span.appendChild(document.createTextNode('\u00A0|\u00A0')); + shortcuts_span.appendChild(clock_link); + + // Create clock link div + // + // Markup looks like: + //
    + //

    Choose a time

    + // + //

    Cancel

    + //
    + + const clock_box = document.createElement('div'); + clock_box.style.display = 'none'; + clock_box.style.position = 'absolute'; + clock_box.className = 'clockbox module'; + clock_box.id = DateTimeShortcuts.clockDivName + num; + document.body.appendChild(clock_box); + clock_box.addEventListener('click', function(e) { e.stopPropagation(); }); + + quickElement('h2', clock_box, gettext('Choose a time')); + const time_list = quickElement('ul', clock_box); + time_list.className = 'timelist'; + // The list of choices can be overridden in JavaScript like this: + // DateTimeShortcuts.clockHours.name = [['3 a.m.', 3]]; + // where name is the name attribute of the . + const name = typeof DateTimeShortcuts.clockHours[inp.name] === 'undefined' ? 'default_' : inp.name; + DateTimeShortcuts.clockHours[name].forEach(function(element) { + const time_link = quickElement('a', quickElement('li', time_list), gettext(element[0]), 'href', '#'); + time_link.addEventListener('click', function(e) { + e.preventDefault(); + DateTimeShortcuts.handleClockQuicklink(num, element[1]); + }); + }); + + const cancel_p = quickElement('p', clock_box); + cancel_p.className = 'calendar-cancel'; + const cancel_link = quickElement('a', cancel_p, gettext('Cancel'), 'href', '#'); + cancel_link.addEventListener('click', function(e) { + e.preventDefault(); + DateTimeShortcuts.dismissClock(num); + }); + + document.addEventListener('keyup', function(event) { + if (event.which === 27) { + // ESC key closes popup + DateTimeShortcuts.dismissClock(num); + event.preventDefault(); + } + }); + }, + openClock: function(num) { + const clock_box = document.getElementById(DateTimeShortcuts.clockDivName + num); + const clock_link = document.getElementById(DateTimeShortcuts.clockLinkName + num); + + // Recalculate the clockbox position + // is it left-to-right or right-to-left layout ? + if (window.getComputedStyle(document.body).direction !== 'rtl') { + clock_box.style.left = findPosX(clock_link) + 17 + 'px'; + } + else { + // since style's width is in em, it'd be tough to calculate + // px value of it. let's use an estimated px for now + clock_box.style.left = findPosX(clock_link) - 110 + 'px'; + } + clock_box.style.top = Math.max(0, findPosY(clock_link) - 30) + 'px'; + + // Show the clock box + clock_box.style.display = 'block'; + document.addEventListener('click', DateTimeShortcuts.dismissClockFunc[num]); + }, + dismissClock: function(num) { + document.getElementById(DateTimeShortcuts.clockDivName + num).style.display = 'none'; + document.removeEventListener('click', DateTimeShortcuts.dismissClockFunc[num]); + }, + handleClockQuicklink: function(num, val) { + let d; + if (val === -1) { + d = DateTimeShortcuts.now(); + } + else { + d = new Date(1970, 1, 1, val, 0, 0, 0); + } + DateTimeShortcuts.clockInputs[num].value = d.strftime(get_format('TIME_INPUT_FORMATS')[0]); + DateTimeShortcuts.clockInputs[num].focus(); + DateTimeShortcuts.dismissClock(num); + }, + // Add calendar widget to a given field. + addCalendar: function(inp) { + const num = DateTimeShortcuts.calendars.length; + + DateTimeShortcuts.calendarInputs[num] = inp; + DateTimeShortcuts.dismissCalendarFunc[num] = function() { DateTimeShortcuts.dismissCalendar(num); return true; }; + + // Shortcut links (calendar icon and "Today" link) + const shortcuts_span = document.createElement('span'); + shortcuts_span.className = DateTimeShortcuts.shortCutsClass; + inp.parentNode.insertBefore(shortcuts_span, inp.nextSibling); + const today_link = document.createElement('a'); + today_link.href = '#'; + today_link.appendChild(document.createTextNode(gettext('Today'))); + today_link.addEventListener('click', function(e) { + e.preventDefault(); + DateTimeShortcuts.handleCalendarQuickLink(num, 0); + }); + const cal_link = document.createElement('a'); + cal_link.href = '#'; + cal_link.id = DateTimeShortcuts.calendarLinkName + num; + cal_link.addEventListener('click', function(e) { + e.preventDefault(); + // avoid triggering the document click handler to dismiss the calendar + e.stopPropagation(); + DateTimeShortcuts.openCalendar(num); + }); + quickElement( + 'span', cal_link, '', + 'class', 'date-icon', + 'title', gettext('Choose a Date') + ); + shortcuts_span.appendChild(document.createTextNode('\u00A0')); + shortcuts_span.appendChild(today_link); + shortcuts_span.appendChild(document.createTextNode('\u00A0|\u00A0')); + shortcuts_span.appendChild(cal_link); + + // Create calendarbox div. + // + // Markup looks like: + // + //
    + //

    + // + // February 2003 + //

    + //
    + // + //
    + //
    + // Yesterday | Today | Tomorrow + //
    + //

    Cancel

    + //
    + const cal_box = document.createElement('div'); + cal_box.style.display = 'none'; + cal_box.style.position = 'absolute'; + cal_box.className = 'calendarbox module'; + cal_box.id = DateTimeShortcuts.calendarDivName1 + num; + document.body.appendChild(cal_box); + cal_box.addEventListener('click', function(e) { e.stopPropagation(); }); + + // next-prev links + const cal_nav = quickElement('div', cal_box); + const cal_nav_prev = quickElement('a', cal_nav, '<', 'href', '#'); + cal_nav_prev.className = 'calendarnav-previous'; + cal_nav_prev.addEventListener('click', function(e) { + e.preventDefault(); + DateTimeShortcuts.drawPrev(num); + }); + + const cal_nav_next = quickElement('a', cal_nav, '>', 'href', '#'); + cal_nav_next.className = 'calendarnav-next'; + cal_nav_next.addEventListener('click', function(e) { + e.preventDefault(); + DateTimeShortcuts.drawNext(num); + }); + + // main box + const cal_main = quickElement('div', cal_box, '', 'id', DateTimeShortcuts.calendarDivName2 + num); + cal_main.className = 'calendar'; + DateTimeShortcuts.calendars[num] = new Calendar(DateTimeShortcuts.calendarDivName2 + num, DateTimeShortcuts.handleCalendarCallback(num)); + DateTimeShortcuts.calendars[num].drawCurrent(); + + // calendar shortcuts + const shortcuts = quickElement('div', cal_box); + shortcuts.className = 'calendar-shortcuts'; + let day_link = quickElement('a', shortcuts, gettext('Yesterday'), 'href', '#'); + day_link.addEventListener('click', function(e) { + e.preventDefault(); + DateTimeShortcuts.handleCalendarQuickLink(num, -1); + }); + shortcuts.appendChild(document.createTextNode('\u00A0|\u00A0')); + day_link = quickElement('a', shortcuts, gettext('Today'), 'href', '#'); + day_link.addEventListener('click', function(e) { + e.preventDefault(); + DateTimeShortcuts.handleCalendarQuickLink(num, 0); + }); + shortcuts.appendChild(document.createTextNode('\u00A0|\u00A0')); + day_link = quickElement('a', shortcuts, gettext('Tomorrow'), 'href', '#'); + day_link.addEventListener('click', function(e) { + e.preventDefault(); + DateTimeShortcuts.handleCalendarQuickLink(num, +1); + }); + + // cancel bar + const cancel_p = quickElement('p', cal_box); + cancel_p.className = 'calendar-cancel'; + const cancel_link = quickElement('a', cancel_p, gettext('Cancel'), 'href', '#'); + cancel_link.addEventListener('click', function(e) { + e.preventDefault(); + DateTimeShortcuts.dismissCalendar(num); + }); + document.addEventListener('keyup', function(event) { + if (event.which === 27) { + // ESC key closes popup + DateTimeShortcuts.dismissCalendar(num); + event.preventDefault(); + } + }); + }, + openCalendar: function(num) { + const cal_box = document.getElementById(DateTimeShortcuts.calendarDivName1 + num); + const cal_link = document.getElementById(DateTimeShortcuts.calendarLinkName + num); + const inp = DateTimeShortcuts.calendarInputs[num]; + + // Determine if the current value in the input has a valid date. + // If so, draw the calendar with that date's year and month. + if (inp.value) { + const format = get_format('DATE_INPUT_FORMATS')[0]; + const selected = inp.value.strptime(format); + const year = selected.getUTCFullYear(); + const month = selected.getUTCMonth() + 1; + const re = /\d{4}/; + if (re.test(year.toString()) && month >= 1 && month <= 12) { + DateTimeShortcuts.calendars[num].drawDate(month, year, selected); + } + } + + // Recalculate the clockbox position + // is it left-to-right or right-to-left layout ? + if (window.getComputedStyle(document.body).direction !== 'rtl') { + cal_box.style.left = findPosX(cal_link) + 17 + 'px'; + } + else { + // since style's width is in em, it'd be tough to calculate + // px value of it. let's use an estimated px for now + cal_box.style.left = findPosX(cal_link) - 180 + 'px'; + } + cal_box.style.top = Math.max(0, findPosY(cal_link) - 75) + 'px'; + + cal_box.style.display = 'block'; + document.addEventListener('click', DateTimeShortcuts.dismissCalendarFunc[num]); + }, + dismissCalendar: function(num) { + document.getElementById(DateTimeShortcuts.calendarDivName1 + num).style.display = 'none'; + document.removeEventListener('click', DateTimeShortcuts.dismissCalendarFunc[num]); + }, + drawPrev: function(num) { + DateTimeShortcuts.calendars[num].drawPreviousMonth(); + }, + drawNext: function(num) { + DateTimeShortcuts.calendars[num].drawNextMonth(); + }, + handleCalendarCallback: function(num) { + const format = get_format('DATE_INPUT_FORMATS')[0]; + return function(y, m, d) { + DateTimeShortcuts.calendarInputs[num].value = new Date(y, m - 1, d).strftime(format); + DateTimeShortcuts.calendarInputs[num].focus(); + document.getElementById(DateTimeShortcuts.calendarDivName1 + num).style.display = 'none'; + }; + }, + handleCalendarQuickLink: function(num, offset) { + const d = DateTimeShortcuts.now(); + d.setDate(d.getDate() + offset); + DateTimeShortcuts.calendarInputs[num].value = d.strftime(get_format('DATE_INPUT_FORMATS')[0]); + DateTimeShortcuts.calendarInputs[num].focus(); + DateTimeShortcuts.dismissCalendar(num); + } + }; + + window.addEventListener('load', DateTimeShortcuts.init); + window.DateTimeShortcuts = DateTimeShortcuts; +} diff --git a/lottery/staticfiles/admin/js/admin/RelatedObjectLookups.js b/lottery/staticfiles/admin/js/admin/RelatedObjectLookups.js new file mode 100644 index 0000000..bc3acce --- /dev/null +++ b/lottery/staticfiles/admin/js/admin/RelatedObjectLookups.js @@ -0,0 +1,240 @@ +/*global SelectBox, interpolate*/ +// Handles related-objects functionality: lookup link for raw_id_fields +// and Add Another links. +'use strict'; +{ + const $ = django.jQuery; + let popupIndex = 0; + const relatedWindows = []; + + function dismissChildPopups() { + relatedWindows.forEach(function(win) { + if(!win.closed) { + win.dismissChildPopups(); + win.close(); + } + }); + } + + function setPopupIndex() { + if(document.getElementsByName("_popup").length > 0) { + const index = window.name.lastIndexOf("__") + 2; + popupIndex = parseInt(window.name.substring(index)); + } else { + popupIndex = 0; + } + } + + function addPopupIndex(name) { + return name + "__" + (popupIndex + 1); + } + + function removePopupIndex(name) { + return name.replace(new RegExp("__" + (popupIndex + 1) + "$"), ''); + } + + function showAdminPopup(triggeringLink, name_regexp, add_popup) { + const name = addPopupIndex(triggeringLink.id.replace(name_regexp, '')); + const href = new URL(triggeringLink.href); + if (add_popup) { + href.searchParams.set('_popup', 1); + } + const win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes'); + relatedWindows.push(win); + win.focus(); + return false; + } + + function showRelatedObjectLookupPopup(triggeringLink) { + return showAdminPopup(triggeringLink, /^lookup_/, true); + } + + function dismissRelatedLookupPopup(win, chosenId) { + const name = removePopupIndex(win.name); + const elem = document.getElementById(name); + if (elem.classList.contains('vManyToManyRawIdAdminField') && elem.value) { + elem.value += ',' + chosenId; + } else { + document.getElementById(name).value = chosenId; + } + const index = relatedWindows.indexOf(win); + if (index > -1) { + relatedWindows.splice(index, 1); + } + win.close(); + } + + function showRelatedObjectPopup(triggeringLink) { + return showAdminPopup(triggeringLink, /^(change|add|delete)_/, false); + } + + function updateRelatedObjectLinks(triggeringLink) { + const $this = $(triggeringLink); + const siblings = $this.nextAll('.view-related, .change-related, .delete-related'); + if (!siblings.length) { + return; + } + const value = $this.val(); + if (value) { + siblings.each(function() { + const elm = $(this); + elm.attr('href', elm.attr('data-href-template').replace('__fk__', value)); + elm.removeAttr('aria-disabled'); + }); + } else { + siblings.removeAttr('href'); + siblings.attr('aria-disabled', true); + } + } + + function updateRelatedSelectsOptions(currentSelect, win, objId, newRepr, newId) { + // After create/edit a model from the options next to the current + // select (+ or :pencil:) update ForeignKey PK of the rest of selects + // in the page. + + const path = win.location.pathname; + // Extract the model from the popup url '...//add/' or + // '...///change/' depending the action (add or change). + const modelName = path.split('/')[path.split('/').length - (objId ? 4 : 3)]; + // Select elements with a specific model reference and context of "available-source". + const selectsRelated = document.querySelectorAll(`[data-model-ref="${modelName}"] [data-context="available-source"]`); + + selectsRelated.forEach(function(select) { + if (currentSelect === select) { + return; + } + + let option = select.querySelector(`option[value="${objId}"]`); + + if (!option) { + option = new Option(newRepr, newId); + select.options.add(option); + return; + } + + option.textContent = newRepr; + option.value = newId; + }); + } + + function dismissAddRelatedObjectPopup(win, newId, newRepr) { + const name = removePopupIndex(win.name); + const elem = document.getElementById(name); + if (elem) { + const elemName = elem.nodeName.toUpperCase(); + if (elemName === 'SELECT') { + elem.options[elem.options.length] = new Option(newRepr, newId, true, true); + updateRelatedSelectsOptions(elem, win, null, newRepr, newId); + } else if (elemName === 'INPUT') { + if (elem.classList.contains('vManyToManyRawIdAdminField') && elem.value) { + elem.value += ',' + newId; + } else { + elem.value = newId; + } + } + // Trigger a change event to update related links if required. + $(elem).trigger('change'); + } else { + const toId = name + "_to"; + const o = new Option(newRepr, newId); + SelectBox.add_to_cache(toId, o); + SelectBox.redisplay(toId); + } + const index = relatedWindows.indexOf(win); + if (index > -1) { + relatedWindows.splice(index, 1); + } + win.close(); + } + + function dismissChangeRelatedObjectPopup(win, objId, newRepr, newId) { + const id = removePopupIndex(win.name.replace(/^edit_/, '')); + const selectsSelector = interpolate('#%s, #%s_from, #%s_to', [id, id, id]); + const selects = $(selectsSelector); + selects.find('option').each(function() { + if (this.value === objId) { + this.textContent = newRepr; + this.value = newId; + } + }).trigger('change'); + updateRelatedSelectsOptions(selects[0], win, objId, newRepr, newId); + selects.next().find('.select2-selection__rendered').each(function() { + // The element can have a clear button as a child. + // Use the lastChild to modify only the displayed value. + this.lastChild.textContent = newRepr; + this.title = newRepr; + }); + const index = relatedWindows.indexOf(win); + if (index > -1) { + relatedWindows.splice(index, 1); + } + win.close(); + } + + function dismissDeleteRelatedObjectPopup(win, objId) { + const id = removePopupIndex(win.name.replace(/^delete_/, '')); + const selectsSelector = interpolate('#%s, #%s_from, #%s_to', [id, id, id]); + const selects = $(selectsSelector); + selects.find('option').each(function() { + if (this.value === objId) { + $(this).remove(); + } + }).trigger('change'); + const index = relatedWindows.indexOf(win); + if (index > -1) { + relatedWindows.splice(index, 1); + } + win.close(); + } + + window.showRelatedObjectLookupPopup = showRelatedObjectLookupPopup; + window.dismissRelatedLookupPopup = dismissRelatedLookupPopup; + window.showRelatedObjectPopup = showRelatedObjectPopup; + window.updateRelatedObjectLinks = updateRelatedObjectLinks; + window.dismissAddRelatedObjectPopup = dismissAddRelatedObjectPopup; + window.dismissChangeRelatedObjectPopup = dismissChangeRelatedObjectPopup; + window.dismissDeleteRelatedObjectPopup = dismissDeleteRelatedObjectPopup; + window.dismissChildPopups = dismissChildPopups; + + // Kept for backward compatibility + window.showAddAnotherPopup = showRelatedObjectPopup; + window.dismissAddAnotherPopup = dismissAddRelatedObjectPopup; + + window.addEventListener('unload', function(evt) { + window.dismissChildPopups(); + }); + + $(document).ready(function() { + setPopupIndex(); + $("a[data-popup-opener]").on('click', function(event) { + event.preventDefault(); + opener.dismissRelatedLookupPopup(window, $(this).data("popup-opener")); + }); + $('body').on('click', '.related-widget-wrapper-link[data-popup="yes"]', function(e) { + e.preventDefault(); + if (this.href) { + const event = $.Event('django:show-related', {href: this.href}); + $(this).trigger(event); + if (!event.isDefaultPrevented()) { + showRelatedObjectPopup(this); + } + } + }); + $('body').on('change', '.related-widget-wrapper select', function(e) { + const event = $.Event('django:update-related'); + $(this).trigger(event); + if (!event.isDefaultPrevented()) { + updateRelatedObjectLinks(this); + } + }); + $('.related-widget-wrapper select').trigger('change'); + $('body').on('click', '.related-lookup', function(e) { + e.preventDefault(); + const event = $.Event('django:lookup-related'); + $(this).trigger(event); + if (!event.isDefaultPrevented()) { + showRelatedObjectLookupPopup(this); + } + }); + }); +} diff --git a/lottery/staticfiles/admin/js/autocomplete.js b/lottery/staticfiles/admin/js/autocomplete.js new file mode 100644 index 0000000..d3daeab --- /dev/null +++ b/lottery/staticfiles/admin/js/autocomplete.js @@ -0,0 +1,33 @@ +'use strict'; +{ + const $ = django.jQuery; + + $.fn.djangoAdminSelect2 = function() { + $.each(this, function(i, element) { + $(element).select2({ + ajax: { + data: (params) => { + return { + term: params.term, + page: params.page, + app_label: element.dataset.appLabel, + model_name: element.dataset.modelName, + field_name: element.dataset.fieldName + }; + } + } + }); + }); + return this; + }; + + $(function() { + // Initialize all autocomplete widgets except the one in the template + // form used when a new formset is added. + $('.admin-autocomplete').not('[name*=__prefix__]').djangoAdminSelect2(); + }); + + document.addEventListener('formset:added', (event) => { + $(event.target).find('.admin-autocomplete').djangoAdminSelect2(); + }); +} diff --git a/lottery/staticfiles/admin/js/calendar.js b/lottery/staticfiles/admin/js/calendar.js new file mode 100644 index 0000000..776310f --- /dev/null +++ b/lottery/staticfiles/admin/js/calendar.js @@ -0,0 +1,239 @@ +/*global gettext, pgettext, get_format, quickElement, removeChildren*/ +/* +calendar.js - Calendar functions by Adrian Holovaty +depends on core.js for utility functions like removeChildren or quickElement +*/ +'use strict'; +{ + // CalendarNamespace -- Provides a collection of HTML calendar-related helper functions + const CalendarNamespace = { + monthsOfYear: [ + gettext('January'), + gettext('February'), + gettext('March'), + gettext('April'), + gettext('May'), + gettext('June'), + gettext('July'), + gettext('August'), + gettext('September'), + gettext('October'), + gettext('November'), + gettext('December') + ], + monthsOfYearAbbrev: [ + pgettext('abbrev. month January', 'Jan'), + pgettext('abbrev. month February', 'Feb'), + pgettext('abbrev. month March', 'Mar'), + pgettext('abbrev. month April', 'Apr'), + pgettext('abbrev. month May', 'May'), + pgettext('abbrev. month June', 'Jun'), + pgettext('abbrev. month July', 'Jul'), + pgettext('abbrev. month August', 'Aug'), + pgettext('abbrev. month September', 'Sep'), + pgettext('abbrev. month October', 'Oct'), + pgettext('abbrev. month November', 'Nov'), + pgettext('abbrev. month December', 'Dec') + ], + daysOfWeek: [ + gettext('Sunday'), + gettext('Monday'), + gettext('Tuesday'), + gettext('Wednesday'), + gettext('Thursday'), + gettext('Friday'), + gettext('Saturday') + ], + daysOfWeekAbbrev: [ + pgettext('abbrev. day Sunday', 'Sun'), + pgettext('abbrev. day Monday', 'Mon'), + pgettext('abbrev. day Tuesday', 'Tue'), + pgettext('abbrev. day Wednesday', 'Wed'), + pgettext('abbrev. day Thursday', 'Thur'), + pgettext('abbrev. day Friday', 'Fri'), + pgettext('abbrev. day Saturday', 'Sat') + ], + daysOfWeekInitial: [ + pgettext('one letter Sunday', 'S'), + pgettext('one letter Monday', 'M'), + pgettext('one letter Tuesday', 'T'), + pgettext('one letter Wednesday', 'W'), + pgettext('one letter Thursday', 'T'), + pgettext('one letter Friday', 'F'), + pgettext('one letter Saturday', 'S') + ], + firstDayOfWeek: parseInt(get_format('FIRST_DAY_OF_WEEK')), + isLeapYear: function(year) { + return (((year % 4) === 0) && ((year % 100) !== 0 ) || ((year % 400) === 0)); + }, + getDaysInMonth: function(month, year) { + let days; + if (month === 1 || month === 3 || month === 5 || month === 7 || month === 8 || month === 10 || month === 12) { + days = 31; + } + else if (month === 4 || month === 6 || month === 9 || month === 11) { + days = 30; + } + else if (month === 2 && CalendarNamespace.isLeapYear(year)) { + days = 29; + } + else { + days = 28; + } + return days; + }, + draw: function(month, year, div_id, callback, selected) { // month = 1-12, year = 1-9999 + const today = new Date(); + const todayDay = today.getDate(); + const todayMonth = today.getMonth() + 1; + const todayYear = today.getFullYear(); + let todayClass = ''; + + // Use UTC functions here because the date field does not contain time + // and using the UTC function variants prevent the local time offset + // from altering the date, specifically the day field. For example: + // + // ``` + // var x = new Date('2013-10-02'); + // var day = x.getDate(); + // ``` + // + // The day variable above will be 1 instead of 2 in, say, US Pacific time + // zone. + let isSelectedMonth = false; + if (typeof selected !== 'undefined') { + isSelectedMonth = (selected.getUTCFullYear() === year && (selected.getUTCMonth() + 1) === month); + } + + month = parseInt(month); + year = parseInt(year); + const calDiv = document.getElementById(div_id); + removeChildren(calDiv); + const calTable = document.createElement('table'); + quickElement('caption', calTable, CalendarNamespace.monthsOfYear[month - 1] + ' ' + year); + const tableBody = quickElement('tbody', calTable); + + // Draw days-of-week header + let tableRow = quickElement('tr', tableBody); + for (let i = 0; i < 7; i++) { + quickElement('th', tableRow, CalendarNamespace.daysOfWeekInitial[(i + CalendarNamespace.firstDayOfWeek) % 7]); + } + + const startingPos = new Date(year, month - 1, 1 - CalendarNamespace.firstDayOfWeek).getDay(); + const days = CalendarNamespace.getDaysInMonth(month, year); + + let nonDayCell; + + // Draw blanks before first of month + tableRow = quickElement('tr', tableBody); + for (let i = 0; i < startingPos; i++) { + nonDayCell = quickElement('td', tableRow, ' '); + nonDayCell.className = "nonday"; + } + + function calendarMonth(y, m) { + function onClick(e) { + e.preventDefault(); + callback(y, m, this.textContent); + } + return onClick; + } + + // Draw days of month + let currentDay = 1; + for (let i = startingPos; currentDay <= days; i++) { + if (i % 7 === 0 && currentDay !== 1) { + tableRow = quickElement('tr', tableBody); + } + if ((currentDay === todayDay) && (month === todayMonth) && (year === todayYear)) { + todayClass = 'today'; + } else { + todayClass = ''; + } + + // use UTC function; see above for explanation. + if (isSelectedMonth && currentDay === selected.getUTCDate()) { + if (todayClass !== '') { + todayClass += " "; + } + todayClass += "selected"; + } + + const cell = quickElement('td', tableRow, '', 'class', todayClass); + const link = quickElement('a', cell, currentDay, 'href', '#'); + link.addEventListener('click', calendarMonth(year, month)); + currentDay++; + } + + // Draw blanks after end of month (optional, but makes for valid code) + while (tableRow.childNodes.length < 7) { + nonDayCell = quickElement('td', tableRow, ' '); + nonDayCell.className = "nonday"; + } + + calDiv.appendChild(calTable); + } + }; + + // Calendar -- A calendar instance + function Calendar(div_id, callback, selected) { + // div_id (string) is the ID of the element in which the calendar will + // be displayed + // callback (string) is the name of a JavaScript function that will be + // called with the parameters (year, month, day) when a day in the + // calendar is clicked + this.div_id = div_id; + this.callback = callback; + this.today = new Date(); + this.currentMonth = this.today.getMonth() + 1; + this.currentYear = this.today.getFullYear(); + if (typeof selected !== 'undefined') { + this.selected = selected; + } + } + Calendar.prototype = { + drawCurrent: function() { + CalendarNamespace.draw(this.currentMonth, this.currentYear, this.div_id, this.callback, this.selected); + }, + drawDate: function(month, year, selected) { + this.currentMonth = month; + this.currentYear = year; + + if(selected) { + this.selected = selected; + } + + this.drawCurrent(); + }, + drawPreviousMonth: function() { + if (this.currentMonth === 1) { + this.currentMonth = 12; + this.currentYear--; + } + else { + this.currentMonth--; + } + this.drawCurrent(); + }, + drawNextMonth: function() { + if (this.currentMonth === 12) { + this.currentMonth = 1; + this.currentYear++; + } + else { + this.currentMonth++; + } + this.drawCurrent(); + }, + drawPreviousYear: function() { + this.currentYear--; + this.drawCurrent(); + }, + drawNextYear: function() { + this.currentYear++; + this.drawCurrent(); + } + }; + window.Calendar = Calendar; + window.CalendarNamespace = CalendarNamespace; +} diff --git a/lottery/staticfiles/admin/js/cancel.js b/lottery/staticfiles/admin/js/cancel.js new file mode 100644 index 0000000..94e5926 --- /dev/null +++ b/lottery/staticfiles/admin/js/cancel.js @@ -0,0 +1,17 @@ +(function($) { + 'use strict'; + + $(document).ready(function() { + $('.cancel-link').click(function(e) { + e.preventDefault(); + const parentWindow = window.parent; + if (parentWindow && typeof(parentWindow.dismissRelatedObjectModal) === 'function' && parentWindow !== window) { + parentWindow.dismissRelatedObjectModal(); + } else { + // fallback to default behavior + window.history.back(); + } + return false; + }); + }); +})(django.jQuery); diff --git a/lottery/staticfiles/admin/js/change_form.js b/lottery/staticfiles/admin/js/change_form.js new file mode 100644 index 0000000..96a4c62 --- /dev/null +++ b/lottery/staticfiles/admin/js/change_form.js @@ -0,0 +1,16 @@ +'use strict'; +{ + const inputTags = ['BUTTON', 'INPUT', 'SELECT', 'TEXTAREA']; + const modelName = document.getElementById('django-admin-form-add-constants').dataset.modelName; + if (modelName) { + const form = document.getElementById(modelName + '_form'); + for (const element of form.elements) { + // HTMLElement.offsetParent returns null when the element is not + // rendered. + if (inputTags.includes(element.tagName) && !element.disabled && element.offsetParent) { + element.focus(); + break; + } + } + } +} diff --git a/lottery/staticfiles/admin/js/core.js b/lottery/staticfiles/admin/js/core.js new file mode 100644 index 0000000..10504d4 --- /dev/null +++ b/lottery/staticfiles/admin/js/core.js @@ -0,0 +1,184 @@ +// Core JavaScript helper functions +'use strict'; + +// quickElement(tagType, parentReference [, textInChildNode, attribute, attributeValue ...]); +function quickElement() { + const obj = document.createElement(arguments[0]); + if (arguments[2]) { + const textNode = document.createTextNode(arguments[2]); + obj.appendChild(textNode); + } + const len = arguments.length; + for (let i = 3; i < len; i += 2) { + obj.setAttribute(arguments[i], arguments[i + 1]); + } + arguments[1].appendChild(obj); + return obj; +} + +// "a" is reference to an object +function removeChildren(a) { + while (a.hasChildNodes()) { + a.removeChild(a.lastChild); + } +} + +// ---------------------------------------------------------------------------- +// Find-position functions by PPK +// See https://www.quirksmode.org/js/findpos.html +// ---------------------------------------------------------------------------- +function findPosX(obj) { + let curleft = 0; + if (obj.offsetParent) { + while (obj.offsetParent) { + curleft += obj.offsetLeft - obj.scrollLeft; + obj = obj.offsetParent; + } + } else if (obj.x) { + curleft += obj.x; + } + return curleft; +} + +function findPosY(obj) { + let curtop = 0; + if (obj.offsetParent) { + while (obj.offsetParent) { + curtop += obj.offsetTop - obj.scrollTop; + obj = obj.offsetParent; + } + } else if (obj.y) { + curtop += obj.y; + } + return curtop; +} + +//----------------------------------------------------------------------------- +// Date object extensions +// ---------------------------------------------------------------------------- +{ + Date.prototype.getTwelveHours = function() { + return this.getHours() % 12 || 12; + }; + + Date.prototype.getTwoDigitMonth = function() { + return (this.getMonth() < 9) ? '0' + (this.getMonth() + 1) : (this.getMonth() + 1); + }; + + Date.prototype.getTwoDigitDate = function() { + return (this.getDate() < 10) ? '0' + this.getDate() : this.getDate(); + }; + + Date.prototype.getTwoDigitTwelveHour = function() { + return (this.getTwelveHours() < 10) ? '0' + this.getTwelveHours() : this.getTwelveHours(); + }; + + Date.prototype.getTwoDigitHour = function() { + return (this.getHours() < 10) ? '0' + this.getHours() : this.getHours(); + }; + + Date.prototype.getTwoDigitMinute = function() { + return (this.getMinutes() < 10) ? '0' + this.getMinutes() : this.getMinutes(); + }; + + Date.prototype.getTwoDigitSecond = function() { + return (this.getSeconds() < 10) ? '0' + this.getSeconds() : this.getSeconds(); + }; + + Date.prototype.getAbbrevDayName = function() { + return typeof window.CalendarNamespace === "undefined" + ? '0' + this.getDay() + : window.CalendarNamespace.daysOfWeekAbbrev[this.getDay()]; + }; + + Date.prototype.getFullDayName = function() { + return typeof window.CalendarNamespace === "undefined" + ? '0' + this.getDay() + : window.CalendarNamespace.daysOfWeek[this.getDay()]; + }; + + Date.prototype.getAbbrevMonthName = function() { + return typeof window.CalendarNamespace === "undefined" + ? this.getTwoDigitMonth() + : window.CalendarNamespace.monthsOfYearAbbrev[this.getMonth()]; + }; + + Date.prototype.getFullMonthName = function() { + return typeof window.CalendarNamespace === "undefined" + ? this.getTwoDigitMonth() + : window.CalendarNamespace.monthsOfYear[this.getMonth()]; + }; + + Date.prototype.strftime = function(format) { + const fields = { + a: this.getAbbrevDayName(), + A: this.getFullDayName(), + b: this.getAbbrevMonthName(), + B: this.getFullMonthName(), + c: this.toString(), + d: this.getTwoDigitDate(), + H: this.getTwoDigitHour(), + I: this.getTwoDigitTwelveHour(), + m: this.getTwoDigitMonth(), + M: this.getTwoDigitMinute(), + p: (this.getHours() >= 12) ? 'PM' : 'AM', + S: this.getTwoDigitSecond(), + w: '0' + this.getDay(), + x: this.toLocaleDateString(), + X: this.toLocaleTimeString(), + y: ('' + this.getFullYear()).substr(2, 4), + Y: '' + this.getFullYear(), + '%': '%' + }; + let result = '', i = 0; + while (i < format.length) { + if (format.charAt(i) === '%') { + result += fields[format.charAt(i + 1)]; + ++i; + } + else { + result += format.charAt(i); + } + ++i; + } + return result; + }; + + // ---------------------------------------------------------------------------- + // String object extensions + // ---------------------------------------------------------------------------- + String.prototype.strptime = function(format) { + const split_format = format.split(/[.\-/]/); + const date = this.split(/[.\-/]/); + let i = 0; + let day, month, year; + while (i < split_format.length) { + switch (split_format[i]) { + case "%d": + day = date[i]; + break; + case "%m": + month = date[i] - 1; + break; + case "%Y": + year = date[i]; + break; + case "%y": + // A %y value in the range of [00, 68] is in the current + // century, while [69, 99] is in the previous century, + // according to the Open Group Specification. + if (parseInt(date[i], 10) >= 69) { + year = date[i]; + } else { + year = (new Date(Date.UTC(date[i], 0))).getUTCFullYear() + 100; + } + break; + } + ++i; + } + // Create Date object from UTC since the parsed value is supposed to be + // in UTC, not local time. Also, the calendar uses UTC functions for + // date extraction. + return new Date(Date.UTC(year, month, day)); + }; +} diff --git a/lottery/staticfiles/admin/js/filters.js b/lottery/staticfiles/admin/js/filters.js new file mode 100644 index 0000000..f5536eb --- /dev/null +++ b/lottery/staticfiles/admin/js/filters.js @@ -0,0 +1,30 @@ +/** + * Persist changelist filters state (collapsed/expanded). + */ +'use strict'; +{ + // Init filters. + let filters = JSON.parse(sessionStorage.getItem('django.admin.filtersState')); + + if (!filters) { + filters = {}; + } + + Object.entries(filters).forEach(([key, value]) => { + const detailElement = document.querySelector(`[data-filter-title='${CSS.escape(key)}']`); + + // Check if the filter is present, it could be from other view. + if (detailElement) { + value ? detailElement.setAttribute('open', '') : detailElement.removeAttribute('open'); + } + }); + + // Save filter state when clicks. + const details = document.querySelectorAll('details'); + details.forEach(detail => { + detail.addEventListener('toggle', event => { + filters[`${event.target.dataset.filterTitle}`] = detail.open; + sessionStorage.setItem('django.admin.filtersState', JSON.stringify(filters)); + }); + }); +} diff --git a/lottery/staticfiles/admin/js/inlines.js b/lottery/staticfiles/admin/js/inlines.js new file mode 100644 index 0000000..e9a1dfe --- /dev/null +++ b/lottery/staticfiles/admin/js/inlines.js @@ -0,0 +1,359 @@ +/*global DateTimeShortcuts, SelectFilter*/ +/** + * Django admin inlines + * + * Based on jQuery Formset 1.1 + * @author Stanislaus Madueke (stan DOT madueke AT gmail DOT com) + * @requires jQuery 1.2.6 or later + * + * Copyright (c) 2009, Stanislaus Madueke + * All rights reserved. + * + * Spiced up with Code from Zain Memon's GSoC project 2009 + * and modified for Django by Jannis Leidel, Travis Swicegood and Julien Phalip. + * + * Licensed under the New BSD License + * See: https://opensource.org/licenses/bsd-license.php + */ +'use strict'; +{ + const $ = django.jQuery; + $.fn.formset = function(opts) { + const options = $.extend({}, $.fn.formset.defaults, opts); + const $this = $(this); + const $parent = $this.parent(); + const updateElementIndex = function(el, prefix, ndx) { + const id_regex = new RegExp("(" + prefix + "-(\\d+|__prefix__))"); + const replacement = prefix + "-" + ndx; + if ($(el).prop("for")) { + $(el).prop("for", $(el).prop("for").replace(id_regex, replacement)); + } + if (el.id) { + el.id = el.id.replace(id_regex, replacement); + } + if (el.name) { + el.name = el.name.replace(id_regex, replacement); + } + }; + const totalForms = $("#id_" + options.prefix + "-TOTAL_FORMS").prop("autocomplete", "off"); + let nextIndex = parseInt(totalForms.val(), 10); + const maxForms = $("#id_" + options.prefix + "-MAX_NUM_FORMS").prop("autocomplete", "off"); + const minForms = $("#id_" + options.prefix + "-MIN_NUM_FORMS").prop("autocomplete", "off"); + let addButton; + + /** + * The "Add another MyModel" button below the inline forms. + */ + const addInlineAddButton = function() { + if (addButton === null) { + if ($this.prop("tagName") === "TR") { + // If forms are laid out as table rows, insert the + // "add" button in a new table row: + const numCols = $this.eq(-1).children().length; + $parent.append('' + options.addText + ""); + addButton = $parent.find("tr:last a"); + } else { + // Otherwise, insert it immediately after the last form: + $this.filter(":last").after('"); + addButton = $this.filter(":last").next().find("a"); + } + } + addButton.on('click', addInlineClickHandler); + }; + + const addInlineClickHandler = function(e) { + e.preventDefault(); + const template = $("#" + options.prefix + "-empty"); + const row = template.clone(true); + row.removeClass(options.emptyCssClass) + .addClass(options.formCssClass) + .attr("id", options.prefix + "-" + nextIndex); + addInlineDeleteButton(row); + row.find("*").each(function() { + updateElementIndex(this, options.prefix, totalForms.val()); + }); + // Insert the new form when it has been fully edited. + row.insertBefore($(template)); + // Update number of total forms. + $(totalForms).val(parseInt(totalForms.val(), 10) + 1); + nextIndex += 1; + // Hide the add button if there's a limit and it's been reached. + if ((maxForms.val() !== '') && (maxForms.val() - totalForms.val()) <= 0) { + addButton.parent().hide(); + } + // Show the remove buttons if there are more than min_num. + toggleDeleteButtonVisibility(row.closest('.inline-group')); + + // Pass the new form to the post-add callback, if provided. + if (options.added) { + options.added(row); + } + row.get(0).dispatchEvent(new CustomEvent("formset:added", { + bubbles: true, + detail: { + formsetName: options.prefix + } + })); + }; + + /** + * The "X" button that is part of every unsaved inline. + * (When saved, it is replaced with a "Delete" checkbox.) + */ + const addInlineDeleteButton = function(row) { + if (row.is("tr")) { + // If the forms are laid out in table rows, insert + // the remove button into the last table cell: + row.children(":last").append('"); + } else if (row.is("ul") || row.is("ol")) { + // If they're laid out as an ordered/unordered list, + // insert an
  • after the last list item: + row.append('
  • ' + options.deleteText + "
  • "); + } else { + // Otherwise, just insert the remove button as the + // last child element of the form's container: + row.children(":first").append('' + options.deleteText + ""); + } + // Add delete handler for each row. + row.find("a." + options.deleteCssClass).on('click', inlineDeleteHandler.bind(this)); + }; + + const inlineDeleteHandler = function(e1) { + e1.preventDefault(); + const deleteButton = $(e1.target); + const row = deleteButton.closest('.' + options.formCssClass); + const inlineGroup = row.closest('.inline-group'); + // Remove the parent form containing this button, + // and also remove the relevant row with non-field errors: + const prevRow = row.prev(); + if (prevRow.length && prevRow.hasClass('row-form-errors')) { + prevRow.remove(); + } + row.remove(); + nextIndex -= 1; + // Pass the deleted form to the post-delete callback, if provided. + if (options.removed) { + options.removed(row); + } + document.dispatchEvent(new CustomEvent("formset:removed", { + detail: { + formsetName: options.prefix + } + })); + // Update the TOTAL_FORMS form count. + const forms = $("." + options.formCssClass); + $("#id_" + options.prefix + "-TOTAL_FORMS").val(forms.length); + // Show add button again once below maximum number. + if ((maxForms.val() === '') || (maxForms.val() - forms.length) > 0) { + addButton.parent().show(); + } + // Hide the remove buttons if at min_num. + toggleDeleteButtonVisibility(inlineGroup); + // Also, update names and ids for all remaining form controls so + // they remain in sequence: + let i, formCount; + const updateElementCallback = function() { + updateElementIndex(this, options.prefix, i); + }; + for (i = 0, formCount = forms.length; i < formCount; i++) { + updateElementIndex($(forms).get(i), options.prefix, i); + $(forms.get(i)).find("*").each(updateElementCallback); + } + }; + + const toggleDeleteButtonVisibility = function(inlineGroup) { + if ((minForms.val() !== '') && (minForms.val() - totalForms.val()) >= 0) { + inlineGroup.find('.inline-deletelink').hide(); + } else { + inlineGroup.find('.inline-deletelink').show(); + } + }; + + $this.each(function(i) { + $(this).not("." + options.emptyCssClass).addClass(options.formCssClass); + }); + + // Create the delete buttons for all unsaved inlines: + $this.filter('.' + options.formCssClass + ':not(.has_original):not(.' + options.emptyCssClass + ')').each(function() { + addInlineDeleteButton($(this)); + }); + toggleDeleteButtonVisibility($this); + + // Create the add button, initially hidden. + addButton = options.addButton; + addInlineAddButton(); + + // Show the add button if allowed to add more items. + // Note that max_num = None translates to a blank string. + const showAddButton = maxForms.val() === '' || (maxForms.val() - totalForms.val()) > 0; + if ($this.length && showAddButton) { + addButton.parent().show(); + } else { + addButton.parent().hide(); + } + + return this; + }; + + /* Setup plugin defaults */ + $.fn.formset.defaults = { + prefix: "form", // The form prefix for your django formset + addText: "add another", // Text for the add link + deleteText: "remove", // Text for the delete link + addCssClass: "add-row", // CSS class applied to the add link + deleteCssClass: "delete-row", // CSS class applied to the delete link + emptyCssClass: "empty-row", // CSS class applied to the empty row + formCssClass: "dynamic-form", // CSS class applied to each form in a formset + added: null, // Function called each time a new form is added + removed: null, // Function called each time a form is deleted + addButton: null // Existing add button to use + }; + + + // Tabular inlines --------------------------------------------------------- + $.fn.tabularFormset = function(selector, options) { + const $rows = $(this); + + const reinitDateTimeShortCuts = function() { + // Reinitialize the calendar and clock widgets by force + if (typeof DateTimeShortcuts !== "undefined") { + $(".datetimeshortcuts").remove(); + DateTimeShortcuts.init(); + } + }; + + const updateSelectFilter = function() { + // If any SelectFilter widgets are a part of the new form, + // instantiate a new SelectFilter instance for it. + if (typeof SelectFilter !== 'undefined') { + $('.selectfilter').each(function(index, value) { + SelectFilter.init(value.id, this.dataset.fieldName, false); + }); + $('.selectfilterstacked').each(function(index, value) { + SelectFilter.init(value.id, this.dataset.fieldName, true); + }); + } + }; + + const initPrepopulatedFields = function(row) { + row.find('.prepopulated_field').each(function() { + const field = $(this), + input = field.find('input, select, textarea'), + dependency_list = input.data('dependency_list') || [], + dependencies = []; + $.each(dependency_list, function(i, field_name) { + dependencies.push('#' + row.find('.field-' + field_name).find('input, select, textarea').attr('id')); + }); + if (dependencies.length) { + input.prepopulate(dependencies, input.attr('maxlength')); + } + }); + }; + + $rows.formset({ + prefix: options.prefix, + addText: options.addText, + formCssClass: "dynamic-" + options.prefix, + deleteCssClass: "inline-deletelink", + deleteText: options.deleteText, + emptyCssClass: "empty-form", + added: function(row) { + initPrepopulatedFields(row); + reinitDateTimeShortCuts(); + updateSelectFilter(); + }, + addButton: options.addButton + }); + + return $rows; + }; + + // Stacked inlines --------------------------------------------------------- + $.fn.stackedFormset = function(selector, options) { + const $rows = $(this); + const updateInlineLabel = function(row) { + $(selector).find(".inline_label").each(function(i) { + const count = i + 1; + $(this).html($(this).html().replace(/(#\d+)/g, "#" + count)); + }); + }; + + const reinitDateTimeShortCuts = function() { + // Reinitialize the calendar and clock widgets by force, yuck. + if (typeof DateTimeShortcuts !== "undefined") { + $(".datetimeshortcuts").remove(); + DateTimeShortcuts.init(); + } + }; + + const updateSelectFilter = function() { + // If any SelectFilter widgets were added, instantiate a new instance. + if (typeof SelectFilter !== "undefined") { + $(".selectfilter").each(function(index, value) { + SelectFilter.init(value.id, this.dataset.fieldName, false); + }); + $(".selectfilterstacked").each(function(index, value) { + SelectFilter.init(value.id, this.dataset.fieldName, true); + }); + } + }; + + const initPrepopulatedFields = function(row) { + row.find('.prepopulated_field').each(function() { + const field = $(this), + input = field.find('input, select, textarea'), + dependency_list = input.data('dependency_list') || [], + dependencies = []; + $.each(dependency_list, function(i, field_name) { + // Dependency in a fieldset. + let field_element = row.find('.form-row .field-' + field_name); + // Dependency without a fieldset. + if (!field_element.length) { + field_element = row.find('.form-row.field-' + field_name); + } + dependencies.push('#' + field_element.find('input, select, textarea').attr('id')); + }); + if (dependencies.length) { + input.prepopulate(dependencies, input.attr('maxlength')); + } + }); + }; + + $rows.formset({ + prefix: options.prefix, + addText: options.addText, + formCssClass: "dynamic-" + options.prefix, + deleteCssClass: "inline-deletelink", + deleteText: options.deleteText, + emptyCssClass: "empty-form", + removed: updateInlineLabel, + added: function(row) { + initPrepopulatedFields(row); + reinitDateTimeShortCuts(); + updateSelectFilter(); + updateInlineLabel(row); + }, + addButton: options.addButton + }); + + return $rows; + }; + + $(document).ready(function() { + $(".js-inline-admin-formset").each(function() { + const data = $(this).data(), + inlineOptions = data.inlineFormset; + let selector; + switch(data.inlineType) { + case "stacked": + selector = inlineOptions.name + "-group .inline-related"; + $(selector).stackedFormset(selector, inlineOptions.options); + break; + case "tabular": + selector = inlineOptions.name + "-group .tabular.inline-related tbody:first > tr.form-row"; + $(selector).tabularFormset(selector, inlineOptions.options); + break; + } + }); + }); +} diff --git a/lottery/staticfiles/admin/js/jquery.init.js b/lottery/staticfiles/admin/js/jquery.init.js new file mode 100644 index 0000000..f40b27f --- /dev/null +++ b/lottery/staticfiles/admin/js/jquery.init.js @@ -0,0 +1,8 @@ +/*global jQuery:false*/ +'use strict'; +/* Puts the included jQuery into our own namespace using noConflict and passing + * it 'true'. This ensures that the included jQuery doesn't pollute the global + * namespace (i.e. this preserves pre-existing values for both window.$ and + * window.jQuery). + */ +window.django = {jQuery: jQuery.noConflict(true)}; diff --git a/lottery/staticfiles/admin/js/nav_sidebar.js b/lottery/staticfiles/admin/js/nav_sidebar.js new file mode 100644 index 0000000..7e735db --- /dev/null +++ b/lottery/staticfiles/admin/js/nav_sidebar.js @@ -0,0 +1,79 @@ +'use strict'; +{ + const toggleNavSidebar = document.getElementById('toggle-nav-sidebar'); + if (toggleNavSidebar !== null) { + const navSidebar = document.getElementById('nav-sidebar'); + const main = document.getElementById('main'); + let navSidebarIsOpen = localStorage.getItem('django.admin.navSidebarIsOpen'); + if (navSidebarIsOpen === null) { + navSidebarIsOpen = 'true'; + } + main.classList.toggle('shifted', navSidebarIsOpen === 'true'); + navSidebar.setAttribute('aria-expanded', navSidebarIsOpen); + + toggleNavSidebar.addEventListener('click', function() { + if (navSidebarIsOpen === 'true') { + navSidebarIsOpen = 'false'; + } else { + navSidebarIsOpen = 'true'; + } + localStorage.setItem('django.admin.navSidebarIsOpen', navSidebarIsOpen); + main.classList.toggle('shifted'); + navSidebar.setAttribute('aria-expanded', navSidebarIsOpen); + }); + } + + function initSidebarQuickFilter() { + const options = []; + const navSidebar = document.getElementById('nav-sidebar'); + if (!navSidebar) { + return; + } + navSidebar.querySelectorAll('th[scope=row] a').forEach((container) => { + options.push({title: container.innerHTML, node: container}); + }); + + function checkValue(event) { + let filterValue = event.target.value; + if (filterValue) { + filterValue = filterValue.toLowerCase(); + } + if (event.key === 'Escape') { + filterValue = ''; + event.target.value = ''; // clear input + } + let matches = false; + for (const o of options) { + let displayValue = ''; + if (filterValue) { + if (o.title.toLowerCase().indexOf(filterValue) === -1) { + displayValue = 'none'; + } else { + matches = true; + } + } + // show/hide parent + o.node.parentNode.parentNode.style.display = displayValue; + } + if (!filterValue || matches) { + event.target.classList.remove('no-results'); + } else { + event.target.classList.add('no-results'); + } + sessionStorage.setItem('django.admin.navSidebarFilterValue', filterValue); + } + + const nav = document.getElementById('nav-filter'); + nav.addEventListener('change', checkValue, false); + nav.addEventListener('input', checkValue, false); + nav.addEventListener('keyup', checkValue, false); + + const storedValue = sessionStorage.getItem('django.admin.navSidebarFilterValue'); + if (storedValue) { + nav.value = storedValue; + checkValue({target: nav, key: ''}); + } + } + window.initSidebarQuickFilter = initSidebarQuickFilter; + initSidebarQuickFilter(); +} diff --git a/lottery/staticfiles/admin/js/popup_response.js b/lottery/staticfiles/admin/js/popup_response.js new file mode 100644 index 0000000..0256abf --- /dev/null +++ b/lottery/staticfiles/admin/js/popup_response.js @@ -0,0 +1,44 @@ +(function() { + + 'use strict'; + + var windowRef = window; + var windowRefProxy; + var windowName, widgetName; + var openerRef = windowRef.opener; + if (!openerRef) { + // related modal is active + openerRef = windowRef.parent; + windowName = windowRef.name; + widgetName = windowName.replace(/^(change|add|delete|lookup)_/, ''); + windowRefProxy = { + name: widgetName, + location: windowRef.location, + close: function() { + openerRef.dismissRelatedObjectModal(); + } + }; + windowRef = windowRefProxy; + } + + // default django popup_response.js + var initData = JSON.parse(document.getElementById('django-admin-popup-response-constants').dataset.popupResponse); + switch (initData.action) { + case 'change': + if (typeof(openerRef.dismissChangeRelatedObjectPopup) === 'function') { + openerRef.dismissChangeRelatedObjectPopup(windowRef, initData.value, initData.obj, initData.new_value); + } + break; + case 'delete': + if (typeof(openerRef.dismissDeleteRelatedObjectPopup) === 'function') { + openerRef.dismissDeleteRelatedObjectPopup(windowRef, initData.value); + } + break; + default: + if (typeof(openerRef.dismissAddRelatedObjectPopup) === 'function') { + openerRef.dismissAddRelatedObjectPopup(windowRef, initData.value, initData.obj); + } + break; + } + +})(); \ No newline at end of file diff --git a/lottery/staticfiles/admin/js/prepopulate.js b/lottery/staticfiles/admin/js/prepopulate.js new file mode 100644 index 0000000..89e95ab --- /dev/null +++ b/lottery/staticfiles/admin/js/prepopulate.js @@ -0,0 +1,43 @@ +/*global URLify*/ +'use strict'; +{ + const $ = django.jQuery; + $.fn.prepopulate = function(dependencies, maxLength, allowUnicode) { + /* + Depends on urlify.js + Populates a selected field with the values of the dependent fields, + URLifies and shortens the string. + dependencies - array of dependent fields ids + maxLength - maximum length of the URLify'd string + allowUnicode - Unicode support of the URLify'd string + */ + return this.each(function() { + const prepopulatedField = $(this); + + const populate = function() { + // Bail if the field's value has been changed by the user + if (prepopulatedField.data('_changed')) { + return; + } + + const values = []; + $.each(dependencies, function(i, field) { + field = $(field); + if (field.val().length > 0) { + values.push(field.val()); + } + }); + prepopulatedField.val(URLify(values.join(' '), maxLength, allowUnicode)); + }; + + prepopulatedField.data('_changed', false); + prepopulatedField.on('change', function() { + prepopulatedField.data('_changed', true); + }); + + if (!prepopulatedField.val()) { + $(dependencies.join(',')).on('keyup change focus', populate); + } + }); + }; +} diff --git a/lottery/staticfiles/admin/js/prepopulate_init.js b/lottery/staticfiles/admin/js/prepopulate_init.js new file mode 100644 index 0000000..a58841f --- /dev/null +++ b/lottery/staticfiles/admin/js/prepopulate_init.js @@ -0,0 +1,15 @@ +'use strict'; +{ + const $ = django.jQuery; + const fields = $('#django-admin-prepopulated-fields-constants').data('prepopulatedFields'); + $.each(fields, function(index, field) { + $( + '.empty-form .form-row .field-' + field.name + + ', .empty-form.form-row .field-' + field.name + + ', .empty-form .form-row.field-' + field.name + ).addClass('prepopulated_field'); + $(field.id).data('dependency_list', field.dependency_list).prepopulate( + field.dependency_ids, field.maxLength, field.allowUnicode + ); + }); +} diff --git a/lottery/staticfiles/admin/js/theme.js b/lottery/staticfiles/admin/js/theme.js new file mode 100644 index 0000000..e79d375 --- /dev/null +++ b/lottery/staticfiles/admin/js/theme.js @@ -0,0 +1,51 @@ +'use strict'; +{ + function setTheme(mode) { + if (mode !== "light" && mode !== "dark" && mode !== "auto") { + console.error(`Got invalid theme mode: ${mode}. Resetting to auto.`); + mode = "auto"; + } + document.documentElement.dataset.theme = mode; + localStorage.setItem("theme", mode); + } + + function cycleTheme() { + const currentTheme = localStorage.getItem("theme") || "auto"; + const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches; + + if (prefersDark) { + // Auto (dark) -> Light -> Dark + if (currentTheme === "auto") { + setTheme("light"); + } else if (currentTheme === "light") { + setTheme("dark"); + } else { + setTheme("auto"); + } + } else { + // Auto (light) -> Dark -> Light + if (currentTheme === "auto") { + setTheme("dark"); + } else if (currentTheme === "dark") { + setTheme("light"); + } else { + setTheme("auto"); + } + } + } + + function initTheme() { + // set theme defined in localStorage if there is one, or fallback to auto mode + const currentTheme = localStorage.getItem("theme"); + currentTheme ? setTheme(currentTheme) : setTheme("auto"); + } + + window.addEventListener('load', function(_) { + const buttons = document.getElementsByClassName("theme-toggle"); + Array.from(buttons).forEach((btn) => { + btn.addEventListener("click", cycleTheme); + }); + }); + + initTheme(); +} diff --git a/lottery/staticfiles/admin/js/unusable_password_field.js b/lottery/staticfiles/admin/js/unusable_password_field.js new file mode 100644 index 0000000..ec26238 --- /dev/null +++ b/lottery/staticfiles/admin/js/unusable_password_field.js @@ -0,0 +1,29 @@ +"use strict"; +// Fallback JS for browsers which do not support :has selector used in +// admin/css/unusable_password_fields.css +// Remove file once all supported browsers support :has selector +try { + // If browser does not support :has selector this will raise an error + document.querySelector("form:has(input)"); +} catch (error) { + console.log("Defaulting to javascript for usable password form management: " + error); + // JS replacement for unsupported :has selector + document.querySelectorAll('input[name="usable_password"]').forEach(option => { + option.addEventListener('change', function() { + const usablePassword = (this.value === "true" ? this.checked : !this.checked); + const submit1 = document.querySelector('input[type="submit"].set-password'); + const submit2 = document.querySelector('input[type="submit"].unset-password'); + const messages = document.querySelector('#id_unusable_warning'); + document.getElementById('id_password1').closest('.form-row').hidden = !usablePassword; + document.getElementById('id_password2').closest('.form-row').hidden = !usablePassword; + if (messages) { + messages.hidden = usablePassword; + } + if (submit1 && submit2) { + submit1.hidden = !usablePassword; + submit2.hidden = usablePassword; + } + }); + option.dispatchEvent(new Event('change')); + }); +} diff --git a/lottery/staticfiles/admin/js/urlify.js b/lottery/staticfiles/admin/js/urlify.js new file mode 100644 index 0000000..9fc0409 --- /dev/null +++ b/lottery/staticfiles/admin/js/urlify.js @@ -0,0 +1,169 @@ +/*global XRegExp*/ +'use strict'; +{ + const LATIN_MAP = { + 'À': 'A', 'Á': 'A', 'Â': 'A', 'Ã': 'A', 'Ä': 'A', 'Å': 'A', 'Æ': 'AE', + 'Ç': 'C', 'È': 'E', 'É': 'E', 'Ê': 'E', 'Ë': 'E', 'Ì': 'I', 'Í': 'I', + 'Î': 'I', 'Ï': 'I', 'Ð': 'D', 'Ñ': 'N', 'Ò': 'O', 'Ó': 'O', 'Ô': 'O', + 'Õ': 'O', 'Ö': 'O', 'Ő': 'O', 'Ø': 'O', 'Ù': 'U', 'Ú': 'U', 'Û': 'U', + 'Ü': 'U', 'Ű': 'U', 'Ý': 'Y', 'Þ': 'TH', 'Ÿ': 'Y', 'ß': 'ss', 'à': 'a', + 'á': 'a', 'â': 'a', 'ã': 'a', 'ä': 'a', 'å': 'a', 'æ': 'ae', 'ç': 'c', + 'è': 'e', 'é': 'e', 'ê': 'e', 'ë': 'e', 'ì': 'i', 'í': 'i', 'î': 'i', + 'ï': 'i', 'ð': 'd', 'ñ': 'n', 'ò': 'o', 'ó': 'o', 'ô': 'o', 'õ': 'o', + 'ö': 'o', 'ő': 'o', 'ø': 'o', 'ù': 'u', 'ú': 'u', 'û': 'u', 'ü': 'u', + 'ű': 'u', 'ý': 'y', 'þ': 'th', 'ÿ': 'y' + }; + const LATIN_SYMBOLS_MAP = { + '©': '(c)' + }; + const GREEK_MAP = { + 'α': 'a', 'β': 'b', 'γ': 'g', 'δ': 'd', 'ε': 'e', 'ζ': 'z', 'η': 'h', + 'θ': '8', 'ι': 'i', 'κ': 'k', 'λ': 'l', 'μ': 'm', 'ν': 'n', 'ξ': '3', + 'ο': 'o', 'π': 'p', 'ρ': 'r', 'σ': 's', 'τ': 't', 'υ': 'y', 'φ': 'f', + 'χ': 'x', 'ψ': 'ps', 'ω': 'w', 'ά': 'a', 'έ': 'e', 'ί': 'i', 'ό': 'o', + 'ύ': 'y', 'ή': 'h', 'ώ': 'w', 'ς': 's', 'ϊ': 'i', 'ΰ': 'y', 'ϋ': 'y', + 'ΐ': 'i', 'Α': 'A', 'Β': 'B', 'Γ': 'G', 'Δ': 'D', 'Ε': 'E', 'Ζ': 'Z', + 'Η': 'H', 'Θ': '8', 'Ι': 'I', 'Κ': 'K', 'Λ': 'L', 'Μ': 'M', 'Ν': 'N', + 'Ξ': '3', 'Ο': 'O', 'Π': 'P', 'Ρ': 'R', 'Σ': 'S', 'Τ': 'T', 'Υ': 'Y', + 'Φ': 'F', 'Χ': 'X', 'Ψ': 'PS', 'Ω': 'W', 'Ά': 'A', 'Έ': 'E', 'Ί': 'I', + 'Ό': 'O', 'Ύ': 'Y', 'Ή': 'H', 'Ώ': 'W', 'Ϊ': 'I', 'Ϋ': 'Y' + }; + const TURKISH_MAP = { + 'ş': 's', 'Ş': 'S', 'ı': 'i', 'İ': 'I', 'ç': 'c', 'Ç': 'C', 'ü': 'u', + 'Ü': 'U', 'ö': 'o', 'Ö': 'O', 'ğ': 'g', 'Ğ': 'G' + }; + const ROMANIAN_MAP = { + 'ă': 'a', 'î': 'i', 'ș': 's', 'ț': 't', 'â': 'a', + 'Ă': 'A', 'Î': 'I', 'Ș': 'S', 'Ț': 'T', 'Â': 'A' + }; + const RUSSIAN_MAP = { + 'а': 'a', 'б': 'b', 'в': 'v', 'г': 'g', 'д': 'd', 'е': 'e', 'ё': 'yo', + 'ж': 'zh', 'з': 'z', 'и': 'i', 'й': 'j', 'к': 'k', 'л': 'l', 'м': 'm', + 'н': 'n', 'о': 'o', 'п': 'p', 'р': 'r', 'с': 's', 'т': 't', 'у': 'u', + 'ф': 'f', 'х': 'h', 'ц': 'c', 'ч': 'ch', 'ш': 'sh', 'щ': 'sh', 'ъ': '', + 'ы': 'y', 'ь': '', 'э': 'e', 'ю': 'yu', 'я': 'ya', + 'А': 'A', 'Б': 'B', 'В': 'V', 'Г': 'G', 'Д': 'D', 'Е': 'E', 'Ё': 'Yo', + 'Ж': 'Zh', 'З': 'Z', 'И': 'I', 'Й': 'J', 'К': 'K', 'Л': 'L', 'М': 'M', + 'Н': 'N', 'О': 'O', 'П': 'P', 'Р': 'R', 'С': 'S', 'Т': 'T', 'У': 'U', + 'Ф': 'F', 'Х': 'H', 'Ц': 'C', 'Ч': 'Ch', 'Ш': 'Sh', 'Щ': 'Sh', 'Ъ': '', + 'Ы': 'Y', 'Ь': '', 'Э': 'E', 'Ю': 'Yu', 'Я': 'Ya' + }; + const UKRAINIAN_MAP = { + 'Є': 'Ye', 'І': 'I', 'Ї': 'Yi', 'Ґ': 'G', 'є': 'ye', 'і': 'i', + 'ї': 'yi', 'ґ': 'g' + }; + const CZECH_MAP = { + 'č': 'c', 'ď': 'd', 'ě': 'e', 'ň': 'n', 'ř': 'r', 'š': 's', 'ť': 't', + 'ů': 'u', 'ž': 'z', 'Č': 'C', 'Ď': 'D', 'Ě': 'E', 'Ň': 'N', 'Ř': 'R', + 'Š': 'S', 'Ť': 'T', 'Ů': 'U', 'Ž': 'Z' + }; + const SLOVAK_MAP = { + 'á': 'a', 'ä': 'a', 'č': 'c', 'ď': 'd', 'é': 'e', 'í': 'i', 'ľ': 'l', + 'ĺ': 'l', 'ň': 'n', 'ó': 'o', 'ô': 'o', 'ŕ': 'r', 'š': 's', 'ť': 't', + 'ú': 'u', 'ý': 'y', 'ž': 'z', + 'Á': 'a', 'Ä': 'A', 'Č': 'C', 'Ď': 'D', 'É': 'E', 'Í': 'I', 'Ľ': 'L', + 'Ĺ': 'L', 'Ň': 'N', 'Ó': 'O', 'Ô': 'O', 'Ŕ': 'R', 'Š': 'S', 'Ť': 'T', + 'Ú': 'U', 'Ý': 'Y', 'Ž': 'Z' + }; + const POLISH_MAP = { + 'ą': 'a', 'ć': 'c', 'ę': 'e', 'ł': 'l', 'ń': 'n', 'ó': 'o', 'ś': 's', + 'ź': 'z', 'ż': 'z', + 'Ą': 'A', 'Ć': 'C', 'Ę': 'E', 'Ł': 'L', 'Ń': 'N', 'Ó': 'O', 'Ś': 'S', + 'Ź': 'Z', 'Ż': 'Z' + }; + const LATVIAN_MAP = { + 'ā': 'a', 'č': 'c', 'ē': 'e', 'ģ': 'g', 'ī': 'i', 'ķ': 'k', 'ļ': 'l', + 'ņ': 'n', 'š': 's', 'ū': 'u', 'ž': 'z', + 'Ā': 'A', 'Č': 'C', 'Ē': 'E', 'Ģ': 'G', 'Ī': 'I', 'Ķ': 'K', 'Ļ': 'L', + 'Ņ': 'N', 'Š': 'S', 'Ū': 'U', 'Ž': 'Z' + }; + const ARABIC_MAP = { + 'أ': 'a', 'ب': 'b', 'ت': 't', 'ث': 'th', 'ج': 'g', 'ح': 'h', 'خ': 'kh', 'د': 'd', + 'ذ': 'th', 'ر': 'r', 'ز': 'z', 'س': 's', 'ش': 'sh', 'ص': 's', 'ض': 'd', 'ط': 't', + 'ظ': 'th', 'ع': 'aa', 'غ': 'gh', 'ف': 'f', 'ق': 'k', 'ك': 'k', 'ل': 'l', 'م': 'm', + 'ن': 'n', 'ه': 'h', 'و': 'o', 'ي': 'y' + }; + const LITHUANIAN_MAP = { + 'ą': 'a', 'č': 'c', 'ę': 'e', 'ė': 'e', 'į': 'i', 'š': 's', 'ų': 'u', + 'ū': 'u', 'ž': 'z', + 'Ą': 'A', 'Č': 'C', 'Ę': 'E', 'Ė': 'E', 'Į': 'I', 'Š': 'S', 'Ų': 'U', + 'Ū': 'U', 'Ž': 'Z' + }; + const SERBIAN_MAP = { + 'ђ': 'dj', 'ј': 'j', 'љ': 'lj', 'њ': 'nj', 'ћ': 'c', 'џ': 'dz', + 'đ': 'dj', 'Ђ': 'Dj', 'Ј': 'j', 'Љ': 'Lj', 'Њ': 'Nj', 'Ћ': 'C', + 'Џ': 'Dz', 'Đ': 'Dj' + }; + const AZERBAIJANI_MAP = { + 'ç': 'c', 'ə': 'e', 'ğ': 'g', 'ı': 'i', 'ö': 'o', 'ş': 's', 'ü': 'u', + 'Ç': 'C', 'Ə': 'E', 'Ğ': 'G', 'İ': 'I', 'Ö': 'O', 'Ş': 'S', 'Ü': 'U' + }; + const GEORGIAN_MAP = { + 'ა': 'a', 'ბ': 'b', 'გ': 'g', 'დ': 'd', 'ე': 'e', 'ვ': 'v', 'ზ': 'z', + 'თ': 't', 'ი': 'i', 'კ': 'k', 'ლ': 'l', 'მ': 'm', 'ნ': 'n', 'ო': 'o', + 'პ': 'p', 'ჟ': 'j', 'რ': 'r', 'ს': 's', 'ტ': 't', 'უ': 'u', 'ფ': 'f', + 'ქ': 'q', 'ღ': 'g', 'ყ': 'y', 'შ': 'sh', 'ჩ': 'ch', 'ც': 'c', 'ძ': 'dz', + 'წ': 'w', 'ჭ': 'ch', 'ხ': 'x', 'ჯ': 'j', 'ჰ': 'h' + }; + + const ALL_DOWNCODE_MAPS = [ + LATIN_MAP, + LATIN_SYMBOLS_MAP, + GREEK_MAP, + TURKISH_MAP, + ROMANIAN_MAP, + RUSSIAN_MAP, + UKRAINIAN_MAP, + CZECH_MAP, + SLOVAK_MAP, + POLISH_MAP, + LATVIAN_MAP, + ARABIC_MAP, + LITHUANIAN_MAP, + SERBIAN_MAP, + AZERBAIJANI_MAP, + GEORGIAN_MAP + ]; + + const Downcoder = { + 'Initialize': function() { + if (Downcoder.map) { // already made + return; + } + Downcoder.map = {}; + for (const lookup of ALL_DOWNCODE_MAPS) { + Object.assign(Downcoder.map, lookup); + } + Downcoder.regex = new RegExp(Object.keys(Downcoder.map).join('|'), 'g'); + } + }; + + function downcode(slug) { + Downcoder.Initialize(); + return slug.replace(Downcoder.regex, function(m) { + return Downcoder.map[m]; + }); + } + + + function URLify(s, num_chars, allowUnicode) { + // changes, e.g., "Petty theft" to "petty-theft" + if (!allowUnicode) { + s = downcode(s); + } + s = s.toLowerCase(); // convert to lowercase + // if downcode doesn't hit, the char will be stripped here + if (allowUnicode) { + // Keep Unicode letters including both lowercase and uppercase + // characters, whitespace, and dash; remove other characters. + s = XRegExp.replace(s, XRegExp('[^-_\\p{L}\\p{N}\\s]', 'g'), ''); + } else { + s = s.replace(/[^-\w\s]/g, ''); // remove unneeded chars + } + s = s.replace(/^\s+|\s+$/g, ''); // trim leading/trailing spaces + s = s.replace(/[-\s]+/g, '-'); // convert spaces to hyphens + s = s.substring(0, num_chars); // trim to first num_chars chars + return s.replace(/-+$/g, ''); // trim any trailing hyphens + } + window.URLify = URLify; +} diff --git a/lottery/staticfiles/admin/js/vendor/jquery/LICENSE.txt b/lottery/staticfiles/admin/js/vendor/jquery/LICENSE.txt new file mode 100644 index 0000000..f642c3f --- /dev/null +++ b/lottery/staticfiles/admin/js/vendor/jquery/LICENSE.txt @@ -0,0 +1,20 @@ +Copyright OpenJS Foundation and other contributors, https://openjsf.org/ + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/lottery/staticfiles/admin/js/vendor/jquery/jquery.js b/lottery/staticfiles/admin/js/vendor/jquery/jquery.js new file mode 100644 index 0000000..1a86433 --- /dev/null +++ b/lottery/staticfiles/admin/js/vendor/jquery/jquery.js @@ -0,0 +1,10716 @@ +/*! + * jQuery JavaScript Library v3.7.1 + * https://jquery.com/ + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + * + * Date: 2023-08-28T13:37Z + */ +( function( global, factory ) { + + "use strict"; + + if ( typeof module === "object" && typeof module.exports === "object" ) { + + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket trac-14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 +// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode +// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common +// enough that all such attempts are guarded in a try block. +"use strict"; + +var arr = []; + +var getProto = Object.getPrototypeOf; + +var slice = arr.slice; + +var flat = arr.flat ? function( array ) { + return arr.flat.call( array ); +} : function( array ) { + return arr.concat.apply( [], array ); +}; + + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var fnToString = hasOwn.toString; + +var ObjectFunctionString = fnToString.call( Object ); + +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. + // 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 ) { + return obj != null && obj === obj.window; + }; + + +var document = window.document; + + + + var preservedScriptAttributes = { + type: true, + src: true, + nonce: true, + noModule: true + }; + + function DOMEval( code, node, doc ) { + doc = doc || document; + + var i, val, + script = doc.createElement( "script" ); + + script.text = code; + if ( node ) { + for ( i in preservedScriptAttributes ) { + + // Support: Firefox 64+, Edge 18+ + // Some browsers don't support the "nonce" property on scripts. + // On the other hand, just using `getAttribute` is not enough as + // the `nonce` attribute is reset to an empty string whenever it + // becomes browsing-context connected. + // See https://github.com/whatwg/html/issues/2369 + // See https://html.spec.whatwg.org/#nonce-attributes + // The `node.getAttribute` check was added for the sake of + // `jQuery.globalEval` so that it can fake a nonce-containing node + // via an object. + val = node[ i ] || node.getAttribute && node.getAttribute( i ); + if ( val ) { + script.setAttribute( i, val ); + } + } + } + doc.head.appendChild( script ).parentNode.removeChild( script ); + } + + +function toType( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; +} +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + + + +var version = "3.7.1", + + rhtmlSuffix = /HTML$/i, + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } + + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + even: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return ( i + 1 ) % 2; + } ) ); + }, + + odd: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return i % 2; + } ) ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + copy = options[ name ]; + + // Prevent Object.prototype pollution + // Prevent never-ending loop + if ( name === "__proto__" || target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = Array.isArray( copy ) ) ) ) { + src = target[ name ]; + + // Ensure proper type for the source value + if ( copyIsArray && !Array.isArray( src ) ) { + clone = []; + } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) { + clone = {}; + } else { + clone = src; + } + copyIsArray = false; + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + // Evaluates a script in a provided context; falls back to the global one + // if not specified. + globalEval: function( code, options, doc ) { + DOMEval( code, { nonce: options && options.nonce }, doc ); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + + // Retrieve the text value of an array of DOM nodes + text: function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + + // If no nodeType, this is expected to be an array + while ( ( node = elem[ i++ ] ) ) { + + // Do not traverse comment nodes + ret += jQuery.text( node ); + } + } + if ( nodeType === 1 || nodeType === 11 ) { + return elem.textContent; + } + if ( nodeType === 9 ) { + return elem.documentElement.textContent; + } + if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + + // Do not include comment or processing instruction nodes + + return ret; + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + isXMLDoc: function( elem ) { + var namespace = elem && elem.namespaceURI, + docElem = elem && ( elem.ownerDocument || elem ).documentElement; + + // Assume HTML when documentElement doesn't yet exist, such as inside + // document fragments. + return !rhtmlSuffix.test( namespace || docElem && docElem.nodeName || "HTML" ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return flat( ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// 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 isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = toType( obj ); + + if ( isFunction( obj ) || isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} + + +function nodeName( elem, name ) { + + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + +} +var pop = arr.pop; + + +var sort = arr.sort; + + +var splice = arr.splice; + + +var whitespace = "[\\x20\\t\\r\\n\\f]"; + + +var rtrimCSS = new RegExp( + "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", + "g" +); + + + + +// Note: an element does not contain itself +jQuery.contains = function( a, b ) { + var bup = b && b.parentNode; + + return a === bup || !!( bup && bup.nodeType === 1 && ( + + // Support: IE 9 - 11+ + // IE doesn't have `contains` on SVG. + a.contains ? + a.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + ) ); +}; + + + + +// CSS string/identifier serialization +// https://drafts.csswg.org/cssom/#common-serializing-idioms +var rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g; + +function fcssescape( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; +} + +jQuery.escapeSelector = function( sel ) { + return ( sel + "" ).replace( rcssescape, fcssescape ); +}; + + + + +var preferredDoc = document, + pushNative = push; + +( function() { + +var i, + Expr, + outermostContext, + sortInput, + hasDuplicate, + push = pushNative, + + // Local document vars + document, + documentElement, + documentIsHTML, + rbuggyQSA, + matches, + + // Instance-specific data + expando = jQuery.expando, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + nonnativeSelectorCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|" + + "loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram + identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + + "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+", + + // Attribute selectors: https://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + + // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + + whitespace + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rleadingCombinator = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + + whitespace + "*" ), + rdescend = new RegExp( whitespace + "|>" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + ID: new RegExp( "^#(" + identifier + ")" ), + CLASS: new RegExp( "^\\.(" + identifier + ")" ), + TAG: new RegExp( "^(" + identifier + "|[*])" ), + ATTR: new RegExp( "^" + attributes ), + PSEUDO: new RegExp( "^" + pseudos ), + CHILD: new RegExp( + "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + bool: new RegExp( "^(?:" + booleans + ")$", "i" ), + + // For use in libraries implementing .is() + // We use this for POS matching in `select` + needsContext: new RegExp( "^" + whitespace + + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + + // CSS escapes + // https://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + + "?|\\\\([^\\r\\n\\f])", "g" ), + funescape = function( escape, nonHex ) { + var high = "0x" + escape.slice( 1 ) - 0x10000; + + if ( nonHex ) { + + // Strip the backslash prefix from a non-hex escape sequence + return nonHex; + } + + // Replace a hexadecimal escape sequence with the encoded Unicode code point + // Support: IE <=11+ + // For values outside the Basic Multilingual Plane (BMP), manually construct a + // surrogate pair + return high < 0 ? + String.fromCharCode( high + 0x10000 ) : + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // Used for iframes; see `setDocument`. + // Support: IE 9 - 11+, Edge 12 - 18+ + // Removing the function wrapper causes a "Permission Denied" + // error in IE/Edge. + unloadHandler = function() { + setDocument(); + }, + + inDisabledFieldset = addCombinator( + function( elem ) { + return elem.disabled === true && nodeName( elem, "fieldset" ); + }, + { dir: "parentNode", next: "legend" } + ); + +// Support: IE <=9 only +// Accessing document.activeElement can throw unexpectedly +// https://bugs.jquery.com/ticket/13393 +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + ( arr = slice.call( preferredDoc.childNodes ) ), + preferredDoc.childNodes + ); + + // Support: Android <=4.0 + // Detect silently failing push.apply + // eslint-disable-next-line no-unused-expressions + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { + apply: function( target, els ) { + pushNative.apply( target, slice.call( els ) ); + }, + call: function( target ) { + pushNative.apply( target, slice.call( arguments, 1 ) ); + } + }; +} + +function find( selector, context, results, seed ) { + var m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + setDocument( context ); + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) { + + // ID selector + if ( ( m = match[ 1 ] ) ) { + + // Document context + if ( nodeType === 9 ) { + if ( ( elem = context.getElementById( m ) ) ) { + + // Support: IE 9 only + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + push.call( results, elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE 9 only + // getElementById can match elements by name instead of ID + if ( newContext && ( elem = newContext.getElementById( m ) ) && + find.contains( context, elem ) && + elem.id === m ) { + + push.call( results, elem ); + return results; + } + } + + // Type selector + } else if ( match[ 2 ] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( ( m = match[ 3 ] ) && context.getElementsByClassName ) { + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( !nonnativeSelectorCache[ selector + " " ] && + ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) ) { + + newSelector = selector; + newContext = context; + + // qSA considers elements outside a scoping root when evaluating child or + // descendant combinators, which is not what we want. + // In such cases, we work around the behavior by prefixing every selector in the + // list with an ID selector referencing the scope context. + // The technique has to be used as well when a leading combinator is used + // as such selectors are not recognized by querySelectorAll. + // Thanks to Andrew Dupont for this technique. + if ( nodeType === 1 && + ( rdescend.test( selector ) || rleadingCombinator.test( selector ) ) ) { + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + + // We can use :scope instead of the ID hack if the browser + // supports it & if we're not changing the context. + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when + // strict-comparing two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( newContext != context || !support.scope ) { + + // Capture the context ID, setting it first if necessary + if ( ( nid = context.getAttribute( "id" ) ) ) { + nid = jQuery.escapeSelector( nid ); + } else { + context.setAttribute( "id", ( nid = expando ) ); + } + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " + + toSelector( groups[ i ] ); + } + newSelector = groups.join( "," ); + } + + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + nonnativeSelectorCache( selector, true ); + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + + // All others + return select( selector.replace( rtrimCSS, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + + // Use (key + " ") to avoid collision with native prototype properties + // (see https://github.com/jquery/sizzle/issues/157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return ( cache[ key + " " ] = value ); + } + return cache; +} + +/** + * Mark a function for special use by jQuery selector module + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement( "fieldset" ); + + try { + return !!fn( el ); + } catch ( e ) { + return false; + } finally { + + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + + // release memory in IE + el = null; + } +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + return nodeName( elem, "input" ) && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + return ( nodeName( elem, "input" ) || nodeName( elem, "button" ) ) && + elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { + + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { + + // Option elements defer to a parent optgroup if present + if ( "label" in elem ) { + if ( "label" in elem.parentNode ) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11+ + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || + + // Where there is no isDisabled, check manually + elem.isDisabled !== !disabled && + inDisabledFieldset( elem ) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ( "label" in elem ) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction( function( argument ) { + argument = +argument; + return markFunction( function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ ( j = matchIndexes[ i ] ) ] ) { + seed[ j ] = !( matches[ j ] = seed[ j ] ); + } + } + } ); + } ); +} + +/** + * Checks a node for validity as a jQuery selector context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [node] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +function setDocument( node ) { + var subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + documentElement = document.documentElement; + documentIsHTML = !jQuery.isXMLDoc( document ); + + // Support: iOS 7 only, IE 9 - 11+ + // Older browsers didn't support unprefixed `matches`. + matches = documentElement.matches || + documentElement.webkitMatchesSelector || + documentElement.msMatchesSelector; + + // Support: IE 9 - 11+, Edge 12 - 18+ + // Accessing iframe documents after unload throws "permission denied" errors + // (see trac-13936). + // Limit the fix to IE & Edge Legacy; despite Edge 15+ implementing `matches`, + // all IE 9+ and Edge Legacy versions implement `msMatchesSelector` as well. + if ( documentElement.msMatchesSelector && + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + preferredDoc != document && + ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) { + + // Support: IE 9 - 11+, Edge 12 - 18+ + subWindow.addEventListener( "unload", unloadHandler ); + } + + // Support: IE <10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert( function( el ) { + documentElement.appendChild( el ).id = jQuery.expando; + return !document.getElementsByName || + !document.getElementsByName( jQuery.expando ).length; + } ); + + // Support: IE 9 only + // Check to see if it's possible to do matchesSelector + // on a disconnected node. + support.disconnectedMatch = assert( function( el ) { + return matches.call( el, "*" ); + } ); + + // Support: IE 9 - 11+, Edge 12 - 18+ + // IE/Edge don't support the :scope pseudo-class. + support.scope = assert( function() { + return document.querySelectorAll( ":scope" ); + } ); + + // Support: Chrome 105 - 111 only, Safari 15.4 - 16.3 only + // Make sure the `:has()` argument is parsed unforgivingly. + // We include `*` in the test to detect buggy implementations that are + // _selectively_ forgiving (specifically when the list includes at least + // one valid selector). + // Note that we treat complete lack of support for `:has()` as if it were + // spec-compliant support, which is fine because use of `:has()` in such + // environments will fail in the qSA path and fall back to jQuery traversal + // anyway. + support.cssHas = assert( function() { + try { + document.querySelector( ":has(*,:jqfake)" ); + return false; + } catch ( e ) { + return true; + } + } ); + + // ID filter and find + if ( support.getById ) { + Expr.filter.ID = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute( "id" ) === attrId; + }; + }; + Expr.find.ID = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var elem = context.getElementById( id ); + return elem ? [ elem ] : []; + } + }; + } else { + Expr.filter.ID = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode( "id" ); + return node && node.value === attrId; + }; + }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find.ID = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var node, i, elems, + elem = context.getElementById( id ); + + if ( elem ) { + + // Verify the id attribute + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName( id ); + i = 0; + while ( ( elem = elems[ i++ ] ) ) { + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + } + } + + return []; + } + }; + } + + // Tag + Expr.find.TAG = function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else { + return context.querySelectorAll( tag ); + } + }; + + // Class + Expr.find.CLASS = function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + rbuggyQSA = []; + + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert( function( el ) { + + var input; + + documentElement.appendChild( el ).innerHTML = + "" + + ""; + + // Support: iOS <=7 - 8 only + // Boolean attributes and "value" are not treated correctly in some XML documents + if ( !el.querySelectorAll( "[selected]" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: iOS <=7 - 8 only + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push( "~=" ); + } + + // Support: iOS 8 only + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push( ".#.+[+~]" ); + } + + // Support: Chrome <=105+, Firefox <=104+, Safari <=15.4+ + // In some of the document kinds, these selectors wouldn't work natively. + // This is probably OK but for backwards compatibility we want to maintain + // handling them through jQuery traversal in jQuery 3.x. + if ( !el.querySelectorAll( ":checked" ).length ) { + rbuggyQSA.push( ":checked" ); + } + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + input = document.createElement( "input" ); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE 9 - 11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + // Support: Chrome <=105+, Firefox <=104+, Safari <=15.4+ + // In some of the document kinds, these selectors wouldn't work natively. + // This is probably OK but for backwards compatibility we want to maintain + // handling them through jQuery traversal in jQuery 3.x. + documentElement.appendChild( el ).disabled = true; + if ( el.querySelectorAll( ":disabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE 11+, Edge 15 - 18+ + // IE 11/Edge don't find elements on a `[name='']` query in some cases. + // Adding a temporary attribute to the document before the selection works + // around the issue. + // Interestingly, IE 10 & older don't seem to have the issue. + input = document.createElement( "input" ); + input.setAttribute( "name", "" ); + el.appendChild( input ); + if ( !el.querySelectorAll( "[name='']" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" + + whitespace + "*(?:''|\"\")" ); + } + } ); + + if ( !support.cssHas ) { + + // Support: Chrome 105 - 110+, Safari 15.4 - 16.3+ + // Our regular `try-catch` mechanism fails to detect natively-unsupported + // pseudo-classes inside `:has()` (such as `:has(:contains("Foo"))`) + // in browsers that parse the `:has()` argument as a forgiving selector list. + // https://drafts.csswg.org/selectors/#relational now requires the argument + // to be parsed unforgivingly, but browsers have not yet fully adjusted. + rbuggyQSA.push( ":has" ); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) ); + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + compare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + ( !support.sortDetached && b.compareDocumentPosition( a ) === compare ) ) { + + // Choose the first element that is related to our preferred document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( a === document || a.ownerDocument == preferredDoc && + find.contains( preferredDoc, a ) ) { + return -1; + } + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( b === document || b.ownerDocument == preferredDoc && + find.contains( preferredDoc, b ) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + }; + + return document; +} + +find.matches = function( expr, elements ) { + return find( expr, null, null, elements ); +}; + +find.matchesSelector = function( elem, expr ) { + setDocument( elem ); + + if ( documentIsHTML && + !nonnativeSelectorCache[ expr + " " ] && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch ( e ) { + nonnativeSelectorCache( expr, true ); + } + } + + return find( expr, document, null, [ elem ] ).length > 0; +}; + +find.contains = function( context, elem ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( context.ownerDocument || context ) != document ) { + setDocument( context ); + } + return jQuery.contains( context, elem ); +}; + + +find.attr = function( elem, name ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( elem.ownerDocument || elem ) != document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + + // Don't get fooled by Object.prototype properties (see trac-13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + if ( val !== undefined ) { + return val; + } + + return elem.getAttribute( name ); +}; + +find.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +jQuery.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + // + // Support: Android <=4.0+ + // Testing for detecting duplicates is unpredictable so instead assume we can't + // depend on duplicate detection in all browsers without a stable sort. + hasDuplicate = !support.sortStable; + sortInput = !support.sortStable && slice.call( results, 0 ); + sort.call( results, sortOrder ); + + if ( hasDuplicate ) { + while ( ( elem = results[ i++ ] ) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + splice.call( results, duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +jQuery.fn.uniqueSort = function() { + return this.pushStack( jQuery.uniqueSort( slice.apply( this ) ) ); +}; + +Expr = jQuery.expr = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + ATTR: function( match ) { + match[ 1 ] = match[ 1 ].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[ 3 ] = ( match[ 3 ] || match[ 4 ] || match[ 5 ] || "" ) + .replace( runescape, funescape ); + + if ( match[ 2 ] === "~=" ) { + match[ 3 ] = " " + match[ 3 ] + " "; + } + + return match.slice( 0, 4 ); + }, + + CHILD: function( match ) { + + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[ 1 ] = match[ 1 ].toLowerCase(); + + if ( match[ 1 ].slice( 0, 3 ) === "nth" ) { + + // nth-* requires argument + if ( !match[ 3 ] ) { + find.error( match[ 0 ] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[ 4 ] = +( match[ 4 ] ? + match[ 5 ] + ( match[ 6 ] || 1 ) : + 2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" ) + ); + match[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === "odd" ); + + // other types prohibit arguments + } else if ( match[ 3 ] ) { + find.error( match[ 0 ] ); + } + + return match; + }, + + PSEUDO: function( match ) { + var excess, + unquoted = !match[ 6 ] && match[ 2 ]; + + if ( matchExpr.CHILD.test( match[ 0 ] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[ 3 ] ) { + match[ 2 ] = match[ 4 ] || match[ 5 ] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + + // Get excess from tokenize (recursively) + ( excess = tokenize( unquoted, true ) ) && + + // advance to the next closing parenthesis + ( excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length ) ) { + + // excess is a negative index + match[ 0 ] = match[ 0 ].slice( 0, excess ); + match[ 2 ] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + TAG: function( nodeNameSelector ) { + var expectedNodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { + return true; + } : + function( elem ) { + return nodeName( elem, expectedNodeName ); + }; + }, + + CLASS: function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + ( pattern = new RegExp( "(^|" + whitespace + ")" + className + + "(" + whitespace + "|$)" ) ) && + classCache( className, function( elem ) { + return pattern.test( + typeof elem.className === "string" && elem.className || + typeof elem.getAttribute !== "undefined" && + elem.getAttribute( "class" ) || + "" + ); + } ); + }, + + ATTR: function( name, operator, check ) { + return function( elem ) { + var result = find.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + if ( operator === "=" ) { + return result === check; + } + if ( operator === "!=" ) { + return result !== check; + } + if ( operator === "^=" ) { + return check && result.indexOf( check ) === 0; + } + if ( operator === "*=" ) { + return check && result.indexOf( check ) > -1; + } + if ( operator === "$=" ) { + return check && result.slice( -check.length ) === check; + } + if ( operator === "~=" ) { + return ( " " + result.replace( rwhitespace, " " ) + " " ) + .indexOf( check ) > -1; + } + if ( operator === "|=" ) { + return result === check || result.slice( 0, check.length + 1 ) === check + "-"; + } + + return false; + }; + }, + + CHILD: function( type, what, _argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, _context, xml ) { + var cache, outerCache, node, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( ( node = node[ dir ] ) ) { + if ( ofType ? + nodeName( node, name ) : + node.nodeType === 1 ) { + + return false; + } + } + + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + + // Seek `elem` from a previously-cached index + outerCache = parent[ expando ] || ( parent[ expando ] = {} ); + cache = outerCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex && cache[ 2 ]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( ( node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + outerCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + + // Use previously-cached element index if available + if ( useCache ) { + outerCache = elem[ expando ] || ( elem[ expando ] = {} ); + cache = outerCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex; + } + + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if ( diff === false ) { + + // Use the same loop as above to seek `elem` from the start + while ( ( node = ++nodeIndex && node && node[ dir ] || + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + if ( ( ofType ? + nodeName( node, name ) : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || + ( node[ expando ] = {} ); + outerCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + PSEUDO: function( pseudo, argument ) { + + // pseudo-class names are case-insensitive + // https://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + find.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as jQuery does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction( function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf.call( seed, matched[ i ] ); + seed[ idx ] = !( matches[ idx ] = matched[ i ] ); + } + } ) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + + // Potentially complex pseudos + not: markFunction( function( selector ) { + + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrimCSS, "$1" ) ); + + return matcher[ expando ] ? + markFunction( function( seed, matches, _context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( ( elem = unmatched[ i ] ) ) { + seed[ i ] = !( matches[ i ] = elem ); + } + } + } ) : + function( elem, _context, xml ) { + input[ 0 ] = elem; + matcher( input, null, xml, results ); + + // Don't keep the element + // (see https://github.com/jquery/sizzle/issues/299) + input[ 0 ] = null; + return !results.pop(); + }; + } ), + + has: markFunction( function( selector ) { + return function( elem ) { + return find( selector, elem ).length > 0; + }; + } ), + + contains: markFunction( function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || jQuery.text( elem ) ).indexOf( text ) > -1; + }; + } ), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // https://www.w3.org/TR/selectors/#lang-pseudo + lang: markFunction( function( lang ) { + + // lang value must be a valid identifier + if ( !ridentifier.test( lang || "" ) ) { + find.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( ( elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute( "xml:lang" ) || elem.getAttribute( "lang" ) ) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( ( elem = elem.parentNode ) && elem.nodeType === 1 ); + return false; + }; + } ), + + // Miscellaneous + target: function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + root: function( elem ) { + return elem === documentElement; + }, + + focus: function( elem ) { + return elem === safeActiveElement() && + document.hasFocus() && + !!( elem.type || elem.href || ~elem.tabIndex ); + }, + + // Boolean properties + enabled: createDisabledPseudo( false ), + disabled: createDisabledPseudo( true ), + + checked: function( elem ) { + + // In CSS3, :checked should return both checked and selected elements + // https://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + return ( nodeName( elem, "input" ) && !!elem.checked ) || + ( nodeName( elem, "option" ) && !!elem.selected ); + }, + + selected: function( elem ) { + + // Support: IE <=11+ + // Accessing the selectedIndex property + // forces the browser to treat the default option as + // selected when in an optgroup. + if ( elem.parentNode ) { + // eslint-disable-next-line no-unused-expressions + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + empty: function( elem ) { + + // https://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + parent: function( elem ) { + return !Expr.pseudos.empty( elem ); + }, + + // Element/input types + header: function( elem ) { + return rheader.test( elem.nodeName ); + }, + + input: function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + button: function( elem ) { + return nodeName( elem, "input" ) && elem.type === "button" || + nodeName( elem, "button" ); + }, + + text: function( elem ) { + var attr; + return nodeName( elem, "input" ) && elem.type === "text" && + + // Support: IE <10 only + // New HTML5 attribute values (e.g., "search") appear + // with elem.type === "text" + ( ( attr = elem.getAttribute( "type" ) ) == null || + attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + first: createPositionalPseudo( function() { + return [ 0 ]; + } ), + + last: createPositionalPseudo( function( _matchIndexes, length ) { + return [ length - 1 ]; + } ), + + eq: createPositionalPseudo( function( _matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + } ), + + even: createPositionalPseudo( function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + odd: createPositionalPseudo( function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + lt: createPositionalPseudo( function( matchIndexes, length, argument ) { + var i; + + if ( argument < 0 ) { + i = argument + length; + } else if ( argument > length ) { + i = length; + } else { + i = argument; + } + + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + gt: createPositionalPseudo( function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ) + } +}; + +Expr.pseudos.nth = Expr.pseudos.eq; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +function tokenize( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || ( match = rcomma.exec( soFar ) ) ) { + if ( match ) { + + // Don't consume trailing commas as valid + soFar = soFar.slice( match[ 0 ].length ) || soFar; + } + groups.push( ( tokens = [] ) ); + } + + matched = false; + + // Combinators + if ( ( match = rleadingCombinator.exec( soFar ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + + // Cast descendant combinators to space + type: match[ 0 ].replace( rtrimCSS, " " ) + } ); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( ( match = matchExpr[ type ].exec( soFar ) ) && ( !preFilters[ type ] || + ( match = preFilters[ type ]( match ) ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + type: type, + matches: match + } ); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + if ( parseOnly ) { + return soFar.length; + } + + return soFar ? + find.error( selector ) : + + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +} + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[ i ].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + skip = combinator.next, + key = skip || dir, + checkNonElements = base && key === "parentNode", + doneName = done++; + + return combinator.first ? + + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + return false; + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching + if ( xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || ( elem[ expando ] = {} ); + + if ( skip && nodeName( elem, skip ) ) { + elem = elem[ dir ] || elem; + } else if ( ( oldCache = outerCache[ key ] ) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return ( newCache[ 2 ] = oldCache[ 2 ] ); + } else { + + // Reuse newcache so results back-propagate to previous elements + outerCache[ key ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) { + return true; + } + } + } + } + } + return false; + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[ i ]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[ 0 ]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + find( selector, contexts[ i ], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( ( elem = unmatched[ i ] ) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction( function( seed, results, context, xml ) { + var temp, i, elem, matcherOut, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || + multipleContexts( selector || "*", + context.nodeType ? [ context ] : context, [] ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems; + + if ( matcher ) { + + // If we have a postFinder, or filtered seed, or non-seed postFilter + // or preexisting results, + matcherOut = postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results; + + // Find primary matches + matcher( matcherIn, matcherOut, context, xml ); + } else { + matcherOut = matcherIn; + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( ( elem = temp[ i ] ) ) { + matcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem ); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) ) { + + // Restore matcherIn since elem is not yet a final match + temp.push( ( matcherIn[ i ] = elem ) ); + } + } + postFinder( null, ( matcherOut = [] ), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) && + ( temp = postFinder ? indexOf.call( seed, elem ) : preMap[ i ] ) > -1 ) { + + seed[ temp ] = !( results[ temp ] = elem ); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + } ); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[ 0 ].type ], + implicitRelative = leadingRelative || Expr.relative[ " " ], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf.call( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + var ret = ( !leadingRelative && ( xml || context != outermostContext ) ) || ( + ( checkContext = context ).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + + // Avoid hanging onto element + // (see https://github.com/jquery/sizzle/issues/299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( ( matcher = Expr.relative[ tokens[ i ].type ] ) ) { + matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ]; + } else { + matcher = Expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[ j ].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens.slice( 0, i - 1 ) + .concat( { value: tokens[ i - 2 ].type === " " ? "*" : "" } ) + ).replace( rtrimCSS, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find.TAG( "*", outermost ), + + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ), + len = elems.length; + + if ( outermost ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + outermostContext = context == document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: iOS <=7 - 9 only + // Tolerate NodeList properties (IE: "length"; Safari: ) matching + // elements by id. (see trac-14142) + for ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( !context && elem.ownerDocument != document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( ( matcher = elementMatchers[ j++ ] ) ) { + if ( matcher( elem, context || document, xml ) ) { + push.call( results, elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + + // They will have gone through all possible matchers + if ( ( elem = !matcher && elem ) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if ( bySet && i !== matchedCount ) { + j = 0; + while ( ( matcher = setMatchers[ j++ ] ) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !( unmatched[ i ] || setMatched[ i ] ) ) { + setMatched[ i ] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + jQuery.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +function compile( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[ i ] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( selector, + matcherFromGroupMatchers( elementMatchers, setMatchers ) ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +} + +/** + * A low-level selection function that works with jQuery's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with jQuery selector compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +function select( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( ( selector = compiled.selector || selector ) ); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if ( match.length === 1 ) { + + // Reduce context if the leading compound selector is an ID + tokens = match[ 0 ] = match[ 0 ].slice( 0 ); + if ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === "ID" && + context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) { + + context = ( Expr.find.ID( + token.matches[ 0 ].replace( runescape, funescape ), + context + ) || [] )[ 0 ]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr.needsContext.test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[ i ]; + + // Abort if we hit a combinator + if ( Expr.relative[ ( type = token.type ) ] ) { + break; + } + if ( ( find = Expr.find[ type ] ) ) { + + // Search, expanding context for leading sibling combinators + if ( ( seed = find( + token.matches[ 0 ].replace( runescape, funescape ), + rsibling.test( tokens[ 0 ].type ) && + testContext( context.parentNode ) || context + ) ) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + !context || rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +} + +// One-time assignments + +// Support: Android <=4.0 - 4.1+ +// Sort stability +support.sortStable = expando.split( "" ).sort( sortOrder ).join( "" ) === expando; + +// Initialize against the default document +setDocument(); + +// Support: Android <=4.0 - 4.1+ +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert( function( el ) { + + // Should return 1, but returns 4 (following) + return el.compareDocumentPosition( document.createElement( "fieldset" ) ) & 1; +} ); + +jQuery.find = find; + +// Deprecated +jQuery.expr[ ":" ] = jQuery.expr.pseudos; +jQuery.unique = jQuery.uniqueSort; + +// These have always been private, but they used to be documented as part of +// Sizzle so let's maintain them for now for backwards compatibility purposes. +find.compile = compile; +find.select = select; +find.setDocument = setDocument; +find.tokenize = tokenize; + +find.escape = jQuery.escapeSelector; +find.getText = jQuery.text; +find.isXML = jQuery.isXMLDoc; +find.selectors = jQuery.expr; +find.support = jQuery.support; +find.uniqueSort = jQuery.uniqueSort; + + /* eslint-enable */ + +} )(); + + +var dir = function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; +}; + + +var siblings = function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; +}; + + +var rneedsContext = jQuery.expr.match.needsContext; + +var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); + + + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) !== not; + } ); + } + + // Single element + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + } + + // Arraylike of elements (jQuery, arguments, Array) + if ( typeof qualifier !== "string" ) { + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not; + } ); + } + + // Filtered directly for both simple and complex selectors + return jQuery.filter( qualifier, elements, not ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + if ( elems.length === 1 && elem.nodeType === 1 ) { + return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; + } + + return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); +}; + +jQuery.fn.extend( { + find: function( selector ) { + var i, ret, + len = this.length, + self = this; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + } ) ); + } + + ret = this.pushStack( [] ); + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + return len > 1 ? jQuery.uniqueSort( ret ) : ret; + }, + filter: function( selector ) { + return this.pushStack( winnow( this, selector || [], false ) ); + }, + not: function( selector ) { + return this.pushStack( winnow( this, selector || [], true ) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +} ); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (trac-9521) + // Strict HTML recognition (trac-11290: must start with <) + // Shortcut simple #id case for speed + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Method init() accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[ 0 ] === "<" && + selector[ selector.length - 1 ] === ">" && + selector.length >= 3 ) { + + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && ( match[ 1 ] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[ 1 ] ) { + context = context instanceof jQuery ? context[ 0 ] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[ 1 ], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + + // Properties of context are called as methods if possible + if ( isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[ 2 ] ); + + if ( elem ) { + + // Inject the element directly into the jQuery object + this[ 0 ] = elem; + this.length = 1; + } + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || root ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( isFunction( selector ) ) { + return root.ready !== undefined ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + + // Methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend( { + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter( function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + targets = typeof selectors !== "string" && jQuery( selectors ); + + // Positional selectors never match, since there's no _selection_ context + if ( !rneedsContext.test( selectors ) ) { + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( targets ? + targets.index( cur ) > -1 : + + // Don't pass non-elements to jQuery#find + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { + + matched.push( cur ); + break; + } + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); + }, + + // Determine the position of an element within the set + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // Index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, _i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, _i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, _i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + if ( elem.contentDocument != null && + + // Support: IE 11+ + // elements with no `data` attribute has an object + // `contentDocument` with a `null` prototype. + getProto( elem.contentDocument ) ) { + + return elem.contentDocument; + } + + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if ( nodeName( elem, "template" ) ) { + elem = elem.content || elem; + } + + return jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var matched = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + matched = jQuery.filter( selector, matched ); + } + + if ( this.length > 1 ) { + + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + jQuery.uniqueSort( matched ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + matched.reverse(); + } + } + + return this.pushStack( matched ); + }; +} ); +var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { + object[ flag ] = true; + } ); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + createOptions( options ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + + // Last fire value for non-forgettable lists + memory, + + // Flag to know if list was already fired + fired, + + // Flag to prevent firing + locked, + + // Actual callback list + list = [], + + // Queue of execution data for repeatable lists + queue = [], + + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, + + // Fire callbacks + fire = function() { + + // Enforce single-firing + locked = locked || options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } + } + } + + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if ( locked ) { + + // Keep an empty list if we have data for future add calls + if ( memory ) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + + // Actual Callbacks object + self = { + + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + + ( function add( args ) { + jQuery.each( args, function( _, arg ) { + if ( isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && toType( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; + } + } + } ); + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = queue = []; + if ( !memory && !firing ) { + list = memory = ""; + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( !locked ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + queue.push( args ); + if ( !firing ) { + fire(); + } + } + return this; + }, + + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +function Identity( v ) { + return v; +} +function Thrower( ex ) { + throw ex; +} + +function adoptValue( value, resolve, reject, noValue ) { + var method; + + try { + + // Check for promise aspect first to privilege synchronous behavior + if ( value && isFunction( ( method = value.promise ) ) ) { + method.call( value ).done( resolve ).fail( reject ); + + // Other thenables + } else if ( value && isFunction( ( method = value.then ) ) ) { + method.call( value, resolve, reject ); + + // Other non-thenables + } else { + + // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: + // * false: [ value ].slice( 0 ) => resolve( value ) + // * true: [ value ].slice( 1 ) => resolve() + resolve.apply( undefined, [ value ].slice( noValue ) ); + } + + // For Promises/A+, convert exceptions into rejections + // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in + // Deferred#then to conditionally suppress rejection. + } catch ( value ) { + + // Support: Android 4.0 only + // Strict mode functions invoked without .call/.apply get global-object context + reject.apply( undefined, [ value ] ); + } +} + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, callbacks, + // ... .then handlers, argument index, [final state] + [ "notify", "progress", jQuery.Callbacks( "memory" ), + jQuery.Callbacks( "memory" ), 2 ], + [ "resolve", "done", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 0, "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 1, "rejected" ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + "catch": function( fn ) { + return promise.then( null, fn ); + }, + + // Keep pipe for back-compat + pipe: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( _i, tuple ) { + + // Map tuples (progress, done, fail) to arguments (done, fail, progress) + var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; + + // deferred.progress(function() { bind to newDefer or newDefer.notify }) + // deferred.done(function() { bind to newDefer or newDefer.resolve }) + // deferred.fail(function() { bind to newDefer or newDefer.reject }) + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + then: function( onFulfilled, onRejected, onProgress ) { + var maxDepth = 0; + function resolve( depth, deferred, handler, special ) { + return function() { + var that = this, + args = arguments, + mightThrow = function() { + var returned, then; + + // Support: Promises/A+ section 2.3.3.3.3 + // https://promisesaplus.com/#point-59 + // Ignore double-resolution attempts + if ( depth < maxDepth ) { + return; + } + + returned = handler.apply( that, args ); + + // Support: Promises/A+ section 2.3.1 + // https://promisesaplus.com/#point-48 + if ( returned === deferred.promise() ) { + throw new TypeError( "Thenable self-resolution" ); + } + + // Support: Promises/A+ sections 2.3.3.1, 3.5 + // https://promisesaplus.com/#point-54 + // https://promisesaplus.com/#point-75 + // Retrieve `then` only once + then = returned && + + // Support: Promises/A+ section 2.3.4 + // https://promisesaplus.com/#point-64 + // Only check objects and functions for thenability + ( typeof returned === "object" || + typeof returned === "function" ) && + returned.then; + + // Handle a returned thenable + if ( isFunction( then ) ) { + + // Special processors (notify) just wait for resolution + if ( special ) { + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ) + ); + + // Normal processors (resolve) also hook into progress + } else { + + // ...and disregard older resolution values + maxDepth++; + + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ), + resolve( maxDepth, deferred, Identity, + deferred.notifyWith ) + ); + } + + // Handle all other returned values + } else { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Identity ) { + that = undefined; + args = [ returned ]; + } + + // Process the value(s) + // Default process is resolve + ( special || deferred.resolveWith )( that, args ); + } + }, + + // Only normal processors (resolve) catch and reject exceptions + process = special ? + mightThrow : + function() { + try { + mightThrow(); + } catch ( e ) { + + if ( jQuery.Deferred.exceptionHook ) { + jQuery.Deferred.exceptionHook( e, + process.error ); + } + + // Support: Promises/A+ section 2.3.3.3.4.1 + // https://promisesaplus.com/#point-61 + // Ignore post-resolution exceptions + if ( depth + 1 >= maxDepth ) { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Thrower ) { + that = undefined; + args = [ e ]; + } + + deferred.rejectWith( that, args ); + } + } + }; + + // Support: Promises/A+ section 2.3.3.3.1 + // https://promisesaplus.com/#point-57 + // Re-resolve promises immediately to dodge false rejection from + // subsequent errors + if ( depth ) { + process(); + } else { + + // Call an optional hook to record the error, in case of exception + // since it's otherwise lost when execution goes async + if ( jQuery.Deferred.getErrorHook ) { + process.error = jQuery.Deferred.getErrorHook(); + + // The deprecated alias of the above. While the name suggests + // returning the stack, not an error instance, jQuery just passes + // it directly to `console.warn` so both will work; an instance + // just better cooperates with source maps. + } else if ( jQuery.Deferred.getStackHook ) { + process.error = jQuery.Deferred.getStackHook(); + } + window.setTimeout( process ); + } + }; + } + + return jQuery.Deferred( function( newDefer ) { + + // progress_handlers.add( ... ) + tuples[ 0 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onProgress ) ? + onProgress : + Identity, + newDefer.notifyWith + ) + ); + + // fulfilled_handlers.add( ... ) + tuples[ 1 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onFulfilled ) ? + onFulfilled : + Identity + ) + ); + + // rejected_handlers.add( ... ) + tuples[ 2 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onRejected ) ? + onRejected : + Thrower + ) + ); + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 5 ]; + + // promise.progress = list.add + // promise.done = list.add + // promise.fail = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( + function() { + + // state = "resolved" (i.e., fulfilled) + // state = "rejected" + state = stateString; + }, + + // rejected_callbacks.disable + // fulfilled_callbacks.disable + tuples[ 3 - i ][ 2 ].disable, + + // rejected_handlers.disable + // fulfilled_handlers.disable + tuples[ 3 - i ][ 3 ].disable, + + // progress_callbacks.lock + tuples[ 0 ][ 2 ].lock, + + // progress_handlers.lock + tuples[ 0 ][ 3 ].lock + ); + } + + // progress_handlers.fire + // fulfilled_handlers.fire + // rejected_handlers.fire + list.add( tuple[ 3 ].fire ); + + // deferred.notify = function() { deferred.notifyWith(...) } + // deferred.resolve = function() { deferred.resolveWith(...) } + // deferred.reject = function() { deferred.rejectWith(...) } + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); + return this; + }; + + // deferred.notifyWith = list.fireWith + // deferred.resolveWith = list.fireWith + // deferred.rejectWith = list.fireWith + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( singleValue ) { + var + + // count of uncompleted subordinates + remaining = arguments.length, + + // count of unprocessed arguments + i = remaining, + + // subordinate fulfillment data + resolveContexts = Array( i ), + resolveValues = slice.call( arguments ), + + // the primary Deferred + primary = jQuery.Deferred(), + + // subordinate callback factory + updateFunc = function( i ) { + return function( value ) { + resolveContexts[ i ] = this; + resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( !( --remaining ) ) { + primary.resolveWith( resolveContexts, resolveValues ); + } + }; + }; + + // Single- and empty arguments are adopted like Promise.resolve + if ( remaining <= 1 ) { + adoptValue( singleValue, primary.done( updateFunc( i ) ).resolve, primary.reject, + !remaining ); + + // Use .then() to unwrap secondary thenables (cf. gh-3000) + if ( primary.state() === "pending" || + isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + + return primary.then(); + } + } + + // Multiple arguments are aggregated like Promise.all array elements + while ( i-- ) { + adoptValue( resolveValues[ i ], updateFunc( i ), primary.reject ); + } + + return primary.promise(); + } +} ); + + +// These usually indicate a programmer mistake during development, +// warn about them ASAP rather than swallowing them by default. +var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; + +// If `jQuery.Deferred.getErrorHook` is defined, `asyncError` is an error +// captured before the async barrier to get the original error cause +// which may otherwise be hidden. +jQuery.Deferred.exceptionHook = function( error, asyncError ) { + + // Support: IE 8 - 9 only + // Console exists when dev tools are open, which can happen at any time + if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { + window.console.warn( "jQuery.Deferred exception: " + error.message, + error.stack, asyncError ); + } +}; + + + + +jQuery.readyException = function( error ) { + window.setTimeout( function() { + throw error; + } ); +}; + + + + +// The deferred used on DOM ready +var readyList = jQuery.Deferred(); + +jQuery.fn.ready = function( fn ) { + + readyList + .then( fn ) + + // Wrap jQuery.readyException in a function so that the lookup + // happens at the time of error handling instead of callback + // registration. + .catch( function( error ) { + jQuery.readyException( error ); + } ); + + return this; +}; + +jQuery.extend( { + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See trac-6781 + readyWait: 1, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + } +} ); + +jQuery.ready.then = readyList.then; + +// The ready event handler and self cleanup method +function completed() { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + jQuery.ready(); +} + +// Catch cases where $(document).ready() is called +// after the browser event has already occurred. +// Support: IE <=9 - 10 only +// Older IE sometimes signals "interactive" too soon +if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { + + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); + +} else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); +} + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( toType( key ) === "object" ) { + chainable = true; + for ( i in key ) { + access( elems, fn, i, key[ i ], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, _key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( + elems[ i ], key, raw ? + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + if ( chainable ) { + return elems; + } + + // Gets + if ( bulk ) { + return fn.call( elems ); + } + + return len ? fn( elems[ 0 ], key ) : emptyGet; +}; + + +// Matches dashed string for camelizing +var rmsPrefix = /^-ms-/, + rdashAlpha = /-([a-z])/g; + +// Used by camelCase as callback to replace() +function fcamelCase( _all, letter ) { + return letter.toUpperCase(); +} + +// Convert dashed to camelCase; used by the css and data modules +// Support: IE <=9 - 11, Edge 12 - 15 +// Microsoft forgot to hump their vendor prefix (trac-9572) +function camelCase( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); +} +var acceptData = function( owner ) { + + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + + + +function Data() { + this.expando = jQuery.expando + Data.uid++; +} + +Data.uid = 1; + +Data.prototype = { + + cache: function( owner ) { + + // Check if the owner object already has a cache + var value = owner[ this.expando ]; + + // If not, create one + if ( !value ) { + value = {}; + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see trac-8335. + // Always return an empty object. + if ( acceptData( owner ) ) { + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable property + // configurable must be true to allow the property to be + // deleted when data is removed + } else { + Object.defineProperty( owner, this.expando, { + value: value, + configurable: true + } ); + } + } + } + + return value; + }, + set: function( owner, data, value ) { + var prop, + cache = this.cache( owner ); + + // Handle: [ owner, key, value ] args + // Always use camelCase key (gh-2257) + if ( typeof data === "string" ) { + cache[ camelCase( data ) ] = value; + + // Handle: [ owner, { properties } ] args + } else { + + // Copy the properties one-by-one to the cache object + for ( prop in data ) { + cache[ camelCase( prop ) ] = data[ prop ]; + } + } + return cache; + }, + get: function( owner, key ) { + return key === undefined ? + this.cache( owner ) : + + // Always use camelCase key (gh-2257) + owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ]; + }, + access: function( owner, key, value ) { + + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ( ( key && typeof key === "string" ) && value === undefined ) ) { + + return this.get( owner, key ); + } + + // When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, + cache = owner[ this.expando ]; + + if ( cache === undefined ) { + return; + } + + if ( key !== undefined ) { + + // Support array or space separated string of keys + if ( Array.isArray( key ) ) { + + // If key is an array of keys... + // We always set camelCase keys, so remove that. + key = key.map( camelCase ); + } else { + key = camelCase( key ); + + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + key = key in cache ? + [ key ] : + ( key.match( rnothtmlwhite ) || [] ); + } + + i = key.length; + + while ( i-- ) { + delete cache[ key[ i ] ]; + } + } + + // Remove the expando if there's no more data + if ( key === undefined || jQuery.isEmptyObject( cache ) ) { + + // Support: Chrome <=35 - 45 + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) + if ( owner.nodeType ) { + owner[ this.expando ] = undefined; + } else { + delete owner[ this.expando ]; + } + } + }, + hasData: function( owner ) { + var cache = owner[ this.expando ]; + return cache !== undefined && !jQuery.isEmptyObject( cache ); + } +}; +var dataPriv = new Data(); + +var dataUser = new Data(); + + + +// Implementation Summary +// +// 1. Enforce API surface and semantic compatibility with 1.9.x branch +// 2. Improve the module's maintainability by reducing the storage +// paths to a single mechanism. +// 3. Use the same single mechanism to support "private" and "user" data. +// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) +// 5. Avoid exposing implementation details on user objects (eg. expando properties) +// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /[A-Z]/g; + +function getData( data ) { + if ( data === "true" ) { + return true; + } + + if ( data === "false" ) { + return false; + } + + if ( data === "null" ) { + return null; + } + + // Only convert to a number if it doesn't change the string + if ( data === +data + "" ) { + return +data; + } + + if ( rbrace.test( data ) ) { + return JSON.parse( data ); + } + + return data; +} + +function dataAttr( elem, key, data ) { + var name; + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = getData( data ); + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + dataUser.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend( { + hasData: function( elem ) { + return dataUser.hasData( elem ) || dataPriv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return dataUser.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + dataUser.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to dataPriv methods, these can be deprecated. + _data: function( elem, name, data ) { + return dataPriv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + dataPriv.remove( elem, name ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = dataUser.get( elem ); + + if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE 11 only + // The attrs elements can be null (trac-14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + dataPriv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + dataUser.set( this, key ); + } ); + } + + return access( this, function( value ) { + var data; + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + + // Attempt to get data from the cache + // The key will always be camelCased in Data + data = dataUser.get( elem, key ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, key ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + this.each( function() { + + // We always store the camelCased key + dataUser.set( this, key, value ); + } ); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each( function() { + dataUser.remove( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = dataPriv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || Array.isArray( data ) ) { + queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // Clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // Not public - generate a queueHooks object, or return the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + dataPriv.remove( elem, [ type + "queue", key ] ); + } ) + } ); + } +} ); + +jQuery.fn.extend( { + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[ 0 ], type ); + } + + return data === undefined ? + this : + this.each( function() { + var queue = jQuery.queue( this, type, data ); + + // Ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var documentElement = document.documentElement; + + + + var isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ); + }, + composed = { composed: true }; + + // Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only + // Check attachment across shadow DOM boundaries when possible (gh-3504) + // Support: iOS 10.0-10.2 only + // Early iOS 10 versions support `attachShadow` but not `getRootNode`, + // leading to errors. We need to check for `getRootNode`. + if ( documentElement.getRootNode ) { + isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ) || + elem.getRootNode( composed ) === elem.ownerDocument; + }; + } +var isHiddenWithinTree = function( elem, el ) { + + // isHiddenWithinTree might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + + // Inline style trumps all + return elem.style.display === "none" || + elem.style.display === "" && + + // Otherwise, check computed style + // Support: Firefox <=43 - 45 + // Disconnected elements can have computed display: none, so first confirm that elem is + // in the document. + isAttached( elem ) && + + jQuery.css( elem, "display" ) === "none"; + }; + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, scale, + maxIterations = 20, + currentValue = tween ? + function() { + return tween.cur(); + } : + function() { + return jQuery.css( elem, prop, "" ); + }, + initial = currentValue(), + unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), + + // Starting value computation is required for potential unit mismatches + initialInUnit = elem.nodeType && + ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Support: Firefox <=54 + // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144) + initial = initial / 2; + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + while ( maxIterations-- ) { + + // Evaluate and update our best guess (doubling guesses that zero out). + // Finish if the scale equals or crosses 1 (making the old*new product non-positive). + jQuery.style( elem, prop, initialInUnit + unit ); + if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) { + maxIterations = 0; + } + initialInUnit = initialInUnit / scale; + + } + + initialInUnit = initialInUnit * 2; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + } + + if ( valueParts ) { + initialInUnit = +initialInUnit || +initial || 0; + + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[ 1 ] ? + initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : + +valueParts[ 2 ]; + if ( tween ) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; + } + } + return adjusted; +} + + +var defaultDisplayMap = {}; + +function getDefaultDisplay( elem ) { + var temp, + doc = elem.ownerDocument, + nodeName = elem.nodeName, + display = defaultDisplayMap[ nodeName ]; + + if ( display ) { + return display; + } + + temp = doc.body.appendChild( doc.createElement( nodeName ) ); + display = jQuery.css( temp, "display" ); + + temp.parentNode.removeChild( temp ); + + if ( display === "none" ) { + display = "block"; + } + defaultDisplayMap[ nodeName ] = display; + + return display; +} + +function showHide( elements, show ) { + var display, elem, + values = [], + index = 0, + length = elements.length; + + // Determine new display value for elements that need to change + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + display = elem.style.display; + if ( show ) { + + // Since we force visibility upon cascade-hidden elements, an immediate (and slow) + // check is required in this first loop unless we have a nonempty display value (either + // inline or about-to-be-restored) + if ( display === "none" ) { + values[ index ] = dataPriv.get( elem, "display" ) || null; + if ( !values[ index ] ) { + elem.style.display = ""; + } + } + if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { + values[ index ] = getDefaultDisplay( elem ); + } + } else { + if ( display !== "none" ) { + values[ index ] = "none"; + + // Remember what we're overwriting + dataPriv.set( elem, "display", display ); + } + } + } + + // Set the display of the elements in a second loop to avoid constant reflow + for ( index = 0; index < length; index++ ) { + if ( values[ index ] != null ) { + elements[ index ].style.display = values[ index ]; + } + } + + return elements; +} + +jQuery.fn.extend( { + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + if ( typeof state === "boolean" ) { + return state ? this.show() : this.hide(); + } + + return this.each( function() { + if ( isHiddenWithinTree( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + } ); + } +} ); +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]*)/i ); + +var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); + + + +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (trac-11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (trac-14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; + + // Support: IE <=9 only + // IE <=9 replaces "; + support.option = !!div.lastChild; +} )(); + + +// We have to close these tags to support XHTML (trac-13200) +var wrapMap = { + + // XHTML parsers do not magically insert elements in the + // same way that tag soup parsers do. So we cannot shorten + // this by omitting or other required elements. + thead: [ 1, "", "
    " ], + col: [ 2, "", "
    " ], + tr: [ 2, "", "
    " ], + td: [ 3, "", "
    " ], + + _default: [ 0, "", "" ] +}; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// Support: IE <=9 only +if ( !support.option ) { + wrapMap.optgroup = wrapMap.option = [ 1, "" ]; +} + + +function getAll( context, tag ) { + + // Support: IE <=9 - 11 only + // Use typeof to avoid zero-argument method invocation on host objects (trac-15151) + var ret; + + if ( typeof context.getElementsByTagName !== "undefined" ) { + ret = context.getElementsByTagName( tag || "*" ); + + } else if ( typeof context.querySelectorAll !== "undefined" ) { + ret = context.querySelectorAll( tag || "*" ); + + } else { + ret = []; + } + + if ( tag === undefined || tag && nodeName( context, tag ) ) { + return jQuery.merge( [ context ], ret ); + } + + return ret; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + dataPriv.set( + elems[ i ], + "globalEval", + !refElements || dataPriv.get( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/; + +function buildFragment( elems, context, scripts, selection, ignored ) { + var elem, tmp, tag, wrap, attached, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( toType( elem ) === "object" ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (trac-12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + continue; + } + + attached = isAttached( elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( attached ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; +} + + +var rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.get( elem ); + + // Only attach events to objects that accept data + if ( !acceptData( elem ) ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Ensure that invalid selectors throw exceptions at attach time + // Evaluate against documentElement in case elem is a non-element node (e.g., document) + if ( selector ) { + jQuery.find.matchesSelector( documentElement, selector ); + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = Object.create( null ); + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = function( e ) { + + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend( { + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove data and the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + dataPriv.remove( elem, "handle events" ); + } + }, + + dispatch: function( nativeEvent ) { + + var i, j, ret, matched, handleObj, handlerQueue, + args = new Array( arguments.length ), + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( nativeEvent ), + + handlers = ( + 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 + args[ 0 ] = event; + + for ( i = 1; i < arguments.length; i++ ) { + args[ i ] = arguments[ i ]; + } + + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // If the event is namespaced, then each handler is only invoked if it is + // specially universal or its namespaces are a superset of the event's. + if ( !event.rnamespace || handleObj.namespace === false || + event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = ret ) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, handleObj, sel, matchedHandlers, matchedSelectors, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + if ( delegateCount && + + // Support: IE <=9 + // Black-hole SVG instance trees (trac-13180) + cur.nodeType && + + // Support: Firefox <=42 + // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) + // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click + // Support: IE 11 only + // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) + !( event.type === "click" && event.button >= 1 ) ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't check non-elements (trac-13208) + // Don't process clicks on disabled elements (trac-6911, trac-8165, trac-11382, trac-11764) + if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { + matchedHandlers = []; + matchedSelectors = {}; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (trac-13203) + sel = handleObj.selector + " "; + + if ( matchedSelectors[ sel ] === undefined ) { + matchedSelectors[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matchedSelectors[ sel ] ) { + matchedHandlers.push( handleObj ); + } + } + if ( matchedHandlers.length ) { + handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + cur = this; + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + addProp: function( name, hook ) { + Object.defineProperty( jQuery.Event.prototype, name, { + enumerable: true, + configurable: true, + + get: isFunction( hook ) ? + function() { + if ( this.originalEvent ) { + return hook( this.originalEvent ); + } + } : + function() { + if ( this.originalEvent ) { + return this.originalEvent[ name ]; + } + }, + + set: function( value ) { + Object.defineProperty( this, name, { + enumerable: true, + configurable: true, + writable: true, + value: value + } ); + } + } ); + }, + + fix: function( originalEvent ) { + return originalEvent[ jQuery.expando ] ? + originalEvent : + new jQuery.Event( originalEvent ); + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + click: { + + // Utilize native event to ensure correct state for checkable inputs + setup: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Claim the first handler + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + // dataPriv.set( el, "click", ... ) + leverageNative( el, "click", true ); + } + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Force setup before triggering a click + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + leverageNative( el, "click" ); + } + + // Return non-false to allow normal event-path propagation + return true; + }, + + // For cross-browser consistency, suppress native .click() on links + // Also prevent it if we're currently inside a leveraged native-event stack + _default: function( event ) { + var target = event.target; + return rcheckableType.test( target.type ) && + target.click && nodeName( target, "input" ) && + dataPriv.get( target, "click" ) || + nodeName( target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + } +}; + +// Ensure the presence of an event listener that handles manually-triggered +// synthetic events by interrupting progress until reinvoked in response to +// *native* events that it fires directly, ensuring that state changes have +// already occurred before other listeners are invoked. +function leverageNative( el, type, isSetup ) { + + // Missing `isSetup` indicates a trigger call, which must force setup through jQuery.event.add + if ( !isSetup ) { + if ( dataPriv.get( el, type ) === undefined ) { + jQuery.event.add( el, type, returnTrue ); + } + return; + } + + // Register the controller as a special universal handler for all event namespaces + dataPriv.set( el, type, false ); + jQuery.event.add( el, type, { + namespace: false, + handler: function( event ) { + var result, + saved = dataPriv.get( this, type ); + + if ( ( event.isTrigger & 1 ) && this[ type ] ) { + + // Interrupt processing of the outer synthetic .trigger()ed event + if ( !saved ) { + + // Store arguments for use when handling the inner native event + // There will always be at least one argument (an event object), so this array + // will not be confused with a leftover capture object. + saved = slice.call( arguments ); + dataPriv.set( this, type, saved ); + + // Trigger the native event and capture its result + this[ type ](); + result = dataPriv.get( this, type ); + dataPriv.set( this, type, false ); + + if ( saved !== result ) { + + // Cancel the outer synthetic event + event.stopImmediatePropagation(); + event.preventDefault(); + + return result; + } + + // If this is an inner synthetic event for an event with a bubbling surrogate + // (focus or blur), assume that the surrogate already propagated from triggering + // the native event and prevent that from happening again here. + // This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the + // bubbling surrogate propagates *after* the non-bubbling base), but that seems + // less bad than duplication. + } else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) { + event.stopPropagation(); + } + + // If this is a native event triggered above, everything is now in order + // Fire an inner synthetic event with the original arguments + } else if ( saved ) { + + // ...and capture the result + dataPriv.set( this, type, jQuery.event.trigger( + saved[ 0 ], + saved.slice( 1 ), + this + ) ); + + // Abort handling of the native event by all jQuery handlers while allowing + // native handlers on the same element to run. On target, this is achieved + // by stopping immediate propagation just on the jQuery event. However, + // the native event is re-wrapped by a jQuery one on each level of the + // propagation so the only way to stop it for jQuery is to stop it for + // everyone via native `stopPropagation()`. This is not a problem for + // focus/blur which don't bubble, but it does also stop click on checkboxes + // and radios. We accept this limitation. + event.stopPropagation(); + event.isImmediatePropagationStopped = returnTrue; + } + } + } ); +} + +jQuery.removeEvent = function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } +}; + +jQuery.Event = function( src, props ) { + + // Allow instantiation without the 'new' keyword + if ( !( this instanceof jQuery.Event ) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + + // Support: Android <=2.3 only + src.returnValue === false ? + returnTrue : + returnFalse; + + // Create target properties + // Support: Safari <=6 - 7 only + // Target should not be a text node (trac-504, trac-13143) + this.target = ( src.target && src.target.nodeType === 3 ) ? + src.target.parentNode : + src.target; + + this.currentTarget = src.currentTarget; + this.relatedTarget = src.relatedTarget; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || Date.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + isSimulated: false, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && !this.isSimulated ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Includes all common event props including KeyEvent and MouseEvent specific props +jQuery.each( { + altKey: true, + bubbles: true, + cancelable: true, + changedTouches: true, + ctrlKey: true, + detail: true, + eventPhase: true, + metaKey: true, + pageX: true, + pageY: true, + shiftKey: true, + view: true, + "char": true, + code: true, + charCode: true, + key: true, + keyCode: true, + button: true, + buttons: true, + clientX: true, + clientY: true, + offsetX: true, + offsetY: true, + pointerId: true, + pointerType: true, + screenX: true, + screenY: true, + targetTouches: true, + toElement: true, + touches: true, + which: true +}, jQuery.event.addProp ); + +jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) { + + function focusMappedHandler( nativeEvent ) { + if ( document.documentMode ) { + + // Support: IE 11+ + // Attach a single focusin/focusout handler on the document while someone wants + // focus/blur. This is because the former are synchronous in IE while the latter + // are async. In other browsers, all those handlers are invoked synchronously. + + // `handle` from private data would already wrap the event, but we need + // to change the `type` here. + var handle = dataPriv.get( this, "handle" ), + event = jQuery.event.fix( nativeEvent ); + event.type = nativeEvent.type === "focusin" ? "focus" : "blur"; + event.isSimulated = true; + + // First, handle focusin/focusout + handle( nativeEvent ); + + // ...then, handle focus/blur + // + // focus/blur don't bubble while focusin/focusout do; simulate the former by only + // invoking the handler at the lower level. + if ( event.target === event.currentTarget ) { + + // The setup part calls `leverageNative`, which, in turn, calls + // `jQuery.event.add`, so event handle will already have been set + // by this point. + handle( event ); + } + } else { + + // For non-IE browsers, attach a single capturing handler on the document + // while someone wants focusin/focusout. + jQuery.event.simulate( delegateType, nativeEvent.target, + jQuery.event.fix( nativeEvent ) ); + } + } + + jQuery.event.special[ type ] = { + + // Utilize native event if possible so blur/focus sequence is correct + setup: function() { + + var attaches; + + // Claim the first handler + // dataPriv.set( this, "focus", ... ) + // dataPriv.set( this, "blur", ... ) + leverageNative( this, type, true ); + + if ( document.documentMode ) { + + // Support: IE 9 - 11+ + // We use the same native handler for focusin & focus (and focusout & blur) + // so we need to coordinate setup & teardown parts between those events. + // Use `delegateType` as the key as `type` is already used by `leverageNative`. + attaches = dataPriv.get( this, delegateType ); + if ( !attaches ) { + this.addEventListener( delegateType, focusMappedHandler ); + } + dataPriv.set( this, delegateType, ( attaches || 0 ) + 1 ); + } else { + + // Return false to allow normal processing in the caller + return false; + } + }, + trigger: function() { + + // Force setup before trigger + leverageNative( this, type ); + + // Return non-false to allow normal event-path propagation + return true; + }, + + teardown: function() { + var attaches; + + if ( document.documentMode ) { + attaches = dataPriv.get( this, delegateType ) - 1; + if ( !attaches ) { + this.removeEventListener( delegateType, focusMappedHandler ); + dataPriv.remove( this, delegateType ); + } else { + dataPriv.set( this, delegateType, attaches ); + } + } else { + + // Return false to indicate standard teardown should be applied + return false; + } + }, + + // Suppress native focus or blur if we're currently inside + // a leveraged native-event stack + _default: function( event ) { + return dataPriv.get( event.target, type ); + }, + + delegateType: delegateType + }; + + // Support: Firefox <=44 + // Firefox doesn't have focus(in | out) events + // Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 + // + // Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 + // focus(in | out) events fire after focus & blur events, + // which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order + // Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 + // + // Support: IE 9 - 11+ + // To preserve relative focusin/focus & focusout/blur event order guaranteed on the 3.x branch, + // attach a single handler for both events in IE. + jQuery.event.special[ delegateType ] = { + setup: function() { + + // Handle: regular nodes (via `this.ownerDocument`), window + // (via `this.document`) & document (via `this`). + var doc = this.ownerDocument || this.document || this, + dataHolder = document.documentMode ? this : doc, + attaches = dataPriv.get( dataHolder, delegateType ); + + // Support: IE 9 - 11+ + // We use the same native handler for focusin & focus (and focusout & blur) + // so we need to coordinate setup & teardown parts between those events. + // Use `delegateType` as the key as `type` is already used by `leverageNative`. + if ( !attaches ) { + if ( document.documentMode ) { + this.addEventListener( delegateType, focusMappedHandler ); + } else { + doc.addEventListener( type, focusMappedHandler, true ); + } + } + dataPriv.set( dataHolder, delegateType, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this.document || this, + dataHolder = document.documentMode ? this : doc, + attaches = dataPriv.get( dataHolder, delegateType ) - 1; + + if ( !attaches ) { + if ( document.documentMode ) { + this.removeEventListener( delegateType, focusMappedHandler ); + } else { + doc.removeEventListener( type, focusMappedHandler, true ); + } + dataPriv.remove( dataHolder, delegateType ); + } else { + dataPriv.set( dataHolder, delegateType, attaches ); + } + } + }; +} ); + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +} ); + +jQuery.fn.extend( { + + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? + handleObj.origType + "." + handleObj.namespace : + handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + } +} ); + + +var + + // Support: IE <=10 - 11, Edge 12 - 13 only + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /\s*$/g; + +// Prefer a tbody over its parent table for containing new rows +function manipulationTarget( elem, content ) { + if ( nodeName( elem, "table" ) && + nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { + + return jQuery( elem ).children( "tbody" )[ 0 ] || elem; + } + + return elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) { + elem.type = elem.type.slice( 5 ); + } else { + elem.removeAttribute( "type" ); + } + + return elem; +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( dataPriv.hasData( src ) ) { + pdataOld = dataPriv.get( src ); + events = pdataOld.events; + + if ( events ) { + dataPriv.remove( dest, "handle events" ); + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( dataUser.hasData( src ) ) { + udataOld = dataUser.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + dataUser.set( dest, udataCur ); + } +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = flat( args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + valueIsFunction = isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( valueIsFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( valueIsFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (trac-8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Re-enable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !dataPriv.access( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl && !node.noModule ) { + jQuery._evalUrl( node.src, { + nonce: node.nonce || node.getAttribute( "nonce" ) + }, doc ); + } + } else { + + // Unwrap a CDATA section containing script contents. This shouldn't be + // needed as in XML documents they're already not visible when + // inspecting element contents and in HTML documents they have no + // meaning but we're preserving that logic for backwards compatibility. + // This will be removed completely in 4.0. See gh-4904. + DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc ); + } + } + } + } + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = nodes[ i ] ) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && isAttached( node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html; + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = isAttached( elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew jQuery#find here for performance reasons: + // https://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + cleanData: function( elems ) { + var data, elem, type, + special = jQuery.event.special, + i = 0; + + for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { + if ( acceptData( elem ) ) { + if ( ( data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataPriv.expando ] = undefined; + } + if ( elem[ dataUser.expando ] ) { + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataUser.expando ] = undefined; + } + } + } + } +} ); + +jQuery.fn.extend( { + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each( function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + } ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: Android <=4.0 only, PhantomJS 1 only + // .get() because push.apply(_, arraylike) throws on ancient WebKit + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); +var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); + +var rcustomProp = /^--/; + + +var getStyles = function( elem ) { + + // Support: IE <=11 only, Firefox <=30 (trac-15098, trac-14150) + // IE throws on elements created in popups + // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" + var view = elem.ownerDocument.defaultView; + + if ( !view || !view.opener ) { + view = window; + } + + return view.getComputedStyle( elem ); + }; + +var swap = function( elem, options, callback ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.call( elem ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; +}; + + +var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); + + + +( function() { + + // Executing both pixelPosition & boxSizingReliable tests require only one layout + // so they're executed at the same time to save the second computation. + function computeStyleTests() { + + // This is a singleton, we need to execute it only once + if ( !div ) { + return; + } + + container.style.cssText = "position:absolute;left:-11111px;width:60px;" + + "margin-top:1px;padding:0;border:0"; + div.style.cssText = + "position:relative;display:block;box-sizing:border-box;overflow:scroll;" + + "margin:auto;border:1px;padding:1px;" + + "width:60%;top:1%"; + documentElement.appendChild( container ).appendChild( div ); + + var divStyle = window.getComputedStyle( div ); + pixelPositionVal = divStyle.top !== "1%"; + + // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 + reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12; + + // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3 + // Some styles come back with percentage values, even though they shouldn't + div.style.right = "60%"; + pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36; + + // Support: IE 9 - 11 only + // Detect misreporting of content dimensions for box-sizing:border-box elements + boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36; + + // Support: IE 9 only + // Detect overflow:scroll screwiness (gh-3699) + // Support: Chrome <=64 + // Don't get tricked when zoom affects offsetWidth (gh-4029) + div.style.position = "absolute"; + scrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12; + + documentElement.removeChild( container ); + + // Nullify the div so it wouldn't be stored in the memory and + // it will also be a sign that checks already performed + div = null; + } + + function roundPixelMeasures( measure ) { + return Math.round( parseFloat( measure ) ); + } + + var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal, + reliableTrDimensionsVal, reliableMarginLeftVal, + container = document.createElement( "div" ), + div = document.createElement( "div" ); + + // Finish early in limited (non-browser) environments + if ( !div.style ) { + return; + } + + // Support: IE <=9 - 11 only + // Style of cloned element affects source element cloned (trac-8908) + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + jQuery.extend( support, { + boxSizingReliable: function() { + computeStyleTests(); + return boxSizingReliableVal; + }, + pixelBoxStyles: function() { + computeStyleTests(); + return pixelBoxStylesVal; + }, + pixelPosition: function() { + computeStyleTests(); + return pixelPositionVal; + }, + reliableMarginLeft: function() { + computeStyleTests(); + return reliableMarginLeftVal; + }, + scrollboxSize: function() { + computeStyleTests(); + return scrollboxSizeVal; + }, + + // Support: IE 9 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // 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 ) { + table = document.createElement( "table" ); + tr = document.createElement( "tr" ); + trChild = document.createElement( "div" ); + + table.style.cssText = "position:absolute;left:-11111px;border-collapse:separate"; + tr.style.cssText = "box-sizing:content-box;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, 10 ) + + parseInt( trStyle.borderTopWidth, 10 ) + + parseInt( trStyle.borderBottomWidth, 10 ) ) === tr.offsetHeight; + + documentElement.removeChild( table ); + } + return reliableTrDimensionsVal; + } + } ); +} )(); + + +function curCSS( elem, name, computed ) { + var width, minWidth, maxWidth, ret, + isCustomProp = rcustomProp.test( name ), + + // Support: Firefox 51+ + // Retrieving style before computed somehow + // fixes an issue with getting wrong values + // on detached elements + style = elem.style; + + computed = computed || getStyles( elem ); + + // getPropertyValue is needed for: + // .css('filter') (IE 9 only, trac-12537) + // .css('--customProperty) (gh-3144) + if ( computed ) { + + // Support: IE <=9 - 11+ + // IE only supports `"float"` in `getPropertyValue`; in computed styles + // it's only available as `"cssFloat"`. We no longer modify properties + // sent to `.css()` apart from camelCasing, so we need to check both. + // Normally, this would create difference in behavior: if + // `getPropertyValue` returns an empty string, the value returned + // by `.css()` would be `undefined`. This is usually the case for + // disconnected elements. However, in IE even disconnected elements + // with no styles return `"none"` for `getPropertyValue( "float" )` + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( isCustomProp && ret ) { + + // Support: Firefox 105+, Chrome <=105+ + // Spec requires trimming whitespace for custom properties (gh-4926). + // Firefox only trims leading whitespace. Chrome just collapses + // both leading & trailing whitespace to a single space. + // + // Fall back to `undefined` if empty string returned. + // This collapses a missing definition with property defined + // and set to an empty string but there's no standard API + // allowing us to differentiate them without a performance penalty + // and returning `undefined` aligns with older jQuery. + // + // rtrimCSS treats U+000D CARRIAGE RETURN and U+000C FORM FEED + // as whitespace while CSS does not, but this is not a problem + // because CSS preprocessing replaces them with U+000A LINE FEED + // (which *is* CSS whitespace) + // https://www.w3.org/TR/css-syntax-3/#input-preprocessing + ret = ret.replace( rtrimCSS, "$1" ) || undefined; + } + + if ( ret === "" && !isAttached( elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Android Browser returns percentage for some values, + // but width seems to be reliably pixels. + // This is against the CSSOM draft spec: + // https://drafts.csswg.org/cssom/#resolved-values + if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret !== undefined ? + + // Support: IE <=9 - 11 only + // IE returns zIndex value as an integer. + ret + "" : + ret; +} + + +function addGetHookIf( conditionFn, hookFn ) { + + // Define the hook, we'll check on the first run if it's really needed. + return { + get: function() { + if ( conditionFn() ) { + + // Hook not needed (or it's not possible to use it due + // to missing dependency), remove it. + delete this.get; + return; + } + + // Hook needed; redefine it so that the support test is not executed again. + return ( this.get = hookFn ).apply( this, arguments ); + } + }; +} + + +var cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style, + vendorProps = {}; + +// Return a vendor-prefixed property or undefined +function vendorPropName( name ) { + + // Check for vendor prefixed names + var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in emptyStyle ) { + return name; + } + } +} + +// Return a potentially-mapped jQuery.cssProps or vendor prefixed property +function finalPropName( name ) { + var final = jQuery.cssProps[ name ] || vendorProps[ name ]; + + if ( final ) { + return final; + } + if ( name in emptyStyle ) { + return name; + } + return vendorProps[ name ] = vendorPropName( name ) || name; +} + + +var + + // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: "0", + fontWeight: "400" + }; + +function setPositiveNumber( _elem, value, subtract ) { + + // Any relative (+/-) values have already been + // normalized at this point + var matches = rcssNum.exec( value ); + return matches ? + + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : + value; +} + +function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) { + var i = dimension === "width" ? 1 : 0, + extra = 0, + delta = 0, + marginDelta = 0; + + // Adjustment may not be necessary + if ( box === ( isBorderBox ? "border" : "content" ) ) { + return 0; + } + + for ( ; i < 4; i += 2 ) { + + // Both box models exclude margin + // Count margin delta separately to only add it after scroll gutter adjustment. + // This is needed to make negative margins work with `outerHeight( true )` (gh-3982). + if ( box === "margin" ) { + marginDelta += jQuery.css( elem, box + cssExpand[ i ], true, styles ); + } + + // If we get here with a content-box, we're seeking "padding" or "border" or "margin" + if ( !isBorderBox ) { + + // Add padding + delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // For "border" or "margin", add border + if ( box !== "padding" ) { + delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + + // But still keep track of it otherwise + } else { + extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + + // If we get here with a border-box (content + padding + border), we're seeking "content" or + // "padding" or "margin" + } else { + + // For "content", subtract padding + if ( box === "content" ) { + delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // For "content" or "padding", subtract border + if ( box !== "margin" ) { + delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + // Account for positive content-box scroll gutter when requested by providing computedVal + if ( !isBorderBox && computedVal >= 0 ) { + + // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border + // Assuming integer scroll gutter, subtract the rest and round down + delta += Math.max( 0, Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + computedVal - + delta - + extra - + 0.5 + + // If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter + // Use an explicit zero to avoid NaN (gh-3964) + ) ) || 0; + } + + return delta + marginDelta; +} + +function getWidthOrHeight( elem, dimension, extra ) { + + // Start with computed style + var styles = getStyles( elem ), + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322). + // Fake content-box until we know it's needed to know the true value. + boxSizingNeeded = !support.boxSizingReliable() || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + valueIsBorderBox = isBorderBox, + + val = curCSS( elem, dimension, styles ), + offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ); + + // Support: Firefox <=54 + // Return a confounding non-pixel value or feign ignorance, as appropriate. + if ( rnumnonpx.test( val ) ) { + if ( !extra ) { + return val; + } + val = "auto"; + } + + + // Support: IE 9 - 11 only + // Use offsetWidth/offsetHeight for when box sizing is unreliable. + // In those cases, the computed value can be trusted to be border-box. + if ( ( !support.boxSizingReliable() && isBorderBox || + + // Support: IE 10 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Interestingly, in some cases IE 9 doesn't suffer from this issue. + !support.reliableTrDimensions() && nodeName( elem, "tr" ) || + + // Fall back to offsetWidth/offsetHeight when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) + val === "auto" || + + // Support: Android <=4.1 - 4.3 only + // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) + !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) && + + // Make sure the element is visible & connected + elem.getClientRects().length ) { + + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // Where available, offsetWidth/offsetHeight approximate border box dimensions. + // Where not available (e.g., SVG), assume unreliable box-sizing and interpret the + // retrieved value as a content box dimension. + valueIsBorderBox = offsetProp in elem; + if ( valueIsBorderBox ) { + val = elem[ offsetProp ]; + } + } + + // Normalize "" and auto + val = parseFloat( val ) || 0; + + // Adjust for the element's box model + return ( val + + boxModelAdjustment( + elem, + dimension, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles, + + // Provide the current computed size to request scroll gutter calculation (gh-3589) + val + ) + ) + "px"; +} + +jQuery.extend( { + + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + animationIterationCount: true, + aspectRatio: true, + borderImageSlice: true, + columnCount: true, + flexGrow: true, + flexShrink: true, + fontWeight: true, + gridArea: true, + gridColumn: true, + gridColumnEnd: true, + gridColumnStart: true, + gridRow: true, + gridRowEnd: true, + gridRowStart: true, + lineHeight: true, + opacity: true, + order: true, + orphans: true, + scale: true, + widows: true, + zIndex: true, + zoom: true, + + // SVG-related + fillOpacity: true, + floodOpacity: true, + stopOpacity: true, + strokeMiterlimit: true, + strokeOpacity: true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: {}, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ), + style = elem.style; + + // Make sure that we're working with the right name. We don't + // want to query the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Gets hook for the prefixed version, then unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // Convert "+=" or "-=" to relative numbers (trac-7345) + if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { + value = adjustCSS( elem, name, ret ); + + // Fixes bug trac-9237 + type = "number"; + } + + // Make sure that null and NaN values aren't set (trac-7116) + if ( value == null || value !== value ) { + return; + } + + // If a number was passed in, add the unit (except for certain CSS properties) + // The isCustomProp check can be removed in jQuery 4.0 when we only auto-append + // "px" to a few hardcoded values. + if ( type === "number" && !isCustomProp ) { + value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); + } + + // background-* props affect original clone's values + if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !( "set" in hooks ) || + ( value = hooks.set( elem, value, extra ) ) !== undefined ) { + + if ( isCustomProp ) { + style.setProperty( name, value ); + } else { + style[ name ] = value; + } + } + + } else { + + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && + ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { + + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var val, num, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ); + + // Make sure that we're working with the right name. We don't + // want to modify the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Try prefixed name followed by the unprefixed name + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + // Convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Make numeric if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || isFinite( num ) ? num || 0 : val; + } + + return val; + } +} ); + +jQuery.each( [ "height", "width" ], function( _i, dimension ) { + jQuery.cssHooks[ dimension ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + + // Certain elements can have dimension info if we invisibly show them + // but it must have a current display style that would benefit + return rdisplayswap.test( jQuery.css( elem, "display" ) ) && + + // Support: Safari 8+ + // Table columns in Safari have non-zero offsetWidth & zero + // getBoundingClientRect().width unless display is changed. + // Support: IE <=11 only + // 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 ); + } + }, + + set: function( elem, value, extra ) { + var matches, + styles = getStyles( elem ), + + // Only read styles.position if the test has a chance to fail + // to avoid forcing a reflow. + scrollboxSizeBuggy = !support.scrollboxSize() && + styles.position === "absolute", + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991) + boxSizingNeeded = scrollboxSizeBuggy || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + subtract = extra ? + boxModelAdjustment( + elem, + dimension, + extra, + isBorderBox, + styles + ) : + 0; + + // Account for unreliable border-box dimensions by comparing offset* to computed and + // faking a content-box to get border and padding (gh-3699) + if ( isBorderBox && scrollboxSizeBuggy ) { + subtract -= Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + parseFloat( styles[ dimension ] ) - + boxModelAdjustment( elem, dimension, "border", false, styles ) - + 0.5 + ); + } + + // Convert to pixels if value adjustment is needed + if ( subtract && ( matches = rcssNum.exec( value ) ) && + ( matches[ 3 ] || "px" ) !== "px" ) { + + elem.style[ dimension ] = value; + value = jQuery.css( elem, dimension ); + } + + return setPositiveNumber( elem, value, subtract ); + } + }; +} ); + +jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, + function( elem, computed ) { + if ( computed ) { + return ( parseFloat( curCSS( elem, "marginLeft" ) ) || + elem.getBoundingClientRect().left - + swap( elem, { marginLeft: 0 }, function() { + return elem.getBoundingClientRect().left; + } ) + ) + "px"; + } + } +); + +// These hooks are used by animate to expand properties +jQuery.each( { + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i = 0, + expanded = {}, + + // Assumes a single number if not a string + parts = typeof value === "string" ? value.split( " " ) : [ value ]; + + for ( ; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( prefix !== "margin" ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +} ); + +jQuery.fn.extend( { + css: function( name, value ) { + return access( this, function( elem, name, value ) { + var styles, len, + map = {}, + i = 0; + + if ( Array.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + } +} ); + + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || jQuery.easing._default; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + // Use a property on the element directly when it is not a DOM element, + // or when there is no matching style property that exists. + if ( tween.elem.nodeType !== 1 || + tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { + return tween.elem[ tween.prop ]; + } + + // Passing an empty string as a 3rd parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails. + // Simple values such as "10px" are parsed to Float; + // complex values such as "rotate(1rad)" are returned as-is. + result = jQuery.css( tween.elem, tween.prop, "" ); + + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + + // Use step hook for back compat. + // Use cssHook if its there. + // Use .style if available and use plain properties where available. + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.nodeType === 1 && ( + jQuery.cssHooks[ tween.prop ] || + tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Support: IE <=9 only +// Panic based approach to setting things on disconnected nodes +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p * Math.PI ) / 2; + }, + _default: "swing" +}; + +jQuery.fx = Tween.prototype.init; + +// Back compat <1.8 extension point +jQuery.fx.step = {}; + + + + +var + fxNow, inProgress, + rfxtypes = /^(?:toggle|show|hide)$/, + rrun = /queueHooks$/; + +function schedule() { + if ( inProgress ) { + if ( document.hidden === false && window.requestAnimationFrame ) { + window.requestAnimationFrame( schedule ); + } else { + window.setTimeout( schedule, jQuery.fx.interval ); + } + + jQuery.fx.tick(); + } +} + +// Animations created synchronously will run synchronously +function createFxNow() { + window.setTimeout( function() { + fxNow = undefined; + } ); + return ( fxNow = Date.now() ); +} + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + i = 0, + attrs = { height: type }; + + // If we include width, step value is 1 to do all cssExpand values, + // otherwise step value is 2 to skip over Left and Right + includeWidth = includeWidth ? 1 : 0; + for ( ; i < 4; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +function createTween( value, prop, animation ) { + var tween, + collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { + + // We're done with this property + return tween; + } + } +} + +function defaultPrefilter( elem, props, opts ) { + var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, + isBox = "width" in props || "height" in props, + anim = this, + orig = {}, + style = elem.style, + hidden = elem.nodeType && isHiddenWithinTree( elem ), + dataShow = dataPriv.get( elem, "fxshow" ); + + // Queue-skipping animations hijack the fx hooks + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always( function() { + + // Ensure the complete handler is called before this completes + anim.always( function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + } ); + } ); + } + + // Detect show/hide animations + for ( prop in props ) { + value = props[ prop ]; + if ( rfxtypes.test( value ) ) { + delete props[ prop ]; + toggle = toggle || value === "toggle"; + if ( value === ( hidden ? "hide" : "show" ) ) { + + // Pretend to be hidden if this is a "show" and + // there is still data from a stopped show/hide + if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { + hidden = true; + + // Ignore all other no-op show/hide data + } else { + continue; + } + } + orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); + } + } + + // Bail out if this is a no-op like .hide().hide() + propTween = !jQuery.isEmptyObject( props ); + if ( !propTween && jQuery.isEmptyObject( orig ) ) { + return; + } + + // Restrict "overflow" and "display" styles during box animations + if ( isBox && elem.nodeType === 1 ) { + + // Support: IE <=9 - 11, Edge 12 - 15 + // Record all 3 overflow attributes because IE does not infer the shorthand + // from identically-valued overflowX and overflowY and Edge just mirrors + // the overflowX value there. + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Identify a display type, preferring old show/hide data over the CSS cascade + restoreDisplay = dataShow && dataShow.display; + if ( restoreDisplay == null ) { + restoreDisplay = dataPriv.get( elem, "display" ); + } + display = jQuery.css( elem, "display" ); + if ( display === "none" ) { + if ( restoreDisplay ) { + display = restoreDisplay; + } else { + + // Get nonempty value(s) by temporarily forcing visibility + showHide( [ elem ], true ); + restoreDisplay = elem.style.display || restoreDisplay; + display = jQuery.css( elem, "display" ); + showHide( [ elem ] ); + } + } + + // Animate inline elements as inline-block + if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { + if ( jQuery.css( elem, "float" ) === "none" ) { + + // Restore the original display value at the end of pure show/hide animations + if ( !propTween ) { + anim.done( function() { + style.display = restoreDisplay; + } ); + if ( restoreDisplay == null ) { + display = style.display; + restoreDisplay = display === "none" ? "" : display; + } + } + style.display = "inline-block"; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + anim.always( function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + } ); + } + + // Implement show/hide animations + propTween = false; + for ( prop in orig ) { + + // General show/hide setup for this element animation + if ( !propTween ) { + if ( dataShow ) { + if ( "hidden" in dataShow ) { + hidden = dataShow.hidden; + } + } else { + dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); + } + + // Store hidden/visible for toggle so `.stop().toggle()` "reverses" + if ( toggle ) { + dataShow.hidden = !hidden; + } + + // Show elements before animating them + if ( hidden ) { + showHide( [ elem ], true ); + } + + /* eslint-disable no-loop-func */ + + anim.done( function() { + + /* eslint-enable no-loop-func */ + + // The final step of a "hide" animation is actually hiding the element + if ( !hidden ) { + showHide( [ elem ] ); + } + dataPriv.remove( elem, "fxshow" ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + } ); + } + + // Per-property setup + propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = propTween.start; + if ( hidden ) { + propTween.end = propTween.start; + propTween.start = 0; + } + } + } +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( Array.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + + if ( index !== name ) { + props[ name ] = value; + delete props[ index ]; + } + + hooks = jQuery.cssHooks[ name ]; + if ( hooks && "expand" in hooks ) { + value = hooks.expand( value ); + delete props[ name ]; + + // Not quite $.extend, this won't overwrite existing keys. + // Reusing 'index' because we have the correct "name" + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; + } + } + } else { + specialEasing[ name ] = easing; + } + } +} + +function Animation( elem, properties, options ) { + var result, + stopped, + index = 0, + length = Animation.prefilters.length, + deferred = jQuery.Deferred().always( function() { + + // Don't match elem in the :animated selector + delete tick.elem; + } ), + tick = function() { + if ( stopped ) { + return false; + } + var currentTime = fxNow || createFxNow(), + remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), + + // Support: Android 2.3 only + // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (trac-12497) + temp = remaining / animation.duration || 0, + percent = 1 - temp, + index = 0, + length = animation.tweens.length; + + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( percent ); + } + + deferred.notifyWith( elem, [ animation, percent, remaining ] ); + + // If there's more to do, yield + if ( percent < 1 && length ) { + return remaining; + } + + // If this was an empty animation, synthesize a final progress notification + if ( !length ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + } + + // Resolve the animation and report its conclusion + deferred.resolveWith( elem, [ animation ] ); + return false; + }, + animation = deferred.promise( { + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { + specialEasing: {}, + easing: jQuery.easing._default + }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + + // If we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + if ( stopped ) { + return this; + } + stopped = true; + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // Resolve when we played the last frame; otherwise, reject + if ( gotoEnd ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + } ), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length; index++ ) { + result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + if ( isFunction( result.stop ) ) { + jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = + result.stop.bind( result ); + } + return result; + } + } + + jQuery.map( props, createTween, animation ); + + if ( isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + // Attach callbacks from options + animation + .progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); + + jQuery.fx.timer( + jQuery.extend( tick, { + elem: elem, + anim: animation, + queue: animation.opts.queue + } ) + ); + + return animation; +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweeners: { + "*": [ function( prop, value ) { + var tween = this.createTween( prop, value ); + adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); + return tween; + } ] + }, + + tweener: function( props, callback ) { + if ( isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.match( rnothtmlwhite ); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length; index++ ) { + prop = props[ index ]; + Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; + Animation.tweeners[ prop ].unshift( callback ); + } + }, + + prefilters: [ defaultPrefilter ], + + prefilter: function( callback, prepend ) { + if ( prepend ) { + Animation.prefilters.unshift( callback ); + } else { + Animation.prefilters.push( callback ); + } + } +} ); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !isFunction( easing ) && easing + }; + + // Go to the end state if fx are off + if ( jQuery.fx.off ) { + opt.duration = 0; + + } else { + if ( typeof opt.duration !== "number" ) { + if ( opt.duration in jQuery.fx.speeds ) { + opt.duration = jQuery.fx.speeds[ opt.duration ]; + + } else { + opt.duration = jQuery.fx.speeds._default; + } + } + } + + // Normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.fn.extend( { + fadeTo: function( speed, to, easing, callback ) { + + // Show any hidden elements after setting opacity to 0 + return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() + + // Animate to the value specified + .end().animate( { opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations, or finishing resolves immediately + if ( empty || dataPriv.get( this, "finish" ) ) { + anim.stop( true ); + } + }; + + doAnimation.finish = doAnimation; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue ) { + this.queue( type || "fx", [] ); + } + + return this.each( function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = dataPriv.get( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && + ( type == null || timers[ index ].queue === type ) ) { + + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // Start the next in the queue if the last step wasn't forced. + // Timers currently will call their complete callbacks, which + // will dequeue but only if they were gotoEnd. + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + } ); + }, + finish: function( type ) { + if ( type !== false ) { + type = type || "fx"; + } + return this.each( function() { + var index, + data = dataPriv.get( this ), + queue = data[ type + "queue" ], + hooks = data[ type + "queueHooks" ], + timers = jQuery.timers, + length = queue ? queue.length : 0; + + // Enable finishing flag on private data + data.finish = true; + + // Empty the queue first + jQuery.queue( this, type, [] ); + + if ( hooks && hooks.stop ) { + hooks.stop.call( this, true ); + } + + // Look for any active animations, and finish them + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && timers[ index ].queue === type ) { + timers[ index ].anim.stop( true ); + timers.splice( index, 1 ); + } + } + + // Look for any animations in the old queue and finish them + for ( index = 0; index < length; index++ ) { + if ( queue[ index ] && queue[ index ].finish ) { + queue[ index ].finish.call( this ); + } + } + + // Turn off finishing flag + delete data.finish; + } ); + } +} ); + +jQuery.each( [ "toggle", "show", "hide" ], function( _i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +} ); + +// Generate shortcuts for custom animations +jQuery.each( { + slideDown: genFx( "show" ), + slideUp: genFx( "hide" ), + slideToggle: genFx( "toggle" ), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +} ); + +jQuery.timers = []; +jQuery.fx.tick = function() { + var timer, + i = 0, + timers = jQuery.timers; + + fxNow = Date.now(); + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + + // Run the timer and safely remove it when done (allowing for external removal) + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } + fxNow = undefined; +}; + +jQuery.fx.timer = function( timer ) { + jQuery.timers.push( timer ); + jQuery.fx.start(); +}; + +jQuery.fx.interval = 13; +jQuery.fx.start = function() { + if ( inProgress ) { + return; + } + + inProgress = true; + schedule(); +}; + +jQuery.fx.stop = function() { + inProgress = null; +}; + +jQuery.fx.speeds = { + slow: 600, + fast: 200, + + // Default speed + _default: 400 +}; + + +// Based off of the plugin by Clint Helfers, with permission. +jQuery.fn.delay = function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = window.setTimeout( next, time ); + hooks.stop = function() { + window.clearTimeout( timeout ); + }; + } ); +}; + + +( function() { + var input = document.createElement( "input" ), + select = document.createElement( "select" ), + opt = select.appendChild( document.createElement( "option" ) ); + + input.type = "checkbox"; + + // Support: Android <=4.3 only + // Default value for a checkbox should be "on" + support.checkOn = input.value !== ""; + + // Support: IE <=11 only + // Must access selectedIndex to make default options select + support.optSelected = opt.selected; + + // Support: IE <=11 only + // An input loses its value after becoming a radio + input = document.createElement( "input" ); + input.value = "t"; + input.type = "radio"; + support.radioValue = input.value === "t"; +} )(); + + +var boolHook, + attrHandle = jQuery.expr.attrHandle; + +jQuery.fn.extend( { + attr: function( name, value ) { + return access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each( function() { + jQuery.removeAttr( this, name ); + } ); + } +} ); + +jQuery.extend( { + attr: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set attributes on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + // Attribute hooks are determined by the lowercase version + // Grab necessary hook if one is defined + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + hooks = jQuery.attrHooks[ name.toLowerCase() ] || + ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); + } + + if ( value !== undefined ) { + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + } + + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + elem.setAttribute( name, value + "" ); + return value; + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + ret = jQuery.find.attr( elem, name ); + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? undefined : ret; + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !support.radioValue && value === "radio" && + nodeName( elem, "input" ) ) { + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + removeAttr: function( elem, value ) { + var name, + i = 0, + + // Attribute names can contain non-HTML whitespace characters + // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 + attrNames = value && value.match( rnothtmlwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( ( name = attrNames[ i++ ] ) ) { + elem.removeAttribute( name ); + } + } + } +} ); + +// Hooks for boolean attributes +boolHook = { + set: function( elem, value, name ) { + if ( value === false ) { + + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + elem.setAttribute( name, name ); + } + return name; + } +}; + +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( _i, name ) { + var getter = attrHandle[ name ] || jQuery.find.attr; + + attrHandle[ name ] = function( elem, name, isXML ) { + var ret, handle, + lowercaseName = name.toLowerCase(); + + if ( !isXML ) { + + // Avoid an infinite loop by temporarily removing this function from the getter + handle = attrHandle[ lowercaseName ]; + attrHandle[ lowercaseName ] = ret; + ret = getter( elem, name, isXML ) != null ? + lowercaseName : + null; + attrHandle[ lowercaseName ] = handle; + } + return ret; + }; +} ); + + + + +var rfocusable = /^(?:input|select|textarea|button)$/i, + rclickable = /^(?:a|area)$/i; + +jQuery.fn.extend( { + prop: function( name, value ) { + return access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + return this.each( function() { + delete this[ jQuery.propFix[ name ] || name ]; + } ); + } +} ); + +jQuery.extend( { + prop: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set properties on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + return ( elem[ name ] = value ); + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + return elem[ name ]; + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + + // Support: IE <=9 - 11 only + // elem.tabIndex doesn't always return the + // correct value when it hasn't been explicitly set + // Use proper attribute retrieval (trac-12072) + var tabindex = jQuery.find.attr( elem, "tabindex" ); + + if ( tabindex ) { + return parseInt( tabindex, 10 ); + } + + if ( + rfocusable.test( elem.nodeName ) || + rclickable.test( elem.nodeName ) && + elem.href + ) { + return 0; + } + + return -1; + } + } + }, + + propFix: { + "for": "htmlFor", + "class": "className" + } +} ); + +// Support: IE <=11 only +// Accessing the selectedIndex property +// forces the browser to respect setting selected +// on the option +// The getter ensures a default option is selected +// when in an optgroup +// eslint rule "no-unused-expressions" is disabled for this code +// since it considers such accessions noop +if ( !support.optSelected ) { + jQuery.propHooks.selected = { + get: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent && parent.parentNode ) { + parent.parentNode.selectedIndex; + } + return null; + }, + set: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + }; +} + +jQuery.each( [ + "tabIndex", + "readOnly", + "maxLength", + "cellSpacing", + "cellPadding", + "rowSpan", + "colSpan", + "useMap", + "frameBorder", + "contentEditable" +], function() { + jQuery.propFix[ this.toLowerCase() ] = this; +} ); + + + + + // Strip and collapse whitespace according to HTML spec + // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace + function stripAndCollapse( value ) { + var tokens = value.match( rnothtmlwhite ) || []; + return tokens.join( " " ); + } + + +function getClass( elem ) { + return elem.getAttribute && elem.getAttribute( "class" ) || ""; +} + +function classesToArray( value ) { + if ( Array.isArray( value ) ) { + return value; + } + if ( typeof value === "string" ) { + return value.match( rnothtmlwhite ) || []; + } + return []; +} + +jQuery.fn.extend( { + addClass: function( value ) { + var classNames, cur, curValue, className, i, finalValue; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + classNames = classesToArray( value ); + + if ( classNames.length ) { + return this.each( function() { + curValue = getClass( this ); + cur = this.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + for ( i = 0; i < classNames.length; i++ ) { + className = classNames[ i ]; + if ( cur.indexOf( " " + className + " " ) < 0 ) { + cur += className + " "; + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + this.setAttribute( "class", finalValue ); + } + } + } ); + } + + return this; + }, + + removeClass: function( value ) { + var classNames, cur, curValue, className, i, finalValue; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( !arguments.length ) { + return this.attr( "class", "" ); + } + + classNames = classesToArray( value ); + + if ( classNames.length ) { + return this.each( function() { + curValue = getClass( this ); + + // This expression is here for better compressibility (see addClass) + cur = this.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + for ( i = 0; i < classNames.length; i++ ) { + className = classNames[ i ]; + + // Remove *all* instances + while ( cur.indexOf( " " + className + " " ) > -1 ) { + cur = cur.replace( " " + className + " ", " " ); + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + this.setAttribute( "class", finalValue ); + } + } + } ); + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var classNames, className, i, self, + type = typeof value, + isValidValue = type === "string" || Array.isArray( value ); + + if ( isFunction( value ) ) { + return this.each( function( i ) { + jQuery( this ).toggleClass( + value.call( this, i, getClass( this ), stateVal ), + stateVal + ); + } ); + } + + if ( typeof stateVal === "boolean" && isValidValue ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + classNames = classesToArray( value ); + + return this.each( function() { + if ( isValidValue ) { + + // Toggle individual class names + self = jQuery( this ); + + for ( i = 0; i < classNames.length; i++ ) { + className = classNames[ i ]; + + // Check each className given, space separated list + if ( self.hasClass( className ) ) { + self.removeClass( className ); + } else { + self.addClass( className ); + } + } + + // Toggle whole class name + } else if ( value === undefined || type === "boolean" ) { + className = getClass( this ); + if ( className ) { + + // Store className if set + dataPriv.set( this, "__className__", className ); + } + + // If the element has a class name or if we're passed `false`, + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + if ( this.setAttribute ) { + this.setAttribute( "class", + className || value === false ? + "" : + dataPriv.get( this, "__className__" ) || "" + ); + } + } + } ); + }, + + hasClass: function( selector ) { + var className, elem, + i = 0; + + className = " " + selector + " "; + while ( ( elem = this[ i++ ] ) ) { + if ( elem.nodeType === 1 && + ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { + return true; + } + } + + return false; + } +} ); + + + + +var rreturn = /\r/g; + +jQuery.fn.extend( { + val: function( value ) { + var hooks, ret, valueIsFunction, + elem = this[ 0 ]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || + jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && + "get" in hooks && + ( ret = hooks.get( elem, "value" ) ) !== undefined + ) { + return ret; + } + + ret = elem.value; + + // Handle most common string cases + if ( typeof ret === "string" ) { + return ret.replace( rreturn, "" ); + } + + // Handle cases where value is null/undef or number + return ret == null ? "" : ret; + } + + return; + } + + valueIsFunction = isFunction( value ); + + return this.each( function( i ) { + var val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( valueIsFunction ) { + val = value.call( this, i, jQuery( this ).val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + + } else if ( typeof val === "number" ) { + val += ""; + + } else if ( Array.isArray( val ) ) { + val = jQuery.map( val, function( value ) { + return value == null ? "" : value + ""; + } ); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + } ); + } +} ); + +jQuery.extend( { + valHooks: { + option: { + get: function( elem ) { + + var val = jQuery.find.attr( elem, "value" ); + return val != null ? + val : + + // Support: IE <=10 - 11 only + // option.text throws exceptions (trac-14686, trac-14858) + // Strip and collapse whitespace + // https://html.spec.whatwg.org/#strip-and-collapse-whitespace + stripAndCollapse( jQuery.text( elem ) ); + } + }, + select: { + get: function( elem ) { + var value, option, i, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one", + values = one ? null : [], + max = one ? index + 1 : options.length; + + if ( index < 0 ) { + i = max; + + } else { + i = one ? index : 0; + } + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Support: IE <=9 only + // IE8-9 doesn't update selected after form reset (trac-2551) + if ( ( option.selected || i === index ) && + + // Don't return options that are disabled or in a disabled optgroup + !option.disabled && + ( !option.parentNode.disabled || + !nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var optionSet, option, + options = elem.options, + values = jQuery.makeArray( value ), + i = options.length; + + while ( i-- ) { + option = options[ i ]; + + /* eslint-disable no-cond-assign */ + + if ( option.selected = + jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 + ) { + optionSet = true; + } + + /* eslint-enable no-cond-assign */ + } + + // Force browsers to behave consistently when non-matching value is set + if ( !optionSet ) { + elem.selectedIndex = -1; + } + return values; + } + } + } +} ); + +// Radios and checkboxes getter/setter +jQuery.each( [ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + set: function( elem, value ) { + if ( Array.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); + } + } + }; + if ( !support.checkOn ) { + jQuery.valHooks[ this ].get = function( elem ) { + return elem.getAttribute( "value" ) === null ? "on" : elem.value; + }; + } +} ); + + + + +// Return jQuery for attributes-only inclusion +var location = window.location; + +var nonce = { guid: Date.now() }; + +var rquery = ( /\?/ ); + + + +// Cross-browser xml parsing +jQuery.parseXML = function( data ) { + var xml, parserErrorElem; + if ( !data || typeof data !== "string" ) { + return null; + } + + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); + } catch ( e ) {} + + 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; +}; + + +var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + stopPropagationCallback = function( e ) { + e.stopPropagation(); + }; + +jQuery.extend( jQuery.event, { + + trigger: function( event, data, elem, onlyHandlers ) { + + var i, cur, tmp, bubbleType, ontype, handle, special, lastElement, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; + + cur = lastElement = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "." ) > -1 ) { + + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split( "." ); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf( ":" ) < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join( "." ); + event.rnamespace = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (trac-9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (trac-9724) + if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === ( elem.ownerDocument || document ) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { + lastElement = cur; + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( dataPriv.get( cur, "events" ) || Object.create( null ) )[ event.type ] && + dataPriv.get( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( ( !special._default || + special._default.apply( eventPath.pop(), data ) === false ) && + acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name as the event. + // Don't do default actions on window, that's where global variables be (trac-6170) + if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + + if ( event.isPropagationStopped() ) { + lastElement.addEventListener( type, stopPropagationCallback ); + } + + elem[ type ](); + + if ( event.isPropagationStopped() ) { + lastElement.removeEventListener( type, stopPropagationCallback ); + } + + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + // Piggyback on a donor event to simulate a different one + // Used only for `focus(in | out)` events + simulate: function( type, elem, event ) { + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true + } + ); + + jQuery.event.trigger( e, null, elem ); + } + +} ); + +jQuery.fn.extend( { + + trigger: function( type, data ) { + return this.each( function() { + jQuery.event.trigger( type, data, this ); + } ); + }, + triggerHandler: function( type, data ) { + var elem = this[ 0 ]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +} ); + + +var + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, + rsubmittable = /^(?:input|select|textarea|keygen)/i; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( Array.isArray( obj ) ) { + + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + + // Item is non-scalar (array or object), encode its numeric index. + buildParams( + prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", + v, + traditional, + add + ); + } + } ); + + } else if ( !traditional && toType( obj ) === "object" ) { + + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + + // Serialize scalar item. + add( prefix, obj ); + } +} + +// Serialize an array of form elements or a set of +// key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, valueOrFunction ) { + + // If value is a function, invoke it and use its return value + var value = isFunction( valueOrFunction ) ? + valueOrFunction() : + valueOrFunction; + + s[ s.length ] = encodeURIComponent( key ) + "=" + + encodeURIComponent( value == null ? "" : value ); + }; + + if ( a == null ) { + return ""; + } + + // If an array was passed in, assume that it is an array of form elements. + if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + } ); + + } else { + + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ); +}; + +jQuery.fn.extend( { + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map( function() { + + // 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() { + 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 ) { + var val = jQuery( this ).val(); + + if ( val == null ) { + return null; + } + + if ( Array.isArray( val ) ) { + return jQuery.map( val, function( val ) { + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ); + } + + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ).get(); + } +} ); + + +var + r20 = /%20/g, + rhash = /#.*$/, + rantiCache = /([?&])_=[^&]*/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, + + // trac-7653, trac-8125, trac-8152: local protocol detection + rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (trac-10098); must appease lint and evade compression + allTypes = "*/".concat( "*" ), + + // Anchor tag for parsing the document origin + originAnchor = document.createElement( "a" ); + +originAnchor.href = location.href; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, + i = 0, + dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; + + if ( isFunction( func ) ) { + + // For each dataType in the dataTypeExpression + while ( ( dataType = dataTypes[ i++ ] ) ) { + + // Prepend if requested + if ( dataType[ 0 ] === "+" ) { + dataType = dataType.slice( 1 ) || "*"; + ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); + + // Otherwise append + } else { + ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); + } + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { + + var inspected = {}, + seekingTransport = ( structure === transports ); + + function inspect( dataType ) { + var selected; + inspected[ dataType ] = true; + jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { + var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); + if ( typeof dataTypeOrTransport === "string" && + !seekingTransport && !inspected[ dataTypeOrTransport ] ) { + + options.dataTypes.unshift( dataTypeOrTransport ); + inspect( dataTypeOrTransport ); + return false; + } else if ( seekingTransport ) { + return !( selected = dataTypeOrTransport ); + } + } ); + return selected; + } + + return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes trac-9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } + + return target; +} + +/* Handles responses to an ajax request: + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes; + + // Remove auto dataType and get content-type in the process + while ( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +/* Chain conversions given the request and the original response + * Also sets the responseXXX fields on the jqXHR instance + */ +function ajaxConvert( s, response, jqXHR, isSuccess ) { + var conv2, current, conv, tmp, prev, + converters = {}, + + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(); + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + current = dataTypes.shift(); + + // Convert to each sequential dataType + while ( current ) { + + if ( s.responseFields[ current ] ) { + jqXHR[ s.responseFields[ current ] ] = response; + } + + // Apply the dataFilter if provided + if ( !prev && isSuccess && s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + prev = current; + current = dataTypes.shift(); + + if ( current ) { + + // There's only work to do if current dataType is non-auto + if ( current === "*" ) { + + current = prev; + + // Convert response if prev dataType is non-auto and differs from current + } else if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split( " " ); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.unshift( tmp[ 1 ] ); + } + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s.throws ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { + state: "parsererror", + error: conv ? e : "No conversion from " + prev + " to " + current + }; + } + } + } + } + } + } + + return { state: "success", data: response }; +} + +jQuery.extend( { + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {}, + + ajaxSettings: { + url: location.href, + type: "GET", + isLocal: rlocalProtocol.test( location.protocol ), + global: true, + processData: true, + async: true, + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + "*": allTypes, + text: "text/plain", + html: "text/html", + xml: "application/xml, text/xml", + json: "application/json, text/javascript" + }, + + contents: { + xml: /\bxml\b/, + html: /\bhtml/, + json: /\bjson\b/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText", + json: "responseJSON" + }, + + // Data converters + // Keys separate source (or catchall "*") and destination types with a single space + converters: { + + // Convert anything to text + "* text": String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": JSON.parse, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + url: true, + context: true + } + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + return settings ? + + // Building a settings object + ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : + + // Extending ajaxSettings + ajaxExtend( jQuery.ajaxSettings, target ); + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var transport, + + // URL without anti-cache param + cacheURL, + + // Response headers + responseHeadersString, + responseHeaders, + + // timeout handle + timeoutTimer, + + // Url cleanup var + urlAnchor, + + // Request state (becomes false upon send and true upon completion) + completed, + + // To know if global events are to be dispatched + fireGlobals, + + // Loop variable + i, + + // uncached part of the url + uncached, + + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + + // Callbacks context + callbackContext = s.context || s, + + // 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, + + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + + // Status-dependent callbacks + statusCode = s.statusCode || {}, + + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + + // Default abort message + strAbort = "canceled", + + // Fake xhr + jqXHR = { + readyState: 0, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( completed ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while ( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[ 1 ].toLowerCase() + " " ] = + ( responseHeaders[ match[ 1 ].toLowerCase() + " " ] || [] ) + .concat( match[ 2 ] ); + } + } + match = responseHeaders[ key.toLowerCase() + " " ]; + } + return match == null ? null : match.join( ", " ); + }, + + // Raw string + getAllResponseHeaders: function() { + return completed ? responseHeadersString : null; + }, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( completed == null ) { + name = requestHeadersNames[ name.toLowerCase() ] = + requestHeadersNames[ name.toLowerCase() ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( completed == null ) { + s.mimeType = type; + } + return this; + }, + + // Status-dependent callbacks + statusCode: function( map ) { + var code; + if ( map ) { + if ( completed ) { + + // Execute the appropriate callbacks + jqXHR.always( map[ jqXHR.status ] ); + } else { + + // Lazy-add the new callbacks in a way that preserves old ones + for ( code in map ) { + statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; + } + } + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + var finalText = statusText || strAbort; + if ( transport ) { + transport.abort( finalText ); + } + done( 0, finalText ); + return this; + } + }; + + // Attach deferreds + deferred.promise( jqXHR ); + + // Add protocol if not provided (prefilters might expect it) + // Handle falsy url in the settings object (trac-10093: consistency with old signature) + // We also use the url parameter if available + s.url = ( ( url || s.url || location.href ) + "" ) + .replace( rprotocol, location.protocol + "//" ); + + // Alias method option to type as per ticket trac-12004 + s.type = options.method || options.type || s.method || s.type; + + // Extract dataTypes list + s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; + + // A cross-domain request is in order when the origin doesn't match the current origin. + if ( s.crossDomain == null ) { + urlAnchor = document.createElement( "a" ); + + // Support: IE <=8 - 11, Edge 12 - 15 + // IE throws exception on accessing the href property if url is malformed, + // e.g. http://example.com:80x/ + try { + urlAnchor.href = s.url; + + // Support: IE <=8 - 11 only + // Anchor's host property isn't correctly set when s.url is relative + urlAnchor.href = urlAnchor.href; + s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== + urlAnchor.protocol + "//" + urlAnchor.host; + } catch ( e ) { + + // If there is an error parsing the URL, assume it is crossDomain, + // it can be rejected by the transport if it is invalid + s.crossDomain = true; + } + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( completed ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (trac-15118) + fireGlobals = jQuery.event && s.global; + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Save the URL in case we're toying with the If-Modified-Since + // and/or If-None-Match header later on + // Remove hash to simplify url manipulation + cacheURL = s.url.replace( rhash, "" ); + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // Remember the hash so we can put it back + uncached = s.url.slice( cacheURL.length ); + + // If data is available and should be processed, append data to url + if ( s.data && ( s.processData || typeof s.data === "string" ) ) { + cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; + + // trac-9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Add or update anti-cache param if needed + if ( s.cache === false ) { + cacheURL = cacheURL.replace( rantiCache, "$1" ); + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce.guid++ ) + + uncached; + } + + // Put hash and anti-cache on the URL that will be requested (gh-1732) + s.url = cacheURL + uncached; + + // Change '%20' to '+' if this is encoded form body content (gh-2658) + } else if ( s.data && s.processData && + ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { + s.data = s.data.replace( r20, "+" ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + if ( jQuery.lastModified[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); + } + if ( jQuery.etag[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? + s.accepts[ s.dataTypes[ 0 ] ] + + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && + ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { + + // Abort if not done already and return + return jqXHR.abort(); + } + + // Aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + completeDeferred.add( s.complete ); + jqXHR.done( s.success ); + jqXHR.fail( s.error ); + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + + // If request was aborted inside ajaxSend, stop there + if ( completed ) { + return jqXHR; + } + + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = window.setTimeout( function() { + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + completed = false; + transport.send( requestHeaders, done ); + } catch ( e ) { + + // Rethrow post-completion exceptions + if ( completed ) { + throw e; + } + + // Propagate others as results + done( -1, e ); + } + } + + // Callback for when everything is done + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Ignore repeat invocations + if ( completed ) { + return; + } + + completed = true; + + // Clear timeout if it exists + if ( timeoutTimer ) { + window.clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Determine if successful + isSuccess = status >= 200 && status < 300 || status === 304; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // 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() {}; + } + + // Convert no matter what (that way responseXXX fields are always set) + response = ajaxConvert( s, response, jqXHR, isSuccess ); + + // If successful, handle type chaining + if ( isSuccess ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + modified = jqXHR.getResponseHeader( "Last-Modified" ); + if ( modified ) { + jQuery.lastModified[ cacheURL ] = modified; + } + modified = jqXHR.getResponseHeader( "etag" ); + if ( modified ) { + jQuery.etag[ cacheURL ] = modified; + } + } + + // if no content + if ( status === 204 || s.type === "HEAD" ) { + statusText = "nocontent"; + + // if not modified + } else if ( status === 304 ) { + statusText = "notmodified"; + + // If we have data, let's convert it + } else { + statusText = response.state; + success = response.data; + error = response.error; + isSuccess = !error; + } + } else { + + // Extract error from statusText and normalize for non-aborts + error = statusText; + if ( status || !statusText ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + return jqXHR; + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + } +} ); + +jQuery.each( [ "get", "post" ], function( _i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + + // Shift arguments if data argument was omitted + if ( isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + // The url can be an options object (which then must have .url) + return jQuery.ajax( jQuery.extend( { + url: url, + type: method, + dataType: type, + data: data, + success: callback + }, jQuery.isPlainObject( url ) && url ) ); + }; +} ); + +jQuery.ajaxPrefilter( function( s ) { + var i; + for ( i in s.headers ) { + if ( i.toLowerCase() === "content-type" ) { + s.contentType = s.headers[ i ] || ""; + } + } +} ); + + +jQuery._evalUrl = function( url, options, doc ) { + return jQuery.ajax( { + url: url, + + // Make this explicit, since user can override this through ajaxSetup (trac-11264) + type: "GET", + dataType: "script", + cache: true, + async: false, + global: false, + + // Only evaluate the response if it is successful (gh-4126) + // dataFilter is not invoked for failure responses, so using it instead + // of the default converter is kludgy but it works. + converters: { + "text script": function() {} + }, + dataFilter: function( response ) { + jQuery.globalEval( response, options, doc ); + } + } ); +}; + + +jQuery.fn.extend( { + wrapAll: function( html ) { + var wrap; + + if ( this[ 0 ] ) { + if ( isFunction( html ) ) { + html = html.call( this[ 0 ] ); + } + + // The elements to wrap the target around + wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); + + if ( this[ 0 ].parentNode ) { + wrap.insertBefore( this[ 0 ] ); + } + + wrap.map( function() { + var elem = this; + + while ( elem.firstElementChild ) { + elem = elem.firstElementChild; + } + + return elem; + } ).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( isFunction( html ) ) { + return this.each( function( i ) { + jQuery( this ).wrapInner( html.call( this, i ) ); + } ); + } + + return this.each( function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + } ); + }, + + wrap: function( html ) { + var htmlIsFunction = isFunction( html ); + + return this.each( function( i ) { + jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html ); + } ); + }, + + unwrap: function( selector ) { + this.parent( selector ).not( "body" ).each( function() { + jQuery( this ).replaceWith( this.childNodes ); + } ); + return this; + } +} ); + + +jQuery.expr.pseudos.hidden = function( elem ) { + return !jQuery.expr.pseudos.visible( elem ); +}; +jQuery.expr.pseudos.visible = function( elem ) { + return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); +}; + + + + +jQuery.ajaxSettings.xhr = function() { + try { + return new window.XMLHttpRequest(); + } catch ( e ) {} +}; + +var xhrSuccessStatus = { + + // File protocol always yields status code 0, assume 200 + 0: 200, + + // Support: IE <=9 only + // trac-1450: sometimes IE returns 1223 when it should be 204 + 1223: 204 + }, + xhrSupported = jQuery.ajaxSettings.xhr(); + +support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); +support.ajax = xhrSupported = !!xhrSupported; + +jQuery.ajaxTransport( function( options ) { + var callback, errorCallback; + + // Cross domain only allowed if supported through XMLHttpRequest + if ( support.cors || xhrSupported && !options.crossDomain ) { + return { + send: function( headers, complete ) { + var i, + xhr = options.xhr(); + + xhr.open( + options.type, + options.url, + options.async, + options.username, + options.password + ); + + // Apply custom fields if provided + if ( options.xhrFields ) { + for ( i in options.xhrFields ) { + xhr[ i ] = options.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( options.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( options.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Set headers + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + + // Callback + callback = function( type ) { + return function() { + if ( callback ) { + callback = errorCallback = xhr.onload = + xhr.onerror = xhr.onabort = xhr.ontimeout = + xhr.onreadystatechange = null; + + if ( type === "abort" ) { + xhr.abort(); + } else if ( type === "error" ) { + + // Support: IE <=9 only + // On a manual native abort, IE9 throws + // errors on any property access that is not readyState + if ( typeof xhr.status !== "number" ) { + complete( 0, "error" ); + } else { + complete( + + // File: protocol always yields status 0; see trac-8605, trac-14207 + xhr.status, + xhr.statusText + ); + } + } else { + complete( + xhrSuccessStatus[ xhr.status ] || xhr.status, + xhr.statusText, + + // Support: IE <=9 only + // IE9 has no XHR2 but throws on binary (trac-11426) + // For XHR2 non-text, let the caller handle it (gh-2498) + ( xhr.responseType || "text" ) !== "text" || + typeof xhr.responseText !== "string" ? + { binary: xhr.response } : + { text: xhr.responseText }, + xhr.getAllResponseHeaders() + ); + } + } + }; + }; + + // Listen to events + xhr.onload = callback(); + errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" ); + + // Support: IE 9 only + // Use onreadystatechange to replace onabort + // to handle uncaught aborts + if ( xhr.onabort !== undefined ) { + xhr.onabort = errorCallback; + } else { + xhr.onreadystatechange = function() { + + // Check readyState before timeout as it changes + if ( xhr.readyState === 4 ) { + + // Allow onerror to be called first, + // but that will not handle a native abort + // Also, save errorCallback to a variable + // as xhr.onerror cannot be accessed + window.setTimeout( function() { + if ( callback ) { + errorCallback(); + } + } ); + } + }; + } + + // Create the abort callback + callback = callback( "abort" ); + + try { + + // Do send the request (this may raise an exception) + xhr.send( options.hasContent && options.data || null ); + } catch ( e ) { + + // trac-14683: Only rethrow if this hasn't been notified as an error yet + if ( callback ) { + throw e; + } + } + }, + + abort: function() { + if ( callback ) { + callback(); + } + } + }; + } +} ); + + + + +// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) +jQuery.ajaxPrefilter( function( s ) { + if ( s.crossDomain ) { + s.contents.script = false; + } +} ); + +// Install script dataType +jQuery.ajaxSetup( { + accepts: { + script: "text/javascript, application/javascript, " + + "application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /\b(?:java|ecma)script\b/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +} ); + +// Handle cache's special case and crossDomain +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + } +} ); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function( s ) { + + // This transport only deals with cross domain or forced-by-attrs requests + if ( s.crossDomain || s.scriptAttrs ) { + var script, callback; + return { + send: function( _, complete ) { + script = jQuery( " +{% endblock extrahead %} + +{% block content %} +
    +

    Добавление участников лотереи: {{ lottery.name }}

    +

    {{ lottery.description }}

    + + +
    + +
    + + +
    +
    + + +
    + +
    + + +
    + {% csrf_token %} +
    + + + + + + + + + + + {% for invoice in form.fields.invoices.queryset %} + + + + + + + {% empty %} + + + + {% endfor %} + +
    СчетВладелец счетаДепозит
    + + {{ invoice.ext_id }} + {% if invoice.client_name %} + {{ invoice.client_name }} + {% else %} + Не указан + {% endif %} + {{ invoice.deposit_sum }}
    Нет доступных счетов
    +
    + +
    + + Вернуться к списку участников +
    +{% endblock content %} diff --git a/lottery/templates/admin/bindingrequests_change_list.html b/lottery/templates/admin/bindingrequests_change_list.html new file mode 100644 index 0000000..90c4395 --- /dev/null +++ b/lottery/templates/admin/bindingrequests_change_list.html @@ -0,0 +1,26 @@ +{% extends "admin/change_list.html" %} + +{% block content %} +

    Список заявок на привязку (Всего: {{ total_requests }})

    + {% if cl.result_list %} + + + + + + + + + {% for request in cl.result_list %} + + + + + {% endfor %} + +
    Клиентская картаСтатус
    {{ request.client_card }}{{ request.status }}
    + {% else %} +

    Нет заявок.

    + {% endif %} + {{ block.super }} +{% endblock %} diff --git a/lottery/templates/admin/clients_change_list.html b/lottery/templates/admin/clients_change_list.html new file mode 100644 index 0000000..facc6ac --- /dev/null +++ b/lottery/templates/admin/clients_change_list.html @@ -0,0 +1,12 @@ +{% extends "admin/change_list.html" %} + +{% block object-tools %} + + {{ block.super }} +{% endblock %} diff --git a/lottery/templates/admin/draw/lotteryparticipant/change_list.html b/lottery/templates/admin/draw/lotteryparticipant/change_list.html new file mode 100644 index 0000000..00c1321 --- /dev/null +++ b/lottery/templates/admin/draw/lotteryparticipant/change_list.html @@ -0,0 +1,22 @@ +{% extends "admin/change_list.html" %} +{% load i18n %} + +{% block object-tools-items %} +
    +
    + + +
    + + {% trans "Добавить участников" %} + +
    +{{ block.super }} +{% endblock %} diff --git a/lottery/templates/admin/draw_result.html b/lottery/templates/admin/draw_result.html new file mode 100644 index 0000000..bfd38e6 --- /dev/null +++ b/lottery/templates/admin/draw_result.html @@ -0,0 +1,57 @@ +{% extends "admin/base_site.html" %} +{% load static %} +{% load i18n %} + +{% block content %} +
    +

    Результаты розыгрыша

    +

    Лотерея: {{ lottery.name }}

    +

    {{ lottery.description }}

    + + + + + + + + + + + + + + + {% for result in draw_results %} + + + + + + + + + + {% endfor %} + +
    Призовое местоОписание призаНаградаПобедитель (Счет)Дата розыгрышаСтатусДействие
    {{ result.prize.prize_place }}{{ result.prize.description }}{{ result.prize.reward }} + {% if result.participant %} + {{ result.participant.invoice }} + {% else %} + Не выбран + {% endif %} + {{ result.drawn_at }} + {% if result.confirmed %} + Подтвержден + {% else %} + Не подтвержден + {% endif %} + + {% if not result.confirmed %} + Подтвердить + {% else %} + - + {% endif %} +
    + Вернуться к списку лотерей +
    +{% endblock %} diff --git a/lottery/templates/admin/invoices_change_list.html b/lottery/templates/admin/invoices_change_list.html new file mode 100644 index 0000000..3c9071d --- /dev/null +++ b/lottery/templates/admin/invoices_change_list.html @@ -0,0 +1,119 @@ +{% extends "admin/base_site.html" %} +{% load static %} +{% load i18n %} + +{% block content %} +
    +

    Счета

    + + + + + +
    +
    +
    + + +
    +
    + + +
    +
    + + +
    + +
    +
    + + +
    + + + + + + + + + + + + + + + + + + +
    СозданЗакрытСчетКлиентНомер клиентаСумма счетаБонусФДДепозитПримечание
    +
    +
    + + + + +{% endblock %} diff --git a/lottery/templates/static/css/custom.css b/lottery/templates/static/css/custom.css new file mode 100644 index 0000000..e69de29 diff --git a/lottery/templates/static/js/jquery.min.js b/lottery/templates/static/js/jquery.min.js new file mode 100644 index 0000000..7f37b5d --- /dev/null +++ b/lottery/templates/static/js/jquery.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.7.1 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!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(ie,e){"use strict";var oe=[],r=Object.getPrototypeOf,ae=oe.slice,g=oe.flat?function(e){return oe.flat.call(e)}:function(e){return oe.concat.apply([],e)},s=oe.push,se=oe.indexOf,n={},i=n.toString,ue=n.hasOwnProperty,o=ue.toString,a=o.call(Object),le={},v=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},y=function(e){return null!=e&&e===e.window},C=ie.document,u={type:!0,src:!0,nonce:!0,noModule:!0};function m(e,t,n){var r,i,o=(n=n||C).createElement("script");if(o.text=e,t)for(r in u)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[i.call(e)]||"object":typeof e}var t="3.7.1",l=/HTML$/i,ce=function(e,t){return new ce.fn.init(e,t)};function c(e){var t=!!e&&"length"in e&&e.length,n=x(e);return!v(e)&&!y(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+ge+")"+ge+"*"),x=new RegExp(ge+"|>"),j=new RegExp(g),A=new RegExp("^"+t+"$"),D={ID:new RegExp("^#("+t+")"),CLASS:new RegExp("^\\.("+t+")"),TAG:new RegExp("^("+t+"|[*])"),ATTR:new RegExp("^"+p),PSEUDO:new RegExp("^"+g),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ge+"*(even|odd|(([+-]|)(\\d*)n|)"+ge+"*(?:([+-]|)"+ge+"*(\\d+)|))"+ge+"*\\)|)","i"),bool:new RegExp("^(?:"+f+")$","i"),needsContext:new RegExp("^"+ge+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ge+"*((?:-\\d)?\\d*)"+ge+"*\\)|)(?=[^-]|$)","i")},N=/^(?:input|select|textarea|button)$/i,q=/^h\d$/i,L=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,H=/[+~]/,O=new RegExp("\\\\[\\da-fA-F]{1,6}"+ge+"?|\\\\([^\\r\\n\\f])","g"),P=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},M=function(){V()},R=J(function(e){return!0===e.disabled&&fe(e,"fieldset")},{dir:"parentNode",next:"legend"});try{k.apply(oe=ae.call(ye.childNodes),ye.childNodes),oe[ye.childNodes.length].nodeType}catch(e){k={apply:function(e,t){me.apply(e,ae.call(t))},call:function(e){me.apply(e,ae.call(arguments,1))}}}function I(t,e,n,r){var i,o,a,s,u,l,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&&(V(e),e=e||T,C)){if(11!==p&&(u=L.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return k.call(n,a),n}else if(f&&(a=f.getElementById(i))&&I.contains(e,a)&&a.id===i)return k.call(n,a),n}else{if(u[2])return k.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&e.getElementsByClassName)return k.apply(n,e.getElementsByClassName(i)),n}if(!(h[t+" "]||d&&d.test(t))){if(c=t,f=e,1===p&&(x.test(t)||m.test(t))){(f=H.test(t)&&U(e.parentNode)||e)==e&&le.scope||((s=e.getAttribute("id"))?s=ce.escapeSelector(s):e.setAttribute("id",s=S)),o=(l=Y(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+Q(l[o]);c=l.join(",")}try{return k.apply(n,f.querySelectorAll(c)),n}catch(e){h(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return re(t.replace(ve,"$1"),e,n,r)}function W(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function F(e){return e[S]=!0,e}function $(e){var t=T.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function B(t){return function(e){return fe(e,"input")&&e.type===t}}function _(t){return function(e){return(fe(e,"input")||fe(e,"button"))&&e.type===t}}function z(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&&R(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function X(a){return F(function(o){return o=+o,F(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function U(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}function V(e){var t,n=e?e.ownerDocument||e:ye;return n!=T&&9===n.nodeType&&n.documentElement&&(r=(T=n).documentElement,C=!ce.isXMLDoc(T),i=r.matches||r.webkitMatchesSelector||r.msMatchesSelector,r.msMatchesSelector&&ye!=T&&(t=T.defaultView)&&t.top!==t&&t.addEventListener("unload",M),le.getById=$(function(e){return r.appendChild(e).id=ce.expando,!T.getElementsByName||!T.getElementsByName(ce.expando).length}),le.disconnectedMatch=$(function(e){return i.call(e,"*")}),le.scope=$(function(){return T.querySelectorAll(":scope")}),le.cssHas=$(function(){try{return T.querySelector(":has(*,:jqfake)"),!1}catch(e){return!0}}),le.getById?(b.filter.ID=function(e){var t=e.replace(O,P);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(O,P);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):t.querySelectorAll(e)},b.find.CLASS=function(e,t){if("undefined"!=typeof t.getElementsByClassName&&C)return t.getElementsByClassName(e)},d=[],$(function(e){var t;r.appendChild(e).innerHTML="",e.querySelectorAll("[selected]").length||d.push("\\["+ge+"*(?:value|"+f+")"),e.querySelectorAll("[id~="+S+"-]").length||d.push("~="),e.querySelectorAll("a#"+S+"+*").length||d.push(".#.+[+~]"),e.querySelectorAll(":checked").length||d.push(":checked"),(t=T.createElement("input")).setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),r.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&d.push(":enabled",":disabled"),(t=T.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||d.push("\\["+ge+"*name"+ge+"*="+ge+"*(?:''|\"\")")}),le.cssHas||d.push(":has"),d=d.length&&new RegExp(d.join("|")),l=function(e,t){if(e===t)return a=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!le.sortDetached&&t.compareDocumentPosition(e)===n?e===T||e.ownerDocument==ye&&I.contains(ye,e)?-1:t===T||t.ownerDocument==ye&&I.contains(ye,t)?1:o?se.call(o,e)-se.call(o,t):0:4&n?-1:1)}),T}for(e in I.matches=function(e,t){return I(e,null,null,t)},I.matchesSelector=function(e,t){if(V(e),C&&!h[t+" "]&&(!d||!d.test(t)))try{var n=i.call(e,t);if(n||le.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){h(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(O,P),e[3]=(e[3]||e[4]||e[5]||"").replace(O,P),"~="===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]||I.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]&&I.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return D.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&j.test(n)&&(t=Y(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(O,P).toLowerCase();return"*"===e?function(){return!0}:function(e){return fe(e,t)}},CLASS:function(e){var t=s[e+" "];return t||(t=new RegExp("(^|"+ge+")"+e+"("+ge+"|$)"))&&s(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=I.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 T(e,n,r){return v(n)?ce.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?ce.grep(e,function(e){return e===n!==r}):"string"!=typeof n?ce.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(ce.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||k,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:S.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 ce?t[0]:t,ce.merge(this,ce.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:C,!0)),w.test(r[1])&&ce.isPlainObject(t))for(r in t)v(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=C.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):v(e)?void 0!==n.ready?n.ready(e):e(ce):ce.makeArray(e,this)}).prototype=ce.fn,k=ce(C);var E=/^(?:parents|prev(?:Until|All))/,j={children:!0,contents:!0,next:!0,prev:!0};function A(e,t){while((e=e[t])&&1!==e.nodeType);return e}ce.fn.extend({has:function(e){var t=ce(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,Ce=/^$|^module$|\/(?:java|ecma)script/i;xe=C.createDocumentFragment().appendChild(C.createElement("div")),(be=C.createElement("input")).setAttribute("type","radio"),be.setAttribute("checked","checked"),be.setAttribute("name","t"),xe.appendChild(be),le.checkClone=xe.cloneNode(!0).cloneNode(!0).lastChild.checked,xe.innerHTML="",le.noCloneChecked=!!xe.cloneNode(!0).lastChild.defaultValue,xe.innerHTML="",le.option=!!xe.lastChild;var ke={thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};function Se(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&fe(e,t)?ce.merge([e],n):n}function Ee(e,t){for(var n=0,r=e.length;n",""]);var je=/<|&#?\w+;/;function Ae(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function Re(e,t){return fe(e,"table")&&fe(11!==t.nodeType?t:t.firstChild,"tr")&&ce(e).children("tbody")[0]||e}function Ie(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function We(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Fe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(_.hasData(e)&&(s=_.get(e).events))for(i in _.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)}),C.head.appendChild(r[0])},abort:function(){i&&i()}}});var Jt,Kt=[],Zt=/(=)\?(?=&|$)|\?\?/;ce.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Kt.pop()||ce.expando+"_"+jt.guid++;return this[e]=!0,e}}),ce.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Zt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Zt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=v(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Zt,"$1"+r):!1!==e.jsonp&&(e.url+=(At.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||ce.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=ie[r],ie[r]=function(){o=arguments},n.always(function(){void 0===i?ce(ie).removeProp(r):ie[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Kt.push(r)),o&&v(i)&&i(o[0]),o=i=void 0}),"script"}),le.createHTMLDocument=((Jt=C.implementation.createHTMLDocument("").body).innerHTML="
    ",2===Jt.childNodes.length),ce.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(le.createHTMLDocument?((r=(t=C.implementation.createHTMLDocument("")).createElement("base")).href=C.location.href,t.head.appendChild(r)):t=C),o=!n&&[],(i=w.exec(e))?[t.createElement(i[1])]:(i=Ae([e],t,o),o&&o.length&&ce(o).remove(),ce.merge([],i.childNodes)));var r,i,o},ce.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(ce.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},ce.expr.pseudos.animated=function(t){return ce.grep(ce.timers,function(e){return t===e.elem}).length},ce.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=ce.css(e,"position"),c=ce(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=ce.css(e,"top"),u=ce.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),v(t)&&(t=t.call(e,n,ce.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)}},ce.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){ce.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"===ce.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===ce.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=ce(e).offset()).top+=ce.css(e,"borderTopWidth",!0),i.left+=ce.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-ce.css(r,"marginTop",!0),left:t.left-i.left-ce.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===ce.css(e,"position"))e=e.offsetParent;return e||J})}}),ce.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;ce.fn[t]=function(e){return M(this,function(e,t,n){var r;if(y(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)}}),ce.each(["top","left"],function(e,n){ce.cssHooks[n]=Ye(le.pixelPosition,function(e,t){if(t)return t=Ge(e,n),_e.test(t)?ce(e).position()[n]+"px":t})}),ce.each({Height:"height",Width:"width"},function(a,s){ce.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){ce.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return M(this,function(e,t,n){var r;return y(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?ce.css(e,t,i):ce.style(e,t,n,i)},s,n?e:void 0,n)}})}),ce.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){ce.fn[t]=function(e){return this.on(t,e)}}),ce.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.on("mouseenter",e).on("mouseleave",t||e)}}),ce.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){ce.fn[n]=function(e,t){return 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 E2R?^}1ONa4 literal 0 HcmV?d00001