diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..7d1a74e --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,17 @@ +name: build +on: [push, pull_request] +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - name: Set up Python 3.7 + uses: actions/setup-python@v1 + with: + python-version: 3.7 + - name: Install flake8 + run: pip install flake8 flake8-import-order flake8-future-import flake8-commas flake8-logging-format + - name: Lint with flake8 + run: | + flake8 --version + flake8 diff --git a/.github/workflows/compilemessages.yml b/.github/workflows/compilemessages.yml new file mode 100644 index 0000000..edcf2bd --- /dev/null +++ b/.github/workflows/compilemessages.yml @@ -0,0 +1,40 @@ +name: compilemessages +on: + push: + paths: + - 'locale/**' + pull_request: + paths: + - 'locale/**' +jobs: + compilemessages: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - name: Set up Python 3.7 + uses: actions/setup-python@v1 + with: + python-version: 3.7 + - name: Checkout submodules + run: | + git submodule init + git submodule update + - name: Install requirements + run: | + sudo apt-get install gettext + pip install -r requirements.txt + pip install pymysql + - name: Check .po file validity + run: | + fail=0 + while read -r file; do + if ! msgfmt --check-format "$file"; then + fail=$((fail + 1)) + fi + done < <(find locale -name '*.po') + exit "$fail" + shell: bash + - name: Compile messages + run: | + echo "STATIC_ROOT = '/tmp'" > dmoj/local_settings.py + python manage.py compilemessages diff --git a/.github/workflows/init.yml b/.github/workflows/init.yml deleted file mode 100644 index 23c4b63..0000000 --- a/.github/workflows/init.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: Lint - -on: - # Trigger the workflow on push or pull request, - # but only for the main branch - push: - branches: - - master - pull_request: - branches: - - master - -jobs: - run-linters: - name: Run linters - runs-on: ubuntu-latest - - steps: - - name: Check out Git repository - uses: actions/checkout@v2 - - - name: Set up Python - uses: actions/setup-python@v1 - with: - python-version: 3.8 - - - name: Install Python dependencies - run: pip install black - - - name: Run linters - uses: wearerequired/lint-action@v2 - with: - black: true diff --git a/.github/workflows/makemessages.yml b/.github/workflows/makemessages.yml new file mode 100644 index 0000000..fdf375d --- /dev/null +++ b/.github/workflows/makemessages.yml @@ -0,0 +1,53 @@ +name: makemessages +on: + push: + branches: + - master +jobs: + makemessages: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - name: Set up Python 3.7 + uses: actions/setup-python@v1 + with: + python-version: 3.7 + - name: Checkout submodules + run: | + git submodule init + git submodule update + - name: Install requirements + run: | + sudo apt-get install gettext + curl -O https://artifacts.crowdin.com/repo/deb/crowdin.deb + sudo dpkg -i crowdin.deb + pip install -r requirements.txt + pip install pymysql + - name: Collect localizable strings + run: | + echo "STATIC_ROOT = '/tmp'" > dmoj/local_settings.py + python manage.py makemessages -l en -e py,html,txt + python manage.py makemessages -l en -d djangojs + - name: Upload strings to Crowdin + env: + CROWDIN_API_TOKEN: ${{ secrets.CROWDIN_API_TOKEN }} + run: | + cat > crowdin.yaml <> crowdin.yaml + crowdin upload sources diff --git a/.github/workflows/updatemessages.yml b/.github/workflows/updatemessages.yml new file mode 100644 index 0000000..b000444 --- /dev/null +++ b/.github/workflows/updatemessages.yml @@ -0,0 +1,67 @@ +name: updatemessages +on: + schedule: + - cron: '0 * * * *' +jobs: + updatemessages: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - name: Set up Python 3.7 + uses: actions/setup-python@v1 + with: + python-version: 3.7 + - name: Checkout submodules + run: | + git submodule init + git submodule update + - name: Install requirements + run: | + sudo apt-get install gettext + curl -O https://artifacts.crowdin.com/repo/deb/crowdin.deb + sudo dpkg -i crowdin.deb + pip install -r requirements.txt + pip install pymysql + - name: Download strings from Crowdin + env: + CROWDIN_API_TOKEN: ${{ secrets.CROWDIN_API_TOKEN }} + run: | + cat > crowdin.yaml <> crowdin.yaml + crowdin download + rm crowdin.yaml + - name: Cleanup + run: | + rm -rf src/ + git add locale + git checkout . + git clean -fd + - name: Create pull request + uses: peter-evans/create-pull-request@v1.4.1-multi + env: + GITHUB_TOKEN: ${{ secrets.REPO_SCOPED_TOKEN }} + COMMIT_MESSAGE: 'i18n: update translations from Crowdin' + PULL_REQUEST_TITLE: 'Update translations from Crowdin' + PULL_REQUEST_BODY: This PR has been auto-generated to pull in latest translations from [Crowdin](https://translate.dmoj.ca). + PULL_REQUEST_LABELS: i18n, enhancement + PULL_REQUEST_REVIEWERS: Xyene, quantum5 + PULL_REQUEST_BRANCH: update-i18n + BRANCH_SUFFIX: none diff --git a/.gitignore b/.gitignore index a8a51bc..e8b3edc 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,6 @@ *.py[co] *.mo *~ -[a-z0-9]{40,} dmoj/local_settings.py resources/style.css resources/content-description.css @@ -13,7 +12,4 @@ resources/ranks.css resources/table.css sass_processed -node_modules/ -package-lock.json -/src diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..0bea662 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,8 @@ +[submodule "resources/pagedown"] + path = resources/pagedown + url = https://github.com/DMOJ/dmoj-pagedown.git + branch = master +[submodule "resources/libs"] + path = resources/libs + url = https://github.com/DMOJ/site-assets.git + branch = master diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml deleted file mode 100644 index 8740838..0000000 --- a/.pre-commit-config.yaml +++ /dev/null @@ -1,17 +0,0 @@ -repos: - - repo: https://github.com/rtts/djhtml - rev: 'v1.5.2' # replace with the latest tag on GitHub - hooks: - - id: djhtml - entry: djhtml -i -t 2 - files: templates/. - - id: djcss - types: [scss] - - repo: https://github.com/psf/black - rev: 22.12.0 - hooks: - - id: black - - repo: https://github.com/hadialqattan/pycln - rev: 'v2.3.0' - hooks: - - id: pycln diff --git a/502.html b/502.html index a65c3cd..4eb512a 100644 --- a/502.html +++ b/502.html @@ -1,7 +1,7 @@ - 502 bad gateway - LQDOJ + 502 bad gateway - DMOJ README

online-judge

+

1. Activate virtualenv:

+

source dmojsite/bin/activate

+

2. Remember to change the local_settings

+

3. Run server:

+

python manage.py runserver 0.0.0.0:8000

+

4. Create configure file for judge:

+

python dmojauto-conf

+

5. Create folder for problems, change the dir in judge conf file and local_settings.py

+

6. Connect judge:

+
    +
  • python manage.py runbridged
  • +
  • dmoj 0.0.0.0 -p 9999 -c judge/conf1.yml (depend on port in the local_settings.py)
  • +
+

7. Change vietnamese:

+
    +
  • go to /home/cuom1999/DMOJ/site/locale/vi
  • +
  • open .po file
  • +
  • python manage.py compilemessages
  • +
  • python manage.py compilejsi18n
  • +
\ No newline at end of file diff --git a/README.md b/README.md index 81fe6e5..a742684 100644 --- a/README.md +++ b/README.md @@ -1,327 +1,25 @@ -LQDOJ: Le Quy Don Online Judge -=== - -[![](https://github.com/DMOJ/online-judge/workflows/build/badge.svg)](https://lqdoj.edu.vn/) -[![Python](https://img.shields.io/pypi/pyversions/tensorflow.svg?style=plastic)](https://python.org) -[![OS](https://img.shields.io/badge/Ubuntu-16.04%20%7C%2018.04%20%7C%2020.04-brightgreen)](https://ubuntu.com/download) -[![License](https://img.shields.io/badge/license-AGPL--3.0-blue)](https://www.gnu.org/licenses/agpl-3.0.en.html) - -## Overview - -Homepage: [https://lqdoj.edu.vn](https://lqdoj.edu.vn) - -Based on [DMOJ](https://dmoj.ca/). - -Supported languages: - -- Assembly (x64) -- AWK -- C -- C++03 / C++11 / C++14 / C++17 / C++20 -- Java 11 -- Pascal -- Perl -- Python 2 / Python 3 -- PyPy 2 / PyPy 3 - -Support plagiarism detection via [Stanford MOSS](https://theory.stanford.edu/~aiken/moss/). - -## Installation - -Most of the setup are the same as DMOJ installations. You can view the installation guide of DMOJ here: https://docs.dmoj.ca/#/site/installation. -There is one minor change: Instead of `git clone https://github.com/DMOJ/site.git`, you clone this repo `git clone https://github.com/LQDJudge/online-judge.git`. - - -- Bước 1: cài các thư viện cần thiết - - $ ở đây nghĩa là sudo. Ví dụ dòng đầu nghĩa là chạy lệnh `sudo apt update` - -```jsx -$ apt update -$ apt install git gcc g++ make python3-dev python3-pip libxml2-dev libxslt1-dev zlib1g-dev gettext curl redis-server -$ curl -sL https://deb.nodesource.com/setup_18.x | sudo -E bash - -$ apt install nodejs -$ npm install -g sass postcss-cli postcss autoprefixer -``` - -- Bước 2: tạo DB - - Server đang dùng MariaDB ≥ 10.5, các bạn cũng có thể dùng Mysql nếu bị conflict - - Nếu các bạn chạy lệnh dưới này xong mà version mariadb bị cũ (< 10.5) thì có thể tra google cách cài MariaDB mới nhất (10.5 hoặc 10.6). - - Các bạn có thể thấy version MariaDB bằng cách gõ lệnh `sudo mysql` (Ctrl + C để quit) - -```jsx -$ apt update -$ apt install mariadb-server libmysqlclient-dev -``` - -- Bước 3: tạo table trong DB - - Các bạn có thể thay tên table và password - -```jsx -$ sudo mysql -mariadb> CREATE DATABASE dmoj DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_general_ci; -mariadb> GRANT ALL PRIVILEGES ON dmoj.* TO 'dmoj'@'localhost' IDENTIFIED BY ''; -mariadb> exit -``` - -- Bước 4: Cài đặt môi trường ảo (virtual env) và pull code - - Nếu `pip3 install mysqlclient` bị lỗi thì thử chạy `pip3 install mysqlclient==2.1.1` - -```jsx -$ python3 -m venv dmojsite -$ . dmojsite/bin/activate - -(dmojsite) $ git clone https://github.com/LQDJudge/online-judge.git -(dmojsite) $ cd online-judge -(dmojsite) $ git submodule init -(dmojsite) $ git submodule update -(dmojsite) $ pip3 install -r requirements.txt -(dmojsite) $ pip3 install mysqlclient -(dmojsite) $ pre-commit install -``` - -- Bước 5: tạo local_settings.py. Đây là file để custom setting cho Django. Các bạn tạo file vào `online-judge/dmoj/local_settings.py` - - File mẫu: https://github.com/DMOJ/docs/blob/master/sample_files/local_settings.py - - Nếu bạn đổi tên hoặc mật khẩu table databases thì thay đổi thông tin tương ứng trong `Databases` - - Sau khi xong, chạy lệnh `(dmojsite) $ python3 manage.py check` để kiểm tra -- Bước 6: Compile CSS và translation - - Giải thích: - - Lệnh 1 và 2 gọi sau mỗi lần thay đổi 1 file css hoặc file js (file html thì không cần) - - Lệnh 3 và 4 gọi sau mỗi lần thay đổi file dịch - - Note: Sau khi chạy lệnh này, folder tương ứng với STATIC_ROOT trong local_settings phải được tạo. Nếu chưa được tạo thì mình cần tạo folder đó trước khi chạy 2 lệnh đầu. - -```jsx -(dmojsite) $ ./make_style.sh -(dmojsite) $ python3 manage.py collectstatic -(dmojsite) $ python3 manage.py compilemessages -(dmojsite) $ python3 manage.py compilejsi18n -``` - -- Bước 7: Thêm dữ liệu vào DB - -```jsx -(dmojsite) $ python3 manage.py migrate -(dmojsite) $ python3 manage.py loaddata navbar -(dmojsite) $ python3 manage.py loaddata language_small -(dmojsite) $ python3 manage.py loaddata demo -``` - -- Bước 8: Chạy site. Đến đây thì cơ bản đã hoàn thành (chưa có judge, websocket, celery). Các bạn có thể truy cập tại `localhost:8000` - -```jsx -python3 manage.py runserver 0.0.0.0:8000 -``` - -**Một số lưu ý:** - -1. (WSL) có thể tải ứng dụng Terminal trong Windows Store -2. (WSL) mỗi lần mở ubuntu, các bạn cần chạy lệnh sau để mariadb khởi động: `sudo service mysql restart` (tương tự cho một số service khác như memcached, celery) -3. Sau khi cài đặt, các bạn chỉ cần activate virtual env và chạy lệnh runserver là ok -```jsx -. dmojsite/bin/activate -python3 manage.py runserver -``` -5. Đối với nginx, sau khi config xong theo guide của DMOJ, bạn cần thêm location như sau để sử dụng được tính năng profile image, thay thế `path/to/oj` thành đường dẫn nơi bạn đã clone source code. - -``` -location /profile_images/ { - root /path/to/oj; -} -``` - -6. Quy trình dev: - 1. Sau khi thay đổi code thì django tự build lại, các bạn chỉ cần F5 - 2. Một số style nằm trong các file .scss. Các bạn cần recompile css thì mới thấy được thay đổi. - -**Optional:** - -************Alias:************ Các bạn có thể lưu các alias này để sau này dùng cho nhanh - -- mtrans: để generate translation khi các bạn add một string trong code -- trans: compile translation (sau khi bạn đã dịch tiếng Việt) -- cr: chuyển tới folder OJ -- pr: chạy server -- sm: restart service (chủ yếu dùng cho WSL) -- sd: activate virtual env -- css: compile các file css - -```jsx -alias mtrans='python3 manage.py makemessages -l vi && python3 manage.py makedmojmessages -l vi' -alias pr='python3 manage.py runserver' -alias sd='source ~/LQDOJ/dmojsite/bin/activate' -alias sm='sudo service mysql restart && sudo service redis-server start && sudo service memcached start' -alias trans='python3 manage.py compilemessages -l vi && python3 manage.py compilejsi18n -l vi' -alias cr='cd ~/LQDOJ/online-judge' -alias css='./make_style.sh && python3 manage.py collectstatic --noinput' -``` - -**Memcached:** dùng cho in-memory cache - -```jsx -$ sudo apt install memcached -``` - -**Websocket:** dùng để live update (như chat) - -- Tạo file online-judge/websocket/config.js - -```jsx -module.exports = { - get_host: '127.0.0.1', - get_port: 15100, - post_host: '127.0.0.1', - post_port: 15101, - http_host: '127.0.0.1', - http_port: 15102, - long_poll_timeout: 29000, -}; -``` - -- Cài các thư viện - -```jsx -(dmojsite) $ npm install qu ws simplesets -(dmojsite) $ pip3 install websocket-client -``` - -- Khởi động (trong 1 tab riêng) - -```jsx -(dmojsite) $ node websocket/daemon.js -``` - -**************Celery:************** (dùng cho một số task như batch rejudge_ - -```jsx -celery -A dmoj_celery worker -``` - -**************Judge:************** - -- Cài đặt ở 1 folder riêng bên ngoài site: - -```jsx -$ apt install python3-dev python3-pip build-essential libseccomp-dev -$ git clone https://github.com/LQDJudge/judge-server.git -$ cd judge-server -$ sudo pip3 install -e . -``` - -- Tạo một file judge.yml ở bên ngoài folder judge-server (file mẫu https://github.com/DMOJ/docs/blob/master/sample_files/judge_conf.yml) -- Thêm judge vào site bằng UI: Admin → Judge → Thêm Judge → nhập id và key (chỉ cần thêm 1 lần) hoặc dùng lệnh `(dmojsite) $ python3 managed.py addjudge `. -- Chạy Bridge (cầu nối giữa judge và site) trong 1 tab riêng trong folder online-judge: - -```jsx -(dmojsite) $ python3 managed.py runbridged -``` - -- Khởi động Judge (trong 1 tab riêng): - -```jsx -$ dmoj -c judge.yml localhost -``` - -- Lưu ý: mỗi lần sau này muốn chạy judge thì mở 1 tab cho bridge và n tab cho judge. Mỗi judge cần 1 file yml khác nhau (chứa authentication khác nhau) - -### Some frequent difficulties when installation: - -1. Missing the `local_settings.py`. You need to copy the `local_settings.py` in order to pass the check. -2. Missing the problem folder in `local_settings.py`. You need to create a folder to contain all problem packages and configure in `local_settings.py`. -3. Missing static folder in `local_settings.py`. Similar to problem folder, make sure to configure `STATIC_FILES` inside `local_settings.py`. -4. Missing configure file for judges. Each judge must have a seperate configure file. To create this file, you can run `python dmojauto-conf`. Checkout all sample files here https://github.com/DMOJ/docs/blob/master/sample_files. -5. Missing timezone data for SQL. If you're using Ubuntu and you're following DMOJ's installation guide for the server, and you are getting the error mentioned in https://github.com/LQDJudge/online-judge/issues/45, then you can follow this method to fix: -``` -mysql --- You may have to do this if you haven't set root password for MySQL, replace mypass with your password --- SET PASSWORD FOR 'root'@'localhost' = PASSWORD('mypass'); --- FLUSH PRIVILEGES; -exit -mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -D mysql -u root -p -mysql -u root -p -e "flush tables;" mysql -``` -6. Missing the chat secret key, you must generate a Fernet key, and assign a variable in `local_settings.py` like this -```python -CHAT_SECRET_KEY = "81HqDtbqAywKSOumSxxxxxxxxxxxxxxxxx=" -``` - - -## Usage - -Suppose you finished all the installation. Everytime you want to run a local server, follow these steps: - -1. Activate virtualenv: -```bash +# online-judge +### 1. Activate virtualenv: source dmojsite/bin/activate -``` +### 2. Remember to change the local_settings -2. Run server: -```bash -python3 manage.py runserver 0.0.0.0:8000 -``` +### 3. Run server: +python manage.py runserver 0.0.0.0:8000 -3. Create a bridge (this is opened in a different terminal with the second step if you are using the same machine) -```bash -python3 manage.py runbridged -``` +### 4. Create configure file for judge: +python dmojauto-conf -4. Create a judge (another terminal) -```bash -dmoj 0.0.0.0 -p 9999 -c -``` -Here we suppose you use the default port 9999 for bridge in `settings.py`. You can create multiple judges, each should be in a seperate terminal. +### 5. Create folder for problems, change the dir in judge conf file and local_settings.py -**Optional** +### 6. Connect judge: ++ python manage.py runbridged ++ dmoj 0.0.0.0 -p 9999 -c judge/conf1.yml (depend on port in the local_settings.py and directory of conf file) -5. Run celery worker (This is server's queue. It may be necessary in some functions) -```bash -celery -A dmoj_celery worker -``` +### 7. Update vietnamese translation: + - go to locale/vi + - modify .po file + - python manage.py compilemessages + - python manage.py compilejsi18n -6. Run a live event server (So everything is updated lively like in the production) -```bash -node websocket/daemon.js -``` - -7. To use subdomain for each organization, go to admin page -> navigation bar -> sites, add domain name (e.g, "localhost:8000"). Then go to add `USE_SUBDOMAIN = True` to local_settings.py. - -## Deploy -Most of the steps are similar to Django tutorials. Here are two usual steps: - -1. Update vietnamese translation: - - If you add any new phrases in the code, ```python3 manage.py makemessages``` - - go to `locale/vi` - - modify `.po` file - - ```python3 manage.py compilemessages``` - - ```python3 manage.py compilejsi18n``` - -2. Update styles (using SASS) - - Change .css/.scss files in `resources` folder - - ```./make_style.sh && python3 manage.py collectstatic``` - - Sometimes you need to press `Ctrl + F5` to see the new user interface in browser. - -## Screenshots - -### Leaderboard - -Leaderboard with information about contest rating, performance points and real name of all users. - -![](https://raw.githubusercontent.com/emladevops/LQDOJ-image/main/brave_SK67WA26FA.png#gh-light-mode-only) -![](https://raw.githubusercontent.com/emladevops/LQDOJ-image/main/brave_cmqqCnwaFc.png#gh-dark-mode-only) - -### Admin dashboard - -Admin dashboard helps you easily managing problems, users, contests and blog posts. - -![](https://i.imgur.com/iccr3mh.png) - -### Statement editor - -You can write the problems' statement in Markdown with LaTeX figures and formulas supported. - -![](https://i.imgur.com/CQVC754.png) - -### Chat - -Users can communicate with each other and can see who's online. - -![](https://raw.githubusercontent.com/emladevops/LQDOJ-image/main/brave_kPsC5bJluc.png#gh-light-mode-only) -![](https://raw.githubusercontent.com/emladevops/LQDOJ-image/main/brave_AtrEzXzEAx.png#gh-dark-mode-only) +###8. Run chat server: +docker run -p 6379:6379 -d redis:2.8 diff --git a/chat_box/apps.py b/chat_box/apps.py index e49c8ad..fbc3ca1 100644 --- a/chat_box/apps.py +++ b/chat_box/apps.py @@ -2,7 +2,4 @@ from django.apps import AppConfig class ChatBoxConfig(AppConfig): - name = "chat_box" - - def ready(self): - from . import models + name = 'chat_box' diff --git a/chat_box/consumers.py b/chat_box/consumers.py new file mode 100644 index 0000000..1588053 --- /dev/null +++ b/chat_box/consumers.py @@ -0,0 +1,64 @@ +import json +from channels.generic.websocket import AsyncWebsocketConsumer +from .models import Message +from .views import format_time +from django.urls import reverse +from django.http import HttpResponse, HttpResponseRedirect + + +from judge.models.profile import Profile + + +class ChatConsumer(AsyncWebsocketConsumer): + async def connect(self): + self.room_name = 'room' + self.room_group_name = 'chat_%s' % self.room_name + + # Join room group + await self.channel_layer.group_add( + self.room_group_name, + self.channel_name, + ) + + await self.accept() + + async def disconnect(self, close_code): + # Leave room group + await self.channel_layer.group_discard( + self.room_group_name, + self.channel_name, + ) + + # Receive message from WebSocket + async def receive(self, text_data): + text_data_json = json.loads(text_data) + message = text_data_json['message'] + time = save_data_and_get_time(message) + message['time'] = format_time(time) + + # Send message to room group + await self.channel_layer.group_send( + self.room_group_name, + { + 'type': 'chat_message', + 'message': message, + }, + ) + + # Receive message from room group + async def chat_message(self, event): + message = event['message'] + # Send message to WebSocket + await self.send(text_data=json.dumps({ + 'message': message, + })) + + +# return time +def save_data_and_get_time(message): + new_message = Message(body=message['body'], + author=Profile.objects + .get(pk=message['author_id']), + ) + new_message.save() + return new_message.time diff --git a/chat_box/migrations/0001_initial.py b/chat_box/migrations/0001_initial.py index f738c77..b311ab5 100644 --- a/chat_box/migrations/0001_initial.py +++ b/chat_box/migrations/0001_initial.py @@ -9,43 +9,22 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ("judge", "0100_auto_20200127_0059"), + ('judge', '0100_auto_20200127_0059'), ] operations = [ migrations.CreateModel( - name="Message", + name='Message', fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "time", - models.DateTimeField(auto_now_add=True, verbose_name="posted time"), - ), - ( - "body", - models.TextField(max_length=8192, verbose_name="body of comment"), - ), - ( - "author", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="judge.Profile", - verbose_name="user", - ), - ), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('time', models.DateTimeField(auto_now_add=True, verbose_name='posted time')), + ('body', models.TextField(max_length=8192, verbose_name='body of comment')), + ('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='judge.Profile', verbose_name='user')), ], options={ - "verbose_name": "message", - "verbose_name_plural": "messages", - "ordering": ("-time",), + 'verbose_name': 'message', + 'verbose_name_plural': 'messages', + 'ordering': ('-time',), }, ), ] diff --git a/chat_box/migrations/0002_message_hidden.py b/chat_box/migrations/0002_message_hidden.py deleted file mode 100644 index baef87e..0000000 --- a/chat_box/migrations/0002_message_hidden.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 2.2.12 on 2020-05-05 15:54 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("chat_box", "0001_initial"), - ] - - operations = [ - migrations.AddField( - model_name="message", - name="hidden", - field=models.BooleanField(default=False, verbose_name="is hidden"), - ), - ] diff --git a/chat_box/migrations/0003_auto_20200505_2306.py b/chat_box/migrations/0003_auto_20200505_2306.py deleted file mode 100644 index 7af087e..0000000 --- a/chat_box/migrations/0003_auto_20200505_2306.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 2.2.12 on 2020-05-05 16:06 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("chat_box", "0002_message_hidden"), - ] - - operations = [ - migrations.AlterField( - model_name="message", - name="hidden", - field=models.BooleanField(default=True, verbose_name="is hidden"), - ), - ] diff --git a/chat_box/migrations/0004_auto_20200505_2336.py b/chat_box/migrations/0004_auto_20200505_2336.py deleted file mode 100644 index 7475262..0000000 --- a/chat_box/migrations/0004_auto_20200505_2336.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 2.2.12 on 2020-05-05 16:36 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("chat_box", "0003_auto_20200505_2306"), - ] - - operations = [ - migrations.AlterField( - model_name="message", - name="hidden", - field=models.BooleanField(default=False, verbose_name="is hidden"), - ), - ] diff --git a/chat_box/migrations/0005_auto_20211011_0714.py b/chat_box/migrations/0005_auto_20211011_0714.py deleted file mode 100644 index a28957e..0000000 --- a/chat_box/migrations/0005_auto_20211011_0714.py +++ /dev/null @@ -1,58 +0,0 @@ -# Generated by Django 2.2.17 on 2021-10-11 00:14 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0116_auto_20211011_0645"), - ("chat_box", "0004_auto_20200505_2336"), - ] - - operations = [ - migrations.CreateModel( - name="Room", - fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "user_one", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="user_one", - to="judge.Profile", - verbose_name="user 1", - ), - ), - ( - "user_two", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="user_two", - to="judge.Profile", - verbose_name="user 2", - ), - ), - ], - ), - migrations.AddField( - model_name="message", - name="room", - field=models.ForeignKey( - default=None, - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="chat_box.Room", - verbose_name="room id", - ), - ), - ] diff --git a/chat_box/migrations/0006_userroom.py b/chat_box/migrations/0006_userroom.py deleted file mode 100644 index 534e1a3..0000000 --- a/chat_box/migrations/0006_userroom.py +++ /dev/null @@ -1,48 +0,0 @@ -# Generated by Django 2.2.17 on 2021-11-12 05:27 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0116_auto_20211011_0645"), - ("chat_box", "0005_auto_20211011_0714"), - ] - - operations = [ - migrations.CreateModel( - name="UserRoom", - fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("last_seen", models.DateTimeField(verbose_name="last seen")), - ( - "room", - models.ForeignKey( - default=None, - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="chat_box.Room", - verbose_name="room id", - ), - ), - ( - "user", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="judge.Profile", - verbose_name="user", - ), - ), - ], - ), - ] diff --git a/chat_box/migrations/0007_auto_20211112_1255.py b/chat_box/migrations/0007_auto_20211112_1255.py deleted file mode 100644 index c38e475..0000000 --- a/chat_box/migrations/0007_auto_20211112_1255.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 2.2.17 on 2021-11-12 05:55 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("chat_box", "0006_userroom"), - ] - - operations = [ - migrations.AlterField( - model_name="userroom", - name="last_seen", - field=models.DateTimeField(auto_now_add=True, verbose_name="last seen"), - ), - ] diff --git a/chat_box/migrations/0008_ignore.py b/chat_box/migrations/0008_ignore.py deleted file mode 100644 index 6648d1e..0000000 --- a/chat_box/migrations/0008_ignore.py +++ /dev/null @@ -1,39 +0,0 @@ -# Generated by Django 2.2.17 on 2021-11-18 10:26 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0116_auto_20211011_0645"), - ("chat_box", "0007_auto_20211112_1255"), - ] - - operations = [ - migrations.CreateModel( - name="Ignore", - fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("ignored_users", models.ManyToManyField(to="judge.Profile")), - ( - "user", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="ignored_chat_users", - to="judge.Profile", - verbose_name="user", - ), - ), - ], - ), - ] diff --git a/chat_box/migrations/0009_auto_20220618_1452.py b/chat_box/migrations/0009_auto_20220618_1452.py deleted file mode 100644 index f0d5e7e..0000000 --- a/chat_box/migrations/0009_auto_20220618_1452.py +++ /dev/null @@ -1,24 +0,0 @@ -# Generated by Django 2.2.25 on 2022-06-18 07:52 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ("chat_box", "0008_ignore"), - ] - - operations = [ - migrations.AlterField( - model_name="ignore", - name="user", - field=models.OneToOneField( - on_delete=django.db.models.deletion.CASCADE, - related_name="ignored_chat_users", - to="judge.Profile", - verbose_name="user", - ), - ), - ] diff --git a/chat_box/migrations/0010_auto_20221028_0300.py b/chat_box/migrations/0010_auto_20221028_0300.py deleted file mode 100644 index df93cd1..0000000 --- a/chat_box/migrations/0010_auto_20221028_0300.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 2.2.25 on 2022-10-27 20:00 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0135_auto_20221028_0300"), - ("chat_box", "0009_auto_20220618_1452"), - ] - - operations = [ - migrations.AlterUniqueTogether( - name="userroom", - unique_together={("user", "room")}, - ), - ] diff --git a/chat_box/migrations/0011_alter_message_hidden.py b/chat_box/migrations/0011_alter_message_hidden.py deleted file mode 100644 index 1393e82..0000000 --- a/chat_box/migrations/0011_alter_message_hidden.py +++ /dev/null @@ -1,20 +0,0 @@ -# Generated by Django 3.2.18 on 2023-02-18 21:10 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("chat_box", "0010_auto_20221028_0300"), - ] - - operations = [ - migrations.AlterField( - model_name="message", - name="hidden", - field=models.BooleanField( - db_index=True, default=False, verbose_name="is hidden" - ), - ), - ] diff --git a/chat_box/migrations/0012_auto_20230308_1417.py b/chat_box/migrations/0012_auto_20230308_1417.py deleted file mode 100644 index bd3ec5a..0000000 --- a/chat_box/migrations/0012_auto_20230308_1417.py +++ /dev/null @@ -1,34 +0,0 @@ -# Generated by Django 3.2.18 on 2023-03-08 07:17 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0154_add_submission_indexes"), - ("chat_box", "0011_alter_message_hidden"), - ] - - operations = [ - migrations.AlterModelOptions( - name="message", - options={ - "ordering": ("-id",), - "verbose_name": "message", - "verbose_name_plural": "messages", - }, - ), - migrations.AlterField( - model_name="message", - name="hidden", - field=models.BooleanField(default=False, verbose_name="is hidden"), - ), - migrations.AddIndex( - model_name="message", - index=models.Index( - fields=["hidden", "room", "-id"], name="chat_box_me_hidden_b2307a_idx" - ), - ), - ] diff --git a/chat_box/migrations/0013_alter_message_time.py b/chat_box/migrations/0013_alter_message_time.py deleted file mode 100644 index 0f4ddc3..0000000 --- a/chat_box/migrations/0013_alter_message_time.py +++ /dev/null @@ -1,20 +0,0 @@ -# Generated by Django 3.2.18 on 2023-08-28 01:24 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("chat_box", "0012_auto_20230308_1417"), - ] - - operations = [ - migrations.AlterField( - model_name="message", - name="time", - field=models.DateTimeField( - auto_now_add=True, db_index=True, verbose_name="posted time" - ), - ), - ] diff --git a/chat_box/migrations/0014_userroom_unread_count.py b/chat_box/migrations/0014_userroom_unread_count.py deleted file mode 100644 index 8f407b3..0000000 --- a/chat_box/migrations/0014_userroom_unread_count.py +++ /dev/null @@ -1,38 +0,0 @@ -# Generated by Django 3.2.18 on 2023-08-28 06:02 - -from django.db import migrations, models - - -def migrate(apps, schema_editor): - UserRoom = apps.get_model("chat_box", "UserRoom") - Message = apps.get_model("chat_box", "Message") - - for ur in UserRoom.objects.all(): - if not ur.room: - continue - messages = ur.room.message_set - last_msg = messages.first() - try: - if last_msg and last_msg.author != ur.user: - ur.unread_count = messages.filter(time__gte=ur.last_seen).count() - else: - ur.unread_count = 0 - ur.save() - except: - continue - - -class Migration(migrations.Migration): - - dependencies = [ - ("chat_box", "0013_alter_message_time"), - ] - - operations = [ - migrations.AddField( - model_name="userroom", - name="unread_count", - field=models.IntegerField(db_index=True, default=0), - ), - migrations.RunPython(migrate, migrations.RunPython.noop, atomic=True), - ] diff --git a/chat_box/migrations/0015_room_last_msg_time.py b/chat_box/migrations/0015_room_last_msg_time.py deleted file mode 100644 index a32f21b..0000000 --- a/chat_box/migrations/0015_room_last_msg_time.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 3.2.18 on 2023-11-02 01:41 - -from django.db import migrations, models - - -def migrate(apps, schema_editor): - Room = apps.get_model("chat_box", "Room") - Message = apps.get_model("chat_box", "Message") - - for room in Room.objects.all(): - messages = room.message_set - last_msg = messages.first() - if last_msg: - room.last_msg_time = last_msg.time - room.save() - - -class Migration(migrations.Migration): - - dependencies = [ - ("chat_box", "0014_userroom_unread_count"), - ] - - operations = [ - migrations.AddField( - model_name="room", - name="last_msg_time", - field=models.DateTimeField( - db_index=True, null=True, verbose_name="last seen" - ), - ), - migrations.RunPython(migrate, migrations.RunPython.noop, atomic=True), - ] diff --git a/chat_box/migrations/0016_alter_room_unique_together.py b/chat_box/migrations/0016_alter_room_unique_together.py deleted file mode 100644 index 14b784a..0000000 --- a/chat_box/migrations/0016_alter_room_unique_together.py +++ /dev/null @@ -1,32 +0,0 @@ -# Generated by Django 3.2.18 on 2024-08-22 03:12 - -from django.db import migrations, models - - -def remove_duplicates(apps, schema_editor): - Room = apps.get_model("chat_box", "Room") - seen = set() - - for room in Room.objects.all(): - pair = (room.user_one_id, room.user_two_id) - reverse_pair = (room.user_two_id, room.user_one_id) - - if pair in seen or reverse_pair in seen: - room.delete() - else: - seen.add(pair) - - -class Migration(migrations.Migration): - - dependencies = [ - ("chat_box", "0015_room_last_msg_time"), - ] - - operations = [ - migrations.RunPython(remove_duplicates), - migrations.AlterUniqueTogether( - name="room", - unique_together={("user_one", "user_two")}, - ), - ] diff --git a/chat_box/models.py b/chat_box/models.py index 6d86125..b895f8d 100644 --- a/chat_box/models.py +++ b/chat_box/models.py @@ -1,154 +1,28 @@ +from asgiref.sync import async_to_sync +from channels.layers import get_channel_layer from django.db import models -from django.db.models import CASCADE, Q +from django.db.models import CASCADE from django.utils.translation import gettext_lazy as _ -from django.utils.functional import cached_property from judge.models.profile import Profile -from judge.caching import cache_wrapper -__all__ = ["Message", "Room", "UserRoom", "Ignore"] - - -class Room(models.Model): - user_one = models.ForeignKey( - Profile, related_name="user_one", verbose_name="user 1", on_delete=CASCADE - ) - user_two = models.ForeignKey( - Profile, related_name="user_two", verbose_name="user 2", on_delete=CASCADE - ) - last_msg_time = models.DateTimeField( - verbose_name=_("last seen"), null=True, db_index=True - ) - - class Meta: - app_label = "chat_box" - unique_together = ("user_one", "user_two") - - @cached_property - def _cached_info(self): - return get_room_info(self.id) - - def contain(self, profile): - return profile.id in [self.user_one_id, self.user_two_id] - - def other_user(self, profile): - return self.user_one if profile == self.user_two else self.user_two - - def other_user_id(self, profile): - user_ids = [self.user_one_id, self.user_two_id] - return sum(user_ids) - profile.id - - def users(self): - return [self.user_one, self.user_two] - - def last_message_body(self): - return self._cached_info["last_message"] - - @classmethod - def prefetch_room_cache(self, room_ids): - get_room_info.prefetch_multi([(i,) for i in room_ids]) +__all__ = ['Message'] class Message(models.Model): - author = models.ForeignKey(Profile, verbose_name=_("user"), on_delete=CASCADE) - time = models.DateTimeField( - verbose_name=_("posted time"), auto_now_add=True, db_index=True - ) - body = models.TextField(verbose_name=_("body of comment"), max_length=8192) - hidden = models.BooleanField(verbose_name="is hidden", default=False) - room = models.ForeignKey( - Room, verbose_name="room id", on_delete=CASCADE, default=None, null=True - ) + author = models.ForeignKey(Profile, verbose_name=_('user'), on_delete=CASCADE) + time = models.DateTimeField(verbose_name=_('posted time'), auto_now_add=True) + body = models.TextField(verbose_name=_('body of comment'), max_length=8192) def save(self, *args, **kwargs): + new_message = self.id self.body = self.body.strip() super(Message, self).save(*args, **kwargs) class Meta: - verbose_name = "message" - verbose_name_plural = "messages" - ordering = ("-id",) - indexes = [ - models.Index(fields=["hidden", "room", "-id"]), - ] - app_label = "chat_box" - - -class UserRoom(models.Model): - user = models.ForeignKey(Profile, verbose_name=_("user"), on_delete=CASCADE) - room = models.ForeignKey( - Room, verbose_name="room id", on_delete=CASCADE, default=None, null=True - ) - last_seen = models.DateTimeField(verbose_name=_("last seen"), auto_now_add=True) - unread_count = models.IntegerField(default=0, db_index=True) - - class Meta: - unique_together = ("user", "room") - app_label = "chat_box" - - -class Ignore(models.Model): - user = models.OneToOneField( - Profile, - related_name="ignored_chat_users", - verbose_name=_("user"), - on_delete=CASCADE, - db_index=True, - ) - ignored_users = models.ManyToManyField(Profile) - - class Meta: - app_label = "chat_box" - - @classmethod - def is_ignored(self, current_user, new_friend): - try: - return current_user.ignored_chat_users.ignored_users.filter( - id=new_friend.id - ).exists() - except: - return False - - @classmethod - def get_ignored_users(self, user): - try: - return self.objects.get(user=user).ignored_users.all() - except: - return Profile.objects.none() - - @classmethod - def get_ignored_rooms(self, user): - try: - ignored_users = self.objects.get(user=user).ignored_users.all() - return Room.objects.filter(Q(user_one=user) | Q(user_two=user)).filter( - Q(user_one__in=ignored_users) | Q(user_two__in=ignored_users) - ) - except: - return Room.objects.none() - - @classmethod - def add_ignore(self, current_user, friend): - ignore, created = self.objects.get_or_create(user=current_user) - ignore.ignored_users.add(friend) - - @classmethod - def remove_ignore(self, current_user, friend): - ignore, created = self.objects.get_or_create(user=current_user) - ignore.ignored_users.remove(friend) - - @classmethod - def toggle_ignore(self, current_user, friend): - if self.is_ignored(current_user, friend): - self.remove_ignore(current_user, friend) - else: - self.add_ignore(current_user, friend) - - -@cache_wrapper(prefix="Rinfo") -def get_room_info(room_id): - last_msg = Message.objects.filter(room_id=room_id).first() - return { - "last_message": last_msg.body if last_msg else None, - } + app_label = 'chat_box' + verbose_name = 'message' + verbose_name_plural = 'messages' + ordering = ('-time',) diff --git a/chat_box/routing.py b/chat_box/routing.py new file mode 100644 index 0000000..6a8fe06 --- /dev/null +++ b/chat_box/routing.py @@ -0,0 +1,7 @@ +from django.urls import re_path + +from . import consumers + +websocket_urlpatterns = [ + re_path(r'ws/chat/', consumers.ChatConsumer), +] \ No newline at end of file diff --git a/chat_box/utils.py b/chat_box/utils.py deleted file mode 100644 index f3f27b4..0000000 --- a/chat_box/utils.py +++ /dev/null @@ -1,51 +0,0 @@ -from cryptography.fernet import Fernet -import hmac -import hashlib - -from django.conf import settings -from django.db.models import OuterRef, Count, Subquery, IntegerField, Q -from django.db.models.functions import Coalesce - -from chat_box.models import Ignore, Message, UserRoom, Room - -from judge.caching import cache_wrapper - -secret_key = settings.CHAT_SECRET_KEY -fernet = Fernet(secret_key) - - -def encrypt_url(creator_id, other_id): - message = str(creator_id) + "_" + str(other_id) - return fernet.encrypt(message.encode()).decode() - - -def decrypt_url(message_encrypted): - try: - dec_message = fernet.decrypt(message_encrypted.encode()).decode() - creator_id, other_id = dec_message.split("_") - return int(creator_id), int(other_id) - except Exception as e: - return None, None - - -def encrypt_channel(channel): - return ( - hmac.new( - settings.CHAT_SECRET_KEY.encode(), - channel.encode(), - hashlib.sha512, - ).hexdigest()[:16] - + "%s" % channel - ) - - -@cache_wrapper(prefix="gub") -def get_unread_boxes(profile): - ignored_rooms = Ignore.get_ignored_rooms(profile) - unread_boxes = ( - UserRoom.objects.filter(user=profile, unread_count__gt=0) - .exclude(room__in=ignored_rooms) - .count() - ) - - return unread_boxes diff --git a/chat_box/views.py b/chat_box/views.py index e3d1646..d92af6d 100644 --- a/chat_box/views.py +++ b/chat_box/views.py @@ -1,554 +1,48 @@ from django.utils.translation import gettext as _ from django.views.generic import ListView -from django.http import ( - HttpResponse, - JsonResponse, - HttpResponseBadRequest, - HttpResponsePermanentRedirect, - HttpResponseRedirect, -) +from django.http import HttpResponse from django.core.paginator import Paginator -from django.core.exceptions import PermissionDenied -from django.shortcuts import render -from django.forms.models import model_to_dict -from django.db.models import ( - Case, - BooleanField, - When, - Q, - Subquery, - OuterRef, - Exists, - Count, - IntegerField, - F, - Max, -) -from django.db.models.functions import Coalesce -from django.utils import timezone -from django.contrib.auth.decorators import login_required -from django.urls import reverse - -from judge import event_poster as event from judge.jinja2.gravatar import gravatar -from judge.models import Friend +from .models import Message +import json -from chat_box.models import Message, Profile, Room, UserRoom, Ignore, get_room_info -from chat_box.utils import encrypt_url, decrypt_url, encrypt_channel, get_unread_boxes -from reversion import revisions +def format_time(time): + return time.strftime('%H:%M %p %d-%m-%Y') + + +def format_messages(messages): + msg_list = [{ + 'time': format_time(msg.time), + 'author': str(msg.author), + 'body': msg.body, + 'image': gravatar(msg.author, 32), + } for msg in messages] + return json.dumps(msg_list) class ChatView(ListView): - context_object_name = "message" - template_name = "chat/chat.html" - title = _("LQDOJ Chat") - - def __init__(self): - super().__init__() - self.room_id = None - self.room = None - self.messages = None - self.first_page_size = 20 # only for first request - self.follow_up_page_size = 50 - - def get_queryset(self): - return self.messages - - def has_next(self): - try: - msg = Message.objects.filter(room=self.room_id).earliest("id") - except Exception as e: - return False - return msg not in self.messages + model = Message + context_object_name = 'message' + template_name = 'chat/chat.html' + title = _('Chat Box') + paginate_by = 50 + paginator = Paginator(Message.objects.all(), paginate_by) def get(self, request, *args, **kwargs): - request_room = kwargs["room_id"] - page_size = self.follow_up_page_size - try: - last_id = int(request.GET.get("last_id")) - except Exception: - last_id = 1e15 - page_size = self.first_page_size - only_messages = request.GET.get("only_messages") - - if request_room: - try: - self.room = Room.objects.get(id=request_room) - if not can_access_room(request, self.room): - return HttpResponseBadRequest() - except Room.DoesNotExist: - return HttpResponseBadRequest() - else: - request_room = None - - self.room_id = request_room - self.messages = ( - Message.objects.filter(hidden=False, room=self.room_id, id__lt=last_id) - .select_related("author") - .only("body", "time", "author__rating", "author__display_rank")[:page_size] - ) - if not only_messages: + page = request.GET.get('page') + if (page == None): return super().get(request, *args, **kwargs) - return render( - request, - "chat/message_list.html", - { - "object_list": self.messages, - "has_next": self.has_next(), - }, - ) + cur_page = self.paginator.get_page(page) + return HttpResponse(format_messages(cur_page.object_list)) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) + context['title'] = self.title + + for msg in context['message']: + msg.time = format_time(msg.time) - context["title"] = self.title - context["last_msg"] = event.last() - context["status_sections"] = get_status_context(self.request.profile) - context["room"] = self.room_id - context["has_next"] = self.has_next() - context["unread_count_lobby"] = get_unread_count(None, self.request.profile) - context["chat_channel"] = encrypt_channel( - "chat_" + str(self.request.profile.id) - ) - context["chat_lobby_channel"] = encrypt_channel("chat_lobby") - if self.room: - users_room = [self.room.user_one, self.room.user_two] - users_room.remove(self.request.profile) - context["other_user"] = users_room[0] - context["other_online"] = get_user_online_status(context["other_user"]) - context["is_ignored"] = Ignore.is_ignored( - self.request.profile, context["other_user"] - ) - else: - context["online_count"] = get_online_count() - context["message_template"] = { - "author": self.request.profile, - "id": "$id", - "time": timezone.now(), - "body": "$body", - } return context - - -def delete_message(request): - ret = {"delete": "done"} - - if request.method == "GET": - return HttpResponseBadRequest() - - try: - messid = int(request.POST.get("message")) - mess = Message.objects.get(id=messid) - except: - return HttpResponseBadRequest() - - if not request.user.is_staff and request.profile != mess.author: - return HttpResponseBadRequest() - - mess.hidden = True - mess.save() - - return JsonResponse(ret) - - -def mute_message(request): - ret = {"mute": "done"} - - if request.method == "GET": - return HttpResponseBadRequest() - - if not request.user.is_staff: - return HttpResponseBadRequest() - - try: - messid = int(request.POST.get("message")) - mess = Message.objects.get(id=messid) - except: - return HttpResponseBadRequest() - - with revisions.create_revision(): - revisions.set_comment(_("Mute chat") + ": " + mess.body) - revisions.set_user(request.user) - mess.author.mute = True - mess.author.save() - - Message.objects.filter(room=None, author=mess.author).update(hidden=True) - - return JsonResponse(ret) - - -def check_valid_message(request, room): - if not room and len(request.POST["body"]) > 200: - return False - - if not can_access_room(request, room) or request.profile.mute: - return False - - last_msg = Message.objects.filter(room=room).first() - if ( - last_msg - and last_msg.author == request.profile - and last_msg.body == request.POST["body"].strip() - ): - return False - - if not room: - four_last_msg = Message.objects.filter(room=room).order_by("-id")[:4] - if len(four_last_msg) >= 4: - same_author = all(msg.author == request.profile for msg in four_last_msg) - time_diff = timezone.now() - four_last_msg[3].time - if same_author and time_diff.total_seconds() < 300: - return False - - return True - - -@login_required -def post_message(request): - ret = {"msg": "posted"} - - if request.method != "POST": - return HttpResponseBadRequest() - if len(request.POST["body"]) > 5000 or len(request.POST["body"].strip()) == 0: - return HttpResponseBadRequest() - - room = None - if request.POST["room"]: - room = Room.objects.get(id=request.POST["room"]) - - if not check_valid_message(request, room): - return HttpResponseBadRequest() - - new_message = Message(author=request.profile, body=request.POST["body"], room=room) - new_message.save() - - if not room: - event.post( - encrypt_channel("chat_lobby"), - { - "type": "lobby", - "author_id": request.profile.id, - "message": new_message.id, - "room": "None", - "tmp_id": request.POST.get("tmp_id"), - }, - ) - else: - get_room_info.dirty(room.id) - room.last_msg_time = new_message.time - room.save() - - for user in room.users(): - event.post( - encrypt_channel("chat_" + str(user.id)), - { - "type": "private", - "author_id": request.profile.id, - "message": new_message.id, - "room": room.id, - "tmp_id": request.POST.get("tmp_id"), - }, - ) - if user != request.profile: - UserRoom.objects.filter(user=user, room=room).update( - unread_count=F("unread_count") + 1 - ) - get_unread_boxes.dirty(user) - - return JsonResponse(ret) - - -def can_access_room(request, room): - return not room or room.contain(request.profile) - - -@login_required -def chat_message_ajax(request): - if request.method != "GET": - return HttpResponseBadRequest() - - try: - message_id = request.GET["message"] - except KeyError: - return HttpResponseBadRequest() - - try: - message = Message.objects.filter(hidden=False).get(id=message_id) - room = message.room - if not can_access_room(request, room): - return HttpResponse("Unauthorized", status=401) - except Message.DoesNotExist: - return HttpResponseBadRequest() - return render( - request, - "chat/message.html", - { - "message": message, - }, - ) - - -@login_required -def update_last_seen(request, **kwargs): - if "room_id" in kwargs: - room_id = kwargs["room_id"] - elif request.method == "GET": - room_id = request.GET.get("room") - elif request.method == "POST": - room_id = request.POST.get("room") - else: - return HttpResponseBadRequest() - try: - profile = request.profile - room = None - if room_id: - room = Room.objects.filter(id=int(room_id)).first() - except Room.DoesNotExist: - return HttpResponseBadRequest() - - if not can_access_room(request, room): - return HttpResponseBadRequest() - - user_room, _ = UserRoom.objects.get_or_create(user=profile, room=room) - user_room.last_seen = timezone.now() - user_room.unread_count = 0 - user_room.save() - - get_unread_boxes.dirty(profile) - - return JsonResponse({"msg": "updated"}) - - -def get_online_count(): - last_5_minutes = timezone.now() - timezone.timedelta(minutes=5) - return Profile.objects.filter(last_access__gte=last_5_minutes).count() - - -def get_user_online_status(user): - time_diff = timezone.now() - user.last_access - is_online = time_diff <= timezone.timedelta(minutes=5) - return is_online - - -def user_online_status_ajax(request): - if request.method != "GET": - return HttpResponseBadRequest() - - user_id = request.GET.get("user") - - if user_id: - try: - user_id = int(user_id) - user = Profile.objects.get(id=user_id) - except Exception as e: - return HttpResponseBadRequest() - - is_online = get_user_online_status(user) - return render( - request, - "chat/user_online_status.html", - { - "other_user": user, - "other_online": is_online, - "is_ignored": Ignore.is_ignored(request.profile, user), - }, - ) - else: - return render( - request, - "chat/user_online_status.html", - { - "online_count": get_online_count(), - }, - ) - - -def get_online_status(profile, other_profile_ids, rooms=None): - if not other_profile_ids: - return None - Profile.prefetch_profile_cache(other_profile_ids) - - joined_ids = ",".join([str(id) for id in other_profile_ids]) - other_profiles = Profile.objects.raw( - f"SELECT * from judge_profile where id in ({joined_ids}) order by field(id,{joined_ids})" - ) - last_5_minutes = timezone.now() - timezone.timedelta(minutes=5) - ret = [] - if rooms: - unread_count = get_unread_count(rooms, profile) - count = {} - last_msg = {} - room_of_user = {} - for i in unread_count: - room = Room.objects.get(id=i["room"]) - other_profile = room.other_user(profile) - count[other_profile.id] = i["unread_count"] - rooms = Room.objects.filter(id__in=rooms) - for room in rooms: - other_profile_id = room.other_user_id(profile) - last_msg[other_profile_id] = room.last_message_body() - room_of_user[other_profile_id] = room.id - - for other_profile in other_profiles: - is_online = False - if other_profile.last_access >= last_5_minutes: - is_online = True - user_dict = {"user": other_profile, "is_online": is_online} - if rooms: - user_dict.update( - { - "unread_count": count.get(other_profile.id), - "last_msg": last_msg.get(other_profile.id), - "room": room_of_user.get(other_profile.id), - } - ) - user_dict["url"] = encrypt_url(profile.id, other_profile.id) - ret.append(user_dict) - return ret - - -def get_status_context(profile, include_ignored=False): - if include_ignored: - ignored_users = [] - queryset = Profile.objects - else: - ignored_users = list( - Ignore.get_ignored_users(profile).values_list("id", flat=True) - ) - queryset = Profile.objects.exclude(id__in=ignored_users) - - last_5_minutes = timezone.now() - timezone.timedelta(minutes=5) - recent_profile = ( - Room.objects.filter(Q(user_one=profile) | Q(user_two=profile)) - .annotate( - other_user=Case( - When(user_one=profile, then="user_two"), - default="user_one", - ), - ) - .filter(last_msg_time__isnull=False) - .exclude(other_user__in=ignored_users) - .order_by("-last_msg_time") - .values("other_user", "id")[:20] - ) - - recent_profile_ids = [str(i["other_user"]) for i in recent_profile] - recent_rooms = [int(i["id"]) for i in recent_profile] - Room.prefetch_room_cache(recent_rooms) - - admin_list = ( - queryset.filter(display_rank="admin") - .exclude(id__in=recent_profile_ids) - .values_list("id", flat=True) - ) - - return [ - { - "title": _("Recent"), - "user_list": get_online_status(profile, recent_profile_ids, recent_rooms), - }, - { - "title": _("Admin"), - "user_list": get_online_status(profile, admin_list), - }, - ] - - -@login_required -def online_status_ajax(request): - return render( - request, - "chat/online_status.html", - { - "status_sections": get_status_context(request.profile), - "unread_count_lobby": get_unread_count(None, request.profile), - }, - ) - - -@login_required -def get_room(user_one, user_two): - if user_one.id > user_two.id: - user_one, user_two = user_two, user_one - room, created = Room.objects.get_or_create(user_one=user_one, user_two=user_two) - return room - - -@login_required -def get_or_create_room(request): - if request.method == "GET": - decrypted_other_id = request.GET.get("other") - elif request.method == "POST": - decrypted_other_id = request.POST.get("other") - else: - return HttpResponseBadRequest() - - request_id, other_id = decrypt_url(decrypted_other_id) - if not other_id or not request_id or request_id != request.profile.id: - return HttpResponseBadRequest() - - try: - other_user = Profile.objects.get(id=int(other_id)) - except Exception: - return HttpResponseBadRequest() - - user = request.profile - - if not other_user or not user: - return HttpResponseBadRequest() - # TODO: each user can only create <= 300 rooms - room = get_room(other_user, user) - for u in [other_user, user]: - user_room, created = UserRoom.objects.get_or_create(user=u, room=room) - if created: - user_room.last_seen = timezone.now() - user_room.save() - - room_url = reverse("chat", kwargs={"room_id": room.id}) - if request.method == "GET": - return JsonResponse( - { - "room": room.id, - "other_user_id": other_user.id, - "url": room_url, - } - ) - return HttpResponseRedirect(room_url) - - -def get_unread_count(rooms, user): - if rooms: - return UserRoom.objects.filter( - user=user, room__in=rooms, unread_count__gt=0 - ).values("unread_count", "room") - else: # lobby - user_room = UserRoom.objects.filter(user=user, room__isnull=True).first() - if not user_room: - return 0 - last_seen = user_room.last_seen - res = ( - Message.objects.filter(room__isnull=True, time__gte=last_seen) - .exclude(author=user) - .exclude(hidden=True) - .count() - ) - - return res - - -@login_required -def toggle_ignore(request, **kwargs): - user_id = kwargs["user_id"] - if not user_id: - return HttpResponseBadRequest() - try: - other_user = Profile.objects.get(id=user_id) - except: - return HttpResponseBadRequest() - - Ignore.toggle_ignore(request.profile, other_user) - next_url = request.GET.get("next", "/") - return HttpResponseRedirect(next_url) diff --git a/django_2_2_pymysql_patch.py b/django_2_2_pymysql_patch.py index c39c823..4470180 100644 --- a/django_2_2_pymysql_patch.py +++ b/django_2_2_pymysql_patch.py @@ -12,6 +12,6 @@ if (2, 2) <= django.VERSION < (3,): # attribute where the exact query sent to the database is saved. # See MySQLdb/cursors.py in the source distribution. # MySQLdb returns string, PyMySQL bytes. - return force_text(getattr(cursor, "_executed", None), errors="replace") + return force_text(getattr(cursor, '_executed', None), errors='replace') DatabaseOperations.last_executed_query = last_executed_query diff --git a/django_ace/static/django_ace/widget.css b/django_ace/static/django_ace/widget.css index a77a288..09ad946 100644 --- a/django_ace/static/django_ace/widget.css +++ b/django_ace/static/django_ace/widget.css @@ -11,12 +11,6 @@ bottom: 0; } -.ace_editor { - overflow: hidden; - font: 12px/normal 'Fira Code', 'Monaco', 'Menlo', monospace; - direction: 1tr; -} - .django-ace-widget.loading { display: none; } @@ -61,4 +55,4 @@ .django-ace-editor-fullscreen .django-ace-max_min { background-image: url(img/contract.png); -} +} \ No newline at end of file diff --git a/django_ace/static/django_ace/widget.js b/django_ace/static/django_ace/widget.js index d5226dd..d097b06 100644 --- a/django_ace/static/django_ace/widget.js +++ b/django_ace/static/django_ace/widget.js @@ -77,17 +77,15 @@ mode = widget.getAttribute('data-mode'), theme = widget.getAttribute('data-theme'), wordwrap = widget.getAttribute('data-wordwrap'), - toolbar = prev(widget); - var main_block = div.parentNode.parentNode; + toolbar = prev(widget), + main_block = toolbar.parentNode; - if (toolbar != null) { - // Toolbar maximize/minimize button - var min_max = toolbar.getElementsByClassName('django-ace-max_min'); - min_max[0].onclick = function () { - minimizeMaximize(widget, main_block, editor); - return false; - }; - } + // Toolbar maximize/minimize button + var min_max = toolbar.getElementsByClassName('django-ace-max_min'); + min_max[0].onclick = function () { + minimizeMaximize(widget, main_block, editor); + return false; + }; editor.getSession().setValue(textarea.value); @@ -162,7 +160,7 @@ ]); window[widget.id] = editor; - setTimeout(() => $(widget).trigger('ace_load', [editor]), 100); + $(widget).trigger('ace_load', [editor]); } function init() { diff --git a/django_ace/widgets.py b/django_ace/widgets.py index 659ec75..91369d0 100644 --- a/django_ace/widgets.py +++ b/django_ace/widgets.py @@ -11,33 +11,22 @@ from django.utils.safestring import mark_safe class AceWidget(forms.Textarea): - def __init__( - self, - mode=None, - theme=None, - wordwrap=False, - width="100%", - height="300px", - no_ace_media=False, - toolbar=True, - *args, - **kwargs - ): + def __init__(self, mode=None, theme=None, wordwrap=False, width='100%', height='300px', + no_ace_media=False, *args, **kwargs): self.mode = mode self.theme = theme self.wordwrap = wordwrap self.width = width self.height = height self.ace_media = not no_ace_media - self.toolbar = toolbar super(AceWidget, self).__init__(*args, **kwargs) @property def media(self): - js = [urljoin(settings.ACE_URL, "ace.js")] if self.ace_media else [] - js.append("django_ace/widget.js") + js = [urljoin(settings.ACE_URL, 'ace.js')] if self.ace_media else [] + js.append('django_ace/widget.js') css = { - "screen": ["django_ace/widget.css"], + 'screen': ['django_ace/widget.css'], } return forms.Media(js=js, css=css) @@ -45,32 +34,24 @@ class AceWidget(forms.Textarea): attrs = attrs or {} ace_attrs = { - "class": "django-ace-widget loading", - "style": "width:%s; height:%s" % (self.width, self.height), - "id": "ace_%s" % name, + 'class': 'django-ace-widget loading', + 'style': 'width:%s; height:%s' % (self.width, self.height), + 'id': 'ace_%s' % name, } if self.mode: - ace_attrs["data-mode"] = self.mode + ace_attrs['data-mode'] = self.mode if self.theme: - ace_attrs["data-theme"] = self.theme + ace_attrs['data-theme'] = self.theme if self.wordwrap: - ace_attrs["data-wordwrap"] = "true" + ace_attrs['data-wordwrap'] = 'true' - attrs.update( - style="width: 100%; min-width: 100%; max-width: 100%; resize: none" - ) + attrs.update(style='width: 100%; min-width: 100%; max-width: 100%; resize: none') textarea = super(AceWidget, self).render(name, value, attrs) - html = "
%s" % (flatatt(ace_attrs), textarea) + html = '
%s' % (flatatt(ace_attrs), textarea) - if self.toolbar: - toolbar = ( - '
' - '' - "
" - ).format(self.width) - html = toolbar + html - - html = '
{}
'.format(html) + # add toolbar + html = ('
' + '
%s
') % html return mark_safe(html) diff --git a/dmoj/celery.py b/dmoj/celery.py index 5f0c87d..96718ea 100644 --- a/dmoj/celery.py +++ b/dmoj/celery.py @@ -4,30 +4,24 @@ import socket from celery import Celery from celery.signals import task_failure -app = Celery("dmoj") +app = Celery('dmoj') from django.conf import settings # noqa: E402, I202, django must be imported here +app.config_from_object(settings, namespace='CELERY') -app.config_from_object(settings, namespace="CELERY") - -if hasattr(settings, "CELERY_BROKER_URL_SECRET"): +if hasattr(settings, 'CELERY_BROKER_URL_SECRET'): app.conf.broker_url = settings.CELERY_BROKER_URL_SECRET -if hasattr(settings, "CELERY_RESULT_BACKEND_SECRET"): +if hasattr(settings, 'CELERY_RESULT_BACKEND_SECRET'): app.conf.result_backend = settings.CELERY_RESULT_BACKEND_SECRET # Load task modules from all registered Django app configs. app.autodiscover_tasks() # Logger to enable errors be reported. -logger = logging.getLogger("judge.celery") +logger = logging.getLogger('judge.celery') @task_failure.connect() def celery_failure_log(sender, task_id, exception, traceback, *args, **kwargs): - logger.error( - "Celery Task %s: %s on %s", - sender.name, - task_id, - socket.gethostname(), # noqa: G201 - exc_info=(type(exception), exception, traceback), - ) + logger.error('Celery Task %s: %s on %s', sender.name, task_id, socket.gethostname(), # noqa: G201 + exc_info=(type(exception), exception, traceback)) diff --git a/dmoj/routing.py b/dmoj/routing.py new file mode 100644 index 0000000..72e0379 --- /dev/null +++ b/dmoj/routing.py @@ -0,0 +1,12 @@ +from channels.auth import AuthMiddlewareStack +from channels.routing import ProtocolTypeRouter, URLRouter +import chat_box.routing + +application = ProtocolTypeRouter({ + # (http->django views is added by default) + 'websocket': AuthMiddlewareStack( + URLRouter( + chat_box.routing.websocket_urlpatterns + ) + ), +}) \ No newline at end of file diff --git a/dmoj/settings.py b/dmoj/settings.py index 2867a2a..1040998 100644 --- a/dmoj/settings.py +++ b/dmoj/settings.py @@ -22,7 +22,7 @@ BASE_DIR = os.path.dirname(os.path.dirname(__file__)) # See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = "5*9f5q57mqmlz2#f$x1h76&jxy#yortjl1v+l*6hd18$d*yx#0" +SECRET_KEY = '5*9f5q57mqmlz2#f$x1h76&jxy#yortjl1v+l*6hd18$d*yx#0' # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True @@ -30,10 +30,9 @@ DEBUG = True ALLOWED_HOSTS = [] SITE_ID = 1 -SITE_NAME = "LQDOJ" -SITE_LONG_NAME = "LQDOJ: Le Quy Don Online Judge" +SITE_NAME = 'LQDOJ' +SITE_LONG_NAME = 'LQDOJ: Le Quy Don Online Judge' SITE_ADMIN_EMAIL = False -SITE_DOMAIN = "lqdoj.edu.vn" DMOJ_REQUIRE_STAFF_2FA = True @@ -45,11 +44,13 @@ DMOJ_SSL = 0 # Refer to dmoj.ca/post/103-point-system-rework DMOJ_PP_STEP = 0.95 DMOJ_PP_ENTRIES = 100 -DMOJ_PP_BONUS_FUNCTION = lambda n: 300 * (1 - 0.997**n) # noqa: E731 +DMOJ_PP_BONUS_FUNCTION = lambda n: 300 * (1 - 0.997 ** n) # noqa: E731 -NODEJS = "/usr/bin/node" -EXIFTOOL = "/usr/bin/exiftool" -ACE_URL = "//cdnjs.cloudflare.com/ajax/libs/ace/1.1.3" +NODEJS = '/usr/bin/node' +EXIFTOOL = '/usr/bin/exiftool' +ACE_URL = '//cdnjs.cloudflare.com/ajax/libs/ace/1.1.3' +SELECT2_JS_URL = '//cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/js/select2.min.js' +DEFAULT_SELECT2_CSS = '//cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/css/select2.min.css' DMOJ_CAMO_URL = None DMOJ_CAMO_KEY = None @@ -61,32 +62,26 @@ DMOJ_PROBLEM_MAX_TIME_LIMIT = 60 # seconds DMOJ_PROBLEM_MIN_MEMORY_LIMIT = 0 # kilobytes DMOJ_PROBLEM_MAX_MEMORY_LIMIT = 1048576 # kilobytes DMOJ_PROBLEM_MIN_PROBLEM_POINTS = 0 -DMOJ_SUBMISSION_ROOT = "/tmp" -DMOJ_RATING_COLORS = True +DMOJ_RATING_COLORS = False DMOJ_EMAIL_THROTTLING = (10, 60) DMOJ_STATS_LANGUAGE_THRESHOLD = 10 DMOJ_SUBMISSIONS_REJUDGE_LIMIT = 10 # Maximum number of submissions a single user can queue without the `spam_submission` permission -DMOJ_SUBMISSION_LIMIT = 3 +DMOJ_SUBMISSION_LIMIT = 2 DMOJ_BLOG_NEW_PROBLEM_COUNT = 7 -DMOJ_BLOG_NEW_CONTEST_COUNT = 7 DMOJ_BLOG_RECENTLY_ATTEMPTED_PROBLEMS_COUNT = 7 DMOJ_TOTP_TOLERANCE_HALF_MINUTES = 1 -DMOJ_USER_MAX_ORGANIZATION_COUNT = 10 -DMOJ_USER_MAX_ORGANIZATION_ADD = 5 +DMOJ_USER_MAX_ORGANIZATION_COUNT = 3 DMOJ_COMMENT_VOTE_HIDE_THRESHOLD = -5 -DMOJ_PDF_PROBLEM_CACHE = "" +DMOJ_PDF_PROBLEM_CACHE = '' DMOJ_PDF_PROBLEM_TEMP_DIR = tempfile.gettempdir() DMOJ_STATS_SUBMISSION_RESULT_COLORS = { - "TLE": "#a3bcbd", - "AC": "#00a92a", - "WA": "#ed4420", - "CE": "#42586d", - "ERR": "#ffa71c", + 'TLE': '#a3bcbd', + 'AC': '#00a92a', + 'WA': '#ed4420', + 'CE': '#42586d', + 'ERR': '#ffa71c', } -DMOJ_PROFILE_IMAGE_ROOT = "profile_images" -DMOJ_ORGANIZATION_IMAGE_ROOT = "organization_images" -DMOJ_TEST_FORMATTER_ROOT = "test_formatter" MARKDOWN_STYLES = {} MARKDOWN_DEFAULT_STYLE = {} @@ -94,15 +89,16 @@ MARKDOWN_DEFAULT_STYLE = {} MATHOID_URL = False MATHOID_GZIP = False MATHOID_MML_CACHE = None -MATHOID_CSS_CACHE = "default" -MATHOID_DEFAULT_TYPE = "auto" +MATHOID_CSS_CACHE = 'default' +MATHOID_DEFAULT_TYPE = 'auto' MATHOID_MML_CACHE_TTL = 86400 -MATHOID_CACHE_ROOT = tempfile.gettempdir() + "/mathoidCache" +MATHOID_CACHE_ROOT = '' MATHOID_CACHE_URL = False TEXOID_GZIP = False -TEXOID_META_CACHE = "default" +TEXOID_META_CACHE = 'default' TEXOID_META_CACHE_TTL = 86400 +DMOJ_NEWSLETTER_ID_ON_REGISTER = None BAD_MAIL_PROVIDERS = () BAD_MAIL_PROVIDER_REGEX = () @@ -113,30 +109,27 @@ TIMEZONE_MAP = None TIMEZONE_DETECT_BACKEND = None TERMS_OF_SERVICE_URL = None -DEFAULT_USER_LANGUAGE = "PY3" +DEFAULT_USER_LANGUAGE = 'CPP11' -PHANTOMJS = "" +PHANTOMJS = '' PHANTOMJS_PDF_ZOOM = 0.75 PHANTOMJS_PDF_TIMEOUT = 5.0 -PHANTOMJS_PAPER_SIZE = "Letter" +PHANTOMJS_PAPER_SIZE = 'Letter' -SLIMERJS = "" +SLIMERJS = '' SLIMERJS_PDF_ZOOM = 0.75 -SLIMERJS_FIREFOX_PATH = "" -SLIMERJS_PAPER_SIZE = "Letter" +SLIMERJS_FIREFOX_PATH = '' +SLIMERJS_PAPER_SIZE = 'Letter' -PUPPETEER_MODULE = "/usr/lib/node_modules/puppeteer" -PUPPETEER_PAPER_SIZE = "Letter" - -USE_SELENIUM = False -SELENIUM_CUSTOM_CHROME_PATH = None -SELENIUM_CHROMEDRIVER_PATH = "chromedriver" +PUPPETEER_MODULE = '/usr/lib/node_modules/puppeteer' +PUPPETEER_PAPER_SIZE = 'Letter' +PYGMENT_THEME = 'pygment-github.css' INLINE_JQUERY = True INLINE_FONTAWESOME = True -JQUERY_JS = "//ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js" -FONTAWESOME_CSS = "//cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css" -DMOJ_CANONICAL = "" +JQUERY_JS = '//ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js' +FONTAWESOME_CSS = '//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css' +DMOJ_CANONICAL = '' # Application definition @@ -148,315 +141,350 @@ except ImportError: pass else: del wpadmin - INSTALLED_APPS += ("wpadmin",) + INSTALLED_APPS += ('wpadmin',) WPADMIN = { - "admin": { - "title": "LQDOJ Admin", - "menu": { - "top": "wpadmin.menu.menus.BasicTopMenu", - "left": "wpadmin.menu.custom.CustomModelLeftMenuWithDashboard", + 'admin': { + 'title': 'LQDOJ Admin', + 'menu': { + 'top': 'wpadmin.menu.menus.BasicTopMenu', + 'left': 'wpadmin.menu.custom.CustomModelLeftMenuWithDashboard', }, - "custom_menu": [ + 'custom_menu': [ { - "model": "judge.Problem", - "icon": "fa-question-circle", - "children": [ - "judge.ProblemGroup", - "judge.ProblemType", - "judge.ProblemPointsVote", + 'model': 'judge.Problem', + 'icon': 'fa-question-circle', + 'children': [ + 'judge.ProblemGroup', + 'judge.ProblemType', ], }, { - "model": "judge.Submission", - "icon": "fa-check-square", - "children": [ - "judge.Language", - "judge.Judge", + 'model': 'judge.Submission', + 'icon': 'fa-check-square-o', + 'children': [ + 'judge.Language', + 'judge.Judge', ], }, { - "model": "judge.Contest", - "icon": "fa-bar-chart", - "children": [ - "judge.ContestParticipation", - "judge.ContestTag", + 'model': 'judge.Contest', + 'icon': 'fa-bar-chart', + 'children': [ + 'judge.ContestParticipation', + 'judge.ContestTag', ], }, { - "model": "auth.User", - "icon": "fa-user", - "children": [ - "auth.Group", - "registration.RegistrationProfile", + 'model': 'auth.User', + 'icon': 'fa-user', + 'children': [ + 'auth.Group', + 'registration.RegistrationProfile', ], }, { - "model": "judge.Profile", - "icon": "fa-user-plus", - "children": [ - "judge.Organization", - "judge.OrganizationRequest", + 'model': 'judge.Profile', + 'icon': 'fa-user-plus', + 'children': [ + 'judge.Organization', + 'judge.OrganizationRequest', ], }, { - "model": "judge.NavigationBar", - "icon": "fa-bars", - "children": [ - "judge.MiscConfig", - "judge.License", - "sites.Site", - "redirects.Redirect", + 'model': 'judge.NavigationBar', + 'icon': 'fa-bars', + 'children': [ + 'judge.MiscConfig', + 'judge.License', + 'sites.Site', + 'redirects.Redirect', ], }, - ("judge.BlogPost", "fa-rss-square"), - ("judge.Ticket", "fa-exclamation-circle"), - ("admin.LogEntry", "fa-empire"), + ('judge.BlogPost', 'fa-rss-square'), + ('judge.Comment', 'fa-comment-o'), + ('flatpages.FlatPage', 'fa-file-text-o'), + ('judge.Solution', 'fa-pencil'), ], - "dashboard": { - "breadcrumbs": True, + 'dashboard': { + 'breadcrumbs': True, }, }, } INSTALLED_APPS += ( - "django.contrib.admin", - "judge", - "django.contrib.auth", - "django.contrib.contenttypes", - "django.contrib.flatpages", - "django.contrib.sessions", - "django.contrib.messages", - "django.contrib.redirects", - "django.contrib.staticfiles", - "django.contrib.sites", - "django.contrib.sitemaps", - "registration", - "mptt", - "reversion", - "reversion_compare", - "django_social_share", - "social_django", - "compressor", - "django_ace", - "pagedown", - "sortedm2m", - "statici18n", - "impersonate", - "django_jinja", - "chat_box", - "django.forms", + 'django.contrib.admin', + 'judge', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.flatpages', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.redirects', + 'django.contrib.staticfiles', + 'django.contrib.sites', + 'django.contrib.sitemaps', + 'registration', + 'mptt', + 'reversion', + 'django_social_share', + 'social_django', + 'compressor', + 'django_ace', + 'pagedown', + 'sortedm2m', + 'statici18n', + 'impersonate', + 'django_jinja', + 'chat_box', + 'channels', ) MIDDLEWARE = ( - "judge.middleware.SlowRequestMiddleware", - "judge.middleware.ShortCircuitMiddleware", - "django.contrib.sessions.middleware.SessionMiddleware", - "django.middleware.locale.LocaleMiddleware", - "django.middleware.common.CommonMiddleware", - "django.middleware.csrf.CsrfViewMiddleware", - "django.contrib.auth.middleware.AuthenticationMiddleware", - "judge.middleware.DMOJLoginMiddleware", - "django.contrib.messages.middleware.MessageMiddleware", - "django.middleware.clickjacking.XFrameOptionsMiddleware", - "judge.user_log.LogUserAccessMiddleware", - "judge.timezone.TimezoneMiddleware", - "impersonate.middleware.ImpersonateMiddleware", - "judge.middleware.DMOJImpersonationMiddleware", - "judge.middleware.ContestMiddleware", - "judge.middleware.DarkModeMiddleware", - "judge.middleware.SubdomainMiddleware", - "django.contrib.flatpages.middleware.FlatpageFallbackMiddleware", - "judge.social_auth.SocialAuthExceptionMiddleware", - "django.contrib.redirects.middleware.RedirectFallbackMiddleware", + 'judge.middleware.ShortCircuitMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.locale.LocaleMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'judge.middleware.DMOJLoginMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', + 'judge.user_log.LogUserAccessMiddleware', + 'judge.timezone.TimezoneMiddleware', + 'impersonate.middleware.ImpersonateMiddleware', + 'judge.middleware.DMOJImpersonationMiddleware', + 'judge.middleware.ContestMiddleware', + 'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware', + 'judge.social_auth.SocialAuthExceptionMiddleware', + 'django.contrib.redirects.middleware.RedirectFallbackMiddleware', ) -X_FRAME_OPTIONS = "SAMEORIGIN" - -LANGUAGE_COOKIE_AGE = 8640000 - -FORM_RENDERER = "django.forms.renderers.TemplatesSetting" - -IMPERSONATE = { - "REQUIRE_SUPERUSER": True, - "DISABLE_LOGGING": True, - "ADMIN_DELETE_PERMISSION": True, -} +IMPERSONATE_REQUIRE_SUPERUSER = True +IMPERSONATE_DISABLE_LOGGING = True ACCOUNT_ACTIVATION_DAYS = 7 AUTH_PASSWORD_VALIDATORS = [ { - "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', }, { - "NAME": "judge.utils.pwned.PwnedPasswordsValidator", + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', }, { - "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", + 'NAME': 'judge.utils.pwned.PwnedPasswordsValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', }, ] -SILENCED_SYSTEM_CHECKS = ["urls.W002", "fields.W342"] +SILENCED_SYSTEM_CHECKS = ['urls.W002', 'fields.W342'] -ROOT_URLCONF = "dmoj.urls" -LOGIN_REDIRECT_URL = "/user" -WSGI_APPLICATION = "dmoj.wsgi.application" +ROOT_URLCONF = 'dmoj.urls' +LOGIN_REDIRECT_URL = '/user' +WSGI_APPLICATION = 'dmoj.wsgi.application' TEMPLATES = [ { - "BACKEND": "django_jinja.backend.Jinja2", - "DIRS": [ - os.path.join(BASE_DIR, "templates"), + 'BACKEND': 'django_jinja.backend.Jinja2', + 'DIRS': [ + os.path.join(BASE_DIR, 'templates'), ], - "APP_DIRS": False, - "OPTIONS": { - "match_extension": (".html", ".txt"), - "match_regex": "^(?!admin/)", - "context_processors": [ - "django.template.context_processors.media", - "django.template.context_processors.tz", - "django.template.context_processors.i18n", - "django.template.context_processors.request", - "django.contrib.messages.context_processors.messages", - "judge.template_context.comet_location", - "judge.template_context.get_resource", - "judge.template_context.general_info", - "judge.template_context.site", - "judge.template_context.site_name", - "judge.template_context.misc_config", - "social_django.context_processors.backends", - "social_django.context_processors.login_redirect", + 'APP_DIRS': False, + 'OPTIONS': { + 'match_extension': ('.html', '.txt'), + 'match_regex': '^(?!admin/)', + 'context_processors': [ + 'django.template.context_processors.media', + 'django.template.context_processors.tz', + 'django.template.context_processors.i18n', + 'django.template.context_processors.request', + 'django.contrib.messages.context_processors.messages', + 'judge.template_context.comet_location', + 'judge.template_context.get_resource', + 'judge.template_context.general_info', + 'judge.template_context.site', + 'judge.template_context.site_name', + 'judge.template_context.misc_config', + 'judge.template_context.math_setting', + 'social_django.context_processors.backends', + 'social_django.context_processors.login_redirect', ], - "autoescape": select_autoescape(["html", "xml"]), - "trim_blocks": True, - "lstrip_blocks": True, - "extensions": DEFAULT_EXTENSIONS - + [ - "compressor.contrib.jinja2ext.CompressorExtension", - "judge.jinja2.DMOJExtension", - "judge.jinja2.spaceless.SpacelessExtension", + 'autoescape': select_autoescape(['html', 'xml']), + 'trim_blocks': True, + 'lstrip_blocks': True, + 'extensions': DEFAULT_EXTENSIONS + [ + 'compressor.contrib.jinja2ext.CompressorExtension', + 'judge.jinja2.DMOJExtension', + 'judge.jinja2.spaceless.SpacelessExtension', ], }, }, { - "BACKEND": "django.template.backends.django.DjangoTemplates", - "APP_DIRS": True, - "DIRS": [ - os.path.join(BASE_DIR, "templates"), + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'APP_DIRS': True, + 'DIRS': [ + os.path.join(BASE_DIR, 'templates'), ], - "OPTIONS": { - "context_processors": [ - "django.contrib.auth.context_processors.auth", - "django.template.context_processors.media", - "django.template.context_processors.tz", - "django.template.context_processors.i18n", - "django.template.context_processors.request", - "django.contrib.messages.context_processors.messages", + 'OPTIONS': { + 'context_processors': [ + 'django.contrib.auth.context_processors.auth', + 'django.template.context_processors.media', + 'django.template.context_processors.tz', + 'django.template.context_processors.i18n', + 'django.template.context_processors.request', + 'django.contrib.messages.context_processors.messages', ], }, }, ] LOCALE_PATHS = [ - os.path.join(BASE_DIR, "locale"), + os.path.join(BASE_DIR, 'locale'), ] LANGUAGES = [ - ("vi", _("Vietnamese")), - ("en", _("English")), + ('de', _('German')), + ('en', _('English')), + ('es', _('Spanish')), + ('fr', _('French')), + ('hr', _('Croatian')), + ('hu', _('Hungarian')), + ('ja', _('Japanese')), + ('ko', _('Korean')), + ('pt', _('Brazilian Portuguese')), + ('ro', _('Romanian')), + ('ru', _('Russian')), + ('sr-latn', _('Serbian (Latin)')), + ('tr', _('Turkish')), + ('vi', _('Vietnamese')), + ('zh-hans', _('Simplified Chinese')), + ('zh-hant', _('Traditional Chinese')), ] +MARKDOWN_ADMIN_EDITABLE_STYLE = { + 'safe_mode': False, + 'use_camo': True, + 'texoid': True, + 'math': True, +} + +MARKDOWN_DEFAULT_STYLE = { + 'safe_mode': True, + 'nofollow': True, + 'use_camo': True, + 'math': True, +} + +MARKDOWN_USER_LARGE_STYLE = { + 'safe_mode': True, + 'nofollow': True, + 'use_camo': True, + 'math': True, +} + +MARKDOWN_STYLES = { + 'comment': MARKDOWN_DEFAULT_STYLE, + 'self-description': MARKDOWN_USER_LARGE_STYLE, + 'problem': MARKDOWN_ADMIN_EDITABLE_STYLE, + 'contest': MARKDOWN_ADMIN_EDITABLE_STYLE, + 'language': MARKDOWN_ADMIN_EDITABLE_STYLE, + 'license': MARKDOWN_ADMIN_EDITABLE_STYLE, + 'judge': MARKDOWN_ADMIN_EDITABLE_STYLE, + 'blog': MARKDOWN_ADMIN_EDITABLE_STYLE, + 'solution': MARKDOWN_ADMIN_EDITABLE_STYLE, + 'contest_tag': MARKDOWN_ADMIN_EDITABLE_STYLE, + 'organization-about': MARKDOWN_USER_LARGE_STYLE, + 'ticket': MARKDOWN_USER_LARGE_STYLE, +} + # Database # https://docs.djangoproject.com/en/1.11/ref/settings/#databases DATABASES = { - "default": { - "ENGINE": "django.db.backends.sqlite3", - "NAME": os.path.join(BASE_DIR, "db.sqlite3"), + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), }, } ENABLE_FTS = False # Bridged configuration -BRIDGED_JUDGE_ADDRESS = [("localhost", 9999)] +BRIDGED_JUDGE_ADDRESS = [('localhost', 9999)] BRIDGED_JUDGE_PROXIES = None -BRIDGED_DJANGO_ADDRESS = [("localhost", 9998)] +BRIDGED_DJANGO_ADDRESS = [('localhost', 9998)] BRIDGED_DJANGO_CONNECT = None -BRIDGED_AUTO_CREATE_JUDGE = False # Event Server configuration EVENT_DAEMON_USE = False -EVENT_DAEMON_POST = "ws://localhost:9997/" -EVENT_DAEMON_GET = "ws://localhost:9996/" -EVENT_DAEMON_POLL = "/channels/" +EVENT_DAEMON_POST = 'ws://localhost:9997/' +EVENT_DAEMON_GET = 'ws://localhost:9996/' +EVENT_DAEMON_POLL = '/channels/' EVENT_DAEMON_KEY = None -EVENT_DAEMON_AMQP_EXCHANGE = "dmoj-events" -EVENT_DAEMON_SUBMISSION_KEY = ( - "6Sdmkx^%pk@GsifDfXcwX*Y7LRF%RGT8vmFpSxFBT$fwS7trc8raWfN#CSfQuKApx&$B#Gh2L7p%W!Ww" -) +EVENT_DAEMON_AMQP_EXCHANGE = 'dmoj-events' +EVENT_DAEMON_SUBMISSION_KEY = '6Sdmkx^%pk@GsifDfXcwX*Y7LRF%RGT8vmFpSxFBT$fwS7trc8raWfN#CSfQuKApx&$B#Gh2L7p%W!Ww' # Internationalization # https://docs.djangoproject.com/en/1.11/topics/i18n/ # Whatever you do, this better be one of the entries in `LANGUAGES`. -LANGUAGE_CODE = "vi" -TIME_ZONE = "Asia/Ho_Chi_Minh" -DEFAULT_USER_TIME_ZONE = "Asia/Ho_Chi_Minh" +LANGUAGE_CODE = 'vi' +TIME_ZONE = 'Asia/Ho_Chi_Minh' +DEFAULT_USER_TIME_ZONE = 'Asia/Ho_Chi_Minh' USE_I18N = True USE_L10N = True USE_TZ = True # Cookies -SESSION_ENGINE = "django.contrib.sessions.backends.cached_db" +SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db' # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/1.11/howto/static-files/ -DMOJ_RESOURCES = os.path.join(BASE_DIR, "resources") +DMOJ_RESOURCES = os.path.join(BASE_DIR, 'resources') STATICFILES_FINDERS = ( - "django.contrib.staticfiles.finders.FileSystemFinder", - "django.contrib.staticfiles.finders.AppDirectoriesFinder", + 'django.contrib.staticfiles.finders.FileSystemFinder', + 'django.contrib.staticfiles.finders.AppDirectoriesFinder', ) STATICFILES_DIRS = [ - os.path.join(BASE_DIR, "resources"), + os.path.join(BASE_DIR, 'resources'), ] -STATIC_URL = "/static/" +STATIC_URL = '/static/' # Define a cache CACHES = {} # Authentication AUTHENTICATION_BACKENDS = ( - "social_core.backends.google.GoogleOAuth2", - "social_core.backends.facebook.FacebookOAuth2", - "judge.social_auth.GitHubSecureEmailOAuth2", - "judge.authentication.CustomModelBackend", + 'social_core.backends.google.GoogleOAuth2', + 'social_core.backends.facebook.FacebookOAuth2', + 'judge.social_auth.GitHubSecureEmailOAuth2', + 'django.contrib.auth.backends.ModelBackend', ) SOCIAL_AUTH_PIPELINE = ( - "social_core.pipeline.social_auth.social_details", - "social_core.pipeline.social_auth.social_uid", - "social_core.pipeline.social_auth.auth_allowed", - "judge.social_auth.verify_email", - "social_core.pipeline.social_auth.social_user", - "social_core.pipeline.user.get_username", - "social_core.pipeline.social_auth.associate_by_email", - "judge.social_auth.choose_username", - "social_core.pipeline.user.create_user", - "judge.social_auth.make_profile", - "social_core.pipeline.social_auth.associate_user", - "social_core.pipeline.social_auth.load_extra_data", - "social_core.pipeline.user.user_details", + 'social_core.pipeline.social_auth.social_details', + 'social_core.pipeline.social_auth.social_uid', + 'social_core.pipeline.social_auth.auth_allowed', + 'judge.social_auth.verify_email', + 'social_core.pipeline.social_auth.social_user', + 'social_core.pipeline.user.get_username', + 'social_core.pipeline.social_auth.associate_by_email', + 'judge.social_auth.choose_username', + 'social_core.pipeline.user.create_user', + 'judge.social_auth.make_profile', + 'social_core.pipeline.social_auth.associate_user', + 'social_core.pipeline.social_auth.load_extra_data', + 'social_core.pipeline.user.user_details', ) -SOCIAL_AUTH_PROTECTED_USER_FIELDS = ["first_name", "last_name"] -SOCIAL_AUTH_GOOGLE_OAUTH2_USER_FIELDS = ["email", "username"] -SOCIAL_AUTH_GITHUB_SECURE_SCOPE = ["user:email"] -SOCIAL_AUTH_FACEBOOK_SCOPE = ["email"] +SOCIAL_AUTH_GITHUB_SECURE_SCOPE = ['user:email'] +SOCIAL_AUTH_FACEBOOK_SCOPE = ['email'] SOCIAL_AUTH_SLUGIFY_USERNAMES = True -SOCIAL_AUTH_SLUGIFY_FUNCTION = "judge.social_auth.slugify_username" +SOCIAL_AUTH_SLUGIFY_FUNCTION = 'judge.social_auth.slugify_username' JUDGE_AMQP_PATH = None @@ -464,38 +492,25 @@ MOSS_API_KEY = None CELERY_WORKER_HIJACK_ROOT_LOGGER = False - -TESTCASE_VISIBLE_LENGTH = 64 - -DATA_UPLOAD_MAX_NUMBER_FIELDS = 10240 -DATA_UPLOAD_MAX_MEMORY_SIZE = 2621440 -FILE_UPLOAD_PERMISSIONS = 0o644 - -MESSAGES_TO_LOAD = 15 - -ML_OUTPUT_PATH = None - -# Use subdomain for organizations -USE_SUBDOMAIN = False - -# Chat -CHAT_SECRET_KEY = "QUdVFsxk6f5-Hd8g9BXv81xMqvIZFRqMl-KbRzztW-U=" - -# Nginx -META_REMOTE_ADDRESS_KEY = "REMOTE_ADDR" - -DEFAULT_AUTO_FIELD = "django.db.models.AutoField" - -# Chunk upload -CHUNK_UPLOAD_DIR = "/tmp/chunk_upload_tmp" - -# Rate limit -RL_VOTE = "200/h" -RL_COMMENT = "30/h" - - try: - with open(os.path.join(os.path.dirname(__file__), "local_settings.py")) as f: + with open(os.path.join(os.path.dirname(__file__), 'local_settings.py')) as f: exec(f.read(), globals()) except IOError: pass + +TESTCASE_VISIBLE_LENGTH = 60 + +DATA_UPLOAD_MAX_NUMBER_FIELDS = 10240 +DATA_UPLOAD_MAX_MEMORY_SIZE = 2621440 + +MESSAGES_TO_LOAD = 15 + +ASGI_APPLICATION = 'dmoj.routing.application' +CHANNEL_LAYERS = { + 'default': { + 'BACKEND': 'channels_redis.core.RedisChannelLayer', + 'CONFIG': { + "hosts": [('0.0.0.0', 6379)], + }, + }, +} \ No newline at end of file diff --git a/dmoj/throttle_mail.py b/dmoj/throttle_mail.py index 047e261..7346a21 100644 --- a/dmoj/throttle_mail.py +++ b/dmoj/throttle_mail.py @@ -8,8 +8,8 @@ DEFAULT_THROTTLE = (10, 60) def new_email(): - cache.add("error_email_throttle", 0, settings.DMOJ_EMAIL_THROTTLING[1]) - return cache.incr("error_email_throttle") + cache.add('error_email_throttle', 0, settings.DMOJ_EMAIL_THROTTLING[1]) + return cache.incr('error_email_throttle') class ThrottledEmailHandler(AdminEmailHandler): diff --git a/dmoj/urls.py b/dmoj/urls.py index 1f077f4..5f29558 100644 --- a/dmoj/urls.py +++ b/dmoj/urls.py @@ -1,5 +1,4 @@ -import chat_box.views as chat - +from chat_box.views import ChatView from django.conf import settings from django.conf.urls import include, url from django.contrib import admin @@ -12,1256 +11,391 @@ from django.utils.functional import lazystr from django.utils.translation import ugettext_lazy as _ from django.views.generic import RedirectView from django.contrib.auth.decorators import login_required -from django.conf.urls.static import static as url_static +from judge.feed import AtomBlogFeed, AtomCommentFeed, AtomProblemFeed, BlogFeed, CommentFeed, ProblemFeed from judge.forms import CustomAuthenticationForm -from judge.sitemap import ( - BlogPostSitemap, - ContestSitemap, - HomePageSitemap, - OrganizationSitemap, - ProblemSitemap, - SolutionSitemap, - UrlSitemap, - UserSitemap, -) -from judge.views import ( - TitledTemplateView, - about, - api, - blog, - comment, - contests, - language, - license, - mailgun, - markdown_editor, - test_formatter, - notification, - organization, - preview, - problem, - problem_manage, - ranked_submission, - register, - stats, - status, - submission, - tasks, - ticket, - totp, - user, - volunteer, - pagevote, - bookmark, - widgets, - internal, - resolver, - course, - email, - custom_file_upload, -) -from judge import authentication - -from judge.views.test_formatter import test_formatter - -from judge.views.problem_data import ( - ProblemDataView, - ProblemSubmissionDiff, - problem_data_file, - problem_init_view, - ProblemZipUploadView, -) +from judge.sitemap import BlogPostSitemap, ContestSitemap, HomePageSitemap, OrganizationSitemap, ProblemSitemap, \ + SolutionSitemap, UrlSitemap, UserSitemap +from judge.views import TitledTemplateView, about, api, blog, comment, contests, language, license, mailgun, \ + organization, preview, problem, problem_manage, ranked_submission, register, stats, status, submission, tasks, \ + ticket, totp, user, widgets +from judge.views.problem_data import ProblemDataView, ProblemSubmissionDiff, \ + problem_data_file, problem_init_view from judge.views.register import ActivationView, RegistrationView -from judge.views.select2 import ( - AssigneeSelect2View, - ChatUserSearchSelect2View, - ContestSelect2View, - ContestUserSearchSelect2View, - OrganizationSelect2View, - ProblemSelect2View, - TicketUserSelect2View, - UserSearchSelect2View, - UserSelect2View, - ProblemAuthorSearchSelect2View, -) +from judge.views.select2 import AssigneeSelect2View, CommentSelect2View, ContestSelect2View, \ + ContestUserSearchSelect2View, OrganizationSelect2View, ProblemSelect2View, TicketUserSelect2View, \ + UserSearchSelect2View, UserSelect2View admin.autodiscover() register_patterns = [ - url( - r"^activate/complete/$", - TitledTemplateView.as_view( - template_name="registration/activation_complete.html", - title="Activation Successful!", - ), - name="registration_activation_complete", - ), + url(r'^activate/complete/$', + TitledTemplateView.as_view(template_name='registration/activation_complete.html', + title='Activation Successful!'), + name='registration_activation_complete'), # Activation keys get matched by \w+ instead of the more specific # [a-fA-F0-9]{40} because a bad activation key should still get to the view; # that way it can return a sensible "invalid key" message instead of a # confusing 404. - url( - r"^activate/(?P\w+)/$", - ActivationView.as_view(title=_("Activation key invalid")), - name="registration_activate", - ), - url( - r"^register/$", - RegistrationView.as_view(title=_("Register")), - name="registration_register", - ), - url( - r"^register/complete/$", - TitledTemplateView.as_view( - template_name="registration/registration_complete.html", - title=_("Registration Completed"), - ), - name="registration_complete", - ), - url( - r"^register/closed/$", - TitledTemplateView.as_view( - template_name="registration/registration_closed.html", - title=_("Registration not allowed"), - ), - name="registration_disallowed", - ), - url( - r"^login/$", - auth_views.LoginView.as_view( - template_name="registration/login.html", - extra_context={"title": _("Login")}, - authentication_form=CustomAuthenticationForm, - redirect_authenticated_user=True, - ), - name="auth_login", - ), - url(r"^logout/$", user.UserLogoutView.as_view(), name="auth_logout"), - url( - r"^password/change/$", - authentication.CustomPasswordChangeView.as_view(), - name="password_change", - ), - url( - r"^password/change/done/$", - auth_views.PasswordChangeDoneView.as_view( - template_name="registration/password_change_done.html", - ), - name="password_change_done", - ), - url( - r"^password/reset/$", - auth_views.PasswordResetView.as_view( - template_name="registration/password_reset.html", - html_email_template_name="registration/password_reset_email.html", - email_template_name="registration/password_reset_email.txt", - ), - name="password_reset", - ), - url( - r"^password/reset/confirm/(?P[0-9A-Za-z]+)-(?P.+)/$", + url(r'^activate/(?P\w+)/$', + ActivationView.as_view(title='Activation key invalid'), + name='registration_activate'), + url(r'^register/$', + RegistrationView.as_view(title='Register'), + name='registration_register'), + url(r'^register/complete/$', + TitledTemplateView.as_view(template_name='registration/registration_complete.html', + title='Registration Completed'), + name='registration_complete'), + url(r'^register/closed/$', + TitledTemplateView.as_view(template_name='registration/registration_closed.html', + title='Registration not allowed'), + name='registration_disallowed'), + url(r'^login/$', auth_views.LoginView.as_view( + template_name='registration/login.html', + extra_context={'title': _('Login')}, + authentication_form=CustomAuthenticationForm, + redirect_authenticated_user=True, + ), name='auth_login'), + url(r'^logout/$', user.UserLogoutView.as_view(), name='auth_logout'), + url(r'^password/change/$', auth_views.PasswordChangeView.as_view( + template_name='registration/password_change_form.html', + ), name='password_change'), + url(r'^password/change/done/$', auth_views.PasswordChangeDoneView.as_view( + template_name='registration/password_change_done.html', + ), name='password_change_done'), + url(r'^password/reset/$', auth_views.PasswordResetView.as_view( + template_name='registration/password_reset.html', + html_email_template_name='registration/password_reset_email.html', + email_template_name='registration/password_reset_email.txt', + ), name='password_reset'), + url(r'^password/reset/confirm/(?P[0-9A-Za-z]+)-(?P.+)/$', auth_views.PasswordResetConfirmView.as_view( - template_name="registration/password_reset_confirm.html", - ), - name="password_reset_confirm", - ), - url( - r"^password/reset/complete/$", - auth_views.PasswordResetCompleteView.as_view( - template_name="registration/password_reset_complete.html", - ), - name="password_reset_complete", - ), - url( - r"^password/reset/done/$", - auth_views.PasswordResetDoneView.as_view( - template_name="registration/password_reset_done.html", - ), - name="password_reset_done", - ), - url(r"^email/change/$", email.email_change_view, name="email_change"), - url( - r"^email/change/verify/(?P[0-9A-Za-z]+)-(?P.+)/$", - email.verify_email_view, - name="email_change_verify", - ), - url( - r"^email/change/pending$", - email.email_change_pending_view, - name="email_change_pending", - ), - url(r"^social/error/$", register.social_auth_error, name="social_auth_error"), - url(r"^2fa/$", totp.TOTPLoginView.as_view(), name="login_2fa"), - url(r"^2fa/enable/$", totp.TOTPEnableView.as_view(), name="enable_2fa"), - url(r"^2fa/disable/$", totp.TOTPDisableView.as_view(), name="disable_2fa"), + template_name='registration/password_reset_confirm.html', + ), name='password_reset_confirm'), + url(r'^password/reset/complete/$', auth_views.PasswordResetCompleteView.as_view( + template_name='registration/password_reset_complete.html', + ), name='password_reset_complete'), + url(r'^password/reset/done/$', auth_views.PasswordResetDoneView.as_view( + template_name='registration/password_reset_done.html', + ), name='password_reset_done'), + url(r'^social/error/$', register.social_auth_error, name='social_auth_error'), + + url(r'^2fa/$', totp.TOTPLoginView.as_view(), name='login_2fa'), + url(r'^2fa/enable/$', totp.TOTPEnableView.as_view(), name='enable_2fa'), + url(r'^2fa/disable/$', totp.TOTPDisableView.as_view(), name='disable_2fa'), ] def exception(request): if not request.user.is_superuser: raise Http404() - raise RuntimeError("@Xyene asked me to cause this") + raise RuntimeError('@Xyene asked me to cause this') -def paged_list_view(view, name, **kwargs): - return include( - [ - url(r"^$", view.as_view(**kwargs), name=name), - url(r"^(?P\d+)$", view.as_view(**kwargs), name=name), - ] - ) +def paged_list_view(view, name): + return include([ + url(r'^$', view.as_view(), name=name), + url(r'^(?P\d+)$', view.as_view(), name=name), + ]) urlpatterns = [ - url("", include("pagedown.urls")), - url( - r"^$", - blog.PostList.as_view(template_name="home.html", title=_("Home")), - kwargs={"page": 1}, - name="home", - ), - url(r"^500/$", exception), - url(r"^toggle_darkmode/$", user.toggle_darkmode, name="toggle_darkmode"), - url(r"^admin/", admin.site.urls), - url(r"^i18n/", include("django.conf.urls.i18n")), - url(r"^accounts/", include(register_patterns)), - url(r"^", include("social_django.urls")), - url( - r"^feed/", - include( - [ - url(r"^tickets/$", blog.TicketFeed.as_view(), name="ticket_feed"), - url(r"^comments/$", blog.CommentFeed.as_view(), name="comment_feed"), - ] - ), - ), - url(r"^problems/", paged_list_view(problem.ProblemList, "problem_list")), - url(r"^problems/random/$", problem.RandomProblem.as_view(), name="problem_random"), - url( - r"^problems/feed/$", - problem.ProblemFeed.as_view(feed_type="for_you"), - name="problem_feed", - ), - url( - r"^problems/feed/new/$", - problem.ProblemFeed.as_view(feed_type="new"), - name="problem_feed_new", - ), - url( - r"^problems/feed/volunteer/$", - problem.ProblemFeed.as_view(feed_type="volunteer"), - name="problem_feed_volunteer", - ), - url( - r"^problem/(?P[^/]+)", - include( - [ - url(r"^$", problem.ProblemDetail.as_view(), name="problem_detail"), - url( - r"^/editorial$", - problem.ProblemSolution.as_view(), - name="problem_editorial", - ), - url(r"^/raw$", problem.ProblemRaw.as_view(), name="problem_raw"), - url(r"^/pdf$", problem.ProblemPdfView.as_view(), name="problem_pdf"), - url( - r"^/pdf/(?P[a-z-]+)$", - problem.ProblemPdfView.as_view(), - name="problem_pdf", - ), - url( - r"^/pdf_description$", - problem.ProblemPdfDescriptionView.as_view(), - name="problem_pdf_description", - ), - url(r"^/clone", problem.ProblemClone.as_view(), name="problem_clone"), - url(r"^/submit$", problem.problem_submit, name="problem_submit"), - url( - r"^/resubmit/(?P\d+)$", - problem.problem_submit, - name="problem_submit", - ), - url( - r"^/rank/", - paged_list_view( - ranked_submission.RankedSubmissions, "ranked_submissions" - ), - ), - url( - r"^/submissions/", - paged_list_view( - submission.ProblemSubmissions, "chronological_submissions" - ), - ), - url( - r"^/submissions/(?P\w+)/", - paged_list_view( - submission.UserProblemSubmissions, "user_submissions" - ), - ), - url( - r"^/$", - lambda _, problem: HttpResponsePermanentRedirect( - reverse("problem_detail", args=[problem]) - ), - ), - url(r"^/test_data$", ProblemDataView.as_view(), name="problem_data"), - url(r"^/test_data/init$", problem_init_view, name="problem_data_init"), - url( - r"^/test_data/diff$", - ProblemSubmissionDiff.as_view(), - name="problem_submission_diff", - ), - url( - r"^/test_data/upload$", - ProblemZipUploadView.as_view(), - name="problem_zip_upload", - ), - url( - r"^/data/(?P.+)$", problem_data_file, name="problem_data_file" - ), - url( - r"^/tickets$", - ticket.ProblemTicketListView.as_view(), - name="problem_ticket_list", - ), - url( - r"^/tickets/new$", - ticket.NewProblemTicketView.as_view(), - name="new_problem_ticket", - ), - url( - r"^/manage/submission", - include( - [ - url( - "^$", - problem_manage.ManageProblemSubmissionView.as_view(), - name="problem_manage_submissions", - ), - url( - "^/action$", - problem_manage.ActionSubmissionsView.as_view(), - name="problem_submissions_action", - ), - url( - "^/action/preview$", - problem_manage.PreviewActionSubmissionsView.as_view(), - name="problem_submissions_rejudge_preview", - ), - url( - "^/rejudge/success/(?P[A-Za-z0-9-]*)$", - problem_manage.rejudge_success, - name="problem_submissions_rejudge_success", - ), - url( - "^/rescore/all$", - problem_manage.RescoreAllSubmissionsView.as_view(), - name="problem_submissions_rescore_all", - ), - url( - "^/rescore/success/(?P[A-Za-z0-9-]*)$", - problem_manage.rescore_success, - name="problem_submissions_rescore_success", - ), - ] - ), - ), - ] - ), - ), - url( - r"^submissions/", paged_list_view(submission.AllSubmissions, "all_submissions") - ), - url( - r"^submissions/user/(?P\w+)/", - paged_list_view(submission.AllUserSubmissions, "all_user_submissions"), - ), - url( - r"^submissions/friends/", - paged_list_view(submission.AllFriendSubmissions, "all_friend_submissions"), - ), - url( - r"^src/(?P\d+)/raw$", - submission.SubmissionSourceRaw.as_view(), - name="submission_source_raw", - ), - url( - r"^submission/(?P\d+)", - include( - [ - url( - r"^$", - submission.SubmissionStatus.as_view(), - name="submission_status", - ), - url(r"^/abort$", submission.abort_submission, name="submission_abort"), - ] - ), - ), - url( - r"^test_formatter/", - include( - [ - url( - r"^$", - login_required(test_formatter.TestFormatter.as_view()), - name="test_formatter", - ), - url( - r"^edit_page$", - login_required(test_formatter.EditTestFormatter.as_view()), - name="test_formatter_edit", - ), - url( - r"^download_page$", - login_required(test_formatter.DownloadTestFormatter.as_view()), - name="test_formatter_download", - ), - ] - ), - ), - url( - r"^markdown_editor/", - markdown_editor.MarkdownEditor.as_view(), - name="markdown_editor", - ), - url( - r"^submission_source_file/(?P(\w|\.)+)", - submission.SubmissionSourceFileView.as_view(), - name="submission_source_file", - ), - url( - r"^users/", - include( - [ - url(r"^$", user.users, name="user_list"), - url( - r"^(?P\d+)$", - lambda request, page: HttpResponsePermanentRedirect( - "%s?page=%s" % (reverse("user_list"), page) - ), - ), - url( - r"^find$", user.user_ranking_redirect, name="user_ranking_redirect" - ), - ] - ), - ), - url(r"^user$", user.UserAboutPage.as_view(), name="user_page"), - url(r"^edit/profile/$", user.edit_profile, name="user_edit_profile"), - url(r"^user/bookmarks", user.UserBookMarkPage.as_view(), name="user_bookmark"), - url( - r"^user/(?P\w+)", - include( - [ - url(r"^$", user.UserAboutPage.as_view(), name="user_page"), - url( - r"^/solved", - include( - [ - url( - r"^$", - user.UserProblemsPage.as_view(), - name="user_problems", - ), - url( - r"/ajax$", - user.UserPerformancePointsAjax.as_view(), - name="user_pp_ajax", - ), - ] - ), - ), - url( - r"^/submissions/", - paged_list_view( - submission.AllUserSubmissions, "all_user_submissions_old" - ), - ), - url( - r"^/submissions/", - lambda _, user: HttpResponsePermanentRedirect( - reverse("all_user_submissions", args=[user]) - ), - ), - url(r"^/toggle_follow/", user.toggle_follow, name="user_toggle_follow"), - url( - r"^/$", - lambda _, user: HttpResponsePermanentRedirect( - reverse("user_page", args=[user]) - ), - ), - ] - ), - ), - url(r"^pagevotes/upvote/$", pagevote.upvote_page, name="pagevote_upvote"), - url(r"^pagevotes/downvote/$", pagevote.downvote_page, name="pagevote_downvote"), - url(r"^bookmarks/dobookmark/$", bookmark.dobookmark_page, name="dobookmark"), - url(r"^bookmarks/undobookmark/$", bookmark.undobookmark_page, name="undobookmark"), - url(r"^comments/upvote/$", comment.upvote_comment, name="comment_upvote"), - url(r"^comments/downvote/$", comment.downvote_comment, name="comment_downvote"), - url(r"^comments/hide/$", comment.comment_hide, name="comment_hide"), - url(r"^comments/get_replies/$", comment.get_replies, name="comment_get_replies"), - url(r"^comments/show_more/$", comment.get_show_more, name="comment_show_more"), - url( - r"^comments/(?P\d+)/", - include( - [ - url(r"^edit$", comment.CommentEdit.as_view(), name="comment_edit"), - url( - r"^history/ajax$", - comment.CommentRevisionAjax.as_view(), - name="comment_revision_ajax", - ), - url( - r"^edit/ajax$", - comment.CommentEditAjax.as_view(), - name="comment_edit_ajax", - ), - url( - r"^votes/ajax$", - comment.CommentVotesAjax.as_view(), - name="comment_votes_ajax", - ), - url( - r"^render$", - comment.CommentContent.as_view(), - name="comment_content", - ), - ] - ), - ), - url(r"^contests/", paged_list_view(contests.ContestList, "contest_list")), - url( - r"^contests/summary/(?P\w+)/", - paged_list_view(contests.ContestsSummaryView, "contests_summary"), - ), - url( - r"^contests/official", - paged_list_view(contests.OfficialContestList, "official_contest_list"), - ), - url(r"^courses/", paged_list_view(course.CourseList, "course_list")), - url( - r"^course/(?P[\w-]*)", - include( - [ - url(r"^$", course.CourseDetail.as_view(), name="course_detail"), - url( - r"^/lesson/(?P\d+)$", - course.CourseLessonDetail.as_view(), - name="course_lesson_detail", - ), - url( - r"^/edit_lessons$", - course.EditCourseLessonsView.as_view(), - name="edit_course_lessons", - ), - url( - r"^/grades$", - course.CourseStudentResults.as_view(), - name="course_grades", - ), - url( - r"^/grades/lesson/(?P\d+)$", - course.CourseStudentResultsLesson.as_view(), - name="course_grades_lesson", - ), - url( - r"^/add_contest$", - course.AddCourseContest.as_view(), - name="add_course_contest", - ), - url( - r"^/edit_contest/(?P\w+)$", - course.EditCourseContest.as_view(), - name="edit_course_contest", - ), - url( - r"^/contests$", - course.CourseContestList.as_view(), - name="course_contest_list", - ), - ] - ), - ), - url( - r"^contests/(?P\d+)/(?P\d+)/$", - contests.ContestCalendar.as_view(), - name="contest_calendar", - ), - url( - r"^contests/tag/(?P[a-z-]+)", - include( - [ - url(r"^$", contests.ContestTagDetail.as_view(), name="contest_tag"), - url( - r"^/ajax$", - contests.ContestTagDetailAjax.as_view(), - name="contest_tag_ajax", - ), - ] - ), - ), - url( - r"^contest/(?P\w+)", - include( - [ - url(r"^$", contests.ContestDetail.as_view(), name="contest_view"), - url( - r"^/moss$", contests.ContestMossView.as_view(), name="contest_moss" - ), - url( - r"^/moss/delete$", - contests.ContestMossDelete.as_view(), - name="contest_moss_delete", - ), - url(r"^/clone$", contests.ContestClone.as_view(), name="contest_clone"), - url( - r"^/ranking/$", - contests.ContestRanking.as_view(), - name="contest_ranking", - ), - url( - r"^/final_ranking/$", - contests.ContestFinalRanking.as_view(), - name="contest_final_ranking", - ), - url(r"^/join$", contests.ContestJoin.as_view(), name="contest_join"), - url(r"^/leave$", contests.ContestLeave.as_view(), name="contest_leave"), - url(r"^/stats$", contests.ContestStats.as_view(), name="contest_stats"), - url( - r"^/submissions/(?P\w+)/(?P\w+)", - paged_list_view( - submission.UserContestSubmissions, "contest_user_submissions" - ), - ), - url( - r"^/submissions/(?P\d+)/(?P\w+)/ajax", - paged_list_view( - submission.UserContestSubmissionsAjax, - "contest_user_submissions_ajax", - ), - ), - url( - r"^/submissions", - paged_list_view( - submission.ContestSubmissions, - "contest_submissions", - ), - ), - url( - r"^/participations$", - contests.ContestParticipationList.as_view(), - name="contest_participation_own", - ), - url( - r"^/participations/(?P\w+)$", - contests.ContestParticipationList.as_view(), - name="contest_participation", - ), - url( - r"^/participation/disqualify$", - contests.ContestParticipationDisqualify.as_view(), - name="contest_participation_disqualify", - ), - url( - r"^/clarification$", - contests.NewContestClarificationView.as_view(), - name="new_contest_clarification", - ), - url( - r"^/clarification/ajax$", - contests.ContestClarificationAjax.as_view(), - name="contest_clarification_ajax", - ), - url( - r"^/$", - lambda _, contest: HttpResponsePermanentRedirect( - reverse("contest_view", args=[contest]) - ), - ), - ] - ), - ), - url( - r"^organizations/$", - organization.OrganizationList.as_view(), - name="organization_list", - ), - url( - r"^organizations/add/$", - organization.AddOrganization.as_view(), - name="organization_add", - ), - url( - r"^organization/(?P\d+)-(?P[\w-]*)", - include( - [ - url( - r"^$", - organization.OrganizationHome.as_view(), - name="organization_home", - ), - url( - r"^/users/", - paged_list_view( - organization.OrganizationUsers, - "organization_users", - ), - ), - url( - r"^/problems/", - paged_list_view( - organization.OrganizationProblems, "organization_problems" - ), - ), - url( - r"^/contests/", - paged_list_view( - organization.OrganizationContests, "organization_contests" - ), - ), - url( - r"^/contest/add", - organization.AddOrganizationContest.as_view(), - name="organization_contest_add", - ), - url( - r"^/contest/edit/(?P\w+)", - organization.EditOrganizationContest.as_view(), - name="organization_contest_edit", - ), - url( - r"^/submissions/", - paged_list_view( - organization.OrganizationSubmissions, "organization_submissions" - ), - ), - url( - r"^/join$", - organization.JoinOrganization.as_view(), - name="join_organization", - ), - url( - r"^/leave$", - organization.LeaveOrganization.as_view(), - name="leave_organization", - ), - url( - r"^/edit$", - organization.EditOrganization.as_view(), - name="edit_organization", - ), - url( - r"^/kick$", - organization.KickUserWidgetView.as_view(), - name="organization_user_kick", - ), - url( - r"^/add_member$", - organization.AddOrganizationMember.as_view(), - name="add_organization_member", - ), - url( - r"^/blog/add$", - organization.AddOrganizationBlog.as_view(), - name="add_organization_blog", - ), - url( - r"^/blog/edit/(?P\d+)$", - organization.EditOrganizationBlog.as_view(), - name="edit_organization_blog", - ), - url( - r"^/blog/pending$", - organization.PendingBlogs.as_view(), - name="organization_pending_blogs", - ), - url( - r"^/request$", - organization.RequestJoinOrganization.as_view(), - name="request_organization", - ), - url( - r"^/request/(?P\d+)$", - organization.OrganizationRequestDetail.as_view(), - name="request_organization_detail", - ), - url( - r"^/requests/", - include( - [ - url( - r"^pending$", - organization.OrganizationRequestView.as_view(), - name="organization_requests_pending", - ), - url( - r"^log$", - organization.OrganizationRequestLog.as_view(), - name="organization_requests_log", - ), - url( - r"^approved$", - organization.OrganizationRequestLog.as_view( - states=("A",), tab="approved" - ), - name="organization_requests_approved", - ), - url( - r"^rejected$", - organization.OrganizationRequestLog.as_view( - states=("R",), tab="rejected" - ), - name="organization_requests_rejected", - ), - ] - ), - ), - url( - r"^/$", - lambda _, pk, slug: HttpResponsePermanentRedirect( - reverse("organization_home", args=[pk, slug]) - ), - ), - ] - ), - ), - url(r"^runtimes/$", language.LanguageList.as_view(), name="runtime_list"), - url(r"^runtimes/matrix/$", status.version_matrix, name="version_matrix"), - url(r"^status/$", status.status_all, name="status_all"), - url( - r"^api/", - include( - [ - url(r"^contest/list$", api.api_v1_contest_list), - url(r"^contest/info/(\w+)$", api.api_v1_contest_detail), - url(r"^problem/list$", api.api_v1_problem_list), - url(r"^problem/info/(\w+)$", api.api_v1_problem_info), - url(r"^user/list$", api.api_v1_user_list), - url(r"^user/info/(\w+)$", api.api_v1_user_info), - url(r"^user/submissions/(\w+)$", api.api_v1_user_submissions), - ] - ), - ), - url(r"^blog/", blog.PostList.as_view(), name="blog_post_list"), - url(r"^post/(?P\d+)-(?P.*)$", blog.PostView.as_view(), name="blog_post"), - url(r"^license/(?P[-\w.]+)$", license.LicenseDetail.as_view(), name="license"), - url( - r"^mailgun/mail_activate/$", - mailgun.MailgunActivationView.as_view(), - name="mailgun_activate", - ), - url( - r"^widgets/", - include( - [ - url( - r"^contest_mode$", - contests.update_contest_mode, - name="contest_mode_ajax", - ), - url( - r"^rejudge$", widgets.rejudge_submission, name="submission_rejudge" - ), - url( - r"^single_submission$", - submission.single_submission_query, - name="submission_single_query", - ), - url( - r"^submission_testcases$", - submission.SubmissionTestCaseQuery.as_view(), - name="submission_testcases_query", - ), - url( - r"^detect_timezone$", - widgets.DetectTimezone.as_view(), - name="detect_timezone", - ), - url(r"^status-table$", status.status_table, name="status_table"), - url( - r"^template$", - problem.LanguageTemplateAjax.as_view(), - name="language_template_ajax", - ), - url( - r"^select2/", - include( - [ - url( - r"^user_search$", - UserSearchSelect2View.as_view(), - name="user_search_select2_ajax", - ), - url( - r"^user_search_chat$", - ChatUserSearchSelect2View.as_view(), - name="chat_user_search_select2_ajax", - ), - url( - r"^contest_users/(?P\w+)$", - ContestUserSearchSelect2View.as_view(), - name="contest_user_search_select2_ajax", - ), - url( - r"^ticket_user$", - TicketUserSelect2View.as_view(), - name="ticket_user_select2_ajax", - ), - url( - r"^ticket_assignee$", - AssigneeSelect2View.as_view(), - name="ticket_assignee_select2_ajax", - ), - url( - r"^problem_authors$", - ProblemAuthorSearchSelect2View.as_view(), - name="problem_authors_select2_ajax", - ), - ] - ), - ), - url( - r"^preview/", - include( - [ - url( - r"^problem$", - preview.ProblemMarkdownPreviewView.as_view(), - name="problem_preview", - ), - url( - r"^blog$", - preview.BlogMarkdownPreviewView.as_view(), - name="blog_preview", - ), - url( - r"^contest$", - preview.ContestMarkdownPreviewView.as_view(), - name="contest_preview", - ), - url( - r"^comment$", - preview.CommentMarkdownPreviewView.as_view(), - name="comment_preview", - ), - url( - r"^profile$", - preview.ProfileMarkdownPreviewView.as_view(), - name="profile_preview", - ), - url( - r"^organization$", - preview.OrganizationMarkdownPreviewView.as_view(), - name="organization_preview", - ), - url( - r"^solution$", - preview.SolutionMarkdownPreviewView.as_view(), - name="solution_preview", - ), - url( - r"^license$", - preview.LicenseMarkdownPreviewView.as_view(), - name="license_preview", - ), - url( - r"^ticket$", - preview.TicketMarkdownPreviewView.as_view(), - name="ticket_preview", - ), - ] - ), - ), - ] - ), - ), - url( - r"^stats/", - include( - [ - url( - "^language/", - include( - [ - url( - "^$", - stats.StatLanguage.as_view(), - name="language_stats", - ), - ] - ), - ), - url( - "^site/", - include( - [ - url("^$", stats.StatSite.as_view(), name="site_stats"), - ] - ), - ), - ] - ), - ), - url( - r"^tickets/", - include( - [ - url(r"^$", ticket.TicketList.as_view(), name="ticket_list"), - url(r"^ajax$", ticket.TicketListDataAjax.as_view(), name="ticket_ajax"), - ] - ), - ), - url( - r"^ticket/(?P\d+)", - include( - [ - url(r"^$", ticket.TicketView.as_view(), name="ticket"), - url( - r"^/ajax$", - ticket.TicketMessageDataAjax.as_view(), - name="ticket_message_ajax", - ), - url( - r"^/open$", - ticket.TicketStatusChangeView.as_view(open=True), - name="ticket_open", - ), - url( - r"^/close$", - ticket.TicketStatusChangeView.as_view(open=False), - name="ticket_close", - ), - url( - r"^/notes$", - ticket.TicketNotesEditView.as_view(), - name="ticket_notes", - ), - ] - ), - ), - url( - r"^sitemap\.xml$", - sitemap, - { - "sitemaps": { - "problem": ProblemSitemap, - "user": UserSitemap, - "home": HomePageSitemap, - "contest": ContestSitemap, - "organization": OrganizationSitemap, - "blog": BlogPostSitemap, - "solutions": SolutionSitemap, - "pages": UrlSitemap( - [ - {"location": "/about/", "priority": 0.9}, - ] - ), - } - }, - ), - url( - r"^judge-select2/", - include( - [ - url(r"^profile/$", UserSelect2View.as_view(), name="profile_select2"), - url( - r"^organization/$", - OrganizationSelect2View.as_view(), - name="organization_select2", - ), - url( - r"^problem/$", ProblemSelect2View.as_view(), name="problem_select2" - ), - url( - r"^contest/$", ContestSelect2View.as_view(), name="contest_select2" - ), - ] - ), - ), - url( - r"^tasks/", - include( - [ - url( - r"^status/(?P[A-Za-z0-9-]*)$", - tasks.task_status, - name="task_status", - ), - url(r"^ajax_status$", tasks.task_status_ajax, name="task_status_ajax"), - url(r"^success$", tasks.demo_success), - url(r"^failure$", tasks.demo_failure), - url(r"^progress$", tasks.demo_progress), - ] - ), - ), - url(r"^about/", about.about, name="about"), - url( - r"^custom_checker_sample/", - about.custom_checker_sample, - name="custom_checker_sample", - ), - url( - r"^chat/", - include( - [ - url( - r"^(?P\d*)$", - login_required(chat.ChatView.as_view()), - name="chat", - ), - url(r"^delete/$", chat.delete_message, name="delete_chat_message"), - url(r"^mute/$", chat.mute_message, name="mute_chat_message"), - url(r"^post/$", chat.post_message, name="post_chat_message"), - url(r"^ajax$", chat.chat_message_ajax, name="chat_message_ajax"), - url( - r"^online_status/ajax$", - chat.online_status_ajax, - name="online_status_ajax", - ), - url( - r"^get_or_create_room$", - chat.get_or_create_room, - name="get_or_create_room", - ), - url( - r"^update_last_seen$", - chat.update_last_seen, - name="update_last_seen", - ), - url( - r"^online_status/user/ajax$", - chat.user_online_status_ajax, - name="user_online_status_ajax", - ), - url( - r"^toggle_ignore/(?P\d+)$", - chat.toggle_ignore, - name="toggle_ignore", - ), - ] - ), - ), - url( - r"^internal/", - include( - [ - url( - r"^problem$", - internal.InternalProblem.as_view(), - name="internal_problem", - ), - url( - r"^problem_votes$", - internal.get_problem_votes, - name="internal_problem_votes", - ), - url( - r"^request_time$", - internal.InternalRequestTime.as_view(), - name="internal_request_time", - ), - url( - r"^request_time_detail$", - internal.InternalRequestTimeDetail.as_view(), - name="internal_request_time_detail", - ), - url( - r"^internal_slow_request$", - internal.InternalSlowRequest.as_view(), - name="internal_slow_request", - ), - url( - r"^internal_slow_request_detail$", - internal.InternalSlowRequestDetail.as_view(), - name="internal_slow_request_detail", - ), - ] - ), - ), - url( - r"^notifications/", - paged_list_view(notification.NotificationList, "notification"), - ), - url( - r"^import_users/", - include( - [ - url(r"^$", user.ImportUsersView.as_view(), name="import_users"), - url( - r"post_file/$", - user.import_users_post_file, - name="import_users_post_file", - ), - url(r"submit/$", user.import_users_submit, name="import_users_submit"), - url(r"sample/$", user.sample_import_users, name="import_users_sample"), - ] - ), - ), - url( - r"^volunteer/", - include( - [ - url( - r"^problem/vote$", - volunteer.vote_problem, - name="volunteer_problem_vote", - ), - ] - ), - ), - url(r"^resolver/(?P\w+)", resolver.Resolver.as_view(), name="resolver"), - url(r"^upload/$", custom_file_upload.file_upload, name="custom_file_upload"), -] + url_static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) + url(r'^$', blog.PostList.as_view(template_name='home.html', title=_('Home')), kwargs={'page': 1}, name='home'), + url(r'^500/$', exception), + url(r'^admin/', admin.site.urls), + url(r'^i18n/', include('django.conf.urls.i18n')), + url(r'^accounts/', include(register_patterns)), + url(r'^', include('social_django.urls')), -# if hasattr(settings, "INTERNAL_IPS"): -# urlpatterns.append(url("__debug__/", include("debug_toolbar.urls"))) + url(r'^problems/$', problem.ProblemList.as_view(), name='problem_list'), + url(r'^problems/random/$', problem.RandomProblem.as_view(), name='problem_random'), -favicon_paths = [ - "apple-touch-icon-180x180.png", - "apple-touch-icon-114x114.png", - "android-chrome-72x72.png", - "apple-touch-icon-57x57.png", - "apple-touch-icon-72x72.png", - "apple-touch-icon.png", - "mstile-70x70.png", - "android-chrome-36x36.png", - "apple-touch-icon-precomposed.png", - "apple-touch-icon-76x76.png", - "apple-touch-icon-60x60.png", - "android-chrome-96x96.png", - "mstile-144x144.png", - "mstile-150x150.png", - "safari-pinned-tab.svg", - "android-chrome-144x144.png", - "apple-touch-icon-152x152.png", - "favicon-96x96.png", - "favicon-32x32.png", - "favicon-16x16.png", - "android-chrome-192x192.png", - "android-chrome-512x512.png", - "android-chrome-48x48.png", - "mstile-310x150.png", - "apple-touch-icon-144x144.png", - "browserconfig.xml", - "manifest.json", - "apple-touch-icon-120x120.png", - "mstile-310x310.png", - "reload.png", + url(r'^problem/(?P[^/]+)', include([ + url(r'^$', problem.ProblemDetail.as_view(), name='problem_detail'), + url(r'^/editorial$', problem.ProblemSolution.as_view(), name='problem_editorial'), + url(r'^/raw$', problem.ProblemRaw.as_view(), name='problem_raw'), + url(r'^/pdf$', problem.ProblemPdfView.as_view(), name='problem_pdf'), + url(r'^/pdf/(?P[a-z-]+)$', problem.ProblemPdfView.as_view(), name='problem_pdf'), + url(r'^/clone', problem.ProblemClone.as_view(), name='problem_clone'), + url(r'^/submit$', problem.problem_submit, name='problem_submit'), + url(r'^/resubmit/(?P\d+)$', problem.problem_submit, name='problem_submit'), + + url(r'^/rank/', paged_list_view(ranked_submission.RankedSubmissions, 'ranked_submissions')), + url(r'^/submissions/', paged_list_view(submission.ProblemSubmissions, 'chronological_submissions')), + url(r'^/submissions/(?P\w+)/', paged_list_view(submission.UserProblemSubmissions, 'user_submissions')), + + url(r'^/$', lambda _, problem: HttpResponsePermanentRedirect(reverse('problem_detail', args=[problem]))), + + url(r'^/test_data$', ProblemDataView.as_view(), name='problem_data'), + url(r'^/test_data/init$', problem_init_view, name='problem_data_init'), + url(r'^/test_data/diff$', ProblemSubmissionDiff.as_view(), name='problem_submission_diff'), + url(r'^/data/(?P.+)$', problem_data_file, name='problem_data_file'), + + url(r'^/tickets$', ticket.ProblemTicketListView.as_view(), name='problem_ticket_list'), + url(r'^/tickets/new$', ticket.NewProblemTicketView.as_view(), name='new_problem_ticket'), + + url(r'^/manage/submission', include([ + url('^$', problem_manage.ManageProblemSubmissionView.as_view(), name='problem_manage_submissions'), + url('^/rejudge$', problem_manage.RejudgeSubmissionsView.as_view(), name='problem_submissions_rejudge'), + url('^/rejudge/preview$', problem_manage.PreviewRejudgeSubmissionsView.as_view(), + name='problem_submissions_rejudge_preview'), + url('^/rejudge/success/(?P[A-Za-z0-9-]*)$', problem_manage.rejudge_success, + name='problem_submissions_rejudge_success'), + url('^/rescore/all$', problem_manage.RescoreAllSubmissionsView.as_view(), + name='problem_submissions_rescore_all'), + url('^/rescore/success/(?P[A-Za-z0-9-]*)$', problem_manage.rescore_success, + name='problem_submissions_rescore_success'), + ])), + ])), + + url(r'^submissions/', paged_list_view(submission.AllSubmissions, 'all_submissions')), + url(r'^submissions/user/(?P\w+)/', paged_list_view(submission.AllUserSubmissions, 'all_user_submissions')), + + url(r'^src/(?P\d+)$', submission.SubmissionSource.as_view(), name='submission_source'), + url(r'^src/(?P\d+)/raw$', submission.SubmissionSourceRaw.as_view(), name='submission_source_raw'), + + url(r'^submission/(?P\d+)', include([ + url(r'^$', submission.SubmissionStatus.as_view(), name='submission_status'), + url(r'^/abort$', submission.abort_submission, name='submission_abort'), + url(r'^/html$', submission.single_submission), + ])), + + url(r'^users/', include([ + url(r'^$', user.users, name='user_list'), + url(r'^(?P\d+)$', lambda request, page: + HttpResponsePermanentRedirect('%s?page=%s' % (reverse('user_list'), page))), + url(r'^find$', user.user_ranking_redirect, name='user_ranking_redirect'), + ])), + + url(r'^user$', user.UserAboutPage.as_view(), name='user_page'), + url(r'^edit/profile/$', user.edit_profile, name='user_edit_profile'), + url(r'^user/(?P\w+)', include([ + url(r'^$', user.UserAboutPage.as_view(), name='user_page'), + url(r'^/solved', include([ + url(r'^$', user.UserProblemsPage.as_view(), name='user_problems'), + url(r'/ajax$', user.UserPerformancePointsAjax.as_view(), name='user_pp_ajax'), + ])), + url(r'^/submissions/', paged_list_view(submission.AllUserSubmissions, 'all_user_submissions_old')), + url(r'^/submissions/', lambda _, user: + HttpResponsePermanentRedirect(reverse('all_user_submissions', args=[user]))), + + url(r'^/$', lambda _, user: HttpResponsePermanentRedirect(reverse('user_page', args=[user]))), + ])), + + url(r'^comments/upvote/$', comment.upvote_comment, name='comment_upvote'), + url(r'^comments/downvote/$', comment.downvote_comment, name='comment_downvote'), + url(r'^comments/hide/$', comment.comment_hide, name='comment_hide'), + url(r'^comments/(?P\d+)/', include([ + url(r'^edit$', comment.CommentEdit.as_view(), name='comment_edit'), + url(r'^history/ajax$', comment.CommentRevisionAjax.as_view(), name='comment_revision_ajax'), + url(r'^edit/ajax$', comment.CommentEditAjax.as_view(), name='comment_edit_ajax'), + url(r'^votes/ajax$', comment.CommentVotesAjax.as_view(), name='comment_votes_ajax'), + url(r'^render$', comment.CommentContent.as_view(), name='comment_content'), + ])), + + url(r'^contests/', paged_list_view(contests.ContestList, 'contest_list')), + url(r'^contests/(?P\d+)/(?P\d+)/$', contests.ContestCalendar.as_view(), name='contest_calendar'), + url(r'^contests/tag/(?P[a-z-]+)', include([ + url(r'^$', contests.ContestTagDetail.as_view(), name='contest_tag'), + url(r'^/ajax$', contests.ContestTagDetailAjax.as_view(), name='contest_tag_ajax'), + ])), + + url(r'^contest/(?P\w+)', include([ + url(r'^$', contests.ContestDetail.as_view(), name='contest_view'), + url(r'^/moss$', contests.ContestMossView.as_view(), name='contest_moss'), + url(r'^/moss/delete$', contests.ContestMossDelete.as_view(), name='contest_moss_delete'), + url(r'^/clone$', contests.ContestClone.as_view(), name='contest_clone'), + url(r'^/ranking/$', contests.ContestRanking.as_view(), name='contest_ranking'), + url(r'^/ranking/ajax$', contests.contest_ranking_ajax, name='contest_ranking_ajax'), + url(r'^/join$', contests.ContestJoin.as_view(), name='contest_join'), + url(r'^/leave$', contests.ContestLeave.as_view(), name='contest_leave'), + url(r'^/stats$', contests.ContestStats.as_view(), name='contest_stats'), + + url(r'^/rank/(?P\w+)/', + paged_list_view(ranked_submission.ContestRankedSubmission, 'contest_ranked_submissions')), + + url(r'^/submissions/(?P\w+)/(?P\w+)/', + paged_list_view(submission.UserContestSubmissions, 'contest_user_submissions')), + + url(r'^/participations$', contests.ContestParticipationList.as_view(), name='contest_participation_own'), + url(r'^/participations/(?P\w+)$', + contests.ContestParticipationList.as_view(), name='contest_participation'), + url(r'^/participation/disqualify$', contests.ContestParticipationDisqualify.as_view(), + name='contest_participation_disqualify'), + + url(r'^/$', lambda _, contest: HttpResponsePermanentRedirect(reverse('contest_view', args=[contest]))), + ])), + + url(r'^organizations/$', organization.OrganizationList.as_view(), name='organization_list'), + url(r'^organization/(?P\d+)-(?P[\w-]*)', include([ + url(r'^$', organization.OrganizationHome.as_view(), name='organization_home'), + url(r'^/users$', organization.OrganizationUsers.as_view(), name='organization_users'), + url(r'^/join$', organization.JoinOrganization.as_view(), name='join_organization'), + url(r'^/leave$', organization.LeaveOrganization.as_view(), name='leave_organization'), + url(r'^/edit$', organization.EditOrganization.as_view(), name='edit_organization'), + url(r'^/kick$', organization.KickUserWidgetView.as_view(), name='organization_user_kick'), + + url(r'^/request$', organization.RequestJoinOrganization.as_view(), name='request_organization'), + url(r'^/request/(?P\d+)$', organization.OrganizationRequestDetail.as_view(), + name='request_organization_detail'), + url(r'^/requests/', include([ + url(r'^pending$', organization.OrganizationRequestView.as_view(), name='organization_requests_pending'), + url(r'^log$', organization.OrganizationRequestLog.as_view(), name='organization_requests_log'), + url(r'^approved$', organization.OrganizationRequestLog.as_view(states=('A',), tab='approved'), + name='organization_requests_approved'), + url(r'^rejected$', organization.OrganizationRequestLog.as_view(states=('R',), tab='rejected'), + name='organization_requests_rejected'), + ])), + + url(r'^/$', lambda _, pk, slug: HttpResponsePermanentRedirect(reverse('organization_home', args=[pk, slug]))), + ])), + + url(r'^runtimes/$', language.LanguageList.as_view(), name='runtime_list'), + url(r'^runtimes/matrix/$', status.version_matrix, name='version_matrix'), + url(r'^status/$', status.status_all, name='status_all'), + + url(r'^api/', include([ + url(r'^contest/list$', api.api_v1_contest_list), + url(r'^contest/info/(\w+)$', api.api_v1_contest_detail), + url(r'^problem/list$', api.api_v1_problem_list), + url(r'^problem/info/(\w+)$', api.api_v1_problem_info), + url(r'^user/list$', api.api_v1_user_list), + url(r'^user/info/(\w+)$', api.api_v1_user_info), + url(r'^user/submissions/(\w+)$', api.api_v1_user_submissions), + ])), + + url(r'^blog/', paged_list_view(blog.PostList, 'blog_post_list')), + url(r'^post/(?P\d+)-(?P.*)$', blog.PostView.as_view(), name='blog_post'), + + url(r'^license/(?P[-\w.]+)$', license.LicenseDetail.as_view(), name='license'), + + url(r'^mailgun/mail_activate/$', mailgun.MailgunActivationView.as_view(), name='mailgun_activate'), + + url(r'^widgets/', include([ + url(r'^rejudge$', widgets.rejudge_submission, name='submission_rejudge'), + url(r'^single_submission$', submission.single_submission_query, name='submission_single_query'), + url(r'^submission_testcases$', submission.SubmissionTestCaseQuery.as_view(), name='submission_testcases_query'), + url(r'^detect_timezone$', widgets.DetectTimezone.as_view(), name='detect_timezone'), + url(r'^status-table$', status.status_table, name='status_table'), + + url(r'^template$', problem.LanguageTemplateAjax.as_view(), name='language_template_ajax'), + + url(r'^select2/', include([ + url(r'^user_search$', UserSearchSelect2View.as_view(), name='user_search_select2_ajax'), + url(r'^contest_users/(?P\w+)$', ContestUserSearchSelect2View.as_view(), + name='contest_user_search_select2_ajax'), + url(r'^ticket_user$', TicketUserSelect2View.as_view(), name='ticket_user_select2_ajax'), + url(r'^ticket_assignee$', AssigneeSelect2View.as_view(), name='ticket_assignee_select2_ajax'), + ])), + + url(r'^preview/', include([ + url(r'^problem$', preview.ProblemMarkdownPreviewView.as_view(), name='problem_preview'), + url(r'^blog$', preview.BlogMarkdownPreviewView.as_view(), name='blog_preview'), + url(r'^contest$', preview.ContestMarkdownPreviewView.as_view(), name='contest_preview'), + url(r'^comment$', preview.CommentMarkdownPreviewView.as_view(), name='comment_preview'), + url(r'^profile$', preview.ProfileMarkdownPreviewView.as_view(), name='profile_preview'), + url(r'^organization$', preview.OrganizationMarkdownPreviewView.as_view(), name='organization_preview'), + url(r'^solution$', preview.SolutionMarkdownPreviewView.as_view(), name='solution_preview'), + url(r'^license$', preview.LicenseMarkdownPreviewView.as_view(), name='license_preview'), + url(r'^ticket$', preview.TicketMarkdownPreviewView.as_view(), name='ticket_preview'), + ])), + ])), + + url(r'^feed/', include([ + url(r'^problems/rss/$', ProblemFeed(), name='problem_rss'), + url(r'^problems/atom/$', AtomProblemFeed(), name='problem_atom'), + url(r'^comment/rss/$', CommentFeed(), name='comment_rss'), + url(r'^comment/atom/$', AtomCommentFeed(), name='comment_atom'), + url(r'^blog/rss/$', BlogFeed(), name='blog_rss'), + url(r'^blog/atom/$', AtomBlogFeed(), name='blog_atom'), + ])), + + url(r'^stats/', include([ + url('^language/', include([ + url('^$', stats.language, name='language_stats'), + url('^data/all/$', stats.language_data, name='language_stats_data_all'), + url('^data/ac/$', stats.ac_language_data, name='language_stats_data_ac'), + url('^data/status/$', stats.status_data, name='stats_data_status'), + url('^data/ac_rate/$', stats.ac_rate, name='language_stats_data_ac_rate'), + ])), + ])), + + url(r'^tickets/', include([ + url(r'^$', ticket.TicketList.as_view(), name='ticket_list'), + url(r'^ajax$', ticket.TicketListDataAjax.as_view(), name='ticket_ajax'), + ])), + + url(r'^ticket/(?P\d+)', include([ + url(r'^$', ticket.TicketView.as_view(), name='ticket'), + url(r'^/ajax$', ticket.TicketMessageDataAjax.as_view(), name='ticket_message_ajax'), + url(r'^/open$', ticket.TicketStatusChangeView.as_view(open=True), name='ticket_open'), + url(r'^/close$', ticket.TicketStatusChangeView.as_view(open=False), name='ticket_close'), + url(r'^/notes$', ticket.TicketNotesEditView.as_view(), name='ticket_notes'), + ])), + + url(r'^sitemap\.xml$', sitemap, {'sitemaps': { + 'problem': ProblemSitemap, + 'user': UserSitemap, + 'home': HomePageSitemap, + 'contest': ContestSitemap, + 'organization': OrganizationSitemap, + 'blog': BlogPostSitemap, + 'solutions': SolutionSitemap, + 'pages': UrlSitemap([ + {'location': '/about/', 'priority': 0.9}, + ]), + }}), + + url(r'^judge-select2/', include([ + url(r'^profile/$', UserSelect2View.as_view(), name='profile_select2'), + url(r'^organization/$', OrganizationSelect2View.as_view(), name='organization_select2'), + url(r'^problem/$', ProblemSelect2View.as_view(), name='problem_select2'), + url(r'^contest/$', ContestSelect2View.as_view(), name='contest_select2'), + url(r'^comment/$', CommentSelect2View.as_view(), name='comment_select2'), + ])), + + url(r'^tasks/', include([ + url(r'^status/(?P[A-Za-z0-9-]*)$', tasks.task_status, name='task_status'), + url(r'^ajax_status$', tasks.task_status_ajax, name='task_status_ajax'), + url(r'^success$', tasks.demo_success), + url(r'^failure$', tasks.demo_failure), + url(r'^progress$', tasks.demo_progress), + ])), + + url(r'^about/', about.about, name='about'), + + url(r'^custom_checker_sample/', about.custom_checker_sample, name='custom_checker_sample'), + + url(r'^chat/', include([ + url(r'^$', + login_required(ChatView.as_view()), + name='chat'), + + ])), ] +favicon_paths = ['apple-touch-icon-180x180.png', 'apple-touch-icon-114x114.png', 'android-chrome-72x72.png', + 'apple-touch-icon-57x57.png', 'apple-touch-icon-72x72.png', 'apple-touch-icon.png', 'mstile-70x70.png', + 'android-chrome-36x36.png', 'apple-touch-icon-precomposed.png', 'apple-touch-icon-76x76.png', + 'apple-touch-icon-60x60.png', 'android-chrome-96x96.png', 'mstile-144x144.png', 'mstile-150x150.png', + 'safari-pinned-tab.svg', 'android-chrome-144x144.png', 'apple-touch-icon-152x152.png', + 'favicon-96x96.png', + 'favicon-32x32.png', 'favicon-16x16.png', 'android-chrome-192x192.png', 'android-chrome-48x48.png', + 'mstile-310x150.png', 'apple-touch-icon-144x144.png', 'browserconfig.xml', 'manifest.json', + 'apple-touch-icon-120x120.png', 'mstile-310x310.png'] + for favicon in favicon_paths: - urlpatterns.append( - url(r"^%s$" % favicon, RedirectView.as_view(url=static("icons/" + favicon))) - ) + urlpatterns.append(url(r'^%s$' % favicon, RedirectView.as_view( + url=static('icons/' + favicon) + ))) -handler404 = "judge.views.error.error404" -handler403 = "judge.views.error.error403" -handler500 = "judge.views.error.error500" +handler404 = 'judge.views.error.error404' +handler403 = 'judge.views.error.error403' +handler500 = 'judge.views.error.error500' -if "impersonate" in settings.INSTALLED_APPS: - urlpatterns.append(url(r"^impersonate/", include("impersonate.urls"))) +if 'newsletter' in settings.INSTALLED_APPS: + urlpatterns.append(url(r'^newsletter/', include('newsletter.urls'))) +if 'impersonate' in settings.INSTALLED_APPS: + urlpatterns.append(url(r'^impersonate/', include('impersonate.urls'))) diff --git a/dmoj/wsgi.py b/dmoj/wsgi.py index 3cde2a4..6bec753 100644 --- a/dmoj/wsgi.py +++ b/dmoj/wsgi.py @@ -1,6 +1,5 @@ import os - -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dmoj.settings") +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'dmoj.settings') try: import MySQLdb # noqa: F401, imported for side effect @@ -9,8 +8,5 @@ except ImportError: pymysql.install_as_MySQLdb() -from django.core.wsgi import ( - get_wsgi_application, -) # noqa: E402, django must be imported here - +from django.core.wsgi import get_wsgi_application # noqa: E402, django must be imported here application = get_wsgi_application() diff --git a/dmoj/wsgi_async.py b/dmoj/wsgi_async.py index 4a727c0..69e105f 100644 --- a/dmoj/wsgi_async.py +++ b/dmoj/wsgi_async.py @@ -2,17 +2,13 @@ import os import gevent.monkey # noqa: I100, gevent must be imported here -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dmoj.settings") +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'dmoj.settings') gevent.monkey.patch_all() # noinspection PyUnresolvedReferences import dmoj_install_pymysql # noqa: F401, I100, I202, imported for side effect -from django.core.wsgi import ( - get_wsgi_application, -) # noqa: E402, I100, I202, django must be imported here - +from django.core.wsgi import get_wsgi_application # noqa: E402, I100, I202, django must be imported here # noinspection PyUnresolvedReferences import django_2_2_pymysql_patch # noqa: I100, F401, I202, imported for side effect - application = get_wsgi_application() diff --git a/dmoj_bridge_async.py b/dmoj_bridge_async.py deleted file mode 100644 index f514d6b..0000000 --- a/dmoj_bridge_async.py +++ /dev/null @@ -1,23 +0,0 @@ -import os - -import gevent.monkey # noqa: I100, gevent must be imported here - -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dmoj.settings") -gevent.monkey.patch_all() - -# noinspection PyUnresolvedReferences -import dmoj_install_pymysql # noqa: E402, F401, I100, I202, imported for side effect - -import django # noqa: E402, F401, I100, I202, django must be imported here - -django.setup() - -# noinspection PyUnresolvedReferences -import django_2_2_pymysql_patch # noqa: E402, I100, F401, I202, imported for side effect - -from judge.bridge.daemon import ( - judge_daemon, -) # noqa: E402, I100, I202, django code must be imported here - -if __name__ == "__main__": - judge_daemon() diff --git a/dmoj_celery.py b/dmoj_celery.py index dc7996d..58ea344 100644 --- a/dmoj_celery.py +++ b/dmoj_celery.py @@ -6,7 +6,7 @@ except ImportError: import dmoj_install_pymysql # noqa: F401, imported for side effect # set the default Django settings module for the 'celery' program. -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dmoj.settings") +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'dmoj.settings') # noinspection PyUnresolvedReferences import django_2_2_pymysql_patch # noqa: I100, F401, I202, imported for side effect diff --git a/dmoj_install_pymysql.py b/dmoj_install_pymysql.py index e1795f5..7adabd5 100644 --- a/dmoj_install_pymysql.py +++ b/dmoj_install_pymysql.py @@ -1,4 +1,4 @@ import pymysql pymysql.install_as_MySQLdb() -pymysql.version_info = (1, 4, 0, "final", 0) +pymysql.version_info = (1, 3, 13, "final", 0) diff --git a/event_socket_server/__init__.py b/event_socket_server/__init__.py new file mode 100644 index 0000000..88f7683 --- /dev/null +++ b/event_socket_server/__init__.py @@ -0,0 +1,11 @@ +from .base_server import BaseServer +from .engines import * +from .handler import Handler +from .helpers import ProxyProtocolMixin, SizedPacketHandler, ZlibPacketHandler + + +def get_preferred_engine(choices=('epoll', 'poll', 'select')): + for choice in choices: + if choice in engines: + return engines[choice] + return engines['select'] diff --git a/event_socket_server/base_server.py b/event_socket_server/base_server.py new file mode 100644 index 0000000..667c627 --- /dev/null +++ b/event_socket_server/base_server.py @@ -0,0 +1,169 @@ +import logging +import socket +import threading +import time +from collections import defaultdict, deque +from functools import total_ordering +from heapq import heappop, heappush + +logger = logging.getLogger('event_socket_server') + + +class SendMessage(object): + __slots__ = ('data', 'callback') + + def __init__(self, data, callback): + self.data = data + self.callback = callback + + +@total_ordering +class ScheduledJob(object): + __slots__ = ('time', 'func', 'args', 'kwargs', 'cancel', 'dispatched') + + def __init__(self, time, func, args, kwargs): + self.time = time + self.func = func + self.args = args + self.kwargs = kwargs + self.cancel = False + self.dispatched = False + + def __eq__(self, other): + return self.time == other.time + + def __lt__(self, other): + return self.time < other.time + + +class BaseServer(object): + def __init__(self, addresses, client): + self._servers = set() + for address, port in addresses: + info = socket.getaddrinfo(address, port, socket.AF_UNSPEC, socket.SOCK_STREAM) + for af, socktype, proto, canonname, sa in info: + sock = socket.socket(af, socktype, proto) + sock.setblocking(0) + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + sock.bind(sa) + self._servers.add(sock) + + self._stop = threading.Event() + self._clients = set() + self._ClientClass = client + self._send_queue = defaultdict(deque) + self._job_queue = [] + self._job_queue_lock = threading.Lock() + + def _serve(self): + raise NotImplementedError() + + def _accept(self, sock): + conn, address = sock.accept() + conn.setblocking(0) + client = self._ClientClass(self, conn) + self._clients.add(client) + return client + + def schedule(self, delay, func, *args, **kwargs): + with self._job_queue_lock: + job = ScheduledJob(time.time() + delay, func, args, kwargs) + heappush(self._job_queue, job) + return job + + def unschedule(self, job): + with self._job_queue_lock: + if job.dispatched or job.cancel: + return False + job.cancel = True + return True + + def _register_write(self, client): + raise NotImplementedError() + + def _register_read(self, client): + raise NotImplementedError() + + def _clean_up_client(self, client, finalize=False): + try: + del self._send_queue[client.fileno()] + except KeyError: + pass + client.on_close() + client._socket.close() + if not finalize: + self._clients.remove(client) + + def _dispatch_event(self): + t = time.time() + tasks = [] + with self._job_queue_lock: + while True: + dt = self._job_queue[0].time - t if self._job_queue else 1 + if dt > 0: + break + task = heappop(self._job_queue) + task.dispatched = True + if not task.cancel: + tasks.append(task) + for task in tasks: + logger.debug('Dispatching event: %r(*%r, **%r)', task.func, task.args, task.kwargs) + task.func(*task.args, **task.kwargs) + if not self._job_queue or dt > 1: + dt = 1 + return dt + + def _nonblock_read(self, client): + try: + data = client._socket.recv(1024) + except socket.error: + self._clean_up_client(client) + else: + logger.debug('Read from %s: %d bytes', client.client_address, len(data)) + if not data: + self._clean_up_client(client) + else: + try: + client._recv_data(data) + except Exception: + logger.exception('Client recv_data failure') + self._clean_up_client(client) + + def _nonblock_write(self, client): + fd = client.fileno() + queue = self._send_queue[fd] + try: + top = queue[0] + cb = client._socket.send(top.data) + top.data = top.data[cb:] + logger.debug('Send to %s: %d bytes', client.client_address, cb) + if not top.data: + logger.debug('Finished sending: %s', client.client_address) + if top.callback is not None: + logger.debug('Calling callback: %s: %r', client.client_address, top.callback) + try: + top.callback() + except Exception: + logger.exception('Client write callback failure') + self._clean_up_client(client) + return + queue.popleft() + if not queue: + self._register_read(client) + del self._send_queue[fd] + except socket.error: + self._clean_up_client(client) + + def send(self, client, data, callback=None): + logger.debug('Writing %d bytes to client %s, callback: %s', len(data), client.client_address, callback) + self._send_queue[client.fileno()].append(SendMessage(data, callback)) + self._register_write(client) + + def stop(self): + self._stop.set() + + def serve_forever(self): + self._serve() + + def on_shutdown(self): + pass diff --git a/event_socket_server/engines/__init__.py b/event_socket_server/engines/__init__.py new file mode 100644 index 0000000..5737684 --- /dev/null +++ b/event_socket_server/engines/__init__.py @@ -0,0 +1,17 @@ +import select + +__author__ = 'Quantum' +engines = {} + +from .select_server import SelectServer # noqa: E402, import not at top for consistency +engines['select'] = SelectServer + +if hasattr(select, 'poll'): + from .poll_server import PollServer + engines['poll'] = PollServer + +if hasattr(select, 'epoll'): + from .epoll_server import EpollServer + engines['epoll'] = EpollServer + +del select diff --git a/event_socket_server/engines/epoll_server.py b/event_socket_server/engines/epoll_server.py new file mode 100644 index 0000000..a59755a --- /dev/null +++ b/event_socket_server/engines/epoll_server.py @@ -0,0 +1,17 @@ +import select +__author__ = 'Quantum' + +if not hasattr(select, 'epoll'): + raise ImportError('System does not support epoll') + +from .poll_server import PollServer # noqa: E402, must be imported here + + +class EpollServer(PollServer): + poll = select.epoll + WRITE = select.EPOLLIN | select.EPOLLOUT | select.EPOLLERR | select.EPOLLHUP + READ = select.EPOLLIN | select.EPOLLERR | select.EPOLLHUP + POLLIN = select.EPOLLIN + POLLOUT = select.EPOLLOUT + POLL_CLOSE = select.EPOLLHUP | select.EPOLLERR + NEED_CLOSE = True diff --git a/event_socket_server/engines/poll_server.py b/event_socket_server/engines/poll_server.py new file mode 100644 index 0000000..aa4124b --- /dev/null +++ b/event_socket_server/engines/poll_server.py @@ -0,0 +1,97 @@ +import errno +import logging +import select +import threading + +from ..base_server import BaseServer + +logger = logging.getLogger('event_socket_server') + +if not hasattr(select, 'poll'): + raise ImportError('System does not support poll') + + +class PollServer(BaseServer): + poll = select.poll + WRITE = select.POLLIN | select.POLLOUT | select.POLLERR | select.POLLHUP + READ = select.POLLIN | select.POLLERR | select.POLLHUP + POLLIN = select.POLLIN + POLLOUT = select.POLLOUT + POLL_CLOSE = select.POLLERR | select.POLLHUP + NEED_CLOSE = False + + def __init__(self, *args, **kwargs): + super(PollServer, self).__init__(*args, **kwargs) + self._poll = self.poll() + self._fdmap = {} + self._server_fds = {sock.fileno(): sock for sock in self._servers} + self._close_lock = threading.RLock() + + def _register_write(self, client): + logger.debug('On write mode: %s', client.client_address) + self._poll.modify(client.fileno(), self.WRITE) + + def _register_read(self, client): + logger.debug('On read mode: %s', client.client_address) + self._poll.modify(client.fileno(), self.READ) + + def _clean_up_client(self, client, finalize=False): + logger.debug('Taking close lock: cleanup') + with self._close_lock: + logger.debug('Cleaning up client: %s, finalize: %d', client.client_address, finalize) + fd = client.fileno() + try: + self._poll.unregister(fd) + except IOError as e: + if e.errno != errno.ENOENT: + raise + except KeyError: + pass + del self._fdmap[fd] + super(PollServer, self)._clean_up_client(client, finalize) + + def _serve(self): + for fd, sock in self._server_fds.items(): + self._poll.register(fd, self.POLLIN) + sock.listen(16) + try: + while not self._stop.is_set(): + for fd, event in self._poll.poll(self._dispatch_event()): + if fd in self._server_fds: + client = self._accept(self._server_fds[fd]) + logger.debug('Accepting: %s', client.client_address) + fd = client.fileno() + self._poll.register(fd, self.READ) + self._fdmap[fd] = client + elif event & self.POLL_CLOSE: + logger.debug('Client closed: %s', self._fdmap[fd].client_address) + self._clean_up_client(self._fdmap[fd]) + else: + logger.debug('Taking close lock: event loop') + with self._close_lock: + try: + client = self._fdmap[fd] + except KeyError: + pass + else: + logger.debug('Client active: %s, read: %d, write: %d', + client.client_address, + event & self.POLLIN, + event & self.POLLOUT) + if event & self.POLLIN: + logger.debug('Non-blocking read on client: %s', client.client_address) + self._nonblock_read(client) + # Might be closed in the read handler. + if event & self.POLLOUT and fd in self._fdmap: + logger.debug('Non-blocking write on client: %s', client.client_address) + self._nonblock_write(client) + finally: + logger.info('Shutting down server') + self.on_shutdown() + for client in self._clients: + self._clean_up_client(client, True) + for fd, sock in self._server_fds.items(): + self._poll.unregister(fd) + sock.close() + if self.NEED_CLOSE: + self._poll.close() diff --git a/event_socket_server/engines/select_server.py b/event_socket_server/engines/select_server.py new file mode 100644 index 0000000..3ae9a4d --- /dev/null +++ b/event_socket_server/engines/select_server.py @@ -0,0 +1,49 @@ +import select + +from ..base_server import BaseServer + + +class SelectServer(BaseServer): + def __init__(self, *args, **kwargs): + super(SelectServer, self).__init__(*args, **kwargs) + self._reads = set(self._servers) + self._writes = set() + + def _register_write(self, client): + self._writes.add(client) + + def _register_read(self, client): + self._writes.remove(client) + + def _clean_up_client(self, client, finalize=False): + self._writes.discard(client) + self._reads.remove(client) + super(SelectServer, self)._clean_up_client(client, finalize) + + def _serve(self, select=select.select): + for server in self._servers: + server.listen(16) + try: + while not self._stop.is_set(): + r, w, x = select(self._reads, self._writes, self._reads, self._dispatch_event()) + for s in r: + if s in self._servers: + self._reads.add(self._accept(s)) + else: + self._nonblock_read(s) + + for client in w: + self._nonblock_write(client) + + for s in x: + s.close() + if s in self._servers: + raise RuntimeError('Server is in exceptional condition') + else: + self._clean_up_client(s) + finally: + self.on_shutdown() + for client in self._clients: + self._clean_up_client(client, True) + for server in self._servers: + server.close() diff --git a/event_socket_server/handler.py b/event_socket_server/handler.py new file mode 100644 index 0000000..ecc3314 --- /dev/null +++ b/event_socket_server/handler.py @@ -0,0 +1,27 @@ +__author__ = 'Quantum' + + +class Handler(object): + def __init__(self, server, socket): + self._socket = socket + self.server = server + self.client_address = socket.getpeername() + + def fileno(self): + return self._socket.fileno() + + def _recv_data(self, data): + raise NotImplementedError + + def _send(self, data, callback=None): + return self.server.send(self, data, callback) + + def close(self): + self.server._clean_up_client(self) + + def on_close(self): + pass + + @property + def socket(self): + return self._socket diff --git a/event_socket_server/helpers.py b/event_socket_server/helpers.py new file mode 100644 index 0000000..e8c3672 --- /dev/null +++ b/event_socket_server/helpers.py @@ -0,0 +1,125 @@ +import struct +import zlib + +from judge.utils.unicode import utf8text +from .handler import Handler + +size_pack = struct.Struct('!I') + + +class SizedPacketHandler(Handler): + def __init__(self, server, socket): + super(SizedPacketHandler, self).__init__(server, socket) + self._buffer = b'' + self._packetlen = 0 + + def _packet(self, data): + raise NotImplementedError() + + def _format_send(self, data): + return data + + def _recv_data(self, data): + self._buffer += data + while len(self._buffer) >= self._packetlen if self._packetlen else len(self._buffer) >= size_pack.size: + if self._packetlen: + data = self._buffer[:self._packetlen] + self._buffer = self._buffer[self._packetlen:] + self._packetlen = 0 + self._packet(data) + else: + data = self._buffer[:size_pack.size] + self._buffer = self._buffer[size_pack.size:] + self._packetlen = size_pack.unpack(data)[0] + + def send(self, data, callback=None): + data = self._format_send(data) + self._send(size_pack.pack(len(data)) + data, callback) + + +class ZlibPacketHandler(SizedPacketHandler): + def _format_send(self, data): + return zlib.compress(data.encode('utf-8')) + + def packet(self, data): + raise NotImplementedError() + + def _packet(self, data): + try: + self.packet(zlib.decompress(data).decode('utf-8')) + except zlib.error as e: + self.malformed_packet(e) + + def malformed_packet(self, exception): + self.close() + + +class ProxyProtocolMixin(object): + __UNKNOWN_TYPE = 0 + __PROXY1 = 1 + __PROXY2 = 2 + __DATA = 3 + + __HEADER2 = b'\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A' + __HEADER2_LEN = len(__HEADER2) + + _REAL_IP_SET = None + + @classmethod + def with_proxy_set(cls, ranges): + from netaddr import IPSet, IPGlob + from itertools import chain + + globs = [] + addrs = [] + for item in ranges: + if '*' in item or '-' in item: + globs.append(IPGlob(item)) + else: + addrs.append(item) + ipset = IPSet(chain(chain.from_iterable(globs), addrs)) + return type(cls.__name__, (cls,), {'_REAL_IP_SET': ipset}) + + def __init__(self, server, socket): + super(ProxyProtocolMixin, self).__init__(server, socket) + self.__buffer = b'' + self.__type = (self.__UNKNOWN_TYPE if self._REAL_IP_SET and + self.client_address[0] in self._REAL_IP_SET else self.__DATA) + + def __parse_proxy1(self, data): + self.__buffer += data + index = self.__buffer.find(b'\r\n') + if 0 <= index < 106: + proxy = data[:index].split() + if len(proxy) < 2: + return self.close() + if proxy[1] == b'TCP4': + if len(proxy) != 6: + return self.close() + self.client_address = (utf8text(proxy[2]), utf8text(proxy[4])) + self.server_address = (utf8text(proxy[3]), utf8text(proxy[5])) + elif proxy[1] == b'TCP6': + self.client_address = (utf8text(proxy[2]), utf8text(proxy[4]), 0, 0) + self.server_address = (utf8text(proxy[3]), utf8text(proxy[5]), 0, 0) + elif proxy[1] != b'UNKNOWN': + return self.close() + + self.__type = self.__DATA + super(ProxyProtocolMixin, self)._recv_data(data[index + 2:]) + elif len(self.__buffer) > 107 or index > 105: + self.close() + + def _recv_data(self, data): + if self.__type == self.__DATA: + super(ProxyProtocolMixin, self)._recv_data(data) + elif self.__type == self.__UNKNOWN_TYPE: + if len(data) >= 16 and data[:self.__HEADER2_LEN] == self.__HEADER2: + self.close() + elif len(data) >= 8 and data[:5] == b'PROXY': + self.__type = self.__PROXY1 + self.__parse_proxy1(data) + else: + self.__type = self.__DATA + super(ProxyProtocolMixin, self)._recv_data(data) + else: + self.__parse_proxy1(data) diff --git a/event_socket_server/test_client.py b/event_socket_server/test_client.py new file mode 100644 index 0000000..4f696e8 --- /dev/null +++ b/event_socket_server/test_client.py @@ -0,0 +1,94 @@ +import ctypes +import socket +import struct +import time +import zlib + +size_pack = struct.Struct('!I') +try: + RtlGenRandom = ctypes.windll.advapi32.SystemFunction036 +except AttributeError: + RtlGenRandom = None + + +def open_connection(): + sock = socket.create_connection((host, port)) + return sock + + +def zlibify(data): + data = zlib.compress(data.encode('utf-8')) + return size_pack.pack(len(data)) + data + + +def dezlibify(data, skip_head=True): + if skip_head: + data = data[size_pack.size:] + return zlib.decompress(data).decode('utf-8') + + +def random(length): + if RtlGenRandom is None: + with open('/dev/urandom') as f: + return f.read(length) + buf = ctypes.create_string_buffer(length) + RtlGenRandom(buf, length) + return buf.raw + + +def main(): + global host, port + import argparse + parser = argparse.ArgumentParser() + parser.add_argument('-l', '--host', default='localhost') + parser.add_argument('-p', '--port', default=9999, type=int) + args = parser.parse_args() + host, port = args.host, args.port + + print('Opening idle connection:', end=' ') + s1 = open_connection() + print('Success') + print('Opening hello world connection:', end=' ') + s2 = open_connection() + print('Success') + print('Sending Hello, World!', end=' ') + s2.sendall(zlibify('Hello, World!')) + print('Success') + print('Testing blank connection:', end=' ') + s3 = open_connection() + s3.close() + print('Success') + result = dezlibify(s2.recv(1024)) + assert result == 'Hello, World!' + print(result) + s2.close() + print('Large random data test:', end=' ') + s4 = open_connection() + data = random(1000000) + print('Generated', end=' ') + s4.sendall(zlibify(data)) + print('Sent', end=' ') + result = '' + while len(result) < size_pack.size: + result += s4.recv(1024) + size = size_pack.unpack(result[:size_pack.size])[0] + result = result[size_pack.size:] + while len(result) < size: + result += s4.recv(1024) + print('Received', end=' ') + assert dezlibify(result, False) == data + print('Success') + s4.close() + print('Test malformed connection:', end=' ') + s5 = open_connection() + s5.sendall(data[:100000]) + s5.close() + print('Success') + print('Waiting for timeout to close idle connection:', end=' ') + time.sleep(6) + print('Done') + s1.close() + + +if __name__ == '__main__': + main() diff --git a/event_socket_server/test_server.py b/event_socket_server/test_server.py new file mode 100644 index 0000000..7dec107 --- /dev/null +++ b/event_socket_server/test_server.py @@ -0,0 +1,54 @@ +from .engines import engines +from .helpers import ProxyProtocolMixin, ZlibPacketHandler + + +class EchoPacketHandler(ProxyProtocolMixin, ZlibPacketHandler): + def __init__(self, server, socket): + super(EchoPacketHandler, self).__init__(server, socket) + self._gotdata = False + self.server.schedule(5, self._kill_if_no_data) + + def _kill_if_no_data(self): + if not self._gotdata: + print('Inactive client:', self._socket.getpeername()) + self.close() + + def packet(self, data): + self._gotdata = True + print('Data from %s: %r' % (self._socket.getpeername(), data[:30] if len(data) > 30 else data)) + self.send(data) + + def on_close(self): + self._gotdata = True + print('Closed client:', self._socket.getpeername()) + + +def main(): + import argparse + parser = argparse.ArgumentParser() + parser.add_argument('-l', '--host', action='append') + parser.add_argument('-p', '--port', type=int, action='append') + parser.add_argument('-e', '--engine', default='select', choices=sorted(engines.keys())) + try: + import netaddr + except ImportError: + netaddr = None + else: + parser.add_argument('-P', '--proxy', action='append') + args = parser.parse_args() + + class TestServer(engines[args.engine]): + def _accept(self, sock): + client = super(TestServer, self)._accept(sock) + print('New connection:', client.socket.getpeername()) + return client + + handler = EchoPacketHandler + if netaddr is not None and args.proxy: + handler = handler.with_proxy_set(args.proxy) + server = TestServer(list(zip(args.host, args.port)), handler) + server.serve_forever() + + +if __name__ == '__main__': + main() diff --git a/judge/__init__.py b/judge/__init__.py index 8aefa9d..5c386cd 100644 --- a/judge/__init__.py +++ b/judge/__init__.py @@ -1 +1 @@ -default_app_config = "judge.apps.JudgeAppConfig" +default_app_config = 'judge.apps.JudgeAppConfig' diff --git a/judge/admin/__init__.py b/judge/admin/__init__.py index d303048..51a7173 100644 --- a/judge/admin/__init__.py +++ b/judge/admin/__init__.py @@ -1,62 +1,19 @@ from django.contrib import admin from django.contrib.admin.models import LogEntry -from django.contrib.auth.models import User from judge.admin.comments import CommentAdmin -from judge.admin.contest import ( - ContestAdmin, - ContestParticipationAdmin, - ContestTagAdmin, - ContestsSummaryAdmin, -) -from judge.admin.interface import ( - BlogPostAdmin, - LicenseAdmin, - LogEntryAdmin, - NavigationBarAdmin, -) +from judge.admin.contest import ContestAdmin, ContestParticipationAdmin, ContestTagAdmin +from judge.admin.interface import BlogPostAdmin, LicenseAdmin, LogEntryAdmin, NavigationBarAdmin from judge.admin.organization import OrganizationAdmin, OrganizationRequestAdmin -from judge.admin.problem import ProblemAdmin, ProblemPointsVoteAdmin -from judge.admin.profile import ProfileAdmin, UserAdmin +from judge.admin.problem import ProblemAdmin +from judge.admin.profile import ProfileAdmin from judge.admin.runtime import JudgeAdmin, LanguageAdmin from judge.admin.submission import SubmissionAdmin -from judge.admin.taxon import ( - ProblemGroupAdmin, - ProblemTypeAdmin, - OfficialContestCategoryAdmin, - OfficialContestLocationAdmin, -) +from judge.admin.taxon import ProblemGroupAdmin, ProblemTypeAdmin from judge.admin.ticket import TicketAdmin -from judge.admin.volunteer import VolunteerProblemVoteAdmin -from judge.admin.course import CourseAdmin -from judge.models import ( - BlogPost, - Comment, - CommentLock, - Contest, - ContestParticipation, - ContestTag, - Judge, - Language, - License, - MiscConfig, - NavigationBar, - Organization, - OrganizationRequest, - Problem, - ProblemGroup, - ProblemPointsVote, - ProblemType, - Profile, - Submission, - Ticket, - VolunteerProblemVote, - Course, - ContestsSummary, - OfficialContestCategory, - OfficialContestLocation, -) - +from judge.models import BlogPost, Comment, CommentLock, Contest, ContestParticipation, \ + ContestTag, Judge, Language, License, MiscConfig, NavigationBar, Organization, \ + OrganizationRequest, Problem, ProblemGroup, ProblemType, Profile, Submission, Ticket admin.site.register(BlogPost, BlogPostAdmin) admin.site.register(Comment, CommentAdmin) @@ -74,15 +31,7 @@ admin.site.register(Organization, OrganizationAdmin) admin.site.register(OrganizationRequest, OrganizationRequestAdmin) admin.site.register(Problem, ProblemAdmin) admin.site.register(ProblemGroup, ProblemGroupAdmin) -admin.site.register(ProblemPointsVote, ProblemPointsVoteAdmin) admin.site.register(ProblemType, ProblemTypeAdmin) admin.site.register(Profile, ProfileAdmin) admin.site.register(Submission, SubmissionAdmin) admin.site.register(Ticket, TicketAdmin) -admin.site.register(VolunteerProblemVote, VolunteerProblemVoteAdmin) -admin.site.register(Course, CourseAdmin) -admin.site.unregister(User) -admin.site.register(User, UserAdmin) -admin.site.register(ContestsSummary, ContestsSummaryAdmin) -admin.site.register(OfficialContestCategory, OfficialContestCategoryAdmin) -admin.site.register(OfficialContestLocation, OfficialContestLocationAdmin) diff --git a/judge/admin/comments.py b/judge/admin/comments.py index c33b683..be6780c 100644 --- a/judge/admin/comments.py +++ b/judge/admin/comments.py @@ -11,71 +11,52 @@ from judge.widgets import AdminHeavySelect2Widget, HeavyPreviewAdminPageDownWidg class CommentForm(ModelForm): class Meta: widgets = { - "author": AdminHeavySelect2Widget(data_view="profile_select2"), + 'author': AdminHeavySelect2Widget(data_view='profile_select2'), + 'parent': AdminHeavySelect2Widget(data_view='comment_select2'), } if HeavyPreviewAdminPageDownWidget is not None: - widgets["body"] = HeavyPreviewAdminPageDownWidget( - preview=reverse_lazy("comment_preview") - ) + widgets['body'] = HeavyPreviewAdminPageDownWidget(preview=reverse_lazy('comment_preview')) class CommentAdmin(VersionAdmin): fieldsets = ( - ( - None, - { - "fields": ( - "author", - "parent", - "score", - "hidden", - "content_type", - "object_id", - ) - }, - ), - ("Content", {"fields": ("body",)}), + (None, {'fields': ('author', 'page', 'parent', 'score', 'hidden')}), + ('Content', {'fields': ('body',)}), ) - list_display = ["author", "linked_object", "time"] - search_fields = ["author__user__username", "body"] - readonly_fields = ["score", "parent"] - actions = ["hide_comment", "unhide_comment"] - list_filter = ["hidden"] + list_display = ['author', 'linked_page', 'time'] + search_fields = ['author__user__username', 'page', 'body'] + actions = ['hide_comment', 'unhide_comment'] + list_filter = ['hidden'] actions_on_top = True actions_on_bottom = True form = CommentForm - date_hierarchy = "time" + date_hierarchy = 'time' def get_queryset(self, request): - return Comment.objects.order_by("-time") + return Comment.objects.order_by('-time') def hide_comment(self, request, queryset): count = queryset.update(hidden=True) - self.message_user( - request, - ungettext( - "%d comment successfully hidden.", - "%d comments successfully hidden.", - count, - ) - % count, - ) - - hide_comment.short_description = _("Hide comments") + self.message_user(request, ungettext('%d comment successfully hidden.', + '%d comments successfully hidden.', + count) % count) + hide_comment.short_description = _('Hide comments') def unhide_comment(self, request, queryset): count = queryset.update(hidden=False) - self.message_user( - request, - ungettext( - "%d comment successfully unhidden.", - "%d comments successfully unhidden.", - count, - ) - % count, - ) + self.message_user(request, ungettext('%d comment successfully unhidden.', + '%d comments successfully unhidden.', + count) % count) + unhide_comment.short_description = _('Unhide comments') - unhide_comment.short_description = _("Unhide comments") + def linked_page(self, obj): + link = obj.link + if link is not None: + return format_html('{1}', link, obj.page) + else: + return format_html('{0}', obj.page) + linked_page.short_description = _('Associated page') + linked_page.admin_order_field = 'page' def save_model(self, request, obj, form, change): super(CommentAdmin, self).save_model(request, obj, form, change) diff --git a/judge/admin/contest.py b/judge/admin/contest.py index 062d014..1fc2201 100644 --- a/judge/admin/contest.py +++ b/judge/admin/contest.py @@ -3,36 +3,18 @@ from django.contrib import admin from django.core.exceptions import PermissionDenied from django.db import connection, transaction from django.db.models import Q, TextField -from django.forms import ModelForm, ModelMultipleChoiceField, TextInput +from django.forms import ModelForm, ModelMultipleChoiceField from django.http import Http404, HttpResponseRedirect from django.shortcuts import get_object_or_404 from django.urls import reverse, reverse_lazy -from django.utils import timezone from django.utils.html import format_html from django.utils.translation import gettext_lazy as _, ungettext from reversion.admin import VersionAdmin -from reversion_compare.admin import CompareVersionAdmin -from django_ace import AceWidget -from judge.models import ( - Contest, - ContestProblem, - ContestSubmission, - Profile, - Rating, - OfficialContest, -) +from judge.models import Contest, ContestProblem, ContestSubmission, Profile, Rating from judge.ratings import rate_contest -from judge.widgets import ( - AdminHeavySelect2MultipleWidget, - AdminHeavySelect2Widget, - AdminPagedownWidget, - AdminSelect2MultipleWidget, - AdminSelect2Widget, - HeavyPreviewAdminPageDownWidget, -) -from judge.views.contests import recalculate_contest_summary_result -from judge.utils.contest import maybe_trigger_contest_rescore +from judge.widgets import AdminHeavySelect2MultipleWidget, AdminHeavySelect2Widget, AdminPagedownWidget, \ + AdminSelect2MultipleWidget, AdminSelect2Widget, HeavyPreviewAdminPageDownWidget class AdminHeavySelect2Widget(AdminHeavySelect2Widget): @@ -43,394 +25,197 @@ class AdminHeavySelect2Widget(AdminHeavySelect2Widget): class ContestTagForm(ModelForm): contests = ModelMultipleChoiceField( - label=_("Included contests"), + label=_('Included contests'), queryset=Contest.objects.all(), required=False, - widget=AdminHeavySelect2MultipleWidget(data_view="contest_select2"), - ) + widget=AdminHeavySelect2MultipleWidget(data_view='contest_select2')) class ContestTagAdmin(admin.ModelAdmin): - fields = ("name", "color", "description", "contests") - list_display = ("name", "color") + fields = ('name', 'color', 'description', 'contests') + list_display = ('name', 'color') actions_on_top = True actions_on_bottom = True form = ContestTagForm if AdminPagedownWidget is not None: formfield_overrides = { - TextField: {"widget": AdminPagedownWidget}, + TextField: {'widget': AdminPagedownWidget}, } def save_model(self, request, obj, form, change): super(ContestTagAdmin, self).save_model(request, obj, form, change) - obj.contests.set(form.cleaned_data["contests"]) + obj.contests.set(form.cleaned_data['contests']) def get_form(self, request, obj=None, **kwargs): form = super(ContestTagAdmin, self).get_form(request, obj, **kwargs) if obj is not None: - form.base_fields["contests"].initial = obj.contests.all() + form.base_fields['contests'].initial = obj.contests.all() return form class ContestProblemInlineForm(ModelForm): class Meta: - widgets = { - "problem": AdminHeavySelect2Widget(data_view="problem_select2"), - "hidden_subtasks": TextInput(attrs={"size": "3"}), - "points": TextInput(attrs={"size": "1"}), - "order": TextInput(attrs={"size": "1"}), - } + widgets = {'problem': AdminHeavySelect2Widget(data_view='problem_select2')} class ContestProblemInline(admin.TabularInline): model = ContestProblem - verbose_name = _("Problem") - verbose_name_plural = "Problems" - fields = ( - "problem", - "points", - "partial", - "is_pretested", - "max_submissions", - "hidden_subtasks", - "show_testcases", - "order", - "rejudge_column", - ) - readonly_fields = ("rejudge_column",) + verbose_name = _('Problem') + verbose_name_plural = 'Problems' + fields = ('problem', 'points', 'partial', 'is_pretested', 'max_submissions', 'output_prefix_override', 'order', + 'rejudge_column') + readonly_fields = ('rejudge_column',) form = ContestProblemInlineForm def rejudge_column(self, obj): if obj.id is None: - return "" - return format_html( - 'Rejudge', - reverse("admin:judge_contest_rejudge", args=(obj.contest.id, obj.id)), - ) - - rejudge_column.short_description = "" + return '' + return format_html('Rejudge', + reverse('admin:judge_contest_rejudge', args=(obj.contest.id, obj.id))) + rejudge_column.short_description = '' class ContestForm(ModelForm): def __init__(self, *args, **kwargs): super(ContestForm, self).__init__(*args, **kwargs) - if "rate_exclude" in self.fields: + if 'rate_exclude' in self.fields: if self.instance and self.instance.id: - self.fields["rate_exclude"].queryset = Profile.objects.filter( - contest_history__contest=self.instance - ).distinct() + self.fields['rate_exclude'].queryset = \ + Profile.objects.filter(contest_history__contest=self.instance).distinct() else: - self.fields["rate_exclude"].queryset = Profile.objects.none() - self.fields["banned_users"].widget.can_add_related = False - self.fields["view_contest_scoreboard"].widget.can_add_related = False + self.fields['rate_exclude'].queryset = Profile.objects.none() + self.fields['banned_users'].widget.can_add_related = False def clean(self): cleaned_data = super(ContestForm, self).clean() - cleaned_data["banned_users"].filter( - current_contest__contest=self.instance - ).update(current_contest=None) + cleaned_data['banned_users'].filter(current_contest__contest=self.instance).update(current_contest=None) class Meta: widgets = { - "authors": AdminHeavySelect2MultipleWidget(data_view="profile_select2"), - "curators": AdminHeavySelect2MultipleWidget(data_view="profile_select2"), - "testers": AdminHeavySelect2MultipleWidget(data_view="profile_select2"), - "private_contestants": AdminHeavySelect2MultipleWidget( - data_view="profile_select2", attrs={"style": "width: 100%"} - ), - "organizations": AdminHeavySelect2MultipleWidget( - data_view="organization_select2" - ), - "tags": AdminSelect2MultipleWidget, - "banned_users": AdminHeavySelect2MultipleWidget( - data_view="profile_select2", attrs={"style": "width: 100%"} - ), - "view_contest_scoreboard": AdminHeavySelect2MultipleWidget( - data_view="profile_select2", attrs={"style": "width: 100%"} - ), + 'organizers': AdminHeavySelect2MultipleWidget(data_view='profile_select2'), + 'private_contestants': AdminHeavySelect2MultipleWidget(data_view='profile_select2', + attrs={'style': 'width: 100%'}), + 'organizations': AdminHeavySelect2MultipleWidget(data_view='organization_select2'), + 'tags': AdminSelect2MultipleWidget, + 'banned_users': AdminHeavySelect2MultipleWidget(data_view='profile_select2', + attrs={'style': 'width: 100%'}), } if HeavyPreviewAdminPageDownWidget is not None: - widgets["description"] = HeavyPreviewAdminPageDownWidget( - preview=reverse_lazy("contest_preview") - ) + widgets['description'] = HeavyPreviewAdminPageDownWidget(preview=reverse_lazy('contest_preview')) -class OfficialContestInlineForm(ModelForm): - class Meta: - widgets = { - "category": AdminSelect2Widget, - "location": AdminSelect2Widget, - } - - -class OfficialContestInline(admin.StackedInline): - fields = ( - "category", - "year", - "location", - ) - model = OfficialContest - can_delete = True - form = OfficialContestInlineForm - extra = 0 - - -class ContestAdmin(CompareVersionAdmin): +class ContestAdmin(VersionAdmin): fieldsets = ( - (None, {"fields": ("key", "name", "authors", "curators", "testers")}), - ( - _("Settings"), - { - "fields": ( - "is_visible", - "use_clarifications", - "hide_problem_tags", - "public_scoreboard", - "scoreboard_visibility", - "run_pretests_only", - "points_precision", - "rate_limit", - ) - }, - ), - ( - _("Scheduling"), - {"fields": ("start_time", "end_time", "time_limit", "freeze_after")}, - ), - ( - _("Details"), - { - "fields": ( - "description", - "og_image", - "logo_override_image", - "tags", - "summary", - ) - }, - ), - ( - _("Format"), - {"fields": ("format_name", "format_config", "problem_label_script")}, - ), - ( - _("Rating"), - { - "fields": ( - "is_rated", - "rate_all", - "rating_floor", - "rating_ceiling", - "rate_exclude", - ) - }, - ), - ( - _("Access"), - { - "fields": ( - "access_code", - "private_contestants", - "organizations", - "view_contest_scoreboard", - ) - }, - ), - (_("Justice"), {"fields": ("banned_users",)}), + (None, {'fields': ('key', 'name', 'organizers')}), + (_('Settings'), {'fields': ('is_visible', 'use_clarifications', 'hide_problem_tags', 'hide_scoreboard', + 'run_pretests_only')}), + (_('Scheduling'), {'fields': ('start_time', 'end_time', 'time_limit')}), + (_('Details'), {'fields': ('description', 'og_image', 'logo_override_image', 'tags', 'summary')}), + (_('Format'), {'fields': ('format_name', 'format_config')}), + (_('Rating'), {'fields': ('is_rated', 'rate_all', 'rating_floor', 'rating_ceiling', 'rate_exclude')}), + (_('Access'), {'fields': ('access_code', 'is_private', 'private_contestants', 'is_organization_private', + 'organizations')}), + (_('Justice'), {'fields': ('banned_users',)}), ) - list_display = ( - "key", - "name", - "is_visible", - "is_rated", - "start_time", - "end_time", - "time_limit", - "user_count", - ) - search_fields = ("key", "name") - inlines = [ContestProblemInline, OfficialContestInline] + list_display = ('key', 'name', 'is_visible', 'is_rated', 'start_time', 'end_time', 'time_limit', 'user_count') + actions = ['make_visible', 'make_hidden'] + inlines = [ContestProblemInline] actions_on_top = True actions_on_bottom = True form = ContestForm - change_list_template = "admin/judge/contest/change_list.html" - filter_horizontal = ["rate_exclude"] - date_hierarchy = "start_time" - - def get_actions(self, request): - actions = super(ContestAdmin, self).get_actions(request) - - if request.user.has_perm( - "judge.change_contest_visibility" - ) or request.user.has_perm("judge.create_private_contest"): - for action in ("make_visible", "make_hidden"): - actions[action] = self.get_action(action) - - return actions + change_list_template = 'admin/judge/contest/change_list.html' + filter_horizontal = ['rate_exclude'] + date_hierarchy = 'start_time' def get_queryset(self, request): queryset = Contest.objects.all() - if request.user.has_perm("judge.edit_all_contest"): + if request.user.has_perm('judge.edit_all_contest'): return queryset else: - return queryset.filter( - Q(authors=request.profile) | Q(curators=request.profile) - ).distinct() + return queryset.filter(organizers__id=request.profile.id) def get_readonly_fields(self, request, obj=None): readonly = [] - if not request.user.has_perm("judge.contest_rating"): - readonly += ["is_rated", "rate_all", "rate_exclude"] - if not request.user.has_perm("judge.contest_access_code"): - readonly += ["access_code"] - if not request.user.has_perm("judge.create_private_contest"): - readonly += [ - "private_contestants", - "organizations", - ] - if not request.user.has_perm("judge.change_contest_visibility"): - readonly += ["is_visible"] - if not request.user.has_perm("judge.contest_problem_label"): - readonly += ["problem_label_script"] + if not request.user.has_perm('judge.contest_rating'): + readonly += ['is_rated', 'rate_all', 'rate_exclude'] + if not request.user.has_perm('judge.contest_access_code'): + readonly += ['access_code'] + if not request.user.has_perm('judge.create_private_contest'): + readonly += ['is_private', 'private_contestants', 'is_organization_private', 'organizations'] return readonly - def save_model(self, request, obj, form, change): - # `is_visible` will not appear in `cleaned_data` if user cannot edit it - if form.cleaned_data.get("is_visible") and not request.user.has_perm( - "judge.change_contest_visibility" - ): - if ( - not len(form.cleaned_data["organizations"]) > 0 - and not len(form.cleaned_data["private_contestants"]) > 0 - ): - raise PermissionDenied - if not request.user.has_perm("judge.create_private_contest"): - raise PermissionDenied - - super().save_model(request, obj, form, change) - - def save_related(self, request, form, formsets, change): - super().save_related(request, form, formsets, change) - # Only rescored if we did not already do so in `save_model` - formset_changed = False - if any(formset.has_changed() for formset in formsets): - formset_changed = True - - maybe_trigger_contest_rescore(form, form.instance, formset_changed) - def has_change_permission(self, request, obj=None): - if not request.user.has_perm("judge.edit_own_contest"): + if not request.user.has_perm('judge.edit_own_contest'): return False - if obj is None: + if request.user.has_perm('judge.edit_all_contest') or obj is None: return True - return obj.is_editable_by(request.user) + return obj.organizers.filter(id=request.profile.id).exists() def make_visible(self, request, queryset): - if not request.user.has_perm("judge.change_contest_visibility"): - queryset = queryset.filter( - Q(is_private=True) | Q(is_organization_private=True) - ) count = queryset.update(is_visible=True) - self.message_user( - request, - ungettext( - "%d contest successfully marked as visible.", - "%d contests successfully marked as visible.", - count, - ) - % count, - ) - - make_visible.short_description = _("Mark contests as visible") + self.message_user(request, ungettext('%d contest successfully marked as visible.', + '%d contests successfully marked as visible.', + count) % count) + make_visible.short_description = _('Mark contests as visible') def make_hidden(self, request, queryset): - if not request.user.has_perm("judge.change_contest_visibility"): - queryset = queryset.filter( - Q(is_private=True) | Q(is_organization_private=True) - ) - count = queryset.update(is_visible=True) - self.message_user( - request, - ungettext( - "%d contest successfully marked as hidden.", - "%d contests successfully marked as hidden.", - count, - ) - % count, - ) - - make_hidden.short_description = _("Mark contests as hidden") + count = queryset.update(is_visible=False) + self.message_user(request, ungettext('%d contest successfully marked as hidden.', + '%d contests successfully marked as hidden.', + count) % count) + make_hidden.short_description = _('Mark contests as hidden') def get_urls(self): return [ - url(r"^rate/all/$", self.rate_all_view, name="judge_contest_rate_all"), - url(r"^(\d+)/rate/$", self.rate_view, name="judge_contest_rate"), - url( - r"^(\d+)/judge/(\d+)/$", self.rejudge_view, name="judge_contest_rejudge" - ), + url(r'^rate/all/$', self.rate_all_view, name='judge_contest_rate_all'), + url(r'^(\d+)/rate/$', self.rate_view, name='judge_contest_rate'), + url(r'^(\d+)/judge/(\d+)/$', self.rejudge_view, name='judge_contest_rejudge'), ] + super(ContestAdmin, self).get_urls() def rejudge_view(self, request, contest_id, problem_id): - queryset = ContestSubmission.objects.filter( - problem_id=problem_id - ).select_related("submission") + queryset = ContestSubmission.objects.filter(problem_id=problem_id).select_related('submission') for model in queryset: model.submission.judge(rejudge=True) - self.message_user( - request, - ungettext( - "%d submission was successfully scheduled for rejudging.", - "%d submissions were successfully scheduled for rejudging.", - len(queryset), - ) - % len(queryset), - ) - return HttpResponseRedirect( - reverse("admin:judge_contest_change", args=(contest_id,)) - ) + self.message_user(request, ungettext('%d submission was successfully scheduled for rejudging.', + '%d submissions were successfully scheduled for rejudging.', + len(queryset)) % len(queryset)) + return HttpResponseRedirect(reverse('admin:judge_contest_change', args=(contest_id,))) def rate_all_view(self, request): - if not request.user.has_perm("judge.contest_rating"): + if not request.user.has_perm('judge.contest_rating'): raise PermissionDenied() with transaction.atomic(): - with connection.cursor() as cursor: - cursor.execute("TRUNCATE TABLE `%s`" % Rating._meta.db_table) + if connection.vendor == 'sqlite': + Rating.objects.all().delete() + else: + cursor = connection.cursor() + cursor.execute('TRUNCATE TABLE `%s`' % Rating._meta.db_table) + cursor.close() Profile.objects.update(rating=None) - for contest in Contest.objects.filter( - is_rated=True, end_time__lte=timezone.now() - ).order_by("end_time"): + for contest in Contest.objects.filter(is_rated=True).order_by('end_time'): rate_contest(contest) - return HttpResponseRedirect(reverse("admin:judge_contest_changelist")) + return HttpResponseRedirect(reverse('admin:judge_contest_changelist')) def rate_view(self, request, id): - if not request.user.has_perm("judge.contest_rating"): + if not request.user.has_perm('judge.contest_rating'): raise PermissionDenied() contest = get_object_or_404(Contest, id=id) - if not contest.is_rated or not contest.ended: + if not contest.is_rated: raise Http404() with transaction.atomic(): contest.rate() - return HttpResponseRedirect( - request.META.get("HTTP_REFERER", reverse("admin:judge_contest_changelist")) - ) + return HttpResponseRedirect(request.META.get('HTTP_REFERER', reverse('admin:judge_contest_changelist'))) - def get_form(self, request, obj=None, **kwargs): - form = super(ContestAdmin, self).get_form(request, obj, **kwargs) - if "problem_label_script" in form.base_fields: - # form.base_fields['problem_label_script'] does not exist when the user has only view permission - # on the model. - form.base_fields["problem_label_script"].widget = AceWidget( - "lua", request.profile.ace_theme - ) - - perms = ("edit_own_contest", "edit_all_contest") - form.base_fields["curators"].queryset = Profile.objects.filter( - Q(user__is_superuser=True) - | Q(user__groups__permissions__codename__in=perms) - | Q(user__user_permissions__codename__in=perms), + def get_form(self, *args, **kwargs): + form = super(ContestAdmin, self).get_form(*args, **kwargs) + perms = ('edit_own_contest', 'edit_all_contest') + form.base_fields['organizers'].queryset = Profile.objects.filter( + Q(user__is_superuser=True) | + Q(user__groups__permissions__codename__in=perms) | + Q(user__user_permissions__codename__in=perms), ).distinct() return form @@ -438,48 +223,29 @@ class ContestAdmin(CompareVersionAdmin): class ContestParticipationForm(ModelForm): class Meta: widgets = { - "contest": AdminSelect2Widget(), - "user": AdminHeavySelect2Widget(data_view="profile_select2"), + 'contest': AdminSelect2Widget(), + 'user': AdminHeavySelect2Widget(data_view='profile_select2'), } class ContestParticipationAdmin(admin.ModelAdmin): - fields = ("contest", "user", "real_start", "virtual", "is_disqualified") - list_display = ( - "contest", - "username", - "show_virtual", - "real_start", - "score", - "cumtime", - "tiebreaker", - ) - actions = ["recalculate_results"] + fields = ('contest', 'user', 'real_start', 'virtual', 'is_disqualified') + list_display = ('contest', 'username', 'show_virtual', 'real_start', 'score', 'cumtime') + actions = ['recalculate_results'] actions_on_bottom = actions_on_top = True - search_fields = ("contest__key", "contest__name", "user__user__username") + search_fields = ('contest__key', 'contest__name', 'user__user__username') form = ContestParticipationForm - date_hierarchy = "real_start" + date_hierarchy = 'real_start' def get_queryset(self, request): - return ( - super(ContestParticipationAdmin, self) - .get_queryset(request) - .only( - "contest__name", - "contest__format_name", - "contest__format_config", - "user__user__username", - "real_start", - "score", - "cumtime", - "tiebreaker", - "virtual", - ) + return super(ContestParticipationAdmin, self).get_queryset(request).only( + 'contest__name', 'contest__format_name', 'contest__format_config', + 'user__user__username', 'real_start', 'score', 'cumtime', 'virtual', ) def save_model(self, request, obj, form, change): super().save_model(request, obj, form, change) - if form.changed_data and "is_disqualified" in form.changed_data: + if form.changed_data and 'is_disqualified' in form.changed_data: obj.set_disqualified(obj.is_disqualified) def recalculate_results(self, request, queryset): @@ -487,48 +253,17 @@ class ContestParticipationAdmin(admin.ModelAdmin): for participation in queryset: participation.recompute_results() count += 1 - self.message_user( - request, - ungettext( - "%d participation recalculated.", - "%d participations recalculated.", - count, - ) - % count, - ) - - recalculate_results.short_description = _("Recalculate results") + self.message_user(request, ungettext('%d participation recalculated.', + '%d participations recalculated.', + count) % count) + recalculate_results.short_description = _('Recalculate results') def username(self, obj): return obj.user.username - - username.short_description = _("username") - username.admin_order_field = "user__user__username" + username.short_description = _('username') + username.admin_order_field = 'user__user__username' def show_virtual(self, obj): - return obj.virtual or "-" - - show_virtual.short_description = _("virtual") - show_virtual.admin_order_field = "virtual" - - -class ContestsSummaryForm(ModelForm): - class Meta: - widgets = { - "contests": AdminHeavySelect2MultipleWidget( - data_view="contest_select2", attrs={"style": "width: 100%"} - ), - } - - -class ContestsSummaryAdmin(admin.ModelAdmin): - fields = ("key", "contests", "scores") - list_display = ("key",) - search_fields = ("key", "contests__key") - form = ContestsSummaryForm - - def save_model(self, request, obj, form, change): - super(ContestsSummaryAdmin, self).save_model(request, obj, form, change) - obj.refresh_from_db() - obj.results = recalculate_contest_summary_result(request, obj) - obj.save() + return obj.virtual or '-' + show_virtual.short_description = _('virtual') + show_virtual.admin_order_field = 'virtual' diff --git a/judge/admin/course.py b/judge/admin/course.py deleted file mode 100644 index ac8c0fd..0000000 --- a/judge/admin/course.py +++ /dev/null @@ -1,52 +0,0 @@ -from django.contrib import admin -from django.utils.html import format_html -from django.urls import reverse, reverse_lazy -from django.utils.translation import gettext, gettext_lazy as _, ungettext -from django.forms import ModelForm - -from judge.models import Course, CourseRole -from judge.widgets import AdminSelect2MultipleWidget -from judge.widgets import ( - AdminHeavySelect2MultipleWidget, - AdminHeavySelect2Widget, - HeavyPreviewAdminPageDownWidget, - AdminSelect2Widget, -) - - -class CourseRoleInlineForm(ModelForm): - class Meta: - widgets = { - "user": AdminHeavySelect2Widget( - data_view="profile_select2", attrs={"style": "width: 100%"} - ), - "role": AdminSelect2Widget, - } - - -class CourseRoleInline(admin.TabularInline): - model = CourseRole - extra = 1 - form = CourseRoleInlineForm - - -class CourseForm(ModelForm): - class Meta: - widgets = { - "organizations": AdminHeavySelect2MultipleWidget( - data_view="organization_select2" - ), - "about": HeavyPreviewAdminPageDownWidget( - preview=reverse_lazy("blog_preview") - ), - } - - -class CourseAdmin(admin.ModelAdmin): - prepopulated_fields = {"slug": ("name",)} - inlines = [ - CourseRoleInline, - ] - list_display = ("name", "is_public", "is_open") - search_fields = ("name",) - form = CourseForm diff --git a/judge/admin/interface.py b/judge/admin/interface.py index b377212..0bfec14 100644 --- a/judge/admin/interface.py +++ b/judge/admin/interface.py @@ -6,33 +6,26 @@ from django.utils.html import format_html from django.utils.translation import gettext_lazy as _ from mptt.admin import DraggableMPTTAdmin from reversion.admin import VersionAdmin -from reversion_compare.admin import CompareVersionAdmin - from judge.dblock import LockModel from judge.models import NavigationBar -from judge.widgets import ( - AdminHeavySelect2MultipleWidget, - AdminHeavySelect2Widget, - HeavyPreviewAdminPageDownWidget, -) +from judge.widgets import AdminHeavySelect2MultipleWidget, AdminHeavySelect2Widget, HeavyPreviewAdminPageDownWidget class NavigationBarAdmin(DraggableMPTTAdmin): - list_display = DraggableMPTTAdmin.list_display + ("key", "linked_path") - fields = ("key", "label", "path", "order", "regex", "parent") + list_display = DraggableMPTTAdmin.list_display + ('key', 'linked_path') + fields = ('key', 'label', 'path', 'order', 'regex', 'parent') list_editable = () # Bug in SortableModelAdmin: 500 without list_editable being set mptt_level_indent = 20 - sortable = "order" + sortable = 'order' def __init__(self, *args, **kwargs): super(NavigationBarAdmin, self).__init__(*args, **kwargs) self.__save_model_calls = 0 def linked_path(self, obj): - return format_html('{0}', obj.path) - - linked_path.short_description = _("link path") + return format_html(u'{0}', obj.path) + linked_path.short_description = _('link path') def save_model(self, request, obj, form, change): self.__save_model_calls += 1 @@ -41,9 +34,7 @@ class NavigationBarAdmin(DraggableMPTTAdmin): def changelist_view(self, request, extra_context=None): self.__save_model_calls = 0 with NavigationBar.objects.disable_mptt_updates(): - result = super(NavigationBarAdmin, self).changelist_view( - request, extra_context - ) + result = super(NavigationBarAdmin, self).changelist_view(request, extra_context) if self.__save_model_calls: with LockModel(write=(NavigationBar,)): NavigationBar.objects.rebuild() @@ -53,106 +44,71 @@ class NavigationBarAdmin(DraggableMPTTAdmin): class BlogPostForm(ModelForm): def __init__(self, *args, **kwargs): super(BlogPostForm, self).__init__(*args, **kwargs) - if "authors" in self.fields: - self.fields["authors"].widget.can_add_related = False + self.fields['authors'].widget.can_add_related = False class Meta: widgets = { - "authors": AdminHeavySelect2MultipleWidget( - data_view="profile_select2", attrs={"style": "width: 100%"} - ), - "organizations": AdminHeavySelect2MultipleWidget( - data_view="organization_select2", attrs={"style": "width: 100%"} - ), + 'authors': AdminHeavySelect2MultipleWidget(data_view='profile_select2', attrs={'style': 'width: 100%'}), } if HeavyPreviewAdminPageDownWidget is not None: - widgets["content"] = HeavyPreviewAdminPageDownWidget( - preview=reverse_lazy("blog_preview") - ) - widgets["summary"] = HeavyPreviewAdminPageDownWidget( - preview=reverse_lazy("blog_preview") - ) + widgets['content'] = HeavyPreviewAdminPageDownWidget(preview=reverse_lazy('blog_preview')) + widgets['summary'] = HeavyPreviewAdminPageDownWidget(preview=reverse_lazy('blog_preview')) -class BlogPostAdmin(CompareVersionAdmin): +class BlogPostAdmin(VersionAdmin): fieldsets = ( - ( - None, - { - "fields": ( - "title", - "slug", - "authors", - "visible", - "sticky", - "publish_on", - "is_organization_private", - "organizations", - ) - }, - ), - (_("Content"), {"fields": ("content", "og_image")}), - (_("Summary"), {"classes": ("collapse",), "fields": ("summary",)}), + (None, {'fields': ('title', 'slug', 'authors', 'visible', 'sticky', 'publish_on')}), + (_('Content'), {'fields': ('content', 'og_image')}), + (_('Summary'), {'classes': ('collapse',), 'fields': ('summary',)}), ) - prepopulated_fields = {"slug": ("title",)} - list_display = ("id", "title", "visible", "sticky", "publish_on") - list_display_links = ("id", "title") - ordering = ("-publish_on",) + prepopulated_fields = {'slug': ('title',)} + list_display = ('id', 'title', 'visible', 'sticky', 'publish_on') + list_display_links = ('id', 'title') + ordering = ('-publish_on',) form = BlogPostForm - date_hierarchy = "publish_on" + date_hierarchy = 'publish_on' def has_change_permission(self, request, obj=None): - return ( - request.user.has_perm("judge.edit_all_post") - or request.user.has_perm("judge.change_blogpost") - and (obj is None or obj.authors.filter(id=request.profile.id).exists()) - ) + return (request.user.has_perm('judge.edit_all_post') or + request.user.has_perm('judge.change_blogpost') and ( + obj is None or + obj.authors.filter(id=request.profile.id).exists())) class SolutionForm(ModelForm): def __init__(self, *args, **kwargs): super(SolutionForm, self).__init__(*args, **kwargs) - self.fields["authors"].widget.can_add_related = False + self.fields['authors'].widget.can_add_related = False class Meta: widgets = { - "authors": AdminHeavySelect2MultipleWidget( - data_view="profile_select2", attrs={"style": "width: 100%"} - ), - "problem": AdminHeavySelect2Widget( - data_view="problem_select2", attrs={"style": "width: 250px"} - ), + 'authors': AdminHeavySelect2MultipleWidget(data_view='profile_select2', attrs={'style': 'width: 100%'}), + 'problem': AdminHeavySelect2Widget(data_view='problem_select2', attrs={'style': 'width: 250px'}), } if HeavyPreviewAdminPageDownWidget is not None: - widgets["content"] = HeavyPreviewAdminPageDownWidget( - preview=reverse_lazy("solution_preview") - ) + widgets['content'] = HeavyPreviewAdminPageDownWidget(preview=reverse_lazy('solution_preview')) class LicenseForm(ModelForm): class Meta: if HeavyPreviewAdminPageDownWidget is not None: - widgets = { - "text": HeavyPreviewAdminPageDownWidget( - preview=reverse_lazy("license_preview") - ) - } + widgets = {'text': HeavyPreviewAdminPageDownWidget(preview=reverse_lazy('license_preview'))} class LicenseAdmin(admin.ModelAdmin): - fields = ("key", "link", "name", "display", "icon", "text") - list_display = ("name", "key") + fields = ('key', 'link', 'name', 'display', 'icon', 'text') + list_display = ('name', 'key') form = LicenseForm class UserListFilter(admin.SimpleListFilter): - title = _("user") - parameter_name = "user" + title = _('user') + parameter_name = 'user' def lookups(self, request, model_admin): - return User.objects.filter(is_staff=True).values_list("id", "username") + return User.objects.filter(is_staff=True).values_list('id', 'username') def queryset(self, request, queryset): if self.value(): @@ -161,29 +117,10 @@ class UserListFilter(admin.SimpleListFilter): class LogEntryAdmin(admin.ModelAdmin): - readonly_fields = ( - "user", - "content_type", - "object_id", - "object_repr", - "action_flag", - "change_message", - ) - list_display = ( - "__str__", - "action_time", - "user", - "content_type", - "object_link", - "diff_link", - ) - search_fields = ( - "object_repr", - "change_message", - "user__username", - "content_type__model", - ) - list_filter = (UserListFilter, "content_type") + readonly_fields = ('user', 'content_type', 'object_id', 'object_repr', 'action_flag', 'change_message') + list_display = ('__str__', 'action_time', 'user', 'content_type', 'object_link') + search_fields = ('object_repr', 'change_message') + list_filter = (UserListFilter, 'content_type') list_display_links = None actions = None @@ -202,35 +139,13 @@ class LogEntryAdmin(admin.ModelAdmin): else: ct = obj.content_type try: - link = format_html( - '{0}', - obj.object_repr, - reverse( - "admin:%s_%s_change" % (ct.app_label, ct.model), - args=(obj.object_id,), - ), - ) + link = format_html('{0}', obj.object_repr, + reverse('admin:%s_%s_change' % (ct.app_label, ct.model), args=(obj.object_id,))) except NoReverseMatch: link = obj.object_repr return link - - object_link.admin_order_field = "object_repr" - object_link.short_description = _("object") - - def diff_link(self, obj): - if obj.is_deletion(): - return None - ct = obj.content_type - try: - url = reverse( - "admin:%s_%s_history" % (ct.app_label, ct.model), args=(obj.object_id,) - ) - link = format_html('{0}', _("Diff"), url) - except NoReverseMatch: - link = None - return link - - diff_link.short_description = _("diff") + object_link.admin_order_field = 'object_repr' + object_link.short_description = _('object') def queryset(self, request): - return super().queryset(request).prefetch_related("content_type") + return super().queryset(request).prefetch_related('content_type') diff --git a/judge/admin/organization.py b/judge/admin/organization.py index 4ac7708..f9d78d4 100644 --- a/judge/admin/organization.py +++ b/judge/admin/organization.py @@ -6,94 +6,61 @@ from django.utils.translation import gettext, gettext_lazy as _ from reversion.admin import VersionAdmin from judge.models import Organization -from judge.widgets import ( - AdminHeavySelect2MultipleWidget, - AdminHeavySelect2Widget, - HeavyPreviewAdminPageDownWidget, -) +from judge.widgets import AdminHeavySelect2MultipleWidget, AdminHeavySelect2Widget, HeavyPreviewAdminPageDownWidget class OrganizationForm(ModelForm): class Meta: widgets = { - "admins": AdminHeavySelect2MultipleWidget(data_view="profile_select2"), - "registrant": AdminHeavySelect2Widget(data_view="profile_select2"), + 'admins': AdminHeavySelect2MultipleWidget(data_view='profile_select2'), + 'registrant': AdminHeavySelect2Widget(data_view='profile_select2'), } if HeavyPreviewAdminPageDownWidget is not None: - widgets["about"] = HeavyPreviewAdminPageDownWidget( - preview=reverse_lazy("organization_preview") - ) + widgets['about'] = HeavyPreviewAdminPageDownWidget(preview=reverse_lazy('organization_preview')) class OrganizationAdmin(VersionAdmin): - readonly_fields = ("creation_date",) - fields = ( - "name", - "slug", - "short_name", - "is_open", - "about", - "slots", - "registrant", - "creation_date", - "admins", - ) - list_display = ( - "name", - "short_name", - "is_open", - "creation_date", - "registrant", - "show_public", - ) - search_fields = ("name", "short_name", "registrant__user__username") - prepopulated_fields = {"slug": ("name",)} + readonly_fields = ('creation_date',) + fields = ('name', 'slug', 'short_name', 'is_open', 'about', 'logo_override_image', 'slots', 'registrant', + 'creation_date', 'admins') + list_display = ('name', 'short_name', 'is_open', 'slots', 'registrant', 'show_public') + prepopulated_fields = {'slug': ('name',)} actions_on_top = True actions_on_bottom = True form = OrganizationForm - ordering = ["-creation_date"] def show_public(self, obj): - return format_html( - '{1}', - obj.get_absolute_url(), - gettext("View on site"), - ) + return format_html('{1}', + obj.get_absolute_url(), gettext('View on site')) - show_public.short_description = "" + show_public.short_description = '' def get_readonly_fields(self, request, obj=None): fields = self.readonly_fields - if not request.user.has_perm("judge.organization_admin"): - return fields + ("registrant", "admins", "is_open", "slots") + if not request.user.has_perm('judge.organization_admin'): + return fields + ('registrant', 'admins', 'is_open', 'slots') return fields def get_queryset(self, request): queryset = Organization.objects.all() - if request.user.has_perm("judge.edit_all_organization"): + if request.user.has_perm('judge.edit_all_organization'): return queryset else: return queryset.filter(admins=request.profile.id) def has_change_permission(self, request, obj=None): - if not request.user.has_perm("judge.change_organization"): + if not request.user.has_perm('judge.change_organization'): return False - if request.user.has_perm("judge.edit_all_organization") or obj is None: + if request.user.has_perm('judge.edit_all_organization') or obj is None: return True return obj.admins.filter(id=request.profile.id).exists() - def save_related(self, request, form, formsets, change): - super().save_related(request, form, formsets, change) - obj = form.instance - obj.members.add(*obj.admins.all()) - class OrganizationRequestAdmin(admin.ModelAdmin): - list_display = ("username", "organization", "state", "time") - readonly_fields = ("user", "organization") + list_display = ('username', 'organization', 'state', 'time') + readonly_fields = ('user', 'organization') def username(self, obj): return obj.user.user.username - - username.short_description = _("username") - username.admin_order_field = "user__user__username" + username.short_description = _('username') + username.admin_order_field = 'user__user__username' diff --git a/judge/admin/problem.py b/judge/admin/problem.py index bf590db..4d29b6a 100644 --- a/judge/admin/problem.py +++ b/judge/admin/problem.py @@ -1,115 +1,54 @@ from operator import attrgetter from django import forms -from django.contrib import admin, messages -from django.db import transaction, IntegrityError -from django.db.models import Q, Avg, Count -from django.db.models.aggregates import StdDev -from django.forms import ModelForm, TextInput +from django.contrib import admin +from django.db import transaction +from django.db.models import Q +from django.forms import ModelForm from django.urls import reverse_lazy from django.utils.html import format_html from django.utils.translation import gettext, gettext_lazy as _, ungettext -from django_ace import AceWidget -from django.utils import timezone -from django.core.exceptions import ValidationError - from reversion.admin import VersionAdmin -from reversion_compare.admin import CompareVersionAdmin - -from judge.models import ( - LanguageLimit, - LanguageTemplate, - Problem, - ProblemTranslation, - Profile, - Solution, - Notification, -) -from judge.models.notification import make_notification -from judge.widgets import ( - AdminHeavySelect2MultipleWidget, - AdminSelect2MultipleWidget, - AdminSelect2Widget, - CheckboxSelectMultipleWithSelectAll, - HeavyPreviewAdminPageDownWidget, -) -from judge.utils.problems import user_editable_ids, user_tester_ids - -MEMORY_UNITS = (("KB", "KB"), ("MB", "MB")) +from judge.models import LanguageLimit, Problem, ProblemClarification, ProblemTranslation, Profile, Solution +from judge.widgets import AdminHeavySelect2MultipleWidget, AdminSelect2MultipleWidget, AdminSelect2Widget, \ + CheckboxSelectMultipleWithSelectAll, HeavyPreviewAdminPageDownWidget, HeavyPreviewPageDownWidget class ProblemForm(ModelForm): - change_message = forms.CharField( - max_length=256, label="Edit reason", required=False - ) - memory_unit = forms.ChoiceField(choices=MEMORY_UNITS) + change_message = forms.CharField(max_length=256, label='Edit reason', required=False) def __init__(self, *args, **kwargs): super(ProblemForm, self).__init__(*args, **kwargs) - self.fields["authors"].widget.can_add_related = False - self.fields["curators"].widget.can_add_related = False - self.fields["testers"].widget.can_add_related = False - self.fields["banned_users"].widget.can_add_related = False - self.fields["change_message"].widget.attrs.update( - { - "placeholder": gettext("Describe the changes you made (optional)"), - } - ) - - def clean_code(self): - code = self.cleaned_data.get("code") - if self.instance.pk: - return code - - if Problem.objects.filter(code=code).exists(): - raise ValidationError(_("A problem with this code already exists.")) - - return code - - def clean(self): - memory_unit = self.cleaned_data.get("memory_unit", "KB") - if memory_unit == "MB": - self.cleaned_data["memory_limit"] *= 1024 - date = self.cleaned_data.get("date") - if not date or date > timezone.now(): - self.cleaned_data["date"] = timezone.now() - return self.cleaned_data + self.fields['authors'].widget.can_add_related = False + self.fields['curators'].widget.can_add_related = False + self.fields['testers'].widget.can_add_related = False + self.fields['banned_users'].widget.can_add_related = False + self.fields['change_message'].widget.attrs.update({ + 'placeholder': gettext('Describe the changes you made (optional)'), + }) class Meta: widgets = { - "authors": AdminHeavySelect2MultipleWidget( - data_view="profile_select2", attrs={"style": "width: 100%"} - ), - "curators": AdminHeavySelect2MultipleWidget( - data_view="profile_select2", attrs={"style": "width: 100%"} - ), - "testers": AdminHeavySelect2MultipleWidget( - data_view="profile_select2", attrs={"style": "width: 100%"} - ), - "banned_users": AdminHeavySelect2MultipleWidget( - data_view="profile_select2", attrs={"style": "width: 100%"} - ), - "organizations": AdminHeavySelect2MultipleWidget( - data_view="organization_select2", attrs={"style": "width: 100%"} - ), - "types": AdminSelect2MultipleWidget, - "group": AdminSelect2Widget, - "memory_limit": TextInput(attrs={"size": "20"}), + 'authors': AdminHeavySelect2MultipleWidget(data_view='profile_select2', attrs={'style': 'width: 100%'}), + 'curators': AdminHeavySelect2MultipleWidget(data_view='profile_select2', attrs={'style': 'width: 100%'}), + 'testers': AdminHeavySelect2MultipleWidget(data_view='profile_select2', attrs={'style': 'width: 100%'}), + 'banned_users': AdminHeavySelect2MultipleWidget(data_view='profile_select2', + attrs={'style': 'width: 100%'}), + 'organizations': AdminHeavySelect2MultipleWidget(data_view='organization_select2', + attrs={'style': 'width: 100%'}), + 'types': AdminSelect2MultipleWidget, + 'group': AdminSelect2Widget, } if HeavyPreviewAdminPageDownWidget is not None: - widgets["description"] = HeavyPreviewAdminPageDownWidget( - preview=reverse_lazy("problem_preview") - ) + widgets['description'] = HeavyPreviewAdminPageDownWidget(preview=reverse_lazy('problem_preview')) class ProblemCreatorListFilter(admin.SimpleListFilter): - title = parameter_name = "creator" + title = parameter_name = 'creator' def lookups(self, request, model_admin): - queryset = Profile.objects.exclude(authored_problems=None).values_list( - "user__username", flat=True - ) + queryset = Profile.objects.exclude(authored_problems=None).values_list('user__username', flat=True) return [(name, name) for name in queryset] def queryset(self, request, queryset): @@ -119,68 +58,46 @@ class ProblemCreatorListFilter(admin.SimpleListFilter): class LanguageLimitInlineForm(ModelForm): - memory_unit = forms.ChoiceField(choices=MEMORY_UNITS, label=_("Memory unit")) - class Meta: - widgets = { - "language": AdminSelect2Widget, - "memory_limit": TextInput(attrs={"size": "10"}), - } - - def clean(self): - if not self.cleaned_data.get("language"): - self.cleaned_data["DELETE"] = True - if ( - self.cleaned_data.get("memory_limit") - and self.cleaned_data.get("memory_unit") == "MB" - ): - self.cleaned_data["memory_limit"] *= 1024 - return self.cleaned_data + widgets = {'language': AdminSelect2Widget} class LanguageLimitInline(admin.TabularInline): model = LanguageLimit - fields = ("language", "time_limit", "memory_limit", "memory_unit") + fields = ('language', 'time_limit', 'memory_limit') form = LanguageLimitInlineForm - extra = 0 -class LanguageTemplateInlineForm(ModelForm): +class ProblemClarificationForm(ModelForm): class Meta: - widgets = { - "language": AdminSelect2Widget, - "source": AceWidget(width="600px", height="200px", toolbar=False), - } + if HeavyPreviewPageDownWidget is not None: + widgets = {'description': HeavyPreviewPageDownWidget(preview=reverse_lazy('comment_preview'))} -class LanguageTemplateInline(admin.TabularInline): - model = LanguageTemplate - fields = ("language", "source") - form = LanguageTemplateInlineForm +class ProblemClarificationInline(admin.StackedInline): + model = ProblemClarification + fields = ('description',) + form = ProblemClarificationForm extra = 0 class ProblemSolutionForm(ModelForm): def __init__(self, *args, **kwargs): super(ProblemSolutionForm, self).__init__(*args, **kwargs) - self.fields["authors"].widget.can_add_related = False + self.fields['authors'].widget.can_add_related = False class Meta: widgets = { - "authors": AdminHeavySelect2MultipleWidget( - data_view="profile_select2", attrs={"style": "width: 100%"} - ), + 'authors': AdminHeavySelect2MultipleWidget(data_view='profile_select2', attrs={'style': 'width: 100%'}), } if HeavyPreviewAdminPageDownWidget is not None: - widgets["content"] = HeavyPreviewAdminPageDownWidget( - preview=reverse_lazy("solution_preview") - ) + widgets['content'] = HeavyPreviewAdminPageDownWidget(preview=reverse_lazy('solution_preview')) class ProblemSolutionInline(admin.StackedInline): model = Solution - fields = ("is_public", "publish_on", "authors", "content") + fields = ('is_public', 'publish_on', 'authors', 'content') form = ProblemSolutionForm extra = 0 @@ -188,300 +105,134 @@ class ProblemSolutionInline(admin.StackedInline): class ProblemTranslationForm(ModelForm): class Meta: if HeavyPreviewAdminPageDownWidget is not None: - widgets = { - "description": HeavyPreviewAdminPageDownWidget( - preview=reverse_lazy("problem_preview") - ) - } + widgets = {'description': HeavyPreviewAdminPageDownWidget(preview=reverse_lazy('problem_preview'))} class ProblemTranslationInline(admin.StackedInline): model = ProblemTranslation - fields = ("language", "name", "description") + fields = ('language', 'name', 'description') form = ProblemTranslationForm extra = 0 -class ProblemAdmin(CompareVersionAdmin): +class ProblemAdmin(VersionAdmin): fieldsets = ( - ( - None, - { - "fields": ( - "code", - "name", - "is_public", - "organizations", - "date", - "authors", - "curators", - "testers", - "description", - "pdf_description", - "license", - ), - }, - ), - ( - _("Social Media"), - {"classes": ("collapse",), "fields": ("og_image", "summary")}, - ), - (_("Taxonomy"), {"fields": ("types", "group")}), - (_("Points"), {"fields": (("points", "partial"), "short_circuit")}), - (_("Limits"), {"fields": ("time_limit", ("memory_limit", "memory_unit"))}), - (_("Language"), {"fields": ("allowed_languages",)}), - (_("Justice"), {"fields": ("banned_users",)}), - (_("History"), {"fields": ("change_message",)}), + (None, { + 'fields': ( + 'code', 'name', 'is_public', 'is_manually_managed', 'date', 'authors', 'curators', 'testers', + 'is_organization_private', 'organizations', 'description', 'license', + ), + }), + (_('Social Media'), {'classes': ('collapse',), 'fields': ('og_image', 'summary')}), + (_('Taxonomy'), {'fields': ('types', 'group')}), + (_('Points'), {'fields': (('points', 'partial'), 'short_circuit')}), + (_('Limits'), {'fields': ('time_limit', 'memory_limit')}), + (_('Language'), {'fields': ('allowed_languages',)}), + (_('Justice'), {'fields': ('banned_users',)}), + (_('History'), {'fields': ('change_message',)}), ) - list_display = [ - "code", - "name", - "show_authors", - "date", - "points", - "is_public", - "show_public", - ] - ordering = ["-date"] - search_fields = ( - "code", - "name", - "authors__user__username", - "curators__user__username", - ) - inlines = [ - LanguageLimitInline, - LanguageTemplateInline, - ProblemSolutionInline, - ProblemTranslationInline, - ] + list_display = ['code', 'name', 'show_authors', 'points', 'is_public', 'show_public'] + ordering = ['code'] + search_fields = ('code', 'name', 'authors__user__username', 'curators__user__username') + inlines = [LanguageLimitInline, ProblemClarificationInline, ProblemSolutionInline, ProblemTranslationInline] list_max_show_all = 1000 actions_on_top = True actions_on_bottom = True - list_filter = ("is_public", ProblemCreatorListFilter) + list_filter = ('is_public', ProblemCreatorListFilter) form = ProblemForm - date_hierarchy = "date" + date_hierarchy = 'date' def get_actions(self, request): actions = super(ProblemAdmin, self).get_actions(request) - if request.user.has_perm("judge.change_public_visibility"): - func, name, desc = self.get_action("make_public") + if request.user.has_perm('judge.change_public_visibility'): + func, name, desc = self.get_action('make_public') actions[name] = (func, name, desc) - func, name, desc = self.get_action("make_private") + func, name, desc = self.get_action('make_private') actions[name] = (func, name, desc) return actions def get_readonly_fields(self, request, obj=None): fields = self.readonly_fields - if not request.user.has_perm("judge.change_public_visibility"): - fields += ("is_public",) + if not request.user.has_perm('judge.change_public_visibility'): + fields += ('is_public',) + if not request.user.has_perm('judge.change_manually_managed'): + fields += ('is_manually_managed',) return fields def show_authors(self, obj): - return ", ".join(map(attrgetter("user.username"), obj.authors.all())) + return ', '.join(map(attrgetter('user.username'), obj.authors.all())) - show_authors.short_description = _("Authors") + show_authors.short_description = _('Authors') def show_public(self, obj): - return format_html( - '{0}', gettext("View on site"), obj.get_absolute_url() - ) + return format_html('{0}', gettext('View on site'), obj.get_absolute_url()) - show_public.short_description = "" + show_public.short_description = '' def _rescore(self, request, problem_id): from judge.tasks import rescore_problem - transaction.on_commit(rescore_problem.s(problem_id).delay) def make_public(self, request, queryset): count = queryset.update(is_public=True) - for problem_id in queryset.values_list("id", flat=True): + for problem_id in queryset.values_list('id', flat=True): self._rescore(request, problem_id) - self.message_user( - request, - ungettext( - "%d problem successfully marked as public.", - "%d problems successfully marked as public.", - count, - ) - % count, - ) + self.message_user(request, ungettext('%d problem successfully marked as public.', + '%d problems successfully marked as public.', + count) % count) - make_public.short_description = _("Mark problems as public") + make_public.short_description = _('Mark problems as public') def make_private(self, request, queryset): count = queryset.update(is_public=False) - for problem_id in queryset.values_list("id", flat=True): + for problem_id in queryset.values_list('id', flat=True): self._rescore(request, problem_id) - self.message_user( - request, - ungettext( - "%d problem successfully marked as private.", - "%d problems successfully marked as private.", - count, - ) - % count, - ) + self.message_user(request, ungettext('%d problem successfully marked as private.', + '%d problems successfully marked as private.', + count) % count) - make_private.short_description = _("Mark problems as private") + make_private.short_description = _('Mark problems as private') def get_queryset(self, request): - queryset = Problem.objects.prefetch_related("authors__user") - if request.user.has_perm("judge.edit_all_problem"): + queryset = Problem.objects.prefetch_related('authors__user') + if request.user.has_perm('judge.edit_all_problem'): return queryset access = Q() - if request.user.has_perm("judge.edit_public_problem"): + if request.user.has_perm('judge.edit_public_problem'): access |= Q(is_public=True) - if request.user.has_perm("judge.edit_own_problem"): - access |= Q(authors__id=request.profile.id) | Q( - curators__id=request.profile.id - ) + if request.user.has_perm('judge.edit_own_problem'): + access |= Q(authors__id=request.profile.id) | Q(curators__id=request.profile.id) return queryset.filter(access).distinct() if access else queryset.none() def has_change_permission(self, request, obj=None): - if request.user.has_perm("judge.edit_all_problem") or obj is None: + if request.user.has_perm('judge.edit_all_problem') or obj is None: return True - if request.user.has_perm("judge.edit_public_problem") and obj.is_public: + if request.user.has_perm('judge.edit_public_problem') and obj.is_public: return True - if not request.user.has_perm("judge.edit_own_problem"): + if not request.user.has_perm('judge.edit_own_problem'): return False return obj.is_editor(request.profile) def formfield_for_manytomany(self, db_field, request=None, **kwargs): - if db_field.name == "allowed_languages": - kwargs["widget"] = CheckboxSelectMultipleWithSelectAll() - return super(ProblemAdmin, self).formfield_for_manytomany( - db_field, request, **kwargs - ) + if db_field.name == 'allowed_languages': + kwargs['widget'] = CheckboxSelectMultipleWithSelectAll() + return super(ProblemAdmin, self).formfield_for_manytomany(db_field, request, **kwargs) def get_form(self, *args, **kwargs): form = super(ProblemAdmin, self).get_form(*args, **kwargs) - form.base_fields["authors"].queryset = Profile.objects.all() + form.base_fields['authors'].queryset = Profile.objects.all() return form def save_model(self, request, obj, form, change): - form.changed_data.remove("memory_unit") - super().save_model(request, obj, form, change) - if form.changed_data and any( - f in form.changed_data for f in ("is_public", "points", "partial") - ): + super(ProblemAdmin, self).save_model(request, obj, form, change) + if form.changed_data and any(f in form.changed_data for f in ('is_public', 'points', 'partial')): self._rescore(request, obj.id) - def save_related(self, request, form, formsets, change): - editors = set() - testers = set() - if "curators" in form.changed_data or "authors" in form.changed_data: - editors = set(form.instance.editor_ids) - if "testers" in form.changed_data: - testers = set(form.instance.tester_ids) - - super().save_related(request, form, formsets, change) - obj = form.instance - obj.curators.add(request.profile) - - if "curators" in form.changed_data or "authors" in form.changed_data: - del obj.editor_ids - editors = editors.union(set(obj.editor_ids)) - if "testers" in form.changed_data: - del obj.tester_ids - testers = testers.union(set(obj.tester_ids)) - - for editor in editors: - user_editable_ids.dirty(editor) - for tester in testers: - user_tester_ids.dirty(tester) - - # Create notification - if "is_public" in form.changed_data or "organizations" in form.changed_data: - users = set(obj.authors.all()) - users = users.union(users, set(obj.curators.all())) - orgs = [] - if obj.organizations.count() > 0: - for org in obj.organizations.all(): - users = users.union(users, set(org.admins.all())) - orgs.append(org.name) - else: - admins = Profile.objects.filter(user__is_superuser=True).all() - users = users.union(users, admins) - link = reverse_lazy("admin:judge_problem_change", args=(obj.id,)) - html = f'{obj.name}' - category = "Problem public: " + str(obj.is_public) - if orgs: - category += " (" + ", ".join(orgs) + ")" - make_notification(users, category, html, request.profile) - def construct_change_message(self, request, form, *args, **kwargs): - if form.cleaned_data.get("change_message"): - return form.cleaned_data["change_message"] - return super(ProblemAdmin, self).construct_change_message( - request, form, *args, **kwargs - ) - - -class ProblemPointsVoteAdmin(admin.ModelAdmin): - list_display = ( - "vote_points", - "voter", - "voter_rating", - "voter_point", - "problem_name", - "problem_code", - "problem_points", - ) - search_fields = ("voter__user__username", "problem__code", "problem__name") - readonly_fields = ( - "voter", - "problem", - "problem_code", - "problem_points", - "voter_rating", - "voter_point", - ) - - def has_change_permission(self, request, obj=None): - if obj is None: - return request.user.has_perm("judge.edit_own_problem") - return obj.problem.is_editable_by(request.user) - - def lookup_allowed(self, key, value): - return True - - def problem_code(self, obj): - return obj.problem.code - - problem_code.short_description = _("Problem code") - problem_code.admin_order_field = "problem__code" - - def problem_points(self, obj): - return obj.problem.points - - problem_points.short_description = _("Points") - problem_points.admin_order_field = "problem__points" - - def problem_name(self, obj): - return obj.problem.name - - problem_name.short_description = _("Problem name") - problem_name.admin_order_field = "problem__name" - - def voter_rating(self, obj): - return obj.voter.rating - - voter_rating.short_description = _("Voter rating") - voter_rating.admin_order_field = "voter__rating" - - def voter_point(self, obj): - return round(obj.voter.performance_points) - - voter_point.short_description = _("Voter point") - voter_point.admin_order_field = "voter__performance_points" - - def vote_points(self, obj): - return obj.points - - vote_points.short_description = _("Vote") + if form.cleaned_data.get('change_message'): + return form.cleaned_data['change_message'] + return super(ProblemAdmin, self).construct_change_message(request, form, *args, **kwargs) diff --git a/judge/admin/profile.py b/judge/admin/profile.py index 4c380c9..e5fbf46 100644 --- a/judge/admin/profile.py +++ b/judge/admin/profile.py @@ -1,58 +1,41 @@ from django.contrib import admin -from django.forms import ModelForm, CharField, TextInput +from django.forms import ModelForm from django.utils.html import format_html from django.utils.translation import gettext, gettext_lazy as _, ungettext -from django.contrib.auth.admin import UserAdmin as OldUserAdmin -from django.core.exceptions import ValidationError -from django.contrib.auth.forms import UserChangeForm - -from django_ace import AceWidget - -from judge.models import Profile, ProfileInfo -from judge.widgets import AdminPagedownWidget, AdminSelect2Widget - from reversion.admin import VersionAdmin -import re +from django_ace import AceWidget +from judge.models import Profile +from judge.widgets import AdminPagedownWidget, AdminSelect2Widget class ProfileForm(ModelForm): def __init__(self, *args, **kwargs): super(ProfileForm, self).__init__(*args, **kwargs) - if "current_contest" in self.base_fields: + if 'current_contest' in self.base_fields: # form.fields['current_contest'] does not exist when the user has only view permission on the model. - self.fields[ - "current_contest" - ].queryset = self.instance.contest_history.select_related("contest").only( - "contest__name", "user_id", "virtual" - ) - self.fields["current_contest"].label_from_instance = ( - lambda obj: "%s v%d" % (obj.contest.name, obj.virtual) - if obj.virtual - else obj.contest.name - ) + self.fields['current_contest'].queryset = self.instance.contest_history.select_related('contest') \ + .only('contest__name', 'user_id', 'virtual') + self.fields['current_contest'].label_from_instance = \ + lambda obj: '%s v%d' % (obj.contest.name, obj.virtual) if obj.virtual else obj.contest.name class Meta: widgets = { - "timezone": AdminSelect2Widget, - "language": AdminSelect2Widget, - "ace_theme": AdminSelect2Widget, - "current_contest": AdminSelect2Widget, + 'timezone': AdminSelect2Widget, + 'language': AdminSelect2Widget, + 'ace_theme': AdminSelect2Widget, + 'current_contest': AdminSelect2Widget, } if AdminPagedownWidget is not None: - widgets["about"] = AdminPagedownWidget + widgets['about'] = AdminPagedownWidget class TimezoneFilter(admin.SimpleListFilter): - title = _("timezone") - parameter_name = "timezone" + title = _('timezone') + parameter_name = 'timezone' def lookups(self, request, model_admin): - return ( - Profile.objects.values_list("timezone", "timezone") - .distinct() - .order_by("timezone") - ) + return Profile.objects.values_list('timezone', 'timezone').distinct().order_by('timezone') def queryset(self, request, queryset): if self.value() is None: @@ -60,168 +43,76 @@ class TimezoneFilter(admin.SimpleListFilter): return queryset.filter(timezone=self.value()) -class ProfileInfoInline(admin.StackedInline): - model = ProfileInfo - can_delete = False - verbose_name_plural = "profile info" - fk_name = "profile" - - class ProfileAdmin(VersionAdmin): - fields = ( - "user", - "display_rank", - "about", - "organizations", - "timezone", - "language", - "ace_theme", - "last_access", - "ip", - "mute", - "is_unlisted", - "notes", - "is_totp_enabled", - "current_contest", - ) - readonly_fields = ("user",) - list_display = ( - "admin_user_admin", - "email", - "is_totp_enabled", - "timezone_full", - "date_joined", - "last_access", - "ip", - "show_public", - ) - ordering = ("user__username",) - search_fields = ("user__username", "ip", "user__email") - list_filter = ("language", TimezoneFilter) - actions = ("recalculate_points",) + fields = ('user', 'display_rank', 'about', 'organizations', 'timezone', 'language', 'ace_theme', + 'math_engine', 'last_access', 'ip', 'mute', 'is_unlisted', 'notes', 'is_totp_enabled', 'user_script', + 'current_contest') + readonly_fields = ('user',) + list_display = ('admin_user_admin', 'email', 'is_totp_enabled', 'timezone_full', + 'date_joined', 'last_access', 'ip', 'show_public') + ordering = ('user__username',) + search_fields = ('user__username', 'ip', 'user__email') + list_filter = ('language', TimezoneFilter) + actions = ('recalculate_points',) actions_on_top = True actions_on_bottom = True form = ProfileForm - inlines = (ProfileInfoInline,) def get_queryset(self, request): - return super(ProfileAdmin, self).get_queryset(request).select_related("user") + return super(ProfileAdmin, self).get_queryset(request).select_related('user') def get_fields(self, request, obj=None): - if request.user.has_perm("judge.totp"): + if request.user.has_perm('judge.totp'): fields = list(self.fields) - fields.insert(fields.index("is_totp_enabled") + 1, "totp_key") + fields.insert(fields.index('is_totp_enabled') + 1, 'totp_key') return tuple(fields) else: return self.fields def get_readonly_fields(self, request, obj=None): fields = self.readonly_fields - if not request.user.has_perm("judge.totp"): - fields += ("is_totp_enabled",) + if not request.user.has_perm('judge.totp'): + fields += ('is_totp_enabled',) return fields def show_public(self, obj): - return format_html( - '{1}', - obj.get_absolute_url(), - gettext("View on site"), - ) - - show_public.short_description = "" + return format_html('{1}', + obj.get_absolute_url(), gettext('View on site')) + show_public.short_description = '' def admin_user_admin(self, obj): return obj.username - - admin_user_admin.admin_order_field = "user__username" - admin_user_admin.short_description = _("User") + admin_user_admin.admin_order_field = 'user__username' + admin_user_admin.short_description = _('User') def email(self, obj): - return obj.email - - email.admin_order_field = "user__email" - email.short_description = _("Email") + return obj.user.email + email.admin_order_field = 'user__email' + email.short_description = _('Email') def timezone_full(self, obj): return obj.timezone - - timezone_full.admin_order_field = "timezone" - timezone_full.short_description = _("Timezone") + timezone_full.admin_order_field = 'timezone' + timezone_full.short_description = _('Timezone') def date_joined(self, obj): return obj.user.date_joined - - date_joined.admin_order_field = "user__date_joined" - date_joined.short_description = _("date joined") + date_joined.admin_order_field = 'user__date_joined' + date_joined.short_description = _('date joined') def recalculate_points(self, request, queryset): count = 0 for profile in queryset: profile.calculate_points() count += 1 - self.message_user( - request, - ungettext( - "%d user have scores recalculated.", - "%d users have scores recalculated.", - count, - ) - % count, - ) + self.message_user(request, ungettext('%d user have scores recalculated.', + '%d users have scores recalculated.', + count) % count) + recalculate_points.short_description = _('Recalculate scores') - recalculate_points.short_description = _("Recalculate scores") - - -class UserForm(UserChangeForm): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.fields["username"].help_text = _( - "Username can only contain letters, digits, and underscores." - ) - - def clean_username(self): - username = self.cleaned_data.get("username") - if not re.match(r"^\w+$", username): - raise ValidationError( - _("Username can only contain letters, digits, and underscores.") - ) - return username - - -class UserAdmin(OldUserAdmin): - # Customize the fieldsets for adding and editing users - form = UserForm - fieldsets = ( - (None, {"fields": ("username", "password")}), - ("Personal Info", {"fields": ("first_name", "last_name", "email")}), - ( - "Permissions", - { - "fields": ( - "is_active", - "is_staff", - "is_superuser", - "groups", - "user_permissions", - ) - }, - ), - ("Important dates", {"fields": ("last_login", "date_joined")}), - ) - - readonly_fields = ("last_login", "date_joined") - - def get_readonly_fields(self, request, obj=None): - fields = self.readonly_fields - if not request.user.is_superuser: - fields += ( - "is_staff", - "is_active", - "is_superuser", - "groups", - "user_permissions", - ) - return fields - - def has_add_permission(self, request): - return False + def get_form(self, request, obj=None, **kwargs): + form = super(ProfileAdmin, self).get_form(request, obj, **kwargs) + if 'user_script' in form.base_fields: + # form.base_fields['user_script'] does not exist when the user has only view permission on the model. + form.base_fields['user_script'].widget = AceWidget('javascript', request.profile.ace_theme) + return form diff --git a/judge/admin/runtime.py b/judge/admin/runtime.py index 791083a..e9f44ec 100644 --- a/judge/admin/runtime.py +++ b/judge/admin/runtime.py @@ -16,63 +16,41 @@ from judge.widgets import AdminHeavySelect2MultipleWidget, AdminPagedownWidget class LanguageForm(ModelForm): problems = ModelMultipleChoiceField( - label=_("Disallowed problems"), + label=_('Disallowed problems'), queryset=Problem.objects.all(), required=False, - help_text=_("These problems are NOT allowed to be submitted in this language"), - widget=AdminHeavySelect2MultipleWidget(data_view="problem_select2"), - ) + help_text=_('These problems are NOT allowed to be submitted in this language'), + widget=AdminHeavySelect2MultipleWidget(data_view='problem_select2')) class Meta: if AdminPagedownWidget is not None: - widgets = {"description": AdminPagedownWidget} + widgets = {'description': AdminPagedownWidget} class LanguageAdmin(VersionAdmin): - fields = ( - "key", - "name", - "short_name", - "common_name", - "ace", - "pygments", - "info", - "description", - "template", - "problems", - ) - list_display = ("key", "name", "common_name", "info") + fields = ('key', 'name', 'short_name', 'common_name', 'ace', 'pygments', 'info', 'description', + 'template', 'problems') + list_display = ('key', 'name', 'common_name', 'info') form = LanguageForm def save_model(self, request, obj, form, change): super(LanguageAdmin, self).save_model(request, obj, form, change) - obj.problem_set.set( - Problem.objects.exclude(id__in=form.cleaned_data["problems"].values("id")) - ) + obj.problem_set.set(Problem.objects.exclude(id__in=form.cleaned_data['problems'].values('id'))) def get_form(self, request, obj=None, **kwargs): - self.form.base_fields["problems"].initial = ( - Problem.objects.exclude(id__in=obj.problem_set.values("id")).values_list( - "pk", flat=True - ) - if obj - else [] - ) + self.form.base_fields['problems'].initial = \ + Problem.objects.exclude(id__in=obj.problem_set.values('id')).values_list('pk', flat=True) if obj else [] form = super(LanguageAdmin, self).get_form(request, obj, **kwargs) if obj is not None: - form.base_fields["template"].widget = AceWidget( - obj.ace, request.profile.ace_theme - ) + form.base_fields['template'].widget = AceWidget(obj.ace, request.profile.ace_theme) return form class GenerateKeyTextInput(TextInput): def render(self, name, value, attrs=None, renderer=None): text = super(TextInput, self).render(name, value, attrs) - return mark_safe( - text - + format_html( - """\ + return mark_safe(text + format_html( + '''\ Regenerate -""", - name, - ) - ) +''', name)) class JudgeAdminForm(ModelForm): class Meta: - widgets = {"auth_key": GenerateKeyTextInput} + widgets = {'auth_key': GenerateKeyTextInput} if AdminPagedownWidget is not None: - widgets["description"] = AdminPagedownWidget + widgets['description'] = AdminPagedownWidget class JudgeAdmin(VersionAdmin): form = JudgeAdminForm - readonly_fields = ( - "created", - "online", - "start_time", - "ping", - "load", - "last_ip", - "runtimes", - "problems", - ) + readonly_fields = ('created', 'online', 'start_time', 'ping', 'load', 'last_ip', 'runtimes', 'problems') fieldsets = ( - (None, {"fields": ("name", "auth_key", "is_blocked")}), - (_("Description"), {"fields": ("description",)}), - ( - _("Information"), - {"fields": ("created", "online", "last_ip", "start_time", "ping", "load")}, - ), - (_("Capabilities"), {"fields": ("runtimes", "problems")}), + (None, {'fields': ('name', 'auth_key', 'is_blocked')}), + (_('Description'), {'fields': ('description',)}), + (_('Information'), {'fields': ('created', 'online', 'last_ip', 'start_time', 'ping', 'load')}), + (_('Capabilities'), {'fields': ('runtimes', 'problems')}), ) - list_display = ("name", "online", "start_time", "ping", "load", "last_ip") - ordering = ["-online", "name"] + list_display = ('name', 'online', 'start_time', 'ping', 'load', 'last_ip') + ordering = ['-online', 'name'] def get_urls(self): - return [ - url( - r"^(\d+)/disconnect/$", - self.disconnect_view, - name="judge_judge_disconnect", - ), - url( - r"^(\d+)/terminate/$", self.terminate_view, name="judge_judge_terminate" - ), - ] + super(JudgeAdmin, self).get_urls() + return ([url(r'^(\d+)/disconnect/$', self.disconnect_view, name='judge_judge_disconnect'), + url(r'^(\d+)/terminate/$', self.terminate_view, name='judge_judge_terminate')] + + super(JudgeAdmin, self).get_urls()) def disconnect_judge(self, id, force=False): judge = get_object_or_404(Judge, id=id) judge.disconnect(force=force) - return HttpResponseRedirect(reverse("admin:judge_judge_changelist")) + return HttpResponseRedirect(reverse('admin:judge_judge_changelist')) def disconnect_view(self, request, id): return self.disconnect_judge(id) @@ -149,7 +105,7 @@ class JudgeAdmin(VersionAdmin): def get_readonly_fields(self, request, obj=None): if obj is not None and obj.online: - return self.readonly_fields + ("name",) + return self.readonly_fields + ('name',) return self.readonly_fields def has_delete_permission(self, request, obj=None): @@ -160,5 +116,5 @@ class JudgeAdmin(VersionAdmin): if AdminPagedownWidget is not None: formfield_overrides = { - TextField: {"widget": AdminPagedownWidget}, + TextField: {'widget': AdminPagedownWidget}, } diff --git a/judge/admin/submission.py b/judge/admin/submission.py index 7218bb2..d774658 100644 --- a/judge/admin/submission.py +++ b/judge/admin/submission.py @@ -13,365 +13,239 @@ from django.utils.html import format_html from django.utils.translation import gettext, gettext_lazy as _, pgettext, ungettext from django_ace import AceWidget -from judge.models import ( - ContestParticipation, - ContestProblem, - ContestSubmission, - Profile, - Submission, - SubmissionSource, - SubmissionTestCase, -) +from judge.models import ContestParticipation, ContestProblem, ContestSubmission, Profile, Submission, \ + SubmissionSource, SubmissionTestCase from judge.utils.raw_sql import use_straight_join class SubmissionStatusFilter(admin.SimpleListFilter): - parameter_name = title = "status" - __lookups = ( - ("None", _("None")), - ("NotDone", _("Not done")), - ("EX", _("Exceptional")), - ) + Submission.STATUS + parameter_name = title = 'status' + __lookups = (('None', _('None')), ('NotDone', _('Not done')), ('EX', _('Exceptional'))) + Submission.STATUS __handles = set(map(itemgetter(0), Submission.STATUS)) def lookups(self, request, model_admin): return self.__lookups def queryset(self, request, queryset): - if self.value() == "None": + if self.value() == 'None': return queryset.filter(status=None) - elif self.value() == "NotDone": - return queryset.exclude(status__in=["D", "IE", "CE", "AB"]) - elif self.value() == "EX": - return queryset.exclude(status__in=["D", "CE", "G", "AB"]) + elif self.value() == 'NotDone': + return queryset.exclude(status__in=['D', 'IE', 'CE', 'AB']) + elif self.value() == 'EX': + return queryset.exclude(status__in=['D', 'CE', 'G', 'AB']) elif self.value() in self.__handles: return queryset.filter(status=self.value()) class SubmissionResultFilter(admin.SimpleListFilter): - parameter_name = title = "result" - __lookups = (("None", _("None")), ("BAD", _("Unaccepted"))) + Submission.RESULT + parameter_name = title = 'result' + __lookups = (('None', _('None')), ('BAD', _('Unaccepted'))) + Submission.RESULT __handles = set(map(itemgetter(0), Submission.RESULT)) def lookups(self, request, model_admin): return self.__lookups def queryset(self, request, queryset): - if self.value() == "None": + if self.value() == 'None': return queryset.filter(result=None) - elif self.value() == "BAD": - return queryset.exclude(result="AC") + elif self.value() == 'BAD': + return queryset.exclude(result='AC') elif self.value() in self.__handles: return queryset.filter(result=self.value()) class SubmissionTestCaseInline(admin.TabularInline): - fields = ("case", "batch", "status", "time", "memory", "points", "total") - readonly_fields = ("case", "batch", "total") + fields = ('case', 'batch', 'status', 'time', 'memory', 'points', 'total') + readonly_fields = ('case', 'batch', 'total') model = SubmissionTestCase can_delete = False max_num = 0 class ContestSubmissionInline(admin.StackedInline): - fields = ("problem", "participation", "points") + fields = ('problem', 'participation', 'points') model = ContestSubmission def get_formset(self, request, obj=None, **kwargs): - kwargs["formfield_callback"] = partial( - self.formfield_for_dbfield, request=request, obj=obj - ) + kwargs['formfield_callback'] = partial(self.formfield_for_dbfield, request=request, obj=obj) return super(ContestSubmissionInline, self).get_formset(request, obj, **kwargs) def formfield_for_dbfield(self, db_field, **kwargs): - submission = kwargs.pop("obj", None) + submission = kwargs.pop('obj', None) label = None if submission: - if db_field.name == "participation": - kwargs["queryset"] = ContestParticipation.objects.filter( - user=submission.user, contest__problems=submission.problem - ).only("id", "contest__name") + if db_field.name == 'participation': + kwargs['queryset'] = ContestParticipation.objects.filter(user=submission.user, + contest__problems=submission.problem) \ + .only('id', 'contest__name') def label(obj): return obj.contest.name - - elif db_field.name == "problem": - kwargs["queryset"] = ContestProblem.objects.filter( - problem=submission.problem - ).only("id", "problem__name", "contest__name") + elif db_field.name == 'problem': + kwargs['queryset'] = ContestProblem.objects.filter(problem=submission.problem) \ + .only('id', 'problem__name', 'contest__name') def label(obj): - return pgettext("contest problem", "%(problem)s in %(contest)s") % { - "problem": obj.problem.name, - "contest": obj.contest.name, + return pgettext('contest problem', '%(problem)s in %(contest)s') % { + 'problem': obj.problem.name, 'contest': obj.contest.name, } - - field = super(ContestSubmissionInline, self).formfield_for_dbfield( - db_field, **kwargs - ) + field = super(ContestSubmissionInline, self).formfield_for_dbfield(db_field, **kwargs) if label is not None: field.label_from_instance = label return field class SubmissionSourceInline(admin.StackedInline): - fields = ("source",) + fields = ('source',) model = SubmissionSource can_delete = False extra = 0 def get_formset(self, request, obj=None, **kwargs): - kwargs.setdefault("widgets", {})["source"] = AceWidget( - mode=obj and obj.language.ace, theme=request.profile.ace_theme - ) + kwargs.setdefault('widgets', {})['source'] = AceWidget(mode=obj and obj.language.ace, + theme=request.profile.ace_theme) return super().get_formset(request, obj, **kwargs) class SubmissionAdmin(admin.ModelAdmin): - readonly_fields = ("user", "problem", "date", "judged_date") - fields = ( - "user", - "problem", - "date", - "judged_date", - "time", - "memory", - "points", - "language", - "status", - "result", - "case_points", - "case_total", - "judged_on", - "error", - ) - actions = ("judge", "recalculate_score") - list_display = ( - "id", - "problem_code", - "problem_name", - "user_column", - "execution_time", - "pretty_memory", - "points", - "language_column", - "status", - "result", - "judge_column", - ) - list_filter = ("language", SubmissionStatusFilter, SubmissionResultFilter) - search_fields = ("problem__code", "problem__name", "user__user__username") + readonly_fields = ('user', 'problem', 'date') + fields = ('user', 'problem', 'date', 'time', 'memory', 'points', 'language', 'status', 'result', + 'case_points', 'case_total', 'judged_on', 'error') + actions = ('judge', 'recalculate_score') + list_display = ('id', 'problem_code', 'problem_name', 'user_column', 'execution_time', 'pretty_memory', + 'points', 'language_column', 'status', 'result', 'judge_column') + list_filter = ('language', SubmissionStatusFilter, SubmissionResultFilter) + search_fields = ('problem__code', 'problem__name', 'user__user__username') actions_on_top = True actions_on_bottom = True - inlines = [ - SubmissionSourceInline, - SubmissionTestCaseInline, - ContestSubmissionInline, - ] + inlines = [SubmissionSourceInline, SubmissionTestCaseInline, ContestSubmissionInline] def get_queryset(self, request): - queryset = Submission.objects.select_related( - "problem", "user__user", "language" - ).only( - "problem__code", - "problem__name", - "user__user__username", - "language__name", - "time", - "memory", - "points", - "status", - "result", + queryset = Submission.objects.select_related('problem', 'user__user', 'language').only( + 'problem__code', 'problem__name', 'user__user__username', 'language__name', + 'time', 'memory', 'points', 'status', 'result', ) use_straight_join(queryset) - if not request.user.has_perm("judge.edit_all_problem"): + if not request.user.has_perm('judge.edit_all_problem'): id = request.profile.id - queryset = queryset.filter( - Q(problem__authors__id=id) | Q(problem__curators__id=id) - ).distinct() + queryset = queryset.filter(Q(problem__authors__id=id) | Q(problem__curators__id=id)).distinct() return queryset def has_add_permission(self, request): return False - def lookup_allowed(self, key, value): - return super(SubmissionAdmin, self).lookup_allowed(key, value) or key in ( - "problem__code", - ) + def has_change_permission(self, request, obj=None): + if not request.user.has_perm('judge.edit_own_problem'): + return False + if request.user.has_perm('judge.edit_all_problem') or obj is None: + return True + return obj.problem.is_editor(request.profile) - def save_model(self, request, obj, form, change): - super().save_model(request, obj, form, change) - if "case_points" in form.changed_data or "case_total" in form.changed_data: - obj.update_contest() + def lookup_allowed(self, key, value): + return super(SubmissionAdmin, self).lookup_allowed(key, value) or key in ('problem__code',) def judge(self, request, queryset): - if not request.user.has_perm( - "judge.rejudge_submission" - ) or not request.user.has_perm("judge.edit_own_problem"): - self.message_user( - request, - gettext("You do not have the permission to rejudge submissions."), - level=messages.ERROR, - ) + if not request.user.has_perm('judge.rejudge_submission') or not request.user.has_perm('judge.edit_own_problem'): + self.message_user(request, gettext('You do not have the permission to rejudge submissions.'), + level=messages.ERROR) return - queryset = queryset.order_by("id") - if ( - not request.user.has_perm("judge.rejudge_submission_lot") - and queryset.count() > settings.DMOJ_SUBMISSIONS_REJUDGE_LIMIT - ): - self.message_user( - request, - gettext( - "You do not have the permission to rejudge THAT many submissions." - ), - level=messages.ERROR, - ) + queryset = queryset.order_by('id') + if not request.user.has_perm('judge.rejudge_submission_lot') and \ + queryset.count() > settings.DMOJ_SUBMISSIONS_REJUDGE_LIMIT: + self.message_user(request, gettext('You do not have the permission to rejudge THAT many submissions.'), + level=messages.ERROR) return - if not request.user.has_perm("judge.edit_all_problem"): + if not request.user.has_perm('judge.edit_all_problem'): id = request.profile.id - queryset = queryset.filter( - Q(problem__authors__id=id) | Q(problem__curators__id=id) - ) + queryset = queryset.filter(Q(problem__authors__id=id) | Q(problem__curators__id=id)) judged = len(queryset) for model in queryset: model.judge(rejudge=True, batch_rejudge=True) - self.message_user( - request, - ungettext( - "%d submission was successfully scheduled for rejudging.", - "%d submissions were successfully scheduled for rejudging.", - judged, - ) - % judged, - ) - - judge.short_description = _("Rejudge the selected submissions") + self.message_user(request, ungettext('%d submission was successfully scheduled for rejudging.', + '%d submissions were successfully scheduled for rejudging.', + judged) % judged) + judge.short_description = _('Rejudge the selected submissions') def recalculate_score(self, request, queryset): - if not request.user.has_perm("judge.rejudge_submission"): - self.message_user( - request, - gettext("You do not have the permission to rejudge submissions."), - level=messages.ERROR, - ) + if not request.user.has_perm('judge.rejudge_submission'): + self.message_user(request, gettext('You do not have the permission to rejudge submissions.'), + level=messages.ERROR) return - submissions = list( - queryset.defer(None) - .select_related(None) - .select_related("problem") - .only( - "points", - "case_points", - "case_total", - "problem__partial", - "problem__points", - ) - ) + submissions = list(queryset.defer(None).select_related(None).select_related('problem') + .only('points', 'case_points', 'case_total', 'problem__partial', 'problem__points')) for submission in submissions: - submission.points = round( - submission.case_points - / submission.case_total - * submission.problem.points - if submission.case_total - else 0, - 1, - ) - if ( - not submission.problem.partial - and submission.points < submission.problem.points - ): + submission.points = round(submission.case_points / submission.case_total * submission.problem.points + if submission.case_total else 0, 1) + if not submission.problem.partial and submission.points < submission.problem.points: submission.points = 0 submission.save() submission.update_contest() - for profile in Profile.objects.filter( - id__in=queryset.values_list("user_id", flat=True).distinct() - ): + for profile in Profile.objects.filter(id__in=queryset.values_list('user_id', flat=True).distinct()): profile.calculate_points() - cache.delete("user_complete:%d" % profile.id) - cache.delete("user_attempted:%d" % profile.id) + cache.delete('user_complete:%d' % profile.id) + cache.delete('user_attempted:%d' % profile.id) for participation in ContestParticipation.objects.filter( - id__in=queryset.values_list("contest__participation_id") - ).prefetch_related("contest"): + id__in=queryset.values_list('contest__participation_id')).prefetch_related('contest'): participation.recompute_results() - self.message_user( - request, - ungettext( - "%d submission were successfully rescored.", - "%d submissions were successfully rescored.", - len(submissions), - ) - % len(submissions), - ) - - recalculate_score.short_description = _("Rescore the selected submissions") + self.message_user(request, ungettext('%d submission were successfully rescored.', + '%d submissions were successfully rescored.', + len(submissions)) % len(submissions)) + recalculate_score.short_description = _('Rescore the selected submissions') def problem_code(self, obj): return obj.problem.code - - problem_code.short_description = _("Problem code") - problem_code.admin_order_field = "problem__code" + problem_code.short_description = _('Problem code') + problem_code.admin_order_field = 'problem__code' def problem_name(self, obj): return obj.problem.name - - problem_name.short_description = _("Problem name") - problem_name.admin_order_field = "problem__name" + problem_name.short_description = _('Problem name') + problem_name.admin_order_field = 'problem__name' def user_column(self, obj): return obj.user.user.username - - user_column.admin_order_field = "user__user__username" - user_column.short_description = _("User") + user_column.admin_order_field = 'user__user__username' + user_column.short_description = _('User') def execution_time(self, obj): - return round(obj.time, 2) if obj.time is not None else "None" - - execution_time.short_description = _("Time") - execution_time.admin_order_field = "time" + return round(obj.time, 2) if obj.time is not None else 'None' + execution_time.short_description = _('Time') + execution_time.admin_order_field = 'time' def pretty_memory(self, obj): memory = obj.memory if memory is None: - return gettext("None") + return gettext('None') if memory < 1000: - return gettext("%d KB") % memory + return gettext('%d KB') % memory else: - return gettext("%.2f MB") % (memory / 1024) - - pretty_memory.admin_order_field = "memory" - pretty_memory.short_description = _("Memory") + return gettext('%.2f MB') % (memory / 1024) + pretty_memory.admin_order_field = 'memory' + pretty_memory.short_description = _('Memory') def language_column(self, obj): return obj.language.name - - language_column.admin_order_field = "language__name" - language_column.short_description = _("Language") + language_column.admin_order_field = 'language__name' + language_column.short_description = _('Language') def judge_column(self, obj): - return format_html( - '', - obj.id, - ) - - judge_column.short_description = "" + return format_html('', obj.id) + judge_column.short_description = '' def get_urls(self): return [ - url(r"^(\d+)/judge/$", self.judge_view, name="judge_submission_rejudge"), + url(r'^(\d+)/judge/$', self.judge_view, name='judge_submission_rejudge'), ] + super(SubmissionAdmin, self).get_urls() def judge_view(self, request, id): - if not request.user.has_perm( - "judge.rejudge_submission" - ) or not request.user.has_perm("judge.edit_own_problem"): + if not request.user.has_perm('judge.rejudge_submission') or not request.user.has_perm('judge.edit_own_problem'): raise PermissionDenied() submission = get_object_or_404(Submission, id=id) - if not request.user.has_perm( - "judge.edit_all_problem" - ) and not submission.problem.is_editor(request.profile): + if not request.user.has_perm('judge.edit_all_problem') and \ + not submission.problem.is_editor(request.profile): raise PermissionDenied() submission.judge(rejudge=True) - return HttpResponseRedirect(request.META.get("HTTP_REFERER", "/")) + return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/')) diff --git a/judge/admin/taxon.py b/judge/admin/taxon.py index dfdc622..c707144 100644 --- a/judge/admin/taxon.py +++ b/judge/admin/taxon.py @@ -8,59 +8,45 @@ from judge.widgets import AdminHeavySelect2MultipleWidget class ProblemGroupForm(ModelForm): problems = ModelMultipleChoiceField( - label=_("Included problems"), + label=_('Included problems'), queryset=Problem.objects.all(), required=False, - help_text=_("These problems are included in this group of problems"), - widget=AdminHeavySelect2MultipleWidget(data_view="problem_select2"), - ) + help_text=_('These problems are included in this group of problems'), + widget=AdminHeavySelect2MultipleWidget(data_view='problem_select2')) class ProblemGroupAdmin(admin.ModelAdmin): - fields = ("name", "full_name", "problems") + fields = ('name', 'full_name', 'problems') form = ProblemGroupForm def save_model(self, request, obj, form, change): super(ProblemGroupAdmin, self).save_model(request, obj, form, change) - obj.problem_set.set(form.cleaned_data["problems"]) + obj.problem_set.set(form.cleaned_data['problems']) obj.save() def get_form(self, request, obj=None, **kwargs): - self.form.base_fields["problems"].initial = ( - [o.pk for o in obj.problem_set.all()] if obj else [] - ) + self.form.base_fields['problems'].initial = [o.pk for o in obj.problem_set.all()] if obj else [] return super(ProblemGroupAdmin, self).get_form(request, obj, **kwargs) class ProblemTypeForm(ModelForm): problems = ModelMultipleChoiceField( - label=_("Included problems"), + label=_('Included problems'), queryset=Problem.objects.all(), required=False, - help_text=_("These problems are included in this type of problems"), - widget=AdminHeavySelect2MultipleWidget(data_view="problem_select2"), - ) + help_text=_('These problems are included in this type of problems'), + widget=AdminHeavySelect2MultipleWidget(data_view='problem_select2')) class ProblemTypeAdmin(admin.ModelAdmin): - fields = ("name", "full_name", "problems") + fields = ('name', 'full_name', 'problems') form = ProblemTypeForm def save_model(self, request, obj, form, change): super(ProblemTypeAdmin, self).save_model(request, obj, form, change) - obj.problem_set.set(form.cleaned_data["problems"]) + obj.problem_set.set(form.cleaned_data['problems']) obj.save() def get_form(self, request, obj=None, **kwargs): - self.form.base_fields["problems"].initial = ( - [o.pk for o in obj.problem_set.all()] if obj else [] - ) + self.form.base_fields['problems'].initial = [o.pk for o in obj.problem_set.all()] if obj else [] return super(ProblemTypeAdmin, self).get_form(request, obj, **kwargs) - - -class OfficialContestCategoryAdmin(admin.ModelAdmin): - fields = ("name",) - - -class OfficialContestLocationAdmin(admin.ModelAdmin): - fields = ("name",) diff --git a/judge/admin/ticket.py b/judge/admin/ticket.py index f7495dd..a5c5a5e 100644 --- a/judge/admin/ticket.py +++ b/judge/admin/ticket.py @@ -4,56 +4,36 @@ from django.forms import ModelForm from django.urls import reverse_lazy from judge.models import TicketMessage -from judge.widgets import ( - AdminHeavySelect2MultipleWidget, - AdminHeavySelect2Widget, - HeavyPreviewAdminPageDownWidget, -) +from judge.widgets import AdminHeavySelect2MultipleWidget, AdminHeavySelect2Widget, HeavyPreviewAdminPageDownWidget class TicketMessageForm(ModelForm): class Meta: widgets = { - "user": AdminHeavySelect2Widget( - data_view="profile_select2", attrs={"style": "width: 100%"} - ), + 'user': AdminHeavySelect2Widget(data_view='profile_select2', attrs={'style': 'width: 100%'}), } if HeavyPreviewAdminPageDownWidget is not None: - widgets["body"] = HeavyPreviewAdminPageDownWidget( - preview=reverse_lazy("ticket_preview") - ) + widgets['body'] = HeavyPreviewAdminPageDownWidget(preview=reverse_lazy('ticket_preview')) class TicketMessageInline(StackedInline): model = TicketMessage form = TicketMessageForm - fields = ("user", "body") + fields = ('user', 'body') class TicketForm(ModelForm): class Meta: widgets = { - "user": AdminHeavySelect2Widget( - data_view="profile_select2", attrs={"style": "width: 100%"} - ), - "assignees": AdminHeavySelect2MultipleWidget( - data_view="profile_select2", attrs={"style": "width: 100%"} - ), + 'user': AdminHeavySelect2Widget(data_view='profile_select2', attrs={'style': 'width: 100%'}), + 'assignees': AdminHeavySelect2MultipleWidget(data_view='profile_select2', attrs={'style': 'width: 100%'}), } class TicketAdmin(ModelAdmin): - fields = ( - "title", - "time", - "user", - "assignees", - "content_type", - "object_id", - "notes", - ) - readonly_fields = ("time",) - list_display = ("title", "user", "time", "linked_item") + fields = ('title', 'time', 'user', 'assignees', 'content_type', 'object_id', 'notes') + readonly_fields = ('time',) + list_display = ('title', 'user', 'time', 'linked_item') inlines = [TicketMessageInline] form = TicketForm - date_hierarchy = "time" + date_hierarchy = 'time' diff --git a/judge/admin/volunteer.py b/judge/admin/volunteer.py deleted file mode 100644 index cadb090..0000000 --- a/judge/admin/volunteer.py +++ /dev/null @@ -1,67 +0,0 @@ -from operator import attrgetter - -from django.contrib import admin -from django.utils.html import format_html -from django.urls import reverse -from django.utils.translation import gettext, gettext_lazy as _, ungettext -from django.forms import ModelForm - -from judge.models import VolunteerProblemVote -from judge.widgets import AdminSelect2MultipleWidget - - -class VolunteerProblemVoteForm(ModelForm): - class Meta: - widgets = { - "types": AdminSelect2MultipleWidget, - } - - -class VolunteerProblemVoteAdmin(admin.ModelAdmin): - form = VolunteerProblemVoteForm - fields = ( - "voter", - "problem_link", - "time", - "thinking_points", - "knowledge_points", - "types", - "feedback", - ) - readonly_fields = ("time", "problem_link", "voter") - list_display = ( - "voter", - "problem_link", - "thinking_points", - "knowledge_points", - "show_types", - "feedback", - ) - search_fields = ( - "voter__user__username", - "problem__code", - "problem__name", - ) - date_hierarchy = "time" - - def problem_link(self, obj): - if self.request.user.is_superuser: - url = reverse("admin:judge_problem_change", args=(obj.problem.id,)) - else: - url = reverse("problem_detail", args=(obj.problem.code,)) - return format_html(f"{obj.problem}") - - problem_link.short_description = _("Problem") - problem_link.admin_order_field = "problem__code" - - def show_types(self, obj): - return ", ".join(map(attrgetter("name"), obj.types.all())) - - show_types.short_description = _("Types") - - def get_queryset(self, request): - self.request = request - if request.user.is_superuser: - return super().get_queryset(request) - queryset = VolunteerProblemVote.objects.prefetch_related("voter") - return queryset.filter(voter=request.profile).distinct() diff --git a/judge/apps.py b/judge/apps.py index 4df4c5a..068889e 100644 --- a/judge/apps.py +++ b/judge/apps.py @@ -4,15 +4,15 @@ from django.utils.translation import gettext_lazy class JudgeAppConfig(AppConfig): - name = "judge" - verbose_name = gettext_lazy("Online Judge") + name = 'judge' + verbose_name = gettext_lazy('Online Judge') def ready(self): # WARNING: AS THIS IS NOT A FUNCTIONAL PROGRAMMING LANGUAGE, # OPERATIONS MAY HAVE SIDE EFFECTS. # DO NOT REMOVE THINKING THE IMPORT IS UNUSED. # noinspection PyUnresolvedReferences - from . import models, signals, jinja2 # noqa: F401, imported for side effects + from . import signals, jinja2 # noqa: F401, imported for side effects from django.contrib.flatpages.models import FlatPage from django.contrib.flatpages.admin import FlatPageAdmin @@ -30,7 +30,7 @@ class JudgeAppConfig(AppConfig): from django.contrib.auth.models import User try: - lang = Language.get_default_language() + lang = Language.get_python3() for user in User.objects.filter(profile=None): # These poor profileless users profile = Profile(user=user, language=lang) diff --git a/judge/authentication.py b/judge/authentication.py deleted file mode 100644 index c7ae7d6..0000000 --- a/judge/authentication.py +++ /dev/null @@ -1,48 +0,0 @@ -from django.contrib.auth.backends import ModelBackend -from django.contrib.auth.models import User -from django.contrib.auth.forms import PasswordChangeForm -from django.contrib.auth.views import PasswordChangeView -from django.urls import reverse_lazy -from django.utils.translation import gettext_lazy as _ - - -class CustomModelBackend(ModelBackend): - def authenticate(self, request, username=None, password=None, **kwargs): - try: - # Check if the username is an email - user = User.objects.get(username=username) - except User.DoesNotExist: - # If the username is not an email, try authenticating with the username field - user = User.objects.filter(email=username).first() - - if user and user.check_password(password): - return user - - -class CustomPasswordChangeForm(PasswordChangeForm): - def __init__(self, *args, **kwargs): - super(CustomPasswordChangeForm, self).__init__(*args, **kwargs) - if not self.user.has_usable_password(): - self.fields.pop("old_password") - - def clean_old_password(self): - if "old_password" not in self.cleaned_data: - return - return super(CustomPasswordChangeForm, self).clean_old_password() - - def clean(self): - cleaned_data = super(CustomPasswordChangeForm, self).clean() - if "old_password" not in self.cleaned_data and not self.errors: - cleaned_data["old_password"] = "" - return cleaned_data - - -class CustomPasswordChangeView(PasswordChangeView): - form_class = CustomPasswordChangeForm - success_url = reverse_lazy("password_change_done") - template_name = "registration/password_change_form.html" - - def get_form_kwargs(self): - kwargs = super(CustomPasswordChangeView, self).get_form_kwargs() - kwargs["user"] = self.request.user - return kwargs diff --git a/judge/bridge/__init__.py b/judge/bridge/__init__.py index e69de29..f1f1bfb 100644 --- a/judge/bridge/__init__.py +++ b/judge/bridge/__init__.py @@ -0,0 +1,6 @@ +from .djangohandler import DjangoHandler +from .djangoserver import DjangoServer +from .judgecallback import DjangoJudgeHandler +from .judgehandler import JudgeHandler +from .judgelist import JudgeList +from .judgeserver import JudgeServer diff --git a/judge/bridge/base_handler.py b/judge/bridge/base_handler.py deleted file mode 100644 index 0e5c067..0000000 --- a/judge/bridge/base_handler.py +++ /dev/null @@ -1,218 +0,0 @@ -import logging -import socket -import struct -import zlib -from itertools import chain - -from netaddr import IPGlob, IPSet - -from judge.utils.unicode import utf8text - -logger = logging.getLogger("judge.bridge") - -size_pack = struct.Struct("!I") -assert size_pack.size == 4 - -MAX_ALLOWED_PACKET_SIZE = 8 * 1024 * 1024 - - -def proxy_list(human_readable): - globs = [] - addrs = [] - for item in human_readable: - if "*" in item or "-" in item: - globs.append(IPGlob(item)) - else: - addrs.append(item) - return IPSet(chain(chain.from_iterable(globs), addrs)) - - -class Disconnect(Exception): - pass - - -# socketserver.BaseRequestHandler does all the handling in __init__, -# making it impossible to inherit __init__ sanely. While it lets you -# use setup(), most tools will complain about uninitialized variables. -# This metaclass will allow sane __init__ behaviour while also magically -# calling the methods that handles the request. -class RequestHandlerMeta(type): - def __call__(cls, *args, **kwargs): - handler = super().__call__(*args, **kwargs) - handler.on_connect() - try: - handler.handle() - except BaseException: - logger.exception("Error in base packet handling") - raise - finally: - handler.on_disconnect() - - -class ZlibPacketHandler(metaclass=RequestHandlerMeta): - proxies = [] - - def __init__(self, request, client_address, server): - self.request = request - self.server = server - self.client_address = client_address - self.server_address = server.server_address - self._initial_tag = None - self._got_packet = False - - @property - def timeout(self): - return self.request.gettimeout() - - @timeout.setter - def timeout(self, timeout): - self.request.settimeout(timeout or None) - - def read_sized_packet(self, size, initial=None): - if size > MAX_ALLOWED_PACKET_SIZE: - logger.log( - logging.WARNING if self._got_packet else logging.INFO, - "Disconnecting client due to too-large message size (%d bytes): %s", - size, - self.client_address, - ) - raise Disconnect() - - buffer = [] - remainder = size - - if initial: - buffer.append(initial) - remainder -= len(initial) - assert remainder >= 0 - - while remainder: - data = self.request.recv(remainder) - remainder -= len(data) - buffer.append(data) - self._on_packet(b"".join(buffer)) - - def parse_proxy_protocol(self, line): - words = line.split() - - if len(words) < 2: - raise Disconnect() - - if words[1] == b"TCP4": - if len(words) != 6: - raise Disconnect() - self.client_address = (utf8text(words[2]), utf8text(words[4])) - self.server_address = (utf8text(words[3]), utf8text(words[5])) - elif words[1] == b"TCP6": - self.client_address = (utf8text(words[2]), utf8text(words[4]), 0, 0) - self.server_address = (utf8text(words[3]), utf8text(words[5]), 0, 0) - elif words[1] != b"UNKNOWN": - raise Disconnect() - - def read_size(self, buffer=b""): - while len(buffer) < size_pack.size: - recv = self.request.recv(size_pack.size - len(buffer)) - if not recv: - raise Disconnect() - buffer += recv - return size_pack.unpack(buffer)[0] - - def read_proxy_header(self, buffer=b""): - # Max line length for PROXY protocol is 107, and we received 4 already. - while b"\r\n" not in buffer: - if len(buffer) > 107: - raise Disconnect() - data = self.request.recv(107) - if not data: - raise Disconnect() - buffer += data - return buffer - - def _on_packet(self, data): - decompressed = zlib.decompress(data).decode("utf-8") - self._got_packet = True - self.on_packet(decompressed) - - def on_packet(self, data): - raise NotImplementedError() - - def on_connect(self): - pass - - def on_disconnect(self): - pass - - def on_timeout(self): - pass - - def on_cleanup(self): - pass - - def handle(self): - try: - tag = self.read_size() - self._initial_tag = size_pack.pack(tag) - if self.client_address[0] in self.proxies and self._initial_tag == b"PROX": - proxy, _, remainder = self.read_proxy_header( - self._initial_tag - ).partition(b"\r\n") - self.parse_proxy_protocol(proxy) - - while remainder: - while len(remainder) < size_pack.size: - self.read_sized_packet(self.read_size(remainder)) - break - - size = size_pack.unpack(remainder[: size_pack.size])[0] - remainder = remainder[size_pack.size :] - if len(remainder) <= size: - self.read_sized_packet(size, remainder) - break - - self._on_packet(remainder[:size]) - remainder = remainder[size:] - else: - self.read_sized_packet(tag) - - while True: - self.read_sized_packet(self.read_size()) - except Disconnect: - return - except zlib.error: - if self._got_packet: - logger.warning( - "Encountered zlib error during packet handling, disconnecting client: %s", - self.client_address, - exc_info=True, - ) - else: - logger.info( - "Potentially wrong protocol (zlib error): %s: %r", - self.client_address, - self._initial_tag, - exc_info=True, - ) - except socket.timeout: - if self._got_packet: - logger.info("Socket timed out: %s", self.client_address) - self.on_timeout() - else: - logger.info( - "Potentially wrong protocol: %s: %r", - self.client_address, - self._initial_tag, - ) - except socket.error as e: - # When a gevent socket is shutdown, gevent cancels all waits, causing recv to raise cancel_wait_ex. - if e.__class__.__name__ == "cancel_wait_ex": - return - raise - finally: - self.on_cleanup() - - def send(self, data): - compressed = zlib.compress(data.encode("utf-8")) - self.request.sendall(size_pack.pack(len(compressed)) + compressed) - - def close(self): - self.request.shutdown(socket.SHUT_RDWR) diff --git a/judge/bridge/daemon.py b/judge/bridge/daemon.py deleted file mode 100644 index b9988ce..0000000 --- a/judge/bridge/daemon.py +++ /dev/null @@ -1,52 +0,0 @@ -import logging -import signal -import threading -from functools import partial - -from django.conf import settings - -from judge.bridge.django_handler import DjangoHandler -from judge.bridge.judge_handler import JudgeHandler -from judge.bridge.judge_list import JudgeList -from judge.bridge.server import Server -from judge.models import Judge, Submission - -logger = logging.getLogger("judge.bridge") - - -def reset_judges(): - Judge.objects.update(online=False, ping=None, load=None) - - -def judge_daemon(): - reset_judges() - Submission.objects.filter(status__in=Submission.IN_PROGRESS_GRADING_STATUS).update( - status="IE", result="IE", error=None - ) - judges = JudgeList() - - judge_server = Server( - settings.BRIDGED_JUDGE_ADDRESS, partial(JudgeHandler, judges=judges) - ) - django_server = Server( - settings.BRIDGED_DJANGO_ADDRESS, partial(DjangoHandler, judges=judges) - ) - - threading.Thread(target=django_server.serve_forever).start() - threading.Thread(target=judge_server.serve_forever).start() - - stop = threading.Event() - - def signal_handler(signum, _): - logger.info("Exiting due to %s", signal.Signals(signum).name) - stop.set() - - signal.signal(signal.SIGINT, signal_handler) - signal.signal(signal.SIGQUIT, signal_handler) - signal.signal(signal.SIGTERM, signal_handler) - - try: - stop.wait() - finally: - django_server.shutdown() - judge_server.shutdown() diff --git a/judge/bridge/django_handler.py b/judge/bridge/django_handler.py deleted file mode 100644 index 8a40c3f..0000000 --- a/judge/bridge/django_handler.py +++ /dev/null @@ -1,66 +0,0 @@ -import json -import logging -import struct - -from django import db - -from judge.bridge.base_handler import Disconnect, ZlibPacketHandler - -logger = logging.getLogger("judge.bridge") -size_pack = struct.Struct("!I") - - -class DjangoHandler(ZlibPacketHandler): - def __init__(self, request, client_address, server, judges): - super().__init__(request, client_address, server) - - self.handlers = { - "submission-request": self.on_submission, - "terminate-submission": self.on_termination, - "disconnect-judge": self.on_disconnect_request, - } - self.judges = judges - - def send(self, data): - super().send(json.dumps(data, separators=(",", ":"))) - - def on_packet(self, packet): - packet = json.loads(packet) - try: - result = self.handlers.get(packet.get("name", None), self.on_malformed)( - packet - ) - except Exception: - logger.exception("Error in packet handling (Django-facing)") - result = {"name": "bad-request"} - self.send(result) - raise Disconnect() - - def on_submission(self, data): - id = data["submission-id"] - problem = data["problem-id"] - language = data["language"] - source = data["source"] - judge_id = data["judge-id"] - priority = data["priority"] - if not self.judges.check_priority(priority): - return {"name": "bad-request"} - self.judges.judge(id, problem, language, source, judge_id, priority) - return {"name": "submission-received", "submission-id": id} - - def on_termination(self, data): - return { - "name": "submission-received", - "judge-aborted": self.judges.abort(data["submission-id"]), - } - - def on_disconnect_request(self, data): - judge_id = data["judge-id"] - force = data["force"] - self.judges.disconnect(judge_id, force=force) - - def on_malformed(self, packet): - logger.error("Malformed packet: %s", packet) - - def on_cleanup(self): - db.connection.close() diff --git a/judge/bridge/djangohandler.py b/judge/bridge/djangohandler.py new file mode 100644 index 0000000..8b18a53 --- /dev/null +++ b/judge/bridge/djangohandler.py @@ -0,0 +1,67 @@ +import json +import logging +import struct + +from event_socket_server import ZlibPacketHandler + +logger = logging.getLogger('judge.bridge') +size_pack = struct.Struct('!I') + + +class DjangoHandler(ZlibPacketHandler): + def __init__(self, server, socket): + super(DjangoHandler, self).__init__(server, socket) + + self.handlers = { + 'submission-request': self.on_submission, + 'terminate-submission': self.on_termination, + 'disconnect-judge': self.on_disconnect, + } + self._to_kill = True + # self.server.schedule(5, self._kill_if_no_request) + + def _kill_if_no_request(self): + if self._to_kill: + logger.info('Killed inactive connection: %s', self._socket.getpeername()) + self.close() + + def _format_send(self, data): + return super(DjangoHandler, self)._format_send(json.dumps(data, separators=(',', ':'))) + + def packet(self, packet): + self._to_kill = False + packet = json.loads(packet) + try: + result = self.handlers.get(packet.get('name', None), self.on_malformed)(packet) + except Exception: + logger.exception('Error in packet handling (Django-facing)') + result = {'name': 'bad-request'} + self.send(result, self._schedule_close) + + def _schedule_close(self): + self.server.schedule(0, self.close) + + def on_submission(self, data): + id = data['submission-id'] + problem = data['problem-id'] + language = data['language'] + source = data['source'] + priority = data['priority'] + if not self.server.judges.check_priority(priority): + return {'name': 'bad-request'} + self.server.judges.judge(id, problem, language, source, priority) + return {'name': 'submission-received', 'submission-id': id} + + def on_termination(self, data): + return {'name': 'submission-received', 'judge-aborted': self.server.judges.abort(data['submission-id'])} + + def on_disconnect(self, data): + judge_id = data['judge-id'] + force = data['force'] + self.server.judges.disconnect(judge_id, force=force) + + def on_malformed(self, packet): + logger.error('Malformed packet: %s', packet) + + def on_close(self): + self._to_kill = False diff --git a/judge/bridge/djangoserver.py b/judge/bridge/djangoserver.py new file mode 100644 index 0000000..39f5787 --- /dev/null +++ b/judge/bridge/djangoserver.py @@ -0,0 +1,7 @@ +from event_socket_server import get_preferred_engine + + +class DjangoServer(get_preferred_engine()): + def __init__(self, judges, *args, **kwargs): + super(DjangoServer, self).__init__(*args, **kwargs) + self.judges = judges diff --git a/judge/bridge/echo_test_client.py b/judge/bridge/echo_test_client.py deleted file mode 100644 index 801d34e..0000000 --- a/judge/bridge/echo_test_client.py +++ /dev/null @@ -1,82 +0,0 @@ -import os -import socket -import struct -import time -import zlib - -size_pack = struct.Struct("!I") - - -def open_connection(): - sock = socket.create_connection((host, port)) - return sock - - -def zlibify(data): - data = zlib.compress(data.encode("utf-8")) - return size_pack.pack(len(data)) + data - - -def dezlibify(data, skip_head=True): - if skip_head: - data = data[size_pack.size :] - return zlib.decompress(data).decode("utf-8") - - -def main(): - global host, port - import argparse - - parser = argparse.ArgumentParser() - parser.add_argument("-l", "--host", default="localhost") - parser.add_argument("-p", "--port", default=9999, type=int) - args = parser.parse_args() - host, port = args.host, args.port - - print("Opening idle connection:", end=" ") - s1 = open_connection() - print("Success") - print("Opening hello world connection:", end=" ") - s2 = open_connection() - print("Success") - print("Sending Hello, World!", end=" ") - s2.sendall(zlibify("Hello, World!")) - print("Success") - print("Testing blank connection:", end=" ") - s3 = open_connection() - s3.close() - print("Success") - result = dezlibify(s2.recv(1024)) - assert result == "Hello, World!" - print(result) - s2.close() - print("Large random data test:", end=" ") - s4 = open_connection() - data = os.urandom(1000000).decode("iso-8859-1") - print("Generated", end=" ") - s4.sendall(zlibify(data)) - print("Sent", end=" ") - result = b"" - while len(result) < size_pack.size: - result += s4.recv(1024) - size = size_pack.unpack(result[: size_pack.size])[0] - result = result[size_pack.size :] - while len(result) < size: - result += s4.recv(1024) - print("Received", end=" ") - assert dezlibify(result, False) == data - print("Success") - s4.close() - print("Test malformed connection:", end=" ") - s5 = open_connection() - s5.sendall(data[:100000].encode("utf-8")) - s5.close() - print("Success") - print("Waiting for timeout to close idle connection:", end=" ") - time.sleep(6) - print("Done") - s1.close() - - -if __name__ == "__main__": - main() diff --git a/judge/bridge/echo_test_server.py b/judge/bridge/echo_test_server.py deleted file mode 100644 index 2d84e85..0000000 --- a/judge/bridge/echo_test_server.py +++ /dev/null @@ -1,42 +0,0 @@ -from judge.bridge.base_handler import ZlibPacketHandler - - -class EchoPacketHandler(ZlibPacketHandler): - def on_connect(self): - print("New client:", self.client_address) - self.timeout = 5 - - def on_timeout(self): - print("Inactive client:", self.client_address) - - def on_packet(self, data): - self.timeout = None - print( - "Data from %s: %r" - % (self.client_address, data[:30] if len(data) > 30 else data) - ) - self.send(data) - - def on_disconnect(self): - print("Closed client:", self.client_address) - - -def main(): - import argparse - from judge.bridge.server import Server - - parser = argparse.ArgumentParser() - parser.add_argument("-l", "--host", action="append") - parser.add_argument("-p", "--port", type=int, action="append") - parser.add_argument("-P", "--proxy", action="append") - args = parser.parse_args() - - class Handler(EchoPacketHandler): - proxies = args.proxy or [] - - server = Server(list(zip(args.host, args.port)), Handler) - server.serve_forever() - - -if __name__ == "__main__": - main() diff --git a/judge/bridge/judge_handler.py b/judge/bridge/judge_handler.py deleted file mode 100644 index bb80f5a..0000000 --- a/judge/bridge/judge_handler.py +++ /dev/null @@ -1,966 +0,0 @@ -import hmac -import json -import logging -import threading -import time -from collections import deque, namedtuple -from operator import itemgetter - -from django import db -from django.conf import settings -from django.utils import timezone -from django.db.models import F -from django.core.cache import cache - -from judge import event_poster as event -from judge.bridge.base_handler import ZlibPacketHandler, proxy_list -from judge.utils.problems import finished_submission -from judge.models import ( - Judge, - Language, - LanguageLimit, - Problem, - RuntimeVersion, - Submission, - SubmissionTestCase, -) -from judge.bridge.utils import VanishedSubmission -from judge.caching import cache_wrapper - -logger = logging.getLogger("judge.bridge") -json_log = logging.getLogger("judge.json.bridge") - -UPDATE_RATE_LIMIT = 5 -UPDATE_RATE_TIME = 0.5 -SubmissionData = namedtuple( - "SubmissionData", - "time memory short_circuit pretests_only contest_no attempt_no user_id", -) - - -def _ensure_connection(): - db.connection.close_if_unusable_or_obsolete() - - -class JudgeHandler(ZlibPacketHandler): - proxies = proxy_list(settings.BRIDGED_JUDGE_PROXIES or []) - - def __init__(self, request, client_address, server, judges): - super().__init__(request, client_address, server) - - self.judges = judges - self.handlers = { - "grading-begin": self.on_grading_begin, - "grading-end": self.on_grading_end, - "compile-error": self.on_compile_error, - "compile-message": self.on_compile_message, - "batch-begin": self.on_batch_begin, - "batch-end": self.on_batch_end, - "test-case-status": self.on_test_case, - "internal-error": self.on_internal_error, - "submission-terminated": self.on_submission_terminated, - "submission-acknowledged": self.on_submission_acknowledged, - "ping-response": self.on_ping_response, - "supported-problems": self.on_supported_problems, - "handshake": self.on_handshake, - } - self._working = False - self._working_data = {} - self._no_response_job = None - self.executors = {} - self.problems = set() - self.latency = None - self.time_delta = None - self.load = 1e100 - self.name = None - self.batch_id = None - self.in_batch = False - self._stop_ping = threading.Event() - self._ping_average = deque(maxlen=6) # 1 minute average, just like load - self._time_delta = deque(maxlen=6) - - # each value is (updates, last reset) - self.update_counter = {} - self.judge = None - self.judge_address = None - - self._submission_cache_id = None - self._submission_cache = {} - - def on_connect(self): - self.timeout = 15 - logger.info("Judge connected from: %s", self.client_address) - json_log.info(self._make_json_log(action="connect")) - - def on_disconnect(self): - self._stop_ping.set() - self.judges.remove(self) - if self.name is not None: - self._disconnected() - logger.info( - "Judge disconnected from: %s with name %s", self.client_address, self.name - ) - - json_log.info( - self._make_json_log(action="disconnect", info="judge disconnected") - ) - if self._working: - self.judges.judge( - self._working, - self._working_data["problem"], - self._working_data["language"], - self._working_data["source"], - None, - 0, - ) - - def _authenticate(self, id, key): - try: - judge = Judge.objects.get(name=id) - except Judge.DoesNotExist: - if settings.BRIDGED_AUTO_CREATE_JUDGE: - judge = Judge() - judge.name = id - judge.auth_key = key - judge.save() - result = True - else: - result = False - else: - if judge.is_blocked: - result = False - else: - result = hmac.compare_digest(judge.auth_key, key) - - if not result: - json_log.warning( - self._make_json_log( - action="auth", judge=id, info="judge failed authentication" - ) - ) - return result - - def _update_supported_problems(self, problem_packet): - # problem_packet is a dict {code: mtimes} from judge-server - self.problems = set(p for p, _ in problem_packet) - - def _update_judge_problems(self): - chunk_size = 500 - - target_problem_codes = self.problems - current_problems = _get_judge_problems(self.judge) - - updated = False - problems_to_add = list(target_problem_codes - current_problems) - problems_to_remove = list(current_problems - target_problem_codes) - - if problems_to_add: - for i in range(0, len(problems_to_add), chunk_size): - chunk = problems_to_add[i : i + chunk_size] - problem_ids = Problem.objects.filter(code__in=chunk).values_list( - "id", flat=True - ) - if not problem_ids: - continue - logger.info("%s: Add %d problems", self.name, len(problem_ids)) - self.judge.problems.add(*problem_ids) - updated = True - - if problems_to_remove: - for i in range(0, len(problems_to_remove), chunk_size): - chunk = problems_to_remove[i : i + chunk_size] - problem_ids = Problem.objects.filter(code__in=chunk).values_list( - "id", flat=True - ) - if not problem_ids: - continue - logger.info("%s: Remove %d problems", self.name, len(problem_ids)) - self.judge.problems.remove(*problem_ids) - updated = True - - if updated: - _get_judge_problems.dirty(self.judge) - - def _connected(self): - judge = self.judge = Judge.objects.get(name=self.name) - judge.start_time = timezone.now() - judge.online = True - self._update_judge_problems() - judge.runtimes.set(Language.objects.filter(key__in=list(self.executors.keys()))) - - # Delete now in case we somehow crashed and left some over from the last connection - RuntimeVersion.objects.filter(judge=judge).delete() - versions = [] - for lang in judge.runtimes.all(): - versions += [ - RuntimeVersion( - language=lang, - name=name, - version=".".join(map(str, version)), - priority=idx, - judge=judge, - ) - for idx, (name, version) in enumerate(self.executors[lang.key]) - ] - RuntimeVersion.objects.bulk_create(versions) - judge.last_ip = self.client_address[0] - judge.save() - self.judge_address = "[%s]:%s" % ( - self.client_address[0], - self.client_address[1], - ) - json_log.info( - self._make_json_log( - action="auth", - info="judge successfully authenticated", - executors=list(self.executors.keys()), - ) - ) - - def _disconnected(self): - Judge.objects.filter(id=self.judge.id).update(online=False) - RuntimeVersion.objects.filter(judge=self.judge).delete() - self.judge.problems.clear() - _get_judge_problems.dirty(self.judge) - - def _update_ping(self): - try: - Judge.objects.filter(name=self.name).update( - ping=self.latency, load=self.load - ) - except Exception as e: - # What can I do? I don't want to tie this to MySQL. - if ( - e.__class__.__name__ == "OperationalError" - and e.__module__ == "_mysql_exceptions" - and e.args[0] == 2006 - ): - db.connection.close() - - def send(self, data): - super().send(json.dumps(data, separators=(",", ":"))) - - def on_handshake(self, packet): - if "id" not in packet or "key" not in packet: - logger.warning("Malformed handshake: %s", self.client_address) - self.close() - return - - if not self._authenticate(packet["id"], packet["key"]): - logger.warning("Authentication failure: %s", self.client_address) - self.close() - return - - self.timeout = 60 - self._update_supported_problems(packet["problems"]) - self.executors = packet["executors"] - self.name = packet["id"] - - self.send({"name": "handshake-success"}) - logger.info("Judge authenticated: %s (%s)", self.client_address, packet["id"]) - self.judges.register(self) - threading.Thread(target=self._ping_thread).start() - self._connected() - - def can_judge(self, problem, executor, judge_id=None): - return ( - problem in self.problems - and executor in self.executors - and (not judge_id or self.name == judge_id) - ) - - @property - def working(self): - return bool(self._working) - - def get_related_submission_data(self, submission): - _ensure_connection() - - try: - ( - pid, - time, - memory, - short_circuit, - lid, - is_pretested, - sub_date, - uid, - part_virtual, - part_id, - ) = ( - Submission.objects.filter(id=submission).values_list( - "problem__id", - "problem__time_limit", - "problem__memory_limit", - "problem__short_circuit", - "language__id", - "is_pretested", - "date", - "user__id", - "contest__participation__virtual", - "contest__participation__id", - ) - ).get() - except Submission.DoesNotExist: - logger.error("Submission vanished: %s", submission) - json_log.error( - self._make_json_log( - sub=self._working, - action="request", - info="submission vanished when fetching info", - ) - ) - return - - attempt_no = ( - Submission.objects.filter( - problem__id=pid, - contest__participation__id=part_id, - user__id=uid, - date__lt=sub_date, - ) - .exclude(status__in=("CE", "IE")) - .count() - + 1 - ) - - try: - time, memory = ( - LanguageLimit.objects.filter(problem__id=pid, language__id=lid) - .values_list("time_limit", "memory_limit") - .get() - ) - except LanguageLimit.DoesNotExist: - pass - - return SubmissionData( - time=time, - memory=memory, - short_circuit=short_circuit, - pretests_only=is_pretested, - contest_no=part_virtual, - attempt_no=attempt_no, - user_id=uid, - ) - - def disconnect(self, force=False): - if force: - # Yank the power out. - self.close() - else: - self.send({"name": "disconnect"}) - - def submit(self, id, problem, language, source): - data = self.get_related_submission_data(id) - if not data: - self._update_internal_error_submission(id, "Submission vanished") - raise VanishedSubmission() - self._working = id - self._working_data = { - "problem": problem, - "language": language, - "source": source, - } - self._no_response_job = threading.Timer(20, self._kill_if_no_response) - self.send( - { - "name": "submission-request", - "submission-id": id, - "problem-id": problem, - "language": language, - "source": source, - "time-limit": data.time, - "memory-limit": data.memory, - "short-circuit": data.short_circuit, - "meta": { - "pretests-only": data.pretests_only, - "in-contest": data.contest_no, - "attempt-no": data.attempt_no, - "user": data.user_id, - }, - } - ) - - def _kill_if_no_response(self): - logger.error( - "Judge failed to acknowledge submission: %s: %s", self.name, self._working - ) - self.close() - - def on_timeout(self): - if self.name: - logger.warning("Judge seems dead: %s: %s", self.name, self._working) - - def malformed_packet(self, exception): - logger.exception("Judge sent malformed packet: %s", self.name) - super(JudgeHandler, self).malformed_packet(exception) - - def on_submission_processing(self, packet): - _ensure_connection() - - id = packet["submission-id"] - if Submission.objects.filter(id=id).update(status="P", judged_on=self.judge): - event.post("sub_%s" % Submission.get_id_secret(id), {"type": "processing"}) - self._post_update_submission(id, "processing") - json_log.info(self._make_json_log(packet, action="processing")) - else: - logger.warning("Unknown submission: %s", id) - json_log.error( - self._make_json_log( - packet, action="processing", info="unknown submission" - ) - ) - - def on_submission_wrong_acknowledge(self, packet, expected, got): - json_log.error( - self._make_json_log( - packet, action="processing", info="wrong-acknowledge", expected=expected - ) - ) - Submission.objects.filter(id=expected).update( - status="IE", result="IE", error=None - ) - Submission.objects.filter(id=got, status="QU").update( - status="IE", result="IE", error=None - ) - - def on_submission_acknowledged(self, packet): - if not packet.get("submission-id", None) == self._working: - logger.error( - "Wrong acknowledgement: %s: %s, expected: %s", - self.name, - packet.get("submission-id", None), - self._working, - ) - self.on_submission_wrong_acknowledge( - packet, self._working, packet.get("submission-id", None) - ) - self.close() - logger.info("Submission acknowledged: %d", self._working) - if self._no_response_job: - self._no_response_job.cancel() - self._no_response_job = None - self.on_submission_processing(packet) - - def abort(self): - self.send({"name": "terminate-submission"}) - - def get_current_submission(self): - return self._working or None - - def ping(self): - self.send({"name": "ping", "when": time.time()}) - - def on_packet(self, data): - try: - try: - data = json.loads(data) - if "name" not in data: - raise ValueError - except ValueError: - self.on_malformed(data) - else: - handler = self.handlers.get(data["name"], self.on_malformed) - handler(data) - except Exception: - logger.exception("Error in packet handling (Judge-side): %s", self.name) - self._packet_exception() - # You can't crash here because you aren't so sure about the judges - # not being malicious or simply malforms. THIS IS A SERVER! - - def _packet_exception(self): - json_log.exception( - self._make_json_log(sub=self._working, info="packet processing exception") - ) - - def _submission_is_batch(self, id): - if not Submission.objects.filter(id=id).update(batch=True): - logger.warning("Unknown submission: %s", id) - - def on_supported_problems(self, packet): - logger.info("%s: Updated problem list", self.name) - self._update_supported_problems(packet["problems"]) - - if not self.working: - self.judges.update_problems(self) - - self._update_judge_problems() - json_log.info( - self._make_json_log(action="update-problems", count=len(self.problems)) - ) - - def on_grading_begin(self, packet): - logger.info("%s: Grading has begun on: %s", self.name, packet["submission-id"]) - self.batch_id = None - - if Submission.objects.filter(id=packet["submission-id"]).update( - status="G", - is_pretested=packet["pretested"], - current_testcase=1, - points=0, - batch=False, - judged_date=timezone.now(), - ): - SubmissionTestCase.objects.filter( - submission_id=packet["submission-id"] - ).delete() - event.post( - "sub_%s" % Submission.get_id_secret(packet["submission-id"]), - {"type": "grading-begin"}, - ) - self._post_update_submission(packet["submission-id"], "grading-begin") - json_log.info(self._make_json_log(packet, action="grading-begin")) - else: - logger.warning("Unknown submission: %s", packet["submission-id"]) - json_log.error( - self._make_json_log( - packet, action="grading-begin", info="unknown submission" - ) - ) - - def on_grading_end(self, packet): - logger.info("%s: Grading has ended on: %s", self.name, packet["submission-id"]) - self._free_self(packet) - self.batch_id = None - - try: - submission = Submission.objects.get(id=packet["submission-id"]) - except Submission.DoesNotExist: - logger.warning("Unknown submission: %s", packet["submission-id"]) - json_log.error( - self._make_json_log( - packet, action="grading-end", info="unknown submission" - ) - ) - return - - time = 0 - memory = 0 - points = 0.0 - total = 0 - status = 0 - status_codes = ["SC", "AC", "WA", "MLE", "TLE", "IR", "RTE", "OLE"] - batches = {} # batch number: (points, total) - - for case in SubmissionTestCase.objects.filter(submission=submission): - time += case.time - if not case.batch: - points += case.points - total += case.total - else: - if case.batch in batches: - batches[case.batch][0] += case.points - batches[case.batch][1] += case.total - else: - batches[case.batch] = [case.points, case.total] - memory = max(memory, case.memory) - i = status_codes.index(case.status) - if i > status: - status = i - - for i in batches: - points += batches[i][0] - total += batches[i][1] - - points = points - total = total - submission.case_points = points - submission.case_total = total - - problem = submission.problem - sub_points = round(points / total * problem.points if total > 0 else 0, 3) - if not problem.partial and sub_points != problem.points: - sub_points = 0 - - submission.status = "D" - submission.time = time - submission.memory = memory - submission.points = sub_points - submission.result = status_codes[status] - submission.save() - - json_log.info( - self._make_json_log( - packet, - action="grading-end", - time=time, - memory=memory, - points=sub_points, - total=problem.points, - result=submission.result, - case_points=points, - case_total=total, - user=submission.user_id, - problem=problem.code, - finish=True, - ) - ) - - submission.user._updating_stats_only = True - submission.user.calculate_points() - problem._updating_stats_only = True - problem.update_stats() - submission.update_contest() - - finished_submission(submission) - - event.post( - "sub_%s" % submission.id_secret, - { - "type": "grading-end", - "time": time, - "memory": memory, - "points": float(points), - "total": float(problem.points), - "result": submission.result, - }, - ) - if hasattr(submission, "contest"): - participation = submission.contest.participation - event.post("contest_%d" % participation.contest_id, {"type": "update"}) - self._post_update_submission(submission.id, "grading-end", done=True) - - def on_compile_error(self, packet): - logger.info( - "%s: Submission failed to compile: %s", self.name, packet["submission-id"] - ) - self._free_self(packet) - - if Submission.objects.filter(id=packet["submission-id"]).update( - status="CE", result="CE", error=packet["log"] - ): - event.post( - "sub_%s" % Submission.get_id_secret(packet["submission-id"]), - { - "type": "compile-error", - "log": packet["log"], - }, - ) - self._post_update_submission( - packet["submission-id"], "compile-error", done=True - ) - json_log.info( - self._make_json_log( - packet, - action="compile-error", - log=packet["log"], - finish=True, - result="CE", - ) - ) - else: - logger.warning("Unknown submission: %s", packet["submission-id"]) - json_log.error( - self._make_json_log( - packet, - action="compile-error", - info="unknown submission", - log=packet["log"], - finish=True, - result="CE", - ) - ) - - def on_compile_message(self, packet): - logger.info( - "%s: Submission generated compiler messages: %s", - self.name, - packet["submission-id"], - ) - - if Submission.objects.filter(id=packet["submission-id"]).update( - error=packet["log"] - ): - event.post( - "sub_%s" % Submission.get_id_secret(packet["submission-id"]), - {"type": "compile-message"}, - ) - json_log.info( - self._make_json_log(packet, action="compile-message", log=packet["log"]) - ) - else: - logger.warning("Unknown submission: %s", packet["submission-id"]) - json_log.error( - self._make_json_log( - packet, - action="compile-message", - info="unknown submission", - log=packet["log"], - ) - ) - - def on_internal_error(self, packet): - try: - raise ValueError("\n\n" + packet["message"]) - except ValueError: - logger.exception( - "Judge %s failed while handling submission %s", - self.name, - packet["submission-id"], - ) - self._free_self(packet) - - id = packet["submission-id"] - self._update_internal_error_submission(id, packet["message"]) - - def _update_internal_error_submission(self, id, message): - if Submission.objects.filter(id=id).update( - status="IE", result="IE", error=message - ): - event.post( - "sub_%s" % Submission.get_id_secret(id), {"type": "internal-error"} - ) - self._post_update_submission(id, "internal-error", done=True) - json_log.info( - self._make_json_log( - sub=id, - action="internal-error", - message=message, - finish=True, - result="IE", - ) - ) - else: - logger.warning("Unknown submission: %s", id) - json_log.error( - self._make_json_log( - sub=id, - action="internal-error", - info="unknown submission", - message=message, - finish=True, - result="IE", - ) - ) - - def on_submission_terminated(self, packet): - logger.info("%s: Submission aborted: %s", self.name, packet["submission-id"]) - self._free_self(packet) - - if Submission.objects.filter(id=packet["submission-id"]).update( - status="AB", result="AB" - ): - event.post( - "sub_%s" % Submission.get_id_secret(packet["submission-id"]), - {"type": "aborted-submission"}, - ) - self._post_update_submission( - packet["submission-id"], "terminated", done=True - ) - json_log.info( - self._make_json_log(packet, action="aborted", finish=True, result="AB") - ) - else: - logger.warning("Unknown submission: %s", packet["submission-id"]) - json_log.error( - self._make_json_log( - packet, - action="aborted", - info="unknown submission", - finish=True, - result="AB", - ) - ) - - def on_batch_begin(self, packet): - logger.info("%s: Batch began on: %s", self.name, packet["submission-id"]) - self.in_batch = True - if self.batch_id is None: - self.batch_id = 0 - self._submission_is_batch(packet["submission-id"]) - self.batch_id += 1 - - json_log.info( - self._make_json_log(packet, action="batch-begin", batch=self.batch_id) - ) - - def on_batch_end(self, packet): - self.in_batch = False - logger.info("%s: Batch ended on: %s", self.name, packet["submission-id"]) - json_log.info( - self._make_json_log(packet, action="batch-end", batch=self.batch_id) - ) - - def on_test_case( - self, - packet, - max_feedback=SubmissionTestCase._meta.get_field("feedback").max_length, - ): - logger.info( - "%s: %d test case(s) completed on: %s", - self.name, - len(packet["cases"]), - packet["submission-id"], - ) - - id = packet["submission-id"] - updates = packet["cases"] - max_position = max(map(itemgetter("position"), updates)) - sum_points = sum(map(itemgetter("points"), updates)) - - if not Submission.objects.filter(id=id).update( - current_testcase=max_position + 1, points=F("points") + sum_points - ): - logger.warning("Unknown submission: %s", id) - json_log.error( - self._make_json_log( - packet, action="test-case", info="unknown submission" - ) - ) - return - - bulk_test_case_updates = [] - for result in updates: - test_case = SubmissionTestCase(submission_id=id, case=result["position"]) - status = result["status"] - if status & 4: - test_case.status = "TLE" - elif status & 8: - test_case.status = "MLE" - elif status & 64: - test_case.status = "OLE" - elif status & 2: - test_case.status = "RTE" - elif status & 16: - test_case.status = "IR" - elif status & 1: - test_case.status = "WA" - elif status & 32: - test_case.status = "SC" - else: - test_case.status = "AC" - test_case.time = result["time"] - test_case.memory = result["memory"] - test_case.points = result["points"] - test_case.total = result["total-points"] - test_case.batch = self.batch_id if self.in_batch else None - test_case.feedback = (result.get("feedback") or "")[:max_feedback] - test_case.extended_feedback = result.get("extended-feedback") or "" - test_case.output = result["output"] - bulk_test_case_updates.append(test_case) - - json_log.info( - self._make_json_log( - packet, - action="test-case", - case=test_case.case, - batch=test_case.batch, - time=test_case.time, - memory=test_case.memory, - feedback=test_case.feedback, - extended_feedback=test_case.extended_feedback, - output=test_case.output, - points=test_case.points, - total=test_case.total, - status=test_case.status, - ) - ) - - do_post = True - - if id in self.update_counter: - cnt, reset = self.update_counter[id] - cnt += 1 - if time.monotonic() - reset > UPDATE_RATE_TIME: - del self.update_counter[id] - else: - self.update_counter[id] = (cnt, reset) - if cnt > UPDATE_RATE_LIMIT: - do_post = False - if id not in self.update_counter: - self.update_counter[id] = (1, time.monotonic()) - - if do_post: - event.post( - "sub_%s" % Submission.get_id_secret(id), - { - "type": "test-case", - "id": max_position, - }, - ) - self._post_update_submission(id, state="test-case") - - SubmissionTestCase.objects.bulk_create(bulk_test_case_updates) - - def on_malformed(self, packet): - logger.error("%s: Malformed packet: %s", self.name, packet) - json_log.exception( - self._make_json_log(sub=self._working, info="malformed json packet") - ) - - def on_ping_response(self, packet): - end = time.time() - self._ping_average.append(end - packet["when"]) - self._time_delta.append((end + packet["when"]) / 2 - packet["time"]) - self.latency = sum(self._ping_average) / len(self._ping_average) - self.time_delta = sum(self._time_delta) / len(self._time_delta) - self.load = packet["load"] - self._update_ping() - - def _free_self(self, packet): - self.judges.on_judge_free(self, packet["submission-id"]) - - def _ping_thread(self): - try: - while True: - self.ping() - if self._stop_ping.wait(10): - break - except Exception: - logger.exception("Ping error in %s", self.name) - self.close() - raise - - def _make_json_log(self, packet=None, sub=None, **kwargs): - data = { - "judge": self.name, - "address": self.judge_address, - } - if sub is None and packet is not None: - sub = packet.get("submission-id") - if sub is not None: - data["submission"] = sub - data.update(kwargs) - return json.dumps(data) - - def _post_update_submission(self, id, state, done=False): - if self._submission_cache_id == id: - data = self._submission_cache - else: - self._submission_cache = data = ( - Submission.objects.filter(id=id) - .values( - "problem__is_public", - "contest_object__key", - "user_id", - "problem_id", - "status", - "language__key", - ) - .get() - ) - self._submission_cache_id = id - - if data["problem__is_public"]: - event.post( - "submissions", - { - "type": "done-submission" if done else "update-submission", - "state": state, - "id": id, - "contest": data["contest_object__key"], - "user": data["user_id"], - "problem": data["problem_id"], - "status": data["status"], - "language": data["language__key"], - }, - ) - - def on_cleanup(self): - db.connection.close() - - -@cache_wrapper(prefix="gjp", timeout=3600) -def _get_judge_problems(judge): - return set(judge.problems.values_list("code", flat=True)) diff --git a/judge/bridge/judgecallback.py b/judge/bridge/judgecallback.py new file mode 100644 index 0000000..cba26a4 --- /dev/null +++ b/judge/bridge/judgecallback.py @@ -0,0 +1,411 @@ +import json +import logging +import time +from operator import itemgetter + +from django import db +from django.utils import timezone + +from judge import event_poster as event +from judge.caching import finished_submission +from judge.models import Judge, Language, LanguageLimit, Problem, RuntimeVersion, Submission, SubmissionTestCase +from .judgehandler import JudgeHandler, SubmissionData + +logger = logging.getLogger('judge.bridge') +json_log = logging.getLogger('judge.json.bridge') + +UPDATE_RATE_LIMIT = 5 +UPDATE_RATE_TIME = 0.5 + + +def _ensure_connection(): + try: + db.connection.cursor().execute('SELECT 1').fetchall() + except Exception: + db.connection.close() + + +class DjangoJudgeHandler(JudgeHandler): + def __init__(self, server, socket): + super(DjangoJudgeHandler, self).__init__(server, socket) + + # each value is (updates, last reset) + self.update_counter = {} + self.judge = None + self.judge_address = None + + self._submission_cache_id = None + self._submission_cache = {} + + json_log.info(self._make_json_log(action='connect')) + + def on_close(self): + super(DjangoJudgeHandler, self).on_close() + json_log.info(self._make_json_log(action='disconnect', info='judge disconnected')) + if self._working: + Submission.objects.filter(id=self._working).update(status='IE', result='IE') + json_log.error(self._make_json_log(sub=self._working, action='close', info='IE due to shutdown on grading')) + + def on_malformed(self, packet): + super(DjangoJudgeHandler, self).on_malformed(packet) + json_log.exception(self._make_json_log(sub=self._working, info='malformed zlib packet')) + + def _packet_exception(self): + json_log.exception(self._make_json_log(sub=self._working, info='packet processing exception')) + + def get_related_submission_data(self, submission): + _ensure_connection() # We are called from the django-facing daemon thread. Guess what happens. + + try: + pid, time, memory, short_circuit, lid, is_pretested, sub_date, uid, part_virtual, part_id = ( + Submission.objects.filter(id=submission) + .values_list('problem__id', 'problem__time_limit', 'problem__memory_limit', + 'problem__short_circuit', 'language__id', 'is_pretested', 'date', 'user__id', + 'contest__participation__virtual', 'contest__participation__id')).get() + except Submission.DoesNotExist: + logger.error('Submission vanished: %s', submission) + json_log.error(self._make_json_log( + sub=self._working, action='request', + info='submission vanished when fetching info', + )) + return + + attempt_no = Submission.objects.filter(problem__id=pid, contest__participation__id=part_id, user__id=uid, + date__lt=sub_date).exclude(status__in=('CE', 'IE')).count() + 1 + + try: + time, memory = (LanguageLimit.objects.filter(problem__id=pid, language__id=lid) + .values_list('time_limit', 'memory_limit').get()) + except LanguageLimit.DoesNotExist: + pass + + return SubmissionData( + time=time, + memory=memory, + short_circuit=short_circuit, + pretests_only=is_pretested, + contest_no=part_virtual, + attempt_no=attempt_no, + user_id=uid, + ) + + def _authenticate(self, id, key): + result = Judge.objects.filter(name=id, auth_key=key, is_blocked=False).exists() + if not result: + json_log.warning(self._make_json_log(action='auth', judge=id, info='judge failed authentication')) + return result + + def _connected(self): + judge = self.judge = Judge.objects.get(name=self.name) + judge.start_time = timezone.now() + judge.online = True + judge.problems.set(Problem.objects.filter(code__in=list(self.problems.keys()))) + judge.runtimes.set(Language.objects.filter(key__in=list(self.executors.keys()))) + + # Delete now in case we somehow crashed and left some over from the last connection + RuntimeVersion.objects.filter(judge=judge).delete() + versions = [] + for lang in judge.runtimes.all(): + versions += [ + RuntimeVersion(language=lang, name=name, version='.'.join(map(str, version)), priority=idx, judge=judge) + for idx, (name, version) in enumerate(self.executors[lang.key]) + ] + RuntimeVersion.objects.bulk_create(versions) + judge.last_ip = self.client_address[0] + judge.save() + self.judge_address = '[%s]:%s' % (self.client_address[0], self.client_address[1]) + json_log.info(self._make_json_log(action='auth', info='judge successfully authenticated', + executors=list(self.executors.keys()))) + + def _disconnected(self): + Judge.objects.filter(id=self.judge.id).update(online=False) + RuntimeVersion.objects.filter(judge=self.judge).delete() + + def _update_ping(self): + try: + Judge.objects.filter(name=self.name).update(ping=self.latency, load=self.load) + except Exception as e: + # What can I do? I don't want to tie this to MySQL. + if e.__class__.__name__ == 'OperationalError' and e.__module__ == '_mysql_exceptions' and e.args[0] == 2006: + db.connection.close() + + def _post_update_submission(self, id, state, done=False): + if self._submission_cache_id == id: + data = self._submission_cache + else: + self._submission_cache = data = Submission.objects.filter(id=id).values( + 'problem__is_public', 'contest__participation__contest__key', + 'user_id', 'problem_id', 'status', 'language__key', + ).get() + self._submission_cache_id = id + + if data['problem__is_public']: + event.post('submissions', { + 'type': 'done-submission' if done else 'update-submission', + 'state': state, 'id': id, + 'contest': data['contest__participation__contest__key'], + 'user': data['user_id'], 'problem': data['problem_id'], + 'status': data['status'], 'language': data['language__key'], + }) + + def on_submission_processing(self, packet): + id = packet['submission-id'] + if Submission.objects.filter(id=id).update(status='P', judged_on=self.judge): + event.post('sub_%s' % Submission.get_id_secret(id), {'type': 'processing'}) + self._post_update_submission(id, 'processing') + json_log.info(self._make_json_log(packet, action='processing')) + else: + logger.warning('Unknown submission: %s', id) + json_log.error(self._make_json_log(packet, action='processing', info='unknown submission')) + + def on_submission_wrong_acknowledge(self, packet, expected, got): + json_log.error(self._make_json_log(packet, action='processing', info='wrong-acknowledge', expected=expected)) + + def on_grading_begin(self, packet): + super(DjangoJudgeHandler, self).on_grading_begin(packet) + if Submission.objects.filter(id=packet['submission-id']).update( + status='G', is_pretested=packet['pretested'], + current_testcase=1, batch=False): + SubmissionTestCase.objects.filter(submission_id=packet['submission-id']).delete() + event.post('sub_%s' % Submission.get_id_secret(packet['submission-id']), {'type': 'grading-begin'}) + self._post_update_submission(packet['submission-id'], 'grading-begin') + json_log.info(self._make_json_log(packet, action='grading-begin')) + else: + logger.warning('Unknown submission: %s', packet['submission-id']) + json_log.error(self._make_json_log(packet, action='grading-begin', info='unknown submission')) + + def _submission_is_batch(self, id): + if not Submission.objects.filter(id=id).update(batch=True): + logger.warning('Unknown submission: %s', id) + + def on_grading_end(self, packet): + super(DjangoJudgeHandler, self).on_grading_end(packet) + + try: + submission = Submission.objects.get(id=packet['submission-id']) + except Submission.DoesNotExist: + logger.warning('Unknown submission: %s', packet['submission-id']) + json_log.error(self._make_json_log(packet, action='grading-end', info='unknown submission')) + return + + time = 0 + memory = 0 + points = 0.0 + total = 0 + status = 0 + status_codes = ['SC', 'AC', 'WA', 'MLE', 'TLE', 'IR', 'RTE', 'OLE'] + batches = {} # batch number: (points, total) + + for case in SubmissionTestCase.objects.filter(submission=submission): + time += case.time + if not case.batch: + points += case.points + total += case.total + else: + if case.batch in batches: + batches[case.batch][0] = min(batches[case.batch][0], case.points) + batches[case.batch][1] = max(batches[case.batch][1], case.total) + else: + batches[case.batch] = [case.points, case.total] + memory = max(memory, case.memory) + i = status_codes.index(case.status) + if i > status: + status = i + + for i in batches: + points += batches[i][0] + total += batches[i][1] + + points = round(points, 1) + total = round(total, 1) + submission.case_points = points + submission.case_total = total + + problem = submission.problem + sub_points = round(points / total * problem.points if total > 0 else 0, 3) + if not problem.partial and sub_points != problem.points: + sub_points = 0 + + submission.status = 'D' + submission.time = time + submission.memory = memory + submission.points = sub_points + submission.result = status_codes[status] + submission.save() + + json_log.info(self._make_json_log( + packet, action='grading-end', time=time, memory=memory, + points=sub_points, total=problem.points, result=submission.result, + case_points=points, case_total=total, user=submission.user_id, + problem=problem.code, finish=True, + )) + + submission.user._updating_stats_only = True + submission.user.calculate_points() + problem._updating_stats_only = True + problem.update_stats() + submission.update_contest() + + finished_submission(submission) + + event.post('sub_%s' % submission.id_secret, { + 'type': 'grading-end', + 'time': time, + 'memory': memory, + 'points': float(points), + 'total': float(problem.points), + 'result': submission.result, + }) + if hasattr(submission, 'contest'): + participation = submission.contest.participation + event.post('contest_%d' % participation.contest_id, {'type': 'update'}) + self._post_update_submission(submission.id, 'grading-end', done=True) + + def on_compile_error(self, packet): + super(DjangoJudgeHandler, self).on_compile_error(packet) + + if Submission.objects.filter(id=packet['submission-id']).update(status='CE', result='CE', error=packet['log']): + event.post('sub_%s' % Submission.get_id_secret(packet['submission-id']), { + 'type': 'compile-error', + 'log': packet['log'], + }) + self._post_update_submission(packet['submission-id'], 'compile-error', done=True) + json_log.info(self._make_json_log(packet, action='compile-error', log=packet['log'], + finish=True, result='CE')) + else: + logger.warning('Unknown submission: %s', packet['submission-id']) + json_log.error(self._make_json_log(packet, action='compile-error', info='unknown submission', + log=packet['log'], finish=True, result='CE')) + + def on_compile_message(self, packet): + super(DjangoJudgeHandler, self).on_compile_message(packet) + + if Submission.objects.filter(id=packet['submission-id']).update(error=packet['log']): + event.post('sub_%s' % Submission.get_id_secret(packet['submission-id']), {'type': 'compile-message'}) + json_log.info(self._make_json_log(packet, action='compile-message', log=packet['log'])) + else: + logger.warning('Unknown submission: %s', packet['submission-id']) + json_log.error(self._make_json_log(packet, action='compile-message', info='unknown submission', + log=packet['log'])) + + def on_internal_error(self, packet): + super(DjangoJudgeHandler, self).on_internal_error(packet) + + id = packet['submission-id'] + if Submission.objects.filter(id=id).update(status='IE', result='IE', error=packet['message']): + event.post('sub_%s' % Submission.get_id_secret(id), {'type': 'internal-error'}) + self._post_update_submission(id, 'internal-error', done=True) + json_log.info(self._make_json_log(packet, action='internal-error', message=packet['message'], + finish=True, result='IE')) + else: + logger.warning('Unknown submission: %s', id) + json_log.error(self._make_json_log(packet, action='internal-error', info='unknown submission', + message=packet['message'], finish=True, result='IE')) + + def on_submission_terminated(self, packet): + super(DjangoJudgeHandler, self).on_submission_terminated(packet) + + if Submission.objects.filter(id=packet['submission-id']).update(status='AB', result='AB'): + event.post('sub_%s' % Submission.get_id_secret(packet['submission-id']), {'type': 'aborted-submission'}) + self._post_update_submission(packet['submission-id'], 'terminated', done=True) + json_log.info(self._make_json_log(packet, action='aborted', finish=True, result='AB')) + else: + logger.warning('Unknown submission: %s', packet['submission-id']) + json_log.error(self._make_json_log(packet, action='aborted', info='unknown submission', + finish=True, result='AB')) + + def on_batch_begin(self, packet): + super(DjangoJudgeHandler, self).on_batch_begin(packet) + json_log.info(self._make_json_log(packet, action='batch-begin', batch=self.batch_id)) + + def on_batch_end(self, packet): + super(DjangoJudgeHandler, self).on_batch_end(packet) + json_log.info(self._make_json_log(packet, action='batch-end', batch=self.batch_id)) + + def on_test_case(self, packet, max_feedback=SubmissionTestCase._meta.get_field('feedback').max_length): + super(DjangoJudgeHandler, self).on_test_case(packet) + id = packet['submission-id'] + updates = packet['cases'] + max_position = max(map(itemgetter('position'), updates)) + + if not Submission.objects.filter(id=id).update(current_testcase=max_position + 1): + logger.warning('Unknown submission: %s', id) + json_log.error(self._make_json_log(packet, action='test-case', info='unknown submission')) + return + + bulk_test_case_updates = [] + for result in updates: + test_case = SubmissionTestCase(submission_id=id, case=result['position']) + status = result['status'] + if status & 4: + test_case.status = 'TLE' + elif status & 8: + test_case.status = 'MLE' + elif status & 64: + test_case.status = 'OLE' + elif status & 2: + test_case.status = 'RTE' + elif status & 16: + test_case.status = 'IR' + elif status & 1: + test_case.status = 'WA' + elif status & 32: + test_case.status = 'SC' + else: + test_case.status = 'AC' + test_case.time = result['time'] + test_case.memory = result['memory'] + test_case.points = result['points'] + test_case.total = result['total-points'] + test_case.batch = self.batch_id if self.in_batch else None + test_case.feedback = (result.get('feedback') or '')[:max_feedback] + test_case.extended_feedback = result.get('extended-feedback') or '' + test_case.output = result['output'] + bulk_test_case_updates.append(test_case) + + json_log.info(self._make_json_log( + packet, action='test-case', case=test_case.case, batch=test_case.batch, + time=test_case.time, memory=test_case.memory, feedback=test_case.feedback, + extended_feedback=test_case.extended_feedback, output=test_case.output, + points=test_case.points, total=test_case.total, status=test_case.status, + )) + + do_post = True + + if id in self.update_counter: + cnt, reset = self.update_counter[id] + cnt += 1 + if time.monotonic() - reset > UPDATE_RATE_TIME: + del self.update_counter[id] + else: + self.update_counter[id] = (cnt, reset) + if cnt > UPDATE_RATE_LIMIT: + do_post = False + if id not in self.update_counter: + self.update_counter[id] = (1, time.monotonic()) + + if do_post: + event.post('sub_%s' % Submission.get_id_secret(id), { + 'type': 'test-case', + 'id': max_position, + }) + self._post_update_submission(id, state='test-case') + + SubmissionTestCase.objects.bulk_create(bulk_test_case_updates) + + def on_supported_problems(self, packet): + super(DjangoJudgeHandler, self).on_supported_problems(packet) + self.judge.problems.set(Problem.objects.filter(code__in=list(self.problems.keys()))) + json_log.info(self._make_json_log(action='update-problems', count=len(self.problems))) + + def _make_json_log(self, packet=None, sub=None, **kwargs): + data = { + 'judge': self.name, + 'address': self.judge_address, + } + if sub is None and packet is not None: + sub = packet.get('submission-id') + if sub is not None: + data['submission'] = sub + data.update(kwargs) + return json.dumps(data) diff --git a/judge/bridge/judgehandler.py b/judge/bridge/judgehandler.py new file mode 100644 index 0000000..2a09218 --- /dev/null +++ b/judge/bridge/judgehandler.py @@ -0,0 +1,268 @@ +import json +import logging +import time +from collections import deque, namedtuple + +from event_socket_server import ProxyProtocolMixin, ZlibPacketHandler + +logger = logging.getLogger('judge.bridge') + +SubmissionData = namedtuple('SubmissionData', 'time memory short_circuit pretests_only contest_no attempt_no user_id') + + +class JudgeHandler(ProxyProtocolMixin, ZlibPacketHandler): + def __init__(self, server, socket): + super(JudgeHandler, self).__init__(server, socket) + + self.handlers = { + 'grading-begin': self.on_grading_begin, + 'grading-end': self.on_grading_end, + 'compile-error': self.on_compile_error, + 'compile-message': self.on_compile_message, + 'batch-begin': self.on_batch_begin, + 'batch-end': self.on_batch_end, + 'test-case-status': self.on_test_case, + 'internal-error': self.on_internal_error, + 'submission-terminated': self.on_submission_terminated, + 'submission-acknowledged': self.on_submission_acknowledged, + 'ping-response': self.on_ping_response, + 'supported-problems': self.on_supported_problems, + 'handshake': self.on_handshake, + } + self._to_kill = True + self._working = False + self._no_response_job = None + self._problems = [] + self.executors = [] + self.problems = {} + self.latency = None + self.time_delta = None + self.load = 1e100 + self.name = None + self.batch_id = None + self.in_batch = False + self._ping_average = deque(maxlen=6) # 1 minute average, just like load + self._time_delta = deque(maxlen=6) + + self.server.schedule(15, self._kill_if_no_auth) + logger.info('Judge connected from: %s', self.client_address) + + def _kill_if_no_auth(self): + if self._to_kill: + logger.info('Judge not authenticated: %s', self.client_address) + self.close() + + def on_close(self): + self._to_kill = False + if self._no_response_job: + self.server.unschedule(self._no_response_job) + self.server.judges.remove(self) + if self.name is not None: + self._disconnected() + logger.info('Judge disconnected from: %s', self.client_address) + + def _authenticate(self, id, key): + return False + + def _connected(self): + pass + + def _disconnected(self): + pass + + def _update_ping(self): + pass + + def _format_send(self, data): + return super(JudgeHandler, self)._format_send(json.dumps(data, separators=(',', ':'))) + + def on_handshake(self, packet): + if 'id' not in packet or 'key' not in packet: + logger.warning('Malformed handshake: %s', self.client_address) + self.close() + return + + if not self._authenticate(packet['id'], packet['key']): + logger.warning('Authentication failure: %s', self.client_address) + self.close() + return + + self._to_kill = False + self._problems = packet['problems'] + self.problems = dict(self._problems) + self.executors = packet['executors'] + self.name = packet['id'] + + self.send({'name': 'handshake-success'}) + logger.info('Judge authenticated: %s (%s)', self.client_address, packet['id']) + self.server.judges.register(self) + self._connected() + + def can_judge(self, problem, executor): + return problem in self.problems and executor in self.executors + + @property + def working(self): + return bool(self._working) + + def get_related_submission_data(self, submission): + return SubmissionData( + time=2, + memory=16384, + short_circuit=False, + pretests_only=False, + contest_no=None, + attempt_no=1, + user_id=None, + ) + + def disconnect(self, force=False): + if force: + # Yank the power out. + self.close() + else: + self.send({'name': 'disconnect'}) + + def submit(self, id, problem, language, source): + data = self.get_related_submission_data(id) + self._working = id + self._no_response_job = self.server.schedule(20, self._kill_if_no_response) + self.send({ + 'name': 'submission-request', + 'submission-id': id, + 'problem-id': problem, + 'language': language, + 'source': source, + 'time-limit': data.time, + 'memory-limit': data.memory, + 'short-circuit': data.short_circuit, + 'meta': { + 'pretests-only': data.pretests_only, + 'in-contest': data.contest_no, + 'attempt-no': data.attempt_no, + 'user': data.user_id, + }, + }) + + def _kill_if_no_response(self): + logger.error('Judge seems dead: %s: %s', self.name, self._working) + self.close() + + def malformed_packet(self, exception): + logger.exception('Judge sent malformed packet: %s', self.name) + super(JudgeHandler, self).malformed_packet(exception) + + def on_submission_processing(self, packet): + pass + + def on_submission_wrong_acknowledge(self, packet, expected, got): + pass + + def on_submission_acknowledged(self, packet): + if not packet.get('submission-id', None) == self._working: + logger.error('Wrong acknowledgement: %s: %s, expected: %s', self.name, packet.get('submission-id', None), + self._working) + self.on_submission_wrong_acknowledge(packet, self._working, packet.get('submission-id', None)) + self.close() + logger.info('Submission acknowledged: %d', self._working) + if self._no_response_job: + self.server.unschedule(self._no_response_job) + self._no_response_job = None + self.on_submission_processing(packet) + + def abort(self): + self.send({'name': 'terminate-submission'}) + + def get_current_submission(self): + return self._working or None + + def ping(self): + self.send({'name': 'ping', 'when': time.time()}) + + def packet(self, data): + try: + try: + data = json.loads(data) + if 'name' not in data: + raise ValueError + except ValueError: + self.on_malformed(data) + else: + handler = self.handlers.get(data['name'], self.on_malformed) + handler(data) + except Exception: + logger.exception('Error in packet handling (Judge-side): %s', self.name) + self._packet_exception() + # You can't crash here because you aren't so sure about the judges + # not being malicious or simply malforms. THIS IS A SERVER! + + def _packet_exception(self): + pass + + def _submission_is_batch(self, id): + pass + + def on_supported_problems(self, packet): + logger.info('%s: Updated problem list', self.name) + self._problems = packet['problems'] + self.problems = dict(self._problems) + if not self.working: + self.server.judges.update_problems(self) + + def on_grading_begin(self, packet): + logger.info('%s: Grading has begun on: %s', self.name, packet['submission-id']) + self.batch_id = None + + def on_grading_end(self, packet): + logger.info('%s: Grading has ended on: %s', self.name, packet['submission-id']) + self._free_self(packet) + self.batch_id = None + + def on_compile_error(self, packet): + logger.info('%s: Submission failed to compile: %s', self.name, packet['submission-id']) + self._free_self(packet) + + def on_compile_message(self, packet): + logger.info('%s: Submission generated compiler messages: %s', self.name, packet['submission-id']) + + def on_internal_error(self, packet): + try: + raise ValueError('\n\n' + packet['message']) + except ValueError: + logger.exception('Judge %s failed while handling submission %s', self.name, packet['submission-id']) + self._free_self(packet) + + def on_submission_terminated(self, packet): + logger.info('%s: Submission aborted: %s', self.name, packet['submission-id']) + self._free_self(packet) + + def on_batch_begin(self, packet): + logger.info('%s: Batch began on: %s', self.name, packet['submission-id']) + self.in_batch = True + if self.batch_id is None: + self.batch_id = 0 + self._submission_is_batch(packet['submission-id']) + self.batch_id += 1 + + def on_batch_end(self, packet): + self.in_batch = False + logger.info('%s: Batch ended on: %s', self.name, packet['submission-id']) + + def on_test_case(self, packet): + logger.info('%s: %d test case(s) completed on: %s', self.name, len(packet['cases']), packet['submission-id']) + + def on_malformed(self, packet): + logger.error('%s: Malformed packet: %s', self.name, packet) + + def on_ping_response(self, packet): + end = time.time() + self._ping_average.append(end - packet['when']) + self._time_delta.append((end + packet['when']) / 2 - packet['time']) + self.latency = sum(self._ping_average) / len(self._ping_average) + self.time_delta = sum(self._time_delta) / len(self._time_delta) + self.load = packet['load'] + self._update_ping() + + def _free_self(self, packet): + self._working = False + self.server.judges.on_judge_free(self, packet['submission-id']) diff --git a/judge/bridge/judge_list.py b/judge/bridge/judgelist.py similarity index 56% rename from judge/bridge/judge_list.py rename to judge/bridge/judgelist.py index bf2b54a..ec3cebd 100644 --- a/judge/bridge/judge_list.py +++ b/judge/bridge/judgelist.py @@ -3,16 +3,14 @@ from collections import namedtuple from operator import attrgetter from threading import RLock -from judge.bridge.utils import VanishedSubmission - try: from llist import dllist except ImportError: from pyllist import dllist -logger = logging.getLogger("judge.bridge") +logger = logging.getLogger('judge.bridge') -PriorityMarker = namedtuple("PriorityMarker", "priority") +PriorityMarker = namedtuple('PriorityMarker', 'priority') class JudgeList(object): @@ -20,9 +18,7 @@ class JudgeList(object): def __init__(self): self.queue = dllist() - self.priority = [ - self.queue.append(PriorityMarker(i)) for i in range(self.priorities) - ] + self.priority = [self.queue.append(PriorityMarker(i)) for i in range(self.priorities)] self.judges = set() self.node_map = {} self.submission_map = {} @@ -33,24 +29,14 @@ class JudgeList(object): node = self.queue.first while node: if not isinstance(node.value, PriorityMarker): - id, problem, language, source, judge_id = node.value - if judge.can_judge(problem, language, judge_id): + id, problem, language, source = node.value + if judge.can_judge(problem, language): self.submission_map[id] = judge - logger.info( - "Dispatched queued submission %d: %s", id, judge.name - ) + logger.info('Dispatched queued submission %d: %s', id, judge.name) try: judge.submit(id, problem, language, source) - except VanishedSubmission: - pass except Exception: - logger.exception( - "Failed to dispatch %d (%s, %s) to %s", - id, - problem, - language, - judge.name, - ) + logger.exception('Failed to dispatch %d (%s, %s) to %s', id, problem, language, judge.name) self.judges.remove(judge) return self.queue.remove(node) @@ -66,10 +52,9 @@ class JudgeList(object): self._handle_free_judge(judge) def disconnect(self, judge_id, force=False): - with self.lock: - for judge in self.judges: - if judge.name == judge_id: - judge.disconnect(force=force) + for judge in self.judges: + if judge.name == judge_id: + judge.disconnect(force=force) def update_problems(self, judge): with self.lock: @@ -90,15 +75,13 @@ class JudgeList(object): def on_judge_free(self, judge, submission): with self.lock: - logger.info("Judge available after grading %d: %s", submission, judge.name) + logger.info('Judge available after grading %d: %s', submission, judge.name) del self.submission_map[submission] - judge._working = False - judge._working_data = {} self._handle_free_judge(judge) def abort(self, submission): with self.lock: - logger.info("Abort request: %d", submission) + logger.info('Abort request: %d', submission) try: self.submission_map[submission].abort() return True @@ -115,46 +98,26 @@ class JudgeList(object): def check_priority(self, priority): return 0 <= priority < self.priorities - def judge(self, id, problem, language, source, judge_id, priority): + def judge(self, id, problem, language, source, priority): with self.lock: if id in self.submission_map or id in self.node_map: # Already judging, don't queue again. This can happen during batch rejudges, rejudges should be # idempotent. return - candidates = [ - judge - for judge in self.judges - if not judge.working and judge.can_judge(problem, language, judge_id) - ] - if judge_id: - logger.info( - "Specified judge %s is%savailable", - judge_id, - " " if candidates else " not ", - ) - else: - logger.info("Free judges: %d", len(candidates)) + candidates = [judge for judge in self.judges if not judge.working and judge.can_judge(problem, language)] + logger.info('Free judges: %d', len(candidates)) if candidates: # Schedule the submission on the judge reporting least load. - judge = min(candidates, key=attrgetter("load")) - logger.info("Dispatched submission %d to: %s", id, judge.name) + judge = min(candidates, key=attrgetter('load')) + logger.info('Dispatched submission %d to: %s', id, judge.name) self.submission_map[id] = judge try: judge.submit(id, problem, language, source) except Exception: - logger.exception( - "Failed to dispatch %d (%s, %s) to %s", - id, - problem, - language, - judge.name, - ) + logger.exception('Failed to dispatch %d (%s, %s) to %s', id, problem, language, judge.name) self.judges.discard(judge) - return self.judge(id, problem, language, source, judge_id, priority) + return self.judge(id, problem, language, source, priority) else: - self.node_map[id] = self.queue.insert( - (id, problem, language, source, judge_id), - self.priority[priority], - ) - logger.info("Queued submission: %d", id) + self.node_map[id] = self.queue.insert((id, problem, language, source), self.priority[priority]) + logger.info('Queued submission: %d', id) diff --git a/judge/bridge/judgeserver.py b/judge/bridge/judgeserver.py new file mode 100644 index 0000000..251a431 --- /dev/null +++ b/judge/bridge/judgeserver.py @@ -0,0 +1,68 @@ +import logging +import os +import threading +import time + +from event_socket_server import get_preferred_engine +from judge.models import Judge +from .judgelist import JudgeList + +logger = logging.getLogger('judge.bridge') + + +def reset_judges(): + Judge.objects.update(online=False, ping=None, load=None) + + +class JudgeServer(get_preferred_engine()): + def __init__(self, *args, **kwargs): + super(JudgeServer, self).__init__(*args, **kwargs) + reset_judges() + self.judges = JudgeList() + self.ping_judge_thread = threading.Thread(target=self.ping_judge, args=()) + self.ping_judge_thread.daemon = True + self.ping_judge_thread.start() + + def on_shutdown(self): + super(JudgeServer, self).on_shutdown() + reset_judges() + + def ping_judge(self): + try: + while True: + for judge in self.judges: + judge.ping() + time.sleep(10) + except Exception: + logger.exception('Ping error') + raise + + +def main(): + import argparse + import logging + from .judgehandler import JudgeHandler + + format = '%(asctime)s:%(levelname)s:%(name)s:%(message)s' + logging.basicConfig(format=format) + logging.getLogger().setLevel(logging.INFO) + handler = logging.FileHandler(os.path.join(os.path.dirname(__file__), 'judgeserver.log'), encoding='utf-8') + handler.setFormatter(logging.Formatter(format)) + handler.setLevel(logging.INFO) + logging.getLogger().addHandler(handler) + + parser = argparse.ArgumentParser(description=''' + Runs the bridge between DMOJ website and judges. + ''') + parser.add_argument('judge_host', nargs='+', action='append', + help='host to listen for the judge') + parser.add_argument('-p', '--judge-port', type=int, action='append', + help='port to listen for the judge') + + args = parser.parse_args() + server = JudgeServer(list(zip(args.judge_host, args.judge_port)), JudgeHandler) + server.serve_forever() + + +if __name__ == '__main__': + main() diff --git a/judge/bridge/server.py b/judge/bridge/server.py deleted file mode 100644 index 4e67310..0000000 --- a/judge/bridge/server.py +++ /dev/null @@ -1,32 +0,0 @@ -import threading -from socketserver import TCPServer, ThreadingMixIn - - -class ThreadingTCPListener(ThreadingMixIn, TCPServer): - allow_reuse_address = True - - -class Server: - def __init__(self, addresses, handler): - self.servers = [ThreadingTCPListener(address, handler) for address in addresses] - self._shutdown = threading.Event() - - def serve_forever(self): - threads = [ - threading.Thread(target=server.serve_forever) for server in self.servers - ] - for thread in threads: - thread.daemon = True - thread.start() - try: - self._shutdown.wait() - except KeyboardInterrupt: - self.shutdown() - finally: - for thread in threads: - thread.join() - - def shutdown(self): - for server in self.servers: - server.shutdown() - self._shutdown.set() diff --git a/judge/bridge/utils.py b/judge/bridge/utils.py deleted file mode 100644 index dfb2ac9..0000000 --- a/judge/bridge/utils.py +++ /dev/null @@ -1,2 +0,0 @@ -class VanishedSubmission(Exception): - pass diff --git a/judge/caching.py b/judge/caching.py index f40adb1..7f0a687 100644 --- a/judge/caching.py +++ b/judge/caching.py @@ -1,117 +1,10 @@ -from inspect import signature -from django.core.cache import cache, caches -from django.db.models.query import QuerySet -from django.core.handlers.wsgi import WSGIRequest - -import hashlib - -from judge.logging import log_debug - -MAX_NUM_CHAR = 50 -NONE_RESULT = "__None__" +from django.core.cache import cache -def arg_to_str(arg): - if hasattr(arg, "id"): - return str(arg.id) - if isinstance(arg, list) or isinstance(arg, QuerySet): - return hashlib.sha1(str(list(arg)).encode()).hexdigest()[:MAX_NUM_CHAR] - if len(str(arg)) > MAX_NUM_CHAR: - return str(arg)[:MAX_NUM_CHAR] - return str(arg) - - -def filter_args(args_list): - return [x for x in args_list if not isinstance(x, WSGIRequest)] - - -l0_cache = caches["l0"] if "l0" in caches else None - - -def cache_wrapper(prefix, timeout=None, expected_type=None): - def get_key(func, *args, **kwargs): - args_list = list(args) - signature_args = list(signature(func).parameters.keys()) - args_list += [kwargs.get(k) for k in signature_args[len(args) :]] - args_list = filter_args(args_list) - args_list = [arg_to_str(i) for i in args_list] - key = prefix + ":" + ":".join(args_list) - key = key.replace(" ", "_") - return key - - def _get(key): - if not l0_cache: - return cache.get(key) - result = l0_cache.get(key) - if result is None: - result = cache.get(key) - return result - - def _set_l0(key, value): - if l0_cache: - l0_cache.set(key, value, 30) - - def _set(key, value, timeout): - _set_l0(key, value) - cache.set(key, value, timeout) - - def decorator(func): - def _validate_type(cache_key, result): - if expected_type and not isinstance(result, expected_type): - data = { - "function": f"{func.__module__}.{func.__qualname__}", - "result": str(result)[:30], - "expected_type": expected_type, - "type": type(result), - "key": cache_key, - } - log_debug("invalid_key", data) - return False - return True - - def wrapper(*args, **kwargs): - cache_key = get_key(func, *args, **kwargs) - result = _get(cache_key) - if result is not None and _validate_type(cache_key, result): - _set_l0(cache_key, result) - if type(result) == str and result == NONE_RESULT: - result = None - return result - result = func(*args, **kwargs) - if result is None: - cache_result = NONE_RESULT - else: - cache_result = result - _set(cache_key, cache_result, timeout) - return result - - def dirty(*args, **kwargs): - cache_key = get_key(func, *args, **kwargs) - cache.delete(cache_key) - if l0_cache: - l0_cache.delete(cache_key) - - def prefetch_multi(args_list): - keys = [] - for args in args_list: - keys.append(get_key(func, *args)) - results = cache.get_many(keys) - for key, result in results.items(): - if result is not None: - _set_l0(key, result) - - def dirty_multi(args_list): - keys = [] - for args in args_list: - keys.append(get_key(func, *args)) - cache.delete_many(keys) - if l0_cache: - l0_cache.delete_many(keys) - - wrapper.dirty = dirty - wrapper.prefetch_multi = prefetch_multi - wrapper.dirty_multi = dirty_multi - - return wrapper - - return decorator +def finished_submission(sub): + keys = ['user_complete:%d' % sub.user_id, 'user_attempted:%s' % sub.user_id] + if hasattr(sub, 'contest'): + participation = sub.contest.participation + keys += ['contest_complete:%d' % participation.id] + keys += ['contest_attempted:%d' % participation.id] + cache.delete_many(keys) diff --git a/judge/comments.py b/judge/comments.py new file mode 100644 index 0000000..4444755 --- /dev/null +++ b/judge/comments.py @@ -0,0 +1,122 @@ +from django import forms +from django.conf import settings +from django.contrib.auth.decorators import login_required +from django.contrib.contenttypes.models import ContentType +from django.core.exceptions import ValidationError +from django.db.models import Count +from django.db.models.expressions import F, Value +from django.db.models.functions import Coalesce +from django.forms import ModelForm +from django.http import HttpResponseForbidden, HttpResponseNotFound, HttpResponseRedirect +from django.urls import reverse_lazy +from django.utils.decorators import method_decorator +from django.utils.translation import gettext as _ +from django.views.generic import View +from django.views.generic.base import TemplateResponseMixin +from django.views.generic.detail import SingleObjectMixin +from reversion import revisions +from reversion.models import Revision, Version + +from judge.dblock import LockModel +from judge.models import Comment, CommentLock, CommentVote +from judge.utils.raw_sql import RawSQLColumn, unique_together_left_join +from judge.widgets import HeavyPreviewPageDownWidget + + +class CommentForm(ModelForm): + class Meta: + model = Comment + fields = ['body', 'parent'] + widgets = { + 'parent': forms.HiddenInput(), + } + + if HeavyPreviewPageDownWidget is not None: + widgets['body'] = HeavyPreviewPageDownWidget(preview=reverse_lazy('comment_preview'), + preview_timeout=1000, hide_preview_button=True) + + def __init__(self, request, *args, **kwargs): + self.request = request + super(CommentForm, self).__init__(*args, **kwargs) + self.fields['body'].widget.attrs.update({'placeholder': _('Comment body')}) + + def clean(self): + if self.request is not None and self.request.user.is_authenticated: + profile = self.request.profile + if profile.mute: + raise ValidationError(_('Your part is silent, little toad.')) + elif (not self.request.user.is_staff and + not profile.submission_set.filter(points=F('problem__points')).exists()): + raise ValidationError(_('You need to have solved at least one problem ' + 'before your voice can be heard.')) + return super(CommentForm, self).clean() + + +class CommentedDetailView(TemplateResponseMixin, SingleObjectMixin, View): + comment_page = None + + def get_comment_page(self): + if self.comment_page is None: + raise NotImplementedError() + return self.comment_page + + def is_comment_locked(self): + return (CommentLock.objects.filter(page=self.get_comment_page()).exists() and + not self.request.user.has_perm('judge.override_comment_lock')) + + @method_decorator(login_required) + def post(self, request, *args, **kwargs): + self.object = self.get_object() + page = self.get_comment_page() + + if self.is_comment_locked(): + return HttpResponseForbidden() + + parent = request.POST.get('parent') + if parent: + try: + parent = int(parent) + except ValueError: + return HttpResponseNotFound() + else: + if not Comment.objects.filter(hidden=False, id=parent, page=page).exists(): + return HttpResponseNotFound() + + form = CommentForm(request, request.POST) + if form.is_valid(): + comment = form.save(commit=False) + comment.author = request.profile + comment.page = page + with LockModel(write=(Comment, Revision, Version), read=(ContentType,)), revisions.create_revision(): + revisions.set_user(request.user) + revisions.set_comment(_('Posted comment')) + comment.save() + return HttpResponseRedirect(request.path) + + context = self.get_context_data(object=self.object, comment_form=form) + return self.render_to_response(context) + + def get(self, request, *args, **kwargs): + self.object = self.get_object() + return self.render_to_response(self.get_context_data( + object=self.object, + comment_form=CommentForm(request, initial={'page': self.get_comment_page(), 'parent': None}), + )) + + def get_context_data(self, **kwargs): + context = super(CommentedDetailView, self).get_context_data(**kwargs) + queryset = Comment.objects.filter(hidden=False, page=self.get_comment_page()) + context['has_comments'] = queryset.exists() + context['comment_lock'] = self.is_comment_locked() + queryset = queryset.select_related('author__user').defer('author__about').annotate(revisions=Count('versions')) + + if self.request.user.is_authenticated: + queryset = queryset.annotate(vote_score=Coalesce(RawSQLColumn(CommentVote, 'score'), Value(0))) + profile = self.request.profile + unique_together_left_join(queryset, CommentVote, 'comment', 'voter', profile.id) + context['is_new_user'] = (not self.request.user.is_staff and + not profile.submission_set.filter(points=F('problem__points')).exists()) + context['comment_list'] = queryset + context['vote_hide_threshold'] = settings.DMOJ_COMMENT_VOTE_HIDE_THRESHOLD + + return context diff --git a/judge/contest_format/__init__.py b/judge/contest_format/__init__.py index 9f6d628..c602e4d 100644 --- a/judge/contest_format/__init__.py +++ b/judge/contest_format/__init__.py @@ -1,8 +1,5 @@ from judge.contest_format.atcoder import AtCoderContestFormat from judge.contest_format.default import DefaultContestFormat from judge.contest_format.ecoo import ECOOContestFormat -from judge.contest_format.icpc import ICPCContestFormat from judge.contest_format.ioi import IOIContestFormat -from judge.contest_format.new_ioi import NewIOIContestFormat -from judge.contest_format.ultimate import UltimateContestFormat from judge.contest_format.registry import choices, formats diff --git a/judge/contest_format/atcoder.py b/judge/contest_format/atcoder.py index 65ceb90..7a1ae8c 100644 --- a/judge/contest_format/atcoder.py +++ b/judge/contest_format/atcoder.py @@ -10,18 +10,18 @@ from django.utils.translation import gettext_lazy from judge.contest_format.default import DefaultContestFormat from judge.contest_format.registry import register_contest_format -from judge.timezone import from_database_time, to_database_time +from judge.timezone import from_database_time from judge.utils.timedelta import nice_repr -@register_contest_format("atcoder") +@register_contest_format('atcoder') class AtCoderContestFormat(DefaultContestFormat): - name = gettext_lazy("AtCoder") - config_defaults = {"penalty": 5} - config_validators = {"penalty": lambda x: x >= 0} - """ + name = gettext_lazy('AtCoder') + config_defaults = {'penalty': 5} + config_validators = {'penalty': lambda x: x >= 0} + ''' penalty: Number of penalty minutes each incorrect submission adds. Defaults to 5. - """ + ''' @classmethod def validate(cls, config): @@ -29,9 +29,7 @@ class AtCoderContestFormat(DefaultContestFormat): return if not isinstance(config, dict): - raise ValidationError( - "AtCoder-styled contest expects no config or dict as config" - ) + raise ValidationError('AtCoder-styled contest expects no config or dict as config') for key, value in config.items(): if key not in cls.config_defaults: @@ -39,9 +37,7 @@ class AtCoderContestFormat(DefaultContestFormat): if not isinstance(value, type(cls.config_defaults[key])): raise ValidationError('invalid type for config key "%s"' % key) if not cls.config_validators[key](value): - raise ValidationError( - 'invalid value "%s" for config key "%s"' % (value, key) - ) + raise ValidationError('invalid value "%s" for config key "%s"' % (value, key)) def __init__(self, contest, config): self.config = self.config_defaults.copy() @@ -54,13 +50,8 @@ class AtCoderContestFormat(DefaultContestFormat): points = 0 format_data = {} - frozen_time = self.contest.end_time - if self.contest.freeze_after: - frozen_time = participation.start + self.contest.freeze_after - with connection.cursor() as cursor: - cursor.execute( - """ + cursor.execute(''' SELECT MAX(cs.points) as `score`, ( SELECT MIN(csub.date) FROM judge_contestsubmission ccs LEFT OUTER JOIN @@ -70,29 +61,22 @@ class AtCoderContestFormat(DefaultContestFormat): FROM judge_contestproblem cp INNER JOIN judge_contestsubmission cs ON (cs.problem_id = cp.id AND cs.participation_id = %s) LEFT OUTER JOIN judge_submission sub ON (sub.id = cs.submission_id) - WHERE sub.date < %s GROUP BY cp.id - """, - (participation.id, participation.id, to_database_time(frozen_time)), - ) + ''', (participation.id, participation.id)) for score, time, prob in cursor.fetchall(): time = from_database_time(time) dt = (time - participation.start).total_seconds() # Compute penalty - if self.config["penalty"]: + if self.config['penalty']: # An IE can have a submission result of `None` - subs = ( - participation.submissions.exclude( - submission__result__isnull=True - ) - .exclude(submission__result__in=["IE", "CE"]) - .filter(problem_id=prob) - ) + subs = participation.submissions.exclude(submission__result__isnull=True) \ + .exclude(submission__result__in=['IE', 'CE']) \ + .filter(problem_id=prob) if score: prev = subs.filter(submission__date__lte=time).count() - 1 - penalty += prev * self.config["penalty"] * 60 + penalty += prev * self.config['penalty'] * 60 else: # We should always display the penalty, even if the user has a score of 0 prev = subs.count() @@ -102,52 +86,28 @@ class AtCoderContestFormat(DefaultContestFormat): if score: cumtime = max(cumtime, dt) - format_data[str(prob)] = {"time": dt, "points": score, "penalty": prev} + format_data[str(prob)] = {'time': dt, 'points': score, 'penalty': prev} points += score - self.handle_frozen_state(participation, format_data) participation.cumtime = cumtime + penalty - participation.score = round(points, self.contest.points_precision) - participation.tiebreaker = 0 + participation.score = points participation.format_data = format_data participation.save() - def display_user_problem(self, participation, contest_problem, show_final=False): + def display_user_problem(self, participation, contest_problem): format_data = (participation.format_data or {}).get(str(contest_problem.id)) if format_data: - penalty = ( - format_html( - ' ({penalty})', - penalty=floatformat(format_data["penalty"]), - ) - if format_data.get("penalty") - else "" - ) + penalty = format_html(' ({penalty})', + penalty=floatformat(format_data['penalty'])) if format_data['penalty'] else '' return format_html( - '{points}{penalty}
{time}
', - state=( - ( - "pretest-" - if self.contest.run_pretests_only - and contest_problem.is_pretested - else "" - ) - + self.best_solution_state( - format_data["points"], contest_problem.points - ) - + (" frozen" if format_data.get("frozen") else "") - ), - url=reverse( - "contest_user_submissions_ajax", - args=[ - self.contest.key, - participation.id, - contest_problem.problem.code, - ], - ), - points=floatformat(format_data["points"]), + '{points}{penalty}
{time}
', + state=(('pretest-' if self.contest.run_pretests_only and contest_problem.is_pretested else '') + + self.best_solution_state(format_data['points'], contest_problem.points)), + url=reverse('contest_user_submissions', + args=[self.contest.key, participation.user.user.username, contest_problem.problem.code]), + points=floatformat(format_data['points']), penalty=penalty, - time=nice_repr(timedelta(seconds=format_data["time"]), "noday"), + time=nice_repr(timedelta(seconds=format_data['time']), 'noday'), ) else: - return mark_safe('') + return mark_safe('') diff --git a/judge/contest_format/base.py b/judge/contest_format/base.py index 3b47e59..7fcadc3 100644 --- a/judge/contest_format/base.py +++ b/judge/contest_format/base.py @@ -1,5 +1,6 @@ from abc import ABCMeta, abstractmethod, abstractproperty -from django.db.models import Max + +from django.utils import six class abstractclassmethod(classmethod): @@ -10,9 +11,7 @@ class abstractclassmethod(classmethod): super(abstractclassmethod, self).__init__(callable) -class BaseContestFormat(metaclass=ABCMeta): - has_hidden_subtasks = False - +class BaseContestFormat(six.with_metaclass(ABCMeta)): @abstractmethod def __init__(self, contest, config): self.config = config @@ -50,7 +49,7 @@ class BaseContestFormat(metaclass=ABCMeta): raise NotImplementedError() @abstractmethod - def display_user_problem(self, participation, contest_problem, show_final): + def display_user_problem(self, participation, contest_problem): """ Returns the HTML fragment to show a user's performance on an individual problem. This is expected to use information from the format_data field instead of computing it from scratch. @@ -62,7 +61,7 @@ class BaseContestFormat(metaclass=ABCMeta): raise NotImplementedError() @abstractmethod - def display_participation_result(self, participation, show_final): + def display_participation_result(self, participation): """ Returns the HTML fragment to show a user's performance on the whole contest. This is expected to use information from the format_data field instead of computing it from scratch. @@ -83,41 +82,10 @@ class BaseContestFormat(metaclass=ABCMeta): """ raise NotImplementedError() - @abstractmethod - def get_contest_problem_label_script(self): - """ - Returns the default Lua script to generate contest problem labels. - :return: A string, the Lua script. - """ - raise NotImplementedError() - @classmethod def best_solution_state(cls, points, total): if not points: - return "failed-score" + return 'failed-score' if points == total: - return "full-score" - return "partial-score" - - def handle_frozen_state(self, participation, format_data): - hidden_subtasks = {} - if hasattr(self, "get_hidden_subtasks"): - hidden_subtasks = self.get_hidden_subtasks() - - queryset = participation.submissions.values("problem_id").annotate( - time=Max("submission__date") - ) - for result in queryset: - problem = str(result["problem_id"]) - if not (self.contest.freeze_after or hidden_subtasks.get(problem)): - continue - if format_data.get(problem): - is_after_freeze = ( - self.contest.freeze_after - and result["time"] - >= self.contest.freeze_after + participation.start - ) - if is_after_freeze or hidden_subtasks.get(problem): - format_data[problem]["frozen"] = True - else: - format_data[problem] = {"time": 0, "points": 0, "frozen": True} + return 'full-score' + return 'partial-score' diff --git a/judge/contest_format/default.py b/judge/contest_format/default.py index 40fceb0..d3cde2d 100644 --- a/judge/contest_format/default.py +++ b/judge/contest_format/default.py @@ -13,16 +13,14 @@ from judge.contest_format.registry import register_contest_format from judge.utils.timedelta import nice_repr -@register_contest_format("default") +@register_contest_format('default') class DefaultContestFormat(BaseContestFormat): - name = gettext_lazy("Default") + name = gettext_lazy('Default') @classmethod def validate(cls, config): if config is not None and (not isinstance(config, dict) or config): - raise ValidationError( - "default contest expects no config or empty dict as config" - ) + raise ValidationError('default contest expects no config or empty dict as config') def __init__(self, contest, config): super(DefaultContestFormat, self).__init__(contest, config) @@ -32,84 +30,41 @@ class DefaultContestFormat(BaseContestFormat): points = 0 format_data = {} - queryset = participation.submissions - - if self.contest.freeze_after: - queryset = queryset.filter( - submission__date__lt=participation.start + self.contest.freeze_after - ) - - queryset = queryset.values("problem_id").annotate( - time=Max("submission__date"), - points=Max("points"), - ) - - for result in queryset: - dt = (result["time"] - participation.start).total_seconds() - if result["points"]: + for result in participation.submissions.values('problem_id').annotate( + time=Max('submission__date'), points=Max('points'), + ): + dt = (result['time'] - participation.start).total_seconds() + if result['points']: cumtime += dt - format_data[str(result["problem_id"])] = { - "time": dt, - "points": result["points"], - } - points += result["points"] + format_data[str(result['problem_id'])] = {'time': dt, 'points': result['points']} + points += result['points'] - self.handle_frozen_state(participation, format_data) participation.cumtime = max(cumtime, 0) - participation.score = round(points, self.contest.points_precision) - participation.tiebreaker = 0 + participation.score = points participation.format_data = format_data participation.save() - def display_user_problem(self, participation, contest_problem, show_final=False): + def display_user_problem(self, participation, contest_problem): format_data = (participation.format_data or {}).get(str(contest_problem.id)) if format_data: return format_html( - '{points}
{time}
', - state=( - ( - "pretest-" - if self.contest.run_pretests_only - and contest_problem.is_pretested - else "" - ) - + self.best_solution_state( - format_data["points"], contest_problem.points - ) - + (" frozen" if format_data.get("frozen") else "") - ), - url=reverse( - "contest_user_submissions_ajax", - args=[ - self.contest.key, - participation.id, - contest_problem.problem.code, - ], - ), - points=floatformat( - format_data["points"], -self.contest.points_precision - ), - time=nice_repr(timedelta(seconds=format_data["time"]), "noday"), + u'{points}
{time}
', + state=(('pretest-' if self.contest.run_pretests_only and contest_problem.is_pretested else '') + + self.best_solution_state(format_data['points'], contest_problem.points)), + url=reverse('contest_user_submissions', + args=[self.contest.key, participation.user.user.username, contest_problem.problem.code]), + points=floatformat(format_data['points']), + time=nice_repr(timedelta(seconds=format_data['time']), 'noday'), ) else: - return mark_safe('') + return mark_safe('') - def display_participation_result(self, participation, show_final=False): + def display_participation_result(self, participation): return format_html( - '{points}
{cumtime}
', - points=floatformat(participation.score, -self.contest.points_precision), - cumtime=nice_repr(timedelta(seconds=participation.cumtime), "noday"), + u'{points}
{cumtime}
', + points=floatformat(participation.score), + cumtime=nice_repr(timedelta(seconds=participation.cumtime), 'noday'), ) def get_problem_breakdown(self, participation, contest_problems): - return [ - (participation.format_data or {}).get(str(contest_problem.id)) - for contest_problem in contest_problems - ] - - def get_contest_problem_label_script(self): - return """ - function(n) - return tostring(math.floor(n + 1)) - end - """ + return [(participation.format_data or {}).get(str(contest_problem.id)) for contest_problem in contest_problems] diff --git a/judge/contest_format/ecoo.py b/judge/contest_format/ecoo.py index c5c177d..ff1060a 100644 --- a/judge/contest_format/ecoo.py +++ b/judge/contest_format/ecoo.py @@ -10,25 +10,21 @@ from django.utils.translation import gettext_lazy from judge.contest_format.default import DefaultContestFormat from judge.contest_format.registry import register_contest_format -from judge.timezone import from_database_time, to_database_time +from judge.timezone import from_database_time from judge.utils.timedelta import nice_repr -@register_contest_format("ecoo") +@register_contest_format('ecoo') class ECOOContestFormat(DefaultContestFormat): - name = gettext_lazy("ECOO") - config_defaults = {"cumtime": False, "first_ac_bonus": 10, "time_bonus": 5} - config_validators = { - "cumtime": lambda x: True, - "first_ac_bonus": lambda x: x >= 0, - "time_bonus": lambda x: x >= 0, - } - """ + name = gettext_lazy('ECOO') + config_defaults = {'cumtime': False, 'first_ac_bonus': 10, 'time_bonus': 5} + config_validators = {'cumtime': lambda x: True, 'first_ac_bonus': lambda x: x >= 0, 'time_bonus': lambda x: x >= 0} + ''' cumtime: Specify True if cumulative time is to be used in breaking ties. Defaults to False. first_ac_bonus: The number of points to award if a solution gets AC on its first non-IE/CE run. Defaults to 10. time_bonus: Number of minutes to award an extra point for submitting before the contest end. Specify 0 to disable. Defaults to 5. - """ + ''' @classmethod def validate(cls, config): @@ -36,9 +32,7 @@ class ECOOContestFormat(DefaultContestFormat): return if not isinstance(config, dict): - raise ValidationError( - "ECOO-styled contest expects no config or dict as config" - ) + raise ValidationError('ECOO-styled contest expects no config or dict as config') for key, value in config.items(): if key not in cls.config_defaults: @@ -46,9 +40,7 @@ class ECOOContestFormat(DefaultContestFormat): if not isinstance(value, type(cls.config_defaults[key])): raise ValidationError('invalid type for config key "%s"' % key) if not cls.config_validators[key](value): - raise ValidationError( - 'invalid value "%s" for config key "%s"' % (value, key) - ) + raise ValidationError('invalid value "%s" for config key "%s"' % (value, key)) def __init__(self, contest, config): self.config = self.config_defaults.copy() @@ -60,13 +52,8 @@ class ECOOContestFormat(DefaultContestFormat): points = 0 format_data = {} - frozen_time = self.contest.end_time - if self.contest.freeze_after: - frozen_time = participation.start + self.contest.freeze_after - with connection.cursor() as cursor: - cursor.execute( - """ + cursor.execute(''' SELECT ( SELECT MAX(ccs.points) FROM judge_contestsubmission ccs LEFT OUTER JOIN @@ -81,92 +68,55 @@ class ECOOContestFormat(DefaultContestFormat): FROM judge_contestproblem cp INNER JOIN judge_contestsubmission cs ON (cs.problem_id = cp.id AND cs.participation_id = %s) LEFT OUTER JOIN judge_submission sub ON (sub.id = cs.submission_id) - WHERE sub.date < %s GROUP BY cp.id - """, - ( - participation.id, - participation.id, - participation.id, - to_database_time(frozen_time), - ), - ) + ''', (participation.id, participation.id, participation.id)) for score, time, prob, subs, max_score in cursor.fetchall(): time = from_database_time(time) dt = (time - participation.start).total_seconds() - if self.config["cumtime"]: + if self.config['cumtime']: cumtime += dt bonus = 0 if score > 0: # First AC bonus if subs == 1 and score == max_score: - bonus += self.config["first_ac_bonus"] + bonus += self.config['first_ac_bonus'] # Time bonus - if self.config["time_bonus"]: - bonus += ( - (participation.end_time - time).total_seconds() - // 60 - // self.config["time_bonus"] - ) + if self.config['time_bonus']: + bonus += (participation.end_time - time).total_seconds() // 60 // self.config['time_bonus'] points += bonus - format_data[str(prob)] = {"time": dt, "points": score, "bonus": bonus} + format_data[str(prob)] = {'time': dt, 'points': score, 'bonus': bonus} points += score - self.handle_frozen_state(participation, format_data) participation.cumtime = cumtime - participation.score = round(points, self.contest.points_precision) - participation.tiebreaker = 0 + participation.score = points participation.format_data = format_data participation.save() - def display_user_problem(self, participation, contest_problem, show_final=False): + def display_user_problem(self, participation, contest_problem): format_data = (participation.format_data or {}).get(str(contest_problem.id)) if format_data: - bonus = ( - format_html( - " +{bonus}", bonus=floatformat(format_data["bonus"]) - ) - if format_data.get("bonus") - else "" - ) + bonus = format_html(' +{bonus}', + bonus=floatformat(format_data['bonus'])) if format_data['bonus'] else '' return format_html( - '{points}{bonus}
{time}
', - state=( - ( - "pretest-" - if self.contest.run_pretests_only - and contest_problem.is_pretested - else "" - ) - + self.best_solution_state( - format_data["points"], contest_problem.points - ) - + (" frozen" if format_data.get("frozen") else "") - ), - url=reverse( - "contest_user_submissions_ajax", - args=[ - self.contest.key, - participation.id, - contest_problem.problem.code, - ], - ), - points=floatformat(format_data["points"]), + '{points}{bonus}
{time}
', + state=(('pretest-' if self.contest.run_pretests_only and contest_problem.is_pretested else '') + + self.best_solution_state(format_data['points'], contest_problem.points)), + url=reverse('contest_user_submissions', + args=[self.contest.key, participation.user.user.username, contest_problem.problem.code]), + points=floatformat(format_data['points']), bonus=bonus, - time=nice_repr(timedelta(seconds=format_data["time"]), "noday"), + time=nice_repr(timedelta(seconds=format_data['time']), 'noday'), ) else: - return mark_safe("") + return mark_safe('') - def display_participation_result(self, participation, show_final=False): + def display_participation_result(self, participation): return format_html( '{points}
{cumtime}
', points=floatformat(participation.score), - cumtime=nice_repr(timedelta(seconds=participation.cumtime), "noday") - if self.config["cumtime"] - else "", + cumtime=nice_repr(timedelta(seconds=participation.cumtime), 'noday') if self.config['cumtime'] else '', ) diff --git a/judge/contest_format/icpc.py b/judge/contest_format/icpc.py deleted file mode 100644 index bf0bfff..0000000 --- a/judge/contest_format/icpc.py +++ /dev/null @@ -1,168 +0,0 @@ -from datetime import timedelta - -from django.core.exceptions import ValidationError -from django.db import connection -from django.template.defaultfilters import floatformat -from django.urls import reverse -from django.utils.html import format_html -from django.utils.safestring import mark_safe -from django.utils.translation import gettext_lazy - -from judge.contest_format.default import DefaultContestFormat -from judge.contest_format.registry import register_contest_format -from judge.timezone import from_database_time, to_database_time -from judge.utils.timedelta import nice_repr - - -@register_contest_format("icpc") -class ICPCContestFormat(DefaultContestFormat): - name = gettext_lazy("ICPC") - config_defaults = {"penalty": 20} - config_validators = {"penalty": lambda x: x >= 0} - """ - penalty: Number of penalty minutes each incorrect submission adds. Defaults to 20. - """ - - @classmethod - def validate(cls, config): - if config is None: - return - - if not isinstance(config, dict): - raise ValidationError( - "ICPC-styled contest expects no config or dict as config" - ) - - for key, value in config.items(): - if key not in cls.config_defaults: - raise ValidationError('unknown config key "%s"' % key) - if not isinstance(value, type(cls.config_defaults[key])): - raise ValidationError('invalid type for config key "%s"' % key) - if not cls.config_validators[key](value): - raise ValidationError( - 'invalid value "%s" for config key "%s"' % (value, key) - ) - - def __init__(self, contest, config): - self.config = self.config_defaults.copy() - self.config.update(config or {}) - self.contest = contest - - def update_participation(self, participation): - cumtime = 0 - last = 0 - penalty = 0 - score = 0 - format_data = {} - - frozen_time = self.contest.end_time - if self.contest.freeze_after: - frozen_time = participation.start + self.contest.freeze_after - - with connection.cursor() as cursor: - cursor.execute( - """ - SELECT MAX(cs.points) as `points`, ( - SELECT MIN(csub.date) - FROM judge_contestsubmission ccs LEFT OUTER JOIN - judge_submission csub ON (csub.id = ccs.submission_id) - WHERE ccs.problem_id = cp.id AND ccs.participation_id = %s AND ccs.points = MAX(cs.points) - ) AS `time`, cp.id AS `prob` - FROM judge_contestproblem cp INNER JOIN - judge_contestsubmission cs ON (cs.problem_id = cp.id AND cs.participation_id = %s) LEFT OUTER JOIN - judge_submission sub ON (sub.id = cs.submission_id) - WHERE sub.date < %s - GROUP BY cp.id - """, - (participation.id, participation.id, to_database_time(frozen_time)), - ) - - for points, time, prob in cursor.fetchall(): - time = from_database_time(time) - dt = (time - participation.start).total_seconds() - - # Compute penalty - if self.config["penalty"]: - # An IE can have a submission result of `None` - subs = ( - participation.submissions.exclude( - submission__result__isnull=True - ) - .exclude(submission__result__in=["IE", "CE"]) - .filter(problem_id=prob) - ) - if points: - prev = subs.filter(submission__date__lte=time).count() - 1 - penalty += prev * self.config["penalty"] * 60 - else: - # We should always display the penalty, even if the user has a score of 0 - prev = subs.count() - else: - prev = 0 - - if points: - cumtime += dt - last = max(last, dt) - - format_data[str(prob)] = {"time": dt, "points": points, "penalty": prev} - score += points - - self.handle_frozen_state(participation, format_data) - participation.cumtime = max(0, cumtime + penalty) - participation.score = round(score, self.contest.points_precision) - participation.tiebreaker = last # field is sorted from least to greatest - participation.format_data = format_data - participation.save() - - def display_user_problem(self, participation, contest_problem, show_final=False): - format_data = (participation.format_data or {}).get(str(contest_problem.id)) - if format_data: - penalty = ( - format_html( - ' +{penalty}', - penalty=floatformat(format_data["penalty"]), - ) - if format_data.get("penalty") - else "" - ) - return format_html( - '{points}{penalty}
{time}
', - state=( - ( - "pretest-" - if self.contest.run_pretests_only - and contest_problem.is_pretested - else "" - ) - + self.best_solution_state( - format_data["points"], contest_problem.points - ) - + (" frozen" if format_data.get("frozen") else "") - ), - url=reverse( - "contest_user_submissions_ajax", - args=[ - self.contest.key, - participation.id, - contest_problem.problem.code, - ], - ), - points=floatformat(format_data["points"]), - penalty=penalty, - time=nice_repr(timedelta(seconds=format_data["time"]), "noday"), - ) - else: - return mark_safe("") - - def get_contest_problem_label_script(self): - return """ - function(n) - n = n + 1 - ret = "" - while n > 0 do - ret = string.char((n - 1) % 26 + 65) .. ret - n = math.floor((n - 1) / 26) - end - return ret - end - """ diff --git a/judge/contest_format/ioi.py b/judge/contest_format/ioi.py index ce93252..ac84c4b 100644 --- a/judge/contest_format/ioi.py +++ b/judge/contest_format/ioi.py @@ -12,16 +12,15 @@ from judge.contest_format.default import DefaultContestFormat from judge.contest_format.registry import register_contest_format from judge.timezone import from_database_time from judge.utils.timedelta import nice_repr -from django.db.models import Min, OuterRef, Subquery -@register_contest_format("ioi") +@register_contest_format('ioi') class IOIContestFormat(DefaultContestFormat): - name = gettext_lazy("IOI") - config_defaults = {"cumtime": False} - """ + name = gettext_lazy('IOI') + config_defaults = {'cumtime': False} + ''' cumtime: Specify True if time penalties are to be computed. Defaults to False. - """ + ''' @classmethod def validate(cls, config): @@ -29,9 +28,7 @@ class IOIContestFormat(DefaultContestFormat): return if not isinstance(config, dict): - raise ValidationError( - "IOI-styled contest expects no config or dict as config" - ) + raise ValidationError('IOI-styled contest expects no config or dict as config') for key, value in config.items(): if key not in cls.config_defaults: @@ -46,97 +43,57 @@ class IOIContestFormat(DefaultContestFormat): def update_participation(self, participation): cumtime = 0 - score = 0 + points = 0 format_data = {} - queryset = participation.submissions - if self.contest.freeze_after: - queryset = queryset.filter( - submission__date__lt=participation.start + self.contest.freeze_after - ) + with connection.cursor() as cursor: + cursor.execute(''' + SELECT MAX(cs.points) as `score`, ( + SELECT MIN(csub.date) + FROM judge_contestsubmission ccs LEFT OUTER JOIN + judge_submission csub ON (csub.id = ccs.submission_id) + WHERE ccs.problem_id = cp.id AND ccs.participation_id = %s AND ccs.points = MAX(cs.points) + ) AS `time`, cp.id AS `prob` + FROM judge_contestproblem cp INNER JOIN + judge_contestsubmission cs ON (cs.problem_id = cp.id AND cs.participation_id = %s) LEFT OUTER JOIN + judge_submission sub ON (sub.id = cs.submission_id) + GROUP BY cp.id + ''', (participation.id, participation.id)) - queryset = ( - queryset.values("problem_id") - .filter( - points=Subquery( - queryset.filter(problem_id=OuterRef("problem_id")) - .order_by("-points") - .values("points")[:1] - ) - ) - .annotate(time=Min("submission__date")) - .values_list("problem_id", "time", "points") - ) + for score, time, prob in cursor.fetchall(): + if self.config['cumtime']: + dt = (from_database_time(time) - participation.start).total_seconds() + if score: + cumtime += dt + else: + dt = 0 - for problem_id, time, points in queryset: - if self.config["cumtime"]: - dt = (time - participation.start).total_seconds() - if points: - cumtime += dt - else: - dt = 0 + format_data[str(prob)] = {'time': dt, 'points': score} + points += score - format_data[str(problem_id)] = {"points": points, "time": dt} - score += points - - self.handle_frozen_state(participation, format_data) participation.cumtime = max(cumtime, 0) - participation.score = round(score, self.contest.points_precision) - participation.tiebreaker = 0 + participation.score = points participation.format_data = format_data participation.save() - def display_user_problem(self, participation, contest_problem, show_final=False): - if show_final: - format_data = (participation.format_data_final or {}).get( - str(contest_problem.id) - ) - else: - format_data = (participation.format_data or {}).get(str(contest_problem.id)) + def display_user_problem(self, participation, contest_problem): + format_data = (participation.format_data or {}).get(str(contest_problem.id)) if format_data: return format_html( - '{points}
{time}
', - state=( - ( - "pretest-" - if self.contest.run_pretests_only - and contest_problem.is_pretested - else "" - ) - + self.best_solution_state( - format_data["points"], contest_problem.points - ) - + (" frozen" if format_data.get("frozen") else "") - ), - url=reverse( - "contest_user_submissions_ajax", - args=[ - self.contest.key, - participation.id, - contest_problem.problem.code, - ], - ), - points=floatformat( - format_data["points"], -self.contest.points_precision - ), - time=nice_repr(timedelta(seconds=format_data["time"]), "noday") - if self.config["cumtime"] - else "", + '{points}
{time}
', + state=(('pretest-' if self.contest.run_pretests_only and contest_problem.is_pretested else '') + + self.best_solution_state(format_data['points'], contest_problem.points)), + url=reverse('contest_user_submissions', + args=[self.contest.key, participation.user.user.username, contest_problem.problem.code]), + points=floatformat(format_data['points']), + time=nice_repr(timedelta(seconds=format_data['time']), 'noday') if self.config['cumtime'] else '', ) else: - return mark_safe('') + return mark_safe('') - def display_participation_result(self, participation, show_final=False): - if show_final: - score = participation.score_final - cumtime = participation.cumtime_final - else: - score = participation.score - cumtime = participation.cumtime + def display_participation_result(self, participation): return format_html( '{points}
{cumtime}
', - points=floatformat(score, -self.contest.points_precision), - cumtime=nice_repr(timedelta(seconds=cumtime), "noday") - if self.config["cumtime"] - else "", + points=floatformat(participation.score), + cumtime=nice_repr(timedelta(seconds=participation.cumtime), 'noday') if self.config['cumtime'] else '', ) diff --git a/judge/contest_format/new_ioi.py b/judge/contest_format/new_ioi.py deleted file mode 100644 index 6e09353..0000000 --- a/judge/contest_format/new_ioi.py +++ /dev/null @@ -1,173 +0,0 @@ -from django.db import connection -from django.utils.translation import gettext as _, gettext_lazy - -from judge.contest_format.ioi import IOIContestFormat -from judge.contest_format.registry import register_contest_format -from judge.timezone import from_database_time, to_database_time - - -@register_contest_format("ioi16") -class NewIOIContestFormat(IOIContestFormat): - name = gettext_lazy("New IOI") - config_defaults = {"cumtime": False} - has_hidden_subtasks = True - """ - cumtime: Specify True if time penalties are to be computed. Defaults to False. - """ - - def get_hidden_subtasks(self): - queryset = self.contest.contest_problems.values_list("id", "hidden_subtasks") - res = {} - for problem_id, hidden_subtasks in queryset: - subtasks = set() - if hidden_subtasks: - hidden_subtasks = hidden_subtasks.split(",") - for i in hidden_subtasks: - try: - subtasks.add(int(i)) - except Exception as e: - pass - res[str(problem_id)] = subtasks - return res - - def get_results_by_subtask(self, participation, include_frozen=False): - frozen_time = self.contest.end_time - if self.contest.freeze_after and not include_frozen: - frozen_time = participation.start + self.contest.freeze_after - - with connection.cursor() as cursor: - cursor.execute( - """ - SELECT q.prob, - q.prob_points, - MIN(q.date) as `date`, - q.batch_points, - q.total_batch_points, - q.batch, - q.subid - FROM ( - SELECT cp.id as `prob`, - cp.points as `prob_points`, - sub.id as `subid`, - sub.date as `date`, - tc.points as `points`, - tc.batch as `batch`, - SUM(tc.points) as `batch_points`, - SUM(tc.total) as `total_batch_points` - FROM judge_contestproblem cp - INNER JOIN - judge_contestsubmission cs - ON (cs.problem_id = cp.id AND cs.participation_id = %s) - LEFT OUTER JOIN - judge_submission sub - ON (sub.id = cs.submission_id AND sub.status = 'D') - INNER JOIN judge_submissiontestcase tc - ON sub.id = tc.submission_id - WHERE sub.date < %s - GROUP BY cp.id, tc.batch, sub.id - ) q - INNER JOIN ( - SELECT prob, batch, MAX(r.batch_points) as max_batch_points - FROM ( - SELECT cp.id as `prob`, - tc.batch as `batch`, - SUM(tc.points) as `batch_points` - FROM judge_contestproblem cp - INNER JOIN - judge_contestsubmission cs - ON (cs.problem_id = cp.id AND cs.participation_id = %s) - LEFT OUTER JOIN - judge_submission sub - ON (sub.id = cs.submission_id AND sub.status = 'D') - INNER JOIN judge_submissiontestcase tc - ON sub.id = tc.submission_id - WHERE sub.date < %s - GROUP BY cp.id, tc.batch, sub.id - ) r - GROUP BY prob, batch - ) p - ON p.prob = q.prob AND (p.batch = q.batch OR p.batch is NULL AND q.batch is NULL) - WHERE p.max_batch_points = q.batch_points - GROUP BY q.prob, q.batch - """, - ( - participation.id, - to_database_time(frozen_time), - participation.id, - to_database_time(frozen_time), - ), - ) - - return cursor.fetchall() - - def update_participation(self, participation): - hidden_subtasks = self.get_hidden_subtasks() - - def calculate_format_data(participation, include_frozen): - format_data = {} - for ( - problem_id, - problem_points, - time, - subtask_points, - total_subtask_points, - subtask, - sub_id, - ) in self.get_results_by_subtask(participation, include_frozen): - problem_id = str(problem_id) - time = from_database_time(time) - if self.config["cumtime"]: - dt = (time - participation.start).total_seconds() - else: - dt = 0 - - if format_data.get(problem_id) is None: - format_data[problem_id] = { - "points": 0, - "time": 0, - "total_points": 0, - } - if ( - subtask not in hidden_subtasks.get(problem_id, set()) - or include_frozen - ): - format_data[problem_id]["points"] += subtask_points - format_data[problem_id]["total_points"] += total_subtask_points - format_data[problem_id]["time"] = max( - dt, format_data[problem_id]["time"] - ) - format_data[problem_id]["problem_points"] = problem_points - - return format_data - - def recalculate_results(format_data): - cumtime = 0 - score = 0 - for problem_data in format_data.values(): - if not problem_data["total_points"]: - continue - penalty = problem_data["time"] - problem_data["points"] = ( - problem_data["points"] - / problem_data["total_points"] - * problem_data["problem_points"] - ) - if self.config["cumtime"] and problem_data["points"]: - cumtime += penalty - score += problem_data["points"] - return score, cumtime - - format_data = calculate_format_data(participation, False) - score, cumtime = recalculate_results(format_data) - self.handle_frozen_state(participation, format_data) - participation.cumtime = max(cumtime, 0) - participation.score = round(score, self.contest.points_precision) - participation.tiebreaker = 0 - participation.format_data = format_data - - format_data_final = calculate_format_data(participation, True) - score_final, cumtime_final = recalculate_results(format_data_final) - participation.cumtime_final = max(cumtime_final, 0) - participation.score_final = round(score_final, self.contest.points_precision) - participation.format_data_final = format_data_final - participation.save() diff --git a/judge/contest_format/registry.py b/judge/contest_format/registry.py index ce5d39a..fba22c0 100644 --- a/judge/contest_format/registry.py +++ b/judge/contest_format/registry.py @@ -1,3 +1,5 @@ +from django.utils import six + formats = {} @@ -11,4 +13,4 @@ def register_contest_format(name): def choices(): - return [(key, value.name) for key, value in sorted(formats.items())] + return [(key, value.name) for key, value in sorted(six.iteritems(formats))] diff --git a/judge/contest_format/ultimate.py b/judge/contest_format/ultimate.py deleted file mode 100644 index 7960d02..0000000 --- a/judge/contest_format/ultimate.py +++ /dev/null @@ -1,55 +0,0 @@ -from django.utils.translation import gettext_lazy - -from judge.contest_format.ioi import IOIContestFormat -from judge.contest_format.registry import register_contest_format -from django.db.models import Min, OuterRef, Subquery - -# This contest format only counts last submission for each problem. - - -@register_contest_format("ultimate") -class UltimateContestFormat(IOIContestFormat): - name = gettext_lazy("Ultimate") - - def update_participation(self, participation): - cumtime = 0 - score = 0 - format_data = {} - - queryset = participation.submissions - if self.contest.freeze_after: - queryset = queryset.filter( - submission__date__lt=participation.start + self.contest.freeze_after - ) - - queryset = ( - queryset.values("problem_id") - .filter( - id=Subquery( - queryset.filter(problem_id=OuterRef("problem_id")) - .order_by("-id") - .values("id")[:1] - ) - ) - .values_list("problem_id", "submission__date", "points") - ) - - for problem_id, time, points in queryset: - if self.config["cumtime"]: - dt = (time - participation.start).total_seconds() - if points: - cumtime += dt - else: - dt = 0 - format_data[str(problem_id)] = { - "time": dt, - "points": points, - } - score += points - - self.handle_frozen_state(participation, format_data) - participation.cumtime = max(cumtime, 0) - participation.score = round(score, self.contest.points_precision) - participation.tiebreaker = 0 - participation.format_data = format_data - participation.save() diff --git a/judge/custom_translations.py b/judge/custom_translations.py deleted file mode 100644 index efe4939..0000000 --- a/judge/custom_translations.py +++ /dev/null @@ -1,22 +0,0 @@ -from django.utils.translation import gettext_lazy as _, ngettext - - -def custom_trans(): - return [ - # Password reset - ngettext( - "This password is too short. It must contain at least %(min_length)d character.", - "This password is too short. It must contain at least %(min_length)d characters.", - 0, - ), - ngettext( - "Your password must contain at least %(min_length)d character.", - "Your password must contain at least %(min_length)d characters.", - 0, - ), - _("The two password fields didn’t match."), - _("Your password can’t be entirely numeric."), - # Navbar - _("Bug Report"), - _("Courses"), - ] diff --git a/judge/dblock.py b/judge/dblock.py index 5b7feab..d4d5184 100644 --- a/judge/dblock.py +++ b/judge/dblock.py @@ -5,21 +5,19 @@ from django.db import connection, transaction class LockModel(object): def __init__(self, write, read=()): - self.tables = ", ".join( - chain( - ("`%s` WRITE" % model._meta.db_table for model in write), - ("`%s` READ" % model._meta.db_table for model in read), - ) - ) + self.tables = ', '.join(chain( + ('`%s` WRITE' % model._meta.db_table for model in write), + ('`%s` READ' % model._meta.db_table for model in read), + )) self.cursor = connection.cursor() def __enter__(self): - self.cursor.execute("LOCK TABLES " + self.tables) + self.cursor.execute('LOCK TABLES ' + self.tables) def __exit__(self, exc_type, exc_val, exc_tb): if exc_type is None: transaction.commit() else: transaction.rollback() - self.cursor.execute("UNLOCK TABLES") + self.cursor.execute('UNLOCK TABLES') self.cursor.close() diff --git a/judge/event_poster.py b/judge/event_poster.py index e7c57fd..29100bd 100644 --- a/judge/event_poster.py +++ b/judge/event_poster.py @@ -1,6 +1,6 @@ from django.conf import settings -__all__ = ["last", "post"] +__all__ = ['last', 'post'] if not settings.EVENT_DAEMON_USE: real = False @@ -10,12 +10,9 @@ if not settings.EVENT_DAEMON_USE: def last(): return 0 - -elif hasattr(settings, "EVENT_DAEMON_AMQP"): +elif hasattr(settings, 'EVENT_DAEMON_AMQP'): from .event_poster_amqp import last, post - real = True else: from .event_poster_ws import last, post - real = True diff --git a/judge/event_poster_amqp.py b/judge/event_poster_amqp.py index 24cec72..74f6331 100644 --- a/judge/event_poster_amqp.py +++ b/judge/event_poster_amqp.py @@ -6,7 +6,7 @@ import pika from django.conf import settings from pika.exceptions import AMQPError -__all__ = ["EventPoster", "post", "last"] +__all__ = ['EventPoster', 'post', 'last'] class EventPoster(object): @@ -15,19 +15,14 @@ class EventPoster(object): self._exchange = settings.EVENT_DAEMON_AMQP_EXCHANGE def _connect(self): - self._conn = pika.BlockingConnection( - pika.URLParameters(settings.EVENT_DAEMON_AMQP), - ) + self._conn = pika.BlockingConnection(pika.URLParameters(settings.EVENT_DAEMON_AMQP)) self._chan = self._conn.channel() def post(self, channel, message, tries=0): try: id = int(time() * 1000000) - self._chan.basic_publish( - self._exchange, - "#", - json.dumps({"id": id, "channel": channel, "message": message}), - ) + self._chan.basic_publish(self._exchange, '', + json.dumps({'id': id, 'channel': channel, 'message': message})) return id except AMQPError: if tries > 10: @@ -40,7 +35,7 @@ _local = threading.local() def _get_poster(): - if "poster" not in _local.__dict__: + if 'poster' not in _local.__dict__: _local.poster = EventPoster() return _local.poster diff --git a/judge/event_poster_ws.py b/judge/event_poster_ws.py index 8daddab..fba4052 100644 --- a/judge/event_poster_ws.py +++ b/judge/event_poster_ws.py @@ -5,7 +5,7 @@ import threading from django.conf import settings from websocket import WebSocketException, create_connection -__all__ = ["EventPostingError", "EventPoster", "post", "last"] +__all__ = ['EventPostingError', 'EventPoster', 'post', 'last'] _local = threading.local() @@ -20,23 +20,19 @@ class EventPoster(object): def _connect(self): self._conn = create_connection(settings.EVENT_DAEMON_POST) if settings.EVENT_DAEMON_KEY is not None: - self._conn.send( - json.dumps({"command": "auth", "key": settings.EVENT_DAEMON_KEY}) - ) + self._conn.send(json.dumps({'command': 'auth', 'key': settings.EVENT_DAEMON_KEY})) resp = json.loads(self._conn.recv()) - if resp["status"] == "error": - raise EventPostingError(resp["code"]) + if resp['status'] == 'error': + raise EventPostingError(resp['code']) def post(self, channel, message, tries=0): try: - self._conn.send( - json.dumps({"command": "post", "channel": channel, "message": message}) - ) + self._conn.send(json.dumps({'command': 'post', 'channel': channel, 'message': message})) resp = json.loads(self._conn.recv()) - if resp["status"] == "error": - raise EventPostingError(resp["code"]) + if resp['status'] == 'error': + raise EventPostingError(resp['code']) else: - return resp["id"] + return resp['id'] except WebSocketException: if tries > 10: raise @@ -47,10 +43,10 @@ class EventPoster(object): try: self._conn.send('{"command": "last-msg"}') resp = json.loads(self._conn.recv()) - if resp["status"] == "error": - raise EventPostingError(resp["code"]) + if resp['status'] == 'error': + raise EventPostingError(resp['code']) else: - return resp["id"] + return resp['id'] except WebSocketException: if tries > 10: raise @@ -59,7 +55,7 @@ class EventPoster(object): def _get_poster(): - if "poster" not in _local.__dict__: + if 'poster' not in _local.__dict__: _local.poster = EventPoster() return _local.poster diff --git a/judge/feed.py b/judge/feed.py new file mode 100644 index 0000000..47e9d51 --- /dev/null +++ b/judge/feed.py @@ -0,0 +1,99 @@ +from django.conf import settings +from django.contrib.auth.models import AnonymousUser +from django.contrib.syndication.views import Feed +from django.core.cache import cache +from django.utils import timezone +from django.utils.feedgenerator import Atom1Feed + +from judge.jinja2.markdown import markdown +from judge.models import BlogPost, Comment, Problem + + +class ProblemFeed(Feed): + title = 'Recently Added %s Problems' % settings.SITE_NAME + link = '/' + description = 'The latest problems added on the %s website' % settings.SITE_LONG_NAME + + def items(self): + return Problem.objects.filter(is_public=True, is_organization_private=False).order_by('-date', '-id')[:25] + + def item_title(self, problem): + return problem.name + + def item_description(self, problem): + key = 'problem_feed:%d' % problem.id + desc = cache.get(key) + if desc is None: + desc = str(markdown(problem.description, 'problem'))[:500] + '...' + cache.set(key, desc, 86400) + return desc + + def item_pubdate(self, problem): + return problem.date + + item_updateddate = item_pubdate + + +class AtomProblemFeed(ProblemFeed): + feed_type = Atom1Feed + subtitle = ProblemFeed.description + + +class CommentFeed(Feed): + title = 'Latest %s Comments' % settings.SITE_NAME + link = '/' + description = 'The latest comments on the %s website' % settings.SITE_LONG_NAME + + def items(self): + return Comment.most_recent(AnonymousUser(), 25) + + def item_title(self, comment): + return '%s -> %s' % (comment.author.user.username, comment.page_title) + + def item_description(self, comment): + key = 'comment_feed:%d' % comment.id + desc = cache.get(key) + if desc is None: + desc = str(markdown(comment.body, 'comment')) + cache.set(key, desc, 86400) + return desc + + def item_pubdate(self, comment): + return comment.time + + item_updateddate = item_pubdate + + +class AtomCommentFeed(CommentFeed): + feed_type = Atom1Feed + subtitle = CommentFeed.description + + +class BlogFeed(Feed): + title = 'Latest %s Blog Posts' % settings.SITE_NAME + link = '/' + description = 'The latest blog posts from the %s' % settings.SITE_LONG_NAME + + def items(self): + return BlogPost.objects.filter(visible=True, publish_on__lte=timezone.now()).order_by('-sticky', '-publish_on') + + def item_title(self, post): + return post.title + + def item_description(self, post): + key = 'blog_feed:%d' % post.id + summary = cache.get(key) + if summary is None: + summary = str(markdown(post.summary or post.content, 'blog')) + cache.set(key, summary, 86400) + return summary + + def item_pubdate(self, post): + return post.publish_on + + item_updateddate = item_pubdate + + +class AtomBlogFeed(BlogFeed): + feed_type = Atom1Feed + subtitle = BlogFeed.description diff --git a/judge/fixtures/demo.json b/judge/fixtures/demo.json index b9fbea7..9d22a9f 100644 --- a/judge/fixtures/demo.json +++ b/judge/fixtures/demo.json @@ -8,6 +8,7 @@ "ip": "10.0.2.2", "language": 1, "last_access": "2017-12-02T08:57:10.093Z", + "math_engine": "auto", "mute": false, "organizations": [ 1 @@ -17,7 +18,8 @@ "problem_count": 0, "rating": null, "timezone": "America/Toronto", - "user": 1 + "user": 1, + "user_script": "" }, "model": "judge.profile", "pk": 1 @@ -145,8 +147,25 @@ }, { "fields": { - "domain": "localhost:8000", - "name": "LQDOJ" + "author": 1, + "body": "This is your first comment!", + "hidden": false, + "level": 0, + "lft": 1, + "page": "b:1", + "parent": null, + "rght": 2, + "score": 0, + "time": "2017-12-02T08:46:54.007Z", + "tree_id": 1 + }, + "model": "judge.comment", + "pk": 1 + }, + { + "fields": { + "domain": "localhost:8081", + "name": "DMOJ: Modern Online Judge" }, "model": "sites.site", "pk": 1 diff --git a/judge/forms.py b/judge/forms.py index 47a4b36..11aa092 100644 --- a/judge/forms.py +++ b/judge/forms.py @@ -1,599 +1,159 @@ -import os -import secrets from operator import attrgetter -import pyotp -import time -import datetime +import pyotp from django import forms from django.conf import settings -from django.contrib.auth.models import User from django.contrib.auth.forms import AuthenticationForm -from django.core.exceptions import ValidationError, ObjectDoesNotExist +from django.core.exceptions import ValidationError from django.core.validators import RegexValidator from django.db.models import Q -from django.forms import ( - CharField, - ChoiceField, - Form, - ModelForm, - formset_factory, - BaseModelFormSet, - FileField, -) -from django.urls import reverse_lazy, reverse +from django.forms import CharField, Form, ModelForm +from django.urls import reverse_lazy from django.utils.translation import gettext_lazy as _ -from django.utils import timezone from django_ace import AceWidget -from judge.models import ( - Contest, - Language, - TestFormatterModel, - Organization, - PrivateMessage, - Problem, - ProblemPointsVote, - Profile, - Submission, - BlogPost, - ContestProblem, - TestFormatterModel, - ProfileInfo, -) - -from judge.widgets import ( - HeavyPreviewPageDownWidget, - PagedownWidget, - Select2MultipleWidget, - Select2Widget, - HeavySelect2MultipleWidget, - HeavySelect2Widget, - Select2MultipleWidget, - DateTimePickerWidget, - ImageWidget, - DatePickerWidget, -) +from judge.models import Contest, Language, Organization, PrivateMessage, Problem, Profile, Submission +from judge.utils.subscription import newsletter_id +from judge.widgets import HeavyPreviewPageDownWidget, MathJaxPagedownWidget, PagedownWidget, Select2MultipleWidget, \ + Select2Widget -def fix_unicode(string, unsafe=tuple("\u202a\u202b\u202d\u202e")): - return ( - string + (sum(k in unsafe for k in string) - string.count("\u202c")) * "\u202c" - ) - - -class UserForm(ModelForm): - class Meta: - model = User - fields = [ - "first_name", - "last_name", - ] - - -class ProfileInfoForm(ModelForm): - class Meta: - model = ProfileInfo - fields = ["tshirt_size", "date_of_birth", "address"] - widgets = { - "tshirt_size": Select2Widget(attrs={"style": "width:100%"}), - "date_of_birth": DatePickerWidget, - "address": forms.TextInput(attrs={"style": "width:100%"}), - } +def fix_unicode(string, unsafe=tuple('\u202a\u202b\u202d\u202e')): + return string + (sum(k in unsafe for k in string) - string.count('\u202c')) * '\u202c' class ProfileForm(ModelForm): + if newsletter_id is not None: + newsletter = forms.BooleanField(label=_('Subscribe to contest updates'), initial=False, required=False) + test_site = forms.BooleanField(label=_('Enable experimental features'), initial=False, required=False) + class Meta: model = Profile - fields = [ - "about", - "timezone", - "language", - "ace_theme", - "profile_image", - "css_background", - ] + fields = ['about', 'organizations', 'timezone', 'language', 'ace_theme', 'user_script'] widgets = { - "timezone": Select2Widget(attrs={"style": "width:200px"}), - "language": Select2Widget(attrs={"style": "width:200px"}), - "ace_theme": Select2Widget(attrs={"style": "width:200px"}), - "profile_image": ImageWidget, - "css_background": forms.TextInput(), + 'user_script': AceWidget(theme='github'), + 'timezone': Select2Widget(attrs={'style': 'width:200px'}), + 'language': Select2Widget(attrs={'style': 'width:200px'}), + 'ace_theme': Select2Widget(attrs={'style': 'width:200px'}), } + has_math_config = bool(settings.MATHOID_URL) + if has_math_config: + fields.append('math_engine') + widgets['math_engine'] = Select2Widget(attrs={'style': 'width:200px'}) + if HeavyPreviewPageDownWidget is not None: - widgets["about"] = HeavyPreviewPageDownWidget( - preview=reverse_lazy("profile_preview"), - attrs={"style": "max-width:700px;min-width:700px;width:700px"}, + widgets['about'] = HeavyPreviewPageDownWidget( + preview=reverse_lazy('profile_preview'), + attrs={'style': 'max-width:700px;min-width:700px;width:700px'}, ) + def clean(self): + organizations = self.cleaned_data.get('organizations') or [] + max_orgs = settings.DMOJ_USER_MAX_ORGANIZATION_COUNT + + if sum(org.is_open for org in organizations) > max_orgs: + raise ValidationError( + _('You may not be part of more than {count} public organizations.').format(count=max_orgs)) + + return self.cleaned_data + def __init__(self, *args, **kwargs): - user = kwargs.pop("user", None) + user = kwargs.pop('user', None) super(ProfileForm, self).__init__(*args, **kwargs) - self.fields["profile_image"].required = False - - def clean_profile_image(self): - profile_image = self.cleaned_data.get("profile_image") - if profile_image: - if profile_image.size > 5 * 1024 * 1024: - raise ValidationError( - _("File size exceeds the maximum allowed limit of 5MB.") - ) - return profile_image - - -def file_size_validator(file): - limit = 10 * 1024 * 1024 - if file.size > limit: - raise ValidationError("File too large. Size should not exceed 10MB.") + if not user.has_perm('judge.edit_all_organization'): + self.fields['organizations'].queryset = Organization.objects.filter( + Q(is_open=True) | Q(id__in=user.profile.organizations.all()), + ) class ProblemSubmitForm(ModelForm): - source = CharField( - max_length=65536, widget=AceWidget(theme="twilight", no_ace_media=True) - ) - judge = ChoiceField(choices=(), widget=forms.HiddenInput(), required=False) - source_file = FileField(required=False, validators=[file_size_validator]) + source = CharField(max_length=65536, widget=AceWidget(theme='twilight', no_ace_media=True)) - def __init__(self, *args, judge_choices=(), request=None, problem=None, **kwargs): + def __init__(self, *args, **kwargs): super(ProblemSubmitForm, self).__init__(*args, **kwargs) - self.source_file_name = None - self.request = request - self.problem = problem - self.fields["language"].empty_label = None - self.fields["language"].label_from_instance = attrgetter("display_name") - self.fields["language"].queryset = Language.objects.filter( - judges__online=True - ).distinct() - - if judge_choices: - self.fields["judge"].widget = Select2Widget( - attrs={"style": "width: 150px", "data-placeholder": _("Any judge")}, - ) - self.fields["judge"].choices = judge_choices - - def allow_url_as_source(self): - key = self.cleaned_data["language"].key - filename = self.files["source_file"].name - if key == "OUTPUT" and self.problem.data_files.output_only: - return filename.endswith(".zip") - if key == "SCAT": - return filename.endswith(".sb3") - return False - - def clean(self): - if "source_file" in self.files: - if self.allow_url_as_source(): - filename = self.files["source_file"].name - now = datetime.datetime.now() - timestamp = str(int(time.mktime(now.timetuple()))) - self.source_file_name = ( - timestamp + secrets.token_hex(5) + "." + filename.split(".")[-1] - ) - filepath = os.path.join( - settings.DMOJ_SUBMISSION_ROOT, self.source_file_name - ) - with open(filepath, "wb+") as destination: - for chunk in self.files["source_file"].chunks(): - destination.write(chunk) - self.cleaned_data["source"] = self.request.build_absolute_uri( - reverse("submission_source_file", args=(self.source_file_name,)) - ) - del self.files["source_file"] - return self.cleaned_data + self.fields['problem'].empty_label = None + self.fields['problem'].widget = forms.HiddenInput() + self.fields['language'].empty_label = None + self.fields['language'].label_from_instance = attrgetter('display_name') + self.fields['language'].queryset = Language.objects.filter(judges__online=True).distinct() class Meta: model = Submission - fields = ["language"] + fields = ['problem', 'language'] class EditOrganizationForm(ModelForm): class Meta: model = Organization - fields = [ - "name", - "slug", - "short_name", - "about", - "organization_image", - "admins", - "is_open", - ] - widgets = { - "admins": Select2MultipleWidget(), - "organization_image": ImageWidget, - } + fields = ['about', 'logo_override_image', 'admins'] + widgets = {'admins': Select2MultipleWidget()} if HeavyPreviewPageDownWidget is not None: - widgets["about"] = HeavyPreviewPageDownWidget( - preview=reverse_lazy("organization_preview") - ) - - def __init__(self, *args, **kwargs): - super(EditOrganizationForm, self).__init__(*args, **kwargs) - self.fields["organization_image"].required = False - - def clean_organization_image(self): - organization_image = self.cleaned_data.get("organization_image") - if organization_image: - if organization_image.size > 5 * 1024 * 1024: - raise ValidationError( - _("File size exceeds the maximum allowed limit of 5MB.") - ) - return organization_image - - -class AddOrganizationForm(ModelForm): - class Meta: - model = Organization - fields = [ - "name", - "slug", - "short_name", - "about", - "organization_image", - "is_open", - ] - widgets = {} - if HeavyPreviewPageDownWidget is not None: - widgets["about"] = HeavyPreviewPageDownWidget( - preview=reverse_lazy("organization_preview") - ) - - def __init__(self, *args, **kwargs): - self.request = kwargs.pop("request", None) - super(AddOrganizationForm, self).__init__(*args, **kwargs) - self.fields["organization_image"].required = False - - def save(self, commit=True): - res = super(AddOrganizationForm, self).save(commit=False) - res.registrant = self.request.profile - if commit: - res.save() - return res - - -class AddOrganizationContestForm(ModelForm): - def __init__(self, *args, **kwargs): - self.request = kwargs.pop("request", None) - super(AddOrganizationContestForm, self).__init__(*args, **kwargs) - - def save(self, commit=True): - contest = super(AddOrganizationContestForm, self).save(commit=False) - old_save_m2m = self.save_m2m - - def save_m2m(): - for i, problem in enumerate(self.cleaned_data["problems"]): - contest_problem = ContestProblem( - contest=contest, problem=problem, points=100, order=i + 1 - ) - contest_problem.save() - contest.contest_problems.add(contest_problem) - old_save_m2m() - - self.save_m2m = save_m2m - contest.save() - self.save_m2m() - return contest - - class Meta: - model = Contest - fields = ( - "key", - "name", - "start_time", - "end_time", - "problems", - ) - widgets = { - "start_time": DateTimePickerWidget(), - "end_time": DateTimePickerWidget(), - "problems": HeavySelect2MultipleWidget(data_view="problem_select2"), - } - - -class EditOrganizationContestForm(ModelForm): - def __init__(self, *args, **kwargs): - self.org_id = kwargs.pop("org_id", 0) - super(EditOrganizationContestForm, self).__init__(*args, **kwargs) - for field in [ - "authors", - "curators", - "testers", - "private_contestants", - "banned_users", - "view_contest_scoreboard", - ]: - self.fields[field].widget.data_url = ( - self.fields[field].widget.get_url() + f"?org_id={self.org_id}" - ) - - class Meta: - model = Contest - fields = ( - "is_visible", - "key", - "name", - "start_time", - "end_time", - "format_name", - "authors", - "curators", - "testers", - "time_limit", - "freeze_after", - "use_clarifications", - "hide_problem_tags", - "public_scoreboard", - "scoreboard_visibility", - "points_precision", - "rate_limit", - "description", - "og_image", - "logo_override_image", - "summary", - "access_code", - "private_contestants", - "view_contest_scoreboard", - "banned_users", - ) - widgets = { - "authors": HeavySelect2MultipleWidget(data_view="profile_select2"), - "curators": HeavySelect2MultipleWidget(data_view="profile_select2"), - "testers": HeavySelect2MultipleWidget(data_view="profile_select2"), - "private_contestants": HeavySelect2MultipleWidget( - data_view="profile_select2" - ), - "banned_users": HeavySelect2MultipleWidget(data_view="profile_select2"), - "view_contest_scoreboard": HeavySelect2MultipleWidget( - data_view="profile_select2" - ), - "organizations": HeavySelect2MultipleWidget( - data_view="organization_select2" - ), - "tags": Select2MultipleWidget, - "description": HeavyPreviewPageDownWidget( - preview=reverse_lazy("contest_preview") - ), - "start_time": DateTimePickerWidget(), - "end_time": DateTimePickerWidget(), - "format_name": Select2Widget(), - "scoreboard_visibility": Select2Widget(), - } - - -class AddOrganizationMemberForm(ModelForm): - new_users = CharField( - max_length=65536, - widget=forms.Textarea, - help_text=_("Enter usernames separating by space"), - label=_("New users"), - ) - - def clean_new_users(self): - new_users = self.cleaned_data.get("new_users") or "" - usernames = new_users.split() - invalid_usernames = [] - valid_usernames = [] - - for username in usernames: - try: - valid_usernames.append(Profile.objects.get(user__username=username)) - except ObjectDoesNotExist: - invalid_usernames.append(username) - - if invalid_usernames: - raise ValidationError( - _("These usernames don't exist: {usernames}").format( - usernames=str(invalid_usernames) - ) - ) - return valid_usernames - - class Meta: - model = Organization - fields = () - - -class OrganizationBlogForm(ModelForm): - class Meta: - model = BlogPost - fields = ("title", "content", "publish_on") - widgets = { - "publish_on": forms.HiddenInput, - } - if HeavyPreviewPageDownWidget is not None: - widgets["content"] = HeavyPreviewPageDownWidget( - preview=reverse_lazy("organization_preview") - ) - - def __init__(self, *args, **kwargs): - super(OrganizationBlogForm, self).__init__(*args, **kwargs) - self.fields["publish_on"].required = False - self.fields["publish_on"].is_hidden = True - - def clean(self): - self.cleaned_data["publish_on"] = timezone.now() - return self.cleaned_data - - -class OrganizationAdminBlogForm(OrganizationBlogForm): - class Meta: - model = BlogPost - fields = ("visible", "sticky", "title", "content", "publish_on") - widgets = { - "publish_on": forms.HiddenInput, - } - if HeavyPreviewPageDownWidget is not None: - widgets["content"] = HeavyPreviewPageDownWidget( - preview=reverse_lazy("organization_preview") - ) + widgets['about'] = HeavyPreviewPageDownWidget(preview=reverse_lazy('organization_preview')) class NewMessageForm(ModelForm): class Meta: model = PrivateMessage - fields = ["title", "content"] + fields = ['title', 'content'] widgets = {} if PagedownWidget is not None: - widgets["content"] = PagedownWidget() + widgets['content'] = MathJaxPagedownWidget() class CustomAuthenticationForm(AuthenticationForm): def __init__(self, *args, **kwargs): super(CustomAuthenticationForm, self).__init__(*args, **kwargs) - self.fields["username"].widget.attrs.update( - {"placeholder": _("Username/Email")} - ) - self.fields["password"].widget.attrs.update({"placeholder": _("Password")}) + self.fields['username'].widget.attrs.update({'placeholder': _('Username')}) + self.fields['password'].widget.attrs.update({'placeholder': _('Password')}) - self.has_google_auth = self._has_social_auth("GOOGLE_OAUTH2") - self.has_facebook_auth = self._has_social_auth("FACEBOOK") - self.has_github_auth = self._has_social_auth("GITHUB_SECURE") + self.has_google_auth = self._has_social_auth('GOOGLE_OAUTH2') + self.has_facebook_auth = self._has_social_auth('FACEBOOK') + self.has_github_auth = self._has_social_auth('GITHUB_SECURE') def _has_social_auth(self, key): - return getattr(settings, "SOCIAL_AUTH_%s_KEY" % key, None) and getattr( - settings, "SOCIAL_AUTH_%s_SECRET" % key, None - ) + return (getattr(settings, 'SOCIAL_AUTH_%s_KEY' % key, None) and + getattr(settings, 'SOCIAL_AUTH_%s_SECRET' % key, None)) class NoAutoCompleteCharField(forms.CharField): def widget_attrs(self, widget): attrs = super(NoAutoCompleteCharField, self).widget_attrs(widget) - attrs["autocomplete"] = "off" + attrs['autocomplete'] = 'off' return attrs class TOTPForm(Form): TOLERANCE = settings.DMOJ_TOTP_TOLERANCE_HALF_MINUTES - totp_token = NoAutoCompleteCharField( - validators=[ - RegexValidator( - "^[0-9]{6}$", - _("Two Factor Authentication tokens must be 6 decimal digits."), - ), - ] - ) + totp_token = NoAutoCompleteCharField(validators=[ + RegexValidator('^[0-9]{6}$', _('Two Factor Authentication tokens must be 6 decimal digits.')), + ]) def __init__(self, *args, **kwargs): - self.totp_key = kwargs.pop("totp_key") + self.totp_key = kwargs.pop('totp_key') super(TOTPForm, self).__init__(*args, **kwargs) def clean_totp_token(self): - if not pyotp.TOTP(self.totp_key).verify( - self.cleaned_data["totp_token"], valid_window=self.TOLERANCE - ): - raise ValidationError(_("Invalid Two Factor Authentication token.")) + if not pyotp.TOTP(self.totp_key).verify(self.cleaned_data['totp_token'], valid_window=self.TOLERANCE): + raise ValidationError(_('Invalid Two Factor Authentication token.')) class ProblemCloneForm(Form): - code = CharField( - max_length=20, - validators=[ - RegexValidator("^[a-z0-9]+$", _("Problem code must be ^[a-z0-9]+$")) - ], - ) + code = CharField(max_length=20, validators=[RegexValidator('^[a-z0-9]+$', _('Problem code must be ^[a-z0-9]+$'))]) def clean_code(self): - code = self.cleaned_data["code"] + code = self.cleaned_data['code'] if Problem.objects.filter(code=code).exists(): - raise ValidationError(_("Problem with code already exists.")) + raise ValidationError(_('Problem with code already exists.')) return code class ContestCloneForm(Form): - key = CharField( - max_length=20, - validators=[RegexValidator("^[a-z0-9]+$", _("Contest id must be ^[a-z0-9]+$"))], - ) - organization = ChoiceField(choices=(), required=True) - - def __init__(self, *args, org_choices=(), profile=None, **kwargs): - super(ContestCloneForm, self).__init__(*args, **kwargs) - self.fields["organization"].widget = Select2Widget( - attrs={"style": "width: 100%", "data-placeholder": _("Group")}, - ) - self.fields["organization"].choices = org_choices - self.profile = profile + key = CharField(max_length=20, validators=[RegexValidator('^[a-z0-9]+$', _('Contest id must be ^[a-z0-9]+$'))]) def clean_key(self): - key = self.cleaned_data["key"] + key = self.cleaned_data['key'] if Contest.objects.filter(key=key).exists(): - raise ValidationError(_("Contest with key already exists.")) + raise ValidationError(_('Contest with key already exists.')) return key - - def clean_organization(self): - organization_id = self.cleaned_data["organization"] - try: - organization = Organization.objects.get(id=organization_id) - except Exception: - raise ValidationError(_("Group doesn't exist.")) - if not organization.admins.filter(id=self.profile.id).exists(): - raise ValidationError(_("You don't have permission in this group.")) - return organization - - -class ProblemPointsVoteForm(ModelForm): - class Meta: - model = ProblemPointsVote - fields = ["points"] - - -class ContestProblemForm(ModelForm): - class Meta: - model = ContestProblem - fields = ( - "order", - "problem", - "points", - "partial", - "show_testcases", - "max_submissions", - ) - widgets = { - "problem": HeavySelect2Widget( - data_view="problem_select2", attrs={"style": "width: 100%"} - ), - } - - -class ContestProblemModelFormSet(BaseModelFormSet): - def is_valid(self): - valid = super().is_valid() - - if not valid: - return valid - - problems = set() - duplicates = [] - - for form in self.forms: - if form.cleaned_data and not form.cleaned_data.get("DELETE", False): - problem = form.cleaned_data.get("problem") - if problem in problems: - duplicates.append(problem) - else: - problems.add(problem) - - if duplicates: - for form in self.forms: - problem = form.cleaned_data.get("problem") - if problem in duplicates: - form.add_error("problem", _("This problem is duplicated.")) - return False - - return True - - -class ContestProblemFormSet( - formset_factory( - ContestProblemForm, formset=ContestProblemModelFormSet, extra=6, can_delete=True - ) -): - model = ContestProblem - - -class TestFormatterForm(ModelForm): - class Meta: - model = TestFormatterModel - fields = ["file"] diff --git a/judge/fulltext.py b/judge/fulltext.py index 209a87e..5b9f7d3 100644 --- a/judge/fulltext.py +++ b/judge/fulltext.py @@ -5,10 +5,10 @@ from django.db.models.query import QuerySet class SearchQuerySet(QuerySet): - DEFAULT = "" - BOOLEAN = " IN BOOLEAN MODE" - NATURAL_LANGUAGE = " IN NATURAL LANGUAGE MODE" - QUERY_EXPANSION = " WITH QUERY EXPANSION" + DEFAULT = '' + BOOLEAN = ' IN BOOLEAN MODE' + NATURAL_LANGUAGE = ' IN NATURAL LANGUAGE MODE' + QUERY_EXPANSION = ' WITH QUERY EXPANSION' def __init__(self, fields=None, **kwargs): super(SearchQuerySet, self).__init__(**kwargs) @@ -25,26 +25,20 @@ class SearchQuerySet(QuerySet): # Get the table name and column names from the model # in `table_name`.`column_name` style columns = [meta.get_field(name).column for name in self._search_fields] - full_names = [ - "%s.%s" - % ( - connection.ops.quote_name(meta.db_table), - connection.ops.quote_name(column), - ) - for column in columns - ] + full_names = ['%s.%s' % + (connection.ops.quote_name(meta.db_table), + connection.ops.quote_name(column)) + for column in columns] # Create the MATCH...AGAINST expressions - fulltext_columns = ", ".join(full_names) - match_expr = "MATCH(%s) AGAINST (%%s%s)" % (fulltext_columns, mode) + fulltext_columns = ', '.join(full_names) + match_expr = ('MATCH(%s) AGAINST (%%s%s)' % (fulltext_columns, mode)) # Add the extra SELECT and WHERE options - return self.extra( - select={"relevance": match_expr}, - select_params=[query], - where=[match_expr], - params=[query], - ) + return self.extra(select={'relevance': match_expr}, + select_params=[query], + where=[match_expr], + params=[query]) class SearchManager(models.Manager): diff --git a/judge/highlight_code.py b/judge/highlight_code.py index f5c91e3..ff330f7 100644 --- a/judge/highlight_code.py +++ b/judge/highlight_code.py @@ -1,13 +1,37 @@ from django.utils.html import escape, mark_safe -from judge.markdown import markdown -__all__ = ["highlight_code"] +__all__ = ['highlight_code'] -def highlight_code(code, language, linenos=True, title=None): - linenos_option = 'linenums="1"' if linenos else "" - title_option = f'title="{title}"' if title else "" - options = f"{{.{language} {linenos_option} {title_option}}}" +def _make_pre_code(code): + return mark_safe('
' + escape(code) + '
') - value = f"```{options}\n{code}\n```\n" - return mark_safe(markdown(value)) + +def _wrap_code(inner): + yield 0, "" + for tup in inner: + yield tup + yield 0, "" + + +try: + import pygments + import pygments.lexers + import pygments.formatters.html + import pygments.util +except ImportError: + def highlight_code(code, language, cssclass=None): + return _make_pre_code(code) +else: + class HtmlCodeFormatter(pygments.formatters.HtmlFormatter): + def wrap(self, source, outfile): + return self._wrap_div(self._wrap_pre(_wrap_code(source))) + + def highlight_code(code, language, cssclass='codehilite'): + try: + lexer = pygments.lexers.get_lexer_by_name(language) + except pygments.util.ClassNotFound: + return _make_pre_code(code) + + # return mark_safe(pygments.highlight(code, lexer, HtmlCodeFormatter(cssclass=cssclass, linenos='table'))) + return mark_safe(pygments.highlight(code, lexer, HtmlCodeFormatter(cssclass=cssclass))) diff --git a/judge/jinja2/__init__.py b/judge/jinja2/__init__.py index e24ea8c..f316397 100644 --- a/judge/jinja2/__init__.py +++ b/judge/jinja2/__init__.py @@ -8,33 +8,19 @@ from statici18n.templatetags.statici18n import inlinei18n from judge.highlight_code import highlight_code from judge.user_translations import gettext -from . import ( - camo, - chat, - datetime, - filesize, - gravatar, - language, - markdown, - rating, - reference, - render, - social, - spaceless, - timedelta, - comment, -) +from . import (camo, datetime, filesize, gravatar, language, markdown, rating, reference, render, social, + spaceless, submission, timedelta) from . import registry -registry.function("str", str) -registry.filter("str", str) -registry.filter("json", json.dumps) -registry.filter("highlight", highlight_code) -registry.filter("urlquote", urlquote) -registry.filter("roundfloat", round) -registry.function("inlinei18n", inlinei18n) -registry.function("mptt_tree", get_cached_trees) -registry.function("user_trans", gettext) +registry.function('str', str) +registry.filter('str', str) +registry.filter('json', json.dumps) +registry.filter('highlight', highlight_code) +registry.filter('urlquote', urlquote) +registry.filter('roundfloat', round) +registry.function('inlinei18n', inlinei18n) +registry.function('mptt_tree', get_cached_trees) +registry.function('user_trans', gettext) @registry.function diff --git a/judge/jinja2/chat.py b/judge/jinja2/chat.py deleted file mode 100644 index 564a748..0000000 --- a/judge/jinja2/chat.py +++ /dev/null @@ -1,7 +0,0 @@ -from . import registry -from chat_box.utils import encrypt_url - - -@registry.function -def chat_param(request_profile, profile): - return encrypt_url(request_profile.id, profile.id) diff --git a/judge/jinja2/comment.py b/judge/jinja2/comment.py deleted file mode 100644 index 6baa365..0000000 --- a/judge/jinja2/comment.py +++ /dev/null @@ -1,12 +0,0 @@ -from . import registry - -from django.contrib.contenttypes.models import ContentType - -from judge.models.comment import get_visible_comment_count -from judge.caching import cache_wrapper - - -@registry.function -def comment_count(obj): - content_type = ContentType.objects.get_for_model(obj) - return get_visible_comment_count(content_type, obj.pk) diff --git a/judge/jinja2/datetime.py b/judge/jinja2/datetime.py index ce7cf32..76c6bfc 100644 --- a/judge/jinja2/datetime.py +++ b/judge/jinja2/datetime.py @@ -10,7 +10,7 @@ from . import registry def localtime_wrapper(func): @functools.wraps(func) def wrapper(datetime, *args, **kwargs): - if getattr(datetime, "convert_to_local_time", True): + if getattr(datetime, 'convert_to_local_time', True): datetime = localtime(datetime) return func(datetime, *args, **kwargs) @@ -22,6 +22,6 @@ registry.filter(localtime_wrapper(time)) @registry.function -@registry.render_with("widgets/relative-time.html") -def relative_time(time, format=_("N j, Y, g:i a"), rel=_("{time}"), abs=_("{time}")): - return {"time": time, "format": format, "rel_format": rel, "abs_format": abs} +@registry.render_with('widgets/relative-time.html') +def relative_time(time, format=_('N j, Y, g:i a'), rel=_('{time}'), abs=_('on {time}')): + return {'time': time, 'format': format, 'rel_format': rel, 'abs_format': abs} diff --git a/judge/jinja2/filesize.py b/judge/jinja2/filesize.py index 0cb0fef..7b27fde 100644 --- a/judge/jinja2/filesize.py +++ b/judge/jinja2/filesize.py @@ -13,28 +13,24 @@ def _format_size(bytes, callback): PB = 1 << 50 if bytes < KB: - return callback("", bytes) + return callback('', bytes) elif bytes < MB: - return callback("K", bytes / KB) + return callback('K', bytes / KB) elif bytes < GB: - return callback("M", bytes / MB) + return callback('M', bytes / MB) elif bytes < TB: - return callback("G", bytes / GB) + return callback('G', bytes / GB) elif bytes < PB: - return callback("T", bytes / TB) + return callback('T', bytes / TB) else: - return callback("P", bytes / PB) + return callback('P', bytes / PB) @registry.filter def kbdetailformat(bytes): - return avoid_wrapping( - _format_size( - bytes * 1024, lambda x, y: ["%d %sB", "%.2f %sB"][bool(x)] % (y, x) - ) - ) + return avoid_wrapping(_format_size(bytes * 1024, lambda x, y: ['%d %sB', '%.2f %sB'][bool(x)] % (y, x))) @registry.filter def kbsimpleformat(kb): - return _format_size(kb * 1024, lambda x, y: "%.0f%s" % (y, x or "B")) + return _format_size(kb * 1024, lambda x, y: '%.0f%s' % (y, x or 'B')) diff --git a/judge/jinja2/gravatar.py b/judge/jinja2/gravatar.py index 175992f..35b3fb8 100644 --- a/judge/jinja2/gravatar.py +++ b/judge/jinja2/gravatar.py @@ -9,23 +9,17 @@ from . import registry @registry.function -def gravatar(profile, size=80, default=None, profile_image=None, email=None): - if profile and not profile.is_muted: - if profile_image: - return profile_image - if profile and profile.profile_image_url: - return profile.profile_image_url - if profile: - email = email or profile.email +def gravatar(email, size=80, default=None): + if isinstance(email, Profile): if default is None: - default = profile.is_muted - gravatar_url = ( - "//www.gravatar.com/avatar/" - + hashlib.md5(utf8bytes(email.strip().lower())).hexdigest() - + "?" - ) - args = {"d": "identicon", "s": str(size)} + default = email.mute + email = email.user.email + elif isinstance(email, AbstractUser): + email = email.email + + gravatar_url = '//www.gravatar.com/avatar/' + hashlib.md5(utf8bytes(email.strip().lower())).hexdigest() + '?' + args = {'d': 'identicon', 's': str(size)} if default: - args["f"] = "y" + args['f'] = 'y' gravatar_url += urlencode(args) return gravatar_url diff --git a/judge/jinja2/language.py b/judge/jinja2/language.py index dda4456..344568a 100644 --- a/judge/jinja2/language.py +++ b/judge/jinja2/language.py @@ -3,7 +3,7 @@ from django.utils import translation from . import registry -@registry.function("language_info") +@registry.function('language_info') def get_language_info(language): # ``language`` is either a language code string or a sequence # with the language code as its first item @@ -13,6 +13,6 @@ def get_language_info(language): return translation.get_language_info(str(language)) -@registry.function("language_info_list") +@registry.function('language_info_list') def get_language_info_list(langs): return [get_language_info(lang) for lang in langs] diff --git a/judge/jinja2/markdown/__init__.py b/judge/jinja2/markdown/__init__.py index 18355d4..4ca07bb 100644 --- a/judge/jinja2/markdown/__init__.py +++ b/judge/jinja2/markdown/__init__.py @@ -1,7 +1,142 @@ +import logging +import re +from html.parser import HTMLParser +from urllib.parse import urlparse + +import mistune +from django.conf import settings +from jinja2 import Markup +from lxml import html +from lxml.etree import ParserError, XMLSyntaxError + +from judge.highlight_code import highlight_code +from judge.jinja2.markdown.lazy_load import lazy_load as lazy_load_processor +from judge.jinja2.markdown.math import MathInlineGrammar, MathInlineLexer, MathRenderer +from judge.utils.camo import client as camo_client +from judge.utils.texoid import TEXOID_ENABLED, TexoidRenderer from .. import registry -from judge.markdown import markdown as _markdown + +logger = logging.getLogger('judge.html') + +NOFOLLOW_WHITELIST = settings.NOFOLLOW_EXCLUDED + + +class CodeSafeInlineGrammar(mistune.InlineGrammar): + double_emphasis = re.compile(r'^\*{2}([\s\S]+?)()\*{2}(?!\*)') # **word** + emphasis = re.compile(r'^\*((?:\*\*|[^\*])+?)()\*(?!\*)') # *word* + + +class AwesomeInlineGrammar(MathInlineGrammar, CodeSafeInlineGrammar): + pass + + +class AwesomeInlineLexer(MathInlineLexer, mistune.InlineLexer): + grammar_class = AwesomeInlineGrammar + + +class AwesomeRenderer(MathRenderer, mistune.Renderer): + def __init__(self, *args, **kwargs): + self.nofollow = kwargs.pop('nofollow', True) + self.texoid = TexoidRenderer() if kwargs.pop('texoid', False) else None + self.parser = HTMLParser() + super(AwesomeRenderer, self).__init__(*args, **kwargs) + + def _link_rel(self, href): + if href: + try: + url = urlparse(href) + except ValueError: + return ' rel="nofollow"' + else: + if url.netloc and url.netloc not in NOFOLLOW_WHITELIST: + return ' rel="nofollow"' + return '' + + def autolink(self, link, is_email=False): + text = link = mistune.escape(link) + if is_email: + link = 'mailto:%s' % link + return '%s' % (link, self._link_rel(link), text) + + def table(self, header, body): + return ( + '\n%s\n' + '\n%s\n
\n' + ) % (header, body) + + def link(self, link, title, text): + link = mistune.escape_link(link) + if not title: + return '%s' % (link, self._link_rel(link), text) + title = mistune.escape(title, quote=True) + return '%s' % (link, title, self._link_rel(link), text) + + def block_code(self, code, lang=None): + if not lang: + return '\n
%s
\n' % mistune.escape(code).rstrip() + return highlight_code(code, lang) + + def block_html(self, html): + if self.texoid and html.startswith('')] + latex = html[html.index('>') + 1:html.rindex('<')] + latex = self.parser.unescape(latex) + result = self.texoid.get_result(latex) + if not result: + return '
%s
' % mistune.escape(latex, smart_amp=False) + elif 'error' not in result: + img = ('''') % { + 'svg': result['svg'], 'png': result['png'], + 'width': result['meta']['width'], 'height': result['meta']['height'], + 'tail': ' /' if self.options.get('use_xhtml') else '', + } + style = ['max-width: 100%', + 'height: %s' % result['meta']['height'], + 'max-height: %s' % result['meta']['height'], + 'width: %s' % result['meta']['height']] + if 'inline' in attr: + tag = 'span' + else: + tag = 'div' + style += ['text-align: center'] + return '<%s style="%s">%s' % (tag, ';'.join(style), img, tag) + else: + return '
%s
' % mistune.escape(result['error'], smart_amp=False) + return super(AwesomeRenderer, self).block_html(html) + + def header(self, text, level, *args, **kwargs): + return super(AwesomeRenderer, self).header(text, level + 2, *args, **kwargs) @registry.filter -def markdown(value, lazy_load=False): - return _markdown(value, lazy_load) +def markdown(value, style, math_engine=None, lazy_load=False): + styles = settings.MARKDOWN_STYLES.get(style, settings.MARKDOWN_DEFAULT_STYLE) + escape = styles.get('safe_mode', True) + nofollow = styles.get('nofollow', True) + texoid = TEXOID_ENABLED and styles.get('texoid', False) + math = hasattr(settings, 'MATHOID_URL') and styles.get('math', False) + + post_processors = [] + if styles.get('use_camo', False) and camo_client is not None: + post_processors.append(camo_client.update_tree) + if lazy_load: + post_processors.append(lazy_load_processor) + + renderer = AwesomeRenderer(escape=escape, nofollow=nofollow, texoid=texoid, + math=math and math_engine is not None, math_engine=math_engine) + markdown = mistune.Markdown(renderer=renderer, inline=AwesomeInlineLexer, + parse_block_html=1, parse_inline_html=1) + result = markdown(value) + + if post_processors: + try: + tree = html.fromstring(result, parser=html.HTMLParser(recover=True)) + except (XMLSyntaxError, ParserError) as e: + if result and (not isinstance(e, ParserError) or e.args[0] != 'Document is empty'): + logger.exception('Failed to parse HTML string') + tree = html.Element('div') + for processor in post_processors: + processor(tree) + result = html.tostring(tree, encoding='unicode') + return Markup(result) diff --git a/judge/jinja2/markdown/lazy_load.py b/judge/jinja2/markdown/lazy_load.py new file mode 100644 index 0000000..cf9849c --- /dev/null +++ b/judge/jinja2/markdown/lazy_load.py @@ -0,0 +1,20 @@ +from copy import deepcopy + +from django.templatetags.static import static +from lxml import html + + +def lazy_load(tree): + blank = static('blank.gif') + for img in tree.xpath('.//img'): + src = img.get('src', '') + if src.startswith('data') or '-math' in img.get('class', ''): + continue + noscript = html.Element('noscript') + copy = deepcopy(img) + copy.tail = '' + noscript.append(copy) + img.addprevious(noscript) + img.set('data-src', src) + img.set('src', blank) + img.set('class', img.get('class') + ' unveil' if img.get('class') else 'unveil') diff --git a/judge/jinja2/markdown/math.py b/judge/jinja2/markdown/math.py new file mode 100644 index 0000000..d619d5b --- /dev/null +++ b/judge/jinja2/markdown/math.py @@ -0,0 +1,65 @@ +import re + +import mistune + +from judge.utils.mathoid import MathoidMathParser + +mistune._pre_tags.append('latex') + + +class MathInlineGrammar(mistune.InlineGrammar): + block_math = re.compile(r'^\$\$(.*?)\$\$|^\\\[(.*?)\\\]', re.DOTALL) + math = re.compile(r'^~(.*?)~|^\\\((.*?)\\\)', re.DOTALL) + text = re.compile(r'^[\s\S]+?(?=[\\%s' % (tag, extra, text, tag) + else: + html = m.group(0) + return self.renderer.inline_html(html) + + +class MathRenderer(mistune.Renderer): + def __init__(self, *args, **kwargs): + if kwargs.pop('math', False): + self.mathoid = MathoidMathParser(kwargs.pop('math_engine', None) or 'svg') + else: + self.mathoid = None + super(MathRenderer, self).__init__(*args, **kwargs) + + def block_math(self, math): + if self.mathoid is None or not math: + return r'\[%s\]' % mistune.escape(str(math)) + return self.mathoid.display_math(math) + + def math(self, math): + if self.mathoid is None or not math: + return r'\(%s\)' % mistune.escape(str(math)) + return self.mathoid.inline_math(math) diff --git a/judge/jinja2/rating.py b/judge/jinja2/rating.py index 0144fbc..b531bb7 100644 --- a/judge/jinja2/rating.py +++ b/judge/jinja2/rating.py @@ -1,3 +1,5 @@ +from django.utils import six + from judge.ratings import rating_class, rating_name, rating_progress from . import registry @@ -6,28 +8,28 @@ def _get_rating_value(func, obj): if obj is None: return None - if isinstance(obj, int): + if isinstance(obj, six.integer_types): return func(obj) else: return func(obj.rating) -@registry.function("rating_class") +@registry.function('rating_class') def get_rating_class(obj): - return _get_rating_value(rating_class, obj) or "rate-none" + return _get_rating_value(rating_class, obj) or 'rate-none' -@registry.function(name="rating_name") +@registry.function(name='rating_name') def get_name(obj): - return _get_rating_value(rating_name, obj) or "Unrated" + return _get_rating_value(rating_name, obj) or 'Unrated' -@registry.function(name="rating_progress") +@registry.function(name='rating_progress') def get_progress(obj): return _get_rating_value(rating_progress, obj) or 0.0 @registry.function -@registry.render_with("user/rating.html") +@registry.render_with('user/rating.html') def rating_number(obj): - return {"rating": obj} + return {'rating': obj} diff --git a/judge/jinja2/reference.py b/judge/jinja2/reference.py index 274382e..239f279 100644 --- a/judge/jinja2/reference.py +++ b/judge/jinja2/reference.py @@ -13,17 +13,17 @@ from judge.models import Contest, Problem, Profile from judge.ratings import rating_class, rating_progress from . import registry -rereference = re.compile(r"\[(r?user):(\w+)\]") +rereference = re.compile(r'\[(r?user):(\w+)\]') def get_user(username, data): if not data: - element = Element("span") + element = Element('span') element.text = username return element - element = Element("span", {"class": Profile.get_user_css_class(*data)}) - link = Element("a", {"href": reverse("user_page", args=[username])}) + element = Element('span', {'class': Profile.get_user_css_class(*data)}) + link = Element('a', {'href': reverse('user_page', args=[username])}) link.text = username element.append(link) return element @@ -31,21 +31,17 @@ def get_user(username, data): def get_user_rating(username, data): if not data: - element = Element("span") + element = Element('span') element.text = username return element rating = data[1] - element = Element( - "a", {"class": "rate-group", "href": reverse("user_page", args=[username])} - ) + element = Element('a', {'class': 'rate-group', 'href': reverse('user_page', args=[username])}) if rating: rating_css = rating_class(rating) - rate_box = Element("span", {"class": "rate-box " + rating_css}) - rate_box.append( - Element("span", {"style": "height: %3.fem" % rating_progress(rating)}) - ) - user = Element("span", {"class": "rating " + rating_css}) + rate_box = Element('span', {'class': 'rate-box ' + rating_css}) + rate_box.append(Element('span', {'style': 'height: %3.fem' % rating_progress(rating)})) + user = Element('span', {'class': 'rating ' + rating_css}) user.text = username element.append(rate_box) element.append(user) @@ -55,24 +51,14 @@ def get_user_rating(username, data): def get_user_info(usernames): - return { - name: (rank, rating) - for name, rank, rating in Profile.objects.filter( - user__username__in=usernames - ).values_list("user__username", "display_rank", "rating") - } - - -def get_user_from_text(text): - user_list = set() - for i in rereference.finditer(text): - user_list.add(text[i.start() + 6 : i.end() - 1]) - return Profile.objects.filter(user__username__in=user_list) + return {name: (rank, rating) for name, rank, rating in + Profile.objects.filter(user__username__in=usernames) + .values_list('user__username', 'display_rank', 'rating')} reference_map = { - "user": (get_user, get_user_info), - "ruser": (get_user_rating, get_user_info), + 'user': (get_user, get_user_info), + 'ruser': (get_user_rating, get_user_info), } @@ -84,9 +70,9 @@ def process_reference(text): elements = [] for piece in rereference.finditer(text): if prev is None: - tail = text[last : piece.start()] + tail = text[last:piece.start()] else: - prev.append(text[last : piece.start()]) + prev.append(text[last:piece.start()]) prev = list(piece.groups()) elements.append(prev) last = piece.end() @@ -150,52 +136,52 @@ def item_title(item): return item.name elif isinstance(item, Contest): return item.name - return "" + return '' @registry.function -@registry.render_with("user/link.html") -def link_user(user, show_image=False): +@registry.render_with('user/link.html') +def link_user(user): if isinstance(user, Profile): - profile = user + user, profile = user.user, user elif isinstance(user, AbstractUser): profile = user.profile - elif isinstance(user, int): - profile = Profile(id=user) + elif type(user).__name__ == 'ContestRankingProfile': + user, profile = user.user, user else: - raise ValueError("Expected profile or user, got %s" % (type(user),)) - return {"profile": profile, "show_image": show_image} + raise ValueError('Expected profile or user, got %s' % (type(user),)) + return {'user': user, 'profile': profile} @registry.function -@registry.render_with("user/link-list.html") +@registry.render_with('user/link-list.html') def link_users(users): - return {"users": users} + return {'users': users} @registry.function -@registry.render_with("runtime-version-fragment.html") +@registry.render_with('runtime-version-fragment.html') def runtime_versions(versions): - return {"runtime_versions": versions} + return {'runtime_versions': versions} -@registry.filter(name="absolutify") +@registry.filter(name='absolutify') def absolute_links(text, url): tree = lxml_tree.fromstring(text) - for anchor in tree.xpath(".//a"): - href = anchor.get("href") + for anchor in tree.xpath('.//a'): + href = anchor.get('href') if href: - anchor.set("href", urljoin(url, href)) + anchor.set('href', urljoin(url, href)) return tree -@registry.function(name="urljoin") +@registry.function(name='urljoin') def join(first, second, *rest): if not rest: return urljoin(first, second) return urljoin(urljoin(first, second), *rest) -@registry.filter(name="ansi2html") +@registry.filter(name='ansi2html') def ansi2html(s): return mark_safe(Ansi2HTMLConverter(inline=True).convert(s, full=False)) diff --git a/judge/jinja2/registry.py b/judge/jinja2/registry.py index 21d3b85..da12166 100644 --- a/judge/jinja2/registry.py +++ b/judge/jinja2/registry.py @@ -5,7 +5,7 @@ tests = {} filters = {} extensions = [] -__all__ = ["render_with", "function", "filter", "test", "extension"] +__all__ = ['render_with', 'function', 'filter', 'test', 'extension'] def _store_function(store, func, name=None): @@ -16,7 +16,6 @@ def _store_function(store, func, name=None): def _register_function(store, name, func): if name is None and func is None: - def decorator(func): _store_function(store, func) return func @@ -27,7 +26,6 @@ def _register_function(store, name, func): _store_function(store, name) return name else: - def decorator(func): _store_function(store, func, name) return func diff --git a/judge/jinja2/render.py b/judge/jinja2/render.py index bea8c7c..778e26a 100644 --- a/judge/jinja2/render.py +++ b/judge/jinja2/render.py @@ -1,9 +1,5 @@ -from django.template import ( - Context, - Template as DjangoTemplate, - TemplateSyntaxError as DjangoTemplateSyntaxError, - VariableDoesNotExist, -) +from django.template import (Context, Template as DjangoTemplate, TemplateSyntaxError as DjangoTemplateSyntaxError, + VariableDoesNotExist) from . import registry @@ -28,4 +24,4 @@ def render_django(template, **context): try: return compile_template(template).render(Context(context)) except (VariableDoesNotExist, DjangoTemplateSyntaxError): - return "Error rendering: %r" % template + return 'Error rendering: %r' % template diff --git a/judge/jinja2/social.py b/judge/jinja2/social.py index f7ea1c5..9f82971 100644 --- a/judge/jinja2/social.py +++ b/judge/jinja2/social.py @@ -1,29 +1,13 @@ from django.template.loader import get_template from django.utils.safestring import mark_safe -from django_social_share.templatetags.social_share import ( - post_to_facebook_url, - post_to_gplus_url, - post_to_twitter_url, -) +from django_social_share.templatetags.social_share import post_to_facebook_url, post_to_gplus_url, post_to_twitter_url from . import registry SHARES = [ - ( - "post_to_twitter", - "django_social_share/templatetags/post_to_twitter.html", - post_to_twitter_url, - ), - ( - "post_to_facebook", - "django_social_share/templatetags/post_to_facebook.html", - post_to_facebook_url, - ), - ( - "post_to_gplus", - "django_social_share/templatetags/post_to_gplus.html", - post_to_gplus_url, - ), + ('post_to_twitter', 'django_social_share/templatetags/post_to_twitter.html', post_to_twitter_url), + ('post_to_facebook', 'django_social_share/templatetags/post_to_facebook.html', post_to_facebook_url), + ('post_to_gplus', 'django_social_share/templatetags/post_to_gplus.html', post_to_gplus_url), # For future versions: # ('post_to_linkedin', 'django_social_share/templatetags/post_to_linkedin.html', post_to_linkedin_url), # ('post_to_reddit', 'django_social_share/templatetags/post_to_reddit.html', post_to_reddit_url), @@ -33,7 +17,7 @@ SHARES = [ def make_func(name, template, url_func): def func(request, *args): link_text = args[-1] - context = {"request": request, "link_text": mark_safe(link_text)} + context = {'request': request, 'link_text': mark_safe(link_text)} context = url_func(context, *args[:-1]) return mark_safe(get_template(template).render(context)) @@ -47,10 +31,4 @@ for name, template, url_func in SHARES: @registry.function def recaptcha_init(language=None): - return get_template("snowpenguin/recaptcha/recaptcha_init.html").render( - { - "explicit": False, - "language": language, - "recaptcha_host": "https://google.com", - } - ) + return get_template('snowpenguin/recaptcha/recaptcha_init.html').render({'explicit': False, 'language': language}) diff --git a/judge/jinja2/spaceless.py b/judge/jinja2/spaceless.py index 01eb5d8..81c5186 100644 --- a/judge/jinja2/spaceless.py +++ b/judge/jinja2/spaceless.py @@ -1,8 +1,7 @@ import re -from jinja2 import nodes +from jinja2 import Markup, nodes from jinja2.ext import Extension -from markupsafe import Markup class SpacelessExtension(Extension): @@ -16,17 +15,15 @@ class SpacelessExtension(Extension): https://stackoverflow.com/a/23741298/1090657 """ - tags = {"spaceless"} + tags = {'spaceless'} def parse(self, parser): lineno = next(parser.stream).lineno - body = parser.parse_statements(["name:endspaceless"], drop_needle=True) + body = parser.parse_statements(['name:endspaceless'], drop_needle=True) return nodes.CallBlock( - self.call_method("_strip_spaces", [], [], None, None), - [], - [], - body, + self.call_method('_strip_spaces', [], [], None, None), + [], [], body, ).set_lineno(lineno) def _strip_spaces(self, caller=None): - return Markup(re.sub(r">\s+<", "><", caller().unescape().strip())) + return Markup(re.sub(r'>\s+<', '><', caller().unescape().strip())) diff --git a/judge/jinja2/submission.py b/judge/jinja2/submission.py new file mode 100644 index 0000000..f1d352e --- /dev/null +++ b/judge/jinja2/submission.py @@ -0,0 +1,21 @@ +from . import registry + + +@registry.function +def submission_layout(submission, profile_id, user, editable_problem_ids, completed_problem_ids): + problem_id = submission.problem_id + can_view = False + + if problem_id in editable_problem_ids: + can_view = True + + if profile_id == submission.user_id: + can_view = True + + if user.has_perm('judge.change_submission'): + can_view = True + + if submission.problem_id in completed_problem_ids: + can_view |= submission.problem.is_public or profile_id in submission.problem.tester_ids + + return can_view diff --git a/judge/jinja2/timedelta.py b/judge/jinja2/timedelta.py index 95acff6..03fd9db 100644 --- a/judge/jinja2/timedelta.py +++ b/judge/jinja2/timedelta.py @@ -5,14 +5,14 @@ from . import registry @registry.filter -def timedelta(value, display="long"): +def timedelta(value, display='long'): if value is None: return value return nice_repr(value, display) @registry.filter -def timestampdelta(value, display="long"): +def timestampdelta(value, display='long'): value = datetime.timedelta(seconds=value) return timedelta(value, display) @@ -23,8 +23,6 @@ def seconds(timedelta): @registry.filter -@registry.render_with("time-remaining-fragment.html") -def as_countdown(time): - time_now = datetime.datetime.now(datetime.timezone.utc) - initial = abs(time - time_now) - return {"countdown": time, "initial": initial} +@registry.render_with('time-remaining-fragment.html') +def as_countdown(timedelta): + return {'countdown': timedelta} diff --git a/judge/judgeapi.py b/judge/judgeapi.py index 96a2153..ca49460 100644 --- a/judge/judgeapi.py +++ b/judge/judgeapi.py @@ -8,55 +8,47 @@ from django.conf import settings from judge import event_poster as event -logger = logging.getLogger("judge.judgeapi") -size_pack = struct.Struct("!I") +logger = logging.getLogger('judge.judgeapi') +size_pack = struct.Struct('!I') def _post_update_submission(submission, done=False): if submission.problem.is_public: - event.post( - "submissions", - { - "type": "done-submission" if done else "update-submission", - "id": submission.id, - "contest": submission.contest_key, - "user": submission.user_id, - "problem": submission.problem_id, - "status": submission.status, - "language": submission.language.key, - }, - ) + event.post('submissions', {'type': 'done-submission' if done else 'update-submission', + 'id': submission.id, + 'contest': submission.contest_key, + 'user': submission.user_id, 'problem': submission.problem_id, + 'status': submission.status, 'language': submission.language.key}) def judge_request(packet, reply=True): - sock = socket.create_connection( - settings.BRIDGED_DJANGO_CONNECT or settings.BRIDGED_DJANGO_ADDRESS[0] - ) + sock = socket.create_connection(settings.BRIDGED_DJANGO_CONNECT or + settings.BRIDGED_DJANGO_ADDRESS[0]) - output = json.dumps(packet, separators=(",", ":")) - output = zlib.compress(output.encode("utf-8")) - writer = sock.makefile("wb") + output = json.dumps(packet, separators=(',', ':')) + output = zlib.compress(output.encode('utf-8')) + writer = sock.makefile('wb') writer.write(size_pack.pack(len(output))) writer.write(output) writer.close() if reply: - reader = sock.makefile("rb", -1) + reader = sock.makefile('rb', -1) input = reader.read(size_pack.size) if not input: - raise ValueError("Judge did not respond") + raise ValueError('Judge did not respond') length = size_pack.unpack(input)[0] input = reader.read(length) if not input: - raise ValueError("Judge did not respond") + raise ValueError('Judge did not respond') reader.close() sock.close() - result = json.loads(zlib.decompress(input).decode("utf-8")) + result = json.loads(zlib.decompress(input).decode('utf-8')) return result -def judge_submission(submission, rejudge=False, batch_rejudge=False, judge_id=None): +def judge_submission(submission, rejudge, batch_rejudge=False): from .models import ContestSubmission, Submission, SubmissionTestCase CONTEST_SUBMISSION_PRIORITY = 0 @@ -64,23 +56,13 @@ def judge_submission(submission, rejudge=False, batch_rejudge=False, judge_id=No REJUDGE_PRIORITY = 2 BATCH_REJUDGE_PRIORITY = 3 - updates = { - "time": None, - "memory": None, - "points": None, - "result": None, - "error": None, - "was_rejudged": rejudge, - "status": "QU", - } + updates = {'time': None, 'memory': None, 'points': None, 'result': None, 'error': None, + 'was_rejudged': rejudge, 'status': 'QU'} try: # This is set proactively; it might get unset in judgecallback's on_grading_begin if the problem doesn't # actually have pretests stored on the judge. - updates["is_pretested"] = all( - ContestSubmission.objects.filter(submission=submission).values_list( - "problem__contest__run_pretests_only", "problem__is_pretested" - )[0] - ) + updates['is_pretested'] = ContestSubmission.objects.filter(submission=submission) \ + .values_list('problem__contest__run_pretests_only', flat=True)[0] except IndexError: priority = DEFAULT_PRIORITY else: @@ -94,65 +76,42 @@ def judge_submission(submission, rejudge=False, batch_rejudge=False, judge_id=No # as that would prevent people from knowing a submission is being scheduled for rejudging. # It is worth noting that this mechanism does not prevent a new rejudge from being scheduled # while already queued, but that does not lead to data corruption. - if ( - not Submission.objects.filter(id=submission.id) - .exclude(status__in=("P", "G")) - .update(**updates) - ): + if not Submission.objects.filter(id=submission.id).exclude(status__in=('P', 'G')).update(**updates): return False SubmissionTestCase.objects.filter(submission_id=submission.id).delete() try: - response = judge_request( - { - "name": "submission-request", - "submission-id": submission.id, - "problem-id": submission.problem.code, - "language": submission.language.key, - "source": submission.source.source, - "judge-id": judge_id, - "priority": BATCH_REJUDGE_PRIORITY - if batch_rejudge - else REJUDGE_PRIORITY - if rejudge - else priority, - } - ) + response = judge_request({ + 'name': 'submission-request', + 'submission-id': submission.id, + 'problem-id': submission.problem.code, + 'language': submission.language.key, + 'source': submission.source.source, + 'priority': BATCH_REJUDGE_PRIORITY if batch_rejudge else REJUDGE_PRIORITY if rejudge else priority, + }) except BaseException: - logger.exception("Failed to send request to judge") - Submission.objects.filter(id=submission.id).update(status="IE", result="IE") + logger.exception('Failed to send request to judge') + Submission.objects.filter(id=submission.id).update(status='IE') success = False else: - if ( - response["name"] != "submission-received" - or response["submission-id"] != submission.id - ): - Submission.objects.filter(id=submission.id).update(status="IE", result="IE") + if response['name'] != 'submission-received' or response['submission-id'] != submission.id: + Submission.objects.filter(id=submission.id).update(status='IE') _post_update_submission(submission) success = True return success def disconnect_judge(judge, force=False): - judge_request( - {"name": "disconnect-judge", "judge-id": judge.name, "force": force}, - reply=False, - ) + judge_request({'name': 'disconnect-judge', 'judge-id': judge.name, 'force': force}, reply=False) def abort_submission(submission): from .models import Submission - - response = judge_request( - {"name": "terminate-submission", "submission-id": submission.id} - ) - # This defaults to true, so that in the case the JudgeList fails to remove the submission from the queue, + response = judge_request({'name': 'terminate-submission', 'submission-id': submission.id}) + # This defaults to true, so that in the case the judgelist fails to remove the submission from the queue, # and returns a bad-request, the submission is not falsely shown as "Aborted" when it will still be judged. - if not response.get("judge-aborted", True): - Submission.objects.filter(id=submission.id).update(status="AB", result="AB") - event.post( - "sub_%s" % Submission.get_id_secret(submission.id), - {"type": "aborted-submission"}, - ) + if not response.get('judge-aborted', True): + Submission.objects.filter(id=submission.id).update(status='AB', result='AB') + event.post('sub_%s' % Submission.get_id_secret(submission.id), {'type': 'aborted-submission'}) _post_update_submission(submission, done=True) diff --git a/judge/logging.py b/judge/logging.py deleted file mode 100644 index a1a25be..0000000 --- a/judge/logging.py +++ /dev/null @@ -1,12 +0,0 @@ -import logging - -error_log = logging.getLogger("judge.errors") -debug_log = logging.getLogger("judge.debug") - - -def log_exception(msg): - error_log.exception(msg) - - -def log_debug(category, data): - debug_log.info(f"{category}: {data}") diff --git a/judge/lxml_tree.py b/judge/lxml_tree.py index bb71840..014f7dc 100644 --- a/judge/lxml_tree.py +++ b/judge/lxml_tree.py @@ -4,7 +4,7 @@ from django.utils.safestring import SafeData, mark_safe from lxml import html from lxml.etree import ParserError, XMLSyntaxError -logger = logging.getLogger("judge.html") +logger = logging.getLogger('judge.html') class HTMLTreeString(SafeData): @@ -12,11 +12,9 @@ class HTMLTreeString(SafeData): try: self._tree = html.fromstring(str, parser=html.HTMLParser(recover=True)) except (XMLSyntaxError, ParserError) as e: - if str and ( - not isinstance(e, ParserError) or e.args[0] != "Document is empty" - ): - logger.exception("Failed to parse HTML string") - self._tree = html.Element("div") + if str and (not isinstance(e, ParserError) or e.args[0] != 'Document is empty'): + logger.exception('Failed to parse HTML string') + self._tree = html.Element('div') def __getattr__(self, attr): try: @@ -25,15 +23,15 @@ class HTMLTreeString(SafeData): return getattr(str(self), attr) def __setattr__(self, key, value): - if key[0] == "_": + if key[0] == '_': super(HTMLTreeString, self).__setattr__(key, value) setattr(self._tree, key, value) def __repr__(self): - return "" % str(self) + return '' % str(self) def __str__(self): - return mark_safe(html.tostring(self._tree, encoding="unicode")) + return mark_safe(html.tostring(self._tree, encoding='unicode')) def __radd__(self, other): return other + str(self) diff --git a/judge/management/commands/addjudge.py b/judge/management/commands/addjudge.py index f9ad589..b659364 100644 --- a/judge/management/commands/addjudge.py +++ b/judge/management/commands/addjudge.py @@ -4,14 +4,14 @@ from judge.models import Judge class Command(BaseCommand): - help = "create a judge" + help = 'create a judge' def add_arguments(self, parser): - parser.add_argument("name", help="the name of the judge") - parser.add_argument("auth_key", help="authentication key for the judge") + parser.add_argument('name', help='the name of the judge') + parser.add_argument('auth_key', help='authentication key for the judge') def handle(self, *args, **options): judge = Judge() - judge.name = options["name"] - judge.auth_key = options["auth_key"] + judge.name = options['name'] + judge.auth_key = options['auth_key'] judge.save() diff --git a/judge/management/commands/adduser.py b/judge/management/commands/adduser.py index 640625c..f214f4a 100644 --- a/judge/management/commands/adduser.py +++ b/judge/management/commands/adduser.py @@ -6,39 +6,27 @@ from judge.models import Language, Profile class Command(BaseCommand): - help = "creates a user" + help = 'creates a user' def add_arguments(self, parser): - parser.add_argument("name", help="username") - parser.add_argument("email", help="email, not necessary to be resolvable") - parser.add_argument("password", help="password for the user") - parser.add_argument( - "language", - nargs="?", - default=settings.DEFAULT_USER_LANGUAGE, - help="default language ID for user", - ) + parser.add_argument('name', help='username') + parser.add_argument('email', help='email, not necessary to be resolvable') + parser.add_argument('password', help='password for the user') + parser.add_argument('language', nargs='?', default=settings.DEFAULT_USER_LANGUAGE, + help='default language ID for user') - parser.add_argument( - "--superuser", - action="store_true", - default=False, - help="if specified, creates user with superuser privileges", - ) - parser.add_argument( - "--staff", - action="store_true", - default=False, - help="if specified, creates user with staff privileges", - ) + parser.add_argument('--superuser', action='store_true', default=False, + help="if specified, creates user with superuser privileges") + parser.add_argument('--staff', action='store_true', default=False, + help="if specified, creates user with staff privileges") def handle(self, *args, **options): - usr = User(username=options["name"], email=options["email"], is_active=True) - usr.set_password(options["password"]) - usr.is_superuser = options["superuser"] - usr.is_staff = options["staff"] + usr = User(username=options['name'], email=options['email'], is_active=True) + usr.set_password(options['password']) + usr.is_superuser = options['superuser'] + usr.is_staff = options['staff'] usr.save() profile = Profile(user=usr) - profile.language = Language.objects.get(key=options["language"]) + profile.language = Language.objects.get(key=options['language']) profile.save() diff --git a/judge/management/commands/camo.py b/judge/management/commands/camo.py index 774837a..aa65521 100644 --- a/judge/management/commands/camo.py +++ b/judge/management/commands/camo.py @@ -4,13 +4,13 @@ from judge.utils.camo import client as camo_client class Command(BaseCommand): - help = "obtains the camo url for the specified url" + help = 'obtains the camo url for the specified url' def add_arguments(self, parser): - parser.add_argument("url", help="url to use camo on") + parser.add_argument('url', help='url to use camo on') def handle(self, *args, **options): if camo_client is None: - raise CommandError("Camo not available") + raise CommandError('Camo not available') - print(camo_client.image_url(options["url"])) + print(camo_client.image_url(options['url'])) diff --git a/judge/management/commands/copy_language.py b/judge/management/commands/copy_language.py index 09120a6..233ccc7 100644 --- a/judge/management/commands/copy_language.py +++ b/judge/management/commands/copy_language.py @@ -4,30 +4,24 @@ from judge.models import Language, LanguageLimit class Command(BaseCommand): - help = "allows the problems that allow to be submitted in " + help = 'allows the problems that allow to be submitted in ' def add_arguments(self, parser): - parser.add_argument("source", help="language to copy from") - parser.add_argument("target", help="language to copy to") + parser.add_argument('source', help='language to copy from') + parser.add_argument('target', help='language to copy to') def handle(self, *args, **options): try: - source = Language.objects.get(key=options["source"]) + source = Language.objects.get(key=options['source']) except Language.DoesNotExist: - raise CommandError("Invalid source language: %s" % options["source"]) + raise CommandError('Invalid source language: %s' % options['source']) try: - target = Language.objects.get(key=options["target"]) + target = Language.objects.get(key=options['target']) except Language.DoesNotExist: - raise CommandError("Invalid target language: %s" % options["target"]) + raise CommandError('Invalid target language: %s' % options['target']) target.problem_set.set(source.problem_set.all()) - LanguageLimit.objects.bulk_create( - LanguageLimit( - problem=ll.problem, - language=target, - time_limit=ll.time_limit, - memory_limit=ll.memory_limit, - ) - for ll in LanguageLimit.objects.filter(language=source) - ) + LanguageLimit.objects.bulk_create(LanguageLimit(problem=ll.problem, language=target, time_limit=ll.time_limit, + memory_limit=ll.memory_limit) + for ll in LanguageLimit.objects.filter(language=source)) diff --git a/judge/management/commands/create_problem.py b/judge/management/commands/create_problem.py index 568103f..b095e08 100644 --- a/judge/management/commands/create_problem.py +++ b/judge/management/commands/create_problem.py @@ -4,20 +4,20 @@ from judge.models import Problem, ProblemGroup, ProblemType class Command(BaseCommand): - help = "create an empty problem" + help = 'create an empty problem' def add_arguments(self, parser): - parser.add_argument("code", help="problem code") - parser.add_argument("name", help="problem title") - parser.add_argument("body", help="problem description") - parser.add_argument("type", help="problem type") - parser.add_argument("group", help="problem group") + parser.add_argument('code', help='problem code') + parser.add_argument('name', help='problem title') + parser.add_argument('body', help='problem description') + parser.add_argument('type', help='problem type') + parser.add_argument('group', help='problem group') def handle(self, *args, **options): problem = Problem() - problem.code = options["code"] - problem.name = options["name"] - problem.description = options["body"] - problem.group = ProblemGroup.objects.get(name=options["group"]) - problem.types = [ProblemType.objects.get(name=options["type"])] + problem.code = options['code'] + problem.name = options['name'] + problem.description = options['body'] + problem.group = ProblemGroup.objects.get(name=options['group']) + problem.types = [ProblemType.objects.get(name=options['type'])] problem.save() diff --git a/judge/management/commands/generate_data.py b/judge/management/commands/generate_data.py deleted file mode 100644 index 4fcaa4e..0000000 --- a/judge/management/commands/generate_data.py +++ /dev/null @@ -1,59 +0,0 @@ -from django.core.management.base import BaseCommand -from judge.models import * -import csv -import os -from django.conf import settings -from django.db import connection - - -def gen_submissions(): - print("Generating submissions") - query = """ - SELECT user_id as uid, problem_id as pid from - (SELECT user_id, problem_id, max(date) as max_date - from judge_submission - group by user_id, problem_id) t - order by user_id, -max_date; - """ - with connection.cursor() as cursor: - cursor.execute(query) - headers = [i[0] for i in cursor.description] - with open( - os.path.join(settings.ML_DATA_PATH, "submissions.csv"), "w" - ) as csvfile: - f = csv.writer(csvfile) - f.writerow(headers) - for row in cursor.fetchall(): - f.writerow(row) - - -def gen_users(): - print("Generating users") - headers = ["uid", "username", "rating", "points"] - with open(os.path.join(settings.ML_DATA_PATH, "profiles.csv"), "w") as csvfile: - f = csv.writer(csvfile) - f.writerow(headers) - - for u in Profile.objects.all().iterator(): - f.writerow([u.id, u.username, u.rating, u.performance_points]) - - -def gen_problems(): - print("Generating problems") - headers = ["pid", "code", "name", "points", "url"] - with open(os.path.join(settings.ML_DATA_PATH, "problems.csv"), "w") as csvfile: - f = csv.writer(csvfile) - f.writerow(headers) - for p in Problem.objects.all().iterator(): - f.writerow( - [p.id, p.code, p.name, p.points, "lqdoj.edu.vn/problem/" + p.code] - ) - - -class Command(BaseCommand): - help = "generate data for ML" - - def handle(self, *args, **options): - gen_users() - gen_problems() - gen_submissions() diff --git a/judge/management/commands/makedmojmessages.py b/judge/management/commands/makedmojmessages.py index 5c2a9ba..55d3acc 100644 --- a/judge/management/commands/makedmojmessages.py +++ b/judge/management/commands/makedmojmessages.py @@ -5,69 +5,33 @@ import sys from django.conf import settings from django.core.management import CommandError -from django.core.management.commands.makemessages import ( - Command as MakeMessagesCommand, - check_programs, -) +from django.core.management.commands.makemessages import Command as MakeMessagesCommand, check_programs from judge.models import NavigationBar, ProblemType class Command(MakeMessagesCommand): def add_arguments(self, parser): - parser.add_argument( - "--locale", - "-l", - default=[], - dest="locale", - action="append", - help="Creates or updates the message files for the given locale(s) (e.g. pt_BR). " - "Can be used multiple times.", - ) - parser.add_argument( - "--exclude", - "-x", - default=[], - dest="exclude", - action="append", - help="Locales to exclude. Default is none. Can be used multiple times.", - ) - parser.add_argument( - "--all", - "-a", - action="store_true", - dest="all", - default=False, - help="Updates the message files for all existing locales.", - ) - parser.add_argument( - "--no-wrap", - action="store_true", - dest="no_wrap", - default=False, - help="Don't break long message lines into several lines.", - ) - parser.add_argument( - "--no-obsolete", - action="store_true", - dest="no_obsolete", - default=False, - help="Remove obsolete message strings.", - ) - parser.add_argument( - "--keep-pot", - action="store_true", - dest="keep_pot", - default=False, - help="Keep .pot file after making messages. Useful when debugging.", - ) + parser.add_argument('--locale', '-l', default=[], dest='locale', action='append', + help='Creates or updates the message files for the given locale(s) (e.g. pt_BR). ' + 'Can be used multiple times.') + parser.add_argument('--exclude', '-x', default=[], dest='exclude', action='append', + help='Locales to exclude. Default is none. Can be used multiple times.') + parser.add_argument('--all', '-a', action='store_true', dest='all', + default=False, help='Updates the message files for all existing locales.') + parser.add_argument('--no-wrap', action='store_true', dest='no_wrap', + default=False, help="Don't break long message lines into several lines.") + parser.add_argument('--no-obsolete', action='store_true', dest='no_obsolete', + default=False, help="Remove obsolete message strings.") + parser.add_argument('--keep-pot', action='store_true', dest='keep_pot', + default=False, help="Keep .pot file after making messages. Useful when debugging.") def handle(self, *args, **options): - locale = options.get("locale") - exclude = options.get("exclude") - self.domain = "dmoj-user" - self.verbosity = options.get("verbosity") - process_all = options.get("all") + locale = options.get('locale') + exclude = options.get('exclude') + self.domain = 'dmoj-user' + self.verbosity = options.get('verbosity') + process_all = options.get('all') # Need to ensure that the i18n framework is enabled if settings.configured: @@ -76,47 +40,43 @@ class Command(MakeMessagesCommand): settings.configure(USE_I18N=True) # Avoid messing with mutable class variables - if options.get("no_wrap"): - self.msgmerge_options = self.msgmerge_options[:] + ["--no-wrap"] - self.msguniq_options = self.msguniq_options[:] + ["--no-wrap"] - self.msgattrib_options = self.msgattrib_options[:] + ["--no-wrap"] - self.xgettext_options = self.xgettext_options[:] + ["--no-wrap"] - if options.get("no_location"): - self.msgmerge_options = self.msgmerge_options[:] + ["--no-location"] - self.msguniq_options = self.msguniq_options[:] + ["--no-location"] - self.msgattrib_options = self.msgattrib_options[:] + ["--no-location"] - self.xgettext_options = self.xgettext_options[:] + ["--no-location"] + if options.get('no_wrap'): + self.msgmerge_options = self.msgmerge_options[:] + ['--no-wrap'] + self.msguniq_options = self.msguniq_options[:] + ['--no-wrap'] + self.msgattrib_options = self.msgattrib_options[:] + ['--no-wrap'] + self.xgettext_options = self.xgettext_options[:] + ['--no-wrap'] + if options.get('no_location'): + self.msgmerge_options = self.msgmerge_options[:] + ['--no-location'] + self.msguniq_options = self.msguniq_options[:] + ['--no-location'] + self.msgattrib_options = self.msgattrib_options[:] + ['--no-location'] + self.xgettext_options = self.xgettext_options[:] + ['--no-location'] - self.no_obsolete = options.get("no_obsolete") - self.keep_pot = options.get("keep_pot") + self.no_obsolete = options.get('no_obsolete') + self.keep_pot = options.get('keep_pot') if locale is None and not exclude and not process_all: - raise CommandError( - "Type '%s help %s' for usage information." - % (os.path.basename(sys.argv[0]), sys.argv[1]) - ) + raise CommandError("Type '%s help %s' for usage information." % ( + os.path.basename(sys.argv[0]), sys.argv[1])) self.invoked_for_django = False self.locale_paths = [] self.default_locale_path = None - if os.path.isdir(os.path.join("conf", "locale")): - self.locale_paths = [os.path.abspath(os.path.join("conf", "locale"))] + if os.path.isdir(os.path.join('conf', 'locale')): + self.locale_paths = [os.path.abspath(os.path.join('conf', 'locale'))] self.default_locale_path = self.locale_paths[0] self.invoked_for_django = True else: self.locale_paths.extend(settings.LOCALE_PATHS) # Allow to run makemessages inside an app dir - if os.path.isdir("locale"): - self.locale_paths.append(os.path.abspath("locale")) + if os.path.isdir('locale'): + self.locale_paths.append(os.path.abspath('locale')) if self.locale_paths: self.default_locale_path = self.locale_paths[0] if not os.path.exists(self.default_locale_path): os.makedirs(self.default_locale_path) # Build locale list - locale_dirs = list( - filter(os.path.isdir, glob.glob("%s/*" % self.default_locale_path)) - ) + locale_dirs = list(filter(os.path.isdir, glob.glob('%s/*' % self.default_locale_path))) all_locales = list(map(os.path.basename, locale_dirs)) # Account for excluded locales @@ -127,9 +87,9 @@ class Command(MakeMessagesCommand): locales = set(locales) - set(exclude) if locales: - check_programs("msguniq", "msgmerge", "msgattrib") + check_programs('msguniq', 'msgmerge', 'msgattrib') - check_programs("xgettext") + check_programs('xgettext') try: potfiles = self.build_potfiles() @@ -148,41 +108,23 @@ class Command(MakeMessagesCommand): return [] def _emit_message(self, potfile, string): - potfile.write( - """ + potfile.write(''' msgid "%s" msgstr "" -""" - % string.replace("\\", r"\\") - .replace("\t", "\\t") - .replace("\n", "\\n") - .replace('"', '\\"') - ) +''' % string.replace('\\', r'\\').replace('\t', '\\t').replace('\n', '\\n').replace('"', '\\"')) def process_files(self, file_list): - with io.open( - os.path.join(self.default_locale_path, "dmoj-user.pot"), - "w", - encoding="utf-8", - ) as potfile: - potfile.write( - """ -msgid "" -msgstr "" - -"Content-Type: text/plain; charset=utf-8\\n" - """ - ) + with io.open(os.path.join(self.default_locale_path, 'dmoj-user.pot'), 'w', encoding='utf-8') as potfile: if self.verbosity > 1: - self.stdout.write("processing navigation bar") - for label in NavigationBar.objects.values_list("label", flat=True): + self.stdout.write('processing navigation bar') + for label in NavigationBar.objects.values_list('label', flat=True): if self.verbosity > 2: self.stdout.write('processing navigation item label "%s"\n' % label) self._emit_message(potfile, label) if self.verbosity > 1: - self.stdout.write("processing problem types") - for name in ProblemType.objects.values_list("full_name", flat=True): + self.stdout.write('processing problem types') + for name in ProblemType.objects.values_list('full_name', flat=True): if self.verbosity > 2: self.stdout.write('processing problem type name "%s"\n' % name) self._emit_message(potfile, name) diff --git a/judge/management/commands/render_pdf.py b/judge/management/commands/render_pdf.py index 87324b4..cc45421 100644 --- a/judge/management/commands/render_pdf.py +++ b/judge/management/commands/render_pdf.py @@ -8,97 +8,51 @@ from django.template.loader import get_template from django.utils import translation from judge.models import Problem, ProblemTranslation -from judge.pdf_problems import ( - DefaultPdfMaker, - PhantomJSPdfMaker, - PuppeteerPDFRender, - SeleniumPDFRender, - SlimerJSPdfMaker, -) +from judge.pdf_problems import DefaultPdfMaker, PhantomJSPdfMaker, PuppeteerPDFRender, SlimerJSPdfMaker class Command(BaseCommand): - help = "renders a PDF file of a problem" + help = 'renders a PDF file of a problem' def add_arguments(self, parser): - parser.add_argument("code", help="code of problem to render") - parser.add_argument( - "directory", nargs="?", help="directory to store temporaries" - ) - parser.add_argument( - "-l", - "--language", - default=settings.LANGUAGE_CODE, - help="language to render PDF in", - ) - parser.add_argument( - "-p", - "--phantomjs", - action="store_const", - const=PhantomJSPdfMaker, - default=DefaultPdfMaker, - dest="engine", - ) - parser.add_argument( - "-s", - "--slimerjs", - action="store_const", - const=SlimerJSPdfMaker, - dest="engine", - ) - parser.add_argument( - "-c", - "--chrome", - "--puppeteer", - action="store_const", - const=PuppeteerPDFRender, - dest="engine", - ) - parser.add_argument( - "-S", - "--selenium", - action="store_const", - const=SeleniumPDFRender, - dest="engine", - ) + parser.add_argument('code', help='code of problem to render') + parser.add_argument('directory', nargs='?', help='directory to store temporaries') + parser.add_argument('-l', '--language', default=settings.LANGUAGE_CODE, + help='language to render PDF in') + parser.add_argument('-p', '--phantomjs', action='store_const', const=PhantomJSPdfMaker, + default=DefaultPdfMaker, dest='engine') + parser.add_argument('-s', '--slimerjs', action='store_const', const=SlimerJSPdfMaker, dest='engine') + parser.add_argument('-c', '--chrome', '--puppeteer', action='store_const', + const=PuppeteerPDFRender, dest='engine') def handle(self, *args, **options): try: - problem = Problem.objects.get(code=options["code"]) + problem = Problem.objects.get(code=options['code']) except Problem.DoesNotExist: - print("Bad problem code") + print('Bad problem code') return try: - trans = problem.translations.get(language=options["language"]) + trans = problem.translations.get(language=options['language']) except ProblemTranslation.DoesNotExist: trans = None - directory = options["directory"] - with options["engine"]( - directory, clean_up=directory is None - ) as maker, translation.override(options["language"]): + directory = options['directory'] + with options['engine'](directory, clean_up=directory is None) as maker, \ + translation.override(options['language']): problem_name = problem.name if trans is None else trans.name - maker.html = ( - get_template("problem/raw.html") - .render( - { - "problem": problem, - "problem_name": problem_name, - "description": problem.description - if trans is None - else trans.description, - "url": "", - } - ) - .replace('"//', '"https://') - .replace("'//", "'https://") - ) + maker.html = get_template('problem/raw.html').render({ + 'problem': problem, + 'problem_name': problem_name, + 'description': problem.description if trans is None else trans.description, + 'url': '', + 'math_engine': maker.math_engine, + }).replace('"//', '"https://').replace("'//", "'https://") maker.title = problem_name - for file in "style.css": + for file in ('style.css', 'pygment-github.css', 'mathjax_config.js'): maker.load(file, os.path.join(settings.DMOJ_RESOURCES, file)) maker.make(debug=True) if not maker.success: print(maker.log, file=sys.stderr) elif directory is None: - shutil.move(maker.pdffile, problem.code + ".pdf") + shutil.move(maker.pdffile, problem.code + '.pdf') diff --git a/judge/management/commands/runbridged.py b/judge/management/commands/runbridged.py index b968d63..f20a9fe 100644 --- a/judge/management/commands/runbridged.py +++ b/judge/management/commands/runbridged.py @@ -1,8 +1,33 @@ +import threading + +from django.conf import settings from django.core.management.base import BaseCommand -from judge.bridge.daemon import judge_daemon +from judge.bridge import DjangoHandler, DjangoServer +from judge.bridge import DjangoJudgeHandler, JudgeServer class Command(BaseCommand): def handle(self, *args, **options): - judge_daemon() + judge_handler = DjangoJudgeHandler + + try: + import netaddr # noqa: F401, imported to see if it exists + except ImportError: + pass + else: + proxies = settings.BRIDGED_JUDGE_PROXIES + if proxies: + judge_handler = judge_handler.with_proxy_set(proxies) + + judge_server = JudgeServer(settings.BRIDGED_JUDGE_ADDRESS, judge_handler) + django_server = DjangoServer(judge_server.judges, settings.BRIDGED_DJANGO_ADDRESS, DjangoHandler) + + # TODO: Merge the two servers + threading.Thread(target=django_server.serve_forever).start() + try: + judge_server.serve_forever() + except KeyboardInterrupt: + pass + finally: + django_server.stop() diff --git a/judge/management/commands/runmoss.py b/judge/management/commands/runmoss.py index c8d026c..9b2d40c 100644 --- a/judge/management/commands/runmoss.py +++ b/judge/management/commands/runmoss.py @@ -6,50 +6,41 @@ from judge.models import Contest, ContestParticipation, Submission class Command(BaseCommand): - help = "Checks for duplicate code using MOSS" + help = 'Checks for duplicate code using MOSS' LANG_MAPPING = { - ("C++", MOSS_LANG_CC), - ("C", MOSS_LANG_C), - ("Java", MOSS_LANG_JAVA), - ("Python", MOSS_LANG_PYTHON), - ("Pascal", MOSS_LANG_PASCAL), + ('C++', MOSS_LANG_CC), + ('C', MOSS_LANG_C), + ('Java', MOSS_LANG_JAVA), + ('Python', MOSS_LANG_PYTHON), } def add_arguments(self, parser): - parser.add_argument("contest", help="the id of the contest") + parser.add_argument('contest', help='the id of the contest') def handle(self, *args, **options): moss_api_key = settings.MOSS_API_KEY if moss_api_key is None: - print("No MOSS API Key supplied") + print('No MOSS API Key supplied') return - contest = options["contest"] + contest = options['contest'] - for problem in Contest.objects.get(key=contest).problems.order_by("code"): - print("========== %s / %s ==========" % (problem.code, problem.name)) + for problem in Contest.objects.get(key=contest).problems.order_by('code'): + print('========== %s / %s ==========' % (problem.code, problem.name)) for dmoj_lang, moss_lang in self.LANG_MAPPING: - print("%s: " % dmoj_lang, end=" ") + print("%s: " % dmoj_lang, end=' ') subs = Submission.objects.filter( - contest__participation__virtual__in=( - ContestParticipation.LIVE, - ContestParticipation.SPECTATE, - ), + contest__participation__virtual__in=(ContestParticipation.LIVE, ContestParticipation.SPECTATE), contest__participation__contest__key=contest, - result="AC", - problem__id=problem.id, + result='AC', problem__id=problem.id, language__common_name=dmoj_lang, - ).values_list("user__user__username", "source__source") + ).values_list('user__user__username', 'source__source') if not subs: - print("") + print('') continue - moss_call = MOSS( - moss_api_key, - language=moss_lang, - matching_file_limit=100, - comment="%s - %s" % (contest, problem.code), - ) + moss_call = MOSS(moss_api_key, language=moss_lang, matching_file_limit=100, + comment='%s - %s' % (contest, problem.code)) users = set() @@ -57,6 +48,6 @@ class Command(BaseCommand): if username in users: continue users.add(username) - moss_call.add_file_from_memory(username, source.encode("utf-8")) + moss_call.add_file_from_memory(username, source.encode('utf-8')) - print("(%d): %s" % (subs.count(), moss_call.process())) + print('(%d): %s' % (subs.count(), moss_call.process())) diff --git a/judge/markdown.py b/judge/markdown.py deleted file mode 100644 index 80eb21a..0000000 --- a/judge/markdown.py +++ /dev/null @@ -1,149 +0,0 @@ -import markdown as _markdown -import bleach -from django.utils.html import escape -from bs4 import BeautifulSoup -from pymdownx import superfences -from django.conf import settings -from urllib.parse import urlparse - -from judge.markdown_extensions import YouTubeExtension, EmoticonExtension - - -EXTENSIONS = [ - "pymdownx.arithmatex", - "pymdownx.magiclink", - "pymdownx.betterem", - "pymdownx.details", - "pymdownx.emoji", - "pymdownx.inlinehilite", - "pymdownx.superfences", - "pymdownx.highlight", - "pymdownx.tasklist", - "markdown.extensions.footnotes", - "markdown.extensions.attr_list", - "markdown.extensions.def_list", - "markdown.extensions.tables", - "markdown.extensions.admonition", - "nl2br", - "mdx_breakless_lists", - YouTubeExtension(), - EmoticonExtension(), -] - -EXTENSION_CONFIGS = { - "pymdownx.arithmatex": { - "generic": True, - }, - "pymdownx.superfences": { - "custom_fences": [ - { - "name": "sample", - "class": "no-border", - "format": superfences.fence_code_format, - } - ], - }, - "pymdownx.highlight": { - "auto_title": True, - "auto_title_map": { - "Text Only": "", - }, - }, -} - -ALLOWED_TAGS = list(bleach.sanitizer.ALLOWED_TAGS) + [ - "img", - "center", - "iframe", - "div", - "span", - "table", - "tr", - "td", - "th", - "tr", - "pre", - "code", - "p", - "hr", - "h1", - "h2", - "h3", - "h4", - "h5", - "h6", - "thead", - "tbody", - "sup", - "dl", - "dt", - "dd", - "br", - "details", - "summary", -] - -ALLOWED_ATTRS = [ - "src", - "width", - "height", - "href", - "class", - "open", - "title", - "frameborder", - "allow", - "allowfullscreen", - "loading", -] - - -def _wrap_img_iframe_with_lazy_load(soup): - for img in soup.findAll("img"): - if img.get("src"): - img["loading"] = "lazy" - for img in soup.findAll("iframe"): - if img.get("src"): - img["loading"] = "lazy" - return soup - - -def _wrap_images_with_featherlight(soup): - for img in soup.findAll("img"): - if img.get("src"): - link = soup.new_tag("a", href=img["src"], **{"data-featherlight": "image"}) - img.wrap(link) - return soup - - -def _open_external_links_in_new_tab(soup): - domain = settings.SITE_DOMAIN.lower() - for a in soup.findAll("a", href=True): - href = a["href"] - if href.startswith("http://") or href.startswith("https://"): - link_domain = urlparse(href).netloc.lower() - if link_domain != domain: - a["target"] = "_blank" - return soup - - -def markdown(value, lazy_load=False): - extensions = EXTENSIONS - html = _markdown.markdown( - value, extensions=extensions, extension_configs=EXTENSION_CONFIGS - ) - - html = bleach.clean(html, tags=ALLOWED_TAGS, attributes=ALLOWED_ATTRS) - - if not html: - html = escape(value) - - soup = BeautifulSoup(html, features="html.parser") - if lazy_load: - soup = _wrap_img_iframe_with_lazy_load(soup) - - soup = _wrap_images_with_featherlight(soup) - soup = _open_external_links_in_new_tab(soup) - html = str(soup) - - return '
%s
' % html diff --git a/judge/markdown_extensions/__init__.py b/judge/markdown_extensions/__init__.py deleted file mode 100644 index bc405f3..0000000 --- a/judge/markdown_extensions/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .youtube import YouTubeExtension -from .emoticon import EmoticonExtension diff --git a/judge/markdown_extensions/emoticon.py b/judge/markdown_extensions/emoticon.py deleted file mode 100644 index 809b1d3..0000000 --- a/judge/markdown_extensions/emoticon.py +++ /dev/null @@ -1,112 +0,0 @@ -import markdown -from markdown.extensions import Extension -from markdown.inlinepatterns import InlineProcessor -import xml.etree.ElementTree as etree -import re - -EMOTICON_EMOJI_MAP = { - ":D": "\U0001F603", # Smiling Face with Open Mouth - ":)": "\U0001F642", # Slightly Smiling Face - ":-)": "\U0001F642", # Slightly Smiling Face with Nose - ":(": "\U0001F641", # Slightly Frowning Face - ":-(": "\U0001F641", # Slightly Frowning Face with Nose - ";)": "\U0001F609", # Winking Face - ";-)": "\U0001F609", # Winking Face with Nose - ":P": "\U0001F61B", # Face with Tongue - ":-P": "\U0001F61B", # Face with Tongue and Nose - ":p": "\U0001F61B", # Face with Tongue - ":-p": "\U0001F61B", # Face with Tongue and Nose - ";P": "\U0001F61C", # Winking Face with Tongue - ";-P": "\U0001F61C", # Winking Face with Tongue and Nose - ";p": "\U0001F61C", # Winking Face with Tongue - ";-p": "\U0001F61C", # Winking Face with Tongue and Nose - ":'(": "\U0001F622", # Crying Face - ":o": "\U0001F62E", # Face with Open Mouth - ":-o": "\U0001F62E", # Face with Open Mouth and Nose - ":O": "\U0001F62E", # Face with Open Mouth - ":-O": "\U0001F62E", # Face with Open Mouth and Nose - ":-0": "\U0001F62E", # Face with Open Mouth and Nose - ">:(": "\U0001F620", # Angry Face - ">:-(": "\U0001F620", # Angry Face with Nose - ">:)": "\U0001F608", # Smiling Face with Horns - ">:-)": "\U0001F608", # Smiling Face with Horns and Nose - "XD": "\U0001F606", # Grinning Squinting Face - "xD": "\U0001F606", # Grinning Squinting Face - "B)": "\U0001F60E", # Smiling Face with Sunglasses - "B-)": "\U0001F60E", # Smiling Face with Sunglasses and Nose - "O:)": "\U0001F607", # Smiling Face with Halo - "O:-)": "\U0001F607", # Smiling Face with Halo and Nose - "0:)": "\U0001F607", # Smiling Face with Halo - "0:-)": "\U0001F607", # Smiling Face with Halo and Nose - ">:P": "\U0001F92A", # Zany Face (sticking out tongue and winking) - ">:-P": "\U0001F92A", # Zany Face with Nose - ">:p": "\U0001F92A", # Zany Face (sticking out tongue and winking) - ">:-p": "\U0001F92A", # Zany Face with Nose - ":/": "\U0001F615", # Confused Face - ":-/": "\U0001F615", # Confused Face with Nose - ":\\": "\U0001F615", # Confused Face - ":-\\": "\U0001F615", # Confused Face with Nose - "3:)": "\U0001F608", # Smiling Face with Horns - "3:-)": "\U0001F608", # Smiling Face with Horns and Nose - "<3": "\u2764\uFE0F", # Red Heart - ":P": "\U0001F61D", # Face with Stuck-Out Tongue and Tightly-Closed Eyes - ":-/": "\U0001F615", # Confused Face - ":/": "\U0001F615", - ":\\": "\U0001F615", - ":-\\": "\U0001F615", - ":|": "\U0001F610", # Neutral Face - ":-|": "\U0001F610", - "8)": "\U0001F60E", # Smiling Face with Sunglasses - "8-)": "\U0001F60E", - "O:)": "\U0001F607", # Smiling Face with Halo - "O:-)": "\U0001F607", - ":3": "\U0001F60A", # Smiling Face with Smiling Eyes - "^.^": "\U0001F60A", - "-_-": "\U0001F611", # Expressionless Face - "T_T": "\U0001F62D", # Loudly Crying Face - "T.T": "\U0001F62D", - ">.<": "\U0001F623", # Persevering Face - "x_x": "\U0001F635", # Dizzy Face - "X_X": "\U0001F635", - ":]": "\U0001F600", # Grinning Face - ":[": "\U0001F641", # Slightly Frowning Face - "=]": "\U0001F600", - "=[": "\U0001F641", - "D:<": "\U0001F621", # Pouting Face - "D:": "\U0001F629", # Weary Face - "D=": "\U0001F6AB", # No Entry Sign (sometimes used to denote dismay or frustration) - ":'D": "\U0001F602", # Face with Tears of Joy - "D':": "\U0001F625", # Disappointed but Relieved Face - "D8": "\U0001F631", # Face Screaming in Fear - "-.-": "\U0001F644", # Face with Rolling Eyes - "-_-;": "\U0001F612", # Unamused -} - - -class EmoticonEmojiInlineProcessor(InlineProcessor): - def handleMatch(self, m, data): - emoticon = m.group(1) - emoji = EMOTICON_EMOJI_MAP.get(emoticon, "") - if emoji: - el = etree.Element("span") - el.text = markdown.util.AtomicString(emoji) - el.set("class", "big-emoji") - return el, m.start(0), m.end(0) - else: - return None, m.start(0), m.end(0) - - -class EmoticonExtension(Extension): - def extendMarkdown(self, md): - emoticon_pattern = ( - r"(?:(?<=\s)|^)" # Lookbehind for a whitespace character or the start of the string - r"(" + "|".join(map(re.escape, EMOTICON_EMOJI_MAP.keys())) + r")" - r"(?=\s|$)" # Lookahead for a whitespace character or the end of the string - ) - emoticon_processor = EmoticonEmojiInlineProcessor(emoticon_pattern, md) - md.inlinePatterns.register(emoticon_processor, "emoticon_to_emoji", 1) diff --git a/judge/markdown_extensions/youtube.py b/judge/markdown_extensions/youtube.py deleted file mode 100644 index 89a9fa8..0000000 --- a/judge/markdown_extensions/youtube.py +++ /dev/null @@ -1,36 +0,0 @@ -import markdown -from markdown.inlinepatterns import InlineProcessor -from markdown.extensions import Extension -import xml.etree.ElementTree as etree - -YOUTUBE_REGEX = ( - r"(https?://)?(www\.)?" "(youtube\.com/watch\?v=|youtu\.be/)" "([\w-]+)(&[\w=]*)?" -) - - -class YouTubeEmbedProcessor(InlineProcessor): - def handleMatch(self, m, data): - youtube_id = m.group(4) - if not youtube_id: - return None, None, None - - # Create an iframe element with the YouTube embed URL - iframe = etree.Element("iframe") - iframe.set("width", "100%") - iframe.set("height", "360") - iframe.set("src", f"https://www.youtube.com/embed/{youtube_id}") - iframe.set("frameborder", "0") - iframe.set("allowfullscreen", "true") - center = etree.Element("center") - center.append(iframe) - - # Return the iframe as the element to replace the match, along with the start and end indices - return center, m.start(0), m.end(0) - - -class YouTubeExtension(Extension): - def extendMarkdown(self, md): - # Create the YouTube link pattern - YOUTUBE_PATTERN = YouTubeEmbedProcessor(YOUTUBE_REGEX, md) - # Register the pattern to apply the YouTubeEmbedProcessor - md.inlinePatterns.register(YOUTUBE_PATTERN, "youtube", 175) diff --git a/judge/middleware.py b/judge/middleware.py index c08b2b9..4a58882 100644 --- a/judge/middleware.py +++ b/judge/middleware.py @@ -1,23 +1,7 @@ -import time -import logging -import random -import json -from datetime import datetime - from django.conf import settings -from django.http import HttpResponseRedirect, Http404 +from django.http import HttpResponseRedirect from django.urls import Resolver404, resolve, reverse from django.utils.http import urlquote -from django.contrib.sites.shortcuts import get_current_site -from django.core.exceptions import ObjectDoesNotExist -from django.utils.translation import gettext as _ - -from judge.models import Organization -from judge.utils.views import generic_message - - -USED_DOMAINS = ["www"] -URL_NAMES_BYPASS_SUBDOMAIN = ["submission_source_file"] class ShortCircuitMiddleware: @@ -26,13 +10,11 @@ class ShortCircuitMiddleware: def __call__(self, request): try: - callback, args, kwargs = resolve( - request.path_info, getattr(request, "urlconf", None) - ) + callback, args, kwargs = resolve(request.path_info, getattr(request, 'urlconf', None)) except Resolver404: callback, args, kwargs = None, None, None - if getattr(callback, "short_circuit_middleware", False): + if getattr(callback, 'short_circuit_middleware', False): return callback(request, *args, **kwargs) return self.get_response(request) @@ -44,16 +26,11 @@ class DMOJLoginMiddleware(object): def __call__(self, request): if request.user.is_authenticated: profile = request.profile = request.user.profile - login_2fa_path = reverse("login_2fa") - if ( - profile.is_totp_enabled - and not request.session.get("2fa_passed", False) - and request.path not in (login_2fa_path, reverse("auth_logout")) - and not request.path.startswith(settings.STATIC_URL) - ): - return HttpResponseRedirect( - login_2fa_path + "?next=" + urlquote(request.get_full_path()) - ) + login_2fa_path = reverse('login_2fa') + if (profile.is_totp_enabled and not request.session.get('2fa_passed', False) and + request.path not in (login_2fa_path, reverse('auth_logout')) and + not request.path.startswith(settings.STATIC_URL)): + return HttpResponseRedirect(login_2fa_path + '?next=' + urlquote(request.get_full_path())) else: request.profile = None return self.get_response(request) @@ -80,101 +57,7 @@ class ContestMiddleware(object): profile.update_contest() request.participation = profile.current_contest request.in_contest = request.participation is not None - request.contest_mode = request.session.get("contest_mode", True) else: request.in_contest = False request.participation = None - request.in_contest_mode = request.in_contest and request.contest_mode return self.get_response(request) - - -class DarkModeMiddleware(object): - def __init__(self, get_response): - self.get_response = get_response - - def __call__(self, request): - if "darkmode" in request.GET: - return HttpResponseRedirect( - reverse("toggle_darkmode") + "?next=" + urlquote(request.path) - ) - return self.get_response(request) - - -class SubdomainMiddleware(object): - def __init__(self, get_response): - self.get_response = get_response - - def __call__(self, request): - request.organization = None - if not settings.USE_SUBDOMAIN: - return self.get_response(request) - - domain = request.get_host() - site = get_current_site(request).domain - subdomain = domain[: len(domain) - len(site)].lower() - - if len(subdomain) <= 1: - return self.get_response(request) - - subdomain = subdomain[:-1] - - if ( - subdomain in USED_DOMAINS - or resolve(request.path).url_name in URL_NAMES_BYPASS_SUBDOMAIN - ): - return self.get_response(request) - - try: - organization = Organization.objects.get(slug=subdomain) - if request.profile and organization in request.profile.organizations.all(): - request.organization = organization - else: - if request.profile: - return generic_message( - request, - _("No permission"), - _("You need to join this group first"), - status=404, - ) - if not request.GET.get("next", None): - return HttpResponseRedirect( - reverse("auth_login") + "?next=" + urlquote(request.path) - ) - except ObjectDoesNotExist: - return generic_message( - request, - _("No such group"), - _("No such group"), - status=404, - ) - return self.get_response(request) - - -class SlowRequestMiddleware(object): - def __init__(self, get_response): - self.get_response = get_response - - def __call__(self, request): - logger = logging.getLogger("judge.request_time") - logger_slow = logging.getLogger("judge.slow_request") - start_time = time.time() - response = self.get_response(request) - if response.status_code == 200: - try: - response_time = time.time() - start_time - url_name = resolve(request.path).url_name - message = { - "url_name": url_name, - "response_time": response_time * 1000, - "profile": request.user.username, - "date": datetime.now().strftime("%Y/%m/%d"), - "url": request.build_absolute_uri(), - "method": request.method, - } - if response_time > 9: - logger_slow.info(json.dumps(message)) - if random.random() < 0.1: - logger.info(json.dumps(message)) - except Exception: - pass - return response diff --git a/judge/migrations/0001_squashed_0084_contest_formats.py b/judge/migrations/0001_squashed_0084_contest_formats.py index ae4e6ae..22aa659 100644 --- a/judge/migrations/0001_squashed_0084_contest_formats.py +++ b/judge/migrations/0001_squashed_0084_contest_formats.py @@ -14,3275 +14,748 @@ import judge.utils.problem_data class Migration(migrations.Migration): - replaces = [ - ("judge", "0001_initial"), - ("judge", "0002_license"), - ("judge", "0003_license_key"), - ("judge", "0004_language_limit"), - ("judge", "0005_nav_path_len"), - ("judge", "0006_language_extension"), - ("judge", "0007_test_site_perm"), - ("judge", "0008_contestproblem_order"), - ("judge", "0009_solution_problem"), - ("judge", "0010_comment_page_index"), - ("judge", "0011_organization_is_open"), - ("judge", "0012_organization_perms"), - ("judge", "0013_private_contests"), - ("judge", "0014_multi_organization"), - ("judge", "0015_remove_single_organization"), - ("judge", "0016_organizationrequest"), - ("judge", "0017_edit_public_problem_perm"), - ("judge", "0018_django_1_9"), - ("judge", "0019_og_images"), - ("judge", "0020_profile_user_script"), - ("judge", "0021_output_prefix_override"), - ("judge", "0022_judge_last_ping"), - ("judge", "0023_contest_tag"), - ("judge", "0024_submission_judge"), - ("judge", "0025_submission_rejudge_flag"), - ("judge", "0026_change_public_visibility_perm"), - ("judge", "0027_bridge_revert"), - ("judge", "0028_judge_ip"), - ("judge", "0029_problem_translation"), - ("judge", "0030_remove_contest_profile"), - ("judge", "0031_judge_versions"), - ("judge", "0032_hide_problem_tags_in_contest"), - ("judge", "0033_proper_pretest_support"), - ("judge", "0034_submission_is_pretested"), - ("judge", "0035_contest_spectate_mode"), - ("judge", "0036_contest_participation_unique"), - ("judge", "0037_user_count_ac_rate_field"), - ("judge", "0038_profile_problem_count"), - ("judge", "0039_remove_contest_is_external"), - ("judge", "0040_profile_math_engine"), - ("judge", "0041_virtual_contest_participation"), - ("judge", "0042_remove_spectate_field"), - ("judge", "0043_contest_user_count"), - ("judge", "0044_organization_slots"), - ("judge", "0045_organization_access_code"), - ("judge", "0046_blogpost_authors"), - ("judge", "0047_site_managed_data"), - ("judge", "0048_site_managed_checkers"), - ("judge", "0049_contest_summary"), - ("judge", "0050_problem_tester_field"), - ("judge", "0051_was_rejudged_field"), - ("judge", "0052_switch_to_durationfield"), - ("judge", "0053_opengraph_problems"), - ("judge", "0054_tickets"), - ("judge", "0055_add_performance_points"), - ("judge", "0056_ticket_is_open"), - ("judge", "0057_blue_pretests"), - ("judge", "0058_problem_curator_field"), - ("judge", "0059_problem_is_manually_managed"), - ("judge", "0060_contest_clarifications"), - ("judge", "0061_language_template"), - ("judge", "0062_add_contest_submission_limit"), - ("judge", "0063_new_solutions"), - ("judge", "0064_unique_solution"), - ("judge", "0065_blogpost_perms"), - ("judge", "0066_submission_date_index"), - ("judge", "0067_contest_access_code"), - ("judge", "0068_hide_scoreboard"), - ("judge", "0069_judge_blocking"), - ("judge", "0070_organization_slug"), - ("judge", "0071_organization_private_problems"), - ("judge", "0072_contest_logo_override_image"), - ("judge", "0073_comment_lock"), - ("judge", "0074_totp"), - ("judge", "0075_organization_admin_reverse"), - ("judge", "0076_problem_statistics"), - ("judge", "0077_remove_organization_key"), - ("judge", "0078_add_user_notes"), - ("judge", "0079_remove_comment_title"), - ("judge", "0080_contest_banned_users"), - ("judge", "0081_unlisted_users"), - ("judge", "0082_remove_profile_name"), - ("judge", "0083_extended_feedback"), - ("judge", "0084_contest_formats"), - ] + replaces = [('judge', '0001_initial'), ('judge', '0002_license'), ('judge', '0003_license_key'), ('judge', '0004_language_limit'), ('judge', '0005_nav_path_len'), ('judge', '0006_language_extension'), ('judge', '0007_test_site_perm'), ('judge', '0008_contestproblem_order'), ('judge', '0009_solution_problem'), ('judge', '0010_comment_page_index'), ('judge', '0011_organization_is_open'), ('judge', '0012_organization_perms'), ('judge', '0013_private_contests'), ('judge', '0014_multi_organization'), ('judge', '0015_remove_single_organization'), ('judge', '0016_organizationrequest'), ('judge', '0017_edit_public_problem_perm'), ('judge', '0018_django_1_9'), ('judge', '0019_og_images'), ('judge', '0020_profile_user_script'), ('judge', '0021_output_prefix_override'), ('judge', '0022_judge_last_ping'), ('judge', '0023_contest_tag'), ('judge', '0024_submission_judge'), ('judge', '0025_submission_rejudge_flag'), ('judge', '0026_change_public_visibility_perm'), ('judge', '0027_bridge_revert'), ('judge', '0028_judge_ip'), ('judge', '0029_problem_translation'), ('judge', '0030_remove_contest_profile'), ('judge', '0031_judge_versions'), ('judge', '0032_hide_problem_tags_in_contest'), ('judge', '0033_proper_pretest_support'), ('judge', '0034_submission_is_pretested'), ('judge', '0035_contest_spectate_mode'), ('judge', '0036_contest_participation_unique'), ('judge', '0037_user_count_ac_rate_field'), ('judge', '0038_profile_problem_count'), ('judge', '0039_remove_contest_is_external'), ('judge', '0040_profile_math_engine'), ('judge', '0041_virtual_contest_participation'), ('judge', '0042_remove_spectate_field'), ('judge', '0043_contest_user_count'), ('judge', '0044_organization_slots'), ('judge', '0045_organization_access_code'), ('judge', '0046_blogpost_authors'), ('judge', '0047_site_managed_data'), ('judge', '0048_site_managed_checkers'), ('judge', '0049_contest_summary'), ('judge', '0050_problem_tester_field'), ('judge', '0051_was_rejudged_field'), ('judge', '0052_switch_to_durationfield'), ('judge', '0053_opengraph_problems'), ('judge', '0054_tickets'), ('judge', '0055_add_performance_points'), ('judge', '0056_ticket_is_open'), ('judge', '0057_blue_pretests'), ('judge', '0058_problem_curator_field'), ('judge', '0059_problem_is_manually_managed'), ('judge', '0060_contest_clarifications'), ('judge', '0061_language_template'), ('judge', '0062_add_contest_submission_limit'), ('judge', '0063_new_solutions'), ('judge', '0064_unique_solution'), ('judge', '0065_blogpost_perms'), ('judge', '0066_submission_date_index'), ('judge', '0067_contest_access_code'), ('judge', '0068_hide_scoreboard'), ('judge', '0069_judge_blocking'), ('judge', '0070_organization_slug'), ('judge', '0071_organization_private_problems'), ('judge', '0072_contest_logo_override_image'), ('judge', '0073_comment_lock'), ('judge', '0074_totp'), ('judge', '0075_organization_admin_reverse'), ('judge', '0076_problem_statistics'), ('judge', '0077_remove_organization_key'), ('judge', '0078_add_user_notes'), ('judge', '0079_remove_comment_title'), ('judge', '0080_contest_banned_users'), ('judge', '0081_unlisted_users'), ('judge', '0082_remove_profile_name'), ('judge', '0083_extended_feedback'), ('judge', '0084_contest_formats')] initial = True dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ("contenttypes", "0002_remove_content_type_name"), + ('contenttypes', '0002_remove_content_type_name'), ] operations = [ migrations.CreateModel( - name="BlogPost", + name='BlogPost', fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("title", models.CharField(max_length=100, verbose_name="post title")), - ("slug", models.SlugField(verbose_name="slug")), - ( - "visible", - models.BooleanField( - default=False, verbose_name="public visibility" - ), - ), - ("sticky", models.BooleanField(default=False, verbose_name="sticky")), - ("publish_on", models.DateTimeField(verbose_name="publish after")), - ("content", models.TextField(verbose_name="post content")), - ("summary", models.TextField(blank=True, verbose_name="post summary")), - ( - "og_image", - models.CharField( - blank=True, - default="", - max_length=150, - verbose_name="openGraph image", - ), - ), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=100, verbose_name='post title')), + ('slug', models.SlugField(verbose_name='slug')), + ('visible', models.BooleanField(default=False, verbose_name='public visibility')), + ('sticky', models.BooleanField(default=False, verbose_name='sticky')), + ('publish_on', models.DateTimeField(verbose_name='publish after')), + ('content', models.TextField(verbose_name='post content')), + ('summary', models.TextField(blank=True, verbose_name='post summary')), + ('og_image', models.CharField(blank=True, default='', max_length=150, verbose_name='openGraph image')), ], options={ - "verbose_name_plural": "blog posts", - "permissions": (("edit_all_post", "Edit all posts"),), - "verbose_name": "blog post", + 'verbose_name_plural': 'blog posts', + 'permissions': (('edit_all_post', 'Edit all posts'),), + 'verbose_name': 'blog post', }, ), migrations.CreateModel( - name="Comment", + name='Comment', fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "time", - models.DateTimeField(auto_now_add=True, verbose_name="posted time"), - ), - ( - "page", - models.CharField( - db_index=True, - max_length=30, - validators=[ - django.core.validators.RegexValidator( - "^[pcs]:[a-z0-9]+$|^b:\\d+$", - "Page code must be ^[pcs]:[a-z0-9]+$|^b:\\d+$", - ) - ], - verbose_name="associated page", - ), - ), - ("score", models.IntegerField(default=0, verbose_name="votes")), - ( - "body", - models.TextField(max_length=8192, verbose_name="body of comment"), - ), - ( - "hidden", - models.BooleanField(default=0, verbose_name="hide the comment"), - ), - ("lft", models.PositiveIntegerField(db_index=True, editable=False)), - ("rght", models.PositiveIntegerField(db_index=True, editable=False)), - ("tree_id", models.PositiveIntegerField(db_index=True, editable=False)), - ("level", models.PositiveIntegerField(db_index=True, editable=False)), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('time', models.DateTimeField(auto_now_add=True, verbose_name='posted time')), + ('page', models.CharField(db_index=True, max_length=30, validators=[django.core.validators.RegexValidator('^[pcs]:[a-z0-9]+$|^b:\\d+$', 'Page code must be ^[pcs]:[a-z0-9]+$|^b:\\d+$')], verbose_name='associated page')), + ('score', models.IntegerField(default=0, verbose_name='votes')), + ('body', models.TextField(max_length=8192, verbose_name='body of comment')), + ('hidden', models.BooleanField(default=0, verbose_name='hide the comment')), + ('lft', models.PositiveIntegerField(db_index=True, editable=False)), + ('rght', models.PositiveIntegerField(db_index=True, editable=False)), + ('tree_id', models.PositiveIntegerField(db_index=True, editable=False)), + ('level', models.PositiveIntegerField(db_index=True, editable=False)), ], options={ - "verbose_name_plural": "comments", - "verbose_name": "comment", + 'verbose_name_plural': 'comments', + 'verbose_name': 'comment', }, ), migrations.CreateModel( - name="CommentLock", + name='CommentLock', fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "page", - models.CharField( - db_index=True, - max_length=30, - validators=[ - django.core.validators.RegexValidator( - "^[pcs]:[a-z0-9]+$|^b:\\d+$", - "Page code must be ^[pcs]:[a-z0-9]+$|^b:\\d+$", - ) - ], - verbose_name="associated page", - ), - ), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('page', models.CharField(db_index=True, max_length=30, validators=[django.core.validators.RegexValidator('^[pcs]:[a-z0-9]+$|^b:\\d+$', 'Page code must be ^[pcs]:[a-z0-9]+$|^b:\\d+$')], verbose_name='associated page')), ], options={ - "permissions": (("override_comment_lock", "Override comment lock"),), + 'permissions': (('override_comment_lock', 'Override comment lock'),), }, ), migrations.CreateModel( - name="CommentVote", + name='CommentVote', fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("score", models.IntegerField()), - ( - "comment", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="votes", - to="judge.Comment", - ), - ), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('score', models.IntegerField()), + ('comment', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='votes', to='judge.Comment')), ], options={ - "verbose_name_plural": "comment votes", - "verbose_name": "comment vote", + 'verbose_name_plural': 'comment votes', + 'verbose_name': 'comment vote', }, ), migrations.CreateModel( - name="Contest", + name='Contest', fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "key", - models.CharField( - max_length=20, - unique=True, - validators=[ - django.core.validators.RegexValidator( - "^[a-z0-9]+$", "Contest id must be ^[a-z0-9]+$" - ) - ], - verbose_name="contest id", - ), - ), - ( - "name", - models.CharField( - db_index=True, max_length=100, verbose_name="contest name" - ), - ), - ( - "description", - models.TextField(blank=True, verbose_name="description"), - ), - ( - "start_time", - models.DateTimeField(db_index=True, verbose_name="start time"), - ), - ( - "end_time", - models.DateTimeField(db_index=True, verbose_name="end time"), - ), - ( - "time_limit", - models.DurationField( - blank=True, null=True, verbose_name="time limit" - ), - ), - ( - "is_public", - models.BooleanField( - default=False, - help_text="Should be set even for organization-private contests, where it determines whether the contest is visible to members of the specified organizations.", - verbose_name="publicly visible", - ), - ), - ( - "is_rated", - models.BooleanField( - default=False, - help_text="Whether this contest can be rated.", - verbose_name="contest rated", - ), - ), - ( - "hide_scoreboard", - models.BooleanField( - default=False, - help_text="Whether the scoreboard should remain hidden for the duration of the contest.", - verbose_name="hide scoreboard", - ), - ), - ( - "use_clarifications", - models.BooleanField( - default=True, - help_text="Use clarification system instead of comments.", - verbose_name="no comments", - ), - ), - ( - "rate_all", - models.BooleanField( - default=False, - help_text="Rate all users who joined.", - verbose_name="rate all", - ), - ), - ( - "is_private", - models.BooleanField( - default=False, verbose_name="private to organizations" - ), - ), - ( - "hide_problem_tags", - models.BooleanField( - default=False, - help_text="Whether problem tags should be hidden by default.", - verbose_name="hide problem tags", - ), - ), - ( - "run_pretests_only", - models.BooleanField( - default=False, - help_text="Whether judges should grade pretests only, versus all testcases. Commonly set during a contest, then unset prior to rejudging user submissions when the contest ends.", - verbose_name="run pretests only", - ), - ), - ( - "og_image", - models.CharField( - blank=True, - default="", - max_length=150, - verbose_name="OpenGraph image", - ), - ), - ( - "logo_override_image", - models.CharField( - blank=True, - default="", - help_text="This image will replace the default site logo for users inside the contest.", - max_length=150, - verbose_name="Logo override image", - ), - ), - ( - "user_count", - models.IntegerField( - default=0, verbose_name="the amount of live participants" - ), - ), - ( - "summary", - models.TextField( - blank=True, - help_text="Plain-text, shown in meta description tag, e.g. for social media.", - verbose_name="contest summary", - ), - ), - ( - "access_code", - models.CharField( - blank=True, - default="", - help_text="An optional code to prompt contestants before they are allowed to join the contest. Leave it blank to disable.", - max_length=255, - verbose_name="access code", - ), - ), - ( - "format_name", - models.CharField( - choices=[("default", "Default")], - default="default", - help_text="The contest format module to use.", - max_length=32, - verbose_name="contest format", - ), - ), - ( - "format_config", - jsonfield.fields.JSONField( - blank=True, - help_text="A JSON object to serve as the configuration for the chosen contest format module. Leave empty to use None. Exact format depends on the contest format selected.", - null=True, - verbose_name="contest format configuration", - ), - ), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('key', models.CharField(max_length=20, unique=True, validators=[django.core.validators.RegexValidator('^[a-z0-9]+$', 'Contest id must be ^[a-z0-9]+$')], verbose_name='contest id')), + ('name', models.CharField(db_index=True, max_length=100, verbose_name='contest name')), + ('description', models.TextField(blank=True, verbose_name='description')), + ('start_time', models.DateTimeField(db_index=True, verbose_name='start time')), + ('end_time', models.DateTimeField(db_index=True, verbose_name='end time')), + ('time_limit', models.DurationField(blank=True, null=True, verbose_name='time limit')), + ('is_public', models.BooleanField(default=False, help_text='Should be set even for organization-private contests, where it determines whether the contest is visible to members of the specified organizations.', verbose_name='publicly visible')), + ('is_rated', models.BooleanField(default=False, help_text='Whether this contest can be rated.', verbose_name='contest rated')), + ('hide_scoreboard', models.BooleanField(default=False, help_text='Whether the scoreboard should remain hidden for the duration of the contest.', verbose_name='hide scoreboard')), + ('use_clarifications', models.BooleanField(default=True, help_text='Use clarification system instead of comments.', verbose_name='no comments')), + ('rate_all', models.BooleanField(default=False, help_text='Rate all users who joined.', verbose_name='rate all')), + ('is_private', models.BooleanField(default=False, verbose_name='private to organizations')), + ('hide_problem_tags', models.BooleanField(default=False, help_text='Whether problem tags should be hidden by default.', verbose_name='hide problem tags')), + ('run_pretests_only', models.BooleanField(default=False, help_text='Whether judges should grade pretests only, versus all testcases. Commonly set during a contest, then unset prior to rejudging user submissions when the contest ends.', verbose_name='run pretests only')), + ('og_image', models.CharField(blank=True, default='', max_length=150, verbose_name='OpenGraph image')), + ('logo_override_image', models.CharField(blank=True, default='', help_text='This image will replace the default site logo for users inside the contest.', max_length=150, verbose_name='Logo override image')), + ('user_count', models.IntegerField(default=0, verbose_name='the amount of live participants')), + ('summary', models.TextField(blank=True, help_text='Plain-text, shown in meta description tag, e.g. for social media.', verbose_name='contest summary')), + ('access_code', models.CharField(blank=True, default='', help_text='An optional code to prompt contestants before they are allowed to join the contest. Leave it blank to disable.', max_length=255, verbose_name='access code')), + ('format_name', models.CharField(choices=[('default', 'Default')], default='default', help_text='The contest format module to use.', max_length=32, verbose_name='contest format')), + ('format_config', jsonfield.fields.JSONField(blank=True, help_text='A JSON object to serve as the configuration for the chosen contest format module. Leave empty to use None. Exact format depends on the contest format selected.', null=True, verbose_name='contest format configuration')), ], options={ - "verbose_name_plural": "contests", - "permissions": ( - ("see_private_contest", "See private contests"), - ("edit_own_contest", "Edit own contests"), - ("edit_all_contest", "Edit all contests"), - ("contest_rating", "Rate contests"), - ("contest_access_code", "Contest access codes"), - ), - "verbose_name": "contest", + 'verbose_name_plural': 'contests', + 'permissions': (('see_private_contest', 'See private contests'), ('edit_own_contest', 'Edit own contests'), ('edit_all_contest', 'Edit all contests'), ('contest_rating', 'Rate contests'), ('contest_access_code', 'Contest access codes')), + 'verbose_name': 'contest', }, ), migrations.CreateModel( - name="ContestParticipation", + name='ContestParticipation', fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "real_start", - models.DateTimeField( - db_column="start", - default=django.utils.timezone.now, - verbose_name="start time", - ), - ), - ( - "score", - models.IntegerField(db_index=True, default=0, verbose_name="score"), - ), - ( - "cumtime", - models.PositiveIntegerField( - default=0, verbose_name="cumulative time" - ), - ), - ( - "virtual", - models.IntegerField( - default=0, - help_text="0 means non-virtual, otherwise the n-th virtual participation", - verbose_name="virtual participation id", - ), - ), - ( - "format_data", - jsonfield.fields.JSONField( - blank=True, - null=True, - verbose_name="contest format specific data", - ), - ), - ( - "contest", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="users", - to="judge.Contest", - verbose_name="associated contest", - ), - ), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('real_start', models.DateTimeField(db_column='start', default=django.utils.timezone.now, verbose_name='start time')), + ('score', models.IntegerField(db_index=True, default=0, verbose_name='score')), + ('cumtime', models.PositiveIntegerField(default=0, verbose_name='cumulative time')), + ('virtual', models.IntegerField(default=0, help_text='0 means non-virtual, otherwise the n-th virtual participation', verbose_name='virtual participation id')), + ('format_data', jsonfield.fields.JSONField(blank=True, null=True, verbose_name='contest format specific data')), + ('contest', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='users', to='judge.Contest', verbose_name='associated contest')), ], options={ - "verbose_name_plural": "contest participations", - "verbose_name": "contest participation", + 'verbose_name_plural': 'contest participations', + 'verbose_name': 'contest participation', }, ), migrations.CreateModel( - name="ContestProblem", + name='ContestProblem', fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("points", models.IntegerField(verbose_name="points")), - ("partial", models.BooleanField(default=True, verbose_name="partial")), - ( - "is_pretested", - models.BooleanField(default=False, verbose_name="is pretested"), - ), - ( - "order", - models.PositiveIntegerField(db_index=True, verbose_name="order"), - ), - ( - "output_prefix_override", - models.IntegerField( - blank=True, - null=True, - verbose_name="output prefix length override", - ), - ), - ( - "max_submissions", - models.IntegerField( - default=0, - help_text="Maximum number of submissions for this problem, or 0 for no limit.", - validators=[ - django.core.validators.MinValueValidator( - 0, "Why include a problem you can't submit to?" - ) - ], - ), - ), - ( - "contest", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="contest_problems", - to="judge.Contest", - verbose_name="contest", - ), - ), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('points', models.IntegerField(verbose_name='points')), + ('partial', models.BooleanField(default=True, verbose_name='partial')), + ('is_pretested', models.BooleanField(default=False, verbose_name='is pretested')), + ('order', models.PositiveIntegerField(db_index=True, verbose_name='order')), + ('output_prefix_override', models.IntegerField(blank=True, null=True, verbose_name='output prefix length override')), + ('max_submissions', models.IntegerField(default=0, help_text='Maximum number of submissions for this problem, or 0 for no limit.', validators=[django.core.validators.MinValueValidator(0, "Why include a problem you can't submit to?")])), + ('contest', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='contest_problems', to='judge.Contest', verbose_name='contest')), ], options={ - "verbose_name_plural": "contest problems", - "verbose_name": "contest problem", + 'verbose_name_plural': 'contest problems', + 'verbose_name': 'contest problem', }, ), migrations.CreateModel( - name="ContestSubmission", + name='ContestSubmission', fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("points", models.FloatField(default=0.0, verbose_name="points")), - ( - "is_pretest", - models.BooleanField( - default=False, - help_text="Whether this submission was ran only on pretests.", - verbose_name="is pretested", - ), - ), - ( - "participation", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="submissions", - related_query_name="submission", - to="judge.ContestParticipation", - verbose_name="participation", - ), - ), - ( - "problem", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="submissions", - related_query_name="submission", - to="judge.ContestProblem", - verbose_name="problem", - ), - ), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('points', models.FloatField(default=0.0, verbose_name='points')), + ('is_pretest', models.BooleanField(default=False, help_text='Whether this submission was ran only on pretests.', verbose_name='is pretested')), + ('participation', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='submissions', related_query_name='submission', to='judge.ContestParticipation', verbose_name='participation')), + ('problem', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='submissions', related_query_name='submission', to='judge.ContestProblem', verbose_name='problem')), ], options={ - "verbose_name_plural": "contest submissions", - "verbose_name": "contest submission", + 'verbose_name_plural': 'contest submissions', + 'verbose_name': 'contest submission', }, ), migrations.CreateModel( - name="ContestTag", + name='ContestTag', fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "name", - models.CharField( - max_length=20, - unique=True, - validators=[ - django.core.validators.RegexValidator( - "^[a-z-]+$", - message="Lowercase letters and hyphens only.", - ) - ], - verbose_name="tag name", - ), - ), - ( - "color", - models.CharField( - max_length=7, - validators=[ - django.core.validators.RegexValidator( - "^#(?:[A-Fa-f0-9]{3}){1,2}$", "Invalid colour." - ) - ], - verbose_name="tag colour", - ), - ), - ( - "description", - models.TextField(blank=True, verbose_name="tag description"), - ), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=20, unique=True, validators=[django.core.validators.RegexValidator('^[a-z-]+$', message='Lowercase letters and hyphens only.')], verbose_name='tag name')), + ('color', models.CharField(max_length=7, validators=[django.core.validators.RegexValidator('^#(?:[A-Fa-f0-9]{3}){1,2}$', 'Invalid colour.')], verbose_name='tag colour')), + ('description', models.TextField(blank=True, verbose_name='tag description')), ], options={ - "verbose_name_plural": "contest tags", - "verbose_name": "contest tag", + 'verbose_name_plural': 'contest tags', + 'verbose_name': 'contest tag', }, ), migrations.CreateModel( - name="Judge", + name='Judge', fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "name", - models.CharField( - help_text="Server name, hostname-style", - max_length=50, - unique=True, - ), - ), - ( - "created", - models.DateTimeField( - auto_now_add=True, verbose_name="time of creation" - ), - ), - ( - "auth_key", - models.CharField( - help_text="A key to authenticated this judge", - max_length=100, - verbose_name="authentication key", - ), - ), - ( - "is_blocked", - models.BooleanField( - default=False, - help_text="Whether this judge should be blocked from connecting, even if its key is correct.", - verbose_name="block judge", - ), - ), - ( - "online", - models.BooleanField( - default=False, verbose_name="judge online status" - ), - ), - ( - "start_time", - models.DateTimeField(null=True, verbose_name="judge start time"), - ), - ("ping", models.FloatField(null=True, verbose_name="response time")), - ( - "load", - models.FloatField( - help_text="Load for the last minute, divided by processors to be fair.", - null=True, - verbose_name="system load", - ), - ), - ( - "description", - models.TextField(blank=True, verbose_name="description"), - ), - ( - "last_ip", - models.GenericIPAddressField( - blank=True, null=True, verbose_name="Last connected IP" - ), - ), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(help_text='Server name, hostname-style', max_length=50, unique=True)), + ('created', models.DateTimeField(auto_now_add=True, verbose_name='time of creation')), + ('auth_key', models.CharField(help_text='A key to authenticated this judge', max_length=100, verbose_name='authentication key')), + ('is_blocked', models.BooleanField(default=False, help_text='Whether this judge should be blocked from connecting, even if its key is correct.', verbose_name='block judge')), + ('online', models.BooleanField(default=False, verbose_name='judge online status')), + ('start_time', models.DateTimeField(null=True, verbose_name='judge start time')), + ('ping', models.FloatField(null=True, verbose_name='response time')), + ('load', models.FloatField(help_text='Load for the last minute, divided by processors to be fair.', null=True, verbose_name='system load')), + ('description', models.TextField(blank=True, verbose_name='description')), + ('last_ip', models.GenericIPAddressField(blank=True, null=True, verbose_name='Last connected IP')), ], options={ - "ordering": ["name"], - "verbose_name_plural": "judges", - "verbose_name": "judge", + 'ordering': ['name'], + 'verbose_name_plural': 'judges', + 'verbose_name': 'judge', }, ), migrations.CreateModel( - name="Language", + name='Language', fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "key", - models.CharField( - help_text="The identifier for this language; the same as its executor id for judges.", - max_length=6, - unique=True, - verbose_name="short identifier", - ), - ), - ( - "name", - models.CharField( - help_text='Longer name for the language, e.g. "Python 2" or "C++11".', - max_length=20, - verbose_name="long name", - ), - ), - ( - "short_name", - models.CharField( - blank=True, - help_text='More readable, but short, name to display publicly; e.g. "PY2" or "C++11". If left blank, it will default to the short identifier.', - max_length=10, - null=True, - verbose_name="short name", - ), - ), - ( - "common_name", - models.CharField( - help_text='Common name for the language. For example, the common name for C++03, C++11, and C++14 would be "C++"', - max_length=10, - verbose_name="common name", - ), - ), - ( - "ace", - models.CharField( - help_text='Language ID for Ace.js editor highlighting, appended to "mode-" to determine the Ace JavaScript file to use, e.g., "python".', - max_length=20, - verbose_name="ace mode name", - ), - ), - ( - "pygments", - models.CharField( - help_text="Language ID for Pygments highlighting in source windows.", - max_length=20, - verbose_name="pygments name", - ), - ), - ( - "template", - models.TextField( - blank=True, - help_text="Code template to display in submission editor.", - verbose_name="code template", - ), - ), - ( - "info", - models.CharField( - blank=True, - help_text="Do not set this unless you know what you're doing! It will override the usually more specific, judge-provided runtime info!", - max_length=50, - verbose_name="runtime info override", - ), - ), - ( - "description", - models.TextField( - blank=True, - help_text="Use field this to inform users of quirks with your environment, additional restrictions, etc.", - verbose_name="language description", - ), - ), - ( - "extension", - models.CharField( - help_text='The extension of source files, e.g., "py" or "cpp".', - max_length=10, - verbose_name="extension", - ), - ), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('key', models.CharField(help_text='The identifier for this language; the same as its executor id for judges.', max_length=6, unique=True, verbose_name='short identifier')), + ('name', models.CharField(help_text='Longer name for the language, e.g. "Python 2" or "C++11".', max_length=20, verbose_name='long name')), + ('short_name', models.CharField(blank=True, help_text='More readable, but short, name to display publicly; e.g. "PY2" or "C++11". If left blank, it will default to the short identifier.', max_length=10, null=True, verbose_name='short name')), + ('common_name', models.CharField(help_text='Common name for the language. For example, the common name for C++03, C++11, and C++14 would be "C++"', max_length=10, verbose_name='common name')), + ('ace', models.CharField(help_text='Language ID for Ace.js editor highlighting, appended to "mode-" to determine the Ace JavaScript file to use, e.g., "python".', max_length=20, verbose_name='ace mode name')), + ('pygments', models.CharField(help_text='Language ID for Pygments highlighting in source windows.', max_length=20, verbose_name='pygments name')), + ('template', models.TextField(blank=True, help_text='Code template to display in submission editor.', verbose_name='code template')), + ('info', models.CharField(blank=True, help_text="Do not set this unless you know what you're doing! It will override the usually more specific, judge-provided runtime info!", max_length=50, verbose_name='runtime info override')), + ('description', models.TextField(blank=True, help_text='Use field this to inform users of quirks with your environment, additional restrictions, etc.', verbose_name='language description')), + ('extension', models.CharField(help_text='The extension of source files, e.g., "py" or "cpp".', max_length=10, verbose_name='extension')), ], options={ - "ordering": ["key"], - "verbose_name_plural": "languages", - "verbose_name": "language", + 'ordering': ['key'], + 'verbose_name_plural': 'languages', + 'verbose_name': 'language', }, ), migrations.CreateModel( - name="LanguageLimit", + name='LanguageLimit', fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("time_limit", models.FloatField(verbose_name="time limit")), - ("memory_limit", models.IntegerField(verbose_name="memory limit")), - ( - "language", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="judge.Language", - verbose_name="language", - ), - ), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('time_limit', models.FloatField(verbose_name='time limit')), + ('memory_limit', models.IntegerField(verbose_name='memory limit')), + ('language', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='judge.Language', verbose_name='language')), ], options={ - "verbose_name_plural": "language-specific resource limits", - "verbose_name": "language-specific resource limit", + 'verbose_name_plural': 'language-specific resource limits', + 'verbose_name': 'language-specific resource limit', }, ), migrations.CreateModel( - name="License", + name='License', fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "key", - models.CharField( - max_length=20, - unique=True, - validators=[ - django.core.validators.RegexValidator( - "^[-\\w.]+$", "License key must be ^[-\\w.]+$" - ) - ], - verbose_name="key", - ), - ), - ("link", models.CharField(max_length=256, verbose_name="link")), - ("name", models.CharField(max_length=256, verbose_name="full name")), - ( - "display", - models.CharField( - blank=True, - help_text="Displayed on pages under this license", - max_length=256, - verbose_name="short name", - ), - ), - ( - "icon", - models.CharField( - blank=True, - help_text="URL to the icon", - max_length=256, - verbose_name="icon", - ), - ), - ("text", models.TextField(verbose_name="license text")), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('key', models.CharField(max_length=20, unique=True, validators=[django.core.validators.RegexValidator('^[-\\w.]+$', 'License key must be ^[-\\w.]+$')], verbose_name='key')), + ('link', models.CharField(max_length=256, verbose_name='link')), + ('name', models.CharField(max_length=256, verbose_name='full name')), + ('display', models.CharField(blank=True, help_text='Displayed on pages under this license', max_length=256, verbose_name='short name')), + ('icon', models.CharField(blank=True, help_text='URL to the icon', max_length=256, verbose_name='icon')), + ('text', models.TextField(verbose_name='license text')), ], options={ - "verbose_name_plural": "licenses", - "verbose_name": "license", + 'verbose_name_plural': 'licenses', + 'verbose_name': 'license', }, ), migrations.CreateModel( - name="MiscConfig", + name='MiscConfig', fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("key", models.CharField(db_index=True, max_length=30)), - ("value", models.TextField(blank=True)), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('key', models.CharField(db_index=True, max_length=30)), + ('value', models.TextField(blank=True)), ], options={ - "verbose_name_plural": "miscellaneous configuration", - "verbose_name": "configuration item", + 'verbose_name_plural': 'miscellaneous configuration', + 'verbose_name': 'configuration item', }, ), migrations.CreateModel( - name="NavigationBar", + name='NavigationBar', fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "order", - models.PositiveIntegerField(db_index=True, verbose_name="order"), - ), - ( - "key", - models.CharField( - max_length=10, unique=True, verbose_name="identifier" - ), - ), - ("label", models.CharField(max_length=20, verbose_name="label")), - ("path", models.CharField(max_length=255, verbose_name="link path")), - ( - "regex", - models.TextField( - validators=[judge.models.interface.validate_regex], - verbose_name="highlight regex", - ), - ), - ("lft", models.PositiveIntegerField(db_index=True, editable=False)), - ("rght", models.PositiveIntegerField(db_index=True, editable=False)), - ("tree_id", models.PositiveIntegerField(db_index=True, editable=False)), - ("level", models.PositiveIntegerField(db_index=True, editable=False)), - ( - "parent", - mptt.fields.TreeForeignKey( - blank=True, - null=True, - on_delete=django.db.models.deletion.CASCADE, - related_name="children", - to="judge.NavigationBar", - verbose_name="parent item", - ), - ), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('order', models.PositiveIntegerField(db_index=True, verbose_name='order')), + ('key', models.CharField(max_length=10, unique=True, verbose_name='identifier')), + ('label', models.CharField(max_length=20, verbose_name='label')), + ('path', models.CharField(max_length=255, verbose_name='link path')), + ('regex', models.TextField(validators=[judge.models.interface.validate_regex], verbose_name='highlight regex')), + ('lft', models.PositiveIntegerField(db_index=True, editable=False)), + ('rght', models.PositiveIntegerField(db_index=True, editable=False)), + ('tree_id', models.PositiveIntegerField(db_index=True, editable=False)), + ('level', models.PositiveIntegerField(db_index=True, editable=False)), + ('parent', mptt.fields.TreeForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='children', to='judge.NavigationBar', verbose_name='parent item')), ], options={ - "verbose_name_plural": "navigation bar", - "verbose_name": "navigation item", + 'verbose_name_plural': 'navigation bar', + 'verbose_name': 'navigation item', }, ), migrations.CreateModel( - name="Organization", + name='Organization', fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "name", - models.CharField(max_length=128, verbose_name="organization title"), - ), - ( - "slug", - models.SlugField( - help_text="Organization name shown in URL", - max_length=128, - verbose_name="organization slug", - ), - ), - ( - "short_name", - models.CharField( - help_text="Displayed beside user name during contests", - max_length=20, - verbose_name="short name", - ), - ), - ("about", models.TextField(verbose_name="organization description")), - ( - "creation_date", - models.DateTimeField( - auto_now_add=True, verbose_name="creation date" - ), - ), - ( - "is_open", - models.BooleanField( - default=True, - help_text="Allow joining organization", - verbose_name="is open organization?", - ), - ), - ( - "slots", - models.IntegerField( - blank=True, - help_text="Maximum amount of users in this organization, only applicable to private organizations", - null=True, - verbose_name="maximum size", - ), - ), - ( - "access_code", - models.CharField( - blank=True, - help_text="Student access code", - max_length=7, - null=True, - verbose_name="access code", - ), - ), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=128, verbose_name='organization title')), + ('slug', models.SlugField(help_text='Organization name shown in URL', max_length=128, verbose_name='organization slug')), + ('short_name', models.CharField(help_text='Displayed beside user name during contests', max_length=20, verbose_name='short name')), + ('about', models.TextField(verbose_name='organization description')), + ('creation_date', models.DateTimeField(auto_now_add=True, verbose_name='creation date')), + ('is_open', models.BooleanField(default=True, help_text='Allow joining organization', verbose_name='is open organization?')), + ('slots', models.IntegerField(blank=True, help_text='Maximum amount of users in this organization, only applicable to private organizations', null=True, verbose_name='maximum size')), + ('access_code', models.CharField(blank=True, help_text='Student access code', max_length=7, null=True, verbose_name='access code')), ], options={ - "ordering": ["name"], - "verbose_name_plural": "organizations", - "permissions": ( - ("organization_admin", "Administer organizations"), - ("edit_all_organization", "Edit all organizations"), - ), - "verbose_name": "organization", + 'ordering': ['name'], + 'verbose_name_plural': 'organizations', + 'permissions': (('organization_admin', 'Administer organizations'), ('edit_all_organization', 'Edit all organizations')), + 'verbose_name': 'organization', }, ), migrations.CreateModel( - name="OrganizationRequest", + name='OrganizationRequest', fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "time", - models.DateTimeField( - auto_now_add=True, verbose_name="request time" - ), - ), - ( - "state", - models.CharField( - choices=[ - ("P", "Pending"), - ("A", "Approved"), - ("R", "Rejected"), - ], - max_length=1, - verbose_name="state", - ), - ), - ("reason", models.TextField(verbose_name="reason")), - ( - "organization", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="requests", - to="judge.Organization", - verbose_name="organization", - ), - ), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('time', models.DateTimeField(auto_now_add=True, verbose_name='request time')), + ('state', models.CharField(choices=[('P', 'Pending'), ('A', 'Approved'), ('R', 'Rejected')], max_length=1, verbose_name='state')), + ('reason', models.TextField(verbose_name='reason')), + ('organization', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='requests', to='judge.Organization', verbose_name='organization')), ], options={ - "verbose_name_plural": "organization join requests", - "verbose_name": "organization join request", + 'verbose_name_plural': 'organization join requests', + 'verbose_name': 'organization join request', }, ), migrations.CreateModel( - name="PrivateMessage", + name='PrivateMessage', fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "title", - models.CharField(max_length=50, verbose_name="message title"), - ), - ("content", models.TextField(verbose_name="message body")), - ( - "timestamp", - models.DateTimeField( - auto_now_add=True, verbose_name="message timestamp" - ), - ), - ("read", models.BooleanField(default=False, verbose_name="read")), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=50, verbose_name='message title')), + ('content', models.TextField(verbose_name='message body')), + ('timestamp', models.DateTimeField(auto_now_add=True, verbose_name='message timestamp')), + ('read', models.BooleanField(default=False, verbose_name='read')), ], ), migrations.CreateModel( - name="PrivateMessageThread", + name='PrivateMessageThread', fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "messages", - models.ManyToManyField( - to="judge.PrivateMessage", verbose_name="messages in the thread" - ), - ), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('messages', models.ManyToManyField(to='judge.PrivateMessage', verbose_name='messages in the thread')), ], ), migrations.CreateModel( - name="Problem", + name='Problem', fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "code", - models.CharField( - max_length=20, - unique=True, - validators=[ - django.core.validators.RegexValidator( - "^[a-z0-9]+$", "Problem code must be ^[a-z0-9]+$" - ) - ], - verbose_name="problem code", - ), - ), - ( - "name", - models.CharField( - db_index=True, max_length=100, verbose_name="problem name" - ), - ), - ("description", models.TextField(verbose_name="problem body")), - ( - "time_limit", - models.FloatField( - help_text="The time limit for this problem, in seconds. Fractional seconds (e.g. 1.5) are supported.", - verbose_name="time limit", - ), - ), - ( - "memory_limit", - models.IntegerField( - help_text="The memory limit for this problem, in kilobytes (e.g. 64mb = 65536 kilobytes).", - verbose_name="memory limit", - ), - ), - ("short_circuit", models.BooleanField(default=False)), - ("points", models.FloatField(verbose_name="points")), - ( - "partial", - models.BooleanField( - default=False, verbose_name="allows partial points" - ), - ), - ( - "is_public", - models.BooleanField( - db_index=True, default=False, verbose_name="publicly visible" - ), - ), - ( - "is_manually_managed", - models.BooleanField( - db_index=True, - default=False, - help_text="Whether judges should be allowed to manage data or not", - verbose_name="manually managed", - ), - ), - ( - "date", - models.DateTimeField( - blank=True, - db_index=True, - help_text="Doesn't have magic ability to auto-publish due to backward compatibility", - null=True, - verbose_name="date of publishing", - ), - ), - ( - "og_image", - models.CharField( - blank=True, max_length=150, verbose_name="OpenGraph image" - ), - ), - ( - "summary", - models.TextField( - blank=True, - help_text="Plain-text, shown in meta description tag, e.g. for social media.", - verbose_name="problem summary", - ), - ), - ( - "user_count", - models.IntegerField( - default=0, - help_text="The number of users who solved the problem.", - verbose_name="number of users", - ), - ), - ("ac_rate", models.FloatField(default=0, verbose_name="solve rate")), - ( - "is_organization_private", - models.BooleanField( - default=False, verbose_name="private to organizations" - ), - ), - ( - "allowed_languages", - models.ManyToManyField( - to="judge.Language", verbose_name="allowed languages" - ), - ), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('code', models.CharField(max_length=20, unique=True, validators=[django.core.validators.RegexValidator('^[a-z0-9]+$', 'Problem code must be ^[a-z0-9]+$')], verbose_name='problem code')), + ('name', models.CharField(db_index=True, max_length=100, verbose_name='problem name')), + ('description', models.TextField(verbose_name='problem body')), + ('time_limit', models.FloatField(help_text='The time limit for this problem, in seconds. Fractional seconds (e.g. 1.5) are supported.', verbose_name='time limit')), + ('memory_limit', models.IntegerField(help_text='The memory limit for this problem, in kilobytes (e.g. 64mb = 65536 kilobytes).', verbose_name='memory limit')), + ('short_circuit', models.BooleanField(default=False)), + ('points', models.FloatField(verbose_name='points')), + ('partial', models.BooleanField(default=False, verbose_name='allows partial points')), + ('is_public', models.BooleanField(db_index=True, default=False, verbose_name='publicly visible')), + ('is_manually_managed', models.BooleanField(db_index=True, default=False, help_text='Whether judges should be allowed to manage data or not', verbose_name='manually managed')), + ('date', models.DateTimeField(blank=True, db_index=True, help_text="Doesn't have magic ability to auto-publish due to backward compatibility", null=True, verbose_name='date of publishing')), + ('og_image', models.CharField(blank=True, max_length=150, verbose_name='OpenGraph image')), + ('summary', models.TextField(blank=True, help_text='Plain-text, shown in meta description tag, e.g. for social media.', verbose_name='problem summary')), + ('user_count', models.IntegerField(default=0, help_text='The number of users who solved the problem.', verbose_name='number of users')), + ('ac_rate', models.FloatField(default=0, verbose_name='solve rate')), + ('is_organization_private', models.BooleanField(default=False, verbose_name='private to organizations')), + ('allowed_languages', models.ManyToManyField(to='judge.Language', verbose_name='allowed languages')), ], options={ - "verbose_name_plural": "problems", - "permissions": ( - ("see_private_problem", "See hidden problems"), - ("edit_own_problem", "Edit own problems"), - ("edit_all_problem", "Edit all problems"), - ("edit_public_problem", "Edit all public problems"), - ("clone_problem", "Clone problem"), - ("change_public_visibility", "Change is_public field"), - ("change_manually_managed", "Change is_manually_managed field"), - ("see_organization_problem", "See organization-private problems"), - ), - "verbose_name": "problem", + 'verbose_name_plural': 'problems', + 'permissions': (('see_private_problem', 'See hidden problems'), ('edit_own_problem', 'Edit own problems'), ('edit_all_problem', 'Edit all problems'), ('edit_public_problem', 'Edit all public problems'), ('clone_problem', 'Clone problem'), ('change_public_visibility', 'Change is_public field'), ('change_manually_managed', 'Change is_manually_managed field'), ('see_organization_problem', 'See organization-private problems')), + 'verbose_name': 'problem', }, ), migrations.CreateModel( - name="ProblemClarification", + name='ProblemClarification', fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("description", models.TextField(verbose_name="clarification body")), - ( - "date", - models.DateTimeField( - auto_now_add=True, verbose_name="clarification timestamp" - ), - ), - ( - "problem", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="judge.Problem", - verbose_name="clarified problem", - ), - ), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('description', models.TextField(verbose_name='clarification body')), + ('date', models.DateTimeField(auto_now_add=True, verbose_name='clarification timestamp')), + ('problem', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='judge.Problem', verbose_name='clarified problem')), ], ), migrations.CreateModel( - name="ProblemData", + name='ProblemData', fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "zipfile", - models.FileField( - blank=True, - null=True, - storage=judge.utils.problem_data.ProblemDataStorage(), - upload_to=judge.models.problem_data.problem_directory_file, - verbose_name="data zip file", - ), - ), - ( - "generator", - models.FileField( - blank=True, - null=True, - storage=judge.utils.problem_data.ProblemDataStorage(), - upload_to=judge.models.problem_data.problem_directory_file, - verbose_name="generator file", - ), - ), - ( - "output_prefix", - models.IntegerField( - blank=True, null=True, verbose_name="output prefix length" - ), - ), - ( - "output_limit", - models.IntegerField( - blank=True, null=True, verbose_name="output limit length" - ), - ), - ( - "feedback", - models.TextField( - blank=True, verbose_name="init.yml generation feedback" - ), - ), - ( - "checker", - models.CharField( - blank=True, - choices=[ - ("standard", "Standard"), - ("floats", "Floats"), - ("floatsabs", "Floats (absolute)"), - ("floatsrel", "Floats (relative)"), - ("rstripped", "Non-trailing spaces"), - ("sorted", "Unordered"), - ("identical", "Byte identical"), - ("linecount", "Line-by-line"), - ], - max_length=10, - verbose_name="checker", - ), - ), - ( - "checker_args", - models.TextField( - blank=True, - help_text="checker arguments as a JSON object", - verbose_name="checker arguments", - ), - ), - ( - "problem", - models.OneToOneField( - on_delete=django.db.models.deletion.CASCADE, - related_name="data_files", - to="judge.Problem", - verbose_name="problem", - ), - ), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('zipfile', models.FileField(blank=True, null=True, storage=judge.utils.problem_data.ProblemDataStorage(), upload_to=judge.models.problem_data.problem_directory_file, verbose_name='data zip file')), + ('generator', models.FileField(blank=True, null=True, storage=judge.utils.problem_data.ProblemDataStorage(), upload_to=judge.models.problem_data.problem_directory_file, verbose_name='generator file')), + ('output_prefix', models.IntegerField(blank=True, null=True, verbose_name='output prefix length')), + ('output_limit', models.IntegerField(blank=True, null=True, verbose_name='output limit length')), + ('feedback', models.TextField(blank=True, verbose_name='init.yml generation feedback')), + ('checker', models.CharField(blank=True, choices=[('standard', 'Standard'), ('floats', 'Floats'), ('floatsabs', 'Floats (absolute)'), ('floatsrel', 'Floats (relative)'), ('rstripped', 'Non-trailing spaces'), ('sorted', 'Unordered'), ('identical', 'Byte identical'), ('linecount', 'Line-by-line')], max_length=10, verbose_name='checker')), + ('checker_args', models.TextField(blank=True, help_text='checker arguments as a JSON object', verbose_name='checker arguments')), + ('problem', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='data_files', to='judge.Problem', verbose_name='problem')), ], ), migrations.CreateModel( - name="ProblemGroup", + name='ProblemGroup', fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "name", - models.CharField( - max_length=20, unique=True, verbose_name="problem group ID" - ), - ), - ( - "full_name", - models.CharField(max_length=100, verbose_name="problem group name"), - ), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=20, unique=True, verbose_name='problem group ID')), + ('full_name', models.CharField(max_length=100, verbose_name='problem group name')), ], options={ - "ordering": ["full_name"], - "verbose_name_plural": "problem groups", - "verbose_name": "problem group", + 'ordering': ['full_name'], + 'verbose_name_plural': 'problem groups', + 'verbose_name': 'problem group', }, ), migrations.CreateModel( - name="ProblemTestCase", + name='ProblemTestCase', fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("order", models.IntegerField(verbose_name="case position")), - ( - "type", - models.CharField( - choices=[ - ("C", "Normal case"), - ("S", "Batch start"), - ("E", "Batch end"), - ], - default="C", - max_length=1, - verbose_name="case type", - ), - ), - ( - "input_file", - models.CharField( - blank=True, max_length=100, verbose_name="input file name" - ), - ), - ( - "output_file", - models.CharField( - blank=True, max_length=100, verbose_name="output file name" - ), - ), - ( - "generator_args", - models.TextField(blank=True, verbose_name="generator arguments"), - ), - ( - "points", - models.IntegerField( - blank=True, null=True, verbose_name="point value" - ), - ), - ("is_pretest", models.BooleanField(verbose_name="case is pretest?")), - ( - "output_prefix", - models.IntegerField( - blank=True, null=True, verbose_name="output prefix length" - ), - ), - ( - "output_limit", - models.IntegerField( - blank=True, null=True, verbose_name="output limit length" - ), - ), - ( - "checker", - models.CharField( - blank=True, - choices=[ - ("standard", "Standard"), - ("floats", "Floats"), - ("floatsabs", "Floats (absolute)"), - ("floatsrel", "Floats (relative)"), - ("rstripped", "Non-trailing spaces"), - ("sorted", "Unordered"), - ("identical", "Byte identical"), - ("linecount", "Line-by-line"), - ], - max_length=10, - verbose_name="checker", - ), - ), - ( - "checker_args", - models.TextField( - blank=True, - help_text="checker arguments as a JSON object", - verbose_name="checker arguments", - ), - ), - ( - "dataset", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="cases", - to="judge.Problem", - verbose_name="problem data set", - ), - ), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('order', models.IntegerField(verbose_name='case position')), + ('type', models.CharField(choices=[('C', 'Normal case'), ('S', 'Batch start'), ('E', 'Batch end')], default='C', max_length=1, verbose_name='case type')), + ('input_file', models.CharField(blank=True, max_length=100, verbose_name='input file name')), + ('output_file', models.CharField(blank=True, max_length=100, verbose_name='output file name')), + ('generator_args', models.TextField(blank=True, verbose_name='generator arguments')), + ('points', models.IntegerField(blank=True, null=True, verbose_name='point value')), + ('is_pretest', models.BooleanField(verbose_name='case is pretest?')), + ('output_prefix', models.IntegerField(blank=True, null=True, verbose_name='output prefix length')), + ('output_limit', models.IntegerField(blank=True, null=True, verbose_name='output limit length')), + ('checker', models.CharField(blank=True, choices=[('standard', 'Standard'), ('floats', 'Floats'), ('floatsabs', 'Floats (absolute)'), ('floatsrel', 'Floats (relative)'), ('rstripped', 'Non-trailing spaces'), ('sorted', 'Unordered'), ('identical', 'Byte identical'), ('linecount', 'Line-by-line')], max_length=10, verbose_name='checker')), + ('checker_args', models.TextField(blank=True, help_text='checker arguments as a JSON object', verbose_name='checker arguments')), + ('dataset', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='cases', to='judge.Problem', verbose_name='problem data set')), ], ), migrations.CreateModel( - name="ProblemTranslation", + name='ProblemTranslation', fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "language", - models.CharField( - choices=[ - ("de", "German"), - ("en", "English"), - ("es", "Spanish"), - ("fr", "French"), - ("hr", "Croatian"), - ("hu", "Hungarian"), - ("ko", "Korean"), - ("ro", "Romanian"), - ("ru", "Russian"), - ("sr-latn", "Serbian (Latin)"), - ("tr", "Turkish"), - ("vi", "Vietnamese"), - ("zh-hans", "Simplified Chinese"), - ], - max_length=7, - verbose_name="language", - ), - ), - ( - "name", - models.CharField( - db_index=True, max_length=100, verbose_name="translated name" - ), - ), - ( - "description", - models.TextField(verbose_name="translated description"), - ), - ( - "problem", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="translations", - to="judge.Problem", - verbose_name="problem", - ), - ), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('language', models.CharField(choices=[('de', 'German'), ('en', 'English'), ('es', 'Spanish'), ('fr', 'French'), ('hr', 'Croatian'), ('hu', 'Hungarian'), ('ko', 'Korean'), ('ro', 'Romanian'), ('ru', 'Russian'), ('sr-latn', 'Serbian (Latin)'), ('tr', 'Turkish'), ('vi', 'Vietnamese'), ('zh-hans', 'Simplified Chinese')], max_length=7, verbose_name='language')), + ('name', models.CharField(db_index=True, max_length=100, verbose_name='translated name')), + ('description', models.TextField(verbose_name='translated description')), + ('problem', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='translations', to='judge.Problem', verbose_name='problem')), ], options={ - "verbose_name_plural": "problem translations", - "verbose_name": "problem translation", + 'verbose_name_plural': 'problem translations', + 'verbose_name': 'problem translation', }, ), migrations.CreateModel( - name="ProblemType", + name='ProblemType', fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "name", - models.CharField( - max_length=20, unique=True, verbose_name="problem category ID" - ), - ), - ( - "full_name", - models.CharField( - max_length=100, verbose_name="problem category name" - ), - ), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=20, unique=True, verbose_name='problem category ID')), + ('full_name', models.CharField(max_length=100, verbose_name='problem category name')), ], options={ - "ordering": ["full_name"], - "verbose_name_plural": "problem types", - "verbose_name": "problem type", + 'ordering': ['full_name'], + 'verbose_name_plural': 'problem types', + 'verbose_name': 'problem type', }, ), migrations.CreateModel( - name="Profile", + name='Profile', fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "about", - models.TextField( - blank=True, null=True, verbose_name="self-description" - ), - ), - ( - "timezone", - models.CharField( - choices=[ - ( - "Africa", - [ - ("Africa/Abidjan", "Abidjan"), - ("Africa/Accra", "Accra"), - ("Africa/Addis_Ababa", "Addis_Ababa"), - ("Africa/Algiers", "Algiers"), - ("Africa/Asmara", "Asmara"), - ("Africa/Asmera", "Asmera"), - ("Africa/Bamako", "Bamako"), - ("Africa/Bangui", "Bangui"), - ("Africa/Banjul", "Banjul"), - ("Africa/Bissau", "Bissau"), - ("Africa/Blantyre", "Blantyre"), - ("Africa/Brazzaville", "Brazzaville"), - ("Africa/Bujumbura", "Bujumbura"), - ("Africa/Cairo", "Cairo"), - ("Africa/Casablanca", "Casablanca"), - ("Africa/Ceuta", "Ceuta"), - ("Africa/Conakry", "Conakry"), - ("Africa/Dakar", "Dakar"), - ("Africa/Dar_es_Salaam", "Dar_es_Salaam"), - ("Africa/Djibouti", "Djibouti"), - ("Africa/Douala", "Douala"), - ("Africa/El_Aaiun", "El_Aaiun"), - ("Africa/Freetown", "Freetown"), - ("Africa/Gaborone", "Gaborone"), - ("Africa/Harare", "Harare"), - ("Africa/Johannesburg", "Johannesburg"), - ("Africa/Juba", "Juba"), - ("Africa/Kampala", "Kampala"), - ("Africa/Khartoum", "Khartoum"), - ("Africa/Kigali", "Kigali"), - ("Africa/Kinshasa", "Kinshasa"), - ("Africa/Lagos", "Lagos"), - ("Africa/Libreville", "Libreville"), - ("Africa/Lome", "Lome"), - ("Africa/Luanda", "Luanda"), - ("Africa/Lubumbashi", "Lubumbashi"), - ("Africa/Lusaka", "Lusaka"), - ("Africa/Malabo", "Malabo"), - ("Africa/Maputo", "Maputo"), - ("Africa/Maseru", "Maseru"), - ("Africa/Mbabane", "Mbabane"), - ("Africa/Mogadishu", "Mogadishu"), - ("Africa/Monrovia", "Monrovia"), - ("Africa/Nairobi", "Nairobi"), - ("Africa/Ndjamena", "Ndjamena"), - ("Africa/Niamey", "Niamey"), - ("Africa/Nouakchott", "Nouakchott"), - ("Africa/Ouagadougou", "Ouagadougou"), - ("Africa/Porto-Novo", "Porto-Novo"), - ("Africa/Sao_Tome", "Sao_Tome"), - ("Africa/Timbuktu", "Timbuktu"), - ("Africa/Tripoli", "Tripoli"), - ("Africa/Tunis", "Tunis"), - ("Africa/Windhoek", "Windhoek"), - ], - ), - ( - "America", - [ - ("America/Adak", "Adak"), - ("America/Anchorage", "Anchorage"), - ("America/Anguilla", "Anguilla"), - ("America/Antigua", "Antigua"), - ("America/Araguaina", "Araguaina"), - ( - "America/Argentina/Buenos_Aires", - "Argentina/Buenos_Aires", - ), - ( - "America/Argentina/Catamarca", - "Argentina/Catamarca", - ), - ( - "America/Argentina/ComodRivadavia", - "Argentina/ComodRivadavia", - ), - ("America/Argentina/Cordoba", "Argentina/Cordoba"), - ("America/Argentina/Jujuy", "Argentina/Jujuy"), - ( - "America/Argentina/La_Rioja", - "Argentina/La_Rioja", - ), - ("America/Argentina/Mendoza", "Argentina/Mendoza"), - ( - "America/Argentina/Rio_Gallegos", - "Argentina/Rio_Gallegos", - ), - ("America/Argentina/Salta", "Argentina/Salta"), - ( - "America/Argentina/San_Juan", - "Argentina/San_Juan", - ), - ( - "America/Argentina/San_Luis", - "Argentina/San_Luis", - ), - ("America/Argentina/Tucuman", "Argentina/Tucuman"), - ("America/Argentina/Ushuaia", "Argentina/Ushuaia"), - ("America/Aruba", "Aruba"), - ("America/Asuncion", "Asuncion"), - ("America/Atikokan", "Atikokan"), - ("America/Atka", "Atka"), - ("America/Bahia", "Bahia"), - ("America/Bahia_Banderas", "Bahia_Banderas"), - ("America/Barbados", "Barbados"), - ("America/Belem", "Belem"), - ("America/Belize", "Belize"), - ("America/Blanc-Sablon", "Blanc-Sablon"), - ("America/Boa_Vista", "Boa_Vista"), - ("America/Bogota", "Bogota"), - ("America/Boise", "Boise"), - ("America/Buenos_Aires", "Buenos_Aires"), - ("America/Cambridge_Bay", "Cambridge_Bay"), - ("America/Campo_Grande", "Campo_Grande"), - ("America/Cancun", "Cancun"), - ("America/Caracas", "Caracas"), - ("America/Catamarca", "Catamarca"), - ("America/Cayenne", "Cayenne"), - ("America/Cayman", "Cayman"), - ("America/Chicago", "Chicago"), - ("America/Chihuahua", "Chihuahua"), - ("America/Coral_Harbour", "Coral_Harbour"), - ("America/Cordoba", "Cordoba"), - ("America/Costa_Rica", "Costa_Rica"), - ("America/Creston", "Creston"), - ("America/Cuiaba", "Cuiaba"), - ("America/Curacao", "Curacao"), - ("America/Danmarkshavn", "Danmarkshavn"), - ("America/Dawson", "Dawson"), - ("America/Dawson_Creek", "Dawson_Creek"), - ("America/Denver", "Denver"), - ("America/Detroit", "Detroit"), - ("America/Dominica", "Dominica"), - ("America/Edmonton", "Edmonton"), - ("America/Eirunepe", "Eirunepe"), - ("America/El_Salvador", "El_Salvador"), - ("America/Ensenada", "Ensenada"), - ("America/Fort_Nelson", "Fort_Nelson"), - ("America/Fort_Wayne", "Fort_Wayne"), - ("America/Fortaleza", "Fortaleza"), - ("America/Glace_Bay", "Glace_Bay"), - ("America/Godthab", "Godthab"), - ("America/Goose_Bay", "Goose_Bay"), - ("America/Grand_Turk", "Grand_Turk"), - ("America/Grenada", "Grenada"), - ("America/Guadeloupe", "Guadeloupe"), - ("America/Guatemala", "Guatemala"), - ("America/Guayaquil", "Guayaquil"), - ("America/Guyana", "Guyana"), - ("America/Halifax", "Halifax"), - ("America/Havana", "Havana"), - ("America/Hermosillo", "Hermosillo"), - ( - "America/Indiana/Indianapolis", - "Indiana/Indianapolis", - ), - ("America/Indiana/Knox", "Indiana/Knox"), - ("America/Indiana/Marengo", "Indiana/Marengo"), - ( - "America/Indiana/Petersburg", - "Indiana/Petersburg", - ), - ("America/Indiana/Tell_City", "Indiana/Tell_City"), - ("America/Indiana/Vevay", "Indiana/Vevay"), - ("America/Indiana/Vincennes", "Indiana/Vincennes"), - ("America/Indiana/Winamac", "Indiana/Winamac"), - ("America/Indianapolis", "Indianapolis"), - ("America/Inuvik", "Inuvik"), - ("America/Iqaluit", "Iqaluit"), - ("America/Jamaica", "Jamaica"), - ("America/Jujuy", "Jujuy"), - ("America/Juneau", "Juneau"), - ( - "America/Kentucky/Louisville", - "Kentucky/Louisville", - ), - ( - "America/Kentucky/Monticello", - "Kentucky/Monticello", - ), - ("America/Knox_IN", "Knox_IN"), - ("America/Kralendijk", "Kralendijk"), - ("America/La_Paz", "La_Paz"), - ("America/Lima", "Lima"), - ("America/Los_Angeles", "Los_Angeles"), - ("America/Louisville", "Louisville"), - ("America/Lower_Princes", "Lower_Princes"), - ("America/Maceio", "Maceio"), - ("America/Managua", "Managua"), - ("America/Manaus", "Manaus"), - ("America/Marigot", "Marigot"), - ("America/Martinique", "Martinique"), - ("America/Matamoros", "Matamoros"), - ("America/Mazatlan", "Mazatlan"), - ("America/Mendoza", "Mendoza"), - ("America/Menominee", "Menominee"), - ("America/Merida", "Merida"), - ("America/Metlakatla", "Metlakatla"), - ("America/Mexico_City", "Mexico_City"), - ("America/Miquelon", "Miquelon"), - ("America/Moncton", "Moncton"), - ("America/Monterrey", "Monterrey"), - ("America/Montevideo", "Montevideo"), - ("America/Montreal", "Montreal"), - ("America/Montserrat", "Montserrat"), - ("America/Nassau", "Nassau"), - ("America/New_York", "New_York"), - ("America/Nipigon", "Nipigon"), - ("America/Nome", "Nome"), - ("America/Noronha", "Noronha"), - ( - "America/North_Dakota/Beulah", - "North_Dakota/Beulah", - ), - ( - "America/North_Dakota/Center", - "North_Dakota/Center", - ), - ( - "America/North_Dakota/New_Salem", - "North_Dakota/New_Salem", - ), - ("America/Ojinaga", "Ojinaga"), - ("America/Panama", "Panama"), - ("America/Pangnirtung", "Pangnirtung"), - ("America/Paramaribo", "Paramaribo"), - ("America/Phoenix", "Phoenix"), - ("America/Port-au-Prince", "Port-au-Prince"), - ("America/Port_of_Spain", "Port_of_Spain"), - ("America/Porto_Acre", "Porto_Acre"), - ("America/Porto_Velho", "Porto_Velho"), - ("America/Puerto_Rico", "Puerto_Rico"), - ("America/Punta_Arenas", "Punta_Arenas"), - ("America/Rainy_River", "Rainy_River"), - ("America/Rankin_Inlet", "Rankin_Inlet"), - ("America/Recife", "Recife"), - ("America/Regina", "Regina"), - ("America/Resolute", "Resolute"), - ("America/Rio_Branco", "Rio_Branco"), - ("America/Rosario", "Rosario"), - ("America/Santa_Isabel", "Santa_Isabel"), - ("America/Santarem", "Santarem"), - ("America/Santiago", "Santiago"), - ("America/Santo_Domingo", "Santo_Domingo"), - ("America/Sao_Paulo", "Sao_Paulo"), - ("America/Scoresbysund", "Scoresbysund"), - ("America/Shiprock", "Shiprock"), - ("America/Sitka", "Sitka"), - ("America/St_Barthelemy", "St_Barthelemy"), - ("America/St_Johns", "St_Johns"), - ("America/St_Kitts", "St_Kitts"), - ("America/St_Lucia", "St_Lucia"), - ("America/St_Thomas", "St_Thomas"), - ("America/St_Vincent", "St_Vincent"), - ("America/Swift_Current", "Swift_Current"), - ("America/Tegucigalpa", "Tegucigalpa"), - ("America/Thule", "Thule"), - ("America/Thunder_Bay", "Thunder_Bay"), - ("America/Tijuana", "Tijuana"), - ("America/Toronto", "Toronto"), - ("America/Tortola", "Tortola"), - ("America/Vancouver", "Vancouver"), - ("America/Virgin", "Virgin"), - ("America/Whitehorse", "Whitehorse"), - ("America/Winnipeg", "Winnipeg"), - ("America/Yakutat", "Yakutat"), - ("America/Yellowknife", "Yellowknife"), - ], - ), - ( - "Antarctica", - [ - ("Antarctica/Casey", "Casey"), - ("Antarctica/Davis", "Davis"), - ("Antarctica/DumontDUrville", "DumontDUrville"), - ("Antarctica/Macquarie", "Macquarie"), - ("Antarctica/Mawson", "Mawson"), - ("Antarctica/McMurdo", "McMurdo"), - ("Antarctica/Palmer", "Palmer"), - ("Antarctica/Rothera", "Rothera"), - ("Antarctica/South_Pole", "South_Pole"), - ("Antarctica/Syowa", "Syowa"), - ("Antarctica/Troll", "Troll"), - ("Antarctica/Vostok", "Vostok"), - ], - ), - ("Arctic", [("Arctic/Longyearbyen", "Longyearbyen")]), - ( - "Asia", - [ - ("Asia/Aden", "Aden"), - ("Asia/Almaty", "Almaty"), - ("Asia/Amman", "Amman"), - ("Asia/Anadyr", "Anadyr"), - ("Asia/Aqtau", "Aqtau"), - ("Asia/Aqtobe", "Aqtobe"), - ("Asia/Ashgabat", "Ashgabat"), - ("Asia/Ashkhabad", "Ashkhabad"), - ("Asia/Atyrau", "Atyrau"), - ("Asia/Baghdad", "Baghdad"), - ("Asia/Bahrain", "Bahrain"), - ("Asia/Baku", "Baku"), - ("Asia/Bangkok", "Bangkok"), - ("Asia/Barnaul", "Barnaul"), - ("Asia/Beirut", "Beirut"), - ("Asia/Bishkek", "Bishkek"), - ("Asia/Brunei", "Brunei"), - ("Asia/Calcutta", "Calcutta"), - ("Asia/Chita", "Chita"), - ("Asia/Choibalsan", "Choibalsan"), - ("Asia/Chongqing", "Chongqing"), - ("Asia/Chungking", "Chungking"), - ("Asia/Colombo", "Colombo"), - ("Asia/Dacca", "Dacca"), - ("Asia/Damascus", "Damascus"), - ("Asia/Dhaka", "Dhaka"), - ("Asia/Dili", "Dili"), - ("Asia/Dubai", "Dubai"), - ("Asia/Dushanbe", "Dushanbe"), - ("Asia/Famagusta", "Famagusta"), - ("Asia/Gaza", "Gaza"), - ("Asia/Harbin", "Harbin"), - ("Asia/Hebron", "Hebron"), - ("Asia/Ho_Chi_Minh", "Ho_Chi_Minh"), - ("Asia/Hong_Kong", "Hong_Kong"), - ("Asia/Hovd", "Hovd"), - ("Asia/Irkutsk", "Irkutsk"), - ("Asia/Istanbul", "Istanbul"), - ("Asia/Jakarta", "Jakarta"), - ("Asia/Jayapura", "Jayapura"), - ("Asia/Jerusalem", "Jerusalem"), - ("Asia/Kabul", "Kabul"), - ("Asia/Kamchatka", "Kamchatka"), - ("Asia/Karachi", "Karachi"), - ("Asia/Kashgar", "Kashgar"), - ("Asia/Kathmandu", "Kathmandu"), - ("Asia/Katmandu", "Katmandu"), - ("Asia/Khandyga", "Khandyga"), - ("Asia/Kolkata", "Kolkata"), - ("Asia/Krasnoyarsk", "Krasnoyarsk"), - ("Asia/Kuala_Lumpur", "Kuala_Lumpur"), - ("Asia/Kuching", "Kuching"), - ("Asia/Kuwait", "Kuwait"), - ("Asia/Macao", "Macao"), - ("Asia/Macau", "Macau"), - ("Asia/Magadan", "Magadan"), - ("Asia/Makassar", "Makassar"), - ("Asia/Manila", "Manila"), - ("Asia/Muscat", "Muscat"), - ("Asia/Nicosia", "Nicosia"), - ("Asia/Novokuznetsk", "Novokuznetsk"), - ("Asia/Novosibirsk", "Novosibirsk"), - ("Asia/Omsk", "Omsk"), - ("Asia/Oral", "Oral"), - ("Asia/Phnom_Penh", "Phnom_Penh"), - ("Asia/Pontianak", "Pontianak"), - ("Asia/Pyongyang", "Pyongyang"), - ("Asia/Qatar", "Qatar"), - ("Asia/Qostanay", "Qostanay"), - ("Asia/Qyzylorda", "Qyzylorda"), - ("Asia/Rangoon", "Rangoon"), - ("Asia/Riyadh", "Riyadh"), - ("Asia/Saigon", "Saigon"), - ("Asia/Sakhalin", "Sakhalin"), - ("Asia/Samarkand", "Samarkand"), - ("Asia/Seoul", "Seoul"), - ("Asia/Shanghai", "Shanghai"), - ("Asia/Singapore", "Singapore"), - ("Asia/Srednekolymsk", "Srednekolymsk"), - ("Asia/Taipei", "Taipei"), - ("Asia/Tashkent", "Tashkent"), - ("Asia/Tbilisi", "Tbilisi"), - ("Asia/Tehran", "Tehran"), - ("Asia/Tel_Aviv", "Tel_Aviv"), - ("Asia/Thimbu", "Thimbu"), - ("Asia/Thimphu", "Thimphu"), - ("Asia/Tokyo", "Tokyo"), - ("Asia/Tomsk", "Tomsk"), - ("Asia/Ujung_Pandang", "Ujung_Pandang"), - ("Asia/Ulaanbaatar", "Ulaanbaatar"), - ("Asia/Ulan_Bator", "Ulan_Bator"), - ("Asia/Urumqi", "Urumqi"), - ("Asia/Ust-Nera", "Ust-Nera"), - ("Asia/Vientiane", "Vientiane"), - ("Asia/Vladivostok", "Vladivostok"), - ("Asia/Yakutsk", "Yakutsk"), - ("Asia/Yangon", "Yangon"), - ("Asia/Yekaterinburg", "Yekaterinburg"), - ("Asia/Yerevan", "Yerevan"), - ], - ), - ( - "Atlantic", - [ - ("Atlantic/Azores", "Azores"), - ("Atlantic/Bermuda", "Bermuda"), - ("Atlantic/Canary", "Canary"), - ("Atlantic/Cape_Verde", "Cape_Verde"), - ("Atlantic/Faeroe", "Faeroe"), - ("Atlantic/Faroe", "Faroe"), - ("Atlantic/Jan_Mayen", "Jan_Mayen"), - ("Atlantic/Madeira", "Madeira"), - ("Atlantic/Reykjavik", "Reykjavik"), - ("Atlantic/South_Georgia", "South_Georgia"), - ("Atlantic/St_Helena", "St_Helena"), - ("Atlantic/Stanley", "Stanley"), - ], - ), - ( - "Australia", - [ - ("Australia/ACT", "ACT"), - ("Australia/Adelaide", "Adelaide"), - ("Australia/Brisbane", "Brisbane"), - ("Australia/Broken_Hill", "Broken_Hill"), - ("Australia/Canberra", "Canberra"), - ("Australia/Currie", "Currie"), - ("Australia/Darwin", "Darwin"), - ("Australia/Eucla", "Eucla"), - ("Australia/Hobart", "Hobart"), - ("Australia/LHI", "LHI"), - ("Australia/Lindeman", "Lindeman"), - ("Australia/Lord_Howe", "Lord_Howe"), - ("Australia/Melbourne", "Melbourne"), - ("Australia/NSW", "NSW"), - ("Australia/North", "North"), - ("Australia/Perth", "Perth"), - ("Australia/Queensland", "Queensland"), - ("Australia/South", "South"), - ("Australia/Sydney", "Sydney"), - ("Australia/Tasmania", "Tasmania"), - ("Australia/Victoria", "Victoria"), - ("Australia/West", "West"), - ("Australia/Yancowinna", "Yancowinna"), - ], - ), - ( - "Brazil", - [ - ("Brazil/Acre", "Acre"), - ("Brazil/DeNoronha", "DeNoronha"), - ("Brazil/East", "East"), - ("Brazil/West", "West"), - ], - ), - ( - "Canada", - [ - ("Canada/Atlantic", "Atlantic"), - ("Canada/Central", "Central"), - ("Canada/Eastern", "Eastern"), - ("Canada/Mountain", "Mountain"), - ("Canada/Newfoundland", "Newfoundland"), - ("Canada/Pacific", "Pacific"), - ("Canada/Saskatchewan", "Saskatchewan"), - ("Canada/Yukon", "Yukon"), - ], - ), - ( - "Chile", - [ - ("Chile/Continental", "Continental"), - ("Chile/EasterIsland", "EasterIsland"), - ], - ), - ( - "Etc", - [ - ("Etc/Greenwich", "Greenwich"), - ("Etc/UCT", "UCT"), - ("Etc/UTC", "UTC"), - ("Etc/Universal", "Universal"), - ("Etc/Zulu", "Zulu"), - ], - ), - ( - "Europe", - [ - ("Europe/Amsterdam", "Amsterdam"), - ("Europe/Andorra", "Andorra"), - ("Europe/Astrakhan", "Astrakhan"), - ("Europe/Athens", "Athens"), - ("Europe/Belfast", "Belfast"), - ("Europe/Belgrade", "Belgrade"), - ("Europe/Berlin", "Berlin"), - ("Europe/Bratislava", "Bratislava"), - ("Europe/Brussels", "Brussels"), - ("Europe/Bucharest", "Bucharest"), - ("Europe/Budapest", "Budapest"), - ("Europe/Busingen", "Busingen"), - ("Europe/Chisinau", "Chisinau"), - ("Europe/Copenhagen", "Copenhagen"), - ("Europe/Dublin", "Dublin"), - ("Europe/Gibraltar", "Gibraltar"), - ("Europe/Guernsey", "Guernsey"), - ("Europe/Helsinki", "Helsinki"), - ("Europe/Isle_of_Man", "Isle_of_Man"), - ("Europe/Istanbul", "Istanbul"), - ("Europe/Jersey", "Jersey"), - ("Europe/Kaliningrad", "Kaliningrad"), - ("Europe/Kiev", "Kiev"), - ("Europe/Kirov", "Kirov"), - ("Europe/Lisbon", "Lisbon"), - ("Europe/Ljubljana", "Ljubljana"), - ("Europe/London", "London"), - ("Europe/Luxembourg", "Luxembourg"), - ("Europe/Madrid", "Madrid"), - ("Europe/Malta", "Malta"), - ("Europe/Mariehamn", "Mariehamn"), - ("Europe/Minsk", "Minsk"), - ("Europe/Monaco", "Monaco"), - ("Europe/Moscow", "Moscow"), - ("Europe/Nicosia", "Nicosia"), - ("Europe/Oslo", "Oslo"), - ("Europe/Paris", "Paris"), - ("Europe/Podgorica", "Podgorica"), - ("Europe/Prague", "Prague"), - ("Europe/Riga", "Riga"), - ("Europe/Rome", "Rome"), - ("Europe/Samara", "Samara"), - ("Europe/San_Marino", "San_Marino"), - ("Europe/Sarajevo", "Sarajevo"), - ("Europe/Saratov", "Saratov"), - ("Europe/Simferopol", "Simferopol"), - ("Europe/Skopje", "Skopje"), - ("Europe/Sofia", "Sofia"), - ("Europe/Stockholm", "Stockholm"), - ("Europe/Tallinn", "Tallinn"), - ("Europe/Tirane", "Tirane"), - ("Europe/Tiraspol", "Tiraspol"), - ("Europe/Ulyanovsk", "Ulyanovsk"), - ("Europe/Uzhgorod", "Uzhgorod"), - ("Europe/Vaduz", "Vaduz"), - ("Europe/Vatican", "Vatican"), - ("Europe/Vienna", "Vienna"), - ("Europe/Vilnius", "Vilnius"), - ("Europe/Volgograd", "Volgograd"), - ("Europe/Warsaw", "Warsaw"), - ("Europe/Zagreb", "Zagreb"), - ("Europe/Zaporozhye", "Zaporozhye"), - ("Europe/Zurich", "Zurich"), - ], - ), - ( - "Indian", - [ - ("Indian/Antananarivo", "Antananarivo"), - ("Indian/Chagos", "Chagos"), - ("Indian/Christmas", "Christmas"), - ("Indian/Cocos", "Cocos"), - ("Indian/Comoro", "Comoro"), - ("Indian/Kerguelen", "Kerguelen"), - ("Indian/Mahe", "Mahe"), - ("Indian/Maldives", "Maldives"), - ("Indian/Mauritius", "Mauritius"), - ("Indian/Mayotte", "Mayotte"), - ("Indian/Reunion", "Reunion"), - ], - ), - ( - "Mexico", - [ - ("Mexico/BajaNorte", "BajaNorte"), - ("Mexico/BajaSur", "BajaSur"), - ("Mexico/General", "General"), - ], - ), - ( - "Other", - [ - ("CET", "CET"), - ("CST6CDT", "CST6CDT"), - ("Cuba", "Cuba"), - ("EET", "EET"), - ("EST", "EST"), - ("EST5EDT", "EST5EDT"), - ("Egypt", "Egypt"), - ("Eire", "Eire"), - ("GB", "GB"), - ("GB-Eire", "GB-Eire"), - ("Greenwich", "Greenwich"), - ("HST", "HST"), - ("Hongkong", "Hongkong"), - ("Iceland", "Iceland"), - ("Iran", "Iran"), - ("Israel", "Israel"), - ("Jamaica", "Jamaica"), - ("Japan", "Japan"), - ("Kwajalein", "Kwajalein"), - ("Libya", "Libya"), - ("MET", "MET"), - ("MST", "MST"), - ("MST7MDT", "MST7MDT"), - ("NZ", "NZ"), - ("NZ-CHAT", "NZ-CHAT"), - ("Navajo", "Navajo"), - ("PRC", "PRC"), - ("PST8PDT", "PST8PDT"), - ("Poland", "Poland"), - ("Portugal", "Portugal"), - ("ROC", "ROC"), - ("ROK", "ROK"), - ("Singapore", "Singapore"), - ("Turkey", "Turkey"), - ("UCT", "UCT"), - ("UTC", "UTC"), - ("Universal", "Universal"), - ("W-SU", "W-SU"), - ("WET", "WET"), - ("Zulu", "Zulu"), - ], - ), - ( - "Pacific", - [ - ("Pacific/Apia", "Apia"), - ("Pacific/Auckland", "Auckland"), - ("Pacific/Bougainville", "Bougainville"), - ("Pacific/Chatham", "Chatham"), - ("Pacific/Chuuk", "Chuuk"), - ("Pacific/Easter", "Easter"), - ("Pacific/Efate", "Efate"), - ("Pacific/Enderbury", "Enderbury"), - ("Pacific/Fakaofo", "Fakaofo"), - ("Pacific/Fiji", "Fiji"), - ("Pacific/Funafuti", "Funafuti"), - ("Pacific/Galapagos", "Galapagos"), - ("Pacific/Gambier", "Gambier"), - ("Pacific/Guadalcanal", "Guadalcanal"), - ("Pacific/Guam", "Guam"), - ("Pacific/Honolulu", "Honolulu"), - ("Pacific/Johnston", "Johnston"), - ("Pacific/Kiritimati", "Kiritimati"), - ("Pacific/Kosrae", "Kosrae"), - ("Pacific/Kwajalein", "Kwajalein"), - ("Pacific/Majuro", "Majuro"), - ("Pacific/Marquesas", "Marquesas"), - ("Pacific/Midway", "Midway"), - ("Pacific/Nauru", "Nauru"), - ("Pacific/Niue", "Niue"), - ("Pacific/Norfolk", "Norfolk"), - ("Pacific/Noumea", "Noumea"), - ("Pacific/Pago_Pago", "Pago_Pago"), - ("Pacific/Palau", "Palau"), - ("Pacific/Pitcairn", "Pitcairn"), - ("Pacific/Pohnpei", "Pohnpei"), - ("Pacific/Ponape", "Ponape"), - ("Pacific/Port_Moresby", "Port_Moresby"), - ("Pacific/Rarotonga", "Rarotonga"), - ("Pacific/Saipan", "Saipan"), - ("Pacific/Samoa", "Samoa"), - ("Pacific/Tahiti", "Tahiti"), - ("Pacific/Tarawa", "Tarawa"), - ("Pacific/Tongatapu", "Tongatapu"), - ("Pacific/Truk", "Truk"), - ("Pacific/Wake", "Wake"), - ("Pacific/Wallis", "Wallis"), - ("Pacific/Yap", "Yap"), - ], - ), - ( - "US", - [ - ("US/Alaska", "Alaska"), - ("US/Aleutian", "Aleutian"), - ("US/Arizona", "Arizona"), - ("US/Central", "Central"), - ("US/East-Indiana", "East-Indiana"), - ("US/Eastern", "Eastern"), - ("US/Hawaii", "Hawaii"), - ("US/Indiana-Starke", "Indiana-Starke"), - ("US/Michigan", "Michigan"), - ("US/Mountain", "Mountain"), - ("US/Pacific", "Pacific"), - ("US/Samoa", "Samoa"), - ], - ), - ], - default="America/Toronto", - max_length=50, - verbose_name="location", - ), - ), - ("points", models.FloatField(db_index=True, default=0)), - ("performance_points", models.FloatField(db_index=True, default=0)), - ("problem_count", models.IntegerField(db_index=True, default=0)), - ( - "ace_theme", - models.CharField( - choices=[ - ("ambiance", "Ambiance"), - ("chaos", "Chaos"), - ("chrome", "Chrome"), - ("clouds", "Clouds"), - ("clouds_midnight", "Clouds Midnight"), - ("cobalt", "Cobalt"), - ("crimson_editor", "Crimson Editor"), - ("dawn", "Dawn"), - ("dreamweaver", "Dreamweaver"), - ("eclipse", "Eclipse"), - ("github", "Github"), - ("idle_fingers", "Idle Fingers"), - ("katzenmilch", "Katzenmilch"), - ("kr_theme", "KR Theme"), - ("kuroir", "Kuroir"), - ("merbivore", "Merbivore"), - ("merbivore_soft", "Merbivore Soft"), - ("mono_industrial", "Mono Industrial"), - ("monokai", "Monokai"), - ("pastel_on_dark", "Pastel on Dark"), - ("solarized_dark", "Solarized Dark"), - ("solarized_light", "Solarized Light"), - ("terminal", "Terminal"), - ("textmate", "Textmate"), - ("tomorrow", "Tomorrow"), - ("tomorrow_night", "Tomorrow Night"), - ("tomorrow_night_blue", "Tomorrow Night Blue"), - ("tomorrow_night_bright", "Tomorrow Night Bright"), - ("tomorrow_night_eighties", "Tomorrow Night Eighties"), - ("twilight", "Twilight"), - ("vibrant_ink", "Vibrant Ink"), - ("xcode", "XCode"), - ], - default="github", - max_length=30, - ), - ), - ( - "last_access", - models.DateTimeField( - default=django.utils.timezone.now, - verbose_name="last access time", - ), - ), - ( - "ip", - models.GenericIPAddressField( - blank=True, null=True, verbose_name="last IP" - ), - ), - ( - "display_rank", - models.CharField( - choices=[ - ("user", "Normal User"), - ("setter", "Problem Setter"), - ("admin", "Admin"), - ], - default="user", - max_length=10, - verbose_name="display rank", - ), - ), - ( - "mute", - models.BooleanField( - default=False, - help_text="Some users are at their best when silent.", - verbose_name="comment mute", - ), - ), - ( - "is_unlisted", - models.BooleanField( - default=False, - help_text="User will not be ranked.", - verbose_name="unlisted user", - ), - ), - ("rating", models.IntegerField(default=None, null=True)), - ( - "user_script", - models.TextField( - blank=True, - default="", - help_text="User-defined JavaScript for site customization.", - max_length=65536, - verbose_name="user script", - ), - ), - ( - "math_engine", - models.CharField( - choices=[ - ("tex", "Leave as LaTeX"), - ("svg", "SVG with PNG fallback"), - ("mml", "MathML only"), - ("jax", "MathJax with SVG/PNG fallback"), - ("auto", "Detect best quality"), - ], - default="auto", - help_text="the rendering engine used to render math", - max_length=4, - verbose_name="math engine", - ), - ), - ( - "is_totp_enabled", - models.BooleanField( - default=False, - help_text="check to enable TOTP-based two factor authentication", - verbose_name="2FA enabled", - ), - ), - ( - "totp_key", - judge.models.profile.EncryptedNullCharField( - blank=True, - help_text="32 character base32-encoded key for TOTP", - max_length=32, - null=True, - validators=[ - django.core.validators.RegexValidator( - "^$|^[A-Z2-7]{32}$", "TOTP key must be empty or base32" - ) - ], - verbose_name="TOTP key", - ), - ), - ( - "notes", - models.TextField( - blank=True, - help_text="Notes for administrators regarding this user.", - null=True, - verbose_name="internal notes", - ), - ), - ( - "current_contest", - models.OneToOneField( - blank=True, - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="+", - to="judge.ContestParticipation", - verbose_name="current contest", - ), - ), - ( - "language", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="judge.Language", - verbose_name="preferred language", - ), - ), - ( - "organizations", - sortedm2m.fields.SortedManyToManyField( - blank=True, - help_text=None, - related_name="members", - related_query_name="member", - to="judge.Organization", - verbose_name="organization", - ), - ), - ( - "user", - models.OneToOneField( - on_delete=django.db.models.deletion.CASCADE, - to=settings.AUTH_USER_MODEL, - verbose_name="user associated", - ), - ), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('about', models.TextField(blank=True, null=True, verbose_name='self-description')), + ('timezone', models.CharField(choices=[('Africa', [('Africa/Abidjan', 'Abidjan'), ('Africa/Accra', 'Accra'), ('Africa/Addis_Ababa', 'Addis_Ababa'), ('Africa/Algiers', 'Algiers'), ('Africa/Asmara', 'Asmara'), ('Africa/Asmera', 'Asmera'), ('Africa/Bamako', 'Bamako'), ('Africa/Bangui', 'Bangui'), ('Africa/Banjul', 'Banjul'), ('Africa/Bissau', 'Bissau'), ('Africa/Blantyre', 'Blantyre'), ('Africa/Brazzaville', 'Brazzaville'), ('Africa/Bujumbura', 'Bujumbura'), ('Africa/Cairo', 'Cairo'), ('Africa/Casablanca', 'Casablanca'), ('Africa/Ceuta', 'Ceuta'), ('Africa/Conakry', 'Conakry'), ('Africa/Dakar', 'Dakar'), ('Africa/Dar_es_Salaam', 'Dar_es_Salaam'), ('Africa/Djibouti', 'Djibouti'), ('Africa/Douala', 'Douala'), ('Africa/El_Aaiun', 'El_Aaiun'), ('Africa/Freetown', 'Freetown'), ('Africa/Gaborone', 'Gaborone'), ('Africa/Harare', 'Harare'), ('Africa/Johannesburg', 'Johannesburg'), ('Africa/Juba', 'Juba'), ('Africa/Kampala', 'Kampala'), ('Africa/Khartoum', 'Khartoum'), ('Africa/Kigali', 'Kigali'), ('Africa/Kinshasa', 'Kinshasa'), ('Africa/Lagos', 'Lagos'), ('Africa/Libreville', 'Libreville'), ('Africa/Lome', 'Lome'), ('Africa/Luanda', 'Luanda'), ('Africa/Lubumbashi', 'Lubumbashi'), ('Africa/Lusaka', 'Lusaka'), ('Africa/Malabo', 'Malabo'), ('Africa/Maputo', 'Maputo'), ('Africa/Maseru', 'Maseru'), ('Africa/Mbabane', 'Mbabane'), ('Africa/Mogadishu', 'Mogadishu'), ('Africa/Monrovia', 'Monrovia'), ('Africa/Nairobi', 'Nairobi'), ('Africa/Ndjamena', 'Ndjamena'), ('Africa/Niamey', 'Niamey'), ('Africa/Nouakchott', 'Nouakchott'), ('Africa/Ouagadougou', 'Ouagadougou'), ('Africa/Porto-Novo', 'Porto-Novo'), ('Africa/Sao_Tome', 'Sao_Tome'), ('Africa/Timbuktu', 'Timbuktu'), ('Africa/Tripoli', 'Tripoli'), ('Africa/Tunis', 'Tunis'), ('Africa/Windhoek', 'Windhoek')]), ('America', [('America/Adak', 'Adak'), ('America/Anchorage', 'Anchorage'), ('America/Anguilla', 'Anguilla'), ('America/Antigua', 'Antigua'), ('America/Araguaina', 'Araguaina'), ('America/Argentina/Buenos_Aires', 'Argentina/Buenos_Aires'), ('America/Argentina/Catamarca', 'Argentina/Catamarca'), ('America/Argentina/ComodRivadavia', 'Argentina/ComodRivadavia'), ('America/Argentina/Cordoba', 'Argentina/Cordoba'), ('America/Argentina/Jujuy', 'Argentina/Jujuy'), ('America/Argentina/La_Rioja', 'Argentina/La_Rioja'), ('America/Argentina/Mendoza', 'Argentina/Mendoza'), ('America/Argentina/Rio_Gallegos', 'Argentina/Rio_Gallegos'), ('America/Argentina/Salta', 'Argentina/Salta'), ('America/Argentina/San_Juan', 'Argentina/San_Juan'), ('America/Argentina/San_Luis', 'Argentina/San_Luis'), ('America/Argentina/Tucuman', 'Argentina/Tucuman'), ('America/Argentina/Ushuaia', 'Argentina/Ushuaia'), ('America/Aruba', 'Aruba'), ('America/Asuncion', 'Asuncion'), ('America/Atikokan', 'Atikokan'), ('America/Atka', 'Atka'), ('America/Bahia', 'Bahia'), ('America/Bahia_Banderas', 'Bahia_Banderas'), ('America/Barbados', 'Barbados'), ('America/Belem', 'Belem'), ('America/Belize', 'Belize'), ('America/Blanc-Sablon', 'Blanc-Sablon'), ('America/Boa_Vista', 'Boa_Vista'), ('America/Bogota', 'Bogota'), ('America/Boise', 'Boise'), ('America/Buenos_Aires', 'Buenos_Aires'), ('America/Cambridge_Bay', 'Cambridge_Bay'), ('America/Campo_Grande', 'Campo_Grande'), ('America/Cancun', 'Cancun'), ('America/Caracas', 'Caracas'), ('America/Catamarca', 'Catamarca'), ('America/Cayenne', 'Cayenne'), ('America/Cayman', 'Cayman'), ('America/Chicago', 'Chicago'), ('America/Chihuahua', 'Chihuahua'), ('America/Coral_Harbour', 'Coral_Harbour'), ('America/Cordoba', 'Cordoba'), ('America/Costa_Rica', 'Costa_Rica'), ('America/Creston', 'Creston'), ('America/Cuiaba', 'Cuiaba'), ('America/Curacao', 'Curacao'), ('America/Danmarkshavn', 'Danmarkshavn'), ('America/Dawson', 'Dawson'), ('America/Dawson_Creek', 'Dawson_Creek'), ('America/Denver', 'Denver'), ('America/Detroit', 'Detroit'), ('America/Dominica', 'Dominica'), ('America/Edmonton', 'Edmonton'), ('America/Eirunepe', 'Eirunepe'), ('America/El_Salvador', 'El_Salvador'), ('America/Ensenada', 'Ensenada'), ('America/Fort_Nelson', 'Fort_Nelson'), ('America/Fort_Wayne', 'Fort_Wayne'), ('America/Fortaleza', 'Fortaleza'), ('America/Glace_Bay', 'Glace_Bay'), ('America/Godthab', 'Godthab'), ('America/Goose_Bay', 'Goose_Bay'), ('America/Grand_Turk', 'Grand_Turk'), ('America/Grenada', 'Grenada'), ('America/Guadeloupe', 'Guadeloupe'), ('America/Guatemala', 'Guatemala'), ('America/Guayaquil', 'Guayaquil'), ('America/Guyana', 'Guyana'), ('America/Halifax', 'Halifax'), ('America/Havana', 'Havana'), ('America/Hermosillo', 'Hermosillo'), ('America/Indiana/Indianapolis', 'Indiana/Indianapolis'), ('America/Indiana/Knox', 'Indiana/Knox'), ('America/Indiana/Marengo', 'Indiana/Marengo'), ('America/Indiana/Petersburg', 'Indiana/Petersburg'), ('America/Indiana/Tell_City', 'Indiana/Tell_City'), ('America/Indiana/Vevay', 'Indiana/Vevay'), ('America/Indiana/Vincennes', 'Indiana/Vincennes'), ('America/Indiana/Winamac', 'Indiana/Winamac'), ('America/Indianapolis', 'Indianapolis'), ('America/Inuvik', 'Inuvik'), ('America/Iqaluit', 'Iqaluit'), ('America/Jamaica', 'Jamaica'), ('America/Jujuy', 'Jujuy'), ('America/Juneau', 'Juneau'), ('America/Kentucky/Louisville', 'Kentucky/Louisville'), ('America/Kentucky/Monticello', 'Kentucky/Monticello'), ('America/Knox_IN', 'Knox_IN'), ('America/Kralendijk', 'Kralendijk'), ('America/La_Paz', 'La_Paz'), ('America/Lima', 'Lima'), ('America/Los_Angeles', 'Los_Angeles'), ('America/Louisville', 'Louisville'), ('America/Lower_Princes', 'Lower_Princes'), ('America/Maceio', 'Maceio'), ('America/Managua', 'Managua'), ('America/Manaus', 'Manaus'), ('America/Marigot', 'Marigot'), ('America/Martinique', 'Martinique'), ('America/Matamoros', 'Matamoros'), ('America/Mazatlan', 'Mazatlan'), ('America/Mendoza', 'Mendoza'), ('America/Menominee', 'Menominee'), ('America/Merida', 'Merida'), ('America/Metlakatla', 'Metlakatla'), ('America/Mexico_City', 'Mexico_City'), ('America/Miquelon', 'Miquelon'), ('America/Moncton', 'Moncton'), ('America/Monterrey', 'Monterrey'), ('America/Montevideo', 'Montevideo'), ('America/Montreal', 'Montreal'), ('America/Montserrat', 'Montserrat'), ('America/Nassau', 'Nassau'), ('America/New_York', 'New_York'), ('America/Nipigon', 'Nipigon'), ('America/Nome', 'Nome'), ('America/Noronha', 'Noronha'), ('America/North_Dakota/Beulah', 'North_Dakota/Beulah'), ('America/North_Dakota/Center', 'North_Dakota/Center'), ('America/North_Dakota/New_Salem', 'North_Dakota/New_Salem'), ('America/Ojinaga', 'Ojinaga'), ('America/Panama', 'Panama'), ('America/Pangnirtung', 'Pangnirtung'), ('America/Paramaribo', 'Paramaribo'), ('America/Phoenix', 'Phoenix'), ('America/Port-au-Prince', 'Port-au-Prince'), ('America/Port_of_Spain', 'Port_of_Spain'), ('America/Porto_Acre', 'Porto_Acre'), ('America/Porto_Velho', 'Porto_Velho'), ('America/Puerto_Rico', 'Puerto_Rico'), ('America/Punta_Arenas', 'Punta_Arenas'), ('America/Rainy_River', 'Rainy_River'), ('America/Rankin_Inlet', 'Rankin_Inlet'), ('America/Recife', 'Recife'), ('America/Regina', 'Regina'), ('America/Resolute', 'Resolute'), ('America/Rio_Branco', 'Rio_Branco'), ('America/Rosario', 'Rosario'), ('America/Santa_Isabel', 'Santa_Isabel'), ('America/Santarem', 'Santarem'), ('America/Santiago', 'Santiago'), ('America/Santo_Domingo', 'Santo_Domingo'), ('America/Sao_Paulo', 'Sao_Paulo'), ('America/Scoresbysund', 'Scoresbysund'), ('America/Shiprock', 'Shiprock'), ('America/Sitka', 'Sitka'), ('America/St_Barthelemy', 'St_Barthelemy'), ('America/St_Johns', 'St_Johns'), ('America/St_Kitts', 'St_Kitts'), ('America/St_Lucia', 'St_Lucia'), ('America/St_Thomas', 'St_Thomas'), ('America/St_Vincent', 'St_Vincent'), ('America/Swift_Current', 'Swift_Current'), ('America/Tegucigalpa', 'Tegucigalpa'), ('America/Thule', 'Thule'), ('America/Thunder_Bay', 'Thunder_Bay'), ('America/Tijuana', 'Tijuana'), ('America/Toronto', 'Toronto'), ('America/Tortola', 'Tortola'), ('America/Vancouver', 'Vancouver'), ('America/Virgin', 'Virgin'), ('America/Whitehorse', 'Whitehorse'), ('America/Winnipeg', 'Winnipeg'), ('America/Yakutat', 'Yakutat'), ('America/Yellowknife', 'Yellowknife')]), ('Antarctica', [('Antarctica/Casey', 'Casey'), ('Antarctica/Davis', 'Davis'), ('Antarctica/DumontDUrville', 'DumontDUrville'), ('Antarctica/Macquarie', 'Macquarie'), ('Antarctica/Mawson', 'Mawson'), ('Antarctica/McMurdo', 'McMurdo'), ('Antarctica/Palmer', 'Palmer'), ('Antarctica/Rothera', 'Rothera'), ('Antarctica/South_Pole', 'South_Pole'), ('Antarctica/Syowa', 'Syowa'), ('Antarctica/Troll', 'Troll'), ('Antarctica/Vostok', 'Vostok')]), ('Arctic', [('Arctic/Longyearbyen', 'Longyearbyen')]), ('Asia', [('Asia/Aden', 'Aden'), ('Asia/Almaty', 'Almaty'), ('Asia/Amman', 'Amman'), ('Asia/Anadyr', 'Anadyr'), ('Asia/Aqtau', 'Aqtau'), ('Asia/Aqtobe', 'Aqtobe'), ('Asia/Ashgabat', 'Ashgabat'), ('Asia/Ashkhabad', 'Ashkhabad'), ('Asia/Atyrau', 'Atyrau'), ('Asia/Baghdad', 'Baghdad'), ('Asia/Bahrain', 'Bahrain'), ('Asia/Baku', 'Baku'), ('Asia/Bangkok', 'Bangkok'), ('Asia/Barnaul', 'Barnaul'), ('Asia/Beirut', 'Beirut'), ('Asia/Bishkek', 'Bishkek'), ('Asia/Brunei', 'Brunei'), ('Asia/Calcutta', 'Calcutta'), ('Asia/Chita', 'Chita'), ('Asia/Choibalsan', 'Choibalsan'), ('Asia/Chongqing', 'Chongqing'), ('Asia/Chungking', 'Chungking'), ('Asia/Colombo', 'Colombo'), ('Asia/Dacca', 'Dacca'), ('Asia/Damascus', 'Damascus'), ('Asia/Dhaka', 'Dhaka'), ('Asia/Dili', 'Dili'), ('Asia/Dubai', 'Dubai'), ('Asia/Dushanbe', 'Dushanbe'), ('Asia/Famagusta', 'Famagusta'), ('Asia/Gaza', 'Gaza'), ('Asia/Harbin', 'Harbin'), ('Asia/Hebron', 'Hebron'), ('Asia/Ho_Chi_Minh', 'Ho_Chi_Minh'), ('Asia/Hong_Kong', 'Hong_Kong'), ('Asia/Hovd', 'Hovd'), ('Asia/Irkutsk', 'Irkutsk'), ('Asia/Istanbul', 'Istanbul'), ('Asia/Jakarta', 'Jakarta'), ('Asia/Jayapura', 'Jayapura'), ('Asia/Jerusalem', 'Jerusalem'), ('Asia/Kabul', 'Kabul'), ('Asia/Kamchatka', 'Kamchatka'), ('Asia/Karachi', 'Karachi'), ('Asia/Kashgar', 'Kashgar'), ('Asia/Kathmandu', 'Kathmandu'), ('Asia/Katmandu', 'Katmandu'), ('Asia/Khandyga', 'Khandyga'), ('Asia/Kolkata', 'Kolkata'), ('Asia/Krasnoyarsk', 'Krasnoyarsk'), ('Asia/Kuala_Lumpur', 'Kuala_Lumpur'), ('Asia/Kuching', 'Kuching'), ('Asia/Kuwait', 'Kuwait'), ('Asia/Macao', 'Macao'), ('Asia/Macau', 'Macau'), ('Asia/Magadan', 'Magadan'), ('Asia/Makassar', 'Makassar'), ('Asia/Manila', 'Manila'), ('Asia/Muscat', 'Muscat'), ('Asia/Nicosia', 'Nicosia'), ('Asia/Novokuznetsk', 'Novokuznetsk'), ('Asia/Novosibirsk', 'Novosibirsk'), ('Asia/Omsk', 'Omsk'), ('Asia/Oral', 'Oral'), ('Asia/Phnom_Penh', 'Phnom_Penh'), ('Asia/Pontianak', 'Pontianak'), ('Asia/Pyongyang', 'Pyongyang'), ('Asia/Qatar', 'Qatar'), ('Asia/Qostanay', 'Qostanay'), ('Asia/Qyzylorda', 'Qyzylorda'), ('Asia/Rangoon', 'Rangoon'), ('Asia/Riyadh', 'Riyadh'), ('Asia/Saigon', 'Saigon'), ('Asia/Sakhalin', 'Sakhalin'), ('Asia/Samarkand', 'Samarkand'), ('Asia/Seoul', 'Seoul'), ('Asia/Shanghai', 'Shanghai'), ('Asia/Singapore', 'Singapore'), ('Asia/Srednekolymsk', 'Srednekolymsk'), ('Asia/Taipei', 'Taipei'), ('Asia/Tashkent', 'Tashkent'), ('Asia/Tbilisi', 'Tbilisi'), ('Asia/Tehran', 'Tehran'), ('Asia/Tel_Aviv', 'Tel_Aviv'), ('Asia/Thimbu', 'Thimbu'), ('Asia/Thimphu', 'Thimphu'), ('Asia/Tokyo', 'Tokyo'), ('Asia/Tomsk', 'Tomsk'), ('Asia/Ujung_Pandang', 'Ujung_Pandang'), ('Asia/Ulaanbaatar', 'Ulaanbaatar'), ('Asia/Ulan_Bator', 'Ulan_Bator'), ('Asia/Urumqi', 'Urumqi'), ('Asia/Ust-Nera', 'Ust-Nera'), ('Asia/Vientiane', 'Vientiane'), ('Asia/Vladivostok', 'Vladivostok'), ('Asia/Yakutsk', 'Yakutsk'), ('Asia/Yangon', 'Yangon'), ('Asia/Yekaterinburg', 'Yekaterinburg'), ('Asia/Yerevan', 'Yerevan')]), ('Atlantic', [('Atlantic/Azores', 'Azores'), ('Atlantic/Bermuda', 'Bermuda'), ('Atlantic/Canary', 'Canary'), ('Atlantic/Cape_Verde', 'Cape_Verde'), ('Atlantic/Faeroe', 'Faeroe'), ('Atlantic/Faroe', 'Faroe'), ('Atlantic/Jan_Mayen', 'Jan_Mayen'), ('Atlantic/Madeira', 'Madeira'), ('Atlantic/Reykjavik', 'Reykjavik'), ('Atlantic/South_Georgia', 'South_Georgia'), ('Atlantic/St_Helena', 'St_Helena'), ('Atlantic/Stanley', 'Stanley')]), ('Australia', [('Australia/ACT', 'ACT'), ('Australia/Adelaide', 'Adelaide'), ('Australia/Brisbane', 'Brisbane'), ('Australia/Broken_Hill', 'Broken_Hill'), ('Australia/Canberra', 'Canberra'), ('Australia/Currie', 'Currie'), ('Australia/Darwin', 'Darwin'), ('Australia/Eucla', 'Eucla'), ('Australia/Hobart', 'Hobart'), ('Australia/LHI', 'LHI'), ('Australia/Lindeman', 'Lindeman'), ('Australia/Lord_Howe', 'Lord_Howe'), ('Australia/Melbourne', 'Melbourne'), ('Australia/NSW', 'NSW'), ('Australia/North', 'North'), ('Australia/Perth', 'Perth'), ('Australia/Queensland', 'Queensland'), ('Australia/South', 'South'), ('Australia/Sydney', 'Sydney'), ('Australia/Tasmania', 'Tasmania'), ('Australia/Victoria', 'Victoria'), ('Australia/West', 'West'), ('Australia/Yancowinna', 'Yancowinna')]), ('Brazil', [('Brazil/Acre', 'Acre'), ('Brazil/DeNoronha', 'DeNoronha'), ('Brazil/East', 'East'), ('Brazil/West', 'West')]), ('Canada', [('Canada/Atlantic', 'Atlantic'), ('Canada/Central', 'Central'), ('Canada/Eastern', 'Eastern'), ('Canada/Mountain', 'Mountain'), ('Canada/Newfoundland', 'Newfoundland'), ('Canada/Pacific', 'Pacific'), ('Canada/Saskatchewan', 'Saskatchewan'), ('Canada/Yukon', 'Yukon')]), ('Chile', [('Chile/Continental', 'Continental'), ('Chile/EasterIsland', 'EasterIsland')]), ('Etc', [('Etc/Greenwich', 'Greenwich'), ('Etc/UCT', 'UCT'), ('Etc/UTC', 'UTC'), ('Etc/Universal', 'Universal'), ('Etc/Zulu', 'Zulu')]), ('Europe', [('Europe/Amsterdam', 'Amsterdam'), ('Europe/Andorra', 'Andorra'), ('Europe/Astrakhan', 'Astrakhan'), ('Europe/Athens', 'Athens'), ('Europe/Belfast', 'Belfast'), ('Europe/Belgrade', 'Belgrade'), ('Europe/Berlin', 'Berlin'), ('Europe/Bratislava', 'Bratislava'), ('Europe/Brussels', 'Brussels'), ('Europe/Bucharest', 'Bucharest'), ('Europe/Budapest', 'Budapest'), ('Europe/Busingen', 'Busingen'), ('Europe/Chisinau', 'Chisinau'), ('Europe/Copenhagen', 'Copenhagen'), ('Europe/Dublin', 'Dublin'), ('Europe/Gibraltar', 'Gibraltar'), ('Europe/Guernsey', 'Guernsey'), ('Europe/Helsinki', 'Helsinki'), ('Europe/Isle_of_Man', 'Isle_of_Man'), ('Europe/Istanbul', 'Istanbul'), ('Europe/Jersey', 'Jersey'), ('Europe/Kaliningrad', 'Kaliningrad'), ('Europe/Kiev', 'Kiev'), ('Europe/Kirov', 'Kirov'), ('Europe/Lisbon', 'Lisbon'), ('Europe/Ljubljana', 'Ljubljana'), ('Europe/London', 'London'), ('Europe/Luxembourg', 'Luxembourg'), ('Europe/Madrid', 'Madrid'), ('Europe/Malta', 'Malta'), ('Europe/Mariehamn', 'Mariehamn'), ('Europe/Minsk', 'Minsk'), ('Europe/Monaco', 'Monaco'), ('Europe/Moscow', 'Moscow'), ('Europe/Nicosia', 'Nicosia'), ('Europe/Oslo', 'Oslo'), ('Europe/Paris', 'Paris'), ('Europe/Podgorica', 'Podgorica'), ('Europe/Prague', 'Prague'), ('Europe/Riga', 'Riga'), ('Europe/Rome', 'Rome'), ('Europe/Samara', 'Samara'), ('Europe/San_Marino', 'San_Marino'), ('Europe/Sarajevo', 'Sarajevo'), ('Europe/Saratov', 'Saratov'), ('Europe/Simferopol', 'Simferopol'), ('Europe/Skopje', 'Skopje'), ('Europe/Sofia', 'Sofia'), ('Europe/Stockholm', 'Stockholm'), ('Europe/Tallinn', 'Tallinn'), ('Europe/Tirane', 'Tirane'), ('Europe/Tiraspol', 'Tiraspol'), ('Europe/Ulyanovsk', 'Ulyanovsk'), ('Europe/Uzhgorod', 'Uzhgorod'), ('Europe/Vaduz', 'Vaduz'), ('Europe/Vatican', 'Vatican'), ('Europe/Vienna', 'Vienna'), ('Europe/Vilnius', 'Vilnius'), ('Europe/Volgograd', 'Volgograd'), ('Europe/Warsaw', 'Warsaw'), ('Europe/Zagreb', 'Zagreb'), ('Europe/Zaporozhye', 'Zaporozhye'), ('Europe/Zurich', 'Zurich')]), ('Indian', [('Indian/Antananarivo', 'Antananarivo'), ('Indian/Chagos', 'Chagos'), ('Indian/Christmas', 'Christmas'), ('Indian/Cocos', 'Cocos'), ('Indian/Comoro', 'Comoro'), ('Indian/Kerguelen', 'Kerguelen'), ('Indian/Mahe', 'Mahe'), ('Indian/Maldives', 'Maldives'), ('Indian/Mauritius', 'Mauritius'), ('Indian/Mayotte', 'Mayotte'), ('Indian/Reunion', 'Reunion')]), ('Mexico', [('Mexico/BajaNorte', 'BajaNorte'), ('Mexico/BajaSur', 'BajaSur'), ('Mexico/General', 'General')]), ('Other', [('CET', 'CET'), ('CST6CDT', 'CST6CDT'), ('Cuba', 'Cuba'), ('EET', 'EET'), ('EST', 'EST'), ('EST5EDT', 'EST5EDT'), ('Egypt', 'Egypt'), ('Eire', 'Eire'), ('GB', 'GB'), ('GB-Eire', 'GB-Eire'), ('Greenwich', 'Greenwich'), ('HST', 'HST'), ('Hongkong', 'Hongkong'), ('Iceland', 'Iceland'), ('Iran', 'Iran'), ('Israel', 'Israel'), ('Jamaica', 'Jamaica'), ('Japan', 'Japan'), ('Kwajalein', 'Kwajalein'), ('Libya', 'Libya'), ('MET', 'MET'), ('MST', 'MST'), ('MST7MDT', 'MST7MDT'), ('NZ', 'NZ'), ('NZ-CHAT', 'NZ-CHAT'), ('Navajo', 'Navajo'), ('PRC', 'PRC'), ('PST8PDT', 'PST8PDT'), ('Poland', 'Poland'), ('Portugal', 'Portugal'), ('ROC', 'ROC'), ('ROK', 'ROK'), ('Singapore', 'Singapore'), ('Turkey', 'Turkey'), ('UCT', 'UCT'), ('UTC', 'UTC'), ('Universal', 'Universal'), ('W-SU', 'W-SU'), ('WET', 'WET'), ('Zulu', 'Zulu')]), ('Pacific', [('Pacific/Apia', 'Apia'), ('Pacific/Auckland', 'Auckland'), ('Pacific/Bougainville', 'Bougainville'), ('Pacific/Chatham', 'Chatham'), ('Pacific/Chuuk', 'Chuuk'), ('Pacific/Easter', 'Easter'), ('Pacific/Efate', 'Efate'), ('Pacific/Enderbury', 'Enderbury'), ('Pacific/Fakaofo', 'Fakaofo'), ('Pacific/Fiji', 'Fiji'), ('Pacific/Funafuti', 'Funafuti'), ('Pacific/Galapagos', 'Galapagos'), ('Pacific/Gambier', 'Gambier'), ('Pacific/Guadalcanal', 'Guadalcanal'), ('Pacific/Guam', 'Guam'), ('Pacific/Honolulu', 'Honolulu'), ('Pacific/Johnston', 'Johnston'), ('Pacific/Kiritimati', 'Kiritimati'), ('Pacific/Kosrae', 'Kosrae'), ('Pacific/Kwajalein', 'Kwajalein'), ('Pacific/Majuro', 'Majuro'), ('Pacific/Marquesas', 'Marquesas'), ('Pacific/Midway', 'Midway'), ('Pacific/Nauru', 'Nauru'), ('Pacific/Niue', 'Niue'), ('Pacific/Norfolk', 'Norfolk'), ('Pacific/Noumea', 'Noumea'), ('Pacific/Pago_Pago', 'Pago_Pago'), ('Pacific/Palau', 'Palau'), ('Pacific/Pitcairn', 'Pitcairn'), ('Pacific/Pohnpei', 'Pohnpei'), ('Pacific/Ponape', 'Ponape'), ('Pacific/Port_Moresby', 'Port_Moresby'), ('Pacific/Rarotonga', 'Rarotonga'), ('Pacific/Saipan', 'Saipan'), ('Pacific/Samoa', 'Samoa'), ('Pacific/Tahiti', 'Tahiti'), ('Pacific/Tarawa', 'Tarawa'), ('Pacific/Tongatapu', 'Tongatapu'), ('Pacific/Truk', 'Truk'), ('Pacific/Wake', 'Wake'), ('Pacific/Wallis', 'Wallis'), ('Pacific/Yap', 'Yap')]), ('US', [('US/Alaska', 'Alaska'), ('US/Aleutian', 'Aleutian'), ('US/Arizona', 'Arizona'), ('US/Central', 'Central'), ('US/East-Indiana', 'East-Indiana'), ('US/Eastern', 'Eastern'), ('US/Hawaii', 'Hawaii'), ('US/Indiana-Starke', 'Indiana-Starke'), ('US/Michigan', 'Michigan'), ('US/Mountain', 'Mountain'), ('US/Pacific', 'Pacific'), ('US/Samoa', 'Samoa')])], default='America/Toronto', max_length=50, verbose_name='location')), + ('points', models.FloatField(db_index=True, default=0)), + ('performance_points', models.FloatField(db_index=True, default=0)), + ('problem_count', models.IntegerField(db_index=True, default=0)), + ('ace_theme', models.CharField(choices=[('ambiance', 'Ambiance'), ('chaos', 'Chaos'), ('chrome', 'Chrome'), ('clouds', 'Clouds'), ('clouds_midnight', 'Clouds Midnight'), ('cobalt', 'Cobalt'), ('crimson_editor', 'Crimson Editor'), ('dawn', 'Dawn'), ('dreamweaver', 'Dreamweaver'), ('eclipse', 'Eclipse'), ('github', 'Github'), ('idle_fingers', 'Idle Fingers'), ('katzenmilch', 'Katzenmilch'), ('kr_theme', 'KR Theme'), ('kuroir', 'Kuroir'), ('merbivore', 'Merbivore'), ('merbivore_soft', 'Merbivore Soft'), ('mono_industrial', 'Mono Industrial'), ('monokai', 'Monokai'), ('pastel_on_dark', 'Pastel on Dark'), ('solarized_dark', 'Solarized Dark'), ('solarized_light', 'Solarized Light'), ('terminal', 'Terminal'), ('textmate', 'Textmate'), ('tomorrow', 'Tomorrow'), ('tomorrow_night', 'Tomorrow Night'), ('tomorrow_night_blue', 'Tomorrow Night Blue'), ('tomorrow_night_bright', 'Tomorrow Night Bright'), ('tomorrow_night_eighties', 'Tomorrow Night Eighties'), ('twilight', 'Twilight'), ('vibrant_ink', 'Vibrant Ink'), ('xcode', 'XCode')], default='github', max_length=30)), + ('last_access', models.DateTimeField(default=django.utils.timezone.now, verbose_name='last access time')), + ('ip', models.GenericIPAddressField(blank=True, null=True, verbose_name='last IP')), + ('display_rank', models.CharField(choices=[('user', 'Normal User'), ('setter', 'Problem Setter'), ('admin', 'Admin')], default='user', max_length=10, verbose_name='display rank')), + ('mute', models.BooleanField(default=False, help_text='Some users are at their best when silent.', verbose_name='comment mute')), + ('is_unlisted', models.BooleanField(default=False, help_text='User will not be ranked.', verbose_name='unlisted user')), + ('rating', models.IntegerField(default=None, null=True)), + ('user_script', models.TextField(blank=True, default='', help_text='User-defined JavaScript for site customization.', max_length=65536, verbose_name='user script')), + ('math_engine', models.CharField(choices=[('tex', 'Leave as LaTeX'), ('svg', 'SVG with PNG fallback'), ('mml', 'MathML only'), ('jax', 'MathJax with SVG/PNG fallback'), ('auto', 'Detect best quality')], default='auto', help_text='the rendering engine used to render math', max_length=4, verbose_name='math engine')), + ('is_totp_enabled', models.BooleanField(default=False, help_text='check to enable TOTP-based two factor authentication', verbose_name='2FA enabled')), + ('totp_key', judge.models.profile.EncryptedNullCharField(blank=True, help_text='32 character base32-encoded key for TOTP', max_length=32, null=True, validators=[django.core.validators.RegexValidator('^$|^[A-Z2-7]{32}$', 'TOTP key must be empty or base32')], verbose_name='TOTP key')), + ('notes', models.TextField(blank=True, help_text='Notes for administrators regarding this user.', null=True, verbose_name='internal notes')), + ('current_contest', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='judge.ContestParticipation', verbose_name='current contest')), + ('language', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='judge.Language', verbose_name='preferred language')), + ('organizations', sortedm2m.fields.SortedManyToManyField(blank=True, help_text=None, related_name='members', related_query_name='member', to='judge.Organization', verbose_name='organization')), + ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='user associated')), ], options={ - "verbose_name_plural": "user profiles", - "permissions": ( - ("test_site", "Shows in-progress development stuff"), - ("totp", "Edit TOTP settings"), - ), - "verbose_name": "user profile", + 'verbose_name_plural': 'user profiles', + 'permissions': (('test_site', 'Shows in-progress development stuff'), ('totp', 'Edit TOTP settings')), + 'verbose_name': 'user profile', }, ), migrations.CreateModel( - name="Rating", + name='Rating', fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("rank", models.IntegerField(verbose_name="rank")), - ("rating", models.IntegerField(verbose_name="rating")), - ("volatility", models.IntegerField(verbose_name="volatility")), - ( - "last_rated", - models.DateTimeField(db_index=True, verbose_name="last rated"), - ), - ( - "contest", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="ratings", - to="judge.Contest", - verbose_name="contest", - ), - ), - ( - "participation", - models.OneToOneField( - on_delete=django.db.models.deletion.CASCADE, - related_name="rating", - to="judge.ContestParticipation", - verbose_name="participation", - ), - ), - ( - "user", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="ratings", - to="judge.Profile", - verbose_name="user", - ), - ), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('rank', models.IntegerField(verbose_name='rank')), + ('rating', models.IntegerField(verbose_name='rating')), + ('volatility', models.IntegerField(verbose_name='volatility')), + ('last_rated', models.DateTimeField(db_index=True, verbose_name='last rated')), + ('contest', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='ratings', to='judge.Contest', verbose_name='contest')), + ('participation', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='rating', to='judge.ContestParticipation', verbose_name='participation')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='ratings', to='judge.Profile', verbose_name='user')), ], options={ - "verbose_name_plural": "contest ratings", - "verbose_name": "contest rating", + 'verbose_name_plural': 'contest ratings', + 'verbose_name': 'contest rating', }, ), migrations.CreateModel( - name="RuntimeVersion", + name='RuntimeVersion', fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("name", models.CharField(max_length=64, verbose_name="runtime name")), - ( - "version", - models.CharField( - blank=True, max_length=64, verbose_name="runtime version" - ), - ), - ( - "priority", - models.IntegerField( - default=0, verbose_name="order in which to display this runtime" - ), - ), - ( - "judge", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="judge.Judge", - verbose_name="judge on which this runtime exists", - ), - ), - ( - "language", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="judge.Language", - verbose_name="language to which this runtime belongs", - ), - ), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=64, verbose_name='runtime name')), + ('version', models.CharField(blank=True, max_length=64, verbose_name='runtime version')), + ('priority', models.IntegerField(default=0, verbose_name='order in which to display this runtime')), + ('judge', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='judge.Judge', verbose_name='judge on which this runtime exists')), + ('language', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='judge.Language', verbose_name='language to which this runtime belongs')), ], ), migrations.CreateModel( - name="Solution", + name='Solution', fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "is_public", - models.BooleanField( - default=False, verbose_name="public visibility" - ), - ), - ("publish_on", models.DateTimeField(verbose_name="publish date")), - ("content", models.TextField(verbose_name="editorial content")), - ( - "authors", - models.ManyToManyField( - blank=True, to="judge.Profile", verbose_name="authors" - ), - ), - ( - "problem", - models.OneToOneField( - blank=True, - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="solution", - to="judge.Problem", - verbose_name="associated problem", - ), - ), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('is_public', models.BooleanField(default=False, verbose_name='public visibility')), + ('publish_on', models.DateTimeField(verbose_name='publish date')), + ('content', models.TextField(verbose_name='editorial content')), + ('authors', models.ManyToManyField(blank=True, to='judge.Profile', verbose_name='authors')), + ('problem', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='solution', to='judge.Problem', verbose_name='associated problem')), ], options={ - "verbose_name_plural": "solutions", - "permissions": (("see_private_solution", "See hidden solutions"),), - "verbose_name": "solution", + 'verbose_name_plural': 'solutions', + 'permissions': (('see_private_solution', 'See hidden solutions'),), + 'verbose_name': 'solution', }, ), migrations.CreateModel( - name="Submission", + name='Submission', fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "date", - models.DateTimeField( - auto_now_add=True, db_index=True, verbose_name="submission time" - ), - ), - ( - "time", - models.FloatField( - db_index=True, null=True, verbose_name="execution time" - ), - ), - ("memory", models.FloatField(null=True, verbose_name="memory usage")), - ( - "points", - models.FloatField( - db_index=True, null=True, verbose_name="points granted" - ), - ), - ( - "source", - models.TextField(max_length=65536, verbose_name="source code"), - ), - ( - "status", - models.CharField( - choices=[ - ("QU", "Queued"), - ("P", "Processing"), - ("G", "Grading"), - ("D", "Completed"), - ("IE", "Internal Error"), - ("CE", "Compile Error"), - ("AB", "Aborted"), - ], - db_index=True, - default="QU", - max_length=2, - verbose_name="status", - ), - ), - ( - "result", - models.CharField( - blank=True, - choices=[ - ("AC", "Accepted"), - ("WA", "Wrong Answer"), - ("TLE", "Time Limit Exceeded"), - ("MLE", "Memory Limit Exceeded"), - ("OLE", "Output Limit Exceeded"), - ("IR", "Invalid Return"), - ("RTE", "Runtime Error"), - ("CE", "Compile Error"), - ("IE", "Internal Error"), - ("SC", "Short circuit"), - ("AB", "Aborted"), - ], - db_index=True, - default=None, - max_length=3, - null=True, - verbose_name="result", - ), - ), - ( - "error", - models.TextField( - blank=True, null=True, verbose_name="compile errors" - ), - ), - ("current_testcase", models.IntegerField(default=0)), - ( - "batch", - models.BooleanField(default=False, verbose_name="batched cases"), - ), - ( - "case_points", - models.FloatField(default=0, verbose_name="test case points"), - ), - ( - "case_total", - models.FloatField(default=0, verbose_name="test case total points"), - ), - ( - "was_rejudged", - models.BooleanField( - default=False, verbose_name="was rejudged by admin" - ), - ), - ( - "is_pretested", - models.BooleanField( - default=False, verbose_name="was ran on pretests only" - ), - ), - ( - "judged_on", - models.ForeignKey( - blank=True, - null=True, - on_delete=django.db.models.deletion.SET_NULL, - to="judge.Judge", - verbose_name="judged on", - ), - ), - ( - "language", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="judge.Language", - verbose_name="submission language", - ), - ), - ( - "problem", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="judge.Problem" - ), - ), - ( - "user", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="judge.Profile" - ), - ), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('date', models.DateTimeField(auto_now_add=True, db_index=True, verbose_name='submission time')), + ('time', models.FloatField(db_index=True, null=True, verbose_name='execution time')), + ('memory', models.FloatField(null=True, verbose_name='memory usage')), + ('points', models.FloatField(db_index=True, null=True, verbose_name='points granted')), + ('source', models.TextField(max_length=65536, verbose_name='source code')), + ('status', models.CharField(choices=[('QU', 'Queued'), ('P', 'Processing'), ('G', 'Grading'), ('D', 'Completed'), ('IE', 'Internal Error'), ('CE', 'Compile Error'), ('AB', 'Aborted')], db_index=True, default='QU', max_length=2, verbose_name='status')), + ('result', models.CharField(blank=True, choices=[('AC', 'Accepted'), ('WA', 'Wrong Answer'), ('TLE', 'Time Limit Exceeded'), ('MLE', 'Memory Limit Exceeded'), ('OLE', 'Output Limit Exceeded'), ('IR', 'Invalid Return'), ('RTE', 'Runtime Error'), ('CE', 'Compile Error'), ('IE', 'Internal Error'), ('SC', 'Short circuit'), ('AB', 'Aborted')], db_index=True, default=None, max_length=3, null=True, verbose_name='result')), + ('error', models.TextField(blank=True, null=True, verbose_name='compile errors')), + ('current_testcase', models.IntegerField(default=0)), + ('batch', models.BooleanField(default=False, verbose_name='batched cases')), + ('case_points', models.FloatField(default=0, verbose_name='test case points')), + ('case_total', models.FloatField(default=0, verbose_name='test case total points')), + ('was_rejudged', models.BooleanField(default=False, verbose_name='was rejudged by admin')), + ('is_pretested', models.BooleanField(default=False, verbose_name='was ran on pretests only')), + ('judged_on', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='judge.Judge', verbose_name='judged on')), + ('language', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='judge.Language', verbose_name='submission language')), + ('problem', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='judge.Problem')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='judge.Profile')), ], options={ - "verbose_name_plural": "submissions", - "permissions": ( - ("abort_any_submission", "Abort any submission"), - ("rejudge_submission", "Rejudge the submission"), - ("rejudge_submission_lot", "Rejudge a lot of submissions"), - ("spam_submission", "Submit without limit"), - ("view_all_submission", "View all submission"), - ("resubmit_other", "Resubmit others' submission"), - ), - "verbose_name": "submission", + 'verbose_name_plural': 'submissions', + 'permissions': (('abort_any_submission', 'Abort any submission'), ('rejudge_submission', 'Rejudge the submission'), ('rejudge_submission_lot', 'Rejudge a lot of submissions'), ('spam_submission', 'Submit without limit'), ('view_all_submission', 'View all submission'), ('resubmit_other', "Resubmit others' submission")), + 'verbose_name': 'submission', }, ), migrations.CreateModel( - name="SubmissionTestCase", + name='SubmissionTestCase', fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("case", models.IntegerField(verbose_name="test case ID")), - ( - "status", - models.CharField( - choices=[ - ("AC", "Accepted"), - ("WA", "Wrong Answer"), - ("TLE", "Time Limit Exceeded"), - ("MLE", "Memory Limit Exceeded"), - ("OLE", "Output Limit Exceeded"), - ("IR", "Invalid Return"), - ("RTE", "Runtime Error"), - ("CE", "Compile Error"), - ("IE", "Internal Error"), - ("SC", "Short circuit"), - ("AB", "Aborted"), - ], - max_length=3, - verbose_name="status flag", - ), - ), - ("time", models.FloatField(null=True, verbose_name="execution time")), - ("memory", models.FloatField(null=True, verbose_name="memory usage")), - ("points", models.FloatField(null=True, verbose_name="points granted")), - ("total", models.FloatField(null=True, verbose_name="points possible")), - ("batch", models.IntegerField(null=True, verbose_name="batch number")), - ( - "feedback", - models.CharField( - blank=True, max_length=50, verbose_name="judging feedback" - ), - ), - ( - "extended_feedback", - models.TextField( - blank=True, verbose_name="extended judging feedback" - ), - ), - ("output", models.TextField(blank=True, verbose_name="program output")), - ( - "submission", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="test_cases", - to="judge.Submission", - verbose_name="associated submission", - ), - ), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('case', models.IntegerField(verbose_name='test case ID')), + ('status', models.CharField(choices=[('AC', 'Accepted'), ('WA', 'Wrong Answer'), ('TLE', 'Time Limit Exceeded'), ('MLE', 'Memory Limit Exceeded'), ('OLE', 'Output Limit Exceeded'), ('IR', 'Invalid Return'), ('RTE', 'Runtime Error'), ('CE', 'Compile Error'), ('IE', 'Internal Error'), ('SC', 'Short circuit'), ('AB', 'Aborted')], max_length=3, verbose_name='status flag')), + ('time', models.FloatField(null=True, verbose_name='execution time')), + ('memory', models.FloatField(null=True, verbose_name='memory usage')), + ('points', models.FloatField(null=True, verbose_name='points granted')), + ('total', models.FloatField(null=True, verbose_name='points possible')), + ('batch', models.IntegerField(null=True, verbose_name='batch number')), + ('feedback', models.CharField(blank=True, max_length=50, verbose_name='judging feedback')), + ('extended_feedback', models.TextField(blank=True, verbose_name='extended judging feedback')), + ('output', models.TextField(blank=True, verbose_name='program output')), + ('submission', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='test_cases', to='judge.Submission', verbose_name='associated submission')), ], options={ - "verbose_name_plural": "submission test cases", - "verbose_name": "submission test case", + 'verbose_name_plural': 'submission test cases', + 'verbose_name': 'submission test case', }, ), migrations.CreateModel( - name="Ticket", + name='Ticket', fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "title", - models.CharField(max_length=100, verbose_name="ticket title"), - ), - ( - "time", - models.DateTimeField( - auto_now_add=True, verbose_name="creation time" - ), - ), - ( - "notes", - models.TextField( - blank=True, - help_text="Staff notes for this issue to aid in processing.", - verbose_name="quick notes", - ), - ), - ( - "object_id", - models.PositiveIntegerField(verbose_name="linked item ID"), - ), - ( - "is_open", - models.BooleanField(default=True, verbose_name="is ticket open?"), - ), - ( - "assignees", - models.ManyToManyField( - related_name="assigned_tickets", - to="judge.Profile", - verbose_name="assignees", - ), - ), - ( - "content_type", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="contenttypes.ContentType", - verbose_name="linked item type", - ), - ), - ( - "user", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="tickets", - to="judge.Profile", - verbose_name="ticket creator", - ), - ), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=100, verbose_name='ticket title')), + ('time', models.DateTimeField(auto_now_add=True, verbose_name='creation time')), + ('notes', models.TextField(blank=True, help_text='Staff notes for this issue to aid in processing.', verbose_name='quick notes')), + ('object_id', models.PositiveIntegerField(verbose_name='linked item ID')), + ('is_open', models.BooleanField(default=True, verbose_name='is ticket open?')), + ('assignees', models.ManyToManyField(related_name='assigned_tickets', to='judge.Profile', verbose_name='assignees')), + ('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.ContentType', verbose_name='linked item type')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tickets', to='judge.Profile', verbose_name='ticket creator')), ], ), migrations.CreateModel( - name="TicketMessage", + name='TicketMessage', fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("body", models.TextField(verbose_name="message body")), - ( - "time", - models.DateTimeField( - auto_now_add=True, verbose_name="message time" - ), - ), - ( - "ticket", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="messages", - related_query_name="message", - to="judge.Ticket", - verbose_name="ticket", - ), - ), - ( - "user", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="ticket_messages", - to="judge.Profile", - verbose_name="poster", - ), - ), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('body', models.TextField(verbose_name='message body')), + ('time', models.DateTimeField(auto_now_add=True, verbose_name='message time')), + ('ticket', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='messages', related_query_name='message', to='judge.Ticket', verbose_name='ticket')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='ticket_messages', to='judge.Profile', verbose_name='poster')), ], ), migrations.AddField( - model_name="problem", - name="authors", - field=models.ManyToManyField( - blank=True, - related_name="authored_problems", - to="judge.Profile", - verbose_name="creators", - ), + model_name='problem', + name='authors', + field=models.ManyToManyField(blank=True, related_name='authored_problems', to='judge.Profile', verbose_name='creators'), ), migrations.AddField( - model_name="problem", - name="banned_users", - field=models.ManyToManyField( - blank=True, - help_text="Bans the selected users from submitting to this problem.", - to="judge.Profile", - verbose_name="personae non gratae", - ), + model_name='problem', + name='banned_users', + field=models.ManyToManyField(blank=True, help_text='Bans the selected users from submitting to this problem.', to='judge.Profile', verbose_name='personae non gratae'), ), migrations.AddField( - model_name="problem", - name="curators", - field=models.ManyToManyField( - blank=True, - help_text="These users will be able to edit a problem, but not be publicly shown as an author.", - related_name="curated_problems", - to="judge.Profile", - verbose_name="curators", - ), + model_name='problem', + name='curators', + field=models.ManyToManyField(blank=True, help_text='These users will be able to edit a problem, but not be publicly shown as an author.', related_name='curated_problems', to='judge.Profile', verbose_name='curators'), ), migrations.AddField( - model_name="problem", - name="group", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="judge.ProblemGroup", - verbose_name="problem group", - ), + model_name='problem', + name='group', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='judge.ProblemGroup', verbose_name='problem group'), ), migrations.AddField( - model_name="problem", - name="license", - field=models.ForeignKey( - blank=True, - null=True, - on_delete=django.db.models.deletion.SET_NULL, - to="judge.License", - ), + model_name='problem', + name='license', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='judge.License'), ), migrations.AddField( - model_name="problem", - name="organizations", - field=models.ManyToManyField( - blank=True, - help_text="If private, only these organizations may see the problem.", - to="judge.Organization", - verbose_name="organizations", - ), + model_name='problem', + name='organizations', + field=models.ManyToManyField(blank=True, help_text='If private, only these organizations may see the problem.', to='judge.Organization', verbose_name='organizations'), ), migrations.AddField( - model_name="problem", - name="testers", - field=models.ManyToManyField( - blank=True, - help_text="These users will be able to view a private problem, but not edit it.", - related_name="tested_problems", - to="judge.Profile", - verbose_name="testers", - ), + model_name='problem', + name='testers', + field=models.ManyToManyField(blank=True, help_text='These users will be able to view a private problem, but not edit it.', related_name='tested_problems', to='judge.Profile', verbose_name='testers'), ), migrations.AddField( - model_name="problem", - name="types", - field=models.ManyToManyField( - to="judge.ProblemType", verbose_name="problem types" - ), + model_name='problem', + name='types', + field=models.ManyToManyField(to='judge.ProblemType', verbose_name='problem types'), ), migrations.AddField( - model_name="privatemessage", - name="sender", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="sent_messages", - to="judge.Profile", - verbose_name="sender", - ), + model_name='privatemessage', + name='sender', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sent_messages', to='judge.Profile', verbose_name='sender'), ), migrations.AddField( - model_name="privatemessage", - name="target", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="received_messages", - to="judge.Profile", - verbose_name="target", - ), + model_name='privatemessage', + name='target', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='received_messages', to='judge.Profile', verbose_name='target'), ), migrations.AddField( - model_name="organizationrequest", - name="user", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="requests", - to="judge.Profile", - verbose_name="user", - ), + model_name='organizationrequest', + name='user', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='requests', to='judge.Profile', verbose_name='user'), ), migrations.AddField( - model_name="organization", - name="admins", - field=models.ManyToManyField( - help_text="Those who can edit this organization", - related_name="admin_of", - to="judge.Profile", - verbose_name="administrators", - ), + model_name='organization', + name='admins', + field=models.ManyToManyField(help_text='Those who can edit this organization', related_name='admin_of', to='judge.Profile', verbose_name='administrators'), ), migrations.AddField( - model_name="organization", - name="registrant", - field=models.ForeignKey( - help_text="User who registered this organization", - on_delete=django.db.models.deletion.CASCADE, - related_name="registrant+", - to="judge.Profile", - verbose_name="registrant", - ), + model_name='organization', + name='registrant', + field=models.ForeignKey(help_text='User who registered this organization', on_delete=django.db.models.deletion.CASCADE, related_name='registrant+', to='judge.Profile', verbose_name='registrant'), ), migrations.AddField( - model_name="languagelimit", - name="problem", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="language_limits", - to="judge.Problem", - verbose_name="problem", - ), + model_name='languagelimit', + name='problem', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='language_limits', to='judge.Problem', verbose_name='problem'), ), migrations.AddField( - model_name="judge", - name="problems", - field=models.ManyToManyField( - related_name="judges", to="judge.Problem", verbose_name="problems" - ), + model_name='judge', + name='problems', + field=models.ManyToManyField(related_name='judges', to='judge.Problem', verbose_name='problems'), ), migrations.AddField( - model_name="judge", - name="runtimes", - field=models.ManyToManyField( - related_name="judges", to="judge.Language", verbose_name="judges" - ), + model_name='judge', + name='runtimes', + field=models.ManyToManyField(related_name='judges', to='judge.Language', verbose_name='judges'), ), migrations.AddField( - model_name="contestsubmission", - name="submission", - field=models.OneToOneField( - on_delete=django.db.models.deletion.CASCADE, - related_name="contest", - to="judge.Submission", - verbose_name="submission", - ), + model_name='contestsubmission', + name='submission', + field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='contest', to='judge.Submission', verbose_name='submission'), ), migrations.AddField( - model_name="contestproblem", - name="problem", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="contests", - to="judge.Problem", - verbose_name="problem", - ), + model_name='contestproblem', + name='problem', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='contests', to='judge.Problem', verbose_name='problem'), ), migrations.AddField( - model_name="contestparticipation", - name="user", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="contest_history", - to="judge.Profile", - verbose_name="user", - ), + model_name='contestparticipation', + name='user', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='contest_history', to='judge.Profile', verbose_name='user'), ), migrations.AddField( - model_name="contest", - name="banned_users", - field=models.ManyToManyField( - blank=True, - help_text="Bans the selected users from joining this contest.", - to="judge.Profile", - verbose_name="personae non gratae", - ), + model_name='contest', + name='banned_users', + field=models.ManyToManyField(blank=True, help_text='Bans the selected users from joining this contest.', to='judge.Profile', verbose_name='personae non gratae'), ), migrations.AddField( - model_name="contest", - name="organizations", - field=models.ManyToManyField( - blank=True, - help_text="If private, only these organizations may see the contest", - to="judge.Organization", - verbose_name="organizations", - ), + model_name='contest', + name='organizations', + field=models.ManyToManyField(blank=True, help_text='If private, only these organizations may see the contest', to='judge.Organization', verbose_name='organizations'), ), migrations.AddField( - model_name="contest", - name="organizers", - field=models.ManyToManyField( - help_text="These people will be able to edit the contest.", - related_name="_contest_organizers_+", - to="judge.Profile", - ), + model_name='contest', + name='organizers', + field=models.ManyToManyField(help_text='These people will be able to edit the contest.', related_name='_contest_organizers_+', to='judge.Profile'), ), migrations.AddField( - model_name="contest", - name="problems", - field=models.ManyToManyField( - through="judge.ContestProblem", - to="judge.Problem", - verbose_name="problems", - ), + model_name='contest', + name='problems', + field=models.ManyToManyField(through='judge.ContestProblem', to='judge.Problem', verbose_name='problems'), ), migrations.AddField( - model_name="contest", - name="rate_exclude", - field=models.ManyToManyField( - blank=True, - related_name="_contest_rate_exclude_+", - to="judge.Profile", - verbose_name="exclude from ratings", - ), + model_name='contest', + name='rate_exclude', + field=models.ManyToManyField(blank=True, related_name='_contest_rate_exclude_+', to='judge.Profile', verbose_name='exclude from ratings'), ), migrations.AddField( - model_name="contest", - name="tags", - field=models.ManyToManyField( - blank=True, - related_name="contests", - to="judge.ContestTag", - verbose_name="contest tags", - ), + model_name='contest', + name='tags', + field=models.ManyToManyField(blank=True, related_name='contests', to='judge.ContestTag', verbose_name='contest tags'), ), migrations.AddField( - model_name="commentvote", - name="voter", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="voted_comments", - to="judge.Profile", - ), + model_name='commentvote', + name='voter', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='voted_comments', to='judge.Profile'), ), migrations.AddField( - model_name="comment", - name="author", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="judge.Profile", - verbose_name="commenter", - ), + model_name='comment', + name='author', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='judge.Profile', verbose_name='commenter'), ), migrations.AddField( - model_name="comment", - name="parent", - field=mptt.fields.TreeForeignKey( - blank=True, - null=True, - on_delete=django.db.models.deletion.CASCADE, - related_name="replies", - to="judge.Comment", - verbose_name="parent", - ), + model_name='comment', + name='parent', + field=mptt.fields.TreeForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='replies', to='judge.Comment', verbose_name='parent'), ), migrations.AddField( - model_name="blogpost", - name="authors", - field=models.ManyToManyField( - blank=True, to="judge.Profile", verbose_name="authors" - ), + model_name='blogpost', + name='authors', + field=models.ManyToManyField(blank=True, to='judge.Profile', verbose_name='authors'), ), migrations.AlterUniqueTogether( - name="rating", - unique_together=set([("user", "contest")]), + name='rating', + unique_together=set([('user', 'contest')]), ), migrations.AlterUniqueTogether( - name="problemtranslation", - unique_together=set([("problem", "language")]), + name='problemtranslation', + unique_together=set([('problem', 'language')]), ), migrations.AlterUniqueTogether( - name="languagelimit", - unique_together=set([("problem", "language")]), + name='languagelimit', + unique_together=set([('problem', 'language')]), ), migrations.AlterUniqueTogether( - name="contestproblem", - unique_together=set([("problem", "contest")]), + name='contestproblem', + unique_together=set([('problem', 'contest')]), ), migrations.AlterUniqueTogether( - name="contestparticipation", - unique_together=set([("contest", "user", "virtual")]), + name='contestparticipation', + unique_together=set([('contest', 'user', 'virtual')]), ), migrations.AlterUniqueTogether( - name="commentvote", - unique_together=set([("voter", "comment")]), + name='commentvote', + unique_together=set([('voter', 'comment')]), ), ] diff --git a/judge/migrations/0085_submission_source.py b/judge/migrations/0085_submission_source.py index 3f0dd18..d094efd 100644 --- a/judge/migrations/0085_submission_source.py +++ b/judge/migrations/0085_submission_source.py @@ -7,61 +7,33 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("judge", "0084_contest_formats"), + ('judge', '0084_contest_formats'), ] operations = [ migrations.CreateModel( - name="SubmissionSource", + name='SubmissionSource', fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "source", - models.TextField(max_length=65536, verbose_name="source code"), - ), - ( - "submission", - models.OneToOneField( - on_delete=django.db.models.deletion.CASCADE, - related_name="link", - to="judge.Submission", - verbose_name="associated submission", - ), - ), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('source', models.TextField(max_length=65536, verbose_name='source code')), + ('submission', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='link', to='judge.Submission', verbose_name='associated submission')), ], ), migrations.RunSQL( - [ - """INSERT INTO judge_submissionsource (source, submission_id) - SELECT source, id AS 'submission_id' FROM judge_submission;""" - ], - [ - """UPDATE judge_submission sub + ['''INSERT INTO judge_submissionsource (source, submission_id) + SELECT source, id AS 'submission_id' FROM judge_submission;'''], + ['''UPDATE judge_submission sub INNER JOIN judge_submissionsource src ON sub.id = src.submission_id - SET sub.source = src.source;""" - ], + SET sub.source = src.source;'''], elidable=True, ), migrations.RemoveField( - model_name="submission", - name="source", + model_name='submission', + name='source', ), migrations.AlterField( - model_name="submissionsource", - name="submission", - field=models.OneToOneField( - on_delete=django.db.models.deletion.CASCADE, - related_name="source", - to="judge.Submission", - verbose_name="associated submission", - ), + model_name='submissionsource', + name='submission', + field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='source', to='judge.Submission', verbose_name='associated submission'), ), ] diff --git a/judge/migrations/0086_rating_ceiling.py b/judge/migrations/0086_rating_ceiling.py index d529ac1..a544a21 100644 --- a/judge/migrations/0086_rating_ceiling.py +++ b/judge/migrations/0086_rating_ceiling.py @@ -6,28 +6,18 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("judge", "0085_submission_source"), + ('judge', '0085_submission_source'), ] operations = [ migrations.AddField( - model_name="contest", - name="rating_ceiling", - field=models.IntegerField( - blank=True, - help_text="Rating ceiling for contest", - null=True, - verbose_name="rating ceiling", - ), + model_name='contest', + name='rating_ceiling', + field=models.IntegerField(blank=True, help_text='Rating ceiling for contest', null=True, verbose_name='rating ceiling'), ), migrations.AddField( - model_name="contest", - name="rating_floor", - field=models.IntegerField( - blank=True, - help_text="Rating floor for contest", - null=True, - verbose_name="rating floor", - ), + model_name='contest', + name='rating_floor', + field=models.IntegerField(blank=True, help_text='Rating floor for contest', null=True, verbose_name='rating floor'), ), ] diff --git a/judge/migrations/0087_problem_resource_limits.py b/judge/migrations/0087_problem_resource_limits.py index c9fd18f..e6da153 100644 --- a/judge/migrations/0087_problem_resource_limits.py +++ b/judge/migrations/0087_problem_resource_limits.py @@ -7,28 +7,18 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("judge", "0086_rating_ceiling"), + ('judge', '0086_rating_ceiling'), ] operations = [ migrations.AlterField( - model_name="problem", - name="memory_limit", - field=models.PositiveIntegerField( - help_text="The memory limit for this problem, in kilobytes (e.g. 64mb = 65536 kilobytes).", - verbose_name="memory limit", - ), + model_name='problem', + name='memory_limit', + field=models.PositiveIntegerField(help_text='The memory limit for this problem, in kilobytes (e.g. 64mb = 65536 kilobytes).', verbose_name='memory limit'), ), migrations.AlterField( - model_name="problem", - name="time_limit", - field=models.FloatField( - help_text="The time limit for this problem, in seconds. Fractional seconds (e.g. 1.5) are supported.", - validators=[ - django.core.validators.MinValueValidator(0), - django.core.validators.MaxValueValidator(2000), - ], - verbose_name="time limit", - ), + model_name='problem', + name='time_limit', + field=models.FloatField(help_text='The time limit for this problem, in seconds. Fractional seconds (e.g. 1.5) are supported.', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(2000)], verbose_name='time limit'), ), ] diff --git a/judge/migrations/0088_private_contests.py b/judge/migrations/0088_private_contests.py index 8a5b886..b3505b5 100644 --- a/judge/migrations/0088_private_contests.py +++ b/judge/migrations/0088_private_contests.py @@ -6,53 +6,32 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("judge", "0087_problem_resource_limits"), + ('judge', '0087_problem_resource_limits'), ] operations = [ migrations.AlterModelOptions( - name="contest", - options={ - "permissions": ( - ("see_private_contest", "See private contests"), - ("edit_own_contest", "Edit own contests"), - ("edit_all_contest", "Edit all contests"), - ("contest_rating", "Rate contests"), - ("contest_access_code", "Contest access codes"), - ("create_private_contest", "Create private contests"), - ), - "verbose_name": "contest", - "verbose_name_plural": "contests", - }, + name='contest', + options={'permissions': (('see_private_contest', 'See private contests'), ('edit_own_contest', 'Edit own contests'), ('edit_all_contest', 'Edit all contests'), ('contest_rating', 'Rate contests'), ('contest_access_code', 'Contest access codes'), ('create_private_contest', 'Create private contests')), 'verbose_name': 'contest', 'verbose_name_plural': 'contests'}, ), migrations.RenameField( - model_name="contest", - old_name="is_public", - new_name="is_visible", + model_name='contest', + old_name='is_public', + new_name='is_visible', ), migrations.AddField( - model_name="contest", - name="is_organization_private", - field=models.BooleanField( - default=False, verbose_name="private to organizations" - ), + model_name='contest', + name='is_organization_private', + field=models.BooleanField(default=False, verbose_name='private to organizations'), ), migrations.AddField( - model_name="contest", - name="private_contestants", - field=models.ManyToManyField( - blank=True, - help_text="If private, only these users may see the contest", - related_name="_contest_private_contestants_+", - to="judge.Profile", - verbose_name="private contestants", - ), + model_name='contest', + name='private_contestants', + field=models.ManyToManyField(blank=True, help_text='If private, only these users may see the contest', related_name='_contest_private_contestants_+', to='judge.Profile', verbose_name='private contestants'), ), migrations.AlterField( - model_name="contest", - name="is_private", - field=models.BooleanField( - default=False, verbose_name="private to specific users" - ), + model_name='contest', + name='is_private', + field=models.BooleanField(default=False, verbose_name='private to specific users'), ), ] diff --git a/judge/migrations/0089_submission_to_contest.py b/judge/migrations/0089_submission_to_contest.py index f1cb283..5d464cb 100644 --- a/judge/migrations/0089_submission_to_contest.py +++ b/judge/migrations/0089_submission_to_contest.py @@ -7,31 +7,21 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("judge", "0088_private_contests"), + ('judge', '0088_private_contests'), ] operations = [ migrations.AddField( - model_name="submission", - name="contest_object", - field=models.ForeignKey( - blank=True, - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="+", - to="judge.Contest", - verbose_name="contest", - ), + model_name='submission', + name='contest_object', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='judge.Contest', verbose_name='contest'), ), - migrations.RunSQL( - """ + migrations.RunSQL(''' UPDATE `judge_submission` INNER JOIN `judge_contestsubmission` ON (`judge_submission`.`id` = `judge_contestsubmission`.`submission_id`) INNER JOIN `judge_contestparticipation` ON (`judge_contestsubmission`.`participation_id` = `judge_contestparticipation`.`id`) SET `judge_submission`.`contest_object_id` = `judge_contestparticipation`.`contest_id` - """, - migrations.RunSQL.noop, - ), + ''', migrations.RunSQL.noop), ] diff --git a/judge/migrations/0090_fix_contest_visibility.py b/judge/migrations/0090_fix_contest_visibility.py index 8e89949..10480fb 100644 --- a/judge/migrations/0090_fix_contest_visibility.py +++ b/judge/migrations/0090_fix_contest_visibility.py @@ -4,19 +4,16 @@ from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ("judge", "0089_submission_to_contest"), + ('judge', '0089_submission_to_contest'), ] operations = [ - migrations.RunSQL( - """ + migrations.RunSQL(''' UPDATE `judge_contest` SET `judge_contest`.`is_private` = 0, `judge_contest`.`is_organization_private` = 1 WHERE `judge_contest`.`is_private` = 1 - """, - """ + ''', ''' UPDATE `judge_contest` SET `judge_contest`.`is_private` = `judge_contest`.`is_organization_private` - """, - ), + '''), ] diff --git a/judge/migrations/0091_compiler_message_ansi2html.py b/judge/migrations/0091_compiler_message_ansi2html.py index 607ddee..7240f95 100644 --- a/judge/migrations/0091_compiler_message_ansi2html.py +++ b/judge/migrations/0091_compiler_message_ansi2html.py @@ -1,21 +1,21 @@ # -*- coding: utf-8 -*- import lxml.html as lh from django.db import migrations -from lxml_html_clean import clean_html +from lxml.html.clean import clean_html def strip_error_html(apps, schema_editor): - Submission = apps.get_model("judge", "Submission") + Submission = apps.get_model('judge', 'Submission') for sub in Submission.objects.filter(error__isnull=False).iterator(): if sub.error: sub.error = clean_html(lh.fromstring(sub.error)).text_content() - sub.save(update_fields=["error"]) + sub.save(update_fields=['error']) class Migration(migrations.Migration): dependencies = [ - ("judge", "0090_fix_contest_visibility"), + ('judge', '0090_fix_contest_visibility'), ] operations = [ diff --git a/judge/migrations/0092_contest_clone.py b/judge/migrations/0092_contest_clone.py index 0982ee8..0235513 100644 --- a/judge/migrations/0092_contest_clone.py +++ b/judge/migrations/0092_contest_clone.py @@ -6,24 +6,12 @@ from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ("judge", "0091_compiler_message_ansi2html"), + ('judge', '0091_compiler_message_ansi2html'), ] operations = [ migrations.AlterModelOptions( - name="contest", - options={ - "permissions": ( - ("see_private_contest", "See private contests"), - ("edit_own_contest", "Edit own contests"), - ("edit_all_contest", "Edit all contests"), - ("clone_contest", "Clone contest"), - ("contest_rating", "Rate contests"), - ("contest_access_code", "Contest access codes"), - ("create_private_contest", "Create private contests"), - ), - "verbose_name": "contest", - "verbose_name_plural": "contests", - }, + name='contest', + options={'permissions': (('see_private_contest', 'See private contests'), ('edit_own_contest', 'Edit own contests'), ('edit_all_contest', 'Edit all contests'), ('clone_contest', 'Clone contest'), ('contest_rating', 'Rate contests'), ('contest_access_code', 'Contest access codes'), ('create_private_contest', 'Create private contests')), 'verbose_name': 'contest', 'verbose_name_plural': 'contests'}, ), ] diff --git a/judge/migrations/0093_contest_moss.py b/judge/migrations/0093_contest_moss.py index 0dec938..10e2799 100644 --- a/judge/migrations/0093_contest_moss.py +++ b/judge/migrations/0093_contest_moss.py @@ -7,70 +7,39 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("judge", "0092_contest_clone"), + ('judge', '0092_contest_clone'), ] operations = [ migrations.CreateModel( - name="ContestMoss", + name='ContestMoss', fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("language", models.CharField(max_length=10)), - ("submission_count", models.PositiveIntegerField(default=0)), - ("url", models.URLField(blank=True, null=True)), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('language', models.CharField(max_length=10)), + ('submission_count', models.PositiveIntegerField(default=0)), + ('url', models.URLField(blank=True, null=True)), ], options={ - "verbose_name": "contest moss result", - "verbose_name_plural": "contest moss results", + 'verbose_name': 'contest moss result', + 'verbose_name_plural': 'contest moss results', }, ), migrations.AlterModelOptions( - name="contest", - options={ - "permissions": ( - ("see_private_contest", "See private contests"), - ("edit_own_contest", "Edit own contests"), - ("edit_all_contest", "Edit all contests"), - ("clone_contest", "Clone contest"), - ("moss_contest", "MOSS contest"), - ("contest_rating", "Rate contests"), - ("contest_access_code", "Contest access codes"), - ("create_private_contest", "Create private contests"), - ), - "verbose_name": "contest", - "verbose_name_plural": "contests", - }, + name='contest', + options={'permissions': (('see_private_contest', 'See private contests'), ('edit_own_contest', 'Edit own contests'), ('edit_all_contest', 'Edit all contests'), ('clone_contest', 'Clone contest'), ('moss_contest', 'MOSS contest'), ('contest_rating', 'Rate contests'), ('contest_access_code', 'Contest access codes'), ('create_private_contest', 'Create private contests')), 'verbose_name': 'contest', 'verbose_name_plural': 'contests'}, ), migrations.AddField( - model_name="contestmoss", - name="contest", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="moss", - to="judge.Contest", - verbose_name="contest", - ), + model_name='contestmoss', + name='contest', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='moss', to='judge.Contest', verbose_name='contest'), ), migrations.AddField( - model_name="contestmoss", - name="problem", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="moss", - to="judge.Problem", - verbose_name="problem", - ), + model_name='contestmoss', + name='problem', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='moss', to='judge.Problem', verbose_name='problem'), ), migrations.AlterUniqueTogether( - name="contestmoss", - unique_together={("contest", "problem", "language")}, + name='contestmoss', + unique_together={('contest', 'problem', 'language')}, ), ] diff --git a/judge/migrations/0094_submissiontestcase_unique_together.py b/judge/migrations/0094_submissiontestcase_unique_together.py index c56cded..8341329 100644 --- a/judge/migrations/0094_submissiontestcase_unique_together.py +++ b/judge/migrations/0094_submissiontestcase_unique_together.py @@ -3,12 +3,12 @@ from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ("judge", "0093_contest_moss"), + ('judge', '0093_contest_moss'), ] operations = [ migrations.AlterUniqueTogether( - name="submissiontestcase", - unique_together={("submission", "case")}, + name='submissiontestcase', + unique_together={('submission', 'case')}, ), ] diff --git a/judge/migrations/0095_organization_logo_override.py b/judge/migrations/0095_organization_logo_override.py index 6db6499..b1d86eb 100644 --- a/judge/migrations/0095_organization_logo_override.py +++ b/judge/migrations/0095_organization_logo_override.py @@ -6,19 +6,13 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("judge", "0094_submissiontestcase_unique_together"), + ('judge', '0094_submissiontestcase_unique_together'), ] operations = [ migrations.AddField( - model_name="organization", - name="logo_override_image", - field=models.CharField( - blank=True, - default="", - help_text="This image will replace the default site logo for users viewing the organization.", - max_length=150, - verbose_name="Logo override image", - ), + model_name='organization', + name='logo_override_image', + field=models.CharField(blank=True, default='', help_text='This image will replace the default site logo for users viewing the organization.', max_length=150, verbose_name='Logo override image'), ), ] diff --git a/judge/migrations/0096_profile_language_set_default.py b/judge/migrations/0096_profile_language_set_default.py index 1468f78..536b7fd 100644 --- a/judge/migrations/0096_profile_language_set_default.py +++ b/judge/migrations/0096_profile_language_set_default.py @@ -6,27 +6,16 @@ from django.db import migrations, models import judge.models.runtime -def create_python3(apps, schema_editor): - Language = apps.get_model("judge", "Language") - Language.objects.get_or_create(key="PY3", defaults={"name": "Python 3"})[0] - - class Migration(migrations.Migration): dependencies = [ - ("judge", "0095_organization_logo_override"), + ('judge', '0095_organization_logo_override'), ] operations = [ - migrations.RunPython(create_python3, reverse_code=migrations.RunPython.noop), migrations.AlterField( - model_name="profile", - name="language", - field=models.ForeignKey( - default=judge.models.runtime.Language.get_default_language_pk, - on_delete=django.db.models.deletion.SET_DEFAULT, - to="judge.Language", - verbose_name="preferred language", - ), + model_name='profile', + name='language', + field=models.ForeignKey(default=judge.models.runtime.Language.get_default_language_pk, on_delete=django.db.models.deletion.SET_DEFAULT, to='judge.Language', verbose_name='preferred language'), ), ] diff --git a/judge/migrations/0097_participation_is_disqualified.py b/judge/migrations/0097_participation_is_disqualified.py index 3d3f367..537f83f 100644 --- a/judge/migrations/0097_participation_is_disqualified.py +++ b/judge/migrations/0097_participation_is_disqualified.py @@ -6,26 +6,18 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("judge", "0096_profile_language_set_default"), + ('judge', '0096_profile_language_set_default'), ] operations = [ migrations.AddField( - model_name="contestparticipation", - name="is_disqualified", - field=models.BooleanField( - default=False, - help_text="Whether this participation is disqualified.", - verbose_name="is disqualified", - ), + model_name='contestparticipation', + name='is_disqualified', + field=models.BooleanField(default=False, help_text='Whether this participation is disqualified.', verbose_name='is disqualified'), ), migrations.AlterField( - model_name="contestparticipation", - name="virtual", - field=models.IntegerField( - default=0, - help_text="0 means non-virtual, otherwise the n-th virtual participation.", - verbose_name="virtual participation id", - ), + model_name='contestparticipation', + name='virtual', + field=models.IntegerField(default=0, help_text='0 means non-virtual, otherwise the n-th virtual participation.', verbose_name='virtual participation id'), ), ] diff --git a/judge/migrations/0098_auto_20200123_2136.py b/judge/migrations/0098_auto_20200123_2136.py index 3093cd3..333c67c 100644 --- a/judge/migrations/0098_auto_20200123_2136.py +++ b/judge/migrations/0098_auto_20200123_2136.py @@ -8,961 +8,148 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("judge", "0097_participation_is_disqualified"), + ('judge', '0097_participation_is_disqualified'), ] operations = [ migrations.AlterField( - model_name="comment", - name="level", + model_name='comment', + name='level', field=models.PositiveIntegerField(editable=False), ), migrations.AlterField( - model_name="comment", - name="lft", + model_name='comment', + name='lft', field=models.PositiveIntegerField(editable=False), ), migrations.AlterField( - model_name="comment", - name="rght", + model_name='comment', + name='rght', field=models.PositiveIntegerField(editable=False), ), migrations.AlterField( - model_name="contest", - name="format_name", - field=models.CharField( - choices=[ - ("atcoder", "AtCoder"), - ("default", "Default"), - ("ecoo", "ECOO"), - ("ioi", "IOI"), - ], - default="default", - help_text="The contest format module to use.", - max_length=32, - verbose_name="contest format", - ), + model_name='contest', + name='format_name', + field=models.CharField(choices=[('atcoder', 'AtCoder'), ('default', 'Default'), ('ecoo', 'ECOO'), ('ioi', 'IOI')], default='default', help_text='The contest format module to use.', max_length=32, verbose_name='contest format'), ), migrations.AlterField( - model_name="judge", - name="auth_key", - field=models.CharField( - help_text="A key to authenticate this judge", - max_length=100, - verbose_name="authentication key", - ), + model_name='judge', + name='auth_key', + field=models.CharField(help_text='A key to authenticate this judge', max_length=100, verbose_name='authentication key'), ), migrations.AlterField( - model_name="language", - name="description", - field=models.TextField( - blank=True, - help_text="Use this field to inform users of quirks with your environment, additional restrictions, etc.", - verbose_name="language description", - ), + model_name='language', + name='description', + field=models.TextField(blank=True, help_text='Use this field to inform users of quirks with your environment, additional restrictions, etc.', verbose_name='language description'), ), migrations.AlterField( - model_name="languagelimit", - name="memory_limit", - field=models.IntegerField( - validators=[ - django.core.validators.MinValueValidator(0), - django.core.validators.MaxValueValidator(1048576), - ], - verbose_name="memory limit", - ), + model_name='languagelimit', + name='memory_limit', + field=models.IntegerField(validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1048576)], verbose_name='memory limit'), ), migrations.AlterField( - model_name="languagelimit", - name="time_limit", - field=models.FloatField( - validators=[ - django.core.validators.MinValueValidator(0), - django.core.validators.MaxValueValidator(60), - ], - verbose_name="time limit", - ), + model_name='languagelimit', + name='time_limit', + field=models.FloatField(validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(60)], verbose_name='time limit'), ), migrations.AlterField( - model_name="navigationbar", - name="level", + model_name='navigationbar', + name='level', field=models.PositiveIntegerField(editable=False), ), migrations.AlterField( - model_name="navigationbar", - name="lft", + model_name='navigationbar', + name='lft', field=models.PositiveIntegerField(editable=False), ), migrations.AlterField( - model_name="navigationbar", - name="rght", + model_name='navigationbar', + name='rght', field=models.PositiveIntegerField(editable=False), ), migrations.AlterField( - model_name="problem", - name="allowed_languages", - field=models.ManyToManyField( - help_text="List of allowed submission languages.", - to="judge.Language", - verbose_name="allowed languages", - ), + model_name='problem', + name='allowed_languages', + field=models.ManyToManyField(help_text='List of allowed submission languages.', to='judge.Language', verbose_name='allowed languages'), ), migrations.AlterField( - model_name="problem", - name="authors", - field=models.ManyToManyField( - blank=True, - help_text="These users will be able to edit the problem, and be listed as authors.", - related_name="authored_problems", - to="judge.Profile", - verbose_name="creators", - ), + model_name='problem', + name='authors', + field=models.ManyToManyField(blank=True, help_text='These users will be able to edit the problem, and be listed as authors.', related_name='authored_problems', to='judge.Profile', verbose_name='creators'), ), migrations.AlterField( - model_name="problem", - name="code", - field=models.CharField( - help_text="A short, unique code for the problem, used in the url after /problem/", - max_length=20, - unique=True, - validators=[ - django.core.validators.RegexValidator( - "^[a-z0-9]+$", "Problem code must be ^[a-z0-9]+$" - ) - ], - verbose_name="problem code", - ), + model_name='problem', + name='code', + field=models.CharField(help_text='A short, unique code for the problem, used in the url after /problem/', max_length=20, unique=True, validators=[django.core.validators.RegexValidator('^[a-z0-9]+$', 'Problem code must be ^[a-z0-9]+$')], verbose_name='problem code'), ), migrations.AlterField( - model_name="problem", - name="curators", - field=models.ManyToManyField( - blank=True, - help_text="These users will be able to edit the problem, but not be listed as authors.", - related_name="curated_problems", - to="judge.Profile", - verbose_name="curators", - ), + model_name='problem', + name='curators', + field=models.ManyToManyField(blank=True, help_text='These users will be able to edit the problem, but not be listed as authors.', related_name='curated_problems', to='judge.Profile', verbose_name='curators'), ), migrations.AlterField( - model_name="problem", - name="group", - field=models.ForeignKey( - help_text="The group of problem, shown under Category in the problem list.", - on_delete=django.db.models.deletion.CASCADE, - to="judge.ProblemGroup", - verbose_name="problem group", - ), + model_name='problem', + name='group', + field=models.ForeignKey(help_text='The group of problem, shown under Category in the problem list.', on_delete=django.db.models.deletion.CASCADE, to='judge.ProblemGroup', verbose_name='problem group'), ), migrations.AlterField( - model_name="problem", - name="is_manually_managed", - field=models.BooleanField( - db_index=True, - default=False, - help_text="Whether judges should be allowed to manage data or not.", - verbose_name="manually managed", - ), + model_name='problem', + name='is_manually_managed', + field=models.BooleanField(db_index=True, default=False, help_text='Whether judges should be allowed to manage data or not.', verbose_name='manually managed'), ), migrations.AlterField( - model_name="problem", - name="license", - field=models.ForeignKey( - blank=True, - help_text="The license under which this problem is published.", - null=True, - on_delete=django.db.models.deletion.SET_NULL, - to="judge.License", - ), + model_name='problem', + name='license', + field=models.ForeignKey(blank=True, help_text='The license under which this problem is published.', null=True, on_delete=django.db.models.deletion.SET_NULL, to='judge.License'), ), migrations.AlterField( - model_name="problem", - name="memory_limit", - field=models.PositiveIntegerField( - help_text="The memory limit for this problem, in kilobytes (e.g. 64mb = 65536 kilobytes).", - validators=[ - django.core.validators.MinValueValidator(0), - django.core.validators.MaxValueValidator(1048576), - ], - verbose_name="memory limit", - ), + model_name='problem', + name='memory_limit', + field=models.PositiveIntegerField(help_text='The memory limit for this problem, in kilobytes (e.g. 64mb = 65536 kilobytes).', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1048576)], verbose_name='memory limit'), ), migrations.AlterField( - model_name="problem", - name="name", - field=models.CharField( - db_index=True, - help_text="The full name of the problem, as shown in the problem list.", - max_length=100, - verbose_name="problem name", - ), + model_name='problem', + name='name', + field=models.CharField(db_index=True, help_text='The full name of the problem, as shown in the problem list.', max_length=100, verbose_name='problem name'), ), migrations.AlterField( - model_name="problem", - name="points", - field=models.FloatField( - help_text="Points awarded for problem completion. Points are displayed with a 'p' suffix if partial.", - validators=[django.core.validators.MinValueValidator(0)], - verbose_name="points", - ), + model_name='problem', + name='points', + field=models.FloatField(help_text="Points awarded for problem completion. Points are displayed with a 'p' suffix if partial.", validators=[django.core.validators.MinValueValidator(0)], verbose_name='points'), ), migrations.AlterField( - model_name="problem", - name="testers", - field=models.ManyToManyField( - blank=True, - help_text="These users will be able to view the private problem, but not edit it.", - related_name="tested_problems", - to="judge.Profile", - verbose_name="testers", - ), + model_name='problem', + name='testers', + field=models.ManyToManyField(blank=True, help_text='These users will be able to view the private problem, but not edit it.', related_name='tested_problems', to='judge.Profile', verbose_name='testers'), ), migrations.AlterField( - model_name="problem", - name="time_limit", - field=models.FloatField( - help_text="The time limit for this problem, in seconds. Fractional seconds (e.g. 1.5) are supported.", - validators=[ - django.core.validators.MinValueValidator(0), - django.core.validators.MaxValueValidator(60), - ], - verbose_name="time limit", - ), + model_name='problem', + name='time_limit', + field=models.FloatField(help_text='The time limit for this problem, in seconds. Fractional seconds (e.g. 1.5) are supported.', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(60)], verbose_name='time limit'), ), migrations.AlterField( - model_name="problem", - name="types", - field=models.ManyToManyField( - help_text="The type of problem, as shown on the problem's page.", - to="judge.ProblemType", - verbose_name="problem types", - ), + model_name='problem', + name='types', + field=models.ManyToManyField(help_text="The type of problem, as shown on the problem's page.", to='judge.ProblemType', verbose_name='problem types'), ), migrations.AlterField( - model_name="problemdata", - name="checker", - field=models.CharField( - blank=True, - choices=[ - ("standard", "Standard"), - ("floats", "Floats"), - ("floatsabs", "Floats (absolute)"), - ("floatsrel", "Floats (relative)"), - ("rstripped", "Non-trailing spaces"), - ("sorted", "Unordered"), - ("identical", "Byte identical"), - ("linecount", "Line-by-line"), - ("checker.py", "Custom checker"), - ], - max_length=10, - verbose_name="checker", - ), + model_name='problemdata', + name='checker', + field=models.CharField(blank=True, choices=[('standard', 'Standard'), ('floats', 'Floats'), ('floatsabs', 'Floats (absolute)'), ('floatsrel', 'Floats (relative)'), ('rstripped', 'Non-trailing spaces'), ('sorted', 'Unordered'), ('identical', 'Byte identical'), ('linecount', 'Line-by-line'), ('checker.py', 'Custom checker')], max_length=10, verbose_name='checker'), ), migrations.AlterField( - model_name="problemtestcase", - name="checker", - field=models.CharField( - blank=True, - choices=[ - ("standard", "Standard"), - ("floats", "Floats"), - ("floatsabs", "Floats (absolute)"), - ("floatsrel", "Floats (relative)"), - ("rstripped", "Non-trailing spaces"), - ("sorted", "Unordered"), - ("identical", "Byte identical"), - ("linecount", "Line-by-line"), - ("checker.py", "Custom checker"), - ], - max_length=10, - verbose_name="checker", - ), + model_name='problemtestcase', + name='checker', + field=models.CharField(blank=True, choices=[('standard', 'Standard'), ('floats', 'Floats'), ('floatsabs', 'Floats (absolute)'), ('floatsrel', 'Floats (relative)'), ('rstripped', 'Non-trailing spaces'), ('sorted', 'Unordered'), ('identical', 'Byte identical'), ('linecount', 'Line-by-line'), ('checker.py', 'Custom checker')], max_length=10, verbose_name='checker'), ), migrations.AlterField( - model_name="problemtranslation", - name="language", - field=models.CharField( - choices=[ - ("de", "German"), - ("en", "English"), - ("es", "Spanish"), - ("fr", "French"), - ("hr", "Croatian"), - ("hu", "Hungarian"), - ("ja", "Japanese"), - ("ko", "Korean"), - ("pt", "Brazilian Portuguese"), - ("ro", "Romanian"), - ("ru", "Russian"), - ("sr-latn", "Serbian (Latin)"), - ("tr", "Turkish"), - ("vi", "Vietnamese"), - ("zh-hans", "Simplified Chinese"), - ("zh-hant", "Traditional Chinese"), - ], - max_length=7, - verbose_name="language", - ), + model_name='problemtranslation', + name='language', + field=models.CharField(choices=[('de', 'German'), ('en', 'English'), ('es', 'Spanish'), ('fr', 'French'), ('hr', 'Croatian'), ('hu', 'Hungarian'), ('ja', 'Japanese'), ('ko', 'Korean'), ('pt', 'Brazilian Portuguese'), ('ro', 'Romanian'), ('ru', 'Russian'), ('sr-latn', 'Serbian (Latin)'), ('tr', 'Turkish'), ('vi', 'Vietnamese'), ('zh-hans', 'Simplified Chinese'), ('zh-hant', 'Traditional Chinese')], max_length=7, verbose_name='language'), ), migrations.AlterField( - model_name="profile", - name="timezone", - field=models.CharField( - choices=[ - ( - "Africa", - [ - ("Africa/Abidjan", "Abidjan"), - ("Africa/Accra", "Accra"), - ("Africa/Addis_Ababa", "Addis_Ababa"), - ("Africa/Algiers", "Algiers"), - ("Africa/Asmara", "Asmara"), - ("Africa/Asmera", "Asmera"), - ("Africa/Bamako", "Bamako"), - ("Africa/Bangui", "Bangui"), - ("Africa/Banjul", "Banjul"), - ("Africa/Bissau", "Bissau"), - ("Africa/Blantyre", "Blantyre"), - ("Africa/Brazzaville", "Brazzaville"), - ("Africa/Bujumbura", "Bujumbura"), - ("Africa/Cairo", "Cairo"), - ("Africa/Casablanca", "Casablanca"), - ("Africa/Ceuta", "Ceuta"), - ("Africa/Conakry", "Conakry"), - ("Africa/Dakar", "Dakar"), - ("Africa/Dar_es_Salaam", "Dar_es_Salaam"), - ("Africa/Djibouti", "Djibouti"), - ("Africa/Douala", "Douala"), - ("Africa/El_Aaiun", "El_Aaiun"), - ("Africa/Freetown", "Freetown"), - ("Africa/Gaborone", "Gaborone"), - ("Africa/Harare", "Harare"), - ("Africa/Johannesburg", "Johannesburg"), - ("Africa/Juba", "Juba"), - ("Africa/Kampala", "Kampala"), - ("Africa/Khartoum", "Khartoum"), - ("Africa/Kigali", "Kigali"), - ("Africa/Kinshasa", "Kinshasa"), - ("Africa/Lagos", "Lagos"), - ("Africa/Libreville", "Libreville"), - ("Africa/Lome", "Lome"), - ("Africa/Luanda", "Luanda"), - ("Africa/Lubumbashi", "Lubumbashi"), - ("Africa/Lusaka", "Lusaka"), - ("Africa/Malabo", "Malabo"), - ("Africa/Maputo", "Maputo"), - ("Africa/Maseru", "Maseru"), - ("Africa/Mbabane", "Mbabane"), - ("Africa/Mogadishu", "Mogadishu"), - ("Africa/Monrovia", "Monrovia"), - ("Africa/Nairobi", "Nairobi"), - ("Africa/Ndjamena", "Ndjamena"), - ("Africa/Niamey", "Niamey"), - ("Africa/Nouakchott", "Nouakchott"), - ("Africa/Ouagadougou", "Ouagadougou"), - ("Africa/Porto-Novo", "Porto-Novo"), - ("Africa/Sao_Tome", "Sao_Tome"), - ("Africa/Timbuktu", "Timbuktu"), - ("Africa/Tripoli", "Tripoli"), - ("Africa/Tunis", "Tunis"), - ("Africa/Windhoek", "Windhoek"), - ], - ), - ( - "America", - [ - ("America/Adak", "Adak"), - ("America/Anchorage", "Anchorage"), - ("America/Anguilla", "Anguilla"), - ("America/Antigua", "Antigua"), - ("America/Araguaina", "Araguaina"), - ( - "America/Argentina/Buenos_Aires", - "Argentina/Buenos_Aires", - ), - ("America/Argentina/Catamarca", "Argentina/Catamarca"), - ( - "America/Argentina/ComodRivadavia", - "Argentina/ComodRivadavia", - ), - ("America/Argentina/Cordoba", "Argentina/Cordoba"), - ("America/Argentina/Jujuy", "Argentina/Jujuy"), - ("America/Argentina/La_Rioja", "Argentina/La_Rioja"), - ("America/Argentina/Mendoza", "Argentina/Mendoza"), - ( - "America/Argentina/Rio_Gallegos", - "Argentina/Rio_Gallegos", - ), - ("America/Argentina/Salta", "Argentina/Salta"), - ("America/Argentina/San_Juan", "Argentina/San_Juan"), - ("America/Argentina/San_Luis", "Argentina/San_Luis"), - ("America/Argentina/Tucuman", "Argentina/Tucuman"), - ("America/Argentina/Ushuaia", "Argentina/Ushuaia"), - ("America/Aruba", "Aruba"), - ("America/Asuncion", "Asuncion"), - ("America/Atikokan", "Atikokan"), - ("America/Atka", "Atka"), - ("America/Bahia", "Bahia"), - ("America/Bahia_Banderas", "Bahia_Banderas"), - ("America/Barbados", "Barbados"), - ("America/Belem", "Belem"), - ("America/Belize", "Belize"), - ("America/Blanc-Sablon", "Blanc-Sablon"), - ("America/Boa_Vista", "Boa_Vista"), - ("America/Bogota", "Bogota"), - ("America/Boise", "Boise"), - ("America/Buenos_Aires", "Buenos_Aires"), - ("America/Cambridge_Bay", "Cambridge_Bay"), - ("America/Campo_Grande", "Campo_Grande"), - ("America/Cancun", "Cancun"), - ("America/Caracas", "Caracas"), - ("America/Catamarca", "Catamarca"), - ("America/Cayenne", "Cayenne"), - ("America/Cayman", "Cayman"), - ("America/Chicago", "Chicago"), - ("America/Chihuahua", "Chihuahua"), - ("America/Coral_Harbour", "Coral_Harbour"), - ("America/Cordoba", "Cordoba"), - ("America/Costa_Rica", "Costa_Rica"), - ("America/Creston", "Creston"), - ("America/Cuiaba", "Cuiaba"), - ("America/Curacao", "Curacao"), - ("America/Danmarkshavn", "Danmarkshavn"), - ("America/Dawson", "Dawson"), - ("America/Dawson_Creek", "Dawson_Creek"), - ("America/Denver", "Denver"), - ("America/Detroit", "Detroit"), - ("America/Dominica", "Dominica"), - ("America/Edmonton", "Edmonton"), - ("America/Eirunepe", "Eirunepe"), - ("America/El_Salvador", "El_Salvador"), - ("America/Ensenada", "Ensenada"), - ("America/Fort_Nelson", "Fort_Nelson"), - ("America/Fort_Wayne", "Fort_Wayne"), - ("America/Fortaleza", "Fortaleza"), - ("America/Glace_Bay", "Glace_Bay"), - ("America/Godthab", "Godthab"), - ("America/Goose_Bay", "Goose_Bay"), - ("America/Grand_Turk", "Grand_Turk"), - ("America/Grenada", "Grenada"), - ("America/Guadeloupe", "Guadeloupe"), - ("America/Guatemala", "Guatemala"), - ("America/Guayaquil", "Guayaquil"), - ("America/Guyana", "Guyana"), - ("America/Halifax", "Halifax"), - ("America/Havana", "Havana"), - ("America/Hermosillo", "Hermosillo"), - ("America/Indiana/Indianapolis", "Indiana/Indianapolis"), - ("America/Indiana/Knox", "Indiana/Knox"), - ("America/Indiana/Marengo", "Indiana/Marengo"), - ("America/Indiana/Petersburg", "Indiana/Petersburg"), - ("America/Indiana/Tell_City", "Indiana/Tell_City"), - ("America/Indiana/Vevay", "Indiana/Vevay"), - ("America/Indiana/Vincennes", "Indiana/Vincennes"), - ("America/Indiana/Winamac", "Indiana/Winamac"), - ("America/Indianapolis", "Indianapolis"), - ("America/Inuvik", "Inuvik"), - ("America/Iqaluit", "Iqaluit"), - ("America/Jamaica", "Jamaica"), - ("America/Jujuy", "Jujuy"), - ("America/Juneau", "Juneau"), - ("America/Kentucky/Louisville", "Kentucky/Louisville"), - ("America/Kentucky/Monticello", "Kentucky/Monticello"), - ("America/Knox_IN", "Knox_IN"), - ("America/Kralendijk", "Kralendijk"), - ("America/La_Paz", "La_Paz"), - ("America/Lima", "Lima"), - ("America/Los_Angeles", "Los_Angeles"), - ("America/Louisville", "Louisville"), - ("America/Lower_Princes", "Lower_Princes"), - ("America/Maceio", "Maceio"), - ("America/Managua", "Managua"), - ("America/Manaus", "Manaus"), - ("America/Marigot", "Marigot"), - ("America/Martinique", "Martinique"), - ("America/Matamoros", "Matamoros"), - ("America/Mazatlan", "Mazatlan"), - ("America/Mendoza", "Mendoza"), - ("America/Menominee", "Menominee"), - ("America/Merida", "Merida"), - ("America/Metlakatla", "Metlakatla"), - ("America/Mexico_City", "Mexico_City"), - ("America/Miquelon", "Miquelon"), - ("America/Moncton", "Moncton"), - ("America/Monterrey", "Monterrey"), - ("America/Montevideo", "Montevideo"), - ("America/Montreal", "Montreal"), - ("America/Montserrat", "Montserrat"), - ("America/Nassau", "Nassau"), - ("America/New_York", "New_York"), - ("America/Nipigon", "Nipigon"), - ("America/Nome", "Nome"), - ("America/Noronha", "Noronha"), - ("America/North_Dakota/Beulah", "North_Dakota/Beulah"), - ("America/North_Dakota/Center", "North_Dakota/Center"), - ( - "America/North_Dakota/New_Salem", - "North_Dakota/New_Salem", - ), - ("America/Ojinaga", "Ojinaga"), - ("America/Panama", "Panama"), - ("America/Pangnirtung", "Pangnirtung"), - ("America/Paramaribo", "Paramaribo"), - ("America/Phoenix", "Phoenix"), - ("America/Port-au-Prince", "Port-au-Prince"), - ("America/Port_of_Spain", "Port_of_Spain"), - ("America/Porto_Acre", "Porto_Acre"), - ("America/Porto_Velho", "Porto_Velho"), - ("America/Puerto_Rico", "Puerto_Rico"), - ("America/Punta_Arenas", "Punta_Arenas"), - ("America/Rainy_River", "Rainy_River"), - ("America/Rankin_Inlet", "Rankin_Inlet"), - ("America/Recife", "Recife"), - ("America/Regina", "Regina"), - ("America/Resolute", "Resolute"), - ("America/Rio_Branco", "Rio_Branco"), - ("America/Rosario", "Rosario"), - ("America/Santa_Isabel", "Santa_Isabel"), - ("America/Santarem", "Santarem"), - ("America/Santiago", "Santiago"), - ("America/Santo_Domingo", "Santo_Domingo"), - ("America/Sao_Paulo", "Sao_Paulo"), - ("America/Scoresbysund", "Scoresbysund"), - ("America/Shiprock", "Shiprock"), - ("America/Sitka", "Sitka"), - ("America/St_Barthelemy", "St_Barthelemy"), - ("America/St_Johns", "St_Johns"), - ("America/St_Kitts", "St_Kitts"), - ("America/St_Lucia", "St_Lucia"), - ("America/St_Thomas", "St_Thomas"), - ("America/St_Vincent", "St_Vincent"), - ("America/Swift_Current", "Swift_Current"), - ("America/Tegucigalpa", "Tegucigalpa"), - ("America/Thule", "Thule"), - ("America/Thunder_Bay", "Thunder_Bay"), - ("America/Tijuana", "Tijuana"), - ("America/Toronto", "Toronto"), - ("America/Tortola", "Tortola"), - ("America/Vancouver", "Vancouver"), - ("America/Virgin", "Virgin"), - ("America/Whitehorse", "Whitehorse"), - ("America/Winnipeg", "Winnipeg"), - ("America/Yakutat", "Yakutat"), - ("America/Yellowknife", "Yellowknife"), - ], - ), - ( - "Antarctica", - [ - ("Antarctica/Casey", "Casey"), - ("Antarctica/Davis", "Davis"), - ("Antarctica/DumontDUrville", "DumontDUrville"), - ("Antarctica/Macquarie", "Macquarie"), - ("Antarctica/Mawson", "Mawson"), - ("Antarctica/McMurdo", "McMurdo"), - ("Antarctica/Palmer", "Palmer"), - ("Antarctica/Rothera", "Rothera"), - ("Antarctica/South_Pole", "South_Pole"), - ("Antarctica/Syowa", "Syowa"), - ("Antarctica/Troll", "Troll"), - ("Antarctica/Vostok", "Vostok"), - ], - ), - ("Arctic", [("Arctic/Longyearbyen", "Longyearbyen")]), - ( - "Asia", - [ - ("Asia/Aden", "Aden"), - ("Asia/Almaty", "Almaty"), - ("Asia/Amman", "Amman"), - ("Asia/Anadyr", "Anadyr"), - ("Asia/Aqtau", "Aqtau"), - ("Asia/Aqtobe", "Aqtobe"), - ("Asia/Ashgabat", "Ashgabat"), - ("Asia/Ashkhabad", "Ashkhabad"), - ("Asia/Atyrau", "Atyrau"), - ("Asia/Baghdad", "Baghdad"), - ("Asia/Bahrain", "Bahrain"), - ("Asia/Baku", "Baku"), - ("Asia/Bangkok", "Bangkok"), - ("Asia/Barnaul", "Barnaul"), - ("Asia/Beirut", "Beirut"), - ("Asia/Bishkek", "Bishkek"), - ("Asia/Brunei", "Brunei"), - ("Asia/Calcutta", "Calcutta"), - ("Asia/Chita", "Chita"), - ("Asia/Choibalsan", "Choibalsan"), - ("Asia/Chongqing", "Chongqing"), - ("Asia/Chungking", "Chungking"), - ("Asia/Colombo", "Colombo"), - ("Asia/Dacca", "Dacca"), - ("Asia/Damascus", "Damascus"), - ("Asia/Dhaka", "Dhaka"), - ("Asia/Dili", "Dili"), - ("Asia/Dubai", "Dubai"), - ("Asia/Dushanbe", "Dushanbe"), - ("Asia/Famagusta", "Famagusta"), - ("Asia/Gaza", "Gaza"), - ("Asia/Harbin", "Harbin"), - ("Asia/Hebron", "Hebron"), - ("Asia/Ho_Chi_Minh", "Ho_Chi_Minh"), - ("Asia/Hong_Kong", "Hong_Kong"), - ("Asia/Hovd", "Hovd"), - ("Asia/Irkutsk", "Irkutsk"), - ("Asia/Istanbul", "Istanbul"), - ("Asia/Jakarta", "Jakarta"), - ("Asia/Jayapura", "Jayapura"), - ("Asia/Jerusalem", "Jerusalem"), - ("Asia/Kabul", "Kabul"), - ("Asia/Kamchatka", "Kamchatka"), - ("Asia/Karachi", "Karachi"), - ("Asia/Kashgar", "Kashgar"), - ("Asia/Kathmandu", "Kathmandu"), - ("Asia/Katmandu", "Katmandu"), - ("Asia/Khandyga", "Khandyga"), - ("Asia/Kolkata", "Kolkata"), - ("Asia/Krasnoyarsk", "Krasnoyarsk"), - ("Asia/Kuala_Lumpur", "Kuala_Lumpur"), - ("Asia/Kuching", "Kuching"), - ("Asia/Kuwait", "Kuwait"), - ("Asia/Macao", "Macao"), - ("Asia/Macau", "Macau"), - ("Asia/Magadan", "Magadan"), - ("Asia/Makassar", "Makassar"), - ("Asia/Manila", "Manila"), - ("Asia/Muscat", "Muscat"), - ("Asia/Nicosia", "Nicosia"), - ("Asia/Novokuznetsk", "Novokuznetsk"), - ("Asia/Novosibirsk", "Novosibirsk"), - ("Asia/Omsk", "Omsk"), - ("Asia/Oral", "Oral"), - ("Asia/Phnom_Penh", "Phnom_Penh"), - ("Asia/Pontianak", "Pontianak"), - ("Asia/Pyongyang", "Pyongyang"), - ("Asia/Qatar", "Qatar"), - ("Asia/Qostanay", "Qostanay"), - ("Asia/Qyzylorda", "Qyzylorda"), - ("Asia/Rangoon", "Rangoon"), - ("Asia/Riyadh", "Riyadh"), - ("Asia/Saigon", "Saigon"), - ("Asia/Sakhalin", "Sakhalin"), - ("Asia/Samarkand", "Samarkand"), - ("Asia/Seoul", "Seoul"), - ("Asia/Shanghai", "Shanghai"), - ("Asia/Singapore", "Singapore"), - ("Asia/Srednekolymsk", "Srednekolymsk"), - ("Asia/Taipei", "Taipei"), - ("Asia/Tashkent", "Tashkent"), - ("Asia/Tbilisi", "Tbilisi"), - ("Asia/Tehran", "Tehran"), - ("Asia/Tel_Aviv", "Tel_Aviv"), - ("Asia/Thimbu", "Thimbu"), - ("Asia/Thimphu", "Thimphu"), - ("Asia/Tokyo", "Tokyo"), - ("Asia/Tomsk", "Tomsk"), - ("Asia/Ujung_Pandang", "Ujung_Pandang"), - ("Asia/Ulaanbaatar", "Ulaanbaatar"), - ("Asia/Ulan_Bator", "Ulan_Bator"), - ("Asia/Urumqi", "Urumqi"), - ("Asia/Ust-Nera", "Ust-Nera"), - ("Asia/Vientiane", "Vientiane"), - ("Asia/Vladivostok", "Vladivostok"), - ("Asia/Yakutsk", "Yakutsk"), - ("Asia/Yangon", "Yangon"), - ("Asia/Yekaterinburg", "Yekaterinburg"), - ("Asia/Yerevan", "Yerevan"), - ], - ), - ( - "Atlantic", - [ - ("Atlantic/Azores", "Azores"), - ("Atlantic/Bermuda", "Bermuda"), - ("Atlantic/Canary", "Canary"), - ("Atlantic/Cape_Verde", "Cape_Verde"), - ("Atlantic/Faeroe", "Faeroe"), - ("Atlantic/Faroe", "Faroe"), - ("Atlantic/Jan_Mayen", "Jan_Mayen"), - ("Atlantic/Madeira", "Madeira"), - ("Atlantic/Reykjavik", "Reykjavik"), - ("Atlantic/South_Georgia", "South_Georgia"), - ("Atlantic/St_Helena", "St_Helena"), - ("Atlantic/Stanley", "Stanley"), - ], - ), - ( - "Australia", - [ - ("Australia/ACT", "ACT"), - ("Australia/Adelaide", "Adelaide"), - ("Australia/Brisbane", "Brisbane"), - ("Australia/Broken_Hill", "Broken_Hill"), - ("Australia/Canberra", "Canberra"), - ("Australia/Currie", "Currie"), - ("Australia/Darwin", "Darwin"), - ("Australia/Eucla", "Eucla"), - ("Australia/Hobart", "Hobart"), - ("Australia/LHI", "LHI"), - ("Australia/Lindeman", "Lindeman"), - ("Australia/Lord_Howe", "Lord_Howe"), - ("Australia/Melbourne", "Melbourne"), - ("Australia/NSW", "NSW"), - ("Australia/North", "North"), - ("Australia/Perth", "Perth"), - ("Australia/Queensland", "Queensland"), - ("Australia/South", "South"), - ("Australia/Sydney", "Sydney"), - ("Australia/Tasmania", "Tasmania"), - ("Australia/Victoria", "Victoria"), - ("Australia/West", "West"), - ("Australia/Yancowinna", "Yancowinna"), - ], - ), - ( - "Brazil", - [ - ("Brazil/Acre", "Acre"), - ("Brazil/DeNoronha", "DeNoronha"), - ("Brazil/East", "East"), - ("Brazil/West", "West"), - ], - ), - ( - "Canada", - [ - ("Canada/Atlantic", "Atlantic"), - ("Canada/Central", "Central"), - ("Canada/Eastern", "Eastern"), - ("Canada/Mountain", "Mountain"), - ("Canada/Newfoundland", "Newfoundland"), - ("Canada/Pacific", "Pacific"), - ("Canada/Saskatchewan", "Saskatchewan"), - ("Canada/Yukon", "Yukon"), - ], - ), - ( - "Chile", - [ - ("Chile/Continental", "Continental"), - ("Chile/EasterIsland", "EasterIsland"), - ], - ), - ( - "Etc", - [ - ("Etc/Greenwich", "Greenwich"), - ("Etc/UCT", "UCT"), - ("Etc/UTC", "UTC"), - ("Etc/Universal", "Universal"), - ("Etc/Zulu", "Zulu"), - ], - ), - ( - "Europe", - [ - ("Europe/Amsterdam", "Amsterdam"), - ("Europe/Andorra", "Andorra"), - ("Europe/Astrakhan", "Astrakhan"), - ("Europe/Athens", "Athens"), - ("Europe/Belfast", "Belfast"), - ("Europe/Belgrade", "Belgrade"), - ("Europe/Berlin", "Berlin"), - ("Europe/Bratislava", "Bratislava"), - ("Europe/Brussels", "Brussels"), - ("Europe/Bucharest", "Bucharest"), - ("Europe/Budapest", "Budapest"), - ("Europe/Busingen", "Busingen"), - ("Europe/Chisinau", "Chisinau"), - ("Europe/Copenhagen", "Copenhagen"), - ("Europe/Dublin", "Dublin"), - ("Europe/Gibraltar", "Gibraltar"), - ("Europe/Guernsey", "Guernsey"), - ("Europe/Helsinki", "Helsinki"), - ("Europe/Isle_of_Man", "Isle_of_Man"), - ("Europe/Istanbul", "Istanbul"), - ("Europe/Jersey", "Jersey"), - ("Europe/Kaliningrad", "Kaliningrad"), - ("Europe/Kiev", "Kiev"), - ("Europe/Kirov", "Kirov"), - ("Europe/Lisbon", "Lisbon"), - ("Europe/Ljubljana", "Ljubljana"), - ("Europe/London", "London"), - ("Europe/Luxembourg", "Luxembourg"), - ("Europe/Madrid", "Madrid"), - ("Europe/Malta", "Malta"), - ("Europe/Mariehamn", "Mariehamn"), - ("Europe/Minsk", "Minsk"), - ("Europe/Monaco", "Monaco"), - ("Europe/Moscow", "Moscow"), - ("Europe/Nicosia", "Nicosia"), - ("Europe/Oslo", "Oslo"), - ("Europe/Paris", "Paris"), - ("Europe/Podgorica", "Podgorica"), - ("Europe/Prague", "Prague"), - ("Europe/Riga", "Riga"), - ("Europe/Rome", "Rome"), - ("Europe/Samara", "Samara"), - ("Europe/San_Marino", "San_Marino"), - ("Europe/Sarajevo", "Sarajevo"), - ("Europe/Saratov", "Saratov"), - ("Europe/Simferopol", "Simferopol"), - ("Europe/Skopje", "Skopje"), - ("Europe/Sofia", "Sofia"), - ("Europe/Stockholm", "Stockholm"), - ("Europe/Tallinn", "Tallinn"), - ("Europe/Tirane", "Tirane"), - ("Europe/Tiraspol", "Tiraspol"), - ("Europe/Ulyanovsk", "Ulyanovsk"), - ("Europe/Uzhgorod", "Uzhgorod"), - ("Europe/Vaduz", "Vaduz"), - ("Europe/Vatican", "Vatican"), - ("Europe/Vienna", "Vienna"), - ("Europe/Vilnius", "Vilnius"), - ("Europe/Volgograd", "Volgograd"), - ("Europe/Warsaw", "Warsaw"), - ("Europe/Zagreb", "Zagreb"), - ("Europe/Zaporozhye", "Zaporozhye"), - ("Europe/Zurich", "Zurich"), - ], - ), - ( - "Indian", - [ - ("Indian/Antananarivo", "Antananarivo"), - ("Indian/Chagos", "Chagos"), - ("Indian/Christmas", "Christmas"), - ("Indian/Cocos", "Cocos"), - ("Indian/Comoro", "Comoro"), - ("Indian/Kerguelen", "Kerguelen"), - ("Indian/Mahe", "Mahe"), - ("Indian/Maldives", "Maldives"), - ("Indian/Mauritius", "Mauritius"), - ("Indian/Mayotte", "Mayotte"), - ("Indian/Reunion", "Reunion"), - ], - ), - ( - "Mexico", - [ - ("Mexico/BajaNorte", "BajaNorte"), - ("Mexico/BajaSur", "BajaSur"), - ("Mexico/General", "General"), - ], - ), - ( - "Other", - [ - ("CET", "CET"), - ("CST6CDT", "CST6CDT"), - ("Cuba", "Cuba"), - ("EET", "EET"), - ("EST", "EST"), - ("EST5EDT", "EST5EDT"), - ("Egypt", "Egypt"), - ("Eire", "Eire"), - ("GB", "GB"), - ("GB-Eire", "GB-Eire"), - ("Greenwich", "Greenwich"), - ("HST", "HST"), - ("Hongkong", "Hongkong"), - ("Iceland", "Iceland"), - ("Iran", "Iran"), - ("Israel", "Israel"), - ("Jamaica", "Jamaica"), - ("Japan", "Japan"), - ("Kwajalein", "Kwajalein"), - ("Libya", "Libya"), - ("MET", "MET"), - ("MST", "MST"), - ("MST7MDT", "MST7MDT"), - ("NZ", "NZ"), - ("NZ-CHAT", "NZ-CHAT"), - ("Navajo", "Navajo"), - ("PRC", "PRC"), - ("PST8PDT", "PST8PDT"), - ("Poland", "Poland"), - ("Portugal", "Portugal"), - ("ROC", "ROC"), - ("ROK", "ROK"), - ("Singapore", "Singapore"), - ("Turkey", "Turkey"), - ("UCT", "UCT"), - ("UTC", "UTC"), - ("Universal", "Universal"), - ("W-SU", "W-SU"), - ("WET", "WET"), - ("Zulu", "Zulu"), - ], - ), - ( - "Pacific", - [ - ("Pacific/Apia", "Apia"), - ("Pacific/Auckland", "Auckland"), - ("Pacific/Bougainville", "Bougainville"), - ("Pacific/Chatham", "Chatham"), - ("Pacific/Chuuk", "Chuuk"), - ("Pacific/Easter", "Easter"), - ("Pacific/Efate", "Efate"), - ("Pacific/Enderbury", "Enderbury"), - ("Pacific/Fakaofo", "Fakaofo"), - ("Pacific/Fiji", "Fiji"), - ("Pacific/Funafuti", "Funafuti"), - ("Pacific/Galapagos", "Galapagos"), - ("Pacific/Gambier", "Gambier"), - ("Pacific/Guadalcanal", "Guadalcanal"), - ("Pacific/Guam", "Guam"), - ("Pacific/Honolulu", "Honolulu"), - ("Pacific/Johnston", "Johnston"), - ("Pacific/Kiritimati", "Kiritimati"), - ("Pacific/Kosrae", "Kosrae"), - ("Pacific/Kwajalein", "Kwajalein"), - ("Pacific/Majuro", "Majuro"), - ("Pacific/Marquesas", "Marquesas"), - ("Pacific/Midway", "Midway"), - ("Pacific/Nauru", "Nauru"), - ("Pacific/Niue", "Niue"), - ("Pacific/Norfolk", "Norfolk"), - ("Pacific/Noumea", "Noumea"), - ("Pacific/Pago_Pago", "Pago_Pago"), - ("Pacific/Palau", "Palau"), - ("Pacific/Pitcairn", "Pitcairn"), - ("Pacific/Pohnpei", "Pohnpei"), - ("Pacific/Ponape", "Ponape"), - ("Pacific/Port_Moresby", "Port_Moresby"), - ("Pacific/Rarotonga", "Rarotonga"), - ("Pacific/Saipan", "Saipan"), - ("Pacific/Samoa", "Samoa"), - ("Pacific/Tahiti", "Tahiti"), - ("Pacific/Tarawa", "Tarawa"), - ("Pacific/Tongatapu", "Tongatapu"), - ("Pacific/Truk", "Truk"), - ("Pacific/Wake", "Wake"), - ("Pacific/Wallis", "Wallis"), - ("Pacific/Yap", "Yap"), - ], - ), - ( - "US", - [ - ("US/Alaska", "Alaska"), - ("US/Aleutian", "Aleutian"), - ("US/Arizona", "Arizona"), - ("US/Central", "Central"), - ("US/East-Indiana", "East-Indiana"), - ("US/Eastern", "Eastern"), - ("US/Hawaii", "Hawaii"), - ("US/Indiana-Starke", "Indiana-Starke"), - ("US/Michigan", "Michigan"), - ("US/Mountain", "Mountain"), - ("US/Pacific", "Pacific"), - ("US/Samoa", "Samoa"), - ], - ), - ], - default="America/Mexico_City", - max_length=50, - verbose_name="location", - ), + model_name='profile', + name='timezone', + field=models.CharField(choices=[('Africa', [('Africa/Abidjan', 'Abidjan'), ('Africa/Accra', 'Accra'), ('Africa/Addis_Ababa', 'Addis_Ababa'), ('Africa/Algiers', 'Algiers'), ('Africa/Asmara', 'Asmara'), ('Africa/Asmera', 'Asmera'), ('Africa/Bamako', 'Bamako'), ('Africa/Bangui', 'Bangui'), ('Africa/Banjul', 'Banjul'), ('Africa/Bissau', 'Bissau'), ('Africa/Blantyre', 'Blantyre'), ('Africa/Brazzaville', 'Brazzaville'), ('Africa/Bujumbura', 'Bujumbura'), ('Africa/Cairo', 'Cairo'), ('Africa/Casablanca', 'Casablanca'), ('Africa/Ceuta', 'Ceuta'), ('Africa/Conakry', 'Conakry'), ('Africa/Dakar', 'Dakar'), ('Africa/Dar_es_Salaam', 'Dar_es_Salaam'), ('Africa/Djibouti', 'Djibouti'), ('Africa/Douala', 'Douala'), ('Africa/El_Aaiun', 'El_Aaiun'), ('Africa/Freetown', 'Freetown'), ('Africa/Gaborone', 'Gaborone'), ('Africa/Harare', 'Harare'), ('Africa/Johannesburg', 'Johannesburg'), ('Africa/Juba', 'Juba'), ('Africa/Kampala', 'Kampala'), ('Africa/Khartoum', 'Khartoum'), ('Africa/Kigali', 'Kigali'), ('Africa/Kinshasa', 'Kinshasa'), ('Africa/Lagos', 'Lagos'), ('Africa/Libreville', 'Libreville'), ('Africa/Lome', 'Lome'), ('Africa/Luanda', 'Luanda'), ('Africa/Lubumbashi', 'Lubumbashi'), ('Africa/Lusaka', 'Lusaka'), ('Africa/Malabo', 'Malabo'), ('Africa/Maputo', 'Maputo'), ('Africa/Maseru', 'Maseru'), ('Africa/Mbabane', 'Mbabane'), ('Africa/Mogadishu', 'Mogadishu'), ('Africa/Monrovia', 'Monrovia'), ('Africa/Nairobi', 'Nairobi'), ('Africa/Ndjamena', 'Ndjamena'), ('Africa/Niamey', 'Niamey'), ('Africa/Nouakchott', 'Nouakchott'), ('Africa/Ouagadougou', 'Ouagadougou'), ('Africa/Porto-Novo', 'Porto-Novo'), ('Africa/Sao_Tome', 'Sao_Tome'), ('Africa/Timbuktu', 'Timbuktu'), ('Africa/Tripoli', 'Tripoli'), ('Africa/Tunis', 'Tunis'), ('Africa/Windhoek', 'Windhoek')]), ('America', [('America/Adak', 'Adak'), ('America/Anchorage', 'Anchorage'), ('America/Anguilla', 'Anguilla'), ('America/Antigua', 'Antigua'), ('America/Araguaina', 'Araguaina'), ('America/Argentina/Buenos_Aires', 'Argentina/Buenos_Aires'), ('America/Argentina/Catamarca', 'Argentina/Catamarca'), ('America/Argentina/ComodRivadavia', 'Argentina/ComodRivadavia'), ('America/Argentina/Cordoba', 'Argentina/Cordoba'), ('America/Argentina/Jujuy', 'Argentina/Jujuy'), ('America/Argentina/La_Rioja', 'Argentina/La_Rioja'), ('America/Argentina/Mendoza', 'Argentina/Mendoza'), ('America/Argentina/Rio_Gallegos', 'Argentina/Rio_Gallegos'), ('America/Argentina/Salta', 'Argentina/Salta'), ('America/Argentina/San_Juan', 'Argentina/San_Juan'), ('America/Argentina/San_Luis', 'Argentina/San_Luis'), ('America/Argentina/Tucuman', 'Argentina/Tucuman'), ('America/Argentina/Ushuaia', 'Argentina/Ushuaia'), ('America/Aruba', 'Aruba'), ('America/Asuncion', 'Asuncion'), ('America/Atikokan', 'Atikokan'), ('America/Atka', 'Atka'), ('America/Bahia', 'Bahia'), ('America/Bahia_Banderas', 'Bahia_Banderas'), ('America/Barbados', 'Barbados'), ('America/Belem', 'Belem'), ('America/Belize', 'Belize'), ('America/Blanc-Sablon', 'Blanc-Sablon'), ('America/Boa_Vista', 'Boa_Vista'), ('America/Bogota', 'Bogota'), ('America/Boise', 'Boise'), ('America/Buenos_Aires', 'Buenos_Aires'), ('America/Cambridge_Bay', 'Cambridge_Bay'), ('America/Campo_Grande', 'Campo_Grande'), ('America/Cancun', 'Cancun'), ('America/Caracas', 'Caracas'), ('America/Catamarca', 'Catamarca'), ('America/Cayenne', 'Cayenne'), ('America/Cayman', 'Cayman'), ('America/Chicago', 'Chicago'), ('America/Chihuahua', 'Chihuahua'), ('America/Coral_Harbour', 'Coral_Harbour'), ('America/Cordoba', 'Cordoba'), ('America/Costa_Rica', 'Costa_Rica'), ('America/Creston', 'Creston'), ('America/Cuiaba', 'Cuiaba'), ('America/Curacao', 'Curacao'), ('America/Danmarkshavn', 'Danmarkshavn'), ('America/Dawson', 'Dawson'), ('America/Dawson_Creek', 'Dawson_Creek'), ('America/Denver', 'Denver'), ('America/Detroit', 'Detroit'), ('America/Dominica', 'Dominica'), ('America/Edmonton', 'Edmonton'), ('America/Eirunepe', 'Eirunepe'), ('America/El_Salvador', 'El_Salvador'), ('America/Ensenada', 'Ensenada'), ('America/Fort_Nelson', 'Fort_Nelson'), ('America/Fort_Wayne', 'Fort_Wayne'), ('America/Fortaleza', 'Fortaleza'), ('America/Glace_Bay', 'Glace_Bay'), ('America/Godthab', 'Godthab'), ('America/Goose_Bay', 'Goose_Bay'), ('America/Grand_Turk', 'Grand_Turk'), ('America/Grenada', 'Grenada'), ('America/Guadeloupe', 'Guadeloupe'), ('America/Guatemala', 'Guatemala'), ('America/Guayaquil', 'Guayaquil'), ('America/Guyana', 'Guyana'), ('America/Halifax', 'Halifax'), ('America/Havana', 'Havana'), ('America/Hermosillo', 'Hermosillo'), ('America/Indiana/Indianapolis', 'Indiana/Indianapolis'), ('America/Indiana/Knox', 'Indiana/Knox'), ('America/Indiana/Marengo', 'Indiana/Marengo'), ('America/Indiana/Petersburg', 'Indiana/Petersburg'), ('America/Indiana/Tell_City', 'Indiana/Tell_City'), ('America/Indiana/Vevay', 'Indiana/Vevay'), ('America/Indiana/Vincennes', 'Indiana/Vincennes'), ('America/Indiana/Winamac', 'Indiana/Winamac'), ('America/Indianapolis', 'Indianapolis'), ('America/Inuvik', 'Inuvik'), ('America/Iqaluit', 'Iqaluit'), ('America/Jamaica', 'Jamaica'), ('America/Jujuy', 'Jujuy'), ('America/Juneau', 'Juneau'), ('America/Kentucky/Louisville', 'Kentucky/Louisville'), ('America/Kentucky/Monticello', 'Kentucky/Monticello'), ('America/Knox_IN', 'Knox_IN'), ('America/Kralendijk', 'Kralendijk'), ('America/La_Paz', 'La_Paz'), ('America/Lima', 'Lima'), ('America/Los_Angeles', 'Los_Angeles'), ('America/Louisville', 'Louisville'), ('America/Lower_Princes', 'Lower_Princes'), ('America/Maceio', 'Maceio'), ('America/Managua', 'Managua'), ('America/Manaus', 'Manaus'), ('America/Marigot', 'Marigot'), ('America/Martinique', 'Martinique'), ('America/Matamoros', 'Matamoros'), ('America/Mazatlan', 'Mazatlan'), ('America/Mendoza', 'Mendoza'), ('America/Menominee', 'Menominee'), ('America/Merida', 'Merida'), ('America/Metlakatla', 'Metlakatla'), ('America/Mexico_City', 'Mexico_City'), ('America/Miquelon', 'Miquelon'), ('America/Moncton', 'Moncton'), ('America/Monterrey', 'Monterrey'), ('America/Montevideo', 'Montevideo'), ('America/Montreal', 'Montreal'), ('America/Montserrat', 'Montserrat'), ('America/Nassau', 'Nassau'), ('America/New_York', 'New_York'), ('America/Nipigon', 'Nipigon'), ('America/Nome', 'Nome'), ('America/Noronha', 'Noronha'), ('America/North_Dakota/Beulah', 'North_Dakota/Beulah'), ('America/North_Dakota/Center', 'North_Dakota/Center'), ('America/North_Dakota/New_Salem', 'North_Dakota/New_Salem'), ('America/Ojinaga', 'Ojinaga'), ('America/Panama', 'Panama'), ('America/Pangnirtung', 'Pangnirtung'), ('America/Paramaribo', 'Paramaribo'), ('America/Phoenix', 'Phoenix'), ('America/Port-au-Prince', 'Port-au-Prince'), ('America/Port_of_Spain', 'Port_of_Spain'), ('America/Porto_Acre', 'Porto_Acre'), ('America/Porto_Velho', 'Porto_Velho'), ('America/Puerto_Rico', 'Puerto_Rico'), ('America/Punta_Arenas', 'Punta_Arenas'), ('America/Rainy_River', 'Rainy_River'), ('America/Rankin_Inlet', 'Rankin_Inlet'), ('America/Recife', 'Recife'), ('America/Regina', 'Regina'), ('America/Resolute', 'Resolute'), ('America/Rio_Branco', 'Rio_Branco'), ('America/Rosario', 'Rosario'), ('America/Santa_Isabel', 'Santa_Isabel'), ('America/Santarem', 'Santarem'), ('America/Santiago', 'Santiago'), ('America/Santo_Domingo', 'Santo_Domingo'), ('America/Sao_Paulo', 'Sao_Paulo'), ('America/Scoresbysund', 'Scoresbysund'), ('America/Shiprock', 'Shiprock'), ('America/Sitka', 'Sitka'), ('America/St_Barthelemy', 'St_Barthelemy'), ('America/St_Johns', 'St_Johns'), ('America/St_Kitts', 'St_Kitts'), ('America/St_Lucia', 'St_Lucia'), ('America/St_Thomas', 'St_Thomas'), ('America/St_Vincent', 'St_Vincent'), ('America/Swift_Current', 'Swift_Current'), ('America/Tegucigalpa', 'Tegucigalpa'), ('America/Thule', 'Thule'), ('America/Thunder_Bay', 'Thunder_Bay'), ('America/Tijuana', 'Tijuana'), ('America/Toronto', 'Toronto'), ('America/Tortola', 'Tortola'), ('America/Vancouver', 'Vancouver'), ('America/Virgin', 'Virgin'), ('America/Whitehorse', 'Whitehorse'), ('America/Winnipeg', 'Winnipeg'), ('America/Yakutat', 'Yakutat'), ('America/Yellowknife', 'Yellowknife')]), ('Antarctica', [('Antarctica/Casey', 'Casey'), ('Antarctica/Davis', 'Davis'), ('Antarctica/DumontDUrville', 'DumontDUrville'), ('Antarctica/Macquarie', 'Macquarie'), ('Antarctica/Mawson', 'Mawson'), ('Antarctica/McMurdo', 'McMurdo'), ('Antarctica/Palmer', 'Palmer'), ('Antarctica/Rothera', 'Rothera'), ('Antarctica/South_Pole', 'South_Pole'), ('Antarctica/Syowa', 'Syowa'), ('Antarctica/Troll', 'Troll'), ('Antarctica/Vostok', 'Vostok')]), ('Arctic', [('Arctic/Longyearbyen', 'Longyearbyen')]), ('Asia', [('Asia/Aden', 'Aden'), ('Asia/Almaty', 'Almaty'), ('Asia/Amman', 'Amman'), ('Asia/Anadyr', 'Anadyr'), ('Asia/Aqtau', 'Aqtau'), ('Asia/Aqtobe', 'Aqtobe'), ('Asia/Ashgabat', 'Ashgabat'), ('Asia/Ashkhabad', 'Ashkhabad'), ('Asia/Atyrau', 'Atyrau'), ('Asia/Baghdad', 'Baghdad'), ('Asia/Bahrain', 'Bahrain'), ('Asia/Baku', 'Baku'), ('Asia/Bangkok', 'Bangkok'), ('Asia/Barnaul', 'Barnaul'), ('Asia/Beirut', 'Beirut'), ('Asia/Bishkek', 'Bishkek'), ('Asia/Brunei', 'Brunei'), ('Asia/Calcutta', 'Calcutta'), ('Asia/Chita', 'Chita'), ('Asia/Choibalsan', 'Choibalsan'), ('Asia/Chongqing', 'Chongqing'), ('Asia/Chungking', 'Chungking'), ('Asia/Colombo', 'Colombo'), ('Asia/Dacca', 'Dacca'), ('Asia/Damascus', 'Damascus'), ('Asia/Dhaka', 'Dhaka'), ('Asia/Dili', 'Dili'), ('Asia/Dubai', 'Dubai'), ('Asia/Dushanbe', 'Dushanbe'), ('Asia/Famagusta', 'Famagusta'), ('Asia/Gaza', 'Gaza'), ('Asia/Harbin', 'Harbin'), ('Asia/Hebron', 'Hebron'), ('Asia/Ho_Chi_Minh', 'Ho_Chi_Minh'), ('Asia/Hong_Kong', 'Hong_Kong'), ('Asia/Hovd', 'Hovd'), ('Asia/Irkutsk', 'Irkutsk'), ('Asia/Istanbul', 'Istanbul'), ('Asia/Jakarta', 'Jakarta'), ('Asia/Jayapura', 'Jayapura'), ('Asia/Jerusalem', 'Jerusalem'), ('Asia/Kabul', 'Kabul'), ('Asia/Kamchatka', 'Kamchatka'), ('Asia/Karachi', 'Karachi'), ('Asia/Kashgar', 'Kashgar'), ('Asia/Kathmandu', 'Kathmandu'), ('Asia/Katmandu', 'Katmandu'), ('Asia/Khandyga', 'Khandyga'), ('Asia/Kolkata', 'Kolkata'), ('Asia/Krasnoyarsk', 'Krasnoyarsk'), ('Asia/Kuala_Lumpur', 'Kuala_Lumpur'), ('Asia/Kuching', 'Kuching'), ('Asia/Kuwait', 'Kuwait'), ('Asia/Macao', 'Macao'), ('Asia/Macau', 'Macau'), ('Asia/Magadan', 'Magadan'), ('Asia/Makassar', 'Makassar'), ('Asia/Manila', 'Manila'), ('Asia/Muscat', 'Muscat'), ('Asia/Nicosia', 'Nicosia'), ('Asia/Novokuznetsk', 'Novokuznetsk'), ('Asia/Novosibirsk', 'Novosibirsk'), ('Asia/Omsk', 'Omsk'), ('Asia/Oral', 'Oral'), ('Asia/Phnom_Penh', 'Phnom_Penh'), ('Asia/Pontianak', 'Pontianak'), ('Asia/Pyongyang', 'Pyongyang'), ('Asia/Qatar', 'Qatar'), ('Asia/Qostanay', 'Qostanay'), ('Asia/Qyzylorda', 'Qyzylorda'), ('Asia/Rangoon', 'Rangoon'), ('Asia/Riyadh', 'Riyadh'), ('Asia/Saigon', 'Saigon'), ('Asia/Sakhalin', 'Sakhalin'), ('Asia/Samarkand', 'Samarkand'), ('Asia/Seoul', 'Seoul'), ('Asia/Shanghai', 'Shanghai'), ('Asia/Singapore', 'Singapore'), ('Asia/Srednekolymsk', 'Srednekolymsk'), ('Asia/Taipei', 'Taipei'), ('Asia/Tashkent', 'Tashkent'), ('Asia/Tbilisi', 'Tbilisi'), ('Asia/Tehran', 'Tehran'), ('Asia/Tel_Aviv', 'Tel_Aviv'), ('Asia/Thimbu', 'Thimbu'), ('Asia/Thimphu', 'Thimphu'), ('Asia/Tokyo', 'Tokyo'), ('Asia/Tomsk', 'Tomsk'), ('Asia/Ujung_Pandang', 'Ujung_Pandang'), ('Asia/Ulaanbaatar', 'Ulaanbaatar'), ('Asia/Ulan_Bator', 'Ulan_Bator'), ('Asia/Urumqi', 'Urumqi'), ('Asia/Ust-Nera', 'Ust-Nera'), ('Asia/Vientiane', 'Vientiane'), ('Asia/Vladivostok', 'Vladivostok'), ('Asia/Yakutsk', 'Yakutsk'), ('Asia/Yangon', 'Yangon'), ('Asia/Yekaterinburg', 'Yekaterinburg'), ('Asia/Yerevan', 'Yerevan')]), ('Atlantic', [('Atlantic/Azores', 'Azores'), ('Atlantic/Bermuda', 'Bermuda'), ('Atlantic/Canary', 'Canary'), ('Atlantic/Cape_Verde', 'Cape_Verde'), ('Atlantic/Faeroe', 'Faeroe'), ('Atlantic/Faroe', 'Faroe'), ('Atlantic/Jan_Mayen', 'Jan_Mayen'), ('Atlantic/Madeira', 'Madeira'), ('Atlantic/Reykjavik', 'Reykjavik'), ('Atlantic/South_Georgia', 'South_Georgia'), ('Atlantic/St_Helena', 'St_Helena'), ('Atlantic/Stanley', 'Stanley')]), ('Australia', [('Australia/ACT', 'ACT'), ('Australia/Adelaide', 'Adelaide'), ('Australia/Brisbane', 'Brisbane'), ('Australia/Broken_Hill', 'Broken_Hill'), ('Australia/Canberra', 'Canberra'), ('Australia/Currie', 'Currie'), ('Australia/Darwin', 'Darwin'), ('Australia/Eucla', 'Eucla'), ('Australia/Hobart', 'Hobart'), ('Australia/LHI', 'LHI'), ('Australia/Lindeman', 'Lindeman'), ('Australia/Lord_Howe', 'Lord_Howe'), ('Australia/Melbourne', 'Melbourne'), ('Australia/NSW', 'NSW'), ('Australia/North', 'North'), ('Australia/Perth', 'Perth'), ('Australia/Queensland', 'Queensland'), ('Australia/South', 'South'), ('Australia/Sydney', 'Sydney'), ('Australia/Tasmania', 'Tasmania'), ('Australia/Victoria', 'Victoria'), ('Australia/West', 'West'), ('Australia/Yancowinna', 'Yancowinna')]), ('Brazil', [('Brazil/Acre', 'Acre'), ('Brazil/DeNoronha', 'DeNoronha'), ('Brazil/East', 'East'), ('Brazil/West', 'West')]), ('Canada', [('Canada/Atlantic', 'Atlantic'), ('Canada/Central', 'Central'), ('Canada/Eastern', 'Eastern'), ('Canada/Mountain', 'Mountain'), ('Canada/Newfoundland', 'Newfoundland'), ('Canada/Pacific', 'Pacific'), ('Canada/Saskatchewan', 'Saskatchewan'), ('Canada/Yukon', 'Yukon')]), ('Chile', [('Chile/Continental', 'Continental'), ('Chile/EasterIsland', 'EasterIsland')]), ('Etc', [('Etc/Greenwich', 'Greenwich'), ('Etc/UCT', 'UCT'), ('Etc/UTC', 'UTC'), ('Etc/Universal', 'Universal'), ('Etc/Zulu', 'Zulu')]), ('Europe', [('Europe/Amsterdam', 'Amsterdam'), ('Europe/Andorra', 'Andorra'), ('Europe/Astrakhan', 'Astrakhan'), ('Europe/Athens', 'Athens'), ('Europe/Belfast', 'Belfast'), ('Europe/Belgrade', 'Belgrade'), ('Europe/Berlin', 'Berlin'), ('Europe/Bratislava', 'Bratislava'), ('Europe/Brussels', 'Brussels'), ('Europe/Bucharest', 'Bucharest'), ('Europe/Budapest', 'Budapest'), ('Europe/Busingen', 'Busingen'), ('Europe/Chisinau', 'Chisinau'), ('Europe/Copenhagen', 'Copenhagen'), ('Europe/Dublin', 'Dublin'), ('Europe/Gibraltar', 'Gibraltar'), ('Europe/Guernsey', 'Guernsey'), ('Europe/Helsinki', 'Helsinki'), ('Europe/Isle_of_Man', 'Isle_of_Man'), ('Europe/Istanbul', 'Istanbul'), ('Europe/Jersey', 'Jersey'), ('Europe/Kaliningrad', 'Kaliningrad'), ('Europe/Kiev', 'Kiev'), ('Europe/Kirov', 'Kirov'), ('Europe/Lisbon', 'Lisbon'), ('Europe/Ljubljana', 'Ljubljana'), ('Europe/London', 'London'), ('Europe/Luxembourg', 'Luxembourg'), ('Europe/Madrid', 'Madrid'), ('Europe/Malta', 'Malta'), ('Europe/Mariehamn', 'Mariehamn'), ('Europe/Minsk', 'Minsk'), ('Europe/Monaco', 'Monaco'), ('Europe/Moscow', 'Moscow'), ('Europe/Nicosia', 'Nicosia'), ('Europe/Oslo', 'Oslo'), ('Europe/Paris', 'Paris'), ('Europe/Podgorica', 'Podgorica'), ('Europe/Prague', 'Prague'), ('Europe/Riga', 'Riga'), ('Europe/Rome', 'Rome'), ('Europe/Samara', 'Samara'), ('Europe/San_Marino', 'San_Marino'), ('Europe/Sarajevo', 'Sarajevo'), ('Europe/Saratov', 'Saratov'), ('Europe/Simferopol', 'Simferopol'), ('Europe/Skopje', 'Skopje'), ('Europe/Sofia', 'Sofia'), ('Europe/Stockholm', 'Stockholm'), ('Europe/Tallinn', 'Tallinn'), ('Europe/Tirane', 'Tirane'), ('Europe/Tiraspol', 'Tiraspol'), ('Europe/Ulyanovsk', 'Ulyanovsk'), ('Europe/Uzhgorod', 'Uzhgorod'), ('Europe/Vaduz', 'Vaduz'), ('Europe/Vatican', 'Vatican'), ('Europe/Vienna', 'Vienna'), ('Europe/Vilnius', 'Vilnius'), ('Europe/Volgograd', 'Volgograd'), ('Europe/Warsaw', 'Warsaw'), ('Europe/Zagreb', 'Zagreb'), ('Europe/Zaporozhye', 'Zaporozhye'), ('Europe/Zurich', 'Zurich')]), ('Indian', [('Indian/Antananarivo', 'Antananarivo'), ('Indian/Chagos', 'Chagos'), ('Indian/Christmas', 'Christmas'), ('Indian/Cocos', 'Cocos'), ('Indian/Comoro', 'Comoro'), ('Indian/Kerguelen', 'Kerguelen'), ('Indian/Mahe', 'Mahe'), ('Indian/Maldives', 'Maldives'), ('Indian/Mauritius', 'Mauritius'), ('Indian/Mayotte', 'Mayotte'), ('Indian/Reunion', 'Reunion')]), ('Mexico', [('Mexico/BajaNorte', 'BajaNorte'), ('Mexico/BajaSur', 'BajaSur'), ('Mexico/General', 'General')]), ('Other', [('CET', 'CET'), ('CST6CDT', 'CST6CDT'), ('Cuba', 'Cuba'), ('EET', 'EET'), ('EST', 'EST'), ('EST5EDT', 'EST5EDT'), ('Egypt', 'Egypt'), ('Eire', 'Eire'), ('GB', 'GB'), ('GB-Eire', 'GB-Eire'), ('Greenwich', 'Greenwich'), ('HST', 'HST'), ('Hongkong', 'Hongkong'), ('Iceland', 'Iceland'), ('Iran', 'Iran'), ('Israel', 'Israel'), ('Jamaica', 'Jamaica'), ('Japan', 'Japan'), ('Kwajalein', 'Kwajalein'), ('Libya', 'Libya'), ('MET', 'MET'), ('MST', 'MST'), ('MST7MDT', 'MST7MDT'), ('NZ', 'NZ'), ('NZ-CHAT', 'NZ-CHAT'), ('Navajo', 'Navajo'), ('PRC', 'PRC'), ('PST8PDT', 'PST8PDT'), ('Poland', 'Poland'), ('Portugal', 'Portugal'), ('ROC', 'ROC'), ('ROK', 'ROK'), ('Singapore', 'Singapore'), ('Turkey', 'Turkey'), ('UCT', 'UCT'), ('UTC', 'UTC'), ('Universal', 'Universal'), ('W-SU', 'W-SU'), ('WET', 'WET'), ('Zulu', 'Zulu')]), ('Pacific', [('Pacific/Apia', 'Apia'), ('Pacific/Auckland', 'Auckland'), ('Pacific/Bougainville', 'Bougainville'), ('Pacific/Chatham', 'Chatham'), ('Pacific/Chuuk', 'Chuuk'), ('Pacific/Easter', 'Easter'), ('Pacific/Efate', 'Efate'), ('Pacific/Enderbury', 'Enderbury'), ('Pacific/Fakaofo', 'Fakaofo'), ('Pacific/Fiji', 'Fiji'), ('Pacific/Funafuti', 'Funafuti'), ('Pacific/Galapagos', 'Galapagos'), ('Pacific/Gambier', 'Gambier'), ('Pacific/Guadalcanal', 'Guadalcanal'), ('Pacific/Guam', 'Guam'), ('Pacific/Honolulu', 'Honolulu'), ('Pacific/Johnston', 'Johnston'), ('Pacific/Kiritimati', 'Kiritimati'), ('Pacific/Kosrae', 'Kosrae'), ('Pacific/Kwajalein', 'Kwajalein'), ('Pacific/Majuro', 'Majuro'), ('Pacific/Marquesas', 'Marquesas'), ('Pacific/Midway', 'Midway'), ('Pacific/Nauru', 'Nauru'), ('Pacific/Niue', 'Niue'), ('Pacific/Norfolk', 'Norfolk'), ('Pacific/Noumea', 'Noumea'), ('Pacific/Pago_Pago', 'Pago_Pago'), ('Pacific/Palau', 'Palau'), ('Pacific/Pitcairn', 'Pitcairn'), ('Pacific/Pohnpei', 'Pohnpei'), ('Pacific/Ponape', 'Ponape'), ('Pacific/Port_Moresby', 'Port_Moresby'), ('Pacific/Rarotonga', 'Rarotonga'), ('Pacific/Saipan', 'Saipan'), ('Pacific/Samoa', 'Samoa'), ('Pacific/Tahiti', 'Tahiti'), ('Pacific/Tarawa', 'Tarawa'), ('Pacific/Tongatapu', 'Tongatapu'), ('Pacific/Truk', 'Truk'), ('Pacific/Wake', 'Wake'), ('Pacific/Wallis', 'Wallis'), ('Pacific/Yap', 'Yap')]), ('US', [('US/Alaska', 'Alaska'), ('US/Aleutian', 'Aleutian'), ('US/Arizona', 'Arizona'), ('US/Central', 'Central'), ('US/East-Indiana', 'East-Indiana'), ('US/Eastern', 'Eastern'), ('US/Hawaii', 'Hawaii'), ('US/Indiana-Starke', 'Indiana-Starke'), ('US/Michigan', 'Michigan'), ('US/Mountain', 'Mountain'), ('US/Pacific', 'Pacific'), ('US/Samoa', 'Samoa')])], default='America/Mexico_City', max_length=50, verbose_name='location'), ), ] diff --git a/judge/migrations/0099_custom_checker.py b/judge/migrations/0099_custom_checker.py index 24ab46b..b2552b7 100644 --- a/judge/migrations/0099_custom_checker.py +++ b/judge/migrations/0099_custom_checker.py @@ -8,59 +8,23 @@ import judge.utils.problem_data class Migration(migrations.Migration): dependencies = [ - ("judge", "0098_auto_20200123_2136"), + ('judge', '0098_auto_20200123_2136'), ] operations = [ migrations.AddField( - model_name="problemdata", - name="custom_checker", - field=models.FileField( - blank=True, - null=True, - storage=judge.utils.problem_data.ProblemDataStorage(), - upload_to=judge.models.problem_data.problem_directory_file, - verbose_name="custom checker file", - ), + model_name='problemdata', + name='custom_checker', + field=models.FileField(blank=True, null=True, storage=judge.utils.problem_data.ProblemDataStorage(), upload_to=judge.models.problem_data.problem_directory_file, verbose_name='custom checker file'), ), migrations.AlterField( - model_name="problemdata", - name="checker", - field=models.CharField( - blank=True, - choices=[ - ("standard", "Standard"), - ("floats", "Floats"), - ("floatsabs", "Floats (absolute)"), - ("floatsrel", "Floats (relative)"), - ("rstripped", "Non-trailing spaces"), - ("sorted", "Unordered"), - ("identical", "Byte identical"), - ("linecount", "Line-by-line"), - ("custom", "Custom checker"), - ], - max_length=10, - verbose_name="checker", - ), + model_name='problemdata', + name='checker', + field=models.CharField(blank=True, choices=[('standard', 'Standard'), ('floats', 'Floats'), ('floatsabs', 'Floats (absolute)'), ('floatsrel', 'Floats (relative)'), ('rstripped', 'Non-trailing spaces'), ('sorted', 'Unordered'), ('identical', 'Byte identical'), ('linecount', 'Line-by-line'), ('custom', 'Custom checker')], max_length=10, verbose_name='checker'), ), migrations.AlterField( - model_name="problemtestcase", - name="checker", - field=models.CharField( - blank=True, - choices=[ - ("standard", "Standard"), - ("floats", "Floats"), - ("floatsabs", "Floats (absolute)"), - ("floatsrel", "Floats (relative)"), - ("rstripped", "Non-trailing spaces"), - ("sorted", "Unordered"), - ("identical", "Byte identical"), - ("linecount", "Line-by-line"), - ("custom", "Custom checker"), - ], - max_length=10, - verbose_name="checker", - ), + model_name='problemtestcase', + name='checker', + field=models.CharField(blank=True, choices=[('standard', 'Standard'), ('floats', 'Floats'), ('floatsabs', 'Floats (absolute)'), ('floatsrel', 'Floats (relative)'), ('rstripped', 'Non-trailing spaces'), ('sorted', 'Unordered'), ('identical', 'Byte identical'), ('linecount', 'Line-by-line'), ('custom', 'Custom checker')], max_length=10, verbose_name='checker'), ), ] diff --git a/judge/migrations/0100_auto_20200127_0059.py b/judge/migrations/0100_auto_20200127_0059.py index 5d1cd91..e070f7a 100644 --- a/judge/migrations/0100_auto_20200127_0059.py +++ b/judge/migrations/0100_auto_20200127_0059.py @@ -9,24 +9,13 @@ import judge.utils.problem_data class Migration(migrations.Migration): dependencies = [ - ("judge", "0099_custom_checker"), + ('judge', '0099_custom_checker'), ] operations = [ migrations.AlterField( - model_name="problemdata", - name="custom_checker", - field=models.FileField( - blank=True, - null=True, - storage=judge.utils.problem_data.ProblemDataStorage(), - upload_to=judge.models.problem_data.problem_directory_file, - validators=[ - django.core.validators.FileExtensionValidator( - allowed_extensions=["py"] - ) - ], - verbose_name="custom checker file", - ), + model_name='problemdata', + name='custom_checker', + field=models.FileField(blank=True, null=True, storage=judge.utils.problem_data.ProblemDataStorage(), upload_to=judge.models.problem_data.problem_directory_file, validators=[django.core.validators.FileExtensionValidator(allowed_extensions=['py'])], verbose_name='custom checker file'), ), ] diff --git a/judge/migrations/0101_custom_validator.py b/judge/migrations/0101_custom_validator.py index 8575ce1..842006c 100644 --- a/judge/migrations/0101_custom_validator.py +++ b/judge/migrations/0101_custom_validator.py @@ -9,727 +9,28 @@ import judge.utils.problem_data class Migration(migrations.Migration): dependencies = [ - ("judge", "0100_auto_20200127_0059"), + ('judge', '0100_auto_20200127_0059'), ] operations = [ migrations.AddField( - model_name="problemdata", - name="custom_valid", - field=models.FileField( - blank=True, - null=True, - storage=judge.utils.problem_data.ProblemDataStorage(), - upload_to=judge.models.problem_data.problem_directory_file, - validators=[ - django.core.validators.FileExtensionValidator( - allowed_extensions=["cpp"] - ) - ], - verbose_name="custom validator file", - ), + model_name='problemdata', + name='custom_valid', + field=models.FileField(blank=True, null=True, storage=judge.utils.problem_data.ProblemDataStorage(), upload_to=judge.models.problem_data.problem_directory_file, validators=[django.core.validators.FileExtensionValidator(allowed_extensions=['cpp'])], verbose_name='custom validator file'), ), migrations.AlterField( - model_name="problemdata", - name="checker", - field=models.CharField( - blank=True, - choices=[ - ("standard", "Standard"), - ("floats", "Floats"), - ("floatsabs", "Floats (absolute)"), - ("floatsrel", "Floats (relative)"), - ("rstripped", "Non-trailing spaces"), - ("sorted", "Unordered"), - ("identical", "Byte identical"), - ("linecount", "Line-by-line"), - ("custom", "Custom checker"), - ("custom_valid", "Custom Validator"), - ], - max_length=10, - verbose_name="checker", - ), + model_name='problemdata', + name='checker', + field=models.CharField(blank=True, choices=[('standard', 'Standard'), ('floats', 'Floats'), ('floatsabs', 'Floats (absolute)'), ('floatsrel', 'Floats (relative)'), ('rstripped', 'Non-trailing spaces'), ('sorted', 'Unordered'), ('identical', 'Byte identical'), ('linecount', 'Line-by-line'), ('custom', 'Custom checker'), ('custom_valid', 'Custom Validator')], max_length=10, verbose_name='checker'), ), migrations.AlterField( - model_name="problemtestcase", - name="checker", - field=models.CharField( - blank=True, - choices=[ - ("standard", "Standard"), - ("floats", "Floats"), - ("floatsabs", "Floats (absolute)"), - ("floatsrel", "Floats (relative)"), - ("rstripped", "Non-trailing spaces"), - ("sorted", "Unordered"), - ("identical", "Byte identical"), - ("linecount", "Line-by-line"), - ("custom", "Custom checker"), - ("custom_valid", "Custom Validator"), - ], - max_length=10, - verbose_name="checker", - ), + model_name='problemtestcase', + name='checker', + field=models.CharField(blank=True, choices=[('standard', 'Standard'), ('floats', 'Floats'), ('floatsabs', 'Floats (absolute)'), ('floatsrel', 'Floats (relative)'), ('rstripped', 'Non-trailing spaces'), ('sorted', 'Unordered'), ('identical', 'Byte identical'), ('linecount', 'Line-by-line'), ('custom', 'Custom checker'), ('custom_valid', 'Custom Validator')], max_length=10, verbose_name='checker'), ), migrations.AlterField( - model_name="profile", - name="timezone", - field=models.CharField( - choices=[ - ( - "Africa", - [ - ("Africa/Abidjan", "Abidjan"), - ("Africa/Accra", "Accra"), - ("Africa/Addis_Ababa", "Addis_Ababa"), - ("Africa/Algiers", "Algiers"), - ("Africa/Asmara", "Asmara"), - ("Africa/Asmera", "Asmera"), - ("Africa/Bamako", "Bamako"), - ("Africa/Bangui", "Bangui"), - ("Africa/Banjul", "Banjul"), - ("Africa/Bissau", "Bissau"), - ("Africa/Blantyre", "Blantyre"), - ("Africa/Brazzaville", "Brazzaville"), - ("Africa/Bujumbura", "Bujumbura"), - ("Africa/Cairo", "Cairo"), - ("Africa/Casablanca", "Casablanca"), - ("Africa/Ceuta", "Ceuta"), - ("Africa/Conakry", "Conakry"), - ("Africa/Dakar", "Dakar"), - ("Africa/Dar_es_Salaam", "Dar_es_Salaam"), - ("Africa/Djibouti", "Djibouti"), - ("Africa/Douala", "Douala"), - ("Africa/El_Aaiun", "El_Aaiun"), - ("Africa/Freetown", "Freetown"), - ("Africa/Gaborone", "Gaborone"), - ("Africa/Harare", "Harare"), - ("Africa/Johannesburg", "Johannesburg"), - ("Africa/Juba", "Juba"), - ("Africa/Kampala", "Kampala"), - ("Africa/Khartoum", "Khartoum"), - ("Africa/Kigali", "Kigali"), - ("Africa/Kinshasa", "Kinshasa"), - ("Africa/Lagos", "Lagos"), - ("Africa/Libreville", "Libreville"), - ("Africa/Lome", "Lome"), - ("Africa/Luanda", "Luanda"), - ("Africa/Lubumbashi", "Lubumbashi"), - ("Africa/Lusaka", "Lusaka"), - ("Africa/Malabo", "Malabo"), - ("Africa/Maputo", "Maputo"), - ("Africa/Maseru", "Maseru"), - ("Africa/Mbabane", "Mbabane"), - ("Africa/Mogadishu", "Mogadishu"), - ("Africa/Monrovia", "Monrovia"), - ("Africa/Nairobi", "Nairobi"), - ("Africa/Ndjamena", "Ndjamena"), - ("Africa/Niamey", "Niamey"), - ("Africa/Nouakchott", "Nouakchott"), - ("Africa/Ouagadougou", "Ouagadougou"), - ("Africa/Porto-Novo", "Porto-Novo"), - ("Africa/Sao_Tome", "Sao_Tome"), - ("Africa/Timbuktu", "Timbuktu"), - ("Africa/Tripoli", "Tripoli"), - ("Africa/Tunis", "Tunis"), - ("Africa/Windhoek", "Windhoek"), - ], - ), - ( - "America", - [ - ("America/Adak", "Adak"), - ("America/Anchorage", "Anchorage"), - ("America/Anguilla", "Anguilla"), - ("America/Antigua", "Antigua"), - ("America/Araguaina", "Araguaina"), - ( - "America/Argentina/Buenos_Aires", - "Argentina/Buenos_Aires", - ), - ("America/Argentina/Catamarca", "Argentina/Catamarca"), - ( - "America/Argentina/ComodRivadavia", - "Argentina/ComodRivadavia", - ), - ("America/Argentina/Cordoba", "Argentina/Cordoba"), - ("America/Argentina/Jujuy", "Argentina/Jujuy"), - ("America/Argentina/La_Rioja", "Argentina/La_Rioja"), - ("America/Argentina/Mendoza", "Argentina/Mendoza"), - ( - "America/Argentina/Rio_Gallegos", - "Argentina/Rio_Gallegos", - ), - ("America/Argentina/Salta", "Argentina/Salta"), - ("America/Argentina/San_Juan", "Argentina/San_Juan"), - ("America/Argentina/San_Luis", "Argentina/San_Luis"), - ("America/Argentina/Tucuman", "Argentina/Tucuman"), - ("America/Argentina/Ushuaia", "Argentina/Ushuaia"), - ("America/Aruba", "Aruba"), - ("America/Asuncion", "Asuncion"), - ("America/Atikokan", "Atikokan"), - ("America/Atka", "Atka"), - ("America/Bahia", "Bahia"), - ("America/Bahia_Banderas", "Bahia_Banderas"), - ("America/Barbados", "Barbados"), - ("America/Belem", "Belem"), - ("America/Belize", "Belize"), - ("America/Blanc-Sablon", "Blanc-Sablon"), - ("America/Boa_Vista", "Boa_Vista"), - ("America/Bogota", "Bogota"), - ("America/Boise", "Boise"), - ("America/Buenos_Aires", "Buenos_Aires"), - ("America/Cambridge_Bay", "Cambridge_Bay"), - ("America/Campo_Grande", "Campo_Grande"), - ("America/Cancun", "Cancun"), - ("America/Caracas", "Caracas"), - ("America/Catamarca", "Catamarca"), - ("America/Cayenne", "Cayenne"), - ("America/Cayman", "Cayman"), - ("America/Chicago", "Chicago"), - ("America/Chihuahua", "Chihuahua"), - ("America/Coral_Harbour", "Coral_Harbour"), - ("America/Cordoba", "Cordoba"), - ("America/Costa_Rica", "Costa_Rica"), - ("America/Creston", "Creston"), - ("America/Cuiaba", "Cuiaba"), - ("America/Curacao", "Curacao"), - ("America/Danmarkshavn", "Danmarkshavn"), - ("America/Dawson", "Dawson"), - ("America/Dawson_Creek", "Dawson_Creek"), - ("America/Denver", "Denver"), - ("America/Detroit", "Detroit"), - ("America/Dominica", "Dominica"), - ("America/Edmonton", "Edmonton"), - ("America/Eirunepe", "Eirunepe"), - ("America/El_Salvador", "El_Salvador"), - ("America/Ensenada", "Ensenada"), - ("America/Fort_Nelson", "Fort_Nelson"), - ("America/Fort_Wayne", "Fort_Wayne"), - ("America/Fortaleza", "Fortaleza"), - ("America/Glace_Bay", "Glace_Bay"), - ("America/Godthab", "Godthab"), - ("America/Goose_Bay", "Goose_Bay"), - ("America/Grand_Turk", "Grand_Turk"), - ("America/Grenada", "Grenada"), - ("America/Guadeloupe", "Guadeloupe"), - ("America/Guatemala", "Guatemala"), - ("America/Guayaquil", "Guayaquil"), - ("America/Guyana", "Guyana"), - ("America/Halifax", "Halifax"), - ("America/Havana", "Havana"), - ("America/Hermosillo", "Hermosillo"), - ("America/Indiana/Indianapolis", "Indiana/Indianapolis"), - ("America/Indiana/Knox", "Indiana/Knox"), - ("America/Indiana/Marengo", "Indiana/Marengo"), - ("America/Indiana/Petersburg", "Indiana/Petersburg"), - ("America/Indiana/Tell_City", "Indiana/Tell_City"), - ("America/Indiana/Vevay", "Indiana/Vevay"), - ("America/Indiana/Vincennes", "Indiana/Vincennes"), - ("America/Indiana/Winamac", "Indiana/Winamac"), - ("America/Indianapolis", "Indianapolis"), - ("America/Inuvik", "Inuvik"), - ("America/Iqaluit", "Iqaluit"), - ("America/Jamaica", "Jamaica"), - ("America/Jujuy", "Jujuy"), - ("America/Juneau", "Juneau"), - ("America/Kentucky/Louisville", "Kentucky/Louisville"), - ("America/Kentucky/Monticello", "Kentucky/Monticello"), - ("America/Knox_IN", "Knox_IN"), - ("America/Kralendijk", "Kralendijk"), - ("America/La_Paz", "La_Paz"), - ("America/Lima", "Lima"), - ("America/Los_Angeles", "Los_Angeles"), - ("America/Louisville", "Louisville"), - ("America/Lower_Princes", "Lower_Princes"), - ("America/Maceio", "Maceio"), - ("America/Managua", "Managua"), - ("America/Manaus", "Manaus"), - ("America/Marigot", "Marigot"), - ("America/Martinique", "Martinique"), - ("America/Matamoros", "Matamoros"), - ("America/Mazatlan", "Mazatlan"), - ("America/Mendoza", "Mendoza"), - ("America/Menominee", "Menominee"), - ("America/Merida", "Merida"), - ("America/Metlakatla", "Metlakatla"), - ("America/Mexico_City", "Mexico_City"), - ("America/Miquelon", "Miquelon"), - ("America/Moncton", "Moncton"), - ("America/Monterrey", "Monterrey"), - ("America/Montevideo", "Montevideo"), - ("America/Montreal", "Montreal"), - ("America/Montserrat", "Montserrat"), - ("America/Nassau", "Nassau"), - ("America/New_York", "New_York"), - ("America/Nipigon", "Nipigon"), - ("America/Nome", "Nome"), - ("America/Noronha", "Noronha"), - ("America/North_Dakota/Beulah", "North_Dakota/Beulah"), - ("America/North_Dakota/Center", "North_Dakota/Center"), - ( - "America/North_Dakota/New_Salem", - "North_Dakota/New_Salem", - ), - ("America/Ojinaga", "Ojinaga"), - ("America/Panama", "Panama"), - ("America/Pangnirtung", "Pangnirtung"), - ("America/Paramaribo", "Paramaribo"), - ("America/Phoenix", "Phoenix"), - ("America/Port-au-Prince", "Port-au-Prince"), - ("America/Port_of_Spain", "Port_of_Spain"), - ("America/Porto_Acre", "Porto_Acre"), - ("America/Porto_Velho", "Porto_Velho"), - ("America/Puerto_Rico", "Puerto_Rico"), - ("America/Punta_Arenas", "Punta_Arenas"), - ("America/Rainy_River", "Rainy_River"), - ("America/Rankin_Inlet", "Rankin_Inlet"), - ("America/Recife", "Recife"), - ("America/Regina", "Regina"), - ("America/Resolute", "Resolute"), - ("America/Rio_Branco", "Rio_Branco"), - ("America/Rosario", "Rosario"), - ("America/Santa_Isabel", "Santa_Isabel"), - ("America/Santarem", "Santarem"), - ("America/Santiago", "Santiago"), - ("America/Santo_Domingo", "Santo_Domingo"), - ("America/Sao_Paulo", "Sao_Paulo"), - ("America/Scoresbysund", "Scoresbysund"), - ("America/Shiprock", "Shiprock"), - ("America/Sitka", "Sitka"), - ("America/St_Barthelemy", "St_Barthelemy"), - ("America/St_Johns", "St_Johns"), - ("America/St_Kitts", "St_Kitts"), - ("America/St_Lucia", "St_Lucia"), - ("America/St_Thomas", "St_Thomas"), - ("America/St_Vincent", "St_Vincent"), - ("America/Swift_Current", "Swift_Current"), - ("America/Tegucigalpa", "Tegucigalpa"), - ("America/Thule", "Thule"), - ("America/Thunder_Bay", "Thunder_Bay"), - ("America/Tijuana", "Tijuana"), - ("America/Toronto", "Toronto"), - ("America/Tortola", "Tortola"), - ("America/Vancouver", "Vancouver"), - ("America/Virgin", "Virgin"), - ("America/Whitehorse", "Whitehorse"), - ("America/Winnipeg", "Winnipeg"), - ("America/Yakutat", "Yakutat"), - ("America/Yellowknife", "Yellowknife"), - ], - ), - ( - "Antarctica", - [ - ("Antarctica/Casey", "Casey"), - ("Antarctica/Davis", "Davis"), - ("Antarctica/DumontDUrville", "DumontDUrville"), - ("Antarctica/Macquarie", "Macquarie"), - ("Antarctica/Mawson", "Mawson"), - ("Antarctica/McMurdo", "McMurdo"), - ("Antarctica/Palmer", "Palmer"), - ("Antarctica/Rothera", "Rothera"), - ("Antarctica/South_Pole", "South_Pole"), - ("Antarctica/Syowa", "Syowa"), - ("Antarctica/Troll", "Troll"), - ("Antarctica/Vostok", "Vostok"), - ], - ), - ("Arctic", [("Arctic/Longyearbyen", "Longyearbyen")]), - ( - "Asia", - [ - ("Asia/Aden", "Aden"), - ("Asia/Almaty", "Almaty"), - ("Asia/Amman", "Amman"), - ("Asia/Anadyr", "Anadyr"), - ("Asia/Aqtau", "Aqtau"), - ("Asia/Aqtobe", "Aqtobe"), - ("Asia/Ashgabat", "Ashgabat"), - ("Asia/Ashkhabad", "Ashkhabad"), - ("Asia/Atyrau", "Atyrau"), - ("Asia/Baghdad", "Baghdad"), - ("Asia/Bahrain", "Bahrain"), - ("Asia/Baku", "Baku"), - ("Asia/Bangkok", "Bangkok"), - ("Asia/Barnaul", "Barnaul"), - ("Asia/Beirut", "Beirut"), - ("Asia/Bishkek", "Bishkek"), - ("Asia/Brunei", "Brunei"), - ("Asia/Calcutta", "Calcutta"), - ("Asia/Chita", "Chita"), - ("Asia/Choibalsan", "Choibalsan"), - ("Asia/Chongqing", "Chongqing"), - ("Asia/Chungking", "Chungking"), - ("Asia/Colombo", "Colombo"), - ("Asia/Dacca", "Dacca"), - ("Asia/Damascus", "Damascus"), - ("Asia/Dhaka", "Dhaka"), - ("Asia/Dili", "Dili"), - ("Asia/Dubai", "Dubai"), - ("Asia/Dushanbe", "Dushanbe"), - ("Asia/Famagusta", "Famagusta"), - ("Asia/Gaza", "Gaza"), - ("Asia/Harbin", "Harbin"), - ("Asia/Hebron", "Hebron"), - ("Asia/Ho_Chi_Minh", "Ho_Chi_Minh"), - ("Asia/Hong_Kong", "Hong_Kong"), - ("Asia/Hovd", "Hovd"), - ("Asia/Irkutsk", "Irkutsk"), - ("Asia/Istanbul", "Istanbul"), - ("Asia/Jakarta", "Jakarta"), - ("Asia/Jayapura", "Jayapura"), - ("Asia/Jerusalem", "Jerusalem"), - ("Asia/Kabul", "Kabul"), - ("Asia/Kamchatka", "Kamchatka"), - ("Asia/Karachi", "Karachi"), - ("Asia/Kashgar", "Kashgar"), - ("Asia/Kathmandu", "Kathmandu"), - ("Asia/Katmandu", "Katmandu"), - ("Asia/Khandyga", "Khandyga"), - ("Asia/Kolkata", "Kolkata"), - ("Asia/Krasnoyarsk", "Krasnoyarsk"), - ("Asia/Kuala_Lumpur", "Kuala_Lumpur"), - ("Asia/Kuching", "Kuching"), - ("Asia/Kuwait", "Kuwait"), - ("Asia/Macao", "Macao"), - ("Asia/Macau", "Macau"), - ("Asia/Magadan", "Magadan"), - ("Asia/Makassar", "Makassar"), - ("Asia/Manila", "Manila"), - ("Asia/Muscat", "Muscat"), - ("Asia/Nicosia", "Nicosia"), - ("Asia/Novokuznetsk", "Novokuznetsk"), - ("Asia/Novosibirsk", "Novosibirsk"), - ("Asia/Omsk", "Omsk"), - ("Asia/Oral", "Oral"), - ("Asia/Phnom_Penh", "Phnom_Penh"), - ("Asia/Pontianak", "Pontianak"), - ("Asia/Pyongyang", "Pyongyang"), - ("Asia/Qatar", "Qatar"), - ("Asia/Qostanay", "Qostanay"), - ("Asia/Qyzylorda", "Qyzylorda"), - ("Asia/Rangoon", "Rangoon"), - ("Asia/Riyadh", "Riyadh"), - ("Asia/Saigon", "Saigon"), - ("Asia/Sakhalin", "Sakhalin"), - ("Asia/Samarkand", "Samarkand"), - ("Asia/Seoul", "Seoul"), - ("Asia/Shanghai", "Shanghai"), - ("Asia/Singapore", "Singapore"), - ("Asia/Srednekolymsk", "Srednekolymsk"), - ("Asia/Taipei", "Taipei"), - ("Asia/Tashkent", "Tashkent"), - ("Asia/Tbilisi", "Tbilisi"), - ("Asia/Tehran", "Tehran"), - ("Asia/Tel_Aviv", "Tel_Aviv"), - ("Asia/Thimbu", "Thimbu"), - ("Asia/Thimphu", "Thimphu"), - ("Asia/Tokyo", "Tokyo"), - ("Asia/Tomsk", "Tomsk"), - ("Asia/Ujung_Pandang", "Ujung_Pandang"), - ("Asia/Ulaanbaatar", "Ulaanbaatar"), - ("Asia/Ulan_Bator", "Ulan_Bator"), - ("Asia/Urumqi", "Urumqi"), - ("Asia/Ust-Nera", "Ust-Nera"), - ("Asia/Vientiane", "Vientiane"), - ("Asia/Vladivostok", "Vladivostok"), - ("Asia/Yakutsk", "Yakutsk"), - ("Asia/Yangon", "Yangon"), - ("Asia/Yekaterinburg", "Yekaterinburg"), - ("Asia/Yerevan", "Yerevan"), - ], - ), - ( - "Atlantic", - [ - ("Atlantic/Azores", "Azores"), - ("Atlantic/Bermuda", "Bermuda"), - ("Atlantic/Canary", "Canary"), - ("Atlantic/Cape_Verde", "Cape_Verde"), - ("Atlantic/Faeroe", "Faeroe"), - ("Atlantic/Faroe", "Faroe"), - ("Atlantic/Jan_Mayen", "Jan_Mayen"), - ("Atlantic/Madeira", "Madeira"), - ("Atlantic/Reykjavik", "Reykjavik"), - ("Atlantic/South_Georgia", "South_Georgia"), - ("Atlantic/St_Helena", "St_Helena"), - ("Atlantic/Stanley", "Stanley"), - ], - ), - ( - "Australia", - [ - ("Australia/ACT", "ACT"), - ("Australia/Adelaide", "Adelaide"), - ("Australia/Brisbane", "Brisbane"), - ("Australia/Broken_Hill", "Broken_Hill"), - ("Australia/Canberra", "Canberra"), - ("Australia/Currie", "Currie"), - ("Australia/Darwin", "Darwin"), - ("Australia/Eucla", "Eucla"), - ("Australia/Hobart", "Hobart"), - ("Australia/LHI", "LHI"), - ("Australia/Lindeman", "Lindeman"), - ("Australia/Lord_Howe", "Lord_Howe"), - ("Australia/Melbourne", "Melbourne"), - ("Australia/NSW", "NSW"), - ("Australia/North", "North"), - ("Australia/Perth", "Perth"), - ("Australia/Queensland", "Queensland"), - ("Australia/South", "South"), - ("Australia/Sydney", "Sydney"), - ("Australia/Tasmania", "Tasmania"), - ("Australia/Victoria", "Victoria"), - ("Australia/West", "West"), - ("Australia/Yancowinna", "Yancowinna"), - ], - ), - ( - "Brazil", - [ - ("Brazil/Acre", "Acre"), - ("Brazil/DeNoronha", "DeNoronha"), - ("Brazil/East", "East"), - ("Brazil/West", "West"), - ], - ), - ( - "Canada", - [ - ("Canada/Atlantic", "Atlantic"), - ("Canada/Central", "Central"), - ("Canada/Eastern", "Eastern"), - ("Canada/Mountain", "Mountain"), - ("Canada/Newfoundland", "Newfoundland"), - ("Canada/Pacific", "Pacific"), - ("Canada/Saskatchewan", "Saskatchewan"), - ("Canada/Yukon", "Yukon"), - ], - ), - ( - "Chile", - [ - ("Chile/Continental", "Continental"), - ("Chile/EasterIsland", "EasterIsland"), - ], - ), - ( - "Etc", - [ - ("Etc/Greenwich", "Greenwich"), - ("Etc/UCT", "UCT"), - ("Etc/UTC", "UTC"), - ("Etc/Universal", "Universal"), - ("Etc/Zulu", "Zulu"), - ], - ), - ( - "Europe", - [ - ("Europe/Amsterdam", "Amsterdam"), - ("Europe/Andorra", "Andorra"), - ("Europe/Astrakhan", "Astrakhan"), - ("Europe/Athens", "Athens"), - ("Europe/Belfast", "Belfast"), - ("Europe/Belgrade", "Belgrade"), - ("Europe/Berlin", "Berlin"), - ("Europe/Bratislava", "Bratislava"), - ("Europe/Brussels", "Brussels"), - ("Europe/Bucharest", "Bucharest"), - ("Europe/Budapest", "Budapest"), - ("Europe/Busingen", "Busingen"), - ("Europe/Chisinau", "Chisinau"), - ("Europe/Copenhagen", "Copenhagen"), - ("Europe/Dublin", "Dublin"), - ("Europe/Gibraltar", "Gibraltar"), - ("Europe/Guernsey", "Guernsey"), - ("Europe/Helsinki", "Helsinki"), - ("Europe/Isle_of_Man", "Isle_of_Man"), - ("Europe/Istanbul", "Istanbul"), - ("Europe/Jersey", "Jersey"), - ("Europe/Kaliningrad", "Kaliningrad"), - ("Europe/Kiev", "Kiev"), - ("Europe/Kirov", "Kirov"), - ("Europe/Lisbon", "Lisbon"), - ("Europe/Ljubljana", "Ljubljana"), - ("Europe/London", "London"), - ("Europe/Luxembourg", "Luxembourg"), - ("Europe/Madrid", "Madrid"), - ("Europe/Malta", "Malta"), - ("Europe/Mariehamn", "Mariehamn"), - ("Europe/Minsk", "Minsk"), - ("Europe/Monaco", "Monaco"), - ("Europe/Moscow", "Moscow"), - ("Europe/Nicosia", "Nicosia"), - ("Europe/Oslo", "Oslo"), - ("Europe/Paris", "Paris"), - ("Europe/Podgorica", "Podgorica"), - ("Europe/Prague", "Prague"), - ("Europe/Riga", "Riga"), - ("Europe/Rome", "Rome"), - ("Europe/Samara", "Samara"), - ("Europe/San_Marino", "San_Marino"), - ("Europe/Sarajevo", "Sarajevo"), - ("Europe/Saratov", "Saratov"), - ("Europe/Simferopol", "Simferopol"), - ("Europe/Skopje", "Skopje"), - ("Europe/Sofia", "Sofia"), - ("Europe/Stockholm", "Stockholm"), - ("Europe/Tallinn", "Tallinn"), - ("Europe/Tirane", "Tirane"), - ("Europe/Tiraspol", "Tiraspol"), - ("Europe/Ulyanovsk", "Ulyanovsk"), - ("Europe/Uzhgorod", "Uzhgorod"), - ("Europe/Vaduz", "Vaduz"), - ("Europe/Vatican", "Vatican"), - ("Europe/Vienna", "Vienna"), - ("Europe/Vilnius", "Vilnius"), - ("Europe/Volgograd", "Volgograd"), - ("Europe/Warsaw", "Warsaw"), - ("Europe/Zagreb", "Zagreb"), - ("Europe/Zaporozhye", "Zaporozhye"), - ("Europe/Zurich", "Zurich"), - ], - ), - ( - "Indian", - [ - ("Indian/Antananarivo", "Antananarivo"), - ("Indian/Chagos", "Chagos"), - ("Indian/Christmas", "Christmas"), - ("Indian/Cocos", "Cocos"), - ("Indian/Comoro", "Comoro"), - ("Indian/Kerguelen", "Kerguelen"), - ("Indian/Mahe", "Mahe"), - ("Indian/Maldives", "Maldives"), - ("Indian/Mauritius", "Mauritius"), - ("Indian/Mayotte", "Mayotte"), - ("Indian/Reunion", "Reunion"), - ], - ), - ( - "Mexico", - [ - ("Mexico/BajaNorte", "BajaNorte"), - ("Mexico/BajaSur", "BajaSur"), - ("Mexico/General", "General"), - ], - ), - ( - "Other", - [ - ("CET", "CET"), - ("CST6CDT", "CST6CDT"), - ("Cuba", "Cuba"), - ("EET", "EET"), - ("EST", "EST"), - ("EST5EDT", "EST5EDT"), - ("Egypt", "Egypt"), - ("Eire", "Eire"), - ("GB", "GB"), - ("GB-Eire", "GB-Eire"), - ("Greenwich", "Greenwich"), - ("HST", "HST"), - ("Hongkong", "Hongkong"), - ("Iceland", "Iceland"), - ("Iran", "Iran"), - ("Israel", "Israel"), - ("Jamaica", "Jamaica"), - ("Japan", "Japan"), - ("Kwajalein", "Kwajalein"), - ("Libya", "Libya"), - ("MET", "MET"), - ("MST", "MST"), - ("MST7MDT", "MST7MDT"), - ("NZ", "NZ"), - ("NZ-CHAT", "NZ-CHAT"), - ("Navajo", "Navajo"), - ("PRC", "PRC"), - ("PST8PDT", "PST8PDT"), - ("Poland", "Poland"), - ("Portugal", "Portugal"), - ("ROC", "ROC"), - ("ROK", "ROK"), - ("Singapore", "Singapore"), - ("Turkey", "Turkey"), - ("UCT", "UCT"), - ("UTC", "UTC"), - ("Universal", "Universal"), - ("W-SU", "W-SU"), - ("WET", "WET"), - ("Zulu", "Zulu"), - ], - ), - ( - "Pacific", - [ - ("Pacific/Apia", "Apia"), - ("Pacific/Auckland", "Auckland"), - ("Pacific/Bougainville", "Bougainville"), - ("Pacific/Chatham", "Chatham"), - ("Pacific/Chuuk", "Chuuk"), - ("Pacific/Easter", "Easter"), - ("Pacific/Efate", "Efate"), - ("Pacific/Enderbury", "Enderbury"), - ("Pacific/Fakaofo", "Fakaofo"), - ("Pacific/Fiji", "Fiji"), - ("Pacific/Funafuti", "Funafuti"), - ("Pacific/Galapagos", "Galapagos"), - ("Pacific/Gambier", "Gambier"), - ("Pacific/Guadalcanal", "Guadalcanal"), - ("Pacific/Guam", "Guam"), - ("Pacific/Honolulu", "Honolulu"), - ("Pacific/Johnston", "Johnston"), - ("Pacific/Kiritimati", "Kiritimati"), - ("Pacific/Kosrae", "Kosrae"), - ("Pacific/Kwajalein", "Kwajalein"), - ("Pacific/Majuro", "Majuro"), - ("Pacific/Marquesas", "Marquesas"), - ("Pacific/Midway", "Midway"), - ("Pacific/Nauru", "Nauru"), - ("Pacific/Niue", "Niue"), - ("Pacific/Norfolk", "Norfolk"), - ("Pacific/Noumea", "Noumea"), - ("Pacific/Pago_Pago", "Pago_Pago"), - ("Pacific/Palau", "Palau"), - ("Pacific/Pitcairn", "Pitcairn"), - ("Pacific/Pohnpei", "Pohnpei"), - ("Pacific/Ponape", "Ponape"), - ("Pacific/Port_Moresby", "Port_Moresby"), - ("Pacific/Rarotonga", "Rarotonga"), - ("Pacific/Saipan", "Saipan"), - ("Pacific/Samoa", "Samoa"), - ("Pacific/Tahiti", "Tahiti"), - ("Pacific/Tarawa", "Tarawa"), - ("Pacific/Tongatapu", "Tongatapu"), - ("Pacific/Truk", "Truk"), - ("Pacific/Wake", "Wake"), - ("Pacific/Wallis", "Wallis"), - ("Pacific/Yap", "Yap"), - ], - ), - ( - "US", - [ - ("US/Alaska", "Alaska"), - ("US/Aleutian", "Aleutian"), - ("US/Arizona", "Arizona"), - ("US/Central", "Central"), - ("US/East-Indiana", "East-Indiana"), - ("US/Eastern", "Eastern"), - ("US/Hawaii", "Hawaii"), - ("US/Indiana-Starke", "Indiana-Starke"), - ("US/Michigan", "Michigan"), - ("US/Mountain", "Mountain"), - ("US/Pacific", "Pacific"), - ("US/Samoa", "Samoa"), - ], - ), - ], - default="Asia/Ho_Chi_Minh", - max_length=50, - verbose_name="location", - ), + model_name='profile', + name='timezone', + field=models.CharField(choices=[('Africa', [('Africa/Abidjan', 'Abidjan'), ('Africa/Accra', 'Accra'), ('Africa/Addis_Ababa', 'Addis_Ababa'), ('Africa/Algiers', 'Algiers'), ('Africa/Asmara', 'Asmara'), ('Africa/Asmera', 'Asmera'), ('Africa/Bamako', 'Bamako'), ('Africa/Bangui', 'Bangui'), ('Africa/Banjul', 'Banjul'), ('Africa/Bissau', 'Bissau'), ('Africa/Blantyre', 'Blantyre'), ('Africa/Brazzaville', 'Brazzaville'), ('Africa/Bujumbura', 'Bujumbura'), ('Africa/Cairo', 'Cairo'), ('Africa/Casablanca', 'Casablanca'), ('Africa/Ceuta', 'Ceuta'), ('Africa/Conakry', 'Conakry'), ('Africa/Dakar', 'Dakar'), ('Africa/Dar_es_Salaam', 'Dar_es_Salaam'), ('Africa/Djibouti', 'Djibouti'), ('Africa/Douala', 'Douala'), ('Africa/El_Aaiun', 'El_Aaiun'), ('Africa/Freetown', 'Freetown'), ('Africa/Gaborone', 'Gaborone'), ('Africa/Harare', 'Harare'), ('Africa/Johannesburg', 'Johannesburg'), ('Africa/Juba', 'Juba'), ('Africa/Kampala', 'Kampala'), ('Africa/Khartoum', 'Khartoum'), ('Africa/Kigali', 'Kigali'), ('Africa/Kinshasa', 'Kinshasa'), ('Africa/Lagos', 'Lagos'), ('Africa/Libreville', 'Libreville'), ('Africa/Lome', 'Lome'), ('Africa/Luanda', 'Luanda'), ('Africa/Lubumbashi', 'Lubumbashi'), ('Africa/Lusaka', 'Lusaka'), ('Africa/Malabo', 'Malabo'), ('Africa/Maputo', 'Maputo'), ('Africa/Maseru', 'Maseru'), ('Africa/Mbabane', 'Mbabane'), ('Africa/Mogadishu', 'Mogadishu'), ('Africa/Monrovia', 'Monrovia'), ('Africa/Nairobi', 'Nairobi'), ('Africa/Ndjamena', 'Ndjamena'), ('Africa/Niamey', 'Niamey'), ('Africa/Nouakchott', 'Nouakchott'), ('Africa/Ouagadougou', 'Ouagadougou'), ('Africa/Porto-Novo', 'Porto-Novo'), ('Africa/Sao_Tome', 'Sao_Tome'), ('Africa/Timbuktu', 'Timbuktu'), ('Africa/Tripoli', 'Tripoli'), ('Africa/Tunis', 'Tunis'), ('Africa/Windhoek', 'Windhoek')]), ('America', [('America/Adak', 'Adak'), ('America/Anchorage', 'Anchorage'), ('America/Anguilla', 'Anguilla'), ('America/Antigua', 'Antigua'), ('America/Araguaina', 'Araguaina'), ('America/Argentina/Buenos_Aires', 'Argentina/Buenos_Aires'), ('America/Argentina/Catamarca', 'Argentina/Catamarca'), ('America/Argentina/ComodRivadavia', 'Argentina/ComodRivadavia'), ('America/Argentina/Cordoba', 'Argentina/Cordoba'), ('America/Argentina/Jujuy', 'Argentina/Jujuy'), ('America/Argentina/La_Rioja', 'Argentina/La_Rioja'), ('America/Argentina/Mendoza', 'Argentina/Mendoza'), ('America/Argentina/Rio_Gallegos', 'Argentina/Rio_Gallegos'), ('America/Argentina/Salta', 'Argentina/Salta'), ('America/Argentina/San_Juan', 'Argentina/San_Juan'), ('America/Argentina/San_Luis', 'Argentina/San_Luis'), ('America/Argentina/Tucuman', 'Argentina/Tucuman'), ('America/Argentina/Ushuaia', 'Argentina/Ushuaia'), ('America/Aruba', 'Aruba'), ('America/Asuncion', 'Asuncion'), ('America/Atikokan', 'Atikokan'), ('America/Atka', 'Atka'), ('America/Bahia', 'Bahia'), ('America/Bahia_Banderas', 'Bahia_Banderas'), ('America/Barbados', 'Barbados'), ('America/Belem', 'Belem'), ('America/Belize', 'Belize'), ('America/Blanc-Sablon', 'Blanc-Sablon'), ('America/Boa_Vista', 'Boa_Vista'), ('America/Bogota', 'Bogota'), ('America/Boise', 'Boise'), ('America/Buenos_Aires', 'Buenos_Aires'), ('America/Cambridge_Bay', 'Cambridge_Bay'), ('America/Campo_Grande', 'Campo_Grande'), ('America/Cancun', 'Cancun'), ('America/Caracas', 'Caracas'), ('America/Catamarca', 'Catamarca'), ('America/Cayenne', 'Cayenne'), ('America/Cayman', 'Cayman'), ('America/Chicago', 'Chicago'), ('America/Chihuahua', 'Chihuahua'), ('America/Coral_Harbour', 'Coral_Harbour'), ('America/Cordoba', 'Cordoba'), ('America/Costa_Rica', 'Costa_Rica'), ('America/Creston', 'Creston'), ('America/Cuiaba', 'Cuiaba'), ('America/Curacao', 'Curacao'), ('America/Danmarkshavn', 'Danmarkshavn'), ('America/Dawson', 'Dawson'), ('America/Dawson_Creek', 'Dawson_Creek'), ('America/Denver', 'Denver'), ('America/Detroit', 'Detroit'), ('America/Dominica', 'Dominica'), ('America/Edmonton', 'Edmonton'), ('America/Eirunepe', 'Eirunepe'), ('America/El_Salvador', 'El_Salvador'), ('America/Ensenada', 'Ensenada'), ('America/Fort_Nelson', 'Fort_Nelson'), ('America/Fort_Wayne', 'Fort_Wayne'), ('America/Fortaleza', 'Fortaleza'), ('America/Glace_Bay', 'Glace_Bay'), ('America/Godthab', 'Godthab'), ('America/Goose_Bay', 'Goose_Bay'), ('America/Grand_Turk', 'Grand_Turk'), ('America/Grenada', 'Grenada'), ('America/Guadeloupe', 'Guadeloupe'), ('America/Guatemala', 'Guatemala'), ('America/Guayaquil', 'Guayaquil'), ('America/Guyana', 'Guyana'), ('America/Halifax', 'Halifax'), ('America/Havana', 'Havana'), ('America/Hermosillo', 'Hermosillo'), ('America/Indiana/Indianapolis', 'Indiana/Indianapolis'), ('America/Indiana/Knox', 'Indiana/Knox'), ('America/Indiana/Marengo', 'Indiana/Marengo'), ('America/Indiana/Petersburg', 'Indiana/Petersburg'), ('America/Indiana/Tell_City', 'Indiana/Tell_City'), ('America/Indiana/Vevay', 'Indiana/Vevay'), ('America/Indiana/Vincennes', 'Indiana/Vincennes'), ('America/Indiana/Winamac', 'Indiana/Winamac'), ('America/Indianapolis', 'Indianapolis'), ('America/Inuvik', 'Inuvik'), ('America/Iqaluit', 'Iqaluit'), ('America/Jamaica', 'Jamaica'), ('America/Jujuy', 'Jujuy'), ('America/Juneau', 'Juneau'), ('America/Kentucky/Louisville', 'Kentucky/Louisville'), ('America/Kentucky/Monticello', 'Kentucky/Monticello'), ('America/Knox_IN', 'Knox_IN'), ('America/Kralendijk', 'Kralendijk'), ('America/La_Paz', 'La_Paz'), ('America/Lima', 'Lima'), ('America/Los_Angeles', 'Los_Angeles'), ('America/Louisville', 'Louisville'), ('America/Lower_Princes', 'Lower_Princes'), ('America/Maceio', 'Maceio'), ('America/Managua', 'Managua'), ('America/Manaus', 'Manaus'), ('America/Marigot', 'Marigot'), ('America/Martinique', 'Martinique'), ('America/Matamoros', 'Matamoros'), ('America/Mazatlan', 'Mazatlan'), ('America/Mendoza', 'Mendoza'), ('America/Menominee', 'Menominee'), ('America/Merida', 'Merida'), ('America/Metlakatla', 'Metlakatla'), ('America/Mexico_City', 'Mexico_City'), ('America/Miquelon', 'Miquelon'), ('America/Moncton', 'Moncton'), ('America/Monterrey', 'Monterrey'), ('America/Montevideo', 'Montevideo'), ('America/Montreal', 'Montreal'), ('America/Montserrat', 'Montserrat'), ('America/Nassau', 'Nassau'), ('America/New_York', 'New_York'), ('America/Nipigon', 'Nipigon'), ('America/Nome', 'Nome'), ('America/Noronha', 'Noronha'), ('America/North_Dakota/Beulah', 'North_Dakota/Beulah'), ('America/North_Dakota/Center', 'North_Dakota/Center'), ('America/North_Dakota/New_Salem', 'North_Dakota/New_Salem'), ('America/Ojinaga', 'Ojinaga'), ('America/Panama', 'Panama'), ('America/Pangnirtung', 'Pangnirtung'), ('America/Paramaribo', 'Paramaribo'), ('America/Phoenix', 'Phoenix'), ('America/Port-au-Prince', 'Port-au-Prince'), ('America/Port_of_Spain', 'Port_of_Spain'), ('America/Porto_Acre', 'Porto_Acre'), ('America/Porto_Velho', 'Porto_Velho'), ('America/Puerto_Rico', 'Puerto_Rico'), ('America/Punta_Arenas', 'Punta_Arenas'), ('America/Rainy_River', 'Rainy_River'), ('America/Rankin_Inlet', 'Rankin_Inlet'), ('America/Recife', 'Recife'), ('America/Regina', 'Regina'), ('America/Resolute', 'Resolute'), ('America/Rio_Branco', 'Rio_Branco'), ('America/Rosario', 'Rosario'), ('America/Santa_Isabel', 'Santa_Isabel'), ('America/Santarem', 'Santarem'), ('America/Santiago', 'Santiago'), ('America/Santo_Domingo', 'Santo_Domingo'), ('America/Sao_Paulo', 'Sao_Paulo'), ('America/Scoresbysund', 'Scoresbysund'), ('America/Shiprock', 'Shiprock'), ('America/Sitka', 'Sitka'), ('America/St_Barthelemy', 'St_Barthelemy'), ('America/St_Johns', 'St_Johns'), ('America/St_Kitts', 'St_Kitts'), ('America/St_Lucia', 'St_Lucia'), ('America/St_Thomas', 'St_Thomas'), ('America/St_Vincent', 'St_Vincent'), ('America/Swift_Current', 'Swift_Current'), ('America/Tegucigalpa', 'Tegucigalpa'), ('America/Thule', 'Thule'), ('America/Thunder_Bay', 'Thunder_Bay'), ('America/Tijuana', 'Tijuana'), ('America/Toronto', 'Toronto'), ('America/Tortola', 'Tortola'), ('America/Vancouver', 'Vancouver'), ('America/Virgin', 'Virgin'), ('America/Whitehorse', 'Whitehorse'), ('America/Winnipeg', 'Winnipeg'), ('America/Yakutat', 'Yakutat'), ('America/Yellowknife', 'Yellowknife')]), ('Antarctica', [('Antarctica/Casey', 'Casey'), ('Antarctica/Davis', 'Davis'), ('Antarctica/DumontDUrville', 'DumontDUrville'), ('Antarctica/Macquarie', 'Macquarie'), ('Antarctica/Mawson', 'Mawson'), ('Antarctica/McMurdo', 'McMurdo'), ('Antarctica/Palmer', 'Palmer'), ('Antarctica/Rothera', 'Rothera'), ('Antarctica/South_Pole', 'South_Pole'), ('Antarctica/Syowa', 'Syowa'), ('Antarctica/Troll', 'Troll'), ('Antarctica/Vostok', 'Vostok')]), ('Arctic', [('Arctic/Longyearbyen', 'Longyearbyen')]), ('Asia', [('Asia/Aden', 'Aden'), ('Asia/Almaty', 'Almaty'), ('Asia/Amman', 'Amman'), ('Asia/Anadyr', 'Anadyr'), ('Asia/Aqtau', 'Aqtau'), ('Asia/Aqtobe', 'Aqtobe'), ('Asia/Ashgabat', 'Ashgabat'), ('Asia/Ashkhabad', 'Ashkhabad'), ('Asia/Atyrau', 'Atyrau'), ('Asia/Baghdad', 'Baghdad'), ('Asia/Bahrain', 'Bahrain'), ('Asia/Baku', 'Baku'), ('Asia/Bangkok', 'Bangkok'), ('Asia/Barnaul', 'Barnaul'), ('Asia/Beirut', 'Beirut'), ('Asia/Bishkek', 'Bishkek'), ('Asia/Brunei', 'Brunei'), ('Asia/Calcutta', 'Calcutta'), ('Asia/Chita', 'Chita'), ('Asia/Choibalsan', 'Choibalsan'), ('Asia/Chongqing', 'Chongqing'), ('Asia/Chungking', 'Chungking'), ('Asia/Colombo', 'Colombo'), ('Asia/Dacca', 'Dacca'), ('Asia/Damascus', 'Damascus'), ('Asia/Dhaka', 'Dhaka'), ('Asia/Dili', 'Dili'), ('Asia/Dubai', 'Dubai'), ('Asia/Dushanbe', 'Dushanbe'), ('Asia/Famagusta', 'Famagusta'), ('Asia/Gaza', 'Gaza'), ('Asia/Harbin', 'Harbin'), ('Asia/Hebron', 'Hebron'), ('Asia/Ho_Chi_Minh', 'Ho_Chi_Minh'), ('Asia/Hong_Kong', 'Hong_Kong'), ('Asia/Hovd', 'Hovd'), ('Asia/Irkutsk', 'Irkutsk'), ('Asia/Istanbul', 'Istanbul'), ('Asia/Jakarta', 'Jakarta'), ('Asia/Jayapura', 'Jayapura'), ('Asia/Jerusalem', 'Jerusalem'), ('Asia/Kabul', 'Kabul'), ('Asia/Kamchatka', 'Kamchatka'), ('Asia/Karachi', 'Karachi'), ('Asia/Kashgar', 'Kashgar'), ('Asia/Kathmandu', 'Kathmandu'), ('Asia/Katmandu', 'Katmandu'), ('Asia/Khandyga', 'Khandyga'), ('Asia/Kolkata', 'Kolkata'), ('Asia/Krasnoyarsk', 'Krasnoyarsk'), ('Asia/Kuala_Lumpur', 'Kuala_Lumpur'), ('Asia/Kuching', 'Kuching'), ('Asia/Kuwait', 'Kuwait'), ('Asia/Macao', 'Macao'), ('Asia/Macau', 'Macau'), ('Asia/Magadan', 'Magadan'), ('Asia/Makassar', 'Makassar'), ('Asia/Manila', 'Manila'), ('Asia/Muscat', 'Muscat'), ('Asia/Nicosia', 'Nicosia'), ('Asia/Novokuznetsk', 'Novokuznetsk'), ('Asia/Novosibirsk', 'Novosibirsk'), ('Asia/Omsk', 'Omsk'), ('Asia/Oral', 'Oral'), ('Asia/Phnom_Penh', 'Phnom_Penh'), ('Asia/Pontianak', 'Pontianak'), ('Asia/Pyongyang', 'Pyongyang'), ('Asia/Qatar', 'Qatar'), ('Asia/Qostanay', 'Qostanay'), ('Asia/Qyzylorda', 'Qyzylorda'), ('Asia/Rangoon', 'Rangoon'), ('Asia/Riyadh', 'Riyadh'), ('Asia/Saigon', 'Saigon'), ('Asia/Sakhalin', 'Sakhalin'), ('Asia/Samarkand', 'Samarkand'), ('Asia/Seoul', 'Seoul'), ('Asia/Shanghai', 'Shanghai'), ('Asia/Singapore', 'Singapore'), ('Asia/Srednekolymsk', 'Srednekolymsk'), ('Asia/Taipei', 'Taipei'), ('Asia/Tashkent', 'Tashkent'), ('Asia/Tbilisi', 'Tbilisi'), ('Asia/Tehran', 'Tehran'), ('Asia/Tel_Aviv', 'Tel_Aviv'), ('Asia/Thimbu', 'Thimbu'), ('Asia/Thimphu', 'Thimphu'), ('Asia/Tokyo', 'Tokyo'), ('Asia/Tomsk', 'Tomsk'), ('Asia/Ujung_Pandang', 'Ujung_Pandang'), ('Asia/Ulaanbaatar', 'Ulaanbaatar'), ('Asia/Ulan_Bator', 'Ulan_Bator'), ('Asia/Urumqi', 'Urumqi'), ('Asia/Ust-Nera', 'Ust-Nera'), ('Asia/Vientiane', 'Vientiane'), ('Asia/Vladivostok', 'Vladivostok'), ('Asia/Yakutsk', 'Yakutsk'), ('Asia/Yangon', 'Yangon'), ('Asia/Yekaterinburg', 'Yekaterinburg'), ('Asia/Yerevan', 'Yerevan')]), ('Atlantic', [('Atlantic/Azores', 'Azores'), ('Atlantic/Bermuda', 'Bermuda'), ('Atlantic/Canary', 'Canary'), ('Atlantic/Cape_Verde', 'Cape_Verde'), ('Atlantic/Faeroe', 'Faeroe'), ('Atlantic/Faroe', 'Faroe'), ('Atlantic/Jan_Mayen', 'Jan_Mayen'), ('Atlantic/Madeira', 'Madeira'), ('Atlantic/Reykjavik', 'Reykjavik'), ('Atlantic/South_Georgia', 'South_Georgia'), ('Atlantic/St_Helena', 'St_Helena'), ('Atlantic/Stanley', 'Stanley')]), ('Australia', [('Australia/ACT', 'ACT'), ('Australia/Adelaide', 'Adelaide'), ('Australia/Brisbane', 'Brisbane'), ('Australia/Broken_Hill', 'Broken_Hill'), ('Australia/Canberra', 'Canberra'), ('Australia/Currie', 'Currie'), ('Australia/Darwin', 'Darwin'), ('Australia/Eucla', 'Eucla'), ('Australia/Hobart', 'Hobart'), ('Australia/LHI', 'LHI'), ('Australia/Lindeman', 'Lindeman'), ('Australia/Lord_Howe', 'Lord_Howe'), ('Australia/Melbourne', 'Melbourne'), ('Australia/NSW', 'NSW'), ('Australia/North', 'North'), ('Australia/Perth', 'Perth'), ('Australia/Queensland', 'Queensland'), ('Australia/South', 'South'), ('Australia/Sydney', 'Sydney'), ('Australia/Tasmania', 'Tasmania'), ('Australia/Victoria', 'Victoria'), ('Australia/West', 'West'), ('Australia/Yancowinna', 'Yancowinna')]), ('Brazil', [('Brazil/Acre', 'Acre'), ('Brazil/DeNoronha', 'DeNoronha'), ('Brazil/East', 'East'), ('Brazil/West', 'West')]), ('Canada', [('Canada/Atlantic', 'Atlantic'), ('Canada/Central', 'Central'), ('Canada/Eastern', 'Eastern'), ('Canada/Mountain', 'Mountain'), ('Canada/Newfoundland', 'Newfoundland'), ('Canada/Pacific', 'Pacific'), ('Canada/Saskatchewan', 'Saskatchewan'), ('Canada/Yukon', 'Yukon')]), ('Chile', [('Chile/Continental', 'Continental'), ('Chile/EasterIsland', 'EasterIsland')]), ('Etc', [('Etc/Greenwich', 'Greenwich'), ('Etc/UCT', 'UCT'), ('Etc/UTC', 'UTC'), ('Etc/Universal', 'Universal'), ('Etc/Zulu', 'Zulu')]), ('Europe', [('Europe/Amsterdam', 'Amsterdam'), ('Europe/Andorra', 'Andorra'), ('Europe/Astrakhan', 'Astrakhan'), ('Europe/Athens', 'Athens'), ('Europe/Belfast', 'Belfast'), ('Europe/Belgrade', 'Belgrade'), ('Europe/Berlin', 'Berlin'), ('Europe/Bratislava', 'Bratislava'), ('Europe/Brussels', 'Brussels'), ('Europe/Bucharest', 'Bucharest'), ('Europe/Budapest', 'Budapest'), ('Europe/Busingen', 'Busingen'), ('Europe/Chisinau', 'Chisinau'), ('Europe/Copenhagen', 'Copenhagen'), ('Europe/Dublin', 'Dublin'), ('Europe/Gibraltar', 'Gibraltar'), ('Europe/Guernsey', 'Guernsey'), ('Europe/Helsinki', 'Helsinki'), ('Europe/Isle_of_Man', 'Isle_of_Man'), ('Europe/Istanbul', 'Istanbul'), ('Europe/Jersey', 'Jersey'), ('Europe/Kaliningrad', 'Kaliningrad'), ('Europe/Kiev', 'Kiev'), ('Europe/Kirov', 'Kirov'), ('Europe/Lisbon', 'Lisbon'), ('Europe/Ljubljana', 'Ljubljana'), ('Europe/London', 'London'), ('Europe/Luxembourg', 'Luxembourg'), ('Europe/Madrid', 'Madrid'), ('Europe/Malta', 'Malta'), ('Europe/Mariehamn', 'Mariehamn'), ('Europe/Minsk', 'Minsk'), ('Europe/Monaco', 'Monaco'), ('Europe/Moscow', 'Moscow'), ('Europe/Nicosia', 'Nicosia'), ('Europe/Oslo', 'Oslo'), ('Europe/Paris', 'Paris'), ('Europe/Podgorica', 'Podgorica'), ('Europe/Prague', 'Prague'), ('Europe/Riga', 'Riga'), ('Europe/Rome', 'Rome'), ('Europe/Samara', 'Samara'), ('Europe/San_Marino', 'San_Marino'), ('Europe/Sarajevo', 'Sarajevo'), ('Europe/Saratov', 'Saratov'), ('Europe/Simferopol', 'Simferopol'), ('Europe/Skopje', 'Skopje'), ('Europe/Sofia', 'Sofia'), ('Europe/Stockholm', 'Stockholm'), ('Europe/Tallinn', 'Tallinn'), ('Europe/Tirane', 'Tirane'), ('Europe/Tiraspol', 'Tiraspol'), ('Europe/Ulyanovsk', 'Ulyanovsk'), ('Europe/Uzhgorod', 'Uzhgorod'), ('Europe/Vaduz', 'Vaduz'), ('Europe/Vatican', 'Vatican'), ('Europe/Vienna', 'Vienna'), ('Europe/Vilnius', 'Vilnius'), ('Europe/Volgograd', 'Volgograd'), ('Europe/Warsaw', 'Warsaw'), ('Europe/Zagreb', 'Zagreb'), ('Europe/Zaporozhye', 'Zaporozhye'), ('Europe/Zurich', 'Zurich')]), ('Indian', [('Indian/Antananarivo', 'Antananarivo'), ('Indian/Chagos', 'Chagos'), ('Indian/Christmas', 'Christmas'), ('Indian/Cocos', 'Cocos'), ('Indian/Comoro', 'Comoro'), ('Indian/Kerguelen', 'Kerguelen'), ('Indian/Mahe', 'Mahe'), ('Indian/Maldives', 'Maldives'), ('Indian/Mauritius', 'Mauritius'), ('Indian/Mayotte', 'Mayotte'), ('Indian/Reunion', 'Reunion')]), ('Mexico', [('Mexico/BajaNorte', 'BajaNorte'), ('Mexico/BajaSur', 'BajaSur'), ('Mexico/General', 'General')]), ('Other', [('CET', 'CET'), ('CST6CDT', 'CST6CDT'), ('Cuba', 'Cuba'), ('EET', 'EET'), ('EST', 'EST'), ('EST5EDT', 'EST5EDT'), ('Egypt', 'Egypt'), ('Eire', 'Eire'), ('GB', 'GB'), ('GB-Eire', 'GB-Eire'), ('Greenwich', 'Greenwich'), ('HST', 'HST'), ('Hongkong', 'Hongkong'), ('Iceland', 'Iceland'), ('Iran', 'Iran'), ('Israel', 'Israel'), ('Jamaica', 'Jamaica'), ('Japan', 'Japan'), ('Kwajalein', 'Kwajalein'), ('Libya', 'Libya'), ('MET', 'MET'), ('MST', 'MST'), ('MST7MDT', 'MST7MDT'), ('NZ', 'NZ'), ('NZ-CHAT', 'NZ-CHAT'), ('Navajo', 'Navajo'), ('PRC', 'PRC'), ('PST8PDT', 'PST8PDT'), ('Poland', 'Poland'), ('Portugal', 'Portugal'), ('ROC', 'ROC'), ('ROK', 'ROK'), ('Singapore', 'Singapore'), ('Turkey', 'Turkey'), ('UCT', 'UCT'), ('UTC', 'UTC'), ('Universal', 'Universal'), ('W-SU', 'W-SU'), ('WET', 'WET'), ('Zulu', 'Zulu')]), ('Pacific', [('Pacific/Apia', 'Apia'), ('Pacific/Auckland', 'Auckland'), ('Pacific/Bougainville', 'Bougainville'), ('Pacific/Chatham', 'Chatham'), ('Pacific/Chuuk', 'Chuuk'), ('Pacific/Easter', 'Easter'), ('Pacific/Efate', 'Efate'), ('Pacific/Enderbury', 'Enderbury'), ('Pacific/Fakaofo', 'Fakaofo'), ('Pacific/Fiji', 'Fiji'), ('Pacific/Funafuti', 'Funafuti'), ('Pacific/Galapagos', 'Galapagos'), ('Pacific/Gambier', 'Gambier'), ('Pacific/Guadalcanal', 'Guadalcanal'), ('Pacific/Guam', 'Guam'), ('Pacific/Honolulu', 'Honolulu'), ('Pacific/Johnston', 'Johnston'), ('Pacific/Kiritimati', 'Kiritimati'), ('Pacific/Kosrae', 'Kosrae'), ('Pacific/Kwajalein', 'Kwajalein'), ('Pacific/Majuro', 'Majuro'), ('Pacific/Marquesas', 'Marquesas'), ('Pacific/Midway', 'Midway'), ('Pacific/Nauru', 'Nauru'), ('Pacific/Niue', 'Niue'), ('Pacific/Norfolk', 'Norfolk'), ('Pacific/Noumea', 'Noumea'), ('Pacific/Pago_Pago', 'Pago_Pago'), ('Pacific/Palau', 'Palau'), ('Pacific/Pitcairn', 'Pitcairn'), ('Pacific/Pohnpei', 'Pohnpei'), ('Pacific/Ponape', 'Ponape'), ('Pacific/Port_Moresby', 'Port_Moresby'), ('Pacific/Rarotonga', 'Rarotonga'), ('Pacific/Saipan', 'Saipan'), ('Pacific/Samoa', 'Samoa'), ('Pacific/Tahiti', 'Tahiti'), ('Pacific/Tarawa', 'Tarawa'), ('Pacific/Tongatapu', 'Tongatapu'), ('Pacific/Truk', 'Truk'), ('Pacific/Wake', 'Wake'), ('Pacific/Wallis', 'Wallis'), ('Pacific/Yap', 'Yap')]), ('US', [('US/Alaska', 'Alaska'), ('US/Aleutian', 'Aleutian'), ('US/Arizona', 'Arizona'), ('US/Central', 'Central'), ('US/East-Indiana', 'East-Indiana'), ('US/Eastern', 'Eastern'), ('US/Hawaii', 'Hawaii'), ('US/Indiana-Starke', 'Indiana-Starke'), ('US/Michigan', 'Michigan'), ('US/Mountain', 'Mountain'), ('US/Pacific', 'Pacific'), ('US/Samoa', 'Samoa')])], default='Asia/Ho_Chi_Minh', max_length=50, verbose_name='location'), ), ] diff --git a/judge/migrations/0102_fix_custom_validator.py b/judge/migrations/0102_fix_custom_validator.py index e6bcd4a..a0dccce 100644 --- a/judge/migrations/0102_fix_custom_validator.py +++ b/judge/migrations/0102_fix_custom_validator.py @@ -6,50 +6,18 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("judge", "0101_custom_validator"), + ('judge', '0101_custom_validator'), ] operations = [ migrations.AlterField( - model_name="problemdata", - name="checker", - field=models.CharField( - blank=True, - choices=[ - ("standard", "Standard"), - ("floats", "Floats"), - ("floatsabs", "Floats (absolute)"), - ("floatsrel", "Floats (relative)"), - ("rstripped", "Non-trailing spaces"), - ("sorted", "Unordered"), - ("identical", "Byte identical"), - ("linecount", "Line-by-line"), - ("custom", "Custom checker"), - ("customval", "Custom Validator"), - ], - max_length=10, - verbose_name="checker", - ), + model_name='problemdata', + name='checker', + field=models.CharField(blank=True, choices=[('standard', 'Standard'), ('floats', 'Floats'), ('floatsabs', 'Floats (absolute)'), ('floatsrel', 'Floats (relative)'), ('rstripped', 'Non-trailing spaces'), ('sorted', 'Unordered'), ('identical', 'Byte identical'), ('linecount', 'Line-by-line'), ('custom', 'Custom checker'), ('customval', 'Custom Validator')], max_length=10, verbose_name='checker'), ), migrations.AlterField( - model_name="problemtestcase", - name="checker", - field=models.CharField( - blank=True, - choices=[ - ("standard", "Standard"), - ("floats", "Floats"), - ("floatsabs", "Floats (absolute)"), - ("floatsrel", "Floats (relative)"), - ("rstripped", "Non-trailing spaces"), - ("sorted", "Unordered"), - ("identical", "Byte identical"), - ("linecount", "Line-by-line"), - ("custom", "Custom checker"), - ("customval", "Custom Validator"), - ], - max_length=10, - verbose_name="checker", - ), + model_name='problemtestcase', + name='checker', + field=models.CharField(blank=True, choices=[('standard', 'Standard'), ('floats', 'Floats'), ('floatsabs', 'Floats (absolute)'), ('floatsrel', 'Floats (relative)'), ('rstripped', 'Non-trailing spaces'), ('sorted', 'Unordered'), ('identical', 'Byte identical'), ('linecount', 'Line-by-line'), ('custom', 'Custom checker'), ('customval', 'Custom Validator')], max_length=10, verbose_name='checker'), ), ] diff --git a/judge/migrations/0103_fix_custom_validator.py b/judge/migrations/0103_fix_custom_validator.py index d354303..2720bb8 100644 --- a/judge/migrations/0103_fix_custom_validator.py +++ b/judge/migrations/0103_fix_custom_validator.py @@ -6,13 +6,13 @@ from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ("judge", "0102_fix_custom_validator"), + ('judge', '0102_fix_custom_validator'), ] operations = [ migrations.RenameField( - model_name="problemdata", - old_name="custom_valid", - new_name="custom_validator", + model_name='problemdata', + old_name='custom_valid', + new_name='custom_validator', ), ] diff --git a/judge/migrations/0104_auto_20200410_1313.py b/judge/migrations/0104_auto_20200410_1313.py index ccba53d..bbefe21 100644 --- a/judge/migrations/0104_auto_20200410_1313.py +++ b/judge/migrations/0104_auto_20200410_1313.py @@ -6,57 +6,23 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("judge", "0103_fix_custom_validator"), + ('judge', '0103_fix_custom_validator'), ] operations = [ migrations.AlterField( - model_name="contestproblem", - name="output_prefix_override", - field=models.IntegerField( - blank=True, default=0, null=True, verbose_name="visible testcases" - ), + model_name='contestproblem', + name='output_prefix_override', + field=models.IntegerField(blank=True, default=0, null=True, verbose_name='visible testcases'), ), migrations.AlterField( - model_name="problemdata", - name="checker", - field=models.CharField( - blank=True, - choices=[ - ("standard", "Standard"), - ("floats", "Floats"), - ("floatsabs", "Floats (absolute)"), - ("floatsrel", "Floats (relative)"), - ("rstripped", "Non-trailing spaces"), - ("sorted", "Unordered"), - ("identical", "Byte identical"), - ("linecount", "Line-by-line"), - ("custom", "Custom checker (PY)"), - ("customval", "Custom validator (CPP)"), - ], - max_length=10, - verbose_name="checker", - ), + model_name='problemdata', + name='checker', + field=models.CharField(blank=True, choices=[('standard', 'Standard'), ('floats', 'Floats'), ('floatsabs', 'Floats (absolute)'), ('floatsrel', 'Floats (relative)'), ('rstripped', 'Non-trailing spaces'), ('sorted', 'Unordered'), ('identical', 'Byte identical'), ('linecount', 'Line-by-line'), ('custom', 'Custom checker (PY)'), ('customval', 'Custom validator (CPP)')], max_length=10, verbose_name='checker'), ), migrations.AlterField( - model_name="problemtestcase", - name="checker", - field=models.CharField( - blank=True, - choices=[ - ("standard", "Standard"), - ("floats", "Floats"), - ("floatsabs", "Floats (absolute)"), - ("floatsrel", "Floats (relative)"), - ("rstripped", "Non-trailing spaces"), - ("sorted", "Unordered"), - ("identical", "Byte identical"), - ("linecount", "Line-by-line"), - ("custom", "Custom checker (PY)"), - ("customval", "Custom validator (CPP)"), - ], - max_length=10, - verbose_name="checker", - ), + model_name='problemtestcase', + name='checker', + field=models.CharField(blank=True, choices=[('standard', 'Standard'), ('floats', 'Floats'), ('floatsabs', 'Floats (absolute)'), ('floatsrel', 'Floats (relative)'), ('rstripped', 'Non-trailing spaces'), ('sorted', 'Unordered'), ('identical', 'Byte identical'), ('linecount', 'Line-by-line'), ('custom', 'Custom checker (PY)'), ('customval', 'Custom validator (CPP)')], max_length=10, verbose_name='checker'), ), ] diff --git a/judge/migrations/0105_auto_20200523_0756.py b/judge/migrations/0105_auto_20200523_0756.py deleted file mode 100644 index 553c24f..0000000 --- a/judge/migrations/0105_auto_20200523_0756.py +++ /dev/null @@ -1,686 +0,0 @@ -# Generated by Django 2.2.12 on 2020-05-23 00:56 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0104_auto_20200410_1313"), - ] - - operations = [ - migrations.AlterField( - model_name="contestproblem", - name="output_prefix_override", - field=models.IntegerField( - blank=True, - default=0, - help_text="0 to not show testcases, 1 to show", - null=True, - verbose_name="visible testcases", - ), - ), - migrations.AlterField( - model_name="profile", - name="timezone", - field=models.CharField( - choices=[ - ( - "Africa", - [ - ("Africa/Abidjan", "Abidjan"), - ("Africa/Accra", "Accra"), - ("Africa/Addis_Ababa", "Addis_Ababa"), - ("Africa/Algiers", "Algiers"), - ("Africa/Asmara", "Asmara"), - ("Africa/Asmera", "Asmera"), - ("Africa/Bamako", "Bamako"), - ("Africa/Bangui", "Bangui"), - ("Africa/Banjul", "Banjul"), - ("Africa/Bissau", "Bissau"), - ("Africa/Blantyre", "Blantyre"), - ("Africa/Brazzaville", "Brazzaville"), - ("Africa/Bujumbura", "Bujumbura"), - ("Africa/Cairo", "Cairo"), - ("Africa/Casablanca", "Casablanca"), - ("Africa/Ceuta", "Ceuta"), - ("Africa/Conakry", "Conakry"), - ("Africa/Dakar", "Dakar"), - ("Africa/Dar_es_Salaam", "Dar_es_Salaam"), - ("Africa/Djibouti", "Djibouti"), - ("Africa/Douala", "Douala"), - ("Africa/El_Aaiun", "El_Aaiun"), - ("Africa/Freetown", "Freetown"), - ("Africa/Gaborone", "Gaborone"), - ("Africa/Harare", "Harare"), - ("Africa/Johannesburg", "Johannesburg"), - ("Africa/Juba", "Juba"), - ("Africa/Kampala", "Kampala"), - ("Africa/Khartoum", "Khartoum"), - ("Africa/Kigali", "Kigali"), - ("Africa/Kinshasa", "Kinshasa"), - ("Africa/Lagos", "Lagos"), - ("Africa/Libreville", "Libreville"), - ("Africa/Lome", "Lome"), - ("Africa/Luanda", "Luanda"), - ("Africa/Lubumbashi", "Lubumbashi"), - ("Africa/Lusaka", "Lusaka"), - ("Africa/Malabo", "Malabo"), - ("Africa/Maputo", "Maputo"), - ("Africa/Maseru", "Maseru"), - ("Africa/Mbabane", "Mbabane"), - ("Africa/Mogadishu", "Mogadishu"), - ("Africa/Monrovia", "Monrovia"), - ("Africa/Nairobi", "Nairobi"), - ("Africa/Ndjamena", "Ndjamena"), - ("Africa/Niamey", "Niamey"), - ("Africa/Nouakchott", "Nouakchott"), - ("Africa/Ouagadougou", "Ouagadougou"), - ("Africa/Porto-Novo", "Porto-Novo"), - ("Africa/Sao_Tome", "Sao_Tome"), - ("Africa/Timbuktu", "Timbuktu"), - ("Africa/Tripoli", "Tripoli"), - ("Africa/Tunis", "Tunis"), - ("Africa/Windhoek", "Windhoek"), - ], - ), - ( - "America", - [ - ("America/Adak", "Adak"), - ("America/Anchorage", "Anchorage"), - ("America/Anguilla", "Anguilla"), - ("America/Antigua", "Antigua"), - ("America/Araguaina", "Araguaina"), - ( - "America/Argentina/Buenos_Aires", - "Argentina/Buenos_Aires", - ), - ("America/Argentina/Catamarca", "Argentina/Catamarca"), - ( - "America/Argentina/ComodRivadavia", - "Argentina/ComodRivadavia", - ), - ("America/Argentina/Cordoba", "Argentina/Cordoba"), - ("America/Argentina/Jujuy", "Argentina/Jujuy"), - ("America/Argentina/La_Rioja", "Argentina/La_Rioja"), - ("America/Argentina/Mendoza", "Argentina/Mendoza"), - ( - "America/Argentina/Rio_Gallegos", - "Argentina/Rio_Gallegos", - ), - ("America/Argentina/Salta", "Argentina/Salta"), - ("America/Argentina/San_Juan", "Argentina/San_Juan"), - ("America/Argentina/San_Luis", "Argentina/San_Luis"), - ("America/Argentina/Tucuman", "Argentina/Tucuman"), - ("America/Argentina/Ushuaia", "Argentina/Ushuaia"), - ("America/Aruba", "Aruba"), - ("America/Asuncion", "Asuncion"), - ("America/Atikokan", "Atikokan"), - ("America/Atka", "Atka"), - ("America/Bahia", "Bahia"), - ("America/Bahia_Banderas", "Bahia_Banderas"), - ("America/Barbados", "Barbados"), - ("America/Belem", "Belem"), - ("America/Belize", "Belize"), - ("America/Blanc-Sablon", "Blanc-Sablon"), - ("America/Boa_Vista", "Boa_Vista"), - ("America/Bogota", "Bogota"), - ("America/Boise", "Boise"), - ("America/Buenos_Aires", "Buenos_Aires"), - ("America/Cambridge_Bay", "Cambridge_Bay"), - ("America/Campo_Grande", "Campo_Grande"), - ("America/Cancun", "Cancun"), - ("America/Caracas", "Caracas"), - ("America/Catamarca", "Catamarca"), - ("America/Cayenne", "Cayenne"), - ("America/Cayman", "Cayman"), - ("America/Chicago", "Chicago"), - ("America/Chihuahua", "Chihuahua"), - ("America/Coral_Harbour", "Coral_Harbour"), - ("America/Cordoba", "Cordoba"), - ("America/Costa_Rica", "Costa_Rica"), - ("America/Creston", "Creston"), - ("America/Cuiaba", "Cuiaba"), - ("America/Curacao", "Curacao"), - ("America/Danmarkshavn", "Danmarkshavn"), - ("America/Dawson", "Dawson"), - ("America/Dawson_Creek", "Dawson_Creek"), - ("America/Denver", "Denver"), - ("America/Detroit", "Detroit"), - ("America/Dominica", "Dominica"), - ("America/Edmonton", "Edmonton"), - ("America/Eirunepe", "Eirunepe"), - ("America/El_Salvador", "El_Salvador"), - ("America/Ensenada", "Ensenada"), - ("America/Fort_Nelson", "Fort_Nelson"), - ("America/Fort_Wayne", "Fort_Wayne"), - ("America/Fortaleza", "Fortaleza"), - ("America/Glace_Bay", "Glace_Bay"), - ("America/Godthab", "Godthab"), - ("America/Goose_Bay", "Goose_Bay"), - ("America/Grand_Turk", "Grand_Turk"), - ("America/Grenada", "Grenada"), - ("America/Guadeloupe", "Guadeloupe"), - ("America/Guatemala", "Guatemala"), - ("America/Guayaquil", "Guayaquil"), - ("America/Guyana", "Guyana"), - ("America/Halifax", "Halifax"), - ("America/Havana", "Havana"), - ("America/Hermosillo", "Hermosillo"), - ("America/Indiana/Indianapolis", "Indiana/Indianapolis"), - ("America/Indiana/Knox", "Indiana/Knox"), - ("America/Indiana/Marengo", "Indiana/Marengo"), - ("America/Indiana/Petersburg", "Indiana/Petersburg"), - ("America/Indiana/Tell_City", "Indiana/Tell_City"), - ("America/Indiana/Vevay", "Indiana/Vevay"), - ("America/Indiana/Vincennes", "Indiana/Vincennes"), - ("America/Indiana/Winamac", "Indiana/Winamac"), - ("America/Indianapolis", "Indianapolis"), - ("America/Inuvik", "Inuvik"), - ("America/Iqaluit", "Iqaluit"), - ("America/Jamaica", "Jamaica"), - ("America/Jujuy", "Jujuy"), - ("America/Juneau", "Juneau"), - ("America/Kentucky/Louisville", "Kentucky/Louisville"), - ("America/Kentucky/Monticello", "Kentucky/Monticello"), - ("America/Knox_IN", "Knox_IN"), - ("America/Kralendijk", "Kralendijk"), - ("America/La_Paz", "La_Paz"), - ("America/Lima", "Lima"), - ("America/Los_Angeles", "Los_Angeles"), - ("America/Louisville", "Louisville"), - ("America/Lower_Princes", "Lower_Princes"), - ("America/Maceio", "Maceio"), - ("America/Managua", "Managua"), - ("America/Manaus", "Manaus"), - ("America/Marigot", "Marigot"), - ("America/Martinique", "Martinique"), - ("America/Matamoros", "Matamoros"), - ("America/Mazatlan", "Mazatlan"), - ("America/Mendoza", "Mendoza"), - ("America/Menominee", "Menominee"), - ("America/Merida", "Merida"), - ("America/Metlakatla", "Metlakatla"), - ("America/Mexico_City", "Mexico_City"), - ("America/Miquelon", "Miquelon"), - ("America/Moncton", "Moncton"), - ("America/Monterrey", "Monterrey"), - ("America/Montevideo", "Montevideo"), - ("America/Montreal", "Montreal"), - ("America/Montserrat", "Montserrat"), - ("America/Nassau", "Nassau"), - ("America/New_York", "New_York"), - ("America/Nipigon", "Nipigon"), - ("America/Nome", "Nome"), - ("America/Noronha", "Noronha"), - ("America/North_Dakota/Beulah", "North_Dakota/Beulah"), - ("America/North_Dakota/Center", "North_Dakota/Center"), - ( - "America/North_Dakota/New_Salem", - "North_Dakota/New_Salem", - ), - ("America/Nuuk", "Nuuk"), - ("America/Ojinaga", "Ojinaga"), - ("America/Panama", "Panama"), - ("America/Pangnirtung", "Pangnirtung"), - ("America/Paramaribo", "Paramaribo"), - ("America/Phoenix", "Phoenix"), - ("America/Port-au-Prince", "Port-au-Prince"), - ("America/Port_of_Spain", "Port_of_Spain"), - ("America/Porto_Acre", "Porto_Acre"), - ("America/Porto_Velho", "Porto_Velho"), - ("America/Puerto_Rico", "Puerto_Rico"), - ("America/Punta_Arenas", "Punta_Arenas"), - ("America/Rainy_River", "Rainy_River"), - ("America/Rankin_Inlet", "Rankin_Inlet"), - ("America/Recife", "Recife"), - ("America/Regina", "Regina"), - ("America/Resolute", "Resolute"), - ("America/Rio_Branco", "Rio_Branco"), - ("America/Rosario", "Rosario"), - ("America/Santa_Isabel", "Santa_Isabel"), - ("America/Santarem", "Santarem"), - ("America/Santiago", "Santiago"), - ("America/Santo_Domingo", "Santo_Domingo"), - ("America/Sao_Paulo", "Sao_Paulo"), - ("America/Scoresbysund", "Scoresbysund"), - ("America/Shiprock", "Shiprock"), - ("America/Sitka", "Sitka"), - ("America/St_Barthelemy", "St_Barthelemy"), - ("America/St_Johns", "St_Johns"), - ("America/St_Kitts", "St_Kitts"), - ("America/St_Lucia", "St_Lucia"), - ("America/St_Thomas", "St_Thomas"), - ("America/St_Vincent", "St_Vincent"), - ("America/Swift_Current", "Swift_Current"), - ("America/Tegucigalpa", "Tegucigalpa"), - ("America/Thule", "Thule"), - ("America/Thunder_Bay", "Thunder_Bay"), - ("America/Tijuana", "Tijuana"), - ("America/Toronto", "Toronto"), - ("America/Tortola", "Tortola"), - ("America/Vancouver", "Vancouver"), - ("America/Virgin", "Virgin"), - ("America/Whitehorse", "Whitehorse"), - ("America/Winnipeg", "Winnipeg"), - ("America/Yakutat", "Yakutat"), - ("America/Yellowknife", "Yellowknife"), - ], - ), - ( - "Antarctica", - [ - ("Antarctica/Casey", "Casey"), - ("Antarctica/Davis", "Davis"), - ("Antarctica/DumontDUrville", "DumontDUrville"), - ("Antarctica/Macquarie", "Macquarie"), - ("Antarctica/Mawson", "Mawson"), - ("Antarctica/McMurdo", "McMurdo"), - ("Antarctica/Palmer", "Palmer"), - ("Antarctica/Rothera", "Rothera"), - ("Antarctica/South_Pole", "South_Pole"), - ("Antarctica/Syowa", "Syowa"), - ("Antarctica/Troll", "Troll"), - ("Antarctica/Vostok", "Vostok"), - ], - ), - ("Arctic", [("Arctic/Longyearbyen", "Longyearbyen")]), - ( - "Asia", - [ - ("Asia/Aden", "Aden"), - ("Asia/Almaty", "Almaty"), - ("Asia/Amman", "Amman"), - ("Asia/Anadyr", "Anadyr"), - ("Asia/Aqtau", "Aqtau"), - ("Asia/Aqtobe", "Aqtobe"), - ("Asia/Ashgabat", "Ashgabat"), - ("Asia/Ashkhabad", "Ashkhabad"), - ("Asia/Atyrau", "Atyrau"), - ("Asia/Baghdad", "Baghdad"), - ("Asia/Bahrain", "Bahrain"), - ("Asia/Baku", "Baku"), - ("Asia/Bangkok", "Bangkok"), - ("Asia/Barnaul", "Barnaul"), - ("Asia/Beirut", "Beirut"), - ("Asia/Bishkek", "Bishkek"), - ("Asia/Brunei", "Brunei"), - ("Asia/Calcutta", "Calcutta"), - ("Asia/Chita", "Chita"), - ("Asia/Choibalsan", "Choibalsan"), - ("Asia/Chongqing", "Chongqing"), - ("Asia/Chungking", "Chungking"), - ("Asia/Colombo", "Colombo"), - ("Asia/Dacca", "Dacca"), - ("Asia/Damascus", "Damascus"), - ("Asia/Dhaka", "Dhaka"), - ("Asia/Dili", "Dili"), - ("Asia/Dubai", "Dubai"), - ("Asia/Dushanbe", "Dushanbe"), - ("Asia/Famagusta", "Famagusta"), - ("Asia/Gaza", "Gaza"), - ("Asia/Harbin", "Harbin"), - ("Asia/Hebron", "Hebron"), - ("Asia/Ho_Chi_Minh", "Ho_Chi_Minh"), - ("Asia/Hong_Kong", "Hong_Kong"), - ("Asia/Hovd", "Hovd"), - ("Asia/Irkutsk", "Irkutsk"), - ("Asia/Istanbul", "Istanbul"), - ("Asia/Jakarta", "Jakarta"), - ("Asia/Jayapura", "Jayapura"), - ("Asia/Jerusalem", "Jerusalem"), - ("Asia/Kabul", "Kabul"), - ("Asia/Kamchatka", "Kamchatka"), - ("Asia/Karachi", "Karachi"), - ("Asia/Kashgar", "Kashgar"), - ("Asia/Kathmandu", "Kathmandu"), - ("Asia/Katmandu", "Katmandu"), - ("Asia/Khandyga", "Khandyga"), - ("Asia/Kolkata", "Kolkata"), - ("Asia/Krasnoyarsk", "Krasnoyarsk"), - ("Asia/Kuala_Lumpur", "Kuala_Lumpur"), - ("Asia/Kuching", "Kuching"), - ("Asia/Kuwait", "Kuwait"), - ("Asia/Macao", "Macao"), - ("Asia/Macau", "Macau"), - ("Asia/Magadan", "Magadan"), - ("Asia/Makassar", "Makassar"), - ("Asia/Manila", "Manila"), - ("Asia/Muscat", "Muscat"), - ("Asia/Nicosia", "Nicosia"), - ("Asia/Novokuznetsk", "Novokuznetsk"), - ("Asia/Novosibirsk", "Novosibirsk"), - ("Asia/Omsk", "Omsk"), - ("Asia/Oral", "Oral"), - ("Asia/Phnom_Penh", "Phnom_Penh"), - ("Asia/Pontianak", "Pontianak"), - ("Asia/Pyongyang", "Pyongyang"), - ("Asia/Qatar", "Qatar"), - ("Asia/Qostanay", "Qostanay"), - ("Asia/Qyzylorda", "Qyzylorda"), - ("Asia/Rangoon", "Rangoon"), - ("Asia/Riyadh", "Riyadh"), - ("Asia/Saigon", "Saigon"), - ("Asia/Sakhalin", "Sakhalin"), - ("Asia/Samarkand", "Samarkand"), - ("Asia/Seoul", "Seoul"), - ("Asia/Shanghai", "Shanghai"), - ("Asia/Singapore", "Singapore"), - ("Asia/Srednekolymsk", "Srednekolymsk"), - ("Asia/Taipei", "Taipei"), - ("Asia/Tashkent", "Tashkent"), - ("Asia/Tbilisi", "Tbilisi"), - ("Asia/Tehran", "Tehran"), - ("Asia/Tel_Aviv", "Tel_Aviv"), - ("Asia/Thimbu", "Thimbu"), - ("Asia/Thimphu", "Thimphu"), - ("Asia/Tokyo", "Tokyo"), - ("Asia/Tomsk", "Tomsk"), - ("Asia/Ujung_Pandang", "Ujung_Pandang"), - ("Asia/Ulaanbaatar", "Ulaanbaatar"), - ("Asia/Ulan_Bator", "Ulan_Bator"), - ("Asia/Urumqi", "Urumqi"), - ("Asia/Ust-Nera", "Ust-Nera"), - ("Asia/Vientiane", "Vientiane"), - ("Asia/Vladivostok", "Vladivostok"), - ("Asia/Yakutsk", "Yakutsk"), - ("Asia/Yangon", "Yangon"), - ("Asia/Yekaterinburg", "Yekaterinburg"), - ("Asia/Yerevan", "Yerevan"), - ], - ), - ( - "Atlantic", - [ - ("Atlantic/Azores", "Azores"), - ("Atlantic/Bermuda", "Bermuda"), - ("Atlantic/Canary", "Canary"), - ("Atlantic/Cape_Verde", "Cape_Verde"), - ("Atlantic/Faeroe", "Faeroe"), - ("Atlantic/Faroe", "Faroe"), - ("Atlantic/Jan_Mayen", "Jan_Mayen"), - ("Atlantic/Madeira", "Madeira"), - ("Atlantic/Reykjavik", "Reykjavik"), - ("Atlantic/South_Georgia", "South_Georgia"), - ("Atlantic/St_Helena", "St_Helena"), - ("Atlantic/Stanley", "Stanley"), - ], - ), - ( - "Australia", - [ - ("Australia/ACT", "ACT"), - ("Australia/Adelaide", "Adelaide"), - ("Australia/Brisbane", "Brisbane"), - ("Australia/Broken_Hill", "Broken_Hill"), - ("Australia/Canberra", "Canberra"), - ("Australia/Currie", "Currie"), - ("Australia/Darwin", "Darwin"), - ("Australia/Eucla", "Eucla"), - ("Australia/Hobart", "Hobart"), - ("Australia/LHI", "LHI"), - ("Australia/Lindeman", "Lindeman"), - ("Australia/Lord_Howe", "Lord_Howe"), - ("Australia/Melbourne", "Melbourne"), - ("Australia/NSW", "NSW"), - ("Australia/North", "North"), - ("Australia/Perth", "Perth"), - ("Australia/Queensland", "Queensland"), - ("Australia/South", "South"), - ("Australia/Sydney", "Sydney"), - ("Australia/Tasmania", "Tasmania"), - ("Australia/Victoria", "Victoria"), - ("Australia/West", "West"), - ("Australia/Yancowinna", "Yancowinna"), - ], - ), - ( - "Brazil", - [ - ("Brazil/Acre", "Acre"), - ("Brazil/DeNoronha", "DeNoronha"), - ("Brazil/East", "East"), - ("Brazil/West", "West"), - ], - ), - ( - "Canada", - [ - ("Canada/Atlantic", "Atlantic"), - ("Canada/Central", "Central"), - ("Canada/Eastern", "Eastern"), - ("Canada/Mountain", "Mountain"), - ("Canada/Newfoundland", "Newfoundland"), - ("Canada/Pacific", "Pacific"), - ("Canada/Saskatchewan", "Saskatchewan"), - ("Canada/Yukon", "Yukon"), - ], - ), - ( - "Chile", - [ - ("Chile/Continental", "Continental"), - ("Chile/EasterIsland", "EasterIsland"), - ], - ), - ( - "Etc", - [ - ("Etc/Greenwich", "Greenwich"), - ("Etc/UCT", "UCT"), - ("Etc/UTC", "UTC"), - ("Etc/Universal", "Universal"), - ("Etc/Zulu", "Zulu"), - ], - ), - ( - "Europe", - [ - ("Europe/Amsterdam", "Amsterdam"), - ("Europe/Andorra", "Andorra"), - ("Europe/Astrakhan", "Astrakhan"), - ("Europe/Athens", "Athens"), - ("Europe/Belfast", "Belfast"), - ("Europe/Belgrade", "Belgrade"), - ("Europe/Berlin", "Berlin"), - ("Europe/Bratislava", "Bratislava"), - ("Europe/Brussels", "Brussels"), - ("Europe/Bucharest", "Bucharest"), - ("Europe/Budapest", "Budapest"), - ("Europe/Busingen", "Busingen"), - ("Europe/Chisinau", "Chisinau"), - ("Europe/Copenhagen", "Copenhagen"), - ("Europe/Dublin", "Dublin"), - ("Europe/Gibraltar", "Gibraltar"), - ("Europe/Guernsey", "Guernsey"), - ("Europe/Helsinki", "Helsinki"), - ("Europe/Isle_of_Man", "Isle_of_Man"), - ("Europe/Istanbul", "Istanbul"), - ("Europe/Jersey", "Jersey"), - ("Europe/Kaliningrad", "Kaliningrad"), - ("Europe/Kiev", "Kiev"), - ("Europe/Kirov", "Kirov"), - ("Europe/Lisbon", "Lisbon"), - ("Europe/Ljubljana", "Ljubljana"), - ("Europe/London", "London"), - ("Europe/Luxembourg", "Luxembourg"), - ("Europe/Madrid", "Madrid"), - ("Europe/Malta", "Malta"), - ("Europe/Mariehamn", "Mariehamn"), - ("Europe/Minsk", "Minsk"), - ("Europe/Monaco", "Monaco"), - ("Europe/Moscow", "Moscow"), - ("Europe/Nicosia", "Nicosia"), - ("Europe/Oslo", "Oslo"), - ("Europe/Paris", "Paris"), - ("Europe/Podgorica", "Podgorica"), - ("Europe/Prague", "Prague"), - ("Europe/Riga", "Riga"), - ("Europe/Rome", "Rome"), - ("Europe/Samara", "Samara"), - ("Europe/San_Marino", "San_Marino"), - ("Europe/Sarajevo", "Sarajevo"), - ("Europe/Saratov", "Saratov"), - ("Europe/Simferopol", "Simferopol"), - ("Europe/Skopje", "Skopje"), - ("Europe/Sofia", "Sofia"), - ("Europe/Stockholm", "Stockholm"), - ("Europe/Tallinn", "Tallinn"), - ("Europe/Tirane", "Tirane"), - ("Europe/Tiraspol", "Tiraspol"), - ("Europe/Ulyanovsk", "Ulyanovsk"), - ("Europe/Uzhgorod", "Uzhgorod"), - ("Europe/Vaduz", "Vaduz"), - ("Europe/Vatican", "Vatican"), - ("Europe/Vienna", "Vienna"), - ("Europe/Vilnius", "Vilnius"), - ("Europe/Volgograd", "Volgograd"), - ("Europe/Warsaw", "Warsaw"), - ("Europe/Zagreb", "Zagreb"), - ("Europe/Zaporozhye", "Zaporozhye"), - ("Europe/Zurich", "Zurich"), - ], - ), - ( - "Indian", - [ - ("Indian/Antananarivo", "Antananarivo"), - ("Indian/Chagos", "Chagos"), - ("Indian/Christmas", "Christmas"), - ("Indian/Cocos", "Cocos"), - ("Indian/Comoro", "Comoro"), - ("Indian/Kerguelen", "Kerguelen"), - ("Indian/Mahe", "Mahe"), - ("Indian/Maldives", "Maldives"), - ("Indian/Mauritius", "Mauritius"), - ("Indian/Mayotte", "Mayotte"), - ("Indian/Reunion", "Reunion"), - ], - ), - ( - "Mexico", - [ - ("Mexico/BajaNorte", "BajaNorte"), - ("Mexico/BajaSur", "BajaSur"), - ("Mexico/General", "General"), - ], - ), - ( - "Other", - [ - ("CET", "CET"), - ("CST6CDT", "CST6CDT"), - ("Cuba", "Cuba"), - ("EET", "EET"), - ("EST", "EST"), - ("EST5EDT", "EST5EDT"), - ("Egypt", "Egypt"), - ("Eire", "Eire"), - ("GB", "GB"), - ("GB-Eire", "GB-Eire"), - ("Greenwich", "Greenwich"), - ("HST", "HST"), - ("Hongkong", "Hongkong"), - ("Iceland", "Iceland"), - ("Iran", "Iran"), - ("Israel", "Israel"), - ("Jamaica", "Jamaica"), - ("Japan", "Japan"), - ("Kwajalein", "Kwajalein"), - ("Libya", "Libya"), - ("MET", "MET"), - ("MST", "MST"), - ("MST7MDT", "MST7MDT"), - ("NZ", "NZ"), - ("NZ-CHAT", "NZ-CHAT"), - ("Navajo", "Navajo"), - ("PRC", "PRC"), - ("PST8PDT", "PST8PDT"), - ("Poland", "Poland"), - ("Portugal", "Portugal"), - ("ROC", "ROC"), - ("ROK", "ROK"), - ("Singapore", "Singapore"), - ("Turkey", "Turkey"), - ("UCT", "UCT"), - ("UTC", "UTC"), - ("Universal", "Universal"), - ("W-SU", "W-SU"), - ("WET", "WET"), - ("Zulu", "Zulu"), - ], - ), - ( - "Pacific", - [ - ("Pacific/Apia", "Apia"), - ("Pacific/Auckland", "Auckland"), - ("Pacific/Bougainville", "Bougainville"), - ("Pacific/Chatham", "Chatham"), - ("Pacific/Chuuk", "Chuuk"), - ("Pacific/Easter", "Easter"), - ("Pacific/Efate", "Efate"), - ("Pacific/Enderbury", "Enderbury"), - ("Pacific/Fakaofo", "Fakaofo"), - ("Pacific/Fiji", "Fiji"), - ("Pacific/Funafuti", "Funafuti"), - ("Pacific/Galapagos", "Galapagos"), - ("Pacific/Gambier", "Gambier"), - ("Pacific/Guadalcanal", "Guadalcanal"), - ("Pacific/Guam", "Guam"), - ("Pacific/Honolulu", "Honolulu"), - ("Pacific/Johnston", "Johnston"), - ("Pacific/Kiritimati", "Kiritimati"), - ("Pacific/Kosrae", "Kosrae"), - ("Pacific/Kwajalein", "Kwajalein"), - ("Pacific/Majuro", "Majuro"), - ("Pacific/Marquesas", "Marquesas"), - ("Pacific/Midway", "Midway"), - ("Pacific/Nauru", "Nauru"), - ("Pacific/Niue", "Niue"), - ("Pacific/Norfolk", "Norfolk"), - ("Pacific/Noumea", "Noumea"), - ("Pacific/Pago_Pago", "Pago_Pago"), - ("Pacific/Palau", "Palau"), - ("Pacific/Pitcairn", "Pitcairn"), - ("Pacific/Pohnpei", "Pohnpei"), - ("Pacific/Ponape", "Ponape"), - ("Pacific/Port_Moresby", "Port_Moresby"), - ("Pacific/Rarotonga", "Rarotonga"), - ("Pacific/Saipan", "Saipan"), - ("Pacific/Samoa", "Samoa"), - ("Pacific/Tahiti", "Tahiti"), - ("Pacific/Tarawa", "Tarawa"), - ("Pacific/Tongatapu", "Tongatapu"), - ("Pacific/Truk", "Truk"), - ("Pacific/Wake", "Wake"), - ("Pacific/Wallis", "Wallis"), - ("Pacific/Yap", "Yap"), - ], - ), - ( - "US", - [ - ("US/Alaska", "Alaska"), - ("US/Aleutian", "Aleutian"), - ("US/Arizona", "Arizona"), - ("US/Central", "Central"), - ("US/East-Indiana", "East-Indiana"), - ("US/Eastern", "Eastern"), - ("US/Hawaii", "Hawaii"), - ("US/Indiana-Starke", "Indiana-Starke"), - ("US/Michigan", "Michigan"), - ("US/Mountain", "Mountain"), - ("US/Pacific", "Pacific"), - ("US/Samoa", "Samoa"), - ], - ), - ], - default="Asia/Ho_Chi_Minh", - max_length=50, - verbose_name="location", - ), - ), - ] diff --git a/judge/migrations/0106_friend.py b/judge/migrations/0106_friend.py deleted file mode 100644 index 1235013..0000000 --- a/judge/migrations/0106_friend.py +++ /dev/null @@ -1,37 +0,0 @@ -# Generated by Django 2.2.12 on 2020-06-23 03:15 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0105_auto_20200523_0756"), - ] - - operations = [ - migrations.CreateModel( - name="Friend", - fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "current_user", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="following_users", - to="judge.Profile", - ), - ), - ("users", models.ManyToManyField(to="judge.Profile")), - ], - ), - ] diff --git a/judge/migrations/0107_notification.py b/judge/migrations/0107_notification.py deleted file mode 100644 index 9539711..0000000 --- a/judge/migrations/0107_notification.py +++ /dev/null @@ -1,51 +0,0 @@ -# Generated by Django 2.2.12 on 2020-07-03 01:16 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0106_friend"), - ] - - operations = [ - migrations.CreateModel( - name="Notification", - fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "time", - models.DateTimeField(auto_now_add=True, verbose_name="posted time"), - ), - ("read", models.BooleanField(default=False, verbose_name="read")), - ("category", models.CharField(max_length=10, verbose_name="category")), - ( - "comment", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="judge.Comment", - verbose_name="comment", - ), - ), - ( - "owner", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="notifications", - to="judge.Profile", - verbose_name="owner", - ), - ), - ], - ), - ] diff --git a/judge/migrations/0108_submission_judged_date.py b/judge/migrations/0108_submission_judged_date.py deleted file mode 100644 index e58ca6b..0000000 --- a/judge/migrations/0108_submission_judged_date.py +++ /dev/null @@ -1,20 +0,0 @@ -# Generated by Django 2.2.12 on 2020-07-19 21:07 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0107_notification"), - ] - - operations = [ - migrations.AddField( - model_name="submission", - name="judged_date", - field=models.DateTimeField( - default=None, null=True, verbose_name="submission judge time" - ), - ), - ] diff --git a/judge/migrations/0109_auto_20201017_1151.py b/judge/migrations/0109_auto_20201017_1151.py deleted file mode 100644 index 3e94df0..0000000 --- a/judge/migrations/0109_auto_20201017_1151.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 2.2.12 on 2020-10-17 04:51 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0108_submission_judged_date"), - ] - - operations = [ - migrations.AddField( - model_name="notification", - name="html_link", - field=models.TextField( - default="", - max_length=1000, - verbose_name="html link to comments, used for non-comments", - ), - ), - migrations.AlterField( - model_name="notification", - name="comment", - field=models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="judge.Comment", - verbose_name="comment", - ), - ), - ] diff --git a/judge/migrations/0110_notification_author.py b/judge/migrations/0110_notification_author.py deleted file mode 100644 index 367c96a..0000000 --- a/judge/migrations/0110_notification_author.py +++ /dev/null @@ -1,24 +0,0 @@ -# Generated by Django 2.2.12 on 2020-10-17 05:10 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0109_auto_20201017_1151"), - ] - - operations = [ - migrations.AddField( - model_name="notification", - name="author", - field=models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="judge.Profile", - verbose_name="who trigger, used for non-comment", - ), - ), - ] diff --git a/judge/migrations/0111_contest_decimal_points.py b/judge/migrations/0111_contest_decimal_points.py deleted file mode 100644 index b83e3b5..0000000 --- a/judge/migrations/0111_contest_decimal_points.py +++ /dev/null @@ -1,32 +0,0 @@ -# Generated by Django 2.2.12 on 2020-10-26 19:51 - -import django.core.validators -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0110_notification_author"), - ] - - operations = [ - migrations.AddField( - model_name="contest", - name="points_precision", - field=models.IntegerField( - default=2, - help_text="Number of digits to round points to.", - validators=[ - django.core.validators.MinValueValidator(0), - django.core.validators.MaxValueValidator(10), - ], - verbose_name="precision points", - ), - ), - migrations.AlterField( - model_name="contestparticipation", - name="score", - field=models.FloatField(db_index=True, default=0, verbose_name="score"), - ), - ] diff --git a/judge/migrations/0112_contest_view_contest_scoreboard.py b/judge/migrations/0112_contest_view_contest_scoreboard.py deleted file mode 100644 index 00e2da4..0000000 --- a/judge/migrations/0112_contest_view_contest_scoreboard.py +++ /dev/null @@ -1,24 +0,0 @@ -# Generated by Django 2.2.17 on 2020-12-28 01:51 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0111_contest_decimal_points"), - ] - - operations = [ - migrations.AddField( - model_name="contest", - name="view_contest_scoreboard", - field=models.ManyToManyField( - blank=True, - help_text="These users will be able to view the scoreboard.", - related_name="view_contest_scoreboard", - to="judge.Profile", - verbose_name="view contest scoreboard", - ), - ), - ] diff --git a/judge/migrations/0113_auto_20201228_0911.py b/judge/migrations/0113_auto_20201228_0911.py deleted file mode 100644 index 36d7dda..0000000 --- a/judge/migrations/0113_auto_20201228_0911.py +++ /dev/null @@ -1,31 +0,0 @@ -# Generated by Django 2.2.17 on 2020-12-28 02:11 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0112_contest_view_contest_scoreboard"), - ] - - operations = [ - migrations.AlterModelOptions( - name="contest", - options={ - "permissions": ( - ("see_private_contest", "See private contests"), - ("edit_own_contest", "Edit own contests"), - ("edit_all_contest", "Edit all contests"), - ("clone_contest", "Clone contest"), - ("moss_contest", "MOSS contest"), - ("contest_rating", "Rate contests"), - ("contest_access_code", "Contest access codes"), - ("create_private_contest", "Create private contests"), - ("change_contest_visibility", "Change contest visibility"), - ), - "verbose_name": "contest", - "verbose_name_plural": "contests", - }, - ), - ] diff --git a/judge/migrations/0114_auto_20201228_1041.py b/judge/migrations/0114_auto_20201228_1041.py deleted file mode 100644 index 609c5d4..0000000 --- a/judge/migrations/0114_auto_20201228_1041.py +++ /dev/null @@ -1,30 +0,0 @@ -# Generated by Django 2.2.17 on 2020-12-28 03:41 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0113_auto_20201228_0911"), - ] - - operations = [ - migrations.AddField( - model_name="blogpost", - name="is_organization_private", - field=models.BooleanField( - default=False, verbose_name="private to organizations" - ), - ), - migrations.AddField( - model_name="blogpost", - name="organizations", - field=models.ManyToManyField( - blank=True, - help_text="If private, only these organizations may see the blog post.", - to="judge.Organization", - verbose_name="organizations", - ), - ), - ] diff --git a/judge/migrations/0115_auto_20210525_0222.py b/judge/migrations/0115_auto_20210525_0222.py deleted file mode 100644 index 52490c2..0000000 --- a/judge/migrations/0115_auto_20210525_0222.py +++ /dev/null @@ -1,110 +0,0 @@ -# Generated by Django 2.2.17 on 2021-05-24 19:22 - -from django.db import migrations, models - - -def hide_scoreboard_eq_true(apps, schema_editor): - Contest = apps.get_model("judge", "Contest") - Contest.objects.filter(hide_scoreboard=True).update(scoreboard_visibility="C") - - -def scoreboard_visibility_eq_contest(apps, schema_editor): - Contest = apps.get_model("judge", "Contest") - Contest.objects.filter(scoreboard_visibility__in=("C", "P")).update( - hide_scoreboard=True - ) - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0114_auto_20201228_1041"), - ] - - operations = [ - migrations.AlterModelOptions( - name="contest", - options={ - "permissions": ( - ("see_private_contest", "See private contests"), - ("edit_own_contest", "Edit own contests"), - ("edit_all_contest", "Edit all contests"), - ("clone_contest", "Clone contest"), - ("moss_contest", "MOSS contest"), - ("contest_rating", "Rate contests"), - ("contest_access_code", "Contest access codes"), - ("create_private_contest", "Create private contests"), - ("change_contest_visibility", "Change contest visibility"), - ("contest_problem_label", "Edit contest problem label script"), - ), - "verbose_name": "contest", - "verbose_name_plural": "contests", - }, - ), - migrations.RemoveField( - model_name="contest", - name="hide_scoreboard", - ), - migrations.RemoveField( - model_name="contest", - name="organizers", - ), - migrations.AddField( - model_name="contest", - name="authors", - field=models.ManyToManyField( - help_text="These users will be able to edit the contest.", - related_name="_contest_authors_+", - to="judge.Profile", - ), - ), - migrations.AddField( - model_name="contest", - name="curators", - field=models.ManyToManyField( - blank=True, - help_text="These users will be able to edit the contest, but will not be listed as authors.", - related_name="_contest_curators_+", - to="judge.Profile", - ), - ), - migrations.AddField( - model_name="contest", - name="problem_label_script", - field=models.TextField( - blank=True, - help_text="A custom Lua function to generate problem labels. Requires a single function with an integer parameter, the zero-indexed contest problem index, and returns a string, the label.", - verbose_name="contest problem label script", - ), - ), - migrations.AddField( - model_name="contest", - name="scoreboard_visibility", - field=models.CharField( - choices=[ - ("V", "Visible"), - ("C", "Hidden for duration of contest"), - ("P", "Hidden for duration of participation"), - ], - default="V", - help_text="Scoreboard visibility through the duration of the contest", - max_length=1, - verbose_name="scoreboard visibility", - ), - ), - migrations.AddField( - model_name="contest", - name="testers", - field=models.ManyToManyField( - blank=True, - help_text="These users will be able to view the contest, but not edit it.", - related_name="_contest_testers_+", - to="judge.Profile", - ), - ), - migrations.AddField( - model_name="contestparticipation", - name="tiebreaker", - field=models.FloatField(default=0.0, verbose_name="tie-breaking field"), - ), - ] diff --git a/judge/migrations/0116_auto_20211011_0645.py b/judge/migrations/0116_auto_20211011_0645.py deleted file mode 100644 index 79eaa8d..0000000 --- a/judge/migrations/0116_auto_20211011_0645.py +++ /dev/null @@ -1,30 +0,0 @@ -# Generated by Django 2.2.17 on 2021-10-10 23:45 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0115_auto_20210525_0222"), - ] - - operations = [ - migrations.AlterField( - model_name="contest", - name="format_name", - field=models.CharField( - choices=[ - ("atcoder", "AtCoder"), - ("default", "Default"), - ("ecoo", "ECOO"), - ("icpc", "ICPC"), - ("ioi", "IOI"), - ], - default="default", - help_text="The contest format module to use.", - max_length=32, - verbose_name="contest format", - ), - ), - ] diff --git a/judge/migrations/0117_auto_20211209_0612.py b/judge/migrations/0117_auto_20211209_0612.py deleted file mode 100644 index 88c170f..0000000 --- a/judge/migrations/0117_auto_20211209_0612.py +++ /dev/null @@ -1,676 +0,0 @@ -# Generated by Django 2.2.25 on 2021-12-08 23:12 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0116_auto_20211011_0645"), - ] - - operations = [ - migrations.AlterField( - model_name="profile", - name="timezone", - field=models.CharField( - choices=[ - ( - "Africa", - [ - ("Africa/Abidjan", "Abidjan"), - ("Africa/Accra", "Accra"), - ("Africa/Addis_Ababa", "Addis_Ababa"), - ("Africa/Algiers", "Algiers"), - ("Africa/Asmara", "Asmara"), - ("Africa/Asmera", "Asmera"), - ("Africa/Bamako", "Bamako"), - ("Africa/Bangui", "Bangui"), - ("Africa/Banjul", "Banjul"), - ("Africa/Bissau", "Bissau"), - ("Africa/Blantyre", "Blantyre"), - ("Africa/Brazzaville", "Brazzaville"), - ("Africa/Bujumbura", "Bujumbura"), - ("Africa/Cairo", "Cairo"), - ("Africa/Casablanca", "Casablanca"), - ("Africa/Ceuta", "Ceuta"), - ("Africa/Conakry", "Conakry"), - ("Africa/Dakar", "Dakar"), - ("Africa/Dar_es_Salaam", "Dar_es_Salaam"), - ("Africa/Djibouti", "Djibouti"), - ("Africa/Douala", "Douala"), - ("Africa/El_Aaiun", "El_Aaiun"), - ("Africa/Freetown", "Freetown"), - ("Africa/Gaborone", "Gaborone"), - ("Africa/Harare", "Harare"), - ("Africa/Johannesburg", "Johannesburg"), - ("Africa/Juba", "Juba"), - ("Africa/Kampala", "Kampala"), - ("Africa/Khartoum", "Khartoum"), - ("Africa/Kigali", "Kigali"), - ("Africa/Kinshasa", "Kinshasa"), - ("Africa/Lagos", "Lagos"), - ("Africa/Libreville", "Libreville"), - ("Africa/Lome", "Lome"), - ("Africa/Luanda", "Luanda"), - ("Africa/Lubumbashi", "Lubumbashi"), - ("Africa/Lusaka", "Lusaka"), - ("Africa/Malabo", "Malabo"), - ("Africa/Maputo", "Maputo"), - ("Africa/Maseru", "Maseru"), - ("Africa/Mbabane", "Mbabane"), - ("Africa/Mogadishu", "Mogadishu"), - ("Africa/Monrovia", "Monrovia"), - ("Africa/Nairobi", "Nairobi"), - ("Africa/Ndjamena", "Ndjamena"), - ("Africa/Niamey", "Niamey"), - ("Africa/Nouakchott", "Nouakchott"), - ("Africa/Ouagadougou", "Ouagadougou"), - ("Africa/Porto-Novo", "Porto-Novo"), - ("Africa/Sao_Tome", "Sao_Tome"), - ("Africa/Timbuktu", "Timbuktu"), - ("Africa/Tripoli", "Tripoli"), - ("Africa/Tunis", "Tunis"), - ("Africa/Windhoek", "Windhoek"), - ], - ), - ( - "America", - [ - ("America/Adak", "Adak"), - ("America/Anchorage", "Anchorage"), - ("America/Anguilla", "Anguilla"), - ("America/Antigua", "Antigua"), - ("America/Araguaina", "Araguaina"), - ( - "America/Argentina/Buenos_Aires", - "Argentina/Buenos_Aires", - ), - ("America/Argentina/Catamarca", "Argentina/Catamarca"), - ( - "America/Argentina/ComodRivadavia", - "Argentina/ComodRivadavia", - ), - ("America/Argentina/Cordoba", "Argentina/Cordoba"), - ("America/Argentina/Jujuy", "Argentina/Jujuy"), - ("America/Argentina/La_Rioja", "Argentina/La_Rioja"), - ("America/Argentina/Mendoza", "Argentina/Mendoza"), - ( - "America/Argentina/Rio_Gallegos", - "Argentina/Rio_Gallegos", - ), - ("America/Argentina/Salta", "Argentina/Salta"), - ("America/Argentina/San_Juan", "Argentina/San_Juan"), - ("America/Argentina/San_Luis", "Argentina/San_Luis"), - ("America/Argentina/Tucuman", "Argentina/Tucuman"), - ("America/Argentina/Ushuaia", "Argentina/Ushuaia"), - ("America/Aruba", "Aruba"), - ("America/Asuncion", "Asuncion"), - ("America/Atikokan", "Atikokan"), - ("America/Atka", "Atka"), - ("America/Bahia", "Bahia"), - ("America/Bahia_Banderas", "Bahia_Banderas"), - ("America/Barbados", "Barbados"), - ("America/Belem", "Belem"), - ("America/Belize", "Belize"), - ("America/Blanc-Sablon", "Blanc-Sablon"), - ("America/Boa_Vista", "Boa_Vista"), - ("America/Bogota", "Bogota"), - ("America/Boise", "Boise"), - ("America/Buenos_Aires", "Buenos_Aires"), - ("America/Cambridge_Bay", "Cambridge_Bay"), - ("America/Campo_Grande", "Campo_Grande"), - ("America/Cancun", "Cancun"), - ("America/Caracas", "Caracas"), - ("America/Catamarca", "Catamarca"), - ("America/Cayenne", "Cayenne"), - ("America/Cayman", "Cayman"), - ("America/Chicago", "Chicago"), - ("America/Chihuahua", "Chihuahua"), - ("America/Coral_Harbour", "Coral_Harbour"), - ("America/Cordoba", "Cordoba"), - ("America/Costa_Rica", "Costa_Rica"), - ("America/Creston", "Creston"), - ("America/Cuiaba", "Cuiaba"), - ("America/Curacao", "Curacao"), - ("America/Danmarkshavn", "Danmarkshavn"), - ("America/Dawson", "Dawson"), - ("America/Dawson_Creek", "Dawson_Creek"), - ("America/Denver", "Denver"), - ("America/Detroit", "Detroit"), - ("America/Dominica", "Dominica"), - ("America/Edmonton", "Edmonton"), - ("America/Eirunepe", "Eirunepe"), - ("America/El_Salvador", "El_Salvador"), - ("America/Ensenada", "Ensenada"), - ("America/Fort_Nelson", "Fort_Nelson"), - ("America/Fort_Wayne", "Fort_Wayne"), - ("America/Fortaleza", "Fortaleza"), - ("America/Glace_Bay", "Glace_Bay"), - ("America/Godthab", "Godthab"), - ("America/Goose_Bay", "Goose_Bay"), - ("America/Grand_Turk", "Grand_Turk"), - ("America/Grenada", "Grenada"), - ("America/Guadeloupe", "Guadeloupe"), - ("America/Guatemala", "Guatemala"), - ("America/Guayaquil", "Guayaquil"), - ("America/Guyana", "Guyana"), - ("America/Halifax", "Halifax"), - ("America/Havana", "Havana"), - ("America/Hermosillo", "Hermosillo"), - ("America/Indiana/Indianapolis", "Indiana/Indianapolis"), - ("America/Indiana/Knox", "Indiana/Knox"), - ("America/Indiana/Marengo", "Indiana/Marengo"), - ("America/Indiana/Petersburg", "Indiana/Petersburg"), - ("America/Indiana/Tell_City", "Indiana/Tell_City"), - ("America/Indiana/Vevay", "Indiana/Vevay"), - ("America/Indiana/Vincennes", "Indiana/Vincennes"), - ("America/Indiana/Winamac", "Indiana/Winamac"), - ("America/Indianapolis", "Indianapolis"), - ("America/Inuvik", "Inuvik"), - ("America/Iqaluit", "Iqaluit"), - ("America/Jamaica", "Jamaica"), - ("America/Jujuy", "Jujuy"), - ("America/Juneau", "Juneau"), - ("America/Kentucky/Louisville", "Kentucky/Louisville"), - ("America/Kentucky/Monticello", "Kentucky/Monticello"), - ("America/Knox_IN", "Knox_IN"), - ("America/Kralendijk", "Kralendijk"), - ("America/La_Paz", "La_Paz"), - ("America/Lima", "Lima"), - ("America/Los_Angeles", "Los_Angeles"), - ("America/Louisville", "Louisville"), - ("America/Lower_Princes", "Lower_Princes"), - ("America/Maceio", "Maceio"), - ("America/Managua", "Managua"), - ("America/Manaus", "Manaus"), - ("America/Marigot", "Marigot"), - ("America/Martinique", "Martinique"), - ("America/Matamoros", "Matamoros"), - ("America/Mazatlan", "Mazatlan"), - ("America/Mendoza", "Mendoza"), - ("America/Menominee", "Menominee"), - ("America/Merida", "Merida"), - ("America/Metlakatla", "Metlakatla"), - ("America/Mexico_City", "Mexico_City"), - ("America/Miquelon", "Miquelon"), - ("America/Moncton", "Moncton"), - ("America/Monterrey", "Monterrey"), - ("America/Montevideo", "Montevideo"), - ("America/Montreal", "Montreal"), - ("America/Montserrat", "Montserrat"), - ("America/Nassau", "Nassau"), - ("America/New_York", "New_York"), - ("America/Nipigon", "Nipigon"), - ("America/Nome", "Nome"), - ("America/Noronha", "Noronha"), - ("America/North_Dakota/Beulah", "North_Dakota/Beulah"), - ("America/North_Dakota/Center", "North_Dakota/Center"), - ( - "America/North_Dakota/New_Salem", - "North_Dakota/New_Salem", - ), - ("America/Nuuk", "Nuuk"), - ("America/Ojinaga", "Ojinaga"), - ("America/Panama", "Panama"), - ("America/Pangnirtung", "Pangnirtung"), - ("America/Paramaribo", "Paramaribo"), - ("America/Phoenix", "Phoenix"), - ("America/Port-au-Prince", "Port-au-Prince"), - ("America/Port_of_Spain", "Port_of_Spain"), - ("America/Porto_Acre", "Porto_Acre"), - ("America/Porto_Velho", "Porto_Velho"), - ("America/Puerto_Rico", "Puerto_Rico"), - ("America/Punta_Arenas", "Punta_Arenas"), - ("America/Rainy_River", "Rainy_River"), - ("America/Rankin_Inlet", "Rankin_Inlet"), - ("America/Recife", "Recife"), - ("America/Regina", "Regina"), - ("America/Resolute", "Resolute"), - ("America/Rio_Branco", "Rio_Branco"), - ("America/Rosario", "Rosario"), - ("America/Santa_Isabel", "Santa_Isabel"), - ("America/Santarem", "Santarem"), - ("America/Santiago", "Santiago"), - ("America/Santo_Domingo", "Santo_Domingo"), - ("America/Sao_Paulo", "Sao_Paulo"), - ("America/Scoresbysund", "Scoresbysund"), - ("America/Shiprock", "Shiprock"), - ("America/Sitka", "Sitka"), - ("America/St_Barthelemy", "St_Barthelemy"), - ("America/St_Johns", "St_Johns"), - ("America/St_Kitts", "St_Kitts"), - ("America/St_Lucia", "St_Lucia"), - ("America/St_Thomas", "St_Thomas"), - ("America/St_Vincent", "St_Vincent"), - ("America/Swift_Current", "Swift_Current"), - ("America/Tegucigalpa", "Tegucigalpa"), - ("America/Thule", "Thule"), - ("America/Thunder_Bay", "Thunder_Bay"), - ("America/Tijuana", "Tijuana"), - ("America/Toronto", "Toronto"), - ("America/Tortola", "Tortola"), - ("America/Vancouver", "Vancouver"), - ("America/Virgin", "Virgin"), - ("America/Whitehorse", "Whitehorse"), - ("America/Winnipeg", "Winnipeg"), - ("America/Yakutat", "Yakutat"), - ("America/Yellowknife", "Yellowknife"), - ], - ), - ( - "Antarctica", - [ - ("Antarctica/Casey", "Casey"), - ("Antarctica/Davis", "Davis"), - ("Antarctica/DumontDUrville", "DumontDUrville"), - ("Antarctica/Macquarie", "Macquarie"), - ("Antarctica/Mawson", "Mawson"), - ("Antarctica/McMurdo", "McMurdo"), - ("Antarctica/Palmer", "Palmer"), - ("Antarctica/Rothera", "Rothera"), - ("Antarctica/South_Pole", "South_Pole"), - ("Antarctica/Syowa", "Syowa"), - ("Antarctica/Troll", "Troll"), - ("Antarctica/Vostok", "Vostok"), - ], - ), - ("Arctic", [("Arctic/Longyearbyen", "Longyearbyen")]), - ( - "Asia", - [ - ("Asia/Aden", "Aden"), - ("Asia/Almaty", "Almaty"), - ("Asia/Amman", "Amman"), - ("Asia/Anadyr", "Anadyr"), - ("Asia/Aqtau", "Aqtau"), - ("Asia/Aqtobe", "Aqtobe"), - ("Asia/Ashgabat", "Ashgabat"), - ("Asia/Ashkhabad", "Ashkhabad"), - ("Asia/Atyrau", "Atyrau"), - ("Asia/Baghdad", "Baghdad"), - ("Asia/Bahrain", "Bahrain"), - ("Asia/Baku", "Baku"), - ("Asia/Bangkok", "Bangkok"), - ("Asia/Barnaul", "Barnaul"), - ("Asia/Beirut", "Beirut"), - ("Asia/Bishkek", "Bishkek"), - ("Asia/Brunei", "Brunei"), - ("Asia/Calcutta", "Calcutta"), - ("Asia/Chita", "Chita"), - ("Asia/Choibalsan", "Choibalsan"), - ("Asia/Chongqing", "Chongqing"), - ("Asia/Chungking", "Chungking"), - ("Asia/Colombo", "Colombo"), - ("Asia/Dacca", "Dacca"), - ("Asia/Damascus", "Damascus"), - ("Asia/Dhaka", "Dhaka"), - ("Asia/Dili", "Dili"), - ("Asia/Dubai", "Dubai"), - ("Asia/Dushanbe", "Dushanbe"), - ("Asia/Famagusta", "Famagusta"), - ("Asia/Gaza", "Gaza"), - ("Asia/Harbin", "Harbin"), - ("Asia/Hebron", "Hebron"), - ("Asia/Ho_Chi_Minh", "Ho_Chi_Minh"), - ("Asia/Hong_Kong", "Hong_Kong"), - ("Asia/Hovd", "Hovd"), - ("Asia/Irkutsk", "Irkutsk"), - ("Asia/Istanbul", "Istanbul"), - ("Asia/Jakarta", "Jakarta"), - ("Asia/Jayapura", "Jayapura"), - ("Asia/Jerusalem", "Jerusalem"), - ("Asia/Kabul", "Kabul"), - ("Asia/Kamchatka", "Kamchatka"), - ("Asia/Karachi", "Karachi"), - ("Asia/Kashgar", "Kashgar"), - ("Asia/Kathmandu", "Kathmandu"), - ("Asia/Katmandu", "Katmandu"), - ("Asia/Khandyga", "Khandyga"), - ("Asia/Kolkata", "Kolkata"), - ("Asia/Krasnoyarsk", "Krasnoyarsk"), - ("Asia/Kuala_Lumpur", "Kuala_Lumpur"), - ("Asia/Kuching", "Kuching"), - ("Asia/Kuwait", "Kuwait"), - ("Asia/Macao", "Macao"), - ("Asia/Macau", "Macau"), - ("Asia/Magadan", "Magadan"), - ("Asia/Makassar", "Makassar"), - ("Asia/Manila", "Manila"), - ("Asia/Muscat", "Muscat"), - ("Asia/Nicosia", "Nicosia"), - ("Asia/Novokuznetsk", "Novokuznetsk"), - ("Asia/Novosibirsk", "Novosibirsk"), - ("Asia/Omsk", "Omsk"), - ("Asia/Oral", "Oral"), - ("Asia/Phnom_Penh", "Phnom_Penh"), - ("Asia/Pontianak", "Pontianak"), - ("Asia/Pyongyang", "Pyongyang"), - ("Asia/Qatar", "Qatar"), - ("Asia/Qostanay", "Qostanay"), - ("Asia/Qyzylorda", "Qyzylorda"), - ("Asia/Rangoon", "Rangoon"), - ("Asia/Riyadh", "Riyadh"), - ("Asia/Saigon", "Saigon"), - ("Asia/Sakhalin", "Sakhalin"), - ("Asia/Samarkand", "Samarkand"), - ("Asia/Seoul", "Seoul"), - ("Asia/Shanghai", "Shanghai"), - ("Asia/Singapore", "Singapore"), - ("Asia/Srednekolymsk", "Srednekolymsk"), - ("Asia/Taipei", "Taipei"), - ("Asia/Tashkent", "Tashkent"), - ("Asia/Tbilisi", "Tbilisi"), - ("Asia/Tehran", "Tehran"), - ("Asia/Tel_Aviv", "Tel_Aviv"), - ("Asia/Thimbu", "Thimbu"), - ("Asia/Thimphu", "Thimphu"), - ("Asia/Tokyo", "Tokyo"), - ("Asia/Tomsk", "Tomsk"), - ("Asia/Ujung_Pandang", "Ujung_Pandang"), - ("Asia/Ulaanbaatar", "Ulaanbaatar"), - ("Asia/Ulan_Bator", "Ulan_Bator"), - ("Asia/Urumqi", "Urumqi"), - ("Asia/Ust-Nera", "Ust-Nera"), - ("Asia/Vientiane", "Vientiane"), - ("Asia/Vladivostok", "Vladivostok"), - ("Asia/Yakutsk", "Yakutsk"), - ("Asia/Yangon", "Yangon"), - ("Asia/Yekaterinburg", "Yekaterinburg"), - ("Asia/Yerevan", "Yerevan"), - ], - ), - ( - "Atlantic", - [ - ("Atlantic/Azores", "Azores"), - ("Atlantic/Bermuda", "Bermuda"), - ("Atlantic/Canary", "Canary"), - ("Atlantic/Cape_Verde", "Cape_Verde"), - ("Atlantic/Faeroe", "Faeroe"), - ("Atlantic/Faroe", "Faroe"), - ("Atlantic/Jan_Mayen", "Jan_Mayen"), - ("Atlantic/Madeira", "Madeira"), - ("Atlantic/Reykjavik", "Reykjavik"), - ("Atlantic/South_Georgia", "South_Georgia"), - ("Atlantic/St_Helena", "St_Helena"), - ("Atlantic/Stanley", "Stanley"), - ], - ), - ( - "Australia", - [ - ("Australia/ACT", "ACT"), - ("Australia/Adelaide", "Adelaide"), - ("Australia/Brisbane", "Brisbane"), - ("Australia/Broken_Hill", "Broken_Hill"), - ("Australia/Canberra", "Canberra"), - ("Australia/Currie", "Currie"), - ("Australia/Darwin", "Darwin"), - ("Australia/Eucla", "Eucla"), - ("Australia/Hobart", "Hobart"), - ("Australia/LHI", "LHI"), - ("Australia/Lindeman", "Lindeman"), - ("Australia/Lord_Howe", "Lord_Howe"), - ("Australia/Melbourne", "Melbourne"), - ("Australia/NSW", "NSW"), - ("Australia/North", "North"), - ("Australia/Perth", "Perth"), - ("Australia/Queensland", "Queensland"), - ("Australia/South", "South"), - ("Australia/Sydney", "Sydney"), - ("Australia/Tasmania", "Tasmania"), - ("Australia/Victoria", "Victoria"), - ("Australia/West", "West"), - ("Australia/Yancowinna", "Yancowinna"), - ], - ), - ( - "Brazil", - [ - ("Brazil/Acre", "Acre"), - ("Brazil/DeNoronha", "DeNoronha"), - ("Brazil/East", "East"), - ("Brazil/West", "West"), - ], - ), - ( - "Canada", - [ - ("Canada/Atlantic", "Atlantic"), - ("Canada/Central", "Central"), - ("Canada/Eastern", "Eastern"), - ("Canada/Mountain", "Mountain"), - ("Canada/Newfoundland", "Newfoundland"), - ("Canada/Pacific", "Pacific"), - ("Canada/Saskatchewan", "Saskatchewan"), - ("Canada/Yukon", "Yukon"), - ], - ), - ( - "Chile", - [ - ("Chile/Continental", "Continental"), - ("Chile/EasterIsland", "EasterIsland"), - ], - ), - ( - "Etc", - [ - ("Etc/Greenwich", "Greenwich"), - ("Etc/UCT", "UCT"), - ("Etc/UTC", "UTC"), - ("Etc/Universal", "Universal"), - ("Etc/Zulu", "Zulu"), - ], - ), - ( - "Europe", - [ - ("Europe/Amsterdam", "Amsterdam"), - ("Europe/Andorra", "Andorra"), - ("Europe/Astrakhan", "Astrakhan"), - ("Europe/Athens", "Athens"), - ("Europe/Belfast", "Belfast"), - ("Europe/Belgrade", "Belgrade"), - ("Europe/Berlin", "Berlin"), - ("Europe/Bratislava", "Bratislava"), - ("Europe/Brussels", "Brussels"), - ("Europe/Bucharest", "Bucharest"), - ("Europe/Budapest", "Budapest"), - ("Europe/Busingen", "Busingen"), - ("Europe/Chisinau", "Chisinau"), - ("Europe/Copenhagen", "Copenhagen"), - ("Europe/Dublin", "Dublin"), - ("Europe/Gibraltar", "Gibraltar"), - ("Europe/Guernsey", "Guernsey"), - ("Europe/Helsinki", "Helsinki"), - ("Europe/Isle_of_Man", "Isle_of_Man"), - ("Europe/Istanbul", "Istanbul"), - ("Europe/Jersey", "Jersey"), - ("Europe/Kaliningrad", "Kaliningrad"), - ("Europe/Kiev", "Kiev"), - ("Europe/Kirov", "Kirov"), - ("Europe/Lisbon", "Lisbon"), - ("Europe/Ljubljana", "Ljubljana"), - ("Europe/London", "London"), - ("Europe/Luxembourg", "Luxembourg"), - ("Europe/Madrid", "Madrid"), - ("Europe/Malta", "Malta"), - ("Europe/Mariehamn", "Mariehamn"), - ("Europe/Minsk", "Minsk"), - ("Europe/Monaco", "Monaco"), - ("Europe/Moscow", "Moscow"), - ("Europe/Nicosia", "Nicosia"), - ("Europe/Oslo", "Oslo"), - ("Europe/Paris", "Paris"), - ("Europe/Podgorica", "Podgorica"), - ("Europe/Prague", "Prague"), - ("Europe/Riga", "Riga"), - ("Europe/Rome", "Rome"), - ("Europe/Samara", "Samara"), - ("Europe/San_Marino", "San_Marino"), - ("Europe/Sarajevo", "Sarajevo"), - ("Europe/Saratov", "Saratov"), - ("Europe/Simferopol", "Simferopol"), - ("Europe/Skopje", "Skopje"), - ("Europe/Sofia", "Sofia"), - ("Europe/Stockholm", "Stockholm"), - ("Europe/Tallinn", "Tallinn"), - ("Europe/Tirane", "Tirane"), - ("Europe/Tiraspol", "Tiraspol"), - ("Europe/Ulyanovsk", "Ulyanovsk"), - ("Europe/Uzhgorod", "Uzhgorod"), - ("Europe/Vaduz", "Vaduz"), - ("Europe/Vatican", "Vatican"), - ("Europe/Vienna", "Vienna"), - ("Europe/Vilnius", "Vilnius"), - ("Europe/Volgograd", "Volgograd"), - ("Europe/Warsaw", "Warsaw"), - ("Europe/Zagreb", "Zagreb"), - ("Europe/Zaporozhye", "Zaporozhye"), - ("Europe/Zurich", "Zurich"), - ], - ), - ( - "Indian", - [ - ("Indian/Antananarivo", "Antananarivo"), - ("Indian/Chagos", "Chagos"), - ("Indian/Christmas", "Christmas"), - ("Indian/Cocos", "Cocos"), - ("Indian/Comoro", "Comoro"), - ("Indian/Kerguelen", "Kerguelen"), - ("Indian/Mahe", "Mahe"), - ("Indian/Maldives", "Maldives"), - ("Indian/Mauritius", "Mauritius"), - ("Indian/Mayotte", "Mayotte"), - ("Indian/Reunion", "Reunion"), - ], - ), - ( - "Mexico", - [ - ("Mexico/BajaNorte", "BajaNorte"), - ("Mexico/BajaSur", "BajaSur"), - ("Mexico/General", "General"), - ], - ), - ( - "Other", - [ - ("CET", "CET"), - ("CST6CDT", "CST6CDT"), - ("Cuba", "Cuba"), - ("EET", "EET"), - ("EST", "EST"), - ("EST5EDT", "EST5EDT"), - ("Egypt", "Egypt"), - ("Eire", "Eire"), - ("GB", "GB"), - ("GB-Eire", "GB-Eire"), - ("Greenwich", "Greenwich"), - ("HST", "HST"), - ("Hongkong", "Hongkong"), - ("Iceland", "Iceland"), - ("Iran", "Iran"), - ("Israel", "Israel"), - ("Jamaica", "Jamaica"), - ("Japan", "Japan"), - ("Kwajalein", "Kwajalein"), - ("Libya", "Libya"), - ("MET", "MET"), - ("MST", "MST"), - ("MST7MDT", "MST7MDT"), - ("NZ", "NZ"), - ("NZ-CHAT", "NZ-CHAT"), - ("Navajo", "Navajo"), - ("PRC", "PRC"), - ("PST8PDT", "PST8PDT"), - ("Poland", "Poland"), - ("Portugal", "Portugal"), - ("ROC", "ROC"), - ("ROK", "ROK"), - ("Singapore", "Singapore"), - ("Turkey", "Turkey"), - ("UCT", "UCT"), - ("UTC", "UTC"), - ("Universal", "Universal"), - ("W-SU", "W-SU"), - ("WET", "WET"), - ("Zulu", "Zulu"), - ], - ), - ( - "Pacific", - [ - ("Pacific/Apia", "Apia"), - ("Pacific/Auckland", "Auckland"), - ("Pacific/Bougainville", "Bougainville"), - ("Pacific/Chatham", "Chatham"), - ("Pacific/Chuuk", "Chuuk"), - ("Pacific/Easter", "Easter"), - ("Pacific/Efate", "Efate"), - ("Pacific/Enderbury", "Enderbury"), - ("Pacific/Fakaofo", "Fakaofo"), - ("Pacific/Fiji", "Fiji"), - ("Pacific/Funafuti", "Funafuti"), - ("Pacific/Galapagos", "Galapagos"), - ("Pacific/Gambier", "Gambier"), - ("Pacific/Guadalcanal", "Guadalcanal"), - ("Pacific/Guam", "Guam"), - ("Pacific/Honolulu", "Honolulu"), - ("Pacific/Johnston", "Johnston"), - ("Pacific/Kanton", "Kanton"), - ("Pacific/Kiritimati", "Kiritimati"), - ("Pacific/Kosrae", "Kosrae"), - ("Pacific/Kwajalein", "Kwajalein"), - ("Pacific/Majuro", "Majuro"), - ("Pacific/Marquesas", "Marquesas"), - ("Pacific/Midway", "Midway"), - ("Pacific/Nauru", "Nauru"), - ("Pacific/Niue", "Niue"), - ("Pacific/Norfolk", "Norfolk"), - ("Pacific/Noumea", "Noumea"), - ("Pacific/Pago_Pago", "Pago_Pago"), - ("Pacific/Palau", "Palau"), - ("Pacific/Pitcairn", "Pitcairn"), - ("Pacific/Pohnpei", "Pohnpei"), - ("Pacific/Ponape", "Ponape"), - ("Pacific/Port_Moresby", "Port_Moresby"), - ("Pacific/Rarotonga", "Rarotonga"), - ("Pacific/Saipan", "Saipan"), - ("Pacific/Samoa", "Samoa"), - ("Pacific/Tahiti", "Tahiti"), - ("Pacific/Tarawa", "Tarawa"), - ("Pacific/Tongatapu", "Tongatapu"), - ("Pacific/Truk", "Truk"), - ("Pacific/Wake", "Wake"), - ("Pacific/Wallis", "Wallis"), - ("Pacific/Yap", "Yap"), - ], - ), - ( - "US", - [ - ("US/Alaska", "Alaska"), - ("US/Aleutian", "Aleutian"), - ("US/Arizona", "Arizona"), - ("US/Central", "Central"), - ("US/East-Indiana", "East-Indiana"), - ("US/Eastern", "Eastern"), - ("US/Hawaii", "Hawaii"), - ("US/Indiana-Starke", "Indiana-Starke"), - ("US/Michigan", "Michigan"), - ("US/Mountain", "Mountain"), - ("US/Pacific", "Pacific"), - ("US/Samoa", "Samoa"), - ], - ), - ], - default="Asia/Ho_Chi_Minh", - max_length=50, - verbose_name="location", - ), - ), - ] diff --git a/judge/migrations/0118_rating.py b/judge/migrations/0118_rating.py deleted file mode 100644 index fb62906..0000000 --- a/judge/migrations/0118_rating.py +++ /dev/null @@ -1,262 +0,0 @@ -import math -from operator import attrgetter, itemgetter - -from django.db import migrations, models -from django.db.models import Count, OuterRef, Subquery -from django.db.models.functions import Coalesce -from django.utils import timezone - - -def tie_ranker(iterable, key=attrgetter("points")): - rank = 0 - delta = 1 - last = None - buf = [] - for item in iterable: - new = key(item) - if new != last: - for _ in buf: - yield rank + (delta - 1) / 2.0 - rank += delta - delta = 0 - buf = [] - delta += 1 - buf.append(item) - last = key(item) - for _ in buf: - yield rank + (delta - 1) / 2.0 - - -def rational_approximation(t): - # Abramowitz and Stegun formula 26.2.23. - # The absolute value of the error should be less than 4.5 e-4. - c = [2.515517, 0.802853, 0.010328] - d = [1.432788, 0.189269, 0.001308] - numerator = (c[2] * t + c[1]) * t + c[0] - denominator = ((d[2] * t + d[1]) * t + d[0]) * t + 1.0 - return t - numerator / denominator - - -def normal_CDF_inverse(p): - assert 0.0 < p < 1 - - # See article above for explanation of this section. - if p < 0.5: - # F^-1(p) = - G^-1(p) - return -rational_approximation(math.sqrt(-2.0 * math.log(p))) - else: - # F^-1(p) = G^-1(1-p) - return rational_approximation(math.sqrt(-2.0 * math.log(1.0 - p))) - - -def WP(RA, RB, VA, VB): - return (math.erf((RB - RA) / math.sqrt(2 * (VA * VA + VB * VB))) + 1) / 2.0 - - -def recalculate_ratings( - old_rating, old_volatility, actual_rank, times_rated, is_disqualified -): - # actual_rank: 1 is first place, N is last place - # if there are ties, use the average of places (if places 2, 3, 4, 5 tie, use 3.5 for all of them) - - N = len(old_rating) - new_rating = old_rating[:] - new_volatility = old_volatility[:] - if N <= 1: - return new_rating, new_volatility - - ranking = list(range(N)) - ranking.sort(key=old_rating.__getitem__, reverse=True) - - ave_rating = float(sum(old_rating)) / N - sum1 = sum(i * i for i in old_volatility) / N - sum2 = sum((i - ave_rating) ** 2 for i in old_rating) / (N - 1) - CF = math.sqrt(sum1 + sum2) - - for i in range(N): - ERank = 0.5 - for j in range(N): - ERank += WP( - old_rating[i], old_rating[j], old_volatility[i], old_volatility[j] - ) - - EPerf = -normal_CDF_inverse((ERank - 0.5) / N) - APerf = -normal_CDF_inverse((actual_rank[i] - 0.5) / N) - PerfAs = old_rating[i] + CF * (APerf - EPerf) - Weight = 1.0 / (1 - (0.42 / (times_rated[i] + 1) + 0.18)) - 1.0 - if old_rating[i] > 2500: - Weight *= 0.8 - elif old_rating[i] >= 2000: - Weight *= 0.9 - - Cap = 150.0 + 1500.0 / (times_rated[i] + 2) - - new_rating[i] = (old_rating[i] + Weight * PerfAs) / (1.0 + Weight) - - if abs(old_rating[i] - new_rating[i]) > Cap: - if old_rating[i] < new_rating[i]: - new_rating[i] = old_rating[i] + Cap - else: - new_rating[i] = old_rating[i] - Cap - - if times_rated[i] == 0: - new_volatility[i] = 385 - else: - new_volatility[i] = math.sqrt( - ((new_rating[i] - old_rating[i]) ** 2) / Weight - + (old_volatility[i] ** 2) / (Weight + 1) - ) - - if is_disqualified[i]: - # DQed users can manipulate TopCoder ratings to get higher volatility in order to increase their rating - # later on, prohibit this by ensuring their volatility never increases in this situation - new_volatility[i] = min(new_volatility[i], old_volatility[i]) - - # try to keep the sum of ratings constant - adjust = float(sum(old_rating) - sum(new_rating)) / N - new_rating = list(map(adjust.__add__, new_rating)) - # inflate a little if we have to so people who placed first don't lose rating - best_rank = min(actual_rank) - for i in range(N): - if ( - abs(actual_rank[i] - best_rank) <= 1e-3 - and new_rating[i] < old_rating[i] + 1 - ): - new_rating[i] = old_rating[i] + 1 - return list(map(int, map(round, new_rating))), list( - map(int, map(round, new_volatility)) - ) - - -def tc_rate_contest(contest, Rating, Profile): - rating_subquery = Rating.objects.filter(user=OuterRef("user")) - rating_sorted = rating_subquery.order_by("-contest__end_time") - users = ( - contest.users.order_by("is_disqualified", "-score", "cumtime", "tiebreaker") - .annotate( - submissions=Count("submission"), - last_rating=Coalesce(Subquery(rating_sorted.values("rating")[:1]), 1200), - volatility=Coalesce(Subquery(rating_sorted.values("volatility")[:1]), 535), - times=Coalesce( - Subquery( - rating_subquery.order_by() - .values("user_id") - .annotate(count=Count("id")) - .values("count") - ), - 0, - ), - ) - .exclude(user_id__in=contest.rate_exclude.all()) - .filter(virtual=0) - .values( - "id", - "user_id", - "score", - "cumtime", - "tiebreaker", - "is_disqualified", - "last_rating", - "volatility", - "times", - ) - ) - if not contest.rate_all: - users = users.filter(submissions__gt=0) - if contest.rating_floor is not None: - users = users.exclude(last_rating__lt=contest.rating_floor) - if contest.rating_ceiling is not None: - users = users.exclude(last_rating__gt=contest.rating_ceiling) - - users = list(users) - participation_ids = list(map(itemgetter("id"), users)) - user_ids = list(map(itemgetter("user_id"), users)) - is_disqualified = list(map(itemgetter("is_disqualified"), users)) - ranking = list(tie_ranker(users, key=itemgetter("score", "cumtime", "tiebreaker"))) - old_rating = list(map(itemgetter("last_rating"), users)) - old_volatility = list(map(itemgetter("volatility"), users)) - times_ranked = list(map(itemgetter("times"), users)) - rating, volatility = recalculate_ratings( - old_rating, old_volatility, ranking, times_ranked, is_disqualified - ) - - now = timezone.now() - ratings = [ - Rating( - user_id=i, - contest=contest, - rating=r, - volatility=v, - last_rated=now, - participation_id=p, - rank=z, - ) - for i, p, r, v, z in zip( - user_ids, participation_ids, rating, volatility, ranking - ) - ] - - Rating.objects.bulk_create(ratings) - - Profile.objects.filter( - contest_history__contest=contest, contest_history__virtual=0 - ).update( - rating=Subquery( - Rating.objects.filter(user=OuterRef("id")) - .order_by("-contest__end_time") - .values("rating")[:1] - ) - ) - - -# inspired by rate_all_view -def rate_tc(apps, schema_editor): - Contest = apps.get_model("judge", "Contest") - Rating = apps.get_model("judge", "Rating") - Profile = apps.get_model("judge", "Profile") - - with schema_editor.connection.cursor() as cursor: - cursor.execute("TRUNCATE TABLE `%s`" % Rating._meta.db_table) - Profile.objects.update(rating=None) - for contest in Contest.objects.filter( - is_rated=True, end_time__lte=timezone.now() - ).order_by("end_time"): - tc_rate_contest(contest, Rating, Profile) - - -# inspired by rate_all_view -def rate_elo_mmr(apps, schema_editor): - Rating = apps.get_model("judge", "Rating") - Profile = apps.get_model("judge", "Profile") - - with schema_editor.connection.cursor() as cursor: - cursor.execute("TRUNCATE TABLE `%s`" % Rating._meta.db_table) - Profile.objects.update(rating=None) - # Don't populate Rating - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0117_auto_20211209_0612"), - ] - - operations = [ - migrations.RunPython(migrations.RunPython.noop, rate_tc, atomic=True), - migrations.AddField( - model_name="rating", - name="mean", - field=models.FloatField(verbose_name="raw rating"), - ), - migrations.AddField( - model_name="rating", - name="performance", - field=models.FloatField(verbose_name="contest performance"), - ), - migrations.RemoveField( - model_name="rating", - name="volatility", - field=models.IntegerField(verbose_name="volatility"), - ), - migrations.RunPython(rate_elo_mmr, migrations.RunPython.noop, atomic=True), - ] diff --git a/judge/migrations/0119_auto_20220306_0512.py b/judge/migrations/0119_auto_20220306_0512.py deleted file mode 100644 index abcf1fb..0000000 --- a/judge/migrations/0119_auto_20220306_0512.py +++ /dev/null @@ -1,22 +0,0 @@ -# Generated by Django 2.2.25 on 2022-03-05 22:12 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0118_rating"), - ] - - operations = [ - migrations.AlterField( - model_name="contest", - name="hide_problem_tags", - field=models.BooleanField( - default=True, - help_text="Whether problem tags should be hidden by default.", - verbose_name="hide problem tags", - ), - ), - ] diff --git a/judge/migrations/0120_auto_20220306_1124.py b/judge/migrations/0120_auto_20220306_1124.py deleted file mode 100644 index 5e02189..0000000 --- a/judge/migrations/0120_auto_20220306_1124.py +++ /dev/null @@ -1,75 +0,0 @@ -# Generated by Django 2.2.25 on 2022-03-06 04:24 - -import django.core.validators -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0119_auto_20220306_0512"), - ] - - operations = [ - migrations.AddField( - model_name="profile", - name="is_banned_problem_voting", - field=models.BooleanField( - default=False, - help_text="User will not be able to vote on problems' point values.", - verbose_name="banned from voting", - ), - ), - migrations.CreateModel( - name="ProblemPointsVote", - fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "points", - models.IntegerField( - help_text="The amount of points you think this problem deserves.", - validators=[ - django.core.validators.MinValueValidator(100), - django.core.validators.MaxValueValidator(600), - ], - verbose_name="proposed point value", - ), - ), - ( - "vote_time", - models.DateTimeField( - auto_now_add=True, verbose_name="The time this vote was cast" - ), - ), - ( - "problem", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="problem_points_votes", - to="judge.Problem", - ), - ), - ( - "voter", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="problem_points_votes", - to="judge.Profile", - ), - ), - ], - options={ - "verbose_name": "vote", - "verbose_name_plural": "votes", - }, - ), - ] diff --git a/judge/migrations/0121_auto_20220415_0135.py b/judge/migrations/0121_auto_20220415_0135.py deleted file mode 100644 index 77d3f6a..0000000 --- a/judge/migrations/0121_auto_20220415_0135.py +++ /dev/null @@ -1,76 +0,0 @@ -# Generated by Django 2.2.25 on 2022-04-14 18:35 - -import django.core.validators -from django.db import migrations, models -import judge.models.problem_data -import judge.utils.problem_data - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0120_auto_20220306_1124"), - ] - - operations = [ - migrations.AddField( - model_name="problemdata", - name="interactive_judge", - field=models.FileField( - blank=True, - null=True, - storage=judge.utils.problem_data.ProblemDataStorage(), - upload_to=judge.models.problem_data.problem_directory_file, - validators=[ - django.core.validators.FileExtensionValidator( - allowed_extensions=["cpp"] - ) - ], - verbose_name="interactive judge", - ), - ), - migrations.AlterField( - model_name="problemdata", - name="checker", - field=models.CharField( - blank=True, - choices=[ - ("standard", "Standard"), - ("floats", "Floats"), - ("floatsabs", "Floats (absolute)"), - ("floatsrel", "Floats (relative)"), - ("rstripped", "Non-trailing spaces"), - ("sorted", "Unordered"), - ("identical", "Byte identical"), - ("linecount", "Line-by-line"), - ("custom", "Custom checker (PY)"), - ("customval", "Custom validator (CPP)"), - ("interact", "Interactive"), - ], - max_length=10, - verbose_name="checker", - ), - ), - migrations.AlterField( - model_name="problemtestcase", - name="checker", - field=models.CharField( - blank=True, - choices=[ - ("standard", "Standard"), - ("floats", "Floats"), - ("floatsabs", "Floats (absolute)"), - ("floatsrel", "Floats (relative)"), - ("rstripped", "Non-trailing spaces"), - ("sorted", "Unordered"), - ("identical", "Byte identical"), - ("linecount", "Line-by-line"), - ("custom", "Custom checker (PY)"), - ("customval", "Custom validator (CPP)"), - ("interact", "Interactive"), - ], - max_length=10, - verbose_name="checker", - ), - ), - ] diff --git a/judge/migrations/0122_auto_20220425_1202.py b/judge/migrations/0122_auto_20220425_1202.py deleted file mode 100644 index 427cd98..0000000 --- a/judge/migrations/0122_auto_20220425_1202.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 2.2.25 on 2022-04-25 05:02 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0121_auto_20220415_0135"), - ] - - operations = [ - migrations.AlterField( - model_name="contest", - name="time_limit", - field=models.DurationField( - blank=True, - help_text="Format hh:mm:ss. For example, if you want a 2-hour contest, enter 02:00:00", - null=True, - verbose_name="time limit", - ), - ), - ] diff --git a/judge/migrations/0123_auto_20220502_2356.py b/judge/migrations/0123_auto_20220502_2356.py deleted file mode 100644 index 54ed0c7..0000000 --- a/judge/migrations/0123_auto_20220502_2356.py +++ /dev/null @@ -1,91 +0,0 @@ -# Generated by Django 2.2.25 on 2022-05-02 16:56 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0122_auto_20220425_1202"), - ] - - operations = [ - migrations.AlterModelOptions( - name="problem", - options={ - "permissions": ( - ("see_private_problem", "See hidden problems"), - ("edit_own_problem", "Edit own problems"), - ("edit_all_problem", "Edit all problems"), - ("edit_public_problem", "Edit all public problems"), - ("clone_problem", "Clone problem"), - ("change_public_visibility", "Change is_public field"), - ("change_manually_managed", "Change is_manually_managed field"), - ("see_organization_problem", "See organization-private problems"), - ("suggest_problem_changes", "Suggest changes to problem"), - ), - "verbose_name": "problem", - "verbose_name_plural": "problems", - }, - ), - migrations.CreateModel( - name="VolunteerProblemVote", - fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("time", models.DateTimeField(auto_now_add=True)), - ( - "knowledge_points", - models.PositiveIntegerField( - help_text="Points awarded by knowledge difficulty", - verbose_name="knowledge points", - ), - ), - ( - "thinking_points", - models.PositiveIntegerField( - help_text="Points awarded by thinking difficulty", - verbose_name="thinking points", - ), - ), - ("feedback", models.TextField(blank=True, verbose_name="feedback")), - ( - "problem", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="volunteer_user_votes", - to="judge.Problem", - ), - ), - ( - "types", - models.ManyToManyField( - help_text="The type of problem, as shown on the problem's page.", - to="judge.ProblemType", - verbose_name="problem types", - ), - ), - ( - "voter", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="volunteer_problem_votes", - to="judge.Profile", - ), - ), - ], - options={ - "verbose_name": "volunteer vote", - "verbose_name_plural": "volunteer votes", - "unique_together": {("voter", "problem")}, - }, - ), - ] diff --git a/judge/migrations/0124_auto_20220602_1116.py b/judge/migrations/0124_auto_20220602_1116.py deleted file mode 100644 index 5b15aef..0000000 --- a/judge/migrations/0124_auto_20220602_1116.py +++ /dev/null @@ -1,27 +0,0 @@ -# Generated by Django 2.2.25 on 2022-06-02 04:16 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0123_auto_20220502_2356"), - ] - - operations = [ - migrations.AddField( - model_name="problemdata", - name="fileio_input", - field=models.TextField( - blank=True, null=True, verbose_name="input file name" - ), - ), - migrations.AddField( - model_name="problemdata", - name="fileio_output", - field=models.TextField( - blank=True, null=True, verbose_name="output file name" - ), - ), - ] diff --git a/judge/migrations/0125_auto_20220602_1216.py b/judge/migrations/0125_auto_20220602_1216.py deleted file mode 100644 index 18bee1c..0000000 --- a/judge/migrations/0125_auto_20220602_1216.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 2.2.25 on 2022-06-02 05:16 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0124_auto_20220602_1116"), - ] - - operations = [ - migrations.AlterField( - model_name="problemdata", - name="fileio_input", - field=models.TextField( - blank=True, - help_text="Leave empty for stdin", - null=True, - verbose_name="input file name", - ), - ), - migrations.AlterField( - model_name="problemdata", - name="fileio_output", - field=models.TextField( - blank=True, - help_text="Leave empty for stdout", - null=True, - verbose_name="output file name", - ), - ), - ] diff --git a/judge/migrations/0126_languagetemplate.py b/judge/migrations/0126_languagetemplate.py deleted file mode 100644 index 7555905..0000000 --- a/judge/migrations/0126_languagetemplate.py +++ /dev/null @@ -1,54 +0,0 @@ -# Generated by Django 2.2.25 on 2022-06-12 06:59 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0125_auto_20220602_1216"), - ] - - operations = [ - migrations.CreateModel( - name="LanguageTemplate", - fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "source", - models.TextField(max_length=65536, verbose_name="source code"), - ), - ( - "language", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="judge.Language", - verbose_name="language", - ), - ), - ( - "problem", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="language_templates", - to="judge.Problem", - verbose_name="problem", - ), - ), - ], - options={ - "verbose_name": "language-specific template", - "verbose_name_plural": "language-specific templates", - "unique_together": {("problem", "language")}, - }, - ), - ] diff --git a/judge/migrations/0127_auto_20220616_1442.py b/judge/migrations/0127_auto_20220616_1442.py deleted file mode 100644 index e5a8af2..0000000 --- a/judge/migrations/0127_auto_20220616_1442.py +++ /dev/null @@ -1,29 +0,0 @@ -# Generated by Django 2.2.25 on 2022-06-16 07:42 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0126_languagetemplate"), - ] - - operations = [ - migrations.AlterModelOptions( - name="submission", - options={ - "permissions": ( - ("abort_any_submission", "Abort any submission"), - ("rejudge_submission", "Rejudge the submission"), - ("rejudge_submission_lot", "Rejudge a lot of submissions"), - ("spam_submission", "Submit without limit"), - ("view_all_submission", "View all submission"), - ("resubmit_other", "Resubmit others' submission"), - ("view_public_submission", "View public submissions"), - ), - "verbose_name": "submission", - "verbose_name_plural": "submissions", - }, - ), - ] diff --git a/judge/migrations/0128_auto_20220620_2210.py b/judge/migrations/0128_auto_20220620_2210.py deleted file mode 100644 index 27fed32..0000000 --- a/judge/migrations/0128_auto_20220620_2210.py +++ /dev/null @@ -1,26 +0,0 @@ -# Generated by Django 2.2.25 on 2022-06-20 15:10 - -import django.core.validators -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0127_auto_20220616_1442"), - ] - - operations = [ - migrations.AlterField( - model_name="problem", - name="memory_limit", - field=models.PositiveIntegerField( - help_text="The memory limit for this problem, in kilobytes (e.g. 256mb = 262144 kilobytes).", - validators=[ - django.core.validators.MinValueValidator(0), - django.core.validators.MaxValueValidator(1048576), - ], - verbose_name="memory limit", - ), - ), - ] diff --git a/judge/migrations/0129_auto_20220622_1424.py b/judge/migrations/0129_auto_20220622_1424.py deleted file mode 100644 index ab1356a..0000000 --- a/judge/migrations/0129_auto_20220622_1424.py +++ /dev/null @@ -1,59 +0,0 @@ -# Generated by Django 2.2.25 on 2022-06-22 07:24 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0128_auto_20220620_2210"), - ] - - operations = [ - migrations.AlterField( - model_name="problemdata", - name="checker", - field=models.CharField( - blank=True, - choices=[ - ("standard", "Standard"), - ("floats", "Floats"), - ("floatsabs", "Floats (absolute)"), - ("floatsrel", "Floats (relative)"), - ("rstripped", "Non-trailing spaces"), - ("sorted", "Unordered"), - ("identical", "Byte identical"), - ("linecount", "Line-by-line"), - ("custom", "Custom checker (PY)"), - ("customval", "Custom validator (CPP)"), - ("interact", "Interactive"), - ("testlib", "Testlib"), - ], - max_length=10, - verbose_name="checker", - ), - ), - migrations.AlterField( - model_name="problemtestcase", - name="checker", - field=models.CharField( - blank=True, - choices=[ - ("standard", "Standard"), - ("floats", "Floats"), - ("floatsabs", "Floats (absolute)"), - ("floatsrel", "Floats (relative)"), - ("rstripped", "Non-trailing spaces"), - ("sorted", "Unordered"), - ("identical", "Byte identical"), - ("linecount", "Line-by-line"), - ("custom", "Custom checker (PY)"), - ("customval", "Custom validator (CPP)"), - ("interact", "Interactive"), - ("testlib", "Testlib"), - ], - max_length=10, - verbose_name="checker", - ), - ), - ] diff --git a/judge/migrations/0130_auto_20220831_1048.py b/judge/migrations/0130_auto_20220831_1048.py deleted file mode 100644 index 6bb3478..0000000 --- a/judge/migrations/0130_auto_20220831_1048.py +++ /dev/null @@ -1,31 +0,0 @@ -# Generated by Django 2.2.25 on 2022-08-31 03:48 - -from django.db import migrations, models -import judge.models.problem -import judge.utils.problem_data - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0129_auto_20220622_1424"), - ] - - operations = [ - migrations.AddField( - model_name="problem", - name="pdf_description", - field=models.FileField( - blank=True, - null=True, - storage=judge.utils.problem_data.ProblemDataStorage(), - upload_to=judge.models.problem.problem_directory_file, - verbose_name="pdf statement", - ), - ), - migrations.AlterField( - model_name="problem", - name="description", - field=models.TextField(blank=True, verbose_name="problem body"), - ), - ] diff --git a/judge/migrations/0131_auto_20220905_0027.py b/judge/migrations/0131_auto_20220905_0027.py deleted file mode 100644 index ae2e79a..0000000 --- a/judge/migrations/0131_auto_20220905_0027.py +++ /dev/null @@ -1,27 +0,0 @@ -# Generated by Django 2.2.25 on 2022-09-04 17:27 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0130_auto_20220831_1048"), - ] - - operations = [ - migrations.AlterField( - model_name="notification", - name="category", - field=models.CharField(max_length=50, verbose_name="category"), - ), - migrations.AlterField( - model_name="problemtranslation", - name="language", - field=models.CharField( - choices=[("en", "English"), ("vi", "Vietnamese")], - max_length=7, - verbose_name="language", - ), - ), - ] diff --git a/judge/migrations/0132_auto_20220915_1349.py b/judge/migrations/0132_auto_20220915_1349.py deleted file mode 100644 index e303f5b..0000000 --- a/judge/migrations/0132_auto_20220915_1349.py +++ /dev/null @@ -1,28 +0,0 @@ -# Generated by Django 2.2.25 on 2022-09-15 06:49 - -import django.core.validators -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0131_auto_20220905_0027"), - ] - - operations = [ - migrations.AlterField( - model_name="contestproblem", - name="max_submissions", - field=models.IntegerField( - default=0, - help_text="Maximum number of submissions for this problem, or 0 for no limit.", - validators=[ - django.core.validators.MinValueValidator( - 0, "Why include a problem you can't submit to?" - ) - ], - verbose_name="max submissions", - ), - ), - ] diff --git a/judge/migrations/0133_auto_20221013_0850.py b/judge/migrations/0133_auto_20221013_0850.py deleted file mode 100644 index b210016..0000000 --- a/judge/migrations/0133_auto_20221013_0850.py +++ /dev/null @@ -1,46 +0,0 @@ -# Generated by Django 2.2.25 on 2022-10-13 01:50 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0132_auto_20220915_1349"), - ] - - operations = [ - migrations.CreateModel( - name="ContestProblemClarification", - fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("description", models.TextField(verbose_name="clarification body")), - ( - "date", - models.DateTimeField( - auto_now_add=True, verbose_name="clarification timestamp" - ), - ), - ( - "problem", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="judge.ContestProblem", - verbose_name="clarified problem", - ), - ), - ], - ), - migrations.DeleteModel( - name="ProblemClarification", - ), - ] diff --git a/judge/migrations/0134_auto_20221018_0124.py b/judge/migrations/0134_auto_20221018_0124.py deleted file mode 100644 index b7fda08..0000000 --- a/judge/migrations/0134_auto_20221018_0124.py +++ /dev/null @@ -1,707 +0,0 @@ -# Generated by Django 2.2.28 on 2022-10-17 18:24 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0133_auto_20221013_0850"), - ] - - operations = [ - migrations.AlterField( - model_name="profile", - name="timezone", - field=models.CharField( - choices=[ - ( - "Africa", - [ - ("Africa/Abidjan", "Abidjan"), - ("Africa/Accra", "Accra"), - ("Africa/Addis_Ababa", "Addis_Ababa"), - ("Africa/Algiers", "Algiers"), - ("Africa/Asmara", "Asmara"), - ("Africa/Asmera", "Asmera"), - ("Africa/Bamako", "Bamako"), - ("Africa/Bangui", "Bangui"), - ("Africa/Banjul", "Banjul"), - ("Africa/Bissau", "Bissau"), - ("Africa/Blantyre", "Blantyre"), - ("Africa/Brazzaville", "Brazzaville"), - ("Africa/Bujumbura", "Bujumbura"), - ("Africa/Cairo", "Cairo"), - ("Africa/Casablanca", "Casablanca"), - ("Africa/Ceuta", "Ceuta"), - ("Africa/Conakry", "Conakry"), - ("Africa/Dakar", "Dakar"), - ("Africa/Dar_es_Salaam", "Dar_es_Salaam"), - ("Africa/Djibouti", "Djibouti"), - ("Africa/Douala", "Douala"), - ("Africa/El_Aaiun", "El_Aaiun"), - ("Africa/Freetown", "Freetown"), - ("Africa/Gaborone", "Gaborone"), - ("Africa/Harare", "Harare"), - ("Africa/Johannesburg", "Johannesburg"), - ("Africa/Juba", "Juba"), - ("Africa/Kampala", "Kampala"), - ("Africa/Khartoum", "Khartoum"), - ("Africa/Kigali", "Kigali"), - ("Africa/Kinshasa", "Kinshasa"), - ("Africa/Lagos", "Lagos"), - ("Africa/Libreville", "Libreville"), - ("Africa/Lome", "Lome"), - ("Africa/Luanda", "Luanda"), - ("Africa/Lubumbashi", "Lubumbashi"), - ("Africa/Lusaka", "Lusaka"), - ("Africa/Malabo", "Malabo"), - ("Africa/Maputo", "Maputo"), - ("Africa/Maseru", "Maseru"), - ("Africa/Mbabane", "Mbabane"), - ("Africa/Mogadishu", "Mogadishu"), - ("Africa/Monrovia", "Monrovia"), - ("Africa/Nairobi", "Nairobi"), - ("Africa/Ndjamena", "Ndjamena"), - ("Africa/Niamey", "Niamey"), - ("Africa/Nouakchott", "Nouakchott"), - ("Africa/Ouagadougou", "Ouagadougou"), - ("Africa/Porto-Novo", "Porto-Novo"), - ("Africa/Sao_Tome", "Sao_Tome"), - ("Africa/Timbuktu", "Timbuktu"), - ("Africa/Tripoli", "Tripoli"), - ("Africa/Tunis", "Tunis"), - ("Africa/Windhoek", "Windhoek"), - ], - ), - ( - "America", - [ - ("America/Adak", "Adak"), - ("America/Anchorage", "Anchorage"), - ("America/Anguilla", "Anguilla"), - ("America/Antigua", "Antigua"), - ("America/Araguaina", "Araguaina"), - ( - "America/Argentina/Buenos_Aires", - "Argentina/Buenos_Aires", - ), - ("America/Argentina/Catamarca", "Argentina/Catamarca"), - ( - "America/Argentina/ComodRivadavia", - "Argentina/ComodRivadavia", - ), - ("America/Argentina/Cordoba", "Argentina/Cordoba"), - ("America/Argentina/Jujuy", "Argentina/Jujuy"), - ("America/Argentina/La_Rioja", "Argentina/La_Rioja"), - ("America/Argentina/Mendoza", "Argentina/Mendoza"), - ( - "America/Argentina/Rio_Gallegos", - "Argentina/Rio_Gallegos", - ), - ("America/Argentina/Salta", "Argentina/Salta"), - ("America/Argentina/San_Juan", "Argentina/San_Juan"), - ("America/Argentina/San_Luis", "Argentina/San_Luis"), - ("America/Argentina/Tucuman", "Argentina/Tucuman"), - ("America/Argentina/Ushuaia", "Argentina/Ushuaia"), - ("America/Aruba", "Aruba"), - ("America/Asuncion", "Asuncion"), - ("America/Atikokan", "Atikokan"), - ("America/Atka", "Atka"), - ("America/Bahia", "Bahia"), - ("America/Bahia_Banderas", "Bahia_Banderas"), - ("America/Barbados", "Barbados"), - ("America/Belem", "Belem"), - ("America/Belize", "Belize"), - ("America/Blanc-Sablon", "Blanc-Sablon"), - ("America/Boa_Vista", "Boa_Vista"), - ("America/Bogota", "Bogota"), - ("America/Boise", "Boise"), - ("America/Buenos_Aires", "Buenos_Aires"), - ("America/Cambridge_Bay", "Cambridge_Bay"), - ("America/Campo_Grande", "Campo_Grande"), - ("America/Cancun", "Cancun"), - ("America/Caracas", "Caracas"), - ("America/Catamarca", "Catamarca"), - ("America/Cayenne", "Cayenne"), - ("America/Cayman", "Cayman"), - ("America/Chicago", "Chicago"), - ("America/Chihuahua", "Chihuahua"), - ("America/Coral_Harbour", "Coral_Harbour"), - ("America/Cordoba", "Cordoba"), - ("America/Costa_Rica", "Costa_Rica"), - ("America/Creston", "Creston"), - ("America/Cuiaba", "Cuiaba"), - ("America/Curacao", "Curacao"), - ("America/Danmarkshavn", "Danmarkshavn"), - ("America/Dawson", "Dawson"), - ("America/Dawson_Creek", "Dawson_Creek"), - ("America/Denver", "Denver"), - ("America/Detroit", "Detroit"), - ("America/Dominica", "Dominica"), - ("America/Edmonton", "Edmonton"), - ("America/Eirunepe", "Eirunepe"), - ("America/El_Salvador", "El_Salvador"), - ("America/Ensenada", "Ensenada"), - ("America/Fort_Nelson", "Fort_Nelson"), - ("America/Fort_Wayne", "Fort_Wayne"), - ("America/Fortaleza", "Fortaleza"), - ("America/Glace_Bay", "Glace_Bay"), - ("America/Godthab", "Godthab"), - ("America/Goose_Bay", "Goose_Bay"), - ("America/Grand_Turk", "Grand_Turk"), - ("America/Grenada", "Grenada"), - ("America/Guadeloupe", "Guadeloupe"), - ("America/Guatemala", "Guatemala"), - ("America/Guayaquil", "Guayaquil"), - ("America/Guyana", "Guyana"), - ("America/Halifax", "Halifax"), - ("America/Havana", "Havana"), - ("America/Hermosillo", "Hermosillo"), - ("America/Indiana/Indianapolis", "Indiana/Indianapolis"), - ("America/Indiana/Knox", "Indiana/Knox"), - ("America/Indiana/Marengo", "Indiana/Marengo"), - ("America/Indiana/Petersburg", "Indiana/Petersburg"), - ("America/Indiana/Tell_City", "Indiana/Tell_City"), - ("America/Indiana/Vevay", "Indiana/Vevay"), - ("America/Indiana/Vincennes", "Indiana/Vincennes"), - ("America/Indiana/Winamac", "Indiana/Winamac"), - ("America/Indianapolis", "Indianapolis"), - ("America/Inuvik", "Inuvik"), - ("America/Iqaluit", "Iqaluit"), - ("America/Jamaica", "Jamaica"), - ("America/Jujuy", "Jujuy"), - ("America/Juneau", "Juneau"), - ("America/Kentucky/Louisville", "Kentucky/Louisville"), - ("America/Kentucky/Monticello", "Kentucky/Monticello"), - ("America/Knox_IN", "Knox_IN"), - ("America/Kralendijk", "Kralendijk"), - ("America/La_Paz", "La_Paz"), - ("America/Lima", "Lima"), - ("America/Los_Angeles", "Los_Angeles"), - ("America/Louisville", "Louisville"), - ("America/Lower_Princes", "Lower_Princes"), - ("America/Maceio", "Maceio"), - ("America/Managua", "Managua"), - ("America/Manaus", "Manaus"), - ("America/Marigot", "Marigot"), - ("America/Martinique", "Martinique"), - ("America/Matamoros", "Matamoros"), - ("America/Mazatlan", "Mazatlan"), - ("America/Mendoza", "Mendoza"), - ("America/Menominee", "Menominee"), - ("America/Merida", "Merida"), - ("America/Metlakatla", "Metlakatla"), - ("America/Mexico_City", "Mexico_City"), - ("America/Miquelon", "Miquelon"), - ("America/Moncton", "Moncton"), - ("America/Monterrey", "Monterrey"), - ("America/Montevideo", "Montevideo"), - ("America/Montreal", "Montreal"), - ("America/Montserrat", "Montserrat"), - ("America/Nassau", "Nassau"), - ("America/New_York", "New_York"), - ("America/Nipigon", "Nipigon"), - ("America/Nome", "Nome"), - ("America/Noronha", "Noronha"), - ("America/North_Dakota/Beulah", "North_Dakota/Beulah"), - ("America/North_Dakota/Center", "North_Dakota/Center"), - ( - "America/North_Dakota/New_Salem", - "North_Dakota/New_Salem", - ), - ("America/Nuuk", "Nuuk"), - ("America/Ojinaga", "Ojinaga"), - ("America/Panama", "Panama"), - ("America/Pangnirtung", "Pangnirtung"), - ("America/Paramaribo", "Paramaribo"), - ("America/Phoenix", "Phoenix"), - ("America/Port-au-Prince", "Port-au-Prince"), - ("America/Port_of_Spain", "Port_of_Spain"), - ("America/Porto_Acre", "Porto_Acre"), - ("America/Porto_Velho", "Porto_Velho"), - ("America/Puerto_Rico", "Puerto_Rico"), - ("America/Punta_Arenas", "Punta_Arenas"), - ("America/Rainy_River", "Rainy_River"), - ("America/Rankin_Inlet", "Rankin_Inlet"), - ("America/Recife", "Recife"), - ("America/Regina", "Regina"), - ("America/Resolute", "Resolute"), - ("America/Rio_Branco", "Rio_Branco"), - ("America/Rosario", "Rosario"), - ("America/Santa_Isabel", "Santa_Isabel"), - ("America/Santarem", "Santarem"), - ("America/Santiago", "Santiago"), - ("America/Santo_Domingo", "Santo_Domingo"), - ("America/Sao_Paulo", "Sao_Paulo"), - ("America/Scoresbysund", "Scoresbysund"), - ("America/Shiprock", "Shiprock"), - ("America/Sitka", "Sitka"), - ("America/St_Barthelemy", "St_Barthelemy"), - ("America/St_Johns", "St_Johns"), - ("America/St_Kitts", "St_Kitts"), - ("America/St_Lucia", "St_Lucia"), - ("America/St_Thomas", "St_Thomas"), - ("America/St_Vincent", "St_Vincent"), - ("America/Swift_Current", "Swift_Current"), - ("America/Tegucigalpa", "Tegucigalpa"), - ("America/Thule", "Thule"), - ("America/Thunder_Bay", "Thunder_Bay"), - ("America/Tijuana", "Tijuana"), - ("America/Toronto", "Toronto"), - ("America/Tortola", "Tortola"), - ("America/Vancouver", "Vancouver"), - ("America/Virgin", "Virgin"), - ("America/Whitehorse", "Whitehorse"), - ("America/Winnipeg", "Winnipeg"), - ("America/Yakutat", "Yakutat"), - ("America/Yellowknife", "Yellowknife"), - ], - ), - ( - "Antarctica", - [ - ("Antarctica/Casey", "Casey"), - ("Antarctica/Davis", "Davis"), - ("Antarctica/DumontDUrville", "DumontDUrville"), - ("Antarctica/Macquarie", "Macquarie"), - ("Antarctica/Mawson", "Mawson"), - ("Antarctica/McMurdo", "McMurdo"), - ("Antarctica/Palmer", "Palmer"), - ("Antarctica/Rothera", "Rothera"), - ("Antarctica/South_Pole", "South_Pole"), - ("Antarctica/Syowa", "Syowa"), - ("Antarctica/Troll", "Troll"), - ("Antarctica/Vostok", "Vostok"), - ], - ), - ("Arctic", [("Arctic/Longyearbyen", "Longyearbyen")]), - ( - "Asia", - [ - ("Asia/Aden", "Aden"), - ("Asia/Almaty", "Almaty"), - ("Asia/Amman", "Amman"), - ("Asia/Anadyr", "Anadyr"), - ("Asia/Aqtau", "Aqtau"), - ("Asia/Aqtobe", "Aqtobe"), - ("Asia/Ashgabat", "Ashgabat"), - ("Asia/Ashkhabad", "Ashkhabad"), - ("Asia/Atyrau", "Atyrau"), - ("Asia/Baghdad", "Baghdad"), - ("Asia/Bahrain", "Bahrain"), - ("Asia/Baku", "Baku"), - ("Asia/Bangkok", "Bangkok"), - ("Asia/Barnaul", "Barnaul"), - ("Asia/Beirut", "Beirut"), - ("Asia/Bishkek", "Bishkek"), - ("Asia/Brunei", "Brunei"), - ("Asia/Calcutta", "Calcutta"), - ("Asia/Chita", "Chita"), - ("Asia/Choibalsan", "Choibalsan"), - ("Asia/Chongqing", "Chongqing"), - ("Asia/Chungking", "Chungking"), - ("Asia/Colombo", "Colombo"), - ("Asia/Dacca", "Dacca"), - ("Asia/Damascus", "Damascus"), - ("Asia/Dhaka", "Dhaka"), - ("Asia/Dili", "Dili"), - ("Asia/Dubai", "Dubai"), - ("Asia/Dushanbe", "Dushanbe"), - ("Asia/Famagusta", "Famagusta"), - ("Asia/Gaza", "Gaza"), - ("Asia/Harbin", "Harbin"), - ("Asia/Hebron", "Hebron"), - ("Asia/Ho_Chi_Minh", "Ho_Chi_Minh"), - ("Asia/Hong_Kong", "Hong_Kong"), - ("Asia/Hovd", "Hovd"), - ("Asia/Irkutsk", "Irkutsk"), - ("Asia/Istanbul", "Istanbul"), - ("Asia/Jakarta", "Jakarta"), - ("Asia/Jayapura", "Jayapura"), - ("Asia/Jerusalem", "Jerusalem"), - ("Asia/Kabul", "Kabul"), - ("Asia/Kamchatka", "Kamchatka"), - ("Asia/Karachi", "Karachi"), - ("Asia/Kashgar", "Kashgar"), - ("Asia/Kathmandu", "Kathmandu"), - ("Asia/Katmandu", "Katmandu"), - ("Asia/Khandyga", "Khandyga"), - ("Asia/Kolkata", "Kolkata"), - ("Asia/Krasnoyarsk", "Krasnoyarsk"), - ("Asia/Kuala_Lumpur", "Kuala_Lumpur"), - ("Asia/Kuching", "Kuching"), - ("Asia/Kuwait", "Kuwait"), - ("Asia/Macao", "Macao"), - ("Asia/Macau", "Macau"), - ("Asia/Magadan", "Magadan"), - ("Asia/Makassar", "Makassar"), - ("Asia/Manila", "Manila"), - ("Asia/Muscat", "Muscat"), - ("Asia/Nicosia", "Nicosia"), - ("Asia/Novokuznetsk", "Novokuznetsk"), - ("Asia/Novosibirsk", "Novosibirsk"), - ("Asia/Omsk", "Omsk"), - ("Asia/Oral", "Oral"), - ("Asia/Phnom_Penh", "Phnom_Penh"), - ("Asia/Pontianak", "Pontianak"), - ("Asia/Pyongyang", "Pyongyang"), - ("Asia/Qatar", "Qatar"), - ("Asia/Qostanay", "Qostanay"), - ("Asia/Qyzylorda", "Qyzylorda"), - ("Asia/Rangoon", "Rangoon"), - ("Asia/Riyadh", "Riyadh"), - ("Asia/Saigon", "Saigon"), - ("Asia/Sakhalin", "Sakhalin"), - ("Asia/Samarkand", "Samarkand"), - ("Asia/Seoul", "Seoul"), - ("Asia/Shanghai", "Shanghai"), - ("Asia/Singapore", "Singapore"), - ("Asia/Srednekolymsk", "Srednekolymsk"), - ("Asia/Taipei", "Taipei"), - ("Asia/Tashkent", "Tashkent"), - ("Asia/Tbilisi", "Tbilisi"), - ("Asia/Tehran", "Tehran"), - ("Asia/Tel_Aviv", "Tel_Aviv"), - ("Asia/Thimbu", "Thimbu"), - ("Asia/Thimphu", "Thimphu"), - ("Asia/Tokyo", "Tokyo"), - ("Asia/Tomsk", "Tomsk"), - ("Asia/Ujung_Pandang", "Ujung_Pandang"), - ("Asia/Ulaanbaatar", "Ulaanbaatar"), - ("Asia/Ulan_Bator", "Ulan_Bator"), - ("Asia/Urumqi", "Urumqi"), - ("Asia/Ust-Nera", "Ust-Nera"), - ("Asia/Vientiane", "Vientiane"), - ("Asia/Vladivostok", "Vladivostok"), - ("Asia/Yakutsk", "Yakutsk"), - ("Asia/Yangon", "Yangon"), - ("Asia/Yekaterinburg", "Yekaterinburg"), - ("Asia/Yerevan", "Yerevan"), - ], - ), - ( - "Atlantic", - [ - ("Atlantic/Azores", "Azores"), - ("Atlantic/Bermuda", "Bermuda"), - ("Atlantic/Canary", "Canary"), - ("Atlantic/Cape_Verde", "Cape_Verde"), - ("Atlantic/Faeroe", "Faeroe"), - ("Atlantic/Faroe", "Faroe"), - ("Atlantic/Jan_Mayen", "Jan_Mayen"), - ("Atlantic/Madeira", "Madeira"), - ("Atlantic/Reykjavik", "Reykjavik"), - ("Atlantic/South_Georgia", "South_Georgia"), - ("Atlantic/St_Helena", "St_Helena"), - ("Atlantic/Stanley", "Stanley"), - ], - ), - ( - "Australia", - [ - ("Australia/ACT", "ACT"), - ("Australia/Adelaide", "Adelaide"), - ("Australia/Brisbane", "Brisbane"), - ("Australia/Broken_Hill", "Broken_Hill"), - ("Australia/Canberra", "Canberra"), - ("Australia/Currie", "Currie"), - ("Australia/Darwin", "Darwin"), - ("Australia/Eucla", "Eucla"), - ("Australia/Hobart", "Hobart"), - ("Australia/LHI", "LHI"), - ("Australia/Lindeman", "Lindeman"), - ("Australia/Lord_Howe", "Lord_Howe"), - ("Australia/Melbourne", "Melbourne"), - ("Australia/NSW", "NSW"), - ("Australia/North", "North"), - ("Australia/Perth", "Perth"), - ("Australia/Queensland", "Queensland"), - ("Australia/South", "South"), - ("Australia/Sydney", "Sydney"), - ("Australia/Tasmania", "Tasmania"), - ("Australia/Victoria", "Victoria"), - ("Australia/West", "West"), - ("Australia/Yancowinna", "Yancowinna"), - ], - ), - ( - "Brazil", - [ - ("Brazil/Acre", "Acre"), - ("Brazil/DeNoronha", "DeNoronha"), - ("Brazil/East", "East"), - ("Brazil/West", "West"), - ], - ), - ( - "Canada", - [ - ("Canada/Atlantic", "Atlantic"), - ("Canada/Central", "Central"), - ("Canada/Eastern", "Eastern"), - ("Canada/Mountain", "Mountain"), - ("Canada/Newfoundland", "Newfoundland"), - ("Canada/Pacific", "Pacific"), - ("Canada/Saskatchewan", "Saskatchewan"), - ("Canada/Yukon", "Yukon"), - ], - ), - ( - "Chile", - [ - ("Chile/Continental", "Continental"), - ("Chile/EasterIsland", "EasterIsland"), - ], - ), - ( - "Etc", - [ - ("Etc/Greenwich", "Greenwich"), - ("Etc/UCT", "UCT"), - ("Etc/UTC", "UTC"), - ("Etc/Universal", "Universal"), - ("Etc/Zulu", "Zulu"), - ], - ), - ( - "Europe", - [ - ("Europe/Amsterdam", "Amsterdam"), - ("Europe/Andorra", "Andorra"), - ("Europe/Astrakhan", "Astrakhan"), - ("Europe/Athens", "Athens"), - ("Europe/Belfast", "Belfast"), - ("Europe/Belgrade", "Belgrade"), - ("Europe/Berlin", "Berlin"), - ("Europe/Bratislava", "Bratislava"), - ("Europe/Brussels", "Brussels"), - ("Europe/Bucharest", "Bucharest"), - ("Europe/Budapest", "Budapest"), - ("Europe/Busingen", "Busingen"), - ("Europe/Chisinau", "Chisinau"), - ("Europe/Copenhagen", "Copenhagen"), - ("Europe/Dublin", "Dublin"), - ("Europe/Gibraltar", "Gibraltar"), - ("Europe/Guernsey", "Guernsey"), - ("Europe/Helsinki", "Helsinki"), - ("Europe/Isle_of_Man", "Isle_of_Man"), - ("Europe/Istanbul", "Istanbul"), - ("Europe/Jersey", "Jersey"), - ("Europe/Kaliningrad", "Kaliningrad"), - ("Europe/Kiev", "Kiev"), - ("Europe/Kirov", "Kirov"), - ("Europe/Kyiv", "Kyiv"), - ("Europe/Lisbon", "Lisbon"), - ("Europe/Ljubljana", "Ljubljana"), - ("Europe/London", "London"), - ("Europe/Luxembourg", "Luxembourg"), - ("Europe/Madrid", "Madrid"), - ("Europe/Malta", "Malta"), - ("Europe/Mariehamn", "Mariehamn"), - ("Europe/Minsk", "Minsk"), - ("Europe/Monaco", "Monaco"), - ("Europe/Moscow", "Moscow"), - ("Europe/Nicosia", "Nicosia"), - ("Europe/Oslo", "Oslo"), - ("Europe/Paris", "Paris"), - ("Europe/Podgorica", "Podgorica"), - ("Europe/Prague", "Prague"), - ("Europe/Riga", "Riga"), - ("Europe/Rome", "Rome"), - ("Europe/Samara", "Samara"), - ("Europe/San_Marino", "San_Marino"), - ("Europe/Sarajevo", "Sarajevo"), - ("Europe/Saratov", "Saratov"), - ("Europe/Simferopol", "Simferopol"), - ("Europe/Skopje", "Skopje"), - ("Europe/Sofia", "Sofia"), - ("Europe/Stockholm", "Stockholm"), - ("Europe/Tallinn", "Tallinn"), - ("Europe/Tirane", "Tirane"), - ("Europe/Tiraspol", "Tiraspol"), - ("Europe/Ulyanovsk", "Ulyanovsk"), - ("Europe/Uzhgorod", "Uzhgorod"), - ("Europe/Vaduz", "Vaduz"), - ("Europe/Vatican", "Vatican"), - ("Europe/Vienna", "Vienna"), - ("Europe/Vilnius", "Vilnius"), - ("Europe/Volgograd", "Volgograd"), - ("Europe/Warsaw", "Warsaw"), - ("Europe/Zagreb", "Zagreb"), - ("Europe/Zaporozhye", "Zaporozhye"), - ("Europe/Zurich", "Zurich"), - ], - ), - ( - "Indian", - [ - ("Indian/Antananarivo", "Antananarivo"), - ("Indian/Chagos", "Chagos"), - ("Indian/Christmas", "Christmas"), - ("Indian/Cocos", "Cocos"), - ("Indian/Comoro", "Comoro"), - ("Indian/Kerguelen", "Kerguelen"), - ("Indian/Mahe", "Mahe"), - ("Indian/Maldives", "Maldives"), - ("Indian/Mauritius", "Mauritius"), - ("Indian/Mayotte", "Mayotte"), - ("Indian/Reunion", "Reunion"), - ], - ), - ( - "Mexico", - [ - ("Mexico/BajaNorte", "BajaNorte"), - ("Mexico/BajaSur", "BajaSur"), - ("Mexico/General", "General"), - ], - ), - ( - "Other", - [ - ("CET", "CET"), - ("CST6CDT", "CST6CDT"), - ("Cuba", "Cuba"), - ("EET", "EET"), - ("EST", "EST"), - ("EST5EDT", "EST5EDT"), - ("Egypt", "Egypt"), - ("Eire", "Eire"), - ("GB", "GB"), - ("GB-Eire", "GB-Eire"), - ("Greenwich", "Greenwich"), - ("HST", "HST"), - ("Hongkong", "Hongkong"), - ("Iceland", "Iceland"), - ("Iran", "Iran"), - ("Israel", "Israel"), - ("Jamaica", "Jamaica"), - ("Japan", "Japan"), - ("Kwajalein", "Kwajalein"), - ("Libya", "Libya"), - ("MET", "MET"), - ("MST", "MST"), - ("MST7MDT", "MST7MDT"), - ("NZ", "NZ"), - ("NZ-CHAT", "NZ-CHAT"), - ("Navajo", "Navajo"), - ("PRC", "PRC"), - ("PST8PDT", "PST8PDT"), - ("Poland", "Poland"), - ("Portugal", "Portugal"), - ("ROC", "ROC"), - ("ROK", "ROK"), - ("Singapore", "Singapore"), - ("Turkey", "Turkey"), - ("UCT", "UCT"), - ("UTC", "UTC"), - ("Universal", "Universal"), - ("W-SU", "W-SU"), - ("WET", "WET"), - ("Zulu", "Zulu"), - ], - ), - ( - "Pacific", - [ - ("Pacific/Apia", "Apia"), - ("Pacific/Auckland", "Auckland"), - ("Pacific/Bougainville", "Bougainville"), - ("Pacific/Chatham", "Chatham"), - ("Pacific/Chuuk", "Chuuk"), - ("Pacific/Easter", "Easter"), - ("Pacific/Efate", "Efate"), - ("Pacific/Enderbury", "Enderbury"), - ("Pacific/Fakaofo", "Fakaofo"), - ("Pacific/Fiji", "Fiji"), - ("Pacific/Funafuti", "Funafuti"), - ("Pacific/Galapagos", "Galapagos"), - ("Pacific/Gambier", "Gambier"), - ("Pacific/Guadalcanal", "Guadalcanal"), - ("Pacific/Guam", "Guam"), - ("Pacific/Honolulu", "Honolulu"), - ("Pacific/Johnston", "Johnston"), - ("Pacific/Kanton", "Kanton"), - ("Pacific/Kiritimati", "Kiritimati"), - ("Pacific/Kosrae", "Kosrae"), - ("Pacific/Kwajalein", "Kwajalein"), - ("Pacific/Majuro", "Majuro"), - ("Pacific/Marquesas", "Marquesas"), - ("Pacific/Midway", "Midway"), - ("Pacific/Nauru", "Nauru"), - ("Pacific/Niue", "Niue"), - ("Pacific/Norfolk", "Norfolk"), - ("Pacific/Noumea", "Noumea"), - ("Pacific/Pago_Pago", "Pago_Pago"), - ("Pacific/Palau", "Palau"), - ("Pacific/Pitcairn", "Pitcairn"), - ("Pacific/Pohnpei", "Pohnpei"), - ("Pacific/Ponape", "Ponape"), - ("Pacific/Port_Moresby", "Port_Moresby"), - ("Pacific/Rarotonga", "Rarotonga"), - ("Pacific/Saipan", "Saipan"), - ("Pacific/Samoa", "Samoa"), - ("Pacific/Tahiti", "Tahiti"), - ("Pacific/Tarawa", "Tarawa"), - ("Pacific/Tongatapu", "Tongatapu"), - ("Pacific/Truk", "Truk"), - ("Pacific/Wake", "Wake"), - ("Pacific/Wallis", "Wallis"), - ("Pacific/Yap", "Yap"), - ], - ), - ( - "US", - [ - ("US/Alaska", "Alaska"), - ("US/Aleutian", "Aleutian"), - ("US/Arizona", "Arizona"), - ("US/Central", "Central"), - ("US/East-Indiana", "East-Indiana"), - ("US/Eastern", "Eastern"), - ("US/Hawaii", "Hawaii"), - ("US/Indiana-Starke", "Indiana-Starke"), - ("US/Michigan", "Michigan"), - ("US/Mountain", "Mountain"), - ("US/Pacific", "Pacific"), - ("US/Samoa", "Samoa"), - ], - ), - ], - default="Asia/Ho_Chi_Minh", - max_length=50, - verbose_name="location", - ), - ), - migrations.CreateModel( - name="OrganizationProfile", - fields=[ - ( - "last_visit", - models.AutoField( - primary_key=True, serialize=False, verbose_name="last visit" - ), - ), - ( - "organization", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="last_vist", - to="judge.Organization", - verbose_name="organization", - ), - ), - ( - "users", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="last_visit", - to="judge.Profile", - verbose_name="user", - ), - ), - ], - ), - ] diff --git a/judge/migrations/0135_auto_20221028_0300.py b/judge/migrations/0135_auto_20221028_0300.py deleted file mode 100644 index 6a0840e..0000000 --- a/judge/migrations/0135_auto_20221028_0300.py +++ /dev/null @@ -1,676 +0,0 @@ -# Generated by Django 2.2.25 on 2022-10-27 20:00 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0134_auto_20221018_0124"), - ] - - operations = [ - migrations.AlterField( - model_name="profile", - name="timezone", - field=models.CharField( - choices=[ - ( - "Africa", - [ - ("Africa/Abidjan", "Abidjan"), - ("Africa/Accra", "Accra"), - ("Africa/Addis_Ababa", "Addis_Ababa"), - ("Africa/Algiers", "Algiers"), - ("Africa/Asmara", "Asmara"), - ("Africa/Asmera", "Asmera"), - ("Africa/Bamako", "Bamako"), - ("Africa/Bangui", "Bangui"), - ("Africa/Banjul", "Banjul"), - ("Africa/Bissau", "Bissau"), - ("Africa/Blantyre", "Blantyre"), - ("Africa/Brazzaville", "Brazzaville"), - ("Africa/Bujumbura", "Bujumbura"), - ("Africa/Cairo", "Cairo"), - ("Africa/Casablanca", "Casablanca"), - ("Africa/Ceuta", "Ceuta"), - ("Africa/Conakry", "Conakry"), - ("Africa/Dakar", "Dakar"), - ("Africa/Dar_es_Salaam", "Dar_es_Salaam"), - ("Africa/Djibouti", "Djibouti"), - ("Africa/Douala", "Douala"), - ("Africa/El_Aaiun", "El_Aaiun"), - ("Africa/Freetown", "Freetown"), - ("Africa/Gaborone", "Gaborone"), - ("Africa/Harare", "Harare"), - ("Africa/Johannesburg", "Johannesburg"), - ("Africa/Juba", "Juba"), - ("Africa/Kampala", "Kampala"), - ("Africa/Khartoum", "Khartoum"), - ("Africa/Kigali", "Kigali"), - ("Africa/Kinshasa", "Kinshasa"), - ("Africa/Lagos", "Lagos"), - ("Africa/Libreville", "Libreville"), - ("Africa/Lome", "Lome"), - ("Africa/Luanda", "Luanda"), - ("Africa/Lubumbashi", "Lubumbashi"), - ("Africa/Lusaka", "Lusaka"), - ("Africa/Malabo", "Malabo"), - ("Africa/Maputo", "Maputo"), - ("Africa/Maseru", "Maseru"), - ("Africa/Mbabane", "Mbabane"), - ("Africa/Mogadishu", "Mogadishu"), - ("Africa/Monrovia", "Monrovia"), - ("Africa/Nairobi", "Nairobi"), - ("Africa/Ndjamena", "Ndjamena"), - ("Africa/Niamey", "Niamey"), - ("Africa/Nouakchott", "Nouakchott"), - ("Africa/Ouagadougou", "Ouagadougou"), - ("Africa/Porto-Novo", "Porto-Novo"), - ("Africa/Sao_Tome", "Sao_Tome"), - ("Africa/Timbuktu", "Timbuktu"), - ("Africa/Tripoli", "Tripoli"), - ("Africa/Tunis", "Tunis"), - ("Africa/Windhoek", "Windhoek"), - ], - ), - ( - "America", - [ - ("America/Adak", "Adak"), - ("America/Anchorage", "Anchorage"), - ("America/Anguilla", "Anguilla"), - ("America/Antigua", "Antigua"), - ("America/Araguaina", "Araguaina"), - ( - "America/Argentina/Buenos_Aires", - "Argentina/Buenos_Aires", - ), - ("America/Argentina/Catamarca", "Argentina/Catamarca"), - ( - "America/Argentina/ComodRivadavia", - "Argentina/ComodRivadavia", - ), - ("America/Argentina/Cordoba", "Argentina/Cordoba"), - ("America/Argentina/Jujuy", "Argentina/Jujuy"), - ("America/Argentina/La_Rioja", "Argentina/La_Rioja"), - ("America/Argentina/Mendoza", "Argentina/Mendoza"), - ( - "America/Argentina/Rio_Gallegos", - "Argentina/Rio_Gallegos", - ), - ("America/Argentina/Salta", "Argentina/Salta"), - ("America/Argentina/San_Juan", "Argentina/San_Juan"), - ("America/Argentina/San_Luis", "Argentina/San_Luis"), - ("America/Argentina/Tucuman", "Argentina/Tucuman"), - ("America/Argentina/Ushuaia", "Argentina/Ushuaia"), - ("America/Aruba", "Aruba"), - ("America/Asuncion", "Asuncion"), - ("America/Atikokan", "Atikokan"), - ("America/Atka", "Atka"), - ("America/Bahia", "Bahia"), - ("America/Bahia_Banderas", "Bahia_Banderas"), - ("America/Barbados", "Barbados"), - ("America/Belem", "Belem"), - ("America/Belize", "Belize"), - ("America/Blanc-Sablon", "Blanc-Sablon"), - ("America/Boa_Vista", "Boa_Vista"), - ("America/Bogota", "Bogota"), - ("America/Boise", "Boise"), - ("America/Buenos_Aires", "Buenos_Aires"), - ("America/Cambridge_Bay", "Cambridge_Bay"), - ("America/Campo_Grande", "Campo_Grande"), - ("America/Cancun", "Cancun"), - ("America/Caracas", "Caracas"), - ("America/Catamarca", "Catamarca"), - ("America/Cayenne", "Cayenne"), - ("America/Cayman", "Cayman"), - ("America/Chicago", "Chicago"), - ("America/Chihuahua", "Chihuahua"), - ("America/Coral_Harbour", "Coral_Harbour"), - ("America/Cordoba", "Cordoba"), - ("America/Costa_Rica", "Costa_Rica"), - ("America/Creston", "Creston"), - ("America/Cuiaba", "Cuiaba"), - ("America/Curacao", "Curacao"), - ("America/Danmarkshavn", "Danmarkshavn"), - ("America/Dawson", "Dawson"), - ("America/Dawson_Creek", "Dawson_Creek"), - ("America/Denver", "Denver"), - ("America/Detroit", "Detroit"), - ("America/Dominica", "Dominica"), - ("America/Edmonton", "Edmonton"), - ("America/Eirunepe", "Eirunepe"), - ("America/El_Salvador", "El_Salvador"), - ("America/Ensenada", "Ensenada"), - ("America/Fort_Nelson", "Fort_Nelson"), - ("America/Fort_Wayne", "Fort_Wayne"), - ("America/Fortaleza", "Fortaleza"), - ("America/Glace_Bay", "Glace_Bay"), - ("America/Godthab", "Godthab"), - ("America/Goose_Bay", "Goose_Bay"), - ("America/Grand_Turk", "Grand_Turk"), - ("America/Grenada", "Grenada"), - ("America/Guadeloupe", "Guadeloupe"), - ("America/Guatemala", "Guatemala"), - ("America/Guayaquil", "Guayaquil"), - ("America/Guyana", "Guyana"), - ("America/Halifax", "Halifax"), - ("America/Havana", "Havana"), - ("America/Hermosillo", "Hermosillo"), - ("America/Indiana/Indianapolis", "Indiana/Indianapolis"), - ("America/Indiana/Knox", "Indiana/Knox"), - ("America/Indiana/Marengo", "Indiana/Marengo"), - ("America/Indiana/Petersburg", "Indiana/Petersburg"), - ("America/Indiana/Tell_City", "Indiana/Tell_City"), - ("America/Indiana/Vevay", "Indiana/Vevay"), - ("America/Indiana/Vincennes", "Indiana/Vincennes"), - ("America/Indiana/Winamac", "Indiana/Winamac"), - ("America/Indianapolis", "Indianapolis"), - ("America/Inuvik", "Inuvik"), - ("America/Iqaluit", "Iqaluit"), - ("America/Jamaica", "Jamaica"), - ("America/Jujuy", "Jujuy"), - ("America/Juneau", "Juneau"), - ("America/Kentucky/Louisville", "Kentucky/Louisville"), - ("America/Kentucky/Monticello", "Kentucky/Monticello"), - ("America/Knox_IN", "Knox_IN"), - ("America/Kralendijk", "Kralendijk"), - ("America/La_Paz", "La_Paz"), - ("America/Lima", "Lima"), - ("America/Los_Angeles", "Los_Angeles"), - ("America/Louisville", "Louisville"), - ("America/Lower_Princes", "Lower_Princes"), - ("America/Maceio", "Maceio"), - ("America/Managua", "Managua"), - ("America/Manaus", "Manaus"), - ("America/Marigot", "Marigot"), - ("America/Martinique", "Martinique"), - ("America/Matamoros", "Matamoros"), - ("America/Mazatlan", "Mazatlan"), - ("America/Mendoza", "Mendoza"), - ("America/Menominee", "Menominee"), - ("America/Merida", "Merida"), - ("America/Metlakatla", "Metlakatla"), - ("America/Mexico_City", "Mexico_City"), - ("America/Miquelon", "Miquelon"), - ("America/Moncton", "Moncton"), - ("America/Monterrey", "Monterrey"), - ("America/Montevideo", "Montevideo"), - ("America/Montreal", "Montreal"), - ("America/Montserrat", "Montserrat"), - ("America/Nassau", "Nassau"), - ("America/New_York", "New_York"), - ("America/Nipigon", "Nipigon"), - ("America/Nome", "Nome"), - ("America/Noronha", "Noronha"), - ("America/North_Dakota/Beulah", "North_Dakota/Beulah"), - ("America/North_Dakota/Center", "North_Dakota/Center"), - ( - "America/North_Dakota/New_Salem", - "North_Dakota/New_Salem", - ), - ("America/Nuuk", "Nuuk"), - ("America/Ojinaga", "Ojinaga"), - ("America/Panama", "Panama"), - ("America/Pangnirtung", "Pangnirtung"), - ("America/Paramaribo", "Paramaribo"), - ("America/Phoenix", "Phoenix"), - ("America/Port-au-Prince", "Port-au-Prince"), - ("America/Port_of_Spain", "Port_of_Spain"), - ("America/Porto_Acre", "Porto_Acre"), - ("America/Porto_Velho", "Porto_Velho"), - ("America/Puerto_Rico", "Puerto_Rico"), - ("America/Punta_Arenas", "Punta_Arenas"), - ("America/Rainy_River", "Rainy_River"), - ("America/Rankin_Inlet", "Rankin_Inlet"), - ("America/Recife", "Recife"), - ("America/Regina", "Regina"), - ("America/Resolute", "Resolute"), - ("America/Rio_Branco", "Rio_Branco"), - ("America/Rosario", "Rosario"), - ("America/Santa_Isabel", "Santa_Isabel"), - ("America/Santarem", "Santarem"), - ("America/Santiago", "Santiago"), - ("America/Santo_Domingo", "Santo_Domingo"), - ("America/Sao_Paulo", "Sao_Paulo"), - ("America/Scoresbysund", "Scoresbysund"), - ("America/Shiprock", "Shiprock"), - ("America/Sitka", "Sitka"), - ("America/St_Barthelemy", "St_Barthelemy"), - ("America/St_Johns", "St_Johns"), - ("America/St_Kitts", "St_Kitts"), - ("America/St_Lucia", "St_Lucia"), - ("America/St_Thomas", "St_Thomas"), - ("America/St_Vincent", "St_Vincent"), - ("America/Swift_Current", "Swift_Current"), - ("America/Tegucigalpa", "Tegucigalpa"), - ("America/Thule", "Thule"), - ("America/Thunder_Bay", "Thunder_Bay"), - ("America/Tijuana", "Tijuana"), - ("America/Toronto", "Toronto"), - ("America/Tortola", "Tortola"), - ("America/Vancouver", "Vancouver"), - ("America/Virgin", "Virgin"), - ("America/Whitehorse", "Whitehorse"), - ("America/Winnipeg", "Winnipeg"), - ("America/Yakutat", "Yakutat"), - ("America/Yellowknife", "Yellowknife"), - ], - ), - ( - "Antarctica", - [ - ("Antarctica/Casey", "Casey"), - ("Antarctica/Davis", "Davis"), - ("Antarctica/DumontDUrville", "DumontDUrville"), - ("Antarctica/Macquarie", "Macquarie"), - ("Antarctica/Mawson", "Mawson"), - ("Antarctica/McMurdo", "McMurdo"), - ("Antarctica/Palmer", "Palmer"), - ("Antarctica/Rothera", "Rothera"), - ("Antarctica/South_Pole", "South_Pole"), - ("Antarctica/Syowa", "Syowa"), - ("Antarctica/Troll", "Troll"), - ("Antarctica/Vostok", "Vostok"), - ], - ), - ("Arctic", [("Arctic/Longyearbyen", "Longyearbyen")]), - ( - "Asia", - [ - ("Asia/Aden", "Aden"), - ("Asia/Almaty", "Almaty"), - ("Asia/Amman", "Amman"), - ("Asia/Anadyr", "Anadyr"), - ("Asia/Aqtau", "Aqtau"), - ("Asia/Aqtobe", "Aqtobe"), - ("Asia/Ashgabat", "Ashgabat"), - ("Asia/Ashkhabad", "Ashkhabad"), - ("Asia/Atyrau", "Atyrau"), - ("Asia/Baghdad", "Baghdad"), - ("Asia/Bahrain", "Bahrain"), - ("Asia/Baku", "Baku"), - ("Asia/Bangkok", "Bangkok"), - ("Asia/Barnaul", "Barnaul"), - ("Asia/Beirut", "Beirut"), - ("Asia/Bishkek", "Bishkek"), - ("Asia/Brunei", "Brunei"), - ("Asia/Calcutta", "Calcutta"), - ("Asia/Chita", "Chita"), - ("Asia/Choibalsan", "Choibalsan"), - ("Asia/Chongqing", "Chongqing"), - ("Asia/Chungking", "Chungking"), - ("Asia/Colombo", "Colombo"), - ("Asia/Dacca", "Dacca"), - ("Asia/Damascus", "Damascus"), - ("Asia/Dhaka", "Dhaka"), - ("Asia/Dili", "Dili"), - ("Asia/Dubai", "Dubai"), - ("Asia/Dushanbe", "Dushanbe"), - ("Asia/Famagusta", "Famagusta"), - ("Asia/Gaza", "Gaza"), - ("Asia/Harbin", "Harbin"), - ("Asia/Hebron", "Hebron"), - ("Asia/Ho_Chi_Minh", "Ho_Chi_Minh"), - ("Asia/Hong_Kong", "Hong_Kong"), - ("Asia/Hovd", "Hovd"), - ("Asia/Irkutsk", "Irkutsk"), - ("Asia/Istanbul", "Istanbul"), - ("Asia/Jakarta", "Jakarta"), - ("Asia/Jayapura", "Jayapura"), - ("Asia/Jerusalem", "Jerusalem"), - ("Asia/Kabul", "Kabul"), - ("Asia/Kamchatka", "Kamchatka"), - ("Asia/Karachi", "Karachi"), - ("Asia/Kashgar", "Kashgar"), - ("Asia/Kathmandu", "Kathmandu"), - ("Asia/Katmandu", "Katmandu"), - ("Asia/Khandyga", "Khandyga"), - ("Asia/Kolkata", "Kolkata"), - ("Asia/Krasnoyarsk", "Krasnoyarsk"), - ("Asia/Kuala_Lumpur", "Kuala_Lumpur"), - ("Asia/Kuching", "Kuching"), - ("Asia/Kuwait", "Kuwait"), - ("Asia/Macao", "Macao"), - ("Asia/Macau", "Macau"), - ("Asia/Magadan", "Magadan"), - ("Asia/Makassar", "Makassar"), - ("Asia/Manila", "Manila"), - ("Asia/Muscat", "Muscat"), - ("Asia/Nicosia", "Nicosia"), - ("Asia/Novokuznetsk", "Novokuznetsk"), - ("Asia/Novosibirsk", "Novosibirsk"), - ("Asia/Omsk", "Omsk"), - ("Asia/Oral", "Oral"), - ("Asia/Phnom_Penh", "Phnom_Penh"), - ("Asia/Pontianak", "Pontianak"), - ("Asia/Pyongyang", "Pyongyang"), - ("Asia/Qatar", "Qatar"), - ("Asia/Qostanay", "Qostanay"), - ("Asia/Qyzylorda", "Qyzylorda"), - ("Asia/Rangoon", "Rangoon"), - ("Asia/Riyadh", "Riyadh"), - ("Asia/Saigon", "Saigon"), - ("Asia/Sakhalin", "Sakhalin"), - ("Asia/Samarkand", "Samarkand"), - ("Asia/Seoul", "Seoul"), - ("Asia/Shanghai", "Shanghai"), - ("Asia/Singapore", "Singapore"), - ("Asia/Srednekolymsk", "Srednekolymsk"), - ("Asia/Taipei", "Taipei"), - ("Asia/Tashkent", "Tashkent"), - ("Asia/Tbilisi", "Tbilisi"), - ("Asia/Tehran", "Tehran"), - ("Asia/Tel_Aviv", "Tel_Aviv"), - ("Asia/Thimbu", "Thimbu"), - ("Asia/Thimphu", "Thimphu"), - ("Asia/Tokyo", "Tokyo"), - ("Asia/Tomsk", "Tomsk"), - ("Asia/Ujung_Pandang", "Ujung_Pandang"), - ("Asia/Ulaanbaatar", "Ulaanbaatar"), - ("Asia/Ulan_Bator", "Ulan_Bator"), - ("Asia/Urumqi", "Urumqi"), - ("Asia/Ust-Nera", "Ust-Nera"), - ("Asia/Vientiane", "Vientiane"), - ("Asia/Vladivostok", "Vladivostok"), - ("Asia/Yakutsk", "Yakutsk"), - ("Asia/Yangon", "Yangon"), - ("Asia/Yekaterinburg", "Yekaterinburg"), - ("Asia/Yerevan", "Yerevan"), - ], - ), - ( - "Atlantic", - [ - ("Atlantic/Azores", "Azores"), - ("Atlantic/Bermuda", "Bermuda"), - ("Atlantic/Canary", "Canary"), - ("Atlantic/Cape_Verde", "Cape_Verde"), - ("Atlantic/Faeroe", "Faeroe"), - ("Atlantic/Faroe", "Faroe"), - ("Atlantic/Jan_Mayen", "Jan_Mayen"), - ("Atlantic/Madeira", "Madeira"), - ("Atlantic/Reykjavik", "Reykjavik"), - ("Atlantic/South_Georgia", "South_Georgia"), - ("Atlantic/St_Helena", "St_Helena"), - ("Atlantic/Stanley", "Stanley"), - ], - ), - ( - "Australia", - [ - ("Australia/ACT", "ACT"), - ("Australia/Adelaide", "Adelaide"), - ("Australia/Brisbane", "Brisbane"), - ("Australia/Broken_Hill", "Broken_Hill"), - ("Australia/Canberra", "Canberra"), - ("Australia/Currie", "Currie"), - ("Australia/Darwin", "Darwin"), - ("Australia/Eucla", "Eucla"), - ("Australia/Hobart", "Hobart"), - ("Australia/LHI", "LHI"), - ("Australia/Lindeman", "Lindeman"), - ("Australia/Lord_Howe", "Lord_Howe"), - ("Australia/Melbourne", "Melbourne"), - ("Australia/NSW", "NSW"), - ("Australia/North", "North"), - ("Australia/Perth", "Perth"), - ("Australia/Queensland", "Queensland"), - ("Australia/South", "South"), - ("Australia/Sydney", "Sydney"), - ("Australia/Tasmania", "Tasmania"), - ("Australia/Victoria", "Victoria"), - ("Australia/West", "West"), - ("Australia/Yancowinna", "Yancowinna"), - ], - ), - ( - "Brazil", - [ - ("Brazil/Acre", "Acre"), - ("Brazil/DeNoronha", "DeNoronha"), - ("Brazil/East", "East"), - ("Brazil/West", "West"), - ], - ), - ( - "Canada", - [ - ("Canada/Atlantic", "Atlantic"), - ("Canada/Central", "Central"), - ("Canada/Eastern", "Eastern"), - ("Canada/Mountain", "Mountain"), - ("Canada/Newfoundland", "Newfoundland"), - ("Canada/Pacific", "Pacific"), - ("Canada/Saskatchewan", "Saskatchewan"), - ("Canada/Yukon", "Yukon"), - ], - ), - ( - "Chile", - [ - ("Chile/Continental", "Continental"), - ("Chile/EasterIsland", "EasterIsland"), - ], - ), - ( - "Etc", - [ - ("Etc/Greenwich", "Greenwich"), - ("Etc/UCT", "UCT"), - ("Etc/UTC", "UTC"), - ("Etc/Universal", "Universal"), - ("Etc/Zulu", "Zulu"), - ], - ), - ( - "Europe", - [ - ("Europe/Amsterdam", "Amsterdam"), - ("Europe/Andorra", "Andorra"), - ("Europe/Astrakhan", "Astrakhan"), - ("Europe/Athens", "Athens"), - ("Europe/Belfast", "Belfast"), - ("Europe/Belgrade", "Belgrade"), - ("Europe/Berlin", "Berlin"), - ("Europe/Bratislava", "Bratislava"), - ("Europe/Brussels", "Brussels"), - ("Europe/Bucharest", "Bucharest"), - ("Europe/Budapest", "Budapest"), - ("Europe/Busingen", "Busingen"), - ("Europe/Chisinau", "Chisinau"), - ("Europe/Copenhagen", "Copenhagen"), - ("Europe/Dublin", "Dublin"), - ("Europe/Gibraltar", "Gibraltar"), - ("Europe/Guernsey", "Guernsey"), - ("Europe/Helsinki", "Helsinki"), - ("Europe/Isle_of_Man", "Isle_of_Man"), - ("Europe/Istanbul", "Istanbul"), - ("Europe/Jersey", "Jersey"), - ("Europe/Kaliningrad", "Kaliningrad"), - ("Europe/Kiev", "Kiev"), - ("Europe/Kirov", "Kirov"), - ("Europe/Lisbon", "Lisbon"), - ("Europe/Ljubljana", "Ljubljana"), - ("Europe/London", "London"), - ("Europe/Luxembourg", "Luxembourg"), - ("Europe/Madrid", "Madrid"), - ("Europe/Malta", "Malta"), - ("Europe/Mariehamn", "Mariehamn"), - ("Europe/Minsk", "Minsk"), - ("Europe/Monaco", "Monaco"), - ("Europe/Moscow", "Moscow"), - ("Europe/Nicosia", "Nicosia"), - ("Europe/Oslo", "Oslo"), - ("Europe/Paris", "Paris"), - ("Europe/Podgorica", "Podgorica"), - ("Europe/Prague", "Prague"), - ("Europe/Riga", "Riga"), - ("Europe/Rome", "Rome"), - ("Europe/Samara", "Samara"), - ("Europe/San_Marino", "San_Marino"), - ("Europe/Sarajevo", "Sarajevo"), - ("Europe/Saratov", "Saratov"), - ("Europe/Simferopol", "Simferopol"), - ("Europe/Skopje", "Skopje"), - ("Europe/Sofia", "Sofia"), - ("Europe/Stockholm", "Stockholm"), - ("Europe/Tallinn", "Tallinn"), - ("Europe/Tirane", "Tirane"), - ("Europe/Tiraspol", "Tiraspol"), - ("Europe/Ulyanovsk", "Ulyanovsk"), - ("Europe/Uzhgorod", "Uzhgorod"), - ("Europe/Vaduz", "Vaduz"), - ("Europe/Vatican", "Vatican"), - ("Europe/Vienna", "Vienna"), - ("Europe/Vilnius", "Vilnius"), - ("Europe/Volgograd", "Volgograd"), - ("Europe/Warsaw", "Warsaw"), - ("Europe/Zagreb", "Zagreb"), - ("Europe/Zaporozhye", "Zaporozhye"), - ("Europe/Zurich", "Zurich"), - ], - ), - ( - "Indian", - [ - ("Indian/Antananarivo", "Antananarivo"), - ("Indian/Chagos", "Chagos"), - ("Indian/Christmas", "Christmas"), - ("Indian/Cocos", "Cocos"), - ("Indian/Comoro", "Comoro"), - ("Indian/Kerguelen", "Kerguelen"), - ("Indian/Mahe", "Mahe"), - ("Indian/Maldives", "Maldives"), - ("Indian/Mauritius", "Mauritius"), - ("Indian/Mayotte", "Mayotte"), - ("Indian/Reunion", "Reunion"), - ], - ), - ( - "Mexico", - [ - ("Mexico/BajaNorte", "BajaNorte"), - ("Mexico/BajaSur", "BajaSur"), - ("Mexico/General", "General"), - ], - ), - ( - "Other", - [ - ("CET", "CET"), - ("CST6CDT", "CST6CDT"), - ("Cuba", "Cuba"), - ("EET", "EET"), - ("EST", "EST"), - ("EST5EDT", "EST5EDT"), - ("Egypt", "Egypt"), - ("Eire", "Eire"), - ("GB", "GB"), - ("GB-Eire", "GB-Eire"), - ("Greenwich", "Greenwich"), - ("HST", "HST"), - ("Hongkong", "Hongkong"), - ("Iceland", "Iceland"), - ("Iran", "Iran"), - ("Israel", "Israel"), - ("Jamaica", "Jamaica"), - ("Japan", "Japan"), - ("Kwajalein", "Kwajalein"), - ("Libya", "Libya"), - ("MET", "MET"), - ("MST", "MST"), - ("MST7MDT", "MST7MDT"), - ("NZ", "NZ"), - ("NZ-CHAT", "NZ-CHAT"), - ("Navajo", "Navajo"), - ("PRC", "PRC"), - ("PST8PDT", "PST8PDT"), - ("Poland", "Poland"), - ("Portugal", "Portugal"), - ("ROC", "ROC"), - ("ROK", "ROK"), - ("Singapore", "Singapore"), - ("Turkey", "Turkey"), - ("UCT", "UCT"), - ("UTC", "UTC"), - ("Universal", "Universal"), - ("W-SU", "W-SU"), - ("WET", "WET"), - ("Zulu", "Zulu"), - ], - ), - ( - "Pacific", - [ - ("Pacific/Apia", "Apia"), - ("Pacific/Auckland", "Auckland"), - ("Pacific/Bougainville", "Bougainville"), - ("Pacific/Chatham", "Chatham"), - ("Pacific/Chuuk", "Chuuk"), - ("Pacific/Easter", "Easter"), - ("Pacific/Efate", "Efate"), - ("Pacific/Enderbury", "Enderbury"), - ("Pacific/Fakaofo", "Fakaofo"), - ("Pacific/Fiji", "Fiji"), - ("Pacific/Funafuti", "Funafuti"), - ("Pacific/Galapagos", "Galapagos"), - ("Pacific/Gambier", "Gambier"), - ("Pacific/Guadalcanal", "Guadalcanal"), - ("Pacific/Guam", "Guam"), - ("Pacific/Honolulu", "Honolulu"), - ("Pacific/Johnston", "Johnston"), - ("Pacific/Kanton", "Kanton"), - ("Pacific/Kiritimati", "Kiritimati"), - ("Pacific/Kosrae", "Kosrae"), - ("Pacific/Kwajalein", "Kwajalein"), - ("Pacific/Majuro", "Majuro"), - ("Pacific/Marquesas", "Marquesas"), - ("Pacific/Midway", "Midway"), - ("Pacific/Nauru", "Nauru"), - ("Pacific/Niue", "Niue"), - ("Pacific/Norfolk", "Norfolk"), - ("Pacific/Noumea", "Noumea"), - ("Pacific/Pago_Pago", "Pago_Pago"), - ("Pacific/Palau", "Palau"), - ("Pacific/Pitcairn", "Pitcairn"), - ("Pacific/Pohnpei", "Pohnpei"), - ("Pacific/Ponape", "Ponape"), - ("Pacific/Port_Moresby", "Port_Moresby"), - ("Pacific/Rarotonga", "Rarotonga"), - ("Pacific/Saipan", "Saipan"), - ("Pacific/Samoa", "Samoa"), - ("Pacific/Tahiti", "Tahiti"), - ("Pacific/Tarawa", "Tarawa"), - ("Pacific/Tongatapu", "Tongatapu"), - ("Pacific/Truk", "Truk"), - ("Pacific/Wake", "Wake"), - ("Pacific/Wallis", "Wallis"), - ("Pacific/Yap", "Yap"), - ], - ), - ( - "US", - [ - ("US/Alaska", "Alaska"), - ("US/Aleutian", "Aleutian"), - ("US/Arizona", "Arizona"), - ("US/Central", "Central"), - ("US/East-Indiana", "East-Indiana"), - ("US/Eastern", "Eastern"), - ("US/Hawaii", "Hawaii"), - ("US/Indiana-Starke", "Indiana-Starke"), - ("US/Michigan", "Michigan"), - ("US/Mountain", "Mountain"), - ("US/Pacific", "Pacific"), - ("US/Samoa", "Samoa"), - ], - ), - ], - default="Asia/Ho_Chi_Minh", - max_length=50, - verbose_name="location", - ), - ), - ] diff --git a/judge/migrations/0136_alter_profile_timezone.py b/judge/migrations/0136_alter_profile_timezone.py deleted file mode 100644 index 75615b1..0000000 --- a/judge/migrations/0136_alter_profile_timezone.py +++ /dev/null @@ -1,677 +0,0 @@ -# Generated by Django 3.2.16 on 2022-11-01 01:05 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0135_auto_20221028_0300"), - ] - - operations = [ - migrations.AlterField( - model_name="profile", - name="timezone", - field=models.CharField( - choices=[ - ( - "Africa", - [ - ("Africa/Abidjan", "Abidjan"), - ("Africa/Accra", "Accra"), - ("Africa/Addis_Ababa", "Addis_Ababa"), - ("Africa/Algiers", "Algiers"), - ("Africa/Asmara", "Asmara"), - ("Africa/Asmera", "Asmera"), - ("Africa/Bamako", "Bamako"), - ("Africa/Bangui", "Bangui"), - ("Africa/Banjul", "Banjul"), - ("Africa/Bissau", "Bissau"), - ("Africa/Blantyre", "Blantyre"), - ("Africa/Brazzaville", "Brazzaville"), - ("Africa/Bujumbura", "Bujumbura"), - ("Africa/Cairo", "Cairo"), - ("Africa/Casablanca", "Casablanca"), - ("Africa/Ceuta", "Ceuta"), - ("Africa/Conakry", "Conakry"), - ("Africa/Dakar", "Dakar"), - ("Africa/Dar_es_Salaam", "Dar_es_Salaam"), - ("Africa/Djibouti", "Djibouti"), - ("Africa/Douala", "Douala"), - ("Africa/El_Aaiun", "El_Aaiun"), - ("Africa/Freetown", "Freetown"), - ("Africa/Gaborone", "Gaborone"), - ("Africa/Harare", "Harare"), - ("Africa/Johannesburg", "Johannesburg"), - ("Africa/Juba", "Juba"), - ("Africa/Kampala", "Kampala"), - ("Africa/Khartoum", "Khartoum"), - ("Africa/Kigali", "Kigali"), - ("Africa/Kinshasa", "Kinshasa"), - ("Africa/Lagos", "Lagos"), - ("Africa/Libreville", "Libreville"), - ("Africa/Lome", "Lome"), - ("Africa/Luanda", "Luanda"), - ("Africa/Lubumbashi", "Lubumbashi"), - ("Africa/Lusaka", "Lusaka"), - ("Africa/Malabo", "Malabo"), - ("Africa/Maputo", "Maputo"), - ("Africa/Maseru", "Maseru"), - ("Africa/Mbabane", "Mbabane"), - ("Africa/Mogadishu", "Mogadishu"), - ("Africa/Monrovia", "Monrovia"), - ("Africa/Nairobi", "Nairobi"), - ("Africa/Ndjamena", "Ndjamena"), - ("Africa/Niamey", "Niamey"), - ("Africa/Nouakchott", "Nouakchott"), - ("Africa/Ouagadougou", "Ouagadougou"), - ("Africa/Porto-Novo", "Porto-Novo"), - ("Africa/Sao_Tome", "Sao_Tome"), - ("Africa/Timbuktu", "Timbuktu"), - ("Africa/Tripoli", "Tripoli"), - ("Africa/Tunis", "Tunis"), - ("Africa/Windhoek", "Windhoek"), - ], - ), - ( - "America", - [ - ("America/Adak", "Adak"), - ("America/Anchorage", "Anchorage"), - ("America/Anguilla", "Anguilla"), - ("America/Antigua", "Antigua"), - ("America/Araguaina", "Araguaina"), - ( - "America/Argentina/Buenos_Aires", - "Argentina/Buenos_Aires", - ), - ("America/Argentina/Catamarca", "Argentina/Catamarca"), - ( - "America/Argentina/ComodRivadavia", - "Argentina/ComodRivadavia", - ), - ("America/Argentina/Cordoba", "Argentina/Cordoba"), - ("America/Argentina/Jujuy", "Argentina/Jujuy"), - ("America/Argentina/La_Rioja", "Argentina/La_Rioja"), - ("America/Argentina/Mendoza", "Argentina/Mendoza"), - ( - "America/Argentina/Rio_Gallegos", - "Argentina/Rio_Gallegos", - ), - ("America/Argentina/Salta", "Argentina/Salta"), - ("America/Argentina/San_Juan", "Argentina/San_Juan"), - ("America/Argentina/San_Luis", "Argentina/San_Luis"), - ("America/Argentina/Tucuman", "Argentina/Tucuman"), - ("America/Argentina/Ushuaia", "Argentina/Ushuaia"), - ("America/Aruba", "Aruba"), - ("America/Asuncion", "Asuncion"), - ("America/Atikokan", "Atikokan"), - ("America/Atka", "Atka"), - ("America/Bahia", "Bahia"), - ("America/Bahia_Banderas", "Bahia_Banderas"), - ("America/Barbados", "Barbados"), - ("America/Belem", "Belem"), - ("America/Belize", "Belize"), - ("America/Blanc-Sablon", "Blanc-Sablon"), - ("America/Boa_Vista", "Boa_Vista"), - ("America/Bogota", "Bogota"), - ("America/Boise", "Boise"), - ("America/Buenos_Aires", "Buenos_Aires"), - ("America/Cambridge_Bay", "Cambridge_Bay"), - ("America/Campo_Grande", "Campo_Grande"), - ("America/Cancun", "Cancun"), - ("America/Caracas", "Caracas"), - ("America/Catamarca", "Catamarca"), - ("America/Cayenne", "Cayenne"), - ("America/Cayman", "Cayman"), - ("America/Chicago", "Chicago"), - ("America/Chihuahua", "Chihuahua"), - ("America/Coral_Harbour", "Coral_Harbour"), - ("America/Cordoba", "Cordoba"), - ("America/Costa_Rica", "Costa_Rica"), - ("America/Creston", "Creston"), - ("America/Cuiaba", "Cuiaba"), - ("America/Curacao", "Curacao"), - ("America/Danmarkshavn", "Danmarkshavn"), - ("America/Dawson", "Dawson"), - ("America/Dawson_Creek", "Dawson_Creek"), - ("America/Denver", "Denver"), - ("America/Detroit", "Detroit"), - ("America/Dominica", "Dominica"), - ("America/Edmonton", "Edmonton"), - ("America/Eirunepe", "Eirunepe"), - ("America/El_Salvador", "El_Salvador"), - ("America/Ensenada", "Ensenada"), - ("America/Fort_Nelson", "Fort_Nelson"), - ("America/Fort_Wayne", "Fort_Wayne"), - ("America/Fortaleza", "Fortaleza"), - ("America/Glace_Bay", "Glace_Bay"), - ("America/Godthab", "Godthab"), - ("America/Goose_Bay", "Goose_Bay"), - ("America/Grand_Turk", "Grand_Turk"), - ("America/Grenada", "Grenada"), - ("America/Guadeloupe", "Guadeloupe"), - ("America/Guatemala", "Guatemala"), - ("America/Guayaquil", "Guayaquil"), - ("America/Guyana", "Guyana"), - ("America/Halifax", "Halifax"), - ("America/Havana", "Havana"), - ("America/Hermosillo", "Hermosillo"), - ("America/Indiana/Indianapolis", "Indiana/Indianapolis"), - ("America/Indiana/Knox", "Indiana/Knox"), - ("America/Indiana/Marengo", "Indiana/Marengo"), - ("America/Indiana/Petersburg", "Indiana/Petersburg"), - ("America/Indiana/Tell_City", "Indiana/Tell_City"), - ("America/Indiana/Vevay", "Indiana/Vevay"), - ("America/Indiana/Vincennes", "Indiana/Vincennes"), - ("America/Indiana/Winamac", "Indiana/Winamac"), - ("America/Indianapolis", "Indianapolis"), - ("America/Inuvik", "Inuvik"), - ("America/Iqaluit", "Iqaluit"), - ("America/Jamaica", "Jamaica"), - ("America/Jujuy", "Jujuy"), - ("America/Juneau", "Juneau"), - ("America/Kentucky/Louisville", "Kentucky/Louisville"), - ("America/Kentucky/Monticello", "Kentucky/Monticello"), - ("America/Knox_IN", "Knox_IN"), - ("America/Kralendijk", "Kralendijk"), - ("America/La_Paz", "La_Paz"), - ("America/Lima", "Lima"), - ("America/Los_Angeles", "Los_Angeles"), - ("America/Louisville", "Louisville"), - ("America/Lower_Princes", "Lower_Princes"), - ("America/Maceio", "Maceio"), - ("America/Managua", "Managua"), - ("America/Manaus", "Manaus"), - ("America/Marigot", "Marigot"), - ("America/Martinique", "Martinique"), - ("America/Matamoros", "Matamoros"), - ("America/Mazatlan", "Mazatlan"), - ("America/Mendoza", "Mendoza"), - ("America/Menominee", "Menominee"), - ("America/Merida", "Merida"), - ("America/Metlakatla", "Metlakatla"), - ("America/Mexico_City", "Mexico_City"), - ("America/Miquelon", "Miquelon"), - ("America/Moncton", "Moncton"), - ("America/Monterrey", "Monterrey"), - ("America/Montevideo", "Montevideo"), - ("America/Montreal", "Montreal"), - ("America/Montserrat", "Montserrat"), - ("America/Nassau", "Nassau"), - ("America/New_York", "New_York"), - ("America/Nipigon", "Nipigon"), - ("America/Nome", "Nome"), - ("America/Noronha", "Noronha"), - ("America/North_Dakota/Beulah", "North_Dakota/Beulah"), - ("America/North_Dakota/Center", "North_Dakota/Center"), - ( - "America/North_Dakota/New_Salem", - "North_Dakota/New_Salem", - ), - ("America/Nuuk", "Nuuk"), - ("America/Ojinaga", "Ojinaga"), - ("America/Panama", "Panama"), - ("America/Pangnirtung", "Pangnirtung"), - ("America/Paramaribo", "Paramaribo"), - ("America/Phoenix", "Phoenix"), - ("America/Port-au-Prince", "Port-au-Prince"), - ("America/Port_of_Spain", "Port_of_Spain"), - ("America/Porto_Acre", "Porto_Acre"), - ("America/Porto_Velho", "Porto_Velho"), - ("America/Puerto_Rico", "Puerto_Rico"), - ("America/Punta_Arenas", "Punta_Arenas"), - ("America/Rainy_River", "Rainy_River"), - ("America/Rankin_Inlet", "Rankin_Inlet"), - ("America/Recife", "Recife"), - ("America/Regina", "Regina"), - ("America/Resolute", "Resolute"), - ("America/Rio_Branco", "Rio_Branco"), - ("America/Rosario", "Rosario"), - ("America/Santa_Isabel", "Santa_Isabel"), - ("America/Santarem", "Santarem"), - ("America/Santiago", "Santiago"), - ("America/Santo_Domingo", "Santo_Domingo"), - ("America/Sao_Paulo", "Sao_Paulo"), - ("America/Scoresbysund", "Scoresbysund"), - ("America/Shiprock", "Shiprock"), - ("America/Sitka", "Sitka"), - ("America/St_Barthelemy", "St_Barthelemy"), - ("America/St_Johns", "St_Johns"), - ("America/St_Kitts", "St_Kitts"), - ("America/St_Lucia", "St_Lucia"), - ("America/St_Thomas", "St_Thomas"), - ("America/St_Vincent", "St_Vincent"), - ("America/Swift_Current", "Swift_Current"), - ("America/Tegucigalpa", "Tegucigalpa"), - ("America/Thule", "Thule"), - ("America/Thunder_Bay", "Thunder_Bay"), - ("America/Tijuana", "Tijuana"), - ("America/Toronto", "Toronto"), - ("America/Tortola", "Tortola"), - ("America/Vancouver", "Vancouver"), - ("America/Virgin", "Virgin"), - ("America/Whitehorse", "Whitehorse"), - ("America/Winnipeg", "Winnipeg"), - ("America/Yakutat", "Yakutat"), - ("America/Yellowknife", "Yellowknife"), - ], - ), - ( - "Antarctica", - [ - ("Antarctica/Casey", "Casey"), - ("Antarctica/Davis", "Davis"), - ("Antarctica/DumontDUrville", "DumontDUrville"), - ("Antarctica/Macquarie", "Macquarie"), - ("Antarctica/Mawson", "Mawson"), - ("Antarctica/McMurdo", "McMurdo"), - ("Antarctica/Palmer", "Palmer"), - ("Antarctica/Rothera", "Rothera"), - ("Antarctica/South_Pole", "South_Pole"), - ("Antarctica/Syowa", "Syowa"), - ("Antarctica/Troll", "Troll"), - ("Antarctica/Vostok", "Vostok"), - ], - ), - ("Arctic", [("Arctic/Longyearbyen", "Longyearbyen")]), - ( - "Asia", - [ - ("Asia/Aden", "Aden"), - ("Asia/Almaty", "Almaty"), - ("Asia/Amman", "Amman"), - ("Asia/Anadyr", "Anadyr"), - ("Asia/Aqtau", "Aqtau"), - ("Asia/Aqtobe", "Aqtobe"), - ("Asia/Ashgabat", "Ashgabat"), - ("Asia/Ashkhabad", "Ashkhabad"), - ("Asia/Atyrau", "Atyrau"), - ("Asia/Baghdad", "Baghdad"), - ("Asia/Bahrain", "Bahrain"), - ("Asia/Baku", "Baku"), - ("Asia/Bangkok", "Bangkok"), - ("Asia/Barnaul", "Barnaul"), - ("Asia/Beirut", "Beirut"), - ("Asia/Bishkek", "Bishkek"), - ("Asia/Brunei", "Brunei"), - ("Asia/Calcutta", "Calcutta"), - ("Asia/Chita", "Chita"), - ("Asia/Choibalsan", "Choibalsan"), - ("Asia/Chongqing", "Chongqing"), - ("Asia/Chungking", "Chungking"), - ("Asia/Colombo", "Colombo"), - ("Asia/Dacca", "Dacca"), - ("Asia/Damascus", "Damascus"), - ("Asia/Dhaka", "Dhaka"), - ("Asia/Dili", "Dili"), - ("Asia/Dubai", "Dubai"), - ("Asia/Dushanbe", "Dushanbe"), - ("Asia/Famagusta", "Famagusta"), - ("Asia/Gaza", "Gaza"), - ("Asia/Harbin", "Harbin"), - ("Asia/Hebron", "Hebron"), - ("Asia/Ho_Chi_Minh", "Ho_Chi_Minh"), - ("Asia/Hong_Kong", "Hong_Kong"), - ("Asia/Hovd", "Hovd"), - ("Asia/Irkutsk", "Irkutsk"), - ("Asia/Istanbul", "Istanbul"), - ("Asia/Jakarta", "Jakarta"), - ("Asia/Jayapura", "Jayapura"), - ("Asia/Jerusalem", "Jerusalem"), - ("Asia/Kabul", "Kabul"), - ("Asia/Kamchatka", "Kamchatka"), - ("Asia/Karachi", "Karachi"), - ("Asia/Kashgar", "Kashgar"), - ("Asia/Kathmandu", "Kathmandu"), - ("Asia/Katmandu", "Katmandu"), - ("Asia/Khandyga", "Khandyga"), - ("Asia/Kolkata", "Kolkata"), - ("Asia/Krasnoyarsk", "Krasnoyarsk"), - ("Asia/Kuala_Lumpur", "Kuala_Lumpur"), - ("Asia/Kuching", "Kuching"), - ("Asia/Kuwait", "Kuwait"), - ("Asia/Macao", "Macao"), - ("Asia/Macau", "Macau"), - ("Asia/Magadan", "Magadan"), - ("Asia/Makassar", "Makassar"), - ("Asia/Manila", "Manila"), - ("Asia/Muscat", "Muscat"), - ("Asia/Nicosia", "Nicosia"), - ("Asia/Novokuznetsk", "Novokuznetsk"), - ("Asia/Novosibirsk", "Novosibirsk"), - ("Asia/Omsk", "Omsk"), - ("Asia/Oral", "Oral"), - ("Asia/Phnom_Penh", "Phnom_Penh"), - ("Asia/Pontianak", "Pontianak"), - ("Asia/Pyongyang", "Pyongyang"), - ("Asia/Qatar", "Qatar"), - ("Asia/Qostanay", "Qostanay"), - ("Asia/Qyzylorda", "Qyzylorda"), - ("Asia/Rangoon", "Rangoon"), - ("Asia/Riyadh", "Riyadh"), - ("Asia/Saigon", "Saigon"), - ("Asia/Sakhalin", "Sakhalin"), - ("Asia/Samarkand", "Samarkand"), - ("Asia/Seoul", "Seoul"), - ("Asia/Shanghai", "Shanghai"), - ("Asia/Singapore", "Singapore"), - ("Asia/Srednekolymsk", "Srednekolymsk"), - ("Asia/Taipei", "Taipei"), - ("Asia/Tashkent", "Tashkent"), - ("Asia/Tbilisi", "Tbilisi"), - ("Asia/Tehran", "Tehran"), - ("Asia/Tel_Aviv", "Tel_Aviv"), - ("Asia/Thimbu", "Thimbu"), - ("Asia/Thimphu", "Thimphu"), - ("Asia/Tokyo", "Tokyo"), - ("Asia/Tomsk", "Tomsk"), - ("Asia/Ujung_Pandang", "Ujung_Pandang"), - ("Asia/Ulaanbaatar", "Ulaanbaatar"), - ("Asia/Ulan_Bator", "Ulan_Bator"), - ("Asia/Urumqi", "Urumqi"), - ("Asia/Ust-Nera", "Ust-Nera"), - ("Asia/Vientiane", "Vientiane"), - ("Asia/Vladivostok", "Vladivostok"), - ("Asia/Yakutsk", "Yakutsk"), - ("Asia/Yangon", "Yangon"), - ("Asia/Yekaterinburg", "Yekaterinburg"), - ("Asia/Yerevan", "Yerevan"), - ], - ), - ( - "Atlantic", - [ - ("Atlantic/Azores", "Azores"), - ("Atlantic/Bermuda", "Bermuda"), - ("Atlantic/Canary", "Canary"), - ("Atlantic/Cape_Verde", "Cape_Verde"), - ("Atlantic/Faeroe", "Faeroe"), - ("Atlantic/Faroe", "Faroe"), - ("Atlantic/Jan_Mayen", "Jan_Mayen"), - ("Atlantic/Madeira", "Madeira"), - ("Atlantic/Reykjavik", "Reykjavik"), - ("Atlantic/South_Georgia", "South_Georgia"), - ("Atlantic/St_Helena", "St_Helena"), - ("Atlantic/Stanley", "Stanley"), - ], - ), - ( - "Australia", - [ - ("Australia/ACT", "ACT"), - ("Australia/Adelaide", "Adelaide"), - ("Australia/Brisbane", "Brisbane"), - ("Australia/Broken_Hill", "Broken_Hill"), - ("Australia/Canberra", "Canberra"), - ("Australia/Currie", "Currie"), - ("Australia/Darwin", "Darwin"), - ("Australia/Eucla", "Eucla"), - ("Australia/Hobart", "Hobart"), - ("Australia/LHI", "LHI"), - ("Australia/Lindeman", "Lindeman"), - ("Australia/Lord_Howe", "Lord_Howe"), - ("Australia/Melbourne", "Melbourne"), - ("Australia/NSW", "NSW"), - ("Australia/North", "North"), - ("Australia/Perth", "Perth"), - ("Australia/Queensland", "Queensland"), - ("Australia/South", "South"), - ("Australia/Sydney", "Sydney"), - ("Australia/Tasmania", "Tasmania"), - ("Australia/Victoria", "Victoria"), - ("Australia/West", "West"), - ("Australia/Yancowinna", "Yancowinna"), - ], - ), - ( - "Brazil", - [ - ("Brazil/Acre", "Acre"), - ("Brazil/DeNoronha", "DeNoronha"), - ("Brazil/East", "East"), - ("Brazil/West", "West"), - ], - ), - ( - "Canada", - [ - ("Canada/Atlantic", "Atlantic"), - ("Canada/Central", "Central"), - ("Canada/Eastern", "Eastern"), - ("Canada/Mountain", "Mountain"), - ("Canada/Newfoundland", "Newfoundland"), - ("Canada/Pacific", "Pacific"), - ("Canada/Saskatchewan", "Saskatchewan"), - ("Canada/Yukon", "Yukon"), - ], - ), - ( - "Chile", - [ - ("Chile/Continental", "Continental"), - ("Chile/EasterIsland", "EasterIsland"), - ], - ), - ( - "Etc", - [ - ("Etc/Greenwich", "Greenwich"), - ("Etc/UCT", "UCT"), - ("Etc/UTC", "UTC"), - ("Etc/Universal", "Universal"), - ("Etc/Zulu", "Zulu"), - ], - ), - ( - "Europe", - [ - ("Europe/Amsterdam", "Amsterdam"), - ("Europe/Andorra", "Andorra"), - ("Europe/Astrakhan", "Astrakhan"), - ("Europe/Athens", "Athens"), - ("Europe/Belfast", "Belfast"), - ("Europe/Belgrade", "Belgrade"), - ("Europe/Berlin", "Berlin"), - ("Europe/Bratislava", "Bratislava"), - ("Europe/Brussels", "Brussels"), - ("Europe/Bucharest", "Bucharest"), - ("Europe/Budapest", "Budapest"), - ("Europe/Busingen", "Busingen"), - ("Europe/Chisinau", "Chisinau"), - ("Europe/Copenhagen", "Copenhagen"), - ("Europe/Dublin", "Dublin"), - ("Europe/Gibraltar", "Gibraltar"), - ("Europe/Guernsey", "Guernsey"), - ("Europe/Helsinki", "Helsinki"), - ("Europe/Isle_of_Man", "Isle_of_Man"), - ("Europe/Istanbul", "Istanbul"), - ("Europe/Jersey", "Jersey"), - ("Europe/Kaliningrad", "Kaliningrad"), - ("Europe/Kiev", "Kiev"), - ("Europe/Kirov", "Kirov"), - ("Europe/Kyiv", "Kyiv"), - ("Europe/Lisbon", "Lisbon"), - ("Europe/Ljubljana", "Ljubljana"), - ("Europe/London", "London"), - ("Europe/Luxembourg", "Luxembourg"), - ("Europe/Madrid", "Madrid"), - ("Europe/Malta", "Malta"), - ("Europe/Mariehamn", "Mariehamn"), - ("Europe/Minsk", "Minsk"), - ("Europe/Monaco", "Monaco"), - ("Europe/Moscow", "Moscow"), - ("Europe/Nicosia", "Nicosia"), - ("Europe/Oslo", "Oslo"), - ("Europe/Paris", "Paris"), - ("Europe/Podgorica", "Podgorica"), - ("Europe/Prague", "Prague"), - ("Europe/Riga", "Riga"), - ("Europe/Rome", "Rome"), - ("Europe/Samara", "Samara"), - ("Europe/San_Marino", "San_Marino"), - ("Europe/Sarajevo", "Sarajevo"), - ("Europe/Saratov", "Saratov"), - ("Europe/Simferopol", "Simferopol"), - ("Europe/Skopje", "Skopje"), - ("Europe/Sofia", "Sofia"), - ("Europe/Stockholm", "Stockholm"), - ("Europe/Tallinn", "Tallinn"), - ("Europe/Tirane", "Tirane"), - ("Europe/Tiraspol", "Tiraspol"), - ("Europe/Ulyanovsk", "Ulyanovsk"), - ("Europe/Uzhgorod", "Uzhgorod"), - ("Europe/Vaduz", "Vaduz"), - ("Europe/Vatican", "Vatican"), - ("Europe/Vienna", "Vienna"), - ("Europe/Vilnius", "Vilnius"), - ("Europe/Volgograd", "Volgograd"), - ("Europe/Warsaw", "Warsaw"), - ("Europe/Zagreb", "Zagreb"), - ("Europe/Zaporozhye", "Zaporozhye"), - ("Europe/Zurich", "Zurich"), - ], - ), - ( - "Indian", - [ - ("Indian/Antananarivo", "Antananarivo"), - ("Indian/Chagos", "Chagos"), - ("Indian/Christmas", "Christmas"), - ("Indian/Cocos", "Cocos"), - ("Indian/Comoro", "Comoro"), - ("Indian/Kerguelen", "Kerguelen"), - ("Indian/Mahe", "Mahe"), - ("Indian/Maldives", "Maldives"), - ("Indian/Mauritius", "Mauritius"), - ("Indian/Mayotte", "Mayotte"), - ("Indian/Reunion", "Reunion"), - ], - ), - ( - "Mexico", - [ - ("Mexico/BajaNorte", "BajaNorte"), - ("Mexico/BajaSur", "BajaSur"), - ("Mexico/General", "General"), - ], - ), - ( - "Other", - [ - ("CET", "CET"), - ("CST6CDT", "CST6CDT"), - ("Cuba", "Cuba"), - ("EET", "EET"), - ("EST", "EST"), - ("EST5EDT", "EST5EDT"), - ("Egypt", "Egypt"), - ("Eire", "Eire"), - ("GB", "GB"), - ("GB-Eire", "GB-Eire"), - ("Greenwich", "Greenwich"), - ("HST", "HST"), - ("Hongkong", "Hongkong"), - ("Iceland", "Iceland"), - ("Iran", "Iran"), - ("Israel", "Israel"), - ("Jamaica", "Jamaica"), - ("Japan", "Japan"), - ("Kwajalein", "Kwajalein"), - ("Libya", "Libya"), - ("MET", "MET"), - ("MST", "MST"), - ("MST7MDT", "MST7MDT"), - ("NZ", "NZ"), - ("NZ-CHAT", "NZ-CHAT"), - ("Navajo", "Navajo"), - ("PRC", "PRC"), - ("PST8PDT", "PST8PDT"), - ("Poland", "Poland"), - ("Portugal", "Portugal"), - ("ROC", "ROC"), - ("ROK", "ROK"), - ("Singapore", "Singapore"), - ("Turkey", "Turkey"), - ("UCT", "UCT"), - ("UTC", "UTC"), - ("Universal", "Universal"), - ("W-SU", "W-SU"), - ("WET", "WET"), - ("Zulu", "Zulu"), - ], - ), - ( - "Pacific", - [ - ("Pacific/Apia", "Apia"), - ("Pacific/Auckland", "Auckland"), - ("Pacific/Bougainville", "Bougainville"), - ("Pacific/Chatham", "Chatham"), - ("Pacific/Chuuk", "Chuuk"), - ("Pacific/Easter", "Easter"), - ("Pacific/Efate", "Efate"), - ("Pacific/Enderbury", "Enderbury"), - ("Pacific/Fakaofo", "Fakaofo"), - ("Pacific/Fiji", "Fiji"), - ("Pacific/Funafuti", "Funafuti"), - ("Pacific/Galapagos", "Galapagos"), - ("Pacific/Gambier", "Gambier"), - ("Pacific/Guadalcanal", "Guadalcanal"), - ("Pacific/Guam", "Guam"), - ("Pacific/Honolulu", "Honolulu"), - ("Pacific/Johnston", "Johnston"), - ("Pacific/Kanton", "Kanton"), - ("Pacific/Kiritimati", "Kiritimati"), - ("Pacific/Kosrae", "Kosrae"), - ("Pacific/Kwajalein", "Kwajalein"), - ("Pacific/Majuro", "Majuro"), - ("Pacific/Marquesas", "Marquesas"), - ("Pacific/Midway", "Midway"), - ("Pacific/Nauru", "Nauru"), - ("Pacific/Niue", "Niue"), - ("Pacific/Norfolk", "Norfolk"), - ("Pacific/Noumea", "Noumea"), - ("Pacific/Pago_Pago", "Pago_Pago"), - ("Pacific/Palau", "Palau"), - ("Pacific/Pitcairn", "Pitcairn"), - ("Pacific/Pohnpei", "Pohnpei"), - ("Pacific/Ponape", "Ponape"), - ("Pacific/Port_Moresby", "Port_Moresby"), - ("Pacific/Rarotonga", "Rarotonga"), - ("Pacific/Saipan", "Saipan"), - ("Pacific/Samoa", "Samoa"), - ("Pacific/Tahiti", "Tahiti"), - ("Pacific/Tarawa", "Tarawa"), - ("Pacific/Tongatapu", "Tongatapu"), - ("Pacific/Truk", "Truk"), - ("Pacific/Wake", "Wake"), - ("Pacific/Wallis", "Wallis"), - ("Pacific/Yap", "Yap"), - ], - ), - ( - "US", - [ - ("US/Alaska", "Alaska"), - ("US/Aleutian", "Aleutian"), - ("US/Arizona", "Arizona"), - ("US/Central", "Central"), - ("US/East-Indiana", "East-Indiana"), - ("US/Eastern", "Eastern"), - ("US/Hawaii", "Hawaii"), - ("US/Indiana-Starke", "Indiana-Starke"), - ("US/Michigan", "Michigan"), - ("US/Mountain", "Mountain"), - ("US/Pacific", "Pacific"), - ("US/Samoa", "Samoa"), - ], - ), - ], - default="Asia/Ho_Chi_Minh", - max_length=50, - verbose_name="location", - ), - ), - ] diff --git a/judge/migrations/0137_auto_20221116_2201.py b/judge/migrations/0137_auto_20221116_2201.py deleted file mode 100644 index 8439d6d..0000000 --- a/judge/migrations/0137_auto_20221116_2201.py +++ /dev/null @@ -1,84 +0,0 @@ -# Generated by Django 3.2.16 on 2022-11-16 15:01 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0136_alter_profile_timezone"), - ] - - operations = [ - migrations.CreateModel( - name="PageVote", - fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "page", - models.CharField( - db_index=True, max_length=30, verbose_name="associated page" - ), - ), - ("score", models.IntegerField(default=0, verbose_name="votes")), - ], - options={ - "verbose_name": "pagevote", - "verbose_name_plural": "pagevotes", - }, - ), - migrations.AlterField( - model_name="problemtranslation", - name="language", - field=models.CharField( - choices=[("vi", "Vietnamese"), ("en", "English")], - max_length=7, - verbose_name="language", - ), - ), - migrations.CreateModel( - name="PageVoteVoter", - fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("score", models.IntegerField()), - ( - "pagevote", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="votes", - to="judge.pagevote", - ), - ), - ( - "voter", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="voted_page", - to="judge.profile", - ), - ), - ], - options={ - "verbose_name": "pagevote vote", - "verbose_name_plural": "pagevote votes", - "unique_together": {("voter", "pagevote")}, - }, - ), - ] diff --git a/judge/migrations/0138_bookmark_makebookmark.py b/judge/migrations/0138_bookmark_makebookmark.py deleted file mode 100644 index a0e4d05..0000000 --- a/judge/migrations/0138_bookmark_makebookmark.py +++ /dev/null @@ -1,73 +0,0 @@ -# Generated by Django 3.2.16 on 2022-11-17 17:13 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0137_auto_20221116_2201"), - ] - - operations = [ - migrations.CreateModel( - name="BookMark", - fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "page", - models.CharField( - db_index=True, max_length=30, verbose_name="associated page" - ), - ), - ], - options={ - "verbose_name": "bookmark", - "verbose_name_plural": "bookmarks", - }, - ), - migrations.CreateModel( - name="MakeBookMark", - fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "bookmark", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="bookmark", - to="judge.bookmark", - ), - ), - ( - "user", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="user_bookmark", - to="judge.profile", - ), - ), - ], - options={ - "verbose_name": "make bookmark", - "verbose_name_plural": "make bookmarks", - "unique_together": {("user", "bookmark")}, - }, - ), - ] diff --git a/judge/migrations/0139_contest_freeze_after.py b/judge/migrations/0139_contest_freeze_after.py deleted file mode 100644 index 97e4a25..0000000 --- a/judge/migrations/0139_contest_freeze_after.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 3.2.16 on 2022-11-18 06:11 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0138_bookmark_makebookmark"), - ] - - operations = [ - migrations.AddField( - model_name="contest", - name="freeze_after", - field=models.DurationField( - blank=True, - help_text="Format hh:mm:ss. For example, if you want to freeze contest after 2 hours, enter 02:00:00", - null=True, - verbose_name="freeze after", - ), - ), - ] diff --git a/judge/migrations/0140_alter_contest_format_name.py b/judge/migrations/0140_alter_contest_format_name.py deleted file mode 100644 index d146e3b..0000000 --- a/judge/migrations/0140_alter_contest_format_name.py +++ /dev/null @@ -1,31 +0,0 @@ -# Generated by Django 3.2.16 on 2022-11-21 22:30 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0139_contest_freeze_after"), - ] - - operations = [ - migrations.AlterField( - model_name="contest", - name="format_name", - field=models.CharField( - choices=[ - ("atcoder", "AtCoder"), - ("default", "Default"), - ("ecoo", "ECOO"), - ("icpc", "ICPC"), - ("ioi", "IOI"), - ("ioi16", "New IOI"), - ], - default="default", - help_text="The contest format module to use.", - max_length=32, - verbose_name="contest format", - ), - ), - ] diff --git a/judge/migrations/0141_contestproblem_frozen_subtasks.py b/judge/migrations/0141_contestproblem_frozen_subtasks.py deleted file mode 100644 index c85dc49..0000000 --- a/judge/migrations/0141_contestproblem_frozen_subtasks.py +++ /dev/null @@ -1,24 +0,0 @@ -# Generated by Django 3.2.16 on 2022-12-20 06:15 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0140_alter_contest_format_name"), - ] - - operations = [ - migrations.AddField( - model_name="contestproblem", - name="frozen_subtasks", - field=models.CharField( - blank=True, - help_text="Only for format new IOI. Separated by commas, e.g: 2, 3", - max_length=20, - null=True, - verbose_name="frozen subtasks", - ), - ), - ] diff --git a/judge/migrations/0142_contestparticipation_format_data_final.py b/judge/migrations/0142_contestparticipation_format_data_final.py deleted file mode 100644 index 50e8dd7..0000000 --- a/judge/migrations/0142_contestparticipation_format_data_final.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 3.2.16 on 2022-12-28 18:36 - -from django.db import migrations -import jsonfield.fields - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0141_contestproblem_frozen_subtasks"), - ] - - operations = [ - migrations.AddField( - model_name="contestparticipation", - name="format_data_final", - field=jsonfield.fields.JSONField( - blank=True, - null=True, - verbose_name="same as format_data, but including frozen results", - ), - ), - ] diff --git a/judge/migrations/0143_auto_20221229_0153.py b/judge/migrations/0143_auto_20221229_0153.py deleted file mode 100644 index 051f192..0000000 --- a/judge/migrations/0143_auto_20221229_0153.py +++ /dev/null @@ -1,25 +0,0 @@ -# Generated by Django 3.2.16 on 2022-12-28 18:53 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0142_contestparticipation_format_data_final"), - ] - - operations = [ - migrations.AddField( - model_name="contestparticipation", - name="cumtime_final", - field=models.PositiveIntegerField( - default=0, verbose_name="final cumulative time" - ), - ), - migrations.AddField( - model_name="contestparticipation", - name="score_final", - field=models.FloatField(default=0, verbose_name="final score"), - ), - ] diff --git a/judge/migrations/0144_auto_20230103_0523.py b/judge/migrations/0144_auto_20230103_0523.py deleted file mode 100644 index 97f6234..0000000 --- a/judge/migrations/0144_auto_20230103_0523.py +++ /dev/null @@ -1,28 +0,0 @@ -# Generated by Django 3.2.16 on 2023-01-02 22:23 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0143_auto_20221229_0153"), - ] - - operations = [ - migrations.RemoveField( - model_name="contestproblem", - name="frozen_subtasks", - ), - migrations.AddField( - model_name="contestproblem", - name="hidden_subtasks", - field=models.CharField( - blank=True, - help_text="Separated by commas, e.g: 2, 3", - max_length=20, - null=True, - verbose_name="hidden subtasks", - ), - ), - ] diff --git a/judge/migrations/0145_alter_organization_slug.py b/judge/migrations/0145_alter_organization_slug.py deleted file mode 100644 index 1cadbe2..0000000 --- a/judge/migrations/0145_alter_organization_slug.py +++ /dev/null @@ -1,36 +0,0 @@ -# Generated by Django 3.2.16 on 2023-01-23 23:39 - -from django.db import migrations, models - - -def make_slug_unique(apps, schema_editor): - Organization = apps.get_model("judge", "Organization") - slugs = Organization.objects.values_list("slug", flat=True) - slugs = set([i.lower() for i in slugs]) - for slug in slugs: - orgs = Organization.objects.filter(slug=slug) - if len(orgs) > 1: - for org in orgs: - org.slug += "-" + str(org.id) - org.save() - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0144_auto_20230103_0523"), - ] - - operations = [ - migrations.RunPython(make_slug_unique, migrations.RunPython.noop, atomic=True), - migrations.AlterField( - model_name="organization", - name="slug", - field=models.SlugField( - help_text="Organization name shown in URL", - max_length=128, - unique=True, - verbose_name="organization slug", - ), - ), - ] diff --git a/judge/migrations/0146_alter_organization_slug.py b/judge/migrations/0146_alter_organization_slug.py deleted file mode 100644 index dbd475d..0000000 --- a/judge/migrations/0146_alter_organization_slug.py +++ /dev/null @@ -1,29 +0,0 @@ -# Generated by Django 3.2.16 on 2023-01-25 19:12 - -import django.core.validators -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0145_alter_organization_slug"), - ] - - operations = [ - migrations.AlterField( - model_name="organization", - name="slug", - field=models.SlugField( - help_text="Organization name shown in URL", - max_length=128, - unique=True, - validators=[ - django.core.validators.RegexValidator( - "^[-a-zA-Z0-9]+$", "Only alphanumeric and hyphens" - ) - ], - verbose_name="organization slug", - ), - ), - ] diff --git a/judge/migrations/0147_alter_profile_timezone.py b/judge/migrations/0147_alter_profile_timezone.py deleted file mode 100644 index 5d6331e..0000000 --- a/judge/migrations/0147_alter_profile_timezone.py +++ /dev/null @@ -1,678 +0,0 @@ -# Generated by Django 3.2.16 on 2023-01-30 11:01 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0146_alter_organization_slug"), - ] - - operations = [ - migrations.AlterField( - model_name="profile", - name="timezone", - field=models.CharField( - choices=[ - ( - "Africa", - [ - ("Africa/Abidjan", "Abidjan"), - ("Africa/Accra", "Accra"), - ("Africa/Addis_Ababa", "Addis_Ababa"), - ("Africa/Algiers", "Algiers"), - ("Africa/Asmara", "Asmara"), - ("Africa/Asmera", "Asmera"), - ("Africa/Bamako", "Bamako"), - ("Africa/Bangui", "Bangui"), - ("Africa/Banjul", "Banjul"), - ("Africa/Bissau", "Bissau"), - ("Africa/Blantyre", "Blantyre"), - ("Africa/Brazzaville", "Brazzaville"), - ("Africa/Bujumbura", "Bujumbura"), - ("Africa/Cairo", "Cairo"), - ("Africa/Casablanca", "Casablanca"), - ("Africa/Ceuta", "Ceuta"), - ("Africa/Conakry", "Conakry"), - ("Africa/Dakar", "Dakar"), - ("Africa/Dar_es_Salaam", "Dar_es_Salaam"), - ("Africa/Djibouti", "Djibouti"), - ("Africa/Douala", "Douala"), - ("Africa/El_Aaiun", "El_Aaiun"), - ("Africa/Freetown", "Freetown"), - ("Africa/Gaborone", "Gaborone"), - ("Africa/Harare", "Harare"), - ("Africa/Johannesburg", "Johannesburg"), - ("Africa/Juba", "Juba"), - ("Africa/Kampala", "Kampala"), - ("Africa/Khartoum", "Khartoum"), - ("Africa/Kigali", "Kigali"), - ("Africa/Kinshasa", "Kinshasa"), - ("Africa/Lagos", "Lagos"), - ("Africa/Libreville", "Libreville"), - ("Africa/Lome", "Lome"), - ("Africa/Luanda", "Luanda"), - ("Africa/Lubumbashi", "Lubumbashi"), - ("Africa/Lusaka", "Lusaka"), - ("Africa/Malabo", "Malabo"), - ("Africa/Maputo", "Maputo"), - ("Africa/Maseru", "Maseru"), - ("Africa/Mbabane", "Mbabane"), - ("Africa/Mogadishu", "Mogadishu"), - ("Africa/Monrovia", "Monrovia"), - ("Africa/Nairobi", "Nairobi"), - ("Africa/Ndjamena", "Ndjamena"), - ("Africa/Niamey", "Niamey"), - ("Africa/Nouakchott", "Nouakchott"), - ("Africa/Ouagadougou", "Ouagadougou"), - ("Africa/Porto-Novo", "Porto-Novo"), - ("Africa/Sao_Tome", "Sao_Tome"), - ("Africa/Timbuktu", "Timbuktu"), - ("Africa/Tripoli", "Tripoli"), - ("Africa/Tunis", "Tunis"), - ("Africa/Windhoek", "Windhoek"), - ], - ), - ( - "America", - [ - ("America/Adak", "Adak"), - ("America/Anchorage", "Anchorage"), - ("America/Anguilla", "Anguilla"), - ("America/Antigua", "Antigua"), - ("America/Araguaina", "Araguaina"), - ( - "America/Argentina/Buenos_Aires", - "Argentina/Buenos_Aires", - ), - ("America/Argentina/Catamarca", "Argentina/Catamarca"), - ( - "America/Argentina/ComodRivadavia", - "Argentina/ComodRivadavia", - ), - ("America/Argentina/Cordoba", "Argentina/Cordoba"), - ("America/Argentina/Jujuy", "Argentina/Jujuy"), - ("America/Argentina/La_Rioja", "Argentina/La_Rioja"), - ("America/Argentina/Mendoza", "Argentina/Mendoza"), - ( - "America/Argentina/Rio_Gallegos", - "Argentina/Rio_Gallegos", - ), - ("America/Argentina/Salta", "Argentina/Salta"), - ("America/Argentina/San_Juan", "Argentina/San_Juan"), - ("America/Argentina/San_Luis", "Argentina/San_Luis"), - ("America/Argentina/Tucuman", "Argentina/Tucuman"), - ("America/Argentina/Ushuaia", "Argentina/Ushuaia"), - ("America/Aruba", "Aruba"), - ("America/Asuncion", "Asuncion"), - ("America/Atikokan", "Atikokan"), - ("America/Atka", "Atka"), - ("America/Bahia", "Bahia"), - ("America/Bahia_Banderas", "Bahia_Banderas"), - ("America/Barbados", "Barbados"), - ("America/Belem", "Belem"), - ("America/Belize", "Belize"), - ("America/Blanc-Sablon", "Blanc-Sablon"), - ("America/Boa_Vista", "Boa_Vista"), - ("America/Bogota", "Bogota"), - ("America/Boise", "Boise"), - ("America/Buenos_Aires", "Buenos_Aires"), - ("America/Cambridge_Bay", "Cambridge_Bay"), - ("America/Campo_Grande", "Campo_Grande"), - ("America/Cancun", "Cancun"), - ("America/Caracas", "Caracas"), - ("America/Catamarca", "Catamarca"), - ("America/Cayenne", "Cayenne"), - ("America/Cayman", "Cayman"), - ("America/Chicago", "Chicago"), - ("America/Chihuahua", "Chihuahua"), - ("America/Ciudad_Juarez", "Ciudad_Juarez"), - ("America/Coral_Harbour", "Coral_Harbour"), - ("America/Cordoba", "Cordoba"), - ("America/Costa_Rica", "Costa_Rica"), - ("America/Creston", "Creston"), - ("America/Cuiaba", "Cuiaba"), - ("America/Curacao", "Curacao"), - ("America/Danmarkshavn", "Danmarkshavn"), - ("America/Dawson", "Dawson"), - ("America/Dawson_Creek", "Dawson_Creek"), - ("America/Denver", "Denver"), - ("America/Detroit", "Detroit"), - ("America/Dominica", "Dominica"), - ("America/Edmonton", "Edmonton"), - ("America/Eirunepe", "Eirunepe"), - ("America/El_Salvador", "El_Salvador"), - ("America/Ensenada", "Ensenada"), - ("America/Fort_Nelson", "Fort_Nelson"), - ("America/Fort_Wayne", "Fort_Wayne"), - ("America/Fortaleza", "Fortaleza"), - ("America/Glace_Bay", "Glace_Bay"), - ("America/Godthab", "Godthab"), - ("America/Goose_Bay", "Goose_Bay"), - ("America/Grand_Turk", "Grand_Turk"), - ("America/Grenada", "Grenada"), - ("America/Guadeloupe", "Guadeloupe"), - ("America/Guatemala", "Guatemala"), - ("America/Guayaquil", "Guayaquil"), - ("America/Guyana", "Guyana"), - ("America/Halifax", "Halifax"), - ("America/Havana", "Havana"), - ("America/Hermosillo", "Hermosillo"), - ("America/Indiana/Indianapolis", "Indiana/Indianapolis"), - ("America/Indiana/Knox", "Indiana/Knox"), - ("America/Indiana/Marengo", "Indiana/Marengo"), - ("America/Indiana/Petersburg", "Indiana/Petersburg"), - ("America/Indiana/Tell_City", "Indiana/Tell_City"), - ("America/Indiana/Vevay", "Indiana/Vevay"), - ("America/Indiana/Vincennes", "Indiana/Vincennes"), - ("America/Indiana/Winamac", "Indiana/Winamac"), - ("America/Indianapolis", "Indianapolis"), - ("America/Inuvik", "Inuvik"), - ("America/Iqaluit", "Iqaluit"), - ("America/Jamaica", "Jamaica"), - ("America/Jujuy", "Jujuy"), - ("America/Juneau", "Juneau"), - ("America/Kentucky/Louisville", "Kentucky/Louisville"), - ("America/Kentucky/Monticello", "Kentucky/Monticello"), - ("America/Knox_IN", "Knox_IN"), - ("America/Kralendijk", "Kralendijk"), - ("America/La_Paz", "La_Paz"), - ("America/Lima", "Lima"), - ("America/Los_Angeles", "Los_Angeles"), - ("America/Louisville", "Louisville"), - ("America/Lower_Princes", "Lower_Princes"), - ("America/Maceio", "Maceio"), - ("America/Managua", "Managua"), - ("America/Manaus", "Manaus"), - ("America/Marigot", "Marigot"), - ("America/Martinique", "Martinique"), - ("America/Matamoros", "Matamoros"), - ("America/Mazatlan", "Mazatlan"), - ("America/Mendoza", "Mendoza"), - ("America/Menominee", "Menominee"), - ("America/Merida", "Merida"), - ("America/Metlakatla", "Metlakatla"), - ("America/Mexico_City", "Mexico_City"), - ("America/Miquelon", "Miquelon"), - ("America/Moncton", "Moncton"), - ("America/Monterrey", "Monterrey"), - ("America/Montevideo", "Montevideo"), - ("America/Montreal", "Montreal"), - ("America/Montserrat", "Montserrat"), - ("America/Nassau", "Nassau"), - ("America/New_York", "New_York"), - ("America/Nipigon", "Nipigon"), - ("America/Nome", "Nome"), - ("America/Noronha", "Noronha"), - ("America/North_Dakota/Beulah", "North_Dakota/Beulah"), - ("America/North_Dakota/Center", "North_Dakota/Center"), - ( - "America/North_Dakota/New_Salem", - "North_Dakota/New_Salem", - ), - ("America/Nuuk", "Nuuk"), - ("America/Ojinaga", "Ojinaga"), - ("America/Panama", "Panama"), - ("America/Pangnirtung", "Pangnirtung"), - ("America/Paramaribo", "Paramaribo"), - ("America/Phoenix", "Phoenix"), - ("America/Port-au-Prince", "Port-au-Prince"), - ("America/Port_of_Spain", "Port_of_Spain"), - ("America/Porto_Acre", "Porto_Acre"), - ("America/Porto_Velho", "Porto_Velho"), - ("America/Puerto_Rico", "Puerto_Rico"), - ("America/Punta_Arenas", "Punta_Arenas"), - ("America/Rainy_River", "Rainy_River"), - ("America/Rankin_Inlet", "Rankin_Inlet"), - ("America/Recife", "Recife"), - ("America/Regina", "Regina"), - ("America/Resolute", "Resolute"), - ("America/Rio_Branco", "Rio_Branco"), - ("America/Rosario", "Rosario"), - ("America/Santa_Isabel", "Santa_Isabel"), - ("America/Santarem", "Santarem"), - ("America/Santiago", "Santiago"), - ("America/Santo_Domingo", "Santo_Domingo"), - ("America/Sao_Paulo", "Sao_Paulo"), - ("America/Scoresbysund", "Scoresbysund"), - ("America/Shiprock", "Shiprock"), - ("America/Sitka", "Sitka"), - ("America/St_Barthelemy", "St_Barthelemy"), - ("America/St_Johns", "St_Johns"), - ("America/St_Kitts", "St_Kitts"), - ("America/St_Lucia", "St_Lucia"), - ("America/St_Thomas", "St_Thomas"), - ("America/St_Vincent", "St_Vincent"), - ("America/Swift_Current", "Swift_Current"), - ("America/Tegucigalpa", "Tegucigalpa"), - ("America/Thule", "Thule"), - ("America/Thunder_Bay", "Thunder_Bay"), - ("America/Tijuana", "Tijuana"), - ("America/Toronto", "Toronto"), - ("America/Tortola", "Tortola"), - ("America/Vancouver", "Vancouver"), - ("America/Virgin", "Virgin"), - ("America/Whitehorse", "Whitehorse"), - ("America/Winnipeg", "Winnipeg"), - ("America/Yakutat", "Yakutat"), - ("America/Yellowknife", "Yellowknife"), - ], - ), - ( - "Antarctica", - [ - ("Antarctica/Casey", "Casey"), - ("Antarctica/Davis", "Davis"), - ("Antarctica/DumontDUrville", "DumontDUrville"), - ("Antarctica/Macquarie", "Macquarie"), - ("Antarctica/Mawson", "Mawson"), - ("Antarctica/McMurdo", "McMurdo"), - ("Antarctica/Palmer", "Palmer"), - ("Antarctica/Rothera", "Rothera"), - ("Antarctica/South_Pole", "South_Pole"), - ("Antarctica/Syowa", "Syowa"), - ("Antarctica/Troll", "Troll"), - ("Antarctica/Vostok", "Vostok"), - ], - ), - ("Arctic", [("Arctic/Longyearbyen", "Longyearbyen")]), - ( - "Asia", - [ - ("Asia/Aden", "Aden"), - ("Asia/Almaty", "Almaty"), - ("Asia/Amman", "Amman"), - ("Asia/Anadyr", "Anadyr"), - ("Asia/Aqtau", "Aqtau"), - ("Asia/Aqtobe", "Aqtobe"), - ("Asia/Ashgabat", "Ashgabat"), - ("Asia/Ashkhabad", "Ashkhabad"), - ("Asia/Atyrau", "Atyrau"), - ("Asia/Baghdad", "Baghdad"), - ("Asia/Bahrain", "Bahrain"), - ("Asia/Baku", "Baku"), - ("Asia/Bangkok", "Bangkok"), - ("Asia/Barnaul", "Barnaul"), - ("Asia/Beirut", "Beirut"), - ("Asia/Bishkek", "Bishkek"), - ("Asia/Brunei", "Brunei"), - ("Asia/Calcutta", "Calcutta"), - ("Asia/Chita", "Chita"), - ("Asia/Choibalsan", "Choibalsan"), - ("Asia/Chongqing", "Chongqing"), - ("Asia/Chungking", "Chungking"), - ("Asia/Colombo", "Colombo"), - ("Asia/Dacca", "Dacca"), - ("Asia/Damascus", "Damascus"), - ("Asia/Dhaka", "Dhaka"), - ("Asia/Dili", "Dili"), - ("Asia/Dubai", "Dubai"), - ("Asia/Dushanbe", "Dushanbe"), - ("Asia/Famagusta", "Famagusta"), - ("Asia/Gaza", "Gaza"), - ("Asia/Harbin", "Harbin"), - ("Asia/Hebron", "Hebron"), - ("Asia/Ho_Chi_Minh", "Ho_Chi_Minh"), - ("Asia/Hong_Kong", "Hong_Kong"), - ("Asia/Hovd", "Hovd"), - ("Asia/Irkutsk", "Irkutsk"), - ("Asia/Istanbul", "Istanbul"), - ("Asia/Jakarta", "Jakarta"), - ("Asia/Jayapura", "Jayapura"), - ("Asia/Jerusalem", "Jerusalem"), - ("Asia/Kabul", "Kabul"), - ("Asia/Kamchatka", "Kamchatka"), - ("Asia/Karachi", "Karachi"), - ("Asia/Kashgar", "Kashgar"), - ("Asia/Kathmandu", "Kathmandu"), - ("Asia/Katmandu", "Katmandu"), - ("Asia/Khandyga", "Khandyga"), - ("Asia/Kolkata", "Kolkata"), - ("Asia/Krasnoyarsk", "Krasnoyarsk"), - ("Asia/Kuala_Lumpur", "Kuala_Lumpur"), - ("Asia/Kuching", "Kuching"), - ("Asia/Kuwait", "Kuwait"), - ("Asia/Macao", "Macao"), - ("Asia/Macau", "Macau"), - ("Asia/Magadan", "Magadan"), - ("Asia/Makassar", "Makassar"), - ("Asia/Manila", "Manila"), - ("Asia/Muscat", "Muscat"), - ("Asia/Nicosia", "Nicosia"), - ("Asia/Novokuznetsk", "Novokuznetsk"), - ("Asia/Novosibirsk", "Novosibirsk"), - ("Asia/Omsk", "Omsk"), - ("Asia/Oral", "Oral"), - ("Asia/Phnom_Penh", "Phnom_Penh"), - ("Asia/Pontianak", "Pontianak"), - ("Asia/Pyongyang", "Pyongyang"), - ("Asia/Qatar", "Qatar"), - ("Asia/Qostanay", "Qostanay"), - ("Asia/Qyzylorda", "Qyzylorda"), - ("Asia/Rangoon", "Rangoon"), - ("Asia/Riyadh", "Riyadh"), - ("Asia/Saigon", "Saigon"), - ("Asia/Sakhalin", "Sakhalin"), - ("Asia/Samarkand", "Samarkand"), - ("Asia/Seoul", "Seoul"), - ("Asia/Shanghai", "Shanghai"), - ("Asia/Singapore", "Singapore"), - ("Asia/Srednekolymsk", "Srednekolymsk"), - ("Asia/Taipei", "Taipei"), - ("Asia/Tashkent", "Tashkent"), - ("Asia/Tbilisi", "Tbilisi"), - ("Asia/Tehran", "Tehran"), - ("Asia/Tel_Aviv", "Tel_Aviv"), - ("Asia/Thimbu", "Thimbu"), - ("Asia/Thimphu", "Thimphu"), - ("Asia/Tokyo", "Tokyo"), - ("Asia/Tomsk", "Tomsk"), - ("Asia/Ujung_Pandang", "Ujung_Pandang"), - ("Asia/Ulaanbaatar", "Ulaanbaatar"), - ("Asia/Ulan_Bator", "Ulan_Bator"), - ("Asia/Urumqi", "Urumqi"), - ("Asia/Ust-Nera", "Ust-Nera"), - ("Asia/Vientiane", "Vientiane"), - ("Asia/Vladivostok", "Vladivostok"), - ("Asia/Yakutsk", "Yakutsk"), - ("Asia/Yangon", "Yangon"), - ("Asia/Yekaterinburg", "Yekaterinburg"), - ("Asia/Yerevan", "Yerevan"), - ], - ), - ( - "Atlantic", - [ - ("Atlantic/Azores", "Azores"), - ("Atlantic/Bermuda", "Bermuda"), - ("Atlantic/Canary", "Canary"), - ("Atlantic/Cape_Verde", "Cape_Verde"), - ("Atlantic/Faeroe", "Faeroe"), - ("Atlantic/Faroe", "Faroe"), - ("Atlantic/Jan_Mayen", "Jan_Mayen"), - ("Atlantic/Madeira", "Madeira"), - ("Atlantic/Reykjavik", "Reykjavik"), - ("Atlantic/South_Georgia", "South_Georgia"), - ("Atlantic/St_Helena", "St_Helena"), - ("Atlantic/Stanley", "Stanley"), - ], - ), - ( - "Australia", - [ - ("Australia/ACT", "ACT"), - ("Australia/Adelaide", "Adelaide"), - ("Australia/Brisbane", "Brisbane"), - ("Australia/Broken_Hill", "Broken_Hill"), - ("Australia/Canberra", "Canberra"), - ("Australia/Currie", "Currie"), - ("Australia/Darwin", "Darwin"), - ("Australia/Eucla", "Eucla"), - ("Australia/Hobart", "Hobart"), - ("Australia/LHI", "LHI"), - ("Australia/Lindeman", "Lindeman"), - ("Australia/Lord_Howe", "Lord_Howe"), - ("Australia/Melbourne", "Melbourne"), - ("Australia/NSW", "NSW"), - ("Australia/North", "North"), - ("Australia/Perth", "Perth"), - ("Australia/Queensland", "Queensland"), - ("Australia/South", "South"), - ("Australia/Sydney", "Sydney"), - ("Australia/Tasmania", "Tasmania"), - ("Australia/Victoria", "Victoria"), - ("Australia/West", "West"), - ("Australia/Yancowinna", "Yancowinna"), - ], - ), - ( - "Brazil", - [ - ("Brazil/Acre", "Acre"), - ("Brazil/DeNoronha", "DeNoronha"), - ("Brazil/East", "East"), - ("Brazil/West", "West"), - ], - ), - ( - "Canada", - [ - ("Canada/Atlantic", "Atlantic"), - ("Canada/Central", "Central"), - ("Canada/Eastern", "Eastern"), - ("Canada/Mountain", "Mountain"), - ("Canada/Newfoundland", "Newfoundland"), - ("Canada/Pacific", "Pacific"), - ("Canada/Saskatchewan", "Saskatchewan"), - ("Canada/Yukon", "Yukon"), - ], - ), - ( - "Chile", - [ - ("Chile/Continental", "Continental"), - ("Chile/EasterIsland", "EasterIsland"), - ], - ), - ( - "Etc", - [ - ("Etc/Greenwich", "Greenwich"), - ("Etc/UCT", "UCT"), - ("Etc/UTC", "UTC"), - ("Etc/Universal", "Universal"), - ("Etc/Zulu", "Zulu"), - ], - ), - ( - "Europe", - [ - ("Europe/Amsterdam", "Amsterdam"), - ("Europe/Andorra", "Andorra"), - ("Europe/Astrakhan", "Astrakhan"), - ("Europe/Athens", "Athens"), - ("Europe/Belfast", "Belfast"), - ("Europe/Belgrade", "Belgrade"), - ("Europe/Berlin", "Berlin"), - ("Europe/Bratislava", "Bratislava"), - ("Europe/Brussels", "Brussels"), - ("Europe/Bucharest", "Bucharest"), - ("Europe/Budapest", "Budapest"), - ("Europe/Busingen", "Busingen"), - ("Europe/Chisinau", "Chisinau"), - ("Europe/Copenhagen", "Copenhagen"), - ("Europe/Dublin", "Dublin"), - ("Europe/Gibraltar", "Gibraltar"), - ("Europe/Guernsey", "Guernsey"), - ("Europe/Helsinki", "Helsinki"), - ("Europe/Isle_of_Man", "Isle_of_Man"), - ("Europe/Istanbul", "Istanbul"), - ("Europe/Jersey", "Jersey"), - ("Europe/Kaliningrad", "Kaliningrad"), - ("Europe/Kiev", "Kiev"), - ("Europe/Kirov", "Kirov"), - ("Europe/Kyiv", "Kyiv"), - ("Europe/Lisbon", "Lisbon"), - ("Europe/Ljubljana", "Ljubljana"), - ("Europe/London", "London"), - ("Europe/Luxembourg", "Luxembourg"), - ("Europe/Madrid", "Madrid"), - ("Europe/Malta", "Malta"), - ("Europe/Mariehamn", "Mariehamn"), - ("Europe/Minsk", "Minsk"), - ("Europe/Monaco", "Monaco"), - ("Europe/Moscow", "Moscow"), - ("Europe/Nicosia", "Nicosia"), - ("Europe/Oslo", "Oslo"), - ("Europe/Paris", "Paris"), - ("Europe/Podgorica", "Podgorica"), - ("Europe/Prague", "Prague"), - ("Europe/Riga", "Riga"), - ("Europe/Rome", "Rome"), - ("Europe/Samara", "Samara"), - ("Europe/San_Marino", "San_Marino"), - ("Europe/Sarajevo", "Sarajevo"), - ("Europe/Saratov", "Saratov"), - ("Europe/Simferopol", "Simferopol"), - ("Europe/Skopje", "Skopje"), - ("Europe/Sofia", "Sofia"), - ("Europe/Stockholm", "Stockholm"), - ("Europe/Tallinn", "Tallinn"), - ("Europe/Tirane", "Tirane"), - ("Europe/Tiraspol", "Tiraspol"), - ("Europe/Ulyanovsk", "Ulyanovsk"), - ("Europe/Uzhgorod", "Uzhgorod"), - ("Europe/Vaduz", "Vaduz"), - ("Europe/Vatican", "Vatican"), - ("Europe/Vienna", "Vienna"), - ("Europe/Vilnius", "Vilnius"), - ("Europe/Volgograd", "Volgograd"), - ("Europe/Warsaw", "Warsaw"), - ("Europe/Zagreb", "Zagreb"), - ("Europe/Zaporozhye", "Zaporozhye"), - ("Europe/Zurich", "Zurich"), - ], - ), - ( - "Indian", - [ - ("Indian/Antananarivo", "Antananarivo"), - ("Indian/Chagos", "Chagos"), - ("Indian/Christmas", "Christmas"), - ("Indian/Cocos", "Cocos"), - ("Indian/Comoro", "Comoro"), - ("Indian/Kerguelen", "Kerguelen"), - ("Indian/Mahe", "Mahe"), - ("Indian/Maldives", "Maldives"), - ("Indian/Mauritius", "Mauritius"), - ("Indian/Mayotte", "Mayotte"), - ("Indian/Reunion", "Reunion"), - ], - ), - ( - "Mexico", - [ - ("Mexico/BajaNorte", "BajaNorte"), - ("Mexico/BajaSur", "BajaSur"), - ("Mexico/General", "General"), - ], - ), - ( - "Other", - [ - ("CET", "CET"), - ("CST6CDT", "CST6CDT"), - ("Cuba", "Cuba"), - ("EET", "EET"), - ("EST", "EST"), - ("EST5EDT", "EST5EDT"), - ("Egypt", "Egypt"), - ("Eire", "Eire"), - ("GB", "GB"), - ("GB-Eire", "GB-Eire"), - ("Greenwich", "Greenwich"), - ("HST", "HST"), - ("Hongkong", "Hongkong"), - ("Iceland", "Iceland"), - ("Iran", "Iran"), - ("Israel", "Israel"), - ("Jamaica", "Jamaica"), - ("Japan", "Japan"), - ("Kwajalein", "Kwajalein"), - ("Libya", "Libya"), - ("MET", "MET"), - ("MST", "MST"), - ("MST7MDT", "MST7MDT"), - ("NZ", "NZ"), - ("NZ-CHAT", "NZ-CHAT"), - ("Navajo", "Navajo"), - ("PRC", "PRC"), - ("PST8PDT", "PST8PDT"), - ("Poland", "Poland"), - ("Portugal", "Portugal"), - ("ROC", "ROC"), - ("ROK", "ROK"), - ("Singapore", "Singapore"), - ("Turkey", "Turkey"), - ("UCT", "UCT"), - ("UTC", "UTC"), - ("Universal", "Universal"), - ("W-SU", "W-SU"), - ("WET", "WET"), - ("Zulu", "Zulu"), - ], - ), - ( - "Pacific", - [ - ("Pacific/Apia", "Apia"), - ("Pacific/Auckland", "Auckland"), - ("Pacific/Bougainville", "Bougainville"), - ("Pacific/Chatham", "Chatham"), - ("Pacific/Chuuk", "Chuuk"), - ("Pacific/Easter", "Easter"), - ("Pacific/Efate", "Efate"), - ("Pacific/Enderbury", "Enderbury"), - ("Pacific/Fakaofo", "Fakaofo"), - ("Pacific/Fiji", "Fiji"), - ("Pacific/Funafuti", "Funafuti"), - ("Pacific/Galapagos", "Galapagos"), - ("Pacific/Gambier", "Gambier"), - ("Pacific/Guadalcanal", "Guadalcanal"), - ("Pacific/Guam", "Guam"), - ("Pacific/Honolulu", "Honolulu"), - ("Pacific/Johnston", "Johnston"), - ("Pacific/Kanton", "Kanton"), - ("Pacific/Kiritimati", "Kiritimati"), - ("Pacific/Kosrae", "Kosrae"), - ("Pacific/Kwajalein", "Kwajalein"), - ("Pacific/Majuro", "Majuro"), - ("Pacific/Marquesas", "Marquesas"), - ("Pacific/Midway", "Midway"), - ("Pacific/Nauru", "Nauru"), - ("Pacific/Niue", "Niue"), - ("Pacific/Norfolk", "Norfolk"), - ("Pacific/Noumea", "Noumea"), - ("Pacific/Pago_Pago", "Pago_Pago"), - ("Pacific/Palau", "Palau"), - ("Pacific/Pitcairn", "Pitcairn"), - ("Pacific/Pohnpei", "Pohnpei"), - ("Pacific/Ponape", "Ponape"), - ("Pacific/Port_Moresby", "Port_Moresby"), - ("Pacific/Rarotonga", "Rarotonga"), - ("Pacific/Saipan", "Saipan"), - ("Pacific/Samoa", "Samoa"), - ("Pacific/Tahiti", "Tahiti"), - ("Pacific/Tarawa", "Tarawa"), - ("Pacific/Tongatapu", "Tongatapu"), - ("Pacific/Truk", "Truk"), - ("Pacific/Wake", "Wake"), - ("Pacific/Wallis", "Wallis"), - ("Pacific/Yap", "Yap"), - ], - ), - ( - "US", - [ - ("US/Alaska", "Alaska"), - ("US/Aleutian", "Aleutian"), - ("US/Arizona", "Arizona"), - ("US/Central", "Central"), - ("US/East-Indiana", "East-Indiana"), - ("US/Eastern", "Eastern"), - ("US/Hawaii", "Hawaii"), - ("US/Indiana-Starke", "Indiana-Starke"), - ("US/Michigan", "Michigan"), - ("US/Mountain", "Mountain"), - ("US/Pacific", "Pacific"), - ("US/Samoa", "Samoa"), - ], - ), - ], - default="Asia/Ho_Chi_Minh", - max_length=50, - verbose_name="location", - ), - ), - ] diff --git a/judge/migrations/0148_course_courseassignment_courseresource_courserole.py b/judge/migrations/0148_course_courseassignment_courseresource_courserole.py deleted file mode 100644 index 64821b7..0000000 --- a/judge/migrations/0148_course_courseassignment_courseresource_courserole.py +++ /dev/null @@ -1,187 +0,0 @@ -# Generated by Django 3.2.16 on 2023-01-31 15:49 - -import django.core.validators -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0147_alter_profile_timezone"), - ] - - operations = [ - migrations.CreateModel( - name="Course", - fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("name", models.CharField(max_length=128, verbose_name="course name")), - ("about", models.TextField(verbose_name="organization description")), - ("ending_time", models.DateTimeField(verbose_name="ending time")), - ( - "is_public", - models.BooleanField(default=False, verbose_name="publicly visible"), - ), - ( - "slug", - models.SlugField( - help_text="Course name shown in URL", - max_length=128, - unique=True, - validators=[ - django.core.validators.RegexValidator( - "^[-a-zA-Z0-9]+$", "Only alphanumeric and hyphens" - ) - ], - verbose_name="course slug", - ), - ), - ( - "is_open", - models.BooleanField( - default=False, verbose_name="public registration" - ), - ), - ( - "image_url", - models.CharField( - blank=True, - default="", - max_length=150, - verbose_name="course image", - ), - ), - ( - "organizations", - models.ManyToManyField( - blank=True, - help_text="If private, only these organizations may see the course", - to="judge.Organization", - verbose_name="organizations", - ), - ), - ], - ), - migrations.CreateModel( - name="CourseRole", - fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "role", - models.CharField( - choices=[ - ("ST", "Student"), - ("AS", "Assistant"), - ("TE", "Teacher"), - ], - default="ST", - max_length=2, - ), - ), - ( - "course", - models.OneToOneField( - on_delete=django.db.models.deletion.CASCADE, - to="judge.course", - verbose_name="course", - ), - ), - ( - "user", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="user_of_course", - to="judge.profile", - verbose_name="user", - ), - ), - ], - ), - migrations.CreateModel( - name="CourseResource", - fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "files", - models.FileField( - blank=True, null=True, upload_to="", verbose_name="course files" - ), - ), - ( - "description", - models.CharField( - blank=True, max_length=150, verbose_name="description" - ), - ), - ("order", models.IntegerField(default=None, null=True)), - ( - "is_public", - models.BooleanField(default=False, verbose_name="publicly visible"), - ), - ( - "course", - models.OneToOneField( - on_delete=django.db.models.deletion.CASCADE, - to="judge.course", - verbose_name="course", - ), - ), - ], - ), - migrations.CreateModel( - name="CourseAssignment", - fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("points", models.FloatField(verbose_name="points")), - ( - "contest", - models.OneToOneField( - on_delete=django.db.models.deletion.CASCADE, - to="judge.contest", - verbose_name="contest", - ), - ), - ( - "course", - models.OneToOneField( - on_delete=django.db.models.deletion.CASCADE, - to="judge.course", - verbose_name="course", - ), - ), - ], - ), - ] diff --git a/judge/migrations/0149_auto_20230202_0902.py b/judge/migrations/0149_auto_20230202_0902.py deleted file mode 100644 index 8b0d885..0000000 --- a/judge/migrations/0149_auto_20230202_0902.py +++ /dev/null @@ -1,682 +0,0 @@ -# Generated by Django 3.2.16 on 2023-02-02 02:02 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0148_course_courseassignment_courseresource_courserole"), - ] - - operations = [ - migrations.AlterField( - model_name="notification", - name="category", - field=models.CharField(max_length=1000, verbose_name="category"), - ), - migrations.AlterField( - model_name="profile", - name="timezone", - field=models.CharField( - choices=[ - ( - "Africa", - [ - ("Africa/Abidjan", "Abidjan"), - ("Africa/Accra", "Accra"), - ("Africa/Addis_Ababa", "Addis_Ababa"), - ("Africa/Algiers", "Algiers"), - ("Africa/Asmara", "Asmara"), - ("Africa/Asmera", "Asmera"), - ("Africa/Bamako", "Bamako"), - ("Africa/Bangui", "Bangui"), - ("Africa/Banjul", "Banjul"), - ("Africa/Bissau", "Bissau"), - ("Africa/Blantyre", "Blantyre"), - ("Africa/Brazzaville", "Brazzaville"), - ("Africa/Bujumbura", "Bujumbura"), - ("Africa/Cairo", "Cairo"), - ("Africa/Casablanca", "Casablanca"), - ("Africa/Ceuta", "Ceuta"), - ("Africa/Conakry", "Conakry"), - ("Africa/Dakar", "Dakar"), - ("Africa/Dar_es_Salaam", "Dar_es_Salaam"), - ("Africa/Djibouti", "Djibouti"), - ("Africa/Douala", "Douala"), - ("Africa/El_Aaiun", "El_Aaiun"), - ("Africa/Freetown", "Freetown"), - ("Africa/Gaborone", "Gaborone"), - ("Africa/Harare", "Harare"), - ("Africa/Johannesburg", "Johannesburg"), - ("Africa/Juba", "Juba"), - ("Africa/Kampala", "Kampala"), - ("Africa/Khartoum", "Khartoum"), - ("Africa/Kigali", "Kigali"), - ("Africa/Kinshasa", "Kinshasa"), - ("Africa/Lagos", "Lagos"), - ("Africa/Libreville", "Libreville"), - ("Africa/Lome", "Lome"), - ("Africa/Luanda", "Luanda"), - ("Africa/Lubumbashi", "Lubumbashi"), - ("Africa/Lusaka", "Lusaka"), - ("Africa/Malabo", "Malabo"), - ("Africa/Maputo", "Maputo"), - ("Africa/Maseru", "Maseru"), - ("Africa/Mbabane", "Mbabane"), - ("Africa/Mogadishu", "Mogadishu"), - ("Africa/Monrovia", "Monrovia"), - ("Africa/Nairobi", "Nairobi"), - ("Africa/Ndjamena", "Ndjamena"), - ("Africa/Niamey", "Niamey"), - ("Africa/Nouakchott", "Nouakchott"), - ("Africa/Ouagadougou", "Ouagadougou"), - ("Africa/Porto-Novo", "Porto-Novo"), - ("Africa/Sao_Tome", "Sao_Tome"), - ("Africa/Timbuktu", "Timbuktu"), - ("Africa/Tripoli", "Tripoli"), - ("Africa/Tunis", "Tunis"), - ("Africa/Windhoek", "Windhoek"), - ], - ), - ( - "America", - [ - ("America/Adak", "Adak"), - ("America/Anchorage", "Anchorage"), - ("America/Anguilla", "Anguilla"), - ("America/Antigua", "Antigua"), - ("America/Araguaina", "Araguaina"), - ( - "America/Argentina/Buenos_Aires", - "Argentina/Buenos_Aires", - ), - ("America/Argentina/Catamarca", "Argentina/Catamarca"), - ( - "America/Argentina/ComodRivadavia", - "Argentina/ComodRivadavia", - ), - ("America/Argentina/Cordoba", "Argentina/Cordoba"), - ("America/Argentina/Jujuy", "Argentina/Jujuy"), - ("America/Argentina/La_Rioja", "Argentina/La_Rioja"), - ("America/Argentina/Mendoza", "Argentina/Mendoza"), - ( - "America/Argentina/Rio_Gallegos", - "Argentina/Rio_Gallegos", - ), - ("America/Argentina/Salta", "Argentina/Salta"), - ("America/Argentina/San_Juan", "Argentina/San_Juan"), - ("America/Argentina/San_Luis", "Argentina/San_Luis"), - ("America/Argentina/Tucuman", "Argentina/Tucuman"), - ("America/Argentina/Ushuaia", "Argentina/Ushuaia"), - ("America/Aruba", "Aruba"), - ("America/Asuncion", "Asuncion"), - ("America/Atikokan", "Atikokan"), - ("America/Atka", "Atka"), - ("America/Bahia", "Bahia"), - ("America/Bahia_Banderas", "Bahia_Banderas"), - ("America/Barbados", "Barbados"), - ("America/Belem", "Belem"), - ("America/Belize", "Belize"), - ("America/Blanc-Sablon", "Blanc-Sablon"), - ("America/Boa_Vista", "Boa_Vista"), - ("America/Bogota", "Bogota"), - ("America/Boise", "Boise"), - ("America/Buenos_Aires", "Buenos_Aires"), - ("America/Cambridge_Bay", "Cambridge_Bay"), - ("America/Campo_Grande", "Campo_Grande"), - ("America/Cancun", "Cancun"), - ("America/Caracas", "Caracas"), - ("America/Catamarca", "Catamarca"), - ("America/Cayenne", "Cayenne"), - ("America/Cayman", "Cayman"), - ("America/Chicago", "Chicago"), - ("America/Chihuahua", "Chihuahua"), - ("America/Coral_Harbour", "Coral_Harbour"), - ("America/Cordoba", "Cordoba"), - ("America/Costa_Rica", "Costa_Rica"), - ("America/Creston", "Creston"), - ("America/Cuiaba", "Cuiaba"), - ("America/Curacao", "Curacao"), - ("America/Danmarkshavn", "Danmarkshavn"), - ("America/Dawson", "Dawson"), - ("America/Dawson_Creek", "Dawson_Creek"), - ("America/Denver", "Denver"), - ("America/Detroit", "Detroit"), - ("America/Dominica", "Dominica"), - ("America/Edmonton", "Edmonton"), - ("America/Eirunepe", "Eirunepe"), - ("America/El_Salvador", "El_Salvador"), - ("America/Ensenada", "Ensenada"), - ("America/Fort_Nelson", "Fort_Nelson"), - ("America/Fort_Wayne", "Fort_Wayne"), - ("America/Fortaleza", "Fortaleza"), - ("America/Glace_Bay", "Glace_Bay"), - ("America/Godthab", "Godthab"), - ("America/Goose_Bay", "Goose_Bay"), - ("America/Grand_Turk", "Grand_Turk"), - ("America/Grenada", "Grenada"), - ("America/Guadeloupe", "Guadeloupe"), - ("America/Guatemala", "Guatemala"), - ("America/Guayaquil", "Guayaquil"), - ("America/Guyana", "Guyana"), - ("America/Halifax", "Halifax"), - ("America/Havana", "Havana"), - ("America/Hermosillo", "Hermosillo"), - ("America/Indiana/Indianapolis", "Indiana/Indianapolis"), - ("America/Indiana/Knox", "Indiana/Knox"), - ("America/Indiana/Marengo", "Indiana/Marengo"), - ("America/Indiana/Petersburg", "Indiana/Petersburg"), - ("America/Indiana/Tell_City", "Indiana/Tell_City"), - ("America/Indiana/Vevay", "Indiana/Vevay"), - ("America/Indiana/Vincennes", "Indiana/Vincennes"), - ("America/Indiana/Winamac", "Indiana/Winamac"), - ("America/Indianapolis", "Indianapolis"), - ("America/Inuvik", "Inuvik"), - ("America/Iqaluit", "Iqaluit"), - ("America/Jamaica", "Jamaica"), - ("America/Jujuy", "Jujuy"), - ("America/Juneau", "Juneau"), - ("America/Kentucky/Louisville", "Kentucky/Louisville"), - ("America/Kentucky/Monticello", "Kentucky/Monticello"), - ("America/Knox_IN", "Knox_IN"), - ("America/Kralendijk", "Kralendijk"), - ("America/La_Paz", "La_Paz"), - ("America/Lima", "Lima"), - ("America/Los_Angeles", "Los_Angeles"), - ("America/Louisville", "Louisville"), - ("America/Lower_Princes", "Lower_Princes"), - ("America/Maceio", "Maceio"), - ("America/Managua", "Managua"), - ("America/Manaus", "Manaus"), - ("America/Marigot", "Marigot"), - ("America/Martinique", "Martinique"), - ("America/Matamoros", "Matamoros"), - ("America/Mazatlan", "Mazatlan"), - ("America/Mendoza", "Mendoza"), - ("America/Menominee", "Menominee"), - ("America/Merida", "Merida"), - ("America/Metlakatla", "Metlakatla"), - ("America/Mexico_City", "Mexico_City"), - ("America/Miquelon", "Miquelon"), - ("America/Moncton", "Moncton"), - ("America/Monterrey", "Monterrey"), - ("America/Montevideo", "Montevideo"), - ("America/Montreal", "Montreal"), - ("America/Montserrat", "Montserrat"), - ("America/Nassau", "Nassau"), - ("America/New_York", "New_York"), - ("America/Nipigon", "Nipigon"), - ("America/Nome", "Nome"), - ("America/Noronha", "Noronha"), - ("America/North_Dakota/Beulah", "North_Dakota/Beulah"), - ("America/North_Dakota/Center", "North_Dakota/Center"), - ( - "America/North_Dakota/New_Salem", - "North_Dakota/New_Salem", - ), - ("America/Nuuk", "Nuuk"), - ("America/Ojinaga", "Ojinaga"), - ("America/Panama", "Panama"), - ("America/Pangnirtung", "Pangnirtung"), - ("America/Paramaribo", "Paramaribo"), - ("America/Phoenix", "Phoenix"), - ("America/Port-au-Prince", "Port-au-Prince"), - ("America/Port_of_Spain", "Port_of_Spain"), - ("America/Porto_Acre", "Porto_Acre"), - ("America/Porto_Velho", "Porto_Velho"), - ("America/Puerto_Rico", "Puerto_Rico"), - ("America/Punta_Arenas", "Punta_Arenas"), - ("America/Rainy_River", "Rainy_River"), - ("America/Rankin_Inlet", "Rankin_Inlet"), - ("America/Recife", "Recife"), - ("America/Regina", "Regina"), - ("America/Resolute", "Resolute"), - ("America/Rio_Branco", "Rio_Branco"), - ("America/Rosario", "Rosario"), - ("America/Santa_Isabel", "Santa_Isabel"), - ("America/Santarem", "Santarem"), - ("America/Santiago", "Santiago"), - ("America/Santo_Domingo", "Santo_Domingo"), - ("America/Sao_Paulo", "Sao_Paulo"), - ("America/Scoresbysund", "Scoresbysund"), - ("America/Shiprock", "Shiprock"), - ("America/Sitka", "Sitka"), - ("America/St_Barthelemy", "St_Barthelemy"), - ("America/St_Johns", "St_Johns"), - ("America/St_Kitts", "St_Kitts"), - ("America/St_Lucia", "St_Lucia"), - ("America/St_Thomas", "St_Thomas"), - ("America/St_Vincent", "St_Vincent"), - ("America/Swift_Current", "Swift_Current"), - ("America/Tegucigalpa", "Tegucigalpa"), - ("America/Thule", "Thule"), - ("America/Thunder_Bay", "Thunder_Bay"), - ("America/Tijuana", "Tijuana"), - ("America/Toronto", "Toronto"), - ("America/Tortola", "Tortola"), - ("America/Vancouver", "Vancouver"), - ("America/Virgin", "Virgin"), - ("America/Whitehorse", "Whitehorse"), - ("America/Winnipeg", "Winnipeg"), - ("America/Yakutat", "Yakutat"), - ("America/Yellowknife", "Yellowknife"), - ], - ), - ( - "Antarctica", - [ - ("Antarctica/Casey", "Casey"), - ("Antarctica/Davis", "Davis"), - ("Antarctica/DumontDUrville", "DumontDUrville"), - ("Antarctica/Macquarie", "Macquarie"), - ("Antarctica/Mawson", "Mawson"), - ("Antarctica/McMurdo", "McMurdo"), - ("Antarctica/Palmer", "Palmer"), - ("Antarctica/Rothera", "Rothera"), - ("Antarctica/South_Pole", "South_Pole"), - ("Antarctica/Syowa", "Syowa"), - ("Antarctica/Troll", "Troll"), - ("Antarctica/Vostok", "Vostok"), - ], - ), - ("Arctic", [("Arctic/Longyearbyen", "Longyearbyen")]), - ( - "Asia", - [ - ("Asia/Aden", "Aden"), - ("Asia/Almaty", "Almaty"), - ("Asia/Amman", "Amman"), - ("Asia/Anadyr", "Anadyr"), - ("Asia/Aqtau", "Aqtau"), - ("Asia/Aqtobe", "Aqtobe"), - ("Asia/Ashgabat", "Ashgabat"), - ("Asia/Ashkhabad", "Ashkhabad"), - ("Asia/Atyrau", "Atyrau"), - ("Asia/Baghdad", "Baghdad"), - ("Asia/Bahrain", "Bahrain"), - ("Asia/Baku", "Baku"), - ("Asia/Bangkok", "Bangkok"), - ("Asia/Barnaul", "Barnaul"), - ("Asia/Beirut", "Beirut"), - ("Asia/Bishkek", "Bishkek"), - ("Asia/Brunei", "Brunei"), - ("Asia/Calcutta", "Calcutta"), - ("Asia/Chita", "Chita"), - ("Asia/Choibalsan", "Choibalsan"), - ("Asia/Chongqing", "Chongqing"), - ("Asia/Chungking", "Chungking"), - ("Asia/Colombo", "Colombo"), - ("Asia/Dacca", "Dacca"), - ("Asia/Damascus", "Damascus"), - ("Asia/Dhaka", "Dhaka"), - ("Asia/Dili", "Dili"), - ("Asia/Dubai", "Dubai"), - ("Asia/Dushanbe", "Dushanbe"), - ("Asia/Famagusta", "Famagusta"), - ("Asia/Gaza", "Gaza"), - ("Asia/Harbin", "Harbin"), - ("Asia/Hebron", "Hebron"), - ("Asia/Ho_Chi_Minh", "Ho_Chi_Minh"), - ("Asia/Hong_Kong", "Hong_Kong"), - ("Asia/Hovd", "Hovd"), - ("Asia/Irkutsk", "Irkutsk"), - ("Asia/Istanbul", "Istanbul"), - ("Asia/Jakarta", "Jakarta"), - ("Asia/Jayapura", "Jayapura"), - ("Asia/Jerusalem", "Jerusalem"), - ("Asia/Kabul", "Kabul"), - ("Asia/Kamchatka", "Kamchatka"), - ("Asia/Karachi", "Karachi"), - ("Asia/Kashgar", "Kashgar"), - ("Asia/Kathmandu", "Kathmandu"), - ("Asia/Katmandu", "Katmandu"), - ("Asia/Khandyga", "Khandyga"), - ("Asia/Kolkata", "Kolkata"), - ("Asia/Krasnoyarsk", "Krasnoyarsk"), - ("Asia/Kuala_Lumpur", "Kuala_Lumpur"), - ("Asia/Kuching", "Kuching"), - ("Asia/Kuwait", "Kuwait"), - ("Asia/Macao", "Macao"), - ("Asia/Macau", "Macau"), - ("Asia/Magadan", "Magadan"), - ("Asia/Makassar", "Makassar"), - ("Asia/Manila", "Manila"), - ("Asia/Muscat", "Muscat"), - ("Asia/Nicosia", "Nicosia"), - ("Asia/Novokuznetsk", "Novokuznetsk"), - ("Asia/Novosibirsk", "Novosibirsk"), - ("Asia/Omsk", "Omsk"), - ("Asia/Oral", "Oral"), - ("Asia/Phnom_Penh", "Phnom_Penh"), - ("Asia/Pontianak", "Pontianak"), - ("Asia/Pyongyang", "Pyongyang"), - ("Asia/Qatar", "Qatar"), - ("Asia/Qostanay", "Qostanay"), - ("Asia/Qyzylorda", "Qyzylorda"), - ("Asia/Rangoon", "Rangoon"), - ("Asia/Riyadh", "Riyadh"), - ("Asia/Saigon", "Saigon"), - ("Asia/Sakhalin", "Sakhalin"), - ("Asia/Samarkand", "Samarkand"), - ("Asia/Seoul", "Seoul"), - ("Asia/Shanghai", "Shanghai"), - ("Asia/Singapore", "Singapore"), - ("Asia/Srednekolymsk", "Srednekolymsk"), - ("Asia/Taipei", "Taipei"), - ("Asia/Tashkent", "Tashkent"), - ("Asia/Tbilisi", "Tbilisi"), - ("Asia/Tehran", "Tehran"), - ("Asia/Tel_Aviv", "Tel_Aviv"), - ("Asia/Thimbu", "Thimbu"), - ("Asia/Thimphu", "Thimphu"), - ("Asia/Tokyo", "Tokyo"), - ("Asia/Tomsk", "Tomsk"), - ("Asia/Ujung_Pandang", "Ujung_Pandang"), - ("Asia/Ulaanbaatar", "Ulaanbaatar"), - ("Asia/Ulan_Bator", "Ulan_Bator"), - ("Asia/Urumqi", "Urumqi"), - ("Asia/Ust-Nera", "Ust-Nera"), - ("Asia/Vientiane", "Vientiane"), - ("Asia/Vladivostok", "Vladivostok"), - ("Asia/Yakutsk", "Yakutsk"), - ("Asia/Yangon", "Yangon"), - ("Asia/Yekaterinburg", "Yekaterinburg"), - ("Asia/Yerevan", "Yerevan"), - ], - ), - ( - "Atlantic", - [ - ("Atlantic/Azores", "Azores"), - ("Atlantic/Bermuda", "Bermuda"), - ("Atlantic/Canary", "Canary"), - ("Atlantic/Cape_Verde", "Cape_Verde"), - ("Atlantic/Faeroe", "Faeroe"), - ("Atlantic/Faroe", "Faroe"), - ("Atlantic/Jan_Mayen", "Jan_Mayen"), - ("Atlantic/Madeira", "Madeira"), - ("Atlantic/Reykjavik", "Reykjavik"), - ("Atlantic/South_Georgia", "South_Georgia"), - ("Atlantic/St_Helena", "St_Helena"), - ("Atlantic/Stanley", "Stanley"), - ], - ), - ( - "Australia", - [ - ("Australia/ACT", "ACT"), - ("Australia/Adelaide", "Adelaide"), - ("Australia/Brisbane", "Brisbane"), - ("Australia/Broken_Hill", "Broken_Hill"), - ("Australia/Canberra", "Canberra"), - ("Australia/Currie", "Currie"), - ("Australia/Darwin", "Darwin"), - ("Australia/Eucla", "Eucla"), - ("Australia/Hobart", "Hobart"), - ("Australia/LHI", "LHI"), - ("Australia/Lindeman", "Lindeman"), - ("Australia/Lord_Howe", "Lord_Howe"), - ("Australia/Melbourne", "Melbourne"), - ("Australia/NSW", "NSW"), - ("Australia/North", "North"), - ("Australia/Perth", "Perth"), - ("Australia/Queensland", "Queensland"), - ("Australia/South", "South"), - ("Australia/Sydney", "Sydney"), - ("Australia/Tasmania", "Tasmania"), - ("Australia/Victoria", "Victoria"), - ("Australia/West", "West"), - ("Australia/Yancowinna", "Yancowinna"), - ], - ), - ( - "Brazil", - [ - ("Brazil/Acre", "Acre"), - ("Brazil/DeNoronha", "DeNoronha"), - ("Brazil/East", "East"), - ("Brazil/West", "West"), - ], - ), - ( - "Canada", - [ - ("Canada/Atlantic", "Atlantic"), - ("Canada/Central", "Central"), - ("Canada/Eastern", "Eastern"), - ("Canada/Mountain", "Mountain"), - ("Canada/Newfoundland", "Newfoundland"), - ("Canada/Pacific", "Pacific"), - ("Canada/Saskatchewan", "Saskatchewan"), - ("Canada/Yukon", "Yukon"), - ], - ), - ( - "Chile", - [ - ("Chile/Continental", "Continental"), - ("Chile/EasterIsland", "EasterIsland"), - ], - ), - ( - "Etc", - [ - ("Etc/Greenwich", "Greenwich"), - ("Etc/UCT", "UCT"), - ("Etc/UTC", "UTC"), - ("Etc/Universal", "Universal"), - ("Etc/Zulu", "Zulu"), - ], - ), - ( - "Europe", - [ - ("Europe/Amsterdam", "Amsterdam"), - ("Europe/Andorra", "Andorra"), - ("Europe/Astrakhan", "Astrakhan"), - ("Europe/Athens", "Athens"), - ("Europe/Belfast", "Belfast"), - ("Europe/Belgrade", "Belgrade"), - ("Europe/Berlin", "Berlin"), - ("Europe/Bratislava", "Bratislava"), - ("Europe/Brussels", "Brussels"), - ("Europe/Bucharest", "Bucharest"), - ("Europe/Budapest", "Budapest"), - ("Europe/Busingen", "Busingen"), - ("Europe/Chisinau", "Chisinau"), - ("Europe/Copenhagen", "Copenhagen"), - ("Europe/Dublin", "Dublin"), - ("Europe/Gibraltar", "Gibraltar"), - ("Europe/Guernsey", "Guernsey"), - ("Europe/Helsinki", "Helsinki"), - ("Europe/Isle_of_Man", "Isle_of_Man"), - ("Europe/Istanbul", "Istanbul"), - ("Europe/Jersey", "Jersey"), - ("Europe/Kaliningrad", "Kaliningrad"), - ("Europe/Kiev", "Kiev"), - ("Europe/Kirov", "Kirov"), - ("Europe/Kyiv", "Kyiv"), - ("Europe/Lisbon", "Lisbon"), - ("Europe/Ljubljana", "Ljubljana"), - ("Europe/London", "London"), - ("Europe/Luxembourg", "Luxembourg"), - ("Europe/Madrid", "Madrid"), - ("Europe/Malta", "Malta"), - ("Europe/Mariehamn", "Mariehamn"), - ("Europe/Minsk", "Minsk"), - ("Europe/Monaco", "Monaco"), - ("Europe/Moscow", "Moscow"), - ("Europe/Nicosia", "Nicosia"), - ("Europe/Oslo", "Oslo"), - ("Europe/Paris", "Paris"), - ("Europe/Podgorica", "Podgorica"), - ("Europe/Prague", "Prague"), - ("Europe/Riga", "Riga"), - ("Europe/Rome", "Rome"), - ("Europe/Samara", "Samara"), - ("Europe/San_Marino", "San_Marino"), - ("Europe/Sarajevo", "Sarajevo"), - ("Europe/Saratov", "Saratov"), - ("Europe/Simferopol", "Simferopol"), - ("Europe/Skopje", "Skopje"), - ("Europe/Sofia", "Sofia"), - ("Europe/Stockholm", "Stockholm"), - ("Europe/Tallinn", "Tallinn"), - ("Europe/Tirane", "Tirane"), - ("Europe/Tiraspol", "Tiraspol"), - ("Europe/Ulyanovsk", "Ulyanovsk"), - ("Europe/Uzhgorod", "Uzhgorod"), - ("Europe/Vaduz", "Vaduz"), - ("Europe/Vatican", "Vatican"), - ("Europe/Vienna", "Vienna"), - ("Europe/Vilnius", "Vilnius"), - ("Europe/Volgograd", "Volgograd"), - ("Europe/Warsaw", "Warsaw"), - ("Europe/Zagreb", "Zagreb"), - ("Europe/Zaporozhye", "Zaporozhye"), - ("Europe/Zurich", "Zurich"), - ], - ), - ( - "Indian", - [ - ("Indian/Antananarivo", "Antananarivo"), - ("Indian/Chagos", "Chagos"), - ("Indian/Christmas", "Christmas"), - ("Indian/Cocos", "Cocos"), - ("Indian/Comoro", "Comoro"), - ("Indian/Kerguelen", "Kerguelen"), - ("Indian/Mahe", "Mahe"), - ("Indian/Maldives", "Maldives"), - ("Indian/Mauritius", "Mauritius"), - ("Indian/Mayotte", "Mayotte"), - ("Indian/Reunion", "Reunion"), - ], - ), - ( - "Mexico", - [ - ("Mexico/BajaNorte", "BajaNorte"), - ("Mexico/BajaSur", "BajaSur"), - ("Mexico/General", "General"), - ], - ), - ( - "Other", - [ - ("CET", "CET"), - ("CST6CDT", "CST6CDT"), - ("Cuba", "Cuba"), - ("EET", "EET"), - ("EST", "EST"), - ("EST5EDT", "EST5EDT"), - ("Egypt", "Egypt"), - ("Eire", "Eire"), - ("GB", "GB"), - ("GB-Eire", "GB-Eire"), - ("Greenwich", "Greenwich"), - ("HST", "HST"), - ("Hongkong", "Hongkong"), - ("Iceland", "Iceland"), - ("Iran", "Iran"), - ("Israel", "Israel"), - ("Jamaica", "Jamaica"), - ("Japan", "Japan"), - ("Kwajalein", "Kwajalein"), - ("Libya", "Libya"), - ("MET", "MET"), - ("MST", "MST"), - ("MST7MDT", "MST7MDT"), - ("NZ", "NZ"), - ("NZ-CHAT", "NZ-CHAT"), - ("Navajo", "Navajo"), - ("PRC", "PRC"), - ("PST8PDT", "PST8PDT"), - ("Poland", "Poland"), - ("Portugal", "Portugal"), - ("ROC", "ROC"), - ("ROK", "ROK"), - ("Singapore", "Singapore"), - ("Turkey", "Turkey"), - ("UCT", "UCT"), - ("UTC", "UTC"), - ("Universal", "Universal"), - ("W-SU", "W-SU"), - ("WET", "WET"), - ("Zulu", "Zulu"), - ], - ), - ( - "Pacific", - [ - ("Pacific/Apia", "Apia"), - ("Pacific/Auckland", "Auckland"), - ("Pacific/Bougainville", "Bougainville"), - ("Pacific/Chatham", "Chatham"), - ("Pacific/Chuuk", "Chuuk"), - ("Pacific/Easter", "Easter"), - ("Pacific/Efate", "Efate"), - ("Pacific/Enderbury", "Enderbury"), - ("Pacific/Fakaofo", "Fakaofo"), - ("Pacific/Fiji", "Fiji"), - ("Pacific/Funafuti", "Funafuti"), - ("Pacific/Galapagos", "Galapagos"), - ("Pacific/Gambier", "Gambier"), - ("Pacific/Guadalcanal", "Guadalcanal"), - ("Pacific/Guam", "Guam"), - ("Pacific/Honolulu", "Honolulu"), - ("Pacific/Johnston", "Johnston"), - ("Pacific/Kanton", "Kanton"), - ("Pacific/Kiritimati", "Kiritimati"), - ("Pacific/Kosrae", "Kosrae"), - ("Pacific/Kwajalein", "Kwajalein"), - ("Pacific/Majuro", "Majuro"), - ("Pacific/Marquesas", "Marquesas"), - ("Pacific/Midway", "Midway"), - ("Pacific/Nauru", "Nauru"), - ("Pacific/Niue", "Niue"), - ("Pacific/Norfolk", "Norfolk"), - ("Pacific/Noumea", "Noumea"), - ("Pacific/Pago_Pago", "Pago_Pago"), - ("Pacific/Palau", "Palau"), - ("Pacific/Pitcairn", "Pitcairn"), - ("Pacific/Pohnpei", "Pohnpei"), - ("Pacific/Ponape", "Ponape"), - ("Pacific/Port_Moresby", "Port_Moresby"), - ("Pacific/Rarotonga", "Rarotonga"), - ("Pacific/Saipan", "Saipan"), - ("Pacific/Samoa", "Samoa"), - ("Pacific/Tahiti", "Tahiti"), - ("Pacific/Tarawa", "Tarawa"), - ("Pacific/Tongatapu", "Tongatapu"), - ("Pacific/Truk", "Truk"), - ("Pacific/Wake", "Wake"), - ("Pacific/Wallis", "Wallis"), - ("Pacific/Yap", "Yap"), - ], - ), - ( - "US", - [ - ("US/Alaska", "Alaska"), - ("US/Aleutian", "Aleutian"), - ("US/Arizona", "Arizona"), - ("US/Central", "Central"), - ("US/East-Indiana", "East-Indiana"), - ("US/Eastern", "Eastern"), - ("US/Hawaii", "Hawaii"), - ("US/Indiana-Starke", "Indiana-Starke"), - ("US/Michigan", "Michigan"), - ("US/Mountain", "Mountain"), - ("US/Pacific", "Pacific"), - ("US/Samoa", "Samoa"), - ], - ), - ], - default="Asia/Ho_Chi_Minh", - max_length=50, - verbose_name="location", - ), - ), - ] diff --git a/judge/migrations/0150_alter_profile_timezone.py b/judge/migrations/0150_alter_profile_timezone.py deleted file mode 100644 index 20b3e12..0000000 --- a/judge/migrations/0150_alter_profile_timezone.py +++ /dev/null @@ -1,676 +0,0 @@ -# Generated by Django 3.2.17 on 2023-02-08 01:06 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0149_auto_20230202_0902"), - ] - - operations = [ - migrations.AlterField( - model_name="profile", - name="timezone", - field=models.CharField( - choices=[ - ( - "Africa", - [ - ("Africa/Abidjan", "Abidjan"), - ("Africa/Accra", "Accra"), - ("Africa/Addis_Ababa", "Addis_Ababa"), - ("Africa/Algiers", "Algiers"), - ("Africa/Asmara", "Asmara"), - ("Africa/Asmera", "Asmera"), - ("Africa/Bamako", "Bamako"), - ("Africa/Bangui", "Bangui"), - ("Africa/Banjul", "Banjul"), - ("Africa/Bissau", "Bissau"), - ("Africa/Blantyre", "Blantyre"), - ("Africa/Brazzaville", "Brazzaville"), - ("Africa/Bujumbura", "Bujumbura"), - ("Africa/Cairo", "Cairo"), - ("Africa/Casablanca", "Casablanca"), - ("Africa/Ceuta", "Ceuta"), - ("Africa/Conakry", "Conakry"), - ("Africa/Dakar", "Dakar"), - ("Africa/Dar_es_Salaam", "Dar_es_Salaam"), - ("Africa/Djibouti", "Djibouti"), - ("Africa/Douala", "Douala"), - ("Africa/El_Aaiun", "El_Aaiun"), - ("Africa/Freetown", "Freetown"), - ("Africa/Gaborone", "Gaborone"), - ("Africa/Harare", "Harare"), - ("Africa/Johannesburg", "Johannesburg"), - ("Africa/Juba", "Juba"), - ("Africa/Kampala", "Kampala"), - ("Africa/Khartoum", "Khartoum"), - ("Africa/Kigali", "Kigali"), - ("Africa/Kinshasa", "Kinshasa"), - ("Africa/Lagos", "Lagos"), - ("Africa/Libreville", "Libreville"), - ("Africa/Lome", "Lome"), - ("Africa/Luanda", "Luanda"), - ("Africa/Lubumbashi", "Lubumbashi"), - ("Africa/Lusaka", "Lusaka"), - ("Africa/Malabo", "Malabo"), - ("Africa/Maputo", "Maputo"), - ("Africa/Maseru", "Maseru"), - ("Africa/Mbabane", "Mbabane"), - ("Africa/Mogadishu", "Mogadishu"), - ("Africa/Monrovia", "Monrovia"), - ("Africa/Nairobi", "Nairobi"), - ("Africa/Ndjamena", "Ndjamena"), - ("Africa/Niamey", "Niamey"), - ("Africa/Nouakchott", "Nouakchott"), - ("Africa/Ouagadougou", "Ouagadougou"), - ("Africa/Porto-Novo", "Porto-Novo"), - ("Africa/Sao_Tome", "Sao_Tome"), - ("Africa/Timbuktu", "Timbuktu"), - ("Africa/Tripoli", "Tripoli"), - ("Africa/Tunis", "Tunis"), - ("Africa/Windhoek", "Windhoek"), - ], - ), - ( - "America", - [ - ("America/Adak", "Adak"), - ("America/Anchorage", "Anchorage"), - ("America/Anguilla", "Anguilla"), - ("America/Antigua", "Antigua"), - ("America/Araguaina", "Araguaina"), - ( - "America/Argentina/Buenos_Aires", - "Argentina/Buenos_Aires", - ), - ("America/Argentina/Catamarca", "Argentina/Catamarca"), - ( - "America/Argentina/ComodRivadavia", - "Argentina/ComodRivadavia", - ), - ("America/Argentina/Cordoba", "Argentina/Cordoba"), - ("America/Argentina/Jujuy", "Argentina/Jujuy"), - ("America/Argentina/La_Rioja", "Argentina/La_Rioja"), - ("America/Argentina/Mendoza", "Argentina/Mendoza"), - ( - "America/Argentina/Rio_Gallegos", - "Argentina/Rio_Gallegos", - ), - ("America/Argentina/Salta", "Argentina/Salta"), - ("America/Argentina/San_Juan", "Argentina/San_Juan"), - ("America/Argentina/San_Luis", "Argentina/San_Luis"), - ("America/Argentina/Tucuman", "Argentina/Tucuman"), - ("America/Argentina/Ushuaia", "Argentina/Ushuaia"), - ("America/Aruba", "Aruba"), - ("America/Asuncion", "Asuncion"), - ("America/Atikokan", "Atikokan"), - ("America/Atka", "Atka"), - ("America/Bahia", "Bahia"), - ("America/Bahia_Banderas", "Bahia_Banderas"), - ("America/Barbados", "Barbados"), - ("America/Belem", "Belem"), - ("America/Belize", "Belize"), - ("America/Blanc-Sablon", "Blanc-Sablon"), - ("America/Boa_Vista", "Boa_Vista"), - ("America/Bogota", "Bogota"), - ("America/Boise", "Boise"), - ("America/Buenos_Aires", "Buenos_Aires"), - ("America/Cambridge_Bay", "Cambridge_Bay"), - ("America/Campo_Grande", "Campo_Grande"), - ("America/Cancun", "Cancun"), - ("America/Caracas", "Caracas"), - ("America/Catamarca", "Catamarca"), - ("America/Cayenne", "Cayenne"), - ("America/Cayman", "Cayman"), - ("America/Chicago", "Chicago"), - ("America/Chihuahua", "Chihuahua"), - ("America/Coral_Harbour", "Coral_Harbour"), - ("America/Cordoba", "Cordoba"), - ("America/Costa_Rica", "Costa_Rica"), - ("America/Creston", "Creston"), - ("America/Cuiaba", "Cuiaba"), - ("America/Curacao", "Curacao"), - ("America/Danmarkshavn", "Danmarkshavn"), - ("America/Dawson", "Dawson"), - ("America/Dawson_Creek", "Dawson_Creek"), - ("America/Denver", "Denver"), - ("America/Detroit", "Detroit"), - ("America/Dominica", "Dominica"), - ("America/Edmonton", "Edmonton"), - ("America/Eirunepe", "Eirunepe"), - ("America/El_Salvador", "El_Salvador"), - ("America/Ensenada", "Ensenada"), - ("America/Fort_Nelson", "Fort_Nelson"), - ("America/Fort_Wayne", "Fort_Wayne"), - ("America/Fortaleza", "Fortaleza"), - ("America/Glace_Bay", "Glace_Bay"), - ("America/Godthab", "Godthab"), - ("America/Goose_Bay", "Goose_Bay"), - ("America/Grand_Turk", "Grand_Turk"), - ("America/Grenada", "Grenada"), - ("America/Guadeloupe", "Guadeloupe"), - ("America/Guatemala", "Guatemala"), - ("America/Guayaquil", "Guayaquil"), - ("America/Guyana", "Guyana"), - ("America/Halifax", "Halifax"), - ("America/Havana", "Havana"), - ("America/Hermosillo", "Hermosillo"), - ("America/Indiana/Indianapolis", "Indiana/Indianapolis"), - ("America/Indiana/Knox", "Indiana/Knox"), - ("America/Indiana/Marengo", "Indiana/Marengo"), - ("America/Indiana/Petersburg", "Indiana/Petersburg"), - ("America/Indiana/Tell_City", "Indiana/Tell_City"), - ("America/Indiana/Vevay", "Indiana/Vevay"), - ("America/Indiana/Vincennes", "Indiana/Vincennes"), - ("America/Indiana/Winamac", "Indiana/Winamac"), - ("America/Indianapolis", "Indianapolis"), - ("America/Inuvik", "Inuvik"), - ("America/Iqaluit", "Iqaluit"), - ("America/Jamaica", "Jamaica"), - ("America/Jujuy", "Jujuy"), - ("America/Juneau", "Juneau"), - ("America/Kentucky/Louisville", "Kentucky/Louisville"), - ("America/Kentucky/Monticello", "Kentucky/Monticello"), - ("America/Knox_IN", "Knox_IN"), - ("America/Kralendijk", "Kralendijk"), - ("America/La_Paz", "La_Paz"), - ("America/Lima", "Lima"), - ("America/Los_Angeles", "Los_Angeles"), - ("America/Louisville", "Louisville"), - ("America/Lower_Princes", "Lower_Princes"), - ("America/Maceio", "Maceio"), - ("America/Managua", "Managua"), - ("America/Manaus", "Manaus"), - ("America/Marigot", "Marigot"), - ("America/Martinique", "Martinique"), - ("America/Matamoros", "Matamoros"), - ("America/Mazatlan", "Mazatlan"), - ("America/Mendoza", "Mendoza"), - ("America/Menominee", "Menominee"), - ("America/Merida", "Merida"), - ("America/Metlakatla", "Metlakatla"), - ("America/Mexico_City", "Mexico_City"), - ("America/Miquelon", "Miquelon"), - ("America/Moncton", "Moncton"), - ("America/Monterrey", "Monterrey"), - ("America/Montevideo", "Montevideo"), - ("America/Montreal", "Montreal"), - ("America/Montserrat", "Montserrat"), - ("America/Nassau", "Nassau"), - ("America/New_York", "New_York"), - ("America/Nipigon", "Nipigon"), - ("America/Nome", "Nome"), - ("America/Noronha", "Noronha"), - ("America/North_Dakota/Beulah", "North_Dakota/Beulah"), - ("America/North_Dakota/Center", "North_Dakota/Center"), - ( - "America/North_Dakota/New_Salem", - "North_Dakota/New_Salem", - ), - ("America/Nuuk", "Nuuk"), - ("America/Ojinaga", "Ojinaga"), - ("America/Panama", "Panama"), - ("America/Pangnirtung", "Pangnirtung"), - ("America/Paramaribo", "Paramaribo"), - ("America/Phoenix", "Phoenix"), - ("America/Port-au-Prince", "Port-au-Prince"), - ("America/Port_of_Spain", "Port_of_Spain"), - ("America/Porto_Acre", "Porto_Acre"), - ("America/Porto_Velho", "Porto_Velho"), - ("America/Puerto_Rico", "Puerto_Rico"), - ("America/Punta_Arenas", "Punta_Arenas"), - ("America/Rainy_River", "Rainy_River"), - ("America/Rankin_Inlet", "Rankin_Inlet"), - ("America/Recife", "Recife"), - ("America/Regina", "Regina"), - ("America/Resolute", "Resolute"), - ("America/Rio_Branco", "Rio_Branco"), - ("America/Rosario", "Rosario"), - ("America/Santa_Isabel", "Santa_Isabel"), - ("America/Santarem", "Santarem"), - ("America/Santiago", "Santiago"), - ("America/Santo_Domingo", "Santo_Domingo"), - ("America/Sao_Paulo", "Sao_Paulo"), - ("America/Scoresbysund", "Scoresbysund"), - ("America/Shiprock", "Shiprock"), - ("America/Sitka", "Sitka"), - ("America/St_Barthelemy", "St_Barthelemy"), - ("America/St_Johns", "St_Johns"), - ("America/St_Kitts", "St_Kitts"), - ("America/St_Lucia", "St_Lucia"), - ("America/St_Thomas", "St_Thomas"), - ("America/St_Vincent", "St_Vincent"), - ("America/Swift_Current", "Swift_Current"), - ("America/Tegucigalpa", "Tegucigalpa"), - ("America/Thule", "Thule"), - ("America/Thunder_Bay", "Thunder_Bay"), - ("America/Tijuana", "Tijuana"), - ("America/Toronto", "Toronto"), - ("America/Tortola", "Tortola"), - ("America/Vancouver", "Vancouver"), - ("America/Virgin", "Virgin"), - ("America/Whitehorse", "Whitehorse"), - ("America/Winnipeg", "Winnipeg"), - ("America/Yakutat", "Yakutat"), - ("America/Yellowknife", "Yellowknife"), - ], - ), - ( - "Antarctica", - [ - ("Antarctica/Casey", "Casey"), - ("Antarctica/Davis", "Davis"), - ("Antarctica/DumontDUrville", "DumontDUrville"), - ("Antarctica/Macquarie", "Macquarie"), - ("Antarctica/Mawson", "Mawson"), - ("Antarctica/McMurdo", "McMurdo"), - ("Antarctica/Palmer", "Palmer"), - ("Antarctica/Rothera", "Rothera"), - ("Antarctica/South_Pole", "South_Pole"), - ("Antarctica/Syowa", "Syowa"), - ("Antarctica/Troll", "Troll"), - ("Antarctica/Vostok", "Vostok"), - ], - ), - ("Arctic", [("Arctic/Longyearbyen", "Longyearbyen")]), - ( - "Asia", - [ - ("Asia/Aden", "Aden"), - ("Asia/Almaty", "Almaty"), - ("Asia/Amman", "Amman"), - ("Asia/Anadyr", "Anadyr"), - ("Asia/Aqtau", "Aqtau"), - ("Asia/Aqtobe", "Aqtobe"), - ("Asia/Ashgabat", "Ashgabat"), - ("Asia/Ashkhabad", "Ashkhabad"), - ("Asia/Atyrau", "Atyrau"), - ("Asia/Baghdad", "Baghdad"), - ("Asia/Bahrain", "Bahrain"), - ("Asia/Baku", "Baku"), - ("Asia/Bangkok", "Bangkok"), - ("Asia/Barnaul", "Barnaul"), - ("Asia/Beirut", "Beirut"), - ("Asia/Bishkek", "Bishkek"), - ("Asia/Brunei", "Brunei"), - ("Asia/Calcutta", "Calcutta"), - ("Asia/Chita", "Chita"), - ("Asia/Choibalsan", "Choibalsan"), - ("Asia/Chongqing", "Chongqing"), - ("Asia/Chungking", "Chungking"), - ("Asia/Colombo", "Colombo"), - ("Asia/Dacca", "Dacca"), - ("Asia/Damascus", "Damascus"), - ("Asia/Dhaka", "Dhaka"), - ("Asia/Dili", "Dili"), - ("Asia/Dubai", "Dubai"), - ("Asia/Dushanbe", "Dushanbe"), - ("Asia/Famagusta", "Famagusta"), - ("Asia/Gaza", "Gaza"), - ("Asia/Harbin", "Harbin"), - ("Asia/Hebron", "Hebron"), - ("Asia/Ho_Chi_Minh", "Ho_Chi_Minh"), - ("Asia/Hong_Kong", "Hong_Kong"), - ("Asia/Hovd", "Hovd"), - ("Asia/Irkutsk", "Irkutsk"), - ("Asia/Istanbul", "Istanbul"), - ("Asia/Jakarta", "Jakarta"), - ("Asia/Jayapura", "Jayapura"), - ("Asia/Jerusalem", "Jerusalem"), - ("Asia/Kabul", "Kabul"), - ("Asia/Kamchatka", "Kamchatka"), - ("Asia/Karachi", "Karachi"), - ("Asia/Kashgar", "Kashgar"), - ("Asia/Kathmandu", "Kathmandu"), - ("Asia/Katmandu", "Katmandu"), - ("Asia/Khandyga", "Khandyga"), - ("Asia/Kolkata", "Kolkata"), - ("Asia/Krasnoyarsk", "Krasnoyarsk"), - ("Asia/Kuala_Lumpur", "Kuala_Lumpur"), - ("Asia/Kuching", "Kuching"), - ("Asia/Kuwait", "Kuwait"), - ("Asia/Macao", "Macao"), - ("Asia/Macau", "Macau"), - ("Asia/Magadan", "Magadan"), - ("Asia/Makassar", "Makassar"), - ("Asia/Manila", "Manila"), - ("Asia/Muscat", "Muscat"), - ("Asia/Nicosia", "Nicosia"), - ("Asia/Novokuznetsk", "Novokuznetsk"), - ("Asia/Novosibirsk", "Novosibirsk"), - ("Asia/Omsk", "Omsk"), - ("Asia/Oral", "Oral"), - ("Asia/Phnom_Penh", "Phnom_Penh"), - ("Asia/Pontianak", "Pontianak"), - ("Asia/Pyongyang", "Pyongyang"), - ("Asia/Qatar", "Qatar"), - ("Asia/Qostanay", "Qostanay"), - ("Asia/Qyzylorda", "Qyzylorda"), - ("Asia/Rangoon", "Rangoon"), - ("Asia/Riyadh", "Riyadh"), - ("Asia/Saigon", "Saigon"), - ("Asia/Sakhalin", "Sakhalin"), - ("Asia/Samarkand", "Samarkand"), - ("Asia/Seoul", "Seoul"), - ("Asia/Shanghai", "Shanghai"), - ("Asia/Singapore", "Singapore"), - ("Asia/Srednekolymsk", "Srednekolymsk"), - ("Asia/Taipei", "Taipei"), - ("Asia/Tashkent", "Tashkent"), - ("Asia/Tbilisi", "Tbilisi"), - ("Asia/Tehran", "Tehran"), - ("Asia/Tel_Aviv", "Tel_Aviv"), - ("Asia/Thimbu", "Thimbu"), - ("Asia/Thimphu", "Thimphu"), - ("Asia/Tokyo", "Tokyo"), - ("Asia/Tomsk", "Tomsk"), - ("Asia/Ujung_Pandang", "Ujung_Pandang"), - ("Asia/Ulaanbaatar", "Ulaanbaatar"), - ("Asia/Ulan_Bator", "Ulan_Bator"), - ("Asia/Urumqi", "Urumqi"), - ("Asia/Ust-Nera", "Ust-Nera"), - ("Asia/Vientiane", "Vientiane"), - ("Asia/Vladivostok", "Vladivostok"), - ("Asia/Yakutsk", "Yakutsk"), - ("Asia/Yangon", "Yangon"), - ("Asia/Yekaterinburg", "Yekaterinburg"), - ("Asia/Yerevan", "Yerevan"), - ], - ), - ( - "Atlantic", - [ - ("Atlantic/Azores", "Azores"), - ("Atlantic/Bermuda", "Bermuda"), - ("Atlantic/Canary", "Canary"), - ("Atlantic/Cape_Verde", "Cape_Verde"), - ("Atlantic/Faeroe", "Faeroe"), - ("Atlantic/Faroe", "Faroe"), - ("Atlantic/Jan_Mayen", "Jan_Mayen"), - ("Atlantic/Madeira", "Madeira"), - ("Atlantic/Reykjavik", "Reykjavik"), - ("Atlantic/South_Georgia", "South_Georgia"), - ("Atlantic/St_Helena", "St_Helena"), - ("Atlantic/Stanley", "Stanley"), - ], - ), - ( - "Australia", - [ - ("Australia/ACT", "ACT"), - ("Australia/Adelaide", "Adelaide"), - ("Australia/Brisbane", "Brisbane"), - ("Australia/Broken_Hill", "Broken_Hill"), - ("Australia/Canberra", "Canberra"), - ("Australia/Currie", "Currie"), - ("Australia/Darwin", "Darwin"), - ("Australia/Eucla", "Eucla"), - ("Australia/Hobart", "Hobart"), - ("Australia/LHI", "LHI"), - ("Australia/Lindeman", "Lindeman"), - ("Australia/Lord_Howe", "Lord_Howe"), - ("Australia/Melbourne", "Melbourne"), - ("Australia/NSW", "NSW"), - ("Australia/North", "North"), - ("Australia/Perth", "Perth"), - ("Australia/Queensland", "Queensland"), - ("Australia/South", "South"), - ("Australia/Sydney", "Sydney"), - ("Australia/Tasmania", "Tasmania"), - ("Australia/Victoria", "Victoria"), - ("Australia/West", "West"), - ("Australia/Yancowinna", "Yancowinna"), - ], - ), - ( - "Brazil", - [ - ("Brazil/Acre", "Acre"), - ("Brazil/DeNoronha", "DeNoronha"), - ("Brazil/East", "East"), - ("Brazil/West", "West"), - ], - ), - ( - "Canada", - [ - ("Canada/Atlantic", "Atlantic"), - ("Canada/Central", "Central"), - ("Canada/Eastern", "Eastern"), - ("Canada/Mountain", "Mountain"), - ("Canada/Newfoundland", "Newfoundland"), - ("Canada/Pacific", "Pacific"), - ("Canada/Saskatchewan", "Saskatchewan"), - ("Canada/Yukon", "Yukon"), - ], - ), - ( - "Chile", - [ - ("Chile/Continental", "Continental"), - ("Chile/EasterIsland", "EasterIsland"), - ], - ), - ( - "Etc", - [ - ("Etc/Greenwich", "Greenwich"), - ("Etc/UCT", "UCT"), - ("Etc/UTC", "UTC"), - ("Etc/Universal", "Universal"), - ("Etc/Zulu", "Zulu"), - ], - ), - ( - "Europe", - [ - ("Europe/Amsterdam", "Amsterdam"), - ("Europe/Andorra", "Andorra"), - ("Europe/Astrakhan", "Astrakhan"), - ("Europe/Athens", "Athens"), - ("Europe/Belfast", "Belfast"), - ("Europe/Belgrade", "Belgrade"), - ("Europe/Berlin", "Berlin"), - ("Europe/Bratislava", "Bratislava"), - ("Europe/Brussels", "Brussels"), - ("Europe/Bucharest", "Bucharest"), - ("Europe/Budapest", "Budapest"), - ("Europe/Busingen", "Busingen"), - ("Europe/Chisinau", "Chisinau"), - ("Europe/Copenhagen", "Copenhagen"), - ("Europe/Dublin", "Dublin"), - ("Europe/Gibraltar", "Gibraltar"), - ("Europe/Guernsey", "Guernsey"), - ("Europe/Helsinki", "Helsinki"), - ("Europe/Isle_of_Man", "Isle_of_Man"), - ("Europe/Istanbul", "Istanbul"), - ("Europe/Jersey", "Jersey"), - ("Europe/Kaliningrad", "Kaliningrad"), - ("Europe/Kiev", "Kiev"), - ("Europe/Kirov", "Kirov"), - ("Europe/Lisbon", "Lisbon"), - ("Europe/Ljubljana", "Ljubljana"), - ("Europe/London", "London"), - ("Europe/Luxembourg", "Luxembourg"), - ("Europe/Madrid", "Madrid"), - ("Europe/Malta", "Malta"), - ("Europe/Mariehamn", "Mariehamn"), - ("Europe/Minsk", "Minsk"), - ("Europe/Monaco", "Monaco"), - ("Europe/Moscow", "Moscow"), - ("Europe/Nicosia", "Nicosia"), - ("Europe/Oslo", "Oslo"), - ("Europe/Paris", "Paris"), - ("Europe/Podgorica", "Podgorica"), - ("Europe/Prague", "Prague"), - ("Europe/Riga", "Riga"), - ("Europe/Rome", "Rome"), - ("Europe/Samara", "Samara"), - ("Europe/San_Marino", "San_Marino"), - ("Europe/Sarajevo", "Sarajevo"), - ("Europe/Saratov", "Saratov"), - ("Europe/Simferopol", "Simferopol"), - ("Europe/Skopje", "Skopje"), - ("Europe/Sofia", "Sofia"), - ("Europe/Stockholm", "Stockholm"), - ("Europe/Tallinn", "Tallinn"), - ("Europe/Tirane", "Tirane"), - ("Europe/Tiraspol", "Tiraspol"), - ("Europe/Ulyanovsk", "Ulyanovsk"), - ("Europe/Uzhgorod", "Uzhgorod"), - ("Europe/Vaduz", "Vaduz"), - ("Europe/Vatican", "Vatican"), - ("Europe/Vienna", "Vienna"), - ("Europe/Vilnius", "Vilnius"), - ("Europe/Volgograd", "Volgograd"), - ("Europe/Warsaw", "Warsaw"), - ("Europe/Zagreb", "Zagreb"), - ("Europe/Zaporozhye", "Zaporozhye"), - ("Europe/Zurich", "Zurich"), - ], - ), - ( - "Indian", - [ - ("Indian/Antananarivo", "Antananarivo"), - ("Indian/Chagos", "Chagos"), - ("Indian/Christmas", "Christmas"), - ("Indian/Cocos", "Cocos"), - ("Indian/Comoro", "Comoro"), - ("Indian/Kerguelen", "Kerguelen"), - ("Indian/Mahe", "Mahe"), - ("Indian/Maldives", "Maldives"), - ("Indian/Mauritius", "Mauritius"), - ("Indian/Mayotte", "Mayotte"), - ("Indian/Reunion", "Reunion"), - ], - ), - ( - "Mexico", - [ - ("Mexico/BajaNorte", "BajaNorte"), - ("Mexico/BajaSur", "BajaSur"), - ("Mexico/General", "General"), - ], - ), - ( - "Other", - [ - ("CET", "CET"), - ("CST6CDT", "CST6CDT"), - ("Cuba", "Cuba"), - ("EET", "EET"), - ("EST", "EST"), - ("EST5EDT", "EST5EDT"), - ("Egypt", "Egypt"), - ("Eire", "Eire"), - ("GB", "GB"), - ("GB-Eire", "GB-Eire"), - ("Greenwich", "Greenwich"), - ("HST", "HST"), - ("Hongkong", "Hongkong"), - ("Iceland", "Iceland"), - ("Iran", "Iran"), - ("Israel", "Israel"), - ("Jamaica", "Jamaica"), - ("Japan", "Japan"), - ("Kwajalein", "Kwajalein"), - ("Libya", "Libya"), - ("MET", "MET"), - ("MST", "MST"), - ("MST7MDT", "MST7MDT"), - ("NZ", "NZ"), - ("NZ-CHAT", "NZ-CHAT"), - ("Navajo", "Navajo"), - ("PRC", "PRC"), - ("PST8PDT", "PST8PDT"), - ("Poland", "Poland"), - ("Portugal", "Portugal"), - ("ROC", "ROC"), - ("ROK", "ROK"), - ("Singapore", "Singapore"), - ("Turkey", "Turkey"), - ("UCT", "UCT"), - ("UTC", "UTC"), - ("Universal", "Universal"), - ("W-SU", "W-SU"), - ("WET", "WET"), - ("Zulu", "Zulu"), - ], - ), - ( - "Pacific", - [ - ("Pacific/Apia", "Apia"), - ("Pacific/Auckland", "Auckland"), - ("Pacific/Bougainville", "Bougainville"), - ("Pacific/Chatham", "Chatham"), - ("Pacific/Chuuk", "Chuuk"), - ("Pacific/Easter", "Easter"), - ("Pacific/Efate", "Efate"), - ("Pacific/Enderbury", "Enderbury"), - ("Pacific/Fakaofo", "Fakaofo"), - ("Pacific/Fiji", "Fiji"), - ("Pacific/Funafuti", "Funafuti"), - ("Pacific/Galapagos", "Galapagos"), - ("Pacific/Gambier", "Gambier"), - ("Pacific/Guadalcanal", "Guadalcanal"), - ("Pacific/Guam", "Guam"), - ("Pacific/Honolulu", "Honolulu"), - ("Pacific/Johnston", "Johnston"), - ("Pacific/Kanton", "Kanton"), - ("Pacific/Kiritimati", "Kiritimati"), - ("Pacific/Kosrae", "Kosrae"), - ("Pacific/Kwajalein", "Kwajalein"), - ("Pacific/Majuro", "Majuro"), - ("Pacific/Marquesas", "Marquesas"), - ("Pacific/Midway", "Midway"), - ("Pacific/Nauru", "Nauru"), - ("Pacific/Niue", "Niue"), - ("Pacific/Norfolk", "Norfolk"), - ("Pacific/Noumea", "Noumea"), - ("Pacific/Pago_Pago", "Pago_Pago"), - ("Pacific/Palau", "Palau"), - ("Pacific/Pitcairn", "Pitcairn"), - ("Pacific/Pohnpei", "Pohnpei"), - ("Pacific/Ponape", "Ponape"), - ("Pacific/Port_Moresby", "Port_Moresby"), - ("Pacific/Rarotonga", "Rarotonga"), - ("Pacific/Saipan", "Saipan"), - ("Pacific/Samoa", "Samoa"), - ("Pacific/Tahiti", "Tahiti"), - ("Pacific/Tarawa", "Tarawa"), - ("Pacific/Tongatapu", "Tongatapu"), - ("Pacific/Truk", "Truk"), - ("Pacific/Wake", "Wake"), - ("Pacific/Wallis", "Wallis"), - ("Pacific/Yap", "Yap"), - ], - ), - ( - "US", - [ - ("US/Alaska", "Alaska"), - ("US/Aleutian", "Aleutian"), - ("US/Arizona", "Arizona"), - ("US/Central", "Central"), - ("US/East-Indiana", "East-Indiana"), - ("US/Eastern", "Eastern"), - ("US/Hawaii", "Hawaii"), - ("US/Indiana-Starke", "Indiana-Starke"), - ("US/Michigan", "Michigan"), - ("US/Mountain", "Mountain"), - ("US/Pacific", "Pacific"), - ("US/Samoa", "Samoa"), - ], - ), - ], - default="Asia/Ho_Chi_Minh", - max_length=50, - verbose_name="location", - ), - ), - ] diff --git a/judge/migrations/0151_comment_content_type.py b/judge/migrations/0151_comment_content_type.py deleted file mode 100644 index d1897d9..0000000 --- a/judge/migrations/0151_comment_content_type.py +++ /dev/null @@ -1,50 +0,0 @@ -# Generated by Django 3.2.18 on 2023-02-20 21:26 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ("contenttypes", "0002_remove_content_type_name"), - ("judge", "0150_alter_profile_timezone"), - ] - - operations = [ - migrations.AddField( - model_name="comment", - name="content_type", - field=models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="contenttypes.contenttype", - ), - preserve_default=False, - ), - migrations.AddField( - model_name="comment", - name="object_id", - field=models.PositiveIntegerField(null=True), - preserve_default=False, - ), - migrations.AlterField( - model_name="solution", - name="problem", - field=models.OneToOneField( - blank=True, - null=True, - on_delete=django.db.models.deletion.CASCADE, - related_name="solution", - to="judge.problem", - verbose_name="associated problem", - ), - ), - migrations.AddIndex( - model_name="comment", - index=models.Index( - fields=["content_type", "object_id"], - name="judge_comme_content_2dce05_idx", - ), - ), - ] diff --git a/judge/migrations/0152_migrate_comments.py b/judge/migrations/0152_migrate_comments.py deleted file mode 100644 index bcf6531..0000000 --- a/judge/migrations/0152_migrate_comments.py +++ /dev/null @@ -1,54 +0,0 @@ -from django.db import migrations, models -import django.db.models.deletion -from django.core.exceptions import ObjectDoesNotExist - - -def migrate_comments(apps, schema_editor): - Comment = apps.get_model("judge", "Comment") - Problem = apps.get_model("judge", "Problem") - Solution = apps.get_model("judge", "Solution") - BlogPost = apps.get_model("judge", "BlogPost") - Contest = apps.get_model("judge", "Contest") - - for comment in Comment.objects.all(): - page = comment.page - try: - if page.startswith("p:"): - code = page[2:] - comment.linked_object = Problem.objects.get(code=code) - elif page.startswith("s:"): - code = page[2:] - comment.linked_object = Solution.objects.get(problem__code=code) - elif page.startswith("c:"): - key = page[2:] - comment.linked_object = Contest.objects.get(key=key) - elif page.startswith("b:"): - blog_id = page[2:] - comment.linked_object = BlogPost.objects.get(id=blog_id) - comment.save() - except ObjectDoesNotExist: - comment.delete() - - -class Migration(migrations.Migration): - dependencies = [ - ("contenttypes", "0002_remove_content_type_name"), - ("judge", "0151_comment_content_type"), - ] - - operations = [ - migrations.RunPython(migrate_comments, migrations.RunPython.noop, atomic=True), - migrations.AlterField( - model_name="comment", - name="content_type", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="contenttypes.contenttype", - ), - ), - migrations.AlterField( - model_name="comment", - name="object_id", - field=models.PositiveIntegerField(), - ), - ] diff --git a/judge/migrations/0153_drop_comment_page.py b/judge/migrations/0153_drop_comment_page.py deleted file mode 100644 index a03ac09..0000000 --- a/judge/migrations/0153_drop_comment_page.py +++ /dev/null @@ -1,24 +0,0 @@ -# Generated by Django 3.2.18 on 2023-02-20 23:46 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0152_migrate_comments"), - ] - - operations = [ - migrations.RemoveField( - model_name="comment", - name="page", - ), - migrations.AlterField( - model_name="commentlock", - name="page", - field=models.CharField( - db_index=True, max_length=30, verbose_name="associated page" - ), - ), - ] diff --git a/judge/migrations/0154_add_submission_indexes.py b/judge/migrations/0154_add_submission_indexes.py deleted file mode 100644 index 28c5fec..0000000 --- a/judge/migrations/0154_add_submission_indexes.py +++ /dev/null @@ -1,27 +0,0 @@ -# Generated by Django 3.2.18 on 2023-03-08 01:55 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0153_drop_comment_page"), - ] - - operations = [ - migrations.AddIndex( - model_name="submission", - index=models.Index( - fields=["problem", "user", "-points"], - name="judge_submi_problem_5687ea_idx", - ), - ), - migrations.AddIndex( - model_name="submission", - index=models.Index( - fields=["contest_object", "problem", "user", "-points"], - name="judge_submi_contest_31cdbb_idx", - ), - ), - ] diff --git a/judge/migrations/0155_output_only.py b/judge/migrations/0155_output_only.py deleted file mode 100644 index e122ed7..0000000 --- a/judge/migrations/0155_output_only.py +++ /dev/null @@ -1,22 +0,0 @@ -# Generated by Django 3.2.18 on 2023-03-10 04:24 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0154_add_submission_indexes"), - ] - - operations = [ - migrations.AddField( - model_name="problemdata", - name="output_only", - field=models.BooleanField( - help_text="Support output-only problem", - null=True, - verbose_name="is output only", - ), - ), - ] diff --git a/judge/migrations/0156_auto_20230801_0107.py b/judge/migrations/0156_auto_20230801_0107.py deleted file mode 100644 index a5f2b9a..0000000 --- a/judge/migrations/0156_auto_20230801_0107.py +++ /dev/null @@ -1,48 +0,0 @@ -# Generated by Django 3.2.18 on 2023-07-31 18:07 - -import django.core.validators -from django.db import migrations, models -import judge.models.problem_data -import judge.utils.problem_data - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0155_output_only"), - ] - - operations = [ - migrations.AddField( - model_name="problemdata", - name="signature_handler", - field=models.FileField( - blank=True, - null=True, - storage=judge.utils.problem_data.ProblemDataStorage(), - upload_to=judge.models.problem_data.problem_directory_file, - validators=[ - django.core.validators.FileExtensionValidator( - allowed_extensions=["cpp"] - ) - ], - verbose_name="signature handler", - ), - ), - migrations.AddField( - model_name="problemdata", - name="signature_header", - field=models.FileField( - blank=True, - null=True, - storage=judge.utils.problem_data.ProblemDataStorage(), - upload_to=judge.models.problem_data.problem_directory_file, - validators=[ - django.core.validators.FileExtensionValidator( - allowed_extensions=["h"] - ) - ], - verbose_name="signature header", - ), - ), - ] diff --git a/judge/migrations/0157_auto_20230801_1145.py b/judge/migrations/0157_auto_20230801_1145.py deleted file mode 100644 index 802c56c..0000000 --- a/judge/migrations/0157_auto_20230801_1145.py +++ /dev/null @@ -1,22 +0,0 @@ -# Generated by Django 3.2.18 on 2023-08-01 04:45 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0156_auto_20230801_0107"), - ] - - operations = [ - migrations.AddField( - model_name="problemdata", - name="use_ioi_signature", - field=models.BooleanField( - help_text="Use IOI Signature", - null=True, - verbose_name="is IOI signature", - ), - ), - ] diff --git a/judge/migrations/0158_migrate_pagevote.py b/judge/migrations/0158_migrate_pagevote.py deleted file mode 100644 index 5563854..0000000 --- a/judge/migrations/0158_migrate_pagevote.py +++ /dev/null @@ -1,70 +0,0 @@ -# Generated by Django 3.2.18 on 2023-08-03 07:40 - -from django.db import migrations, models -import django.db.models.deletion -from django.core.exceptions import ObjectDoesNotExist - - -def migrate_pagevote(apps, schema_editor): - PageVote = apps.get_model("judge", "PageVote") - Problem = apps.get_model("judge", "Problem") - Solution = apps.get_model("judge", "Solution") - BlogPost = apps.get_model("judge", "BlogPost") - Contest = apps.get_model("judge", "Contest") - - for vote in PageVote.objects.all(): - page = vote.page - try: - if page.startswith("p:"): - code = page[2:] - vote.linked_object = Problem.objects.get(code=code) - elif page.startswith("s:"): - code = page[2:] - vote.linked_object = Solution.objects.get(problem__code=code) - elif page.startswith("c:"): - key = page[2:] - vote.linked_object = Contest.objects.get(key=key) - elif page.startswith("b:"): - blog_id = page[2:] - vote.linked_object = BlogPost.objects.get(id=blog_id) - vote.save() - except ObjectDoesNotExist: - vote.delete() - - -class Migration(migrations.Migration): - - dependencies = [ - ("contenttypes", "0002_remove_content_type_name"), - ("judge", "0157_auto_20230801_1145"), - ] - - operations = [ - migrations.AddField( - model_name="pagevote", - name="content_type", - field=models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="contenttypes.contenttype", - ), - ), - migrations.AddField( - model_name="pagevote", - name="object_id", - field=models.PositiveIntegerField(default=None), - preserve_default=False, - ), - migrations.AlterUniqueTogether( - name="pagevote", - unique_together={("content_type", "object_id")}, - ), - migrations.AddIndex( - model_name="pagevote", - index=models.Index( - fields=["content_type", "object_id"], - name="judge_pagev_content_ed8899_idx", - ), - ), - migrations.RunPython(migrate_pagevote, migrations.RunPython.noop, atomic=True), - ] diff --git a/judge/migrations/0159_auto_20230803_1518.py b/judge/migrations/0159_auto_20230803_1518.py deleted file mode 100644 index 691121b..0000000 --- a/judge/migrations/0159_auto_20230803_1518.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 3.2.18 on 2023-08-03 08:18 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ("contenttypes", "0002_remove_content_type_name"), - ("judge", "0158_migrate_pagevote"), - ] - - operations = [ - migrations.AlterField( - model_name="pagevote", - name="content_type", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="contenttypes.contenttype", - ), - ), - ] diff --git a/judge/migrations/0160_migrate_bookmark.py b/judge/migrations/0160_migrate_bookmark.py deleted file mode 100644 index 6fa1b3e..0000000 --- a/judge/migrations/0160_migrate_bookmark.py +++ /dev/null @@ -1,80 +0,0 @@ -# Generated by Django 3.2.18 on 2023-08-03 08:32 - -from django.db import migrations, models -import django.db.models.deletion -from django.core.exceptions import ObjectDoesNotExist - - -def migrate_bookmark(apps, schema_editor): - BookMark = apps.get_model("judge", "BookMark") - Problem = apps.get_model("judge", "Problem") - Solution = apps.get_model("judge", "Solution") - BlogPost = apps.get_model("judge", "BlogPost") - Contest = apps.get_model("judge", "Contest") - - for bookmark in BookMark.objects.all(): - page = bookmark.page - try: - if page.startswith("p:"): - code = page[2:] - bookmark.linked_object = Problem.objects.get(code=code) - elif page.startswith("s:"): - code = page[2:] - bookmark.linked_object = Solution.objects.get(problem__code=code) - elif page.startswith("c:"): - key = page[2:] - bookmark.linked_object = Contest.objects.get(key=key) - elif page.startswith("b:"): - blog_id = page[2:] - bookmark.linked_object = BlogPost.objects.get(id=blog_id) - bookmark.save() - except ObjectDoesNotExist: - bookmark.delete() - - -class Migration(migrations.Migration): - - dependencies = [ - ("contenttypes", "0002_remove_content_type_name"), - ("judge", "0159_auto_20230803_1518"), - ] - - operations = [ - migrations.AddField( - model_name="bookmark", - name="content_type", - field=models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="contenttypes.contenttype", - ), - ), - migrations.AddField( - model_name="bookmark", - name="object_id", - field=models.PositiveIntegerField(default=1), - ), - migrations.AddField( - model_name="bookmark", - name="score", - field=models.IntegerField(default=0, verbose_name="votes"), - ), - migrations.AlterUniqueTogether( - name="bookmark", - unique_together={("content_type", "object_id")}, - ), - migrations.AddIndex( - model_name="bookmark", - index=models.Index( - fields=["content_type", "object_id"], - name="judge_bookm_content_964329_idx", - ), - ), - migrations.AddIndex( - model_name="makebookmark", - index=models.Index( - fields=["user", "bookmark"], name="judge_makeb_user_id_f0e226_idx" - ), - ), - migrations.RunPython(migrate_bookmark, migrations.RunPython.noop, atomic=True), - ] diff --git a/judge/migrations/0161_auto_20230803_1536.py b/judge/migrations/0161_auto_20230803_1536.py deleted file mode 100644 index 7e12b9a..0000000 --- a/judge/migrations/0161_auto_20230803_1536.py +++ /dev/null @@ -1,28 +0,0 @@ -# Generated by Django 3.2.18 on 2023-08-03 08:36 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ("contenttypes", "0002_remove_content_type_name"), - ("judge", "0160_migrate_bookmark"), - ] - - operations = [ - migrations.AlterField( - model_name="bookmark", - name="content_type", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="contenttypes.contenttype", - ), - ), - migrations.AlterField( - model_name="bookmark", - name="object_id", - field=models.PositiveIntegerField(), - ), - ] diff --git a/judge/migrations/0162_profile_image.py b/judge/migrations/0162_profile_image.py deleted file mode 100644 index b371f39..0000000 --- a/judge/migrations/0162_profile_image.py +++ /dev/null @@ -1,21 +0,0 @@ -# Generated by Django 3.2.18 on 2023-08-24 00:50 - -from django.db import migrations, models -import judge.models.profile - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0161_auto_20230803_1536"), - ] - - operations = [ - migrations.AddField( - model_name="profile", - name="profile_image", - field=models.ImageField( - null=True, upload_to=judge.models.profile.profile_image_path - ), - ), - ] diff --git a/judge/migrations/0163_email_change.py b/judge/migrations/0163_email_change.py deleted file mode 100644 index 985121d..0000000 --- a/judge/migrations/0163_email_change.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 3.2.18 on 2023-08-25 00:19 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0162_profile_image"), - ] - - operations = [ - migrations.AddField( - model_name="profile", - name="email_change_pending", - field=models.EmailField(blank=True, max_length=254, null=True), - ), - ] diff --git a/judge/migrations/0164_show_testcase.py b/judge/migrations/0164_show_testcase.py deleted file mode 100644 index 33cbdf8..0000000 --- a/judge/migrations/0164_show_testcase.py +++ /dev/null @@ -1,30 +0,0 @@ -# Generated by Django 3.2.18 on 2023-08-25 23:03 - -from django.db import migrations, models - - -def migrate_show_testcases(apps, schema_editor): - ContestProblem = apps.get_model("judge", "ContestProblem") - - for c in ContestProblem.objects.all(): - if c.output_prefix_override == 1: - c.show_testcases = True - c.save() - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0163_email_change"), - ] - - operations = [ - migrations.AddField( - model_name="contestproblem", - name="show_testcases", - field=models.BooleanField(default=False, verbose_name="visible testcases"), - ), - migrations.RunPython( - migrate_show_testcases, migrations.RunPython.noop, atomic=True - ), - ] diff --git a/judge/migrations/0165_drop_output_prefix_override.py b/judge/migrations/0165_drop_output_prefix_override.py deleted file mode 100644 index ea9b17a..0000000 --- a/judge/migrations/0165_drop_output_prefix_override.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 3.2.18 on 2023-08-25 23:11 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0164_show_testcase"), - ] - - operations = [ - migrations.RemoveField( - model_name="contestproblem", - name="output_prefix_override", - ), - ] diff --git a/judge/migrations/0166_display_rank_index.py b/judge/migrations/0166_display_rank_index.py deleted file mode 100644 index ffea311..0000000 --- a/judge/migrations/0166_display_rank_index.py +++ /dev/null @@ -1,28 +0,0 @@ -# Generated by Django 3.2.18 on 2023-08-28 01:13 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0165_drop_output_prefix_override"), - ] - - operations = [ - migrations.AlterField( - model_name="profile", - name="display_rank", - field=models.CharField( - choices=[ - ("user", "Normal User"), - ("setter", "Problem Setter"), - ("admin", "Admin"), - ], - db_index=True, - default="user", - max_length=10, - verbose_name="display rank", - ), - ), - ] diff --git a/judge/migrations/0167_ultimate_contest_format.py b/judge/migrations/0167_ultimate_contest_format.py deleted file mode 100644 index 636e882..0000000 --- a/judge/migrations/0167_ultimate_contest_format.py +++ /dev/null @@ -1,32 +0,0 @@ -# Generated by Django 3.2.18 on 2023-09-01 00:09 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0166_display_rank_index"), - ] - - operations = [ - migrations.AlterField( - model_name="contest", - name="format_name", - field=models.CharField( - choices=[ - ("atcoder", "AtCoder"), - ("default", "Default"), - ("ecoo", "ECOO"), - ("icpc", "ICPC"), - ("ioi", "IOI"), - ("ioi16", "New IOI"), - ("ultimate", "Ultimate"), - ], - default="default", - help_text="The contest format module to use.", - max_length=32, - verbose_name="contest format", - ), - ), - ] diff --git a/judge/migrations/0168_css_background.py b/judge/migrations/0168_css_background.py deleted file mode 100644 index 6210a26..0000000 --- a/judge/migrations/0168_css_background.py +++ /dev/null @@ -1,24 +0,0 @@ -# Generated by Django 3.2.18 on 2023-09-02 00:30 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0167_ultimate_contest_format"), - ] - - operations = [ - migrations.AddField( - model_name="profile", - name="css_background", - field=models.TextField( - blank=True, - help_text='CSS custom background properties: url("image_url"), color, etc', - max_length=300, - null=True, - verbose_name="Custom background", - ), - ), - ] diff --git a/judge/migrations/0169_public_scoreboard.py b/judge/migrations/0169_public_scoreboard.py deleted file mode 100644 index 0dc7338..0000000 --- a/judge/migrations/0169_public_scoreboard.py +++ /dev/null @@ -1,22 +0,0 @@ -# Generated by Django 3.2.18 on 2023-09-17 01:55 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0168_css_background"), - ] - - operations = [ - migrations.AddField( - model_name="contest", - name="public_scoreboard", - field=models.BooleanField( - default=False, - help_text="Ranking page is public even for private contests.", - verbose_name="public scoreboard", - ), - ), - ] diff --git a/judge/migrations/0170_contests_summary.py b/judge/migrations/0170_contests_summary.py deleted file mode 100644 index a2b19de..0000000 --- a/judge/migrations/0170_contests_summary.py +++ /dev/null @@ -1,30 +0,0 @@ -# Generated by Django 3.2.21 on 2023-10-02 03:25 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0169_public_scoreboard"), - ] - - operations = [ - migrations.CreateModel( - name="ContestsSummary", - fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("scores", models.JSONField(blank=True, null=True)), - ("key", models.CharField(max_length=20, unique=True)), - ("contests", models.ManyToManyField(to="judge.Contest")), - ], - ), - ] diff --git a/judge/migrations/0171_update_notification.py b/judge/migrations/0171_update_notification.py deleted file mode 100644 index 7803e4b..0000000 --- a/judge/migrations/0171_update_notification.py +++ /dev/null @@ -1,68 +0,0 @@ -# Generated by Django 3.2.18 on 2023-10-10 21:17 - -from django.db import migrations, models -import django.db.models.deletion -from django.urls import reverse - -from collections import defaultdict - - -# Run this in shell -def migrate_notif(apps, schema_editor): - Notification = apps.get_model("judge", "Notification") - Profile = apps.get_model("judge", "Profile") - NotificationProfile = apps.get_model("judge", "NotificationProfile") - - unread_count = defaultdict(int) - for c in Notification.objects.all(): - if c.comment: - c.html_link = ( - f'{c.comment.page_title}' - ) - c.author = c.comment.author - c.save() - if c.read is False: - unread_count[c.author] += 1 - - for user in unread_count: - np = NotificationProfile(user=user) - np.unread_count = unread_count[user] - np.save() - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0170_contests_summary"), - ] - - operations = [ - migrations.AlterModelOptions( - name="contestssummary", - options={ - "verbose_name": "contests summary", - "verbose_name_plural": "contests summaries", - }, - ), - migrations.CreateModel( - name="NotificationProfile", - fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("unread_count", models.IntegerField(default=0)), - ( - "user", - models.OneToOneField( - on_delete=django.db.models.deletion.CASCADE, to="judge.profile" - ), - ), - ], - ), - ] diff --git a/judge/migrations/0172_index_rating.py b/judge/migrations/0172_index_rating.py deleted file mode 100644 index 157c005..0000000 --- a/judge/migrations/0172_index_rating.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 3.2.18 on 2023-10-10 23:15 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0171_update_notification"), - ] - - operations = [ - migrations.AlterField( - model_name="profile", - name="rating", - field=models.IntegerField(db_index=True, default=None, null=True), - ), - ] diff --git a/judge/migrations/0173_fulltext.py b/judge/migrations/0173_fulltext.py deleted file mode 100644 index a47ef7b..0000000 --- a/judge/migrations/0173_fulltext.py +++ /dev/null @@ -1,25 +0,0 @@ -# Generated by Django 3.2.18 on 2023-10-14 00:53 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0172_index_rating"), - ] - - operations = [ - migrations.RunSQL( - ( - "CREATE FULLTEXT INDEX IF NOT EXISTS code_name_index ON judge_problem (code, name)", - ), - reverse_sql=migrations.RunSQL.noop, - ), - migrations.RunSQL( - ( - "CREATE FULLTEXT INDEX IF NOT EXISTS key_name_index ON judge_contest (`key`, name)", - ), - reverse_sql=migrations.RunSQL.noop, - ), - ] diff --git a/judge/migrations/0174_contest_summary_result.py b/judge/migrations/0174_contest_summary_result.py deleted file mode 100644 index 1a4c9cc..0000000 --- a/judge/migrations/0174_contest_summary_result.py +++ /dev/null @@ -1,50 +0,0 @@ -# Generated by Django 3.2.18 on 2023-11-24 05:45 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0173_fulltext"), - ] - - operations = [ - migrations.AddField( - model_name="contestssummary", - name="results", - field=models.JSONField(blank=True, null=True), - ), - migrations.AlterField( - model_name="contest", - name="authors", - field=models.ManyToManyField( - help_text="These users will be able to edit the contest.", - related_name="_judge_contest_authors_+", - to="judge.Profile", - verbose_name="authors", - ), - ), - migrations.AlterField( - model_name="contest", - name="curators", - field=models.ManyToManyField( - blank=True, - help_text="These users will be able to edit the contest, but will not be listed as authors.", - related_name="_judge_contest_curators_+", - to="judge.Profile", - verbose_name="curators", - ), - ), - migrations.AlterField( - model_name="contest", - name="testers", - field=models.ManyToManyField( - blank=True, - help_text="These users will be able to view the contest, but not edit it.", - related_name="_judge_contest_testers_+", - to="judge.Profile", - verbose_name="testers", - ), - ), - ] diff --git a/judge/migrations/0175_add_profile_index.py b/judge/migrations/0175_add_profile_index.py deleted file mode 100644 index d9ec296..0000000 --- a/judge/migrations/0175_add_profile_index.py +++ /dev/null @@ -1,20 +0,0 @@ -# Generated by Django 3.2.18 on 2023-11-29 02:26 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0174_contest_summary_result"), - ] - - operations = [ - migrations.AddIndex( - model_name="profile", - index=models.Index( - fields=["is_unlisted", "performance_points"], - name="judge_profi_is_unli_d4034c_idx", - ), - ), - ] diff --git a/judge/migrations/0176_comment_revision_count.py b/judge/migrations/0176_comment_revision_count.py deleted file mode 100644 index ed2a246..0000000 --- a/judge/migrations/0176_comment_revision_count.py +++ /dev/null @@ -1,30 +0,0 @@ -# Generated by Django 3.2.18 on 2023-12-06 01:28 - -from django.db import migrations, models - - -# Run this in shell -def migrate_revision(apps, schema_editor): - Comment = apps.get_model("judge", "Comment") - - for c in Comment.objects.all(): - c.revision_count = c.versions.count() - c.save() - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0175_add_profile_index"), - ] - - operations = [ - migrations.AddField( - model_name="comment", - name="revision_count", - field=models.PositiveIntegerField(default=1), - ), - # migrations.RunPython( - # migrate_revision, migrations.RunPython.noop, atomic=True - # ), - ] diff --git a/judge/migrations/0177_test_formatter.py b/judge/migrations/0177_test_formatter.py deleted file mode 100644 index 78eadb5..0000000 --- a/judge/migrations/0177_test_formatter.py +++ /dev/null @@ -1,35 +0,0 @@ -from django.db import migrations, models -import judge.models.test_formatter - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0176_comment_revision_count"), - ] - - operations = [ - migrations.CreateModel( - name="TestFormatterModel", - fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "file", - models.FileField( - blank=True, - null=True, - upload_to=judge.models.test_formatter.test_formatter_path, - verbose_name="testcase file", - ), - ), - ], - ) - ] diff --git a/judge/migrations/0178_remove_user_script.py b/judge/migrations/0178_remove_user_script.py deleted file mode 100644 index dc4b560..0000000 --- a/judge/migrations/0178_remove_user_script.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 3.2.18 on 2024-01-14 01:04 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0177_test_formatter"), - ] - - operations = [ - migrations.RemoveField( - model_name="profile", - name="user_script", - ), - ] diff --git a/judge/migrations/0179_submission_result_lang_index.py b/judge/migrations/0179_submission_result_lang_index.py deleted file mode 100644 index 3e43918..0000000 --- a/judge/migrations/0179_submission_result_lang_index.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 3.2.18 on 2024-01-23 00:32 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0178_remove_user_script"), - ] - - operations = [ - migrations.AddIndex( - model_name="submission", - index=models.Index( - fields=["language", "result"], name="judge_submi_languag_874af4_idx" - ), - ), - ] diff --git a/judge/migrations/0180_course.py b/judge/migrations/0180_course.py deleted file mode 100644 index 439d32e..0000000 --- a/judge/migrations/0180_course.py +++ /dev/null @@ -1,78 +0,0 @@ -# Generated by Django 3.2.18 on 2024-02-15 02:12 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0179_submission_result_lang_index"), - ] - - operations = [ - migrations.CreateModel( - name="CourseLesson", - fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("title", models.TextField(verbose_name="course title")), - ("content", models.TextField(verbose_name="course content")), - ("order", models.IntegerField(default=0, verbose_name="order")), - ("points", models.IntegerField(verbose_name="points")), - ], - ), - migrations.RemoveField( - model_name="courseresource", - name="course", - ), - migrations.RemoveField( - model_name="course", - name="ending_time", - ), - migrations.AlterField( - model_name="courserole", - name="course", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="judge.course", - verbose_name="course", - ), - ), - migrations.DeleteModel( - name="CourseAssignment", - ), - migrations.DeleteModel( - name="CourseResource", - ), - migrations.AddField( - model_name="courselesson", - name="course", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="judge.course", - verbose_name="course", - ), - ), - migrations.AddField( - model_name="courselesson", - name="problems", - field=models.ManyToManyField(to="judge.Problem"), - ), - migrations.AlterUniqueTogether( - name="courserole", - unique_together={("course", "user")}, - ), - migrations.AlterField( - model_name="courselesson", - name="problems", - field=models.ManyToManyField(blank=True, to="judge.Problem"), - ), - ] diff --git a/judge/migrations/0181_remove_math_engine.py b/judge/migrations/0181_remove_math_engine.py deleted file mode 100644 index 99e4a85..0000000 --- a/judge/migrations/0181_remove_math_engine.py +++ /dev/null @@ -1,50 +0,0 @@ -# Generated by Django 3.2.18 on 2024-02-26 20:43 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0180_course"), - ] - - operations = [ - migrations.RemoveField( - model_name="profile", - name="math_engine", - ), - migrations.AlterField( - model_name="course", - name="about", - field=models.TextField(verbose_name="course description"), - ), - migrations.AlterField( - model_name="courselesson", - name="course", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="lessons", - to="judge.course", - verbose_name="course", - ), - ), - migrations.AlterField( - model_name="courselesson", - name="problems", - field=models.ManyToManyField( - blank=True, to="judge.Problem", verbose_name="problem" - ), - ), - migrations.AlterField( - model_name="courserole", - name="user", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="course_roles", - to="judge.profile", - verbose_name="user", - ), - ), - ] diff --git a/judge/migrations/0182_rename_customcpp.py b/judge/migrations/0182_rename_customcpp.py deleted file mode 100644 index 5f991be..0000000 --- a/judge/migrations/0182_rename_customcpp.py +++ /dev/null @@ -1,75 +0,0 @@ -# Generated by Django 3.2.18 on 2024-03-19 04:28 - -from django.db import migrations, models - - -def migrate_checker(apps, schema_editor): - ProblemData = apps.get_model("judge", "ProblemData") - ProblemTestCase = apps.get_model("judge", "ProblemTestCase") - - for p in ProblemData.objects.all(): - if p.checker == "customval": - p.checker = "customcpp" - p.save() - - for p in ProblemTestCase.objects.all(): - if p.checker == "customval": - p.checker = "customcpp" - p.save() - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0181_remove_math_engine"), - ] - - operations = [ - migrations.RunPython(migrate_checker, migrations.RunPython.noop, atomic=True), - migrations.AlterField( - model_name="problemdata", - name="checker", - field=models.CharField( - blank=True, - choices=[ - ("standard", "Standard"), - ("floats", "Floats"), - ("floatsabs", "Floats (absolute)"), - ("floatsrel", "Floats (relative)"), - ("rstripped", "Non-trailing spaces"), - ("sorted", "Unordered"), - ("identical", "Byte identical"), - ("linecount", "Line-by-line"), - ("custom", "Custom checker (PY)"), - ("customcpp", "Custom checker (CPP)"), - ("interact", "Interactive"), - ("testlib", "Testlib"), - ], - max_length=10, - verbose_name="checker", - ), - ), - migrations.AlterField( - model_name="problemtestcase", - name="checker", - field=models.CharField( - blank=True, - choices=[ - ("standard", "Standard"), - ("floats", "Floats"), - ("floatsabs", "Floats (absolute)"), - ("floatsrel", "Floats (relative)"), - ("rstripped", "Non-trailing spaces"), - ("sorted", "Unordered"), - ("identical", "Byte identical"), - ("linecount", "Line-by-line"), - ("custom", "Custom checker (PY)"), - ("customcpp", "Custom checker (CPP)"), - ("interact", "Interactive"), - ("testlib", "Testlib"), - ], - max_length=10, - verbose_name="checker", - ), - ), - ] diff --git a/judge/migrations/0183_rename_custom_checker_cpp.py b/judge/migrations/0183_rename_custom_checker_cpp.py deleted file mode 100644 index 65280ae..0000000 --- a/judge/migrations/0183_rename_custom_checker_cpp.py +++ /dev/null @@ -1,45 +0,0 @@ -# Generated by Django 3.2.18 on 2024-03-19 04:45 - -import django.core.validators -from django.db import migrations, models -import judge.models.problem_data -import judge.utils.problem_data - - -def migrate_checker(apps, schema_editor): - ProblemData = apps.get_model("judge", "ProblemData") - - for p in ProblemData.objects.all(): - p.custom_checker_cpp = p.custom_validator - p.save() - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0182_rename_customcpp"), - ] - - operations = [ - migrations.AddField( - model_name="problemdata", - name="custom_checker_cpp", - field=models.FileField( - blank=True, - null=True, - storage=judge.utils.problem_data.ProblemDataStorage(), - upload_to=judge.models.problem_data.problem_directory_file, - validators=[ - django.core.validators.FileExtensionValidator( - allowed_extensions=["cpp"] - ) - ], - verbose_name="custom cpp checker file", - ), - ), - migrations.RunPython(migrate_checker, migrations.RunPython.noop, atomic=True), - migrations.RemoveField( - model_name="problemdata", - name="custom_validator", - ), - ] diff --git a/judge/migrations/0184_contest_rate_limit.py b/judge/migrations/0184_contest_rate_limit.py deleted file mode 100644 index c05174d..0000000 --- a/judge/migrations/0184_contest_rate_limit.py +++ /dev/null @@ -1,28 +0,0 @@ -# Generated by Django 3.2.18 on 2024-03-23 04:07 - -import django.core.validators -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0183_rename_custom_checker_cpp"), - ] - - operations = [ - migrations.AddField( - model_name="contest", - name="rate_limit", - field=models.PositiveIntegerField( - blank=True, - help_text="Maximum number of submissions per minute. Leave empty if you don't want rate limit.", - null=True, - validators=[ - django.core.validators.MinValueValidator(1), - django.core.validators.MaxValueValidator(5), - ], - verbose_name="rate limit", - ), - ), - ] diff --git a/judge/migrations/0185_rename_org_profile_colum.py b/judge/migrations/0185_rename_org_profile_colum.py deleted file mode 100644 index c184169..0000000 --- a/judge/migrations/0185_rename_org_profile_colum.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 3.2.18 on 2024-04-12 05:50 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0184_contest_rate_limit"), - ] - - operations = [ - migrations.RenameField( - model_name="organizationprofile", - old_name="users", - new_name="profile", - ), - ] diff --git a/judge/migrations/0186_change_about_fields_max_len.py b/judge/migrations/0186_change_about_fields_max_len.py deleted file mode 100644 index 9e8cf01..0000000 --- a/judge/migrations/0186_change_about_fields_max_len.py +++ /dev/null @@ -1,43 +0,0 @@ -# Generated by Django 3.2.18 on 2024-04-12 17:04 - -from django.db import migrations, models - - -def truncate_about_text(apps, schema_editor): - Organization = apps.get_model("judge", "Organization") - Profile = apps.get_model("judge", "Profile") - - for org in Organization.objects.all(): - if len(org.about) > 10000: - org.about = org.about[:10000] - org.save() - - for profile in Profile.objects.all(): - if profile.about and len(profile.about) > 10000: - profile.about = profile.about[:10000] - profile.save() - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0185_rename_org_profile_colum"), - ] - - operations = [ - migrations.RunPython(truncate_about_text), - migrations.AlterField( - model_name="organization", - name="about", - field=models.CharField( - max_length=10000, verbose_name="organization description" - ), - ), - migrations.AlterField( - model_name="profile", - name="about", - field=models.CharField( - blank=True, max_length=10000, null=True, verbose_name="self-description" - ), - ), - ] diff --git a/judge/migrations/0187_profile_info.py b/judge/migrations/0187_profile_info.py deleted file mode 100644 index c3b02c2..0000000 --- a/judge/migrations/0187_profile_info.py +++ /dev/null @@ -1,69 +0,0 @@ -# Generated by Django 3.2.18 on 2024-04-27 03:35 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0186_change_about_fields_max_len"), - ] - - operations = [ - migrations.RemoveField( - model_name="profile", - name="is_banned_problem_voting", - ), - migrations.CreateModel( - name="ProfileInfo", - fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "tshirt_size", - models.CharField( - blank=True, - choices=[ - ("S", "Small (S)"), - ("M", "Medium (M)"), - ("L", "Large (L)"), - ("XL", "Extra Large (XL)"), - ("XXL", "2 Extra Large (XXL)"), - ], - max_length=5, - null=True, - verbose_name="t-shirt size", - ), - ), - ( - "date_of_birth", - models.DateField( - blank=True, null=True, verbose_name="date of birth" - ), - ), - ( - "address", - models.CharField( - blank=True, max_length=255, null=True, verbose_name="address" - ), - ), - ( - "profile", - models.OneToOneField( - on_delete=django.db.models.deletion.CASCADE, - related_name="info", - to="judge.profile", - verbose_name="profile associated", - ), - ), - ], - ), - ] diff --git a/judge/migrations/0188_official_contest.py b/judge/migrations/0188_official_contest.py deleted file mode 100644 index 89414a7..0000000 --- a/judge/migrations/0188_official_contest.py +++ /dev/null @@ -1,110 +0,0 @@ -# Generated by Django 3.2.18 on 2024-05-30 04:32 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0187_profile_info"), - ] - - operations = [ - migrations.CreateModel( - name="OfficialContestCategory", - fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "name", - models.CharField( - max_length=50, - unique=True, - verbose_name="official contest category", - ), - ), - ], - options={ - "verbose_name": "official contest category", - "verbose_name_plural": "official contest categories", - }, - ), - migrations.CreateModel( - name="OfficialContestLocation", - fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "name", - models.CharField( - max_length=50, - unique=True, - verbose_name="official contest location", - ), - ), - ], - options={ - "verbose_name": "official contest location", - "verbose_name_plural": "official contest locations", - }, - ), - migrations.CreateModel( - name="OfficialContest", - fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("year", models.PositiveIntegerField(verbose_name="year")), - ( - "category", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="judge.officialcontestcategory", - verbose_name="contest category", - ), - ), - ( - "contest", - models.OneToOneField( - on_delete=django.db.models.deletion.CASCADE, - related_name="official", - to="judge.contest", - verbose_name="contest", - ), - ), - ( - "location", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="judge.officialcontestlocation", - verbose_name="contest location", - ), - ), - ], - options={ - "verbose_name": "official contest", - "verbose_name_plural": "official contests", - }, - ), - ] diff --git a/judge/migrations/0189_organization_image.py b/judge/migrations/0189_organization_image.py deleted file mode 100644 index 4307a24..0000000 --- a/judge/migrations/0189_organization_image.py +++ /dev/null @@ -1,21 +0,0 @@ -# Generated by Django 3.2.21 on 2024-07-08 00:05 - -from django.db import migrations, models -import judge.models.profile - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0188_official_contest"), - ] - - operations = [ - migrations.AddField( - model_name="organization", - name="organization_image", - field=models.ImageField( - null=True, upload_to=judge.models.profile.organization_image_path - ), - ), - ] diff --git a/judge/migrations/0190_deprecate_old_notif_fields.py b/judge/migrations/0190_deprecate_old_notif_fields.py deleted file mode 100644 index dbf6f00..0000000 --- a/judge/migrations/0190_deprecate_old_notif_fields.py +++ /dev/null @@ -1,21 +0,0 @@ -# Generated by Django 3.2.18 on 2024-08-13 10:36 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0189_organization_image"), - ] - - operations = [ - migrations.RemoveField( - model_name="notification", - name="comment", - ), - migrations.RemoveField( - model_name="notification", - name="read", - ), - ] diff --git a/judge/migrations/0191_deprecate_old_org_image.py b/judge/migrations/0191_deprecate_old_org_image.py deleted file mode 100644 index 76d76f3..0000000 --- a/judge/migrations/0191_deprecate_old_org_image.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 3.2.18 on 2024-08-22 03:12 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0190_deprecate_old_notif_fields"), - ] - - operations = [ - migrations.RemoveField( - model_name="organization", - name="logo_override_image", - ), - ] diff --git a/judge/migrations/0192_course_lesson_problem.py b/judge/migrations/0192_course_lesson_problem.py deleted file mode 100644 index 89a1185..0000000 --- a/judge/migrations/0192_course_lesson_problem.py +++ /dev/null @@ -1,44 +0,0 @@ -# Generated by Django 3.2.21 on 2024-09-02 05:28 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0191_deprecate_old_org_image"), - ] - - operations = [ - migrations.CreateModel( - name="CourseLessonProblem", - fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("order", models.IntegerField(default=0, verbose_name="order")), - ("score", models.IntegerField(default=0, verbose_name="score")), - ( - "lesson", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="lesson_problems", - to="judge.courselesson", - ), - ), - ( - "problem", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="judge.problem" - ), - ), - ], - ), - ] diff --git a/judge/migrations/0193_remove_old_course_problems.py b/judge/migrations/0193_remove_old_course_problems.py deleted file mode 100644 index 809b3e9..0000000 --- a/judge/migrations/0193_remove_old_course_problems.py +++ /dev/null @@ -1,29 +0,0 @@ -# Generated by Django 3.2.18 on 2024-09-03 14:33 - -from django.db import migrations, models - - -def migrate_problems_to_courselessonproblem(apps, schema_editor): - CourseLesson = apps.get_model("judge", "CourseLesson") - CourseLessonProblem = apps.get_model("judge", "CourseLessonProblem") - - for lesson in CourseLesson.objects.all(): - for problem in lesson.problems.all(): - CourseLessonProblem.objects.create( - lesson=lesson, problem=problem, order=1, score=1 - ) - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0192_course_lesson_problem"), - ] - - operations = [ - migrations.RunPython(migrate_problems_to_courselessonproblem), - migrations.RemoveField( - model_name="courselesson", - name="problems", - ), - ] diff --git a/judge/migrations/0194_course_contest.py b/judge/migrations/0194_course_contest.py deleted file mode 100644 index 6c3e534..0000000 --- a/judge/migrations/0194_course_contest.py +++ /dev/null @@ -1,67 +0,0 @@ -# Generated by Django 3.2.21 on 2024-09-30 22:31 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ("judge", "0193_remove_old_course_problems"), - ] - - operations = [ - migrations.AddField( - model_name="contest", - name="is_in_course", - field=models.BooleanField(default=False, verbose_name="contest in course"), - ), - migrations.AddField( - model_name="courselesson", - name="is_visible", - field=models.BooleanField(default=True, verbose_name="publicly visible"), - ), - migrations.AlterField( - model_name="courselesson", - name="content", - field=models.TextField(verbose_name="lesson content"), - ), - migrations.AlterField( - model_name="courselesson", - name="title", - field=models.TextField(verbose_name="lesson title"), - ), - migrations.CreateModel( - name="CourseContest", - fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("order", models.IntegerField(default=0, verbose_name="order")), - ("points", models.IntegerField(verbose_name="points")), - ( - "contest", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="course", - to="judge.contest", - unique=True, - ), - ), - ( - "course", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="contests", - to="judge.course", - ), - ), - ], - ), - ] diff --git a/judge/ml/collab_filter.py b/judge/ml/collab_filter.py deleted file mode 100644 index 105a534..0000000 --- a/judge/ml/collab_filter.py +++ /dev/null @@ -1,82 +0,0 @@ -import numpy as np -import os -import hashlib - -from django.core.cache import cache -from django.conf import settings - -from judge.caching import cache_wrapper - - -class CollabFilter: - DOT = "dot" - COSINE = "cosine" - - # name = 'collab_filter' or 'collab_filter_time' - def __init__(self, name): - self.embeddings = np.load( - os.path.join(settings.ML_OUTPUT_PATH, name + "/embeddings.npz"), - allow_pickle=True, - ) - _, problem_arr = self.embeddings.files - self.name = name - self.problem_embeddings = self.embeddings[problem_arr].item() - - def __str__(self): - return self.name - - def compute_scores(self, query_embedding, item_embeddings, measure=DOT): - """Return {id: score}""" - u = query_embedding - V = np.stack(list(item_embeddings.values())) - if measure == self.COSINE: - V = V / np.linalg.norm(V, axis=1, keepdims=True) - u = u / np.linalg.norm(u) - scores = u.dot(V.T) - scores_by_id = {id_: s for id_, s in zip(item_embeddings.keys(), scores)} - return scores_by_id - - def _get_embedding_version(self): - first_problem = self.problem_embeddings[0] - array_bytes = first_problem.tobytes() - hash_object = hashlib.sha256(array_bytes) - hash_bytes = hash_object.digest() - return hash_bytes.hex()[:5] - - @cache_wrapper(prefix="CFgue", timeout=86400) - def _get_user_embedding(self, user_id, embedding_version): - user_arr, _ = self.embeddings.files - user_embeddings = self.embeddings[user_arr].item() - if user_id not in user_embeddings: - return user_embeddings[0] - return user_embeddings[user_id] - - def get_user_embedding(self, user_id): - version = self._get_embedding_version() - return self._get_user_embedding(user_id, version) - - @cache_wrapper(prefix="user_recommendations", timeout=3600) - def user_recommendations(self, user_id, problems, measure=DOT, limit=None): - user_embedding = self.get_user_embedding(user_id) - scores = self.compute_scores(user_embedding, self.problem_embeddings, measure) - res = [] # [(score, problem)] - for pid in problems: - if pid in scores: - res.append((scores[pid], pid)) - - res.sort(reverse=True, key=lambda x: x[0]) - return res[:limit] - - # return a list of pid - def problem_neighbors(self, problem, problemset, measure=DOT, limit=None): - pid = problem.id - if pid not in self.problem_embeddings: - return [] - embedding = self.problem_embeddings[pid] - scores = self.compute_scores(embedding, self.problem_embeddings, measure) - res = [] - for p in problemset: - if p in scores: - res.append((scores[p], p)) - res.sort(reverse=True, key=lambda x: x[0]) - return res[:limit] diff --git a/judge/models/__init__.py b/judge/models/__init__.py index ef62797..d780360 100644 --- a/judge/models/__init__.py +++ b/judge/models/__init__.py @@ -1,99 +1,29 @@ from reversion import revisions -from judge.models.choices import ( - ACE_THEMES, - TIMEZONE, -) +from judge.models.choices import ACE_THEMES, EFFECTIVE_MATH_ENGINES, MATH_ENGINES_CHOICES, TIMEZONE from judge.models.comment import Comment, CommentLock, CommentVote -from judge.models.contest import ( - Contest, - ContestMoss, - ContestParticipation, - ContestProblem, - ContestSubmission, - ContestTag, - Rating, - ContestProblemClarification, - ContestsSummary, - OfficialContestCategory, - OfficialContestLocation, - OfficialContest, -) +from judge.models.contest import Contest, ContestMoss, ContestParticipation, ContestProblem, ContestSubmission, \ + ContestTag, Rating from judge.models.interface import BlogPost, MiscConfig, NavigationBar, validate_regex from judge.models.message import PrivateMessage, PrivateMessageThread -from judge.models.problem import ( - LanguageLimit, - LanguageTemplate, - License, - Problem, - ProblemGroup, - ProblemTranslation, - ProblemType, - Solution, - TranslatedProblemQuerySet, - ProblemPointsVote, -) -from judge.models.problem_data import ( - CHECKERS, - ProblemData, - ProblemTestCase, - problem_data_storage, - problem_directory_file, -) -from judge.models.profile import ( - Organization, - OrganizationRequest, - Profile, - Friend, - OrganizationProfile, - ProfileInfo, -) +from judge.models.problem import LanguageLimit, License, Problem, ProblemClarification, ProblemGroup, \ + ProblemTranslation, ProblemType, Solution, TranslatedProblemForeignKeyQuerySet, TranslatedProblemQuerySet +from judge.models.problem_data import CHECKERS, ProblemData, ProblemTestCase, problem_data_storage, \ + problem_directory_file +from judge.models.profile import Organization, OrganizationRequest, Profile from judge.models.runtime import Judge, Language, RuntimeVersion -from judge.models.submission import ( - SUBMISSION_RESULT, - Submission, - SubmissionSource, - SubmissionTestCase, -) - -from judge.models.test_formatter import TestFormatterModel +from judge.models.submission import SUBMISSION_RESULT, Submission, SubmissionSource, SubmissionTestCase from judge.models.ticket import Ticket, TicketMessage -from judge.models.volunteer import VolunteerProblemVote -from judge.models.pagevote import PageVote, PageVoteVoter -from judge.models.bookmark import BookMark, MakeBookMark -from judge.models.course import ( - Course, - CourseRole, - CourseLesson, - CourseLessonProblem, - CourseContest, -) -from judge.models.notification import Notification, NotificationProfile -from judge.models.test_formatter import TestFormatterModel -revisions.register(Profile, exclude=["points", "last_access", "ip", "rating"]) -revisions.register(Problem, follow=["language_limits"]) +revisions.register(Profile, exclude=['points', 'last_access', 'ip', 'rating']) +revisions.register(Problem, follow=['language_limits']) revisions.register(LanguageLimit) -revisions.register(LanguageTemplate) -revisions.register(Contest, follow=["contest_problems"]) +revisions.register(Contest, follow=['contest_problems']) revisions.register(ContestProblem) revisions.register(Organization) revisions.register(BlogPost) revisions.register(Solution) -revisions.register(Judge, fields=["name", "created", "auth_key", "description"]) +revisions.register(Judge, fields=['name', 'created', 'auth_key', 'description']) revisions.register(Language) -revisions.register( - Comment, fields=["author", "time", "page", "score", "body", "hidden", "parent"] -) -revisions.register(ProblemTranslation) -revisions.register(ProblemPointsVote) -revisions.register(ContestMoss) -revisions.register(ProblemData) -revisions.register(ProblemTestCase) -revisions.register(ContestParticipation) -revisions.register(Rating) -revisions.register(PageVoteVoter) -revisions.register(VolunteerProblemVote) -revisions.register(MakeBookMark) -revisions.register(Course) +revisions.register(Comment, fields=['author', 'time', 'page', 'score', 'body', 'hidden', 'parent']) del revisions diff --git a/judge/models/bookmark.py b/judge/models/bookmark.py deleted file mode 100644 index 06be327..0000000 --- a/judge/models/bookmark.py +++ /dev/null @@ -1,74 +0,0 @@ -from django.db import models -from django.db.models import CASCADE -from django.utils.translation import gettext_lazy as _ -from django.core.exceptions import ObjectDoesNotExist -from django.contrib.contenttypes.fields import GenericForeignKey -from django.contrib.contenttypes.models import ContentType - -from judge.models.profile import Profile -from judge.caching import cache_wrapper - -__all__ = ["BookMark"] - - -class BookMark(models.Model): - page = models.CharField( - max_length=30, - verbose_name=_("associated page"), - db_index=True, - ) # deprecated - score = models.IntegerField(verbose_name=_("votes"), default=0) - content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) - object_id = models.PositiveIntegerField() - linked_object = GenericForeignKey("content_type", "object_id") - - @cache_wrapper(prefix="BMgb") - def is_bookmarked_by(self, user): - return MakeBookMark.objects.filter(bookmark=self, user=user).exists() - - class Meta: - verbose_name = _("bookmark") - verbose_name_plural = _("bookmarks") - indexes = [ - models.Index(fields=["content_type", "object_id"]), - ] - unique_together = ("content_type", "object_id") - - def __str__(self): - return f"bookmark for {self.linked_object}" - - -class MakeBookMark(models.Model): - bookmark = models.ForeignKey(BookMark, related_name="bookmark", on_delete=CASCADE) - user = models.ForeignKey( - Profile, related_name="user_bookmark", on_delete=CASCADE, db_index=True - ) - - class Meta: - indexes = [ - models.Index(fields=["user", "bookmark"]), - ] - unique_together = ["user", "bookmark"] - verbose_name = _("make bookmark") - verbose_name_plural = _("make bookmarks") - - -@cache_wrapper(prefix="gocb", expected_type=BookMark) -def _get_or_create_bookmark(content_type, object_id): - bookmark, created = BookMark.objects.get_or_create( - content_type=content_type, - object_id=object_id, - ) - return bookmark - - -class Bookmarkable: - def get_or_create_bookmark(self): - content_type = ContentType.objects.get_for_model(self) - object_id = self.pk - return _get_or_create_bookmark(content_type, object_id) - - -def dirty_bookmark(bookmark, profile): - bookmark.is_bookmarked_by.dirty(bookmark, profile) - _get_or_create_bookmark.dirty(bookmark.content_type, bookmark.object_id) diff --git a/judge/models/choices.py b/judge/models/choices.py index 105e7e7..16c57de 100644 --- a/judge/models/choices.py +++ b/judge/models/choices.py @@ -8,11 +8,11 @@ from django.utils.translation import gettext_lazy as _ def make_timezones(): data = defaultdict(list) for tz in pytz.all_timezones: - if "/" in tz: - area, loc = tz.split("/", 1) + if '/' in tz: + area, loc = tz.split('/', 1) else: - area, loc = "Other", tz - if not loc.startswith("GMT"): + area, loc = 'Other', tz + if not loc.startswith('GMT'): data[area].append((tz, loc)) return sorted(data.items(), key=itemgetter(0)) @@ -21,36 +21,46 @@ TIMEZONE = make_timezones() del make_timezones ACE_THEMES = ( - ("ambiance", "Ambiance"), - ("chaos", "Chaos"), - ("chrome", "Chrome"), - ("clouds", "Clouds"), - ("clouds_midnight", "Clouds Midnight"), - ("cobalt", "Cobalt"), - ("crimson_editor", "Crimson Editor"), - ("dawn", "Dawn"), - ("dreamweaver", "Dreamweaver"), - ("eclipse", "Eclipse"), - ("github", "Github"), - ("idle_fingers", "Idle Fingers"), - ("katzenmilch", "Katzenmilch"), - ("kr_theme", "KR Theme"), - ("kuroir", "Kuroir"), - ("merbivore", "Merbivore"), - ("merbivore_soft", "Merbivore Soft"), - ("mono_industrial", "Mono Industrial"), - ("monokai", "Monokai"), - ("pastel_on_dark", "Pastel on Dark"), - ("solarized_dark", "Solarized Dark"), - ("solarized_light", "Solarized Light"), - ("terminal", "Terminal"), - ("textmate", "Textmate"), - ("tomorrow", "Tomorrow"), - ("tomorrow_night", "Tomorrow Night"), - ("tomorrow_night_blue", "Tomorrow Night Blue"), - ("tomorrow_night_bright", "Tomorrow Night Bright"), - ("tomorrow_night_eighties", "Tomorrow Night Eighties"), - ("twilight", "Twilight"), - ("vibrant_ink", "Vibrant Ink"), - ("xcode", "XCode"), + ('ambiance', 'Ambiance'), + ('chaos', 'Chaos'), + ('chrome', 'Chrome'), + ('clouds', 'Clouds'), + ('clouds_midnight', 'Clouds Midnight'), + ('cobalt', 'Cobalt'), + ('crimson_editor', 'Crimson Editor'), + ('dawn', 'Dawn'), + ('dreamweaver', 'Dreamweaver'), + ('eclipse', 'Eclipse'), + ('github', 'Github'), + ('idle_fingers', 'Idle Fingers'), + ('katzenmilch', 'Katzenmilch'), + ('kr_theme', 'KR Theme'), + ('kuroir', 'Kuroir'), + ('merbivore', 'Merbivore'), + ('merbivore_soft', 'Merbivore Soft'), + ('mono_industrial', 'Mono Industrial'), + ('monokai', 'Monokai'), + ('pastel_on_dark', 'Pastel on Dark'), + ('solarized_dark', 'Solarized Dark'), + ('solarized_light', 'Solarized Light'), + ('terminal', 'Terminal'), + ('textmate', 'Textmate'), + ('tomorrow', 'Tomorrow'), + ('tomorrow_night', 'Tomorrow Night'), + ('tomorrow_night_blue', 'Tomorrow Night Blue'), + ('tomorrow_night_bright', 'Tomorrow Night Bright'), + ('tomorrow_night_eighties', 'Tomorrow Night Eighties'), + ('twilight', 'Twilight'), + ('vibrant_ink', 'Vibrant Ink'), + ('xcode', 'XCode'), ) + +MATH_ENGINES_CHOICES = ( + ('tex', _('Leave as LaTeX')), + ('svg', _('SVG with PNG fallback')), + ('mml', _('MathML only')), + ('jax', _('MathJax with SVG/PNG fallback')), + ('auto', _('Detect best quality')), +) + +EFFECTIVE_MATH_ENGINES = ('svg', 'mml', 'tex', 'jax') diff --git a/judge/models/comment.py b/judge/models/comment.py index 7e9f5bf..d14d613 100644 --- a/judge/models/comment.py +++ b/judge/models/comment.py @@ -9,171 +9,177 @@ from django.db.models import CASCADE from django.urls import reverse from django.utils.functional import cached_property from django.utils.translation import gettext_lazy as _ -from django.contrib.contenttypes.fields import GenericForeignKey -from django.contrib.contenttypes.models import ContentType from mptt.fields import TreeForeignKey from mptt.models import MPTTModel from reversion.models import Version from judge.models.contest import Contest from judge.models.interface import BlogPost -from judge.models.problem import Problem, Solution +from judge.models.problem import Problem from judge.models.profile import Profile from judge.utils.cachedict import CacheDict -from judge.caching import cache_wrapper +__all__ = ['Comment', 'CommentLock', 'CommentVote'] -__all__ = ["Comment", "CommentLock", "CommentVote", "Notification"] +comment_validator = RegexValidator(r'^[pcs]:[a-z0-9]+$|^b:\d+$', + _(r'Page code must be ^[pcs]:[a-z0-9]+$|^b:\d+$')) class VersionRelation(GenericRelation): def __init__(self): - super(VersionRelation, self).__init__(Version, object_id_field="object_id") + super(VersionRelation, self).__init__(Version, object_id_field='object_id') def get_extra_restriction(self, where_class, alias, remote_alias): - cond = super(VersionRelation, self).get_extra_restriction( - where_class, alias, remote_alias - ) - field = self.remote_field.model._meta.get_field("db") - lookup = field.get_lookup("exact")(field.get_col(remote_alias), "default") - cond.add(lookup, "AND") + cond = super(VersionRelation, self).get_extra_restriction(where_class, alias, remote_alias) + field = self.remote_field.model._meta.get_field('db') + lookup = field.get_lookup('exact')(field.get_col(remote_alias), 'default') + cond.add(lookup, 'AND') return cond class Comment(MPTTModel): - author = models.ForeignKey(Profile, verbose_name=_("commenter"), on_delete=CASCADE) - time = models.DateTimeField(verbose_name=_("posted time"), auto_now_add=True) - content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) - object_id = models.PositiveIntegerField() - linked_object = GenericForeignKey("content_type", "object_id") - score = models.IntegerField(verbose_name=_("votes"), default=0) - body = models.TextField(verbose_name=_("body of comment"), max_length=8192) - hidden = models.BooleanField(verbose_name=_("hide the comment"), default=0) - parent = TreeForeignKey( - "self", - verbose_name=_("parent"), - null=True, - blank=True, - related_name="replies", - on_delete=CASCADE, - ) - revision_count = models.PositiveIntegerField(default=1) - + author = models.ForeignKey(Profile, verbose_name=_('commenter'), on_delete=CASCADE) + time = models.DateTimeField(verbose_name=_('posted time'), auto_now_add=True) + page = models.CharField(max_length=30, verbose_name=_('associated page'), db_index=True, + validators=[comment_validator]) + score = models.IntegerField(verbose_name=_('votes'), default=0) + body = models.TextField(verbose_name=_('body of comment'), max_length=8192) + hidden = models.BooleanField(verbose_name=_('hide the comment'), default=0) + parent = TreeForeignKey('self', verbose_name=_('parent'), null=True, blank=True, related_name='replies', + on_delete=CASCADE) versions = VersionRelation() class Meta: - verbose_name = _("comment") - verbose_name_plural = _("comments") - indexes = [ - models.Index(fields=["content_type", "object_id"]), - ] + verbose_name = _('comment') + verbose_name_plural = _('comments') class MPTTMeta: - order_insertion_by = ["-time"] + order_insertion_by = ['-time'] @classmethod - def most_recent(cls, user, n, batch=None, organization=None): - queryset = cls.objects.filter(hidden=False).order_by("-id") + def most_recent(cls, user, n, batch=None): + queryset = cls.objects.filter(hidden=False).select_related('author__user') \ + .defer('author__about', 'body').order_by('-id') - if organization: - queryset = queryset.filter(author__in=organization.members.all()) + problem_access = CacheDict(lambda code: Problem.objects.get(code=code).is_accessible_by(user)) + contest_access = CacheDict(lambda key: Contest.objects.get(key=key).is_accessible_by(user)) + blog_access = CacheDict(lambda id: BlogPost.objects.get(id=id).can_see(user)) - problem_access = CacheDict(lambda p: p.is_accessible_by(user)) - contest_access = CacheDict(lambda c: c.is_accessible_by(user)) - blog_access = CacheDict(lambda b: b.is_accessible_by(user)) - - if n == -1: - n = len(queryset) if user.is_superuser: return queryset[:n] if batch is None: batch = 2 * n output = [] for i in itertools.count(0): - slice = queryset[i * batch : i * batch + batch] + slice = queryset[i * batch:i * batch + batch] if not slice: break for comment in slice: - if isinstance(comment.linked_object, Problem): - if problem_access[comment.linked_object]: - output.append(comment) - elif isinstance(comment.linked_object, Contest): - if contest_access[comment.linked_object]: - output.append(comment) - elif isinstance(comment.linked_object, BlogPost): - if blog_access[comment.linked_object]: - output.append(comment) - elif isinstance(comment.linked_object, Solution): - if problem_access[comment.linked_object.problem]: - output.append(comment) + if comment.page.startswith('p:') or comment.page.startswith('s:'): + try: + if problem_access[comment.page[2:]]: + output.append(comment) + except Problem.DoesNotExist: + pass + elif comment.page.startswith('c:'): + try: + if contest_access[comment.page[2:]]: + output.append(comment) + except Contest.DoesNotExist: + pass + elif comment.page.startswith('b:'): + try: + if blog_access[comment.page[2:]]: + output.append(comment) + except BlogPost.DoesNotExist: + pass + else: + output.append(comment) if len(output) >= n: return output return output @cached_property - def get_replies(self): - query = Comment.filter(parent=self) - return len(query) + def link(self): + try: + link = None + if self.page.startswith('p:'): + link = reverse('problem_detail', args=(self.page[2:],)) + elif self.page.startswith('c:'): + link = reverse('contest_view', args=(self.page[2:],)) + elif self.page.startswith('b:'): + key = 'blog_slug:%s' % self.page[2:] + slug = cache.get(key) + if slug is None: + try: + slug = BlogPost.objects.get(id=self.page[2:]).slug + except ObjectDoesNotExist: + slug = '' + cache.set(key, slug, 3600) + link = reverse('blog_post', args=(self.page[2:], slug)) + elif self.page.startswith('s:'): + link = reverse('problem_editorial', args=(self.page[2:],)) + except Exception: + link = 'invalid' + return link + + @classmethod + def get_page_title(cls, page): + try: + if page.startswith('p:'): + return Problem.objects.values_list('name', flat=True).get(code=page[2:]) + elif page.startswith('c:'): + return Contest.objects.values_list('name', flat=True).get(key=page[2:]) + elif page.startswith('b:'): + return BlogPost.objects.values_list('title', flat=True).get(id=page[2:]) + elif page.startswith('s:'): + return _('Editorial for %s') % Problem.objects.values_list('name', flat=True).get(code=page[2:]) + return '' + except ObjectDoesNotExist: + return '' @cached_property def page_title(self): - if isinstance(self.linked_object, Problem): - return self.linked_object.name - elif isinstance(self.linked_object, Contest): - return self.linked_object.name - elif isinstance(self.linked_object, Solution): - return _("Editorial for ") + self.linked_object.problem.name - elif isinstance(self.linked_object, BlogPost): - return self.linked_object.title - - @cached_property - def link(self): - if isinstance(self.linked_object, Problem): - return reverse("problem_detail", args=(self.linked_object.code,)) - elif isinstance(self.linked_object, Contest): - return reverse("contest_view", args=(self.linked_object.key,)) - elif isinstance(self.linked_object, Solution): - return reverse("problem_editorial", args=(self.linked_object.problem.code,)) - elif isinstance(self.linked_object, BlogPost): - return reverse( - "blog_post", - args=( - self.object_id, - self.linked_object.slug, - ), - ) + return self.get_page_title(self.page) def get_absolute_url(self): - return "%s?comment-id=%d#comment-%d" % (self.link, self.id, self.id) + return '%s#comment-%d' % (self.link, self.id) + + def __str__(self): + return '%(page)s by %(user)s' % {'page': self.page, 'user': self.author.user.username} + + # Only use this when queried with + # .prefetch_related(Prefetch('votes', queryset=CommentVote.objects.filter(voter_id=profile_id))) + # It's rather stupid to put a query specific property on the model, but the alternative requires + # digging Django internals, and could not be guaranteed to work forever. + # Hence it is left here for when the alternative breaks. + # @property + # def vote_score(self): + # queryset = self.votes.all() + # if not queryset: + # return 0 + # return queryset[0].score class CommentVote(models.Model): - voter = models.ForeignKey(Profile, related_name="voted_comments", on_delete=CASCADE) - comment = models.ForeignKey(Comment, related_name="votes", on_delete=CASCADE) + voter = models.ForeignKey(Profile, related_name='voted_comments', on_delete=CASCADE) + comment = models.ForeignKey(Comment, related_name='votes', on_delete=CASCADE) score = models.IntegerField() class Meta: - unique_together = ["voter", "comment"] - verbose_name = _("comment vote") - verbose_name_plural = _("comment votes") + unique_together = ['voter', 'comment'] + verbose_name = _('comment vote') + verbose_name_plural = _('comment votes') class CommentLock(models.Model): - page = models.CharField( - max_length=30, - verbose_name=_("associated page"), - db_index=True, - ) + page = models.CharField(max_length=30, verbose_name=_('associated page'), db_index=True, + validators=[comment_validator]) class Meta: - permissions = (("override_comment_lock", _("Override comment lock")),) + permissions = ( + ('override_comment_lock', _('Override comment lock')), + ) def __str__(self): return str(self.page) - - -@cache_wrapper(prefix="gcc") -def get_visible_comment_count(content_type, object_id): - return Comment.objects.filter( - content_type=content_type, object_id=object_id, hidden=False - ).count() diff --git a/judge/models/contest.py b/judge/models/contest.py index 625841d..2337ef1 100644 --- a/judge/models/contest.py +++ b/judge/models/contest.py @@ -1,74 +1,36 @@ from django.core.exceptions import ValidationError -from django.core.validators import MaxValueValidator, MinValueValidator, RegexValidator +from django.core.validators import MinValueValidator, RegexValidator from django.db import models, transaction -from django.db.models import CASCADE, Q -from django.db.models.signals import m2m_changed +from django.db.models import CASCADE from django.urls import reverse from django.utils import timezone from django.utils.functional import cached_property from django.utils.translation import gettext, gettext_lazy as _ -from django.contrib.contenttypes.fields import GenericRelation -from django.dispatch import receiver - from jsonfield import JSONField -from lupa import LuaRuntime -from moss import ( - MOSS_LANG_C, - MOSS_LANG_CC, - MOSS_LANG_JAVA, - MOSS_LANG_PYTHON, - MOSS_LANG_PASCAL, -) -from datetime import timedelta, datetime +from moss import MOSS_LANG_C, MOSS_LANG_CC, MOSS_LANG_JAVA, MOSS_LANG_PYTHON from judge import contest_format from judge.models.problem import Problem from judge.models.profile import Organization, Profile from judge.models.submission import Submission from judge.ratings import rate_contest -from judge.models.pagevote import PageVotable -from judge.models.bookmark import Bookmarkable -from judge.fulltext import SearchManager -from judge.caching import cache_wrapper -__all__ = [ - "Contest", - "ContestTag", - "ContestParticipation", - "ContestProblem", - "ContestSubmission", - "Rating", - "ContestProblemClarification", - "ContestsSummary", - "OfficialContest", - "OfficialContestCategory", - "OfficialContestLocation", -] +__all__ = ['Contest', 'ContestTag', 'ContestParticipation', 'ContestProblem', 'ContestSubmission', 'Rating'] class ContestTag(models.Model): - color_validator = RegexValidator("^#(?:[A-Fa-f0-9]{3}){1,2}$", _("Invalid colour.")) + color_validator = RegexValidator('^#(?:[A-Fa-f0-9]{3}){1,2}$', _('Invalid colour.')) - name = models.CharField( - max_length=20, - verbose_name=_("tag name"), - unique=True, - validators=[ - RegexValidator( - r"^[a-z-]+$", message=_("Lowercase letters and hyphens only.") - ) - ], - ) - color = models.CharField( - max_length=7, verbose_name=_("tag colour"), validators=[color_validator] - ) - description = models.TextField(verbose_name=_("tag description"), blank=True) + name = models.CharField(max_length=20, verbose_name=_('tag name'), unique=True, + validators=[RegexValidator(r'^[a-z-]+$', message=_('Lowercase letters and hyphens only.'))]) + color = models.CharField(max_length=7, verbose_name=_('tag colour'), validators=[color_validator]) + description = models.TextField(verbose_name=_('tag description'), blank=True) def __str__(self): return self.name def get_absolute_url(self): - return reverse("contest_tag", args=[self.name]) + return reverse('contest_tag', args=[self.name]) @property def text_color(self, cache={}): @@ -77,264 +39,80 @@ class ContestTag(models.Model): r, g, b = [ord(bytes.fromhex(i * 2)) for i in self.color[1:]] else: r, g, b = [i for i in bytes.fromhex(self.color[1:])] - cache[self.color] = ( - "#000" if 299 * r + 587 * g + 144 * b > 140000 else "#fff" - ) + cache[self.color] = '#000' if 299 * r + 587 * g + 144 * b > 140000 else '#fff' return cache[self.color] class Meta: - verbose_name = _("contest tag") - verbose_name_plural = _("contest tags") + verbose_name = _('contest tag') + verbose_name_plural = _('contest tags') -class Contest(models.Model, PageVotable, Bookmarkable): - SCOREBOARD_VISIBLE = "V" - SCOREBOARD_AFTER_CONTEST = "C" - SCOREBOARD_AFTER_PARTICIPATION = "P" - SCOREBOARD_VISIBILITY = ( - (SCOREBOARD_VISIBLE, _("Visible")), - (SCOREBOARD_AFTER_CONTEST, _("Hidden for duration of contest")), - (SCOREBOARD_AFTER_PARTICIPATION, _("Hidden for duration of participation")), - ) - key = models.CharField( - max_length=20, - verbose_name=_("contest id"), - unique=True, - validators=[RegexValidator("^[a-z0-9]+$", _("Contest id must be ^[a-z0-9]+$"))], - ) - name = models.CharField( - max_length=100, verbose_name=_("contest name"), db_index=True - ) - authors = models.ManyToManyField( - Profile, - verbose_name=_("authors"), - help_text=_("These users will be able to edit the contest."), - related_name="authors+", - ) - curators = models.ManyToManyField( - Profile, - verbose_name=_("curators"), - help_text=_( - "These users will be able to edit the contest, " - "but will not be listed as authors." - ), - related_name="curators+", - blank=True, - ) - testers = models.ManyToManyField( - Profile, - verbose_name=_("testers"), - help_text=_( - "These users will be able to view the contest, " "but not edit it." - ), - blank=True, - related_name="testers+", - ) - description = models.TextField(verbose_name=_("description"), blank=True) - problems = models.ManyToManyField( - Problem, verbose_name=_("problems"), through="ContestProblem" - ) - start_time = models.DateTimeField(verbose_name=_("start time"), db_index=True) - end_time = models.DateTimeField(verbose_name=_("end time"), db_index=True) - time_limit = models.DurationField( - verbose_name=_("time limit"), - blank=True, - null=True, - help_text=_( - "Format hh:mm:ss. For example, if you want a 2-hour contest, enter 02:00:00" - ), - ) - freeze_after = models.DurationField( - verbose_name=_("freeze after"), - blank=True, - null=True, - help_text=_( - "Format hh:mm:ss. For example, if you want to freeze contest after 2 hours, enter 02:00:00" - ), - ) - is_visible = models.BooleanField( - verbose_name=_("publicly visible"), - default=False, - help_text=_( - "Should be set even for organization-private contests, where it " - "determines whether the contest is visible to members of the " - "specified organizations." - ), - ) - is_rated = models.BooleanField( - verbose_name=_("contest rated"), - help_text=_("Whether this contest can be rated."), - default=False, - ) - scoreboard_visibility = models.CharField( - verbose_name=_("scoreboard visibility"), - default=SCOREBOARD_VISIBLE, - max_length=1, - help_text=_("Scoreboard visibility through the duration " "of the contest"), - choices=SCOREBOARD_VISIBILITY, - ) - view_contest_scoreboard = models.ManyToManyField( - Profile, - verbose_name=_("view contest scoreboard"), - blank=True, - related_name="view_contest_scoreboard", - help_text=_("These users will be able to view the scoreboard."), - ) - public_scoreboard = models.BooleanField( - verbose_name=_("public scoreboard"), - help_text=_("Ranking page is public even for private contests."), - default=False, - ) - use_clarifications = models.BooleanField( - verbose_name=_("no comments"), - help_text=_("Use clarification system instead of comments."), - default=True, - ) - rating_floor = models.IntegerField( - verbose_name=("rating floor"), - help_text=_("Rating floor for contest"), - null=True, - blank=True, - ) - rating_ceiling = models.IntegerField( - verbose_name=("rating ceiling"), - help_text=_("Rating ceiling for contest"), - null=True, - blank=True, - ) - rate_all = models.BooleanField( - verbose_name=_("rate all"), - help_text=_("Rate all users who joined."), - default=False, - ) - rate_exclude = models.ManyToManyField( - Profile, - verbose_name=_("exclude from ratings"), - blank=True, - related_name="rate_exclude+", - ) - is_private = models.BooleanField( - verbose_name=_("private to specific users"), default=False - ) - private_contestants = models.ManyToManyField( - Profile, - blank=True, - verbose_name=_("private contestants"), - help_text=_("If private, only these users may see the contest"), - related_name="private_contestants+", - ) - hide_problem_tags = models.BooleanField( - verbose_name=_("hide problem tags"), - help_text=_("Whether problem tags should be hidden by default."), - default=True, - ) - run_pretests_only = models.BooleanField( - verbose_name=_("run pretests only"), - help_text=_( - "Whether judges should grade pretests only, versus all " - "testcases. Commonly set during a contest, then unset " - "prior to rejudging user submissions when the contest ends." - ), - default=False, - ) - is_organization_private = models.BooleanField( - verbose_name=_("private to organizations"), default=False - ) - organizations = models.ManyToManyField( - Organization, - blank=True, - verbose_name=_("organizations"), - help_text=_("If private, only these organizations may see the contest"), - ) - is_in_course = models.BooleanField( - verbose_name=_("contest in course"), - default=False, - ) - og_image = models.CharField( - verbose_name=_("OpenGraph image"), default="", max_length=150, blank=True - ) - logo_override_image = models.CharField( - verbose_name=_("Logo override image"), - default="", - max_length=150, - blank=True, - help_text=_( - "This image will replace the default site logo for users " - "inside the contest." - ), - ) - tags = models.ManyToManyField( - ContestTag, verbose_name=_("contest tags"), blank=True, related_name="contests" - ) - user_count = models.IntegerField( - verbose_name=_("the amount of live participants"), default=0 - ) - summary = models.TextField( - blank=True, - verbose_name=_("contest summary"), - help_text=_( - "Plain-text, shown in meta description tag, e.g. for social media." - ), - ) - access_code = models.CharField( - verbose_name=_("access code"), - blank=True, - default="", - max_length=255, - help_text=_( - "An optional code to prompt contestants before they are allowed " - "to join the contest. Leave it blank to disable." - ), - ) - banned_users = models.ManyToManyField( - Profile, - verbose_name=_("personae non gratae"), - blank=True, - help_text=_("Bans the selected users from joining this contest."), - ) - format_name = models.CharField( - verbose_name=_("contest format"), - default="default", - max_length=32, - choices=contest_format.choices(), - help_text=_("The contest format module to use."), - ) - format_config = JSONField( - verbose_name=_("contest format configuration"), - null=True, - blank=True, - help_text=_( - "A JSON object to serve as the configuration for the chosen contest format " - "module. Leave empty to use None. Exact format depends on the contest format " - "selected." - ), - ) - problem_label_script = models.TextField( - verbose_name="contest problem label script", - blank=True, - help_text="A custom Lua function to generate problem labels. Requires a " - "single function with an integer parameter, the zero-indexed " - "contest problem index, and returns a string, the label.", - ) - points_precision = models.IntegerField( - verbose_name=_("precision points"), - default=2, - validators=[MinValueValidator(0), MaxValueValidator(10)], - help_text=_("Number of digits to round points to."), - ) - rate_limit = models.PositiveIntegerField( - verbose_name=(_("rate limit")), - null=True, - blank=True, - validators=[MinValueValidator(1), MaxValueValidator(5)], - help_text=_( - "Maximum number of submissions per minute. Leave empty if you don't want rate limit." - ), - ) - comments = GenericRelation("Comment") - pagevote = GenericRelation("PageVote") - bookmark = GenericRelation("BookMark") - objects = SearchManager(("key", "name")) +class Contest(models.Model): + key = models.CharField(max_length=20, verbose_name=_('contest id'), unique=True, + validators=[RegexValidator('^[a-z0-9]+$', _('Contest id must be ^[a-z0-9]+$'))]) + name = models.CharField(max_length=100, verbose_name=_('contest name'), db_index=True) + organizers = models.ManyToManyField(Profile, help_text=_('These people will be able to edit the contest.'), + related_name='organizers+') + description = models.TextField(verbose_name=_('description'), blank=True) + problems = models.ManyToManyField(Problem, verbose_name=_('problems'), through='ContestProblem') + start_time = models.DateTimeField(verbose_name=_('start time'), db_index=True) + end_time = models.DateTimeField(verbose_name=_('end time'), db_index=True) + time_limit = models.DurationField(verbose_name=_('time limit'), blank=True, null=True) + is_visible = models.BooleanField(verbose_name=_('publicly visible'), default=False, + help_text=_('Should be set even for organization-private contests, where it ' + 'determines whether the contest is visible to members of the ' + 'specified organizations.')) + is_rated = models.BooleanField(verbose_name=_('contest rated'), help_text=_('Whether this contest can be rated.'), + default=False) + hide_scoreboard = models.BooleanField(verbose_name=_('hide scoreboard'), + help_text=_('Whether the scoreboard should remain hidden for the duration ' + 'of the contest.'), + default=False) + use_clarifications = models.BooleanField(verbose_name=_('no comments'), + help_text=_("Use clarification system instead of comments."), + default=True) + rating_floor = models.IntegerField(verbose_name=('rating floor'), help_text=_('Rating floor for contest'), + null=True, blank=True) + rating_ceiling = models.IntegerField(verbose_name=('rating ceiling'), help_text=_('Rating ceiling for contest'), + null=True, blank=True) + rate_all = models.BooleanField(verbose_name=_('rate all'), help_text=_('Rate all users who joined.'), default=False) + rate_exclude = models.ManyToManyField(Profile, verbose_name=_('exclude from ratings'), blank=True, + related_name='rate_exclude+') + is_private = models.BooleanField(verbose_name=_('private to specific users'), default=False) + private_contestants = models.ManyToManyField(Profile, blank=True, verbose_name=_('private contestants'), + help_text=_('If private, only these users may see the contest'), + related_name='private_contestants+') + hide_problem_tags = models.BooleanField(verbose_name=_('hide problem tags'), + help_text=_('Whether problem tags should be hidden by default.'), + default=False) + run_pretests_only = models.BooleanField(verbose_name=_('run pretests only'), + help_text=_('Whether judges should grade pretests only, versus all ' + 'testcases. Commonly set during a contest, then unset ' + 'prior to rejudging user submissions when the contest ends.'), + default=False) + is_organization_private = models.BooleanField(verbose_name=_('private to organizations'), default=False) + organizations = models.ManyToManyField(Organization, blank=True, verbose_name=_('organizations'), + help_text=_('If private, only these organizations may see the contest')) + og_image = models.CharField(verbose_name=_('OpenGraph image'), default='', max_length=150, blank=True) + logo_override_image = models.CharField(verbose_name=_('Logo override image'), default='', max_length=150, + blank=True, + help_text=_('This image will replace the default site logo for users ' + 'inside the contest.')) + tags = models.ManyToManyField(ContestTag, verbose_name=_('contest tags'), blank=True, related_name='contests') + user_count = models.IntegerField(verbose_name=_('the amount of live participants'), default=0) + summary = models.TextField(blank=True, verbose_name=_('contest summary'), + help_text=_('Plain-text, shown in meta description tag, e.g. for social media.')) + access_code = models.CharField(verbose_name=_('access code'), blank=True, default='', max_length=255, + help_text=_('An optional code to prompt contestants before they are allowed ' + 'to join the contest. Leave it blank to disable.')) + banned_users = models.ManyToManyField(Profile, verbose_name=_('personae non gratae'), blank=True, + help_text=_('Bans the selected users from joining this contest.')) + format_name = models.CharField(verbose_name=_('contest format'), default='default', max_length=32, + choices=contest_format.choices(), help_text=_('The contest format module to use.')) + format_config = JSONField(verbose_name=_('contest format configuration'), null=True, blank=True, + help_text=_('A JSON object to serve as the configuration for the chosen contest format ' + 'module. Leave empty to use None. Exact format depends on the contest format ' + 'selected.')) @cached_property def format_class(self): @@ -344,111 +122,28 @@ class Contest(models.Model, PageVotable, Bookmarkable): def format(self): return self.format_class(self, self.format_config) - @cached_property - def get_label_for_problem(self): - def DENY_ALL(obj, attr_name, is_setting): - raise AttributeError() - - lua = LuaRuntime( - attribute_filter=DENY_ALL, register_eval=False, register_builtins=False - ) - return lua.eval( - self.problem_label_script or self.format.get_contest_problem_label_script() - ) - def clean(self): # Django will complain if you didn't fill in start_time or end_time, so we don't have to. if self.start_time and self.end_time and self.start_time >= self.end_time: - raise ValidationError(_("End time must be after start time")) + raise ValidationError('What is this? A contest that ended before it starts?') self.format_class.validate(self.format_config) - try: - # a contest should have at least one problem, with contest problem index 0 - # so test it to see if the script returns a valid label. - label = self.get_label_for_problem(0) - except Exception as e: - raise ValidationError("Contest problem label script: %s" % e) - else: - if not isinstance(label, str): - raise ValidationError( - "Contest problem label script: script should return a string." - ) - - def save(self, *args, **kwargs): - earliest_start_time = datetime(2020, 1, 1).replace(tzinfo=timezone.utc) - if self.start_time < earliest_start_time: - self.start_time = earliest_start_time - - if self.end_time < self.start_time: - self.end_time = self.start_time + timedelta(hours=1) - - one_year_later = self.start_time + timedelta(days=365) - if self.end_time > one_year_later: - self.end_time = one_year_later - - max_duration = timedelta(days=7) - if self.time_limit and self.time_limit > max_duration: - self.time_limit = max_duration - - super().save(*args, **kwargs) - def is_in_contest(self, user): if user.is_authenticated: profile = user.profile - return ( - profile - and profile.current_contest is not None - and profile.current_contest.contest == self - ) + return profile and profile.current_contest is not None and profile.current_contest.contest == self return False - def can_see_own_scoreboard(self, user): - if self.can_see_full_scoreboard(user): + def can_see_scoreboard(self, user): + if user.has_perm('judge.see_private_contest'): return True - if not self.can_join: + if user.is_authenticated and self.organizers.filter(id=user.profile.id).exists(): + return True + if not self.is_visible: return False - if not self.show_scoreboard and not self.is_in_contest(user): + if self.start_time is not None and self.start_time > timezone.now(): return False - return True - - def can_see_full_scoreboard(self, user): - if self.show_scoreboard: - return True - if not user.is_authenticated: - return False - if user.has_perm("judge.see_private_contest") or user.has_perm( - "judge.edit_all_contest" - ): - return True - if user.profile.id in self.editor_ids: - return True - if self.view_contest_scoreboard.filter(id=user.profile.id).exists(): - return True - if ( - self.scoreboard_visibility == self.SCOREBOARD_AFTER_PARTICIPATION - and self.has_completed_contest(user) - ): - return True - return False - - def has_completed_contest(self, user): - if user.is_authenticated: - participation = self.users.filter( - virtual=ContestParticipation.LIVE, user=user.profile - ).first() - if participation and participation.ended: - return True - return False - - @cached_property - def show_scoreboard(self): - if not self.can_join: - return False - if ( - self.scoreboard_visibility - in (self.SCOREBOARD_AFTER_CONTEST, self.SCOREBOARD_AFTER_PARTICIPATION) - and not self.ended - ): + if self.hide_scoreboard and not self.is_in_contest(user) and self.end_time > timezone.now(): return False return True @@ -483,47 +178,11 @@ class Contest(models.Model, PageVotable, Bookmarkable): def ended(self): return self.end_time < self._now - @cache_wrapper(prefix="Coai") - def _author_ids(self): - return set( - Contest.authors.through.objects.filter(contest=self).values_list( - "profile_id", flat=True - ) - ) - - @cache_wrapper(prefix="Coci") - def _curator_ids(self): - return set( - Contest.curators.through.objects.filter(contest=self).values_list( - "profile_id", flat=True - ) - ) - - @cache_wrapper(prefix="Coti") - def _tester_ids(self): - return set( - Contest.testers.through.objects.filter(contest=self).values_list( - "profile_id", flat=True - ) - ) - - @cached_property - def author_ids(self): - return self._author_ids() - - @cached_property - def editor_ids(self): - return self.author_ids.union(self._curator_ids()) - - @cached_property - def tester_ids(self): - return self._tester_ids() - def __str__(self): - return f"{self.name} ({self.key})" + return self.name def get_absolute_url(self): - return reverse("contest_view", args=(self.key,)) + return reverse('contest_view', args=(self.key,)) def update_user_count(self): self.user_count = self.users.filter(virtual=0).count() @@ -531,237 +190,86 @@ class Contest(models.Model, PageVotable, Bookmarkable): update_user_count.alters_data = True - class Inaccessible(Exception): - pass - - class PrivateContest(Exception): - pass - - def access_check(self, user): - # Do unauthenticated check here so we can skip authentication checks later on. - if not user.is_authenticated: - # Unauthenticated users can only see visible, non-private contests - if not self.is_visible: - raise self.Inaccessible() - if self.is_private or self.is_organization_private: - raise self.PrivateContest() - return - - # If the user can view or edit all contests - if user.has_perm("judge.see_private_contest") or user.has_perm( - "judge.edit_all_contest" - ): - return - - # User is organizer or curator for contest - if user.profile.id in self.editor_ids: - return - - # User is tester for contest - if user.profile.id in self.tester_ids: - return - - # Contest is not publicly visible - if not self.is_visible: - raise self.Inaccessible() - - if self.is_in_course: - from judge.models import Course, CourseContest - - course_contest = CourseContest.objects.filter(contest=self).first() - if Course.is_accessible_by(course_contest.course, user.profile): - return - raise self.Inaccessible() - - # Contest is not private - if not self.is_private and not self.is_organization_private: - return - - if self.view_contest_scoreboard.filter(id=user.profile.id).exists(): - return - - in_org = self.organizations.filter( - id__in=user.profile.organizations.all() - ).exists() - in_users = self.private_contestants.filter(id=user.profile.id).exists() - - if not self.is_private and self.is_organization_private: - if in_org: - return - raise self.PrivateContest() - - if self.is_private and not self.is_organization_private: - if in_users: - return - raise self.PrivateContest() - - if self.is_private and self.is_organization_private: - if in_org and in_users: - return - raise self.PrivateContest() + @cached_property + def show_scoreboard(self): + if self.hide_scoreboard and not self.ended: + return False + return True def is_accessible_by(self, user): - try: - self.access_check(user) - except (self.Inaccessible, self.PrivateContest): - return False - else: + # Contest is publicly visible + if self.is_visible: + # Contest is not private + if not self.is_private and not self.is_organization_private: + return True + if user.is_authenticated: + # User is in the organizations it is private to + if self.organizations.filter(id__in=user.profile.organizations.all()).exists(): + return True + # User is in the group of private contestants + if self.private_contestants.filter(id=user.profile.id).exists(): + return True + + # If the user can view all contests + if user.has_perm('judge.see_private_contest'): return True + # User can edit the contest + return self.is_editable_by(user) + def is_editable_by(self, user): # If the user can edit all contests - if user.has_perm("judge.edit_all_contest"): + if user.has_perm('judge.edit_all_contest'): return True - # If the user is a contest organizer or curator - if hasattr(user, "profile") and user.profile.id in self.editor_ids: + # If the user is a contest organizer + if user.has_perm('judge.edit_own_contest') and \ + self.organizers.filter(id=user.profile.id).exists(): return True return False - @classmethod - def get_visible_contests(cls, user, show_own_contests_only=False): - if not user.is_authenticated: - return ( - cls.objects.filter( - is_visible=True, - is_organization_private=False, - is_private=False, - is_in_course=False, - ) - .defer("description") - .distinct() - ) - - queryset = cls.objects.defer("description") - if ( - not ( - user.has_perm("judge.see_private_contest") - or user.has_perm("judge.edit_all_contest") - ) - or show_own_contests_only - ): - q = Q(is_visible=True, is_in_course=False) - q &= ( - Q(view_contest_scoreboard=user.profile) - | Q(is_organization_private=False, is_private=False) - | Q( - is_organization_private=False, - is_private=True, - private_contestants=user.profile, - ) - | Q( - is_organization_private=True, - is_private=False, - organizations__in=user.profile.organizations.all(), - ) - | Q( - is_organization_private=True, - is_private=True, - organizations__in=user.profile.organizations.all(), - private_contestants=user.profile, - ) - ) - - q |= Q(authors=user.profile) - q |= Q(curators=user.profile) - q |= Q(testers=user.profile) - queryset = queryset.filter(q) - return queryset.distinct() - def rate(self): - Rating.objects.filter( - contest__end_time__range=(self.end_time, self._now) - ).delete() - for contest in Contest.objects.filter( - is_rated=True, - end_time__range=(self.end_time, self._now), - ).order_by("end_time"): + Rating.objects.filter(contest__end_time__gte=self.end_time).delete() + for contest in Contest.objects.filter(is_rated=True, end_time__gte=self.end_time).order_by('end_time'): rate_contest(contest) class Meta: permissions = ( - ("see_private_contest", _("See private contests")), - ("edit_own_contest", _("Edit own contests")), - ("edit_all_contest", _("Edit all contests")), - ("clone_contest", _("Clone contest")), - ("moss_contest", _("MOSS contest")), - ("contest_rating", _("Rate contests")), - ("contest_access_code", _("Contest access codes")), - ("create_private_contest", _("Create private contests")), - ("change_contest_visibility", _("Change contest visibility")), - ("contest_problem_label", _("Edit contest problem label script")), + ('see_private_contest', _('See private contests')), + ('edit_own_contest', _('Edit own contests')), + ('edit_all_contest', _('Edit all contests')), + ('clone_contest', _('Clone contest')), + ('moss_contest', _('MOSS contest')), + ('contest_rating', _('Rate contests')), + ('contest_access_code', _('Contest access codes')), + ('create_private_contest', _('Create private contests')), ) - verbose_name = _("contest") - verbose_name_plural = _("contests") - - -@receiver(m2m_changed, sender=Contest.organizations.through) -def update_organization_private(sender, instance, **kwargs): - if kwargs["action"] in ["post_add", "post_remove", "post_clear"]: - instance.is_organization_private = instance.organizations.exists() - instance.save(update_fields=["is_organization_private"]) - - -@receiver(m2m_changed, sender=Contest.private_contestants.through) -def update_private(sender, instance, **kwargs): - if kwargs["action"] in ["post_add", "post_remove", "post_clear"]: - instance.is_private = instance.private_contestants.exists() - instance.save(update_fields=["is_private"]) + verbose_name = _('contest') + verbose_name_plural = _('contests') class ContestParticipation(models.Model): LIVE = 0 SPECTATE = -1 - contest = models.ForeignKey( - Contest, - verbose_name=_("associated contest"), - related_name="users", - on_delete=CASCADE, - ) - user = models.ForeignKey( - Profile, - verbose_name=_("user"), - related_name="contest_history", - on_delete=CASCADE, - ) - real_start = models.DateTimeField( - verbose_name=_("start time"), default=timezone.now, db_column="start" - ) - score = models.FloatField(verbose_name=_("score"), default=0, db_index=True) - cumtime = models.PositiveIntegerField(verbose_name=_("cumulative time"), default=0) - is_disqualified = models.BooleanField( - verbose_name=_("is disqualified"), - default=False, - help_text=_("Whether this participation is disqualified."), - ) - tiebreaker = models.FloatField(verbose_name=_("tie-breaking field"), default=0.0) - virtual = models.IntegerField( - verbose_name=_("virtual participation id"), - default=LIVE, - help_text=_("0 means non-virtual, otherwise the n-th virtual participation."), - ) - format_data = JSONField( - verbose_name=_("contest format specific data"), null=True, blank=True - ) - format_data_final = JSONField( - verbose_name=_("same as format_data, but including frozen results"), - null=True, - blank=True, - ) - score_final = models.FloatField(verbose_name=_("final score"), default=0) - cumtime_final = models.PositiveIntegerField( - verbose_name=_("final cumulative time"), default=0 - ) + contest = models.ForeignKey(Contest, verbose_name=_('associated contest'), related_name='users', on_delete=CASCADE) + user = models.ForeignKey(Profile, verbose_name=_('user'), related_name='contest_history', on_delete=CASCADE) + real_start = models.DateTimeField(verbose_name=_('start time'), default=timezone.now, db_column='start') + score = models.IntegerField(verbose_name=_('score'), default=0, db_index=True) + cumtime = models.PositiveIntegerField(verbose_name=_('cumulative time'), default=0) + is_disqualified = models.BooleanField(verbose_name=_('is disqualified'), default=False, + help_text=_('Whether this participation is disqualified.')) + virtual = models.IntegerField(verbose_name=_('virtual participation id'), default=LIVE, + help_text=_('0 means non-virtual, otherwise the n-th virtual participation.')) + format_data = JSONField(verbose_name=_('contest format specific data'), null=True, blank=True) def recompute_results(self): with transaction.atomic(): self.contest.format.update_participation(self) if self.is_disqualified: self.score = -9999 - self.save(update_fields=["score"]) - + self.save(update_fields=['score']) recompute_results.alters_data = True def set_disqualified(self, disqualified): @@ -775,7 +283,6 @@ class ContestParticipation(models.Model): self.contest.banned_users.add(self.user) else: self.contest.banned_users.remove(self.user) - set_disqualified.alters_data = True @property @@ -789,11 +296,7 @@ class ContestParticipation(models.Model): @cached_property def start(self): contest = self.contest - return ( - contest.start_time - if contest.time_limit is None and (self.live or self.spectate) - else self.real_start - ) + return contest.start_time if contest.time_limit is None and (self.live or self.spectate) else self.real_start @cached_property def end_time(self): @@ -805,11 +308,8 @@ class ContestParticipation(models.Model): return self.real_start + contest.time_limit else: return self.real_start + (contest.end_time - contest.start_time) - return ( - contest.end_time - if contest.time_limit is None - else min(self.real_start + contest.time_limit, contest.end_time) - ) + return contest.end_time if contest.time_limit is None else \ + min(self.real_start + contest.time_limit, contest.end_time) @cached_property def _now(self): @@ -828,234 +328,86 @@ class ContestParticipation(models.Model): def __str__(self): if self.spectate: - return gettext("%s spectating in %s") % ( - self.user.username, - self.contest.name, - ) + return gettext('%s spectating in %s') % (self.user.username, self.contest.name) if self.virtual: - return gettext("%s in %s, v%d") % ( - self.user.username, - self.contest.name, - self.virtual, - ) - return gettext("%s in %s") % (self.user.username, self.contest.name) + return gettext('%s in %s, v%d') % (self.user.username, self.contest.name, self.virtual) + return gettext('%s in %s') % (self.user.username, self.contest.name) class Meta: - verbose_name = _("contest participation") - verbose_name_plural = _("contest participations") + verbose_name = _('contest participation') + verbose_name_plural = _('contest participations') - unique_together = ("contest", "user", "virtual") + unique_together = ('contest', 'user', 'virtual') class ContestProblem(models.Model): - problem = models.ForeignKey( - Problem, verbose_name=_("problem"), related_name="contests", on_delete=CASCADE - ) - contest = models.ForeignKey( - Contest, - verbose_name=_("contest"), - related_name="contest_problems", - on_delete=CASCADE, - ) - points = models.IntegerField(verbose_name=_("points")) - partial = models.BooleanField(default=True, verbose_name=_("partial")) - is_pretested = models.BooleanField(default=False, verbose_name=_("is pretested")) - order = models.PositiveIntegerField(db_index=True, verbose_name=_("order")) - show_testcases = models.BooleanField( - verbose_name=_("visible testcases"), - default=False, - ) - max_submissions = models.IntegerField( - help_text=_( - "Maximum number of submissions for this problem, " "or 0 for no limit." - ), - verbose_name=_("max submissions"), - default=0, - validators=[ - MinValueValidator(0, _("Why include a problem you " "can't submit to?")) - ], - ) - hidden_subtasks = models.CharField( - help_text=_("Separated by commas, e.g: 2, 3"), - verbose_name=_("hidden subtasks"), - null=True, - blank=True, - max_length=20, - ) - - @property - def clarifications(self): - return ContestProblemClarification.objects.filter(problem=self) + problem = models.ForeignKey(Problem, verbose_name=_('problem'), related_name='contests', on_delete=CASCADE) + contest = models.ForeignKey(Contest, verbose_name=_('contest'), related_name='contest_problems', on_delete=CASCADE) + points = models.IntegerField(verbose_name=_('points')) + partial = models.BooleanField(default=True, verbose_name=_('partial')) + is_pretested = models.BooleanField(default=False, verbose_name=_('is pretested')) + order = models.PositiveIntegerField(db_index=True, verbose_name=_('order')) + output_prefix_override = models.IntegerField(help_text=_('0 to not show testcases, 1 to show'), + verbose_name=_('visible testcases'), null=True, blank=True, default=0) + max_submissions = models.IntegerField(help_text=_('Maximum number of submissions for this problem, ' + 'or 0 for no limit.'), default=0, + validators=[MinValueValidator(0, _('Why include a problem you ' + 'can\'t submit to?'))]) class Meta: - unique_together = ("problem", "contest") - verbose_name = _("contest problem") - verbose_name_plural = _("contest problems") + unique_together = ('problem', 'contest') + verbose_name = _('contest problem') + verbose_name_plural = _('contest problems') class ContestSubmission(models.Model): - submission = models.OneToOneField( - Submission, - verbose_name=_("submission"), - related_name="contest", - on_delete=CASCADE, - ) - problem = models.ForeignKey( - ContestProblem, - verbose_name=_("problem"), - on_delete=CASCADE, - related_name="submissions", - related_query_name="submission", - ) - participation = models.ForeignKey( - ContestParticipation, - verbose_name=_("participation"), - on_delete=CASCADE, - related_name="submissions", - related_query_name="submission", - ) - points = models.FloatField(default=0.0, verbose_name=_("points")) - is_pretest = models.BooleanField( - verbose_name=_("is pretested"), - help_text=_("Whether this submission was ran only on pretests."), - default=False, - ) + submission = models.OneToOneField(Submission, verbose_name=_('submission'), + related_name='contest', on_delete=CASCADE) + problem = models.ForeignKey(ContestProblem, verbose_name=_('problem'), on_delete=CASCADE, + related_name='submissions', related_query_name='submission') + participation = models.ForeignKey(ContestParticipation, verbose_name=_('participation'), on_delete=CASCADE, + related_name='submissions', related_query_name='submission') + points = models.FloatField(default=0.0, verbose_name=_('points')) + is_pretest = models.BooleanField(verbose_name=_('is pretested'), + help_text=_('Whether this submission was ran only on pretests.'), + default=False) class Meta: - verbose_name = _("contest submission") - verbose_name_plural = _("contest submissions") + verbose_name = _('contest submission') + verbose_name_plural = _('contest submissions') class Rating(models.Model): - user = models.ForeignKey( - Profile, verbose_name=_("user"), related_name="ratings", on_delete=CASCADE - ) - contest = models.ForeignKey( - Contest, verbose_name=_("contest"), related_name="ratings", on_delete=CASCADE - ) - participation = models.OneToOneField( - ContestParticipation, - verbose_name=_("participation"), - related_name="rating", - on_delete=CASCADE, - ) - rank = models.IntegerField(verbose_name=_("rank")) - rating = models.IntegerField(verbose_name=_("rating")) - mean = models.FloatField(verbose_name=_("raw rating")) - performance = models.FloatField(verbose_name=_("contest performance")) - last_rated = models.DateTimeField(db_index=True, verbose_name=_("last rated")) + user = models.ForeignKey(Profile, verbose_name=_('user'), related_name='ratings', on_delete=CASCADE) + contest = models.ForeignKey(Contest, verbose_name=_('contest'), related_name='ratings', on_delete=CASCADE) + participation = models.OneToOneField(ContestParticipation, verbose_name=_('participation'), + related_name='rating', on_delete=CASCADE) + rank = models.IntegerField(verbose_name=_('rank')) + rating = models.IntegerField(verbose_name=_('rating')) + volatility = models.IntegerField(verbose_name=_('volatility')) + last_rated = models.DateTimeField(db_index=True, verbose_name=_('last rated')) class Meta: - unique_together = ("user", "contest") - verbose_name = _("contest rating") - verbose_name_plural = _("contest ratings") + unique_together = ('user', 'contest') + verbose_name = _('contest rating') + verbose_name_plural = _('contest ratings') class ContestMoss(models.Model): LANG_MAPPING = [ - ("C", MOSS_LANG_C), - ("C++", MOSS_LANG_CC), - ("Java", MOSS_LANG_JAVA), - ("Python", MOSS_LANG_PYTHON), - ("Pascal", MOSS_LANG_PASCAL), + ('C', MOSS_LANG_C), + ('C++', MOSS_LANG_CC), + ('Java', MOSS_LANG_JAVA), + ('Python', MOSS_LANG_PYTHON), ] - contest = models.ForeignKey( - Contest, verbose_name=_("contest"), related_name="moss", on_delete=CASCADE - ) - problem = models.ForeignKey( - Problem, verbose_name=_("problem"), related_name="moss", on_delete=CASCADE - ) + contest = models.ForeignKey(Contest, verbose_name=_('contest'), related_name='moss', on_delete=CASCADE) + problem = models.ForeignKey(Problem, verbose_name=_('problem'), related_name='moss', on_delete=CASCADE) language = models.CharField(max_length=10) submission_count = models.PositiveIntegerField(default=0) url = models.URLField(null=True, blank=True) class Meta: - unique_together = ("contest", "problem", "language") - verbose_name = _("contest moss result") - verbose_name_plural = _("contest moss results") - - -class ContestProblemClarification(models.Model): - problem = models.ForeignKey( - ContestProblem, verbose_name=_("clarified problem"), on_delete=CASCADE - ) - description = models.TextField(verbose_name=_("clarification body")) - date = models.DateTimeField( - verbose_name=_("clarification timestamp"), auto_now_add=True - ) - - -class ContestsSummary(models.Model): - contests = models.ManyToManyField( - Contest, - ) - scores = models.JSONField( - null=True, - blank=True, - ) - key = models.CharField( - max_length=20, - unique=True, - ) - results = models.JSONField(null=True, blank=True) - - class Meta: - verbose_name = _("contests summary") - verbose_name_plural = _("contests summaries") - - def __str__(self): - return self.key - - def get_absolute_url(self): - return reverse("contests_summary", args=[self.key]) - - -class OfficialContestCategory(models.Model): - name = models.CharField( - max_length=50, verbose_name=_("official contest category"), unique=True - ) - - def __str__(self): - return self.name - - class Meta: - verbose_name = _("official contest category") - verbose_name_plural = _("official contest categories") - - -class OfficialContestLocation(models.Model): - name = models.CharField( - max_length=50, verbose_name=_("official contest location"), unique=True - ) - - def __str__(self): - return self.name - - class Meta: - verbose_name = _("official contest location") - verbose_name_plural = _("official contest locations") - - -class OfficialContest(models.Model): - contest = models.OneToOneField( - Contest, - verbose_name=_("contest"), - related_name="official", - on_delete=CASCADE, - ) - category = models.ForeignKey( - OfficialContestCategory, - verbose_name=_("contest category"), - on_delete=CASCADE, - ) - year = models.PositiveIntegerField(verbose_name=_("year")) - location = models.ForeignKey( - OfficialContestLocation, - verbose_name=_("contest location"), - on_delete=CASCADE, - ) - - class Meta: - verbose_name = _("official contest") - verbose_name_plural = _("official contests") + unique_together = ('contest', 'problem', 'language') + verbose_name = _('contest moss result') + verbose_name_plural = _('contest moss results') diff --git a/judge/models/course.py b/judge/models/course.py deleted file mode 100644 index df4df21..0000000 --- a/judge/models/course.py +++ /dev/null @@ -1,201 +0,0 @@ -from django.core.validators import RegexValidator -from django.db import models -from django.utils.translation import gettext, gettext_lazy as _ -from django.urls import reverse -from django.db.models import Q - -from judge.models import BlogPost, Problem, Contest -from judge.models.profile import Organization, Profile - - -class RoleInCourse(models.TextChoices): - STUDENT = "ST", _("Student") - ASSISTANT = "AS", _("Assistant") - TEACHER = "TE", _("Teacher") - - -EDITABLE_ROLES = (RoleInCourse.TEACHER, RoleInCourse.ASSISTANT) - - -class Course(models.Model): - name = models.CharField( - max_length=128, - verbose_name=_("course name"), - ) - about = models.TextField(verbose_name=_("course description")) - is_public = models.BooleanField( - verbose_name=_("publicly visible"), - default=False, - ) - organizations = models.ManyToManyField( - Organization, - blank=True, - verbose_name=_("organizations"), - help_text=_("If private, only these organizations may see the course"), - ) - slug = models.SlugField( - max_length=128, - verbose_name=_("course slug"), - help_text=_("Course name shown in URL"), - unique=True, - validators=[ - RegexValidator("^[-a-zA-Z0-9]+$", _("Only alphanumeric and hyphens")) - ], - ) - is_open = models.BooleanField( - verbose_name=_("public registration"), - default=False, - ) - image_url = models.CharField( - verbose_name=_("course image"), - default="", - max_length=150, - blank=True, - ) - - def __str__(self): - return self.name - - def get_absolute_url(self): - return reverse("course_detail", args=(self.slug,)) - - @classmethod - def is_editable_by(cls, course, profile): - try: - course_role = CourseRole.objects.get(course=course, user=profile) - return course_role.role in EDITABLE_ROLES - except CourseRole.DoesNotExist: - return False - - @classmethod - def is_accessible_by(cls, course, profile): - if not profile: - return False - try: - course_role = CourseRole.objects.get(course=course, user=profile) - if course_role.course.is_public: - return True - return course_role.role in EDITABLE_ROLES - except CourseRole.DoesNotExist: - return False - - @classmethod - def get_accessible_courses(cls, profile): - return Course.objects.filter( - Q(is_public=True) | Q(courserole__role__in=EDITABLE_ROLES), - courserole__user=profile, - ).distinct() - - def _get_users_by_role(self, role): - course_roles = CourseRole.objects.filter(course=self, role=role).select_related( - "user" - ) - return [course_role.user for course_role in course_roles] - - def get_students(self): - return self._get_users_by_role(RoleInCourse.STUDENT) - - def get_assistants(self): - return self._get_users_by_role(RoleInCourse.ASSISTANT) - - def get_teachers(self): - return self._get_users_by_role(RoleInCourse.TEACHER) - - @classmethod - def add_student(cls, course, profiles): - for profile in profiles: - CourseRole.make_role(course=course, user=profile, role="ST") - - @classmethod - def add_teachers(cls, course, profiles): - for profile in profiles: - CourseRole.make_role(course=course, user=profile, role="TE") - - @classmethod - def add_assistants(cls, course, profiles): - for profile in profiles: - CourseRole.make_role(course=course, user=profile, role="AS") - - -class CourseRole(models.Model): - course = models.ForeignKey( - Course, - verbose_name=_("course"), - on_delete=models.CASCADE, - db_index=True, - ) - user = models.ForeignKey( - Profile, - verbose_name=_("user"), - on_delete=models.CASCADE, - related_name="course_roles", - ) - - role = models.CharField( - max_length=2, - choices=RoleInCourse.choices, - default=RoleInCourse.STUDENT, - ) - - @classmethod - def make_role(self, course, user, role): - userqueryset = CourseRole.objects.filter(course=course, user=user) - if userqueryset.exists(): - userqueryset[0].role = role - else: - couresrole = CourseRole() - couresrole.course = course - couresrole.user = user - couresrole.role = role - couresrole.save() - - class Meta: - unique_together = ("course", "user") - - -class CourseLesson(models.Model): - course = models.ForeignKey( - Course, - verbose_name=_("course"), - related_name="lessons", - on_delete=models.CASCADE, - ) - title = models.TextField(verbose_name=_("lesson title")) - content = models.TextField(verbose_name=_("lesson content")) - order = models.IntegerField(verbose_name=_("order"), default=0) - points = models.IntegerField(verbose_name=_("points")) - is_visible = models.BooleanField(verbose_name=_("publicly visible"), default=True) - - def get_absolute_url(self): - return reverse( - "course_lesson_detail", - args=( - self.course.slug, - self.id, - ), - ) - - -class CourseLessonProblem(models.Model): - lesson = models.ForeignKey( - CourseLesson, on_delete=models.CASCADE, related_name="lesson_problems" - ) - problem = models.ForeignKey(Problem, on_delete=models.CASCADE) - order = models.IntegerField(verbose_name=_("order"), default=0) - score = models.IntegerField(verbose_name=_("score"), default=0) - - -class CourseContest(models.Model): - course = models.ForeignKey( - Course, on_delete=models.CASCADE, related_name="contests" - ) - contest = models.ForeignKey( - Contest, unique=True, on_delete=models.CASCADE, related_name="course" - ) - order = models.IntegerField(verbose_name=_("order"), default=0) - points = models.IntegerField(verbose_name=_("points")) - - def get_course_of_contest(contest): - course_contest = contest.course.get() - course = course_contest.course - return course diff --git a/judge/models/interface.py b/judge/models/interface.py index d9c6e2c..ed25d63 100644 --- a/judge/models/interface.py +++ b/judge/models/interface.py @@ -5,17 +5,12 @@ from django.db import models from django.urls import reverse from django.utils import timezone from django.utils.translation import gettext_lazy as _ -from django.utils.functional import cached_property -from django.contrib.contenttypes.fields import GenericRelation from mptt.fields import TreeForeignKey from mptt.models import MPTTModel -from judge.models.profile import Organization, Profile -from judge.models.pagevote import PageVotable -from judge.models.bookmark import Bookmarkable -from judge.caching import cache_wrapper +from judge.models.profile import Profile -__all__ = ["MiscConfig", "validate_regex", "NavigationBar", "BlogPost"] +__all__ = ['MiscConfig', 'validate_regex', 'NavigationBar', 'BlogPost'] class MiscConfig(models.Model): @@ -26,40 +21,32 @@ class MiscConfig(models.Model): return self.key class Meta: - verbose_name = _("configuration item") - verbose_name_plural = _("miscellaneous configuration") + verbose_name = _('configuration item') + verbose_name_plural = _('miscellaneous configuration') def validate_regex(regex): try: re.compile(regex, re.VERBOSE) except re.error as e: - raise ValidationError("Invalid regex: %s" % e.message) + raise ValidationError('Invalid regex: %s' % e.message) class NavigationBar(MPTTModel): class Meta: - verbose_name = _("navigation item") - verbose_name_plural = _("navigation bar") + verbose_name = _('navigation item') + verbose_name_plural = _('navigation bar') class MPTTMeta: - order_insertion_by = ["order"] + order_insertion_by = ['order'] - order = models.PositiveIntegerField(db_index=True, verbose_name=_("order")) - key = models.CharField(max_length=10, unique=True, verbose_name=_("identifier")) - label = models.CharField(max_length=20, verbose_name=_("label")) - path = models.CharField(max_length=255, verbose_name=_("link path")) - regex = models.TextField( - verbose_name=_("highlight regex"), validators=[validate_regex] - ) - parent = TreeForeignKey( - "self", - verbose_name=_("parent item"), - null=True, - blank=True, - related_name="children", - on_delete=models.CASCADE, - ) + order = models.PositiveIntegerField(db_index=True, verbose_name=_('order')) + key = models.CharField(max_length=10, unique=True, verbose_name=_('identifier')) + label = models.CharField(max_length=20, verbose_name=_('label')) + path = models.CharField(max_length=255, verbose_name=_('link path')) + regex = models.TextField(verbose_name=_('highlight regex'), validators=[validate_regex]) + parent = TreeForeignKey('self', verbose_name=_('parent item'), null=True, blank=True, + related_name='children', on_delete=models.CASCADE) def __str__(self): return self.label @@ -75,69 +62,33 @@ class NavigationBar(MPTTModel): return pattern -class BlogPost(models.Model, PageVotable, Bookmarkable): - title = models.CharField(verbose_name=_("post title"), max_length=100) - authors = models.ManyToManyField(Profile, verbose_name=_("authors"), blank=True) - slug = models.SlugField(verbose_name=_("slug")) - visible = models.BooleanField(verbose_name=_("public visibility"), default=False) - sticky = models.BooleanField(verbose_name=_("sticky"), default=False) - publish_on = models.DateTimeField(verbose_name=_("publish after")) - content = models.TextField(verbose_name=_("post content")) - summary = models.TextField(verbose_name=_("post summary"), blank=True) - og_image = models.CharField( - verbose_name=_("openGraph image"), default="", max_length=150, blank=True - ) - organizations = models.ManyToManyField( - Organization, - blank=True, - verbose_name=_("organizations"), - help_text=_("If private, only these organizations may see the blog post."), - ) - is_organization_private = models.BooleanField( - verbose_name=_("private to organizations"), default=False - ) - comments = GenericRelation("Comment") - pagevote = GenericRelation("PageVote") - bookmark = GenericRelation("BookMark") +class BlogPost(models.Model): + title = models.CharField(verbose_name=_('post title'), max_length=100) + authors = models.ManyToManyField(Profile, verbose_name=_('authors'), blank=True) + slug = models.SlugField(verbose_name=_('slug')) + visible = models.BooleanField(verbose_name=_('public visibility'), default=False) + sticky = models.BooleanField(verbose_name=_('sticky'), default=False) + publish_on = models.DateTimeField(verbose_name=_('publish after')) + content = models.TextField(verbose_name=_('post content')) + summary = models.TextField(verbose_name=_('post summary'), blank=True) + og_image = models.CharField(verbose_name=_('openGraph image'), default='', max_length=150, blank=True) def __str__(self): return self.title def get_absolute_url(self): - return reverse("blog_post", args=(self.id, self.slug)) + return reverse('blog_post', args=(self.id, self.slug)) - def is_accessible_by(self, user): + def can_see(self, user): if self.visible and self.publish_on <= timezone.now(): - if not self.is_organization_private: - return True - if ( - user.is_authenticated - and self.organizations.filter( - id__in=user.profile.organizations.all() - ).exists() - ): - return True - if user.has_perm("judge.edit_all_post"): return True - return ( - user.is_authenticated and self.authors.filter(id=user.profile.id).exists() - ) - - def is_editable_by(self, user): - if not user.is_authenticated: - return False - if user.has_perm("judge.edit_all_post"): + if user.has_perm('judge.edit_all_post'): return True - return ( - user.has_perm("judge.change_blogpost") - and self.authors.filter(id=user.profile.id).exists() - ) - - @cache_wrapper(prefix="BPga", expected_type=models.query.QuerySet) - def get_authors(self): - return self.authors.only("id") + return user.is_authenticated and self.authors.filter(id=user.profile.id).exists() class Meta: - permissions = (("edit_all_post", _("Edit all posts")),) - verbose_name = _("blog post") - verbose_name_plural = _("blog posts") + permissions = ( + ('edit_all_post', _('Edit all posts')), + ) + verbose_name = _('blog post') + verbose_name_plural = _('blog posts') diff --git a/judge/models/message.py b/judge/models/message.py index c2e8291..541d63f 100644 --- a/judge/models/message.py +++ b/judge/models/message.py @@ -4,31 +4,17 @@ from django.utils.translation import gettext_lazy as _ from judge.models.profile import Profile -__all__ = ["PrivateMessage", "PrivateMessageThread"] +__all__ = ['PrivateMessage', 'PrivateMessageThread'] class PrivateMessage(models.Model): - title = models.CharField(verbose_name=_("message title"), max_length=50) - content = models.TextField(verbose_name=_("message body")) - sender = models.ForeignKey( - Profile, - verbose_name=_("sender"), - related_name="sent_messages", - on_delete=CASCADE, - ) - target = models.ForeignKey( - Profile, - verbose_name=_("target"), - related_name="received_messages", - on_delete=CASCADE, - ) - timestamp = models.DateTimeField( - verbose_name=_("message timestamp"), auto_now_add=True - ) - read = models.BooleanField(verbose_name=_("read"), default=False) + title = models.CharField(verbose_name=_('message title'), max_length=50) + content = models.TextField(verbose_name=_('message body')) + sender = models.ForeignKey(Profile, verbose_name=_('sender'), related_name='sent_messages', on_delete=CASCADE) + target = models.ForeignKey(Profile, verbose_name=_('target'), related_name='received_messages', on_delete=CASCADE) + timestamp = models.DateTimeField(verbose_name=_('message timestamp'), auto_now_add=True) + read = models.BooleanField(verbose_name=_('read'), default=False) class PrivateMessageThread(models.Model): - messages = models.ManyToManyField( - PrivateMessage, verbose_name=_("messages in the thread") - ) + messages = models.ManyToManyField(PrivateMessage, verbose_name=_('messages in the thread')) diff --git a/judge/models/notification.py b/judge/models/notification.py deleted file mode 100644 index f5f40a6..0000000 --- a/judge/models/notification.py +++ /dev/null @@ -1,94 +0,0 @@ -from django.db import models -from django.utils.translation import gettext_lazy as _ -from django.db.models import CASCADE, F -from django.core.exceptions import ObjectDoesNotExist - -from judge.models import Profile, Comment -from judge.caching import cache_wrapper - - -category_to_verbose_message = { - "Add blog": _("Added a post"), - "Added to group": _("You are added to a group"), - "Comment": _("You have a new comment"), - "Delete blog": _("Deleted a post"), - "Reject blog": _("Rejected a post"), - "Approve blog": _("Approved a post"), - "Edit blog": _("Edited a post"), - "Mention": _("Mentioned you"), - "Reply": _("Replied you"), - "Ticket": _("Ticket"), -} - - -class Notification(models.Model): - owner = models.ForeignKey( - Profile, - verbose_name=_("owner"), - related_name="notifications", - on_delete=CASCADE, - ) - time = models.DateTimeField(verbose_name=_("posted time"), auto_now_add=True) - category = models.CharField(verbose_name=_("category"), max_length=1000) - html_link = models.TextField( - default="", - verbose_name=_("html link to comments, used for non-comments"), - max_length=1000, - ) - author = models.ForeignKey( - Profile, - null=True, - verbose_name=_("who trigger, used for non-comment"), - on_delete=CASCADE, - ) - - def verbose_activity(self): - if self.category in category_to_verbose_message: - return category_to_verbose_message[self.category] - - if "Problem public" in self.category: - is_public = "True" in self.category - if "(" in self.category and ")" in self.category: - groups = self.category.split("(", 1)[1].strip(")") - if is_public: - verbose_message = _("The problem is public to: ") + groups - else: - verbose_message = _("The problem is private to: ") + groups - else: - verbose_message = ( - _("The problem is public to everyone.") - if is_public - else _("The problem is private.") - ) - - return verbose_message - - return self.category - - -class NotificationProfile(models.Model): - unread_count = models.IntegerField(default=0) - user = models.OneToOneField(Profile, on_delete=CASCADE) - - -def make_notification(to_users, category, html_link, author): - for user in to_users: - if user == author: - continue - notif = Notification( - owner=user, category=category, html_link=html_link, author=author - ) - notif.save() - NotificationProfile.objects.get_or_create(user=user) - NotificationProfile.objects.filter(user=user).update( - unread_count=F("unread_count") + 1 - ) - unseen_notifications_count.dirty(user) - - -@cache_wrapper(prefix="unc") -def unseen_notifications_count(profile): - try: - return NotificationProfile.objects.get(user=profile).unread_count - except ObjectDoesNotExist: - return 0 diff --git a/judge/models/pagevote.py b/judge/models/pagevote.py deleted file mode 100644 index bc0224e..0000000 --- a/judge/models/pagevote.py +++ /dev/null @@ -1,70 +0,0 @@ -from django.db import models -from django.db.models import CASCADE -from django.utils.translation import gettext_lazy as _ -from django.contrib.contenttypes.fields import GenericForeignKey -from django.contrib.contenttypes.models import ContentType - -from judge.models.profile import Profile -from judge.caching import cache_wrapper - -__all__ = ["PageVote", "PageVoteVoter"] - - -class PageVote(models.Model): - page = models.CharField( - max_length=30, - verbose_name=_("associated page"), - db_index=True, - ) # deprecated - score = models.IntegerField(verbose_name=_("votes"), default=0) - content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) - object_id = models.PositiveIntegerField() - linked_object = GenericForeignKey("content_type", "object_id") - - class Meta: - verbose_name = _("pagevote") - verbose_name_plural = _("pagevotes") - indexes = [ - models.Index(fields=["content_type", "object_id"]), - ] - unique_together = ("content_type", "object_id") - - @cache_wrapper(prefix="PVvs") - def vote_score(self, user): - page_vote = PageVoteVoter.objects.filter(pagevote=self, voter=user).first() - return page_vote.score if page_vote else 0 - - def __str__(self): - return f"pagevote for {self.linked_object}" - - -class PageVoteVoter(models.Model): - voter = models.ForeignKey(Profile, related_name="voted_page", on_delete=CASCADE) - pagevote = models.ForeignKey(PageVote, related_name="votes", on_delete=CASCADE) - score = models.IntegerField() - - class Meta: - unique_together = ["voter", "pagevote"] - verbose_name = _("pagevote vote") - verbose_name_plural = _("pagevote votes") - - -@cache_wrapper(prefix="gocp", expected_type=PageVote) -def _get_or_create_pagevote(content_type, object_id): - pagevote, created = PageVote.objects.get_or_create( - content_type=content_type, - object_id=object_id, - ) - return pagevote - - -class PageVotable: - def get_or_create_pagevote(self): - content_type = ContentType.objects.get_for_model(self) - object_id = self.pk - return _get_or_create_pagevote(content_type, object_id) - - -def dirty_pagevote(pagevote, profile): - pagevote.vote_score.dirty(pagevote, profile) - _get_or_create_pagevote.dirty(pagevote.content_type, pagevote.object_id) diff --git a/judge/models/problem.py b/judge/models/problem.py index 8114fb7..a469ef6 100644 --- a/judge/models/problem.py +++ b/judge/models/problem.py @@ -1,4 +1,3 @@ -import errno from operator import attrgetter from django.conf import settings @@ -6,291 +5,156 @@ from django.contrib.contenttypes.fields import GenericRelation from django.core.cache import cache from django.core.validators import MaxValueValidator, MinValueValidator, RegexValidator from django.db import models -from django.db.models import CASCADE, F, FilteredRelation, Q, SET_NULL, Exists, OuterRef +from django.db.models import CASCADE, F, QuerySet, SET_NULL +from django.db.models.expressions import RawSQL from django.db.models.functions import Coalesce from django.urls import reverse from django.utils.functional import cached_property from django.utils.translation import gettext_lazy as _ -from django.db.models.signals import m2m_changed -from django.dispatch import receiver from judge.fulltext import SearchQuerySet -from judge.models.pagevote import PageVotable -from judge.models.bookmark import Bookmarkable from judge.models.profile import Organization, Profile from judge.models.runtime import Language from judge.user_translations import gettext as user_gettext -from judge.models.problem_data import ( - problem_data_storage, - problem_directory_file_helper, -) -from judge.caching import cache_wrapper +from judge.utils.raw_sql import RawSQLColumn, unique_together_left_join -__all__ = [ - "ProblemGroup", - "ProblemType", - "Problem", - "ProblemTranslation", - "License", - "Solution", - "TranslatedProblemQuerySet", -] - - -def problem_directory_file(data, filename): - return problem_directory_file_helper(data.code, filename) +__all__ = ['ProblemGroup', 'ProblemType', 'Problem', 'ProblemTranslation', 'ProblemClarification', + 'License', 'Solution', 'TranslatedProblemQuerySet', 'TranslatedProblemForeignKeyQuerySet'] class ProblemType(models.Model): - name = models.CharField( - max_length=20, verbose_name=_("problem category ID"), unique=True - ) - full_name = models.CharField( - max_length=100, verbose_name=_("problem category name") - ) + name = models.CharField(max_length=20, verbose_name=_('problem category ID'), unique=True) + full_name = models.CharField(max_length=100, verbose_name=_('problem category name')) def __str__(self): return self.full_name class Meta: - ordering = ["full_name"] - verbose_name = _("problem type") - verbose_name_plural = _("problem types") + ordering = ['full_name'] + verbose_name = _('problem type') + verbose_name_plural = _('problem types') class ProblemGroup(models.Model): - name = models.CharField( - max_length=20, verbose_name=_("problem group ID"), unique=True - ) - full_name = models.CharField(max_length=100, verbose_name=_("problem group name")) + name = models.CharField(max_length=20, verbose_name=_('problem group ID'), unique=True) + full_name = models.CharField(max_length=100, verbose_name=_('problem group name')) def __str__(self): return self.full_name class Meta: - ordering = ["full_name"] - verbose_name = _("problem group") - verbose_name_plural = _("problem groups") + ordering = ['full_name'] + verbose_name = _('problem group') + verbose_name_plural = _('problem groups') class License(models.Model): - key = models.CharField( - max_length=20, - unique=True, - verbose_name=_("key"), - validators=[RegexValidator(r"^[-\w.]+$", r"License key must be ^[-\w.]+$")], - ) - link = models.CharField(max_length=256, verbose_name=_("link")) - name = models.CharField(max_length=256, verbose_name=_("full name")) - display = models.CharField( - max_length=256, - blank=True, - verbose_name=_("short name"), - help_text=_("Displayed on pages under this license"), - ) - icon = models.CharField( - max_length=256, - blank=True, - verbose_name=_("icon"), - help_text=_("URL to the icon"), - ) - text = models.TextField(verbose_name=_("license text")) + key = models.CharField(max_length=20, unique=True, verbose_name=_('key'), + validators=[RegexValidator(r'^[-\w.]+$', r'License key must be ^[-\w.]+$')]) + link = models.CharField(max_length=256, verbose_name=_('link')) + name = models.CharField(max_length=256, verbose_name=_('full name')) + display = models.CharField(max_length=256, blank=True, verbose_name=_('short name'), + help_text=_('Displayed on pages under this license')) + icon = models.CharField(max_length=256, blank=True, verbose_name=_('icon'), help_text=_('URL to the icon')) + text = models.TextField(verbose_name=_('license text')) def __str__(self): return self.name def get_absolute_url(self): - return reverse("license", args=(self.key,)) + return reverse('license', args=(self.key,)) class Meta: - verbose_name = _("license") - verbose_name_plural = _("licenses") + verbose_name = _('license') + verbose_name_plural = _('licenses') class TranslatedProblemQuerySet(SearchQuerySet): def __init__(self, **kwargs): - super(TranslatedProblemQuerySet, self).__init__(("code", "name"), **kwargs) + super(TranslatedProblemQuerySet, self).__init__(('code', 'name', 'description'), **kwargs) def add_i18n_name(self, language): - return self.annotate( - i18n_translation=FilteredRelation( - "translations", - condition=Q(translations__language=language), - ) - ).annotate( - i18n_name=Coalesce( - F("i18n_translation__name"), F("name"), output_field=models.CharField() - ) - ) + queryset = self._clone() + alias = unique_together_left_join(queryset, ProblemTranslation, 'problem', 'language', language) + return queryset.annotate(i18n_name=Coalesce(RawSQL('%s.name' % alias, ()), F('name'), + output_field=models.CharField())) -class Problem(models.Model, PageVotable, Bookmarkable): - code = models.CharField( - max_length=20, - verbose_name=_("problem code"), - unique=True, - validators=[ - RegexValidator("^[a-z0-9]+$", _("Problem code must be ^[a-z0-9]+$")) - ], - help_text=_( - "A short, unique code for the problem, " "used in the url after /problem/" - ), - ) - name = models.CharField( - max_length=100, - verbose_name=_("problem name"), - db_index=True, - help_text=_("The full name of the problem, " "as shown in the problem list."), - ) - description = models.TextField(verbose_name=_("problem body"), blank=True) - authors = models.ManyToManyField( - Profile, - verbose_name=_("creators"), - blank=True, - related_name="authored_problems", - help_text=_( - "These users will be able to edit the problem, " "and be listed as authors." - ), - ) - curators = models.ManyToManyField( - Profile, - verbose_name=_("curators"), - blank=True, - related_name="curated_problems", - help_text=_( - "These users will be able to edit the problem, " - "but not be listed as authors." - ), - ) - testers = models.ManyToManyField( - Profile, - verbose_name=_("testers"), - blank=True, - related_name="tested_problems", - help_text=_( - "These users will be able to view the private problem, but not edit it." - ), - ) - types = models.ManyToManyField( - ProblemType, - verbose_name=_("problem types"), - help_text=_("The type of problem, " "as shown on the problem's page."), - ) - group = models.ForeignKey( - ProblemGroup, - verbose_name=_("problem group"), - on_delete=CASCADE, - help_text=_("The group of problem, shown under Category in the problem list."), - ) - time_limit = models.FloatField( - verbose_name=_("time limit"), - help_text=_( - "The time limit for this problem, in seconds. " - "Fractional seconds (e.g. 1.5) are supported." - ), - validators=[ - MinValueValidator(settings.DMOJ_PROBLEM_MIN_TIME_LIMIT), - MaxValueValidator(settings.DMOJ_PROBLEM_MAX_TIME_LIMIT), - ], - ) - memory_limit = models.PositiveIntegerField( - verbose_name=_("memory limit"), - help_text=_( - "The memory limit for this problem, in kilobytes " - "(e.g. 256mb = 262144 kilobytes)." - ), - validators=[ - MinValueValidator(settings.DMOJ_PROBLEM_MIN_MEMORY_LIMIT), - MaxValueValidator(settings.DMOJ_PROBLEM_MAX_MEMORY_LIMIT), - ], - ) +class TranslatedProblemForeignKeyQuerySet(QuerySet): + def add_problem_i18n_name(self, key, language, name_field=None): + queryset = self._clone() if name_field is None else self.annotate(_name=F(name_field)) + alias = unique_together_left_join(queryset, ProblemTranslation, 'problem', 'language', language, + parent_model=Problem) + # You must specify name_field if Problem is not yet joined into the QuerySet. + kwargs = {key: Coalesce(RawSQL('%s.name' % alias, ()), + F(name_field) if name_field else RawSQLColumn(Problem, 'name'), + output_field=models.CharField())} + return queryset.annotate(**kwargs) + + +class Problem(models.Model): + code = models.CharField(max_length=20, verbose_name=_('problem code'), unique=True, + validators=[RegexValidator('^[a-z0-9]+$', _('Problem code must be ^[a-z0-9]+$'))], + help_text=_('A short, unique code for the problem, ' + 'used in the url after /problem/')) + name = models.CharField(max_length=100, verbose_name=_('problem name'), db_index=True, + help_text=_('The full name of the problem, ' + 'as shown in the problem list.')) + description = models.TextField(verbose_name=_('problem body')) + authors = models.ManyToManyField(Profile, verbose_name=_('creators'), blank=True, related_name='authored_problems', + help_text=_('These users will be able to edit the problem, ' + 'and be listed as authors.')) + curators = models.ManyToManyField(Profile, verbose_name=_('curators'), blank=True, related_name='curated_problems', + help_text=_('These users will be able to edit the problem, ' + 'but not be listed as authors.')) + testers = models.ManyToManyField(Profile, verbose_name=_('testers'), blank=True, related_name='tested_problems', + help_text=_( + 'These users will be able to view the private problem, but not edit it.')) + types = models.ManyToManyField(ProblemType, verbose_name=_('problem types'), + help_text=_('The type of problem, ' + "as shown on the problem's page.")) + group = models.ForeignKey(ProblemGroup, verbose_name=_('problem group'), on_delete=CASCADE, + help_text=_('The group of problem, shown under Category in the problem list.')) + time_limit = models.FloatField(verbose_name=_('time limit'), + help_text=_('The time limit for this problem, in seconds. ' + 'Fractional seconds (e.g. 1.5) are supported.'), + validators=[MinValueValidator(settings.DMOJ_PROBLEM_MIN_TIME_LIMIT), + MaxValueValidator(settings.DMOJ_PROBLEM_MAX_TIME_LIMIT)]) + memory_limit = models.PositiveIntegerField(verbose_name=_('memory limit'), + help_text=_('The memory limit for this problem, in kilobytes ' + '(e.g. 64mb = 65536 kilobytes).'), + validators=[MinValueValidator(settings.DMOJ_PROBLEM_MIN_MEMORY_LIMIT), + MaxValueValidator(settings.DMOJ_PROBLEM_MAX_MEMORY_LIMIT)]) short_circuit = models.BooleanField(default=False) - points = models.FloatField( - verbose_name=_("points"), - help_text=_( - "Points awarded for problem completion. " - "Points are displayed with a 'p' suffix if partial." - ), - validators=[MinValueValidator(settings.DMOJ_PROBLEM_MIN_PROBLEM_POINTS)], - ) - partial = models.BooleanField( - verbose_name=_("allows partial points"), default=False - ) - allowed_languages = models.ManyToManyField( - Language, - verbose_name=_("allowed languages"), - help_text=_("List of allowed submission languages."), - ) - is_public = models.BooleanField( - verbose_name=_("publicly visible"), db_index=True, default=False - ) - is_manually_managed = models.BooleanField( - verbose_name=_("manually managed"), - db_index=True, - default=False, - help_text=_("Whether judges should be allowed to manage data or not."), - ) - date = models.DateTimeField( - verbose_name=_("date of publishing"), - null=True, - blank=True, - db_index=True, - help_text=_( - "Doesn't have magic ability to auto-publish due to backward compatibility" - ), - ) - banned_users = models.ManyToManyField( - Profile, - verbose_name=_("personae non gratae"), - blank=True, - help_text=_("Bans the selected users from submitting to this problem."), - ) - license = models.ForeignKey( - License, - null=True, - blank=True, - on_delete=SET_NULL, - help_text=_("The license under which this problem is published."), - ) - og_image = models.CharField( - verbose_name=_("OpenGraph image"), max_length=150, blank=True - ) - summary = models.TextField( - blank=True, - verbose_name=_("problem summary"), - help_text=_( - "Plain-text, shown in meta description tag, e.g. for social media." - ), - ) - user_count = models.IntegerField( - verbose_name=_("number of users"), - default=0, - help_text=_("The number of users who solved the problem."), - ) - ac_rate = models.FloatField(verbose_name=_("solve rate"), default=0) + points = models.FloatField(verbose_name=_('points'), + help_text=_('Points awarded for problem completion. ' + "Points are displayed with a 'p' suffix if partial."), + validators=[MinValueValidator(settings.DMOJ_PROBLEM_MIN_PROBLEM_POINTS)]) + partial = models.BooleanField(verbose_name=_('allows partial points'), default=False) + allowed_languages = models.ManyToManyField(Language, verbose_name=_('allowed languages'), + help_text=_('List of allowed submission languages.')) + is_public = models.BooleanField(verbose_name=_('publicly visible'), db_index=True, default=False) + is_manually_managed = models.BooleanField(verbose_name=_('manually managed'), db_index=True, default=False, + help_text=_('Whether judges should be allowed to manage data or not.')) + date = models.DateTimeField(verbose_name=_('date of publishing'), null=True, blank=True, db_index=True, + help_text=_("Doesn't have magic ability to auto-publish due to backward compatibility")) + banned_users = models.ManyToManyField(Profile, verbose_name=_('personae non gratae'), blank=True, + help_text=_('Bans the selected users from submitting to this problem.')) + license = models.ForeignKey(License, null=True, blank=True, on_delete=SET_NULL, + help_text=_('The license under which this problem is published.')) + og_image = models.CharField(verbose_name=_('OpenGraph image'), max_length=150, blank=True) + summary = models.TextField(blank=True, verbose_name=_('problem summary'), + help_text=_('Plain-text, shown in meta description tag, e.g. for social media.')) + user_count = models.IntegerField(verbose_name=_('number of users'), default=0, + help_text=_('The number of users who solved the problem.')) + ac_rate = models.FloatField(verbose_name=_('solve rate'), default=0) objects = TranslatedProblemQuerySet.as_manager() - tickets = GenericRelation("Ticket") - comments = GenericRelation("Comment") - pagevote = GenericRelation("PageVote") - bookmark = GenericRelation("BookMark") + tickets = GenericRelation('Ticket') - organizations = models.ManyToManyField( - Organization, - blank=True, - verbose_name=_("organizations"), - help_text=_("If private, only these organizations may see the problem."), - ) - is_organization_private = models.BooleanField( - verbose_name=_("private to organizations"), default=False - ) - pdf_description = models.FileField( - verbose_name=_("pdf statement"), - storage=problem_data_storage, - null=True, - blank=True, - upload_to=problem_directory_file, - ) + organizations = models.ManyToManyField(Organization, blank=True, verbose_name=_('organizations'), + help_text=_('If private, only these organizations may see the problem.')) + is_organization_private = models.BooleanField(verbose_name=_('private to organizations'), default=False) def __init__(self, *args, **kwargs): super(Problem, self).__init__(*args, **kwargs) @@ -300,32 +164,22 @@ class Problem(models.Model, PageVotable, Bookmarkable): @cached_property def types_list(self): - return list(map(user_gettext, map(attrgetter("full_name"), self.types.all()))) + return list(map(user_gettext, map(attrgetter('full_name'), self.types.all()))) def languages_list(self): - return ( - self.allowed_languages.values_list("common_name", flat=True) - .distinct() - .order_by("common_name") - ) + return self.allowed_languages.values_list('common_name', flat=True).distinct().order_by('common_name') def is_editor(self, profile): - return ( - self.authors.filter(id=profile.id) | self.curators.filter(id=profile.id) - ).exists() + return (self.authors.filter(id=profile.id) | self.curators.filter(id=profile.id)).exists() def is_editable_by(self, user): if not user.is_authenticated: return False - if ( - user.has_perm("judge.edit_all_problem") - or user.has_perm("judge.edit_public_problem") - and self.is_public - ): + if user.has_perm('judge.edit_all_problem') or user.has_perm('judge.edit_public_problem') and self.is_public: return True - return user.has_perm("judge.edit_own_problem") and self.is_editor(user.profile) + return user.has_perm('judge.edit_own_problem') and self.is_editor(user.profile) - def is_accessible_by(self, user, in_contest_mode=True): + def is_accessible_by(self, user): # Problem is public. if self.is_public: # Problem is not private to an organization. @@ -333,24 +187,23 @@ class Problem(models.Model, PageVotable, Bookmarkable): return True # If the user can see all organization private problems. - if user.has_perm("judge.see_organization_problem"): + if user.has_perm('judge.see_organization_problem'): return True # If the user is in the organization. - if user.is_authenticated and self.organizations.filter( - id__in=user.profile.organizations.all() - ): + if user.is_authenticated and \ + self.organizations.filter(id__in=user.profile.organizations.all()): return True # If the user can view all problems. - if user.has_perm("judge.see_private_problem"): + if user.has_perm('judge.see_private_problem'): return True if not user.is_authenticated: return False # If the user authored the problem or is a curator. - if user.has_perm("judge.edit_own_problem") and self.is_editor(user.profile): + if user.has_perm('judge.edit_own_problem') and self.is_editor(user.profile): return True # If user is a tester. @@ -359,123 +212,46 @@ class Problem(models.Model, PageVotable, Bookmarkable): # If user is currently in a contest containing that problem. current = user.profile.current_contest_id - if not in_contest_mode or current is None: + if current is None: return False from judge.models import ContestProblem - - return ContestProblem.objects.filter( - problem_id=self.id, contest__users__id=current - ).exists() + return ContestProblem.objects.filter(problem_id=self.id, contest__users__id=current).exists() def is_subs_manageable_by(self, user): - return ( - user.is_staff - and user.has_perm("judge.rejudge_submission") - and self.is_editable_by(user) - ) - - @classmethod - def get_visible_problems(cls, user, profile=None): - # Do unauthenticated check here so we can skip authentication checks later on. - if not user.is_authenticated or not user: - return cls.get_public_problems() - - # Conditions for visible problem: - # - `judge.edit_all_problem` or `judge.see_private_problem` - # - otherwise - # - not is_public problems - # - author or curator or tester - # - is_public problems - # - not is_organization_private or in organization or `judge.see_organization_problem` - # - author or curator or tester - queryset = cls.objects.defer("description") - profile = profile or user.profile - if not ( - user.has_perm("judge.see_private_problem") - or user.has_perm("judge.edit_all_problem") - ): - q = Q(is_public=True) - if not user.has_perm("judge.see_organization_problem"): - # Either not organization private or in the organization. - q &= Q(is_organization_private=False) | Q( - is_organization_private=True, - organizations__in=profile.organizations.all(), - ) - - # Authors, curators, and testers should always have access, so OR at the very end. - q |= Exists( - Problem.authors.through.objects.filter( - problem=OuterRef("pk"), profile=profile - ) - ) - q |= Exists( - Problem.curators.through.objects.filter( - problem=OuterRef("pk"), profile=profile - ) - ) - q |= Exists( - Problem.testers.through.objects.filter( - problem=OuterRef("pk"), profile=profile - ) - ) - queryset = queryset.filter(q) - - return queryset - - @classmethod - def get_public_problems(cls): - return cls.objects.filter(is_public=True, is_organization_private=False).defer( - "description" - ) + return user.is_staff and user.has_perm('judge.rejudge_submission') and self.is_editable_by(user) def __str__(self): - return "%s (%s)" % (self.name, self.code) + return self.name def get_absolute_url(self): - return reverse("problem_detail", args=(self.code,)) + return reverse('problem_detail', args=(self.code,)) @cached_property def author_ids(self): - return Problem.authors.through.objects.filter(problem=self).values_list( - "profile_id", flat=True - ) - - @cache_wrapper(prefix="Pga", expected_type=models.query.QuerySet) - def get_authors(self): - return self.authors.only("id") + return self.authors.values_list('id', flat=True) @cached_property def editor_ids(self): - return self.author_ids.union( - Problem.curators.through.objects.filter(problem=self).values_list( - "profile_id", flat=True - ) - ) + return self.author_ids | self.curators.values_list('id', flat=True) @cached_property def tester_ids(self): - return Problem.testers.through.objects.filter(problem=self).values_list( - "profile_id", flat=True - ) + return self.testers.values_list('id', flat=True) @cached_property def usable_common_names(self): - return set(self.usable_languages.values_list("common_name", flat=True)) + return set(self.usable_languages.values_list('common_name', flat=True)) @property def usable_languages(self): - return self.allowed_languages.filter( - judges__in=self.judges.filter(online=True) - ).distinct() + return self.allowed_languages.filter(judges__in=self.judges.filter(online=True)).distinct() def translated_name(self, language): if language in self._translated_name_cache: return self._translated_name_cache[language] # Hits database despite prefetch_related. try: - name = self.translations.filter(language=language).values_list( - "name", flat=True - )[0] + name = self.translations.filter(language=language).values_list('name', flat=True)[0] except IndexError: name = self.name self._translated_name_cache[language] = name @@ -491,24 +267,17 @@ class Problem(models.Model, PageVotable, Bookmarkable): def i18n_name(self, value): self._i18n_name = value + @property + def clarifications(self): + return ProblemClarification.objects.filter(problem=self) + def update_stats(self): - self.user_count = ( - self.submission_set.filter( - points__gte=self.points, result="AC", user__is_unlisted=False - ) - .values("user") - .distinct() - .count() - ) + self.user_count = self.submission_set.filter(points__gte=self.points, result='AC', + user__is_unlisted=False).values('user').distinct().count() submissions = self.submission_set.count() if submissions: - self.ac_rate = ( - 100.0 - * self.submission_set.filter( - points__gte=self.points, result="AC", user__is_unlisted=False - ).count() - / submissions - ) + self.ac_rate = 100.0 * self.submission_set.filter(points__gte=self.points, result='AC', + user__is_unlisted=False).count() / submissions else: self.ac_rate = 0 self.save() @@ -517,13 +286,9 @@ class Problem(models.Model, PageVotable, Bookmarkable): def _get_limits(self, key): global_limit = getattr(self, key) - limits = { - limit["language_id"]: (limit["language__name"], limit[key]) - for limit in self.language_limits.values( - "language_id", "language__name", key - ) - if limit[key] != global_limit - } + limits = {limit['language_id']: (limit['language__name'], limit[key]) + for limit in self.language_limits.values('language_id', 'language__name', key) + if limit[key] != global_limit} limit_ids = set(limits.keys()) common = [] @@ -543,212 +308,106 @@ class Problem(models.Model, PageVotable, Bookmarkable): @property def language_time_limit(self): - key = "problem_tls:%d" % self.id + key = 'problem_tls:%d' % self.id result = cache.get(key) if result is not None: return result - result = self._get_limits("time_limit") + result = self._get_limits('time_limit') cache.set(key, result) return result @property def language_memory_limit(self): - key = "problem_mls:%d" % self.id + key = 'problem_mls:%d' % self.id result = cache.get(key) if result is not None: return result - result = self._get_limits("memory_limit") + result = self._get_limits('memory_limit') cache.set(key, result) return result - def handle_code_change(self): - has_data = hasattr(self, "data_files") - has_pdf = bool(self.pdf_description) - if not has_data and not has_pdf: - return - - try: - problem_data_storage.rename(self.__original_code, self.code) - except OSError as e: - if e.errno != errno.ENOENT: - raise - - if has_pdf: - self.pdf_description.name = problem_directory_file_helper( - self.code, self.pdf_description.name - ) - super().save(update_fields=["pdf_description"]) - - if has_data: - self.data_files._update_code(self.__original_code, self.code) - - def save(self, should_move_data=True, *args, **kwargs): - code_changed = self.__original_code and self.code != self.__original_code + def save(self, *args, **kwargs): super(Problem, self).save(*args, **kwargs) - if code_changed and should_move_data: - self.handle_code_change() - - def delete(self, *args, **kwargs): - super().delete(*args, **kwargs) - problem_data_storage.delete_directory(self.code) + if self.code != self.__original_code: + try: + problem_data = self.data_files + except AttributeError: + pass + else: + problem_data._update_code(self.__original_code, self.code) save.alters_data = True class Meta: permissions = ( - ("see_private_problem", "See hidden problems"), - ("edit_own_problem", "Edit own problems"), - ("edit_all_problem", "Edit all problems"), - ("edit_public_problem", "Edit all public problems"), - ("clone_problem", "Clone problem"), - ("change_public_visibility", "Change is_public field"), - ("change_manually_managed", "Change is_manually_managed field"), - ("see_organization_problem", "See organization-private problems"), - ("suggest_problem_changes", "Suggest changes to problem"), + ('see_private_problem', 'See hidden problems'), + ('edit_own_problem', 'Edit own problems'), + ('edit_all_problem', 'Edit all problems'), + ('edit_public_problem', 'Edit all public problems'), + ('clone_problem', 'Clone problem'), + ('change_public_visibility', 'Change is_public field'), + ('change_manually_managed', 'Change is_manually_managed field'), + ('see_organization_problem', 'See organization-private problems'), ) - verbose_name = _("problem") - verbose_name_plural = _("problems") + verbose_name = _('problem') + verbose_name_plural = _('problems') class ProblemTranslation(models.Model): - problem = models.ForeignKey( - Problem, - verbose_name=_("problem"), - related_name="translations", - on_delete=CASCADE, - ) - language = models.CharField( - verbose_name=_("language"), max_length=7, choices=settings.LANGUAGES - ) - name = models.CharField( - verbose_name=_("translated name"), max_length=100, db_index=True - ) - description = models.TextField(verbose_name=_("translated description")) + problem = models.ForeignKey(Problem, verbose_name=_('problem'), related_name='translations', on_delete=CASCADE) + language = models.CharField(verbose_name=_('language'), max_length=7, choices=settings.LANGUAGES) + name = models.CharField(verbose_name=_('translated name'), max_length=100, db_index=True) + description = models.TextField(verbose_name=_('translated description')) class Meta: - unique_together = ("problem", "language") - verbose_name = _("problem translation") - verbose_name_plural = _("problem translations") + unique_together = ('problem', 'language') + verbose_name = _('problem translation') + verbose_name_plural = _('problem translations') + + +class ProblemClarification(models.Model): + problem = models.ForeignKey(Problem, verbose_name=_('clarified problem'), on_delete=CASCADE) + description = models.TextField(verbose_name=_('clarification body')) + date = models.DateTimeField(verbose_name=_('clarification timestamp'), auto_now_add=True) class LanguageLimit(models.Model): - problem = models.ForeignKey( - Problem, - verbose_name=_("problem"), - related_name="language_limits", - on_delete=CASCADE, - ) - language = models.ForeignKey( - Language, verbose_name=_("language"), on_delete=CASCADE - ) - time_limit = models.FloatField( - verbose_name=_("time limit"), - validators=[ - MinValueValidator(settings.DMOJ_PROBLEM_MIN_TIME_LIMIT), - MaxValueValidator(settings.DMOJ_PROBLEM_MAX_TIME_LIMIT), - ], - ) - memory_limit = models.IntegerField( - verbose_name=_("memory limit"), - validators=[ - MinValueValidator(settings.DMOJ_PROBLEM_MIN_MEMORY_LIMIT), - MaxValueValidator(settings.DMOJ_PROBLEM_MAX_MEMORY_LIMIT), - ], - ) + problem = models.ForeignKey(Problem, verbose_name=_('problem'), related_name='language_limits', on_delete=CASCADE) + language = models.ForeignKey(Language, verbose_name=_('language'), on_delete=CASCADE) + time_limit = models.FloatField(verbose_name=_('time limit'), + validators=[MinValueValidator(settings.DMOJ_PROBLEM_MIN_TIME_LIMIT), + MaxValueValidator(settings.DMOJ_PROBLEM_MAX_TIME_LIMIT)]) + memory_limit = models.IntegerField(verbose_name=_('memory limit'), + validators=[MinValueValidator(settings.DMOJ_PROBLEM_MIN_MEMORY_LIMIT), + MaxValueValidator(settings.DMOJ_PROBLEM_MAX_MEMORY_LIMIT)]) class Meta: - unique_together = ("problem", "language") - verbose_name = _("language-specific resource limit") - verbose_name_plural = _("language-specific resource limits") + unique_together = ('problem', 'language') + verbose_name = _('language-specific resource limit') + verbose_name_plural = _('language-specific resource limits') -class LanguageTemplate(models.Model): - problem = models.ForeignKey( - Problem, - verbose_name=_("problem"), - related_name="language_templates", - on_delete=CASCADE, - ) - language = models.ForeignKey( - Language, verbose_name=_("language"), on_delete=CASCADE - ) - source = models.TextField(verbose_name=_("source code"), max_length=65536) - - class Meta: - unique_together = ("problem", "language") - verbose_name = _("language-specific template") - verbose_name_plural = _("language-specific templates") - - -class Solution(models.Model, PageVotable, Bookmarkable): - problem = models.OneToOneField( - Problem, - on_delete=CASCADE, - verbose_name=_("associated problem"), - null=True, - blank=True, - related_name="solution", - ) - is_public = models.BooleanField(verbose_name=_("public visibility"), default=False) - publish_on = models.DateTimeField(verbose_name=_("publish date")) - authors = models.ManyToManyField(Profile, verbose_name=_("authors"), blank=True) - content = models.TextField(verbose_name=_("editorial content")) - comments = GenericRelation("Comment") - pagevote = GenericRelation("PageVote") - bookmark = GenericRelation("BookMark") +class Solution(models.Model): + problem = models.OneToOneField(Problem, on_delete=SET_NULL, verbose_name=_('associated problem'), + null=True, blank=True, related_name='solution') + is_public = models.BooleanField(verbose_name=_('public visibility'), default=False) + publish_on = models.DateTimeField(verbose_name=_('publish date')) + authors = models.ManyToManyField(Profile, verbose_name=_('authors'), blank=True) + content = models.TextField(verbose_name=_('editorial content')) def get_absolute_url(self): problem = self.problem if problem is None: - return reverse("home") + return reverse('home') else: - return reverse("problem_editorial", args=[problem.code]) - - @cache_wrapper(prefix="Sga", expected_type=models.query.QuerySet) - def get_authors(self): - return self.authors.only("id") + return reverse('problem_editorial', args=[problem.code]) def __str__(self): - return _("Editorial for %s") % self.problem.name + return _('Editorial for %s') % self.problem.name class Meta: - permissions = (("see_private_solution", "See hidden solutions"),) - verbose_name = _("solution") - verbose_name_plural = _("solutions") - - -class ProblemPointsVote(models.Model): - points = models.IntegerField( - verbose_name=_("proposed point value"), - help_text=_("The amount of points you think this problem deserves."), - validators=[ - MinValueValidator(100), - MaxValueValidator(600), - ], - ) - - voter = models.ForeignKey( - Profile, related_name="problem_points_votes", on_delete=CASCADE, db_index=True - ) - problem = models.ForeignKey( - Problem, related_name="problem_points_votes", on_delete=CASCADE, db_index=True - ) - vote_time = models.DateTimeField( - verbose_name=_("The time this vote was cast"), - auto_now_add=True, - blank=True, - ) - - class Meta: - verbose_name = _("vote") - verbose_name_plural = _("votes") - - def __str__(self): - return f"{self.voter}: {self.points} for {self.problem.code}" - - -@receiver(m2m_changed, sender=Problem.organizations.through) -def update_organization_private(sender, instance, **kwargs): - if kwargs["action"] in ["post_add", "post_remove", "post_clear"]: - instance.is_organization_private = instance.organizations.exists() - instance.save(update_fields=["is_organization_private"]) + permissions = ( + ('see_private_solution', 'See hidden solutions'), + ) + verbose_name = _('solution') + verbose_name_plural = _('solutions') diff --git a/judge/models/problem_data.py b/judge/models/problem_data.py index adb92d8..da443e5 100644 --- a/judge/models/problem_data.py +++ b/judge/models/problem_data.py @@ -1,150 +1,64 @@ import errno import os -from zipfile import BadZipFile, ZipFile from django.core.validators import FileExtensionValidator -from django.core.cache import cache from django.db import models from django.utils.translation import gettext_lazy as _ -from judge.utils.problem_data import ProblemDataStorage, get_file_cachekey +from judge.utils.problem_data import ProblemDataStorage -__all__ = [ - "problem_data_storage", - "problem_directory_file", - "ProblemData", - "ProblemTestCase", - "CHECKERS", -] +__all__ = ['problem_data_storage', 'problem_directory_file', 'ProblemData', 'ProblemTestCase', 'CHECKERS'] problem_data_storage = ProblemDataStorage() -def problem_directory_file_helper(code, filename): +def _problem_directory_file(code, filename): return os.path.join(code, os.path.basename(filename)) def problem_directory_file(data, filename): - return problem_directory_file_helper(data.problem.code, filename) + return _problem_directory_file(data.problem.code, filename) CHECKERS = ( - ("standard", _("Standard")), - ("floats", _("Floats")), - ("floatsabs", _("Floats (absolute)")), - ("floatsrel", _("Floats (relative)")), - ("rstripped", _("Non-trailing spaces")), - ("sorted", _("Unordered")), - ("identical", _("Byte identical")), - ("linecount", _("Line-by-line")), - ("custom", _("Custom checker (PY)")), - ("customcpp", _("Custom checker (CPP)")), - ("interact", _("Interactive")), - ("testlib", _("Testlib")), + ('standard', _('Standard')), + ('floats', _('Floats')), + ('floatsabs', _('Floats (absolute)')), + ('floatsrel', _('Floats (relative)')), + ('rstripped', _('Non-trailing spaces')), + ('sorted', _('Unordered')), + ('identical', _('Byte identical')), + ('linecount', _('Line-by-line')), + ('custom', _('Custom checker (PY)')), + ('customval', _('Custom validator (CPP)')), ) class ProblemData(models.Model): - problem = models.OneToOneField( - "Problem", - verbose_name=_("problem"), - related_name="data_files", - on_delete=models.CASCADE, - ) - zipfile = models.FileField( - verbose_name=_("data zip file"), - storage=problem_data_storage, - null=True, - blank=True, - upload_to=problem_directory_file, - ) - generator = models.FileField( - verbose_name=_("generator file"), - storage=problem_data_storage, - null=True, - blank=True, - upload_to=problem_directory_file, - ) - output_prefix = models.IntegerField( - verbose_name=_("output prefix length"), blank=True, null=True - ) - output_limit = models.IntegerField( - verbose_name=_("output limit length"), blank=True, null=True - ) - feedback = models.TextField( - verbose_name=_("init.yml generation feedback"), blank=True - ) - checker = models.CharField( - max_length=10, verbose_name=_("checker"), choices=CHECKERS, blank=True - ) - checker_args = models.TextField( - verbose_name=_("checker arguments"), - blank=True, - help_text=_("checker arguments as a JSON object"), - ) - custom_checker = models.FileField( - verbose_name=_("custom checker file"), - storage=problem_data_storage, - null=True, - blank=True, - upload_to=problem_directory_file, - validators=[FileExtensionValidator(allowed_extensions=["py"])], - ) - custom_checker_cpp = models.FileField( - verbose_name=_("custom cpp checker file"), - storage=problem_data_storage, - null=True, - blank=True, - upload_to=problem_directory_file, - validators=[FileExtensionValidator(allowed_extensions=["cpp"])], - ) - interactive_judge = models.FileField( - verbose_name=_("interactive judge"), - storage=problem_data_storage, - null=True, - blank=True, - upload_to=problem_directory_file, - validators=[FileExtensionValidator(allowed_extensions=["cpp"])], - ) - fileio_input = models.TextField( - verbose_name=_("input file name"), - blank=True, - null=True, - help_text=_("Leave empty for stdin"), - ) - fileio_output = models.TextField( - verbose_name=_("output file name"), - blank=True, - null=True, - help_text=_("Leave empty for stdout"), - ) - output_only = models.BooleanField( - verbose_name=_("is output only"), - help_text=_("Support output-only problem"), - null=True, - ) - use_ioi_signature = models.BooleanField( - verbose_name=_("is IOI signature"), - help_text=_("Use IOI Signature"), - null=True, - ) - signature_handler = models.FileField( - verbose_name=_("signature handler"), - storage=problem_data_storage, - null=True, - blank=True, - upload_to=problem_directory_file, - validators=[FileExtensionValidator(allowed_extensions=["cpp"])], - ) - signature_header = models.FileField( - verbose_name=_("signature header"), - storage=problem_data_storage, - null=True, - blank=True, - upload_to=problem_directory_file, - validators=[FileExtensionValidator(allowed_extensions=["h"])], - ) - + problem = models.OneToOneField('Problem', verbose_name=_('problem'), related_name='data_files', + on_delete=models.CASCADE) + zipfile = models.FileField(verbose_name=_('data zip file'), storage=problem_data_storage, null=True, blank=True, + upload_to=problem_directory_file) + generator = models.FileField(verbose_name=_('generator file'), storage=problem_data_storage, null=True, blank=True, + upload_to=problem_directory_file) + output_prefix = models.IntegerField(verbose_name=_('output prefix length'), blank=True, null=True) + output_limit = models.IntegerField(verbose_name=_('output limit length'), blank=True, null=True) + feedback = models.TextField(verbose_name=_('init.yml generation feedback'), blank=True) + checker = models.CharField(max_length=10, verbose_name=_('checker'), choices=CHECKERS, blank=True) + checker_args = models.TextField(verbose_name=_('checker arguments'), blank=True, + help_text=_('checker arguments as a JSON object')) + custom_checker = models.FileField(verbose_name=_('custom checker file'), + storage=problem_data_storage, + null=True, + blank=True, + upload_to=problem_directory_file, + validators=[FileExtensionValidator(allowed_extensions=['py'])]) + custom_validator = models.FileField(verbose_name=_('custom validator file'), + storage=problem_data_storage, + null=True, + blank=True, + upload_to=problem_directory_file, + validators=[FileExtensionValidator(allowed_extensions=['cpp'])]) __original_zipfile = None def __init__(self, *args, **kwargs): @@ -152,99 +66,49 @@ class ProblemData(models.Model): self.__original_zipfile = self.zipfile def save(self, *args, **kwargs): - # Delete caches - if self.__original_zipfile: - try: - files = ZipFile(self.__original_zipfile.path).namelist() - for file in files: - cache_key = "problem_archive:%s:%s" % ( - self.problem.code, - get_file_cachekey(file), - ) - cache.delete(cache_key) - except (BadZipFile, FileNotFoundError): - pass - if self.zipfile != self.__original_zipfile: - self.__original_zipfile.delete(save=False) + if self.zipfile != self.__original_zipfile: + self.__original_zipfile.delete(save=False) return super(ProblemData, self).save(*args, **kwargs) def has_yml(self): - return problem_data_storage.exists("%s/init.yml" % self.problem.code) + return problem_data_storage.exists('%s/init.yml' % self.problem.code) def _update_code(self, original, new): + try: + problem_data_storage.rename(original, new) + except OSError as e: + if e.errno != errno.ENOENT: + raise if self.zipfile: - self.zipfile.name = problem_directory_file_helper(new, self.zipfile.name) + self.zipfile.name = _problem_directory_file(new, self.zipfile.name) if self.generator: - self.generator.name = problem_directory_file_helper( - new, self.generator.name - ) + self.generator.name = _problem_directory_file(new, self.generator.name) if self.custom_checker: - self.custom_checker.name = problem_directory_file_helper( - new, self.custom_checker.name - ) + self.custom_checker.name = _problem_directory_file(new, self.custom_checker.name) if self.custom_checker: - self.custom_checker.name = problem_directory_file_helper( - new, self.custom_checker.name - ) - if self.custom_checker_cpp: - self.custom_checker_cpp.name = problem_directory_file_helper( - new, self.custom_checker_cpp.name - ) - if self.interactive_judge: - self.interactive_judge.name = problem_directory_file_helper( - new, self.interactive_judge.name - ) - if self.signature_header: - self.signature_header.name = problem_directory_file_helper( - new, self.signature_header.name - ) - if self.signature_handler: - self.signature_handler.name = problem_directory_file_helper( - new, self.signature_handler.name - ) + self.custom_checker.name = _problem_directory_file(new, self.custom_checker.name) + if self.custom_validator: + self.custom_validator.name = _problem_directory_file(new, self.custom_validator.name) self.save() - _update_code.alters_data = True class ProblemTestCase(models.Model): - dataset = models.ForeignKey( - "Problem", - verbose_name=_("problem data set"), - related_name="cases", - on_delete=models.CASCADE, - ) - order = models.IntegerField(verbose_name=_("case position")) - type = models.CharField( - max_length=1, - verbose_name=_("case type"), - choices=( - ("C", _("Normal case")), - ("S", _("Batch start")), - ("E", _("Batch end")), - ), - default="C", - ) - input_file = models.CharField( - max_length=100, verbose_name=_("input file name"), blank=True - ) - output_file = models.CharField( - max_length=100, verbose_name=_("output file name"), blank=True - ) - generator_args = models.TextField(verbose_name=_("generator arguments"), blank=True) - points = models.IntegerField(verbose_name=_("point value"), blank=True, null=True) - is_pretest = models.BooleanField(verbose_name=_("case is pretest?")) - output_prefix = models.IntegerField( - verbose_name=_("output prefix length"), blank=True, null=True - ) - output_limit = models.IntegerField( - verbose_name=_("output limit length"), blank=True, null=True - ) - checker = models.CharField( - max_length=10, verbose_name=_("checker"), choices=CHECKERS, blank=True - ) - checker_args = models.TextField( - verbose_name=_("checker arguments"), - blank=True, - help_text=_("checker arguments as a JSON object"), - ) + dataset = models.ForeignKey('Problem', verbose_name=_('problem data set'), related_name='cases', + on_delete=models.CASCADE) + order = models.IntegerField(verbose_name=_('case position')) + type = models.CharField(max_length=1, verbose_name=_('case type'), + choices=(('C', _('Normal case')), + ('S', _('Batch start')), + ('E', _('Batch end'))), + default='C') + input_file = models.CharField(max_length=100, verbose_name=_('input file name'), blank=True) + output_file = models.CharField(max_length=100, verbose_name=_('output file name'), blank=True) + generator_args = models.TextField(verbose_name=_('generator arguments'), blank=True) + points = models.IntegerField(verbose_name=_('point value'), blank=True, null=True) + is_pretest = models.BooleanField(verbose_name=_('case is pretest?')) + output_prefix = models.IntegerField(verbose_name=_('output prefix length'), blank=True, null=True) + output_limit = models.IntegerField(verbose_name=_('output limit length'), blank=True, null=True) + checker = models.CharField(max_length=10, verbose_name=_('checker'), choices=CHECKERS, blank=True) + checker_args = models.TextField(verbose_name=_('checker arguments'), blank=True, + help_text=_('checker arguments as a JSON object')) diff --git a/judge/models/profile.py b/judge/models/profile.py index 4572b69..9cf046c 100644 --- a/judge/models/profile.py +++ b/judge/models/profile.py @@ -1,38 +1,22 @@ from operator import mul -import os from django.conf import settings from django.contrib.auth.models import User from django.core.validators import RegexValidator from django.db import models -from django.db.models import Max, CASCADE +from django.db.models import Max from django.urls import reverse from django.utils.functional import cached_property from django.utils.timezone import now from django.utils.translation import gettext_lazy as _ -from django.dispatch import receiver -from django.db.models.signals import post_save, pre_save - - from fernet_fields import EncryptedCharField from sortedm2m.fields import SortedManyToManyField -from judge.models.choices import ACE_THEMES, TIMEZONE +from judge.models.choices import ACE_THEMES, MATH_ENGINES_CHOICES, TIMEZONE from judge.models.runtime import Language from judge.ratings import rating_class -from judge.caching import cache_wrapper - -__all__ = ["Organization", "Profile", "OrganizationRequest", "Friend"] - - -TSHIRT_SIZES = ( - ("S", "Small (S)"), - ("M", "Medium (M)"), - ("L", "Large (L)"), - ("XL", "Extra Large (XL)"), - ("XXL", "2 Extra Large (XXL)"), -) +__all__ = ['Organization', 'Profile', 'OrganizationRequest'] class EncryptedNullCharField(EncryptedCharField): @@ -42,75 +26,29 @@ class EncryptedNullCharField(EncryptedCharField): return super(EncryptedNullCharField, self).get_prep_value(value) -def profile_image_path(profile, filename): - tail = filename.split(".")[-1] - new_filename = f"user_{profile.id}.{tail}" - return os.path.join(settings.DMOJ_PROFILE_IMAGE_ROOT, new_filename) - - -def organization_image_path(organization, filename): - tail = filename.split(".")[-1] - new_filename = f"organization_{organization.id}.{tail}" - return os.path.join(settings.DMOJ_ORGANIZATION_IMAGE_ROOT, new_filename) - - class Organization(models.Model): - name = models.CharField(max_length=128, verbose_name=_("organization title")) - slug = models.SlugField( - max_length=128, - verbose_name=_("organization slug"), - help_text=_("Organization name shown in URL"), - unique=True, - validators=[ - RegexValidator("^[-a-zA-Z0-9]+$", _("Only alphanumeric and hyphens")) - ], - ) - short_name = models.CharField( - max_length=20, - verbose_name=_("short name"), - help_text=_("Displayed beside user name during contests"), - ) - about = models.CharField( - max_length=10000, verbose_name=_("organization description") - ) - registrant = models.ForeignKey( - "Profile", - verbose_name=_("registrant"), - on_delete=models.CASCADE, - related_name="registrant+", - help_text=_("User who registered this organization"), - ) - admins = models.ManyToManyField( - "Profile", - verbose_name=_("administrators"), - related_name="admin_of", - help_text=_("Those who can edit this organization"), - ) - creation_date = models.DateTimeField( - verbose_name=_("creation date"), auto_now_add=True - ) - is_open = models.BooleanField( - verbose_name=_("is open organization?"), - help_text=_("Allow joining organization"), - default=True, - ) - slots = models.IntegerField( - verbose_name=_("maximum size"), - null=True, - blank=True, - help_text=_( - "Maximum amount of users in this organization, " - "only applicable to private organizations" - ), - ) - access_code = models.CharField( - max_length=7, - help_text=_("Student access code"), - verbose_name=_("access code"), - null=True, - blank=True, - ) - organization_image = models.ImageField(upload_to=organization_image_path, null=True) + name = models.CharField(max_length=128, verbose_name=_('organization title')) + slug = models.SlugField(max_length=128, verbose_name=_('organization slug'), + help_text=_('Organization name shown in URL')) + short_name = models.CharField(max_length=20, verbose_name=_('short name'), + help_text=_('Displayed beside user name during contests')) + about = models.TextField(verbose_name=_('organization description')) + registrant = models.ForeignKey('Profile', verbose_name=_('registrant'), on_delete=models.CASCADE, + related_name='registrant+', help_text=_('User who registered this organization')) + admins = models.ManyToManyField('Profile', verbose_name=_('administrators'), related_name='admin_of', + help_text=_('Those who can edit this organization')) + creation_date = models.DateTimeField(verbose_name=_('creation date'), auto_now_add=True) + is_open = models.BooleanField(verbose_name=_('is open organization?'), + help_text=_('Allow joining organization'), default=True) + slots = models.IntegerField(verbose_name=_('maximum size'), null=True, blank=True, + help_text=_('Maximum amount of users in this organization, ' + 'only applicable to private organizations')) + access_code = models.CharField(max_length=7, help_text=_('Student access code'), + verbose_name=_('access code'), null=True, blank=True) + logo_override_image = models.CharField(verbose_name=_('Logo override image'), default='', max_length=150, + blank=True, + help_text=_('This image will replace the default site logo for users ' + 'viewing the organization.')) def __contains__(self, item): if isinstance(item, int): @@ -118,152 +56,64 @@ class Organization(models.Model): elif isinstance(item, Profile): return self.members.filter(id=item.id).exists() else: - raise TypeError( - "Organization membership test must be Profile or primany key" - ) - - def delete(self, *args, **kwargs): - contests = self.contest_set - for contest in contests.all(): - if contest.organizations.count() == 1: - contest.delete() - super().delete(*args, **kwargs) + raise TypeError('Organization membership test must be Profile or primany key') def __str__(self): return self.name def get_absolute_url(self): - return reverse("organization_home", args=(self.id, self.slug)) + return reverse('organization_home', args=(self.id, self.slug)) def get_users_url(self): - return reverse("organization_users", args=(self.id, self.slug)) - - def get_problems_url(self): - return reverse("organization_problems", args=(self.id, self.slug)) - - def get_contests_url(self): - return reverse("organization_contests", args=(self.id, self.slug)) - - def get_submissions_url(self): - return reverse("organization_submissions", args=(self.id, self.slug)) - - def is_admin(self, profile): - return profile.id in self.get_admin_ids() - - @cache_wrapper(prefix="Orgai", expected_type=list) - def get_admin_ids(self): - return list(self.admins.values_list("id", flat=True)) - - def is_member(self, profile): - return profile in self + return reverse('organization_users', args=(self.id, self.slug)) class Meta: - ordering = ["name"] + ordering = ['name'] permissions = ( - ("organization_admin", "Administer organizations"), - ("edit_all_organization", "Edit all organizations"), + ('organization_admin', 'Administer organizations'), + ('edit_all_organization', 'Edit all organizations'), ) - verbose_name = _("organization") - verbose_name_plural = _("organizations") - app_label = "judge" + verbose_name = _('organization') + verbose_name_plural = _('organizations') class Profile(models.Model): - user = models.OneToOneField( - User, verbose_name=_("user associated"), on_delete=models.CASCADE - ) - about = models.CharField( - max_length=10000, verbose_name=_("self-description"), null=True, blank=True - ) - timezone = models.CharField( - max_length=50, - verbose_name=_("location"), - choices=TIMEZONE, - default=settings.DEFAULT_USER_TIME_ZONE, - ) - language = models.ForeignKey( - "Language", - verbose_name=_("preferred language"), - on_delete=models.SET_DEFAULT, - default=Language.get_default_language_pk, - ) + user = models.OneToOneField(User, verbose_name=_('user associated'), on_delete=models.CASCADE) + about = models.TextField(verbose_name=_('self-description'), null=True, blank=True) + timezone = models.CharField(max_length=50, verbose_name=_('location'), choices=TIMEZONE, + default=settings.DEFAULT_USER_TIME_ZONE) + language = models.ForeignKey('Language', verbose_name=_('preferred language'), on_delete=models.SET_DEFAULT, + default=Language.get_default_language_pk) points = models.FloatField(default=0, db_index=True) performance_points = models.FloatField(default=0, db_index=True) problem_count = models.IntegerField(default=0, db_index=True) - ace_theme = models.CharField(max_length=30, choices=ACE_THEMES, default="github") - last_access = models.DateTimeField(verbose_name=_("last access time"), default=now) - ip = models.GenericIPAddressField(verbose_name=_("last IP"), blank=True, null=True) - organizations = SortedManyToManyField( - Organization, - verbose_name=_("organization"), - blank=True, - related_name="members", - related_query_name="member", - ) - display_rank = models.CharField( - max_length=10, - default="user", - verbose_name=_("display rank"), - choices=( - ("user", "Normal User"), - ("setter", "Problem Setter"), - ("admin", "Admin"), - ), - db_index=True, - ) - mute = models.BooleanField( - verbose_name=_("comment mute"), - help_text=_("Some users are at their best when silent."), - default=False, - ) - is_unlisted = models.BooleanField( - verbose_name=_("unlisted user"), - help_text=_("User will not be ranked."), - default=False, - ) - rating = models.IntegerField(null=True, default=None, db_index=True) - current_contest = models.OneToOneField( - "ContestParticipation", - verbose_name=_("current contest"), - null=True, - blank=True, - related_name="+", - on_delete=models.SET_NULL, - ) - is_totp_enabled = models.BooleanField( - verbose_name=_("2FA enabled"), - default=False, - help_text=_("check to enable TOTP-based two factor authentication"), - ) - totp_key = EncryptedNullCharField( - max_length=32, - null=True, - blank=True, - verbose_name=_("TOTP key"), - help_text=_("32 character base32-encoded key for TOTP"), - validators=[ - RegexValidator("^$|^[A-Z2-7]{32}$", _("TOTP key must be empty or base32")) - ], - ) - notes = models.TextField( - verbose_name=_("internal notes"), - null=True, - blank=True, - help_text=_("Notes for administrators regarding this user."), - ) - profile_image = models.ImageField(upload_to=profile_image_path, null=True) - email_change_pending = models.EmailField(blank=True, null=True) - css_background = models.TextField( - verbose_name=_("Custom background"), - null=True, - blank=True, - help_text=_('CSS custom background properties: url("image_url"), color, etc'), - max_length=300, - ) - - @cached_property - def _cached_info(self): - return _get_basic_info(self.id) + ace_theme = models.CharField(max_length=30, choices=ACE_THEMES, default='github') + last_access = models.DateTimeField(verbose_name=_('last access time'), default=now) + ip = models.GenericIPAddressField(verbose_name=_('last IP'), blank=True, null=True) + organizations = SortedManyToManyField(Organization, verbose_name=_('organization'), blank=True, + related_name='members', related_query_name='member') + display_rank = models.CharField(max_length=10, default='user', verbose_name=_('display rank'), + choices=(('user', 'Normal User'), ('setter', 'Problem Setter'), ('admin', 'Admin'))) + mute = models.BooleanField(verbose_name=_('comment mute'), help_text=_('Some users are at their best when silent.'), + default=False) + is_unlisted = models.BooleanField(verbose_name=_('unlisted user'), help_text=_('User will not be ranked.'), + default=False) + rating = models.IntegerField(null=True, default=None) + user_script = models.TextField(verbose_name=_('user script'), default='', blank=True, max_length=65536, + help_text=_('User-defined JavaScript for site customization.')) + current_contest = models.OneToOneField('ContestParticipation', verbose_name=_('current contest'), + null=True, blank=True, related_name='+', on_delete=models.SET_NULL) + math_engine = models.CharField(verbose_name=_('math engine'), choices=MATH_ENGINES_CHOICES, max_length=4, + default=settings.MATHOID_DEFAULT_TYPE, + help_text=_('the rendering engine used to render math')) + is_totp_enabled = models.BooleanField(verbose_name=_('2FA enabled'), default=False, + help_text=_('check to enable TOTP-based two factor authentication')) + totp_key = EncryptedNullCharField(max_length=32, null=True, blank=True, verbose_name=_('TOTP key'), + help_text=_('32 character base32-encoded key for TOTP'), + validators=[RegexValidator('^$|^[A-Z2-7]{32}$', + _('TOTP key must be empty or base32'))]) + notes = models.TextField(verbose_name=_('internal notes'), null=True, blank=True, + help_text=_('Notes for administrators regarding this user.')) @cached_property def organization(self): @@ -273,86 +123,28 @@ class Profile(models.Model): @cached_property def username(self): - try: - return self._cached_info["username"] - except KeyError: - _get_basic_info.dirty(self.id) - - @cached_property - def first_name(self): - return self._cached_info.get("first_name", "") - - @cached_property - def last_name(self): - return self._cached_info.get("last_name", "") - - @cached_property - def email(self): - return self._cached_info["email"] - - @cached_property - def is_muted(self): - return self._cached_info["mute"] - - @cached_property - def cached_display_rank(self): - return self._cached_info.get("display_rank") - - @cached_property - def cached_rating(self): - return self._cached_info.get("rating") - - @cached_property - def profile_image_url(self): - return self._cached_info.get("profile_image_url") - - @cached_property - def count_unseen_notifications(self): - from judge.models.notification import unseen_notifications_count - - return unseen_notifications_count(self) - - @cached_property - def count_unread_chat_boxes(self): - from chat_box.utils import get_unread_boxes - - return get_unread_boxes(self) + return self.user.username _pp_table = [pow(settings.DMOJ_PP_STEP, i) for i in range(settings.DMOJ_PP_ENTRIES)] def calculate_points(self, table=_pp_table): from judge.models import Problem - - public_problems = Problem.get_public_problems() - data = ( - public_problems.filter( - submission__user=self, submission__points__isnull=False - ) - .annotate(max_points=Max("submission__points")) - .order_by("-max_points") - .values_list("max_points", flat=True) - .filter(max_points__gt=0) - ) - extradata = ( - public_problems.filter(submission__user=self, submission__result="AC") - .values("id") - .distinct() - .count() - ) + data = (Problem.objects.filter(submission__user=self, submission__points__isnull=False, is_public=True, + is_organization_private=False) + .annotate(max_points=Max('submission__points')).order_by('-max_points') + .values_list('max_points', flat=True).filter(max_points__gt=0)) + extradata = Problem.objects.filter(submission__user=self, submission__result='AC', is_public=True) \ + .values('id').distinct().count() bonus_function = settings.DMOJ_PP_BONUS_FUNCTION points = sum(data) problems = len(data) entries = min(len(data), len(table)) pp = sum(map(mul, table[:entries], data[:entries])) + bonus_function(extradata) - if ( - self.points != points - or problems != self.problem_count - or self.performance_points != pp - ): + if self.points != points or problems != self.problem_count or self.performance_points != pp: self.points = points self.problem_count = problems self.performance_points = pp - self.save(update_fields=["points", "problem_count", "performance_points"]) + self.save(update_fields=['points', 'problem_count', 'performance_points']) return points calculate_points.alters_data = True @@ -364,255 +156,49 @@ class Profile(models.Model): remove_contest.alters_data = True def update_contest(self): - from judge.models import ContestParticipation - - try: - contest = self.current_contest - if contest is not None and ( - contest.ended or not contest.contest.is_accessible_by(self.user) - ): - self.remove_contest() - except ContestParticipation.DoesNotExist: + contest = self.current_contest + if contest is not None and (contest.ended or not contest.contest.is_accessible_by(self.user)): self.remove_contest() update_contest.alters_data = True def get_absolute_url(self): - return reverse("user_page", args=(self.user.username,)) + return reverse('user_page', args=(self.user.username,)) def __str__(self): return self.user.username @classmethod - def get_user_css_class( - cls, display_rank, rating, rating_colors=settings.DMOJ_RATING_COLORS - ): + def get_user_css_class(cls, display_rank, rating, rating_colors=settings.DMOJ_RATING_COLORS): if rating_colors: - return "rating %s %s" % ( - rating_class(rating) if rating is not None else "rate-none", - display_rank, - ) + return 'rating %s %s' % (rating_class(rating) if rating is not None else 'rate-none', display_rank) return display_rank @cached_property def css_class(self): - return self.get_user_css_class(self.cached_display_rank, self.cached_rating) - - def get_friends(self): # list of ids, including you - friend_obj = self.following_users.prefetch_related("users").first() - friend_ids = ( - [friend.id for friend in friend_obj.users.all()] if friend_obj else [] - ) - friend_ids.append(self.id) - - return friend_ids - - def can_edit_organization(self, org): - if not self.user.is_authenticated: - return False - profile_id = self.id - return org.is_admin(self) or self.user.is_superuser - - @classmethod - def prefetch_profile_cache(self, profile_ids): - _get_basic_info.prefetch_multi([(pid,) for pid in profile_ids]) + return self.get_user_css_class(self.display_rank, self.rating) class Meta: - indexes = [ - models.Index(fields=["is_unlisted", "performance_points"]), - ] permissions = ( - ("test_site", "Shows in-progress development stuff"), - ("totp", "Edit TOTP settings"), + ('test_site', 'Shows in-progress development stuff'), + ('totp', 'Edit TOTP settings'), ) - verbose_name = _("user profile") - verbose_name_plural = _("user profiles") - - -class ProfileInfo(models.Model): - profile = models.OneToOneField( - Profile, - verbose_name=_("profile associated"), - on_delete=models.CASCADE, - related_name="info", - ) - tshirt_size = models.CharField( - max_length=5, - choices=TSHIRT_SIZES, - verbose_name=_("t-shirt size"), - null=True, - blank=True, - ) - date_of_birth = models.DateField( - verbose_name=_("date of birth"), - null=True, - blank=True, - ) - address = models.CharField( - max_length=255, - verbose_name=_("address"), - null=True, - blank=True, - ) - - def __str__(self): - return f"{self.profile.user.username}'s Info" + verbose_name = _('user profile') + verbose_name_plural = _('user profiles') class OrganizationRequest(models.Model): - user = models.ForeignKey( - Profile, - verbose_name=_("user"), - related_name="requests", - on_delete=models.CASCADE, - ) - organization = models.ForeignKey( - Organization, - verbose_name=_("organization"), - related_name="requests", - on_delete=models.CASCADE, - ) - time = models.DateTimeField(verbose_name=_("request time"), auto_now_add=True) - state = models.CharField( - max_length=1, - verbose_name=_("state"), - choices=( - ("P", "Pending"), - ("A", "Approved"), - ("R", "Rejected"), - ), - ) - reason = models.TextField(verbose_name=_("reason")) + user = models.ForeignKey(Profile, verbose_name=_('user'), related_name='requests', on_delete=models.CASCADE) + organization = models.ForeignKey(Organization, verbose_name=_('organization'), related_name='requests', + on_delete=models.CASCADE) + time = models.DateTimeField(verbose_name=_('request time'), auto_now_add=True) + state = models.CharField(max_length=1, verbose_name=_('state'), choices=( + ('P', 'Pending'), + ('A', 'Approved'), + ('R', 'Rejected'), + )) + reason = models.TextField(verbose_name=_('reason')) class Meta: - verbose_name = _("organization join request") - verbose_name_plural = _("organization join requests") - - -class Friend(models.Model): - users = models.ManyToManyField(Profile) - current_user = models.ForeignKey( - Profile, - related_name="following_users", - on_delete=CASCADE, - ) - - @classmethod - def is_friend(self, current_user, new_friend): - try: - return current_user.following_users.filter(users=new_friend).exists() - except: - return False - - @classmethod - def make_friend(self, current_user, new_friend): - friend, created = self.objects.get_or_create(current_user=current_user) - friend.users.add(new_friend) - - @classmethod - def remove_friend(self, current_user, new_friend): - friend, created = self.objects.get_or_create(current_user=current_user) - friend.users.remove(new_friend) - - @classmethod - def toggle_friend(self, current_user, new_friend): - if self.is_friend(current_user, new_friend): - self.remove_friend(current_user, new_friend) - else: - self.make_friend(current_user, new_friend) - - @classmethod - def get_friend_profiles(self, current_user): - try: - ret = self.objects.get(current_user=current_user).users.all() - except Friend.DoesNotExist: - ret = Profile.objects.none() - return ret - - def __str__(self): - return str(self.current_user) - - -class OrganizationProfile(models.Model): - profile = models.ForeignKey( - Profile, - verbose_name=_("user"), - related_name="last_visit", - on_delete=models.CASCADE, - db_index=True, - ) - organization = models.ForeignKey( - Organization, - verbose_name=_("organization"), - related_name="last_vist", - on_delete=models.CASCADE, - ) - last_visit = models.AutoField( - verbose_name=_("last visit"), - primary_key=True, - ) - - @classmethod - def remove_organization(self, profile, organization): - organization_profile = self.objects.filter( - profile=profile, organization=organization - ) - if organization_profile.exists(): - organization_profile.delete() - - @classmethod - def add_organization(self, profile, organization): - self.remove_organization(profile, organization) - new_row = OrganizationProfile(profile=profile, organization=organization) - new_row.save() - - @classmethod - def get_most_recent_organizations(cls, profile): - queryset = cls.objects.filter(profile=profile).order_by("-last_visit")[:5] - queryset = queryset.select_related("organization").defer("organization__about") - organizations = [op.organization for op in queryset] - - return organizations - - -@receiver([post_save], sender=User) -def on_user_save(sender, instance, **kwargs): - try: - profile = instance.profile - _get_basic_info.dirty(profile.id) - except: - pass - - -@cache_wrapper(prefix="Pgbi3", expected_type=dict) -def _get_basic_info(profile_id): - profile = ( - Profile.objects.select_related("user") - .only( - "id", - "mute", - "profile_image", - "user__username", - "user__email", - "user__first_name", - "user__last_name", - "display_rank", - "rating", - ) - .get(id=profile_id) - ) - user = profile.user - res = { - "email": user.email, - "username": user.username, - "mute": profile.mute, - "first_name": user.first_name or None, - "last_name": user.last_name or None, - "profile_image_url": profile.profile_image.url - if profile.profile_image - else None, - "display_rank": profile.display_rank, - "rating": profile.rating, - } - res = {k: v for k, v in res.items() if v is not None} - return res + verbose_name = _('organization join request') + verbose_name_plural = _('organization join requests') diff --git a/judge/models/runtime.py b/judge/models/runtime.py index 97db711..d28be9c 100644 --- a/judge/models/runtime.py +++ b/judge/models/runtime.py @@ -11,84 +11,39 @@ from django.utils.functional import cached_property from django.utils.translation import gettext_lazy as _ from judge.judgeapi import disconnect_judge -from judge.caching import cache_wrapper -__all__ = ["Language", "RuntimeVersion", "Judge"] +__all__ = ['Language', 'RuntimeVersion', 'Judge'] class Language(models.Model): - key = models.CharField( - max_length=6, - verbose_name=_("short identifier"), - help_text=_( - "The identifier for this language; the same as its executor id for judges." - ), - unique=True, - ) - name = models.CharField( - max_length=20, - verbose_name=_("long name"), - help_text=_('Longer name for the language, e.g. "Python 2" or "C++11".'), - ) - short_name = models.CharField( - max_length=10, - verbose_name=_("short name"), - help_text=_( - 'More readable, but short, name to display publicly; e.g. "PY2" or ' - '"C++11". If left blank, it will default to the ' - "short identifier." - ), - null=True, - blank=True, - ) - common_name = models.CharField( - max_length=10, - verbose_name=_("common name"), - help_text=_( - "Common name for the language. For example, the common name for C++03, " - 'C++11, and C++14 would be "C++"' - ), - ) - ace = models.CharField( - max_length=20, - verbose_name=_("ace mode name"), - help_text=_( - 'Language ID for Ace.js editor highlighting, appended to "mode-" to determine ' - 'the Ace JavaScript file to use, e.g., "python".' - ), - ) - pygments = models.CharField( - max_length=20, - verbose_name=_("pygments name"), - help_text=_("Language ID for Pygments highlighting in source windows."), - ) - template = models.TextField( - verbose_name=_("code template"), - help_text=_("Code template to display in submission editor."), - blank=True, - ) - info = models.CharField( - max_length=50, - verbose_name=_("runtime info override"), - blank=True, - help_text=_( - "Do not set this unless you know what you're doing! It will override the " - "usually more specific, judge-provided runtime info!" - ), - ) - description = models.TextField( - verbose_name=_("language description"), - help_text=_( - "Use this field to inform users of quirks with your environment, " - "additional restrictions, etc." - ), - blank=True, - ) - extension = models.CharField( - max_length=10, - verbose_name=_("extension"), - help_text=_('The extension of source files, e.g., "py" or "cpp".'), - ) + key = models.CharField(max_length=6, verbose_name=_('short identifier'), + help_text=_('The identifier for this language; the same as its executor id for judges.'), + unique=True) + name = models.CharField(max_length=20, verbose_name=_('long name'), + help_text=_('Longer name for the language, e.g. "Python 2" or "C++11".')) + short_name = models.CharField(max_length=10, verbose_name=_('short name'), + help_text=_('More readable, but short, name to display publicly; e.g. "PY2" or ' + '"C++11". If left blank, it will default to the ' + 'short identifier.'), + null=True, blank=True) + common_name = models.CharField(max_length=10, verbose_name=_('common name'), + help_text=_('Common name for the language. For example, the common name for C++03, ' + 'C++11, and C++14 would be "C++"')) + ace = models.CharField(max_length=20, verbose_name=_('ace mode name'), + help_text=_('Language ID for Ace.js editor highlighting, appended to "mode-" to determine ' + 'the Ace JavaScript file to use, e.g., "python".')) + pygments = models.CharField(max_length=20, verbose_name=_('pygments name'), + help_text=_('Language ID for Pygments highlighting in source windows.')) + template = models.TextField(verbose_name=_('code template'), + help_text=_('Code template to display in submission editor.'), blank=True) + info = models.CharField(max_length=50, verbose_name=_('runtime info override'), blank=True, + help_text=_("Do not set this unless you know what you're doing! It will override the " + "usually more specific, judge-provided runtime info!")) + description = models.TextField(verbose_name=_('language description'), + help_text=_('Use this field to inform users of quirks with your environment, ' + 'additional restrictions, etc.'), blank=True) + extension = models.CharField(max_length=10, verbose_name=_('extension'), + help_text=_('The extension of source files, e.g., "py" or "cpp".')) def runtime_versions(self): runtimes = OrderedDict() @@ -97,29 +52,25 @@ class Language(models.Model): id = runtime.name if id not in runtimes: runtimes[id] = set() - if ( - not runtime.version - ): # empty str == error determining version on judge side + if not runtime.version: # empty str == error determining version on judge side continue runtimes[id].add(runtime.version) lang_versions = [] for id, version_list in runtimes.items(): - lang_versions.append( - (id, sorted(version_list, key=lambda a: tuple(map(int, a.split("."))))) - ) + lang_versions.append((id, sorted(version_list, key=lambda a: tuple(map(int, a.split('.')))))) return lang_versions @classmethod def get_common_name_map(cls): - result = cache.get("lang:cn_map") + result = cache.get('lang:cn_map') if result is not None: return result result = defaultdict(set) - for id, cn in Language.objects.values_list("id", "common_name"): + for id, cn in Language.objects.values_list('id', 'common_name'): result[cn].add(id) result = {id: cns for id, cns in result.items() if len(cns) > 1} - cache.set("lang:cn_map", result, 86400) + cache.set('lang:cn_map', result, 86400) return result @cached_property @@ -132,98 +83,57 @@ class Language(models.Model): @cached_property def display_name(self): if self.info: - return "%s (%s)" % (self.name, self.info) + return '%s (%s)' % (self.name, self.info) else: return self.name @classmethod def get_python3(cls): # We really need a default language, and this app is in Python 3 - return Language.objects.get_or_create(key="PY3", defaults={"name": "Python 3"})[ - 0 - ] + return Language.objects.get_or_create(key='PY3', defaults={'name': 'Python 3'})[0] def get_absolute_url(self): - return reverse("runtime_list") + "#" + self.key + return reverse('runtime_list') + '#' + self.key @classmethod def get_default_language(cls): - return _get_default_language() + return Language.objects.get(key=settings.DEFAULT_USER_LANGUAGE) @classmethod def get_default_language_pk(cls): - return _get_default_language().pk + return cls.get_default_language().pk class Meta: - ordering = ["key"] - verbose_name = _("language") - verbose_name_plural = _("languages") - - -@cache_wrapper(prefix="gdl") -def _get_default_language(): - try: - return Language.objects.get(key=settings.DEFAULT_USER_LANGUAGE) - except Language.DoesNotExist: - return cls.get_python3() + ordering = ['key'] + verbose_name = _('language') + verbose_name_plural = _('languages') class RuntimeVersion(models.Model): - language = models.ForeignKey( - Language, - verbose_name=_("language to which this runtime belongs"), - on_delete=CASCADE, - ) - judge = models.ForeignKey( - "Judge", verbose_name=_("judge on which this runtime exists"), on_delete=CASCADE - ) - name = models.CharField(max_length=64, verbose_name=_("runtime name")) - version = models.CharField( - max_length=64, verbose_name=_("runtime version"), blank=True - ) - priority = models.IntegerField( - verbose_name=_("order in which to display this runtime"), default=0 - ) + language = models.ForeignKey(Language, verbose_name=_('language to which this runtime belongs'), on_delete=CASCADE) + judge = models.ForeignKey('Judge', verbose_name=_('judge on which this runtime exists'), on_delete=CASCADE) + name = models.CharField(max_length=64, verbose_name=_('runtime name')) + version = models.CharField(max_length=64, verbose_name=_('runtime version'), blank=True) + priority = models.IntegerField(verbose_name=_('order in which to display this runtime'), default=0) class Judge(models.Model): - name = models.CharField( - max_length=50, help_text=_("Server name, hostname-style"), unique=True - ) - created = models.DateTimeField( - auto_now_add=True, verbose_name=_("time of creation") - ) - auth_key = models.CharField( - max_length=100, - help_text=_("A key to authenticate this judge"), - verbose_name=_("authentication key"), - ) - is_blocked = models.BooleanField( - verbose_name=_("block judge"), - default=False, - help_text=_( - "Whether this judge should be blocked from connecting, " - "even if its key is correct." - ), - ) - online = models.BooleanField(verbose_name=_("judge online status"), default=False) - start_time = models.DateTimeField(verbose_name=_("judge start time"), null=True) - ping = models.FloatField(verbose_name=_("response time"), null=True) - load = models.FloatField( - verbose_name=_("system load"), - null=True, - help_text=_("Load for the last minute, divided by processors to be fair."), - ) - description = models.TextField(blank=True, verbose_name=_("description")) - last_ip = models.GenericIPAddressField( - verbose_name="Last connected IP", blank=True, null=True - ) - problems = models.ManyToManyField( - "Problem", verbose_name=_("problems"), related_name="judges" - ) - runtimes = models.ManyToManyField( - Language, verbose_name=_("judges"), related_name="judges" - ) + name = models.CharField(max_length=50, help_text=_('Server name, hostname-style'), unique=True) + created = models.DateTimeField(auto_now_add=True, verbose_name=_('time of creation')) + auth_key = models.CharField(max_length=100, help_text=_('A key to authenticate this judge'), + verbose_name=_('authentication key')) + is_blocked = models.BooleanField(verbose_name=_('block judge'), default=False, + help_text=_('Whether this judge should be blocked from connecting, ' + 'even if its key is correct.')) + online = models.BooleanField(verbose_name=_('judge online status'), default=False) + start_time = models.DateTimeField(verbose_name=_('judge start time'), null=True) + ping = models.FloatField(verbose_name=_('response time'), null=True) + load = models.FloatField(verbose_name=_('system load'), null=True, + help_text=_('Load for the last minute, divided by processors to be fair.')) + description = models.TextField(blank=True, verbose_name=_('description')) + last_ip = models.GenericIPAddressField(verbose_name='Last connected IP', blank=True, null=True) + problems = models.ManyToManyField('Problem', verbose_name=_('problems'), related_name='judges') + runtimes = models.ManyToManyField(Language, verbose_name=_('judges'), related_name='judges') def __str__(self): return self.name @@ -235,23 +145,22 @@ class Judge(models.Model): @cached_property def runtime_versions(self): - qs = self.runtimeversion_set.values( - "language__key", "language__name", "version", "name" - ).order_by("language__key", "priority") + qs = (self.runtimeversion_set.values('language__key', 'language__name', 'version', 'name') + .order_by('language__key', 'priority')) ret = OrderedDict() for data in qs: - key = data["language__key"] + key = data['language__key'] if key not in ret: - ret[key] = {"name": data["language__name"], "runtime": []} - ret[key]["runtime"].append((data["name"], (data["version"],))) + ret[key] = {'name': data['language__name'], 'runtime': []} + ret[key]['runtime'].append((data['name'], (data['version'],))) return list(ret.items()) @cached_property def uptime(self): - return timezone.now() - self.start_time if self.online else "N/A" + return timezone.now() - self.start_time if self.online else 'N/A' @cached_property def ping_ms(self): @@ -259,9 +168,9 @@ class Judge(models.Model): @cached_property def runtime_list(self): - return map(attrgetter("name"), self.runtimes.all()) + return map(attrgetter('name'), self.runtimes.all()) class Meta: - ordering = ["name"] - verbose_name = _("judge") - verbose_name_plural = _("judges") + ordering = ['name'] + verbose_name = _('judge') + verbose_name_plural = _('judges') diff --git a/judge/models/submission.py b/judge/models/submission.py index 814344d..0941eb2 100644 --- a/judge/models/submission.py +++ b/judge/models/submission.py @@ -9,133 +9,96 @@ from django.utils.functional import cached_property from django.utils.translation import gettext_lazy as _ from judge.judgeapi import abort_submission, judge_submission -from judge.models.problem import Problem +from judge.models.problem import Problem, TranslatedProblemForeignKeyQuerySet from judge.models.profile import Profile from judge.models.runtime import Language from judge.utils.unicode import utf8bytes -__all__ = ["SUBMISSION_RESULT", "Submission", "SubmissionSource", "SubmissionTestCase"] +__all__ = ['SUBMISSION_RESULT', 'Submission', 'SubmissionSource', 'SubmissionTestCase'] SUBMISSION_RESULT = ( - ("AC", _("Accepted")), - ("WA", _("Wrong Answer")), - ("TLE", _("Time Limit Exceeded")), - ("MLE", _("Memory Limit Exceeded")), - ("OLE", _("Output Limit Exceeded")), - ("IR", _("Invalid Return")), - ("RTE", _("Runtime Error")), - ("CE", _("Compile Error")), - ("IE", _("Internal Error")), - ("SC", _("Short circuit")), - ("AB", _("Aborted")), + ('AC', _('Accepted')), + ('WA', _('Wrong Answer')), + ('TLE', _('Time Limit Exceeded')), + ('MLE', _('Memory Limit Exceeded')), + ('OLE', _('Output Limit Exceeded')), + ('IR', _('Invalid Return')), + ('RTE', _('Runtime Error')), + ('CE', _('Compile Error')), + ('IE', _('Internal Error')), + ('SC', _('Short circuit')), + ('AB', _('Aborted')), ) class Submission(models.Model): STATUS = ( - ("QU", _("Queued")), - ("P", _("Processing")), - ("G", _("Grading")), - ("D", _("Completed")), - ("IE", _("Internal Error")), - ("CE", _("Compile Error")), - ("AB", _("Aborted")), + ('QU', _('Queued')), + ('P', _('Processing')), + ('G', _('Grading')), + ('D', _('Completed')), + ('IE', _('Internal Error')), + ('CE', _('Compile Error')), + ('AB', _('Aborted')), ) - IN_PROGRESS_GRADING_STATUS = ("QU", "P", "G") + IN_PROGRESS_GRADING_STATUS = ('QU', 'P', 'G') RESULT = SUBMISSION_RESULT USER_DISPLAY_CODES = { - "AC": _("Accepted"), - "WA": _("Wrong Answer"), - "SC": "Short Circuited", - "TLE": _("Time Limit Exceeded"), - "MLE": _("Memory Limit Exceeded"), - "OLE": _("Output Limit Exceeded"), - "IR": _("Invalid Return"), - "RTE": _("Runtime Error"), - "CE": _("Compile Error"), - "IE": _("Internal Error (judging server error)"), - "QU": _("Queued"), - "P": _("Processing"), - "G": _("Grading"), - "D": _("Completed"), - "AB": _("Aborted"), + 'AC': _('Accepted'), + 'WA': _('Wrong Answer'), + 'SC': "Short Circuited", + 'TLE': _('Time Limit Exceeded'), + 'MLE': _('Memory Limit Exceeded'), + 'OLE': _('Output Limit Exceeded'), + 'IR': _('Invalid Return'), + 'RTE': _('Runtime Error'), + 'CE': _('Compile Error'), + 'IE': _('Internal Error (judging server error)'), + 'QU': _('Queued'), + 'P': _('Processing'), + 'G': _('Grading'), + 'D': _('Completed'), + 'AB': _('Aborted'), } user = models.ForeignKey(Profile, on_delete=models.CASCADE) problem = models.ForeignKey(Problem, on_delete=models.CASCADE) - date = models.DateTimeField( - verbose_name=_("submission time"), auto_now_add=True, db_index=True - ) - time = models.FloatField(verbose_name=_("execution time"), null=True, db_index=True) - memory = models.FloatField(verbose_name=_("memory usage"), null=True) - points = models.FloatField( - verbose_name=_("points granted"), null=True, db_index=True - ) - language = models.ForeignKey( - Language, verbose_name=_("submission language"), on_delete=models.CASCADE - ) - status = models.CharField( - verbose_name=_("status"), - max_length=2, - choices=STATUS, - default="QU", - db_index=True, - ) - result = models.CharField( - verbose_name=_("result"), - max_length=3, - choices=SUBMISSION_RESULT, - default=None, - null=True, - blank=True, - db_index=True, - ) - error = models.TextField(verbose_name=_("compile errors"), null=True, blank=True) + date = models.DateTimeField(verbose_name=_('submission time'), auto_now_add=True, db_index=True) + time = models.FloatField(verbose_name=_('execution time'), null=True, db_index=True) + memory = models.FloatField(verbose_name=_('memory usage'), null=True) + points = models.FloatField(verbose_name=_('points granted'), null=True, db_index=True) + language = models.ForeignKey(Language, verbose_name=_('submission language'), on_delete=models.CASCADE) + status = models.CharField(verbose_name=_('status'), max_length=2, choices=STATUS, default='QU', db_index=True) + result = models.CharField(verbose_name=_('result'), max_length=3, choices=SUBMISSION_RESULT, + default=None, null=True, blank=True, db_index=True) + error = models.TextField(verbose_name=_('compile errors'), null=True, blank=True) current_testcase = models.IntegerField(default=0) - batch = models.BooleanField(verbose_name=_("batched cases"), default=False) - case_points = models.FloatField(verbose_name=_("test case points"), default=0) - case_total = models.FloatField(verbose_name=_("test case total points"), default=0) - judged_on = models.ForeignKey( - "Judge", - verbose_name=_("judged on"), - null=True, - blank=True, - on_delete=models.SET_NULL, - ) - judged_date = models.DateTimeField( - verbose_name=_("submission judge time"), default=None, null=True - ) - was_rejudged = models.BooleanField( - verbose_name=_("was rejudged by admin"), default=False - ) - is_pretested = models.BooleanField( - verbose_name=_("was ran on pretests only"), default=False - ) - contest_object = models.ForeignKey( - "Contest", - verbose_name=_("contest"), - null=True, - blank=True, - on_delete=models.SET_NULL, - related_name="+", - ) + batch = models.BooleanField(verbose_name=_('batched cases'), default=False) + case_points = models.FloatField(verbose_name=_('test case points'), default=0) + case_total = models.FloatField(verbose_name=_('test case total points'), default=0) + judged_on = models.ForeignKey('Judge', verbose_name=_('judged on'), null=True, blank=True, + on_delete=models.SET_NULL) + was_rejudged = models.BooleanField(verbose_name=_('was rejudged by admin'), default=False) + is_pretested = models.BooleanField(verbose_name=_('was ran on pretests only'), default=False) + contest_object = models.ForeignKey('Contest', verbose_name=_('contest'), null=True, blank=True, + on_delete=models.SET_NULL, related_name='+') + + objects = TranslatedProblemForeignKeyQuerySet.as_manager() @classmethod def result_class_from_code(cls, result, case_points, case_total): - if result == "AC": + if result == 'AC': if case_points == case_total: - return "AC" - return "_AC" + return 'AC' + return '_AC' return result @property def result_class(self): # This exists to save all these conditionals from being executed (slowly) in each row.jade template - if self.status in ("IE", "CE"): + if self.status in ('IE', 'CE'): return self.status - return Submission.result_class_from_code( - self.result, self.case_points, self.case_total - ) + return Submission.result_class_from_code(self.result, self.case_points, self.case_total) @property def memory_bytes(self): @@ -147,10 +110,10 @@ class Submission(models.Model): @property def long_status(self): - return Submission.USER_DISPLAY_CODES.get(self.short_status, "") + return Submission.USER_DISPLAY_CODES.get(self.short_status, '') - def judge(self, *args, **kwargs): - judge_submission(self, *args, **kwargs) + def judge(self, rejudge=False, batch_rejudge=False): + judge_submission(self, rejudge, batch_rejudge) judge.alters_data = True @@ -166,12 +129,8 @@ class Submission(models.Model): return contest_problem = contest.problem - contest.points = round( - self.case_points / self.case_total * contest_problem.points - if self.case_total > 0 - else 0, - 3, - ) + contest.points = round(self.case_points / self.case_total * contest_problem.points + if self.case_total > 0 else 0, 3) if not contest_problem.partial and contest.points != contest_problem.points: contest.points = 0 contest.save() @@ -181,22 +140,18 @@ class Submission(models.Model): @property def is_graded(self): - return self.status not in ("QU", "P", "G") + return self.status not in ('QU', 'P', 'G') @cached_property def contest_key(self): - if hasattr(self, "contest"): + if hasattr(self, 'contest'): return self.contest_object.key def __str__(self): - return "Submission %d of %s by %s" % ( - self.id, - self.problem, - self.user.user.username, - ) + return 'Submission %d of %s by %s' % (self.id, self.problem, self.user.user.username) def get_absolute_url(self): - return reverse("submission_status", args=(self.id,)) + return reverse('submission_status', args=(self.id,)) @cached_property def contest_or_none(self): @@ -207,124 +162,56 @@ class Submission(models.Model): @classmethod def get_id_secret(cls, sub_id): - return ( - hmac.new( - utf8bytes(settings.EVENT_DAEMON_SUBMISSION_KEY), - b"%d" % sub_id, - hashlib.sha512, - ).hexdigest()[:16] - + "%08x" % sub_id - ) + return (hmac.new(utf8bytes(settings.EVENT_DAEMON_SUBMISSION_KEY), b'%d' % sub_id, hashlib.sha512) + .hexdigest()[:16] + '%08x' % sub_id) @cached_property def id_secret(self): return self.get_id_secret(self.id) - def is_accessible_by(self, profile, check_contest=True): - if not profile: - return False - - problem_id = self.problem_id - user = profile.user - - if profile.id == self.user_id: - return True - - if user.has_perm("judge.change_submission"): - return True - - if user.has_perm("judge.view_all_submission"): - return True - - if self.problem.is_public and user.has_perm("judge.view_public_submission"): - return True - - if check_contest: - contest = self.contest_object - if contest and contest.is_editable_by(user): - return True - - from judge.utils.problems import ( - user_completed_ids, - user_tester_ids, - user_editable_ids, - ) - - if problem_id in user_editable_ids(profile): - return True - - if self.problem_id in user_completed_ids(profile): - if self.problem.is_public: - return True - if problem_id in user_tester_ids(profile): - return True - - return False - class Meta: permissions = ( - ("abort_any_submission", "Abort any submission"), - ("rejudge_submission", "Rejudge the submission"), - ("rejudge_submission_lot", "Rejudge a lot of submissions"), - ("spam_submission", "Submit without limit"), - ("view_all_submission", "View all submission"), - ("resubmit_other", "Resubmit others' submission"), - ("view_public_submission", "View public submissions"), + ('abort_any_submission', 'Abort any submission'), + ('rejudge_submission', 'Rejudge the submission'), + ('rejudge_submission_lot', 'Rejudge a lot of submissions'), + ('spam_submission', 'Submit without limit'), + ('view_all_submission', 'View all submission'), + ('resubmit_other', "Resubmit others' submission"), ) - verbose_name = _("submission") - verbose_name_plural = _("submissions") - - indexes = [ - models.Index(fields=["problem", "user", "-points"]), - models.Index(fields=["contest_object", "problem", "user", "-points"]), - models.Index(fields=["language", "result"]), - ] + verbose_name = _('submission') + verbose_name_plural = _('submissions') class SubmissionSource(models.Model): - submission = models.OneToOneField( - Submission, - on_delete=models.CASCADE, - verbose_name=_("associated submission"), - related_name="source", - ) - source = models.TextField(verbose_name=_("source code"), max_length=65536) + submission = models.OneToOneField(Submission, on_delete=models.CASCADE, verbose_name=_('associated submission'), + related_name='source') + source = models.TextField(verbose_name=_('source code'), max_length=65536) def __str__(self): - return "Source of %s" % self.submission + return 'Source of %s' % self.submission class SubmissionTestCase(models.Model): RESULT = SUBMISSION_RESULT - submission = models.ForeignKey( - Submission, - verbose_name=_("associated submission"), - related_name="test_cases", - on_delete=models.CASCADE, - ) - case = models.IntegerField(verbose_name=_("test case ID")) - status = models.CharField( - max_length=3, verbose_name=_("status flag"), choices=SUBMISSION_RESULT - ) - time = models.FloatField(verbose_name=_("execution time"), null=True) - memory = models.FloatField(verbose_name=_("memory usage"), null=True) - points = models.FloatField(verbose_name=_("points granted"), null=True) - total = models.FloatField(verbose_name=_("points possible"), null=True) - batch = models.IntegerField(verbose_name=_("batch number"), null=True) - feedback = models.CharField( - max_length=50, verbose_name=_("judging feedback"), blank=True - ) - extended_feedback = models.TextField( - verbose_name=_("extended judging feedback"), blank=True - ) - output = models.TextField(verbose_name=_("program output"), blank=True) + submission = models.ForeignKey(Submission, verbose_name=_('associated submission'), + related_name='test_cases', on_delete=models.CASCADE) + case = models.IntegerField(verbose_name=_('test case ID')) + status = models.CharField(max_length=3, verbose_name=_('status flag'), choices=SUBMISSION_RESULT) + time = models.FloatField(verbose_name=_('execution time'), null=True) + memory = models.FloatField(verbose_name=_('memory usage'), null=True) + points = models.FloatField(verbose_name=_('points granted'), null=True) + total = models.FloatField(verbose_name=_('points possible'), null=True) + batch = models.IntegerField(verbose_name=_('batch number'), null=True) + feedback = models.CharField(max_length=50, verbose_name=_('judging feedback'), blank=True) + extended_feedback = models.TextField(verbose_name=_('extended judging feedback'), blank=True) + output = models.TextField(verbose_name=_('program output'), blank=True) @property def long_status(self): - return Submission.USER_DISPLAY_CODES.get(self.status, "") + return Submission.USER_DISPLAY_CODES.get(self.status, '') class Meta: - unique_together = ("submission", "case") - verbose_name = _("submission test case") - verbose_name_plural = _("submission test cases") + unique_together = ('submission', 'case') + verbose_name = _('submission test case') + verbose_name_plural = _('submission test cases') diff --git a/judge/models/test_formatter.py b/judge/models/test_formatter.py deleted file mode 100644 index b613b14..0000000 --- a/judge/models/test_formatter.py +++ /dev/null @@ -1,26 +0,0 @@ -import os -from django.db import models -from dmoj import settings -from django.utils.translation import gettext_lazy as _ - -__all__ = [ - "TestFormatterModel", -] - - -def test_formatter_path(test_formatter, filename): - tail = filename.split(".")[-1] - head = filename.split(".")[0] - if str(tail).lower() != "zip": - raise Exception("400: Only ZIP files are supported") - new_filename = f"{head}.{tail}" - return os.path.join(settings.DMOJ_TEST_FORMATTER_ROOT, new_filename) - - -class TestFormatterModel(models.Model): - file = models.FileField( - verbose_name=_("testcase file"), - null=True, - blank=True, - upload_to=test_formatter_path, - ) diff --git a/judge/models/ticket.py b/judge/models/ticket.py index 27d6fb4..9b3fc54 100644 --- a/judge/models/ticket.py +++ b/judge/models/ticket.py @@ -7,43 +7,24 @@ from judge.models.profile import Profile class Ticket(models.Model): - title = models.CharField(max_length=100, verbose_name=_("ticket title")) - user = models.ForeignKey( - Profile, - verbose_name=_("ticket creator"), - related_name="tickets", - on_delete=models.CASCADE, - ) - time = models.DateTimeField(verbose_name=_("creation time"), auto_now_add=True) - assignees = models.ManyToManyField( - Profile, verbose_name=_("assignees"), related_name="assigned_tickets" - ) - notes = models.TextField( - verbose_name=_("quick notes"), - blank=True, - help_text=_("Staff notes for this issue to aid in processing."), - ) - content_type = models.ForeignKey( - ContentType, verbose_name=_("linked item type"), on_delete=models.CASCADE - ) - object_id = models.PositiveIntegerField(verbose_name=_("linked item ID")) + title = models.CharField(max_length=100, verbose_name=_('ticket title')) + user = models.ForeignKey(Profile, verbose_name=_('ticket creator'), related_name='tickets', + on_delete=models.CASCADE) + time = models.DateTimeField(verbose_name=_('creation time'), auto_now_add=True) + assignees = models.ManyToManyField(Profile, verbose_name=_('assignees'), related_name='assigned_tickets') + notes = models.TextField(verbose_name=_('quick notes'), blank=True, + help_text=_('Staff notes for this issue to aid in processing.')) + content_type = models.ForeignKey(ContentType, verbose_name=_('linked item type'), + on_delete=models.CASCADE) + object_id = models.PositiveIntegerField(verbose_name=_('linked item ID')) linked_item = GenericForeignKey() - is_open = models.BooleanField(verbose_name=_("is ticket open?"), default=True) + is_open = models.BooleanField(verbose_name=_('is ticket open?'), default=True) class TicketMessage(models.Model): - ticket = models.ForeignKey( - Ticket, - verbose_name=_("ticket"), - related_name="messages", - related_query_name="message", - on_delete=models.CASCADE, - ) - user = models.ForeignKey( - Profile, - verbose_name=_("poster"), - related_name="ticket_messages", - on_delete=models.CASCADE, - ) - body = models.TextField(verbose_name=_("message body")) - time = models.DateTimeField(verbose_name=_("message time"), auto_now_add=True) + ticket = models.ForeignKey(Ticket, verbose_name=_('ticket'), related_name='messages', + related_query_name='message', on_delete=models.CASCADE) + user = models.ForeignKey(Profile, verbose_name=_('poster'), related_name='ticket_messages', + on_delete=models.CASCADE) + body = models.TextField(verbose_name=_('message body')) + time = models.DateTimeField(verbose_name=_('message time'), auto_now_add=True) diff --git a/judge/models/volunteer.py b/judge/models/volunteer.py deleted file mode 100644 index 5d3babd..0000000 --- a/judge/models/volunteer.py +++ /dev/null @@ -1,39 +0,0 @@ -from django.db import models -from django.db.models import CASCADE -from django.utils.translation import gettext_lazy as _ - -from judge.models import Profile, Problem, ProblemType - -__all__ = ["VolunteerProblemVote"] - - -class VolunteerProblemVote(models.Model): - voter = models.ForeignKey( - Profile, related_name="volunteer_problem_votes", on_delete=CASCADE - ) - problem = models.ForeignKey( - Problem, related_name="volunteer_user_votes", on_delete=CASCADE - ) - time = models.DateTimeField(auto_now_add=True) - knowledge_points = models.PositiveIntegerField( - verbose_name=_("knowledge points"), - help_text=_("Points awarded by knowledge difficulty"), - ) - thinking_points = models.PositiveIntegerField( - verbose_name=_("thinking points"), - help_text=_("Points awarded by thinking difficulty"), - ) - types = models.ManyToManyField( - ProblemType, - verbose_name=_("problem types"), - help_text=_("The type of problem, " "as shown on the problem's page."), - ) - feedback = models.TextField(verbose_name=_("feedback"), blank=True) - - class Meta: - verbose_name = _("volunteer vote") - verbose_name_plural = _("volunteer votes") - unique_together = ["voter", "problem"] - - def __str__(self): - return f"{self.voter} for {self.problem.code}" diff --git a/judge/pdf_problems.py b/judge/pdf_problems.py index 4cd4a14..0e9835e 100644 --- a/judge/pdf_problems.py +++ b/judge/pdf_problems.py @@ -1,4 +1,3 @@ -import base64 import errno import io import json @@ -11,21 +10,6 @@ import uuid from django.conf import settings from django.utils.translation import gettext -logger = logging.getLogger("judge.problem.pdf") - -HAS_SELENIUM = False -if settings.USE_SELENIUM: - try: - from selenium import webdriver - from selenium.common.exceptions import TimeoutException - from selenium.webdriver.common.by import By - from selenium.webdriver.support import expected_conditions as EC - from selenium.webdriver.support.ui import WebDriverWait - - HAS_SELENIUM = True - except ImportError: - logger.warning("Failed to import Selenium", exc_info=True) - HAS_PHANTOMJS = os.access(settings.PHANTOMJS, os.X_OK) HAS_SLIMERJS = os.access(settings.SLIMERJS, os.X_OK) @@ -33,30 +17,29 @@ NODE_PATH = settings.NODEJS PUPPETEER_MODULE = settings.PUPPETEER_MODULE HAS_PUPPETEER = os.access(NODE_PATH, os.X_OK) and os.path.isdir(PUPPETEER_MODULE) -HAS_PDF = os.path.isdir(settings.DMOJ_PDF_PROBLEM_CACHE) and ( - HAS_PHANTOMJS or HAS_SLIMERJS or HAS_PUPPETEER or HAS_SELENIUM -) +HAS_PDF = (os.path.isdir(settings.DMOJ_PDF_PROBLEM_CACHE) and + (HAS_PHANTOMJS or HAS_SLIMERJS or HAS_PUPPETEER)) EXIFTOOL = settings.EXIFTOOL HAS_EXIFTOOL = os.access(EXIFTOOL, os.X_OK) +logger = logging.getLogger('judge.problem.pdf') + class BasePdfMaker(object): - math_engine = "jax" + math_engine = 'jax' title = None def __init__(self, dir=None, clean_up=True): - self.dir = dir or os.path.join( - settings.DMOJ_PDF_PROBLEM_TEMP_DIR, str(uuid.uuid1()) - ) + self.dir = dir or os.path.join(settings.DMOJ_PDF_PROBLEM_TEMP_DIR, str(uuid.uuid1())) self.proc = None self.log = None - self.htmlfile = os.path.join(self.dir, "input.html") - self.pdffile = os.path.join(self.dir, "output.pdf") + self.htmlfile = os.path.join(self.dir, 'input.html') + self.pdffile = os.path.join(self.dir, 'output.pdf') self.clean_up = clean_up def load(self, file, source): - with open(os.path.join(self.dir, file), "w") as target, open(source) as source: + with open(os.path.join(self.dir, file), 'w') as target, open(source) as source: target.write(source.read()) def make(self, debug=False): @@ -64,27 +47,21 @@ class BasePdfMaker(object): if self.title and HAS_EXIFTOOL: try: - subprocess.check_output( - [EXIFTOOL, "-Title=%s" % (self.title,), self.pdffile] - ) + subprocess.check_output([EXIFTOOL, '-Title=%s' % (self.title,), self.pdffile]) except subprocess.CalledProcessError as e: - logger.error( - "Failed to run exiftool to set title for: %s\n%s", - self.title, - e.output, - ) + logger.error('Failed to run exiftool to set title for: %s\n%s', self.title, e.output) def _make(self, debug): raise NotImplementedError() @property def html(self): - with io.open(self.htmlfile, encoding="utf-8") as f: + with io.open(self.htmlfile, encoding='utf-8') as f: return f.read() @html.setter def html(self, data): - with io.open(self.htmlfile, "w", encoding="utf-8") as f: + with io.open(self.htmlfile, 'w', encoding='utf-8') as f: f.write(data) @property @@ -109,7 +86,7 @@ class BasePdfMaker(object): class PhantomJSPdfMaker(BasePdfMaker): - template = """\ + template = '''\ "use strict"; var page = require('webpage').create(); var param = {params}; @@ -146,37 +123,29 @@ page.open(param.input, function (status) { }, param.timeout); } }); -""" +''' def get_render_script(self): - return self.template.replace( - "{params}", - json.dumps( - { - "zoom": settings.PHANTOMJS_PDF_ZOOM, - "timeout": int(settings.PHANTOMJS_PDF_TIMEOUT * 1000), - "input": "input.html", - "output": "output.pdf", - "paper": settings.PHANTOMJS_PAPER_SIZE, - "footer": gettext("Page [page] of [topage]"), - } - ), - ) + return self.template.replace('{params}', json.dumps({ + 'zoom': settings.PHANTOMJS_PDF_ZOOM, + 'timeout': int(settings.PHANTOMJS_PDF_TIMEOUT * 1000), + 'input': 'input.html', 'output': 'output.pdf', + 'paper': settings.PHANTOMJS_PAPER_SIZE, + 'footer': gettext('Page [page] of [topage]'), + })) def _make(self, debug): - with io.open(os.path.join(self.dir, "_render.js"), "w", encoding="utf-8") as f: + with io.open(os.path.join(self.dir, '_render.js'), 'w', encoding='utf-8') as f: f.write(self.get_render_script()) - cmdline = [settings.PHANTOMJS, "_render.js"] - self.proc = subprocess.Popen( - cmdline, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=self.dir - ) + cmdline = [settings.PHANTOMJS, '_render.js'] + self.proc = subprocess.Popen(cmdline, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=self.dir) self.log = self.proc.communicate()[0] class SlimerJSPdfMaker(BasePdfMaker): - math_engine = "mml" + math_engine = 'mml' - template = """\ + template = '''\ "use strict"; try { var param = {params}; @@ -207,47 +176,33 @@ try { console.error(e); slimer.exit(1); } -""" +''' def get_render_script(self): - return self.template.replace( - "{params}", - json.dumps( - { - "zoom": settings.SLIMERJS_PDF_ZOOM, - "input": "input.html", - "output": "output.pdf", - "paper": settings.SLIMERJS_PAPER_SIZE, - "footer": gettext("Page [page] of [topage]") - .replace("[page]", "&P") - .replace("[topage]", "&L"), - } - ), - ) + return self.template.replace('{params}', json.dumps({ + 'zoom': settings.SLIMERJS_PDF_ZOOM, + 'input': 'input.html', 'output': 'output.pdf', + 'paper': settings.SLIMERJS_PAPER_SIZE, + 'footer': gettext('Page [page] of [topage]').replace('[page]', '&P').replace('[topage]', '&L'), + })) def _make(self, debug): - with io.open(os.path.join(self.dir, "_render.js"), "w", encoding="utf-8") as f: + with io.open(os.path.join(self.dir, '_render.js'), 'w', encoding='utf-8') as f: f.write(self.get_render_script()) env = None firefox = settings.SLIMERJS_FIREFOX_PATH if firefox: env = os.environ.copy() - env["SLIMERJSLAUNCHER"] = firefox + env['SLIMERJSLAUNCHER'] = firefox - cmdline = [settings.SLIMERJS, "--headless", "_render.js"] - self.proc = subprocess.Popen( - cmdline, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - cwd=self.dir, - env=env, - ) + cmdline = [settings.SLIMERJS, '--headless', '_render.js'] + self.proc = subprocess.Popen(cmdline, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=self.dir, env=env) self.log = self.proc.communicate()[0] class PuppeteerPDFRender(BasePdfMaker): - template = """\ + template = '''\ "use strict"; const param = {params}; const puppeteer = require('puppeteer'); @@ -281,90 +236,30 @@ puppeteer.launch().then(browser => Promise.resolve() console.error(e); process.exit(1); }); -""" +''' def get_render_script(self): - return self.template.replace( - "{params}", - json.dumps( - { - "input": "file://%s" % self.htmlfile, - "output": self.pdffile, - "paper": settings.PUPPETEER_PAPER_SIZE, - "footer": gettext("Page [page] of [topage]"), - } - ), - ) + return self.template.replace('{params}', json.dumps({ + 'input': 'file://' + os.path.abspath(os.path.join(self.dir, 'input.html')), + 'output': os.path.abspath(os.path.join(self.dir, 'output.pdf')), + 'paper': settings.PUPPETEER_PAPER_SIZE, + 'footer': gettext('Page [page] of [topage]'), + })) def _make(self, debug): - with io.open(os.path.join(self.dir, "_render.js"), "w", encoding="utf-8") as f: + with io.open(os.path.join(self.dir, '_render.js'), 'w', encoding='utf-8') as f: f.write(self.get_render_script()) env = os.environ.copy() - env["NODE_PATH"] = os.path.dirname(PUPPETEER_MODULE) + env['NODE_PATH'] = os.path.dirname(PUPPETEER_MODULE) - cmdline = [NODE_PATH, "_render.js"] - self.proc = subprocess.Popen( - cmdline, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - cwd=self.dir, - env=env, - ) + cmdline = [NODE_PATH, '_render.js'] + self.proc = subprocess.Popen(cmdline, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=self.dir, env=env) self.log = self.proc.communicate()[0] -class SeleniumPDFRender(BasePdfMaker): - success = False - template = { - "printBackground": True, - "displayHeaderFooter": True, - "headerTemplate": "
", - "footerTemplate": '
' - + gettext("Page %s of %s") - % ('', '') - + "
", - } - - def get_log(self, driver): - return "\n".join(map(str, driver.get_log("driver") + driver.get_log("browser"))) - - def _make(self, debug): - options = webdriver.ChromeOptions() - options.add_argument("--headless") - options.add_argument("--no-sandbox") # for root - options.binary_location = settings.SELENIUM_CUSTOM_CHROME_PATH - - browser = webdriver.Chrome(settings.SELENIUM_CHROMEDRIVER_PATH, options=options) - browser.get("file://%s" % self.htmlfile) - self.log = self.get_log(browser) - - try: - WebDriverWait(browser, 15).until( - EC.presence_of_element_located((By.CLASS_NAME, "math-loaded")) - ) - except TimeoutException: - logger.error("PDF math rendering timed out") - self.log = self.get_log(browser) + "\nPDF math rendering timed out" - browser.quit() - return - response = browser.execute_cdp_cmd("Page.printToPDF", self.template) - self.log = self.get_log(browser) - if not response: - browser.quit() - return - - with open(self.pdffile, "wb") as f: - f.write(base64.b64decode(response["data"])) - - self.success = True - browser.quit() - - if HAS_PUPPETEER: DefaultPdfMaker = PuppeteerPDFRender -elif HAS_SELENIUM: - DefaultPdfMaker = SeleniumPDFRender elif HAS_SLIMERJS: DefaultPdfMaker = SlimerJSPdfMaker elif HAS_PHANTOMJS: diff --git a/judge/performance_points.py b/judge/performance_points.py index c806081..eee3c10 100644 --- a/judge/performance_points.py +++ b/judge/performance_points.py @@ -6,22 +6,16 @@ from django.db import connection from judge.models import Submission from judge.timezone import from_database_time -PP_WEIGHT_TABLE = [ - pow(settings.DMOJ_PP_STEP, i) for i in range(settings.DMOJ_PP_ENTRIES) -] +PP_WEIGHT_TABLE = [pow(settings.DMOJ_PP_STEP, i) for i in range(settings.DMOJ_PP_ENTRIES)] -PPBreakdown = namedtuple( - "PPBreakdown", - "points weight scaled_points problem_name problem_code " - "sub_id sub_date sub_points sub_total sub_result_class " - "sub_short_status sub_long_status sub_lang", -) +PPBreakdown = namedtuple('PPBreakdown', 'points weight scaled_points problem_name problem_code ' + 'sub_id sub_date sub_points sub_total sub_result_class ' + 'sub_short_status sub_long_status sub_lang') def get_pp_breakdown(user, start=0, end=settings.DMOJ_PP_ENTRIES): with connection.cursor() as cursor: - cursor.execute( - f""" + cursor.execute(''' SELECT max_points_table.problem_code, max_points_table.problem_name, max_points_table.max_points, @@ -32,72 +26,53 @@ def get_pp_breakdown(user, start=0, end=settings.DMOJ_PP_ENTRIES): judge_submission.result, judge_language.short_name, judge_language.key - FROM ( - SELECT judge_problem.id problem_id, - judge_problem.name problem_name, - judge_problem.code problem_code, - MAX(judge_submission.points) AS max_points + FROM judge_submission + JOIN (SELECT judge_problem.id problem_id, + judge_problem.name problem_name, + judge_problem.code problem_code, + MAX(judge_submission.points) AS max_points FROM judge_problem INNER JOIN judge_submission ON (judge_problem.id = judge_submission.problem_id) - WHERE (judge_problem.is_public AND - NOT judge_problem.is_organization_private AND + WHERE (judge_problem.is_public = True AND + judge_problem.is_organization_private = False AND judge_submission.points IS NOT NULL AND judge_submission.user_id = %s) GROUP BY judge_problem.id - HAVING MAX(judge_submission.points) > 0.0 - ) AS max_points_table - INNER JOIN judge_submission ON ( - judge_submission.problem_id = max_points_table.problem_id AND + HAVING MAX(judge_submission.points) > 0.0) AS max_points_table + ON (judge_submission.problem_id = max_points_table.problem_id AND judge_submission.points = max_points_table.max_points AND - judge_submission.user_id = %s - ) - INNER JOIN judge_language ON (judge_submission.language_id = judge_language.id) + judge_submission.user_id = %s) + JOIN judge_language + ON judge_submission.language_id = judge_language.id GROUP BY max_points_table.problem_id ORDER BY max_points DESC, judge_submission.date DESC LIMIT %s OFFSET %s - """, - (user.id, user.id, end - start + 1, start), - ) + ''', (user.id, user.id, end - start + 1, start)) data = cursor.fetchall() breakdown = [] for weight, contrib in zip(PP_WEIGHT_TABLE[start:end], data): - ( - code, - name, - points, - id, - date, - case_points, - case_total, - result, - lang_short_name, - lang_key, - ) = contrib + code, name, points, id, date, case_points, case_total, result, lang_short_name, lang_key = contrib # Replicates a lot of the logic usually done on Submission objects lang_short_display_name = lang_short_name or lang_key - result_class = Submission.result_class_from_code( - result, case_points, case_total - ) - long_status = Submission.USER_DISPLAY_CODES.get(result, "") + result_class = Submission.result_class_from_code(result, case_points, case_total) + long_status = Submission.USER_DISPLAY_CODES.get(result, '') - breakdown.append( - PPBreakdown( - points=points, - weight=weight * 100, - scaled_points=points * weight, - problem_name=name, - problem_code=code, - sub_id=id, - sub_date=from_database_time(date), - sub_points=case_points, - sub_total=case_total, - sub_short_status=result, - sub_long_status=long_status, - sub_result_class=result_class, - sub_lang=lang_short_display_name, - ) - ) + breakdown.append(PPBreakdown( + points=points, + weight=weight * 100, + scaled_points=points * weight, + problem_name=name, + problem_code=code, + sub_id=id, + sub_date=from_database_time(date), + sub_points=case_points, + sub_total=case_total, + sub_short_status=result, + sub_long_status=long_status, + sub_result_class=result_class, + sub_lang=lang_short_display_name, + )) has_more = end < min(len(PP_WEIGHT_TABLE), start + len(data)) return breakdown, has_more diff --git a/judge/ratings.py b/judge/ratings.py index 854bdcb..8fb5ff8 100644 --- a/judge/ratings.py +++ b/judge/ratings.py @@ -1,268 +1,163 @@ +import math from bisect import bisect -from math import pi, sqrt, tanh -from operator import attrgetter, itemgetter +from operator import itemgetter -from django.db import transaction -from django.db.models import Count, OuterRef, Subquery -from django.db.models.functions import Coalesce +from django.db import connection, transaction +from django.db.models import Count from django.utils import timezone -BETA2 = 328.33**2 -RATING_INIT = 1200 # Newcomer's rating when applying the rating floor/ceiling -MEAN_INIT = 1400.0 -VAR_INIT = 250**2 * (BETA2 / 212**2) -SD_INIT = sqrt(VAR_INIT) -VALID_RANGE = MEAN_INIT - 20 * SD_INIT, MEAN_INIT + 20 * SD_INIT -VAR_PER_CONTEST = 1219.047619 * (BETA2 / 212**2) -VAR_LIM = ( - sqrt(VAR_PER_CONTEST**2 + 4 * BETA2 * VAR_PER_CONTEST) - VAR_PER_CONTEST -) / 2 -SD_LIM = sqrt(VAR_LIM) -TANH_C = sqrt(3) / pi +from judge.utils.ranker import tie_ranker -def tie_ranker(iterable, key=attrgetter("points")): - rank = 0 - delta = 1 - last = None - buf = [] - for item in iterable: - new = key(item) - if new != last: - for _ in buf: - yield rank + (delta - 1) / 2.0 - rank += delta - delta = 0 - buf = [] - delta += 1 - buf.append(item) - last = key(item) - for _ in buf: - yield rank + (delta - 1) / 2.0 +def rational_approximation(t): + # Abramowitz and Stegun formula 26.2.23. + # The absolute value of the error should be less than 4.5 e-4. + c = [2.515517, 0.802853, 0.010328] + d = [1.432788, 0.189269, 0.001308] + numerator = (c[2] * t + c[1]) * t + c[0] + denominator = ((d[2] * t + d[1]) * t + d[0]) * t + 1.0 + return t - numerator / denominator -def eval_tanhs(tanh_terms, x): - return sum((wt / sd) * tanh((x - mu) / (2 * sd)) for mu, sd, wt in tanh_terms) +def normal_CDF_inverse(p): + assert 0.0 < p < 1 - -def solve(tanh_terms, y_tg, lin_factor=0, bounds=VALID_RANGE): - L, R = bounds - Ly, Ry = None, None - while R - L > 2: - x = (L + R) / 2 - y = lin_factor * x + eval_tanhs(tanh_terms, x) - if y > y_tg: - R, Ry = x, y - elif y < y_tg: - L, Ly = x, y - else: - return x - # Use linear interpolation to be slightly more accurate. - if Ly is None: - Ly = lin_factor * L + eval_tanhs(tanh_terms, L) - if y_tg <= Ly: - return L - if Ry is None: - Ry = lin_factor * R + eval_tanhs(tanh_terms, R) - if y_tg >= Ry: - return R - ratio = (y_tg - Ly) / (Ry - Ly) - return L * (1 - ratio) + R * ratio - - -def get_var(times_ranked, cache=[VAR_INIT]): - while times_ranked >= len(cache): - next_var = 1.0 / (1.0 / (cache[-1] + VAR_PER_CONTEST) + 1.0 / BETA2) - cache.append(next_var) - return cache[times_ranked] - - -def recalculate_ratings(ranking, old_mean, times_ranked, historical_p): - n = len(ranking) - new_p = [0.0] * n - new_mean = [0.0] * n - - # Note: pre-multiply delta by TANH_C to improve efficiency. - delta = [TANH_C * sqrt(get_var(t) + VAR_PER_CONTEST + BETA2) for t in times_ranked] - p_tanh_terms = [(m, d, 1) for m, d in zip(old_mean, delta)] - - # Calculate performance at index i. - def solve_idx(i, bounds=VALID_RANGE): - r = ranking[i] - y_tg = 0 - for d, s in zip(delta, ranking): - if s > r: # s loses to r - y_tg += 1.0 / d - elif s < r: # s beats r - y_tg -= 1.0 / d - # Otherwise, this is a tie that counts as half a win, as per Elo-MMR. - new_p[i] = solve(p_tanh_terms, y_tg, bounds=bounds) - - # Fill all indices between i and j, inclusive. Use the fact that new_p is non-increasing. - def divconq(i, j): - if j - i > 1: - k = (i + j) // 2 - solve_idx(k, bounds=(new_p[j], new_p[i])) - divconq(i, k) - divconq(k, j) - - if n < 2: - new_p = list(old_mean) - new_mean = list(old_mean) + # See article above for explanation of this section. + if p < 0.5: + # F^-1(p) = - G^-1(p) + return -rational_approximation(math.sqrt(-2.0 * math.log(p))) else: - # Calculate performance. - solve_idx(0) - solve_idx(n - 1) - divconq(0, n - 1) + # F^-1(p) = G^-1(1-p) + return rational_approximation(math.sqrt(-2.0 * math.log(1.0 - p))) - # Calculate mean. - for i, r in enumerate(ranking): - tanh_terms = [] - w_prev = 1.0 - w_sum = 0.0 - for j, h in enumerate([new_p[i]] + historical_p[i]): - gamma2 = VAR_PER_CONTEST if j > 0 else 0 - h_var = get_var(times_ranked[i] + 1 - j) - k = h_var / (h_var + gamma2) - w = w_prev * k**2 - # Future optimization: If j is around 20, then w < 1e-3 and it is possible to break early. - tanh_terms.append((h, sqrt(BETA2) * TANH_C, w)) - w_prev = w - w_sum += w / BETA2 - w0 = 1.0 / get_var(times_ranked[i] + 1) - w_sum - p0 = eval_tanhs(tanh_terms[1:], old_mean[i]) / w0 + old_mean[i] - new_mean[i] = solve(tanh_terms, w0 * p0, lin_factor=w0) - # Display a slightly lower rating to incentivize participation. - # As times_ranked increases, new_rating converges to new_mean. - new_rating = [ - max(1, round(m - (sqrt(get_var(t + 1)) - SD_LIM))) - for m, t in zip(new_mean, times_ranked) - ] +def WP(RA, RB, VA, VB): + return (math.erf((RB - RA) / math.sqrt(2 * (VA * VA + VB * VB))) + 1) / 2.0 - return new_rating, new_mean, new_p + +def recalculate_ratings(old_rating, old_volatility, actual_rank, times_rated): + # actual_rank: 1 is first place, N is last place + # if there are ties, use the average of places (if places 2, 3, 4, 5 tie, use 3.5 for all of them) + + N = len(old_rating) + new_rating = old_rating[:] + new_volatility = old_volatility[:] + if N <= 1: + return new_rating, new_volatility + + ranking = list(range(N)) + ranking.sort(key=old_rating.__getitem__, reverse=True) + + ave_rating = float(sum(old_rating)) / N + sum1 = sum(i * i for i in old_volatility) / N + sum2 = sum((i - ave_rating) ** 2 for i in old_rating) / (N - 1) + CF = math.sqrt(sum1 + sum2) + + for i in range(N): + ERank = 0.5 + for j in range(N): + ERank += WP(old_rating[i], old_rating[j], old_volatility[i], old_volatility[j]) + + EPerf = -normal_CDF_inverse((ERank - 0.5) / N) + APerf = -normal_CDF_inverse((actual_rank[i] - 0.5) / N) + PerfAs = old_rating[i] + CF * (APerf - EPerf) + Weight = 1.0 / (1 - (0.42 / (times_rated[i] + 1) + 0.18)) - 1.0 + if old_rating[i] > 2500: + Weight *= 0.8 + elif old_rating[i] >= 2000: + Weight *= 0.9 + + Cap = 150.0 + 1500.0 / (times_rated[i] + 2) + + new_rating[i] = (old_rating[i] + Weight * PerfAs) / (1.0 + Weight) + + if times_rated[i] == 0: + new_volatility[i] = 385 + else: + new_volatility[i] = math.sqrt(((new_rating[i] - old_rating[i]) ** 2) / Weight + + (old_volatility[i] ** 2) / (Weight + 1)) + if abs(old_rating[i] - new_rating[i]) > Cap: + if old_rating[i] < new_rating[i]: + new_rating[i] = old_rating[i] + Cap + else: + new_rating[i] = old_rating[i] - Cap + + # try to keep the sum of ratings constant + adjust = float(sum(old_rating) - sum(new_rating)) / N + new_rating = list(map(adjust.__add__, new_rating)) + # inflate a little if we have to so people who placed first don't lose rating + best_rank = min(actual_rank) + for i in range(N): + if abs(actual_rank[i] - best_rank) <= 1e-3 and new_rating[i] < old_rating[i] + 1: + new_rating[i] = old_rating[i] + 1 + return list(map(int, map(round, new_rating))), list(map(int, map(round, new_volatility))) def rate_contest(contest): from judge.models import Rating, Profile - from judge.models.profile import _get_basic_info - from judge.utils.users import get_contest_ratings, get_rating_rank - rating_subquery = Rating.objects.filter(user=OuterRef("user")) - rating_sorted = rating_subquery.order_by("-contest__end_time") - users = ( - contest.users.order_by("is_disqualified", "-score", "cumtime", "tiebreaker") - .annotate( - submissions=Count("submission"), - last_rating=Coalesce( - Subquery(rating_sorted.values("rating")[:1]), RATING_INIT - ), - last_mean=Coalesce(Subquery(rating_sorted.values("mean")[:1]), MEAN_INIT), - times=Coalesce( - Subquery( - rating_subquery.order_by() - .values("user_id") - .annotate(count=Count("id")) - .values("count") - ), - 0, - ), - ) - .exclude(user_id__in=contest.rate_exclude.all()) - .filter(virtual=0) - .values( - "id", - "user_id", - "score", - "cumtime", - "tiebreaker", - "last_rating", - "last_mean", - "times", - ) - ) + cursor = connection.cursor() + cursor.execute(''' + SELECT judge_rating.user_id, judge_rating.rating, judge_rating.volatility, r.times + FROM judge_rating INNER JOIN + judge_contest ON (judge_contest.id = judge_rating.contest_id) INNER JOIN ( + SELECT judge_rating.user_id AS id, MAX(judge_contest.end_time) AS last_time, + COUNT(judge_rating.user_id) AS times + FROM judge_contestparticipation INNER JOIN + judge_rating ON (judge_rating.user_id = judge_contestparticipation.user_id) INNER JOIN + judge_contest ON (judge_contest.id = judge_rating.contest_id) + WHERE judge_contestparticipation.contest_id = %s AND judge_contest.end_time < %s AND + judge_contestparticipation.user_id NOT IN ( + SELECT profile_id FROM judge_contest_rate_exclude WHERE contest_id = %s + ) AND judge_contestparticipation.virtual = 0 + GROUP BY judge_rating.user_id + ORDER BY judge_contestparticipation.score DESC, judge_contestparticipation.cumtime ASC + ) AS r ON (judge_rating.user_id = r.id AND judge_contest.end_time = r.last_time) + ''', (contest.id, contest.end_time, contest.id)) + data = {user: (rating, volatility, times) for user, rating, volatility, times in cursor.fetchall()} + cursor.close() + + users = contest.users.order_by('is_disqualified', '-score', 'cumtime').annotate(submissions=Count('submission')) \ + .exclude(user_id__in=contest.rate_exclude.all()).filter(virtual=0, user__is_unlisted=False) \ + .values_list('id', 'user_id', 'score', 'cumtime') if not contest.rate_all: users = users.filter(submissions__gt=0) if contest.rating_floor is not None: - users = users.exclude(last_rating__lt=contest.rating_floor) + users = users.exclude(user__rating__lt=contest.rating_floor) if contest.rating_ceiling is not None: - users = users.exclude(last_rating__gt=contest.rating_ceiling) - - users = list(users) - participation_ids = list(map(itemgetter("id"), users)) - user_ids = list(map(itemgetter("user_id"), users)) - ranking = list(tie_ranker(users, key=itemgetter("score", "cumtime", "tiebreaker"))) - old_mean = list(map(itemgetter("last_mean"), users)) - times_ranked = list(map(itemgetter("times"), users)) - historical_p = [[] for _ in users] - - user_id_to_idx = {uid: i for i, uid in enumerate(user_ids)} - for h in ( - Rating.objects.filter(user_id__in=user_ids) - .order_by("-contest__end_time") - .values("user_id", "performance") - ): - idx = user_id_to_idx[h["user_id"]] - historical_p[idx].append(h["performance"]) - - rating, mean, performance = recalculate_ratings( - ranking, old_mean, times_ranked, historical_p - ) + users = users.exclude(user__rating__gt=contest.rating_ceiling) + users = list(tie_ranker(users, key=itemgetter(2, 3))) + participation_ids = [user[1][0] for user in users] + user_ids = [user[1][1] for user in users] + ranking = list(map(itemgetter(0), users)) + old_data = [data.get(user, (1200, 535, 0)) for user in user_ids] + old_rating = list(map(itemgetter(0), old_data)) + old_volatility = list(map(itemgetter(1), old_data)) + times_ranked = list(map(itemgetter(2), old_data)) + rating, volatility = recalculate_ratings(old_rating, old_volatility, ranking, times_ranked) now = timezone.now() - ratings = [ - Rating( - user_id=i, - contest=contest, - rating=r, - mean=m, - performance=perf, - last_rated=now, - participation_id=pid, - rank=z, - ) - for i, pid, r, m, perf, z in zip( - user_ids, participation_ids, rating, mean, performance, ranking - ) - ] + ratings = [Rating(user_id=id, contest=contest, rating=r, volatility=v, last_rated=now, participation_id=p, rank=z) + for id, p, r, v, z in zip(user_ids, participation_ids, rating, volatility, ranking)] + cursor = connection.cursor() + cursor.execute('CREATE TEMPORARY TABLE _profile_rating_update(id integer, rating integer)') + cursor.executemany('INSERT INTO _profile_rating_update VALUES (%s, %s)', list(zip(user_ids, rating))) with transaction.atomic(): + Rating.objects.filter(contest=contest).delete() Rating.objects.bulk_create(ratings) - - Profile.objects.filter( - contest_history__contest=contest, contest_history__virtual=0 - ).update( - rating=Subquery( - Rating.objects.filter(user=OuterRef("id")) - .order_by("-contest__end_time") - .values("rating")[:1] - ) - ) - - _get_basic_info.dirty_multi([(uid,) for uid in user_ids]) - get_contest_ratings.dirty_multi([(uid,) for uid in user_ids]) - get_rating_rank.dirty_multi([(uid,) for uid in user_ids]) + cursor.execute(''' + UPDATE `%s` p INNER JOIN `_profile_rating_update` tmp ON (p.id = tmp.id) + SET p.rating = tmp.rating + ''' % Profile._meta.db_table) + cursor.execute('DROP TABLE _profile_rating_update') + cursor.close() + return old_rating, old_volatility, ranking, times_ranked, rating, volatility -RATING_LEVELS = [ - "Newbie", - "Amateur", - "Expert", - "Candidate Master", - "Master", - "Grandmaster", - "Target", -] -RATING_VALUES = [1000, 1400, 1700, 1900, 2100, 2400, 3000] -RATING_CLASS = [ - "rate-newbie", - "rate-amateur", - "rate-specialist", - "rate-expert", - "rate-candidate-master", - "rate-master", - "rate-grandmaster", - "rate-target", -] +RATING_LEVELS = ['Newbie', 'Amateur', 'Expert', 'Candidate Master', 'Master', 'Grandmaster', 'Target'] +RATING_VALUES = [1000, 1200, 1500, 1800, 2200, 3000] +RATING_CLASS = ['rate-newbie', 'rate-amateur', 'rate-expert', 'rate-candidate-master', + 'rate-master', 'rate-grandmaster', 'rate-target'] def rating_level(rating): diff --git a/judge/scripts/migrate_organization_image.py b/judge/scripts/migrate_organization_image.py deleted file mode 100644 index 9134d21..0000000 --- a/judge/scripts/migrate_organization_image.py +++ /dev/null @@ -1,64 +0,0 @@ -# Download organization images from "logo_override_image" and upload to organization_images folder to use "organization_image" -# In folder online_judge, run python3 manage.py shell < judge/scripts/migrate_organization_image.py - -import os -import requests -from urllib.parse import urlparse -from django.core.files.base import ContentFile -from django.core.files.storage import default_storage -from django.conf import settings -from django.db import transaction -from judge.models import Organization - - -def is_valid_image_url(url): - try: - parsed_url = urlparse(url) - _, ext = os.path.splitext(parsed_url.path) - return ext.lower() in [".jpg", ".jpeg", ".png", ".gif", ".svg"] - except Exception as e: - return False - - -def download_image(url): - response = requests.get(url) - response.raise_for_status() - return ContentFile(response.content) - - -def organization_image_path(organization, filename): - tail = filename.split(".")[-1] - new_filename = f"organization_{organization.id}.{tail}" - return os.path.join(settings.DMOJ_ORGANIZATION_IMAGE_ROOT, new_filename) - - -@transaction.atomic -def migrate_images(): - print("Start") - organizations = Organization.objects.all() - for org in organizations: - if org.logo_override_image: - if is_valid_image_url(org.logo_override_image): - try: - # Download the image - image_content = download_image(org.logo_override_image) - # Determine the file extension - file_ext = org.logo_override_image.split(".")[-1] - filename = f"organization_{org.id}.{file_ext}" - # Save the image to the new location - new_path = organization_image_path(org, filename) - saved_path = default_storage.save(new_path, image_content) - # Update the organization_image field - org.organization_image = saved_path - org.save() - print(f"Image for organization {org.id} migrated successfully.") - except Exception as e: - print(f"Failed to migrate image for organization {org.id}: {e}") - else: - print( - f"Invalid image URL for organization {org.id}: {org.logo_override_image}" - ) - print("Finish") - - -migrate_images() diff --git a/judge/signals.py b/judge/signals.py index c482c1f..e03c17c 100644 --- a/judge/signals.py +++ b/judge/signals.py @@ -8,26 +8,9 @@ from django.core.cache.utils import make_template_fragment_key from django.db.models.signals import post_delete, post_save from django.dispatch import receiver -import judge -from judge import template_context -from judge.utils.problems import finished_submission -from .models import ( - BlogPost, - Comment, - Contest, - ContestSubmission, - Judge, - Language, - License, - MiscConfig, - Organization, - Problem, - Profile, - Submission, - NavigationBar, - Solution, - ContestProblem, -) +from .caching import finished_submission +from .models import BlogPost, Comment, Contest, ContestSubmission, EFFECTIVE_MATH_ENGINES, Judge, Language, License, \ + MiscConfig, Organization, Problem, Profile, Submission def get_pdf_path(basename): @@ -44,89 +27,75 @@ def unlink_if_exists(file): @receiver(post_save, sender=Problem) def problem_update(sender, instance, **kwargs): - if hasattr(instance, "_updating_stats_only"): + if hasattr(instance, '_updating_stats_only'): return - cache.delete_many( - [ - make_template_fragment_key("submission_problem", (instance.id,)), - "problem_tls:%s" % instance.id, - "problem_mls:%s" % instance.id, - ] - ) - cache.delete_many( - [ - make_template_fragment_key("problem_html", (instance.id, lang)) - for lang, _ in settings.LANGUAGES - ] - ) - cache.delete_many( - [ - "generated-meta-problem:%s:%d" % (lang, instance.id) - for lang, _ in settings.LANGUAGES - ] - ) - Problem.get_authors.dirty(instance) + cache.delete_many([ + make_template_fragment_key('submission_problem', (instance.id,)), + make_template_fragment_key('problem_feed', (instance.id,)), + 'problem_tls:%s' % instance.id, 'problem_mls:%s' % instance.id, + ]) + cache.delete_many([make_template_fragment_key('problem_html', (instance.id, engine, lang)) + for lang, _ in settings.LANGUAGES for engine in EFFECTIVE_MATH_ENGINES]) + cache.delete_many([make_template_fragment_key('problem_authors', (instance.id, lang)) + for lang, _ in settings.LANGUAGES]) + cache.delete_many(['generated-meta-problem:%s:%d' % (lang, instance.id) for lang, _ in settings.LANGUAGES]) for lang, _ in settings.LANGUAGES: - unlink_if_exists(get_pdf_path("%s.%s.pdf" % (instance.code, lang))) + unlink_if_exists(get_pdf_path('%s.%s.pdf' % (instance.code, lang))) @receiver(post_save, sender=Profile) def profile_update(sender, instance, **kwargs): - judge.utils.users.get_points_rank.dirty(instance.id) - judge.utils.users.get_rating_rank.dirty(instance.id) - if hasattr(instance, "_updating_stats_only"): + if hasattr(instance, '_updating_stats_only'): return - cache.delete_many( - [make_template_fragment_key("user_about", (instance.id,))] - + [ - make_template_fragment_key("org_member_count", (org_id,)) - for org_id in instance.organizations.values_list("id", flat=True) - ] - ) - - judge.models.profile._get_basic_info.dirty(instance.id) + cache.delete_many([make_template_fragment_key('user_about', (instance.id, engine)) + for engine in EFFECTIVE_MATH_ENGINES] + + [make_template_fragment_key('org_member_count', (org_id,)) + for org_id in instance.organizations.values_list('id', flat=True)]) @receiver(post_save, sender=Contest) def contest_update(sender, instance, **kwargs): - if hasattr(instance, "_updating_stats_only"): + if hasattr(instance, '_updating_stats_only'): return - cache.delete_many( - ["generated-meta-contest:%d" % instance.id] - + [make_template_fragment_key("contest_html", (instance.id,))] - ) + cache.delete_many(['generated-meta-contest:%d' % instance.id] + + [make_template_fragment_key('contest_html', (instance.id, engine)) + for engine in EFFECTIVE_MATH_ENGINES]) @receiver(post_save, sender=License) def license_update(sender, instance, **kwargs): - cache.delete(make_template_fragment_key("license_html", (instance.id,))) + cache.delete(make_template_fragment_key('license_html', (instance.id,))) @receiver(post_save, sender=Language) def language_update(sender, instance, **kwargs): - cache.delete_many( - [make_template_fragment_key("language_html", (instance.id,)), "lang:cn_map"] - ) + cache.delete_many([make_template_fragment_key('language_html', (instance.id,)), + 'lang:cn_map']) @receiver(post_save, sender=Judge) def judge_update(sender, instance, **kwargs): - cache.delete(make_template_fragment_key("judge_html", (instance.id,))) + cache.delete(make_template_fragment_key('judge_html', (instance.id,))) @receiver(post_save, sender=Comment) def comment_update(sender, instance, **kwargs): - cache.delete("comment_feed:%d" % instance.id) + cache.delete('comment_feed:%d' % instance.id) @receiver(post_save, sender=BlogPost) def post_update(sender, instance, **kwargs): - cache.delete(make_template_fragment_key("post_content", (instance.id,))) - BlogPost.get_authors.dirty(instance) + cache.delete_many([ + make_template_fragment_key('post_summary', (instance.id,)), + 'blog_slug:%d' % instance.id, + 'blog_feed:%d' % instance.id, + ]) + cache.delete_many([make_template_fragment_key('post_content', (instance.id, engine)) + for engine in EFFECTIVE_MATH_ENGINES]) @receiver(post_delete, sender=Submission) @@ -143,44 +112,21 @@ def contest_submission_delete(sender, instance, **kwargs): @receiver(post_save, sender=Organization) def organization_update(sender, instance, **kwargs): - cache.delete_many([make_template_fragment_key("organization_html", (instance.id,))]) - Organization.get_admin_ids.dirty(instance) + cache.delete_many([make_template_fragment_key('organization_html', (instance.id, engine)) + for engine in EFFECTIVE_MATH_ENGINES]) _misc_config_i18n = [code for code, _ in settings.LANGUAGES] -_misc_config_i18n.append("") +_misc_config_i18n.append('') @receiver(post_save, sender=MiscConfig) def misc_config_update(sender, instance, **kwargs): - cache.delete_many( - [ - "misc_config:%s:%s:%s" % (domain, lang, instance.key.split(".")[0]) - for lang in _misc_config_i18n - for domain in Site.objects.values_list("domain", flat=True) - ] - ) + cache.delete_many(['misc_config:%s:%s:%s' % (domain, lang, instance.key.split('.')[0]) + for lang in _misc_config_i18n + for domain in Site.objects.values_list('domain', flat=True)]) @receiver(post_save, sender=ContestSubmission) def contest_submission_update(sender, instance, **kwargs): - Submission.objects.filter(id=instance.submission_id).update( - contest_object_id=instance.participation.contest_id - ) - - -@receiver(post_save, sender=NavigationBar) -def navbar_update(sender, instance, **kwargs): - template_context._nav_bar.dirty() - - -@receiver(post_save, sender=Solution) -def solution_update(sender, instance, **kwargs): - cache.delete(make_template_fragment_key("solution_content", (instance.id,))) - - -@receiver(post_delete, sender=ContestProblem) -def contest_problem_delete(sender, instance, **kwargs): - Submission.objects.filter( - contest_object=instance.contest, contest__isnull=True - ).update(contest_object=None) + Submission.objects.filter(id=instance.submission_id).update(contest_object_id=instance.participation.contest_id) diff --git a/judge/sitemap.py b/judge/sitemap.py index dd71525..5678d76 100644 --- a/judge/sitemap.py +++ b/judge/sitemap.py @@ -7,83 +7,79 @@ from judge.models import BlogPost, Contest, Organization, Problem, Solution class ProblemSitemap(Sitemap): - changefreq = "daily" + changefreq = 'daily' priority = 0.8 def items(self): - return Problem.get_public_problems().values_list("code") + return Problem.objects.filter(is_public=True, is_organization_private=False).values_list('code') def location(self, obj): - return reverse("problem_detail", args=obj) + return reverse('problem_detail', args=obj) class UserSitemap(Sitemap): - changefreq = "hourly" + changefreq = 'hourly' priority = 0.5 def items(self): - return User.objects.values_list("username") + return User.objects.values_list('username') def location(self, obj): - return reverse("user_page", args=obj) + return reverse('user_page', args=obj) class ContestSitemap(Sitemap): - changefreq = "hourly" + changefreq = 'hourly' priority = 0.5 def items(self): - return Contest.objects.filter( - is_visible=True, is_private=False, is_organization_private=False - ).values_list("key") + return Contest.objects.filter(is_visible=True, is_private=False, + is_organization_private=False).values_list('key') def location(self, obj): - return reverse("contest_view", args=obj) + return reverse('contest_view', args=obj) class OrganizationSitemap(Sitemap): - changefreq = "hourly" + changefreq = 'hourly' priority = 0.5 def items(self): - return Organization.objects.values_list("id", "slug") + return Organization.objects.values_list('id', 'slug') def location(self, obj): - return reverse("organization_home", args=obj) + return reverse('organization_home', args=obj) class BlogPostSitemap(Sitemap): - changefreq = "hourly" + changefreq = 'hourly' priority = 0.7 def items(self): - return BlogPost.objects.filter( - visible=True, is_organization_private=False, publish_on__lte=timezone.now() - ).values_list("id", "slug") + return BlogPost.objects.filter(visible=True, publish_on__lte=timezone.now()).values_list('id', 'slug') def location(self, obj): - return reverse("blog_post", args=obj) + return reverse('blog_post', args=obj) class SolutionSitemap(Sitemap): - changefreq = "hourly" + changefreq = 'hourly' priority = 0.8 def items(self): - return Solution.objects.filter( - is_public=True, publish_on__lte=timezone.now(), problem__isnull=False - ).values_list("problem__code") + return (Solution.objects.filter(is_public=True, publish_on__lte=timezone.now(), problem__isnull=False) + .values_list('problem__code')) def location(self, obj): - return reverse("problem_editorial", args=obj) + return reverse('problem_editorial', args=obj) class HomePageSitemap(Sitemap): priority = 1.0 - changefreq = "daily" + changefreq = 'daily' def items(self): - return ["home"] + return ['home'] def location(self, obj): return reverse(obj) @@ -97,10 +93,10 @@ class UrlSitemap(Sitemap): return self.pages def location(self, obj): - return obj["location"] if isinstance(obj, dict) else obj + return obj['location'] if isinstance(obj, dict) else obj def priority(self, obj): - return obj.get("priority", 0.5) if isinstance(obj, dict) else 0.5 + return obj.get('priority', 0.5) if isinstance(obj, dict) else 0.5 def changefreq(self, obj): - return obj.get("changefreq", "daily") if isinstance(obj, dict) else "daily" + return obj.get('changefreq', 'daily') if isinstance(obj, dict) else 'daily' diff --git a/judge/social_auth.py b/judge/social_auth.py index 3f3bdcd..b6c5e10 100644 --- a/judge/social_auth.py +++ b/judge/social_auth.py @@ -9,71 +9,58 @@ from django.db import transaction from django.http import HttpResponseRedirect from django.shortcuts import render from django.urls import reverse -from django.utils.translation import gettext as _ from requests import HTTPError from reversion import revisions from social_core.backends.github import GithubOAuth2 from social_core.exceptions import InvalidEmail, SocialAuthBaseException from social_core.pipeline.partial import partial -from social_django.middleware import ( - SocialAuthExceptionMiddleware as OldSocialAuthExceptionMiddleware, -) +from social_django.middleware import SocialAuthExceptionMiddleware as OldSocialAuthExceptionMiddleware from judge.forms import ProfileForm from judge.models import Language, Profile -logger = logging.getLogger("judge.social_auth") +logger = logging.getLogger('judge.social_auth') class GitHubSecureEmailOAuth2(GithubOAuth2): - name = "github-secure" + name = 'github-secure' def user_data(self, access_token, *args, **kwargs): data = self._user_data(access_token) try: - emails = self._user_data(access_token, "/emails") + emails = self._user_data(access_token, '/emails') except (HTTPError, ValueError, TypeError): emails = [] - emails = [ - (e.get("email"), e.get("primary"), 0) - for e in emails - if isinstance(e, dict) and e.get("verified") - ] + emails = [(e.get('email'), e.get('primary'), 0) for e in emails if isinstance(e, dict) and e.get('verified')] emails.sort(key=itemgetter(1), reverse=True) emails = list(map(itemgetter(0), emails)) if emails: - data["email"] = emails[0] + data['email'] = emails[0] else: - data["email"] = None + data['email'] = None return data -def slugify_username(username, renotword=re.compile(r"[^\w]")): - return renotword.sub("", username.replace("-", "_")) +def slugify_username(username, renotword=re.compile(r'[^\w]')): + return renotword.sub('', username.replace('-', '_')) def verify_email(backend, details, *args, **kwargs): - if not details["email"]: + if not details['email']: raise InvalidEmail(backend) class UsernameForm(forms.Form): - username = forms.RegexField( - regex=r"^\w+$", - max_length=30, - label="Username", - error_messages={ - "invalid": _("A username must contain letters, numbers, or underscores") - }, - ) + username = forms.RegexField(regex=r'^\w+$', max_length=30, label='Username', + error_messages={'invalid': 'A username must contain letters, numbers, or underscores'}) def clean_username(self): - if User.objects.filter(username=self.cleaned_data["username"]).exists(): - raise forms.ValidationError(_("Sorry, the username is taken.")) - return self.cleaned_data["username"] + if User.objects.filter(username=self.cleaned_data['username']).exists(): + raise forms.ValidationError('Sorry, the username is taken.') + return self.cleaned_data['username'] @partial @@ -83,26 +70,21 @@ def choose_username(backend, user, username=None, *args, **kwargs): if request.POST: form = UsernameForm(request.POST) if form.is_valid(): - return {"username": form.cleaned_data["username"]} + return {'username': form.cleaned_data['username']} else: - form = UsernameForm(initial={"username": username}) - return render( - request, - "registration/username_select.html", - { - "title": _("Choose a username"), - "form": form, - }, - ) + form = UsernameForm(initial={'username': username}) + return render(request, 'registration/username_select.html', { + 'title': 'Choose a username', 'form': form, + }) @partial def make_profile(backend, user, response, is_new=False, *args, **kwargs): if is_new: - if not hasattr(user, "profile"): + if not hasattr(user, 'profile'): profile = Profile(user=user) - profile.language = Language.get_default_language() - logger.info("Info from %s: %s", backend.name, response) + profile.language = Language.get_python3() + logger.info('Info from %s: %s', backend.name, response) profile.save() form = ProfileForm(instance=profile, user=user) else: @@ -113,25 +95,15 @@ def make_profile(backend, user, response, is_new=False, *args, **kwargs): with transaction.atomic(), revisions.create_revision(): form.save() revisions.set_user(user) - revisions.set_comment("Updated on registration") + revisions.set_comment('Updated on registration') return - return render( - backend.strategy.request, - "registration/profile_creation.html", - { - "title": _("Create your profile"), - "form": form, - }, - ) + return render(backend.strategy.request, 'registration/profile_creation.html', { + 'title': 'Create your profile', 'form': form, + }) class SocialAuthExceptionMiddleware(OldSocialAuthExceptionMiddleware): def process_exception(self, request, exception): if isinstance(exception, SocialAuthBaseException): - return HttpResponseRedirect( - "%s?message=%s" - % ( - reverse("social_auth_error"), - quote(self.get_message(request, exception)), - ) - ) + return HttpResponseRedirect('%s?message=%s' % (reverse('social_auth_error'), + quote(self.get_message(request, exception)))) diff --git a/judge/tasks/__init__.py b/judge/tasks/__init__.py index 90fd6d3..e2ad1f2 100644 --- a/judge/tasks/__init__.py +++ b/judge/tasks/__init__.py @@ -1,4 +1,3 @@ -from judge.tasks.contest import * from judge.tasks.demo import * -from judge.tasks.contest import * +from judge.tasks.moss import * from judge.tasks.submission import * diff --git a/judge/tasks/contest.py b/judge/tasks/contest.py deleted file mode 100644 index beaf2d5..0000000 --- a/judge/tasks/contest.py +++ /dev/null @@ -1,104 +0,0 @@ -from celery import shared_task -from django.conf import settings -from django.core.exceptions import ImproperlyConfigured -from django.utils.translation import gettext as _ -from moss import MOSS - -from judge.models import Contest, ContestMoss, ContestParticipation, Submission -from judge.utils.celery import Progress - -__all__ = ("rescore_contest", "run_moss") - - -@shared_task(bind=True) -def rescore_contest(self, contest_key): - contest = Contest.objects.get(key=contest_key) - participations = contest.users - - rescored = 0 - with Progress( - self, participations.count(), stage=_("Recalculating contest scores") - ) as p: - for participation in participations.iterator(): - for contest_submission in participation.submissions.iterator(): - submission = contest_submission.submission - contest_problem = contest_submission.problem - contest_submission.points = round( - submission.case_points - / submission.case_total - * contest_problem.points - if submission.case_total > 0 - else 0, - 3, - ) - if ( - not contest_problem.partial - and contest_submission.points != contest_problem.points - ): - contest_submission.points = 0 - contest_submission.save() - participation.recompute_results() - rescored += 1 - if rescored % 10 == 0: - p.done = rescored - return rescored - - -@shared_task(bind=True) -def run_moss(self, contest_key): - moss_api_key = settings.MOSS_API_KEY - if moss_api_key is None: - raise ImproperlyConfigured("No MOSS API Key supplied") - - contest = Contest.objects.get(key=contest_key) - ContestMoss.objects.filter(contest=contest).delete() - - length = len(ContestMoss.LANG_MAPPING) * contest.problems.count() - moss_results = [] - - with Progress(self, length, stage=_("Running MOSS")) as p: - for problem in contest.problems.all(): - for dmoj_lang, moss_lang in ContestMoss.LANG_MAPPING: - result = ContestMoss( - contest=contest, problem=problem, language=dmoj_lang - ) - - subs = ( - Submission.objects.filter( - contest__participation__virtual__in=( - ContestParticipation.LIVE, - ContestParticipation.SPECTATE, - ), - contest_object=contest, - problem=problem, - language__common_name=dmoj_lang, - ) - .order_by("-points") - .values_list("user__user__username", "source__source") - ) - - if subs.exists(): - moss_call = MOSS( - moss_api_key, - language=moss_lang, - matching_file_limit=100, - comment="%s - %s" % (contest.key, problem.code), - ) - - users = set() - - for username, source in subs: - if username in users: - continue - users.add(username) - moss_call.add_file_from_memory(username, source.encode("utf-8")) - - result.url = moss_call.process() - result.submission_count = len(users) - - moss_results.append(result) - p.did(1) - - ContestMoss.objects.bulk_create(moss_results) - - return len(moss_results) diff --git a/judge/tasks/demo.py b/judge/tasks/demo.py index bd97401..c09dcbf 100644 --- a/judge/tasks/demo.py +++ b/judge/tasks/demo.py @@ -4,7 +4,7 @@ from celery import shared_task from judge.utils.celery import Progress -__all__ = ("success", "failure", "progress") +__all__ = ('success', 'failure', 'progress') @shared_task @@ -14,7 +14,7 @@ def success(): @shared_task def failure(): - raise RuntimeError("This task always fails.") + raise RuntimeError('This task always fails.') @shared_task(bind=True) diff --git a/judge/tasks/experiment.py b/judge/tasks/experiment.py deleted file mode 100644 index 978c643..0000000 --- a/judge/tasks/experiment.py +++ /dev/null @@ -1,21 +0,0 @@ -from judge.models import SubmissionTestCase, Problem - -from collections import defaultdict - - -def generate_report(problem): - testcases = SubmissionTestCase.objects.filter(submission__problem=problem).all() - - score = defaultdict(int) - total = defaultdict(int) - rate = defaultdict(int) - - for case in testcases.iterator(): - score[case.case] += int(case.status == "AC") - total[case.case] += 1 - - for i in score: - rate[i] = score[i] / total[i] - - for i, _ in sorted(rate.items(), key=lambda x: x[1], reverse=True): - print(i, score[i], total[i], rate[i]) diff --git a/judge/tasks/import_users.py b/judge/tasks/import_users.py deleted file mode 100644 index 07acd4e..0000000 --- a/judge/tasks/import_users.py +++ /dev/null @@ -1,115 +0,0 @@ -import csv -import re - -from django.conf import settings -from django.contrib.auth.models import User - -from judge.models import Profile, Language, Organization - - -fields = ["username", "password", "name", "school", "email", "organizations"] -descriptions = [ - "my_username(edit old one if exist)", - "123456 (must have)", - "Le Van A (can be empty)", - "Le Quy Don (can be empty)", - "email@email.com (can be empty)", - "org1&org2&org3&... (can be empty - org slug in URL)", -] - - -def csv_to_dict(csv_file): - rows = csv.reader(csv_file.read().decode().split("\n")) - header = next(rows) - header = [i.lower() for i in header] - - if "username" not in header: - return [] - - res = [] - - for row in rows: - if len(row) != len(header): - continue - cur_dict = {i: "" for i in fields} - for i in range(len(header)): - if header[i] not in fields: - continue - cur_dict[header[i]] = row[i] - if cur_dict["username"]: - res.append(cur_dict) - return res - - -def is_valid_username(username): - match = re.match(r"\w+", username) - return match is not None and match.group() == username - - -# return result log -def import_users(users): - log = "" - for i, row in enumerate(users): - cur_log = str(i + 1) + ". " - - username = row["username"] - if not is_valid_username(username): - log += username + ": Invalid username\n" - continue - - cur_log += username + ": " - pwd = row["password"] - user, created = User.objects.get_or_create( - username=username, - defaults={ - "is_active": True, - }, - ) - profile, _ = Profile.objects.get_or_create( - user=user, - defaults={ - "language": Language.get_python3(), - "timezone": settings.DEFAULT_USER_TIME_ZONE, - }, - ) - - if created: - cur_log += "Create new - " - else: - cur_log += "Edit - " - - if pwd: - user.set_password(pwd) - elif created: - user.set_password("lqdoj") - cur_log += "Missing password, set password = lqdoj - " - - if "name" in row.keys() and row["name"]: - user.first_name = row["name"] - - if "school" in row.keys() and row["school"]: - user.last_name = row["school"] - - if row["organizations"]: - orgs = row["organizations"].split("&") - added_orgs = [] - for o in orgs: - try: - org = Organization.objects.get(slug=o) - profile.organizations.add(org) - added_orgs.append(org.name) - except Organization.DoesNotExist: - continue - if added_orgs: - cur_log += "Added to " + ", ".join(added_orgs) + " - " - - if row["email"]: - user.email = row["email"] - - user.save() - profile.save() - cur_log += "Saved\n" - log += cur_log - log += "FINISH" - - return log diff --git a/judge/tasks/moss.py b/judge/tasks/moss.py new file mode 100644 index 0000000..66a4119 --- /dev/null +++ b/judge/tasks/moss.py @@ -0,0 +1,57 @@ +from celery import shared_task +from django.conf import settings +from django.core.exceptions import ImproperlyConfigured +from django.utils.translation import gettext as _ +from moss import MOSS + +from judge.models import Contest, ContestMoss, ContestParticipation, Submission +from judge.utils.celery import Progress + +__all__ = ('run_moss',) + + +@shared_task(bind=True) +def run_moss(self, contest_key): + moss_api_key = settings.MOSS_API_KEY + if moss_api_key is None: + raise ImproperlyConfigured('No MOSS API Key supplied') + + contest = Contest.objects.get(key=contest_key) + ContestMoss.objects.filter(contest=contest).delete() + + length = len(ContestMoss.LANG_MAPPING) * contest.problems.count() + moss_results = [] + + with Progress(self, length, stage=_('Running MOSS')) as p: + for problem in contest.problems.all(): + for dmoj_lang, moss_lang in ContestMoss.LANG_MAPPING: + result = ContestMoss(contest=contest, problem=problem, language=dmoj_lang) + + subs = Submission.objects.filter( + contest__participation__virtual__in=(ContestParticipation.LIVE, ContestParticipation.SPECTATE), + contest_object=contest, + problem=problem, + language__common_name=dmoj_lang, + ).order_by('-points').values_list('user__user__username', 'source__source') + + if subs.exists(): + moss_call = MOSS(moss_api_key, language=moss_lang, matching_file_limit=100, + comment='%s - %s' % (contest.key, problem.code)) + + users = set() + + for username, source in subs: + if username in users: + continue + users.add(username) + moss_call.add_file_from_memory(username, source.encode('utf-8')) + + result.url = moss_call.process() + result.submission_count = len(users) + + moss_results.append(result) + p.did(1) + + ContestMoss.objects.bulk_create(moss_results) + + return len(moss_results) diff --git a/judge/tasks/submission.py b/judge/tasks/submission.py index 5333dba..a11de8c 100644 --- a/judge/tasks/submission.py +++ b/judge/tasks/submission.py @@ -5,10 +5,10 @@ from django.utils.translation import gettext as _ from judge.models import Problem, Profile, Submission from judge.utils.celery import Progress -__all__ = ("apply_submission_filter", "rejudge_problem_filter", "rescore_problem") +__all__ = ('apply_submission_filter', 'rejudge_problem_filter', 'rescore_problem') -def apply_submission_filter(queryset, id_range, languages, results, contests): +def apply_submission_filter(queryset, id_range, languages, results): if id_range: start, end = id_range queryset = queryset.filter(id__gte=start, id__lte=end) @@ -16,18 +16,14 @@ def apply_submission_filter(queryset, id_range, languages, results, contests): queryset = queryset.filter(language_id__in=languages) if results: queryset = queryset.filter(result__in=results) - if contests: - queryset = queryset.filter(contest_object__in=contests) queryset = queryset.exclude(status__in=Submission.IN_PROGRESS_GRADING_STATUS) return queryset @shared_task(bind=True) -def rejudge_problem_filter( - self, problem_id, id_range=None, languages=None, results=None, contest=None -): +def rejudge_problem_filter(self, problem_id, id_range=None, languages=None, results=None): queryset = Submission.objects.filter(problem_id=problem_id) - queryset = apply_submission_filter(queryset, id_range, languages, results, contest) + queryset = apply_submission_filter(queryset, id_range, languages, results) rejudged = 0 with Progress(self, queryset.count()) as p: @@ -44,37 +40,27 @@ def rescore_problem(self, problem_id): problem = Problem.objects.get(id=problem_id) submissions = Submission.objects.filter(problem_id=problem_id) - with Progress(self, submissions.count(), stage=_("Modifying submissions")) as p: + with Progress(self, submissions.count(), stage=_('Modifying submissions')) as p: rescored = 0 for submission in submissions.iterator(): - submission.points = round( - submission.case_points / submission.case_total * problem.points - if submission.case_total - else 0, - 1, - ) + submission.points = round(submission.case_points / submission.case_total * problem.points + if submission.case_total else 0, 1) if not problem.partial and submission.points < problem.points: submission.points = 0 - submission.save(update_fields=["points"]) + submission.save(update_fields=['points']) submission.update_contest() rescored += 1 if rescored % 10 == 0: p.done = rescored - with Progress( - self, - submissions.values("user_id").distinct().count(), - stage=_("Recalculating user points"), - ) as p: + with Progress(self, submissions.values('user_id').distinct().count(), stage=_('Recalculating user points')) as p: users = 0 - profiles = Profile.objects.filter( - id__in=submissions.values_list("user_id", flat=True).distinct() - ) + profiles = Profile.objects.filter(id__in=submissions.values_list('user_id', flat=True).distinct()) for profile in profiles.iterator(): profile._updating_stats_only = True profile.calculate_points() - cache.delete("user_complete:%d" % profile.id) - cache.delete("user_attempted:%d" % profile.id) + cache.delete('user_complete:%d' % profile.id) + cache.delete('user_attempted:%d' % profile.id) users += 1 if users % 10 == 0: p.done = users diff --git a/judge/template_context.py b/judge/template_context.py index 337d32a..6348407 100644 --- a/judge/template_context.py +++ b/judge/template_context.py @@ -1,4 +1,3 @@ -import re from functools import partial from django.conf import settings @@ -7,34 +6,31 @@ from django.contrib.sites.shortcuts import get_current_site from django.core.cache import cache from django.utils.functional import SimpleLazyObject, new_method_proxy -from mptt.querysets import TreeQuerySet - +from judge.utils.caniuse import CanIUse, SUPPORT from .models import MiscConfig, NavigationBar, Profile -from judge.caching import cache_wrapper class FixedSimpleLazyObject(SimpleLazyObject): - if not hasattr(SimpleLazyObject, "__iter__"): + if not hasattr(SimpleLazyObject, '__iter__'): __iter__ = new_method_proxy(iter) def get_resource(request): use_https = settings.DMOJ_SSL if use_https == 1: - scheme = "https" if request.is_secure() else "http" + scheme = 'https' if request.is_secure() else 'http' elif use_https > 1: - scheme = "https" + scheme = 'https' else: - scheme = "http" - + scheme = 'http' return { - "INLINE_JQUERY": settings.INLINE_JQUERY, - "INLINE_FONTAWESOME": settings.INLINE_FONTAWESOME, - "JQUERY_JS": settings.JQUERY_JS, - "FONTAWESOME_CSS": settings.FONTAWESOME_CSS, - "DMOJ_SCHEME": scheme, - "DMOJ_CANONICAL": settings.DMOJ_CANONICAL, - "use_darkmode": request.session.get("darkmode", False) == True, + 'PYGMENT_THEME': settings.PYGMENT_THEME, + 'INLINE_JQUERY': settings.INLINE_JQUERY, + 'INLINE_FONTAWESOME': settings.INLINE_FONTAWESOME, + 'JQUERY_JS': settings.JQUERY_JS, + 'FONTAWESOME_CSS': settings.FONTAWESOME_CSS, + 'DMOJ_SCHEME': scheme, + 'DMOJ_CANONICAL': settings.DMOJ_CANONICAL, } @@ -46,69 +42,56 @@ def get_profile(request): def comet_location(request): if request.is_secure(): - websocket = getattr(settings, "EVENT_DAEMON_GET_SSL", settings.EVENT_DAEMON_GET) - poll = getattr(settings, "EVENT_DAEMON_POLL_SSL", settings.EVENT_DAEMON_POLL) + websocket = getattr(settings, 'EVENT_DAEMON_GET_SSL', settings.EVENT_DAEMON_GET) + poll = getattr(settings, 'EVENT_DAEMON_POLL_SSL', settings.EVENT_DAEMON_POLL) else: websocket = settings.EVENT_DAEMON_GET poll = settings.EVENT_DAEMON_POLL - return {"EVENT_DAEMON_LOCATION": websocket, "EVENT_DAEMON_POLL_LOCATION": poll} - - -@cache_wrapper(prefix="nb", expected_type=TreeQuerySet) -def _nav_bar(): - return NavigationBar.objects.all() + return {'EVENT_DAEMON_LOCATION': websocket, + 'EVENT_DAEMON_POLL_LOCATION': poll} def __nav_tab(path): - nav_bar_list = list(_nav_bar()) - nav_bar_dict = {nb.id: nb for nb in nav_bar_list} - result = next((nb for nb in nav_bar_list if re.match(nb.regex, path)), None) - if result: - while result.parent_id: - result = nav_bar_dict.get(result.parent_id) - return result.key - else: - return [] + result = list(NavigationBar.objects.extra(where=['%s REGEXP BINARY regex'], params=[path])[:1]) + return result[0].get_ancestors(include_self=True).values_list('key', flat=True) if result else [] def general_info(request): path = request.get_full_path() return { - "nav_tab": FixedSimpleLazyObject(partial(__nav_tab, request.path)), - "nav_bar": _nav_bar(), - "LOGIN_RETURN_PATH": "" if path.startswith("/accounts/") else path, - "perms": PermWrapper(request.user), + 'nav_tab': FixedSimpleLazyObject(partial(__nav_tab, request.path)), + 'nav_bar': NavigationBar.objects.all(), + 'LOGIN_RETURN_PATH': '' if path.startswith('/accounts/') else path, + 'perms': PermWrapper(request.user), } def site(request): - return {"site": get_current_site(request)} + return {'site': get_current_site(request)} class MiscConfigDict(dict): - __slots__ = ("language", "site") + __slots__ = ('language', 'site') - def __init__(self, language="", domain=None): + def __init__(self, language='', domain=None): self.language = language self.site = domain super(MiscConfigDict, self).__init__() def __missing__(self, key): - cache_key = "misc_config:%s:%s:%s" % (self.site, self.language, key) + cache_key = 'misc_config:%s:%s:%s' % (self.site, self.language, key) value = cache.get(cache_key) if value is None: - keys = ["%s.%s" % (key, self.language), key] if self.language else [key] + keys = ['%s.%s' % (key, self.language), key] if self.language else [key] if self.site is not None: - keys = ["%s:%s" % (self.site, key) for key in keys] + keys - map = dict( - MiscConfig.objects.values_list("key", "value").filter(key__in=keys) - ) + keys = ['%s:%s' % (self.site, key) for key in keys] + keys + map = dict(MiscConfig.objects.values_list('key', 'value').filter(key__in=keys)) for item in keys: if item in map: value = map[item] break else: - value = "" + value = '' cache.set(cache_key, value, 86400) self[key] = value return value @@ -116,15 +99,23 @@ class MiscConfigDict(dict): def misc_config(request): domain = get_current_site(request).domain - return { - "misc_config": MiscConfigDict(domain=domain), - "i18n_config": MiscConfigDict(language=request.LANGUAGE_CODE, domain=domain), - } + return {'misc_config': MiscConfigDict(domain=domain), + 'i18n_config': MiscConfigDict(language=request.LANGUAGE_CODE, domain=domain)} def site_name(request): - return { - "SITE_NAME": settings.SITE_NAME, - "SITE_LONG_NAME": settings.SITE_LONG_NAME, - "SITE_ADMIN_EMAIL": settings.SITE_ADMIN_EMAIL, - } + return {'SITE_NAME': settings.SITE_NAME, + 'SITE_LONG_NAME': settings.SITE_LONG_NAME, + 'SITE_ADMIN_EMAIL': settings.SITE_ADMIN_EMAIL} + + +def math_setting(request): + caniuse = CanIUse(request.META.get('HTTP_USER_AGENT', '')) + + if request.user.is_authenticated: + engine = request.profile.math_engine + else: + engine = settings.MATHOID_DEFAULT_TYPE + if engine == 'auto': + engine = 'mml' if bool(settings.MATHOID_URL) and caniuse.mathml == SUPPORT else 'jax' + return {'MATH_ENGINE': engine, 'REQUIRE_JAX': engine == 'jax', 'caniuse': caniuse} diff --git a/judge/templatetags/code_highlight.py b/judge/templatetags/code_highlight.py index 06ff6d0..e47e165 100644 --- a/judge/templatetags/code_highlight.py +++ b/judge/templatetags/code_highlight.py @@ -6,5 +6,5 @@ register = template.Library() @register.filter -def highlight(code, language, linenos=True): - return highlight_code(code, language, linenos) +def highlight(code, language): + return highlight_code(code, language) diff --git a/judge/templatetags/dicts.py b/judge/templatetags/dicts.py index efb321c..3afc15b 100644 --- a/judge/templatetags/dicts.py +++ b/judge/templatetags/dicts.py @@ -3,6 +3,6 @@ from django import template register = template.Library() -@register.filter(name="get_dict_item") +@register.filter(name='get_dict_item') def get_item(dictionary, key): return dictionary.get(key) diff --git a/judge/templatetags/list_processor.py b/judge/templatetags/list_processor.py index 15109cf..dc37105 100644 --- a/judge/templatetags/list_processor.py +++ b/judge/templatetags/list_processor.py @@ -5,7 +5,7 @@ from django import template register = template.Library() -@register.filter(name="list_attr") +@register.filter(name='list_attr') def list_attr(iterable, prop): result = [] for item in iterable: @@ -15,43 +15,43 @@ def list_attr(iterable, prop): try: result.append(item[prop]) except KeyError: - result.append("") + result.append('') except TypeError: try: result.append(item[int(prop)]) except (IndexError, ValueError, TypeError): - result.append("") + result.append('') return result -@register.filter(name="list_getitem") +@register.filter(name='list_getitem') def list_getitem(iterable, prop): return list(map(itemgetter(prop), iterable)) -@register.filter(name="list_getindex") +@register.filter(name='list_getindex') def list_getindex(iterable, index): return list(map(itemgetter(int(index)), iterable)) -@register.filter(name="list_getattr") +@register.filter(name='list_getattr') def list_getattr(iterable, prop): return list(map(attrgetter(prop), iterable)) -@register.filter(name="sum_list") +@register.filter(name='sum_list') def sum_list(iterable): return sum(iterable) -@register.filter(name="max_list") +@register.filter(name='max_list') def max_list(iterable): if not iterable: return 0 return max(iterable) -@register.filter(name="min_list") +@register.filter(name='min_list') def min_list(iterable): if not iterable: return 0 diff --git a/judge/templatetags/strings.py b/judge/templatetags/strings.py index 475a615..6bd685a 100644 --- a/judge/templatetags/strings.py +++ b/judge/templatetags/strings.py @@ -3,16 +3,16 @@ from django import template register = template.Library() -@register.filter(name="split") +@register.filter(name='split') def split(value): - return value.split("\n") + return value.split('\n') -@register.filter(name="cutoff") +@register.filter(name='cutoff') def cutoff(value, length): - return value[: int(length)] + return value[:int(length)] -@register.filter(name="roundfloat") +@register.filter(name='roundfloat') def roundfloat(value, at): return str(round(value, int(at))) diff --git a/judge/timezone.py b/judge/timezone.py index c609649..c3b5b04 100644 --- a/judge/timezone.py +++ b/judge/timezone.py @@ -2,7 +2,7 @@ import pytz from django.conf import settings from django.db import connection from django.utils import timezone -from django.utils.timezone import make_aware, make_naive +from django.utils.timezone import make_aware class TimezoneMiddleware(object): @@ -25,10 +25,3 @@ def from_database_time(datetime): if tz is None: return datetime return make_aware(datetime, tz) - - -def to_database_time(datetime): - tz = connection.timezone - if tz is None: - return datetime - return make_naive(datetime, tz) diff --git a/judge/user_log.py b/judge/user_log.py index b718b30..d5304ff 100644 --- a/judge/user_log.py +++ b/judge/user_log.py @@ -1,6 +1,4 @@ from django.utils.timezone import now -from django.conf import settings -from django.core.cache import cache from judge.models import Profile @@ -12,17 +10,12 @@ class LogUserAccessMiddleware(object): def __call__(self, request): response = self.get_response(request) - if ( - hasattr(request, "user") - and request.user.is_authenticated - and not getattr(request, "no_profile_update", False) - and not cache.get(f"user_log_update_{request.user.id}") - ): - updates = {"last_access": now()} + if (hasattr(request, 'user') and request.user.is_authenticated and + not getattr(request, 'no_profile_update', False)): + updates = {'last_access': now()} # Decided on using REMOTE_ADDR as nginx will translate it to the external IP that hits it. - if request.META.get(settings.META_REMOTE_ADDRESS_KEY): - updates["ip"] = request.META.get(settings.META_REMOTE_ADDRESS_KEY) + if request.META.get('REMOTE_ADDR'): + updates['ip'] = request.META.get('REMOTE_ADDR') Profile.objects.filter(user_id=request.user.pk).update(**updates) - cache.set(f"user_log_update_{request.user.id}", True, 120) return response diff --git a/judge/user_translations.py b/judge/user_translations.py index f93deaa..edc32ae 100644 --- a/judge/user_translations.py +++ b/judge/user_translations.py @@ -1,4 +1,5 @@ from django.conf import settings +from django.utils import six from django.utils.safestring import SafeData, mark_safe if settings.USE_I18N: @@ -9,25 +10,23 @@ if settings.USE_I18N: def translation(language): global _translations if language not in _translations: - _translations[language] = DjangoTranslation(language, domain="dmoj-user") + _translations[language] = DjangoTranslation(language, domain='dmoj-user') return _translations[language] def do_translate(message, translation_function): """Copied from django.utils.translation.trans_real""" # str() is allowing a bytestring message to remain bytestring on Python 2 - eol_message = message.replace(str("\r\n"), str("\n")).replace( - str("\r"), str("\n") - ) + eol_message = message.replace(str('\r\n'), str('\n')).replace(str('\r'), str('\n')) if len(eol_message) == 0: # Returns an empty value of the corresponding type if an empty message # is given, instead of metadata, which is the default gettext behavior. - result = "" + result = '' else: translation_object = translation(get_language()) result = getattr(translation_object, translation_function)(eol_message) - if not isinstance(result, str): - result = result.decode("utf-8") + if not isinstance(result, six.text_type): + result = result.decode('utf-8') if isinstance(message, SafeData): return mark_safe(result) @@ -35,9 +34,7 @@ if settings.USE_I18N: return result def gettext(message): - return do_translate(message, "gettext") - + return do_translate(message, 'gettext') else: - def gettext(message): return message diff --git a/judge/utils/camo.py b/judge/utils/camo.py index 025963f..a3c90a5 100644 --- a/judge/utils/camo.py +++ b/judge/utils/camo.py @@ -10,44 +10,39 @@ class CamoClient(object): """Based on https://github.com/sionide21/camo-client""" def __init__(self, server, key, excluded=(), https=False): - self.server = server.rstrip("/") + self.server = server.rstrip('/') self.key = key self.https = https self.excluded = excluded def image_url(self, url): - return "%s/%s/%s" % ( - self.server, - hmac.new(utf8bytes(self.key), utf8bytes(url), sha1).hexdigest(), - utf8bytes(url).hex(), - ) + return '%s/%s/%s' % (self.server, + hmac.new(utf8bytes(self.key), utf8bytes(url), sha1).hexdigest(), + utf8bytes(url).hex()) def rewrite_url(self, url): if url.startswith(self.server) or url.startswith(self.excluded): return url - elif url.startswith(("http://", "https://")): + elif url.startswith(('http://', 'https://')): return self.image_url(url) - elif url.startswith("//"): - return self.rewrite_url(("https:" if self.https else "http:") + url) + elif url.startswith('//'): + return self.rewrite_url(('https:' if self.https else 'http:') + url) else: return url def update_tree(self, doc): - for img in doc.xpath(".//img"): - for attr in ("src", "data-src"): + for img in doc.xpath('.//img'): + for attr in ('src', 'data-src'): if img.get(attr): img.set(attr, self.rewrite_url(img.get(attr))) - for obj in doc.xpath(".//object"): - if obj.get("data"): - obj.set("data", self.rewrite_url(obj.get("data"))) + for obj in doc.xpath('.//object'): + if obj.get('data'): + obj.set('data', self.rewrite_url(obj.get('data'))) if settings.DMOJ_CAMO_URL and settings.DMOJ_CAMO_KEY: - client = CamoClient( - settings.DMOJ_CAMO_URL, - key=settings.DMOJ_CAMO_KEY, - excluded=settings.DMOJ_CAMO_EXCLUDE, - https=settings.DMOJ_CAMO_HTTPS, - ) + client = CamoClient(settings.DMOJ_CAMO_URL, key=settings.DMOJ_CAMO_KEY, + excluded=settings.DMOJ_CAMO_EXCLUDE, + https=settings.DMOJ_CAMO_HTTPS) else: client = None diff --git a/judge/utils/caniuse.py b/judge/utils/caniuse.py index 2414785..bd4bb52 100644 --- a/judge/utils/caniuse.py +++ b/judge/utils/caniuse.py @@ -1,17 +1,15 @@ import requests from ua_parser import user_agent_parser -_SUPPORT_DATA = requests.get( - "https://raw.githubusercontent.com/Fyrd/caniuse/master/data.json" -).json()["data"] +_SUPPORT_DATA = requests.get('https://raw.githubusercontent.com/Fyrd/caniuse/master/data.json').json()['data'] -SUPPORT = "y" -PARTIAL_SUPPORT = "a" -UNSUPPORTED = "n" -POLYFILL = "p" -UNKNOWN = "u" -PREFIX = "x" -DISABLED = "d" +SUPPORT = 'y' +PARTIAL_SUPPORT = 'a' +UNSUPPORTED = 'n' +POLYFILL = 'p' +UNKNOWN = 'u' +PREFIX = 'x' +DISABLED = 'd' def safe_int(string): @@ -30,19 +28,19 @@ class BrowserFamily(object): max_support = UNKNOWN for version, support in data.items(): - if version == "all": + if version == 'all': self.max_support = support - elif "-" in version: - start, end = version.split("-") - start = tuple(map(int, start.split("."))) - end = tuple(map(int, end.split("."))) + (1e3000,) + elif '-' in version: + start, end = version.split('-') + start = tuple(map(int, start.split('.'))) + end = tuple(map(int, end.split('.'))) + (1e3000,) ranges.append((start, end, support)) if end > max_version: max_version = end max_support = support else: try: - version = tuple(map(int, version.split("."))) + version = tuple(map(int, version.split('.'))) except ValueError: pass else: @@ -61,12 +59,7 @@ class BrowserFamily(object): if version > self.max_version: return self.max_support - for key in ( - (int_major, int_minor, int_patch), - (int_major, int_minor), - (int_major,), - major, - ): + for key in ((int_major, int_minor, int_patch), (int_major, int_minor), (int_major,), major): try: return self._versions[key] except KeyError: @@ -82,9 +75,7 @@ class BrowserFamily(object): class Feat(object): def __init__(self, data): self._data = data - self._family = { - name: BrowserFamily(data) for name, data in data["stats"].items() - } + self._family = {name: BrowserFamily(data) for name, data in data['stats'].items()} def __getitem__(self, item): return self._family[item] @@ -106,31 +97,31 @@ class CanIUse(object): def __init__(self, ua): self._agent = user_agent_parser.Parse(ua) - os_family = self._agent["os"]["family"] - browser_family = self._agent["user_agent"]["family"] + os_family = self._agent['os']['family'] + browser_family = self._agent['user_agent']['family'] family = None - if os_family == "Android": - if "Firefox" in browser_family: - family = "and_ff" - elif "Chrome" in browser_family: - family = "and_chr" - elif "Android" in browser_family: - family = "android" + if os_family == 'Android': + if 'Firefox' in browser_family: + family = 'and_ff' + elif 'Chrome' in browser_family: + family = 'and_chr' + elif 'Android' in browser_family: + family = 'android' else: - if "Edge" in browser_family: - family = "edge" - elif "Firefox" in browser_family: - family = "firefox" - elif "Chrome" in browser_family: - family = "chrome" - elif "IE" in browser_family: - family = "ie" - elif "Opera" in browser_family: - family = "opera" - elif "Safari" in browser_family: - family = "safari" + if 'Edge' in browser_family: + family = 'edge' + elif 'Firefox' in browser_family: + family = 'firefox' + elif 'Chrome' in browser_family: + family = 'chrome' + elif 'IE' in browser_family: + family = 'ie' + elif 'Opera' in browser_family: + family = 'opera' + elif 'Safari' in browser_family: + family = 'safari' self._family = family @@ -143,12 +134,12 @@ class CanIUse(object): except KeyError: return UNKNOWN else: - ua = self._agent["user_agent"] - return stats.check(ua["major"], ua["minor"], ua["patch"])[0] + ua = self._agent['user_agent'] + return stats.check(ua['major'], ua['minor'], ua['patch'])[0] def __getattr__(self, attr): try: - feat = database[attr.replace("_", "-")] + feat = database[attr.replace('_', '-')] except KeyError: raise AttributeError(attr) else: diff --git a/judge/utils/celery.py b/judge/utils/celery.py index a632ddb..c905eae 100644 --- a/judge/utils/celery.py +++ b/judge/utils/celery.py @@ -12,11 +12,11 @@ class Progress: def _update_state(self): self.task.update_state( - state="PROGRESS", + state='PROGRESS', meta={ - "done": self._done, - "total": self._total, - "stage": self._stage, + 'done': self._done, + 'total': self._total, + 'stage': self._stage, }, ) @@ -54,12 +54,12 @@ class Progress: def task_status_url(result, message=None, redirect=None): args = {} if message: - args["message"] = message + args['message'] = message if redirect: - args["redirect"] = redirect - url = reverse("task_status", args=[result.id]) + args['redirect'] = redirect + url = reverse('task_status', args=[result.id]) if args: - url += "?" + urlencode(args) + url += '?' + urlencode(args) return url diff --git a/judge/utils/contest.py b/judge/utils/contest.py deleted file mode 100644 index 959749e..0000000 --- a/judge/utils/contest.py +++ /dev/null @@ -1,35 +0,0 @@ -from django.db import transaction -from judge.tasks import rescore_contest -from judge.models import ( - Contest, -) - - -def maybe_trigger_contest_rescore(form, contest, force_rescore=False): - if ( - any( - f in form.changed_data - for f in ( - "start_time", - "end_time", - "time_limit", - "format_config", - "format_name", - "freeze_after", - ) - ) - or force_rescore - ): - transaction.on_commit(rescore_contest.s(contest.key).delay) - - if any( - f in form.changed_data - for f in ( - "authors", - "curators", - "testers", - ) - ): - Contest._author_ids.dirty(contest) - Contest._curator_ids.dirty(contest) - Contest._tester_ids.dirty(contest) diff --git a/judge/utils/diggpaginator.py b/judge/utils/diggpaginator.py index 2ba8581..2832d2d 100644 --- a/judge/utils/diggpaginator.py +++ b/judge/utils/diggpaginator.py @@ -4,10 +4,10 @@ from functools import reduce from django.core.paginator import InvalidPage, Page, Paginator __all__ = ( - "InvalidPage", - "ExPaginator", - "DiggPaginator", - "QuerySetDiggPaginator", + 'InvalidPage', + 'ExPaginator', + 'DiggPaginator', + 'QuerySetDiggPaginator', ) @@ -182,20 +182,15 @@ class DiggPaginator(ExPaginator): """ def __init__(self, *args, **kwargs): - self.body = kwargs.pop("body", 10) - self.tail = kwargs.pop("tail", 2) - self.align_left = kwargs.pop("align_left", False) - self.margin = kwargs.pop( - "margin", 4 - ) # TODO: make the default relative to body? + self.body = kwargs.pop('body', 10) + self.tail = kwargs.pop('tail', 2) + self.align_left = kwargs.pop('align_left', False) + self.margin = kwargs.pop('margin', 4) # TODO: make the default relative to body? # validate padding value max_padding = int(math.ceil(self.body / 2.0) - 1) - self.padding = kwargs.pop("padding", min(4, max_padding)) - count_override = kwargs.pop("count", None) - if count_override is not None: - self.__dict__["count"] = count_override + self.padding = kwargs.pop('padding', min(4, max_padding)) if self.padding > max_padding: - raise ValueError("padding too large for body (max %d)" % max_padding) + raise ValueError('padding too large for body (max %d)' % max_padding) super(DiggPaginator, self).__init__(*args, **kwargs) def page(self, number, *args, **kwargs): @@ -207,24 +202,13 @@ class DiggPaginator(ExPaginator): number = int(number) # we know this will work # easier access - num_pages, body, tail, padding, margin = ( - self.num_pages, - self.body, - self.tail, - self.padding, - self.margin, - ) + num_pages, body, tail, padding, margin = \ + self.num_pages, self.body, self.tail, self.padding, self.margin # put active page in middle of main range - main_range = list( - map( - int, - [ - math.floor(number - body / 2.0) + 1, # +1 = shift odd body to right - math.floor(number + body / 2.0), - ], - ) - ) + main_range = list(map(int, [ + math.floor(number - body / 2.0) + 1, # +1 = shift odd body to right + math.floor(number + body / 2.0)])) # adjust bounds if main_range[0] < 1: main_range = list(map(abs(main_range[0] - 1).__add__, main_range)) @@ -265,10 +249,7 @@ class DiggPaginator(ExPaginator): # section, again. main_range = [1, num_pages] else: - main_range = [ - min(num_pages - body + 1, max(number - padding, main_range[0])), - num_pages, - ] + main_range = [min(num_pages - body + 1, max(number - padding, main_range[0])), num_pages] else: trailing = list(range(num_pages - tail + 1, num_pages + 1)) @@ -282,10 +263,8 @@ class DiggPaginator(ExPaginator): page.main_range = list(range(main_range[0], main_range[1] + 1)) page.leading_range = leading page.trailing_range = trailing - page.page_range = reduce( - lambda x, y: x + ((x and y) and [False]) + y, - [page.leading_range, page.main_range, page.trailing_range], - ) + page.page_range = reduce(lambda x, y: x + ((x and y) and [False]) + y, + [page.leading_range, page.main_range, page.trailing_range]) page.__class__ = DiggPage return page @@ -293,16 +272,10 @@ class DiggPaginator(ExPaginator): class DiggPage(Page): def __str__(self): - return " ... ".join( - filter( - None, - [ - " ".join(map(str, self.leading_range)), - " ".join(map(str, self.main_range)), - " ".join(map(str, self.trailing_range)), - ], - ) - ) + return " ... ".join(filter(None, [ + " ".join(map(str, self.leading_range)), + " ".join(map(str, self.main_range)), + " ".join(map(str, self.trailing_range))])) @property def num_pages(self): diff --git a/judge/utils/email_render.py b/judge/utils/email_render.py deleted file mode 100644 index a092f88..0000000 --- a/judge/utils/email_render.py +++ /dev/null @@ -1,19 +0,0 @@ -from django.template.loader import render_to_string -from django.contrib.sites.shortcuts import get_current_site -from django.conf import settings - - -def render_email_message(request, contexts): - current_site = get_current_site(request) - email_contexts = { - "username": request.user.username, - "domain": current_site.domain, - "site_name": settings.SITE_NAME, - "message": None, - "title": None, - "button_text": "Click here", - "url_path": None, - } - email_contexts.update(contexts) - message = render_to_string("general_email.html", email_contexts) - return message diff --git a/judge/utils/file_cache.py b/judge/utils/file_cache.py index 3b19b4c..3864f59 100644 --- a/judge/utils/file_cache.py +++ b/judge/utils/file_cache.py @@ -24,10 +24,10 @@ class HashFileCache(object): return os.path.join(self.root, hash, file) def get_url(self, hash, file): - return urljoin(self.url, "%s/%s" % (hash, file)) + return urljoin(self.url, '%s/%s' % (hash, file)) def read_file(self, hash, file): - return open(self.get_path(hash, file), "rb") + return open(self.get_path(hash, file), 'rb') def read_data(self, hash, file): with self.read_file(hash, file) as f: @@ -35,10 +35,10 @@ class HashFileCache(object): def cache_data(self, hash, file, data, url=True, gzip=True): if gzip and self.gzip: - with gzip_open(self.get_path(hash, file + ".gz"), "wb") as f: + with gzip_open(self.get_path(hash, file + '.gz'), 'wb') as f: f.write(data) - with open(self.get_path(hash, file), "wb") as f: + with open(self.get_path(hash, file), 'wb') as f: f.write(data) if url: diff --git a/judge/utils/fine_uploader.py b/judge/utils/fine_uploader.py deleted file mode 100644 index 8f64d78..0000000 --- a/judge/utils/fine_uploader.py +++ /dev/null @@ -1,93 +0,0 @@ -# https://github.com/FineUploader/server-examples/blob/master/python/django-fine-uploader - -from django.conf import settings -from django import forms -from django.forms import ClearableFileInput - -import os, os.path -import shutil - -__all__ = ("handle_upload", "save_upload", "FineUploadForm", "FineUploadFileInput") - - -def combine_chunks(total_parts, total_size, source_folder, dest): - if not os.path.exists(os.path.dirname(dest)): - os.makedirs(os.path.dirname(dest)) - - with open(dest, "wb+") as destination: - for i in range(total_parts): - part = os.path.join(source_folder, str(i)) - with open(part, "rb") as source: - destination.write(source.read()) - - -def save_upload(f, path): - if not os.path.exists(os.path.dirname(path)): - os.makedirs(os.path.dirname(path)) - with open(path, "wb+") as destination: - if hasattr(f, "multiple_chunks") and f.multiple_chunks(): - for chunk in f.chunks(): - destination.write(chunk) - else: - destination.write(f.read()) - - -# pass callback function to post_upload -def handle_upload(f, fileattrs, upload_dir, post_upload=None): - chunks_dir = settings.CHUNK_UPLOAD_DIR - if not os.path.exists(os.path.dirname(chunks_dir)): - os.makedirs(os.path.dirname(chunks_dir)) - chunked = False - dest_folder = upload_dir - dest = os.path.join(dest_folder, fileattrs["qqfilename"]) - - # Chunked - if fileattrs.get("qqtotalparts") and int(fileattrs["qqtotalparts"]) > 1: - chunked = True - dest_folder = os.path.join(chunks_dir, fileattrs["qquuid"]) - dest = os.path.join( - dest_folder, fileattrs["qqfilename"], str(fileattrs["qqpartindex"]) - ) - save_upload(f, dest) - - # If the last chunk has been sent, combine the parts. - if chunked and (fileattrs["qqtotalparts"] - 1 == fileattrs["qqpartindex"]): - combine_chunks( - fileattrs["qqtotalparts"], - fileattrs["qqtotalfilesize"], - source_folder=os.path.dirname(dest), - dest=os.path.join(upload_dir, fileattrs["qqfilename"]), - ) - shutil.rmtree(os.path.dirname(os.path.dirname(dest))) - - if post_upload and ( - not chunked or fileattrs["qqtotalparts"] - 1 == fileattrs["qqpartindex"] - ): - post_upload() - - -class FineUploadForm(forms.Form): - qqfile = forms.FileField() - qquuid = forms.CharField() - qqfilename = forms.CharField() - qqpartindex = forms.IntegerField(required=False) - qqchunksize = forms.IntegerField(required=False) - qqpartbyteoffset = forms.IntegerField(required=False) - qqtotalfilesize = forms.IntegerField(required=False) - qqtotalparts = forms.IntegerField(required=False) - - -class FineUploadFileInput(ClearableFileInput): - template_name = "widgets/fine_uploader.html" - - def fine_uploader_id(self, name): - return name + "_" + "fine_uploader" - - def get_context(self, name, value, attrs): - context = super().get_context(name, value, attrs) - context["widget"].update( - { - "fine_uploader_id": self.fine_uploader_id(name), - } - ) - return context diff --git a/judge/utils/infinite_paginator.py b/judge/utils/infinite_paginator.py deleted file mode 100644 index afd004f..0000000 --- a/judge/utils/infinite_paginator.py +++ /dev/null @@ -1,152 +0,0 @@ -import collections -import inspect -from math import ceil - -from django.core.paginator import EmptyPage, InvalidPage -from django.http import Http404 -from django.utils.functional import cached_property -from django.utils.inspect import method_has_no_args - - -class InfinitePage(collections.abc.Sequence): - def __init__( - self, object_list, number, unfiltered_queryset, page_size, pad_pages, paginator - ): - self.object_list = list(object_list) - self.number = number - self.unfiltered_queryset = unfiltered_queryset - self.page_size = page_size - self.pad_pages = pad_pages - self.num_pages = 1e3000 - self.paginator = paginator - - def __repr__(self): - return "" % self.number - - def __len__(self): - return len(self.object_list) - - def __getitem__(self, index): - return self.object_list[index] - - @cached_property - def _after_up_to_pad(self): - first_after = self.number * self.page_size - padding_length = self.pad_pages * self.page_size - queryset = self.unfiltered_queryset[ - first_after : first_after + padding_length + 1 - ] - c = getattr(queryset, "count", None) - if callable(c) and not inspect.isbuiltin(c) and method_has_no_args(c): - return c() - return len(queryset) - - def has_next(self): - return self._after_up_to_pad > 0 - - def has_previous(self): - return self.number > 1 - - def has_other_pages(self): - return self.has_previous() or self.has_next() - - def next_page_number(self): - if not self.has_next(): - raise EmptyPage() - return self.number + 1 - - def previous_page_number(self): - if self.number <= 1: - raise EmptyPage() - return self.number - 1 - - def start_index(self): - return (self.page_size * (self.number - 1)) + 1 - - def end_index(self): - return self.start_index() + len(self.object_list) - - @cached_property - def main_range(self): - start = max(1, self.number - self.pad_pages) - end = self.number + min( - int(ceil(self._after_up_to_pad / self.page_size)), self.pad_pages - ) - return range(start, end + 1) - - @cached_property - def leading_range(self): - return range(1, min(3, self.main_range[0])) - - @cached_property - def has_trailing(self): - return self._after_up_to_pad > self.pad_pages * self.page_size - - @cached_property - def page_range(self): - result = list(self.leading_range) - main_range = self.main_range - - # Add ... element if there is space in between. - if result and result[-1] + 1 < self.main_range[0]: - result.append(False) - - result += list(main_range) - - # Add ... element if there are elements after main_range. - if self.has_trailing: - result.append(False) - return result - - -class DummyPaginator: - is_infinite = True - - def __init__(self, per_page): - self.per_page = per_page - - -def infinite_paginate(queryset, page, page_size, pad_pages, paginator=None): - if page < 1: - raise EmptyPage() - sliced = queryset[(page - 1) * page_size : page * page_size] - if page > 1 and not sliced: - raise EmptyPage() - return InfinitePage(sliced, page, queryset, page_size, pad_pages, paginator) - - -class InfinitePaginationMixin: - pad_pages = 2 - - @property - def use_infinite_pagination(self): - return True - - def paginate_queryset(self, queryset, page_size): - if not self.use_infinite_pagination: - paginator, page, object_list, has_other = super().paginate_queryset( - queryset, page_size - ) - paginator.is_infinite = False - return paginator, page, object_list, has_other - - page_kwarg = self.page_kwarg - page = self.kwargs.get(page_kwarg) or self.request.GET.get(page_kwarg) or 1 - try: - page_number = int(page) - except ValueError: - raise Http404("Page cannot be converted to an int.") - try: - paginator = DummyPaginator(page_size) - page = infinite_paginate( - queryset, page_number, page_size, self.pad_pages, paginator - ) - return paginator, page, page.object_list, page.has_other_pages() - except InvalidPage as e: - raise Http404( - "Invalid page (%(page_number)s): %(message)s" - % { - "page_number": page_number, - "message": str(e), - } - ) diff --git a/judge/utils/mathoid.py b/judge/utils/mathoid.py index a7ceb24..a28357d 100644 --- a/judge/utils/mathoid.py +++ b/judge/utils/mathoid.py @@ -12,25 +12,25 @@ from mistune import escape from judge.utils.file_cache import HashFileCache from judge.utils.unicode import utf8bytes, utf8text -logger = logging.getLogger("judge.mathoid") -reescape = re.compile(r"(?"), - ("&", "&"), - ("−", "-"), - ("≤", r"\le"), - ("≥", r"\ge"), - ("…", "..."), - (r"\lt", "<"), - (r"\gt", ">"), + ('\u2264', r'\le'), + ('\u2265', r'\ge'), + ('\u2026', '...'), + ('\u2212', '-'), + ('≤', r'\le'), + ('≥', r'\ge'), + ('<', '<'), + ('>', '>'), + ('&', '&'), + ('−', '-'), + ('≤', r'\le'), + ('≥', r'\ge'), + ('…', '...'), + (r'\lt', '<'), + (r'\gt', '>'), ] @@ -41,17 +41,15 @@ def format_math(math): class MathoidMathParser(object): - types = ("svg", "mml", "tex", "jax") + types = ('svg', 'mml', 'tex', 'jax') def __init__(self, type): self.type = type self.mathoid_url = settings.MATHOID_URL - self.cache = HashFileCache( - settings.MATHOID_CACHE_ROOT, - settings.MATHOID_CACHE_URL, - settings.MATHOID_GZIP, - ) + self.cache = HashFileCache(settings.MATHOID_CACHE_ROOT, + settings.MATHOID_CACHE_URL, + settings.MATHOID_GZIP) mml_cache = settings.MATHOID_MML_CACHE self.mml_cache = mml_cache and caches[mml_cache] @@ -63,80 +61,69 @@ class MathoidMathParser(object): self.cache.create(hash) try: - response = requests.post( - self.mathoid_url, - data={ - "q": reescape.sub(lambda m: "\\" + m.group(0), formula).encode( - "utf-8" - ), - "type": "tex" - if formula.startswith(r"\displaystyle") - else "inline-tex", - }, - ) + response = requests.post(self.mathoid_url, data={ + 'q': reescape.sub(lambda m: '\\' + m.group(0), formula).encode('utf-8'), + 'type': 'tex' if formula.startswith(r'\displaystyle') else 'inline-tex', + }) response.raise_for_status() data = response.json() except requests.ConnectionError: - logger.exception("Failed to connect to mathoid for: %s", formula) + logger.exception('Failed to connect to mathoid for: %s', formula) return except requests.HTTPError as e: - logger.error("Mathoid failed to render: %s\n%s", formula, e.response.text) + logger.error('Mathoid failed to render: %s\n%s', formula, e.response.text) return except Exception: - logger.exception("Failed to connect to mathoid for: %s", formula) + logger.exception('Failed to connect to mathoid for: %s', formula) return - if not data["success"]: - logger.error("Mathoid failure for: %s\n%s", formula, data) + if not data['success']: + logger.error('Mathoid failure for: %s\n%s', formula, data) return - if any(i not in data for i in ("mml", "png", "svg", "mathoidStyle")): - logger.error( - "Mathoid did not return required information (mml, png, svg, mathoidStyle needed):\n%s", - data, - ) + if any(i not in data for i in ('mml', 'png', 'svg', 'mathoidStyle')): + logger.error('Mathoid did not return required information (mml, png, svg, mathoidStyle needed):\n%s', data) return - css = data["mathoidStyle"] - mml = data["mml"] + css = data['mathoidStyle'] + mml = data['mml'] result = { - "css": css, - "mml": mml, - "png": self.cache.cache_data(hash, "png", bytearray(data["png"]["data"])), - "svg": self.cache.cache_data(hash, "svg", data["svg"].encode("utf-8")), + 'css': css, 'mml': mml, + 'png': self.cache.cache_data(hash, 'png', bytearray(data['png']['data'])), + 'svg': self.cache.cache_data(hash, 'svg', data['svg'].encode('utf-8')), } - self.cache.cache_data(hash, "mml", mml.encode("utf-8"), url=False, gzip=False) - self.cache.cache_data(hash, "css", css.encode("utf-8"), url=False, gzip=False) + self.cache.cache_data(hash, 'mml', mml.encode('utf-8'), url=False, gzip=False) + self.cache.cache_data(hash, 'css', css.encode('utf-8'), url=False, gzip=False) return result def query_cache(self, hash): result = { - "svg": self.cache.get_url(hash, "svg"), - "png": self.cache.get_url(hash, "png"), + 'svg': self.cache.get_url(hash, 'svg'), + 'png': self.cache.get_url(hash, 'png'), } - key = "mathoid:css:" + hash - css = result["css"] = self.css_cache.get(key) + key = 'mathoid:css:' + hash + css = result['css'] = self.css_cache.get(key) if css is None: - css = result["css"] = self.cache.read_data(hash, "css").decode("utf-8") + css = result['css'] = self.cache.read_data(hash, 'css').decode('utf-8') self.css_cache.set(key, css, self.mml_cache_ttl) mml = None if self.mml_cache: - mml = result["mml"] = self.mml_cache.get("mathoid:mml:" + hash) + mml = result['mml'] = self.mml_cache.get('mathoid:mml:' + hash) if mml is None: - mml = result["mml"] = self.cache.read_data(hash, "mml").decode("utf-8") + mml = result['mml'] = self.cache.read_data(hash, 'mml').decode('utf-8') if self.mml_cache: - self.mml_cache.set("mathoid:mml:" + hash, mml, self.mml_cache_ttl) + self.mml_cache.set('mathoid:mml:' + hash, mml, self.mml_cache_ttl) return result def get_result(self, formula): - if self.type == "tex": + if self.type == 'tex': return hash = hashlib.sha1(utf8bytes(formula)).hexdigest() formula = utf8text(formula) - if self.cache.has_file(hash, "css"): + if self.cache.has_file(hash, 'css'): result = self.query_cache(hash) else: result = self.query_mathoid(formula, hash) @@ -144,76 +131,55 @@ class MathoidMathParser(object): if not result: return None - result["tex"] = formula - result["display"] = formula.startswith(r"\displaystyle") + result['tex'] = formula + result['display'] = formula.startswith(r'\displaystyle') return { - "mml": self.output_mml, - "msp": self.output_msp, - "svg": self.output_svg, - "jax": self.output_jax, - "png": self.output_png, - "raw": lambda x: x, + 'mml': self.output_mml, + 'msp': self.output_msp, + 'svg': self.output_svg, + 'jax': self.output_jax, + 'png': self.output_png, + 'raw': lambda x: x, }[self.type](result) def output_mml(self, result): - return result["mml"] + return result['mml'] def output_msp(self, result): # 100% MediaWiki compatibility. - return format_html( - '' - '' - '', - mark_safe(result["mml"]), - result["svg"], - result["png"], - result["css"], - result["tex"], - ["inline", "display"][result["display"]], - ) + return format_html('' + '' + '', + mark_safe(result['mml']), result['svg'], result['png'], result['css'], result['tex'], + ['inline', 'display'][result['display']]) def output_jax(self, result): - return format_html( - '' - '''{3}""" - """""" - "", - result["svg"], - result["png"], - result["css"], - result["tex"], - ["inline-math", "display-math"][result["display"]], - ["~", "$$"][result["display"]], - ) + return format_html('' + '''{3}''' + '''''' + '', + result['svg'], result['png'], result['css'], result['tex'], + ['inline-math', 'display-math'][result['display']], ['~', '$$'][result['display']]) def output_svg(self, result): - return format_html( - '{3}""", - result["svg"], - result["png"], - result["css"], - result["tex"], - ["inline-math", "display-math"][result["display"]], - ) + return format_html('{3}''', + result['svg'], result['png'], result['css'], result['tex'], + ['inline-math', 'display-math'][result['display']]) def output_png(self, result): - return format_html( - '{2}', - result["png"], - result["css"], - result["tex"], - ["inline-math", "display-math"][result["display"]], - ) + return format_html('{2}', + result['png'], result['css'], result['tex'], + ['inline-math', 'display-math'][result['display']]) def display_math(self, math): math = format_math(math) - return self.get_result(r"\displaystyle " + math) or r"\[%s\]" % escape(math) + return self.get_result(r'\displaystyle ' + math) or r'\[%s\]' % escape(math) def inline_math(self, math): math = format_math(math) - return self.get_result(math) or r"\(%s\)" % escape(math) + return self.get_result(math) or r'\(%s\)' % escape(math) diff --git a/judge/utils/opengraph.py b/judge/utils/opengraph.py index 7454415..df016c2 100644 --- a/judge/utils/opengraph.py +++ b/judge/utils/opengraph.py @@ -5,20 +5,20 @@ from judge.jinja2.markdown import markdown from judge.jinja2.reference import reference -def generate_opengraph(cache_key, data): +def generate_opengraph(cache_key, data, style): metadata = cache.get(cache_key) if metadata is None: description = None - tree = reference(markdown(data)).tree - for p in tree.iterfind(".//p"): + tree = reference(markdown(data, style)).tree + for p in tree.iterfind('.//p'): text = p.text_content().strip() if text: description = text break if description: - for remove in (r"\[", r"\]", r"\(", r"\)"): - description = description.replace(remove, "") - img = tree.xpath(".//img") - metadata = truncatewords(description, 60), img[0].get("src") if img else None + for remove in (r'\[', r'\]', r'\(', r'\)'): + description = description.replace(remove, '') + img = tree.xpath('.//img') + metadata = truncatewords(description, 60), img[0].get('src') if img else None cache.set(cache_key, metadata, 86400) return metadata diff --git a/judge/utils/problem_data.py b/judge/utils/problem_data.py index 5cf9fe7..5bf6341 100644 --- a/judge/utils/problem_data.py +++ b/judge/utils/problem_data.py @@ -1,29 +1,23 @@ -import hashlib import json import os import re -import yaml -import zipfile import shutil +import yaml from django.conf import settings from django.core.files.base import ContentFile from django.core.files.storage import FileSystemStorage from django.urls import reverse from django.utils.translation import gettext as _ -from django.core.cache import cache -from judge.logging import log_exception + +VALIDATOR_TEMPLATE_PATH = 'validator_template/template.py' + if os.altsep: - - def split_path_first( - path, repath=re.compile("[%s]" % re.escape(os.sep + os.altsep)) - ): + def split_path_first(path, repath=re.compile('[%s]' % re.escape(os.sep + os.altsep))): return repath.split(path, 1) - else: - def split_path_first(path): return path.split(os.sep, 1) @@ -35,8 +29,8 @@ class ProblemDataStorage(FileSystemStorage): def url(self, name): path = split_path_first(name) if len(path) != 2: - raise ValueError("This file is not accessible via a URL.") - return reverse("problem_data_file", args=path) + raise ValueError('This file is not accessible via a URL.') + return reverse('problem_data_file', args=path) def _save(self, name, content): if self.exists(name): @@ -49,13 +43,6 @@ class ProblemDataStorage(FileSystemStorage): def rename(self, old, new): return os.rename(self.path(old), self.path(new)) - def delete_directory(self, name): - directory_path = self.path(name) - try: - shutil.rmtree(directory_path) - except FileNotFoundError: - pass - class ProblemDataError(Exception): def __init__(self, message): @@ -77,136 +64,118 @@ class ProblemDataCompiler(object): batch = None def end_batch(): - if not batch["batched"]: - raise ProblemDataError(_("Empty batches not allowed.")) + if not batch['batched']: + raise ProblemDataError(_('Empty batches not allowed.')) cases.append(batch) + def make_checker_for_validator(case): + checker_name = "cppvalidator.py" + validator_path = split_path_first(case.custom_validator.name) + + if len(validator_path) != 2: + raise ProblemDataError(_('How did you corrupt the custom checker path?')) + + checker = os.path.join(settings.DMOJ_PROBLEM_DATA_ROOT, + validator_path[0], + checker_name) + + validator_name = validator_path[1] + shutil.copy(VALIDATOR_TEMPLATE_PATH, checker) + + # replace {{filecpp}} and {{problemid}} in checker file + filedata = open(checker, 'r').read() + filedata = filedata.replace('{{filecpp}}', "\'%s\'" % validator_name) + filedata = filedata.replace('{{problemid}}', "\'%s\'" % validator_path[0]) + open(checker, 'w').write(filedata) + + return checker_name + def make_checker(case): - if case.checker == "custom": + if (case.checker == 'custom'): custom_checker_path = split_path_first(case.custom_checker.name) if len(custom_checker_path) != 2: - raise ProblemDataError( - _("How did you corrupt the custom checker path?") - ) - return custom_checker_path[1] + raise ProblemDataError(_('How did you corrupt the custom checker path?')) + return(custom_checker_path[1]) - if case.checker == "customcpp": - custom_checker_path = split_path_first(case.custom_checker_cpp.name) - if len(custom_checker_path) != 2: - raise ProblemDataError( - _("How did you corrupt the custom checker path?") - ) - return { - "name": "bridged", - "args": { - "files": custom_checker_path[1], - "lang": "CPP14", - "type": "lqdoj", - }, - } - - if case.checker == "testlib": - custom_checker_path = split_path_first(case.custom_checker_cpp.name) - if len(custom_checker_path) != 2: - raise ProblemDataError( - _("How did you corrupt the custom checker path?") - ) - return { - "name": "bridged", - "args": { - "files": custom_checker_path[1], - "lang": "CPP14", - "type": "testlib", - }, - } + if (case.checker == 'customval'): + return make_checker_for_validator(case) if case.checker_args: return { - "name": case.checker, - "args": json.loads(case.checker_args), + 'name': case.checker, + 'args': json.loads(case.checker_args), } return case.checker for i, case in enumerate(self.cases, 1): - if case.type == "C": + if case.type == 'C': data = {} if batch: - if case.points is None: - case.points = 0 - case.is_pretest = batch["is_pretest"] + case.points = None + case.is_pretest = batch['is_pretest'] else: if case.points is None: - raise ProblemDataError( - _("Points must be defined for non-batch case #%d.") % i - ) - data["is_pretest"] = case.is_pretest + raise ProblemDataError(_('Points must be defined for non-batch case #%d.') % i) + data['is_pretest'] = case.is_pretest if not self.generator: if case.input_file not in self.files: - raise ProblemDataError( - _("Input file for case %d does not exist: %s") - % (i, case.input_file) - ) + raise ProblemDataError(_('Input file for case %d does not exist: %s') % + (i, case.input_file)) if case.output_file not in self.files: - raise ProblemDataError( - _("Output file for case %d does not exist: %s") - % (i, case.output_file) - ) + raise ProblemDataError(_('Output file for case %d does not exist: %s') % + (i, case.output_file)) if case.input_file: - data["in"] = case.input_file + data['in'] = case.input_file if case.output_file: - data["out"] = case.output_file + data['out'] = case.output_file if case.points is not None: - data["points"] = case.points + data['points'] = case.points if case.generator_args: - data["generator_args"] = case.generator_args.splitlines() + data['generator_args'] = case.generator_args.splitlines() if case.output_limit is not None: - data["output_limit_length"] = case.output_limit + data['output_limit_length'] = case.output_limit if case.output_prefix is not None: - data["output_prefix_length"] = case.output_prefix + data['output_prefix_length'] = case.output_prefix if case.checker: - data["checker"] = make_checker(case) + data['checker'] = make_checker(case) else: - case.checker_args = "" - case.save(update_fields=("checker_args", "is_pretest")) - (batch["batched"] if batch else cases).append(data) - elif case.type == "S": + case.checker_args = '' + case.save(update_fields=('checker_args', 'is_pretest')) + (batch['batched'] if batch else cases).append(data) + elif case.type == 'S': if batch: end_batch() if case.points is None: - raise ProblemDataError( - _("Batch start case #%d requires points.") % i - ) + raise ProblemDataError(_('Batch start case #%d requires points.') % i) batch = { - "points": case.points, - "batched": [], - "is_pretest": case.is_pretest, + 'points': case.points, + 'batched': [], + 'is_pretest': case.is_pretest, } if case.generator_args: - batch["generator_args"] = case.generator_args.splitlines() + batch['generator_args'] = case.generator_args.splitlines() if case.output_limit is not None: - batch["output_limit_length"] = case.output_limit + batch['output_limit_length'] = case.output_limit if case.output_prefix is not None: - batch["output_prefix_length"] = case.output_prefix + batch['output_prefix_length'] = case.output_prefix if case.checker: - batch["checker"] = make_checker(case) + batch['checker'] = make_checker(case) else: - case.checker_args = "" - case.input_file = "" - case.output_file = "" - case.save(update_fields=("checker_args", "input_file", "output_file")) - elif case.type == "E": + case.checker_args = '' + case.input_file = '' + case.output_file = '' + case.save(update_fields=('checker_args', 'input_file', 'output_file')) + elif case.type == 'E': if not batch: - raise ProblemDataError( - _("Attempt to end batch outside of one in case #%d") % i - ) - case.is_pretest = batch["is_pretest"] - case.input_file = "" - case.output_file = "" - case.generator_args = "" - case.checker = "" - case.checker_args = "" + raise ProblemDataError(_('Attempt to end batch outside of one in case #%d') % i) + case.is_pretest = batch['is_pretest'] + case.input_file = '' + case.output_file = '' + case.generator_args = '' + case.checker = '' + case.checker_args = '' case.save() end_batch() batch = None @@ -218,69 +187,36 @@ class ProblemDataCompiler(object): if self.data.zipfile: zippath = split_path_first(self.data.zipfile.name) if len(zippath) != 2: - raise ProblemDataError(_("How did you corrupt the zip path?")) - init["archive"] = zippath[1] + raise ProblemDataError(_('How did you corrupt the zip path?')) + init['archive'] = zippath[1] if self.generator: generator_path = split_path_first(self.generator.name) if len(generator_path) != 2: - raise ProblemDataError(_("How did you corrupt the generator path?")) - init["generator"] = generator_path[1] + raise ProblemDataError(_('How did you corrupt the generator path?')) + init['generator'] = generator_path[1] - pretests = [case for case in cases if case["is_pretest"]] + pretests = [case for case in cases if case['is_pretest']] for case in cases: - del case["is_pretest"] + del case['is_pretest'] if pretests: - init["pretest_test_cases"] = pretests + init['pretest_test_cases'] = pretests if cases: - init["test_cases"] = cases + init['test_cases'] = cases if self.data.output_limit is not None: - init["output_limit_length"] = self.data.output_limit + init['output_limit_length'] = self.data.output_limit if self.data.output_prefix is not None: - init["output_prefix_length"] = self.data.output_prefix + init['output_prefix_length'] = self.data.output_prefix if self.data.checker: - if self.data.checker == "interact": - interactor_path = split_path_first(self.data.interactive_judge.name) - if len(interactor_path) != 2: - raise ProblemDataError(_("Invalid interactor judge")) - init["interactive"] = { - "files": interactor_path[1], - "feedback": True, - "type": "lqdoj", - } - init["unbuffered"] = True - else: - init["checker"] = make_checker(self.data) + init['checker'] = make_checker(self.data) else: - self.data.checker_args = "" - if self.data.fileio_input: - if "file_io" not in init: - init["file_io"] = {} - init["file_io"]["input"] = self.data.fileio_input - if self.data.fileio_output: - if "file_io" not in init: - init["file_io"] = {} - init["file_io"]["output"] = self.data.fileio_output - if self.data.output_only: - init["output_only"] = True - if self.data.use_ioi_signature: - handler_path = split_path_first(self.data.signature_handler.name) - if len(handler_path) != 2: - raise ProblemDataError(_("Invalid signature handler")) - header_path = split_path_first(self.data.signature_header.name) - if len(header_path) != 2: - raise ProblemDataError(_("Invalid signature header")) - - init["signature_grader"] = { - "entry": handler_path[1], - "header": header_path[1], - } + self.data.checker_args = '' return init def compile(self): from judge.models import problem_data_storage - yml_file = "%s/init.yml" % self.problem.code + yml_file = '%s/init.yml' % self.problem.code try: init = yaml.safe_dump(self.make_init()) except ProblemDataError as e: @@ -288,7 +224,7 @@ class ProblemDataCompiler(object): self.data.save() problem_data_storage.delete(yml_file) else: - self.data.feedback = "" + self.data.feedback = '' self.data.save() problem_data_storage.save(yml_file, ContentFile(init)) @@ -296,70 +232,3 @@ class ProblemDataCompiler(object): def generate(cls, *args, **kwargs): self = cls(*args, **kwargs) self.compile() - - -def get_visible_content(data): - data = data or b"" - data = data.replace(b"\r\n", b"\r").replace(b"\r", b"\n") - - data = data.decode("utf-8") - - if len(data) > settings.TESTCASE_VISIBLE_LENGTH: - data = data[: settings.TESTCASE_VISIBLE_LENGTH] - data += "." * 3 - return data - - -def get_file_cachekey(file): - return hashlib.sha1(file.encode()).hexdigest() - - -def get_problem_case(problem, files): - result = {} - uncached_files = [] - - for file in files: - cache_key = "problem_archive:%s:%s" % (problem.code, get_file_cachekey(file)) - qs = cache.get(cache_key) - if qs is None: - uncached_files.append(file) - else: - result[file] = qs - - if not uncached_files: - return result - - archive_path = os.path.join( - settings.DMOJ_PROBLEM_DATA_ROOT, str(problem.data_files.zipfile) - ) - if not os.path.exists(archive_path): - log_exception('archive file "%s" does not exist' % archive_path) - return {} - try: - archive = zipfile.ZipFile(archive_path, "r") - except zipfile.BadZipfile: - log_exception('bad archive: "%s"' % archive_path) - return {} - - for file in uncached_files: - cache_key = "problem_archive:%s:%s" % (problem.code, get_file_cachekey(file)) - with archive.open(file) as f: - s = f.read(settings.TESTCASE_VISIBLE_LENGTH + 3) - # add this so there are no characters left behind (ex, 'á' = 2 utf-8 chars) - while True: - try: - s.decode("utf-8") - break - except UnicodeDecodeError: - next_char = f.read(1) - if next_char: - s += next_char - else: - s = f"File {file} is not able to decode in utf-8" - s = s.encode("utf-8") - break - qs = get_visible_content(s) - cache.set(cache_key, qs, 86400) - result[file] = qs - - return result diff --git a/judge/utils/problems.py b/judge/utils/problems.py index 6423c70..f87f807 100644 --- a/judge/utils/problems.py +++ b/judge/utils/problems.py @@ -1,146 +1,87 @@ from collections import defaultdict from math import e -from datetime import datetime, timedelta -import random -from enum import Enum -from django.conf import settings from django.core.cache import cache from django.db.models import Case, Count, ExpressionWrapper, F, Max, Q, When from django.db.models.fields import FloatField from django.utils import timezone from django.utils.translation import gettext as _, gettext_noop -from django.http import Http404 from judge.models import Problem, Submission -from judge.ml.collab_filter import CollabFilter -from judge.caching import cache_wrapper -__all__ = [ - "contest_completed_ids", - "get_result_data", - "user_completed_ids", - "user_editable_ids", - "user_tester_ids", -] +__all__ = ['contest_completed_ids', 'get_result_data', 'user_completed_ids', 'user_authored_ids', 'user_editable_ids'] -@cache_wrapper(prefix="user_tester") -def user_tester_ids(profile): - return set( - Problem.testers.through.objects.filter(profile=profile) - .values_list("problem_id", flat=True) - .distinct() - ) +def user_authored_ids(profile): + result = set(Problem.objects.filter(authors=profile).values_list('id', flat=True)) + return result -@cache_wrapper(prefix="user_editable") def user_editable_ids(profile): - result = set( - ( - Problem.objects.filter(authors=profile) - | Problem.objects.filter(curators=profile) - ) - .values_list("id", flat=True) - .distinct() - ) + result = set((Problem.objects.filter(authors=profile) | Problem.objects.filter(curators=profile)) + .values_list('id', flat=True)) return result -@cache_wrapper(prefix="contest_complete") def contest_completed_ids(participation): - result = set( - participation.submissions.filter( - submission__result="AC", points=F("problem__points") - ) - .values_list("problem__problem__id", flat=True) - .distinct() - ) + key = 'contest_complete:%d' % participation.id + result = cache.get(key) + if result is None: + result = set(participation.submissions.filter(submission__result='AC', points=F('problem__points')) + .values_list('problem__problem__id', flat=True).distinct()) + cache.set(key, result, 86400) return result -@cache_wrapper(prefix="user_complete") def user_completed_ids(profile): - result = set( - Submission.objects.filter( - user=profile, result="AC", points=F("problem__points") - ) - .values_list("problem_id", flat=True) - .distinct() - ) + key = 'user_complete:%d' % profile.id + result = cache.get(key) + if result is None: + result = set(Submission.objects.filter(user=profile, result='AC', points=F('problem__points')) + .values_list('problem_id', flat=True).distinct()) + cache.set(key, result, 86400) return result -@cache_wrapper(prefix="contest_attempted") def contest_attempted_ids(participation): - result = { - id: {"achieved_points": points, "max_points": max_points} - for id, max_points, points in ( - participation.submissions.values_list( - "problem__problem__id", "problem__points" - ) - .annotate(points=Max("points")) - .filter(points__lt=F("problem__points")) - ) - } + key = 'contest_attempted:%s' % participation.id + result = cache.get(key) + if result is None: + result = {id: {'achieved_points': points, 'max_points': max_points} + for id, max_points, points in (participation.submissions + .values_list('problem__problem__id', 'problem__points') + .annotate(points=Max('points')) + .filter(points__lt=F('problem__points')))} + cache.set(key, result, 86400) return result -@cache_wrapper(prefix="user_attempted") def user_attempted_ids(profile): - result = { - id: { - "achieved_points": points, - "max_points": max_points, - "last_submission": last_submission, - "code": problem_code, - "name": problem_name, - } - for id, max_points, problem_code, problem_name, points, last_submission in ( - Submission.objects.filter(user=profile) - .values_list( - "problem__id", "problem__points", "problem__code", "problem__name" - ) - .annotate(points=Max("points"), last_submission=Max("id")) - .filter(points__lt=F("problem__points")) - ) - } + key = 'user_attempted:%s' % profile.id + result = cache.get(key) + if result is None: + result = {id: {'achieved_points': points, 'max_points': max_points} + for id, max_points, points in (Submission.objects.filter(user=profile) + .values_list('problem__id', 'problem__points') + .annotate(points=Max('points')) + .filter(points__lt=F('problem__points')))} + cache.set(key, result, 86400) return result def _get_result_data(results): return { - "categories": [ + 'categories': [ # Using gettext_noop here since this will be tacked into the cache, so it must be language neutral. # The caller, SubmissionList.get_result_data will run ugettext on the name. - {"code": "AC", "name": gettext_noop("Accepted"), "count": results["AC"]}, - { - "code": "WA", - "name": gettext_noop("Wrong Answer"), - "count": results["WA"], - }, - { - "code": "CE", - "name": gettext_noop("Compile Error"), - "count": results["CE"], - }, - { - "code": "TLE", - "name": gettext_noop("Time Limit Exceeded"), - "count": results["TLE"], - }, - { - "code": "ERR", - "name": gettext_noop("Error"), - "count": results["MLE"] - + results["OLE"] - + results["IR"] - + results["RTE"] - + results["AB"] - + results["IE"], - }, + {'code': 'AC', 'name': gettext_noop('Accepted'), 'count': results['AC']}, + {'code': 'WA', 'name': gettext_noop('Wrong'), 'count': results['WA']}, + {'code': 'CE', 'name': gettext_noop('Compile Error'), 'count': results['CE']}, + {'code': 'TLE', 'name': gettext_noop('Timeout'), 'count': results['TLE']}, + {'code': 'ERR', 'name': gettext_noop('Error'), + 'count': results['MLE'] + results['OLE'] + results['IR'] + results['RTE'] + results['AB'] + results['IE']}, ], - "total": sum(results.values()), + 'total': sum(results.values()), } @@ -150,16 +91,8 @@ def get_result_data(*args, **kwargs): if kwargs: raise ValueError(_("Can't pass both queryset and keyword filters")) else: - submissions = ( - Submission.objects.filter(**kwargs) - if kwargs is not None - else Submission.objects - ) - raw = ( - submissions.values("result") - .annotate(count=Count("result")) - .values_list("result", "count") - ) + submissions = Submission.objects.filter(**kwargs) if kwargs is not None else Submission.objects + raw = submissions.values('result').annotate(count=Count('result')).values_list('result', 'count') return _get_result_data(defaultdict(int, raw)) @@ -167,163 +100,48 @@ def editable_problems(user, profile=None): subquery = Problem.objects.all() if profile is None: profile = user.profile - if not user.has_perm("judge.edit_all_problem"): + if not user.has_perm('judge.edit_all_problem'): subfilter = Q(authors__id=profile.id) | Q(curators__id=profile.id) - if user.has_perm("judge.edit_public_problem"): + if user.has_perm('judge.edit_public_problem'): subfilter |= Q(is_public=True) subquery = subquery.filter(subfilter) return subquery -@cache_wrapper(prefix="hp", timeout=14400) def hot_problems(duration, limit): - qs = Problem.get_public_problems().filter( - submission__date__gt=timezone.now() - duration - ) - qs0 = ( - qs.annotate(k=Count("submission__user", distinct=True)) - .order_by("-k") - .values_list("k", flat=True) - ) + cache_key = 'hot_problems:%d:%d' % (duration.total_seconds(), limit) + qs = cache.get(cache_key) + if qs is None: + qs = Problem.objects.filter(is_public=True, is_organization_private=False, + submission__date__gt=timezone.now() - duration, points__gt=3, points__lt=25) + qs0 = qs.annotate(k=Count('submission__user', distinct=True)).order_by('-k').values_list('k', flat=True) - if not qs0: - return [] - # make this an aggregate - mx = float(qs0[0]) + if not qs0: + return [] + # make this an aggregate + mx = float(qs0[0]) - qs = qs.annotate(unique_user_count=Count("submission__user", distinct=True)) - # fix braindamage in excluding CE - qs = qs.annotate( - submission_volume=Count( - Case( - When(submission__result="AC", then=1), - When(submission__result="WA", then=1), - When(submission__result="IR", then=1), - When(submission__result="RTE", then=1), - When(submission__result="TLE", then=1), - When(submission__result="OLE", then=1), - output_field=FloatField(), - ) - ) - ) - qs = qs.annotate( - ac_volume=Count( - Case( - When(submission__result="AC", then=1), - output_field=FloatField(), - ) - ) - ) - qs = qs.filter(unique_user_count__gt=max(mx / 3.0, 1)) + qs = qs.annotate(unique_user_count=Count('submission__user', distinct=True)) + # fix braindamage in excluding CE + qs = qs.annotate(submission_volume=Count(Case( + When(submission__result='AC', then=1), + When(submission__result='WA', then=1), + When(submission__result='IR', then=1), + When(submission__result='RTE', then=1), + When(submission__result='TLE', then=1), + When(submission__result='OLE', then=1), + output_field=FloatField(), + ))) + qs = qs.annotate(ac_volume=Count(Case( + When(submission__result='AC', then=1), + output_field=FloatField(), + ))) + qs = qs.filter(unique_user_count__gt=max(mx / 3.0, 1)) - qs = ( - qs.annotate( - ordering=ExpressionWrapper( - 0.02 - * F("points") - * (0.4 * F("ac_volume") / F("submission_volume") + 0.6 * F("ac_rate")) - + 100 * e ** (F("unique_user_count") / mx), - output_field=FloatField(), - ) - ) - .order_by("-ordering") - .defer("description")[:limit] - ) + qs = qs.annotate(ordering=ExpressionWrapper( + 0.5 * F('points') * (0.4 * F('ac_volume') / F('submission_volume') + 0.6 * F('ac_rate')) + + 100 * e ** (F('unique_user_count') / mx), output_field=FloatField(), + )).order_by('-ordering').defer('description')[:limit] + + cache.set(cache_key, qs, 900) return qs - - -@cache_wrapper(prefix="grp", timeout=14400) -def get_related_problems(profile, problem, limit=8): - if not profile or not settings.ML_OUTPUT_PATH: - return None - problemset = Problem.get_visible_problems(profile.user).values_list("id", flat=True) - problemset = problemset.exclude(id__in=user_completed_ids(profile)) - problemset = problemset.exclude(id=problem.id) - cf_model = CollabFilter("collab_filter") - results = cf_model.problem_neighbors( - problem, problemset, CollabFilter.DOT, limit - ) + cf_model.problem_neighbors(problem, problemset, CollabFilter.COSINE, limit) - results = list(set([i[1] for i in results])) - seed = datetime.now().strftime("%d%m%Y") - random.shuffle(results) - results = results[:limit] - results = [Problem.objects.get(id=i) for i in results] - return results - - -def finished_submission(sub): - keys = ["user_complete:%d" % sub.user_id, "user_attempted:%s" % sub.user_id] - if hasattr(sub, "contest"): - participation = sub.contest.participation - keys += ["contest_complete:%d" % participation.id] - keys += ["contest_attempted:%d" % participation.id] - cache.delete_many(keys) - - -class RecommendationType(Enum): - HOT_PROBLEM = 1 - CF_DOT = 2 - CF_COSINE = 3 - CF_TIME_DOT = 4 - CF_TIME_COSINE = 5 - - -# Return a list of list. Each inner list correspond to each type in types -def get_user_recommended_problems( - user_id, - problem_ids, - recommendation_types, - limits, - shuffle=False, -): - cf_model = CollabFilter("collab_filter") - cf_time_model = CollabFilter("collab_filter_time") - - def get_problem_ids_from_type(rec_type, limit): - if type(rec_type) == int: - try: - rec_type = RecommendationType(rec_type) - except ValueError: - raise Http404() - if rec_type == RecommendationType.HOT_PROBLEM: - return [ - problem.id - for problem in hot_problems(timedelta(days=7), limit) - if problem.id in set(problem_ids) - ] - if rec_type == RecommendationType.CF_DOT: - return cf_model.user_recommendations( - user_id, problem_ids, cf_model.DOT, limit - ) - if rec_type == RecommendationType.CF_COSINE: - return cf_model.user_recommendations( - user_id, problem_ids, cf_model.COSINE, limit - ) - if rec_type == RecommendationType.CF_TIME_DOT: - return cf_time_model.user_recommendations( - user_id, problem_ids, cf_model.DOT, limit - ) - if rec_type == RecommendationType.CF_TIME_COSINE: - return cf_time_model.user_recommendations( - user_id, problem_ids, cf_model.COSINE, limit - ) - return [] - - all_problems = [] - for rec_type, limit in zip(recommendation_types, limits): - all_problems += get_problem_ids_from_type(rec_type, limit) - if shuffle: - seed = datetime.now().strftime("%d%m%Y") - random.Random(seed).shuffle(all_problems) - - # deduplicate problems - res = [] - used_pid = set() - - for obj in all_problems: - if type(obj) == tuple: - obj = obj[1] - if obj not in used_pid: - res.append(obj) - used_pid.add(obj) - return res diff --git a/judge/utils/pwned.py b/judge/utils/pwned.py index bd67acc..fa3df63 100644 --- a/judge/utils/pwned.py +++ b/judge/utils/pwned.py @@ -40,13 +40,14 @@ import requests from django.conf import settings from django.contrib.auth.password_validation import CommonPasswordValidator from django.core.exceptions import ValidationError +from django.utils.six import string_types from django.utils.translation import gettext as _, ungettext from judge.utils.unicode import utf8bytes log = logging.getLogger(__name__) -API_ENDPOINT = "https://api.pwnedpasswords.com/range/{}" +API_ENDPOINT = 'https://api.pwnedpasswords.com/range/{}' REQUEST_TIMEOUT = 2.0 # 2 seconds @@ -60,19 +61,19 @@ def _get_pwned(prefix): url=API_ENDPOINT.format(prefix), timeout=getattr( settings, - "PWNED_PASSWORDS_API_TIMEOUT", + 'PWNED_PASSWORDS_API_TIMEOUT', REQUEST_TIMEOUT, ), ) response.raise_for_status() except requests.RequestException: # Gracefully handle timeouts and HTTP error response codes. - log.warning("Skipped Pwned Passwords check due to error", exc_info=True) + log.warning('Skipped Pwned Passwords check due to error', exc_info=True) return None results = {} for line in response.text.splitlines(): - line_suffix, _, times = line.partition(":") + line_suffix, _, times = line.partition(':') results[line_suffix] = int(times) return results @@ -82,8 +83,8 @@ def pwned_password(password): """ Checks a password against the Pwned Passwords database. """ - if not isinstance(password, str): - raise TypeError("Password values to check must be strings.") + if not isinstance(password, string_types): + raise TypeError('Password values to check must be strings.') password_hash = hashlib.sha1(utf8bytes(password)).hexdigest().upper() prefix, suffix = password_hash[:5], password_hash[5:] results = _get_pwned(prefix) @@ -97,22 +98,21 @@ class PwnedPasswordsValidator(object): """ Password validator which checks the Pwned Passwords database. """ - DEFAULT_HELP_MESSAGE = _("Your password can't be a commonly used password.") - DEFAULT_PWNED_MESSAGE = _("This password is too common.") + DEFAULT_PWNED_MESSAGE = _('This password is too common.') def __init__(self, error_message=None, help_message=None): self.help_message = help_message or self.DEFAULT_HELP_MESSAGE error_message = error_message or self.DEFAULT_PWNED_MESSAGE # If there is no plural, use the same message for both forms. - if isinstance(error_message, str): + if isinstance(error_message, string_types): singular, plural = error_message, error_message else: singular, plural = error_message self.error_message = { - "singular": singular, - "plural": plural, + 'singular': singular, + 'plural': plural, } def validate(self, password, user=None): @@ -125,12 +125,12 @@ class PwnedPasswordsValidator(object): elif amount: raise ValidationError( ungettext( - self.error_message["singular"], - self.error_message["plural"], + self.error_message['singular'], + self.error_message['plural'], amount, ), - params={"amount": amount}, - code="pwned_password", + params={'amount': amount}, + code='pwned_password', ) def get_help_text(self): diff --git a/judge/utils/ranker.py b/judge/utils/ranker.py index 3f15e62..b1a856a 100644 --- a/judge/utils/ranker.py +++ b/judge/utils/ranker.py @@ -1,7 +1,7 @@ from operator import attrgetter -def ranker(iterable, key=attrgetter("points"), rank=0): +def ranker(iterable, key=attrgetter('points'), rank=0): delta = 1 last = None for item in iterable: @@ -12,3 +12,23 @@ def ranker(iterable, key=attrgetter("points"), rank=0): delta += 1 yield rank, item last = key(item) + + +def tie_ranker(iterable, key=attrgetter('points')): + rank = 0 + delta = 1 + last = None + buf = [] + for item in iterable: + new = key(item) + if new != last: + for i in buf: + yield rank + (delta - 1) / 2.0, i + rank += delta + delta = 0 + buf = [] + delta += 1 + buf.append(item) + last = key(item) + for i in buf: + yield rank + (delta - 1) / 2.0, i diff --git a/judge/utils/raw_sql.py b/judge/utils/raw_sql.py index 736314d..edbca4c 100644 --- a/judge/utils/raw_sql.py +++ b/judge/utils/raw_sql.py @@ -1,43 +1,48 @@ +from copy import copy + from django.db import connections +from django.db.models import Field +from django.db.models.expressions import RawSQL from django.db.models.sql.constants import INNER, LOUTER from django.db.models.sql.datastructures import Join +from django.utils import six from judge.utils.cachedict import CacheDict +def unique_together_left_join(queryset, model, link_field_name, filter_field_name, filter_value, parent_model=None): + link_field = copy(model._meta.get_field(link_field_name).remote_field) + filter_field = model._meta.get_field(filter_field_name) + + def restrictions(where_class, alias, related_alias): + cond = where_class() + cond.add(filter_field.get_lookup('exact')(filter_field.get_col(alias), filter_value), 'AND') + return cond + + link_field.get_extra_restriction = restrictions + + if parent_model is not None: + parent_alias = parent_model._meta.db_table + else: + parent_alias = queryset.query.get_initial_alias() + return queryset.query.join(Join(model._meta.db_table, parent_alias, None, LOUTER, link_field, True)) + + class RawSQLJoin(Join): - def __init__( - self, - subquery, - subquery_params, - parent_alias, - table_alias, - join_type, - join_field, - nullable, - filtered_relation=None, - ): + def __init__(self, subquery, subquery_params, parent_alias, table_alias, join_type, join_field, nullable, + filtered_relation=None): self.subquery_params = subquery_params - super().__init__( - subquery, - parent_alias, - table_alias, - join_type, - join_field, - nullable, - filtered_relation, - ) + super().__init__(subquery, parent_alias, table_alias, join_type, join_field, nullable, filtered_relation) def as_sql(self, compiler, connection): - compiler.quote_cache[self.table_name] = "(%s)" % self.table_name + compiler.quote_cache[self.table_name] = '(%s)' % self.table_name sql, params = super().as_sql(compiler, connection) return sql, self.subquery_params + params class FakeJoinField: - def __init__(self, joining_columns, related_model): + def __init__(self, joining_columns): self.joining_columns = joining_columns - self.related_model = related_model def get_joining_columns(self): return self.joining_columns @@ -46,44 +51,33 @@ class FakeJoinField: pass -def join_sql_subquery( - queryset, - subquery, - params, - join_fields, - alias, - related_model, - join_type=INNER, - parent_model=None, -): +def join_sql_subquery(queryset, subquery, params, join_fields, alias, join_type=INNER, parent_model=None): if parent_model is not None: parent_alias = parent_model._meta.db_table else: parent_alias = queryset.query.get_initial_alias() - if isinstance(queryset.query.external_aliases, dict): # Django 3.x - queryset.query.external_aliases[alias] = True - else: - queryset.query.external_aliases.add(alias) - join = RawSQLJoin( - subquery, - params, - parent_alias, - alias, - join_type, - FakeJoinField(join_fields, related_model), - join_type == LOUTER, - ) + queryset.query.external_aliases.add(alias) + join = RawSQLJoin(subquery, params, parent_alias, alias, join_type, FakeJoinField(join_fields), join_type == LOUTER) queryset.query.join(join) join.table_alias = alias +def RawSQLColumn(model, field=None): + if isinstance(model, Field): + field = model + model = field.model + if isinstance(field, six.string_types): + field = model._meta.get_field(field) + return RawSQL('%s.%s' % (model._meta.db_table, field.get_attname_column()[1]), ()) + + def make_straight_join_query(QueryType): class Query(QueryType): def join(self, join, *args, **kwargs): alias = super().join(join, *args, **kwargs) join = self.alias_map[alias] if join.join_type == INNER: - join.join_type = "STRAIGHT_JOIN" + join.join_type = 'STRAIGHT_JOIN' return alias return Query @@ -93,7 +87,7 @@ straight_join_cache = CacheDict(make_straight_join_query) def use_straight_join(queryset): - if connections[queryset.db].vendor != "mysql": + if connections[queryset.db].vendor != 'mysql': return try: cloner = queryset.query.chain diff --git a/judge/utils/recaptcha.py b/judge/utils/recaptcha.py index 9be7e5f..331a12d 100644 --- a/judge/utils/recaptcha.py +++ b/judge/utils/recaptcha.py @@ -6,7 +6,6 @@ except ImportError: ReCaptchaWidget = None else: from django.conf import settings - - if not hasattr(settings, "RECAPTCHA_PRIVATE_KEY"): + if not hasattr(settings, 'RECAPTCHA_PRIVATE_KEY'): ReCaptchaField = None ReCaptchaWidget = None diff --git a/judge/utils/stats.py b/judge/utils/stats.py index 6c79d8c..cf3b251 100644 --- a/judge/utils/stats.py +++ b/judge/utils/stats.py @@ -1,30 +1,10 @@ from operator import itemgetter -__all__ = ("chart_colors", "highlight_colors", "get_pie_chart", "get_bar_chart") +__all__ = ('chart_colors', 'highlight_colors', 'get_pie_chart', 'get_bar_chart') -chart_colors = [ - 0x3366CC, - 0xDC3912, - 0xFF9900, - 0x109618, - 0x990099, - 0x3B3EAC, - 0x0099C6, - 0xDD4477, - 0x66AA00, - 0xB82E2E, - 0x316395, - 0x994499, - 0x22AA99, - 0xAAAA11, - 0x6633CC, - 0xE67300, - 0x8B0707, - 0x329262, - 0x5574A6, - 0x3B3EAC, -] +chart_colors = [0x3366CC, 0xDC3912, 0xFF9900, 0x109618, 0x990099, 0x3B3EAC, 0x0099C6, 0xDD4477, 0x66AA00, 0xB82E2E, + 0x316395, 0x994499, 0x22AA99, 0xAAAA11, 0x6633CC, 0xE67300, 0x8B0707, 0x329262, 0x5574A6, 0x3B3EAC] highlight_colors = [] @@ -33,26 +13,25 @@ highlight_colors = [] def _highlight_colors(): for color in chart_colors: r, g, b = color >> 16, (color >> 8) & 0xFF, color & 0xFF - highlight_colors.append( - "#%02X%02X%02X" - % (min(int(r * 1.2), 255), min(int(g * 1.2), 255), min(int(b * 1.2), 255)) - ) + highlight_colors.append('#%02X%02X%02X' % (min(int(r * 1.2), 255), + min(int(g * 1.2), 255), + min(int(b * 1.2), 255))) _highlight_colors() -chart_colors = list(map("#%06X".__mod__, chart_colors)) +chart_colors = list(map('#%06X'.__mod__, chart_colors)) def get_pie_chart(data): return { - "labels": list(map(itemgetter(0), data)), - "datasets": [ + 'labels': list(map(itemgetter(0), data)), + 'datasets': [ { - "backgroundColor": chart_colors, - "highlightBackgroundColor": highlight_colors, - "data": list(map(itemgetter(1), data)), + 'backgroundColor': chart_colors, + 'highlightBackgroundColor': highlight_colors, + 'data': list(map(itemgetter(1), data)), }, ], } @@ -60,39 +39,15 @@ def get_pie_chart(data): def get_bar_chart(data, **kwargs): return { - "labels": list(map(itemgetter(0), data)), - "datasets": [ + 'labels': list(map(itemgetter(0), data)), + 'datasets': [ { - "backgroundColor": kwargs.get("fillColor", "rgba(151,187,205,0.5)"), - "borderColor": kwargs.get("strokeColor", "rgba(151,187,205,0.8)"), - "borderWidth": 1, - "hoverBackgroundColor": kwargs.get( - "highlightFill", "rgba(151,187,205,0.75)" - ), - "hoverBorderColor": kwargs.get( - "highlightStroke", "rgba(151,187,205,1)" - ), - "data": list(map(itemgetter(1), data)), - }, - ], - } - - -def get_histogram(data, **kwargs): - return { - "labels": [round(i, 1) for i in list(map(itemgetter(0), data))], - "datasets": [ - { - "backgroundColor": kwargs.get("fillColor", "rgba(151,187,205,0.5)"), - "borderColor": kwargs.get("strokeColor", "rgba(151,187,205,0.8)"), - "borderWidth": 1, - "hoverBackgroundColor": kwargs.get( - "highlightFill", "rgba(151,187,205,0.75)" - ), - "hoverBorderColor": kwargs.get( - "highlightStroke", "rgba(151,187,205,1)" - ), - "data": list(map(itemgetter(1), data)), + 'backgroundColor': kwargs.get('fillColor', 'rgba(151,187,205,0.5)'), + 'borderColor': kwargs.get('strokeColor', 'rgba(151,187,205,0.8)'), + 'borderWidth': 1, + 'hoverBackgroundColor': kwargs.get('highlightFill', 'rgba(151,187,205,0.75)'), + 'hoverBorderColor': kwargs.get('highlightStroke', 'rgba(151,187,205,1)'), + 'data': list(map(itemgetter(1), data)), }, ], } diff --git a/judge/utils/subscription.py b/judge/utils/subscription.py new file mode 100644 index 0000000..1129b0d --- /dev/null +++ b/judge/utils/subscription.py @@ -0,0 +1,8 @@ +from django.conf import settings + +if 'newsletter' in settings.INSTALLED_APPS: + from newsletter.models import Subscription +else: + Subscription = None + +newsletter_id = None if Subscription is None else settings.DMOJ_NEWSLETTER_ID_ON_REGISTER diff --git a/judge/utils/texoid.py b/judge/utils/texoid.py index cb51169..d668066 100644 --- a/judge/utils/texoid.py +++ b/judge/utils/texoid.py @@ -10,16 +10,16 @@ from django.core.cache import caches from judge.utils.file_cache import HashFileCache from judge.utils.unicode import utf8bytes -logger = logging.getLogger("judge.texoid") +logger = logging.getLogger('judge.texoid') -TEXOID_ENABLED = hasattr(settings, "TEXOID_URL") +TEXOID_ENABLED = hasattr(settings, 'TEXOID_URL') class TexoidRenderer(object): def __init__(self): - self.cache = HashFileCache( - settings.TEXOID_CACHE_ROOT, settings.TEXOID_CACHE_URL, settings.TEXOID_GZIP - ) + self.cache = HashFileCache(settings.TEXOID_CACHE_ROOT, + settings.TEXOID_CACHE_URL, + settings.TEXOID_GZIP) self.meta_cache = caches[settings.TEXOID_META_CACHE] self.meta_cache_ttl = settings.TEXOID_META_CACHE_TTL @@ -27,69 +27,59 @@ class TexoidRenderer(object): self.cache.create(hash) try: - response = requests.post( - settings.TEXOID_URL, - data=utf8bytes(document), - headers={ - "Content-Type": "application/x-tex", - }, - ) + response = requests.post(settings.TEXOID_URL, data=utf8bytes(document), headers={ + 'Content-Type': 'application/x-tex', + }) response.raise_for_status() except requests.HTTPError as e: if e.response.status == 400: - logger.error( - "Texoid failed to render: %s\n%s", document, e.response.text - ) + logger.error('Texoid failed to render: %s\n%s', document, e.response.text) else: - logger.exception("Failed to connect to texoid for: %s", document) + logger.exception('Failed to connect to texoid for: %s', document) return except Exception: - logger.exception("Failed to connect to texoid for: %s", document) + logger.exception('Failed to connect to texoid for: %s', document) return try: data = response.json() except ValueError: - logger.exception( - "Invalid texoid response for: %s\n%s", document, response.text - ) + logger.exception('Invalid texoid response for: %s\n%s', document, response.text) return - if not data["success"]: - logger.error("Texoid failure for: %s\n%s", document, data) - return {"error": data["error"]} + if not data['success']: + logger.error('Texoid failure for: %s\n%s', document, data) + return {'error': data['error']} - meta = data["meta"] - self.cache.cache_data( - hash, "meta", utf8bytes(json.dumps(meta)), url=False, gzip=False - ) + meta = data['meta'] + self.cache.cache_data(hash, 'meta', utf8bytes(json.dumps(meta)), url=False, gzip=False) result = { - "png": self.cache.cache_data(hash, "png", b64decode(data["png"])), - "svg": self.cache.cache_data(hash, "svg", data["svg"].encode("utf-8")), - "meta": meta, + 'png': self.cache.cache_data(hash, 'png', b64decode(data['png'])), + 'svg': self.cache.cache_data(hash, 'svg', data['svg'].encode('utf-8')), + 'meta': meta, } return result def query_cache(self, hash): result = { - "svg": self.cache.get_url(hash, "svg"), - "png": self.cache.get_url(hash, "png"), + 'svg': self.cache.get_url(hash, 'svg'), + 'png': self.cache.get_url(hash, 'png'), } - key = "texoid:meta:" + hash + key = 'texoid:meta:' + hash cached_meta = self.meta_cache.get(key) if cached_meta is None: - cached_meta = json.loads(self.cache.read_data(hash, "meta").decode("utf-8")) + cached_meta = json.loads(self.cache.read_data(hash, 'meta').decode('utf-8')) self.meta_cache.set(key, cached_meta, self.meta_cache_ttl) - result["meta"] = cached_meta + result['meta'] = cached_meta return result def get_result(self, formula): hash = hashlib.sha1(utf8bytes(formula)).hexdigest() - if self.cache.has_file(hash, "svg"): + if self.cache.has_file(hash, 'svg'): return self.query_cache(hash) else: return self.query_texoid(formula, hash) diff --git a/judge/utils/tickets.py b/judge/utils/tickets.py index b630e60..1743db4 100644 --- a/judge/utils/tickets.py +++ b/judge/utils/tickets.py @@ -12,10 +12,6 @@ def own_ticket_filter(profile_id): def filter_visible_tickets(queryset, user, profile=None): if profile is None: profile = user.profile - return queryset.filter( - own_ticket_filter(profile.id) - | Q( - content_type=ContentType.objects.get_for_model(Problem), - object_id__in=editable_problems(user, profile), - ) - ).distinct() + return queryset.filter(own_ticket_filter(profile.id) | + Q(content_type=ContentType.objects.get_for_model(Problem), + object_id__in=editable_problems(user, profile))).distinct() diff --git a/judge/utils/timedelta.py b/judge/utils/timedelta.py index adf3330..292caeb 100644 --- a/judge/utils/timedelta.py +++ b/judge/utils/timedelta.py @@ -3,7 +3,7 @@ import datetime from django.utils.translation import npgettext, pgettext, ungettext -def nice_repr(timedelta, display="long", sep=", "): +def nice_repr(timedelta, display='long', sep=', '): """ Turns a datetime.timedelta object into a nice string repr. @@ -16,9 +16,7 @@ def nice_repr(timedelta, display="long", sep=", "): '1d, 1s' """ - assert isinstance( - timedelta, datetime.timedelta - ), "First argument must be a timedelta." + assert isinstance(timedelta, datetime.timedelta), 'First argument must be a timedelta.' result = [] @@ -28,94 +26,65 @@ def nice_repr(timedelta, display="long", sep=", "): minutes = (timedelta.seconds % 3600) // 60 seconds = timedelta.seconds % 60 - if display == "simple-no-seconds": + if display == 'simple-no-seconds': days += weeks * 7 if days: if hours or minutes: - return "%d day%s %d:%02d" % (days, "s"[days == 1 :], hours, minutes) - return "%d day%s" % (days, "s"[days == 1 :]) + return '%d day%s %d:%02d' % (days, 's'[days == 1:], hours, minutes) + return '%d day%s' % (days, 's'[days == 1:]) else: - return "%d:%02d" % (hours, minutes) - elif display == "sql": + return '%d:%02d' % (hours, minutes) + elif display == 'sql': days += weeks * 7 - return "%d %02d:%02d:%02d" % (days, hours, minutes, seconds) - elif display == "simple": + return '%d %02d:%02d:%02d' % (days, hours, minutes, seconds) + elif display == 'simple': days += weeks * 7 if days: - return "%d day%s %02d:%02d:%02d" % ( - days, - "s"[days == 1 :], - hours, - minutes, - seconds, - ) + return '%d day%s %02d:%02d:%02d' % (days, 's'[days == 1:], hours, minutes, seconds) else: - return "%02d:%02d:%02d" % (hours, minutes, seconds) - elif display == "localized": + return '%02d:%02d:%02d' % (hours, minutes, seconds) + elif display == 'localized': days += weeks * 7 if days: - return ( - npgettext( - "time format with day", "%d day %h:%m:%s", "%d days %h:%m:%s", days - ) - .replace("%d", str(days)) - .replace("%h", "%02d" % hours) - .replace("%m", "%02d" % minutes) - .replace("%s", "%02d" % seconds) - ) + return npgettext('time format with day', '%d day %h:%m:%s', '%d days %h:%m:%s', days) \ + .replace('%d', str(days)).replace('%h', '%02d' % hours).replace('%m', '%02d' % minutes) \ + .replace('%s', '%02d' % seconds) else: - return ( - pgettext("time format without day", "%h:%m:%s") - .replace("%h", "%02d" % hours) - .replace("%m", "%02d" % minutes) - .replace("%s", "%02d" % seconds) - ) - elif display == "localized-no-seconds": + return pgettext('time format without day', '%h:%m:%s') \ + .replace('%h', '%02d' % hours).replace('%m', '%02d' % minutes).replace('%s', '%02d' % seconds) + elif display == 'localized-no-seconds': days += weeks * 7 if days: if hours or minutes: - return ( - npgettext( - "time format no seconds with day", - "%d day %h:%m", - "%d days %h:%m", - days, - ) - .replace("%d", str(days)) - .replace("%h", "%02d" % hours) - .replace("%m", "%02d" % minutes) - ) - return ungettext("%d day", "%d days", days) % days + return npgettext('time format no seconds with day', '%d day %h:%m', '%d days %h:%m', days) \ + .replace('%d', str(days)).replace('%h', '%02d' % hours).replace('%m', '%02d' % minutes) + return ungettext('%d day', '%d days', days) % days else: - return ( - pgettext("hours and minutes", "%h:%m") - .replace("%h", "%02d" % hours) - .replace("%m", "%02d" % minutes) - ) - elif display == "concise": + return pgettext('hours and minutes', '%h:%m').replace('%h', '%02d' % hours).replace('%m', '%02d' % minutes) + elif display == 'concise': days += weeks * 7 if days: - return "%dd %02d:%02d:%02d" % (days, hours, minutes, seconds) + return '%dd %02d:%02d:%02d' % (days, hours, minutes, seconds) else: - return "%02d:%02d:%02d" % (hours, minutes, seconds) - elif display == "noday": + return '%02d:%02d:%02d' % (hours, minutes, seconds) + elif display == 'noday': days += weeks * 7 hours += days * 24 - return "%02d:%02d:%02d" % (hours, minutes, seconds) - elif display == "minimal": - words = ["w", "d", "h", "m", "s"] - elif display == "short": - words = [" wks", " days", " hrs", " min", " sec"] + return '%02d:%02d:%02d' % (hours, minutes, seconds) + elif display == 'minimal': + words = ['w', 'd', 'h', 'm', 's'] + elif display == 'short': + words = [' wks', ' days', ' hrs', ' min', ' sec'] else: - words = [" weeks", " days", " hours", " minutes", " seconds"] + words = [' weeks', ' days', ' hours', ' minutes', ' seconds'] values = [weeks, days, hours, minutes, seconds] for i in range(len(values)): if values[i]: if values[i] == 1 and len(words[i]) > 1: - result.append("%i%s" % (values[i], words[i].rstrip("s"))) + result.append('%i%s' % (values[i], words[i].rstrip('s'))) else: - result.append("%i%s" % (values[i], words[i])) + result.append('%i%s' % (values[i], words[i])) return sep.join(result) diff --git a/judge/utils/unicode.py b/judge/utils/unicode.py index 084be4f..78cc176 100644 --- a/judge/utils/unicode.py +++ b/judge/utils/unicode.py @@ -1,37 +1,17 @@ -from typing import AnyStr, Optional, overload - - -@overload -def utf8bytes(maybe_text: AnyStr) -> bytes: - pass - - -@overload -def utf8bytes(maybe_text: None) -> None: - pass +from django.utils import six def utf8bytes(maybe_text): if maybe_text is None: - return None - if isinstance(maybe_text, bytes): + return + if isinstance(maybe_text, six.binary_type): return maybe_text - return maybe_text.encode("utf-8") + return maybe_text.encode('utf-8') -@overload -def utf8text(maybe_bytes: AnyStr, errors="strict") -> str: - pass - - -@overload -def utf8text(maybe_bytes: None, errors="strict") -> None: - pass - - -def utf8text(maybe_bytes, errors="strict") -> Optional[str]: +def utf8text(maybe_bytes, errors='strict'): if maybe_bytes is None: - return None - if isinstance(maybe_bytes, str): + return + if isinstance(maybe_bytes, six.text_type): return maybe_bytes - return maybe_bytes.decode("utf-8", errors) + return maybe_bytes.decode('utf-8', errors) diff --git a/judge/utils/users.py b/judge/utils/users.py deleted file mode 100644 index 9ac071c..0000000 --- a/judge/utils/users.py +++ /dev/null @@ -1,67 +0,0 @@ -from django.urls import reverse -from django.utils.formats import date_format -from django.utils.translation import gettext as _, gettext_lazy - -from judge.caching import cache_wrapper -from judge.models import Profile, Rating, Submission, Friend, ProfileInfo - - -@cache_wrapper(prefix="grr") -def get_rating_rank(profile): - if profile.is_unlisted: - return None - rank = None - if profile.rating: - rank = ( - Profile.objects.filter( - is_unlisted=False, - rating__gt=profile.rating, - ).count() - + 1 - ) - return rank - - -@cache_wrapper(prefix="gpr") -def get_points_rank(profile): - if profile.is_unlisted: - return None - return ( - Profile.objects.filter( - is_unlisted=False, - performance_points__gt=profile.performance_points, - ).count() - + 1 - ) - - -@cache_wrapper(prefix="gcr") -def get_contest_ratings(profile): - return ( - profile.ratings.order_by("-contest__end_time") - .select_related("contest") - .defer("contest__description") - ) - - -def get_awards(profile): - ratings = get_contest_ratings(profile) - - sorted_ratings = sorted( - ratings, key=lambda x: (x.rank, -x.contest.end_time.timestamp()) - ) - - result = [ - { - "label": rating.contest.name, - "ranking": rating.rank, - "link": reverse("contest_ranking", args=(rating.contest.key,)) - + "#!" - + profile.username, - "date": date_format(rating.contest.end_time, _("M j, Y")), - } - for rating in sorted_ratings - if rating.rank <= 3 - ] - - return result diff --git a/judge/utils/views.py b/judge/utils/views.py index 530caba..ba383ce 100644 --- a/judge/utils/views.py +++ b/judge/utils/views.py @@ -4,7 +4,6 @@ from django.views.generic import FormView from django.views.generic.detail import SingleObjectMixin from judge.utils.diggpaginator import DiggPaginator -from django.utils.html import mark_safe def class_view_decorator(function_decorator): @@ -23,43 +22,34 @@ def class_view_decorator(function_decorator): def generic_message(request, title, message, status=None): - return render( - request, - "generic-message.html", - { - "message": message, - "title": title, - }, - status=status, - ) + return render(request, 'generic-message.html', { + 'message': message, + 'title': title, + }, status=status) def paginate_query_context(request): query = request.GET.copy() - query.setlist("page", []) + query.setlist('page', []) query = query.urlencode() if query: - return { - "page_prefix": "%s?%s&page=" % (request.path, query), - "first_page_href": "%s?%s" % (request.path, query), - } + return {'page_prefix': '%s?%s&page=' % (request.path, query), + 'first_page_href': '%s?%s' % (request.path, query)} else: - return { - "page_prefix": "%s?page=" % request.path, - "first_page_href": request.path, - } + return {'page_prefix': '%s?page=' % request.path, + 'first_page_href': request.path} class TitleMixin(object): - title = "(untitled)" + title = '(untitled)' content_title = None def get_context_data(self, **kwargs): context = super(TitleMixin, self).get_context_data(**kwargs) - context["title"] = self.get_title() + context['title'] = self.get_title() content_title = self.get_content_title() if content_title is not None: - context["content_title"] = content_title + context['content_title'] = content_title return context def get_content_title(self): @@ -70,18 +60,10 @@ class TitleMixin(object): class DiggPaginatorMixin(object): - def get_paginator( - self, queryset, per_page, orphans=0, allow_empty_first_page=True, **kwargs - ): - return DiggPaginator( - queryset, - per_page, - body=6, - padding=2, - orphans=orphans, - allow_empty_first_page=allow_empty_first_page, - **kwargs - ) + def get_paginator(self, queryset, per_page, orphans=0, + allow_empty_first_page=True, **kwargs): + return DiggPaginator(queryset, per_page, body=6, padding=2, + orphans=orphans, allow_empty_first_page=allow_empty_first_page, **kwargs) class QueryStringSortMixin(object): @@ -93,11 +75,8 @@ class QueryStringSortMixin(object): return self.default_sort def get(self, request, *args, **kwargs): - order = request.GET.get("order", "") - if not ( - (not order.startswith("-") or order.count("-") == 1) - and (order.lstrip("-") in self.all_sorts) - ): + order = request.GET.get('order', '') + if not ((not order.startswith('-') or order.count('-') == 1) and (order.lstrip('-') in self.all_sorts)): order = self.get_default_sort_order(request) self.order = order @@ -105,26 +84,17 @@ class QueryStringSortMixin(object): def get_sort_context(self): query = self.request.GET.copy() - query.setlist("order", []) + query.setlist('order', []) query = query.urlencode() - sort_prefix = ( - "%s?%s&order=" % (self.request.path, query) - if query - else "%s?order=" % self.request.path - ) - current = self.order.lstrip("-") + sort_prefix = '%s?%s&order=' % (self.request.path, query) if query else '%s?order=' % self.request.path + current = self.order.lstrip('-') - links = { - key: sort_prefix + ("-" if key in self.default_desc else "") + key - for key in self.all_sorts - } - links[current] = ( - sort_prefix + ("" if self.order.startswith("-") else "-") + current - ) + links = {key: sort_prefix + ('-' if key in self.default_desc else '') + key for key in self.all_sorts} + links[current] = sort_prefix + ('' if self.order.startswith('-') else '-') + current - order = {key: "" for key in self.all_sorts} - order[current] = " \u25BE" if self.order.startswith("-") else " \u25B4" - return {"sort_links": links, "sort_order": order} + order = {key: '' for key in self.all_sorts} + order[current] = ' \u25BE' if self.order.startswith('-') else u' \u25B4' + return {'sort_links': links, 'sort_order': order} def get_sort_paginate_context(self): return paginate_query_context(self.request) diff --git a/judge/views/__init__.py b/judge/views/__init__.py index 94a01c5..37d173d 100644 --- a/judge/views/__init__.py +++ b/judge/views/__init__.py @@ -5,6 +5,6 @@ class TitledTemplateView(TemplateView): title = None def get_context_data(self, **kwargs): - if "title" not in kwargs and self.title is not None: - kwargs["title"] = self.title + if 'title' not in kwargs and self.title is not None: + kwargs['title'] = self.title return super(TitledTemplateView, self).get_context_data(**kwargs) diff --git a/judge/views/about.py b/judge/views/about.py index 3f6d266..d328066 100644 --- a/judge/views/about.py +++ b/judge/views/about.py @@ -3,252 +3,12 @@ from django.utils.translation import gettext as _ def about(request): - return render( - request, - "about/about.html", - { - "title": _("About"), - }, - ) + return render(request, 'about/about.html', { + 'title': _('About'), + }) def custom_checker_sample(request): - content = """ -1. Trình chấm tự viết (PY) -2. Trình chấm tự viết (CPP) -3. Interactive (CPP) -4. Dùng hàm như IOI (CPP) - ---- - -##1. Trình chấm tự viết (PY) -Đây là checker mặc định của website, cho phép người dùng cập nhật được nhiều thông tin nhất (chi tiết xem ở bên dưới). Chúng ta cần hoàn thành hàm `check` dưới đây: -```py -def check(process_output, judge_output, **kwargs): - # return True/False -``` - -Trong đó, `**kwargs` có thể chứa các biến sau: - -- `process_output`: output -- `judge_output`: đáp án -- `submission_source`: Code bài nộp -- `judge_input`: input -- `point_value`: điểm của test đang chấm -- `case_position`: thứ tự của test -- `submission_language`: ngôn ngữ của bài nộp -- `execution_time`: thời gian chạy - -**Return**: - -- Cách 1: Trả về True/False -- Cách 2: Trả về một object `CheckerResult` có thể được gọi như sau `CheckerResult(case_passed_bool, points_awarded, feedback='')` - -**Ví dụ:** -Dưới đây là ví dụ cho bài toán: Input gồm 1 số nguyên n. In ra 2 số nguyên a, b sao cho a + b = n. - -```py -from dmoj.result import CheckerResult - -def wa(feedback): - return CheckerResult(False, 0, feedback) - -def check(process_output, judge_output, judge_input, **kwargs): - # process the input - input_arr = judge_input.split() - assert(len(input_arr) == 1) - n = int(input_arr[0]) - - # process the contestant's output - output_arr = process_output.split() - - if (len(output_arr) != 2): - return wa('Wrong output format') - - try: - a, b = int(output_arr[0]), int(output_arr[1]) - except: - return wa('Wrong output format') - - if (n == a + b): - return True - return wa('a + b != n') -``` - -## 2. Trình chấm tự viết (CPP) - -Để sử dụng chức năng này, cần viết một chương trình C++ pass vào 3 arguments theo thứ tự `input_file`, `output_file`, `ans_file` tương ứng với các file input, output, đáp án. - -Để test chương trình trên máy tính, có thể dùng lệnh như sau (Windows): - -```bash -main.exe [input_file] [output_file] [ans_file] -``` - -hoặc thay bằng `./main` trên Linux/MacOS. - -**Return:** -Chương trình trả về giá trị: - -- 0 nếu AC (100% điểm) -- 1 nếu WA (0 điểm) -- 2 nếu điểm thành phần. Khi đó cần in ra stderr một số thực trong đoạn [0, 1] thể hiện cho tỷ lệ điểm. Nếu điểm < 1 thì hiển thị WA, điểm = 1 thì hiển thị AC. -Những thông tin được viết ra stdout (bằng cout) sẽ được in ra màn hình cho người nộp bài(feedback) - -**Ví dụ:** -Chương trình sau dùng để chấm bài toán: Cho n là một số nguyên dương. In ra hai số tự nhiên a, b sao cho a + b = n. - -Nếu in ra a + b = n và a, b >= 0 thì được 100% số điểm, nếu a + b = n nhưng một trong 2 số a, b âm thì được 50% số điểm. - -```cpp -#include -using namespace std; - -int main(int argc, char** argv) { - ifstream inp(argv[1]); - ifstream out(argv[2]); - ifstream ans(argv[3]); - - int n, a, b, c, d; - - inp >> n; - out >> a >> b; - ans >> c >> d; - - if (a + b == c + d) { - cout << a << " + " << b << " = " << c << " + " << d << endl; - - if (a >= 0 && b >= 0) { - return 0; // AC - } - else { - cerr << 0.5; - return 2; // PARTIAL - } - } - else { - cout << "a + b = " << a + b << " != " << n << endl; - return 1; // WA - } -} -``` - -## 3. Interactive (CPP) -Để sử dụng chức năng này, cần viết một chương trình C++ pass vào 2 arguments `input_file` `answer_file` tương ứng file input và đáp án (nếu cần thiết). - -Để test chương trình trên máy tính với tư cách thí sinh, có thể dùng lệnh như sau (Windows): - -```bash -main.exe [input_file] [answer_file] -``` - -hoặc thay bằng `./main` trên Linux/MacOS. - -**Return:** -Chương trình trả về giá trị: - -- 0 nếu AC (100% điểm) -- 1 nếu WA (0 điểm) -- 2 nếu điểm thành phần. Khi đó cần in ra stderr một số thực trong đoạn [0, 1] thể hiện cho tỷ lệ điểm. Nếu điểm < 1 thì hiển thị WA, điểm = 1 thì hiển thị AC. -Thông tin được in ra trong stderr (bằng cerr) sẽ là feedback hiển thị cho người dùng. - -**Ví dụ:** -Chương trình sau dùng để chấm bài toán guessgame: Người chơi phải tìm 1 số bí mật n (n chứa trong file input). Mỗi lần họ được hỏi một số x, và chương trình sẽ trả về "SMALLER", "BIGGER" hoặc "HOLA" dựa trên giá trị của n và x. Cần tìm ra n sau không quá 31 câu hỏi. - -```cpp -#include -using namespace std; - -void quit(string reason) { - cerr << reason << endl; - exit(1); -} - -void read(long long& guess) { - if (!(cin >> guess)) exit(1); // Nếu không có dòng này, chương trình sẽ chờ vô hạn - if (guess < 1 || guess > 2e9) exit(1); -} - -int main(int argc, char *argv[]) { - ifstream inp(argv[1]); - int N, guesses = 0; - long long guess; - inp >> N; - - while (guess != N && guesses <= 31) { - read(guess); - if (guess == N) { - cout << "HOLA" << endl; - } else if (guess > N) { - cout << "SMALLER" << endl; - } else { - cout << "BIGGER" << endl; - } - guesses++; - } - - cerr << "Number of used guesses: " << guesses << endl; - - if (guesses <= 31) - return 0; // AC - else { - cerr << "Used too many guesses" << endl; - return 1; // WA - } -} -``` -## 4. IOI Signature (CPP) -Đây là chức năng để sử dụng hàm như trong IOI. Thí sinh được cho một định nghĩa hàm và cần cài đặt hàm đó trả về giá trị đúng. -Để sử dụng chức năng này, cần viết 2 chương trình: -- Header: Đây là file định nghĩa hàm (đuôi phải là `.h`) -- Handler: Đây là chương trình xử lý input và xuất ra output dựa trên hàm (đuôi phải là `.cpp`) - -**Ví dụ:** -Cho bài toán: nhập vào số n. Viết hàm `solve(int n)` trả về `n * 2`. Giả sử input là multitest có dạng: -- Dòng đầu chứa `t` là số test -- Mỗi dòng chứa một số nguyên `n` - -**Header (header.h):** -```cpp -#ifndef _HEADER_INCLUDED -#define _HEADER_INCLUDED -long long solve(long long n); -#endif -``` - -**Handler (handler.cpp):** -```cpp -#include -#include "header.h" -using namespace std; - - -int main() { - int t; - cin >> t; - for (int z = 1; z <= t; z++) { - long long n; - cin >> n; - cout << solve(n) << "\\n"; - } - - return 0; -} -``` - -**Bài nộp thí sinh:** -```cpp -int solve(int n) { - return n * 2; -} -``` - -""" - return render( - request, - "about/custom-checker-sample.html", - { - "title": _("Custom Checker Sample"), - "content": content, - }, - ) + return render(request, 'about/custom-checker-sample.html', { + 'title': _('Custom Checker Sample'), + }) diff --git a/judge/views/api/api_v1.py b/judge/views/api/api_v1.py index 80f18f0..93e7690 100644 --- a/judge/views/api/api_v1.py +++ b/judge/views/api/api_v1.py @@ -5,128 +5,93 @@ from django.http import Http404, JsonResponse from django.shortcuts import get_object_or_404 from dmoj import settings -from judge.models import ( - Contest, - ContestParticipation, - ContestTag, - Problem, - Profile, - Submission, -) +from judge.models import Contest, ContestParticipation, ContestTag, Problem, Profile, Submission def sane_time_repr(delta): days = delta.days hours = delta.seconds / 3600 minutes = (delta.seconds % 3600) / 60 - return "%02d:%02d:%02d" % (days, hours, minutes) + return '%02d:%02d:%02d' % (days, hours, minutes) def api_v1_contest_list(request): - queryset = Contest.get_visible_contests(request.user).prefetch_related( - Prefetch("tags", queryset=ContestTag.objects.only("name"), to_attr="tag_list") - ) + queryset = Contest.objects.filter(is_visible=True, is_private=False, + is_organization_private=False).prefetch_related( + Prefetch('tags', queryset=ContestTag.objects.only('name'), to_attr='tag_list')).defer('description') - return JsonResponse( - { - c.key: { - "name": c.name, - "start_time": c.start_time.isoformat(), - "end_time": c.end_time.isoformat(), - "time_limit": c.time_limit and sane_time_repr(c.time_limit), - "labels": list(map(attrgetter("name"), c.tag_list)), - } - for c in queryset - } - ) + return JsonResponse({c.key: { + 'name': c.name, + 'start_time': c.start_time.isoformat(), + 'end_time': c.end_time.isoformat(), + 'time_limit': c.time_limit and sane_time_repr(c.time_limit), + 'labels': list(map(attrgetter('name'), c.tag_list)), + } for c in queryset}) def api_v1_contest_detail(request, contest): contest = get_object_or_404(Contest, key=contest) in_contest = contest.is_in_contest(request.user) - can_see_rankings = contest.can_see_full_scoreboard(request.user) - problems = list( - contest.contest_problems.select_related("problem") - .defer("problem__description") - .order_by("order") - ) - participations = ( - contest.users.filter(virtual=0) - .prefetch_related("user__organizations") - .annotate(username=F("user__user__username")) - .order_by("-score", "cumtime") - if can_see_rankings - else [] - ) + can_see_rankings = contest.can_see_scoreboard(request.user) + if contest.hide_scoreboard and in_contest: + can_see_rankings = False - can_see_problems = ( - in_contest or contest.ended or contest.is_editable_by(request.user) - ) + problems = list(contest.contest_problems.select_related('problem') + .defer('problem__description').order_by('order')) + participations = (contest.users.filter(virtual=0, user__is_unlisted=False) + .prefetch_related('user__organizations') + .annotate(username=F('user__user__username')) + .order_by('-score', 'cumtime') if can_see_rankings else []) - return JsonResponse( - { - "time_limit": contest.time_limit and contest.time_limit.total_seconds(), - "start_time": contest.start_time.isoformat(), - "end_time": contest.end_time.isoformat(), - "tags": list(contest.tags.values_list("name", flat=True)), - "is_rated": contest.is_rated, - "rate_all": contest.is_rated and contest.rate_all, - "has_rating": contest.ratings.exists(), - "rating_floor": contest.rating_floor, - "rating_ceiling": contest.rating_ceiling, - "format": { - "name": contest.format_name, - "config": contest.format_config, - }, - "problems": [ - { - "points": int(problem.points), - "partial": problem.partial, - "name": problem.problem.name, - "code": problem.problem.code, - } - for problem in problems - ] - if can_see_problems - else [], - "rankings": [ - { - "user": participation.username, - "points": participation.score, - "cumtime": participation.cumtime, - "is_disqualified": participation.is_disqualified, - "solutions": contest.format.get_problem_breakdown( - participation, problems - ), - } - for participation in participations - ], - } - ) + can_see_problems = (in_contest or contest.ended or contest.is_editable_by(request.user)) + + return JsonResponse({ + 'time_limit': contest.time_limit and contest.time_limit.total_seconds(), + 'start_time': contest.start_time.isoformat(), + 'end_time': contest.end_time.isoformat(), + 'tags': list(contest.tags.values_list('name', flat=True)), + 'is_rated': contest.is_rated, + 'rate_all': contest.is_rated and contest.rate_all, + 'has_rating': contest.ratings.exists(), + 'rating_floor': contest.rating_floor, + 'rating_ceiling': contest.rating_ceiling, + 'format': { + 'name': contest.format_name, + 'config': contest.format_config, + }, + 'problems': [ + { + 'points': int(problem.points), + 'partial': problem.partial, + 'name': problem.problem.name, + 'code': problem.problem.code, + } for problem in problems] if can_see_problems else [], + 'rankings': [ + { + 'user': participation.username, + 'points': participation.score, + 'cumtime': participation.cumtime, + 'is_disqualified': participation.is_disqualified, + 'solutions': contest.format.get_problem_breakdown(participation, problems), + } for participation in participations], + }) def api_v1_problem_list(request): queryset = Problem.objects.filter(is_public=True, is_organization_private=False) - if settings.ENABLE_FTS and "search" in request.GET: - query = " ".join(request.GET.getlist("search")).strip() + if settings.ENABLE_FTS and 'search' in request.GET: + query = ' '.join(request.GET.getlist('search')).strip() if query: queryset = queryset.search(query) - queryset = queryset.values_list( - "code", "points", "partial", "name", "group__full_name" - ) + queryset = queryset.values_list('code', 'points', 'partial', 'name', 'group__full_name') - return JsonResponse( - { - code: { - "points": points, - "partial": partial, - "name": name, - "group": group, - } - for code, points, partial, name, group in queryset - } - ) + return JsonResponse({code: { + 'points': points, + 'partial': partial, + 'name': name, + 'group': group, + } for code, points, partial, name, group in queryset}) def api_v1_problem_info(request, problem): @@ -134,83 +99,60 @@ def api_v1_problem_info(request, problem): if not p.is_accessible_by(request.user): raise Http404() - return JsonResponse( - { - "name": p.name, - "authors": list(p.authors.values_list("user__username", flat=True)), - "types": list(p.types.values_list("full_name", flat=True)), - "group": p.group.full_name, - "time_limit": p.time_limit, - "memory_limit": p.memory_limit, - "points": p.points, - "partial": p.partial, - "languages": list(p.allowed_languages.values_list("key", flat=True)), - } - ) + return JsonResponse({ + 'name': p.name, + 'authors': list(p.authors.values_list('user__username', flat=True)), + 'types': list(p.types.values_list('full_name', flat=True)), + 'group': p.group.full_name, + 'time_limit': p.time_limit, + 'memory_limit': p.memory_limit, + 'points': p.points, + 'partial': p.partial, + 'languages': list(p.allowed_languages.values_list('key', flat=True)), + }) def api_v1_user_list(request): - queryset = Profile.objects.filter(is_unlisted=False).values_list( - "user__username", "points", "performance_points", "display_rank" - ) - return JsonResponse( - { - username: { - "points": points, - "performance_points": performance_points, - "rank": rank, - } - for username, points, performance_points, rank in queryset - } - ) + queryset = Profile.objects.filter(is_unlisted=False).values_list('user__username', 'points', 'performance_points', + 'display_rank') + return JsonResponse({username: { + 'points': points, + 'performance_points': performance_points, + 'rank': rank, + } for username, points, performance_points, rank in queryset}) def api_v1_user_info(request, user): profile = get_object_or_404(Profile, user__username=user) - submissions = list( - Submission.objects.filter( - case_points=F("case_total"), - user=profile, - problem__is_public=True, - problem__is_organization_private=False, - ) - .values("problem") - .distinct() - .values_list("problem__code", flat=True) - ) + submissions = list(Submission.objects.filter(case_points=F('case_total'), user=profile, problem__is_public=True, + problem__is_organization_private=False) + .values('problem').distinct().values_list('problem__code', flat=True)) resp = { - "points": profile.points, - "performance_points": profile.performance_points, - "rank": profile.display_rank, - "solved_problems": submissions, - "organizations": list(profile.organizations.values_list("id", flat=True)), + 'points': profile.points, + 'performance_points': profile.performance_points, + 'rank': profile.display_rank, + 'solved_problems': submissions, + 'organizations': list(profile.organizations.values_list('id', flat=True)), } last_rating = profile.ratings.last() contest_history = {} - participations = ContestParticipation.objects.filter( - user=profile, - virtual=0, - contest__is_visible=True, - contest__is_private=False, - contest__is_organization_private=False, - ) - for contest_key, rating, mean, performance in participations.values_list( - "contest__key", - "rating__rating", - "rating__mean", - "rating__performance", - ): - contest_history[contest_key] = { - "rating": rating, - "raw_rating": mean, - "performance": performance, - } + if not profile.is_unlisted: + participations = ContestParticipation.objects.filter(user=profile, virtual=0, contest__is_visible=True, + contest__is_private=False, + contest__is_organization_private=False) + for contest_key, rating, volatility in participations.values_list('contest__key', 'rating__rating', + 'rating__volatility'): + contest_history[contest_key] = { + 'rating': rating, + 'volatility': volatility, + } - resp["contests"] = { - "current_rating": last_rating.rating if last_rating else None, - "history": contest_history, + resp['contests'] = { + 'current_rating': last_rating.rating if last_rating else None, + 'volatility': last_rating.volatility if last_rating else None, + 'history': contest_history, } return JsonResponse(resp) @@ -218,30 +160,14 @@ def api_v1_user_info(request, user): def api_v1_user_submissions(request, user): profile = get_object_or_404(Profile, user__username=user) - subs = Submission.objects.filter( - user=profile, problem__is_public=True, problem__is_organization_private=False - ) + subs = Submission.objects.filter(user=profile, problem__is_public=True, problem__is_organization_private=False) - return JsonResponse( - { - sub["id"]: { - "problem": sub["problem__code"], - "time": sub["time"], - "memory": sub["memory"], - "points": sub["points"], - "language": sub["language__key"], - "status": sub["status"], - "result": sub["result"], - } - for sub in subs.values( - "id", - "problem__code", - "time", - "memory", - "points", - "language__key", - "status", - "result", - ) - } - ) + return JsonResponse({sub['id']: { + 'problem': sub['problem__code'], + 'time': sub['time'], + 'memory': sub['memory'], + 'points': sub['points'], + 'language': sub['language__key'], + 'status': sub['status'], + 'result': sub['result'], + } for sub in subs.values('id', 'problem__code', 'time', 'memory', 'points', 'language__key', 'status', 'result')}) diff --git a/judge/views/api/api_v2.py b/judge/views/api/api_v2.py index a750d98..7850d96 100644 --- a/judge/views/api/api_v2.py +++ b/judge/views/api/api_v2.py @@ -9,7 +9,7 @@ from judge.views.contests import contest_ranking_list def error(message): - return JsonResponse({"error": message}, status=422) + return JsonResponse({'error': message}, status=422) def api_v2_user_info(request): @@ -44,9 +44,9 @@ def api_v2_user_info(request): // ... ] } - """ + """ try: - username = request.GET["username"] + username = request.GET['username'] except KeyError: return error("no username passed") if not username: @@ -56,90 +56,67 @@ def api_v2_user_info(request): except Profile.DoesNotExist: return error("no such user") - last_rating = list(profile.ratings.order_by("-contest__end_time")) + last_rating = list(profile.ratings.order_by('-contest__end_time')) resp = { "rank": profile.display_rank, - "organizations": list(profile.organizations.values_list("key", flat=True)), + "organizations": list(profile.organizations.values_list('key', flat=True)), } contest_history = [] - for participation in ContestParticipation.objects.filter( - user=profile, virtual=0, contest__is_visible=True - ).order_by("-contest__end_time"): + for participation in (ContestParticipation.objects.filter(user=profile, virtual=0, contest__is_visible=True) + .order_by('-contest__end_time')): contest = participation.contest - problems = list( - contest.contest_problems.select_related("problem") - .defer("problem__description") - .order_by("order") - ) - rank, result = next( - filter( - lambda data: data[1].user == profile.user, - ranker( - contest_ranking_list(contest, problems), - key=attrgetter("points", "cumtime"), - ), - ) - ) + problems = list(contest.contest_problems.select_related('problem').defer('problem__description') + .order_by('order')) + rank, result = next(filter(lambda data: data[1].user == profile.user, + ranker(contest_ranking_list(contest, problems), + key=attrgetter('points', 'cumtime')))) - contest_history.append( - { - "contest": { - "code": contest.key, - "name": contest.name, - "tags": list(contest.tags.values_list("name", flat=True)), - "time_limit": contest.time_limit - and contest.time_limit.total_seconds(), - "start_time": contest.start_time.isoformat(), - "end_time": contest.end_time.isoformat(), - }, - "rank": rank, - "rating": result.participation_rating, - } - ) + contest_history.append({ + 'contest': { + 'code': contest.key, + 'name': contest.name, + 'tags': list(contest.tags.values_list('name', flat=True)), + 'time_limit': contest.time_limit and contest.time_limit.total_seconds(), + 'start_time': contest.start_time.isoformat(), + 'end_time': contest.end_time.isoformat(), + }, + 'rank': rank, + 'rating': result.participation_rating, + }) - resp["contests"] = { + resp['contests'] = { "current_rating": last_rating[0].rating if last_rating else None, - "history": contest_history, + "volatility": last_rating[0].volatility if last_rating else None, + 'history': contest_history, } solved_problems = [] attempted_problems = [] - problem_data = ( - Submission.objects.filter( - points__gt=0, - user=profile, - problem__is_public=True, - problem__is_organization_private=False, - ) - .annotate(max_pts=Max("points")) - .values_list("max_pts", "problem__points", "problem__code") - .distinct() - ) + problem_data = (Submission.objects.filter(points__gt=0, user=profile, problem__is_public=True, + problem__is_organization_private=False) + .annotate(max_pts=Max('points')) + .values_list('max_pts', 'problem__points', 'problem__code') + .distinct()) for awarded_pts, max_pts, problem in problem_data: if awarded_pts == max_pts: solved_problems.append(problem) else: - attempted_problems.append( - { - "awarded": awarded_pts, - "max": max_pts, - "problem": problem, - } - ) + attempted_problems.append({ + 'awarded': awarded_pts, + 'max': max_pts, + 'problem': problem, + }) - resp["problems"] = { - "points": profile.points, - "solved": solved_problems, - "attempted": attempted_problems, - "authored": list( - Problem.objects.filter( - is_public=True, is_organization_private=False, authors=profile - ).values_list("code", flat=True) - ), + resp['problems'] = { + 'points': profile.points, + 'solved': solved_problems, + 'attempted': attempted_problems, + 'authored': list(Problem.objects.filter(is_public=True, is_organization_private=False, authors=profile) + .values_list('code', flat=True)), } return JsonResponse(resp) diff --git a/judge/views/blog.py b/judge/views/blog.py index 93b3c35..66832c8 100644 --- a/judge/views/blog.py +++ b/judge/views/blog.py @@ -1,3 +1,4 @@ +from django.conf import settings from django.db.models import Count, Max, Q from django.http import Http404 from django.urls import reverse @@ -6,215 +7,120 @@ from django.utils.functional import lazy from django.utils.translation import ugettext as _ from django.views.generic import ListView -from judge.views.comment import CommentedDetailView -from judge.views.pagevote import PageVoteDetailView -from judge.views.bookmark import BookMarkDetailView -from judge.models import ( - BlogPost, - Comment, - Contest, - Language, - Problem, - ContestProblemClarification, - Profile, - Submission, - Ticket, -) -from judge.models.profile import Organization, OrganizationProfile +from judge.comments import CommentedDetailView +from judge.models import BlogPost, Comment, Contest, Language, Problem, ProblemClarification, Profile, Submission, \ + Ticket from judge.utils.cachedict import CacheDict from judge.utils.diggpaginator import DiggPaginator +from judge.utils.problems import user_completed_ids from judge.utils.tickets import filter_visible_tickets from judge.utils.views import TitleMixin -from judge.utils.users import get_rating_rank, get_points_rank, get_awards -from judge.views.feed import FeedView -# General view for all content list on home feed -class HomeFeedView(FeedView): - template_name = "blog/list.html" +class PostList(ListView): + model = BlogPost + paginate_by = 10 + context_object_name = 'posts' + template_name = 'blog/list.html' title = None - def get_context_data(self, **kwargs): - context = super(HomeFeedView, self).get_context_data(**kwargs) - context["has_clarifications"] = False - if self.request.user.is_authenticated: - participation = self.request.profile.current_contest - if participation: - clarifications = ContestProblemClarification.objects.filter( - problem__in=participation.contest.contest_problems.all() - ) - context["has_clarifications"] = clarifications.count() > 0 - context["clarifications"] = clarifications.order_by("-date") - if participation.contest.is_editable_by(self.request.user): - context["can_edit_contest"] = True - - now = timezone.now() - visible_contests = ( - Contest.get_visible_contests(self.request.user, show_own_contests_only=True) - .filter(is_visible=True, official__isnull=True) - .order_by("start_time") - ) - if self.request.organization: - visible_contests = visible_contests.filter( - is_organization_private=True, organizations=self.request.organization - ) - context["current_contests"] = visible_contests.filter( - start_time__lte=now, end_time__gt=now - ) - context["future_contests"] = visible_contests.filter(start_time__gt=now) - context[ - "recent_organizations" - ] = OrganizationProfile.get_most_recent_organizations(self.request.profile) - - profile_queryset = Profile.objects - if self.request.organization: - profile_queryset = self.request.organization.members - context["top_rated"] = ( - profile_queryset.filter(is_unlisted=False) - .order_by("-rating") - .only("id", "rating")[:10] - ) - context["top_scorer"] = ( - profile_queryset.filter(is_unlisted=False) - .order_by("-performance_points") - .only("id", "performance_points")[:10] - ) - Profile.prefetch_profile_cache([p.id for p in context["top_rated"]]) - Profile.prefetch_profile_cache([p.id for p in context["top_scorer"]]) - - if self.request.user.is_authenticated: - context["rating_rank"] = get_rating_rank(self.request.profile) - context["points_rank"] = get_points_rank(self.request.profile) - - medals_list = get_awards(self.request.profile) - context["awards"] = { - "medals": medals_list, - "gold_count": 0, - "silver_count": 0, - "bronze_count": 0, - } - for medal in medals_list: - if medal["ranking"] == 1: - context["awards"]["gold_count"] += 1 - elif medal["ranking"] == 2: - context["awards"]["silver_count"] += 1 - elif medal["ranking"] == 3: - context["awards"]["bronze_count"] += 1 - - return context - - -class PostList(HomeFeedView): - model = BlogPost - paginate_by = 4 - context_object_name = "posts" - feed_content_template_name = "blog/content.html" - url_name = "blog_post_list" + def get_paginator(self, queryset, per_page, orphans=0, + allow_empty_first_page=True, **kwargs): + return DiggPaginator(queryset, per_page, body=6, padding=2, + orphans=orphans, allow_empty_first_page=allow_empty_first_page, **kwargs) def get_queryset(self): - queryset = ( - BlogPost.objects.filter(visible=True, publish_on__lte=timezone.now()) - .order_by("-sticky", "-publish_on") - .prefetch_related("organizations") - ) - filter = Q(is_organization_private=False) - if self.request.user.is_authenticated: - filter |= Q(organizations__in=self.request.profile.organizations.all()) - if self.request.organization: - filter &= Q(organizations=self.request.organization) - queryset = queryset.filter(filter) - return queryset + return (BlogPost.objects.filter(visible=True, publish_on__lte=timezone.now()).order_by('-sticky', '-publish_on') + .prefetch_related('authors__user')) def get_context_data(self, **kwargs): context = super(PostList, self).get_context_data(**kwargs) - context["title"] = ( - self.title or _("Page %d of Posts") % context["page_obj"].number - ) - context["page_type"] = "blog" - return context + context['title'] = self.title or _('Page %d of Posts') % context['page_obj'].number + context['first_page_href'] = reverse('home') + context['page_prefix'] = reverse('blog_post_list') + context['comments'] = Comment.most_recent(self.request.user, 10) + context['new_problems'] = Problem.objects.filter(is_public=True, is_organization_private=False) \ + .order_by('-date', '-id')[:settings.DMOJ_BLOG_NEW_PROBLEM_COUNT] + context['page_titles'] = CacheDict(lambda page: Comment.get_page_title(page)) + context['has_clarifications'] = False + if self.request.user.is_authenticated: + participation = self.request.profile.current_contest + if participation: + clarifications = ProblemClarification.objects.filter(problem__in=participation.contest.problems.all()) + context['has_clarifications'] = clarifications.count() > 0 + context['clarifications'] = clarifications.order_by('-date') -class TicketFeed(HomeFeedView): - model = Ticket - context_object_name = "tickets" - paginate_by = 8 - feed_content_template_name = "ticket/feed.html" + context['user_count'] = lazy(Profile.objects.count, int, int) + context['problem_count'] = lazy(Problem.objects.filter(is_public=True).count, int, int) + context['submission_count'] = lazy(Submission.objects.count, int, int) + context['language_count'] = lazy(Language.objects.count, int, int) - def get_queryset(self, is_own=True): - profile = self.request.profile - if is_own: - if self.request.user.is_authenticated: - return ( - Ticket.objects.filter( - Q(user=profile) | Q(assignees__in=[profile]), is_open=True - ) - .order_by("-id") - .prefetch_related("linked_item") - ) - else: - return [] + context['post_comment_counts'] = { + int(page[2:]): count for page, count in + Comment.objects + .filter(page__in=['b:%d' % post.id for post in context['posts']], hidden=False) + .values_list('page').annotate(count=Count('page')).order_by() + } + + now = timezone.now() + + # Dashboard stuff + if self.request.user.is_authenticated: + user = self.request.profile + context['recently_attempted_problems'] = (Submission.objects.filter(user=user) + .exclude(problem__in=user_completed_ids(user)) + .values_list('problem__code', 'problem__name', 'problem__points') + .annotate(points=Max('points'), latest=Max('date')) + .order_by('-latest') + [:settings.DMOJ_BLOG_RECENTLY_ATTEMPTED_PROBLEMS_COUNT]) + + visible_contests = Contest.objects.filter(is_visible=True).order_by('start_time') + q = Q(is_private=False, is_organization_private=False) + if self.request.user.is_authenticated: + q |= Q(is_organization_private=True, organizations__in=user.organizations.all()) + q |= Q(is_private=True, private_contestants=user) + visible_contests = visible_contests.filter(q) + context['current_contests'] = visible_contests.filter(start_time__lte=now, end_time__gt=now) + context['future_contests'] = visible_contests.filter(start_time__gt=now) + + if self.request.user.is_authenticated: + profile = self.request.profile + context['own_open_tickets'] = (Ticket.objects.filter(user=profile, is_open=True).order_by('-id') + .prefetch_related('linked_item').select_related('user__user')) else: - # Superusers better be staffs, not the spell-casting kind either. - if self.request.user.is_staff: - tickets = ( - Ticket.objects.order_by("-id") - .filter(is_open=True) - .prefetch_related("linked_item") - ) - return filter_visible_tickets(tickets, self.request.user, profile) - else: - return [] + profile = None + context['own_open_tickets'] = [] - def get_context_data(self, **kwargs): - context = super(TicketFeed, self).get_context_data(**kwargs) - context["page_type"] = "ticket" - context["title"] = _("Ticket feed") + # Superusers better be staffs, not the spell-casting kind either. + if self.request.user.is_staff: + tickets = (Ticket.objects.order_by('-id').filter(is_open=True).prefetch_related('linked_item') + .select_related('user__user')) + context['open_tickets'] = filter_visible_tickets(tickets, self.request.user, profile)[:10] + else: + context['open_tickets'] = [] return context -class CommentFeed(HomeFeedView): - model = Comment - context_object_name = "comments" - paginate_by = 15 - feed_content_template_name = "comments/feed.html" - - def get_queryset(self): - return Comment.most_recent( - self.request.user, 100, organization=self.request.organization - ) - - def get_context_data(self, **kwargs): - context = super(CommentFeed, self).get_context_data(**kwargs) - context["title"] = _("Comment feed") - context["page_type"] = "comment" - return context - - -class PostView(TitleMixin, CommentedDetailView, PageVoteDetailView, BookMarkDetailView): +class PostView(TitleMixin, CommentedDetailView): model = BlogPost - pk_url_kwarg = "id" - context_object_name = "post" - template_name = "blog/blog.html" + pk_url_kwarg = 'id' + context_object_name = 'post' + template_name = 'blog/content.html' def get_title(self): return self.object.title + def get_comment_page(self): + return 'b:%s' % self.object.id + def get_context_data(self, **kwargs): context = super(PostView, self).get_context_data(**kwargs) - context["og_image"] = self.object.og_image - context["editable_orgs"] = [] - - orgs = list(self.object.organizations.all()) - - if self.request.profile: - for org in orgs: - if self.request.profile.can_edit_organization(org): - context["editable_orgs"].append(org) - + context['og_image'] = self.object.og_image return context def get_object(self, queryset=None): post = super(PostView, self).get_object(queryset) - if not post.is_accessible_by(self.request.user): + if not post.can_see(self.request.user): raise Http404() return post diff --git a/judge/views/bookmark.py b/judge/views/bookmark.py deleted file mode 100644 index a05f715..0000000 --- a/judge/views/bookmark.py +++ /dev/null @@ -1,75 +0,0 @@ -from django.contrib.auth.decorators import login_required -from django.db import IntegrityError -from django.db.models import F -from django.http import ( - Http404, - HttpResponse, - HttpResponseBadRequest, - HttpResponseForbidden, -) -from django.utils.translation import gettext as _ -from django.views.generic.base import TemplateResponseMixin -from django.views.generic.detail import SingleObjectMixin - -from django.views.generic import View, ListView - -from judge.models.bookmark import BookMark, MakeBookMark, dirty_bookmark - -__all__ = [ - "dobookmark_page", - "undobookmark_page", - "BookMarkDetailView", -] - - -@login_required -def bookmark_page(request, delta): - if request.method != "POST": - return HttpResponseForbidden() - - if "id" not in request.POST: - return HttpResponseBadRequest() - - try: - bookmark_id = int(request.POST["id"]) - bookmark = BookMark.objects.get(id=bookmark_id) - except ValueError: - return HttpResponseBadRequest() - except BookMark.DoesNotExist: - raise Http404() - - if delta == 0: - bookmarklist = MakeBookMark.objects.filter( - bookmark=bookmark, user=request.profile - ) - if not bookmarklist.exists(): - newbookmark = MakeBookMark( - bookmark=bookmark, - user=request.profile, - ) - newbookmark.save() - else: - bookmarklist = MakeBookMark.objects.filter( - bookmark=bookmark, user=request.profile - ) - if bookmarklist.exists(): - bookmarklist.delete() - - dirty_bookmark(bookmark, request.profile) - - return HttpResponse("success", content_type="text/plain") - - -def dobookmark_page(request): - return bookmark_page(request, 0) - - -def undobookmark_page(request): - return bookmark_page(request, 1) - - -class BookMarkDetailView(TemplateResponseMixin, SingleObjectMixin, View): - def get_context_data(self, **kwargs): - context = super(BookMarkDetailView, self).get_context_data(**kwargs) - context["bookmark"] = self.object.get_or_create_bookmark() - return context diff --git a/judge/views/comment.py b/judge/views/comment.py index 8ac62fa..f216bba 100644 --- a/judge/views/comment.py +++ b/judge/views/comment.py @@ -1,95 +1,43 @@ -import json - -from django import forms -from django.conf import settings -from django.contrib.auth.context_processors import PermWrapper from django.contrib.auth.decorators import login_required from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin -from django.contrib.contenttypes.models import ContentType -from django.core.exceptions import PermissionDenied, ValidationError -from django.db import IntegrityError -from django.db.models import Count, F, FilteredRelation, Q -from django.db.models.expressions import Value -from django.db.models.functions import Coalesce -from django.forms import ModelForm -from django.http import ( - Http404, - HttpResponse, - HttpResponseBadRequest, - HttpResponseForbidden, - HttpResponseNotFound, - HttpResponseRedirect, -) -from django.shortcuts import get_object_or_404, render -from django.urls import reverse_lazy -from django.utils.decorators import method_decorator +from django.core.exceptions import PermissionDenied +from django.db import IntegrityError, transaction +from django.db.models import F +from django.forms.models import ModelForm +from django.http import Http404, HttpResponse, HttpResponseBadRequest, HttpResponseForbidden +from django.shortcuts import get_object_or_404 from django.utils.translation import gettext as _ -from django.utils.datastructures import MultiValueDictKeyError from django.views.decorators.http import require_POST -from django.views.generic import DetailView, UpdateView, View -from django.views.generic.base import TemplateResponseMixin -from django.views.generic.detail import SingleObjectMixin -from django_ratelimit.decorators import ratelimit -from django.contrib.contenttypes.models import ContentType - +from django.views.generic import DetailView, UpdateView from reversion import revisions -from reversion.models import Revision, Version +from reversion.models import Version -from judge.jinja2.reference import get_user_from_text -from judge.models import BlogPost, Comment, CommentVote, Notification -from judge.models.notification import make_notification -from judge.models.comment import get_visible_comment_count +from judge.dblock import LockModel +from judge.models import Comment, CommentVote from judge.utils.views import TitleMixin -from judge.widgets import HeavyPreviewPageDownWidget +from judge.widgets import MathJaxPagedownWidget -__all__ = [ - "upvote_comment", - "downvote_comment", - "CommentEditAjax", - "CommentContent", - "CommentEdit", -] - -DEFAULT_OFFSET = 10 +__all__ = ['upvote_comment', 'downvote_comment', 'CommentEditAjax', 'CommentContent', + 'CommentEdit'] -def _get_html_link_notification(comment): - return f'{comment.page_title}' - - -def add_mention_notifications(comment): - users_mentioned = get_user_from_text(comment.body).exclude(id=comment.author.id) - link = _get_html_link_notification(comment) - make_notification(users_mentioned, "Mention", link, comment.author) - - -@ratelimit(key="user", rate=settings.RL_VOTE) @login_required def vote_comment(request, delta): if abs(delta) != 1: - return HttpResponseBadRequest( - _("Messing around, are we?"), content_type="text/plain" - ) + return HttpResponseBadRequest(_('Messing around, are we?'), content_type='text/plain') - if request.method != "POST": + if request.method != 'POST': return HttpResponseForbidden() - if "id" not in request.POST: + if 'id' not in request.POST: return HttpResponseBadRequest() - if ( - not request.user.is_staff - and not request.profile.submission_set.filter( - points=F("problem__points") - ).exists() - ): - return HttpResponseBadRequest( - _("You must solve at least one problem before you can vote."), - content_type="text/plain", - ) + if not request.user.is_staff and not request.profile.submission_set.filter(points=F('problem__points')).exists(): + return HttpResponseBadRequest(_('You must solve at least one problem before you can vote.'), + content_type='text/plain') try: - comment_id = int(request.POST["id"]) + comment_id = int(request.POST['id']) except ValueError: return HttpResponseBadRequest() else: @@ -101,22 +49,24 @@ def vote_comment(request, delta): vote.voter = request.profile vote.score = delta - try: - vote.save() - except IntegrityError: + while True: try: - vote = CommentVote.objects.get(comment_id=comment_id, voter=request.profile) - except CommentVote.DoesNotExist: - raise Http404() - if -vote.score != delta: - return HttpResponseBadRequest( - _("You already voted."), content_type="text/plain" - ) - vote.delete() - Comment.objects.filter(id=comment_id).update(score=F("score") - vote.score) - else: - Comment.objects.filter(id=comment_id).update(score=F("score") + delta) - return HttpResponse("success", content_type="text/plain") + vote.save() + except IntegrityError: + with LockModel(write=(CommentVote,)): + try: + vote = CommentVote.objects.get(comment_id=comment_id, voter=request.profile) + except CommentVote.DoesNotExist: + # We must continue racing in case this is exploited to manipulate votes. + continue + if -vote.score != delta: + return HttpResponseBadRequest(_('You already voted.'), content_type='text/plain') + vote.delete() + Comment.objects.filter(id=comment_id).update(score=F('score') - vote.score) + else: + Comment.objects.filter(id=comment_id).update(score=F('score') + delta) + break + return HttpResponse('success', content_type='text/plain') def upvote_comment(request): @@ -127,119 +77,28 @@ def downvote_comment(request): return vote_comment(request, -1) -def get_comments(request, limit=10): - try: - comment_id = int(request.GET["id"]) - parent_none = int(request.GET["parent_none"]) - except (ValueError, MultiValueDictKeyError): - return HttpResponseBadRequest() - else: - if comment_id and not Comment.objects.filter(id=comment_id).exists(): - raise Http404() - - offset = 0 - if "offset" in request.GET: - try: - offset = int(request.GET["offset"]) - except ValueError: - return HttpResponseBadRequest() - - target_comment = -1 - if "target_comment" in request.GET: - target_comment = int(request.GET["target_comment"]) - - comment_root_id = 0 - - if comment_id: - comment_obj = Comment.objects.get(pk=comment_id) - comment_root_id = comment_obj.id - else: - comment_obj = None - - queryset = comment_obj.linked_object.comments - if parent_none: - queryset = queryset.filter(parent=None, hidden=False) - queryset = queryset.exclude(pk=target_comment) - else: - queryset = queryset.filter(parent=comment_obj, hidden=False) - comment_count = len(queryset) - queryset = ( - queryset.select_related("author__user") - .defer("author__about") - .annotate( - count_replies=Count("replies", distinct=True), - )[offset : offset + limit] - ) - profile = None - if request.user.is_authenticated: - profile = request.profile - queryset = queryset.annotate( - my_vote=FilteredRelation("votes", condition=Q(votes__voter_id=profile.id)), - ).annotate(vote_score=Coalesce(F("my_vote__score"), Value(0))) - - new_offset = offset + min(len(queryset), limit) - - return render( - request, - "comments/content-list.html", - { - "profile": profile, - "comment_root_id": comment_root_id, - "comment_list": queryset, - "vote_hide_threshold": settings.DMOJ_COMMENT_VOTE_HIDE_THRESHOLD, - "perms": PermWrapper(request.user), - "offset": new_offset, - "limit": limit, - "comment_count": comment_count, - "comment_parent_none": parent_none, - "target_comment": target_comment, - "comment_more": comment_count - new_offset, - }, - ) - - -def get_show_more(request): - return get_comments(request) - - -def get_replies(request): - return get_comments(request) - - class CommentMixin(object): model = Comment - pk_url_kwarg = "id" - context_object_name = "comment" + pk_url_kwarg = 'id' + context_object_name = 'comment' class CommentRevisionAjax(CommentMixin, DetailView): - template_name = "comments/revision-ajax.html" + template_name = 'comments/revision-ajax.html' def get_context_data(self, **kwargs): context = super(CommentRevisionAjax, self).get_context_data(**kwargs) - revisions = Version.objects.get_for_object(self.object).order_by("-revision") - - if len(revisions) == 0: - raise Http404 - + revisions = Version.objects.get_for_object(self.object).order_by('-revision') try: - wanted = min( - max(int(self.request.GET.get("revision", 0)), 0), len(revisions) - 1 - ) - revision = revisions[wanted] - except (ValueError, IndexError): + wanted = min(max(int(self.request.GET.get('revision', 0)), 0), len(revisions) - 1) + except ValueError: raise Http404 - - data = json.loads(revision.serialized_data) - try: - context["body"] = data[0]["fields"]["body"] - except Exception: - context["body"] = "" + context['revision'] = revisions[wanted] return context def get_object(self, queryset=None): comment = super(CommentRevisionAjax, self).get_object(queryset) - if comment.hidden and not self.request.user.has_perm("judge.change_comment"): + if comment.hidden and not self.request.user.has_perm('judge.change_comment'): raise Http404() return comment @@ -247,29 +106,18 @@ class CommentRevisionAjax(CommentMixin, DetailView): class CommentEditForm(ModelForm): class Meta: model = Comment - fields = ["body"] - widgets = { - "body": HeavyPreviewPageDownWidget( - id="id-edit-comment-body", - preview=reverse_lazy("comment_preview"), - preview_timeout=1000, - hide_preview_button=True, - ), - } + fields = ['body'] + if MathJaxPagedownWidget is not None: + widgets = {'body': MathJaxPagedownWidget(attrs={'id': 'id-edit-comment-body'})} class CommentEditAjax(LoginRequiredMixin, CommentMixin, UpdateView): - template_name = "comments/edit-ajax.html" + template_name = 'comments/edit-ajax.html' form_class = CommentEditForm def form_valid(self, form): - # update notifications - comment = form.instance - add_mention_notifications(comment) - comment.revision_count = comment.versions.count() + 1 - comment.save(update_fields=["revision_count"]) - with revisions.create_revision(): - revisions.set_comment(_("Edited from site")) + with transaction.atomic(), revisions.create_revision(): + revisions.set_comment(_('Edited from site')) revisions.set_user(self.request.user) return super(CommentEditAjax, self).form_valid(form) @@ -278,7 +126,7 @@ class CommentEditAjax(LoginRequiredMixin, CommentMixin, UpdateView): def get_object(self, queryset=None): comment = super(CommentEditAjax, self).get_object(queryset) - if self.request.user.has_perm("judge.change_comment"): + if self.request.user.has_perm('judge.change_comment'): return comment profile = self.request.profile if profile != comment.author or profile.mute or comment.hidden: @@ -287,228 +135,36 @@ class CommentEditAjax(LoginRequiredMixin, CommentMixin, UpdateView): class CommentEdit(TitleMixin, CommentEditAjax): - template_name = "comments/edit.html" + template_name = 'comments/edit.html' def get_title(self): - return _("Editing comment") + return _('Editing comment') class CommentContent(CommentMixin, DetailView): - template_name = "comments/content.html" + template_name = 'comments/content.html' class CommentVotesAjax(PermissionRequiredMixin, CommentMixin, DetailView): - template_name = "comments/votes.html" - permission_required = "judge.change_commentvote" + template_name = 'comments/votes.html' + permission_required = 'judge.change_commentvote' def get_context_data(self, **kwargs): context = super(CommentVotesAjax, self).get_context_data(**kwargs) - context["votes"] = self.object.votes.select_related("voter__user").only( - "id", "voter__display_rank", "voter__user__username", "score" - ) + context['votes'] = (self.object.votes.select_related('voter__user') + .only('id', 'voter__display_rank', 'voter__user__username', 'score')) return context @require_POST def comment_hide(request): - if not request.user.has_perm("judge.change_comment"): + if not request.user.has_perm('judge.change_comment'): raise PermissionDenied() try: - comment_id = int(request.POST["id"]) + comment_id = int(request.POST['id']) except ValueError: return HttpResponseBadRequest() comment = get_object_or_404(Comment, id=comment_id) comment.get_descendants(include_self=True).update(hidden=True) - get_visible_comment_count.dirty(comment.content_type, comment.object_id) - return HttpResponse("ok") - - -class CommentForm(ModelForm): - class Meta: - model = Comment - fields = ["body", "parent"] - widgets = { - "parent": forms.HiddenInput(), - } - - if HeavyPreviewPageDownWidget is not None: - widgets["body"] = HeavyPreviewPageDownWidget( - preview=reverse_lazy("comment_preview"), - preview_timeout=1000, - hide_preview_button=True, - ) - - def __init__(self, request, *args, **kwargs): - self.request = request - super(CommentForm, self).__init__(*args, **kwargs) - self.fields["body"].widget.attrs.update({"placeholder": _("Comment body")}) - - def clean(self): - if self.request is not None and self.request.user.is_authenticated: - profile = self.request.profile - if profile.mute: - raise ValidationError(_("Your part is silent, little toad.")) - elif ( - not self.request.user.is_staff - and not profile.submission_set.filter( - points=F("problem__points") - ).exists() - ): - raise ValidationError( - _( - "You need to have solved at least one problem " - "before your voice can be heard." - ) - ) - return super(CommentForm, self).clean() - - -class CommentedDetailView(TemplateResponseMixin, SingleObjectMixin, View): - comment_page = None - - def is_comment_locked(self): - if self.request.user.has_perm("judge.override_comment_lock"): - return False - return ( - self.request.in_contest - and self.request.participation.contest.use_clarifications - ) - - @method_decorator(ratelimit(key="user", rate=settings.RL_COMMENT)) - @method_decorator(login_required) - def post(self, request, *args, **kwargs): - self.object = self.get_object() - if self.is_comment_locked(): - return HttpResponseForbidden() - - parent = request.POST.get("parent") - if parent: - try: - parent = int(parent) - except ValueError: - return HttpResponseNotFound() - else: - if not self.object.comments.filter(hidden=False, id=parent).exists(): - return HttpResponseNotFound() - - form = CommentForm(request, request.POST) - if form.is_valid(): - comment = form.save(commit=False) - comment.author = request.profile - comment.linked_object = self.object - - with revisions.create_revision(): - revisions.set_user(request.user) - revisions.set_comment(_("Posted comment")) - comment.save() - - # add notification for reply - comment_notif_link = _get_html_link_notification(comment) - if comment.parent and comment.parent.author != comment.author: - make_notification( - [comment.parent.author], "Reply", comment_notif_link, comment.author - ) - - # add notification for page authors - page_authors = comment.linked_object.authors.all() - make_notification( - page_authors, "Comment", comment_notif_link, comment.author - ) - - add_mention_notifications(comment) - get_visible_comment_count.dirty(comment.content_type, comment.object_id) - - return HttpResponseRedirect(comment.get_absolute_url()) - - context = self.get_context_data(object=self.object, comment_form=form) - return self.render_to_response(context) - - def get(self, request, *args, **kwargs): - target_comment = None - self.object = self.get_object() - if "comment-id" in request.GET: - try: - comment_id = int(request.GET["comment-id"]) - comment_obj = Comment.objects.get(id=comment_id) - except (Comment.DoesNotExist, ValueError): - raise Http404 - if comment_obj.linked_object != self.object: - raise Http404 - target_comment = comment_obj.get_root() - return self.render_to_response( - self.get_context_data( - object=self.object, - target_comment=target_comment, - comment_form=CommentForm(request, initial={"parent": None}), - ) - ) - - def _get_queryset(self, target_comment): - if target_comment: - queryset = target_comment.get_descendants(include_self=True) - queryset = queryset.filter(hidden=False) - else: - queryset = self.object.comments - queryset = queryset.filter(parent=None, hidden=False) - queryset = queryset.filter(hidden=False).annotate( - count_replies=Count("replies", distinct=True), - )[:DEFAULT_OFFSET] - - if self.request.user.is_authenticated: - profile = self.request.profile - queryset = queryset.annotate( - my_vote=FilteredRelation( - "votes", condition=Q(votes__voter_id=profile.id) - ), - ).annotate(vote_score=Coalesce(F("my_vote__score"), Value(0))) - - return queryset - - def get_context_data(self, target_comment=None, **kwargs): - context = super(CommentedDetailView, self).get_context_data(**kwargs) - queryset = self._get_queryset(target_comment) - comment_count = self.object.comments.filter(parent=None, hidden=False).count() - - content_type = ContentType.objects.get_for_model(self.object) - all_comment_count = get_visible_comment_count(content_type, self.object.pk) - - if target_comment != None: - context["target_comment"] = target_comment.id - else: - context["target_comment"] = -1 - - if self.request.user.is_authenticated: - context["is_new_user"] = ( - not self.request.user.is_staff - and not self.request.profile.submission_set.filter( - points=F("problem__points") - ).exists() - ) - - context["comment_lock"] = self.is_comment_locked() - context["comment_list"] = list(queryset) - context["has_comments"] = len(context["comment_list"]) > 0 - - context["vote_hide_threshold"] = settings.DMOJ_COMMENT_VOTE_HIDE_THRESHOLD - - if queryset.exists(): - context["comment_root_id"] = context["comment_list"][0].id - else: - context["comment_root_id"] = 0 - - context["comment_parent_none"] = 1 - - if target_comment != None: - context["offset"] = 0 - context["comment_more"] = comment_count - 1 - else: - context["offset"] = DEFAULT_OFFSET - context["comment_more"] = comment_count - DEFAULT_OFFSET - - context["limit"] = DEFAULT_OFFSET - context["comment_count"] = comment_count - context["profile"] = self.request.profile - context["all_comment_count"] = all_comment_count - - return context + return HttpResponse('ok') diff --git a/judge/views/contests.py b/judge/views/contests.py index 3dc27f2..d803375 100644 --- a/judge/views/contests.py +++ b/judge/views/contests.py @@ -1,6 +1,4 @@ -from copy import deepcopy import json -import math from calendar import Calendar, SUNDAY from collections import defaultdict, namedtuple from datetime import date, datetime, time, timedelta @@ -14,329 +12,110 @@ from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMix from django.core.cache import cache from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist from django.db import IntegrityError -from django.db.models import ( - Case, - Count, - F, - FloatField, - IntegerField, - Max, - Min, - Q, - Sum, - Value, - When, -) -from django.dispatch import receiver +from django.db.models import Case, Count, FloatField, IntegerField, Max, Min, Q, Sum, Value, When from django.db.models.expressions import CombinedExpression -from django.http import ( - Http404, - HttpResponse, - HttpResponseBadRequest, - HttpResponseRedirect, - JsonResponse, - HttpResponseNotAllowed, -) +from django.http import Http404, HttpResponse, HttpResponseBadRequest, HttpResponseRedirect from django.shortcuts import get_object_or_404, render from django.template.defaultfilters import date as date_filter -from django.urls import reverse, reverse_lazy +from django.urls import reverse from django.utils import timezone from django.utils.functional import cached_property -from django.utils.html import format_html, escape +from django.utils.html import format_html from django.utils.safestring import mark_safe from django.utils.timezone import make_aware from django.utils.translation import gettext as _, gettext_lazy from django.views.generic import ListView, TemplateView -from django.views.generic.detail import ( - BaseDetailView, - DetailView, - SingleObjectMixin, - View, -) +from django.views.generic.detail import BaseDetailView, DetailView, SingleObjectMixin, View from judge import event_poster as event -from judge.views.comment import CommentedDetailView +from judge.comments import CommentedDetailView from judge.forms import ContestCloneForm -from judge.models import ( - Contest, - ContestMoss, - ContestParticipation, - ContestProblem, - ContestTag, - Organization, - Problem, - Profile, - Submission, - ContestProblemClarification, - ContestsSummary, - OfficialContestCategory, - OfficialContestLocation, -) +from judge.models import Contest, ContestMoss, ContestParticipation, ContestProblem, ContestTag, \ + Problem, Profile, Submission from judge.tasks import run_moss from judge.utils.celery import redirect_to_task_status from judge.utils.opengraph import generate_opengraph from judge.utils.problems import _get_result_data from judge.utils.ranker import ranker -from judge.utils.stats import get_bar_chart, get_pie_chart, get_histogram -from judge.utils.views import ( - DiggPaginatorMixin, - QueryStringSortMixin, - SingleObjectFormView, - TitleMixin, - generic_message, -) -from judge.widgets import HeavyPreviewPageDownWidget -from judge.views.pagevote import PageVoteDetailView -from judge.views.bookmark import BookMarkDetailView +from judge.utils.stats import get_bar_chart, get_pie_chart +from judge.utils.views import DiggPaginatorMixin, SingleObjectFormView, TitleMixin, generic_message + +__all__ = ['ContestList', 'ContestDetail', 'ContestRanking', 'ContestJoin', 'ContestLeave', 'ContestCalendar', + 'ContestClone', 'ContestStats', 'ContestMossView', 'ContestMossDelete', 'contest_ranking_ajax', + 'ContestParticipationList', 'ContestParticipationDisqualify', 'get_contest_ranking_list', + 'base_contest_ranking_list'] -__all__ = [ - "ContestList", - "ContestDetail", - "ContestRanking", - "ContestJoin", - "ContestLeave", - "ContestCalendar", - "ContestClone", - "ContestStats", - "ContestMossView", - "ContestMossDelete", - "ContestParticipationList", - "ContestParticipationDisqualify", - "get_contest_ranking_list", - "base_contest_ranking_list", - "ContestClarificationView", - "update_contest_mode", - "OfficialContestList", -] - - -def _find_contest(request, key): +def _find_contest(request, key, private_check=True): try: contest = Contest.objects.get(key=key) - private_check = not contest.public_scoreboard if private_check and not contest.is_accessible_by(request.user): raise ObjectDoesNotExist() except ObjectDoesNotExist: - return ( - generic_message( - request, - _("No such contest"), - _('Could not find a contest with the key "%s".') % key, - status=404, - ), - False, - ) + return generic_message(request, _('No such contest'), + _('Could not find a contest with the key "%s".') % key, status=404), False return contest, True class ContestListMixin(object): - official = False - def get_queryset(self): - q = Contest.get_visible_contests(self.request.user) - if self.official: - q = q.filter(official__isnull=False).select_related( - "official", "official__category", "official__location" - ) - else: - q = q.filter(official__isnull=True) - return q + queryset = Contest.objects.all() + if not self.request.user.has_perm('judge.see_private_contest'): + q = Q(is_visible=True) + if self.request.user.is_authenticated: + q |= Q(organizers=self.request.profile) + queryset = queryset.filter(q) + if not self.request.user.has_perm('judge.edit_all_contest'): + q = Q(is_private=False, is_organization_private=False) + if self.request.user.is_authenticated: + q |= Q(is_organization_private=True, organizations__in=self.request.profile.organizations.all()) + q |= Q(is_private=True, private_contestants=self.request.profile) + queryset = queryset.filter(q) + return queryset.distinct() -class ContestList( - QueryStringSortMixin, DiggPaginatorMixin, TitleMixin, ContestListMixin, ListView -): +class ContestList(DiggPaginatorMixin, TitleMixin, ContestListMixin, ListView): model = Contest - paginate_by = 10 - template_name = "contest/list.html" - title = gettext_lazy("Contests") - all_sorts = frozenset(("name", "user_count", "start_time")) - default_desc = frozenset(("name", "user_count")) - context_object_name = "contests" - - def get_default_sort_order(self, request): - if request.GET.get("contest") and settings.ENABLE_FTS: - return "-relevance" - if self.current_tab == "future": - return "start_time" - return "-start_time" + paginate_by = 20 + template_name = 'contest/list.html' + title = gettext_lazy('Contests') + context_object_name = 'past_contests' @cached_property def _now(self): return timezone.now() - def GET_with_session(self, request, key): - if not request.GET.get(key): - return request.session.get(key, False) - return request.GET.get(key, None) == "1" - - def setup_contest_list(self, request): - self.contest_query = request.GET.get("contest", "") - - self.hide_organization_contests = 0 - if self.GET_with_session(request, "hide_organization_contests"): - self.hide_organization_contests = 1 - - self.org_query = [] - if request.GET.get("orgs") and request.profile: - try: - self.org_query = list(map(int, request.GET.getlist("orgs"))) - if not request.user.is_superuser: - self.org_query = [ - i - for i in self.org_query - if i - in set( - request.profile.organizations.values_list("id", flat=True) - ) - ] - except ValueError: - pass - - def get(self, request, *args, **kwargs): - default_tab = "active" - if not self.request.user.is_authenticated: - default_tab = "current" - self.current_tab = self.request.GET.get("tab", default_tab) - - self.setup_contest_list(request) - - return super(ContestList, self).get(request, *args, **kwargs) - - def post(self, request, *args, **kwargs): - to_update = ("hide_organization_contests",) - for key in to_update: - if key in request.GET: - val = request.GET.get(key) == "1" - request.session[key] = val - else: - request.session[key] = False - return HttpResponseRedirect(request.get_full_path()) - - def extra_queryset_filters(self, queryset): - return queryset - def _get_queryset(self): - queryset = ( - super(ContestList, self) - .get_queryset() - .prefetch_related("tags", "organizations") - ) - - if self.contest_query: - substr_queryset = queryset.filter( - Q(key__icontains=self.contest_query) - | Q(name__icontains=self.contest_query) - ) - if settings.ENABLE_FTS: - queryset = ( - queryset.search(self.contest_query).extra(order_by=["-relevance"]) - | substr_queryset - ) - else: - queryset = substr_queryset - if not self.org_query and self.request.organization: - self.org_query = [self.request.organization.id] - if self.hide_organization_contests: - queryset = queryset.filter(organizations=None) - if self.org_query: - queryset = queryset.filter(organizations__in=self.org_query) - queryset = self.extra_queryset_filters(queryset) - return queryset - - def _get_past_contests_queryset(self): - return ( - self._get_queryset() - .filter(end_time__lt=self._now) - .order_by(self.order, "key") - ) - - def _active_participations(self): - return ContestParticipation.objects.filter( - virtual=0, - user=self.request.profile, - contest__start_time__lte=self._now, - contest__end_time__gte=self._now, - ) - - @cached_property - def _active_contests_ids(self): - return [ - participation.contest_id - for participation in self._active_participations().select_related("contest") - if not participation.ended - ] - - def _get_current_contests_queryset(self): - return ( - self._get_queryset() - .exclude(id__in=self._active_contests_ids) - .filter(start_time__lte=self._now, end_time__gte=self._now) - .order_by(self.order, "key") - ) - - def _get_future_contests_queryset(self): - return ( - self._get_queryset() - .filter(start_time__gt=self._now) - .order_by(self.order, "key") - ) - - def _get_active_participations_queryset(self): - active_contests = ( - self._get_queryset() - .filter(id__in=self._active_contests_ids) - .order_by(self.order, "key") - ) - ordered_ids = list(active_contests.values_list("id", flat=True)) - - participations = self._active_participations().filter( - contest_id__in=ordered_ids - ) - participations = sorted( - participations, key=lambda p: ordered_ids.index(p.contest_id) - ) - return participations + return super(ContestList, self).get_queryset() \ + .order_by('-start_time', 'key').prefetch_related('tags', 'organizations', 'organizers') def get_queryset(self): - if self.current_tab == "past": - return self._get_past_contests_queryset() - elif self.current_tab == "current": - return self._get_current_contests_queryset() - elif self.current_tab == "future": - return self._get_future_contests_queryset() - else: # Default to active - return self._get_active_participations_queryset() + return self._get_queryset().filter(end_time__lt=self._now) def get_context_data(self, **kwargs): context = super(ContestList, self).get_context_data(**kwargs) + present, active, future = [], [], [] + for contest in self._get_queryset().exclude(end_time__lt=self._now): + if contest.start_time > self._now: + future.append(contest) + else: + present.append(contest) - context["current_tab"] = self.current_tab + if self.request.user.is_authenticated: + for participation in ContestParticipation.objects.filter(virtual=0, user=self.request.profile, + contest_id__in=present) \ + .select_related('contest').prefetch_related('contest__organizers'): + if not participation.ended: + active.append(participation) + present.remove(participation.contest) - context["current_count"] = self._get_current_contests_queryset().count() - context["future_count"] = self._get_future_contests_queryset().count() - context["active_count"] = len(self._get_active_participations_queryset()) - - context["now"] = self._now - context["first_page_href"] = "." - context["contest_query"] = self.contest_query - context["org_query"] = self.org_query - context["hide_organization_contests"] = int(self.hide_organization_contests) - if self.request.profile: - context["organizations"] = self.request.profile.organizations.all() - context["page_type"] = "list" - context["selected_order"] = self.request.GET.get("order") - context["all_sort_options"] = [ - ("start_time", _("Start time (asc.)")), - ("-start_time", _("Start time (desc.)")), - ("name", _("Name (asc.)")), - ("-name", _("Name (desc.)")), - ("user_count", _("User count (asc.)")), - ("-user_count", _("User count (desc.)")), - ] - context.update(self.get_sort_context()) - context.update(self.get_sort_paginate_context()) + active.sort(key=attrgetter('end_time')) + future.sort(key=attrgetter('start_time')) + context['active_participations'] = active + context['current_contests'] = present + context['future_contests'] = future + context['now'] = self._now + context['first_page_href'] = '.' return context @@ -349,114 +128,81 @@ class PrivateContestError(Exception): class ContestMixin(object): - context_object_name = "contest" + context_object_name = 'contest' model = Contest - slug_field = "key" - slug_url_kwarg = "contest" + slug_field = 'key' + slug_url_kwarg = 'contest' @cached_property - def is_editor(self): - if not self.request.user.is_authenticated: - return False - return self.request.profile.id in self.object.editor_ids + def is_organizer(self): + return self.check_organizer() - @cached_property - def is_tester(self): - if not self.request.user.is_authenticated: - return False - return self.request.profile.id in self.object.tester_ids - - @cached_property - def can_edit(self): - return self.object.is_editable_by(self.request.user) - - @cached_property - def can_access(self): - return self.object.is_accessible_by(self.request.user) - - def should_bypass_access_check(self, contest): - return False + def check_organizer(self, contest=None, user=None): + if user is None: + user = self.request.user + return (contest or self.object).is_editable_by(user) def get_context_data(self, **kwargs): context = super(ContestMixin, self).get_context_data(**kwargs) if self.request.user.is_authenticated: - try: - context[ - "live_participation" - ] = self.request.profile.contest_history.get( - contest=self.object, - virtual=ContestParticipation.LIVE, - ) - except ContestParticipation.DoesNotExist: - context["live_participation"] = None - context["has_joined"] = False + profile = self.request.profile + in_contest = context['in_contest'] = (profile.current_contest is not None and + profile.current_contest.contest == self.object) + if in_contest: + context['participation'] = profile.current_contest + context['participating'] = True else: - context["has_joined"] = True + try: + context['participation'] = profile.contest_history.get(contest=self.object, virtual=0) + except ContestParticipation.DoesNotExist: + context['participating'] = False + context['participation'] = None + else: + context['participating'] = True else: - context["live_participation"] = None - context["has_joined"] = False - - context["now"] = timezone.now() - context["is_editor"] = self.is_editor - context["is_tester"] = self.is_tester - context["can_edit"] = self.can_edit - context["can_access"] = self.can_access + context['participating'] = False + context['participation'] = None + context['in_contest'] = False + context['now'] = timezone.now() + context['is_organizer'] = self.is_organizer if not self.object.og_image or not self.object.summary: - metadata = generate_opengraph( - "generated-meta-contest:%d" % self.object.id, - self.object.description, - ) - context["meta_description"] = self.object.summary or metadata[0] - context["og_image"] = self.object.og_image or metadata[1] - context["has_moss_api_key"] = settings.MOSS_API_KEY is not None - context["contest_has_hidden_subtasks"] = self.object.format.has_hidden_subtasks - context[ - "show_final_ranking" - ] = self.object.format.has_hidden_subtasks and self.object.is_editable_by( - self.request.user - ) - context["logo_override_image"] = self.object.logo_override_image - - if ( - not context["logo_override_image"] - and self.object.organizations.count() == 1 - ): - org_image = self.object.organizations.first().organization_image - if org_image: - context["logo_override_image"] = org_image.url + metadata = generate_opengraph('generated-meta-contest:%d' % self.object.id, + self.object.description, 'contest') + context['meta_description'] = self.object.summary or metadata[0] + context['og_image'] = self.object.og_image or metadata[1] + context['has_moss_api_key'] = settings.MOSS_API_KEY is not None + context['logo_override_image'] = self.object.logo_override_image + if not context['logo_override_image'] and self.object.organizations.count() == 1: + context['logo_override_image'] = self.object.organizations.first().logo_override_image return context - def contest_access_check(self, contest): - try: - contest.access_check(self.request.user) - except Contest.PrivateContest: - raise PrivateContestError( - contest.name, - contest.is_private, - contest.is_organization_private, - contest.organizations.all(), - ) - except Contest.Inaccessible: - raise Http404() - def get_object(self, queryset=None): contest = super(ContestMixin, self).get_object(queryset) + user = self.request.user profile = self.request.profile - if ( - profile is not None - and ContestParticipation.objects.filter( - id=profile.current_contest_id, contest_id=contest.id - ).exists() - ): + if (profile is not None and + ContestParticipation.objects.filter(id=profile.current_contest_id, contest_id=contest.id).exists()): return contest - if self.should_bypass_access_check(contest): - return contest + if not contest.is_visible and not user.has_perm('judge.see_private_contest') and ( + not user.has_perm('judge.edit_own_contest') or + not self.check_organizer(contest, user)): + raise Http404() - self.contest_access_check(contest) + if contest.is_private or contest.is_organization_private: + private_contest_error = PrivateContestError(contest.name, contest.is_private, + contest.is_organization_private, contest.organizations.all()) + if profile is None: + raise private_contest_error + if user.has_perm('judge.edit_all_contest'): + return contest + if not (contest.is_organization_private and + contest.organizations.filter(id__in=profile.organizations.all()).exists()) and \ + not (contest.is_private and contest.private_contestants.filter(id=profile.id).exists()): + raise private_contest_error return contest @@ -466,164 +212,67 @@ class ContestMixin(object): except Http404: key = kwargs.get(self.slug_url_kwarg, None) if key: - return generic_message( - request, - _("No such contest"), - _('Could not find a contest with the key "%s".') % key, - ) + return generic_message(request, _('No such contest'), + _('Could not find a contest with the key "%s".') % key) else: - return generic_message( - request, _("No such contest"), _("Could not find such contest.") - ) + return generic_message(request, _('No such contest'), + _('Could not find such contest.')) except PrivateContestError as e: - return render( - request, - "contest/private.html", - { - "error": e, - "title": _('Access to contest "%s" denied') % e.name, - }, - status=403, - ) + return render(request, 'contest/private.html', { + 'error': e, 'title': _('Access to contest "%s" denied') % e.name, + }, status=403) -class ContestDetail( - ContestMixin, - TitleMixin, - CommentedDetailView, - PageVoteDetailView, - BookMarkDetailView, -): - template_name = "contest/contest.html" +class ContestDetail(ContestMixin, TitleMixin, CommentedDetailView): + template_name = 'contest/contest.html' + + def get_comment_page(self): + return 'c:%s' % self.object.key def get_title(self): return self.object.name - def get_editable_organizations(self): - if not self.request.profile: - return [] - res = [] - for organization in self.object.organizations.all(): - can_edit = False - if self.request.profile.can_edit_organization(organization): - can_edit = True - if self.request.profile in organization and self.object.is_editable_by( - self.request.user - ): - can_edit = True - if can_edit: - res.append(organization) - return res - def get_context_data(self, **kwargs): context = super(ContestDetail, self).get_context_data(**kwargs) - context["contest_problems"] = ( - Problem.objects.filter(contests__contest=self.object) - .order_by("contests__order") - .defer("description") - .annotate( - has_public_editorial=Sum( - Case( - When(solution__is_public=True, then=1), - default=0, - output_field=IntegerField(), - ) - ) - ) + context['contest_problems'] = Problem.objects.filter(contests__contest=self.object) \ + .order_by('contests__order').defer('description') \ + .annotate(has_public_editorial=Sum(Case(When(solution__is_public=True, then=1), + default=0, output_field=IntegerField()))) \ .add_i18n_name(self.request.LANGUAGE_CODE) - ) - context["editable_organizations"] = self.get_editable_organizations() - context["is_clonable"] = is_contest_clonable(self.request, self.object) - - if self.object.is_in_course: - from judge.models import Course, CourseContest - - course = CourseContest.get_course_of_contest(self.object) - if Course.is_editable_by(course, self.request.profile): - context["editable_course"] = course - - if self.request.in_contest: - context["current_contest"] = self.request.participation.contest - else: - context["current_contest"] = None return context -def is_contest_clonable(request, contest): - if not request.profile: - return False - if not Organization.objects.filter(admins=request.profile).exists(): - return False - if request.user.has_perm("judge.clone_contest"): - return True - if contest.access_code and not contest.is_editable_by(request.user): - return False - if ( - contest.end_time is not None - and contest.end_time + timedelta(days=1) < contest._now - ): - return True - return False - - -class ContestClone(ContestMixin, TitleMixin, SingleObjectFormView): - title = _("Clone Contest") - template_name = "contest/clone.html" +class ContestClone(ContestMixin, PermissionRequiredMixin, TitleMixin, SingleObjectFormView): + title = _('Clone Contest') + template_name = 'contest/clone.html' form_class = ContestCloneForm - - def get_object(self, queryset=None): - contest = super().get_object(queryset) - if not is_contest_clonable(self.request, contest): - raise Http404() - return contest - - def get_form_kwargs(self): - kwargs = super().get_form_kwargs() - kwargs["org_choices"] = tuple( - Organization.objects.filter(admins=self.request.profile).values_list( - "id", "name" - ) - ) - kwargs["profile"] = self.request.profile - return kwargs + permission_required = 'judge.clone_contest' def form_valid(self, form): - tags = self.object.tags.all() - organization = form.cleaned_data["organization"] - private_contestants = self.object.private_contestants.all() - view_contest_scoreboard = self.object.view_contest_scoreboard.all() - contest_problems = self.object.contest_problems.all() + contest = self.object - contest = deepcopy(self.object) + tags = contest.tags.all() + organizations = contest.organizations.all() + private_contestants = contest.private_contestants.all() + contest_problems = contest.contest_problems.all() contest.pk = None contest.is_visible = False contest.user_count = 0 - contest.key = form.cleaned_data["key"] - contest.is_rated = False + contest.key = form.cleaned_data['key'] contest.save() contest.tags.set(tags) - contest.organizations.set([organization]) + contest.organizations.set(organizations) contest.private_contestants.set(private_contestants) - contest.view_contest_scoreboard.set(view_contest_scoreboard) - contest.authors.add(self.request.profile) + contest.organizers.add(self.request.profile) for problem in contest_problems: problem.contest = contest problem.pk = None ContestProblem.objects.bulk_create(contest_problems) - return HttpResponseRedirect( - reverse( - "organization_contest_edit", - args=( - organization.id, - organization.slug, - contest.key, - ), - ) - ) + return HttpResponseRedirect(reverse('admin:judge_contest_change', args=(contest.id,))) class ContestAccessDenied(Exception): @@ -635,7 +284,7 @@ class ContestAccessCodeForm(forms.Form): def __init__(self, *args, **kwargs): super(ContestAccessCodeForm, self).__init__(*args, **kwargs) - self.fields["access_code"].widget.attrs.update({"autocomplete": "off"}) + self.fields['access_code'].widget.attrs.update({'autocomplete': 'off'}) class ContestJoin(LoginRequiredMixin, ContestMixin, BaseDetailView): @@ -648,7 +297,7 @@ class ContestJoin(LoginRequiredMixin, ContestMixin, BaseDetailView): try: return self.join_contest(request) except ContestAccessDenied: - if request.POST.get("access_code"): + if request.POST.get('access_code'): return self.ask_for_access_code(ContestAccessCodeForm(request.POST)) else: return HttpResponseRedirect(request.path) @@ -656,55 +305,32 @@ class ContestJoin(LoginRequiredMixin, ContestMixin, BaseDetailView): def join_contest(self, request, access_code=None): contest = self.object - if not contest.can_join and not (self.is_editor or self.is_tester): - return generic_message( - request, - _("Contest not ongoing"), - _('"%s" is not currently ongoing.') % contest.name, - ) + if not contest.can_join and not self.is_organizer: + return generic_message(request, _('Contest not ongoing'), + _('"%s" is not currently ongoing.') % contest.name) profile = request.profile if profile.current_contest is not None: - profile.remove_contest() + return generic_message(request, _('Already in contest'), + _('You are already in a contest: "%s".') % profile.current_contest.contest.name) - if ( - not request.user.is_superuser - and contest.banned_users.filter(id=profile.id).exists() - ): - return generic_message( - request, - _("Banned from joining"), - _( - "You have been declared persona non grata for this contest. " - "You are permanently barred from joining this contest." - ), - ) + if not request.user.is_superuser and contest.banned_users.filter(id=profile.id).exists(): + return generic_message(request, _('Banned from joining'), + _('You have been declared persona non grata for this contest. ' + 'You are permanently barred from joining this contest.')) - requires_access_code = ( - not self.can_edit - and contest.access_code - and access_code != contest.access_code - ) + requires_access_code = (not (request.user.is_superuser or self.is_organizer) and + contest.access_code and access_code != contest.access_code) if contest.ended: if requires_access_code: raise ContestAccessDenied() while True: - virtual_id = max( - ( - ContestParticipation.objects.filter( - contest=contest, user=profile - ).aggregate(virtual_id=Max("virtual"))["virtual_id"] - or 0 - ) - + 1, - 1, - ) + virtual_id = max((ContestParticipation.objects.filter(contest=contest, user=profile) + .aggregate(virtual_id=Max('virtual'))['virtual_id'] or 0) + 1, 1) try: participation = ContestParticipation.objects.create( - contest=contest, - user=profile, - virtual=virtual_id, + contest=contest, user=profile, virtual=virtual_id, real_start=timezone.now(), ) # There is obviously a race condition here, so we keep trying until we win the race. @@ -713,61 +339,45 @@ class ContestJoin(LoginRequiredMixin, ContestMixin, BaseDetailView): else: break else: - SPECTATE = ContestParticipation.SPECTATE - LIVE = ContestParticipation.LIVE try: participation = ContestParticipation.objects.get( - contest=contest, - user=profile, - virtual=(SPECTATE if self.is_editor or self.is_tester else LIVE), + contest=contest, user=profile, virtual=(-1 if self.is_organizer else 0), ) except ContestParticipation.DoesNotExist: if requires_access_code: raise ContestAccessDenied() participation = ContestParticipation.objects.create( - contest=contest, - user=profile, - virtual=(SPECTATE if self.is_editor or self.is_tester else LIVE), + contest=contest, user=profile, virtual=(-1 if self.is_organizer else 0), real_start=timezone.now(), ) else: if participation.ended: participation = ContestParticipation.objects.get_or_create( - contest=contest, - user=profile, - virtual=SPECTATE, - defaults={"real_start": timezone.now()}, + contest=contest, user=profile, virtual=-1, + defaults={'real_start': timezone.now()}, )[0] profile.current_contest = participation profile.save() contest._updating_stats_only = True contest.update_user_count() - request.session["contest_mode"] = True - return HttpResponseRedirect(reverse("problem_list")) + return HttpResponseRedirect(reverse('problem_list')) def ask_for_access_code(self, form=None): contest = self.object wrong_code = False if form: if form.is_valid(): - if form.cleaned_data["access_code"] == contest.access_code: - return self.join_contest( - self.request, form.cleaned_data["access_code"] - ) + if form.cleaned_data['access_code'] == contest.access_code: + return self.join_contest(self.request, form.cleaned_data['access_code']) wrong_code = True else: form = ContestAccessCodeForm() - return render( - self.request, - "contest/access_code.html", - { - "form": form, - "wrong_code": wrong_code, - "title": _('Enter access code for "%s"') % contest.name, - }, - ) + return render(self.request, 'contest/access_code.html', { + 'form': form, 'wrong_code': wrong_code, + 'title': _('Enter access code for "%s"') % contest.name, + }) class ContestLeave(LoginRequiredMixin, ContestMixin, BaseDetailView): @@ -775,38 +385,28 @@ class ContestLeave(LoginRequiredMixin, ContestMixin, BaseDetailView): contest = self.get_object() profile = request.profile - if ( - profile.current_contest is None - or profile.current_contest.contest_id != contest.id - ): - return generic_message( - request, - _("No such contest"), - _('You are not in contest "%s".') % contest.key, - 404, - ) + if profile.current_contest is None or profile.current_contest.contest_id != contest.id: + return generic_message(request, _('No such contest'), + _('You are not in contest "%s".') % contest.key, 404) profile.remove_contest() - request.session["contest_mode"] = True # reset contest_mode - return HttpResponseRedirect(reverse("contest_view", args=(contest.key,))) + return HttpResponseRedirect(reverse('contest_view', args=(contest.key,))) -ContestDay = namedtuple("ContestDay", "date weekday is_pad is_today starts ends oneday") +ContestDay = namedtuple('ContestDay', 'date weekday is_pad is_today starts ends oneday') class ContestCalendar(TitleMixin, ContestListMixin, TemplateView): firstweekday = SUNDAY - weekday_classes = ["sun", "mon", "tue", "wed", "thu", "fri", "sat"] - template_name = "contest/calendar.html" + weekday_classes = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'] + template_name = 'contest/calendar.html' def get(self, request, *args, **kwargs): try: - self.year = int(kwargs["year"]) - self.month = int(kwargs["month"]) + self.year = int(kwargs['year']) + self.month = int(kwargs['month']) except (KeyError, ValueError): - raise ImproperlyConfigured( - _("ContestCalendar requires integer year and month") - ) + raise ImproperlyConfigured(_('ContestCalendar requires integer year and month')) self.today = timezone.now().date() return self.render() @@ -816,16 +416,12 @@ class ContestCalendar(TitleMixin, ContestListMixin, TemplateView): def get_contest_data(self, start, end): end += timedelta(days=1) - contests = self.get_queryset().filter( - Q(start_time__gte=start, start_time__lt=end) - | Q(end_time__gte=start, end_time__lt=end) - ) + contests = self.get_queryset().filter(Q(start_time__gte=start, start_time__lt=end) | + Q(end_time__gte=start, end_time__lt=end)).defer('description') starts, ends, oneday = (defaultdict(list) for i in range(3)) for contest in contests: start_date = timezone.localtime(contest.start_time).date() - end_date = timezone.localtime( - contest.end_time - timedelta(seconds=1) - ).date() + end_date = timezone.localtime(contest.end_time - timedelta(seconds=1)).date() if start_date == end_date: oneday[start_date].append(contest) else: @@ -835,25 +431,12 @@ class ContestCalendar(TitleMixin, ContestListMixin, TemplateView): def get_table(self): calendar = Calendar(self.firstweekday).monthdatescalendar(self.year, self.month) - starts, ends, oneday = self.get_contest_data( - make_aware(datetime.combine(calendar[0][0], time.min)), - make_aware(datetime.combine(calendar[-1][-1], time.min)), - ) - return [ - [ - ContestDay( - date=date, - weekday=self.weekday_classes[weekday], - is_pad=date.month != self.month, - is_today=date == self.today, - starts=starts[date], - ends=ends[date], - oneday=oneday[date], - ) - for weekday, date in enumerate(week) - ] - for week in calendar - ] + starts, ends, oneday = self.get_contest_data(make_aware(datetime.combine(calendar[0][0], time.min)), + make_aware(datetime.combine(calendar[-1][-1], time.min))) + return [[ContestDay( + date=date, weekday=self.weekday_classes[weekday], is_pad=date.month != self.month, + is_today=date == self.today, starts=starts[date], ends=ends[date], oneday=oneday[date], + ) for weekday, date in enumerate(week)] for week in calendar] def get_context_data(self, **kwargs): context = super(ContestCalendar, self).get_context_data(**kwargs) @@ -863,53 +446,40 @@ class ContestCalendar(TitleMixin, ContestListMixin, TemplateView): except ValueError: raise Http404() else: - context["title"] = _("Contests in %(month)s") % { - "month": date_filter(month, _("F Y")) - } + context['title'] = _('Contests in %(month)s') % {'month': date_filter(month, _("F Y"))} - dates = Contest.objects.aggregate(min=Min("start_time"), max=Max("end_time")) + dates = Contest.objects.aggregate(min=Min('start_time'), max=Max('end_time')) min_month = (self.today.year, self.today.month) - if dates["min"] is not None: - min_month = dates["min"].year, dates["min"].month + if dates['min'] is not None: + min_month = dates['min'].year, dates['min'].month max_month = (self.today.year, self.today.month) - if dates["max"] is not None: - max_month = max( - (dates["max"].year, dates["max"].month), - (self.today.year, self.today.month), - ) + if dates['max'] is not None: + max_month = max((dates['max'].year, dates['max'].month), (self.today.year, self.today.month)) month = (self.year, self.month) if month < min_month or month > max_month: # 404 is valid because it merely declares the lack of existence, without any reason raise Http404() - context["now"] = timezone.now() - context["calendar"] = self.get_table() - context["curr_month"] = date(self.year, self.month, 1) + context['now'] = timezone.now() + context['calendar'] = self.get_table() + context['curr_month'] = date(self.year, self.month, 1) if month > min_month: - context["prev_month"] = date( - self.year - (self.month == 1), - 12 if self.month == 1 else self.month - 1, - 1, - ) + context['prev_month'] = date(self.year - (self.month == 1), 12 if self.month == 1 else self.month - 1, 1) else: - context["prev_month"] = None + context['prev_month'] = None if month < max_month: - context["next_month"] = date( - self.year + (self.month == 12), - 1 if self.month == 12 else self.month + 1, - 1, - ) + context['next_month'] = date(self.year + (self.month == 12), 1 if self.month == 12 else self.month + 1, 1) else: - context["next_month"] = None + context['next_month'] = None return context class CachedContestCalendar(ContestCalendar): def render(self): - key = "contest_cal:%d:%d" % (self.year, self.month) + key = 'contest_cal:%d:%d' % (self.year, self.month) cached = cache.get(key) if cached is not None: return HttpResponse(cached) @@ -920,38 +490,29 @@ class CachedContestCalendar(ContestCalendar): class ContestStats(TitleMixin, ContestMixin, DetailView): - template_name = "contest/stats.html" - POINT_BIN = 10 # in point distribution + template_name = 'contest/stats.html' def get_title(self): - return _("%s Statistics") % self.object.name + return _('%s Statistics') % self.object.name def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - if not (self.object.ended or self.can_edit): + if not (self.object.ended or self.object.is_editable_by(self.request.user)): raise Http404() queryset = Submission.objects.filter(contest_object=self.object) - ac_count = Count( - Case(When(result="AC", then=Value(1)), output_field=IntegerField()) - ) - ac_rate = CombinedExpression( - ac_count / Count("problem"), "*", Value(100.0), output_field=FloatField() - ) + ac_count = Count(Case(When(result='AC', then=Value(1)), output_field=IntegerField())) + ac_rate = CombinedExpression(ac_count / Count('problem'), '*', Value(100.0), output_field=FloatField()) status_count_queryset = list( - queryset.values("problem__code", "result") - .annotate(count=Count("result")) - .values_list("problem__code", "result", "count"), + queryset.values('problem__code', 'result').annotate(count=Count('result')) + .values_list('problem__code', 'result', 'count'), ) - labels, codes = [], [] - contest_problems = self.object.contest_problems.order_by("order").values_list( - "problem__name", "problem__code" + labels, codes = zip( + *self.object.contest_problems.order_by('order').values_list('problem__name', 'problem__code'), ) - if contest_problems: - labels, codes = zip(*contest_problems) num_problems = len(labels) status_counts = [[] for i in range(num_problems)] for problem_code, result, count in status_count_queryset: @@ -960,218 +521,118 @@ class ContestStats(TitleMixin, ContestMixin, DetailView): result_data = defaultdict(partial(list, [0] * num_problems)) for i in range(num_problems): - for category in _get_result_data(defaultdict(int, status_counts[i]))[ - "categories" - ]: - result_data[category["code"]][i] = category["count"] - - problem_points = [[] for _ in range(num_problems)] - point_count_queryset = list( - queryset.values( - "problem__code", "contest__points", "contest__problem__points" - ) - .annotate(count=Count("contest__points")) - .order_by("problem__code", "contest__points") - .values_list( - "problem__code", "contest__points", "contest__problem__points", "count" - ) - ) - counter = [[0 for _ in range(self.POINT_BIN + 1)] for _ in range(num_problems)] - for problem_code, point, max_point, count in point_count_queryset: - if (point == None) or (problem_code not in codes): - continue - problem_idx = codes.index(problem_code) - if max_point > 0: - bin_idx = math.floor(point * self.POINT_BIN / max_point) - else: - bin_idx = 0 - bin_idx = max(min(bin_idx, self.POINT_BIN), 0) - counter[problem_idx][bin_idx] += count - for i in range(num_problems): - problem_points[i] = [ - (j * 100 / self.POINT_BIN, counter[i][j]) - for j in range(len(counter[i])) - ] + for category in _get_result_data(defaultdict(int, status_counts[i]))['categories']: + result_data[category['code']][i] = category['count'] stats = { - "problem_status_count": { - "labels": labels, - "datasets": [ + 'problem_status_count': { + 'labels': labels, + 'datasets': [ { - "label": name, - "backgroundColor": settings.DMOJ_STATS_SUBMISSION_RESULT_COLORS[ - name - ], - "data": data, + 'label': name, + 'backgroundColor': settings.DMOJ_STATS_SUBMISSION_RESULT_COLORS[name], + 'data': data, } for name, data in result_data.items() ], }, - "problem_ac_rate": get_bar_chart( - queryset.values("contest__problem__order", "problem__name") - .annotate(ac_rate=ac_rate) - .order_by("contest__problem__order") - .values_list("problem__name", "ac_rate"), + 'problem_ac_rate': get_bar_chart( + queryset.values('contest__problem__order', 'problem__name').annotate(ac_rate=ac_rate) + .order_by('contest__problem__order').values_list('problem__name', 'ac_rate'), ), - "problem_point": [ - get_histogram(problem_points[i]) for i in range(num_problems) - ], - "language_count": get_pie_chart( - queryset.values("language__name") - .annotate(count=Count("language__name")) - .filter(count__gt=0) - .order_by("-count") - .values_list("language__name", "count"), + 'language_count': get_pie_chart( + queryset.values('language__name').annotate(count=Count('language__name')) + .filter(count__gt=0).order_by('-count').values_list('language__name', 'count'), ), - "language_ac_rate": get_bar_chart( - queryset.values("language__name") - .annotate(ac_rate=ac_rate) - .filter(ac_rate__gt=0) - .values_list("language__name", "ac_rate"), + 'language_ac_rate': get_bar_chart( + queryset.values('language__name').annotate(ac_rate=ac_rate) + .filter(ac_rate__gt=0).values_list('language__name', 'ac_rate'), ), } - context["stats"] = mark_safe(json.dumps(stats)) - context["problems"] = labels + context['stats'] = mark_safe(json.dumps(stats)) + return context ContestRankingProfile = namedtuple( - "ContestRankingProfile", - "id user username points cumtime tiebreaker participation " - "participation_rating problem_cells result_cell", + 'ContestRankingProfile', + 'id user css_class username points cumtime organization participation ' + 'participation_rating problem_cells result_cell', ) -BestSolutionData = namedtuple("BestSolutionData", "code points time state is_pretested") +BestSolutionData = namedtuple('BestSolutionData', 'code points time state is_pretested') -def make_contest_ranking_profile( - contest, participation, contest_problems, show_final=False -): - if not show_final: - points = participation.score - cumtime = participation.cumtime - else: - points = participation.score_final - cumtime = participation.cumtime_final - +def make_contest_ranking_profile(contest, participation, contest_problems): user = participation.user return ContestRankingProfile( id=user.id, - user=user, + user=user.user, + css_class=user.css_class, username=user.username, - points=points, - cumtime=cumtime, - tiebreaker=participation.tiebreaker, - participation_rating=participation.rating.rating - if hasattr(participation, "rating") - else None, - problem_cells=[ - contest.format.display_user_problem( - participation, contest_problem, show_final - ) - for contest_problem in contest_problems - ], - result_cell=contest.format.display_participation_result( - participation, show_final - ), + points=participation.score, + cumtime=participation.cumtime, + organization=user.organization, + participation_rating=participation.rating.rating if hasattr(participation, 'rating') else None, + problem_cells=[contest.format.display_user_problem(participation, contest_problem) + for contest_problem in contest_problems], + result_cell=contest.format.display_participation_result(participation), participation=participation, ) -def base_contest_ranking_list( - contest, problems, queryset, show_final=False, extra_participation=None -): - participation_fields = [ - field.name - for field in ContestParticipation._meta.get_fields() - if field.concrete and not field.many_to_many - ] - fields_to_fetch = participation_fields + [ - "user__id", - "rating__rating", - ] - - res = [ - make_contest_ranking_profile(contest, participation, problems, show_final) - for participation in queryset.select_related("user", "rating").only( - *fields_to_fetch - ) - ] - Profile.prefetch_profile_cache([p.id for p in res]) - return res +def base_contest_ranking_list(contest, problems, queryset): + return [make_contest_ranking_profile(contest, participation, problems) for participation in + queryset.select_related('user__user', 'rating').defer('user__about', 'user__organizations__about')] -def contest_ranking_list( - contest, problems, queryset=None, show_final=False, extra_participation=None -): - if queryset is None: - queryset = contest.users.filter(virtual=0) - - if extra_participation and extra_participation.virtual: - queryset = queryset | contest.users.filter(id=extra_participation.id) - - if show_final: - queryset = queryset.order_by( - "is_disqualified", "-score_final", "cumtime_final", "tiebreaker" - ) - else: - queryset = queryset.order_by( - "is_disqualified", "-score", "cumtime", "tiebreaker" - ) - - return base_contest_ranking_list( - contest, - problems, - queryset, - show_final, - ) +def contest_ranking_list(contest, problems): + return base_contest_ranking_list(contest, problems, contest.users.filter(virtual=0, user__is_unlisted=False) + .prefetch_related('user__organizations') + .order_by('is_disqualified', '-score', 'cumtime')) -def get_contest_ranking_list( - request, - contest, - participation=None, - ranking_list=contest_ranking_list, - ranker=ranker, - show_final=False, -): - problems = list( - contest.contest_problems.select_related("problem") - .defer("problem__description") - .order_by("order") - ) +def get_contest_ranking_list(request, contest, participation=None, ranking_list=contest_ranking_list, + show_current_virtual=True, ranker=ranker): + problems = list(contest.contest_problems.select_related('problem').defer('problem__description').order_by('order')) - if participation is None: - participation = _get_current_virtual_participation(request, contest) + if contest.hide_scoreboard and contest.is_in_contest(request.user): + return ([(_('???'), make_contest_ranking_profile(contest, request.profile.current_contest, problems))], + problems) - ranking_list_result = ranking_list( - contest, problems, show_final=show_final, extra_participation=participation - ) + users = ranker(ranking_list(contest, problems), key=attrgetter('points', 'cumtime')) - users = ranker( - ranking_list_result, - key=attrgetter("points", "cumtime", "tiebreaker"), - ) + if show_current_virtual: + if participation is None and request.user.is_authenticated: + participation = request.profile.current_contest + if participation is None or participation.contest_id != contest.id: + participation = None + if participation is not None and participation.virtual: + users = chain([('-', make_contest_ranking_profile(contest, participation, problems))], users) return users, problems -def _get_current_virtual_participation(request, contest): - # Return None if not eligible - if not request.user.is_authenticated: - return None +def contest_ranking_ajax(request, contest, participation=None): + contest, exists = _find_contest(request, contest) + if not exists: + return HttpResponseBadRequest('Invalid contest', content_type='text/plain') - participation = request.profile.current_contest + if not contest.can_see_scoreboard(request.user): + raise Http404() - if participation is None or participation.contest_id != contest.id: - return None - - return participation + users, problems = get_contest_ranking_list(request, contest, participation) + return render(request, 'contest/ranking-table.html', { + 'users': users, + 'problems': problems, + 'contest': contest, + 'has_rating': contest.ratings.exists(), + }) class ContestRankingBase(ContestMixin, TitleMixin, DetailView): - template_name = "contest/ranking.html" - page_type = None + template_name = 'contest/ranking.html' + tab = None def get_title(self): raise NotImplementedError() @@ -1185,139 +646,60 @@ class ContestRankingBase(ContestMixin, TitleMixin, DetailView): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - if not self.object.can_see_own_scoreboard(self.request.user): + if not self.object.can_see_scoreboard(self.request.user): raise Http404() users, problems = self.get_ranking_list() - context["users"] = users - context["problems"] = problems - context["page_type"] = self.page_type + context['users'] = users + context['problems'] = problems + context['last_msg'] = event.last() + context['tab'] = self.tab return context class ContestRanking(ContestRankingBase): - page_type = "ranking" - show_final = False - - def should_bypass_access_check(self, contest): - return contest.public_scoreboard + tab = 'ranking' def get_title(self): - return _("%s Rankings") % self.object.name + return _('%s Rankings') % self.object.name def get_ranking_list(self): - if not self.object.can_see_full_scoreboard(self.request.user): - queryset = self.object.users.filter( - user=self.request.profile, virtual=ContestParticipation.LIVE - ) - return get_contest_ranking_list( - self.request, - self.object, - ranking_list=partial(base_contest_ranking_list, queryset=queryset), - ranker=lambda users, key: ((_("???"), user) for user in users), - ) - - queryset = self.object.users - if self.friend_only: - friends = self.request.profile.get_friends() - queryset = queryset.filter(user_id__in=friends) - if not self.include_virtual: - queryset = queryset.filter(virtual=0) - else: - queryset = queryset.filter(virtual__gte=0) - - return get_contest_ranking_list( - self.request, - self.object, - ranking_list=partial(contest_ranking_list, queryset=queryset), - show_final=self.show_final, - ) - - def _get_default_include_virtual(self): - if hasattr(self.object, "official"): - return "1" - return "0" - - def setup_filters(self): - if self.request.profile: - self.friend_only = bool(self.request.GET.get("friend") == "1") - else: - self.friend_only = False - self.include_virtual = bool( - self.request.GET.get("virtual", self._get_default_include_virtual()) == "1" - ) - self.ajax_only = bool(self.request.GET.get("ajax") == "1") - - if self.ajax_only: - self.template_name = "contest/ranking-table.html" + return get_contest_ranking_list(self.request, self.object) def get_context_data(self, **kwargs): - self.setup_filters() context = super().get_context_data(**kwargs) - context["has_rating"] = self.object.ratings.exists() - if not self.ajax_only: - context["include_virtual"] = self.include_virtual - context["friend_only"] = self.friend_only + context['has_rating'] = self.object.ratings.exists() return context -class ContestFinalRanking(LoginRequiredMixin, ContestRanking): - page_type = "final_ranking" - show_final = True - - def get_ranking_list(self): - if not self.object.is_editable_by(self.request.user): - raise Http404() - if not self.object.format.has_hidden_subtasks: - raise Http404() - return super().get_ranking_list() - - class ContestParticipationList(LoginRequiredMixin, ContestRankingBase): - page_type = "participation" + tab = 'participation' def get_title(self): if self.profile == self.request.profile: - return _("Your participation in %s") % self.object.name + return _('Your participation in %s') % self.object.name return _("%s's participation in %s") % (self.profile.username, self.object.name) def get_ranking_list(self): - if ( - not self.object.can_see_full_scoreboard(self.request.user) - and self.profile != self.request.profile - ): - raise Http404() - - queryset = self.object.users.filter(user=self.profile, virtual__gte=0).order_by( - "-virtual" - ) - live_link = format_html( - '{0}', - _("Live"), - self.profile.username, - reverse("contest_ranking", args=[self.object.key]), - ) + queryset = self.object.users.filter(user=self.profile, virtual__gte=0).order_by('-virtual') + live_link = format_html('{0}', _('Live'), self.profile.username, + reverse('contest_ranking', args=[self.object.key])) return get_contest_ranking_list( - self.request, - self.object, + self.request, self.object, show_current_virtual=False, ranking_list=partial(base_contest_ranking_list, queryset=queryset), - ranker=lambda users, key: ( - (user.participation.virtual or live_link, user) for user in users - ), - ) + ranker=lambda users, key: ((user.participation.virtual or live_link, user) for user in users)) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context["has_rating"] = False - context["now"] = timezone.now() - context["rank_header"] = _("Participation") - context["participation_tab"] = True + context['has_rating'] = False + context['now'] = timezone.now() + context['rank_header'] = _('Participation') return context def get(self, request, *args, **kwargs): - if "user" in kwargs: - self.profile = get_object_or_404(Profile, user__username=kwargs["user"]) + if 'user' in kwargs: + self.profile = get_object_or_404(Profile, user__username=kwargs['user']) else: self.profile = self.request.profile return super().get(request, *args, **kwargs) @@ -1334,22 +716,20 @@ class ContestParticipationDisqualify(ContestMixin, SingleObjectMixin, View): self.object = self.get_object() try: - participation = self.object.users.get(pk=request.POST.get("participation")) + participation = self.object.users.get(pk=request.POST.get('participation')) except ObjectDoesNotExist: pass else: participation.set_disqualified(not participation.is_disqualified) - return HttpResponseRedirect(reverse("contest_ranking", args=(self.object.key,))) + return HttpResponseRedirect(reverse('contest_ranking', args=(self.object.key,))) class ContestMossMixin(ContestMixin, PermissionRequiredMixin): - permission_required = "judge.moss_contest" + permission_required = 'judge.moss_contest' def get_object(self, queryset=None): contest = super().get_object(queryset) - if settings.MOSS_API_KEY is None or not contest.is_editable_by( - self.request.user - ): + if settings.MOSS_API_KEY is None: raise Http404() if not contest.is_editable_by(self.request.user): raise Http404() @@ -1357,22 +737,16 @@ class ContestMossMixin(ContestMixin, PermissionRequiredMixin): class ContestMossView(ContestMossMixin, TitleMixin, DetailView): - template_name = "contest/moss.html" + template_name = 'contest/moss.html' def get_title(self): - return _("%s MOSS Results") % self.object.name + return _('%s MOSS Results') % self.object.name def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - problems = list( - map( - attrgetter("problem"), - self.object.contest_problems.order_by("order").select_related( - "problem" - ), - ) - ) + problems = list(map(attrgetter('problem'), self.object.contest_problems.order_by('order') + .select_related('problem'))) languages = list(map(itemgetter(0), ContestMoss.LANG_MAPPING)) results = ContestMoss.objects.filter(contest=self.object) @@ -1383,11 +757,9 @@ class ContestMossView(ContestMossMixin, TitleMixin, DetailView): for result_list in moss_results.values(): result_list.sort(key=lambda x: languages.index(x.language)) - context["languages"] = languages - context["has_results"] = results.exists() - context["moss_results"] = [ - (problem, moss_results[problem]) for problem in problems - ] + context['languages'] = languages + context['has_results'] = results.exists() + context['moss_results'] = [(problem, moss_results[problem]) for problem in problems] return context @@ -1395,9 +767,8 @@ class ContestMossView(ContestMossMixin, TitleMixin, DetailView): self.object = self.get_object() status = run_moss.delay(self.object.key) return redirect_to_task_status( - status, - message=_("Running MOSS for %s...") % (self.object.name,), - redirect=reverse("contest_moss", args=(self.object.key,)), + status, message=_('Running MOSS for %s...') % (self.object.name,), + redirect=reverse('contest_moss', args=(self.object.key,)), ) @@ -1405,258 +776,18 @@ class ContestMossDelete(ContestMossMixin, SingleObjectMixin, View): def post(self, request, *args, **kwargs): self.object = self.get_object() ContestMoss.objects.filter(contest=self.object).delete() - return HttpResponseRedirect(reverse("contest_moss", args=(self.object.key,))) + return HttpResponseRedirect(reverse('contest_moss', args=(self.object.key,))) class ContestTagDetailAjax(DetailView): model = ContestTag - slug_field = slug_url_kwarg = "name" - context_object_name = "tag" - template_name = "contest/tag-ajax.html" + slug_field = slug_url_kwarg = 'name' + context_object_name = 'tag' + template_name = 'contest/tag-ajax.html' class ContestTagDetail(TitleMixin, ContestTagDetailAjax): - template_name = "contest/tag.html" + template_name = 'contest/tag.html' def get_title(self): - return _("Contest tag: %s") % self.object.name - - -class ContestProblemClarificationForm(forms.Form): - body = forms.CharField( - widget=HeavyPreviewPageDownWidget( - preview=reverse_lazy("comment_preview"), - preview_timeout=1000, - hide_preview_button=True, - ) - ) - - def __init__(self, request, *args, **kwargs): - self.request = request - super(ContestProblemClarificationForm, self).__init__(*args, **kwargs) - self.fields["body"].widget.attrs.update({"placeholder": _("Issue description")}) - - -class NewContestClarificationView(ContestMixin, TitleMixin, SingleObjectFormView): - form_class = ContestProblemClarificationForm - template_name = "contest/clarification.html" - - def get_form_kwargs(self): - kwargs = super(NewContestClarificationView, self).get_form_kwargs() - kwargs["request"] = self.request - return kwargs - - def is_accessible(self): - if not self.request.user.is_authenticated: - return False - if not self.request.in_contest: - return False - if not self.request.participation.contest == self.get_object(): - return False - return self.get_object().is_editable_by(self.request.user) - - def get(self, request, *args, **kwargs): - if not self.is_accessible(): - raise Http404() - return super().get(self, request, *args, **kwargs) - - def form_valid(self, form): - problem_code = self.request.POST["problem"] - description = form.cleaned_data["body"] - - clarification = ContestProblemClarification(description=description) - clarification.problem = get_object_or_404( - ContestProblem, contest=self.get_object(), problem__code=problem_code - ) - clarification.save() - - return HttpResponseRedirect(reverse("problem_list")) - - def get_title(self): - return "New clarification for %s" % self.object.name - - def get_content_title(self): - return mark_safe( - escape(_("New clarification for %s")) - % format_html( - '{1}', - reverse("problem_detail", args=[self.object.key]), - self.object.name, - ) - ) - - def get_context_data(self, **kwargs): - context = super(NewContestClarificationView, self).get_context_data(**kwargs) - context["problems"] = ContestProblem.objects.filter( - contest=self.object - ).order_by("order") - return context - - -class ContestClarificationAjax(ContestMixin, DetailView): - def get(self, request, *args, **kwargs): - self.object = self.get_object() - if not self.object.is_accessible_by(request.user): - raise Http404() - - polling_time = 1 # minute - last_one_minute = timezone.now() - timezone.timedelta(minutes=polling_time) - - queryset = ContestProblemClarification.objects.filter( - problem__in=self.object.contest_problems.all(), date__gte=last_one_minute - ) - - problems = list( - ContestProblem.objects.filter(contest=self.object) - .order_by("order") - .values_list("problem__code", flat=True) - ) - res = [] - for clarification in queryset: - value = { - "order": self.object.get_label_for_problem( - problems.index(clarification.problem.problem.code) - ), - "problem__name": clarification.problem.problem.name, - "description": clarification.description, - } - res.append(value) - - return JsonResponse(res, safe=False, json_dumps_params={"ensure_ascii": False}) - - -def update_contest_mode(request): - if not request.is_ajax() or not request.method == "POST": - return HttpResponseNotAllowed(["POST"]) - - old_mode = request.session.get("contest_mode", True) - request.session["contest_mode"] = not old_mode - return HttpResponse() - - -ContestsSummaryData = namedtuple( - "ContestsSummaryData", - "username first_name last_name points point_contests css_class", -) - - -class ContestsSummaryView(DiggPaginatorMixin, ListView): - paginate_by = 50 - template_name = "contest/contests_summary.html" - - def get(self, *args, **kwargs): - try: - self.contests_summary = ContestsSummary.objects.get(key=kwargs["key"]) - except: - raise Http404() - return super().get(*args, **kwargs) - - def get_queryset(self): - total_rank = self.contests_summary.results - return total_rank - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - context["contests"] = self.contests_summary.contests.all() - context["title"] = _("Contests") - context["first_page_href"] = "." - return context - - -def recalculate_contest_summary_result(request, contest_summary): - scores_system = contest_summary.scores - contests = contest_summary.contests.all() - total_points = defaultdict(int) - result_per_contest = defaultdict(lambda: [(0, 0)] * len(contests)) - user_css_class = {} - - for i in range(len(contests)): - contest = contests[i] - users, problems = get_contest_ranking_list(request, contest) - for rank, user in users: - curr_score = 0 - if rank - 1 < len(scores_system): - curr_score = scores_system[rank - 1] - total_points[user.user] += curr_score - result_per_contest[user.user][i] = (curr_score, rank) - user_css_class[user.user] = user.user.css_class - - sorted_total_points = [ - ContestsSummaryData( - username=user.username, - first_name=user.first_name, - last_name=user.last_name, - points=total_points[user], - point_contests=result_per_contest[user], - css_class=user_css_class[user], - ) - for user in total_points - ] - - sorted_total_points.sort(key=lambda x: x.points, reverse=True) - total_rank = ranker(sorted_total_points) - return [(rank, item._asdict()) for rank, item in total_rank] - - -class OfficialContestList(ContestList): - official = True - template_name = "contest/official_list.html" - - def setup_contest_list(self, request): - self.contest_query = request.GET.get("contest", "") - self.org_query = [] - self.hide_organization_contests = False - - self.selected_categories = [] - self.selected_locations = [] - self.year_from = None - self.year_to = None - - if "category" in request.GET: - try: - self.selected_categories = list( - map(int, request.GET.getlist("category")) - ) - except ValueError: - pass - if "location" in request.GET: - try: - self.selected_locations = list( - map(int, request.GET.getlist("location")) - ) - except ValueError: - pass - if "year_from" in request.GET: - try: - self.year_from = int(request.GET.get("year_from")) - except ValueError: - pass - if "year_to" in request.GET: - try: - self.year_to = int(request.GET.get("year_to")) - except ValueError: - pass - - def extra_queryset_filters(self, queryset): - if self.selected_categories: - queryset = queryset.filter(official__category__in=self.selected_categories) - if self.selected_locations: - queryset = queryset.filter(official__location__in=self.selected_locations) - if self.year_from: - queryset = queryset.filter(official__year__gte=self.year_from) - if self.year_to: - queryset = queryset.filter(official__year__lte=self.year_to) - return queryset - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - context["page_type"] = "official" - context["is_official"] = True - context["categories"] = OfficialContestCategory.objects.all() - context["locations"] = OfficialContestLocation.objects.all() - context["selected_categories"] = self.selected_categories - context["selected_locations"] = self.selected_locations - context["year_from"] = self.year_from - context["year_to"] = self.year_to - - return context + return _('Contest tag: %s') % self.object.name diff --git a/judge/views/course.py b/judge/views/course.py deleted file mode 100644 index 7514d6f..0000000 --- a/judge/views/course.py +++ /dev/null @@ -1,781 +0,0 @@ -from django.utils.html import mark_safe -from django.db import models -from django.views.generic import ListView, DetailView, View -from django.utils.translation import gettext, gettext_lazy as _ -from django.http import Http404 -from django import forms -from django.forms import ( - inlineformset_factory, - ModelForm, - modelformset_factory, - BaseModelFormSet, -) -from django.views.generic.edit import FormView -from django.shortcuts import get_object_or_404 -from django.urls import reverse_lazy, reverse -from django.db.models import Max, F, Sum -from django.core.exceptions import ObjectDoesNotExist - -from judge.models import ( - Course, - Contest, - CourseLesson, - Submission, - Profile, - CourseRole, - CourseLessonProblem, - CourseContest, - ContestProblem, - ContestParticipation, -) -from judge.models.course import RoleInCourse -from judge.widgets import ( - HeavyPreviewPageDownWidget, - HeavySelect2MultipleWidget, - HeavySelect2Widget, - DateTimePickerWidget, - Select2MultipleWidget, - Select2Widget, -) -from judge.forms import ( - ContestProblemFormSet, -) -from judge.utils.problems import ( - user_attempted_ids, - user_completed_ids, -) -from judge.utils.contest import ( - maybe_trigger_contest_rescore, -) -from reversion import revisions - - -def max_case_points_per_problem(profile, problems): - # return a dict {problem_id: {case_points, case_total}} - q = ( - Submission.objects.filter(user=profile, problem__in=problems) - .values("problem") - .annotate(case_points=Max("case_points"), case_total=F("case_total")) - .order_by("problem") - ) - res = {} - for problem in q: - res[problem["problem"]] = problem - return res - - -def calculate_lessons_progress(profile, lessons): - res = {} - total_achieved_points = total_lesson_points = 0 - for lesson in lessons: - problems = lesson.lesson_problems.values_list("problem", flat=True) - problem_points = max_case_points_per_problem(profile, problems) - achieved_points = total_points = 0 - - for lesson_problem in lesson.lesson_problems.all(): - val = problem_points.get(lesson_problem.problem.id) - if val and val["case_total"]: - achieved_points += ( - val["case_points"] / val["case_total"] * lesson_problem.score - ) - total_points += lesson_problem.score - - res[lesson.id] = { - "achieved_points": achieved_points, - "total_points": total_points, - "percentage": achieved_points / total_points * 100 if total_points else 0, - } - if total_points: - total_achieved_points += achieved_points / total_points * lesson.points - total_lesson_points += lesson.points - - res["total"] = { - "achieved_points": total_achieved_points, - "total_points": total_lesson_points, - "percentage": total_achieved_points / total_lesson_points * 100 - if total_lesson_points - else 0, - } - return res - - -def calculate_contests_progress(profile, course_contests): - res = {} - total_achieved_points = total_contest_points = 0 - for course_contest in course_contests: - contest = course_contest.contest - - achieved_points = 0 - participation = ContestParticipation.objects.filter( - contest=contest, user=profile, virtual=0 - ).first() - - if participation: - achieved_points = participation.score - - total_points = ( - ContestProblem.objects.filter(contest=contest).aggregate(Sum("points"))[ - "points__sum" - ] - or 0 - ) - - res[course_contest.id] = { - "achieved_points": achieved_points, - "total_points": total_points, - "percentage": achieved_points / total_points * 100 if total_points else 0, - } - - if total_points: - total_achieved_points += ( - achieved_points / total_points * course_contest.points - ) - total_contest_points += course_contest.points - - res["total"] = { - "achieved_points": total_achieved_points, - "total_points": total_contest_points, - "percentage": total_achieved_points / total_contest_points * 100 - if total_contest_points - else 0, - } - return res - - -def calculate_total_progress(profile, lesson_progress, contest_progress): - lesson_total = lesson_progress["total"] - contest_total = contest_progress["total"] - total_achieved_points = ( - lesson_total["achieved_points"] + contest_total["achieved_points"] - ) - total_points = lesson_total["total_points"] + contest_total["total_points"] - - res = { - "achieved_points": total_achieved_points, - "total_points": total_points, - "percentage": total_achieved_points / total_points * 100 if total_points else 0, - } - return res - - -class CourseList(ListView): - model = Course - template_name = "course/list.html" - queryset = Course.objects.filter(is_public=True).filter(is_open=True) - - def get_context_data(self, **kwargs): - context = super(CourseList, self).get_context_data(**kwargs) - context["courses"] = Course.get_accessible_courses(self.request.profile) - context["title"] = _("Courses") - context["page_type"] = "list" - return context - - -class CourseDetailMixin(object): - def dispatch(self, request, *args, **kwargs): - self.course = get_object_or_404(Course, slug=self.kwargs["slug"]) - if not Course.is_accessible_by(self.course, self.request.profile): - raise Http404() - self.is_editable = Course.is_editable_by(self.course, self.request.profile) - return super(CourseDetailMixin, self).dispatch(request, *args, **kwargs) - - def get_context_data(self, **kwargs): - context = super(CourseDetailMixin, self).get_context_data(**kwargs) - context["course"] = self.course - context["is_editable"] = self.is_editable - return context - - -class CourseEditableMixin(CourseDetailMixin): - def dispatch(self, request, *args, **kwargs): - res = super(CourseEditableMixin, self).dispatch(request, *args, **kwargs) - if not self.is_editable: - raise Http404() - return res - - -class CourseDetail(CourseDetailMixin, DetailView): - model = Course - template_name = "course/course.html" - - def get_object(self): - return self.course - - def get_context_data(self, **kwargs): - context = super(CourseDetail, self).get_context_data(**kwargs) - lessons = ( - self.course.lessons.filter(is_visible=True) - .order_by("order") - .prefetch_related("lesson_problems") - .all() - ) - course_contests = ( - self.course.contests.select_related("contest") - .filter(contest__is_visible=True) - .order_by("order") - ) - context["title"] = self.course.name - context["page_type"] = "home" - context["lessons"] = lessons - context["lesson_progress"] = calculate_lessons_progress( - self.request.profile, lessons - ) - context["course_contests"] = course_contests - context["contest_progress"] = calculate_contests_progress( - self.request.profile, course_contests - ) - - context["total_progress"] = calculate_total_progress( - self.request.profile, - context["lesson_progress"], - context["contest_progress"], - ) - - return context - - -class CourseLessonDetail(CourseDetailMixin, DetailView): - model = CourseLesson - template_name = "course/lesson.html" - - def get_object(self): - try: - self.lesson = CourseLesson.objects.get( - course=self.course, id=self.kwargs["id"] - ) - - is_editable = Course.is_editable_by(self.course, self.request.profile) - if not self.lesson.is_visible and not is_editable: - raise Http404() - - return self.lesson - except ObjectDoesNotExist: - raise Http404() - - def get_profile(self): - username = self.request.GET.get("user") - if not username: - return self.request.profile - - is_editable = Course.is_editable_by(self.course, self.request.profile) - if not is_editable: - raise Http404() - - try: - profile = Profile.objects.get(user__username=username) - is_student = profile.course_roles.filter( - role=RoleInCourse.STUDENT, course=self.course - ).exists() - if not is_student: - raise Http404() - return profile - except ObjectDoesNotExist: - raise Http404() - - def get_context_data(self, **kwargs): - context = super(CourseLessonDetail, self).get_context_data(**kwargs) - profile = self.get_profile() - context["profile"] = profile - context["title"] = self.lesson.title - context["lesson"] = self.lesson - context["completed_problem_ids"] = user_completed_ids(profile) - context["attempted_problems"] = user_attempted_ids(profile) - context["problem_points"] = max_case_points_per_problem( - profile, self.lesson.lesson_problems.values_list("problem", flat=True) - ) - return context - - -class CourseLessonForm(forms.ModelForm): - class Meta: - model = CourseLesson - fields = ["order", "title", "is_visible", "points", "content"] - widgets = { - "title": forms.TextInput(), - "content": HeavyPreviewPageDownWidget(preview=reverse_lazy("blog_preview")), - "problems": HeavySelect2MultipleWidget(data_view="problem_select2"), - } - - -CourseLessonFormSet = inlineformset_factory( - Course, CourseLesson, form=CourseLessonForm, extra=1, can_delete=True -) - - -class CourseLessonProblemForm(ModelForm): - class Meta: - model = CourseLessonProblem - fields = ["order", "problem", "score", "lesson"] - widgets = { - "problem": HeavySelect2Widget( - data_view="problem_select2", attrs={"style": "width: 100%"} - ), - "lesson": forms.HiddenInput(), - } - - -CourseLessonProblemFormSet = modelformset_factory( - CourseLessonProblem, form=CourseLessonProblemForm, extra=5, can_delete=True -) - - -class EditCourseLessonsView(CourseEditableMixin, FormView): - template_name = "course/edit_lesson.html" - form_class = CourseLessonFormSet - - def get_problem_formset(self, post=False, lesson=None): - formset = CourseLessonProblemFormSet( - data=self.request.POST if post else None, - prefix=f"problems_{lesson.id}" if lesson else "problems", - queryset=CourseLessonProblem.objects.filter(lesson=lesson).order_by( - "order" - ), - ) - if lesson: - for form in formset: - form.fields["lesson"].initial = lesson - return formset - - def get_context_data(self, **kwargs): - context = super(EditCourseLessonsView, self).get_context_data(**kwargs) - if self.request.method == "POST": - context["formset"] = self.form_class( - self.request.POST, self.request.FILES, instance=self.course - ) - context["problem_formsets"] = { - lesson.instance.id: self.get_problem_formset( - post=True, lesson=lesson.instance - ) - for lesson in context["formset"].forms - if lesson.instance.id - } - else: - context["formset"] = self.form_class( - instance=self.course, queryset=self.course.lessons.order_by("order") - ) - context["problem_formsets"] = { - lesson.instance.id: self.get_problem_formset( - post=False, lesson=lesson.instance - ) - for lesson in context["formset"].forms - if lesson.instance.id - } - - context["title"] = _("Edit lessons for %(course_name)s") % { - "course_name": self.course.name - } - context["content_title"] = mark_safe( - _("Edit lessons for %(course_name)s") - % { - "course_name": self.course.name, - "url": self.course.get_absolute_url(), - } - ) - context["page_type"] = "edit_lesson" - - return context - - def post(self, request, *args, **kwargs): - formset = self.form_class(request.POST, instance=self.course) - problem_formsets = [ - self.get_problem_formset(post=True, lesson=lesson.instance) - for lesson in formset.forms - if lesson.instance.id - ] - for pf in problem_formsets: - if not pf.is_valid(): - return self.form_invalid(pf) - - if formset.is_valid(): - formset.save() - for problem_formset in problem_formsets: - problem_formset.save() - for obj in problem_formset.deleted_objects: - if obj.pk is not None: - obj.delete() - return self.form_valid(formset) - else: - return self.form_invalid(formset) - - def get_success_url(self): - return self.request.path - - -class CourseStudentResults(CourseEditableMixin, DetailView): - model = Course - template_name = "course/grades.html" - - def get_object(self): - return self.course - - def get_grades(self): - students = self.course.get_students() - students.sort(key=lambda u: u.username.lower()) - lessons = ( - self.course.lessons.filter(is_visible=True) - .prefetch_related("lesson_problems") - .all() - ) - course_contests = ( - self.course.contests.select_related("contest") - .filter(contest__is_visible=True) - .order_by("order") - ) - - grade_lessons = {} - grade_contests = {} - grade_total = {} - for s in students: - grade_lessons[s] = lesson_progress = calculate_lessons_progress(s, lessons) - grade_contests[s] = contest_progress = calculate_contests_progress( - s, course_contests - ) - grade_total[s] = calculate_total_progress( - s, lesson_progress, contest_progress - ) - return grade_lessons, grade_contests, grade_total - - def get_context_data(self, **kwargs): - context = super(CourseStudentResults, self).get_context_data(**kwargs) - context["title"] = _("Grades in %(course_name)s") % { - "course_name": self.course.name, - } - context["content_title"] = mark_safe( - _("Grades in %(course_name)s") - % { - "course_name": self.course.name, - "url": self.course.get_absolute_url(), - } - ) - context["page_type"] = "grades" - ( - context["grade_lessons"], - context["grade_contests"], - context["grade_total"], - ) = self.get_grades() - context["lessons"] = self.course.lessons.filter(is_visible=True).order_by( - "order" - ) - context["course_contests"] = ( - self.course.contests.select_related("contest") - .filter(contest__is_visible=True) - .order_by("order") - ) - return context - - -class CourseStudentResultsLesson(CourseEditableMixin, DetailView): - model = CourseLesson - template_name = "course/grades_lesson.html" - - def get_object(self): - try: - self.lesson = CourseLesson.objects.get( - course=self.course, id=self.kwargs["id"] - ) - return self.lesson - except ObjectDoesNotExist: - raise Http404() - - def get_lesson_grades(self): - students = self.course.get_students() - students.sort(key=lambda u: u.username.lower()) - problems = self.lesson.lesson_problems.values_list("problem", flat=True) - lesson_problems = self.lesson.lesson_problems.all() - grades = {} - for s in students: - grades[s] = problem_points = max_case_points_per_problem(s, problems) - achieved_points = total_points = 0 - for lesson_problem in lesson_problems: - val = problem_points.get(lesson_problem.problem.id) - if val and val["case_total"]: - achieved_points += ( - val["case_points"] / val["case_total"] * lesson_problem.score - ) - total_points += lesson_problem.score - grades[s]["total"] = { - "achieved_points": achieved_points, - "total_points": total_points, - "percentage": achieved_points / total_points * 100 - if total_points - else 0, - } - return grades - - def get_context_data(self, **kwargs): - context = super(CourseStudentResultsLesson, self).get_context_data(**kwargs) - context["lesson"] = self.lesson - context["title"] = _("Grades of %(lesson_name)s in %(course_name)s") % { - "course_name": self.course.name, - "lesson_name": self.lesson.title, - } - context["content_title"] = mark_safe( - _( - "Grades of %(lesson_name)s in %(course_name)s" - ) - % { - "course_name": self.course.name, - "lesson_name": self.lesson.title, - "url_course": self.course.get_absolute_url(), - "url_lesson": self.lesson.get_absolute_url(), - } - ) - context["page_type"] = "grades" - context["grades"] = self.get_lesson_grades() - return context - - -class AddCourseContestForm(forms.ModelForm): - order = forms.IntegerField(label=_("Order")) - points = forms.IntegerField(label=_("Points")) - - class Meta: - model = Contest - fields = [ - "order", - "points", - "key", - "name", - "start_time", - "end_time", - "problems", - ] - widgets = { - "start_time": DateTimePickerWidget(), - "end_time": DateTimePickerWidget(), - "problems": HeavySelect2MultipleWidget(data_view="problem_select2"), - } - - def save(self, course, profile, commit=True): - contest = super().save(commit=False) - contest.is_in_course = True - - old_save_m2m = self.save_m2m - - def save_m2m(): - for i, problem in enumerate(self.cleaned_data["problems"]): - contest_problem = ContestProblem( - contest=contest, problem=problem, points=100, order=i + 1 - ) - contest_problem.save() - contest.contest_problems.add(contest_problem) - contest.authors.add(profile) - old_save_m2m() - - self.save_m2m = save_m2m - contest.save() - self.save_m2m() - - CourseContest.objects.create( - course=course, - contest=contest, - order=self.cleaned_data["order"], - points=self.cleaned_data["points"], - ) - - return contest - - -class AddCourseContest(CourseEditableMixin, FormView): - template_name = "course/add_contest.html" - form_class = AddCourseContestForm - - def get_title(self): - return _("Add contest") - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - context["title"] = self.get_title() - return context - - def form_valid(self, form): - with revisions.create_revision(): - revisions.set_comment(_("Added from course") + " " + self.course.name) - revisions.set_user(self.request.user) - - self.contest = form.save(course=self.course, profile=self.request.profile) - - return super().form_valid(form) - - def get_success_url(self): - return reverse( - "edit_course_contest", - args=[self.course.slug, self.contest.key], - ) - - -class CourseContestList(CourseEditableMixin, ListView): - template_name = "course/contest_list.html" - context_object_name = "course_contests" - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - context["title"] = _("Contest list") - context["page_type"] = "contests" - return context - - def get_queryset(self): - return self.course.contests.select_related("contest").all().order_by("order") - - -class EditCourseContestForm(ModelForm): - order = forms.IntegerField(label=_("Order")) - points = forms.IntegerField(label=_("Points")) - - class Meta: - model = Contest - fields = ( - "order", - "points", - "is_visible", - "key", - "name", - "start_time", - "end_time", - "format_name", - "authors", - "curators", - "testers", - "time_limit", - "freeze_after", - "use_clarifications", - "hide_problem_tags", - "public_scoreboard", - "scoreboard_visibility", - "points_precision", - "rate_limit", - "description", - "access_code", - "private_contestants", - "view_contest_scoreboard", - "banned_users", - ) - widgets = { - "authors": HeavySelect2MultipleWidget(data_view="profile_select2"), - "curators": HeavySelect2MultipleWidget(data_view="profile_select2"), - "testers": HeavySelect2MultipleWidget(data_view="profile_select2"), - "private_contestants": HeavySelect2MultipleWidget( - data_view="profile_select2" - ), - "banned_users": HeavySelect2MultipleWidget(data_view="profile_select2"), - "view_contest_scoreboard": HeavySelect2MultipleWidget( - data_view="profile_select2" - ), - "tags": Select2MultipleWidget, - "description": HeavyPreviewPageDownWidget( - preview=reverse_lazy("contest_preview") - ), - "start_time": DateTimePickerWidget(), - "end_time": DateTimePickerWidget(), - "format_name": Select2Widget(), - "scoreboard_visibility": Select2Widget(), - } - - def __init__(self, *args, **kwargs): - self.course_contest_instance = kwargs.pop("course_contest_instance", None) - super().__init__(*args, **kwargs) - - if self.course_contest_instance: - self.fields["order"].initial = self.course_contest_instance.order - self.fields["points"].initial = self.course_contest_instance.points - - def save(self, commit=True): - contest = super().save(commit=commit) - - if self.course_contest_instance: - self.course_contest_instance.order = self.cleaned_data["order"] - self.course_contest_instance.points = self.cleaned_data["points"] - if commit: - self.course_contest_instance.save() - - return contest - - -class EditCourseContest(CourseEditableMixin, FormView): - template_name = "course/edit_contest.html" - form_class = EditCourseContestForm - - def dispatch(self, request, *args, **kwargs): - self.contest = get_object_or_404(Contest, key=self.kwargs["contest"]) - res = super().dispatch(request, *args, **kwargs) - if not self.contest.is_in_course: - raise Http404() - return res - - def get_form_kwargs(self): - self.course_contest = get_object_or_404( - CourseContest, course=self.course, contest=self.contest - ) - - kwargs = super().get_form_kwargs() - kwargs["instance"] = self.contest - kwargs["course_contest_instance"] = self.course_contest - return kwargs - - def post(self, request, *args, **kwargs): - problem_formset = self.get_problem_formset(True) - if problem_formset.is_valid(): - self.problem_form_changes = False - for problem_form in problem_formset: - if problem_form.has_changed(): - self.problem_form_changes = True - if problem_form.cleaned_data.get("DELETE") and problem_form.instance.pk: - problem_form.instance.delete() - - for problem_form in problem_formset.save(commit=False): - if problem_form: - problem_form.contest = self.contest - problem_form.save() - - return super().post(request, *args, **kwargs) - - self.object = self.contest - return self.render_to_response( - self.get_context_data( - problems_form=problem_formset, - ) - ) - - def get_title(self): - return _("Edit contest") - - def form_valid(self, form): - with revisions.create_revision(): - revisions.set_comment(_("Edited from course") + " " + self.course.name) - revisions.set_user(self.request.user) - - if self.problem_form_changes: - maybe_trigger_contest_rescore(form, self.contest, True) - - form.save() - - return super().form_valid(form) - - def get_problem_formset(self, post=False): - return ContestProblemFormSet( - data=self.request.POST if post else None, - prefix="problems", - queryset=ContestProblem.objects.filter(contest=self.contest).order_by( - "order" - ), - ) - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - context["title"] = self.get_title() - context["content_title"] = mark_safe( - _("Edit %(contest_name)s") - % { - "contest_name": self.contest.name, - "url": self.contest.get_absolute_url(), - } - ) - if "problems_form" not in context: - context["problems_form"] = self.get_problem_formset() - return context - - def get_success_url(self): - return reverse( - "edit_course_contest", - args=[self.course.slug, self.contest.key], - ) diff --git a/judge/views/custom_file_upload.py b/judge/views/custom_file_upload.py deleted file mode 100644 index cdc4f8e..0000000 --- a/judge/views/custom_file_upload.py +++ /dev/null @@ -1,43 +0,0 @@ -from django.shortcuts import render -from django.core.files.storage import FileSystemStorage -from django import forms -from django.utils.translation import gettext as _ -from django.conf import settings -from django.http import Http404 - -import os -import secrets -from urllib.parse import urljoin - -MEDIA_PATH = "uploads" - - -class FileUploadForm(forms.Form): - file = forms.FileField() - - -def file_upload(request): - if not request.user.is_superuser: - raise Http404() - file_url = None - if request.method == "POST": - form = FileUploadForm(request.POST, request.FILES) - if form.is_valid(): - file = request.FILES["file"] - random_str = secrets.token_urlsafe(5) - file_name, file_extension = os.path.splitext(file.name) - new_filename = f"{file_name}_{random_str}{file_extension}" - - fs = FileSystemStorage( - location=os.path.join(settings.MEDIA_ROOT, MEDIA_PATH) - ) - filename = fs.save(new_filename, file) - file_url = urljoin(settings.MEDIA_URL, os.path.join(MEDIA_PATH, filename)) - else: - form = FileUploadForm() - - return render( - request, - "custom_file_upload.html", - {"form": form, "file_url": file_url, "title": _("File Upload")}, - ) diff --git a/judge/views/email.py b/judge/views/email.py deleted file mode 100644 index 5544daf..0000000 --- a/judge/views/email.py +++ /dev/null @@ -1,121 +0,0 @@ -from django.contrib.auth.tokens import default_token_generator -from django.core.mail import send_mail -from django.shortcuts import render, redirect -from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode -from django.utils.encoding import force_bytes, force_text -from django.conf import settings -from django import forms -from django.utils.translation import gettext_lazy as _ -from django.urls import reverse -from django.contrib.auth.decorators import login_required -from django.contrib.auth.models import User -from django.contrib.auth.hashers import check_password - -from urllib.parse import urlencode, urlunparse, urlparse - -from judge.models import Profile -from judge.utils.email_render import render_email_message - - -class EmailChangeForm(forms.Form): - new_email = forms.EmailField(label=_("New Email")) - password = forms.CharField(label=_("Password"), widget=forms.PasswordInput) - - def __init__(self, *args, **kwargs): - self.user = kwargs.pop("user", None) - super().__init__(*args, **kwargs) - - def clean_new_email(self): - new_email = self.cleaned_data.get("new_email") - if User.objects.filter(email=new_email).exists(): - raise forms.ValidationError(_("An account with this email already exists.")) - return new_email - - def clean_password(self): - password = self.cleaned_data.get("password") - if not self.user.check_password(password): - raise forms.ValidationError("Invalid password") - return password - - -@login_required -def email_change_view(request): - form = EmailChangeForm(request.POST or None, user=request.user) - - if request.method == "POST" and form.is_valid(): - new_email = request.POST.get("new_email") - user = request.user - profile = request.profile - - # Generate a token for email verification - token = default_token_generator.make_token(user) - uid = urlsafe_base64_encode(force_bytes(user.pk)) - - # Send the email to the user - subject = settings.SITE_NAME + " - " + _("Email Change Request") - email_contexts = { - "message": _( - "We have received a request to change your email to this email. Click the button below to change your email:" - ), - "title": _("Email Change"), - "button_text": _("Change Email"), - "url_path": reverse( - "email_change_verify", kwargs={"uidb64": uid, "token": token} - ), - } - message = render_email_message(request, email_contexts) - send_mail( - subject, - message, - settings.EMAIL_HOST_USER, - [new_email], - html_message=message, - ) - profile.email_change_pending = new_email - profile.save() - return redirect("email_change_pending") - - return render( - request, - "email_change/email_change.html", - { - "form": form, - "title": _("Change email"), - }, - ) - - -def verify_email_view(request, uidb64, token): - try: - uid = force_text(urlsafe_base64_decode(uidb64)) - user = User.objects.get(pk=uid) - except (TypeError, ValueError, OverflowError, User.DoesNotExist): - user = None - if user is not None and default_token_generator.check_token(user, token): - profile = Profile.objects.get(user=user) - new_email = profile.email_change_pending - if new_email and not User.objects.filter(email=new_email).exists(): - user.email = new_email - profile.email_change_pending = None - user.save() - profile.save() - - return render( - request, - "email_change/email_change_success.html", - {"title": _("Success"), "user": user}, - ) - - return render( - request, "email_change/email_change_failure.html", {"title": _("Invalid")} - ) - - -def email_change_pending_view(request): - return render( - request, - "email_change/email_change_pending.html", - { - "title": _("Email change pending"), - }, - ) diff --git a/judge/views/error.py b/judge/views/error.py index cffed7e..113422d 100644 --- a/judge/views/error.py +++ b/judge/views/error.py @@ -5,42 +5,29 @@ from django.utils.translation import gettext as _ def error(request, context, status): - return render(request, "error.html", context=context, status=status) + return render(request, 'error.html', context=context, status=status) def error404(request, exception=None): # TODO: "panic: go back" - return render( - request, - "generic-message.html", - { - "title": _("404 error"), - "message": _('Could not find page "%s"') % request.path, - }, - status=404, - ) + return render(request, 'generic-message.html', { + 'title': _('404 error'), + 'message': _('Could not find page "%s"') % request.path, + }, status=404) def error403(request, exception=None): - return error( - request, - { - "id": "unauthorized_access", - "description": _("no permission for %s") % request.path, - "code": 403, - }, - 403, - ) + return error(request, { + 'id': 'unauthorized_access', + 'description': _('no permission for %s') % request.path, + 'code': 403, + }, 403) def error500(request): - return error( - request, - { - "id": "invalid_state", - "description": _("corrupt page %s") % request.path, - "traceback": traceback.format_exc(), - "code": 500, - }, - 500, - ) + return error(request, { + 'id': 'invalid_state', + 'description': _('corrupt page %s') % request.path, + 'traceback': traceback.format_exc(), + 'code': 500, + }, 500) diff --git a/judge/views/feed.py b/judge/views/feed.py deleted file mode 100644 index cd809d5..0000000 --- a/judge/views/feed.py +++ /dev/null @@ -1,35 +0,0 @@ -from django.views.generic import ListView -from django.shortcuts import render -from django.urls import reverse - -from judge.utils.infinite_paginator import InfinitePaginationMixin - - -class FeedView(InfinitePaginationMixin, ListView): - def get_feed_context(selfl, object_list): - return {} - - def get(self, request, *args, **kwargs): - only_content = request.GET.get("only_content", None) - if only_content and self.feed_content_template_name: - queryset = self.get_queryset() - paginator, page, object_list, _ = self.paginate_queryset( - queryset, self.paginate_by - ) - context = { - self.context_object_name: object_list, - "has_next_page": page.has_next(), - } - context.update(self.get_feed_context(object_list)) - return render(request, self.feed_content_template_name, context) - - return super(FeedView, self).get(request, *args, **kwargs) - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - context["has_next_page"] = context["page_obj"].has_next() - try: - context["feed_content_url"] = reverse(self.url_name) - except Exception as e: - context["feed_content_url"] = self.request.path - return context diff --git a/judge/views/internal.py b/judge/views/internal.py deleted file mode 100644 index 060a2c3..0000000 --- a/judge/views/internal.py +++ /dev/null @@ -1,170 +0,0 @@ -import logging -import json - -from django.views.generic import ListView -from django.utils.translation import gettext as _, gettext_lazy -from django.db.models import Count, Q -from django.http import HttpResponseForbidden -from django.urls import reverse -from django.shortcuts import render - -from judge.utils.diggpaginator import DiggPaginator -from judge.models import VolunteerProblemVote, Problem - - -class InternalView(object): - def get(self, request, *args, **kwargs): - if request.user.is_superuser: - return super(InternalView, self).get(request, *args, **kwargs) - return HttpResponseForbidden() - - -class InternalProblem(InternalView, ListView): - model = Problem - title = _("Internal problems") - template_name = "internal/problem/problem.html" - paginate_by = 100 - context_object_name = "problems" - - def get_paginator( - self, queryset, per_page, orphans=0, allow_empty_first_page=True, **kwargs - ): - return DiggPaginator( - queryset, - per_page, - body=6, - padding=2, - orphans=orphans, - allow_empty_first_page=allow_empty_first_page, - **kwargs - ) - - def get_search_query(self): - return self.request.GET.get("q") or self.request.POST.get("q") - - def get_queryset(self): - queryset = Problem.objects.annotate( - vote_count=Count("volunteer_user_votes") - ).filter(vote_count__gte=1) - query = self.get_search_query() - if query: - queryset = queryset.filter( - Q(code__icontains=query) | Q(name__icontains=query) - ) - return queryset.order_by("-vote_count") - - def get_context_data(self, **kwargs): - context = super(InternalProblem, self).get_context_data(**kwargs) - context["page_type"] = "problem" - context["title"] = self.title - context["page_prefix"] = self.request.path + "?page=" - context["first_page_href"] = self.request.path - context["query"] = self.get_search_query() - - return context - - -def get_problem_votes(request): - if not request.user.is_superuser: - return HttpResponseForbidden() - try: - problem = Problem.objects.get(id=request.GET.get("id")) - except: - return HttpResponseForbidden() - votes = ( - problem.volunteer_user_votes.select_related("voter") - .prefetch_related("types") - .order_by("id") - ) - return render( - request, - "internal/problem/votes.html", - { - "problem": problem, - "votes": votes, - }, - ) - - -class RequestTimeMixin(object): - def get_requests_data(self): - logger = logging.getLogger(self.log_name) - log_filename = logger.handlers[0].baseFilename - requests = [] - - with open(log_filename, "r") as f: - for line in f: - try: - info = json.loads(line) - requests.append(info) - except: - continue - return requests - - -class InternalRequestTime(InternalView, ListView, RequestTimeMixin): - title = _("Request times") - template_name = "internal/request_time.html" - context_object_name = "pages" - log_name = "judge.request_time" - detail_url_name = "internal_request_time_detail" - page_type = "request_time" - - def get_queryset(self): - requests = self.get_requests_data() - table = {} - for r in requests: - url_name = r["url_name"] - if url_name not in table: - table[url_name] = { - "time": 0, - "count": 0, - "url_name": url_name, - } - old_sum = table[url_name]["time"] * table[url_name]["count"] - table[url_name]["count"] += 1 - table[url_name]["time"] = (old_sum + float(r["response_time"])) / table[ - url_name - ]["count"] - order = self.request.GET.get("order", "time") - return sorted(table.values(), key=lambda x: x[order], reverse=True) - - def get_context_data(self, **kwargs): - context = super(InternalRequestTime, self).get_context_data(**kwargs) - context["page_type"] = self.page_type - context["title"] = self.title - context["current_path"] = self.request.path - context["detail_path"] = reverse(self.detail_url_name) - return context - - -class InternalRequestTimeDetail(InternalRequestTime): - template_name = "internal/request_time_detail.html" - context_object_name = "requests" - - def get_queryset(self): - url_name = self.request.GET.get("url_name", None) - if not url_name: - return HttpResponseForbidden() - if url_name == "None": - url_name = None - self.title = url_name - requests = self.get_requests_data() - filtered_requests = [r for r in requests if r["url_name"] == url_name] - order = self.request.GET.get("order", "response_time") - return sorted(filtered_requests, key=lambda x: x[order], reverse=True)[:200] - - def get_context_data(self, **kwargs): - context = super(InternalRequestTimeDetail, self).get_context_data(**kwargs) - context["url_name"] = self.request.GET.get("url_name", None) - return context - - -class InternalSlowRequest(InternalRequestTime): - log_name = "judge.slow_request" - detail_url_name = "internal_slow_request_detail" - page_type = "slow_request" - - -class InternalSlowRequestDetail(InternalRequestTimeDetail): - log_name = "judge.slow_request" diff --git a/judge/views/language.py b/judge/views/language.py index bbdc4bd..87ab8cb 100644 --- a/judge/views/language.py +++ b/judge/views/language.py @@ -7,12 +7,12 @@ from judge.utils.views import TitleMixin class LanguageList(TitleMixin, ListView): model = Language - context_object_name = "languages" - template_name = "status/language-list.html" - title = gettext_lazy("Runtimes") + context_object_name = 'languages' + template_name = 'status/language-list.html' + title = gettext_lazy('Runtimes') def get_queryset(self): - queryset = super().get_queryset().prefetch_related("runtimeversion_set") + queryset = super().get_queryset().prefetch_related('runtimeversion_set') if not self.request.user.is_superuser and not self.request.user.is_staff: queryset = queryset.filter(judges__online=True).distinct() return queryset diff --git a/judge/views/license.py b/judge/views/license.py index 0e208b7..77208e6 100644 --- a/judge/views/license.py +++ b/judge/views/license.py @@ -6,9 +6,9 @@ from judge.utils.views import TitleMixin class LicenseDetail(TitleMixin, DetailView): model = License - slug_field = slug_url_kwarg = "key" - context_object_name = "license" - template_name = "license.html" + slug_field = slug_url_kwarg = 'key' + context_object_name = 'license' + template_name = 'license.html' def get_title(self): return self.object.name diff --git a/judge/views/mailgun.py b/judge/views/mailgun.py index f28589a..3bd8321 100644 --- a/judge/views/mailgun.py +++ b/judge/views/mailgun.py @@ -15,77 +15,49 @@ from registration.models import RegistrationProfile from judge.utils.unicode import utf8bytes -logger = logging.getLogger("judge.mail.activate") +logger = logging.getLogger('judge.mail.activate') class MailgunActivationView(View): - if hasattr(settings, "MAILGUN_ACCESS_KEY"): - + if hasattr(settings, 'MAILGUN_ACCESS_KEY'): def post(self, request, *args, **kwargs): params = request.POST - timestamp = params.get("timestamp", "") - token = params.get("token", "") - signature = params.get("signature", "") + timestamp = params.get('timestamp', '') + token = params.get('token', '') + signature = params.get('signature', '') - logger.debug("Received request: %s", params) + logger.debug('Received request: %s', params) - if ( - signature - != hmac.new( - key=utf8bytes(settings.MAILGUN_ACCESS_KEY), - msg=utf8bytes("%s%s" % (timestamp, token)), - digestmod=hashlib.sha256, - ).hexdigest() - ): - logger.info( - "Rejected request: signature: %s, timestamp: %s, token: %s", - signature, - timestamp, - token, - ) + if signature != hmac.new(key=utf8bytes(settings.MAILGUN_ACCESS_KEY), + msg=utf8bytes('%s%s' % (timestamp, token)), digestmod=hashlib.sha256).hexdigest(): + logger.info('Rejected request: signature: %s, timestamp: %s, token: %s', signature, timestamp, token) raise PermissionDenied() - _, sender = parseaddr(params.get("from")) + _, sender = parseaddr(params.get('from')) if not sender: - logger.info("Rejected invalid sender: %s", params.get("from")) + logger.info('Rejected invalid sender: %s', params.get('from')) return HttpResponse(status=406) try: user = User.objects.get(email__iexact=sender) except (User.DoesNotExist, User.MultipleObjectsReturned): - logger.info( - "Rejected unknown sender: %s: %s", sender, params.get("from") - ) + logger.info('Rejected unknown sender: %s: %s', sender, params.get('from')) return HttpResponse(status=406) try: registration = RegistrationProfile.objects.get(user=user) except RegistrationProfile.DoesNotExist: - logger.info( - "Rejected sender without RegistrationProfile: %s: %s", - sender, - params.get("from"), - ) + logger.info('Rejected sender without RegistrationProfile: %s: %s', sender, params.get('from')) return HttpResponse(status=406) if registration.activated: - logger.info( - "Rejected activated sender: %s: %s", sender, params.get("from") - ) + logger.info('Rejected activated sender: %s: %s', sender, params.get('from')) return HttpResponse(status=406) key = registration.activation_key - if key in params.get("body-plain", "") or key in params.get( - "body-html", "" - ): - if RegistrationProfile.objects.activate_user( - key, get_current_site(request) - ): - logger.info("Activated sender: %s: %s", sender, params.get("from")) - return HttpResponse("Activated", status=200) - logger.info( - "Failed to activate sender: %s: %s", sender, params.get("from") - ) + if key in params.get('body-plain', '') or key in params.get('body-html', ''): + if RegistrationProfile.objects.activate_user(key, get_current_site(request)): + logger.info('Activated sender: %s: %s', sender, params.get('from')) + return HttpResponse('Activated', status=200) + logger.info('Failed to activate sender: %s: %s', sender, params.get('from')) else: - logger.info( - "Activation key not found: %s: %s", sender, params.get("from") - ) + logger.info('Activation key not found: %s: %s', sender, params.get('from')) return HttpResponse(status=406) @method_decorator(csrf_exempt) diff --git a/judge/views/markdown_editor.py b/judge/views/markdown_editor.py deleted file mode 100644 index a014ba6..0000000 --- a/judge/views/markdown_editor.py +++ /dev/null @@ -1,14 +0,0 @@ -from django.views import View -from django.shortcuts import render -from django.utils.translation import gettext_lazy as _ - - -class MarkdownEditor(View): - def get(self, request): - return render( - request, - "markdown_editor/markdown_editor.html", - { - "title": _("Markdown Editor"), - }, - ) diff --git a/judge/views/notification.py b/judge/views/notification.py deleted file mode 100644 index ee720c1..0000000 --- a/judge/views/notification.py +++ /dev/null @@ -1,42 +0,0 @@ -from django.contrib.auth.decorators import login_required -from django.views.generic import ListView -from django.utils.translation import ugettext as _ -from django.utils.timezone import now -from django.http import Http404 - -from judge.models import Profile, Notification, NotificationProfile -from judge.models.notification import unseen_notifications_count -from judge.utils.infinite_paginator import InfinitePaginationMixin - -__all__ = ["NotificationList"] - - -class NotificationList(InfinitePaginationMixin, ListView): - model = Notification - context_object_name = "notifications" - template_name = "notification/list.html" - paginate_by = 50 - - def get_queryset(self): - self.unseen_cnt = unseen_notifications_count(self.request.profile) - - self.queryset = Notification.objects.filter( - owner=self.request.profile - ).order_by("-id") - - return self.queryset - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - context["unseen_count"] = self.unseen_cnt - context["title"] = _("Notifications (%d unseen)") % context["unseen_count"] - context["first_page_href"] = "." - return context - - def get(self, request, *args, **kwargs): - ret = super().get(request, *args, **kwargs) - if not request.user.is_authenticated: - raise Http404() - NotificationProfile.objects.filter(user=request.profile).update(unread_count=0) - unseen_notifications_count.dirty(self.request.profile) - return ret diff --git a/judge/views/organization.py b/judge/views/organization.py index 2a5fea1..a9c1053 100644 --- a/judge/views/organization.py +++ b/judge/views/organization.py @@ -6,543 +6,101 @@ from django.core.cache import cache from django.core.cache.utils import make_template_fragment_key from django.core.exceptions import PermissionDenied from django.db import transaction -from django.db.models import Count, Q, Value, BooleanField -from django.db.utils import ProgrammingError +from django.db.models import Count, Q from django.forms import Form, modelformset_factory -from django.http import ( - Http404, - HttpResponsePermanentRedirect, - HttpResponseRedirect, - HttpResponseBadRequest, -) -from django.shortcuts import get_object_or_404 +from django.http import Http404, HttpResponsePermanentRedirect, HttpResponseRedirect from django.urls import reverse -from django.utils import timezone -from django.utils.html import format_html -from django.utils.functional import cached_property -from django.utils.safestring import mark_safe from django.utils.translation import gettext as _, gettext_lazy, ungettext -from django.views.generic import ( - DetailView, - FormView, - ListView, - UpdateView, - View, - CreateView, -) -from django.views.generic.detail import ( - SingleObjectMixin, - SingleObjectTemplateResponseMixin, -) -from django.core.paginator import Paginator -from django.contrib.sites.shortcuts import get_current_site +from django.views.generic import DetailView, FormView, ListView, UpdateView, View +from django.views.generic.detail import SingleObjectMixin, SingleObjectTemplateResponseMixin from reversion import revisions -from judge.forms import ( - EditOrganizationForm, - AddOrganizationForm, - AddOrganizationMemberForm, - OrganizationBlogForm, - OrganizationAdminBlogForm, - EditOrganizationContestForm, - ContestProblemFormSet, - AddOrganizationContestForm, -) -from judge.models import ( - BlogPost, - Comment, - Organization, - OrganizationRequest, - Problem, - Profile, - Contest, - ContestProblem, - OrganizationProfile, -) -from judge.models.notification import make_notification -from judge import event_poster as event +from judge.forms import EditOrganizationForm +from judge.models import Organization, OrganizationRequest, Profile from judge.utils.ranker import ranker -from judge.utils.views import ( - TitleMixin, - generic_message, - QueryStringSortMixin, - DiggPaginatorMixin, -) -from judge.utils.problems import user_attempted_ids, user_completed_ids -from judge.utils.contest import maybe_trigger_contest_rescore -from judge.views.problem import ProblemList -from judge.views.contests import ContestList -from judge.views.submission import SubmissionsListBase -from judge.views.feed import FeedView -from judge.tasks import rescore_contest +from judge.utils.views import TitleMixin, generic_message -__all__ = [ - "OrganizationList", - "OrganizationHome", - "OrganizationUsers", - "OrganizationProblems", - "OrganizationContests", - "OrganizationMembershipChange", - "JoinOrganization", - "LeaveOrganization", - "EditOrganization", - "RequestJoinOrganization", - "OrganizationRequestDetail", - "OrganizationRequestView", - "OrganizationRequestLog", - "KickUserWidgetView", -] +__all__ = ['OrganizationList', 'OrganizationHome', 'OrganizationUsers', 'OrganizationMembershipChange', + 'JoinOrganization', 'LeaveOrganization', 'EditOrganization', 'RequestJoinOrganization', + 'OrganizationRequestDetail', 'OrganizationRequestView', 'OrganizationRequestLog', + 'KickUserWidgetView'] -class OrganizationBase(object): - def can_edit_organization(self, org=None): - if org is None: - org = self.object - if self.request.profile: - return self.request.profile.can_edit_organization(org) - return False +class OrganizationMixin(object): + context_object_name = 'organization' + model = Organization - def is_member(self, org=None): - if org is None: - org = self.object - if self.request.profile: - return org.is_member(self.request.profile) - return False - - def is_admin(self, org=None): - if org is None: - org = self.object - if self.request.profile: - return org.is_admin(self.request.profile) - return False - - def can_access(self, org): - if self.request.user.is_superuser: - return True - if org is None: - org = self.object - return self.is_member(org) or self.can_edit_organization(org) - - -class OrganizationMixin(OrganizationBase): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context["is_member"] = self.is_member(self.organization) - context["is_admin"] = self.is_admin(self.organization) - context["can_edit"] = self.can_edit_organization(self.organization) - context["organization"] = self.organization - context["organization_image"] = self.organization.organization_image - context["organization_subdomain"] = ( - ("http" if settings.DMOJ_SSL == 0 else "https") - + "://" - + self.organization.slug - + "." - + get_current_site(self.request).domain - ) - if "organizations" in context: - context.pop("organizations") + context['logo_override_image'] = self.object.logo_override_image return context def dispatch(self, request, *args, **kwargs): try: - self.organization_id = int(kwargs["pk"]) - self.organization = get_object_or_404(Organization, id=self.organization_id) + return super(OrganizationMixin, self).dispatch(request, *args, **kwargs) except Http404: - key = None - if hasattr(self, "slug_url_kwarg"): - key = kwargs.get(self.slug_url_kwarg, None) + key = kwargs.get(self.slug_url_kwarg, None) if key: - return generic_message( - request, - _("No such organization"), - _('Could not find an organization with the key "%s".') % key, - status=403, - ) + return generic_message(request, _('No such organization'), + _('Could not find an organization with the key "%s".') % key) else: - return generic_message( - request, - _("No such organization"), - _("Could not find such organization."), - status=403, - ) - if self.organization.slug != kwargs["slug"]: - return HttpResponsePermanentRedirect( - request.get_full_path().replace(kwargs["slug"], self.organization.slug) - ) - if self.request.user.is_authenticated: - OrganizationProfile.add_organization( - self.request.profile, self.organization - ) + return generic_message(request, _('No such organization'), + _('Could not find such organization.')) - return super(OrganizationMixin, self).dispatch(request, *args, **kwargs) - - -class AdminOrganizationMixin(OrganizationMixin): - def dispatch(self, request, *args, **kwargs): - res = super(AdminOrganizationMixin, self).dispatch(request, *args, **kwargs) - if not hasattr(self, "organization") or self.can_edit_organization( - self.organization - ): - return res - return generic_message( - request, - _("Can't edit organization"), - _("You are not allowed to edit this organization."), - status=403, - ) - - -class MemberOrganizationMixin(OrganizationMixin): - def dispatch(self, request, *args, **kwargs): - res = super(MemberOrganizationMixin, self).dispatch(request, *args, **kwargs) - if not hasattr(self, "organization") or self.can_access(self.organization): - return res - return generic_message( - request, - _("Can't access organization"), - _("You are not allowed to access this organization."), - status=403, - ) - - -class OrganizationHomeView(OrganizationMixin): - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - if not hasattr(self, "organization"): - self.organization = self.object - if self.can_edit_organization(self.organization): - context["pending_count"] = OrganizationRequest.objects.filter( - state="P", organization=self.organization - ).count() - context["pending_blog_count"] = BlogPost.objects.filter( - visible=False, organizations=self.organization - ).count() - else: - context["pending_blog_count"] = BlogPost.objects.filter( - visible=False, - organizations=self.organization, - authors=self.request.profile, - ).count() - context["top_rated"] = ( - self.organization.members.filter(is_unlisted=False) - .order_by("-rating") - .only("id", "rating")[:10] - ) - context["top_scorer"] = ( - self.organization.members.filter(is_unlisted=False) - .order_by("-performance_points") - .only("id", "performance_points")[:10] - ) - Profile.prefetch_profile_cache([p.id for p in context["top_rated"]]) - Profile.prefetch_profile_cache([p.id for p in context["top_scorer"]]) - - return context - - -class OrganizationList( - QueryStringSortMixin, DiggPaginatorMixin, TitleMixin, ListView, OrganizationBase -): - model = Organization - context_object_name = "organizations" - template_name = "organization/list.html" - title = gettext_lazy("Groups") - paginate_by = 12 - all_sorts = frozenset(("name", "member_count")) - default_desc = frozenset(("name", "member_count")) - - def get_default_sort_order(self, request): - return "-member_count" - - def get(self, request, *args, **kwargs): - default_tab = "mine" + def can_edit_organization(self, org=None): + if org is None: + org = self.object if not self.request.user.is_authenticated: - default_tab = "public" - self.current_tab = self.request.GET.get("tab", default_tab) - self.organization_query = request.GET.get("organization", "") + return False + profile_id = self.request.profile.id + return org.admins.filter(id=profile_id).exists() or org.registrant_id == profile_id - return super(OrganizationList, self).get(request, *args, **kwargs) - def _get_queryset(self): - queryset = ( - super(OrganizationList, self) - .get_queryset() - .annotate(member_count=Count("member")) - .defer("about") - ) +class OrganizationDetailView(OrganizationMixin, DetailView): + def get(self, request, *args, **kwargs): + self.object = self.get_object() + if self.object.slug != kwargs['slug']: + return HttpResponsePermanentRedirect(request.get_full_path().replace(kwargs['slug'], self.object.slug)) + context = self.get_context_data(object=self.object) + return self.render_to_response(context) - if self.organization_query: - queryset = queryset.filter( - Q(slug__icontains=self.organization_query) - | Q(name__icontains=self.organization_query) - | Q(short_name__icontains=self.organization_query) - ) - return queryset + +class OrganizationList(TitleMixin, ListView): + model = Organization + context_object_name = 'organizations' + template_name = 'organization/list.html' + title = gettext_lazy('Organizations') def get_queryset(self): - organization_list = self._get_queryset() - - my_organizations = [] - if self.request.profile: - my_organizations = organization_list.filter( - id__in=self.request.profile.organizations.values("id") - ) - - if self.current_tab == "public": - queryset = organization_list.exclude(id__in=my_organizations).filter( - is_open=True - ) - elif self.current_tab == "private": - queryset = organization_list.exclude(id__in=my_organizations).filter( - is_open=False - ) - else: - queryset = my_organizations - - if queryset: - queryset = queryset.order_by(self.order) - return queryset - - def get_context_data(self, **kwargs): - context = super(OrganizationList, self).get_context_data(**kwargs) - - context["first_page_href"] = "." - context["current_tab"] = self.current_tab - context["page_type"] = self.current_tab - context["organization_query"] = self.organization_query - context["selected_order"] = self.request.GET.get("order") - context["all_sort_options"] = [ - ("name", _("Name (asc.)")), - ("-name", _("Name (desc.)")), - ("member_count", _("Member count (asc.)")), - ("-member_count", _("Member count (desc.)")), - ] - - context.update(self.get_sort_context()) - context.update(self.get_sort_paginate_context()) - - return context + return super(OrganizationList, self).get_queryset().annotate(member_count=Count('member')) -class OrganizationHome(OrganizationHomeView, FeedView): - template_name = "organization/home.html" - paginate_by = 4 - context_object_name = "posts" - feed_content_template_name = "blog/content.html" - - def get_queryset(self): - return ( - BlogPost.objects.filter( - visible=True, - publish_on__lte=timezone.now(), - is_organization_private=True, - organizations=self.organization, - ) - .order_by("-sticky", "-publish_on") - .prefetch_related("authors__user", "organizations") - ) +class OrganizationHome(OrganizationDetailView): + template_name = 'organization/home.html' def get_context_data(self, **kwargs): context = super(OrganizationHome, self).get_context_data(**kwargs) - context["title"] = self.organization.name - - now = timezone.now() - visible_contests = ( - Contest.get_visible_contests(self.request.user) - .filter( - is_visible=True, - is_organization_private=True, - organizations=self.organization, - ) - .order_by("start_time") - ) - context["current_contests"] = visible_contests.filter( - start_time__lte=now, end_time__gt=now - ) - context["future_contests"] = visible_contests.filter(start_time__gt=now) - context["page_type"] = "home" - + context['title'] = self.object.name + context['can_edit'] = self.can_edit_organization() return context -class OrganizationUsers( - DiggPaginatorMixin, QueryStringSortMixin, OrganizationMixin, ListView -): - template_name = "organization/users.html" - all_sorts = frozenset(("points", "problem_count", "rating", "performance_points")) - default_desc = all_sorts - default_sort = "-performance_points" - paginate_by = 100 - context_object_name = "users" - - def get_queryset(self): - return ( - self.organization.members.filter(is_unlisted=False) - .order_by(self.order, "id") - .select_related("user") - .only( - "display_rank", - "user__username", - "points", - "rating", - "performance_points", - "problem_count", - ) - ) - - def dispatch(self, request, *args, **kwargs): - res = super(OrganizationUsers, self).dispatch(request, *args, **kwargs) - if res.status_code != 200: - return res - if self.can_access(self.organization) or self.organization.is_open: - return res - return generic_message( - request, - _("Can't access organization"), - _("You are not allowed to access this organization."), - status=403, - ) +class OrganizationUsers(OrganizationDetailView): + template_name = 'organization/users.html' def get_context_data(self, **kwargs): context = super(OrganizationUsers, self).get_context_data(**kwargs) - context["title"] = _("%s Members") % self.organization.name - context["partial"] = True - context["kick_url"] = reverse( - "organization_user_kick", - args=[self.organization.id, self.organization.slug], - ) - context["users"] = ranker( - context["users"], rank=self.paginate_by * (context["page_obj"].number - 1) - ) - - context["first_page_href"] = "." - context["page_type"] = "users" - context.update(self.get_sort_context()) + context['title'] = _('%s Members') % self.object.name + context['users'] = \ + ranker(self.object.members.filter(is_unlisted=False).order_by('-performance_points', '-problem_count') + .select_related('user').defer('about', 'user_script', 'notes')) + context['partial'] = True + context['is_admin'] = self.can_edit_organization() + context['kick_url'] = reverse('organization_user_kick', args=[self.object.id, self.object.slug]) return context -class OrganizationProblems(LoginRequiredMixin, MemberOrganizationMixin, ProblemList): - template_name = "organization/problems.html" - filter_organization = True - - def get_queryset(self): - self.org_query = [self.organization_id] - return super().get_normal_queryset() - - def get(self, request, *args, **kwargs): - self.setup_problem_list(request) - return super().get(request, *args, **kwargs) - - def get_completed_problems(self): - return user_completed_ids(self.profile) if self.profile is not None else () - - def get_attempted_problems(self): - return user_attempted_ids(self.profile) if self.profile is not None else () - - @cached_property - def in_contest(self): - return False - - def get_context_data(self, **kwargs): - context = super(OrganizationProblems, self).get_context_data(**kwargs) - context["page_type"] = "problems" - context["show_contest_mode"] = False - return context - - -class OrganizationContestMixin( - LoginRequiredMixin, - TitleMixin, - OrganizationHomeView, -): - model = Contest - - def is_contest_editable(self, request, contest): - return contest.is_editable_by(request.user) or self.can_edit_organization( - self.organization - ) - - -class OrganizationContests( - OrganizationContestMixin, MemberOrganizationMixin, ContestList -): - template_name = "organization/contests.html" - - def get_queryset(self): - self.org_query = [self.organization_id] - self.hide_organization_contests = False - return super().get_queryset() - - def set_editable_contest(self, contest): - if not contest: - return False - contest.is_editable = self.is_contest_editable(self.request, contest) - - def get_context_data(self, **kwargs): - context = super(OrganizationContests, self).get_context_data(**kwargs) - context["page_type"] = "contests" - context.pop("organizations") - - if self.can_edit_organization(self.organization): - context["create_url"] = reverse( - "organization_contest_add", - args=[self.organization.id, self.organization.slug], - ) - - if self.current_tab == "active": - for participation in context["contests"]: - self.set_editable_contest(participation.contest) - else: - for contest in context["contests"]: - self.set_editable_contest(contest) - return context - - -class OrganizationSubmissions( - LoginRequiredMixin, MemberOrganizationMixin, SubmissionsListBase -): - template_name = "organization/submissions.html" - - @cached_property - def in_contest(self): - return False - - @cached_property - def contest(self): - return None - - def get_context_data(self, **kwargs): - context = super(OrganizationSubmissions, self).get_context_data(**kwargs) - # context["dynamic_update"] = context["page_obj"].number == 1 - # context["last_msg"] = event.last() - context["stats_update_interval"] = 3600 - context["page_type"] = "submissions" - context["page_prefix"] = None - context["page_suffix"] = suffix = ( - ("?" + self.request.GET.urlencode()) if self.request.GET else "" - ) - context["first_page_href"] = (self.first_page_href or ".") + suffix - - return context - - def get_content_title(self): - return format_html( - _('All submissions in {0}'), - self.organization, - reverse( - "organization_home", args=[self.organization.id, self.organization.slug] - ), - ) - - def get_title(self): - return _("Submissions in") + f" {self.organization}" - - -class OrganizationMembershipChange( - LoginRequiredMixin, OrganizationMixin, SingleObjectMixin, View -): - model = Organization - context_object_name = "organization" - +class OrganizationMembershipChange(LoginRequiredMixin, OrganizationMixin, SingleObjectMixin, View): def post(self, request, *args, **kwargs): org = self.get_object() response = self.handle(request, org, request.profile) @@ -557,42 +115,29 @@ class OrganizationMembershipChange( class JoinOrganization(OrganizationMembershipChange): def handle(self, request, org, profile): if profile.organizations.filter(id=org.id).exists(): - return generic_message( - request, - _("Joining group"), - _("You are already in the group."), - ) + return generic_message(request, _('Joining organization'), _('You are already in the organization.')) if not org.is_open: - return generic_message( - request, _("Joining group"), _("This group is not open.") - ) + return generic_message(request, _('Joining organization'), _('This organization is not open.')) max_orgs = settings.DMOJ_USER_MAX_ORGANIZATION_COUNT if profile.organizations.filter(is_open=True).count() >= max_orgs: return generic_message( - request, - _("Joining group"), - _("You may not be part of more than {count} public groups.").format( - count=max_orgs - ), + request, _('Joining organization'), + _('You may not be part of more than {count} public organizations.').format(count=max_orgs), ) profile.organizations.add(org) profile.save() - cache.delete(make_template_fragment_key("org_member_count", (org.id,))) + cache.delete(make_template_fragment_key('org_member_count', (org.id,))) class LeaveOrganization(OrganizationMembershipChange): def handle(self, request, org, profile): if not profile.organizations.filter(id=org.id).exists(): - return generic_message( - request, - _("Leaving group"), - _('You are not in "%s".') % org.short_name, - ) + return generic_message(request, _('Leaving organization'), _('You are not in "%s".') % org.short_name) profile.organizations.remove(org) - cache.delete(make_template_fragment_key("org_member_count", (org.id,))) + cache.delete(make_template_fragment_key('org_member_count', (org.id,))) class OrganizationRequestForm(Form): @@ -601,9 +146,9 @@ class OrganizationRequestForm(Form): class RequestJoinOrganization(LoginRequiredMixin, SingleObjectMixin, FormView): model = Organization - slug_field = "key" - slug_url_kwarg = "key" - template_name = "organization/requests/request.html" + slug_field = 'key' + slug_url_kwarg = 'key' + template_name = 'organization/requests/request.html' form_class = OrganizationRequestForm def dispatch(self, request, *args, **kwargs): @@ -614,94 +159,71 @@ class RequestJoinOrganization(LoginRequiredMixin, SingleObjectMixin, FormView): context = super(RequestJoinOrganization, self).get_context_data(**kwargs) if self.object.is_open: raise Http404() - context["title"] = _("Request to join %s") % self.object.name + context['title'] = _('Request to join %s') % self.object.name return context def form_valid(self, form): request = OrganizationRequest() request.organization = self.get_object() request.user = self.request.profile - request.reason = form.cleaned_data["reason"] - request.state = "P" + request.reason = form.cleaned_data['reason'] + request.state = 'P' request.save() - return HttpResponseRedirect( - reverse( - "request_organization_detail", - args=( - request.organization.id, - request.organization.slug, - request.id, - ), - ) - ) + return HttpResponseRedirect(reverse('request_organization_detail', args=( + request.organization.id, request.organization.slug, request.id, + ))) -class OrganizationRequestDetail( - LoginRequiredMixin, - TitleMixin, - OrganizationHomeView, - DetailView, -): +class OrganizationRequestDetail(LoginRequiredMixin, TitleMixin, DetailView): model = OrganizationRequest - template_name = "organization/requests/detail.html" - title = gettext_lazy("Join request detail") - pk_url_kwarg = "rpk" + template_name = 'organization/requests/detail.html' + title = gettext_lazy('Join request detail') + pk_url_kwarg = 'rpk' def get_object(self, queryset=None): object = super(OrganizationRequestDetail, self).get_object(queryset) profile = self.request.profile - if ( - object.user_id != profile.id - and not object.organization.admins.filter(id=profile.id).exists() - ): + if object.user_id != profile.id and not object.organization.admins.filter(id=profile.id).exists(): raise PermissionDenied() return object -OrganizationRequestFormSet = modelformset_factory( - OrganizationRequest, extra=0, fields=("state",), can_delete=True -) +OrganizationRequestFormSet = modelformset_factory(OrganizationRequest, extra=0, fields=('state',), can_delete=True) -class OrganizationRequestBaseView( - AdminOrganizationMixin, - DetailView, - OrganizationHomeView, - TitleMixin, - LoginRequiredMixin, - SingleObjectTemplateResponseMixin, - SingleObjectMixin, -): +class OrganizationRequestBaseView(LoginRequiredMixin, SingleObjectTemplateResponseMixin, SingleObjectMixin, View): model = Organization - slug_field = "key" - slug_url_kwarg = "key" + slug_field = 'key' + slug_url_kwarg = 'key' tab = None - def get_content_title(self): - return _("Manage join requests") + def get_object(self, queryset=None): + organization = super(OrganizationRequestBaseView, self).get_object(queryset) + if not (organization.admins.filter(id=self.request.profile.id).exists() or + organization.registrant_id == self.request.profile.id): + raise PermissionDenied() + return organization def get_context_data(self, **kwargs): context = super(OrganizationRequestBaseView, self).get_context_data(**kwargs) - context["title"] = _("Managing join requests for %s") % self.object.name - context["tab"] = self.tab + context['title'] = _('Managing join requests for %s') % self.object.name + context['tab'] = self.tab return context class OrganizationRequestView(OrganizationRequestBaseView): - template_name = "organization/requests/pending.html" - tab = "pending" + template_name = 'organization/requests/pending.html' + tab = 'pending' def get_context_data(self, **kwargs): context = super(OrganizationRequestView, self).get_context_data(**kwargs) - context["formset"] = self.formset + context['formset'] = self.formset return context def get(self, request, *args, **kwargs): self.object = self.get_object() self.formset = OrganizationRequestFormSet( - queryset=OrganizationRequest.objects.filter( - state="P", organization=self.object - ), + queryset=OrganizationRequest.objects.filter(state='P', organization=self.object), ) context = self.get_context_data(object=self.object) return self.render_to_response(context) @@ -712,43 +234,24 @@ class OrganizationRequestView(OrganizationRequestBaseView): if formset.is_valid(): if organization.slots is not None: deleted_set = set(formset.deleted_forms) - to_approve = sum( - form.cleaned_data["state"] == "A" - for form in formset.forms - if form not in deleted_set - ) + to_approve = sum(form.cleaned_data['state'] == 'A' for form in formset.forms if form not in deleted_set) can_add = organization.slots - organization.members.count() if to_approve > can_add: - messages.error( - request, - _( - "Your organization can only receive %d more members. " - "You cannot approve %d users." - ) - % (can_add, to_approve), - ) - return self.render_to_response( - self.get_context_data(object=organization) - ) + messages.error(request, _('Your organization can only receive %d more members. ' + 'You cannot approve %d users.') % (can_add, to_approve)) + return self.render_to_response(self.get_context_data(object=organization)) approved, rejected = 0, 0 for obj in formset.save(): - if obj.state == "A": + if obj.state == 'A': obj.user.organizations.add(obj.organization) approved += 1 - elif obj.state == "R": + elif obj.state == 'R': rejected += 1 - messages.success( - request, - ungettext("Approved %d user.", "Approved %d users.", approved) - % approved - + "\n" - + ungettext("Rejected %d user.", "Rejected %d users.", rejected) - % rejected, - ) - cache.delete( - make_template_fragment_key("org_member_count", (organization.id,)) - ) + messages.success(request, + ungettext('Approved %d user.', 'Approved %d users.', approved) % approved + '\n' + + ungettext('Rejected %d user.', 'Rejected %d users.', rejected) % rejected) + cache.delete(make_template_fragment_key('org_member_count', (organization.id,))) return HttpResponseRedirect(request.get_full_path()) return self.render_to_response(self.get_context_data(object=organization)) @@ -756,9 +259,9 @@ class OrganizationRequestView(OrganizationRequestBaseView): class OrganizationRequestLog(OrganizationRequestBaseView): - states = ("A", "R") - tab = "log" - template_name = "organization/requests/log.html" + states = ('A', 'R') + tab = 'log' + template_name = 'organization/requests/log.html' def get(self, request, *args, **kwargs): self.object = self.get_object() @@ -767,102 +270,17 @@ class OrganizationRequestLog(OrganizationRequestBaseView): def get_context_data(self, **kwargs): context = super(OrganizationRequestLog, self).get_context_data(**kwargs) - context["requests"] = self.object.requests.filter(state__in=self.states) + context['requests'] = self.object.requests.filter(state__in=self.states) return context -class AddOrganizationMember( - LoginRequiredMixin, - TitleMixin, - AdminOrganizationMixin, - OrganizationHomeView, - UpdateView, -): - template_name = "organization/add-member.html" - model = Organization - form_class = AddOrganizationMemberForm - - def get_title(self): - return _("Add member for %s") % self.object.name - - def get_object(self, queryset=None): - object = super(AddOrganizationMember, self).get_object() - if not self.can_edit_organization(object): - raise PermissionDenied() - return object - - def form_valid(self, form): - new_users = form.cleaned_data["new_users"] - self.object.members.add(*new_users) - link = reverse("organization_home", args=[self.object.id, self.object.slug]) - html = f'{self.object.name}' - make_notification(new_users, "Added to group", html, self.request.profile) - with revisions.create_revision(): - usernames = ", ".join([u.username for u in new_users]) - revisions.set_comment(_("Added members from site") + ": " + usernames) - revisions.set_user(self.request.user) - return super(AddOrganizationMember, self).form_valid(form) - - def get_success_url(self): - return reverse("organization_users", args=[self.object.id, self.object.slug]) - - -class KickUserWidgetView( - LoginRequiredMixin, AdminOrganizationMixin, SingleObjectMixin, View -): - model = Organization - - def post(self, request, *args, **kwargs): - organization = self.get_object() - try: - user = Profile.objects.get(id=request.POST.get("user", None)) - except Profile.DoesNotExist: - return generic_message( - request, - _("Can't kick user"), - _("The user you are trying to kick does not exist!"), - status=400, - ) - - if not organization.is_member(user): - return generic_message( - request, - _("Can't kick user"), - _("The user you are trying to kick is not in organization: %s.") - % organization.name, - status=400, - ) - - if organization.is_admin(user): - return generic_message( - request, - _("Can't kick user"), - _("The user you are trying to kick is an organization admin."), - status=400, - ) - - with revisions.create_revision(): - revisions.set_comment(_("Kicked member") + " " + user.username) - revisions.set_user(self.request.user) - organization.members.remove(user) - organization.save() - - return HttpResponseRedirect(organization.get_users_url()) - - -class EditOrganization( - LoginRequiredMixin, - TitleMixin, - AdminOrganizationMixin, - OrganizationHomeView, - UpdateView, -): - template_name = "organization/edit.html" +class EditOrganization(LoginRequiredMixin, TitleMixin, OrganizationMixin, UpdateView): + template_name = 'organization/edit.html' model = Organization form_class = EditOrganizationForm def get_title(self): - return _("Edit %s") % self.object.name + return _('Editing %s') % self.object.name def get_object(self, queryset=None): object = super(EditOrganization, self).get_object() @@ -872,373 +290,41 @@ class EditOrganization( def get_form(self, form_class=None): form = super(EditOrganization, self).get_form(form_class) - form.fields["admins"].queryset = Profile.objects.filter( - Q(organizations=self.object) | Q(admin_of=self.object) - ).distinct() + form.fields['admins'].queryset = \ + Profile.objects.filter(Q(organizations=self.object) | Q(admin_of=self.object)).distinct() return form def form_valid(self, form): - with revisions.create_revision(): - revisions.set_comment(_("Edited from site")) + with transaction.atomic(), revisions.create_revision(): + revisions.set_comment(_('Edited from site')) revisions.set_user(self.request.user) return super(EditOrganization, self).form_valid(form) - -class AddOrganization(LoginRequiredMixin, TitleMixin, CreateView): - template_name = "organization/add.html" - model = Organization - form_class = AddOrganizationForm - - def get_title(self): - return _("Create group") - - def get_form_kwargs(self): - kwargs = super(AddOrganization, self).get_form_kwargs() - kwargs["request"] = self.request - return kwargs - - def form_valid(self, form): - if ( - not self.request.user.is_staff - and Organization.objects.filter(registrant=self.request.profile).count() - >= settings.DMOJ_USER_MAX_ORGANIZATION_ADD - ): - return generic_message( - self.request, - _("Exceeded limit"), - _("You created too many groups. You can only create at most %d groups") - % settings.DMOJ_USER_MAX_ORGANIZATION_ADD, - status=400, - ) - with revisions.create_revision(): - revisions.set_comment(_("Added from site")) - revisions.set_user(self.request.user) - res = super(AddOrganization, self).form_valid(form) - self.object.admins.add(self.request.profile) - self.object.members.add(self.request.profile) - self.object.save() - return res - - -class AddOrganizationContest( - AdminOrganizationMixin, OrganizationContestMixin, CreateView -): - template_name = "organization/contest/add.html" - form_class = AddOrganizationContestForm - - def get_title(self): - return _("Add contest") - - def get_form_kwargs(self): - kwargs = super(AddOrganizationContest, self).get_form_kwargs() - kwargs["request"] = self.request - return kwargs - - def form_valid(self, form): - with revisions.create_revision(): - revisions.set_comment(_("Added from site")) - revisions.set_user(self.request.user) - - res = super(AddOrganizationContest, self).form_valid(form) - - self.object.organizations.add(self.organization) - self.object.is_organization_private = True - self.object.authors.add(self.request.profile) - self.object.save() - return res - - def get_success_url(self): - return reverse( - "organization_contest_edit", - args=[self.organization.id, self.organization.slug, self.object.key], - ) - - -class EditOrganizationContest( - OrganizationContestMixin, MemberOrganizationMixin, UpdateView -): - template_name = "organization/contest/edit.html" - form_class = EditOrganizationContestForm - - def setup_contest(self, request, *args, **kwargs): - contest_key = kwargs.get("contest", None) - if not contest_key: - raise Http404() - self.contest = get_object_or_404(Contest, key=contest_key) - if self.organization not in self.contest.organizations.all(): - raise Http404() - if not self.is_contest_editable(request, self.contest): - return generic_message( - self.request, - _("Permission denied"), - _("You are not allowed to edit this contest"), - status=400, - ) - - def get_form_kwargs(self): - kwargs = super(EditOrganizationContest, self).get_form_kwargs() - kwargs["org_id"] = self.organization.id - return kwargs - - def get(self, request, *args, **kwargs): - res = self.setup_contest(request, *args, **kwargs) - if res: - return res - return super().get(request, *args, **kwargs) - - def post(self, request, *args, **kwargs): - res = self.setup_contest(request, *args, **kwargs) - if res: - return res - problem_formset = self.get_problem_formset(True) - if problem_formset.is_valid(): - for problem_form in problem_formset: - if problem_form.cleaned_data.get("DELETE") and problem_form.instance.pk: - problem_form.instance.delete() - - for problem_form in problem_formset.save(commit=False): - if problem_form: - problem_form.contest = self.contest - problem_form.save() - - super().post(request, *args, **kwargs) - return HttpResponseRedirect( - reverse( - "organization_contest_edit", - args=( - self.organization_id, - self.organization.slug, - self.contest.key, - ), - ) - ) - - self.object = self.contest - return self.render_to_response( - self.get_context_data( - problems_form=problem_formset, - ) - ) - - def get_title(self): - return _("Edit %s") % self.contest.key - - def get_content_title(self): - href = reverse("contest_view", args=[self.contest.key]) - return mark_safe(_("Edit") + f' {self.contest.key}') - - def get_object(self): - return self.contest - - def form_valid(self, form): - with revisions.create_revision(): - revisions.set_comment(_("Edited from site")) - revisions.set_user(self.request.user) - res = super(EditOrganizationContest, self).form_valid(form) - self.object.organizations.add(self.organization) - self.object.is_organization_private = True - self.object.save() - - maybe_trigger_contest_rescore(form, self.object, True) - - return res - - def get_problem_formset(self, post=False): - return ContestProblemFormSet( - data=self.request.POST if post else None, - prefix="problems", - queryset=ContestProblem.objects.filter(contest=self.contest).order_by( - "order" - ), - ) - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - if "problems_form" not in context: - context["problems_form"] = self.get_problem_formset() - return context - - def get_success_url(self): - return self.request.path - - -class AddOrganizationBlog( - LoginRequiredMixin, - TitleMixin, - OrganizationHomeView, - MemberOrganizationMixin, - CreateView, -): - template_name = "organization/blog/add.html" - model = BlogPost - form_class = OrganizationBlogForm - - def get_form_class(self): - if self.can_edit_organization(self.organization): - return OrganizationAdminBlogForm - return OrganizationBlogForm - - def get_title(self): - return _("Add blog for %s") % self.organization.name - - def form_valid(self, form): - with revisions.create_revision(): - res = super(AddOrganizationBlog, self).form_valid(form) - self.object.is_organization_private = True - self.object.authors.add(self.request.profile) - self.object.slug = self.organization.slug + "-" + self.request.user.username - self.object.organizations.add(self.organization) - self.object.save() - - revisions.set_comment(_("Added from site")) - revisions.set_user(self.request.user) - - link = reverse( - "edit_organization_blog", - args=[self.organization.id, self.organization.slug, self.object.id], - ) - html = ( - f'{self.object.title} - {self.organization.name}' - ) - make_notification( - self.organization.admins.all(), "Add blog", html, self.request.profile - ) - return res - - def get_success_url(self): - return reverse( - "organization_home", args=[self.organization.id, self.organization.slug] - ) - - -class EditOrganizationBlog( - LoginRequiredMixin, - TitleMixin, - OrganizationHomeView, - AdminOrganizationMixin, - UpdateView, -): - template_name = "organization/blog/edit.html" - model = BlogPost - - def get_form_class(self): - if self.can_edit_organization(self.organization): - return OrganizationAdminBlogForm - return OrganizationBlogForm - - def setup_blog(self, request, *args, **kwargs): + def dispatch(self, request, *args, **kwargs): try: - self.blog_id = kwargs["blog_pk"] - self.blog = BlogPost.objects.get(id=self.blog_id) - if self.organization not in self.blog.organizations.all(): - raise Exception(_("This blog does not belong to this organization")) - if not self.request.profile.can_edit_organization(self.organization): - raise Exception(_("Not allowed to edit this blog")) - except Exception as e: - return generic_message( - request, - _("Permission denied"), - e, - ) + return super(EditOrganization, self).dispatch(request, *args, **kwargs) + except PermissionDenied: + return generic_message(request, _("Can't edit organization"), + _('You are not allowed to edit this organization.'), status=403) - def publish_blog(self, request, *args, **kwargs): - self.blog_id = kwargs["blog_pk"] - BlogPost.objects.filter(pk=self.blog_id).update(visible=True) - - def delete_blog(self, request, *args, **kwargs): - self.blog_id = kwargs["blog_pk"] - BlogPost.objects.get(pk=self.blog_id).delete() - - def get(self, request, *args, **kwargs): - res = self.setup_blog(request, *args, **kwargs) - if res: - return res - return super().get(request, *args, **kwargs) +class KickUserWidgetView(LoginRequiredMixin, OrganizationMixin, SingleObjectMixin, View): def post(self, request, *args, **kwargs): - res = self.setup_blog(request, *args, **kwargs) - if res: - return res - if request.POST["action"] == "Delete": - self.create_notification("Delete blog") - self.delete_blog(request, *args, **kwargs) - cur_url = reverse( - "organization_home", - args=(self.organization_id, self.organization.slug), - ) - return HttpResponseRedirect(cur_url) - elif request.POST["action"] == "Reject": - self.create_notification("Reject blog") - self.delete_blog(request, *args, **kwargs) - cur_url = reverse( - "organization_pending_blogs", - args=(self.organization_id, self.organization.slug), - ) - return HttpResponseRedirect(cur_url) - elif request.POST["action"] == "Approve": - self.create_notification("Approve blog") - self.publish_blog(request, *args, **kwargs) - cur_url = reverse( - "organization_pending_blogs", - args=(self.organization_id, self.organization.slug), - ) - return HttpResponseRedirect(cur_url) - else: - return super().post(request, *args, **kwargs) + organization = self.get_object() + if not self.can_edit_organization(organization): + return generic_message(request, _("Can't edit organization"), + _('You are not allowed to kick people from this organization.'), status=403) - def get_object(self): - return self.blog + try: + user = Profile.objects.get(id=request.POST.get('user', None)) + except Profile.DoesNotExist: + return generic_message(request, _("Can't kick user"), + _('The user you are trying to kick does not exist!'), status=400) - def get_title(self): - return _("Edit blog %s") % self.object.title + if not organization.members.filter(id=user.id).exists(): + return generic_message(request, _("Can't kick user"), + _('The user you are trying to kick is not in organization: %s.') % + organization.name, status=400) - def create_notification(self, action): - blog = BlogPost.objects.get(pk=self.blog_id) - link = reverse( - "edit_organization_blog", - args=[self.organization.id, self.organization.slug, self.blog_id], - ) - html = f'{blog.title} - {self.organization.name}' - to_users = (self.organization.admins.all() | blog.get_authors()).distinct() - make_notification(to_users, action, html, self.request.profile) - - def form_valid(self, form): - with revisions.create_revision(): - res = super(EditOrganizationBlog, self).form_valid(form) - revisions.set_comment(_("Edited from site")) - revisions.set_user(self.request.user) - self.create_notification("Edit blog") - return res - - def get_success_url(self): - return reverse( - "organization_home", args=[self.organization.id, self.organization.slug] - ) - - -class PendingBlogs( - LoginRequiredMixin, - TitleMixin, - MemberOrganizationMixin, - OrganizationHomeView, - ListView, -): - model = BlogPost - template_name = "organization/blog/pending.html" - context_object_name = "blogs" - - def get_queryset(self): - queryset = BlogPost.objects.filter( - organizations=self.organization, visible=False - ) - if not self.can_edit_organization(self.organization): - queryset = queryset.filter(authors=self.request.profile) - return queryset.order_by("publish_on") - - def get_title(self): - return _("Pending blogs in %s") % self.organization.name - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - context["org"] = self.organization - return context + organization.members.remove(user) + return HttpResponseRedirect(organization.get_users_url()) diff --git a/judge/views/pagevote.py b/judge/views/pagevote.py deleted file mode 100644 index a24680c..0000000 --- a/judge/views/pagevote.py +++ /dev/null @@ -1,105 +0,0 @@ -from django.contrib.auth.decorators import login_required -from django.db import IntegrityError -from django.db.models import F -from django.http import ( - Http404, - HttpResponse, - HttpResponseBadRequest, - HttpResponseForbidden, -) -from django.utils.translation import gettext as _ -from django.views.generic.base import TemplateResponseMixin -from django.views.generic.detail import SingleObjectMixin -from django.views.generic import View, ListView -from django_ratelimit.decorators import ratelimit -from django.conf import settings - -from judge.models.pagevote import PageVote, PageVoteVoter, dirty_pagevote - -__all__ = [ - "upvote_page", - "downvote_page", - "PageVoteDetailView", - "PageVoteListView", -] - - -@ratelimit(key="user", rate=settings.RL_VOTE) -@login_required -def vote_page(request, delta): - if abs(delta) != 1: - return HttpResponseBadRequest( - _("Messing around, are we?"), content_type="text/plain" - ) - - if request.method != "POST": - return HttpResponseForbidden() - - if "id" not in request.POST: - return HttpResponseBadRequest() - - if ( - not request.user.is_staff - and not request.profile.submission_set.filter( - points=F("problem__points") - ).exists() - ): - return HttpResponseBadRequest( - _("You must solve at least one problem before you can vote."), - content_type="text/plain", - ) - - try: - pagevote_id = int(request.POST["id"]) - except ValueError: - return HttpResponseBadRequest() - - try: - pagevote = PageVote.objects.get(id=pagevote_id) - except PageVote.DoesNotExist: - raise Http404() - - vote = PageVoteVoter() - vote.pagevote_id = pagevote_id - vote.voter = request.profile - vote.score = delta - - try: - vote.save() - except IntegrityError: - try: - vote = PageVoteVoter.objects.get( - pagevote_id=pagevote_id, voter=request.profile - ) - except PageVoteVoter.DoesNotExist: - raise Http404() - vote.delete() - PageVote.objects.filter(id=pagevote_id).update(score=F("score") - vote.score) - else: - PageVote.objects.filter(id=pagevote_id).update(score=F("score") + delta) - - dirty_pagevote(pagevote, request.profile) - - return HttpResponse("success", content_type="text/plain") - - -def upvote_page(request): - return vote_page(request, 1) - - -def downvote_page(request): - return vote_page(request, -1) - - -class PageVoteDetailView(TemplateResponseMixin, SingleObjectMixin, View): - pagevote_page = None - - def get_pagevote_page(self): - if self.pagevote_page is None: - raise NotImplementedError() - return self.pagevote_page - - def get_context_data(self, **kwargs): - context = super(PageVoteDetailView, self).get_context_data(**kwargs) - context["pagevote"] = self.object.get_or_create_pagevote() - return context diff --git a/judge/views/preview.py b/judge/views/preview.py index e4581d4..5fbd2e8 100644 --- a/judge/views/preview.py +++ b/judge/views/preview.py @@ -5,48 +5,46 @@ from django.views.generic.base import ContextMixin, TemplateResponseMixin, View class MarkdownPreviewView(TemplateResponseMixin, ContextMixin, View): def post(self, request, *args, **kwargs): try: - self.preview_data = data = request.POST["preview"] + self.preview_data = data = request.POST['preview'] except KeyError: - return HttpResponseBadRequest("No preview data specified.") + return HttpResponseBadRequest('No preview data specified.') - return self.render_to_response( - self.get_context_data( - preview_data=data, - ) - ) + return self.render_to_response(self.get_context_data( + preview_data=data, + )) class ProblemMarkdownPreviewView(MarkdownPreviewView): - template_name = "problem/preview.html" + template_name = 'problem/preview.html' class BlogMarkdownPreviewView(MarkdownPreviewView): - template_name = "blog/preview.html" + template_name = 'blog/preview.html' class ContestMarkdownPreviewView(MarkdownPreviewView): - template_name = "contest/preview.html" + template_name = 'contest/preview.html' class CommentMarkdownPreviewView(MarkdownPreviewView): - template_name = "comments/preview.html" + template_name = 'comments/preview.html' class ProfileMarkdownPreviewView(MarkdownPreviewView): - template_name = "user/preview.html" + template_name = 'user/preview.html' class OrganizationMarkdownPreviewView(MarkdownPreviewView): - template_name = "organization/preview.html" + template_name = 'organization/preview.html' class SolutionMarkdownPreviewView(MarkdownPreviewView): - template_name = "solution-preview.html" + template_name = 'solution-preview.html' class LicenseMarkdownPreviewView(MarkdownPreviewView): - template_name = "license-preview.html" + template_name = 'license-preview.html' class TicketMarkdownPreviewView(MarkdownPreviewView): - template_name = "ticket/preview.html" + template_name = 'ticket/preview.html' diff --git a/judge/views/problem.py b/judge/views/problem.py index ad57692..23e6e5a 100644 --- a/judge/views/problem.py +++ b/judge/views/problem.py @@ -1,38 +1,18 @@ import logging import os import shutil +from datetime import timedelta from operator import itemgetter from random import randrange -from copy import deepcopy -from django.core.cache import cache from django.conf import settings from django.contrib.auth.decorators import login_required from django.contrib.auth.mixins import PermissionRequiredMixin from django.core.exceptions import ObjectDoesNotExist, PermissionDenied from django.db import transaction -from django.db.models import ( - BooleanField, - Case, - CharField, - Count, - F, - FilteredRelation, - Prefetch, - Q, - When, - IntegerField, - Sum, -) -from django.db.models.functions import Coalesce +from django.db.models import Count, F, Prefetch, Q from django.db.utils import ProgrammingError -from django.http import ( - Http404, - HttpResponse, - HttpResponseForbidden, - HttpResponseRedirect, - JsonResponse, -) +from django.http import Http404, HttpResponse, HttpResponseBadRequest, HttpResponseForbidden, HttpResponseRedirect from django.shortcuts import get_object_or_404, render from django.template.loader import get_template from django.urls import reverse @@ -45,53 +25,19 @@ from django.views.generic import ListView, View from django.views.generic.base import TemplateResponseMixin from django.views.generic.detail import SingleObjectMixin -from judge.views.comment import CommentedDetailView -from judge.forms import ProblemCloneForm, ProblemSubmitForm, ProblemPointsVoteForm -from judge.models import ( - ContestProblem, - ContestSubmission, - Judge, - Language, - Problem, - ContestProblemClarification, - ProblemGroup, - ProblemTranslation, - ProblemType, - ProblemPointsVote, - RuntimeVersion, - Solution, - Submission, - SubmissionSource, - Organization, - Profile, - LanguageTemplate, - Contest, -) +from judge.comments import CommentedDetailView +from judge.forms import ProblemCloneForm, ProblemSubmitForm +from judge.models import ContestProblem, ContestSubmission, Judge, Language, Problem, ProblemGroup, \ + ProblemTranslation, ProblemType, RuntimeVersion, Solution, Submission, SubmissionSource, \ + TranslatedProblemForeignKeyQuerySet from judge.pdf_problems import DefaultPdfMaker, HAS_PDF from judge.utils.diggpaginator import DiggPaginator from judge.utils.opengraph import generate_opengraph -from judge.utils.problems import ( - contest_attempted_ids, - contest_completed_ids, - hot_problems, - user_attempted_ids, - user_completed_ids, - get_related_problems, - get_user_recommended_problems, - RecommendationType, -) +from judge.utils.problems import contest_attempted_ids, contest_completed_ids, hot_problems, user_attempted_ids, \ + user_completed_ids from judge.utils.strings import safe_float_or_none, safe_int_or_none from judge.utils.tickets import own_ticket_filter -from judge.utils.views import ( - QueryStringSortMixin, - SingleObjectFormView, - TitleMixin, - generic_message, -) -from judge.ml.collab_filter import CollabFilter -from judge.views.pagevote import PageVoteDetailView -from judge.views.bookmark import BookMarkDetailView -from judge.views.feed import FeedView +from judge.utils.views import QueryStringSortMixin, SingleObjectFormView, TitleMixin, generic_message def get_contest_problem(problem, profile): @@ -102,25 +48,14 @@ def get_contest_problem(problem, profile): def get_contest_submission_count(problem, profile, virtual): - return ( - profile.current_contest.submissions.exclude(submission__status__in=["IE"]) - .filter(problem__problem=problem, participation__virtual=virtual) - .count() - ) - - -def get_problems_in_organization(request, organization): - problem_list = ProblemList(request=request) - problem_list.setup_problem_list(request) - problem_list.org_query = [organization.id] - problems = problem_list.get_normal_queryset() - return problems + return profile.current_contest.submissions.exclude(submission__status__in=['IE']) \ + .filter(problem__problem__code=problem, participation__virtual=virtual).count() class ProblemMixin(object): model = Problem - slug_url_kwarg = "problem" - slug_field = "code" + slug_url_kwarg = 'problem' + slug_field = 'code' def get_object(self, queryset=None): problem = super(ProblemMixin, self).get_object(queryset) @@ -130,17 +65,13 @@ class ProblemMixin(object): def no_such_problem(self): code = self.kwargs.get(self.slug_url_kwarg, None) - return generic_message( - self.request, - _("No such problem"), - _('Could not find a problem with the code "%s".') % code, - status=404, - ) + return generic_message(self.request, _('No such problem'), + _('Could not find a problem with the code "%s".') % code, status=404) def get(self, request, *args, **kwargs): try: return super(ProblemMixin, self).get(request, *args, **kwargs) - except Http404 as e: + except Http404: return self.no_such_problem() @@ -157,25 +88,9 @@ class SolvedProblemMixin(object): else: return user_attempted_ids(self.profile) if self.profile is not None else () - def get_latest_attempted_problems(self, limit=None, queryset=None): - if self.in_contest or not self.profile: - return () - result = list(user_attempted_ids(self.profile).values()) - if queryset: - queryset_ids = set([i.code for i in queryset]) - result = filter(lambda i: i["code"] in queryset_ids, result) - result = sorted(result, key=lambda d: -d["last_submission"]) - if limit: - result = result[:limit] - return result - @cached_property def in_contest(self): - return ( - self.profile is not None - and self.profile.current_contest is not None - and self.request.in_contest_mode - ) + return self.profile is not None and self.profile.current_contest is not None @cached_property def contest(self): @@ -188,176 +103,120 @@ class SolvedProblemMixin(object): return self.request.profile -class ProblemSolution( - SolvedProblemMixin, - ProblemMixin, - TitleMixin, - CommentedDetailView, - PageVoteDetailView, - BookMarkDetailView, -): - context_object_name = "solution" - template_name = "problem/editorial.html" +class ProblemSolution(SolvedProblemMixin, ProblemMixin, TitleMixin, CommentedDetailView): + context_object_name = 'problem' + template_name = 'problem/editorial.html' def get_title(self): - return _("Editorial for {0}").format(self.problem.name) + return _('Editorial for {0}').format(self.object.name) def get_content_title(self): - return format_html( - _('Editorial for {0}'), - self.problem.name, - reverse("problem_detail", args=[self.problem.code]), - ) - - def get_object(self): - self.problem = super().get_object() - solution = get_object_or_404(Solution, problem=self.problem) - return solution + return format_html(_(u'Editorial for {0}'), self.object.name, + reverse('problem_detail', args=[self.object.code])) def get_context_data(self, **kwargs): context = super(ProblemSolution, self).get_context_data(**kwargs) - solution = self.get_object() - if ( - not solution.is_public or solution.publish_on > timezone.now() - ) and not self.request.user.has_perm("judge.see_private_solution"): - raise Http404() - context["problem"] = self.problem - context["has_solved_problem"] = self.problem.id in self.get_completed_problems() + solution = get_object_or_404(Solution, problem=self.object) + + if (not solution.is_public or solution.publish_on > timezone.now()) and \ + not self.request.user.has_perm('judge.see_private_solution') or \ + (self.request.user.is_authenticated and + self.request.profile.current_contest): + raise Http404() + context['solution'] = solution + context['has_solved_problem'] = self.object.id in self.get_completed_problems() return context + def get_comment_page(self): + return 's:' + self.object.code -class ProblemRaw( - ProblemMixin, TitleMixin, TemplateResponseMixin, SingleObjectMixin, View -): - context_object_name = "problem" - template_name = "problem/raw.html" + +class ProblemRaw(ProblemMixin, TitleMixin, TemplateResponseMixin, SingleObjectMixin, View): + context_object_name = 'problem' + template_name = 'problem/raw.html' def get_title(self): return self.object.name def get_context_data(self, **kwargs): context = super(ProblemRaw, self).get_context_data(**kwargs) - context["problem_name"] = self.object.name - context["url"] = self.request.build_absolute_uri() - context["description"] = self.object.description - if hasattr(self.object, "data_files"): - context["fileio_input"] = self.object.data_files.fileio_input - context["fileio_output"] = self.object.data_files.fileio_output - else: - context["fileio_input"] = None - context["fileio_output"] = None + context['problem_name'] = self.object.name + context['url'] = self.request.build_absolute_uri() + context['description'] = self.object.description return context def get(self, request, *args, **kwargs): self.object = self.get_object() with translation.override(settings.LANGUAGE_CODE): - return self.render_to_response( - self.get_context_data( - object=self.object, - ) - ) + return self.render_to_response(self.get_context_data( + object=self.object, + )) -class ProblemDetail( - ProblemMixin, - SolvedProblemMixin, - CommentedDetailView, - PageVoteDetailView, - BookMarkDetailView, -): - context_object_name = "problem" - template_name = "problem/problem.html" +class ProblemDetail(ProblemMixin, SolvedProblemMixin, CommentedDetailView): + context_object_name = 'problem' + template_name = 'problem/problem.html' + + def get_comment_page(self): + return 'p:%s' % self.object.code def get_context_data(self, **kwargs): context = super(ProblemDetail, self).get_context_data(**kwargs) user = self.request.user authed = user.is_authenticated - context["has_submissions"] = ( - authed - and Submission.objects.filter( - user=user.profile, problem=self.object - ).exists() - ) - contest_problem = ( - None - if not authed or user.profile.current_contest is None - else get_contest_problem(self.object, user.profile) - ) - context["contest_problem"] = contest_problem - + context['has_submissions'] = authed and Submission.objects.filter(user=user.profile, + problem=self.object).exists() + contest_problem = (None if not authed or user.profile.current_contest is None else + get_contest_problem(self.object, user.profile)) + context['contest_problem'] = contest_problem if contest_problem: - clarifications = contest_problem.clarifications - context["has_clarifications"] = clarifications.count() > 0 - context["clarifications"] = clarifications.order_by("-date") - context["submission_limit"] = contest_problem.max_submissions + clarifications = self.object.clarifications + context['has_clarifications'] = clarifications.count() > 0 + context['clarifications'] = clarifications.order_by('-date') + context['submission_limit'] = contest_problem.max_submissions if contest_problem.max_submissions: - context["submissions_left"] = max( - contest_problem.max_submissions - - get_contest_submission_count( - self.object, user.profile, user.profile.current_contest.virtual - ), - 0, - ) + context['submissions_left'] = max(contest_problem.max_submissions - + get_contest_submission_count(self.object.code, user.profile, + user.profile.current_contest.virtual), 0) - context["available_judges"] = Judge.objects.filter( - online=True, problems=self.object - ) - context["show_languages"] = ( - self.object.allowed_languages.count() != Language.objects.count() - ) - context["has_pdf_render"] = HAS_PDF - context["completed_problem_ids"] = self.get_completed_problems() - context["attempted_problems"] = self.get_attempted_problems() + context['available_judges'] = Judge.objects.filter(online=True, problems=self.object) + context['show_languages'] = self.object.allowed_languages.count() != Language.objects.count() + context['has_pdf_render'] = HAS_PDF + context['completed_problem_ids'] = self.get_completed_problems() + context['attempted_problems'] = self.get_attempted_problems() can_edit = self.object.is_editable_by(user) - context["can_edit_problem"] = can_edit + context['can_edit_problem'] = can_edit if user.is_authenticated: tickets = self.object.tickets if not can_edit: tickets = tickets.filter(own_ticket_filter(user.profile.id)) - context["has_tickets"] = tickets.exists() - context["num_open_tickets"] = ( - tickets.filter(is_open=True).values("id").distinct().count() - ) + context['has_tickets'] = tickets.exists() + context['num_open_tickets'] = tickets.filter(is_open=True).values('id').distinct().count() try: - context["editorial"] = Solution.objects.get(problem=self.object) + context['editorial'] = Solution.objects.get(problem=self.object) except ObjectDoesNotExist: pass try: - translation = self.object.translations.get( - language=self.request.LANGUAGE_CODE - ) + translation = self.object.translations.get(language=self.request.LANGUAGE_CODE) except ProblemTranslation.DoesNotExist: - context["title"] = self.object.name - context["language"] = settings.LANGUAGE_CODE - context["description"] = self.object.description - context["translated"] = False + context['title'] = self.object.name + context['language'] = settings.LANGUAGE_CODE + context['description'] = self.object.description + context['translated'] = False else: - context["title"] = translation.name - context["language"] = self.request.LANGUAGE_CODE - context["description"] = translation.description - context["translated"] = True + context['title'] = translation.name + context['language'] = self.request.LANGUAGE_CODE + context['description'] = translation.description + context['translated'] = True if not self.object.og_image or not self.object.summary: - metadata = generate_opengraph( - "generated-meta-problem:%s:%d" % (context["language"], self.object.id), - context["description"], - ) - context["meta_description"] = self.object.summary or metadata[0] - context["og_image"] = self.object.og_image or metadata[1] - if hasattr(self.object, "data_files"): - context["fileio_input"] = self.object.data_files.fileio_input - context["fileio_output"] = self.object.data_files.fileio_output - else: - context["fileio_input"] = None - context["fileio_output"] = None - if not self.in_contest and settings.ML_OUTPUT_PATH: - context["related_problems"] = get_related_problems( - self.profile, self.object - ) - + metadata = generate_opengraph('generated-meta-problem:%s:%d' % (context['language'], self.object.id), + context['description'], 'problem') + context['meta_description'] = self.object.summary or metadata[0] + context['og_image'] = self.object.og_image or metadata[1] return context @@ -366,14 +225,14 @@ class LatexError(Exception): class ProblemPdfView(ProblemMixin, SingleObjectMixin, View): - logger = logging.getLogger("judge.problem.pdf") + logger = logging.getLogger('judge.problem.pdf') languages = set(map(itemgetter(0), settings.LANGUAGES)) def get(self, request, *args, **kwargs): if not HAS_PDF: raise Http404() - language = kwargs.get("language", self.request.LANGUAGE_CODE) + language = kwargs.get('language', self.request.LANGUAGE_CODE) if language not in self.languages: raise Http404() @@ -383,151 +242,97 @@ class ProblemPdfView(ProblemMixin, SingleObjectMixin, View): except ProblemTranslation.DoesNotExist: trans = None - cache = os.path.join( - settings.DMOJ_PDF_PROBLEM_CACHE, "%s.%s.pdf" % (problem.code, language) - ) + cache = os.path.join(settings.DMOJ_PDF_PROBLEM_CACHE, '%s.%s.pdf' % (problem.code, language)) if not os.path.exists(cache): - self.logger.info("Rendering: %s.%s.pdf", problem.code, language) + self.logger.info('Rendering: %s.%s.pdf', problem.code, language) with DefaultPdfMaker() as maker, translation.override(language): problem_name = problem.name if trans is None else trans.name - maker.html = ( - get_template("problem/raw.html") - .render( - { - "problem": problem, - "problem_name": problem_name, - "description": problem.description - if trans is None - else trans.description, - "url": request.build_absolute_uri(), - } - ) - .replace('"//', '"https://') - .replace("'//", "'https://") - ) + maker.html = get_template('problem/raw.html').render({ + 'problem': problem, + 'problem_name': problem_name, + 'description': problem.description if trans is None else trans.description, + 'url': request.build_absolute_uri(), + 'math_engine': maker.math_engine, + }).replace('"//', '"https://').replace("'//", "'https://") maker.title = problem_name - assets = ["style.css"] + + assets = ['style.css', 'pygment-github.css'] + if maker.math_engine == 'jax': + assets.append('mathjax_config.js') for file in assets: maker.load(file, os.path.join(settings.DMOJ_RESOURCES, file)) maker.make() if not maker.success: - self.logger.error("Failed to render PDF for %s", problem.code) - return HttpResponse( - maker.log, status=500, content_type="text/plain" - ) + self.logger.error('Failed to render PDF for %s', problem.code) + return HttpResponse(maker.log, status=500, content_type='text/plain') shutil.move(maker.pdffile, cache) + response = HttpResponse() - if hasattr(settings, "DMOJ_PDF_PROBLEM_INTERNAL") and request.META.get( - "SERVER_SOFTWARE", "" - ).startswith("nginx/"): - response["X-Accel-Redirect"] = "%s/%s.%s.pdf" % ( - settings.DMOJ_PDF_PROBLEM_INTERNAL, - problem.code, - language, - ) + if hasattr(settings, 'DMOJ_PDF_PROBLEM_INTERNAL') and \ + request.META.get('SERVER_SOFTWARE', '').startswith('nginx/'): + response['X-Accel-Redirect'] = '%s/%s.%s.pdf' % (settings.DMOJ_PDF_PROBLEM_INTERNAL, problem.code, language) else: - with open(cache, "rb") as f: + with open(cache, 'rb') as f: response.content = f.read() - response["Content-Type"] = "application/pdf" - response["Content-Disposition"] = "inline; filename=%s.%s.pdf" % ( - problem.code, - language, - ) - return response - - -class ProblemPdfDescriptionView(ProblemMixin, SingleObjectMixin, View): - def get(self, request, *args, **kwargs): - problem = self.get_object() - if not problem.pdf_description: - raise Http404() - response = HttpResponse() - # if request.META.get("SERVER_SOFTWARE", "").startswith("nginx/"): - # response["X-Accel-Redirect"] = problem.pdf_description.path - # else: - with open(problem.pdf_description.path, "rb") as f: - response.content = f.read() - - response["Content-Type"] = "application/pdf" - response["Content-Disposition"] = "inline; filename=%s.pdf" % (problem.code,) + response['Content-Type'] = 'application/pdf' + response['Content-Disposition'] = 'inline; filename=%s.%s.pdf' % (problem.code, language) return response class ProblemList(QueryStringSortMixin, TitleMixin, SolvedProblemMixin, ListView): model = Problem - title = gettext_lazy("Problems") - context_object_name = "problems" - template_name = "problem/list.html" + title = gettext_lazy('Problems') + context_object_name = 'problems' + template_name = 'problem/list.html' paginate_by = 50 - sql_sort = frozenset(("date", "points", "ac_rate", "user_count", "code")) - manual_sort = frozenset(("name", "group", "solved", "type")) + sql_sort = frozenset(('date', 'points', 'ac_rate', 'user_count', 'code')) + manual_sort = frozenset(('name', 'group', 'solved', 'type')) all_sorts = sql_sort | manual_sort - default_desc = frozenset(("date", "points", "ac_rate", "user_count")) - first_page_href = None - filter_organization = False + default_desc = frozenset(('date', 'points', 'ac_rate', 'user_count')) + default_sort = '-date' - def get_default_sort_order(self, request): - if "search" in request.GET and settings.ENABLE_FTS: - return "-relevance" - return "-date" - - def get_paginator( - self, queryset, per_page, orphans=0, allow_empty_first_page=True, **kwargs - ): - paginator = DiggPaginator( - queryset, - per_page, - body=6, - padding=2, - orphans=orphans, - allow_empty_first_page=allow_empty_first_page, - count=queryset.values("pk").count() if not self.in_contest else None, - **kwargs, - ) + def get_paginator(self, queryset, per_page, orphans=0, + allow_empty_first_page=True, **kwargs): + paginator = DiggPaginator(queryset, per_page, body=6, padding=2, orphans=orphans, + allow_empty_first_page=allow_empty_first_page, **kwargs) if not self.in_contest: + # Get the number of pages and then add in this magic. + # noinspection PyStatementEffect + paginator.num_pages + queryset = queryset.add_i18n_name(self.request.LANGUAGE_CODE) - queryset = self.sort_queryset(queryset) + sort_key = self.order.lstrip('-') + if sort_key in self.sql_sort: + queryset = queryset.order_by(self.order) + elif sort_key == 'name': + queryset = queryset.order_by(self.order.replace('name', 'i18n_name')) + elif sort_key == 'group': + queryset = queryset.order_by(self.order + '__name') + elif sort_key == 'solved': + if self.request.user.is_authenticated: + profile = self.request.profile + solved = user_completed_ids(profile) + attempted = user_attempted_ids(profile) + + def _solved_sort_order(problem): + if problem.id in solved: + return 1 + if problem.id in attempted: + return 0 + return -1 + + queryset = list(queryset) + queryset.sort(key=_solved_sort_order, reverse=self.order.startswith('-')) + elif sort_key == 'type': + if self.show_types: + queryset = list(queryset) + queryset.sort(key=lambda problem: problem.types_list[0] if problem.types_list else '', + reverse=self.order.startswith('-')) paginator.object_list = queryset return paginator - def sort_queryset(self, queryset): - sort_key = self.order.lstrip("-") - if sort_key in self.sql_sort: - queryset = queryset.order_by(self.order) - elif sort_key == "name": - queryset = queryset.order_by(self.order.replace("name", "i18n_name")) - elif sort_key == "group": - queryset = queryset.order_by(self.order + "__name") - elif sort_key == "solved": - if self.request.user.is_authenticated: - profile = self.request.profile - solved = user_completed_ids(profile) - attempted = user_attempted_ids(profile) - - def _solved_sort_order(problem): - if problem.id in solved: - return 1 - if problem.id in attempted: - return 0 - return -1 - - queryset = list(queryset) - queryset.sort( - key=_solved_sort_order, reverse=self.order.startswith("-") - ) - elif sort_key == "type": - if self.show_types: - queryset = list(queryset) - queryset.sort( - key=lambda problem: problem.types_list[0] - if problem.types_list - else "", - reverse=self.order.startswith("-"), - ) - return queryset - @cached_property def profile(self): if not self.request.user.is_authenticated: @@ -535,126 +340,60 @@ class ProblemList(QueryStringSortMixin, TitleMixin, SolvedProblemMixin, ListView return self.request.profile def get_contest_queryset(self): - queryset = ( - self.profile.current_contest.contest.contest_problems.select_related( - "problem__group" - ) - .defer("problem__description") - .order_by("problem__code") - .annotate(user_count=Count("submission__participation", distinct=True)) - .annotate( - i18n_translation=FilteredRelation( - "problem__translations", - condition=Q( - problem__translations__language=self.request.LANGUAGE_CODE - ), - ) - ) - .annotate( - i18n_name=Coalesce( - F("i18n_translation__name"), - F("problem__name"), - output_field=CharField(), - ) - ) - .order_by("order") - ) - return [ - { - "id": p["problem_id"], - "code": p["problem__code"], - "name": p["problem__name"], - "i18n_name": p["i18n_name"], - "group": {"full_name": p["problem__group__full_name"]}, - "points": p["points"], - "partial": p["partial"], - "user_count": p["user_count"], - } - for p in queryset.values( - "problem_id", - "problem__code", - "problem__name", - "i18n_name", - "problem__group__full_name", - "points", - "partial", - "user_count", - ) - ] - - def get_org_query(self, query): - if not self.profile: - return [] - return [ - i - for i in query - if i in self.profile.organizations.values_list("id", flat=True) - ][:3] + queryset = self.profile.current_contest.contest.contest_problems.select_related('problem__group') \ + .defer('problem__description').order_by('problem__code') \ + .annotate(user_count=Count('submission__participation', distinct=True)) \ + .order_by('order') + queryset = TranslatedProblemForeignKeyQuerySet.add_problem_i18n_name(queryset, 'i18n_name', + self.request.LANGUAGE_CODE, + 'problem__name') + return [{ + 'id': p['problem_id'], + 'code': p['problem__code'], + 'name': p['problem__name'], + 'i18n_name': p['i18n_name'], + 'group': {'full_name': p['problem__group__full_name']}, + 'points': p['points'], + 'partial': p['partial'], + 'user_count': p['user_count'], + } for p in queryset.values('problem_id', 'problem__code', 'problem__name', 'i18n_name', + 'problem__group__full_name', 'points', 'partial', 'user_count')] def get_normal_queryset(self): - queryset = Problem.get_visible_problems(self.request.user) - queryset = queryset.select_related("group") + filter = Q(is_public=True) + if self.profile is not None: + filter |= Q(authors=self.profile) + filter |= Q(curators=self.profile) + filter |= Q(testers=self.profile) + queryset = Problem.objects.filter(filter).select_related('group').defer('description') + if not self.request.user.has_perm('see_organization_problem'): + filter = Q(is_organization_private=False) + if self.profile is not None: + filter |= Q(organizations__in=self.profile.organizations.all()) + queryset = queryset.filter(filter) if self.profile is not None and self.hide_solved: - solved_problems = self.get_completed_problems() - queryset = queryset.exclude(id__in=solved_problems) - if not self.org_query and self.request.organization: - self.org_query = [self.request.organization.id] - if self.org_query: - self.org_query = self.get_org_query(self.org_query) - contest_problems = ( - Contest.objects.filter(organizations__in=self.org_query) - .select_related("problems") - .values_list("contest_problems__problem__id") - .distinct() - ) - queryset = queryset.filter( - Q(organizations__in=self.org_query) | Q(id__in=contest_problems) - ) - if self.author_query: - queryset = queryset.filter(authors__in=self.author_query) + queryset = queryset.exclude(id__in=Submission.objects.filter(user=self.profile, points=F('problem__points')) + .values_list('problem__id', flat=True)) if self.show_types: - queryset = queryset.prefetch_related("types") + queryset = queryset.prefetch_related('types') if self.category is not None: queryset = queryset.filter(group__id=self.category) if self.selected_types: queryset = queryset.filter(types__in=self.selected_types) - if "search" in self.request.GET: - self.search_query = query = " ".join( - self.request.GET.getlist("search") - ).strip() + if 'search' in self.request.GET: + self.search_query = query = ' '.join(self.request.GET.getlist('search')).strip() if query: - substr_queryset = queryset.filter( - Q(code__icontains=query) - | Q(name__icontains=query) - | Q( - translations__name__icontains=query, - translations__language=self.request.LANGUAGE_CODE, - ) - ) - if settings.ENABLE_FTS: - queryset = ( - queryset.search(query, queryset.BOOLEAN).extra( - order_by=["-relevance"] - ) - | substr_queryset - ) + if settings.ENABLE_FTS and self.full_text: + queryset = queryset.search(query, queryset.BOOLEAN).extra(order_by=['-relevance']) else: - queryset = substr_queryset + queryset = queryset.filter( + Q(code__icontains=query) | Q(name__icontains=query) | + Q(translations__name__icontains=query, translations__language=self.request.LANGUAGE_CODE)) self.prepoint_queryset = queryset if self.point_start is not None: queryset = queryset.filter(points__gte=self.point_start) if self.point_end is not None: queryset = queryset.filter(points__lte=self.point_end) - - queryset = queryset.annotate( - has_public_editorial=Sum( - Case( - When(solution__is_public=True, then=1), - default=0, - output_field=IntegerField(), - ) - ) - ) return queryset.distinct() def get_queryset(self): @@ -665,148 +404,77 @@ class ProblemList(QueryStringSortMixin, TitleMixin, SolvedProblemMixin, ListView def get_context_data(self, **kwargs): context = super(ProblemList, self).get_context_data(**kwargs) - - if self.request.organization: - self.filter_organization = True - context["hide_solved"] = 0 if self.in_contest else int(self.hide_solved) - context["show_types"] = 0 if self.in_contest else int(self.show_types) - context["full_text"] = 0 if self.in_contest else int(self.full_text) - context["show_editorial"] = 0 if self.in_contest else int(self.show_editorial) - context["show_solved_only"] = ( - 0 if self.in_contest else int(self.show_solved_only) - ) - - if self.request.profile: - context["organizations"] = self.request.profile.organizations.all() - context["category"] = self.category - context["categories"] = ProblemGroup.objects.all() + context['hide_solved'] = 0 if self.in_contest else int(self.hide_solved) + context['show_types'] = 0 if self.in_contest else int(self.show_types) + context['full_text'] = 0 if self.in_contest else int(self.full_text) + context['category'] = self.category + context['categories'] = ProblemGroup.objects.all() if self.show_types: - context["selected_types"] = self.selected_types - context["problem_types"] = ProblemType.objects.all() - context["has_fts"] = settings.ENABLE_FTS - context["org_query"] = self.org_query - context["author_query"] = Profile.objects.filter(id__in=self.author_query) - context["search_query"] = self.search_query - context["completed_problem_ids"] = self.get_completed_problems() - context["attempted_problems"] = self.get_attempted_problems() - context["last_attempted_problems"] = self.get_latest_attempted_problems( - 15, context["problems"] if self.filter_organization else None - ) - context["page_type"] = "list" + context['selected_types'] = self.selected_types + context['problem_types'] = ProblemType.objects.all() + context['has_fts'] = settings.ENABLE_FTS + context['search_query'] = self.search_query + context['completed_problem_ids'] = self.get_completed_problems() + context['attempted_problems'] = self.get_attempted_problems() + context.update(self.get_sort_paginate_context()) if not self.in_contest: context.update(self.get_sort_context()) - ( - context["point_start"], - context["point_end"], - context["point_values"], - ) = self.get_noui_slider_points() + context['hot_problems'] = hot_problems(timedelta(days=1), 7) + context['point_start'], context['point_end'], context['point_values'] = self.get_noui_slider_points() else: - context["point_start"], context["point_end"], context["point_values"] = ( - 0, - 0, - {}, - ) - context["hide_contest_scoreboard"] = self.contest.scoreboard_visibility in ( - self.contest.SCOREBOARD_AFTER_CONTEST, - self.contest.SCOREBOARD_AFTER_PARTICIPATION, - ) - context["has_clarifications"] = False - - if self.request.user.is_authenticated: - participation = self.request.profile.current_contest - if participation: - clarifications = ContestProblemClarification.objects.filter( - problem__in=participation.contest.contest_problems.all() - ) - context["has_clarifications"] = clarifications.count() > 0 - context["clarifications"] = clarifications.order_by("-date") - if participation.contest.is_editable_by(self.request.user): - context["can_edit_contest"] = True - - context["page_prefix"] = None - context["page_suffix"] = suffix = ( - ("?" + self.request.GET.urlencode()) if self.request.GET else "" - ) - context["first_page_href"] = (self.first_page_href or ".") + suffix - context["has_show_editorial_option"] = True - context["show_contest_mode"] = self.request.in_contest_mode + context['hot_problems'] = None + context['point_start'], context['point_end'], context['point_values'] = 0, 0, {} + context['hide_contest_scoreboard'] = self.contest.hide_scoreboard return context def get_noui_slider_points(self): - points = sorted( - self.prepoint_queryset.values_list("points", flat=True).distinct() - ) + points = sorted(self.prepoint_queryset.values_list('points', flat=True).distinct()) if not points: return 0, 0, {} if len(points) == 1: - return ( - points[0], - points[0], - { - "min": points[0] - 1, - "max": points[0] + 1, - }, - ) + return points[0], points[0], { + 'min': points[0] - 1, + 'max': points[0] + 1, + } start, end = points[0], points[-1] if self.point_start is not None: start = self.point_start if self.point_end is not None: end = self.point_end - points_map = {0.0: "min", 1.0: "max"} + points_map = {0.0: 'min', 1.0: 'max'} size = len(points) - 1 - return ( - start, - end, - { - points_map.get(i / size, "%.2f%%" % (100 * i / size,)): j - for i, j in enumerate(points) - }, - ) + return start, end, {points_map.get(i / size, '%.2f%%' % (100 * i / size,)): j for i, j in enumerate(points)} def GET_with_session(self, request, key): - if not request.GET.get(key): + if not request.GET: return request.session.get(key, False) - return request.GET.get(key, None) == "1" + return request.GET.get(key, None) == '1' def setup_problem_list(self, request): - self.hide_solved = self.GET_with_session(request, "hide_solved") - self.show_types = self.GET_with_session(request, "show_types") - self.full_text = self.GET_with_session(request, "full_text") - self.show_editorial = self.GET_with_session(request, "show_editorial") - self.show_solved_only = self.GET_with_session(request, "show_solved_only") + self.hide_solved = self.GET_with_session(request, 'hide_solved') + self.show_types = self.GET_with_session(request, 'show_types') + self.full_text = self.GET_with_session(request, 'full_text') self.search_query = None self.category = None - self.org_query = [] - self.author_query = [] self.selected_types = [] # This actually copies into the instance dictionary... self.all_sorts = set(self.all_sorts) if not self.show_types: - self.all_sorts.discard("type") + self.all_sorts.discard('type') - self.category = safe_int_or_none(request.GET.get("category")) - if "type" in request.GET: + self.category = safe_int_or_none(request.GET.get('category')) + if 'type' in request.GET: try: - self.selected_types = list(map(int, request.GET.getlist("type"))) - except ValueError: - pass - if "orgs" in request.GET: - try: - self.org_query = list(map(int, request.GET.getlist("orgs"))) - except ValueError: - pass - if "authors" in request.GET: - try: - self.author_query = list(map(int, request.GET.getlist("authors"))) + self.selected_types = list(map(int, request.GET.getlist('type'))) except ValueError: pass - self.point_start = safe_float_or_none(request.GET.get("point_start")) - self.point_end = safe_float_or_none(request.GET.get("point_end")) + self.point_start = safe_float_or_none(request.GET.get('point_start')) + self.point_end = safe_float_or_none(request.GET.get('point_end')) def get(self, request, *args, **kwargs): self.setup_problem_list(request) @@ -814,344 +482,136 @@ class ProblemList(QueryStringSortMixin, TitleMixin, SolvedProblemMixin, ListView try: return super(ProblemList, self).get(request, *args, **kwargs) except ProgrammingError as e: - return generic_message(request, "FTS syntax error", e.args[1], status=400) + return generic_message(request, 'FTS syntax error', e.args[1], status=400) def post(self, request, *args, **kwargs): - to_update = ( - "hide_solved", - "show_types", - "full_text", - "show_editorial", - "show_solved_only", - ) + to_update = ('hide_solved', 'show_types', 'full_text') for key in to_update: if key in request.GET: - val = request.GET.get(key) == "1" + val = request.GET.get(key) == '1' request.session[key] = val else: - request.session[key] = False + request.session.pop(key, None) return HttpResponseRedirect(request.get_full_path()) -class ProblemFeed(ProblemList, FeedView): - model = Problem - context_object_name = "problems" - template_name = "problem/feed.html" - feed_content_template_name = "problem/feed/items.html" - paginate_by = 4 - title = _("Problem feed") - feed_type = None - - def get_recommended_problem_ids(self, queryset): - user_id = self.request.profile.id - problem_ids = queryset.values_list("id", flat=True) - rec_types = [ - RecommendationType.CF_DOT, - RecommendationType.CF_COSINE, - RecommendationType.CF_TIME_DOT, - RecommendationType.CF_TIME_COSINE, - RecommendationType.HOT_PROBLEM, - ] - limits = [100, 100, 100, 100, 20] - shuffle = True - - allow_debug_type = ( - self.request.user.is_impersonate or self.request.user.is_superuser - ) - if allow_debug_type and "debug_type" in self.request.GET: - try: - debug_type = int(self.request.GET.get("debug_type")) - except ValueError: - raise Http404() - rec_types = [debug_type] - limits = [100] - shuffle = False - - return get_user_recommended_problems( - user_id, problem_ids, rec_types, limits, shuffle - ) - - def get_queryset(self): - if self.feed_type == "volunteer": - self.hide_solved = 0 - self.show_types = 1 - queryset = super(ProblemFeed, self).get_queryset() - - user = self.request.profile - - if self.feed_type == "new": - return queryset.order_by("-date").add_i18n_name(self.request.LANGUAGE_CODE) - elif user and self.feed_type == "volunteer": - voted_problems = ( - user.volunteer_problem_votes.values_list("problem", flat=True) - if not bool(self.search_query) - else [] - ) - if self.show_solved_only: - queryset = queryset.filter( - id__in=Submission.objects.filter( - user=self.profile, points=F("problem__points") - ).values_list("problem__id", flat=True) - ) - return ( - queryset.exclude(id__in=voted_problems) - .order_by("?") - .add_i18n_name(self.request.LANGUAGE_CODE) - ) - if "search" in self.request.GET: - return queryset.add_i18n_name(self.request.LANGUAGE_CODE) - if not settings.ML_OUTPUT_PATH or not user: - return queryset.order_by("?").add_i18n_name(self.request.LANGUAGE_CODE) - - q = self.get_recommended_problem_ids(queryset) - - queryset = Problem.objects.filter(id__in=q) - queryset = queryset.add_i18n_name(self.request.LANGUAGE_CODE) - - # Reorder results from database to correct positions - res = [None for _ in range(len(q))] - position_in_q = {i: idx for idx, i in enumerate(q)} - for problem in queryset: - res[position_in_q[problem.id]] = problem - return res - - def get_feed_context(self, object_list): - return { - "completed_problem_ids": self.get_completed_problems(), - "attempted_problems": self.get_attempted_problems(), - "show_types": self.show_types, - } - - def get_context_data(self, **kwargs): - context = super(ProblemFeed, self).get_context_data(**kwargs) - context["page_type"] = "feed" - context["title"] = self.title - context["feed_type"] = self.feed_type - context["has_show_editorial_option"] = False - - return context - - def get(self, request, *args, **kwargs): - if request.in_contest_mode: - return HttpResponseRedirect(reverse("problem_list")) - return super(ProblemFeed, self).get(request, *args, **kwargs) - - class LanguageTemplateAjax(View): def get(self, request, *args, **kwargs): try: - problem = request.GET.get("problem", None) - lang_id = int(request.GET.get("id", 0)) - res = None - if problem: - try: - res = LanguageTemplate.objects.get( - language__id=lang_id, problem__id=problem - ).source - except ObjectDoesNotExist: - pass - if not res: - res = get_object_or_404(Language, id=lang_id).template + language = get_object_or_404(Language, id=int(request.GET.get('id', 0))) except ValueError: raise Http404() - return HttpResponse(res, content_type="text/plain") + return HttpResponse(language.template, content_type='text/plain') class RandomProblem(ProblemList): def get(self, request, *args, **kwargs): self.setup_problem_list(request) - - try: - return super().get(request, *args, **kwargs) - except ProgrammingError as e: - return generic_message(request, "FTS syntax error", e.args[1], status=400) - if self.in_contest: raise Http404() queryset = self.get_normal_queryset() count = queryset.count() if not count: - return HttpResponseRedirect( - "%s%s%s" - % ( - reverse("problem_list"), - request.META["QUERY_STRING"] and "?", - request.META["QUERY_STRING"], - ) - ) + return HttpResponseRedirect('%s%s%s' % (reverse('problem_list'), request.META['QUERY_STRING'] and '?', + request.META['QUERY_STRING'])) return HttpResponseRedirect(queryset[randrange(count)].get_absolute_url()) -user_logger = logging.getLogger("judge.user") - - -def last_nth_submitted_date_in_contest(profile, contest, n): - submissions = Submission.objects.filter( - user=profile, contest_object=contest - ).order_by("-id")[:n] - if submissions.count() >= n: - return submissions[n - 1].date - return None +user_logger = logging.getLogger('judge.user') @login_required -def problem_submit(request, problem, submission=None): - if ( - submission is not None - and not request.user.has_perm("judge.resubmit_other") - and get_object_or_404(Submission, id=int(submission)).user.user != request.user - ): +def problem_submit(request, problem=None, submission=None): + if submission is not None and not request.user.has_perm('judge.resubmit_other') and \ + get_object_or_404(Submission, id=int(submission)).user.user != request.user: raise PermissionDenied() profile = request.profile - problem = get_object_or_404(Problem, code=problem) - if not problem.is_accessible_by(request.user): - if request.method == "POST": - user_logger.info( - "Naughty user %s wants to submit to %s without permission", - request.user.username, - problem.code, - ) - return HttpResponseForbidden("

Not allowed to submit. Try later.

") - raise Http404() - - if problem.is_editable_by(request.user): - judge_choices = tuple( - Judge.objects.filter(online=True, problems=problem).values_list( - "name", "name" - ) - ) - else: - judge_choices = () - - if request.method == "POST": - form = ProblemSubmitForm( - request.POST, - request.FILES, - judge_choices=judge_choices, - instance=Submission(user=profile, problem=problem), - request=request, - problem=problem, - ) + if request.method == 'POST': + form = ProblemSubmitForm(request.POST, instance=Submission(user=profile)) if form.is_valid(): - if ( - not request.user.has_perm("judge.spam_submission") - and Submission.objects.filter(user=profile, was_rejudged=False) - .exclude(status__in=["D", "IE", "CE", "AB"]) - .count() - >= settings.DMOJ_SUBMISSION_LIMIT - ): - return HttpResponse( - _("

You have submitted too many submissions.

"), status=429 - ) - if not problem.allowed_languages.filter( - id=form.cleaned_data["language"].id - ).exists(): + if (not request.user.has_perm('judge.spam_submission') and + Submission.objects.filter(user=profile, was_rejudged=False) + .exclude(status__in=['D', 'IE', 'CE', 'AB']).count() >= settings.DMOJ_SUBMISSION_LIMIT): + return HttpResponse('

You submitted too many submissions.

', status=429) + if not form.cleaned_data['problem'].allowed_languages.filter( + id=form.cleaned_data['language'].id).exists(): raise PermissionDenied() - if ( - not request.user.is_superuser - and problem.banned_users.filter(id=profile.id).exists() - ): - return generic_message( - request, - _("Banned from submitting"), - _( - "You have been declared persona non grata for this problem. " - "You are permanently barred from submitting this problem." - ), - ) + if not form.cleaned_data['problem'].is_accessible_by(request.user): + user_logger.info('Naughty user %s wants to submit to %s without permission', + request.user.username, form.cleaned_data['problem'].code) + return HttpResponseForbidden('

Do you want me to ban you?

') + if not request.user.is_superuser and form.cleaned_data['problem'].banned_users.filter( + id=profile.id).exists(): + return generic_message(request, _('Banned from submitting'), + _('You have been declared persona non grata for this problem. ' + 'You are permanently barred from submitting this problem.')) with transaction.atomic(): if profile.current_contest is not None: - contest = profile.current_contest.contest contest_id = profile.current_contest.contest_id - rate_limit = contest.rate_limit - - if rate_limit: - t = last_nth_submitted_date_in_contest( - profile, contest, rate_limit - ) - if t is not None and timezone.now() - t < timezone.timedelta( - minutes=1 - ): - return HttpResponse( - _("

You have submitted too many submissions.

"), - status=429, - ) - try: - contest_problem = problem.contests.get(contest_id=contest_id) + contest_problem = form.cleaned_data['problem'].contests.get(contest_id=contest_id) except ContestProblem.DoesNotExist: model = form.save() else: max_subs = contest_problem.max_submissions - if ( - max_subs - and get_contest_submission_count( - problem, profile, profile.current_contest.virtual - ) - >= max_subs - ): - return generic_message( - request, - _("Too many submissions"), - _( - "You have exceeded the submission limit for this problem." - ), - ) + if max_subs and get_contest_submission_count(problem, profile, + profile.current_contest.virtual) >= max_subs: + return generic_message(request, _('Too many submissions'), + _('You have exceeded the submission limit for this problem.')) model = form.save() model.contest_object_id = contest_id - contest = ContestSubmission( - submission=model, - problem=contest_problem, - participation=profile.current_contest, - ) + contest = ContestSubmission(submission=model, problem=contest_problem, + participation=profile.current_contest) contest.save() else: model = form.save() # Create the SubmissionSource object - source = SubmissionSource( - submission=model, source=form.cleaned_data["source"] - ) + source = SubmissionSource(submission=model, source=form.cleaned_data['source']) source.save() profile.update_contest() # Save a query model.source = source - model.judge(rejudge=False, judge_id=form.cleaned_data["judge"]) + model.judge(rejudge=False) - return HttpResponseRedirect( - reverse("submission_status", args=[str(model.id)]) - ) + return HttpResponseRedirect(reverse('submission_status', args=[str(model.id)])) else: form_data = form.cleaned_data if submission is not None: sub = get_object_or_404(Submission, id=int(submission)) + + if 'problem' not in form_data: + return HttpResponseBadRequest() else: - initial = {"language": profile.language} + initial = {'language': profile.language} + if problem is not None: + initial['problem'] = get_object_or_404(Problem, code=problem) + problem_object = initial['problem'] + if not problem_object.is_accessible_by(request.user): + raise Http404() if submission is not None: try: - sub = get_object_or_404( - Submission.objects.select_related("source", "language"), - id=int(submission), - ) - initial["source"] = sub.source.source - initial["language"] = sub.language + sub = get_object_or_404(Submission.objects.select_related('source', 'language'), id=int(submission)) + initial['source'] = sub.source.source + initial['language'] = sub.language except ValueError: raise Http404() - form = ProblemSubmitForm(judge_choices=judge_choices, initial=initial) + form = ProblemSubmitForm(initial=initial) form_data = initial - form.fields["language"].queryset = problem.usable_languages.order_by( - "name", "key" - ).prefetch_related( - Prefetch("runtimeversion_set", RuntimeVersion.objects.order_by("priority")) - ) - if "language" in form_data: - form.fields["source"].widget.mode = form_data["language"].ace - form.fields["source"].widget.theme = profile.ace_theme + if 'problem' in form_data: + form.fields['language'].queryset = ( + form_data['problem'].usable_languages.order_by('name', 'key') + .prefetch_related(Prefetch('runtimeversion_set', RuntimeVersion.objects.order_by('priority'))) + ) + problem_object = form_data['problem'] + if 'language' in form_data: + form.fields['source'].widget.mode = form_data['language'].ace + form.fields['source'].widget.theme = profile.ace_theme if submission is not None: default_lang = sub.language @@ -1159,84 +619,56 @@ def problem_submit(request, problem, submission=None): default_lang = request.profile.language submission_limit = submissions_left = None - next_valid_submit_time = None if profile.current_contest is not None: - contest = profile.current_contest.contest try: - submission_limit = problem.contests.get(contest=contest).max_submissions + submission_limit = problem_object.contests.get(contest=profile.current_contest.contest).max_submissions except ContestProblem.DoesNotExist: pass else: if submission_limit: - submissions_left = submission_limit - get_contest_submission_count( - problem, profile, profile.current_contest.virtual - ) - if contest.rate_limit: - t = last_nth_submitted_date_in_contest(profile, contest, contest.rate_limit) - if t is not None: - next_valid_submit_time = t + timezone.timedelta(minutes=1) - next_valid_submit_time = next_valid_submit_time.isoformat() - - return render( - request, - "problem/submit.html", - { - "form": form, - "title": _("Submit to %(problem)s") - % { - "problem": problem.translated_name(request.LANGUAGE_CODE), - }, - "content_title": mark_safe( - escape(_("Submit to %(problem)s")) - % { - "problem": format_html( - '{1}', - reverse("problem_detail", args=[problem.code]), - problem.translated_name(request.LANGUAGE_CODE), - ), - } - ), - "langs": Language.objects.all(), - "no_judges": not form.fields["language"].queryset, - "submission_limit": submission_limit, - "submissions_left": submissions_left, - "ACE_URL": settings.ACE_URL, - "default_lang": default_lang, - "problem_id": problem.id, - "output_only": problem.data_files.output_only - if hasattr(problem, "data_files") - else False, - "next_valid_submit_time": next_valid_submit_time, + submissions_left = submission_limit - get_contest_submission_count(problem, profile, + profile.current_contest.virtual) + return render(request, 'problem/submit.html', { + 'form': form, + 'title': _('Submit to %(problem)s') % { + 'problem': problem_object.translated_name(request.LANGUAGE_CODE), }, - ) + 'content_title': mark_safe(escape(_('Submit to %(problem)s')) % { + 'problem': format_html('{1}', + reverse('problem_detail', args=[problem_object.code]), + problem_object.translated_name(request.LANGUAGE_CODE)), + }), + 'langs': Language.objects.all(), + 'no_judges': not form.fields['language'].queryset, + 'submission_limit': submission_limit, + 'submissions_left': submissions_left, + 'ACE_URL': settings.ACE_URL, + + 'default_lang': default_lang, + }) -class ProblemClone( - ProblemMixin, PermissionRequiredMixin, TitleMixin, SingleObjectFormView -): - title = _("Clone Problem") - template_name = "problem/clone.html" +class ProblemClone(ProblemMixin, PermissionRequiredMixin, TitleMixin, SingleObjectFormView): + title = _('Clone Problem') + template_name = 'problem/clone.html' form_class = ProblemCloneForm - permission_required = "judge.clone_problem" + permission_required = 'judge.clone_problem' def form_valid(self, form): - languages = self.object.allowed_languages.all() - language_limits = self.object.language_limits.all() - types = self.object.types.all() - - problem = deepcopy(self.object) + problem = self.object + languages = problem.allowed_languages.all() + language_limits = problem.language_limits.all() + types = problem.types.all() problem.pk = None problem.is_public = False problem.ac_rate = 0 problem.user_count = 0 - problem.code = form.cleaned_data["code"] - problem.save(should_move_data=False) + problem.code = form.cleaned_data['code'] + problem.save() problem.authors.add(self.request.profile) problem.allowed_languages.set(languages) problem.language_limits.set(language_limits) problem.types.set(types) - return HttpResponseRedirect( - reverse("admin:judge_problem_change", args=(problem.id,)) - ) + return HttpResponseRedirect(reverse('admin:judge_problem_change', args=(problem.id,))) diff --git a/judge/views/problem_data.py b/judge/views/problem_data.py index 006a304..00bd38c 100644 --- a/judge/views/problem_data.py +++ b/judge/views/problem_data.py @@ -2,34 +2,14 @@ import json import mimetypes import os from itertools import chain -import shutil -from tempfile import gettempdir from zipfile import BadZipfile, ZipFile -from django import forms -from django.conf import settings -from django.http import HttpResponse, HttpRequest -from django.shortcuts import render -from django.views.decorators.csrf import csrf_exempt -from django.views.generic import View - from django.conf import settings from django.contrib.auth.decorators import login_required from django.contrib.auth.mixins import LoginRequiredMixin -from django.core.files import File from django.core.exceptions import ValidationError -from django.forms import ( - BaseModelFormSet, - HiddenInput, - ModelForm, - NumberInput, - Select, - formset_factory, - FileInput, - TextInput, - CheckboxInput, -) -from django.http import Http404, HttpResponse, HttpResponseRedirect, JsonResponse +from django.forms import BaseModelFormSet, HiddenInput, ModelForm, NumberInput, Select, formset_factory, FileInput +from django.http import Http404, HttpResponse, HttpResponseRedirect from django.shortcuts import get_object_or_404, render from django.urls import reverse from django.utils.html import escape, format_html @@ -38,76 +18,44 @@ from django.utils.translation import gettext as _ from django.views.generic import DetailView from judge.highlight_code import highlight_code -from judge.models import ( - Problem, - ProblemData, - ProblemTestCase, - Submission, - problem_data_storage, -) +from judge.models import Problem, ProblemData, ProblemTestCase, Submission, problem_data_storage from judge.utils.problem_data import ProblemDataCompiler from judge.utils.unicode import utf8text from judge.utils.views import TitleMixin -from judge.utils.fine_uploader import ( - combine_chunks, - save_upload, - handle_upload, - FineUploadFileInput, - FineUploadForm, -) from judge.views.problem import ProblemMixin -from judge.logging import log_exception mimetypes.init() -mimetypes.add_type("application/x-yaml", ".yml") +mimetypes.add_type('application/x-yaml', '.yml') def checker_args_cleaner(self): - data = self.cleaned_data["checker_args"] + data = self.cleaned_data['checker_args'] if not data or data.isspace(): - return "" + return '' try: if not isinstance(json.loads(data), dict): - raise ValidationError(_("Checker arguments must be a JSON object")) + raise ValidationError(_('Checker arguments must be a JSON object')) except ValueError: - raise ValidationError(_("Checker arguments is invalid JSON")) + raise ValidationError(_('Checker arguments is invalid JSON')) return data class ProblemDataForm(ModelForm): def clean_zipfile(self): - if hasattr(self, "zip_valid") and not self.zip_valid: - raise ValidationError(_("Your zip file is invalid!")) - return self.cleaned_data["zipfile"] + if hasattr(self, 'zip_valid') and not self.zip_valid: + raise ValidationError(_('Your zip file is invalid!')) + return self.cleaned_data['zipfile'] clean_checker_args = checker_args_cleaner class Meta: model = ProblemData - fields = [ - "zipfile", - "checker", - "checker_args", - "custom_checker", - "custom_checker_cpp", - "interactive_judge", - "fileio_input", - "fileio_output", - "output_only", - "use_ioi_signature", - "signature_handler", - "signature_header", - ] + fields = ['zipfile', 'checker', 'checker_args', 'custom_checker', 'custom_validator'] widgets = { - "zipfile": FineUploadFileInput, - "checker_args": HiddenInput, - "generator": HiddenInput, - "output_limit": HiddenInput, - "output_prefix": HiddenInput, - "fileio_input": TextInput, - "fileio_output": TextInput, - "output_only": CheckboxInput, - "use_ioi_signature": CheckboxInput, + 'checker_args': HiddenInput, + 'generator': HiddenInput, + 'output_limit': HiddenInput, + 'output_prefix': HiddenInput, } @@ -116,35 +64,24 @@ class ProblemCaseForm(ModelForm): class Meta: model = ProblemTestCase - fields = ( - "order", - "type", - "input_file", - "output_file", - "points", - "is_pretest", - "checker", - "checker_args", - ) # , 'output_limit', 'output_prefix', 'generator_args') + fields = ('order', 'type', 'input_file', 'output_file', 'points', + 'is_pretest', 'checker', 'checker_args') #, 'output_limit', 'output_prefix', 'generator_args') widgets = { # 'generator_args': HiddenInput, - "type": Select(attrs={"style": "width: 100%"}), - "points": NumberInput(attrs={"style": "width: 4em"}), + 'type': Select(attrs={'style': 'width: 100%'}), + 'points': NumberInput(attrs={'style': 'width: 4em'}), # 'output_prefix': NumberInput(attrs={'style': 'width: 4.5em'}), # 'output_limit': NumberInput(attrs={'style': 'width: 6em'}), # 'checker_args': HiddenInput, } -class ProblemCaseFormSet( - formset_factory( - ProblemCaseForm, formset=BaseModelFormSet, extra=1, max_num=1, can_delete=True - ) -): +class ProblemCaseFormSet(formset_factory(ProblemCaseForm, formset=BaseModelFormSet, extra=1, max_num=1, + can_delete=True)): model = ProblemTestCase def __init__(self, *args, **kwargs): - self.valid_files = kwargs.pop("valid_files", None) + self.valid_files = kwargs.pop('valid_files', None) super(ProblemCaseFormSet, self).__init__(*args, **kwargs) def _construct_form(self, i, **kwargs): @@ -164,17 +101,14 @@ class ProblemManagerMixin(LoginRequiredMixin, ProblemMixin, DetailView): class ProblemSubmissionDiff(TitleMixin, ProblemMixin, DetailView): - template_name = "problem/submission-diff.html" + template_name = 'problem/submission-diff.html' def get_title(self): - return _("Comparing submissions for {0}").format(self.object.name) + return _('Comparing submissions for {0}').format(self.object.name) def get_content_title(self): - return format_html( - _('Comparing submissions for {0}'), - self.object.name, - reverse("problem_detail", args=[self.object.code]), - ) + return format_html(_('Comparing submissions for {0}'), self.object.name, + reverse('problem_detail', args=[self.object.code])) def get_object(self, queryset=None): problem = super(ProblemSubmissionDiff, self).get_object(queryset) @@ -185,90 +119,67 @@ class ProblemSubmissionDiff(TitleMixin, ProblemMixin, DetailView): def get_context_data(self, **kwargs): context = super(ProblemSubmissionDiff, self).get_context_data(**kwargs) try: - ids = self.request.GET.getlist("id") + ids = self.request.GET.getlist('id') subs = Submission.objects.filter(id__in=ids) except ValueError: raise Http404 if not subs: raise Http404 - context["submissions"] = subs + context['submissions'] = subs # If we have associated data we can do better than just guess - data = ProblemTestCase.objects.filter(dataset=self.object, type="C") + data = ProblemTestCase.objects.filter(dataset=self.object, type='C') if data: num_cases = data.count() else: num_cases = subs.first().test_cases.count() - context["num_cases"] = num_cases + context['num_cases'] = num_cases return context class ProblemDataView(TitleMixin, ProblemManagerMixin): - template_name = "problem/data.html" + template_name = 'problem/data.html' def get_title(self): - return _("Editing data for {0}").format(self.object.name) + return _('Editing data for {0}').format(self.object.name) def get_content_title(self): - return mark_safe( - escape(_("Editing data for %s")) - % ( - format_html( - '{0}', - self.object.name, - reverse("problem_detail", args=[self.object.code]), - ) - ) - ) + return mark_safe(escape(_('Editing data for %s')) % ( + format_html('{0}', self.object.name, + reverse('problem_detail', args=[self.object.code])))) def get_data_form(self, post=False): - return ProblemDataForm( - data=self.request.POST if post else None, - prefix="problem-data", - files=self.request.FILES if post else None, - instance=ProblemData.objects.get_or_create(problem=self.object)[0], - ) + return ProblemDataForm(data=self.request.POST if post else None, prefix='problem-data', + files=self.request.FILES if post else None, + instance=ProblemData.objects.get_or_create(problem=self.object)[0]) def get_case_formset(self, files, post=False): - return ProblemCaseFormSet( - data=self.request.POST if post else None, - prefix="cases", - valid_files=files, - queryset=ProblemTestCase.objects.filter(dataset_id=self.object.pk).order_by( - "order" - ), - ) + return ProblemCaseFormSet(data=self.request.POST if post else None, prefix='cases', valid_files=files, + queryset=ProblemTestCase.objects.filter(dataset_id=self.object.pk).order_by('order')) def get_valid_files(self, data, post=False): try: - if post and "problem-data-zipfile-clear" in self.request.POST: + if post and 'problem-data-zipfile-clear' in self.request.POST: return [] - elif post and "problem-data-zipfile" in self.request.FILES: - return ZipFile(self.request.FILES["problem-data-zipfile"]).namelist() + elif post and 'problem-data-zipfile' in self.request.FILES: + return ZipFile(self.request.FILES['problem-data-zipfile']).namelist() elif data.zipfile: return ZipFile(data.zipfile.path).namelist() except BadZipfile: return [] - except FileNotFoundError as e: - log_exception(e) - return [] return [] def get_context_data(self, **kwargs): context = super(ProblemDataView, self).get_context_data(**kwargs) - if "data_form" not in context: - context["data_form"] = self.get_data_form() - valid_files = context["valid_files"] = self.get_valid_files( - context["data_form"].instance - ) - context["data_form"].zip_valid = valid_files is not False - context["cases_formset"] = self.get_case_formset(valid_files) - context["valid_files_json"] = mark_safe(json.dumps(context["valid_files"])) - context["valid_files"] = set(context["valid_files"]) - context["all_case_forms"] = chain( - context["cases_formset"], [context["cases_formset"].empty_form] - ) + if 'data_form' not in context: + context['data_form'] = self.get_data_form() + valid_files = context['valid_files'] = self.get_valid_files(context['data_form'].instance) + context['data_form'].zip_valid = valid_files is not False + context['cases_formset'] = self.get_case_formset(valid_files) + context['valid_files_json'] = mark_safe(json.dumps(context['valid_files'])) + context['valid_files'] = set(context['valid_files']) + context['all_case_forms'] = chain(context['cases_formset'], [context['cases_formset'].empty_form]) return context def post(self, request, *args, **kwargs): @@ -284,17 +195,10 @@ class ProblemDataView(TitleMixin, ProblemManagerMixin): case.save() for case in cases_formset.deleted_objects: case.delete() - ProblemDataCompiler.generate( - problem, data, problem.cases.order_by("order"), valid_files - ) + ProblemDataCompiler.generate(problem, data, problem.cases.order_by('order'), valid_files) return HttpResponseRedirect(request.get_full_path()) - return self.render_to_response( - self.get_context_data( - data_form=data_form, - cases_formset=cases_formset, - valid_files=valid_files, - ) - ) + return self.render_to_response(self.get_context_data(data_form=data_form, cases_formset=cases_formset, + valid_files=valid_files)) put = post @@ -306,22 +210,16 @@ def problem_data_file(request, problem, path): raise Http404() response = HttpResponse() - if hasattr(settings, "DMOJ_PROBLEM_DATA_INTERNAL") and request.META.get( - "SERVER_SOFTWARE", "" - ).startswith("nginx/"): - response["X-Accel-Redirect"] = "%s/%s/%s" % ( - settings.DMOJ_PROBLEM_DATA_INTERNAL, - problem, - path, - ) + if hasattr(settings, 'DMOJ_PROBLEM_DATA_INTERNAL') and request.META.get('SERVER_SOFTWARE', '').startswith('nginx/'): + response['X-Accel-Redirect'] = '%s/%s/%s' % (settings.DMOJ_PROBLEM_DATA_INTERNAL, problem, path) else: try: - with problem_data_storage.open(os.path.join(problem, path), "rb") as f: + with problem_data_storage.open(os.path.join(problem, path), 'rb') as f: response.content = f.read() except IOError: raise Http404() - response["Content-Type"] = "application/octet-stream" + response['Content-Type'] = 'application/octet-stream' return response @@ -332,70 +230,15 @@ def problem_init_view(request, problem): raise Http404() try: - with problem_data_storage.open( - os.path.join(problem.code, "init.yml"), "rb" - ) as f: - data = utf8text(f.read()).rstrip("\n") + with problem_data_storage.open(os.path.join(problem.code, 'init.yml'), 'rb') as f: + data = utf8text(f.read()).rstrip('\n') except IOError: raise Http404() - return render( - request, - "problem/yaml.html", - { - "raw_source": data, - "highlighted_source": highlight_code(data, "yaml", linenos=True), - "title": _("Generated init.yml for %s") % problem.name, - "content_title": mark_safe( - escape(_("Generated init.yml for %s")) - % ( - format_html( - '{0}', - problem.name, - reverse("problem_detail", args=[problem.code]), - ) - ) - ), - }, - ) - - -class ProblemZipUploadView(ProblemManagerMixin, View): - def dispatch(self, *args, **kwargs): - return super(ProblemZipUploadView, self).dispatch(*args, **kwargs) - - def post(self, request, *args, **kwargs): - self.object = problem = self.get_object() - problem_data = get_object_or_404(ProblemData, problem=self.object) - form = FineUploadForm(request.POST, request.FILES) - - if form.is_valid(): - fileuid = form.cleaned_data["qquuid"] - filename = form.cleaned_data["qqfilename"] - dest = os.path.join(gettempdir(), fileuid) - - def post_upload(): - zip_dest = os.path.join(dest, filename) - try: - ZipFile(zip_dest).namelist() # check if this file is valid - with open(zip_dest, "rb") as f: - problem_data.zipfile.delete() - problem_data.zipfile.save(filename, File(f)) - f.close() - except Exception as e: - raise Exception(e) - finally: - shutil.rmtree(dest) - - try: - handle_upload( - request.FILES["qqfile"], - form.cleaned_data, - dest, - post_upload=post_upload, - ) - except Exception as e: - return JsonResponse({"success": False, "error": str(e)}) - return JsonResponse({"success": True}) - else: - return HttpResponse(status_code=400) + return render(request, 'problem/yaml.html', { + 'raw_source': data, 'highlighted_source': highlight_code(data, 'yaml'), + 'title': _('Generated init.yml for %s') % problem.name, + 'content_title': mark_safe(escape(_('Generated init.yml for %s')) % ( + format_html('{0}', problem.name, + reverse('problem_detail', args=[problem.code])))), + }) diff --git a/judge/views/problem_manage.py b/judge/views/problem_manage.py index dfce739..0fe8b1a 100644 --- a/judge/views/problem_manage.py +++ b/judge/views/problem_manage.py @@ -1,16 +1,9 @@ from operator import itemgetter -import zipfile, tempfile - from celery.result import AsyncResult from django.contrib import messages from django.contrib.auth.mixins import PermissionRequiredMixin -from django.http import ( - Http404, - HttpResponse, - HttpResponseBadRequest, - HttpResponseRedirect, -) +from django.http import Http404, HttpResponse, HttpResponseBadRequest, HttpResponseRedirect from django.urls import reverse from django.utils.html import escape, format_html from django.utils.safestring import mark_safe @@ -51,53 +44,33 @@ class ManageProblemSubmissionActionMixin(ManageProblemSubmissionMixin): class ManageProblemSubmissionView(TitleMixin, ManageProblemSubmissionMixin, DetailView): - template_name = "problem/manage_submission.html" + template_name = 'problem/manage_submission.html' def get_title(self): - return _("Managing submissions for %s") % (self.object.name,) + return _('Managing submissions for %s') % (self.object.name,) def get_content_title(self): - return mark_safe( - escape(_("Managing submissions for %s")) - % ( - format_html( - '{0}', - self.object.name, - reverse("problem_detail", args=[self.object.code]), - ) - ) - ) + return mark_safe(escape(_('Managing submissions for %s')) % ( + format_html('{0}', self.object.name, + reverse('problem_detail', args=[self.object.code])))) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context["submission_count"] = self.object.submission_set.count() - context["languages"] = [ - (lang_id, short_name or key) - for lang_id, key, short_name in Language.objects.values_list( - "id", "key", "short_name" - ) - ] - context["results"] = sorted(map(itemgetter(0), Submission.RESULT)) - context["current_contest"] = None - if ( - self.request.in_contest_mode - and self.object in self.request.participation.contest.problems.all() - ): - context["current_contest"] = self.request.participation.contest - + context['submission_count'] = self.object.submission_set.count() + context['languages'] = [(lang_id, short_name or key) for lang_id, key, short_name in + Language.objects.values_list('id', 'key', 'short_name')] + context['results'] = sorted(map(itemgetter(0), Submission.RESULT)) return context -class BaseActionSubmissionsView( - PermissionRequiredMixin, ManageProblemSubmissionActionMixin, BaseDetailView -): - permission_required = "judge.rejudge_submission_lot" +class BaseRejudgeSubmissionsView(PermissionRequiredMixin, ManageProblemSubmissionActionMixin, BaseDetailView): + permission_required = 'judge.rejudge_submission_lot' def perform_action(self): - if self.request.POST.get("use_range", "off") == "on": + if self.request.POST.get('use_range', 'off') == 'on': try: - start = int(self.request.POST.get("start")) - end = int(self.request.POST.get("end")) + start = int(self.request.POST.get('start')) + end = int(self.request.POST.get('end')) except (KeyError, ValueError): return HttpResponseBadRequest() id_range = (start, end) @@ -105,77 +78,28 @@ class BaseActionSubmissionsView( id_range = None try: - languages = list(map(int, self.request.POST.getlist("language"))) - results = list(map(str, self.request.POST.getlist("result"))) - contests = list(map(int, self.request.POST.getlist("contest"))) + languages = list(map(int, self.request.POST.getlist('language'))) except ValueError: return HttpResponseBadRequest() - return self.generate_response(id_range, languages, results, contests) + return self.generate_response(id_range, languages, self.request.POST.getlist('result')) - def generate_response(self, id_range, languages, results, contest): + def generate_response(self, id_range, languages, results): raise NotImplementedError() -class ActionSubmissionsView(BaseActionSubmissionsView): - def rejudge_response(self, id_range, languages, results, contest): - status = rejudge_problem_filter.delay( - self.object.id, id_range, languages, results, contest - ) +class RejudgeSubmissionsView(BaseRejudgeSubmissionsView): + def generate_response(self, id_range, languages, results): + status = rejudge_problem_filter.delay(self.object.id, id_range, languages, results) return redirect_to_task_status( - status, - message=_("Rejudging selected submissions for %s...") % (self.object.name,), - redirect=reverse( - "problem_submissions_rejudge_success", - args=[self.object.code, status.id], - ), + status, message=_('Rejudging selected submissions for %s...') % (self.object.name,), + redirect=reverse('problem_submissions_rejudge_success', args=[self.object.code, status.id]), ) - def download_response(self, id_range, languages, results, contest): - queryset = Submission.objects.filter(problem_id=self.object.id) - submissions = apply_submission_filter( - queryset, id_range, languages, results, contest - ) - with tempfile.SpooledTemporaryFile() as tmp: - with zipfile.ZipFile(tmp, "w", zipfile.ZIP_DEFLATED) as archive: - for submission in submissions: - file_name = ( - str(submission.id) - + "_" - + str(submission.user) - + "." - + str(submission.language.key) - ) - archive.writestr(file_name, submission.source.source) - - # Reset file pointer - tmp.seek(0) - - # Write file data to response - response = HttpResponse( - tmp.read(), content_type="application/x-zip-compressed" - ) - response["Content-Disposition"] = 'attachment; filename="%s"' % ( - str(self.object.code) + "_submissions.zip" - ) - return response - - def generate_response(self, id_range, languages, results, contest): - action = self.request.POST.get("action") - if action == "rejudge": - return self.rejudge_response(id_range, languages, results, contest) - elif action == "download": - return self.download_response(id_range, languages, results, contest) - else: - return Http404() - - -class PreviewActionSubmissionsView(BaseActionSubmissionsView): - def generate_response(self, id_range, languages, results, contest): - queryset = apply_submission_filter( - self.object.submission_set.all(), id_range, languages, results, contest - ) +class PreviewRejudgeSubmissionsView(BaseRejudgeSubmissionsView): + def generate_response(self, id_range, languages, results): + queryset = apply_submission_filter(self.object.submission_set.all(), id_range, languages, results) return HttpResponse(str(queryset.count())) @@ -183,12 +107,8 @@ class RescoreAllSubmissionsView(ManageProblemSubmissionActionMixin, BaseDetailVi def perform_action(self): status = rescore_problem.delay(self.object.id) return redirect_to_task_status( - status, - message=_("Rescoring all submissions for %s...") % (self.object.name,), - redirect=reverse( - "problem_submissions_rescore_success", - args=[self.object.code, status.id], - ), + status, message=_('Rescoring all submissions for %s...') % (self.object.name,), + redirect=reverse('problem_submissions_rescore_success', args=[self.object.code, status.id]), ) @@ -196,29 +116,15 @@ def rejudge_success(request, problem, task_id): count = AsyncResult(task_id).result if not isinstance(count, int): raise Http404() - messages.success( - request, - ngettext( - "Successfully scheduled %d submission for rejudging.", - "Successfully scheduled %d submissions for rejudging.", - count, - ) - % (count,), - ) - return HttpResponseRedirect(reverse("problem_manage_submissions", args=[problem])) + messages.success(request, ngettext('Successfully scheduled %d submission for rejudging.', + 'Successfully scheduled %d submissions for rejudging.', count) % (count,)) + return HttpResponseRedirect(reverse('problem_manage_submissions', args=[problem])) def rescore_success(request, problem, task_id): count = AsyncResult(task_id).result if not isinstance(count, int): raise Http404() - messages.success( - request, - ngettext( - "%d submission were successfully rescored.", - "%d submissions were successfully rescored.", - count, - ) - % (count,), - ) - return HttpResponseRedirect(reverse("problem_manage_submissions", args=[problem])) + messages.success(request, ngettext('%d submission were successfully rescored.', + '%d submissions were successfully rescored.', count) % (count,)) + return HttpResponseRedirect(reverse('problem_manage_submissions', args=[problem])) diff --git a/judge/views/ranked_submission.py b/judge/views/ranked_submission.py index fcf13f2..f368d41 100644 --- a/judge/views/ranked_submission.py +++ b/judge/views/ranked_submission.py @@ -7,31 +7,27 @@ from judge.utils.problems import get_result_data from judge.utils.raw_sql import join_sql_subquery from judge.views.submission import ForceContestMixin, ProblemSubmissions -__all__ = ["RankedSubmissions"] +__all__ = ['RankedSubmissions', 'ContestRankedSubmission'] class RankedSubmissions(ProblemSubmissions): - tab = "best_submissions_list" - page_type = "best_submissions_list" + tab = 'best_submissions_list' dynamic_update = False def get_queryset(self): if self.in_contest: - contest_join = "INNER JOIN judge_contestsubmission AS cs ON (sub.id = cs.submission_id)" - points = "cs.points" - constraint = " AND sub.contest_object_id = %s" + contest_join = '''INNER JOIN judge_contestsubmission AS cs ON (sub.id = cs.submission_id) + INNER JOIN judge_contestparticipation AS cp ON (cs.participation_id = cp.id)''' + points = 'cs.points' + constraint = 'AND cp.contest_id = %s' else: - contest_join = "" - points = "sub.points" - constraint = "" - queryset = ( - super(RankedSubmissions, self) - .get_queryset() - .filter(user__is_unlisted=False) - ) + contest_join = '' + points = 'sub.points' + constraint = '' + queryset = super(RankedSubmissions, self).get_queryset().filter(user__is_unlisted=False) join_sql_subquery( queryset, - subquery=""" + subquery=''' SELECT sub.id AS id FROM ( SELECT sub.user_id AS uid, MAX(sub.points) AS points @@ -45,34 +41,49 @@ class RankedSubmissions(ProblemSubmissions): GROUP BY sub.user_id, {points} ) AS fastest ON (highscore.uid = fastest.uid AND highscore.points = fastest.points) STRAIGHT_JOIN judge_submission AS sub - ON (sub.user_id = fastest.uid AND sub.time = fastest.time) - WHERE sub.problem_id = %s {constraint} + ON (sub.user_id = fastest.uid AND sub.time = fastest.time) {contest_join} + WHERE sub.problem_id = %s AND {points} > 0 {constraint} GROUP BY sub.user_id - """.format( - points=points, contest_join=contest_join, constraint=constraint - ), - params=[self.problem.id, self.contest.id] * 3 - if self.in_contest - else [self.problem.id] * 3, - alias="best_subs", - join_fields=[("id", "id")], - related_model=Submission, + '''.format(points=points, contest_join=contest_join, constraint=constraint), + params=[self.problem.id, self.contest.id] * 3 if self.in_contest else [self.problem.id] * 3, + alias='best_subs', join_fields=[('id', 'id')], ) if self.in_contest: - return queryset.order_by("-contest__points", "time") + return queryset.order_by('-contest__points', 'time') else: - return queryset.order_by("-points", "time") + return queryset.order_by('-points', 'time') def get_title(self): - return _("Best solutions for %s") % self.problem_name + return _('Best solutions for %s') % self.problem_name def get_content_title(self): - return format_html( - _('Best solutions for {0}'), - self.problem_name, - reverse("problem_detail", args=[self.problem.code]), - ) + return format_html(_('Best solutions for {0}'), self.problem_name, + reverse('problem_detail', args=[self.problem.code])) def _get_result_data(self): return get_result_data(super(RankedSubmissions, self).get_queryset().order_by()) + + +class ContestRankedSubmission(ForceContestMixin, RankedSubmissions): + def get_title(self): + if self.problem.is_accessible_by(self.request.user): + return _('Best solutions for %(problem)s in %(contest)s') % { + 'problem': self.problem_name, 'contest': self.contest.name, + } + return _('Best solutions for problem %(number)s in %(contest)s') % { + 'number': self.get_problem_number(self.problem), 'contest': self.contest.name, + } + + def get_content_title(self): + if self.problem.is_accessible_by(self.request.user): + return format_html(_('Best solutions for {0} in {2}'), + self.problem_name, reverse('problem_detail', args=[self.problem.code]), + self.contest.name, reverse('contest_view', args=[self.contest.key])) + return format_html(_('Best solutions for problem {0} in {1}'), + self.get_problem_number(self.problem), self.contest.name, + reverse('contest_view', args=[self.contest.key])) + + def _get_result_data(self): + return get_result_data(Submission.objects.filter( + problem_id=self.problem.id, contest__participation__contest_id=self.contest.id)) diff --git a/judge/views/register.py b/judge/views/register.py index 58d1d6f..67c1c4f 100644 --- a/judge/views/register.py +++ b/judge/views/register.py @@ -8,121 +8,101 @@ from django.contrib.auth.password_validation import get_default_password_validat from django.forms import ChoiceField, ModelChoiceField from django.shortcuts import render from django.utils.translation import gettext, gettext_lazy as _ -from registration.backends.default.views import ( - ActivationView as OldActivationView, - RegistrationView as OldRegistrationView, -) +from registration.backends.default.views import (ActivationView as OldActivationView, + RegistrationView as OldRegistrationView) from registration.forms import RegistrationForm from sortedm2m.forms import SortedMultipleChoiceField -from judge.models import Language, Profile, TIMEZONE +from judge.models import Language, Organization, Profile, TIMEZONE from judge.utils.recaptcha import ReCaptchaField, ReCaptchaWidget +from judge.utils.subscription import Subscription, newsletter_id from judge.widgets import Select2MultipleWidget, Select2Widget -valid_id = re.compile(r"^\w+$") +valid_id = re.compile(r'^\w+$') bad_mail_regex = list(map(re.compile, settings.BAD_MAIL_PROVIDER_REGEX)) class CustomRegistrationForm(RegistrationForm): - username = forms.RegexField( - regex=r"^\w+$", - max_length=30, - label=_("Username"), - error_messages={ - "invalid": _("A username must contain letters, " "numbers, or underscores") - }, - ) - timezone = ChoiceField( - label=_("Timezone"), - choices=TIMEZONE, - widget=Select2Widget(attrs={"style": "width:100%"}), - ) - language = ModelChoiceField( - queryset=Language.objects.all(), - label=_("Preferred language"), - empty_label=None, - widget=Select2Widget(attrs={"style": "width:100%"}), - ) + username = forms.RegexField(regex=r'^\w+$', max_length=30, label=_('Username'), + error_messages={'invalid': _('A username must contain letters, ' + 'numbers, or underscores')}) + timezone = ChoiceField(label=_('Timezone'), choices=TIMEZONE, + widget=Select2Widget(attrs={'style': 'width:100%'})) + language = ModelChoiceField(queryset=Language.objects.all(), label=_('Preferred language'), empty_label=None, + widget=Select2Widget(attrs={'style': 'width:100%'})) + organizations = SortedMultipleChoiceField(queryset=Organization.objects.filter(is_open=True), + label=_('Organizations'), required=False, + widget=Select2MultipleWidget(attrs={'style': 'width:100%'})) + + if newsletter_id is not None: + newsletter = forms.BooleanField(label=_('Subscribe to newsletter?'), initial=True, required=False) if ReCaptchaField is not None: captcha = ReCaptchaField(widget=ReCaptchaWidget()) def clean_email(self): - if User.objects.filter(email=self.cleaned_data["email"]).exists(): - raise forms.ValidationError( - gettext( - 'The email address "%s" is already taken. Only one registration ' - "is allowed per address." - ) - % self.cleaned_data["email"] - ) - if "@" in self.cleaned_data["email"]: - domain = self.cleaned_data["email"].split("@")[-1].lower() - if domain in settings.BAD_MAIL_PROVIDERS or any( - regex.match(domain) for regex in bad_mail_regex - ): - raise forms.ValidationError( - gettext( - "Your email provider is not allowed due to history of abuse. " - "Please use a reputable email provider." - ) - ) - return self.cleaned_data["email"] + if User.objects.filter(email=self.cleaned_data['email']).exists(): + raise forms.ValidationError(gettext('The email address "%s" is already taken. Only one registration ' + 'is allowed per address.') % self.cleaned_data['email']) + if '@' in self.cleaned_data['email']: + domain = self.cleaned_data['email'].split('@')[-1].lower() + if (domain in settings.BAD_MAIL_PROVIDERS or + any(regex.match(domain) for regex in bad_mail_regex)): + raise forms.ValidationError(gettext('Your email provider is not allowed due to history of abuse. ' + 'Please use a reputable email provider.')) + return self.cleaned_data['email'] class RegistrationView(OldRegistrationView): - title = _("Registration") + title = _('Registration') form_class = CustomRegistrationForm - template_name = "registration/registration_form.html" + template_name = 'registration/registration_form.html' def get_context_data(self, **kwargs): - if "title" not in kwargs: - kwargs["title"] = self.title + if 'title' not in kwargs: + kwargs['title'] = self.title tzmap = settings.TIMEZONE_MAP - kwargs["TIMEZONE_MAP"] = tzmap or "http://momentjs.com/static/img/world.png" - kwargs["TIMEZONE_BG"] = settings.TIMEZONE_BG if tzmap else "#4E7CAD" - kwargs["password_validators"] = get_default_password_validators() - kwargs["tos_url"] = settings.TERMS_OF_SERVICE_URL + kwargs['TIMEZONE_MAP'] = tzmap or 'http://momentjs.com/static/img/world.png' + kwargs['TIMEZONE_BG'] = settings.TIMEZONE_BG if tzmap else '#4E7CAD' + kwargs['password_validators'] = get_default_password_validators() + kwargs['tos_url'] = settings.TERMS_OF_SERVICE_URL return super(RegistrationView, self).get_context_data(**kwargs) def register(self, form): user = super(RegistrationView, self).register(form) - profile, _ = Profile.objects.get_or_create( - user=user, - defaults={ - "language": Language.get_default_language(), - }, - ) + profile, _ = Profile.objects.get_or_create(user=user, defaults={ + 'language': Language.get_python3(), + }) cleaned_data = form.cleaned_data - profile.timezone = cleaned_data["timezone"] - profile.language = cleaned_data["language"] + profile.timezone = cleaned_data['timezone'] + profile.language = cleaned_data['language'] + profile.organizations.add(*cleaned_data['organizations']) profile.save() + + if newsletter_id is not None and cleaned_data['newsletter']: + Subscription(user=user, newsletter_id=newsletter_id, subscribed=True).save() return user def get_initial(self, *args, **kwargs): initial = super(RegistrationView, self).get_initial(*args, **kwargs) - initial["timezone"] = settings.DEFAULT_USER_TIME_ZONE - initial["language"] = Language.objects.get(key=settings.DEFAULT_USER_LANGUAGE) + initial['timezone'] = settings.DEFAULT_USER_TIME_ZONE + initial['language'] = Language.objects.get(key=settings.DEFAULT_USER_LANGUAGE) return initial class ActivationView(OldActivationView): - title = _("Registration") - template_name = "registration/activate.html" + title = _('Registration') + template_name = 'registration/activate.html' def get_context_data(self, **kwargs): - if "title" not in kwargs: - kwargs["title"] = self.title + if 'title' not in kwargs: + kwargs['title'] = self.title return super(ActivationView, self).get_context_data(**kwargs) def social_auth_error(request): - return render( - request, - "generic-message.html", - { - "title": gettext("Authentication failure"), - "message": request.GET.get("message"), - }, - ) + return render(request, 'generic-message.html', { + 'title': gettext('Authentication failure'), + 'message': request.GET.get('message'), + }) diff --git a/judge/views/resolver.py b/judge/views/resolver.py deleted file mode 100644 index 84e5dff..0000000 --- a/judge/views/resolver.py +++ /dev/null @@ -1,155 +0,0 @@ -from django.views.generic import TemplateView -from django.utils.translation import gettext as _ -from django.http import HttpResponseForbidden, JsonResponse -from judge.models import Contest -from django.utils.safestring import mark_safe - -import json - - -class Resolver(TemplateView): - title = _("Resolver") - template_name = "resolver/resolver.html" - - def get_contest_json(self): - problems = self.contest.contest_problems.values_list("order", "id") - order_to_id = {} - id_to_order = {} - for order, problem_id in problems: - id_to_order[str(problem_id)] = order - - hidden_subtasks = self.contest.format.get_hidden_subtasks() - num_problems = len(problems) - problem_sub = [0] * num_problems - sub_frozen = [[] for _ in range(num_problems)] - problems_json = {str(i): {} for i in range(1, num_problems + 1)} - - users = {} - cnt_user = 0 - total_subtask_points_map = {} - - for participation in self.contest.users.filter(virtual=0): - cnt_user += 1 - users[str(cnt_user)] = { - "username": participation.user.username, - "name": participation.user.first_name or participation.user.username, - "school": participation.user.last_name, - "last_submission": participation.cumtime_final, - "problems": {}, - } - for ( - problem_id, - problem_points, - time, - subtask_points, - total_subtask_points, - subtask, - sub_id, - ) in self.contest.format.get_results_by_subtask(participation, True): - subtask = subtask or 1 - problem_id = str(problem_id) - order = id_to_order[problem_id] - problem_sub[order - 1] = max(problem_sub[order - 1], subtask) - if total_subtask_points: - total_subtask_points_map[(order, subtask)] = total_subtask_points - - cnt_user = 0 - for participation in self.contest.users.filter(virtual=0): - cnt_user += 1 - total_points = {} - points_map = {} - frozen_points_map = {} - problem_points_map = {} - for ( - problem_id, - problem_points, - time, - subtask_points, - total_subtask_points, - subtask, - sub_id, - ) in self.contest.format.get_results_by_subtask(participation, True): - subtask = subtask or 1 - problem_id = str(problem_id) - order = id_to_order[problem_id] - points_map[(order, subtask)] = subtask_points - if order not in total_points: - total_points[order] = 0 - total_points[order] += total_subtask_points - problem_points_map[order] = problem_points - - for ( - problem_id, - problem_points, - time, - subtask_points, - total_subtask_points, - subtask, - sub_id, - ) in self.contest.format.get_results_by_subtask(participation, False): - subtask = subtask or 1 - problem_id = str(problem_id) - order = id_to_order[problem_id] - frozen_points_map[(order, subtask)] = subtask_points - - for order in range(1, num_problems + 1): - for subtask in range(1, problem_sub[order - 1] + 1): - if not total_points.get(order, 0): - continue - if str(order) not in users[str(cnt_user)]["problems"]: - users[str(cnt_user)]["problems"][str(order)] = { - "points": {}, - "frozen_points": {}, - } - problems_json[str(order)][str(subtask)] = round( - total_subtask_points_map[(order, subtask)] - / total_points[order] - * problem_points_map[order], - self.contest.points_precision, - ) - users[str(cnt_user)]["problems"][str(order)]["points"][ - str(subtask) - ] = round( - points_map.get((order, subtask), 0) - / total_points[order] - * problem_points_map[order], - self.contest.points_precision, - ) - users[str(cnt_user)]["problems"][str(order)]["frozen_points"][ - str(subtask) - ] = round( - frozen_points_map.get((order, subtask), 0) - / total_points[order] - * problem_points_map[order], - self.contest.points_precision, - ) - - for i in hidden_subtasks: - order = id_to_order[i] - sub_frozen[order - 1] = list(hidden_subtasks[i]) - - return { - "problem_sub": problem_sub, - "sub_frozen": sub_frozen, - "problems": problems_json, - "users": users, - } - - def get_context_data(self, **kwargs): - context = super(Resolver, self).get_context_data(**kwargs) - context["contest_json"] = mark_safe(json.dumps(self.get_contest_json())) - return context - - def get(self, request, *args, **kwargs): - if not request.user.is_superuser: - return HttpResponseForbidden() - self.contest = Contest.objects.get(key=kwargs.get("contest")) - if not self.contest.format.has_hidden_subtasks: - return HttpResponseForbidden() - - if self.request.GET.get("json"): - json_dumps_params = {"ensure_ascii": False} - return JsonResponse( - self.get_contest_json(), json_dumps_params=json_dumps_params - ) - return super(Resolver, self).get(request, *args, **kwargs) diff --git a/judge/views/select2.py b/judge/views/select2.py index 62a850c..b58b36b 100644 --- a/judge/views/select2.py +++ b/judge/views/select2.py @@ -1,27 +1,16 @@ -from urllib.parse import urljoin - from django.db.models import F, Q from django.http import Http404, JsonResponse from django.shortcuts import get_object_or_404 from django.utils.encoding import smart_text from django.views.generic.list import BaseListView -from django.conf import settings - -from chat_box.utils import encrypt_url from judge.jinja2.gravatar import gravatar from judge.models import Comment, Contest, Organization, Problem, Profile -def _get_user_queryset(term, org_id=None): - if org_id: - try: - qs = Organization.objects.get(id=org_id).members.all() - except Exception: - raise Http404() - else: - qs = Profile.objects - if term.endswith(" "): +def _get_user_queryset(term): + qs = Profile.objects + if term.endswith(' '): qs = qs.filter(user__username=term.strip()) else: qs = qs.filter(user__username__icontains=term) @@ -33,38 +22,26 @@ class Select2View(BaseListView): def get(self, request, *args, **kwargs): self.request = request - self.term = kwargs.get("term", request.GET.get("term", "")) + self.term = kwargs.get('term', request.GET.get('term', '')) self.object_list = self.get_queryset() context = self.get_context_data() - return JsonResponse( - { - "results": [ - { - "text": smart_text(self.get_name(obj)), - "id": obj.pk, - } - for obj in context["object_list"] - ], - "more": context["page_obj"].has_next(), - } - ) + return JsonResponse({ + 'results': [ + { + 'text': smart_text(self.get_name(obj)), + 'id': obj.pk, + } for obj in context['object_list']], + 'more': context['page_obj'].has_next(), + }) def get_name(self, obj): return str(obj) class UserSelect2View(Select2View): - def get(self, request, *args, **kwargs): - self.org_id = kwargs.get("org_id", request.GET.get("org_id", "")) - return super(UserSelect2View, self).get(request, *args, **kwargs) - def get_queryset(self): - return ( - _get_user_queryset(self.term, self.org_id) - .annotate(username=F("user__username")) - .only("id") - ) + return _get_user_queryset(self.term).annotate(username=F('user__username')).only('id') def get_name(self, obj): return obj.username @@ -77,25 +54,33 @@ class OrganizationSelect2View(Select2View): class ProblemSelect2View(Select2View): def get_queryset(self): - return ( - Problem.get_visible_problems(self.request.user) - .filter(Q(code__icontains=self.term) | Q(name__icontains=self.term)) - .distinct() - ) + queryset = Problem.objects.filter(Q(code__icontains=self.term) | Q(name__icontains=self.term)) + if not self.request.user.has_perm('judge.see_private_problem'): + filter = Q(is_public=True) + if self.request.user.is_authenticated: + filter |= Q(authors=self.request.profile) | Q(curators=self.request.profile) + queryset = queryset.filter(filter).distinct() + return queryset.distinct() class ContestSelect2View(Select2View): - def get(self, request, *args, **kwargs): - self.problem_id = kwargs.get("problem_id", request.GET.get("problem_id", "")) - return super(ContestSelect2View, self).get(request, *args, **kwargs) - def get_queryset(self): - q = Contest.get_visible_contests(self.request.user).filter( - Q(key__icontains=self.term) | Q(name__icontains=self.term) - ) - if self.problem_id: - q = q.filter(problems=self.problem_id) - return q + queryset = Contest.objects.filter(Q(key__icontains=self.term) | Q(name__icontains=self.term)) + if not self.request.user.has_perm('judge.see_private_contest'): + queryset = queryset.filter(is_visible=True) + if not self.request.user.has_perm('judge.edit_all_contest'): + q = Q(is_private=False, is_organization_private=False) + if self.request.user.is_authenticated: + q |= Q(is_organization_private=True, + organizations__in=self.request.profile.organizations.all()) + q |= Q(is_private=True, private_contestants=self.request.profile) + queryset = queryset.filter(q) + return queryset + + +class CommentSelect2View(Select2View): + def get_queryset(self): + return Comment.objects.filter(page__icontains=self.term) class UserSearchSelect2View(BaseListView): @@ -104,108 +89,50 @@ class UserSearchSelect2View(BaseListView): def get_queryset(self): return _get_user_queryset(self.term) - def get_json_result_from_object(self, user_tuple): - pk, username, email, display_rank, profile_image = user_tuple - return { - "text": username, - "id": username, - "gravatar_url": gravatar( - None, - self.gravatar_size, - self.gravatar_default, - self.get_profile_image_url(profile_image), - email, - ), - "display_rank": display_rank, - } - def get(self, request, *args, **kwargs): self.request = request self.kwargs = kwargs - self.term = kwargs.get("term", request.GET.get("term", "")) - self.gravatar_size = request.GET.get("gravatar_size", 128) - self.gravatar_default = request.GET.get("gravatar_default", None) + self.term = kwargs.get('term', request.GET.get('term', '')) + self.gravatar_size = request.GET.get('gravatar_size', 128) + self.gravatar_default = request.GET.get('gravatar_default', None) - self.object_list = self.get_queryset().values_list( - "pk", "user__username", "user__email", "display_rank", "profile_image" - ) + self.object_list = self.get_queryset().values_list('pk', 'user__username', 'user__email', 'display_rank') context = self.get_context_data() - return JsonResponse( - { - "results": [ - self.get_json_result_from_object(user_tuple) - for user_tuple in context["object_list"] - ], - "more": context["page_obj"].has_next(), - } - ) + return JsonResponse({ + 'results': [ + { + 'text': username, + 'id': username, + 'gravatar_url': gravatar(email, self.gravatar_size, self.gravatar_default), + 'display_rank': display_rank, + } for pk, username, email, display_rank in context['object_list']], + 'more': context['page_obj'].has_next(), + }) def get_name(self, obj): return str(obj) - def get_profile_image_url(self, profile_image): - if profile_image: - return urljoin(settings.MEDIA_URL, profile_image) - return None - class ContestUserSearchSelect2View(UserSearchSelect2View): def get_queryset(self): - contest = get_object_or_404(Contest, key=self.kwargs["contest"]) - if not contest.is_accessible_by( - self.request.user - ) or not contest.can_see_full_scoreboard(self.request.user): + contest = get_object_or_404(Contest, key=self.kwargs['contest']) + if not contest.can_see_scoreboard(self.request.user) or \ + contest.hide_scoreboard and contest.is_in_contest(self.request.user): raise Http404() - return Profile.objects.filter( - contest_history__contest=contest, user__username__icontains=self.term - ).distinct() + return Profile.objects.filter(contest_history__contest=contest, + user__username__icontains=self.term).distinct() class TicketUserSelect2View(UserSearchSelect2View): def get_queryset(self): - return Profile.objects.filter( - tickets__isnull=False, user__username__icontains=self.term - ).distinct() + return Profile.objects.filter(tickets__isnull=False, + user__username__icontains=self.term).distinct() class AssigneeSelect2View(UserSearchSelect2View): def get_queryset(self): - return Profile.objects.filter( - assigned_tickets__isnull=False, user__username__icontains=self.term - ).distinct() - - -class ChatUserSearchSelect2View(UserSearchSelect2View): - def get_json_result_from_object(self, user_tuple): - if not self.request.user.is_authenticated: - raise Http404() - pk, username, email, display_rank, profile_image = user_tuple - return { - "text": username, - "id": encrypt_url(self.request.profile.id, pk), - "gravatar_url": gravatar( - None, - self.gravatar_size, - self.gravatar_default, - self.get_profile_image_url(profile_image), - email, - ), - "display_rank": display_rank, - } - - -class ProblemAuthorSearchSelect2View(UserSearchSelect2View): - def get_queryset(self): - return Profile.objects.filter( - authored_problems__isnull=False, user__username__icontains=self.term - ).distinct() - - def get_json_result_from_object(self, user_tuple): - pk, username, email, display_rank, profile_image = user_tuple - return { - "text": username, - "id": pk, - } + return Profile.objects.filter(assigned_tickets__isnull=False, + user__username__icontains=self.term).distinct() diff --git a/judge/views/stats.py b/judge/views/stats.py index 5071dd5..41a852b 100644 --- a/judge/views/stats.py +++ b/judge/views/stats.py @@ -1,7 +1,5 @@ from itertools import chain, repeat from operator import itemgetter -import json -import pandas as pd from django.conf import settings from django.db.models import Case, Count, FloatField, IntegerField, Value, When @@ -9,192 +7,62 @@ from django.db.models.expressions import CombinedExpression from django.http import JsonResponse from django.shortcuts import render from django.utils.translation import gettext as _ -from django.http import Http404 -from django.views.generic import TemplateView -from django.utils.safestring import mark_safe -from django.db import connection from judge.models import Language, Submission -from judge.utils.stats import ( - chart_colors, - get_bar_chart, - get_pie_chart, - highlight_colors, -) +from judge.utils.stats import chart_colors, get_bar_chart, get_pie_chart, highlight_colors -class StatViewBase(TemplateView): - def get(self, request, *args, **kwargs): - if not request.user.is_superuser: - raise Http404 - return super().get(request, *args, **kwargs) +ac_count = Count(Case(When(submission__result='AC', then=Value(1)), output_field=IntegerField())) -class StatLanguage(StatViewBase): - template_name = "stats/language.html" - ac_count = Count( - Case(When(submission__result="AC", then=Value(1)), output_field=IntegerField()) - ) - - def repeat_chain(iterable): - return chain.from_iterable(repeat(iterable)) - - def language_data( - self, language_count=Language.objects.annotate(count=Count("submission")) - ): - languages = ( - language_count.filter(count__gt=0) - .values("key", "name", "count") - .order_by("-count") - ) - num_languages = min(len(languages), settings.DMOJ_STATS_LANGUAGE_THRESHOLD) - other_count = sum(map(itemgetter("count"), languages[num_languages:])) - - return { - "labels": list(map(itemgetter("name"), languages[:num_languages])) - + ["Other"], - "datasets": [ - { - "backgroundColor": chart_colors[:num_languages] + ["#FDB45C"], - "highlightBackgroundColor": highlight_colors[:num_languages] - + ["#FFC870"], - "data": list(map(itemgetter("count"), languages[:num_languages])) - + [other_count], - }, - ], - } - - def ac_language_data(self): - return self.language_data(Language.objects.annotate(count=self.ac_count)) - - def status_data(self, statuses=None): - if not statuses: - statuses = ( - Submission.objects.values("result") - .annotate(count=Count("result")) - .values("result", "count") - .order_by("-count") - ) - data = [] - for status in statuses: - res = status["result"] - if not res: - continue - count = status["count"] - data.append((str(Submission.USER_DISPLAY_CODES[res]), count)) - - return get_pie_chart(data) - - def ac_rate(self): - rate = CombinedExpression( - self.ac_count / Count("submission"), - "*", - Value(100.0), - output_field=FloatField(), - ) - data = ( - Language.objects.annotate(total=Count("submission"), ac_rate=rate) - .filter(total__gt=0) - .order_by("total") - .values_list("name", "ac_rate") - ) - return get_bar_chart(list(data)) - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - context["title"] = _("Language statistics") - context["tab"] = "language" - context["data_all"] = mark_safe(json.dumps(self.language_data())) - context["lang_ac"] = mark_safe(json.dumps(self.ac_language_data())) - context["status_counts"] = mark_safe(json.dumps(self.status_data())) - context["ac_rate"] = mark_safe(json.dumps(self.ac_rate())) - return context +def repeat_chain(iterable): + return chain.from_iterable(repeat(iterable)) -def group_data_by_period(dates, data, period="1W"): - df = pd.DataFrame() - df["dates"] = pd.to_datetime(dates) - df["data"] = data - df = df.groupby([pd.Grouper(key="dates", freq=period)])["data"].mean().reset_index() - return list(df["dates"]), list(df["data"]) +def language_data(request, language_count=Language.objects.annotate(count=Count('submission'))): + languages = language_count.filter(count__gt=0).values('key', 'name', 'count').order_by('-count') + num_languages = min(len(languages), settings.DMOJ_STATS_LANGUAGE_THRESHOLD) + other_count = sum(map(itemgetter('count'), languages[num_languages:])) + + return JsonResponse({ + 'labels': list(map(itemgetter('name'), languages[:num_languages])) + ['Other'], + 'datasets': [ + { + 'backgroundColor': chart_colors[:num_languages] + ['#FDB45C'], + 'highlightBackgroundColor': highlight_colors[:num_languages] + ['#FFC870'], + 'data': list(map(itemgetter('count'), languages[:num_languages])) + [other_count], + }, + ], + }, safe=False) -class StatSite(StatViewBase): - template_name = "stats/site.html" +def ac_language_data(request): + return language_data(request, Language.objects.annotate(count=ac_count)) - def create_dataset(self, query, label): - labels = [] - data = [] - with connection.cursor() as cursor: - cursor.execute(query) - for row in cursor.fetchall(): - data.append(row[0]) - labels.append(row[1]) - labels, data = group_data_by_period(labels, data, self.period) +def status_data(request, statuses=None): + if not statuses: + statuses = (Submission.objects.values('result').annotate(count=Count('result')) + .values('result', 'count').order_by('-count')) + data = [] + for status in statuses: + res = status['result'] + if not res: + continue + count = status['count'] + data.append((str(Submission.USER_DISPLAY_CODES[res]), count)) - res = { - "labels": labels, - "datasets": [ - { - "label": label, - "data": data, - "borderColor": "rgb(75, 192, 192)", - "pointRadius": 1, - "borderWidth": 2, - } - ], - } - return mark_safe(json.dumps(res, default=str)) + return JsonResponse(get_pie_chart(data), safe=False) - def get_submissions(self): - query = """ - SELECT COUNT(*), CAST(date AS Date) as day from judge_submission GROUP BY day; - """ - return self.create_dataset(query, _("Submissions")) - def get_comments(self): - query = """ - SELECT COUNT(*), CAST(time AS Date) as day from judge_comment GROUP BY day; - """ - return self.create_dataset(query, _("Comments")) +def ac_rate(request): + rate = CombinedExpression(ac_count / Count('submission'), '*', Value(100.0), output_field=FloatField()) + data = Language.objects.annotate(total=Count('submission'), ac_rate=rate).filter(total__gt=0) \ + .order_by('total').values_list('name', 'ac_rate') + return JsonResponse(get_bar_chart(list(data))) - def get_new_users(self): - query = """ - SELECT COUNT(*), CAST(date_joined AS Date) as day from auth_user GROUP BY day; - """ - return self.create_dataset(query, _("New users")) - def get_chat_messages(self): - query = """ - SELECT COUNT(*), CAST(time AS Date) as day from chat_box_message GROUP BY day; - """ - return self.create_dataset(query, _("Chat messages")) - - def get_contests(self): - query = """ - SELECT COUNT(*), CAST(start_time AS Date) as day from judge_contest GROUP BY day; - """ - return self.create_dataset(query, _("Contests")) - - def get_groups(self): - query = """ - SELECT COUNT(*), CAST(creation_date AS Date) as day from judge_organization GROUP BY day; - """ - return self.create_dataset(query, _("Groups")) - - def get(self, request, *args, **kwargs): - self.period = request.GET.get("period", "1W") - return super().get(request, *args, **kwargs) - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - context["tab"] = "site" - context["title"] = _("Site statistics") - context["submissions"] = self.get_submissions() - context["comments"] = self.get_comments() - context["new_users"] = self.get_new_users() - context["chat_messages"] = self.get_chat_messages() - context["contests"] = self.get_contests() - context["groups"] = self.get_groups() - return context +def language(request): + return render(request, 'stats/language.html', { + 'title': _('Language statistics'), 'tab': 'language', + }) diff --git a/judge/views/status.py b/judge/views/status.py index c829206..a7f0b26 100644 --- a/judge/views/status.py +++ b/judge/views/status.py @@ -2,48 +2,41 @@ from collections import defaultdict from functools import partial from django.shortcuts import render +from django.utils import six from django.utils.translation import gettext as _ from packaging import version from judge.models import Judge, Language, RuntimeVersion -__all__ = ["status_all", "status_table"] +__all__ = ['status_all', 'status_table'] def get_judges(request): if request.user.is_superuser or request.user.is_staff: - return True, Judge.objects.order_by("-online", "name") + return True, Judge.objects.order_by('-online', 'name') else: return False, Judge.objects.filter(online=True) def status_all(request): see_all, judges = get_judges(request) - return render( - request, - "status/judge-status.html", - { - "title": _("Status"), - "judges": judges, - "see_all_judges": see_all, - }, - ) + return render(request, 'status/judge-status.html', { + 'title': _('Status'), + 'judges': judges, + 'see_all_judges': see_all, + }) def status_table(request): see_all, judges = get_judges(request) - return render( - request, - "status/judge-status-table.html", - { - "judges": judges, - "see_all_judges": see_all, - }, - ) + return render(request, 'status/judge-status-table.html', { + 'judges': judges, + 'see_all_judges': see_all, + }) class LatestList(list): - __slots__ = ("versions", "is_latest") + __slots__ = ('versions', 'is_latest') def compare_version_list(x, y): @@ -68,17 +61,15 @@ def version_matrix(request): judges = {judge.id: judge.name for judge in Judge.objects.filter(online=True)} languages = Language.objects.filter(judges__online=True).distinct() - for runtime in RuntimeVersion.objects.filter(judge__online=True).order_by( - "priority" - ): + for runtime in RuntimeVersion.objects.filter(judge__online=True).order_by('priority'): matrix[runtime.judge_id][runtime.language_id].append(runtime) - for judge, data in matrix.items(): - name_tuple = judges[judge].rpartition(".") + for judge, data in six.iteritems(matrix): + name_tuple = judges[judge].rpartition('.') groups[name_tuple[0] or name_tuple[-1]].append((judges[judge], data)) matrix = {} - for group, data in groups.items(): + for group, data in six.iteritems(groups): if len(data) == 1: judge, data = data[0] matrix[judge] = data @@ -101,24 +92,20 @@ def version_matrix(request): if ds[i] != rep: matrix[j] = x - for data in matrix.values(): - for language, versions in data.items(): + for data in six.itervalues(matrix): + for language, versions in six.iteritems(data): versions.versions = [version.parse(runtime.version) for runtime in versions] if versions.versions > latest[language]: latest[language] = versions.versions - for data in matrix.values(): - for language, versions in data.items(): + for data in six.itervalues(matrix): + for language, versions in six.iteritems(data): versions.is_latest = versions.versions == latest[language] languages = sorted(languages, key=lambda lang: version.parse(lang.name)) - return render( - request, - "status/versions.html", - { - "title": _("Version matrix"), - "judges": sorted(matrix.keys()), - "languages": languages, - "matrix": matrix, - }, - ) + return render(request, 'status/versions.html', { + 'title': _('Version matrix'), + 'judges': sorted(matrix.keys()), + 'languages': languages, + 'matrix': matrix, + }) diff --git a/judge/views/submission.py b/judge/views/submission.py index 09dcabe..d7ebfc0 100644 --- a/judge/views/submission.py +++ b/judge/views/submission.py @@ -1,4 +1,6 @@ +import json import os.path +import zipfile from operator import attrgetter from django.conf import settings @@ -16,7 +18,6 @@ from django.http import HttpResponseRedirect from django.http import JsonResponse from django.shortcuts import get_object_or_404 from django.shortcuts import render -from django.template.defaultfilters import floatformat from django.urls import reverse from django.utils import timezone from django.utils.functional import cached_property @@ -28,279 +29,212 @@ from django.utils.translation import gettext_lazy from django.views.decorators.http import require_POST from django.views.generic import DetailView from django.views.generic import ListView -from django.views import View from judge import event_poster as event from judge.highlight_code import highlight_code -from judge.models import ( - Contest, - ContestParticipation, - Language, - Problem, - ProblemTestCase, - ProblemTranslation, - Profile, - Submission, -) +from judge.models import Contest +from judge.models import Language +from judge.models import Problem +from judge.models import ProblemTestCase +from judge.models import ProblemTranslation +from judge.models import Profile +from judge.models import Submission from judge.utils.problems import get_result_data -from judge.utils.problem_data import get_problem_case -from judge.utils.raw_sql import join_sql_subquery, use_straight_join +from judge.utils.problems import user_authored_ids +from judge.utils.problems import user_completed_ids +from judge.utils.problems import user_editable_ids +from judge.utils.raw_sql import use_straight_join from judge.utils.views import DiggPaginatorMixin -from judge.utils.infinite_paginator import InfinitePaginationMixin from judge.utils.views import TitleMixin -from judge.utils.timedelta import nice_repr -from judge.views.contests import ContestMixin -from judge.caching import cache_wrapper def submission_related(queryset): - return queryset.select_related("user", "problem", "language").only( - "id", - "user__id", - "problem__name", - "problem__code", - "problem__is_public", - "language__short_name", - "language__key", - "date", - "time", - "memory", - "points", - "result", - "status", - "case_points", - "case_total", - "current_testcase", - "contest_object__key", - "contest_object__name", - ) + return queryset.select_related('user__user', 'problem', 'language') \ + .only('id', 'user__user__username', 'user__display_rank', 'user__rating', 'problem__name', + 'problem__code', 'problem__is_public', 'language__short_name', 'language__key', 'date', 'time', 'memory', + 'points', 'result', 'status', 'case_points', 'case_total', 'current_testcase', 'contest_object') class SubmissionMixin(object): model = Submission - context_object_name = "submission" - pk_url_kwarg = "submission" + context_object_name = 'submission' + pk_url_kwarg = 'submission' class SubmissionDetailBase(LoginRequiredMixin, TitleMixin, SubmissionMixin, DetailView): - queryset = Submission.objects.select_related( - "language", "problem", "user", "contest_object" - ).defer("problem__description", "user__about", "contest_object__description") - def get_object(self, queryset=None): submission = super(SubmissionDetailBase, self).get_object(queryset) - if submission.is_accessible_by(self.request.profile): + profile = self.request.profile + problem = submission.problem + if self.request.user.has_perm('judge.view_all_submission'): return submission - + if submission.user_id == profile.id: + return submission + if problem.is_editor(profile): + return submission + if problem.is_public or problem.testers.filter(id=profile.id).exists(): + if Submission.objects.filter(user_id=profile.id, result='AC', problem_id=problem.id, + points=problem.points).exists(): + return submission raise PermissionDenied() def get_title(self): submission = self.object - return _("Submission of %(problem)s by %(user)s") % { - "problem": submission.problem.translated_name(self.request.LANGUAGE_CODE), - "user": submission.user.username, + return _('Submission of %(problem)s by %(user)s') % { + 'problem': submission.problem.translated_name(self.request.LANGUAGE_CODE), + 'user': submission.user.user.username, } def get_content_title(self): submission = self.object - return mark_safe( - escape(_("Submission of %(problem)s by %(user)s")) - % { - "problem": format_html( - '{1}', - reverse("problem_detail", args=[submission.problem.code]), - submission.problem.translated_name(self.request.LANGUAGE_CODE), - ), - "user": format_html( - '{1}', - reverse("user_page", args=[submission.user.username]), - submission.user.username, - ), - } - ) + return mark_safe(escape(_('Submission of %(problem)s by %(user)s')) % { + 'problem': format_html('{1}', + reverse('problem_detail', args=[ + submission.problem.code]), + submission.problem.translated_name(self.request.LANGUAGE_CODE)), + 'user': format_html('{1}', + reverse('user_page', args=[ + submission.user.user.username]), + submission.user.user.username), + }) -def get_hidden_subtasks(request, submission): - contest = submission.contest_object - if contest and contest.is_editable_by(request.user): - return set() - if contest and contest.format.has_hidden_subtasks: - try: - return contest.format.get_hidden_subtasks().get( - str(submission.contest.problem.id), set() - ) - except Exception: - pass - return set() +class SubmissionSource(SubmissionDetailBase): + template_name = 'submission/source.html' + + def get_queryset(self): + return super().get_queryset().select_related('source') + + def get_context_data(self, **kwargs): + context = super(SubmissionSource, self).get_context_data(**kwargs) + submission = self.object + context['raw_source'] = submission.source.source.rstrip('\n') + context['highlighted_source'] = highlight_code( + submission.source.source, submission.language.pygments) + return context -def make_batch(batch, cases, include_cases=True): - result = {"id": batch} - if include_cases: - result["cases"] = cases +def make_batch(batch, cases): + result = {'id': batch, 'cases': cases} if batch: - result["points"] = sum(map(attrgetter("points"), cases)) - result["total"] = sum(map(attrgetter("total"), cases)) - result["AC"] = abs(result["points"] - result["total"]) < 1e-5 - + result['points'] = min(map(attrgetter('points'), cases)) + result['total'] = max(map(attrgetter('total'), cases)) return result -def group_test_cases(submission, hidden_subtasks, include_cases=True): - cases = submission.test_cases.exclude(batch__in=hidden_subtasks) +def group_test_cases(cases): result = [] buf = [] last = None for case in cases: if case.batch != last and buf: - result.append(make_batch(last, buf, include_cases)) + result.append(make_batch(last, buf)) buf = [] buf.append(case) last = case.batch if buf: - result.append(make_batch(last, buf, include_cases)) + result.append(make_batch(last, buf)) return result -def get_cases_data(submission): - testcases = ProblemTestCase.objects.filter(dataset=submission.problem).order_by( - "order" - ) +def get_visible_content(data): + data = data or b'' + data = data.replace(b'\r\n', b'\r').replace(b'\r', b'\n') + if (len(data) > settings.TESTCASE_VISIBLE_LENGTH): + data = data[:settings.TESTCASE_VISIBLE_LENGTH] + data += b'.' * 3 + elif not data.endswith(b'\n'): + data += b'\n' + return data.decode('utf-8') - if submission.is_pretested: - testcases = testcases.filter(is_pretest=True) - files = [] - for case in testcases: - if case.input_file: - files.append(case.input_file) - if case.output_file: - files.append(case.output_file) - case_data = get_problem_case(submission.problem, files) +def get_input_answer(case, archive): + result = {} + result['input'] = get_visible_content(archive.read(case.input_file)) + result['answer'] = get_visible_content(archive.read(case.output_file)) + return result - problem_data = {} - count = 0 - for case in testcases: - if case.type != "C": - continue - count += 1 - problem_data[count] = { - "input": case_data.get(case.input_file, "") if case.input_file else "", - "answer": case_data.get(case.output_file, "") if case.output_file else "", - } +def get_problem_data(submission): + archive_path = os.path.join(settings.DMOJ_PROBLEM_DATA_ROOT, + str(submission.problem.data_files.zipfile)) + if not os.path.exists(archive_path): + raise Exception( + 'archive file "%s" does not exist' % archive_path) + try: + archive = zipfile.ZipFile(archive_path, 'r') + except zipfile.BadZipfile: + raise Exception('bad archive: "%s"' % archive_path) + testcases = ProblemTestCase.objects.filter(dataset=submission.problem)\ + .order_by('order') + + problem_data = {case.order: get_input_answer(case, archive) + for case in testcases} return problem_data class SubmissionStatus(SubmissionDetailBase): - template_name = "submission/status.html" - - def can_see_testcases(self): - contest_submission = self.object.contest_or_none - if contest_submission is None: - return True - - contest_problem = contest_submission.problem - problem = self.object.problem - contest = self.object.contest_object - - if contest_problem.show_testcases: - return True - if problem.is_editable_by(self.request.user): - return True - if contest.is_editable_by(self.request.user): - return True - if not problem.is_public: - return False - if contest.is_in_contest(self.request.user): - return False - if not contest.ended: - return False - if contest_submission.participation.ended: - return True - return False + template_name = 'submission/status.html' def get_context_data(self, **kwargs): context = super(SubmissionStatus, self).get_context_data(**kwargs) submission = self.object - - context["hidden_subtasks"] = get_hidden_subtasks(self.request, self.object) - context["last_msg"] = event.last() - context["batches"] = group_test_cases( - submission, context["hidden_subtasks"], True - ) - context["time_limit"] = submission.problem.time_limit - context["can_see_testcases"] = False - context["highlighted_source"] = highlight_code( - submission.source.source, - submission.language.pygments, - linenos=True, - title=submission.language, - ) - - if self.can_see_testcases(): - context["cases_data"] = get_cases_data(submission) - context["can_see_testcases"] = True + context['last_msg'] = event.last() + context['batches'] = group_test_cases(submission.test_cases.all()) + context['time_limit'] = submission.problem.time_limit + context['cases_data'] = get_problem_data(submission) try: lang_limit = submission.problem.language_limits.get( - language=submission.language - ) + language=submission.language) except ObjectDoesNotExist: pass else: - context["time_limit"] = lang_limit.time_limit + context['time_limit'] = lang_limit.time_limit return context class SubmissionTestCaseQuery(SubmissionStatus): - template_name = "submission/status-testcases.html" + template_name = 'submission/status-testcases.html' def get(self, request, *args, **kwargs): - if "id" not in request.GET or not request.GET["id"].isdigit(): + if 'id' not in request.GET or not request.GET['id'].isdigit(): return HttpResponseBadRequest() self.kwargs[self.pk_url_kwarg] = kwargs[self.pk_url_kwarg] = int( - request.GET["id"] - ) + request.GET['id']) return super(SubmissionTestCaseQuery, self).get(request, *args, **kwargs) -class SubmissionSourceRaw(SubmissionDetailBase): +class SubmissionSourceRaw(SubmissionSource): def get(self, request, *args, **kwargs): submission = self.get_object() - return HttpResponse(submission.source.source, content_type="text/plain") + return HttpResponse(submission.source.source, content_type='text/plain') @require_POST def abort_submission(request, submission): submission = get_object_or_404(Submission, id=int(submission)) - # if (not request.user.is_authenticated or (submission.was_rejudged or (request.profile != submission.user)) and - # not request.user.has_perm('abort_any_submission')): - # raise PermissionDenied() - if not request.user.is_authenticated or not request.user.has_perm( - "abort_any_submission" - ): + if (not request.user.is_authenticated or (submission.was_rejudged or (request.profile != submission.user)) and + not request.user.has_perm('abort_any_submission')): raise PermissionDenied() submission.abort() - return HttpResponseRedirect(reverse("submission_status", args=(submission.id,))) + return HttpResponseRedirect(reverse('submission_status', args=(submission.id,))) class SubmissionsListBase(DiggPaginatorMixin, TitleMixin, ListView): model = Submission paginate_by = 50 show_problem = True - title = gettext_lazy("All submissions") - content_title = gettext_lazy("All submissions") - page_type = "all_submissions_list" - template_name = "submission/list.html" - context_object_name = "submissions" + title = gettext_lazy('All submissions') + content_title = gettext_lazy('All submissions') + tab = 'all_submissions_list' + template_name = 'submission/list.html' + context_object_name = 'submissions' first_page_href = None - include_frozen = False - organization = None def get_result_data(self): result = self._get_result_data() - for category in result["categories"]: - category["name"] = _(category["name"]) + for category in result['categories']: + category['name'] = _(category['name']) return result def _get_result_data(self): @@ -309,170 +243,100 @@ class SubmissionsListBase(DiggPaginatorMixin, TitleMixin, ListView): def access_check(self, request): pass - def hide_contest_in_row(self): - return self.request.in_contest_mode - @cached_property def in_contest(self): - return ( - self.request.user.is_authenticated - and self.request.profile.current_contest is not None - and self.request.in_contest_mode - ) + return self.request.user.is_authenticated and self.request.profile.current_contest is not None @cached_property def contest(self): return self.request.profile.current_contest.contest - def _get_entire_queryset(self): - organization = self.organization or self.request.organization - if organization: - queryset = Submission.objects.filter( - contest_object__organizations=organization - ) - else: - queryset = Submission.objects.all() + def _get_queryset(self): + queryset = Submission.objects.all() use_straight_join(queryset) - queryset = submission_related(queryset.order_by("-id")) + queryset = submission_related(queryset.order_by('-id')) if self.show_problem: - queryset = queryset.prefetch_related( - Prefetch( - "problem__translations", - queryset=ProblemTranslation.objects.filter( - language=self.request.LANGUAGE_CODE - ), - to_attr="_trans", - ) - ) + queryset = queryset.prefetch_related(Prefetch('problem__translations', + queryset=ProblemTranslation.objects.filter( + language=self.request.LANGUAGE_CODE), to_attr='_trans')) if self.in_contest: - queryset = queryset.filter(contest_object=self.contest) - if not self.contest.can_see_full_scoreboard(self.request.user): - queryset = queryset.filter(user=self.request.profile) - if ( - self.contest.format.has_hidden_subtasks - and not self.contest.is_editable_by(self.request.user) - ): - queryset = queryset.filter(user=self.request.profile) - if self.contest.freeze_after and not self.include_frozen: - queryset = queryset.exclude( - ~Q(user=self.request.profile), - date__gte=self.contest.freeze_after + self.contest.start_time, - ) + queryset = queryset.filter( + contest__participation__contest_id=self.contest.id) + if self.contest.hide_scoreboard and self.contest.is_in_contest(self.request.user): + queryset = queryset.filter( + contest__participation__user=self.request.profile) else: - queryset = queryset.select_related("contest_object").defer( - "contest_object__description" - ) + queryset = queryset.select_related( + 'contest_object').defer('contest_object__description') # This is not technically correct since contest organizers *should* see these, but # the join would be far too messy - if not self.request.user.has_perm("judge.see_private_contest"): - # Show submissions for any contest you can edit or visible scoreboard - contest_queryset = Contest.objects.filter( - Q(authors=self.request.profile) - | Q(curators=self.request.profile) - | Q(scoreboard_visibility=Contest.SCOREBOARD_VISIBLE) - | Q(end_time__lt=timezone.now()) - ).distinct() - queryset = queryset.filter( - Q(user=self.request.profile) - | Q(contest_object__in=contest_queryset) - | Q(contest_object__isnull=True) - ) + if not self.request.user.has_perm('judge.see_private_contest'): + queryset = queryset.exclude( + contest_object_id__in=Contest.objects.filter(hide_scoreboard=True)) if self.selected_languages: - queryset = queryset.filter(language__in=self.selected_languages) + queryset = queryset.filter( + language_id__in=Language.objects.filter(key__in=self.selected_languages)) if self.selected_statuses: - submission_results = [i for i, _ in Submission.RESULT] - if self.selected_statuses[0] in submission_results: - queryset = queryset.filter(result__in=self.selected_statuses) - else: - queryset = queryset.filter(status__in=self.selected_statuses) + queryset = queryset.filter(result__in=self.selected_statuses) return queryset def get_queryset(self): - queryset = self._get_entire_queryset() + queryset = self._get_queryset() if not self.in_contest: - join_sql_subquery( - queryset, - subquery=str( - Problem.get_visible_problems(self.request.user) - .distinct() - .only("id") - .query - ), - params=[], - join_fields=[("problem_id", "id")], - alias="visible_problems", - related_model=Problem, - ) + if not self.request.user.has_perm('judge.see_private_problem'): + queryset = queryset.filter(problem__is_public=True) + if not self.request.user.has_perm('judge.see_organization_problem'): + filter = Q(problem__is_organization_private=False) + if self.request.user.is_authenticated: + filter |= Q( + problem__organizations__in=self.request.profile.organizations.all()) + queryset = queryset.filter(filter) return queryset def get_my_submissions_page(self): return None - def get_friend_submissions_page(self): - return None - def get_all_submissions_page(self): - return reverse("all_submissions") + return reverse('all_submissions') def get_searchable_status_codes(self): - all_statuses = list(Submission.RESULT) - all_statuses.extend([i for i in Submission.STATUS if i not in all_statuses]) - hidden_codes = ["SC", "D", "G"] + hidden_codes = ['SC'] if not self.request.user.is_superuser and not self.request.user.is_staff: - hidden_codes += ["IE"] - return [(key, value) for key, value in all_statuses if key not in hidden_codes] - - def in_hidden_subtasks_contest(self): - return ( - self.in_contest - and self.contest.format.has_hidden_subtasks - and not self.contest.is_editable_by(self.request.user) - ) - - def modify_attrs(self, submission): - # Used to modify submission's info in contest with hidden subtasks - batches = group_test_cases( - submission, get_hidden_subtasks(self.request, submission), False - ) - setattr(submission, "case_points", sum([i.get("points", 0) for i in batches])) - setattr(submission, "batches", batches) - if submission.status in ("IE", "CE", "AB"): - setattr(submission, "_result_class", submission.result_class) - else: - setattr(submission, "_result_class", "TLE") + hidden_codes += ['IE'] + return [(key, value) for key, value in Submission.RESULT if key not in hidden_codes] def get_context_data(self, **kwargs): context = super(SubmissionsListBase, self).get_context_data(**kwargs) authenticated = self.request.user.is_authenticated - context["dynamic_update"] = False - context["show_problem"] = self.show_problem - context["profile"] = self.request.profile - context["all_languages"] = Language.objects.all().values_list("key", "name") - context["selected_languages"] = self.selected_languages_key - context["all_statuses"] = self.get_searchable_status_codes() - context["selected_statuses"] = self.selected_statuses - context["can_show_result_data"] = not self.in_hidden_subtasks_contest() - context["page_suffix"] = suffix = ( - ("?" + self.request.GET.urlencode()) if self.request.GET else "" - ) - context["first_page_href"] = (self.first_page_href or ".") + suffix - context["my_submissions_link"] = self.get_my_submissions_page() - context["friend_submissions_link"] = self.get_friend_submissions_page() - context["all_submissions_link"] = self.get_all_submissions_page() - context["page_type"] = self.page_type - context["hide_contest_in_row"] = self.hide_contest_in_row() + context['dynamic_update'] = False + context['show_problem'] = self.show_problem + context['completed_problem_ids'] = user_completed_ids( + self.request.profile) if authenticated else [] + context['authored_problem_ids'] = user_authored_ids( + self.request.profile) if authenticated else [] + context['editable_problem_ids'] = user_editable_ids( + self.request.profile) if authenticated else [] - context["in_hidden_subtasks_contest"] = self.in_hidden_subtasks_contest() - if context["in_hidden_subtasks_contest"]: - for submission in context["submissions"]: - self.modify_attrs(submission) - context[ - "is_in_editable_contest" - ] = self.in_contest and self.contest.is_editable_by(self.request.user) + context['all_languages'] = Language.objects.all( + ).values_list('key', 'name') + context['selected_languages'] = self.selected_languages + context['all_statuses'] = self.get_searchable_status_codes() + context['selected_statuses'] = self.selected_statuses + + context['results_json'] = mark_safe(json.dumps(self.get_result_data())) + context['results_colors_json'] = mark_safe( + json.dumps(settings.DMOJ_STATS_SUBMISSION_RESULT_COLORS)) + + context['page_suffix'] = suffix = ( + '?' + self.request.GET.urlencode()) if self.request.GET else '' + context['first_page_href'] = (self.first_page_href or '.') + suffix + context['my_submissions_link'] = self.get_my_submissions_page() + context['all_submissions_link'] = self.get_all_submissions_page() + context['tab'] = self.tab return context def get(self, request, *args, **kwargs): @@ -480,211 +344,120 @@ class SubmissionsListBase(DiggPaginatorMixin, TitleMixin, ListView): if check is not None: return check - self.selected_languages = request.GET.getlist("language") - self.selected_statuses = request.GET.getlist("status") - self.selected_languages_key = [] + self.selected_languages = set(request.GET.getlist('language')) + self.selected_statuses = set(request.GET.getlist('status')) - if self.selected_languages: - languages = Language.objects.filter(key__in=self.selected_languages).values( - "id", "key" - ) - self.selected_languages = [i["id"] for i in languages] - self.selected_languages_key = [i["key"] for i in languages] - if self.selected_statuses: - allowed_statuses = [i for i, _ in Submission.RESULT + Submission.STATUS] - self.selected_statuses = [ - i for i in self.selected_statuses if i in allowed_statuses - ] - - if self.in_contest and self.contest.is_editable_by(self.request.user): - self.include_frozen = True - - if "results" in request.GET: - response = {} - if not self.in_hidden_subtasks_contest(): - response["results_json"] = self.get_result_data() - response[ - "results_colors_json" - ] = settings.DMOJ_STATS_SUBMISSION_RESULT_COLORS - else: - response["results_json"] = None - return JsonResponse(response) + if 'results' in request.GET: + return JsonResponse(self.get_result_data()) return super(SubmissionsListBase, self).get(request, *args, **kwargs) class UserMixin(object): def get(self, request, *args, **kwargs): - if "user" not in kwargs and "participation" not in kwargs: - raise ImproperlyConfigured("Must pass a user or participation") - if "user" in kwargs: - self.profile = get_object_or_404(Profile, user__username=kwargs["user"]) - self.username = kwargs["user"] - else: - self.participation = get_object_or_404( - ContestParticipation, id=kwargs["participation"] - ) - self.profile = self.participation.user - self.username = self.profile.user.username - if self.profile == request.profile: - self.include_frozen = True + if 'user' not in kwargs: + raise ImproperlyConfigured('Must pass a user') + self.profile = get_object_or_404( + Profile, user__username=kwargs['user']) + self.username = kwargs['user'] return super(UserMixin, self).get(request, *args, **kwargs) class ConditionalUserTabMixin(object): def get_context_data(self, **kwargs): - context = super(ConditionalUserTabMixin, self).get_context_data(**kwargs) + context = super(ConditionalUserTabMixin, + self).get_context_data(**kwargs) if self.request.user.is_authenticated and self.request.profile == self.profile: - context["page_type"] = "my_submissions_tab" + context['tab'] = 'my_submissions_tab' else: - context["page_type"] = "user_submissions_tab" - context["tab_username"] = self.profile.user.username + context['tab'] = 'user_submissions_tab' + context['tab_username'] = self.profile.user.username return context -class GeneralSubmissions(SubmissionsListBase): - def get_my_submissions_page(self): - if self.request.user.is_authenticated: - return reverse( - "all_user_submissions", kwargs={"user": self.request.user.username} - ) - return None - - def get_friend_submissions_page(self): - if self.request.user.is_authenticated: - return reverse("all_friend_submissions") - return None - - -class AllUserSubmissions(ConditionalUserTabMixin, UserMixin, GeneralSubmissions): +class AllUserSubmissions(ConditionalUserTabMixin, UserMixin, SubmissionsListBase): def get_queryset(self): - return ( - super(AllUserSubmissions, self) - .get_queryset() - .filter(user_id=self.profile.id) - ) + return super(AllUserSubmissions, self).get_queryset().filter(user_id=self.profile.id) def get_title(self): if self.request.user.is_authenticated and self.request.profile == self.profile: - return _("All my submissions") - return _("All submissions by %s") % self.username + return _('All my submissions') + return _('All submissions by %s') % self.username def get_content_title(self): if self.request.user.is_authenticated and self.request.profile == self.profile: - return format_html(_("All my submissions")) - return format_html( - _('All submissions by {0}'), - self.username, - reverse("user_page", args=[self.username]), - ) + return format_html('All my submissions') + return format_html('All submissions by {0}', self.username, + reverse('user_page', args=[self.username])) + + def get_my_submissions_page(self): + if self.request.user.is_authenticated: + return reverse('all_user_submissions', kwargs={'user': self.request.user.username}) def get_context_data(self, **kwargs): context = super(AllUserSubmissions, self).get_context_data(**kwargs) - context["dynamic_update"] = context["page_obj"].number == 1 - context["dynamic_user_id"] = self.profile.id - context["last_msg"] = event.last() - return context - - -class AllFriendSubmissions( - LoginRequiredMixin, InfinitePaginationMixin, GeneralSubmissions -): - def get_queryset(self): - friends = self.request.profile.get_friends() - return ( - super(AllFriendSubmissions, self).get_queryset().filter(user_id__in=friends) - ) - - def get_title(self): - return _("All friend submissions") - - def get_context_data(self, **kwargs): - context = super(AllFriendSubmissions, self).get_context_data(**kwargs) - context["dynamic_update"] = False - context["page_type"] = "friend_tab" + context['dynamic_update'] = context['page_obj'].number == 1 + context['dynamic_user_id'] = self.profile.id + context['last_msg'] = event.last() return context class ProblemSubmissionsBase(SubmissionsListBase): show_problem = False dynamic_update = True - check_contest_in_access_check = False + check_contest_in_access_check = True def get_queryset(self): - if ( - self.in_contest - and not self.contest.contest_problems.filter( - problem_id=self.problem.id - ).exists() - ): + if self.in_contest and not self.contest.contest_problems.filter(problem_id=self.problem.id).exists(): raise Http404() - return ( - super(ProblemSubmissionsBase, self) - ._get_entire_queryset() - .filter(problem_id=self.problem.id) - ) + return super(ProblemSubmissionsBase, self)._get_queryset().filter(problem_id=self.problem.id) def get_title(self): - return _("All submissions for %s") % self.problem_name + return _('All submissions for %s') % self.problem_name def get_content_title(self): - return format_html( - 'All submissions for {0}', - self.problem_name, - reverse("problem_detail", args=[self.problem.code]), - ) + return format_html('All submissions for {0}', self.problem_name, + reverse('problem_detail', args=[self.problem.code])) def access_check_contest(self, request): - if self.in_contest: - if not self.contest.can_see_own_scoreboard(request.user): - raise Http404() - if not self.contest.is_accessible_by(request.user): - raise Http404() + if self.in_contest and not self.contest.can_see_scoreboard(request.user): + raise Http404() def access_check(self, request): + if not self.problem.is_accessible_by(request.user): + raise Http404() + if self.check_contest_in_access_check: self.access_check_contest(request) - else: - is_own = hasattr(self, "is_own") and self.is_own - if not is_own and not self.problem.is_accessible_by( - request.user, request.in_contest_mode - ): - raise Http404() def get(self, request, *args, **kwargs): - if "problem" not in kwargs: - raise ImproperlyConfigured(_("Must pass a problem")) - self.problem = get_object_or_404(Problem, code=kwargs["problem"]) - self.problem_name = self.problem.translated_name(self.request.LANGUAGE_CODE) + if 'problem' not in kwargs: + raise ImproperlyConfigured(_('Must pass a problem')) + self.problem = get_object_or_404(Problem, code=kwargs['problem']) + self.problem_name = self.problem.translated_name( + self.request.LANGUAGE_CODE) return super(ProblemSubmissionsBase, self).get(request, *args, **kwargs) def get_all_submissions_page(self): - return reverse( - "chronological_submissions", kwargs={"problem": self.problem.code} - ) + return reverse('chronological_submissions', kwargs={'problem': self.problem.code}) def get_context_data(self, **kwargs): - context = super(ProblemSubmissionsBase, self).get_context_data(**kwargs) + context = super(ProblemSubmissionsBase, + self).get_context_data(**kwargs) if self.dynamic_update: - context["dynamic_update"] = context["page_obj"].number == 1 - context["dynamic_problem_id"] = self.problem.id - context["last_msg"] = event.last() - context["best_submissions_link"] = reverse( - "ranked_submissions", kwargs={"problem": self.problem.code} - ) + context['dynamic_update'] = context['page_obj'].number == 1 + context['dynamic_problem_id'] = self.problem.id + context['last_msg'] = event.last() + context['best_submissions_link'] = reverse('ranked_submissions', kwargs={ + 'problem': self.problem.code}) return context class ProblemSubmissions(ProblemSubmissionsBase): def get_my_submissions_page(self): if self.request.user.is_authenticated: - return reverse( - "user_submissions", - kwargs={ - "problem": self.problem.code, - "user": self.request.user.username, - }, - ) + return reverse('user_submissions', kwargs={'problem': self.problem.code, + 'user': self.request.user.username}) class UserProblemSubmissions(ConditionalUserTabMixin, UserMixin, ProblemSubmissions): @@ -692,9 +465,7 @@ class UserProblemSubmissions(ConditionalUserTabMixin, UserMixin, ProblemSubmissi @cached_property def is_own(self): - return ( - self.request.user.is_authenticated and self.request.profile == self.profile - ) + return self.request.user.is_authenticated and self.request.profile == self.profile def access_check(self, request): super(UserProblemSubmissions, self).access_check(request) @@ -703,106 +474,87 @@ class UserProblemSubmissions(ConditionalUserTabMixin, UserMixin, ProblemSubmissi self.access_check_contest(request) def get_queryset(self): - return ( - super(UserProblemSubmissions, self) - .get_queryset() - .filter(user_id=self.profile.id) - ) + return super(UserProblemSubmissions, self).get_queryset().filter(user_id=self.profile.id) def get_title(self): if self.is_own: - return _("My submissions for %(problem)s") % {"problem": self.problem_name} - return _("%(user)s's submissions for %(problem)s") % { - "user": self.username, - "problem": self.problem_name, - } + return _("My submissions for %(problem)s") % {'problem': self.problem_name} + return _("%(user)s's submissions for %(problem)s") % {'user': self.username, 'problem': self.problem_name} def get_content_title(self): if self.request.user.is_authenticated and self.request.profile == self.profile: - return format_html( - """My submissions for {2}""", - self.username, - reverse("user_page", args=[self.username]), - self.problem_name, - reverse("problem_detail", args=[self.problem.code]), - ) - return format_html( - """{0}'s submissions for {2}""", - self.username, - reverse("user_page", args=[self.username]), - self.problem_name, - reverse("problem_detail", args=[self.problem.code]), - ) + return format_html('''My submissions for {2}''', + self.username, reverse( + 'user_page', args=[self.username]), + self.problem_name, reverse('problem_detail', args=[self.problem.code])) + return format_html('''{0}'s submissions for {2}''', + self.username, reverse( + 'user_page', args=[self.username]), + self.problem_name, reverse('problem_detail', args=[self.problem.code])) def get_context_data(self, **kwargs): - context = super(UserProblemSubmissions, self).get_context_data(**kwargs) - context["dynamic_user_id"] = self.profile.id + context = super(UserProblemSubmissions, + self).get_context_data(**kwargs) + context['dynamic_user_id'] = self.profile.id return context def single_submission(request, submission_id, show_problem=True): request.no_profile_update = True authenticated = request.user.is_authenticated - submission = get_object_or_404( - submission_related(Submission.objects.all()), id=int(submission_id) - ) - - is_in_editable_contest = False - if authenticated and request.in_contest_mode: - contest = request.profile.current_contest.contest - is_in_editable_contest = contest.is_editable_by(request.user) + submission = get_object_or_404(submission_related( + Submission.objects.all()), id=int(submission_id)) if not submission.problem.is_accessible_by(request.user): raise Http404() - return render( - request, - "submission/row.html", - { - "submission": submission, - "show_problem": show_problem, - "problem_name": show_problem - and submission.problem.translated_name(request.LANGUAGE_CODE), - "profile": request.profile if authenticated else None, - "is_in_editable_contest": is_in_editable_contest, - }, - ) + return render(request, 'submission/row.html', { + 'submission': submission, + 'authored_problem_ids': user_authored_ids(request.profile) if authenticated else [], + 'completed_problem_ids': user_completed_ids(request.profile) if authenticated else [], + 'editable_problem_ids': user_editable_ids(request.profile) if authenticated else [], + 'show_problem': show_problem, + 'problem_name': show_problem and submission.problem.translated_name(request.LANGUAGE_CODE), + 'profile_id': request.profile.id if authenticated else 0, + }) def single_submission_query(request): request.no_profile_update = True - if "id" not in request.GET or not request.GET["id"].isdigit(): + if 'id' not in request.GET or not request.GET['id'].isdigit(): return HttpResponseBadRequest() try: - show_problem = int(request.GET.get("show_problem", "1")) + show_problem = int(request.GET.get('show_problem', '1')) except ValueError: return HttpResponseBadRequest() - return single_submission(request, int(request.GET["id"]), bool(show_problem)) + return single_submission(request, int(request.GET['id']), bool(show_problem)) -class AllSubmissions(InfinitePaginationMixin, GeneralSubmissions): +class AllSubmissions(SubmissionsListBase): stats_update_interval = 3600 - @property - def use_infinite_pagination(self): - return not self.in_contest + def get_my_submissions_page(self): + if self.request.user.is_authenticated: + return reverse('all_user_submissions', kwargs={'user': self.request.user.username}) def get_context_data(self, **kwargs): context = super(AllSubmissions, self).get_context_data(**kwargs) - context["dynamic_update"] = ( - context["page_obj"].number == 1 - ) and not self.request.organization - context["last_msg"] = event.last() - context["stats_update_interval"] = self.stats_update_interval + context['dynamic_update'] = context['page_obj'].number == 1 + context['last_msg'] = event.last() + context['stats_update_interval'] = self.stats_update_interval return context def _get_result_data(self): - if self.request.organization or self.in_contest: + if self.in_contest or self.selected_languages or self.selected_statuses: return super(AllSubmissions, self)._get_result_data() - return _get_global_submission_result_data( - self.selected_statuses, self.selected_languages - ) + key = 'global_submission_result_data' + result = cache.get(key) + if result: + return result + result = super(AllSubmissions, self)._get_result_data() + cache.set(key, result, self.stats_update_interval) + return result class ForceContestMixin(object): @@ -817,76 +569,28 @@ class ForceContestMixin(object): def access_check(self, request): super(ForceContestMixin, self).access_check(request) - if not request.user.has_perm("judge.see_private_contest"): + if not request.user.has_perm('judge.see_private_contest'): if not self.contest.is_visible: raise Http404() - if ( - self.contest.start_time is not None - and self.contest.start_time > timezone.now() - ): + if self.contest.start_time is not None and self.contest.start_time > timezone.now(): raise Http404() def get_problem_number(self, problem): - return ( - self.contest.contest_problems.select_related("problem") - .get(problem=problem) - .order - ) + return self.contest.contest_problems.select_related('problem').get(problem=problem).order def get(self, request, *args, **kwargs): - if "contest" not in kwargs: - raise ImproperlyConfigured(_("Must pass a contest")) - self._contest = get_object_or_404(Contest, key=kwargs["contest"]) + if 'contest' not in kwargs: + raise ImproperlyConfigured(_('Must pass a contest')) + self._contest = get_object_or_404(Contest, key=kwargs['contest']) return super(ForceContestMixin, self).get(request, *args, **kwargs) -class ContestSubmissions( - LoginRequiredMixin, ContestMixin, ForceContestMixin, SubmissionsListBase -): - check_contest_in_access_check = True - template_name = "contest/submissions.html" - context_object_name = "submissions" - - def hide_contest_in_row(self): - return True - - def access_check(self, request): - super().contest_access_check(self.contest) - super().access_check(request) - - def get_title(self): - return _("Submissions in") + " " + self.contest.name - - def get_content_title(self): - return format_html( - _('Submissions in {1}'), - reverse("contest_view", args=[self.contest.key]), - self.contest.name, - ) - - def get_context_data(self, **kwargs): - self.object = self.contest - context = super(ContestSubmissions, self).get_context_data(**kwargs) - context["contest"] = self.contest - context["page_type"] = "submissions" - return context - - class UserContestSubmissions(ForceContestMixin, UserProblemSubmissions): - check_contest_in_access_check = True - def get_title(self): if self.problem.is_accessible_by(self.request.user): - return "%s's submissions for %s in %s" % ( - self.username, - self.problem_name, - self.contest.name, - ) + return "%s's submissions for %s in %s" % (self.username, self.problem_name, self.contest.name) return "%s's submissions for problem %s in %s" % ( - self.username, - self.get_problem_number(self.problem), - self.contest.name, - ) + self.username, self.get_problem_number(self.problem), self.contest.name) def access_check(self, request): super(UserContestSubmissions, self).access_check(request) @@ -895,181 +599,16 @@ class UserContestSubmissions(ForceContestMixin, UserProblemSubmissions): def get_content_title(self): if self.problem.is_accessible_by(self.request.user): - return format_html( - _( - '{0}\'s submissions for ' - '{2} in {4}' - ), - self.username, - reverse("user_page", args=[self.username]), - self.problem_name, - reverse("problem_detail", args=[self.problem.code]), - self.contest.name, - reverse("contest_view", args=[self.contest.key]), - ) - return format_html( - _( - '{0}\'s submissions for ' - 'problem {2} in {3}' - ), - self.username, - reverse("user_page", args=[self.username]), - self.get_problem_number(self.problem), - self.contest.name, - reverse("contest_view", args=[self.contest.key]), - ) - - -class UserContestSubmissionsAjax(UserContestSubmissions): - template_name = "submission/user-ajax.html" - - def contest_time(self, s): - if s.contest.participation.live: - if self.contest.time_limit: - return s.date - s.contest.participation.real_start - return s.date - self.contest.start_time - return None - - def get_best_subtask_points(self): - if self.contest.format.has_hidden_subtasks: - contest_problem = self.contest.contest_problems.get(problem=self.problem) - best_subtasks = {} - total_points = 0 - problem_points = 0 - achieved_points = 0 - hidden_subtasks = self.contest.format.get_hidden_subtasks() - - for ( - problem_id, - pp, - time, - subtask_points, - total_subtask_points, - subtask, - sub_id, - ) in self.contest.format.get_results_by_subtask( - self.participation, self.include_frozen - ): - if contest_problem.id != problem_id or total_subtask_points == 0: - continue - if not subtask: - subtask = 0 - problem_points = pp - submission = Submission.objects.get(id=sub_id) - if subtask in hidden_subtasks.get( - str(problem_id), set() - ) and not self.contest.is_editable_by(self.request.user): - best_subtasks[subtask] = { - "submission": None, - "contest_time": None, - "points": "???", - "total": total_subtask_points, - } - else: - best_subtasks[subtask] = { - "submission": submission, - "contest_time": nice_repr( - self.contest_time(submission), "noday" - ), - "points": subtask_points, - "total": total_subtask_points, - } - achieved_points += subtask_points - total_points += total_subtask_points - for subtask in best_subtasks.values(): - if subtask["points"] != "???": - subtask["points"] = floatformat( - subtask["points"] / total_points * problem_points, - -self.contest.points_precision, - ) - subtask["total"] = floatformat( - subtask["total"] / total_points * problem_points, - -self.contest.points_precision, - ) - if total_points > 0 and best_subtasks: - achieved_points = achieved_points / total_points * problem_points - return best_subtasks, achieved_points, problem_points - return None - - def get_context_data(self, **kwargs): - context = super(UserContestSubmissionsAjax, self).get_context_data(**kwargs) - context["contest"] = self.contest - context["problem"] = self.problem - context["profile"] = self.profile - - contest_problem = self.contest.contest_problems.get(problem=self.problem) - filtered_submissions = [] - - # Only show this for some users when using ioi16 - if not self.contest.format.has_hidden_subtasks or self.contest.is_editable_by( - self.request.user - ): - for s in context["submissions"]: - if not hasattr(s, "contest"): - continue - contest_time = self.contest_time(s) - if contest_time: - s.contest_time = nice_repr(contest_time, "noday") - else: - s.contest_time = None - total = floatformat( - contest_problem.points, -self.contest.points_precision - ) - points = floatformat(s.contest.points, -self.contest.points_precision) - s.display_point = f"{points} / {total}" - filtered_submissions.append(s) - context["submissions"] = filtered_submissions - else: - context["submissions"] = None - - best_subtasks = self.get_best_subtask_points() - if best_subtasks: - ( - context["best_subtasks"], - context["points"], - context["total"], - ) = best_subtasks - if context["points"] != "???": - context["points"] = floatformat( - context["points"], -self.contest.points_precision - ) - context["total"] = floatformat( - context["total"], -self.contest.points_precision - ) - context["subtasks"] = sorted(context["best_subtasks"].keys()) - return context - - def get(self, request, *args, **kwargs): - try: - return super(UserContestSubmissionsAjax, self).get(request, *args, **kwargs) - except Http404: - return HttpResponse(_("You don't have permission to access.")) - - -class SubmissionSourceFileView(View): - def get(self, request, filename): - filepath = os.path.join(settings.DMOJ_SUBMISSION_ROOT, filename) - if not os.path.exists(filepath): - raise Http404("File not found") - response = HttpResponse() - with open(filepath, "rb") as f: - response.content = f.read() - response["Content-Type"] = "application/octet-stream" - response["Content-Disposition"] = "attachment; filename=%s" % (filename,) - return response - - -@cache_wrapper(prefix="gsrd", timeout=3600, expected_type=dict) -def _get_global_submission_result_data(statuses, languages): - queryset = Submission.objects - if languages: - queryset = queryset.filter( - language__in=Language.objects.filter(id__in=languages) - ) - if statuses: - submission_results = [i for i, _ in Submission.RESULT] - if statuses[0] in submission_results: - queryset = queryset.filter(result__in=statuses) - else: - queryset = queryset.filter(status__in=statuses) - return get_result_data(queryset) + return format_html(_('{0}\'s submissions for ' + '{2} in {4}'), + self.username, reverse( + 'user_page', args=[self.username]), + self.problem_name, reverse( + 'problem_detail', args=[self.problem.code]), + self.contest.name, reverse('contest_view', args=[self.contest.key])) + return format_html(_('{0}\'s submissions for ' + 'problem {2} in {3}'), + self.username, reverse( + 'user_page', args=[self.username]), + self.get_problem_number(self.problem), + self.contest.name, reverse('contest_view', args=[self.contest.key])) diff --git a/judge/views/tasks.py b/judge/views/tasks.py index a1c0644..42e123f 100644 --- a/judge/views/tasks.py +++ b/judge/views/tasks.py @@ -4,12 +4,7 @@ from uuid import UUID from celery.result import AsyncResult from django.core.exceptions import PermissionDenied -from django.http import ( - Http404, - HttpResponseBadRequest, - HttpResponseRedirect, - JsonResponse, -) +from django.http import Http404, HttpResponseBadRequest, HttpResponseRedirect, JsonResponse from django.shortcuts import render from django.urls import reverse from django.utils.http import is_safe_url @@ -22,19 +17,14 @@ from judge.utils.views import short_circuit_middleware def get_task_status(task_id): result = AsyncResult(task_id) info = result.result - if result.state == "PROGRESS": - return { - "code": "PROGRESS", - "done": info["done"], - "total": info["total"], - "stage": info["stage"], - } - elif result.state == "SUCCESS": - return {"code": "SUCCESS"} - elif result.state == "FAILURE": - return {"code": "FAILURE", "error": str(info)} + if result.state == 'PROGRESS': + return {'code': 'PROGRESS', 'done': info['done'], 'total': info['total'], 'stage': info['stage']} + elif result.state == 'SUCCESS': + return {'code': 'SUCCESS'} + elif result.state == 'FAILURE': + return {'code': 'FAILURE', 'error': str(info)} else: - return {"code": "WORKING"} + return {'code': 'WORKING'} def task_status(request, task_id): @@ -43,48 +33,34 @@ def task_status(request, task_id): except ValueError: raise Http404() - redirect = request.GET.get("redirect") + redirect = request.GET.get('redirect') if not is_safe_url(redirect, allowed_hosts={request.get_host()}): redirect = None status = get_task_status(task_id) - if status["code"] == "SUCCESS" and redirect: + if status['code'] == 'SUCCESS' and redirect: return HttpResponseRedirect(redirect) - return render( - request, - "task_status.html", - { - "task_id": task_id, - "task_status": json.dumps(status), - "message": request.GET.get("message", ""), - "redirect": redirect or "", - }, - ) + return render(request, 'task_status.html', { + 'task_id': task_id, 'task_status': json.dumps(status), + 'message': request.GET.get('message', ''), 'redirect': redirect or '', + }) @short_circuit_middleware def task_status_ajax(request): - if "id" not in request.GET: - return HttpResponseBadRequest( - 'Need to pass GET parameter "id"', content_type="text/plain" - ) - return JsonResponse(get_task_status(request.GET["id"])) + if 'id' not in request.GET: + return HttpResponseBadRequest('Need to pass GET parameter "id"', content_type='text/plain') + return JsonResponse(get_task_status(request.GET['id'])) def demo_task(request, task, message): if not request.user.is_superuser: raise PermissionDenied() result = task.delay() - return redirect_to_task_status(result, message=message, redirect=reverse("home")) + return redirect_to_task_status(result, message=message, redirect=reverse('home')) -demo_success = partial( - demo_task, task=success, message="Running example task that succeeds..." -) -demo_failure = partial( - demo_task, task=failure, message="Running example task that fails..." -) -demo_progress = partial( - demo_task, task=progress, message="Running example task that waits 10 seconds..." -) +demo_success = partial(demo_task, task=success, message='Running example task that succeeds...') +demo_failure = partial(demo_task, task=failure, message='Running example task that fails...') +demo_progress = partial(demo_task, task=progress, message='Running example task that waits 10 seconds...') diff --git a/judge/views/test_formatter/test_formatter.py b/judge/views/test_formatter/test_formatter.py deleted file mode 100644 index 4818bcc..0000000 --- a/judge/views/test_formatter/test_formatter.py +++ /dev/null @@ -1,207 +0,0 @@ -from django.views import View -from django.shortcuts import render, redirect, get_object_or_404 -from django.urls import reverse -from django.core.files import File -from django.core.files.base import ContentFile -from django.http import ( - FileResponse, - HttpResponseRedirect, - HttpResponseBadRequest, - HttpResponse, -) -from judge.models import TestFormatterModel -from judge.forms import TestFormatterForm -from judge.views.test_formatter import tf_logic, tf_utils -from django.utils.translation import gettext_lazy as _ -from zipfile import ZipFile, ZIP_DEFLATED - -import os -import uuid -from dmoj import settings - - -def id_to_path(id): - return os.path.join(settings.MEDIA_ROOT, "test_formatter/" + id + "/") - - -def get_names_in_archive(file_path): - suffixes = ("inp", "out", "INP", "OUT") - with ZipFile(os.path.join(settings.MEDIA_ROOT, file_path)) as f: - result = [ - x for x in f.namelist() if not x.endswith("/") and x.endswith(suffixes) - ] - return list(sorted(result, key=tf_utils.natural_sorting_key)) - - -def get_renamed_archive(file_str, file_name, file_path, bef, aft): - target_file_id = str(uuid.uuid4()) - source_path = os.path.join(settings.MEDIA_ROOT, file_str) - target_path = os.path.join(settings.MEDIA_ROOT, file_str + "_" + target_file_id) - new_path = os.path.join(settings.MEDIA_ROOT, "test_formatter/" + file_name) - - source = ZipFile(source_path, "r") - target = ZipFile(target_path, "w", ZIP_DEFLATED) - - for bef_name, aft_name in zip(bef, aft): - target.writestr(aft_name, source.read(bef_name)) - - os.remove(source_path) - os.rename(target_path, new_path) - - target.close() - source.close() - - return {"file_path": "test_formatter/" + file_name} - - -class TestFormatter(View): - form_class = TestFormatterForm() - - def get(self, request): - return render( - request, - "test_formatter/test_formatter.html", - {"title": _("Test Formatter"), "form": self.form_class}, - ) - - def post(self, request): - form = TestFormatterForm(request.POST, request.FILES) - if form.is_valid(): - form.save() - return HttpResponseRedirect("edit_page") - return render( - request, "test_formatter/test_formatter.html", {"form": self.form_class} - ) - - -class EditTestFormatter(View): - file_path = "" - - def get(self, request): - file = TestFormatterModel.objects.last() - filestr = str(file.file) - filename = filestr.split("/")[-1] - filepath = filestr.split("/")[0] - - bef_file = get_names_in_archive(filestr) - preview_data = { - "bef_inp_format": bef_file[0], - "bef_out_format": bef_file[1], - "aft_inp_format": "input.000", - "aft_out_format": "output.000", - "file_str": filestr, - } - - preview = tf_logic.preview(preview_data) - - response = "" - for i in range(len(bef_file)): - bef = preview["bef_preview"][i]["value"] - aft = preview["aft_preview"][i]["value"] - response = response + f"

{bef} => {aft}

\n" - - return render( - request, - "test_formatter/edit_test_formatter.html", - { - "title": _("Test Formatter"), - "check": 0, - "files_list": bef_file, - "file_name": filename, - "res": response, - }, - ) - - def post(self, request, *args, **kwargs): - action = request.POST.get("action") - if action == "convert": - try: - file = TestFormatterModel.objects.last() - filestr = str(file.file) - filename = filestr.split("/")[-1] - filepath = filestr.split("/")[0] - bef_inp_format = request.POST["bef_inp_format"] - bef_out_format = request.POST["bef_out_format"] - aft_inp_format = request.POST["aft_inp_format"] - aft_out_format = request.POST["aft_out_format"] - aft_file_name = request.POST["file_name"] - except KeyError: - return HttpResponseBadRequest("No data.") - - if filename != aft_file_name: - source_path = os.path.join(settings.MEDIA_ROOT, filestr) - new_path = os.path.join( - settings.MEDIA_ROOT, "test_formatter/" + aft_file_name - ) - os.rename(source_path, new_path) - filename = aft_file_name - - preview_data = { - "bef_inp_format": bef_inp_format, - "bef_out_format": bef_out_format, - "aft_inp_format": aft_inp_format, - "aft_out_format": aft_out_format, - "file_name": filename, - "file_path": filepath, - "file_str": filepath + "/" + filename, - } - - converted_zip = tf_logic.convert(preview_data) - - global file_path - file_path = converted_zip["file_path"] - - zip_instance = TestFormatterModel() - zip_instance.file = file_path - zip_instance.save() - - preview = tf_logic.preview(preview_data) - response = HttpResponse() - - for i in range(len(preview["bef_preview"])): - bef = preview["bef_preview"][i]["value"] - aft = preview["aft_preview"][i]["value"] - response.write(f"

{bef} => {aft}

") - - return response - - elif action == "download": - return HttpResponse(file_path) - - return HttpResponseBadRequest("Invalid action") - - -class DownloadTestFormatter(View): - def get(self, request): - file_path = request.GET.get("file_path") - file_name = file_path.split("/")[-1] - preview_file = tf_logic.preview_file(file_path) - - response = "" - for i in range(len(preview_file)): - response = response + (f"

{preview_file[i]}

\n") - - files_list = [preview_file[0], preview_file[1]] - - return render( - request, - "test_formatter/download_test_formatter.html", - { - "title": _("Test Formatter"), - "response": response, - "files_list": files_list, - "file_path": os.path.join(settings.MEDIA_ROOT, file_path), - "file_path_getnames": file_path, - "file_name": file_name, - }, - ) - - def post(self, request): - file_path = request.POST.get("file_path") - - with open(file_path, "rb") as zip_file: - response = HttpResponse(zip_file.read(), content_type="application/zip") - response[ - "Content-Disposition" - ] = f"attachment; filename={os.path.basename(file_path)}" - return response diff --git a/judge/views/test_formatter/tf_logic.py b/judge/views/test_formatter/tf_logic.py deleted file mode 100644 index f981745..0000000 --- a/judge/views/test_formatter/tf_logic.py +++ /dev/null @@ -1,116 +0,0 @@ -import os -from judge.views.test_formatter import test_formatter as tf -from judge.views.test_formatter import tf_pattern as pattern - - -class TestSuite: - def __init__( - self, - file_id: str, - pattern_pair: pattern.PatternPair, - test_id_list: list, - extra_files: list, - ): - self.file_id = file_id - self.pattern_pair = pattern_pair - self.test_id_list = test_id_list - self.extra_files = extra_files - - @classmethod - def get_test_suite(cls, file_name: str, inp_format: str, out_format: str): - pattern_pair = pattern.PatternPair.from_string_pair(inp_format, out_format) - names = tf.get_names_in_archive(file_name) - test_id_list, extra_files = pattern_pair.matches( - names, returns="test_id_with_extra_files" - ) - return cls(file_name, pattern_pair, test_id_list, extra_files) - - def get_name_list(self, add_extra_info=False): - important_files = [] - - for index, t in enumerate(self.test_id_list): - inp_name = self.pattern_pair.x.get_name(t, index=index, use_index=True) - out_name = self.pattern_pair.y.get_name(t, index=index, use_index=True) - important_files.extend([inp_name, out_name]) - - result = [] - - for name in important_files: - if add_extra_info: - result.append({"value": name, "is_extra_file": False}) - else: - result.append(name) - - for name in self.extra_files: - if add_extra_info: - result.append({"value": name, "is_extra_file": True}) - else: - result.append(name) - - return result - - -def is_valid_file_type(file_name): - _, ext = os.path.splitext(file_name) - return ext in [".zip", ".ZIP"] - - -def preview(params): - bif = params["bef_inp_format"] - bof = params["bef_out_format"] - aif = params["aft_inp_format"] - aof = params["aft_out_format"] - file_str = params["file_str"] - - try: - test_suite = TestSuite.get_test_suite(file_str, bif, bof) - bef_preview = test_suite.get_name_list(add_extra_info=True) - try: - test_suite.pattern_pair = pattern.PatternPair.from_string_pair(aif, aof) - aft_preview = test_suite.get_name_list(add_extra_info=True) - return {"bef_preview": bef_preview, "aft_preview": aft_preview} - except: - return {"bef_preview": bef_preview, "aft_preview": []} - except: - test_suite = TestSuite.get_test_suite(file_id, "*", "*") - preview = test_suite.get_name_list(add_extra_info=True) - return {"bef_preview": preview, "aft_preview": []} - - -def convert(params): - bif = params["bef_inp_format"] - bof = params["bef_out_format"] - aif = params["aft_inp_format"] - aof = params["aft_out_format"] - file_str = params["file_str"] - file_name = params["file_name"] - file_path = params["file_path"] - - test_suite = TestSuite.get_test_suite(file_str, bif, bof) - bef_preview = test_suite.get_name_list() - test_suite.pattern_pair = pattern.PatternPair.from_string_pair(aif, aof) - aft_preview = test_suite.get_name_list() - - result = tf.get_renamed_archive( - file_str, file_name, file_path, bef_preview, aft_preview - ) - return result - - -def prefill(params): - file_str = params["file_str"] - file_name = params["file_name"] - - names = tf.get_names_in_archive(file_str) - pattern_pair = pattern.find_best_pattern_pair(names) - - return { - "file_name": file_name, - "inp_format": pattern_pair.x.to_string(), - "out_format": pattern_pair.y.to_string(), - } - - -def preview_file(file_str): - names = tf.get_names_in_archive(file_str) - return names diff --git a/judge/views/test_formatter/tf_pattern.py b/judge/views/test_formatter/tf_pattern.py deleted file mode 100644 index 071976d..0000000 --- a/judge/views/test_formatter/tf_pattern.py +++ /dev/null @@ -1,268 +0,0 @@ -import os -import random -from judge.views.test_formatter import tf_utils as utils - -SAMPLE_SIZE = 16 -NUMBERED_MM = ["0", "1", "00", "01", "000", "001", "0000", "0001"] -VALID_MM = ["*"] + NUMBERED_MM - -MSG_TOO_MANY_OCCURRENCES = ( - "400: Invalid pattern: Pattern cannot have more than one '{}'" -) -MSG_MM_NOT_FOUND = "400: Invalid pattern: Wildcard not found. Wildcard list: {}" - - -class Pattern: - def __init__(self, ll, mm, rr): - assert mm in VALID_MM, "Invalid wildcard" - self.ll = ll - self.mm = mm - self.rr = rr - - def __repr__(self): - return "Pattern('{}', '{}', '{}')".format(self.ll, self.mm, self.rr) - - def __eq__(self, other): - return self.__repr__() == other.__repr__() - - def __hash__(self): - return self.__repr__().__hash__() - - @classmethod - def from_string(cls, text): - for mm in ["*"] + sorted(NUMBERED_MM, key=len, reverse=True): - if mm in text: - if text.count(mm) > 1: - raise Exception(MSG_TOO_MANY_OCCURRENCES.format(mm)) - i = text.index(mm) - return cls(text[:i], mm, text[i + len(mm) :]) - raise Exception(MSG_MM_NOT_FOUND.format(",".join(VALID_MM))) - - def to_string(self): - return self.ll + self.mm + self.rr - - def is_valid_test_id(self, test_id): - if self.mm == "*": - return True - if self.mm in NUMBERED_MM: - return test_id.isdigit() and len(test_id) >= len(self.mm) - raise NotImplementedError - - def matched(self, name): - return ( - name.startswith(self.ll) - and name.endswith(self.rr) - and len(name) >= len(self.ll) + len(self.rr) - and self.is_valid_test_id(self.get_test_id(name)) - ) - - def get_test_id(self, name): - return name[len(self.ll) : len(name) - len(self.rr)] - - def get_test_id_from_index(self, index): - assert self.mm in NUMBERED_MM, "Wildcard is not a number" - return str(int(self.mm) + index).zfill(len(self.mm)) - - def get_name(self, test_id, index=None, use_index=False): - if use_index and self.mm in NUMBERED_MM: - return self.ll + self.get_test_id_from_index(index) + self.rr - return self.ll + test_id + self.rr - - def matches(self, names, returns): - if returns == "test_id": - result = [n for n in names] - result = [n for n in result if self.matched(n)] - result = [self.get_test_id(n) for n in result] - return result - else: - raise NotImplementedError - - -class PatternPair: - def __init__(self, x: Pattern, y: Pattern): - assert x.mm == y.mm, "Input wildcard and output wildcard must be equal" - self.x = x - self.y = y - - def __repr__(self): - return "PatternPair({}, {})".format(self.x, self.y) - - def __eq__(self, other): - return self.__repr__() == other.__repr__() - - def __hash__(self): - return self.__repr__().__hash__() - - @classmethod - def from_string_pair(cls, inp_format, out_format): - return cls(Pattern.from_string(inp_format), Pattern.from_string(out_format)) - - def matches(self, names, returns): - x_test_ids = self.x.matches(names, returns="test_id") - y_test_ids = self.y.matches(names, returns="test_id") - - test_ids = set(x_test_ids) & set(y_test_ids) - test_ids = list(sorted(test_ids, key=utils.natural_sorting_key)) - - if returns == "fast_count": - if self.x.mm == "*": - return len(test_ids) - elif self.x.mm in NUMBERED_MM: - count_valid = 0 - for t in test_ids: - if t == self.x.get_test_id_from_index(count_valid): - count_valid += 1 - - return count_valid - - extra_files = list(names) - valid_test_ids = [] - for t in test_ids: - if self.x.mm in NUMBERED_MM: - if t != self.x.get_test_id_from_index(len(valid_test_ids)): - continue - - inp_name = self.x.get_name(t) - out_name = self.y.get_name(t) - - if inp_name == out_name: - continue - if inp_name not in extra_files: - continue - if out_name not in extra_files: - continue - - valid_test_ids.append(t) - extra_files.remove(inp_name) - extra_files.remove(out_name) - - if returns == "count": - return len(valid_test_ids) - elif returns == "test_id": - return valid_test_ids - elif returns == "test_id_with_extra_files": - return valid_test_ids, extra_files - else: - raise NotImplementedError - - def score(self, names): - def ls(s): - return len(s) - s.count("0") - - def zs(s): - return -s.count("0") - - def vs(s): - return sum( - s.lower().count(c) * w - for c, w in [("a", -1), ("e", -1), ("i", +1), ("o", -1), ("u", -1)] - ) - - count_score = self.matches(names, returns="fast_count") - - len_score = ls(self.x.ll + self.x.rr + self.y.ll + self.y.rr) - zero_score = zs(self.x.ll + self.x.rr + self.y.ll + self.y.rr) - - assert self.x.mm in ["*"] + NUMBERED_MM - specific_score = 0 if self.x.mm == "*" else len(self.x.mm) - - vowel_score = vs(self.x.ll + self.x.rr) - vs(self.y.ll + self.y.rr) - - return count_score, specific_score, len_score, zero_score, vowel_score - - def is_string_safe(self): - try: - x = Pattern.from_string(self.x.to_string()) - y = Pattern.from_string(self.y.to_string()) - return self == PatternPair(x, y) - except: - return False - - -def maximal(a, key): - max_score = max(map(key, a)) - result = [x for x in a if key(x) == max_score] - if len(result) == 1: - return result[0] - else: - print(result) - raise Exception("More than one maximum values") - - -def get_all_star_pattern_pairs(names): - sample = random.sample(names, min(len(names), SAMPLE_SIZE)) - - star_pattern_pairs = [] - - all_prefixes = [n[:i] for n in sample for i in range(len(n) + 1)] - all_prefixes = list(sorted(set(all_prefixes))) - all_suffixes = [n[i:] for n in sample for i in range(len(n) + 1)] - all_suffixes = list(sorted(set(all_suffixes))) - - for prefix in all_prefixes: - matched_names = [n for n in names if n.startswith(prefix)] - if len(matched_names) == 2: - mn0, mn1 = matched_names - for i in range(len(prefix) + 1): - x = Pattern(prefix[:i], "*", mn0[len(prefix) :]) - y = Pattern(prefix[:i], "*", mn1[len(prefix) :]) - star_pattern_pairs.append(PatternPair(x, y)) - - for suffix in all_suffixes: - matched_names = [n for n in names if n.endswith(suffix)] - if len(matched_names) == 2: - mn0, mn1 = matched_names - for i in range(len(suffix) + 1): - x = Pattern(mn0[: len(mn0) - len(suffix)], "*", suffix[i:]) - y = Pattern(mn1[: len(mn1) - len(suffix)], "*", suffix[i:]) - star_pattern_pairs.append(PatternPair(x, y)) - - star_pattern_pairs = list(set(star_pattern_pairs)) - return star_pattern_pairs - - -def get_variant_pattern_pairs(pp): - return [ - PatternPair(Pattern(pp.x.ll, mm, pp.x.rr), Pattern(pp.y.ll, mm, pp.y.rr)) - for mm in VALID_MM - ] + [ - PatternPair(Pattern(pp.y.ll, mm, pp.y.rr), Pattern(pp.x.ll, mm, pp.x.rr)) - for mm in VALID_MM - ] - - -def find_best_pattern_pair(names): - star_pattern_pairs = get_all_star_pattern_pairs(names) - star_pattern_pairs = [ - pp for pp in star_pattern_pairs if pp.matches(names, returns="fast_count") >= 2 - ] - # for pp in star_pattern_pairs: - # print(pp, pp.is_string_safe(), pp.score(names)) - - if len(star_pattern_pairs) == 0: - return PatternPair(Pattern("", "*", ""), Pattern("", "*", "")) - best_star_pattern_pair = maximal(star_pattern_pairs, key=lambda pp: pp.score(names)) - - pattern_pairs = get_variant_pattern_pairs(best_star_pattern_pair) - # for pp in pattern_pairs: - # print(pp, pp.is_string_safe(), pp.score(names)) - pattern_pairs = [pp for pp in pattern_pairs if pp.is_string_safe()] - best_pattern_pair = maximal(pattern_pairs, key=lambda pp: pp.score(names)) - - return best_pattern_pair - - -def list_dir_recursively(folder): - old_cwd = os.getcwd() - os.chdir(folder) - result = [] - for root, _, filenames in os.walk("."): - for filename in filenames: - result.append(os.path.join(root, filename)) - os.chdir(old_cwd) - return result - - -def test_with_dir(folder): - names = list_dir_recursively(folder) - print(folder, find_best_pattern_pair(names)) diff --git a/judge/views/test_formatter/tf_utils.py b/judge/views/test_formatter/tf_utils.py deleted file mode 100644 index 919b069..0000000 --- a/judge/views/test_formatter/tf_utils.py +++ /dev/null @@ -1,15 +0,0 @@ -def get_char_kind(char): - return 1 if char.isdigit() else 2 if char.isalpha() else 3 - - -def natural_sorting_key(name): - result = [] - last_kind = -1 - for char in name: - curr_kind = get_char_kind(char) - if curr_kind != last_kind: - result.append("") - result[-1] += char - last_kind = curr_kind - - return [x.zfill(16) if x.isdigit() else x for x in result] diff --git a/judge/views/ticket.py b/judge/views/ticket.py index 60a151e..85538b4 100644 --- a/judge/views/ticket.py +++ b/judge/views/ticket.py @@ -1,21 +1,9 @@ import json -from itertools import chain - from django import forms from django.contrib.auth.mixins import LoginRequiredMixin -from django.core.exceptions import ( - ImproperlyConfigured, - PermissionDenied, - ValidationError, -) -from django.http import ( - Http404, - HttpResponse, - HttpResponseBadRequest, - HttpResponseRedirect, - JsonResponse, -) +from django.core.exceptions import ImproperlyConfigured, PermissionDenied, ValidationError +from django.http import Http404, HttpResponse, HttpResponseBadRequest, HttpResponseRedirect, JsonResponse from django.shortcuts import get_object_or_404 from django.template.defaultfilters import truncatechars from django.template.loader import get_template @@ -29,109 +17,77 @@ from django.views.generic import ListView from django.views.generic.detail import SingleObjectMixin from judge import event_poster as event -from judge.models import Problem, Profile, Ticket, TicketMessage, Notification +from judge.models import Problem, Profile, Ticket, TicketMessage from judge.utils.diggpaginator import DiggPaginator from judge.utils.tickets import filter_visible_tickets, own_ticket_filter from judge.utils.views import SingleObjectFormView, TitleMixin, paginate_query_context from judge.views.problem import ProblemMixin from judge.widgets import HeavyPreviewPageDownWidget -from judge.models.notification import make_notification -ticket_widget = ( - forms.Textarea() - if HeavyPreviewPageDownWidget is None - else HeavyPreviewPageDownWidget( - preview=reverse_lazy("ticket_preview"), - preview_timeout=1000, - hide_preview_button=True, - ) -) - - -def add_ticket_notifications(users, author, link, ticket): - html = f'{ticket.linked_item}' - users = set(users) - if author in users: - users.remove(author) - make_notification(users, "Ticket", html, author) +ticket_widget = (forms.Textarea() if HeavyPreviewPageDownWidget is None else + HeavyPreviewPageDownWidget(preview=reverse_lazy('ticket_preview'), + preview_timeout=1000, hide_preview_button=True)) class TicketForm(forms.Form): - title = forms.CharField(max_length=100, label=gettext_lazy("Ticket title")) + title = forms.CharField(max_length=100, label=gettext_lazy('Ticket title')) body = forms.CharField(widget=ticket_widget) def __init__(self, request, *args, **kwargs): self.request = request super(TicketForm, self).__init__(*args, **kwargs) - self.fields["title"].widget.attrs.update({"placeholder": _("Ticket title")}) - self.fields["body"].widget.attrs.update({"placeholder": _("Issue description")}) + self.fields['title'].widget.attrs.update({'placeholder': _('Ticket title')}) + self.fields['body'].widget.attrs.update({'placeholder': _('Issue description')}) def clean(self): if self.request is not None and self.request.user.is_authenticated: profile = self.request.profile if profile.mute: - raise ValidationError(_("Your part is silent, little toad.")) + raise ValidationError(_('Your part is silent, little toad.')) return super(TicketForm, self).clean() class NewTicketView(LoginRequiredMixin, SingleObjectFormView): form_class = TicketForm - template_name = "ticket/new.html" + template_name = 'ticket/new.html' def get_assignees(self): return [] def get_form_kwargs(self): kwargs = super(NewTicketView, self).get_form_kwargs() - kwargs["request"] = self.request + kwargs['request'] = self.request return kwargs def form_valid(self, form): - ticket = Ticket(user=self.request.profile, title=form.cleaned_data["title"]) + ticket = Ticket(user=self.request.profile, title=form.cleaned_data['title']) ticket.linked_item = self.object ticket.save() - message = TicketMessage( - ticket=ticket, user=ticket.user, body=form.cleaned_data["body"] - ) + message = TicketMessage(ticket=ticket, user=ticket.user, body=form.cleaned_data['body']) message.save() ticket.assignees.set(self.get_assignees()) - - link = reverse("ticket", args=[ticket.id]) - - add_ticket_notifications(ticket.assignees.all(), ticket.user, link, ticket) - if event.real: - event.post( - "tickets", - { - "type": "new-ticket", - "id": ticket.id, - "message": message.id, - "user": ticket.user_id, - "assignees": list(ticket.assignees.values_list("id", flat=True)), - }, - ) - return HttpResponseRedirect(link) + event.post('tickets', { + 'type': 'new-ticket', 'id': ticket.id, + 'message': message.id, 'user': ticket.user_id, + 'assignees': list(ticket.assignees.values_list('id', flat=True)), + }) + return HttpResponseRedirect(reverse('ticket', args=[ticket.id])) class NewProblemTicketView(ProblemMixin, TitleMixin, NewTicketView): - template_name = "ticket/new_problem.html" + template_name = 'ticket/new_problem.html' def get_assignees(self): return self.object.authors.all() def get_title(self): - return _("New ticket for %s") % self.object.name + return _('New ticket for %s') % self.object.name def get_content_title(self): - return mark_safe( - escape(_("New ticket for %s")) - % format_html( - '{1}', - reverse("problem_detail", args=[self.object.code]), - self.object.translated_name(self.request.LANGUAGE_CODE), - ) - ) + return mark_safe(escape(_('New ticket for %s')) % + format_html('{1}', reverse('problem_detail', args=[self.object.code]), + self.object.translated_name(self.request.LANGUAGE_CODE))) def form_valid(self, form): if not self.object.is_accessible_by(self.request.user): @@ -149,7 +105,7 @@ class TicketMixin(object): def get_object(self, queryset=None): ticket = super(TicketMixin, self).get_object(queryset) profile_id = self.request.profile.id - if self.request.user.has_perm("judge.change_ticket"): + if self.request.user.has_perm('judge.change_ticket'): return ticket if ticket.user_id == profile_id: return ticket @@ -163,55 +119,33 @@ class TicketMixin(object): class TicketView(TitleMixin, LoginRequiredMixin, TicketMixin, SingleObjectFormView): form_class = TicketCommentForm - template_name = "ticket/ticket.html" - context_object_name = "ticket" + template_name = 'ticket/ticket.html' + context_object_name = 'ticket' def form_valid(self, form): - message = TicketMessage( - user=self.request.profile, - body=form.cleaned_data["body"], - ticket=self.object, - ) + message = TicketMessage(user=self.request.profile, + body=form.cleaned_data['body'], + ticket=self.object) message.save() - - link = "%s#message-%d" % (reverse("ticket", args=[self.object.id]), message.id) - - notify_list = list(chain(self.object.assignees.all(), [self.object.user])) - add_ticket_notifications(notify_list, message.user, link, self.object) - if event.real: - event.post( - "tickets", - { - "type": "ticket-message", - "id": self.object.id, - "message": message.id, - "user": self.object.user_id, - "assignees": list( - self.object.assignees.values_list("id", flat=True) - ), - }, - ) - event.post( - "ticket-%d" % self.object.id, - { - "type": "ticket-message", - "message": message.id, - }, - ) - return HttpResponseRedirect(link) + event.post('tickets', { + 'type': 'ticket-message', 'id': self.object.id, + 'message': message.id, 'user': self.object.user_id, + 'assignees': list(self.object.assignees.values_list('id', flat=True)), + }) + event.post('ticket-%d' % self.object.id, { + 'type': 'ticket-message', 'message': message.id, + }) + return HttpResponseRedirect('%s#message-%d' % (reverse('ticket', args=[self.object.id]), message.id)) def get_title(self): - return _("%(title)s - Ticket %(id)d") % { - "title": self.object.title, - "id": self.object.id, - } + return _('%(title)s - Ticket %(id)d') % {'title': self.object.title, 'id': self.object.id} def get_context_data(self, **kwargs): context = super(TicketView, self).get_context_data(**kwargs) - context["ticket_messages"] = self.object.messages.select_related("user__user") - context["assignees"] = self.object.assignees.select_related("user") - context["last_msg"] = event.last() + context['ticket_messages'] = self.object.messages.select_related('user__user') + context['assignees'] = self.object.assignees.select_related('user') + context['last_msg'] = event.last() return context @@ -220,32 +154,21 @@ class TicketStatusChangeView(LoginRequiredMixin, TicketMixin, SingleObjectMixin, def post(self, request, *args, **kwargs): if self.open is None: - raise ImproperlyConfigured("Need to define open") + raise ImproperlyConfigured('Need to define open') ticket = self.get_object() if ticket.is_open != self.open: ticket.is_open = self.open ticket.save() if event.real: - event.post( - "tickets", - { - "type": "ticket-status", - "id": ticket.id, - "open": self.open, - "user": ticket.user_id, - "assignees": list( - ticket.assignees.values_list("id", flat=True) - ), - "title": ticket.title, - }, - ) - event.post( - "ticket-%d" % ticket.id, - { - "type": "ticket-status", - "open": self.open, - }, - ) + event.post('tickets', { + 'type': 'ticket-status', 'id': ticket.id, + 'open': self.open, 'user': ticket.user_id, + 'assignees': list(ticket.assignees.values_list('id', flat=True)), + 'title': ticket.title, + }) + event.post('ticket-%d' % ticket.id, { + 'type': 'ticket-status', 'open': self.open, + }) return HttpResponse(status=204) @@ -254,16 +177,16 @@ class TicketNotesForm(forms.Form): class TicketNotesEditView(LoginRequiredMixin, TicketMixin, SingleObjectFormView): - template_name = "ticket/edit-notes.html" + template_name = 'ticket/edit-notes.html' form_class = TicketNotesForm - context_object_name = "ticket" + context_object_name = 'ticket' def get_initial(self): - return {"notes": self.get_object().notes} + return {'notes': self.get_object().notes} def form_valid(self, form): ticket = self.get_object() - ticket.notes = notes = form.cleaned_data["notes"] + ticket.notes = notes = form.cleaned_data['notes'] ticket.save() if notes: return HttpResponse(linebreaks(notes, autoescape=True)) @@ -276,8 +199,8 @@ class TicketNotesEditView(LoginRequiredMixin, TicketMixin, SingleObjectFormView) class TicketList(LoginRequiredMixin, ListView): model = Ticket - template_name = "ticket/list.html" - context_object_name = "tickets" + template_name = 'ticket/list.html' + context_object_name = 'tickets' paginate_by = 50 paginator_class = DiggPaginator @@ -291,38 +214,32 @@ class TicketList(LoginRequiredMixin, ListView): @cached_property def can_edit_all(self): - return self.request.user.has_perm("judge.change_ticket") + return self.request.user.has_perm('judge.change_ticket') @cached_property def filter_users(self): - return self.request.GET.getlist("user") + return self.request.GET.getlist('user') @cached_property def filter_assignees(self): - return self.request.GET.getlist("assignee") + return self.request.GET.getlist('assignee') def GET_with_session(self, key): if not self.request.GET: return self.request.session.get(key, False) - return self.request.GET.get(key, None) == "1" + return self.request.GET.get(key, None) == '1' def _get_queryset(self): - return ( - Ticket.objects.select_related("user__user") - .prefetch_related("assignees__user") - .order_by("-id") - ) + return Ticket.objects.select_related('user__user').prefetch_related('assignees__user').order_by('-id') def get_queryset(self): queryset = self._get_queryset() - if self.GET_with_session("own"): + if self.GET_with_session('own'): queryset = queryset.filter(own_ticket_filter(self.profile.id)) elif not self.can_edit_all: queryset = filter_visible_tickets(queryset, self.user, self.profile) if self.filter_assignees: - queryset = queryset.filter( - assignees__user__username__in=self.filter_assignees - ) + queryset = queryset.filter(assignees__user__username__in=self.filter_assignees) if self.filter_users: queryset = queryset.filter(user__user__username__in=self.filter_users) return queryset.distinct() @@ -330,41 +247,29 @@ class TicketList(LoginRequiredMixin, ListView): def get_context_data(self, **kwargs): context = super(TicketList, self).get_context_data(**kwargs) - page = context["page_obj"] - context["title"] = _("Tickets - Page %(number)d of %(total)d") % { - "number": page.number, - "total": page.paginator.num_pages, + page = context['page_obj'] + context['title'] = _('Tickets - Page %(number)d of %(total)d') % { + 'number': page.number, + 'total': page.paginator.num_pages, } - context["can_edit_all"] = self.can_edit_all - context["filter_status"] = { - "own": self.GET_with_session("own"), - "user": self.filter_users, - "assignee": self.filter_assignees, - "user_id": json.dumps( - list( - Profile.objects.filter( - user__username__in=self.filter_users - ).values_list("id", flat=True) - ) - ), - "assignee_id": json.dumps( - list( - Profile.objects.filter( - user__username__in=self.filter_assignees - ).values_list("id", flat=True) - ) - ), - "own_id": self.profile.id if self.GET_with_session("own") else "null", + context['can_edit_all'] = self.can_edit_all + context['filter_status'] = { + 'own': self.GET_with_session('own'), 'user': self.filter_users, 'assignee': self.filter_assignees, + 'user_id': json.dumps(list(Profile.objects.filter(user__username__in=self.filter_users) + .values_list('id', flat=True))), + 'assignee_id': json.dumps(list(Profile.objects.filter(user__username__in=self.filter_assignees) + .values_list('id', flat=True))), + 'own_id': self.profile.id if self.GET_with_session('own') else 'null', } - context["last_msg"] = event.last() + context['last_msg'] = event.last() context.update(paginate_query_context(self.request)) return context def post(self, request, *args, **kwargs): - to_update = ("own",) + to_update = ('own',) for key in to_update: if key in request.GET: - val = request.GET.get(key) == "1" + val = request.GET.get(key) == '1' request.session[key] = val else: request.session.pop(key, None) @@ -373,56 +278,38 @@ class TicketList(LoginRequiredMixin, ListView): class ProblemTicketListView(TicketList): def _get_queryset(self): - problem = get_object_or_404(Problem, code=self.kwargs.get("problem")) + problem = get_object_or_404(Problem, code=self.kwargs.get('problem')) if problem.is_editable_by(self.request.user): - return problem.tickets.order_by("-id") + return problem.tickets.order_by('-id') elif problem.is_accessible_by(self.request.user): - return problem.tickets.filter(own_ticket_filter(self.profile.id)).order_by( - "-id" - ) + return problem.tickets.filter(own_ticket_filter(self.profile.id)).order_by('-id') raise Http404() class TicketListDataAjax(TicketMixin, SingleObjectMixin, View): def get(self, request, *args, **kwargs): try: - self.kwargs["pk"] = request.GET["id"] + self.kwargs['pk'] = request.GET['id'] except KeyError: return HttpResponseBadRequest() ticket = self.get_object() message = ticket.messages.first() - return JsonResponse( - { - "row": get_template("ticket/row.html").render( - {"ticket": ticket}, request - ), - "notification": { - "title": _("New Ticket: %s") % ticket.title, - "body": "%s\n%s" - % ( - _("#%(id)d, assigned to: %(users)s") - % { - "id": ticket.id, - "users": ( - _(", ").join( - ticket.assignees.values_list( - "user__username", flat=True - ) - ) - or _("no one") - ), - }, - truncatechars(message.body, 200), - ), - }, - } - ) + return JsonResponse({ + 'row': get_template('ticket/row.html').render({'ticket': ticket}, request), + 'notification': { + 'title': _('New Ticket: %s') % ticket.title, + 'body': '%s\n%s' % (_('#%(id)d, assigned to: %(users)s') % { + 'id': ticket.id, + 'users': (_(', ').join(ticket.assignees.values_list('user__username', flat=True)) or _('no one')), + }, truncatechars(message.body, 200)), + }, + }) class TicketMessageDataAjax(TicketMixin, SingleObjectMixin, View): def get(self, request, *args, **kwargs): try: - message_id = request.GET["message"] + message_id = request.GET['message'] except KeyError: return HttpResponseBadRequest() ticket = self.get_object() @@ -430,14 +317,10 @@ class TicketMessageDataAjax(TicketMixin, SingleObjectMixin, View): message = ticket.messages.get(id=message_id) except TicketMessage.DoesNotExist: return HttpResponseBadRequest() - return JsonResponse( - { - "message": get_template("ticket/message.html").render( - {"message": message}, request - ), - "notification": { - "title": _("New Ticket Message For: %s") % ticket.title, - "body": truncatechars(message.body, 200), - }, - } - ) + return JsonResponse({ + 'message': get_template('ticket/message.html').render({'message': message}, request), + 'notification': { + 'title': _('New Ticket Message For: %s') % ticket.title, + 'body': truncatechars(message.body, 200), + }, + }) diff --git a/judge/views/totp.py b/judge/views/totp.py index 88fd63a..097137f 100644 --- a/judge/views/totp.py +++ b/judge/views/totp.py @@ -21,7 +21,7 @@ class TOTPView(TitleMixin, LoginRequiredMixin, FormView): def get_form_kwargs(self): result = super(TOTPView, self).get_form_kwargs() - result["totp_key"] = self.profile.totp_key + result['totp_key'] = self.profile.totp_key return result def dispatch(self, request, *args, **kwargs): @@ -35,12 +35,12 @@ class TOTPView(TitleMixin, LoginRequiredMixin, FormView): raise NotImplementedError() def next_page(self): - return HttpResponseRedirect(reverse("user_edit_profile")) + return HttpResponseRedirect(reverse('user_edit_profile')) class TOTPEnableView(TOTPView): - title = _("Enable Two Factor Authentication") - template_name = "registration/totp_enable.html" + title = _('Enable Two Factor Authentication') + template_name = 'registration/totp_enable.html' def get(self, request, *args, **kwargs): profile = self.profile @@ -54,22 +54,20 @@ class TOTPEnableView(TOTPView): def post(self, request, *args, **kwargs): if not self.profile.totp_key: - return HttpResponseBadRequest("No TOTP key generated on server side?") + return HttpResponseBadRequest('No TOTP key generated on server side?') return super(TOTPEnableView, self).post(request, *args, **kwargs) def get_context_data(self, **kwargs): context = super(TOTPEnableView, self).get_context_data(**kwargs) - context["totp_key"] = self.profile.totp_key - context["qr_code"] = self.render_qr_code( - self.request.user.username, self.profile.totp_key - ) + context['totp_key'] = self.profile.totp_key + context['qr_code'] = self.render_qr_code(self.request.user.username, self.profile.totp_key) return context def form_valid(self, form): self.profile.is_totp_enabled = True self.profile.save() # Make sure users don't get prompted to enter code right after enabling: - self.request.session["2fa_passed"] = True + self.request.session['2fa_passed'] = True return self.next_page() @classmethod @@ -81,17 +79,15 @@ class TOTPEnableView(TOTPView): qr.add_data(uri) qr.make(fit=True) - image = qr.make_image(fill_color="black", back_color="white") + image = qr.make_image(fill_color='black', back_color='white') buf = BytesIO() - image.save(buf, format="PNG") - return "data:image/png;base64," + base64.b64encode(buf.getvalue()).decode( - "ascii" - ) + image.save(buf, format='PNG') + return 'data:image/png;base64,' + base64.b64encode(buf.getvalue()).decode('ascii') class TOTPDisableView(TOTPView): - title = _("Disable Two Factor Authentication") - template_name = "registration/totp_disable.html" + title = _('Disable Two Factor Authentication') + template_name = 'registration/totp_disable.html' def check_skip(self): if not self.profile.is_totp_enabled: @@ -106,25 +102,21 @@ class TOTPDisableView(TOTPView): class TOTPLoginView(SuccessURLAllowedHostsMixin, TOTPView): - title = _("Perform Two Factor Authentication") - template_name = "registration/totp_auth.html" + title = _('Perform Two Factor Authentication') + template_name = 'registration/totp_auth.html' def check_skip(self): - return not self.profile.is_totp_enabled or self.request.session.get( - "2fa_passed", False - ) + return not self.profile.is_totp_enabled or self.request.session.get('2fa_passed', False) def next_page(self): - redirect_to = self.request.GET.get("next", "") + redirect_to = self.request.GET.get('next', '') url_is_safe = is_safe_url( url=redirect_to, allowed_hosts=self.get_success_url_allowed_hosts(), require_https=self.request.is_secure(), ) - return HttpResponseRedirect( - (redirect_to if url_is_safe else "") or reverse("user_page") - ) + return HttpResponseRedirect((redirect_to if url_is_safe else '') or reverse('user_page')) def form_valid(self, form): - self.request.session["2fa_passed"] = True + self.request.session['2fa_passed'] = True return self.next_page() diff --git a/judge/views/user.py b/judge/views/user.py index 6feaffa..36bdd83 100644 --- a/judge/views/user.py +++ b/judge/views/user.py @@ -11,18 +11,7 @@ from django.contrib.auth.views import redirect_to_login from django.contrib.contenttypes.models import ContentType from django.db import transaction from django.db.models import Count, Max, Min -from django.db.models.fields import DateField -from django.db.models.functions import Cast, ExtractYear -from judge.models.bookmark import MakeBookMark -from django.forms import Form -from django.http import ( - Http404, - HttpResponseRedirect, - JsonResponse, - HttpResponseForbidden, - HttpResponseBadRequest, - HttpResponse, -) +from django.http import Http404, HttpResponseRedirect, JsonResponse from django.shortcuts import get_object_or_404, render from django.urls import reverse from django.utils import timezone @@ -30,55 +19,21 @@ from django.utils.formats import date_format from django.utils.functional import cached_property from django.utils.safestring import mark_safe from django.utils.translation import gettext as _, gettext_lazy -from django.views import View from django.views.generic import DetailView, ListView, TemplateView -from django.template.loader import render_to_string from reversion import revisions -from judge.forms import UserForm, ProfileForm, ProfileInfoForm -from judge.models import ( - Profile, - Rating, - Submission, - Friend, - ProfileInfo, - BlogPost, - Problem, - Contest, - Solution, -) +from judge.forms import ProfileForm, newsletter_id +from judge.models import Profile, Rating, Submission from judge.performance_points import get_pp_breakdown from judge.ratings import rating_class, rating_progress -from judge.tasks import import_users from judge.utils.problems import contest_completed_ids, user_completed_ids from judge.utils.ranker import ranker +from judge.utils.subscription import Subscription from judge.utils.unicode import utf8text -from judge.utils.users import ( - get_rating_rank, - get_points_rank, - get_awards, - get_contest_ratings, -) -from judge.utils.views import ( - QueryStringSortMixin, - TitleMixin, - generic_message, - SingleObjectFormView, - DiggPaginatorMixin, -) -from judge.utils.infinite_paginator import InfinitePaginationMixin -from judge.views.problem import ProblemList +from judge.utils.views import DiggPaginatorMixin, QueryStringSortMixin, TitleMixin, generic_message from .contests import ContestRanking - -__all__ = [ - "UserPage", - "UserAboutPage", - "UserProblemsPage", - "UserBookMarkPage", - "users", - "edit_profile", -] +__all__ = ['UserPage', 'UserAboutPage', 'UserProblemsPage', 'users', 'edit_profile'] def remap_keys(iterable, mapping): @@ -87,16 +42,16 @@ def remap_keys(iterable, mapping): class UserMixin(object): model = Profile - slug_field = "user__username" - slug_url_kwarg = "user" - context_object_name = "user" + slug_field = 'user__username' + slug_url_kwarg = 'user' + context_object_name = 'user' def render_to_response(self, context, **response_kwargs): return super(UserMixin, self).render_to_response(context, **response_kwargs) class UserPage(TitleMixin, UserMixin, DetailView): - template_name = "user/user-base.html" + template_name = 'user/user-base.html' def get_object(self, queryset=None): if self.kwargs.get(self.slug_url_kwarg, None) is None: @@ -110,23 +65,12 @@ class UserPage(TitleMixin, UserMixin, DetailView): try: return super(UserPage, self).dispatch(request, *args, **kwargs) except Http404: - return generic_message( - request, - _("No such user"), - _('No user handle "%s".') % self.kwargs.get(self.slug_url_kwarg, None), - ) + return generic_message(request, _('No such user'), _('No user handle "%s".') % + self.kwargs.get(self.slug_url_kwarg, None)) def get_title(self): - return ( - _("My account") - if self.request.profile == self.object - else _("User %s") % self.object.username - ) - - def get_content_title(self): - username = self.object.username - css_class = self.object.css_class - return mark_safe(f'{username}') + return (_('My account') if self.request.user == self.object.user else + _('User %s') % self.object.user.username) # TODO: the same code exists in problem.py, maybe move to problems.py? @cached_property @@ -137,11 +81,7 @@ class UserPage(TitleMixin, UserMixin, DetailView): @cached_property def in_contest(self): - return ( - self.profile is not None - and self.profile.current_contest is not None - and self.request.in_contest_mode - ) + return self.profile is not None and self.profile.current_contest is not None def get_completed_problems(self): if self.in_contest: @@ -152,37 +92,27 @@ class UserPage(TitleMixin, UserMixin, DetailView): def get_context_data(self, **kwargs): context = super(UserPage, self).get_context_data(**kwargs) - context["followed"] = Friend.is_friend(self.request.profile, self.object) - context["hide_solved"] = int(self.hide_solved) - context["authored"] = self.object.authored_problems.filter( - is_public=True, is_organization_private=False - ).order_by("code") + context['hide_solved'] = int(self.hide_solved) + context['authored'] = self.object.authored_problems.filter(is_public=True, is_organization_private=False) \ + .order_by('code') + rating = self.object.ratings.order_by('-contest__end_time')[:1] + context['rating'] = rating[0] if rating else None - rating = self.object.ratings.order_by("-contest__end_time")[:1] - context["rating"] = rating[0] if rating else None - - context["points_rank"] = get_points_rank(self.object) + context['rank'] = Profile.objects.filter( + is_unlisted=False, performance_points__gt=self.object.performance_points, + ).count() + 1 if rating: - context["rating_rank"] = get_rating_rank(self.object) - context["rated_users"] = Profile.objects.filter( - is_unlisted=False, rating__isnull=False - ).count() - context.update( - self.object.ratings.aggregate( - min_rating=Min("rating"), - max_rating=Max("rating"), - contests=Count("contest"), - ) - ) + context['rating_rank'] = Profile.objects.filter( + is_unlisted=False, rating__gt=self.object.rating, + ).count() + 1 + context['rated_users'] = Profile.objects.filter(is_unlisted=False, rating__isnull=False).count() + context.update(self.object.ratings.aggregate(min_rating=Min('rating'), max_rating=Max('rating'), + contests=Count('contest'))) return context def get(self, request, *args, **kwargs): - self.hide_solved = ( - request.GET.get("hide_solved") == "1" - if "hide_solved" in request.GET - else False - ) + self.hide_solved = request.GET.get('hide_solved') == '1' if 'hide_solved' in request.GET else False return super(UserPage, self).get(request, *args, **kwargs) @@ -190,296 +120,163 @@ EPOCH = datetime(1970, 1, 1, tzinfo=timezone.utc) class UserAboutPage(UserPage): - template_name = "user/user-about.html" + template_name = 'user/user-about.html' def get_context_data(self, **kwargs): context = super(UserAboutPage, self).get_context_data(**kwargs) - ratings = context["ratings"] = get_contest_ratings(self.object) + ratings = context['ratings'] = self.object.ratings.order_by('-contest__end_time').select_related('contest') \ + .defer('contest__description') - context["rating_data"] = mark_safe( - json.dumps( - [ - { - "label": rating.contest.name, - "rating": rating.rating, - "ranking": rating.rank, - "link": reverse("contest_ranking", args=(rating.contest.key,)) - + "#!" - + self.object.username, - "timestamp": (rating.contest.end_time - EPOCH).total_seconds() - * 1000, - "date": date_format( - timezone.localtime(rating.contest.end_time), - _("M j, Y, G:i"), - ), - "class": rating_class(rating.rating), - "height": "%.3fem" % rating_progress(rating.rating), - } - for rating in ratings - ] - ) - ) - - context["awards"] = get_awards(self.object) + context['rating_data'] = mark_safe(json.dumps([{ + 'label': rating.contest.name, + 'rating': rating.rating, + 'ranking': rating.rank, + 'link': reverse('contest_ranking', args=(rating.contest.key,)), + 'timestamp': (rating.contest.end_time - EPOCH).total_seconds() * 1000, + 'date': date_format(rating.contest.end_time, _('M j, Y, G:i')), + 'class': rating_class(rating.rating), + 'height': '%.3fem' % rating_progress(rating.rating), + } for rating in ratings])) if ratings: - user_data = self.object.ratings.aggregate(Min("rating"), Max("rating")) - global_data = Rating.objects.aggregate(Min("rating"), Max("rating")) - min_ever, max_ever = global_data["rating__min"], global_data["rating__max"] - min_user, max_user = user_data["rating__min"], user_data["rating__max"] + user_data = self.object.ratings.aggregate(Min('rating'), Max('rating')) + global_data = Rating.objects.aggregate(Min('rating'), Max('rating')) + min_ever, max_ever = global_data['rating__min'], global_data['rating__max'] + min_user, max_user = user_data['rating__min'], user_data['rating__max'] delta = max_user - min_user - ratio = ( - (max_ever - max_user) / (max_ever - min_ever) - if max_ever != min_ever - else 1.0 - ) - context["max_graph"] = max_user + ratio * delta - context["min_graph"] = min_user + ratio * delta - delta - - submissions = ( - self.object.submission_set.annotate(date_only=Cast("date", DateField())) - .values("date_only") - .annotate(cnt=Count("id")) - ) - - context["submission_data"] = mark_safe( - json.dumps( - { - date_counts["date_only"].isoformat(): date_counts["cnt"] - for date_counts in submissions - } - ) - ) - context["submission_metadata"] = mark_safe( - json.dumps( - { - "min_year": ( - self.object.submission_set.annotate( - year_only=ExtractYear("date") - ).aggregate(min_year=Min("year_only"))["min_year"] - ), - } - ) - ) - + ratio = (max_ever - max_user) / (max_ever - min_ever) if max_ever != min_ever else 1.0 + context['max_graph'] = max_user + ratio * delta + context['min_graph'] = min_user + ratio * delta - delta return context class UserProblemsPage(UserPage): - template_name = "user/user-problems.html" + template_name = 'user/user-problems.html' def get_context_data(self, **kwargs): context = super(UserProblemsPage, self).get_context_data(**kwargs) - result = ( - Submission.objects.filter( - user=self.object, - points__gt=0, - problem__is_public=True, - problem__is_organization_private=False, - ) - .exclude( - problem__in=self.get_completed_problems() if self.hide_solved else [] - ) - .values( - "problem__id", - "problem__code", - "problem__name", - "problem__points", - "problem__group__full_name", - ) - .distinct() - .annotate(points=Max("points")) - .order_by("problem__group__full_name", "problem__code") - ) + result = Submission.objects.filter(user=self.object, points__gt=0, problem__is_public=True, + problem__is_organization_private=False) \ + .exclude(problem__in=self.get_completed_problems() if self.hide_solved else []) \ + .values('problem__id', 'problem__code', 'problem__name', 'problem__points', 'problem__group__full_name') \ + .distinct().annotate(points=Max('points')).order_by('problem__group__full_name', 'problem__code') def process_group(group, problems_iter): problems = list(problems_iter) - points = sum(map(itemgetter("points"), problems)) - return {"name": group, "problems": problems, "points": points} + points = sum(map(itemgetter('points'), problems)) + return {'name': group, 'problems': problems, 'points': points} - context["best_submissions"] = [ - process_group(group, problems) - for group, problems in itertools.groupby( - remap_keys( - result, - { - "problem__code": "code", - "problem__name": "name", - "problem__points": "total", - "problem__group__full_name": "group", - }, - ), - itemgetter("group"), - ) + context['best_submissions'] = [ + process_group(group, problems) for group, problems in itertools.groupby( + remap_keys(result, { + 'problem__code': 'code', 'problem__name': 'name', 'problem__points': 'total', + 'problem__group__full_name': 'group', + }), itemgetter('group')) ] breakdown, has_more = get_pp_breakdown(self.object, start=0, end=10) - context["pp_breakdown"] = breakdown - context["pp_has_more"] = has_more - - return context - - -class UserBookMarkPage(DiggPaginatorMixin, ListView, UserPage): - template_name = "user/user-bookmarks.html" - context_object_name = "bookmarks" - paginate_by = 10 - - def get(self, request, *args, **kwargs): - self.current_tab = self.request.GET.get("tab", "problems") - self.user = self.object = self.get_object() - return super(UserBookMarkPage, self).get(request, *args, **kwargs) - - def get_queryset(self): - model = None - if self.current_tab == "posts": - model = BlogPost - elif self.current_tab == "contests": - model = Contest - elif self.current_tab == "editorials": - model = Solution - else: - model = Problem - - q = MakeBookMark.objects.filter(user=self.user).select_related("bookmark") - q = q.filter(bookmark__content_type=ContentType.objects.get_for_model(model)) - object_ids = q.values_list("bookmark__object_id", flat=True) - - res = model.objects.filter(id__in=object_ids) - if self.current_tab == "contests": - res = res.prefetch_related("organizations", "tags") - elif self.current_tab == "editorials": - res = res.select_related("problem") - - return res - - def get_context_data(self, **kwargs): - context = super(UserBookMarkPage, self).get_context_data(**kwargs) - - context["current_tab"] = self.current_tab - context["user"] = self.user - - context["page_prefix"] = ( - self.request.path + "?tab=" + self.current_tab + "&page=" - ) - context["first_page_href"] = self.request.path + context['pp_breakdown'] = breakdown + context['pp_has_more'] = has_more return context class UserPerformancePointsAjax(UserProblemsPage): - template_name = "user/pp-table-body.html" + template_name = 'user/pp-table-body.html' def get_context_data(self, **kwargs): context = super(UserPerformancePointsAjax, self).get_context_data(**kwargs) try: - start = int(self.request.GET.get("start", 0)) - end = int(self.request.GET.get("end", settings.DMOJ_PP_ENTRIES)) + start = int(self.request.GET.get('start', 0)) + end = int(self.request.GET.get('end', settings.DMOJ_PP_ENTRIES)) if start < 0 or end < 0 or start > end: raise ValueError except ValueError: start, end = 0, 100 breakdown, self.has_more = get_pp_breakdown(self.object, start=start, end=end) - context["pp_breakdown"] = breakdown + context['pp_breakdown'] = breakdown return context def get(self, request, *args, **kwargs): httpresp = super(UserPerformancePointsAjax, self).get(request, *args, **kwargs) httpresp.render() - return JsonResponse( - { - "results": utf8text(httpresp.content), - "has_more": self.has_more, - } - ) + return JsonResponse({ + 'results': utf8text(httpresp.content), + 'has_more': self.has_more, + }) @login_required def edit_profile(request): - profile = request.profile - profile_info, created = ProfileInfo.objects.get_or_create(profile=profile) - if request.method == "POST": - form_user = UserForm(request.POST, instance=request.user) - form = ProfileForm( - request.POST, request.FILES, instance=profile, user=request.user - ) - form_info = ProfileInfoForm(request.POST, instance=profile_info) - if form_user.is_valid() and form.is_valid(): - with revisions.create_revision(): - form_user.save() + profile = Profile.objects.get(user=request.user) + if profile.mute: + raise Http404() + if request.method == 'POST': + form = ProfileForm(request.POST, instance=profile, user=request.user) + if form.is_valid(): + with transaction.atomic(), revisions.create_revision(): form.save() - form_info.save() revisions.set_user(request.user) - revisions.set_comment(_("Updated on site")) + revisions.set_comment(_('Updated on site')) + + if newsletter_id is not None: + try: + subscription = Subscription.objects.get(user=request.user, newsletter_id=newsletter_id) + except Subscription.DoesNotExist: + if form.cleaned_data['newsletter']: + Subscription(user=request.user, newsletter_id=newsletter_id, subscribed=True).save() + else: + if subscription.subscribed != form.cleaned_data['newsletter']: + subscription.update(('unsubscribe', 'subscribe')[form.cleaned_data['newsletter']]) + + perm = Permission.objects.get(codename='test_site', content_type=ContentType.objects.get_for_model(Profile)) + if form.cleaned_data['test_site']: + request.user.user_permissions.add(perm) + else: + request.user.user_permissions.remove(perm) + return HttpResponseRedirect(request.path) else: - form_user = UserForm(instance=request.user) form = ProfileForm(instance=profile, user=request.user) - form_info = ProfileInfoForm(instance=profile_info) + if newsletter_id is not None: + try: + subscription = Subscription.objects.get(user=request.user, newsletter_id=newsletter_id) + except Subscription.DoesNotExist: + form.fields['newsletter'].initial = False + else: + form.fields['newsletter'].initial = subscription.subscribed + form.fields['test_site'].initial = request.user.has_perm('judge.test_site') tzmap = settings.TIMEZONE_MAP - - return render( - request, - "user/edit-profile.html", - { - "require_staff_2fa": settings.DMOJ_REQUIRE_STAFF_2FA, - "form_user": form_user, - "form": form, - "form_info": form_info, - "title": _("Edit profile"), - "profile": profile, - "TIMEZONE_MAP": tzmap or "http://momentjs.com/static/img/world.png", - "TIMEZONE_BG": settings.TIMEZONE_BG if tzmap else "#4E7CAD", - }, - ) + return render(request, 'user/edit-profile.html', { + 'require_staff_2fa': settings.DMOJ_REQUIRE_STAFF_2FA, + 'form': form, 'title': _('Edit profile'), 'profile': profile, + 'has_math_config': bool(settings.MATHOID_URL), + 'TIMEZONE_MAP': tzmap or 'http://momentjs.com/static/img/world.png', + 'TIMEZONE_BG': settings.TIMEZONE_BG if tzmap else '#4E7CAD', + }) -class UserList(QueryStringSortMixin, InfinitePaginationMixin, TitleMixin, ListView): +class UserList(QueryStringSortMixin, DiggPaginatorMixin, TitleMixin, ListView): model = Profile - title = gettext_lazy("Leaderboard") - context_object_name = "users" - template_name = "user/list.html" + title = gettext_lazy('Leaderboard') + context_object_name = 'users' + template_name = 'user/list.html' paginate_by = 100 - all_sorts = frozenset(("points", "problem_count", "rating", "performance_points")) + all_sorts = frozenset(('points', 'problem_count', 'rating', 'performance_points')) default_desc = all_sorts - default_sort = "-performance_points" - filter_friend = False - - def filter_friend_queryset(self, queryset): - friends = self.request.profile.get_friends() - ret = queryset.filter(id__in=friends) - return ret + default_sort = '-performance_points' def get_queryset(self): - queryset = ( - Profile.objects.filter(is_unlisted=False) - .order_by(self.order, "id") - .only( - "display_rank", - "points", - "rating", - "performance_points", - "problem_count", - "about", - ) - ) - if self.request.organization: - queryset = queryset.filter(organizations=self.request.organization) - if (self.request.GET.get("friend") == "true") and self.request.profile: - queryset = self.filter_friend_queryset(queryset) - self.filter_friend = True - return queryset + return (Profile.objects.filter(is_unlisted=False).order_by(self.order, 'id').select_related('user') + .only('display_rank', 'user__username', 'points', 'rating', 'performance_points', + 'problem_count')) def get_context_data(self, **kwargs): context = super(UserList, self).get_context_data(**kwargs) - Profile.prefetch_profile_cache([u.id for u in context["users"]]) - context["users"] = ranker( - context["users"], rank=self.paginate_by * (context["page_obj"].number - 1) - ) - context["first_page_href"] = "." - context["page_type"] = "friends" if self.filter_friend else "list" + context['users'] = ranker(context['users'], rank=self.paginate_by * (context['page_obj'].number - 1)) + context['first_page_href'] = '.' context.update(self.get_sort_context()) context.update(self.get_sort_paginate_context()) return context @@ -497,110 +294,31 @@ class FixedContestRanking(ContestRanking): def users(request): if request.user.is_authenticated: - if request.in_contest_mode: - participation = request.profile.current_contest + participation = request.profile.current_contest + if participation is not None: contest = participation.contest - return FixedContestRanking.as_view(contest=contest)( - request, contest=contest.key - ) + return FixedContestRanking.as_view(contest=contest)(request, contest=contest.key) return user_list_view(request) def user_ranking_redirect(request): try: - username = request.GET["handle"] + username = request.GET['handle'] except KeyError: raise Http404() user = get_object_or_404(Profile, user__username=username) - rank = Profile.objects.filter( - is_unlisted=False, performance_points__gt=user.performance_points - ).count() + rank = Profile.objects.filter(is_unlisted=False, performance_points__gt=user.performance_points).count() rank += Profile.objects.filter( - is_unlisted=False, - performance_points__exact=user.performance_points, - id__lt=user.id, + is_unlisted=False, performance_points__exact=user.performance_points, id__lt=user.id, ).count() page = rank // UserList.paginate_by - return HttpResponseRedirect( - "%s%s#!%s" - % (reverse("user_list"), "?page=%d" % (page + 1) if page else "", username) - ) + return HttpResponseRedirect('%s%s#!%s' % (reverse('user_list'), '?page=%d' % (page + 1) if page else '', username)) class UserLogoutView(TitleMixin, TemplateView): - template_name = "registration/logout.html" - title = "You have been successfully logged out." + template_name = 'registration/logout.html' + title = 'You have been successfully logged out.' def post(self, request, *args, **kwargs): auth_logout(request) return HttpResponseRedirect(request.get_full_path()) - - -class ImportUsersView(TitleMixin, TemplateView): - template_name = "user/import/index.html" - title = _("Import Users") - - def get(self, *args, **kwargs): - if self.request.user.is_superuser: - return super().get(self, *args, **kwargs) - return HttpResponseForbidden() - - -def import_users_post_file(request): - if not request.user.is_superuser or request.method != "POST": - return HttpResponseForbidden() - users = import_users.csv_to_dict(request.FILES["csv_file"]) - - if not users: - return JsonResponse( - { - "done": False, - "msg": "No valid row found. Make sure row containing username.", - } - ) - - table_html = render_to_string("user/import/table_csv.html", {"data": users}) - return JsonResponse({"done": True, "html": table_html, "data": users}) - - -def import_users_submit(request): - import json - - if not request.user.is_superuser or request.method != "POST": - return HttpResponseForbidden() - - users = json.loads(request.body)["users"] - log = import_users.import_users(users) - return JsonResponse({"msg": log}) - - -def sample_import_users(request): - if not request.user.is_superuser or request.method != "GET": - return HttpResponseForbidden() - filename = "import_sample.csv" - content = ",".join(import_users.fields) + "\n" + ",".join(import_users.descriptions) - response = HttpResponse(content, content_type="text/plain") - response["Content-Disposition"] = "attachment; filename={0}".format(filename) - return response - - -def toggle_darkmode(request): - path = request.GET.get("next") - if not path: - return HttpResponseBadRequest() - request.session["darkmode"] = not request.session.get("darkmode", False) - return HttpResponseRedirect(path) - - -@login_required -def toggle_follow(request, user): - if request.method != "POST": - raise Http404() - - profile_to_follow = get_object_or_404(Profile, user__username=user) - - if request.profile.id == profile_to_follow.id: - raise Http404() - - Friend.toggle_friend(request.profile, profile_to_follow) - return HttpResponseRedirect(reverse("user_page", args=(user,))) diff --git a/judge/views/volunteer.py b/judge/views/volunteer.py deleted file mode 100644 index acd3469..0000000 --- a/judge/views/volunteer.py +++ /dev/null @@ -1,32 +0,0 @@ -from django.http import HttpResponseBadRequest, JsonResponse -from django.db import transaction - -from judge.models import VolunteerProblemVote, Problem, ProblemType - - -def vote_problem(request): - if not request.user or not request.user.has_perm("judge.suggest_problem_changes"): - return HttpResponseBadRequest() - if not request.method == "POST": - return HttpResponseBadRequest() - try: - types_id = request.POST.getlist("types[]") - types = ProblemType.objects.filter(id__in=types_id) - problem = Problem.objects.get(code=request.POST["problem"]) - knowledge_points = request.POST["knowledge_points"] - thinking_points = request.POST["thinking_points"] - feedback = request.POST["feedback"] - except Exception as e: - return HttpResponseBadRequest() - - vote, _ = VolunteerProblemVote.objects.get_or_create( - voter=request.profile, - problem=problem, - defaults={"knowledge_points": 0, "thinking_points": 0}, - ) - vote.knowledge_points = knowledge_points - vote.thinking_points = thinking_points - vote.feedback = feedback - vote.types.set(types) - vote.save() - return JsonResponse({}) diff --git a/judge/views/widgets.py b/judge/views/widgets.py index f746704..57fe15b 100644 --- a/judge/views/widgets.py +++ b/judge/views/widgets.py @@ -2,90 +2,60 @@ import requests from django.conf import settings from django.contrib.auth.decorators import login_required from django.core.exceptions import ImproperlyConfigured -from django.http import ( - Http404, - HttpResponse, - HttpResponseBadRequest, - HttpResponseForbidden, - HttpResponseRedirect, -) +from django.http import Http404, HttpResponse, HttpResponseBadRequest, HttpResponseForbidden, HttpResponseRedirect from django.utils.translation import gettext as _ from django.views.generic import View from judge.models import Submission -__all__ = ["rejudge_submission", "DetectTimezone"] +__all__ = ['rejudge_submission', 'DetectTimezone'] @login_required def rejudge_submission(request): - if ( - request.method != "POST" - or not request.user.has_perm("judge.rejudge_submission") - or not request.user.has_perm("judge.edit_own_problem") - ): + if request.method != 'POST' or not request.user.has_perm('judge.rejudge_submission') or \ + not request.user.has_perm('judge.edit_own_problem'): return HttpResponseForbidden() - if "id" not in request.POST or not request.POST["id"].isdigit(): + if 'id' not in request.POST or not request.POST['id'].isdigit(): return HttpResponseBadRequest() try: - submission = Submission.objects.get(id=request.POST["id"]) + submission = Submission.objects.get(id=request.POST['id']) except Submission.DoesNotExist: return HttpResponseBadRequest() - if not request.user.has_perm( - "judge.edit_all_problem" - ) and not submission.problem.is_editor(request.profile): + if not request.user.has_perm('judge.edit_all_problem') and \ + not submission.problem.is_editor(request.profile): return HttpResponseForbidden() submission.judge(rejudge=True) - redirect = request.POST.get("path", None) + redirect = request.POST.get('path', None) - return ( - HttpResponseRedirect(redirect) - if redirect - else HttpResponse("success", content_type="text/plain") - ) + return HttpResponseRedirect(redirect) if redirect else HttpResponse('success', content_type='text/plain') class DetectTimezone(View): def askgeo(self, lat, long): - if not hasattr(settings, "ASKGEO_ACCOUNT_ID") or not hasattr( - settings, "ASKGEO_ACCOUNT_API_KEY" - ): + if not hasattr(settings, 'ASKGEO_ACCOUNT_ID') or not hasattr(settings, 'ASKGEO_ACCOUNT_API_KEY'): raise ImproperlyConfigured() - data = requests.get( - "http://api.askgeo.com/v1/%s/%s/query.json?databases=TimeZone&points=%f,%f" - % (settings.ASKGEO_ACCOUNT_ID, settings.ASKGEO_ACCOUNT_API_KEY, lat, long) - ).json() + data = requests.get('http://api.askgeo.com/v1/%s/%s/query.json?databases=TimeZone&points=%f,%f' % + (settings.ASKGEO_ACCOUNT_ID, settings.ASKGEO_ACCOUNT_API_KEY, lat, long)).json() try: - return HttpResponse( - data["data"][0]["TimeZone"]["TimeZoneId"], content_type="text/plain" - ) + return HttpResponse(data['data'][0]['TimeZone']['TimeZoneId'], content_type='text/plain') except (IndexError, KeyError): - return HttpResponse( - _("Invalid upstream data: %s") % data, - content_type="text/plain", - status=500, - ) + return HttpResponse(_('Invalid upstream data: %s') % data, content_type='text/plain', status=500) def geonames(self, lat, long): - if not hasattr(settings, "GEONAMES_USERNAME"): + if not hasattr(settings, 'GEONAMES_USERNAME'): raise ImproperlyConfigured() - data = requests.get( - "http://api.geonames.org/timezoneJSON?lat=%f&lng=%f&username=%s" - % (lat, long, settings.GEONAMES_USERNAME) - ).json() + data = requests.get('http://api.geonames.org/timezoneJSON?lat=%f&lng=%f&username=%s' % + (lat, long, settings.GEONAMES_USERNAME)).json() try: - return HttpResponse(data["timezoneId"], content_type="text/plain") + return HttpResponse(data['timezoneId'], content_type='text/plain') except KeyError: - return HttpResponse( - _("Invalid upstream data: %s") % data, - content_type="text/plain", - status=500, - ) + return HttpResponse(_('Invalid upstream data: %s') % data, content_type='text/plain', status=500) def default(self, lat, long): raise Http404() @@ -93,11 +63,10 @@ class DetectTimezone(View): def get(self, request, *args, **kwargs): backend = settings.TIMEZONE_DETECT_BACKEND try: - lat, long = float(request.GET["lat"]), float(request.GET["long"]) + lat, long = float(request.GET['lat']), float(request.GET['long']) except (ValueError, KeyError): - return HttpResponse( - _("Bad latitude or longitude"), content_type="text/plain", status=404 - ) - return {"askgeo": self.askgeo, "geonames": self.geonames,}.get( - backend, self.default - )(lat, long) + return HttpResponse(_('Bad latitude or longitude'), content_type='text/plain', status=404) + return { + 'askgeo': self.askgeo, + 'geonames': self.geonames, + }.get(backend, self.default)(lat, long) diff --git a/judge/widgets/__init__.py b/judge/widgets/__init__.py index a9455a9..51983a9 100644 --- a/judge/widgets/__init__.py +++ b/judge/widgets/__init__.py @@ -2,5 +2,3 @@ from judge.widgets.checkbox import CheckboxSelectMultipleWithSelectAll from judge.widgets.mixins import CompressorWidgetMixin from judge.widgets.pagedown import * from judge.widgets.select2 import * -from judge.widgets.datetime import * -from judge.widgets.image import * diff --git a/judge/widgets/checkbox.py b/judge/widgets/checkbox.py index b4b2249..0a7eebf 100644 --- a/judge/widgets/checkbox.py +++ b/judge/widgets/checkbox.py @@ -6,25 +6,17 @@ from django.utils.safestring import mark_safe class CheckboxSelectMultipleWithSelectAll(forms.CheckboxSelectMultiple): def render(self, name, value, attrs=None, renderer=None): - if "id" not in attrs: - raise FieldError("id required") + if 'id' not in attrs: + raise FieldError('id required') - select_all_id = attrs["id"] + "_all" - select_all_name = name + "_all" - original = super(CheckboxSelectMultipleWithSelectAll, self).render( - name, value, attrs, renderer - ) - template = get_template("widgets/select_all.html") - return mark_safe( - template.render( - { - "original_widget": original, - "select_all_id": select_all_id, - "select_all_name": select_all_name, - "all_selected": all(choice[0] in value for choice in self.choices) - if value - else False, - "empty": not self.choices, - } - ) - ) + select_all_id = attrs['id'] + '_all' + select_all_name = name + '_all' + original = super(CheckboxSelectMultipleWithSelectAll, self).render(name, value, attrs, renderer) + template = get_template('widgets/select_all.html') + return mark_safe(template.render({ + 'original_widget': original, + 'select_all_id': select_all_id, + 'select_all_name': select_all_name, + 'all_selected': all(choice[0] in value for choice in self.choices) if value else False, + 'empty': not self.choices, + })) diff --git a/judge/widgets/datetime.py b/judge/widgets/datetime.py deleted file mode 100644 index d205e1c..0000000 --- a/judge/widgets/datetime.py +++ /dev/null @@ -1,49 +0,0 @@ -from django import forms -from django.templatetags.static import static -from django.utils.html import format_html -from django.forms.utils import flatatt -from django.utils.dateparse import parse_datetime, parse_date - - -class DateTimePickerWidget(forms.DateTimeInput): - input_type = "datetime-local" - - def render(self, name, value, attrs=None, renderer=None): - if value is None: - value = "" - elif isinstance(value, str): - # Attempt to parse the string back to datetime - parsed_date = parse_datetime(value) - if parsed_date is not None: - value = parsed_date.strftime("%Y-%m-%dT%H:%M") - else: - value = "" - else: - value = value.strftime("%Y-%m-%dT%H:%M") - - final_attrs = self.build_attrs( - attrs, {"type": self.input_type, "name": name, "value": value} - ) - return format_html("", flatatt(final_attrs)) - - -class DatePickerWidget(forms.DateInput): - input_type = "date" - - def render(self, name, value, attrs=None, renderer=None): - if value is None: - value = "" - elif isinstance(value, str): - # Attempt to parse the string back to date - parsed_date = parse_date(value) - if parsed_date is not None: - value = parsed_date.strftime("%Y-%m-%d") - else: - value = "" - else: - value = value.strftime("%Y-%m-%d") - - final_attrs = self.build_attrs( - attrs, {"type": self.input_type, "name": name, "value": value} - ) - return format_html("", flatatt(final_attrs)) diff --git a/judge/widgets/image.py b/judge/widgets/image.py deleted file mode 100644 index 89b4fb4..0000000 --- a/judge/widgets/image.py +++ /dev/null @@ -1,16 +0,0 @@ -from django import forms - - -class ImageWidget(forms.ClearableFileInput): - template_name = "widgets/image.html" - - def __init__(self, attrs=None, width=80, height=80): - self.width = width - self.height = height - super().__init__(attrs) - - def get_context(self, name, value, attrs=None): - context = super().get_context(name, value, attrs) - context["widget"]["height"] = self.height - context["widget"]["width"] = self.height - return context diff --git a/judge/widgets/mixins.py b/judge/widgets/mixins.py index 6317bac..0270276 100644 --- a/judge/widgets/mixins.py +++ b/judge/widgets/mixins.py @@ -7,27 +7,23 @@ from lxml import html class CompressorWidgetMixin(object): - __template_css = dedent( - """\ + __template_css = dedent('''\ {% compress css %} {{ media.css }} {% endcompress %} - """ - ) + ''') - __template_js = dedent( - """\ + __template_js = dedent('''\ {% compress js %} {{ media.js }} {% endcompress %} - """ - ) + ''') __templates = { - (False, False): Template(""), - (True, False): Template("{% load compress %}" + __template_css), - (False, True): Template("{% load compress %}" + __template_js), - (True, True): Template("{% load compress %}" + __template_js + __template_css), + (False, False): Template(''), + (True, False): Template('{% load compress %}' + __template_css), + (False, True): Template('{% load compress %}' + __template_js), + (True, True): Template('{% load compress %}' + __template_js + __template_css), } compress_css = False @@ -38,19 +34,14 @@ class CompressorWidgetMixin(object): except ImportError: pass else: - if getattr(settings, "COMPRESS_ENABLED", not settings.DEBUG): - + if getattr(settings, 'COMPRESS_ENABLED', not settings.DEBUG): @property def media(self): media = super().media template = self.__templates[self.compress_css, self.compress_js] - result = html.fromstring(template.render(Context({"media": media}))) + result = html.fromstring(template.render(Context({'media': media}))) return forms.Media( - css={"all": [result.find(".//link").get("href")]} - if self.compress_css - else media._css, - js=[result.find(".//script").get("src")] - if self.compress_js - else media._js, + css={'all': [result.find('.//link').get('href')]} if self.compress_css else media._css, + js=[result.find('.//script').get('src')] if self.compress_js else media._js, ) diff --git a/judge/widgets/pagedown.py b/judge/widgets/pagedown.py index b0403d5..0968107 100644 --- a/judge/widgets/pagedown.py +++ b/judge/widgets/pagedown.py @@ -3,30 +3,23 @@ from django.forms.utils import flatatt from django.template.loader import get_template from django.utils.encoding import force_text from django.utils.html import conditional_escape -from django.conf import settings from judge.widgets.mixins import CompressorWidgetMixin -__all__ = [ - "PagedownWidget", - "AdminPagedownWidget", - "KatexPagedownWidget", - "KatexAdminPagedownWidget", - "HeavyPreviewPageDownWidget", - "HeavyPreviewAdminPageDownWidget", -] +__all__ = ['PagedownWidget', 'AdminPagedownWidget', + 'MathJaxPagedownWidget', 'MathJaxAdminPagedownWidget', + 'HeavyPreviewPageDownWidget', 'HeavyPreviewAdminPageDownWidget'] try: from pagedown.widgets import PagedownWidget as OldPagedownWidget except ImportError: PagedownWidget = None AdminPagedownWidget = None - KatexPagedownWidget = None - KatexAdminPagedownWidget = None + MathJaxPagedownWidget = None + MathJaxAdminPagedownWidget = None HeavyPreviewPageDownWidget = None HeavyPreviewAdminPageDownWidget = None else: - class PagedownWidget(CompressorWidgetMixin, OldPagedownWidget): # The goal here is to compress all the pagedown JS into one file. # We do not want any further compress down the chain, because @@ -35,94 +28,64 @@ else: compress_js = True def __init__(self, *args, **kwargs): + kwargs.setdefault('css', ('pagedown_widget.css',)) super(PagedownWidget, self).__init__(*args, **kwargs) - class Media: - extend = False - js = [ - "pagedown/Markdown.Converter.js", - "pagedown-extra/pagedown/Markdown.Converter.js", - "pagedown/Markdown.Sanitizer.js", - "pagedown/Markdown.Editor.js", - "pagedown-extra/Markdown.Extra.js", - "pagedown_init.js", - ] - class AdminPagedownWidget(PagedownWidget, admin_widgets.AdminTextareaWidget): class Media: - css = { - "all": [ - "pagedown_widget.css", - "content-description.css", - "admin/css/pagedown.css", - "pagedown.css", - "https://fonts.googleapis.com/css2?family=Fira+Code&family=Noto+Sans&display=swap", - ] - } - js = ["admin/js/pagedown.js"] + css = {'all': [ + 'content-description.css', + 'admin/css/pagedown.css', + ]} + js = ['admin/js/pagedown.js'] - class KatexPagedownWidget(PagedownWidget): + class MathJaxPagedownWidget(PagedownWidget): class Media: - css = { - "all": ["https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css"] - } js = [ - "katex_config.js", - "https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.js", - "https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/contrib/auto-render.min.js", - "pagedown_math.js", + 'mathjax_config.js', + 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_HTMLorMML', + 'pagedown_math.js', ] - class KatexAdminPagedownWidget(AdminPagedownWidget, KatexPagedownWidget): + class MathJaxAdminPagedownWidget(AdminPagedownWidget, MathJaxPagedownWidget): pass class HeavyPreviewPageDownWidget(PagedownWidget): def __init__(self, *args, **kwargs): - self.template = "pagedown.html" - self.id = kwargs.pop("id", None) - self.preview_url = kwargs.pop("preview") - self.preview_timeout = kwargs.pop("preview_timeout", None) - self.hide_preview_button = kwargs.pop("hide_preview_button", False) + kwargs.setdefault('template', 'pagedown.html') + self.preview_url = kwargs.pop('preview') + self.preview_timeout = kwargs.pop('preview_timeout', None) + self.hide_preview_button = kwargs.pop('hide_preview_button', False) super(HeavyPreviewPageDownWidget, self).__init__(*args, **kwargs) def render(self, name, value, attrs=None, renderer=None): if value is None: - value = "" - final_attrs = self.build_attrs(attrs, {"name": name}) - if "class" not in final_attrs: - final_attrs["class"] = "" - final_attrs["class"] += " wmd-input" - if self.id: - final_attrs["id"] = self.id - return get_template(self.template).render( - self.get_template_context(final_attrs, value) - ) + value = '' + final_attrs = self.build_attrs(attrs, {'name': name}) + if 'class' not in final_attrs: + final_attrs['class'] = '' + final_attrs['class'] += ' wmd-input' + return get_template(self.template).render(self.get_template_context(final_attrs, value)) def get_template_context(self, attrs, value): return { - "image_upload_enabled": getattr( - settings, "PAGEDOWN_IMAGE_UPLOAD_ENABLED", False - ), - "attrs": flatatt(attrs), - "body": conditional_escape(force_text(value)), - "postfix": attrs["id"], - "show_preview": True, - "preview_url": self.preview_url, - "preview_timeout": self.preview_timeout, - "extra_classes": "dmmd-no-button" if self.hide_preview_button else None, + 'attrs': flatatt(attrs), + 'body': conditional_escape(force_text(value)), + 'id': attrs['id'], + 'show_preview': self.show_preview, + 'preview_url': self.preview_url, + 'preview_timeout': self.preview_timeout, + 'extra_classes': 'dmmd-no-button' if self.hide_preview_button else None, } class Media: - js = ["dmmd-preview.js"] + css = {'all': ['dmmd-preview.css']} + js = ['dmmd-preview.js'] - class HeavyPreviewAdminPageDownWidget( - KatexPagedownWidget, AdminPagedownWidget, HeavyPreviewPageDownWidget - ): + class HeavyPreviewAdminPageDownWidget(AdminPagedownWidget, HeavyPreviewPageDownWidget): class Media: - css = { - "all": [ - "table.css", - "ranks.css", - "dmmd-preview.css", - ] - } + css = {'all': [ + 'pygment-github.css', + 'table.css', + 'ranks.css', + ]} diff --git a/judge/widgets/select2.py b/judge/widgets/select2.py index 62acc89..af4843b 100644 --- a/judge/widgets/select2.py +++ b/judge/widgets/select2.py @@ -45,23 +45,14 @@ from django.conf import settings from django.core import signing from django.forms.models import ModelChoiceIterator from django.urls import reverse_lazy -from django.utils.http import urlencode -DEFAULT_SELECT2_JS = settings.STATIC_URL + "libs/select2/select2.js" -DEFAULT_SELECT2_CSS = settings.STATIC_URL + ("libs/select2/select2.css") +DEFAULT_SELECT2_JS = '//cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/js/select2.min.js' +DEFAULT_SELECT2_CSS = '//cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/css/select2.min.css' -__all__ = [ - "Select2Widget", - "Select2MultipleWidget", - "Select2TagWidget", - "HeavySelect2Widget", - "HeavySelect2MultipleWidget", - "HeavySelect2TagWidget", - "AdminSelect2Widget", - "AdminSelect2MultipleWidget", - "AdminHeavySelect2Widget", - "AdminHeavySelect2MultipleWidget", -] +__all__ = ['Select2Widget', 'Select2MultipleWidget', 'Select2TagWidget', + 'HeavySelect2Widget', 'HeavySelect2MultipleWidget', 'HeavySelect2TagWidget', + 'AdminSelect2Widget', 'AdminSelect2MultipleWidget', 'AdminHeavySelect2Widget', + 'AdminHeavySelect2MultipleWidget'] class Select2Mixin(object): @@ -77,22 +68,22 @@ class Select2Mixin(object): """Add select2 data attributes.""" attrs = super(Select2Mixin, self).build_attrs(base_attrs, extra_attrs) if self.is_required: - attrs.setdefault("data-allow-clear", "false") + attrs.setdefault('data-allow-clear', 'false') else: - attrs.setdefault("data-allow-clear", "true") - attrs.setdefault("data-placeholder", "") + attrs.setdefault('data-allow-clear', 'true') + attrs.setdefault('data-placeholder', '') - attrs.setdefault("data-minimum-input-length", 0) - if "class" in attrs: - attrs["class"] += " django-select2" + attrs.setdefault('data-minimum-input-length', 0) + if 'class' in attrs: + attrs['class'] += ' django-select2' else: - attrs["class"] = "django-select2" + attrs['class'] = 'django-select2' return attrs def optgroups(self, name, value, attrs=None): """Add empty option for clearable selects.""" if not self.is_required and not self.allow_multiple_selected: - self.choices = list(chain([("", "")], self.choices)) + self.choices = list(chain([('', '')], self.choices)) return super(Select2Mixin, self).optgroups(name, value, attrs=attrs) @property @@ -104,7 +95,8 @@ class Select2Mixin(object): https://docs.djangoproject.com/en/1.8/topics/forms/media/#media-as-a-dynamic-property """ return forms.Media( - js=["django_select2.js"], + js=[settings.SELECT2_JS_URL, 'django_select2.js'], + css={'screen': [settings.SELECT2_CSS_URL]}, ) @@ -112,12 +104,8 @@ class AdminSelect2Mixin(Select2Mixin): @property def media(self): return forms.Media( - js=[ - "admin/js/jquery.init.js", - DEFAULT_SELECT2_JS, - "django_select2.js", - ], - css={"screen": [DEFAULT_SELECT2_CSS]}, + js=['admin/js/jquery.init.js', settings.SELECT2_JS_URL, 'django_select2.js'], + css={'screen': [settings.SELECT2_CSS_URL]}, ) @@ -127,9 +115,9 @@ class Select2TagMixin(object): def build_attrs(self, base_attrs, extra_attrs=None): """Add select2's tag attributes.""" extra_attrs = extra_attrs or {} - extra_attrs.setdefault("data-minimum-input-length", 1) - extra_attrs.setdefault("data-tags", "true") - extra_attrs.setdefault("data-token-separators", [",", " "]) + extra_attrs.setdefault('data-minimum-input-length', 1) + extra_attrs.setdefault('data-tags', 'true') + extra_attrs.setdefault('data-token-separators', [",", " "]) return super(Select2TagMixin, self).build_attrs(base_attrs, extra_attrs) @@ -194,8 +182,8 @@ class HeavySelect2Mixin(Select2Mixin): else: self.attrs = {} - self.data_view = kwargs.pop("data_view", None) - self.data_url = kwargs.pop("data_url", None) + self.data_view = kwargs.pop('data_view', None) + self.data_url = kwargs.pop('data_url', None) if not (self.data_view or self.data_url): raise ValueError('You must ether specify "data_view" or "data_url".') @@ -213,26 +201,23 @@ class HeavySelect2Mixin(Select2Mixin): # encrypt instance Id self.widget_id = signing.dumps(id(self)) - attrs["data-field_id"] = self.widget_id - attrs.setdefault("data-ajax--url", self.get_url()) - attrs.setdefault("data-ajax--cache", "true") - attrs.setdefault("data-ajax--type", "GET") - attrs.setdefault("data-minimum-input-length", 2) + attrs['data-field_id'] = self.widget_id + attrs.setdefault('data-ajax--url', self.get_url()) + attrs.setdefault('data-ajax--cache', "true") + attrs.setdefault('data-ajax--type', "GET") + attrs.setdefault('data-minimum-input-length', 2) - attrs["class"] += " django-select2-heavy" + attrs['class'] += ' django-select2-heavy' return attrs def format_value(self, value): result = super(HeavySelect2Mixin, self).format_value(value) if isinstance(self.choices, ModelChoiceIterator): chosen = copy(self.choices) - chosen.queryset = chosen.queryset.filter( - pk__in=[int(i) for i in result if isinstance(i, int) or i.isdigit()] - ) - self.choices = { - (value if isinstance(value, str) else value.value, label) - for value, label in chosen - } + chosen.queryset = chosen.queryset.filter(pk__in=[ + int(i) for i in result if isinstance(i, int) or i.isdigit() + ]) + self.choices = set(chosen) return result diff --git a/locale/ar/LC_MESSAGES/django.po b/locale/ar/LC_MESSAGES/django.po index 12d2bd5..3cffc88 100644 --- a/locale/ar/LC_MESSAGES/django.po +++ b/locale/ar/LC_MESSAGES/django.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: dmoj\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-10-25 05:59+0700\n" +"POT-Creation-Date: 2020-04-10 01:26-0500\n" "PO-Revision-Date: 2019-11-11 22:05\n" "Last-Translator: Icyene\n" "Language-Team: Arabic, Saudi Arabia\n" @@ -17,93 +17,93 @@ msgstr "" "X-Crowdin-Language: ar-SA\n" "X-Crowdin-File: django.po\n" -#: chat_box/models.py:16 judge/admin/interface.py:110 -#: judge/models/contest.py:403 judge/models/contest.py:528 -#: judge/models/profile.py:211 +#: chat_box/models.py:15 judge/admin/interface.py:107 +#: judge/models/contest.py:257 judge/models/contest.py:381 +#: judge/models/profile.py:191 msgid "user" msgstr "" -#: chat_box/models.py:17 judge/models/comment.py:43 judge/models/comment.py:191 +#: chat_box/models.py:16 judge/models/comment.py:42 msgid "posted time" msgstr "" -#: chat_box/models.py:18 judge/models/comment.py:47 +#: chat_box/models.py:17 judge/models/comment.py:46 msgid "body of comment" msgstr "" -#: chat_box/views.py:29 templates/chat/chat.html:4 +#: chat_box/views.py:29 msgid "Chat Box" msgstr "" -#: dmoj/settings.py:355 +#: dmoj/settings.py:349 msgid "German" msgstr "" -#: dmoj/settings.py:356 +#: dmoj/settings.py:350 msgid "English" msgstr "" -#: dmoj/settings.py:357 +#: dmoj/settings.py:351 msgid "Spanish" msgstr "" -#: dmoj/settings.py:358 +#: dmoj/settings.py:352 msgid "French" msgstr "" -#: dmoj/settings.py:359 +#: dmoj/settings.py:353 msgid "Croatian" msgstr "" -#: dmoj/settings.py:360 +#: dmoj/settings.py:354 msgid "Hungarian" msgstr "" -#: dmoj/settings.py:361 +#: dmoj/settings.py:355 msgid "Japanese" msgstr "" -#: dmoj/settings.py:362 +#: dmoj/settings.py:356 msgid "Korean" msgstr "" -#: dmoj/settings.py:363 +#: dmoj/settings.py:357 msgid "Brazilian Portuguese" msgstr "" -#: dmoj/settings.py:364 +#: dmoj/settings.py:358 msgid "Romanian" msgstr "" -#: dmoj/settings.py:365 +#: dmoj/settings.py:359 msgid "Russian" msgstr "" -#: dmoj/settings.py:366 +#: dmoj/settings.py:360 msgid "Serbian (Latin)" msgstr "" -#: dmoj/settings.py:367 +#: dmoj/settings.py:361 msgid "Turkish" msgstr "" -#: dmoj/settings.py:368 +#: dmoj/settings.py:362 msgid "Vietnamese" msgstr "" -#: dmoj/settings.py:369 +#: dmoj/settings.py:363 msgid "Simplified Chinese" msgstr "" -#: dmoj/settings.py:370 +#: dmoj/settings.py:364 msgid "Traditional Chinese" msgstr "" -#: dmoj/urls.py:58 +#: dmoj/urls.py:57 msgid "Login" msgstr "" -#: dmoj/urls.py:106 templates/base.html:193 +#: dmoj/urls.py:105 templates/base.html:190 msgid "Home" msgstr "" @@ -141,48 +141,46 @@ msgstr "" msgid "Associated page" msgstr "" -#: judge/admin/contest.py:30 +#: judge/admin/contest.py:28 msgid "Included contests" msgstr "" -#: judge/admin/contest.py:66 templates/contest/clarification.html:42 -#: templates/contest/contest.html:83 templates/contest/moss.html:43 -#: templates/problem/list.html:214 templates/problem/list.html:232 -#: templates/problem/list.html:350 templates/user/user-problems.html:56 +#: judge/admin/contest.py:64 templates/contest/contest.html:83 +#: templates/contest/moss.html:43 templates/problem/list.html:206 +#: templates/problem/list.html:221 templates/user/user-problems.html:56 #: templates/user/user-problems.html:98 msgid "Problem" msgstr "" -#: judge/admin/contest.py:119 +#: judge/admin/contest.py:112 msgid "Settings" msgstr "" -#: judge/admin/contest.py:121 +#: judge/admin/contest.py:114 msgid "Scheduling" msgstr "" -#: judge/admin/contest.py:122 templates/organization/home.html:107 +#: judge/admin/contest.py:115 msgid "Details" msgstr "" -#: judge/admin/contest.py:123 +#: judge/admin/contest.py:116 msgid "Format" msgstr "" -#: judge/admin/contest.py:124 templates/contest/ranking-table.html:7 -#: templates/user/user-about.html:15 templates/user/user-about.html:45 +#: judge/admin/contest.py:117 templates/contest/ranking-table.html:5 msgid "Rating" msgstr "" -#: judge/admin/contest.py:125 +#: judge/admin/contest.py:118 msgid "Access" msgstr "" -#: judge/admin/contest.py:127 judge/admin/problem.py:131 +#: judge/admin/contest.py:120 judge/admin/problem.py:131 msgid "Justice" msgstr "" -#: judge/admin/contest.py:207 +#: judge/admin/contest.py:158 #, python-format msgid "%d contest successfully marked as visible." msgid_plural "%d contests successfully marked as visible." @@ -193,11 +191,11 @@ msgstr[3] "" msgstr[4] "" msgstr[5] "" -#: judge/admin/contest.py:210 +#: judge/admin/contest.py:161 msgid "Mark contests as visible" msgstr "" -#: judge/admin/contest.py:216 +#: judge/admin/contest.py:165 #, python-format msgid "%d contest successfully marked as hidden." msgid_plural "%d contests successfully marked as hidden." @@ -208,11 +206,11 @@ msgstr[3] "" msgstr[4] "" msgstr[5] "" -#: judge/admin/contest.py:219 +#: judge/admin/contest.py:168 msgid "Mark contests as hidden" msgstr "" -#: judge/admin/contest.py:233 judge/admin/submission.py:164 +#: judge/admin/contest.py:182 judge/admin/submission.py:164 #, python-format msgid "%d submission was successfully scheduled for rejudging." msgid_plural "%d submissions were successfully scheduled for rejudging." @@ -223,7 +221,7 @@ msgstr[3] "" msgstr[4] "" msgstr[5] "" -#: judge/admin/contest.py:308 +#: judge/admin/contest.py:256 #, python-format msgid "%d participation recalculated." msgid_plural "%d participations recalculated." @@ -234,15 +232,15 @@ msgstr[3] "" msgstr[4] "" msgstr[5] "" -#: judge/admin/contest.py:311 +#: judge/admin/contest.py:259 msgid "Recalculate results" msgstr "" -#: judge/admin/contest.py:315 judge/admin/organization.py:65 +#: judge/admin/contest.py:263 judge/admin/organization.py:65 msgid "username" msgstr "" -#: judge/admin/contest.py:320 templates/base.html:277 +#: judge/admin/contest.py:268 templates/base.html:260 msgid "virtual" msgstr "" @@ -250,15 +248,15 @@ msgstr "" msgid "link path" msgstr "" -#: judge/admin/interface.py:65 +#: judge/admin/interface.py:62 msgid "Content" msgstr "" -#: judge/admin/interface.py:66 +#: judge/admin/interface.py:63 msgid "Summary" msgstr "" -#: judge/admin/interface.py:151 +#: judge/admin/interface.py:148 msgid "object" msgstr "" @@ -280,9 +278,8 @@ msgid "Taxonomy" msgstr "" #: judge/admin/problem.py:128 templates/contest/contest.html:84 -#: templates/problem/data.html:429 templates/problem/list.html:222 -#: templates/problem/list.html:248 templates/user/base-users-table.html:10 -#: templates/user/user-about.html:36 templates/user/user-about.html:52 +#: templates/problem/data.html:449 templates/problem/list.html:211 +#: templates/problem/list.html:232 templates/user/base-users-table.html:10 #: templates/user/user-problems.html:58 msgid "Points" msgstr "" @@ -339,7 +336,6 @@ msgid "timezone" msgstr "" #: judge/admin/profile.py:86 judge/admin/submission.py:211 -#: templates/notification/list.html:12 #: templates/organization/requests/log.html:9 #: templates/organization/requests/pending.html:12 #: templates/ticket/list.html:263 @@ -347,7 +343,6 @@ msgid "User" msgstr "" #: judge/admin/profile.py:91 templates/registration/registration_form.html:145 -#: templates/user/import/table_csv.html:8 msgid "Email" msgstr "" @@ -384,7 +379,7 @@ msgstr "" msgid "These problems are NOT allowed to be submitted in this language" msgstr "" -#: judge/admin/runtime.py:83 templates/problem/list.html:352 +#: judge/admin/runtime.py:83 msgid "Description" msgstr "" @@ -431,7 +426,7 @@ msgstr "" msgid "Rejudge the selected submissions" msgstr "" -#: judge/admin/submission.py:193 judge/views/problem_manage.py:159 +#: judge/admin/submission.py:193 judge/views/problem_manage.py:128 #, python-format msgid "%d submission were successfully rescored." msgid_plural "%d submissions were successfully rescored." @@ -446,8 +441,7 @@ msgstr[5] "" msgid "Rescore the selected submissions" msgstr "" -#: judge/admin/submission.py:200 templates/problem/list.html:216 -#: templates/problem/list.html:236 +#: judge/admin/submission.py:200 msgid "Problem code" msgstr "" @@ -455,12 +449,10 @@ msgstr "" msgid "Problem name" msgstr "" -#: judge/admin/submission.py:215 templates/notification/list.html:15 -#: templates/organization/requests/log.html:10 +#: judge/admin/submission.py:215 templates/organization/requests/log.html:10 #: templates/organization/requests/pending.html:13 -#: templates/problem/list.html:351 -#: templates/submission/status-testcases.html:125 -#: templates/submission/status-testcases.html:127 +#: templates/submission/status-testcases.html:105 +#: templates/submission/status-testcases.html:107 msgid "Time" msgstr "" @@ -474,7 +466,7 @@ msgstr "" msgid "%.2f MB" msgstr "" -#: judge/admin/submission.py:227 templates/submission/status-testcases.html:132 +#: judge/admin/submission.py:227 templates/submission/status-testcases.html:112 msgid "Memory" msgstr "" @@ -494,20 +486,20 @@ msgstr "" msgid "Online Judge" msgstr "" -#: judge/comments.py:60 +#: judge/comments.py:41 msgid "Comment body" msgstr "" -#: judge/comments.py:66 judge/views/ticket.py:63 +#: judge/comments.py:47 judge/views/ticket.py:46 msgid "Your part is silent, little toad." msgstr "" -#: judge/comments.py:69 templates/comments/list.html:132 +#: judge/comments.py:50 templates/comments/list.html:131 msgid "" "You need to have solved at least one problem before your voice can be heard." msgstr "" -#: judge/comments.py:113 +#: judge/comments.py:92 msgid "Posted comment" msgstr "" @@ -523,10 +515,6 @@ msgstr "" msgid "ECOO" msgstr "" -#: judge/contest_format/icpc.py:19 -msgid "ICPC" -msgstr "" - #: judge/contest_format/ioi.py:19 msgid "IOI" msgstr "" @@ -539,58 +527,52 @@ msgstr "" msgid "Enable experimental features" msgstr "" -#: judge/forms.py:57 judge/views/organization.py:168 judge/views/register.py:49 +#: judge/forms.py:57 judge/views/organization.py:127 #, python-brace-format msgid "You may not be part of more than {count} public organizations." msgstr "" -#: judge/forms.py:82 -msgid "Any judge" -msgstr "" - -#: judge/forms.py:112 judge/views/register.py:26 +#: judge/forms.py:107 judge/views/register.py:26 #: templates/registration/registration_form.html:139 #: templates/user/base-users-table.html:5 -#: templates/user/import/table_csv.html:4 msgid "Username" msgstr "" -#: judge/forms.py:113 templates/registration/registration_form.html:151 +#: judge/forms.py:108 templates/registration/registration_form.html:151 #: templates/registration/registration_form.html:165 -#: templates/user/import/table_csv.html:5 msgid "Password" msgstr "" -#: judge/forms.py:135 +#: judge/forms.py:130 msgid "Two Factor Authentication tokens must be 6 decimal digits." msgstr "" -#: judge/forms.py:144 templates/registration/totp_auth.html:32 +#: judge/forms.py:139 templates/registration/totp_auth.html:32 msgid "Invalid Two Factor Authentication token." msgstr "" -#: judge/forms.py:148 judge/models/problem.py:97 +#: judge/forms.py:143 judge/models/problem.py:97 msgid "Problem code must be ^[a-z0-9]+$" msgstr "" -#: judge/forms.py:153 +#: judge/forms.py:148 msgid "Problem with code already exists." msgstr "" -#: judge/forms.py:158 judge/models/contest.py:61 +#: judge/forms.py:153 judge/models/contest.py:52 msgid "Contest id must be ^[a-z0-9]+$" msgstr "" -#: judge/forms.py:163 +#: judge/forms.py:158 msgid "Contest with key already exists." msgstr "" -#: judge/jinja2/datetime.py:26 templates/blog/blog.html:26 +#: judge/jinja2/datetime.py:26 templates/blog/content.html:27 #: templates/blog/dashboard.html:21 msgid "N j, Y, g:i a" msgstr "" -#: judge/jinja2/datetime.py:26 templates/chat/message.html:13 +#: judge/jinja2/datetime.py:26 #, python-brace-format msgid "{time}" msgstr "" @@ -620,542 +602,472 @@ msgstr "" msgid "Detect best quality" msgstr "" -#: judge/models/comment.py:26 +#: judge/models/comment.py:25 msgid "Page code must be ^[pcs]:[a-z0-9]+$|^b:\\d+$" msgstr "" -#: judge/models/comment.py:42 +#: judge/models/comment.py:41 msgid "commenter" msgstr "" -#: judge/models/comment.py:44 judge/models/comment.py:177 +#: judge/models/comment.py:43 judge/models/comment.py:176 msgid "associated page" msgstr "" -#: judge/models/comment.py:46 +#: judge/models/comment.py:45 msgid "votes" msgstr "" -#: judge/models/comment.py:48 +#: judge/models/comment.py:47 msgid "hide the comment" msgstr "" -#: judge/models/comment.py:49 +#: judge/models/comment.py:48 msgid "parent" msgstr "" -#: judge/models/comment.py:54 judge/models/comment.py:192 +#: judge/models/comment.py:53 msgid "comment" msgstr "" -#: judge/models/comment.py:55 +#: judge/models/comment.py:54 msgid "comments" msgstr "" -#: judge/models/comment.py:137 judge/models/problem.py:443 +#: judge/models/comment.py:136 judge/models/problem.py:406 #, python-format msgid "Editorial for %s" msgstr "" -#: judge/models/comment.py:172 +#: judge/models/comment.py:171 msgid "comment vote" msgstr "" -#: judge/models/comment.py:173 +#: judge/models/comment.py:172 msgid "comment votes" msgstr "" -#: judge/models/comment.py:182 +#: judge/models/comment.py:181 msgid "Override comment lock" msgstr "" -#: judge/models/comment.py:190 -msgid "owner" -msgstr "" - -#: judge/models/comment.py:193 judge/models/message.py:16 -msgid "read" -msgstr "" - -#: judge/models/comment.py:194 -msgid "category" -msgstr "" - -#: judge/models/comment.py:195 -msgid "html link to comments, used for non-comments" -msgstr "" - -#: judge/models/comment.py:196 -msgid "who trigger, used for non-comment" -msgstr "" - -#: judge/models/contest.py:23 +#: judge/models/contest.py:22 msgid "Invalid colour." msgstr "" -#: judge/models/contest.py:25 +#: judge/models/contest.py:24 msgid "tag name" msgstr "" -#: judge/models/contest.py:26 +#: judge/models/contest.py:25 msgid "Lowercase letters and hyphens only." msgstr "" -#: judge/models/contest.py:27 +#: judge/models/contest.py:26 msgid "tag colour" msgstr "" -#: judge/models/contest.py:28 +#: judge/models/contest.py:27 msgid "tag description" msgstr "" -#: judge/models/contest.py:47 +#: judge/models/contest.py:46 msgid "contest tag" msgstr "" -#: judge/models/contest.py:48 judge/models/contest.py:118 +#: judge/models/contest.py:47 judge/models/contest.py:101 msgid "contest tags" msgstr "" -#: judge/models/contest.py:56 -msgid "Visible" -msgstr "" - -#: judge/models/contest.py:57 -msgid "Hidden for duration of contest" -msgstr "" - -#: judge/models/contest.py:58 -msgid "Hidden for duration of participation" -msgstr "" - -#: judge/models/contest.py:60 +#: judge/models/contest.py:51 msgid "contest id" msgstr "" -#: judge/models/contest.py:62 +#: judge/models/contest.py:53 msgid "contest name" msgstr "" -#: judge/models/contest.py:63 -msgid "These users will be able to edit the contest." +#: judge/models/contest.py:54 +msgid "These people will be able to edit the contest." msgstr "" -#: judge/models/contest.py:65 -msgid "" -"These users will be able to edit the contest, but will not be listed as " -"authors." -msgstr "" - -#: judge/models/contest.py:68 -msgid "These users will be able to view the contest, but not edit it." -msgstr "" - -#: judge/models/contest.py:71 judge/models/runtime.py:136 +#: judge/models/contest.py:56 judge/models/runtime.py:133 msgid "description" msgstr "" -#: judge/models/contest.py:72 judge/models/problem.py:390 -#: judge/models/runtime.py:138 +#: judge/models/contest.py:57 judge/models/problem.py:353 +#: judge/models/runtime.py:135 msgid "problems" msgstr "" -#: judge/models/contest.py:73 judge/models/contest.py:404 +#: judge/models/contest.py:58 judge/models/contest.py:258 msgid "start time" msgstr "" -#: judge/models/contest.py:74 +#: judge/models/contest.py:59 msgid "end time" msgstr "" -#: judge/models/contest.py:75 judge/models/problem.py:118 -#: judge/models/problem.py:414 +#: judge/models/contest.py:60 judge/models/problem.py:118 +#: judge/models/problem.py:377 msgid "time limit" msgstr "" -#: judge/models/contest.py:76 judge/models/problem.py:136 +#: judge/models/contest.py:61 judge/models/problem.py:136 msgid "publicly visible" msgstr "" -#: judge/models/contest.py:77 +#: judge/models/contest.py:62 msgid "" "Should be set even for organization-private contests, where it determines " "whether the contest is visible to members of the specified organizations." msgstr "" -#: judge/models/contest.py:80 +#: judge/models/contest.py:65 msgid "contest rated" msgstr "" -#: judge/models/contest.py:80 +#: judge/models/contest.py:65 msgid "Whether this contest can be rated." msgstr "" -#: judge/models/contest.py:82 -msgid "scoreboard visibility" +#: judge/models/contest.py:67 +msgid "hide scoreboard" msgstr "" -#: judge/models/contest.py:83 -msgid "Scoreboard visibility through the duration of the contest" +#: judge/models/contest.py:68 +msgid "" +"Whether the scoreboard should remain hidden for the duration of the contest." msgstr "" -#: judge/models/contest.py:85 -msgid "view contest scoreboard" -msgstr "" - -#: judge/models/contest.py:87 -msgid "These users will be able to view the scoreboard." -msgstr "" - -#: judge/models/contest.py:88 +#: judge/models/contest.py:71 msgid "no comments" msgstr "" -#: judge/models/contest.py:89 +#: judge/models/contest.py:72 msgid "Use clarification system instead of comments." msgstr "" -#: judge/models/contest.py:91 +#: judge/models/contest.py:74 msgid "Rating floor for contest" msgstr "" -#: judge/models/contest.py:93 +#: judge/models/contest.py:76 msgid "Rating ceiling for contest" msgstr "" -#: judge/models/contest.py:95 +#: judge/models/contest.py:78 msgid "rate all" msgstr "" -#: judge/models/contest.py:95 +#: judge/models/contest.py:78 msgid "Rate all users who joined." msgstr "" -#: judge/models/contest.py:96 +#: judge/models/contest.py:79 msgid "exclude from ratings" msgstr "" -#: judge/models/contest.py:98 +#: judge/models/contest.py:81 msgid "private to specific users" msgstr "" -#: judge/models/contest.py:99 +#: judge/models/contest.py:82 msgid "private contestants" msgstr "" -#: judge/models/contest.py:100 +#: judge/models/contest.py:83 msgid "If private, only these users may see the contest" msgstr "" -#: judge/models/contest.py:102 +#: judge/models/contest.py:85 msgid "hide problem tags" msgstr "" -#: judge/models/contest.py:103 +#: judge/models/contest.py:86 msgid "Whether problem tags should be hidden by default." msgstr "" -#: judge/models/contest.py:105 +#: judge/models/contest.py:88 msgid "run pretests only" msgstr "" -#: judge/models/contest.py:106 +#: judge/models/contest.py:89 msgid "" "Whether judges should grade pretests only, versus all testcases. Commonly " "set during a contest, then unset prior to rejudging user submissions when " "the contest ends." msgstr "" -#: judge/models/contest.py:110 judge/models/interface.py:77 -#: judge/models/problem.py:157 +#: judge/models/contest.py:93 judge/models/problem.py:157 msgid "private to organizations" msgstr "" -#: judge/models/contest.py:111 judge/models/interface.py:75 -#: judge/models/problem.py:155 judge/models/profile.py:77 +#: judge/models/contest.py:94 judge/models/problem.py:155 +#: judge/models/profile.py:77 msgid "organizations" msgstr "" -#: judge/models/contest.py:112 +#: judge/models/contest.py:95 msgid "If private, only these organizations may see the contest" msgstr "" -#: judge/models/contest.py:113 judge/models/problem.py:145 +#: judge/models/contest.py:96 judge/models/problem.py:145 msgid "OpenGraph image" msgstr "" -#: judge/models/contest.py:114 judge/models/profile.py:48 +#: judge/models/contest.py:97 judge/models/profile.py:48 msgid "Logo override image" msgstr "" -#: judge/models/contest.py:116 +#: judge/models/contest.py:99 msgid "" "This image will replace the default site logo for users inside the contest." msgstr "" -#: judge/models/contest.py:119 +#: judge/models/contest.py:102 msgid "the amount of live participants" msgstr "" -#: judge/models/contest.py:120 +#: judge/models/contest.py:103 msgid "contest summary" msgstr "" -#: judge/models/contest.py:121 judge/models/problem.py:147 +#: judge/models/contest.py:104 judge/models/problem.py:147 msgid "Plain-text, shown in meta description tag, e.g. for social media." msgstr "" -#: judge/models/contest.py:122 judge/models/profile.py:47 +#: judge/models/contest.py:105 judge/models/profile.py:47 msgid "access code" msgstr "" -#: judge/models/contest.py:123 +#: judge/models/contest.py:106 msgid "" "An optional code to prompt contestants before they are allowed to join the " "contest. Leave it blank to disable." msgstr "" -#: judge/models/contest.py:125 judge/models/problem.py:141 +#: judge/models/contest.py:108 judge/models/problem.py:141 msgid "personae non gratae" msgstr "" -#: judge/models/contest.py:126 +#: judge/models/contest.py:109 msgid "Bans the selected users from joining this contest." msgstr "" -#: judge/models/contest.py:127 +#: judge/models/contest.py:110 msgid "contest format" msgstr "" -#: judge/models/contest.py:128 +#: judge/models/contest.py:111 msgid "The contest format module to use." msgstr "" -#: judge/models/contest.py:129 +#: judge/models/contest.py:112 msgid "contest format configuration" msgstr "" -#: judge/models/contest.py:130 +#: judge/models/contest.py:113 msgid "" "A JSON object to serve as the configuration for the chosen contest format " "module. Leave empty to use None. Exact format depends on the contest format " "selected." msgstr "" -#: judge/models/contest.py:137 -msgid "precision points" -msgstr "" - -#: judge/models/contest.py:139 -msgid "Number of digits to round points to." -msgstr "" - -#: judge/models/contest.py:383 +#: judge/models/contest.py:239 msgid "See private contests" msgstr "" -#: judge/models/contest.py:384 +#: judge/models/contest.py:240 msgid "Edit own contests" msgstr "" -#: judge/models/contest.py:385 +#: judge/models/contest.py:241 msgid "Edit all contests" msgstr "" -#: judge/models/contest.py:386 +#: judge/models/contest.py:242 msgid "Clone contest" msgstr "" -#: judge/models/contest.py:387 templates/contest/moss.html:74 +#: judge/models/contest.py:243 templates/contest/moss.html:74 msgid "MOSS contest" msgstr "" -#: judge/models/contest.py:388 +#: judge/models/contest.py:244 msgid "Rate contests" msgstr "" -#: judge/models/contest.py:389 +#: judge/models/contest.py:245 msgid "Contest access codes" msgstr "" -#: judge/models/contest.py:390 +#: judge/models/contest.py:246 msgid "Create private contests" msgstr "" -#: judge/models/contest.py:391 -msgid "Change contest visibility" -msgstr "" - -#: judge/models/contest.py:392 -msgid "Edit contest problem label script" -msgstr "" - -#: judge/models/contest.py:394 judge/models/contest.py:492 -#: judge/models/contest.py:529 judge/models/contest.py:552 -#: judge/models/submission.py:84 +#: judge/models/contest.py:248 judge/models/contest.py:345 +#: judge/models/contest.py:382 judge/models/contest.py:404 +#: judge/models/submission.py:83 msgid "contest" msgstr "" -#: judge/models/contest.py:395 +#: judge/models/contest.py:249 msgid "contests" msgstr "" -#: judge/models/contest.py:402 +#: judge/models/contest.py:256 msgid "associated contest" msgstr "" -#: judge/models/contest.py:405 +#: judge/models/contest.py:259 msgid "score" msgstr "" -#: judge/models/contest.py:406 +#: judge/models/contest.py:260 msgid "cumulative time" msgstr "" -#: judge/models/contest.py:407 +#: judge/models/contest.py:261 msgid "is disqualified" msgstr "" -#: judge/models/contest.py:408 +#: judge/models/contest.py:262 msgid "Whether this participation is disqualified." msgstr "" -#: judge/models/contest.py:409 -msgid "tie-breaking field" -msgstr "" - -#: judge/models/contest.py:410 +#: judge/models/contest.py:263 msgid "virtual participation id" msgstr "" -#: judge/models/contest.py:411 +#: judge/models/contest.py:264 msgid "0 means non-virtual, otherwise the n-th virtual participation." msgstr "" -#: judge/models/contest.py:412 +#: judge/models/contest.py:265 msgid "contest format specific data" msgstr "" -#: judge/models/contest.py:478 +#: judge/models/contest.py:331 #, python-format msgid "%s spectating in %s" msgstr "" -#: judge/models/contest.py:480 +#: judge/models/contest.py:333 #, python-format msgid "%s in %s, v%d" msgstr "" -#: judge/models/contest.py:481 +#: judge/models/contest.py:334 #, python-format msgid "%s in %s" msgstr "" -#: judge/models/contest.py:484 +#: judge/models/contest.py:337 msgid "contest participation" msgstr "" -#: judge/models/contest.py:485 +#: judge/models/contest.py:338 msgid "contest participations" msgstr "" -#: judge/models/contest.py:491 judge/models/contest.py:513 -#: judge/models/contest.py:553 judge/models/problem.py:389 -#: judge/models/problem.py:394 judge/models/problem.py:412 -#: judge/models/problem_data.py:40 +#: judge/models/contest.py:344 judge/models/contest.py:366 +#: judge/models/contest.py:405 judge/models/problem.py:352 +#: judge/models/problem.py:357 judge/models/problem.py:375 +#: judge/models/problem_data.py:38 msgid "problem" msgstr "" -#: judge/models/contest.py:493 judge/models/contest.py:517 +#: judge/models/contest.py:346 judge/models/contest.py:370 #: judge/models/problem.py:129 msgid "points" msgstr "" -#: judge/models/contest.py:494 +#: judge/models/contest.py:347 msgid "partial" msgstr "" -#: judge/models/contest.py:495 judge/models/contest.py:518 +#: judge/models/contest.py:348 judge/models/contest.py:371 msgid "is pretested" msgstr "" -#: judge/models/contest.py:496 judge/models/interface.py:43 +#: judge/models/contest.py:349 judge/models/interface.py:43 msgid "order" msgstr "" -#: judge/models/contest.py:497 +#: judge/models/contest.py:350 msgid "0 to not show testcases, 1 to show" msgstr "" -#: judge/models/contest.py:498 +#: judge/models/contest.py:351 msgid "visible testcases" msgstr "" -#: judge/models/contest.py:499 +#: judge/models/contest.py:352 msgid "Maximum number of submissions for this problem, or 0 for no limit." msgstr "" -#: judge/models/contest.py:501 +#: judge/models/contest.py:354 msgid "Why include a problem you can't submit to?" msgstr "" -#: judge/models/contest.py:506 +#: judge/models/contest.py:359 msgid "contest problem" msgstr "" -#: judge/models/contest.py:507 +#: judge/models/contest.py:360 msgid "contest problems" msgstr "" -#: judge/models/contest.py:511 judge/models/submission.py:183 +#: judge/models/contest.py:364 judge/models/submission.py:181 msgid "submission" msgstr "" -#: judge/models/contest.py:515 judge/models/contest.py:530 +#: judge/models/contest.py:368 judge/models/contest.py:383 msgid "participation" msgstr "" -#: judge/models/contest.py:519 +#: judge/models/contest.py:372 msgid "Whether this submission was ran only on pretests." msgstr "" -#: judge/models/contest.py:523 +#: judge/models/contest.py:376 msgid "contest submission" msgstr "" -#: judge/models/contest.py:524 +#: judge/models/contest.py:377 msgid "contest submissions" msgstr "" -#: judge/models/contest.py:532 +#: judge/models/contest.py:385 msgid "rank" msgstr "" -#: judge/models/contest.py:533 +#: judge/models/contest.py:386 msgid "rating" msgstr "" -#: judge/models/contest.py:534 +#: judge/models/contest.py:387 msgid "volatility" msgstr "" -#: judge/models/contest.py:535 +#: judge/models/contest.py:388 msgid "last rated" msgstr "" -#: judge/models/contest.py:539 +#: judge/models/contest.py:392 msgid "contest rating" msgstr "" -#: judge/models/contest.py:540 +#: judge/models/contest.py:393 msgid "contest ratings" msgstr "" -#: judge/models/contest.py:560 +#: judge/models/contest.py:412 msgid "contest moss result" msgstr "" -#: judge/models/contest.py:561 +#: judge/models/contest.py:413 msgid "contest moss results" msgstr "" @@ -1195,7 +1107,7 @@ msgstr "" msgid "post title" msgstr "" -#: judge/models/interface.py:67 judge/models/problem.py:432 +#: judge/models/interface.py:67 judge/models/problem.py:395 msgid "authors" msgstr "" @@ -1203,7 +1115,7 @@ msgstr "" msgid "slug" msgstr "" -#: judge/models/interface.py:69 judge/models/problem.py:430 +#: judge/models/interface.py:69 judge/models/problem.py:393 msgid "public visibility" msgstr "" @@ -1227,19 +1139,15 @@ msgstr "" msgid "openGraph image" msgstr "" -#: judge/models/interface.py:76 -msgid "If private, only these organizations may see the blog post." -msgstr "" - -#: judge/models/interface.py:105 +#: judge/models/interface.py:91 msgid "Edit all posts" msgstr "" -#: judge/models/interface.py:107 +#: judge/models/interface.py:93 msgid "blog post" msgstr "" -#: judge/models/interface.py:108 +#: judge/models/interface.py:94 msgid "blog posts" msgstr "" @@ -1263,6 +1171,10 @@ msgstr "" msgid "message timestamp" msgstr "" +#: judge/models/message.py:16 +msgid "read" +msgstr "" + #: judge/models/message.py:20 msgid "messages in the thread" msgstr "" @@ -1399,7 +1311,7 @@ msgid "" "are supported." msgstr "" -#: judge/models/problem.py:123 judge/models/problem.py:417 +#: judge/models/problem.py:123 judge/models/problem.py:380 msgid "memory limit" msgstr "" @@ -1472,188 +1384,188 @@ msgstr "" msgid "If private, only these organizations may see the problem." msgstr "" -#: judge/models/problem.py:395 judge/models/problem.py:413 -#: judge/models/runtime.py:111 +#: judge/models/problem.py:358 judge/models/problem.py:376 +#: judge/models/runtime.py:108 msgid "language" msgstr "" -#: judge/models/problem.py:396 +#: judge/models/problem.py:359 msgid "translated name" msgstr "" -#: judge/models/problem.py:397 +#: judge/models/problem.py:360 msgid "translated description" msgstr "" -#: judge/models/problem.py:401 +#: judge/models/problem.py:364 msgid "problem translation" msgstr "" -#: judge/models/problem.py:402 +#: judge/models/problem.py:365 msgid "problem translations" msgstr "" -#: judge/models/problem.py:406 +#: judge/models/problem.py:369 msgid "clarified problem" msgstr "" -#: judge/models/problem.py:407 +#: judge/models/problem.py:370 msgid "clarification body" msgstr "" -#: judge/models/problem.py:408 +#: judge/models/problem.py:371 msgid "clarification timestamp" msgstr "" -#: judge/models/problem.py:423 +#: judge/models/problem.py:386 msgid "language-specific resource limit" msgstr "" -#: judge/models/problem.py:424 +#: judge/models/problem.py:387 msgid "language-specific resource limits" msgstr "" -#: judge/models/problem.py:428 +#: judge/models/problem.py:391 msgid "associated problem" msgstr "" -#: judge/models/problem.py:431 +#: judge/models/problem.py:394 msgid "publish date" msgstr "" -#: judge/models/problem.py:433 +#: judge/models/problem.py:396 msgid "editorial content" msgstr "" -#: judge/models/problem.py:449 +#: judge/models/problem.py:412 msgid "solution" msgstr "" -#: judge/models/problem.py:450 +#: judge/models/problem.py:413 msgid "solutions" msgstr "" -#: judge/models/problem_data.py:26 +#: judge/models/problem_data.py:24 msgid "Standard" msgstr "" -#: judge/models/problem_data.py:27 +#: judge/models/problem_data.py:25 msgid "Floats" msgstr "" -#: judge/models/problem_data.py:28 +#: judge/models/problem_data.py:26 msgid "Floats (absolute)" msgstr "" -#: judge/models/problem_data.py:29 +#: judge/models/problem_data.py:27 msgid "Floats (relative)" msgstr "" -#: judge/models/problem_data.py:30 +#: judge/models/problem_data.py:28 msgid "Non-trailing spaces" msgstr "" -#: judge/models/problem_data.py:31 +#: judge/models/problem_data.py:29 msgid "Unordered" msgstr "" -#: judge/models/problem_data.py:32 +#: judge/models/problem_data.py:30 msgid "Byte identical" msgstr "" -#: judge/models/problem_data.py:33 +#: judge/models/problem_data.py:31 msgid "Line-by-line" msgstr "" -#: judge/models/problem_data.py:34 +#: judge/models/problem_data.py:32 msgid "Custom checker (PY)" msgstr "" -#: judge/models/problem_data.py:35 +#: judge/models/problem_data.py:33 msgid "Custom validator (CPP)" msgstr "" -#: judge/models/problem_data.py:42 +#: judge/models/problem_data.py:40 msgid "data zip file" msgstr "" -#: judge/models/problem_data.py:44 +#: judge/models/problem_data.py:42 msgid "generator file" msgstr "" -#: judge/models/problem_data.py:46 judge/models/problem_data.py:121 +#: judge/models/problem_data.py:44 judge/models/problem_data.py:110 msgid "output prefix length" msgstr "" -#: judge/models/problem_data.py:47 judge/models/problem_data.py:122 +#: judge/models/problem_data.py:45 judge/models/problem_data.py:111 msgid "output limit length" msgstr "" -#: judge/models/problem_data.py:48 +#: judge/models/problem_data.py:46 msgid "init.yml generation feedback" msgstr "" -#: judge/models/problem_data.py:49 judge/models/problem_data.py:123 +#: judge/models/problem_data.py:47 judge/models/problem_data.py:112 msgid "checker" msgstr "" -#: judge/models/problem_data.py:50 judge/models/problem_data.py:124 +#: judge/models/problem_data.py:48 judge/models/problem_data.py:113 msgid "checker arguments" msgstr "" -#: judge/models/problem_data.py:51 judge/models/problem_data.py:125 +#: judge/models/problem_data.py:49 judge/models/problem_data.py:114 msgid "checker arguments as a JSON object" msgstr "" -#: judge/models/problem_data.py:52 +#: judge/models/problem_data.py:50 msgid "custom checker file" msgstr "" -#: judge/models/problem_data.py:58 +#: judge/models/problem_data.py:56 msgid "custom validator file" msgstr "" -#: judge/models/problem_data.py:108 +#: judge/models/problem_data.py:97 msgid "problem data set" msgstr "" -#: judge/models/problem_data.py:110 +#: judge/models/problem_data.py:99 msgid "case position" msgstr "" -#: judge/models/problem_data.py:111 +#: judge/models/problem_data.py:100 msgid "case type" msgstr "" -#: judge/models/problem_data.py:112 +#: judge/models/problem_data.py:101 msgid "Normal case" msgstr "" -#: judge/models/problem_data.py:113 +#: judge/models/problem_data.py:102 msgid "Batch start" msgstr "" -#: judge/models/problem_data.py:114 +#: judge/models/problem_data.py:103 msgid "Batch end" msgstr "" -#: judge/models/problem_data.py:116 +#: judge/models/problem_data.py:105 msgid "input file name" msgstr "" -#: judge/models/problem_data.py:117 +#: judge/models/problem_data.py:106 msgid "output file name" msgstr "" -#: judge/models/problem_data.py:118 +#: judge/models/problem_data.py:107 msgid "generator arguments" msgstr "" -#: judge/models/problem_data.py:119 +#: judge/models/problem_data.py:108 msgid "point value" msgstr "" -#: judge/models/problem_data.py:120 +#: judge/models/problem_data.py:109 msgid "case is pretest?" msgstr "" @@ -1726,7 +1638,7 @@ msgid "" msgstr "" #: judge/models/profile.py:76 judge/models/profile.py:93 -#: judge/models/profile.py:212 +#: judge/models/profile.py:192 msgid "organization" msgstr "" @@ -1822,31 +1734,31 @@ msgstr "" msgid "Notes for administrators regarding this user." msgstr "" -#: judge/models/profile.py:206 +#: judge/models/profile.py:186 msgid "user profile" msgstr "" -#: judge/models/profile.py:207 +#: judge/models/profile.py:187 msgid "user profiles" msgstr "" -#: judge/models/profile.py:214 +#: judge/models/profile.py:194 msgid "request time" msgstr "" -#: judge/models/profile.py:215 +#: judge/models/profile.py:195 msgid "state" msgstr "" -#: judge/models/profile.py:220 +#: judge/models/profile.py:200 msgid "reason" msgstr "" -#: judge/models/profile.py:223 +#: judge/models/profile.py:203 msgid "organization join request" msgstr "" -#: judge/models/profile.py:224 +#: judge/models/profile.py:204 msgid "organization join requests" msgstr "" @@ -1937,86 +1849,86 @@ msgstr "" msgid "The extension of source files, e.g., \"py\" or \"cpp\"." msgstr "" -#: judge/models/runtime.py:112 +#: judge/models/runtime.py:109 msgid "languages" msgstr "" -#: judge/models/runtime.py:116 +#: judge/models/runtime.py:113 msgid "language to which this runtime belongs" msgstr "" -#: judge/models/runtime.py:117 +#: judge/models/runtime.py:114 msgid "judge on which this runtime exists" msgstr "" -#: judge/models/runtime.py:118 +#: judge/models/runtime.py:115 msgid "runtime name" msgstr "" -#: judge/models/runtime.py:119 +#: judge/models/runtime.py:116 msgid "runtime version" msgstr "" -#: judge/models/runtime.py:120 +#: judge/models/runtime.py:117 msgid "order in which to display this runtime" msgstr "" -#: judge/models/runtime.py:124 +#: judge/models/runtime.py:121 msgid "Server name, hostname-style" msgstr "" -#: judge/models/runtime.py:125 +#: judge/models/runtime.py:122 msgid "time of creation" msgstr "" -#: judge/models/runtime.py:126 +#: judge/models/runtime.py:123 msgid "A key to authenticate this judge" msgstr "" -#: judge/models/runtime.py:127 +#: judge/models/runtime.py:124 msgid "authentication key" msgstr "" -#: judge/models/runtime.py:128 +#: judge/models/runtime.py:125 msgid "block judge" msgstr "" -#: judge/models/runtime.py:129 +#: judge/models/runtime.py:126 msgid "" "Whether this judge should be blocked from connecting, even if its key is " "correct." msgstr "" -#: judge/models/runtime.py:131 +#: judge/models/runtime.py:128 msgid "judge online status" msgstr "" -#: judge/models/runtime.py:132 +#: judge/models/runtime.py:129 msgid "judge start time" msgstr "" -#: judge/models/runtime.py:133 +#: judge/models/runtime.py:130 msgid "response time" msgstr "" -#: judge/models/runtime.py:134 +#: judge/models/runtime.py:131 msgid "system load" msgstr "" -#: judge/models/runtime.py:135 +#: judge/models/runtime.py:132 msgid "Load for the last minute, divided by processors to be fair." msgstr "" -#: judge/models/runtime.py:139 judge/models/runtime.py:179 +#: judge/models/runtime.py:136 judge/models/runtime.py:176 msgid "judges" msgstr "" -#: judge/models/runtime.py:178 +#: judge/models/runtime.py:175 msgid "judge" msgstr "" #: judge/models/submission.py:20 judge/models/submission.py:47 -#: judge/utils/problems.py:79 +#: judge/utils/problems.py:77 msgid "Accepted" msgstr "" @@ -2045,7 +1957,7 @@ msgid "Runtime Error" msgstr "" #: judge/models/submission.py:27 judge/models/submission.py:41 -#: judge/models/submission.py:55 judge/utils/problems.py:81 +#: judge/models/submission.py:55 judge/utils/problems.py:79 msgid "Compile Error" msgstr "" @@ -2086,15 +1998,15 @@ msgstr "" msgid "submission time" msgstr "" -#: judge/models/submission.py:67 judge/models/submission.py:203 +#: judge/models/submission.py:67 judge/models/submission.py:201 msgid "execution time" msgstr "" -#: judge/models/submission.py:68 judge/models/submission.py:204 +#: judge/models/submission.py:68 judge/models/submission.py:202 msgid "memory usage" msgstr "" -#: judge/models/submission.py:69 judge/models/submission.py:205 +#: judge/models/submission.py:69 judge/models/submission.py:203 msgid "points granted" msgstr "" @@ -2131,62 +2043,58 @@ msgid "judged on" msgstr "" #: judge/models/submission.py:81 -msgid "submission judge time" -msgstr "" - -#: judge/models/submission.py:82 msgid "was rejudged by admin" msgstr "" -#: judge/models/submission.py:83 +#: judge/models/submission.py:82 msgid "was ran on pretests only" msgstr "" -#: judge/models/submission.py:184 templates/contest/moss.html:58 +#: judge/models/submission.py:182 templates/contest/moss.html:58 msgid "submissions" msgstr "" -#: judge/models/submission.py:188 judge/models/submission.py:199 +#: judge/models/submission.py:186 judge/models/submission.py:197 msgid "associated submission" msgstr "" -#: judge/models/submission.py:190 +#: judge/models/submission.py:188 msgid "source code" msgstr "" -#: judge/models/submission.py:201 +#: judge/models/submission.py:199 msgid "test case ID" msgstr "" -#: judge/models/submission.py:202 +#: judge/models/submission.py:200 msgid "status flag" msgstr "" -#: judge/models/submission.py:206 +#: judge/models/submission.py:204 msgid "points possible" msgstr "" -#: judge/models/submission.py:207 +#: judge/models/submission.py:205 msgid "batch number" msgstr "" -#: judge/models/submission.py:208 +#: judge/models/submission.py:206 msgid "judging feedback" msgstr "" -#: judge/models/submission.py:209 +#: judge/models/submission.py:207 msgid "extended judging feedback" msgstr "" -#: judge/models/submission.py:210 +#: judge/models/submission.py:208 msgid "program output" msgstr "" -#: judge/models/submission.py:218 +#: judge/models/submission.py:216 msgid "submission test case" msgstr "" -#: judge/models/submission.py:219 +#: judge/models/submission.py:217 msgid "submission test cases" msgstr "" @@ -2238,21 +2146,12 @@ msgstr "" msgid "message time" msgstr "" -#: judge/pdf_problems.py:147 judge/pdf_problems.py:199 -#: judge/pdf_problems.py:259 +#: judge/pdf_problems.py:134 judge/pdf_problems.py:186 +#: judge/pdf_problems.py:246 msgid "Page [page] of [topage]" msgstr "" -#: judge/pdf_problems.py:280 -#, python-format -msgid "Page %s of %s" -msgstr "" - -#: judge/tasks/contest.py:19 -msgid "Recalculating contest scores" -msgstr "" - -#: judge/tasks/contest.py:40 +#: judge/tasks/moss.py:25 msgid "Running MOSS" msgstr "" @@ -2264,60 +2163,60 @@ msgstr "" msgid "Recalculating user points" msgstr "" -#: judge/utils/problem_data.py:70 +#: judge/utils/problem_data.py:68 msgid "Empty batches not allowed." msgstr "" -#: judge/utils/problem_data.py:78 judge/utils/problem_data.py:99 +#: judge/utils/problem_data.py:76 judge/utils/problem_data.py:97 msgid "How did you corrupt the custom checker path?" msgstr "" -#: judge/utils/problem_data.py:120 +#: judge/utils/problem_data.py:118 #, python-format msgid "Points must be defined for non-batch case #%d." msgstr "" -#: judge/utils/problem_data.py:125 +#: judge/utils/problem_data.py:123 #, python-format msgid "Input file for case %d does not exist: %s" msgstr "" -#: judge/utils/problem_data.py:128 +#: judge/utils/problem_data.py:126 #, python-format msgid "Output file for case %d does not exist: %s" msgstr "" -#: judge/utils/problem_data.py:153 +#: judge/utils/problem_data.py:151 #, python-format msgid "Batch start case #%d requires points." msgstr "" -#: judge/utils/problem_data.py:174 +#: judge/utils/problem_data.py:172 #, python-format msgid "Attempt to end batch outside of one in case #%d" msgstr "" -#: judge/utils/problem_data.py:192 +#: judge/utils/problem_data.py:190 msgid "How did you corrupt the zip path?" msgstr "" -#: judge/utils/problem_data.py:198 +#: judge/utils/problem_data.py:196 msgid "How did you corrupt the generator path?" msgstr "" -#: judge/utils/problems.py:80 +#: judge/utils/problems.py:78 msgid "Wrong" msgstr "" -#: judge/utils/problems.py:82 +#: judge/utils/problems.py:80 msgid "Timeout" msgstr "" -#: judge/utils/problems.py:83 +#: judge/utils/problems.py:81 msgid "Error" msgstr "" -#: judge/utils/problems.py:94 +#: judge/utils/problems.py:92 msgid "Can't pass both queryset and keyword filters" msgstr "" @@ -2372,8 +2271,7 @@ msgctxt "hours and minutes" msgid "%h:%m" msgstr "" -#: judge/views/about.py:7 templates/organization/home.html:112 -#: templates/user/user-about.html:83 templates/user/user-tabs.html:4 +#: judge/views/about.py:7 templates/user/user-about.html:33 msgid "About" msgstr "" @@ -2381,165 +2279,156 @@ msgstr "" msgid "Custom Checker Sample" msgstr "" -#: judge/views/blog.py:45 +#: judge/views/blog.py:38 #, python-format msgid "Page %d of Posts" msgstr "" -#: judge/views/comment.py:28 +#: judge/views/comment.py:27 msgid "Messing around, are we?" msgstr "" -#: judge/views/comment.py:37 +#: judge/views/comment.py:36 msgid "You must solve at least one problem before you can vote." msgstr "" -#: judge/views/comment.py:64 +#: judge/views/comment.py:63 msgid "You already voted." msgstr "" -#: judge/views/comment.py:126 judge/views/organization.py:344 +#: judge/views/comment.py:120 judge/views/organization.py:299 msgid "Edited from site" msgstr "" -#: judge/views/comment.py:147 +#: judge/views/comment.py:141 msgid "Editing comment" msgstr "" -#: judge/views/contests.py:57 judge/views/contests.py:247 -#: judge/views/contests.py:250 judge/views/contests.py:424 +#: judge/views/contests.py:55 judge/views/contests.py:215 +#: judge/views/contests.py:218 judge/views/contests.py:389 msgid "No such contest" msgstr "" -#: judge/views/contests.py:58 judge/views/contests.py:248 +#: judge/views/contests.py:56 judge/views/contests.py:216 #, python-format msgid "Could not find a contest with the key \"%s\"." msgstr "" -#: judge/views/contests.py:71 +#: judge/views/contests.py:81 msgid "Contests" msgstr "" -#: judge/views/contests.py:251 +#: judge/views/contests.py:219 msgid "Could not find such contest." msgstr "" -#: judge/views/contests.py:254 +#: judge/views/contests.py:222 #, python-format msgid "Access to contest \"%s\" denied" msgstr "" -#: judge/views/contests.py:278 +#: judge/views/contests.py:246 msgid "Clone Contest" msgstr "" -#: judge/views/contests.py:343 +#: judge/views/contests.py:309 msgid "Contest not ongoing" msgstr "" -#: judge/views/contests.py:344 +#: judge/views/contests.py:310 #, python-format msgid "\"%s\" is not currently ongoing." msgstr "" -#: judge/views/contests.py:348 +#: judge/views/contests.py:314 msgid "Already in contest" msgstr "" -#: judge/views/contests.py:349 +#: judge/views/contests.py:315 #, python-format msgid "You are already in a contest: \"%s\"." msgstr "" -#: judge/views/contests.py:352 +#: judge/views/contests.py:318 msgid "Banned from joining" msgstr "" -#: judge/views/contests.py:353 +#: judge/views/contests.py:319 msgid "" "You have been declared persona non grata for this contest. You are " "permanently barred from joining this contest." msgstr "" -#: judge/views/contests.py:414 +#: judge/views/contests.py:379 #, python-format msgid "Enter access code for \"%s\"" msgstr "" -#: judge/views/contests.py:425 +#: judge/views/contests.py:390 #, python-format msgid "You are not in contest \"%s\"." msgstr "" -#: judge/views/contests.py:444 +#: judge/views/contests.py:409 msgid "ContestCalendar requires integer year and month" msgstr "" -#: judge/views/contests.py:484 +#: judge/views/contests.py:449 #, python-format msgid "Contests in %(month)s" msgstr "" -#: judge/views/contests.py:484 +#: judge/views/contests.py:449 msgid "F Y" msgstr "" -#: judge/views/contests.py:532 +#: judge/views/contests.py:496 #, python-format msgid "%s Statistics" msgstr "" -#: judge/views/contests.py:717 +#: judge/views/contests.py:601 +msgid "???" +msgstr "" + +#: judge/views/contests.py:664 #, python-format msgid "%s Rankings" msgstr "" -#: judge/views/contests.py:725 -msgid "???" -msgstr "" - -#: judge/views/contests.py:741 +#: judge/views/contests.py:680 #, python-format msgid "Your participation in %s" msgstr "" -#: judge/views/contests.py:742 +#: judge/views/contests.py:681 #, python-format msgid "%s's participation in %s" msgstr "" -#: judge/views/contests.py:749 +#: judge/views/contests.py:685 msgid "Live" msgstr "" -#: judge/views/contests.py:761 templates/contest/contest-tabs.html:13 +#: judge/views/contests.py:697 msgid "Participation" msgstr "" -#: judge/views/contests.py:808 +#: judge/views/contests.py:743 #, python-format msgid "%s MOSS Results" msgstr "" -#: judge/views/contests.py:835 +#: judge/views/contests.py:770 #, python-format msgid "Running MOSS for %s..." msgstr "" -#: judge/views/contests.py:858 +#: judge/views/contests.py:793 #, python-format msgid "Contest tag: %s" msgstr "" -#: judge/views/contests.py:868 judge/views/ticket.py:57 -msgid "Issue description" -msgstr "" - -#: judge/views/contests.py:911 -#, python-format -msgid "New clarification for %s" -msgstr "" - #: judge/views/error.py:14 msgid "404 error" msgstr "" @@ -2560,83 +2449,76 @@ msgid "corrupt page %s" msgstr "" #: judge/views/language.py:12 templates/status/judge-status-table.html:9 -#: templates/status/status-tabs.html:5 msgid "Runtimes" msgstr "" -#: judge/views/notification.py:40 -#, python-format -msgid "Notifications (%d unseen)" -msgstr "" - -#: judge/views/organization.py:59 judge/views/organization.py:62 +#: judge/views/organization.py:44 judge/views/organization.py:47 msgid "No such organization" msgstr "" -#: judge/views/organization.py:60 +#: judge/views/organization.py:45 #, python-format msgid "Could not find an organization with the key \"%s\"." msgstr "" -#: judge/views/organization.py:63 +#: judge/views/organization.py:48 msgid "Could not find such organization." msgstr "" -#: judge/views/organization.py:79 judge/views/register.py:34 -#: templates/organization/list.html:32 templates/user/import/table_csv.html:9 -#: templates/user/user-list-tabs.html:6 +#: judge/views/organization.py:72 judge/views/register.py:34 +#: templates/organization/list.html:15 msgid "Organizations" msgstr "" -#: judge/views/organization.py:130 +#: judge/views/organization.py:93 #, python-format msgid "%s Members" msgstr "" -#: judge/views/organization.py:159 judge/views/organization.py:162 -#: judge/views/organization.py:167 +#: judge/views/organization.py:118 judge/views/organization.py:121 +#: judge/views/organization.py:126 msgid "Joining organization" msgstr "" -#: judge/views/organization.py:159 +#: judge/views/organization.py:118 msgid "You are already in the organization." msgstr "" -#: judge/views/organization.py:162 +#: judge/views/organization.py:121 msgid "This organization is not open." msgstr "" -#: judge/views/organization.py:179 +#: judge/views/organization.py:138 msgid "Leaving organization" msgstr "" -#: judge/views/organization.py:179 +#: judge/views/organization.py:138 #, python-format msgid "You are not in \"%s\"." msgstr "" -#: judge/views/organization.py:203 +#: judge/views/organization.py:162 #, python-format msgid "Request to join %s" msgstr "" -#: judge/views/organization.py:221 +#: judge/views/organization.py:180 msgid "Join request detail" msgstr "" -#: judge/views/organization.py:254 +#: judge/views/organization.py:209 #, python-format msgid "Managing join requests for %s" msgstr "" -#: judge/views/organization.py:285 +#: judge/views/organization.py:240 #, python-format msgid "" "Your organization can only receive %d more members. You cannot approve %d " "users." msgstr "" -#: judge/views/organization.py:297 +#: judge/views/organization.py:252 #, python-format msgid "Approved %d user." msgid_plural "Approved %d users." @@ -2647,7 +2529,7 @@ msgstr[3] "" msgstr[4] "" msgstr[5] "" -#: judge/views/organization.py:298 +#: judge/views/organization.py:253 #, python-format msgid "Rejected %d user." msgid_plural "Rejected %d users." @@ -2658,32 +2540,32 @@ msgstr[3] "" msgstr[4] "" msgstr[5] "" -#: judge/views/organization.py:328 +#: judge/views/organization.py:283 #, python-format msgid "Editing %s" msgstr "" -#: judge/views/organization.py:352 judge/views/organization.py:360 +#: judge/views/organization.py:307 judge/views/organization.py:315 msgid "Can't edit organization" msgstr "" -#: judge/views/organization.py:353 +#: judge/views/organization.py:308 msgid "You are not allowed to edit this organization." msgstr "" -#: judge/views/organization.py:361 +#: judge/views/organization.py:316 msgid "You are not allowed to kick people from this organization." msgstr "" -#: judge/views/organization.py:366 judge/views/organization.py:370 +#: judge/views/organization.py:321 judge/views/organization.py:325 msgid "Can't kick user" msgstr "" -#: judge/views/organization.py:367 +#: judge/views/organization.py:322 msgid "The user you are trying to kick does not exist!" msgstr "" -#: judge/views/organization.py:371 +#: judge/views/organization.py:326 #, python-format msgid "The user you are trying to kick is not in organization: %s." msgstr "" @@ -2707,36 +2589,35 @@ msgstr "" msgid "Editorial for {0}" msgstr "" -#: judge/views/problem.py:285 templates/contest/contest.html:79 -#: templates/user/user-about.html:28 templates/user/user-tabs.html:5 -#: templates/user/users-table.html:31 +#: judge/views/problem.py:286 templates/contest/contest.html:79 +#: templates/user/users-table.html:23 msgid "Problems" msgstr "" -#: judge/views/problem.py:585 +#: judge/views/problem.py:547 msgid "Banned from submitting" msgstr "" -#: judge/views/problem.py:586 +#: judge/views/problem.py:548 msgid "" "You have been declared persona non grata for this problem. You are " "permanently barred from submitting this problem." msgstr "" -#: judge/views/problem.py:600 +#: judge/views/problem.py:562 msgid "Too many submissions" msgstr "" -#: judge/views/problem.py:601 +#: judge/views/problem.py:563 msgid "You have exceeded the submission limit for this problem." msgstr "" -#: judge/views/problem.py:661 judge/views/problem.py:664 +#: judge/views/problem.py:633 judge/views/problem.py:636 #, python-format msgid "Submit to %(problem)s" msgstr "" -#: judge/views/problem.py:679 +#: judge/views/problem.py:652 msgid "Clone Problem" msgstr "" @@ -2777,22 +2658,22 @@ msgstr "" msgid "Generated init.yml for %s" msgstr "" -#: judge/views/problem_manage.py:52 judge/views/problem_manage.py:55 +#: judge/views/problem_manage.py:50 judge/views/problem_manage.py:53 #, python-format msgid "Managing submissions for %s" msgstr "" -#: judge/views/problem_manage.py:97 +#: judge/views/problem_manage.py:95 #, python-format msgid "Rejudging selected submissions for %s..." msgstr "" -#: judge/views/problem_manage.py:141 +#: judge/views/problem_manage.py:110 #, python-format msgid "Rescoring all submissions for %s..." msgstr "" -#: judge/views/problem_manage.py:150 +#: judge/views/problem_manage.py:119 #, python-format msgid "Successfully scheduled %d submission for rejudging." msgid_plural "Successfully scheduled %d submissions for rejudging." @@ -2845,24 +2726,24 @@ msgstr "" msgid "Subscribe to newsletter?" msgstr "" -#: judge/views/register.py:55 +#: judge/views/register.py:45 #, python-format msgid "" "The email address \"%s\" is already taken. Only one registration is allowed " "per address." msgstr "" -#: judge/views/register.py:61 +#: judge/views/register.py:51 msgid "" "Your email provider is not allowed due to history of abuse. Please use a " "reputable email provider." msgstr "" -#: judge/views/register.py:67 judge/views/register.py:105 +#: judge/views/register.py:57 judge/views/register.py:95 msgid "Registration" msgstr "" -#: judge/views/register.py:116 +#: judge/views/register.py:106 msgid "Authentication failure" msgstr "" @@ -2878,100 +2759,104 @@ msgstr "" msgid "Version matrix" msgstr "" -#: judge/views/submission.py:84 judge/views/submission.py:91 +#: judge/views/submission.py:83 judge/views/submission.py:90 #, python-format msgid "Submission of %(problem)s by %(user)s" msgstr "" -#: judge/views/submission.py:244 judge/views/submission.py:245 -#: templates/problem/problem.html:167 +#: judge/views/submission.py:227 judge/views/submission.py:228 +#: templates/problem/problem.html:127 msgid "All submissions" msgstr "" -#: judge/views/submission.py:404 +#: judge/views/submission.py:384 msgid "All my submissions" msgstr "" -#: judge/views/submission.py:405 +#: judge/views/submission.py:385 #, python-format msgid "All submissions by %s" msgstr "" -#: judge/views/submission.py:436 +#: judge/views/submission.py:416 #, python-format msgid "All submissions for %s" msgstr "" -#: judge/views/submission.py:455 +#: judge/views/submission.py:435 msgid "Must pass a problem" msgstr "" -#: judge/views/submission.py:501 +#: judge/views/submission.py:481 #, python-format msgid "My submissions for %(problem)s" msgstr "" -#: judge/views/submission.py:502 +#: judge/views/submission.py:482 #, python-format msgid "%(user)s's submissions for %(problem)s" msgstr "" -#: judge/views/submission.py:603 +#: judge/views/submission.py:583 msgid "Must pass a contest" msgstr "" -#: judge/views/submission.py:622 +#: judge/views/submission.py:602 #, python-brace-format msgid "" "{0}'s submissions for {2} in {4}" msgstr "" -#: judge/views/submission.py:629 +#: judge/views/submission.py:609 #, python-brace-format msgid "" "{0}'s submissions for problem {2} in {3}" "" msgstr "" -#: judge/views/ticket.py:50 judge/views/ticket.py:56 +#: judge/views/ticket.py:33 judge/views/ticket.py:39 msgid "Ticket title" msgstr "" -#: judge/views/ticket.py:107 judge/views/ticket.py:110 +#: judge/views/ticket.py:40 +msgid "Issue description" +msgstr "" + +#: judge/views/ticket.py:85 judge/views/ticket.py:88 #, python-format msgid "New ticket for %s" msgstr "" -#: judge/views/ticket.py:170 +#: judge/views/ticket.py:142 #, python-format msgid "%(title)s - Ticket %(id)d" msgstr "" -#: judge/views/ticket.py:279 +#: judge/views/ticket.py:251 #, python-format msgid "Tickets - Page %(number)d of %(total)d" msgstr "" -#: judge/views/ticket.py:328 +#: judge/views/ticket.py:300 #, python-format msgid "New Ticket: %s" msgstr "" -#: judge/views/ticket.py:329 +#: judge/views/ticket.py:301 #, python-format msgid "#%(id)d, assigned to: %(users)s" msgstr "" -#: judge/views/ticket.py:331 +#: judge/views/ticket.py:303 msgid ", " msgstr "" -#: judge/views/ticket.py:331 +#: judge/views/ticket.py:303 msgid "no one" msgstr "" -#: judge/views/ticket.py:351 +#: judge/views/ticket.py:323 #, python-format msgid "New Ticket Message For: %s" msgstr "" @@ -2988,50 +2873,41 @@ msgstr "" msgid "Perform Two Factor Authentication" msgstr "" -#: judge/views/user.py:74 +#: judge/views/user.py:68 msgid "No such user" msgstr "" -#: judge/views/user.py:74 +#: judge/views/user.py:68 #, python-format msgid "No user handle \"%s\"." msgstr "" -#: judge/views/user.py:78 +#: judge/views/user.py:72 msgid "My account" msgstr "" -#: judge/views/user.py:79 +#: judge/views/user.py:73 #, python-format msgid "User %s" msgstr "" -#: judge/views/user.py:148 -msgid "M j, Y" -msgstr "" - -#: judge/views/user.py:171 +#: judge/views/user.py:136 msgid "M j, Y, G:i" msgstr "" -#: judge/views/user.py:290 +#: judge/views/user.py:221 msgid "Updated on site" msgstr "" -#: judge/views/user.py:323 templates/admin/auth/user/change_form.html:14 -#: templates/admin/auth/user/change_form.html:17 templates/base.html:238 -#: templates/user/user-tabs.html:10 +#: judge/views/user.py:254 templates/admin/auth/user/change_form.html:14 +#: templates/admin/auth/user/change_form.html:17 templates/base.html:224 msgid "Edit profile" msgstr "" -#: judge/views/user.py:332 templates/user/user-list-tabs.html:4 +#: judge/views/user.py:263 msgid "Leaderboard" msgstr "" -#: judge/views/user.py:407 -msgid "Import Users" -msgstr "" - #: judge/views/widgets.py:48 judge/views/widgets.py:58 #, python-format msgid "Invalid upstream data: %s" @@ -3069,7 +2945,7 @@ msgid "View Submissions" msgstr "" #: templates/admin/judge/problem/change_form.html:17 -#: templates/user/user-base.html:112 +#: templates/user/user-base.html:61 msgid "View submissions" msgstr "" @@ -3084,145 +2960,90 @@ msgstr "" msgid "Rejudge" msgstr "" -#: templates/base.html:230 -#, python-format -msgid "Hello, %(username)s." -msgstr "" - -#: templates/base.html:236 templates/comments/list.html:89 -#: templates/contest/contest-list-tabs.html:24 -#: templates/contest/ranking-table.html:53 -#: templates/problem/problem-list-tabs.html:6 +#: templates/base.html:222 templates/comments/list.html:89 +#: templates/contest/ranking-table.html:39 #: templates/submission/info-base.html:12 -#: templates/submission/submission-list-tabs.html:15 msgid "Admin" msgstr "" -#: templates/base.html:245 +#: templates/base.html:231 msgid "Log out" msgstr "" -#: templates/base.html:254 +#: templates/base.html:240 #: templates/registration/password_reset_complete.html:4 msgid "Log in" msgstr "" -#: templates/base.html:255 templates/registration/registration_form.html:177 +#: templates/base.html:241 templates/registration/registration_form.html:177 msgid "or" msgstr "" -#: templates/base.html:256 +#: templates/base.html:242 msgid "Sign up" msgstr "" -#: templates/base.html:271 +#: templates/base.html:254 msgid "spectating" msgstr "" -#: templates/base.html:284 +#: templates/base.html:267 msgid "This site works best with JavaScript enabled." msgstr "" -#: templates/blog/blog.html:13 templates/comments/list.html:68 -#: templates/comments/list.html:83 templates/contest/contest-tabs.html:23 -#: templates/contest/tag-title.html:9 templates/flatpages/admin_link.html:3 -#: templates/license.html:10 templates/problem/editorial.html:14 +#: templates/blog/content.html:13 templates/comments/list.html:68 +#: templates/comments/list.html:83 templates/contest/tag-title.html:9 +#: templates/flatpages/admin_link.html:3 templates/license.html:10 +#: templates/problem/editorial.html:14 msgid "Edit" msgstr "" -#: templates/blog/blog.html:26 -#, python-format -msgid "" -"\n" -" posted on %(time)s\n" -" " -msgstr "" - -#: templates/blog/content.html:10 -#, python-brace-format -msgid "posted on {time}" -msgstr "" - -#: templates/blog/dashboard.html:21 -#, python-format -msgid "" -"\n" -" on %(time)s\n" -" " -msgstr "" - -#: templates/blog/list.html:93 +#: templates/blog/list.html:85 msgid "Blog" msgstr "" -#: templates/blog/list.html:95 +#: templates/blog/list.html:87 msgid "Events" msgstr "" -#: templates/blog/list.html:100 +#: templates/blog/list.html:92 msgid "News" msgstr "" -#: templates/blog/list.html:115 templates/problem/list.html:347 -#: templates/problem/problem.html:361 +#: templates/blog/list.html:130 templates/problem/problem.html:310 msgid "Clarifications" msgstr "" -#: templates/blog/list.html:121 -msgid "Add" -msgstr "" - -#: templates/blog/list.html:140 templates/problem/list.html:369 -#: templates/problem/problem.html:372 +#: templates/blog/list.html:146 templates/problem/problem.html:321 msgid "No clarifications have been made at this time." msgstr "" -#: templates/blog/list.html:148 +#: templates/blog/list.html:154 msgid "Ongoing contests" msgstr "" -#: templates/blog/list.html:166 +#: templates/blog/list.html:172 msgid "Upcoming contests" msgstr "" -#: templates/blog/list.html:184 -msgid "My open tickets" -msgstr "" - -#: templates/blog/list.html:206 -msgid "New tickets" -msgstr "" - -#: templates/blog/list.html:227 -msgid "New problems" -msgstr "" - -#: templates/blog/list.html:244 +#: templates/blog/list.html:189 msgid "Comment stream" msgstr "" -#: templates/chat/chat.html:305 -msgid "Chat" +#: templates/blog/list.html:208 +msgid "New problems" msgstr "" -#: templates/chat/chat.html:307 templates/chat/chat.html:314 -msgid "Online Users" +#: templates/blog/list.html:225 +msgid "My open tickets" msgstr "" -#: templates/chat/chat.html:315 -msgid "Refresh" +#: templates/blog/list.html:246 +msgid "New tickets" msgstr "" -#: templates/chat/chat.html:333 -msgid "Emoji" -msgstr "" - -#: templates/chat/chat.html:334 -msgid "Enter your message" -msgstr "" - -#: templates/chat/message.html:20 -msgid "Delete" +#: templates/chat/chat.html:167 +msgid "Your message" msgstr "" #: templates/comments/list.html:2 @@ -3233,21 +3054,11 @@ msgstr "" msgid "Please login to vote" msgstr "" -#: templates/comments/list.html:40 -#, python-brace-format -msgid "commented on {time}" -msgstr "" - -#: templates/comments/list.html:49 -#, python-format -msgid "edit %(edits)s" -msgstr "" - -#: templates/comments/list.html:51 templates/comments/media-js.html:92 +#: templates/comments/list.html:51 templates/comments/media-js.html:77 msgid "edited" msgstr "" -#: templates/comments/list.html:60 templates/notification/list.html:14 +#: templates/comments/list.html:60 msgid "Link" msgstr "" @@ -3255,52 +3066,36 @@ msgstr "" msgid "Reply" msgstr "" -#: templates/comments/list.html:86 templates/contest/list.html:91 -#: templates/contest/list.html:95 templates/contest/list.html:280 +#: templates/comments/list.html:86 msgid "Hide" msgstr "" -#: templates/comments/list.html:101 -#, python-format -msgid "" -"\n" -" This comment is hidden due " -"to too much negative feedback.\n" -" Click here to view it.\n" -" " -msgstr "" - -#: templates/comments/list.html:121 +#: templates/comments/list.html:120 msgid "There are no comments at the moment." msgstr "" -#: templates/comments/list.html:127 +#: templates/comments/list.html:126 msgid "New comment" msgstr "" -#: templates/comments/list.html:141 +#: templates/comments/list.html:140 msgid "Invalid comment body." msgstr "" -#: templates/comments/list.html:149 +#: templates/comments/list.html:148 msgid "Post!" msgstr "" -#: templates/comments/list.html:157 +#: templates/comments/list.html:156 msgid "Comments are disabled on this page." msgstr "" -#: templates/comments/media-js.html:38 -msgid "Replying to comment" -msgstr "" - -#: templates/comments/media-js.html:87 +#: templates/comments/media-js.html:72 #, python-brace-format msgid "edit {edits}" msgstr "" -#: templates/comments/media-js.html:90 +#: templates/comments/media-js.html:75 msgid "original" msgstr "" @@ -3344,11 +3139,6 @@ msgstr "" msgid "Saturday" msgstr "" -#: templates/contest/clarification.html:52 templates/organization/new.html:10 -#: templates/ticket/new.html:38 -msgid "Create" -msgstr "" - #: templates/contest/clone.html:37 msgid "Enter a new key for the cloned contest:" msgstr "" @@ -3369,171 +3159,97 @@ msgstr "" msgid "Next" msgstr "" -#: templates/contest/contest-list-tabs.html:21 -#: templates/problem/problem-list-tabs.html:5 -msgid "List" -msgstr "" - -#: templates/contest/contest-list-tabs.html:22 -msgid "Calendar" -msgstr "" - -#: templates/contest/contest-tabs.html:4 templates/organization/home.html:105 -msgid "Info" -msgstr "" - -#: templates/contest/contest-tabs.html:6 templates/stats/base.html:9 -#: templates/submission/list.html:339 -msgid "Statistics" -msgstr "" - -#: templates/contest/contest-tabs.html:11 -msgid "Rankings" -msgstr "" - -#: templates/contest/contest-tabs.html:16 -msgid "Hidden Rankings" -msgstr "" - -#: templates/contest/contest-tabs.html:21 -msgid "MOSS" -msgstr "" - -#: templates/contest/contest-tabs.html:26 -msgid "Clone" -msgstr "" - -#: templates/contest/contest-tabs.html:38 -#: templates/contest/contest-tabs.html:58 +#: templates/contest/contest-tabs.html:37 msgid "Leave contest" msgstr "" -#: templates/contest/contest-tabs.html:45 templates/contest/list.html:388 +#: templates/contest/contest-tabs.html:44 templates/contest/list.html:293 msgid "Virtual join" msgstr "" -#: templates/contest/contest-tabs.html:56 -msgid "Stop spectating" -msgstr "" - -#: templates/contest/contest-tabs.html:65 +#: templates/contest/contest-tabs.html:64 msgid "Spectate contest" msgstr "" -#: templates/contest/contest-tabs.html:72 +#: templates/contest/contest-tabs.html:70 +#: templates/contest/contest-tabs.html:76 msgid "Join contest" msgstr "" -#: templates/contest/contest-tabs.html:81 +#: templates/contest/contest-tabs.html:85 msgid "Login to participate" msgstr "" -#: templates/contest/contest.html:37 -msgid "Participating virtually." -msgstr "" - -#: templates/contest/contest.html:43 -msgid "Contest is over." -msgstr "" - #: templates/contest/contest.html:59 templates/contest/contest.html:63 msgid "F j, Y, G:i T" msgstr "" -#: templates/contest/contest.html:59 -#, python-format -msgid "" -"%(time_limit)s window between %(start_time)s and " -"%(end_time)s" -msgstr "" - -#: templates/contest/contest.html:63 -#, python-format -msgid "%(length)s long starting on %(start_time)s" -msgstr "" - #: templates/contest/contest.html:85 msgid "AC Rate" msgstr "" -#: templates/contest/contest.html:86 templates/contest/list.html:237 -#: templates/contest/list.html:289 templates/contest/list.html:366 -#: templates/problem/list.html:223 templates/problem/list.html:254 +#: templates/contest/contest.html:86 templates/contest/list.html:153 +#: templates/contest/list.html:195 templates/contest/list.html:271 +#: templates/problem/list.html:212 templates/problem/list.html:238 msgid "Users" msgstr "" -#: templates/contest/contest.html:111 templates/problem/list.html:330 +#: templates/contest/contest.html:111 msgid "Editorial" msgstr "" -#: templates/contest/list.html:83 templates/contest/media-js.html:9 +#: templates/contest/list.html:31 templates/contest/media-js.html:9 msgid "Are you sure you want to join?" msgstr "" -#: templates/contest/list.html:84 +#: templates/contest/list.html:32 msgid "" "Joining a contest for the first time starts your timer, after which it " "becomes unstoppable." msgstr "" -#: templates/contest/list.html:92 templates/contest/list.html:278 -msgid "Show" -msgstr "" - -#: templates/contest/list.html:102 templates/problem/list.html:68 -msgid "Organizations..." -msgstr "" - -#: templates/contest/list.html:135 +#: templates/contest/list.html:65 msgid "hidden" msgstr "" -#: templates/contest/list.html:140 +#: templates/contest/list.html:70 msgid "private" msgstr "" -#: templates/contest/list.html:154 +#: templates/contest/list.html:84 msgid "rated" msgstr "" -#: templates/contest/list.html:202 +#: templates/contest/list.html:132 msgid "Spectate" msgstr "" -#: templates/contest/list.html:208 +#: templates/contest/list.html:138 msgid "Join" msgstr "" -#: templates/contest/list.html:220 -msgid "Search contests..." -msgstr "" - -#: templates/contest/list.html:229 -msgid "Search" -msgstr "" - -#: templates/contest/list.html:232 +#: templates/contest/list.html:148 msgid "Active Contests" msgstr "" -#: templates/contest/list.html:236 templates/contest/list.html:288 -#: templates/contest/list.html:327 templates/contest/list.html:365 +#: templates/contest/list.html:152 templates/contest/list.html:194 +#: templates/contest/list.html:232 templates/contest/list.html:270 msgid "Contest" msgstr "" -#: templates/contest/list.html:275 +#: templates/contest/list.html:190 msgid "Ongoing Contests" msgstr "" -#: templates/contest/list.html:322 +#: templates/contest/list.html:227 msgid "Upcoming Contests" msgstr "" -#: templates/contest/list.html:350 +#: templates/contest/list.html:255 msgid "There are no scheduled contests at this time." msgstr "" -#: templates/contest/list.html:356 +#: templates/contest/list.html:261 msgid "Past Contests" msgstr "" @@ -3584,71 +3300,47 @@ msgstr "" msgid "Only the following organizations may access this contest:" msgstr "" -#: templates/contest/ranking-table.html:9 templates/problem/search-form.html:35 +#: templates/contest/ranking-table.html:7 msgid "Organization" msgstr "" -#: templates/contest/ranking-table.html:10 templates/user/users-table.html:13 -msgid "Full Name" -msgstr "" - -#: templates/contest/ranking-table.html:44 +#: templates/contest/ranking-table.html:30 msgid "Un-Disqualify" msgstr "" -#: templates/contest/ranking-table.html:47 +#: templates/contest/ranking-table.html:33 msgid "Disqualify" msgstr "" -#: templates/contest/ranking.html:187 +#: templates/contest/ranking.html:173 msgid "Are you sure you want to disqualify this participation?" msgstr "" -#: templates/contest/ranking.html:192 +#: templates/contest/ranking.html:178 msgid "Are you sure you want to un-disqualify this participation?" msgstr "" -#: templates/contest/ranking.html:463 +#: templates/contest/ranking.html:252 msgid "View user participation" msgstr "" -#: templates/contest/ranking.html:467 +#: templates/contest/ranking.html:256 msgid "Show organizations" msgstr "" -#: templates/contest/ranking.html:471 -msgid "Show full name" -msgstr "" - -#: templates/contest/ranking.html:474 -msgid "Show friends only" -msgstr "" - -#: templates/contest/ranking.html:477 -msgid "Total score only" -msgstr "" - -#: templates/contest/ranking.html:479 -msgid "Show virtual participation" -msgstr "" - -#: templates/contest/stats.html:51 +#: templates/contest/stats.html:38 msgid "Problem Status Distribution" msgstr "" -#: templates/contest/stats.html:56 +#: templates/contest/stats.html:43 msgid "Problem AC Rate" msgstr "" -#: templates/contest/stats.html:62 -msgid "Problem Point Distribution" -msgstr "" - -#: templates/contest/stats.html:76 templates/stats/language.html:16 +#: templates/contest/stats.html:48 templates/stats/language.html:16 msgid "Submissions by Language" msgstr "" -#: templates/contest/stats.html:82 templates/stats/language.html:26 +#: templates/contest/stats.html:54 templates/stats/language.html:26 msgid "Language AC Rate" msgstr "" @@ -3657,7 +3349,6 @@ msgid "Source:" msgstr "" #: templates/newsletter/common.html:6 -#: templates/newsletter/newsletter_list.html:15 #: templates/newsletter/subscription_unsubscribe_activated.html:3 #: templates/newsletter/subscription_unsubscribe_activated.html:6 #: templates/newsletter/subscription_update_activated.html:3 @@ -3665,23 +3356,6 @@ msgstr "" msgid "Newsletter" msgstr "" -#: templates/newsletter/newsletter_list.html:2 -#: templates/newsletter/newsletter_list.html:3 -msgid "Newsletter list" -msgstr "" - -#: templates/newsletter/newsletter_list.html:6 -msgid "Subscribe to get the latest emails about upcoming contests and events." -msgstr "" - -#: templates/newsletter/newsletter_list.html:16 -msgid "Subscribe" -msgstr "" - -#: templates/newsletter/newsletter_list.html:30 -msgid "Update subscriptions" -msgstr "" - #: templates/newsletter/subscription_unsubscribe_activated.html:3 #: templates/newsletter/subscription_unsubscribe_activated.html:6 #: templates/newsletter/subscription_update_activated.html:3 @@ -3743,97 +3417,64 @@ msgid "" "follow in order to update your subscription." msgstr "" -#: templates/notification/list.html:7 -msgid "You have no notifications" -msgstr "" - -#: templates/notification/list.html:13 -msgid "Activity" -msgstr "" - #: templates/organization/edit.html:46 #: templates/organization/requests/pending.html:34 #: templates/ticket/edit-notes.html:4 msgid "Update" msgstr "" -#: templates/organization/home.html:41 +#: templates/organization/home.html:7 msgid "Are you sure you want to leave this organization?" msgstr "" -#: templates/organization/home.html:43 +#: templates/organization/home.html:9 msgid "You will have to rejoin to show up on the organization leaderboard." msgstr "" -#: templates/organization/home.html:45 +#: templates/organization/home.html:11 msgid "You will have to request membership in order to join again." msgstr "" -#: templates/organization/home.html:88 -msgid "Join organization" -msgstr "" - -#: templates/organization/home.html:92 -msgid "Request membership" -msgstr "" - -#: templates/organization/home.html:122 -msgid "Organization news" -msgstr "" - -#: templates/organization/home.html:128 -msgid "There is no news at this time." -msgstr "" - -#: templates/organization/home.html:137 -msgid "Controls" -msgstr "" - -#: templates/organization/home.html:142 -msgid "Edit organization" -msgstr "" - -#: templates/organization/home.html:148 -msgid "View requests" -msgstr "" - -#: templates/organization/home.html:161 -msgid "Admin organization" -msgstr "" - -#: templates/organization/home.html:167 -msgid "View members" -msgstr "" - -#: templates/organization/home.html:174 +#: templates/organization/home.html:24 msgid "Leave organization" msgstr "" -#: templates/organization/home.html:183 -msgid "New private contests" +#: templates/organization/home.html:29 +msgid "Join organization" msgstr "" -#: templates/organization/home.html:193 templates/organization/home.html:208 -msgid "View all" +#: templates/organization/home.html:33 +msgid "Request membership" msgstr "" -#: templates/organization/home.html:199 -msgid "New private problems" +#: templates/organization/home.html:39 +msgid "Edit organization" msgstr "" -#: templates/organization/list.html:40 -msgid "Show my organizations only" +#: templates/organization/home.html:43 +msgid "View requests" msgstr "" -#: templates/organization/list.html:47 templates/status/language-list.html:34 -#: templates/user/import/table_csv.html:6 +#: templates/organization/home.html:50 +msgid "Admin organization" +msgstr "" + +#: templates/organization/home.html:55 +msgid "View members" +msgstr "" + +#: templates/organization/list.html:23 templates/status/language-list.html:34 msgid "Name" msgstr "" -#: templates/organization/list.html:48 +#: templates/organization/list.html:24 msgid "Members" msgstr "" +#: templates/organization/new.html:10 templates/ticket/new.html:38 +msgid "Create" +msgstr "" + #: templates/organization/requests/detail.html:13 msgid "User:" msgstr "" @@ -3866,7 +3507,7 @@ msgid "There are no requests to approve." msgstr "" #: templates/organization/requests/pending.html:17 -#: templates/problem/data.html:432 +#: templates/problem/data.html:452 msgid "Delete?" msgstr "" @@ -3902,35 +3543,35 @@ msgstr "" msgid "Enter a new code for the cloned problem:" msgstr "" -#: templates/problem/data.html:119 +#: templates/problem/data.html:108 msgid "Instruction" msgstr "" -#: templates/problem/data.html:390 +#: templates/problem/data.html:410 msgid "View YAML" msgstr "" -#: templates/problem/data.html:421 templates/problem/data.html:472 +#: templates/problem/data.html:441 templates/problem/data.html:491 msgid "Apply!" msgstr "" -#: templates/problem/data.html:426 +#: templates/problem/data.html:446 msgid "Type" msgstr "" -#: templates/problem/data.html:427 +#: templates/problem/data.html:447 msgid "Input file" msgstr "" -#: templates/problem/data.html:428 +#: templates/problem/data.html:448 msgid "Output file" msgstr "" -#: templates/problem/data.html:430 +#: templates/problem/data.html:450 msgid "Pretest?" msgstr "" -#: templates/problem/data.html:473 +#: templates/problem/data.html:492 msgid "Add new case" msgstr "" @@ -3942,32 +3583,28 @@ msgid "" "problem yourself is a bannable offence." msgstr "" -#: templates/problem/list.html:66 +#: templates/problem/list.html:62 msgid "Filter by type..." msgstr "" -#: templates/problem/list.html:193 +#: templates/problem/list.html:185 msgid "Hot problems" msgstr "" -#: templates/problem/list.html:218 templates/problem/list.html:240 -#: templates/problem/search-form.html:45 templates/user/user-problems.html:57 +#: templates/problem/list.html:207 templates/problem/list.html:224 +#: templates/problem/search-form.html:30 templates/user/user-problems.html:57 msgid "Category" msgstr "" -#: templates/problem/list.html:220 templates/problem/list.html:244 +#: templates/problem/list.html:209 templates/problem/list.html:228 msgid "Types" msgstr "" -#: templates/problem/list.html:251 +#: templates/problem/list.html:235 #, python-format msgid "AC %%" msgstr "" -#: templates/problem/list.html:342 -msgid "Add clarifications" -msgstr "" - #: templates/problem/manage_submission.html:55 msgid "Leave empty to not filter by language" msgstr "" @@ -3976,215 +3613,152 @@ msgstr "" msgid "Leave empty to not filter by result" msgstr "" -#: templates/problem/manage_submission.html:80 +#: templates/problem/manage_submission.html:79 msgid "Need valid values for both start and end IDs." msgstr "" -#: templates/problem/manage_submission.html:83 +#: templates/problem/manage_submission.html:82 msgid "End ID must be after start ID." msgstr "" +#: templates/problem/manage_submission.html:90 +#, python-brace-format +msgid "" +"You are about to rejudge {count} submissions. Are you sure you want to do " +"this?" +msgstr "" + #: templates/problem/manage_submission.html:96 -#, python-brace-format msgid "" -"You are about to {action} {count} submissions. Are you sure you want to do " -"this?" +"You are about to rejudge a few submissions. Are you sure you want to do this?" msgstr "" -#: templates/problem/manage_submission.html:103 -#, python-brace-format -msgid "" -"You are about to {action} a few submissions. Are you sure you want to do " -"this?" +#: templates/problem/manage_submission.html:115 +msgid "Rejudge Submissions" msgstr "" -#: templates/problem/manage_submission.html:127 -#: templates/submission/list.html:309 -msgid "Filter submissions" -msgstr "" - -#: templates/problem/manage_submission.html:132 +#: templates/problem/manage_submission.html:120 msgid "Filter by ID:" msgstr "" -#: templates/problem/manage_submission.html:135 +#: templates/problem/manage_submission.html:123 msgid "Starting ID:" msgstr "" -#: templates/problem/manage_submission.html:139 +#: templates/problem/manage_submission.html:127 msgid "Ending ID:" msgstr "" -#: templates/problem/manage_submission.html:143 +#: templates/problem/manage_submission.html:131 msgid "This range includes both endpoints." msgstr "" -#: templates/problem/manage_submission.html:146 +#: templates/problem/manage_submission.html:134 msgid "Filter by language:" msgstr "" -#: templates/problem/manage_submission.html:154 +#: templates/problem/manage_submission.html:142 msgid "Filter by result:" msgstr "" -#: templates/problem/manage_submission.html:164 -msgid "Action" -msgstr "" - -#: templates/problem/manage_submission.html:166 +#: templates/problem/manage_submission.html:150 msgid "Rejudge selected submissions" msgstr "" -#: templates/problem/manage_submission.html:171 -msgid "Download selected submissions" +#: templates/problem/manage_submission.html:157 +msgid "Rescore Everything" msgstr "" -#: templates/problem/manage_submission.html:177 -#, python-format -msgid "Are you sure you want to rescore %(count)d submissions?" -msgstr "" - -#: templates/problem/manage_submission.html:178 +#: templates/problem/manage_submission.html:163 msgid "Rescore all submissions" msgstr "" -#: templates/problem/problem.html:132 +#: templates/problem/problem.html:91 msgid "View as PDF" msgstr "" -#: templates/problem/problem.html:141 templates/problem/problem.html:151 -#: templates/problem/problem.html:156 +#: templates/problem/problem.html:101 templates/problem/problem.html:111 +#: templates/problem/problem.html:116 msgid "Submit solution" msgstr "" -#: templates/problem/problem.html:144 -#, python-format -msgid "%(counter)s submission left" -msgid_plural "%(counter)s submissions left" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" -msgstr[3] "" -msgstr[4] "" -msgstr[5] "" - -#: templates/problem/problem.html:152 +#: templates/problem/problem.html:112 msgid "0 submissions left" msgstr "" -#: templates/problem/problem.html:164 +#: templates/problem/problem.html:124 msgid "My submissions" msgstr "" -#: templates/problem/problem.html:168 +#: templates/problem/problem.html:128 msgid "Best submissions" msgstr "" -#: templates/problem/problem.html:172 +#: templates/problem/problem.html:132 msgid "Read editorial" msgstr "" -#: templates/problem/problem.html:177 +#: templates/problem/problem.html:137 msgid "Manage tickets" msgstr "" -#: templates/problem/problem.html:181 +#: templates/problem/problem.html:141 msgid "Edit problem" msgstr "" -#: templates/problem/problem.html:183 +#: templates/problem/problem.html:143 msgid "Edit test data" msgstr "" -#: templates/problem/problem.html:188 +#: templates/problem/problem.html:148 msgid "My tickets" msgstr "" -#: templates/problem/problem.html:196 +#: templates/problem/problem.html:156 msgid "Manage submissions" msgstr "" -#: templates/problem/problem.html:202 +#: templates/problem/problem.html:162 msgid "Clone problem" msgstr "" -#: templates/problem/problem.html:209 +#: templates/problem/problem.html:169 msgid "Points:" msgstr "" -#: templates/problem/problem.html:212 templates/problem/problem.html:214 +#: templates/problem/problem.html:172 templates/problem/problem.html:174 msgid "(partial)" msgstr "" -#: templates/problem/problem.html:219 +#: templates/problem/problem.html:179 msgid "Time limit:" msgstr "" -#: templates/problem/problem.html:231 +#: templates/problem/problem.html:191 msgid "Memory limit:" msgstr "" -#: templates/problem/problem.html:250 -msgid "Author:" -msgid_plural "Authors:" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" -msgstr[3] "" -msgstr[4] "" -msgstr[5] "" - -#: templates/problem/problem.html:265 -msgid "Problem type" -msgid_plural "Problem types" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" -msgstr[3] "" -msgstr[4] "" -msgstr[5] "" - -#: templates/problem/problem.html:278 +#: templates/problem/problem.html:238 msgid "Allowed languages" msgstr "" -#: templates/problem/problem.html:286 -#, python-format -msgid "No %(lang)s judge online" -msgstr "" - -#: templates/problem/problem.html:297 -msgid "Judge:" -msgid_plural "Judges:" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" -msgstr[3] "" -msgstr[4] "" -msgstr[5] "" - -#: templates/problem/problem.html:314 +#: templates/problem/problem.html:274 msgid "none available" msgstr "" -#: templates/problem/problem.html:326 -#, python-format -msgid "This problem has %(length)s clarification(s)" -msgstr "" - -#: templates/problem/problem.html:350 +#: templates/problem/problem.html:299 msgid "Request clarification" msgstr "" -#: templates/problem/problem.html:352 +#: templates/problem/problem.html:301 msgid "Report an issue" msgstr "" -#: templates/problem/raw.html:64 +#: templates/problem/raw.html:62 msgid "Time Limit:" msgstr "" -#: templates/problem/raw.html:73 +#: templates/problem/raw.html:71 msgid "Memory Limit:" msgstr "" @@ -4208,77 +3782,39 @@ msgstr "" msgid "Show problem types" msgstr "" -#: templates/problem/search-form.html:32 -msgid "Show editorial" -msgstr "" - -#: templates/problem/search-form.html:48 templates/problem/search-form.html:50 -#: templates/submission/submission-list-tabs.html:4 +#: templates/problem/search-form.html:33 templates/problem/search-form.html:35 msgid "All" msgstr "" -#: templates/problem/search-form.html:62 +#: templates/problem/search-form.html:46 msgid "Problem types" msgstr "" -#: templates/problem/search-form.html:73 +#: templates/problem/search-form.html:57 msgid "Point range" msgstr "" -#: templates/problem/search-form.html:79 templates/submission/list.html:331 +#: templates/problem/search-form.html:63 templates/submission/list.html:331 #: templates/ticket/list.html:248 msgid "Go" msgstr "" -#: templates/problem/search-form.html:80 +#: templates/problem/search-form.html:64 msgid "Random" msgstr "" -#: templates/problem/submit.html:117 -msgid "Your source code must contain at most 65536 characters." -msgstr "" - -#: templates/problem/submit.html:204 -#, python-format -msgid "" -"Warning! Your default language, %(default_language)s, is " -"unavailable for this problem and has been deselected." -msgstr "" - -#: templates/problem/submit.html:215 -#, python-format -msgid "" -"\n" -" You have %(left)s submission left\n" -" " -msgid_plural "" -"\n" -" You have %(left)s submissions left\n" -" " -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" -msgstr[3] "" -msgstr[4] "" -msgstr[5] "" - -#: templates/problem/submit.html:224 +#: templates/problem/submit.html:212 msgid "You have 0 submissions left" msgstr "" -#: templates/problem/submit.html:258 +#: templates/problem/submit.html:250 msgid "No judge is available for this problem." msgstr "" -#: templates/problem/submit.html:262 +#: templates/problem/submit.html:252 msgid "Submit!" msgstr "" -#: templates/registration/activate.html:3 -#, python-format -msgid "%(key)s is an invalid activation key." -msgstr "" - #: templates/registration/activation_complete.html:3 msgid "Your account has been successfully activated." msgstr "" @@ -4336,13 +3872,6 @@ msgid "" "you registered with, and check your spam folder." msgstr "" -#: templates/registration/password_reset_email.txt:1 -#, python-format -msgid "" -"You're receiving this email because you requested a password reset for your " -"user account at %(site_name)s." -msgstr "" - #: templates/registration/password_reset_email.txt:3 msgid "Please go to the following page and choose a new password:" msgstr "" @@ -4355,16 +3884,6 @@ msgstr "" msgid "Thanks for using our site!" msgstr "" -#: templates/registration/password_reset_email.txt:11 -#, python-format -msgid "The %(site_name)s team" -msgstr "" - -#: templates/registration/password_reset_subject.txt:1 -#, python-format -msgid "Password reset on %(site_name)s" -msgstr "" - #: templates/registration/profile_creation.html:36 #: templates/registration/username_select.html:7 msgid "Continue >" @@ -4401,20 +3920,19 @@ msgstr "" msgid "Affiliated organizations" msgstr "" -#: templates/registration/registration_form.html:195 -#: templates/user/edit-profile.html:128 +#: templates/registration/registration_form.html:192 msgid "Notify me about upcoming contests" msgstr "" -#: templates/registration/registration_form.html:209 +#: templates/registration/registration_form.html:206 msgid "By registering, you agree to our" msgstr "" -#: templates/registration/registration_form.html:210 +#: templates/registration/registration_form.html:207 msgid "Terms & Conditions" msgstr "" -#: templates/registration/registration_form.html:213 +#: templates/registration/registration_form.html:210 msgid "Register!" msgstr "" @@ -4424,11 +3942,6 @@ msgstr "" msgid "Enter the 6-digit code generated by your app:" msgstr "" -#: templates/registration/totp_auth.html:41 -#, python-format -msgid "If you lost your authentication device, please contact us at %(email)s." -msgstr "" - #: templates/registration/totp_disable.html:38 msgid "" "To protect your account, you must first authenticate before you can disable " @@ -4447,6 +3960,10 @@ msgstr "" msgid "Or enter this code manually:" msgstr "" +#: templates/stats/base.html:9 templates/submission/list.html:339 +msgid "Statistics" +msgstr "" + #: templates/stats/language.html:11 msgid "Submission Statistics" msgstr "" @@ -4472,7 +3989,6 @@ msgid "Ping" msgstr "" #: templates/status/judge-status-table.html:8 -#: templates/user/import/index.html:104 msgid "Load" msgstr "" @@ -4488,7 +4004,6 @@ msgid "There are no judges available at this time." msgstr "" #: templates/status/language-list.html:33 templates/ticket/list.html:261 -#: templates/user/import/table_csv.html:3 msgid "ID" msgstr "" @@ -4496,22 +4011,6 @@ msgstr "" msgid "Runtime Info" msgstr "" -#: templates/status/status-tabs.html:4 -msgid "Judges" -msgstr "" - -#: templates/status/status-tabs.html:6 -msgid "Version Matrix" -msgstr "" - -#: templates/submission/internal-error-message.html:3 -#, python-format -msgid "" -"An internal error occurred while grading, and the %(SITE_NAME)s " -"administrators have been notified.
In the meantime, try resubmitting in " -"a few seconds." -msgstr "" - #: templates/submission/internal-error-message.html:8 msgid "An internal error occurred while grading." msgstr "" @@ -4528,6 +4027,10 @@ msgstr "" msgid "Filter by language..." msgstr "" +#: templates/submission/list.html:309 +msgid "Filter submissions" +msgstr "" + #: templates/submission/list.html:345 msgid "Total:" msgstr "" @@ -4584,64 +4087,63 @@ msgstr "" msgid "Execution Results" msgstr "" -#: templates/submission/status-testcases.html:34 -msgid "Overall: " -msgstr "" - -#: templates/submission/status-testcases.html:48 -msgid "Point: " -msgstr "" - -#: templates/submission/status-testcases.html:53 -msgid "Time: " -msgstr "" - -#: templates/submission/status-testcases.html:62 -msgid "Memory: " -msgstr "" - -#: templates/submission/status-testcases.html:73 +#: templates/submission/status-testcases.html:31 msgid "Batch " msgstr "" -#: templates/submission/status-testcases.html:84 -#: templates/submission/status-testcases.html:113 -msgid "Point" +#: templates/submission/status-testcases.html:43 +msgid "Overall: " msgstr "" -#: templates/submission/status-testcases.html:99 +#: templates/submission/status-testcases.html:57 +msgid "Point: " +msgstr "" + +#: templates/submission/status-testcases.html:62 +msgid "Time: " +msgstr "" + +#: templates/submission/status-testcases.html:71 +msgid "Memory: " +msgstr "" + +#: templates/submission/status-testcases.html:84 msgid "Case" msgstr "" -#: templates/submission/status-testcases.html:101 +#: templates/submission/status-testcases.html:86 msgid "Pretest" msgstr "" -#: templates/submission/status-testcases.html:103 +#: templates/submission/status-testcases.html:88 msgid "Test case" msgstr "" -#: templates/submission/status-testcases.html:141 +#: templates/submission/status-testcases.html:99 +msgid "Point" +msgstr "" + +#: templates/submission/status-testcases.html:121 msgid "Input:" msgstr "" -#: templates/submission/status-testcases.html:145 +#: templates/submission/status-testcases.html:125 msgid "Output:" msgstr "" -#: templates/submission/status-testcases.html:149 +#: templates/submission/status-testcases.html:129 msgid "Answer:" msgstr "" -#: templates/submission/status-testcases.html:154 +#: templates/submission/status-testcases.html:134 msgid "Judge feedback:" msgstr "" -#: templates/submission/status-testcases.html:175 +#: templates/submission/status-testcases.html:157 msgid "Passing pretests does not guarantee a full score on system tests." msgstr "" -#: templates/submission/status-testcases.html:178 +#: templates/submission/status-testcases.html:160 msgid "Submission aborted!" msgstr "" @@ -4653,24 +4155,11 @@ msgstr "" msgid "Abort" msgstr "" -#: templates/submission/submission-list-tabs.html:6 -msgid "Mine" -msgstr "" - -#: templates/submission/submission-list-tabs.html:9 -msgid "Best" -msgstr "" - -#: templates/submission/submission-list-tabs.html:12 -#, python-format -msgid "%(user)s's" -msgstr "" - -#: templates/ticket/list.html:135 templates/ticket/ticket.html:273 +#: templates/ticket/list.html:135 templates/ticket/ticket.html:257 msgid "Reopened: " msgstr "" -#: templates/ticket/list.html:138 templates/ticket/ticket.html:274 +#: templates/ticket/list.html:138 templates/ticket/ticket.html:258 msgid "Closed: " msgstr "" @@ -4694,7 +4183,7 @@ msgstr "" msgid "Title" msgstr "" -#: templates/ticket/list.html:264 templates/ticket/ticket.html:369 +#: templates/ticket/list.html:264 templates/ticket/ticket.html:328 msgid "Assignees" msgstr "" @@ -4709,36 +4198,32 @@ msgid "" "a problem, ask in the comments instead." msgstr "" -#: templates/ticket/ticket.html:355 -msgid "Post" -msgstr "" - -#: templates/ticket/ticket.html:363 +#: templates/ticket/ticket.html:322 msgid "Associated object" msgstr "" -#: templates/ticket/ticket.html:374 +#: templates/ticket/ticket.html:333 msgid "No one is assigned." msgstr "" -#: templates/ticket/ticket.html:380 +#: templates/ticket/ticket.html:339 msgid "Close ticket" msgstr "" -#: templates/ticket/ticket.html:382 +#: templates/ticket/ticket.html:341 msgid "Reopen ticket" msgstr "" -#: templates/ticket/ticket.html:386 +#: templates/ticket/ticket.html:345 msgid "Assignee notes" msgstr "" -#: templates/ticket/ticket.html:393 templates/widgets/select_all.html:4 +#: templates/ticket/ticket.html:352 templates/widgets/select_all.html:4 msgid "Nothing here." msgstr "" -#: templates/user/base-users-table.html:3 -msgid "Rank" +#: templates/ticket/ticket.html:385 +msgid "Post" msgstr "" #: templates/user/base-users.html:14 templates/user/base-users.html:69 @@ -4785,172 +4270,50 @@ msgstr "" msgid "Update profile" msgstr "" -#: templates/user/import/index.html:31 -msgid "Upload CSV only" -msgstr "" - -#: templates/user/import/index.html:100 -msgid "User File" -msgstr "" - -#: templates/user/import/index.html:102 -msgid "Sample" -msgstr "" - -#: templates/user/import/index.html:105 templates/user/user-list-tabs.html:8 -msgid "Import" -msgstr "" - -#: templates/user/import/table_csv.html:7 -msgid "School" -msgstr "" - -#: templates/user/pp-row.html:22 -#, python-format -msgid "" -"\n" -" weighted %(weight)s%%\n" -" " -msgstr "" - -#: templates/user/pp-row.html:27 -#, python-format -msgid "%(pp).1fpp" -msgstr "" - -#: templates/user/pp-row.html:29 -#, python-format -msgid "%(pp).0fpp" -msgstr "" - -#: templates/user/user-about.html:23 -#, python-format -msgid "%(counter)s problem solved" -msgid_plural "%(counter)s problems solved" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" -msgstr[3] "" -msgstr[4] "" -msgstr[5] "" - -#: templates/user/user-about.html:35 -msgid "Total points" -msgstr "" - -#: templates/user/user-about.html:45 -msgid "Rank by rating" -msgstr "" - -#: templates/user/user-about.html:52 -msgid "Rank by points" -msgstr "" - -#: templates/user/user-about.html:64 +#: templates/user/user-about.html:14 msgid "From" msgstr "" -#: templates/user/user-about.html:75 +#: templates/user/user-about.html:25 msgid "Admin Notes" msgstr "" -#: templates/user/user-about.html:90 +#: templates/user/user-about.html:40 msgid "You have not shared any information." msgstr "" -#: templates/user/user-about.html:92 +#: templates/user/user-about.html:42 msgid "This user has not shared any information." msgstr "" -#: templates/user/user-about.html:101 -msgid "Awards" +#: templates/user/user-base.html:50 +msgid "Rank by points:" msgstr "" -#: templates/user/user-about.html:112 -#, python-format -msgid "%(label)s (%(date)s)" +#: templates/user/user-base.html:53 +msgid "Total points:" msgstr "" -#: templates/user/user-about.html:130 -msgid "Mon" +#: templates/user/user-base.html:68 +msgid "Rank by rating:" msgstr "" -#: templates/user/user-about.html:135 -msgid "Tues" +#: templates/user/user-base.html:70 +msgid "Rating:" msgstr "" -#: templates/user/user-about.html:140 -msgid "Wed" -msgstr "" - -#: templates/user/user-about.html:145 -msgid "Thurs" -msgstr "" - -#: templates/user/user-about.html:150 -msgid "Fri" -msgstr "" - -#: templates/user/user-about.html:155 -msgid "Sat" -msgstr "" - -#: templates/user/user-about.html:160 -msgid "Sun" -msgstr "" - -#: templates/user/user-about.html:169 -msgid "Less" -msgstr "" - -#: templates/user/user-about.html:175 -msgid "More" -msgstr "" - -#: templates/user/user-about.html:184 -msgid "Rating History" -msgstr "" - -#: templates/user/user-about.html:255 -msgid "past year" -msgstr "" - -#: templates/user/user-about.html:272 -msgid "total submission(s)" -msgstr "" - -#: templates/user/user-about.html:276 -msgid "submissions in the last year" -msgstr "" - -#: templates/user/user-base.html:101 -msgid "Unfollow" -msgstr "" - -#: templates/user/user-base.html:104 -msgid "Follow" -msgstr "" - -#: templates/user/user-base.html:120 -msgid "Contests written" -msgstr "" - -#: templates/user/user-base.html:124 +#: templates/user/user-base.html:71 msgid "Volatility:" msgstr "" -#: templates/user/user-base.html:128 +#: templates/user/user-base.html:72 msgid "Min. rating:" msgstr "" -#: templates/user/user-base.html:132 +#: templates/user/user-base.html:73 msgid "Max rating:" msgstr "" -#: templates/user/user-list-tabs.html:5 -msgid "Friends" -msgstr "" - #: templates/user/user-problems.html:35 msgid "Points Breakdown" msgstr "" @@ -4971,32 +4334,10 @@ msgstr "" msgid "Hide problems I've solved" msgstr "" -#: templates/user/user-problems.html:93 -#, python-format -msgid "%(points).1f points" -msgstr "" - #: templates/user/user-problems.html:99 msgid "Score" msgstr "" -#: templates/user/user-problems.html:110 -#, python-format -msgid "%(points)s / %(total)s" -msgstr "" - -#: templates/user/user-tabs.html:7 -msgid "Impersonate" -msgstr "" - -#: templates/user/user-tabs.html:13 -msgid "Admin User" -msgstr "" - -#: templates/user/user-tabs.html:16 -msgid "Admin Profile" -msgstr "" - #: templates/widgets/select_all.html:8 msgid "Check all" msgstr "" diff --git a/locale/ar/LC_MESSAGES/djangojs.po b/locale/ar/LC_MESSAGES/djangojs.po index 82d2d43..e2a3d5f 100644 --- a/locale/ar/LC_MESSAGES/djangojs.po +++ b/locale/ar/LC_MESSAGES/djangojs.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: dmoj\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-07-20 23:30+0700\n" +"POT-Creation-Date: 2019-10-01 23:12+0000\n" "PO-Revision-Date: 2019-11-11 22:05\n" "Last-Translator: Icyene\n" "Language-Team: Arabic, Saudi Arabia\n" @@ -10,8 +10,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=6; plural=(n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 " -"&& n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5);\n" +"Plural-Forms: nplurals=6; plural=(n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: dmoj\n" "X-Crowdin-Language: ar-SA\n" @@ -32,3 +31,4 @@ msgstr[5] "" msgctxt "time format without day" msgid "%h:%m:%s" msgstr "" + diff --git a/locale/de/LC_MESSAGES/django.po b/locale/de/LC_MESSAGES/django.po index f1ea49d..0348415 100644 --- a/locale/de/LC_MESSAGES/django.po +++ b/locale/de/LC_MESSAGES/django.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: dmoj\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-10-25 05:59+0700\n" +"POT-Creation-Date: 2020-04-10 01:26-0500\n" "PO-Revision-Date: 2019-11-11 22:05\n" "Last-Translator: Icyene\n" "Language-Team: German\n" @@ -16,93 +16,93 @@ msgstr "" "X-Crowdin-Language: de\n" "X-Crowdin-File: django.po\n" -#: chat_box/models.py:16 judge/admin/interface.py:110 -#: judge/models/contest.py:403 judge/models/contest.py:528 -#: judge/models/profile.py:211 +#: chat_box/models.py:15 judge/admin/interface.py:107 +#: judge/models/contest.py:257 judge/models/contest.py:381 +#: judge/models/profile.py:191 msgid "user" msgstr "" -#: chat_box/models.py:17 judge/models/comment.py:43 judge/models/comment.py:191 +#: chat_box/models.py:16 judge/models/comment.py:42 msgid "posted time" msgstr "" -#: chat_box/models.py:18 judge/models/comment.py:47 +#: chat_box/models.py:17 judge/models/comment.py:46 msgid "body of comment" msgstr "" -#: chat_box/views.py:29 templates/chat/chat.html:4 +#: chat_box/views.py:29 msgid "Chat Box" msgstr "" -#: dmoj/settings.py:355 +#: dmoj/settings.py:349 msgid "German" msgstr "Deutsch" -#: dmoj/settings.py:356 +#: dmoj/settings.py:350 msgid "English" msgstr "Englisch" -#: dmoj/settings.py:357 +#: dmoj/settings.py:351 msgid "Spanish" msgstr "" -#: dmoj/settings.py:358 +#: dmoj/settings.py:352 msgid "French" msgstr "Französisch" -#: dmoj/settings.py:359 +#: dmoj/settings.py:353 msgid "Croatian" msgstr "" -#: dmoj/settings.py:360 +#: dmoj/settings.py:354 msgid "Hungarian" msgstr "" -#: dmoj/settings.py:361 +#: dmoj/settings.py:355 msgid "Japanese" msgstr "" -#: dmoj/settings.py:362 +#: dmoj/settings.py:356 msgid "Korean" msgstr "" -#: dmoj/settings.py:363 +#: dmoj/settings.py:357 msgid "Brazilian Portuguese" msgstr "" -#: dmoj/settings.py:364 +#: dmoj/settings.py:358 msgid "Romanian" msgstr "Rumänisch" -#: dmoj/settings.py:365 +#: dmoj/settings.py:359 msgid "Russian" msgstr "Russisch" -#: dmoj/settings.py:366 +#: dmoj/settings.py:360 msgid "Serbian (Latin)" msgstr "" -#: dmoj/settings.py:367 +#: dmoj/settings.py:361 msgid "Turkish" msgstr "" -#: dmoj/settings.py:368 +#: dmoj/settings.py:362 msgid "Vietnamese" msgstr "" -#: dmoj/settings.py:369 +#: dmoj/settings.py:363 msgid "Simplified Chinese" msgstr "Chinesisch (vereinfacht)" -#: dmoj/settings.py:370 +#: dmoj/settings.py:364 msgid "Traditional Chinese" msgstr "" -#: dmoj/urls.py:58 +#: dmoj/urls.py:57 msgid "Login" msgstr "" -#: dmoj/urls.py:106 templates/base.html:193 +#: dmoj/urls.py:105 templates/base.html:190 msgid "Home" msgstr "" @@ -132,92 +132,90 @@ msgstr "" msgid "Associated page" msgstr "" -#: judge/admin/contest.py:30 +#: judge/admin/contest.py:28 msgid "Included contests" msgstr "" -#: judge/admin/contest.py:66 templates/contest/clarification.html:42 -#: templates/contest/contest.html:83 templates/contest/moss.html:43 -#: templates/problem/list.html:214 templates/problem/list.html:232 -#: templates/problem/list.html:350 templates/user/user-problems.html:56 +#: judge/admin/contest.py:64 templates/contest/contest.html:83 +#: templates/contest/moss.html:43 templates/problem/list.html:206 +#: templates/problem/list.html:221 templates/user/user-problems.html:56 #: templates/user/user-problems.html:98 msgid "Problem" msgstr "" -#: judge/admin/contest.py:119 +#: judge/admin/contest.py:112 msgid "Settings" msgstr "" -#: judge/admin/contest.py:121 +#: judge/admin/contest.py:114 msgid "Scheduling" msgstr "" -#: judge/admin/contest.py:122 templates/organization/home.html:107 +#: judge/admin/contest.py:115 msgid "Details" msgstr "" -#: judge/admin/contest.py:123 +#: judge/admin/contest.py:116 msgid "Format" msgstr "" -#: judge/admin/contest.py:124 templates/contest/ranking-table.html:7 -#: templates/user/user-about.html:15 templates/user/user-about.html:45 +#: judge/admin/contest.py:117 templates/contest/ranking-table.html:5 msgid "Rating" msgstr "" -#: judge/admin/contest.py:125 +#: judge/admin/contest.py:118 msgid "Access" msgstr "" -#: judge/admin/contest.py:127 judge/admin/problem.py:131 +#: judge/admin/contest.py:120 judge/admin/problem.py:131 msgid "Justice" msgstr "" -#: judge/admin/contest.py:207 +#: judge/admin/contest.py:158 #, python-format msgid "%d contest successfully marked as visible." msgid_plural "%d contests successfully marked as visible." msgstr[0] "" msgstr[1] "" -#: judge/admin/contest.py:210 +#: judge/admin/contest.py:161 msgid "Mark contests as visible" msgstr "" -#: judge/admin/contest.py:216 +#: judge/admin/contest.py:165 #, python-format msgid "%d contest successfully marked as hidden." msgid_plural "%d contests successfully marked as hidden." msgstr[0] "" msgstr[1] "" -#: judge/admin/contest.py:219 +#: judge/admin/contest.py:168 msgid "Mark contests as hidden" msgstr "" -#: judge/admin/contest.py:233 judge/admin/submission.py:164 +#: judge/admin/contest.py:182 judge/admin/submission.py:164 #, python-format msgid "%d submission was successfully scheduled for rejudging." msgid_plural "%d submissions were successfully scheduled for rejudging." msgstr[0] "" msgstr[1] "" -#: judge/admin/contest.py:308 +#: judge/admin/contest.py:256 #, python-format msgid "%d participation recalculated." msgid_plural "%d participations recalculated." msgstr[0] "" msgstr[1] "" -#: judge/admin/contest.py:311 +#: judge/admin/contest.py:259 msgid "Recalculate results" msgstr "" -#: judge/admin/contest.py:315 judge/admin/organization.py:65 +#: judge/admin/contest.py:263 judge/admin/organization.py:65 msgid "username" msgstr "" -#: judge/admin/contest.py:320 templates/base.html:277 +#: judge/admin/contest.py:268 templates/base.html:260 msgid "virtual" msgstr "" @@ -225,15 +223,15 @@ msgstr "" msgid "link path" msgstr "" -#: judge/admin/interface.py:65 +#: judge/admin/interface.py:62 msgid "Content" msgstr "" -#: judge/admin/interface.py:66 +#: judge/admin/interface.py:63 msgid "Summary" msgstr "" -#: judge/admin/interface.py:151 +#: judge/admin/interface.py:148 msgid "object" msgstr "" @@ -255,9 +253,8 @@ msgid "Taxonomy" msgstr "Systematik" #: judge/admin/problem.py:128 templates/contest/contest.html:84 -#: templates/problem/data.html:429 templates/problem/list.html:222 -#: templates/problem/list.html:248 templates/user/base-users-table.html:10 -#: templates/user/user-about.html:36 templates/user/user-about.html:52 +#: templates/problem/data.html:449 templates/problem/list.html:211 +#: templates/problem/list.html:232 templates/user/base-users-table.html:10 #: templates/user/user-problems.html:58 msgid "Points" msgstr "" @@ -306,7 +303,6 @@ msgid "timezone" msgstr "" #: judge/admin/profile.py:86 judge/admin/submission.py:211 -#: templates/notification/list.html:12 #: templates/organization/requests/log.html:9 #: templates/organization/requests/pending.html:12 #: templates/ticket/list.html:263 @@ -314,7 +310,6 @@ msgid "User" msgstr "" #: judge/admin/profile.py:91 templates/registration/registration_form.html:145 -#: templates/user/import/table_csv.html:8 msgid "Email" msgstr "" @@ -347,7 +342,7 @@ msgstr "" msgid "These problems are NOT allowed to be submitted in this language" msgstr "" -#: judge/admin/runtime.py:83 templates/problem/list.html:352 +#: judge/admin/runtime.py:83 msgid "Description" msgstr "" @@ -394,7 +389,7 @@ msgstr "" msgid "Rejudge the selected submissions" msgstr "" -#: judge/admin/submission.py:193 judge/views/problem_manage.py:159 +#: judge/admin/submission.py:193 judge/views/problem_manage.py:128 #, python-format msgid "%d submission were successfully rescored." msgid_plural "%d submissions were successfully rescored." @@ -405,8 +400,7 @@ msgstr[1] "" msgid "Rescore the selected submissions" msgstr "" -#: judge/admin/submission.py:200 templates/problem/list.html:216 -#: templates/problem/list.html:236 +#: judge/admin/submission.py:200 msgid "Problem code" msgstr "" @@ -414,12 +408,10 @@ msgstr "" msgid "Problem name" msgstr "" -#: judge/admin/submission.py:215 templates/notification/list.html:15 -#: templates/organization/requests/log.html:10 +#: judge/admin/submission.py:215 templates/organization/requests/log.html:10 #: templates/organization/requests/pending.html:13 -#: templates/problem/list.html:351 -#: templates/submission/status-testcases.html:125 -#: templates/submission/status-testcases.html:127 +#: templates/submission/status-testcases.html:105 +#: templates/submission/status-testcases.html:107 msgid "Time" msgstr "" @@ -433,7 +425,7 @@ msgstr "" msgid "%.2f MB" msgstr "" -#: judge/admin/submission.py:227 templates/submission/status-testcases.html:132 +#: judge/admin/submission.py:227 templates/submission/status-testcases.html:112 msgid "Memory" msgstr "" @@ -453,20 +445,20 @@ msgstr "" msgid "Online Judge" msgstr "" -#: judge/comments.py:60 +#: judge/comments.py:41 msgid "Comment body" msgstr "" -#: judge/comments.py:66 judge/views/ticket.py:63 +#: judge/comments.py:47 judge/views/ticket.py:46 msgid "Your part is silent, little toad." msgstr "" -#: judge/comments.py:69 templates/comments/list.html:132 +#: judge/comments.py:50 templates/comments/list.html:131 msgid "" "You need to have solved at least one problem before your voice can be heard." msgstr "" -#: judge/comments.py:113 +#: judge/comments.py:92 msgid "Posted comment" msgstr "" @@ -482,10 +474,6 @@ msgstr "" msgid "ECOO" msgstr "" -#: judge/contest_format/icpc.py:19 -msgid "ICPC" -msgstr "" - #: judge/contest_format/ioi.py:19 msgid "IOI" msgstr "" @@ -498,58 +486,52 @@ msgstr "" msgid "Enable experimental features" msgstr "" -#: judge/forms.py:57 judge/views/organization.py:168 judge/views/register.py:49 +#: judge/forms.py:57 judge/views/organization.py:127 #, python-brace-format msgid "You may not be part of more than {count} public organizations." msgstr "" -#: judge/forms.py:82 -msgid "Any judge" -msgstr "" - -#: judge/forms.py:112 judge/views/register.py:26 +#: judge/forms.py:107 judge/views/register.py:26 #: templates/registration/registration_form.html:139 #: templates/user/base-users-table.html:5 -#: templates/user/import/table_csv.html:4 msgid "Username" msgstr "" -#: judge/forms.py:113 templates/registration/registration_form.html:151 +#: judge/forms.py:108 templates/registration/registration_form.html:151 #: templates/registration/registration_form.html:165 -#: templates/user/import/table_csv.html:5 msgid "Password" msgstr "" -#: judge/forms.py:135 +#: judge/forms.py:130 msgid "Two Factor Authentication tokens must be 6 decimal digits." msgstr "" -#: judge/forms.py:144 templates/registration/totp_auth.html:32 +#: judge/forms.py:139 templates/registration/totp_auth.html:32 msgid "Invalid Two Factor Authentication token." msgstr "" -#: judge/forms.py:148 judge/models/problem.py:97 +#: judge/forms.py:143 judge/models/problem.py:97 msgid "Problem code must be ^[a-z0-9]+$" msgstr "" -#: judge/forms.py:153 +#: judge/forms.py:148 msgid "Problem with code already exists." msgstr "" -#: judge/forms.py:158 judge/models/contest.py:61 +#: judge/forms.py:153 judge/models/contest.py:52 msgid "Contest id must be ^[a-z0-9]+$" msgstr "" -#: judge/forms.py:163 +#: judge/forms.py:158 msgid "Contest with key already exists." msgstr "" -#: judge/jinja2/datetime.py:26 templates/blog/blog.html:26 +#: judge/jinja2/datetime.py:26 templates/blog/content.html:27 #: templates/blog/dashboard.html:21 msgid "N j, Y, g:i a" msgstr "" -#: judge/jinja2/datetime.py:26 templates/chat/message.html:13 +#: judge/jinja2/datetime.py:26 #, python-brace-format msgid "{time}" msgstr "" @@ -579,542 +561,472 @@ msgstr "" msgid "Detect best quality" msgstr "" -#: judge/models/comment.py:26 +#: judge/models/comment.py:25 msgid "Page code must be ^[pcs]:[a-z0-9]+$|^b:\\d+$" msgstr "" -#: judge/models/comment.py:42 +#: judge/models/comment.py:41 msgid "commenter" msgstr "" -#: judge/models/comment.py:44 judge/models/comment.py:177 +#: judge/models/comment.py:43 judge/models/comment.py:176 msgid "associated page" msgstr "" -#: judge/models/comment.py:46 +#: judge/models/comment.py:45 msgid "votes" msgstr "" -#: judge/models/comment.py:48 +#: judge/models/comment.py:47 msgid "hide the comment" msgstr "" -#: judge/models/comment.py:49 +#: judge/models/comment.py:48 msgid "parent" msgstr "" -#: judge/models/comment.py:54 judge/models/comment.py:192 +#: judge/models/comment.py:53 msgid "comment" msgstr "" -#: judge/models/comment.py:55 +#: judge/models/comment.py:54 msgid "comments" msgstr "" -#: judge/models/comment.py:137 judge/models/problem.py:443 +#: judge/models/comment.py:136 judge/models/problem.py:406 #, python-format msgid "Editorial for %s" msgstr "" -#: judge/models/comment.py:172 +#: judge/models/comment.py:171 msgid "comment vote" msgstr "" -#: judge/models/comment.py:173 +#: judge/models/comment.py:172 msgid "comment votes" msgstr "" -#: judge/models/comment.py:182 +#: judge/models/comment.py:181 msgid "Override comment lock" msgstr "" -#: judge/models/comment.py:190 -msgid "owner" -msgstr "" - -#: judge/models/comment.py:193 judge/models/message.py:16 -msgid "read" -msgstr "" - -#: judge/models/comment.py:194 -msgid "category" -msgstr "" - -#: judge/models/comment.py:195 -msgid "html link to comments, used for non-comments" -msgstr "" - -#: judge/models/comment.py:196 -msgid "who trigger, used for non-comment" -msgstr "" - -#: judge/models/contest.py:23 +#: judge/models/contest.py:22 msgid "Invalid colour." msgstr "" -#: judge/models/contest.py:25 +#: judge/models/contest.py:24 msgid "tag name" msgstr "" -#: judge/models/contest.py:26 +#: judge/models/contest.py:25 msgid "Lowercase letters and hyphens only." msgstr "" -#: judge/models/contest.py:27 +#: judge/models/contest.py:26 msgid "tag colour" msgstr "" -#: judge/models/contest.py:28 +#: judge/models/contest.py:27 msgid "tag description" msgstr "" -#: judge/models/contest.py:47 +#: judge/models/contest.py:46 msgid "contest tag" msgstr "" -#: judge/models/contest.py:48 judge/models/contest.py:118 +#: judge/models/contest.py:47 judge/models/contest.py:101 msgid "contest tags" msgstr "" -#: judge/models/contest.py:56 -msgid "Visible" -msgstr "" - -#: judge/models/contest.py:57 -msgid "Hidden for duration of contest" -msgstr "" - -#: judge/models/contest.py:58 -msgid "Hidden for duration of participation" -msgstr "" - -#: judge/models/contest.py:60 +#: judge/models/contest.py:51 msgid "contest id" msgstr "" -#: judge/models/contest.py:62 +#: judge/models/contest.py:53 msgid "contest name" msgstr "" -#: judge/models/contest.py:63 -msgid "These users will be able to edit the contest." +#: judge/models/contest.py:54 +msgid "These people will be able to edit the contest." msgstr "" -#: judge/models/contest.py:65 -msgid "" -"These users will be able to edit the contest, but will not be listed as " -"authors." -msgstr "" - -#: judge/models/contest.py:68 -msgid "These users will be able to view the contest, but not edit it." -msgstr "" - -#: judge/models/contest.py:71 judge/models/runtime.py:136 +#: judge/models/contest.py:56 judge/models/runtime.py:133 msgid "description" msgstr "" -#: judge/models/contest.py:72 judge/models/problem.py:390 -#: judge/models/runtime.py:138 +#: judge/models/contest.py:57 judge/models/problem.py:353 +#: judge/models/runtime.py:135 msgid "problems" msgstr "" -#: judge/models/contest.py:73 judge/models/contest.py:404 +#: judge/models/contest.py:58 judge/models/contest.py:258 msgid "start time" msgstr "" -#: judge/models/contest.py:74 +#: judge/models/contest.py:59 msgid "end time" msgstr "" -#: judge/models/contest.py:75 judge/models/problem.py:118 -#: judge/models/problem.py:414 +#: judge/models/contest.py:60 judge/models/problem.py:118 +#: judge/models/problem.py:377 msgid "time limit" msgstr "" -#: judge/models/contest.py:76 judge/models/problem.py:136 +#: judge/models/contest.py:61 judge/models/problem.py:136 msgid "publicly visible" msgstr "" -#: judge/models/contest.py:77 +#: judge/models/contest.py:62 msgid "" "Should be set even for organization-private contests, where it determines " "whether the contest is visible to members of the specified organizations." msgstr "" -#: judge/models/contest.py:80 +#: judge/models/contest.py:65 msgid "contest rated" msgstr "" -#: judge/models/contest.py:80 +#: judge/models/contest.py:65 msgid "Whether this contest can be rated." msgstr "" -#: judge/models/contest.py:82 -msgid "scoreboard visibility" +#: judge/models/contest.py:67 +msgid "hide scoreboard" msgstr "" -#: judge/models/contest.py:83 -msgid "Scoreboard visibility through the duration of the contest" +#: judge/models/contest.py:68 +msgid "" +"Whether the scoreboard should remain hidden for the duration of the contest." msgstr "" -#: judge/models/contest.py:85 -msgid "view contest scoreboard" -msgstr "" - -#: judge/models/contest.py:87 -msgid "These users will be able to view the scoreboard." -msgstr "" - -#: judge/models/contest.py:88 +#: judge/models/contest.py:71 msgid "no comments" msgstr "" -#: judge/models/contest.py:89 +#: judge/models/contest.py:72 msgid "Use clarification system instead of comments." msgstr "" -#: judge/models/contest.py:91 +#: judge/models/contest.py:74 msgid "Rating floor for contest" msgstr "" -#: judge/models/contest.py:93 +#: judge/models/contest.py:76 msgid "Rating ceiling for contest" msgstr "" -#: judge/models/contest.py:95 +#: judge/models/contest.py:78 msgid "rate all" msgstr "" -#: judge/models/contest.py:95 +#: judge/models/contest.py:78 msgid "Rate all users who joined." msgstr "" -#: judge/models/contest.py:96 +#: judge/models/contest.py:79 msgid "exclude from ratings" msgstr "" -#: judge/models/contest.py:98 +#: judge/models/contest.py:81 msgid "private to specific users" msgstr "" -#: judge/models/contest.py:99 +#: judge/models/contest.py:82 msgid "private contestants" msgstr "" -#: judge/models/contest.py:100 +#: judge/models/contest.py:83 msgid "If private, only these users may see the contest" msgstr "" -#: judge/models/contest.py:102 +#: judge/models/contest.py:85 msgid "hide problem tags" msgstr "" -#: judge/models/contest.py:103 +#: judge/models/contest.py:86 msgid "Whether problem tags should be hidden by default." msgstr "" -#: judge/models/contest.py:105 +#: judge/models/contest.py:88 msgid "run pretests only" msgstr "" -#: judge/models/contest.py:106 +#: judge/models/contest.py:89 msgid "" "Whether judges should grade pretests only, versus all testcases. Commonly " "set during a contest, then unset prior to rejudging user submissions when " "the contest ends." msgstr "" -#: judge/models/contest.py:110 judge/models/interface.py:77 -#: judge/models/problem.py:157 +#: judge/models/contest.py:93 judge/models/problem.py:157 msgid "private to organizations" msgstr "" -#: judge/models/contest.py:111 judge/models/interface.py:75 -#: judge/models/problem.py:155 judge/models/profile.py:77 +#: judge/models/contest.py:94 judge/models/problem.py:155 +#: judge/models/profile.py:77 msgid "organizations" msgstr "" -#: judge/models/contest.py:112 +#: judge/models/contest.py:95 msgid "If private, only these organizations may see the contest" msgstr "" -#: judge/models/contest.py:113 judge/models/problem.py:145 +#: judge/models/contest.py:96 judge/models/problem.py:145 msgid "OpenGraph image" msgstr "" -#: judge/models/contest.py:114 judge/models/profile.py:48 +#: judge/models/contest.py:97 judge/models/profile.py:48 msgid "Logo override image" msgstr "" -#: judge/models/contest.py:116 +#: judge/models/contest.py:99 msgid "" "This image will replace the default site logo for users inside the contest." msgstr "" -#: judge/models/contest.py:119 +#: judge/models/contest.py:102 msgid "the amount of live participants" msgstr "" -#: judge/models/contest.py:120 +#: judge/models/contest.py:103 msgid "contest summary" msgstr "" -#: judge/models/contest.py:121 judge/models/problem.py:147 +#: judge/models/contest.py:104 judge/models/problem.py:147 msgid "Plain-text, shown in meta description tag, e.g. for social media." msgstr "" -#: judge/models/contest.py:122 judge/models/profile.py:47 +#: judge/models/contest.py:105 judge/models/profile.py:47 msgid "access code" msgstr "" -#: judge/models/contest.py:123 +#: judge/models/contest.py:106 msgid "" "An optional code to prompt contestants before they are allowed to join the " "contest. Leave it blank to disable." msgstr "" -#: judge/models/contest.py:125 judge/models/problem.py:141 +#: judge/models/contest.py:108 judge/models/problem.py:141 msgid "personae non gratae" msgstr "" -#: judge/models/contest.py:126 +#: judge/models/contest.py:109 msgid "Bans the selected users from joining this contest." msgstr "" -#: judge/models/contest.py:127 +#: judge/models/contest.py:110 msgid "contest format" msgstr "" -#: judge/models/contest.py:128 +#: judge/models/contest.py:111 msgid "The contest format module to use." msgstr "" -#: judge/models/contest.py:129 +#: judge/models/contest.py:112 msgid "contest format configuration" msgstr "" -#: judge/models/contest.py:130 +#: judge/models/contest.py:113 msgid "" "A JSON object to serve as the configuration for the chosen contest format " "module. Leave empty to use None. Exact format depends on the contest format " "selected." msgstr "" -#: judge/models/contest.py:137 -msgid "precision points" -msgstr "" - -#: judge/models/contest.py:139 -msgid "Number of digits to round points to." -msgstr "" - -#: judge/models/contest.py:383 +#: judge/models/contest.py:239 msgid "See private contests" msgstr "" -#: judge/models/contest.py:384 +#: judge/models/contest.py:240 msgid "Edit own contests" msgstr "" -#: judge/models/contest.py:385 +#: judge/models/contest.py:241 msgid "Edit all contests" msgstr "" -#: judge/models/contest.py:386 +#: judge/models/contest.py:242 msgid "Clone contest" msgstr "" -#: judge/models/contest.py:387 templates/contest/moss.html:74 +#: judge/models/contest.py:243 templates/contest/moss.html:74 msgid "MOSS contest" msgstr "" -#: judge/models/contest.py:388 +#: judge/models/contest.py:244 msgid "Rate contests" msgstr "" -#: judge/models/contest.py:389 +#: judge/models/contest.py:245 msgid "Contest access codes" msgstr "" -#: judge/models/contest.py:390 +#: judge/models/contest.py:246 msgid "Create private contests" msgstr "" -#: judge/models/contest.py:391 -msgid "Change contest visibility" -msgstr "" - -#: judge/models/contest.py:392 -msgid "Edit contest problem label script" -msgstr "" - -#: judge/models/contest.py:394 judge/models/contest.py:492 -#: judge/models/contest.py:529 judge/models/contest.py:552 -#: judge/models/submission.py:84 +#: judge/models/contest.py:248 judge/models/contest.py:345 +#: judge/models/contest.py:382 judge/models/contest.py:404 +#: judge/models/submission.py:83 msgid "contest" msgstr "" -#: judge/models/contest.py:395 +#: judge/models/contest.py:249 msgid "contests" msgstr "" -#: judge/models/contest.py:402 +#: judge/models/contest.py:256 msgid "associated contest" msgstr "" -#: judge/models/contest.py:405 +#: judge/models/contest.py:259 msgid "score" msgstr "" -#: judge/models/contest.py:406 +#: judge/models/contest.py:260 msgid "cumulative time" msgstr "" -#: judge/models/contest.py:407 +#: judge/models/contest.py:261 msgid "is disqualified" msgstr "" -#: judge/models/contest.py:408 +#: judge/models/contest.py:262 msgid "Whether this participation is disqualified." msgstr "" -#: judge/models/contest.py:409 -msgid "tie-breaking field" -msgstr "" - -#: judge/models/contest.py:410 +#: judge/models/contest.py:263 msgid "virtual participation id" msgstr "" -#: judge/models/contest.py:411 +#: judge/models/contest.py:264 msgid "0 means non-virtual, otherwise the n-th virtual participation." msgstr "" -#: judge/models/contest.py:412 +#: judge/models/contest.py:265 msgid "contest format specific data" msgstr "" -#: judge/models/contest.py:478 +#: judge/models/contest.py:331 #, python-format msgid "%s spectating in %s" msgstr "" -#: judge/models/contest.py:480 +#: judge/models/contest.py:333 #, python-format msgid "%s in %s, v%d" msgstr "" -#: judge/models/contest.py:481 +#: judge/models/contest.py:334 #, python-format msgid "%s in %s" msgstr "" -#: judge/models/contest.py:484 +#: judge/models/contest.py:337 msgid "contest participation" msgstr "" -#: judge/models/contest.py:485 +#: judge/models/contest.py:338 msgid "contest participations" msgstr "" -#: judge/models/contest.py:491 judge/models/contest.py:513 -#: judge/models/contest.py:553 judge/models/problem.py:389 -#: judge/models/problem.py:394 judge/models/problem.py:412 -#: judge/models/problem_data.py:40 +#: judge/models/contest.py:344 judge/models/contest.py:366 +#: judge/models/contest.py:405 judge/models/problem.py:352 +#: judge/models/problem.py:357 judge/models/problem.py:375 +#: judge/models/problem_data.py:38 msgid "problem" msgstr "" -#: judge/models/contest.py:493 judge/models/contest.py:517 +#: judge/models/contest.py:346 judge/models/contest.py:370 #: judge/models/problem.py:129 msgid "points" msgstr "" -#: judge/models/contest.py:494 +#: judge/models/contest.py:347 msgid "partial" msgstr "" -#: judge/models/contest.py:495 judge/models/contest.py:518 +#: judge/models/contest.py:348 judge/models/contest.py:371 msgid "is pretested" msgstr "" -#: judge/models/contest.py:496 judge/models/interface.py:43 +#: judge/models/contest.py:349 judge/models/interface.py:43 msgid "order" msgstr "" -#: judge/models/contest.py:497 +#: judge/models/contest.py:350 msgid "0 to not show testcases, 1 to show" msgstr "" -#: judge/models/contest.py:498 +#: judge/models/contest.py:351 msgid "visible testcases" msgstr "" -#: judge/models/contest.py:499 +#: judge/models/contest.py:352 msgid "Maximum number of submissions for this problem, or 0 for no limit." msgstr "" -#: judge/models/contest.py:501 +#: judge/models/contest.py:354 msgid "Why include a problem you can't submit to?" msgstr "" -#: judge/models/contest.py:506 +#: judge/models/contest.py:359 msgid "contest problem" msgstr "" -#: judge/models/contest.py:507 +#: judge/models/contest.py:360 msgid "contest problems" msgstr "" -#: judge/models/contest.py:511 judge/models/submission.py:183 +#: judge/models/contest.py:364 judge/models/submission.py:181 msgid "submission" msgstr "" -#: judge/models/contest.py:515 judge/models/contest.py:530 +#: judge/models/contest.py:368 judge/models/contest.py:383 msgid "participation" msgstr "" -#: judge/models/contest.py:519 +#: judge/models/contest.py:372 msgid "Whether this submission was ran only on pretests." msgstr "" -#: judge/models/contest.py:523 +#: judge/models/contest.py:376 msgid "contest submission" msgstr "" -#: judge/models/contest.py:524 +#: judge/models/contest.py:377 msgid "contest submissions" msgstr "" -#: judge/models/contest.py:532 +#: judge/models/contest.py:385 msgid "rank" msgstr "" -#: judge/models/contest.py:533 +#: judge/models/contest.py:386 msgid "rating" msgstr "" -#: judge/models/contest.py:534 +#: judge/models/contest.py:387 msgid "volatility" msgstr "" -#: judge/models/contest.py:535 +#: judge/models/contest.py:388 msgid "last rated" msgstr "" -#: judge/models/contest.py:539 +#: judge/models/contest.py:392 msgid "contest rating" msgstr "" -#: judge/models/contest.py:540 +#: judge/models/contest.py:393 msgid "contest ratings" msgstr "" -#: judge/models/contest.py:560 +#: judge/models/contest.py:412 msgid "contest moss result" msgstr "" -#: judge/models/contest.py:561 +#: judge/models/contest.py:413 msgid "contest moss results" msgstr "" @@ -1154,7 +1066,7 @@ msgstr "" msgid "post title" msgstr "" -#: judge/models/interface.py:67 judge/models/problem.py:432 +#: judge/models/interface.py:67 judge/models/problem.py:395 msgid "authors" msgstr "" @@ -1162,7 +1074,7 @@ msgstr "" msgid "slug" msgstr "" -#: judge/models/interface.py:69 judge/models/problem.py:430 +#: judge/models/interface.py:69 judge/models/problem.py:393 msgid "public visibility" msgstr "" @@ -1186,19 +1098,15 @@ msgstr "" msgid "openGraph image" msgstr "" -#: judge/models/interface.py:76 -msgid "If private, only these organizations may see the blog post." -msgstr "" - -#: judge/models/interface.py:105 +#: judge/models/interface.py:91 msgid "Edit all posts" msgstr "" -#: judge/models/interface.py:107 +#: judge/models/interface.py:93 msgid "blog post" msgstr "" -#: judge/models/interface.py:108 +#: judge/models/interface.py:94 msgid "blog posts" msgstr "" @@ -1222,6 +1130,10 @@ msgstr "" msgid "message timestamp" msgstr "" +#: judge/models/message.py:16 +msgid "read" +msgstr "" + #: judge/models/message.py:20 msgid "messages in the thread" msgstr "" @@ -1358,7 +1270,7 @@ msgid "" "are supported." msgstr "" -#: judge/models/problem.py:123 judge/models/problem.py:417 +#: judge/models/problem.py:123 judge/models/problem.py:380 msgid "memory limit" msgstr "" @@ -1431,188 +1343,188 @@ msgstr "" msgid "If private, only these organizations may see the problem." msgstr "" -#: judge/models/problem.py:395 judge/models/problem.py:413 -#: judge/models/runtime.py:111 +#: judge/models/problem.py:358 judge/models/problem.py:376 +#: judge/models/runtime.py:108 msgid "language" msgstr "" -#: judge/models/problem.py:396 +#: judge/models/problem.py:359 msgid "translated name" msgstr "" -#: judge/models/problem.py:397 +#: judge/models/problem.py:360 msgid "translated description" msgstr "" -#: judge/models/problem.py:401 +#: judge/models/problem.py:364 msgid "problem translation" msgstr "" -#: judge/models/problem.py:402 +#: judge/models/problem.py:365 msgid "problem translations" msgstr "" -#: judge/models/problem.py:406 +#: judge/models/problem.py:369 msgid "clarified problem" msgstr "" -#: judge/models/problem.py:407 +#: judge/models/problem.py:370 msgid "clarification body" msgstr "" -#: judge/models/problem.py:408 +#: judge/models/problem.py:371 msgid "clarification timestamp" msgstr "" -#: judge/models/problem.py:423 +#: judge/models/problem.py:386 msgid "language-specific resource limit" msgstr "" -#: judge/models/problem.py:424 +#: judge/models/problem.py:387 msgid "language-specific resource limits" msgstr "" -#: judge/models/problem.py:428 +#: judge/models/problem.py:391 msgid "associated problem" msgstr "" -#: judge/models/problem.py:431 +#: judge/models/problem.py:394 msgid "publish date" msgstr "" -#: judge/models/problem.py:433 +#: judge/models/problem.py:396 msgid "editorial content" msgstr "" -#: judge/models/problem.py:449 +#: judge/models/problem.py:412 msgid "solution" msgstr "" -#: judge/models/problem.py:450 +#: judge/models/problem.py:413 msgid "solutions" msgstr "" -#: judge/models/problem_data.py:26 +#: judge/models/problem_data.py:24 msgid "Standard" msgstr "" -#: judge/models/problem_data.py:27 +#: judge/models/problem_data.py:25 msgid "Floats" msgstr "" -#: judge/models/problem_data.py:28 +#: judge/models/problem_data.py:26 msgid "Floats (absolute)" msgstr "" -#: judge/models/problem_data.py:29 +#: judge/models/problem_data.py:27 msgid "Floats (relative)" msgstr "" -#: judge/models/problem_data.py:30 +#: judge/models/problem_data.py:28 msgid "Non-trailing spaces" msgstr "" -#: judge/models/problem_data.py:31 +#: judge/models/problem_data.py:29 msgid "Unordered" msgstr "" -#: judge/models/problem_data.py:32 +#: judge/models/problem_data.py:30 msgid "Byte identical" msgstr "" -#: judge/models/problem_data.py:33 +#: judge/models/problem_data.py:31 msgid "Line-by-line" msgstr "" -#: judge/models/problem_data.py:34 +#: judge/models/problem_data.py:32 msgid "Custom checker (PY)" msgstr "" -#: judge/models/problem_data.py:35 +#: judge/models/problem_data.py:33 msgid "Custom validator (CPP)" msgstr "" -#: judge/models/problem_data.py:42 +#: judge/models/problem_data.py:40 msgid "data zip file" msgstr "" -#: judge/models/problem_data.py:44 +#: judge/models/problem_data.py:42 msgid "generator file" msgstr "" -#: judge/models/problem_data.py:46 judge/models/problem_data.py:121 +#: judge/models/problem_data.py:44 judge/models/problem_data.py:110 msgid "output prefix length" msgstr "" -#: judge/models/problem_data.py:47 judge/models/problem_data.py:122 +#: judge/models/problem_data.py:45 judge/models/problem_data.py:111 msgid "output limit length" msgstr "" -#: judge/models/problem_data.py:48 +#: judge/models/problem_data.py:46 msgid "init.yml generation feedback" msgstr "" -#: judge/models/problem_data.py:49 judge/models/problem_data.py:123 +#: judge/models/problem_data.py:47 judge/models/problem_data.py:112 msgid "checker" msgstr "" -#: judge/models/problem_data.py:50 judge/models/problem_data.py:124 +#: judge/models/problem_data.py:48 judge/models/problem_data.py:113 msgid "checker arguments" msgstr "" -#: judge/models/problem_data.py:51 judge/models/problem_data.py:125 +#: judge/models/problem_data.py:49 judge/models/problem_data.py:114 msgid "checker arguments as a JSON object" msgstr "" -#: judge/models/problem_data.py:52 +#: judge/models/problem_data.py:50 msgid "custom checker file" msgstr "" -#: judge/models/problem_data.py:58 +#: judge/models/problem_data.py:56 msgid "custom validator file" msgstr "" -#: judge/models/problem_data.py:108 +#: judge/models/problem_data.py:97 msgid "problem data set" msgstr "" -#: judge/models/problem_data.py:110 +#: judge/models/problem_data.py:99 msgid "case position" msgstr "" -#: judge/models/problem_data.py:111 +#: judge/models/problem_data.py:100 msgid "case type" msgstr "" -#: judge/models/problem_data.py:112 +#: judge/models/problem_data.py:101 msgid "Normal case" msgstr "" -#: judge/models/problem_data.py:113 +#: judge/models/problem_data.py:102 msgid "Batch start" msgstr "" -#: judge/models/problem_data.py:114 +#: judge/models/problem_data.py:103 msgid "Batch end" msgstr "" -#: judge/models/problem_data.py:116 +#: judge/models/problem_data.py:105 msgid "input file name" msgstr "" -#: judge/models/problem_data.py:117 +#: judge/models/problem_data.py:106 msgid "output file name" msgstr "" -#: judge/models/problem_data.py:118 +#: judge/models/problem_data.py:107 msgid "generator arguments" msgstr "" -#: judge/models/problem_data.py:119 +#: judge/models/problem_data.py:108 msgid "point value" msgstr "" -#: judge/models/problem_data.py:120 +#: judge/models/problem_data.py:109 msgid "case is pretest?" msgstr "" @@ -1685,7 +1597,7 @@ msgid "" msgstr "" #: judge/models/profile.py:76 judge/models/profile.py:93 -#: judge/models/profile.py:212 +#: judge/models/profile.py:192 msgid "organization" msgstr "" @@ -1781,31 +1693,31 @@ msgstr "" msgid "Notes for administrators regarding this user." msgstr "" -#: judge/models/profile.py:206 +#: judge/models/profile.py:186 msgid "user profile" msgstr "" -#: judge/models/profile.py:207 +#: judge/models/profile.py:187 msgid "user profiles" msgstr "" -#: judge/models/profile.py:214 +#: judge/models/profile.py:194 msgid "request time" msgstr "" -#: judge/models/profile.py:215 +#: judge/models/profile.py:195 msgid "state" msgstr "" -#: judge/models/profile.py:220 +#: judge/models/profile.py:200 msgid "reason" msgstr "" -#: judge/models/profile.py:223 +#: judge/models/profile.py:203 msgid "organization join request" msgstr "" -#: judge/models/profile.py:224 +#: judge/models/profile.py:204 msgid "organization join requests" msgstr "" @@ -1896,86 +1808,86 @@ msgstr "" msgid "The extension of source files, e.g., \"py\" or \"cpp\"." msgstr "" -#: judge/models/runtime.py:112 +#: judge/models/runtime.py:109 msgid "languages" msgstr "" -#: judge/models/runtime.py:116 +#: judge/models/runtime.py:113 msgid "language to which this runtime belongs" msgstr "" -#: judge/models/runtime.py:117 +#: judge/models/runtime.py:114 msgid "judge on which this runtime exists" msgstr "" -#: judge/models/runtime.py:118 +#: judge/models/runtime.py:115 msgid "runtime name" msgstr "" -#: judge/models/runtime.py:119 +#: judge/models/runtime.py:116 msgid "runtime version" msgstr "" -#: judge/models/runtime.py:120 +#: judge/models/runtime.py:117 msgid "order in which to display this runtime" msgstr "" -#: judge/models/runtime.py:124 +#: judge/models/runtime.py:121 msgid "Server name, hostname-style" msgstr "" -#: judge/models/runtime.py:125 +#: judge/models/runtime.py:122 msgid "time of creation" msgstr "" -#: judge/models/runtime.py:126 +#: judge/models/runtime.py:123 msgid "A key to authenticate this judge" msgstr "" -#: judge/models/runtime.py:127 +#: judge/models/runtime.py:124 msgid "authentication key" msgstr "" -#: judge/models/runtime.py:128 +#: judge/models/runtime.py:125 msgid "block judge" msgstr "" -#: judge/models/runtime.py:129 +#: judge/models/runtime.py:126 msgid "" "Whether this judge should be blocked from connecting, even if its key is " "correct." msgstr "" -#: judge/models/runtime.py:131 +#: judge/models/runtime.py:128 msgid "judge online status" msgstr "" -#: judge/models/runtime.py:132 +#: judge/models/runtime.py:129 msgid "judge start time" msgstr "" -#: judge/models/runtime.py:133 +#: judge/models/runtime.py:130 msgid "response time" msgstr "" -#: judge/models/runtime.py:134 +#: judge/models/runtime.py:131 msgid "system load" msgstr "" -#: judge/models/runtime.py:135 +#: judge/models/runtime.py:132 msgid "Load for the last minute, divided by processors to be fair." msgstr "" -#: judge/models/runtime.py:139 judge/models/runtime.py:179 +#: judge/models/runtime.py:136 judge/models/runtime.py:176 msgid "judges" msgstr "" -#: judge/models/runtime.py:178 +#: judge/models/runtime.py:175 msgid "judge" msgstr "" #: judge/models/submission.py:20 judge/models/submission.py:47 -#: judge/utils/problems.py:79 +#: judge/utils/problems.py:77 msgid "Accepted" msgstr "" @@ -2004,7 +1916,7 @@ msgid "Runtime Error" msgstr "" #: judge/models/submission.py:27 judge/models/submission.py:41 -#: judge/models/submission.py:55 judge/utils/problems.py:81 +#: judge/models/submission.py:55 judge/utils/problems.py:79 msgid "Compile Error" msgstr "" @@ -2045,15 +1957,15 @@ msgstr "" msgid "submission time" msgstr "" -#: judge/models/submission.py:67 judge/models/submission.py:203 +#: judge/models/submission.py:67 judge/models/submission.py:201 msgid "execution time" msgstr "" -#: judge/models/submission.py:68 judge/models/submission.py:204 +#: judge/models/submission.py:68 judge/models/submission.py:202 msgid "memory usage" msgstr "" -#: judge/models/submission.py:69 judge/models/submission.py:205 +#: judge/models/submission.py:69 judge/models/submission.py:203 msgid "points granted" msgstr "" @@ -2090,62 +2002,58 @@ msgid "judged on" msgstr "" #: judge/models/submission.py:81 -msgid "submission judge time" -msgstr "" - -#: judge/models/submission.py:82 msgid "was rejudged by admin" msgstr "" -#: judge/models/submission.py:83 +#: judge/models/submission.py:82 msgid "was ran on pretests only" msgstr "" -#: judge/models/submission.py:184 templates/contest/moss.html:58 +#: judge/models/submission.py:182 templates/contest/moss.html:58 msgid "submissions" msgstr "" -#: judge/models/submission.py:188 judge/models/submission.py:199 +#: judge/models/submission.py:186 judge/models/submission.py:197 msgid "associated submission" msgstr "" -#: judge/models/submission.py:190 +#: judge/models/submission.py:188 msgid "source code" msgstr "" -#: judge/models/submission.py:201 +#: judge/models/submission.py:199 msgid "test case ID" msgstr "" -#: judge/models/submission.py:202 +#: judge/models/submission.py:200 msgid "status flag" msgstr "" -#: judge/models/submission.py:206 +#: judge/models/submission.py:204 msgid "points possible" msgstr "" -#: judge/models/submission.py:207 +#: judge/models/submission.py:205 msgid "batch number" msgstr "" -#: judge/models/submission.py:208 +#: judge/models/submission.py:206 msgid "judging feedback" msgstr "" -#: judge/models/submission.py:209 +#: judge/models/submission.py:207 msgid "extended judging feedback" msgstr "" -#: judge/models/submission.py:210 +#: judge/models/submission.py:208 msgid "program output" msgstr "" -#: judge/models/submission.py:218 +#: judge/models/submission.py:216 msgid "submission test case" msgstr "" -#: judge/models/submission.py:219 +#: judge/models/submission.py:217 msgid "submission test cases" msgstr "" @@ -2197,21 +2105,12 @@ msgstr "" msgid "message time" msgstr "" -#: judge/pdf_problems.py:147 judge/pdf_problems.py:199 -#: judge/pdf_problems.py:259 +#: judge/pdf_problems.py:134 judge/pdf_problems.py:186 +#: judge/pdf_problems.py:246 msgid "Page [page] of [topage]" msgstr "" -#: judge/pdf_problems.py:280 -#, python-format -msgid "Page %s of %s" -msgstr "" - -#: judge/tasks/contest.py:19 -msgid "Recalculating contest scores" -msgstr "" - -#: judge/tasks/contest.py:40 +#: judge/tasks/moss.py:25 msgid "Running MOSS" msgstr "" @@ -2223,60 +2122,60 @@ msgstr "" msgid "Recalculating user points" msgstr "" -#: judge/utils/problem_data.py:70 +#: judge/utils/problem_data.py:68 msgid "Empty batches not allowed." msgstr "" -#: judge/utils/problem_data.py:78 judge/utils/problem_data.py:99 +#: judge/utils/problem_data.py:76 judge/utils/problem_data.py:97 msgid "How did you corrupt the custom checker path?" msgstr "" -#: judge/utils/problem_data.py:120 +#: judge/utils/problem_data.py:118 #, python-format msgid "Points must be defined for non-batch case #%d." msgstr "" -#: judge/utils/problem_data.py:125 +#: judge/utils/problem_data.py:123 #, python-format msgid "Input file for case %d does not exist: %s" msgstr "" -#: judge/utils/problem_data.py:128 +#: judge/utils/problem_data.py:126 #, python-format msgid "Output file for case %d does not exist: %s" msgstr "" -#: judge/utils/problem_data.py:153 +#: judge/utils/problem_data.py:151 #, python-format msgid "Batch start case #%d requires points." msgstr "" -#: judge/utils/problem_data.py:174 +#: judge/utils/problem_data.py:172 #, python-format msgid "Attempt to end batch outside of one in case #%d" msgstr "" -#: judge/utils/problem_data.py:192 +#: judge/utils/problem_data.py:190 msgid "How did you corrupt the zip path?" msgstr "" -#: judge/utils/problem_data.py:198 +#: judge/utils/problem_data.py:196 msgid "How did you corrupt the generator path?" msgstr "" -#: judge/utils/problems.py:80 +#: judge/utils/problems.py:78 msgid "Wrong" msgstr "" -#: judge/utils/problems.py:82 +#: judge/utils/problems.py:80 msgid "Timeout" msgstr "" -#: judge/utils/problems.py:83 +#: judge/utils/problems.py:81 msgid "Error" msgstr "" -#: judge/utils/problems.py:94 +#: judge/utils/problems.py:92 msgid "Can't pass both queryset and keyword filters" msgstr "" @@ -2319,8 +2218,7 @@ msgctxt "hours and minutes" msgid "%h:%m" msgstr "" -#: judge/views/about.py:7 templates/organization/home.html:112 -#: templates/user/user-about.html:83 templates/user/user-tabs.html:4 +#: judge/views/about.py:7 templates/user/user-about.html:33 msgid "About" msgstr "" @@ -2328,165 +2226,156 @@ msgstr "" msgid "Custom Checker Sample" msgstr "" -#: judge/views/blog.py:45 +#: judge/views/blog.py:38 #, python-format msgid "Page %d of Posts" msgstr "" -#: judge/views/comment.py:28 +#: judge/views/comment.py:27 msgid "Messing around, are we?" msgstr "" -#: judge/views/comment.py:37 +#: judge/views/comment.py:36 msgid "You must solve at least one problem before you can vote." msgstr "" -#: judge/views/comment.py:64 +#: judge/views/comment.py:63 msgid "You already voted." msgstr "" -#: judge/views/comment.py:126 judge/views/organization.py:344 +#: judge/views/comment.py:120 judge/views/organization.py:299 msgid "Edited from site" msgstr "" -#: judge/views/comment.py:147 +#: judge/views/comment.py:141 msgid "Editing comment" msgstr "" -#: judge/views/contests.py:57 judge/views/contests.py:247 -#: judge/views/contests.py:250 judge/views/contests.py:424 +#: judge/views/contests.py:55 judge/views/contests.py:215 +#: judge/views/contests.py:218 judge/views/contests.py:389 msgid "No such contest" msgstr "" -#: judge/views/contests.py:58 judge/views/contests.py:248 +#: judge/views/contests.py:56 judge/views/contests.py:216 #, python-format msgid "Could not find a contest with the key \"%s\"." msgstr "" -#: judge/views/contests.py:71 +#: judge/views/contests.py:81 msgid "Contests" msgstr "" -#: judge/views/contests.py:251 +#: judge/views/contests.py:219 msgid "Could not find such contest." msgstr "" -#: judge/views/contests.py:254 +#: judge/views/contests.py:222 #, python-format msgid "Access to contest \"%s\" denied" msgstr "" -#: judge/views/contests.py:278 +#: judge/views/contests.py:246 msgid "Clone Contest" msgstr "" -#: judge/views/contests.py:343 +#: judge/views/contests.py:309 msgid "Contest not ongoing" msgstr "" -#: judge/views/contests.py:344 +#: judge/views/contests.py:310 #, python-format msgid "\"%s\" is not currently ongoing." msgstr "" -#: judge/views/contests.py:348 +#: judge/views/contests.py:314 msgid "Already in contest" msgstr "" -#: judge/views/contests.py:349 +#: judge/views/contests.py:315 #, python-format msgid "You are already in a contest: \"%s\"." msgstr "" -#: judge/views/contests.py:352 +#: judge/views/contests.py:318 msgid "Banned from joining" msgstr "" -#: judge/views/contests.py:353 +#: judge/views/contests.py:319 msgid "" "You have been declared persona non grata for this contest. You are " "permanently barred from joining this contest." msgstr "" -#: judge/views/contests.py:414 +#: judge/views/contests.py:379 #, python-format msgid "Enter access code for \"%s\"" msgstr "" -#: judge/views/contests.py:425 +#: judge/views/contests.py:390 #, python-format msgid "You are not in contest \"%s\"." msgstr "" -#: judge/views/contests.py:444 +#: judge/views/contests.py:409 msgid "ContestCalendar requires integer year and month" msgstr "" -#: judge/views/contests.py:484 +#: judge/views/contests.py:449 #, python-format msgid "Contests in %(month)s" msgstr "" -#: judge/views/contests.py:484 +#: judge/views/contests.py:449 msgid "F Y" msgstr "" -#: judge/views/contests.py:532 +#: judge/views/contests.py:496 #, python-format msgid "%s Statistics" msgstr "" -#: judge/views/contests.py:717 +#: judge/views/contests.py:601 +msgid "???" +msgstr "" + +#: judge/views/contests.py:664 #, python-format msgid "%s Rankings" msgstr "" -#: judge/views/contests.py:725 -msgid "???" -msgstr "" - -#: judge/views/contests.py:741 +#: judge/views/contests.py:680 #, python-format msgid "Your participation in %s" msgstr "" -#: judge/views/contests.py:742 +#: judge/views/contests.py:681 #, python-format msgid "%s's participation in %s" msgstr "" -#: judge/views/contests.py:749 +#: judge/views/contests.py:685 msgid "Live" msgstr "" -#: judge/views/contests.py:761 templates/contest/contest-tabs.html:13 +#: judge/views/contests.py:697 msgid "Participation" msgstr "" -#: judge/views/contests.py:808 +#: judge/views/contests.py:743 #, python-format msgid "%s MOSS Results" msgstr "" -#: judge/views/contests.py:835 +#: judge/views/contests.py:770 #, python-format msgid "Running MOSS for %s..." msgstr "" -#: judge/views/contests.py:858 +#: judge/views/contests.py:793 #, python-format msgid "Contest tag: %s" msgstr "" -#: judge/views/contests.py:868 judge/views/ticket.py:57 -msgid "Issue description" -msgstr "" - -#: judge/views/contests.py:911 -#, python-format -msgid "New clarification for %s" -msgstr "" - #: judge/views/error.py:14 msgid "404 error" msgstr "" @@ -2507,122 +2396,115 @@ msgid "corrupt page %s" msgstr "" #: judge/views/language.py:12 templates/status/judge-status-table.html:9 -#: templates/status/status-tabs.html:5 msgid "Runtimes" msgstr "" -#: judge/views/notification.py:40 -#, python-format -msgid "Notifications (%d unseen)" -msgstr "" - -#: judge/views/organization.py:59 judge/views/organization.py:62 +#: judge/views/organization.py:44 judge/views/organization.py:47 msgid "No such organization" msgstr "" -#: judge/views/organization.py:60 +#: judge/views/organization.py:45 #, python-format msgid "Could not find an organization with the key \"%s\"." msgstr "" -#: judge/views/organization.py:63 +#: judge/views/organization.py:48 msgid "Could not find such organization." msgstr "" -#: judge/views/organization.py:79 judge/views/register.py:34 -#: templates/organization/list.html:32 templates/user/import/table_csv.html:9 -#: templates/user/user-list-tabs.html:6 +#: judge/views/organization.py:72 judge/views/register.py:34 +#: templates/organization/list.html:15 msgid "Organizations" msgstr "" -#: judge/views/organization.py:130 +#: judge/views/organization.py:93 #, python-format msgid "%s Members" msgstr "" -#: judge/views/organization.py:159 judge/views/organization.py:162 -#: judge/views/organization.py:167 +#: judge/views/organization.py:118 judge/views/organization.py:121 +#: judge/views/organization.py:126 msgid "Joining organization" msgstr "" -#: judge/views/organization.py:159 +#: judge/views/organization.py:118 msgid "You are already in the organization." msgstr "" -#: judge/views/organization.py:162 +#: judge/views/organization.py:121 msgid "This organization is not open." msgstr "" -#: judge/views/organization.py:179 +#: judge/views/organization.py:138 msgid "Leaving organization" msgstr "" -#: judge/views/organization.py:179 +#: judge/views/organization.py:138 #, python-format msgid "You are not in \"%s\"." msgstr "" -#: judge/views/organization.py:203 +#: judge/views/organization.py:162 #, python-format msgid "Request to join %s" msgstr "" -#: judge/views/organization.py:221 +#: judge/views/organization.py:180 msgid "Join request detail" msgstr "" -#: judge/views/organization.py:254 +#: judge/views/organization.py:209 #, python-format msgid "Managing join requests for %s" msgstr "" -#: judge/views/organization.py:285 +#: judge/views/organization.py:240 #, python-format msgid "" "Your organization can only receive %d more members. You cannot approve %d " "users." msgstr "" -#: judge/views/organization.py:297 +#: judge/views/organization.py:252 #, python-format msgid "Approved %d user." msgid_plural "Approved %d users." msgstr[0] "" msgstr[1] "" -#: judge/views/organization.py:298 +#: judge/views/organization.py:253 #, python-format msgid "Rejected %d user." msgid_plural "Rejected %d users." msgstr[0] "" msgstr[1] "" -#: judge/views/organization.py:328 +#: judge/views/organization.py:283 #, python-format msgid "Editing %s" msgstr "" -#: judge/views/organization.py:352 judge/views/organization.py:360 +#: judge/views/organization.py:307 judge/views/organization.py:315 msgid "Can't edit organization" msgstr "" -#: judge/views/organization.py:353 +#: judge/views/organization.py:308 msgid "You are not allowed to edit this organization." msgstr "" -#: judge/views/organization.py:361 +#: judge/views/organization.py:316 msgid "You are not allowed to kick people from this organization." msgstr "" -#: judge/views/organization.py:366 judge/views/organization.py:370 +#: judge/views/organization.py:321 judge/views/organization.py:325 msgid "Can't kick user" msgstr "" -#: judge/views/organization.py:367 +#: judge/views/organization.py:322 msgid "The user you are trying to kick does not exist!" msgstr "" -#: judge/views/organization.py:371 +#: judge/views/organization.py:326 #, python-format msgid "The user you are trying to kick is not in organization: %s." msgstr "" @@ -2646,36 +2528,35 @@ msgstr "" msgid "Editorial for {0}" msgstr "" -#: judge/views/problem.py:285 templates/contest/contest.html:79 -#: templates/user/user-about.html:28 templates/user/user-tabs.html:5 -#: templates/user/users-table.html:31 +#: judge/views/problem.py:286 templates/contest/contest.html:79 +#: templates/user/users-table.html:23 msgid "Problems" msgstr "" -#: judge/views/problem.py:585 +#: judge/views/problem.py:547 msgid "Banned from submitting" msgstr "" -#: judge/views/problem.py:586 +#: judge/views/problem.py:548 msgid "" "You have been declared persona non grata for this problem. You are " "permanently barred from submitting this problem." msgstr "" -#: judge/views/problem.py:600 +#: judge/views/problem.py:562 msgid "Too many submissions" msgstr "" -#: judge/views/problem.py:601 +#: judge/views/problem.py:563 msgid "You have exceeded the submission limit for this problem." msgstr "" -#: judge/views/problem.py:661 judge/views/problem.py:664 +#: judge/views/problem.py:633 judge/views/problem.py:636 #, python-format msgid "Submit to %(problem)s" msgstr "" -#: judge/views/problem.py:679 +#: judge/views/problem.py:652 msgid "Clone Problem" msgstr "" @@ -2716,22 +2597,22 @@ msgstr "" msgid "Generated init.yml for %s" msgstr "" -#: judge/views/problem_manage.py:52 judge/views/problem_manage.py:55 +#: judge/views/problem_manage.py:50 judge/views/problem_manage.py:53 #, python-format msgid "Managing submissions for %s" msgstr "" -#: judge/views/problem_manage.py:97 +#: judge/views/problem_manage.py:95 #, python-format msgid "Rejudging selected submissions for %s..." msgstr "" -#: judge/views/problem_manage.py:141 +#: judge/views/problem_manage.py:110 #, python-format msgid "Rescoring all submissions for %s..." msgstr "" -#: judge/views/problem_manage.py:150 +#: judge/views/problem_manage.py:119 #, python-format msgid "Successfully scheduled %d submission for rejudging." msgid_plural "Successfully scheduled %d submissions for rejudging." @@ -2780,24 +2661,24 @@ msgstr "" msgid "Subscribe to newsletter?" msgstr "" -#: judge/views/register.py:55 +#: judge/views/register.py:45 #, python-format msgid "" "The email address \"%s\" is already taken. Only one registration is allowed " "per address." msgstr "" -#: judge/views/register.py:61 +#: judge/views/register.py:51 msgid "" "Your email provider is not allowed due to history of abuse. Please use a " "reputable email provider." msgstr "" -#: judge/views/register.py:67 judge/views/register.py:105 +#: judge/views/register.py:57 judge/views/register.py:95 msgid "Registration" msgstr "" -#: judge/views/register.py:116 +#: judge/views/register.py:106 msgid "Authentication failure" msgstr "" @@ -2813,100 +2694,104 @@ msgstr "" msgid "Version matrix" msgstr "" -#: judge/views/submission.py:84 judge/views/submission.py:91 +#: judge/views/submission.py:83 judge/views/submission.py:90 #, python-format msgid "Submission of %(problem)s by %(user)s" msgstr "" -#: judge/views/submission.py:244 judge/views/submission.py:245 -#: templates/problem/problem.html:167 +#: judge/views/submission.py:227 judge/views/submission.py:228 +#: templates/problem/problem.html:127 msgid "All submissions" msgstr "" -#: judge/views/submission.py:404 +#: judge/views/submission.py:384 msgid "All my submissions" msgstr "" -#: judge/views/submission.py:405 +#: judge/views/submission.py:385 #, python-format msgid "All submissions by %s" msgstr "" -#: judge/views/submission.py:436 +#: judge/views/submission.py:416 #, python-format msgid "All submissions for %s" msgstr "" -#: judge/views/submission.py:455 +#: judge/views/submission.py:435 msgid "Must pass a problem" msgstr "" -#: judge/views/submission.py:501 +#: judge/views/submission.py:481 #, python-format msgid "My submissions for %(problem)s" msgstr "" -#: judge/views/submission.py:502 +#: judge/views/submission.py:482 #, python-format msgid "%(user)s's submissions for %(problem)s" msgstr "" -#: judge/views/submission.py:603 +#: judge/views/submission.py:583 msgid "Must pass a contest" msgstr "" -#: judge/views/submission.py:622 +#: judge/views/submission.py:602 #, python-brace-format msgid "" "{0}'s submissions for {2} in {4}" msgstr "" -#: judge/views/submission.py:629 +#: judge/views/submission.py:609 #, python-brace-format msgid "" "{0}'s submissions for problem {2} in {3}" "" msgstr "" -#: judge/views/ticket.py:50 judge/views/ticket.py:56 +#: judge/views/ticket.py:33 judge/views/ticket.py:39 msgid "Ticket title" msgstr "" -#: judge/views/ticket.py:107 judge/views/ticket.py:110 +#: judge/views/ticket.py:40 +msgid "Issue description" +msgstr "" + +#: judge/views/ticket.py:85 judge/views/ticket.py:88 #, python-format msgid "New ticket for %s" msgstr "" -#: judge/views/ticket.py:170 +#: judge/views/ticket.py:142 #, python-format msgid "%(title)s - Ticket %(id)d" msgstr "" -#: judge/views/ticket.py:279 +#: judge/views/ticket.py:251 #, python-format msgid "Tickets - Page %(number)d of %(total)d" msgstr "" -#: judge/views/ticket.py:328 +#: judge/views/ticket.py:300 #, python-format msgid "New Ticket: %s" msgstr "" -#: judge/views/ticket.py:329 +#: judge/views/ticket.py:301 #, python-format msgid "#%(id)d, assigned to: %(users)s" msgstr "" -#: judge/views/ticket.py:331 +#: judge/views/ticket.py:303 msgid ", " msgstr "" -#: judge/views/ticket.py:331 +#: judge/views/ticket.py:303 msgid "no one" msgstr "" -#: judge/views/ticket.py:351 +#: judge/views/ticket.py:323 #, python-format msgid "New Ticket Message For: %s" msgstr "" @@ -2923,50 +2808,41 @@ msgstr "" msgid "Perform Two Factor Authentication" msgstr "" -#: judge/views/user.py:74 +#: judge/views/user.py:68 msgid "No such user" msgstr "" -#: judge/views/user.py:74 +#: judge/views/user.py:68 #, python-format msgid "No user handle \"%s\"." msgstr "" -#: judge/views/user.py:78 +#: judge/views/user.py:72 msgid "My account" msgstr "" -#: judge/views/user.py:79 +#: judge/views/user.py:73 #, python-format msgid "User %s" msgstr "" -#: judge/views/user.py:148 -msgid "M j, Y" -msgstr "" - -#: judge/views/user.py:171 +#: judge/views/user.py:136 msgid "M j, Y, G:i" msgstr "" -#: judge/views/user.py:290 +#: judge/views/user.py:221 msgid "Updated on site" msgstr "" -#: judge/views/user.py:323 templates/admin/auth/user/change_form.html:14 -#: templates/admin/auth/user/change_form.html:17 templates/base.html:238 -#: templates/user/user-tabs.html:10 +#: judge/views/user.py:254 templates/admin/auth/user/change_form.html:14 +#: templates/admin/auth/user/change_form.html:17 templates/base.html:224 msgid "Edit profile" msgstr "" -#: judge/views/user.py:332 templates/user/user-list-tabs.html:4 +#: judge/views/user.py:263 msgid "Leaderboard" msgstr "" -#: judge/views/user.py:407 -msgid "Import Users" -msgstr "" - #: judge/views/widgets.py:48 judge/views/widgets.py:58 #, python-format msgid "Invalid upstream data: %s" @@ -3004,7 +2880,7 @@ msgid "View Submissions" msgstr "" #: templates/admin/judge/problem/change_form.html:17 -#: templates/user/user-base.html:112 +#: templates/user/user-base.html:61 msgid "View submissions" msgstr "" @@ -3019,147 +2895,90 @@ msgstr "" msgid "Rejudge" msgstr "" -#: templates/base.html:230 -#, python-format -msgid "Hello, %(username)s." -msgstr "" - -#: templates/base.html:236 templates/comments/list.html:89 -#: templates/contest/contest-list-tabs.html:24 -#: templates/contest/ranking-table.html:53 -#: templates/problem/problem-list-tabs.html:6 +#: templates/base.html:222 templates/comments/list.html:89 +#: templates/contest/ranking-table.html:39 #: templates/submission/info-base.html:12 -#: templates/submission/submission-list-tabs.html:15 msgid "Admin" msgstr "" -#: templates/base.html:245 +#: templates/base.html:231 msgid "Log out" msgstr "" -#: templates/base.html:254 +#: templates/base.html:240 #: templates/registration/password_reset_complete.html:4 msgid "Log in" msgstr "" -#: templates/base.html:255 templates/registration/registration_form.html:177 +#: templates/base.html:241 templates/registration/registration_form.html:177 msgid "or" msgstr "" -#: templates/base.html:256 +#: templates/base.html:242 msgid "Sign up" msgstr "" -#: templates/base.html:271 +#: templates/base.html:254 msgid "spectating" msgstr "" -#: templates/base.html:284 +#: templates/base.html:267 msgid "This site works best with JavaScript enabled." msgstr "" -#: templates/blog/blog.html:13 templates/comments/list.html:68 -#: templates/comments/list.html:83 templates/contest/contest-tabs.html:23 -#: templates/contest/tag-title.html:9 templates/flatpages/admin_link.html:3 -#: templates/license.html:10 templates/problem/editorial.html:14 +#: templates/blog/content.html:13 templates/comments/list.html:68 +#: templates/comments/list.html:83 templates/contest/tag-title.html:9 +#: templates/flatpages/admin_link.html:3 templates/license.html:10 +#: templates/problem/editorial.html:14 msgid "Edit" msgstr "" -#: templates/blog/blog.html:26 -#, python-format -msgid "" -"\n" -" posted on %(time)s\n" -" " -msgstr "" - -#: templates/blog/content.html:10 -#, python-brace-format -msgid "posted on {time}" -msgstr "" - -#: templates/blog/dashboard.html:21 -#, python-format -msgid "" -"\n" -" on %(time)s\n" -" " -msgstr "" - -#: templates/blog/list.html:93 +#: templates/blog/list.html:85 msgid "Blog" msgstr "" -#: templates/blog/list.html:95 +#: templates/blog/list.html:87 msgid "Events" msgstr "" -#: templates/blog/list.html:100 +#: templates/blog/list.html:92 msgid "News" msgstr "" -#: templates/blog/list.html:115 templates/problem/list.html:347 -#: templates/problem/problem.html:361 +#: templates/blog/list.html:130 templates/problem/problem.html:310 msgid "Clarifications" msgstr "" -#: templates/blog/list.html:121 -msgid "Add" -msgstr "" - -#: templates/blog/list.html:140 templates/problem/list.html:369 -#: templates/problem/problem.html:372 +#: templates/blog/list.html:146 templates/problem/problem.html:321 msgid "No clarifications have been made at this time." msgstr "" -#: templates/blog/list.html:148 +#: templates/blog/list.html:154 msgid "Ongoing contests" msgstr "" -#: templates/blog/list.html:166 +#: templates/blog/list.html:172 msgid "Upcoming contests" msgstr "" -#: templates/blog/list.html:184 -msgid "My open tickets" -msgstr "" - -#: templates/blog/list.html:206 -msgid "New tickets" -msgstr "" - -#: templates/blog/list.html:227 -msgid "New problems" -msgstr "" - -#: templates/blog/list.html:244 +#: templates/blog/list.html:189 msgid "Comment stream" msgstr "" -#: templates/chat/chat.html:305 -msgid "Chat" +#: templates/blog/list.html:208 +msgid "New problems" msgstr "" -#: templates/chat/chat.html:307 templates/chat/chat.html:314 -#, fuzzy -#| msgid "Online" -msgid "Online Users" -msgstr "Online" - -#: templates/chat/chat.html:315 -msgid "Refresh" +#: templates/blog/list.html:225 +msgid "My open tickets" msgstr "" -#: templates/chat/chat.html:333 -msgid "Emoji" +#: templates/blog/list.html:246 +msgid "New tickets" msgstr "" -#: templates/chat/chat.html:334 -msgid "Enter your message" -msgstr "" - -#: templates/chat/message.html:20 -msgid "Delete" +#: templates/chat/chat.html:167 +msgid "Your message" msgstr "" #: templates/comments/list.html:2 @@ -3170,21 +2989,11 @@ msgstr "" msgid "Please login to vote" msgstr "" -#: templates/comments/list.html:40 -#, python-brace-format -msgid "commented on {time}" -msgstr "" - -#: templates/comments/list.html:49 -#, python-format -msgid "edit %(edits)s" -msgstr "" - -#: templates/comments/list.html:51 templates/comments/media-js.html:92 +#: templates/comments/list.html:51 templates/comments/media-js.html:77 msgid "edited" msgstr "" -#: templates/comments/list.html:60 templates/notification/list.html:14 +#: templates/comments/list.html:60 msgid "Link" msgstr "" @@ -3192,52 +3001,36 @@ msgstr "" msgid "Reply" msgstr "" -#: templates/comments/list.html:86 templates/contest/list.html:91 -#: templates/contest/list.html:95 templates/contest/list.html:280 +#: templates/comments/list.html:86 msgid "Hide" msgstr "" -#: templates/comments/list.html:101 -#, python-format -msgid "" -"\n" -" This comment is hidden due " -"to too much negative feedback.\n" -" Click here to view it.\n" -" " -msgstr "" - -#: templates/comments/list.html:121 +#: templates/comments/list.html:120 msgid "There are no comments at the moment." msgstr "" -#: templates/comments/list.html:127 +#: templates/comments/list.html:126 msgid "New comment" msgstr "" -#: templates/comments/list.html:141 +#: templates/comments/list.html:140 msgid "Invalid comment body." msgstr "" -#: templates/comments/list.html:149 +#: templates/comments/list.html:148 msgid "Post!" msgstr "" -#: templates/comments/list.html:157 +#: templates/comments/list.html:156 msgid "Comments are disabled on this page." msgstr "" -#: templates/comments/media-js.html:38 -msgid "Replying to comment" -msgstr "" - -#: templates/comments/media-js.html:87 +#: templates/comments/media-js.html:72 #, python-brace-format msgid "edit {edits}" msgstr "" -#: templates/comments/media-js.html:90 +#: templates/comments/media-js.html:75 msgid "original" msgstr "" @@ -3281,11 +3074,6 @@ msgstr "" msgid "Saturday" msgstr "" -#: templates/contest/clarification.html:52 templates/organization/new.html:10 -#: templates/ticket/new.html:38 -msgid "Create" -msgstr "" - #: templates/contest/clone.html:37 msgid "Enter a new key for the cloned contest:" msgstr "" @@ -3306,171 +3094,97 @@ msgstr "" msgid "Next" msgstr "" -#: templates/contest/contest-list-tabs.html:21 -#: templates/problem/problem-list-tabs.html:5 -msgid "List" -msgstr "" - -#: templates/contest/contest-list-tabs.html:22 -msgid "Calendar" -msgstr "" - -#: templates/contest/contest-tabs.html:4 templates/organization/home.html:105 -msgid "Info" -msgstr "" - -#: templates/contest/contest-tabs.html:6 templates/stats/base.html:9 -#: templates/submission/list.html:339 -msgid "Statistics" -msgstr "" - -#: templates/contest/contest-tabs.html:11 -msgid "Rankings" -msgstr "" - -#: templates/contest/contest-tabs.html:16 -msgid "Hidden Rankings" -msgstr "" - -#: templates/contest/contest-tabs.html:21 -msgid "MOSS" -msgstr "" - -#: templates/contest/contest-tabs.html:26 -msgid "Clone" -msgstr "" - -#: templates/contest/contest-tabs.html:38 -#: templates/contest/contest-tabs.html:58 +#: templates/contest/contest-tabs.html:37 msgid "Leave contest" msgstr "" -#: templates/contest/contest-tabs.html:45 templates/contest/list.html:388 +#: templates/contest/contest-tabs.html:44 templates/contest/list.html:293 msgid "Virtual join" msgstr "" -#: templates/contest/contest-tabs.html:56 -msgid "Stop spectating" -msgstr "" - -#: templates/contest/contest-tabs.html:65 +#: templates/contest/contest-tabs.html:64 msgid "Spectate contest" msgstr "" -#: templates/contest/contest-tabs.html:72 +#: templates/contest/contest-tabs.html:70 +#: templates/contest/contest-tabs.html:76 msgid "Join contest" msgstr "" -#: templates/contest/contest-tabs.html:81 +#: templates/contest/contest-tabs.html:85 msgid "Login to participate" msgstr "" -#: templates/contest/contest.html:37 -msgid "Participating virtually." -msgstr "" - -#: templates/contest/contest.html:43 -msgid "Contest is over." -msgstr "" - #: templates/contest/contest.html:59 templates/contest/contest.html:63 msgid "F j, Y, G:i T" msgstr "" -#: templates/contest/contest.html:59 -#, python-format -msgid "" -"%(time_limit)s window between %(start_time)s and " -"%(end_time)s" -msgstr "" - -#: templates/contest/contest.html:63 -#, python-format -msgid "%(length)s long starting on %(start_time)s" -msgstr "" - #: templates/contest/contest.html:85 msgid "AC Rate" msgstr "" -#: templates/contest/contest.html:86 templates/contest/list.html:237 -#: templates/contest/list.html:289 templates/contest/list.html:366 -#: templates/problem/list.html:223 templates/problem/list.html:254 +#: templates/contest/contest.html:86 templates/contest/list.html:153 +#: templates/contest/list.html:195 templates/contest/list.html:271 +#: templates/problem/list.html:212 templates/problem/list.html:238 msgid "Users" msgstr "" -#: templates/contest/contest.html:111 templates/problem/list.html:330 +#: templates/contest/contest.html:111 msgid "Editorial" msgstr "" -#: templates/contest/list.html:83 templates/contest/media-js.html:9 +#: templates/contest/list.html:31 templates/contest/media-js.html:9 msgid "Are you sure you want to join?" msgstr "" -#: templates/contest/list.html:84 +#: templates/contest/list.html:32 msgid "" "Joining a contest for the first time starts your timer, after which it " "becomes unstoppable." msgstr "" -#: templates/contest/list.html:92 templates/contest/list.html:278 -msgid "Show" -msgstr "" - -#: templates/contest/list.html:102 templates/problem/list.html:68 -msgid "Organizations..." -msgstr "" - -#: templates/contest/list.html:135 +#: templates/contest/list.html:65 msgid "hidden" msgstr "" -#: templates/contest/list.html:140 +#: templates/contest/list.html:70 msgid "private" msgstr "" -#: templates/contest/list.html:154 +#: templates/contest/list.html:84 msgid "rated" msgstr "" -#: templates/contest/list.html:202 +#: templates/contest/list.html:132 msgid "Spectate" msgstr "" -#: templates/contest/list.html:208 +#: templates/contest/list.html:138 msgid "Join" msgstr "" -#: templates/contest/list.html:220 -msgid "Search contests..." -msgstr "" - -#: templates/contest/list.html:229 -msgid "Search" -msgstr "" - -#: templates/contest/list.html:232 +#: templates/contest/list.html:148 msgid "Active Contests" msgstr "" -#: templates/contest/list.html:236 templates/contest/list.html:288 -#: templates/contest/list.html:327 templates/contest/list.html:365 +#: templates/contest/list.html:152 templates/contest/list.html:194 +#: templates/contest/list.html:232 templates/contest/list.html:270 msgid "Contest" msgstr "" -#: templates/contest/list.html:275 +#: templates/contest/list.html:190 msgid "Ongoing Contests" msgstr "" -#: templates/contest/list.html:322 +#: templates/contest/list.html:227 msgid "Upcoming Contests" msgstr "" -#: templates/contest/list.html:350 +#: templates/contest/list.html:255 msgid "There are no scheduled contests at this time." msgstr "" -#: templates/contest/list.html:356 +#: templates/contest/list.html:261 msgid "Past Contests" msgstr "" @@ -3521,71 +3235,47 @@ msgstr "" msgid "Only the following organizations may access this contest:" msgstr "" -#: templates/contest/ranking-table.html:9 templates/problem/search-form.html:35 +#: templates/contest/ranking-table.html:7 msgid "Organization" msgstr "" -#: templates/contest/ranking-table.html:10 templates/user/users-table.html:13 -msgid "Full Name" -msgstr "" - -#: templates/contest/ranking-table.html:44 +#: templates/contest/ranking-table.html:30 msgid "Un-Disqualify" msgstr "" -#: templates/contest/ranking-table.html:47 +#: templates/contest/ranking-table.html:33 msgid "Disqualify" msgstr "" -#: templates/contest/ranking.html:187 +#: templates/contest/ranking.html:173 msgid "Are you sure you want to disqualify this participation?" msgstr "" -#: templates/contest/ranking.html:192 +#: templates/contest/ranking.html:178 msgid "Are you sure you want to un-disqualify this participation?" msgstr "" -#: templates/contest/ranking.html:463 +#: templates/contest/ranking.html:252 msgid "View user participation" msgstr "" -#: templates/contest/ranking.html:467 +#: templates/contest/ranking.html:256 msgid "Show organizations" msgstr "" -#: templates/contest/ranking.html:471 -msgid "Show full name" -msgstr "" - -#: templates/contest/ranking.html:474 -msgid "Show friends only" -msgstr "" - -#: templates/contest/ranking.html:477 -msgid "Total score only" -msgstr "" - -#: templates/contest/ranking.html:479 -msgid "Show virtual participation" -msgstr "" - -#: templates/contest/stats.html:51 +#: templates/contest/stats.html:38 msgid "Problem Status Distribution" msgstr "" -#: templates/contest/stats.html:56 +#: templates/contest/stats.html:43 msgid "Problem AC Rate" msgstr "" -#: templates/contest/stats.html:62 -msgid "Problem Point Distribution" -msgstr "" - -#: templates/contest/stats.html:76 templates/stats/language.html:16 +#: templates/contest/stats.html:48 templates/stats/language.html:16 msgid "Submissions by Language" msgstr "" -#: templates/contest/stats.html:82 templates/stats/language.html:26 +#: templates/contest/stats.html:54 templates/stats/language.html:26 msgid "Language AC Rate" msgstr "" @@ -3594,7 +3284,6 @@ msgid "Source:" msgstr "" #: templates/newsletter/common.html:6 -#: templates/newsletter/newsletter_list.html:15 #: templates/newsletter/subscription_unsubscribe_activated.html:3 #: templates/newsletter/subscription_unsubscribe_activated.html:6 #: templates/newsletter/subscription_update_activated.html:3 @@ -3602,23 +3291,6 @@ msgstr "" msgid "Newsletter" msgstr "" -#: templates/newsletter/newsletter_list.html:2 -#: templates/newsletter/newsletter_list.html:3 -msgid "Newsletter list" -msgstr "" - -#: templates/newsletter/newsletter_list.html:6 -msgid "Subscribe to get the latest emails about upcoming contests and events." -msgstr "" - -#: templates/newsletter/newsletter_list.html:16 -msgid "Subscribe" -msgstr "" - -#: templates/newsletter/newsletter_list.html:30 -msgid "Update subscriptions" -msgstr "" - #: templates/newsletter/subscription_unsubscribe_activated.html:3 #: templates/newsletter/subscription_unsubscribe_activated.html:6 #: templates/newsletter/subscription_update_activated.html:3 @@ -3680,97 +3352,64 @@ msgid "" "follow in order to update your subscription." msgstr "" -#: templates/notification/list.html:7 -msgid "You have no notifications" -msgstr "" - -#: templates/notification/list.html:13 -msgid "Activity" -msgstr "" - #: templates/organization/edit.html:46 #: templates/organization/requests/pending.html:34 #: templates/ticket/edit-notes.html:4 msgid "Update" msgstr "" -#: templates/organization/home.html:41 +#: templates/organization/home.html:7 msgid "Are you sure you want to leave this organization?" msgstr "" -#: templates/organization/home.html:43 +#: templates/organization/home.html:9 msgid "You will have to rejoin to show up on the organization leaderboard." msgstr "" -#: templates/organization/home.html:45 +#: templates/organization/home.html:11 msgid "You will have to request membership in order to join again." msgstr "" -#: templates/organization/home.html:88 -msgid "Join organization" -msgstr "" - -#: templates/organization/home.html:92 -msgid "Request membership" -msgstr "" - -#: templates/organization/home.html:122 -msgid "Organization news" -msgstr "" - -#: templates/organization/home.html:128 -msgid "There is no news at this time." -msgstr "" - -#: templates/organization/home.html:137 -msgid "Controls" -msgstr "" - -#: templates/organization/home.html:142 -msgid "Edit organization" -msgstr "" - -#: templates/organization/home.html:148 -msgid "View requests" -msgstr "" - -#: templates/organization/home.html:161 -msgid "Admin organization" -msgstr "" - -#: templates/organization/home.html:167 -msgid "View members" -msgstr "" - -#: templates/organization/home.html:174 +#: templates/organization/home.html:24 msgid "Leave organization" msgstr "" -#: templates/organization/home.html:183 -msgid "New private contests" +#: templates/organization/home.html:29 +msgid "Join organization" msgstr "" -#: templates/organization/home.html:193 templates/organization/home.html:208 -msgid "View all" +#: templates/organization/home.html:33 +msgid "Request membership" msgstr "" -#: templates/organization/home.html:199 -msgid "New private problems" +#: templates/organization/home.html:39 +msgid "Edit organization" msgstr "" -#: templates/organization/list.html:40 -msgid "Show my organizations only" +#: templates/organization/home.html:43 +msgid "View requests" msgstr "" -#: templates/organization/list.html:47 templates/status/language-list.html:34 -#: templates/user/import/table_csv.html:6 +#: templates/organization/home.html:50 +msgid "Admin organization" +msgstr "" + +#: templates/organization/home.html:55 +msgid "View members" +msgstr "" + +#: templates/organization/list.html:23 templates/status/language-list.html:34 msgid "Name" msgstr "" -#: templates/organization/list.html:48 +#: templates/organization/list.html:24 msgid "Members" msgstr "" +#: templates/organization/new.html:10 templates/ticket/new.html:38 +msgid "Create" +msgstr "" + #: templates/organization/requests/detail.html:13 msgid "User:" msgstr "" @@ -3803,7 +3442,7 @@ msgid "There are no requests to approve." msgstr "" #: templates/organization/requests/pending.html:17 -#: templates/problem/data.html:432 +#: templates/problem/data.html:452 msgid "Delete?" msgstr "" @@ -3839,35 +3478,35 @@ msgstr "" msgid "Enter a new code for the cloned problem:" msgstr "" -#: templates/problem/data.html:119 +#: templates/problem/data.html:108 msgid "Instruction" msgstr "" -#: templates/problem/data.html:390 +#: templates/problem/data.html:410 msgid "View YAML" msgstr "" -#: templates/problem/data.html:421 templates/problem/data.html:472 +#: templates/problem/data.html:441 templates/problem/data.html:491 msgid "Apply!" msgstr "" -#: templates/problem/data.html:426 +#: templates/problem/data.html:446 msgid "Type" msgstr "" -#: templates/problem/data.html:427 +#: templates/problem/data.html:447 msgid "Input file" msgstr "" -#: templates/problem/data.html:428 +#: templates/problem/data.html:448 msgid "Output file" msgstr "" -#: templates/problem/data.html:430 +#: templates/problem/data.html:450 msgid "Pretest?" msgstr "" -#: templates/problem/data.html:473 +#: templates/problem/data.html:492 msgid "Add new case" msgstr "" @@ -3879,32 +3518,28 @@ msgid "" "problem yourself is a bannable offence." msgstr "" -#: templates/problem/list.html:66 +#: templates/problem/list.html:62 msgid "Filter by type..." msgstr "" -#: templates/problem/list.html:193 +#: templates/problem/list.html:185 msgid "Hot problems" msgstr "" -#: templates/problem/list.html:218 templates/problem/list.html:240 -#: templates/problem/search-form.html:45 templates/user/user-problems.html:57 +#: templates/problem/list.html:207 templates/problem/list.html:224 +#: templates/problem/search-form.html:30 templates/user/user-problems.html:57 msgid "Category" msgstr "" -#: templates/problem/list.html:220 templates/problem/list.html:244 +#: templates/problem/list.html:209 templates/problem/list.html:228 msgid "Types" msgstr "" -#: templates/problem/list.html:251 +#: templates/problem/list.html:235 #, python-format msgid "AC %%" msgstr "" -#: templates/problem/list.html:342 -msgid "Add clarifications" -msgstr "" - #: templates/problem/manage_submission.html:55 msgid "Leave empty to not filter by language" msgstr "" @@ -3913,201 +3548,152 @@ msgstr "" msgid "Leave empty to not filter by result" msgstr "" -#: templates/problem/manage_submission.html:80 +#: templates/problem/manage_submission.html:79 msgid "Need valid values for both start and end IDs." msgstr "" -#: templates/problem/manage_submission.html:83 +#: templates/problem/manage_submission.html:82 msgid "End ID must be after start ID." msgstr "" +#: templates/problem/manage_submission.html:90 +#, python-brace-format +msgid "" +"You are about to rejudge {count} submissions. Are you sure you want to do " +"this?" +msgstr "" + #: templates/problem/manage_submission.html:96 -#, python-brace-format msgid "" -"You are about to {action} {count} submissions. Are you sure you want to do " -"this?" +"You are about to rejudge a few submissions. Are you sure you want to do this?" msgstr "" -#: templates/problem/manage_submission.html:103 -#, python-brace-format -msgid "" -"You are about to {action} a few submissions. Are you sure you want to do " -"this?" +#: templates/problem/manage_submission.html:115 +msgid "Rejudge Submissions" msgstr "" -#: templates/problem/manage_submission.html:127 -#: templates/submission/list.html:309 -msgid "Filter submissions" -msgstr "" - -#: templates/problem/manage_submission.html:132 +#: templates/problem/manage_submission.html:120 msgid "Filter by ID:" msgstr "" -#: templates/problem/manage_submission.html:135 +#: templates/problem/manage_submission.html:123 msgid "Starting ID:" msgstr "" -#: templates/problem/manage_submission.html:139 +#: templates/problem/manage_submission.html:127 msgid "Ending ID:" msgstr "" -#: templates/problem/manage_submission.html:143 +#: templates/problem/manage_submission.html:131 msgid "This range includes both endpoints." msgstr "" -#: templates/problem/manage_submission.html:146 +#: templates/problem/manage_submission.html:134 msgid "Filter by language:" msgstr "" -#: templates/problem/manage_submission.html:154 +#: templates/problem/manage_submission.html:142 msgid "Filter by result:" msgstr "" -#: templates/problem/manage_submission.html:164 -msgid "Action" -msgstr "" - -#: templates/problem/manage_submission.html:166 +#: templates/problem/manage_submission.html:150 msgid "Rejudge selected submissions" msgstr "" -#: templates/problem/manage_submission.html:171 -msgid "Download selected submissions" +#: templates/problem/manage_submission.html:157 +msgid "Rescore Everything" msgstr "" -#: templates/problem/manage_submission.html:177 -#, python-format -msgid "Are you sure you want to rescore %(count)d submissions?" -msgstr "" - -#: templates/problem/manage_submission.html:178 +#: templates/problem/manage_submission.html:163 msgid "Rescore all submissions" msgstr "" -#: templates/problem/problem.html:132 +#: templates/problem/problem.html:91 msgid "View as PDF" msgstr "" -#: templates/problem/problem.html:141 templates/problem/problem.html:151 -#: templates/problem/problem.html:156 +#: templates/problem/problem.html:101 templates/problem/problem.html:111 +#: templates/problem/problem.html:116 msgid "Submit solution" msgstr "" -#: templates/problem/problem.html:144 -#, python-format -msgid "%(counter)s submission left" -msgid_plural "%(counter)s submissions left" -msgstr[0] "" -msgstr[1] "" - -#: templates/problem/problem.html:152 +#: templates/problem/problem.html:112 msgid "0 submissions left" msgstr "" -#: templates/problem/problem.html:164 +#: templates/problem/problem.html:124 msgid "My submissions" msgstr "" -#: templates/problem/problem.html:168 +#: templates/problem/problem.html:128 msgid "Best submissions" msgstr "" -#: templates/problem/problem.html:172 +#: templates/problem/problem.html:132 msgid "Read editorial" msgstr "" -#: templates/problem/problem.html:177 +#: templates/problem/problem.html:137 msgid "Manage tickets" msgstr "" -#: templates/problem/problem.html:181 +#: templates/problem/problem.html:141 msgid "Edit problem" msgstr "" -#: templates/problem/problem.html:183 +#: templates/problem/problem.html:143 msgid "Edit test data" msgstr "" -#: templates/problem/problem.html:188 +#: templates/problem/problem.html:148 msgid "My tickets" msgstr "" -#: templates/problem/problem.html:196 +#: templates/problem/problem.html:156 msgid "Manage submissions" msgstr "" -#: templates/problem/problem.html:202 +#: templates/problem/problem.html:162 msgid "Clone problem" msgstr "" -#: templates/problem/problem.html:209 +#: templates/problem/problem.html:169 msgid "Points:" msgstr "" -#: templates/problem/problem.html:212 templates/problem/problem.html:214 +#: templates/problem/problem.html:172 templates/problem/problem.html:174 msgid "(partial)" msgstr "" -#: templates/problem/problem.html:219 +#: templates/problem/problem.html:179 msgid "Time limit:" msgstr "" -#: templates/problem/problem.html:231 +#: templates/problem/problem.html:191 msgid "Memory limit:" msgstr "" -#: templates/problem/problem.html:250 -#, fuzzy -#| msgid "Authors" -msgid "Author:" -msgid_plural "Authors:" -msgstr[0] "Autoren" -msgstr[1] "Autoren" - -#: templates/problem/problem.html:265 -msgid "Problem type" -msgid_plural "Problem types" -msgstr[0] "" -msgstr[1] "" - -#: templates/problem/problem.html:278 +#: templates/problem/problem.html:238 msgid "Allowed languages" msgstr "" -#: templates/problem/problem.html:286 -#, python-format -msgid "No %(lang)s judge online" -msgstr "" - -#: templates/problem/problem.html:297 -msgid "Judge:" -msgid_plural "Judges:" -msgstr[0] "" -msgstr[1] "" - -#: templates/problem/problem.html:314 +#: templates/problem/problem.html:274 msgid "none available" msgstr "" -#: templates/problem/problem.html:326 -#, python-format -msgid "This problem has %(length)s clarification(s)" -msgstr "" - -#: templates/problem/problem.html:350 +#: templates/problem/problem.html:299 msgid "Request clarification" msgstr "" -#: templates/problem/problem.html:352 +#: templates/problem/problem.html:301 msgid "Report an issue" msgstr "" -#: templates/problem/raw.html:64 +#: templates/problem/raw.html:62 msgid "Time Limit:" msgstr "" -#: templates/problem/raw.html:73 +#: templates/problem/raw.html:71 msgid "Memory Limit:" msgstr "" @@ -4131,73 +3717,39 @@ msgstr "" msgid "Show problem types" msgstr "" -#: templates/problem/search-form.html:32 -msgid "Show editorial" -msgstr "" - -#: templates/problem/search-form.html:48 templates/problem/search-form.html:50 -#: templates/submission/submission-list-tabs.html:4 +#: templates/problem/search-form.html:33 templates/problem/search-form.html:35 msgid "All" msgstr "" -#: templates/problem/search-form.html:62 +#: templates/problem/search-form.html:46 msgid "Problem types" msgstr "" -#: templates/problem/search-form.html:73 +#: templates/problem/search-form.html:57 msgid "Point range" msgstr "" -#: templates/problem/search-form.html:79 templates/submission/list.html:331 +#: templates/problem/search-form.html:63 templates/submission/list.html:331 #: templates/ticket/list.html:248 msgid "Go" msgstr "" -#: templates/problem/search-form.html:80 +#: templates/problem/search-form.html:64 msgid "Random" msgstr "" -#: templates/problem/submit.html:117 -msgid "Your source code must contain at most 65536 characters." -msgstr "" - -#: templates/problem/submit.html:204 -#, python-format -msgid "" -"Warning! Your default language, %(default_language)s, is " -"unavailable for this problem and has been deselected." -msgstr "" - -#: templates/problem/submit.html:215 -#, python-format -msgid "" -"\n" -" You have %(left)s submission left\n" -" " -msgid_plural "" -"\n" -" You have %(left)s submissions left\n" -" " -msgstr[0] "" -msgstr[1] "" - -#: templates/problem/submit.html:224 +#: templates/problem/submit.html:212 msgid "You have 0 submissions left" msgstr "" -#: templates/problem/submit.html:258 +#: templates/problem/submit.html:250 msgid "No judge is available for this problem." msgstr "" -#: templates/problem/submit.html:262 +#: templates/problem/submit.html:252 msgid "Submit!" msgstr "" -#: templates/registration/activate.html:3 -#, python-format -msgid "%(key)s is an invalid activation key." -msgstr "" - #: templates/registration/activation_complete.html:3 msgid "Your account has been successfully activated." msgstr "" @@ -4255,13 +3807,6 @@ msgid "" "you registered with, and check your spam folder." msgstr "" -#: templates/registration/password_reset_email.txt:1 -#, python-format -msgid "" -"You're receiving this email because you requested a password reset for your " -"user account at %(site_name)s." -msgstr "" - #: templates/registration/password_reset_email.txt:3 msgid "Please go to the following page and choose a new password:" msgstr "" @@ -4274,16 +3819,6 @@ msgstr "" msgid "Thanks for using our site!" msgstr "" -#: templates/registration/password_reset_email.txt:11 -#, python-format -msgid "The %(site_name)s team" -msgstr "" - -#: templates/registration/password_reset_subject.txt:1 -#, python-format -msgid "Password reset on %(site_name)s" -msgstr "" - #: templates/registration/profile_creation.html:36 #: templates/registration/username_select.html:7 msgid "Continue >" @@ -4320,20 +3855,19 @@ msgstr "" msgid "Affiliated organizations" msgstr "" -#: templates/registration/registration_form.html:195 -#: templates/user/edit-profile.html:128 +#: templates/registration/registration_form.html:192 msgid "Notify me about upcoming contests" msgstr "" -#: templates/registration/registration_form.html:209 +#: templates/registration/registration_form.html:206 msgid "By registering, you agree to our" msgstr "" -#: templates/registration/registration_form.html:210 +#: templates/registration/registration_form.html:207 msgid "Terms & Conditions" msgstr "" -#: templates/registration/registration_form.html:213 +#: templates/registration/registration_form.html:210 msgid "Register!" msgstr "" @@ -4343,11 +3877,6 @@ msgstr "" msgid "Enter the 6-digit code generated by your app:" msgstr "" -#: templates/registration/totp_auth.html:41 -#, python-format -msgid "If you lost your authentication device, please contact us at %(email)s." -msgstr "" - #: templates/registration/totp_disable.html:38 msgid "" "To protect your account, you must first authenticate before you can disable " @@ -4366,6 +3895,10 @@ msgstr "" msgid "Or enter this code manually:" msgstr "" +#: templates/stats/base.html:9 templates/submission/list.html:339 +msgid "Statistics" +msgstr "" + #: templates/stats/language.html:11 msgid "Submission Statistics" msgstr "" @@ -4391,7 +3924,6 @@ msgid "Ping" msgstr "" #: templates/status/judge-status-table.html:8 -#: templates/user/import/index.html:104 msgid "Load" msgstr "" @@ -4407,7 +3939,6 @@ msgid "There are no judges available at this time." msgstr "" #: templates/status/language-list.html:33 templates/ticket/list.html:261 -#: templates/user/import/table_csv.html:3 msgid "ID" msgstr "" @@ -4415,22 +3946,6 @@ msgstr "" msgid "Runtime Info" msgstr "" -#: templates/status/status-tabs.html:4 -msgid "Judges" -msgstr "" - -#: templates/status/status-tabs.html:6 -msgid "Version Matrix" -msgstr "" - -#: templates/submission/internal-error-message.html:3 -#, python-format -msgid "" -"An internal error occurred while grading, and the %(SITE_NAME)s " -"administrators have been notified.
In the meantime, try resubmitting in " -"a few seconds." -msgstr "" - #: templates/submission/internal-error-message.html:8 msgid "An internal error occurred while grading." msgstr "" @@ -4447,6 +3962,10 @@ msgstr "" msgid "Filter by language..." msgstr "" +#: templates/submission/list.html:309 +msgid "Filter submissions" +msgstr "" + #: templates/submission/list.html:345 msgid "Total:" msgstr "" @@ -4503,64 +4022,63 @@ msgstr "" msgid "Execution Results" msgstr "" -#: templates/submission/status-testcases.html:34 -msgid "Overall: " -msgstr "" - -#: templates/submission/status-testcases.html:48 -msgid "Point: " -msgstr "" - -#: templates/submission/status-testcases.html:53 -msgid "Time: " -msgstr "" - -#: templates/submission/status-testcases.html:62 -msgid "Memory: " -msgstr "" - -#: templates/submission/status-testcases.html:73 +#: templates/submission/status-testcases.html:31 msgid "Batch " msgstr "" -#: templates/submission/status-testcases.html:84 -#: templates/submission/status-testcases.html:113 -msgid "Point" +#: templates/submission/status-testcases.html:43 +msgid "Overall: " msgstr "" -#: templates/submission/status-testcases.html:99 +#: templates/submission/status-testcases.html:57 +msgid "Point: " +msgstr "" + +#: templates/submission/status-testcases.html:62 +msgid "Time: " +msgstr "" + +#: templates/submission/status-testcases.html:71 +msgid "Memory: " +msgstr "" + +#: templates/submission/status-testcases.html:84 msgid "Case" msgstr "" -#: templates/submission/status-testcases.html:101 +#: templates/submission/status-testcases.html:86 msgid "Pretest" msgstr "" -#: templates/submission/status-testcases.html:103 +#: templates/submission/status-testcases.html:88 msgid "Test case" msgstr "" -#: templates/submission/status-testcases.html:141 +#: templates/submission/status-testcases.html:99 +msgid "Point" +msgstr "" + +#: templates/submission/status-testcases.html:121 msgid "Input:" msgstr "" -#: templates/submission/status-testcases.html:145 +#: templates/submission/status-testcases.html:125 msgid "Output:" msgstr "" -#: templates/submission/status-testcases.html:149 +#: templates/submission/status-testcases.html:129 msgid "Answer:" msgstr "" -#: templates/submission/status-testcases.html:154 +#: templates/submission/status-testcases.html:134 msgid "Judge feedback:" msgstr "" -#: templates/submission/status-testcases.html:175 +#: templates/submission/status-testcases.html:157 msgid "Passing pretests does not guarantee a full score on system tests." msgstr "" -#: templates/submission/status-testcases.html:178 +#: templates/submission/status-testcases.html:160 msgid "Submission aborted!" msgstr "" @@ -4572,24 +4090,11 @@ msgstr "" msgid "Abort" msgstr "" -#: templates/submission/submission-list-tabs.html:6 -msgid "Mine" -msgstr "" - -#: templates/submission/submission-list-tabs.html:9 -msgid "Best" -msgstr "" - -#: templates/submission/submission-list-tabs.html:12 -#, python-format -msgid "%(user)s's" -msgstr "" - -#: templates/ticket/list.html:135 templates/ticket/ticket.html:273 +#: templates/ticket/list.html:135 templates/ticket/ticket.html:257 msgid "Reopened: " msgstr "" -#: templates/ticket/list.html:138 templates/ticket/ticket.html:274 +#: templates/ticket/list.html:138 templates/ticket/ticket.html:258 msgid "Closed: " msgstr "" @@ -4613,7 +4118,7 @@ msgstr "" msgid "Title" msgstr "" -#: templates/ticket/list.html:264 templates/ticket/ticket.html:369 +#: templates/ticket/list.html:264 templates/ticket/ticket.html:328 msgid "Assignees" msgstr "" @@ -4628,36 +4133,32 @@ msgid "" "a problem, ask in the comments instead." msgstr "" -#: templates/ticket/ticket.html:355 -msgid "Post" -msgstr "" - -#: templates/ticket/ticket.html:363 +#: templates/ticket/ticket.html:322 msgid "Associated object" msgstr "" -#: templates/ticket/ticket.html:374 +#: templates/ticket/ticket.html:333 msgid "No one is assigned." msgstr "" -#: templates/ticket/ticket.html:380 +#: templates/ticket/ticket.html:339 msgid "Close ticket" msgstr "" -#: templates/ticket/ticket.html:382 +#: templates/ticket/ticket.html:341 msgid "Reopen ticket" msgstr "" -#: templates/ticket/ticket.html:386 +#: templates/ticket/ticket.html:345 msgid "Assignee notes" msgstr "" -#: templates/ticket/ticket.html:393 templates/widgets/select_all.html:4 +#: templates/ticket/ticket.html:352 templates/widgets/select_all.html:4 msgid "Nothing here." msgstr "" -#: templates/user/base-users-table.html:3 -msgid "Rank" +#: templates/ticket/ticket.html:385 +msgid "Post" msgstr "" #: templates/user/base-users.html:14 templates/user/base-users.html:69 @@ -4704,168 +4205,50 @@ msgstr "" msgid "Update profile" msgstr "" -#: templates/user/import/index.html:31 -msgid "Upload CSV only" -msgstr "" - -#: templates/user/import/index.html:100 -msgid "User File" -msgstr "" - -#: templates/user/import/index.html:102 -msgid "Sample" -msgstr "" - -#: templates/user/import/index.html:105 templates/user/user-list-tabs.html:8 -msgid "Import" -msgstr "" - -#: templates/user/import/table_csv.html:7 -msgid "School" -msgstr "" - -#: templates/user/pp-row.html:22 -#, python-format -msgid "" -"\n" -" weighted %(weight)s%%\n" -" " -msgstr "" - -#: templates/user/pp-row.html:27 -#, python-format -msgid "%(pp).1fpp" -msgstr "" - -#: templates/user/pp-row.html:29 -#, python-format -msgid "%(pp).0fpp" -msgstr "" - -#: templates/user/user-about.html:23 -#, python-format -msgid "%(counter)s problem solved" -msgid_plural "%(counter)s problems solved" -msgstr[0] "" -msgstr[1] "" - -#: templates/user/user-about.html:35 -msgid "Total points" -msgstr "" - -#: templates/user/user-about.html:45 -msgid "Rank by rating" -msgstr "" - -#: templates/user/user-about.html:52 -msgid "Rank by points" -msgstr "" - -#: templates/user/user-about.html:64 +#: templates/user/user-about.html:14 msgid "From" msgstr "" -#: templates/user/user-about.html:75 +#: templates/user/user-about.html:25 msgid "Admin Notes" msgstr "" -#: templates/user/user-about.html:90 +#: templates/user/user-about.html:40 msgid "You have not shared any information." msgstr "" -#: templates/user/user-about.html:92 +#: templates/user/user-about.html:42 msgid "This user has not shared any information." msgstr "" -#: templates/user/user-about.html:101 -msgid "Awards" +#: templates/user/user-base.html:50 +msgid "Rank by points:" msgstr "" -#: templates/user/user-about.html:112 -#, python-format -msgid "%(label)s (%(date)s)" +#: templates/user/user-base.html:53 +msgid "Total points:" msgstr "" -#: templates/user/user-about.html:130 -msgid "Mon" +#: templates/user/user-base.html:68 +msgid "Rank by rating:" msgstr "" -#: templates/user/user-about.html:135 -msgid "Tues" +#: templates/user/user-base.html:70 +msgid "Rating:" msgstr "" -#: templates/user/user-about.html:140 -msgid "Wed" -msgstr "" - -#: templates/user/user-about.html:145 -msgid "Thurs" -msgstr "" - -#: templates/user/user-about.html:150 -msgid "Fri" -msgstr "" - -#: templates/user/user-about.html:155 -msgid "Sat" -msgstr "" - -#: templates/user/user-about.html:160 -msgid "Sun" -msgstr "" - -#: templates/user/user-about.html:169 -msgid "Less" -msgstr "" - -#: templates/user/user-about.html:175 -msgid "More" -msgstr "" - -#: templates/user/user-about.html:184 -msgid "Rating History" -msgstr "" - -#: templates/user/user-about.html:255 -msgid "past year" -msgstr "" - -#: templates/user/user-about.html:272 -msgid "total submission(s)" -msgstr "" - -#: templates/user/user-about.html:276 -msgid "submissions in the last year" -msgstr "" - -#: templates/user/user-base.html:101 -msgid "Unfollow" -msgstr "" - -#: templates/user/user-base.html:104 -msgid "Follow" -msgstr "" - -#: templates/user/user-base.html:120 -msgid "Contests written" -msgstr "" - -#: templates/user/user-base.html:124 +#: templates/user/user-base.html:71 msgid "Volatility:" msgstr "" -#: templates/user/user-base.html:128 +#: templates/user/user-base.html:72 msgid "Min. rating:" msgstr "" -#: templates/user/user-base.html:132 +#: templates/user/user-base.html:73 msgid "Max rating:" msgstr "" -#: templates/user/user-list-tabs.html:5 -msgid "Friends" -msgstr "" - #: templates/user/user-problems.html:35 msgid "Points Breakdown" msgstr "" @@ -4886,32 +4269,10 @@ msgstr "" msgid "Hide problems I've solved" msgstr "" -#: templates/user/user-problems.html:93 -#, python-format -msgid "%(points).1f points" -msgstr "" - #: templates/user/user-problems.html:99 msgid "Score" msgstr "" -#: templates/user/user-problems.html:110 -#, python-format -msgid "%(points)s / %(total)s" -msgstr "" - -#: templates/user/user-tabs.html:7 -msgid "Impersonate" -msgstr "" - -#: templates/user/user-tabs.html:13 -msgid "Admin User" -msgstr "" - -#: templates/user/user-tabs.html:16 -msgid "Admin Profile" -msgstr "" - #: templates/widgets/select_all.html:8 msgid "Check all" msgstr "" diff --git a/locale/de/LC_MESSAGES/djangojs.po b/locale/de/LC_MESSAGES/djangojs.po index 7937ae0..8c9c3ad 100644 --- a/locale/de/LC_MESSAGES/djangojs.po +++ b/locale/de/LC_MESSAGES/djangojs.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: dmoj\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-07-20 23:30+0700\n" +"POT-Creation-Date: 2020-04-08 21:06-0500\n" "PO-Revision-Date: 2019-11-11 22:05\n" "Last-Translator: Icyene\n" "Language-Team: German\n" diff --git a/locale/en/LC_MESSAGES/django.po b/locale/en/LC_MESSAGES/django.po index 9bcad4c..d203309 100644 --- a/locale/en/LC_MESSAGES/django.po +++ b/locale/en/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-10-25 05:59+0700\n" +"POT-Creation-Date: 2020-04-10 01:26-0500\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -18,93 +18,93 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: chat_box/models.py:16 judge/admin/interface.py:110 -#: judge/models/contest.py:403 judge/models/contest.py:528 -#: judge/models/profile.py:211 +#: chat_box/models.py:15 judge/admin/interface.py:107 +#: judge/models/contest.py:257 judge/models/contest.py:381 +#: judge/models/profile.py:191 msgid "user" msgstr "" -#: chat_box/models.py:17 judge/models/comment.py:43 judge/models/comment.py:191 +#: chat_box/models.py:16 judge/models/comment.py:42 msgid "posted time" msgstr "" -#: chat_box/models.py:18 judge/models/comment.py:47 +#: chat_box/models.py:17 judge/models/comment.py:46 msgid "body of comment" msgstr "" -#: chat_box/views.py:29 templates/chat/chat.html:4 +#: chat_box/views.py:29 msgid "Chat Box" msgstr "" -#: dmoj/settings.py:355 +#: dmoj/settings.py:349 msgid "German" msgstr "" -#: dmoj/settings.py:356 +#: dmoj/settings.py:350 msgid "English" msgstr "" -#: dmoj/settings.py:357 +#: dmoj/settings.py:351 msgid "Spanish" msgstr "" -#: dmoj/settings.py:358 +#: dmoj/settings.py:352 msgid "French" msgstr "" -#: dmoj/settings.py:359 +#: dmoj/settings.py:353 msgid "Croatian" msgstr "" -#: dmoj/settings.py:360 +#: dmoj/settings.py:354 msgid "Hungarian" msgstr "" -#: dmoj/settings.py:361 +#: dmoj/settings.py:355 msgid "Japanese" msgstr "" -#: dmoj/settings.py:362 +#: dmoj/settings.py:356 msgid "Korean" msgstr "" -#: dmoj/settings.py:363 +#: dmoj/settings.py:357 msgid "Brazilian Portuguese" msgstr "" -#: dmoj/settings.py:364 +#: dmoj/settings.py:358 msgid "Romanian" msgstr "" -#: dmoj/settings.py:365 +#: dmoj/settings.py:359 msgid "Russian" msgstr "" -#: dmoj/settings.py:366 +#: dmoj/settings.py:360 msgid "Serbian (Latin)" msgstr "" -#: dmoj/settings.py:367 +#: dmoj/settings.py:361 msgid "Turkish" msgstr "" -#: dmoj/settings.py:368 +#: dmoj/settings.py:362 msgid "Vietnamese" msgstr "" -#: dmoj/settings.py:369 +#: dmoj/settings.py:363 msgid "Simplified Chinese" msgstr "" -#: dmoj/settings.py:370 +#: dmoj/settings.py:364 msgid "Traditional Chinese" msgstr "" -#: dmoj/urls.py:58 +#: dmoj/urls.py:57 msgid "Login" msgstr "" -#: dmoj/urls.py:106 templates/base.html:193 +#: dmoj/urls.py:105 templates/base.html:190 msgid "Home" msgstr "" @@ -134,92 +134,90 @@ msgstr "" msgid "Associated page" msgstr "" -#: judge/admin/contest.py:30 +#: judge/admin/contest.py:28 msgid "Included contests" msgstr "" -#: judge/admin/contest.py:66 templates/contest/clarification.html:42 -#: templates/contest/contest.html:83 templates/contest/moss.html:43 -#: templates/problem/list.html:214 templates/problem/list.html:232 -#: templates/problem/list.html:350 templates/user/user-problems.html:56 +#: judge/admin/contest.py:64 templates/contest/contest.html:83 +#: templates/contest/moss.html:43 templates/problem/list.html:206 +#: templates/problem/list.html:221 templates/user/user-problems.html:56 #: templates/user/user-problems.html:98 msgid "Problem" msgstr "" -#: judge/admin/contest.py:119 +#: judge/admin/contest.py:112 msgid "Settings" msgstr "" -#: judge/admin/contest.py:121 +#: judge/admin/contest.py:114 msgid "Scheduling" msgstr "" -#: judge/admin/contest.py:122 templates/organization/home.html:107 +#: judge/admin/contest.py:115 msgid "Details" msgstr "" -#: judge/admin/contest.py:123 +#: judge/admin/contest.py:116 msgid "Format" msgstr "" -#: judge/admin/contest.py:124 templates/contest/ranking-table.html:7 -#: templates/user/user-about.html:15 templates/user/user-about.html:45 +#: judge/admin/contest.py:117 templates/contest/ranking-table.html:5 msgid "Rating" msgstr "" -#: judge/admin/contest.py:125 +#: judge/admin/contest.py:118 msgid "Access" msgstr "" -#: judge/admin/contest.py:127 judge/admin/problem.py:131 +#: judge/admin/contest.py:120 judge/admin/problem.py:131 msgid "Justice" msgstr "" -#: judge/admin/contest.py:207 +#: judge/admin/contest.py:158 #, python-format msgid "%d contest successfully marked as visible." msgid_plural "%d contests successfully marked as visible." msgstr[0] "" msgstr[1] "" -#: judge/admin/contest.py:210 +#: judge/admin/contest.py:161 msgid "Mark contests as visible" msgstr "" -#: judge/admin/contest.py:216 +#: judge/admin/contest.py:165 #, python-format msgid "%d contest successfully marked as hidden." msgid_plural "%d contests successfully marked as hidden." msgstr[0] "" msgstr[1] "" -#: judge/admin/contest.py:219 +#: judge/admin/contest.py:168 msgid "Mark contests as hidden" msgstr "" -#: judge/admin/contest.py:233 judge/admin/submission.py:164 +#: judge/admin/contest.py:182 judge/admin/submission.py:164 #, python-format msgid "%d submission was successfully scheduled for rejudging." msgid_plural "%d submissions were successfully scheduled for rejudging." msgstr[0] "" msgstr[1] "" -#: judge/admin/contest.py:308 +#: judge/admin/contest.py:256 #, python-format msgid "%d participation recalculated." msgid_plural "%d participations recalculated." msgstr[0] "" msgstr[1] "" -#: judge/admin/contest.py:311 +#: judge/admin/contest.py:259 msgid "Recalculate results" msgstr "" -#: judge/admin/contest.py:315 judge/admin/organization.py:65 +#: judge/admin/contest.py:263 judge/admin/organization.py:65 msgid "username" msgstr "" -#: judge/admin/contest.py:320 templates/base.html:277 +#: judge/admin/contest.py:268 templates/base.html:260 msgid "virtual" msgstr "" @@ -227,15 +225,15 @@ msgstr "" msgid "link path" msgstr "" -#: judge/admin/interface.py:65 +#: judge/admin/interface.py:62 msgid "Content" msgstr "" -#: judge/admin/interface.py:66 +#: judge/admin/interface.py:63 msgid "Summary" msgstr "" -#: judge/admin/interface.py:151 +#: judge/admin/interface.py:148 msgid "object" msgstr "" @@ -257,9 +255,8 @@ msgid "Taxonomy" msgstr "" #: judge/admin/problem.py:128 templates/contest/contest.html:84 -#: templates/problem/data.html:429 templates/problem/list.html:222 -#: templates/problem/list.html:248 templates/user/base-users-table.html:10 -#: templates/user/user-about.html:36 templates/user/user-about.html:52 +#: templates/problem/data.html:449 templates/problem/list.html:211 +#: templates/problem/list.html:232 templates/user/base-users-table.html:10 #: templates/user/user-problems.html:58 msgid "Points" msgstr "" @@ -308,7 +305,6 @@ msgid "timezone" msgstr "" #: judge/admin/profile.py:86 judge/admin/submission.py:211 -#: templates/notification/list.html:12 #: templates/organization/requests/log.html:9 #: templates/organization/requests/pending.html:12 #: templates/ticket/list.html:263 @@ -316,7 +312,6 @@ msgid "User" msgstr "" #: judge/admin/profile.py:91 templates/registration/registration_form.html:145 -#: templates/user/import/table_csv.html:8 msgid "Email" msgstr "" @@ -349,7 +344,7 @@ msgstr "" msgid "These problems are NOT allowed to be submitted in this language" msgstr "" -#: judge/admin/runtime.py:83 templates/problem/list.html:352 +#: judge/admin/runtime.py:83 msgid "Description" msgstr "" @@ -396,7 +391,7 @@ msgstr "" msgid "Rejudge the selected submissions" msgstr "" -#: judge/admin/submission.py:193 judge/views/problem_manage.py:159 +#: judge/admin/submission.py:193 judge/views/problem_manage.py:128 #, python-format msgid "%d submission were successfully rescored." msgid_plural "%d submissions were successfully rescored." @@ -407,8 +402,7 @@ msgstr[1] "" msgid "Rescore the selected submissions" msgstr "" -#: judge/admin/submission.py:200 templates/problem/list.html:216 -#: templates/problem/list.html:236 +#: judge/admin/submission.py:200 msgid "Problem code" msgstr "" @@ -416,12 +410,10 @@ msgstr "" msgid "Problem name" msgstr "" -#: judge/admin/submission.py:215 templates/notification/list.html:15 -#: templates/organization/requests/log.html:10 +#: judge/admin/submission.py:215 templates/organization/requests/log.html:10 #: templates/organization/requests/pending.html:13 -#: templates/problem/list.html:351 -#: templates/submission/status-testcases.html:125 -#: templates/submission/status-testcases.html:127 +#: templates/submission/status-testcases.html:105 +#: templates/submission/status-testcases.html:107 msgid "Time" msgstr "" @@ -435,7 +427,7 @@ msgstr "" msgid "%.2f MB" msgstr "" -#: judge/admin/submission.py:227 templates/submission/status-testcases.html:132 +#: judge/admin/submission.py:227 templates/submission/status-testcases.html:112 msgid "Memory" msgstr "" @@ -455,20 +447,20 @@ msgstr "" msgid "Online Judge" msgstr "" -#: judge/comments.py:60 +#: judge/comments.py:41 msgid "Comment body" msgstr "" -#: judge/comments.py:66 judge/views/ticket.py:63 +#: judge/comments.py:47 judge/views/ticket.py:46 msgid "Your part is silent, little toad." msgstr "" -#: judge/comments.py:69 templates/comments/list.html:132 +#: judge/comments.py:50 templates/comments/list.html:131 msgid "" "You need to have solved at least one problem before your voice can be heard." msgstr "" -#: judge/comments.py:113 +#: judge/comments.py:92 msgid "Posted comment" msgstr "" @@ -484,10 +476,6 @@ msgstr "" msgid "ECOO" msgstr "" -#: judge/contest_format/icpc.py:19 -msgid "ICPC" -msgstr "" - #: judge/contest_format/ioi.py:19 msgid "IOI" msgstr "" @@ -500,58 +488,52 @@ msgstr "" msgid "Enable experimental features" msgstr "" -#: judge/forms.py:57 judge/views/organization.py:168 judge/views/register.py:49 +#: judge/forms.py:57 judge/views/organization.py:127 #, python-brace-format msgid "You may not be part of more than {count} public organizations." msgstr "" -#: judge/forms.py:82 -msgid "Any judge" -msgstr "" - -#: judge/forms.py:112 judge/views/register.py:26 +#: judge/forms.py:107 judge/views/register.py:26 #: templates/registration/registration_form.html:139 #: templates/user/base-users-table.html:5 -#: templates/user/import/table_csv.html:4 msgid "Username" msgstr "" -#: judge/forms.py:113 templates/registration/registration_form.html:151 +#: judge/forms.py:108 templates/registration/registration_form.html:151 #: templates/registration/registration_form.html:165 -#: templates/user/import/table_csv.html:5 msgid "Password" msgstr "" -#: judge/forms.py:135 +#: judge/forms.py:130 msgid "Two Factor Authentication tokens must be 6 decimal digits." msgstr "" -#: judge/forms.py:144 templates/registration/totp_auth.html:32 +#: judge/forms.py:139 templates/registration/totp_auth.html:32 msgid "Invalid Two Factor Authentication token." msgstr "" -#: judge/forms.py:148 judge/models/problem.py:97 +#: judge/forms.py:143 judge/models/problem.py:97 msgid "Problem code must be ^[a-z0-9]+$" msgstr "" -#: judge/forms.py:153 +#: judge/forms.py:148 msgid "Problem with code already exists." msgstr "" -#: judge/forms.py:158 judge/models/contest.py:61 +#: judge/forms.py:153 judge/models/contest.py:52 msgid "Contest id must be ^[a-z0-9]+$" msgstr "" -#: judge/forms.py:163 +#: judge/forms.py:158 msgid "Contest with key already exists." msgstr "" -#: judge/jinja2/datetime.py:26 templates/blog/blog.html:26 +#: judge/jinja2/datetime.py:26 templates/blog/content.html:27 #: templates/blog/dashboard.html:21 msgid "N j, Y, g:i a" msgstr "" -#: judge/jinja2/datetime.py:26 templates/chat/message.html:13 +#: judge/jinja2/datetime.py:26 #, python-brace-format msgid "{time}" msgstr "" @@ -581,542 +563,472 @@ msgstr "" msgid "Detect best quality" msgstr "" -#: judge/models/comment.py:26 +#: judge/models/comment.py:25 msgid "Page code must be ^[pcs]:[a-z0-9]+$|^b:\\d+$" msgstr "" -#: judge/models/comment.py:42 +#: judge/models/comment.py:41 msgid "commenter" msgstr "" -#: judge/models/comment.py:44 judge/models/comment.py:177 +#: judge/models/comment.py:43 judge/models/comment.py:176 msgid "associated page" msgstr "" -#: judge/models/comment.py:46 +#: judge/models/comment.py:45 msgid "votes" msgstr "" -#: judge/models/comment.py:48 +#: judge/models/comment.py:47 msgid "hide the comment" msgstr "" -#: judge/models/comment.py:49 +#: judge/models/comment.py:48 msgid "parent" msgstr "" -#: judge/models/comment.py:54 judge/models/comment.py:192 +#: judge/models/comment.py:53 msgid "comment" msgstr "" -#: judge/models/comment.py:55 +#: judge/models/comment.py:54 msgid "comments" msgstr "" -#: judge/models/comment.py:137 judge/models/problem.py:443 +#: judge/models/comment.py:136 judge/models/problem.py:406 #, python-format msgid "Editorial for %s" msgstr "" -#: judge/models/comment.py:172 +#: judge/models/comment.py:171 msgid "comment vote" msgstr "" -#: judge/models/comment.py:173 +#: judge/models/comment.py:172 msgid "comment votes" msgstr "" -#: judge/models/comment.py:182 +#: judge/models/comment.py:181 msgid "Override comment lock" msgstr "" -#: judge/models/comment.py:190 -msgid "owner" -msgstr "" - -#: judge/models/comment.py:193 judge/models/message.py:16 -msgid "read" -msgstr "" - -#: judge/models/comment.py:194 -msgid "category" -msgstr "" - -#: judge/models/comment.py:195 -msgid "html link to comments, used for non-comments" -msgstr "" - -#: judge/models/comment.py:196 -msgid "who trigger, used for non-comment" -msgstr "" - -#: judge/models/contest.py:23 +#: judge/models/contest.py:22 msgid "Invalid colour." msgstr "" -#: judge/models/contest.py:25 +#: judge/models/contest.py:24 msgid "tag name" msgstr "" -#: judge/models/contest.py:26 +#: judge/models/contest.py:25 msgid "Lowercase letters and hyphens only." msgstr "" -#: judge/models/contest.py:27 +#: judge/models/contest.py:26 msgid "tag colour" msgstr "" -#: judge/models/contest.py:28 +#: judge/models/contest.py:27 msgid "tag description" msgstr "" -#: judge/models/contest.py:47 +#: judge/models/contest.py:46 msgid "contest tag" msgstr "" -#: judge/models/contest.py:48 judge/models/contest.py:118 +#: judge/models/contest.py:47 judge/models/contest.py:101 msgid "contest tags" msgstr "" -#: judge/models/contest.py:56 -msgid "Visible" -msgstr "" - -#: judge/models/contest.py:57 -msgid "Hidden for duration of contest" -msgstr "" - -#: judge/models/contest.py:58 -msgid "Hidden for duration of participation" -msgstr "" - -#: judge/models/contest.py:60 +#: judge/models/contest.py:51 msgid "contest id" msgstr "" -#: judge/models/contest.py:62 +#: judge/models/contest.py:53 msgid "contest name" msgstr "" -#: judge/models/contest.py:63 -msgid "These users will be able to edit the contest." +#: judge/models/contest.py:54 +msgid "These people will be able to edit the contest." msgstr "" -#: judge/models/contest.py:65 -msgid "" -"These users will be able to edit the contest, but will not be listed as " -"authors." -msgstr "" - -#: judge/models/contest.py:68 -msgid "These users will be able to view the contest, but not edit it." -msgstr "" - -#: judge/models/contest.py:71 judge/models/runtime.py:136 +#: judge/models/contest.py:56 judge/models/runtime.py:133 msgid "description" msgstr "" -#: judge/models/contest.py:72 judge/models/problem.py:390 -#: judge/models/runtime.py:138 +#: judge/models/contest.py:57 judge/models/problem.py:353 +#: judge/models/runtime.py:135 msgid "problems" msgstr "" -#: judge/models/contest.py:73 judge/models/contest.py:404 +#: judge/models/contest.py:58 judge/models/contest.py:258 msgid "start time" msgstr "" -#: judge/models/contest.py:74 +#: judge/models/contest.py:59 msgid "end time" msgstr "" -#: judge/models/contest.py:75 judge/models/problem.py:118 -#: judge/models/problem.py:414 +#: judge/models/contest.py:60 judge/models/problem.py:118 +#: judge/models/problem.py:377 msgid "time limit" msgstr "" -#: judge/models/contest.py:76 judge/models/problem.py:136 +#: judge/models/contest.py:61 judge/models/problem.py:136 msgid "publicly visible" msgstr "" -#: judge/models/contest.py:77 +#: judge/models/contest.py:62 msgid "" "Should be set even for organization-private contests, where it determines " "whether the contest is visible to members of the specified organizations." msgstr "" -#: judge/models/contest.py:80 +#: judge/models/contest.py:65 msgid "contest rated" msgstr "" -#: judge/models/contest.py:80 +#: judge/models/contest.py:65 msgid "Whether this contest can be rated." msgstr "" -#: judge/models/contest.py:82 -msgid "scoreboard visibility" +#: judge/models/contest.py:67 +msgid "hide scoreboard" msgstr "" -#: judge/models/contest.py:83 -msgid "Scoreboard visibility through the duration of the contest" +#: judge/models/contest.py:68 +msgid "" +"Whether the scoreboard should remain hidden for the duration of the contest." msgstr "" -#: judge/models/contest.py:85 -msgid "view contest scoreboard" -msgstr "" - -#: judge/models/contest.py:87 -msgid "These users will be able to view the scoreboard." -msgstr "" - -#: judge/models/contest.py:88 +#: judge/models/contest.py:71 msgid "no comments" msgstr "" -#: judge/models/contest.py:89 +#: judge/models/contest.py:72 msgid "Use clarification system instead of comments." msgstr "" -#: judge/models/contest.py:91 +#: judge/models/contest.py:74 msgid "Rating floor for contest" msgstr "" -#: judge/models/contest.py:93 +#: judge/models/contest.py:76 msgid "Rating ceiling for contest" msgstr "" -#: judge/models/contest.py:95 +#: judge/models/contest.py:78 msgid "rate all" msgstr "" -#: judge/models/contest.py:95 +#: judge/models/contest.py:78 msgid "Rate all users who joined." msgstr "" -#: judge/models/contest.py:96 +#: judge/models/contest.py:79 msgid "exclude from ratings" msgstr "" -#: judge/models/contest.py:98 +#: judge/models/contest.py:81 msgid "private to specific users" msgstr "" -#: judge/models/contest.py:99 +#: judge/models/contest.py:82 msgid "private contestants" msgstr "" -#: judge/models/contest.py:100 +#: judge/models/contest.py:83 msgid "If private, only these users may see the contest" msgstr "" -#: judge/models/contest.py:102 +#: judge/models/contest.py:85 msgid "hide problem tags" msgstr "" -#: judge/models/contest.py:103 +#: judge/models/contest.py:86 msgid "Whether problem tags should be hidden by default." msgstr "" -#: judge/models/contest.py:105 +#: judge/models/contest.py:88 msgid "run pretests only" msgstr "" -#: judge/models/contest.py:106 +#: judge/models/contest.py:89 msgid "" "Whether judges should grade pretests only, versus all testcases. Commonly " "set during a contest, then unset prior to rejudging user submissions when " "the contest ends." msgstr "" -#: judge/models/contest.py:110 judge/models/interface.py:77 -#: judge/models/problem.py:157 +#: judge/models/contest.py:93 judge/models/problem.py:157 msgid "private to organizations" msgstr "" -#: judge/models/contest.py:111 judge/models/interface.py:75 -#: judge/models/problem.py:155 judge/models/profile.py:77 +#: judge/models/contest.py:94 judge/models/problem.py:155 +#: judge/models/profile.py:77 msgid "organizations" msgstr "" -#: judge/models/contest.py:112 +#: judge/models/contest.py:95 msgid "If private, only these organizations may see the contest" msgstr "" -#: judge/models/contest.py:113 judge/models/problem.py:145 +#: judge/models/contest.py:96 judge/models/problem.py:145 msgid "OpenGraph image" msgstr "" -#: judge/models/contest.py:114 judge/models/profile.py:48 +#: judge/models/contest.py:97 judge/models/profile.py:48 msgid "Logo override image" msgstr "" -#: judge/models/contest.py:116 +#: judge/models/contest.py:99 msgid "" "This image will replace the default site logo for users inside the contest." msgstr "" -#: judge/models/contest.py:119 +#: judge/models/contest.py:102 msgid "the amount of live participants" msgstr "" -#: judge/models/contest.py:120 +#: judge/models/contest.py:103 msgid "contest summary" msgstr "" -#: judge/models/contest.py:121 judge/models/problem.py:147 +#: judge/models/contest.py:104 judge/models/problem.py:147 msgid "Plain-text, shown in meta description tag, e.g. for social media." msgstr "" -#: judge/models/contest.py:122 judge/models/profile.py:47 +#: judge/models/contest.py:105 judge/models/profile.py:47 msgid "access code" msgstr "" -#: judge/models/contest.py:123 +#: judge/models/contest.py:106 msgid "" "An optional code to prompt contestants before they are allowed to join the " "contest. Leave it blank to disable." msgstr "" -#: judge/models/contest.py:125 judge/models/problem.py:141 +#: judge/models/contest.py:108 judge/models/problem.py:141 msgid "personae non gratae" msgstr "" -#: judge/models/contest.py:126 +#: judge/models/contest.py:109 msgid "Bans the selected users from joining this contest." msgstr "" -#: judge/models/contest.py:127 +#: judge/models/contest.py:110 msgid "contest format" msgstr "" -#: judge/models/contest.py:128 +#: judge/models/contest.py:111 msgid "The contest format module to use." msgstr "" -#: judge/models/contest.py:129 +#: judge/models/contest.py:112 msgid "contest format configuration" msgstr "" -#: judge/models/contest.py:130 +#: judge/models/contest.py:113 msgid "" "A JSON object to serve as the configuration for the chosen contest format " "module. Leave empty to use None. Exact format depends on the contest format " "selected." msgstr "" -#: judge/models/contest.py:137 -msgid "precision points" -msgstr "" - -#: judge/models/contest.py:139 -msgid "Number of digits to round points to." -msgstr "" - -#: judge/models/contest.py:383 +#: judge/models/contest.py:239 msgid "See private contests" msgstr "" -#: judge/models/contest.py:384 +#: judge/models/contest.py:240 msgid "Edit own contests" msgstr "" -#: judge/models/contest.py:385 +#: judge/models/contest.py:241 msgid "Edit all contests" msgstr "" -#: judge/models/contest.py:386 +#: judge/models/contest.py:242 msgid "Clone contest" msgstr "" -#: judge/models/contest.py:387 templates/contest/moss.html:74 +#: judge/models/contest.py:243 templates/contest/moss.html:74 msgid "MOSS contest" msgstr "" -#: judge/models/contest.py:388 +#: judge/models/contest.py:244 msgid "Rate contests" msgstr "" -#: judge/models/contest.py:389 +#: judge/models/contest.py:245 msgid "Contest access codes" msgstr "" -#: judge/models/contest.py:390 +#: judge/models/contest.py:246 msgid "Create private contests" msgstr "" -#: judge/models/contest.py:391 -msgid "Change contest visibility" -msgstr "" - -#: judge/models/contest.py:392 -msgid "Edit contest problem label script" -msgstr "" - -#: judge/models/contest.py:394 judge/models/contest.py:492 -#: judge/models/contest.py:529 judge/models/contest.py:552 -#: judge/models/submission.py:84 +#: judge/models/contest.py:248 judge/models/contest.py:345 +#: judge/models/contest.py:382 judge/models/contest.py:404 +#: judge/models/submission.py:83 msgid "contest" msgstr "" -#: judge/models/contest.py:395 +#: judge/models/contest.py:249 msgid "contests" msgstr "" -#: judge/models/contest.py:402 +#: judge/models/contest.py:256 msgid "associated contest" msgstr "" -#: judge/models/contest.py:405 +#: judge/models/contest.py:259 msgid "score" msgstr "" -#: judge/models/contest.py:406 +#: judge/models/contest.py:260 msgid "cumulative time" msgstr "" -#: judge/models/contest.py:407 +#: judge/models/contest.py:261 msgid "is disqualified" msgstr "" -#: judge/models/contest.py:408 +#: judge/models/contest.py:262 msgid "Whether this participation is disqualified." msgstr "" -#: judge/models/contest.py:409 -msgid "tie-breaking field" -msgstr "" - -#: judge/models/contest.py:410 +#: judge/models/contest.py:263 msgid "virtual participation id" msgstr "" -#: judge/models/contest.py:411 +#: judge/models/contest.py:264 msgid "0 means non-virtual, otherwise the n-th virtual participation." msgstr "" -#: judge/models/contest.py:412 +#: judge/models/contest.py:265 msgid "contest format specific data" msgstr "" -#: judge/models/contest.py:478 +#: judge/models/contest.py:331 #, python-format msgid "%s spectating in %s" msgstr "" -#: judge/models/contest.py:480 +#: judge/models/contest.py:333 #, python-format msgid "%s in %s, v%d" msgstr "" -#: judge/models/contest.py:481 +#: judge/models/contest.py:334 #, python-format msgid "%s in %s" msgstr "" -#: judge/models/contest.py:484 +#: judge/models/contest.py:337 msgid "contest participation" msgstr "" -#: judge/models/contest.py:485 +#: judge/models/contest.py:338 msgid "contest participations" msgstr "" -#: judge/models/contest.py:491 judge/models/contest.py:513 -#: judge/models/contest.py:553 judge/models/problem.py:389 -#: judge/models/problem.py:394 judge/models/problem.py:412 -#: judge/models/problem_data.py:40 +#: judge/models/contest.py:344 judge/models/contest.py:366 +#: judge/models/contest.py:405 judge/models/problem.py:352 +#: judge/models/problem.py:357 judge/models/problem.py:375 +#: judge/models/problem_data.py:38 msgid "problem" msgstr "" -#: judge/models/contest.py:493 judge/models/contest.py:517 +#: judge/models/contest.py:346 judge/models/contest.py:370 #: judge/models/problem.py:129 msgid "points" msgstr "" -#: judge/models/contest.py:494 +#: judge/models/contest.py:347 msgid "partial" msgstr "" -#: judge/models/contest.py:495 judge/models/contest.py:518 +#: judge/models/contest.py:348 judge/models/contest.py:371 msgid "is pretested" msgstr "" -#: judge/models/contest.py:496 judge/models/interface.py:43 +#: judge/models/contest.py:349 judge/models/interface.py:43 msgid "order" msgstr "" -#: judge/models/contest.py:497 +#: judge/models/contest.py:350 msgid "0 to not show testcases, 1 to show" msgstr "" -#: judge/models/contest.py:498 +#: judge/models/contest.py:351 msgid "visible testcases" msgstr "" -#: judge/models/contest.py:499 +#: judge/models/contest.py:352 msgid "Maximum number of submissions for this problem, or 0 for no limit." msgstr "" -#: judge/models/contest.py:501 +#: judge/models/contest.py:354 msgid "Why include a problem you can't submit to?" msgstr "" -#: judge/models/contest.py:506 +#: judge/models/contest.py:359 msgid "contest problem" msgstr "" -#: judge/models/contest.py:507 +#: judge/models/contest.py:360 msgid "contest problems" msgstr "" -#: judge/models/contest.py:511 judge/models/submission.py:183 +#: judge/models/contest.py:364 judge/models/submission.py:181 msgid "submission" msgstr "" -#: judge/models/contest.py:515 judge/models/contest.py:530 +#: judge/models/contest.py:368 judge/models/contest.py:383 msgid "participation" msgstr "" -#: judge/models/contest.py:519 +#: judge/models/contest.py:372 msgid "Whether this submission was ran only on pretests." msgstr "" -#: judge/models/contest.py:523 +#: judge/models/contest.py:376 msgid "contest submission" msgstr "" -#: judge/models/contest.py:524 +#: judge/models/contest.py:377 msgid "contest submissions" msgstr "" -#: judge/models/contest.py:532 +#: judge/models/contest.py:385 msgid "rank" msgstr "" -#: judge/models/contest.py:533 +#: judge/models/contest.py:386 msgid "rating" msgstr "" -#: judge/models/contest.py:534 +#: judge/models/contest.py:387 msgid "volatility" msgstr "" -#: judge/models/contest.py:535 +#: judge/models/contest.py:388 msgid "last rated" msgstr "" -#: judge/models/contest.py:539 +#: judge/models/contest.py:392 msgid "contest rating" msgstr "" -#: judge/models/contest.py:540 +#: judge/models/contest.py:393 msgid "contest ratings" msgstr "" -#: judge/models/contest.py:560 +#: judge/models/contest.py:412 msgid "contest moss result" msgstr "" -#: judge/models/contest.py:561 +#: judge/models/contest.py:413 msgid "contest moss results" msgstr "" @@ -1156,7 +1068,7 @@ msgstr "" msgid "post title" msgstr "" -#: judge/models/interface.py:67 judge/models/problem.py:432 +#: judge/models/interface.py:67 judge/models/problem.py:395 msgid "authors" msgstr "" @@ -1164,7 +1076,7 @@ msgstr "" msgid "slug" msgstr "" -#: judge/models/interface.py:69 judge/models/problem.py:430 +#: judge/models/interface.py:69 judge/models/problem.py:393 msgid "public visibility" msgstr "" @@ -1188,19 +1100,15 @@ msgstr "" msgid "openGraph image" msgstr "" -#: judge/models/interface.py:76 -msgid "If private, only these organizations may see the blog post." -msgstr "" - -#: judge/models/interface.py:105 +#: judge/models/interface.py:91 msgid "Edit all posts" msgstr "" -#: judge/models/interface.py:107 +#: judge/models/interface.py:93 msgid "blog post" msgstr "" -#: judge/models/interface.py:108 +#: judge/models/interface.py:94 msgid "blog posts" msgstr "" @@ -1224,6 +1132,10 @@ msgstr "" msgid "message timestamp" msgstr "" +#: judge/models/message.py:16 +msgid "read" +msgstr "" + #: judge/models/message.py:20 msgid "messages in the thread" msgstr "" @@ -1360,7 +1272,7 @@ msgid "" "are supported." msgstr "" -#: judge/models/problem.py:123 judge/models/problem.py:417 +#: judge/models/problem.py:123 judge/models/problem.py:380 msgid "memory limit" msgstr "" @@ -1433,188 +1345,188 @@ msgstr "" msgid "If private, only these organizations may see the problem." msgstr "" -#: judge/models/problem.py:395 judge/models/problem.py:413 -#: judge/models/runtime.py:111 +#: judge/models/problem.py:358 judge/models/problem.py:376 +#: judge/models/runtime.py:108 msgid "language" msgstr "" -#: judge/models/problem.py:396 +#: judge/models/problem.py:359 msgid "translated name" msgstr "" -#: judge/models/problem.py:397 +#: judge/models/problem.py:360 msgid "translated description" msgstr "" -#: judge/models/problem.py:401 +#: judge/models/problem.py:364 msgid "problem translation" msgstr "" -#: judge/models/problem.py:402 +#: judge/models/problem.py:365 msgid "problem translations" msgstr "" -#: judge/models/problem.py:406 +#: judge/models/problem.py:369 msgid "clarified problem" msgstr "" -#: judge/models/problem.py:407 +#: judge/models/problem.py:370 msgid "clarification body" msgstr "" -#: judge/models/problem.py:408 +#: judge/models/problem.py:371 msgid "clarification timestamp" msgstr "" -#: judge/models/problem.py:423 +#: judge/models/problem.py:386 msgid "language-specific resource limit" msgstr "" -#: judge/models/problem.py:424 +#: judge/models/problem.py:387 msgid "language-specific resource limits" msgstr "" -#: judge/models/problem.py:428 +#: judge/models/problem.py:391 msgid "associated problem" msgstr "" -#: judge/models/problem.py:431 +#: judge/models/problem.py:394 msgid "publish date" msgstr "" -#: judge/models/problem.py:433 +#: judge/models/problem.py:396 msgid "editorial content" msgstr "" -#: judge/models/problem.py:449 +#: judge/models/problem.py:412 msgid "solution" msgstr "" -#: judge/models/problem.py:450 +#: judge/models/problem.py:413 msgid "solutions" msgstr "" -#: judge/models/problem_data.py:26 +#: judge/models/problem_data.py:24 msgid "Standard" msgstr "" -#: judge/models/problem_data.py:27 +#: judge/models/problem_data.py:25 msgid "Floats" msgstr "" -#: judge/models/problem_data.py:28 +#: judge/models/problem_data.py:26 msgid "Floats (absolute)" msgstr "" -#: judge/models/problem_data.py:29 +#: judge/models/problem_data.py:27 msgid "Floats (relative)" msgstr "" -#: judge/models/problem_data.py:30 +#: judge/models/problem_data.py:28 msgid "Non-trailing spaces" msgstr "" -#: judge/models/problem_data.py:31 +#: judge/models/problem_data.py:29 msgid "Unordered" msgstr "" -#: judge/models/problem_data.py:32 +#: judge/models/problem_data.py:30 msgid "Byte identical" msgstr "" -#: judge/models/problem_data.py:33 +#: judge/models/problem_data.py:31 msgid "Line-by-line" msgstr "" -#: judge/models/problem_data.py:34 +#: judge/models/problem_data.py:32 msgid "Custom checker (PY)" msgstr "" -#: judge/models/problem_data.py:35 +#: judge/models/problem_data.py:33 msgid "Custom validator (CPP)" msgstr "" -#: judge/models/problem_data.py:42 +#: judge/models/problem_data.py:40 msgid "data zip file" msgstr "" -#: judge/models/problem_data.py:44 +#: judge/models/problem_data.py:42 msgid "generator file" msgstr "" -#: judge/models/problem_data.py:46 judge/models/problem_data.py:121 +#: judge/models/problem_data.py:44 judge/models/problem_data.py:110 msgid "output prefix length" msgstr "" -#: judge/models/problem_data.py:47 judge/models/problem_data.py:122 +#: judge/models/problem_data.py:45 judge/models/problem_data.py:111 msgid "output limit length" msgstr "" -#: judge/models/problem_data.py:48 +#: judge/models/problem_data.py:46 msgid "init.yml generation feedback" msgstr "" -#: judge/models/problem_data.py:49 judge/models/problem_data.py:123 +#: judge/models/problem_data.py:47 judge/models/problem_data.py:112 msgid "checker" msgstr "" -#: judge/models/problem_data.py:50 judge/models/problem_data.py:124 +#: judge/models/problem_data.py:48 judge/models/problem_data.py:113 msgid "checker arguments" msgstr "" -#: judge/models/problem_data.py:51 judge/models/problem_data.py:125 +#: judge/models/problem_data.py:49 judge/models/problem_data.py:114 msgid "checker arguments as a JSON object" msgstr "" -#: judge/models/problem_data.py:52 +#: judge/models/problem_data.py:50 msgid "custom checker file" msgstr "" -#: judge/models/problem_data.py:58 +#: judge/models/problem_data.py:56 msgid "custom validator file" msgstr "" -#: judge/models/problem_data.py:108 +#: judge/models/problem_data.py:97 msgid "problem data set" msgstr "" -#: judge/models/problem_data.py:110 +#: judge/models/problem_data.py:99 msgid "case position" msgstr "" -#: judge/models/problem_data.py:111 +#: judge/models/problem_data.py:100 msgid "case type" msgstr "" -#: judge/models/problem_data.py:112 +#: judge/models/problem_data.py:101 msgid "Normal case" msgstr "" -#: judge/models/problem_data.py:113 +#: judge/models/problem_data.py:102 msgid "Batch start" msgstr "" -#: judge/models/problem_data.py:114 +#: judge/models/problem_data.py:103 msgid "Batch end" msgstr "" -#: judge/models/problem_data.py:116 +#: judge/models/problem_data.py:105 msgid "input file name" msgstr "" -#: judge/models/problem_data.py:117 +#: judge/models/problem_data.py:106 msgid "output file name" msgstr "" -#: judge/models/problem_data.py:118 +#: judge/models/problem_data.py:107 msgid "generator arguments" msgstr "" -#: judge/models/problem_data.py:119 +#: judge/models/problem_data.py:108 msgid "point value" msgstr "" -#: judge/models/problem_data.py:120 +#: judge/models/problem_data.py:109 msgid "case is pretest?" msgstr "" @@ -1687,7 +1599,7 @@ msgid "" msgstr "" #: judge/models/profile.py:76 judge/models/profile.py:93 -#: judge/models/profile.py:212 +#: judge/models/profile.py:192 msgid "organization" msgstr "" @@ -1783,31 +1695,31 @@ msgstr "" msgid "Notes for administrators regarding this user." msgstr "" -#: judge/models/profile.py:206 +#: judge/models/profile.py:186 msgid "user profile" msgstr "" -#: judge/models/profile.py:207 +#: judge/models/profile.py:187 msgid "user profiles" msgstr "" -#: judge/models/profile.py:214 +#: judge/models/profile.py:194 msgid "request time" msgstr "" -#: judge/models/profile.py:215 +#: judge/models/profile.py:195 msgid "state" msgstr "" -#: judge/models/profile.py:220 +#: judge/models/profile.py:200 msgid "reason" msgstr "" -#: judge/models/profile.py:223 +#: judge/models/profile.py:203 msgid "organization join request" msgstr "" -#: judge/models/profile.py:224 +#: judge/models/profile.py:204 msgid "organization join requests" msgstr "" @@ -1898,86 +1810,86 @@ msgstr "" msgid "The extension of source files, e.g., \"py\" or \"cpp\"." msgstr "" -#: judge/models/runtime.py:112 +#: judge/models/runtime.py:109 msgid "languages" msgstr "" -#: judge/models/runtime.py:116 +#: judge/models/runtime.py:113 msgid "language to which this runtime belongs" msgstr "" -#: judge/models/runtime.py:117 +#: judge/models/runtime.py:114 msgid "judge on which this runtime exists" msgstr "" -#: judge/models/runtime.py:118 +#: judge/models/runtime.py:115 msgid "runtime name" msgstr "" -#: judge/models/runtime.py:119 +#: judge/models/runtime.py:116 msgid "runtime version" msgstr "" -#: judge/models/runtime.py:120 +#: judge/models/runtime.py:117 msgid "order in which to display this runtime" msgstr "" -#: judge/models/runtime.py:124 +#: judge/models/runtime.py:121 msgid "Server name, hostname-style" msgstr "" -#: judge/models/runtime.py:125 +#: judge/models/runtime.py:122 msgid "time of creation" msgstr "" -#: judge/models/runtime.py:126 +#: judge/models/runtime.py:123 msgid "A key to authenticate this judge" msgstr "" -#: judge/models/runtime.py:127 +#: judge/models/runtime.py:124 msgid "authentication key" msgstr "" -#: judge/models/runtime.py:128 +#: judge/models/runtime.py:125 msgid "block judge" msgstr "" -#: judge/models/runtime.py:129 +#: judge/models/runtime.py:126 msgid "" "Whether this judge should be blocked from connecting, even if its key is " "correct." msgstr "" -#: judge/models/runtime.py:131 +#: judge/models/runtime.py:128 msgid "judge online status" msgstr "" -#: judge/models/runtime.py:132 +#: judge/models/runtime.py:129 msgid "judge start time" msgstr "" -#: judge/models/runtime.py:133 +#: judge/models/runtime.py:130 msgid "response time" msgstr "" -#: judge/models/runtime.py:134 +#: judge/models/runtime.py:131 msgid "system load" msgstr "" -#: judge/models/runtime.py:135 +#: judge/models/runtime.py:132 msgid "Load for the last minute, divided by processors to be fair." msgstr "" -#: judge/models/runtime.py:139 judge/models/runtime.py:179 +#: judge/models/runtime.py:136 judge/models/runtime.py:176 msgid "judges" msgstr "" -#: judge/models/runtime.py:178 +#: judge/models/runtime.py:175 msgid "judge" msgstr "" #: judge/models/submission.py:20 judge/models/submission.py:47 -#: judge/utils/problems.py:79 +#: judge/utils/problems.py:77 msgid "Accepted" msgstr "" @@ -2006,7 +1918,7 @@ msgid "Runtime Error" msgstr "" #: judge/models/submission.py:27 judge/models/submission.py:41 -#: judge/models/submission.py:55 judge/utils/problems.py:81 +#: judge/models/submission.py:55 judge/utils/problems.py:79 msgid "Compile Error" msgstr "" @@ -2047,15 +1959,15 @@ msgstr "" msgid "submission time" msgstr "" -#: judge/models/submission.py:67 judge/models/submission.py:203 +#: judge/models/submission.py:67 judge/models/submission.py:201 msgid "execution time" msgstr "" -#: judge/models/submission.py:68 judge/models/submission.py:204 +#: judge/models/submission.py:68 judge/models/submission.py:202 msgid "memory usage" msgstr "" -#: judge/models/submission.py:69 judge/models/submission.py:205 +#: judge/models/submission.py:69 judge/models/submission.py:203 msgid "points granted" msgstr "" @@ -2092,62 +2004,58 @@ msgid "judged on" msgstr "" #: judge/models/submission.py:81 -msgid "submission judge time" -msgstr "" - -#: judge/models/submission.py:82 msgid "was rejudged by admin" msgstr "" -#: judge/models/submission.py:83 +#: judge/models/submission.py:82 msgid "was ran on pretests only" msgstr "" -#: judge/models/submission.py:184 templates/contest/moss.html:58 +#: judge/models/submission.py:182 templates/contest/moss.html:58 msgid "submissions" msgstr "" -#: judge/models/submission.py:188 judge/models/submission.py:199 +#: judge/models/submission.py:186 judge/models/submission.py:197 msgid "associated submission" msgstr "" -#: judge/models/submission.py:190 +#: judge/models/submission.py:188 msgid "source code" msgstr "" -#: judge/models/submission.py:201 +#: judge/models/submission.py:199 msgid "test case ID" msgstr "" -#: judge/models/submission.py:202 +#: judge/models/submission.py:200 msgid "status flag" msgstr "" -#: judge/models/submission.py:206 +#: judge/models/submission.py:204 msgid "points possible" msgstr "" -#: judge/models/submission.py:207 +#: judge/models/submission.py:205 msgid "batch number" msgstr "" -#: judge/models/submission.py:208 +#: judge/models/submission.py:206 msgid "judging feedback" msgstr "" -#: judge/models/submission.py:209 +#: judge/models/submission.py:207 msgid "extended judging feedback" msgstr "" -#: judge/models/submission.py:210 +#: judge/models/submission.py:208 msgid "program output" msgstr "" -#: judge/models/submission.py:218 +#: judge/models/submission.py:216 msgid "submission test case" msgstr "" -#: judge/models/submission.py:219 +#: judge/models/submission.py:217 msgid "submission test cases" msgstr "" @@ -2199,21 +2107,12 @@ msgstr "" msgid "message time" msgstr "" -#: judge/pdf_problems.py:147 judge/pdf_problems.py:199 -#: judge/pdf_problems.py:259 +#: judge/pdf_problems.py:134 judge/pdf_problems.py:186 +#: judge/pdf_problems.py:246 msgid "Page [page] of [topage]" msgstr "" -#: judge/pdf_problems.py:280 -#, python-format -msgid "Page %s of %s" -msgstr "" - -#: judge/tasks/contest.py:19 -msgid "Recalculating contest scores" -msgstr "" - -#: judge/tasks/contest.py:40 +#: judge/tasks/moss.py:25 msgid "Running MOSS" msgstr "" @@ -2225,60 +2124,60 @@ msgstr "" msgid "Recalculating user points" msgstr "" -#: judge/utils/problem_data.py:70 +#: judge/utils/problem_data.py:68 msgid "Empty batches not allowed." msgstr "" -#: judge/utils/problem_data.py:78 judge/utils/problem_data.py:99 +#: judge/utils/problem_data.py:76 judge/utils/problem_data.py:97 msgid "How did you corrupt the custom checker path?" msgstr "" -#: judge/utils/problem_data.py:120 +#: judge/utils/problem_data.py:118 #, python-format msgid "Points must be defined for non-batch case #%d." msgstr "" -#: judge/utils/problem_data.py:125 +#: judge/utils/problem_data.py:123 #, python-format msgid "Input file for case %d does not exist: %s" msgstr "" -#: judge/utils/problem_data.py:128 +#: judge/utils/problem_data.py:126 #, python-format msgid "Output file for case %d does not exist: %s" msgstr "" -#: judge/utils/problem_data.py:153 +#: judge/utils/problem_data.py:151 #, python-format msgid "Batch start case #%d requires points." msgstr "" -#: judge/utils/problem_data.py:174 +#: judge/utils/problem_data.py:172 #, python-format msgid "Attempt to end batch outside of one in case #%d" msgstr "" -#: judge/utils/problem_data.py:192 +#: judge/utils/problem_data.py:190 msgid "How did you corrupt the zip path?" msgstr "" -#: judge/utils/problem_data.py:198 +#: judge/utils/problem_data.py:196 msgid "How did you corrupt the generator path?" msgstr "" -#: judge/utils/problems.py:80 +#: judge/utils/problems.py:78 msgid "Wrong" msgstr "" -#: judge/utils/problems.py:82 +#: judge/utils/problems.py:80 msgid "Timeout" msgstr "" -#: judge/utils/problems.py:83 +#: judge/utils/problems.py:81 msgid "Error" msgstr "" -#: judge/utils/problems.py:94 +#: judge/utils/problems.py:92 msgid "Can't pass both queryset and keyword filters" msgstr "" @@ -2321,8 +2220,7 @@ msgctxt "hours and minutes" msgid "%h:%m" msgstr "" -#: judge/views/about.py:7 templates/organization/home.html:112 -#: templates/user/user-about.html:83 templates/user/user-tabs.html:4 +#: judge/views/about.py:7 templates/user/user-about.html:33 msgid "About" msgstr "" @@ -2330,165 +2228,156 @@ msgstr "" msgid "Custom Checker Sample" msgstr "" -#: judge/views/blog.py:45 +#: judge/views/blog.py:38 #, python-format msgid "Page %d of Posts" msgstr "" -#: judge/views/comment.py:28 +#: judge/views/comment.py:27 msgid "Messing around, are we?" msgstr "" -#: judge/views/comment.py:37 +#: judge/views/comment.py:36 msgid "You must solve at least one problem before you can vote." msgstr "" -#: judge/views/comment.py:64 +#: judge/views/comment.py:63 msgid "You already voted." msgstr "" -#: judge/views/comment.py:126 judge/views/organization.py:344 +#: judge/views/comment.py:120 judge/views/organization.py:299 msgid "Edited from site" msgstr "" -#: judge/views/comment.py:147 +#: judge/views/comment.py:141 msgid "Editing comment" msgstr "" -#: judge/views/contests.py:57 judge/views/contests.py:247 -#: judge/views/contests.py:250 judge/views/contests.py:424 +#: judge/views/contests.py:55 judge/views/contests.py:215 +#: judge/views/contests.py:218 judge/views/contests.py:389 msgid "No such contest" msgstr "" -#: judge/views/contests.py:58 judge/views/contests.py:248 +#: judge/views/contests.py:56 judge/views/contests.py:216 #, python-format msgid "Could not find a contest with the key \"%s\"." msgstr "" -#: judge/views/contests.py:71 +#: judge/views/contests.py:81 msgid "Contests" msgstr "" -#: judge/views/contests.py:251 +#: judge/views/contests.py:219 msgid "Could not find such contest." msgstr "" -#: judge/views/contests.py:254 +#: judge/views/contests.py:222 #, python-format msgid "Access to contest \"%s\" denied" msgstr "" -#: judge/views/contests.py:278 +#: judge/views/contests.py:246 msgid "Clone Contest" msgstr "" -#: judge/views/contests.py:343 +#: judge/views/contests.py:309 msgid "Contest not ongoing" msgstr "" -#: judge/views/contests.py:344 +#: judge/views/contests.py:310 #, python-format msgid "\"%s\" is not currently ongoing." msgstr "" -#: judge/views/contests.py:348 +#: judge/views/contests.py:314 msgid "Already in contest" msgstr "" -#: judge/views/contests.py:349 +#: judge/views/contests.py:315 #, python-format msgid "You are already in a contest: \"%s\"." msgstr "" -#: judge/views/contests.py:352 +#: judge/views/contests.py:318 msgid "Banned from joining" msgstr "" -#: judge/views/contests.py:353 +#: judge/views/contests.py:319 msgid "" "You have been declared persona non grata for this contest. You are " "permanently barred from joining this contest." msgstr "" -#: judge/views/contests.py:414 +#: judge/views/contests.py:379 #, python-format msgid "Enter access code for \"%s\"" msgstr "" -#: judge/views/contests.py:425 +#: judge/views/contests.py:390 #, python-format msgid "You are not in contest \"%s\"." msgstr "" -#: judge/views/contests.py:444 +#: judge/views/contests.py:409 msgid "ContestCalendar requires integer year and month" msgstr "" -#: judge/views/contests.py:484 +#: judge/views/contests.py:449 #, python-format msgid "Contests in %(month)s" msgstr "" -#: judge/views/contests.py:484 +#: judge/views/contests.py:449 msgid "F Y" msgstr "" -#: judge/views/contests.py:532 +#: judge/views/contests.py:496 #, python-format msgid "%s Statistics" msgstr "" -#: judge/views/contests.py:717 +#: judge/views/contests.py:601 +msgid "???" +msgstr "" + +#: judge/views/contests.py:664 #, python-format msgid "%s Rankings" msgstr "" -#: judge/views/contests.py:725 -msgid "???" -msgstr "" - -#: judge/views/contests.py:741 +#: judge/views/contests.py:680 #, python-format msgid "Your participation in %s" msgstr "" -#: judge/views/contests.py:742 +#: judge/views/contests.py:681 #, python-format msgid "%s's participation in %s" msgstr "" -#: judge/views/contests.py:749 +#: judge/views/contests.py:685 msgid "Live" msgstr "" -#: judge/views/contests.py:761 templates/contest/contest-tabs.html:13 +#: judge/views/contests.py:697 msgid "Participation" msgstr "" -#: judge/views/contests.py:808 +#: judge/views/contests.py:743 #, python-format msgid "%s MOSS Results" msgstr "" -#: judge/views/contests.py:835 +#: judge/views/contests.py:770 #, python-format msgid "Running MOSS for %s..." msgstr "" -#: judge/views/contests.py:858 +#: judge/views/contests.py:793 #, python-format msgid "Contest tag: %s" msgstr "" -#: judge/views/contests.py:868 judge/views/ticket.py:57 -msgid "Issue description" -msgstr "" - -#: judge/views/contests.py:911 -#, python-format -msgid "New clarification for %s" -msgstr "" - #: judge/views/error.py:14 msgid "404 error" msgstr "" @@ -2509,122 +2398,115 @@ msgid "corrupt page %s" msgstr "" #: judge/views/language.py:12 templates/status/judge-status-table.html:9 -#: templates/status/status-tabs.html:5 msgid "Runtimes" msgstr "" -#: judge/views/notification.py:40 -#, python-format -msgid "Notifications (%d unseen)" -msgstr "" - -#: judge/views/organization.py:59 judge/views/organization.py:62 +#: judge/views/organization.py:44 judge/views/organization.py:47 msgid "No such organization" msgstr "" -#: judge/views/organization.py:60 +#: judge/views/organization.py:45 #, python-format msgid "Could not find an organization with the key \"%s\"." msgstr "" -#: judge/views/organization.py:63 +#: judge/views/organization.py:48 msgid "Could not find such organization." msgstr "" -#: judge/views/organization.py:79 judge/views/register.py:34 -#: templates/organization/list.html:32 templates/user/import/table_csv.html:9 -#: templates/user/user-list-tabs.html:6 +#: judge/views/organization.py:72 judge/views/register.py:34 +#: templates/organization/list.html:15 msgid "Organizations" msgstr "" -#: judge/views/organization.py:130 +#: judge/views/organization.py:93 #, python-format msgid "%s Members" msgstr "" -#: judge/views/organization.py:159 judge/views/organization.py:162 -#: judge/views/organization.py:167 +#: judge/views/organization.py:118 judge/views/organization.py:121 +#: judge/views/organization.py:126 msgid "Joining organization" msgstr "" -#: judge/views/organization.py:159 +#: judge/views/organization.py:118 msgid "You are already in the organization." msgstr "" -#: judge/views/organization.py:162 +#: judge/views/organization.py:121 msgid "This organization is not open." msgstr "" -#: judge/views/organization.py:179 +#: judge/views/organization.py:138 msgid "Leaving organization" msgstr "" -#: judge/views/organization.py:179 +#: judge/views/organization.py:138 #, python-format msgid "You are not in \"%s\"." msgstr "" -#: judge/views/organization.py:203 +#: judge/views/organization.py:162 #, python-format msgid "Request to join %s" msgstr "" -#: judge/views/organization.py:221 +#: judge/views/organization.py:180 msgid "Join request detail" msgstr "" -#: judge/views/organization.py:254 +#: judge/views/organization.py:209 #, python-format msgid "Managing join requests for %s" msgstr "" -#: judge/views/organization.py:285 +#: judge/views/organization.py:240 #, python-format msgid "" "Your organization can only receive %d more members. You cannot approve %d " "users." msgstr "" -#: judge/views/organization.py:297 +#: judge/views/organization.py:252 #, python-format msgid "Approved %d user." msgid_plural "Approved %d users." msgstr[0] "" msgstr[1] "" -#: judge/views/organization.py:298 +#: judge/views/organization.py:253 #, python-format msgid "Rejected %d user." msgid_plural "Rejected %d users." msgstr[0] "" msgstr[1] "" -#: judge/views/organization.py:328 +#: judge/views/organization.py:283 #, python-format msgid "Editing %s" msgstr "" -#: judge/views/organization.py:352 judge/views/organization.py:360 +#: judge/views/organization.py:307 judge/views/organization.py:315 msgid "Can't edit organization" msgstr "" -#: judge/views/organization.py:353 +#: judge/views/organization.py:308 msgid "You are not allowed to edit this organization." msgstr "" -#: judge/views/organization.py:361 +#: judge/views/organization.py:316 msgid "You are not allowed to kick people from this organization." msgstr "" -#: judge/views/organization.py:366 judge/views/organization.py:370 +#: judge/views/organization.py:321 judge/views/organization.py:325 msgid "Can't kick user" msgstr "" -#: judge/views/organization.py:367 +#: judge/views/organization.py:322 msgid "The user you are trying to kick does not exist!" msgstr "" -#: judge/views/organization.py:371 +#: judge/views/organization.py:326 #, python-format msgid "The user you are trying to kick is not in organization: %s." msgstr "" @@ -2648,36 +2530,35 @@ msgstr "" msgid "Editorial for {0}" msgstr "" -#: judge/views/problem.py:285 templates/contest/contest.html:79 -#: templates/user/user-about.html:28 templates/user/user-tabs.html:5 -#: templates/user/users-table.html:31 +#: judge/views/problem.py:286 templates/contest/contest.html:79 +#: templates/user/users-table.html:23 msgid "Problems" msgstr "" -#: judge/views/problem.py:585 +#: judge/views/problem.py:547 msgid "Banned from submitting" msgstr "" -#: judge/views/problem.py:586 +#: judge/views/problem.py:548 msgid "" "You have been declared persona non grata for this problem. You are " "permanently barred from submitting this problem." msgstr "" -#: judge/views/problem.py:600 +#: judge/views/problem.py:562 msgid "Too many submissions" msgstr "" -#: judge/views/problem.py:601 +#: judge/views/problem.py:563 msgid "You have exceeded the submission limit for this problem." msgstr "" -#: judge/views/problem.py:661 judge/views/problem.py:664 +#: judge/views/problem.py:633 judge/views/problem.py:636 #, python-format msgid "Submit to %(problem)s" msgstr "" -#: judge/views/problem.py:679 +#: judge/views/problem.py:652 msgid "Clone Problem" msgstr "" @@ -2718,22 +2599,22 @@ msgstr "" msgid "Generated init.yml for %s" msgstr "" -#: judge/views/problem_manage.py:52 judge/views/problem_manage.py:55 +#: judge/views/problem_manage.py:50 judge/views/problem_manage.py:53 #, python-format msgid "Managing submissions for %s" msgstr "" -#: judge/views/problem_manage.py:97 +#: judge/views/problem_manage.py:95 #, python-format msgid "Rejudging selected submissions for %s..." msgstr "" -#: judge/views/problem_manage.py:141 +#: judge/views/problem_manage.py:110 #, python-format msgid "Rescoring all submissions for %s..." msgstr "" -#: judge/views/problem_manage.py:150 +#: judge/views/problem_manage.py:119 #, python-format msgid "Successfully scheduled %d submission for rejudging." msgid_plural "Successfully scheduled %d submissions for rejudging." @@ -2782,24 +2663,24 @@ msgstr "" msgid "Subscribe to newsletter?" msgstr "" -#: judge/views/register.py:55 +#: judge/views/register.py:45 #, python-format msgid "" "The email address \"%s\" is already taken. Only one registration is allowed " "per address." msgstr "" -#: judge/views/register.py:61 +#: judge/views/register.py:51 msgid "" "Your email provider is not allowed due to history of abuse. Please use a " "reputable email provider." msgstr "" -#: judge/views/register.py:67 judge/views/register.py:105 +#: judge/views/register.py:57 judge/views/register.py:95 msgid "Registration" msgstr "" -#: judge/views/register.py:116 +#: judge/views/register.py:106 msgid "Authentication failure" msgstr "" @@ -2815,100 +2696,104 @@ msgstr "" msgid "Version matrix" msgstr "" -#: judge/views/submission.py:84 judge/views/submission.py:91 +#: judge/views/submission.py:83 judge/views/submission.py:90 #, python-format msgid "Submission of %(problem)s by %(user)s" msgstr "" -#: judge/views/submission.py:244 judge/views/submission.py:245 -#: templates/problem/problem.html:167 +#: judge/views/submission.py:227 judge/views/submission.py:228 +#: templates/problem/problem.html:127 msgid "All submissions" msgstr "" -#: judge/views/submission.py:404 +#: judge/views/submission.py:384 msgid "All my submissions" msgstr "" -#: judge/views/submission.py:405 +#: judge/views/submission.py:385 #, python-format msgid "All submissions by %s" msgstr "" -#: judge/views/submission.py:436 +#: judge/views/submission.py:416 #, python-format msgid "All submissions for %s" msgstr "" -#: judge/views/submission.py:455 +#: judge/views/submission.py:435 msgid "Must pass a problem" msgstr "" -#: judge/views/submission.py:501 +#: judge/views/submission.py:481 #, python-format msgid "My submissions for %(problem)s" msgstr "" -#: judge/views/submission.py:502 +#: judge/views/submission.py:482 #, python-format msgid "%(user)s's submissions for %(problem)s" msgstr "" -#: judge/views/submission.py:603 +#: judge/views/submission.py:583 msgid "Must pass a contest" msgstr "" -#: judge/views/submission.py:622 +#: judge/views/submission.py:602 #, python-brace-format msgid "" "{0}'s submissions for {2} in {4}" msgstr "" -#: judge/views/submission.py:629 +#: judge/views/submission.py:609 #, python-brace-format msgid "" "{0}'s submissions for problem {2} in {3}" "" msgstr "" -#: judge/views/ticket.py:50 judge/views/ticket.py:56 +#: judge/views/ticket.py:33 judge/views/ticket.py:39 msgid "Ticket title" msgstr "" -#: judge/views/ticket.py:107 judge/views/ticket.py:110 +#: judge/views/ticket.py:40 +msgid "Issue description" +msgstr "" + +#: judge/views/ticket.py:85 judge/views/ticket.py:88 #, python-format msgid "New ticket for %s" msgstr "" -#: judge/views/ticket.py:170 +#: judge/views/ticket.py:142 #, python-format msgid "%(title)s - Ticket %(id)d" msgstr "" -#: judge/views/ticket.py:279 +#: judge/views/ticket.py:251 #, python-format msgid "Tickets - Page %(number)d of %(total)d" msgstr "" -#: judge/views/ticket.py:328 +#: judge/views/ticket.py:300 #, python-format msgid "New Ticket: %s" msgstr "" -#: judge/views/ticket.py:329 +#: judge/views/ticket.py:301 #, python-format msgid "#%(id)d, assigned to: %(users)s" msgstr "" -#: judge/views/ticket.py:331 +#: judge/views/ticket.py:303 msgid ", " msgstr "" -#: judge/views/ticket.py:331 +#: judge/views/ticket.py:303 msgid "no one" msgstr "" -#: judge/views/ticket.py:351 +#: judge/views/ticket.py:323 #, python-format msgid "New Ticket Message For: %s" msgstr "" @@ -2925,50 +2810,41 @@ msgstr "" msgid "Perform Two Factor Authentication" msgstr "" -#: judge/views/user.py:74 +#: judge/views/user.py:68 msgid "No such user" msgstr "" -#: judge/views/user.py:74 +#: judge/views/user.py:68 #, python-format msgid "No user handle \"%s\"." msgstr "" -#: judge/views/user.py:78 +#: judge/views/user.py:72 msgid "My account" msgstr "" -#: judge/views/user.py:79 +#: judge/views/user.py:73 #, python-format msgid "User %s" msgstr "" -#: judge/views/user.py:148 -msgid "M j, Y" -msgstr "" - -#: judge/views/user.py:171 +#: judge/views/user.py:136 msgid "M j, Y, G:i" msgstr "" -#: judge/views/user.py:290 +#: judge/views/user.py:221 msgid "Updated on site" msgstr "" -#: judge/views/user.py:323 templates/admin/auth/user/change_form.html:14 -#: templates/admin/auth/user/change_form.html:17 templates/base.html:238 -#: templates/user/user-tabs.html:10 +#: judge/views/user.py:254 templates/admin/auth/user/change_form.html:14 +#: templates/admin/auth/user/change_form.html:17 templates/base.html:224 msgid "Edit profile" msgstr "" -#: judge/views/user.py:332 templates/user/user-list-tabs.html:4 +#: judge/views/user.py:263 msgid "Leaderboard" msgstr "" -#: judge/views/user.py:407 -msgid "Import Users" -msgstr "" - #: judge/views/widgets.py:48 judge/views/widgets.py:58 #, python-format msgid "Invalid upstream data: %s" @@ -3006,7 +2882,7 @@ msgid "View Submissions" msgstr "" #: templates/admin/judge/problem/change_form.html:17 -#: templates/user/user-base.html:112 +#: templates/user/user-base.html:61 msgid "View submissions" msgstr "" @@ -3021,145 +2897,90 @@ msgstr "" msgid "Rejudge" msgstr "" -#: templates/base.html:230 -#, python-format -msgid "Hello, %(username)s." -msgstr "" - -#: templates/base.html:236 templates/comments/list.html:89 -#: templates/contest/contest-list-tabs.html:24 -#: templates/contest/ranking-table.html:53 -#: templates/problem/problem-list-tabs.html:6 +#: templates/base.html:222 templates/comments/list.html:89 +#: templates/contest/ranking-table.html:39 #: templates/submission/info-base.html:12 -#: templates/submission/submission-list-tabs.html:15 msgid "Admin" msgstr "" -#: templates/base.html:245 +#: templates/base.html:231 msgid "Log out" msgstr "" -#: templates/base.html:254 +#: templates/base.html:240 #: templates/registration/password_reset_complete.html:4 msgid "Log in" msgstr "" -#: templates/base.html:255 templates/registration/registration_form.html:177 +#: templates/base.html:241 templates/registration/registration_form.html:177 msgid "or" msgstr "" -#: templates/base.html:256 +#: templates/base.html:242 msgid "Sign up" msgstr "" -#: templates/base.html:271 +#: templates/base.html:254 msgid "spectating" msgstr "" -#: templates/base.html:284 +#: templates/base.html:267 msgid "This site works best with JavaScript enabled." msgstr "" -#: templates/blog/blog.html:13 templates/comments/list.html:68 -#: templates/comments/list.html:83 templates/contest/contest-tabs.html:23 -#: templates/contest/tag-title.html:9 templates/flatpages/admin_link.html:3 -#: templates/license.html:10 templates/problem/editorial.html:14 +#: templates/blog/content.html:13 templates/comments/list.html:68 +#: templates/comments/list.html:83 templates/contest/tag-title.html:9 +#: templates/flatpages/admin_link.html:3 templates/license.html:10 +#: templates/problem/editorial.html:14 msgid "Edit" msgstr "" -#: templates/blog/blog.html:26 -#, python-format -msgid "" -"\n" -" posted on %(time)s\n" -" " -msgstr "" - -#: templates/blog/content.html:10 -#, python-brace-format -msgid "posted on {time}" -msgstr "" - -#: templates/blog/dashboard.html:21 -#, python-format -msgid "" -"\n" -" on %(time)s\n" -" " -msgstr "" - -#: templates/blog/list.html:93 +#: templates/blog/list.html:85 msgid "Blog" msgstr "" -#: templates/blog/list.html:95 +#: templates/blog/list.html:87 msgid "Events" msgstr "" -#: templates/blog/list.html:100 +#: templates/blog/list.html:92 msgid "News" msgstr "" -#: templates/blog/list.html:115 templates/problem/list.html:347 -#: templates/problem/problem.html:361 +#: templates/blog/list.html:130 templates/problem/problem.html:310 msgid "Clarifications" msgstr "" -#: templates/blog/list.html:121 -msgid "Add" -msgstr "" - -#: templates/blog/list.html:140 templates/problem/list.html:369 -#: templates/problem/problem.html:372 +#: templates/blog/list.html:146 templates/problem/problem.html:321 msgid "No clarifications have been made at this time." msgstr "" -#: templates/blog/list.html:148 +#: templates/blog/list.html:154 msgid "Ongoing contests" msgstr "" -#: templates/blog/list.html:166 +#: templates/blog/list.html:172 msgid "Upcoming contests" msgstr "" -#: templates/blog/list.html:184 -msgid "My open tickets" -msgstr "" - -#: templates/blog/list.html:206 -msgid "New tickets" -msgstr "" - -#: templates/blog/list.html:227 -msgid "New problems" -msgstr "" - -#: templates/blog/list.html:244 +#: templates/blog/list.html:189 msgid "Comment stream" msgstr "" -#: templates/chat/chat.html:305 -msgid "Chat" +#: templates/blog/list.html:208 +msgid "New problems" msgstr "" -#: templates/chat/chat.html:307 templates/chat/chat.html:314 -msgid "Online Users" +#: templates/blog/list.html:225 +msgid "My open tickets" msgstr "" -#: templates/chat/chat.html:315 -msgid "Refresh" +#: templates/blog/list.html:246 +msgid "New tickets" msgstr "" -#: templates/chat/chat.html:333 -msgid "Emoji" -msgstr "" - -#: templates/chat/chat.html:334 -msgid "Enter your message" -msgstr "" - -#: templates/chat/message.html:20 -msgid "Delete" +#: templates/chat/chat.html:167 +msgid "Your message" msgstr "" #: templates/comments/list.html:2 @@ -3170,21 +2991,11 @@ msgstr "" msgid "Please login to vote" msgstr "" -#: templates/comments/list.html:40 -#, python-brace-format -msgid "commented on {time}" -msgstr "" - -#: templates/comments/list.html:49 -#, python-format -msgid "edit %(edits)s" -msgstr "" - -#: templates/comments/list.html:51 templates/comments/media-js.html:92 +#: templates/comments/list.html:51 templates/comments/media-js.html:77 msgid "edited" msgstr "" -#: templates/comments/list.html:60 templates/notification/list.html:14 +#: templates/comments/list.html:60 msgid "Link" msgstr "" @@ -3192,52 +3003,36 @@ msgstr "" msgid "Reply" msgstr "" -#: templates/comments/list.html:86 templates/contest/list.html:91 -#: templates/contest/list.html:95 templates/contest/list.html:280 +#: templates/comments/list.html:86 msgid "Hide" msgstr "" -#: templates/comments/list.html:101 -#, python-format -msgid "" -"\n" -" This comment is hidden due " -"to too much negative feedback.\n" -" Click here to view it.\n" -" " -msgstr "" - -#: templates/comments/list.html:121 +#: templates/comments/list.html:120 msgid "There are no comments at the moment." msgstr "" -#: templates/comments/list.html:127 +#: templates/comments/list.html:126 msgid "New comment" msgstr "" -#: templates/comments/list.html:141 +#: templates/comments/list.html:140 msgid "Invalid comment body." msgstr "" -#: templates/comments/list.html:149 +#: templates/comments/list.html:148 msgid "Post!" msgstr "" -#: templates/comments/list.html:157 +#: templates/comments/list.html:156 msgid "Comments are disabled on this page." msgstr "" -#: templates/comments/media-js.html:38 -msgid "Replying to comment" -msgstr "" - -#: templates/comments/media-js.html:87 +#: templates/comments/media-js.html:72 #, python-brace-format msgid "edit {edits}" msgstr "" -#: templates/comments/media-js.html:90 +#: templates/comments/media-js.html:75 msgid "original" msgstr "" @@ -3281,11 +3076,6 @@ msgstr "" msgid "Saturday" msgstr "" -#: templates/contest/clarification.html:52 templates/organization/new.html:10 -#: templates/ticket/new.html:38 -msgid "Create" -msgstr "" - #: templates/contest/clone.html:37 msgid "Enter a new key for the cloned contest:" msgstr "" @@ -3306,171 +3096,97 @@ msgstr "" msgid "Next" msgstr "" -#: templates/contest/contest-list-tabs.html:21 -#: templates/problem/problem-list-tabs.html:5 -msgid "List" -msgstr "" - -#: templates/contest/contest-list-tabs.html:22 -msgid "Calendar" -msgstr "" - -#: templates/contest/contest-tabs.html:4 templates/organization/home.html:105 -msgid "Info" -msgstr "" - -#: templates/contest/contest-tabs.html:6 templates/stats/base.html:9 -#: templates/submission/list.html:339 -msgid "Statistics" -msgstr "" - -#: templates/contest/contest-tabs.html:11 -msgid "Rankings" -msgstr "" - -#: templates/contest/contest-tabs.html:16 -msgid "Hidden Rankings" -msgstr "" - -#: templates/contest/contest-tabs.html:21 -msgid "MOSS" -msgstr "" - -#: templates/contest/contest-tabs.html:26 -msgid "Clone" -msgstr "" - -#: templates/contest/contest-tabs.html:38 -#: templates/contest/contest-tabs.html:58 +#: templates/contest/contest-tabs.html:37 msgid "Leave contest" msgstr "" -#: templates/contest/contest-tabs.html:45 templates/contest/list.html:388 +#: templates/contest/contest-tabs.html:44 templates/contest/list.html:293 msgid "Virtual join" msgstr "" -#: templates/contest/contest-tabs.html:56 -msgid "Stop spectating" -msgstr "" - -#: templates/contest/contest-tabs.html:65 +#: templates/contest/contest-tabs.html:64 msgid "Spectate contest" msgstr "" -#: templates/contest/contest-tabs.html:72 +#: templates/contest/contest-tabs.html:70 +#: templates/contest/contest-tabs.html:76 msgid "Join contest" msgstr "" -#: templates/contest/contest-tabs.html:81 +#: templates/contest/contest-tabs.html:85 msgid "Login to participate" msgstr "" -#: templates/contest/contest.html:37 -msgid "Participating virtually." -msgstr "" - -#: templates/contest/contest.html:43 -msgid "Contest is over." -msgstr "" - #: templates/contest/contest.html:59 templates/contest/contest.html:63 msgid "F j, Y, G:i T" msgstr "" -#: templates/contest/contest.html:59 -#, python-format -msgid "" -"%(time_limit)s window between %(start_time)s and " -"%(end_time)s" -msgstr "" - -#: templates/contest/contest.html:63 -#, python-format -msgid "%(length)s long starting on %(start_time)s" -msgstr "" - #: templates/contest/contest.html:85 msgid "AC Rate" msgstr "" -#: templates/contest/contest.html:86 templates/contest/list.html:237 -#: templates/contest/list.html:289 templates/contest/list.html:366 -#: templates/problem/list.html:223 templates/problem/list.html:254 +#: templates/contest/contest.html:86 templates/contest/list.html:153 +#: templates/contest/list.html:195 templates/contest/list.html:271 +#: templates/problem/list.html:212 templates/problem/list.html:238 msgid "Users" msgstr "" -#: templates/contest/contest.html:111 templates/problem/list.html:330 +#: templates/contest/contest.html:111 msgid "Editorial" msgstr "" -#: templates/contest/list.html:83 templates/contest/media-js.html:9 +#: templates/contest/list.html:31 templates/contest/media-js.html:9 msgid "Are you sure you want to join?" msgstr "" -#: templates/contest/list.html:84 +#: templates/contest/list.html:32 msgid "" "Joining a contest for the first time starts your timer, after which it " "becomes unstoppable." msgstr "" -#: templates/contest/list.html:92 templates/contest/list.html:278 -msgid "Show" -msgstr "" - -#: templates/contest/list.html:102 templates/problem/list.html:68 -msgid "Organizations..." -msgstr "" - -#: templates/contest/list.html:135 +#: templates/contest/list.html:65 msgid "hidden" msgstr "" -#: templates/contest/list.html:140 +#: templates/contest/list.html:70 msgid "private" msgstr "" -#: templates/contest/list.html:154 +#: templates/contest/list.html:84 msgid "rated" msgstr "" -#: templates/contest/list.html:202 +#: templates/contest/list.html:132 msgid "Spectate" msgstr "" -#: templates/contest/list.html:208 +#: templates/contest/list.html:138 msgid "Join" msgstr "" -#: templates/contest/list.html:220 -msgid "Search contests..." -msgstr "" - -#: templates/contest/list.html:229 -msgid "Search" -msgstr "" - -#: templates/contest/list.html:232 +#: templates/contest/list.html:148 msgid "Active Contests" msgstr "" -#: templates/contest/list.html:236 templates/contest/list.html:288 -#: templates/contest/list.html:327 templates/contest/list.html:365 +#: templates/contest/list.html:152 templates/contest/list.html:194 +#: templates/contest/list.html:232 templates/contest/list.html:270 msgid "Contest" msgstr "" -#: templates/contest/list.html:275 +#: templates/contest/list.html:190 msgid "Ongoing Contests" msgstr "" -#: templates/contest/list.html:322 +#: templates/contest/list.html:227 msgid "Upcoming Contests" msgstr "" -#: templates/contest/list.html:350 +#: templates/contest/list.html:255 msgid "There are no scheduled contests at this time." msgstr "" -#: templates/contest/list.html:356 +#: templates/contest/list.html:261 msgid "Past Contests" msgstr "" @@ -3521,71 +3237,47 @@ msgstr "" msgid "Only the following organizations may access this contest:" msgstr "" -#: templates/contest/ranking-table.html:9 templates/problem/search-form.html:35 +#: templates/contest/ranking-table.html:7 msgid "Organization" msgstr "" -#: templates/contest/ranking-table.html:10 templates/user/users-table.html:13 -msgid "Full Name" -msgstr "" - -#: templates/contest/ranking-table.html:44 +#: templates/contest/ranking-table.html:30 msgid "Un-Disqualify" msgstr "" -#: templates/contest/ranking-table.html:47 +#: templates/contest/ranking-table.html:33 msgid "Disqualify" msgstr "" -#: templates/contest/ranking.html:187 +#: templates/contest/ranking.html:173 msgid "Are you sure you want to disqualify this participation?" msgstr "" -#: templates/contest/ranking.html:192 +#: templates/contest/ranking.html:178 msgid "Are you sure you want to un-disqualify this participation?" msgstr "" -#: templates/contest/ranking.html:463 +#: templates/contest/ranking.html:252 msgid "View user participation" msgstr "" -#: templates/contest/ranking.html:467 +#: templates/contest/ranking.html:256 msgid "Show organizations" msgstr "" -#: templates/contest/ranking.html:471 -msgid "Show full name" -msgstr "" - -#: templates/contest/ranking.html:474 -msgid "Show friends only" -msgstr "" - -#: templates/contest/ranking.html:477 -msgid "Total score only" -msgstr "" - -#: templates/contest/ranking.html:479 -msgid "Show virtual participation" -msgstr "" - -#: templates/contest/stats.html:51 +#: templates/contest/stats.html:38 msgid "Problem Status Distribution" msgstr "" -#: templates/contest/stats.html:56 +#: templates/contest/stats.html:43 msgid "Problem AC Rate" msgstr "" -#: templates/contest/stats.html:62 -msgid "Problem Point Distribution" -msgstr "" - -#: templates/contest/stats.html:76 templates/stats/language.html:16 +#: templates/contest/stats.html:48 templates/stats/language.html:16 msgid "Submissions by Language" msgstr "" -#: templates/contest/stats.html:82 templates/stats/language.html:26 +#: templates/contest/stats.html:54 templates/stats/language.html:26 msgid "Language AC Rate" msgstr "" @@ -3594,7 +3286,6 @@ msgid "Source:" msgstr "" #: templates/newsletter/common.html:6 -#: templates/newsletter/newsletter_list.html:15 #: templates/newsletter/subscription_unsubscribe_activated.html:3 #: templates/newsletter/subscription_unsubscribe_activated.html:6 #: templates/newsletter/subscription_update_activated.html:3 @@ -3602,23 +3293,6 @@ msgstr "" msgid "Newsletter" msgstr "" -#: templates/newsletter/newsletter_list.html:2 -#: templates/newsletter/newsletter_list.html:3 -msgid "Newsletter list" -msgstr "" - -#: templates/newsletter/newsletter_list.html:6 -msgid "Subscribe to get the latest emails about upcoming contests and events." -msgstr "" - -#: templates/newsletter/newsletter_list.html:16 -msgid "Subscribe" -msgstr "" - -#: templates/newsletter/newsletter_list.html:30 -msgid "Update subscriptions" -msgstr "" - #: templates/newsletter/subscription_unsubscribe_activated.html:3 #: templates/newsletter/subscription_unsubscribe_activated.html:6 #: templates/newsletter/subscription_update_activated.html:3 @@ -3680,97 +3354,64 @@ msgid "" "follow in order to update your subscription." msgstr "" -#: templates/notification/list.html:7 -msgid "You have no notifications" -msgstr "" - -#: templates/notification/list.html:13 -msgid "Activity" -msgstr "" - #: templates/organization/edit.html:46 #: templates/organization/requests/pending.html:34 #: templates/ticket/edit-notes.html:4 msgid "Update" msgstr "" -#: templates/organization/home.html:41 +#: templates/organization/home.html:7 msgid "Are you sure you want to leave this organization?" msgstr "" -#: templates/organization/home.html:43 +#: templates/organization/home.html:9 msgid "You will have to rejoin to show up on the organization leaderboard." msgstr "" -#: templates/organization/home.html:45 +#: templates/organization/home.html:11 msgid "You will have to request membership in order to join again." msgstr "" -#: templates/organization/home.html:88 -msgid "Join organization" -msgstr "" - -#: templates/organization/home.html:92 -msgid "Request membership" -msgstr "" - -#: templates/organization/home.html:122 -msgid "Organization news" -msgstr "" - -#: templates/organization/home.html:128 -msgid "There is no news at this time." -msgstr "" - -#: templates/organization/home.html:137 -msgid "Controls" -msgstr "" - -#: templates/organization/home.html:142 -msgid "Edit organization" -msgstr "" - -#: templates/organization/home.html:148 -msgid "View requests" -msgstr "" - -#: templates/organization/home.html:161 -msgid "Admin organization" -msgstr "" - -#: templates/organization/home.html:167 -msgid "View members" -msgstr "" - -#: templates/organization/home.html:174 +#: templates/organization/home.html:24 msgid "Leave organization" msgstr "" -#: templates/organization/home.html:183 -msgid "New private contests" +#: templates/organization/home.html:29 +msgid "Join organization" msgstr "" -#: templates/organization/home.html:193 templates/organization/home.html:208 -msgid "View all" +#: templates/organization/home.html:33 +msgid "Request membership" msgstr "" -#: templates/organization/home.html:199 -msgid "New private problems" +#: templates/organization/home.html:39 +msgid "Edit organization" msgstr "" -#: templates/organization/list.html:40 -msgid "Show my organizations only" +#: templates/organization/home.html:43 +msgid "View requests" msgstr "" -#: templates/organization/list.html:47 templates/status/language-list.html:34 -#: templates/user/import/table_csv.html:6 +#: templates/organization/home.html:50 +msgid "Admin organization" +msgstr "" + +#: templates/organization/home.html:55 +msgid "View members" +msgstr "" + +#: templates/organization/list.html:23 templates/status/language-list.html:34 msgid "Name" msgstr "" -#: templates/organization/list.html:48 +#: templates/organization/list.html:24 msgid "Members" msgstr "" +#: templates/organization/new.html:10 templates/ticket/new.html:38 +msgid "Create" +msgstr "" + #: templates/organization/requests/detail.html:13 msgid "User:" msgstr "" @@ -3803,7 +3444,7 @@ msgid "There are no requests to approve." msgstr "" #: templates/organization/requests/pending.html:17 -#: templates/problem/data.html:432 +#: templates/problem/data.html:452 msgid "Delete?" msgstr "" @@ -3839,35 +3480,35 @@ msgstr "" msgid "Enter a new code for the cloned problem:" msgstr "" -#: templates/problem/data.html:119 +#: templates/problem/data.html:108 msgid "Instruction" msgstr "" -#: templates/problem/data.html:390 +#: templates/problem/data.html:410 msgid "View YAML" msgstr "" -#: templates/problem/data.html:421 templates/problem/data.html:472 +#: templates/problem/data.html:441 templates/problem/data.html:491 msgid "Apply!" msgstr "" -#: templates/problem/data.html:426 +#: templates/problem/data.html:446 msgid "Type" msgstr "" -#: templates/problem/data.html:427 +#: templates/problem/data.html:447 msgid "Input file" msgstr "" -#: templates/problem/data.html:428 +#: templates/problem/data.html:448 msgid "Output file" msgstr "" -#: templates/problem/data.html:430 +#: templates/problem/data.html:450 msgid "Pretest?" msgstr "" -#: templates/problem/data.html:473 +#: templates/problem/data.html:492 msgid "Add new case" msgstr "" @@ -3879,32 +3520,28 @@ msgid "" "problem yourself is a bannable offence." msgstr "" -#: templates/problem/list.html:66 +#: templates/problem/list.html:62 msgid "Filter by type..." msgstr "" -#: templates/problem/list.html:193 +#: templates/problem/list.html:185 msgid "Hot problems" msgstr "" -#: templates/problem/list.html:218 templates/problem/list.html:240 -#: templates/problem/search-form.html:45 templates/user/user-problems.html:57 +#: templates/problem/list.html:207 templates/problem/list.html:224 +#: templates/problem/search-form.html:30 templates/user/user-problems.html:57 msgid "Category" msgstr "" -#: templates/problem/list.html:220 templates/problem/list.html:244 +#: templates/problem/list.html:209 templates/problem/list.html:228 msgid "Types" msgstr "" -#: templates/problem/list.html:251 +#: templates/problem/list.html:235 #, python-format msgid "AC %%" msgstr "" -#: templates/problem/list.html:342 -msgid "Add clarifications" -msgstr "" - #: templates/problem/manage_submission.html:55 msgid "Leave empty to not filter by language" msgstr "" @@ -3913,199 +3550,152 @@ msgstr "" msgid "Leave empty to not filter by result" msgstr "" -#: templates/problem/manage_submission.html:80 +#: templates/problem/manage_submission.html:79 msgid "Need valid values for both start and end IDs." msgstr "" -#: templates/problem/manage_submission.html:83 +#: templates/problem/manage_submission.html:82 msgid "End ID must be after start ID." msgstr "" +#: templates/problem/manage_submission.html:90 +#, python-brace-format +msgid "" +"You are about to rejudge {count} submissions. Are you sure you want to do " +"this?" +msgstr "" + #: templates/problem/manage_submission.html:96 -#, python-brace-format msgid "" -"You are about to {action} {count} submissions. Are you sure you want to do " -"this?" +"You are about to rejudge a few submissions. Are you sure you want to do this?" msgstr "" -#: templates/problem/manage_submission.html:103 -#, python-brace-format -msgid "" -"You are about to {action} a few submissions. Are you sure you want to do " -"this?" +#: templates/problem/manage_submission.html:115 +msgid "Rejudge Submissions" msgstr "" -#: templates/problem/manage_submission.html:127 -#: templates/submission/list.html:309 -msgid "Filter submissions" -msgstr "" - -#: templates/problem/manage_submission.html:132 +#: templates/problem/manage_submission.html:120 msgid "Filter by ID:" msgstr "" -#: templates/problem/manage_submission.html:135 +#: templates/problem/manage_submission.html:123 msgid "Starting ID:" msgstr "" -#: templates/problem/manage_submission.html:139 +#: templates/problem/manage_submission.html:127 msgid "Ending ID:" msgstr "" -#: templates/problem/manage_submission.html:143 +#: templates/problem/manage_submission.html:131 msgid "This range includes both endpoints." msgstr "" -#: templates/problem/manage_submission.html:146 +#: templates/problem/manage_submission.html:134 msgid "Filter by language:" msgstr "" -#: templates/problem/manage_submission.html:154 +#: templates/problem/manage_submission.html:142 msgid "Filter by result:" msgstr "" -#: templates/problem/manage_submission.html:164 -msgid "Action" -msgstr "" - -#: templates/problem/manage_submission.html:166 +#: templates/problem/manage_submission.html:150 msgid "Rejudge selected submissions" msgstr "" -#: templates/problem/manage_submission.html:171 -msgid "Download selected submissions" +#: templates/problem/manage_submission.html:157 +msgid "Rescore Everything" msgstr "" -#: templates/problem/manage_submission.html:177 -#, python-format -msgid "Are you sure you want to rescore %(count)d submissions?" -msgstr "" - -#: templates/problem/manage_submission.html:178 +#: templates/problem/manage_submission.html:163 msgid "Rescore all submissions" msgstr "" -#: templates/problem/problem.html:132 +#: templates/problem/problem.html:91 msgid "View as PDF" msgstr "" -#: templates/problem/problem.html:141 templates/problem/problem.html:151 -#: templates/problem/problem.html:156 +#: templates/problem/problem.html:101 templates/problem/problem.html:111 +#: templates/problem/problem.html:116 msgid "Submit solution" msgstr "" -#: templates/problem/problem.html:144 -#, python-format -msgid "%(counter)s submission left" -msgid_plural "%(counter)s submissions left" -msgstr[0] "" -msgstr[1] "" - -#: templates/problem/problem.html:152 +#: templates/problem/problem.html:112 msgid "0 submissions left" msgstr "" -#: templates/problem/problem.html:164 +#: templates/problem/problem.html:124 msgid "My submissions" msgstr "" -#: templates/problem/problem.html:168 +#: templates/problem/problem.html:128 msgid "Best submissions" msgstr "" -#: templates/problem/problem.html:172 +#: templates/problem/problem.html:132 msgid "Read editorial" msgstr "" -#: templates/problem/problem.html:177 +#: templates/problem/problem.html:137 msgid "Manage tickets" msgstr "" -#: templates/problem/problem.html:181 +#: templates/problem/problem.html:141 msgid "Edit problem" msgstr "" -#: templates/problem/problem.html:183 +#: templates/problem/problem.html:143 msgid "Edit test data" msgstr "" -#: templates/problem/problem.html:188 +#: templates/problem/problem.html:148 msgid "My tickets" msgstr "" -#: templates/problem/problem.html:196 +#: templates/problem/problem.html:156 msgid "Manage submissions" msgstr "" -#: templates/problem/problem.html:202 +#: templates/problem/problem.html:162 msgid "Clone problem" msgstr "" -#: templates/problem/problem.html:209 +#: templates/problem/problem.html:169 msgid "Points:" msgstr "" -#: templates/problem/problem.html:212 templates/problem/problem.html:214 +#: templates/problem/problem.html:172 templates/problem/problem.html:174 msgid "(partial)" msgstr "" -#: templates/problem/problem.html:219 +#: templates/problem/problem.html:179 msgid "Time limit:" msgstr "" -#: templates/problem/problem.html:231 +#: templates/problem/problem.html:191 msgid "Memory limit:" msgstr "" -#: templates/problem/problem.html:250 -msgid "Author:" -msgid_plural "Authors:" -msgstr[0] "" -msgstr[1] "" - -#: templates/problem/problem.html:265 -msgid "Problem type" -msgid_plural "Problem types" -msgstr[0] "" -msgstr[1] "" - -#: templates/problem/problem.html:278 +#: templates/problem/problem.html:238 msgid "Allowed languages" msgstr "" -#: templates/problem/problem.html:286 -#, python-format -msgid "No %(lang)s judge online" -msgstr "" - -#: templates/problem/problem.html:297 -msgid "Judge:" -msgid_plural "Judges:" -msgstr[0] "" -msgstr[1] "" - -#: templates/problem/problem.html:314 +#: templates/problem/problem.html:274 msgid "none available" msgstr "" -#: templates/problem/problem.html:326 -#, python-format -msgid "This problem has %(length)s clarification(s)" -msgstr "" - -#: templates/problem/problem.html:350 +#: templates/problem/problem.html:299 msgid "Request clarification" msgstr "" -#: templates/problem/problem.html:352 +#: templates/problem/problem.html:301 msgid "Report an issue" msgstr "" -#: templates/problem/raw.html:64 +#: templates/problem/raw.html:62 msgid "Time Limit:" msgstr "" -#: templates/problem/raw.html:73 +#: templates/problem/raw.html:71 msgid "Memory Limit:" msgstr "" @@ -4129,73 +3719,39 @@ msgstr "" msgid "Show problem types" msgstr "" -#: templates/problem/search-form.html:32 -msgid "Show editorial" -msgstr "" - -#: templates/problem/search-form.html:48 templates/problem/search-form.html:50 -#: templates/submission/submission-list-tabs.html:4 +#: templates/problem/search-form.html:33 templates/problem/search-form.html:35 msgid "All" msgstr "" -#: templates/problem/search-form.html:62 +#: templates/problem/search-form.html:46 msgid "Problem types" msgstr "" -#: templates/problem/search-form.html:73 +#: templates/problem/search-form.html:57 msgid "Point range" msgstr "" -#: templates/problem/search-form.html:79 templates/submission/list.html:331 +#: templates/problem/search-form.html:63 templates/submission/list.html:331 #: templates/ticket/list.html:248 msgid "Go" msgstr "" -#: templates/problem/search-form.html:80 +#: templates/problem/search-form.html:64 msgid "Random" msgstr "" -#: templates/problem/submit.html:117 -msgid "Your source code must contain at most 65536 characters." -msgstr "" - -#: templates/problem/submit.html:204 -#, python-format -msgid "" -"Warning! Your default language, %(default_language)s, is " -"unavailable for this problem and has been deselected." -msgstr "" - -#: templates/problem/submit.html:215 -#, python-format -msgid "" -"\n" -" You have %(left)s submission left\n" -" " -msgid_plural "" -"\n" -" You have %(left)s submissions left\n" -" " -msgstr[0] "" -msgstr[1] "" - -#: templates/problem/submit.html:224 +#: templates/problem/submit.html:212 msgid "You have 0 submissions left" msgstr "" -#: templates/problem/submit.html:258 +#: templates/problem/submit.html:250 msgid "No judge is available for this problem." msgstr "" -#: templates/problem/submit.html:262 +#: templates/problem/submit.html:252 msgid "Submit!" msgstr "" -#: templates/registration/activate.html:3 -#, python-format -msgid "%(key)s is an invalid activation key." -msgstr "" - #: templates/registration/activation_complete.html:3 msgid "Your account has been successfully activated." msgstr "" @@ -4253,13 +3809,6 @@ msgid "" "you registered with, and check your spam folder." msgstr "" -#: templates/registration/password_reset_email.txt:1 -#, python-format -msgid "" -"You're receiving this email because you requested a password reset for your " -"user account at %(site_name)s." -msgstr "" - #: templates/registration/password_reset_email.txt:3 msgid "Please go to the following page and choose a new password:" msgstr "" @@ -4272,16 +3821,6 @@ msgstr "" msgid "Thanks for using our site!" msgstr "" -#: templates/registration/password_reset_email.txt:11 -#, python-format -msgid "The %(site_name)s team" -msgstr "" - -#: templates/registration/password_reset_subject.txt:1 -#, python-format -msgid "Password reset on %(site_name)s" -msgstr "" - #: templates/registration/profile_creation.html:36 #: templates/registration/username_select.html:7 msgid "Continue >" @@ -4318,20 +3857,19 @@ msgstr "" msgid "Affiliated organizations" msgstr "" -#: templates/registration/registration_form.html:195 -#: templates/user/edit-profile.html:128 +#: templates/registration/registration_form.html:192 msgid "Notify me about upcoming contests" msgstr "" -#: templates/registration/registration_form.html:209 +#: templates/registration/registration_form.html:206 msgid "By registering, you agree to our" msgstr "" -#: templates/registration/registration_form.html:210 +#: templates/registration/registration_form.html:207 msgid "Terms & Conditions" msgstr "" -#: templates/registration/registration_form.html:213 +#: templates/registration/registration_form.html:210 msgid "Register!" msgstr "" @@ -4341,11 +3879,6 @@ msgstr "" msgid "Enter the 6-digit code generated by your app:" msgstr "" -#: templates/registration/totp_auth.html:41 -#, python-format -msgid "If you lost your authentication device, please contact us at %(email)s." -msgstr "" - #: templates/registration/totp_disable.html:38 msgid "" "To protect your account, you must first authenticate before you can disable " @@ -4364,6 +3897,10 @@ msgstr "" msgid "Or enter this code manually:" msgstr "" +#: templates/stats/base.html:9 templates/submission/list.html:339 +msgid "Statistics" +msgstr "" + #: templates/stats/language.html:11 msgid "Submission Statistics" msgstr "" @@ -4389,7 +3926,6 @@ msgid "Ping" msgstr "" #: templates/status/judge-status-table.html:8 -#: templates/user/import/index.html:104 msgid "Load" msgstr "" @@ -4405,7 +3941,6 @@ msgid "There are no judges available at this time." msgstr "" #: templates/status/language-list.html:33 templates/ticket/list.html:261 -#: templates/user/import/table_csv.html:3 msgid "ID" msgstr "" @@ -4413,22 +3948,6 @@ msgstr "" msgid "Runtime Info" msgstr "" -#: templates/status/status-tabs.html:4 -msgid "Judges" -msgstr "" - -#: templates/status/status-tabs.html:6 -msgid "Version Matrix" -msgstr "" - -#: templates/submission/internal-error-message.html:3 -#, python-format -msgid "" -"An internal error occurred while grading, and the %(SITE_NAME)s " -"administrators have been notified.
In the meantime, try resubmitting in " -"a few seconds." -msgstr "" - #: templates/submission/internal-error-message.html:8 msgid "An internal error occurred while grading." msgstr "" @@ -4445,6 +3964,10 @@ msgstr "" msgid "Filter by language..." msgstr "" +#: templates/submission/list.html:309 +msgid "Filter submissions" +msgstr "" + #: templates/submission/list.html:345 msgid "Total:" msgstr "" @@ -4501,64 +4024,63 @@ msgstr "" msgid "Execution Results" msgstr "" -#: templates/submission/status-testcases.html:34 -msgid "Overall: " -msgstr "" - -#: templates/submission/status-testcases.html:48 -msgid "Point: " -msgstr "" - -#: templates/submission/status-testcases.html:53 -msgid "Time: " -msgstr "" - -#: templates/submission/status-testcases.html:62 -msgid "Memory: " -msgstr "" - -#: templates/submission/status-testcases.html:73 +#: templates/submission/status-testcases.html:31 msgid "Batch " msgstr "" -#: templates/submission/status-testcases.html:84 -#: templates/submission/status-testcases.html:113 -msgid "Point" +#: templates/submission/status-testcases.html:43 +msgid "Overall: " msgstr "" -#: templates/submission/status-testcases.html:99 +#: templates/submission/status-testcases.html:57 +msgid "Point: " +msgstr "" + +#: templates/submission/status-testcases.html:62 +msgid "Time: " +msgstr "" + +#: templates/submission/status-testcases.html:71 +msgid "Memory: " +msgstr "" + +#: templates/submission/status-testcases.html:84 msgid "Case" msgstr "" -#: templates/submission/status-testcases.html:101 +#: templates/submission/status-testcases.html:86 msgid "Pretest" msgstr "" -#: templates/submission/status-testcases.html:103 +#: templates/submission/status-testcases.html:88 msgid "Test case" msgstr "" -#: templates/submission/status-testcases.html:141 +#: templates/submission/status-testcases.html:99 +msgid "Point" +msgstr "" + +#: templates/submission/status-testcases.html:121 msgid "Input:" msgstr "" -#: templates/submission/status-testcases.html:145 +#: templates/submission/status-testcases.html:125 msgid "Output:" msgstr "" -#: templates/submission/status-testcases.html:149 +#: templates/submission/status-testcases.html:129 msgid "Answer:" msgstr "" -#: templates/submission/status-testcases.html:154 +#: templates/submission/status-testcases.html:134 msgid "Judge feedback:" msgstr "" -#: templates/submission/status-testcases.html:175 +#: templates/submission/status-testcases.html:157 msgid "Passing pretests does not guarantee a full score on system tests." msgstr "" -#: templates/submission/status-testcases.html:178 +#: templates/submission/status-testcases.html:160 msgid "Submission aborted!" msgstr "" @@ -4570,24 +4092,11 @@ msgstr "" msgid "Abort" msgstr "" -#: templates/submission/submission-list-tabs.html:6 -msgid "Mine" -msgstr "" - -#: templates/submission/submission-list-tabs.html:9 -msgid "Best" -msgstr "" - -#: templates/submission/submission-list-tabs.html:12 -#, python-format -msgid "%(user)s's" -msgstr "" - -#: templates/ticket/list.html:135 templates/ticket/ticket.html:273 +#: templates/ticket/list.html:135 templates/ticket/ticket.html:257 msgid "Reopened: " msgstr "" -#: templates/ticket/list.html:138 templates/ticket/ticket.html:274 +#: templates/ticket/list.html:138 templates/ticket/ticket.html:258 msgid "Closed: " msgstr "" @@ -4611,7 +4120,7 @@ msgstr "" msgid "Title" msgstr "" -#: templates/ticket/list.html:264 templates/ticket/ticket.html:369 +#: templates/ticket/list.html:264 templates/ticket/ticket.html:328 msgid "Assignees" msgstr "" @@ -4626,36 +4135,32 @@ msgid "" "a problem, ask in the comments instead." msgstr "" -#: templates/ticket/ticket.html:355 -msgid "Post" -msgstr "" - -#: templates/ticket/ticket.html:363 +#: templates/ticket/ticket.html:322 msgid "Associated object" msgstr "" -#: templates/ticket/ticket.html:374 +#: templates/ticket/ticket.html:333 msgid "No one is assigned." msgstr "" -#: templates/ticket/ticket.html:380 +#: templates/ticket/ticket.html:339 msgid "Close ticket" msgstr "" -#: templates/ticket/ticket.html:382 +#: templates/ticket/ticket.html:341 msgid "Reopen ticket" msgstr "" -#: templates/ticket/ticket.html:386 +#: templates/ticket/ticket.html:345 msgid "Assignee notes" msgstr "" -#: templates/ticket/ticket.html:393 templates/widgets/select_all.html:4 +#: templates/ticket/ticket.html:352 templates/widgets/select_all.html:4 msgid "Nothing here." msgstr "" -#: templates/user/base-users-table.html:3 -msgid "Rank" +#: templates/ticket/ticket.html:385 +msgid "Post" msgstr "" #: templates/user/base-users.html:14 templates/user/base-users.html:69 @@ -4702,168 +4207,50 @@ msgstr "" msgid "Update profile" msgstr "" -#: templates/user/import/index.html:31 -msgid "Upload CSV only" -msgstr "" - -#: templates/user/import/index.html:100 -msgid "User File" -msgstr "" - -#: templates/user/import/index.html:102 -msgid "Sample" -msgstr "" - -#: templates/user/import/index.html:105 templates/user/user-list-tabs.html:8 -msgid "Import" -msgstr "" - -#: templates/user/import/table_csv.html:7 -msgid "School" -msgstr "" - -#: templates/user/pp-row.html:22 -#, python-format -msgid "" -"\n" -" weighted %(weight)s%%\n" -" " -msgstr "" - -#: templates/user/pp-row.html:27 -#, python-format -msgid "%(pp).1fpp" -msgstr "" - -#: templates/user/pp-row.html:29 -#, python-format -msgid "%(pp).0fpp" -msgstr "" - -#: templates/user/user-about.html:23 -#, python-format -msgid "%(counter)s problem solved" -msgid_plural "%(counter)s problems solved" -msgstr[0] "" -msgstr[1] "" - -#: templates/user/user-about.html:35 -msgid "Total points" -msgstr "" - -#: templates/user/user-about.html:45 -msgid "Rank by rating" -msgstr "" - -#: templates/user/user-about.html:52 -msgid "Rank by points" -msgstr "" - -#: templates/user/user-about.html:64 +#: templates/user/user-about.html:14 msgid "From" msgstr "" -#: templates/user/user-about.html:75 +#: templates/user/user-about.html:25 msgid "Admin Notes" msgstr "" -#: templates/user/user-about.html:90 +#: templates/user/user-about.html:40 msgid "You have not shared any information." msgstr "" -#: templates/user/user-about.html:92 +#: templates/user/user-about.html:42 msgid "This user has not shared any information." msgstr "" -#: templates/user/user-about.html:101 -msgid "Awards" +#: templates/user/user-base.html:50 +msgid "Rank by points:" msgstr "" -#: templates/user/user-about.html:112 -#, python-format -msgid "%(label)s (%(date)s)" +#: templates/user/user-base.html:53 +msgid "Total points:" msgstr "" -#: templates/user/user-about.html:130 -msgid "Mon" +#: templates/user/user-base.html:68 +msgid "Rank by rating:" msgstr "" -#: templates/user/user-about.html:135 -msgid "Tues" +#: templates/user/user-base.html:70 +msgid "Rating:" msgstr "" -#: templates/user/user-about.html:140 -msgid "Wed" -msgstr "" - -#: templates/user/user-about.html:145 -msgid "Thurs" -msgstr "" - -#: templates/user/user-about.html:150 -msgid "Fri" -msgstr "" - -#: templates/user/user-about.html:155 -msgid "Sat" -msgstr "" - -#: templates/user/user-about.html:160 -msgid "Sun" -msgstr "" - -#: templates/user/user-about.html:169 -msgid "Less" -msgstr "" - -#: templates/user/user-about.html:175 -msgid "More" -msgstr "" - -#: templates/user/user-about.html:184 -msgid "Rating History" -msgstr "" - -#: templates/user/user-about.html:255 -msgid "past year" -msgstr "" - -#: templates/user/user-about.html:272 -msgid "total submission(s)" -msgstr "" - -#: templates/user/user-about.html:276 -msgid "submissions in the last year" -msgstr "" - -#: templates/user/user-base.html:101 -msgid "Unfollow" -msgstr "" - -#: templates/user/user-base.html:104 -msgid "Follow" -msgstr "" - -#: templates/user/user-base.html:120 -msgid "Contests written" -msgstr "" - -#: templates/user/user-base.html:124 +#: templates/user/user-base.html:71 msgid "Volatility:" msgstr "" -#: templates/user/user-base.html:128 +#: templates/user/user-base.html:72 msgid "Min. rating:" msgstr "" -#: templates/user/user-base.html:132 +#: templates/user/user-base.html:73 msgid "Max rating:" msgstr "" -#: templates/user/user-list-tabs.html:5 -msgid "Friends" -msgstr "" - #: templates/user/user-problems.html:35 msgid "Points Breakdown" msgstr "" @@ -4884,32 +4271,10 @@ msgstr "" msgid "Hide problems I've solved" msgstr "" -#: templates/user/user-problems.html:93 -#, python-format -msgid "%(points).1f points" -msgstr "" - #: templates/user/user-problems.html:99 msgid "Score" msgstr "" -#: templates/user/user-problems.html:110 -#, python-format -msgid "%(points)s / %(total)s" -msgstr "" - -#: templates/user/user-tabs.html:7 -msgid "Impersonate" -msgstr "" - -#: templates/user/user-tabs.html:13 -msgid "Admin User" -msgstr "" - -#: templates/user/user-tabs.html:16 -msgid "Admin Profile" -msgstr "" - #: templates/widgets/select_all.html:8 msgid "Check all" msgstr "" diff --git a/locale/en/LC_MESSAGES/djangojs.po b/locale/en/LC_MESSAGES/djangojs.po index fbc97b5..2396075 100644 --- a/locale/en/LC_MESSAGES/djangojs.po +++ b/locale/en/LC_MESSAGES/djangojs.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-07-20 23:30+0700\n" +"POT-Creation-Date: 2018-08-21 17:54-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -18,14 +18,14 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: resources/common.js:207 +#: .\resources\common.js:203 msgctxt "time format with day" msgid "%d day %h:%m:%s" msgid_plural "%d days %h:%m:%s" msgstr[0] "" msgstr[1] "" -#: resources/common.js:210 +#: .\resources\common.js:206 msgctxt "time format without day" msgid "%h:%m:%s" msgstr "" diff --git a/locale/es/LC_MESSAGES/django.po b/locale/es/LC_MESSAGES/django.po index d03046a..37a4c3c 100644 --- a/locale/es/LC_MESSAGES/django.po +++ b/locale/es/LC_MESSAGES/django.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: dmoj\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-10-25 05:59+0700\n" +"POT-Creation-Date: 2020-04-10 01:26-0500\n" "PO-Revision-Date: 2019-11-11 22:06\n" "Last-Translator: Icyene\n" "Language-Team: Spanish\n" @@ -16,93 +16,93 @@ msgstr "" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: django.po\n" -#: chat_box/models.py:16 judge/admin/interface.py:110 -#: judge/models/contest.py:403 judge/models/contest.py:528 -#: judge/models/profile.py:211 +#: chat_box/models.py:15 judge/admin/interface.py:107 +#: judge/models/contest.py:257 judge/models/contest.py:381 +#: judge/models/profile.py:191 msgid "user" msgstr "usuario" -#: chat_box/models.py:17 judge/models/comment.py:43 judge/models/comment.py:191 +#: chat_box/models.py:16 judge/models/comment.py:42 msgid "posted time" msgstr "hora de publicación" -#: chat_box/models.py:18 judge/models/comment.py:47 +#: chat_box/models.py:17 judge/models/comment.py:46 msgid "body of comment" msgstr "cuerpo del comentario" -#: chat_box/views.py:29 templates/chat/chat.html:4 +#: chat_box/views.py:29 msgid "Chat Box" msgstr "" -#: dmoj/settings.py:355 +#: dmoj/settings.py:349 msgid "German" msgstr "Alemán" -#: dmoj/settings.py:356 +#: dmoj/settings.py:350 msgid "English" msgstr "Inglés" -#: dmoj/settings.py:357 +#: dmoj/settings.py:351 msgid "Spanish" msgstr "Español" -#: dmoj/settings.py:358 +#: dmoj/settings.py:352 msgid "French" msgstr "Francés" -#: dmoj/settings.py:359 +#: dmoj/settings.py:353 msgid "Croatian" msgstr "Croata" -#: dmoj/settings.py:360 +#: dmoj/settings.py:354 msgid "Hungarian" msgstr "Húngaro" -#: dmoj/settings.py:361 +#: dmoj/settings.py:355 msgid "Japanese" msgstr "" -#: dmoj/settings.py:362 +#: dmoj/settings.py:356 msgid "Korean" msgstr "Coreano" -#: dmoj/settings.py:363 +#: dmoj/settings.py:357 msgid "Brazilian Portuguese" msgstr "" -#: dmoj/settings.py:364 +#: dmoj/settings.py:358 msgid "Romanian" msgstr "Rumano" -#: dmoj/settings.py:365 +#: dmoj/settings.py:359 msgid "Russian" msgstr "Ruso" -#: dmoj/settings.py:366 +#: dmoj/settings.py:360 msgid "Serbian (Latin)" msgstr "Serbio (Latino)" -#: dmoj/settings.py:367 +#: dmoj/settings.py:361 msgid "Turkish" msgstr "Turco" -#: dmoj/settings.py:368 +#: dmoj/settings.py:362 msgid "Vietnamese" msgstr "Vietnamita" -#: dmoj/settings.py:369 +#: dmoj/settings.py:363 msgid "Simplified Chinese" msgstr "Chino simplificado" -#: dmoj/settings.py:370 +#: dmoj/settings.py:364 msgid "Traditional Chinese" msgstr "" -#: dmoj/urls.py:58 +#: dmoj/urls.py:57 msgid "Login" msgstr "Iniciar sesión" -#: dmoj/urls.py:106 templates/base.html:193 +#: dmoj/urls.py:105 templates/base.html:190 msgid "Home" msgstr "Inicio" @@ -132,92 +132,90 @@ msgstr "Mostrar comentarios" msgid "Associated page" msgstr "Página asociada" -#: judge/admin/contest.py:30 +#: judge/admin/contest.py:28 msgid "Included contests" msgstr "Concurso incluido" -#: judge/admin/contest.py:66 templates/contest/clarification.html:42 -#: templates/contest/contest.html:83 templates/contest/moss.html:43 -#: templates/problem/list.html:214 templates/problem/list.html:232 -#: templates/problem/list.html:350 templates/user/user-problems.html:56 +#: judge/admin/contest.py:64 templates/contest/contest.html:83 +#: templates/contest/moss.html:43 templates/problem/list.html:206 +#: templates/problem/list.html:221 templates/user/user-problems.html:56 #: templates/user/user-problems.html:98 msgid "Problem" msgstr "Problema" -#: judge/admin/contest.py:119 +#: judge/admin/contest.py:112 msgid "Settings" msgstr "" -#: judge/admin/contest.py:121 +#: judge/admin/contest.py:114 msgid "Scheduling" msgstr "Programación" -#: judge/admin/contest.py:122 templates/organization/home.html:107 +#: judge/admin/contest.py:115 msgid "Details" msgstr "Detalles" -#: judge/admin/contest.py:123 +#: judge/admin/contest.py:116 msgid "Format" msgstr "" -#: judge/admin/contest.py:124 templates/contest/ranking-table.html:7 -#: templates/user/user-about.html:15 templates/user/user-about.html:45 +#: judge/admin/contest.py:117 templates/contest/ranking-table.html:5 msgid "Rating" msgstr "Puntuación" -#: judge/admin/contest.py:125 +#: judge/admin/contest.py:118 msgid "Access" msgstr "" -#: judge/admin/contest.py:127 judge/admin/problem.py:131 +#: judge/admin/contest.py:120 judge/admin/problem.py:131 msgid "Justice" msgstr "Justicia" -#: judge/admin/contest.py:207 +#: judge/admin/contest.py:158 #, python-format msgid "%d contest successfully marked as visible." msgid_plural "%d contests successfully marked as visible." msgstr[0] "" msgstr[1] "" -#: judge/admin/contest.py:210 +#: judge/admin/contest.py:161 msgid "Mark contests as visible" msgstr "" -#: judge/admin/contest.py:216 +#: judge/admin/contest.py:165 #, python-format msgid "%d contest successfully marked as hidden." msgid_plural "%d contests successfully marked as hidden." msgstr[0] "" msgstr[1] "" -#: judge/admin/contest.py:219 +#: judge/admin/contest.py:168 msgid "Mark contests as hidden" msgstr "" -#: judge/admin/contest.py:233 judge/admin/submission.py:164 +#: judge/admin/contest.py:182 judge/admin/submission.py:164 #, python-format msgid "%d submission was successfully scheduled for rejudging." msgid_plural "%d submissions were successfully scheduled for rejudging." msgstr[0] "" msgstr[1] "" -#: judge/admin/contest.py:308 +#: judge/admin/contest.py:256 #, python-format msgid "%d participation recalculated." msgid_plural "%d participations recalculated." msgstr[0] "" msgstr[1] "" -#: judge/admin/contest.py:311 +#: judge/admin/contest.py:259 msgid "Recalculate results" msgstr "" -#: judge/admin/contest.py:315 judge/admin/organization.py:65 +#: judge/admin/contest.py:263 judge/admin/organization.py:65 msgid "username" msgstr "nombre de usuario" -#: judge/admin/contest.py:320 templates/base.html:277 +#: judge/admin/contest.py:268 templates/base.html:260 msgid "virtual" msgstr "virtual" @@ -225,15 +223,15 @@ msgstr "virtual" msgid "link path" msgstr "ruta de enlace" -#: judge/admin/interface.py:65 +#: judge/admin/interface.py:62 msgid "Content" msgstr "Contenido" -#: judge/admin/interface.py:66 +#: judge/admin/interface.py:63 msgid "Summary" msgstr "Resumen" -#: judge/admin/interface.py:151 +#: judge/admin/interface.py:148 msgid "object" msgstr "" @@ -255,9 +253,8 @@ msgid "Taxonomy" msgstr "Taxanomía" #: judge/admin/problem.py:128 templates/contest/contest.html:84 -#: templates/problem/data.html:429 templates/problem/list.html:222 -#: templates/problem/list.html:248 templates/user/base-users-table.html:10 -#: templates/user/user-about.html:36 templates/user/user-about.html:52 +#: templates/problem/data.html:449 templates/problem/list.html:211 +#: templates/problem/list.html:232 templates/user/base-users-table.html:10 #: templates/user/user-problems.html:58 msgid "Points" msgstr "Puntos" @@ -306,7 +303,6 @@ msgid "timezone" msgstr "zona horaria" #: judge/admin/profile.py:86 judge/admin/submission.py:211 -#: templates/notification/list.html:12 #: templates/organization/requests/log.html:9 #: templates/organization/requests/pending.html:12 #: templates/ticket/list.html:263 @@ -314,7 +310,6 @@ msgid "User" msgstr "Usuario" #: judge/admin/profile.py:91 templates/registration/registration_form.html:145 -#: templates/user/import/table_csv.html:8 msgid "Email" msgstr "Email" @@ -348,7 +343,7 @@ msgid "These problems are NOT allowed to be submitted in this language" msgstr "" "Estos problemas no están permitidos para ser presentados en este idioma" -#: judge/admin/runtime.py:83 templates/problem/list.html:352 +#: judge/admin/runtime.py:83 msgid "Description" msgstr "Descripción" @@ -395,7 +390,7 @@ msgstr "No tienes permiso de revaluar todos esos envíos." msgid "Rejudge the selected submissions" msgstr "Hacer de nuevo el juicio para las presentaciones seleccionadas" -#: judge/admin/submission.py:193 judge/views/problem_manage.py:159 +#: judge/admin/submission.py:193 judge/views/problem_manage.py:128 #, python-format msgid "%d submission were successfully rescored." msgid_plural "%d submissions were successfully rescored." @@ -406,8 +401,7 @@ msgstr[1] "%d de las presentaciones fue rescatado con éxito." msgid "Rescore the selected submissions" msgstr "Repuntear las presentaciones seleccionadas" -#: judge/admin/submission.py:200 templates/problem/list.html:216 -#: templates/problem/list.html:236 +#: judge/admin/submission.py:200 msgid "Problem code" msgstr "Código del problema" @@ -415,12 +409,10 @@ msgstr "Código del problema" msgid "Problem name" msgstr "Nombre del problema" -#: judge/admin/submission.py:215 templates/notification/list.html:15 -#: templates/organization/requests/log.html:10 +#: judge/admin/submission.py:215 templates/organization/requests/log.html:10 #: templates/organization/requests/pending.html:13 -#: templates/problem/list.html:351 -#: templates/submission/status-testcases.html:125 -#: templates/submission/status-testcases.html:127 +#: templates/submission/status-testcases.html:105 +#: templates/submission/status-testcases.html:107 msgid "Time" msgstr "Tiempo" @@ -434,7 +426,7 @@ msgstr "%d KB" msgid "%.2f MB" msgstr "%.2f MB" -#: judge/admin/submission.py:227 templates/submission/status-testcases.html:132 +#: judge/admin/submission.py:227 templates/submission/status-testcases.html:112 msgid "Memory" msgstr "Memoria" @@ -454,22 +446,22 @@ msgstr "Estos problemas están incluidos en este tipo de problemas" msgid "Online Judge" msgstr "Juez en línea" -#: judge/comments.py:60 +#: judge/comments.py:41 msgid "Comment body" msgstr "Cuerpo del comentario" -#: judge/comments.py:66 judge/views/ticket.py:63 +#: judge/comments.py:47 judge/views/ticket.py:46 msgid "Your part is silent, little toad." msgstr "Estás un poco callado." -#: judge/comments.py:69 templates/comments/list.html:132 +#: judge/comments.py:50 templates/comments/list.html:131 msgid "" "You need to have solved at least one problem before your voice can be heard." msgstr "" "Usted necesita tener resuelto por lo menos un problema antes de que su voz " "pueda ser escuchada." -#: judge/comments.py:113 +#: judge/comments.py:92 msgid "Posted comment" msgstr "Comentario publicado" @@ -485,10 +477,6 @@ msgstr "" msgid "ECOO" msgstr "" -#: judge/contest_format/icpc.py:19 -msgid "ICPC" -msgstr "" - #: judge/contest_format/ioi.py:19 msgid "IOI" msgstr "" @@ -501,60 +489,52 @@ msgstr "Subscribirse en las actualizaciones de los concursos" msgid "Enable experimental features" msgstr "Habilitar las actualizaciones experimentales" -#: judge/forms.py:57 judge/views/organization.py:168 judge/views/register.py:49 +#: judge/forms.py:57 judge/views/organization.py:127 #, python-brace-format msgid "You may not be part of more than {count} public organizations." msgstr "Tu no deberías formar parte de más de {count} organizaciones públicas." -#: judge/forms.py:82 -#, fuzzy -#| msgid "judge" -msgid "Any judge" -msgstr "juez" - -#: judge/forms.py:112 judge/views/register.py:26 +#: judge/forms.py:107 judge/views/register.py:26 #: templates/registration/registration_form.html:139 #: templates/user/base-users-table.html:5 -#: templates/user/import/table_csv.html:4 msgid "Username" msgstr "Nombre de usuario" -#: judge/forms.py:113 templates/registration/registration_form.html:151 +#: judge/forms.py:108 templates/registration/registration_form.html:151 #: templates/registration/registration_form.html:165 -#: templates/user/import/table_csv.html:5 msgid "Password" msgstr "Contraseña" -#: judge/forms.py:135 +#: judge/forms.py:130 msgid "Two Factor Authentication tokens must be 6 decimal digits." msgstr "" -#: judge/forms.py:144 templates/registration/totp_auth.html:32 +#: judge/forms.py:139 templates/registration/totp_auth.html:32 msgid "Invalid Two Factor Authentication token." msgstr "" -#: judge/forms.py:148 judge/models/problem.py:97 +#: judge/forms.py:143 judge/models/problem.py:97 msgid "Problem code must be ^[a-z0-9]+$" msgstr "Código del problema debe ser ^[a-z0-9]+$" -#: judge/forms.py:153 +#: judge/forms.py:148 msgid "Problem with code already exists." msgstr "" -#: judge/forms.py:158 judge/models/contest.py:61 +#: judge/forms.py:153 judge/models/contest.py:52 msgid "Contest id must be ^[a-z0-9]+$" msgstr "Identificación del concurso debe ser ^[a-z0-9]+$" -#: judge/forms.py:163 +#: judge/forms.py:158 msgid "Contest with key already exists." msgstr "" -#: judge/jinja2/datetime.py:26 templates/blog/blog.html:26 +#: judge/jinja2/datetime.py:26 templates/blog/content.html:27 #: templates/blog/dashboard.html:21 msgid "N j, Y, g:i a" msgstr "N j, Y, g:i a" -#: judge/jinja2/datetime.py:26 templates/chat/message.html:13 +#: judge/jinja2/datetime.py:26 #, python-brace-format msgid "{time}" msgstr "{time}" @@ -584,174 +564,122 @@ msgstr "MathJax con suplencia SVG/PNG" msgid "Detect best quality" msgstr "Detectar la mejor calidad" -#: judge/models/comment.py:26 +#: judge/models/comment.py:25 msgid "Page code must be ^[pcs]:[a-z0-9]+$|^b:\\d+$" msgstr "" -#: judge/models/comment.py:42 +#: judge/models/comment.py:41 msgid "commenter" msgstr "comentador" -#: judge/models/comment.py:44 judge/models/comment.py:177 +#: judge/models/comment.py:43 judge/models/comment.py:176 msgid "associated page" msgstr "" -#: judge/models/comment.py:46 +#: judge/models/comment.py:45 msgid "votes" msgstr "votos" -#: judge/models/comment.py:48 +#: judge/models/comment.py:47 msgid "hide the comment" msgstr "ocultar el comentario" -#: judge/models/comment.py:49 +#: judge/models/comment.py:48 msgid "parent" msgstr "padre" -#: judge/models/comment.py:54 judge/models/comment.py:192 +#: judge/models/comment.py:53 msgid "comment" msgstr "comentario" -#: judge/models/comment.py:55 +#: judge/models/comment.py:54 msgid "comments" msgstr "comentarios" -#: judge/models/comment.py:137 judge/models/problem.py:443 +#: judge/models/comment.py:136 judge/models/problem.py:406 #, python-format msgid "Editorial for %s" msgstr "Editorial de %s" -#: judge/models/comment.py:172 +#: judge/models/comment.py:171 msgid "comment vote" msgstr "voto del comentario" -#: judge/models/comment.py:173 +#: judge/models/comment.py:172 msgid "comment votes" msgstr "votos del comentario" -#: judge/models/comment.py:182 +#: judge/models/comment.py:181 msgid "Override comment lock" msgstr "" -#: judge/models/comment.py:190 -msgid "owner" -msgstr "" - -#: judge/models/comment.py:193 judge/models/message.py:16 -msgid "read" -msgstr "leer" - -#: judge/models/comment.py:194 -#, fuzzy -#| msgid "Category" -msgid "category" -msgstr "Categoría" - -#: judge/models/comment.py:195 -msgid "html link to comments, used for non-comments" -msgstr "" - -#: judge/models/comment.py:196 -msgid "who trigger, used for non-comment" -msgstr "" - -#: judge/models/contest.py:23 +#: judge/models/contest.py:22 msgid "Invalid colour." msgstr "Color no válido." -#: judge/models/contest.py:25 +#: judge/models/contest.py:24 msgid "tag name" msgstr "nombre de la etiqueta" -#: judge/models/contest.py:26 +#: judge/models/contest.py:25 msgid "Lowercase letters and hyphens only." msgstr "Sólo letras minúsculas y guiones." -#: judge/models/contest.py:27 +#: judge/models/contest.py:26 msgid "tag colour" msgstr "color de etiqueta" -#: judge/models/contest.py:28 +#: judge/models/contest.py:27 msgid "tag description" msgstr "descripción de la etiqueta" -#: judge/models/contest.py:47 +#: judge/models/contest.py:46 msgid "contest tag" msgstr "etiqueta del concurso" -#: judge/models/contest.py:48 judge/models/contest.py:118 +#: judge/models/contest.py:47 judge/models/contest.py:101 msgid "contest tags" msgstr "etiquetas del concurso" -#: judge/models/contest.py:56 -msgid "Visible" -msgstr "" - -#: judge/models/contest.py:57 -msgid "Hidden for duration of contest" -msgstr "" - -#: judge/models/contest.py:58 -#, fuzzy -#| msgid "View user participation" -msgid "Hidden for duration of participation" -msgstr "Ver la participación del usuario" - -#: judge/models/contest.py:60 +#: judge/models/contest.py:51 msgid "contest id" msgstr "identificación del concurso" -#: judge/models/contest.py:62 +#: judge/models/contest.py:53 msgid "contest name" msgstr "nombre del concurso" -#: judge/models/contest.py:63 -#, fuzzy -#| msgid "These people will be able to edit the contest." -msgid "These users will be able to edit the contest." +#: judge/models/contest.py:54 +msgid "These people will be able to edit the contest." msgstr "Estas personas serán capaces de editar el concurso." -#: judge/models/contest.py:65 -#, fuzzy -#| msgid "These people will be able to edit the contest." -msgid "" -"These users will be able to edit the contest, but will not be listed as " -"authors." -msgstr "Estas personas serán capaces de editar el concurso." - -#: judge/models/contest.py:68 -#, fuzzy -#| msgid "These people will be able to edit the contest." -msgid "These users will be able to view the contest, but not edit it." -msgstr "Estas personas serán capaces de editar el concurso." - -#: judge/models/contest.py:71 judge/models/runtime.py:136 +#: judge/models/contest.py:56 judge/models/runtime.py:133 msgid "description" msgstr "descripción" -#: judge/models/contest.py:72 judge/models/problem.py:390 -#: judge/models/runtime.py:138 +#: judge/models/contest.py:57 judge/models/problem.py:353 +#: judge/models/runtime.py:135 msgid "problems" msgstr "problemas" -#: judge/models/contest.py:73 judge/models/contest.py:404 +#: judge/models/contest.py:58 judge/models/contest.py:258 msgid "start time" msgstr "hora de inicio" -#: judge/models/contest.py:74 +#: judge/models/contest.py:59 msgid "end time" msgstr "hora final" -#: judge/models/contest.py:75 judge/models/problem.py:118 -#: judge/models/problem.py:414 +#: judge/models/contest.py:60 judge/models/problem.py:118 +#: judge/models/problem.py:377 msgid "time limit" msgstr "tiempo límite" -#: judge/models/contest.py:76 judge/models/problem.py:136 +#: judge/models/contest.py:61 judge/models/problem.py:136 msgid "publicly visible" msgstr "publicidad visible" -#: judge/models/contest.py:77 +#: judge/models/contest.py:62 msgid "" "Should be set even for organization-private contests, where it determines " "whether the contest is visible to members of the specified organizations." @@ -760,95 +688,78 @@ msgstr "" "donde se determina si la publicación es visible para los miembros de las " "organizaciones especificadas." -#: judge/models/contest.py:80 +#: judge/models/contest.py:65 msgid "contest rated" msgstr "concurso calificado" -#: judge/models/contest.py:80 +#: judge/models/contest.py:65 msgid "Whether this contest can be rated." msgstr "Si esta publicación puede ser calificada." -#: judge/models/contest.py:82 -#, fuzzy -#| msgid "public visibility" -msgid "scoreboard visibility" -msgstr "visibilidad pública" - -#: judge/models/contest.py:83 -#, fuzzy -#| msgid "" -#| "Whether the scoreboard should remain hidden for the duration of the " -#| "contest." -msgid "Scoreboard visibility through the duration of the contest" -msgstr "Si el scoreboard debe permanecer oculto durante la competencia." - -#: judge/models/contest.py:85 -#, fuzzy -#| msgid "hide scoreboard" -msgid "view contest scoreboard" +#: judge/models/contest.py:67 +msgid "hide scoreboard" msgstr "ocultar scoreboard" -#: judge/models/contest.py:87 -#, fuzzy -#| msgid "These people will be able to edit the contest." -msgid "These users will be able to view the scoreboard." -msgstr "Estas personas serán capaces de editar el concurso." +#: judge/models/contest.py:68 +msgid "" +"Whether the scoreboard should remain hidden for the duration of the contest." +msgstr "Si el scoreboard debe permanecer oculto durante la competencia." -#: judge/models/contest.py:88 +#: judge/models/contest.py:71 msgid "no comments" msgstr "sin comentarios" -#: judge/models/contest.py:89 +#: judge/models/contest.py:72 msgid "Use clarification system instead of comments." msgstr "Use el sistema de calificación en vez de comentar." -#: judge/models/contest.py:91 +#: judge/models/contest.py:74 msgid "Rating floor for contest" msgstr "" -#: judge/models/contest.py:93 +#: judge/models/contest.py:76 msgid "Rating ceiling for contest" msgstr "" -#: judge/models/contest.py:95 +#: judge/models/contest.py:78 msgid "rate all" msgstr "calificar todo" -#: judge/models/contest.py:95 +#: judge/models/contest.py:78 msgid "Rate all users who joined." msgstr "Calificar todos los usuarios que se unieron." -#: judge/models/contest.py:96 +#: judge/models/contest.py:79 msgid "exclude from ratings" msgstr "excluir de las calificaciones" -#: judge/models/contest.py:98 +#: judge/models/contest.py:81 msgid "private to specific users" msgstr "" -#: judge/models/contest.py:99 +#: judge/models/contest.py:82 msgid "private contestants" msgstr "" -#: judge/models/contest.py:100 +#: judge/models/contest.py:83 msgid "If private, only these users may see the contest" msgstr "" -#: judge/models/contest.py:102 +#: judge/models/contest.py:85 msgid "hide problem tags" msgstr "ocultar etiquetas de problemas" -#: judge/models/contest.py:103 +#: judge/models/contest.py:86 msgid "Whether problem tags should be hidden by default." msgstr "" "Si las etiquetas problemáticas deberían estar ocultas de forma " "predeterminada." -#: judge/models/contest.py:105 +#: judge/models/contest.py:88 msgid "run pretests only" msgstr "ejecutar exámenes solamente" -#: judge/models/contest.py:106 +#: judge/models/contest.py:89 msgid "" "Whether judges should grade pretests only, versus all testcases. Commonly " "set during a contest, then unset prior to rejudging user submissions when " @@ -859,52 +770,51 @@ msgstr "" "desarmado antes de volver a juzgar las presentaciones de los usuarios cuando " "finaliza el concurso." -#: judge/models/contest.py:110 judge/models/interface.py:77 -#: judge/models/problem.py:157 +#: judge/models/contest.py:93 judge/models/problem.py:157 msgid "private to organizations" msgstr "privado para organizaciones" -#: judge/models/contest.py:111 judge/models/interface.py:75 -#: judge/models/problem.py:155 judge/models/profile.py:77 +#: judge/models/contest.py:94 judge/models/problem.py:155 +#: judge/models/profile.py:77 msgid "organizations" msgstr "organizaciones" -#: judge/models/contest.py:112 +#: judge/models/contest.py:95 msgid "If private, only these organizations may see the contest" msgstr "Es privado, sólo estas organizaciones deben ser el concurso" -#: judge/models/contest.py:113 judge/models/problem.py:145 +#: judge/models/contest.py:96 judge/models/problem.py:145 msgid "OpenGraph image" msgstr "Imagen de OpenGraph" -#: judge/models/contest.py:114 judge/models/profile.py:48 +#: judge/models/contest.py:97 judge/models/profile.py:48 msgid "Logo override image" msgstr "" -#: judge/models/contest.py:116 +#: judge/models/contest.py:99 msgid "" "This image will replace the default site logo for users inside the contest." msgstr "" -#: judge/models/contest.py:119 +#: judge/models/contest.py:102 msgid "the amount of live participants" msgstr "la cantidad de participantes en vivo" -#: judge/models/contest.py:120 +#: judge/models/contest.py:103 msgid "contest summary" msgstr "resumen del concurso" -#: judge/models/contest.py:121 judge/models/problem.py:147 +#: judge/models/contest.py:104 judge/models/problem.py:147 msgid "Plain-text, shown in meta description tag, e.g. for social media." msgstr "" "Texto sin formato, que se muestra en la etiqueta de metadescripción, por " "ejemplo, para las redes sociales." -#: judge/models/contest.py:122 judge/models/profile.py:47 +#: judge/models/contest.py:105 judge/models/profile.py:47 msgid "access code" msgstr "código de acceso" -#: judge/models/contest.py:123 +#: judge/models/contest.py:106 msgid "" "An optional code to prompt contestants before they are allowed to join the " "contest. Leave it blank to disable." @@ -912,256 +822,232 @@ msgstr "" "Un código opcional para incitar a los concursantes antes de que se les " "permita unirse al concurso. Déjelo en blanco para desactivar." -#: judge/models/contest.py:125 judge/models/problem.py:141 +#: judge/models/contest.py:108 judge/models/problem.py:141 msgid "personae non gratae" msgstr "persona no grata" -#: judge/models/contest.py:126 +#: judge/models/contest.py:109 msgid "Bans the selected users from joining this contest." msgstr "" -#: judge/models/contest.py:127 +#: judge/models/contest.py:110 msgid "contest format" msgstr "" -#: judge/models/contest.py:128 +#: judge/models/contest.py:111 msgid "The contest format module to use." msgstr "" -#: judge/models/contest.py:129 +#: judge/models/contest.py:112 msgid "contest format configuration" msgstr "" -#: judge/models/contest.py:130 +#: judge/models/contest.py:113 msgid "" "A JSON object to serve as the configuration for the chosen contest format " "module. Leave empty to use None. Exact format depends on the contest format " "selected." msgstr "" -#: judge/models/contest.py:137 -#, fuzzy -#| msgid "test case points" -msgid "precision points" -msgstr "puntos de prueba" - -#: judge/models/contest.py:139 -msgid "Number of digits to round points to." -msgstr "" - -#: judge/models/contest.py:383 +#: judge/models/contest.py:239 msgid "See private contests" msgstr "Ver publicaciones privadas" -#: judge/models/contest.py:384 +#: judge/models/contest.py:240 msgid "Edit own contests" msgstr "Editar sus propias notas" -#: judge/models/contest.py:385 +#: judge/models/contest.py:241 msgid "Edit all contests" msgstr "Editar todas las publicaciones" -#: judge/models/contest.py:386 +#: judge/models/contest.py:242 msgid "Clone contest" msgstr "" -#: judge/models/contest.py:387 templates/contest/moss.html:74 +#: judge/models/contest.py:243 templates/contest/moss.html:74 msgid "MOSS contest" msgstr "" -#: judge/models/contest.py:388 +#: judge/models/contest.py:244 msgid "Rate contests" msgstr "Calificar publicaciones" -#: judge/models/contest.py:389 +#: judge/models/contest.py:245 msgid "Contest access codes" msgstr "Código de acceso a las publicaciones" -#: judge/models/contest.py:390 +#: judge/models/contest.py:246 msgid "Create private contests" msgstr "" -#: judge/models/contest.py:391 -msgid "Change contest visibility" -msgstr "" - -#: judge/models/contest.py:392 -#, fuzzy -#| msgid "contest problems" -msgid "Edit contest problem label script" -msgstr "problemas del concurso" - -#: judge/models/contest.py:394 judge/models/contest.py:492 -#: judge/models/contest.py:529 judge/models/contest.py:552 -#: judge/models/submission.py:84 +#: judge/models/contest.py:248 judge/models/contest.py:345 +#: judge/models/contest.py:382 judge/models/contest.py:404 +#: judge/models/submission.py:83 msgid "contest" msgstr "concurso" -#: judge/models/contest.py:395 +#: judge/models/contest.py:249 msgid "contests" msgstr "concursos" -#: judge/models/contest.py:402 +#: judge/models/contest.py:256 msgid "associated contest" msgstr "concurso asociado" -#: judge/models/contest.py:405 +#: judge/models/contest.py:259 msgid "score" msgstr "puntuación" -#: judge/models/contest.py:406 +#: judge/models/contest.py:260 msgid "cumulative time" msgstr "tiempo acumulado" -#: judge/models/contest.py:407 +#: judge/models/contest.py:261 msgid "is disqualified" msgstr "" -#: judge/models/contest.py:408 +#: judge/models/contest.py:262 msgid "Whether this participation is disqualified." msgstr "" -#: judge/models/contest.py:409 -msgid "tie-breaking field" -msgstr "" - -#: judge/models/contest.py:410 +#: judge/models/contest.py:263 msgid "virtual participation id" msgstr "identificación de la participación virtual" -#: judge/models/contest.py:411 +#: judge/models/contest.py:264 #, fuzzy #| msgid "0 means non-virtual, otherwise the n-th virtual participation" msgid "0 means non-virtual, otherwise the n-th virtual participation." msgstr "" "0 significa no virtual, de lo contrario la n-ésima participación virtual" -#: judge/models/contest.py:412 +#: judge/models/contest.py:265 msgid "contest format specific data" msgstr "" -#: judge/models/contest.py:478 +#: judge/models/contest.py:331 #, python-format msgid "%s spectating in %s" msgstr "%s ver en %s" -#: judge/models/contest.py:480 +#: judge/models/contest.py:333 #, python-format msgid "%s in %s, v%d" msgstr "%s en %s, v%d" -#: judge/models/contest.py:481 +#: judge/models/contest.py:334 #, python-format msgid "%s in %s" msgstr "%s en %s" -#: judge/models/contest.py:484 +#: judge/models/contest.py:337 msgid "contest participation" msgstr "participación del concurso" -#: judge/models/contest.py:485 +#: judge/models/contest.py:338 msgid "contest participations" msgstr "participaciones del concurso" -#: judge/models/contest.py:491 judge/models/contest.py:513 -#: judge/models/contest.py:553 judge/models/problem.py:389 -#: judge/models/problem.py:394 judge/models/problem.py:412 -#: judge/models/problem_data.py:40 +#: judge/models/contest.py:344 judge/models/contest.py:366 +#: judge/models/contest.py:405 judge/models/problem.py:352 +#: judge/models/problem.py:357 judge/models/problem.py:375 +#: judge/models/problem_data.py:38 msgid "problem" msgstr "problema" -#: judge/models/contest.py:493 judge/models/contest.py:517 +#: judge/models/contest.py:346 judge/models/contest.py:370 #: judge/models/problem.py:129 msgid "points" msgstr "puntos" -#: judge/models/contest.py:494 +#: judge/models/contest.py:347 msgid "partial" msgstr "parcial" -#: judge/models/contest.py:495 judge/models/contest.py:518 +#: judge/models/contest.py:348 judge/models/contest.py:371 msgid "is pretested" msgstr "está protegido" -#: judge/models/contest.py:496 judge/models/interface.py:43 +#: judge/models/contest.py:349 judge/models/interface.py:43 msgid "order" msgstr "orden" -#: judge/models/contest.py:497 +#: judge/models/contest.py:350 msgid "0 to not show testcases, 1 to show" msgstr "" -#: judge/models/contest.py:498 +#: judge/models/contest.py:351 #, fuzzy #| msgid "submission test cases" msgid "visible testcases" msgstr "pruebas de presentación" -#: judge/models/contest.py:499 +#: judge/models/contest.py:352 msgid "Maximum number of submissions for this problem, or 0 for no limit." msgstr "Máximo número de envíos para este problema, o 0 para ningún límite." -#: judge/models/contest.py:501 +#: judge/models/contest.py:354 msgid "Why include a problem you can't submit to?" msgstr "¿Por qué incluir un problema que no puede enviarse?" -#: judge/models/contest.py:506 +#: judge/models/contest.py:359 msgid "contest problem" msgstr "problema de concurso" -#: judge/models/contest.py:507 +#: judge/models/contest.py:360 msgid "contest problems" msgstr "problemas del concurso" -#: judge/models/contest.py:511 judge/models/submission.py:183 +#: judge/models/contest.py:364 judge/models/submission.py:181 msgid "submission" msgstr "envío" -#: judge/models/contest.py:515 judge/models/contest.py:530 +#: judge/models/contest.py:368 judge/models/contest.py:383 msgid "participation" msgstr "participación" -#: judge/models/contest.py:519 +#: judge/models/contest.py:372 msgid "Whether this submission was ran only on pretests." msgstr "Si esta presentación funcionó sólo en pruebas previas." -#: judge/models/contest.py:523 +#: judge/models/contest.py:376 msgid "contest submission" msgstr "presentación del concurso" -#: judge/models/contest.py:524 +#: judge/models/contest.py:377 msgid "contest submissions" msgstr "presentaciones de concurso" -#: judge/models/contest.py:532 +#: judge/models/contest.py:385 msgid "rank" msgstr "rango" -#: judge/models/contest.py:533 +#: judge/models/contest.py:386 msgid "rating" msgstr "puntuación" -#: judge/models/contest.py:534 +#: judge/models/contest.py:387 msgid "volatility" msgstr "volatilidad" -#: judge/models/contest.py:535 +#: judge/models/contest.py:388 msgid "last rated" msgstr "último calificado" -#: judge/models/contest.py:539 +#: judge/models/contest.py:392 msgid "contest rating" msgstr "calificación del concurso" -#: judge/models/contest.py:540 +#: judge/models/contest.py:393 msgid "contest ratings" msgstr "calificaciones del concurso" -#: judge/models/contest.py:560 +#: judge/models/contest.py:412 msgid "contest moss result" msgstr "" -#: judge/models/contest.py:561 +#: judge/models/contest.py:413 msgid "contest moss results" msgstr "" @@ -1201,7 +1087,7 @@ msgstr "elementos paternales" msgid "post title" msgstr "título de la publicación" -#: judge/models/interface.py:67 judge/models/problem.py:432 +#: judge/models/interface.py:67 judge/models/problem.py:395 msgid "authors" msgstr "autores" @@ -1209,7 +1095,7 @@ msgstr "autores" msgid "slug" msgstr "babosa" -#: judge/models/interface.py:69 judge/models/problem.py:430 +#: judge/models/interface.py:69 judge/models/problem.py:393 msgid "public visibility" msgstr "visibilidad pública" @@ -1233,21 +1119,15 @@ msgstr "resumen del post" msgid "openGraph image" msgstr "imagen de openGraph" -#: judge/models/interface.py:76 -#, fuzzy -#| msgid "If private, only these organizations may see the contest" -msgid "If private, only these organizations may see the blog post." -msgstr "Es privado, sólo estas organizaciones deben ser el concurso" - -#: judge/models/interface.py:105 +#: judge/models/interface.py:91 msgid "Edit all posts" msgstr "Editar todas las publicaciones" -#: judge/models/interface.py:107 +#: judge/models/interface.py:93 msgid "blog post" msgstr "post del blog" -#: judge/models/interface.py:108 +#: judge/models/interface.py:94 msgid "blog posts" msgstr "posts del blog" @@ -1271,6 +1151,10 @@ msgstr "objetivo" msgid "message timestamp" msgstr "hora del mensaje" +#: judge/models/message.py:16 +msgid "read" +msgstr "leer" + #: judge/models/message.py:20 msgid "messages in the thread" msgstr "mensajes en el hilo" @@ -1409,7 +1293,7 @@ msgstr "" "El límite de tiempo para este problema, en segundos. Los segundos " "fraccionarios (por ejemplo, 1.5) serán permitidos." -#: judge/models/problem.py:123 judge/models/problem.py:417 +#: judge/models/problem.py:123 judge/models/problem.py:380 msgid "memory limit" msgstr "límite de memoria" @@ -1486,188 +1370,188 @@ msgstr "" msgid "If private, only these organizations may see the problem." msgstr "" -#: judge/models/problem.py:395 judge/models/problem.py:413 -#: judge/models/runtime.py:111 +#: judge/models/problem.py:358 judge/models/problem.py:376 +#: judge/models/runtime.py:108 msgid "language" msgstr "idioma" -#: judge/models/problem.py:396 +#: judge/models/problem.py:359 msgid "translated name" msgstr "nombre traducido" -#: judge/models/problem.py:397 +#: judge/models/problem.py:360 msgid "translated description" msgstr "descripción traducida" -#: judge/models/problem.py:401 +#: judge/models/problem.py:364 msgid "problem translation" msgstr "problemas de traducción" -#: judge/models/problem.py:402 +#: judge/models/problem.py:365 msgid "problem translations" msgstr "problemas de traducciones" -#: judge/models/problem.py:406 +#: judge/models/problem.py:369 msgid "clarified problem" msgstr "problema calificado" -#: judge/models/problem.py:407 +#: judge/models/problem.py:370 msgid "clarification body" msgstr "calificación del cuerpo" -#: judge/models/problem.py:408 +#: judge/models/problem.py:371 msgid "clarification timestamp" msgstr "marca de tiempo de aclaración" -#: judge/models/problem.py:423 +#: judge/models/problem.py:386 msgid "language-specific resource limit" msgstr "límite de recursos específicos del idioma" -#: judge/models/problem.py:424 +#: judge/models/problem.py:387 msgid "language-specific resource limits" msgstr "límites de recursos específicos del idioma" -#: judge/models/problem.py:428 +#: judge/models/problem.py:391 msgid "associated problem" msgstr "problema asociado" -#: judge/models/problem.py:431 +#: judge/models/problem.py:394 msgid "publish date" msgstr "fecha de publicación" -#: judge/models/problem.py:433 +#: judge/models/problem.py:396 msgid "editorial content" msgstr "contenido editorial" -#: judge/models/problem.py:449 +#: judge/models/problem.py:412 msgid "solution" msgstr "solución" -#: judge/models/problem.py:450 +#: judge/models/problem.py:413 msgid "solutions" msgstr "soluciones" -#: judge/models/problem_data.py:26 +#: judge/models/problem_data.py:24 msgid "Standard" msgstr "Estándar" -#: judge/models/problem_data.py:27 +#: judge/models/problem_data.py:25 msgid "Floats" msgstr "Flotantes" -#: judge/models/problem_data.py:28 +#: judge/models/problem_data.py:26 msgid "Floats (absolute)" msgstr "Flotantes (absoluto)" -#: judge/models/problem_data.py:29 +#: judge/models/problem_data.py:27 msgid "Floats (relative)" msgstr "Flotante (relativo)" -#: judge/models/problem_data.py:30 +#: judge/models/problem_data.py:28 msgid "Non-trailing spaces" msgstr "Espacios sin seguimiento" -#: judge/models/problem_data.py:31 +#: judge/models/problem_data.py:29 msgid "Unordered" msgstr "Sin ordenar" -#: judge/models/problem_data.py:32 +#: judge/models/problem_data.py:30 msgid "Byte identical" msgstr "Byte idéntico" -#: judge/models/problem_data.py:33 +#: judge/models/problem_data.py:31 msgid "Line-by-line" msgstr "" -#: judge/models/problem_data.py:34 +#: judge/models/problem_data.py:32 msgid "Custom checker (PY)" msgstr "" -#: judge/models/problem_data.py:35 +#: judge/models/problem_data.py:33 msgid "Custom validator (CPP)" msgstr "" -#: judge/models/problem_data.py:42 +#: judge/models/problem_data.py:40 msgid "data zip file" msgstr "archivos de datos de zip" -#: judge/models/problem_data.py:44 +#: judge/models/problem_data.py:42 msgid "generator file" msgstr "generador de archivos" -#: judge/models/problem_data.py:46 judge/models/problem_data.py:121 +#: judge/models/problem_data.py:44 judge/models/problem_data.py:110 msgid "output prefix length" msgstr "longitud del prefijo de salida" -#: judge/models/problem_data.py:47 judge/models/problem_data.py:122 +#: judge/models/problem_data.py:45 judge/models/problem_data.py:111 msgid "output limit length" msgstr "longitud de límite de salida" -#: judge/models/problem_data.py:48 +#: judge/models/problem_data.py:46 msgid "init.yml generation feedback" msgstr "generación de recomendaciones init.yml" -#: judge/models/problem_data.py:49 judge/models/problem_data.py:123 +#: judge/models/problem_data.py:47 judge/models/problem_data.py:112 msgid "checker" msgstr "verificador" -#: judge/models/problem_data.py:50 judge/models/problem_data.py:124 +#: judge/models/problem_data.py:48 judge/models/problem_data.py:113 msgid "checker arguments" msgstr "argumentos del verificador" -#: judge/models/problem_data.py:51 judge/models/problem_data.py:125 +#: judge/models/problem_data.py:49 judge/models/problem_data.py:114 msgid "checker arguments as a JSON object" msgstr "argumentos del verificador como un objetivo JSON" -#: judge/models/problem_data.py:52 +#: judge/models/problem_data.py:50 msgid "custom checker file" msgstr "" -#: judge/models/problem_data.py:58 +#: judge/models/problem_data.py:56 msgid "custom validator file" msgstr "" -#: judge/models/problem_data.py:108 +#: judge/models/problem_data.py:97 msgid "problem data set" msgstr "problemas de conjunto de datos" -#: judge/models/problem_data.py:110 +#: judge/models/problem_data.py:99 msgid "case position" msgstr "posición del caso" -#: judge/models/problem_data.py:111 +#: judge/models/problem_data.py:100 msgid "case type" msgstr "tipo de caso" -#: judge/models/problem_data.py:112 +#: judge/models/problem_data.py:101 msgid "Normal case" msgstr "Caso normal" -#: judge/models/problem_data.py:113 +#: judge/models/problem_data.py:102 msgid "Batch start" msgstr "Lote de inicio" -#: judge/models/problem_data.py:114 +#: judge/models/problem_data.py:103 msgid "Batch end" msgstr "Lote final" -#: judge/models/problem_data.py:116 +#: judge/models/problem_data.py:105 msgid "input file name" msgstr "nombre de archivo de entrada" -#: judge/models/problem_data.py:117 +#: judge/models/problem_data.py:106 msgid "output file name" msgstr "nombre del archivo de salida" -#: judge/models/problem_data.py:118 +#: judge/models/problem_data.py:107 msgid "generator arguments" msgstr "generador de argumentos" -#: judge/models/problem_data.py:119 +#: judge/models/problem_data.py:108 msgid "point value" msgstr "valor del punto" -#: judge/models/problem_data.py:120 +#: judge/models/problem_data.py:109 msgid "case is pretest?" msgstr "¿Se trata de una prueba previa?" @@ -1742,7 +1626,7 @@ msgid "" msgstr "" #: judge/models/profile.py:76 judge/models/profile.py:93 -#: judge/models/profile.py:212 +#: judge/models/profile.py:192 msgid "organization" msgstr "onganización" @@ -1838,31 +1722,31 @@ msgstr "" msgid "Notes for administrators regarding this user." msgstr "" -#: judge/models/profile.py:206 +#: judge/models/profile.py:186 msgid "user profile" msgstr "perfil del usuario" -#: judge/models/profile.py:207 +#: judge/models/profile.py:187 msgid "user profiles" msgstr "perfiles de usuarios" -#: judge/models/profile.py:214 +#: judge/models/profile.py:194 msgid "request time" msgstr "tiempo requerido" -#: judge/models/profile.py:215 +#: judge/models/profile.py:195 msgid "state" msgstr "estado" -#: judge/models/profile.py:220 +#: judge/models/profile.py:200 msgid "reason" msgstr "razón" -#: judge/models/profile.py:223 +#: judge/models/profile.py:203 msgid "organization join request" msgstr "solicitud para asociarse a la organización" -#: judge/models/profile.py:224 +#: judge/models/profile.py:204 msgid "organization join requests" msgstr "peticiones para unirse a la organización" @@ -1973,88 +1857,88 @@ msgid "The extension of source files, e.g., \"py\" or \"cpp\"." msgstr "" "La extensión de los archivos de código fuente, por ejemplo, \"py\" o \"cpp\"." -#: judge/models/runtime.py:112 +#: judge/models/runtime.py:109 msgid "languages" msgstr "idiomas" -#: judge/models/runtime.py:116 +#: judge/models/runtime.py:113 msgid "language to which this runtime belongs" msgstr "idioma al que pertenece este tiempo de ejecución" -#: judge/models/runtime.py:117 +#: judge/models/runtime.py:114 msgid "judge on which this runtime exists" msgstr "juzgar donde exista el runtime" -#: judge/models/runtime.py:118 +#: judge/models/runtime.py:115 msgid "runtime name" msgstr "nombre de tiempo de ejecución" -#: judge/models/runtime.py:119 +#: judge/models/runtime.py:116 msgid "runtime version" msgstr "versión de tiempo de ejecución" -#: judge/models/runtime.py:120 +#: judge/models/runtime.py:117 msgid "order in which to display this runtime" msgstr "orden en el que se muestra este tiempo de ejecución" -#: judge/models/runtime.py:124 +#: judge/models/runtime.py:121 msgid "Server name, hostname-style" msgstr "Nombre del servidor, nombre del host-style" -#: judge/models/runtime.py:125 +#: judge/models/runtime.py:122 msgid "time of creation" msgstr "fecha de creación" -#: judge/models/runtime.py:126 +#: judge/models/runtime.py:123 #, fuzzy #| msgid "A key to authenticated this judge" msgid "A key to authenticate this judge" msgstr "Una llave para validar este juez" -#: judge/models/runtime.py:127 +#: judge/models/runtime.py:124 msgid "authentication key" msgstr "llave de autentificación" -#: judge/models/runtime.py:128 +#: judge/models/runtime.py:125 msgid "block judge" msgstr "" -#: judge/models/runtime.py:129 +#: judge/models/runtime.py:126 msgid "" "Whether this judge should be blocked from connecting, even if its key is " "correct." msgstr "" -#: judge/models/runtime.py:131 +#: judge/models/runtime.py:128 msgid "judge online status" msgstr "estatus del juez en línea" -#: judge/models/runtime.py:132 +#: judge/models/runtime.py:129 msgid "judge start time" msgstr "hola de inicio del juzgado" -#: judge/models/runtime.py:133 +#: judge/models/runtime.py:130 msgid "response time" msgstr "tiempo de respuesta" -#: judge/models/runtime.py:134 +#: judge/models/runtime.py:131 msgid "system load" msgstr "carga del sistema" -#: judge/models/runtime.py:135 +#: judge/models/runtime.py:132 msgid "Load for the last minute, divided by processors to be fair." msgstr "Carga para el último minuto, dividido procesadores para ser justos." -#: judge/models/runtime.py:139 judge/models/runtime.py:179 +#: judge/models/runtime.py:136 judge/models/runtime.py:176 msgid "judges" msgstr "jueces" -#: judge/models/runtime.py:178 +#: judge/models/runtime.py:175 msgid "judge" msgstr "juez" #: judge/models/submission.py:20 judge/models/submission.py:47 -#: judge/utils/problems.py:79 +#: judge/utils/problems.py:77 msgid "Accepted" msgstr "Aceptado" @@ -2083,7 +1967,7 @@ msgid "Runtime Error" msgstr "Error de tiempo de ejecución" #: judge/models/submission.py:27 judge/models/submission.py:41 -#: judge/models/submission.py:55 judge/utils/problems.py:81 +#: judge/models/submission.py:55 judge/utils/problems.py:79 msgid "Compile Error" msgstr "Error de compilación" @@ -2124,15 +2008,15 @@ msgstr "Error interno (juzgando error del servidor)" msgid "submission time" msgstr "tiempo de envío" -#: judge/models/submission.py:67 judge/models/submission.py:203 +#: judge/models/submission.py:67 judge/models/submission.py:201 msgid "execution time" msgstr "tiempo de ejecución" -#: judge/models/submission.py:68 judge/models/submission.py:204 +#: judge/models/submission.py:68 judge/models/submission.py:202 msgid "memory usage" msgstr "uso de memoria" -#: judge/models/submission.py:69 judge/models/submission.py:205 +#: judge/models/submission.py:69 judge/models/submission.py:203 msgid "points granted" msgstr "puntos otorgados" @@ -2169,64 +2053,58 @@ msgid "judged on" msgstr "juzgado en" #: judge/models/submission.py:81 -#, fuzzy -#| msgid "submission time" -msgid "submission judge time" -msgstr "tiempo de envío" - -#: judge/models/submission.py:82 msgid "was rejudged by admin" msgstr "fue reevaluado por el administrador" -#: judge/models/submission.py:83 +#: judge/models/submission.py:82 msgid "was ran on pretests only" msgstr "solo se ejecutó en pruebas previas" -#: judge/models/submission.py:184 templates/contest/moss.html:58 +#: judge/models/submission.py:182 templates/contest/moss.html:58 msgid "submissions" msgstr "envíos" -#: judge/models/submission.py:188 judge/models/submission.py:199 +#: judge/models/submission.py:186 judge/models/submission.py:197 msgid "associated submission" msgstr "presentaciones asociadas" -#: judge/models/submission.py:190 +#: judge/models/submission.py:188 msgid "source code" msgstr "código fuente" -#: judge/models/submission.py:201 +#: judge/models/submission.py:199 msgid "test case ID" msgstr "identificación en caso de prueba" -#: judge/models/submission.py:202 +#: judge/models/submission.py:200 msgid "status flag" msgstr "indicador de estado" -#: judge/models/submission.py:206 +#: judge/models/submission.py:204 msgid "points possible" msgstr "puntos posibles" -#: judge/models/submission.py:207 +#: judge/models/submission.py:205 msgid "batch number" msgstr "número de lote" -#: judge/models/submission.py:208 +#: judge/models/submission.py:206 msgid "judging feedback" msgstr "respuesta del juzgado" -#: judge/models/submission.py:209 +#: judge/models/submission.py:207 msgid "extended judging feedback" msgstr "" -#: judge/models/submission.py:210 +#: judge/models/submission.py:208 msgid "program output" msgstr "salida del programa" -#: judge/models/submission.py:218 +#: judge/models/submission.py:216 msgid "submission test case" msgstr "prueba de presentación" -#: judge/models/submission.py:219 +#: judge/models/submission.py:217 msgid "submission test cases" msgstr "pruebas de presentación" @@ -2278,24 +2156,12 @@ msgstr "publicación" msgid "message time" msgstr "hora del mensaje" -#: judge/pdf_problems.py:147 judge/pdf_problems.py:199 -#: judge/pdf_problems.py:259 +#: judge/pdf_problems.py:134 judge/pdf_problems.py:186 +#: judge/pdf_problems.py:246 msgid "Page [page] of [topage]" msgstr "Página [page] de [topage]" -#: judge/pdf_problems.py:280 -#, fuzzy, python-format -#| msgid "Page %d of Posts" -msgid "Page %s of %s" -msgstr "Página %d de publicaciones" - -#: judge/tasks/contest.py:19 -#, fuzzy -#| msgid "Recalculate scores" -msgid "Recalculating contest scores" -msgstr "Recalcular puntajes" - -#: judge/tasks/contest.py:40 +#: judge/tasks/moss.py:25 msgid "Running MOSS" msgstr "" @@ -2307,62 +2173,62 @@ msgstr "" msgid "Recalculating user points" msgstr "" -#: judge/utils/problem_data.py:70 +#: judge/utils/problem_data.py:68 msgid "Empty batches not allowed." msgstr "No está permitido contraseñas vacías." -#: judge/utils/problem_data.py:78 judge/utils/problem_data.py:99 +#: judge/utils/problem_data.py:76 judge/utils/problem_data.py:97 #, fuzzy #| msgid "How did you corrupt the generator path?" msgid "How did you corrupt the custom checker path?" msgstr "¿Cómo corrompió la ruta del generador?" -#: judge/utils/problem_data.py:120 +#: judge/utils/problem_data.py:118 #, python-format msgid "Points must be defined for non-batch case #%d." msgstr "Puntos deben ser definidos para casos de no lote #%d." -#: judge/utils/problem_data.py:125 +#: judge/utils/problem_data.py:123 #, python-format msgid "Input file for case %d does not exist: %s" msgstr "El archivo de entrada para el caso %d no existe: %s" -#: judge/utils/problem_data.py:128 +#: judge/utils/problem_data.py:126 #, python-format msgid "Output file for case %d does not exist: %s" msgstr "El archivo de salida para el caso %d no existe: %s" -#: judge/utils/problem_data.py:153 +#: judge/utils/problem_data.py:151 #, python-format msgid "Batch start case #%d requires points." msgstr "El caso de inicio de lote #%d requiere puntos." -#: judge/utils/problem_data.py:174 +#: judge/utils/problem_data.py:172 #, python-format msgid "Attempt to end batch outside of one in case #%d" msgstr "" -#: judge/utils/problem_data.py:192 +#: judge/utils/problem_data.py:190 msgid "How did you corrupt the zip path?" msgstr "¿Cómo usted corrompió la ruta postal?" -#: judge/utils/problem_data.py:198 +#: judge/utils/problem_data.py:196 msgid "How did you corrupt the generator path?" msgstr "¿Cómo corrompió la ruta del generador?" -#: judge/utils/problems.py:80 +#: judge/utils/problems.py:78 msgid "Wrong" msgstr "" -#: judge/utils/problems.py:82 +#: judge/utils/problems.py:80 msgid "Timeout" msgstr "" -#: judge/utils/problems.py:83 +#: judge/utils/problems.py:81 msgid "Error" msgstr "" -#: judge/utils/problems.py:94 +#: judge/utils/problems.py:92 msgid "Can't pass both queryset and keyword filters" msgstr "" "No se pueden pasar los filtros de consulta y conjunto de palabras clave" @@ -2406,8 +2272,7 @@ msgctxt "hours and minutes" msgid "%h:%m" msgstr "%h:%m" -#: judge/views/about.py:7 templates/organization/home.html:112 -#: templates/user/user-about.html:83 templates/user/user-tabs.html:4 +#: judge/views/about.py:7 templates/user/user-about.html:33 msgid "About" msgstr "Sobre" @@ -2415,167 +2280,157 @@ msgstr "Sobre" msgid "Custom Checker Sample" msgstr "" -#: judge/views/blog.py:45 +#: judge/views/blog.py:38 #, python-format msgid "Page %d of Posts" msgstr "Página %d de publicaciones" -#: judge/views/comment.py:28 +#: judge/views/comment.py:27 msgid "Messing around, are we?" msgstr "¿Estamos perdiendo el tiempo?" -#: judge/views/comment.py:37 +#: judge/views/comment.py:36 msgid "You must solve at least one problem before you can vote." msgstr "" -#: judge/views/comment.py:64 +#: judge/views/comment.py:63 msgid "You already voted." msgstr "Tu ya votaste." -#: judge/views/comment.py:126 judge/views/organization.py:344 +#: judge/views/comment.py:120 judge/views/organization.py:299 msgid "Edited from site" msgstr "Editado desde sitio" -#: judge/views/comment.py:147 +#: judge/views/comment.py:141 msgid "Editing comment" msgstr "Comentario editado" -#: judge/views/contests.py:57 judge/views/contests.py:247 -#: judge/views/contests.py:250 judge/views/contests.py:424 +#: judge/views/contests.py:55 judge/views/contests.py:215 +#: judge/views/contests.py:218 judge/views/contests.py:389 msgid "No such contest" msgstr "No hay tal concurso" -#: judge/views/contests.py:58 judge/views/contests.py:248 +#: judge/views/contests.py:56 judge/views/contests.py:216 #, python-format msgid "Could not find a contest with the key \"%s\"." msgstr "No se pudo encontrar una publicación con la clave \"%s\"." -#: judge/views/contests.py:71 +#: judge/views/contests.py:81 msgid "Contests" msgstr "Concursos" -#: judge/views/contests.py:251 +#: judge/views/contests.py:219 msgid "Could not find such contest." msgstr "No se pudo encontrar dicho concurso." -#: judge/views/contests.py:254 +#: judge/views/contests.py:222 #, python-format msgid "Access to contest \"%s\" denied" msgstr "Acceso al concurso \"%s\" denegado" -#: judge/views/contests.py:278 +#: judge/views/contests.py:246 msgid "Clone Contest" msgstr "" -#: judge/views/contests.py:343 +#: judge/views/contests.py:309 msgid "Contest not ongoing" msgstr "Concurso no permanente" -#: judge/views/contests.py:344 +#: judge/views/contests.py:310 #, python-format msgid "\"%s\" is not currently ongoing." msgstr "\"%s\" no esta actualmente en curso." -#: judge/views/contests.py:348 +#: judge/views/contests.py:314 msgid "Already in contest" msgstr "Ya en el concurso" -#: judge/views/contests.py:349 +#: judge/views/contests.py:315 #, python-format msgid "You are already in a contest: \"%s\"." msgstr "Ya estas en el concurso: \"%s\"." -#: judge/views/contests.py:352 +#: judge/views/contests.py:318 msgid "Banned from joining" msgstr "" -#: judge/views/contests.py:353 +#: judge/views/contests.py:319 msgid "" "You have been declared persona non grata for this contest. You are " "permanently barred from joining this contest." msgstr "" -#: judge/views/contests.py:414 +#: judge/views/contests.py:379 #, python-format msgid "Enter access code for \"%s\"" msgstr "Ingrese el código de acceso para \"%s\"" -#: judge/views/contests.py:425 +#: judge/views/contests.py:390 #, python-format msgid "You are not in contest \"%s\"." msgstr "Tu no estas concursando \"%s\"." -#: judge/views/contests.py:444 +#: judge/views/contests.py:409 msgid "ContestCalendar requires integer year and month" msgstr "" -#: judge/views/contests.py:484 +#: judge/views/contests.py:449 #, python-format msgid "Contests in %(month)s" msgstr "Concursos en %(month)s" -#: judge/views/contests.py:484 +#: judge/views/contests.py:449 msgid "F Y" msgstr "" -#: judge/views/contests.py:532 +#: judge/views/contests.py:496 #, fuzzy, python-format #| msgid "Statistics" msgid "%s Statistics" msgstr "Estadística" -#: judge/views/contests.py:717 +#: judge/views/contests.py:601 +msgid "???" +msgstr "" + +#: judge/views/contests.py:664 #, python-format msgid "%s Rankings" msgstr "%s Clasificaciones" -#: judge/views/contests.py:725 -msgid "???" -msgstr "" - -#: judge/views/contests.py:741 +#: judge/views/contests.py:680 #, python-format msgid "Your participation in %s" msgstr "Su participación en %s" -#: judge/views/contests.py:742 +#: judge/views/contests.py:681 #, python-format msgid "%s's participation in %s" msgstr "participación de %s en %s" -#: judge/views/contests.py:749 +#: judge/views/contests.py:685 msgid "Live" msgstr "En Vivo" -#: judge/views/contests.py:761 templates/contest/contest-tabs.html:13 +#: judge/views/contests.py:697 msgid "Participation" msgstr "Participación" -#: judge/views/contests.py:808 +#: judge/views/contests.py:743 #, python-format msgid "%s MOSS Results" msgstr "" -#: judge/views/contests.py:835 +#: judge/views/contests.py:770 #, python-format msgid "Running MOSS for %s..." msgstr "" -#: judge/views/contests.py:858 +#: judge/views/contests.py:793 #, python-format msgid "Contest tag: %s" msgstr "Concurso etiqueta: %s" -#: judge/views/contests.py:868 judge/views/ticket.py:57 -msgid "Issue description" -msgstr "Descripción del problema" - -#: judge/views/contests.py:911 -#, fuzzy, python-format -#| msgid "clarification body" -msgid "New clarification for %s" -msgstr "calificación del cuerpo" - #: judge/views/error.py:14 msgid "404 error" msgstr "404 error" @@ -2596,76 +2451,69 @@ msgid "corrupt page %s" msgstr "página corrupta %s" #: judge/views/language.py:12 templates/status/judge-status-table.html:9 -#: templates/status/status-tabs.html:5 msgid "Runtimes" msgstr "Duración" -#: judge/views/notification.py:40 -#, python-format -msgid "Notifications (%d unseen)" -msgstr "" - -#: judge/views/organization.py:59 judge/views/organization.py:62 +#: judge/views/organization.py:44 judge/views/organization.py:47 msgid "No such organization" msgstr "Ninguna organización" -#: judge/views/organization.py:60 +#: judge/views/organization.py:45 #, python-format msgid "Could not find an organization with the key \"%s\"." msgstr "No se encontró una organización con la clave \"%s\"." -#: judge/views/organization.py:63 +#: judge/views/organization.py:48 msgid "Could not find such organization." msgstr "No se pudo encontrar tal organización." -#: judge/views/organization.py:79 judge/views/register.py:34 -#: templates/organization/list.html:32 templates/user/import/table_csv.html:9 -#: templates/user/user-list-tabs.html:6 +#: judge/views/organization.py:72 judge/views/register.py:34 +#: templates/organization/list.html:15 msgid "Organizations" msgstr "Organizaciones" -#: judge/views/organization.py:130 +#: judge/views/organization.py:93 #, python-format msgid "%s Members" msgstr "%s miembros" -#: judge/views/organization.py:159 judge/views/organization.py:162 -#: judge/views/organization.py:167 +#: judge/views/organization.py:118 judge/views/organization.py:121 +#: judge/views/organization.py:126 msgid "Joining organization" msgstr "Unirse a la organización" -#: judge/views/organization.py:159 +#: judge/views/organization.py:118 msgid "You are already in the organization." msgstr "Ya estas en esta organización." -#: judge/views/organization.py:162 +#: judge/views/organization.py:121 msgid "This organization is not open." msgstr "Esta organización no está abierta." -#: judge/views/organization.py:179 +#: judge/views/organization.py:138 msgid "Leaving organization" msgstr "Abandonar organización" -#: judge/views/organization.py:179 +#: judge/views/organization.py:138 #, python-format msgid "You are not in \"%s\"." msgstr "No estás en \"%s\"." -#: judge/views/organization.py:203 +#: judge/views/organization.py:162 #, python-format msgid "Request to join %s" msgstr "Solicitar para unirse %s" -#: judge/views/organization.py:221 +#: judge/views/organization.py:180 msgid "Join request detail" msgstr "Únete a detalle de la solicitud" -#: judge/views/organization.py:254 +#: judge/views/organization.py:209 #, python-format msgid "Managing join requests for %s" msgstr "Gestionar solicitudes de unirse para %s" -#: judge/views/organization.py:285 +#: judge/views/organization.py:240 #, python-format msgid "" "Your organization can only receive %d more members. You cannot approve %d " @@ -2674,46 +2522,46 @@ msgstr "" "Su organización solo puede recibir %d miembros más. No puede aprobar %d " "usuarios." -#: judge/views/organization.py:297 +#: judge/views/organization.py:252 #, python-format msgid "Approved %d user." msgid_plural "Approved %d users." msgstr[0] "%d usuarios aprobados." msgstr[1] "Usuarios aprobados \"%d\"." -#: judge/views/organization.py:298 +#: judge/views/organization.py:253 #, python-format msgid "Rejected %d user." msgid_plural "Rejected %d users." msgstr[0] "%d usuarios rechazados." msgstr[1] "Usuarios rechazados \"%d\"." -#: judge/views/organization.py:328 +#: judge/views/organization.py:283 #, python-format msgid "Editing %s" msgstr "Editando %s" -#: judge/views/organization.py:352 judge/views/organization.py:360 +#: judge/views/organization.py:307 judge/views/organization.py:315 msgid "Can't edit organization" msgstr "No se puede editar la organización" -#: judge/views/organization.py:353 +#: judge/views/organization.py:308 msgid "You are not allowed to edit this organization." msgstr "No tiene permitido editar esta organización." -#: judge/views/organization.py:361 +#: judge/views/organization.py:316 msgid "You are not allowed to kick people from this organization." msgstr "No tiene permitido expulsar a personas de esta organización." -#: judge/views/organization.py:366 judge/views/organization.py:370 +#: judge/views/organization.py:321 judge/views/organization.py:325 msgid "Can't kick user" msgstr "No se puede reaccionar en contra del usuario" -#: judge/views/organization.py:367 +#: judge/views/organization.py:322 msgid "The user you are trying to kick does not exist!" msgstr "¡El usuario que estás tratando de poner no existe!" -#: judge/views/organization.py:371 +#: judge/views/organization.py:326 #, python-format msgid "The user you are trying to kick is not in organization: %s." msgstr "El usuario que estás tratando poner no está en la organización: %s." @@ -2737,17 +2585,16 @@ msgstr "Editorial de{0}" msgid "Editorial for {0}" msgstr "Editorial de {0}" -#: judge/views/problem.py:285 templates/contest/contest.html:79 -#: templates/user/user-about.html:28 templates/user/user-tabs.html:5 -#: templates/user/users-table.html:31 +#: judge/views/problem.py:286 templates/contest/contest.html:79 +#: templates/user/users-table.html:23 msgid "Problems" msgstr "Problemas" -#: judge/views/problem.py:585 +#: judge/views/problem.py:547 msgid "Banned from submitting" msgstr "Esta prohibido enviarlo" -#: judge/views/problem.py:586 +#: judge/views/problem.py:548 msgid "" "You have been declared persona non grata for this problem. You are " "permanently barred from submitting this problem." @@ -2755,20 +2602,20 @@ msgstr "" "Usted ha sido declarado persona no grata por este problema. Usted está " "permanentemente impedido en presentar este problema." -#: judge/views/problem.py:600 +#: judge/views/problem.py:562 msgid "Too many submissions" msgstr "Muchos envíos" -#: judge/views/problem.py:601 +#: judge/views/problem.py:563 msgid "You have exceeded the submission limit for this problem." msgstr "Usted ha excedido el límite de presentaciones de este problema." -#: judge/views/problem.py:661 judge/views/problem.py:664 +#: judge/views/problem.py:633 judge/views/problem.py:636 #, python-format msgid "Submit to %(problem)s" msgstr "Enviar a %(problem)s" -#: judge/views/problem.py:679 +#: judge/views/problem.py:652 msgid "Clone Problem" msgstr "" @@ -2809,22 +2656,22 @@ msgstr "Editando datos para %s" msgid "Generated init.yml for %s" msgstr "Generado init.yml para %s" -#: judge/views/problem_manage.py:52 judge/views/problem_manage.py:55 +#: judge/views/problem_manage.py:50 judge/views/problem_manage.py:53 #, python-format msgid "Managing submissions for %s" msgstr "" -#: judge/views/problem_manage.py:97 +#: judge/views/problem_manage.py:95 #, python-format msgid "Rejudging selected submissions for %s..." msgstr "" -#: judge/views/problem_manage.py:141 +#: judge/views/problem_manage.py:110 #, python-format msgid "Rescoring all submissions for %s..." msgstr "" -#: judge/views/problem_manage.py:150 +#: judge/views/problem_manage.py:119 #, python-format msgid "Successfully scheduled %d submission for rejudging." msgid_plural "Successfully scheduled %d submissions for rejudging." @@ -2877,7 +2724,7 @@ msgstr "Idioma preferido" msgid "Subscribe to newsletter?" msgstr "¿suscribete en el boletín de noticias?" -#: judge/views/register.py:55 +#: judge/views/register.py:45 #, python-format msgid "" "The email address \"%s\" is already taken. Only one registration is allowed " @@ -2886,7 +2733,7 @@ msgstr "" "La dirección de email \"%s\" ya ha sido tomada. Sólo un registro es " "permitido por dirección." -#: judge/views/register.py:61 +#: judge/views/register.py:51 msgid "" "Your email provider is not allowed due to history of abuse. Please use a " "reputable email provider." @@ -2894,11 +2741,11 @@ msgstr "" "Su proveedor de correo electrónico no esta permitido debido a el historial " "de abuso. Por favor utilice un proveedor de correo con buena reputación." -#: judge/views/register.py:67 judge/views/register.py:105 +#: judge/views/register.py:57 judge/views/register.py:95 msgid "Registration" msgstr "Registro de usuarios" -#: judge/views/register.py:116 +#: judge/views/register.py:106 msgid "Authentication failure" msgstr "Error de autenticación" @@ -2914,49 +2761,49 @@ msgstr "Estado" msgid "Version matrix" msgstr "Versión matriz" -#: judge/views/submission.py:84 judge/views/submission.py:91 +#: judge/views/submission.py:83 judge/views/submission.py:90 #, python-format msgid "Submission of %(problem)s by %(user)s" msgstr "Presentación de %(problem)s por %(user)s" -#: judge/views/submission.py:244 judge/views/submission.py:245 -#: templates/problem/problem.html:167 +#: judge/views/submission.py:227 judge/views/submission.py:228 +#: templates/problem/problem.html:127 msgid "All submissions" msgstr "Todos los envíos" -#: judge/views/submission.py:404 +#: judge/views/submission.py:384 msgid "All my submissions" msgstr "Todos mis envíos" -#: judge/views/submission.py:405 +#: judge/views/submission.py:385 #, python-format msgid "All submissions by %s" msgstr "Todos las presentaciones por %s" -#: judge/views/submission.py:436 +#: judge/views/submission.py:416 #, python-format msgid "All submissions for %s" msgstr "Todas las presentaciones por %s" -#: judge/views/submission.py:455 +#: judge/views/submission.py:435 msgid "Must pass a problem" msgstr "Debe pasar un problema" -#: judge/views/submission.py:501 +#: judge/views/submission.py:481 #, python-format msgid "My submissions for %(problem)s" msgstr "Mis presentaciones de %(problem)s" -#: judge/views/submission.py:502 +#: judge/views/submission.py:482 #, python-format msgid "%(user)s's submissions for %(problem)s" msgstr "%(user)s's presentaciones para %(problem)s" -#: judge/views/submission.py:603 +#: judge/views/submission.py:583 msgid "Must pass a contest" msgstr "Debe pasar un concurso" -#: judge/views/submission.py:622 +#: judge/views/submission.py:602 #, python-brace-format msgid "" "{0}'s submissions for {2} in {0} envíos de {2} en " "{4}" -#: judge/views/submission.py:629 +#: judge/views/submission.py:609 #, python-brace-format msgid "" "{0}'s submissions for problem {2} in {3}" @@ -2973,44 +2820,48 @@ msgid "" msgstr "" "{0} envíos de problema {2} en {3}" -#: judge/views/ticket.py:50 judge/views/ticket.py:56 +#: judge/views/ticket.py:33 judge/views/ticket.py:39 msgid "Ticket title" msgstr "Título del ticket" -#: judge/views/ticket.py:107 judge/views/ticket.py:110 +#: judge/views/ticket.py:40 +msgid "Issue description" +msgstr "Descripción del problema" + +#: judge/views/ticket.py:85 judge/views/ticket.py:88 #, python-format msgid "New ticket for %s" msgstr "Nuevo ticket de %s" -#: judge/views/ticket.py:170 +#: judge/views/ticket.py:142 #, python-format msgid "%(title)s - Ticket %(id)d" msgstr "%(title)s - Ticket %(id)d" -#: judge/views/ticket.py:279 +#: judge/views/ticket.py:251 #, python-format msgid "Tickets - Page %(number)d of %(total)d" msgstr "Tickets - Página %(number)d de %(total)d" -#: judge/views/ticket.py:328 +#: judge/views/ticket.py:300 #, python-format msgid "New Ticket: %s" msgstr "Tickets nuevos: %s" -#: judge/views/ticket.py:329 +#: judge/views/ticket.py:301 #, python-format msgid "#%(id)d, assigned to: %(users)s" msgstr "#%(id)d asignado para: %(users)s" -#: judge/views/ticket.py:331 +#: judge/views/ticket.py:303 msgid ", " msgstr ", " -#: judge/views/ticket.py:331 +#: judge/views/ticket.py:303 msgid "no one" msgstr "ninguno" -#: judge/views/ticket.py:351 +#: judge/views/ticket.py:323 #, fuzzy, python-format #| msgid "New Ticket: %s" msgid "New Ticket Message For: %s" @@ -3028,52 +2879,41 @@ msgstr "" msgid "Perform Two Factor Authentication" msgstr "" -#: judge/views/user.py:74 +#: judge/views/user.py:68 msgid "No such user" msgstr "No existe este usuario" -#: judge/views/user.py:74 +#: judge/views/user.py:68 #, python-format msgid "No user handle \"%s\"." msgstr "Ningún usuario se encarga de \"%s\"." -#: judge/views/user.py:78 +#: judge/views/user.py:72 msgid "My account" msgstr "Mi cuenta" -#: judge/views/user.py:79 +#: judge/views/user.py:73 #, python-format msgid "User %s" msgstr "Usuario %s" -#: judge/views/user.py:148 -#, fuzzy -#| msgid "M j, Y, G:i" -msgid "M j, Y" -msgstr "M j, Y, G:i" - -#: judge/views/user.py:171 +#: judge/views/user.py:136 msgid "M j, Y, G:i" msgstr "M j, Y, G:i" -#: judge/views/user.py:290 +#: judge/views/user.py:221 msgid "Updated on site" msgstr "Actualizado en el sitio" -#: judge/views/user.py:323 templates/admin/auth/user/change_form.html:14 -#: templates/admin/auth/user/change_form.html:17 templates/base.html:238 -#: templates/user/user-tabs.html:10 +#: judge/views/user.py:254 templates/admin/auth/user/change_form.html:14 +#: templates/admin/auth/user/change_form.html:17 templates/base.html:224 msgid "Edit profile" msgstr "Modificar perfil" -#: judge/views/user.py:332 templates/user/user-list-tabs.html:4 +#: judge/views/user.py:263 msgid "Leaderboard" msgstr "Tabla de calificación" -#: judge/views/user.py:407 -msgid "Import Users" -msgstr "" - #: judge/views/widgets.py:48 judge/views/widgets.py:58 #, python-format msgid "Invalid upstream data: %s" @@ -3111,7 +2951,7 @@ msgid "View Submissions" msgstr "" #: templates/admin/judge/problem/change_form.html:17 -#: templates/user/user-base.html:112 +#: templates/user/user-base.html:61 msgid "View submissions" msgstr "Ver presentaciones" @@ -3126,157 +2966,92 @@ msgstr "Editar usuario" msgid "Rejudge" msgstr "Juzgar de nuevo" -#: templates/base.html:230 -#, python-format -msgid "Hello, %(username)s." -msgstr "Hola, %(username)s." - -#: templates/base.html:236 templates/comments/list.html:89 -#: templates/contest/contest-list-tabs.html:24 -#: templates/contest/ranking-table.html:53 -#: templates/problem/problem-list-tabs.html:6 +#: templates/base.html:222 templates/comments/list.html:89 +#: templates/contest/ranking-table.html:39 #: templates/submission/info-base.html:12 -#: templates/submission/submission-list-tabs.html:15 msgid "Admin" msgstr "Administrador" -#: templates/base.html:245 +#: templates/base.html:231 msgid "Log out" msgstr "Cerrar Sesión" -#: templates/base.html:254 +#: templates/base.html:240 #: templates/registration/password_reset_complete.html:4 msgid "Log in" msgstr "Iniciar sesión" -#: templates/base.html:255 templates/registration/registration_form.html:177 +#: templates/base.html:241 templates/registration/registration_form.html:177 msgid "or" msgstr "o" -#: templates/base.html:256 +#: templates/base.html:242 msgid "Sign up" msgstr "" -#: templates/base.html:271 +#: templates/base.html:254 msgid "spectating" msgstr "modo de espectador" -#: templates/base.html:284 +#: templates/base.html:267 msgid "This site works best with JavaScript enabled." msgstr "Esta aplicación funciona mejor con JavaScript activado." -#: templates/blog/blog.html:13 templates/comments/list.html:68 -#: templates/comments/list.html:83 templates/contest/contest-tabs.html:23 -#: templates/contest/tag-title.html:9 templates/flatpages/admin_link.html:3 -#: templates/license.html:10 templates/problem/editorial.html:14 +#: templates/blog/content.html:13 templates/comments/list.html:68 +#: templates/comments/list.html:83 templates/contest/tag-title.html:9 +#: templates/flatpages/admin_link.html:3 templates/license.html:10 +#: templates/problem/editorial.html:14 msgid "Edit" msgstr "Editar" -#: templates/blog/blog.html:26 -#, python-format -msgid "" -"\n" -" posted on %(time)s\n" -" " -msgstr "" -"\n" -" publicada en %(time)s\n" -" " - -#: templates/blog/content.html:10 -#, python-brace-format -msgid "posted on {time}" -msgstr "publicado en {time}" - -#: templates/blog/dashboard.html:21 -#, python-format -msgid "" -"\n" -" on %(time)s\n" -" " -msgstr "" -"\n" -" en %(time)s\n" -" " - -#: templates/blog/list.html:93 +#: templates/blog/list.html:85 msgid "Blog" msgstr "Blog" -#: templates/blog/list.html:95 +#: templates/blog/list.html:87 msgid "Events" msgstr "Eventos" -#: templates/blog/list.html:100 +#: templates/blog/list.html:92 msgid "News" msgstr "Noticias" -#: templates/blog/list.html:115 templates/problem/list.html:347 -#: templates/problem/problem.html:361 +#: templates/blog/list.html:130 templates/problem/problem.html:310 msgid "Clarifications" msgstr "Aclaraciones" -#: templates/blog/list.html:121 -msgid "Add" -msgstr "" - -#: templates/blog/list.html:140 templates/problem/list.html:369 -#: templates/problem/problem.html:372 +#: templates/blog/list.html:146 templates/problem/problem.html:321 msgid "No clarifications have been made at this time." msgstr "No se han hecho aclaraciones en este momento." -#: templates/blog/list.html:148 +#: templates/blog/list.html:154 msgid "Ongoing contests" msgstr "Concursos en marcha" -#: templates/blog/list.html:166 +#: templates/blog/list.html:172 msgid "Upcoming contests" msgstr "Próximos concursos" -#: templates/blog/list.html:184 -msgid "My open tickets" -msgstr "Mis tickets abiertos" - -#: templates/blog/list.html:206 -msgid "New tickets" -msgstr "Tickets nuevos" - -#: templates/blog/list.html:227 -msgid "New problems" -msgstr "Problemas nuevos" - -#: templates/blog/list.html:244 +#: templates/blog/list.html:189 msgid "Comment stream" msgstr "Corriente del comentario" -#: templates/chat/chat.html:305 -msgid "Chat" +#: templates/blog/list.html:208 +msgid "New problems" +msgstr "Problemas nuevos" + +#: templates/blog/list.html:225 +msgid "My open tickets" +msgstr "Mis tickets abiertos" + +#: templates/blog/list.html:246 +msgid "New tickets" +msgstr "Tickets nuevos" + +#: templates/chat/chat.html:167 +msgid "Your message" msgstr "" -#: templates/chat/chat.html:307 templates/chat/chat.html:314 -#, fuzzy -#| msgid "Online Judge" -msgid "Online Users" -msgstr "Juez en línea" - -#: templates/chat/chat.html:315 -msgid "Refresh" -msgstr "" - -#: templates/chat/chat.html:333 -msgid "Emoji" -msgstr "" - -#: templates/chat/chat.html:334 -msgid "Enter your message" -msgstr "" - -#: templates/chat/message.html:20 -#, fuzzy -#| msgid "Delete?" -msgid "Delete" -msgstr "¿Eliminar?" - #: templates/comments/list.html:2 msgid "Comments" msgstr "Comentarios" @@ -3285,21 +3060,11 @@ msgstr "Comentarios" msgid "Please login to vote" msgstr "Por favor iniciar sesión para votar" -#: templates/comments/list.html:40 -#, python-brace-format -msgid "commented on {time}" -msgstr "comentado en {time}" - -#: templates/comments/list.html:49 -#, python-format -msgid "edit %(edits)s" -msgstr "editar %(edits)s" - -#: templates/comments/list.html:51 templates/comments/media-js.html:92 +#: templates/comments/list.html:51 templates/comments/media-js.html:77 msgid "edited" msgstr "editado" -#: templates/comments/list.html:60 templates/notification/list.html:14 +#: templates/comments/list.html:60 msgid "Link" msgstr "Enlace" @@ -3307,54 +3072,36 @@ msgstr "Enlace" msgid "Reply" msgstr "Responder" -#: templates/comments/list.html:86 templates/contest/list.html:91 -#: templates/contest/list.html:95 templates/contest/list.html:280 +#: templates/comments/list.html:86 msgid "Hide" msgstr "Ocultar" -#: templates/comments/list.html:101 -#, python-format -msgid "" -"\n" -" This comment is hidden due " -"to too much negative feedback.\n" -" Click here to view it.\n" -" " -msgstr "" - -#: templates/comments/list.html:121 +#: templates/comments/list.html:120 msgid "There are no comments at the moment." msgstr "No hay comentarios por el momento." -#: templates/comments/list.html:127 +#: templates/comments/list.html:126 msgid "New comment" msgstr "Comentario nuevo" -#: templates/comments/list.html:141 +#: templates/comments/list.html:140 msgid "Invalid comment body." msgstr "Cuerpo del comentario inválido." -#: templates/comments/list.html:149 +#: templates/comments/list.html:148 msgid "Post!" msgstr "¡Publicar!" -#: templates/comments/list.html:157 +#: templates/comments/list.html:156 msgid "Comments are disabled on this page." msgstr "" -#: templates/comments/media-js.html:38 -#, fuzzy -#| msgid "no comments" -msgid "Replying to comment" -msgstr "sin comentarios" - -#: templates/comments/media-js.html:87 +#: templates/comments/media-js.html:72 #, python-brace-format msgid "edit {edits}" msgstr "editar {edits}" -#: templates/comments/media-js.html:90 +#: templates/comments/media-js.html:75 msgid "original" msgstr "original" @@ -3398,11 +3145,6 @@ msgstr "Viernes" msgid "Saturday" msgstr "Sábado" -#: templates/contest/clarification.html:52 templates/organization/new.html:10 -#: templates/ticket/new.html:38 -msgid "Create" -msgstr "Crear" - #: templates/contest/clone.html:37 msgid "Enter a new key for the cloned contest:" msgstr "" @@ -3423,110 +3165,50 @@ msgstr "" msgid "Next" msgstr "Siguiente" -#: templates/contest/contest-list-tabs.html:21 -#: templates/problem/problem-list-tabs.html:5 -msgid "List" -msgstr "Lista" - -#: templates/contest/contest-list-tabs.html:22 -msgid "Calendar" -msgstr "Calendario" - -#: templates/contest/contest-tabs.html:4 templates/organization/home.html:105 -msgid "Info" -msgstr "Información" - -#: templates/contest/contest-tabs.html:6 templates/stats/base.html:9 -#: templates/submission/list.html:339 -msgid "Statistics" -msgstr "Estadística" - -#: templates/contest/contest-tabs.html:11 -msgid "Rankings" -msgstr "Valoraciones" - -#: templates/contest/contest-tabs.html:16 -msgid "Hidden Rankings" -msgstr "Rankings ocultos" - -#: templates/contest/contest-tabs.html:21 -msgid "MOSS" -msgstr "" - -#: templates/contest/contest-tabs.html:26 -msgid "Clone" -msgstr "" - -#: templates/contest/contest-tabs.html:38 -#: templates/contest/contest-tabs.html:58 +#: templates/contest/contest-tabs.html:37 msgid "Leave contest" msgstr "Abandonar concurso" -#: templates/contest/contest-tabs.html:45 templates/contest/list.html:388 +#: templates/contest/contest-tabs.html:44 templates/contest/list.html:293 msgid "Virtual join" msgstr "Unión virtual" -#: templates/contest/contest-tabs.html:56 -msgid "Stop spectating" -msgstr "Parar de ver" - -#: templates/contest/contest-tabs.html:65 +#: templates/contest/contest-tabs.html:64 msgid "Spectate contest" msgstr "Ver concurso" -#: templates/contest/contest-tabs.html:72 +#: templates/contest/contest-tabs.html:70 +#: templates/contest/contest-tabs.html:76 msgid "Join contest" msgstr "Unirse al concurso" -#: templates/contest/contest-tabs.html:81 +#: templates/contest/contest-tabs.html:85 msgid "Login to participate" msgstr "Inicio de sesión para participar" -#: templates/contest/contest.html:37 -msgid "Participating virtually." -msgstr "Participación virtual." - -#: templates/contest/contest.html:43 -msgid "Contest is over." -msgstr "El concurso ha terminado." - #: templates/contest/contest.html:59 templates/contest/contest.html:63 msgid "F j, Y, G:i T" msgstr "F j, Y, G:i T" -#: templates/contest/contest.html:59 -#, python-format -msgid "" -"%(time_limit)s window between %(start_time)s and " -"%(end_time)s" -msgstr "" -"%(time_limit)s ventana entre %(start_time)s y %(end_time)s" - -#: templates/contest/contest.html:63 -#, python-format -msgid "%(length)s long starting on %(start_time)s" -msgstr "%(length)s larga a partir de %(start_time)s" - #: templates/contest/contest.html:85 msgid "AC Rate" msgstr "Tasa de AC" -#: templates/contest/contest.html:86 templates/contest/list.html:237 -#: templates/contest/list.html:289 templates/contest/list.html:366 -#: templates/problem/list.html:223 templates/problem/list.html:254 +#: templates/contest/contest.html:86 templates/contest/list.html:153 +#: templates/contest/list.html:195 templates/contest/list.html:271 +#: templates/problem/list.html:212 templates/problem/list.html:238 msgid "Users" msgstr "Usuarios" -#: templates/contest/contest.html:111 templates/problem/list.html:330 +#: templates/contest/contest.html:111 msgid "Editorial" msgstr "Editorial" -#: templates/contest/list.html:83 templates/contest/media-js.html:9 +#: templates/contest/list.html:31 templates/contest/media-js.html:9 msgid "Are you sure you want to join?" msgstr "¿Usted esta seguro de que quiere unirse?" -#: templates/contest/list.html:84 +#: templates/contest/list.html:32 msgid "" "Joining a contest for the first time starts your timer, after which it " "becomes unstoppable." @@ -3534,68 +3216,48 @@ msgstr "" "Al unirse a un concurso por primera vez inicia el cronómetro, después se " "vuelve imparable." -#: templates/contest/list.html:92 templates/contest/list.html:278 -msgid "Show" -msgstr "" - -#: templates/contest/list.html:102 templates/problem/list.html:68 -#, fuzzy -#| msgid "Organizations" -msgid "Organizations..." -msgstr "Organizaciones" - -#: templates/contest/list.html:135 +#: templates/contest/list.html:65 msgid "hidden" msgstr "" -#: templates/contest/list.html:140 +#: templates/contest/list.html:70 msgid "private" msgstr "" -#: templates/contest/list.html:154 +#: templates/contest/list.html:84 msgid "rated" msgstr "" -#: templates/contest/list.html:202 +#: templates/contest/list.html:132 msgid "Spectate" msgstr "Espectador" -#: templates/contest/list.html:208 +#: templates/contest/list.html:138 msgid "Join" msgstr "Unir" -#: templates/contest/list.html:220 -#, fuzzy -#| msgid "Search problems..." -msgid "Search contests..." -msgstr "Búsqueda de problemas..." - -#: templates/contest/list.html:229 -msgid "Search" -msgstr "" - -#: templates/contest/list.html:232 +#: templates/contest/list.html:148 msgid "Active Contests" msgstr "" -#: templates/contest/list.html:236 templates/contest/list.html:288 -#: templates/contest/list.html:327 templates/contest/list.html:365 +#: templates/contest/list.html:152 templates/contest/list.html:194 +#: templates/contest/list.html:232 templates/contest/list.html:270 msgid "Contest" msgstr "Concurso" -#: templates/contest/list.html:275 +#: templates/contest/list.html:190 msgid "Ongoing Contests" msgstr "Concursos en curso" -#: templates/contest/list.html:322 +#: templates/contest/list.html:227 msgid "Upcoming Contests" msgstr "Próximos eventos" -#: templates/contest/list.html:350 +#: templates/contest/list.html:255 msgid "There are no scheduled contests at this time." msgstr "No hay concursos programados en este momento." -#: templates/contest/list.html:356 +#: templates/contest/list.html:261 msgid "Past Contests" msgstr "Concursos pasados" @@ -3651,89 +3313,55 @@ msgid "Only the following organizations may access this contest:" msgstr "" "Sólo las siguientes organizaciones pueden tener acceso a este concurso:" -#: templates/contest/ranking-table.html:9 templates/problem/search-form.html:35 +#: templates/contest/ranking-table.html:7 msgid "Organization" msgstr "Organización" -#: templates/contest/ranking-table.html:10 templates/user/users-table.html:13 -#, fuzzy -#| msgid "full name" -msgid "Full Name" -msgstr "nombre completo" - -#: templates/contest/ranking-table.html:44 +#: templates/contest/ranking-table.html:30 msgid "Un-Disqualify" msgstr "" -#: templates/contest/ranking-table.html:47 +#: templates/contest/ranking-table.html:33 msgid "Disqualify" msgstr "" -#: templates/contest/ranking.html:187 +#: templates/contest/ranking.html:173 #, fuzzy #| msgid "Are you sure you want to join?" msgid "Are you sure you want to disqualify this participation?" msgstr "¿Usted esta seguro de que quiere unirse?" -#: templates/contest/ranking.html:192 +#: templates/contest/ranking.html:178 #, fuzzy #| msgid "Are you sure you want to join?" msgid "Are you sure you want to un-disqualify this participation?" msgstr "¿Usted esta seguro de que quiere unirse?" -#: templates/contest/ranking.html:463 +#: templates/contest/ranking.html:252 msgid "View user participation" msgstr "Ver la participación del usuario" -#: templates/contest/ranking.html:467 +#: templates/contest/ranking.html:256 msgid "Show organizations" msgstr "Mostrar organizaciones" -#: templates/contest/ranking.html:471 -#, fuzzy -#| msgid "full name" -msgid "Show full name" -msgstr "nombre completo" - -#: templates/contest/ranking.html:474 -#, fuzzy -#| msgid "Show my tickets only" -msgid "Show friends only" -msgstr "Sólo mostrar mis tickets" - -#: templates/contest/ranking.html:477 -msgid "Total score only" -msgstr "" - -#: templates/contest/ranking.html:479 -#, fuzzy -#| msgid "virtual participation id" -msgid "Show virtual participation" -msgstr "identificación de la participación virtual" - -#: templates/contest/stats.html:51 +#: templates/contest/stats.html:38 #, fuzzy #| msgid "problem translation" msgid "Problem Status Distribution" msgstr "problemas de traducción" -#: templates/contest/stats.html:56 +#: templates/contest/stats.html:43 #, fuzzy #| msgid "Problem name" msgid "Problem AC Rate" msgstr "Nombre del problema" -#: templates/contest/stats.html:62 -#, fuzzy -#| msgid "problem translation" -msgid "Problem Point Distribution" -msgstr "problemas de traducción" - -#: templates/contest/stats.html:76 templates/stats/language.html:16 +#: templates/contest/stats.html:48 templates/stats/language.html:16 msgid "Submissions by Language" msgstr "Envíos por Lenguaje" -#: templates/contest/stats.html:82 templates/stats/language.html:26 +#: templates/contest/stats.html:54 templates/stats/language.html:26 msgid "Language AC Rate" msgstr "Tasa de AC por Lenguaje" @@ -3742,7 +3370,6 @@ msgid "Source:" msgstr "Origen:" #: templates/newsletter/common.html:6 -#: templates/newsletter/newsletter_list.html:15 #: templates/newsletter/subscription_unsubscribe_activated.html:3 #: templates/newsletter/subscription_unsubscribe_activated.html:6 #: templates/newsletter/subscription_update_activated.html:3 @@ -3750,29 +3377,6 @@ msgstr "Origen:" msgid "Newsletter" msgstr "Boletín informativo" -#: templates/newsletter/newsletter_list.html:2 -#: templates/newsletter/newsletter_list.html:3 -#, fuzzy -#| msgid "Newsletter" -msgid "Newsletter list" -msgstr "Boletín informativo" - -#: templates/newsletter/newsletter_list.html:6 -msgid "Subscribe to get the latest emails about upcoming contests and events." -msgstr "" - -#: templates/newsletter/newsletter_list.html:16 -#, fuzzy -#| msgid "Unsubscribe" -msgid "Subscribe" -msgstr "Desuscribirse" - -#: templates/newsletter/newsletter_list.html:30 -#, fuzzy -#| msgid "Update subscription" -msgid "Update subscriptions" -msgstr "Actualizar suscripción" - #: templates/newsletter/subscription_unsubscribe_activated.html:3 #: templates/newsletter/subscription_unsubscribe_activated.html:6 #: templates/newsletter/subscription_update_activated.html:3 @@ -3843,115 +3447,64 @@ msgstr "" "correo electrónico de activación. En ese correo electrónico encontrará un " "vinculo que debe seguir para actualizar su suscripción." -#: templates/notification/list.html:7 -#, fuzzy -#| msgid "You have not shared any information." -msgid "You have no notifications" -msgstr "No has compartido ninguna información." - -#: templates/notification/list.html:13 -#, fuzzy -#| msgid "activate" -msgid "Activity" -msgstr "activar" - #: templates/organization/edit.html:46 #: templates/organization/requests/pending.html:34 #: templates/ticket/edit-notes.html:4 msgid "Update" msgstr "Actualizar" -#: templates/organization/home.html:41 +#: templates/organization/home.html:7 msgid "Are you sure you want to leave this organization?" msgstr "" -#: templates/organization/home.html:43 +#: templates/organization/home.html:9 msgid "You will have to rejoin to show up on the organization leaderboard." msgstr "" -#: templates/organization/home.html:45 +#: templates/organization/home.html:11 msgid "You will have to request membership in order to join again." msgstr "" -#: templates/organization/home.html:88 -msgid "Join organization" -msgstr "Unirse a esta organización" - -#: templates/organization/home.html:92 -msgid "Request membership" -msgstr "Solicitar membresía" - -#: templates/organization/home.html:122 -#, fuzzy -#| msgid "Organizations" -msgid "Organization news" -msgstr "Organizaciones" - -#: templates/organization/home.html:128 -#, fuzzy -#| msgid "There are no scheduled contests at this time." -msgid "There is no news at this time." -msgstr "No hay concursos programados en este momento." - -#: templates/organization/home.html:137 -#, fuzzy -#| msgid "Contest" -msgid "Controls" -msgstr "Concurso" - -#: templates/organization/home.html:142 -msgid "Edit organization" -msgstr "Editar organización" - -#: templates/organization/home.html:148 -msgid "View requests" -msgstr "Ver solicitud" - -#: templates/organization/home.html:161 -msgid "Admin organization" -msgstr "Administrador de la organización" - -#: templates/organization/home.html:167 -msgid "View members" -msgstr "Ver miembros" - -#: templates/organization/home.html:174 +#: templates/organization/home.html:24 msgid "Leave organization" msgstr "Abandonar organización" -#: templates/organization/home.html:183 -#, fuzzy -#| msgid "See private contests" -msgid "New private contests" -msgstr "Ver publicaciones privadas" +#: templates/organization/home.html:29 +msgid "Join organization" +msgstr "Unirse a esta organización" -#: templates/organization/home.html:193 templates/organization/home.html:208 -#, fuzzy -#| msgid "View as PDF" -msgid "View all" -msgstr "Ver en PDF" +#: templates/organization/home.html:33 +msgid "Request membership" +msgstr "Solicitar membresía" -#: templates/organization/home.html:199 -#, fuzzy -#| msgid "New problems" -msgid "New private problems" -msgstr "Problemas nuevos" +#: templates/organization/home.html:39 +msgid "Edit organization" +msgstr "Editar organización" -#: templates/organization/list.html:40 -#, fuzzy -#| msgid "Show organizations" -msgid "Show my organizations only" -msgstr "Mostrar organizaciones" +#: templates/organization/home.html:43 +msgid "View requests" +msgstr "Ver solicitud" -#: templates/organization/list.html:47 templates/status/language-list.html:34 -#: templates/user/import/table_csv.html:6 +#: templates/organization/home.html:50 +msgid "Admin organization" +msgstr "Administrador de la organización" + +#: templates/organization/home.html:55 +msgid "View members" +msgstr "Ver miembros" + +#: templates/organization/list.html:23 templates/status/language-list.html:34 msgid "Name" msgstr "Nombre" -#: templates/organization/list.html:48 +#: templates/organization/list.html:24 msgid "Members" msgstr "Miembros" +#: templates/organization/new.html:10 templates/ticket/new.html:38 +msgid "Create" +msgstr "Crear" + #: templates/organization/requests/detail.html:13 msgid "User:" msgstr "Usuario:" @@ -3984,7 +3537,7 @@ msgid "There are no requests to approve." msgstr "No hay solicitudes para aprobar." #: templates/organization/requests/pending.html:17 -#: templates/problem/data.html:432 +#: templates/problem/data.html:452 msgid "Delete?" msgstr "¿Eliminar?" @@ -4020,37 +3573,37 @@ msgstr "Expulsar" msgid "Enter a new code for the cloned problem:" msgstr "" -#: templates/problem/data.html:119 +#: templates/problem/data.html:108 #, fuzzy #| msgid "Information" msgid "Instruction" msgstr "Información" -#: templates/problem/data.html:390 +#: templates/problem/data.html:410 msgid "View YAML" msgstr "Ver YAML" -#: templates/problem/data.html:421 templates/problem/data.html:472 +#: templates/problem/data.html:441 templates/problem/data.html:491 msgid "Apply!" msgstr "" -#: templates/problem/data.html:426 +#: templates/problem/data.html:446 msgid "Type" msgstr "Tipo" -#: templates/problem/data.html:427 +#: templates/problem/data.html:447 msgid "Input file" msgstr "Archivo de entrada" -#: templates/problem/data.html:428 +#: templates/problem/data.html:448 msgid "Output file" msgstr "Archivo de salida" -#: templates/problem/data.html:430 +#: templates/problem/data.html:450 msgid "Pretest?" msgstr "Pretest?" -#: templates/problem/data.html:473 +#: templates/problem/data.html:492 msgid "Add new case" msgstr "Añadir nueva etiqueta" @@ -4066,34 +3619,28 @@ msgstr "" "problema y el editorialista.

Presentar una solución oficial antes " "de resolver el problema usted mismo es una infracción banneable." -#: templates/problem/list.html:66 +#: templates/problem/list.html:62 msgid "Filter by type..." msgstr "Filtrar por tipo..." -#: templates/problem/list.html:193 +#: templates/problem/list.html:185 msgid "Hot problems" msgstr "Problemas calientes" -#: templates/problem/list.html:218 templates/problem/list.html:240 -#: templates/problem/search-form.html:45 templates/user/user-problems.html:57 +#: templates/problem/list.html:207 templates/problem/list.html:224 +#: templates/problem/search-form.html:30 templates/user/user-problems.html:57 msgid "Category" msgstr "Categoría" -#: templates/problem/list.html:220 templates/problem/list.html:244 +#: templates/problem/list.html:209 templates/problem/list.html:228 msgid "Types" msgstr "Tipos" -#: templates/problem/list.html:251 +#: templates/problem/list.html:235 #, python-format msgid "AC %%" msgstr "AC%%" -#: templates/problem/list.html:342 -#, fuzzy -#| msgid "Clarifications" -msgid "Add clarifications" -msgstr "Aclaraciones" - #: templates/problem/manage_submission.html:55 msgid "Leave empty to not filter by language" msgstr "" @@ -4102,206 +3649,152 @@ msgstr "" msgid "Leave empty to not filter by result" msgstr "" -#: templates/problem/manage_submission.html:80 +#: templates/problem/manage_submission.html:79 msgid "Need valid values for both start and end IDs." msgstr "" -#: templates/problem/manage_submission.html:83 +#: templates/problem/manage_submission.html:82 msgid "End ID must be after start ID." msgstr "" +#: templates/problem/manage_submission.html:90 +#, python-brace-format +msgid "" +"You are about to rejudge {count} submissions. Are you sure you want to do " +"this?" +msgstr "" + #: templates/problem/manage_submission.html:96 -#, python-brace-format msgid "" -"You are about to {action} {count} submissions. Are you sure you want to do " -"this?" +"You are about to rejudge a few submissions. Are you sure you want to do this?" msgstr "" -#: templates/problem/manage_submission.html:103 -#, python-brace-format -msgid "" -"You are about to {action} a few submissions. Are you sure you want to do " -"this?" +#: templates/problem/manage_submission.html:115 +msgid "Rejudge Submissions" msgstr "" -#: templates/problem/manage_submission.html:127 -#: templates/submission/list.html:309 -msgid "Filter submissions" -msgstr "Filtrar envíos" - -#: templates/problem/manage_submission.html:132 +#: templates/problem/manage_submission.html:120 msgid "Filter by ID:" msgstr "" -#: templates/problem/manage_submission.html:135 +#: templates/problem/manage_submission.html:123 msgid "Starting ID:" msgstr "" -#: templates/problem/manage_submission.html:139 +#: templates/problem/manage_submission.html:127 msgid "Ending ID:" msgstr "" -#: templates/problem/manage_submission.html:143 +#: templates/problem/manage_submission.html:131 msgid "This range includes both endpoints." msgstr "" -#: templates/problem/manage_submission.html:146 +#: templates/problem/manage_submission.html:134 msgid "Filter by language:" msgstr "" -#: templates/problem/manage_submission.html:154 +#: templates/problem/manage_submission.html:142 msgid "Filter by result:" msgstr "" -#: templates/problem/manage_submission.html:164 -#, fuzzy -#| msgid "location" -msgid "Action" -msgstr "ubicación" - -#: templates/problem/manage_submission.html:166 +#: templates/problem/manage_submission.html:150 msgid "Rejudge selected submissions" msgstr "" -#: templates/problem/manage_submission.html:171 -#, fuzzy -#| msgid "Too many submissions" -msgid "Download selected submissions" -msgstr "Muchos envíos" +#: templates/problem/manage_submission.html:157 +msgid "Rescore Everything" +msgstr "" -#: templates/problem/manage_submission.html:177 -#, fuzzy, python-format -#| msgid "Are you sure you want to join?" -msgid "Are you sure you want to rescore %(count)d submissions?" -msgstr "¿Usted esta seguro de que quiere unirse?" - -#: templates/problem/manage_submission.html:178 +#: templates/problem/manage_submission.html:163 msgid "Rescore all submissions" msgstr "" -#: templates/problem/problem.html:132 +#: templates/problem/problem.html:91 msgid "View as PDF" msgstr "Ver en PDF" -#: templates/problem/problem.html:141 templates/problem/problem.html:151 -#: templates/problem/problem.html:156 +#: templates/problem/problem.html:101 templates/problem/problem.html:111 +#: templates/problem/problem.html:116 msgid "Submit solution" msgstr "Enviar solución" -#: templates/problem/problem.html:144 -#, python-format -msgid "%(counter)s submission left" -msgid_plural "%(counter)s submissions left" -msgstr[0] "%(counter)s envío restante" -msgstr[1] "%(counter)s envíos restantes" - -#: templates/problem/problem.html:152 +#: templates/problem/problem.html:112 msgid "0 submissions left" msgstr "0 envíos restantes" -#: templates/problem/problem.html:164 +#: templates/problem/problem.html:124 msgid "My submissions" msgstr "Mis Envíos" -#: templates/problem/problem.html:168 +#: templates/problem/problem.html:128 msgid "Best submissions" msgstr "Mejores envíos" -#: templates/problem/problem.html:172 +#: templates/problem/problem.html:132 msgid "Read editorial" msgstr "Leer editorial" -#: templates/problem/problem.html:177 +#: templates/problem/problem.html:137 msgid "Manage tickets" msgstr "Administrar tickets" -#: templates/problem/problem.html:181 +#: templates/problem/problem.html:141 msgid "Edit problem" msgstr "Editar el problema" -#: templates/problem/problem.html:183 +#: templates/problem/problem.html:143 msgid "Edit test data" msgstr "Editar casos de prueba" -#: templates/problem/problem.html:188 +#: templates/problem/problem.html:148 msgid "My tickets" msgstr "" -#: templates/problem/problem.html:196 +#: templates/problem/problem.html:156 msgid "Manage submissions" msgstr "" -#: templates/problem/problem.html:202 +#: templates/problem/problem.html:162 msgid "Clone problem" msgstr "Clonar problema" -#: templates/problem/problem.html:209 +#: templates/problem/problem.html:169 msgid "Points:" msgstr "Puntos:" -#: templates/problem/problem.html:212 templates/problem/problem.html:214 +#: templates/problem/problem.html:172 templates/problem/problem.html:174 msgid "(partial)" msgstr "(parcial)" -#: templates/problem/problem.html:219 +#: templates/problem/problem.html:179 msgid "Time limit:" msgstr "Tiempo límite:" -#: templates/problem/problem.html:231 +#: templates/problem/problem.html:191 msgid "Memory limit:" msgstr "Límite de memoria:" -#: templates/problem/problem.html:250 -msgid "Author:" -msgid_plural "Authors:" -msgstr[0] "Autor:" -msgstr[1] "Autores:" - -#: templates/problem/problem.html:265 -msgid "Problem type" -msgid_plural "Problem types" -msgstr[0] "Tipo de problema" -msgstr[1] "Tipos de problema" - -#: templates/problem/problem.html:278 +#: templates/problem/problem.html:238 msgid "Allowed languages" msgstr "Idiomas permitidos" -#: templates/problem/problem.html:286 -#, python-format -msgid "No %(lang)s judge online" -msgstr "No hay jueces online para %(lang)s" - -#: templates/problem/problem.html:297 -#, fuzzy -#| msgid "Judge" -msgid "Judge:" -msgid_plural "Judges:" -msgstr[0] "Juez" -msgstr[1] "Juez" - -#: templates/problem/problem.html:314 +#: templates/problem/problem.html:274 msgid "none available" msgstr "" -#: templates/problem/problem.html:326 -#, python-format -msgid "This problem has %(length)s clarification(s)" -msgstr "" - -#: templates/problem/problem.html:350 +#: templates/problem/problem.html:299 msgid "Request clarification" msgstr "Solicitar aclaración" -#: templates/problem/problem.html:352 +#: templates/problem/problem.html:301 msgid "Report an issue" msgstr "Reportar un problema" -#: templates/problem/raw.html:64 +#: templates/problem/raw.html:62 msgid "Time Limit:" msgstr "" -#: templates/problem/raw.html:73 +#: templates/problem/raw.html:71 msgid "Memory Limit:" msgstr "" @@ -4325,83 +3818,39 @@ msgstr "Ocultar problemas resueltos" msgid "Show problem types" msgstr "Mostrar tipos de problemas" -#: templates/problem/search-form.html:32 -#, fuzzy -#| msgid "Read editorial" -msgid "Show editorial" -msgstr "Leer editorial" - -#: templates/problem/search-form.html:48 templates/problem/search-form.html:50 -#: templates/submission/submission-list-tabs.html:4 +#: templates/problem/search-form.html:33 templates/problem/search-form.html:35 msgid "All" msgstr "Todo" -#: templates/problem/search-form.html:62 +#: templates/problem/search-form.html:46 msgid "Problem types" msgstr "Tipos de problema" -#: templates/problem/search-form.html:73 +#: templates/problem/search-form.html:57 msgid "Point range" msgstr "" -#: templates/problem/search-form.html:79 templates/submission/list.html:331 +#: templates/problem/search-form.html:63 templates/submission/list.html:331 #: templates/ticket/list.html:248 msgid "Go" msgstr "Ir" -#: templates/problem/search-form.html:80 +#: templates/problem/search-form.html:64 msgid "Random" msgstr "Aleatorio" -#: templates/problem/submit.html:117 -msgid "Your source code must contain at most 65536 characters." -msgstr "" - -#: templates/problem/submit.html:204 -#, python-format -msgid "" -"Warning! Your default language, %(default_language)s, is " -"unavailable for this problem and has been deselected." -msgstr "" -"¡Advertencia! Su idioma predeterminado, %(default_language)s, " -"no está disponible para este problema y no se seleccionó." - -#: templates/problem/submit.html:215 -#, python-format -msgid "" -"\n" -" You have %(left)s submission left\n" -" " -msgid_plural "" -"\n" -" You have %(left)s submissions left\n" -" " -msgstr[0] "" -"\n" -" Aún tienes %(left)s envío restante\n" -" " -msgstr[1] "" -"\n" -" Aún tienes %(left)s envíos restantes\n" -" " - -#: templates/problem/submit.html:224 +#: templates/problem/submit.html:212 msgid "You have 0 submissions left" msgstr "Usted tiene 0 presentaciones aun" -#: templates/problem/submit.html:258 +#: templates/problem/submit.html:250 msgid "No judge is available for this problem." msgstr "Ningún Juez esta disponible para este problema." -#: templates/problem/submit.html:262 +#: templates/problem/submit.html:252 msgid "Submit!" msgstr "¡Enviar!" -#: templates/registration/activate.html:3 -#, python-format -msgid "%(key)s is an invalid activation key." -msgstr "%(key)s es una llave no válida." - #: templates/registration/activation_complete.html:3 msgid "Your account has been successfully activated." msgstr "Su cuenta ha sido activada con éxito." @@ -4465,15 +3914,6 @@ msgstr "" "Si usted no recibe un correo electrónico, asegúrese de haber ingresado la " "dirección con la que se registró y revise su carpeta de correo no deseado." -#: templates/registration/password_reset_email.txt:1 -#, python-format -msgid "" -"You're receiving this email because you requested a password reset for your " -"user account at %(site_name)s." -msgstr "" -"Usted está recibiendo este correo electrónico porque solicitó restablecer la " -"contraseña de su cuenta de usuario en%(site_name)s." - #: templates/registration/password_reset_email.txt:3 msgid "Please go to the following page and choose a new password:" msgstr "Por favor ve a la siguiente página y elige una nueva contraseña:" @@ -4486,16 +3926,6 @@ msgstr "Nombre de usuario, en caso de que lo hayas olvidado:" msgid "Thanks for using our site!" msgstr "¡Gracias por usar nuestro sitio!" -#: templates/registration/password_reset_email.txt:11 -#, python-format -msgid "The %(site_name)s team" -msgstr "El equipo de %(site_name)s" - -#: templates/registration/password_reset_subject.txt:1 -#, python-format -msgid "Password reset on %(site_name)s" -msgstr "Contraseña se reinicia en %(site_name)s" - #: templates/registration/profile_creation.html:36 #: templates/registration/username_select.html:7 msgid "Continue >" @@ -4534,20 +3964,19 @@ msgstr "Idioma predeterminado" msgid "Affiliated organizations" msgstr "Organizaciones afiliadas" -#: templates/registration/registration_form.html:195 -#: templates/user/edit-profile.html:128 +#: templates/registration/registration_form.html:192 msgid "Notify me about upcoming contests" msgstr "Notificarme sobre próximas competencias" -#: templates/registration/registration_form.html:209 +#: templates/registration/registration_form.html:206 msgid "By registering, you agree to our" msgstr "Al registrarte, estás aceptando nuestras" -#: templates/registration/registration_form.html:210 +#: templates/registration/registration_form.html:207 msgid "Terms & Conditions" msgstr "Términos y condiciones" -#: templates/registration/registration_form.html:213 +#: templates/registration/registration_form.html:210 msgid "Register!" msgstr "¡Registrarse!" @@ -4557,11 +3986,6 @@ msgstr "¡Registrarse!" msgid "Enter the 6-digit code generated by your app:" msgstr "" -#: templates/registration/totp_auth.html:41 -#, python-format -msgid "If you lost your authentication device, please contact us at %(email)s." -msgstr "" - #: templates/registration/totp_disable.html:38 msgid "" "To protect your account, you must first authenticate before you can disable " @@ -4580,6 +4004,10 @@ msgstr "" msgid "Or enter this code manually:" msgstr "" +#: templates/stats/base.html:9 templates/submission/list.html:339 +msgid "Statistics" +msgstr "Estadística" + #: templates/stats/language.html:11 msgid "Submission Statistics" msgstr "Estadísticas de envíos" @@ -4605,7 +4033,6 @@ msgid "Ping" msgstr "" #: templates/status/judge-status-table.html:8 -#: templates/user/import/index.html:104 msgid "Load" msgstr "Cargar" @@ -4621,7 +4048,6 @@ msgid "There are no judges available at this time." msgstr "No hay jueces disponibles en este momento." #: templates/status/language-list.html:33 templates/ticket/list.html:261 -#: templates/user/import/table_csv.html:3 msgid "ID" msgstr "Identificación" @@ -4629,22 +4055,6 @@ msgstr "Identificación" msgid "Runtime Info" msgstr "Información del tiempo transcurrido" -#: templates/status/status-tabs.html:4 -msgid "Judges" -msgstr "Jueces" - -#: templates/status/status-tabs.html:6 -msgid "Version Matrix" -msgstr "Versión matriz" - -#: templates/submission/internal-error-message.html:3 -#, python-format -msgid "" -"An internal error occurred while grading, and the %(SITE_NAME)s " -"administrators have been notified.
In the meantime, try resubmitting in " -"a few seconds." -msgstr "" - #: templates/submission/internal-error-message.html:8 msgid "An internal error occurred while grading." msgstr "A ocurrido un error interno durante la clasificación." @@ -4661,6 +4071,10 @@ msgstr "Filtrar por estatus..." msgid "Filter by language..." msgstr "Filtrar por idioma..." +#: templates/submission/list.html:309 +msgid "Filter submissions" +msgstr "Filtrar envíos" + #: templates/submission/list.html:345 msgid "Total:" msgstr "" @@ -4718,82 +4132,81 @@ msgstr "Resultados de la ejecución de prueba previa" msgid "Execution Results" msgstr "Resultados de la ejecución" -#: templates/submission/status-testcases.html:34 +#: templates/submission/status-testcases.html:31 +msgid "Batch " +msgstr "Grupo " + +#: templates/submission/status-testcases.html:43 msgid "Overall: " msgstr "" -#: templates/submission/status-testcases.html:48 +#: templates/submission/status-testcases.html:57 #, fuzzy #| msgid "Points:" msgid "Point: " msgstr "Puntos:" -#: templates/submission/status-testcases.html:53 +#: templates/submission/status-testcases.html:62 #, fuzzy #| msgid "Time:" msgid "Time: " msgstr "Tiempo:" -#: templates/submission/status-testcases.html:62 +#: templates/submission/status-testcases.html:71 #, fuzzy #| msgid "Memory" msgid "Memory: " msgstr "Memoria" -#: templates/submission/status-testcases.html:73 -msgid "Batch " -msgstr "Grupo " - #: templates/submission/status-testcases.html:84 -#: templates/submission/status-testcases.html:113 +msgid "Case" +msgstr "Caso" + +#: templates/submission/status-testcases.html:86 +msgid "Pretest" +msgstr "Antes de la prueba" + +#: templates/submission/status-testcases.html:88 +msgid "Test case" +msgstr "Caso de prueba" + +#: templates/submission/status-testcases.html:99 #, fuzzy #| msgid "Points" msgid "Point" msgstr "Puntos" -#: templates/submission/status-testcases.html:99 -msgid "Case" -msgstr "Caso" - -#: templates/submission/status-testcases.html:101 -msgid "Pretest" -msgstr "Antes de la prueba" - -#: templates/submission/status-testcases.html:103 -msgid "Test case" -msgstr "Caso de prueba" - -#: templates/submission/status-testcases.html:141 +#: templates/submission/status-testcases.html:121 #, fuzzy #| msgid "Input file" msgid "Input:" msgstr "Archivo de entrada" -#: templates/submission/status-testcases.html:145 +#: templates/submission/status-testcases.html:125 #, fuzzy #| msgid "Output file" msgid "Output:" msgstr "Archivo de salida" -#: templates/submission/status-testcases.html:149 +#: templates/submission/status-testcases.html:129 #, fuzzy #| msgid "Wrong Answer" msgid "Answer:" msgstr "Respuesta incorrecta" -#: templates/submission/status-testcases.html:154 +#: templates/submission/status-testcases.html:134 #, fuzzy #| msgid "judging feedback" msgid "Judge feedback:" msgstr "respuesta del juzgado" -#: templates/submission/status-testcases.html:175 +#: templates/submission/status-testcases.html:157 msgid "Passing pretests does not guarantee a full score on system tests." msgstr "" "Pasar pruebas previas no garantiza una puntuación completa en pruebas del " "sistema." -#: templates/submission/status-testcases.html:178 +#: templates/submission/status-testcases.html:160 msgid "Submission aborted!" msgstr "¡Presentación abortada!" @@ -4805,24 +4218,11 @@ msgstr "Ver fuente" msgid "Abort" msgstr "Anular" -#: templates/submission/submission-list-tabs.html:6 -msgid "Mine" -msgstr "Mío" - -#: templates/submission/submission-list-tabs.html:9 -msgid "Best" -msgstr "El Mejor" - -#: templates/submission/submission-list-tabs.html:12 -#, python-format -msgid "%(user)s's" -msgstr "De %(user)s" - -#: templates/ticket/list.html:135 templates/ticket/ticket.html:273 +#: templates/ticket/list.html:135 templates/ticket/ticket.html:257 msgid "Reopened: " msgstr "Reabierto: " -#: templates/ticket/list.html:138 templates/ticket/ticket.html:274 +#: templates/ticket/list.html:138 templates/ticket/ticket.html:258 msgid "Closed: " msgstr "Cerrado: " @@ -4846,7 +4246,7 @@ msgstr "Asignado" msgid "Title" msgstr "Título" -#: templates/ticket/list.html:264 templates/ticket/ticket.html:369 +#: templates/ticket/list.html:264 templates/ticket/ticket.html:328 msgid "Assignees" msgstr "Asignados" @@ -4864,37 +4264,33 @@ msgstr "" "una declaración del mismo y no para pedir ayuda. Si necesita ayuda para " "resolver un problema, pregunte en los comentarios." -#: templates/ticket/ticket.html:355 -msgid "Post" -msgstr "Publicar" - -#: templates/ticket/ticket.html:363 +#: templates/ticket/ticket.html:322 msgid "Associated object" msgstr "Objeto asociado" -#: templates/ticket/ticket.html:374 +#: templates/ticket/ticket.html:333 msgid "No one is assigned." msgstr "Ninguno asignado." -#: templates/ticket/ticket.html:380 +#: templates/ticket/ticket.html:339 msgid "Close ticket" msgstr "Ticket de cierre" -#: templates/ticket/ticket.html:382 +#: templates/ticket/ticket.html:341 msgid "Reopen ticket" msgstr "Reabrir ticket" -#: templates/ticket/ticket.html:386 +#: templates/ticket/ticket.html:345 msgid "Assignee notes" msgstr "Notas de asignado" -#: templates/ticket/ticket.html:393 templates/widgets/select_all.html:4 +#: templates/ticket/ticket.html:352 templates/widgets/select_all.html:4 msgid "Nothing here." msgstr "Nada aquí." -#: templates/user/base-users-table.html:3 -msgid "Rank" -msgstr "Puesto" +#: templates/ticket/ticket.html:385 +msgid "Post" +msgstr "Publicar" #: templates/user/base-users.html:14 templates/user/base-users.html:69 msgid "Search by handle..." @@ -4940,212 +4336,50 @@ msgstr "Script de usuario" msgid "Update profile" msgstr "Actualizar perfil" -#: templates/user/import/index.html:31 -msgid "Upload CSV only" -msgstr "" - -#: templates/user/import/index.html:100 -#, fuzzy -#| msgid "user profile" -msgid "User File" -msgstr "perfil del usuario" - -#: templates/user/import/index.html:102 -msgid "Sample" -msgstr "" - -#: templates/user/import/index.html:105 templates/user/user-list-tabs.html:8 -msgid "Import" -msgstr "" - -#: templates/user/import/table_csv.html:7 -msgid "School" -msgstr "" - -#: templates/user/pp-row.html:22 -#, python-format -msgid "" -"\n" -" weighted %(weight)s%%\n" -" " -msgstr "" -"\n" -" ponderado %(weight)s\n" -" " - -#: templates/user/pp-row.html:27 -#, python-format -msgid "%(pp).1fpp" -msgstr "%(pp).1fpp" - -#: templates/user/pp-row.html:29 -#, python-format -msgid "%(pp).0fpp" -msgstr "%(pp).0fpp" - -#: templates/user/user-about.html:23 -#, fuzzy, python-format -#| msgid "contest problems" -msgid "%(counter)s problem solved" -msgid_plural "%(counter)s problems solved" -msgstr[0] "problemas del concurso" -msgstr[1] "problemas del concurso" - -#: templates/user/user-about.html:35 -#, fuzzy -#| msgid "Total points:" -msgid "Total points" -msgstr "Puntos totales:" - -#: templates/user/user-about.html:45 -#, fuzzy -#| msgid "Rank by rating:" -msgid "Rank by rating" -msgstr "Rango de la clasificación:" - -#: templates/user/user-about.html:52 -#, fuzzy -#| msgid "Rank by points:" -msgid "Rank by points" -msgstr "Calificar por puntos:" - -#: templates/user/user-about.html:64 +#: templates/user/user-about.html:14 msgid "From" msgstr "De" -#: templates/user/user-about.html:75 +#: templates/user/user-about.html:25 msgid "Admin Notes" msgstr "" -#: templates/user/user-about.html:90 +#: templates/user/user-about.html:40 msgid "You have not shared any information." msgstr "No has compartido ninguna información." -#: templates/user/user-about.html:92 +#: templates/user/user-about.html:42 msgid "This user has not shared any information." msgstr "Este usuario no ha compartido ninguna información." -#: templates/user/user-about.html:101 -msgid "Awards" -msgstr "" +#: templates/user/user-base.html:50 +msgid "Rank by points:" +msgstr "Calificar por puntos:" -#: templates/user/user-about.html:112 -#, fuzzy, python-format -#| msgctxt "contest problem" -#| msgid "%(problem)s in %(contest)s" -msgid "%(label)s (%(date)s)" -msgstr "%(problem)s en %(contest)s" +#: templates/user/user-base.html:53 +msgid "Total points:" +msgstr "Puntos totales:" -#: templates/user/user-about.html:130 -#, fuzzy -#| msgid "Monday" -msgid "Mon" -msgstr "Lunes" +#: templates/user/user-base.html:68 +msgid "Rank by rating:" +msgstr "Rango de la clasificación:" -#: templates/user/user-about.html:135 -#, fuzzy -#| msgid "Tuesday" -msgid "Tues" -msgstr "Martes" +#: templates/user/user-base.html:70 +msgid "Rating:" +msgstr "Puntuación:" -#: templates/user/user-about.html:140 -msgid "Wed" -msgstr "" - -#: templates/user/user-about.html:145 -#, fuzzy -#| msgid "Thursday" -msgid "Thurs" -msgstr "Jueves" - -#: templates/user/user-about.html:150 -#, fuzzy -#| msgid "Friday" -msgid "Fri" -msgstr "Viernes" - -#: templates/user/user-about.html:155 -#, fuzzy -#| msgid "State" -msgid "Sat" -msgstr "Estado" - -#: templates/user/user-about.html:160 -#, fuzzy -#| msgid "Sunday" -msgid "Sun" -msgstr "Domingo" - -#: templates/user/user-about.html:169 -msgid "Less" -msgstr "" - -#: templates/user/user-about.html:175 -msgid "More" -msgstr "" - -#: templates/user/user-about.html:184 -#, fuzzy -#| msgid "History" -msgid "Rating History" -msgstr "Historia" - -#: templates/user/user-about.html:255 -msgid "past year" -msgstr "" - -#: templates/user/user-about.html:272 -#, fuzzy -#| msgid "All submissions" -msgid "total submission(s)" -msgstr "Todos los envíos" - -#: templates/user/user-about.html:276 -#, fuzzy -#| msgid "submission test case" -msgid "submissions in the last year" -msgstr "prueba de presentación" - -#: templates/user/user-base.html:101 -msgid "Unfollow" -msgstr "" - -#: templates/user/user-base.html:104 -msgid "Follow" -msgstr "" - -#: templates/user/user-base.html:120 -#, fuzzy -#| msgid "" -#| "\n" -#| " You have %(left)s submission left\n" -#| " " -#| msgid_plural "" -#| "\n" -#| " You have %(left)s submissions left\n" -#| " " -msgid "Contests written" -msgstr "" -"\n" -" Aún tienes %(left)s envío restante\n" -" " - -#: templates/user/user-base.html:124 +#: templates/user/user-base.html:71 msgid "Volatility:" msgstr "Valatilidad:" -#: templates/user/user-base.html:128 +#: templates/user/user-base.html:72 msgid "Min. rating:" msgstr "Calificación mínima:" -#: templates/user/user-base.html:132 +#: templates/user/user-base.html:73 msgid "Max rating:" msgstr "Calificación máxima:" -#: templates/user/user-list-tabs.html:5 -msgid "Friends" -msgstr "" - #: templates/user/user-problems.html:35 msgid "Points Breakdown" msgstr "Puntos de ruptura" @@ -5166,65 +4400,81 @@ msgstr "Problemas de autores" msgid "Hide problems I've solved" msgstr "Ocultar problemas que ya he solucionado" -#: templates/user/user-problems.html:93 -#, python-format -msgid "%(points).1f points" -msgstr "puntos %(points).1f" - #: templates/user/user-problems.html:99 msgid "Score" msgstr "Puntuación" -#: templates/user/user-problems.html:110 -#, python-format -msgid "%(points)s / %(total)s" -msgstr "%(points)s / %(total)s" - -#: templates/user/user-tabs.html:7 -msgid "Impersonate" -msgstr "Impersonal" - -#: templates/user/user-tabs.html:13 -msgid "Admin User" -msgstr "Administrador" - -#: templates/user/user-tabs.html:16 -msgid "Admin Profile" -msgstr "Perfil del administrador" - #: templates/widgets/select_all.html:8 msgid "Check all" msgstr "Seleccionar todo" -#, fuzzy -#~| msgid "%(counter)s submission left" -#~| msgid_plural "%(counter)s submissions left" -#~ msgid "%(cnt)d submission on %(date)s" -#~ msgid_plural "%(cnt)d submissions on %(date)s" -#~ msgstr[0] "%(counter)s envío restante" -#~ msgstr[1] "%(counter)s envíos restantes" - -#~ msgid "Rating:" -#~ msgstr "Puntuación:" - -#, fuzzy -#~| msgid "Admin" -#~ msgid "Admins" -#~ msgstr "Administrador" - -#, fuzzy -#~| msgid "Rescore the selected submissions" -#~ msgid "This will rescore %(count)d submissions." -#~ msgstr "Repuntear las presentaciones seleccionadas" - -#, fuzzy -#~| msgid "%(points)s / %(total)s" -#~ msgid "Point %(point)s / Case #%(case)s" -#~ msgstr "%(points)s / %(total)s" - #~ msgid "output prefix length override" #~ msgstr "anular la longitud del prefijo de salida" +#~ msgid "Hello, %(username)s." +#~ msgstr "Hola, %(username)s." + +#~ msgid "" +#~ "\n" +#~ " posted on %(time)s\n" +#~ " " +#~ msgstr "" +#~ "\n" +#~ " publicada en %(time)s\n" +#~ " " + +#~ msgid "" +#~ "\n" +#~ " on %(time)s\n" +#~ " " +#~ msgstr "" +#~ "\n" +#~ " en %(time)s\n" +#~ " " + +#~ msgid "posted on {time}" +#~ msgstr "publicado en {time}" + +#~ msgid "commented on {time}" +#~ msgstr "comentado en {time}" + +#~ msgid "edit %(edits)s" +#~ msgstr "editar %(edits)s" + +#~ msgid "List" +#~ msgstr "Lista" + +#~ msgid "Calendar" +#~ msgstr "Calendario" + +#~ msgid "Info" +#~ msgstr "Información" + +#~ msgid "Rankings" +#~ msgstr "Valoraciones" + +#~ msgid "Hidden Rankings" +#~ msgstr "Rankings ocultos" + +#~ msgid "Stop spectating" +#~ msgstr "Parar de ver" + +#~ msgid "Participating virtually." +#~ msgstr "Participación virtual." + +#~ msgid "Contest is over." +#~ msgstr "El concurso ha terminado." + +#~ msgid "" +#~ "%(time_limit)s window between %(start_time)s and " +#~ "%(end_time)s" +#~ msgstr "" +#~ "%(time_limit)s ventana entre %(start_time)s y " +#~ "%(end_time)s" + +#~ msgid "%(length)s long starting on %(start_time)s" +#~ msgstr "%(length)s larga a partir de %(start_time)s" + #~ msgid "Started on {time}" #~ msgstr "Comenzó en {time}" @@ -5246,6 +4496,70 @@ msgstr "Seleccionar todo" #~ msgid "Generator args" #~ msgstr "Generador de argumentos" +#~ msgid "%(counter)s submission left" +#~ msgid_plural "%(counter)s submissions left" +#~ msgstr[0] "%(counter)s envío restante" +#~ msgstr[1] "%(counter)s envíos restantes" + +#~ msgid "Author:" +#~ msgid_plural "Authors:" +#~ msgstr[0] "Autor:" +#~ msgstr[1] "Autores:" + +#~ msgid "Problem type" +#~ msgid_plural "Problem types" +#~ msgstr[0] "Tipo de problema" +#~ msgstr[1] "Tipos de problema" + +#~ msgid "No %(lang)s judge online" +#~ msgstr "No hay jueces online para %(lang)s" + +#~ msgid "" +#~ "Warning! Your default language, %(default_language)s, is " +#~ "unavailable for this problem and has been deselected." +#~ msgstr "" +#~ "¡Advertencia! Su idioma predeterminado, %(default_language)s, no está disponible para este problema y no se seleccionó." + +#~ msgid "" +#~ "\n" +#~ " You have %(left)s submission left\n" +#~ " " +#~ msgid_plural "" +#~ "\n" +#~ " You have %(left)s submissions left\n" +#~ " " +#~ msgstr[0] "" +#~ "\n" +#~ " Aún tienes %(left)s envío restante\n" +#~ " " +#~ msgstr[1] "" +#~ "\n" +#~ " Aún tienes %(left)s envíos restantes\n" +#~ " " + +#~ msgid "%(key)s is an invalid activation key." +#~ msgstr "%(key)s es una llave no válida." + +#~ msgid "" +#~ "You're receiving this email because you requested a password reset for " +#~ "your user account at %(site_name)s." +#~ msgstr "" +#~ "Usted está recibiendo este correo electrónico porque solicitó restablecer " +#~ "la contraseña de su cuenta de usuario en%(site_name)s." + +#~ msgid "The %(site_name)s team" +#~ msgstr "El equipo de %(site_name)s" + +#~ msgid "Password reset on %(site_name)s" +#~ msgstr "Contraseña se reinicia en %(site_name)s" + +#~ msgid "Judges" +#~ msgstr "Jueces" + +#~ msgid "Version Matrix" +#~ msgstr "Versión matriz" + #~ msgid "Case #%(case)s" #~ msgstr "Caso #%(case)s" @@ -5257,3 +4571,45 @@ msgstr "Seleccionar todo" #~ msgid "Final score:" #~ msgstr "Puntuación total:" + +#~ msgid "Mine" +#~ msgstr "Mío" + +#~ msgid "Best" +#~ msgstr "El Mejor" + +#~ msgid "%(user)s's" +#~ msgstr "De %(user)s" + +#~ msgid "Rank" +#~ msgstr "Puesto" + +#~ msgid "" +#~ "\n" +#~ " weighted %(weight)s%%\n" +#~ " " +#~ msgstr "" +#~ "\n" +#~ " ponderado %(weight)s\n" +#~ " " + +#~ msgid "%(pp).1fpp" +#~ msgstr "%(pp).1fpp" + +#~ msgid "%(pp).0fpp" +#~ msgstr "%(pp).0fpp" + +#~ msgid "%(points).1f points" +#~ msgstr "puntos %(points).1f" + +#~ msgid "%(points)s / %(total)s" +#~ msgstr "%(points)s / %(total)s" + +#~ msgid "Impersonate" +#~ msgstr "Impersonal" + +#~ msgid "Admin User" +#~ msgstr "Administrador" + +#~ msgid "Admin Profile" +#~ msgstr "Perfil del administrador" diff --git a/locale/es/LC_MESSAGES/djangojs.po b/locale/es/LC_MESSAGES/djangojs.po index 57005ea..1dd72ac 100644 --- a/locale/es/LC_MESSAGES/djangojs.po +++ b/locale/es/LC_MESSAGES/djangojs.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: dmoj\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-07-20 23:30+0700\n" +"POT-Creation-Date: 2019-10-01 23:12+0000\n" "PO-Revision-Date: 2019-11-11 22:06\n" "Last-Translator: Icyene\n" "Language-Team: Spanish\n" @@ -27,3 +27,4 @@ msgstr[1] "%d días %h:%m:%s" msgctxt "time format without day" msgid "%h:%m:%s" msgstr "%h:%m:%s" + diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po index a1dd7f8..18694ec 100644 --- a/locale/fr/LC_MESSAGES/django.po +++ b/locale/fr/LC_MESSAGES/django.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: dmoj\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-10-25 05:59+0700\n" +"POT-Creation-Date: 2020-04-10 01:26-0500\n" "PO-Revision-Date: 2019-11-11 22:05\n" "Last-Translator: Icyene\n" "Language-Team: French\n" @@ -16,93 +16,93 @@ msgstr "" "X-Crowdin-Language: fr\n" "X-Crowdin-File: django.po\n" -#: chat_box/models.py:16 judge/admin/interface.py:110 -#: judge/models/contest.py:403 judge/models/contest.py:528 -#: judge/models/profile.py:211 +#: chat_box/models.py:15 judge/admin/interface.py:107 +#: judge/models/contest.py:257 judge/models/contest.py:381 +#: judge/models/profile.py:191 msgid "user" msgstr "utilisateur" -#: chat_box/models.py:17 judge/models/comment.py:43 judge/models/comment.py:191 +#: chat_box/models.py:16 judge/models/comment.py:42 msgid "posted time" msgstr "" -#: chat_box/models.py:18 judge/models/comment.py:47 +#: chat_box/models.py:17 judge/models/comment.py:46 msgid "body of comment" msgstr "" -#: chat_box/views.py:29 templates/chat/chat.html:4 +#: chat_box/views.py:29 msgid "Chat Box" msgstr "" -#: dmoj/settings.py:355 +#: dmoj/settings.py:349 msgid "German" msgstr "Allemand" -#: dmoj/settings.py:356 +#: dmoj/settings.py:350 msgid "English" msgstr "Anglais" -#: dmoj/settings.py:357 +#: dmoj/settings.py:351 msgid "Spanish" msgstr "Espagnol" -#: dmoj/settings.py:358 +#: dmoj/settings.py:352 msgid "French" msgstr "Français" -#: dmoj/settings.py:359 +#: dmoj/settings.py:353 msgid "Croatian" msgstr "Croate" -#: dmoj/settings.py:360 +#: dmoj/settings.py:354 msgid "Hungarian" msgstr "Hongrois" -#: dmoj/settings.py:361 +#: dmoj/settings.py:355 msgid "Japanese" msgstr "" -#: dmoj/settings.py:362 +#: dmoj/settings.py:356 msgid "Korean" msgstr "Coréen" -#: dmoj/settings.py:363 +#: dmoj/settings.py:357 msgid "Brazilian Portuguese" msgstr "" -#: dmoj/settings.py:364 +#: dmoj/settings.py:358 msgid "Romanian" msgstr "Roumain" -#: dmoj/settings.py:365 +#: dmoj/settings.py:359 msgid "Russian" msgstr "Russe" -#: dmoj/settings.py:366 +#: dmoj/settings.py:360 msgid "Serbian (Latin)" msgstr "Serbe (Latin)" -#: dmoj/settings.py:367 +#: dmoj/settings.py:361 msgid "Turkish" msgstr "Turque" -#: dmoj/settings.py:368 +#: dmoj/settings.py:362 msgid "Vietnamese" msgstr "Vietnamien" -#: dmoj/settings.py:369 +#: dmoj/settings.py:363 msgid "Simplified Chinese" msgstr "Chinois simplifié" -#: dmoj/settings.py:370 +#: dmoj/settings.py:364 msgid "Traditional Chinese" msgstr "" -#: dmoj/urls.py:58 +#: dmoj/urls.py:57 msgid "Login" msgstr "Se connecter" -#: dmoj/urls.py:106 templates/base.html:193 +#: dmoj/urls.py:105 templates/base.html:190 msgid "Home" msgstr "Accueil" @@ -132,92 +132,90 @@ msgstr "Montrer les commentaires" msgid "Associated page" msgstr "Page associée" -#: judge/admin/contest.py:30 +#: judge/admin/contest.py:28 msgid "Included contests" msgstr "Concours inclus" -#: judge/admin/contest.py:66 templates/contest/clarification.html:42 -#: templates/contest/contest.html:83 templates/contest/moss.html:43 -#: templates/problem/list.html:214 templates/problem/list.html:232 -#: templates/problem/list.html:350 templates/user/user-problems.html:56 +#: judge/admin/contest.py:64 templates/contest/contest.html:83 +#: templates/contest/moss.html:43 templates/problem/list.html:206 +#: templates/problem/list.html:221 templates/user/user-problems.html:56 #: templates/user/user-problems.html:98 msgid "Problem" msgstr "Problème" -#: judge/admin/contest.py:119 +#: judge/admin/contest.py:112 msgid "Settings" msgstr "" -#: judge/admin/contest.py:121 +#: judge/admin/contest.py:114 msgid "Scheduling" msgstr "Planification" -#: judge/admin/contest.py:122 templates/organization/home.html:107 +#: judge/admin/contest.py:115 msgid "Details" msgstr "Détails" -#: judge/admin/contest.py:123 +#: judge/admin/contest.py:116 msgid "Format" msgstr "" -#: judge/admin/contest.py:124 templates/contest/ranking-table.html:7 -#: templates/user/user-about.html:15 templates/user/user-about.html:45 +#: judge/admin/contest.py:117 templates/contest/ranking-table.html:5 msgid "Rating" msgstr "Valeur" -#: judge/admin/contest.py:125 +#: judge/admin/contest.py:118 msgid "Access" msgstr "" -#: judge/admin/contest.py:127 judge/admin/problem.py:131 +#: judge/admin/contest.py:120 judge/admin/problem.py:131 msgid "Justice" msgstr "Justice" -#: judge/admin/contest.py:207 +#: judge/admin/contest.py:158 #, python-format msgid "%d contest successfully marked as visible." msgid_plural "%d contests successfully marked as visible." msgstr[0] "" msgstr[1] "" -#: judge/admin/contest.py:210 +#: judge/admin/contest.py:161 msgid "Mark contests as visible" msgstr "" -#: judge/admin/contest.py:216 +#: judge/admin/contest.py:165 #, python-format msgid "%d contest successfully marked as hidden." msgid_plural "%d contests successfully marked as hidden." msgstr[0] "" msgstr[1] "" -#: judge/admin/contest.py:219 +#: judge/admin/contest.py:168 msgid "Mark contests as hidden" msgstr "" -#: judge/admin/contest.py:233 judge/admin/submission.py:164 +#: judge/admin/contest.py:182 judge/admin/submission.py:164 #, python-format msgid "%d submission was successfully scheduled for rejudging." msgid_plural "%d submissions were successfully scheduled for rejudging." msgstr[0] "" msgstr[1] "" -#: judge/admin/contest.py:308 +#: judge/admin/contest.py:256 #, python-format msgid "%d participation recalculated." msgid_plural "%d participations recalculated." msgstr[0] "" msgstr[1] "" -#: judge/admin/contest.py:311 +#: judge/admin/contest.py:259 msgid "Recalculate results" msgstr "" -#: judge/admin/contest.py:315 judge/admin/organization.py:65 +#: judge/admin/contest.py:263 judge/admin/organization.py:65 msgid "username" msgstr "nom d'utilisateur" -#: judge/admin/contest.py:320 templates/base.html:277 +#: judge/admin/contest.py:268 templates/base.html:260 msgid "virtual" msgstr "virtuel" @@ -225,15 +223,15 @@ msgstr "virtuel" msgid "link path" msgstr "chemin du lien" -#: judge/admin/interface.py:65 +#: judge/admin/interface.py:62 msgid "Content" msgstr "Contenu" -#: judge/admin/interface.py:66 +#: judge/admin/interface.py:63 msgid "Summary" msgstr "Résumé" -#: judge/admin/interface.py:151 +#: judge/admin/interface.py:148 msgid "object" msgstr "" @@ -255,9 +253,8 @@ msgid "Taxonomy" msgstr "Taxonomie" #: judge/admin/problem.py:128 templates/contest/contest.html:84 -#: templates/problem/data.html:429 templates/problem/list.html:222 -#: templates/problem/list.html:248 templates/user/base-users-table.html:10 -#: templates/user/user-about.html:36 templates/user/user-about.html:52 +#: templates/problem/data.html:449 templates/problem/list.html:211 +#: templates/problem/list.html:232 templates/user/base-users-table.html:10 #: templates/user/user-problems.html:58 msgid "Points" msgstr "Points " @@ -306,7 +303,6 @@ msgid "timezone" msgstr "" #: judge/admin/profile.py:86 judge/admin/submission.py:211 -#: templates/notification/list.html:12 #: templates/organization/requests/log.html:9 #: templates/organization/requests/pending.html:12 #: templates/ticket/list.html:263 @@ -314,7 +310,6 @@ msgid "User" msgstr "Utilisateur" #: judge/admin/profile.py:91 templates/registration/registration_form.html:145 -#: templates/user/import/table_csv.html:8 msgid "Email" msgstr "Courriel" @@ -347,7 +342,7 @@ msgstr "Problèmes non autorisés" msgid "These problems are NOT allowed to be submitted in this language" msgstr "Ces problèmes ne peuvent êtres soumis dans ce language" -#: judge/admin/runtime.py:83 templates/problem/list.html:352 +#: judge/admin/runtime.py:83 msgid "Description" msgstr "Description" @@ -394,7 +389,7 @@ msgstr "Vous n'avez pas le droit de resoumettre AUTANT de soumissions." msgid "Rejudge the selected submissions" msgstr "Resoumettre les soumissions sélectionnées" -#: judge/admin/submission.py:193 judge/views/problem_manage.py:159 +#: judge/admin/submission.py:193 judge/views/problem_manage.py:128 #, python-format msgid "%d submission were successfully rescored." msgid_plural "%d submissions were successfully rescored." @@ -405,8 +400,7 @@ msgstr[1] "" msgid "Rescore the selected submissions" msgstr "" -#: judge/admin/submission.py:200 templates/problem/list.html:216 -#: templates/problem/list.html:236 +#: judge/admin/submission.py:200 msgid "Problem code" msgstr "Code de la problème" @@ -414,12 +408,10 @@ msgstr "Code de la problème" msgid "Problem name" msgstr "Nom de la problème" -#: judge/admin/submission.py:215 templates/notification/list.html:15 -#: templates/organization/requests/log.html:10 +#: judge/admin/submission.py:215 templates/organization/requests/log.html:10 #: templates/organization/requests/pending.html:13 -#: templates/problem/list.html:351 -#: templates/submission/status-testcases.html:125 -#: templates/submission/status-testcases.html:127 +#: templates/submission/status-testcases.html:105 +#: templates/submission/status-testcases.html:107 msgid "Time" msgstr "Temps" @@ -433,7 +425,7 @@ msgstr "%d Ko" msgid "%.2f MB" msgstr "%.2f Mo" -#: judge/admin/submission.py:227 templates/submission/status-testcases.html:132 +#: judge/admin/submission.py:227 templates/submission/status-testcases.html:112 msgid "Memory" msgstr "RAM" @@ -453,20 +445,20 @@ msgstr "" msgid "Online Judge" msgstr "Juge en ligne" -#: judge/comments.py:60 +#: judge/comments.py:41 msgid "Comment body" msgstr "Corps du commentaire" -#: judge/comments.py:66 judge/views/ticket.py:63 +#: judge/comments.py:47 judge/views/ticket.py:46 msgid "Your part is silent, little toad." msgstr "Votre partie est silencieux, petit crapaud." -#: judge/comments.py:69 templates/comments/list.html:132 +#: judge/comments.py:50 templates/comments/list.html:131 msgid "" "You need to have solved at least one problem before your voice can be heard." msgstr "Il faut résoudre un problème avant que tu ne puisse être entendu." -#: judge/comments.py:113 +#: judge/comments.py:92 msgid "Posted comment" msgstr "Commentaire posté" @@ -482,10 +474,6 @@ msgstr "" msgid "ECOO" msgstr "" -#: judge/contest_format/icpc.py:19 -msgid "ICPC" -msgstr "" - #: judge/contest_format/ioi.py:19 msgid "IOI" msgstr "" @@ -498,58 +486,52 @@ msgstr "" msgid "Enable experimental features" msgstr "" -#: judge/forms.py:57 judge/views/organization.py:168 judge/views/register.py:49 +#: judge/forms.py:57 judge/views/organization.py:127 #, python-brace-format msgid "You may not be part of more than {count} public organizations." msgstr "" -#: judge/forms.py:82 -msgid "Any judge" -msgstr "" - -#: judge/forms.py:112 judge/views/register.py:26 +#: judge/forms.py:107 judge/views/register.py:26 #: templates/registration/registration_form.html:139 #: templates/user/base-users-table.html:5 -#: templates/user/import/table_csv.html:4 msgid "Username" msgstr "Nom d'utilisateur" -#: judge/forms.py:113 templates/registration/registration_form.html:151 +#: judge/forms.py:108 templates/registration/registration_form.html:151 #: templates/registration/registration_form.html:165 -#: templates/user/import/table_csv.html:5 msgid "Password" msgstr "Mot de passe " -#: judge/forms.py:135 +#: judge/forms.py:130 msgid "Two Factor Authentication tokens must be 6 decimal digits." msgstr "" -#: judge/forms.py:144 templates/registration/totp_auth.html:32 +#: judge/forms.py:139 templates/registration/totp_auth.html:32 msgid "Invalid Two Factor Authentication token." msgstr "" -#: judge/forms.py:148 judge/models/problem.py:97 +#: judge/forms.py:143 judge/models/problem.py:97 msgid "Problem code must be ^[a-z0-9]+$" msgstr "" -#: judge/forms.py:153 +#: judge/forms.py:148 msgid "Problem with code already exists." msgstr "" -#: judge/forms.py:158 judge/models/contest.py:61 +#: judge/forms.py:153 judge/models/contest.py:52 msgid "Contest id must be ^[a-z0-9]+$" msgstr "" -#: judge/forms.py:163 +#: judge/forms.py:158 msgid "Contest with key already exists." msgstr "" -#: judge/jinja2/datetime.py:26 templates/blog/blog.html:26 +#: judge/jinja2/datetime.py:26 templates/blog/content.html:27 #: templates/blog/dashboard.html:21 msgid "N j, Y, g:i a" msgstr "" -#: judge/jinja2/datetime.py:26 templates/chat/message.html:13 +#: judge/jinja2/datetime.py:26 #, python-brace-format msgid "{time}" msgstr "" @@ -579,542 +561,472 @@ msgstr "" msgid "Detect best quality" msgstr "" -#: judge/models/comment.py:26 +#: judge/models/comment.py:25 msgid "Page code must be ^[pcs]:[a-z0-9]+$|^b:\\d+$" msgstr "" -#: judge/models/comment.py:42 +#: judge/models/comment.py:41 msgid "commenter" msgstr "" -#: judge/models/comment.py:44 judge/models/comment.py:177 +#: judge/models/comment.py:43 judge/models/comment.py:176 msgid "associated page" msgstr "" -#: judge/models/comment.py:46 +#: judge/models/comment.py:45 msgid "votes" msgstr "votes" -#: judge/models/comment.py:48 +#: judge/models/comment.py:47 msgid "hide the comment" msgstr "" -#: judge/models/comment.py:49 +#: judge/models/comment.py:48 msgid "parent" msgstr "parent" -#: judge/models/comment.py:54 judge/models/comment.py:192 +#: judge/models/comment.py:53 msgid "comment" msgstr "commentaire" -#: judge/models/comment.py:55 +#: judge/models/comment.py:54 msgid "comments" msgstr "commentaires" -#: judge/models/comment.py:137 judge/models/problem.py:443 +#: judge/models/comment.py:136 judge/models/problem.py:406 #, python-format msgid "Editorial for %s" msgstr "" -#: judge/models/comment.py:172 +#: judge/models/comment.py:171 msgid "comment vote" msgstr "" -#: judge/models/comment.py:173 +#: judge/models/comment.py:172 msgid "comment votes" msgstr "" -#: judge/models/comment.py:182 +#: judge/models/comment.py:181 msgid "Override comment lock" msgstr "" -#: judge/models/comment.py:190 -msgid "owner" -msgstr "" - -#: judge/models/comment.py:193 judge/models/message.py:16 -msgid "read" -msgstr "" - -#: judge/models/comment.py:194 -msgid "category" -msgstr "" - -#: judge/models/comment.py:195 -msgid "html link to comments, used for non-comments" -msgstr "" - -#: judge/models/comment.py:196 -msgid "who trigger, used for non-comment" -msgstr "" - -#: judge/models/contest.py:23 +#: judge/models/contest.py:22 msgid "Invalid colour." msgstr "Couleur invalide." -#: judge/models/contest.py:25 +#: judge/models/contest.py:24 msgid "tag name" msgstr "" -#: judge/models/contest.py:26 +#: judge/models/contest.py:25 msgid "Lowercase letters and hyphens only." msgstr "Des lettres minuscules et des traits d’Union seulement." -#: judge/models/contest.py:27 +#: judge/models/contest.py:26 msgid "tag colour" msgstr "" -#: judge/models/contest.py:28 +#: judge/models/contest.py:27 msgid "tag description" msgstr "" -#: judge/models/contest.py:47 +#: judge/models/contest.py:46 msgid "contest tag" msgstr "" -#: judge/models/contest.py:48 judge/models/contest.py:118 +#: judge/models/contest.py:47 judge/models/contest.py:101 msgid "contest tags" msgstr "" -#: judge/models/contest.py:56 -msgid "Visible" -msgstr "" - -#: judge/models/contest.py:57 -msgid "Hidden for duration of contest" -msgstr "" - -#: judge/models/contest.py:58 -msgid "Hidden for duration of participation" -msgstr "" - -#: judge/models/contest.py:60 +#: judge/models/contest.py:51 msgid "contest id" msgstr "" -#: judge/models/contest.py:62 +#: judge/models/contest.py:53 msgid "contest name" msgstr "nom du concours" -#: judge/models/contest.py:63 -msgid "These users will be able to edit the contest." +#: judge/models/contest.py:54 +msgid "These people will be able to edit the contest." msgstr "" -#: judge/models/contest.py:65 -msgid "" -"These users will be able to edit the contest, but will not be listed as " -"authors." -msgstr "" - -#: judge/models/contest.py:68 -msgid "These users will be able to view the contest, but not edit it." -msgstr "" - -#: judge/models/contest.py:71 judge/models/runtime.py:136 +#: judge/models/contest.py:56 judge/models/runtime.py:133 msgid "description" msgstr "" -#: judge/models/contest.py:72 judge/models/problem.py:390 -#: judge/models/runtime.py:138 +#: judge/models/contest.py:57 judge/models/problem.py:353 +#: judge/models/runtime.py:135 msgid "problems" msgstr "problèmes" -#: judge/models/contest.py:73 judge/models/contest.py:404 +#: judge/models/contest.py:58 judge/models/contest.py:258 msgid "start time" msgstr "heure de début" -#: judge/models/contest.py:74 +#: judge/models/contest.py:59 msgid "end time" msgstr "heure de fin" -#: judge/models/contest.py:75 judge/models/problem.py:118 -#: judge/models/problem.py:414 +#: judge/models/contest.py:60 judge/models/problem.py:118 +#: judge/models/problem.py:377 msgid "time limit" msgstr "limite de Temps" -#: judge/models/contest.py:76 judge/models/problem.py:136 +#: judge/models/contest.py:61 judge/models/problem.py:136 msgid "publicly visible" msgstr "visible publiquement" -#: judge/models/contest.py:77 +#: judge/models/contest.py:62 msgid "" "Should be set even for organization-private contests, where it determines " "whether the contest is visible to members of the specified organizations." msgstr "" -#: judge/models/contest.py:80 +#: judge/models/contest.py:65 msgid "contest rated" msgstr "" -#: judge/models/contest.py:80 +#: judge/models/contest.py:65 msgid "Whether this contest can be rated." msgstr "" -#: judge/models/contest.py:82 -msgid "scoreboard visibility" +#: judge/models/contest.py:67 +msgid "hide scoreboard" msgstr "" -#: judge/models/contest.py:83 -msgid "Scoreboard visibility through the duration of the contest" +#: judge/models/contest.py:68 +msgid "" +"Whether the scoreboard should remain hidden for the duration of the contest." msgstr "" -#: judge/models/contest.py:85 -msgid "view contest scoreboard" -msgstr "" - -#: judge/models/contest.py:87 -msgid "These users will be able to view the scoreboard." -msgstr "" - -#: judge/models/contest.py:88 +#: judge/models/contest.py:71 msgid "no comments" msgstr "" -#: judge/models/contest.py:89 +#: judge/models/contest.py:72 msgid "Use clarification system instead of comments." msgstr "" -#: judge/models/contest.py:91 +#: judge/models/contest.py:74 msgid "Rating floor for contest" msgstr "" -#: judge/models/contest.py:93 +#: judge/models/contest.py:76 msgid "Rating ceiling for contest" msgstr "" -#: judge/models/contest.py:95 +#: judge/models/contest.py:78 msgid "rate all" msgstr "" -#: judge/models/contest.py:95 +#: judge/models/contest.py:78 msgid "Rate all users who joined." msgstr "" -#: judge/models/contest.py:96 +#: judge/models/contest.py:79 msgid "exclude from ratings" msgstr "" -#: judge/models/contest.py:98 +#: judge/models/contest.py:81 msgid "private to specific users" msgstr "" -#: judge/models/contest.py:99 +#: judge/models/contest.py:82 msgid "private contestants" msgstr "" -#: judge/models/contest.py:100 +#: judge/models/contest.py:83 msgid "If private, only these users may see the contest" msgstr "" -#: judge/models/contest.py:102 +#: judge/models/contest.py:85 msgid "hide problem tags" msgstr "" -#: judge/models/contest.py:103 +#: judge/models/contest.py:86 msgid "Whether problem tags should be hidden by default." msgstr "" -#: judge/models/contest.py:105 +#: judge/models/contest.py:88 msgid "run pretests only" msgstr "" -#: judge/models/contest.py:106 +#: judge/models/contest.py:89 msgid "" "Whether judges should grade pretests only, versus all testcases. Commonly " "set during a contest, then unset prior to rejudging user submissions when " "the contest ends." msgstr "" -#: judge/models/contest.py:110 judge/models/interface.py:77 -#: judge/models/problem.py:157 +#: judge/models/contest.py:93 judge/models/problem.py:157 msgid "private to organizations" msgstr "" -#: judge/models/contest.py:111 judge/models/interface.py:75 -#: judge/models/problem.py:155 judge/models/profile.py:77 +#: judge/models/contest.py:94 judge/models/problem.py:155 +#: judge/models/profile.py:77 msgid "organizations" msgstr "organisations" -#: judge/models/contest.py:112 +#: judge/models/contest.py:95 msgid "If private, only these organizations may see the contest" msgstr "" -#: judge/models/contest.py:113 judge/models/problem.py:145 +#: judge/models/contest.py:96 judge/models/problem.py:145 msgid "OpenGraph image" msgstr "" -#: judge/models/contest.py:114 judge/models/profile.py:48 +#: judge/models/contest.py:97 judge/models/profile.py:48 msgid "Logo override image" msgstr "" -#: judge/models/contest.py:116 +#: judge/models/contest.py:99 msgid "" "This image will replace the default site logo for users inside the contest." msgstr "" -#: judge/models/contest.py:119 +#: judge/models/contest.py:102 msgid "the amount of live participants" msgstr "" -#: judge/models/contest.py:120 +#: judge/models/contest.py:103 msgid "contest summary" msgstr "" -#: judge/models/contest.py:121 judge/models/problem.py:147 +#: judge/models/contest.py:104 judge/models/problem.py:147 msgid "Plain-text, shown in meta description tag, e.g. for social media." msgstr "" -#: judge/models/contest.py:122 judge/models/profile.py:47 +#: judge/models/contest.py:105 judge/models/profile.py:47 msgid "access code" msgstr "" -#: judge/models/contest.py:123 +#: judge/models/contest.py:106 msgid "" "An optional code to prompt contestants before they are allowed to join the " "contest. Leave it blank to disable." msgstr "" -#: judge/models/contest.py:125 judge/models/problem.py:141 +#: judge/models/contest.py:108 judge/models/problem.py:141 msgid "personae non gratae" msgstr "" -#: judge/models/contest.py:126 +#: judge/models/contest.py:109 msgid "Bans the selected users from joining this contest." msgstr "" -#: judge/models/contest.py:127 +#: judge/models/contest.py:110 msgid "contest format" msgstr "" -#: judge/models/contest.py:128 +#: judge/models/contest.py:111 msgid "The contest format module to use." msgstr "" -#: judge/models/contest.py:129 +#: judge/models/contest.py:112 msgid "contest format configuration" msgstr "" -#: judge/models/contest.py:130 +#: judge/models/contest.py:113 msgid "" "A JSON object to serve as the configuration for the chosen contest format " "module. Leave empty to use None. Exact format depends on the contest format " "selected." msgstr "" -#: judge/models/contest.py:137 -msgid "precision points" -msgstr "" - -#: judge/models/contest.py:139 -msgid "Number of digits to round points to." -msgstr "" - -#: judge/models/contest.py:383 +#: judge/models/contest.py:239 msgid "See private contests" msgstr "" -#: judge/models/contest.py:384 +#: judge/models/contest.py:240 msgid "Edit own contests" msgstr "" -#: judge/models/contest.py:385 +#: judge/models/contest.py:241 msgid "Edit all contests" msgstr "" -#: judge/models/contest.py:386 +#: judge/models/contest.py:242 msgid "Clone contest" msgstr "" -#: judge/models/contest.py:387 templates/contest/moss.html:74 +#: judge/models/contest.py:243 templates/contest/moss.html:74 msgid "MOSS contest" msgstr "" -#: judge/models/contest.py:388 +#: judge/models/contest.py:244 msgid "Rate contests" msgstr "" -#: judge/models/contest.py:389 +#: judge/models/contest.py:245 msgid "Contest access codes" msgstr "" -#: judge/models/contest.py:390 +#: judge/models/contest.py:246 msgid "Create private contests" msgstr "" -#: judge/models/contest.py:391 -msgid "Change contest visibility" -msgstr "" - -#: judge/models/contest.py:392 -msgid "Edit contest problem label script" -msgstr "" - -#: judge/models/contest.py:394 judge/models/contest.py:492 -#: judge/models/contest.py:529 judge/models/contest.py:552 -#: judge/models/submission.py:84 +#: judge/models/contest.py:248 judge/models/contest.py:345 +#: judge/models/contest.py:382 judge/models/contest.py:404 +#: judge/models/submission.py:83 msgid "contest" msgstr "concours" -#: judge/models/contest.py:395 +#: judge/models/contest.py:249 msgid "contests" msgstr "concours" -#: judge/models/contest.py:402 +#: judge/models/contest.py:256 msgid "associated contest" msgstr "" -#: judge/models/contest.py:405 +#: judge/models/contest.py:259 msgid "score" msgstr "score" -#: judge/models/contest.py:406 +#: judge/models/contest.py:260 msgid "cumulative time" msgstr "" -#: judge/models/contest.py:407 +#: judge/models/contest.py:261 msgid "is disqualified" msgstr "" -#: judge/models/contest.py:408 +#: judge/models/contest.py:262 msgid "Whether this participation is disqualified." msgstr "" -#: judge/models/contest.py:409 -msgid "tie-breaking field" -msgstr "" - -#: judge/models/contest.py:410 +#: judge/models/contest.py:263 msgid "virtual participation id" msgstr "" -#: judge/models/contest.py:411 +#: judge/models/contest.py:264 msgid "0 means non-virtual, otherwise the n-th virtual participation." msgstr "" -#: judge/models/contest.py:412 +#: judge/models/contest.py:265 msgid "contest format specific data" msgstr "" -#: judge/models/contest.py:478 +#: judge/models/contest.py:331 #, python-format msgid "%s spectating in %s" msgstr "" -#: judge/models/contest.py:480 +#: judge/models/contest.py:333 #, python-format msgid "%s in %s, v%d" msgstr "" -#: judge/models/contest.py:481 +#: judge/models/contest.py:334 #, python-format msgid "%s in %s" msgstr "" -#: judge/models/contest.py:484 +#: judge/models/contest.py:337 msgid "contest participation" msgstr "" -#: judge/models/contest.py:485 +#: judge/models/contest.py:338 msgid "contest participations" msgstr "" -#: judge/models/contest.py:491 judge/models/contest.py:513 -#: judge/models/contest.py:553 judge/models/problem.py:389 -#: judge/models/problem.py:394 judge/models/problem.py:412 -#: judge/models/problem_data.py:40 +#: judge/models/contest.py:344 judge/models/contest.py:366 +#: judge/models/contest.py:405 judge/models/problem.py:352 +#: judge/models/problem.py:357 judge/models/problem.py:375 +#: judge/models/problem_data.py:38 msgid "problem" msgstr "problème" -#: judge/models/contest.py:493 judge/models/contest.py:517 +#: judge/models/contest.py:346 judge/models/contest.py:370 #: judge/models/problem.py:129 msgid "points" msgstr "points" -#: judge/models/contest.py:494 +#: judge/models/contest.py:347 msgid "partial" msgstr "partiel" -#: judge/models/contest.py:495 judge/models/contest.py:518 +#: judge/models/contest.py:348 judge/models/contest.py:371 msgid "is pretested" msgstr "" -#: judge/models/contest.py:496 judge/models/interface.py:43 +#: judge/models/contest.py:349 judge/models/interface.py:43 msgid "order" msgstr "" -#: judge/models/contest.py:497 +#: judge/models/contest.py:350 msgid "0 to not show testcases, 1 to show" msgstr "" -#: judge/models/contest.py:498 +#: judge/models/contest.py:351 msgid "visible testcases" msgstr "" -#: judge/models/contest.py:499 +#: judge/models/contest.py:352 msgid "Maximum number of submissions for this problem, or 0 for no limit." msgstr "" -#: judge/models/contest.py:501 +#: judge/models/contest.py:354 msgid "Why include a problem you can't submit to?" msgstr "" -#: judge/models/contest.py:506 +#: judge/models/contest.py:359 msgid "contest problem" msgstr "" -#: judge/models/contest.py:507 +#: judge/models/contest.py:360 msgid "contest problems" msgstr "" -#: judge/models/contest.py:511 judge/models/submission.py:183 +#: judge/models/contest.py:364 judge/models/submission.py:181 msgid "submission" msgstr "soumission" -#: judge/models/contest.py:515 judge/models/contest.py:530 +#: judge/models/contest.py:368 judge/models/contest.py:383 msgid "participation" msgstr "" -#: judge/models/contest.py:519 +#: judge/models/contest.py:372 msgid "Whether this submission was ran only on pretests." msgstr "" -#: judge/models/contest.py:523 +#: judge/models/contest.py:376 msgid "contest submission" msgstr "" -#: judge/models/contest.py:524 +#: judge/models/contest.py:377 msgid "contest submissions" msgstr "" -#: judge/models/contest.py:532 +#: judge/models/contest.py:385 msgid "rank" msgstr "" -#: judge/models/contest.py:533 +#: judge/models/contest.py:386 msgid "rating" msgstr "évaluation" -#: judge/models/contest.py:534 +#: judge/models/contest.py:387 msgid "volatility" msgstr "" -#: judge/models/contest.py:535 +#: judge/models/contest.py:388 msgid "last rated" msgstr "" -#: judge/models/contest.py:539 +#: judge/models/contest.py:392 msgid "contest rating" msgstr "" -#: judge/models/contest.py:540 +#: judge/models/contest.py:393 msgid "contest ratings" msgstr "" -#: judge/models/contest.py:560 +#: judge/models/contest.py:412 msgid "contest moss result" msgstr "" -#: judge/models/contest.py:561 +#: judge/models/contest.py:413 msgid "contest moss results" msgstr "" @@ -1154,7 +1066,7 @@ msgstr "" msgid "post title" msgstr "" -#: judge/models/interface.py:67 judge/models/problem.py:432 +#: judge/models/interface.py:67 judge/models/problem.py:395 msgid "authors" msgstr "auteurs" @@ -1162,7 +1074,7 @@ msgstr "auteurs" msgid "slug" msgstr "" -#: judge/models/interface.py:69 judge/models/problem.py:430 +#: judge/models/interface.py:69 judge/models/problem.py:393 msgid "public visibility" msgstr "" @@ -1186,19 +1098,15 @@ msgstr "" msgid "openGraph image" msgstr "" -#: judge/models/interface.py:76 -msgid "If private, only these organizations may see the blog post." -msgstr "" - -#: judge/models/interface.py:105 +#: judge/models/interface.py:91 msgid "Edit all posts" msgstr "" -#: judge/models/interface.py:107 +#: judge/models/interface.py:93 msgid "blog post" msgstr "" -#: judge/models/interface.py:108 +#: judge/models/interface.py:94 msgid "blog posts" msgstr "" @@ -1222,6 +1130,10 @@ msgstr "" msgid "message timestamp" msgstr "" +#: judge/models/message.py:16 +msgid "read" +msgstr "" + #: judge/models/message.py:20 msgid "messages in the thread" msgstr "" @@ -1358,7 +1270,7 @@ msgid "" "are supported." msgstr "" -#: judge/models/problem.py:123 judge/models/problem.py:417 +#: judge/models/problem.py:123 judge/models/problem.py:380 msgid "memory limit" msgstr "limite de mémoire" @@ -1431,188 +1343,188 @@ msgstr "" msgid "If private, only these organizations may see the problem." msgstr "" -#: judge/models/problem.py:395 judge/models/problem.py:413 -#: judge/models/runtime.py:111 +#: judge/models/problem.py:358 judge/models/problem.py:376 +#: judge/models/runtime.py:108 msgid "language" msgstr "langue" -#: judge/models/problem.py:396 +#: judge/models/problem.py:359 msgid "translated name" msgstr "" -#: judge/models/problem.py:397 +#: judge/models/problem.py:360 msgid "translated description" msgstr "" -#: judge/models/problem.py:401 +#: judge/models/problem.py:364 msgid "problem translation" msgstr "" -#: judge/models/problem.py:402 +#: judge/models/problem.py:365 msgid "problem translations" msgstr "" -#: judge/models/problem.py:406 +#: judge/models/problem.py:369 msgid "clarified problem" msgstr "" -#: judge/models/problem.py:407 +#: judge/models/problem.py:370 msgid "clarification body" msgstr "" -#: judge/models/problem.py:408 +#: judge/models/problem.py:371 msgid "clarification timestamp" msgstr "" -#: judge/models/problem.py:423 +#: judge/models/problem.py:386 msgid "language-specific resource limit" msgstr "limite de ressources spécifiques à un language" -#: judge/models/problem.py:424 +#: judge/models/problem.py:387 msgid "language-specific resource limits" msgstr "limites de ressources spécifiques à un language" -#: judge/models/problem.py:428 +#: judge/models/problem.py:391 msgid "associated problem" msgstr "" -#: judge/models/problem.py:431 +#: judge/models/problem.py:394 msgid "publish date" msgstr "" -#: judge/models/problem.py:433 +#: judge/models/problem.py:396 msgid "editorial content" msgstr "" -#: judge/models/problem.py:449 +#: judge/models/problem.py:412 msgid "solution" msgstr "solution" -#: judge/models/problem.py:450 +#: judge/models/problem.py:413 msgid "solutions" msgstr "solutions" -#: judge/models/problem_data.py:26 +#: judge/models/problem_data.py:24 msgid "Standard" msgstr "" -#: judge/models/problem_data.py:27 +#: judge/models/problem_data.py:25 msgid "Floats" msgstr "" -#: judge/models/problem_data.py:28 +#: judge/models/problem_data.py:26 msgid "Floats (absolute)" msgstr "" -#: judge/models/problem_data.py:29 +#: judge/models/problem_data.py:27 msgid "Floats (relative)" msgstr "" -#: judge/models/problem_data.py:30 +#: judge/models/problem_data.py:28 msgid "Non-trailing spaces" msgstr "" -#: judge/models/problem_data.py:31 +#: judge/models/problem_data.py:29 msgid "Unordered" msgstr "" -#: judge/models/problem_data.py:32 +#: judge/models/problem_data.py:30 msgid "Byte identical" msgstr "" -#: judge/models/problem_data.py:33 +#: judge/models/problem_data.py:31 msgid "Line-by-line" msgstr "" -#: judge/models/problem_data.py:34 +#: judge/models/problem_data.py:32 msgid "Custom checker (PY)" msgstr "" -#: judge/models/problem_data.py:35 +#: judge/models/problem_data.py:33 msgid "Custom validator (CPP)" msgstr "" -#: judge/models/problem_data.py:42 +#: judge/models/problem_data.py:40 msgid "data zip file" msgstr "" -#: judge/models/problem_data.py:44 +#: judge/models/problem_data.py:42 msgid "generator file" msgstr "" -#: judge/models/problem_data.py:46 judge/models/problem_data.py:121 +#: judge/models/problem_data.py:44 judge/models/problem_data.py:110 msgid "output prefix length" msgstr "" -#: judge/models/problem_data.py:47 judge/models/problem_data.py:122 +#: judge/models/problem_data.py:45 judge/models/problem_data.py:111 msgid "output limit length" msgstr "" -#: judge/models/problem_data.py:48 +#: judge/models/problem_data.py:46 msgid "init.yml generation feedback" msgstr "" -#: judge/models/problem_data.py:49 judge/models/problem_data.py:123 +#: judge/models/problem_data.py:47 judge/models/problem_data.py:112 msgid "checker" msgstr "" -#: judge/models/problem_data.py:50 judge/models/problem_data.py:124 +#: judge/models/problem_data.py:48 judge/models/problem_data.py:113 msgid "checker arguments" msgstr "" -#: judge/models/problem_data.py:51 judge/models/problem_data.py:125 +#: judge/models/problem_data.py:49 judge/models/problem_data.py:114 msgid "checker arguments as a JSON object" msgstr "" -#: judge/models/problem_data.py:52 +#: judge/models/problem_data.py:50 msgid "custom checker file" msgstr "" -#: judge/models/problem_data.py:58 +#: judge/models/problem_data.py:56 msgid "custom validator file" msgstr "" -#: judge/models/problem_data.py:108 +#: judge/models/problem_data.py:97 msgid "problem data set" msgstr "" -#: judge/models/problem_data.py:110 +#: judge/models/problem_data.py:99 msgid "case position" msgstr "" -#: judge/models/problem_data.py:111 +#: judge/models/problem_data.py:100 msgid "case type" msgstr "" -#: judge/models/problem_data.py:112 +#: judge/models/problem_data.py:101 msgid "Normal case" msgstr "" -#: judge/models/problem_data.py:113 +#: judge/models/problem_data.py:102 msgid "Batch start" msgstr "" -#: judge/models/problem_data.py:114 +#: judge/models/problem_data.py:103 msgid "Batch end" msgstr "" -#: judge/models/problem_data.py:116 +#: judge/models/problem_data.py:105 msgid "input file name" msgstr "" -#: judge/models/problem_data.py:117 +#: judge/models/problem_data.py:106 msgid "output file name" msgstr "" -#: judge/models/problem_data.py:118 +#: judge/models/problem_data.py:107 msgid "generator arguments" msgstr "" -#: judge/models/problem_data.py:119 +#: judge/models/problem_data.py:108 msgid "point value" msgstr "" -#: judge/models/problem_data.py:120 +#: judge/models/problem_data.py:109 msgid "case is pretest?" msgstr "" @@ -1685,7 +1597,7 @@ msgid "" msgstr "" #: judge/models/profile.py:76 judge/models/profile.py:93 -#: judge/models/profile.py:212 +#: judge/models/profile.py:192 msgid "organization" msgstr "organisation" @@ -1781,31 +1693,31 @@ msgstr "" msgid "Notes for administrators regarding this user." msgstr "" -#: judge/models/profile.py:206 +#: judge/models/profile.py:186 msgid "user profile" msgstr "profil utilisateur" -#: judge/models/profile.py:207 +#: judge/models/profile.py:187 msgid "user profiles" msgstr "" -#: judge/models/profile.py:214 +#: judge/models/profile.py:194 msgid "request time" msgstr "" -#: judge/models/profile.py:215 +#: judge/models/profile.py:195 msgid "state" msgstr "" -#: judge/models/profile.py:220 +#: judge/models/profile.py:200 msgid "reason" msgstr "raison" -#: judge/models/profile.py:223 +#: judge/models/profile.py:203 msgid "organization join request" msgstr "" -#: judge/models/profile.py:224 +#: judge/models/profile.py:204 msgid "organization join requests" msgstr "" @@ -1896,86 +1808,86 @@ msgstr "" msgid "The extension of source files, e.g., \"py\" or \"cpp\"." msgstr "L'extension des fichiers sources, par exemple \"py\" ou \"cpp\"." -#: judge/models/runtime.py:112 +#: judge/models/runtime.py:109 msgid "languages" msgstr "langues" -#: judge/models/runtime.py:116 +#: judge/models/runtime.py:113 msgid "language to which this runtime belongs" msgstr "" -#: judge/models/runtime.py:117 +#: judge/models/runtime.py:114 msgid "judge on which this runtime exists" msgstr "" -#: judge/models/runtime.py:118 +#: judge/models/runtime.py:115 msgid "runtime name" msgstr "" -#: judge/models/runtime.py:119 +#: judge/models/runtime.py:116 msgid "runtime version" msgstr "" -#: judge/models/runtime.py:120 +#: judge/models/runtime.py:117 msgid "order in which to display this runtime" msgstr "" -#: judge/models/runtime.py:124 +#: judge/models/runtime.py:121 msgid "Server name, hostname-style" msgstr "" -#: judge/models/runtime.py:125 +#: judge/models/runtime.py:122 msgid "time of creation" msgstr "moment de création" -#: judge/models/runtime.py:126 +#: judge/models/runtime.py:123 msgid "A key to authenticate this judge" msgstr "" -#: judge/models/runtime.py:127 +#: judge/models/runtime.py:124 msgid "authentication key" msgstr "" -#: judge/models/runtime.py:128 +#: judge/models/runtime.py:125 msgid "block judge" msgstr "" -#: judge/models/runtime.py:129 +#: judge/models/runtime.py:126 msgid "" "Whether this judge should be blocked from connecting, even if its key is " "correct." msgstr "" -#: judge/models/runtime.py:131 +#: judge/models/runtime.py:128 msgid "judge online status" msgstr "" -#: judge/models/runtime.py:132 +#: judge/models/runtime.py:129 msgid "judge start time" msgstr "" -#: judge/models/runtime.py:133 +#: judge/models/runtime.py:130 msgid "response time" msgstr "" -#: judge/models/runtime.py:134 +#: judge/models/runtime.py:131 msgid "system load" msgstr "" -#: judge/models/runtime.py:135 +#: judge/models/runtime.py:132 msgid "Load for the last minute, divided by processors to be fair." msgstr "" -#: judge/models/runtime.py:139 judge/models/runtime.py:179 +#: judge/models/runtime.py:136 judge/models/runtime.py:176 msgid "judges" msgstr "" -#: judge/models/runtime.py:178 +#: judge/models/runtime.py:175 msgid "judge" msgstr "" #: judge/models/submission.py:20 judge/models/submission.py:47 -#: judge/utils/problems.py:79 +#: judge/utils/problems.py:77 msgid "Accepted" msgstr "Accepté" @@ -2004,7 +1916,7 @@ msgid "Runtime Error" msgstr "Erreur d'exécution" #: judge/models/submission.py:27 judge/models/submission.py:41 -#: judge/models/submission.py:55 judge/utils/problems.py:81 +#: judge/models/submission.py:55 judge/utils/problems.py:79 msgid "Compile Error" msgstr "Erreur de compilation" @@ -2045,15 +1957,15 @@ msgstr "" msgid "submission time" msgstr "" -#: judge/models/submission.py:67 judge/models/submission.py:203 +#: judge/models/submission.py:67 judge/models/submission.py:201 msgid "execution time" msgstr "" -#: judge/models/submission.py:68 judge/models/submission.py:204 +#: judge/models/submission.py:68 judge/models/submission.py:202 msgid "memory usage" msgstr "" -#: judge/models/submission.py:69 judge/models/submission.py:205 +#: judge/models/submission.py:69 judge/models/submission.py:203 msgid "points granted" msgstr "" @@ -2090,64 +2002,58 @@ msgid "judged on" msgstr "" #: judge/models/submission.py:81 -#, fuzzy -#| msgid "submission" -msgid "submission judge time" -msgstr "soumission" - -#: judge/models/submission.py:82 msgid "was rejudged by admin" msgstr "" -#: judge/models/submission.py:83 +#: judge/models/submission.py:82 msgid "was ran on pretests only" msgstr "" -#: judge/models/submission.py:184 templates/contest/moss.html:58 +#: judge/models/submission.py:182 templates/contest/moss.html:58 msgid "submissions" msgstr "soumissions" -#: judge/models/submission.py:188 judge/models/submission.py:199 +#: judge/models/submission.py:186 judge/models/submission.py:197 msgid "associated submission" msgstr "" -#: judge/models/submission.py:190 +#: judge/models/submission.py:188 msgid "source code" msgstr "" -#: judge/models/submission.py:201 +#: judge/models/submission.py:199 msgid "test case ID" msgstr "" -#: judge/models/submission.py:202 +#: judge/models/submission.py:200 msgid "status flag" msgstr "" -#: judge/models/submission.py:206 +#: judge/models/submission.py:204 msgid "points possible" msgstr "" -#: judge/models/submission.py:207 +#: judge/models/submission.py:205 msgid "batch number" msgstr "" -#: judge/models/submission.py:208 +#: judge/models/submission.py:206 msgid "judging feedback" msgstr "" -#: judge/models/submission.py:209 +#: judge/models/submission.py:207 msgid "extended judging feedback" msgstr "" -#: judge/models/submission.py:210 +#: judge/models/submission.py:208 msgid "program output" msgstr "" -#: judge/models/submission.py:218 +#: judge/models/submission.py:216 msgid "submission test case" msgstr "" -#: judge/models/submission.py:219 +#: judge/models/submission.py:217 msgid "submission test cases" msgstr "" @@ -2199,23 +2105,12 @@ msgstr "" msgid "message time" msgstr "" -#: judge/pdf_problems.py:147 judge/pdf_problems.py:199 -#: judge/pdf_problems.py:259 +#: judge/pdf_problems.py:134 judge/pdf_problems.py:186 +#: judge/pdf_problems.py:246 msgid "Page [page] of [topage]" msgstr "" -#: judge/pdf_problems.py:280 -#, python-format -msgid "Page %s of %s" -msgstr "" - -#: judge/tasks/contest.py:19 -#, fuzzy -#| msgid "Recalculate scores" -msgid "Recalculating contest scores" -msgstr "Recalculer les scores" - -#: judge/tasks/contest.py:40 +#: judge/tasks/moss.py:25 msgid "Running MOSS" msgstr "" @@ -2227,60 +2122,60 @@ msgstr "" msgid "Recalculating user points" msgstr "" -#: judge/utils/problem_data.py:70 +#: judge/utils/problem_data.py:68 msgid "Empty batches not allowed." msgstr "" -#: judge/utils/problem_data.py:78 judge/utils/problem_data.py:99 +#: judge/utils/problem_data.py:76 judge/utils/problem_data.py:97 msgid "How did you corrupt the custom checker path?" msgstr "" -#: judge/utils/problem_data.py:120 +#: judge/utils/problem_data.py:118 #, python-format msgid "Points must be defined for non-batch case #%d." msgstr "" -#: judge/utils/problem_data.py:125 +#: judge/utils/problem_data.py:123 #, python-format msgid "Input file for case %d does not exist: %s" msgstr "" -#: judge/utils/problem_data.py:128 +#: judge/utils/problem_data.py:126 #, python-format msgid "Output file for case %d does not exist: %s" msgstr "" -#: judge/utils/problem_data.py:153 +#: judge/utils/problem_data.py:151 #, python-format msgid "Batch start case #%d requires points." msgstr "" -#: judge/utils/problem_data.py:174 +#: judge/utils/problem_data.py:172 #, python-format msgid "Attempt to end batch outside of one in case #%d" msgstr "" -#: judge/utils/problem_data.py:192 +#: judge/utils/problem_data.py:190 msgid "How did you corrupt the zip path?" msgstr "" -#: judge/utils/problem_data.py:198 +#: judge/utils/problem_data.py:196 msgid "How did you corrupt the generator path?" msgstr "" -#: judge/utils/problems.py:80 +#: judge/utils/problems.py:78 msgid "Wrong" msgstr "" -#: judge/utils/problems.py:82 +#: judge/utils/problems.py:80 msgid "Timeout" msgstr "" -#: judge/utils/problems.py:83 +#: judge/utils/problems.py:81 msgid "Error" msgstr "" -#: judge/utils/problems.py:94 +#: judge/utils/problems.py:92 msgid "Can't pass both queryset and keyword filters" msgstr "" @@ -2323,8 +2218,7 @@ msgctxt "hours and minutes" msgid "%h:%m" msgstr "" -#: judge/views/about.py:7 templates/organization/home.html:112 -#: templates/user/user-about.html:83 templates/user/user-tabs.html:4 +#: judge/views/about.py:7 templates/user/user-about.html:33 msgid "About" msgstr "A propos" @@ -2332,166 +2226,156 @@ msgstr "A propos" msgid "Custom Checker Sample" msgstr "" -#: judge/views/blog.py:45 +#: judge/views/blog.py:38 #, python-format msgid "Page %d of Posts" msgstr "" -#: judge/views/comment.py:28 +#: judge/views/comment.py:27 msgid "Messing around, are we?" msgstr "" -#: judge/views/comment.py:37 +#: judge/views/comment.py:36 msgid "You must solve at least one problem before you can vote." msgstr "" -#: judge/views/comment.py:64 +#: judge/views/comment.py:63 msgid "You already voted." msgstr "" -#: judge/views/comment.py:126 judge/views/organization.py:344 +#: judge/views/comment.py:120 judge/views/organization.py:299 msgid "Edited from site" msgstr "" -#: judge/views/comment.py:147 +#: judge/views/comment.py:141 msgid "Editing comment" msgstr "" -#: judge/views/contests.py:57 judge/views/contests.py:247 -#: judge/views/contests.py:250 judge/views/contests.py:424 +#: judge/views/contests.py:55 judge/views/contests.py:215 +#: judge/views/contests.py:218 judge/views/contests.py:389 msgid "No such contest" msgstr "" -#: judge/views/contests.py:58 judge/views/contests.py:248 +#: judge/views/contests.py:56 judge/views/contests.py:216 #, python-format msgid "Could not find a contest with the key \"%s\"." msgstr "" -#: judge/views/contests.py:71 +#: judge/views/contests.py:81 msgid "Contests" msgstr "Concours" -#: judge/views/contests.py:251 +#: judge/views/contests.py:219 msgid "Could not find such contest." msgstr "" -#: judge/views/contests.py:254 +#: judge/views/contests.py:222 #, python-format msgid "Access to contest \"%s\" denied" msgstr "" -#: judge/views/contests.py:278 +#: judge/views/contests.py:246 msgid "Clone Contest" msgstr "" -#: judge/views/contests.py:343 +#: judge/views/contests.py:309 msgid "Contest not ongoing" msgstr "" -#: judge/views/contests.py:344 +#: judge/views/contests.py:310 #, python-format msgid "\"%s\" is not currently ongoing." msgstr "" -#: judge/views/contests.py:348 +#: judge/views/contests.py:314 msgid "Already in contest" msgstr "" -#: judge/views/contests.py:349 +#: judge/views/contests.py:315 #, python-format msgid "You are already in a contest: \"%s\"." msgstr "" -#: judge/views/contests.py:352 +#: judge/views/contests.py:318 msgid "Banned from joining" msgstr "" -#: judge/views/contests.py:353 +#: judge/views/contests.py:319 msgid "" "You have been declared persona non grata for this contest. You are " "permanently barred from joining this contest." msgstr "" -#: judge/views/contests.py:414 +#: judge/views/contests.py:379 #, python-format msgid "Enter access code for \"%s\"" msgstr "" -#: judge/views/contests.py:425 +#: judge/views/contests.py:390 #, python-format msgid "You are not in contest \"%s\"." msgstr "" -#: judge/views/contests.py:444 +#: judge/views/contests.py:409 msgid "ContestCalendar requires integer year and month" msgstr "" -#: judge/views/contests.py:484 +#: judge/views/contests.py:449 #, python-format msgid "Contests in %(month)s" msgstr "" -#: judge/views/contests.py:484 +#: judge/views/contests.py:449 msgid "F Y" msgstr "" -#: judge/views/contests.py:532 +#: judge/views/contests.py:496 #, python-format msgid "%s Statistics" msgstr "" -#: judge/views/contests.py:717 +#: judge/views/contests.py:601 +msgid "???" +msgstr "" + +#: judge/views/contests.py:664 #, python-format msgid "%s Rankings" msgstr "" -#: judge/views/contests.py:725 -msgid "???" -msgstr "" - -#: judge/views/contests.py:741 +#: judge/views/contests.py:680 #, python-format msgid "Your participation in %s" msgstr "" -#: judge/views/contests.py:742 +#: judge/views/contests.py:681 #, python-format msgid "%s's participation in %s" msgstr "" -#: judge/views/contests.py:749 +#: judge/views/contests.py:685 msgid "Live" msgstr "" -#: judge/views/contests.py:761 templates/contest/contest-tabs.html:13 +#: judge/views/contests.py:697 msgid "Participation" msgstr "" -#: judge/views/contests.py:808 +#: judge/views/contests.py:743 #, python-format msgid "%s MOSS Results" msgstr "" -#: judge/views/contests.py:835 +#: judge/views/contests.py:770 #, python-format msgid "Running MOSS for %s..." msgstr "" -#: judge/views/contests.py:858 +#: judge/views/contests.py:793 #, python-format msgid "Contest tag: %s" msgstr "" -#: judge/views/contests.py:868 judge/views/ticket.py:57 -msgid "Issue description" -msgstr "" - -#: judge/views/contests.py:911 -#, fuzzy, python-format -#| msgid "Best solutions for %s" -msgid "New clarification for %s" -msgstr "Les meilleures solutions pour %s" - #: judge/views/error.py:14 msgid "404 error" msgstr "Erreur 404" @@ -2512,122 +2396,115 @@ msgid "corrupt page %s" msgstr "" #: judge/views/language.py:12 templates/status/judge-status-table.html:9 -#: templates/status/status-tabs.html:5 msgid "Runtimes" msgstr "" -#: judge/views/notification.py:40 -#, python-format -msgid "Notifications (%d unseen)" -msgstr "" - -#: judge/views/organization.py:59 judge/views/organization.py:62 +#: judge/views/organization.py:44 judge/views/organization.py:47 msgid "No such organization" msgstr "" -#: judge/views/organization.py:60 +#: judge/views/organization.py:45 #, python-format msgid "Could not find an organization with the key \"%s\"." msgstr "" -#: judge/views/organization.py:63 +#: judge/views/organization.py:48 msgid "Could not find such organization." msgstr "" -#: judge/views/organization.py:79 judge/views/register.py:34 -#: templates/organization/list.html:32 templates/user/import/table_csv.html:9 -#: templates/user/user-list-tabs.html:6 +#: judge/views/organization.py:72 judge/views/register.py:34 +#: templates/organization/list.html:15 msgid "Organizations" msgstr "" -#: judge/views/organization.py:130 +#: judge/views/organization.py:93 #, python-format msgid "%s Members" msgstr "" -#: judge/views/organization.py:159 judge/views/organization.py:162 -#: judge/views/organization.py:167 +#: judge/views/organization.py:118 judge/views/organization.py:121 +#: judge/views/organization.py:126 msgid "Joining organization" msgstr "" -#: judge/views/organization.py:159 +#: judge/views/organization.py:118 msgid "You are already in the organization." msgstr "" -#: judge/views/organization.py:162 +#: judge/views/organization.py:121 msgid "This organization is not open." msgstr "" -#: judge/views/organization.py:179 +#: judge/views/organization.py:138 msgid "Leaving organization" msgstr "" -#: judge/views/organization.py:179 +#: judge/views/organization.py:138 #, python-format msgid "You are not in \"%s\"." msgstr "" -#: judge/views/organization.py:203 +#: judge/views/organization.py:162 #, python-format msgid "Request to join %s" msgstr "" -#: judge/views/organization.py:221 +#: judge/views/organization.py:180 msgid "Join request detail" msgstr "" -#: judge/views/organization.py:254 +#: judge/views/organization.py:209 #, python-format msgid "Managing join requests for %s" msgstr "" -#: judge/views/organization.py:285 +#: judge/views/organization.py:240 #, python-format msgid "" "Your organization can only receive %d more members. You cannot approve %d " "users." msgstr "" -#: judge/views/organization.py:297 +#: judge/views/organization.py:252 #, python-format msgid "Approved %d user." msgid_plural "Approved %d users." msgstr[0] "" msgstr[1] "" -#: judge/views/organization.py:298 +#: judge/views/organization.py:253 #, python-format msgid "Rejected %d user." msgid_plural "Rejected %d users." msgstr[0] "" msgstr[1] "" -#: judge/views/organization.py:328 +#: judge/views/organization.py:283 #, python-format msgid "Editing %s" msgstr "" -#: judge/views/organization.py:352 judge/views/organization.py:360 +#: judge/views/organization.py:307 judge/views/organization.py:315 msgid "Can't edit organization" msgstr "" -#: judge/views/organization.py:353 +#: judge/views/organization.py:308 msgid "You are not allowed to edit this organization." msgstr "" -#: judge/views/organization.py:361 +#: judge/views/organization.py:316 msgid "You are not allowed to kick people from this organization." msgstr "" -#: judge/views/organization.py:366 judge/views/organization.py:370 +#: judge/views/organization.py:321 judge/views/organization.py:325 msgid "Can't kick user" msgstr "" -#: judge/views/organization.py:367 +#: judge/views/organization.py:322 msgid "The user you are trying to kick does not exist!" msgstr "" -#: judge/views/organization.py:371 +#: judge/views/organization.py:326 #, python-format msgid "The user you are trying to kick is not in organization: %s." msgstr "" @@ -2651,36 +2528,35 @@ msgstr "" msgid "Editorial for {0}" msgstr "" -#: judge/views/problem.py:285 templates/contest/contest.html:79 -#: templates/user/user-about.html:28 templates/user/user-tabs.html:5 -#: templates/user/users-table.html:31 +#: judge/views/problem.py:286 templates/contest/contest.html:79 +#: templates/user/users-table.html:23 msgid "Problems" msgstr "Problèmes" -#: judge/views/problem.py:585 +#: judge/views/problem.py:547 msgid "Banned from submitting" msgstr "" -#: judge/views/problem.py:586 +#: judge/views/problem.py:548 msgid "" "You have been declared persona non grata for this problem. You are " "permanently barred from submitting this problem." msgstr "" -#: judge/views/problem.py:600 +#: judge/views/problem.py:562 msgid "Too many submissions" msgstr "" -#: judge/views/problem.py:601 +#: judge/views/problem.py:563 msgid "You have exceeded the submission limit for this problem." msgstr "" -#: judge/views/problem.py:661 judge/views/problem.py:664 +#: judge/views/problem.py:633 judge/views/problem.py:636 #, python-format msgid "Submit to %(problem)s" msgstr "" -#: judge/views/problem.py:679 +#: judge/views/problem.py:652 msgid "Clone Problem" msgstr "" @@ -2721,22 +2597,22 @@ msgstr "" msgid "Generated init.yml for %s" msgstr "" -#: judge/views/problem_manage.py:52 judge/views/problem_manage.py:55 +#: judge/views/problem_manage.py:50 judge/views/problem_manage.py:53 #, python-format msgid "Managing submissions for %s" msgstr "" -#: judge/views/problem_manage.py:97 +#: judge/views/problem_manage.py:95 #, python-format msgid "Rejudging selected submissions for %s..." msgstr "" -#: judge/views/problem_manage.py:141 +#: judge/views/problem_manage.py:110 #, python-format msgid "Rescoring all submissions for %s..." msgstr "" -#: judge/views/problem_manage.py:150 +#: judge/views/problem_manage.py:119 #, python-format msgid "Successfully scheduled %d submission for rejudging." msgid_plural "Successfully scheduled %d submissions for rejudging." @@ -2785,7 +2661,7 @@ msgstr "Langue préférée" msgid "Subscribe to newsletter?" msgstr "" -#: judge/views/register.py:55 +#: judge/views/register.py:45 #, python-format msgid "" "The email address \"%s\" is already taken. Only one registration is allowed " @@ -2794,17 +2670,17 @@ msgstr "" "Il y a déjà un compte avec cette adresse: \"%s\". Qu’une seule compte est " "autorisée par adresse." -#: judge/views/register.py:61 +#: judge/views/register.py:51 msgid "" "Your email provider is not allowed due to history of abuse. Please use a " "reputable email provider." msgstr "" -#: judge/views/register.py:67 judge/views/register.py:105 +#: judge/views/register.py:57 judge/views/register.py:95 msgid "Registration" msgstr "" -#: judge/views/register.py:116 +#: judge/views/register.py:106 msgid "Authentication failure" msgstr "" @@ -2820,100 +2696,104 @@ msgstr "Etat" msgid "Version matrix" msgstr "" -#: judge/views/submission.py:84 judge/views/submission.py:91 +#: judge/views/submission.py:83 judge/views/submission.py:90 #, python-format msgid "Submission of %(problem)s by %(user)s" msgstr "" -#: judge/views/submission.py:244 judge/views/submission.py:245 -#: templates/problem/problem.html:167 +#: judge/views/submission.py:227 judge/views/submission.py:228 +#: templates/problem/problem.html:127 msgid "All submissions" msgstr "" -#: judge/views/submission.py:404 +#: judge/views/submission.py:384 msgid "All my submissions" msgstr "" -#: judge/views/submission.py:405 +#: judge/views/submission.py:385 #, python-format msgid "All submissions by %s" msgstr "" -#: judge/views/submission.py:436 +#: judge/views/submission.py:416 #, python-format msgid "All submissions for %s" msgstr "" -#: judge/views/submission.py:455 +#: judge/views/submission.py:435 msgid "Must pass a problem" msgstr "" -#: judge/views/submission.py:501 +#: judge/views/submission.py:481 #, python-format msgid "My submissions for %(problem)s" msgstr "" -#: judge/views/submission.py:502 +#: judge/views/submission.py:482 #, python-format msgid "%(user)s's submissions for %(problem)s" msgstr "" -#: judge/views/submission.py:603 +#: judge/views/submission.py:583 msgid "Must pass a contest" msgstr "" -#: judge/views/submission.py:622 +#: judge/views/submission.py:602 #, python-brace-format msgid "" "{0}'s submissions for {2} in {4}" msgstr "" -#: judge/views/submission.py:629 +#: judge/views/submission.py:609 #, python-brace-format msgid "" "{0}'s submissions for problem {2} in {3}" "" msgstr "" -#: judge/views/ticket.py:50 judge/views/ticket.py:56 +#: judge/views/ticket.py:33 judge/views/ticket.py:39 msgid "Ticket title" msgstr "" -#: judge/views/ticket.py:107 judge/views/ticket.py:110 +#: judge/views/ticket.py:40 +msgid "Issue description" +msgstr "" + +#: judge/views/ticket.py:85 judge/views/ticket.py:88 #, python-format msgid "New ticket for %s" msgstr "" -#: judge/views/ticket.py:170 +#: judge/views/ticket.py:142 #, python-format msgid "%(title)s - Ticket %(id)d" msgstr "" -#: judge/views/ticket.py:279 +#: judge/views/ticket.py:251 #, python-format msgid "Tickets - Page %(number)d of %(total)d" msgstr "" -#: judge/views/ticket.py:328 +#: judge/views/ticket.py:300 #, python-format msgid "New Ticket: %s" msgstr "" -#: judge/views/ticket.py:329 +#: judge/views/ticket.py:301 #, python-format msgid "#%(id)d, assigned to: %(users)s" msgstr "" -#: judge/views/ticket.py:331 +#: judge/views/ticket.py:303 msgid ", " msgstr "" -#: judge/views/ticket.py:331 +#: judge/views/ticket.py:303 msgid "no one" msgstr "" -#: judge/views/ticket.py:351 +#: judge/views/ticket.py:323 #, python-format msgid "New Ticket Message For: %s" msgstr "" @@ -2930,50 +2810,41 @@ msgstr "" msgid "Perform Two Factor Authentication" msgstr "" -#: judge/views/user.py:74 +#: judge/views/user.py:68 msgid "No such user" msgstr "" -#: judge/views/user.py:74 +#: judge/views/user.py:68 #, python-format msgid "No user handle \"%s\"." msgstr "" -#: judge/views/user.py:78 +#: judge/views/user.py:72 msgid "My account" msgstr "" -#: judge/views/user.py:79 +#: judge/views/user.py:73 #, python-format msgid "User %s" msgstr "" -#: judge/views/user.py:148 -msgid "M j, Y" -msgstr "" - -#: judge/views/user.py:171 +#: judge/views/user.py:136 msgid "M j, Y, G:i" msgstr "" -#: judge/views/user.py:290 +#: judge/views/user.py:221 msgid "Updated on site" msgstr "" -#: judge/views/user.py:323 templates/admin/auth/user/change_form.html:14 -#: templates/admin/auth/user/change_form.html:17 templates/base.html:238 -#: templates/user/user-tabs.html:10 +#: judge/views/user.py:254 templates/admin/auth/user/change_form.html:14 +#: templates/admin/auth/user/change_form.html:17 templates/base.html:224 msgid "Edit profile" msgstr "Modifier le profile" -#: judge/views/user.py:332 templates/user/user-list-tabs.html:4 +#: judge/views/user.py:263 msgid "Leaderboard" msgstr "" -#: judge/views/user.py:407 -msgid "Import Users" -msgstr "" - #: judge/views/widgets.py:48 judge/views/widgets.py:58 #, python-format msgid "Invalid upstream data: %s" @@ -3011,7 +2882,7 @@ msgid "View Submissions" msgstr "" #: templates/admin/judge/problem/change_form.html:17 -#: templates/user/user-base.html:112 +#: templates/user/user-base.html:61 msgid "View submissions" msgstr "Voir les soumissions" @@ -3026,152 +2897,92 @@ msgstr "" msgid "Rejudge" msgstr "" -#: templates/base.html:230 -#, python-format -msgid "Hello, %(username)s." -msgstr "Bonjour, %(username)s." - -#: templates/base.html:236 templates/comments/list.html:89 -#: templates/contest/contest-list-tabs.html:24 -#: templates/contest/ranking-table.html:53 -#: templates/problem/problem-list-tabs.html:6 +#: templates/base.html:222 templates/comments/list.html:89 +#: templates/contest/ranking-table.html:39 #: templates/submission/info-base.html:12 -#: templates/submission/submission-list-tabs.html:15 msgid "Admin" msgstr "Admin" -#: templates/base.html:245 +#: templates/base.html:231 msgid "Log out" msgstr "Se déconnecter" -#: templates/base.html:254 +#: templates/base.html:240 #: templates/registration/password_reset_complete.html:4 msgid "Log in" msgstr "" -#: templates/base.html:255 templates/registration/registration_form.html:177 +#: templates/base.html:241 templates/registration/registration_form.html:177 msgid "or" msgstr "" -#: templates/base.html:256 +#: templates/base.html:242 msgid "Sign up" msgstr "" -#: templates/base.html:271 +#: templates/base.html:254 msgid "spectating" msgstr "" -#: templates/base.html:284 +#: templates/base.html:267 msgid "This site works best with JavaScript enabled." msgstr "Ce site fonctionne mieux avec JavaScript activé." -#: templates/blog/blog.html:13 templates/comments/list.html:68 -#: templates/comments/list.html:83 templates/contest/contest-tabs.html:23 -#: templates/contest/tag-title.html:9 templates/flatpages/admin_link.html:3 -#: templates/license.html:10 templates/problem/editorial.html:14 +#: templates/blog/content.html:13 templates/comments/list.html:68 +#: templates/comments/list.html:83 templates/contest/tag-title.html:9 +#: templates/flatpages/admin_link.html:3 templates/license.html:10 +#: templates/problem/editorial.html:14 msgid "Edit" msgstr "Modifier" -#: templates/blog/blog.html:26 -#, python-format -msgid "" -"\n" -" posted on %(time)s\n" -" " -msgstr "" - -#: templates/blog/content.html:10 -#, fuzzy, python-brace-format -#| msgid "Posted comment" -msgid "posted on {time}" -msgstr "Commentaire posté" - -#: templates/blog/dashboard.html:21 -#, python-format -msgid "" -"\n" -" on %(time)s\n" -" " -msgstr "" - -#: templates/blog/list.html:93 +#: templates/blog/list.html:85 msgid "Blog" msgstr "Blog" -#: templates/blog/list.html:95 +#: templates/blog/list.html:87 msgid "Events" msgstr "Evènements" -#: templates/blog/list.html:100 +#: templates/blog/list.html:92 msgid "News" msgstr "" -#: templates/blog/list.html:115 templates/problem/list.html:347 -#: templates/problem/problem.html:361 +#: templates/blog/list.html:130 templates/problem/problem.html:310 msgid "Clarifications" msgstr "" -#: templates/blog/list.html:121 -msgid "Add" -msgstr "" - -#: templates/blog/list.html:140 templates/problem/list.html:369 -#: templates/problem/problem.html:372 +#: templates/blog/list.html:146 templates/problem/problem.html:321 msgid "No clarifications have been made at this time." msgstr "" -#: templates/blog/list.html:148 +#: templates/blog/list.html:154 msgid "Ongoing contests" msgstr "Concours en cours" -#: templates/blog/list.html:166 +#: templates/blog/list.html:172 msgid "Upcoming contests" msgstr "Concours à venir" -#: templates/blog/list.html:184 -msgid "My open tickets" -msgstr "" - -#: templates/blog/list.html:206 -msgid "New tickets" -msgstr "" - -#: templates/blog/list.html:227 -msgid "New problems" -msgstr "Nouveaux problèmes" - -#: templates/blog/list.html:244 +#: templates/blog/list.html:189 msgid "Comment stream" msgstr "Flux de commentaire" -#: templates/chat/chat.html:305 -msgid "Chat" +#: templates/blog/list.html:208 +msgid "New problems" +msgstr "Nouveaux problèmes" + +#: templates/blog/list.html:225 +msgid "My open tickets" msgstr "" -#: templates/chat/chat.html:307 templates/chat/chat.html:314 -#, fuzzy -#| msgid "Online Judge" -msgid "Online Users" -msgstr "Juge en ligne" - -#: templates/chat/chat.html:315 -msgid "Refresh" +#: templates/blog/list.html:246 +msgid "New tickets" msgstr "" -#: templates/chat/chat.html:333 -msgid "Emoji" +#: templates/chat/chat.html:167 +msgid "Your message" msgstr "" -#: templates/chat/chat.html:334 -msgid "Enter your message" -msgstr "" - -#: templates/chat/message.html:20 -#, fuzzy -#| msgid "Delete?" -msgid "Delete" -msgstr "Supprimer ?" - #: templates/comments/list.html:2 msgid "Comments" msgstr "Commentaires" @@ -3180,21 +2991,11 @@ msgstr "Commentaires" msgid "Please login to vote" msgstr "" -#: templates/comments/list.html:40 -#, python-brace-format -msgid "commented on {time}" -msgstr "" - -#: templates/comments/list.html:49 -#, python-format -msgid "edit %(edits)s" -msgstr "" - -#: templates/comments/list.html:51 templates/comments/media-js.html:92 +#: templates/comments/list.html:51 templates/comments/media-js.html:77 msgid "edited" msgstr "" -#: templates/comments/list.html:60 templates/notification/list.html:14 +#: templates/comments/list.html:60 msgid "Link" msgstr "" @@ -3202,54 +3003,36 @@ msgstr "" msgid "Reply" msgstr "" -#: templates/comments/list.html:86 templates/contest/list.html:91 -#: templates/contest/list.html:95 templates/contest/list.html:280 +#: templates/comments/list.html:86 msgid "Hide" msgstr "" -#: templates/comments/list.html:101 -#, python-format -msgid "" -"\n" -" This comment is hidden due " -"to too much negative feedback.\n" -" Click here to view it.\n" -" " -msgstr "" - -#: templates/comments/list.html:121 +#: templates/comments/list.html:120 msgid "There are no comments at the moment." msgstr "Il n'y a aucun commentaire pour le moment." -#: templates/comments/list.html:127 +#: templates/comments/list.html:126 msgid "New comment" msgstr "Commenter" -#: templates/comments/list.html:141 +#: templates/comments/list.html:140 msgid "Invalid comment body." msgstr "Corps de commentaire non valide." -#: templates/comments/list.html:149 +#: templates/comments/list.html:148 msgid "Post!" msgstr "" -#: templates/comments/list.html:157 +#: templates/comments/list.html:156 msgid "Comments are disabled on this page." msgstr "" -#: templates/comments/media-js.html:38 -#, fuzzy -#| msgid "New comment" -msgid "Replying to comment" -msgstr "Commenter" - -#: templates/comments/media-js.html:87 +#: templates/comments/media-js.html:72 #, python-brace-format msgid "edit {edits}" msgstr "" -#: templates/comments/media-js.html:90 +#: templates/comments/media-js.html:75 msgid "original" msgstr "" @@ -3293,11 +3076,6 @@ msgstr "Vendredi" msgid "Saturday" msgstr "Samedi" -#: templates/contest/clarification.html:52 templates/organization/new.html:10 -#: templates/ticket/new.html:38 -msgid "Create" -msgstr "Créer" - #: templates/contest/clone.html:37 msgid "Enter a new key for the cloned contest:" msgstr "" @@ -3318,177 +3096,97 @@ msgstr "" msgid "Next" msgstr "Suiv" -#: templates/contest/contest-list-tabs.html:21 -#: templates/problem/problem-list-tabs.html:5 -msgid "List" -msgstr "" - -#: templates/contest/contest-list-tabs.html:22 -msgid "Calendar" -msgstr "" - -#: templates/contest/contest-tabs.html:4 templates/organization/home.html:105 -msgid "Info" -msgstr "" - -#: templates/contest/contest-tabs.html:6 templates/stats/base.html:9 -#: templates/submission/list.html:339 -msgid "Statistics" -msgstr "" - -#: templates/contest/contest-tabs.html:11 -#, fuzzy -#| msgid "Rank" -msgid "Rankings" -msgstr "Classement" - -#: templates/contest/contest-tabs.html:16 -msgid "Hidden Rankings" -msgstr "" - -#: templates/contest/contest-tabs.html:21 -msgid "MOSS" -msgstr "" - -#: templates/contest/contest-tabs.html:26 -msgid "Clone" -msgstr "" - -#: templates/contest/contest-tabs.html:38 -#: templates/contest/contest-tabs.html:58 +#: templates/contest/contest-tabs.html:37 msgid "Leave contest" msgstr "Quitter le concours" -#: templates/contest/contest-tabs.html:45 templates/contest/list.html:388 +#: templates/contest/contest-tabs.html:44 templates/contest/list.html:293 msgid "Virtual join" msgstr "" -#: templates/contest/contest-tabs.html:56 -msgid "Stop spectating" -msgstr "" - -#: templates/contest/contest-tabs.html:65 +#: templates/contest/contest-tabs.html:64 msgid "Spectate contest" msgstr "" -#: templates/contest/contest-tabs.html:72 +#: templates/contest/contest-tabs.html:70 +#: templates/contest/contest-tabs.html:76 msgid "Join contest" msgstr "Joindre les concours" -#: templates/contest/contest-tabs.html:81 +#: templates/contest/contest-tabs.html:85 msgid "Login to participate" msgstr "" -#: templates/contest/contest.html:37 -msgid "Participating virtually." -msgstr "" - -#: templates/contest/contest.html:43 -msgid "Contest is over." -msgstr "Concours est terminé." - #: templates/contest/contest.html:59 templates/contest/contest.html:63 msgid "F j, Y, G:i T" msgstr "" -#: templates/contest/contest.html:59 -#, python-format -msgid "" -"%(time_limit)s window between %(start_time)s and " -"%(end_time)s" -msgstr "" - -#: templates/contest/contest.html:63 -#, python-format -msgid "%(length)s long starting on %(start_time)s" -msgstr "" - #: templates/contest/contest.html:85 msgid "AC Rate" msgstr "" -#: templates/contest/contest.html:86 templates/contest/list.html:237 -#: templates/contest/list.html:289 templates/contest/list.html:366 -#: templates/problem/list.html:223 templates/problem/list.html:254 +#: templates/contest/contest.html:86 templates/contest/list.html:153 +#: templates/contest/list.html:195 templates/contest/list.html:271 +#: templates/problem/list.html:212 templates/problem/list.html:238 msgid "Users" msgstr "Utilisateurs" -#: templates/contest/contest.html:111 templates/problem/list.html:330 +#: templates/contest/contest.html:111 msgid "Editorial" msgstr "" -#: templates/contest/list.html:83 templates/contest/media-js.html:9 +#: templates/contest/list.html:31 templates/contest/media-js.html:9 msgid "Are you sure you want to join?" msgstr "" -#: templates/contest/list.html:84 +#: templates/contest/list.html:32 msgid "" "Joining a contest for the first time starts your timer, after which it " "becomes unstoppable." msgstr "" -#: templates/contest/list.html:92 templates/contest/list.html:278 -msgid "Show" -msgstr "" - -#: templates/contest/list.html:102 templates/problem/list.html:68 -#, fuzzy -#| msgid "Organization" -msgid "Organizations..." -msgstr "Organisation " - -#: templates/contest/list.html:135 +#: templates/contest/list.html:65 msgid "hidden" msgstr "" -#: templates/contest/list.html:140 +#: templates/contest/list.html:70 msgid "private" msgstr "" -#: templates/contest/list.html:154 +#: templates/contest/list.html:84 msgid "rated" msgstr "" -#: templates/contest/list.html:202 +#: templates/contest/list.html:132 msgid "Spectate" msgstr "" -#: templates/contest/list.html:208 +#: templates/contest/list.html:138 msgid "Join" msgstr "Joindre" -#: templates/contest/list.html:220 -#, fuzzy -#| msgid "Leave contest" -msgid "Search contests..." -msgstr "Quitter le concours" - -#: templates/contest/list.html:229 -msgid "Search" -msgstr "" - -#: templates/contest/list.html:232 +#: templates/contest/list.html:148 msgid "Active Contests" msgstr "" -#: templates/contest/list.html:236 templates/contest/list.html:288 -#: templates/contest/list.html:327 templates/contest/list.html:365 +#: templates/contest/list.html:152 templates/contest/list.html:194 +#: templates/contest/list.html:232 templates/contest/list.html:270 msgid "Contest" msgstr "Concours" -#: templates/contest/list.html:275 +#: templates/contest/list.html:190 msgid "Ongoing Contests" msgstr "Concours en cours" -#: templates/contest/list.html:322 +#: templates/contest/list.html:227 msgid "Upcoming Contests" msgstr "Concours à venir" -#: templates/contest/list.html:350 +#: templates/contest/list.html:255 msgid "There are no scheduled contests at this time." msgstr "Il n'y a aucun concours au futur à ce moment." -#: templates/contest/list.html:356 +#: templates/contest/list.html:261 msgid "Past Contests" msgstr "Concours de la passé" @@ -3539,77 +3237,49 @@ msgstr "" msgid "Only the following organizations may access this contest:" msgstr "" -#: templates/contest/ranking-table.html:9 templates/problem/search-form.html:35 +#: templates/contest/ranking-table.html:7 msgid "Organization" msgstr "Organisation " -#: templates/contest/ranking-table.html:10 templates/user/users-table.html:13 -#, fuzzy -#| msgid "full name" -msgid "Full Name" -msgstr "nom complet" - -#: templates/contest/ranking-table.html:44 +#: templates/contest/ranking-table.html:30 msgid "Un-Disqualify" msgstr "" -#: templates/contest/ranking-table.html:47 +#: templates/contest/ranking-table.html:33 msgid "Disqualify" msgstr "" -#: templates/contest/ranking.html:187 +#: templates/contest/ranking.html:173 msgid "Are you sure you want to disqualify this participation?" msgstr "" -#: templates/contest/ranking.html:192 +#: templates/contest/ranking.html:178 msgid "Are you sure you want to un-disqualify this participation?" msgstr "" -#: templates/contest/ranking.html:463 +#: templates/contest/ranking.html:252 msgid "View user participation" msgstr "" -#: templates/contest/ranking.html:467 +#: templates/contest/ranking.html:256 msgid "Show organizations" msgstr "" -#: templates/contest/ranking.html:471 -#, fuzzy -#| msgid "full name" -msgid "Show full name" -msgstr "nom complet" - -#: templates/contest/ranking.html:474 -msgid "Show friends only" -msgstr "" - -#: templates/contest/ranking.html:477 -msgid "Total score only" -msgstr "" - -#: templates/contest/ranking.html:479 -msgid "Show virtual participation" -msgstr "" - -#: templates/contest/stats.html:51 +#: templates/contest/stats.html:38 msgid "Problem Status Distribution" msgstr "" -#: templates/contest/stats.html:56 +#: templates/contest/stats.html:43 #, fuzzy #| msgid "Problem name" msgid "Problem AC Rate" msgstr "Nom de la problème" -#: templates/contest/stats.html:62 -msgid "Problem Point Distribution" -msgstr "" - -#: templates/contest/stats.html:76 templates/stats/language.html:16 +#: templates/contest/stats.html:48 templates/stats/language.html:16 msgid "Submissions by Language" msgstr "" -#: templates/contest/stats.html:82 templates/stats/language.html:26 +#: templates/contest/stats.html:54 templates/stats/language.html:26 msgid "Language AC Rate" msgstr "" @@ -3618,7 +3288,6 @@ msgid "Source:" msgstr "" #: templates/newsletter/common.html:6 -#: templates/newsletter/newsletter_list.html:15 #: templates/newsletter/subscription_unsubscribe_activated.html:3 #: templates/newsletter/subscription_unsubscribe_activated.html:6 #: templates/newsletter/subscription_update_activated.html:3 @@ -3626,25 +3295,6 @@ msgstr "" msgid "Newsletter" msgstr "" -#: templates/newsletter/newsletter_list.html:2 -#: templates/newsletter/newsletter_list.html:3 -msgid "Newsletter list" -msgstr "" - -#: templates/newsletter/newsletter_list.html:6 -msgid "Subscribe to get the latest emails about upcoming contests and events." -msgstr "" - -#: templates/newsletter/newsletter_list.html:16 -msgid "Subscribe" -msgstr "" - -#: templates/newsletter/newsletter_list.html:30 -#, fuzzy -#| msgid "Description" -msgid "Update subscriptions" -msgstr "Description" - #: templates/newsletter/subscription_unsubscribe_activated.html:3 #: templates/newsletter/subscription_unsubscribe_activated.html:6 #: templates/newsletter/subscription_update_activated.html:3 @@ -3706,111 +3356,64 @@ msgid "" "follow in order to update your subscription." msgstr "" -#: templates/notification/list.html:7 -msgid "You have no notifications" -msgstr "" - -#: templates/notification/list.html:13 -msgid "Activity" -msgstr "" - #: templates/organization/edit.html:46 #: templates/organization/requests/pending.html:34 #: templates/ticket/edit-notes.html:4 msgid "Update" msgstr "" -#: templates/organization/home.html:41 +#: templates/organization/home.html:7 msgid "Are you sure you want to leave this organization?" msgstr "" -#: templates/organization/home.html:43 +#: templates/organization/home.html:9 msgid "You will have to rejoin to show up on the organization leaderboard." msgstr "" -#: templates/organization/home.html:45 +#: templates/organization/home.html:11 msgid "You will have to request membership in order to join again." msgstr "" -#: templates/organization/home.html:88 -msgid "Join organization" -msgstr "" - -#: templates/organization/home.html:92 -msgid "Request membership" -msgstr "" - -#: templates/organization/home.html:122 -#, fuzzy -#| msgid "Organization" -msgid "Organization news" -msgstr "Organisation " - -#: templates/organization/home.html:128 -#, fuzzy -#| msgid "There are no scheduled contests at this time." -msgid "There is no news at this time." -msgstr "Il n'y a aucun concours au futur à ce moment." - -#: templates/organization/home.html:137 -#, fuzzy -#| msgid "Contest" -msgid "Controls" -msgstr "Concours" - -#: templates/organization/home.html:142 -msgid "Edit organization" -msgstr "" - -#: templates/organization/home.html:148 -msgid "View requests" -msgstr "" - -#: templates/organization/home.html:161 -msgid "Admin organization" -msgstr "" - -#: templates/organization/home.html:167 -msgid "View members" -msgstr "" - -#: templates/organization/home.html:174 +#: templates/organization/home.html:24 msgid "Leave organization" msgstr "" -#: templates/organization/home.html:183 -#, fuzzy -#| msgid "Leave contest" -msgid "New private contests" -msgstr "Quitter le concours" +#: templates/organization/home.html:29 +msgid "Join organization" +msgstr "" -#: templates/organization/home.html:193 templates/organization/home.html:208 -#, fuzzy -#| msgid "View as PDF" -msgid "View all" -msgstr "Voir en PDF" +#: templates/organization/home.html:33 +msgid "Request membership" +msgstr "" -#: templates/organization/home.html:199 -#, fuzzy -#| msgid "New problems" -msgid "New private problems" -msgstr "Nouveaux problèmes" +#: templates/organization/home.html:39 +msgid "Edit organization" +msgstr "" -#: templates/organization/list.html:40 -#, fuzzy -#| msgid "organizations" -msgid "Show my organizations only" -msgstr "organisations" +#: templates/organization/home.html:43 +msgid "View requests" +msgstr "" -#: templates/organization/list.html:47 templates/status/language-list.html:34 -#: templates/user/import/table_csv.html:6 +#: templates/organization/home.html:50 +msgid "Admin organization" +msgstr "" + +#: templates/organization/home.html:55 +msgid "View members" +msgstr "" + +#: templates/organization/list.html:23 templates/status/language-list.html:34 msgid "Name" msgstr "" -#: templates/organization/list.html:48 +#: templates/organization/list.html:24 msgid "Members" msgstr "Membres" +#: templates/organization/new.html:10 templates/ticket/new.html:38 +msgid "Create" +msgstr "Créer" + #: templates/organization/requests/detail.html:13 msgid "User:" msgstr "" @@ -3843,7 +3446,7 @@ msgid "There are no requests to approve." msgstr "" #: templates/organization/requests/pending.html:17 -#: templates/problem/data.html:432 +#: templates/problem/data.html:452 msgid "Delete?" msgstr "Supprimer ?" @@ -3879,37 +3482,37 @@ msgstr "" msgid "Enter a new code for the cloned problem:" msgstr "" -#: templates/problem/data.html:119 +#: templates/problem/data.html:108 #, fuzzy #| msgid "Information" msgid "Instruction" msgstr "Information" -#: templates/problem/data.html:390 +#: templates/problem/data.html:410 msgid "View YAML" msgstr "" -#: templates/problem/data.html:421 templates/problem/data.html:472 +#: templates/problem/data.html:441 templates/problem/data.html:491 msgid "Apply!" msgstr "" -#: templates/problem/data.html:426 +#: templates/problem/data.html:446 msgid "Type" msgstr "Genre" -#: templates/problem/data.html:427 +#: templates/problem/data.html:447 msgid "Input file" msgstr "" -#: templates/problem/data.html:428 +#: templates/problem/data.html:448 msgid "Output file" msgstr "" -#: templates/problem/data.html:430 +#: templates/problem/data.html:450 msgid "Pretest?" msgstr "" -#: templates/problem/data.html:473 +#: templates/problem/data.html:492 msgid "Add new case" msgstr "" @@ -3921,34 +3524,28 @@ msgid "" "problem yourself is a bannable offence." msgstr "" -#: templates/problem/list.html:66 +#: templates/problem/list.html:62 msgid "Filter by type..." msgstr "" -#: templates/problem/list.html:193 +#: templates/problem/list.html:185 msgid "Hot problems" msgstr "" -#: templates/problem/list.html:218 templates/problem/list.html:240 -#: templates/problem/search-form.html:45 templates/user/user-problems.html:57 +#: templates/problem/list.html:207 templates/problem/list.html:224 +#: templates/problem/search-form.html:30 templates/user/user-problems.html:57 msgid "Category" msgstr "" -#: templates/problem/list.html:220 templates/problem/list.html:244 +#: templates/problem/list.html:209 templates/problem/list.html:228 msgid "Types" msgstr "" -#: templates/problem/list.html:251 +#: templates/problem/list.html:235 #, python-format msgid "AC %%" msgstr "" -#: templates/problem/list.html:342 -#, fuzzy -#| msgid "Best solutions for %s" -msgid "Add clarifications" -msgstr "Les meilleures solutions pour %s" - #: templates/problem/manage_submission.html:55 msgid "Leave empty to not filter by language" msgstr "" @@ -3957,205 +3554,152 @@ msgstr "" msgid "Leave empty to not filter by result" msgstr "" -#: templates/problem/manage_submission.html:80 +#: templates/problem/manage_submission.html:79 msgid "Need valid values for both start and end IDs." msgstr "" -#: templates/problem/manage_submission.html:83 +#: templates/problem/manage_submission.html:82 msgid "End ID must be after start ID." msgstr "" +#: templates/problem/manage_submission.html:90 +#, python-brace-format +msgid "" +"You are about to rejudge {count} submissions. Are you sure you want to do " +"this?" +msgstr "" + #: templates/problem/manage_submission.html:96 -#, python-brace-format msgid "" -"You are about to {action} {count} submissions. Are you sure you want to do " -"this?" +"You are about to rejudge a few submissions. Are you sure you want to do this?" msgstr "" -#: templates/problem/manage_submission.html:103 -#, python-brace-format -msgid "" -"You are about to {action} a few submissions. Are you sure you want to do " -"this?" +#: templates/problem/manage_submission.html:115 +msgid "Rejudge Submissions" msgstr "" -#: templates/problem/manage_submission.html:127 -#: templates/submission/list.html:309 -msgid "Filter submissions" -msgstr "" - -#: templates/problem/manage_submission.html:132 +#: templates/problem/manage_submission.html:120 msgid "Filter by ID:" msgstr "" -#: templates/problem/manage_submission.html:135 +#: templates/problem/manage_submission.html:123 msgid "Starting ID:" msgstr "" -#: templates/problem/manage_submission.html:139 +#: templates/problem/manage_submission.html:127 msgid "Ending ID:" msgstr "" -#: templates/problem/manage_submission.html:143 +#: templates/problem/manage_submission.html:131 msgid "This range includes both endpoints." msgstr "" -#: templates/problem/manage_submission.html:146 +#: templates/problem/manage_submission.html:134 msgid "Filter by language:" msgstr "" -#: templates/problem/manage_submission.html:154 +#: templates/problem/manage_submission.html:142 msgid "Filter by result:" msgstr "" -#: templates/problem/manage_submission.html:164 -msgid "Action" -msgstr "" - -#: templates/problem/manage_submission.html:166 +#: templates/problem/manage_submission.html:150 msgid "Rejudge selected submissions" msgstr "" -#: templates/problem/manage_submission.html:171 -#, fuzzy -#| msgid "View submissions" -msgid "Download selected submissions" -msgstr "Voir les soumissions" - -#: templates/problem/manage_submission.html:177 -#, python-format -msgid "Are you sure you want to rescore %(count)d submissions?" +#: templates/problem/manage_submission.html:157 +msgid "Rescore Everything" msgstr "" -#: templates/problem/manage_submission.html:178 +#: templates/problem/manage_submission.html:163 msgid "Rescore all submissions" msgstr "" -#: templates/problem/problem.html:132 +#: templates/problem/problem.html:91 msgid "View as PDF" msgstr "Voir en PDF" -#: templates/problem/problem.html:141 templates/problem/problem.html:151 -#: templates/problem/problem.html:156 +#: templates/problem/problem.html:101 templates/problem/problem.html:111 +#: templates/problem/problem.html:116 msgid "Submit solution" msgstr "" -#: templates/problem/problem.html:144 -#, python-format -msgid "%(counter)s submission left" -msgid_plural "%(counter)s submissions left" -msgstr[0] "" -msgstr[1] "" - -#: templates/problem/problem.html:152 +#: templates/problem/problem.html:112 msgid "0 submissions left" msgstr "" -#: templates/problem/problem.html:164 +#: templates/problem/problem.html:124 msgid "My submissions" msgstr "" -#: templates/problem/problem.html:168 +#: templates/problem/problem.html:128 msgid "Best submissions" msgstr "" -#: templates/problem/problem.html:172 +#: templates/problem/problem.html:132 msgid "Read editorial" msgstr "" -#: templates/problem/problem.html:177 +#: templates/problem/problem.html:137 msgid "Manage tickets" msgstr "" -#: templates/problem/problem.html:181 +#: templates/problem/problem.html:141 msgid "Edit problem" msgstr "" -#: templates/problem/problem.html:183 +#: templates/problem/problem.html:143 msgid "Edit test data" msgstr "" -#: templates/problem/problem.html:188 +#: templates/problem/problem.html:148 msgid "My tickets" msgstr "" -#: templates/problem/problem.html:196 +#: templates/problem/problem.html:156 msgid "Manage submissions" msgstr "" -#: templates/problem/problem.html:202 +#: templates/problem/problem.html:162 msgid "Clone problem" msgstr "" -#: templates/problem/problem.html:209 +#: templates/problem/problem.html:169 msgid "Points:" msgstr "Points :" -#: templates/problem/problem.html:212 templates/problem/problem.html:214 +#: templates/problem/problem.html:172 templates/problem/problem.html:174 msgid "(partial)" msgstr "" -#: templates/problem/problem.html:219 +#: templates/problem/problem.html:179 msgid "Time limit:" msgstr "" -#: templates/problem/problem.html:231 +#: templates/problem/problem.html:191 msgid "Memory limit:" msgstr "" -#: templates/problem/problem.html:250 -#, fuzzy -#| msgid "Authors" -msgid "Author:" -msgid_plural "Authors:" -msgstr[0] "Auteurs" -msgstr[1] "Auteurs" - -#: templates/problem/problem.html:265 -#, fuzzy -#| msgid "problem type" -msgid "Problem type" -msgid_plural "Problem types" -msgstr[0] "type de problème" -msgstr[1] "type de problème" - -#: templates/problem/problem.html:278 +#: templates/problem/problem.html:238 msgid "Allowed languages" msgstr "Languages autorisés" -#: templates/problem/problem.html:286 -#, python-format -msgid "No %(lang)s judge online" -msgstr "" - -#: templates/problem/problem.html:297 -msgid "Judge:" -msgid_plural "Judges:" -msgstr[0] "" -msgstr[1] "" - -#: templates/problem/problem.html:314 +#: templates/problem/problem.html:274 msgid "none available" msgstr "" -#: templates/problem/problem.html:326 -#, python-format -msgid "This problem has %(length)s clarification(s)" -msgstr "" - -#: templates/problem/problem.html:350 +#: templates/problem/problem.html:299 msgid "Request clarification" msgstr "" -#: templates/problem/problem.html:352 +#: templates/problem/problem.html:301 msgid "Report an issue" msgstr "" -#: templates/problem/raw.html:64 +#: templates/problem/raw.html:62 msgid "Time Limit:" msgstr "" -#: templates/problem/raw.html:73 +#: templates/problem/raw.html:71 msgid "Memory Limit:" msgstr "" @@ -4179,73 +3723,39 @@ msgstr "" msgid "Show problem types" msgstr "" -#: templates/problem/search-form.html:32 -msgid "Show editorial" -msgstr "" - -#: templates/problem/search-form.html:48 templates/problem/search-form.html:50 -#: templates/submission/submission-list-tabs.html:4 +#: templates/problem/search-form.html:33 templates/problem/search-form.html:35 msgid "All" msgstr "" -#: templates/problem/search-form.html:62 +#: templates/problem/search-form.html:46 msgid "Problem types" msgstr "" -#: templates/problem/search-form.html:73 +#: templates/problem/search-form.html:57 msgid "Point range" msgstr "" -#: templates/problem/search-form.html:79 templates/submission/list.html:331 +#: templates/problem/search-form.html:63 templates/submission/list.html:331 #: templates/ticket/list.html:248 msgid "Go" msgstr "" -#: templates/problem/search-form.html:80 +#: templates/problem/search-form.html:64 msgid "Random" msgstr "" -#: templates/problem/submit.html:117 -msgid "Your source code must contain at most 65536 characters." -msgstr "" - -#: templates/problem/submit.html:204 -#, python-format -msgid "" -"Warning! Your default language, %(default_language)s, is " -"unavailable for this problem and has been deselected." -msgstr "" - -#: templates/problem/submit.html:215 -#, python-format -msgid "" -"\n" -" You have %(left)s submission left\n" -" " -msgid_plural "" -"\n" -" You have %(left)s submissions left\n" -" " -msgstr[0] "" -msgstr[1] "" - -#: templates/problem/submit.html:224 +#: templates/problem/submit.html:212 msgid "You have 0 submissions left" msgstr "" -#: templates/problem/submit.html:258 +#: templates/problem/submit.html:250 msgid "No judge is available for this problem." msgstr "" -#: templates/problem/submit.html:262 +#: templates/problem/submit.html:252 msgid "Submit!" msgstr "" -#: templates/registration/activate.html:3 -#, python-format -msgid "%(key)s is an invalid activation key." -msgstr "" - #: templates/registration/activation_complete.html:3 msgid "Your account has been successfully activated." msgstr "" @@ -4303,13 +3813,6 @@ msgid "" "you registered with, and check your spam folder." msgstr "" -#: templates/registration/password_reset_email.txt:1 -#, python-format -msgid "" -"You're receiving this email because you requested a password reset for your " -"user account at %(site_name)s." -msgstr "" - #: templates/registration/password_reset_email.txt:3 msgid "Please go to the following page and choose a new password:" msgstr "" @@ -4322,16 +3825,6 @@ msgstr "" msgid "Thanks for using our site!" msgstr "" -#: templates/registration/password_reset_email.txt:11 -#, python-format -msgid "The %(site_name)s team" -msgstr "" - -#: templates/registration/password_reset_subject.txt:1 -#, python-format -msgid "Password reset on %(site_name)s" -msgstr "" - #: templates/registration/profile_creation.html:36 #: templates/registration/username_select.html:7 msgid "Continue >" @@ -4368,20 +3861,19 @@ msgstr "" msgid "Affiliated organizations" msgstr "" -#: templates/registration/registration_form.html:195 -#: templates/user/edit-profile.html:128 +#: templates/registration/registration_form.html:192 msgid "Notify me about upcoming contests" msgstr "" -#: templates/registration/registration_form.html:209 +#: templates/registration/registration_form.html:206 msgid "By registering, you agree to our" msgstr "" -#: templates/registration/registration_form.html:210 +#: templates/registration/registration_form.html:207 msgid "Terms & Conditions" msgstr "" -#: templates/registration/registration_form.html:213 +#: templates/registration/registration_form.html:210 msgid "Register!" msgstr "" @@ -4391,11 +3883,6 @@ msgstr "" msgid "Enter the 6-digit code generated by your app:" msgstr "" -#: templates/registration/totp_auth.html:41 -#, python-format -msgid "If you lost your authentication device, please contact us at %(email)s." -msgstr "" - #: templates/registration/totp_disable.html:38 msgid "" "To protect your account, you must first authenticate before you can disable " @@ -4414,6 +3901,10 @@ msgstr "" msgid "Or enter this code manually:" msgstr "" +#: templates/stats/base.html:9 templates/submission/list.html:339 +msgid "Statistics" +msgstr "" + #: templates/stats/language.html:11 msgid "Submission Statistics" msgstr "" @@ -4439,7 +3930,6 @@ msgid "Ping" msgstr "" #: templates/status/judge-status-table.html:8 -#: templates/user/import/index.html:104 msgid "Load" msgstr "Charge" @@ -4455,7 +3945,6 @@ msgid "There are no judges available at this time." msgstr "" #: templates/status/language-list.html:33 templates/ticket/list.html:261 -#: templates/user/import/table_csv.html:3 msgid "ID" msgstr "" @@ -4463,22 +3952,6 @@ msgstr "" msgid "Runtime Info" msgstr "" -#: templates/status/status-tabs.html:4 -msgid "Judges" -msgstr "" - -#: templates/status/status-tabs.html:6 -msgid "Version Matrix" -msgstr "" - -#: templates/submission/internal-error-message.html:3 -#, python-format -msgid "" -"An internal error occurred while grading, and the %(SITE_NAME)s " -"administrators have been notified.
In the meantime, try resubmitting in " -"a few seconds." -msgstr "" - #: templates/submission/internal-error-message.html:8 msgid "An internal error occurred while grading." msgstr "" @@ -4495,6 +3968,10 @@ msgstr "" msgid "Filter by language..." msgstr "" +#: templates/submission/list.html:309 +msgid "Filter submissions" +msgstr "" + #: templates/submission/list.html:345 msgid "Total:" msgstr "" @@ -4551,74 +4028,73 @@ msgstr "" msgid "Execution Results" msgstr "" -#: templates/submission/status-testcases.html:34 +#: templates/submission/status-testcases.html:31 +msgid "Batch " +msgstr "" + +#: templates/submission/status-testcases.html:43 msgid "Overall: " msgstr "" -#: templates/submission/status-testcases.html:48 +#: templates/submission/status-testcases.html:57 #, fuzzy #| msgid "Points:" msgid "Point: " msgstr "Points :" -#: templates/submission/status-testcases.html:53 +#: templates/submission/status-testcases.html:62 #, fuzzy #| msgid "Time:" msgid "Time: " msgstr "Temps:" -#: templates/submission/status-testcases.html:62 +#: templates/submission/status-testcases.html:71 #, fuzzy #| msgid "Memory" msgid "Memory: " msgstr "RAM" -#: templates/submission/status-testcases.html:73 -msgid "Batch " +#: templates/submission/status-testcases.html:84 +msgid "Case" msgstr "" -#: templates/submission/status-testcases.html:84 -#: templates/submission/status-testcases.html:113 +#: templates/submission/status-testcases.html:86 +msgid "Pretest" +msgstr "" + +#: templates/submission/status-testcases.html:88 +msgid "Test case" +msgstr "Cas de test" + +#: templates/submission/status-testcases.html:99 #, fuzzy #| msgid "Points" msgid "Point" msgstr "Points " -#: templates/submission/status-testcases.html:99 -msgid "Case" -msgstr "" - -#: templates/submission/status-testcases.html:101 -msgid "Pretest" -msgstr "" - -#: templates/submission/status-testcases.html:103 -msgid "Test case" -msgstr "Cas de test" - -#: templates/submission/status-testcases.html:141 +#: templates/submission/status-testcases.html:121 msgid "Input:" msgstr "" -#: templates/submission/status-testcases.html:145 +#: templates/submission/status-testcases.html:125 msgid "Output:" msgstr "" -#: templates/submission/status-testcases.html:149 +#: templates/submission/status-testcases.html:129 #, fuzzy #| msgid "Wrong Answer" msgid "Answer:" msgstr "Mauvaise réponse" -#: templates/submission/status-testcases.html:154 +#: templates/submission/status-testcases.html:134 msgid "Judge feedback:" msgstr "" -#: templates/submission/status-testcases.html:175 +#: templates/submission/status-testcases.html:157 msgid "Passing pretests does not guarantee a full score on system tests." msgstr "" -#: templates/submission/status-testcases.html:178 +#: templates/submission/status-testcases.html:160 msgid "Submission aborted!" msgstr "Soumission abandonnée !" @@ -4630,24 +4106,11 @@ msgstr "" msgid "Abort" msgstr "Interrompre" -#: templates/submission/submission-list-tabs.html:6 -msgid "Mine" -msgstr "" - -#: templates/submission/submission-list-tabs.html:9 -msgid "Best" -msgstr "" - -#: templates/submission/submission-list-tabs.html:12 -#, python-format -msgid "%(user)s's" -msgstr "" - -#: templates/ticket/list.html:135 templates/ticket/ticket.html:273 +#: templates/ticket/list.html:135 templates/ticket/ticket.html:257 msgid "Reopened: " msgstr "" -#: templates/ticket/list.html:138 templates/ticket/ticket.html:274 +#: templates/ticket/list.html:138 templates/ticket/ticket.html:258 msgid "Closed: " msgstr "" @@ -4671,7 +4134,7 @@ msgstr "" msgid "Title" msgstr "" -#: templates/ticket/list.html:264 templates/ticket/ticket.html:369 +#: templates/ticket/list.html:264 templates/ticket/ticket.html:328 msgid "Assignees" msgstr "" @@ -4686,37 +4149,33 @@ msgid "" "a problem, ask in the comments instead." msgstr "" -#: templates/ticket/ticket.html:355 -msgid "Post" -msgstr "" - -#: templates/ticket/ticket.html:363 +#: templates/ticket/ticket.html:322 msgid "Associated object" msgstr "" -#: templates/ticket/ticket.html:374 +#: templates/ticket/ticket.html:333 msgid "No one is assigned." msgstr "" -#: templates/ticket/ticket.html:380 +#: templates/ticket/ticket.html:339 msgid "Close ticket" msgstr "" -#: templates/ticket/ticket.html:382 +#: templates/ticket/ticket.html:341 msgid "Reopen ticket" msgstr "" -#: templates/ticket/ticket.html:386 +#: templates/ticket/ticket.html:345 msgid "Assignee notes" msgstr "" -#: templates/ticket/ticket.html:393 templates/widgets/select_all.html:4 +#: templates/ticket/ticket.html:352 templates/widgets/select_all.html:4 msgid "Nothing here." msgstr "Il n'y a rien ici." -#: templates/user/base-users-table.html:3 -msgid "Rank" -msgstr "Classement" +#: templates/ticket/ticket.html:385 +msgid "Post" +msgstr "" #: templates/user/base-users.html:14 templates/user/base-users.html:69 msgid "Search by handle..." @@ -4762,197 +4221,50 @@ msgstr "" msgid "Update profile" msgstr "" -#: templates/user/import/index.html:31 -msgid "Upload CSV only" -msgstr "" - -#: templates/user/import/index.html:100 -#, fuzzy -#| msgid "user profile" -msgid "User File" -msgstr "profil utilisateur" - -#: templates/user/import/index.html:102 -msgid "Sample" -msgstr "" - -#: templates/user/import/index.html:105 templates/user/user-list-tabs.html:8 -msgid "Import" -msgstr "" - -#: templates/user/import/table_csv.html:7 -msgid "School" -msgstr "" - -#: templates/user/pp-row.html:22 -#, python-format -msgid "" -"\n" -" weighted %(weight)s%%\n" -" " -msgstr "" - -#: templates/user/pp-row.html:27 -#, python-format -msgid "%(pp).1fpp" -msgstr "" - -#: templates/user/pp-row.html:29 -#, python-format -msgid "%(pp).0fpp" -msgstr "" - -#: templates/user/user-about.html:23 -#, fuzzy, python-format -#| msgid "Hide problems I've solved" -msgid "%(counter)s problem solved" -msgid_plural "%(counter)s problems solved" -msgstr[0] "Cacher les problèmes que j'ai déjà résolus" -msgstr[1] "Cacher les problèmes que j'ai déjà résolus" - -#: templates/user/user-about.html:35 -#, fuzzy -#| msgid "Total points:" -msgid "Total points" -msgstr "Total des points :" - -#: templates/user/user-about.html:45 -#, fuzzy -#| msgid "Rank by points:" -msgid "Rank by rating" -msgstr "Classement par points :" - -#: templates/user/user-about.html:52 -#, fuzzy -#| msgid "Rank by points:" -msgid "Rank by points" -msgstr "Classement par points :" - -#: templates/user/user-about.html:64 +#: templates/user/user-about.html:14 msgid "From" msgstr "" -#: templates/user/user-about.html:75 +#: templates/user/user-about.html:25 msgid "Admin Notes" msgstr "" -#: templates/user/user-about.html:90 +#: templates/user/user-about.html:40 msgid "You have not shared any information." msgstr "" -#: templates/user/user-about.html:92 +#: templates/user/user-about.html:42 msgid "This user has not shared any information." msgstr "" -#: templates/user/user-about.html:101 -msgid "Awards" +#: templates/user/user-base.html:50 +msgid "Rank by points:" +msgstr "Classement par points :" + +#: templates/user/user-base.html:53 +msgid "Total points:" +msgstr "Total des points :" + +#: templates/user/user-base.html:68 +msgid "Rank by rating:" msgstr "" -#: templates/user/user-about.html:112 -#, python-format -msgid "%(label)s (%(date)s)" -msgstr "" +#: templates/user/user-base.html:70 +msgid "Rating:" +msgstr "Classement :" -#: templates/user/user-about.html:130 -#, fuzzy -#| msgid "Monday" -msgid "Mon" -msgstr "Lundi" - -#: templates/user/user-about.html:135 -#, fuzzy -#| msgid "Tuesday" -msgid "Tues" -msgstr "Mardi" - -#: templates/user/user-about.html:140 -msgid "Wed" -msgstr "" - -#: templates/user/user-about.html:145 -#, fuzzy -#| msgid "Thursday" -msgid "Thurs" -msgstr "Jeudi" - -#: templates/user/user-about.html:150 -#, fuzzy -#| msgid "Friday" -msgid "Fri" -msgstr "Vendredi" - -#: templates/user/user-about.html:155 -#, fuzzy -#| msgid "State" -msgid "Sat" -msgstr "Etat" - -#: templates/user/user-about.html:160 -#, fuzzy -#| msgid "Sunday" -msgid "Sun" -msgstr "Dimanche" - -#: templates/user/user-about.html:169 -msgid "Less" -msgstr "" - -#: templates/user/user-about.html:175 -msgid "More" -msgstr "" - -#: templates/user/user-about.html:184 -#, fuzzy -#| msgid "History" -msgid "Rating History" -msgstr "Histoire" - -#: templates/user/user-about.html:255 -msgid "past year" -msgstr "" - -#: templates/user/user-about.html:272 -#, fuzzy -#| msgid "submissions" -msgid "total submission(s)" -msgstr "soumissions" - -#: templates/user/user-about.html:276 -#, fuzzy -#| msgid "submission" -msgid "submissions in the last year" -msgstr "soumission" - -#: templates/user/user-base.html:101 -msgid "Unfollow" -msgstr "" - -#: templates/user/user-base.html:104 -msgid "Follow" -msgstr "" - -#: templates/user/user-base.html:120 -#, fuzzy -#| msgid "Contests" -msgid "Contests written" -msgstr "Concours" - -#: templates/user/user-base.html:124 +#: templates/user/user-base.html:71 msgid "Volatility:" msgstr "" -#: templates/user/user-base.html:128 +#: templates/user/user-base.html:72 msgid "Min. rating:" msgstr "" -#: templates/user/user-base.html:132 +#: templates/user/user-base.html:73 msgid "Max rating:" msgstr "" -#: templates/user/user-list-tabs.html:5 -msgid "Friends" -msgstr "" - #: templates/user/user-problems.html:35 msgid "Points Breakdown" msgstr "" @@ -4973,46 +4285,31 @@ msgstr "" msgid "Hide problems I've solved" msgstr "Cacher les problèmes que j'ai déjà résolus" -#: templates/user/user-problems.html:93 -#, python-format -msgid "%(points).1f points" -msgstr "" - #: templates/user/user-problems.html:99 msgid "Score" msgstr "" -#: templates/user/user-problems.html:110 -#, python-format -msgid "%(points)s / %(total)s" -msgstr "" - -#: templates/user/user-tabs.html:7 -msgid "Impersonate" -msgstr "" - -#: templates/user/user-tabs.html:13 -msgid "Admin User" -msgstr "Administrateurs" - -#: templates/user/user-tabs.html:16 -msgid "Admin Profile" -msgstr "Profil d'Admin" - #: templates/widgets/select_all.html:8 msgid "Check all" msgstr "Cocher tout" -#~ msgid "Rating:" -#~ msgstr "Classement :" +#~ msgid "Hello, %(username)s." +#~ msgstr "Bonjour, %(username)s." -#, fuzzy -#~| msgid "Admin" -#~ msgid "Admins" -#~ msgstr "Admin" +#~ msgid "Contest is over." +#~ msgstr "Concours est terminé." #~ msgid "Your output (clipped)" #~ msgstr "Votre retour (abrégé)" #~ msgid "Final score:" #~ msgstr "Score final :" + +#~ msgid "Rank" +#~ msgstr "Classement" + +#~ msgid "Admin User" +#~ msgstr "Administrateurs" + +#~ msgid "Admin Profile" +#~ msgstr "Profil d'Admin" diff --git a/locale/fr/LC_MESSAGES/djangojs.po b/locale/fr/LC_MESSAGES/djangojs.po index 697e5ac..c41af44 100644 --- a/locale/fr/LC_MESSAGES/djangojs.po +++ b/locale/fr/LC_MESSAGES/djangojs.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: dmoj\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-07-20 23:30+0700\n" +"POT-Creation-Date: 2019-10-01 23:12+0000\n" "PO-Revision-Date: 2019-11-11 22:05\n" "Last-Translator: Icyene\n" "Language-Team: French\n" @@ -27,3 +27,4 @@ msgstr[1] "%d jours %h:%m:%s" msgctxt "time format without day" msgid "%h:%m:%s" msgstr "%h:%m:%s" + diff --git a/locale/hr/LC_MESSAGES/django.po b/locale/hr/LC_MESSAGES/django.po index c55f0a3..2f333aa 100644 --- a/locale/hr/LC_MESSAGES/django.po +++ b/locale/hr/LC_MESSAGES/django.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: dmoj\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-10-25 05:59+0700\n" +"POT-Creation-Date: 2020-04-10 01:26-0500\n" "PO-Revision-Date: 2019-11-11 22:05\n" "Last-Translator: Icyene\n" "Language-Team: Croatian\n" @@ -17,93 +17,93 @@ msgstr "" "X-Crowdin-Language: hr\n" "X-Crowdin-File: django.po\n" -#: chat_box/models.py:16 judge/admin/interface.py:110 -#: judge/models/contest.py:403 judge/models/contest.py:528 -#: judge/models/profile.py:211 +#: chat_box/models.py:15 judge/admin/interface.py:107 +#: judge/models/contest.py:257 judge/models/contest.py:381 +#: judge/models/profile.py:191 msgid "user" msgstr "korisnik" -#: chat_box/models.py:17 judge/models/comment.py:43 judge/models/comment.py:191 +#: chat_box/models.py:16 judge/models/comment.py:42 msgid "posted time" msgstr "vrijeme objave" -#: chat_box/models.py:18 judge/models/comment.py:47 +#: chat_box/models.py:17 judge/models/comment.py:46 msgid "body of comment" msgstr "tekst komentara" -#: chat_box/views.py:29 templates/chat/chat.html:4 +#: chat_box/views.py:29 msgid "Chat Box" msgstr "" -#: dmoj/settings.py:355 +#: dmoj/settings.py:349 msgid "German" msgstr "Njemački" -#: dmoj/settings.py:356 +#: dmoj/settings.py:350 msgid "English" msgstr "Engleski" -#: dmoj/settings.py:357 +#: dmoj/settings.py:351 msgid "Spanish" msgstr "Španjolski" -#: dmoj/settings.py:358 +#: dmoj/settings.py:352 msgid "French" msgstr "Francuski" -#: dmoj/settings.py:359 +#: dmoj/settings.py:353 msgid "Croatian" msgstr "Hrvatski" -#: dmoj/settings.py:360 +#: dmoj/settings.py:354 msgid "Hungarian" msgstr "Mađarski" -#: dmoj/settings.py:361 +#: dmoj/settings.py:355 msgid "Japanese" msgstr "" -#: dmoj/settings.py:362 +#: dmoj/settings.py:356 msgid "Korean" msgstr "Korejski" -#: dmoj/settings.py:363 +#: dmoj/settings.py:357 msgid "Brazilian Portuguese" msgstr "" -#: dmoj/settings.py:364 +#: dmoj/settings.py:358 msgid "Romanian" msgstr "Rumunjski" -#: dmoj/settings.py:365 +#: dmoj/settings.py:359 msgid "Russian" msgstr "Ruski" -#: dmoj/settings.py:366 +#: dmoj/settings.py:360 msgid "Serbian (Latin)" msgstr "Srpski (Latinica)" -#: dmoj/settings.py:367 +#: dmoj/settings.py:361 msgid "Turkish" msgstr "Turski" -#: dmoj/settings.py:368 +#: dmoj/settings.py:362 msgid "Vietnamese" msgstr "Vijetnamski" -#: dmoj/settings.py:369 +#: dmoj/settings.py:363 msgid "Simplified Chinese" msgstr "Pojednostavljeni kineski" -#: dmoj/settings.py:370 +#: dmoj/settings.py:364 msgid "Traditional Chinese" msgstr "" -#: dmoj/urls.py:58 +#: dmoj/urls.py:57 msgid "Login" msgstr "Prijava" -#: dmoj/urls.py:106 templates/base.html:193 +#: dmoj/urls.py:105 templates/base.html:190 msgid "Home" msgstr "Početna" @@ -135,48 +135,46 @@ msgstr "Otkrij komentare" msgid "Associated page" msgstr "Povezana stranica" -#: judge/admin/contest.py:30 +#: judge/admin/contest.py:28 msgid "Included contests" msgstr "Uključena natjecanja" -#: judge/admin/contest.py:66 templates/contest/clarification.html:42 -#: templates/contest/contest.html:83 templates/contest/moss.html:43 -#: templates/problem/list.html:214 templates/problem/list.html:232 -#: templates/problem/list.html:350 templates/user/user-problems.html:56 +#: judge/admin/contest.py:64 templates/contest/contest.html:83 +#: templates/contest/moss.html:43 templates/problem/list.html:206 +#: templates/problem/list.html:221 templates/user/user-problems.html:56 #: templates/user/user-problems.html:98 msgid "Problem" msgstr "Zadatak" -#: judge/admin/contest.py:119 +#: judge/admin/contest.py:112 msgid "Settings" msgstr "" -#: judge/admin/contest.py:121 +#: judge/admin/contest.py:114 msgid "Scheduling" msgstr "Raspoređivanje" -#: judge/admin/contest.py:122 templates/organization/home.html:107 +#: judge/admin/contest.py:115 msgid "Details" msgstr "Pojedinosti" -#: judge/admin/contest.py:123 +#: judge/admin/contest.py:116 msgid "Format" msgstr "" -#: judge/admin/contest.py:124 templates/contest/ranking-table.html:7 -#: templates/user/user-about.html:15 templates/user/user-about.html:45 +#: judge/admin/contest.py:117 templates/contest/ranking-table.html:5 msgid "Rating" msgstr "Bodovi" -#: judge/admin/contest.py:125 +#: judge/admin/contest.py:118 msgid "Access" msgstr "" -#: judge/admin/contest.py:127 judge/admin/problem.py:131 +#: judge/admin/contest.py:120 judge/admin/problem.py:131 msgid "Justice" msgstr "Pravda" -#: judge/admin/contest.py:207 +#: judge/admin/contest.py:158 #, python-format msgid "%d contest successfully marked as visible." msgid_plural "%d contests successfully marked as visible." @@ -184,11 +182,11 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: judge/admin/contest.py:210 +#: judge/admin/contest.py:161 msgid "Mark contests as visible" msgstr "" -#: judge/admin/contest.py:216 +#: judge/admin/contest.py:165 #, python-format msgid "%d contest successfully marked as hidden." msgid_plural "%d contests successfully marked as hidden." @@ -196,11 +194,11 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: judge/admin/contest.py:219 +#: judge/admin/contest.py:168 msgid "Mark contests as hidden" msgstr "" -#: judge/admin/contest.py:233 judge/admin/submission.py:164 +#: judge/admin/contest.py:182 judge/admin/submission.py:164 #, python-format msgid "%d submission was successfully scheduled for rejudging." msgid_plural "%d submissions were successfully scheduled for rejudging." @@ -208,7 +206,7 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: judge/admin/contest.py:308 +#: judge/admin/contest.py:256 #, python-format msgid "%d participation recalculated." msgid_plural "%d participations recalculated." @@ -216,15 +214,15 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: judge/admin/contest.py:311 +#: judge/admin/contest.py:259 msgid "Recalculate results" msgstr "" -#: judge/admin/contest.py:315 judge/admin/organization.py:65 +#: judge/admin/contest.py:263 judge/admin/organization.py:65 msgid "username" msgstr "korisničko ime" -#: judge/admin/contest.py:320 templates/base.html:277 +#: judge/admin/contest.py:268 templates/base.html:260 msgid "virtual" msgstr "virtualno" @@ -232,15 +230,15 @@ msgstr "virtualno" msgid "link path" msgstr "putanja veze" -#: judge/admin/interface.py:65 +#: judge/admin/interface.py:62 msgid "Content" msgstr "Sadržaj" -#: judge/admin/interface.py:66 +#: judge/admin/interface.py:63 msgid "Summary" msgstr "Sažetak" -#: judge/admin/interface.py:151 +#: judge/admin/interface.py:148 msgid "object" msgstr "" @@ -262,9 +260,8 @@ msgid "Taxonomy" msgstr "Taksonomija" #: judge/admin/problem.py:128 templates/contest/contest.html:84 -#: templates/problem/data.html:429 templates/problem/list.html:222 -#: templates/problem/list.html:248 templates/user/base-users-table.html:10 -#: templates/user/user-about.html:36 templates/user/user-about.html:52 +#: templates/problem/data.html:449 templates/problem/list.html:211 +#: templates/problem/list.html:232 templates/user/base-users-table.html:10 #: templates/user/user-problems.html:58 msgid "Points" msgstr "Bodovi" @@ -315,7 +312,6 @@ msgid "timezone" msgstr "" #: judge/admin/profile.py:86 judge/admin/submission.py:211 -#: templates/notification/list.html:12 #: templates/organization/requests/log.html:9 #: templates/organization/requests/pending.html:12 #: templates/ticket/list.html:263 @@ -323,7 +319,6 @@ msgid "User" msgstr "Korisnik" #: judge/admin/profile.py:91 templates/registration/registration_form.html:145 -#: templates/user/import/table_csv.html:8 msgid "Email" msgstr "E-mail" @@ -357,7 +352,7 @@ msgstr "Nedozvoljeni zadaci" msgid "These problems are NOT allowed to be submitted in this language" msgstr "Sljedeći zadatke NE možete riješiti u ovom jeziku" -#: judge/admin/runtime.py:83 templates/problem/list.html:352 +#: judge/admin/runtime.py:83 msgid "Description" msgstr "Opis" @@ -404,7 +399,7 @@ msgstr "Nemate dozvolu za ponovnu evaluaciju toliko puno predanih rješenja." msgid "Rejudge the selected submissions" msgstr "Reevaluiraj označena predana rješenja" -#: judge/admin/submission.py:193 judge/views/problem_manage.py:159 +#: judge/admin/submission.py:193 judge/views/problem_manage.py:128 #, python-format msgid "%d submission were successfully rescored." msgid_plural "%d submissions were successfully rescored." @@ -416,8 +411,7 @@ msgstr[2] "%d predanih rješenja je uspješno ponovno ocijenjeno." msgid "Rescore the selected submissions" msgstr "Ponovno ocijeni označena predana rješenja" -#: judge/admin/submission.py:200 templates/problem/list.html:216 -#: templates/problem/list.html:236 +#: judge/admin/submission.py:200 msgid "Problem code" msgstr "Kod zadatka" @@ -425,12 +419,10 @@ msgstr "Kod zadatka" msgid "Problem name" msgstr "Ime zadatka" -#: judge/admin/submission.py:215 templates/notification/list.html:15 -#: templates/organization/requests/log.html:10 +#: judge/admin/submission.py:215 templates/organization/requests/log.html:10 #: templates/organization/requests/pending.html:13 -#: templates/problem/list.html:351 -#: templates/submission/status-testcases.html:125 -#: templates/submission/status-testcases.html:127 +#: templates/submission/status-testcases.html:105 +#: templates/submission/status-testcases.html:107 msgid "Time" msgstr "Vrijeme" @@ -444,7 +436,7 @@ msgstr "%d KB" msgid "%.2f MB" msgstr "%.2f MB" -#: judge/admin/submission.py:227 templates/submission/status-testcases.html:132 +#: judge/admin/submission.py:227 templates/submission/status-testcases.html:112 msgid "Memory" msgstr "Memorija" @@ -464,20 +456,20 @@ msgstr "Ovi zadaci imaju ovaj tip zadatka" msgid "Online Judge" msgstr "Evaluator" -#: judge/comments.py:60 +#: judge/comments.py:41 msgid "Comment body" msgstr "Tekst komentara" -#: judge/comments.py:66 judge/views/ticket.py:63 +#: judge/comments.py:47 judge/views/ticket.py:46 msgid "Your part is silent, little toad." msgstr "Budi tiho, mala žabice." -#: judge/comments.py:69 templates/comments/list.html:132 +#: judge/comments.py:50 templates/comments/list.html:131 msgid "" "You need to have solved at least one problem before your voice can be heard." msgstr "Moraš riješiti barem jedan zadatak kako bi mogao komentirati." -#: judge/comments.py:113 +#: judge/comments.py:92 msgid "Posted comment" msgstr "Objavljen komentar" @@ -493,10 +485,6 @@ msgstr "" msgid "ECOO" msgstr "" -#: judge/contest_format/icpc.py:19 -msgid "ICPC" -msgstr "" - #: judge/contest_format/ioi.py:19 msgid "IOI" msgstr "" @@ -509,58 +497,52 @@ msgstr "Pretplati se na novosti na natjecanju" msgid "Enable experimental features" msgstr "Uključi eksperimentalne opcije" -#: judge/forms.py:57 judge/views/organization.py:168 judge/views/register.py:49 +#: judge/forms.py:57 judge/views/organization.py:127 #, python-brace-format msgid "You may not be part of more than {count} public organizations." msgstr "Ne možete biti član više od {count} javnih organizacija." -#: judge/forms.py:82 -msgid "Any judge" -msgstr "" - -#: judge/forms.py:112 judge/views/register.py:26 +#: judge/forms.py:107 judge/views/register.py:26 #: templates/registration/registration_form.html:139 #: templates/user/base-users-table.html:5 -#: templates/user/import/table_csv.html:4 msgid "Username" msgstr "Korisničko ime" -#: judge/forms.py:113 templates/registration/registration_form.html:151 +#: judge/forms.py:108 templates/registration/registration_form.html:151 #: templates/registration/registration_form.html:165 -#: templates/user/import/table_csv.html:5 msgid "Password" msgstr "Lozinka" -#: judge/forms.py:135 +#: judge/forms.py:130 msgid "Two Factor Authentication tokens must be 6 decimal digits." msgstr "" -#: judge/forms.py:144 templates/registration/totp_auth.html:32 +#: judge/forms.py:139 templates/registration/totp_auth.html:32 msgid "Invalid Two Factor Authentication token." msgstr "" -#: judge/forms.py:148 judge/models/problem.py:97 +#: judge/forms.py:143 judge/models/problem.py:97 msgid "Problem code must be ^[a-z0-9]+$" msgstr "" -#: judge/forms.py:153 +#: judge/forms.py:148 msgid "Problem with code already exists." msgstr "" -#: judge/forms.py:158 judge/models/contest.py:61 +#: judge/forms.py:153 judge/models/contest.py:52 msgid "Contest id must be ^[a-z0-9]+$" msgstr "ID natjecanja mora biti ^[a-z0-9]+$" -#: judge/forms.py:163 +#: judge/forms.py:158 msgid "Contest with key already exists." msgstr "" -#: judge/jinja2/datetime.py:26 templates/blog/blog.html:26 +#: judge/jinja2/datetime.py:26 templates/blog/content.html:27 #: templates/blog/dashboard.html:21 msgid "N j, Y, g:i a" msgstr "N j, Y, g:i a" -#: judge/jinja2/datetime.py:26 templates/chat/message.html:13 +#: judge/jinja2/datetime.py:26 #, python-brace-format msgid "{time}" msgstr "{time}" @@ -590,556 +572,472 @@ msgstr "MathJax sa SVG/PNG rezervom" msgid "Detect best quality" msgstr "Prepoznaj najbolju kvalitetu" -#: judge/models/comment.py:26 +#: judge/models/comment.py:25 msgid "Page code must be ^[pcs]:[a-z0-9]+$|^b:\\d+$" msgstr "" -#: judge/models/comment.py:42 +#: judge/models/comment.py:41 msgid "commenter" msgstr "komentator" -#: judge/models/comment.py:44 judge/models/comment.py:177 +#: judge/models/comment.py:43 judge/models/comment.py:176 msgid "associated page" msgstr "" -#: judge/models/comment.py:46 +#: judge/models/comment.py:45 msgid "votes" msgstr "glasova" -#: judge/models/comment.py:48 +#: judge/models/comment.py:47 msgid "hide the comment" msgstr "sakrij komentar" -#: judge/models/comment.py:49 +#: judge/models/comment.py:48 msgid "parent" msgstr "nadređeni komentar" -#: judge/models/comment.py:54 judge/models/comment.py:192 +#: judge/models/comment.py:53 msgid "comment" msgstr "komentar" -#: judge/models/comment.py:55 +#: judge/models/comment.py:54 msgid "comments" msgstr "komentari" -#: judge/models/comment.py:137 judge/models/problem.py:443 +#: judge/models/comment.py:136 judge/models/problem.py:406 #, python-format msgid "Editorial for %s" msgstr "Objašnjenje za %s" -#: judge/models/comment.py:172 +#: judge/models/comment.py:171 msgid "comment vote" msgstr "" -#: judge/models/comment.py:173 +#: judge/models/comment.py:172 msgid "comment votes" msgstr "" -#: judge/models/comment.py:182 +#: judge/models/comment.py:181 msgid "Override comment lock" msgstr "" -#: judge/models/comment.py:190 -msgid "owner" -msgstr "" - -#: judge/models/comment.py:193 judge/models/message.py:16 -msgid "read" -msgstr "" - -#: judge/models/comment.py:194 -msgid "category" -msgstr "" - -#: judge/models/comment.py:195 -msgid "html link to comments, used for non-comments" -msgstr "" - -#: judge/models/comment.py:196 -msgid "who trigger, used for non-comment" -msgstr "" - -#: judge/models/contest.py:23 +#: judge/models/contest.py:22 msgid "Invalid colour." msgstr "Pogrešna boja." -#: judge/models/contest.py:25 +#: judge/models/contest.py:24 msgid "tag name" msgstr "naziv oznake" -#: judge/models/contest.py:26 +#: judge/models/contest.py:25 msgid "Lowercase letters and hyphens only." msgstr "Samo mala slova i crtice." -#: judge/models/contest.py:27 +#: judge/models/contest.py:26 msgid "tag colour" msgstr "boja oznake" -#: judge/models/contest.py:28 +#: judge/models/contest.py:27 msgid "tag description" msgstr "opis oznake" -#: judge/models/contest.py:47 +#: judge/models/contest.py:46 msgid "contest tag" msgstr "oznaka natjecanja" -#: judge/models/contest.py:48 judge/models/contest.py:118 +#: judge/models/contest.py:47 judge/models/contest.py:101 msgid "contest tags" msgstr "oznake natjecanja" -#: judge/models/contest.py:56 -msgid "Visible" -msgstr "" - -#: judge/models/contest.py:57 -msgid "Hidden for duration of contest" -msgstr "" - -#: judge/models/contest.py:58 -msgid "Hidden for duration of participation" -msgstr "" - -#: judge/models/contest.py:60 +#: judge/models/contest.py:51 msgid "contest id" msgstr "ID natjecanja" -#: judge/models/contest.py:62 +#: judge/models/contest.py:53 msgid "contest name" msgstr "naziv natjecanja" -#: judge/models/contest.py:63 -#, fuzzy -#| msgid "These people will be able to edit the contest." -msgid "These users will be able to edit the contest." +#: judge/models/contest.py:54 +msgid "These people will be able to edit the contest." msgstr "Ove osobe će moći uređivati natjecanje." -#: judge/models/contest.py:65 -#, fuzzy -#| msgid "These people will be able to edit the contest." -msgid "" -"These users will be able to edit the contest, but will not be listed as " -"authors." -msgstr "Ove osobe će moći uređivati natjecanje." - -#: judge/models/contest.py:68 -#, fuzzy -#| msgid "These people will be able to edit the contest." -msgid "These users will be able to view the contest, but not edit it." -msgstr "Ove osobe će moći uređivati natjecanje." - -#: judge/models/contest.py:71 judge/models/runtime.py:136 +#: judge/models/contest.py:56 judge/models/runtime.py:133 msgid "description" msgstr "opis" -#: judge/models/contest.py:72 judge/models/problem.py:390 -#: judge/models/runtime.py:138 +#: judge/models/contest.py:57 judge/models/problem.py:353 +#: judge/models/runtime.py:135 msgid "problems" msgstr "zadaci" -#: judge/models/contest.py:73 judge/models/contest.py:404 +#: judge/models/contest.py:58 judge/models/contest.py:258 msgid "start time" msgstr "vrijeme početka" -#: judge/models/contest.py:74 +#: judge/models/contest.py:59 msgid "end time" msgstr "vrijeme kraja" -#: judge/models/contest.py:75 judge/models/problem.py:118 -#: judge/models/problem.py:414 +#: judge/models/contest.py:60 judge/models/problem.py:118 +#: judge/models/problem.py:377 msgid "time limit" msgstr "vremensko ograničenje" -#: judge/models/contest.py:76 judge/models/problem.py:136 +#: judge/models/contest.py:61 judge/models/problem.py:136 msgid "publicly visible" msgstr "javno vidljivo" -#: judge/models/contest.py:77 +#: judge/models/contest.py:62 msgid "" "Should be set even for organization-private contests, where it determines " "whether the contest is visible to members of the specified organizations." msgstr "" -#: judge/models/contest.py:80 +#: judge/models/contest.py:65 msgid "contest rated" msgstr "bodovanje natjecanja" -#: judge/models/contest.py:80 +#: judge/models/contest.py:65 msgid "Whether this contest can be rated." msgstr "Može li ovo natjecanje biti bodovano." -#: judge/models/contest.py:82 -msgid "scoreboard visibility" +#: judge/models/contest.py:67 +msgid "hide scoreboard" msgstr "" -#: judge/models/contest.py:83 -#, fuzzy -#| msgid "" -#| "Whether the scoreboard should remain hidden for the duration of the " -#| "contest." -msgid "Scoreboard visibility through the duration of the contest" +#: judge/models/contest.py:68 +msgid "" +"Whether the scoreboard should remain hidden for the duration of the contest." msgstr "Treba li tablica poretka ostati skrivena za vrijeme natjecanja." -#: judge/models/contest.py:85 -#, fuzzy -#| msgid "contest rated" -msgid "view contest scoreboard" -msgstr "bodovanje natjecanja" - -#: judge/models/contest.py:87 -#, fuzzy -#| msgid "These people will be able to edit the contest." -msgid "These users will be able to view the scoreboard." -msgstr "Ove osobe će moći uređivati natjecanje." - -#: judge/models/contest.py:88 +#: judge/models/contest.py:71 msgid "no comments" msgstr "bez komentara" -#: judge/models/contest.py:89 +#: judge/models/contest.py:72 msgid "Use clarification system instead of comments." msgstr "Koristite sustav za pojašnjenja umjesto komentara." -#: judge/models/contest.py:91 +#: judge/models/contest.py:74 msgid "Rating floor for contest" msgstr "" -#: judge/models/contest.py:93 +#: judge/models/contest.py:76 msgid "Rating ceiling for contest" msgstr "" -#: judge/models/contest.py:95 +#: judge/models/contest.py:78 msgid "rate all" msgstr "boduj sve" -#: judge/models/contest.py:95 +#: judge/models/contest.py:78 msgid "Rate all users who joined." msgstr "Boduj sve korisnike koji su se pridružili." -#: judge/models/contest.py:96 +#: judge/models/contest.py:79 msgid "exclude from ratings" msgstr "izostavi iz bodovanja" -#: judge/models/contest.py:98 +#: judge/models/contest.py:81 msgid "private to specific users" msgstr "" -#: judge/models/contest.py:99 +#: judge/models/contest.py:82 msgid "private contestants" msgstr "" -#: judge/models/contest.py:100 +#: judge/models/contest.py:83 msgid "If private, only these users may see the contest" msgstr "" -#: judge/models/contest.py:102 +#: judge/models/contest.py:85 msgid "hide problem tags" msgstr "sakrij oznake zadataka" -#: judge/models/contest.py:103 +#: judge/models/contest.py:86 msgid "Whether problem tags should be hidden by default." msgstr "Trebaju li oznake zadataka biti zadano skrivene." -#: judge/models/contest.py:105 +#: judge/models/contest.py:88 msgid "run pretests only" msgstr "pokreni samo predtestiranje" -#: judge/models/contest.py:106 +#: judge/models/contest.py:89 msgid "" "Whether judges should grade pretests only, versus all testcases. Commonly " "set during a contest, then unset prior to rejudging user submissions when " "the contest ends." msgstr "" -#: judge/models/contest.py:110 judge/models/interface.py:77 -#: judge/models/problem.py:157 +#: judge/models/contest.py:93 judge/models/problem.py:157 msgid "private to organizations" msgstr "privatno za organizacije" -#: judge/models/contest.py:111 judge/models/interface.py:75 -#: judge/models/problem.py:155 judge/models/profile.py:77 +#: judge/models/contest.py:94 judge/models/problem.py:155 +#: judge/models/profile.py:77 msgid "organizations" msgstr "" -#: judge/models/contest.py:112 +#: judge/models/contest.py:95 msgid "If private, only these organizations may see the contest" msgstr "" -#: judge/models/contest.py:113 judge/models/problem.py:145 +#: judge/models/contest.py:96 judge/models/problem.py:145 msgid "OpenGraph image" msgstr "OpenGraph slika" -#: judge/models/contest.py:114 judge/models/profile.py:48 +#: judge/models/contest.py:97 judge/models/profile.py:48 msgid "Logo override image" msgstr "" -#: judge/models/contest.py:116 +#: judge/models/contest.py:99 msgid "" "This image will replace the default site logo for users inside the contest." msgstr "" -#: judge/models/contest.py:119 +#: judge/models/contest.py:102 msgid "the amount of live participants" msgstr "" -#: judge/models/contest.py:120 +#: judge/models/contest.py:103 msgid "contest summary" msgstr "" -#: judge/models/contest.py:121 judge/models/problem.py:147 +#: judge/models/contest.py:104 judge/models/problem.py:147 msgid "Plain-text, shown in meta description tag, e.g. for social media." msgstr "" -#: judge/models/contest.py:122 judge/models/profile.py:47 +#: judge/models/contest.py:105 judge/models/profile.py:47 msgid "access code" msgstr "" -#: judge/models/contest.py:123 +#: judge/models/contest.py:106 msgid "" "An optional code to prompt contestants before they are allowed to join the " "contest. Leave it blank to disable." msgstr "" -#: judge/models/contest.py:125 judge/models/problem.py:141 +#: judge/models/contest.py:108 judge/models/problem.py:141 msgid "personae non gratae" msgstr "persona non grata" -#: judge/models/contest.py:126 +#: judge/models/contest.py:109 msgid "Bans the selected users from joining this contest." msgstr "" -#: judge/models/contest.py:127 +#: judge/models/contest.py:110 msgid "contest format" msgstr "" -#: judge/models/contest.py:128 +#: judge/models/contest.py:111 msgid "The contest format module to use." msgstr "" -#: judge/models/contest.py:129 +#: judge/models/contest.py:112 msgid "contest format configuration" msgstr "" -#: judge/models/contest.py:130 +#: judge/models/contest.py:113 msgid "" "A JSON object to serve as the configuration for the chosen contest format " "module. Leave empty to use None. Exact format depends on the contest format " "selected." msgstr "" -#: judge/models/contest.py:137 -msgid "precision points" -msgstr "" - -#: judge/models/contest.py:139 -msgid "Number of digits to round points to." -msgstr "" - -#: judge/models/contest.py:383 +#: judge/models/contest.py:239 msgid "See private contests" msgstr "" -#: judge/models/contest.py:384 +#: judge/models/contest.py:240 msgid "Edit own contests" msgstr "" -#: judge/models/contest.py:385 +#: judge/models/contest.py:241 msgid "Edit all contests" msgstr "" -#: judge/models/contest.py:386 +#: judge/models/contest.py:242 msgid "Clone contest" msgstr "" -#: judge/models/contest.py:387 templates/contest/moss.html:74 +#: judge/models/contest.py:243 templates/contest/moss.html:74 msgid "MOSS contest" msgstr "" -#: judge/models/contest.py:388 +#: judge/models/contest.py:244 msgid "Rate contests" msgstr "" -#: judge/models/contest.py:389 +#: judge/models/contest.py:245 msgid "Contest access codes" msgstr "" -#: judge/models/contest.py:390 +#: judge/models/contest.py:246 msgid "Create private contests" msgstr "" -#: judge/models/contest.py:391 -msgid "Change contest visibility" -msgstr "" - -#: judge/models/contest.py:392 -msgid "Edit contest problem label script" -msgstr "" - -#: judge/models/contest.py:394 judge/models/contest.py:492 -#: judge/models/contest.py:529 judge/models/contest.py:552 -#: judge/models/submission.py:84 +#: judge/models/contest.py:248 judge/models/contest.py:345 +#: judge/models/contest.py:382 judge/models/contest.py:404 +#: judge/models/submission.py:83 msgid "contest" msgstr "natjecanje" -#: judge/models/contest.py:395 +#: judge/models/contest.py:249 msgid "contests" msgstr "natjecanja" -#: judge/models/contest.py:402 +#: judge/models/contest.py:256 msgid "associated contest" msgstr "" -#: judge/models/contest.py:405 +#: judge/models/contest.py:259 msgid "score" msgstr "bodovi" -#: judge/models/contest.py:406 +#: judge/models/contest.py:260 msgid "cumulative time" msgstr "" -#: judge/models/contest.py:407 +#: judge/models/contest.py:261 msgid "is disqualified" msgstr "" -#: judge/models/contest.py:408 +#: judge/models/contest.py:262 msgid "Whether this participation is disqualified." msgstr "" -#: judge/models/contest.py:409 -msgid "tie-breaking field" -msgstr "" - -#: judge/models/contest.py:410 +#: judge/models/contest.py:263 msgid "virtual participation id" msgstr "" -#: judge/models/contest.py:411 +#: judge/models/contest.py:264 msgid "0 means non-virtual, otherwise the n-th virtual participation." msgstr "" -#: judge/models/contest.py:412 +#: judge/models/contest.py:265 msgid "contest format specific data" msgstr "" -#: judge/models/contest.py:478 +#: judge/models/contest.py:331 #, python-format msgid "%s spectating in %s" msgstr "" -#: judge/models/contest.py:480 +#: judge/models/contest.py:333 #, python-format msgid "%s in %s, v%d" msgstr "" -#: judge/models/contest.py:481 +#: judge/models/contest.py:334 #, python-format msgid "%s in %s" msgstr "" -#: judge/models/contest.py:484 +#: judge/models/contest.py:337 msgid "contest participation" msgstr "" -#: judge/models/contest.py:485 +#: judge/models/contest.py:338 msgid "contest participations" msgstr "" -#: judge/models/contest.py:491 judge/models/contest.py:513 -#: judge/models/contest.py:553 judge/models/problem.py:389 -#: judge/models/problem.py:394 judge/models/problem.py:412 -#: judge/models/problem_data.py:40 +#: judge/models/contest.py:344 judge/models/contest.py:366 +#: judge/models/contest.py:405 judge/models/problem.py:352 +#: judge/models/problem.py:357 judge/models/problem.py:375 +#: judge/models/problem_data.py:38 msgid "problem" msgstr "" -#: judge/models/contest.py:493 judge/models/contest.py:517 +#: judge/models/contest.py:346 judge/models/contest.py:370 #: judge/models/problem.py:129 msgid "points" msgstr "" -#: judge/models/contest.py:494 +#: judge/models/contest.py:347 msgid "partial" msgstr "" -#: judge/models/contest.py:495 judge/models/contest.py:518 +#: judge/models/contest.py:348 judge/models/contest.py:371 msgid "is pretested" msgstr "" -#: judge/models/contest.py:496 judge/models/interface.py:43 +#: judge/models/contest.py:349 judge/models/interface.py:43 msgid "order" msgstr "" -#: judge/models/contest.py:497 +#: judge/models/contest.py:350 msgid "0 to not show testcases, 1 to show" msgstr "" -#: judge/models/contest.py:498 +#: judge/models/contest.py:351 msgid "visible testcases" msgstr "" -#: judge/models/contest.py:499 +#: judge/models/contest.py:352 msgid "Maximum number of submissions for this problem, or 0 for no limit." msgstr "" -#: judge/models/contest.py:501 +#: judge/models/contest.py:354 msgid "Why include a problem you can't submit to?" msgstr "" -#: judge/models/contest.py:506 +#: judge/models/contest.py:359 msgid "contest problem" msgstr "" -#: judge/models/contest.py:507 +#: judge/models/contest.py:360 msgid "contest problems" msgstr "" -#: judge/models/contest.py:511 judge/models/submission.py:183 +#: judge/models/contest.py:364 judge/models/submission.py:181 msgid "submission" msgstr "" -#: judge/models/contest.py:515 judge/models/contest.py:530 +#: judge/models/contest.py:368 judge/models/contest.py:383 msgid "participation" msgstr "" -#: judge/models/contest.py:519 +#: judge/models/contest.py:372 msgid "Whether this submission was ran only on pretests." msgstr "" -#: judge/models/contest.py:523 +#: judge/models/contest.py:376 msgid "contest submission" msgstr "" -#: judge/models/contest.py:524 +#: judge/models/contest.py:377 msgid "contest submissions" msgstr "" -#: judge/models/contest.py:532 +#: judge/models/contest.py:385 msgid "rank" msgstr "" -#: judge/models/contest.py:533 +#: judge/models/contest.py:386 msgid "rating" msgstr "" -#: judge/models/contest.py:534 +#: judge/models/contest.py:387 msgid "volatility" msgstr "" -#: judge/models/contest.py:535 +#: judge/models/contest.py:388 msgid "last rated" msgstr "" -#: judge/models/contest.py:539 +#: judge/models/contest.py:392 msgid "contest rating" msgstr "" -#: judge/models/contest.py:540 +#: judge/models/contest.py:393 msgid "contest ratings" msgstr "" -#: judge/models/contest.py:560 +#: judge/models/contest.py:412 msgid "contest moss result" msgstr "" -#: judge/models/contest.py:561 +#: judge/models/contest.py:413 msgid "contest moss results" msgstr "" @@ -1179,7 +1077,7 @@ msgstr "" msgid "post title" msgstr "" -#: judge/models/interface.py:67 judge/models/problem.py:432 +#: judge/models/interface.py:67 judge/models/problem.py:395 msgid "authors" msgstr "" @@ -1187,7 +1085,7 @@ msgstr "" msgid "slug" msgstr "" -#: judge/models/interface.py:69 judge/models/problem.py:430 +#: judge/models/interface.py:69 judge/models/problem.py:393 msgid "public visibility" msgstr "" @@ -1211,19 +1109,15 @@ msgstr "" msgid "openGraph image" msgstr "" -#: judge/models/interface.py:76 -msgid "If private, only these organizations may see the blog post." -msgstr "" - -#: judge/models/interface.py:105 +#: judge/models/interface.py:91 msgid "Edit all posts" msgstr "" -#: judge/models/interface.py:107 +#: judge/models/interface.py:93 msgid "blog post" msgstr "" -#: judge/models/interface.py:108 +#: judge/models/interface.py:94 msgid "blog posts" msgstr "" @@ -1247,6 +1141,10 @@ msgstr "" msgid "message timestamp" msgstr "" +#: judge/models/message.py:16 +msgid "read" +msgstr "" + #: judge/models/message.py:20 msgid "messages in the thread" msgstr "" @@ -1383,7 +1281,7 @@ msgid "" "are supported." msgstr "" -#: judge/models/problem.py:123 judge/models/problem.py:417 +#: judge/models/problem.py:123 judge/models/problem.py:380 msgid "memory limit" msgstr "memorijsko ograničenje" @@ -1458,188 +1356,188 @@ msgstr "" msgid "If private, only these organizations may see the problem." msgstr "" -#: judge/models/problem.py:395 judge/models/problem.py:413 -#: judge/models/runtime.py:111 +#: judge/models/problem.py:358 judge/models/problem.py:376 +#: judge/models/runtime.py:108 msgid "language" msgstr "" -#: judge/models/problem.py:396 +#: judge/models/problem.py:359 msgid "translated name" msgstr "" -#: judge/models/problem.py:397 +#: judge/models/problem.py:360 msgid "translated description" msgstr "" -#: judge/models/problem.py:401 +#: judge/models/problem.py:364 msgid "problem translation" msgstr "" -#: judge/models/problem.py:402 +#: judge/models/problem.py:365 msgid "problem translations" msgstr "" -#: judge/models/problem.py:406 +#: judge/models/problem.py:369 msgid "clarified problem" msgstr "" -#: judge/models/problem.py:407 +#: judge/models/problem.py:370 msgid "clarification body" msgstr "" -#: judge/models/problem.py:408 +#: judge/models/problem.py:371 msgid "clarification timestamp" msgstr "" -#: judge/models/problem.py:423 +#: judge/models/problem.py:386 msgid "language-specific resource limit" msgstr "" -#: judge/models/problem.py:424 +#: judge/models/problem.py:387 msgid "language-specific resource limits" msgstr "" -#: judge/models/problem.py:428 +#: judge/models/problem.py:391 msgid "associated problem" msgstr "" -#: judge/models/problem.py:431 +#: judge/models/problem.py:394 msgid "publish date" msgstr "" -#: judge/models/problem.py:433 +#: judge/models/problem.py:396 msgid "editorial content" msgstr "" -#: judge/models/problem.py:449 +#: judge/models/problem.py:412 msgid "solution" msgstr "" -#: judge/models/problem.py:450 +#: judge/models/problem.py:413 msgid "solutions" msgstr "" -#: judge/models/problem_data.py:26 +#: judge/models/problem_data.py:24 msgid "Standard" msgstr "" -#: judge/models/problem_data.py:27 +#: judge/models/problem_data.py:25 msgid "Floats" msgstr "" -#: judge/models/problem_data.py:28 +#: judge/models/problem_data.py:26 msgid "Floats (absolute)" msgstr "" -#: judge/models/problem_data.py:29 +#: judge/models/problem_data.py:27 msgid "Floats (relative)" msgstr "" -#: judge/models/problem_data.py:30 +#: judge/models/problem_data.py:28 msgid "Non-trailing spaces" msgstr "" -#: judge/models/problem_data.py:31 +#: judge/models/problem_data.py:29 msgid "Unordered" msgstr "" -#: judge/models/problem_data.py:32 +#: judge/models/problem_data.py:30 msgid "Byte identical" msgstr "" -#: judge/models/problem_data.py:33 +#: judge/models/problem_data.py:31 msgid "Line-by-line" msgstr "" -#: judge/models/problem_data.py:34 +#: judge/models/problem_data.py:32 msgid "Custom checker (PY)" msgstr "" -#: judge/models/problem_data.py:35 +#: judge/models/problem_data.py:33 msgid "Custom validator (CPP)" msgstr "" -#: judge/models/problem_data.py:42 +#: judge/models/problem_data.py:40 msgid "data zip file" msgstr "" -#: judge/models/problem_data.py:44 +#: judge/models/problem_data.py:42 msgid "generator file" msgstr "" -#: judge/models/problem_data.py:46 judge/models/problem_data.py:121 +#: judge/models/problem_data.py:44 judge/models/problem_data.py:110 msgid "output prefix length" msgstr "" -#: judge/models/problem_data.py:47 judge/models/problem_data.py:122 +#: judge/models/problem_data.py:45 judge/models/problem_data.py:111 msgid "output limit length" msgstr "" -#: judge/models/problem_data.py:48 +#: judge/models/problem_data.py:46 msgid "init.yml generation feedback" msgstr "" -#: judge/models/problem_data.py:49 judge/models/problem_data.py:123 +#: judge/models/problem_data.py:47 judge/models/problem_data.py:112 msgid "checker" msgstr "" -#: judge/models/problem_data.py:50 judge/models/problem_data.py:124 +#: judge/models/problem_data.py:48 judge/models/problem_data.py:113 msgid "checker arguments" msgstr "" -#: judge/models/problem_data.py:51 judge/models/problem_data.py:125 +#: judge/models/problem_data.py:49 judge/models/problem_data.py:114 msgid "checker arguments as a JSON object" msgstr "" -#: judge/models/problem_data.py:52 +#: judge/models/problem_data.py:50 msgid "custom checker file" msgstr "" -#: judge/models/problem_data.py:58 +#: judge/models/problem_data.py:56 msgid "custom validator file" msgstr "" -#: judge/models/problem_data.py:108 +#: judge/models/problem_data.py:97 msgid "problem data set" msgstr "" -#: judge/models/problem_data.py:110 +#: judge/models/problem_data.py:99 msgid "case position" msgstr "" -#: judge/models/problem_data.py:111 +#: judge/models/problem_data.py:100 msgid "case type" msgstr "" -#: judge/models/problem_data.py:112 +#: judge/models/problem_data.py:101 msgid "Normal case" msgstr "" -#: judge/models/problem_data.py:113 +#: judge/models/problem_data.py:102 msgid "Batch start" msgstr "" -#: judge/models/problem_data.py:114 +#: judge/models/problem_data.py:103 msgid "Batch end" msgstr "" -#: judge/models/problem_data.py:116 +#: judge/models/problem_data.py:105 msgid "input file name" msgstr "" -#: judge/models/problem_data.py:117 +#: judge/models/problem_data.py:106 msgid "output file name" msgstr "" -#: judge/models/problem_data.py:118 +#: judge/models/problem_data.py:107 msgid "generator arguments" msgstr "" -#: judge/models/problem_data.py:119 +#: judge/models/problem_data.py:108 msgid "point value" msgstr "" -#: judge/models/problem_data.py:120 +#: judge/models/problem_data.py:109 msgid "case is pretest?" msgstr "" @@ -1712,7 +1610,7 @@ msgid "" msgstr "" #: judge/models/profile.py:76 judge/models/profile.py:93 -#: judge/models/profile.py:212 +#: judge/models/profile.py:192 msgid "organization" msgstr "" @@ -1808,31 +1706,31 @@ msgstr "" msgid "Notes for administrators regarding this user." msgstr "" -#: judge/models/profile.py:206 +#: judge/models/profile.py:186 msgid "user profile" msgstr "" -#: judge/models/profile.py:207 +#: judge/models/profile.py:187 msgid "user profiles" msgstr "" -#: judge/models/profile.py:214 +#: judge/models/profile.py:194 msgid "request time" msgstr "" -#: judge/models/profile.py:215 +#: judge/models/profile.py:195 msgid "state" msgstr "" -#: judge/models/profile.py:220 +#: judge/models/profile.py:200 msgid "reason" msgstr "" -#: judge/models/profile.py:223 +#: judge/models/profile.py:203 msgid "organization join request" msgstr "" -#: judge/models/profile.py:224 +#: judge/models/profile.py:204 msgid "organization join requests" msgstr "" @@ -1923,86 +1821,86 @@ msgstr "" msgid "The extension of source files, e.g., \"py\" or \"cpp\"." msgstr "" -#: judge/models/runtime.py:112 +#: judge/models/runtime.py:109 msgid "languages" msgstr "" -#: judge/models/runtime.py:116 +#: judge/models/runtime.py:113 msgid "language to which this runtime belongs" msgstr "" -#: judge/models/runtime.py:117 +#: judge/models/runtime.py:114 msgid "judge on which this runtime exists" msgstr "" -#: judge/models/runtime.py:118 +#: judge/models/runtime.py:115 msgid "runtime name" msgstr "" -#: judge/models/runtime.py:119 +#: judge/models/runtime.py:116 msgid "runtime version" msgstr "" -#: judge/models/runtime.py:120 +#: judge/models/runtime.py:117 msgid "order in which to display this runtime" msgstr "" -#: judge/models/runtime.py:124 +#: judge/models/runtime.py:121 msgid "Server name, hostname-style" msgstr "" -#: judge/models/runtime.py:125 +#: judge/models/runtime.py:122 msgid "time of creation" msgstr "" -#: judge/models/runtime.py:126 +#: judge/models/runtime.py:123 msgid "A key to authenticate this judge" msgstr "" -#: judge/models/runtime.py:127 +#: judge/models/runtime.py:124 msgid "authentication key" msgstr "" -#: judge/models/runtime.py:128 +#: judge/models/runtime.py:125 msgid "block judge" msgstr "" -#: judge/models/runtime.py:129 +#: judge/models/runtime.py:126 msgid "" "Whether this judge should be blocked from connecting, even if its key is " "correct." msgstr "" -#: judge/models/runtime.py:131 +#: judge/models/runtime.py:128 msgid "judge online status" msgstr "" -#: judge/models/runtime.py:132 +#: judge/models/runtime.py:129 msgid "judge start time" msgstr "" -#: judge/models/runtime.py:133 +#: judge/models/runtime.py:130 msgid "response time" msgstr "" -#: judge/models/runtime.py:134 +#: judge/models/runtime.py:131 msgid "system load" msgstr "" -#: judge/models/runtime.py:135 +#: judge/models/runtime.py:132 msgid "Load for the last minute, divided by processors to be fair." msgstr "" -#: judge/models/runtime.py:139 judge/models/runtime.py:179 +#: judge/models/runtime.py:136 judge/models/runtime.py:176 msgid "judges" msgstr "" -#: judge/models/runtime.py:178 +#: judge/models/runtime.py:175 msgid "judge" msgstr "" #: judge/models/submission.py:20 judge/models/submission.py:47 -#: judge/utils/problems.py:79 +#: judge/utils/problems.py:77 msgid "Accepted" msgstr "" @@ -2031,7 +1929,7 @@ msgid "Runtime Error" msgstr "" #: judge/models/submission.py:27 judge/models/submission.py:41 -#: judge/models/submission.py:55 judge/utils/problems.py:81 +#: judge/models/submission.py:55 judge/utils/problems.py:79 msgid "Compile Error" msgstr "" @@ -2072,15 +1970,15 @@ msgstr "" msgid "submission time" msgstr "" -#: judge/models/submission.py:67 judge/models/submission.py:203 +#: judge/models/submission.py:67 judge/models/submission.py:201 msgid "execution time" msgstr "" -#: judge/models/submission.py:68 judge/models/submission.py:204 +#: judge/models/submission.py:68 judge/models/submission.py:202 msgid "memory usage" msgstr "" -#: judge/models/submission.py:69 judge/models/submission.py:205 +#: judge/models/submission.py:69 judge/models/submission.py:203 msgid "points granted" msgstr "" @@ -2117,62 +2015,58 @@ msgid "judged on" msgstr "" #: judge/models/submission.py:81 -msgid "submission judge time" -msgstr "" - -#: judge/models/submission.py:82 msgid "was rejudged by admin" msgstr "" -#: judge/models/submission.py:83 +#: judge/models/submission.py:82 msgid "was ran on pretests only" msgstr "" -#: judge/models/submission.py:184 templates/contest/moss.html:58 +#: judge/models/submission.py:182 templates/contest/moss.html:58 msgid "submissions" msgstr "" -#: judge/models/submission.py:188 judge/models/submission.py:199 +#: judge/models/submission.py:186 judge/models/submission.py:197 msgid "associated submission" msgstr "" -#: judge/models/submission.py:190 +#: judge/models/submission.py:188 msgid "source code" msgstr "" -#: judge/models/submission.py:201 +#: judge/models/submission.py:199 msgid "test case ID" msgstr "" -#: judge/models/submission.py:202 +#: judge/models/submission.py:200 msgid "status flag" msgstr "" -#: judge/models/submission.py:206 +#: judge/models/submission.py:204 msgid "points possible" msgstr "" -#: judge/models/submission.py:207 +#: judge/models/submission.py:205 msgid "batch number" msgstr "" -#: judge/models/submission.py:208 +#: judge/models/submission.py:206 msgid "judging feedback" msgstr "" -#: judge/models/submission.py:209 +#: judge/models/submission.py:207 msgid "extended judging feedback" msgstr "" -#: judge/models/submission.py:210 +#: judge/models/submission.py:208 msgid "program output" msgstr "" -#: judge/models/submission.py:218 +#: judge/models/submission.py:216 msgid "submission test case" msgstr "" -#: judge/models/submission.py:219 +#: judge/models/submission.py:217 msgid "submission test cases" msgstr "" @@ -2224,23 +2118,12 @@ msgstr "" msgid "message time" msgstr "" -#: judge/pdf_problems.py:147 judge/pdf_problems.py:199 -#: judge/pdf_problems.py:259 +#: judge/pdf_problems.py:134 judge/pdf_problems.py:186 +#: judge/pdf_problems.py:246 msgid "Page [page] of [topage]" msgstr "" -#: judge/pdf_problems.py:280 -#, python-format -msgid "Page %s of %s" -msgstr "" - -#: judge/tasks/contest.py:19 -#, fuzzy -#| msgid "Recalculate scores" -msgid "Recalculating contest scores" -msgstr "Ponovno izračunavanje rezultata" - -#: judge/tasks/contest.py:40 +#: judge/tasks/moss.py:25 msgid "Running MOSS" msgstr "" @@ -2252,60 +2135,60 @@ msgstr "" msgid "Recalculating user points" msgstr "" -#: judge/utils/problem_data.py:70 +#: judge/utils/problem_data.py:68 msgid "Empty batches not allowed." msgstr "" -#: judge/utils/problem_data.py:78 judge/utils/problem_data.py:99 +#: judge/utils/problem_data.py:76 judge/utils/problem_data.py:97 msgid "How did you corrupt the custom checker path?" msgstr "" -#: judge/utils/problem_data.py:120 +#: judge/utils/problem_data.py:118 #, python-format msgid "Points must be defined for non-batch case #%d." msgstr "" -#: judge/utils/problem_data.py:125 +#: judge/utils/problem_data.py:123 #, python-format msgid "Input file for case %d does not exist: %s" msgstr "" -#: judge/utils/problem_data.py:128 +#: judge/utils/problem_data.py:126 #, python-format msgid "Output file for case %d does not exist: %s" msgstr "" -#: judge/utils/problem_data.py:153 +#: judge/utils/problem_data.py:151 #, python-format msgid "Batch start case #%d requires points." msgstr "" -#: judge/utils/problem_data.py:174 +#: judge/utils/problem_data.py:172 #, python-format msgid "Attempt to end batch outside of one in case #%d" msgstr "" -#: judge/utils/problem_data.py:192 +#: judge/utils/problem_data.py:190 msgid "How did you corrupt the zip path?" msgstr "" -#: judge/utils/problem_data.py:198 +#: judge/utils/problem_data.py:196 msgid "How did you corrupt the generator path?" msgstr "" -#: judge/utils/problems.py:80 +#: judge/utils/problems.py:78 msgid "Wrong" msgstr "" -#: judge/utils/problems.py:82 +#: judge/utils/problems.py:80 msgid "Timeout" msgstr "" -#: judge/utils/problems.py:83 +#: judge/utils/problems.py:81 msgid "Error" msgstr "" -#: judge/utils/problems.py:94 +#: judge/utils/problems.py:92 msgid "Can't pass both queryset and keyword filters" msgstr "" @@ -2351,8 +2234,7 @@ msgctxt "hours and minutes" msgid "%h:%m" msgstr "%h:%m" -#: judge/views/about.py:7 templates/organization/home.html:112 -#: templates/user/user-about.html:83 templates/user/user-tabs.html:4 +#: judge/views/about.py:7 templates/user/user-about.html:33 msgid "About" msgstr "" @@ -2360,165 +2242,156 @@ msgstr "" msgid "Custom Checker Sample" msgstr "" -#: judge/views/blog.py:45 +#: judge/views/blog.py:38 #, python-format msgid "Page %d of Posts" msgstr "" -#: judge/views/comment.py:28 +#: judge/views/comment.py:27 msgid "Messing around, are we?" msgstr "" -#: judge/views/comment.py:37 +#: judge/views/comment.py:36 msgid "You must solve at least one problem before you can vote." msgstr "" -#: judge/views/comment.py:64 +#: judge/views/comment.py:63 msgid "You already voted." msgstr "" -#: judge/views/comment.py:126 judge/views/organization.py:344 +#: judge/views/comment.py:120 judge/views/organization.py:299 msgid "Edited from site" msgstr "" -#: judge/views/comment.py:147 +#: judge/views/comment.py:141 msgid "Editing comment" msgstr "" -#: judge/views/contests.py:57 judge/views/contests.py:247 -#: judge/views/contests.py:250 judge/views/contests.py:424 +#: judge/views/contests.py:55 judge/views/contests.py:215 +#: judge/views/contests.py:218 judge/views/contests.py:389 msgid "No such contest" msgstr "" -#: judge/views/contests.py:58 judge/views/contests.py:248 +#: judge/views/contests.py:56 judge/views/contests.py:216 #, python-format msgid "Could not find a contest with the key \"%s\"." msgstr "" -#: judge/views/contests.py:71 +#: judge/views/contests.py:81 msgid "Contests" msgstr "" -#: judge/views/contests.py:251 +#: judge/views/contests.py:219 msgid "Could not find such contest." msgstr "" -#: judge/views/contests.py:254 +#: judge/views/contests.py:222 #, python-format msgid "Access to contest \"%s\" denied" msgstr "" -#: judge/views/contests.py:278 +#: judge/views/contests.py:246 msgid "Clone Contest" msgstr "" -#: judge/views/contests.py:343 +#: judge/views/contests.py:309 msgid "Contest not ongoing" msgstr "" -#: judge/views/contests.py:344 +#: judge/views/contests.py:310 #, python-format msgid "\"%s\" is not currently ongoing." msgstr "" -#: judge/views/contests.py:348 +#: judge/views/contests.py:314 msgid "Already in contest" msgstr "" -#: judge/views/contests.py:349 +#: judge/views/contests.py:315 #, python-format msgid "You are already in a contest: \"%s\"." msgstr "" -#: judge/views/contests.py:352 +#: judge/views/contests.py:318 msgid "Banned from joining" msgstr "" -#: judge/views/contests.py:353 +#: judge/views/contests.py:319 msgid "" "You have been declared persona non grata for this contest. You are " "permanently barred from joining this contest." msgstr "" -#: judge/views/contests.py:414 +#: judge/views/contests.py:379 #, python-format msgid "Enter access code for \"%s\"" msgstr "" -#: judge/views/contests.py:425 +#: judge/views/contests.py:390 #, python-format msgid "You are not in contest \"%s\"." msgstr "" -#: judge/views/contests.py:444 +#: judge/views/contests.py:409 msgid "ContestCalendar requires integer year and month" msgstr "" -#: judge/views/contests.py:484 +#: judge/views/contests.py:449 #, python-format msgid "Contests in %(month)s" msgstr "" -#: judge/views/contests.py:484 +#: judge/views/contests.py:449 msgid "F Y" msgstr "" -#: judge/views/contests.py:532 +#: judge/views/contests.py:496 #, python-format msgid "%s Statistics" msgstr "" -#: judge/views/contests.py:717 +#: judge/views/contests.py:601 +msgid "???" +msgstr "" + +#: judge/views/contests.py:664 #, python-format msgid "%s Rankings" msgstr "" -#: judge/views/contests.py:725 -msgid "???" -msgstr "" - -#: judge/views/contests.py:741 +#: judge/views/contests.py:680 #, python-format msgid "Your participation in %s" msgstr "" -#: judge/views/contests.py:742 +#: judge/views/contests.py:681 #, python-format msgid "%s's participation in %s" msgstr "" -#: judge/views/contests.py:749 +#: judge/views/contests.py:685 msgid "Live" msgstr "" -#: judge/views/contests.py:761 templates/contest/contest-tabs.html:13 +#: judge/views/contests.py:697 msgid "Participation" msgstr "" -#: judge/views/contests.py:808 +#: judge/views/contests.py:743 #, python-format msgid "%s MOSS Results" msgstr "" -#: judge/views/contests.py:835 +#: judge/views/contests.py:770 #, python-format msgid "Running MOSS for %s..." msgstr "" -#: judge/views/contests.py:858 +#: judge/views/contests.py:793 #, python-format msgid "Contest tag: %s" msgstr "" -#: judge/views/contests.py:868 judge/views/ticket.py:57 -msgid "Issue description" -msgstr "" - -#: judge/views/contests.py:911 -#, python-format -msgid "New clarification for %s" -msgstr "" - #: judge/views/error.py:14 msgid "404 error" msgstr "404 greška" @@ -2539,83 +2412,76 @@ msgid "corrupt page %s" msgstr "" #: judge/views/language.py:12 templates/status/judge-status-table.html:9 -#: templates/status/status-tabs.html:5 msgid "Runtimes" msgstr "" -#: judge/views/notification.py:40 -#, python-format -msgid "Notifications (%d unseen)" -msgstr "" - -#: judge/views/organization.py:59 judge/views/organization.py:62 +#: judge/views/organization.py:44 judge/views/organization.py:47 msgid "No such organization" msgstr "" -#: judge/views/organization.py:60 +#: judge/views/organization.py:45 #, python-format msgid "Could not find an organization with the key \"%s\"." msgstr "" -#: judge/views/organization.py:63 +#: judge/views/organization.py:48 msgid "Could not find such organization." msgstr "" -#: judge/views/organization.py:79 judge/views/register.py:34 -#: templates/organization/list.html:32 templates/user/import/table_csv.html:9 -#: templates/user/user-list-tabs.html:6 +#: judge/views/organization.py:72 judge/views/register.py:34 +#: templates/organization/list.html:15 msgid "Organizations" msgstr "" -#: judge/views/organization.py:130 +#: judge/views/organization.py:93 #, python-format msgid "%s Members" msgstr "" -#: judge/views/organization.py:159 judge/views/organization.py:162 -#: judge/views/organization.py:167 +#: judge/views/organization.py:118 judge/views/organization.py:121 +#: judge/views/organization.py:126 msgid "Joining organization" msgstr "" -#: judge/views/organization.py:159 +#: judge/views/organization.py:118 msgid "You are already in the organization." msgstr "" -#: judge/views/organization.py:162 +#: judge/views/organization.py:121 msgid "This organization is not open." msgstr "" -#: judge/views/organization.py:179 +#: judge/views/organization.py:138 msgid "Leaving organization" msgstr "" -#: judge/views/organization.py:179 +#: judge/views/organization.py:138 #, python-format msgid "You are not in \"%s\"." msgstr "" -#: judge/views/organization.py:203 +#: judge/views/organization.py:162 #, python-format msgid "Request to join %s" msgstr "Zahtjev za pridruživanje %s" -#: judge/views/organization.py:221 +#: judge/views/organization.py:180 msgid "Join request detail" msgstr "" -#: judge/views/organization.py:254 +#: judge/views/organization.py:209 #, python-format msgid "Managing join requests for %s" msgstr "" -#: judge/views/organization.py:285 +#: judge/views/organization.py:240 #, python-format msgid "" "Your organization can only receive %d more members. You cannot approve %d " "users." msgstr "" -#: judge/views/organization.py:297 +#: judge/views/organization.py:252 #, python-format msgid "Approved %d user." msgid_plural "Approved %d users." @@ -2623,7 +2489,7 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: judge/views/organization.py:298 +#: judge/views/organization.py:253 #, python-format msgid "Rejected %d user." msgid_plural "Rejected %d users." @@ -2631,32 +2497,32 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: judge/views/organization.py:328 +#: judge/views/organization.py:283 #, python-format msgid "Editing %s" msgstr "Uređivanje %s" -#: judge/views/organization.py:352 judge/views/organization.py:360 +#: judge/views/organization.py:307 judge/views/organization.py:315 msgid "Can't edit organization" msgstr "Nije moguće urediti organizaciju" -#: judge/views/organization.py:353 +#: judge/views/organization.py:308 msgid "You are not allowed to edit this organization." msgstr "Nemate ovlasti za uređivanje ove organizacije." -#: judge/views/organization.py:361 +#: judge/views/organization.py:316 msgid "You are not allowed to kick people from this organization." msgstr "Nemate ovlasti za izbacivanje ljudi iz ove organizacije." -#: judge/views/organization.py:366 judge/views/organization.py:370 +#: judge/views/organization.py:321 judge/views/organization.py:325 msgid "Can't kick user" msgstr "Nije moguće izbaciti korisnika" -#: judge/views/organization.py:367 +#: judge/views/organization.py:322 msgid "The user you are trying to kick does not exist!" msgstr "Korisnik kojeg pokušavate izbaciti ne postoji!" -#: judge/views/organization.py:371 +#: judge/views/organization.py:326 #, python-format msgid "The user you are trying to kick is not in organization: %s." msgstr "Korisnik kojeg pokušavate izbaciti nije u organizaciji: %s." @@ -2680,36 +2546,35 @@ msgstr "" msgid "Editorial for {0}" msgstr "" -#: judge/views/problem.py:285 templates/contest/contest.html:79 -#: templates/user/user-about.html:28 templates/user/user-tabs.html:5 -#: templates/user/users-table.html:31 +#: judge/views/problem.py:286 templates/contest/contest.html:79 +#: templates/user/users-table.html:23 msgid "Problems" msgstr "Zadaci" -#: judge/views/problem.py:585 +#: judge/views/problem.py:547 msgid "Banned from submitting" msgstr "" -#: judge/views/problem.py:586 +#: judge/views/problem.py:548 msgid "" "You have been declared persona non grata for this problem. You are " "permanently barred from submitting this problem." msgstr "" -#: judge/views/problem.py:600 +#: judge/views/problem.py:562 msgid "Too many submissions" msgstr "Previše poslanih rješenja" -#: judge/views/problem.py:601 +#: judge/views/problem.py:563 msgid "You have exceeded the submission limit for this problem." msgstr "" -#: judge/views/problem.py:661 judge/views/problem.py:664 +#: judge/views/problem.py:633 judge/views/problem.py:636 #, python-format msgid "Submit to %(problem)s" msgstr "" -#: judge/views/problem.py:679 +#: judge/views/problem.py:652 msgid "Clone Problem" msgstr "" @@ -2750,22 +2615,22 @@ msgstr "" msgid "Generated init.yml for %s" msgstr "" -#: judge/views/problem_manage.py:52 judge/views/problem_manage.py:55 +#: judge/views/problem_manage.py:50 judge/views/problem_manage.py:53 #, python-format msgid "Managing submissions for %s" msgstr "" -#: judge/views/problem_manage.py:97 +#: judge/views/problem_manage.py:95 #, python-format msgid "Rejudging selected submissions for %s..." msgstr "" -#: judge/views/problem_manage.py:141 +#: judge/views/problem_manage.py:110 #, python-format msgid "Rescoring all submissions for %s..." msgstr "" -#: judge/views/problem_manage.py:150 +#: judge/views/problem_manage.py:119 #, python-format msgid "Successfully scheduled %d submission for rejudging." msgid_plural "Successfully scheduled %d submissions for rejudging." @@ -2815,7 +2680,7 @@ msgstr "" msgid "Subscribe to newsletter?" msgstr "Pretplatite se na naš newsletter?" -#: judge/views/register.py:55 +#: judge/views/register.py:45 #, python-format msgid "" "The email address \"%s\" is already taken. Only one registration is allowed " @@ -2824,17 +2689,17 @@ msgstr "" "Vaša adresa e-pošte \"%s\" je već zauzeta. Dopuštena je isključivo jedna " "registracija za jednu adresu e-pošte." -#: judge/views/register.py:61 +#: judge/views/register.py:51 msgid "" "Your email provider is not allowed due to history of abuse. Please use a " "reputable email provider." msgstr "" -#: judge/views/register.py:67 judge/views/register.py:105 +#: judge/views/register.py:57 judge/views/register.py:95 msgid "Registration" msgstr "Registracija" -#: judge/views/register.py:116 +#: judge/views/register.py:106 msgid "Authentication failure" msgstr "" @@ -2850,100 +2715,104 @@ msgstr "Status predanog rješenja" msgid "Version matrix" msgstr "" -#: judge/views/submission.py:84 judge/views/submission.py:91 +#: judge/views/submission.py:83 judge/views/submission.py:90 #, python-format msgid "Submission of %(problem)s by %(user)s" msgstr "Predano rješenje za zadatak %(problem)s od korisnika %(user)s" -#: judge/views/submission.py:244 judge/views/submission.py:245 -#: templates/problem/problem.html:167 +#: judge/views/submission.py:227 judge/views/submission.py:228 +#: templates/problem/problem.html:127 msgid "All submissions" msgstr "Sva predana rješenja" -#: judge/views/submission.py:404 +#: judge/views/submission.py:384 msgid "All my submissions" msgstr "Sva moja predana rješenja" -#: judge/views/submission.py:405 +#: judge/views/submission.py:385 #, python-format msgid "All submissions by %s" msgstr "Sva predana rješenja od korisnika %s" -#: judge/views/submission.py:436 +#: judge/views/submission.py:416 #, python-format msgid "All submissions for %s" msgstr "Sva predana rješenja za korisnika %s" -#: judge/views/submission.py:455 +#: judge/views/submission.py:435 msgid "Must pass a problem" msgstr "" -#: judge/views/submission.py:501 +#: judge/views/submission.py:481 #, python-format msgid "My submissions for %(problem)s" msgstr "" -#: judge/views/submission.py:502 +#: judge/views/submission.py:482 #, python-format msgid "%(user)s's submissions for %(problem)s" msgstr "" -#: judge/views/submission.py:603 +#: judge/views/submission.py:583 msgid "Must pass a contest" msgstr "" -#: judge/views/submission.py:622 +#: judge/views/submission.py:602 #, python-brace-format msgid "" "{0}'s submissions for {2} in {4}" msgstr "" -#: judge/views/submission.py:629 +#: judge/views/submission.py:609 #, python-brace-format msgid "" "{0}'s submissions for problem {2} in {3}" "" msgstr "" -#: judge/views/ticket.py:50 judge/views/ticket.py:56 +#: judge/views/ticket.py:33 judge/views/ticket.py:39 msgid "Ticket title" msgstr "" -#: judge/views/ticket.py:107 judge/views/ticket.py:110 +#: judge/views/ticket.py:40 +msgid "Issue description" +msgstr "" + +#: judge/views/ticket.py:85 judge/views/ticket.py:88 #, python-format msgid "New ticket for %s" msgstr "" -#: judge/views/ticket.py:170 +#: judge/views/ticket.py:142 #, python-format msgid "%(title)s - Ticket %(id)d" msgstr "" -#: judge/views/ticket.py:279 +#: judge/views/ticket.py:251 #, python-format msgid "Tickets - Page %(number)d of %(total)d" msgstr "" -#: judge/views/ticket.py:328 +#: judge/views/ticket.py:300 #, python-format msgid "New Ticket: %s" msgstr "" -#: judge/views/ticket.py:329 +#: judge/views/ticket.py:301 #, python-format msgid "#%(id)d, assigned to: %(users)s" msgstr "" -#: judge/views/ticket.py:331 +#: judge/views/ticket.py:303 msgid ", " msgstr "" -#: judge/views/ticket.py:331 +#: judge/views/ticket.py:303 msgid "no one" msgstr "" -#: judge/views/ticket.py:351 +#: judge/views/ticket.py:323 #, python-format msgid "New Ticket Message For: %s" msgstr "" @@ -2960,50 +2829,41 @@ msgstr "" msgid "Perform Two Factor Authentication" msgstr "" -#: judge/views/user.py:74 +#: judge/views/user.py:68 msgid "No such user" msgstr "" -#: judge/views/user.py:74 +#: judge/views/user.py:68 #, python-format msgid "No user handle \"%s\"." msgstr "" -#: judge/views/user.py:78 +#: judge/views/user.py:72 msgid "My account" msgstr "" -#: judge/views/user.py:79 +#: judge/views/user.py:73 #, python-format msgid "User %s" msgstr "" -#: judge/views/user.py:148 -msgid "M j, Y" -msgstr "" - -#: judge/views/user.py:171 +#: judge/views/user.py:136 msgid "M j, Y, G:i" msgstr "" -#: judge/views/user.py:290 +#: judge/views/user.py:221 msgid "Updated on site" msgstr "" -#: judge/views/user.py:323 templates/admin/auth/user/change_form.html:14 -#: templates/admin/auth/user/change_form.html:17 templates/base.html:238 -#: templates/user/user-tabs.html:10 +#: judge/views/user.py:254 templates/admin/auth/user/change_form.html:14 +#: templates/admin/auth/user/change_form.html:17 templates/base.html:224 msgid "Edit profile" msgstr "" -#: judge/views/user.py:332 templates/user/user-list-tabs.html:4 +#: judge/views/user.py:263 msgid "Leaderboard" msgstr "" -#: judge/views/user.py:407 -msgid "Import Users" -msgstr "" - #: judge/views/widgets.py:48 judge/views/widgets.py:58 #, python-format msgid "Invalid upstream data: %s" @@ -3041,7 +2901,7 @@ msgid "View Submissions" msgstr "" #: templates/admin/judge/problem/change_form.html:17 -#: templates/user/user-base.html:112 +#: templates/user/user-base.html:61 msgid "View submissions" msgstr "" @@ -3056,148 +2916,90 @@ msgstr "" msgid "Rejudge" msgstr "" -#: templates/base.html:230 -#, python-format -msgid "Hello, %(username)s." -msgstr "" - -#: templates/base.html:236 templates/comments/list.html:89 -#: templates/contest/contest-list-tabs.html:24 -#: templates/contest/ranking-table.html:53 -#: templates/problem/problem-list-tabs.html:6 +#: templates/base.html:222 templates/comments/list.html:89 +#: templates/contest/ranking-table.html:39 #: templates/submission/info-base.html:12 -#: templates/submission/submission-list-tabs.html:15 msgid "Admin" msgstr "" -#: templates/base.html:245 +#: templates/base.html:231 msgid "Log out" msgstr "" -#: templates/base.html:254 +#: templates/base.html:240 #: templates/registration/password_reset_complete.html:4 msgid "Log in" msgstr "" -#: templates/base.html:255 templates/registration/registration_form.html:177 +#: templates/base.html:241 templates/registration/registration_form.html:177 msgid "or" msgstr "" -#: templates/base.html:256 +#: templates/base.html:242 msgid "Sign up" msgstr "" -#: templates/base.html:271 +#: templates/base.html:254 msgid "spectating" msgstr "" -#: templates/base.html:284 +#: templates/base.html:267 msgid "This site works best with JavaScript enabled." msgstr "" -#: templates/blog/blog.html:13 templates/comments/list.html:68 -#: templates/comments/list.html:83 templates/contest/contest-tabs.html:23 -#: templates/contest/tag-title.html:9 templates/flatpages/admin_link.html:3 -#: templates/license.html:10 templates/problem/editorial.html:14 +#: templates/blog/content.html:13 templates/comments/list.html:68 +#: templates/comments/list.html:83 templates/contest/tag-title.html:9 +#: templates/flatpages/admin_link.html:3 templates/license.html:10 +#: templates/problem/editorial.html:14 msgid "Edit" msgstr "" -#: templates/blog/blog.html:26 -#, python-format -msgid "" -"\n" -" posted on %(time)s\n" -" " -msgstr "" - -#: templates/blog/content.html:10 -#, fuzzy, python-brace-format -#| msgid "posted time" -msgid "posted on {time}" -msgstr "vrijeme objave" - -#: templates/blog/dashboard.html:21 -#, python-format -msgid "" -"\n" -" on %(time)s\n" -" " -msgstr "" - -#: templates/blog/list.html:93 +#: templates/blog/list.html:85 msgid "Blog" msgstr "" -#: templates/blog/list.html:95 +#: templates/blog/list.html:87 msgid "Events" msgstr "" -#: templates/blog/list.html:100 +#: templates/blog/list.html:92 msgid "News" msgstr "" -#: templates/blog/list.html:115 templates/problem/list.html:347 -#: templates/problem/problem.html:361 +#: templates/blog/list.html:130 templates/problem/problem.html:310 msgid "Clarifications" msgstr "" -#: templates/blog/list.html:121 -msgid "Add" -msgstr "" - -#: templates/blog/list.html:140 templates/problem/list.html:369 -#: templates/problem/problem.html:372 +#: templates/blog/list.html:146 templates/problem/problem.html:321 msgid "No clarifications have been made at this time." msgstr "" -#: templates/blog/list.html:148 +#: templates/blog/list.html:154 msgid "Ongoing contests" msgstr "" -#: templates/blog/list.html:166 +#: templates/blog/list.html:172 msgid "Upcoming contests" msgstr "" -#: templates/blog/list.html:184 -msgid "My open tickets" -msgstr "" - -#: templates/blog/list.html:206 -msgid "New tickets" -msgstr "" - -#: templates/blog/list.html:227 -msgid "New problems" -msgstr "" - -#: templates/blog/list.html:244 +#: templates/blog/list.html:189 msgid "Comment stream" msgstr "" -#: templates/chat/chat.html:305 -msgid "Chat" +#: templates/blog/list.html:208 +msgid "New problems" msgstr "" -#: templates/chat/chat.html:307 templates/chat/chat.html:314 -#, fuzzy -#| msgid "Online Judge" -msgid "Online Users" -msgstr "Evaluator" - -#: templates/chat/chat.html:315 -msgid "Refresh" +#: templates/blog/list.html:225 +msgid "My open tickets" msgstr "" -#: templates/chat/chat.html:333 -msgid "Emoji" +#: templates/blog/list.html:246 +msgid "New tickets" msgstr "" -#: templates/chat/chat.html:334 -msgid "Enter your message" -msgstr "" - -#: templates/chat/message.html:20 -msgid "Delete" +#: templates/chat/chat.html:167 +msgid "Your message" msgstr "" #: templates/comments/list.html:2 @@ -3208,22 +3010,11 @@ msgstr "Komentari" msgid "Please login to vote" msgstr "Molimo, prijavite se da biste mogli glasati" -#: templates/comments/list.html:40 -#, fuzzy, python-brace-format -#| msgid "on {time}" -msgid "commented on {time}" -msgstr "u {time}" - -#: templates/comments/list.html:49 -#, python-format -msgid "edit %(edits)s" -msgstr "" - -#: templates/comments/list.html:51 templates/comments/media-js.html:92 +#: templates/comments/list.html:51 templates/comments/media-js.html:77 msgid "edited" msgstr "" -#: templates/comments/list.html:60 templates/notification/list.html:14 +#: templates/comments/list.html:60 msgid "Link" msgstr "" @@ -3231,54 +3022,36 @@ msgstr "" msgid "Reply" msgstr "" -#: templates/comments/list.html:86 templates/contest/list.html:91 -#: templates/contest/list.html:95 templates/contest/list.html:280 +#: templates/comments/list.html:86 msgid "Hide" msgstr "" -#: templates/comments/list.html:101 -#, python-format -msgid "" -"\n" -" This comment is hidden due " -"to too much negative feedback.\n" -" Click here to view it.\n" -" " -msgstr "" - -#: templates/comments/list.html:121 +#: templates/comments/list.html:120 msgid "There are no comments at the moment." msgstr "" -#: templates/comments/list.html:127 +#: templates/comments/list.html:126 msgid "New comment" msgstr "" -#: templates/comments/list.html:141 +#: templates/comments/list.html:140 msgid "Invalid comment body." msgstr "" -#: templates/comments/list.html:149 +#: templates/comments/list.html:148 msgid "Post!" msgstr "" -#: templates/comments/list.html:157 +#: templates/comments/list.html:156 msgid "Comments are disabled on this page." msgstr "" -#: templates/comments/media-js.html:38 -#, fuzzy -#| msgid "no comments" -msgid "Replying to comment" -msgstr "bez komentara" - -#: templates/comments/media-js.html:87 +#: templates/comments/media-js.html:72 #, python-brace-format msgid "edit {edits}" msgstr "" -#: templates/comments/media-js.html:90 +#: templates/comments/media-js.html:75 msgid "original" msgstr "" @@ -3322,11 +3095,6 @@ msgstr "Petak" msgid "Saturday" msgstr "Subota" -#: templates/contest/clarification.html:52 templates/organization/new.html:10 -#: templates/ticket/new.html:38 -msgid "Create" -msgstr "" - #: templates/contest/clone.html:37 msgid "Enter a new key for the cloned contest:" msgstr "" @@ -3347,177 +3115,97 @@ msgstr "" msgid "Next" msgstr "Sljedeća" -#: templates/contest/contest-list-tabs.html:21 -#: templates/problem/problem-list-tabs.html:5 -msgid "List" -msgstr "" - -#: templates/contest/contest-list-tabs.html:22 -msgid "Calendar" -msgstr "Kalendar" - -#: templates/contest/contest-tabs.html:4 templates/organization/home.html:105 -msgid "Info" -msgstr "" - -#: templates/contest/contest-tabs.html:6 templates/stats/base.html:9 -#: templates/submission/list.html:339 -msgid "Statistics" -msgstr "" - -#: templates/contest/contest-tabs.html:11 -msgid "Rankings" -msgstr "" - -#: templates/contest/contest-tabs.html:16 -msgid "Hidden Rankings" -msgstr "" - -#: templates/contest/contest-tabs.html:21 -msgid "MOSS" -msgstr "" - -#: templates/contest/contest-tabs.html:26 -msgid "Clone" -msgstr "" - -#: templates/contest/contest-tabs.html:38 -#: templates/contest/contest-tabs.html:58 +#: templates/contest/contest-tabs.html:37 msgid "Leave contest" msgstr "" -#: templates/contest/contest-tabs.html:45 templates/contest/list.html:388 +#: templates/contest/contest-tabs.html:44 templates/contest/list.html:293 msgid "Virtual join" msgstr "" -#: templates/contest/contest-tabs.html:56 -msgid "Stop spectating" -msgstr "" - -#: templates/contest/contest-tabs.html:65 +#: templates/contest/contest-tabs.html:64 msgid "Spectate contest" msgstr "" -#: templates/contest/contest-tabs.html:72 +#: templates/contest/contest-tabs.html:70 +#: templates/contest/contest-tabs.html:76 msgid "Join contest" msgstr "" -#: templates/contest/contest-tabs.html:81 +#: templates/contest/contest-tabs.html:85 msgid "Login to participate" msgstr "" -#: templates/contest/contest.html:37 -msgid "Participating virtually." -msgstr "" - -#: templates/contest/contest.html:43 -#, fuzzy -#| msgid "contest id" -msgid "Contest is over." -msgstr "ID natjecanja" - #: templates/contest/contest.html:59 templates/contest/contest.html:63 msgid "F j, Y, G:i T" msgstr "" -#: templates/contest/contest.html:59 -#, python-format -msgid "" -"%(time_limit)s window between %(start_time)s and " -"%(end_time)s" -msgstr "" - -#: templates/contest/contest.html:63 -#, python-format -msgid "%(length)s long starting on %(start_time)s" -msgstr "" - #: templates/contest/contest.html:85 msgid "AC Rate" msgstr "" -#: templates/contest/contest.html:86 templates/contest/list.html:237 -#: templates/contest/list.html:289 templates/contest/list.html:366 -#: templates/problem/list.html:223 templates/problem/list.html:254 +#: templates/contest/contest.html:86 templates/contest/list.html:153 +#: templates/contest/list.html:195 templates/contest/list.html:271 +#: templates/problem/list.html:212 templates/problem/list.html:238 msgid "Users" msgstr "" -#: templates/contest/contest.html:111 templates/problem/list.html:330 +#: templates/contest/contest.html:111 msgid "Editorial" msgstr "" -#: templates/contest/list.html:83 templates/contest/media-js.html:9 +#: templates/contest/list.html:31 templates/contest/media-js.html:9 msgid "Are you sure you want to join?" msgstr "" -#: templates/contest/list.html:84 +#: templates/contest/list.html:32 msgid "" "Joining a contest for the first time starts your timer, after which it " "becomes unstoppable." msgstr "" -#: templates/contest/list.html:92 templates/contest/list.html:278 -msgid "Show" -msgstr "" - -#: templates/contest/list.html:102 templates/problem/list.html:68 -#, fuzzy -#| msgid "Organization" -msgid "Organizations..." -msgstr "Organizacija" - -#: templates/contest/list.html:135 +#: templates/contest/list.html:65 msgid "hidden" msgstr "" -#: templates/contest/list.html:140 +#: templates/contest/list.html:70 msgid "private" msgstr "" -#: templates/contest/list.html:154 +#: templates/contest/list.html:84 msgid "rated" msgstr "" -#: templates/contest/list.html:202 +#: templates/contest/list.html:132 msgid "Spectate" msgstr "" -#: templates/contest/list.html:208 +#: templates/contest/list.html:138 msgid "Join" msgstr "" -#: templates/contest/list.html:220 -#, fuzzy -#| msgid "contests" -msgid "Search contests..." -msgstr "natjecanja" - -#: templates/contest/list.html:229 -msgid "Search" -msgstr "" - -#: templates/contest/list.html:232 +#: templates/contest/list.html:148 msgid "Active Contests" msgstr "" -#: templates/contest/list.html:236 templates/contest/list.html:288 -#: templates/contest/list.html:327 templates/contest/list.html:365 +#: templates/contest/list.html:152 templates/contest/list.html:194 +#: templates/contest/list.html:232 templates/contest/list.html:270 msgid "Contest" msgstr "" -#: templates/contest/list.html:275 +#: templates/contest/list.html:190 msgid "Ongoing Contests" msgstr "" -#: templates/contest/list.html:322 +#: templates/contest/list.html:227 msgid "Upcoming Contests" msgstr "" -#: templates/contest/list.html:350 +#: templates/contest/list.html:255 msgid "There are no scheduled contests at this time." msgstr "" -#: templates/contest/list.html:356 +#: templates/contest/list.html:261 msgid "Past Contests" msgstr "" @@ -3568,73 +3256,49 @@ msgstr "" msgid "Only the following organizations may access this contest:" msgstr "" -#: templates/contest/ranking-table.html:9 templates/problem/search-form.html:35 +#: templates/contest/ranking-table.html:7 msgid "Organization" msgstr "Organizacija" -#: templates/contest/ranking-table.html:10 templates/user/users-table.html:13 -msgid "Full Name" -msgstr "" - -#: templates/contest/ranking-table.html:44 +#: templates/contest/ranking-table.html:30 msgid "Un-Disqualify" msgstr "" -#: templates/contest/ranking-table.html:47 +#: templates/contest/ranking-table.html:33 msgid "Disqualify" msgstr "" -#: templates/contest/ranking.html:187 +#: templates/contest/ranking.html:173 msgid "Are you sure you want to disqualify this participation?" msgstr "" -#: templates/contest/ranking.html:192 +#: templates/contest/ranking.html:178 msgid "Are you sure you want to un-disqualify this participation?" msgstr "" -#: templates/contest/ranking.html:463 +#: templates/contest/ranking.html:252 msgid "View user participation" msgstr "" -#: templates/contest/ranking.html:467 +#: templates/contest/ranking.html:256 msgid "Show organizations" msgstr "" -#: templates/contest/ranking.html:471 -msgid "Show full name" -msgstr "" - -#: templates/contest/ranking.html:474 -msgid "Show friends only" -msgstr "" - -#: templates/contest/ranking.html:477 -msgid "Total score only" -msgstr "" - -#: templates/contest/ranking.html:479 -msgid "Show virtual participation" -msgstr "" - -#: templates/contest/stats.html:51 +#: templates/contest/stats.html:38 msgid "Problem Status Distribution" msgstr "" -#: templates/contest/stats.html:56 +#: templates/contest/stats.html:43 #, fuzzy #| msgid "Problem name" msgid "Problem AC Rate" msgstr "Ime zadatka" -#: templates/contest/stats.html:62 -msgid "Problem Point Distribution" -msgstr "" - -#: templates/contest/stats.html:76 templates/stats/language.html:16 +#: templates/contest/stats.html:48 templates/stats/language.html:16 msgid "Submissions by Language" msgstr "" -#: templates/contest/stats.html:82 templates/stats/language.html:26 +#: templates/contest/stats.html:54 templates/stats/language.html:26 msgid "Language AC Rate" msgstr "" @@ -3643,7 +3307,6 @@ msgid "Source:" msgstr "" #: templates/newsletter/common.html:6 -#: templates/newsletter/newsletter_list.html:15 #: templates/newsletter/subscription_unsubscribe_activated.html:3 #: templates/newsletter/subscription_unsubscribe_activated.html:6 #: templates/newsletter/subscription_update_activated.html:3 @@ -3651,25 +3314,6 @@ msgstr "" msgid "Newsletter" msgstr "" -#: templates/newsletter/newsletter_list.html:2 -#: templates/newsletter/newsletter_list.html:3 -msgid "Newsletter list" -msgstr "" - -#: templates/newsletter/newsletter_list.html:6 -msgid "Subscribe to get the latest emails about upcoming contests and events." -msgstr "" - -#: templates/newsletter/newsletter_list.html:16 -msgid "Subscribe" -msgstr "" - -#: templates/newsletter/newsletter_list.html:30 -#, fuzzy -#| msgid "description" -msgid "Update subscriptions" -msgstr "opis" - #: templates/newsletter/subscription_unsubscribe_activated.html:3 #: templates/newsletter/subscription_unsubscribe_activated.html:6 #: templates/newsletter/subscription_update_activated.html:3 @@ -3731,105 +3375,64 @@ msgid "" "follow in order to update your subscription." msgstr "" -#: templates/notification/list.html:7 -msgid "You have no notifications" -msgstr "" - -#: templates/notification/list.html:13 -msgid "Activity" -msgstr "" - #: templates/organization/edit.html:46 #: templates/organization/requests/pending.html:34 #: templates/ticket/edit-notes.html:4 msgid "Update" msgstr "" -#: templates/organization/home.html:41 +#: templates/organization/home.html:7 msgid "Are you sure you want to leave this organization?" msgstr "" -#: templates/organization/home.html:43 +#: templates/organization/home.html:9 msgid "You will have to rejoin to show up on the organization leaderboard." msgstr "" -#: templates/organization/home.html:45 +#: templates/organization/home.html:11 msgid "You will have to request membership in order to join again." msgstr "" -#: templates/organization/home.html:88 -msgid "Join organization" -msgstr "" - -#: templates/organization/home.html:92 -msgid "Request membership" -msgstr "" - -#: templates/organization/home.html:122 -#, fuzzy -#| msgid "Organization" -msgid "Organization news" -msgstr "Organizacija" - -#: templates/organization/home.html:128 -msgid "There is no news at this time." -msgstr "" - -#: templates/organization/home.html:137 -msgid "Controls" -msgstr "" - -#: templates/organization/home.html:142 -msgid "Edit organization" -msgstr "" - -#: templates/organization/home.html:148 -msgid "View requests" -msgstr "" - -#: templates/organization/home.html:161 -msgid "Admin organization" -msgstr "" - -#: templates/organization/home.html:167 -msgid "View members" -msgstr "" - -#: templates/organization/home.html:174 +#: templates/organization/home.html:24 msgid "Leave organization" msgstr "" -#: templates/organization/home.html:183 -msgid "New private contests" +#: templates/organization/home.html:29 +msgid "Join organization" msgstr "" -#: templates/organization/home.html:193 templates/organization/home.html:208 -#, fuzzy -#| msgid "rate all" -msgid "View all" -msgstr "boduj sve" +#: templates/organization/home.html:33 +msgid "Request membership" +msgstr "" -#: templates/organization/home.html:199 -#, fuzzy -#| msgid "Disallowed problems" -msgid "New private problems" -msgstr "Nedozvoljeni zadaci" +#: templates/organization/home.html:39 +msgid "Edit organization" +msgstr "" -#: templates/organization/list.html:40 -#, fuzzy -#| msgid "private to organizations" -msgid "Show my organizations only" -msgstr "privatno za organizacije" +#: templates/organization/home.html:43 +msgid "View requests" +msgstr "" -#: templates/organization/list.html:47 templates/status/language-list.html:34 -#: templates/user/import/table_csv.html:6 +#: templates/organization/home.html:50 +msgid "Admin organization" +msgstr "" + +#: templates/organization/home.html:55 +msgid "View members" +msgstr "" + +#: templates/organization/list.html:23 templates/status/language-list.html:34 msgid "Name" msgstr "" -#: templates/organization/list.html:48 +#: templates/organization/list.html:24 msgid "Members" msgstr "" +#: templates/organization/new.html:10 templates/ticket/new.html:38 +msgid "Create" +msgstr "" + #: templates/organization/requests/detail.html:13 msgid "User:" msgstr "" @@ -3862,7 +3465,7 @@ msgid "There are no requests to approve." msgstr "" #: templates/organization/requests/pending.html:17 -#: templates/problem/data.html:432 +#: templates/problem/data.html:452 msgid "Delete?" msgstr "" @@ -3898,37 +3501,37 @@ msgstr "" msgid "Enter a new code for the cloned problem:" msgstr "" -#: templates/problem/data.html:119 +#: templates/problem/data.html:108 #, fuzzy #| msgid "Information" msgid "Instruction" msgstr "Informacije" -#: templates/problem/data.html:390 +#: templates/problem/data.html:410 msgid "View YAML" msgstr "" -#: templates/problem/data.html:421 templates/problem/data.html:472 +#: templates/problem/data.html:441 templates/problem/data.html:491 msgid "Apply!" msgstr "" -#: templates/problem/data.html:426 +#: templates/problem/data.html:446 msgid "Type" msgstr "" -#: templates/problem/data.html:427 +#: templates/problem/data.html:447 msgid "Input file" msgstr "" -#: templates/problem/data.html:428 +#: templates/problem/data.html:448 msgid "Output file" msgstr "" -#: templates/problem/data.html:430 +#: templates/problem/data.html:450 msgid "Pretest?" msgstr "" -#: templates/problem/data.html:473 +#: templates/problem/data.html:492 msgid "Add new case" msgstr "" @@ -3940,32 +3543,28 @@ msgid "" "problem yourself is a bannable offence.
" msgstr "" -#: templates/problem/list.html:66 +#: templates/problem/list.html:62 msgid "Filter by type..." msgstr "" -#: templates/problem/list.html:193 +#: templates/problem/list.html:185 msgid "Hot problems" msgstr "" -#: templates/problem/list.html:218 templates/problem/list.html:240 -#: templates/problem/search-form.html:45 templates/user/user-problems.html:57 +#: templates/problem/list.html:207 templates/problem/list.html:224 +#: templates/problem/search-form.html:30 templates/user/user-problems.html:57 msgid "Category" msgstr "" -#: templates/problem/list.html:220 templates/problem/list.html:244 +#: templates/problem/list.html:209 templates/problem/list.html:228 msgid "Types" msgstr "" -#: templates/problem/list.html:251 +#: templates/problem/list.html:235 #, python-format msgid "AC %%" msgstr "" -#: templates/problem/list.html:342 -msgid "Add clarifications" -msgstr "" - #: templates/problem/manage_submission.html:55 msgid "Leave empty to not filter by language" msgstr "" @@ -3974,209 +3573,152 @@ msgstr "" msgid "Leave empty to not filter by result" msgstr "" -#: templates/problem/manage_submission.html:80 +#: templates/problem/manage_submission.html:79 msgid "Need valid values for both start and end IDs." msgstr "" -#: templates/problem/manage_submission.html:83 +#: templates/problem/manage_submission.html:82 msgid "End ID must be after start ID." msgstr "" +#: templates/problem/manage_submission.html:90 +#, python-brace-format +msgid "" +"You are about to rejudge {count} submissions. Are you sure you want to do " +"this?" +msgstr "" + #: templates/problem/manage_submission.html:96 -#, python-brace-format msgid "" -"You are about to {action} {count} submissions. Are you sure you want to do " -"this?" +"You are about to rejudge a few submissions. Are you sure you want to do this?" msgstr "" -#: templates/problem/manage_submission.html:103 -#, python-brace-format -msgid "" -"You are about to {action} a few submissions. Are you sure you want to do " -"this?" +#: templates/problem/manage_submission.html:115 +msgid "Rejudge Submissions" msgstr "" -#: templates/problem/manage_submission.html:127 -#: templates/submission/list.html:309 -msgid "Filter submissions" -msgstr "" - -#: templates/problem/manage_submission.html:132 +#: templates/problem/manage_submission.html:120 msgid "Filter by ID:" msgstr "" -#: templates/problem/manage_submission.html:135 +#: templates/problem/manage_submission.html:123 msgid "Starting ID:" msgstr "" -#: templates/problem/manage_submission.html:139 +#: templates/problem/manage_submission.html:127 msgid "Ending ID:" msgstr "" -#: templates/problem/manage_submission.html:143 +#: templates/problem/manage_submission.html:131 msgid "This range includes both endpoints." msgstr "" -#: templates/problem/manage_submission.html:146 +#: templates/problem/manage_submission.html:134 msgid "Filter by language:" msgstr "" -#: templates/problem/manage_submission.html:154 +#: templates/problem/manage_submission.html:142 msgid "Filter by result:" msgstr "" -#: templates/problem/manage_submission.html:164 -msgid "Action" -msgstr "" - -#: templates/problem/manage_submission.html:166 +#: templates/problem/manage_submission.html:150 msgid "Rejudge selected submissions" msgstr "" -#: templates/problem/manage_submission.html:171 -#, fuzzy -#| msgid "Too many submissions" -msgid "Download selected submissions" -msgstr "Previše poslanih rješenja" - -#: templates/problem/manage_submission.html:177 -#, python-format -msgid "Are you sure you want to rescore %(count)d submissions?" +#: templates/problem/manage_submission.html:157 +msgid "Rescore Everything" msgstr "" -#: templates/problem/manage_submission.html:178 +#: templates/problem/manage_submission.html:163 msgid "Rescore all submissions" msgstr "" -#: templates/problem/problem.html:132 +#: templates/problem/problem.html:91 msgid "View as PDF" msgstr "" -#: templates/problem/problem.html:141 templates/problem/problem.html:151 -#: templates/problem/problem.html:156 +#: templates/problem/problem.html:101 templates/problem/problem.html:111 +#: templates/problem/problem.html:116 msgid "Submit solution" msgstr "" -#: templates/problem/problem.html:144 -#, python-format -msgid "%(counter)s submission left" -msgid_plural "%(counter)s submissions left" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" - -#: templates/problem/problem.html:152 +#: templates/problem/problem.html:112 msgid "0 submissions left" msgstr "" -#: templates/problem/problem.html:164 +#: templates/problem/problem.html:124 msgid "My submissions" msgstr "" -#: templates/problem/problem.html:168 +#: templates/problem/problem.html:128 msgid "Best submissions" msgstr "" -#: templates/problem/problem.html:172 +#: templates/problem/problem.html:132 msgid "Read editorial" msgstr "" -#: templates/problem/problem.html:177 +#: templates/problem/problem.html:137 msgid "Manage tickets" msgstr "" -#: templates/problem/problem.html:181 +#: templates/problem/problem.html:141 msgid "Edit problem" msgstr "" -#: templates/problem/problem.html:183 +#: templates/problem/problem.html:143 msgid "Edit test data" msgstr "" -#: templates/problem/problem.html:188 +#: templates/problem/problem.html:148 msgid "My tickets" msgstr "" -#: templates/problem/problem.html:196 +#: templates/problem/problem.html:156 msgid "Manage submissions" msgstr "" -#: templates/problem/problem.html:202 +#: templates/problem/problem.html:162 msgid "Clone problem" msgstr "" -#: templates/problem/problem.html:209 +#: templates/problem/problem.html:169 msgid "Points:" msgstr "" -#: templates/problem/problem.html:212 templates/problem/problem.html:214 +#: templates/problem/problem.html:172 templates/problem/problem.html:174 msgid "(partial)" msgstr "" -#: templates/problem/problem.html:219 +#: templates/problem/problem.html:179 msgid "Time limit:" msgstr "" -#: templates/problem/problem.html:231 +#: templates/problem/problem.html:191 msgid "Memory limit:" msgstr "" -#: templates/problem/problem.html:250 -#, fuzzy -#| msgid "Authors" -msgid "Author:" -msgid_plural "Authors:" -msgstr[0] "Autori" -msgstr[1] "Autori" -msgstr[2] "Autori" - -#: templates/problem/problem.html:265 -#, fuzzy -#| msgid "Problem code" -msgid "Problem type" -msgid_plural "Problem types" -msgstr[0] "Kod zadatka" -msgstr[1] "Kod zadatka" -msgstr[2] "Kod zadatka" - -#: templates/problem/problem.html:278 +#: templates/problem/problem.html:238 msgid "Allowed languages" msgstr "" -#: templates/problem/problem.html:286 -#, python-format -msgid "No %(lang)s judge online" -msgstr "" - -#: templates/problem/problem.html:297 -msgid "Judge:" -msgid_plural "Judges:" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" - -#: templates/problem/problem.html:314 +#: templates/problem/problem.html:274 msgid "none available" msgstr "" -#: templates/problem/problem.html:326 -#, python-format -msgid "This problem has %(length)s clarification(s)" -msgstr "" - -#: templates/problem/problem.html:350 +#: templates/problem/problem.html:299 msgid "Request clarification" msgstr "" -#: templates/problem/problem.html:352 +#: templates/problem/problem.html:301 msgid "Report an issue" msgstr "" -#: templates/problem/raw.html:64 +#: templates/problem/raw.html:62 msgid "Time Limit:" msgstr "" -#: templates/problem/raw.html:73 +#: templates/problem/raw.html:71 msgid "Memory Limit:" msgstr "" @@ -4200,74 +3742,39 @@ msgstr "" msgid "Show problem types" msgstr "" -#: templates/problem/search-form.html:32 -msgid "Show editorial" -msgstr "" - -#: templates/problem/search-form.html:48 templates/problem/search-form.html:50 -#: templates/submission/submission-list-tabs.html:4 +#: templates/problem/search-form.html:33 templates/problem/search-form.html:35 msgid "All" msgstr "" -#: templates/problem/search-form.html:62 +#: templates/problem/search-form.html:46 msgid "Problem types" msgstr "" -#: templates/problem/search-form.html:73 +#: templates/problem/search-form.html:57 msgid "Point range" msgstr "" -#: templates/problem/search-form.html:79 templates/submission/list.html:331 +#: templates/problem/search-form.html:63 templates/submission/list.html:331 #: templates/ticket/list.html:248 msgid "Go" msgstr "" -#: templates/problem/search-form.html:80 +#: templates/problem/search-form.html:64 msgid "Random" msgstr "" -#: templates/problem/submit.html:117 -msgid "Your source code must contain at most 65536 characters." -msgstr "" - -#: templates/problem/submit.html:204 -#, python-format -msgid "" -"Warning! Your default language, %(default_language)s, is " -"unavailable for this problem and has been deselected." -msgstr "" - -#: templates/problem/submit.html:215 -#, python-format -msgid "" -"\n" -" You have %(left)s submission left\n" -" " -msgid_plural "" -"\n" -" You have %(left)s submissions left\n" -" " -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" - -#: templates/problem/submit.html:224 +#: templates/problem/submit.html:212 msgid "You have 0 submissions left" msgstr "" -#: templates/problem/submit.html:258 +#: templates/problem/submit.html:250 msgid "No judge is available for this problem." msgstr "" -#: templates/problem/submit.html:262 +#: templates/problem/submit.html:252 msgid "Submit!" msgstr "" -#: templates/registration/activate.html:3 -#, python-format -msgid "%(key)s is an invalid activation key." -msgstr "" - #: templates/registration/activation_complete.html:3 msgid "Your account has been successfully activated." msgstr "" @@ -4325,13 +3832,6 @@ msgid "" "you registered with, and check your spam folder." msgstr "" -#: templates/registration/password_reset_email.txt:1 -#, python-format -msgid "" -"You're receiving this email because you requested a password reset for your " -"user account at %(site_name)s." -msgstr "" - #: templates/registration/password_reset_email.txt:3 msgid "Please go to the following page and choose a new password:" msgstr "" @@ -4344,16 +3844,6 @@ msgstr "" msgid "Thanks for using our site!" msgstr "" -#: templates/registration/password_reset_email.txt:11 -#, python-format -msgid "The %(site_name)s team" -msgstr "" - -#: templates/registration/password_reset_subject.txt:1 -#, python-format -msgid "Password reset on %(site_name)s" -msgstr "" - #: templates/registration/profile_creation.html:36 #: templates/registration/username_select.html:7 msgid "Continue >" @@ -4390,20 +3880,19 @@ msgstr "" msgid "Affiliated organizations" msgstr "" -#: templates/registration/registration_form.html:195 -#: templates/user/edit-profile.html:128 +#: templates/registration/registration_form.html:192 msgid "Notify me about upcoming contests" msgstr "" -#: templates/registration/registration_form.html:209 +#: templates/registration/registration_form.html:206 msgid "By registering, you agree to our" msgstr "" -#: templates/registration/registration_form.html:210 +#: templates/registration/registration_form.html:207 msgid "Terms & Conditions" msgstr "" -#: templates/registration/registration_form.html:213 +#: templates/registration/registration_form.html:210 msgid "Register!" msgstr "" @@ -4413,11 +3902,6 @@ msgstr "" msgid "Enter the 6-digit code generated by your app:" msgstr "" -#: templates/registration/totp_auth.html:41 -#, python-format -msgid "If you lost your authentication device, please contact us at %(email)s." -msgstr "" - #: templates/registration/totp_disable.html:38 msgid "" "To protect your account, you must first authenticate before you can disable " @@ -4436,6 +3920,10 @@ msgstr "" msgid "Or enter this code manually:" msgstr "" +#: templates/stats/base.html:9 templates/submission/list.html:339 +msgid "Statistics" +msgstr "" + #: templates/stats/language.html:11 msgid "Submission Statistics" msgstr "" @@ -4461,7 +3949,6 @@ msgid "Ping" msgstr "" #: templates/status/judge-status-table.html:8 -#: templates/user/import/index.html:104 msgid "Load" msgstr "" @@ -4477,7 +3964,6 @@ msgid "There are no judges available at this time." msgstr "" #: templates/status/language-list.html:33 templates/ticket/list.html:261 -#: templates/user/import/table_csv.html:3 msgid "ID" msgstr "" @@ -4485,22 +3971,6 @@ msgstr "" msgid "Runtime Info" msgstr "" -#: templates/status/status-tabs.html:4 -msgid "Judges" -msgstr "" - -#: templates/status/status-tabs.html:6 -msgid "Version Matrix" -msgstr "" - -#: templates/submission/internal-error-message.html:3 -#, python-format -msgid "" -"An internal error occurred while grading, and the %(SITE_NAME)s " -"administrators have been notified.
In the meantime, try resubmitting in " -"a few seconds." -msgstr "" - #: templates/submission/internal-error-message.html:8 msgid "An internal error occurred while grading." msgstr "" @@ -4517,6 +3987,10 @@ msgstr "" msgid "Filter by language..." msgstr "" +#: templates/submission/list.html:309 +msgid "Filter submissions" +msgstr "" + #: templates/submission/list.html:345 msgid "Total:" msgstr "" @@ -4573,72 +4047,71 @@ msgstr "" msgid "Execution Results" msgstr "" -#: templates/submission/status-testcases.html:34 +#: templates/submission/status-testcases.html:31 +msgid "Batch " +msgstr "" + +#: templates/submission/status-testcases.html:43 msgid "Overall: " msgstr "" -#: templates/submission/status-testcases.html:48 +#: templates/submission/status-testcases.html:57 #, fuzzy #| msgid "Points" msgid "Point: " msgstr "Bodovi" -#: templates/submission/status-testcases.html:53 +#: templates/submission/status-testcases.html:62 #, fuzzy #| msgid "Time" msgid "Time: " msgstr "Vrijeme" -#: templates/submission/status-testcases.html:62 +#: templates/submission/status-testcases.html:71 #, fuzzy #| msgid "Memory" msgid "Memory: " msgstr "Memorija" -#: templates/submission/status-testcases.html:73 -msgid "Batch " +#: templates/submission/status-testcases.html:84 +msgid "Case" msgstr "" -#: templates/submission/status-testcases.html:84 -#: templates/submission/status-testcases.html:113 +#: templates/submission/status-testcases.html:86 +msgid "Pretest" +msgstr "" + +#: templates/submission/status-testcases.html:88 +msgid "Test case" +msgstr "" + +#: templates/submission/status-testcases.html:99 #, fuzzy #| msgid "Points" msgid "Point" msgstr "Bodovi" -#: templates/submission/status-testcases.html:99 -msgid "Case" -msgstr "" - -#: templates/submission/status-testcases.html:101 -msgid "Pretest" -msgstr "" - -#: templates/submission/status-testcases.html:103 -msgid "Test case" -msgstr "" - -#: templates/submission/status-testcases.html:141 +#: templates/submission/status-testcases.html:121 msgid "Input:" msgstr "" -#: templates/submission/status-testcases.html:145 +#: templates/submission/status-testcases.html:125 msgid "Output:" msgstr "" -#: templates/submission/status-testcases.html:149 +#: templates/submission/status-testcases.html:129 msgid "Answer:" msgstr "" -#: templates/submission/status-testcases.html:154 +#: templates/submission/status-testcases.html:134 msgid "Judge feedback:" msgstr "" -#: templates/submission/status-testcases.html:175 +#: templates/submission/status-testcases.html:157 msgid "Passing pretests does not guarantee a full score on system tests." msgstr "" -#: templates/submission/status-testcases.html:178 +#: templates/submission/status-testcases.html:160 msgid "Submission aborted!" msgstr "" @@ -4650,24 +4123,11 @@ msgstr "" msgid "Abort" msgstr "" -#: templates/submission/submission-list-tabs.html:6 -msgid "Mine" -msgstr "" - -#: templates/submission/submission-list-tabs.html:9 -msgid "Best" -msgstr "" - -#: templates/submission/submission-list-tabs.html:12 -#, python-format -msgid "%(user)s's" -msgstr "" - -#: templates/ticket/list.html:135 templates/ticket/ticket.html:273 +#: templates/ticket/list.html:135 templates/ticket/ticket.html:257 msgid "Reopened: " msgstr "" -#: templates/ticket/list.html:138 templates/ticket/ticket.html:274 +#: templates/ticket/list.html:138 templates/ticket/ticket.html:258 msgid "Closed: " msgstr "" @@ -4691,7 +4151,7 @@ msgstr "" msgid "Title" msgstr "" -#: templates/ticket/list.html:264 templates/ticket/ticket.html:369 +#: templates/ticket/list.html:264 templates/ticket/ticket.html:328 msgid "Assignees" msgstr "" @@ -4706,36 +4166,32 @@ msgid "" "a problem, ask in the comments instead." msgstr "" -#: templates/ticket/ticket.html:355 -msgid "Post" -msgstr "" - -#: templates/ticket/ticket.html:363 +#: templates/ticket/ticket.html:322 msgid "Associated object" msgstr "" -#: templates/ticket/ticket.html:374 +#: templates/ticket/ticket.html:333 msgid "No one is assigned." msgstr "" -#: templates/ticket/ticket.html:380 +#: templates/ticket/ticket.html:339 msgid "Close ticket" msgstr "" -#: templates/ticket/ticket.html:382 +#: templates/ticket/ticket.html:341 msgid "Reopen ticket" msgstr "" -#: templates/ticket/ticket.html:386 +#: templates/ticket/ticket.html:345 msgid "Assignee notes" msgstr "" -#: templates/ticket/ticket.html:393 templates/widgets/select_all.html:4 +#: templates/ticket/ticket.html:352 templates/widgets/select_all.html:4 msgid "Nothing here." msgstr "" -#: templates/user/base-users-table.html:3 -msgid "Rank" +#: templates/ticket/ticket.html:385 +msgid "Post" msgstr "" #: templates/user/base-users.html:14 templates/user/base-users.html:69 @@ -4782,195 +4238,50 @@ msgstr "" msgid "Update profile" msgstr "" -#: templates/user/import/index.html:31 -msgid "Upload CSV only" -msgstr "" - -#: templates/user/import/index.html:100 -#, fuzzy -#| msgid "User" -msgid "User File" -msgstr "Korisnik" - -#: templates/user/import/index.html:102 -msgid "Sample" -msgstr "" - -#: templates/user/import/index.html:105 templates/user/user-list-tabs.html:8 -msgid "Import" -msgstr "" - -#: templates/user/import/table_csv.html:7 -msgid "School" -msgstr "" - -#: templates/user/pp-row.html:22 -#, python-format -msgid "" -"\n" -" weighted %(weight)s%%\n" -" " -msgstr "" - -#: templates/user/pp-row.html:27 -#, python-format -msgid "%(pp).1fpp" -msgstr "" - -#: templates/user/pp-row.html:29 -#, python-format -msgid "%(pp).0fpp" -msgstr "" - -#: templates/user/user-about.html:23 -#, python-format -msgid "%(counter)s problem solved" -msgid_plural "%(counter)s problems solved" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" - -#: templates/user/user-about.html:35 -#, fuzzy -#| msgid "allows partial points" -msgid "Total points" -msgstr "dopušteno djelomično bodovanje" - -#: templates/user/user-about.html:45 -#, fuzzy -#| msgid "Rating" -msgid "Rank by rating" -msgstr "Bodovi" - -#: templates/user/user-about.html:52 -msgid "Rank by points" -msgstr "" - -#: templates/user/user-about.html:64 +#: templates/user/user-about.html:14 msgid "From" msgstr "" -#: templates/user/user-about.html:75 +#: templates/user/user-about.html:25 msgid "Admin Notes" msgstr "" -#: templates/user/user-about.html:90 +#: templates/user/user-about.html:40 msgid "You have not shared any information." msgstr "" -#: templates/user/user-about.html:92 +#: templates/user/user-about.html:42 msgid "This user has not shared any information." msgstr "" -#: templates/user/user-about.html:101 -msgid "Awards" +#: templates/user/user-base.html:50 +msgid "Rank by points:" msgstr "" -#: templates/user/user-about.html:112 -#, fuzzy, python-format -#| msgctxt "contest problem" -#| msgid "%(problem)s in %(contest)s" -msgid "%(label)s (%(date)s)" -msgstr "%(problem)s u %(contest)s" - -#: templates/user/user-about.html:130 -#, fuzzy -#| msgid "Monday" -msgid "Mon" -msgstr "Ponedjeljak" - -#: templates/user/user-about.html:135 -#, fuzzy -#| msgid "Tuesday" -msgid "Tues" -msgstr "Utorak" - -#: templates/user/user-about.html:140 -msgid "Wed" +#: templates/user/user-base.html:53 +msgid "Total points:" msgstr "" -#: templates/user/user-about.html:145 -#, fuzzy -#| msgid "Thursday" -msgid "Thurs" -msgstr "Četvrtak" - -#: templates/user/user-about.html:150 -#, fuzzy -#| msgid "Friday" -msgid "Fri" -msgstr "Petak" - -#: templates/user/user-about.html:155 -#, fuzzy -#| msgid "Status" -msgid "Sat" -msgstr "Status predanog rješenja" - -#: templates/user/user-about.html:160 -#, fuzzy -#| msgid "Sunday" -msgid "Sun" -msgstr "Nedjelja" - -#: templates/user/user-about.html:169 -msgid "Less" +#: templates/user/user-base.html:68 +msgid "Rank by rating:" msgstr "" -#: templates/user/user-about.html:175 -msgid "More" +#: templates/user/user-base.html:70 +msgid "Rating:" msgstr "" -#: templates/user/user-about.html:184 -#, fuzzy -#| msgid "History" -msgid "Rating History" -msgstr "Povijest" - -#: templates/user/user-about.html:255 -msgid "past year" -msgstr "" - -#: templates/user/user-about.html:272 -#, fuzzy -#| msgid "All submissions" -msgid "total submission(s)" -msgstr "Sva predana rješenja" - -#: templates/user/user-about.html:276 -msgid "submissions in the last year" -msgstr "" - -#: templates/user/user-base.html:101 -msgid "Unfollow" -msgstr "" - -#: templates/user/user-base.html:104 -msgid "Follow" -msgstr "" - -#: templates/user/user-base.html:120 -#, fuzzy -#| msgid "contest rated" -msgid "Contests written" -msgstr "bodovanje natjecanja" - -#: templates/user/user-base.html:124 +#: templates/user/user-base.html:71 msgid "Volatility:" msgstr "" -#: templates/user/user-base.html:128 +#: templates/user/user-base.html:72 msgid "Min. rating:" msgstr "" -#: templates/user/user-base.html:132 +#: templates/user/user-base.html:73 msgid "Max rating:" msgstr "" -#: templates/user/user-list-tabs.html:5 -msgid "Friends" -msgstr "" - #: templates/user/user-problems.html:35 msgid "Points Breakdown" msgstr "" @@ -4991,47 +4302,13 @@ msgstr "" msgid "Hide problems I've solved" msgstr "" -#: templates/user/user-problems.html:93 -#, python-format -msgid "%(points).1f points" -msgstr "" - #: templates/user/user-problems.html:99 msgid "Score" msgstr "" -#: templates/user/user-problems.html:110 -#, python-format -msgid "%(points)s / %(total)s" -msgstr "" - -#: templates/user/user-tabs.html:7 -#, fuzzy -#| msgid "personae non gratae" -msgid "Impersonate" -msgstr "persona non grata" - -#: templates/user/user-tabs.html:13 -msgid "Admin User" -msgstr "" - -#: templates/user/user-tabs.html:16 -msgid "Admin Profile" -msgstr "" - #: templates/widgets/select_all.html:8 msgid "Check all" msgstr "" -#, fuzzy -#~| msgid "All submissions for %s" -#~ msgid "%(cnt)d submission on %(date)s" -#~ msgid_plural "%(cnt)d submissions on %(date)s" -#~ msgstr[0] "Sva predana rješenja za korisnika %s" -#~ msgstr[1] "Sva predana rješenja za korisnika %s" -#~ msgstr[2] "Sva predana rješenja za korisnika %s" - -#, fuzzy -#~| msgid "Rescore the selected submissions" -#~ msgid "This will rescore %(count)d submissions." -#~ msgstr "Ponovno ocijeni označena predana rješenja" +#~ msgid "Calendar" +#~ msgstr "Kalendar" diff --git a/locale/hr/LC_MESSAGES/djangojs.po b/locale/hr/LC_MESSAGES/djangojs.po index 5f9bde4..ef0d238 100644 --- a/locale/hr/LC_MESSAGES/djangojs.po +++ b/locale/hr/LC_MESSAGES/djangojs.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: dmoj\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-07-20 23:30+0700\n" +"POT-Creation-Date: 2019-10-01 23:12+0000\n" "PO-Revision-Date: 2019-11-11 22:05\n" "Last-Translator: Icyene\n" "Language-Team: Croatian\n" @@ -10,8 +10,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" -"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: dmoj\n" "X-Crowdin-Language: hr\n" @@ -29,3 +28,4 @@ msgstr[2] "%d dana %h:%m:%s" msgctxt "time format without day" msgid "%h:%m:%s" msgstr "%h:%m:%s" + diff --git a/locale/hu/LC_MESSAGES/django.po b/locale/hu/LC_MESSAGES/django.po index 0707642..4f9c6df 100644 --- a/locale/hu/LC_MESSAGES/django.po +++ b/locale/hu/LC_MESSAGES/django.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: dmoj\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-10-25 05:59+0700\n" +"POT-Creation-Date: 2020-04-10 01:26-0500\n" "PO-Revision-Date: 2019-11-11 22:05\n" "Last-Translator: Icyene\n" "Language-Team: Hungarian\n" @@ -16,93 +16,93 @@ msgstr "" "X-Crowdin-Language: hu\n" "X-Crowdin-File: django.po\n" -#: chat_box/models.py:16 judge/admin/interface.py:110 -#: judge/models/contest.py:403 judge/models/contest.py:528 -#: judge/models/profile.py:211 +#: chat_box/models.py:15 judge/admin/interface.py:107 +#: judge/models/contest.py:257 judge/models/contest.py:381 +#: judge/models/profile.py:191 msgid "user" msgstr "felhasználó" -#: chat_box/models.py:17 judge/models/comment.py:43 judge/models/comment.py:191 +#: chat_box/models.py:16 judge/models/comment.py:42 msgid "posted time" msgstr "hozzászólás ideje" -#: chat_box/models.py:18 judge/models/comment.py:47 +#: chat_box/models.py:17 judge/models/comment.py:46 msgid "body of comment" msgstr "hozzászólás törzse" -#: chat_box/views.py:29 templates/chat/chat.html:4 +#: chat_box/views.py:29 msgid "Chat Box" msgstr "" -#: dmoj/settings.py:355 +#: dmoj/settings.py:349 msgid "German" msgstr "Német" -#: dmoj/settings.py:356 +#: dmoj/settings.py:350 msgid "English" msgstr "Angol" -#: dmoj/settings.py:357 +#: dmoj/settings.py:351 msgid "Spanish" msgstr "Spanyol" -#: dmoj/settings.py:358 +#: dmoj/settings.py:352 msgid "French" msgstr "Francia" -#: dmoj/settings.py:359 +#: dmoj/settings.py:353 msgid "Croatian" msgstr "Horvát" -#: dmoj/settings.py:360 +#: dmoj/settings.py:354 msgid "Hungarian" msgstr "" -#: dmoj/settings.py:361 +#: dmoj/settings.py:355 msgid "Japanese" msgstr "" -#: dmoj/settings.py:362 +#: dmoj/settings.py:356 msgid "Korean" msgstr "Koreai" -#: dmoj/settings.py:363 +#: dmoj/settings.py:357 msgid "Brazilian Portuguese" msgstr "" -#: dmoj/settings.py:364 +#: dmoj/settings.py:358 msgid "Romanian" msgstr "Román" -#: dmoj/settings.py:365 +#: dmoj/settings.py:359 msgid "Russian" msgstr "Orosz" -#: dmoj/settings.py:366 +#: dmoj/settings.py:360 msgid "Serbian (Latin)" msgstr "Szerb (latin)" -#: dmoj/settings.py:367 +#: dmoj/settings.py:361 msgid "Turkish" msgstr "" -#: dmoj/settings.py:368 +#: dmoj/settings.py:362 msgid "Vietnamese" msgstr "Vietnami" -#: dmoj/settings.py:369 +#: dmoj/settings.py:363 msgid "Simplified Chinese" msgstr "Egyszerűsített kínai" -#: dmoj/settings.py:370 +#: dmoj/settings.py:364 msgid "Traditional Chinese" msgstr "" -#: dmoj/urls.py:58 +#: dmoj/urls.py:57 msgid "Login" msgstr "Belépés" -#: dmoj/urls.py:106 templates/base.html:193 +#: dmoj/urls.py:105 templates/base.html:190 msgid "Home" msgstr "Nyitólap" @@ -132,92 +132,90 @@ msgstr "Kommentek megjelenítése" msgid "Associated page" msgstr "Kapcsolódó lap" -#: judge/admin/contest.py:30 +#: judge/admin/contest.py:28 msgid "Included contests" msgstr "Hozzárendelt versenyek" -#: judge/admin/contest.py:66 templates/contest/clarification.html:42 -#: templates/contest/contest.html:83 templates/contest/moss.html:43 -#: templates/problem/list.html:214 templates/problem/list.html:232 -#: templates/problem/list.html:350 templates/user/user-problems.html:56 +#: judge/admin/contest.py:64 templates/contest/contest.html:83 +#: templates/contest/moss.html:43 templates/problem/list.html:206 +#: templates/problem/list.html:221 templates/user/user-problems.html:56 #: templates/user/user-problems.html:98 msgid "Problem" msgstr "Feladat" -#: judge/admin/contest.py:119 +#: judge/admin/contest.py:112 msgid "Settings" msgstr "" -#: judge/admin/contest.py:121 +#: judge/admin/contest.py:114 msgid "Scheduling" msgstr "Időbeosztás" -#: judge/admin/contest.py:122 templates/organization/home.html:107 +#: judge/admin/contest.py:115 msgid "Details" msgstr "Részletek" -#: judge/admin/contest.py:123 +#: judge/admin/contest.py:116 msgid "Format" msgstr "" -#: judge/admin/contest.py:124 templates/contest/ranking-table.html:7 -#: templates/user/user-about.html:15 templates/user/user-about.html:45 +#: judge/admin/contest.py:117 templates/contest/ranking-table.html:5 msgid "Rating" msgstr "Értékelés" -#: judge/admin/contest.py:125 +#: judge/admin/contest.py:118 msgid "Access" msgstr "" -#: judge/admin/contest.py:127 judge/admin/problem.py:131 +#: judge/admin/contest.py:120 judge/admin/problem.py:131 msgid "Justice" msgstr "Igazságszolgáltatás" -#: judge/admin/contest.py:207 +#: judge/admin/contest.py:158 #, python-format msgid "%d contest successfully marked as visible." msgid_plural "%d contests successfully marked as visible." msgstr[0] "" msgstr[1] "" -#: judge/admin/contest.py:210 +#: judge/admin/contest.py:161 msgid "Mark contests as visible" msgstr "" -#: judge/admin/contest.py:216 +#: judge/admin/contest.py:165 #, python-format msgid "%d contest successfully marked as hidden." msgid_plural "%d contests successfully marked as hidden." msgstr[0] "" msgstr[1] "" -#: judge/admin/contest.py:219 +#: judge/admin/contest.py:168 msgid "Mark contests as hidden" msgstr "" -#: judge/admin/contest.py:233 judge/admin/submission.py:164 +#: judge/admin/contest.py:182 judge/admin/submission.py:164 #, python-format msgid "%d submission was successfully scheduled for rejudging." msgid_plural "%d submissions were successfully scheduled for rejudging." msgstr[0] "" msgstr[1] "" -#: judge/admin/contest.py:308 +#: judge/admin/contest.py:256 #, python-format msgid "%d participation recalculated." msgid_plural "%d participations recalculated." msgstr[0] "" msgstr[1] "" -#: judge/admin/contest.py:311 +#: judge/admin/contest.py:259 msgid "Recalculate results" msgstr "" -#: judge/admin/contest.py:315 judge/admin/organization.py:65 +#: judge/admin/contest.py:263 judge/admin/organization.py:65 msgid "username" msgstr "felhasználónév" -#: judge/admin/contest.py:320 templates/base.html:277 +#: judge/admin/contest.py:268 templates/base.html:260 msgid "virtual" msgstr "virtuális" @@ -225,15 +223,15 @@ msgstr "virtuális" msgid "link path" msgstr "csatolási útvonal" -#: judge/admin/interface.py:65 +#: judge/admin/interface.py:62 msgid "Content" msgstr "Tartalom" -#: judge/admin/interface.py:66 +#: judge/admin/interface.py:63 msgid "Summary" msgstr "Összefoglalás" -#: judge/admin/interface.py:151 +#: judge/admin/interface.py:148 msgid "object" msgstr "" @@ -255,9 +253,8 @@ msgid "Taxonomy" msgstr "Rendszerezés" #: judge/admin/problem.py:128 templates/contest/contest.html:84 -#: templates/problem/data.html:429 templates/problem/list.html:222 -#: templates/problem/list.html:248 templates/user/base-users-table.html:10 -#: templates/user/user-about.html:36 templates/user/user-about.html:52 +#: templates/problem/data.html:449 templates/problem/list.html:211 +#: templates/problem/list.html:232 templates/user/base-users-table.html:10 #: templates/user/user-problems.html:58 msgid "Points" msgstr "Pontok" @@ -306,7 +303,6 @@ msgid "timezone" msgstr "időzóna" #: judge/admin/profile.py:86 judge/admin/submission.py:211 -#: templates/notification/list.html:12 #: templates/organization/requests/log.html:9 #: templates/organization/requests/pending.html:12 #: templates/ticket/list.html:263 @@ -314,7 +310,6 @@ msgid "User" msgstr "Felhasználó" #: judge/admin/profile.py:91 templates/registration/registration_form.html:145 -#: templates/user/import/table_csv.html:8 msgid "Email" msgstr "Email" @@ -347,7 +342,7 @@ msgstr "Tiltott feladatok" msgid "These problems are NOT allowed to be submitted in this language" msgstr "Ezekre a feladatokra nem lehet megoldást beküldeni ezen a nyelven" -#: judge/admin/runtime.py:83 templates/problem/list.html:352 +#: judge/admin/runtime.py:83 msgid "Description" msgstr "Leírás" @@ -394,7 +389,7 @@ msgstr "Nincs jogosultságod ilyen sok feltöltés újratesztelésére." msgid "Rejudge the selected submissions" msgstr "A kiválasztott feltöltések újratesztelése" -#: judge/admin/submission.py:193 judge/views/problem_manage.py:159 +#: judge/admin/submission.py:193 judge/views/problem_manage.py:128 #, python-format msgid "%d submission were successfully rescored." msgid_plural "%d submissions were successfully rescored." @@ -405,8 +400,7 @@ msgstr[1] "%d feltöltés sikeresen újrapontozva." msgid "Rescore the selected submissions" msgstr "A kiválasztott feltöltések újrapontozása" -#: judge/admin/submission.py:200 templates/problem/list.html:216 -#: templates/problem/list.html:236 +#: judge/admin/submission.py:200 msgid "Problem code" msgstr "Feladat azonosító" @@ -414,12 +408,10 @@ msgstr "Feladat azonosító" msgid "Problem name" msgstr "Feladat név" -#: judge/admin/submission.py:215 templates/notification/list.html:15 -#: templates/organization/requests/log.html:10 +#: judge/admin/submission.py:215 templates/organization/requests/log.html:10 #: templates/organization/requests/pending.html:13 -#: templates/problem/list.html:351 -#: templates/submission/status-testcases.html:125 -#: templates/submission/status-testcases.html:127 +#: templates/submission/status-testcases.html:105 +#: templates/submission/status-testcases.html:107 msgid "Time" msgstr "Idő" @@ -433,7 +425,7 @@ msgstr "%d KB" msgid "%.2f MB" msgstr "%.2f MB" -#: judge/admin/submission.py:227 templates/submission/status-testcases.html:132 +#: judge/admin/submission.py:227 templates/submission/status-testcases.html:112 msgid "Memory" msgstr "Memória" @@ -453,20 +445,20 @@ msgstr "Ezek a problémák tartoznak ehhez a típushoz" msgid "Online Judge" msgstr "Online tesztelő" -#: judge/comments.py:60 +#: judge/comments.py:41 msgid "Comment body" msgstr "Hozzászólás törzse" -#: judge/comments.py:66 judge/views/ticket.py:63 +#: judge/comments.py:47 judge/views/ticket.py:46 msgid "Your part is silent, little toad." msgstr "Az útvonalad csendes, kis varangy." -#: judge/comments.py:69 templates/comments/list.html:132 +#: judge/comments.py:50 templates/comments/list.html:131 msgid "" "You need to have solved at least one problem before your voice can be heard." msgstr "Legalább 1 feladatot meg kell oldanod mielőtt hozzászólsz." -#: judge/comments.py:113 +#: judge/comments.py:92 msgid "Posted comment" msgstr "Elküldött hozzászólás" @@ -482,10 +474,6 @@ msgstr "" msgid "ECOO" msgstr "" -#: judge/contest_format/icpc.py:19 -msgid "ICPC" -msgstr "" - #: judge/contest_format/ioi.py:19 msgid "IOI" msgstr "" @@ -498,60 +486,52 @@ msgstr "Iratkozz fel hírlevelünkre" msgid "Enable experimental features" msgstr "Kísérleti funkciók engedélyezése" -#: judge/forms.py:57 judge/views/organization.py:168 judge/views/register.py:49 +#: judge/forms.py:57 judge/views/organization.py:127 #, python-brace-format msgid "You may not be part of more than {count} public organizations." msgstr "Nem lehetsz tagja több mint {count} nyilvános csoportnak." -#: judge/forms.py:82 -#, fuzzy -#| msgid "judge" -msgid "Any judge" -msgstr "bíró" - -#: judge/forms.py:112 judge/views/register.py:26 +#: judge/forms.py:107 judge/views/register.py:26 #: templates/registration/registration_form.html:139 #: templates/user/base-users-table.html:5 -#: templates/user/import/table_csv.html:4 msgid "Username" msgstr "Felhasználóinév" -#: judge/forms.py:113 templates/registration/registration_form.html:151 +#: judge/forms.py:108 templates/registration/registration_form.html:151 #: templates/registration/registration_form.html:165 -#: templates/user/import/table_csv.html:5 msgid "Password" msgstr "Jelszó" -#: judge/forms.py:135 +#: judge/forms.py:130 msgid "Two Factor Authentication tokens must be 6 decimal digits." msgstr "" -#: judge/forms.py:144 templates/registration/totp_auth.html:32 +#: judge/forms.py:139 templates/registration/totp_auth.html:32 msgid "Invalid Two Factor Authentication token." msgstr "" -#: judge/forms.py:148 judge/models/problem.py:97 +#: judge/forms.py:143 judge/models/problem.py:97 msgid "Problem code must be ^[a-z0-9]+$" msgstr "A feladat azonosítónak ^[a-z0-9]+$ kell lennie" -#: judge/forms.py:153 +#: judge/forms.py:148 msgid "Problem with code already exists." msgstr "" -#: judge/forms.py:158 judge/models/contest.py:61 +#: judge/forms.py:153 judge/models/contest.py:52 msgid "Contest id must be ^[a-z0-9]+$" msgstr "A verseny azonosítójának ^[a-z0-9]+$ kell lennie" -#: judge/forms.py:163 +#: judge/forms.py:158 msgid "Contest with key already exists." msgstr "" -#: judge/jinja2/datetime.py:26 templates/blog/blog.html:26 +#: judge/jinja2/datetime.py:26 templates/blog/content.html:27 #: templates/blog/dashboard.html:21 msgid "N j, Y, g:i a" msgstr "N j, Y, g:i a" -#: judge/jinja2/datetime.py:26 templates/chat/message.html:13 +#: judge/jinja2/datetime.py:26 #, python-brace-format msgid "{time}" msgstr "{time}" @@ -581,174 +561,122 @@ msgstr "MathJax SVG/PNG fallback-kel" msgid "Detect best quality" msgstr "Legjobb minőség detektálása" -#: judge/models/comment.py:26 +#: judge/models/comment.py:25 msgid "Page code must be ^[pcs]:[a-z0-9]+$|^b:\\d+$" msgstr "" -#: judge/models/comment.py:42 +#: judge/models/comment.py:41 msgid "commenter" msgstr "hozzászóló" -#: judge/models/comment.py:44 judge/models/comment.py:177 +#: judge/models/comment.py:43 judge/models/comment.py:176 msgid "associated page" msgstr "" -#: judge/models/comment.py:46 +#: judge/models/comment.py:45 msgid "votes" msgstr "szavazatok" -#: judge/models/comment.py:48 +#: judge/models/comment.py:47 msgid "hide the comment" msgstr "hozzászólás elrejtése" -#: judge/models/comment.py:49 +#: judge/models/comment.py:48 msgid "parent" msgstr "előzmény" -#: judge/models/comment.py:54 judge/models/comment.py:192 +#: judge/models/comment.py:53 msgid "comment" msgstr "hozzászólás" -#: judge/models/comment.py:55 +#: judge/models/comment.py:54 msgid "comments" msgstr "hozzászólások" -#: judge/models/comment.py:137 judge/models/problem.py:443 +#: judge/models/comment.py:136 judge/models/problem.py:406 #, python-format msgid "Editorial for %s" msgstr "Megoldási útmutató %s-hez" -#: judge/models/comment.py:172 +#: judge/models/comment.py:171 msgid "comment vote" msgstr "hozzászólás értékelése" -#: judge/models/comment.py:173 +#: judge/models/comment.py:172 msgid "comment votes" msgstr "hozzászólás értékelései" -#: judge/models/comment.py:182 +#: judge/models/comment.py:181 msgid "Override comment lock" msgstr "" -#: judge/models/comment.py:190 -msgid "owner" -msgstr "" - -#: judge/models/comment.py:193 judge/models/message.py:16 -msgid "read" -msgstr "olvas" - -#: judge/models/comment.py:194 -#, fuzzy -#| msgid "Category" -msgid "category" -msgstr "Kategória" - -#: judge/models/comment.py:195 -msgid "html link to comments, used for non-comments" -msgstr "" - -#: judge/models/comment.py:196 -msgid "who trigger, used for non-comment" -msgstr "" - -#: judge/models/contest.py:23 +#: judge/models/contest.py:22 msgid "Invalid colour." msgstr "Érvénytelen szín." -#: judge/models/contest.py:25 +#: judge/models/contest.py:24 msgid "tag name" msgstr "címke neve" -#: judge/models/contest.py:26 +#: judge/models/contest.py:25 msgid "Lowercase letters and hyphens only." msgstr "Csak kisbetűk és kötőjelek." -#: judge/models/contest.py:27 +#: judge/models/contest.py:26 msgid "tag colour" msgstr "címke színe" -#: judge/models/contest.py:28 +#: judge/models/contest.py:27 msgid "tag description" msgstr "címke leírása" -#: judge/models/contest.py:47 +#: judge/models/contest.py:46 msgid "contest tag" msgstr "verseny címkéje" -#: judge/models/contest.py:48 judge/models/contest.py:118 +#: judge/models/contest.py:47 judge/models/contest.py:101 msgid "contest tags" msgstr "verseny cimkéi" -#: judge/models/contest.py:56 -msgid "Visible" -msgstr "" - -#: judge/models/contest.py:57 -msgid "Hidden for duration of contest" -msgstr "" - -#: judge/models/contest.py:58 -#, fuzzy -#| msgid "virtual participation id" -msgid "Hidden for duration of participation" -msgstr "virtuális részvételi azonosító" - -#: judge/models/contest.py:60 +#: judge/models/contest.py:51 msgid "contest id" msgstr "verseny azonosítója" -#: judge/models/contest.py:62 +#: judge/models/contest.py:53 msgid "contest name" msgstr "verseny neve" -#: judge/models/contest.py:63 -#, fuzzy -#| msgid "These people will be able to edit the contest." -msgid "These users will be able to edit the contest." +#: judge/models/contest.py:54 +msgid "These people will be able to edit the contest." msgstr "Ezek az emberek szerkeszthetik a versenyt." -#: judge/models/contest.py:65 -#, fuzzy -#| msgid "These people will be able to edit the contest." -msgid "" -"These users will be able to edit the contest, but will not be listed as " -"authors." -msgstr "Ezek az emberek szerkeszthetik a versenyt." - -#: judge/models/contest.py:68 -#, fuzzy -#| msgid "These people will be able to edit the contest." -msgid "These users will be able to view the contest, but not edit it." -msgstr "Ezek az emberek szerkeszthetik a versenyt." - -#: judge/models/contest.py:71 judge/models/runtime.py:136 +#: judge/models/contest.py:56 judge/models/runtime.py:133 msgid "description" msgstr "leírás" -#: judge/models/contest.py:72 judge/models/problem.py:390 -#: judge/models/runtime.py:138 +#: judge/models/contest.py:57 judge/models/problem.py:353 +#: judge/models/runtime.py:135 msgid "problems" msgstr "feladatok" -#: judge/models/contest.py:73 judge/models/contest.py:404 +#: judge/models/contest.py:58 judge/models/contest.py:258 msgid "start time" msgstr "kezdés" -#: judge/models/contest.py:74 +#: judge/models/contest.py:59 msgid "end time" msgstr "befejezés" -#: judge/models/contest.py:75 judge/models/problem.py:118 -#: judge/models/problem.py:414 +#: judge/models/contest.py:60 judge/models/problem.py:118 +#: judge/models/problem.py:377 msgid "time limit" msgstr "időkorlát" -#: judge/models/contest.py:76 judge/models/problem.py:136 +#: judge/models/contest.py:61 judge/models/problem.py:136 msgid "publicly visible" msgstr "nyilvánosan látható" -#: judge/models/contest.py:77 +#: judge/models/contest.py:62 msgid "" "Should be set even for organization-private contests, where it determines " "whether the contest is visible to members of the specified organizations." @@ -757,391 +685,353 @@ msgstr "" "látható-e. Célszerű meghatározni még szervezeten belüli-privát versenyeken " "is." -#: judge/models/contest.py:80 +#: judge/models/contest.py:65 msgid "contest rated" msgstr "értékelt verseny" -#: judge/models/contest.py:80 +#: judge/models/contest.py:65 msgid "Whether this contest can be rated." msgstr "Hogy ez a verseny értékelhető-e." -#: judge/models/contest.py:82 -#, fuzzy -#| msgid "public visibility" -msgid "scoreboard visibility" -msgstr "láthatóság" - -#: judge/models/contest.py:83 -msgid "Scoreboard visibility through the duration of the contest" +#: judge/models/contest.py:67 +msgid "hide scoreboard" msgstr "" -#: judge/models/contest.py:85 -#, fuzzy -#| msgid "contest rated" -msgid "view contest scoreboard" -msgstr "értékelt verseny" +#: judge/models/contest.py:68 +msgid "" +"Whether the scoreboard should remain hidden for the duration of the contest." +msgstr "" -#: judge/models/contest.py:87 -#, fuzzy -#| msgid "These people will be able to edit the contest." -msgid "These users will be able to view the scoreboard." -msgstr "Ezek az emberek szerkeszthetik a versenyt." - -#: judge/models/contest.py:88 +#: judge/models/contest.py:71 msgid "no comments" msgstr "nincsenek hozzászólások" -#: judge/models/contest.py:89 +#: judge/models/contest.py:72 msgid "Use clarification system instead of comments." msgstr "A pontosítási rendszer használata hozzászólások helyett." -#: judge/models/contest.py:91 +#: judge/models/contest.py:74 msgid "Rating floor for contest" msgstr "" -#: judge/models/contest.py:93 +#: judge/models/contest.py:76 msgid "Rating ceiling for contest" msgstr "" -#: judge/models/contest.py:95 +#: judge/models/contest.py:78 msgid "rate all" msgstr "összes értékelése" -#: judge/models/contest.py:95 +#: judge/models/contest.py:78 msgid "Rate all users who joined." msgstr "Értékelése az összes felhasználónak, aki csatlakozott." -#: judge/models/contest.py:96 +#: judge/models/contest.py:79 msgid "exclude from ratings" msgstr "kizárás a értékelésből" -#: judge/models/contest.py:98 +#: judge/models/contest.py:81 msgid "private to specific users" msgstr "" -#: judge/models/contest.py:99 +#: judge/models/contest.py:82 msgid "private contestants" msgstr "" -#: judge/models/contest.py:100 +#: judge/models/contest.py:83 msgid "If private, only these users may see the contest" msgstr "" -#: judge/models/contest.py:102 +#: judge/models/contest.py:85 msgid "hide problem tags" msgstr "feladat címkék elrejtése" -#: judge/models/contest.py:103 +#: judge/models/contest.py:86 msgid "Whether problem tags should be hidden by default." msgstr "" -#: judge/models/contest.py:105 +#: judge/models/contest.py:88 msgid "run pretests only" msgstr "csak pretesztek futtatása" -#: judge/models/contest.py:106 +#: judge/models/contest.py:89 msgid "" "Whether judges should grade pretests only, versus all testcases. Commonly " "set during a contest, then unset prior to rejudging user submissions when " "the contest ends." msgstr "" -#: judge/models/contest.py:110 judge/models/interface.py:77 -#: judge/models/problem.py:157 +#: judge/models/contest.py:93 judge/models/problem.py:157 msgid "private to organizations" msgstr "privát a csoport számára" -#: judge/models/contest.py:111 judge/models/interface.py:75 -#: judge/models/problem.py:155 judge/models/profile.py:77 +#: judge/models/contest.py:94 judge/models/problem.py:155 +#: judge/models/profile.py:77 msgid "organizations" msgstr "csoportok" -#: judge/models/contest.py:112 +#: judge/models/contest.py:95 msgid "If private, only these organizations may see the contest" msgstr "Ha privát, csak ezek a csoportok láthatják a versenyt" -#: judge/models/contest.py:113 judge/models/problem.py:145 +#: judge/models/contest.py:96 judge/models/problem.py:145 msgid "OpenGraph image" msgstr "OpenGraph kép" -#: judge/models/contest.py:114 judge/models/profile.py:48 +#: judge/models/contest.py:97 judge/models/profile.py:48 msgid "Logo override image" msgstr "" -#: judge/models/contest.py:116 +#: judge/models/contest.py:99 msgid "" "This image will replace the default site logo for users inside the contest." msgstr "" -#: judge/models/contest.py:119 +#: judge/models/contest.py:102 msgid "the amount of live participants" msgstr "az éles résztvevők száma" -#: judge/models/contest.py:120 +#: judge/models/contest.py:103 msgid "contest summary" msgstr "verseny összefoglaló" -#: judge/models/contest.py:121 judge/models/problem.py:147 +#: judge/models/contest.py:104 judge/models/problem.py:147 msgid "Plain-text, shown in meta description tag, e.g. for social media." msgstr "" -#: judge/models/contest.py:122 judge/models/profile.py:47 +#: judge/models/contest.py:105 judge/models/profile.py:47 msgid "access code" msgstr "hozzáférési kód" -#: judge/models/contest.py:123 +#: judge/models/contest.py:106 msgid "" "An optional code to prompt contestants before they are allowed to join the " "contest. Leave it blank to disable." msgstr "" -#: judge/models/contest.py:125 judge/models/problem.py:141 +#: judge/models/contest.py:108 judge/models/problem.py:141 msgid "personae non gratae" msgstr "nemkívánatos személy" -#: judge/models/contest.py:126 +#: judge/models/contest.py:109 msgid "Bans the selected users from joining this contest." msgstr "" -#: judge/models/contest.py:127 +#: judge/models/contest.py:110 msgid "contest format" msgstr "" -#: judge/models/contest.py:128 +#: judge/models/contest.py:111 msgid "The contest format module to use." msgstr "" -#: judge/models/contest.py:129 +#: judge/models/contest.py:112 msgid "contest format configuration" msgstr "" -#: judge/models/contest.py:130 +#: judge/models/contest.py:113 msgid "" "A JSON object to serve as the configuration for the chosen contest format " "module. Leave empty to use None. Exact format depends on the contest format " "selected." msgstr "" -#: judge/models/contest.py:137 -#, fuzzy -#| msgid "test case points" -msgid "precision points" -msgstr "teszteset pontjai" - -#: judge/models/contest.py:139 -msgid "Number of digits to round points to." -msgstr "" - -#: judge/models/contest.py:383 +#: judge/models/contest.py:239 msgid "See private contests" msgstr "Privát versenyek mutatása" -#: judge/models/contest.py:384 +#: judge/models/contest.py:240 msgid "Edit own contests" msgstr "Saját versenyek szerkesztése" -#: judge/models/contest.py:385 +#: judge/models/contest.py:241 msgid "Edit all contests" msgstr "Az összes verseny szerkesztése" -#: judge/models/contest.py:386 +#: judge/models/contest.py:242 msgid "Clone contest" msgstr "" -#: judge/models/contest.py:387 templates/contest/moss.html:74 +#: judge/models/contest.py:243 templates/contest/moss.html:74 msgid "MOSS contest" msgstr "" -#: judge/models/contest.py:388 +#: judge/models/contest.py:244 msgid "Rate contests" msgstr "Versenyek értékelése" -#: judge/models/contest.py:389 +#: judge/models/contest.py:245 msgid "Contest access codes" msgstr "Verseny hozzáférési kódok" -#: judge/models/contest.py:390 +#: judge/models/contest.py:246 msgid "Create private contests" msgstr "" -#: judge/models/contest.py:391 -msgid "Change contest visibility" -msgstr "" - -#: judge/models/contest.py:392 -#, fuzzy -#| msgid "contest problems" -msgid "Edit contest problem label script" -msgstr "versenyfeladatok" - -#: judge/models/contest.py:394 judge/models/contest.py:492 -#: judge/models/contest.py:529 judge/models/contest.py:552 -#: judge/models/submission.py:84 +#: judge/models/contest.py:248 judge/models/contest.py:345 +#: judge/models/contest.py:382 judge/models/contest.py:404 +#: judge/models/submission.py:83 msgid "contest" msgstr "verseny" -#: judge/models/contest.py:395 +#: judge/models/contest.py:249 msgid "contests" msgstr "versenyek" -#: judge/models/contest.py:402 +#: judge/models/contest.py:256 msgid "associated contest" msgstr "" -#: judge/models/contest.py:405 +#: judge/models/contest.py:259 msgid "score" msgstr "pontszám" -#: judge/models/contest.py:406 +#: judge/models/contest.py:260 msgid "cumulative time" msgstr "összes idő" -#: judge/models/contest.py:407 +#: judge/models/contest.py:261 msgid "is disqualified" msgstr "" -#: judge/models/contest.py:408 +#: judge/models/contest.py:262 msgid "Whether this participation is disqualified." msgstr "" -#: judge/models/contest.py:409 -msgid "tie-breaking field" -msgstr "" - -#: judge/models/contest.py:410 +#: judge/models/contest.py:263 msgid "virtual participation id" msgstr "virtuális részvételi azonosító" -#: judge/models/contest.py:411 +#: judge/models/contest.py:264 #, fuzzy #| msgid "0 means non-virtual, otherwise the n-th virtual participation" msgid "0 means non-virtual, otherwise the n-th virtual participation." msgstr "A 0 nem virtuális, egyébként az n. virtuális részvétel" -#: judge/models/contest.py:412 +#: judge/models/contest.py:265 msgid "contest format specific data" msgstr "" -#: judge/models/contest.py:478 +#: judge/models/contest.py:331 #, python-format msgid "%s spectating in %s" msgstr "%s megfigyel %s-ben" -#: judge/models/contest.py:480 +#: judge/models/contest.py:333 #, python-format msgid "%s in %s, v%d" msgstr "%s en %s, v%d" -#: judge/models/contest.py:481 +#: judge/models/contest.py:334 #, python-format msgid "%s in %s" msgstr "%s %s-ben" -#: judge/models/contest.py:484 +#: judge/models/contest.py:337 msgid "contest participation" msgstr "verseny részvétel" -#: judge/models/contest.py:485 +#: judge/models/contest.py:338 msgid "contest participations" msgstr "verseny részvételek" -#: judge/models/contest.py:491 judge/models/contest.py:513 -#: judge/models/contest.py:553 judge/models/problem.py:389 -#: judge/models/problem.py:394 judge/models/problem.py:412 -#: judge/models/problem_data.py:40 +#: judge/models/contest.py:344 judge/models/contest.py:366 +#: judge/models/contest.py:405 judge/models/problem.py:352 +#: judge/models/problem.py:357 judge/models/problem.py:375 +#: judge/models/problem_data.py:38 msgid "problem" msgstr "feladat" -#: judge/models/contest.py:493 judge/models/contest.py:517 +#: judge/models/contest.py:346 judge/models/contest.py:370 #: judge/models/problem.py:129 msgid "points" msgstr "pontok" -#: judge/models/contest.py:494 +#: judge/models/contest.py:347 msgid "partial" msgstr "részleges" -#: judge/models/contest.py:495 judge/models/contest.py:518 +#: judge/models/contest.py:348 judge/models/contest.py:371 msgid "is pretested" msgstr "pretesztes-e" -#: judge/models/contest.py:496 judge/models/interface.py:43 +#: judge/models/contest.py:349 judge/models/interface.py:43 msgid "order" msgstr "sorrend" -#: judge/models/contest.py:497 +#: judge/models/contest.py:350 msgid "0 to not show testcases, 1 to show" msgstr "" -#: judge/models/contest.py:498 +#: judge/models/contest.py:351 msgid "visible testcases" msgstr "" -#: judge/models/contest.py:499 +#: judge/models/contest.py:352 msgid "Maximum number of submissions for this problem, or 0 for no limit." msgstr "A feltöltések maximális száma, 0 esetén nincs korlát." -#: judge/models/contest.py:501 +#: judge/models/contest.py:354 msgid "Why include a problem you can't submit to?" msgstr "" -#: judge/models/contest.py:506 +#: judge/models/contest.py:359 msgid "contest problem" msgstr "versenyfeladat" -#: judge/models/contest.py:507 +#: judge/models/contest.py:360 msgid "contest problems" msgstr "versenyfeladatok" -#: judge/models/contest.py:511 judge/models/submission.py:183 +#: judge/models/contest.py:364 judge/models/submission.py:181 msgid "submission" msgstr "feltöltés" -#: judge/models/contest.py:515 judge/models/contest.py:530 +#: judge/models/contest.py:368 judge/models/contest.py:383 msgid "participation" msgstr "részvétel" -#: judge/models/contest.py:519 +#: judge/models/contest.py:372 msgid "Whether this submission was ran only on pretests." msgstr "" -#: judge/models/contest.py:523 +#: judge/models/contest.py:376 msgid "contest submission" msgstr "verseny feltöltés" -#: judge/models/contest.py:524 +#: judge/models/contest.py:377 msgid "contest submissions" msgstr "verseny feltöltések" -#: judge/models/contest.py:532 +#: judge/models/contest.py:385 msgid "rank" msgstr "helyezés" -#: judge/models/contest.py:533 +#: judge/models/contest.py:386 msgid "rating" msgstr "értékelés" -#: judge/models/contest.py:534 +#: judge/models/contest.py:387 msgid "volatility" msgstr "volatilitás" -#: judge/models/contest.py:535 +#: judge/models/contest.py:388 msgid "last rated" msgstr "utolsó értékelt" -#: judge/models/contest.py:539 +#: judge/models/contest.py:392 msgid "contest rating" msgstr "verseny értékelés" -#: judge/models/contest.py:540 +#: judge/models/contest.py:393 msgid "contest ratings" msgstr "verseny értékelések" -#: judge/models/contest.py:560 +#: judge/models/contest.py:412 msgid "contest moss result" msgstr "" -#: judge/models/contest.py:561 +#: judge/models/contest.py:413 msgid "contest moss results" msgstr "" @@ -1181,7 +1071,7 @@ msgstr "szülő elem" msgid "post title" msgstr "bejegyzés címe" -#: judge/models/interface.py:67 judge/models/problem.py:432 +#: judge/models/interface.py:67 judge/models/problem.py:395 msgid "authors" msgstr "szerzők" @@ -1189,7 +1079,7 @@ msgstr "szerzők" msgid "slug" msgstr "csonk" -#: judge/models/interface.py:69 judge/models/problem.py:430 +#: judge/models/interface.py:69 judge/models/problem.py:393 msgid "public visibility" msgstr "láthatóság" @@ -1213,21 +1103,15 @@ msgstr "tartalom összefoglalója" msgid "openGraph image" msgstr "openGraph kép" -#: judge/models/interface.py:76 -#, fuzzy -#| msgid "If private, only these organizations may see the contest" -msgid "If private, only these organizations may see the blog post." -msgstr "Ha privát, csak ezek a csoportok láthatják a versenyt" - -#: judge/models/interface.py:105 +#: judge/models/interface.py:91 msgid "Edit all posts" msgstr "Összes poszt szerkesztése" -#: judge/models/interface.py:107 +#: judge/models/interface.py:93 msgid "blog post" msgstr "blog poszt" -#: judge/models/interface.py:108 +#: judge/models/interface.py:94 msgid "blog posts" msgstr "blog posztok" @@ -1251,6 +1135,10 @@ msgstr "címzett" msgid "message timestamp" msgstr "üzenet időbélyege" +#: judge/models/message.py:16 +msgid "read" +msgstr "olvas" + #: judge/models/message.py:20 msgid "messages in the thread" msgstr "üzenetek a szálban" @@ -1389,7 +1277,7 @@ msgstr "" "A feladat időlimitje másodpercekben. Tört másodperceket (pl. 1.5) is " "írhatunk." -#: judge/models/problem.py:123 judge/models/problem.py:417 +#: judge/models/problem.py:123 judge/models/problem.py:380 msgid "memory limit" msgstr "memória korlát" @@ -1462,188 +1350,188 @@ msgstr "" msgid "If private, only these organizations may see the problem." msgstr "" -#: judge/models/problem.py:395 judge/models/problem.py:413 -#: judge/models/runtime.py:111 +#: judge/models/problem.py:358 judge/models/problem.py:376 +#: judge/models/runtime.py:108 msgid "language" msgstr "nyelv" -#: judge/models/problem.py:396 +#: judge/models/problem.py:359 msgid "translated name" msgstr "lefordított név" -#: judge/models/problem.py:397 +#: judge/models/problem.py:360 msgid "translated description" msgstr "lefordított leírás" -#: judge/models/problem.py:401 +#: judge/models/problem.py:364 msgid "problem translation" msgstr "feladat fordítás" -#: judge/models/problem.py:402 +#: judge/models/problem.py:365 msgid "problem translations" msgstr "feladat fordítások" -#: judge/models/problem.py:406 +#: judge/models/problem.py:369 msgid "clarified problem" msgstr "pontosított feladat" -#: judge/models/problem.py:407 +#: judge/models/problem.py:370 msgid "clarification body" msgstr "pontosítás törzse" -#: judge/models/problem.py:408 +#: judge/models/problem.py:371 msgid "clarification timestamp" msgstr "pontosítás időbélyege" -#: judge/models/problem.py:423 +#: judge/models/problem.py:386 msgid "language-specific resource limit" msgstr "nyelv specifikus erőforrás korlát" -#: judge/models/problem.py:424 +#: judge/models/problem.py:387 msgid "language-specific resource limits" msgstr "nyelv specifikus erőforrás korlátok" -#: judge/models/problem.py:428 +#: judge/models/problem.py:391 msgid "associated problem" msgstr "hozzárendelt probléma" -#: judge/models/problem.py:431 +#: judge/models/problem.py:394 msgid "publish date" msgstr "publikálás dátuma" -#: judge/models/problem.py:433 +#: judge/models/problem.py:396 msgid "editorial content" msgstr "megoldási útmutató tartalom" -#: judge/models/problem.py:449 +#: judge/models/problem.py:412 msgid "solution" msgstr "megoldás" -#: judge/models/problem.py:450 +#: judge/models/problem.py:413 msgid "solutions" msgstr "megoldások" -#: judge/models/problem_data.py:26 +#: judge/models/problem_data.py:24 msgid "Standard" msgstr "Alapértelmezett" -#: judge/models/problem_data.py:27 +#: judge/models/problem_data.py:25 msgid "Floats" msgstr "Lebegőpontosak" -#: judge/models/problem_data.py:28 +#: judge/models/problem_data.py:26 msgid "Floats (absolute)" msgstr "Lebegőpontosak (abszolút)" -#: judge/models/problem_data.py:29 +#: judge/models/problem_data.py:27 msgid "Floats (relative)" msgstr "Lebegőpontosak (relatív)" -#: judge/models/problem_data.py:30 +#: judge/models/problem_data.py:28 msgid "Non-trailing spaces" msgstr "" -#: judge/models/problem_data.py:31 +#: judge/models/problem_data.py:29 msgid "Unordered" msgstr "Rendezetlen" -#: judge/models/problem_data.py:32 +#: judge/models/problem_data.py:30 msgid "Byte identical" msgstr "Bájtonként azonos" -#: judge/models/problem_data.py:33 +#: judge/models/problem_data.py:31 msgid "Line-by-line" msgstr "" -#: judge/models/problem_data.py:34 +#: judge/models/problem_data.py:32 msgid "Custom checker (PY)" msgstr "" -#: judge/models/problem_data.py:35 +#: judge/models/problem_data.py:33 msgid "Custom validator (CPP)" msgstr "" -#: judge/models/problem_data.py:42 +#: judge/models/problem_data.py:40 msgid "data zip file" msgstr "adat zip fájl" -#: judge/models/problem_data.py:44 +#: judge/models/problem_data.py:42 msgid "generator file" msgstr "generátor fájl" -#: judge/models/problem_data.py:46 judge/models/problem_data.py:121 +#: judge/models/problem_data.py:44 judge/models/problem_data.py:110 msgid "output prefix length" msgstr "kimeneti prefix hossza" -#: judge/models/problem_data.py:47 judge/models/problem_data.py:122 +#: judge/models/problem_data.py:45 judge/models/problem_data.py:111 msgid "output limit length" msgstr "kimenet hossz limitje" -#: judge/models/problem_data.py:48 +#: judge/models/problem_data.py:46 msgid "init.yml generation feedback" msgstr "init.yml generálás visszajelzése" -#: judge/models/problem_data.py:49 judge/models/problem_data.py:123 +#: judge/models/problem_data.py:47 judge/models/problem_data.py:112 msgid "checker" msgstr "checker" -#: judge/models/problem_data.py:50 judge/models/problem_data.py:124 +#: judge/models/problem_data.py:48 judge/models/problem_data.py:113 msgid "checker arguments" msgstr "checker argumentumai" -#: judge/models/problem_data.py:51 judge/models/problem_data.py:125 +#: judge/models/problem_data.py:49 judge/models/problem_data.py:114 msgid "checker arguments as a JSON object" msgstr "chceker argumentumai JSON objektumként" -#: judge/models/problem_data.py:52 +#: judge/models/problem_data.py:50 msgid "custom checker file" msgstr "" -#: judge/models/problem_data.py:58 +#: judge/models/problem_data.py:56 msgid "custom validator file" msgstr "" -#: judge/models/problem_data.py:108 +#: judge/models/problem_data.py:97 msgid "problem data set" msgstr "feladat adathalmaz" -#: judge/models/problem_data.py:110 +#: judge/models/problem_data.py:99 msgid "case position" msgstr "eset hely" -#: judge/models/problem_data.py:111 +#: judge/models/problem_data.py:100 msgid "case type" msgstr "eset típus" -#: judge/models/problem_data.py:112 +#: judge/models/problem_data.py:101 msgid "Normal case" msgstr "Normál eset" -#: judge/models/problem_data.py:113 +#: judge/models/problem_data.py:102 msgid "Batch start" msgstr "Batch kezdete" -#: judge/models/problem_data.py:114 +#: judge/models/problem_data.py:103 msgid "Batch end" msgstr "Batch vége" -#: judge/models/problem_data.py:116 +#: judge/models/problem_data.py:105 msgid "input file name" msgstr "bemeneti fájl név" -#: judge/models/problem_data.py:117 +#: judge/models/problem_data.py:106 msgid "output file name" msgstr "kimeneti fájl név" -#: judge/models/problem_data.py:118 +#: judge/models/problem_data.py:107 msgid "generator arguments" msgstr "generátor argumentumai" -#: judge/models/problem_data.py:119 +#: judge/models/problem_data.py:108 msgid "point value" msgstr "pont érték" -#: judge/models/problem_data.py:120 +#: judge/models/problem_data.py:109 msgid "case is pretest?" msgstr "ez az eset preteszt?" @@ -1718,7 +1606,7 @@ msgid "" msgstr "" #: judge/models/profile.py:76 judge/models/profile.py:93 -#: judge/models/profile.py:212 +#: judge/models/profile.py:192 msgid "organization" msgstr "csoport" @@ -1814,31 +1702,31 @@ msgstr "" msgid "Notes for administrators regarding this user." msgstr "" -#: judge/models/profile.py:206 +#: judge/models/profile.py:186 msgid "user profile" msgstr "felhasználói profil" -#: judge/models/profile.py:207 +#: judge/models/profile.py:187 msgid "user profiles" msgstr "felhasználói profilok" -#: judge/models/profile.py:214 +#: judge/models/profile.py:194 msgid "request time" msgstr "kérési idő" -#: judge/models/profile.py:215 +#: judge/models/profile.py:195 msgid "state" msgstr "állapot" -#: judge/models/profile.py:220 +#: judge/models/profile.py:200 msgid "reason" msgstr "ok" -#: judge/models/profile.py:223 +#: judge/models/profile.py:203 msgid "organization join request" msgstr "csoport belépési kérelem" -#: judge/models/profile.py:224 +#: judge/models/profile.py:204 msgid "organization join requests" msgstr "csoport belépési kérelmek" @@ -1929,88 +1817,88 @@ msgstr "kiterjesztés" msgid "The extension of source files, e.g., \"py\" or \"cpp\"." msgstr "" -#: judge/models/runtime.py:112 +#: judge/models/runtime.py:109 msgid "languages" msgstr "nyelvek" -#: judge/models/runtime.py:116 +#: judge/models/runtime.py:113 msgid "language to which this runtime belongs" msgstr "" -#: judge/models/runtime.py:117 +#: judge/models/runtime.py:114 msgid "judge on which this runtime exists" msgstr "" -#: judge/models/runtime.py:118 +#: judge/models/runtime.py:115 msgid "runtime name" msgstr "runtime név" -#: judge/models/runtime.py:119 +#: judge/models/runtime.py:116 msgid "runtime version" msgstr "runtime verzió" -#: judge/models/runtime.py:120 +#: judge/models/runtime.py:117 msgid "order in which to display this runtime" msgstr "" -#: judge/models/runtime.py:124 +#: judge/models/runtime.py:121 msgid "Server name, hostname-style" msgstr "Szerver név, hosztnév-szerűen" -#: judge/models/runtime.py:125 +#: judge/models/runtime.py:122 msgid "time of creation" msgstr "létrehozás dátuma" -#: judge/models/runtime.py:126 +#: judge/models/runtime.py:123 #, fuzzy #| msgid "A key to authenticated this judge" msgid "A key to authenticate this judge" msgstr "A tesztelőhöz hozzárendelt kulcs" -#: judge/models/runtime.py:127 +#: judge/models/runtime.py:124 msgid "authentication key" msgstr "hitelesítő kulcs" -#: judge/models/runtime.py:128 +#: judge/models/runtime.py:125 msgid "block judge" msgstr "" -#: judge/models/runtime.py:129 +#: judge/models/runtime.py:126 msgid "" "Whether this judge should be blocked from connecting, even if its key is " "correct." msgstr "" -#: judge/models/runtime.py:131 +#: judge/models/runtime.py:128 msgid "judge online status" msgstr "tesztelő státusza" -#: judge/models/runtime.py:132 +#: judge/models/runtime.py:129 msgid "judge start time" msgstr "tesztelő indítási ideje" -#: judge/models/runtime.py:133 +#: judge/models/runtime.py:130 msgid "response time" msgstr "válaszidő" -#: judge/models/runtime.py:134 +#: judge/models/runtime.py:131 msgid "system load" msgstr "rendszer terheltsége" -#: judge/models/runtime.py:135 +#: judge/models/runtime.py:132 msgid "Load for the last minute, divided by processors to be fair." msgstr "" -#: judge/models/runtime.py:139 judge/models/runtime.py:179 +#: judge/models/runtime.py:136 judge/models/runtime.py:176 msgid "judges" msgstr "bírók" -#: judge/models/runtime.py:178 +#: judge/models/runtime.py:175 msgid "judge" msgstr "bíró" #: judge/models/submission.py:20 judge/models/submission.py:47 -#: judge/utils/problems.py:79 +#: judge/utils/problems.py:77 msgid "Accepted" msgstr "Elfogadva" @@ -2039,7 +1927,7 @@ msgid "Runtime Error" msgstr "Futási hiba" #: judge/models/submission.py:27 judge/models/submission.py:41 -#: judge/models/submission.py:55 judge/utils/problems.py:81 +#: judge/models/submission.py:55 judge/utils/problems.py:79 msgid "Compile Error" msgstr "Fordítási hiba" @@ -2080,15 +1968,15 @@ msgstr "Belső hiba (tesztelő szerver hiba)" msgid "submission time" msgstr "" -#: judge/models/submission.py:67 judge/models/submission.py:203 +#: judge/models/submission.py:67 judge/models/submission.py:201 msgid "execution time" msgstr "futási idő" -#: judge/models/submission.py:68 judge/models/submission.py:204 +#: judge/models/submission.py:68 judge/models/submission.py:202 msgid "memory usage" msgstr "memória használat" -#: judge/models/submission.py:69 judge/models/submission.py:205 +#: judge/models/submission.py:69 judge/models/submission.py:203 msgid "points granted" msgstr "" @@ -2125,64 +2013,58 @@ msgid "judged on" msgstr "ezen tesztelve" #: judge/models/submission.py:81 -#, fuzzy -#| msgid "0 submissions left" -msgid "submission judge time" -msgstr "0 beküldés van hátra" - -#: judge/models/submission.py:82 msgid "was rejudged by admin" msgstr "" -#: judge/models/submission.py:83 +#: judge/models/submission.py:82 msgid "was ran on pretests only" msgstr "" -#: judge/models/submission.py:184 templates/contest/moss.html:58 +#: judge/models/submission.py:182 templates/contest/moss.html:58 msgid "submissions" msgstr "" -#: judge/models/submission.py:188 judge/models/submission.py:199 +#: judge/models/submission.py:186 judge/models/submission.py:197 msgid "associated submission" msgstr "" -#: judge/models/submission.py:190 +#: judge/models/submission.py:188 msgid "source code" msgstr "forráskód" -#: judge/models/submission.py:201 +#: judge/models/submission.py:199 msgid "test case ID" msgstr "teszteset azonosító" -#: judge/models/submission.py:202 +#: judge/models/submission.py:200 msgid "status flag" msgstr "" -#: judge/models/submission.py:206 +#: judge/models/submission.py:204 msgid "points possible" msgstr "" -#: judge/models/submission.py:207 +#: judge/models/submission.py:205 msgid "batch number" msgstr "" -#: judge/models/submission.py:208 +#: judge/models/submission.py:206 msgid "judging feedback" msgstr "tesztelési visszajelzés" -#: judge/models/submission.py:209 +#: judge/models/submission.py:207 msgid "extended judging feedback" msgstr "" -#: judge/models/submission.py:210 +#: judge/models/submission.py:208 msgid "program output" msgstr "program kimenet" -#: judge/models/submission.py:218 +#: judge/models/submission.py:216 msgid "submission test case" msgstr "" -#: judge/models/submission.py:219 +#: judge/models/submission.py:217 msgid "submission test cases" msgstr "" @@ -2234,23 +2116,12 @@ msgstr "" msgid "message time" msgstr "" -#: judge/pdf_problems.py:147 judge/pdf_problems.py:199 -#: judge/pdf_problems.py:259 +#: judge/pdf_problems.py:134 judge/pdf_problems.py:186 +#: judge/pdf_problems.py:246 msgid "Page [page] of [topage]" msgstr "" -#: judge/pdf_problems.py:280 -#, python-format -msgid "Page %s of %s" -msgstr "" - -#: judge/tasks/contest.py:19 -#, fuzzy -#| msgid "Recalculate scores" -msgid "Recalculating contest scores" -msgstr "Pontok újraszámítása" - -#: judge/tasks/contest.py:40 +#: judge/tasks/moss.py:25 msgid "Running MOSS" msgstr "" @@ -2262,60 +2133,60 @@ msgstr "" msgid "Recalculating user points" msgstr "" -#: judge/utils/problem_data.py:70 +#: judge/utils/problem_data.py:68 msgid "Empty batches not allowed." msgstr "" -#: judge/utils/problem_data.py:78 judge/utils/problem_data.py:99 +#: judge/utils/problem_data.py:76 judge/utils/problem_data.py:97 msgid "How did you corrupt the custom checker path?" msgstr "" -#: judge/utils/problem_data.py:120 +#: judge/utils/problem_data.py:118 #, python-format msgid "Points must be defined for non-batch case #%d." msgstr "" -#: judge/utils/problem_data.py:125 +#: judge/utils/problem_data.py:123 #, python-format msgid "Input file for case %d does not exist: %s" msgstr "Bemeneti fájl a %d esetre nem létezik: %s" -#: judge/utils/problem_data.py:128 +#: judge/utils/problem_data.py:126 #, python-format msgid "Output file for case %d does not exist: %s" msgstr "Kimeneti fájl a %d esetre nem létezik: %s" -#: judge/utils/problem_data.py:153 +#: judge/utils/problem_data.py:151 #, python-format msgid "Batch start case #%d requires points." msgstr "" -#: judge/utils/problem_data.py:174 +#: judge/utils/problem_data.py:172 #, python-format msgid "Attempt to end batch outside of one in case #%d" msgstr "" -#: judge/utils/problem_data.py:192 +#: judge/utils/problem_data.py:190 msgid "How did you corrupt the zip path?" msgstr "" -#: judge/utils/problem_data.py:198 +#: judge/utils/problem_data.py:196 msgid "How did you corrupt the generator path?" msgstr "" -#: judge/utils/problems.py:80 +#: judge/utils/problems.py:78 msgid "Wrong" msgstr "" -#: judge/utils/problems.py:82 +#: judge/utils/problems.py:80 msgid "Timeout" msgstr "" -#: judge/utils/problems.py:83 +#: judge/utils/problems.py:81 msgid "Error" msgstr "" -#: judge/utils/problems.py:94 +#: judge/utils/problems.py:92 msgid "Can't pass both queryset and keyword filters" msgstr "" @@ -2358,8 +2229,7 @@ msgctxt "hours and minutes" msgid "%h:%m" msgstr "%h:%m" -#: judge/views/about.py:7 templates/organization/home.html:112 -#: templates/user/user-about.html:83 templates/user/user-tabs.html:4 +#: judge/views/about.py:7 templates/user/user-about.html:33 msgid "About" msgstr "" @@ -2367,167 +2237,157 @@ msgstr "" msgid "Custom Checker Sample" msgstr "" -#: judge/views/blog.py:45 +#: judge/views/blog.py:38 #, python-format msgid "Page %d of Posts" msgstr "" -#: judge/views/comment.py:28 +#: judge/views/comment.py:27 msgid "Messing around, are we?" msgstr "Játszogatunk, he?" -#: judge/views/comment.py:37 +#: judge/views/comment.py:36 msgid "You must solve at least one problem before you can vote." msgstr "" -#: judge/views/comment.py:64 +#: judge/views/comment.py:63 msgid "You already voted." msgstr "Már szavaztál." -#: judge/views/comment.py:126 judge/views/organization.py:344 +#: judge/views/comment.py:120 judge/views/organization.py:299 msgid "Edited from site" msgstr "Szerkesztve az oldalról" -#: judge/views/comment.py:147 +#: judge/views/comment.py:141 msgid "Editing comment" msgstr "Hozzászólás szerkesztése" -#: judge/views/contests.py:57 judge/views/contests.py:247 -#: judge/views/contests.py:250 judge/views/contests.py:424 +#: judge/views/contests.py:55 judge/views/contests.py:215 +#: judge/views/contests.py:218 judge/views/contests.py:389 msgid "No such contest" msgstr "Nincs ilyen verseny" -#: judge/views/contests.py:58 judge/views/contests.py:248 +#: judge/views/contests.py:56 judge/views/contests.py:216 #, python-format msgid "Could not find a contest with the key \"%s\"." msgstr "Nem található verseny a \"%s\" kulccsal." -#: judge/views/contests.py:71 +#: judge/views/contests.py:81 msgid "Contests" msgstr "Versenyek" -#: judge/views/contests.py:251 +#: judge/views/contests.py:219 msgid "Could not find such contest." msgstr "Nem található ilyen verseny." -#: judge/views/contests.py:254 +#: judge/views/contests.py:222 #, python-format msgid "Access to contest \"%s\" denied" msgstr "Hozzáférés a \"%s\" versenyhez megtagadva" -#: judge/views/contests.py:278 +#: judge/views/contests.py:246 msgid "Clone Contest" msgstr "" -#: judge/views/contests.py:343 +#: judge/views/contests.py:309 msgid "Contest not ongoing" msgstr "A verseny nincs folyamatban" -#: judge/views/contests.py:344 +#: judge/views/contests.py:310 #, python-format msgid "\"%s\" is not currently ongoing." msgstr "\"%s\" nincs folyamatban." -#: judge/views/contests.py:348 +#: judge/views/contests.py:314 msgid "Already in contest" msgstr "Már a versenyben vagy" -#: judge/views/contests.py:349 +#: judge/views/contests.py:315 #, python-format msgid "You are already in a contest: \"%s\"." msgstr "Már a \"%s\" versenyben vagy." -#: judge/views/contests.py:352 +#: judge/views/contests.py:318 msgid "Banned from joining" msgstr "" -#: judge/views/contests.py:353 +#: judge/views/contests.py:319 msgid "" "You have been declared persona non grata for this contest. You are " "permanently barred from joining this contest." msgstr "" -#: judge/views/contests.py:414 +#: judge/views/contests.py:379 #, python-format msgid "Enter access code for \"%s\"" msgstr "Add meg a hozzáférési kódot a \"%s\"-hoz" -#: judge/views/contests.py:425 +#: judge/views/contests.py:390 #, python-format msgid "You are not in contest \"%s\"." msgstr "Nem vagy a \"%s\" versenyben." -#: judge/views/contests.py:444 +#: judge/views/contests.py:409 msgid "ContestCalendar requires integer year and month" msgstr "" -#: judge/views/contests.py:484 +#: judge/views/contests.py:449 #, python-format msgid "Contests in %(month)s" msgstr "" -#: judge/views/contests.py:484 +#: judge/views/contests.py:449 msgid "F Y" msgstr "" -#: judge/views/contests.py:532 +#: judge/views/contests.py:496 #, fuzzy, python-format #| msgid "Submission Statistics" msgid "%s Statistics" msgstr "Beküldési statisztikák" -#: judge/views/contests.py:717 +#: judge/views/contests.py:601 +msgid "???" +msgstr "???" + +#: judge/views/contests.py:664 #, python-format msgid "%s Rankings" msgstr "" -#: judge/views/contests.py:725 -msgid "???" -msgstr "???" - -#: judge/views/contests.py:741 +#: judge/views/contests.py:680 #, python-format msgid "Your participation in %s" msgstr "" -#: judge/views/contests.py:742 +#: judge/views/contests.py:681 #, python-format msgid "%s's participation in %s" msgstr "" -#: judge/views/contests.py:749 +#: judge/views/contests.py:685 msgid "Live" msgstr "" -#: judge/views/contests.py:761 templates/contest/contest-tabs.html:13 +#: judge/views/contests.py:697 msgid "Participation" msgstr "" -#: judge/views/contests.py:808 +#: judge/views/contests.py:743 #, python-format msgid "%s MOSS Results" msgstr "" -#: judge/views/contests.py:835 +#: judge/views/contests.py:770 #, python-format msgid "Running MOSS for %s..." msgstr "" -#: judge/views/contests.py:858 +#: judge/views/contests.py:793 #, python-format msgid "Contest tag: %s" msgstr "" -#: judge/views/contests.py:868 judge/views/ticket.py:57 -msgid "Issue description" -msgstr "Probléma leírása" - -#: judge/views/contests.py:911 -#, fuzzy, python-format -#| msgid "clarification body" -msgid "New clarification for %s" -msgstr "pontosítás törzse" - #: judge/views/error.py:14 msgid "404 error" msgstr "404-es hiba" @@ -2548,76 +2408,69 @@ msgid "corrupt page %s" msgstr "" #: judge/views/language.py:12 templates/status/judge-status-table.html:9 -#: templates/status/status-tabs.html:5 msgid "Runtimes" msgstr "" -#: judge/views/notification.py:40 -#, python-format -msgid "Notifications (%d unseen)" -msgstr "" - -#: judge/views/organization.py:59 judge/views/organization.py:62 +#: judge/views/organization.py:44 judge/views/organization.py:47 msgid "No such organization" msgstr "Nincs ilyen csoport" -#: judge/views/organization.py:60 +#: judge/views/organization.py:45 #, python-format msgid "Could not find an organization with the key \"%s\"." msgstr "Nem található csoport a \"%s\" kulccsal." -#: judge/views/organization.py:63 +#: judge/views/organization.py:48 msgid "Could not find such organization." msgstr "Nem található ilyen csoport." -#: judge/views/organization.py:79 judge/views/register.py:34 -#: templates/organization/list.html:32 templates/user/import/table_csv.html:9 -#: templates/user/user-list-tabs.html:6 +#: judge/views/organization.py:72 judge/views/register.py:34 +#: templates/organization/list.html:15 msgid "Organizations" msgstr "Csoportok" -#: judge/views/organization.py:130 +#: judge/views/organization.py:93 #, python-format msgid "%s Members" msgstr "%s Tagok" -#: judge/views/organization.py:159 judge/views/organization.py:162 -#: judge/views/organization.py:167 +#: judge/views/organization.py:118 judge/views/organization.py:121 +#: judge/views/organization.py:126 msgid "Joining organization" msgstr "Belépés a csoportba" -#: judge/views/organization.py:159 +#: judge/views/organization.py:118 msgid "You are already in the organization." msgstr "Már benne vagy a csoportba." -#: judge/views/organization.py:162 +#: judge/views/organization.py:121 msgid "This organization is not open." msgstr "Ez a csoport nem nyílt." -#: judge/views/organization.py:179 +#: judge/views/organization.py:138 msgid "Leaving organization" msgstr "Csoport elhagyása" -#: judge/views/organization.py:179 +#: judge/views/organization.py:138 #, python-format msgid "You are not in \"%s\"." msgstr "Nem vagy \"%s\"-ben." -#: judge/views/organization.py:203 +#: judge/views/organization.py:162 #, python-format msgid "Request to join %s" msgstr "Kérés a \"%s\"-hez való csatlakozásra" -#: judge/views/organization.py:221 +#: judge/views/organization.py:180 msgid "Join request detail" msgstr "Belépési kérés részletei" -#: judge/views/organization.py:254 +#: judge/views/organization.py:209 #, python-format msgid "Managing join requests for %s" msgstr "%s belépési kéréseinek kezelése" -#: judge/views/organization.py:285 +#: judge/views/organization.py:240 #, python-format msgid "" "Your organization can only receive %d more members. You cannot approve %d " @@ -2626,46 +2479,46 @@ msgstr "" "A csoportod csak %d további tagot tud fogadni. Nem tudsz felvenni %d " "felhasználót." -#: judge/views/organization.py:297 +#: judge/views/organization.py:252 #, python-format msgid "Approved %d user." msgid_plural "Approved %d users." msgstr[0] "%d darab felhasználó jóváhagyva." msgstr[1] "%d darab felhasználó jóváhagyva." -#: judge/views/organization.py:298 +#: judge/views/organization.py:253 #, python-format msgid "Rejected %d user." msgid_plural "Rejected %d users." msgstr[0] "%d darab felhasználó elutasítva." msgstr[1] "%d darab felhasználó elutasítva." -#: judge/views/organization.py:328 +#: judge/views/organization.py:283 #, python-format msgid "Editing %s" msgstr "%s szerkesztése" -#: judge/views/organization.py:352 judge/views/organization.py:360 +#: judge/views/organization.py:307 judge/views/organization.py:315 msgid "Can't edit organization" msgstr "Nem lehet szerkeszteni a csoportot" -#: judge/views/organization.py:353 +#: judge/views/organization.py:308 msgid "You are not allowed to edit this organization." msgstr "Nincs jogosultságod szerkeszteni ezt a csoportot." -#: judge/views/organization.py:361 +#: judge/views/organization.py:316 msgid "You are not allowed to kick people from this organization." msgstr "Nincs jogosultságod embereket kirúgni ebből a csoportból." -#: judge/views/organization.py:366 judge/views/organization.py:370 +#: judge/views/organization.py:321 judge/views/organization.py:325 msgid "Can't kick user" msgstr "Nem lehet kirúgni a felhasználót" -#: judge/views/organization.py:367 +#: judge/views/organization.py:322 msgid "The user you are trying to kick does not exist!" msgstr "A felhasználó akit megpróbálsz kirúgni nem létezik!" -#: judge/views/organization.py:371 +#: judge/views/organization.py:326 #, python-format msgid "The user you are trying to kick is not in organization: %s." msgstr "A felhasználó akit ki akarsz rúgni nincs a csoportban: %s." @@ -2689,17 +2542,16 @@ msgstr "Megoldás útmutató {0}-hez" msgid "Editorial for {0}" msgstr "Megoldási útmutató {0}-hez" -#: judge/views/problem.py:285 templates/contest/contest.html:79 -#: templates/user/user-about.html:28 templates/user/user-tabs.html:5 -#: templates/user/users-table.html:31 +#: judge/views/problem.py:286 templates/contest/contest.html:79 +#: templates/user/users-table.html:23 msgid "Problems" msgstr "Feladatok" -#: judge/views/problem.py:585 +#: judge/views/problem.py:547 msgid "Banned from submitting" msgstr "Feltöltéstől eltiltott" -#: judge/views/problem.py:586 +#: judge/views/problem.py:548 msgid "" "You have been declared persona non grata for this problem. You are " "permanently barred from submitting this problem." @@ -2707,20 +2559,20 @@ msgstr "" "Nemkívánatos személy vagy ennél a feladatnál, így örökre el vagy tiltva a " "feltöltéstől." -#: judge/views/problem.py:600 +#: judge/views/problem.py:562 msgid "Too many submissions" msgstr "Túl sok feltöltés" -#: judge/views/problem.py:601 +#: judge/views/problem.py:563 msgid "You have exceeded the submission limit for this problem." msgstr "" -#: judge/views/problem.py:661 judge/views/problem.py:664 +#: judge/views/problem.py:633 judge/views/problem.py:636 #, python-format msgid "Submit to %(problem)s" msgstr "" -#: judge/views/problem.py:679 +#: judge/views/problem.py:652 msgid "Clone Problem" msgstr "" @@ -2761,22 +2613,22 @@ msgstr "" msgid "Generated init.yml for %s" msgstr "init.yml generálva %s-hez" -#: judge/views/problem_manage.py:52 judge/views/problem_manage.py:55 +#: judge/views/problem_manage.py:50 judge/views/problem_manage.py:53 #, python-format msgid "Managing submissions for %s" msgstr "" -#: judge/views/problem_manage.py:97 +#: judge/views/problem_manage.py:95 #, python-format msgid "Rejudging selected submissions for %s..." msgstr "" -#: judge/views/problem_manage.py:141 +#: judge/views/problem_manage.py:110 #, python-format msgid "Rescoring all submissions for %s..." msgstr "" -#: judge/views/problem_manage.py:150 +#: judge/views/problem_manage.py:119 #, python-format msgid "Successfully scheduled %d submission for rejudging." msgid_plural "Successfully scheduled %d submissions for rejudging." @@ -2825,7 +2677,7 @@ msgstr "Preferált nyelv" msgid "Subscribe to newsletter?" msgstr "Feliratkozol a hírlevélre?" -#: judge/views/register.py:55 +#: judge/views/register.py:45 #, python-format msgid "" "The email address \"%s\" is already taken. Only one registration is allowed " @@ -2834,17 +2686,17 @@ msgstr "" "A \"%s\" email cím már foglalt. Csak egy regisztráció engedélyezett " "címenként." -#: judge/views/register.py:61 +#: judge/views/register.py:51 msgid "" "Your email provider is not allowed due to history of abuse. Please use a " "reputable email provider." msgstr "" -#: judge/views/register.py:67 judge/views/register.py:105 +#: judge/views/register.py:57 judge/views/register.py:95 msgid "Registration" msgstr "Regisztráció" -#: judge/views/register.py:116 +#: judge/views/register.py:106 msgid "Authentication failure" msgstr "Azonosítási hiba" @@ -2860,100 +2712,104 @@ msgstr "Státusz" msgid "Version matrix" msgstr "Verzió mátrix" -#: judge/views/submission.py:84 judge/views/submission.py:91 +#: judge/views/submission.py:83 judge/views/submission.py:90 #, python-format msgid "Submission of %(problem)s by %(user)s" msgstr "" -#: judge/views/submission.py:244 judge/views/submission.py:245 -#: templates/problem/problem.html:167 +#: judge/views/submission.py:227 judge/views/submission.py:228 +#: templates/problem/problem.html:127 msgid "All submissions" msgstr "Összes beküldés" -#: judge/views/submission.py:404 +#: judge/views/submission.py:384 msgid "All my submissions" msgstr "Összes beküldésem" -#: judge/views/submission.py:405 +#: judge/views/submission.py:385 #, python-format msgid "All submissions by %s" msgstr "" -#: judge/views/submission.py:436 +#: judge/views/submission.py:416 #, python-format msgid "All submissions for %s" msgstr "" -#: judge/views/submission.py:455 +#: judge/views/submission.py:435 msgid "Must pass a problem" msgstr "" -#: judge/views/submission.py:501 +#: judge/views/submission.py:481 #, python-format msgid "My submissions for %(problem)s" msgstr "" -#: judge/views/submission.py:502 +#: judge/views/submission.py:482 #, python-format msgid "%(user)s's submissions for %(problem)s" msgstr "" -#: judge/views/submission.py:603 +#: judge/views/submission.py:583 msgid "Must pass a contest" msgstr "" -#: judge/views/submission.py:622 +#: judge/views/submission.py:602 #, python-brace-format msgid "" "{0}'s submissions for {2} in {4}" msgstr "" -#: judge/views/submission.py:629 +#: judge/views/submission.py:609 #, python-brace-format msgid "" "{0}'s submissions for problem {2} in {3}" "" msgstr "" -#: judge/views/ticket.py:50 judge/views/ticket.py:56 +#: judge/views/ticket.py:33 judge/views/ticket.py:39 msgid "Ticket title" msgstr "Hibajegy cím" -#: judge/views/ticket.py:107 judge/views/ticket.py:110 +#: judge/views/ticket.py:40 +msgid "Issue description" +msgstr "Probléma leírása" + +#: judge/views/ticket.py:85 judge/views/ticket.py:88 #, python-format msgid "New ticket for %s" msgstr "Új hibajegy %s-hez" -#: judge/views/ticket.py:170 +#: judge/views/ticket.py:142 #, python-format msgid "%(title)s - Ticket %(id)d" msgstr "" -#: judge/views/ticket.py:279 +#: judge/views/ticket.py:251 #, python-format msgid "Tickets - Page %(number)d of %(total)d" msgstr "" -#: judge/views/ticket.py:328 +#: judge/views/ticket.py:300 #, python-format msgid "New Ticket: %s" msgstr "Új Hibajegy: %s" -#: judge/views/ticket.py:329 +#: judge/views/ticket.py:301 #, python-format msgid "#%(id)d, assigned to: %(users)s" msgstr "" -#: judge/views/ticket.py:331 +#: judge/views/ticket.py:303 msgid ", " msgstr ", " -#: judge/views/ticket.py:331 +#: judge/views/ticket.py:303 msgid "no one" msgstr "" -#: judge/views/ticket.py:351 +#: judge/views/ticket.py:323 #, fuzzy, python-format #| msgid "New Ticket: %s" msgid "New Ticket Message For: %s" @@ -2971,52 +2827,41 @@ msgstr "" msgid "Perform Two Factor Authentication" msgstr "" -#: judge/views/user.py:74 +#: judge/views/user.py:68 msgid "No such user" msgstr "Nincs ilyen felhasználó" -#: judge/views/user.py:74 +#: judge/views/user.py:68 #, python-format msgid "No user handle \"%s\"." msgstr "" -#: judge/views/user.py:78 +#: judge/views/user.py:72 msgid "My account" msgstr "Saját fiók" -#: judge/views/user.py:79 +#: judge/views/user.py:73 #, python-format msgid "User %s" msgstr "Felhasználó %s" -#: judge/views/user.py:148 -#, fuzzy -#| msgid "M j, Y, G:i" -msgid "M j, Y" -msgstr "M j, Y, G:i" - -#: judge/views/user.py:171 +#: judge/views/user.py:136 msgid "M j, Y, G:i" msgstr "M j, Y, G:i" -#: judge/views/user.py:290 +#: judge/views/user.py:221 msgid "Updated on site" msgstr "Frissítve az oldalon" -#: judge/views/user.py:323 templates/admin/auth/user/change_form.html:14 -#: templates/admin/auth/user/change_form.html:17 templates/base.html:238 -#: templates/user/user-tabs.html:10 +#: judge/views/user.py:254 templates/admin/auth/user/change_form.html:14 +#: templates/admin/auth/user/change_form.html:17 templates/base.html:224 msgid "Edit profile" msgstr "Profil szerkesztése" -#: judge/views/user.py:332 templates/user/user-list-tabs.html:4 +#: judge/views/user.py:263 msgid "Leaderboard" msgstr "Ranglista" -#: judge/views/user.py:407 -msgid "Import Users" -msgstr "" - #: judge/views/widgets.py:48 judge/views/widgets.py:58 #, python-format msgid "Invalid upstream data: %s" @@ -3054,7 +2899,7 @@ msgid "View Submissions" msgstr "" #: templates/admin/judge/problem/change_form.html:17 -#: templates/user/user-base.html:112 +#: templates/user/user-base.html:61 msgid "View submissions" msgstr "" @@ -3069,151 +2914,92 @@ msgstr "Felhasználó szerkesztése" msgid "Rejudge" msgstr "Újratesztel" -#: templates/base.html:230 -#, python-format -msgid "Hello, %(username)s." -msgstr "Heló, %(username)s." - -#: templates/base.html:236 templates/comments/list.html:89 -#: templates/contest/contest-list-tabs.html:24 -#: templates/contest/ranking-table.html:53 -#: templates/problem/problem-list-tabs.html:6 +#: templates/base.html:222 templates/comments/list.html:89 +#: templates/contest/ranking-table.html:39 #: templates/submission/info-base.html:12 -#: templates/submission/submission-list-tabs.html:15 msgid "Admin" msgstr "Admin" -#: templates/base.html:245 +#: templates/base.html:231 msgid "Log out" msgstr "Kilépés" -#: templates/base.html:254 +#: templates/base.html:240 #: templates/registration/password_reset_complete.html:4 msgid "Log in" msgstr "" -#: templates/base.html:255 templates/registration/registration_form.html:177 +#: templates/base.html:241 templates/registration/registration_form.html:177 msgid "or" msgstr "vagy" -#: templates/base.html:256 +#: templates/base.html:242 msgid "Sign up" msgstr "" -#: templates/base.html:271 +#: templates/base.html:254 msgid "spectating" msgstr "megfigyelés" -#: templates/base.html:284 +#: templates/base.html:267 msgid "This site works best with JavaScript enabled." msgstr "Az oldal JavaScript engedélyezésével működik a legjobban." -#: templates/blog/blog.html:13 templates/comments/list.html:68 -#: templates/comments/list.html:83 templates/contest/contest-tabs.html:23 -#: templates/contest/tag-title.html:9 templates/flatpages/admin_link.html:3 -#: templates/license.html:10 templates/problem/editorial.html:14 +#: templates/blog/content.html:13 templates/comments/list.html:68 +#: templates/comments/list.html:83 templates/contest/tag-title.html:9 +#: templates/flatpages/admin_link.html:3 templates/license.html:10 +#: templates/problem/editorial.html:14 msgid "Edit" msgstr "Szerkesztés" -#: templates/blog/blog.html:26 -#, python-format -msgid "" -"\n" -" posted on %(time)s\n" -" " -msgstr "" - -#: templates/blog/content.html:10 -#, python-brace-format -msgid "posted on {time}" -msgstr "{time}-kor posztolva" - -#: templates/blog/dashboard.html:21 -#, python-format -msgid "" -"\n" -" on %(time)s\n" -" " -msgstr "" - -#: templates/blog/list.html:93 +#: templates/blog/list.html:85 msgid "Blog" msgstr "Blog" -#: templates/blog/list.html:95 +#: templates/blog/list.html:87 msgid "Events" msgstr "Események" -#: templates/blog/list.html:100 +#: templates/blog/list.html:92 msgid "News" msgstr "Hírek" -#: templates/blog/list.html:115 templates/problem/list.html:347 -#: templates/problem/problem.html:361 +#: templates/blog/list.html:130 templates/problem/problem.html:310 msgid "Clarifications" msgstr "Pontosítások" -#: templates/blog/list.html:121 -msgid "Add" -msgstr "" - -#: templates/blog/list.html:140 templates/problem/list.html:369 -#: templates/problem/problem.html:372 +#: templates/blog/list.html:146 templates/problem/problem.html:321 msgid "No clarifications have been made at this time." msgstr "Nem jelentek meg pontosítások még." -#: templates/blog/list.html:148 +#: templates/blog/list.html:154 msgid "Ongoing contests" msgstr "Folyamatban lévő versenyek" -#: templates/blog/list.html:166 +#: templates/blog/list.html:172 msgid "Upcoming contests" msgstr "Közelgő versenyek" -#: templates/blog/list.html:184 -msgid "My open tickets" -msgstr "Nyitott hibajegyeim" - -#: templates/blog/list.html:206 -msgid "New tickets" -msgstr "Új hibajegy" - -#: templates/blog/list.html:227 -msgid "New problems" -msgstr "Új feladatok" - -#: templates/blog/list.html:244 +#: templates/blog/list.html:189 msgid "Comment stream" msgstr "Kommentfolyam" -#: templates/chat/chat.html:305 -msgid "Chat" +#: templates/blog/list.html:208 +msgid "New problems" +msgstr "Új feladatok" + +#: templates/blog/list.html:225 +msgid "My open tickets" +msgstr "Nyitott hibajegyeim" + +#: templates/blog/list.html:246 +msgid "New tickets" +msgstr "Új hibajegy" + +#: templates/chat/chat.html:167 +msgid "Your message" msgstr "" -#: templates/chat/chat.html:307 templates/chat/chat.html:314 -#, fuzzy -#| msgid "Online Judge" -msgid "Online Users" -msgstr "Online tesztelő" - -#: templates/chat/chat.html:315 -msgid "Refresh" -msgstr "" - -#: templates/chat/chat.html:333 -msgid "Emoji" -msgstr "" - -#: templates/chat/chat.html:334 -msgid "Enter your message" -msgstr "" - -#: templates/chat/message.html:20 -#, fuzzy -#| msgid "Delete?" -msgid "Delete" -msgstr "Törlés?" - #: templates/comments/list.html:2 msgid "Comments" msgstr "Hozzászólások" @@ -3222,23 +3008,11 @@ msgstr "Hozzászólások" msgid "Please login to vote" msgstr "Jelentkezz be a szavazáshoz" -#: templates/comments/list.html:40 -#, fuzzy, python-brace-format -#| msgid "posted on {time}" -msgid "commented on {time}" -msgstr "{time}-kor posztolva" - -#: templates/comments/list.html:49 -#, fuzzy, python-format -#| msgid "edited" -msgid "edit %(edits)s" -msgstr "szerkesztett" - -#: templates/comments/list.html:51 templates/comments/media-js.html:92 +#: templates/comments/list.html:51 templates/comments/media-js.html:77 msgid "edited" msgstr "szerkesztett" -#: templates/comments/list.html:60 templates/notification/list.html:14 +#: templates/comments/list.html:60 msgid "Link" msgstr "Link" @@ -3246,54 +3020,36 @@ msgstr "Link" msgid "Reply" msgstr "Válasz" -#: templates/comments/list.html:86 templates/contest/list.html:91 -#: templates/contest/list.html:95 templates/contest/list.html:280 +#: templates/comments/list.html:86 msgid "Hide" msgstr "Elrejtés" -#: templates/comments/list.html:101 -#, python-format -msgid "" -"\n" -" This comment is hidden due " -"to too much negative feedback.\n" -" Click here to view it.\n" -" " -msgstr "" - -#: templates/comments/list.html:121 +#: templates/comments/list.html:120 msgid "There are no comments at the moment." msgstr "" -#: templates/comments/list.html:127 +#: templates/comments/list.html:126 msgid "New comment" msgstr "Új hozzászólás" -#: templates/comments/list.html:141 +#: templates/comments/list.html:140 msgid "Invalid comment body." msgstr "Érvénytelen hozzászólás törzs." -#: templates/comments/list.html:149 +#: templates/comments/list.html:148 msgid "Post!" msgstr "Küld!" -#: templates/comments/list.html:157 +#: templates/comments/list.html:156 msgid "Comments are disabled on this page." msgstr "" -#: templates/comments/media-js.html:38 -#, fuzzy -#| msgid "no comments" -msgid "Replying to comment" -msgstr "nincsenek hozzászólások" - -#: templates/comments/media-js.html:87 +#: templates/comments/media-js.html:72 #, python-brace-format msgid "edit {edits}" msgstr "" -#: templates/comments/media-js.html:90 +#: templates/comments/media-js.html:75 msgid "original" msgstr "" @@ -3337,11 +3093,6 @@ msgstr "Péntek" msgid "Saturday" msgstr "Szombat" -#: templates/contest/clarification.html:52 templates/organization/new.html:10 -#: templates/ticket/new.html:38 -msgid "Create" -msgstr "Létrehozás" - #: templates/contest/clone.html:37 msgid "Enter a new key for the cloned contest:" msgstr "" @@ -3362,175 +3113,97 @@ msgstr "" msgid "Next" msgstr "Következő" -#: templates/contest/contest-list-tabs.html:21 -#: templates/problem/problem-list-tabs.html:5 -msgid "List" -msgstr "Lista" - -#: templates/contest/contest-list-tabs.html:22 -msgid "Calendar" -msgstr "Naptár" - -#: templates/contest/contest-tabs.html:4 templates/organization/home.html:105 -msgid "Info" -msgstr "" - -#: templates/contest/contest-tabs.html:6 templates/stats/base.html:9 -#: templates/submission/list.html:339 -msgid "Statistics" -msgstr "" - -#: templates/contest/contest-tabs.html:11 -msgid "Rankings" -msgstr "" - -#: templates/contest/contest-tabs.html:16 -msgid "Hidden Rankings" -msgstr "" - -#: templates/contest/contest-tabs.html:21 -msgid "MOSS" -msgstr "" - -#: templates/contest/contest-tabs.html:26 -msgid "Clone" -msgstr "" - -#: templates/contest/contest-tabs.html:38 -#: templates/contest/contest-tabs.html:58 +#: templates/contest/contest-tabs.html:37 msgid "Leave contest" msgstr "" -#: templates/contest/contest-tabs.html:45 templates/contest/list.html:388 +#: templates/contest/contest-tabs.html:44 templates/contest/list.html:293 msgid "Virtual join" msgstr "Virtuális csatlakozás" -#: templates/contest/contest-tabs.html:56 -msgid "Stop spectating" -msgstr "Felhagyás a megfigyeléssel" - -#: templates/contest/contest-tabs.html:65 +#: templates/contest/contest-tabs.html:64 msgid "Spectate contest" msgstr "" -#: templates/contest/contest-tabs.html:72 +#: templates/contest/contest-tabs.html:70 +#: templates/contest/contest-tabs.html:76 msgid "Join contest" msgstr "" -#: templates/contest/contest-tabs.html:81 +#: templates/contest/contest-tabs.html:85 msgid "Login to participate" msgstr "" -#: templates/contest/contest.html:37 -msgid "Participating virtually." -msgstr "" - -#: templates/contest/contest.html:43 -msgid "Contest is over." -msgstr "A versenynek vége." - #: templates/contest/contest.html:59 templates/contest/contest.html:63 msgid "F j, Y, G:i T" msgstr "F j, Y, G:i T" -#: templates/contest/contest.html:59 -#, python-format -msgid "" -"%(time_limit)s window between %(start_time)s and " -"%(end_time)s" -msgstr "" - -#: templates/contest/contest.html:63 -#, python-format -msgid "%(length)s long starting on %(start_time)s" -msgstr "" - #: templates/contest/contest.html:85 msgid "AC Rate" msgstr "AC arány" -#: templates/contest/contest.html:86 templates/contest/list.html:237 -#: templates/contest/list.html:289 templates/contest/list.html:366 -#: templates/problem/list.html:223 templates/problem/list.html:254 +#: templates/contest/contest.html:86 templates/contest/list.html:153 +#: templates/contest/list.html:195 templates/contest/list.html:271 +#: templates/problem/list.html:212 templates/problem/list.html:238 msgid "Users" msgstr "Felhasználók" -#: templates/contest/contest.html:111 templates/problem/list.html:330 +#: templates/contest/contest.html:111 msgid "Editorial" msgstr "Megoldási útmutató" -#: templates/contest/list.html:83 templates/contest/media-js.html:9 +#: templates/contest/list.html:31 templates/contest/media-js.html:9 msgid "Are you sure you want to join?" msgstr "Biztos hogy csatlakozni akarsz?" -#: templates/contest/list.html:84 +#: templates/contest/list.html:32 msgid "" "Joining a contest for the first time starts your timer, after which it " "becomes unstoppable." msgstr "" -#: templates/contest/list.html:92 templates/contest/list.html:278 -msgid "Show" -msgstr "" - -#: templates/contest/list.html:102 templates/problem/list.html:68 -#, fuzzy -#| msgid "Organizations" -msgid "Organizations..." -msgstr "Csoportok" - -#: templates/contest/list.html:135 +#: templates/contest/list.html:65 msgid "hidden" msgstr "" -#: templates/contest/list.html:140 +#: templates/contest/list.html:70 msgid "private" msgstr "" -#: templates/contest/list.html:154 +#: templates/contest/list.html:84 msgid "rated" msgstr "" -#: templates/contest/list.html:202 +#: templates/contest/list.html:132 msgid "Spectate" msgstr "Megfigyelés" -#: templates/contest/list.html:208 +#: templates/contest/list.html:138 msgid "Join" msgstr "Csatlakozás" -#: templates/contest/list.html:220 -#, fuzzy -#| msgid "Search problems..." -msgid "Search contests..." -msgstr "Feladatok keresése..." - -#: templates/contest/list.html:229 -msgid "Search" -msgstr "" - -#: templates/contest/list.html:232 +#: templates/contest/list.html:148 msgid "Active Contests" msgstr "" -#: templates/contest/list.html:236 templates/contest/list.html:288 -#: templates/contest/list.html:327 templates/contest/list.html:365 +#: templates/contest/list.html:152 templates/contest/list.html:194 +#: templates/contest/list.html:232 templates/contest/list.html:270 msgid "Contest" msgstr "Verseny" -#: templates/contest/list.html:275 +#: templates/contest/list.html:190 msgid "Ongoing Contests" msgstr "Folyamatban lévő versenyek" -#: templates/contest/list.html:322 +#: templates/contest/list.html:227 msgid "Upcoming Contests" msgstr "Közelgő Versenyek" -#: templates/contest/list.html:350 +#: templates/contest/list.html:255 msgid "There are no scheduled contests at this time." msgstr "Jelenleg nincs ütemezett verseny." -#: templates/contest/list.html:356 +#: templates/contest/list.html:261 msgid "Past Contests" msgstr "Elmúlt Versenyek" @@ -3581,89 +3254,55 @@ msgstr "" msgid "Only the following organizations may access this contest:" msgstr "Csak a következő csoportok tagjai férhetnek hozzá ehhez a versenyhez:" -#: templates/contest/ranking-table.html:9 templates/problem/search-form.html:35 +#: templates/contest/ranking-table.html:7 msgid "Organization" msgstr "Intézmény" -#: templates/contest/ranking-table.html:10 templates/user/users-table.html:13 -#, fuzzy -#| msgid "full name" -msgid "Full Name" -msgstr "teljes név" - -#: templates/contest/ranking-table.html:44 +#: templates/contest/ranking-table.html:30 msgid "Un-Disqualify" msgstr "" -#: templates/contest/ranking-table.html:47 +#: templates/contest/ranking-table.html:33 msgid "Disqualify" msgstr "" -#: templates/contest/ranking.html:187 +#: templates/contest/ranking.html:173 #, fuzzy #| msgid "Are you sure you want to join?" msgid "Are you sure you want to disqualify this participation?" msgstr "Biztos hogy csatlakozni akarsz?" -#: templates/contest/ranking.html:192 +#: templates/contest/ranking.html:178 #, fuzzy #| msgid "Are you sure you want to join?" msgid "Are you sure you want to un-disqualify this participation?" msgstr "Biztos hogy csatlakozni akarsz?" -#: templates/contest/ranking.html:463 +#: templates/contest/ranking.html:252 msgid "View user participation" msgstr "" -#: templates/contest/ranking.html:467 +#: templates/contest/ranking.html:256 msgid "Show organizations" msgstr "Csoportok mutatása" -#: templates/contest/ranking.html:471 -#, fuzzy -#| msgid "full name" -msgid "Show full name" -msgstr "teljes név" - -#: templates/contest/ranking.html:474 -#, fuzzy -#| msgid "Show my tickets only" -msgid "Show friends only" -msgstr "Csak a saját hibajegyek mutatása" - -#: templates/contest/ranking.html:477 -msgid "Total score only" -msgstr "" - -#: templates/contest/ranking.html:479 -#, fuzzy -#| msgid "virtual participation id" -msgid "Show virtual participation" -msgstr "virtuális részvételi azonosító" - -#: templates/contest/stats.html:51 +#: templates/contest/stats.html:38 #, fuzzy #| msgid "problem translation" msgid "Problem Status Distribution" msgstr "feladat fordítás" -#: templates/contest/stats.html:56 +#: templates/contest/stats.html:43 #, fuzzy #| msgid "Problem name" msgid "Problem AC Rate" msgstr "Feladat név" -#: templates/contest/stats.html:62 -#, fuzzy -#| msgid "problem translation" -msgid "Problem Point Distribution" -msgstr "feladat fordítás" - -#: templates/contest/stats.html:76 templates/stats/language.html:16 +#: templates/contest/stats.html:48 templates/stats/language.html:16 msgid "Submissions by Language" msgstr "Beküldések nyelvenként" -#: templates/contest/stats.html:82 templates/stats/language.html:26 +#: templates/contest/stats.html:54 templates/stats/language.html:26 msgid "Language AC Rate" msgstr "" @@ -3672,7 +3311,6 @@ msgid "Source:" msgstr "Forrás:" #: templates/newsletter/common.html:6 -#: templates/newsletter/newsletter_list.html:15 #: templates/newsletter/subscription_unsubscribe_activated.html:3 #: templates/newsletter/subscription_unsubscribe_activated.html:6 #: templates/newsletter/subscription_update_activated.html:3 @@ -3680,29 +3318,6 @@ msgstr "Forrás:" msgid "Newsletter" msgstr "Hírlevél" -#: templates/newsletter/newsletter_list.html:2 -#: templates/newsletter/newsletter_list.html:3 -#, fuzzy -#| msgid "Newsletter" -msgid "Newsletter list" -msgstr "Hírlevél" - -#: templates/newsletter/newsletter_list.html:6 -msgid "Subscribe to get the latest emails about upcoming contests and events." -msgstr "" - -#: templates/newsletter/newsletter_list.html:16 -#, fuzzy -#| msgid "Unsubscribe" -msgid "Subscribe" -msgstr "Leiratkozás" - -#: templates/newsletter/newsletter_list.html:30 -#, fuzzy -#| msgid "description" -msgid "Update subscriptions" -msgstr "leírás" - #: templates/newsletter/subscription_unsubscribe_activated.html:3 #: templates/newsletter/subscription_unsubscribe_activated.html:6 #: templates/newsletter/subscription_update_activated.html:3 @@ -3764,115 +3379,64 @@ msgid "" "follow in order to update your subscription." msgstr "" -#: templates/notification/list.html:7 -#, fuzzy -#| msgid "Use desktop notification" -msgid "You have no notifications" -msgstr "Asztali értesítés használata" - -#: templates/notification/list.html:13 -#, fuzzy -#| msgid "activate" -msgid "Activity" -msgstr "aktiválás" - #: templates/organization/edit.html:46 #: templates/organization/requests/pending.html:34 #: templates/ticket/edit-notes.html:4 msgid "Update" msgstr "Frissít" -#: templates/organization/home.html:41 +#: templates/organization/home.html:7 msgid "Are you sure you want to leave this organization?" msgstr "" -#: templates/organization/home.html:43 +#: templates/organization/home.html:9 msgid "You will have to rejoin to show up on the organization leaderboard." msgstr "" -#: templates/organization/home.html:45 +#: templates/organization/home.html:11 msgid "You will have to request membership in order to join again." msgstr "" -#: templates/organization/home.html:88 -msgid "Join organization" -msgstr "Belépés a csoportba" - -#: templates/organization/home.html:92 -msgid "Request membership" -msgstr "Tagság kérelmezése" - -#: templates/organization/home.html:122 -#, fuzzy -#| msgid "Organizations" -msgid "Organization news" -msgstr "Csoportok" - -#: templates/organization/home.html:128 -#, fuzzy -#| msgid "There are no scheduled contests at this time." -msgid "There is no news at this time." -msgstr "Jelenleg nincs ütemezett verseny." - -#: templates/organization/home.html:137 -#, fuzzy -#| msgid "Contest" -msgid "Controls" -msgstr "Verseny" - -#: templates/organization/home.html:142 -msgid "Edit organization" -msgstr "Csoport szerkesztése" - -#: templates/organization/home.html:148 -msgid "View requests" -msgstr "Kérések megtekintése" - -#: templates/organization/home.html:161 -msgid "Admin organization" -msgstr "Csoport adminisztrációja" - -#: templates/organization/home.html:167 -msgid "View members" -msgstr "Tagok megtekintése" - -#: templates/organization/home.html:174 +#: templates/organization/home.html:24 msgid "Leave organization" msgstr "Csoport elhagyása" -#: templates/organization/home.html:183 -#, fuzzy -#| msgid "See private contests" -msgid "New private contests" -msgstr "Privát versenyek mutatása" +#: templates/organization/home.html:29 +msgid "Join organization" +msgstr "Belépés a csoportba" -#: templates/organization/home.html:193 templates/organization/home.html:208 -#, fuzzy -#| msgid "View as PDF" -msgid "View all" -msgstr "Mutasd PDF-ként" +#: templates/organization/home.html:33 +msgid "Request membership" +msgstr "Tagság kérelmezése" -#: templates/organization/home.html:199 -#, fuzzy -#| msgid "New problems" -msgid "New private problems" -msgstr "Új feladatok" +#: templates/organization/home.html:39 +msgid "Edit organization" +msgstr "Csoport szerkesztése" -#: templates/organization/list.html:40 -#, fuzzy -#| msgid "Show organizations" -msgid "Show my organizations only" -msgstr "Csoportok mutatása" +#: templates/organization/home.html:43 +msgid "View requests" +msgstr "Kérések megtekintése" -#: templates/organization/list.html:47 templates/status/language-list.html:34 -#: templates/user/import/table_csv.html:6 +#: templates/organization/home.html:50 +msgid "Admin organization" +msgstr "Csoport adminisztrációja" + +#: templates/organization/home.html:55 +msgid "View members" +msgstr "Tagok megtekintése" + +#: templates/organization/list.html:23 templates/status/language-list.html:34 msgid "Name" msgstr "Név" -#: templates/organization/list.html:48 +#: templates/organization/list.html:24 msgid "Members" msgstr "Tagok" +#: templates/organization/new.html:10 templates/ticket/new.html:38 +msgid "Create" +msgstr "Létrehozás" + #: templates/organization/requests/detail.html:13 msgid "User:" msgstr "Felhasználó:" @@ -3905,7 +3469,7 @@ msgid "There are no requests to approve." msgstr "Nincsenek jóváhagyásra váló kérések." #: templates/organization/requests/pending.html:17 -#: templates/problem/data.html:432 +#: templates/problem/data.html:452 msgid "Delete?" msgstr "Törlés?" @@ -3941,37 +3505,37 @@ msgstr "Kirúg" msgid "Enter a new code for the cloned problem:" msgstr "" -#: templates/problem/data.html:119 +#: templates/problem/data.html:108 #, fuzzy #| msgid "Information" msgid "Instruction" msgstr "Információ" -#: templates/problem/data.html:390 +#: templates/problem/data.html:410 msgid "View YAML" msgstr "" -#: templates/problem/data.html:421 templates/problem/data.html:472 +#: templates/problem/data.html:441 templates/problem/data.html:491 msgid "Apply!" msgstr "" -#: templates/problem/data.html:426 +#: templates/problem/data.html:446 msgid "Type" msgstr "Típus" -#: templates/problem/data.html:427 +#: templates/problem/data.html:447 msgid "Input file" msgstr "Bementi fájl" -#: templates/problem/data.html:428 +#: templates/problem/data.html:448 msgid "Output file" msgstr "Kimeneti fájl" -#: templates/problem/data.html:430 +#: templates/problem/data.html:450 msgid "Pretest?" msgstr "Preteszt?" -#: templates/problem/data.html:473 +#: templates/problem/data.html:492 msgid "Add new case" msgstr "Új eset hozzáadása" @@ -3988,34 +3552,28 @@ msgstr "" "hivatalos megoldást küldesz be mielőtt te magad megoldanád a feladatot az " "kitiltást vonhat maga után!
" -#: templates/problem/list.html:66 +#: templates/problem/list.html:62 msgid "Filter by type..." msgstr "Szűrés típus szerint..." -#: templates/problem/list.html:193 +#: templates/problem/list.html:185 msgid "Hot problems" msgstr "" -#: templates/problem/list.html:218 templates/problem/list.html:240 -#: templates/problem/search-form.html:45 templates/user/user-problems.html:57 +#: templates/problem/list.html:207 templates/problem/list.html:224 +#: templates/problem/search-form.html:30 templates/user/user-problems.html:57 msgid "Category" msgstr "Kategória" -#: templates/problem/list.html:220 templates/problem/list.html:244 +#: templates/problem/list.html:209 templates/problem/list.html:228 msgid "Types" msgstr "Típusok" -#: templates/problem/list.html:251 +#: templates/problem/list.html:235 #, python-format msgid "AC %%" msgstr "AC %%" -#: templates/problem/list.html:342 -#, fuzzy -#| msgid "Clarifications" -msgid "Add clarifications" -msgstr "Pontosítások" - #: templates/problem/manage_submission.html:55 msgid "Leave empty to not filter by language" msgstr "" @@ -4024,206 +3582,152 @@ msgstr "" msgid "Leave empty to not filter by result" msgstr "" -#: templates/problem/manage_submission.html:80 +#: templates/problem/manage_submission.html:79 msgid "Need valid values for both start and end IDs." msgstr "" -#: templates/problem/manage_submission.html:83 +#: templates/problem/manage_submission.html:82 msgid "End ID must be after start ID." msgstr "" +#: templates/problem/manage_submission.html:90 +#, python-brace-format +msgid "" +"You are about to rejudge {count} submissions. Are you sure you want to do " +"this?" +msgstr "" + #: templates/problem/manage_submission.html:96 -#, python-brace-format msgid "" -"You are about to {action} {count} submissions. Are you sure you want to do " -"this?" +"You are about to rejudge a few submissions. Are you sure you want to do this?" msgstr "" -#: templates/problem/manage_submission.html:103 -#, python-brace-format -msgid "" -"You are about to {action} a few submissions. Are you sure you want to do " -"this?" +#: templates/problem/manage_submission.html:115 +msgid "Rejudge Submissions" msgstr "" -#: templates/problem/manage_submission.html:127 -#: templates/submission/list.html:309 -msgid "Filter submissions" -msgstr "" - -#: templates/problem/manage_submission.html:132 +#: templates/problem/manage_submission.html:120 msgid "Filter by ID:" msgstr "" -#: templates/problem/manage_submission.html:135 +#: templates/problem/manage_submission.html:123 msgid "Starting ID:" msgstr "" -#: templates/problem/manage_submission.html:139 +#: templates/problem/manage_submission.html:127 msgid "Ending ID:" msgstr "" -#: templates/problem/manage_submission.html:143 +#: templates/problem/manage_submission.html:131 msgid "This range includes both endpoints." msgstr "" -#: templates/problem/manage_submission.html:146 +#: templates/problem/manage_submission.html:134 msgid "Filter by language:" msgstr "" -#: templates/problem/manage_submission.html:154 +#: templates/problem/manage_submission.html:142 msgid "Filter by result:" msgstr "" -#: templates/problem/manage_submission.html:164 -#, fuzzy -#| msgid "location" -msgid "Action" -msgstr "helyszín" - -#: templates/problem/manage_submission.html:166 +#: templates/problem/manage_submission.html:150 msgid "Rejudge selected submissions" msgstr "" -#: templates/problem/manage_submission.html:171 -#, fuzzy -#| msgid "Too many submissions" -msgid "Download selected submissions" -msgstr "Túl sok feltöltés" +#: templates/problem/manage_submission.html:157 +msgid "Rescore Everything" +msgstr "" -#: templates/problem/manage_submission.html:177 -#, fuzzy, python-format -#| msgid "Are you sure you want to join?" -msgid "Are you sure you want to rescore %(count)d submissions?" -msgstr "Biztos hogy csatlakozni akarsz?" - -#: templates/problem/manage_submission.html:178 +#: templates/problem/manage_submission.html:163 msgid "Rescore all submissions" msgstr "" -#: templates/problem/problem.html:132 +#: templates/problem/problem.html:91 msgid "View as PDF" msgstr "Mutasd PDF-ként" -#: templates/problem/problem.html:141 templates/problem/problem.html:151 -#: templates/problem/problem.html:156 +#: templates/problem/problem.html:101 templates/problem/problem.html:111 +#: templates/problem/problem.html:116 msgid "Submit solution" msgstr "Megoldás beküldése" -#: templates/problem/problem.html:144 -#, python-format -msgid "%(counter)s submission left" -msgid_plural "%(counter)s submissions left" -msgstr[0] "%(counter)s beküldés van hátra" -msgstr[1] "%(counter)s beküldés van hátra" - -#: templates/problem/problem.html:152 +#: templates/problem/problem.html:112 msgid "0 submissions left" msgstr "0 beküldés van hátra" -#: templates/problem/problem.html:164 +#: templates/problem/problem.html:124 msgid "My submissions" msgstr "Beküldéseim" -#: templates/problem/problem.html:168 +#: templates/problem/problem.html:128 msgid "Best submissions" msgstr "Legjobb beküldések" -#: templates/problem/problem.html:172 +#: templates/problem/problem.html:132 msgid "Read editorial" msgstr "Megoldási útmutató olvasása" -#: templates/problem/problem.html:177 +#: templates/problem/problem.html:137 msgid "Manage tickets" msgstr "Hibajegyek kezelése" -#: templates/problem/problem.html:181 +#: templates/problem/problem.html:141 msgid "Edit problem" msgstr "Feladat szerkesztése" -#: templates/problem/problem.html:183 +#: templates/problem/problem.html:143 msgid "Edit test data" msgstr "Teszt adatok szerkesztése" -#: templates/problem/problem.html:188 +#: templates/problem/problem.html:148 msgid "My tickets" msgstr "" -#: templates/problem/problem.html:196 +#: templates/problem/problem.html:156 msgid "Manage submissions" msgstr "" -#: templates/problem/problem.html:202 +#: templates/problem/problem.html:162 msgid "Clone problem" msgstr "Feladat klónozása" -#: templates/problem/problem.html:209 +#: templates/problem/problem.html:169 msgid "Points:" msgstr "Pontok:" -#: templates/problem/problem.html:212 templates/problem/problem.html:214 +#: templates/problem/problem.html:172 templates/problem/problem.html:174 msgid "(partial)" msgstr "(részleges)" -#: templates/problem/problem.html:219 +#: templates/problem/problem.html:179 msgid "Time limit:" msgstr "Időkorlát:" -#: templates/problem/problem.html:231 +#: templates/problem/problem.html:191 msgid "Memory limit:" msgstr "Memóriakorlát:" -#: templates/problem/problem.html:250 -msgid "Author:" -msgid_plural "Authors:" -msgstr[0] "Szerző:" -msgstr[1] "Szerzők:" - -#: templates/problem/problem.html:265 -msgid "Problem type" -msgid_plural "Problem types" -msgstr[0] "Feladat típus" -msgstr[1] "Feladat típusok" - -#: templates/problem/problem.html:278 +#: templates/problem/problem.html:238 msgid "Allowed languages" msgstr "Engedélyezett nyelvek" -#: templates/problem/problem.html:286 -#, python-format -msgid "No %(lang)s judge online" -msgstr "Nincs jelenleg online %(lang)s tesztelő" - -#: templates/problem/problem.html:297 -#, fuzzy -#| msgid "Judge" -msgid "Judge:" -msgid_plural "Judges:" -msgstr[0] "Tesztelő" -msgstr[1] "Tesztelő" - -#: templates/problem/problem.html:314 +#: templates/problem/problem.html:274 msgid "none available" msgstr "" -#: templates/problem/problem.html:326 -#, python-format -msgid "This problem has %(length)s clarification(s)" -msgstr "" - -#: templates/problem/problem.html:350 +#: templates/problem/problem.html:299 msgid "Request clarification" msgstr "Pontosítást kérek" -#: templates/problem/problem.html:352 +#: templates/problem/problem.html:301 msgid "Report an issue" msgstr "Hiba jelentése" -#: templates/problem/raw.html:64 +#: templates/problem/raw.html:62 msgid "Time Limit:" msgstr "" -#: templates/problem/raw.html:73 +#: templates/problem/raw.html:71 msgid "Memory Limit:" msgstr "" @@ -4247,75 +3751,39 @@ msgstr "" msgid "Show problem types" msgstr "" -#: templates/problem/search-form.html:32 -#, fuzzy -#| msgid "Read editorial" -msgid "Show editorial" -msgstr "Megoldási útmutató olvasása" - -#: templates/problem/search-form.html:48 templates/problem/search-form.html:50 -#: templates/submission/submission-list-tabs.html:4 +#: templates/problem/search-form.html:33 templates/problem/search-form.html:35 msgid "All" msgstr "" -#: templates/problem/search-form.html:62 +#: templates/problem/search-form.html:46 msgid "Problem types" msgstr "" -#: templates/problem/search-form.html:73 +#: templates/problem/search-form.html:57 msgid "Point range" msgstr "" -#: templates/problem/search-form.html:79 templates/submission/list.html:331 +#: templates/problem/search-form.html:63 templates/submission/list.html:331 #: templates/ticket/list.html:248 msgid "Go" msgstr "" -#: templates/problem/search-form.html:80 +#: templates/problem/search-form.html:64 msgid "Random" msgstr "" -#: templates/problem/submit.html:117 -msgid "Your source code must contain at most 65536 characters." -msgstr "" - -#: templates/problem/submit.html:204 -#, python-format -msgid "" -"Warning! Your default language, %(default_language)s, is " -"unavailable for this problem and has been deselected." -msgstr "" - -#: templates/problem/submit.html:215 -#, python-format -msgid "" -"\n" -" You have %(left)s submission left\n" -" " -msgid_plural "" -"\n" -" You have %(left)s submissions left\n" -" " -msgstr[0] "" -msgstr[1] "" - -#: templates/problem/submit.html:224 +#: templates/problem/submit.html:212 msgid "You have 0 submissions left" msgstr "" -#: templates/problem/submit.html:258 +#: templates/problem/submit.html:250 msgid "No judge is available for this problem." msgstr "" -#: templates/problem/submit.html:262 +#: templates/problem/submit.html:252 msgid "Submit!" msgstr "Beküld!" -#: templates/registration/activate.html:3 -#, python-format -msgid "%(key)s is an invalid activation key." -msgstr "" - #: templates/registration/activation_complete.html:3 msgid "Your account has been successfully activated." msgstr "" @@ -4373,13 +3841,6 @@ msgid "" "you registered with, and check your spam folder." msgstr "" -#: templates/registration/password_reset_email.txt:1 -#, python-format -msgid "" -"You're receiving this email because you requested a password reset for your " -"user account at %(site_name)s." -msgstr "" - #: templates/registration/password_reset_email.txt:3 msgid "Please go to the following page and choose a new password:" msgstr "" @@ -4392,16 +3853,6 @@ msgstr "" msgid "Thanks for using our site!" msgstr "" -#: templates/registration/password_reset_email.txt:11 -#, python-format -msgid "The %(site_name)s team" -msgstr "" - -#: templates/registration/password_reset_subject.txt:1 -#, python-format -msgid "Password reset on %(site_name)s" -msgstr "" - #: templates/registration/profile_creation.html:36 #: templates/registration/username_select.html:7 msgid "Continue >" @@ -4438,20 +3889,19 @@ msgstr "Alapértelmezett nyelv" msgid "Affiliated organizations" msgstr "Kapcsolódó csoportok" -#: templates/registration/registration_form.html:195 -#: templates/user/edit-profile.html:128 +#: templates/registration/registration_form.html:192 msgid "Notify me about upcoming contests" msgstr "" -#: templates/registration/registration_form.html:209 +#: templates/registration/registration_form.html:206 msgid "By registering, you agree to our" msgstr "" -#: templates/registration/registration_form.html:210 +#: templates/registration/registration_form.html:207 msgid "Terms & Conditions" msgstr "Felhasználási feltételek" -#: templates/registration/registration_form.html:213 +#: templates/registration/registration_form.html:210 msgid "Register!" msgstr "" @@ -4461,11 +3911,6 @@ msgstr "" msgid "Enter the 6-digit code generated by your app:" msgstr "" -#: templates/registration/totp_auth.html:41 -#, python-format -msgid "If you lost your authentication device, please contact us at %(email)s." -msgstr "" - #: templates/registration/totp_disable.html:38 msgid "" "To protect your account, you must first authenticate before you can disable " @@ -4484,6 +3929,10 @@ msgstr "" msgid "Or enter this code manually:" msgstr "" +#: templates/stats/base.html:9 templates/submission/list.html:339 +msgid "Statistics" +msgstr "" + #: templates/stats/language.html:11 msgid "Submission Statistics" msgstr "Beküldési statisztikák" @@ -4509,7 +3958,6 @@ msgid "Ping" msgstr "Ping" #: templates/status/judge-status-table.html:8 -#: templates/user/import/index.html:104 msgid "Load" msgstr "" @@ -4525,7 +3973,6 @@ msgid "There are no judges available at this time." msgstr "" #: templates/status/language-list.html:33 templates/ticket/list.html:261 -#: templates/user/import/table_csv.html:3 msgid "ID" msgstr "Azonosító" @@ -4533,26 +3980,6 @@ msgstr "Azonosító" msgid "Runtime Info" msgstr "" -#: templates/status/status-tabs.html:4 -#, fuzzy -#| msgid "Judge" -msgid "Judges" -msgstr "Tesztelő" - -#: templates/status/status-tabs.html:6 -#, fuzzy -#| msgid "Version matrix" -msgid "Version Matrix" -msgstr "Verzió mátrix" - -#: templates/submission/internal-error-message.html:3 -#, python-format -msgid "" -"An internal error occurred while grading, and the %(SITE_NAME)s " -"administrators have been notified.
In the meantime, try resubmitting in " -"a few seconds." -msgstr "" - #: templates/submission/internal-error-message.html:8 msgid "An internal error occurred while grading." msgstr "" @@ -4569,6 +3996,10 @@ msgstr "" msgid "Filter by language..." msgstr "" +#: templates/submission/list.html:309 +msgid "Filter submissions" +msgstr "" + #: templates/submission/list.html:345 msgid "Total:" msgstr "" @@ -4625,80 +4056,79 @@ msgstr "Pretesztek futtatásának eredményei" msgid "Execution Results" msgstr "" -#: templates/submission/status-testcases.html:34 +#: templates/submission/status-testcases.html:31 +msgid "Batch " +msgstr "" + +#: templates/submission/status-testcases.html:43 msgid "Overall: " msgstr "" -#: templates/submission/status-testcases.html:48 +#: templates/submission/status-testcases.html:57 #, fuzzy #| msgid "Points:" msgid "Point: " msgstr "Pontok:" -#: templates/submission/status-testcases.html:53 +#: templates/submission/status-testcases.html:62 #, fuzzy #| msgid "Time:" msgid "Time: " msgstr "Idő:" -#: templates/submission/status-testcases.html:62 +#: templates/submission/status-testcases.html:71 #, fuzzy #| msgid "Memory" msgid "Memory: " msgstr "Memória" -#: templates/submission/status-testcases.html:73 -msgid "Batch " -msgstr "" - #: templates/submission/status-testcases.html:84 -#: templates/submission/status-testcases.html:113 +msgid "Case" +msgstr "Eset" + +#: templates/submission/status-testcases.html:86 +msgid "Pretest" +msgstr "Preteszt" + +#: templates/submission/status-testcases.html:88 +msgid "Test case" +msgstr "Teszt eset" + +#: templates/submission/status-testcases.html:99 #, fuzzy #| msgid "Points" msgid "Point" msgstr "Pontok" -#: templates/submission/status-testcases.html:99 -msgid "Case" -msgstr "Eset" - -#: templates/submission/status-testcases.html:101 -msgid "Pretest" -msgstr "Preteszt" - -#: templates/submission/status-testcases.html:103 -msgid "Test case" -msgstr "Teszt eset" - -#: templates/submission/status-testcases.html:141 +#: templates/submission/status-testcases.html:121 #, fuzzy #| msgid "Input file" msgid "Input:" msgstr "Bementi fájl" -#: templates/submission/status-testcases.html:145 +#: templates/submission/status-testcases.html:125 #, fuzzy #| msgid "Output file" msgid "Output:" msgstr "Kimeneti fájl" -#: templates/submission/status-testcases.html:149 +#: templates/submission/status-testcases.html:129 #, fuzzy #| msgid "Wrong Answer" msgid "Answer:" msgstr "Rossz válasz" -#: templates/submission/status-testcases.html:154 +#: templates/submission/status-testcases.html:134 #, fuzzy #| msgid "judging feedback" msgid "Judge feedback:" msgstr "tesztelési visszajelzés" -#: templates/submission/status-testcases.html:175 +#: templates/submission/status-testcases.html:157 msgid "Passing pretests does not guarantee a full score on system tests." msgstr "" -#: templates/submission/status-testcases.html:178 +#: templates/submission/status-testcases.html:160 msgid "Submission aborted!" msgstr "" @@ -4710,24 +4140,11 @@ msgstr "Forráskód megtekintése" msgid "Abort" msgstr "Megszakít" -#: templates/submission/submission-list-tabs.html:6 -msgid "Mine" -msgstr "Saját" - -#: templates/submission/submission-list-tabs.html:9 -msgid "Best" -msgstr "Legjobb" - -#: templates/submission/submission-list-tabs.html:12 -#, python-format -msgid "%(user)s's" -msgstr "" - -#: templates/ticket/list.html:135 templates/ticket/ticket.html:273 +#: templates/ticket/list.html:135 templates/ticket/ticket.html:257 msgid "Reopened: " msgstr "Újranyitva: " -#: templates/ticket/list.html:138 templates/ticket/ticket.html:274 +#: templates/ticket/list.html:138 templates/ticket/ticket.html:258 msgid "Closed: " msgstr "Lezárva: " @@ -4751,7 +4168,7 @@ msgstr "" msgid "Title" msgstr "" -#: templates/ticket/list.html:264 templates/ticket/ticket.html:369 +#: templates/ticket/list.html:264 templates/ticket/ticket.html:328 msgid "Assignees" msgstr "" @@ -4766,36 +4183,32 @@ msgid "" "a problem, ask in the comments instead." msgstr "" -#: templates/ticket/ticket.html:355 -msgid "Post" -msgstr "" - -#: templates/ticket/ticket.html:363 +#: templates/ticket/ticket.html:322 msgid "Associated object" msgstr "" -#: templates/ticket/ticket.html:374 +#: templates/ticket/ticket.html:333 msgid "No one is assigned." msgstr "" -#: templates/ticket/ticket.html:380 +#: templates/ticket/ticket.html:339 msgid "Close ticket" msgstr "" -#: templates/ticket/ticket.html:382 +#: templates/ticket/ticket.html:341 msgid "Reopen ticket" msgstr "" -#: templates/ticket/ticket.html:386 +#: templates/ticket/ticket.html:345 msgid "Assignee notes" msgstr "" -#: templates/ticket/ticket.html:393 templates/widgets/select_all.html:4 +#: templates/ticket/ticket.html:352 templates/widgets/select_all.html:4 msgid "Nothing here." msgstr "" -#: templates/user/base-users-table.html:3 -msgid "Rank" +#: templates/ticket/ticket.html:385 +msgid "Post" msgstr "" #: templates/user/base-users.html:14 templates/user/base-users.html:69 @@ -4842,199 +4255,50 @@ msgstr "" msgid "Update profile" msgstr "" -#: templates/user/import/index.html:31 -msgid "Upload CSV only" -msgstr "" - -#: templates/user/import/index.html:100 -#, fuzzy -#| msgid "user profile" -msgid "User File" -msgstr "felhasználói profil" - -#: templates/user/import/index.html:102 -msgid "Sample" -msgstr "" - -#: templates/user/import/index.html:105 templates/user/user-list-tabs.html:8 -msgid "Import" -msgstr "" - -#: templates/user/import/table_csv.html:7 -msgid "School" -msgstr "" - -#: templates/user/pp-row.html:22 -#, python-format -msgid "" -"\n" -" weighted %(weight)s%%\n" -" " -msgstr "" - -#: templates/user/pp-row.html:27 -#, python-format -msgid "%(pp).1fpp" -msgstr "" - -#: templates/user/pp-row.html:29 -#, python-format -msgid "%(pp).0fpp" -msgstr "" - -#: templates/user/user-about.html:23 -#, fuzzy, python-format -#| msgid "contest problems" -msgid "%(counter)s problem solved" -msgid_plural "%(counter)s problems solved" -msgstr[0] "versenyfeladatok" -msgstr[1] "versenyfeladatok" - -#: templates/user/user-about.html:35 -#, fuzzy -#| msgid "allows partial points" -msgid "Total points" -msgstr "részleges pontok engedélyezése" - -#: templates/user/user-about.html:45 -#, fuzzy -#| msgid "rating" -msgid "Rank by rating" -msgstr "értékelés" - -#: templates/user/user-about.html:52 -#, fuzzy -#| msgid "points" -msgid "Rank by points" -msgstr "pontok" - -#: templates/user/user-about.html:64 +#: templates/user/user-about.html:14 msgid "From" msgstr "" -#: templates/user/user-about.html:75 +#: templates/user/user-about.html:25 msgid "Admin Notes" msgstr "" -#: templates/user/user-about.html:90 +#: templates/user/user-about.html:40 msgid "You have not shared any information." msgstr "" -#: templates/user/user-about.html:92 +#: templates/user/user-about.html:42 msgid "This user has not shared any information." msgstr "" -#: templates/user/user-about.html:101 -msgid "Awards" +#: templates/user/user-base.html:50 +msgid "Rank by points:" msgstr "" -#: templates/user/user-about.html:112 -#, fuzzy, python-format -#| msgctxt "contest problem" -#| msgid "%(problem)s in %(contest)s" -msgid "%(label)s (%(date)s)" -msgstr "%(problem)s - %(contest)s" - -#: templates/user/user-about.html:130 -#, fuzzy -#| msgid "Monday" -msgid "Mon" -msgstr "Hétfő" - -#: templates/user/user-about.html:135 -#, fuzzy -#| msgid "Tuesday" -msgid "Tues" -msgstr "Kedd" - -#: templates/user/user-about.html:140 -msgid "Wed" +#: templates/user/user-base.html:53 +msgid "Total points:" msgstr "" -#: templates/user/user-about.html:145 -#, fuzzy -#| msgid "Thursday" -msgid "Thurs" -msgstr "Csütörtök" - -#: templates/user/user-about.html:150 -#, fuzzy -#| msgid "Friday" -msgid "Fri" -msgstr "Péntek" - -#: templates/user/user-about.html:155 -#, fuzzy -#| msgid "State" -msgid "Sat" -msgstr "Állapot" - -#: templates/user/user-about.html:160 -#, fuzzy -#| msgid "Sunday" -msgid "Sun" -msgstr "Vasárnap" - -#: templates/user/user-about.html:169 -msgid "Less" +#: templates/user/user-base.html:68 +msgid "Rank by rating:" msgstr "" -#: templates/user/user-about.html:175 -msgid "More" +#: templates/user/user-base.html:70 +msgid "Rating:" msgstr "" -#: templates/user/user-about.html:184 -#, fuzzy -#| msgid "History" -msgid "Rating History" -msgstr "Előzmények" - -#: templates/user/user-about.html:255 -msgid "past year" -msgstr "" - -#: templates/user/user-about.html:272 -#, fuzzy -#| msgid "All submissions" -msgid "total submission(s)" -msgstr "Összes beküldés" - -#: templates/user/user-about.html:276 -#, fuzzy -#| msgid "0 submissions left" -msgid "submissions in the last year" -msgstr "0 beküldés van hátra" - -#: templates/user/user-base.html:101 -msgid "Unfollow" -msgstr "" - -#: templates/user/user-base.html:104 -msgid "Follow" -msgstr "" - -#: templates/user/user-base.html:120 -#, fuzzy -#| msgid "contest rated" -msgid "Contests written" -msgstr "értékelt verseny" - -#: templates/user/user-base.html:124 +#: templates/user/user-base.html:71 msgid "Volatility:" msgstr "" -#: templates/user/user-base.html:128 +#: templates/user/user-base.html:72 msgid "Min. rating:" msgstr "" -#: templates/user/user-base.html:132 +#: templates/user/user-base.html:73 msgid "Max rating:" msgstr "" -#: templates/user/user-list-tabs.html:5 -msgid "Friends" -msgstr "" - #: templates/user/user-problems.html:35 msgid "Points Breakdown" msgstr "" @@ -5055,59 +4319,31 @@ msgstr "Létrehozott feladatok" msgid "Hide problems I've solved" msgstr "" -#: templates/user/user-problems.html:93 -#, python-format -msgid "%(points).1f points" -msgstr "" - #: templates/user/user-problems.html:99 msgid "Score" msgstr "Pont" -#: templates/user/user-problems.html:110 -#, python-format -msgid "%(points)s / %(total)s" -msgstr "" - -#: templates/user/user-tabs.html:7 -#, fuzzy -#| msgid "personae non gratae" -msgid "Impersonate" -msgstr "nemkívánatos személy" - -#: templates/user/user-tabs.html:13 -#, fuzzy -#| msgid "Admin" -msgid "Admin User" -msgstr "Admin" - -#: templates/user/user-tabs.html:16 -#, fuzzy -#| msgid "Edit profile" -msgid "Admin Profile" -msgstr "Profil szerkesztése" - #: templates/widgets/select_all.html:8 msgid "Check all" msgstr "Az összes kijelölése" -#, fuzzy -#~| msgid "%(counter)s submission left" -#~| msgid_plural "%(counter)s submissions left" -#~ msgid "%(cnt)d submission on %(date)s" -#~ msgid_plural "%(cnt)d submissions on %(date)s" -#~ msgstr[0] "%(counter)s beküldés van hátra" -#~ msgstr[1] "%(counter)s beküldés van hátra" +#~ msgid "Hello, %(username)s." +#~ msgstr "Heló, %(username)s." -#, fuzzy -#~| msgid "Admin" -#~ msgid "Admins" -#~ msgstr "Admin" +#~ msgid "posted on {time}" +#~ msgstr "{time}-kor posztolva" -#, fuzzy -#~| msgid "Rescore the selected submissions" -#~ msgid "This will rescore %(count)d submissions." -#~ msgstr "A kiválasztott feltöltések újrapontozása" +#~ msgid "List" +#~ msgstr "Lista" + +#~ msgid "Calendar" +#~ msgstr "Naptár" + +#~ msgid "Stop spectating" +#~ msgstr "Felhagyás a megfigyeléssel" + +#~ msgid "Contest is over." +#~ msgstr "A versenynek vége." #~ msgid "Output limit" #~ msgstr "Kimenet limit" @@ -5118,6 +4354,24 @@ msgstr "Az összes kijelölése" #~ msgid "Generator args" #~ msgstr "Generátor argumentumok" +#~ msgid "%(counter)s submission left" +#~ msgid_plural "%(counter)s submissions left" +#~ msgstr[0] "%(counter)s beküldés van hátra" +#~ msgstr[1] "%(counter)s beküldés van hátra" + +#~ msgid "Author:" +#~ msgid_plural "Authors:" +#~ msgstr[0] "Szerző:" +#~ msgstr[1] "Szerzők:" + +#~ msgid "Problem type" +#~ msgid_plural "Problem types" +#~ msgstr[0] "Feladat típus" +#~ msgstr[1] "Feladat típusok" + +#~ msgid "No %(lang)s judge online" +#~ msgstr "Nincs jelenleg online %(lang)s tesztelő" + #~ msgid "Your output (clipped)" #~ msgstr "A kimeneted (levágva)" @@ -5126,3 +4380,9 @@ msgstr "Az összes kijelölése" #~ msgid "Final score:" #~ msgstr "Végső pontszám:" + +#~ msgid "Mine" +#~ msgstr "Saját" + +#~ msgid "Best" +#~ msgstr "Legjobb" diff --git a/locale/hu/LC_MESSAGES/djangojs.po b/locale/hu/LC_MESSAGES/djangojs.po index 24f1796..83fa1a0 100644 --- a/locale/hu/LC_MESSAGES/djangojs.po +++ b/locale/hu/LC_MESSAGES/djangojs.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: dmoj\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-07-20 23:30+0700\n" +"POT-Creation-Date: 2019-10-01 23:12+0000\n" "PO-Revision-Date: 2019-11-11 22:05\n" "Last-Translator: Icyene\n" "Language-Team: Hungarian\n" @@ -27,3 +27,4 @@ msgstr[1] "%d nap %h:%m:%s" msgctxt "time format without day" msgid "%h:%m:%s" msgstr "%h:%m:%s" + diff --git a/locale/it/LC_MESSAGES/django.po b/locale/it/LC_MESSAGES/django.po index cd68ad8..1e2b8a0 100644 --- a/locale/it/LC_MESSAGES/django.po +++ b/locale/it/LC_MESSAGES/django.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: dmoj\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-10-25 05:59+0700\n" +"POT-Creation-Date: 2020-04-10 01:26-0500\n" "PO-Revision-Date: 2019-11-11 22:05\n" "Last-Translator: Icyene\n" "Language-Team: Italian\n" @@ -16,93 +16,93 @@ msgstr "" "X-Crowdin-Language: it\n" "X-Crowdin-File: django.po\n" -#: chat_box/models.py:16 judge/admin/interface.py:110 -#: judge/models/contest.py:403 judge/models/contest.py:528 -#: judge/models/profile.py:211 +#: chat_box/models.py:15 judge/admin/interface.py:107 +#: judge/models/contest.py:257 judge/models/contest.py:381 +#: judge/models/profile.py:191 msgid "user" msgstr "" -#: chat_box/models.py:17 judge/models/comment.py:43 judge/models/comment.py:191 +#: chat_box/models.py:16 judge/models/comment.py:42 msgid "posted time" msgstr "" -#: chat_box/models.py:18 judge/models/comment.py:47 +#: chat_box/models.py:17 judge/models/comment.py:46 msgid "body of comment" msgstr "" -#: chat_box/views.py:29 templates/chat/chat.html:4 +#: chat_box/views.py:29 msgid "Chat Box" msgstr "" -#: dmoj/settings.py:355 +#: dmoj/settings.py:349 msgid "German" msgstr "" -#: dmoj/settings.py:356 +#: dmoj/settings.py:350 msgid "English" msgstr "" -#: dmoj/settings.py:357 +#: dmoj/settings.py:351 msgid "Spanish" msgstr "" -#: dmoj/settings.py:358 +#: dmoj/settings.py:352 msgid "French" msgstr "" -#: dmoj/settings.py:359 +#: dmoj/settings.py:353 msgid "Croatian" msgstr "" -#: dmoj/settings.py:360 +#: dmoj/settings.py:354 msgid "Hungarian" msgstr "" -#: dmoj/settings.py:361 +#: dmoj/settings.py:355 msgid "Japanese" msgstr "" -#: dmoj/settings.py:362 +#: dmoj/settings.py:356 msgid "Korean" msgstr "" -#: dmoj/settings.py:363 +#: dmoj/settings.py:357 msgid "Brazilian Portuguese" msgstr "" -#: dmoj/settings.py:364 +#: dmoj/settings.py:358 msgid "Romanian" msgstr "" -#: dmoj/settings.py:365 +#: dmoj/settings.py:359 msgid "Russian" msgstr "" -#: dmoj/settings.py:366 +#: dmoj/settings.py:360 msgid "Serbian (Latin)" msgstr "" -#: dmoj/settings.py:367 +#: dmoj/settings.py:361 msgid "Turkish" msgstr "" -#: dmoj/settings.py:368 +#: dmoj/settings.py:362 msgid "Vietnamese" msgstr "" -#: dmoj/settings.py:369 +#: dmoj/settings.py:363 msgid "Simplified Chinese" msgstr "" -#: dmoj/settings.py:370 +#: dmoj/settings.py:364 msgid "Traditional Chinese" msgstr "" -#: dmoj/urls.py:58 +#: dmoj/urls.py:57 msgid "Login" msgstr "" -#: dmoj/urls.py:106 templates/base.html:193 +#: dmoj/urls.py:105 templates/base.html:190 msgid "Home" msgstr "" @@ -132,92 +132,90 @@ msgstr "" msgid "Associated page" msgstr "" -#: judge/admin/contest.py:30 +#: judge/admin/contest.py:28 msgid "Included contests" msgstr "" -#: judge/admin/contest.py:66 templates/contest/clarification.html:42 -#: templates/contest/contest.html:83 templates/contest/moss.html:43 -#: templates/problem/list.html:214 templates/problem/list.html:232 -#: templates/problem/list.html:350 templates/user/user-problems.html:56 +#: judge/admin/contest.py:64 templates/contest/contest.html:83 +#: templates/contest/moss.html:43 templates/problem/list.html:206 +#: templates/problem/list.html:221 templates/user/user-problems.html:56 #: templates/user/user-problems.html:98 msgid "Problem" msgstr "" -#: judge/admin/contest.py:119 +#: judge/admin/contest.py:112 msgid "Settings" msgstr "" -#: judge/admin/contest.py:121 +#: judge/admin/contest.py:114 msgid "Scheduling" msgstr "" -#: judge/admin/contest.py:122 templates/organization/home.html:107 +#: judge/admin/contest.py:115 msgid "Details" msgstr "" -#: judge/admin/contest.py:123 +#: judge/admin/contest.py:116 msgid "Format" msgstr "" -#: judge/admin/contest.py:124 templates/contest/ranking-table.html:7 -#: templates/user/user-about.html:15 templates/user/user-about.html:45 +#: judge/admin/contest.py:117 templates/contest/ranking-table.html:5 msgid "Rating" msgstr "" -#: judge/admin/contest.py:125 +#: judge/admin/contest.py:118 msgid "Access" msgstr "" -#: judge/admin/contest.py:127 judge/admin/problem.py:131 +#: judge/admin/contest.py:120 judge/admin/problem.py:131 msgid "Justice" msgstr "" -#: judge/admin/contest.py:207 +#: judge/admin/contest.py:158 #, python-format msgid "%d contest successfully marked as visible." msgid_plural "%d contests successfully marked as visible." msgstr[0] "" msgstr[1] "" -#: judge/admin/contest.py:210 +#: judge/admin/contest.py:161 msgid "Mark contests as visible" msgstr "" -#: judge/admin/contest.py:216 +#: judge/admin/contest.py:165 #, python-format msgid "%d contest successfully marked as hidden." msgid_plural "%d contests successfully marked as hidden." msgstr[0] "" msgstr[1] "" -#: judge/admin/contest.py:219 +#: judge/admin/contest.py:168 msgid "Mark contests as hidden" msgstr "" -#: judge/admin/contest.py:233 judge/admin/submission.py:164 +#: judge/admin/contest.py:182 judge/admin/submission.py:164 #, python-format msgid "%d submission was successfully scheduled for rejudging." msgid_plural "%d submissions were successfully scheduled for rejudging." msgstr[0] "" msgstr[1] "" -#: judge/admin/contest.py:308 +#: judge/admin/contest.py:256 #, python-format msgid "%d participation recalculated." msgid_plural "%d participations recalculated." msgstr[0] "" msgstr[1] "" -#: judge/admin/contest.py:311 +#: judge/admin/contest.py:259 msgid "Recalculate results" msgstr "" -#: judge/admin/contest.py:315 judge/admin/organization.py:65 +#: judge/admin/contest.py:263 judge/admin/organization.py:65 msgid "username" msgstr "" -#: judge/admin/contest.py:320 templates/base.html:277 +#: judge/admin/contest.py:268 templates/base.html:260 msgid "virtual" msgstr "" @@ -225,15 +223,15 @@ msgstr "" msgid "link path" msgstr "" -#: judge/admin/interface.py:65 +#: judge/admin/interface.py:62 msgid "Content" msgstr "" -#: judge/admin/interface.py:66 +#: judge/admin/interface.py:63 msgid "Summary" msgstr "" -#: judge/admin/interface.py:151 +#: judge/admin/interface.py:148 msgid "object" msgstr "" @@ -255,9 +253,8 @@ msgid "Taxonomy" msgstr "" #: judge/admin/problem.py:128 templates/contest/contest.html:84 -#: templates/problem/data.html:429 templates/problem/list.html:222 -#: templates/problem/list.html:248 templates/user/base-users-table.html:10 -#: templates/user/user-about.html:36 templates/user/user-about.html:52 +#: templates/problem/data.html:449 templates/problem/list.html:211 +#: templates/problem/list.html:232 templates/user/base-users-table.html:10 #: templates/user/user-problems.html:58 msgid "Points" msgstr "" @@ -306,7 +303,6 @@ msgid "timezone" msgstr "" #: judge/admin/profile.py:86 judge/admin/submission.py:211 -#: templates/notification/list.html:12 #: templates/organization/requests/log.html:9 #: templates/organization/requests/pending.html:12 #: templates/ticket/list.html:263 @@ -314,7 +310,6 @@ msgid "User" msgstr "" #: judge/admin/profile.py:91 templates/registration/registration_form.html:145 -#: templates/user/import/table_csv.html:8 msgid "Email" msgstr "" @@ -347,7 +342,7 @@ msgstr "" msgid "These problems are NOT allowed to be submitted in this language" msgstr "" -#: judge/admin/runtime.py:83 templates/problem/list.html:352 +#: judge/admin/runtime.py:83 msgid "Description" msgstr "" @@ -394,7 +389,7 @@ msgstr "" msgid "Rejudge the selected submissions" msgstr "" -#: judge/admin/submission.py:193 judge/views/problem_manage.py:159 +#: judge/admin/submission.py:193 judge/views/problem_manage.py:128 #, python-format msgid "%d submission were successfully rescored." msgid_plural "%d submissions were successfully rescored." @@ -405,8 +400,7 @@ msgstr[1] "" msgid "Rescore the selected submissions" msgstr "" -#: judge/admin/submission.py:200 templates/problem/list.html:216 -#: templates/problem/list.html:236 +#: judge/admin/submission.py:200 msgid "Problem code" msgstr "" @@ -414,12 +408,10 @@ msgstr "" msgid "Problem name" msgstr "" -#: judge/admin/submission.py:215 templates/notification/list.html:15 -#: templates/organization/requests/log.html:10 +#: judge/admin/submission.py:215 templates/organization/requests/log.html:10 #: templates/organization/requests/pending.html:13 -#: templates/problem/list.html:351 -#: templates/submission/status-testcases.html:125 -#: templates/submission/status-testcases.html:127 +#: templates/submission/status-testcases.html:105 +#: templates/submission/status-testcases.html:107 msgid "Time" msgstr "" @@ -433,7 +425,7 @@ msgstr "" msgid "%.2f MB" msgstr "" -#: judge/admin/submission.py:227 templates/submission/status-testcases.html:132 +#: judge/admin/submission.py:227 templates/submission/status-testcases.html:112 msgid "Memory" msgstr "" @@ -453,20 +445,20 @@ msgstr "" msgid "Online Judge" msgstr "" -#: judge/comments.py:60 +#: judge/comments.py:41 msgid "Comment body" msgstr "" -#: judge/comments.py:66 judge/views/ticket.py:63 +#: judge/comments.py:47 judge/views/ticket.py:46 msgid "Your part is silent, little toad." msgstr "" -#: judge/comments.py:69 templates/comments/list.html:132 +#: judge/comments.py:50 templates/comments/list.html:131 msgid "" "You need to have solved at least one problem before your voice can be heard." msgstr "" -#: judge/comments.py:113 +#: judge/comments.py:92 msgid "Posted comment" msgstr "" @@ -482,10 +474,6 @@ msgstr "" msgid "ECOO" msgstr "" -#: judge/contest_format/icpc.py:19 -msgid "ICPC" -msgstr "" - #: judge/contest_format/ioi.py:19 msgid "IOI" msgstr "" @@ -498,58 +486,52 @@ msgstr "" msgid "Enable experimental features" msgstr "" -#: judge/forms.py:57 judge/views/organization.py:168 judge/views/register.py:49 +#: judge/forms.py:57 judge/views/organization.py:127 #, python-brace-format msgid "You may not be part of more than {count} public organizations." msgstr "" -#: judge/forms.py:82 -msgid "Any judge" -msgstr "" - -#: judge/forms.py:112 judge/views/register.py:26 +#: judge/forms.py:107 judge/views/register.py:26 #: templates/registration/registration_form.html:139 #: templates/user/base-users-table.html:5 -#: templates/user/import/table_csv.html:4 msgid "Username" msgstr "" -#: judge/forms.py:113 templates/registration/registration_form.html:151 +#: judge/forms.py:108 templates/registration/registration_form.html:151 #: templates/registration/registration_form.html:165 -#: templates/user/import/table_csv.html:5 msgid "Password" msgstr "" -#: judge/forms.py:135 +#: judge/forms.py:130 msgid "Two Factor Authentication tokens must be 6 decimal digits." msgstr "" -#: judge/forms.py:144 templates/registration/totp_auth.html:32 +#: judge/forms.py:139 templates/registration/totp_auth.html:32 msgid "Invalid Two Factor Authentication token." msgstr "" -#: judge/forms.py:148 judge/models/problem.py:97 +#: judge/forms.py:143 judge/models/problem.py:97 msgid "Problem code must be ^[a-z0-9]+$" msgstr "" -#: judge/forms.py:153 +#: judge/forms.py:148 msgid "Problem with code already exists." msgstr "" -#: judge/forms.py:158 judge/models/contest.py:61 +#: judge/forms.py:153 judge/models/contest.py:52 msgid "Contest id must be ^[a-z0-9]+$" msgstr "" -#: judge/forms.py:163 +#: judge/forms.py:158 msgid "Contest with key already exists." msgstr "" -#: judge/jinja2/datetime.py:26 templates/blog/blog.html:26 +#: judge/jinja2/datetime.py:26 templates/blog/content.html:27 #: templates/blog/dashboard.html:21 msgid "N j, Y, g:i a" msgstr "" -#: judge/jinja2/datetime.py:26 templates/chat/message.html:13 +#: judge/jinja2/datetime.py:26 #, python-brace-format msgid "{time}" msgstr "" @@ -579,542 +561,472 @@ msgstr "" msgid "Detect best quality" msgstr "" -#: judge/models/comment.py:26 +#: judge/models/comment.py:25 msgid "Page code must be ^[pcs]:[a-z0-9]+$|^b:\\d+$" msgstr "" -#: judge/models/comment.py:42 +#: judge/models/comment.py:41 msgid "commenter" msgstr "" -#: judge/models/comment.py:44 judge/models/comment.py:177 +#: judge/models/comment.py:43 judge/models/comment.py:176 msgid "associated page" msgstr "" -#: judge/models/comment.py:46 +#: judge/models/comment.py:45 msgid "votes" msgstr "" -#: judge/models/comment.py:48 +#: judge/models/comment.py:47 msgid "hide the comment" msgstr "" -#: judge/models/comment.py:49 +#: judge/models/comment.py:48 msgid "parent" msgstr "" -#: judge/models/comment.py:54 judge/models/comment.py:192 +#: judge/models/comment.py:53 msgid "comment" msgstr "" -#: judge/models/comment.py:55 +#: judge/models/comment.py:54 msgid "comments" msgstr "" -#: judge/models/comment.py:137 judge/models/problem.py:443 +#: judge/models/comment.py:136 judge/models/problem.py:406 #, python-format msgid "Editorial for %s" msgstr "" -#: judge/models/comment.py:172 +#: judge/models/comment.py:171 msgid "comment vote" msgstr "" -#: judge/models/comment.py:173 +#: judge/models/comment.py:172 msgid "comment votes" msgstr "" -#: judge/models/comment.py:182 +#: judge/models/comment.py:181 msgid "Override comment lock" msgstr "" -#: judge/models/comment.py:190 -msgid "owner" -msgstr "" - -#: judge/models/comment.py:193 judge/models/message.py:16 -msgid "read" -msgstr "" - -#: judge/models/comment.py:194 -msgid "category" -msgstr "" - -#: judge/models/comment.py:195 -msgid "html link to comments, used for non-comments" -msgstr "" - -#: judge/models/comment.py:196 -msgid "who trigger, used for non-comment" -msgstr "" - -#: judge/models/contest.py:23 +#: judge/models/contest.py:22 msgid "Invalid colour." msgstr "" -#: judge/models/contest.py:25 +#: judge/models/contest.py:24 msgid "tag name" msgstr "" -#: judge/models/contest.py:26 +#: judge/models/contest.py:25 msgid "Lowercase letters and hyphens only." msgstr "" -#: judge/models/contest.py:27 +#: judge/models/contest.py:26 msgid "tag colour" msgstr "" -#: judge/models/contest.py:28 +#: judge/models/contest.py:27 msgid "tag description" msgstr "" -#: judge/models/contest.py:47 +#: judge/models/contest.py:46 msgid "contest tag" msgstr "" -#: judge/models/contest.py:48 judge/models/contest.py:118 +#: judge/models/contest.py:47 judge/models/contest.py:101 msgid "contest tags" msgstr "" -#: judge/models/contest.py:56 -msgid "Visible" -msgstr "" - -#: judge/models/contest.py:57 -msgid "Hidden for duration of contest" -msgstr "" - -#: judge/models/contest.py:58 -msgid "Hidden for duration of participation" -msgstr "" - -#: judge/models/contest.py:60 +#: judge/models/contest.py:51 msgid "contest id" msgstr "" -#: judge/models/contest.py:62 +#: judge/models/contest.py:53 msgid "contest name" msgstr "" -#: judge/models/contest.py:63 -msgid "These users will be able to edit the contest." +#: judge/models/contest.py:54 +msgid "These people will be able to edit the contest." msgstr "" -#: judge/models/contest.py:65 -msgid "" -"These users will be able to edit the contest, but will not be listed as " -"authors." -msgstr "" - -#: judge/models/contest.py:68 -msgid "These users will be able to view the contest, but not edit it." -msgstr "" - -#: judge/models/contest.py:71 judge/models/runtime.py:136 +#: judge/models/contest.py:56 judge/models/runtime.py:133 msgid "description" msgstr "" -#: judge/models/contest.py:72 judge/models/problem.py:390 -#: judge/models/runtime.py:138 +#: judge/models/contest.py:57 judge/models/problem.py:353 +#: judge/models/runtime.py:135 msgid "problems" msgstr "" -#: judge/models/contest.py:73 judge/models/contest.py:404 +#: judge/models/contest.py:58 judge/models/contest.py:258 msgid "start time" msgstr "" -#: judge/models/contest.py:74 +#: judge/models/contest.py:59 msgid "end time" msgstr "" -#: judge/models/contest.py:75 judge/models/problem.py:118 -#: judge/models/problem.py:414 +#: judge/models/contest.py:60 judge/models/problem.py:118 +#: judge/models/problem.py:377 msgid "time limit" msgstr "" -#: judge/models/contest.py:76 judge/models/problem.py:136 +#: judge/models/contest.py:61 judge/models/problem.py:136 msgid "publicly visible" msgstr "" -#: judge/models/contest.py:77 +#: judge/models/contest.py:62 msgid "" "Should be set even for organization-private contests, where it determines " "whether the contest is visible to members of the specified organizations." msgstr "" -#: judge/models/contest.py:80 +#: judge/models/contest.py:65 msgid "contest rated" msgstr "" -#: judge/models/contest.py:80 +#: judge/models/contest.py:65 msgid "Whether this contest can be rated." msgstr "" -#: judge/models/contest.py:82 -msgid "scoreboard visibility" +#: judge/models/contest.py:67 +msgid "hide scoreboard" msgstr "" -#: judge/models/contest.py:83 -msgid "Scoreboard visibility through the duration of the contest" +#: judge/models/contest.py:68 +msgid "" +"Whether the scoreboard should remain hidden for the duration of the contest." msgstr "" -#: judge/models/contest.py:85 -msgid "view contest scoreboard" -msgstr "" - -#: judge/models/contest.py:87 -msgid "These users will be able to view the scoreboard." -msgstr "" - -#: judge/models/contest.py:88 +#: judge/models/contest.py:71 msgid "no comments" msgstr "" -#: judge/models/contest.py:89 +#: judge/models/contest.py:72 msgid "Use clarification system instead of comments." msgstr "" -#: judge/models/contest.py:91 +#: judge/models/contest.py:74 msgid "Rating floor for contest" msgstr "" -#: judge/models/contest.py:93 +#: judge/models/contest.py:76 msgid "Rating ceiling for contest" msgstr "" -#: judge/models/contest.py:95 +#: judge/models/contest.py:78 msgid "rate all" msgstr "" -#: judge/models/contest.py:95 +#: judge/models/contest.py:78 msgid "Rate all users who joined." msgstr "" -#: judge/models/contest.py:96 +#: judge/models/contest.py:79 msgid "exclude from ratings" msgstr "" -#: judge/models/contest.py:98 +#: judge/models/contest.py:81 msgid "private to specific users" msgstr "" -#: judge/models/contest.py:99 +#: judge/models/contest.py:82 msgid "private contestants" msgstr "" -#: judge/models/contest.py:100 +#: judge/models/contest.py:83 msgid "If private, only these users may see the contest" msgstr "" -#: judge/models/contest.py:102 +#: judge/models/contest.py:85 msgid "hide problem tags" msgstr "" -#: judge/models/contest.py:103 +#: judge/models/contest.py:86 msgid "Whether problem tags should be hidden by default." msgstr "" -#: judge/models/contest.py:105 +#: judge/models/contest.py:88 msgid "run pretests only" msgstr "" -#: judge/models/contest.py:106 +#: judge/models/contest.py:89 msgid "" "Whether judges should grade pretests only, versus all testcases. Commonly " "set during a contest, then unset prior to rejudging user submissions when " "the contest ends." msgstr "" -#: judge/models/contest.py:110 judge/models/interface.py:77 -#: judge/models/problem.py:157 +#: judge/models/contest.py:93 judge/models/problem.py:157 msgid "private to organizations" msgstr "" -#: judge/models/contest.py:111 judge/models/interface.py:75 -#: judge/models/problem.py:155 judge/models/profile.py:77 +#: judge/models/contest.py:94 judge/models/problem.py:155 +#: judge/models/profile.py:77 msgid "organizations" msgstr "" -#: judge/models/contest.py:112 +#: judge/models/contest.py:95 msgid "If private, only these organizations may see the contest" msgstr "" -#: judge/models/contest.py:113 judge/models/problem.py:145 +#: judge/models/contest.py:96 judge/models/problem.py:145 msgid "OpenGraph image" msgstr "" -#: judge/models/contest.py:114 judge/models/profile.py:48 +#: judge/models/contest.py:97 judge/models/profile.py:48 msgid "Logo override image" msgstr "" -#: judge/models/contest.py:116 +#: judge/models/contest.py:99 msgid "" "This image will replace the default site logo for users inside the contest." msgstr "" -#: judge/models/contest.py:119 +#: judge/models/contest.py:102 msgid "the amount of live participants" msgstr "" -#: judge/models/contest.py:120 +#: judge/models/contest.py:103 msgid "contest summary" msgstr "" -#: judge/models/contest.py:121 judge/models/problem.py:147 +#: judge/models/contest.py:104 judge/models/problem.py:147 msgid "Plain-text, shown in meta description tag, e.g. for social media." msgstr "" -#: judge/models/contest.py:122 judge/models/profile.py:47 +#: judge/models/contest.py:105 judge/models/profile.py:47 msgid "access code" msgstr "" -#: judge/models/contest.py:123 +#: judge/models/contest.py:106 msgid "" "An optional code to prompt contestants before they are allowed to join the " "contest. Leave it blank to disable." msgstr "" -#: judge/models/contest.py:125 judge/models/problem.py:141 +#: judge/models/contest.py:108 judge/models/problem.py:141 msgid "personae non gratae" msgstr "" -#: judge/models/contest.py:126 +#: judge/models/contest.py:109 msgid "Bans the selected users from joining this contest." msgstr "" -#: judge/models/contest.py:127 +#: judge/models/contest.py:110 msgid "contest format" msgstr "" -#: judge/models/contest.py:128 +#: judge/models/contest.py:111 msgid "The contest format module to use." msgstr "" -#: judge/models/contest.py:129 +#: judge/models/contest.py:112 msgid "contest format configuration" msgstr "" -#: judge/models/contest.py:130 +#: judge/models/contest.py:113 msgid "" "A JSON object to serve as the configuration for the chosen contest format " "module. Leave empty to use None. Exact format depends on the contest format " "selected." msgstr "" -#: judge/models/contest.py:137 -msgid "precision points" -msgstr "" - -#: judge/models/contest.py:139 -msgid "Number of digits to round points to." -msgstr "" - -#: judge/models/contest.py:383 +#: judge/models/contest.py:239 msgid "See private contests" msgstr "" -#: judge/models/contest.py:384 +#: judge/models/contest.py:240 msgid "Edit own contests" msgstr "" -#: judge/models/contest.py:385 +#: judge/models/contest.py:241 msgid "Edit all contests" msgstr "" -#: judge/models/contest.py:386 +#: judge/models/contest.py:242 msgid "Clone contest" msgstr "" -#: judge/models/contest.py:387 templates/contest/moss.html:74 +#: judge/models/contest.py:243 templates/contest/moss.html:74 msgid "MOSS contest" msgstr "" -#: judge/models/contest.py:388 +#: judge/models/contest.py:244 msgid "Rate contests" msgstr "" -#: judge/models/contest.py:389 +#: judge/models/contest.py:245 msgid "Contest access codes" msgstr "" -#: judge/models/contest.py:390 +#: judge/models/contest.py:246 msgid "Create private contests" msgstr "" -#: judge/models/contest.py:391 -msgid "Change contest visibility" -msgstr "" - -#: judge/models/contest.py:392 -msgid "Edit contest problem label script" -msgstr "" - -#: judge/models/contest.py:394 judge/models/contest.py:492 -#: judge/models/contest.py:529 judge/models/contest.py:552 -#: judge/models/submission.py:84 +#: judge/models/contest.py:248 judge/models/contest.py:345 +#: judge/models/contest.py:382 judge/models/contest.py:404 +#: judge/models/submission.py:83 msgid "contest" msgstr "" -#: judge/models/contest.py:395 +#: judge/models/contest.py:249 msgid "contests" msgstr "" -#: judge/models/contest.py:402 +#: judge/models/contest.py:256 msgid "associated contest" msgstr "" -#: judge/models/contest.py:405 +#: judge/models/contest.py:259 msgid "score" msgstr "" -#: judge/models/contest.py:406 +#: judge/models/contest.py:260 msgid "cumulative time" msgstr "" -#: judge/models/contest.py:407 +#: judge/models/contest.py:261 msgid "is disqualified" msgstr "" -#: judge/models/contest.py:408 +#: judge/models/contest.py:262 msgid "Whether this participation is disqualified." msgstr "" -#: judge/models/contest.py:409 -msgid "tie-breaking field" -msgstr "" - -#: judge/models/contest.py:410 +#: judge/models/contest.py:263 msgid "virtual participation id" msgstr "" -#: judge/models/contest.py:411 +#: judge/models/contest.py:264 msgid "0 means non-virtual, otherwise the n-th virtual participation." msgstr "" -#: judge/models/contest.py:412 +#: judge/models/contest.py:265 msgid "contest format specific data" msgstr "" -#: judge/models/contest.py:478 +#: judge/models/contest.py:331 #, python-format msgid "%s spectating in %s" msgstr "" -#: judge/models/contest.py:480 +#: judge/models/contest.py:333 #, python-format msgid "%s in %s, v%d" msgstr "" -#: judge/models/contest.py:481 +#: judge/models/contest.py:334 #, python-format msgid "%s in %s" msgstr "" -#: judge/models/contest.py:484 +#: judge/models/contest.py:337 msgid "contest participation" msgstr "" -#: judge/models/contest.py:485 +#: judge/models/contest.py:338 msgid "contest participations" msgstr "" -#: judge/models/contest.py:491 judge/models/contest.py:513 -#: judge/models/contest.py:553 judge/models/problem.py:389 -#: judge/models/problem.py:394 judge/models/problem.py:412 -#: judge/models/problem_data.py:40 +#: judge/models/contest.py:344 judge/models/contest.py:366 +#: judge/models/contest.py:405 judge/models/problem.py:352 +#: judge/models/problem.py:357 judge/models/problem.py:375 +#: judge/models/problem_data.py:38 msgid "problem" msgstr "" -#: judge/models/contest.py:493 judge/models/contest.py:517 +#: judge/models/contest.py:346 judge/models/contest.py:370 #: judge/models/problem.py:129 msgid "points" msgstr "" -#: judge/models/contest.py:494 +#: judge/models/contest.py:347 msgid "partial" msgstr "" -#: judge/models/contest.py:495 judge/models/contest.py:518 +#: judge/models/contest.py:348 judge/models/contest.py:371 msgid "is pretested" msgstr "" -#: judge/models/contest.py:496 judge/models/interface.py:43 +#: judge/models/contest.py:349 judge/models/interface.py:43 msgid "order" msgstr "" -#: judge/models/contest.py:497 +#: judge/models/contest.py:350 msgid "0 to not show testcases, 1 to show" msgstr "" -#: judge/models/contest.py:498 +#: judge/models/contest.py:351 msgid "visible testcases" msgstr "" -#: judge/models/contest.py:499 +#: judge/models/contest.py:352 msgid "Maximum number of submissions for this problem, or 0 for no limit." msgstr "" -#: judge/models/contest.py:501 +#: judge/models/contest.py:354 msgid "Why include a problem you can't submit to?" msgstr "" -#: judge/models/contest.py:506 +#: judge/models/contest.py:359 msgid "contest problem" msgstr "" -#: judge/models/contest.py:507 +#: judge/models/contest.py:360 msgid "contest problems" msgstr "" -#: judge/models/contest.py:511 judge/models/submission.py:183 +#: judge/models/contest.py:364 judge/models/submission.py:181 msgid "submission" msgstr "" -#: judge/models/contest.py:515 judge/models/contest.py:530 +#: judge/models/contest.py:368 judge/models/contest.py:383 msgid "participation" msgstr "" -#: judge/models/contest.py:519 +#: judge/models/contest.py:372 msgid "Whether this submission was ran only on pretests." msgstr "" -#: judge/models/contest.py:523 +#: judge/models/contest.py:376 msgid "contest submission" msgstr "" -#: judge/models/contest.py:524 +#: judge/models/contest.py:377 msgid "contest submissions" msgstr "" -#: judge/models/contest.py:532 +#: judge/models/contest.py:385 msgid "rank" msgstr "" -#: judge/models/contest.py:533 +#: judge/models/contest.py:386 msgid "rating" msgstr "" -#: judge/models/contest.py:534 +#: judge/models/contest.py:387 msgid "volatility" msgstr "" -#: judge/models/contest.py:535 +#: judge/models/contest.py:388 msgid "last rated" msgstr "" -#: judge/models/contest.py:539 +#: judge/models/contest.py:392 msgid "contest rating" msgstr "" -#: judge/models/contest.py:540 +#: judge/models/contest.py:393 msgid "contest ratings" msgstr "" -#: judge/models/contest.py:560 +#: judge/models/contest.py:412 msgid "contest moss result" msgstr "" -#: judge/models/contest.py:561 +#: judge/models/contest.py:413 msgid "contest moss results" msgstr "" @@ -1154,7 +1066,7 @@ msgstr "" msgid "post title" msgstr "" -#: judge/models/interface.py:67 judge/models/problem.py:432 +#: judge/models/interface.py:67 judge/models/problem.py:395 msgid "authors" msgstr "" @@ -1162,7 +1074,7 @@ msgstr "" msgid "slug" msgstr "" -#: judge/models/interface.py:69 judge/models/problem.py:430 +#: judge/models/interface.py:69 judge/models/problem.py:393 msgid "public visibility" msgstr "" @@ -1186,19 +1098,15 @@ msgstr "" msgid "openGraph image" msgstr "" -#: judge/models/interface.py:76 -msgid "If private, only these organizations may see the blog post." -msgstr "" - -#: judge/models/interface.py:105 +#: judge/models/interface.py:91 msgid "Edit all posts" msgstr "" -#: judge/models/interface.py:107 +#: judge/models/interface.py:93 msgid "blog post" msgstr "" -#: judge/models/interface.py:108 +#: judge/models/interface.py:94 msgid "blog posts" msgstr "" @@ -1222,6 +1130,10 @@ msgstr "" msgid "message timestamp" msgstr "" +#: judge/models/message.py:16 +msgid "read" +msgstr "" + #: judge/models/message.py:20 msgid "messages in the thread" msgstr "" @@ -1358,7 +1270,7 @@ msgid "" "are supported." msgstr "" -#: judge/models/problem.py:123 judge/models/problem.py:417 +#: judge/models/problem.py:123 judge/models/problem.py:380 msgid "memory limit" msgstr "" @@ -1431,188 +1343,188 @@ msgstr "" msgid "If private, only these organizations may see the problem." msgstr "" -#: judge/models/problem.py:395 judge/models/problem.py:413 -#: judge/models/runtime.py:111 +#: judge/models/problem.py:358 judge/models/problem.py:376 +#: judge/models/runtime.py:108 msgid "language" msgstr "" -#: judge/models/problem.py:396 +#: judge/models/problem.py:359 msgid "translated name" msgstr "" -#: judge/models/problem.py:397 +#: judge/models/problem.py:360 msgid "translated description" msgstr "" -#: judge/models/problem.py:401 +#: judge/models/problem.py:364 msgid "problem translation" msgstr "" -#: judge/models/problem.py:402 +#: judge/models/problem.py:365 msgid "problem translations" msgstr "" -#: judge/models/problem.py:406 +#: judge/models/problem.py:369 msgid "clarified problem" msgstr "" -#: judge/models/problem.py:407 +#: judge/models/problem.py:370 msgid "clarification body" msgstr "" -#: judge/models/problem.py:408 +#: judge/models/problem.py:371 msgid "clarification timestamp" msgstr "" -#: judge/models/problem.py:423 +#: judge/models/problem.py:386 msgid "language-specific resource limit" msgstr "" -#: judge/models/problem.py:424 +#: judge/models/problem.py:387 msgid "language-specific resource limits" msgstr "" -#: judge/models/problem.py:428 +#: judge/models/problem.py:391 msgid "associated problem" msgstr "" -#: judge/models/problem.py:431 +#: judge/models/problem.py:394 msgid "publish date" msgstr "" -#: judge/models/problem.py:433 +#: judge/models/problem.py:396 msgid "editorial content" msgstr "" -#: judge/models/problem.py:449 +#: judge/models/problem.py:412 msgid "solution" msgstr "" -#: judge/models/problem.py:450 +#: judge/models/problem.py:413 msgid "solutions" msgstr "" -#: judge/models/problem_data.py:26 +#: judge/models/problem_data.py:24 msgid "Standard" msgstr "" -#: judge/models/problem_data.py:27 +#: judge/models/problem_data.py:25 msgid "Floats" msgstr "" -#: judge/models/problem_data.py:28 +#: judge/models/problem_data.py:26 msgid "Floats (absolute)" msgstr "" -#: judge/models/problem_data.py:29 +#: judge/models/problem_data.py:27 msgid "Floats (relative)" msgstr "" -#: judge/models/problem_data.py:30 +#: judge/models/problem_data.py:28 msgid "Non-trailing spaces" msgstr "" -#: judge/models/problem_data.py:31 +#: judge/models/problem_data.py:29 msgid "Unordered" msgstr "" -#: judge/models/problem_data.py:32 +#: judge/models/problem_data.py:30 msgid "Byte identical" msgstr "" -#: judge/models/problem_data.py:33 +#: judge/models/problem_data.py:31 msgid "Line-by-line" msgstr "" -#: judge/models/problem_data.py:34 +#: judge/models/problem_data.py:32 msgid "Custom checker (PY)" msgstr "" -#: judge/models/problem_data.py:35 +#: judge/models/problem_data.py:33 msgid "Custom validator (CPP)" msgstr "" -#: judge/models/problem_data.py:42 +#: judge/models/problem_data.py:40 msgid "data zip file" msgstr "" -#: judge/models/problem_data.py:44 +#: judge/models/problem_data.py:42 msgid "generator file" msgstr "" -#: judge/models/problem_data.py:46 judge/models/problem_data.py:121 +#: judge/models/problem_data.py:44 judge/models/problem_data.py:110 msgid "output prefix length" msgstr "" -#: judge/models/problem_data.py:47 judge/models/problem_data.py:122 +#: judge/models/problem_data.py:45 judge/models/problem_data.py:111 msgid "output limit length" msgstr "" -#: judge/models/problem_data.py:48 +#: judge/models/problem_data.py:46 msgid "init.yml generation feedback" msgstr "" -#: judge/models/problem_data.py:49 judge/models/problem_data.py:123 +#: judge/models/problem_data.py:47 judge/models/problem_data.py:112 msgid "checker" msgstr "" -#: judge/models/problem_data.py:50 judge/models/problem_data.py:124 +#: judge/models/problem_data.py:48 judge/models/problem_data.py:113 msgid "checker arguments" msgstr "" -#: judge/models/problem_data.py:51 judge/models/problem_data.py:125 +#: judge/models/problem_data.py:49 judge/models/problem_data.py:114 msgid "checker arguments as a JSON object" msgstr "" -#: judge/models/problem_data.py:52 +#: judge/models/problem_data.py:50 msgid "custom checker file" msgstr "" -#: judge/models/problem_data.py:58 +#: judge/models/problem_data.py:56 msgid "custom validator file" msgstr "" -#: judge/models/problem_data.py:108 +#: judge/models/problem_data.py:97 msgid "problem data set" msgstr "" -#: judge/models/problem_data.py:110 +#: judge/models/problem_data.py:99 msgid "case position" msgstr "" -#: judge/models/problem_data.py:111 +#: judge/models/problem_data.py:100 msgid "case type" msgstr "" -#: judge/models/problem_data.py:112 +#: judge/models/problem_data.py:101 msgid "Normal case" msgstr "" -#: judge/models/problem_data.py:113 +#: judge/models/problem_data.py:102 msgid "Batch start" msgstr "" -#: judge/models/problem_data.py:114 +#: judge/models/problem_data.py:103 msgid "Batch end" msgstr "" -#: judge/models/problem_data.py:116 +#: judge/models/problem_data.py:105 msgid "input file name" msgstr "" -#: judge/models/problem_data.py:117 +#: judge/models/problem_data.py:106 msgid "output file name" msgstr "" -#: judge/models/problem_data.py:118 +#: judge/models/problem_data.py:107 msgid "generator arguments" msgstr "" -#: judge/models/problem_data.py:119 +#: judge/models/problem_data.py:108 msgid "point value" msgstr "" -#: judge/models/problem_data.py:120 +#: judge/models/problem_data.py:109 msgid "case is pretest?" msgstr "" @@ -1685,7 +1597,7 @@ msgid "" msgstr "" #: judge/models/profile.py:76 judge/models/profile.py:93 -#: judge/models/profile.py:212 +#: judge/models/profile.py:192 msgid "organization" msgstr "" @@ -1781,31 +1693,31 @@ msgstr "" msgid "Notes for administrators regarding this user." msgstr "" -#: judge/models/profile.py:206 +#: judge/models/profile.py:186 msgid "user profile" msgstr "" -#: judge/models/profile.py:207 +#: judge/models/profile.py:187 msgid "user profiles" msgstr "" -#: judge/models/profile.py:214 +#: judge/models/profile.py:194 msgid "request time" msgstr "" -#: judge/models/profile.py:215 +#: judge/models/profile.py:195 msgid "state" msgstr "" -#: judge/models/profile.py:220 +#: judge/models/profile.py:200 msgid "reason" msgstr "" -#: judge/models/profile.py:223 +#: judge/models/profile.py:203 msgid "organization join request" msgstr "" -#: judge/models/profile.py:224 +#: judge/models/profile.py:204 msgid "organization join requests" msgstr "" @@ -1896,86 +1808,86 @@ msgstr "" msgid "The extension of source files, e.g., \"py\" or \"cpp\"." msgstr "" -#: judge/models/runtime.py:112 +#: judge/models/runtime.py:109 msgid "languages" msgstr "" -#: judge/models/runtime.py:116 +#: judge/models/runtime.py:113 msgid "language to which this runtime belongs" msgstr "" -#: judge/models/runtime.py:117 +#: judge/models/runtime.py:114 msgid "judge on which this runtime exists" msgstr "" -#: judge/models/runtime.py:118 +#: judge/models/runtime.py:115 msgid "runtime name" msgstr "" -#: judge/models/runtime.py:119 +#: judge/models/runtime.py:116 msgid "runtime version" msgstr "" -#: judge/models/runtime.py:120 +#: judge/models/runtime.py:117 msgid "order in which to display this runtime" msgstr "" -#: judge/models/runtime.py:124 +#: judge/models/runtime.py:121 msgid "Server name, hostname-style" msgstr "" -#: judge/models/runtime.py:125 +#: judge/models/runtime.py:122 msgid "time of creation" msgstr "" -#: judge/models/runtime.py:126 +#: judge/models/runtime.py:123 msgid "A key to authenticate this judge" msgstr "" -#: judge/models/runtime.py:127 +#: judge/models/runtime.py:124 msgid "authentication key" msgstr "" -#: judge/models/runtime.py:128 +#: judge/models/runtime.py:125 msgid "block judge" msgstr "" -#: judge/models/runtime.py:129 +#: judge/models/runtime.py:126 msgid "" "Whether this judge should be blocked from connecting, even if its key is " "correct." msgstr "" -#: judge/models/runtime.py:131 +#: judge/models/runtime.py:128 msgid "judge online status" msgstr "" -#: judge/models/runtime.py:132 +#: judge/models/runtime.py:129 msgid "judge start time" msgstr "" -#: judge/models/runtime.py:133 +#: judge/models/runtime.py:130 msgid "response time" msgstr "" -#: judge/models/runtime.py:134 +#: judge/models/runtime.py:131 msgid "system load" msgstr "" -#: judge/models/runtime.py:135 +#: judge/models/runtime.py:132 msgid "Load for the last minute, divided by processors to be fair." msgstr "" -#: judge/models/runtime.py:139 judge/models/runtime.py:179 +#: judge/models/runtime.py:136 judge/models/runtime.py:176 msgid "judges" msgstr "" -#: judge/models/runtime.py:178 +#: judge/models/runtime.py:175 msgid "judge" msgstr "" #: judge/models/submission.py:20 judge/models/submission.py:47 -#: judge/utils/problems.py:79 +#: judge/utils/problems.py:77 msgid "Accepted" msgstr "" @@ -2004,7 +1916,7 @@ msgid "Runtime Error" msgstr "" #: judge/models/submission.py:27 judge/models/submission.py:41 -#: judge/models/submission.py:55 judge/utils/problems.py:81 +#: judge/models/submission.py:55 judge/utils/problems.py:79 msgid "Compile Error" msgstr "" @@ -2045,15 +1957,15 @@ msgstr "" msgid "submission time" msgstr "" -#: judge/models/submission.py:67 judge/models/submission.py:203 +#: judge/models/submission.py:67 judge/models/submission.py:201 msgid "execution time" msgstr "" -#: judge/models/submission.py:68 judge/models/submission.py:204 +#: judge/models/submission.py:68 judge/models/submission.py:202 msgid "memory usage" msgstr "" -#: judge/models/submission.py:69 judge/models/submission.py:205 +#: judge/models/submission.py:69 judge/models/submission.py:203 msgid "points granted" msgstr "" @@ -2090,62 +2002,58 @@ msgid "judged on" msgstr "" #: judge/models/submission.py:81 -msgid "submission judge time" -msgstr "" - -#: judge/models/submission.py:82 msgid "was rejudged by admin" msgstr "" -#: judge/models/submission.py:83 +#: judge/models/submission.py:82 msgid "was ran on pretests only" msgstr "" -#: judge/models/submission.py:184 templates/contest/moss.html:58 +#: judge/models/submission.py:182 templates/contest/moss.html:58 msgid "submissions" msgstr "" -#: judge/models/submission.py:188 judge/models/submission.py:199 +#: judge/models/submission.py:186 judge/models/submission.py:197 msgid "associated submission" msgstr "" -#: judge/models/submission.py:190 +#: judge/models/submission.py:188 msgid "source code" msgstr "" -#: judge/models/submission.py:201 +#: judge/models/submission.py:199 msgid "test case ID" msgstr "" -#: judge/models/submission.py:202 +#: judge/models/submission.py:200 msgid "status flag" msgstr "" -#: judge/models/submission.py:206 +#: judge/models/submission.py:204 msgid "points possible" msgstr "" -#: judge/models/submission.py:207 +#: judge/models/submission.py:205 msgid "batch number" msgstr "" -#: judge/models/submission.py:208 +#: judge/models/submission.py:206 msgid "judging feedback" msgstr "" -#: judge/models/submission.py:209 +#: judge/models/submission.py:207 msgid "extended judging feedback" msgstr "" -#: judge/models/submission.py:210 +#: judge/models/submission.py:208 msgid "program output" msgstr "" -#: judge/models/submission.py:218 +#: judge/models/submission.py:216 msgid "submission test case" msgstr "" -#: judge/models/submission.py:219 +#: judge/models/submission.py:217 msgid "submission test cases" msgstr "" @@ -2197,21 +2105,12 @@ msgstr "" msgid "message time" msgstr "" -#: judge/pdf_problems.py:147 judge/pdf_problems.py:199 -#: judge/pdf_problems.py:259 +#: judge/pdf_problems.py:134 judge/pdf_problems.py:186 +#: judge/pdf_problems.py:246 msgid "Page [page] of [topage]" msgstr "" -#: judge/pdf_problems.py:280 -#, python-format -msgid "Page %s of %s" -msgstr "" - -#: judge/tasks/contest.py:19 -msgid "Recalculating contest scores" -msgstr "" - -#: judge/tasks/contest.py:40 +#: judge/tasks/moss.py:25 msgid "Running MOSS" msgstr "" @@ -2223,60 +2122,60 @@ msgstr "" msgid "Recalculating user points" msgstr "" -#: judge/utils/problem_data.py:70 +#: judge/utils/problem_data.py:68 msgid "Empty batches not allowed." msgstr "" -#: judge/utils/problem_data.py:78 judge/utils/problem_data.py:99 +#: judge/utils/problem_data.py:76 judge/utils/problem_data.py:97 msgid "How did you corrupt the custom checker path?" msgstr "" -#: judge/utils/problem_data.py:120 +#: judge/utils/problem_data.py:118 #, python-format msgid "Points must be defined for non-batch case #%d." msgstr "" -#: judge/utils/problem_data.py:125 +#: judge/utils/problem_data.py:123 #, python-format msgid "Input file for case %d does not exist: %s" msgstr "" -#: judge/utils/problem_data.py:128 +#: judge/utils/problem_data.py:126 #, python-format msgid "Output file for case %d does not exist: %s" msgstr "" -#: judge/utils/problem_data.py:153 +#: judge/utils/problem_data.py:151 #, python-format msgid "Batch start case #%d requires points." msgstr "" -#: judge/utils/problem_data.py:174 +#: judge/utils/problem_data.py:172 #, python-format msgid "Attempt to end batch outside of one in case #%d" msgstr "" -#: judge/utils/problem_data.py:192 +#: judge/utils/problem_data.py:190 msgid "How did you corrupt the zip path?" msgstr "" -#: judge/utils/problem_data.py:198 +#: judge/utils/problem_data.py:196 msgid "How did you corrupt the generator path?" msgstr "" -#: judge/utils/problems.py:80 +#: judge/utils/problems.py:78 msgid "Wrong" msgstr "" -#: judge/utils/problems.py:82 +#: judge/utils/problems.py:80 msgid "Timeout" msgstr "" -#: judge/utils/problems.py:83 +#: judge/utils/problems.py:81 msgid "Error" msgstr "" -#: judge/utils/problems.py:94 +#: judge/utils/problems.py:92 msgid "Can't pass both queryset and keyword filters" msgstr "" @@ -2319,8 +2218,7 @@ msgctxt "hours and minutes" msgid "%h:%m" msgstr "" -#: judge/views/about.py:7 templates/organization/home.html:112 -#: templates/user/user-about.html:83 templates/user/user-tabs.html:4 +#: judge/views/about.py:7 templates/user/user-about.html:33 msgid "About" msgstr "" @@ -2328,165 +2226,156 @@ msgstr "" msgid "Custom Checker Sample" msgstr "" -#: judge/views/blog.py:45 +#: judge/views/blog.py:38 #, python-format msgid "Page %d of Posts" msgstr "" -#: judge/views/comment.py:28 +#: judge/views/comment.py:27 msgid "Messing around, are we?" msgstr "" -#: judge/views/comment.py:37 +#: judge/views/comment.py:36 msgid "You must solve at least one problem before you can vote." msgstr "" -#: judge/views/comment.py:64 +#: judge/views/comment.py:63 msgid "You already voted." msgstr "" -#: judge/views/comment.py:126 judge/views/organization.py:344 +#: judge/views/comment.py:120 judge/views/organization.py:299 msgid "Edited from site" msgstr "" -#: judge/views/comment.py:147 +#: judge/views/comment.py:141 msgid "Editing comment" msgstr "" -#: judge/views/contests.py:57 judge/views/contests.py:247 -#: judge/views/contests.py:250 judge/views/contests.py:424 +#: judge/views/contests.py:55 judge/views/contests.py:215 +#: judge/views/contests.py:218 judge/views/contests.py:389 msgid "No such contest" msgstr "" -#: judge/views/contests.py:58 judge/views/contests.py:248 +#: judge/views/contests.py:56 judge/views/contests.py:216 #, python-format msgid "Could not find a contest with the key \"%s\"." msgstr "" -#: judge/views/contests.py:71 +#: judge/views/contests.py:81 msgid "Contests" msgstr "" -#: judge/views/contests.py:251 +#: judge/views/contests.py:219 msgid "Could not find such contest." msgstr "" -#: judge/views/contests.py:254 +#: judge/views/contests.py:222 #, python-format msgid "Access to contest \"%s\" denied" msgstr "" -#: judge/views/contests.py:278 +#: judge/views/contests.py:246 msgid "Clone Contest" msgstr "" -#: judge/views/contests.py:343 +#: judge/views/contests.py:309 msgid "Contest not ongoing" msgstr "" -#: judge/views/contests.py:344 +#: judge/views/contests.py:310 #, python-format msgid "\"%s\" is not currently ongoing." msgstr "" -#: judge/views/contests.py:348 +#: judge/views/contests.py:314 msgid "Already in contest" msgstr "" -#: judge/views/contests.py:349 +#: judge/views/contests.py:315 #, python-format msgid "You are already in a contest: \"%s\"." msgstr "" -#: judge/views/contests.py:352 +#: judge/views/contests.py:318 msgid "Banned from joining" msgstr "" -#: judge/views/contests.py:353 +#: judge/views/contests.py:319 msgid "" "You have been declared persona non grata for this contest. You are " "permanently barred from joining this contest." msgstr "" -#: judge/views/contests.py:414 +#: judge/views/contests.py:379 #, python-format msgid "Enter access code for \"%s\"" msgstr "" -#: judge/views/contests.py:425 +#: judge/views/contests.py:390 #, python-format msgid "You are not in contest \"%s\"." msgstr "" -#: judge/views/contests.py:444 +#: judge/views/contests.py:409 msgid "ContestCalendar requires integer year and month" msgstr "" -#: judge/views/contests.py:484 +#: judge/views/contests.py:449 #, python-format msgid "Contests in %(month)s" msgstr "" -#: judge/views/contests.py:484 +#: judge/views/contests.py:449 msgid "F Y" msgstr "" -#: judge/views/contests.py:532 +#: judge/views/contests.py:496 #, python-format msgid "%s Statistics" msgstr "" -#: judge/views/contests.py:717 +#: judge/views/contests.py:601 +msgid "???" +msgstr "" + +#: judge/views/contests.py:664 #, python-format msgid "%s Rankings" msgstr "" -#: judge/views/contests.py:725 -msgid "???" -msgstr "" - -#: judge/views/contests.py:741 +#: judge/views/contests.py:680 #, python-format msgid "Your participation in %s" msgstr "" -#: judge/views/contests.py:742 +#: judge/views/contests.py:681 #, python-format msgid "%s's participation in %s" msgstr "" -#: judge/views/contests.py:749 +#: judge/views/contests.py:685 msgid "Live" msgstr "" -#: judge/views/contests.py:761 templates/contest/contest-tabs.html:13 +#: judge/views/contests.py:697 msgid "Participation" msgstr "" -#: judge/views/contests.py:808 +#: judge/views/contests.py:743 #, python-format msgid "%s MOSS Results" msgstr "" -#: judge/views/contests.py:835 +#: judge/views/contests.py:770 #, python-format msgid "Running MOSS for %s..." msgstr "" -#: judge/views/contests.py:858 +#: judge/views/contests.py:793 #, python-format msgid "Contest tag: %s" msgstr "" -#: judge/views/contests.py:868 judge/views/ticket.py:57 -msgid "Issue description" -msgstr "" - -#: judge/views/contests.py:911 -#, python-format -msgid "New clarification for %s" -msgstr "" - #: judge/views/error.py:14 msgid "404 error" msgstr "" @@ -2507,122 +2396,115 @@ msgid "corrupt page %s" msgstr "" #: judge/views/language.py:12 templates/status/judge-status-table.html:9 -#: templates/status/status-tabs.html:5 msgid "Runtimes" msgstr "" -#: judge/views/notification.py:40 -#, python-format -msgid "Notifications (%d unseen)" -msgstr "" - -#: judge/views/organization.py:59 judge/views/organization.py:62 +#: judge/views/organization.py:44 judge/views/organization.py:47 msgid "No such organization" msgstr "" -#: judge/views/organization.py:60 +#: judge/views/organization.py:45 #, python-format msgid "Could not find an organization with the key \"%s\"." msgstr "" -#: judge/views/organization.py:63 +#: judge/views/organization.py:48 msgid "Could not find such organization." msgstr "" -#: judge/views/organization.py:79 judge/views/register.py:34 -#: templates/organization/list.html:32 templates/user/import/table_csv.html:9 -#: templates/user/user-list-tabs.html:6 +#: judge/views/organization.py:72 judge/views/register.py:34 +#: templates/organization/list.html:15 msgid "Organizations" msgstr "" -#: judge/views/organization.py:130 +#: judge/views/organization.py:93 #, python-format msgid "%s Members" msgstr "" -#: judge/views/organization.py:159 judge/views/organization.py:162 -#: judge/views/organization.py:167 +#: judge/views/organization.py:118 judge/views/organization.py:121 +#: judge/views/organization.py:126 msgid "Joining organization" msgstr "" -#: judge/views/organization.py:159 +#: judge/views/organization.py:118 msgid "You are already in the organization." msgstr "" -#: judge/views/organization.py:162 +#: judge/views/organization.py:121 msgid "This organization is not open." msgstr "" -#: judge/views/organization.py:179 +#: judge/views/organization.py:138 msgid "Leaving organization" msgstr "" -#: judge/views/organization.py:179 +#: judge/views/organization.py:138 #, python-format msgid "You are not in \"%s\"." msgstr "" -#: judge/views/organization.py:203 +#: judge/views/organization.py:162 #, python-format msgid "Request to join %s" msgstr "" -#: judge/views/organization.py:221 +#: judge/views/organization.py:180 msgid "Join request detail" msgstr "" -#: judge/views/organization.py:254 +#: judge/views/organization.py:209 #, python-format msgid "Managing join requests for %s" msgstr "" -#: judge/views/organization.py:285 +#: judge/views/organization.py:240 #, python-format msgid "" "Your organization can only receive %d more members. You cannot approve %d " "users." msgstr "" -#: judge/views/organization.py:297 +#: judge/views/organization.py:252 #, python-format msgid "Approved %d user." msgid_plural "Approved %d users." msgstr[0] "" msgstr[1] "" -#: judge/views/organization.py:298 +#: judge/views/organization.py:253 #, python-format msgid "Rejected %d user." msgid_plural "Rejected %d users." msgstr[0] "" msgstr[1] "" -#: judge/views/organization.py:328 +#: judge/views/organization.py:283 #, python-format msgid "Editing %s" msgstr "" -#: judge/views/organization.py:352 judge/views/organization.py:360 +#: judge/views/organization.py:307 judge/views/organization.py:315 msgid "Can't edit organization" msgstr "" -#: judge/views/organization.py:353 +#: judge/views/organization.py:308 msgid "You are not allowed to edit this organization." msgstr "" -#: judge/views/organization.py:361 +#: judge/views/organization.py:316 msgid "You are not allowed to kick people from this organization." msgstr "" -#: judge/views/organization.py:366 judge/views/organization.py:370 +#: judge/views/organization.py:321 judge/views/organization.py:325 msgid "Can't kick user" msgstr "" -#: judge/views/organization.py:367 +#: judge/views/organization.py:322 msgid "The user you are trying to kick does not exist!" msgstr "" -#: judge/views/organization.py:371 +#: judge/views/organization.py:326 #, python-format msgid "The user you are trying to kick is not in organization: %s." msgstr "" @@ -2646,36 +2528,35 @@ msgstr "" msgid "Editorial for {0}" msgstr "" -#: judge/views/problem.py:285 templates/contest/contest.html:79 -#: templates/user/user-about.html:28 templates/user/user-tabs.html:5 -#: templates/user/users-table.html:31 +#: judge/views/problem.py:286 templates/contest/contest.html:79 +#: templates/user/users-table.html:23 msgid "Problems" msgstr "" -#: judge/views/problem.py:585 +#: judge/views/problem.py:547 msgid "Banned from submitting" msgstr "" -#: judge/views/problem.py:586 +#: judge/views/problem.py:548 msgid "" "You have been declared persona non grata for this problem. You are " "permanently barred from submitting this problem." msgstr "" -#: judge/views/problem.py:600 +#: judge/views/problem.py:562 msgid "Too many submissions" msgstr "" -#: judge/views/problem.py:601 +#: judge/views/problem.py:563 msgid "You have exceeded the submission limit for this problem." msgstr "" -#: judge/views/problem.py:661 judge/views/problem.py:664 +#: judge/views/problem.py:633 judge/views/problem.py:636 #, python-format msgid "Submit to %(problem)s" msgstr "" -#: judge/views/problem.py:679 +#: judge/views/problem.py:652 msgid "Clone Problem" msgstr "" @@ -2716,22 +2597,22 @@ msgstr "" msgid "Generated init.yml for %s" msgstr "" -#: judge/views/problem_manage.py:52 judge/views/problem_manage.py:55 +#: judge/views/problem_manage.py:50 judge/views/problem_manage.py:53 #, python-format msgid "Managing submissions for %s" msgstr "" -#: judge/views/problem_manage.py:97 +#: judge/views/problem_manage.py:95 #, python-format msgid "Rejudging selected submissions for %s..." msgstr "" -#: judge/views/problem_manage.py:141 +#: judge/views/problem_manage.py:110 #, python-format msgid "Rescoring all submissions for %s..." msgstr "" -#: judge/views/problem_manage.py:150 +#: judge/views/problem_manage.py:119 #, python-format msgid "Successfully scheduled %d submission for rejudging." msgid_plural "Successfully scheduled %d submissions for rejudging." @@ -2780,24 +2661,24 @@ msgstr "" msgid "Subscribe to newsletter?" msgstr "" -#: judge/views/register.py:55 +#: judge/views/register.py:45 #, python-format msgid "" "The email address \"%s\" is already taken. Only one registration is allowed " "per address." msgstr "" -#: judge/views/register.py:61 +#: judge/views/register.py:51 msgid "" "Your email provider is not allowed due to history of abuse. Please use a " "reputable email provider." msgstr "" -#: judge/views/register.py:67 judge/views/register.py:105 +#: judge/views/register.py:57 judge/views/register.py:95 msgid "Registration" msgstr "" -#: judge/views/register.py:116 +#: judge/views/register.py:106 msgid "Authentication failure" msgstr "" @@ -2813,100 +2694,104 @@ msgstr "" msgid "Version matrix" msgstr "" -#: judge/views/submission.py:84 judge/views/submission.py:91 +#: judge/views/submission.py:83 judge/views/submission.py:90 #, python-format msgid "Submission of %(problem)s by %(user)s" msgstr "" -#: judge/views/submission.py:244 judge/views/submission.py:245 -#: templates/problem/problem.html:167 +#: judge/views/submission.py:227 judge/views/submission.py:228 +#: templates/problem/problem.html:127 msgid "All submissions" msgstr "" -#: judge/views/submission.py:404 +#: judge/views/submission.py:384 msgid "All my submissions" msgstr "" -#: judge/views/submission.py:405 +#: judge/views/submission.py:385 #, python-format msgid "All submissions by %s" msgstr "" -#: judge/views/submission.py:436 +#: judge/views/submission.py:416 #, python-format msgid "All submissions for %s" msgstr "" -#: judge/views/submission.py:455 +#: judge/views/submission.py:435 msgid "Must pass a problem" msgstr "" -#: judge/views/submission.py:501 +#: judge/views/submission.py:481 #, python-format msgid "My submissions for %(problem)s" msgstr "" -#: judge/views/submission.py:502 +#: judge/views/submission.py:482 #, python-format msgid "%(user)s's submissions for %(problem)s" msgstr "" -#: judge/views/submission.py:603 +#: judge/views/submission.py:583 msgid "Must pass a contest" msgstr "" -#: judge/views/submission.py:622 +#: judge/views/submission.py:602 #, python-brace-format msgid "" "{0}'s submissions for {2} in {4}" msgstr "" -#: judge/views/submission.py:629 +#: judge/views/submission.py:609 #, python-brace-format msgid "" "{0}'s submissions for problem {2} in {3}" "" msgstr "" -#: judge/views/ticket.py:50 judge/views/ticket.py:56 +#: judge/views/ticket.py:33 judge/views/ticket.py:39 msgid "Ticket title" msgstr "" -#: judge/views/ticket.py:107 judge/views/ticket.py:110 +#: judge/views/ticket.py:40 +msgid "Issue description" +msgstr "" + +#: judge/views/ticket.py:85 judge/views/ticket.py:88 #, python-format msgid "New ticket for %s" msgstr "" -#: judge/views/ticket.py:170 +#: judge/views/ticket.py:142 #, python-format msgid "%(title)s - Ticket %(id)d" msgstr "" -#: judge/views/ticket.py:279 +#: judge/views/ticket.py:251 #, python-format msgid "Tickets - Page %(number)d of %(total)d" msgstr "" -#: judge/views/ticket.py:328 +#: judge/views/ticket.py:300 #, python-format msgid "New Ticket: %s" msgstr "" -#: judge/views/ticket.py:329 +#: judge/views/ticket.py:301 #, python-format msgid "#%(id)d, assigned to: %(users)s" msgstr "" -#: judge/views/ticket.py:331 +#: judge/views/ticket.py:303 msgid ", " msgstr "" -#: judge/views/ticket.py:331 +#: judge/views/ticket.py:303 msgid "no one" msgstr "" -#: judge/views/ticket.py:351 +#: judge/views/ticket.py:323 #, python-format msgid "New Ticket Message For: %s" msgstr "" @@ -2923,50 +2808,41 @@ msgstr "" msgid "Perform Two Factor Authentication" msgstr "" -#: judge/views/user.py:74 +#: judge/views/user.py:68 msgid "No such user" msgstr "" -#: judge/views/user.py:74 +#: judge/views/user.py:68 #, python-format msgid "No user handle \"%s\"." msgstr "" -#: judge/views/user.py:78 +#: judge/views/user.py:72 msgid "My account" msgstr "" -#: judge/views/user.py:79 +#: judge/views/user.py:73 #, python-format msgid "User %s" msgstr "" -#: judge/views/user.py:148 -msgid "M j, Y" -msgstr "" - -#: judge/views/user.py:171 +#: judge/views/user.py:136 msgid "M j, Y, G:i" msgstr "" -#: judge/views/user.py:290 +#: judge/views/user.py:221 msgid "Updated on site" msgstr "" -#: judge/views/user.py:323 templates/admin/auth/user/change_form.html:14 -#: templates/admin/auth/user/change_form.html:17 templates/base.html:238 -#: templates/user/user-tabs.html:10 +#: judge/views/user.py:254 templates/admin/auth/user/change_form.html:14 +#: templates/admin/auth/user/change_form.html:17 templates/base.html:224 msgid "Edit profile" msgstr "" -#: judge/views/user.py:332 templates/user/user-list-tabs.html:4 +#: judge/views/user.py:263 msgid "Leaderboard" msgstr "" -#: judge/views/user.py:407 -msgid "Import Users" -msgstr "" - #: judge/views/widgets.py:48 judge/views/widgets.py:58 #, python-format msgid "Invalid upstream data: %s" @@ -3004,7 +2880,7 @@ msgid "View Submissions" msgstr "" #: templates/admin/judge/problem/change_form.html:17 -#: templates/user/user-base.html:112 +#: templates/user/user-base.html:61 msgid "View submissions" msgstr "" @@ -3019,145 +2895,90 @@ msgstr "" msgid "Rejudge" msgstr "" -#: templates/base.html:230 -#, python-format -msgid "Hello, %(username)s." -msgstr "" - -#: templates/base.html:236 templates/comments/list.html:89 -#: templates/contest/contest-list-tabs.html:24 -#: templates/contest/ranking-table.html:53 -#: templates/problem/problem-list-tabs.html:6 +#: templates/base.html:222 templates/comments/list.html:89 +#: templates/contest/ranking-table.html:39 #: templates/submission/info-base.html:12 -#: templates/submission/submission-list-tabs.html:15 msgid "Admin" msgstr "" -#: templates/base.html:245 +#: templates/base.html:231 msgid "Log out" msgstr "" -#: templates/base.html:254 +#: templates/base.html:240 #: templates/registration/password_reset_complete.html:4 msgid "Log in" msgstr "" -#: templates/base.html:255 templates/registration/registration_form.html:177 +#: templates/base.html:241 templates/registration/registration_form.html:177 msgid "or" msgstr "" -#: templates/base.html:256 +#: templates/base.html:242 msgid "Sign up" msgstr "" -#: templates/base.html:271 +#: templates/base.html:254 msgid "spectating" msgstr "" -#: templates/base.html:284 +#: templates/base.html:267 msgid "This site works best with JavaScript enabled." msgstr "" -#: templates/blog/blog.html:13 templates/comments/list.html:68 -#: templates/comments/list.html:83 templates/contest/contest-tabs.html:23 -#: templates/contest/tag-title.html:9 templates/flatpages/admin_link.html:3 -#: templates/license.html:10 templates/problem/editorial.html:14 +#: templates/blog/content.html:13 templates/comments/list.html:68 +#: templates/comments/list.html:83 templates/contest/tag-title.html:9 +#: templates/flatpages/admin_link.html:3 templates/license.html:10 +#: templates/problem/editorial.html:14 msgid "Edit" msgstr "" -#: templates/blog/blog.html:26 -#, python-format -msgid "" -"\n" -" posted on %(time)s\n" -" " -msgstr "" - -#: templates/blog/content.html:10 -#, python-brace-format -msgid "posted on {time}" -msgstr "" - -#: templates/blog/dashboard.html:21 -#, python-format -msgid "" -"\n" -" on %(time)s\n" -" " -msgstr "" - -#: templates/blog/list.html:93 +#: templates/blog/list.html:85 msgid "Blog" msgstr "" -#: templates/blog/list.html:95 +#: templates/blog/list.html:87 msgid "Events" msgstr "" -#: templates/blog/list.html:100 +#: templates/blog/list.html:92 msgid "News" msgstr "" -#: templates/blog/list.html:115 templates/problem/list.html:347 -#: templates/problem/problem.html:361 +#: templates/blog/list.html:130 templates/problem/problem.html:310 msgid "Clarifications" msgstr "" -#: templates/blog/list.html:121 -msgid "Add" -msgstr "" - -#: templates/blog/list.html:140 templates/problem/list.html:369 -#: templates/problem/problem.html:372 +#: templates/blog/list.html:146 templates/problem/problem.html:321 msgid "No clarifications have been made at this time." msgstr "" -#: templates/blog/list.html:148 +#: templates/blog/list.html:154 msgid "Ongoing contests" msgstr "" -#: templates/blog/list.html:166 +#: templates/blog/list.html:172 msgid "Upcoming contests" msgstr "" -#: templates/blog/list.html:184 -msgid "My open tickets" -msgstr "" - -#: templates/blog/list.html:206 -msgid "New tickets" -msgstr "" - -#: templates/blog/list.html:227 -msgid "New problems" -msgstr "" - -#: templates/blog/list.html:244 +#: templates/blog/list.html:189 msgid "Comment stream" msgstr "" -#: templates/chat/chat.html:305 -msgid "Chat" +#: templates/blog/list.html:208 +msgid "New problems" msgstr "" -#: templates/chat/chat.html:307 templates/chat/chat.html:314 -msgid "Online Users" +#: templates/blog/list.html:225 +msgid "My open tickets" msgstr "" -#: templates/chat/chat.html:315 -msgid "Refresh" +#: templates/blog/list.html:246 +msgid "New tickets" msgstr "" -#: templates/chat/chat.html:333 -msgid "Emoji" -msgstr "" - -#: templates/chat/chat.html:334 -msgid "Enter your message" -msgstr "" - -#: templates/chat/message.html:20 -msgid "Delete" +#: templates/chat/chat.html:167 +msgid "Your message" msgstr "" #: templates/comments/list.html:2 @@ -3168,21 +2989,11 @@ msgstr "" msgid "Please login to vote" msgstr "" -#: templates/comments/list.html:40 -#, python-brace-format -msgid "commented on {time}" -msgstr "" - -#: templates/comments/list.html:49 -#, python-format -msgid "edit %(edits)s" -msgstr "" - -#: templates/comments/list.html:51 templates/comments/media-js.html:92 +#: templates/comments/list.html:51 templates/comments/media-js.html:77 msgid "edited" msgstr "" -#: templates/comments/list.html:60 templates/notification/list.html:14 +#: templates/comments/list.html:60 msgid "Link" msgstr "" @@ -3190,52 +3001,36 @@ msgstr "" msgid "Reply" msgstr "" -#: templates/comments/list.html:86 templates/contest/list.html:91 -#: templates/contest/list.html:95 templates/contest/list.html:280 +#: templates/comments/list.html:86 msgid "Hide" msgstr "" -#: templates/comments/list.html:101 -#, python-format -msgid "" -"\n" -" This comment is hidden due " -"to too much negative feedback.\n" -" Click here to view it.\n" -" " -msgstr "" - -#: templates/comments/list.html:121 +#: templates/comments/list.html:120 msgid "There are no comments at the moment." msgstr "" -#: templates/comments/list.html:127 +#: templates/comments/list.html:126 msgid "New comment" msgstr "" -#: templates/comments/list.html:141 +#: templates/comments/list.html:140 msgid "Invalid comment body." msgstr "" -#: templates/comments/list.html:149 +#: templates/comments/list.html:148 msgid "Post!" msgstr "" -#: templates/comments/list.html:157 +#: templates/comments/list.html:156 msgid "Comments are disabled on this page." msgstr "" -#: templates/comments/media-js.html:38 -msgid "Replying to comment" -msgstr "" - -#: templates/comments/media-js.html:87 +#: templates/comments/media-js.html:72 #, python-brace-format msgid "edit {edits}" msgstr "" -#: templates/comments/media-js.html:90 +#: templates/comments/media-js.html:75 msgid "original" msgstr "" @@ -3279,11 +3074,6 @@ msgstr "" msgid "Saturday" msgstr "" -#: templates/contest/clarification.html:52 templates/organization/new.html:10 -#: templates/ticket/new.html:38 -msgid "Create" -msgstr "" - #: templates/contest/clone.html:37 msgid "Enter a new key for the cloned contest:" msgstr "" @@ -3304,171 +3094,97 @@ msgstr "" msgid "Next" msgstr "" -#: templates/contest/contest-list-tabs.html:21 -#: templates/problem/problem-list-tabs.html:5 -msgid "List" -msgstr "" - -#: templates/contest/contest-list-tabs.html:22 -msgid "Calendar" -msgstr "" - -#: templates/contest/contest-tabs.html:4 templates/organization/home.html:105 -msgid "Info" -msgstr "" - -#: templates/contest/contest-tabs.html:6 templates/stats/base.html:9 -#: templates/submission/list.html:339 -msgid "Statistics" -msgstr "" - -#: templates/contest/contest-tabs.html:11 -msgid "Rankings" -msgstr "" - -#: templates/contest/contest-tabs.html:16 -msgid "Hidden Rankings" -msgstr "" - -#: templates/contest/contest-tabs.html:21 -msgid "MOSS" -msgstr "" - -#: templates/contest/contest-tabs.html:26 -msgid "Clone" -msgstr "" - -#: templates/contest/contest-tabs.html:38 -#: templates/contest/contest-tabs.html:58 +#: templates/contest/contest-tabs.html:37 msgid "Leave contest" msgstr "" -#: templates/contest/contest-tabs.html:45 templates/contest/list.html:388 +#: templates/contest/contest-tabs.html:44 templates/contest/list.html:293 msgid "Virtual join" msgstr "" -#: templates/contest/contest-tabs.html:56 -msgid "Stop spectating" -msgstr "" - -#: templates/contest/contest-tabs.html:65 +#: templates/contest/contest-tabs.html:64 msgid "Spectate contest" msgstr "" -#: templates/contest/contest-tabs.html:72 +#: templates/contest/contest-tabs.html:70 +#: templates/contest/contest-tabs.html:76 msgid "Join contest" msgstr "" -#: templates/contest/contest-tabs.html:81 +#: templates/contest/contest-tabs.html:85 msgid "Login to participate" msgstr "" -#: templates/contest/contest.html:37 -msgid "Participating virtually." -msgstr "" - -#: templates/contest/contest.html:43 -msgid "Contest is over." -msgstr "" - #: templates/contest/contest.html:59 templates/contest/contest.html:63 msgid "F j, Y, G:i T" msgstr "" -#: templates/contest/contest.html:59 -#, python-format -msgid "" -"%(time_limit)s window between %(start_time)s and " -"%(end_time)s" -msgstr "" - -#: templates/contest/contest.html:63 -#, python-format -msgid "%(length)s long starting on %(start_time)s" -msgstr "" - #: templates/contest/contest.html:85 msgid "AC Rate" msgstr "" -#: templates/contest/contest.html:86 templates/contest/list.html:237 -#: templates/contest/list.html:289 templates/contest/list.html:366 -#: templates/problem/list.html:223 templates/problem/list.html:254 +#: templates/contest/contest.html:86 templates/contest/list.html:153 +#: templates/contest/list.html:195 templates/contest/list.html:271 +#: templates/problem/list.html:212 templates/problem/list.html:238 msgid "Users" msgstr "" -#: templates/contest/contest.html:111 templates/problem/list.html:330 +#: templates/contest/contest.html:111 msgid "Editorial" msgstr "" -#: templates/contest/list.html:83 templates/contest/media-js.html:9 +#: templates/contest/list.html:31 templates/contest/media-js.html:9 msgid "Are you sure you want to join?" msgstr "" -#: templates/contest/list.html:84 +#: templates/contest/list.html:32 msgid "" "Joining a contest for the first time starts your timer, after which it " "becomes unstoppable." msgstr "" -#: templates/contest/list.html:92 templates/contest/list.html:278 -msgid "Show" -msgstr "" - -#: templates/contest/list.html:102 templates/problem/list.html:68 -msgid "Organizations..." -msgstr "" - -#: templates/contest/list.html:135 +#: templates/contest/list.html:65 msgid "hidden" msgstr "" -#: templates/contest/list.html:140 +#: templates/contest/list.html:70 msgid "private" msgstr "" -#: templates/contest/list.html:154 +#: templates/contest/list.html:84 msgid "rated" msgstr "" -#: templates/contest/list.html:202 +#: templates/contest/list.html:132 msgid "Spectate" msgstr "" -#: templates/contest/list.html:208 +#: templates/contest/list.html:138 msgid "Join" msgstr "" -#: templates/contest/list.html:220 -msgid "Search contests..." -msgstr "" - -#: templates/contest/list.html:229 -msgid "Search" -msgstr "" - -#: templates/contest/list.html:232 +#: templates/contest/list.html:148 msgid "Active Contests" msgstr "" -#: templates/contest/list.html:236 templates/contest/list.html:288 -#: templates/contest/list.html:327 templates/contest/list.html:365 +#: templates/contest/list.html:152 templates/contest/list.html:194 +#: templates/contest/list.html:232 templates/contest/list.html:270 msgid "Contest" msgstr "" -#: templates/contest/list.html:275 +#: templates/contest/list.html:190 msgid "Ongoing Contests" msgstr "" -#: templates/contest/list.html:322 +#: templates/contest/list.html:227 msgid "Upcoming Contests" msgstr "" -#: templates/contest/list.html:350 +#: templates/contest/list.html:255 msgid "There are no scheduled contests at this time." msgstr "" -#: templates/contest/list.html:356 +#: templates/contest/list.html:261 msgid "Past Contests" msgstr "" @@ -3519,71 +3235,47 @@ msgstr "" msgid "Only the following organizations may access this contest:" msgstr "" -#: templates/contest/ranking-table.html:9 templates/problem/search-form.html:35 +#: templates/contest/ranking-table.html:7 msgid "Organization" msgstr "" -#: templates/contest/ranking-table.html:10 templates/user/users-table.html:13 -msgid "Full Name" -msgstr "" - -#: templates/contest/ranking-table.html:44 +#: templates/contest/ranking-table.html:30 msgid "Un-Disqualify" msgstr "" -#: templates/contest/ranking-table.html:47 +#: templates/contest/ranking-table.html:33 msgid "Disqualify" msgstr "" -#: templates/contest/ranking.html:187 +#: templates/contest/ranking.html:173 msgid "Are you sure you want to disqualify this participation?" msgstr "" -#: templates/contest/ranking.html:192 +#: templates/contest/ranking.html:178 msgid "Are you sure you want to un-disqualify this participation?" msgstr "" -#: templates/contest/ranking.html:463 +#: templates/contest/ranking.html:252 msgid "View user participation" msgstr "" -#: templates/contest/ranking.html:467 +#: templates/contest/ranking.html:256 msgid "Show organizations" msgstr "" -#: templates/contest/ranking.html:471 -msgid "Show full name" -msgstr "" - -#: templates/contest/ranking.html:474 -msgid "Show friends only" -msgstr "" - -#: templates/contest/ranking.html:477 -msgid "Total score only" -msgstr "" - -#: templates/contest/ranking.html:479 -msgid "Show virtual participation" -msgstr "" - -#: templates/contest/stats.html:51 +#: templates/contest/stats.html:38 msgid "Problem Status Distribution" msgstr "" -#: templates/contest/stats.html:56 +#: templates/contest/stats.html:43 msgid "Problem AC Rate" msgstr "" -#: templates/contest/stats.html:62 -msgid "Problem Point Distribution" -msgstr "" - -#: templates/contest/stats.html:76 templates/stats/language.html:16 +#: templates/contest/stats.html:48 templates/stats/language.html:16 msgid "Submissions by Language" msgstr "" -#: templates/contest/stats.html:82 templates/stats/language.html:26 +#: templates/contest/stats.html:54 templates/stats/language.html:26 msgid "Language AC Rate" msgstr "" @@ -3592,7 +3284,6 @@ msgid "Source:" msgstr "" #: templates/newsletter/common.html:6 -#: templates/newsletter/newsletter_list.html:15 #: templates/newsletter/subscription_unsubscribe_activated.html:3 #: templates/newsletter/subscription_unsubscribe_activated.html:6 #: templates/newsletter/subscription_update_activated.html:3 @@ -3600,23 +3291,6 @@ msgstr "" msgid "Newsletter" msgstr "" -#: templates/newsletter/newsletter_list.html:2 -#: templates/newsletter/newsletter_list.html:3 -msgid "Newsletter list" -msgstr "" - -#: templates/newsletter/newsletter_list.html:6 -msgid "Subscribe to get the latest emails about upcoming contests and events." -msgstr "" - -#: templates/newsletter/newsletter_list.html:16 -msgid "Subscribe" -msgstr "" - -#: templates/newsletter/newsletter_list.html:30 -msgid "Update subscriptions" -msgstr "" - #: templates/newsletter/subscription_unsubscribe_activated.html:3 #: templates/newsletter/subscription_unsubscribe_activated.html:6 #: templates/newsletter/subscription_update_activated.html:3 @@ -3678,97 +3352,64 @@ msgid "" "follow in order to update your subscription." msgstr "" -#: templates/notification/list.html:7 -msgid "You have no notifications" -msgstr "" - -#: templates/notification/list.html:13 -msgid "Activity" -msgstr "" - #: templates/organization/edit.html:46 #: templates/organization/requests/pending.html:34 #: templates/ticket/edit-notes.html:4 msgid "Update" msgstr "" -#: templates/organization/home.html:41 +#: templates/organization/home.html:7 msgid "Are you sure you want to leave this organization?" msgstr "" -#: templates/organization/home.html:43 +#: templates/organization/home.html:9 msgid "You will have to rejoin to show up on the organization leaderboard." msgstr "" -#: templates/organization/home.html:45 +#: templates/organization/home.html:11 msgid "You will have to request membership in order to join again." msgstr "" -#: templates/organization/home.html:88 -msgid "Join organization" -msgstr "" - -#: templates/organization/home.html:92 -msgid "Request membership" -msgstr "" - -#: templates/organization/home.html:122 -msgid "Organization news" -msgstr "" - -#: templates/organization/home.html:128 -msgid "There is no news at this time." -msgstr "" - -#: templates/organization/home.html:137 -msgid "Controls" -msgstr "" - -#: templates/organization/home.html:142 -msgid "Edit organization" -msgstr "" - -#: templates/organization/home.html:148 -msgid "View requests" -msgstr "" - -#: templates/organization/home.html:161 -msgid "Admin organization" -msgstr "" - -#: templates/organization/home.html:167 -msgid "View members" -msgstr "" - -#: templates/organization/home.html:174 +#: templates/organization/home.html:24 msgid "Leave organization" msgstr "" -#: templates/organization/home.html:183 -msgid "New private contests" +#: templates/organization/home.html:29 +msgid "Join organization" msgstr "" -#: templates/organization/home.html:193 templates/organization/home.html:208 -msgid "View all" +#: templates/organization/home.html:33 +msgid "Request membership" msgstr "" -#: templates/organization/home.html:199 -msgid "New private problems" +#: templates/organization/home.html:39 +msgid "Edit organization" msgstr "" -#: templates/organization/list.html:40 -msgid "Show my organizations only" +#: templates/organization/home.html:43 +msgid "View requests" msgstr "" -#: templates/organization/list.html:47 templates/status/language-list.html:34 -#: templates/user/import/table_csv.html:6 +#: templates/organization/home.html:50 +msgid "Admin organization" +msgstr "" + +#: templates/organization/home.html:55 +msgid "View members" +msgstr "" + +#: templates/organization/list.html:23 templates/status/language-list.html:34 msgid "Name" msgstr "" -#: templates/organization/list.html:48 +#: templates/organization/list.html:24 msgid "Members" msgstr "" +#: templates/organization/new.html:10 templates/ticket/new.html:38 +msgid "Create" +msgstr "" + #: templates/organization/requests/detail.html:13 msgid "User:" msgstr "" @@ -3801,7 +3442,7 @@ msgid "There are no requests to approve." msgstr "" #: templates/organization/requests/pending.html:17 -#: templates/problem/data.html:432 +#: templates/problem/data.html:452 msgid "Delete?" msgstr "" @@ -3837,35 +3478,35 @@ msgstr "" msgid "Enter a new code for the cloned problem:" msgstr "" -#: templates/problem/data.html:119 +#: templates/problem/data.html:108 msgid "Instruction" msgstr "" -#: templates/problem/data.html:390 +#: templates/problem/data.html:410 msgid "View YAML" msgstr "" -#: templates/problem/data.html:421 templates/problem/data.html:472 +#: templates/problem/data.html:441 templates/problem/data.html:491 msgid "Apply!" msgstr "" -#: templates/problem/data.html:426 +#: templates/problem/data.html:446 msgid "Type" msgstr "" -#: templates/problem/data.html:427 +#: templates/problem/data.html:447 msgid "Input file" msgstr "" -#: templates/problem/data.html:428 +#: templates/problem/data.html:448 msgid "Output file" msgstr "" -#: templates/problem/data.html:430 +#: templates/problem/data.html:450 msgid "Pretest?" msgstr "" -#: templates/problem/data.html:473 +#: templates/problem/data.html:492 msgid "Add new case" msgstr "" @@ -3877,32 +3518,28 @@ msgid "" "problem yourself is a bannable offence." msgstr "" -#: templates/problem/list.html:66 +#: templates/problem/list.html:62 msgid "Filter by type..." msgstr "" -#: templates/problem/list.html:193 +#: templates/problem/list.html:185 msgid "Hot problems" msgstr "" -#: templates/problem/list.html:218 templates/problem/list.html:240 -#: templates/problem/search-form.html:45 templates/user/user-problems.html:57 +#: templates/problem/list.html:207 templates/problem/list.html:224 +#: templates/problem/search-form.html:30 templates/user/user-problems.html:57 msgid "Category" msgstr "" -#: templates/problem/list.html:220 templates/problem/list.html:244 +#: templates/problem/list.html:209 templates/problem/list.html:228 msgid "Types" msgstr "" -#: templates/problem/list.html:251 +#: templates/problem/list.html:235 #, python-format msgid "AC %%" msgstr "" -#: templates/problem/list.html:342 -msgid "Add clarifications" -msgstr "" - #: templates/problem/manage_submission.html:55 msgid "Leave empty to not filter by language" msgstr "" @@ -3911,199 +3548,152 @@ msgstr "" msgid "Leave empty to not filter by result" msgstr "" -#: templates/problem/manage_submission.html:80 +#: templates/problem/manage_submission.html:79 msgid "Need valid values for both start and end IDs." msgstr "" -#: templates/problem/manage_submission.html:83 +#: templates/problem/manage_submission.html:82 msgid "End ID must be after start ID." msgstr "" +#: templates/problem/manage_submission.html:90 +#, python-brace-format +msgid "" +"You are about to rejudge {count} submissions. Are you sure you want to do " +"this?" +msgstr "" + #: templates/problem/manage_submission.html:96 -#, python-brace-format msgid "" -"You are about to {action} {count} submissions. Are you sure you want to do " -"this?" +"You are about to rejudge a few submissions. Are you sure you want to do this?" msgstr "" -#: templates/problem/manage_submission.html:103 -#, python-brace-format -msgid "" -"You are about to {action} a few submissions. Are you sure you want to do " -"this?" +#: templates/problem/manage_submission.html:115 +msgid "Rejudge Submissions" msgstr "" -#: templates/problem/manage_submission.html:127 -#: templates/submission/list.html:309 -msgid "Filter submissions" -msgstr "" - -#: templates/problem/manage_submission.html:132 +#: templates/problem/manage_submission.html:120 msgid "Filter by ID:" msgstr "" -#: templates/problem/manage_submission.html:135 +#: templates/problem/manage_submission.html:123 msgid "Starting ID:" msgstr "" -#: templates/problem/manage_submission.html:139 +#: templates/problem/manage_submission.html:127 msgid "Ending ID:" msgstr "" -#: templates/problem/manage_submission.html:143 +#: templates/problem/manage_submission.html:131 msgid "This range includes both endpoints." msgstr "" -#: templates/problem/manage_submission.html:146 +#: templates/problem/manage_submission.html:134 msgid "Filter by language:" msgstr "" -#: templates/problem/manage_submission.html:154 +#: templates/problem/manage_submission.html:142 msgid "Filter by result:" msgstr "" -#: templates/problem/manage_submission.html:164 -msgid "Action" -msgstr "" - -#: templates/problem/manage_submission.html:166 +#: templates/problem/manage_submission.html:150 msgid "Rejudge selected submissions" msgstr "" -#: templates/problem/manage_submission.html:171 -msgid "Download selected submissions" +#: templates/problem/manage_submission.html:157 +msgid "Rescore Everything" msgstr "" -#: templates/problem/manage_submission.html:177 -#, python-format -msgid "Are you sure you want to rescore %(count)d submissions?" -msgstr "" - -#: templates/problem/manage_submission.html:178 +#: templates/problem/manage_submission.html:163 msgid "Rescore all submissions" msgstr "" -#: templates/problem/problem.html:132 +#: templates/problem/problem.html:91 msgid "View as PDF" msgstr "" -#: templates/problem/problem.html:141 templates/problem/problem.html:151 -#: templates/problem/problem.html:156 +#: templates/problem/problem.html:101 templates/problem/problem.html:111 +#: templates/problem/problem.html:116 msgid "Submit solution" msgstr "" -#: templates/problem/problem.html:144 -#, python-format -msgid "%(counter)s submission left" -msgid_plural "%(counter)s submissions left" -msgstr[0] "" -msgstr[1] "" - -#: templates/problem/problem.html:152 +#: templates/problem/problem.html:112 msgid "0 submissions left" msgstr "" -#: templates/problem/problem.html:164 +#: templates/problem/problem.html:124 msgid "My submissions" msgstr "" -#: templates/problem/problem.html:168 +#: templates/problem/problem.html:128 msgid "Best submissions" msgstr "" -#: templates/problem/problem.html:172 +#: templates/problem/problem.html:132 msgid "Read editorial" msgstr "" -#: templates/problem/problem.html:177 +#: templates/problem/problem.html:137 msgid "Manage tickets" msgstr "" -#: templates/problem/problem.html:181 +#: templates/problem/problem.html:141 msgid "Edit problem" msgstr "" -#: templates/problem/problem.html:183 +#: templates/problem/problem.html:143 msgid "Edit test data" msgstr "" -#: templates/problem/problem.html:188 +#: templates/problem/problem.html:148 msgid "My tickets" msgstr "" -#: templates/problem/problem.html:196 +#: templates/problem/problem.html:156 msgid "Manage submissions" msgstr "" -#: templates/problem/problem.html:202 +#: templates/problem/problem.html:162 msgid "Clone problem" msgstr "" -#: templates/problem/problem.html:209 +#: templates/problem/problem.html:169 msgid "Points:" msgstr "" -#: templates/problem/problem.html:212 templates/problem/problem.html:214 +#: templates/problem/problem.html:172 templates/problem/problem.html:174 msgid "(partial)" msgstr "" -#: templates/problem/problem.html:219 +#: templates/problem/problem.html:179 msgid "Time limit:" msgstr "" -#: templates/problem/problem.html:231 +#: templates/problem/problem.html:191 msgid "Memory limit:" msgstr "" -#: templates/problem/problem.html:250 -msgid "Author:" -msgid_plural "Authors:" -msgstr[0] "" -msgstr[1] "" - -#: templates/problem/problem.html:265 -msgid "Problem type" -msgid_plural "Problem types" -msgstr[0] "" -msgstr[1] "" - -#: templates/problem/problem.html:278 +#: templates/problem/problem.html:238 msgid "Allowed languages" msgstr "" -#: templates/problem/problem.html:286 -#, python-format -msgid "No %(lang)s judge online" -msgstr "" - -#: templates/problem/problem.html:297 -msgid "Judge:" -msgid_plural "Judges:" -msgstr[0] "" -msgstr[1] "" - -#: templates/problem/problem.html:314 +#: templates/problem/problem.html:274 msgid "none available" msgstr "" -#: templates/problem/problem.html:326 -#, python-format -msgid "This problem has %(length)s clarification(s)" -msgstr "" - -#: templates/problem/problem.html:350 +#: templates/problem/problem.html:299 msgid "Request clarification" msgstr "" -#: templates/problem/problem.html:352 +#: templates/problem/problem.html:301 msgid "Report an issue" msgstr "" -#: templates/problem/raw.html:64 +#: templates/problem/raw.html:62 msgid "Time Limit:" msgstr "" -#: templates/problem/raw.html:73 +#: templates/problem/raw.html:71 msgid "Memory Limit:" msgstr "" @@ -4127,73 +3717,39 @@ msgstr "" msgid "Show problem types" msgstr "" -#: templates/problem/search-form.html:32 -msgid "Show editorial" -msgstr "" - -#: templates/problem/search-form.html:48 templates/problem/search-form.html:50 -#: templates/submission/submission-list-tabs.html:4 +#: templates/problem/search-form.html:33 templates/problem/search-form.html:35 msgid "All" msgstr "" -#: templates/problem/search-form.html:62 +#: templates/problem/search-form.html:46 msgid "Problem types" msgstr "" -#: templates/problem/search-form.html:73 +#: templates/problem/search-form.html:57 msgid "Point range" msgstr "" -#: templates/problem/search-form.html:79 templates/submission/list.html:331 +#: templates/problem/search-form.html:63 templates/submission/list.html:331 #: templates/ticket/list.html:248 msgid "Go" msgstr "" -#: templates/problem/search-form.html:80 +#: templates/problem/search-form.html:64 msgid "Random" msgstr "" -#: templates/problem/submit.html:117 -msgid "Your source code must contain at most 65536 characters." -msgstr "" - -#: templates/problem/submit.html:204 -#, python-format -msgid "" -"Warning! Your default language, %(default_language)s, is " -"unavailable for this problem and has been deselected." -msgstr "" - -#: templates/problem/submit.html:215 -#, python-format -msgid "" -"\n" -" You have %(left)s submission left\n" -" " -msgid_plural "" -"\n" -" You have %(left)s submissions left\n" -" " -msgstr[0] "" -msgstr[1] "" - -#: templates/problem/submit.html:224 +#: templates/problem/submit.html:212 msgid "You have 0 submissions left" msgstr "" -#: templates/problem/submit.html:258 +#: templates/problem/submit.html:250 msgid "No judge is available for this problem." msgstr "" -#: templates/problem/submit.html:262 +#: templates/problem/submit.html:252 msgid "Submit!" msgstr "" -#: templates/registration/activate.html:3 -#, python-format -msgid "%(key)s is an invalid activation key." -msgstr "" - #: templates/registration/activation_complete.html:3 msgid "Your account has been successfully activated." msgstr "" @@ -4251,13 +3807,6 @@ msgid "" "you registered with, and check your spam folder." msgstr "" -#: templates/registration/password_reset_email.txt:1 -#, python-format -msgid "" -"You're receiving this email because you requested a password reset for your " -"user account at %(site_name)s." -msgstr "" - #: templates/registration/password_reset_email.txt:3 msgid "Please go to the following page and choose a new password:" msgstr "" @@ -4270,16 +3819,6 @@ msgstr "" msgid "Thanks for using our site!" msgstr "" -#: templates/registration/password_reset_email.txt:11 -#, python-format -msgid "The %(site_name)s team" -msgstr "" - -#: templates/registration/password_reset_subject.txt:1 -#, python-format -msgid "Password reset on %(site_name)s" -msgstr "" - #: templates/registration/profile_creation.html:36 #: templates/registration/username_select.html:7 msgid "Continue >" @@ -4316,20 +3855,19 @@ msgstr "" msgid "Affiliated organizations" msgstr "" -#: templates/registration/registration_form.html:195 -#: templates/user/edit-profile.html:128 +#: templates/registration/registration_form.html:192 msgid "Notify me about upcoming contests" msgstr "" -#: templates/registration/registration_form.html:209 +#: templates/registration/registration_form.html:206 msgid "By registering, you agree to our" msgstr "" -#: templates/registration/registration_form.html:210 +#: templates/registration/registration_form.html:207 msgid "Terms & Conditions" msgstr "" -#: templates/registration/registration_form.html:213 +#: templates/registration/registration_form.html:210 msgid "Register!" msgstr "" @@ -4339,11 +3877,6 @@ msgstr "" msgid "Enter the 6-digit code generated by your app:" msgstr "" -#: templates/registration/totp_auth.html:41 -#, python-format -msgid "If you lost your authentication device, please contact us at %(email)s." -msgstr "" - #: templates/registration/totp_disable.html:38 msgid "" "To protect your account, you must first authenticate before you can disable " @@ -4362,6 +3895,10 @@ msgstr "" msgid "Or enter this code manually:" msgstr "" +#: templates/stats/base.html:9 templates/submission/list.html:339 +msgid "Statistics" +msgstr "" + #: templates/stats/language.html:11 msgid "Submission Statistics" msgstr "" @@ -4387,7 +3924,6 @@ msgid "Ping" msgstr "" #: templates/status/judge-status-table.html:8 -#: templates/user/import/index.html:104 msgid "Load" msgstr "" @@ -4403,7 +3939,6 @@ msgid "There are no judges available at this time." msgstr "" #: templates/status/language-list.html:33 templates/ticket/list.html:261 -#: templates/user/import/table_csv.html:3 msgid "ID" msgstr "" @@ -4411,22 +3946,6 @@ msgstr "" msgid "Runtime Info" msgstr "" -#: templates/status/status-tabs.html:4 -msgid "Judges" -msgstr "" - -#: templates/status/status-tabs.html:6 -msgid "Version Matrix" -msgstr "" - -#: templates/submission/internal-error-message.html:3 -#, python-format -msgid "" -"An internal error occurred while grading, and the %(SITE_NAME)s " -"administrators have been notified.
In the meantime, try resubmitting in " -"a few seconds." -msgstr "" - #: templates/submission/internal-error-message.html:8 msgid "An internal error occurred while grading." msgstr "" @@ -4443,6 +3962,10 @@ msgstr "" msgid "Filter by language..." msgstr "" +#: templates/submission/list.html:309 +msgid "Filter submissions" +msgstr "" + #: templates/submission/list.html:345 msgid "Total:" msgstr "" @@ -4499,64 +4022,63 @@ msgstr "" msgid "Execution Results" msgstr "" -#: templates/submission/status-testcases.html:34 -msgid "Overall: " -msgstr "" - -#: templates/submission/status-testcases.html:48 -msgid "Point: " -msgstr "" - -#: templates/submission/status-testcases.html:53 -msgid "Time: " -msgstr "" - -#: templates/submission/status-testcases.html:62 -msgid "Memory: " -msgstr "" - -#: templates/submission/status-testcases.html:73 +#: templates/submission/status-testcases.html:31 msgid "Batch " msgstr "" -#: templates/submission/status-testcases.html:84 -#: templates/submission/status-testcases.html:113 -msgid "Point" +#: templates/submission/status-testcases.html:43 +msgid "Overall: " msgstr "" -#: templates/submission/status-testcases.html:99 +#: templates/submission/status-testcases.html:57 +msgid "Point: " +msgstr "" + +#: templates/submission/status-testcases.html:62 +msgid "Time: " +msgstr "" + +#: templates/submission/status-testcases.html:71 +msgid "Memory: " +msgstr "" + +#: templates/submission/status-testcases.html:84 msgid "Case" msgstr "" -#: templates/submission/status-testcases.html:101 +#: templates/submission/status-testcases.html:86 msgid "Pretest" msgstr "" -#: templates/submission/status-testcases.html:103 +#: templates/submission/status-testcases.html:88 msgid "Test case" msgstr "" -#: templates/submission/status-testcases.html:141 +#: templates/submission/status-testcases.html:99 +msgid "Point" +msgstr "" + +#: templates/submission/status-testcases.html:121 msgid "Input:" msgstr "" -#: templates/submission/status-testcases.html:145 +#: templates/submission/status-testcases.html:125 msgid "Output:" msgstr "" -#: templates/submission/status-testcases.html:149 +#: templates/submission/status-testcases.html:129 msgid "Answer:" msgstr "" -#: templates/submission/status-testcases.html:154 +#: templates/submission/status-testcases.html:134 msgid "Judge feedback:" msgstr "" -#: templates/submission/status-testcases.html:175 +#: templates/submission/status-testcases.html:157 msgid "Passing pretests does not guarantee a full score on system tests." msgstr "" -#: templates/submission/status-testcases.html:178 +#: templates/submission/status-testcases.html:160 msgid "Submission aborted!" msgstr "" @@ -4568,24 +4090,11 @@ msgstr "" msgid "Abort" msgstr "" -#: templates/submission/submission-list-tabs.html:6 -msgid "Mine" -msgstr "" - -#: templates/submission/submission-list-tabs.html:9 -msgid "Best" -msgstr "" - -#: templates/submission/submission-list-tabs.html:12 -#, python-format -msgid "%(user)s's" -msgstr "" - -#: templates/ticket/list.html:135 templates/ticket/ticket.html:273 +#: templates/ticket/list.html:135 templates/ticket/ticket.html:257 msgid "Reopened: " msgstr "" -#: templates/ticket/list.html:138 templates/ticket/ticket.html:274 +#: templates/ticket/list.html:138 templates/ticket/ticket.html:258 msgid "Closed: " msgstr "" @@ -4609,7 +4118,7 @@ msgstr "" msgid "Title" msgstr "" -#: templates/ticket/list.html:264 templates/ticket/ticket.html:369 +#: templates/ticket/list.html:264 templates/ticket/ticket.html:328 msgid "Assignees" msgstr "" @@ -4624,36 +4133,32 @@ msgid "" "a problem, ask in the comments instead." msgstr "" -#: templates/ticket/ticket.html:355 -msgid "Post" -msgstr "" - -#: templates/ticket/ticket.html:363 +#: templates/ticket/ticket.html:322 msgid "Associated object" msgstr "" -#: templates/ticket/ticket.html:374 +#: templates/ticket/ticket.html:333 msgid "No one is assigned." msgstr "" -#: templates/ticket/ticket.html:380 +#: templates/ticket/ticket.html:339 msgid "Close ticket" msgstr "" -#: templates/ticket/ticket.html:382 +#: templates/ticket/ticket.html:341 msgid "Reopen ticket" msgstr "" -#: templates/ticket/ticket.html:386 +#: templates/ticket/ticket.html:345 msgid "Assignee notes" msgstr "" -#: templates/ticket/ticket.html:393 templates/widgets/select_all.html:4 +#: templates/ticket/ticket.html:352 templates/widgets/select_all.html:4 msgid "Nothing here." msgstr "" -#: templates/user/base-users-table.html:3 -msgid "Rank" +#: templates/ticket/ticket.html:385 +msgid "Post" msgstr "" #: templates/user/base-users.html:14 templates/user/base-users.html:69 @@ -4700,168 +4205,50 @@ msgstr "" msgid "Update profile" msgstr "" -#: templates/user/import/index.html:31 -msgid "Upload CSV only" -msgstr "" - -#: templates/user/import/index.html:100 -msgid "User File" -msgstr "" - -#: templates/user/import/index.html:102 -msgid "Sample" -msgstr "" - -#: templates/user/import/index.html:105 templates/user/user-list-tabs.html:8 -msgid "Import" -msgstr "" - -#: templates/user/import/table_csv.html:7 -msgid "School" -msgstr "" - -#: templates/user/pp-row.html:22 -#, python-format -msgid "" -"\n" -" weighted %(weight)s%%\n" -" " -msgstr "" - -#: templates/user/pp-row.html:27 -#, python-format -msgid "%(pp).1fpp" -msgstr "" - -#: templates/user/pp-row.html:29 -#, python-format -msgid "%(pp).0fpp" -msgstr "" - -#: templates/user/user-about.html:23 -#, python-format -msgid "%(counter)s problem solved" -msgid_plural "%(counter)s problems solved" -msgstr[0] "" -msgstr[1] "" - -#: templates/user/user-about.html:35 -msgid "Total points" -msgstr "" - -#: templates/user/user-about.html:45 -msgid "Rank by rating" -msgstr "" - -#: templates/user/user-about.html:52 -msgid "Rank by points" -msgstr "" - -#: templates/user/user-about.html:64 +#: templates/user/user-about.html:14 msgid "From" msgstr "" -#: templates/user/user-about.html:75 +#: templates/user/user-about.html:25 msgid "Admin Notes" msgstr "" -#: templates/user/user-about.html:90 +#: templates/user/user-about.html:40 msgid "You have not shared any information." msgstr "" -#: templates/user/user-about.html:92 +#: templates/user/user-about.html:42 msgid "This user has not shared any information." msgstr "" -#: templates/user/user-about.html:101 -msgid "Awards" +#: templates/user/user-base.html:50 +msgid "Rank by points:" msgstr "" -#: templates/user/user-about.html:112 -#, python-format -msgid "%(label)s (%(date)s)" +#: templates/user/user-base.html:53 +msgid "Total points:" msgstr "" -#: templates/user/user-about.html:130 -msgid "Mon" +#: templates/user/user-base.html:68 +msgid "Rank by rating:" msgstr "" -#: templates/user/user-about.html:135 -msgid "Tues" +#: templates/user/user-base.html:70 +msgid "Rating:" msgstr "" -#: templates/user/user-about.html:140 -msgid "Wed" -msgstr "" - -#: templates/user/user-about.html:145 -msgid "Thurs" -msgstr "" - -#: templates/user/user-about.html:150 -msgid "Fri" -msgstr "" - -#: templates/user/user-about.html:155 -msgid "Sat" -msgstr "" - -#: templates/user/user-about.html:160 -msgid "Sun" -msgstr "" - -#: templates/user/user-about.html:169 -msgid "Less" -msgstr "" - -#: templates/user/user-about.html:175 -msgid "More" -msgstr "" - -#: templates/user/user-about.html:184 -msgid "Rating History" -msgstr "" - -#: templates/user/user-about.html:255 -msgid "past year" -msgstr "" - -#: templates/user/user-about.html:272 -msgid "total submission(s)" -msgstr "" - -#: templates/user/user-about.html:276 -msgid "submissions in the last year" -msgstr "" - -#: templates/user/user-base.html:101 -msgid "Unfollow" -msgstr "" - -#: templates/user/user-base.html:104 -msgid "Follow" -msgstr "" - -#: templates/user/user-base.html:120 -msgid "Contests written" -msgstr "" - -#: templates/user/user-base.html:124 +#: templates/user/user-base.html:71 msgid "Volatility:" msgstr "" -#: templates/user/user-base.html:128 +#: templates/user/user-base.html:72 msgid "Min. rating:" msgstr "" -#: templates/user/user-base.html:132 +#: templates/user/user-base.html:73 msgid "Max rating:" msgstr "" -#: templates/user/user-list-tabs.html:5 -msgid "Friends" -msgstr "" - #: templates/user/user-problems.html:35 msgid "Points Breakdown" msgstr "" @@ -4882,32 +4269,10 @@ msgstr "" msgid "Hide problems I've solved" msgstr "" -#: templates/user/user-problems.html:93 -#, python-format -msgid "%(points).1f points" -msgstr "" - #: templates/user/user-problems.html:99 msgid "Score" msgstr "" -#: templates/user/user-problems.html:110 -#, python-format -msgid "%(points)s / %(total)s" -msgstr "" - -#: templates/user/user-tabs.html:7 -msgid "Impersonate" -msgstr "" - -#: templates/user/user-tabs.html:13 -msgid "Admin User" -msgstr "" - -#: templates/user/user-tabs.html:16 -msgid "Admin Profile" -msgstr "" - #: templates/widgets/select_all.html:8 msgid "Check all" msgstr "" diff --git a/locale/it/LC_MESSAGES/djangojs.po b/locale/it/LC_MESSAGES/djangojs.po index ef56d5b..958375c 100644 --- a/locale/it/LC_MESSAGES/djangojs.po +++ b/locale/it/LC_MESSAGES/djangojs.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: dmoj\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-07-20 23:30+0700\n" +"POT-Creation-Date: 2019-10-01 23:12+0000\n" "PO-Revision-Date: 2019-11-11 22:05\n" "Last-Translator: Icyene\n" "Language-Team: Italian\n" @@ -27,3 +27,4 @@ msgstr[1] "" msgctxt "time format without day" msgid "%h:%m:%s" msgstr "" + diff --git a/locale/ja/LC_MESSAGES/django.po b/locale/ja/LC_MESSAGES/django.po index 5d14a95..2802159 100644 --- a/locale/ja/LC_MESSAGES/django.po +++ b/locale/ja/LC_MESSAGES/django.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: dmoj\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-10-25 05:59+0700\n" +"POT-Creation-Date: 2020-04-10 01:26-0500\n" "PO-Revision-Date: 2019-11-11 22:05\n" "Last-Translator: Icyene\n" "Language-Team: Japanese\n" @@ -16,93 +16,93 @@ msgstr "" "X-Crowdin-Language: ja\n" "X-Crowdin-File: django.po\n" -#: chat_box/models.py:16 judge/admin/interface.py:110 -#: judge/models/contest.py:403 judge/models/contest.py:528 -#: judge/models/profile.py:211 +#: chat_box/models.py:15 judge/admin/interface.py:107 +#: judge/models/contest.py:257 judge/models/contest.py:381 +#: judge/models/profile.py:191 msgid "user" msgstr "利用者" -#: chat_box/models.py:17 judge/models/comment.py:43 judge/models/comment.py:191 +#: chat_box/models.py:16 judge/models/comment.py:42 msgid "posted time" msgstr "投稿時刻" -#: chat_box/models.py:18 judge/models/comment.py:47 +#: chat_box/models.py:17 judge/models/comment.py:46 msgid "body of comment" msgstr "コメント本文" -#: chat_box/views.py:29 templates/chat/chat.html:4 +#: chat_box/views.py:29 msgid "Chat Box" msgstr "" -#: dmoj/settings.py:355 +#: dmoj/settings.py:349 msgid "German" msgstr "ドイツ語" -#: dmoj/settings.py:356 +#: dmoj/settings.py:350 msgid "English" msgstr "英語" -#: dmoj/settings.py:357 +#: dmoj/settings.py:351 msgid "Spanish" msgstr "スペイン語" -#: dmoj/settings.py:358 +#: dmoj/settings.py:352 msgid "French" msgstr "フランス語" -#: dmoj/settings.py:359 +#: dmoj/settings.py:353 msgid "Croatian" msgstr "クロアチア語" -#: dmoj/settings.py:360 +#: dmoj/settings.py:354 msgid "Hungarian" msgstr "ハンガリー語" -#: dmoj/settings.py:361 +#: dmoj/settings.py:355 msgid "Japanese" msgstr "日本語" -#: dmoj/settings.py:362 +#: dmoj/settings.py:356 msgid "Korean" msgstr "韓国語" -#: dmoj/settings.py:363 +#: dmoj/settings.py:357 msgid "Brazilian Portuguese" msgstr "" -#: dmoj/settings.py:364 +#: dmoj/settings.py:358 msgid "Romanian" msgstr "ルーマニア語" -#: dmoj/settings.py:365 +#: dmoj/settings.py:359 msgid "Russian" msgstr "ロシア語" -#: dmoj/settings.py:366 +#: dmoj/settings.py:360 msgid "Serbian (Latin)" msgstr "セルビア語(ラテン)" -#: dmoj/settings.py:367 +#: dmoj/settings.py:361 msgid "Turkish" msgstr "トルコ語" -#: dmoj/settings.py:368 +#: dmoj/settings.py:362 msgid "Vietnamese" msgstr "ベトナム語" -#: dmoj/settings.py:369 +#: dmoj/settings.py:363 msgid "Simplified Chinese" msgstr "簡体字中国語" -#: dmoj/settings.py:370 +#: dmoj/settings.py:364 msgid "Traditional Chinese" msgstr "" -#: dmoj/urls.py:58 +#: dmoj/urls.py:57 msgid "Login" msgstr "ログイン" -#: dmoj/urls.py:106 templates/base.html:193 +#: dmoj/urls.py:105 templates/base.html:190 msgid "Home" msgstr "ホーム" @@ -130,88 +130,86 @@ msgstr "コメントの非表示を解除する" msgid "Associated page" msgstr "関連するページ" -#: judge/admin/contest.py:30 +#: judge/admin/contest.py:28 msgid "Included contests" msgstr "含まれているコンテスト" -#: judge/admin/contest.py:66 templates/contest/clarification.html:42 -#: templates/contest/contest.html:83 templates/contest/moss.html:43 -#: templates/problem/list.html:214 templates/problem/list.html:232 -#: templates/problem/list.html:350 templates/user/user-problems.html:56 +#: judge/admin/contest.py:64 templates/contest/contest.html:83 +#: templates/contest/moss.html:43 templates/problem/list.html:206 +#: templates/problem/list.html:221 templates/user/user-problems.html:56 #: templates/user/user-problems.html:98 msgid "Problem" msgstr "課題" -#: judge/admin/contest.py:119 +#: judge/admin/contest.py:112 msgid "Settings" msgstr "設定" -#: judge/admin/contest.py:121 +#: judge/admin/contest.py:114 msgid "Scheduling" msgstr "スケジュール" -#: judge/admin/contest.py:122 templates/organization/home.html:107 +#: judge/admin/contest.py:115 msgid "Details" msgstr "詳細" -#: judge/admin/contest.py:123 +#: judge/admin/contest.py:116 msgid "Format" msgstr "フォーマット" -#: judge/admin/contest.py:124 templates/contest/ranking-table.html:7 -#: templates/user/user-about.html:15 templates/user/user-about.html:45 +#: judge/admin/contest.py:117 templates/contest/ranking-table.html:5 msgid "Rating" msgstr "評価" -#: judge/admin/contest.py:125 +#: judge/admin/contest.py:118 msgid "Access" msgstr "アクセス" -#: judge/admin/contest.py:127 judge/admin/problem.py:131 +#: judge/admin/contest.py:120 judge/admin/problem.py:131 msgid "Justice" msgstr "正義" -#: judge/admin/contest.py:207 +#: judge/admin/contest.py:158 #, python-format msgid "%d contest successfully marked as visible." msgid_plural "%d contests successfully marked as visible." msgstr[0] "%d 個の課題を公開しました。" -#: judge/admin/contest.py:210 +#: judge/admin/contest.py:161 msgid "Mark contests as visible" msgstr "課題を公開する" -#: judge/admin/contest.py:216 +#: judge/admin/contest.py:165 #, python-format msgid "%d contest successfully marked as hidden." msgid_plural "%d contests successfully marked as hidden." msgstr[0] "%d 個の課題を非公開としました。" -#: judge/admin/contest.py:219 +#: judge/admin/contest.py:168 msgid "Mark contests as hidden" msgstr "課題を非公開にする" -#: judge/admin/contest.py:233 judge/admin/submission.py:164 +#: judge/admin/contest.py:182 judge/admin/submission.py:164 #, python-format msgid "%d submission was successfully scheduled for rejudging." msgid_plural "%d submissions were successfully scheduled for rejudging." msgstr[0] "%d 個の提出を再判定するよう設定しました。" -#: judge/admin/contest.py:308 +#: judge/admin/contest.py:256 #, python-format msgid "%d participation recalculated." msgid_plural "%d participations recalculated." msgstr[0] "%d 人の参加者を再計算。" -#: judge/admin/contest.py:311 +#: judge/admin/contest.py:259 msgid "Recalculate results" msgstr "再計算の結果" -#: judge/admin/contest.py:315 judge/admin/organization.py:65 +#: judge/admin/contest.py:263 judge/admin/organization.py:65 msgid "username" msgstr "利用者名" -#: judge/admin/contest.py:320 templates/base.html:277 +#: judge/admin/contest.py:268 templates/base.html:260 msgid "virtual" msgstr "仮想" @@ -219,15 +217,15 @@ msgstr "仮想" msgid "link path" msgstr "リンクパス" -#: judge/admin/interface.py:65 +#: judge/admin/interface.py:62 msgid "Content" msgstr "内容" -#: judge/admin/interface.py:66 +#: judge/admin/interface.py:63 msgid "Summary" msgstr "概要" -#: judge/admin/interface.py:151 +#: judge/admin/interface.py:148 msgid "object" msgstr "" @@ -249,9 +247,8 @@ msgid "Taxonomy" msgstr "分類" #: judge/admin/problem.py:128 templates/contest/contest.html:84 -#: templates/problem/data.html:429 templates/problem/list.html:222 -#: templates/problem/list.html:248 templates/user/base-users-table.html:10 -#: templates/user/user-about.html:36 templates/user/user-about.html:52 +#: templates/problem/data.html:449 templates/problem/list.html:211 +#: templates/problem/list.html:232 templates/user/base-users-table.html:10 #: templates/user/user-problems.html:58 msgid "Points" msgstr "点数" @@ -298,7 +295,6 @@ msgid "timezone" msgstr "時間帯" #: judge/admin/profile.py:86 judge/admin/submission.py:211 -#: templates/notification/list.html:12 #: templates/organization/requests/log.html:9 #: templates/organization/requests/pending.html:12 #: templates/ticket/list.html:263 @@ -306,7 +302,6 @@ msgid "User" msgstr "利用者" #: judge/admin/profile.py:91 templates/registration/registration_form.html:145 -#: templates/user/import/table_csv.html:8 msgid "Email" msgstr "電子メール" @@ -338,7 +333,7 @@ msgstr "許可されていない課題" msgid "These problems are NOT allowed to be submitted in this language" msgstr "それらの課題は、この言語での提出は許可されていません" -#: judge/admin/runtime.py:83 templates/problem/list.html:352 +#: judge/admin/runtime.py:83 msgid "Description" msgstr "説明" @@ -385,7 +380,7 @@ msgstr "あなたには、それら多くの提出物を再判定する権限が msgid "Rejudge the selected submissions" msgstr "選択された提出物を再判定する" -#: judge/admin/submission.py:193 judge/views/problem_manage.py:159 +#: judge/admin/submission.py:193 judge/views/problem_manage.py:128 #, python-format msgid "%d submission were successfully rescored." msgid_plural "%d submissions were successfully rescored." @@ -395,8 +390,7 @@ msgstr[0] "%d 個の提出物が正常に再採点されました。" msgid "Rescore the selected submissions" msgstr "選択した提出物を再採点する" -#: judge/admin/submission.py:200 templates/problem/list.html:216 -#: templates/problem/list.html:236 +#: judge/admin/submission.py:200 msgid "Problem code" msgstr "課題のコード" @@ -404,12 +398,10 @@ msgstr "課題のコード" msgid "Problem name" msgstr "課題名" -#: judge/admin/submission.py:215 templates/notification/list.html:15 -#: templates/organization/requests/log.html:10 +#: judge/admin/submission.py:215 templates/organization/requests/log.html:10 #: templates/organization/requests/pending.html:13 -#: templates/problem/list.html:351 -#: templates/submission/status-testcases.html:125 -#: templates/submission/status-testcases.html:127 +#: templates/submission/status-testcases.html:105 +#: templates/submission/status-testcases.html:107 msgid "Time" msgstr "時間" @@ -423,7 +415,7 @@ msgstr "%d KB" msgid "%.2f MB" msgstr "%.2f MB" -#: judge/admin/submission.py:227 templates/submission/status-testcases.html:132 +#: judge/admin/submission.py:227 templates/submission/status-testcases.html:112 msgid "Memory" msgstr "メモリ" @@ -443,20 +435,20 @@ msgstr "これらの課題は、この課題タイプに含まれている" msgid "Online Judge" msgstr "オンライン判定" -#: judge/comments.py:60 +#: judge/comments.py:41 msgid "Comment body" msgstr "コメント本文" -#: judge/comments.py:66 judge/views/ticket.py:63 +#: judge/comments.py:47 judge/views/ticket.py:46 msgid "Your part is silent, little toad." msgstr "お黙り、ヒキガエル。" -#: judge/comments.py:69 templates/comments/list.html:132 +#: judge/comments.py:50 templates/comments/list.html:131 msgid "" "You need to have solved at least one problem before your voice can be heard." msgstr "コメントを書くには、少なくとも1度は課題を解く必要があります。" -#: judge/comments.py:113 +#: judge/comments.py:92 msgid "Posted comment" msgstr "投稿されたコメント" @@ -472,10 +464,6 @@ msgstr "既定値" msgid "ECOO" msgstr "" -#: judge/contest_format/icpc.py:19 -msgid "ICPC" -msgstr "" - #: judge/contest_format/ioi.py:19 msgid "IOI" msgstr "" @@ -488,60 +476,52 @@ msgstr "コンテストの更新を購読する" msgid "Enable experimental features" msgstr "実験的な機能を有効化する" -#: judge/forms.py:57 judge/views/organization.py:168 judge/views/register.py:49 +#: judge/forms.py:57 judge/views/organization.py:127 #, python-brace-format msgid "You may not be part of more than {count} public organizations." msgstr "あなたは {count} 個以上の公開組織に参加できない場合があります。" -#: judge/forms.py:82 -#, fuzzy -#| msgid "judge" -msgid "Any judge" -msgstr "判定器" - -#: judge/forms.py:112 judge/views/register.py:26 +#: judge/forms.py:107 judge/views/register.py:26 #: templates/registration/registration_form.html:139 #: templates/user/base-users-table.html:5 -#: templates/user/import/table_csv.html:4 msgid "Username" msgstr "利用者名" -#: judge/forms.py:113 templates/registration/registration_form.html:151 +#: judge/forms.py:108 templates/registration/registration_form.html:151 #: templates/registration/registration_form.html:165 -#: templates/user/import/table_csv.html:5 msgid "Password" msgstr "パスワード" -#: judge/forms.py:135 +#: judge/forms.py:130 msgid "Two Factor Authentication tokens must be 6 decimal digits." msgstr "二要素認証のトークンは6桁の数字でなければなりません。" -#: judge/forms.py:144 templates/registration/totp_auth.html:32 +#: judge/forms.py:139 templates/registration/totp_auth.html:32 msgid "Invalid Two Factor Authentication token." msgstr "無効な二要素認証トークンです。" -#: judge/forms.py:148 judge/models/problem.py:97 +#: judge/forms.py:143 judge/models/problem.py:97 msgid "Problem code must be ^[a-z0-9]+$" msgstr "課題のコードは ^[a-z0-9]+$ でなければなりません" -#: judge/forms.py:153 +#: judge/forms.py:148 msgid "Problem with code already exists." msgstr "このコードを使用している問題はすでに存在しています。" -#: judge/forms.py:158 judge/models/contest.py:61 +#: judge/forms.py:153 judge/models/contest.py:52 msgid "Contest id must be ^[a-z0-9]+$" msgstr "コンテスト id は ^[a-z0-9]+$ でなければなりません" -#: judge/forms.py:163 +#: judge/forms.py:158 msgid "Contest with key already exists." msgstr "同じキーを持つコンテストはすでに存在しています。" -#: judge/jinja2/datetime.py:26 templates/blog/blog.html:26 +#: judge/jinja2/datetime.py:26 templates/blog/content.html:27 #: templates/blog/dashboard.html:21 msgid "N j, Y, g:i a" msgstr "N j, Y, g:i a" -#: judge/jinja2/datetime.py:26 templates/chat/message.html:13 +#: judge/jinja2/datetime.py:26 #, python-brace-format msgid "{time}" msgstr "{time}" @@ -571,174 +551,122 @@ msgstr "SVG/PNG フォールバックのある MathJax" msgid "Detect best quality" msgstr "最高品質を検出する" -#: judge/models/comment.py:26 +#: judge/models/comment.py:25 msgid "Page code must be ^[pcs]:[a-z0-9]+$|^b:\\d+$" msgstr "ページコードは ^[pcs]:[a-z0-9]+$|^b:\\d+$ でなければなりません。" -#: judge/models/comment.py:42 +#: judge/models/comment.py:41 msgid "commenter" msgstr "コメンター" -#: judge/models/comment.py:44 judge/models/comment.py:177 +#: judge/models/comment.py:43 judge/models/comment.py:176 msgid "associated page" msgstr "関連するページ" -#: judge/models/comment.py:46 +#: judge/models/comment.py:45 msgid "votes" msgstr "投票" -#: judge/models/comment.py:48 +#: judge/models/comment.py:47 msgid "hide the comment" msgstr "コメントを非表示にする" -#: judge/models/comment.py:49 +#: judge/models/comment.py:48 msgid "parent" msgstr "親" -#: judge/models/comment.py:54 judge/models/comment.py:192 +#: judge/models/comment.py:53 msgid "comment" msgstr "コメント" -#: judge/models/comment.py:55 +#: judge/models/comment.py:54 msgid "comments" msgstr "コメント" -#: judge/models/comment.py:137 judge/models/problem.py:443 +#: judge/models/comment.py:136 judge/models/problem.py:406 #, python-format msgid "Editorial for %s" msgstr "%s の論説" -#: judge/models/comment.py:172 +#: judge/models/comment.py:171 msgid "comment vote" msgstr "コメント投票" -#: judge/models/comment.py:173 +#: judge/models/comment.py:172 msgid "comment votes" msgstr "コメント投票" -#: judge/models/comment.py:182 +#: judge/models/comment.py:181 msgid "Override comment lock" msgstr "" -#: judge/models/comment.py:190 -msgid "owner" -msgstr "" - -#: judge/models/comment.py:193 judge/models/message.py:16 -msgid "read" -msgstr "読む" - -#: judge/models/comment.py:194 -#, fuzzy -#| msgid "Category" -msgid "category" -msgstr "カテゴリ" - -#: judge/models/comment.py:195 -msgid "html link to comments, used for non-comments" -msgstr "" - -#: judge/models/comment.py:196 -msgid "who trigger, used for non-comment" -msgstr "" - -#: judge/models/contest.py:23 +#: judge/models/contest.py:22 msgid "Invalid colour." msgstr "不正な色。" -#: judge/models/contest.py:25 +#: judge/models/contest.py:24 msgid "tag name" msgstr "タグ名" -#: judge/models/contest.py:26 +#: judge/models/contest.py:25 msgid "Lowercase letters and hyphens only." msgstr "小文字とハイフンのみです。" -#: judge/models/contest.py:27 +#: judge/models/contest.py:26 msgid "tag colour" msgstr "タグの色" -#: judge/models/contest.py:28 +#: judge/models/contest.py:27 msgid "tag description" msgstr "タグの説明" -#: judge/models/contest.py:47 +#: judge/models/contest.py:46 msgid "contest tag" msgstr "コンテストのタグ" -#: judge/models/contest.py:48 judge/models/contest.py:118 +#: judge/models/contest.py:47 judge/models/contest.py:101 msgid "contest tags" msgstr "コンテストのタグ" -#: judge/models/contest.py:56 -msgid "Visible" -msgstr "" - -#: judge/models/contest.py:57 -msgid "Hidden for duration of contest" -msgstr "" - -#: judge/models/contest.py:58 -#, fuzzy -#| msgid "View user participation" -msgid "Hidden for duration of participation" -msgstr "利用者の参加を見る" - -#: judge/models/contest.py:60 +#: judge/models/contest.py:51 msgid "contest id" msgstr "コンテスト id" -#: judge/models/contest.py:62 +#: judge/models/contest.py:53 msgid "contest name" msgstr "コンテスト名" -#: judge/models/contest.py:63 -#, fuzzy -#| msgid "These people will be able to edit the contest." -msgid "These users will be able to edit the contest." +#: judge/models/contest.py:54 +msgid "These people will be able to edit the contest." msgstr "これらの人々 は、コンテストを編集することができます。" -#: judge/models/contest.py:65 -#, fuzzy -#| msgid "These people will be able to edit the contest." -msgid "" -"These users will be able to edit the contest, but will not be listed as " -"authors." -msgstr "これらの人々 は、コンテストを編集することができます。" - -#: judge/models/contest.py:68 -#, fuzzy -#| msgid "These people will be able to edit the contest." -msgid "These users will be able to view the contest, but not edit it." -msgstr "これらの人々 は、コンテストを編集することができます。" - -#: judge/models/contest.py:71 judge/models/runtime.py:136 +#: judge/models/contest.py:56 judge/models/runtime.py:133 msgid "description" msgstr "説明" -#: judge/models/contest.py:72 judge/models/problem.py:390 -#: judge/models/runtime.py:138 +#: judge/models/contest.py:57 judge/models/problem.py:353 +#: judge/models/runtime.py:135 msgid "problems" msgstr "課題" -#: judge/models/contest.py:73 judge/models/contest.py:404 +#: judge/models/contest.py:58 judge/models/contest.py:258 msgid "start time" msgstr "開始時刻" -#: judge/models/contest.py:74 +#: judge/models/contest.py:59 msgid "end time" msgstr "終了時刻" -#: judge/models/contest.py:75 judge/models/problem.py:118 -#: judge/models/problem.py:414 +#: judge/models/contest.py:60 judge/models/problem.py:118 +#: judge/models/problem.py:377 msgid "time limit" msgstr "時間制限" -#: judge/models/contest.py:76 judge/models/problem.py:136 +#: judge/models/contest.py:61 judge/models/problem.py:136 msgid "publicly visible" msgstr "公開されています" -#: judge/models/contest.py:77 +#: judge/models/contest.py:62 msgid "" "Should be set even for organization-private contests, where it determines " "whether the contest is visible to members of the specified organizations." @@ -746,94 +674,77 @@ msgstr "" "コンテストが指定された組織のメンバーに表示されるかどうかを決定するものであ" "り、組織にプライベートなコンテストには設定すべきです。" -#: judge/models/contest.py:80 +#: judge/models/contest.py:65 msgid "contest rated" msgstr "評価されているコンテスト" -#: judge/models/contest.py:80 +#: judge/models/contest.py:65 msgid "Whether this contest can be rated." msgstr "このコンテストを評価できるようにするか。" -#: judge/models/contest.py:82 -#, fuzzy -#| msgid "public visibility" -msgid "scoreboard visibility" -msgstr "一般公開" - -#: judge/models/contest.py:83 -#, fuzzy -#| msgid "" -#| "Whether the scoreboard should remain hidden for the duration of the " -#| "contest." -msgid "Scoreboard visibility through the duration of the contest" -msgstr "コンテスト中に得点表を非表示にしておくべきかどうか" - -#: judge/models/contest.py:85 -#, fuzzy -#| msgid "hide scoreboard" -msgid "view contest scoreboard" +#: judge/models/contest.py:67 +msgid "hide scoreboard" msgstr "得点表を非表示にする" -#: judge/models/contest.py:87 -#, fuzzy -#| msgid "These people will be able to edit the contest." -msgid "These users will be able to view the scoreboard." -msgstr "これらの人々 は、コンテストを編集することができます。" +#: judge/models/contest.py:68 +msgid "" +"Whether the scoreboard should remain hidden for the duration of the contest." +msgstr "コンテスト中に得点表を非表示にしておくべきかどうか" -#: judge/models/contest.py:88 +#: judge/models/contest.py:71 msgid "no comments" msgstr "コメントがありません" -#: judge/models/contest.py:89 +#: judge/models/contest.py:72 msgid "Use clarification system instead of comments." msgstr "コメントではなく解説システムを使う。" -#: judge/models/contest.py:91 +#: judge/models/contest.py:74 msgid "Rating floor for contest" msgstr "" -#: judge/models/contest.py:93 +#: judge/models/contest.py:76 msgid "Rating ceiling for contest" msgstr "" -#: judge/models/contest.py:95 +#: judge/models/contest.py:78 msgid "rate all" msgstr "全てを評価する" -#: judge/models/contest.py:95 +#: judge/models/contest.py:78 msgid "Rate all users who joined." msgstr "参加している全ての利用者を評価する。" -#: judge/models/contest.py:96 +#: judge/models/contest.py:79 msgid "exclude from ratings" msgstr "評価から除外する" -#: judge/models/contest.py:98 +#: judge/models/contest.py:81 msgid "private to specific users" msgstr "" -#: judge/models/contest.py:99 +#: judge/models/contest.py:82 msgid "private contestants" msgstr "プライベートな参加者" -#: judge/models/contest.py:100 +#: judge/models/contest.py:83 msgid "If private, only these users may see the contest" msgstr "" "もしプライベートであれば、その参加者のみがコンテストを見ることができます。" -#: judge/models/contest.py:102 +#: judge/models/contest.py:85 msgid "hide problem tags" msgstr "課題のタグを非表示にする" -#: judge/models/contest.py:103 +#: judge/models/contest.py:86 msgid "Whether problem tags should be hidden by default." msgstr "課題タグをデフォルトで非表示にするかどうか" -#: judge/models/contest.py:105 +#: judge/models/contest.py:88 msgid "run pretests only" msgstr "予備テストのみ実行する" -#: judge/models/contest.py:106 +#: judge/models/contest.py:89 msgid "" "Whether judges should grade pretests only, versus all testcases. Commonly " "set during a contest, then unset prior to rejudging user submissions when " @@ -843,50 +754,49 @@ msgstr "" "コンテスト中に設定し、コンテストが終了して利用者の提出物を再判定する前に解除" "する。" -#: judge/models/contest.py:110 judge/models/interface.py:77 -#: judge/models/problem.py:157 +#: judge/models/contest.py:93 judge/models/problem.py:157 msgid "private to organizations" msgstr "組織へプライベートにする" -#: judge/models/contest.py:111 judge/models/interface.py:75 -#: judge/models/problem.py:155 judge/models/profile.py:77 +#: judge/models/contest.py:94 judge/models/problem.py:155 +#: judge/models/profile.py:77 msgid "organizations" msgstr "組織" -#: judge/models/contest.py:112 +#: judge/models/contest.py:95 msgid "If private, only these organizations may see the contest" msgstr "もしプライベートであれば、組織の者だけがコンテストを見ることができます" -#: judge/models/contest.py:113 judge/models/problem.py:145 +#: judge/models/contest.py:96 judge/models/problem.py:145 msgid "OpenGraph image" msgstr "OpenGraph 画像" -#: judge/models/contest.py:114 judge/models/profile.py:48 +#: judge/models/contest.py:97 judge/models/profile.py:48 msgid "Logo override image" msgstr "" -#: judge/models/contest.py:116 +#: judge/models/contest.py:99 msgid "" "This image will replace the default site logo for users inside the contest." msgstr "" -#: judge/models/contest.py:119 +#: judge/models/contest.py:102 msgid "the amount of live participants" msgstr "ライブ参加者の人数" -#: judge/models/contest.py:120 +#: judge/models/contest.py:103 msgid "contest summary" msgstr "コンテスト概要" -#: judge/models/contest.py:121 judge/models/problem.py:147 +#: judge/models/contest.py:104 judge/models/problem.py:147 msgid "Plain-text, shown in meta description tag, e.g. for social media." msgstr "ソーシャルメディアなどのメタ説明タグに表示されるプレーンテキスト。" -#: judge/models/contest.py:122 judge/models/profile.py:47 +#: judge/models/contest.py:105 judge/models/profile.py:47 msgid "access code" msgstr "アクセスコード" -#: judge/models/contest.py:123 +#: judge/models/contest.py:106 msgid "" "An optional code to prompt contestants before they are allowed to join the " "contest. Leave it blank to disable." @@ -894,257 +804,231 @@ msgstr "" "コンテストへの参加が許可される前に競技者に提示するオプションのコード。無効に" "するには空白のままにします。" -#: judge/models/contest.py:125 judge/models/problem.py:141 +#: judge/models/contest.py:108 judge/models/problem.py:141 msgid "personae non gratae" msgstr "感謝しない人" -#: judge/models/contest.py:126 +#: judge/models/contest.py:109 msgid "Bans the selected users from joining this contest." msgstr "選択した利用者の、このコンテストへの参加を禁止する。" -#: judge/models/contest.py:127 +#: judge/models/contest.py:110 msgid "contest format" msgstr "" -#: judge/models/contest.py:128 +#: judge/models/contest.py:111 msgid "The contest format module to use." msgstr "" -#: judge/models/contest.py:129 +#: judge/models/contest.py:112 msgid "contest format configuration" msgstr "" -#: judge/models/contest.py:130 +#: judge/models/contest.py:113 msgid "" "A JSON object to serve as the configuration for the chosen contest format " "module. Leave empty to use None. Exact format depends on the contest format " "selected." msgstr "" -#: judge/models/contest.py:137 -#, fuzzy -#| msgid "test case points" -msgid "precision points" -msgstr "テストケースの点数" - -#: judge/models/contest.py:139 -msgid "Number of digits to round points to." -msgstr "" - -#: judge/models/contest.py:383 +#: judge/models/contest.py:239 msgid "See private contests" msgstr "プライベートのコンテストを見る" -#: judge/models/contest.py:384 +#: judge/models/contest.py:240 msgid "Edit own contests" msgstr "自分のコンテストを編集する" -#: judge/models/contest.py:385 +#: judge/models/contest.py:241 msgid "Edit all contests" msgstr "全てのコンテストを編集する" -#: judge/models/contest.py:386 +#: judge/models/contest.py:242 msgid "Clone contest" msgstr "" -#: judge/models/contest.py:387 templates/contest/moss.html:74 +#: judge/models/contest.py:243 templates/contest/moss.html:74 msgid "MOSS contest" msgstr "" -#: judge/models/contest.py:388 +#: judge/models/contest.py:244 msgid "Rate contests" msgstr "コンテストを評価する" -#: judge/models/contest.py:389 +#: judge/models/contest.py:245 msgid "Contest access codes" msgstr "コンテストのアクセス コード" -#: judge/models/contest.py:390 +#: judge/models/contest.py:246 msgid "Create private contests" msgstr "プライベートなコンテストの生成" -#: judge/models/contest.py:391 -#, fuzzy -#| msgid "Mark contests as visible" -msgid "Change contest visibility" -msgstr "課題を公開する" - -#: judge/models/contest.py:392 -#, fuzzy -#| msgid "contest problems" -msgid "Edit contest problem label script" -msgstr "コンテストの課題" - -#: judge/models/contest.py:394 judge/models/contest.py:492 -#: judge/models/contest.py:529 judge/models/contest.py:552 -#: judge/models/submission.py:84 +#: judge/models/contest.py:248 judge/models/contest.py:345 +#: judge/models/contest.py:382 judge/models/contest.py:404 +#: judge/models/submission.py:83 msgid "contest" msgstr "コンテスト" -#: judge/models/contest.py:395 +#: judge/models/contest.py:249 msgid "contests" msgstr "コンテスト" -#: judge/models/contest.py:402 +#: judge/models/contest.py:256 msgid "associated contest" msgstr "関連するコンテスト" -#: judge/models/contest.py:405 +#: judge/models/contest.py:259 msgid "score" msgstr "得点" -#: judge/models/contest.py:406 +#: judge/models/contest.py:260 msgid "cumulative time" msgstr "累積時間" -#: judge/models/contest.py:407 +#: judge/models/contest.py:261 msgid "is disqualified" msgstr "" -#: judge/models/contest.py:408 +#: judge/models/contest.py:262 msgid "Whether this participation is disqualified." msgstr "" -#: judge/models/contest.py:409 -msgid "tie-breaking field" -msgstr "" - -#: judge/models/contest.py:410 +#: judge/models/contest.py:263 msgid "virtual participation id" msgstr "仮想参加 id" -#: judge/models/contest.py:411 +#: judge/models/contest.py:264 #, fuzzy #| msgid "0 means non-virtual, otherwise the n-th virtual participation" msgid "0 means non-virtual, otherwise the n-th virtual participation." msgstr "0 は仮想参加者がおらず、そうでなければn人の仮想参加者がいます" -#: judge/models/contest.py:412 +#: judge/models/contest.py:265 msgid "contest format specific data" msgstr "" -#: judge/models/contest.py:478 +#: judge/models/contest.py:331 #, python-format msgid "%s spectating in %s" msgstr "%s は %s を観戦している" -#: judge/models/contest.py:480 +#: judge/models/contest.py:333 #, python-format msgid "%s in %s, v%d" msgstr "%s は %s 中で v%d として参加" -#: judge/models/contest.py:481 +#: judge/models/contest.py:334 #, python-format msgid "%s in %s" msgstr "%s は %s に参加" -#: judge/models/contest.py:484 +#: judge/models/contest.py:337 msgid "contest participation" msgstr "コンテスト参加者" -#: judge/models/contest.py:485 +#: judge/models/contest.py:338 msgid "contest participations" msgstr "コンテスト参加者" -#: judge/models/contest.py:491 judge/models/contest.py:513 -#: judge/models/contest.py:553 judge/models/problem.py:389 -#: judge/models/problem.py:394 judge/models/problem.py:412 -#: judge/models/problem_data.py:40 +#: judge/models/contest.py:344 judge/models/contest.py:366 +#: judge/models/contest.py:405 judge/models/problem.py:352 +#: judge/models/problem.py:357 judge/models/problem.py:375 +#: judge/models/problem_data.py:38 msgid "problem" msgstr "課題" -#: judge/models/contest.py:493 judge/models/contest.py:517 +#: judge/models/contest.py:346 judge/models/contest.py:370 #: judge/models/problem.py:129 msgid "points" msgstr "点数" -#: judge/models/contest.py:494 +#: judge/models/contest.py:347 msgid "partial" msgstr "部分点" -#: judge/models/contest.py:495 judge/models/contest.py:518 +#: judge/models/contest.py:348 judge/models/contest.py:371 msgid "is pretested" msgstr "予備テストされているか" -#: judge/models/contest.py:496 judge/models/interface.py:43 +#: judge/models/contest.py:349 judge/models/interface.py:43 msgid "order" msgstr "順番" -#: judge/models/contest.py:497 +#: judge/models/contest.py:350 msgid "0 to not show testcases, 1 to show" msgstr "" -#: judge/models/contest.py:498 +#: judge/models/contest.py:351 #, fuzzy #| msgid "submission test cases" msgid "visible testcases" msgstr "提出テストケース" -#: judge/models/contest.py:499 +#: judge/models/contest.py:352 msgid "Maximum number of submissions for this problem, or 0 for no limit." msgstr "この課題への提出物の最大数、制限なしの場合は 0 。" -#: judge/models/contest.py:501 +#: judge/models/contest.py:354 msgid "Why include a problem you can't submit to?" msgstr "なぜあなたが提出できない課題を含むのか?" -#: judge/models/contest.py:506 +#: judge/models/contest.py:359 msgid "contest problem" msgstr "コンテストの課題" -#: judge/models/contest.py:507 +#: judge/models/contest.py:360 msgid "contest problems" msgstr "コンテストの課題" -#: judge/models/contest.py:511 judge/models/submission.py:183 +#: judge/models/contest.py:364 judge/models/submission.py:181 msgid "submission" msgstr "提出" -#: judge/models/contest.py:515 judge/models/contest.py:530 +#: judge/models/contest.py:368 judge/models/contest.py:383 msgid "participation" msgstr "参加者" -#: judge/models/contest.py:519 +#: judge/models/contest.py:372 msgid "Whether this submission was ran only on pretests." msgstr "この提出物が予備テストだけを実行したのかどうか。" -#: judge/models/contest.py:523 +#: judge/models/contest.py:376 msgid "contest submission" msgstr "コンテスト提出" -#: judge/models/contest.py:524 +#: judge/models/contest.py:377 msgid "contest submissions" msgstr "コンテスト提出" -#: judge/models/contest.py:532 +#: judge/models/contest.py:385 msgid "rank" msgstr "順位" -#: judge/models/contest.py:533 +#: judge/models/contest.py:386 msgid "rating" msgstr "評価" -#: judge/models/contest.py:534 +#: judge/models/contest.py:387 msgid "volatility" msgstr "変動率" -#: judge/models/contest.py:535 +#: judge/models/contest.py:388 msgid "last rated" msgstr "最後の評価" -#: judge/models/contest.py:539 +#: judge/models/contest.py:392 msgid "contest rating" msgstr "コンテストの評価" -#: judge/models/contest.py:540 +#: judge/models/contest.py:393 msgid "contest ratings" msgstr "コンテストの評価" -#: judge/models/contest.py:560 +#: judge/models/contest.py:412 msgid "contest moss result" msgstr "" -#: judge/models/contest.py:561 +#: judge/models/contest.py:413 msgid "contest moss results" msgstr "" @@ -1184,7 +1068,7 @@ msgstr "親項目" msgid "post title" msgstr "投稿の題目" -#: judge/models/interface.py:67 judge/models/problem.py:432 +#: judge/models/interface.py:67 judge/models/problem.py:395 msgid "authors" msgstr "著者" @@ -1192,7 +1076,7 @@ msgstr "著者" msgid "slug" msgstr "スラグ" -#: judge/models/interface.py:69 judge/models/problem.py:430 +#: judge/models/interface.py:69 judge/models/problem.py:393 msgid "public visibility" msgstr "一般公開" @@ -1216,21 +1100,15 @@ msgstr "投稿の概要" msgid "openGraph image" msgstr "openGraph 画像" -#: judge/models/interface.py:76 -#, fuzzy -#| msgid "If private, only these organizations may see the contest" -msgid "If private, only these organizations may see the blog post." -msgstr "もしプライベートであれば、組織の者だけがコンテストを見ることができます" - -#: judge/models/interface.py:105 +#: judge/models/interface.py:91 msgid "Edit all posts" msgstr "すべての投稿を編集する" -#: judge/models/interface.py:107 +#: judge/models/interface.py:93 msgid "blog post" msgstr "ブログ投稿" -#: judge/models/interface.py:108 +#: judge/models/interface.py:94 msgid "blog posts" msgstr "ブログ投稿" @@ -1254,6 +1132,10 @@ msgstr "宛先" msgid "message timestamp" msgstr "メッセージのタイムスタンプ" +#: judge/models/message.py:16 +msgid "read" +msgstr "読む" + #: judge/models/message.py:20 msgid "messages in the thread" msgstr "スレッド中のメッセージ" @@ -1391,7 +1273,7 @@ msgid "" msgstr "" "この課題の秒単位での制限時間。小数秒(例えば1.5)はサポートされています。" -#: judge/models/problem.py:123 judge/models/problem.py:417 +#: judge/models/problem.py:123 judge/models/problem.py:380 msgid "memory limit" msgstr "メモリ制限" @@ -1465,188 +1347,188 @@ msgstr "" msgid "If private, only these organizations may see the problem." msgstr "" -#: judge/models/problem.py:395 judge/models/problem.py:413 -#: judge/models/runtime.py:111 +#: judge/models/problem.py:358 judge/models/problem.py:376 +#: judge/models/runtime.py:108 msgid "language" msgstr "言語" -#: judge/models/problem.py:396 +#: judge/models/problem.py:359 msgid "translated name" msgstr "翻訳された名前" -#: judge/models/problem.py:397 +#: judge/models/problem.py:360 msgid "translated description" msgstr "翻訳された説明" -#: judge/models/problem.py:401 +#: judge/models/problem.py:364 msgid "problem translation" msgstr "翻訳された課題" -#: judge/models/problem.py:402 +#: judge/models/problem.py:365 msgid "problem translations" msgstr "翻訳された課題" -#: judge/models/problem.py:406 +#: judge/models/problem.py:369 msgid "clarified problem" msgstr "解説された課題" -#: judge/models/problem.py:407 +#: judge/models/problem.py:370 msgid "clarification body" msgstr "解説本文" -#: judge/models/problem.py:408 +#: judge/models/problem.py:371 msgid "clarification timestamp" msgstr "解説のタイムスタンプ" -#: judge/models/problem.py:423 +#: judge/models/problem.py:386 msgid "language-specific resource limit" msgstr "言語固有のリソース制限" -#: judge/models/problem.py:424 +#: judge/models/problem.py:387 msgid "language-specific resource limits" msgstr "言語固有のリソース制限" -#: judge/models/problem.py:428 +#: judge/models/problem.py:391 msgid "associated problem" msgstr "関連する課題" -#: judge/models/problem.py:431 +#: judge/models/problem.py:394 msgid "publish date" msgstr "発行日" -#: judge/models/problem.py:433 +#: judge/models/problem.py:396 msgid "editorial content" msgstr "編集内容" -#: judge/models/problem.py:449 +#: judge/models/problem.py:412 msgid "solution" msgstr "解答" -#: judge/models/problem.py:450 +#: judge/models/problem.py:413 msgid "solutions" msgstr "解答" -#: judge/models/problem_data.py:26 +#: judge/models/problem_data.py:24 msgid "Standard" msgstr "標準" -#: judge/models/problem_data.py:27 +#: judge/models/problem_data.py:25 msgid "Floats" msgstr "実数" -#: judge/models/problem_data.py:28 +#: judge/models/problem_data.py:26 msgid "Floats (absolute)" msgstr "実数(絶対値)" -#: judge/models/problem_data.py:29 +#: judge/models/problem_data.py:27 msgid "Floats (relative)" msgstr "実数(相対値)" -#: judge/models/problem_data.py:30 +#: judge/models/problem_data.py:28 msgid "Non-trailing spaces" msgstr "非末尾スペース" -#: judge/models/problem_data.py:31 +#: judge/models/problem_data.py:29 msgid "Unordered" msgstr "順不同" -#: judge/models/problem_data.py:32 +#: judge/models/problem_data.py:30 msgid "Byte identical" msgstr "バイト一致" -#: judge/models/problem_data.py:33 +#: judge/models/problem_data.py:31 msgid "Line-by-line" msgstr "" -#: judge/models/problem_data.py:34 +#: judge/models/problem_data.py:32 msgid "Custom checker (PY)" msgstr "" -#: judge/models/problem_data.py:35 +#: judge/models/problem_data.py:33 msgid "Custom validator (CPP)" msgstr "" -#: judge/models/problem_data.py:42 +#: judge/models/problem_data.py:40 msgid "data zip file" msgstr "データの zip ファイル" -#: judge/models/problem_data.py:44 +#: judge/models/problem_data.py:42 msgid "generator file" msgstr "ジェネレータファイル" -#: judge/models/problem_data.py:46 judge/models/problem_data.py:121 +#: judge/models/problem_data.py:44 judge/models/problem_data.py:110 msgid "output prefix length" msgstr "出力プレフィクス長" -#: judge/models/problem_data.py:47 judge/models/problem_data.py:122 +#: judge/models/problem_data.py:45 judge/models/problem_data.py:111 msgid "output limit length" msgstr "出力制限長" -#: judge/models/problem_data.py:48 +#: judge/models/problem_data.py:46 msgid "init.yml generation feedback" msgstr "init.yml 生成のフィードバック" -#: judge/models/problem_data.py:49 judge/models/problem_data.py:123 +#: judge/models/problem_data.py:47 judge/models/problem_data.py:112 msgid "checker" msgstr "チェッカー" -#: judge/models/problem_data.py:50 judge/models/problem_data.py:124 +#: judge/models/problem_data.py:48 judge/models/problem_data.py:113 msgid "checker arguments" msgstr "チェッカー引数" -#: judge/models/problem_data.py:51 judge/models/problem_data.py:125 +#: judge/models/problem_data.py:49 judge/models/problem_data.py:114 msgid "checker arguments as a JSON object" msgstr "JSON オブジェクトとしてのチェッカー引数" -#: judge/models/problem_data.py:52 +#: judge/models/problem_data.py:50 msgid "custom checker file" msgstr "" -#: judge/models/problem_data.py:58 +#: judge/models/problem_data.py:56 msgid "custom validator file" msgstr "" -#: judge/models/problem_data.py:108 +#: judge/models/problem_data.py:97 msgid "problem data set" msgstr "課題データセット" -#: judge/models/problem_data.py:110 +#: judge/models/problem_data.py:99 msgid "case position" msgstr "ケースの位置" -#: judge/models/problem_data.py:111 +#: judge/models/problem_data.py:100 msgid "case type" msgstr "ケースのタイプ" -#: judge/models/problem_data.py:112 +#: judge/models/problem_data.py:101 msgid "Normal case" msgstr "標準のケース" -#: judge/models/problem_data.py:113 +#: judge/models/problem_data.py:102 msgid "Batch start" msgstr "バッチ開始" -#: judge/models/problem_data.py:114 +#: judge/models/problem_data.py:103 msgid "Batch end" msgstr "バッチ終了" -#: judge/models/problem_data.py:116 +#: judge/models/problem_data.py:105 msgid "input file name" msgstr "入力ファイル名" -#: judge/models/problem_data.py:117 +#: judge/models/problem_data.py:106 msgid "output file name" msgstr "出力ファイル名" -#: judge/models/problem_data.py:118 +#: judge/models/problem_data.py:107 msgid "generator arguments" msgstr "ジェネレーターの引数" -#: judge/models/problem_data.py:119 +#: judge/models/problem_data.py:108 msgid "point value" msgstr "点数" -#: judge/models/problem_data.py:120 +#: judge/models/problem_data.py:109 msgid "case is pretest?" msgstr "予備テストのケースか?" @@ -1719,7 +1601,7 @@ msgid "" msgstr "" #: judge/models/profile.py:76 judge/models/profile.py:93 -#: judge/models/profile.py:212 +#: judge/models/profile.py:192 msgid "organization" msgstr "組織" @@ -1815,31 +1697,31 @@ msgstr "内部メモ" msgid "Notes for administrators regarding this user." msgstr "" -#: judge/models/profile.py:206 +#: judge/models/profile.py:186 msgid "user profile" msgstr "ユーザープロフィール" -#: judge/models/profile.py:207 +#: judge/models/profile.py:187 msgid "user profiles" msgstr "ユーザープロフィール" -#: judge/models/profile.py:214 +#: judge/models/profile.py:194 msgid "request time" msgstr "要求時刻" -#: judge/models/profile.py:215 +#: judge/models/profile.py:195 msgid "state" msgstr "状態" -#: judge/models/profile.py:220 +#: judge/models/profile.py:200 msgid "reason" msgstr "理由" -#: judge/models/profile.py:223 +#: judge/models/profile.py:203 msgid "organization join request" msgstr "組織への参加要求" -#: judge/models/profile.py:224 +#: judge/models/profile.py:204 msgid "organization join requests" msgstr "組織への参加要求" @@ -1942,88 +1824,88 @@ msgstr "拡張子" msgid "The extension of source files, e.g., \"py\" or \"cpp\"." msgstr "ソースファイルの拡張子、例えば \"py\" や \"cpp\"。" -#: judge/models/runtime.py:112 +#: judge/models/runtime.py:109 msgid "languages" msgstr "言語" -#: judge/models/runtime.py:116 +#: judge/models/runtime.py:113 msgid "language to which this runtime belongs" msgstr "このランタイムが属する言語" -#: judge/models/runtime.py:117 +#: judge/models/runtime.py:114 msgid "judge on which this runtime exists" msgstr "このランタイムが存在する判定器" -#: judge/models/runtime.py:118 +#: judge/models/runtime.py:115 msgid "runtime name" msgstr "ランタイム名" -#: judge/models/runtime.py:119 +#: judge/models/runtime.py:116 msgid "runtime version" msgstr "ランタイムのバージョン" -#: judge/models/runtime.py:120 +#: judge/models/runtime.py:117 msgid "order in which to display this runtime" msgstr "このランタイムを表示する順序" -#: judge/models/runtime.py:124 +#: judge/models/runtime.py:121 msgid "Server name, hostname-style" msgstr "サーバー名、ホスト名形式" -#: judge/models/runtime.py:125 +#: judge/models/runtime.py:122 msgid "time of creation" msgstr "作成日" -#: judge/models/runtime.py:126 +#: judge/models/runtime.py:123 #, fuzzy #| msgid "A key to authenticated this judge" msgid "A key to authenticate this judge" msgstr "この判定器を認証する鍵" -#: judge/models/runtime.py:127 +#: judge/models/runtime.py:124 msgid "authentication key" msgstr "認証鍵" -#: judge/models/runtime.py:128 +#: judge/models/runtime.py:125 msgid "block judge" msgstr "" -#: judge/models/runtime.py:129 +#: judge/models/runtime.py:126 msgid "" "Whether this judge should be blocked from connecting, even if its key is " "correct." msgstr "" -#: judge/models/runtime.py:131 +#: judge/models/runtime.py:128 msgid "judge online status" msgstr "判定器のオンライン状態" -#: judge/models/runtime.py:132 +#: judge/models/runtime.py:129 msgid "judge start time" msgstr "判定器の開始時刻" -#: judge/models/runtime.py:133 +#: judge/models/runtime.py:130 msgid "response time" msgstr "応答時間" -#: judge/models/runtime.py:134 +#: judge/models/runtime.py:131 msgid "system load" msgstr "システム負荷" -#: judge/models/runtime.py:135 +#: judge/models/runtime.py:132 msgid "Load for the last minute, divided by processors to be fair." msgstr "最近1分の負荷、公平のためプロセッサ数で割ってある。" -#: judge/models/runtime.py:139 judge/models/runtime.py:179 +#: judge/models/runtime.py:136 judge/models/runtime.py:176 msgid "judges" msgstr "判定器" -#: judge/models/runtime.py:178 +#: judge/models/runtime.py:175 msgid "judge" msgstr "判定器" #: judge/models/submission.py:20 judge/models/submission.py:47 -#: judge/utils/problems.py:79 +#: judge/utils/problems.py:77 msgid "Accepted" msgstr "合格した" @@ -2052,7 +1934,7 @@ msgid "Runtime Error" msgstr "ランタイムエラー" #: judge/models/submission.py:27 judge/models/submission.py:41 -#: judge/models/submission.py:55 judge/utils/problems.py:81 +#: judge/models/submission.py:55 judge/utils/problems.py:79 msgid "Compile Error" msgstr "コンパイル エラー" @@ -2093,15 +1975,15 @@ msgstr "内部エラー(判定サーバエラー)" msgid "submission time" msgstr "提出時刻" -#: judge/models/submission.py:67 judge/models/submission.py:203 +#: judge/models/submission.py:67 judge/models/submission.py:201 msgid "execution time" msgstr "実行時間" -#: judge/models/submission.py:68 judge/models/submission.py:204 +#: judge/models/submission.py:68 judge/models/submission.py:202 msgid "memory usage" msgstr "メモリ使用量" -#: judge/models/submission.py:69 judge/models/submission.py:205 +#: judge/models/submission.py:69 judge/models/submission.py:203 msgid "points granted" msgstr "付与された点数" @@ -2138,64 +2020,58 @@ msgid "judged on" msgstr "判定された" #: judge/models/submission.py:81 -#, fuzzy -#| msgid "submission time" -msgid "submission judge time" -msgstr "提出時刻" - -#: judge/models/submission.py:82 msgid "was rejudged by admin" msgstr "管理者により再判定された" -#: judge/models/submission.py:83 +#: judge/models/submission.py:82 msgid "was ran on pretests only" msgstr "予備テストのみ実行された" -#: judge/models/submission.py:184 templates/contest/moss.html:58 +#: judge/models/submission.py:182 templates/contest/moss.html:58 msgid "submissions" msgstr "提出" -#: judge/models/submission.py:188 judge/models/submission.py:199 +#: judge/models/submission.py:186 judge/models/submission.py:197 msgid "associated submission" msgstr "関連する提出物" -#: judge/models/submission.py:190 +#: judge/models/submission.py:188 msgid "source code" msgstr "ソースコード" -#: judge/models/submission.py:201 +#: judge/models/submission.py:199 msgid "test case ID" msgstr "テストケースの ID" -#: judge/models/submission.py:202 +#: judge/models/submission.py:200 msgid "status flag" msgstr "状態フラグ" -#: judge/models/submission.py:206 +#: judge/models/submission.py:204 msgid "points possible" msgstr "可能な点数" -#: judge/models/submission.py:207 +#: judge/models/submission.py:205 msgid "batch number" msgstr "バッチ番号" -#: judge/models/submission.py:208 +#: judge/models/submission.py:206 msgid "judging feedback" msgstr "判定のフィードバック" -#: judge/models/submission.py:209 +#: judge/models/submission.py:207 msgid "extended judging feedback" msgstr "" -#: judge/models/submission.py:210 +#: judge/models/submission.py:208 msgid "program output" msgstr "プログラムの出力" -#: judge/models/submission.py:218 +#: judge/models/submission.py:216 msgid "submission test case" msgstr "提出テストケース" -#: judge/models/submission.py:219 +#: judge/models/submission.py:217 msgid "submission test cases" msgstr "提出テストケース" @@ -2247,24 +2123,12 @@ msgstr "投稿者" msgid "message time" msgstr "メッセージの時刻" -#: judge/pdf_problems.py:147 judge/pdf_problems.py:199 -#: judge/pdf_problems.py:259 +#: judge/pdf_problems.py:134 judge/pdf_problems.py:186 +#: judge/pdf_problems.py:246 msgid "Page [page] of [topage]" msgstr "ページ [page] / [topage]" -#: judge/pdf_problems.py:280 -#, fuzzy, python-format -#| msgid "Page %d of Posts" -msgid "Page %s of %s" -msgstr "投稿のページ %d" - -#: judge/tasks/contest.py:19 -#, fuzzy -#| msgid "Recalculate scores" -msgid "Recalculating contest scores" -msgstr "得点を再計算する" - -#: judge/tasks/contest.py:40 +#: judge/tasks/moss.py:25 msgid "Running MOSS" msgstr "" @@ -2276,62 +2140,62 @@ msgstr "" msgid "Recalculating user points" msgstr "" -#: judge/utils/problem_data.py:70 +#: judge/utils/problem_data.py:68 msgid "Empty batches not allowed." msgstr "空のバッチは、許可されていません。" -#: judge/utils/problem_data.py:78 judge/utils/problem_data.py:99 +#: judge/utils/problem_data.py:76 judge/utils/problem_data.py:97 #, fuzzy #| msgid "How did you corrupt the generator path?" msgid "How did you corrupt the custom checker path?" msgstr "どのようにあなたがジェネレータのパスを破損したか?" -#: judge/utils/problem_data.py:120 +#: judge/utils/problem_data.py:118 #, python-format msgid "Points must be defined for non-batch case #%d." msgstr "非バッチケース #%d のために点数が定義されなければなりません。" -#: judge/utils/problem_data.py:125 +#: judge/utils/problem_data.py:123 #, python-format msgid "Input file for case %d does not exist: %s" msgstr "ケース %d の入力ファイルが存在しません: %s" -#: judge/utils/problem_data.py:128 +#: judge/utils/problem_data.py:126 #, python-format msgid "Output file for case %d does not exist: %s" msgstr "ケース %d の出力ファイルが存在しません: %s" -#: judge/utils/problem_data.py:153 +#: judge/utils/problem_data.py:151 #, python-format msgid "Batch start case #%d requires points." msgstr "ケース #%d のバッチ開始には点数が必要です。" -#: judge/utils/problem_data.py:174 +#: judge/utils/problem_data.py:172 #, python-format msgid "Attempt to end batch outside of one in case #%d" msgstr "ケース #%d の外でバッチの終了を試みる。" -#: judge/utils/problem_data.py:192 +#: judge/utils/problem_data.py:190 msgid "How did you corrupt the zip path?" msgstr "どのようにあなたが zip パスを破損したか?" -#: judge/utils/problem_data.py:198 +#: judge/utils/problem_data.py:196 msgid "How did you corrupt the generator path?" msgstr "どのようにあなたがジェネレータのパスを破損したか?" -#: judge/utils/problems.py:80 +#: judge/utils/problems.py:78 msgid "Wrong" msgstr "" -#: judge/utils/problems.py:82 +#: judge/utils/problems.py:80 msgid "Timeout" msgstr "" -#: judge/utils/problems.py:83 +#: judge/utils/problems.py:81 msgid "Error" msgstr "" -#: judge/utils/problems.py:94 +#: judge/utils/problems.py:92 msgid "Can't pass both queryset and keyword filters" msgstr "問合せセットと絞り込みキーワードの両方は渡せません。" @@ -2371,8 +2235,7 @@ msgctxt "hours and minutes" msgid "%h:%m" msgstr "%h:%m" -#: judge/views/about.py:7 templates/organization/home.html:112 -#: templates/user/user-about.html:83 templates/user/user-tabs.html:4 +#: judge/views/about.py:7 templates/user/user-about.html:33 msgid "About" msgstr "サイトについて" @@ -2380,167 +2243,157 @@ msgstr "サイトについて" msgid "Custom Checker Sample" msgstr "" -#: judge/views/blog.py:45 +#: judge/views/blog.py:38 #, python-format msgid "Page %d of Posts" msgstr "投稿のページ %d" -#: judge/views/comment.py:28 +#: judge/views/comment.py:27 msgid "Messing around, are we?" msgstr "私たちはめちゃくちゃですか?" -#: judge/views/comment.py:37 +#: judge/views/comment.py:36 msgid "You must solve at least one problem before you can vote." msgstr "" -#: judge/views/comment.py:64 +#: judge/views/comment.py:63 msgid "You already voted." msgstr "あなたは既に投票しました。" -#: judge/views/comment.py:126 judge/views/organization.py:344 +#: judge/views/comment.py:120 judge/views/organization.py:299 msgid "Edited from site" msgstr "サイトから編集された" -#: judge/views/comment.py:147 +#: judge/views/comment.py:141 msgid "Editing comment" msgstr "コメントの編集" -#: judge/views/contests.py:57 judge/views/contests.py:247 -#: judge/views/contests.py:250 judge/views/contests.py:424 +#: judge/views/contests.py:55 judge/views/contests.py:215 +#: judge/views/contests.py:218 judge/views/contests.py:389 msgid "No such contest" msgstr "そのようなコンテストはありません" -#: judge/views/contests.py:58 judge/views/contests.py:248 +#: judge/views/contests.py:56 judge/views/contests.py:216 #, python-format msgid "Could not find a contest with the key \"%s\"." msgstr "鍵 \"%s\" を持つコンテストは見つかりませんでした。" -#: judge/views/contests.py:71 +#: judge/views/contests.py:81 msgid "Contests" msgstr "コンテスト" -#: judge/views/contests.py:251 +#: judge/views/contests.py:219 msgid "Could not find such contest." msgstr "このようなコンテストは見つかりませんでした。" -#: judge/views/contests.py:254 +#: judge/views/contests.py:222 #, python-format msgid "Access to contest \"%s\" denied" msgstr "コンテスト \"%s\" へのアクセスは拒否されました" -#: judge/views/contests.py:278 +#: judge/views/contests.py:246 msgid "Clone Contest" msgstr "" -#: judge/views/contests.py:343 +#: judge/views/contests.py:309 msgid "Contest not ongoing" msgstr "開催中ではないコンテスト" -#: judge/views/contests.py:344 +#: judge/views/contests.py:310 #, python-format msgid "\"%s\" is not currently ongoing." msgstr "\"%s\" は現在開催中ではありません。" -#: judge/views/contests.py:348 +#: judge/views/contests.py:314 msgid "Already in contest" msgstr "既にコンテストに参加しています" -#: judge/views/contests.py:349 +#: judge/views/contests.py:315 #, python-format msgid "You are already in a contest: \"%s\"." msgstr "あなたは既にコンテストに参加しています: \"%s\"。" -#: judge/views/contests.py:352 +#: judge/views/contests.py:318 msgid "Banned from joining" msgstr "" -#: judge/views/contests.py:353 +#: judge/views/contests.py:319 msgid "" "You have been declared persona non grata for this contest. You are " "permanently barred from joining this contest." msgstr "" -#: judge/views/contests.py:414 +#: judge/views/contests.py:379 #, python-format msgid "Enter access code for \"%s\"" msgstr "\"%s\" のアクセスコードを入力してください" -#: judge/views/contests.py:425 +#: judge/views/contests.py:390 #, python-format msgid "You are not in contest \"%s\"." msgstr "あなたはコンテストに参加していません: \"%s\"。" -#: judge/views/contests.py:444 +#: judge/views/contests.py:409 msgid "ContestCalendar requires integer year and month" msgstr "" -#: judge/views/contests.py:484 +#: judge/views/contests.py:449 #, python-format msgid "Contests in %(month)s" msgstr "%(month)s 年のコンテスト" -#: judge/views/contests.py:484 +#: judge/views/contests.py:449 msgid "F Y" msgstr "" -#: judge/views/contests.py:532 +#: judge/views/contests.py:496 #, fuzzy, python-format #| msgid "Statistics" msgid "%s Statistics" msgstr "統計" -#: judge/views/contests.py:717 +#: judge/views/contests.py:601 +msgid "???" +msgstr "???" + +#: judge/views/contests.py:664 #, python-format msgid "%s Rankings" msgstr "%s 順位表" -#: judge/views/contests.py:725 -msgid "???" -msgstr "???" - -#: judge/views/contests.py:741 +#: judge/views/contests.py:680 #, python-format msgid "Your participation in %s" msgstr "あなたの %s への参加" -#: judge/views/contests.py:742 +#: judge/views/contests.py:681 #, python-format msgid "%s's participation in %s" msgstr "%s の %s への参加" -#: judge/views/contests.py:749 +#: judge/views/contests.py:685 msgid "Live" msgstr "ライブ" -#: judge/views/contests.py:761 templates/contest/contest-tabs.html:13 +#: judge/views/contests.py:697 msgid "Participation" msgstr "参加" -#: judge/views/contests.py:808 +#: judge/views/contests.py:743 #, python-format msgid "%s MOSS Results" msgstr "" -#: judge/views/contests.py:835 +#: judge/views/contests.py:770 #, python-format msgid "Running MOSS for %s..." msgstr "" -#: judge/views/contests.py:858 +#: judge/views/contests.py:793 #, python-format msgid "Contest tag: %s" msgstr "コンテストタグ: %s" -#: judge/views/contests.py:868 judge/views/ticket.py:57 -msgid "Issue description" -msgstr "問題の説明" - -#: judge/views/contests.py:911 -#, fuzzy, python-format -#| msgid "clarification body" -msgid "New clarification for %s" -msgstr "解説本文" - #: judge/views/error.py:14 msgid "404 error" msgstr "404エラー" @@ -2561,76 +2414,69 @@ msgid "corrupt page %s" msgstr "破損ページ %s" #: judge/views/language.py:12 templates/status/judge-status-table.html:9 -#: templates/status/status-tabs.html:5 msgid "Runtimes" msgstr "ランタイム" -#: judge/views/notification.py:40 -#, python-format -msgid "Notifications (%d unseen)" -msgstr "" - -#: judge/views/organization.py:59 judge/views/organization.py:62 +#: judge/views/organization.py:44 judge/views/organization.py:47 msgid "No such organization" msgstr "このような組織はありません" -#: judge/views/organization.py:60 +#: judge/views/organization.py:45 #, python-format msgid "Could not find an organization with the key \"%s\"." msgstr "鍵 \"%s\" を持つ組織は見つかりませんでした。" -#: judge/views/organization.py:63 +#: judge/views/organization.py:48 msgid "Could not find such organization." msgstr "このような組織を見つけることができませんでした。" -#: judge/views/organization.py:79 judge/views/register.py:34 -#: templates/organization/list.html:32 templates/user/import/table_csv.html:9 -#: templates/user/user-list-tabs.html:6 +#: judge/views/organization.py:72 judge/views/register.py:34 +#: templates/organization/list.html:15 msgid "Organizations" msgstr "組織" -#: judge/views/organization.py:130 +#: judge/views/organization.py:93 #, python-format msgid "%s Members" msgstr "%s のメンバー" -#: judge/views/organization.py:159 judge/views/organization.py:162 -#: judge/views/organization.py:167 +#: judge/views/organization.py:118 judge/views/organization.py:121 +#: judge/views/organization.py:126 msgid "Joining organization" msgstr "所属している組織" -#: judge/views/organization.py:159 +#: judge/views/organization.py:118 msgid "You are already in the organization." msgstr "あなたは、既にこの組織にしょぞくしています。" -#: judge/views/organization.py:162 +#: judge/views/organization.py:121 msgid "This organization is not open." msgstr "この組織は公開ではありません。" -#: judge/views/organization.py:179 +#: judge/views/organization.py:138 msgid "Leaving organization" msgstr "組織から脱退する" -#: judge/views/organization.py:179 +#: judge/views/organization.py:138 #, python-format msgid "You are not in \"%s\"." msgstr "あなたは \"%s\" に所属していません。" -#: judge/views/organization.py:203 +#: judge/views/organization.py:162 #, python-format msgid "Request to join %s" msgstr "%s への参加を申し込む" -#: judge/views/organization.py:221 +#: judge/views/organization.py:180 msgid "Join request detail" msgstr "参加申込みの詳細" -#: judge/views/organization.py:254 +#: judge/views/organization.py:209 #, python-format msgid "Managing join requests for %s" msgstr "%s への参加申込みを管理する" -#: judge/views/organization.py:285 +#: judge/views/organization.py:240 #, python-format msgid "" "Your organization can only receive %d more members. You cannot approve %d " @@ -2639,44 +2485,44 @@ msgstr "" "あなたの組織はあと %d 人のメンバーしか受け入れられません。あなたは %d 人の利" "用者を承認できません。" -#: judge/views/organization.py:297 +#: judge/views/organization.py:252 #, python-format msgid "Approved %d user." msgid_plural "Approved %d users." msgstr[0] "%d 人の利用者を承認しました。" -#: judge/views/organization.py:298 +#: judge/views/organization.py:253 #, python-format msgid "Rejected %d user." msgid_plural "Rejected %d users." msgstr[0] "%d 人の利用者を拒否しました。" -#: judge/views/organization.py:328 +#: judge/views/organization.py:283 #, python-format msgid "Editing %s" msgstr "%s を編集" -#: judge/views/organization.py:352 judge/views/organization.py:360 +#: judge/views/organization.py:307 judge/views/organization.py:315 msgid "Can't edit organization" msgstr "組織を編集できません" -#: judge/views/organization.py:353 +#: judge/views/organization.py:308 msgid "You are not allowed to edit this organization." msgstr "あなたは、この組織を編集することは許可されていません。" -#: judge/views/organization.py:361 +#: judge/views/organization.py:316 msgid "You are not allowed to kick people from this organization." msgstr "あなたはこの組織から人を追い出すことを許可されていません。" -#: judge/views/organization.py:366 judge/views/organization.py:370 +#: judge/views/organization.py:321 judge/views/organization.py:325 msgid "Can't kick user" msgstr "利用者を追い出せません" -#: judge/views/organization.py:367 +#: judge/views/organization.py:322 msgid "The user you are trying to kick does not exist!" msgstr "あなたが追い出そうとしている利用者は存在しません!" -#: judge/views/organization.py:371 +#: judge/views/organization.py:326 #, python-format msgid "The user you are trying to kick is not in organization: %s." msgstr "あなたが追い出そうとしているユーザは組織内にいません: %s 。" @@ -2700,17 +2546,16 @@ msgstr "{0} の論説" msgid "Editorial for {0}" msgstr "{0} の論説" -#: judge/views/problem.py:285 templates/contest/contest.html:79 -#: templates/user/user-about.html:28 templates/user/user-tabs.html:5 -#: templates/user/users-table.html:31 +#: judge/views/problem.py:286 templates/contest/contest.html:79 +#: templates/user/users-table.html:23 msgid "Problems" msgstr "課題" -#: judge/views/problem.py:585 +#: judge/views/problem.py:547 msgid "Banned from submitting" msgstr "提出が禁止された" -#: judge/views/problem.py:586 +#: judge/views/problem.py:548 msgid "" "You have been declared persona non grata for this problem. You are " "permanently barred from submitting this problem." @@ -2718,20 +2563,20 @@ msgstr "" "あなたはこの課題に感謝しない人として宣言されている。あなたはこの課題に提出す" "ることを永続的に禁止されている。" -#: judge/views/problem.py:600 +#: judge/views/problem.py:562 msgid "Too many submissions" msgstr "提出物が多過ぎます" -#: judge/views/problem.py:601 +#: judge/views/problem.py:563 msgid "You have exceeded the submission limit for this problem." msgstr "あなたは、この課題の提出制限を超えました" -#: judge/views/problem.py:661 judge/views/problem.py:664 +#: judge/views/problem.py:633 judge/views/problem.py:636 #, python-format msgid "Submit to %(problem)s" msgstr "%(problem)s に提出する" -#: judge/views/problem.py:679 +#: judge/views/problem.py:652 msgid "Clone Problem" msgstr "" @@ -2772,22 +2617,22 @@ msgstr "%s のデータの編集" msgid "Generated init.yml for %s" msgstr "%s への生成された init.yml" -#: judge/views/problem_manage.py:52 judge/views/problem_manage.py:55 +#: judge/views/problem_manage.py:50 judge/views/problem_manage.py:53 #, python-format msgid "Managing submissions for %s" msgstr "" -#: judge/views/problem_manage.py:97 +#: judge/views/problem_manage.py:95 #, python-format msgid "Rejudging selected submissions for %s..." msgstr "" -#: judge/views/problem_manage.py:141 +#: judge/views/problem_manage.py:110 #, python-format msgid "Rescoring all submissions for %s..." msgstr "" -#: judge/views/problem_manage.py:150 +#: judge/views/problem_manage.py:119 #, python-format msgid "Successfully scheduled %d submission for rejudging." msgid_plural "Successfully scheduled %d submissions for rejudging." @@ -2835,7 +2680,7 @@ msgstr "好みの言語" msgid "Subscribe to newsletter?" msgstr "ニュースレターを購読しますか?" -#: judge/views/register.py:55 +#: judge/views/register.py:45 #, python-format msgid "" "The email address \"%s\" is already taken. Only one registration is allowed " @@ -2844,7 +2689,7 @@ msgstr "" "電子メールアドレス \"%s\" は既に使用されています。1アドレスにつき1登録だけが" "許されています。" -#: judge/views/register.py:61 +#: judge/views/register.py:51 msgid "" "Your email provider is not allowed due to history of abuse. Please use a " "reputable email provider." @@ -2852,11 +2697,11 @@ msgstr "" "あなたの電子メールプロバイダは不正利用の履歴のため許可されていません。信頼で" "きる電子メールプロバイダを利用してください。" -#: judge/views/register.py:67 judge/views/register.py:105 +#: judge/views/register.py:57 judge/views/register.py:95 msgid "Registration" msgstr "登録" -#: judge/views/register.py:116 +#: judge/views/register.py:106 msgid "Authentication failure" msgstr "認証の失敗" @@ -2872,49 +2717,49 @@ msgstr "状態" msgid "Version matrix" msgstr "バージョンマトリックス" -#: judge/views/submission.py:84 judge/views/submission.py:91 +#: judge/views/submission.py:83 judge/views/submission.py:90 #, python-format msgid "Submission of %(problem)s by %(user)s" msgstr "%(user)s による %(problem)s への提出物" -#: judge/views/submission.py:244 judge/views/submission.py:245 -#: templates/problem/problem.html:167 +#: judge/views/submission.py:227 judge/views/submission.py:228 +#: templates/problem/problem.html:127 msgid "All submissions" msgstr "全ての提出物" -#: judge/views/submission.py:404 +#: judge/views/submission.py:384 msgid "All my submissions" msgstr "私の全ての提出物" -#: judge/views/submission.py:405 +#: judge/views/submission.py:385 #, python-format msgid "All submissions by %s" msgstr "%s による全ての提出物" -#: judge/views/submission.py:436 +#: judge/views/submission.py:416 #, python-format msgid "All submissions for %s" msgstr "%s への全ての提出物" -#: judge/views/submission.py:455 +#: judge/views/submission.py:435 msgid "Must pass a problem" msgstr "課題を通過しなければなりません" -#: judge/views/submission.py:501 +#: judge/views/submission.py:481 #, python-format msgid "My submissions for %(problem)s" msgstr "%(problem)s への私の提出物" -#: judge/views/submission.py:502 +#: judge/views/submission.py:482 #, python-format msgid "%(user)s's submissions for %(problem)s" msgstr "%(problem)s への %(user)s による提出物" -#: judge/views/submission.py:603 +#: judge/views/submission.py:583 msgid "Must pass a contest" msgstr "コンテストを通過しなければなりません" -#: judge/views/submission.py:622 +#: judge/views/submission.py:602 #, python-brace-format msgid "" "{0}'s submissions for {2} in {4} 中の {2} への {0}" " による提出物" -#: judge/views/submission.py:629 +#: judge/views/submission.py:609 #, python-brace-format msgid "" "{0}'s submissions for problem {2} in {3}" @@ -2932,44 +2777,48 @@ msgstr "" "{3} 中の課題 {2} への {0} による提出" "物" -#: judge/views/ticket.py:50 judge/views/ticket.py:56 +#: judge/views/ticket.py:33 judge/views/ticket.py:39 msgid "Ticket title" msgstr "チケットの題目" -#: judge/views/ticket.py:107 judge/views/ticket.py:110 +#: judge/views/ticket.py:40 +msgid "Issue description" +msgstr "問題の説明" + +#: judge/views/ticket.py:85 judge/views/ticket.py:88 #, python-format msgid "New ticket for %s" msgstr "%s への新しいチケット" -#: judge/views/ticket.py:170 +#: judge/views/ticket.py:142 #, python-format msgid "%(title)s - Ticket %(id)d" msgstr "%(title)s - チケット %(id)d" -#: judge/views/ticket.py:279 +#: judge/views/ticket.py:251 #, python-format msgid "Tickets - Page %(number)d of %(total)d" msgstr "チケットのページ %(number)d / %(total)d" -#: judge/views/ticket.py:328 +#: judge/views/ticket.py:300 #, python-format msgid "New Ticket: %s" msgstr "新しいチケット: %s" -#: judge/views/ticket.py:329 +#: judge/views/ticket.py:301 #, python-format msgid "#%(id)d, assigned to: %(users)s" msgstr "#%(id)d, %(users)s に割り当てられた" -#: judge/views/ticket.py:331 +#: judge/views/ticket.py:303 msgid ", " msgstr "、" -#: judge/views/ticket.py:331 +#: judge/views/ticket.py:303 msgid "no one" msgstr "誰もいません" -#: judge/views/ticket.py:351 +#: judge/views/ticket.py:323 #, fuzzy, python-format #| msgid "New Ticket: %s" msgid "New Ticket Message For: %s" @@ -2987,52 +2836,41 @@ msgstr "" msgid "Perform Two Factor Authentication" msgstr "" -#: judge/views/user.py:74 +#: judge/views/user.py:68 msgid "No such user" msgstr "そのような利用者はいません" -#: judge/views/user.py:74 +#: judge/views/user.py:68 #, python-format msgid "No user handle \"%s\"." msgstr "利用者ハンドル \"%s\" はありません。" -#: judge/views/user.py:78 +#: judge/views/user.py:72 msgid "My account" msgstr "自分のアカウント" -#: judge/views/user.py:79 +#: judge/views/user.py:73 #, python-format msgid "User %s" msgstr "利用者 %s" -#: judge/views/user.py:148 -#, fuzzy -#| msgid "M j, Y, G:i" -msgid "M j, Y" -msgstr "M j, Y, G:i" - -#: judge/views/user.py:171 +#: judge/views/user.py:136 msgid "M j, Y, G:i" msgstr "M j, Y, G:i" -#: judge/views/user.py:290 +#: judge/views/user.py:221 msgid "Updated on site" msgstr "サイトで更新された" -#: judge/views/user.py:323 templates/admin/auth/user/change_form.html:14 -#: templates/admin/auth/user/change_form.html:17 templates/base.html:238 -#: templates/user/user-tabs.html:10 +#: judge/views/user.py:254 templates/admin/auth/user/change_form.html:14 +#: templates/admin/auth/user/change_form.html:17 templates/base.html:224 msgid "Edit profile" msgstr "プロフィールを編集する" -#: judge/views/user.py:332 templates/user/user-list-tabs.html:4 +#: judge/views/user.py:263 msgid "Leaderboard" msgstr "リーダーボード" -#: judge/views/user.py:407 -msgid "Import Users" -msgstr "" - #: judge/views/widgets.py:48 judge/views/widgets.py:58 #, python-format msgid "Invalid upstream data: %s" @@ -3070,7 +2908,7 @@ msgid "View Submissions" msgstr "" #: templates/admin/judge/problem/change_form.html:17 -#: templates/user/user-base.html:112 +#: templates/user/user-base.html:61 msgid "View submissions" msgstr "提出物を表示する" @@ -3085,157 +2923,92 @@ msgstr "利用者を編集する" msgid "Rejudge" msgstr "再判定" -#: templates/base.html:230 -#, python-format -msgid "Hello, %(username)s." -msgstr "こんにちは、%(username)s。" - -#: templates/base.html:236 templates/comments/list.html:89 -#: templates/contest/contest-list-tabs.html:24 -#: templates/contest/ranking-table.html:53 -#: templates/problem/problem-list-tabs.html:6 +#: templates/base.html:222 templates/comments/list.html:89 +#: templates/contest/ranking-table.html:39 #: templates/submission/info-base.html:12 -#: templates/submission/submission-list-tabs.html:15 msgid "Admin" msgstr "管理" -#: templates/base.html:245 +#: templates/base.html:231 msgid "Log out" msgstr "ログアウト" -#: templates/base.html:254 +#: templates/base.html:240 #: templates/registration/password_reset_complete.html:4 msgid "Log in" msgstr "ログイン" -#: templates/base.html:255 templates/registration/registration_form.html:177 +#: templates/base.html:241 templates/registration/registration_form.html:177 msgid "or" msgstr "または" -#: templates/base.html:256 +#: templates/base.html:242 msgid "Sign up" msgstr "" -#: templates/base.html:271 +#: templates/base.html:254 msgid "spectating" msgstr "観戦中" -#: templates/base.html:284 +#: templates/base.html:267 msgid "This site works best with JavaScript enabled." msgstr "このサイトはJavaScriptを有効にすると最適に動作します。" -#: templates/blog/blog.html:13 templates/comments/list.html:68 -#: templates/comments/list.html:83 templates/contest/contest-tabs.html:23 -#: templates/contest/tag-title.html:9 templates/flatpages/admin_link.html:3 -#: templates/license.html:10 templates/problem/editorial.html:14 +#: templates/blog/content.html:13 templates/comments/list.html:68 +#: templates/comments/list.html:83 templates/contest/tag-title.html:9 +#: templates/flatpages/admin_link.html:3 templates/license.html:10 +#: templates/problem/editorial.html:14 msgid "Edit" msgstr "編集" -#: templates/blog/blog.html:26 -#, python-format -msgid "" -"\n" -" posted on %(time)s\n" -" " -msgstr "" -"\n" -" %(time)s に投稿された \n" -" " - -#: templates/blog/content.html:10 -#, python-brace-format -msgid "posted on {time}" -msgstr "{time} に投稿された" - -#: templates/blog/dashboard.html:21 -#, python-format -msgid "" -"\n" -" on %(time)s\n" -" " -msgstr "" -"\n" -" %(time)s にて \n" -" " - -#: templates/blog/list.html:93 +#: templates/blog/list.html:85 msgid "Blog" msgstr "ブログ" -#: templates/blog/list.html:95 +#: templates/blog/list.html:87 msgid "Events" msgstr "イベント" -#: templates/blog/list.html:100 +#: templates/blog/list.html:92 msgid "News" msgstr "お知らせ" -#: templates/blog/list.html:115 templates/problem/list.html:347 -#: templates/problem/problem.html:361 +#: templates/blog/list.html:130 templates/problem/problem.html:310 msgid "Clarifications" msgstr "解説" -#: templates/blog/list.html:121 -msgid "Add" -msgstr "" - -#: templates/blog/list.html:140 templates/problem/list.html:369 -#: templates/problem/problem.html:372 +#: templates/blog/list.html:146 templates/problem/problem.html:321 msgid "No clarifications have been made at this time." msgstr "現時点では何も解説されていません。" -#: templates/blog/list.html:148 +#: templates/blog/list.html:154 msgid "Ongoing contests" msgstr "開催中のコンテスト" -#: templates/blog/list.html:166 +#: templates/blog/list.html:172 msgid "Upcoming contests" msgstr "近日開催予定のコンテスト" -#: templates/blog/list.html:184 -msgid "My open tickets" -msgstr "私のオープンチケット" - -#: templates/blog/list.html:206 -msgid "New tickets" -msgstr "新しいチケット" - -#: templates/blog/list.html:227 -msgid "New problems" -msgstr "新しい課題" - -#: templates/blog/list.html:244 +#: templates/blog/list.html:189 msgid "Comment stream" msgstr "コメントストリーム" -#: templates/chat/chat.html:305 -msgid "Chat" +#: templates/blog/list.html:208 +msgid "New problems" +msgstr "新しい課題" + +#: templates/blog/list.html:225 +msgid "My open tickets" +msgstr "私のオープンチケット" + +#: templates/blog/list.html:246 +msgid "New tickets" +msgstr "新しいチケット" + +#: templates/chat/chat.html:167 +msgid "Your message" msgstr "" -#: templates/chat/chat.html:307 templates/chat/chat.html:314 -#, fuzzy -#| msgid "Online Judge" -msgid "Online Users" -msgstr "オンライン判定" - -#: templates/chat/chat.html:315 -msgid "Refresh" -msgstr "" - -#: templates/chat/chat.html:333 -msgid "Emoji" -msgstr "" - -#: templates/chat/chat.html:334 -msgid "Enter your message" -msgstr "" - -#: templates/chat/message.html:20 -#, fuzzy -#| msgid "Delete?" -msgid "Delete" -msgstr "削除しますか?" - #: templates/comments/list.html:2 msgid "Comments" msgstr "コメント" @@ -3244,21 +3017,11 @@ msgstr "コメント" msgid "Please login to vote" msgstr "投票するにはログインしてください" -#: templates/comments/list.html:40 -#, python-brace-format -msgid "commented on {time}" -msgstr "{time} にコメントされた" - -#: templates/comments/list.html:49 -#, python-format -msgid "edit %(edits)s" -msgstr "%(edits)s を編集する" - -#: templates/comments/list.html:51 templates/comments/media-js.html:92 +#: templates/comments/list.html:51 templates/comments/media-js.html:77 msgid "edited" msgstr "編集された" -#: templates/comments/list.html:60 templates/notification/list.html:14 +#: templates/comments/list.html:60 msgid "Link" msgstr "リンク" @@ -3266,54 +3029,36 @@ msgstr "リンク" msgid "Reply" msgstr "返信" -#: templates/comments/list.html:86 templates/contest/list.html:91 -#: templates/contest/list.html:95 templates/contest/list.html:280 +#: templates/comments/list.html:86 msgid "Hide" msgstr "非表示" -#: templates/comments/list.html:101 -#, python-format -msgid "" -"\n" -" This comment is hidden due " -"to too much negative feedback.\n" -" Click here to view it.\n" -" " -msgstr "" - -#: templates/comments/list.html:121 +#: templates/comments/list.html:120 msgid "There are no comments at the moment." msgstr "現時点でコメントはありません。" -#: templates/comments/list.html:127 +#: templates/comments/list.html:126 msgid "New comment" msgstr "新しいコメント" -#: templates/comments/list.html:141 +#: templates/comments/list.html:140 msgid "Invalid comment body." msgstr "不正なコメント本文。" -#: templates/comments/list.html:149 +#: templates/comments/list.html:148 msgid "Post!" msgstr "投稿!" -#: templates/comments/list.html:157 +#: templates/comments/list.html:156 msgid "Comments are disabled on this page." msgstr "" -#: templates/comments/media-js.html:38 -#, fuzzy -#| msgid "no comments" -msgid "Replying to comment" -msgstr "コメントがありません" - -#: templates/comments/media-js.html:87 +#: templates/comments/media-js.html:72 #, python-brace-format msgid "edit {edits}" msgstr "{edits} を編集する" -#: templates/comments/media-js.html:90 +#: templates/comments/media-js.html:75 msgid "original" msgstr "オリジナル" @@ -3357,11 +3102,6 @@ msgstr "金曜日" msgid "Saturday" msgstr "土曜日" -#: templates/contest/clarification.html:52 templates/organization/new.html:10 -#: templates/ticket/new.html:38 -msgid "Create" -msgstr "作成" - #: templates/contest/clone.html:37 msgid "Enter a new key for the cloned contest:" msgstr "" @@ -3382,110 +3122,50 @@ msgstr "" msgid "Next" msgstr "次へ" -#: templates/contest/contest-list-tabs.html:21 -#: templates/problem/problem-list-tabs.html:5 -msgid "List" -msgstr "一覧" - -#: templates/contest/contest-list-tabs.html:22 -msgid "Calendar" -msgstr "カレンダー" - -#: templates/contest/contest-tabs.html:4 templates/organization/home.html:105 -msgid "Info" -msgstr "情報" - -#: templates/contest/contest-tabs.html:6 templates/stats/base.html:9 -#: templates/submission/list.html:339 -msgid "Statistics" -msgstr "統計" - -#: templates/contest/contest-tabs.html:11 -msgid "Rankings" -msgstr "順位表" - -#: templates/contest/contest-tabs.html:16 -msgid "Hidden Rankings" -msgstr "非表示の順位表" - -#: templates/contest/contest-tabs.html:21 -msgid "MOSS" -msgstr "" - -#: templates/contest/contest-tabs.html:26 -msgid "Clone" -msgstr "" - -#: templates/contest/contest-tabs.html:38 -#: templates/contest/contest-tabs.html:58 +#: templates/contest/contest-tabs.html:37 msgid "Leave contest" msgstr "コンテストから脱退する" -#: templates/contest/contest-tabs.html:45 templates/contest/list.html:388 +#: templates/contest/contest-tabs.html:44 templates/contest/list.html:293 msgid "Virtual join" msgstr "仮想参加" -#: templates/contest/contest-tabs.html:56 -msgid "Stop spectating" -msgstr "観戦を停止する" - -#: templates/contest/contest-tabs.html:65 +#: templates/contest/contest-tabs.html:64 msgid "Spectate contest" msgstr "コンテストを観戦する" -#: templates/contest/contest-tabs.html:72 +#: templates/contest/contest-tabs.html:70 +#: templates/contest/contest-tabs.html:76 msgid "Join contest" msgstr "コンテストに参加する" -#: templates/contest/contest-tabs.html:81 +#: templates/contest/contest-tabs.html:85 msgid "Login to participate" msgstr "参加するためにログインする" -#: templates/contest/contest.html:37 -msgid "Participating virtually." -msgstr "仮想的に参加している" - -#: templates/contest/contest.html:43 -msgid "Contest is over." -msgstr "コンテストは終了しました。" - #: templates/contest/contest.html:59 templates/contest/contest.html:63 msgid "F j, Y, G:i T" msgstr "F j, Y, G:i T" -#: templates/contest/contest.html:59 -#, python-format -msgid "" -"%(time_limit)s window between %(start_time)s and " -"%(end_time)s" -msgstr "" -"%(time_limit)s 窓は %(start_time)s から %(end_time)s ま" -"で" - -#: templates/contest/contest.html:63 -#, python-format -msgid "%(length)s long starting on %(start_time)s" -msgstr "開始時刻 %(start_time)s まであと %(length)s" - #: templates/contest/contest.html:85 msgid "AC Rate" msgstr "受理率" -#: templates/contest/contest.html:86 templates/contest/list.html:237 -#: templates/contest/list.html:289 templates/contest/list.html:366 -#: templates/problem/list.html:223 templates/problem/list.html:254 +#: templates/contest/contest.html:86 templates/contest/list.html:153 +#: templates/contest/list.html:195 templates/contest/list.html:271 +#: templates/problem/list.html:212 templates/problem/list.html:238 msgid "Users" msgstr "利用者" -#: templates/contest/contest.html:111 templates/problem/list.html:330 +#: templates/contest/contest.html:111 msgid "Editorial" msgstr "論説" -#: templates/contest/list.html:83 templates/contest/media-js.html:9 +#: templates/contest/list.html:31 templates/contest/media-js.html:9 msgid "Are you sure you want to join?" msgstr "あなたは本当に参加したいですか?" -#: templates/contest/list.html:84 +#: templates/contest/list.html:32 msgid "" "Joining a contest for the first time starts your timer, after which it " "becomes unstoppable." @@ -3493,68 +3173,48 @@ msgstr "" "コンテストに参加するとあなたのタイマーがスタートし、その後は止められなくなり" "ます。" -#: templates/contest/list.html:92 templates/contest/list.html:278 -msgid "Show" -msgstr "" - -#: templates/contest/list.html:102 templates/problem/list.html:68 -#, fuzzy -#| msgid "Organizations" -msgid "Organizations..." -msgstr "組織" - -#: templates/contest/list.html:135 +#: templates/contest/list.html:65 msgid "hidden" msgstr "" -#: templates/contest/list.html:140 +#: templates/contest/list.html:70 msgid "private" msgstr "" -#: templates/contest/list.html:154 +#: templates/contest/list.html:84 msgid "rated" msgstr "" -#: templates/contest/list.html:202 +#: templates/contest/list.html:132 msgid "Spectate" msgstr "観戦する" -#: templates/contest/list.html:208 +#: templates/contest/list.html:138 msgid "Join" msgstr "参加する" -#: templates/contest/list.html:220 -#, fuzzy -#| msgid "Search problems..." -msgid "Search contests..." -msgstr "問題を検索する..." - -#: templates/contest/list.html:229 -msgid "Search" -msgstr "" - -#: templates/contest/list.html:232 +#: templates/contest/list.html:148 msgid "Active Contests" msgstr "" -#: templates/contest/list.html:236 templates/contest/list.html:288 -#: templates/contest/list.html:327 templates/contest/list.html:365 +#: templates/contest/list.html:152 templates/contest/list.html:194 +#: templates/contest/list.html:232 templates/contest/list.html:270 msgid "Contest" msgstr "コンテスト" -#: templates/contest/list.html:275 +#: templates/contest/list.html:190 msgid "Ongoing Contests" msgstr "開催中のコンテスト" -#: templates/contest/list.html:322 +#: templates/contest/list.html:227 msgid "Upcoming Contests" msgstr "近日開催予定のコンテスト" -#: templates/contest/list.html:350 +#: templates/contest/list.html:255 msgid "There are no scheduled contests at this time." msgstr "現在スケジュールされているコンテストはありません。" -#: templates/contest/list.html:356 +#: templates/contest/list.html:261 msgid "Past Contests" msgstr "過去のコンテスト" @@ -3608,89 +3268,55 @@ msgstr "" msgid "Only the following organizations may access this contest:" msgstr "次の組織だけがこのコンテストをアクセスできます:" -#: templates/contest/ranking-table.html:9 templates/problem/search-form.html:35 +#: templates/contest/ranking-table.html:7 msgid "Organization" msgstr "組織" -#: templates/contest/ranking-table.html:10 templates/user/users-table.html:13 -#, fuzzy -#| msgid "full name" -msgid "Full Name" -msgstr "氏名" - -#: templates/contest/ranking-table.html:44 +#: templates/contest/ranking-table.html:30 msgid "Un-Disqualify" msgstr "" -#: templates/contest/ranking-table.html:47 +#: templates/contest/ranking-table.html:33 msgid "Disqualify" msgstr "" -#: templates/contest/ranking.html:187 +#: templates/contest/ranking.html:173 #, fuzzy #| msgid "Are you sure you want to join?" msgid "Are you sure you want to disqualify this participation?" msgstr "あなたは本当に参加したいですか?" -#: templates/contest/ranking.html:192 +#: templates/contest/ranking.html:178 #, fuzzy #| msgid "Are you sure you want to join?" msgid "Are you sure you want to un-disqualify this participation?" msgstr "あなたは本当に参加したいですか?" -#: templates/contest/ranking.html:463 +#: templates/contest/ranking.html:252 msgid "View user participation" msgstr "利用者の参加を見る" -#: templates/contest/ranking.html:467 +#: templates/contest/ranking.html:256 msgid "Show organizations" msgstr "組織を表示する" -#: templates/contest/ranking.html:471 -#, fuzzy -#| msgid "full name" -msgid "Show full name" -msgstr "氏名" - -#: templates/contest/ranking.html:474 -#, fuzzy -#| msgid "Show my tickets only" -msgid "Show friends only" -msgstr "私のチケットだけを表示する" - -#: templates/contest/ranking.html:477 -msgid "Total score only" -msgstr "" - -#: templates/contest/ranking.html:479 -#, fuzzy -#| msgid "virtual participation id" -msgid "Show virtual participation" -msgstr "仮想参加 id" - -#: templates/contest/stats.html:51 +#: templates/contest/stats.html:38 #, fuzzy #| msgid "problem translation" msgid "Problem Status Distribution" msgstr "翻訳された課題" -#: templates/contest/stats.html:56 +#: templates/contest/stats.html:43 #, fuzzy #| msgid "Problem name" msgid "Problem AC Rate" msgstr "課題名" -#: templates/contest/stats.html:62 -#, fuzzy -#| msgid "problem translation" -msgid "Problem Point Distribution" -msgstr "翻訳された課題" - -#: templates/contest/stats.html:76 templates/stats/language.html:16 +#: templates/contest/stats.html:48 templates/stats/language.html:16 msgid "Submissions by Language" msgstr "言語ごとの提出物" -#: templates/contest/stats.html:82 templates/stats/language.html:26 +#: templates/contest/stats.html:54 templates/stats/language.html:26 msgid "Language AC Rate" msgstr "言語の受理割合" @@ -3699,7 +3325,6 @@ msgid "Source:" msgstr "ソース:" #: templates/newsletter/common.html:6 -#: templates/newsletter/newsletter_list.html:15 #: templates/newsletter/subscription_unsubscribe_activated.html:3 #: templates/newsletter/subscription_unsubscribe_activated.html:6 #: templates/newsletter/subscription_update_activated.html:3 @@ -3707,29 +3332,6 @@ msgstr "ソース:" msgid "Newsletter" msgstr "ニュースレター" -#: templates/newsletter/newsletter_list.html:2 -#: templates/newsletter/newsletter_list.html:3 -#, fuzzy -#| msgid "Newsletter" -msgid "Newsletter list" -msgstr "ニュースレター" - -#: templates/newsletter/newsletter_list.html:6 -msgid "Subscribe to get the latest emails about upcoming contests and events." -msgstr "" - -#: templates/newsletter/newsletter_list.html:16 -#, fuzzy -#| msgid "Unsubscribe" -msgid "Subscribe" -msgstr "購読解除" - -#: templates/newsletter/newsletter_list.html:30 -#, fuzzy -#| msgid "Update subscription" -msgid "Update subscriptions" -msgstr "購読の更新" - #: templates/newsletter/subscription_unsubscribe_activated.html:3 #: templates/newsletter/subscription_unsubscribe_activated.html:6 #: templates/newsletter/subscription_update_activated.html:3 @@ -3797,115 +3399,64 @@ msgstr "" "更新要求は正常に受け付けられ、有効化の電子メールがあなたに送信されました。そ" "の電子メールには、購読を更新するためのリンクがあります。" -#: templates/notification/list.html:7 -#, fuzzy -#| msgid "You have not shared any information." -msgid "You have no notifications" -msgstr "あなたは、いかなる情報も共有していません。" - -#: templates/notification/list.html:13 -#, fuzzy -#| msgid "activate" -msgid "Activity" -msgstr "有効化" - #: templates/organization/edit.html:46 #: templates/organization/requests/pending.html:34 #: templates/ticket/edit-notes.html:4 msgid "Update" msgstr "更新" -#: templates/organization/home.html:41 +#: templates/organization/home.html:7 msgid "Are you sure you want to leave this organization?" msgstr "" -#: templates/organization/home.html:43 +#: templates/organization/home.html:9 msgid "You will have to rejoin to show up on the organization leaderboard." msgstr "" -#: templates/organization/home.html:45 +#: templates/organization/home.html:11 msgid "You will have to request membership in order to join again." msgstr "" -#: templates/organization/home.html:88 -msgid "Join organization" -msgstr "組織に参加する" - -#: templates/organization/home.html:92 -msgid "Request membership" -msgstr "メンバーシップを要求する" - -#: templates/organization/home.html:122 -#, fuzzy -#| msgid "Organizations" -msgid "Organization news" -msgstr "組織" - -#: templates/organization/home.html:128 -#, fuzzy -#| msgid "There are no scheduled contests at this time." -msgid "There is no news at this time." -msgstr "現在スケジュールされているコンテストはありません。" - -#: templates/organization/home.html:137 -#, fuzzy -#| msgid "Contest" -msgid "Controls" -msgstr "コンテスト" - -#: templates/organization/home.html:142 -msgid "Edit organization" -msgstr "組織を編集する" - -#: templates/organization/home.html:148 -msgid "View requests" -msgstr "要求を表示する" - -#: templates/organization/home.html:161 -msgid "Admin organization" -msgstr "組織を管理する" - -#: templates/organization/home.html:167 -msgid "View members" -msgstr "メンバーを表示する" - -#: templates/organization/home.html:174 +#: templates/organization/home.html:24 msgid "Leave organization" msgstr "組織から脱退する" -#: templates/organization/home.html:183 -#, fuzzy -#| msgid "See private contests" -msgid "New private contests" -msgstr "プライベートのコンテストを見る" +#: templates/organization/home.html:29 +msgid "Join organization" +msgstr "組織に参加する" -#: templates/organization/home.html:193 templates/organization/home.html:208 -#, fuzzy -#| msgid "View as PDF" -msgid "View all" -msgstr "PDF として表示する" +#: templates/organization/home.html:33 +msgid "Request membership" +msgstr "メンバーシップを要求する" -#: templates/organization/home.html:199 -#, fuzzy -#| msgid "New problems" -msgid "New private problems" -msgstr "新しい課題" +#: templates/organization/home.html:39 +msgid "Edit organization" +msgstr "組織を編集する" -#: templates/organization/list.html:40 -#, fuzzy -#| msgid "Show organizations" -msgid "Show my organizations only" -msgstr "組織を表示する" +#: templates/organization/home.html:43 +msgid "View requests" +msgstr "要求を表示する" -#: templates/organization/list.html:47 templates/status/language-list.html:34 -#: templates/user/import/table_csv.html:6 +#: templates/organization/home.html:50 +msgid "Admin organization" +msgstr "組織を管理する" + +#: templates/organization/home.html:55 +msgid "View members" +msgstr "メンバーを表示する" + +#: templates/organization/list.html:23 templates/status/language-list.html:34 msgid "Name" msgstr "名前" -#: templates/organization/list.html:48 +#: templates/organization/list.html:24 msgid "Members" msgstr "メンバー" +#: templates/organization/new.html:10 templates/ticket/new.html:38 +msgid "Create" +msgstr "作成" + #: templates/organization/requests/detail.html:13 msgid "User:" msgstr "利用者:" @@ -3938,7 +3489,7 @@ msgid "There are no requests to approve." msgstr "承認するための要求がありません。" #: templates/organization/requests/pending.html:17 -#: templates/problem/data.html:432 +#: templates/problem/data.html:452 msgid "Delete?" msgstr "削除しますか?" @@ -3974,37 +3525,37 @@ msgstr "追い出す" msgid "Enter a new code for the cloned problem:" msgstr "" -#: templates/problem/data.html:119 +#: templates/problem/data.html:108 #, fuzzy #| msgid "Information" msgid "Instruction" msgstr "情報" -#: templates/problem/data.html:390 +#: templates/problem/data.html:410 msgid "View YAML" msgstr "YAML を見る" -#: templates/problem/data.html:421 templates/problem/data.html:472 +#: templates/problem/data.html:441 templates/problem/data.html:491 msgid "Apply!" msgstr "" -#: templates/problem/data.html:426 +#: templates/problem/data.html:446 msgid "Type" msgstr "タイプ" -#: templates/problem/data.html:427 +#: templates/problem/data.html:447 msgid "Input file" msgstr "入力ファイル" -#: templates/problem/data.html:428 +#: templates/problem/data.html:448 msgid "Output file" msgstr "出力ファイル" -#: templates/problem/data.html:430 +#: templates/problem/data.html:450 msgid "Pretest?" msgstr "事前テストか?" -#: templates/problem/data.html:473 +#: templates/problem/data.html:492 msgid "Add new case" msgstr "新しいケースを追加する" @@ -4020,34 +3571,28 @@ msgstr "" "意を表してください。

自身で課題を解く前に公式の解答を提出すること" "は禁止されています。" -#: templates/problem/list.html:66 +#: templates/problem/list.html:62 msgid "Filter by type..." msgstr "タイプで絞り込む..." -#: templates/problem/list.html:193 +#: templates/problem/list.html:185 msgid "Hot problems" msgstr "ホットな課題" -#: templates/problem/list.html:218 templates/problem/list.html:240 -#: templates/problem/search-form.html:45 templates/user/user-problems.html:57 +#: templates/problem/list.html:207 templates/problem/list.html:224 +#: templates/problem/search-form.html:30 templates/user/user-problems.html:57 msgid "Category" msgstr "カテゴリ" -#: templates/problem/list.html:220 templates/problem/list.html:244 +#: templates/problem/list.html:209 templates/problem/list.html:228 msgid "Types" msgstr "タイプ" -#: templates/problem/list.html:251 +#: templates/problem/list.html:235 #, python-format msgid "AC %%" msgstr "受理 %%" -#: templates/problem/list.html:342 -#, fuzzy -#| msgid "Clarifications" -msgid "Add clarifications" -msgstr "解説" - #: templates/problem/manage_submission.html:55 msgid "Leave empty to not filter by language" msgstr "" @@ -4056,202 +3601,152 @@ msgstr "" msgid "Leave empty to not filter by result" msgstr "" -#: templates/problem/manage_submission.html:80 +#: templates/problem/manage_submission.html:79 msgid "Need valid values for both start and end IDs." msgstr "" -#: templates/problem/manage_submission.html:83 +#: templates/problem/manage_submission.html:82 msgid "End ID must be after start ID." msgstr "" +#: templates/problem/manage_submission.html:90 +#, python-brace-format +msgid "" +"You are about to rejudge {count} submissions. Are you sure you want to do " +"this?" +msgstr "" + #: templates/problem/manage_submission.html:96 -#, python-brace-format msgid "" -"You are about to {action} {count} submissions. Are you sure you want to do " -"this?" +"You are about to rejudge a few submissions. Are you sure you want to do this?" msgstr "" -#: templates/problem/manage_submission.html:103 -#, python-brace-format -msgid "" -"You are about to {action} a few submissions. Are you sure you want to do " -"this?" +#: templates/problem/manage_submission.html:115 +msgid "Rejudge Submissions" msgstr "" -#: templates/problem/manage_submission.html:127 -#: templates/submission/list.html:309 -msgid "Filter submissions" -msgstr "提出物を絞り込む" - -#: templates/problem/manage_submission.html:132 +#: templates/problem/manage_submission.html:120 msgid "Filter by ID:" msgstr "" -#: templates/problem/manage_submission.html:135 +#: templates/problem/manage_submission.html:123 msgid "Starting ID:" msgstr "" -#: templates/problem/manage_submission.html:139 +#: templates/problem/manage_submission.html:127 msgid "Ending ID:" msgstr "" -#: templates/problem/manage_submission.html:143 +#: templates/problem/manage_submission.html:131 msgid "This range includes both endpoints." msgstr "" -#: templates/problem/manage_submission.html:146 +#: templates/problem/manage_submission.html:134 msgid "Filter by language:" msgstr "" -#: templates/problem/manage_submission.html:154 +#: templates/problem/manage_submission.html:142 msgid "Filter by result:" msgstr "" -#: templates/problem/manage_submission.html:164 -#, fuzzy -#| msgid "location" -msgid "Action" -msgstr "位置" - -#: templates/problem/manage_submission.html:166 +#: templates/problem/manage_submission.html:150 msgid "Rejudge selected submissions" msgstr "" -#: templates/problem/manage_submission.html:171 -#, fuzzy -#| msgid "Too many submissions" -msgid "Download selected submissions" -msgstr "提出物が多過ぎます" +#: templates/problem/manage_submission.html:157 +msgid "Rescore Everything" +msgstr "" -#: templates/problem/manage_submission.html:177 -#, fuzzy, python-format -#| msgid "Are you sure you want to join?" -msgid "Are you sure you want to rescore %(count)d submissions?" -msgstr "あなたは本当に参加したいですか?" - -#: templates/problem/manage_submission.html:178 +#: templates/problem/manage_submission.html:163 msgid "Rescore all submissions" msgstr "" -#: templates/problem/problem.html:132 +#: templates/problem/problem.html:91 msgid "View as PDF" msgstr "PDF として表示する" -#: templates/problem/problem.html:141 templates/problem/problem.html:151 -#: templates/problem/problem.html:156 +#: templates/problem/problem.html:101 templates/problem/problem.html:111 +#: templates/problem/problem.html:116 msgid "Submit solution" msgstr "解答を提出する" -#: templates/problem/problem.html:144 -#, python-format -msgid "%(counter)s submission left" -msgid_plural "%(counter)s submissions left" -msgstr[0] "%(counter)s 個の提出物が残っています" - -#: templates/problem/problem.html:152 +#: templates/problem/problem.html:112 msgid "0 submissions left" msgstr "提出物が残っていません" -#: templates/problem/problem.html:164 +#: templates/problem/problem.html:124 msgid "My submissions" msgstr "私の提出物" -#: templates/problem/problem.html:168 +#: templates/problem/problem.html:128 msgid "Best submissions" msgstr "最優秀提出物" -#: templates/problem/problem.html:172 +#: templates/problem/problem.html:132 msgid "Read editorial" msgstr "論説を読む" -#: templates/problem/problem.html:177 +#: templates/problem/problem.html:137 msgid "Manage tickets" msgstr "チケットを管理する" -#: templates/problem/problem.html:181 +#: templates/problem/problem.html:141 msgid "Edit problem" msgstr "課題を編集する" -#: templates/problem/problem.html:183 +#: templates/problem/problem.html:143 msgid "Edit test data" msgstr "テストデータを編集する" -#: templates/problem/problem.html:188 +#: templates/problem/problem.html:148 msgid "My tickets" msgstr "" -#: templates/problem/problem.html:196 +#: templates/problem/problem.html:156 msgid "Manage submissions" msgstr "" -#: templates/problem/problem.html:202 +#: templates/problem/problem.html:162 msgid "Clone problem" msgstr "課題を複製する" -#: templates/problem/problem.html:209 +#: templates/problem/problem.html:169 msgid "Points:" msgstr "点数:" -#: templates/problem/problem.html:212 templates/problem/problem.html:214 +#: templates/problem/problem.html:172 templates/problem/problem.html:174 msgid "(partial)" msgstr "(部分点)" -#: templates/problem/problem.html:219 +#: templates/problem/problem.html:179 msgid "Time limit:" msgstr "制限時間:" -#: templates/problem/problem.html:231 +#: templates/problem/problem.html:191 msgid "Memory limit:" msgstr "メモリ制限:" -#: templates/problem/problem.html:250 -msgid "Author:" -msgid_plural "Authors:" -msgstr[0] "著者:" - -#: templates/problem/problem.html:265 -msgid "Problem type" -msgid_plural "Problem types" -msgstr[0] "課題のタイプ" - -#: templates/problem/problem.html:278 +#: templates/problem/problem.html:238 msgid "Allowed languages" msgstr "許可されている言語" -#: templates/problem/problem.html:286 -#, python-format -msgid "No %(lang)s judge online" -msgstr "%(lang)s はオンライン判定されません" - -#: templates/problem/problem.html:297 -#, fuzzy -#| msgid "Judge" -msgid "Judge:" -msgid_plural "Judges:" -msgstr[0] "判定器" - -#: templates/problem/problem.html:314 +#: templates/problem/problem.html:274 msgid "none available" msgstr "" -#: templates/problem/problem.html:326 -#, python-format -msgid "This problem has %(length)s clarification(s)" -msgstr "" - -#: templates/problem/problem.html:350 +#: templates/problem/problem.html:299 msgid "Request clarification" msgstr "解説を要求する" -#: templates/problem/problem.html:352 +#: templates/problem/problem.html:301 msgid "Report an issue" msgstr "問題を報告する" -#: templates/problem/raw.html:64 +#: templates/problem/raw.html:62 msgid "Time Limit:" msgstr "" -#: templates/problem/raw.html:73 +#: templates/problem/raw.html:71 msgid "Memory Limit:" msgstr "" @@ -4275,79 +3770,39 @@ msgstr "解いた課題を非表示にする" msgid "Show problem types" msgstr "課題のタイプを表示する" -#: templates/problem/search-form.html:32 -#, fuzzy -#| msgid "Read editorial" -msgid "Show editorial" -msgstr "論説を読む" - -#: templates/problem/search-form.html:48 templates/problem/search-form.html:50 -#: templates/submission/submission-list-tabs.html:4 +#: templates/problem/search-form.html:33 templates/problem/search-form.html:35 msgid "All" msgstr "全て" -#: templates/problem/search-form.html:62 +#: templates/problem/search-form.html:46 msgid "Problem types" msgstr "課題のタイプ" -#: templates/problem/search-form.html:73 +#: templates/problem/search-form.html:57 msgid "Point range" msgstr "点数の範囲" -#: templates/problem/search-form.html:79 templates/submission/list.html:331 +#: templates/problem/search-form.html:63 templates/submission/list.html:331 #: templates/ticket/list.html:248 msgid "Go" msgstr "実行する" -#: templates/problem/search-form.html:80 +#: templates/problem/search-form.html:64 msgid "Random" msgstr "ランダム" -#: templates/problem/submit.html:117 -msgid "Your source code must contain at most 65536 characters." -msgstr "" - -#: templates/problem/submit.html:204 -#, python-format -msgid "" -"Warning! Your default language, %(default_language)s, is " -"unavailable for this problem and has been deselected." -msgstr "" -"警告! あなたのデフォルト言語 %(default_language)s はこの課題に" -"利用可能ではないので選択を解除しました。" - -#: templates/problem/submit.html:215 -#, python-format -msgid "" -"\n" -" You have %(left)s submission left\n" -" " -msgid_plural "" -"\n" -" You have %(left)s submissions left\n" -" " -msgstr[0] "" -"\n" -" あなたは提出物 %(left)s が残っています \n" -" " - -#: templates/problem/submit.html:224 +#: templates/problem/submit.html:212 msgid "You have 0 submissions left" msgstr "あなたには提出物が残っていません" -#: templates/problem/submit.html:258 +#: templates/problem/submit.html:250 msgid "No judge is available for this problem." msgstr "この課題は判定器が利用可能ではありません。" -#: templates/problem/submit.html:262 +#: templates/problem/submit.html:252 msgid "Submit!" msgstr "提出!" -#: templates/registration/activate.html:3 -#, python-format -msgid "%(key)s is an invalid activation key." -msgstr "%(key)s は無効な有効化鍵です。" - #: templates/registration/activation_complete.html:3 msgid "Your account has been successfully activated." msgstr "あなたのアカウントは正常に有効化されました。" @@ -4409,15 +3864,6 @@ msgstr "" "もし電子メールが届かなければ、あなたが登録時に入力したアドレスを確認し、迷惑" "メールフォルダをチェックしてください。" -#: templates/registration/password_reset_email.txt:1 -#, python-format -msgid "" -"You're receiving this email because you requested a password reset for your " -"user account at %(site_name)s." -msgstr "" -"あなたが %(site_name)s の利用者アカウントのパスワードリセットを要求したため、" -"この電子メールが届いています。" - #: templates/registration/password_reset_email.txt:3 msgid "Please go to the following page and choose a new password:" msgstr "次のページに進み、新しいパスワードを設定してください:" @@ -4430,16 +3876,6 @@ msgstr "あなたの利用者名、もし忘れたのであれば:" msgid "Thanks for using our site!" msgstr "私たちのサイトを利用してくれてありがとう!" -#: templates/registration/password_reset_email.txt:11 -#, python-format -msgid "The %(site_name)s team" -msgstr "%(site_name)s チーム" - -#: templates/registration/password_reset_subject.txt:1 -#, python-format -msgid "Password reset on %(site_name)s" -msgstr "%(site_name)s のパスワードをリセットする" - #: templates/registration/profile_creation.html:36 #: templates/registration/username_select.html:7 msgid "Continue >" @@ -4478,20 +3914,19 @@ msgstr "デフォルトの言語" msgid "Affiliated organizations" msgstr "所属組織" -#: templates/registration/registration_form.html:195 -#: templates/user/edit-profile.html:128 +#: templates/registration/registration_form.html:192 msgid "Notify me about upcoming contests" msgstr "まもなく開催予定のコンテストを通知する" -#: templates/registration/registration_form.html:209 +#: templates/registration/registration_form.html:206 msgid "By registering, you agree to our" msgstr "登録することで、あなたは同意することになります" -#: templates/registration/registration_form.html:210 +#: templates/registration/registration_form.html:207 msgid "Terms & Conditions" msgstr "利用規約・条件" -#: templates/registration/registration_form.html:213 +#: templates/registration/registration_form.html:210 msgid "Register!" msgstr "登録!" @@ -4501,11 +3936,6 @@ msgstr "登録!" msgid "Enter the 6-digit code generated by your app:" msgstr "" -#: templates/registration/totp_auth.html:41 -#, python-format -msgid "If you lost your authentication device, please contact us at %(email)s." -msgstr "" - #: templates/registration/totp_disable.html:38 msgid "" "To protect your account, you must first authenticate before you can disable " @@ -4524,6 +3954,10 @@ msgstr "" msgid "Or enter this code manually:" msgstr "" +#: templates/stats/base.html:9 templates/submission/list.html:339 +msgid "Statistics" +msgstr "統計" + #: templates/stats/language.html:11 msgid "Submission Statistics" msgstr "提出物の統計" @@ -4549,7 +3983,6 @@ msgid "Ping" msgstr "ピン" #: templates/status/judge-status-table.html:8 -#: templates/user/import/index.html:104 msgid "Load" msgstr "負荷" @@ -4565,7 +3998,6 @@ msgid "There are no judges available at this time." msgstr "現在利用できる判定器はありません。" #: templates/status/language-list.html:33 templates/ticket/list.html:261 -#: templates/user/import/table_csv.html:3 msgid "ID" msgstr "ID" @@ -4573,22 +4005,6 @@ msgstr "ID" msgid "Runtime Info" msgstr "ランタイム情報" -#: templates/status/status-tabs.html:4 -msgid "Judges" -msgstr "判定器" - -#: templates/status/status-tabs.html:6 -msgid "Version Matrix" -msgstr "バージョンマトリックス" - -#: templates/submission/internal-error-message.html:3 -#, python-format -msgid "" -"An internal error occurred while grading, and the %(SITE_NAME)s " -"administrators have been notified.
In the meantime, try resubmitting in " -"a few seconds." -msgstr "" - #: templates/submission/internal-error-message.html:8 msgid "An internal error occurred while grading." msgstr "採点中に内部エラーが発生しました。" @@ -4605,6 +4021,10 @@ msgstr "状態で絞り込む..." msgid "Filter by language..." msgstr "言語で絞り込む..." +#: templates/submission/list.html:309 +msgid "Filter submissions" +msgstr "提出物を絞り込む" + #: templates/submission/list.html:345 msgid "Total:" msgstr "" @@ -4662,84 +4082,83 @@ msgstr "事前テストの実行結果" msgid "Execution Results" msgstr "実行結果" -#: templates/submission/status-testcases.html:34 +#: templates/submission/status-testcases.html:31 +msgid "Batch " +msgstr "バッチ" + +#: templates/submission/status-testcases.html:43 msgid "Overall: " msgstr "" -#: templates/submission/status-testcases.html:48 +#: templates/submission/status-testcases.html:57 #, fuzzy #| msgid "Points:" msgid "Point: " msgstr "点数:" -#: templates/submission/status-testcases.html:53 +#: templates/submission/status-testcases.html:62 #, fuzzy #| msgid "Time:" msgid "Time: " msgstr "時刻:" -#: templates/submission/status-testcases.html:62 +#: templates/submission/status-testcases.html:71 #, fuzzy #| msgid "Memory" msgid "Memory: " msgstr "メモリ" -#: templates/submission/status-testcases.html:73 -msgid "Batch " -msgstr "バッチ" - #: templates/submission/status-testcases.html:84 -#: templates/submission/status-testcases.html:113 -#, fuzzy -#| msgid "Points" -msgid "Point" -msgstr "点数" - -#: templates/submission/status-testcases.html:99 msgid "Case" msgstr "" "ケース\n" "Vaka" -#: templates/submission/status-testcases.html:101 +#: templates/submission/status-testcases.html:86 msgid "Pretest" msgstr "事前テスト" -#: templates/submission/status-testcases.html:103 +#: templates/submission/status-testcases.html:88 msgid "Test case" msgstr "テストケース" -#: templates/submission/status-testcases.html:141 +#: templates/submission/status-testcases.html:99 +#, fuzzy +#| msgid "Points" +msgid "Point" +msgstr "点数" + +#: templates/submission/status-testcases.html:121 #, fuzzy #| msgid "Input file" msgid "Input:" msgstr "入力ファイル" -#: templates/submission/status-testcases.html:145 +#: templates/submission/status-testcases.html:125 #, fuzzy #| msgid "Output file" msgid "Output:" msgstr "出力ファイル" -#: templates/submission/status-testcases.html:149 +#: templates/submission/status-testcases.html:129 #, fuzzy #| msgid "Wrong Answer" msgid "Answer:" msgstr "間違った解答" -#: templates/submission/status-testcases.html:154 +#: templates/submission/status-testcases.html:134 #, fuzzy #| msgid "judging feedback" msgid "Judge feedback:" msgstr "判定のフィードバック" -#: templates/submission/status-testcases.html:175 +#: templates/submission/status-testcases.html:157 msgid "Passing pretests does not guarantee a full score on system tests." msgstr "" "予備テストに通過したことは、システムテストでの満点を保証するものではありませ" "ん。" -#: templates/submission/status-testcases.html:178 +#: templates/submission/status-testcases.html:160 msgid "Submission aborted!" msgstr "提出が中断された!" @@ -4751,24 +4170,11 @@ msgstr "ソースを表示する" msgid "Abort" msgstr "中断する" -#: templates/submission/submission-list-tabs.html:6 -msgid "Mine" -msgstr "私の" - -#: templates/submission/submission-list-tabs.html:9 -msgid "Best" -msgstr "最優秀" - -#: templates/submission/submission-list-tabs.html:12 -#, python-format -msgid "%(user)s's" -msgstr "%(user)s" - -#: templates/ticket/list.html:135 templates/ticket/ticket.html:273 +#: templates/ticket/list.html:135 templates/ticket/ticket.html:257 msgid "Reopened: " msgstr "再オープンしました:" -#: templates/ticket/list.html:138 templates/ticket/ticket.html:274 +#: templates/ticket/list.html:138 templates/ticket/ticket.html:258 msgid "Closed: " msgstr "閉じられました:" @@ -4792,7 +4198,7 @@ msgstr "担当者" msgid "Title" msgstr "題目" -#: templates/ticket/list.html:264 templates/ticket/ticket.html:369 +#: templates/ticket/list.html:264 templates/ticket/ticket.html:328 msgid "Assignees" msgstr "担当者" @@ -4810,37 +4216,33 @@ msgstr "" "のではないことを心に留めてください。課題を解くのに援助が必要な場合は、代わり" "にコメントで尋ねて下さい。" -#: templates/ticket/ticket.html:355 -msgid "Post" -msgstr "投稿する" - -#: templates/ticket/ticket.html:363 +#: templates/ticket/ticket.html:322 msgid "Associated object" msgstr "関連するオブジェクト" -#: templates/ticket/ticket.html:374 +#: templates/ticket/ticket.html:333 msgid "No one is assigned." msgstr "誰も割り当てられていません。" -#: templates/ticket/ticket.html:380 +#: templates/ticket/ticket.html:339 msgid "Close ticket" msgstr "チケットを閉じる" -#: templates/ticket/ticket.html:382 +#: templates/ticket/ticket.html:341 msgid "Reopen ticket" msgstr "チケットを再度開く" -#: templates/ticket/ticket.html:386 +#: templates/ticket/ticket.html:345 msgid "Assignee notes" msgstr "担当者メモ" -#: templates/ticket/ticket.html:393 templates/widgets/select_all.html:4 +#: templates/ticket/ticket.html:352 templates/widgets/select_all.html:4 msgid "Nothing here." msgstr "何もありません。" -#: templates/user/base-users-table.html:3 -msgid "Rank" -msgstr "ランク" +#: templates/ticket/ticket.html:385 +msgid "Post" +msgstr "投稿する" #: templates/user/base-users.html:14 templates/user/base-users.html:69 msgid "Search by handle..." @@ -4886,211 +4288,50 @@ msgstr "利用者スクリプト" msgid "Update profile" msgstr "プロフィールの更新" -#: templates/user/import/index.html:31 -msgid "Upload CSV only" -msgstr "" - -#: templates/user/import/index.html:100 -#, fuzzy -#| msgid "user profile" -msgid "User File" -msgstr "ユーザープロフィール" - -#: templates/user/import/index.html:102 -msgid "Sample" -msgstr "" - -#: templates/user/import/index.html:105 templates/user/user-list-tabs.html:8 -msgid "Import" -msgstr "" - -#: templates/user/import/table_csv.html:7 -msgid "School" -msgstr "" - -#: templates/user/pp-row.html:22 -#, python-format -msgid "" -"\n" -" weighted %(weight)s%%\n" -" " -msgstr "" -"\n" -" 重み %(weight)s%%\n" -" " - -#: templates/user/pp-row.html:27 -#, python-format -msgid "%(pp).1fpp" -msgstr "%(pp).1fpp" - -#: templates/user/pp-row.html:29 -#, python-format -msgid "%(pp).0fpp" -msgstr "%(pp).0fpp" - -#: templates/user/user-about.html:23 -#, fuzzy, python-format -#| msgid "contest problems" -msgid "%(counter)s problem solved" -msgid_plural "%(counter)s problems solved" -msgstr[0] "コンテストの課題" - -#: templates/user/user-about.html:35 -#, fuzzy -#| msgid "Total points:" -msgid "Total points" -msgstr "合計点:" - -#: templates/user/user-about.html:45 -#, fuzzy -#| msgid "Rank by rating:" -msgid "Rank by rating" -msgstr "評価による順位:" - -#: templates/user/user-about.html:52 -#, fuzzy -#| msgid "Rank by points:" -msgid "Rank by points" -msgstr "点数による順位:" - -#: templates/user/user-about.html:64 +#: templates/user/user-about.html:14 msgid "From" msgstr "差出人" -#: templates/user/user-about.html:75 +#: templates/user/user-about.html:25 msgid "Admin Notes" msgstr "" -#: templates/user/user-about.html:90 +#: templates/user/user-about.html:40 msgid "You have not shared any information." msgstr "あなたは、いかなる情報も共有していません。" -#: templates/user/user-about.html:92 +#: templates/user/user-about.html:42 msgid "This user has not shared any information." msgstr "この利用者は、いかなる情報も共有していません。" -#: templates/user/user-about.html:101 -msgid "Awards" -msgstr "" +#: templates/user/user-base.html:50 +msgid "Rank by points:" +msgstr "点数による順位:" -#: templates/user/user-about.html:112 -#, fuzzy, python-format -#| msgctxt "contest problem" -#| msgid "%(problem)s in %(contest)s" -msgid "%(label)s (%(date)s)" -msgstr "%(contest)s 中の %(problem)s" +#: templates/user/user-base.html:53 +msgid "Total points:" +msgstr "合計点:" -#: templates/user/user-about.html:130 -#, fuzzy -#| msgid "Monday" -msgid "Mon" -msgstr "月曜日" +#: templates/user/user-base.html:68 +msgid "Rank by rating:" +msgstr "評価による順位:" -#: templates/user/user-about.html:135 -#, fuzzy -#| msgid "Tuesday" -msgid "Tues" -msgstr "火曜日" +#: templates/user/user-base.html:70 +msgid "Rating:" +msgstr "評価:" -#: templates/user/user-about.html:140 -msgid "Wed" -msgstr "" - -#: templates/user/user-about.html:145 -#, fuzzy -#| msgid "Thursday" -msgid "Thurs" -msgstr "木曜日" - -#: templates/user/user-about.html:150 -#, fuzzy -#| msgid "Friday" -msgid "Fri" -msgstr "金曜日" - -#: templates/user/user-about.html:155 -#, fuzzy -#| msgid "State" -msgid "Sat" -msgstr "状態" - -#: templates/user/user-about.html:160 -#, fuzzy -#| msgid "Sunday" -msgid "Sun" -msgstr "日曜日" - -#: templates/user/user-about.html:169 -msgid "Less" -msgstr "" - -#: templates/user/user-about.html:175 -msgid "More" -msgstr "" - -#: templates/user/user-about.html:184 -#, fuzzy -#| msgid "History" -msgid "Rating History" -msgstr "履歴" - -#: templates/user/user-about.html:255 -msgid "past year" -msgstr "" - -#: templates/user/user-about.html:272 -#, fuzzy -#| msgid "All submissions" -msgid "total submission(s)" -msgstr "全ての提出物" - -#: templates/user/user-about.html:276 -#, fuzzy -#| msgid "submission test case" -msgid "submissions in the last year" -msgstr "提出テストケース" - -#: templates/user/user-base.html:101 -msgid "Unfollow" -msgstr "" - -#: templates/user/user-base.html:104 -msgid "Follow" -msgstr "" - -#: templates/user/user-base.html:120 -#, fuzzy -#| msgid "" -#| "\n" -#| " You have %(left)s submission left\n" -#| " " -#| msgid_plural "" -#| "\n" -#| " You have %(left)s submissions left\n" -#| " " -msgid "Contests written" -msgstr "" -"\n" -" あなたは提出物 %(left)s が残っています \n" -" " - -#: templates/user/user-base.html:124 +#: templates/user/user-base.html:71 msgid "Volatility:" msgstr "変動率:" -#: templates/user/user-base.html:128 +#: templates/user/user-base.html:72 msgid "Min. rating:" msgstr "最小の評価:" -#: templates/user/user-base.html:132 +#: templates/user/user-base.html:73 msgid "Max rating:" msgstr "最大の評価:" -#: templates/user/user-list-tabs.html:5 -msgid "Friends" -msgstr "" - #: templates/user/user-problems.html:35 msgid "Points Breakdown" msgstr "点数の内訳" @@ -5111,64 +4352,81 @@ msgstr "作成された課題" msgid "Hide problems I've solved" msgstr "自分が解いた課題を非表示にする" -#: templates/user/user-problems.html:93 -#, python-format -msgid "%(points).1f points" -msgstr "%(points).1f 点" - #: templates/user/user-problems.html:99 msgid "Score" msgstr "得点" -#: templates/user/user-problems.html:110 -#, python-format -msgid "%(points)s / %(total)s" -msgstr "%(points)s / %(total)s" - -#: templates/user/user-tabs.html:7 -msgid "Impersonate" -msgstr "なりすまし" - -#: templates/user/user-tabs.html:13 -msgid "Admin User" -msgstr "管理者" - -#: templates/user/user-tabs.html:16 -msgid "Admin Profile" -msgstr "管理者プロフィール" - #: templates/widgets/select_all.html:8 msgid "Check all" msgstr "すべてをチェックする" -#, fuzzy -#~| msgid "%(counter)s submission left" -#~| msgid_plural "%(counter)s submissions left" -#~ msgid "%(cnt)d submission on %(date)s" -#~ msgid_plural "%(cnt)d submissions on %(date)s" -#~ msgstr[0] "%(counter)s 個の提出物が残っています" - -#~ msgid "Rating:" -#~ msgstr "評価:" - -#, fuzzy -#~| msgid "Admin" -#~ msgid "Admins" -#~ msgstr "管理" - -#, fuzzy -#~| msgid "Rescore the selected submissions" -#~ msgid "This will rescore %(count)d submissions." -#~ msgstr "選択した提出物を再採点する" - -#, fuzzy -#~| msgid "%(points)s / %(total)s" -#~ msgid "Point %(point)s / Case #%(case)s" -#~ msgstr "%(points)s / %(total)s" - #~ msgid "output prefix length override" #~ msgstr "出力プレフィックス長のオーバーライド" +#~ msgid "Hello, %(username)s." +#~ msgstr "こんにちは、%(username)s。" + +#~ msgid "" +#~ "\n" +#~ " posted on %(time)s\n" +#~ " " +#~ msgstr "" +#~ "\n" +#~ " %(time)s に投稿された \n" +#~ " " + +#~ msgid "" +#~ "\n" +#~ " on %(time)s\n" +#~ " " +#~ msgstr "" +#~ "\n" +#~ " %(time)s にて \n" +#~ " " + +#~ msgid "posted on {time}" +#~ msgstr "{time} に投稿された" + +#~ msgid "commented on {time}" +#~ msgstr "{time} にコメントされた" + +#~ msgid "edit %(edits)s" +#~ msgstr "%(edits)s を編集する" + +#~ msgid "List" +#~ msgstr "一覧" + +#~ msgid "Calendar" +#~ msgstr "カレンダー" + +#~ msgid "Info" +#~ msgstr "情報" + +#~ msgid "Rankings" +#~ msgstr "順位表" + +#~ msgid "Hidden Rankings" +#~ msgstr "非表示の順位表" + +#~ msgid "Stop spectating" +#~ msgstr "観戦を停止する" + +#~ msgid "Participating virtually." +#~ msgstr "仮想的に参加している" + +#~ msgid "Contest is over." +#~ msgstr "コンテストは終了しました。" + +#~ msgid "" +#~ "%(time_limit)s window between %(start_time)s and " +#~ "%(end_time)s" +#~ msgstr "" +#~ "%(time_limit)s 窓は %(start_time)s から %(end_time)s " +#~ "まで" + +#~ msgid "%(length)s long starting on %(start_time)s" +#~ msgstr "開始時刻 %(start_time)s まであと %(length)s" + #~ msgid "Started on {time}" #~ msgstr "{time} に開始した" @@ -5190,6 +4448,63 @@ msgstr "すべてをチェックする" #~ msgid "Generator args" #~ msgstr "ジェネレータの引数" +#~ msgid "%(counter)s submission left" +#~ msgid_plural "%(counter)s submissions left" +#~ msgstr[0] "%(counter)s 個の提出物が残っています" + +#~ msgid "Author:" +#~ msgid_plural "Authors:" +#~ msgstr[0] "著者:" + +#~ msgid "Problem type" +#~ msgid_plural "Problem types" +#~ msgstr[0] "課題のタイプ" + +#~ msgid "No %(lang)s judge online" +#~ msgstr "%(lang)s はオンライン判定されません" + +#~ msgid "" +#~ "Warning! Your default language, %(default_language)s, is " +#~ "unavailable for this problem and has been deselected." +#~ msgstr "" +#~ "警告! あなたのデフォルト言語 %(default_language)s はこの課" +#~ "題に利用可能ではないので選択を解除しました。" + +#~ msgid "" +#~ "\n" +#~ " You have %(left)s submission left\n" +#~ " " +#~ msgid_plural "" +#~ "\n" +#~ " You have %(left)s submissions left\n" +#~ " " +#~ msgstr[0] "" +#~ "\n" +#~ " あなたは提出物 %(left)s が残っています \n" +#~ " " + +#~ msgid "%(key)s is an invalid activation key." +#~ msgstr "%(key)s は無効な有効化鍵です。" + +#~ msgid "" +#~ "You're receiving this email because you requested a password reset for " +#~ "your user account at %(site_name)s." +#~ msgstr "" +#~ "あなたが %(site_name)s の利用者アカウントのパスワードリセットを要求したた" +#~ "め、この電子メールが届いています。" + +#~ msgid "The %(site_name)s team" +#~ msgstr "%(site_name)s チーム" + +#~ msgid "Password reset on %(site_name)s" +#~ msgstr "%(site_name)s のパスワードをリセットする" + +#~ msgid "Judges" +#~ msgstr "判定器" + +#~ msgid "Version Matrix" +#~ msgstr "バージョンマトリックス" + #~ msgid "Case #%(case)s" #~ msgstr "ケース #%(case)s" @@ -5201,3 +4516,45 @@ msgstr "すべてをチェックする" #~ msgid "Final score:" #~ msgstr "最終得点:" + +#~ msgid "Mine" +#~ msgstr "私の" + +#~ msgid "Best" +#~ msgstr "最優秀" + +#~ msgid "%(user)s's" +#~ msgstr "%(user)s" + +#~ msgid "Rank" +#~ msgstr "ランク" + +#~ msgid "" +#~ "\n" +#~ " weighted %(weight)s%%\n" +#~ " " +#~ msgstr "" +#~ "\n" +#~ " 重み %(weight)s%%\n" +#~ " " + +#~ msgid "%(pp).1fpp" +#~ msgstr "%(pp).1fpp" + +#~ msgid "%(pp).0fpp" +#~ msgstr "%(pp).0fpp" + +#~ msgid "%(points).1f points" +#~ msgstr "%(points).1f 点" + +#~ msgid "%(points)s / %(total)s" +#~ msgstr "%(points)s / %(total)s" + +#~ msgid "Impersonate" +#~ msgstr "なりすまし" + +#~ msgid "Admin User" +#~ msgstr "管理者" + +#~ msgid "Admin Profile" +#~ msgstr "管理者プロフィール" diff --git a/locale/ja/LC_MESSAGES/djangojs.po b/locale/ja/LC_MESSAGES/djangojs.po index 4838764..236f5d4 100644 --- a/locale/ja/LC_MESSAGES/djangojs.po +++ b/locale/ja/LC_MESSAGES/djangojs.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: dmoj\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-07-20 23:30+0700\n" +"POT-Creation-Date: 2019-10-01 23:12+0000\n" "PO-Revision-Date: 2019-11-11 22:05\n" "Last-Translator: Icyene\n" "Language-Team: Japanese\n" @@ -26,3 +26,4 @@ msgstr[0] "%d 日 %h:%m:%s" msgctxt "time format without day" msgid "%h:%m:%s" msgstr "%h:%m:%s" + diff --git a/locale/ko/LC_MESSAGES/django.po b/locale/ko/LC_MESSAGES/django.po index 858e8bd..e2f670d 100644 --- a/locale/ko/LC_MESSAGES/django.po +++ b/locale/ko/LC_MESSAGES/django.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: dmoj\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-10-25 05:59+0700\n" +"POT-Creation-Date: 2020-04-10 01:26-0500\n" "PO-Revision-Date: 2019-11-11 22:05\n" "Last-Translator: Icyene\n" "Language-Team: Korean\n" @@ -16,93 +16,93 @@ msgstr "" "X-Crowdin-Language: ko\n" "X-Crowdin-File: django.po\n" -#: chat_box/models.py:16 judge/admin/interface.py:110 -#: judge/models/contest.py:403 judge/models/contest.py:528 -#: judge/models/profile.py:211 +#: chat_box/models.py:15 judge/admin/interface.py:107 +#: judge/models/contest.py:257 judge/models/contest.py:381 +#: judge/models/profile.py:191 msgid "user" msgstr "사용자" -#: chat_box/models.py:17 judge/models/comment.py:43 judge/models/comment.py:191 +#: chat_box/models.py:16 judge/models/comment.py:42 msgid "posted time" msgstr "게시 시각" -#: chat_box/models.py:18 judge/models/comment.py:47 +#: chat_box/models.py:17 judge/models/comment.py:46 msgid "body of comment" msgstr "코멘트 본문" -#: chat_box/views.py:29 templates/chat/chat.html:4 +#: chat_box/views.py:29 msgid "Chat Box" msgstr "" -#: dmoj/settings.py:355 +#: dmoj/settings.py:349 msgid "German" msgstr "독일어" -#: dmoj/settings.py:356 +#: dmoj/settings.py:350 msgid "English" msgstr "영어" -#: dmoj/settings.py:357 +#: dmoj/settings.py:351 msgid "Spanish" msgstr "스페인어" -#: dmoj/settings.py:358 +#: dmoj/settings.py:352 msgid "French" msgstr "프랑스어" -#: dmoj/settings.py:359 +#: dmoj/settings.py:353 msgid "Croatian" msgstr "크로아티아어" -#: dmoj/settings.py:360 +#: dmoj/settings.py:354 msgid "Hungarian" msgstr "헝가리어" -#: dmoj/settings.py:361 +#: dmoj/settings.py:355 msgid "Japanese" msgstr "" -#: dmoj/settings.py:362 +#: dmoj/settings.py:356 msgid "Korean" msgstr "한국어" -#: dmoj/settings.py:363 +#: dmoj/settings.py:357 msgid "Brazilian Portuguese" msgstr "" -#: dmoj/settings.py:364 +#: dmoj/settings.py:358 msgid "Romanian" msgstr "루마니아어" -#: dmoj/settings.py:365 +#: dmoj/settings.py:359 msgid "Russian" msgstr "러시아어" -#: dmoj/settings.py:366 +#: dmoj/settings.py:360 msgid "Serbian (Latin)" msgstr "세르비아어(라틴문자)" -#: dmoj/settings.py:367 +#: dmoj/settings.py:361 msgid "Turkish" msgstr "터키어" -#: dmoj/settings.py:368 +#: dmoj/settings.py:362 msgid "Vietnamese" msgstr "베트남어" -#: dmoj/settings.py:369 +#: dmoj/settings.py:363 msgid "Simplified Chinese" msgstr "중국어(간체)" -#: dmoj/settings.py:370 +#: dmoj/settings.py:364 msgid "Traditional Chinese" msgstr "" -#: dmoj/urls.py:58 +#: dmoj/urls.py:57 msgid "Login" msgstr "로그인" -#: dmoj/urls.py:106 templates/base.html:193 +#: dmoj/urls.py:105 templates/base.html:190 msgid "Home" msgstr "메인" @@ -130,88 +130,86 @@ msgstr "코멘트 보이기" msgid "Associated page" msgstr "관련 페이지" -#: judge/admin/contest.py:30 +#: judge/admin/contest.py:28 msgid "Included contests" msgstr "포함된 대회" -#: judge/admin/contest.py:66 templates/contest/clarification.html:42 -#: templates/contest/contest.html:83 templates/contest/moss.html:43 -#: templates/problem/list.html:214 templates/problem/list.html:232 -#: templates/problem/list.html:350 templates/user/user-problems.html:56 +#: judge/admin/contest.py:64 templates/contest/contest.html:83 +#: templates/contest/moss.html:43 templates/problem/list.html:206 +#: templates/problem/list.html:221 templates/user/user-problems.html:56 #: templates/user/user-problems.html:98 msgid "Problem" msgstr "문제" -#: judge/admin/contest.py:119 +#: judge/admin/contest.py:112 msgid "Settings" msgstr "" -#: judge/admin/contest.py:121 +#: judge/admin/contest.py:114 msgid "Scheduling" msgstr "Scheduling" -#: judge/admin/contest.py:122 templates/organization/home.html:107 +#: judge/admin/contest.py:115 msgid "Details" msgstr "세부사항" -#: judge/admin/contest.py:123 +#: judge/admin/contest.py:116 msgid "Format" msgstr "" -#: judge/admin/contest.py:124 templates/contest/ranking-table.html:7 -#: templates/user/user-about.html:15 templates/user/user-about.html:45 +#: judge/admin/contest.py:117 templates/contest/ranking-table.html:5 msgid "Rating" msgstr "순위" -#: judge/admin/contest.py:125 +#: judge/admin/contest.py:118 msgid "Access" msgstr "" -#: judge/admin/contest.py:127 judge/admin/problem.py:131 +#: judge/admin/contest.py:120 judge/admin/problem.py:131 msgid "Justice" msgstr "정의" -#: judge/admin/contest.py:207 +#: judge/admin/contest.py:158 #, python-format msgid "%d contest successfully marked as visible." msgid_plural "%d contests successfully marked as visible." msgstr[0] "" -#: judge/admin/contest.py:210 +#: judge/admin/contest.py:161 msgid "Mark contests as visible" msgstr "" -#: judge/admin/contest.py:216 +#: judge/admin/contest.py:165 #, python-format msgid "%d contest successfully marked as hidden." msgid_plural "%d contests successfully marked as hidden." msgstr[0] "" -#: judge/admin/contest.py:219 +#: judge/admin/contest.py:168 msgid "Mark contests as hidden" msgstr "" -#: judge/admin/contest.py:233 judge/admin/submission.py:164 +#: judge/admin/contest.py:182 judge/admin/submission.py:164 #, python-format msgid "%d submission was successfully scheduled for rejudging." msgid_plural "%d submissions were successfully scheduled for rejudging." msgstr[0] "" -#: judge/admin/contest.py:308 +#: judge/admin/contest.py:256 #, python-format msgid "%d participation recalculated." msgid_plural "%d participations recalculated." msgstr[0] "" -#: judge/admin/contest.py:311 +#: judge/admin/contest.py:259 msgid "Recalculate results" msgstr "" -#: judge/admin/contest.py:315 judge/admin/organization.py:65 +#: judge/admin/contest.py:263 judge/admin/organization.py:65 msgid "username" msgstr "사용자 이름" -#: judge/admin/contest.py:320 templates/base.html:277 +#: judge/admin/contest.py:268 templates/base.html:260 msgid "virtual" msgstr "가상" @@ -219,15 +217,15 @@ msgstr "가상" msgid "link path" msgstr "링크 경로" -#: judge/admin/interface.py:65 +#: judge/admin/interface.py:62 msgid "Content" msgstr "내용" -#: judge/admin/interface.py:66 +#: judge/admin/interface.py:63 msgid "Summary" msgstr "요약" -#: judge/admin/interface.py:151 +#: judge/admin/interface.py:148 msgid "object" msgstr "" @@ -249,9 +247,8 @@ msgid "Taxonomy" msgstr "분류" #: judge/admin/problem.py:128 templates/contest/contest.html:84 -#: templates/problem/data.html:429 templates/problem/list.html:222 -#: templates/problem/list.html:248 templates/user/base-users-table.html:10 -#: templates/user/user-about.html:36 templates/user/user-about.html:52 +#: templates/problem/data.html:449 templates/problem/list.html:211 +#: templates/problem/list.html:232 templates/user/base-users-table.html:10 #: templates/user/user-problems.html:58 msgid "Points" msgstr "포인트" @@ -298,7 +295,6 @@ msgid "timezone" msgstr "" #: judge/admin/profile.py:86 judge/admin/submission.py:211 -#: templates/notification/list.html:12 #: templates/organization/requests/log.html:9 #: templates/organization/requests/pending.html:12 #: templates/ticket/list.html:263 @@ -306,7 +302,6 @@ msgid "User" msgstr "사용자" #: judge/admin/profile.py:91 templates/registration/registration_form.html:145 -#: templates/user/import/table_csv.html:8 msgid "Email" msgstr "이메일" @@ -338,7 +333,7 @@ msgstr "허가되지 않은 문제" msgid "These problems are NOT allowed to be submitted in this language" msgstr "이 문제는 이 언어로는 제출이 불가합니다." -#: judge/admin/runtime.py:83 templates/problem/list.html:352 +#: judge/admin/runtime.py:83 msgid "Description" msgstr "설명" @@ -385,7 +380,7 @@ msgstr "재채점 가능 개수를 초과하였습니다." msgid "Rejudge the selected submissions" msgstr "선택한 제출 재채점" -#: judge/admin/submission.py:193 judge/views/problem_manage.py:159 +#: judge/admin/submission.py:193 judge/views/problem_manage.py:128 #, python-format msgid "%d submission were successfully rescored." msgid_plural "%d submissions were successfully rescored." @@ -395,8 +390,7 @@ msgstr[0] "%d개의 제출이 성공적으로 재채점되었습니다." msgid "Rescore the selected submissions" msgstr "재채점" -#: judge/admin/submission.py:200 templates/problem/list.html:216 -#: templates/problem/list.html:236 +#: judge/admin/submission.py:200 msgid "Problem code" msgstr "문제 코드" @@ -404,12 +398,10 @@ msgstr "문제 코드" msgid "Problem name" msgstr "문제 이름" -#: judge/admin/submission.py:215 templates/notification/list.html:15 -#: templates/organization/requests/log.html:10 +#: judge/admin/submission.py:215 templates/organization/requests/log.html:10 #: templates/organization/requests/pending.html:13 -#: templates/problem/list.html:351 -#: templates/submission/status-testcases.html:125 -#: templates/submission/status-testcases.html:127 +#: templates/submission/status-testcases.html:105 +#: templates/submission/status-testcases.html:107 msgid "Time" msgstr "시간" @@ -423,7 +415,7 @@ msgstr "%d KB" msgid "%.2f MB" msgstr "%.2f MB" -#: judge/admin/submission.py:227 templates/submission/status-testcases.html:132 +#: judge/admin/submission.py:227 templates/submission/status-testcases.html:112 msgid "Memory" msgstr "Memory" @@ -443,20 +435,20 @@ msgstr "이 문제들은 이러한 문제 유형에 포함되어 있습니다." msgid "Online Judge" msgstr "Online Judge" -#: judge/comments.py:60 +#: judge/comments.py:41 msgid "Comment body" msgstr "코멘트 본문" -#: judge/comments.py:66 judge/views/ticket.py:63 +#: judge/comments.py:47 judge/views/ticket.py:46 msgid "Your part is silent, little toad." msgstr "침묵하세요." -#: judge/comments.py:69 templates/comments/list.html:132 +#: judge/comments.py:50 templates/comments/list.html:131 msgid "" "You need to have solved at least one problem before your voice can be heard." msgstr "최소 1개 이상의 문제를 해결해야 합니다." -#: judge/comments.py:113 +#: judge/comments.py:92 msgid "Posted comment" msgstr "게시된 코멘트" @@ -472,10 +464,6 @@ msgstr "" msgid "ECOO" msgstr "" -#: judge/contest_format/icpc.py:19 -msgid "ICPC" -msgstr "" - #: judge/contest_format/ioi.py:19 msgid "IOI" msgstr "" @@ -488,60 +476,52 @@ msgstr "대회 업데이트를 구독하세요." msgid "Enable experimental features" msgstr "베타 기능 활성화" -#: judge/forms.py:57 judge/views/organization.py:168 judge/views/register.py:49 +#: judge/forms.py:57 judge/views/organization.py:127 #, python-brace-format msgid "You may not be part of more than {count} public organizations." msgstr "{count}개보다 많은 공개 조직에 소속될 수 없습니다." -#: judge/forms.py:82 -#, fuzzy -#| msgid "judge" -msgid "Any judge" -msgstr "채점" - -#: judge/forms.py:112 judge/views/register.py:26 +#: judge/forms.py:107 judge/views/register.py:26 #: templates/registration/registration_form.html:139 #: templates/user/base-users-table.html:5 -#: templates/user/import/table_csv.html:4 msgid "Username" msgstr "사용자 이름" -#: judge/forms.py:113 templates/registration/registration_form.html:151 +#: judge/forms.py:108 templates/registration/registration_form.html:151 #: templates/registration/registration_form.html:165 -#: templates/user/import/table_csv.html:5 msgid "Password" msgstr "비밀번호" -#: judge/forms.py:135 +#: judge/forms.py:130 msgid "Two Factor Authentication tokens must be 6 decimal digits." msgstr "" -#: judge/forms.py:144 templates/registration/totp_auth.html:32 +#: judge/forms.py:139 templates/registration/totp_auth.html:32 msgid "Invalid Two Factor Authentication token." msgstr "" -#: judge/forms.py:148 judge/models/problem.py:97 +#: judge/forms.py:143 judge/models/problem.py:97 msgid "Problem code must be ^[a-z0-9]+$" msgstr "" -#: judge/forms.py:153 +#: judge/forms.py:148 msgid "Problem with code already exists." msgstr "" -#: judge/forms.py:158 judge/models/contest.py:61 +#: judge/forms.py:153 judge/models/contest.py:52 msgid "Contest id must be ^[a-z0-9]+$" msgstr "Contest id must be ^[a-z0-9]+$" -#: judge/forms.py:163 +#: judge/forms.py:158 msgid "Contest with key already exists." msgstr "" -#: judge/jinja2/datetime.py:26 templates/blog/blog.html:26 +#: judge/jinja2/datetime.py:26 templates/blog/content.html:27 #: templates/blog/dashboard.html:21 msgid "N j, Y, g:i a" msgstr "" -#: judge/jinja2/datetime.py:26 templates/chat/message.html:13 +#: judge/jinja2/datetime.py:26 #, python-brace-format msgid "{time}" msgstr "" @@ -571,260 +551,197 @@ msgstr "MathJax with SVG/PNG fallback" msgid "Detect best quality" msgstr "" -#: judge/models/comment.py:26 +#: judge/models/comment.py:25 msgid "Page code must be ^[pcs]:[a-z0-9]+$|^b:\\d+$" msgstr "" -#: judge/models/comment.py:42 +#: judge/models/comment.py:41 msgid "commenter" msgstr "코멘터" -#: judge/models/comment.py:44 judge/models/comment.py:177 +#: judge/models/comment.py:43 judge/models/comment.py:176 msgid "associated page" msgstr "" -#: judge/models/comment.py:46 +#: judge/models/comment.py:45 msgid "votes" msgstr "표" -#: judge/models/comment.py:48 +#: judge/models/comment.py:47 msgid "hide the comment" msgstr "코멘트 숨기기" -#: judge/models/comment.py:49 +#: judge/models/comment.py:48 msgid "parent" msgstr "부모" -#: judge/models/comment.py:54 judge/models/comment.py:192 +#: judge/models/comment.py:53 msgid "comment" msgstr "코멘트" -#: judge/models/comment.py:55 +#: judge/models/comment.py:54 msgid "comments" msgstr "코멘트" -#: judge/models/comment.py:137 judge/models/problem.py:443 +#: judge/models/comment.py:136 judge/models/problem.py:406 #, python-format msgid "Editorial for %s" msgstr "" -#: judge/models/comment.py:172 +#: judge/models/comment.py:171 msgid "comment vote" msgstr "코멘트 투표" -#: judge/models/comment.py:173 +#: judge/models/comment.py:172 msgid "comment votes" msgstr "코멘트 투표" -#: judge/models/comment.py:182 +#: judge/models/comment.py:181 msgid "Override comment lock" msgstr "" -#: judge/models/comment.py:190 -msgid "owner" -msgstr "" - -#: judge/models/comment.py:193 judge/models/message.py:16 -msgid "read" -msgstr "읽음" - -#: judge/models/comment.py:194 -msgid "category" -msgstr "" - -#: judge/models/comment.py:195 -msgid "html link to comments, used for non-comments" -msgstr "" - -#: judge/models/comment.py:196 -msgid "who trigger, used for non-comment" -msgstr "" - -#: judge/models/contest.py:23 +#: judge/models/contest.py:22 msgid "Invalid colour." msgstr "잘못된 색상" -#: judge/models/contest.py:25 +#: judge/models/contest.py:24 msgid "tag name" msgstr "태그 이름" -#: judge/models/contest.py:26 +#: judge/models/contest.py:25 msgid "Lowercase letters and hyphens only." msgstr "소문자와 하이픈만 사용가능합니다." -#: judge/models/contest.py:27 +#: judge/models/contest.py:26 msgid "tag colour" msgstr "태그 색상" -#: judge/models/contest.py:28 +#: judge/models/contest.py:27 msgid "tag description" msgstr "태그 설명" -#: judge/models/contest.py:47 +#: judge/models/contest.py:46 msgid "contest tag" msgstr "대회 태그" -#: judge/models/contest.py:48 judge/models/contest.py:118 +#: judge/models/contest.py:47 judge/models/contest.py:101 msgid "contest tags" msgstr "대회 태그" -#: judge/models/contest.py:56 -msgid "Visible" -msgstr "" - -#: judge/models/contest.py:57 -msgid "Hidden for duration of contest" -msgstr "" - -#: judge/models/contest.py:58 -#, fuzzy -#| msgid "virtual participation id" -msgid "Hidden for duration of participation" -msgstr "가상 참여 id" - -#: judge/models/contest.py:60 +#: judge/models/contest.py:51 msgid "contest id" msgstr "대회 id" -#: judge/models/contest.py:62 +#: judge/models/contest.py:53 msgid "contest name" msgstr "대회 이름" -#: judge/models/contest.py:63 -#, fuzzy -#| msgid "These people will be able to edit the contest." -msgid "These users will be able to edit the contest." +#: judge/models/contest.py:54 +msgid "These people will be able to edit the contest." msgstr "이 사람들은 대회를 편집할 권한이 있습니다." -#: judge/models/contest.py:65 -#, fuzzy -#| msgid "These people will be able to edit the contest." -msgid "" -"These users will be able to edit the contest, but will not be listed as " -"authors." -msgstr "이 사람들은 대회를 편집할 권한이 있습니다." - -#: judge/models/contest.py:68 -#, fuzzy -#| msgid "These people will be able to edit the contest." -msgid "These users will be able to view the contest, but not edit it." -msgstr "이 사람들은 대회를 편집할 권한이 있습니다." - -#: judge/models/contest.py:71 judge/models/runtime.py:136 +#: judge/models/contest.py:56 judge/models/runtime.py:133 msgid "description" msgstr "설명" -#: judge/models/contest.py:72 judge/models/problem.py:390 -#: judge/models/runtime.py:138 +#: judge/models/contest.py:57 judge/models/problem.py:353 +#: judge/models/runtime.py:135 msgid "problems" msgstr "문제" -#: judge/models/contest.py:73 judge/models/contest.py:404 +#: judge/models/contest.py:58 judge/models/contest.py:258 msgid "start time" msgstr "시작 시각" -#: judge/models/contest.py:74 +#: judge/models/contest.py:59 msgid "end time" msgstr "종료 시각" -#: judge/models/contest.py:75 judge/models/problem.py:118 -#: judge/models/problem.py:414 +#: judge/models/contest.py:60 judge/models/problem.py:118 +#: judge/models/problem.py:377 msgid "time limit" msgstr "시간 제한" -#: judge/models/contest.py:76 judge/models/problem.py:136 +#: judge/models/contest.py:61 judge/models/problem.py:136 msgid "publicly visible" msgstr "공개" -#: judge/models/contest.py:77 +#: judge/models/contest.py:62 msgid "" "Should be set even for organization-private contests, where it determines " "whether the contest is visible to members of the specified organizations." msgstr "" -#: judge/models/contest.py:80 +#: judge/models/contest.py:65 msgid "contest rated" msgstr "대회 순위" -#: judge/models/contest.py:80 +#: judge/models/contest.py:65 msgid "Whether this contest can be rated." msgstr "대회 순위 표시 여부" -#: judge/models/contest.py:82 -#, fuzzy -#| msgid "public visibility" -msgid "scoreboard visibility" -msgstr "공개 여부" - -#: judge/models/contest.py:83 -msgid "Scoreboard visibility through the duration of the contest" +#: judge/models/contest.py:67 +msgid "hide scoreboard" msgstr "" -#: judge/models/contest.py:85 -#, fuzzy -#| msgid "contest rated" -msgid "view contest scoreboard" -msgstr "대회 순위" +#: judge/models/contest.py:68 +msgid "" +"Whether the scoreboard should remain hidden for the duration of the contest." +msgstr "" -#: judge/models/contest.py:87 -#, fuzzy -#| msgid "These people will be able to edit the contest." -msgid "These users will be able to view the scoreboard." -msgstr "이 사람들은 대회를 편집할 권한이 있습니다." - -#: judge/models/contest.py:88 +#: judge/models/contest.py:71 msgid "no comments" msgstr "코멘트 없음" -#: judge/models/contest.py:89 +#: judge/models/contest.py:72 msgid "Use clarification system instead of comments." msgstr "코멘트 대신 수정 시스템을 사용하세요." -#: judge/models/contest.py:91 +#: judge/models/contest.py:74 msgid "Rating floor for contest" msgstr "" -#: judge/models/contest.py:93 +#: judge/models/contest.py:76 msgid "Rating ceiling for contest" msgstr "" -#: judge/models/contest.py:95 +#: judge/models/contest.py:78 msgid "rate all" msgstr "모든 순위" -#: judge/models/contest.py:95 +#: judge/models/contest.py:78 msgid "Rate all users who joined." msgstr "참가한 모든 사용자에 대한 순위" -#: judge/models/contest.py:96 +#: judge/models/contest.py:79 msgid "exclude from ratings" msgstr "순위에서 제외" -#: judge/models/contest.py:98 +#: judge/models/contest.py:81 msgid "private to specific users" msgstr "" -#: judge/models/contest.py:99 +#: judge/models/contest.py:82 msgid "private contestants" msgstr "" -#: judge/models/contest.py:100 +#: judge/models/contest.py:83 msgid "If private, only these users may see the contest" msgstr "" -#: judge/models/contest.py:102 +#: judge/models/contest.py:85 msgid "hide problem tags" msgstr "문제 태그 숨기기" -#: judge/models/contest.py:103 +#: judge/models/contest.py:86 msgid "Whether problem tags should be hidden by default." msgstr "문제 태그 공개 여부 기본값" -#: judge/models/contest.py:105 +#: judge/models/contest.py:88 msgid "run pretests only" msgstr "pretests만 실행" -#: judge/models/contest.py:106 +#: judge/models/contest.py:89 msgid "" "Whether judges should grade pretests only, versus all testcases. Commonly " "set during a contest, then unset prior to rejudging user submissions when " @@ -833,302 +750,277 @@ msgstr "" "judge가 pretests만 채점할지, 모든 테스트 데이터를 채점할지 여부. 일반적으로 " "대회 종료전까지 설정 후 대회 종료 후 해제하여 모든 테스트 케이스 채점 진행" -#: judge/models/contest.py:110 judge/models/interface.py:77 -#: judge/models/problem.py:157 +#: judge/models/contest.py:93 judge/models/problem.py:157 msgid "private to organizations" msgstr "조직에 비공개" -#: judge/models/contest.py:111 judge/models/interface.py:75 -#: judge/models/problem.py:155 judge/models/profile.py:77 +#: judge/models/contest.py:94 judge/models/problem.py:155 +#: judge/models/profile.py:77 msgid "organizations" msgstr "조직" -#: judge/models/contest.py:112 +#: judge/models/contest.py:95 msgid "If private, only these organizations may see the contest" msgstr "비공개로 설정 시, 이 조직만 대회를 볼 수 있습니다." -#: judge/models/contest.py:113 judge/models/problem.py:145 +#: judge/models/contest.py:96 judge/models/problem.py:145 msgid "OpenGraph image" msgstr "OpenGraph 이미지" -#: judge/models/contest.py:114 judge/models/profile.py:48 +#: judge/models/contest.py:97 judge/models/profile.py:48 msgid "Logo override image" msgstr "" -#: judge/models/contest.py:116 +#: judge/models/contest.py:99 msgid "" "This image will replace the default site logo for users inside the contest." msgstr "" -#: judge/models/contest.py:119 +#: judge/models/contest.py:102 msgid "the amount of live participants" msgstr "현재 접속되어 있는 참가자 수" -#: judge/models/contest.py:120 +#: judge/models/contest.py:103 msgid "contest summary" msgstr "대회 요약" -#: judge/models/contest.py:121 judge/models/problem.py:147 +#: judge/models/contest.py:104 judge/models/problem.py:147 msgid "Plain-text, shown in meta description tag, e.g. for social media." msgstr "" -#: judge/models/contest.py:122 judge/models/profile.py:47 +#: judge/models/contest.py:105 judge/models/profile.py:47 msgid "access code" msgstr "액세스 코드" -#: judge/models/contest.py:123 +#: judge/models/contest.py:106 msgid "" "An optional code to prompt contestants before they are allowed to join the " "contest. Leave it blank to disable." msgstr "" -#: judge/models/contest.py:125 judge/models/problem.py:141 +#: judge/models/contest.py:108 judge/models/problem.py:141 msgid "personae non gratae" msgstr "" -#: judge/models/contest.py:126 +#: judge/models/contest.py:109 msgid "Bans the selected users from joining this contest." msgstr "" -#: judge/models/contest.py:127 +#: judge/models/contest.py:110 msgid "contest format" msgstr "" -#: judge/models/contest.py:128 +#: judge/models/contest.py:111 msgid "The contest format module to use." msgstr "" -#: judge/models/contest.py:129 +#: judge/models/contest.py:112 msgid "contest format configuration" msgstr "" -#: judge/models/contest.py:130 +#: judge/models/contest.py:113 msgid "" "A JSON object to serve as the configuration for the chosen contest format " "module. Leave empty to use None. Exact format depends on the contest format " "selected." msgstr "" -#: judge/models/contest.py:137 -#, fuzzy -#| msgid "test case points" -msgid "precision points" -msgstr "테스크 케이스 점수" - -#: judge/models/contest.py:139 -msgid "Number of digits to round points to." -msgstr "" - -#: judge/models/contest.py:383 +#: judge/models/contest.py:239 msgid "See private contests" msgstr "" -#: judge/models/contest.py:384 +#: judge/models/contest.py:240 msgid "Edit own contests" msgstr "" -#: judge/models/contest.py:385 +#: judge/models/contest.py:241 msgid "Edit all contests" msgstr "" -#: judge/models/contest.py:386 +#: judge/models/contest.py:242 msgid "Clone contest" msgstr "" -#: judge/models/contest.py:387 templates/contest/moss.html:74 +#: judge/models/contest.py:243 templates/contest/moss.html:74 msgid "MOSS contest" msgstr "" -#: judge/models/contest.py:388 +#: judge/models/contest.py:244 msgid "Rate contests" msgstr "" -#: judge/models/contest.py:389 +#: judge/models/contest.py:245 msgid "Contest access codes" msgstr "" -#: judge/models/contest.py:390 +#: judge/models/contest.py:246 msgid "Create private contests" msgstr "" -#: judge/models/contest.py:391 -msgid "Change contest visibility" -msgstr "" - -#: judge/models/contest.py:392 -#, fuzzy -#| msgid "contest problems" -msgid "Edit contest problem label script" -msgstr "대회 문제" - -#: judge/models/contest.py:394 judge/models/contest.py:492 -#: judge/models/contest.py:529 judge/models/contest.py:552 -#: judge/models/submission.py:84 +#: judge/models/contest.py:248 judge/models/contest.py:345 +#: judge/models/contest.py:382 judge/models/contest.py:404 +#: judge/models/submission.py:83 msgid "contest" msgstr "대회" -#: judge/models/contest.py:395 +#: judge/models/contest.py:249 msgid "contests" msgstr "대회" -#: judge/models/contest.py:402 +#: judge/models/contest.py:256 msgid "associated contest" msgstr "관련된 대회" -#: judge/models/contest.py:405 +#: judge/models/contest.py:259 msgid "score" msgstr "점수" -#: judge/models/contest.py:406 +#: judge/models/contest.py:260 msgid "cumulative time" msgstr "누적 시간" -#: judge/models/contest.py:407 +#: judge/models/contest.py:261 msgid "is disqualified" msgstr "" -#: judge/models/contest.py:408 +#: judge/models/contest.py:262 msgid "Whether this participation is disqualified." msgstr "" -#: judge/models/contest.py:409 -msgid "tie-breaking field" -msgstr "" - -#: judge/models/contest.py:410 +#: judge/models/contest.py:263 msgid "virtual participation id" msgstr "가상 참여 id" -#: judge/models/contest.py:411 +#: judge/models/contest.py:264 msgid "0 means non-virtual, otherwise the n-th virtual participation." msgstr "" -#: judge/models/contest.py:412 +#: judge/models/contest.py:265 msgid "contest format specific data" msgstr "" -#: judge/models/contest.py:478 +#: judge/models/contest.py:331 #, python-format msgid "%s spectating in %s" msgstr "" -#: judge/models/contest.py:480 +#: judge/models/contest.py:333 #, python-format msgid "%s in %s, v%d" msgstr "" -#: judge/models/contest.py:481 +#: judge/models/contest.py:334 #, python-format msgid "%s in %s" msgstr "%s에서 %s" -#: judge/models/contest.py:484 +#: judge/models/contest.py:337 msgid "contest participation" msgstr "대회 참가" -#: judge/models/contest.py:485 +#: judge/models/contest.py:338 msgid "contest participations" msgstr "대회 참가자" -#: judge/models/contest.py:491 judge/models/contest.py:513 -#: judge/models/contest.py:553 judge/models/problem.py:389 -#: judge/models/problem.py:394 judge/models/problem.py:412 -#: judge/models/problem_data.py:40 +#: judge/models/contest.py:344 judge/models/contest.py:366 +#: judge/models/contest.py:405 judge/models/problem.py:352 +#: judge/models/problem.py:357 judge/models/problem.py:375 +#: judge/models/problem_data.py:38 msgid "problem" msgstr "문제" -#: judge/models/contest.py:493 judge/models/contest.py:517 +#: judge/models/contest.py:346 judge/models/contest.py:370 #: judge/models/problem.py:129 msgid "points" msgstr "점수" -#: judge/models/contest.py:494 +#: judge/models/contest.py:347 msgid "partial" msgstr "부분" -#: judge/models/contest.py:495 judge/models/contest.py:518 +#: judge/models/contest.py:348 judge/models/contest.py:371 msgid "is pretested" msgstr "pretested 됨" -#: judge/models/contest.py:496 judge/models/interface.py:43 +#: judge/models/contest.py:349 judge/models/interface.py:43 msgid "order" msgstr "순서" -#: judge/models/contest.py:497 +#: judge/models/contest.py:350 msgid "0 to not show testcases, 1 to show" msgstr "" -#: judge/models/contest.py:498 +#: judge/models/contest.py:351 #, fuzzy #| msgid "submission test cases" msgid "visible testcases" msgstr "제출 테스트 케이스" -#: judge/models/contest.py:499 +#: judge/models/contest.py:352 msgid "Maximum number of submissions for this problem, or 0 for no limit." msgstr "" -#: judge/models/contest.py:501 +#: judge/models/contest.py:354 msgid "Why include a problem you can't submit to?" msgstr "" -#: judge/models/contest.py:506 +#: judge/models/contest.py:359 msgid "contest problem" msgstr "대회 문제" -#: judge/models/contest.py:507 +#: judge/models/contest.py:360 msgid "contest problems" msgstr "대회 문제" -#: judge/models/contest.py:511 judge/models/submission.py:183 +#: judge/models/contest.py:364 judge/models/submission.py:181 msgid "submission" msgstr "제출" -#: judge/models/contest.py:515 judge/models/contest.py:530 +#: judge/models/contest.py:368 judge/models/contest.py:383 msgid "participation" msgstr "참가 여부" -#: judge/models/contest.py:519 +#: judge/models/contest.py:372 msgid "Whether this submission was ran only on pretests." msgstr "Pretests에서만 이 제출이 실행되었는지 여부" -#: judge/models/contest.py:523 +#: judge/models/contest.py:376 msgid "contest submission" msgstr "대회 제출" -#: judge/models/contest.py:524 +#: judge/models/contest.py:377 msgid "contest submissions" msgstr "대회 제출" -#: judge/models/contest.py:532 +#: judge/models/contest.py:385 msgid "rank" msgstr "등수" -#: judge/models/contest.py:533 +#: judge/models/contest.py:386 msgid "rating" msgstr "순위" -#: judge/models/contest.py:534 +#: judge/models/contest.py:387 msgid "volatility" msgstr "변동" -#: judge/models/contest.py:535 +#: judge/models/contest.py:388 msgid "last rated" msgstr "최근 순위" -#: judge/models/contest.py:539 +#: judge/models/contest.py:392 msgid "contest rating" msgstr "대회 순위" -#: judge/models/contest.py:540 +#: judge/models/contest.py:393 msgid "contest ratings" msgstr "대회 순위" -#: judge/models/contest.py:560 +#: judge/models/contest.py:412 msgid "contest moss result" msgstr "" -#: judge/models/contest.py:561 +#: judge/models/contest.py:413 msgid "contest moss results" msgstr "" @@ -1168,7 +1060,7 @@ msgstr "부모 항목" msgid "post title" msgstr "게시물 제목" -#: judge/models/interface.py:67 judge/models/problem.py:432 +#: judge/models/interface.py:67 judge/models/problem.py:395 msgid "authors" msgstr "저자" @@ -1176,7 +1068,7 @@ msgstr "저자" msgid "slug" msgstr "slug" -#: judge/models/interface.py:69 judge/models/problem.py:430 +#: judge/models/interface.py:69 judge/models/problem.py:393 msgid "public visibility" msgstr "공개 여부" @@ -1200,21 +1092,15 @@ msgstr "게시물 요약" msgid "openGraph image" msgstr "openGraph 이미지" -#: judge/models/interface.py:76 -#, fuzzy -#| msgid "If private, only these organizations may see the contest" -msgid "If private, only these organizations may see the blog post." -msgstr "비공개로 설정 시, 이 조직만 대회를 볼 수 있습니다." - -#: judge/models/interface.py:105 +#: judge/models/interface.py:91 msgid "Edit all posts" msgstr "" -#: judge/models/interface.py:107 +#: judge/models/interface.py:93 msgid "blog post" msgstr "블로그 게시물" -#: judge/models/interface.py:108 +#: judge/models/interface.py:94 msgid "blog posts" msgstr "블로그 게시물" @@ -1238,6 +1124,10 @@ msgstr "대상" msgid "message timestamp" msgstr "메시지 타임스탬프" +#: judge/models/message.py:16 +msgid "read" +msgstr "읽음" + #: judge/models/message.py:20 msgid "messages in the thread" msgstr "messages in the thread" @@ -1374,7 +1264,7 @@ msgid "" "are supported." msgstr "" -#: judge/models/problem.py:123 judge/models/problem.py:417 +#: judge/models/problem.py:123 judge/models/problem.py:380 msgid "memory limit" msgstr "메모리 제한" @@ -1447,188 +1337,188 @@ msgstr "" msgid "If private, only these organizations may see the problem." msgstr "" -#: judge/models/problem.py:395 judge/models/problem.py:413 -#: judge/models/runtime.py:111 +#: judge/models/problem.py:358 judge/models/problem.py:376 +#: judge/models/runtime.py:108 msgid "language" msgstr "언어" -#: judge/models/problem.py:396 +#: judge/models/problem.py:359 msgid "translated name" msgstr "번역된 이름" -#: judge/models/problem.py:397 +#: judge/models/problem.py:360 msgid "translated description" msgstr "번역된 설명" -#: judge/models/problem.py:401 +#: judge/models/problem.py:364 msgid "problem translation" msgstr "문제 번역" -#: judge/models/problem.py:402 +#: judge/models/problem.py:365 msgid "problem translations" msgstr "문제 번역" -#: judge/models/problem.py:406 +#: judge/models/problem.py:369 msgid "clarified problem" msgstr "수정된 문제" -#: judge/models/problem.py:407 +#: judge/models/problem.py:370 msgid "clarification body" msgstr "수정사항" -#: judge/models/problem.py:408 +#: judge/models/problem.py:371 msgid "clarification timestamp" msgstr "수정 타임스탬프" -#: judge/models/problem.py:423 +#: judge/models/problem.py:386 msgid "language-specific resource limit" msgstr "특정 언어 리소스 제한" -#: judge/models/problem.py:424 +#: judge/models/problem.py:387 msgid "language-specific resource limits" msgstr "특정 언어 리소스 제한" -#: judge/models/problem.py:428 +#: judge/models/problem.py:391 msgid "associated problem" msgstr "관련된 문제" -#: judge/models/problem.py:431 +#: judge/models/problem.py:394 msgid "publish date" msgstr "" -#: judge/models/problem.py:433 +#: judge/models/problem.py:396 msgid "editorial content" msgstr "" -#: judge/models/problem.py:449 +#: judge/models/problem.py:412 msgid "solution" msgstr "솔루션" -#: judge/models/problem.py:450 +#: judge/models/problem.py:413 msgid "solutions" msgstr "솔루션" -#: judge/models/problem_data.py:26 +#: judge/models/problem_data.py:24 msgid "Standard" msgstr "표준" -#: judge/models/problem_data.py:27 +#: judge/models/problem_data.py:25 msgid "Floats" msgstr "Floats" -#: judge/models/problem_data.py:28 +#: judge/models/problem_data.py:26 msgid "Floats (absolute)" msgstr "Floats (absolute)" -#: judge/models/problem_data.py:29 +#: judge/models/problem_data.py:27 msgid "Floats (relative)" msgstr "Floats (relative)" -#: judge/models/problem_data.py:30 +#: judge/models/problem_data.py:28 msgid "Non-trailing spaces" msgstr "" -#: judge/models/problem_data.py:31 +#: judge/models/problem_data.py:29 msgid "Unordered" msgstr "정렬되지 않은" -#: judge/models/problem_data.py:32 +#: judge/models/problem_data.py:30 msgid "Byte identical" msgstr "바이트 단위로 동일" -#: judge/models/problem_data.py:33 +#: judge/models/problem_data.py:31 msgid "Line-by-line" msgstr "" -#: judge/models/problem_data.py:34 +#: judge/models/problem_data.py:32 msgid "Custom checker (PY)" msgstr "" -#: judge/models/problem_data.py:35 +#: judge/models/problem_data.py:33 msgid "Custom validator (CPP)" msgstr "" -#: judge/models/problem_data.py:42 +#: judge/models/problem_data.py:40 msgid "data zip file" msgstr "채점 데이터 파일" -#: judge/models/problem_data.py:44 +#: judge/models/problem_data.py:42 msgid "generator file" msgstr "generator 파일" -#: judge/models/problem_data.py:46 judge/models/problem_data.py:121 +#: judge/models/problem_data.py:44 judge/models/problem_data.py:110 msgid "output prefix length" msgstr "출력 접두사 길이" -#: judge/models/problem_data.py:47 judge/models/problem_data.py:122 +#: judge/models/problem_data.py:45 judge/models/problem_data.py:111 msgid "output limit length" msgstr "출력 길이 제한" -#: judge/models/problem_data.py:48 +#: judge/models/problem_data.py:46 msgid "init.yml generation feedback" msgstr "init.yml generation 피드백" -#: judge/models/problem_data.py:49 judge/models/problem_data.py:123 +#: judge/models/problem_data.py:47 judge/models/problem_data.py:112 msgid "checker" msgstr "checker" -#: judge/models/problem_data.py:50 judge/models/problem_data.py:124 +#: judge/models/problem_data.py:48 judge/models/problem_data.py:113 msgid "checker arguments" msgstr "checker arguments" -#: judge/models/problem_data.py:51 judge/models/problem_data.py:125 +#: judge/models/problem_data.py:49 judge/models/problem_data.py:114 msgid "checker arguments as a JSON object" msgstr "checker arguments as a JSON object" -#: judge/models/problem_data.py:52 +#: judge/models/problem_data.py:50 msgid "custom checker file" msgstr "" -#: judge/models/problem_data.py:58 +#: judge/models/problem_data.py:56 msgid "custom validator file" msgstr "" -#: judge/models/problem_data.py:108 +#: judge/models/problem_data.py:97 msgid "problem data set" msgstr "채점 데이터" -#: judge/models/problem_data.py:110 +#: judge/models/problem_data.py:99 msgid "case position" msgstr "case position" -#: judge/models/problem_data.py:111 +#: judge/models/problem_data.py:100 msgid "case type" msgstr "데이터 유형" -#: judge/models/problem_data.py:112 +#: judge/models/problem_data.py:101 msgid "Normal case" msgstr "일반 테스트 케이스" -#: judge/models/problem_data.py:113 +#: judge/models/problem_data.py:102 msgid "Batch start" msgstr "Batch 시작" -#: judge/models/problem_data.py:114 +#: judge/models/problem_data.py:103 msgid "Batch end" msgstr "Batch 종료" -#: judge/models/problem_data.py:116 +#: judge/models/problem_data.py:105 msgid "input file name" msgstr "입력 파일 이름" -#: judge/models/problem_data.py:117 +#: judge/models/problem_data.py:106 msgid "output file name" msgstr "출력 파일 이름" -#: judge/models/problem_data.py:118 +#: judge/models/problem_data.py:107 msgid "generator arguments" msgstr "" -#: judge/models/problem_data.py:119 +#: judge/models/problem_data.py:108 msgid "point value" msgstr "" -#: judge/models/problem_data.py:120 +#: judge/models/problem_data.py:109 msgid "case is pretest?" msgstr "" @@ -1701,7 +1591,7 @@ msgid "" msgstr "" #: judge/models/profile.py:76 judge/models/profile.py:93 -#: judge/models/profile.py:212 +#: judge/models/profile.py:192 msgid "organization" msgstr "조직" @@ -1797,31 +1687,31 @@ msgstr "" msgid "Notes for administrators regarding this user." msgstr "" -#: judge/models/profile.py:206 +#: judge/models/profile.py:186 msgid "user profile" msgstr "사용자 프로파일" -#: judge/models/profile.py:207 +#: judge/models/profile.py:187 msgid "user profiles" msgstr "사용자 프로파일" -#: judge/models/profile.py:214 +#: judge/models/profile.py:194 msgid "request time" msgstr "요청 시간" -#: judge/models/profile.py:215 +#: judge/models/profile.py:195 msgid "state" msgstr "상태" -#: judge/models/profile.py:220 +#: judge/models/profile.py:200 msgid "reason" msgstr "이유" -#: judge/models/profile.py:223 +#: judge/models/profile.py:203 msgid "organization join request" msgstr "조직 가입 요청" -#: judge/models/profile.py:224 +#: judge/models/profile.py:204 msgid "organization join requests" msgstr "조직 가입 요청" @@ -1912,88 +1802,88 @@ msgstr "확장" msgid "The extension of source files, e.g., \"py\" or \"cpp\"." msgstr "소스 파일 확장자" -#: judge/models/runtime.py:112 +#: judge/models/runtime.py:109 msgid "languages" msgstr "언어" -#: judge/models/runtime.py:116 +#: judge/models/runtime.py:113 msgid "language to which this runtime belongs" msgstr "이 런타임에 속해 있는 언어" -#: judge/models/runtime.py:117 +#: judge/models/runtime.py:114 msgid "judge on which this runtime exists" msgstr "judge on which this runtime exists" -#: judge/models/runtime.py:118 +#: judge/models/runtime.py:115 msgid "runtime name" msgstr "런타임 이름" -#: judge/models/runtime.py:119 +#: judge/models/runtime.py:116 msgid "runtime version" msgstr "런타임 버전" -#: judge/models/runtime.py:120 +#: judge/models/runtime.py:117 msgid "order in which to display this runtime" msgstr "런타임 표시 순서" -#: judge/models/runtime.py:124 +#: judge/models/runtime.py:121 msgid "Server name, hostname-style" msgstr "서버 이름" -#: judge/models/runtime.py:125 +#: judge/models/runtime.py:122 msgid "time of creation" msgstr "생성 날짜" -#: judge/models/runtime.py:126 +#: judge/models/runtime.py:123 #, fuzzy #| msgid "A key to authenticated this judge" msgid "A key to authenticate this judge" msgstr "A key to authenticated this judge" -#: judge/models/runtime.py:127 +#: judge/models/runtime.py:124 msgid "authentication key" msgstr "authentication key" -#: judge/models/runtime.py:128 +#: judge/models/runtime.py:125 msgid "block judge" msgstr "" -#: judge/models/runtime.py:129 +#: judge/models/runtime.py:126 msgid "" "Whether this judge should be blocked from connecting, even if its key is " "correct." msgstr "" -#: judge/models/runtime.py:131 +#: judge/models/runtime.py:128 msgid "judge online status" msgstr "judge 상태" -#: judge/models/runtime.py:132 +#: judge/models/runtime.py:129 msgid "judge start time" msgstr "judge 시작 시간" -#: judge/models/runtime.py:133 +#: judge/models/runtime.py:130 msgid "response time" msgstr "응답 시간" -#: judge/models/runtime.py:134 +#: judge/models/runtime.py:131 msgid "system load" msgstr "시스템 로드" -#: judge/models/runtime.py:135 +#: judge/models/runtime.py:132 msgid "Load for the last minute, divided by processors to be fair." msgstr "1분간의 로드율(프로세서 수로 나눔)" -#: judge/models/runtime.py:139 judge/models/runtime.py:179 +#: judge/models/runtime.py:136 judge/models/runtime.py:176 msgid "judges" msgstr "채점기" -#: judge/models/runtime.py:178 +#: judge/models/runtime.py:175 msgid "judge" msgstr "채점" #: judge/models/submission.py:20 judge/models/submission.py:47 -#: judge/utils/problems.py:79 +#: judge/utils/problems.py:77 msgid "Accepted" msgstr "통과" @@ -2022,7 +1912,7 @@ msgid "Runtime Error" msgstr "런타임 에러" #: judge/models/submission.py:27 judge/models/submission.py:41 -#: judge/models/submission.py:55 judge/utils/problems.py:81 +#: judge/models/submission.py:55 judge/utils/problems.py:79 msgid "Compile Error" msgstr "컴파일 에러" @@ -2063,15 +1953,15 @@ msgstr "" msgid "submission time" msgstr "제출 시간" -#: judge/models/submission.py:67 judge/models/submission.py:203 +#: judge/models/submission.py:67 judge/models/submission.py:201 msgid "execution time" msgstr "실행 시간" -#: judge/models/submission.py:68 judge/models/submission.py:204 +#: judge/models/submission.py:68 judge/models/submission.py:202 msgid "memory usage" msgstr "메모리 사용량" -#: judge/models/submission.py:69 judge/models/submission.py:205 +#: judge/models/submission.py:69 judge/models/submission.py:203 msgid "points granted" msgstr "획득 포인트" @@ -2108,64 +1998,58 @@ msgid "judged on" msgstr "" #: judge/models/submission.py:81 -#, fuzzy -#| msgid "submission time" -msgid "submission judge time" -msgstr "제출 시간" - -#: judge/models/submission.py:82 msgid "was rejudged by admin" msgstr "관리자에 의해 재채점" -#: judge/models/submission.py:83 +#: judge/models/submission.py:82 msgid "was ran on pretests only" msgstr "pretest에서만 채점됨" -#: judge/models/submission.py:184 templates/contest/moss.html:58 +#: judge/models/submission.py:182 templates/contest/moss.html:58 msgid "submissions" msgstr "제출" -#: judge/models/submission.py:188 judge/models/submission.py:199 +#: judge/models/submission.py:186 judge/models/submission.py:197 msgid "associated submission" msgstr "관련된 제출" -#: judge/models/submission.py:190 +#: judge/models/submission.py:188 msgid "source code" msgstr "소스 코드" -#: judge/models/submission.py:201 +#: judge/models/submission.py:199 msgid "test case ID" msgstr "test case ID" -#: judge/models/submission.py:202 +#: judge/models/submission.py:200 msgid "status flag" msgstr "상태 flag" -#: judge/models/submission.py:206 +#: judge/models/submission.py:204 msgid "points possible" msgstr "획득 가능한 포인트" -#: judge/models/submission.py:207 +#: judge/models/submission.py:205 msgid "batch number" msgstr "batch number" -#: judge/models/submission.py:208 +#: judge/models/submission.py:206 msgid "judging feedback" msgstr "채점 피드백" -#: judge/models/submission.py:209 +#: judge/models/submission.py:207 msgid "extended judging feedback" msgstr "" -#: judge/models/submission.py:210 +#: judge/models/submission.py:208 msgid "program output" msgstr "프로그램 출력" -#: judge/models/submission.py:218 +#: judge/models/submission.py:216 msgid "submission test case" msgstr "제출 테스트 케이스" -#: judge/models/submission.py:219 +#: judge/models/submission.py:217 msgid "submission test cases" msgstr "제출 테스트 케이스" @@ -2217,24 +2101,12 @@ msgstr "포스터" msgid "message time" msgstr "메시지 시간" -#: judge/pdf_problems.py:147 judge/pdf_problems.py:199 -#: judge/pdf_problems.py:259 +#: judge/pdf_problems.py:134 judge/pdf_problems.py:186 +#: judge/pdf_problems.py:246 msgid "Page [page] of [topage]" msgstr "[topage]의 페이지 [page]" -#: judge/pdf_problems.py:280 -#, fuzzy, python-format -#| msgid "Page %d of Posts" -msgid "Page %s of %s" -msgstr "게시물 %d 페이지" - -#: judge/tasks/contest.py:19 -#, fuzzy -#| msgid "Recalculate scores" -msgid "Recalculating contest scores" -msgstr "점수 재계산" - -#: judge/tasks/contest.py:40 +#: judge/tasks/moss.py:25 msgid "Running MOSS" msgstr "" @@ -2246,62 +2118,62 @@ msgstr "" msgid "Recalculating user points" msgstr "" -#: judge/utils/problem_data.py:70 +#: judge/utils/problem_data.py:68 msgid "Empty batches not allowed." msgstr "빈 batches는 허용되지 않습니다." -#: judge/utils/problem_data.py:78 judge/utils/problem_data.py:99 +#: judge/utils/problem_data.py:76 judge/utils/problem_data.py:97 #, fuzzy #| msgid "How did you corrupt the zip path?" msgid "How did you corrupt the custom checker path?" msgstr "압축 파일 경로를 어떻게 손상하셨나요?" -#: judge/utils/problem_data.py:120 +#: judge/utils/problem_data.py:118 #, python-format msgid "Points must be defined for non-batch case #%d." msgstr "" -#: judge/utils/problem_data.py:125 +#: judge/utils/problem_data.py:123 #, python-format msgid "Input file for case %d does not exist: %s" msgstr "테스트 케이스 %d에 대한 입력 파일이 존재하지 않습니다.: %s" -#: judge/utils/problem_data.py:128 +#: judge/utils/problem_data.py:126 #, python-format msgid "Output file for case %d does not exist: %s" msgstr "테스트 케이스 %d에 대한 출력 파일이 존재하지 않습니다.: %s" -#: judge/utils/problem_data.py:153 +#: judge/utils/problem_data.py:151 #, python-format msgid "Batch start case #%d requires points." msgstr "" -#: judge/utils/problem_data.py:174 +#: judge/utils/problem_data.py:172 #, python-format msgid "Attempt to end batch outside of one in case #%d" msgstr "" -#: judge/utils/problem_data.py:192 +#: judge/utils/problem_data.py:190 msgid "How did you corrupt the zip path?" msgstr "압축 파일 경로를 어떻게 손상하셨나요?" -#: judge/utils/problem_data.py:198 +#: judge/utils/problem_data.py:196 msgid "How did you corrupt the generator path?" msgstr "" -#: judge/utils/problems.py:80 +#: judge/utils/problems.py:78 msgid "Wrong" msgstr "" -#: judge/utils/problems.py:82 +#: judge/utils/problems.py:80 msgid "Timeout" msgstr "" -#: judge/utils/problems.py:83 +#: judge/utils/problems.py:81 msgid "Error" msgstr "" -#: judge/utils/problems.py:94 +#: judge/utils/problems.py:92 msgid "Can't pass both queryset and keyword filters" msgstr "" @@ -2341,8 +2213,7 @@ msgctxt "hours and minutes" msgid "%h:%m" msgstr "%h:%m" -#: judge/views/about.py:7 templates/organization/home.html:112 -#: templates/user/user-about.html:83 templates/user/user-tabs.html:4 +#: judge/views/about.py:7 templates/user/user-about.html:33 msgid "About" msgstr "" @@ -2350,167 +2221,157 @@ msgstr "" msgid "Custom Checker Sample" msgstr "" -#: judge/views/blog.py:45 +#: judge/views/blog.py:38 #, python-format msgid "Page %d of Posts" msgstr "게시물 %d 페이지" -#: judge/views/comment.py:28 +#: judge/views/comment.py:27 msgid "Messing around, are we?" msgstr "" -#: judge/views/comment.py:37 +#: judge/views/comment.py:36 msgid "You must solve at least one problem before you can vote." msgstr "" -#: judge/views/comment.py:64 +#: judge/views/comment.py:63 msgid "You already voted." msgstr "이미 투표하셨습니다." -#: judge/views/comment.py:126 judge/views/organization.py:344 +#: judge/views/comment.py:120 judge/views/organization.py:299 msgid "Edited from site" msgstr "사이트에서 편집" -#: judge/views/comment.py:147 +#: judge/views/comment.py:141 msgid "Editing comment" msgstr "" -#: judge/views/contests.py:57 judge/views/contests.py:247 -#: judge/views/contests.py:250 judge/views/contests.py:424 +#: judge/views/contests.py:55 judge/views/contests.py:215 +#: judge/views/contests.py:218 judge/views/contests.py:389 msgid "No such contest" msgstr "그런 대회는 존재하지 않습니다." -#: judge/views/contests.py:58 judge/views/contests.py:248 +#: judge/views/contests.py:56 judge/views/contests.py:216 #, python-format msgid "Could not find a contest with the key \"%s\"." msgstr "키 %s로는 대회를 찾을 수 없습니다." -#: judge/views/contests.py:71 +#: judge/views/contests.py:81 msgid "Contests" msgstr "대회" -#: judge/views/contests.py:251 +#: judge/views/contests.py:219 msgid "Could not find such contest." msgstr "그런 대회를 찾을 수 있습니다." -#: judge/views/contests.py:254 +#: judge/views/contests.py:222 #, python-format msgid "Access to contest \"%s\" denied" msgstr "%s 대회 접근이 거부되었습니다." -#: judge/views/contests.py:278 +#: judge/views/contests.py:246 msgid "Clone Contest" msgstr "" -#: judge/views/contests.py:343 +#: judge/views/contests.py:309 msgid "Contest not ongoing" msgstr "현재 진행중인 대회가 아닙니다." -#: judge/views/contests.py:344 +#: judge/views/contests.py:310 #, python-format msgid "\"%s\" is not currently ongoing." msgstr "%s는 현재 진행중이 아닙니다." -#: judge/views/contests.py:348 +#: judge/views/contests.py:314 msgid "Already in contest" msgstr "대회에 이미 있습니다." -#: judge/views/contests.py:349 +#: judge/views/contests.py:315 #, python-format msgid "You are already in a contest: \"%s\"." msgstr "현재 대회 %s에 이미 참가해 있습니다." -#: judge/views/contests.py:352 +#: judge/views/contests.py:318 msgid "Banned from joining" msgstr "" -#: judge/views/contests.py:353 +#: judge/views/contests.py:319 msgid "" "You have been declared persona non grata for this contest. You are " "permanently barred from joining this contest." msgstr "" -#: judge/views/contests.py:414 +#: judge/views/contests.py:379 #, python-format msgid "Enter access code for \"%s\"" msgstr "" -#: judge/views/contests.py:425 +#: judge/views/contests.py:390 #, python-format msgid "You are not in contest \"%s\"." msgstr "현재 대회 %s에 참가중이 아닙니다." -#: judge/views/contests.py:444 +#: judge/views/contests.py:409 msgid "ContestCalendar requires integer year and month" msgstr "" -#: judge/views/contests.py:484 +#: judge/views/contests.py:449 #, python-format msgid "Contests in %(month)s" msgstr "" -#: judge/views/contests.py:484 +#: judge/views/contests.py:449 msgid "F Y" msgstr "" -#: judge/views/contests.py:532 +#: judge/views/contests.py:496 #, fuzzy, python-format #| msgid "Language statistics" msgid "%s Statistics" msgstr "언어 통계" -#: judge/views/contests.py:717 +#: judge/views/contests.py:601 +msgid "???" +msgstr "" + +#: judge/views/contests.py:664 #, python-format msgid "%s Rankings" msgstr "%s 순위" -#: judge/views/contests.py:725 -msgid "???" -msgstr "" - -#: judge/views/contests.py:741 +#: judge/views/contests.py:680 #, python-format msgid "Your participation in %s" msgstr "%s에 대한 당신의 참가" -#: judge/views/contests.py:742 +#: judge/views/contests.py:681 #, python-format msgid "%s's participation in %s" msgstr "%s's %s에 대한 참가" -#: judge/views/contests.py:749 +#: judge/views/contests.py:685 msgid "Live" msgstr "실시간" -#: judge/views/contests.py:761 templates/contest/contest-tabs.html:13 +#: judge/views/contests.py:697 msgid "Participation" msgstr "참여" -#: judge/views/contests.py:808 +#: judge/views/contests.py:743 #, python-format msgid "%s MOSS Results" msgstr "" -#: judge/views/contests.py:835 +#: judge/views/contests.py:770 #, python-format msgid "Running MOSS for %s..." msgstr "" -#: judge/views/contests.py:858 +#: judge/views/contests.py:793 #, python-format msgid "Contest tag: %s" msgstr "대회 태그: %s" -#: judge/views/contests.py:868 judge/views/ticket.py:57 -msgid "Issue description" -msgstr "" - -#: judge/views/contests.py:911 -#, fuzzy, python-format -#| msgid "clarification body" -msgid "New clarification for %s" -msgstr "수정사항" - #: judge/views/error.py:14 msgid "404 error" msgstr "404 Error!!!" @@ -2531,76 +2392,69 @@ msgid "corrupt page %s" msgstr "손상된 페이지 %s" #: judge/views/language.py:12 templates/status/judge-status-table.html:9 -#: templates/status/status-tabs.html:5 msgid "Runtimes" msgstr "런타임" -#: judge/views/notification.py:40 -#, python-format -msgid "Notifications (%d unseen)" -msgstr "" - -#: judge/views/organization.py:59 judge/views/organization.py:62 +#: judge/views/organization.py:44 judge/views/organization.py:47 msgid "No such organization" msgstr "존재하지 않는 조직" -#: judge/views/organization.py:60 +#: judge/views/organization.py:45 #, python-format msgid "Could not find an organization with the key \"%s\"." msgstr "%s 조직을 찾을 수 없습니다." -#: judge/views/organization.py:63 +#: judge/views/organization.py:48 msgid "Could not find such organization." msgstr "그러한 조직을 찾을 수 없습니다." -#: judge/views/organization.py:79 judge/views/register.py:34 -#: templates/organization/list.html:32 templates/user/import/table_csv.html:9 -#: templates/user/user-list-tabs.html:6 +#: judge/views/organization.py:72 judge/views/register.py:34 +#: templates/organization/list.html:15 msgid "Organizations" msgstr "조직" -#: judge/views/organization.py:130 +#: judge/views/organization.py:93 #, python-format msgid "%s Members" msgstr "%s 멤버" -#: judge/views/organization.py:159 judge/views/organization.py:162 -#: judge/views/organization.py:167 +#: judge/views/organization.py:118 judge/views/organization.py:121 +#: judge/views/organization.py:126 msgid "Joining organization" msgstr "조직 가입" -#: judge/views/organization.py:159 +#: judge/views/organization.py:118 msgid "You are already in the organization." msgstr "이미 조직에 가입되어 있습니다." -#: judge/views/organization.py:162 +#: judge/views/organization.py:121 msgid "This organization is not open." msgstr "이 조직은 공개되어 있지 않습니다." -#: judge/views/organization.py:179 +#: judge/views/organization.py:138 msgid "Leaving organization" msgstr "조직 탈퇴" -#: judge/views/organization.py:179 +#: judge/views/organization.py:138 #, python-format msgid "You are not in \"%s\"." msgstr "%s에 있지 않습니다." -#: judge/views/organization.py:203 +#: judge/views/organization.py:162 #, python-format msgid "Request to join %s" msgstr "%s 가입 신청" -#: judge/views/organization.py:221 +#: judge/views/organization.py:180 msgid "Join request detail" msgstr "가입 신청 세부 사항" -#: judge/views/organization.py:254 +#: judge/views/organization.py:209 #, python-format msgid "Managing join requests for %s" msgstr "%s 가입 신청 가입" -#: judge/views/organization.py:285 +#: judge/views/organization.py:240 #, python-format msgid "" "Your organization can only receive %d more members. You cannot approve %d " @@ -2609,44 +2463,44 @@ msgstr "" "당신의 조직은 %d명의 회원만 더 가입이 가능합니다. %d명의 사용자 가입 승인이 " "불가합니다." -#: judge/views/organization.py:297 +#: judge/views/organization.py:252 #, python-format msgid "Approved %d user." msgid_plural "Approved %d users." msgstr[0] "%d명 사용자 승인" -#: judge/views/organization.py:298 +#: judge/views/organization.py:253 #, python-format msgid "Rejected %d user." msgid_plural "Rejected %d users." msgstr[0] "%d명 거부" -#: judge/views/organization.py:328 +#: judge/views/organization.py:283 #, python-format msgid "Editing %s" msgstr "%s 편집중" -#: judge/views/organization.py:352 judge/views/organization.py:360 +#: judge/views/organization.py:307 judge/views/organization.py:315 msgid "Can't edit organization" msgstr "조직 편집이 불가합니다." -#: judge/views/organization.py:353 +#: judge/views/organization.py:308 msgid "You are not allowed to edit this organization." msgstr "조직을 편집할 권한이 없습니다." -#: judge/views/organization.py:361 +#: judge/views/organization.py:316 msgid "You are not allowed to kick people from this organization." msgstr "조직 사용자를 탈퇴시킬 권한이 없습니다." -#: judge/views/organization.py:366 judge/views/organization.py:370 +#: judge/views/organization.py:321 judge/views/organization.py:325 msgid "Can't kick user" msgstr "이 사용자를 탈퇴시킬 수 없습니다." -#: judge/views/organization.py:367 +#: judge/views/organization.py:322 msgid "The user you are trying to kick does not exist!" msgstr "탈퇴시키려는 사용자가 존재하지 않습니다." -#: judge/views/organization.py:371 +#: judge/views/organization.py:326 #, python-format msgid "The user you are trying to kick is not in organization: %s." msgstr "" @@ -2670,36 +2524,35 @@ msgstr "" msgid "Editorial for {0}" msgstr "" -#: judge/views/problem.py:285 templates/contest/contest.html:79 -#: templates/user/user-about.html:28 templates/user/user-tabs.html:5 -#: templates/user/users-table.html:31 +#: judge/views/problem.py:286 templates/contest/contest.html:79 +#: templates/user/users-table.html:23 msgid "Problems" msgstr "문제" -#: judge/views/problem.py:585 +#: judge/views/problem.py:547 msgid "Banned from submitting" msgstr "" -#: judge/views/problem.py:586 +#: judge/views/problem.py:548 msgid "" "You have been declared persona non grata for this problem. You are " "permanently barred from submitting this problem." msgstr "" -#: judge/views/problem.py:600 +#: judge/views/problem.py:562 msgid "Too many submissions" msgstr "" -#: judge/views/problem.py:601 +#: judge/views/problem.py:563 msgid "You have exceeded the submission limit for this problem." msgstr "" -#: judge/views/problem.py:661 judge/views/problem.py:664 +#: judge/views/problem.py:633 judge/views/problem.py:636 #, python-format msgid "Submit to %(problem)s" msgstr "" -#: judge/views/problem.py:679 +#: judge/views/problem.py:652 msgid "Clone Problem" msgstr "" @@ -2740,22 +2593,22 @@ msgstr "" msgid "Generated init.yml for %s" msgstr "" -#: judge/views/problem_manage.py:52 judge/views/problem_manage.py:55 +#: judge/views/problem_manage.py:50 judge/views/problem_manage.py:53 #, python-format msgid "Managing submissions for %s" msgstr "" -#: judge/views/problem_manage.py:97 +#: judge/views/problem_manage.py:95 #, python-format msgid "Rejudging selected submissions for %s..." msgstr "" -#: judge/views/problem_manage.py:141 +#: judge/views/problem_manage.py:110 #, python-format msgid "Rescoring all submissions for %s..." msgstr "" -#: judge/views/problem_manage.py:150 +#: judge/views/problem_manage.py:119 #, python-format msgid "Successfully scheduled %d submission for rejudging." msgid_plural "Successfully scheduled %d submissions for rejudging." @@ -2803,7 +2656,7 @@ msgstr "선호하는 언어" msgid "Subscribe to newsletter?" msgstr "뉴스레터에 구독하시겠습니까?" -#: judge/views/register.py:55 +#: judge/views/register.py:45 #, python-format msgid "" "The email address \"%s\" is already taken. Only one registration is allowed " @@ -2811,7 +2664,7 @@ msgid "" msgstr "" "이메일 주소 %s는 사용중입니다. 하나의 주소에 대해 한번만 가입이 허용됩니다." -#: judge/views/register.py:61 +#: judge/views/register.py:51 msgid "" "Your email provider is not allowed due to history of abuse. Please use a " "reputable email provider." @@ -2819,11 +2672,11 @@ msgstr "" "스팸으로 인해 이 이메일 제공업체는 허용되지 않습니다. 다른 메일 주소를 사용" "해 주세요." -#: judge/views/register.py:67 judge/views/register.py:105 +#: judge/views/register.py:57 judge/views/register.py:95 msgid "Registration" msgstr "회원가입" -#: judge/views/register.py:116 +#: judge/views/register.py:106 msgid "Authentication failure" msgstr "인증 실패" @@ -2839,49 +2692,49 @@ msgstr "현재 상태" msgid "Version matrix" msgstr "" -#: judge/views/submission.py:84 judge/views/submission.py:91 +#: judge/views/submission.py:83 judge/views/submission.py:90 #, python-format msgid "Submission of %(problem)s by %(user)s" msgstr "" -#: judge/views/submission.py:244 judge/views/submission.py:245 -#: templates/problem/problem.html:167 +#: judge/views/submission.py:227 judge/views/submission.py:228 +#: templates/problem/problem.html:127 msgid "All submissions" msgstr "모든 제출들" -#: judge/views/submission.py:404 +#: judge/views/submission.py:384 msgid "All my submissions" msgstr "내 모든 제출들" -#: judge/views/submission.py:405 +#: judge/views/submission.py:385 #, python-format msgid "All submissions by %s" msgstr "" -#: judge/views/submission.py:436 +#: judge/views/submission.py:416 #, python-format msgid "All submissions for %s" msgstr "" -#: judge/views/submission.py:455 +#: judge/views/submission.py:435 msgid "Must pass a problem" msgstr "" -#: judge/views/submission.py:501 +#: judge/views/submission.py:481 #, python-format msgid "My submissions for %(problem)s" msgstr "%(problem)s에 대한 나의 제출" -#: judge/views/submission.py:502 +#: judge/views/submission.py:482 #, python-format msgid "%(user)s's submissions for %(problem)s" msgstr "%(problem)s에 대한 %(user)s의 제출" -#: judge/views/submission.py:603 +#: judge/views/submission.py:583 msgid "Must pass a contest" msgstr "대회를 통화해야한다" -#: judge/views/submission.py:622 +#: judge/views/submission.py:602 #, python-brace-format msgid "" "{0}'s submissions for {2} in {0}'s submissions for {2} in {4}" -#: judge/views/submission.py:629 +#: judge/views/submission.py:609 #, python-brace-format msgid "" "{0}'s submissions for problem {2} in {3}" @@ -2899,44 +2752,48 @@ msgstr "" "{0}'s submissions for problem {2} in {3}" "" -#: judge/views/ticket.py:50 judge/views/ticket.py:56 +#: judge/views/ticket.py:33 judge/views/ticket.py:39 msgid "Ticket title" msgstr "" -#: judge/views/ticket.py:107 judge/views/ticket.py:110 +#: judge/views/ticket.py:40 +msgid "Issue description" +msgstr "" + +#: judge/views/ticket.py:85 judge/views/ticket.py:88 #, python-format msgid "New ticket for %s" msgstr "" -#: judge/views/ticket.py:170 +#: judge/views/ticket.py:142 #, python-format msgid "%(title)s - Ticket %(id)d" msgstr "" -#: judge/views/ticket.py:279 +#: judge/views/ticket.py:251 #, python-format msgid "Tickets - Page %(number)d of %(total)d" msgstr "" -#: judge/views/ticket.py:328 +#: judge/views/ticket.py:300 #, python-format msgid "New Ticket: %s" msgstr "" -#: judge/views/ticket.py:329 +#: judge/views/ticket.py:301 #, python-format msgid "#%(id)d, assigned to: %(users)s" msgstr "" -#: judge/views/ticket.py:331 +#: judge/views/ticket.py:303 msgid ", " msgstr "" -#: judge/views/ticket.py:331 +#: judge/views/ticket.py:303 msgid "no one" msgstr "" -#: judge/views/ticket.py:351 +#: judge/views/ticket.py:323 #, python-format msgid "New Ticket Message For: %s" msgstr "" @@ -2953,50 +2810,41 @@ msgstr "" msgid "Perform Two Factor Authentication" msgstr "" -#: judge/views/user.py:74 +#: judge/views/user.py:68 msgid "No such user" msgstr "" -#: judge/views/user.py:74 +#: judge/views/user.py:68 #, python-format msgid "No user handle \"%s\"." msgstr "" -#: judge/views/user.py:78 +#: judge/views/user.py:72 msgid "My account" msgstr "" -#: judge/views/user.py:79 +#: judge/views/user.py:73 #, python-format msgid "User %s" msgstr "" -#: judge/views/user.py:148 -msgid "M j, Y" -msgstr "" - -#: judge/views/user.py:171 +#: judge/views/user.py:136 msgid "M j, Y, G:i" msgstr "" -#: judge/views/user.py:290 +#: judge/views/user.py:221 msgid "Updated on site" msgstr "" -#: judge/views/user.py:323 templates/admin/auth/user/change_form.html:14 -#: templates/admin/auth/user/change_form.html:17 templates/base.html:238 -#: templates/user/user-tabs.html:10 +#: judge/views/user.py:254 templates/admin/auth/user/change_form.html:14 +#: templates/admin/auth/user/change_form.html:17 templates/base.html:224 msgid "Edit profile" msgstr "" -#: judge/views/user.py:332 templates/user/user-list-tabs.html:4 +#: judge/views/user.py:263 msgid "Leaderboard" msgstr "" -#: judge/views/user.py:407 -msgid "Import Users" -msgstr "" - #: judge/views/widgets.py:48 judge/views/widgets.py:58 #, python-format msgid "Invalid upstream data: %s" @@ -3034,7 +2882,7 @@ msgid "View Submissions" msgstr "" #: templates/admin/judge/problem/change_form.html:17 -#: templates/user/user-base.html:112 +#: templates/user/user-base.html:61 msgid "View submissions" msgstr "" @@ -3049,148 +2897,90 @@ msgstr "사용자 수정" msgid "Rejudge" msgstr "재체점" -#: templates/base.html:230 -#, python-format -msgid "Hello, %(username)s." -msgstr "" - -#: templates/base.html:236 templates/comments/list.html:89 -#: templates/contest/contest-list-tabs.html:24 -#: templates/contest/ranking-table.html:53 -#: templates/problem/problem-list-tabs.html:6 +#: templates/base.html:222 templates/comments/list.html:89 +#: templates/contest/ranking-table.html:39 #: templates/submission/info-base.html:12 -#: templates/submission/submission-list-tabs.html:15 msgid "Admin" msgstr "관리자" -#: templates/base.html:245 +#: templates/base.html:231 msgid "Log out" msgstr "로그아웃" -#: templates/base.html:254 +#: templates/base.html:240 #: templates/registration/password_reset_complete.html:4 msgid "Log in" msgstr "" -#: templates/base.html:255 templates/registration/registration_form.html:177 +#: templates/base.html:241 templates/registration/registration_form.html:177 msgid "or" msgstr "" -#: templates/base.html:256 +#: templates/base.html:242 msgid "Sign up" msgstr "" -#: templates/base.html:271 +#: templates/base.html:254 msgid "spectating" msgstr "관전" -#: templates/base.html:284 +#: templates/base.html:267 msgid "This site works best with JavaScript enabled." msgstr "이 사이트는 자바 스크립트를 활성화시켜야 정상적으로 작동합니다." -#: templates/blog/blog.html:13 templates/comments/list.html:68 -#: templates/comments/list.html:83 templates/contest/contest-tabs.html:23 -#: templates/contest/tag-title.html:9 templates/flatpages/admin_link.html:3 -#: templates/license.html:10 templates/problem/editorial.html:14 +#: templates/blog/content.html:13 templates/comments/list.html:68 +#: templates/comments/list.html:83 templates/contest/tag-title.html:9 +#: templates/flatpages/admin_link.html:3 templates/license.html:10 +#: templates/problem/editorial.html:14 msgid "Edit" msgstr "" -#: templates/blog/blog.html:26 -#, python-format -msgid "" -"\n" -" posted on %(time)s\n" -" " -msgstr "" - -#: templates/blog/content.html:10 -#, fuzzy, python-brace-format -#| msgid "posted time" -msgid "posted on {time}" -msgstr "게시 시각" - -#: templates/blog/dashboard.html:21 -#, python-format -msgid "" -"\n" -" on %(time)s\n" -" " -msgstr "" - -#: templates/blog/list.html:93 +#: templates/blog/list.html:85 msgid "Blog" msgstr "" -#: templates/blog/list.html:95 +#: templates/blog/list.html:87 msgid "Events" msgstr "" -#: templates/blog/list.html:100 +#: templates/blog/list.html:92 msgid "News" msgstr "" -#: templates/blog/list.html:115 templates/problem/list.html:347 -#: templates/problem/problem.html:361 +#: templates/blog/list.html:130 templates/problem/problem.html:310 msgid "Clarifications" msgstr "" -#: templates/blog/list.html:121 -msgid "Add" -msgstr "" - -#: templates/blog/list.html:140 templates/problem/list.html:369 -#: templates/problem/problem.html:372 +#: templates/blog/list.html:146 templates/problem/problem.html:321 msgid "No clarifications have been made at this time." msgstr "" -#: templates/blog/list.html:148 +#: templates/blog/list.html:154 msgid "Ongoing contests" msgstr "" -#: templates/blog/list.html:166 +#: templates/blog/list.html:172 msgid "Upcoming contests" msgstr "" -#: templates/blog/list.html:184 -msgid "My open tickets" -msgstr "" - -#: templates/blog/list.html:206 -msgid "New tickets" -msgstr "" - -#: templates/blog/list.html:227 -msgid "New problems" -msgstr "" - -#: templates/blog/list.html:244 +#: templates/blog/list.html:189 msgid "Comment stream" msgstr "" -#: templates/chat/chat.html:305 -msgid "Chat" +#: templates/blog/list.html:208 +msgid "New problems" msgstr "" -#: templates/chat/chat.html:307 templates/chat/chat.html:314 -#, fuzzy -#| msgid "Online Judge" -msgid "Online Users" -msgstr "Online Judge" - -#: templates/chat/chat.html:315 -msgid "Refresh" +#: templates/blog/list.html:225 +msgid "My open tickets" msgstr "" -#: templates/chat/chat.html:333 -msgid "Emoji" +#: templates/blog/list.html:246 +msgid "New tickets" msgstr "" -#: templates/chat/chat.html:334 -msgid "Enter your message" -msgstr "" - -#: templates/chat/message.html:20 -msgid "Delete" +#: templates/chat/chat.html:167 +msgid "Your message" msgstr "" #: templates/comments/list.html:2 @@ -3201,22 +2991,11 @@ msgstr "" msgid "Please login to vote" msgstr "" -#: templates/comments/list.html:40 -#, fuzzy, python-brace-format -#| msgid "comment vote" -msgid "commented on {time}" -msgstr "코멘트 투표" - -#: templates/comments/list.html:49 -#, python-format -msgid "edit %(edits)s" -msgstr "" - -#: templates/comments/list.html:51 templates/comments/media-js.html:92 +#: templates/comments/list.html:51 templates/comments/media-js.html:77 msgid "edited" msgstr "" -#: templates/comments/list.html:60 templates/notification/list.html:14 +#: templates/comments/list.html:60 msgid "Link" msgstr "" @@ -3224,54 +3003,36 @@ msgstr "" msgid "Reply" msgstr "" -#: templates/comments/list.html:86 templates/contest/list.html:91 -#: templates/contest/list.html:95 templates/contest/list.html:280 +#: templates/comments/list.html:86 msgid "Hide" msgstr "" -#: templates/comments/list.html:101 -#, python-format -msgid "" -"\n" -" This comment is hidden due " -"to too much negative feedback.\n" -" Click here to view it.\n" -" " -msgstr "" - -#: templates/comments/list.html:121 +#: templates/comments/list.html:120 msgid "There are no comments at the moment." msgstr "" -#: templates/comments/list.html:127 +#: templates/comments/list.html:126 msgid "New comment" msgstr "" -#: templates/comments/list.html:141 +#: templates/comments/list.html:140 msgid "Invalid comment body." msgstr "" -#: templates/comments/list.html:149 +#: templates/comments/list.html:148 msgid "Post!" msgstr "" -#: templates/comments/list.html:157 +#: templates/comments/list.html:156 msgid "Comments are disabled on this page." msgstr "" -#: templates/comments/media-js.html:38 -#, fuzzy -#| msgid "no comments" -msgid "Replying to comment" -msgstr "코멘트 없음" - -#: templates/comments/media-js.html:87 +#: templates/comments/media-js.html:72 #, python-brace-format msgid "edit {edits}" msgstr "" -#: templates/comments/media-js.html:90 +#: templates/comments/media-js.html:75 msgid "original" msgstr "" @@ -3315,11 +3076,6 @@ msgstr "" msgid "Saturday" msgstr "" -#: templates/contest/clarification.html:52 templates/organization/new.html:10 -#: templates/ticket/new.html:38 -msgid "Create" -msgstr "" - #: templates/contest/clone.html:37 msgid "Enter a new key for the cloned contest:" msgstr "" @@ -3340,187 +3096,97 @@ msgstr "" msgid "Next" msgstr "" -#: templates/contest/contest-list-tabs.html:21 -#: templates/problem/problem-list-tabs.html:5 -msgid "List" -msgstr "" - -#: templates/contest/contest-list-tabs.html:22 -#, fuzzy -#| msgid "Standard" -msgid "Calendar" -msgstr "표준" - -#: templates/contest/contest-tabs.html:4 templates/organization/home.html:105 -msgid "Info" -msgstr "" - -#: templates/contest/contest-tabs.html:6 templates/stats/base.html:9 -#: templates/submission/list.html:339 -msgid "Statistics" -msgstr "" - -#: templates/contest/contest-tabs.html:11 -#, fuzzy -#| msgid "%s Rankings" -msgid "Rankings" -msgstr "%s 순위" - -#: templates/contest/contest-tabs.html:16 -#, fuzzy -#| msgid "%s Rankings" -msgid "Hidden Rankings" -msgstr "%s 순위" - -#: templates/contest/contest-tabs.html:21 -msgid "MOSS" -msgstr "" - -#: templates/contest/contest-tabs.html:26 -msgid "Clone" -msgstr "" - -#: templates/contest/contest-tabs.html:38 -#: templates/contest/contest-tabs.html:58 +#: templates/contest/contest-tabs.html:37 msgid "Leave contest" msgstr "" -#: templates/contest/contest-tabs.html:45 templates/contest/list.html:388 +#: templates/contest/contest-tabs.html:44 templates/contest/list.html:293 msgid "Virtual join" msgstr "" -#: templates/contest/contest-tabs.html:56 -#, fuzzy -#| msgid "spectating" -msgid "Stop spectating" -msgstr "관전" - -#: templates/contest/contest-tabs.html:65 +#: templates/contest/contest-tabs.html:64 msgid "Spectate contest" msgstr "" -#: templates/contest/contest-tabs.html:72 +#: templates/contest/contest-tabs.html:70 +#: templates/contest/contest-tabs.html:76 msgid "Join contest" msgstr "" -#: templates/contest/contest-tabs.html:81 +#: templates/contest/contest-tabs.html:85 msgid "Login to participate" msgstr "" -#: templates/contest/contest.html:37 -#, fuzzy -#| msgid "Participation" -msgid "Participating virtually." -msgstr "참여" - -#: templates/contest/contest.html:43 -#, fuzzy -#| msgid "Contests" -msgid "Contest is over." -msgstr "대회" - #: templates/contest/contest.html:59 templates/contest/contest.html:63 msgid "F j, Y, G:i T" msgstr "" -#: templates/contest/contest.html:59 -#, python-format -msgid "" -"%(time_limit)s window between %(start_time)s and " -"%(end_time)s" -msgstr "" - -#: templates/contest/contest.html:63 -#, python-format -msgid "%(length)s long starting on %(start_time)s" -msgstr "" - #: templates/contest/contest.html:85 msgid "AC Rate" msgstr "" -#: templates/contest/contest.html:86 templates/contest/list.html:237 -#: templates/contest/list.html:289 templates/contest/list.html:366 -#: templates/problem/list.html:223 templates/problem/list.html:254 +#: templates/contest/contest.html:86 templates/contest/list.html:153 +#: templates/contest/list.html:195 templates/contest/list.html:271 +#: templates/problem/list.html:212 templates/problem/list.html:238 msgid "Users" msgstr "" -#: templates/contest/contest.html:111 templates/problem/list.html:330 +#: templates/contest/contest.html:111 msgid "Editorial" msgstr "" -#: templates/contest/list.html:83 templates/contest/media-js.html:9 +#: templates/contest/list.html:31 templates/contest/media-js.html:9 msgid "Are you sure you want to join?" msgstr "" -#: templates/contest/list.html:84 +#: templates/contest/list.html:32 msgid "" "Joining a contest for the first time starts your timer, after which it " "becomes unstoppable." msgstr "" -#: templates/contest/list.html:92 templates/contest/list.html:278 -msgid "Show" -msgstr "" - -#: templates/contest/list.html:102 templates/problem/list.html:68 -#, fuzzy -#| msgid "Organizations" -msgid "Organizations..." -msgstr "조직" - -#: templates/contest/list.html:135 +#: templates/contest/list.html:65 msgid "hidden" msgstr "" -#: templates/contest/list.html:140 +#: templates/contest/list.html:70 msgid "private" msgstr "" -#: templates/contest/list.html:154 +#: templates/contest/list.html:84 msgid "rated" msgstr "" -#: templates/contest/list.html:202 +#: templates/contest/list.html:132 msgid "Spectate" msgstr "" -#: templates/contest/list.html:208 +#: templates/contest/list.html:138 msgid "Join" msgstr "" -#: templates/contest/list.html:220 -#, fuzzy -#| msgid "contests" -msgid "Search contests..." -msgstr "대회" - -#: templates/contest/list.html:229 -msgid "Search" -msgstr "" - -#: templates/contest/list.html:232 +#: templates/contest/list.html:148 msgid "Active Contests" msgstr "" -#: templates/contest/list.html:236 templates/contest/list.html:288 -#: templates/contest/list.html:327 templates/contest/list.html:365 +#: templates/contest/list.html:152 templates/contest/list.html:194 +#: templates/contest/list.html:232 templates/contest/list.html:270 msgid "Contest" msgstr "" -#: templates/contest/list.html:275 +#: templates/contest/list.html:190 msgid "Ongoing Contests" msgstr "" -#: templates/contest/list.html:322 +#: templates/contest/list.html:227 msgid "Upcoming Contests" msgstr "" -#: templates/contest/list.html:350 +#: templates/contest/list.html:255 msgid "There are no scheduled contests at this time." msgstr "" -#: templates/contest/list.html:356 +#: templates/contest/list.html:261 msgid "Past Contests" msgstr "" @@ -3571,83 +3237,51 @@ msgstr "" msgid "Only the following organizations may access this contest:" msgstr "" -#: templates/contest/ranking-table.html:9 templates/problem/search-form.html:35 +#: templates/contest/ranking-table.html:7 msgid "Organization" msgstr "그룹" -#: templates/contest/ranking-table.html:10 templates/user/users-table.html:13 -#, fuzzy -#| msgid "full name" -msgid "Full Name" -msgstr "전체 이름" - -#: templates/contest/ranking-table.html:44 +#: templates/contest/ranking-table.html:30 msgid "Un-Disqualify" msgstr "" -#: templates/contest/ranking-table.html:47 +#: templates/contest/ranking-table.html:33 msgid "Disqualify" msgstr "" -#: templates/contest/ranking.html:187 +#: templates/contest/ranking.html:173 msgid "Are you sure you want to disqualify this participation?" msgstr "" -#: templates/contest/ranking.html:192 +#: templates/contest/ranking.html:178 msgid "Are you sure you want to un-disqualify this participation?" msgstr "" -#: templates/contest/ranking.html:463 +#: templates/contest/ranking.html:252 msgid "View user participation" msgstr "" -#: templates/contest/ranking.html:467 +#: templates/contest/ranking.html:256 msgid "Show organizations" msgstr "" -#: templates/contest/ranking.html:471 -#, fuzzy -#| msgid "full name" -msgid "Show full name" -msgstr "전체 이름" - -#: templates/contest/ranking.html:474 -msgid "Show friends only" -msgstr "" - -#: templates/contest/ranking.html:477 -msgid "Total score only" -msgstr "" - -#: templates/contest/ranking.html:479 -#, fuzzy -#| msgid "virtual participation id" -msgid "Show virtual participation" -msgstr "가상 참여 id" - -#: templates/contest/stats.html:51 +#: templates/contest/stats.html:38 #, fuzzy #| msgid "problem translation" msgid "Problem Status Distribution" msgstr "문제 번역" -#: templates/contest/stats.html:56 +#: templates/contest/stats.html:43 #, fuzzy #| msgid "Problem name" msgid "Problem AC Rate" msgstr "문제 이름" -#: templates/contest/stats.html:62 -#, fuzzy -#| msgid "problem translation" -msgid "Problem Point Distribution" -msgstr "문제 번역" - -#: templates/contest/stats.html:76 templates/stats/language.html:16 +#: templates/contest/stats.html:48 templates/stats/language.html:16 msgid "Submissions by Language" msgstr "" -#: templates/contest/stats.html:82 templates/stats/language.html:26 +#: templates/contest/stats.html:54 templates/stats/language.html:26 msgid "Language AC Rate" msgstr "" @@ -3656,7 +3290,6 @@ msgid "Source:" msgstr "" #: templates/newsletter/common.html:6 -#: templates/newsletter/newsletter_list.html:15 #: templates/newsletter/subscription_unsubscribe_activated.html:3 #: templates/newsletter/subscription_unsubscribe_activated.html:6 #: templates/newsletter/subscription_update_activated.html:3 @@ -3664,25 +3297,6 @@ msgstr "" msgid "Newsletter" msgstr "" -#: templates/newsletter/newsletter_list.html:2 -#: templates/newsletter/newsletter_list.html:3 -msgid "Newsletter list" -msgstr "" - -#: templates/newsletter/newsletter_list.html:6 -msgid "Subscribe to get the latest emails about upcoming contests and events." -msgstr "" - -#: templates/newsletter/newsletter_list.html:16 -msgid "Subscribe" -msgstr "" - -#: templates/newsletter/newsletter_list.html:30 -#, fuzzy -#| msgid "description" -msgid "Update subscriptions" -msgstr "설명" - #: templates/newsletter/subscription_unsubscribe_activated.html:3 #: templates/newsletter/subscription_unsubscribe_activated.html:6 #: templates/newsletter/subscription_update_activated.html:3 @@ -3744,109 +3358,64 @@ msgid "" "follow in order to update your subscription." msgstr "" -#: templates/notification/list.html:7 -msgid "You have no notifications" -msgstr "" - -#: templates/notification/list.html:13 -msgid "Activity" -msgstr "" - #: templates/organization/edit.html:46 #: templates/organization/requests/pending.html:34 #: templates/ticket/edit-notes.html:4 msgid "Update" msgstr "" -#: templates/organization/home.html:41 +#: templates/organization/home.html:7 msgid "Are you sure you want to leave this organization?" msgstr "" -#: templates/organization/home.html:43 +#: templates/organization/home.html:9 msgid "You will have to rejoin to show up on the organization leaderboard." msgstr "" -#: templates/organization/home.html:45 +#: templates/organization/home.html:11 msgid "You will have to request membership in order to join again." msgstr "" -#: templates/organization/home.html:88 -msgid "Join organization" -msgstr "" - -#: templates/organization/home.html:92 -msgid "Request membership" -msgstr "" - -#: templates/organization/home.html:122 -#, fuzzy -#| msgid "Organizations" -msgid "Organization news" -msgstr "조직" - -#: templates/organization/home.html:128 -msgid "There is no news at this time." -msgstr "" - -#: templates/organization/home.html:137 -#, fuzzy -#| msgid "Contests" -msgid "Controls" -msgstr "대회" - -#: templates/organization/home.html:142 -msgid "Edit organization" -msgstr "" - -#: templates/organization/home.html:148 -msgid "View requests" -msgstr "" - -#: templates/organization/home.html:161 -msgid "Admin organization" -msgstr "" - -#: templates/organization/home.html:167 -msgid "View members" -msgstr "" - -#: templates/organization/home.html:174 +#: templates/organization/home.html:24 msgid "Leave organization" msgstr "" -#: templates/organization/home.html:183 -#, fuzzy -#| msgid "associated contest" -msgid "New private contests" -msgstr "관련된 대회" +#: templates/organization/home.html:29 +msgid "Join organization" +msgstr "" -#: templates/organization/home.html:193 templates/organization/home.html:208 -#, fuzzy -#| msgid "rate all" -msgid "View all" -msgstr "모든 순위" +#: templates/organization/home.html:33 +msgid "Request membership" +msgstr "" -#: templates/organization/home.html:199 -#, fuzzy -#| msgid "associated problem" -msgid "New private problems" -msgstr "관련된 문제" +#: templates/organization/home.html:39 +msgid "Edit organization" +msgstr "" -#: templates/organization/list.html:40 -#, fuzzy -#| msgid "organizations" -msgid "Show my organizations only" -msgstr "조직" +#: templates/organization/home.html:43 +msgid "View requests" +msgstr "" -#: templates/organization/list.html:47 templates/status/language-list.html:34 -#: templates/user/import/table_csv.html:6 +#: templates/organization/home.html:50 +msgid "Admin organization" +msgstr "" + +#: templates/organization/home.html:55 +msgid "View members" +msgstr "" + +#: templates/organization/list.html:23 templates/status/language-list.html:34 msgid "Name" msgstr "" -#: templates/organization/list.html:48 +#: templates/organization/list.html:24 msgid "Members" msgstr "" +#: templates/organization/new.html:10 templates/ticket/new.html:38 +msgid "Create" +msgstr "" + #: templates/organization/requests/detail.html:13 msgid "User:" msgstr "" @@ -3879,7 +3448,7 @@ msgid "There are no requests to approve." msgstr "" #: templates/organization/requests/pending.html:17 -#: templates/problem/data.html:432 +#: templates/problem/data.html:452 msgid "Delete?" msgstr "" @@ -3915,37 +3484,37 @@ msgstr "" msgid "Enter a new code for the cloned problem:" msgstr "" -#: templates/problem/data.html:119 +#: templates/problem/data.html:108 #, fuzzy #| msgid "Information" msgid "Instruction" msgstr "정보" -#: templates/problem/data.html:390 +#: templates/problem/data.html:410 msgid "View YAML" msgstr "" -#: templates/problem/data.html:421 templates/problem/data.html:472 +#: templates/problem/data.html:441 templates/problem/data.html:491 msgid "Apply!" msgstr "" -#: templates/problem/data.html:426 +#: templates/problem/data.html:446 msgid "Type" msgstr "" -#: templates/problem/data.html:427 +#: templates/problem/data.html:447 msgid "Input file" msgstr "" -#: templates/problem/data.html:428 +#: templates/problem/data.html:448 msgid "Output file" msgstr "" -#: templates/problem/data.html:430 +#: templates/problem/data.html:450 msgid "Pretest?" msgstr "" -#: templates/problem/data.html:473 +#: templates/problem/data.html:492 msgid "Add new case" msgstr "" @@ -3957,34 +3526,28 @@ msgid "" "problem yourself is a bannable offence." msgstr "" -#: templates/problem/list.html:66 +#: templates/problem/list.html:62 msgid "Filter by type..." msgstr "" -#: templates/problem/list.html:193 +#: templates/problem/list.html:185 msgid "Hot problems" msgstr "" -#: templates/problem/list.html:218 templates/problem/list.html:240 -#: templates/problem/search-form.html:45 templates/user/user-problems.html:57 +#: templates/problem/list.html:207 templates/problem/list.html:224 +#: templates/problem/search-form.html:30 templates/user/user-problems.html:57 msgid "Category" msgstr "" -#: templates/problem/list.html:220 templates/problem/list.html:244 +#: templates/problem/list.html:209 templates/problem/list.html:228 msgid "Types" msgstr "" -#: templates/problem/list.html:251 +#: templates/problem/list.html:235 #, python-format msgid "AC %%" msgstr "" -#: templates/problem/list.html:342 -#, fuzzy -#| msgid "clarification body" -msgid "Add clarifications" -msgstr "수정사항" - #: templates/problem/manage_submission.html:55 msgid "Leave empty to not filter by language" msgstr "" @@ -3993,206 +3556,152 @@ msgstr "" msgid "Leave empty to not filter by result" msgstr "" -#: templates/problem/manage_submission.html:80 +#: templates/problem/manage_submission.html:79 msgid "Need valid values for both start and end IDs." msgstr "" -#: templates/problem/manage_submission.html:83 +#: templates/problem/manage_submission.html:82 msgid "End ID must be after start ID." msgstr "" +#: templates/problem/manage_submission.html:90 +#, python-brace-format +msgid "" +"You are about to rejudge {count} submissions. Are you sure you want to do " +"this?" +msgstr "" + #: templates/problem/manage_submission.html:96 -#, python-brace-format msgid "" -"You are about to {action} {count} submissions. Are you sure you want to do " -"this?" +"You are about to rejudge a few submissions. Are you sure you want to do this?" msgstr "" -#: templates/problem/manage_submission.html:103 -#, python-brace-format -msgid "" -"You are about to {action} a few submissions. Are you sure you want to do " -"this?" +#: templates/problem/manage_submission.html:115 +msgid "Rejudge Submissions" msgstr "" -#: templates/problem/manage_submission.html:127 -#: templates/submission/list.html:309 -msgid "Filter submissions" -msgstr "" - -#: templates/problem/manage_submission.html:132 +#: templates/problem/manage_submission.html:120 msgid "Filter by ID:" msgstr "" -#: templates/problem/manage_submission.html:135 +#: templates/problem/manage_submission.html:123 msgid "Starting ID:" msgstr "" -#: templates/problem/manage_submission.html:139 +#: templates/problem/manage_submission.html:127 msgid "Ending ID:" msgstr "" -#: templates/problem/manage_submission.html:143 +#: templates/problem/manage_submission.html:131 msgid "This range includes both endpoints." msgstr "" -#: templates/problem/manage_submission.html:146 +#: templates/problem/manage_submission.html:134 msgid "Filter by language:" msgstr "" -#: templates/problem/manage_submission.html:154 +#: templates/problem/manage_submission.html:142 msgid "Filter by result:" msgstr "" -#: templates/problem/manage_submission.html:164 -#, fuzzy -#| msgid "location" -msgid "Action" -msgstr "위치" - -#: templates/problem/manage_submission.html:166 +#: templates/problem/manage_submission.html:150 msgid "Rejudge selected submissions" msgstr "" -#: templates/problem/manage_submission.html:171 -#, fuzzy -#| msgid "All submissions" -msgid "Download selected submissions" -msgstr "모든 제출들" - -#: templates/problem/manage_submission.html:177 -#, python-format -msgid "Are you sure you want to rescore %(count)d submissions?" +#: templates/problem/manage_submission.html:157 +msgid "Rescore Everything" msgstr "" -#: templates/problem/manage_submission.html:178 +#: templates/problem/manage_submission.html:163 msgid "Rescore all submissions" msgstr "" -#: templates/problem/problem.html:132 +#: templates/problem/problem.html:91 msgid "View as PDF" msgstr "" -#: templates/problem/problem.html:141 templates/problem/problem.html:151 -#: templates/problem/problem.html:156 +#: templates/problem/problem.html:101 templates/problem/problem.html:111 +#: templates/problem/problem.html:116 msgid "Submit solution" msgstr "" -#: templates/problem/problem.html:144 -#, fuzzy, python-format -#| msgid "contest submission" -msgid "%(counter)s submission left" -msgid_plural "%(counter)s submissions left" -msgstr[0] "대회 제출" - -#: templates/problem/problem.html:152 +#: templates/problem/problem.html:112 msgid "0 submissions left" msgstr "" -#: templates/problem/problem.html:164 +#: templates/problem/problem.html:124 msgid "My submissions" msgstr "" -#: templates/problem/problem.html:168 +#: templates/problem/problem.html:128 msgid "Best submissions" msgstr "" -#: templates/problem/problem.html:172 +#: templates/problem/problem.html:132 msgid "Read editorial" msgstr "" -#: templates/problem/problem.html:177 +#: templates/problem/problem.html:137 msgid "Manage tickets" msgstr "" -#: templates/problem/problem.html:181 +#: templates/problem/problem.html:141 msgid "Edit problem" msgstr "" -#: templates/problem/problem.html:183 +#: templates/problem/problem.html:143 msgid "Edit test data" msgstr "" -#: templates/problem/problem.html:188 +#: templates/problem/problem.html:148 msgid "My tickets" msgstr "" -#: templates/problem/problem.html:196 +#: templates/problem/problem.html:156 msgid "Manage submissions" msgstr "" -#: templates/problem/problem.html:202 +#: templates/problem/problem.html:162 msgid "Clone problem" msgstr "" -#: templates/problem/problem.html:209 +#: templates/problem/problem.html:169 msgid "Points:" msgstr "" -#: templates/problem/problem.html:212 templates/problem/problem.html:214 +#: templates/problem/problem.html:172 templates/problem/problem.html:174 msgid "(partial)" msgstr "" -#: templates/problem/problem.html:219 +#: templates/problem/problem.html:179 msgid "Time limit:" msgstr "" -#: templates/problem/problem.html:231 +#: templates/problem/problem.html:191 msgid "Memory limit:" msgstr "" -#: templates/problem/problem.html:250 -#, fuzzy -#| msgid "Authors" -msgid "Author:" -msgid_plural "Authors:" -msgstr[0] "저자" - -#: templates/problem/problem.html:265 -#, fuzzy -#| msgid "problem type" -msgid "Problem type" -msgid_plural "Problem types" -msgstr[0] "문제 유형" - -#: templates/problem/problem.html:278 +#: templates/problem/problem.html:238 msgid "Allowed languages" msgstr "" -#: templates/problem/problem.html:286 -#, python-format -msgid "No %(lang)s judge online" -msgstr "" - -#: templates/problem/problem.html:297 -#, fuzzy -#| msgid "judge" -msgid "Judge:" -msgid_plural "Judges:" -msgstr[0] "채점" - -#: templates/problem/problem.html:314 +#: templates/problem/problem.html:274 msgid "none available" msgstr "" -#: templates/problem/problem.html:326 -#, python-format -msgid "This problem has %(length)s clarification(s)" -msgstr "" - -#: templates/problem/problem.html:350 +#: templates/problem/problem.html:299 msgid "Request clarification" msgstr "" -#: templates/problem/problem.html:352 +#: templates/problem/problem.html:301 msgid "Report an issue" msgstr "" -#: templates/problem/raw.html:64 +#: templates/problem/raw.html:62 msgid "Time Limit:" msgstr "" -#: templates/problem/raw.html:73 +#: templates/problem/raw.html:71 msgid "Memory Limit:" msgstr "" @@ -4216,72 +3725,39 @@ msgstr "" msgid "Show problem types" msgstr "" -#: templates/problem/search-form.html:32 -msgid "Show editorial" -msgstr "" - -#: templates/problem/search-form.html:48 templates/problem/search-form.html:50 -#: templates/submission/submission-list-tabs.html:4 +#: templates/problem/search-form.html:33 templates/problem/search-form.html:35 msgid "All" msgstr "" -#: templates/problem/search-form.html:62 +#: templates/problem/search-form.html:46 msgid "Problem types" msgstr "" -#: templates/problem/search-form.html:73 +#: templates/problem/search-form.html:57 msgid "Point range" msgstr "" -#: templates/problem/search-form.html:79 templates/submission/list.html:331 +#: templates/problem/search-form.html:63 templates/submission/list.html:331 #: templates/ticket/list.html:248 msgid "Go" msgstr "" -#: templates/problem/search-form.html:80 +#: templates/problem/search-form.html:64 msgid "Random" msgstr "" -#: templates/problem/submit.html:117 -msgid "Your source code must contain at most 65536 characters." -msgstr "" - -#: templates/problem/submit.html:204 -#, python-format -msgid "" -"Warning! Your default language, %(default_language)s, is " -"unavailable for this problem and has been deselected." -msgstr "" - -#: templates/problem/submit.html:215 -#, python-format -msgid "" -"\n" -" You have %(left)s submission left\n" -" " -msgid_plural "" -"\n" -" You have %(left)s submissions left\n" -" " -msgstr[0] "" - -#: templates/problem/submit.html:224 +#: templates/problem/submit.html:212 msgid "You have 0 submissions left" msgstr "" -#: templates/problem/submit.html:258 +#: templates/problem/submit.html:250 msgid "No judge is available for this problem." msgstr "" -#: templates/problem/submit.html:262 +#: templates/problem/submit.html:252 msgid "Submit!" msgstr "" -#: templates/registration/activate.html:3 -#, python-format -msgid "%(key)s is an invalid activation key." -msgstr "" - #: templates/registration/activation_complete.html:3 msgid "Your account has been successfully activated." msgstr "" @@ -4339,13 +3815,6 @@ msgid "" "you registered with, and check your spam folder." msgstr "" -#: templates/registration/password_reset_email.txt:1 -#, python-format -msgid "" -"You're receiving this email because you requested a password reset for your " -"user account at %(site_name)s." -msgstr "" - #: templates/registration/password_reset_email.txt:3 msgid "Please go to the following page and choose a new password:" msgstr "" @@ -4358,16 +3827,6 @@ msgstr "" msgid "Thanks for using our site!" msgstr "" -#: templates/registration/password_reset_email.txt:11 -#, python-format -msgid "The %(site_name)s team" -msgstr "" - -#: templates/registration/password_reset_subject.txt:1 -#, python-format -msgid "Password reset on %(site_name)s" -msgstr "" - #: templates/registration/profile_creation.html:36 #: templates/registration/username_select.html:7 msgid "Continue >" @@ -4404,20 +3863,19 @@ msgstr "" msgid "Affiliated organizations" msgstr "" -#: templates/registration/registration_form.html:195 -#: templates/user/edit-profile.html:128 +#: templates/registration/registration_form.html:192 msgid "Notify me about upcoming contests" msgstr "" -#: templates/registration/registration_form.html:209 +#: templates/registration/registration_form.html:206 msgid "By registering, you agree to our" msgstr "" -#: templates/registration/registration_form.html:210 +#: templates/registration/registration_form.html:207 msgid "Terms & Conditions" msgstr "" -#: templates/registration/registration_form.html:213 +#: templates/registration/registration_form.html:210 msgid "Register!" msgstr "" @@ -4427,11 +3885,6 @@ msgstr "" msgid "Enter the 6-digit code generated by your app:" msgstr "" -#: templates/registration/totp_auth.html:41 -#, python-format -msgid "If you lost your authentication device, please contact us at %(email)s." -msgstr "" - #: templates/registration/totp_disable.html:38 msgid "" "To protect your account, you must first authenticate before you can disable " @@ -4450,6 +3903,10 @@ msgstr "" msgid "Or enter this code manually:" msgstr "" +#: templates/stats/base.html:9 templates/submission/list.html:339 +msgid "Statistics" +msgstr "" + #: templates/stats/language.html:11 msgid "Submission Statistics" msgstr "" @@ -4475,7 +3932,6 @@ msgid "Ping" msgstr "" #: templates/status/judge-status-table.html:8 -#: templates/user/import/index.html:104 msgid "Load" msgstr "" @@ -4491,7 +3947,6 @@ msgid "There are no judges available at this time." msgstr "" #: templates/status/language-list.html:33 templates/ticket/list.html:261 -#: templates/user/import/table_csv.html:3 msgid "ID" msgstr "" @@ -4499,24 +3954,6 @@ msgstr "" msgid "Runtime Info" msgstr "" -#: templates/status/status-tabs.html:4 -#, fuzzy -#| msgid "judges" -msgid "Judges" -msgstr "채점기" - -#: templates/status/status-tabs.html:6 -msgid "Version Matrix" -msgstr "" - -#: templates/submission/internal-error-message.html:3 -#, python-format -msgid "" -"An internal error occurred while grading, and the %(SITE_NAME)s " -"administrators have been notified.
In the meantime, try resubmitting in " -"a few seconds." -msgstr "" - #: templates/submission/internal-error-message.html:8 msgid "An internal error occurred while grading." msgstr "" @@ -4533,6 +3970,10 @@ msgstr "" msgid "Filter by language..." msgstr "" +#: templates/submission/list.html:309 +msgid "Filter submissions" +msgstr "" + #: templates/submission/list.html:345 msgid "Total:" msgstr "" @@ -4589,76 +4030,75 @@ msgstr "" msgid "Execution Results" msgstr "" -#: templates/submission/status-testcases.html:34 +#: templates/submission/status-testcases.html:31 +msgid "Batch " +msgstr "" + +#: templates/submission/status-testcases.html:43 msgid "Overall: " msgstr "" -#: templates/submission/status-testcases.html:48 +#: templates/submission/status-testcases.html:57 #, fuzzy #| msgid "Points" msgid "Point: " msgstr "포인트" -#: templates/submission/status-testcases.html:53 +#: templates/submission/status-testcases.html:62 #, fuzzy #| msgid "Time" msgid "Time: " msgstr "시간" -#: templates/submission/status-testcases.html:62 +#: templates/submission/status-testcases.html:71 #, fuzzy #| msgid "Memory" msgid "Memory: " msgstr "Memory" -#: templates/submission/status-testcases.html:73 -msgid "Batch " +#: templates/submission/status-testcases.html:84 +msgid "Case" msgstr "" -#: templates/submission/status-testcases.html:84 -#: templates/submission/status-testcases.html:113 +#: templates/submission/status-testcases.html:86 +msgid "Pretest" +msgstr "" + +#: templates/submission/status-testcases.html:88 +msgid "Test case" +msgstr "" + +#: templates/submission/status-testcases.html:99 #, fuzzy #| msgid "Points" msgid "Point" msgstr "포인트" -#: templates/submission/status-testcases.html:99 -msgid "Case" -msgstr "" - -#: templates/submission/status-testcases.html:101 -msgid "Pretest" -msgstr "" - -#: templates/submission/status-testcases.html:103 -msgid "Test case" -msgstr "" - -#: templates/submission/status-testcases.html:141 +#: templates/submission/status-testcases.html:121 msgid "Input:" msgstr "" -#: templates/submission/status-testcases.html:145 +#: templates/submission/status-testcases.html:125 msgid "Output:" msgstr "" -#: templates/submission/status-testcases.html:149 +#: templates/submission/status-testcases.html:129 #, fuzzy #| msgid "Wrong Answer" msgid "Answer:" msgstr "오답" -#: templates/submission/status-testcases.html:154 +#: templates/submission/status-testcases.html:134 #, fuzzy #| msgid "judging feedback" msgid "Judge feedback:" msgstr "채점 피드백" -#: templates/submission/status-testcases.html:175 +#: templates/submission/status-testcases.html:157 msgid "Passing pretests does not guarantee a full score on system tests." msgstr "" -#: templates/submission/status-testcases.html:178 +#: templates/submission/status-testcases.html:160 msgid "Submission aborted!" msgstr "" @@ -4670,24 +4110,11 @@ msgstr "" msgid "Abort" msgstr "" -#: templates/submission/submission-list-tabs.html:6 -msgid "Mine" -msgstr "" - -#: templates/submission/submission-list-tabs.html:9 -msgid "Best" -msgstr "" - -#: templates/submission/submission-list-tabs.html:12 -#, python-format -msgid "%(user)s's" -msgstr "" - -#: templates/ticket/list.html:135 templates/ticket/ticket.html:273 +#: templates/ticket/list.html:135 templates/ticket/ticket.html:257 msgid "Reopened: " msgstr "" -#: templates/ticket/list.html:138 templates/ticket/ticket.html:274 +#: templates/ticket/list.html:138 templates/ticket/ticket.html:258 msgid "Closed: " msgstr "" @@ -4711,7 +4138,7 @@ msgstr "" msgid "Title" msgstr "" -#: templates/ticket/list.html:264 templates/ticket/ticket.html:369 +#: templates/ticket/list.html:264 templates/ticket/ticket.html:328 msgid "Assignees" msgstr "" @@ -4726,36 +4153,32 @@ msgid "" "a problem, ask in the comments instead." msgstr "" -#: templates/ticket/ticket.html:355 -msgid "Post" -msgstr "" - -#: templates/ticket/ticket.html:363 +#: templates/ticket/ticket.html:322 msgid "Associated object" msgstr "" -#: templates/ticket/ticket.html:374 +#: templates/ticket/ticket.html:333 msgid "No one is assigned." msgstr "" -#: templates/ticket/ticket.html:380 +#: templates/ticket/ticket.html:339 msgid "Close ticket" msgstr "" -#: templates/ticket/ticket.html:382 +#: templates/ticket/ticket.html:341 msgid "Reopen ticket" msgstr "" -#: templates/ticket/ticket.html:386 +#: templates/ticket/ticket.html:345 msgid "Assignee notes" msgstr "" -#: templates/ticket/ticket.html:393 templates/widgets/select_all.html:4 +#: templates/ticket/ticket.html:352 templates/widgets/select_all.html:4 msgid "Nothing here." msgstr "" -#: templates/user/base-users-table.html:3 -msgid "Rank" +#: templates/ticket/ticket.html:385 +msgid "Post" msgstr "" #: templates/user/base-users.html:14 templates/user/base-users.html:69 @@ -4802,188 +4225,50 @@ msgstr "" msgid "Update profile" msgstr "" -#: templates/user/import/index.html:31 -msgid "Upload CSV only" -msgstr "" - -#: templates/user/import/index.html:100 -#, fuzzy -#| msgid "user profile" -msgid "User File" -msgstr "사용자 프로파일" - -#: templates/user/import/index.html:102 -msgid "Sample" -msgstr "" - -#: templates/user/import/index.html:105 templates/user/user-list-tabs.html:8 -msgid "Import" -msgstr "" - -#: templates/user/import/table_csv.html:7 -msgid "School" -msgstr "" - -#: templates/user/pp-row.html:22 -#, python-format -msgid "" -"\n" -" weighted %(weight)s%%\n" -" " -msgstr "" - -#: templates/user/pp-row.html:27 -#, python-format -msgid "%(pp).1fpp" -msgstr "" - -#: templates/user/pp-row.html:29 -#, python-format -msgid "%(pp).0fpp" -msgstr "" - -#: templates/user/user-about.html:23 -#, fuzzy, python-format -#| msgid "contest problems" -msgid "%(counter)s problem solved" -msgid_plural "%(counter)s problems solved" -msgstr[0] "대회 문제" - -#: templates/user/user-about.html:35 -#, fuzzy -#| msgid "allows partial points" -msgid "Total points" -msgstr "부분 점수 허용" - -#: templates/user/user-about.html:45 -#, fuzzy -#| msgid "%s Rankings" -msgid "Rank by rating" -msgstr "%s 순위" - -#: templates/user/user-about.html:52 -#, fuzzy -#| msgid "%s Rankings" -msgid "Rank by points" -msgstr "%s 순위" - -#: templates/user/user-about.html:64 +#: templates/user/user-about.html:14 msgid "From" msgstr "" -#: templates/user/user-about.html:75 +#: templates/user/user-about.html:25 msgid "Admin Notes" msgstr "" -#: templates/user/user-about.html:90 +#: templates/user/user-about.html:40 msgid "You have not shared any information." msgstr "" -#: templates/user/user-about.html:92 +#: templates/user/user-about.html:42 msgid "This user has not shared any information." msgstr "" -#: templates/user/user-about.html:101 -msgid "Awards" +#: templates/user/user-base.html:50 +msgid "Rank by points:" msgstr "" -#: templates/user/user-about.html:112 -#, fuzzy, python-format -#| msgctxt "contest problem" -#| msgid "%(problem)s in %(contest)s" -msgid "%(label)s (%(date)s)" -msgstr "%(problem)s 대회의 문제 %(contest)s" - -#: templates/user/user-about.html:130 -msgid "Mon" +#: templates/user/user-base.html:53 +msgid "Total points:" msgstr "" -#: templates/user/user-about.html:135 -msgid "Tues" +#: templates/user/user-base.html:68 +msgid "Rank by rating:" msgstr "" -#: templates/user/user-about.html:140 -msgid "Wed" +#: templates/user/user-base.html:70 +msgid "Rating:" msgstr "" -#: templates/user/user-about.html:145 -msgid "Thurs" -msgstr "" - -#: templates/user/user-about.html:150 -msgid "Fri" -msgstr "" - -#: templates/user/user-about.html:155 -#, fuzzy -#| msgid "Status" -msgid "Sat" -msgstr "현재 상태" - -#: templates/user/user-about.html:160 -msgid "Sun" -msgstr "" - -#: templates/user/user-about.html:169 -msgid "Less" -msgstr "" - -#: templates/user/user-about.html:175 -msgid "More" -msgstr "" - -#: templates/user/user-about.html:184 -#, fuzzy -#| msgid "History" -msgid "Rating History" -msgstr "히스토리" - -#: templates/user/user-about.html:255 -msgid "past year" -msgstr "" - -#: templates/user/user-about.html:272 -#, fuzzy -#| msgid "All submissions" -msgid "total submission(s)" -msgstr "모든 제출들" - -#: templates/user/user-about.html:276 -#, fuzzy -#| msgid "submission test case" -msgid "submissions in the last year" -msgstr "제출 테스트 케이스" - -#: templates/user/user-base.html:101 -msgid "Unfollow" -msgstr "" - -#: templates/user/user-base.html:104 -msgid "Follow" -msgstr "" - -#: templates/user/user-base.html:120 -#, fuzzy -#| msgid "contest rated" -msgid "Contests written" -msgstr "대회 순위" - -#: templates/user/user-base.html:124 +#: templates/user/user-base.html:71 msgid "Volatility:" msgstr "" -#: templates/user/user-base.html:128 +#: templates/user/user-base.html:72 msgid "Min. rating:" msgstr "" -#: templates/user/user-base.html:132 +#: templates/user/user-base.html:73 msgid "Max rating:" msgstr "" -#: templates/user/user-list-tabs.html:5 -msgid "Friends" -msgstr "" - #: templates/user/user-problems.html:35 msgid "Points Breakdown" msgstr "" @@ -5004,53 +4289,13 @@ msgstr "" msgid "Hide problems I've solved" msgstr "" -#: templates/user/user-problems.html:93 -#, python-format -msgid "%(points).1f points" -msgstr "" - #: templates/user/user-problems.html:99 msgid "Score" msgstr "" -#: templates/user/user-problems.html:110 -#, python-format -msgid "%(points)s / %(total)s" -msgstr "" - -#: templates/user/user-tabs.html:7 -msgid "Impersonate" -msgstr "" - -#: templates/user/user-tabs.html:13 -#, fuzzy -#| msgid "Admin" -msgid "Admin User" -msgstr "관리자" - -#: templates/user/user-tabs.html:16 -msgid "Admin Profile" -msgstr "" - #: templates/widgets/select_all.html:8 msgid "Check all" msgstr "" -#, fuzzy -#~| msgid "contest submission" -#~ msgid "%(cnt)d submission on %(date)s" -#~ msgid_plural "%(cnt)d submissions on %(date)s" -#~ msgstr[0] "대회 제출" - -#, fuzzy -#~| msgid "Admin" -#~ msgid "Admins" -#~ msgstr "관리자" - -#, fuzzy -#~| msgid "Rescore the selected submissions" -#~ msgid "This will rescore %(count)d submissions." -#~ msgstr "재채점" - #~ msgid "output prefix length override" #~ msgstr "출력 접두사 길이 재정의" diff --git a/locale/ko/LC_MESSAGES/djangojs.po b/locale/ko/LC_MESSAGES/djangojs.po index 285ea15..1a5cecb 100644 --- a/locale/ko/LC_MESSAGES/djangojs.po +++ b/locale/ko/LC_MESSAGES/djangojs.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: dmoj\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-07-20 23:30+0700\n" +"POT-Creation-Date: 2019-10-01 23:12+0000\n" "PO-Revision-Date: 2019-11-11 22:05\n" "Last-Translator: Icyene\n" "Language-Team: Korean\n" @@ -26,3 +26,4 @@ msgstr[0] "%d일 %h:%m:%s" msgctxt "time format without day" msgid "%h:%m:%s" msgstr "%h:%m:%s" + diff --git a/locale/lt/LC_MESSAGES/django.po b/locale/lt/LC_MESSAGES/django.po index 6ed93e7..73cd663 100644 --- a/locale/lt/LC_MESSAGES/django.po +++ b/locale/lt/LC_MESSAGES/django.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: dmoj\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-10-25 05:59+0700\n" +"POT-Creation-Date: 2020-04-10 01:26-0500\n" "PO-Revision-Date: 2019-11-11 22:05\n" "Last-Translator: Icyene\n" "Language-Team: Lithuanian\n" @@ -17,93 +17,93 @@ msgstr "" "X-Crowdin-Language: lt\n" "X-Crowdin-File: django.po\n" -#: chat_box/models.py:16 judge/admin/interface.py:110 -#: judge/models/contest.py:403 judge/models/contest.py:528 -#: judge/models/profile.py:211 +#: chat_box/models.py:15 judge/admin/interface.py:107 +#: judge/models/contest.py:257 judge/models/contest.py:381 +#: judge/models/profile.py:191 msgid "user" msgstr "" -#: chat_box/models.py:17 judge/models/comment.py:43 judge/models/comment.py:191 +#: chat_box/models.py:16 judge/models/comment.py:42 msgid "posted time" msgstr "" -#: chat_box/models.py:18 judge/models/comment.py:47 +#: chat_box/models.py:17 judge/models/comment.py:46 msgid "body of comment" msgstr "" -#: chat_box/views.py:29 templates/chat/chat.html:4 +#: chat_box/views.py:29 msgid "Chat Box" msgstr "" -#: dmoj/settings.py:355 +#: dmoj/settings.py:349 msgid "German" msgstr "" -#: dmoj/settings.py:356 +#: dmoj/settings.py:350 msgid "English" msgstr "" -#: dmoj/settings.py:357 +#: dmoj/settings.py:351 msgid "Spanish" msgstr "" -#: dmoj/settings.py:358 +#: dmoj/settings.py:352 msgid "French" msgstr "" -#: dmoj/settings.py:359 +#: dmoj/settings.py:353 msgid "Croatian" msgstr "" -#: dmoj/settings.py:360 +#: dmoj/settings.py:354 msgid "Hungarian" msgstr "" -#: dmoj/settings.py:361 +#: dmoj/settings.py:355 msgid "Japanese" msgstr "" -#: dmoj/settings.py:362 +#: dmoj/settings.py:356 msgid "Korean" msgstr "" -#: dmoj/settings.py:363 +#: dmoj/settings.py:357 msgid "Brazilian Portuguese" msgstr "" -#: dmoj/settings.py:364 +#: dmoj/settings.py:358 msgid "Romanian" msgstr "" -#: dmoj/settings.py:365 +#: dmoj/settings.py:359 msgid "Russian" msgstr "" -#: dmoj/settings.py:366 +#: dmoj/settings.py:360 msgid "Serbian (Latin)" msgstr "" -#: dmoj/settings.py:367 +#: dmoj/settings.py:361 msgid "Turkish" msgstr "" -#: dmoj/settings.py:368 +#: dmoj/settings.py:362 msgid "Vietnamese" msgstr "" -#: dmoj/settings.py:369 +#: dmoj/settings.py:363 msgid "Simplified Chinese" msgstr "" -#: dmoj/settings.py:370 +#: dmoj/settings.py:364 msgid "Traditional Chinese" msgstr "" -#: dmoj/urls.py:58 +#: dmoj/urls.py:57 msgid "Login" msgstr "" -#: dmoj/urls.py:106 templates/base.html:193 +#: dmoj/urls.py:105 templates/base.html:190 msgid "Home" msgstr "" @@ -137,48 +137,46 @@ msgstr "" msgid "Associated page" msgstr "" -#: judge/admin/contest.py:30 +#: judge/admin/contest.py:28 msgid "Included contests" msgstr "" -#: judge/admin/contest.py:66 templates/contest/clarification.html:42 -#: templates/contest/contest.html:83 templates/contest/moss.html:43 -#: templates/problem/list.html:214 templates/problem/list.html:232 -#: templates/problem/list.html:350 templates/user/user-problems.html:56 +#: judge/admin/contest.py:64 templates/contest/contest.html:83 +#: templates/contest/moss.html:43 templates/problem/list.html:206 +#: templates/problem/list.html:221 templates/user/user-problems.html:56 #: templates/user/user-problems.html:98 msgid "Problem" msgstr "" -#: judge/admin/contest.py:119 +#: judge/admin/contest.py:112 msgid "Settings" msgstr "" -#: judge/admin/contest.py:121 +#: judge/admin/contest.py:114 msgid "Scheduling" msgstr "" -#: judge/admin/contest.py:122 templates/organization/home.html:107 +#: judge/admin/contest.py:115 msgid "Details" msgstr "" -#: judge/admin/contest.py:123 +#: judge/admin/contest.py:116 msgid "Format" msgstr "" -#: judge/admin/contest.py:124 templates/contest/ranking-table.html:7 -#: templates/user/user-about.html:15 templates/user/user-about.html:45 +#: judge/admin/contest.py:117 templates/contest/ranking-table.html:5 msgid "Rating" msgstr "" -#: judge/admin/contest.py:125 +#: judge/admin/contest.py:118 msgid "Access" msgstr "" -#: judge/admin/contest.py:127 judge/admin/problem.py:131 +#: judge/admin/contest.py:120 judge/admin/problem.py:131 msgid "Justice" msgstr "" -#: judge/admin/contest.py:207 +#: judge/admin/contest.py:158 #, python-format msgid "%d contest successfully marked as visible." msgid_plural "%d contests successfully marked as visible." @@ -187,11 +185,11 @@ msgstr[1] "" msgstr[2] "" msgstr[3] "" -#: judge/admin/contest.py:210 +#: judge/admin/contest.py:161 msgid "Mark contests as visible" msgstr "" -#: judge/admin/contest.py:216 +#: judge/admin/contest.py:165 #, python-format msgid "%d contest successfully marked as hidden." msgid_plural "%d contests successfully marked as hidden." @@ -200,11 +198,11 @@ msgstr[1] "" msgstr[2] "" msgstr[3] "" -#: judge/admin/contest.py:219 +#: judge/admin/contest.py:168 msgid "Mark contests as hidden" msgstr "" -#: judge/admin/contest.py:233 judge/admin/submission.py:164 +#: judge/admin/contest.py:182 judge/admin/submission.py:164 #, python-format msgid "%d submission was successfully scheduled for rejudging." msgid_plural "%d submissions were successfully scheduled for rejudging." @@ -213,7 +211,7 @@ msgstr[1] "" msgstr[2] "" msgstr[3] "" -#: judge/admin/contest.py:308 +#: judge/admin/contest.py:256 #, python-format msgid "%d participation recalculated." msgid_plural "%d participations recalculated." @@ -222,15 +220,15 @@ msgstr[1] "" msgstr[2] "" msgstr[3] "" -#: judge/admin/contest.py:311 +#: judge/admin/contest.py:259 msgid "Recalculate results" msgstr "" -#: judge/admin/contest.py:315 judge/admin/organization.py:65 +#: judge/admin/contest.py:263 judge/admin/organization.py:65 msgid "username" msgstr "" -#: judge/admin/contest.py:320 templates/base.html:277 +#: judge/admin/contest.py:268 templates/base.html:260 msgid "virtual" msgstr "" @@ -238,15 +236,15 @@ msgstr "" msgid "link path" msgstr "" -#: judge/admin/interface.py:65 +#: judge/admin/interface.py:62 msgid "Content" msgstr "" -#: judge/admin/interface.py:66 +#: judge/admin/interface.py:63 msgid "Summary" msgstr "" -#: judge/admin/interface.py:151 +#: judge/admin/interface.py:148 msgid "object" msgstr "" @@ -268,9 +266,8 @@ msgid "Taxonomy" msgstr "" #: judge/admin/problem.py:128 templates/contest/contest.html:84 -#: templates/problem/data.html:429 templates/problem/list.html:222 -#: templates/problem/list.html:248 templates/user/base-users-table.html:10 -#: templates/user/user-about.html:36 templates/user/user-about.html:52 +#: templates/problem/data.html:449 templates/problem/list.html:211 +#: templates/problem/list.html:232 templates/user/base-users-table.html:10 #: templates/user/user-problems.html:58 msgid "Points" msgstr "" @@ -323,7 +320,6 @@ msgid "timezone" msgstr "" #: judge/admin/profile.py:86 judge/admin/submission.py:211 -#: templates/notification/list.html:12 #: templates/organization/requests/log.html:9 #: templates/organization/requests/pending.html:12 #: templates/ticket/list.html:263 @@ -331,7 +327,6 @@ msgid "User" msgstr "" #: judge/admin/profile.py:91 templates/registration/registration_form.html:145 -#: templates/user/import/table_csv.html:8 msgid "Email" msgstr "" @@ -366,7 +361,7 @@ msgstr "" msgid "These problems are NOT allowed to be submitted in this language" msgstr "" -#: judge/admin/runtime.py:83 templates/problem/list.html:352 +#: judge/admin/runtime.py:83 msgid "Description" msgstr "" @@ -413,7 +408,7 @@ msgstr "" msgid "Rejudge the selected submissions" msgstr "" -#: judge/admin/submission.py:193 judge/views/problem_manage.py:159 +#: judge/admin/submission.py:193 judge/views/problem_manage.py:128 #, python-format msgid "%d submission were successfully rescored." msgid_plural "%d submissions were successfully rescored." @@ -426,8 +421,7 @@ msgstr[3] "" msgid "Rescore the selected submissions" msgstr "" -#: judge/admin/submission.py:200 templates/problem/list.html:216 -#: templates/problem/list.html:236 +#: judge/admin/submission.py:200 msgid "Problem code" msgstr "" @@ -435,12 +429,10 @@ msgstr "" msgid "Problem name" msgstr "" -#: judge/admin/submission.py:215 templates/notification/list.html:15 -#: templates/organization/requests/log.html:10 +#: judge/admin/submission.py:215 templates/organization/requests/log.html:10 #: templates/organization/requests/pending.html:13 -#: templates/problem/list.html:351 -#: templates/submission/status-testcases.html:125 -#: templates/submission/status-testcases.html:127 +#: templates/submission/status-testcases.html:105 +#: templates/submission/status-testcases.html:107 msgid "Time" msgstr "" @@ -454,7 +446,7 @@ msgstr "" msgid "%.2f MB" msgstr "" -#: judge/admin/submission.py:227 templates/submission/status-testcases.html:132 +#: judge/admin/submission.py:227 templates/submission/status-testcases.html:112 msgid "Memory" msgstr "" @@ -474,20 +466,20 @@ msgstr "" msgid "Online Judge" msgstr "" -#: judge/comments.py:60 +#: judge/comments.py:41 msgid "Comment body" msgstr "" -#: judge/comments.py:66 judge/views/ticket.py:63 +#: judge/comments.py:47 judge/views/ticket.py:46 msgid "Your part is silent, little toad." msgstr "" -#: judge/comments.py:69 templates/comments/list.html:132 +#: judge/comments.py:50 templates/comments/list.html:131 msgid "" "You need to have solved at least one problem before your voice can be heard." msgstr "" -#: judge/comments.py:113 +#: judge/comments.py:92 msgid "Posted comment" msgstr "" @@ -503,10 +495,6 @@ msgstr "" msgid "ECOO" msgstr "" -#: judge/contest_format/icpc.py:19 -msgid "ICPC" -msgstr "" - #: judge/contest_format/ioi.py:19 msgid "IOI" msgstr "" @@ -519,58 +507,52 @@ msgstr "" msgid "Enable experimental features" msgstr "" -#: judge/forms.py:57 judge/views/organization.py:168 judge/views/register.py:49 +#: judge/forms.py:57 judge/views/organization.py:127 #, python-brace-format msgid "You may not be part of more than {count} public organizations." msgstr "" -#: judge/forms.py:82 -msgid "Any judge" -msgstr "" - -#: judge/forms.py:112 judge/views/register.py:26 +#: judge/forms.py:107 judge/views/register.py:26 #: templates/registration/registration_form.html:139 #: templates/user/base-users-table.html:5 -#: templates/user/import/table_csv.html:4 msgid "Username" msgstr "" -#: judge/forms.py:113 templates/registration/registration_form.html:151 +#: judge/forms.py:108 templates/registration/registration_form.html:151 #: templates/registration/registration_form.html:165 -#: templates/user/import/table_csv.html:5 msgid "Password" msgstr "" -#: judge/forms.py:135 +#: judge/forms.py:130 msgid "Two Factor Authentication tokens must be 6 decimal digits." msgstr "" -#: judge/forms.py:144 templates/registration/totp_auth.html:32 +#: judge/forms.py:139 templates/registration/totp_auth.html:32 msgid "Invalid Two Factor Authentication token." msgstr "" -#: judge/forms.py:148 judge/models/problem.py:97 +#: judge/forms.py:143 judge/models/problem.py:97 msgid "Problem code must be ^[a-z0-9]+$" msgstr "" -#: judge/forms.py:153 +#: judge/forms.py:148 msgid "Problem with code already exists." msgstr "" -#: judge/forms.py:158 judge/models/contest.py:61 +#: judge/forms.py:153 judge/models/contest.py:52 msgid "Contest id must be ^[a-z0-9]+$" msgstr "" -#: judge/forms.py:163 +#: judge/forms.py:158 msgid "Contest with key already exists." msgstr "" -#: judge/jinja2/datetime.py:26 templates/blog/blog.html:26 +#: judge/jinja2/datetime.py:26 templates/blog/content.html:27 #: templates/blog/dashboard.html:21 msgid "N j, Y, g:i a" msgstr "" -#: judge/jinja2/datetime.py:26 templates/chat/message.html:13 +#: judge/jinja2/datetime.py:26 #, python-brace-format msgid "{time}" msgstr "" @@ -600,542 +582,472 @@ msgstr "" msgid "Detect best quality" msgstr "" -#: judge/models/comment.py:26 +#: judge/models/comment.py:25 msgid "Page code must be ^[pcs]:[a-z0-9]+$|^b:\\d+$" msgstr "" -#: judge/models/comment.py:42 +#: judge/models/comment.py:41 msgid "commenter" msgstr "" -#: judge/models/comment.py:44 judge/models/comment.py:177 +#: judge/models/comment.py:43 judge/models/comment.py:176 msgid "associated page" msgstr "" -#: judge/models/comment.py:46 +#: judge/models/comment.py:45 msgid "votes" msgstr "" -#: judge/models/comment.py:48 +#: judge/models/comment.py:47 msgid "hide the comment" msgstr "" -#: judge/models/comment.py:49 +#: judge/models/comment.py:48 msgid "parent" msgstr "" -#: judge/models/comment.py:54 judge/models/comment.py:192 +#: judge/models/comment.py:53 msgid "comment" msgstr "" -#: judge/models/comment.py:55 +#: judge/models/comment.py:54 msgid "comments" msgstr "" -#: judge/models/comment.py:137 judge/models/problem.py:443 +#: judge/models/comment.py:136 judge/models/problem.py:406 #, python-format msgid "Editorial for %s" msgstr "" -#: judge/models/comment.py:172 +#: judge/models/comment.py:171 msgid "comment vote" msgstr "" -#: judge/models/comment.py:173 +#: judge/models/comment.py:172 msgid "comment votes" msgstr "" -#: judge/models/comment.py:182 +#: judge/models/comment.py:181 msgid "Override comment lock" msgstr "" -#: judge/models/comment.py:190 -msgid "owner" -msgstr "" - -#: judge/models/comment.py:193 judge/models/message.py:16 -msgid "read" -msgstr "" - -#: judge/models/comment.py:194 -msgid "category" -msgstr "" - -#: judge/models/comment.py:195 -msgid "html link to comments, used for non-comments" -msgstr "" - -#: judge/models/comment.py:196 -msgid "who trigger, used for non-comment" -msgstr "" - -#: judge/models/contest.py:23 +#: judge/models/contest.py:22 msgid "Invalid colour." msgstr "" -#: judge/models/contest.py:25 +#: judge/models/contest.py:24 msgid "tag name" msgstr "" -#: judge/models/contest.py:26 +#: judge/models/contest.py:25 msgid "Lowercase letters and hyphens only." msgstr "" -#: judge/models/contest.py:27 +#: judge/models/contest.py:26 msgid "tag colour" msgstr "" -#: judge/models/contest.py:28 +#: judge/models/contest.py:27 msgid "tag description" msgstr "" -#: judge/models/contest.py:47 +#: judge/models/contest.py:46 msgid "contest tag" msgstr "" -#: judge/models/contest.py:48 judge/models/contest.py:118 +#: judge/models/contest.py:47 judge/models/contest.py:101 msgid "contest tags" msgstr "" -#: judge/models/contest.py:56 -msgid "Visible" -msgstr "" - -#: judge/models/contest.py:57 -msgid "Hidden for duration of contest" -msgstr "" - -#: judge/models/contest.py:58 -msgid "Hidden for duration of participation" -msgstr "" - -#: judge/models/contest.py:60 +#: judge/models/contest.py:51 msgid "contest id" msgstr "" -#: judge/models/contest.py:62 +#: judge/models/contest.py:53 msgid "contest name" msgstr "" -#: judge/models/contest.py:63 -msgid "These users will be able to edit the contest." +#: judge/models/contest.py:54 +msgid "These people will be able to edit the contest." msgstr "" -#: judge/models/contest.py:65 -msgid "" -"These users will be able to edit the contest, but will not be listed as " -"authors." -msgstr "" - -#: judge/models/contest.py:68 -msgid "These users will be able to view the contest, but not edit it." -msgstr "" - -#: judge/models/contest.py:71 judge/models/runtime.py:136 +#: judge/models/contest.py:56 judge/models/runtime.py:133 msgid "description" msgstr "" -#: judge/models/contest.py:72 judge/models/problem.py:390 -#: judge/models/runtime.py:138 +#: judge/models/contest.py:57 judge/models/problem.py:353 +#: judge/models/runtime.py:135 msgid "problems" msgstr "" -#: judge/models/contest.py:73 judge/models/contest.py:404 +#: judge/models/contest.py:58 judge/models/contest.py:258 msgid "start time" msgstr "" -#: judge/models/contest.py:74 +#: judge/models/contest.py:59 msgid "end time" msgstr "" -#: judge/models/contest.py:75 judge/models/problem.py:118 -#: judge/models/problem.py:414 +#: judge/models/contest.py:60 judge/models/problem.py:118 +#: judge/models/problem.py:377 msgid "time limit" msgstr "" -#: judge/models/contest.py:76 judge/models/problem.py:136 +#: judge/models/contest.py:61 judge/models/problem.py:136 msgid "publicly visible" msgstr "" -#: judge/models/contest.py:77 +#: judge/models/contest.py:62 msgid "" "Should be set even for organization-private contests, where it determines " "whether the contest is visible to members of the specified organizations." msgstr "" -#: judge/models/contest.py:80 +#: judge/models/contest.py:65 msgid "contest rated" msgstr "" -#: judge/models/contest.py:80 +#: judge/models/contest.py:65 msgid "Whether this contest can be rated." msgstr "" -#: judge/models/contest.py:82 -msgid "scoreboard visibility" +#: judge/models/contest.py:67 +msgid "hide scoreboard" msgstr "" -#: judge/models/contest.py:83 -msgid "Scoreboard visibility through the duration of the contest" +#: judge/models/contest.py:68 +msgid "" +"Whether the scoreboard should remain hidden for the duration of the contest." msgstr "" -#: judge/models/contest.py:85 -msgid "view contest scoreboard" -msgstr "" - -#: judge/models/contest.py:87 -msgid "These users will be able to view the scoreboard." -msgstr "" - -#: judge/models/contest.py:88 +#: judge/models/contest.py:71 msgid "no comments" msgstr "" -#: judge/models/contest.py:89 +#: judge/models/contest.py:72 msgid "Use clarification system instead of comments." msgstr "" -#: judge/models/contest.py:91 +#: judge/models/contest.py:74 msgid "Rating floor for contest" msgstr "" -#: judge/models/contest.py:93 +#: judge/models/contest.py:76 msgid "Rating ceiling for contest" msgstr "" -#: judge/models/contest.py:95 +#: judge/models/contest.py:78 msgid "rate all" msgstr "" -#: judge/models/contest.py:95 +#: judge/models/contest.py:78 msgid "Rate all users who joined." msgstr "" -#: judge/models/contest.py:96 +#: judge/models/contest.py:79 msgid "exclude from ratings" msgstr "" -#: judge/models/contest.py:98 +#: judge/models/contest.py:81 msgid "private to specific users" msgstr "" -#: judge/models/contest.py:99 +#: judge/models/contest.py:82 msgid "private contestants" msgstr "" -#: judge/models/contest.py:100 +#: judge/models/contest.py:83 msgid "If private, only these users may see the contest" msgstr "" -#: judge/models/contest.py:102 +#: judge/models/contest.py:85 msgid "hide problem tags" msgstr "" -#: judge/models/contest.py:103 +#: judge/models/contest.py:86 msgid "Whether problem tags should be hidden by default." msgstr "" -#: judge/models/contest.py:105 +#: judge/models/contest.py:88 msgid "run pretests only" msgstr "" -#: judge/models/contest.py:106 +#: judge/models/contest.py:89 msgid "" "Whether judges should grade pretests only, versus all testcases. Commonly " "set during a contest, then unset prior to rejudging user submissions when " "the contest ends." msgstr "" -#: judge/models/contest.py:110 judge/models/interface.py:77 -#: judge/models/problem.py:157 +#: judge/models/contest.py:93 judge/models/problem.py:157 msgid "private to organizations" msgstr "" -#: judge/models/contest.py:111 judge/models/interface.py:75 -#: judge/models/problem.py:155 judge/models/profile.py:77 +#: judge/models/contest.py:94 judge/models/problem.py:155 +#: judge/models/profile.py:77 msgid "organizations" msgstr "" -#: judge/models/contest.py:112 +#: judge/models/contest.py:95 msgid "If private, only these organizations may see the contest" msgstr "" -#: judge/models/contest.py:113 judge/models/problem.py:145 +#: judge/models/contest.py:96 judge/models/problem.py:145 msgid "OpenGraph image" msgstr "" -#: judge/models/contest.py:114 judge/models/profile.py:48 +#: judge/models/contest.py:97 judge/models/profile.py:48 msgid "Logo override image" msgstr "" -#: judge/models/contest.py:116 +#: judge/models/contest.py:99 msgid "" "This image will replace the default site logo for users inside the contest." msgstr "" -#: judge/models/contest.py:119 +#: judge/models/contest.py:102 msgid "the amount of live participants" msgstr "" -#: judge/models/contest.py:120 +#: judge/models/contest.py:103 msgid "contest summary" msgstr "" -#: judge/models/contest.py:121 judge/models/problem.py:147 +#: judge/models/contest.py:104 judge/models/problem.py:147 msgid "Plain-text, shown in meta description tag, e.g. for social media." msgstr "" -#: judge/models/contest.py:122 judge/models/profile.py:47 +#: judge/models/contest.py:105 judge/models/profile.py:47 msgid "access code" msgstr "" -#: judge/models/contest.py:123 +#: judge/models/contest.py:106 msgid "" "An optional code to prompt contestants before they are allowed to join the " "contest. Leave it blank to disable." msgstr "" -#: judge/models/contest.py:125 judge/models/problem.py:141 +#: judge/models/contest.py:108 judge/models/problem.py:141 msgid "personae non gratae" msgstr "" -#: judge/models/contest.py:126 +#: judge/models/contest.py:109 msgid "Bans the selected users from joining this contest." msgstr "" -#: judge/models/contest.py:127 +#: judge/models/contest.py:110 msgid "contest format" msgstr "" -#: judge/models/contest.py:128 +#: judge/models/contest.py:111 msgid "The contest format module to use." msgstr "" -#: judge/models/contest.py:129 +#: judge/models/contest.py:112 msgid "contest format configuration" msgstr "" -#: judge/models/contest.py:130 +#: judge/models/contest.py:113 msgid "" "A JSON object to serve as the configuration for the chosen contest format " "module. Leave empty to use None. Exact format depends on the contest format " "selected." msgstr "" -#: judge/models/contest.py:137 -msgid "precision points" -msgstr "" - -#: judge/models/contest.py:139 -msgid "Number of digits to round points to." -msgstr "" - -#: judge/models/contest.py:383 +#: judge/models/contest.py:239 msgid "See private contests" msgstr "" -#: judge/models/contest.py:384 +#: judge/models/contest.py:240 msgid "Edit own contests" msgstr "" -#: judge/models/contest.py:385 +#: judge/models/contest.py:241 msgid "Edit all contests" msgstr "" -#: judge/models/contest.py:386 +#: judge/models/contest.py:242 msgid "Clone contest" msgstr "" -#: judge/models/contest.py:387 templates/contest/moss.html:74 +#: judge/models/contest.py:243 templates/contest/moss.html:74 msgid "MOSS contest" msgstr "" -#: judge/models/contest.py:388 +#: judge/models/contest.py:244 msgid "Rate contests" msgstr "" -#: judge/models/contest.py:389 +#: judge/models/contest.py:245 msgid "Contest access codes" msgstr "" -#: judge/models/contest.py:390 +#: judge/models/contest.py:246 msgid "Create private contests" msgstr "" -#: judge/models/contest.py:391 -msgid "Change contest visibility" -msgstr "" - -#: judge/models/contest.py:392 -msgid "Edit contest problem label script" -msgstr "" - -#: judge/models/contest.py:394 judge/models/contest.py:492 -#: judge/models/contest.py:529 judge/models/contest.py:552 -#: judge/models/submission.py:84 +#: judge/models/contest.py:248 judge/models/contest.py:345 +#: judge/models/contest.py:382 judge/models/contest.py:404 +#: judge/models/submission.py:83 msgid "contest" msgstr "" -#: judge/models/contest.py:395 +#: judge/models/contest.py:249 msgid "contests" msgstr "" -#: judge/models/contest.py:402 +#: judge/models/contest.py:256 msgid "associated contest" msgstr "" -#: judge/models/contest.py:405 +#: judge/models/contest.py:259 msgid "score" msgstr "" -#: judge/models/contest.py:406 +#: judge/models/contest.py:260 msgid "cumulative time" msgstr "" -#: judge/models/contest.py:407 +#: judge/models/contest.py:261 msgid "is disqualified" msgstr "" -#: judge/models/contest.py:408 +#: judge/models/contest.py:262 msgid "Whether this participation is disqualified." msgstr "" -#: judge/models/contest.py:409 -msgid "tie-breaking field" -msgstr "" - -#: judge/models/contest.py:410 +#: judge/models/contest.py:263 msgid "virtual participation id" msgstr "" -#: judge/models/contest.py:411 +#: judge/models/contest.py:264 msgid "0 means non-virtual, otherwise the n-th virtual participation." msgstr "" -#: judge/models/contest.py:412 +#: judge/models/contest.py:265 msgid "contest format specific data" msgstr "" -#: judge/models/contest.py:478 +#: judge/models/contest.py:331 #, python-format msgid "%s spectating in %s" msgstr "" -#: judge/models/contest.py:480 +#: judge/models/contest.py:333 #, python-format msgid "%s in %s, v%d" msgstr "" -#: judge/models/contest.py:481 +#: judge/models/contest.py:334 #, python-format msgid "%s in %s" msgstr "" -#: judge/models/contest.py:484 +#: judge/models/contest.py:337 msgid "contest participation" msgstr "" -#: judge/models/contest.py:485 +#: judge/models/contest.py:338 msgid "contest participations" msgstr "" -#: judge/models/contest.py:491 judge/models/contest.py:513 -#: judge/models/contest.py:553 judge/models/problem.py:389 -#: judge/models/problem.py:394 judge/models/problem.py:412 -#: judge/models/problem_data.py:40 +#: judge/models/contest.py:344 judge/models/contest.py:366 +#: judge/models/contest.py:405 judge/models/problem.py:352 +#: judge/models/problem.py:357 judge/models/problem.py:375 +#: judge/models/problem_data.py:38 msgid "problem" msgstr "" -#: judge/models/contest.py:493 judge/models/contest.py:517 +#: judge/models/contest.py:346 judge/models/contest.py:370 #: judge/models/problem.py:129 msgid "points" msgstr "" -#: judge/models/contest.py:494 +#: judge/models/contest.py:347 msgid "partial" msgstr "" -#: judge/models/contest.py:495 judge/models/contest.py:518 +#: judge/models/contest.py:348 judge/models/contest.py:371 msgid "is pretested" msgstr "" -#: judge/models/contest.py:496 judge/models/interface.py:43 +#: judge/models/contest.py:349 judge/models/interface.py:43 msgid "order" msgstr "" -#: judge/models/contest.py:497 +#: judge/models/contest.py:350 msgid "0 to not show testcases, 1 to show" msgstr "" -#: judge/models/contest.py:498 +#: judge/models/contest.py:351 msgid "visible testcases" msgstr "" -#: judge/models/contest.py:499 +#: judge/models/contest.py:352 msgid "Maximum number of submissions for this problem, or 0 for no limit." msgstr "" -#: judge/models/contest.py:501 +#: judge/models/contest.py:354 msgid "Why include a problem you can't submit to?" msgstr "" -#: judge/models/contest.py:506 +#: judge/models/contest.py:359 msgid "contest problem" msgstr "" -#: judge/models/contest.py:507 +#: judge/models/contest.py:360 msgid "contest problems" msgstr "" -#: judge/models/contest.py:511 judge/models/submission.py:183 +#: judge/models/contest.py:364 judge/models/submission.py:181 msgid "submission" msgstr "" -#: judge/models/contest.py:515 judge/models/contest.py:530 +#: judge/models/contest.py:368 judge/models/contest.py:383 msgid "participation" msgstr "" -#: judge/models/contest.py:519 +#: judge/models/contest.py:372 msgid "Whether this submission was ran only on pretests." msgstr "" -#: judge/models/contest.py:523 +#: judge/models/contest.py:376 msgid "contest submission" msgstr "" -#: judge/models/contest.py:524 +#: judge/models/contest.py:377 msgid "contest submissions" msgstr "" -#: judge/models/contest.py:532 +#: judge/models/contest.py:385 msgid "rank" msgstr "" -#: judge/models/contest.py:533 +#: judge/models/contest.py:386 msgid "rating" msgstr "" -#: judge/models/contest.py:534 +#: judge/models/contest.py:387 msgid "volatility" msgstr "" -#: judge/models/contest.py:535 +#: judge/models/contest.py:388 msgid "last rated" msgstr "" -#: judge/models/contest.py:539 +#: judge/models/contest.py:392 msgid "contest rating" msgstr "" -#: judge/models/contest.py:540 +#: judge/models/contest.py:393 msgid "contest ratings" msgstr "" -#: judge/models/contest.py:560 +#: judge/models/contest.py:412 msgid "contest moss result" msgstr "" -#: judge/models/contest.py:561 +#: judge/models/contest.py:413 msgid "contest moss results" msgstr "" @@ -1175,7 +1087,7 @@ msgstr "" msgid "post title" msgstr "" -#: judge/models/interface.py:67 judge/models/problem.py:432 +#: judge/models/interface.py:67 judge/models/problem.py:395 msgid "authors" msgstr "" @@ -1183,7 +1095,7 @@ msgstr "" msgid "slug" msgstr "" -#: judge/models/interface.py:69 judge/models/problem.py:430 +#: judge/models/interface.py:69 judge/models/problem.py:393 msgid "public visibility" msgstr "" @@ -1207,19 +1119,15 @@ msgstr "" msgid "openGraph image" msgstr "" -#: judge/models/interface.py:76 -msgid "If private, only these organizations may see the blog post." -msgstr "" - -#: judge/models/interface.py:105 +#: judge/models/interface.py:91 msgid "Edit all posts" msgstr "" -#: judge/models/interface.py:107 +#: judge/models/interface.py:93 msgid "blog post" msgstr "" -#: judge/models/interface.py:108 +#: judge/models/interface.py:94 msgid "blog posts" msgstr "" @@ -1243,6 +1151,10 @@ msgstr "" msgid "message timestamp" msgstr "" +#: judge/models/message.py:16 +msgid "read" +msgstr "" + #: judge/models/message.py:20 msgid "messages in the thread" msgstr "" @@ -1379,7 +1291,7 @@ msgid "" "are supported." msgstr "" -#: judge/models/problem.py:123 judge/models/problem.py:417 +#: judge/models/problem.py:123 judge/models/problem.py:380 msgid "memory limit" msgstr "" @@ -1452,188 +1364,188 @@ msgstr "" msgid "If private, only these organizations may see the problem." msgstr "" -#: judge/models/problem.py:395 judge/models/problem.py:413 -#: judge/models/runtime.py:111 +#: judge/models/problem.py:358 judge/models/problem.py:376 +#: judge/models/runtime.py:108 msgid "language" msgstr "" -#: judge/models/problem.py:396 +#: judge/models/problem.py:359 msgid "translated name" msgstr "" -#: judge/models/problem.py:397 +#: judge/models/problem.py:360 msgid "translated description" msgstr "" -#: judge/models/problem.py:401 +#: judge/models/problem.py:364 msgid "problem translation" msgstr "" -#: judge/models/problem.py:402 +#: judge/models/problem.py:365 msgid "problem translations" msgstr "" -#: judge/models/problem.py:406 +#: judge/models/problem.py:369 msgid "clarified problem" msgstr "" -#: judge/models/problem.py:407 +#: judge/models/problem.py:370 msgid "clarification body" msgstr "" -#: judge/models/problem.py:408 +#: judge/models/problem.py:371 msgid "clarification timestamp" msgstr "" -#: judge/models/problem.py:423 +#: judge/models/problem.py:386 msgid "language-specific resource limit" msgstr "" -#: judge/models/problem.py:424 +#: judge/models/problem.py:387 msgid "language-specific resource limits" msgstr "" -#: judge/models/problem.py:428 +#: judge/models/problem.py:391 msgid "associated problem" msgstr "" -#: judge/models/problem.py:431 +#: judge/models/problem.py:394 msgid "publish date" msgstr "" -#: judge/models/problem.py:433 +#: judge/models/problem.py:396 msgid "editorial content" msgstr "" -#: judge/models/problem.py:449 +#: judge/models/problem.py:412 msgid "solution" msgstr "" -#: judge/models/problem.py:450 +#: judge/models/problem.py:413 msgid "solutions" msgstr "" -#: judge/models/problem_data.py:26 +#: judge/models/problem_data.py:24 msgid "Standard" msgstr "" -#: judge/models/problem_data.py:27 +#: judge/models/problem_data.py:25 msgid "Floats" msgstr "" -#: judge/models/problem_data.py:28 +#: judge/models/problem_data.py:26 msgid "Floats (absolute)" msgstr "" -#: judge/models/problem_data.py:29 +#: judge/models/problem_data.py:27 msgid "Floats (relative)" msgstr "" -#: judge/models/problem_data.py:30 +#: judge/models/problem_data.py:28 msgid "Non-trailing spaces" msgstr "" -#: judge/models/problem_data.py:31 +#: judge/models/problem_data.py:29 msgid "Unordered" msgstr "" -#: judge/models/problem_data.py:32 +#: judge/models/problem_data.py:30 msgid "Byte identical" msgstr "" -#: judge/models/problem_data.py:33 +#: judge/models/problem_data.py:31 msgid "Line-by-line" msgstr "" -#: judge/models/problem_data.py:34 +#: judge/models/problem_data.py:32 msgid "Custom checker (PY)" msgstr "" -#: judge/models/problem_data.py:35 +#: judge/models/problem_data.py:33 msgid "Custom validator (CPP)" msgstr "" -#: judge/models/problem_data.py:42 +#: judge/models/problem_data.py:40 msgid "data zip file" msgstr "" -#: judge/models/problem_data.py:44 +#: judge/models/problem_data.py:42 msgid "generator file" msgstr "" -#: judge/models/problem_data.py:46 judge/models/problem_data.py:121 +#: judge/models/problem_data.py:44 judge/models/problem_data.py:110 msgid "output prefix length" msgstr "" -#: judge/models/problem_data.py:47 judge/models/problem_data.py:122 +#: judge/models/problem_data.py:45 judge/models/problem_data.py:111 msgid "output limit length" msgstr "" -#: judge/models/problem_data.py:48 +#: judge/models/problem_data.py:46 msgid "init.yml generation feedback" msgstr "" -#: judge/models/problem_data.py:49 judge/models/problem_data.py:123 +#: judge/models/problem_data.py:47 judge/models/problem_data.py:112 msgid "checker" msgstr "" -#: judge/models/problem_data.py:50 judge/models/problem_data.py:124 +#: judge/models/problem_data.py:48 judge/models/problem_data.py:113 msgid "checker arguments" msgstr "" -#: judge/models/problem_data.py:51 judge/models/problem_data.py:125 +#: judge/models/problem_data.py:49 judge/models/problem_data.py:114 msgid "checker arguments as a JSON object" msgstr "" -#: judge/models/problem_data.py:52 +#: judge/models/problem_data.py:50 msgid "custom checker file" msgstr "" -#: judge/models/problem_data.py:58 +#: judge/models/problem_data.py:56 msgid "custom validator file" msgstr "" -#: judge/models/problem_data.py:108 +#: judge/models/problem_data.py:97 msgid "problem data set" msgstr "" -#: judge/models/problem_data.py:110 +#: judge/models/problem_data.py:99 msgid "case position" msgstr "" -#: judge/models/problem_data.py:111 +#: judge/models/problem_data.py:100 msgid "case type" msgstr "" -#: judge/models/problem_data.py:112 +#: judge/models/problem_data.py:101 msgid "Normal case" msgstr "" -#: judge/models/problem_data.py:113 +#: judge/models/problem_data.py:102 msgid "Batch start" msgstr "" -#: judge/models/problem_data.py:114 +#: judge/models/problem_data.py:103 msgid "Batch end" msgstr "" -#: judge/models/problem_data.py:116 +#: judge/models/problem_data.py:105 msgid "input file name" msgstr "" -#: judge/models/problem_data.py:117 +#: judge/models/problem_data.py:106 msgid "output file name" msgstr "" -#: judge/models/problem_data.py:118 +#: judge/models/problem_data.py:107 msgid "generator arguments" msgstr "" -#: judge/models/problem_data.py:119 +#: judge/models/problem_data.py:108 msgid "point value" msgstr "" -#: judge/models/problem_data.py:120 +#: judge/models/problem_data.py:109 msgid "case is pretest?" msgstr "" @@ -1706,7 +1618,7 @@ msgid "" msgstr "" #: judge/models/profile.py:76 judge/models/profile.py:93 -#: judge/models/profile.py:212 +#: judge/models/profile.py:192 msgid "organization" msgstr "" @@ -1802,31 +1714,31 @@ msgstr "" msgid "Notes for administrators regarding this user." msgstr "" -#: judge/models/profile.py:206 +#: judge/models/profile.py:186 msgid "user profile" msgstr "" -#: judge/models/profile.py:207 +#: judge/models/profile.py:187 msgid "user profiles" msgstr "" -#: judge/models/profile.py:214 +#: judge/models/profile.py:194 msgid "request time" msgstr "" -#: judge/models/profile.py:215 +#: judge/models/profile.py:195 msgid "state" msgstr "" -#: judge/models/profile.py:220 +#: judge/models/profile.py:200 msgid "reason" msgstr "" -#: judge/models/profile.py:223 +#: judge/models/profile.py:203 msgid "organization join request" msgstr "" -#: judge/models/profile.py:224 +#: judge/models/profile.py:204 msgid "organization join requests" msgstr "" @@ -1917,86 +1829,86 @@ msgstr "" msgid "The extension of source files, e.g., \"py\" or \"cpp\"." msgstr "" -#: judge/models/runtime.py:112 +#: judge/models/runtime.py:109 msgid "languages" msgstr "" -#: judge/models/runtime.py:116 +#: judge/models/runtime.py:113 msgid "language to which this runtime belongs" msgstr "" -#: judge/models/runtime.py:117 +#: judge/models/runtime.py:114 msgid "judge on which this runtime exists" msgstr "" -#: judge/models/runtime.py:118 +#: judge/models/runtime.py:115 msgid "runtime name" msgstr "" -#: judge/models/runtime.py:119 +#: judge/models/runtime.py:116 msgid "runtime version" msgstr "" -#: judge/models/runtime.py:120 +#: judge/models/runtime.py:117 msgid "order in which to display this runtime" msgstr "" -#: judge/models/runtime.py:124 +#: judge/models/runtime.py:121 msgid "Server name, hostname-style" msgstr "" -#: judge/models/runtime.py:125 +#: judge/models/runtime.py:122 msgid "time of creation" msgstr "" -#: judge/models/runtime.py:126 +#: judge/models/runtime.py:123 msgid "A key to authenticate this judge" msgstr "" -#: judge/models/runtime.py:127 +#: judge/models/runtime.py:124 msgid "authentication key" msgstr "" -#: judge/models/runtime.py:128 +#: judge/models/runtime.py:125 msgid "block judge" msgstr "" -#: judge/models/runtime.py:129 +#: judge/models/runtime.py:126 msgid "" "Whether this judge should be blocked from connecting, even if its key is " "correct." msgstr "" -#: judge/models/runtime.py:131 +#: judge/models/runtime.py:128 msgid "judge online status" msgstr "" -#: judge/models/runtime.py:132 +#: judge/models/runtime.py:129 msgid "judge start time" msgstr "" -#: judge/models/runtime.py:133 +#: judge/models/runtime.py:130 msgid "response time" msgstr "" -#: judge/models/runtime.py:134 +#: judge/models/runtime.py:131 msgid "system load" msgstr "" -#: judge/models/runtime.py:135 +#: judge/models/runtime.py:132 msgid "Load for the last minute, divided by processors to be fair." msgstr "" -#: judge/models/runtime.py:139 judge/models/runtime.py:179 +#: judge/models/runtime.py:136 judge/models/runtime.py:176 msgid "judges" msgstr "" -#: judge/models/runtime.py:178 +#: judge/models/runtime.py:175 msgid "judge" msgstr "" #: judge/models/submission.py:20 judge/models/submission.py:47 -#: judge/utils/problems.py:79 +#: judge/utils/problems.py:77 msgid "Accepted" msgstr "" @@ -2025,7 +1937,7 @@ msgid "Runtime Error" msgstr "" #: judge/models/submission.py:27 judge/models/submission.py:41 -#: judge/models/submission.py:55 judge/utils/problems.py:81 +#: judge/models/submission.py:55 judge/utils/problems.py:79 msgid "Compile Error" msgstr "" @@ -2066,15 +1978,15 @@ msgstr "" msgid "submission time" msgstr "" -#: judge/models/submission.py:67 judge/models/submission.py:203 +#: judge/models/submission.py:67 judge/models/submission.py:201 msgid "execution time" msgstr "" -#: judge/models/submission.py:68 judge/models/submission.py:204 +#: judge/models/submission.py:68 judge/models/submission.py:202 msgid "memory usage" msgstr "" -#: judge/models/submission.py:69 judge/models/submission.py:205 +#: judge/models/submission.py:69 judge/models/submission.py:203 msgid "points granted" msgstr "" @@ -2111,62 +2023,58 @@ msgid "judged on" msgstr "" #: judge/models/submission.py:81 -msgid "submission judge time" -msgstr "" - -#: judge/models/submission.py:82 msgid "was rejudged by admin" msgstr "" -#: judge/models/submission.py:83 +#: judge/models/submission.py:82 msgid "was ran on pretests only" msgstr "" -#: judge/models/submission.py:184 templates/contest/moss.html:58 +#: judge/models/submission.py:182 templates/contest/moss.html:58 msgid "submissions" msgstr "" -#: judge/models/submission.py:188 judge/models/submission.py:199 +#: judge/models/submission.py:186 judge/models/submission.py:197 msgid "associated submission" msgstr "" -#: judge/models/submission.py:190 +#: judge/models/submission.py:188 msgid "source code" msgstr "" -#: judge/models/submission.py:201 +#: judge/models/submission.py:199 msgid "test case ID" msgstr "" -#: judge/models/submission.py:202 +#: judge/models/submission.py:200 msgid "status flag" msgstr "" -#: judge/models/submission.py:206 +#: judge/models/submission.py:204 msgid "points possible" msgstr "" -#: judge/models/submission.py:207 +#: judge/models/submission.py:205 msgid "batch number" msgstr "" -#: judge/models/submission.py:208 +#: judge/models/submission.py:206 msgid "judging feedback" msgstr "" -#: judge/models/submission.py:209 +#: judge/models/submission.py:207 msgid "extended judging feedback" msgstr "" -#: judge/models/submission.py:210 +#: judge/models/submission.py:208 msgid "program output" msgstr "" -#: judge/models/submission.py:218 +#: judge/models/submission.py:216 msgid "submission test case" msgstr "" -#: judge/models/submission.py:219 +#: judge/models/submission.py:217 msgid "submission test cases" msgstr "" @@ -2218,21 +2126,12 @@ msgstr "" msgid "message time" msgstr "" -#: judge/pdf_problems.py:147 judge/pdf_problems.py:199 -#: judge/pdf_problems.py:259 +#: judge/pdf_problems.py:134 judge/pdf_problems.py:186 +#: judge/pdf_problems.py:246 msgid "Page [page] of [topage]" msgstr "" -#: judge/pdf_problems.py:280 -#, python-format -msgid "Page %s of %s" -msgstr "" - -#: judge/tasks/contest.py:19 -msgid "Recalculating contest scores" -msgstr "" - -#: judge/tasks/contest.py:40 +#: judge/tasks/moss.py:25 msgid "Running MOSS" msgstr "" @@ -2244,60 +2143,60 @@ msgstr "" msgid "Recalculating user points" msgstr "" -#: judge/utils/problem_data.py:70 +#: judge/utils/problem_data.py:68 msgid "Empty batches not allowed." msgstr "" -#: judge/utils/problem_data.py:78 judge/utils/problem_data.py:99 +#: judge/utils/problem_data.py:76 judge/utils/problem_data.py:97 msgid "How did you corrupt the custom checker path?" msgstr "" -#: judge/utils/problem_data.py:120 +#: judge/utils/problem_data.py:118 #, python-format msgid "Points must be defined for non-batch case #%d." msgstr "" -#: judge/utils/problem_data.py:125 +#: judge/utils/problem_data.py:123 #, python-format msgid "Input file for case %d does not exist: %s" msgstr "" -#: judge/utils/problem_data.py:128 +#: judge/utils/problem_data.py:126 #, python-format msgid "Output file for case %d does not exist: %s" msgstr "" -#: judge/utils/problem_data.py:153 +#: judge/utils/problem_data.py:151 #, python-format msgid "Batch start case #%d requires points." msgstr "" -#: judge/utils/problem_data.py:174 +#: judge/utils/problem_data.py:172 #, python-format msgid "Attempt to end batch outside of one in case #%d" msgstr "" -#: judge/utils/problem_data.py:192 +#: judge/utils/problem_data.py:190 msgid "How did you corrupt the zip path?" msgstr "" -#: judge/utils/problem_data.py:198 +#: judge/utils/problem_data.py:196 msgid "How did you corrupt the generator path?" msgstr "" -#: judge/utils/problems.py:80 +#: judge/utils/problems.py:78 msgid "Wrong" msgstr "" -#: judge/utils/problems.py:82 +#: judge/utils/problems.py:80 msgid "Timeout" msgstr "" -#: judge/utils/problems.py:83 +#: judge/utils/problems.py:81 msgid "Error" msgstr "" -#: judge/utils/problems.py:94 +#: judge/utils/problems.py:92 msgid "Can't pass both queryset and keyword filters" msgstr "" @@ -2346,8 +2245,7 @@ msgctxt "hours and minutes" msgid "%h:%m" msgstr "" -#: judge/views/about.py:7 templates/organization/home.html:112 -#: templates/user/user-about.html:83 templates/user/user-tabs.html:4 +#: judge/views/about.py:7 templates/user/user-about.html:33 msgid "About" msgstr "" @@ -2355,165 +2253,156 @@ msgstr "" msgid "Custom Checker Sample" msgstr "" -#: judge/views/blog.py:45 +#: judge/views/blog.py:38 #, python-format msgid "Page %d of Posts" msgstr "" -#: judge/views/comment.py:28 +#: judge/views/comment.py:27 msgid "Messing around, are we?" msgstr "" -#: judge/views/comment.py:37 +#: judge/views/comment.py:36 msgid "You must solve at least one problem before you can vote." msgstr "" -#: judge/views/comment.py:64 +#: judge/views/comment.py:63 msgid "You already voted." msgstr "" -#: judge/views/comment.py:126 judge/views/organization.py:344 +#: judge/views/comment.py:120 judge/views/organization.py:299 msgid "Edited from site" msgstr "" -#: judge/views/comment.py:147 +#: judge/views/comment.py:141 msgid "Editing comment" msgstr "" -#: judge/views/contests.py:57 judge/views/contests.py:247 -#: judge/views/contests.py:250 judge/views/contests.py:424 +#: judge/views/contests.py:55 judge/views/contests.py:215 +#: judge/views/contests.py:218 judge/views/contests.py:389 msgid "No such contest" msgstr "" -#: judge/views/contests.py:58 judge/views/contests.py:248 +#: judge/views/contests.py:56 judge/views/contests.py:216 #, python-format msgid "Could not find a contest with the key \"%s\"." msgstr "" -#: judge/views/contests.py:71 +#: judge/views/contests.py:81 msgid "Contests" msgstr "" -#: judge/views/contests.py:251 +#: judge/views/contests.py:219 msgid "Could not find such contest." msgstr "" -#: judge/views/contests.py:254 +#: judge/views/contests.py:222 #, python-format msgid "Access to contest \"%s\" denied" msgstr "" -#: judge/views/contests.py:278 +#: judge/views/contests.py:246 msgid "Clone Contest" msgstr "" -#: judge/views/contests.py:343 +#: judge/views/contests.py:309 msgid "Contest not ongoing" msgstr "" -#: judge/views/contests.py:344 +#: judge/views/contests.py:310 #, python-format msgid "\"%s\" is not currently ongoing." msgstr "" -#: judge/views/contests.py:348 +#: judge/views/contests.py:314 msgid "Already in contest" msgstr "" -#: judge/views/contests.py:349 +#: judge/views/contests.py:315 #, python-format msgid "You are already in a contest: \"%s\"." msgstr "" -#: judge/views/contests.py:352 +#: judge/views/contests.py:318 msgid "Banned from joining" msgstr "" -#: judge/views/contests.py:353 +#: judge/views/contests.py:319 msgid "" "You have been declared persona non grata for this contest. You are " "permanently barred from joining this contest." msgstr "" -#: judge/views/contests.py:414 +#: judge/views/contests.py:379 #, python-format msgid "Enter access code for \"%s\"" msgstr "" -#: judge/views/contests.py:425 +#: judge/views/contests.py:390 #, python-format msgid "You are not in contest \"%s\"." msgstr "" -#: judge/views/contests.py:444 +#: judge/views/contests.py:409 msgid "ContestCalendar requires integer year and month" msgstr "" -#: judge/views/contests.py:484 +#: judge/views/contests.py:449 #, python-format msgid "Contests in %(month)s" msgstr "" -#: judge/views/contests.py:484 +#: judge/views/contests.py:449 msgid "F Y" msgstr "" -#: judge/views/contests.py:532 +#: judge/views/contests.py:496 #, python-format msgid "%s Statistics" msgstr "" -#: judge/views/contests.py:717 +#: judge/views/contests.py:601 +msgid "???" +msgstr "" + +#: judge/views/contests.py:664 #, python-format msgid "%s Rankings" msgstr "" -#: judge/views/contests.py:725 -msgid "???" -msgstr "" - -#: judge/views/contests.py:741 +#: judge/views/contests.py:680 #, python-format msgid "Your participation in %s" msgstr "" -#: judge/views/contests.py:742 +#: judge/views/contests.py:681 #, python-format msgid "%s's participation in %s" msgstr "" -#: judge/views/contests.py:749 +#: judge/views/contests.py:685 msgid "Live" msgstr "" -#: judge/views/contests.py:761 templates/contest/contest-tabs.html:13 +#: judge/views/contests.py:697 msgid "Participation" msgstr "" -#: judge/views/contests.py:808 +#: judge/views/contests.py:743 #, python-format msgid "%s MOSS Results" msgstr "" -#: judge/views/contests.py:835 +#: judge/views/contests.py:770 #, python-format msgid "Running MOSS for %s..." msgstr "" -#: judge/views/contests.py:858 +#: judge/views/contests.py:793 #, python-format msgid "Contest tag: %s" msgstr "" -#: judge/views/contests.py:868 judge/views/ticket.py:57 -msgid "Issue description" -msgstr "" - -#: judge/views/contests.py:911 -#, python-format -msgid "New clarification for %s" -msgstr "" - #: judge/views/error.py:14 msgid "404 error" msgstr "" @@ -2534,83 +2423,76 @@ msgid "corrupt page %s" msgstr "" #: judge/views/language.py:12 templates/status/judge-status-table.html:9 -#: templates/status/status-tabs.html:5 msgid "Runtimes" msgstr "" -#: judge/views/notification.py:40 -#, python-format -msgid "Notifications (%d unseen)" -msgstr "" - -#: judge/views/organization.py:59 judge/views/organization.py:62 +#: judge/views/organization.py:44 judge/views/organization.py:47 msgid "No such organization" msgstr "" -#: judge/views/organization.py:60 +#: judge/views/organization.py:45 #, python-format msgid "Could not find an organization with the key \"%s\"." msgstr "" -#: judge/views/organization.py:63 +#: judge/views/organization.py:48 msgid "Could not find such organization." msgstr "" -#: judge/views/organization.py:79 judge/views/register.py:34 -#: templates/organization/list.html:32 templates/user/import/table_csv.html:9 -#: templates/user/user-list-tabs.html:6 +#: judge/views/organization.py:72 judge/views/register.py:34 +#: templates/organization/list.html:15 msgid "Organizations" msgstr "" -#: judge/views/organization.py:130 +#: judge/views/organization.py:93 #, python-format msgid "%s Members" msgstr "" -#: judge/views/organization.py:159 judge/views/organization.py:162 -#: judge/views/organization.py:167 +#: judge/views/organization.py:118 judge/views/organization.py:121 +#: judge/views/organization.py:126 msgid "Joining organization" msgstr "" -#: judge/views/organization.py:159 +#: judge/views/organization.py:118 msgid "You are already in the organization." msgstr "" -#: judge/views/organization.py:162 +#: judge/views/organization.py:121 msgid "This organization is not open." msgstr "" -#: judge/views/organization.py:179 +#: judge/views/organization.py:138 msgid "Leaving organization" msgstr "" -#: judge/views/organization.py:179 +#: judge/views/organization.py:138 #, python-format msgid "You are not in \"%s\"." msgstr "" -#: judge/views/organization.py:203 +#: judge/views/organization.py:162 #, python-format msgid "Request to join %s" msgstr "" -#: judge/views/organization.py:221 +#: judge/views/organization.py:180 msgid "Join request detail" msgstr "" -#: judge/views/organization.py:254 +#: judge/views/organization.py:209 #, python-format msgid "Managing join requests for %s" msgstr "" -#: judge/views/organization.py:285 +#: judge/views/organization.py:240 #, python-format msgid "" "Your organization can only receive %d more members. You cannot approve %d " "users." msgstr "" -#: judge/views/organization.py:297 +#: judge/views/organization.py:252 #, python-format msgid "Approved %d user." msgid_plural "Approved %d users." @@ -2619,7 +2501,7 @@ msgstr[1] "" msgstr[2] "" msgstr[3] "" -#: judge/views/organization.py:298 +#: judge/views/organization.py:253 #, python-format msgid "Rejected %d user." msgid_plural "Rejected %d users." @@ -2628,32 +2510,32 @@ msgstr[1] "" msgstr[2] "" msgstr[3] "" -#: judge/views/organization.py:328 +#: judge/views/organization.py:283 #, python-format msgid "Editing %s" msgstr "" -#: judge/views/organization.py:352 judge/views/organization.py:360 +#: judge/views/organization.py:307 judge/views/organization.py:315 msgid "Can't edit organization" msgstr "" -#: judge/views/organization.py:353 +#: judge/views/organization.py:308 msgid "You are not allowed to edit this organization." msgstr "" -#: judge/views/organization.py:361 +#: judge/views/organization.py:316 msgid "You are not allowed to kick people from this organization." msgstr "" -#: judge/views/organization.py:366 judge/views/organization.py:370 +#: judge/views/organization.py:321 judge/views/organization.py:325 msgid "Can't kick user" msgstr "" -#: judge/views/organization.py:367 +#: judge/views/organization.py:322 msgid "The user you are trying to kick does not exist!" msgstr "" -#: judge/views/organization.py:371 +#: judge/views/organization.py:326 #, python-format msgid "The user you are trying to kick is not in organization: %s." msgstr "" @@ -2677,36 +2559,35 @@ msgstr "" msgid "Editorial for {0}" msgstr "" -#: judge/views/problem.py:285 templates/contest/contest.html:79 -#: templates/user/user-about.html:28 templates/user/user-tabs.html:5 -#: templates/user/users-table.html:31 +#: judge/views/problem.py:286 templates/contest/contest.html:79 +#: templates/user/users-table.html:23 msgid "Problems" msgstr "" -#: judge/views/problem.py:585 +#: judge/views/problem.py:547 msgid "Banned from submitting" msgstr "" -#: judge/views/problem.py:586 +#: judge/views/problem.py:548 msgid "" "You have been declared persona non grata for this problem. You are " "permanently barred from submitting this problem." msgstr "" -#: judge/views/problem.py:600 +#: judge/views/problem.py:562 msgid "Too many submissions" msgstr "" -#: judge/views/problem.py:601 +#: judge/views/problem.py:563 msgid "You have exceeded the submission limit for this problem." msgstr "" -#: judge/views/problem.py:661 judge/views/problem.py:664 +#: judge/views/problem.py:633 judge/views/problem.py:636 #, python-format msgid "Submit to %(problem)s" msgstr "" -#: judge/views/problem.py:679 +#: judge/views/problem.py:652 msgid "Clone Problem" msgstr "" @@ -2747,22 +2628,22 @@ msgstr "" msgid "Generated init.yml for %s" msgstr "" -#: judge/views/problem_manage.py:52 judge/views/problem_manage.py:55 +#: judge/views/problem_manage.py:50 judge/views/problem_manage.py:53 #, python-format msgid "Managing submissions for %s" msgstr "" -#: judge/views/problem_manage.py:97 +#: judge/views/problem_manage.py:95 #, python-format msgid "Rejudging selected submissions for %s..." msgstr "" -#: judge/views/problem_manage.py:141 +#: judge/views/problem_manage.py:110 #, python-format msgid "Rescoring all submissions for %s..." msgstr "" -#: judge/views/problem_manage.py:150 +#: judge/views/problem_manage.py:119 #, python-format msgid "Successfully scheduled %d submission for rejudging." msgid_plural "Successfully scheduled %d submissions for rejudging." @@ -2813,24 +2694,24 @@ msgstr "" msgid "Subscribe to newsletter?" msgstr "" -#: judge/views/register.py:55 +#: judge/views/register.py:45 #, python-format msgid "" "The email address \"%s\" is already taken. Only one registration is allowed " "per address." msgstr "" -#: judge/views/register.py:61 +#: judge/views/register.py:51 msgid "" "Your email provider is not allowed due to history of abuse. Please use a " "reputable email provider." msgstr "" -#: judge/views/register.py:67 judge/views/register.py:105 +#: judge/views/register.py:57 judge/views/register.py:95 msgid "Registration" msgstr "" -#: judge/views/register.py:116 +#: judge/views/register.py:106 msgid "Authentication failure" msgstr "" @@ -2846,100 +2727,104 @@ msgstr "" msgid "Version matrix" msgstr "" -#: judge/views/submission.py:84 judge/views/submission.py:91 +#: judge/views/submission.py:83 judge/views/submission.py:90 #, python-format msgid "Submission of %(problem)s by %(user)s" msgstr "" -#: judge/views/submission.py:244 judge/views/submission.py:245 -#: templates/problem/problem.html:167 +#: judge/views/submission.py:227 judge/views/submission.py:228 +#: templates/problem/problem.html:127 msgid "All submissions" msgstr "" -#: judge/views/submission.py:404 +#: judge/views/submission.py:384 msgid "All my submissions" msgstr "" -#: judge/views/submission.py:405 +#: judge/views/submission.py:385 #, python-format msgid "All submissions by %s" msgstr "" -#: judge/views/submission.py:436 +#: judge/views/submission.py:416 #, python-format msgid "All submissions for %s" msgstr "" -#: judge/views/submission.py:455 +#: judge/views/submission.py:435 msgid "Must pass a problem" msgstr "" -#: judge/views/submission.py:501 +#: judge/views/submission.py:481 #, python-format msgid "My submissions for %(problem)s" msgstr "" -#: judge/views/submission.py:502 +#: judge/views/submission.py:482 #, python-format msgid "%(user)s's submissions for %(problem)s" msgstr "" -#: judge/views/submission.py:603 +#: judge/views/submission.py:583 msgid "Must pass a contest" msgstr "" -#: judge/views/submission.py:622 +#: judge/views/submission.py:602 #, python-brace-format msgid "" "{0}'s submissions for {2} in {4}" msgstr "" -#: judge/views/submission.py:629 +#: judge/views/submission.py:609 #, python-brace-format msgid "" "{0}'s submissions for problem {2} in {3}" "" msgstr "" -#: judge/views/ticket.py:50 judge/views/ticket.py:56 +#: judge/views/ticket.py:33 judge/views/ticket.py:39 msgid "Ticket title" msgstr "" -#: judge/views/ticket.py:107 judge/views/ticket.py:110 +#: judge/views/ticket.py:40 +msgid "Issue description" +msgstr "" + +#: judge/views/ticket.py:85 judge/views/ticket.py:88 #, python-format msgid "New ticket for %s" msgstr "" -#: judge/views/ticket.py:170 +#: judge/views/ticket.py:142 #, python-format msgid "%(title)s - Ticket %(id)d" msgstr "" -#: judge/views/ticket.py:279 +#: judge/views/ticket.py:251 #, python-format msgid "Tickets - Page %(number)d of %(total)d" msgstr "" -#: judge/views/ticket.py:328 +#: judge/views/ticket.py:300 #, python-format msgid "New Ticket: %s" msgstr "" -#: judge/views/ticket.py:329 +#: judge/views/ticket.py:301 #, python-format msgid "#%(id)d, assigned to: %(users)s" msgstr "" -#: judge/views/ticket.py:331 +#: judge/views/ticket.py:303 msgid ", " msgstr "" -#: judge/views/ticket.py:331 +#: judge/views/ticket.py:303 msgid "no one" msgstr "" -#: judge/views/ticket.py:351 +#: judge/views/ticket.py:323 #, python-format msgid "New Ticket Message For: %s" msgstr "" @@ -2956,50 +2841,41 @@ msgstr "" msgid "Perform Two Factor Authentication" msgstr "" -#: judge/views/user.py:74 +#: judge/views/user.py:68 msgid "No such user" msgstr "" -#: judge/views/user.py:74 +#: judge/views/user.py:68 #, python-format msgid "No user handle \"%s\"." msgstr "" -#: judge/views/user.py:78 +#: judge/views/user.py:72 msgid "My account" msgstr "" -#: judge/views/user.py:79 +#: judge/views/user.py:73 #, python-format msgid "User %s" msgstr "" -#: judge/views/user.py:148 -msgid "M j, Y" -msgstr "" - -#: judge/views/user.py:171 +#: judge/views/user.py:136 msgid "M j, Y, G:i" msgstr "" -#: judge/views/user.py:290 +#: judge/views/user.py:221 msgid "Updated on site" msgstr "" -#: judge/views/user.py:323 templates/admin/auth/user/change_form.html:14 -#: templates/admin/auth/user/change_form.html:17 templates/base.html:238 -#: templates/user/user-tabs.html:10 +#: judge/views/user.py:254 templates/admin/auth/user/change_form.html:14 +#: templates/admin/auth/user/change_form.html:17 templates/base.html:224 msgid "Edit profile" msgstr "" -#: judge/views/user.py:332 templates/user/user-list-tabs.html:4 +#: judge/views/user.py:263 msgid "Leaderboard" msgstr "" -#: judge/views/user.py:407 -msgid "Import Users" -msgstr "" - #: judge/views/widgets.py:48 judge/views/widgets.py:58 #, python-format msgid "Invalid upstream data: %s" @@ -3037,7 +2913,7 @@ msgid "View Submissions" msgstr "" #: templates/admin/judge/problem/change_form.html:17 -#: templates/user/user-base.html:112 +#: templates/user/user-base.html:61 msgid "View submissions" msgstr "" @@ -3052,145 +2928,90 @@ msgstr "" msgid "Rejudge" msgstr "" -#: templates/base.html:230 -#, python-format -msgid "Hello, %(username)s." -msgstr "" - -#: templates/base.html:236 templates/comments/list.html:89 -#: templates/contest/contest-list-tabs.html:24 -#: templates/contest/ranking-table.html:53 -#: templates/problem/problem-list-tabs.html:6 +#: templates/base.html:222 templates/comments/list.html:89 +#: templates/contest/ranking-table.html:39 #: templates/submission/info-base.html:12 -#: templates/submission/submission-list-tabs.html:15 msgid "Admin" msgstr "" -#: templates/base.html:245 +#: templates/base.html:231 msgid "Log out" msgstr "" -#: templates/base.html:254 +#: templates/base.html:240 #: templates/registration/password_reset_complete.html:4 msgid "Log in" msgstr "" -#: templates/base.html:255 templates/registration/registration_form.html:177 +#: templates/base.html:241 templates/registration/registration_form.html:177 msgid "or" msgstr "" -#: templates/base.html:256 +#: templates/base.html:242 msgid "Sign up" msgstr "" -#: templates/base.html:271 +#: templates/base.html:254 msgid "spectating" msgstr "" -#: templates/base.html:284 +#: templates/base.html:267 msgid "This site works best with JavaScript enabled." msgstr "" -#: templates/blog/blog.html:13 templates/comments/list.html:68 -#: templates/comments/list.html:83 templates/contest/contest-tabs.html:23 -#: templates/contest/tag-title.html:9 templates/flatpages/admin_link.html:3 -#: templates/license.html:10 templates/problem/editorial.html:14 +#: templates/blog/content.html:13 templates/comments/list.html:68 +#: templates/comments/list.html:83 templates/contest/tag-title.html:9 +#: templates/flatpages/admin_link.html:3 templates/license.html:10 +#: templates/problem/editorial.html:14 msgid "Edit" msgstr "" -#: templates/blog/blog.html:26 -#, python-format -msgid "" -"\n" -" posted on %(time)s\n" -" " -msgstr "" - -#: templates/blog/content.html:10 -#, python-brace-format -msgid "posted on {time}" -msgstr "" - -#: templates/blog/dashboard.html:21 -#, python-format -msgid "" -"\n" -" on %(time)s\n" -" " -msgstr "" - -#: templates/blog/list.html:93 +#: templates/blog/list.html:85 msgid "Blog" msgstr "" -#: templates/blog/list.html:95 +#: templates/blog/list.html:87 msgid "Events" msgstr "" -#: templates/blog/list.html:100 +#: templates/blog/list.html:92 msgid "News" msgstr "" -#: templates/blog/list.html:115 templates/problem/list.html:347 -#: templates/problem/problem.html:361 +#: templates/blog/list.html:130 templates/problem/problem.html:310 msgid "Clarifications" msgstr "" -#: templates/blog/list.html:121 -msgid "Add" -msgstr "" - -#: templates/blog/list.html:140 templates/problem/list.html:369 -#: templates/problem/problem.html:372 +#: templates/blog/list.html:146 templates/problem/problem.html:321 msgid "No clarifications have been made at this time." msgstr "" -#: templates/blog/list.html:148 +#: templates/blog/list.html:154 msgid "Ongoing contests" msgstr "" -#: templates/blog/list.html:166 +#: templates/blog/list.html:172 msgid "Upcoming contests" msgstr "" -#: templates/blog/list.html:184 -msgid "My open tickets" -msgstr "" - -#: templates/blog/list.html:206 -msgid "New tickets" -msgstr "" - -#: templates/blog/list.html:227 -msgid "New problems" -msgstr "" - -#: templates/blog/list.html:244 +#: templates/blog/list.html:189 msgid "Comment stream" msgstr "" -#: templates/chat/chat.html:305 -msgid "Chat" +#: templates/blog/list.html:208 +msgid "New problems" msgstr "" -#: templates/chat/chat.html:307 templates/chat/chat.html:314 -msgid "Online Users" +#: templates/blog/list.html:225 +msgid "My open tickets" msgstr "" -#: templates/chat/chat.html:315 -msgid "Refresh" +#: templates/blog/list.html:246 +msgid "New tickets" msgstr "" -#: templates/chat/chat.html:333 -msgid "Emoji" -msgstr "" - -#: templates/chat/chat.html:334 -msgid "Enter your message" -msgstr "" - -#: templates/chat/message.html:20 -msgid "Delete" +#: templates/chat/chat.html:167 +msgid "Your message" msgstr "" #: templates/comments/list.html:2 @@ -3201,21 +3022,11 @@ msgstr "" msgid "Please login to vote" msgstr "" -#: templates/comments/list.html:40 -#, python-brace-format -msgid "commented on {time}" -msgstr "" - -#: templates/comments/list.html:49 -#, python-format -msgid "edit %(edits)s" -msgstr "" - -#: templates/comments/list.html:51 templates/comments/media-js.html:92 +#: templates/comments/list.html:51 templates/comments/media-js.html:77 msgid "edited" msgstr "" -#: templates/comments/list.html:60 templates/notification/list.html:14 +#: templates/comments/list.html:60 msgid "Link" msgstr "" @@ -3223,52 +3034,36 @@ msgstr "" msgid "Reply" msgstr "" -#: templates/comments/list.html:86 templates/contest/list.html:91 -#: templates/contest/list.html:95 templates/contest/list.html:280 +#: templates/comments/list.html:86 msgid "Hide" msgstr "" -#: templates/comments/list.html:101 -#, python-format -msgid "" -"\n" -" This comment is hidden due " -"to too much negative feedback.\n" -" Click here to view it.\n" -" " -msgstr "" - -#: templates/comments/list.html:121 +#: templates/comments/list.html:120 msgid "There are no comments at the moment." msgstr "" -#: templates/comments/list.html:127 +#: templates/comments/list.html:126 msgid "New comment" msgstr "" -#: templates/comments/list.html:141 +#: templates/comments/list.html:140 msgid "Invalid comment body." msgstr "" -#: templates/comments/list.html:149 +#: templates/comments/list.html:148 msgid "Post!" msgstr "" -#: templates/comments/list.html:157 +#: templates/comments/list.html:156 msgid "Comments are disabled on this page." msgstr "" -#: templates/comments/media-js.html:38 -msgid "Replying to comment" -msgstr "" - -#: templates/comments/media-js.html:87 +#: templates/comments/media-js.html:72 #, python-brace-format msgid "edit {edits}" msgstr "" -#: templates/comments/media-js.html:90 +#: templates/comments/media-js.html:75 msgid "original" msgstr "" @@ -3312,11 +3107,6 @@ msgstr "" msgid "Saturday" msgstr "" -#: templates/contest/clarification.html:52 templates/organization/new.html:10 -#: templates/ticket/new.html:38 -msgid "Create" -msgstr "" - #: templates/contest/clone.html:37 msgid "Enter a new key for the cloned contest:" msgstr "" @@ -3337,171 +3127,97 @@ msgstr "" msgid "Next" msgstr "" -#: templates/contest/contest-list-tabs.html:21 -#: templates/problem/problem-list-tabs.html:5 -msgid "List" -msgstr "" - -#: templates/contest/contest-list-tabs.html:22 -msgid "Calendar" -msgstr "" - -#: templates/contest/contest-tabs.html:4 templates/organization/home.html:105 -msgid "Info" -msgstr "" - -#: templates/contest/contest-tabs.html:6 templates/stats/base.html:9 -#: templates/submission/list.html:339 -msgid "Statistics" -msgstr "" - -#: templates/contest/contest-tabs.html:11 -msgid "Rankings" -msgstr "" - -#: templates/contest/contest-tabs.html:16 -msgid "Hidden Rankings" -msgstr "" - -#: templates/contest/contest-tabs.html:21 -msgid "MOSS" -msgstr "" - -#: templates/contest/contest-tabs.html:26 -msgid "Clone" -msgstr "" - -#: templates/contest/contest-tabs.html:38 -#: templates/contest/contest-tabs.html:58 +#: templates/contest/contest-tabs.html:37 msgid "Leave contest" msgstr "" -#: templates/contest/contest-tabs.html:45 templates/contest/list.html:388 +#: templates/contest/contest-tabs.html:44 templates/contest/list.html:293 msgid "Virtual join" msgstr "" -#: templates/contest/contest-tabs.html:56 -msgid "Stop spectating" -msgstr "" - -#: templates/contest/contest-tabs.html:65 +#: templates/contest/contest-tabs.html:64 msgid "Spectate contest" msgstr "" -#: templates/contest/contest-tabs.html:72 +#: templates/contest/contest-tabs.html:70 +#: templates/contest/contest-tabs.html:76 msgid "Join contest" msgstr "" -#: templates/contest/contest-tabs.html:81 +#: templates/contest/contest-tabs.html:85 msgid "Login to participate" msgstr "" -#: templates/contest/contest.html:37 -msgid "Participating virtually." -msgstr "" - -#: templates/contest/contest.html:43 -msgid "Contest is over." -msgstr "" - #: templates/contest/contest.html:59 templates/contest/contest.html:63 msgid "F j, Y, G:i T" msgstr "" -#: templates/contest/contest.html:59 -#, python-format -msgid "" -"%(time_limit)s window between %(start_time)s and " -"%(end_time)s" -msgstr "" - -#: templates/contest/contest.html:63 -#, python-format -msgid "%(length)s long starting on %(start_time)s" -msgstr "" - #: templates/contest/contest.html:85 msgid "AC Rate" msgstr "" -#: templates/contest/contest.html:86 templates/contest/list.html:237 -#: templates/contest/list.html:289 templates/contest/list.html:366 -#: templates/problem/list.html:223 templates/problem/list.html:254 +#: templates/contest/contest.html:86 templates/contest/list.html:153 +#: templates/contest/list.html:195 templates/contest/list.html:271 +#: templates/problem/list.html:212 templates/problem/list.html:238 msgid "Users" msgstr "" -#: templates/contest/contest.html:111 templates/problem/list.html:330 +#: templates/contest/contest.html:111 msgid "Editorial" msgstr "" -#: templates/contest/list.html:83 templates/contest/media-js.html:9 +#: templates/contest/list.html:31 templates/contest/media-js.html:9 msgid "Are you sure you want to join?" msgstr "" -#: templates/contest/list.html:84 +#: templates/contest/list.html:32 msgid "" "Joining a contest for the first time starts your timer, after which it " "becomes unstoppable." msgstr "" -#: templates/contest/list.html:92 templates/contest/list.html:278 -msgid "Show" -msgstr "" - -#: templates/contest/list.html:102 templates/problem/list.html:68 -msgid "Organizations..." -msgstr "" - -#: templates/contest/list.html:135 +#: templates/contest/list.html:65 msgid "hidden" msgstr "" -#: templates/contest/list.html:140 +#: templates/contest/list.html:70 msgid "private" msgstr "" -#: templates/contest/list.html:154 +#: templates/contest/list.html:84 msgid "rated" msgstr "" -#: templates/contest/list.html:202 +#: templates/contest/list.html:132 msgid "Spectate" msgstr "" -#: templates/contest/list.html:208 +#: templates/contest/list.html:138 msgid "Join" msgstr "" -#: templates/contest/list.html:220 -msgid "Search contests..." -msgstr "" - -#: templates/contest/list.html:229 -msgid "Search" -msgstr "" - -#: templates/contest/list.html:232 +#: templates/contest/list.html:148 msgid "Active Contests" msgstr "" -#: templates/contest/list.html:236 templates/contest/list.html:288 -#: templates/contest/list.html:327 templates/contest/list.html:365 +#: templates/contest/list.html:152 templates/contest/list.html:194 +#: templates/contest/list.html:232 templates/contest/list.html:270 msgid "Contest" msgstr "" -#: templates/contest/list.html:275 +#: templates/contest/list.html:190 msgid "Ongoing Contests" msgstr "" -#: templates/contest/list.html:322 +#: templates/contest/list.html:227 msgid "Upcoming Contests" msgstr "" -#: templates/contest/list.html:350 +#: templates/contest/list.html:255 msgid "There are no scheduled contests at this time." msgstr "" -#: templates/contest/list.html:356 +#: templates/contest/list.html:261 msgid "Past Contests" msgstr "" @@ -3552,71 +3268,47 @@ msgstr "" msgid "Only the following organizations may access this contest:" msgstr "" -#: templates/contest/ranking-table.html:9 templates/problem/search-form.html:35 +#: templates/contest/ranking-table.html:7 msgid "Organization" msgstr "" -#: templates/contest/ranking-table.html:10 templates/user/users-table.html:13 -msgid "Full Name" -msgstr "" - -#: templates/contest/ranking-table.html:44 +#: templates/contest/ranking-table.html:30 msgid "Un-Disqualify" msgstr "" -#: templates/contest/ranking-table.html:47 +#: templates/contest/ranking-table.html:33 msgid "Disqualify" msgstr "" -#: templates/contest/ranking.html:187 +#: templates/contest/ranking.html:173 msgid "Are you sure you want to disqualify this participation?" msgstr "" -#: templates/contest/ranking.html:192 +#: templates/contest/ranking.html:178 msgid "Are you sure you want to un-disqualify this participation?" msgstr "" -#: templates/contest/ranking.html:463 +#: templates/contest/ranking.html:252 msgid "View user participation" msgstr "" -#: templates/contest/ranking.html:467 +#: templates/contest/ranking.html:256 msgid "Show organizations" msgstr "" -#: templates/contest/ranking.html:471 -msgid "Show full name" -msgstr "" - -#: templates/contest/ranking.html:474 -msgid "Show friends only" -msgstr "" - -#: templates/contest/ranking.html:477 -msgid "Total score only" -msgstr "" - -#: templates/contest/ranking.html:479 -msgid "Show virtual participation" -msgstr "" - -#: templates/contest/stats.html:51 +#: templates/contest/stats.html:38 msgid "Problem Status Distribution" msgstr "" -#: templates/contest/stats.html:56 +#: templates/contest/stats.html:43 msgid "Problem AC Rate" msgstr "" -#: templates/contest/stats.html:62 -msgid "Problem Point Distribution" -msgstr "" - -#: templates/contest/stats.html:76 templates/stats/language.html:16 +#: templates/contest/stats.html:48 templates/stats/language.html:16 msgid "Submissions by Language" msgstr "" -#: templates/contest/stats.html:82 templates/stats/language.html:26 +#: templates/contest/stats.html:54 templates/stats/language.html:26 msgid "Language AC Rate" msgstr "" @@ -3625,7 +3317,6 @@ msgid "Source:" msgstr "" #: templates/newsletter/common.html:6 -#: templates/newsletter/newsletter_list.html:15 #: templates/newsletter/subscription_unsubscribe_activated.html:3 #: templates/newsletter/subscription_unsubscribe_activated.html:6 #: templates/newsletter/subscription_update_activated.html:3 @@ -3633,23 +3324,6 @@ msgstr "" msgid "Newsletter" msgstr "" -#: templates/newsletter/newsletter_list.html:2 -#: templates/newsletter/newsletter_list.html:3 -msgid "Newsletter list" -msgstr "" - -#: templates/newsletter/newsletter_list.html:6 -msgid "Subscribe to get the latest emails about upcoming contests and events." -msgstr "" - -#: templates/newsletter/newsletter_list.html:16 -msgid "Subscribe" -msgstr "" - -#: templates/newsletter/newsletter_list.html:30 -msgid "Update subscriptions" -msgstr "" - #: templates/newsletter/subscription_unsubscribe_activated.html:3 #: templates/newsletter/subscription_unsubscribe_activated.html:6 #: templates/newsletter/subscription_update_activated.html:3 @@ -3711,97 +3385,64 @@ msgid "" "follow in order to update your subscription." msgstr "" -#: templates/notification/list.html:7 -msgid "You have no notifications" -msgstr "" - -#: templates/notification/list.html:13 -msgid "Activity" -msgstr "" - #: templates/organization/edit.html:46 #: templates/organization/requests/pending.html:34 #: templates/ticket/edit-notes.html:4 msgid "Update" msgstr "" -#: templates/organization/home.html:41 +#: templates/organization/home.html:7 msgid "Are you sure you want to leave this organization?" msgstr "" -#: templates/organization/home.html:43 +#: templates/organization/home.html:9 msgid "You will have to rejoin to show up on the organization leaderboard." msgstr "" -#: templates/organization/home.html:45 +#: templates/organization/home.html:11 msgid "You will have to request membership in order to join again." msgstr "" -#: templates/organization/home.html:88 -msgid "Join organization" -msgstr "" - -#: templates/organization/home.html:92 -msgid "Request membership" -msgstr "" - -#: templates/organization/home.html:122 -msgid "Organization news" -msgstr "" - -#: templates/organization/home.html:128 -msgid "There is no news at this time." -msgstr "" - -#: templates/organization/home.html:137 -msgid "Controls" -msgstr "" - -#: templates/organization/home.html:142 -msgid "Edit organization" -msgstr "" - -#: templates/organization/home.html:148 -msgid "View requests" -msgstr "" - -#: templates/organization/home.html:161 -msgid "Admin organization" -msgstr "" - -#: templates/organization/home.html:167 -msgid "View members" -msgstr "" - -#: templates/organization/home.html:174 +#: templates/organization/home.html:24 msgid "Leave organization" msgstr "" -#: templates/organization/home.html:183 -msgid "New private contests" +#: templates/organization/home.html:29 +msgid "Join organization" msgstr "" -#: templates/organization/home.html:193 templates/organization/home.html:208 -msgid "View all" +#: templates/organization/home.html:33 +msgid "Request membership" msgstr "" -#: templates/organization/home.html:199 -msgid "New private problems" +#: templates/organization/home.html:39 +msgid "Edit organization" msgstr "" -#: templates/organization/list.html:40 -msgid "Show my organizations only" +#: templates/organization/home.html:43 +msgid "View requests" msgstr "" -#: templates/organization/list.html:47 templates/status/language-list.html:34 -#: templates/user/import/table_csv.html:6 +#: templates/organization/home.html:50 +msgid "Admin organization" +msgstr "" + +#: templates/organization/home.html:55 +msgid "View members" +msgstr "" + +#: templates/organization/list.html:23 templates/status/language-list.html:34 msgid "Name" msgstr "" -#: templates/organization/list.html:48 +#: templates/organization/list.html:24 msgid "Members" msgstr "" +#: templates/organization/new.html:10 templates/ticket/new.html:38 +msgid "Create" +msgstr "" + #: templates/organization/requests/detail.html:13 msgid "User:" msgstr "" @@ -3834,7 +3475,7 @@ msgid "There are no requests to approve." msgstr "" #: templates/organization/requests/pending.html:17 -#: templates/problem/data.html:432 +#: templates/problem/data.html:452 msgid "Delete?" msgstr "" @@ -3870,35 +3511,35 @@ msgstr "" msgid "Enter a new code for the cloned problem:" msgstr "" -#: templates/problem/data.html:119 +#: templates/problem/data.html:108 msgid "Instruction" msgstr "" -#: templates/problem/data.html:390 +#: templates/problem/data.html:410 msgid "View YAML" msgstr "" -#: templates/problem/data.html:421 templates/problem/data.html:472 +#: templates/problem/data.html:441 templates/problem/data.html:491 msgid "Apply!" msgstr "" -#: templates/problem/data.html:426 +#: templates/problem/data.html:446 msgid "Type" msgstr "" -#: templates/problem/data.html:427 +#: templates/problem/data.html:447 msgid "Input file" msgstr "" -#: templates/problem/data.html:428 +#: templates/problem/data.html:448 msgid "Output file" msgstr "" -#: templates/problem/data.html:430 +#: templates/problem/data.html:450 msgid "Pretest?" msgstr "" -#: templates/problem/data.html:473 +#: templates/problem/data.html:492 msgid "Add new case" msgstr "" @@ -3910,32 +3551,28 @@ msgid "" "problem yourself is a bannable offence." msgstr "" -#: templates/problem/list.html:66 +#: templates/problem/list.html:62 msgid "Filter by type..." msgstr "" -#: templates/problem/list.html:193 +#: templates/problem/list.html:185 msgid "Hot problems" msgstr "" -#: templates/problem/list.html:218 templates/problem/list.html:240 -#: templates/problem/search-form.html:45 templates/user/user-problems.html:57 +#: templates/problem/list.html:207 templates/problem/list.html:224 +#: templates/problem/search-form.html:30 templates/user/user-problems.html:57 msgid "Category" msgstr "" -#: templates/problem/list.html:220 templates/problem/list.html:244 +#: templates/problem/list.html:209 templates/problem/list.html:228 msgid "Types" msgstr "" -#: templates/problem/list.html:251 +#: templates/problem/list.html:235 #, python-format msgid "AC %%" msgstr "" -#: templates/problem/list.html:342 -msgid "Add clarifications" -msgstr "" - #: templates/problem/manage_submission.html:55 msgid "Leave empty to not filter by language" msgstr "" @@ -3944,207 +3581,152 @@ msgstr "" msgid "Leave empty to not filter by result" msgstr "" -#: templates/problem/manage_submission.html:80 +#: templates/problem/manage_submission.html:79 msgid "Need valid values for both start and end IDs." msgstr "" -#: templates/problem/manage_submission.html:83 +#: templates/problem/manage_submission.html:82 msgid "End ID must be after start ID." msgstr "" +#: templates/problem/manage_submission.html:90 +#, python-brace-format +msgid "" +"You are about to rejudge {count} submissions. Are you sure you want to do " +"this?" +msgstr "" + #: templates/problem/manage_submission.html:96 -#, python-brace-format msgid "" -"You are about to {action} {count} submissions. Are you sure you want to do " -"this?" +"You are about to rejudge a few submissions. Are you sure you want to do this?" msgstr "" -#: templates/problem/manage_submission.html:103 -#, python-brace-format -msgid "" -"You are about to {action} a few submissions. Are you sure you want to do " -"this?" +#: templates/problem/manage_submission.html:115 +msgid "Rejudge Submissions" msgstr "" -#: templates/problem/manage_submission.html:127 -#: templates/submission/list.html:309 -msgid "Filter submissions" -msgstr "" - -#: templates/problem/manage_submission.html:132 +#: templates/problem/manage_submission.html:120 msgid "Filter by ID:" msgstr "" -#: templates/problem/manage_submission.html:135 +#: templates/problem/manage_submission.html:123 msgid "Starting ID:" msgstr "" -#: templates/problem/manage_submission.html:139 +#: templates/problem/manage_submission.html:127 msgid "Ending ID:" msgstr "" -#: templates/problem/manage_submission.html:143 +#: templates/problem/manage_submission.html:131 msgid "This range includes both endpoints." msgstr "" -#: templates/problem/manage_submission.html:146 +#: templates/problem/manage_submission.html:134 msgid "Filter by language:" msgstr "" -#: templates/problem/manage_submission.html:154 +#: templates/problem/manage_submission.html:142 msgid "Filter by result:" msgstr "" -#: templates/problem/manage_submission.html:164 -msgid "Action" -msgstr "" - -#: templates/problem/manage_submission.html:166 +#: templates/problem/manage_submission.html:150 msgid "Rejudge selected submissions" msgstr "" -#: templates/problem/manage_submission.html:171 -msgid "Download selected submissions" +#: templates/problem/manage_submission.html:157 +msgid "Rescore Everything" msgstr "" -#: templates/problem/manage_submission.html:177 -#, python-format -msgid "Are you sure you want to rescore %(count)d submissions?" -msgstr "" - -#: templates/problem/manage_submission.html:178 +#: templates/problem/manage_submission.html:163 msgid "Rescore all submissions" msgstr "" -#: templates/problem/problem.html:132 +#: templates/problem/problem.html:91 msgid "View as PDF" msgstr "" -#: templates/problem/problem.html:141 templates/problem/problem.html:151 -#: templates/problem/problem.html:156 +#: templates/problem/problem.html:101 templates/problem/problem.html:111 +#: templates/problem/problem.html:116 msgid "Submit solution" msgstr "" -#: templates/problem/problem.html:144 -#, python-format -msgid "%(counter)s submission left" -msgid_plural "%(counter)s submissions left" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" -msgstr[3] "" - -#: templates/problem/problem.html:152 +#: templates/problem/problem.html:112 msgid "0 submissions left" msgstr "" -#: templates/problem/problem.html:164 +#: templates/problem/problem.html:124 msgid "My submissions" msgstr "" -#: templates/problem/problem.html:168 +#: templates/problem/problem.html:128 msgid "Best submissions" msgstr "" -#: templates/problem/problem.html:172 +#: templates/problem/problem.html:132 msgid "Read editorial" msgstr "" -#: templates/problem/problem.html:177 +#: templates/problem/problem.html:137 msgid "Manage tickets" msgstr "" -#: templates/problem/problem.html:181 +#: templates/problem/problem.html:141 msgid "Edit problem" msgstr "" -#: templates/problem/problem.html:183 +#: templates/problem/problem.html:143 msgid "Edit test data" msgstr "" -#: templates/problem/problem.html:188 +#: templates/problem/problem.html:148 msgid "My tickets" msgstr "" -#: templates/problem/problem.html:196 +#: templates/problem/problem.html:156 msgid "Manage submissions" msgstr "" -#: templates/problem/problem.html:202 +#: templates/problem/problem.html:162 msgid "Clone problem" msgstr "" -#: templates/problem/problem.html:209 +#: templates/problem/problem.html:169 msgid "Points:" msgstr "" -#: templates/problem/problem.html:212 templates/problem/problem.html:214 +#: templates/problem/problem.html:172 templates/problem/problem.html:174 msgid "(partial)" msgstr "" -#: templates/problem/problem.html:219 +#: templates/problem/problem.html:179 msgid "Time limit:" msgstr "" -#: templates/problem/problem.html:231 +#: templates/problem/problem.html:191 msgid "Memory limit:" msgstr "" -#: templates/problem/problem.html:250 -msgid "Author:" -msgid_plural "Authors:" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" -msgstr[3] "" - -#: templates/problem/problem.html:265 -msgid "Problem type" -msgid_plural "Problem types" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" -msgstr[3] "" - -#: templates/problem/problem.html:278 +#: templates/problem/problem.html:238 msgid "Allowed languages" msgstr "" -#: templates/problem/problem.html:286 -#, python-format -msgid "No %(lang)s judge online" -msgstr "" - -#: templates/problem/problem.html:297 -msgid "Judge:" -msgid_plural "Judges:" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" -msgstr[3] "" - -#: templates/problem/problem.html:314 +#: templates/problem/problem.html:274 msgid "none available" msgstr "" -#: templates/problem/problem.html:326 -#, python-format -msgid "This problem has %(length)s clarification(s)" -msgstr "" - -#: templates/problem/problem.html:350 +#: templates/problem/problem.html:299 msgid "Request clarification" msgstr "" -#: templates/problem/problem.html:352 +#: templates/problem/problem.html:301 msgid "Report an issue" msgstr "" -#: templates/problem/raw.html:64 +#: templates/problem/raw.html:62 msgid "Time Limit:" msgstr "" -#: templates/problem/raw.html:73 +#: templates/problem/raw.html:71 msgid "Memory Limit:" msgstr "" @@ -4168,75 +3750,39 @@ msgstr "" msgid "Show problem types" msgstr "" -#: templates/problem/search-form.html:32 -msgid "Show editorial" -msgstr "" - -#: templates/problem/search-form.html:48 templates/problem/search-form.html:50 -#: templates/submission/submission-list-tabs.html:4 +#: templates/problem/search-form.html:33 templates/problem/search-form.html:35 msgid "All" msgstr "" -#: templates/problem/search-form.html:62 +#: templates/problem/search-form.html:46 msgid "Problem types" msgstr "" -#: templates/problem/search-form.html:73 +#: templates/problem/search-form.html:57 msgid "Point range" msgstr "" -#: templates/problem/search-form.html:79 templates/submission/list.html:331 +#: templates/problem/search-form.html:63 templates/submission/list.html:331 #: templates/ticket/list.html:248 msgid "Go" msgstr "" -#: templates/problem/search-form.html:80 +#: templates/problem/search-form.html:64 msgid "Random" msgstr "" -#: templates/problem/submit.html:117 -msgid "Your source code must contain at most 65536 characters." -msgstr "" - -#: templates/problem/submit.html:204 -#, python-format -msgid "" -"Warning! Your default language, %(default_language)s, is " -"unavailable for this problem and has been deselected." -msgstr "" - -#: templates/problem/submit.html:215 -#, python-format -msgid "" -"\n" -" You have %(left)s submission left\n" -" " -msgid_plural "" -"\n" -" You have %(left)s submissions left\n" -" " -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" -msgstr[3] "" - -#: templates/problem/submit.html:224 +#: templates/problem/submit.html:212 msgid "You have 0 submissions left" msgstr "" -#: templates/problem/submit.html:258 +#: templates/problem/submit.html:250 msgid "No judge is available for this problem." msgstr "" -#: templates/problem/submit.html:262 +#: templates/problem/submit.html:252 msgid "Submit!" msgstr "" -#: templates/registration/activate.html:3 -#, python-format -msgid "%(key)s is an invalid activation key." -msgstr "" - #: templates/registration/activation_complete.html:3 msgid "Your account has been successfully activated." msgstr "" @@ -4294,13 +3840,6 @@ msgid "" "you registered with, and check your spam folder." msgstr "" -#: templates/registration/password_reset_email.txt:1 -#, python-format -msgid "" -"You're receiving this email because you requested a password reset for your " -"user account at %(site_name)s." -msgstr "" - #: templates/registration/password_reset_email.txt:3 msgid "Please go to the following page and choose a new password:" msgstr "" @@ -4313,16 +3852,6 @@ msgstr "" msgid "Thanks for using our site!" msgstr "" -#: templates/registration/password_reset_email.txt:11 -#, python-format -msgid "The %(site_name)s team" -msgstr "" - -#: templates/registration/password_reset_subject.txt:1 -#, python-format -msgid "Password reset on %(site_name)s" -msgstr "" - #: templates/registration/profile_creation.html:36 #: templates/registration/username_select.html:7 msgid "Continue >" @@ -4359,20 +3888,19 @@ msgstr "" msgid "Affiliated organizations" msgstr "" -#: templates/registration/registration_form.html:195 -#: templates/user/edit-profile.html:128 +#: templates/registration/registration_form.html:192 msgid "Notify me about upcoming contests" msgstr "" -#: templates/registration/registration_form.html:209 +#: templates/registration/registration_form.html:206 msgid "By registering, you agree to our" msgstr "" -#: templates/registration/registration_form.html:210 +#: templates/registration/registration_form.html:207 msgid "Terms & Conditions" msgstr "" -#: templates/registration/registration_form.html:213 +#: templates/registration/registration_form.html:210 msgid "Register!" msgstr "" @@ -4382,11 +3910,6 @@ msgstr "" msgid "Enter the 6-digit code generated by your app:" msgstr "" -#: templates/registration/totp_auth.html:41 -#, python-format -msgid "If you lost your authentication device, please contact us at %(email)s." -msgstr "" - #: templates/registration/totp_disable.html:38 msgid "" "To protect your account, you must first authenticate before you can disable " @@ -4405,6 +3928,10 @@ msgstr "" msgid "Or enter this code manually:" msgstr "" +#: templates/stats/base.html:9 templates/submission/list.html:339 +msgid "Statistics" +msgstr "" + #: templates/stats/language.html:11 msgid "Submission Statistics" msgstr "" @@ -4430,7 +3957,6 @@ msgid "Ping" msgstr "" #: templates/status/judge-status-table.html:8 -#: templates/user/import/index.html:104 msgid "Load" msgstr "" @@ -4446,7 +3972,6 @@ msgid "There are no judges available at this time." msgstr "" #: templates/status/language-list.html:33 templates/ticket/list.html:261 -#: templates/user/import/table_csv.html:3 msgid "ID" msgstr "" @@ -4454,22 +3979,6 @@ msgstr "" msgid "Runtime Info" msgstr "" -#: templates/status/status-tabs.html:4 -msgid "Judges" -msgstr "" - -#: templates/status/status-tabs.html:6 -msgid "Version Matrix" -msgstr "" - -#: templates/submission/internal-error-message.html:3 -#, python-format -msgid "" -"An internal error occurred while grading, and the %(SITE_NAME)s " -"administrators have been notified.
In the meantime, try resubmitting in " -"a few seconds." -msgstr "" - #: templates/submission/internal-error-message.html:8 msgid "An internal error occurred while grading." msgstr "" @@ -4486,6 +3995,10 @@ msgstr "" msgid "Filter by language..." msgstr "" +#: templates/submission/list.html:309 +msgid "Filter submissions" +msgstr "" + #: templates/submission/list.html:345 msgid "Total:" msgstr "" @@ -4542,64 +4055,63 @@ msgstr "" msgid "Execution Results" msgstr "" -#: templates/submission/status-testcases.html:34 -msgid "Overall: " -msgstr "" - -#: templates/submission/status-testcases.html:48 -msgid "Point: " -msgstr "" - -#: templates/submission/status-testcases.html:53 -msgid "Time: " -msgstr "" - -#: templates/submission/status-testcases.html:62 -msgid "Memory: " -msgstr "" - -#: templates/submission/status-testcases.html:73 +#: templates/submission/status-testcases.html:31 msgid "Batch " msgstr "" -#: templates/submission/status-testcases.html:84 -#: templates/submission/status-testcases.html:113 -msgid "Point" +#: templates/submission/status-testcases.html:43 +msgid "Overall: " msgstr "" -#: templates/submission/status-testcases.html:99 +#: templates/submission/status-testcases.html:57 +msgid "Point: " +msgstr "" + +#: templates/submission/status-testcases.html:62 +msgid "Time: " +msgstr "" + +#: templates/submission/status-testcases.html:71 +msgid "Memory: " +msgstr "" + +#: templates/submission/status-testcases.html:84 msgid "Case" msgstr "" -#: templates/submission/status-testcases.html:101 +#: templates/submission/status-testcases.html:86 msgid "Pretest" msgstr "" -#: templates/submission/status-testcases.html:103 +#: templates/submission/status-testcases.html:88 msgid "Test case" msgstr "" -#: templates/submission/status-testcases.html:141 +#: templates/submission/status-testcases.html:99 +msgid "Point" +msgstr "" + +#: templates/submission/status-testcases.html:121 msgid "Input:" msgstr "" -#: templates/submission/status-testcases.html:145 +#: templates/submission/status-testcases.html:125 msgid "Output:" msgstr "" -#: templates/submission/status-testcases.html:149 +#: templates/submission/status-testcases.html:129 msgid "Answer:" msgstr "" -#: templates/submission/status-testcases.html:154 +#: templates/submission/status-testcases.html:134 msgid "Judge feedback:" msgstr "" -#: templates/submission/status-testcases.html:175 +#: templates/submission/status-testcases.html:157 msgid "Passing pretests does not guarantee a full score on system tests." msgstr "" -#: templates/submission/status-testcases.html:178 +#: templates/submission/status-testcases.html:160 msgid "Submission aborted!" msgstr "" @@ -4611,24 +4123,11 @@ msgstr "" msgid "Abort" msgstr "" -#: templates/submission/submission-list-tabs.html:6 -msgid "Mine" -msgstr "" - -#: templates/submission/submission-list-tabs.html:9 -msgid "Best" -msgstr "" - -#: templates/submission/submission-list-tabs.html:12 -#, python-format -msgid "%(user)s's" -msgstr "" - -#: templates/ticket/list.html:135 templates/ticket/ticket.html:273 +#: templates/ticket/list.html:135 templates/ticket/ticket.html:257 msgid "Reopened: " msgstr "" -#: templates/ticket/list.html:138 templates/ticket/ticket.html:274 +#: templates/ticket/list.html:138 templates/ticket/ticket.html:258 msgid "Closed: " msgstr "" @@ -4652,7 +4151,7 @@ msgstr "" msgid "Title" msgstr "" -#: templates/ticket/list.html:264 templates/ticket/ticket.html:369 +#: templates/ticket/list.html:264 templates/ticket/ticket.html:328 msgid "Assignees" msgstr "" @@ -4667,36 +4166,32 @@ msgid "" "a problem, ask in the comments instead." msgstr "" -#: templates/ticket/ticket.html:355 -msgid "Post" -msgstr "" - -#: templates/ticket/ticket.html:363 +#: templates/ticket/ticket.html:322 msgid "Associated object" msgstr "" -#: templates/ticket/ticket.html:374 +#: templates/ticket/ticket.html:333 msgid "No one is assigned." msgstr "" -#: templates/ticket/ticket.html:380 +#: templates/ticket/ticket.html:339 msgid "Close ticket" msgstr "" -#: templates/ticket/ticket.html:382 +#: templates/ticket/ticket.html:341 msgid "Reopen ticket" msgstr "" -#: templates/ticket/ticket.html:386 +#: templates/ticket/ticket.html:345 msgid "Assignee notes" msgstr "" -#: templates/ticket/ticket.html:393 templates/widgets/select_all.html:4 +#: templates/ticket/ticket.html:352 templates/widgets/select_all.html:4 msgid "Nothing here." msgstr "" -#: templates/user/base-users-table.html:3 -msgid "Rank" +#: templates/ticket/ticket.html:385 +msgid "Post" msgstr "" #: templates/user/base-users.html:14 templates/user/base-users.html:69 @@ -4743,170 +4238,50 @@ msgstr "" msgid "Update profile" msgstr "" -#: templates/user/import/index.html:31 -msgid "Upload CSV only" -msgstr "" - -#: templates/user/import/index.html:100 -msgid "User File" -msgstr "" - -#: templates/user/import/index.html:102 -msgid "Sample" -msgstr "" - -#: templates/user/import/index.html:105 templates/user/user-list-tabs.html:8 -msgid "Import" -msgstr "" - -#: templates/user/import/table_csv.html:7 -msgid "School" -msgstr "" - -#: templates/user/pp-row.html:22 -#, python-format -msgid "" -"\n" -" weighted %(weight)s%%\n" -" " -msgstr "" - -#: templates/user/pp-row.html:27 -#, python-format -msgid "%(pp).1fpp" -msgstr "" - -#: templates/user/pp-row.html:29 -#, python-format -msgid "%(pp).0fpp" -msgstr "" - -#: templates/user/user-about.html:23 -#, python-format -msgid "%(counter)s problem solved" -msgid_plural "%(counter)s problems solved" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" -msgstr[3] "" - -#: templates/user/user-about.html:35 -msgid "Total points" -msgstr "" - -#: templates/user/user-about.html:45 -msgid "Rank by rating" -msgstr "" - -#: templates/user/user-about.html:52 -msgid "Rank by points" -msgstr "" - -#: templates/user/user-about.html:64 +#: templates/user/user-about.html:14 msgid "From" msgstr "" -#: templates/user/user-about.html:75 +#: templates/user/user-about.html:25 msgid "Admin Notes" msgstr "" -#: templates/user/user-about.html:90 +#: templates/user/user-about.html:40 msgid "You have not shared any information." msgstr "" -#: templates/user/user-about.html:92 +#: templates/user/user-about.html:42 msgid "This user has not shared any information." msgstr "" -#: templates/user/user-about.html:101 -msgid "Awards" +#: templates/user/user-base.html:50 +msgid "Rank by points:" msgstr "" -#: templates/user/user-about.html:112 -#, python-format -msgid "%(label)s (%(date)s)" +#: templates/user/user-base.html:53 +msgid "Total points:" msgstr "" -#: templates/user/user-about.html:130 -msgid "Mon" +#: templates/user/user-base.html:68 +msgid "Rank by rating:" msgstr "" -#: templates/user/user-about.html:135 -msgid "Tues" +#: templates/user/user-base.html:70 +msgid "Rating:" msgstr "" -#: templates/user/user-about.html:140 -msgid "Wed" -msgstr "" - -#: templates/user/user-about.html:145 -msgid "Thurs" -msgstr "" - -#: templates/user/user-about.html:150 -msgid "Fri" -msgstr "" - -#: templates/user/user-about.html:155 -msgid "Sat" -msgstr "" - -#: templates/user/user-about.html:160 -msgid "Sun" -msgstr "" - -#: templates/user/user-about.html:169 -msgid "Less" -msgstr "" - -#: templates/user/user-about.html:175 -msgid "More" -msgstr "" - -#: templates/user/user-about.html:184 -msgid "Rating History" -msgstr "" - -#: templates/user/user-about.html:255 -msgid "past year" -msgstr "" - -#: templates/user/user-about.html:272 -msgid "total submission(s)" -msgstr "" - -#: templates/user/user-about.html:276 -msgid "submissions in the last year" -msgstr "" - -#: templates/user/user-base.html:101 -msgid "Unfollow" -msgstr "" - -#: templates/user/user-base.html:104 -msgid "Follow" -msgstr "" - -#: templates/user/user-base.html:120 -msgid "Contests written" -msgstr "" - -#: templates/user/user-base.html:124 +#: templates/user/user-base.html:71 msgid "Volatility:" msgstr "" -#: templates/user/user-base.html:128 +#: templates/user/user-base.html:72 msgid "Min. rating:" msgstr "" -#: templates/user/user-base.html:132 +#: templates/user/user-base.html:73 msgid "Max rating:" msgstr "" -#: templates/user/user-list-tabs.html:5 -msgid "Friends" -msgstr "" - #: templates/user/user-problems.html:35 msgid "Points Breakdown" msgstr "" @@ -4927,32 +4302,10 @@ msgstr "" msgid "Hide problems I've solved" msgstr "" -#: templates/user/user-problems.html:93 -#, python-format -msgid "%(points).1f points" -msgstr "" - #: templates/user/user-problems.html:99 msgid "Score" msgstr "" -#: templates/user/user-problems.html:110 -#, python-format -msgid "%(points)s / %(total)s" -msgstr "" - -#: templates/user/user-tabs.html:7 -msgid "Impersonate" -msgstr "" - -#: templates/user/user-tabs.html:13 -msgid "Admin User" -msgstr "" - -#: templates/user/user-tabs.html:16 -msgid "Admin Profile" -msgstr "" - #: templates/widgets/select_all.html:8 msgid "Check all" msgstr "" diff --git a/locale/lt/LC_MESSAGES/djangojs.po b/locale/lt/LC_MESSAGES/djangojs.po index 7f6fc81..de87146 100644 --- a/locale/lt/LC_MESSAGES/djangojs.po +++ b/locale/lt/LC_MESSAGES/djangojs.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: dmoj\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-07-20 23:30+0700\n" +"POT-Creation-Date: 2019-10-01 23:12+0000\n" "PO-Revision-Date: 2019-11-11 22:05\n" "Last-Translator: Icyene\n" "Language-Team: Lithuanian\n" @@ -10,8 +10,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=4; plural=(n%10==1 && (n%100>19 || n%100<11) ? 0 : (n" -"%10>=2 && n%10<=9) && (n%100>19 || n%100<11) ? 1 : n%1!=0 ? 2: 3);\n" +"Plural-Forms: nplurals=4; plural=(n%10==1 && (n%100>19 || n%100<11) ? 0 : (n%10>=2 && n%10<=9) && (n%100>19 || n%100<11) ? 1 : n%1!=0 ? 2: 3);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: dmoj\n" "X-Crowdin-Language: lt\n" @@ -30,3 +29,4 @@ msgstr[3] "" msgctxt "time format without day" msgid "%h:%m:%s" msgstr "" + diff --git a/locale/nl/LC_MESSAGES/django.po b/locale/nl/LC_MESSAGES/django.po index a300f0f..48a7159 100644 --- a/locale/nl/LC_MESSAGES/django.po +++ b/locale/nl/LC_MESSAGES/django.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: dmoj\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-10-25 05:59+0700\n" +"POT-Creation-Date: 2020-04-10 01:26-0500\n" "PO-Revision-Date: 2019-11-11 22:05\n" "Last-Translator: Icyene\n" "Language-Team: Dutch\n" @@ -16,93 +16,93 @@ msgstr "" "X-Crowdin-Language: nl\n" "X-Crowdin-File: django.po\n" -#: chat_box/models.py:16 judge/admin/interface.py:110 -#: judge/models/contest.py:403 judge/models/contest.py:528 -#: judge/models/profile.py:211 +#: chat_box/models.py:15 judge/admin/interface.py:107 +#: judge/models/contest.py:257 judge/models/contest.py:381 +#: judge/models/profile.py:191 msgid "user" msgstr "" -#: chat_box/models.py:17 judge/models/comment.py:43 judge/models/comment.py:191 +#: chat_box/models.py:16 judge/models/comment.py:42 msgid "posted time" msgstr "" -#: chat_box/models.py:18 judge/models/comment.py:47 +#: chat_box/models.py:17 judge/models/comment.py:46 msgid "body of comment" msgstr "" -#: chat_box/views.py:29 templates/chat/chat.html:4 +#: chat_box/views.py:29 msgid "Chat Box" msgstr "" -#: dmoj/settings.py:355 +#: dmoj/settings.py:349 msgid "German" msgstr "" -#: dmoj/settings.py:356 +#: dmoj/settings.py:350 msgid "English" msgstr "" -#: dmoj/settings.py:357 +#: dmoj/settings.py:351 msgid "Spanish" msgstr "" -#: dmoj/settings.py:358 +#: dmoj/settings.py:352 msgid "French" msgstr "" -#: dmoj/settings.py:359 +#: dmoj/settings.py:353 msgid "Croatian" msgstr "" -#: dmoj/settings.py:360 +#: dmoj/settings.py:354 msgid "Hungarian" msgstr "" -#: dmoj/settings.py:361 +#: dmoj/settings.py:355 msgid "Japanese" msgstr "" -#: dmoj/settings.py:362 +#: dmoj/settings.py:356 msgid "Korean" msgstr "" -#: dmoj/settings.py:363 +#: dmoj/settings.py:357 msgid "Brazilian Portuguese" msgstr "" -#: dmoj/settings.py:364 +#: dmoj/settings.py:358 msgid "Romanian" msgstr "" -#: dmoj/settings.py:365 +#: dmoj/settings.py:359 msgid "Russian" msgstr "" -#: dmoj/settings.py:366 +#: dmoj/settings.py:360 msgid "Serbian (Latin)" msgstr "" -#: dmoj/settings.py:367 +#: dmoj/settings.py:361 msgid "Turkish" msgstr "" -#: dmoj/settings.py:368 +#: dmoj/settings.py:362 msgid "Vietnamese" msgstr "" -#: dmoj/settings.py:369 +#: dmoj/settings.py:363 msgid "Simplified Chinese" msgstr "" -#: dmoj/settings.py:370 +#: dmoj/settings.py:364 msgid "Traditional Chinese" msgstr "" -#: dmoj/urls.py:58 +#: dmoj/urls.py:57 msgid "Login" msgstr "" -#: dmoj/urls.py:106 templates/base.html:193 +#: dmoj/urls.py:105 templates/base.html:190 msgid "Home" msgstr "" @@ -132,92 +132,90 @@ msgstr "" msgid "Associated page" msgstr "" -#: judge/admin/contest.py:30 +#: judge/admin/contest.py:28 msgid "Included contests" msgstr "" -#: judge/admin/contest.py:66 templates/contest/clarification.html:42 -#: templates/contest/contest.html:83 templates/contest/moss.html:43 -#: templates/problem/list.html:214 templates/problem/list.html:232 -#: templates/problem/list.html:350 templates/user/user-problems.html:56 +#: judge/admin/contest.py:64 templates/contest/contest.html:83 +#: templates/contest/moss.html:43 templates/problem/list.html:206 +#: templates/problem/list.html:221 templates/user/user-problems.html:56 #: templates/user/user-problems.html:98 msgid "Problem" msgstr "" -#: judge/admin/contest.py:119 +#: judge/admin/contest.py:112 msgid "Settings" msgstr "" -#: judge/admin/contest.py:121 +#: judge/admin/contest.py:114 msgid "Scheduling" msgstr "" -#: judge/admin/contest.py:122 templates/organization/home.html:107 +#: judge/admin/contest.py:115 msgid "Details" msgstr "" -#: judge/admin/contest.py:123 +#: judge/admin/contest.py:116 msgid "Format" msgstr "" -#: judge/admin/contest.py:124 templates/contest/ranking-table.html:7 -#: templates/user/user-about.html:15 templates/user/user-about.html:45 +#: judge/admin/contest.py:117 templates/contest/ranking-table.html:5 msgid "Rating" msgstr "" -#: judge/admin/contest.py:125 +#: judge/admin/contest.py:118 msgid "Access" msgstr "" -#: judge/admin/contest.py:127 judge/admin/problem.py:131 +#: judge/admin/contest.py:120 judge/admin/problem.py:131 msgid "Justice" msgstr "" -#: judge/admin/contest.py:207 +#: judge/admin/contest.py:158 #, python-format msgid "%d contest successfully marked as visible." msgid_plural "%d contests successfully marked as visible." msgstr[0] "" msgstr[1] "" -#: judge/admin/contest.py:210 +#: judge/admin/contest.py:161 msgid "Mark contests as visible" msgstr "" -#: judge/admin/contest.py:216 +#: judge/admin/contest.py:165 #, python-format msgid "%d contest successfully marked as hidden." msgid_plural "%d contests successfully marked as hidden." msgstr[0] "" msgstr[1] "" -#: judge/admin/contest.py:219 +#: judge/admin/contest.py:168 msgid "Mark contests as hidden" msgstr "" -#: judge/admin/contest.py:233 judge/admin/submission.py:164 +#: judge/admin/contest.py:182 judge/admin/submission.py:164 #, python-format msgid "%d submission was successfully scheduled for rejudging." msgid_plural "%d submissions were successfully scheduled for rejudging." msgstr[0] "" msgstr[1] "" -#: judge/admin/contest.py:308 +#: judge/admin/contest.py:256 #, python-format msgid "%d participation recalculated." msgid_plural "%d participations recalculated." msgstr[0] "" msgstr[1] "" -#: judge/admin/contest.py:311 +#: judge/admin/contest.py:259 msgid "Recalculate results" msgstr "" -#: judge/admin/contest.py:315 judge/admin/organization.py:65 +#: judge/admin/contest.py:263 judge/admin/organization.py:65 msgid "username" msgstr "" -#: judge/admin/contest.py:320 templates/base.html:277 +#: judge/admin/contest.py:268 templates/base.html:260 msgid "virtual" msgstr "" @@ -225,15 +223,15 @@ msgstr "" msgid "link path" msgstr "" -#: judge/admin/interface.py:65 +#: judge/admin/interface.py:62 msgid "Content" msgstr "" -#: judge/admin/interface.py:66 +#: judge/admin/interface.py:63 msgid "Summary" msgstr "" -#: judge/admin/interface.py:151 +#: judge/admin/interface.py:148 msgid "object" msgstr "" @@ -255,9 +253,8 @@ msgid "Taxonomy" msgstr "" #: judge/admin/problem.py:128 templates/contest/contest.html:84 -#: templates/problem/data.html:429 templates/problem/list.html:222 -#: templates/problem/list.html:248 templates/user/base-users-table.html:10 -#: templates/user/user-about.html:36 templates/user/user-about.html:52 +#: templates/problem/data.html:449 templates/problem/list.html:211 +#: templates/problem/list.html:232 templates/user/base-users-table.html:10 #: templates/user/user-problems.html:58 msgid "Points" msgstr "" @@ -306,7 +303,6 @@ msgid "timezone" msgstr "" #: judge/admin/profile.py:86 judge/admin/submission.py:211 -#: templates/notification/list.html:12 #: templates/organization/requests/log.html:9 #: templates/organization/requests/pending.html:12 #: templates/ticket/list.html:263 @@ -314,7 +310,6 @@ msgid "User" msgstr "" #: judge/admin/profile.py:91 templates/registration/registration_form.html:145 -#: templates/user/import/table_csv.html:8 msgid "Email" msgstr "" @@ -347,7 +342,7 @@ msgstr "" msgid "These problems are NOT allowed to be submitted in this language" msgstr "" -#: judge/admin/runtime.py:83 templates/problem/list.html:352 +#: judge/admin/runtime.py:83 msgid "Description" msgstr "" @@ -394,7 +389,7 @@ msgstr "" msgid "Rejudge the selected submissions" msgstr "" -#: judge/admin/submission.py:193 judge/views/problem_manage.py:159 +#: judge/admin/submission.py:193 judge/views/problem_manage.py:128 #, python-format msgid "%d submission were successfully rescored." msgid_plural "%d submissions were successfully rescored." @@ -405,8 +400,7 @@ msgstr[1] "" msgid "Rescore the selected submissions" msgstr "" -#: judge/admin/submission.py:200 templates/problem/list.html:216 -#: templates/problem/list.html:236 +#: judge/admin/submission.py:200 msgid "Problem code" msgstr "" @@ -414,12 +408,10 @@ msgstr "" msgid "Problem name" msgstr "" -#: judge/admin/submission.py:215 templates/notification/list.html:15 -#: templates/organization/requests/log.html:10 +#: judge/admin/submission.py:215 templates/organization/requests/log.html:10 #: templates/organization/requests/pending.html:13 -#: templates/problem/list.html:351 -#: templates/submission/status-testcases.html:125 -#: templates/submission/status-testcases.html:127 +#: templates/submission/status-testcases.html:105 +#: templates/submission/status-testcases.html:107 msgid "Time" msgstr "" @@ -433,7 +425,7 @@ msgstr "" msgid "%.2f MB" msgstr "" -#: judge/admin/submission.py:227 templates/submission/status-testcases.html:132 +#: judge/admin/submission.py:227 templates/submission/status-testcases.html:112 msgid "Memory" msgstr "" @@ -453,20 +445,20 @@ msgstr "" msgid "Online Judge" msgstr "" -#: judge/comments.py:60 +#: judge/comments.py:41 msgid "Comment body" msgstr "" -#: judge/comments.py:66 judge/views/ticket.py:63 +#: judge/comments.py:47 judge/views/ticket.py:46 msgid "Your part is silent, little toad." msgstr "" -#: judge/comments.py:69 templates/comments/list.html:132 +#: judge/comments.py:50 templates/comments/list.html:131 msgid "" "You need to have solved at least one problem before your voice can be heard." msgstr "" -#: judge/comments.py:113 +#: judge/comments.py:92 msgid "Posted comment" msgstr "" @@ -482,10 +474,6 @@ msgstr "" msgid "ECOO" msgstr "" -#: judge/contest_format/icpc.py:19 -msgid "ICPC" -msgstr "" - #: judge/contest_format/ioi.py:19 msgid "IOI" msgstr "" @@ -498,58 +486,52 @@ msgstr "" msgid "Enable experimental features" msgstr "" -#: judge/forms.py:57 judge/views/organization.py:168 judge/views/register.py:49 +#: judge/forms.py:57 judge/views/organization.py:127 #, python-brace-format msgid "You may not be part of more than {count} public organizations." msgstr "" -#: judge/forms.py:82 -msgid "Any judge" -msgstr "" - -#: judge/forms.py:112 judge/views/register.py:26 +#: judge/forms.py:107 judge/views/register.py:26 #: templates/registration/registration_form.html:139 #: templates/user/base-users-table.html:5 -#: templates/user/import/table_csv.html:4 msgid "Username" msgstr "" -#: judge/forms.py:113 templates/registration/registration_form.html:151 +#: judge/forms.py:108 templates/registration/registration_form.html:151 #: templates/registration/registration_form.html:165 -#: templates/user/import/table_csv.html:5 msgid "Password" msgstr "" -#: judge/forms.py:135 +#: judge/forms.py:130 msgid "Two Factor Authentication tokens must be 6 decimal digits." msgstr "" -#: judge/forms.py:144 templates/registration/totp_auth.html:32 +#: judge/forms.py:139 templates/registration/totp_auth.html:32 msgid "Invalid Two Factor Authentication token." msgstr "" -#: judge/forms.py:148 judge/models/problem.py:97 +#: judge/forms.py:143 judge/models/problem.py:97 msgid "Problem code must be ^[a-z0-9]+$" msgstr "" -#: judge/forms.py:153 +#: judge/forms.py:148 msgid "Problem with code already exists." msgstr "" -#: judge/forms.py:158 judge/models/contest.py:61 +#: judge/forms.py:153 judge/models/contest.py:52 msgid "Contest id must be ^[a-z0-9]+$" msgstr "" -#: judge/forms.py:163 +#: judge/forms.py:158 msgid "Contest with key already exists." msgstr "" -#: judge/jinja2/datetime.py:26 templates/blog/blog.html:26 +#: judge/jinja2/datetime.py:26 templates/blog/content.html:27 #: templates/blog/dashboard.html:21 msgid "N j, Y, g:i a" msgstr "" -#: judge/jinja2/datetime.py:26 templates/chat/message.html:13 +#: judge/jinja2/datetime.py:26 #, python-brace-format msgid "{time}" msgstr "" @@ -579,542 +561,472 @@ msgstr "" msgid "Detect best quality" msgstr "" -#: judge/models/comment.py:26 +#: judge/models/comment.py:25 msgid "Page code must be ^[pcs]:[a-z0-9]+$|^b:\\d+$" msgstr "" -#: judge/models/comment.py:42 +#: judge/models/comment.py:41 msgid "commenter" msgstr "" -#: judge/models/comment.py:44 judge/models/comment.py:177 +#: judge/models/comment.py:43 judge/models/comment.py:176 msgid "associated page" msgstr "" -#: judge/models/comment.py:46 +#: judge/models/comment.py:45 msgid "votes" msgstr "" -#: judge/models/comment.py:48 +#: judge/models/comment.py:47 msgid "hide the comment" msgstr "" -#: judge/models/comment.py:49 +#: judge/models/comment.py:48 msgid "parent" msgstr "" -#: judge/models/comment.py:54 judge/models/comment.py:192 +#: judge/models/comment.py:53 msgid "comment" msgstr "" -#: judge/models/comment.py:55 +#: judge/models/comment.py:54 msgid "comments" msgstr "" -#: judge/models/comment.py:137 judge/models/problem.py:443 +#: judge/models/comment.py:136 judge/models/problem.py:406 #, python-format msgid "Editorial for %s" msgstr "" -#: judge/models/comment.py:172 +#: judge/models/comment.py:171 msgid "comment vote" msgstr "" -#: judge/models/comment.py:173 +#: judge/models/comment.py:172 msgid "comment votes" msgstr "" -#: judge/models/comment.py:182 +#: judge/models/comment.py:181 msgid "Override comment lock" msgstr "" -#: judge/models/comment.py:190 -msgid "owner" -msgstr "" - -#: judge/models/comment.py:193 judge/models/message.py:16 -msgid "read" -msgstr "" - -#: judge/models/comment.py:194 -msgid "category" -msgstr "" - -#: judge/models/comment.py:195 -msgid "html link to comments, used for non-comments" -msgstr "" - -#: judge/models/comment.py:196 -msgid "who trigger, used for non-comment" -msgstr "" - -#: judge/models/contest.py:23 +#: judge/models/contest.py:22 msgid "Invalid colour." msgstr "" -#: judge/models/contest.py:25 +#: judge/models/contest.py:24 msgid "tag name" msgstr "" -#: judge/models/contest.py:26 +#: judge/models/contest.py:25 msgid "Lowercase letters and hyphens only." msgstr "" -#: judge/models/contest.py:27 +#: judge/models/contest.py:26 msgid "tag colour" msgstr "" -#: judge/models/contest.py:28 +#: judge/models/contest.py:27 msgid "tag description" msgstr "" -#: judge/models/contest.py:47 +#: judge/models/contest.py:46 msgid "contest tag" msgstr "" -#: judge/models/contest.py:48 judge/models/contest.py:118 +#: judge/models/contest.py:47 judge/models/contest.py:101 msgid "contest tags" msgstr "" -#: judge/models/contest.py:56 -msgid "Visible" -msgstr "" - -#: judge/models/contest.py:57 -msgid "Hidden for duration of contest" -msgstr "" - -#: judge/models/contest.py:58 -msgid "Hidden for duration of participation" -msgstr "" - -#: judge/models/contest.py:60 +#: judge/models/contest.py:51 msgid "contest id" msgstr "" -#: judge/models/contest.py:62 +#: judge/models/contest.py:53 msgid "contest name" msgstr "" -#: judge/models/contest.py:63 -msgid "These users will be able to edit the contest." +#: judge/models/contest.py:54 +msgid "These people will be able to edit the contest." msgstr "" -#: judge/models/contest.py:65 -msgid "" -"These users will be able to edit the contest, but will not be listed as " -"authors." -msgstr "" - -#: judge/models/contest.py:68 -msgid "These users will be able to view the contest, but not edit it." -msgstr "" - -#: judge/models/contest.py:71 judge/models/runtime.py:136 +#: judge/models/contest.py:56 judge/models/runtime.py:133 msgid "description" msgstr "" -#: judge/models/contest.py:72 judge/models/problem.py:390 -#: judge/models/runtime.py:138 +#: judge/models/contest.py:57 judge/models/problem.py:353 +#: judge/models/runtime.py:135 msgid "problems" msgstr "" -#: judge/models/contest.py:73 judge/models/contest.py:404 +#: judge/models/contest.py:58 judge/models/contest.py:258 msgid "start time" msgstr "" -#: judge/models/contest.py:74 +#: judge/models/contest.py:59 msgid "end time" msgstr "" -#: judge/models/contest.py:75 judge/models/problem.py:118 -#: judge/models/problem.py:414 +#: judge/models/contest.py:60 judge/models/problem.py:118 +#: judge/models/problem.py:377 msgid "time limit" msgstr "" -#: judge/models/contest.py:76 judge/models/problem.py:136 +#: judge/models/contest.py:61 judge/models/problem.py:136 msgid "publicly visible" msgstr "" -#: judge/models/contest.py:77 +#: judge/models/contest.py:62 msgid "" "Should be set even for organization-private contests, where it determines " "whether the contest is visible to members of the specified organizations." msgstr "" -#: judge/models/contest.py:80 +#: judge/models/contest.py:65 msgid "contest rated" msgstr "" -#: judge/models/contest.py:80 +#: judge/models/contest.py:65 msgid "Whether this contest can be rated." msgstr "" -#: judge/models/contest.py:82 -msgid "scoreboard visibility" +#: judge/models/contest.py:67 +msgid "hide scoreboard" msgstr "" -#: judge/models/contest.py:83 -msgid "Scoreboard visibility through the duration of the contest" +#: judge/models/contest.py:68 +msgid "" +"Whether the scoreboard should remain hidden for the duration of the contest." msgstr "" -#: judge/models/contest.py:85 -msgid "view contest scoreboard" -msgstr "" - -#: judge/models/contest.py:87 -msgid "These users will be able to view the scoreboard." -msgstr "" - -#: judge/models/contest.py:88 +#: judge/models/contest.py:71 msgid "no comments" msgstr "" -#: judge/models/contest.py:89 +#: judge/models/contest.py:72 msgid "Use clarification system instead of comments." msgstr "" -#: judge/models/contest.py:91 +#: judge/models/contest.py:74 msgid "Rating floor for contest" msgstr "" -#: judge/models/contest.py:93 +#: judge/models/contest.py:76 msgid "Rating ceiling for contest" msgstr "" -#: judge/models/contest.py:95 +#: judge/models/contest.py:78 msgid "rate all" msgstr "" -#: judge/models/contest.py:95 +#: judge/models/contest.py:78 msgid "Rate all users who joined." msgstr "" -#: judge/models/contest.py:96 +#: judge/models/contest.py:79 msgid "exclude from ratings" msgstr "" -#: judge/models/contest.py:98 +#: judge/models/contest.py:81 msgid "private to specific users" msgstr "" -#: judge/models/contest.py:99 +#: judge/models/contest.py:82 msgid "private contestants" msgstr "" -#: judge/models/contest.py:100 +#: judge/models/contest.py:83 msgid "If private, only these users may see the contest" msgstr "" -#: judge/models/contest.py:102 +#: judge/models/contest.py:85 msgid "hide problem tags" msgstr "" -#: judge/models/contest.py:103 +#: judge/models/contest.py:86 msgid "Whether problem tags should be hidden by default." msgstr "" -#: judge/models/contest.py:105 +#: judge/models/contest.py:88 msgid "run pretests only" msgstr "" -#: judge/models/contest.py:106 +#: judge/models/contest.py:89 msgid "" "Whether judges should grade pretests only, versus all testcases. Commonly " "set during a contest, then unset prior to rejudging user submissions when " "the contest ends." msgstr "" -#: judge/models/contest.py:110 judge/models/interface.py:77 -#: judge/models/problem.py:157 +#: judge/models/contest.py:93 judge/models/problem.py:157 msgid "private to organizations" msgstr "" -#: judge/models/contest.py:111 judge/models/interface.py:75 -#: judge/models/problem.py:155 judge/models/profile.py:77 +#: judge/models/contest.py:94 judge/models/problem.py:155 +#: judge/models/profile.py:77 msgid "organizations" msgstr "" -#: judge/models/contest.py:112 +#: judge/models/contest.py:95 msgid "If private, only these organizations may see the contest" msgstr "" -#: judge/models/contest.py:113 judge/models/problem.py:145 +#: judge/models/contest.py:96 judge/models/problem.py:145 msgid "OpenGraph image" msgstr "" -#: judge/models/contest.py:114 judge/models/profile.py:48 +#: judge/models/contest.py:97 judge/models/profile.py:48 msgid "Logo override image" msgstr "" -#: judge/models/contest.py:116 +#: judge/models/contest.py:99 msgid "" "This image will replace the default site logo for users inside the contest." msgstr "" -#: judge/models/contest.py:119 +#: judge/models/contest.py:102 msgid "the amount of live participants" msgstr "" -#: judge/models/contest.py:120 +#: judge/models/contest.py:103 msgid "contest summary" msgstr "" -#: judge/models/contest.py:121 judge/models/problem.py:147 +#: judge/models/contest.py:104 judge/models/problem.py:147 msgid "Plain-text, shown in meta description tag, e.g. for social media." msgstr "" -#: judge/models/contest.py:122 judge/models/profile.py:47 +#: judge/models/contest.py:105 judge/models/profile.py:47 msgid "access code" msgstr "" -#: judge/models/contest.py:123 +#: judge/models/contest.py:106 msgid "" "An optional code to prompt contestants before they are allowed to join the " "contest. Leave it blank to disable." msgstr "" -#: judge/models/contest.py:125 judge/models/problem.py:141 +#: judge/models/contest.py:108 judge/models/problem.py:141 msgid "personae non gratae" msgstr "" -#: judge/models/contest.py:126 +#: judge/models/contest.py:109 msgid "Bans the selected users from joining this contest." msgstr "" -#: judge/models/contest.py:127 +#: judge/models/contest.py:110 msgid "contest format" msgstr "" -#: judge/models/contest.py:128 +#: judge/models/contest.py:111 msgid "The contest format module to use." msgstr "" -#: judge/models/contest.py:129 +#: judge/models/contest.py:112 msgid "contest format configuration" msgstr "" -#: judge/models/contest.py:130 +#: judge/models/contest.py:113 msgid "" "A JSON object to serve as the configuration for the chosen contest format " "module. Leave empty to use None. Exact format depends on the contest format " "selected." msgstr "" -#: judge/models/contest.py:137 -msgid "precision points" -msgstr "" - -#: judge/models/contest.py:139 -msgid "Number of digits to round points to." -msgstr "" - -#: judge/models/contest.py:383 +#: judge/models/contest.py:239 msgid "See private contests" msgstr "" -#: judge/models/contest.py:384 +#: judge/models/contest.py:240 msgid "Edit own contests" msgstr "" -#: judge/models/contest.py:385 +#: judge/models/contest.py:241 msgid "Edit all contests" msgstr "" -#: judge/models/contest.py:386 +#: judge/models/contest.py:242 msgid "Clone contest" msgstr "" -#: judge/models/contest.py:387 templates/contest/moss.html:74 +#: judge/models/contest.py:243 templates/contest/moss.html:74 msgid "MOSS contest" msgstr "" -#: judge/models/contest.py:388 +#: judge/models/contest.py:244 msgid "Rate contests" msgstr "" -#: judge/models/contest.py:389 +#: judge/models/contest.py:245 msgid "Contest access codes" msgstr "" -#: judge/models/contest.py:390 +#: judge/models/contest.py:246 msgid "Create private contests" msgstr "" -#: judge/models/contest.py:391 -msgid "Change contest visibility" -msgstr "" - -#: judge/models/contest.py:392 -msgid "Edit contest problem label script" -msgstr "" - -#: judge/models/contest.py:394 judge/models/contest.py:492 -#: judge/models/contest.py:529 judge/models/contest.py:552 -#: judge/models/submission.py:84 +#: judge/models/contest.py:248 judge/models/contest.py:345 +#: judge/models/contest.py:382 judge/models/contest.py:404 +#: judge/models/submission.py:83 msgid "contest" msgstr "" -#: judge/models/contest.py:395 +#: judge/models/contest.py:249 msgid "contests" msgstr "" -#: judge/models/contest.py:402 +#: judge/models/contest.py:256 msgid "associated contest" msgstr "" -#: judge/models/contest.py:405 +#: judge/models/contest.py:259 msgid "score" msgstr "" -#: judge/models/contest.py:406 +#: judge/models/contest.py:260 msgid "cumulative time" msgstr "" -#: judge/models/contest.py:407 +#: judge/models/contest.py:261 msgid "is disqualified" msgstr "" -#: judge/models/contest.py:408 +#: judge/models/contest.py:262 msgid "Whether this participation is disqualified." msgstr "" -#: judge/models/contest.py:409 -msgid "tie-breaking field" -msgstr "" - -#: judge/models/contest.py:410 +#: judge/models/contest.py:263 msgid "virtual participation id" msgstr "" -#: judge/models/contest.py:411 +#: judge/models/contest.py:264 msgid "0 means non-virtual, otherwise the n-th virtual participation." msgstr "" -#: judge/models/contest.py:412 +#: judge/models/contest.py:265 msgid "contest format specific data" msgstr "" -#: judge/models/contest.py:478 +#: judge/models/contest.py:331 #, python-format msgid "%s spectating in %s" msgstr "" -#: judge/models/contest.py:480 +#: judge/models/contest.py:333 #, python-format msgid "%s in %s, v%d" msgstr "" -#: judge/models/contest.py:481 +#: judge/models/contest.py:334 #, python-format msgid "%s in %s" msgstr "" -#: judge/models/contest.py:484 +#: judge/models/contest.py:337 msgid "contest participation" msgstr "" -#: judge/models/contest.py:485 +#: judge/models/contest.py:338 msgid "contest participations" msgstr "" -#: judge/models/contest.py:491 judge/models/contest.py:513 -#: judge/models/contest.py:553 judge/models/problem.py:389 -#: judge/models/problem.py:394 judge/models/problem.py:412 -#: judge/models/problem_data.py:40 +#: judge/models/contest.py:344 judge/models/contest.py:366 +#: judge/models/contest.py:405 judge/models/problem.py:352 +#: judge/models/problem.py:357 judge/models/problem.py:375 +#: judge/models/problem_data.py:38 msgid "problem" msgstr "" -#: judge/models/contest.py:493 judge/models/contest.py:517 +#: judge/models/contest.py:346 judge/models/contest.py:370 #: judge/models/problem.py:129 msgid "points" msgstr "" -#: judge/models/contest.py:494 +#: judge/models/contest.py:347 msgid "partial" msgstr "" -#: judge/models/contest.py:495 judge/models/contest.py:518 +#: judge/models/contest.py:348 judge/models/contest.py:371 msgid "is pretested" msgstr "" -#: judge/models/contest.py:496 judge/models/interface.py:43 +#: judge/models/contest.py:349 judge/models/interface.py:43 msgid "order" msgstr "" -#: judge/models/contest.py:497 +#: judge/models/contest.py:350 msgid "0 to not show testcases, 1 to show" msgstr "" -#: judge/models/contest.py:498 +#: judge/models/contest.py:351 msgid "visible testcases" msgstr "" -#: judge/models/contest.py:499 +#: judge/models/contest.py:352 msgid "Maximum number of submissions for this problem, or 0 for no limit." msgstr "" -#: judge/models/contest.py:501 +#: judge/models/contest.py:354 msgid "Why include a problem you can't submit to?" msgstr "" -#: judge/models/contest.py:506 +#: judge/models/contest.py:359 msgid "contest problem" msgstr "" -#: judge/models/contest.py:507 +#: judge/models/contest.py:360 msgid "contest problems" msgstr "" -#: judge/models/contest.py:511 judge/models/submission.py:183 +#: judge/models/contest.py:364 judge/models/submission.py:181 msgid "submission" msgstr "" -#: judge/models/contest.py:515 judge/models/contest.py:530 +#: judge/models/contest.py:368 judge/models/contest.py:383 msgid "participation" msgstr "" -#: judge/models/contest.py:519 +#: judge/models/contest.py:372 msgid "Whether this submission was ran only on pretests." msgstr "" -#: judge/models/contest.py:523 +#: judge/models/contest.py:376 msgid "contest submission" msgstr "" -#: judge/models/contest.py:524 +#: judge/models/contest.py:377 msgid "contest submissions" msgstr "" -#: judge/models/contest.py:532 +#: judge/models/contest.py:385 msgid "rank" msgstr "" -#: judge/models/contest.py:533 +#: judge/models/contest.py:386 msgid "rating" msgstr "" -#: judge/models/contest.py:534 +#: judge/models/contest.py:387 msgid "volatility" msgstr "" -#: judge/models/contest.py:535 +#: judge/models/contest.py:388 msgid "last rated" msgstr "" -#: judge/models/contest.py:539 +#: judge/models/contest.py:392 msgid "contest rating" msgstr "" -#: judge/models/contest.py:540 +#: judge/models/contest.py:393 msgid "contest ratings" msgstr "" -#: judge/models/contest.py:560 +#: judge/models/contest.py:412 msgid "contest moss result" msgstr "" -#: judge/models/contest.py:561 +#: judge/models/contest.py:413 msgid "contest moss results" msgstr "" @@ -1154,7 +1066,7 @@ msgstr "" msgid "post title" msgstr "" -#: judge/models/interface.py:67 judge/models/problem.py:432 +#: judge/models/interface.py:67 judge/models/problem.py:395 msgid "authors" msgstr "" @@ -1162,7 +1074,7 @@ msgstr "" msgid "slug" msgstr "" -#: judge/models/interface.py:69 judge/models/problem.py:430 +#: judge/models/interface.py:69 judge/models/problem.py:393 msgid "public visibility" msgstr "" @@ -1186,19 +1098,15 @@ msgstr "" msgid "openGraph image" msgstr "" -#: judge/models/interface.py:76 -msgid "If private, only these organizations may see the blog post." -msgstr "" - -#: judge/models/interface.py:105 +#: judge/models/interface.py:91 msgid "Edit all posts" msgstr "" -#: judge/models/interface.py:107 +#: judge/models/interface.py:93 msgid "blog post" msgstr "" -#: judge/models/interface.py:108 +#: judge/models/interface.py:94 msgid "blog posts" msgstr "" @@ -1222,6 +1130,10 @@ msgstr "" msgid "message timestamp" msgstr "" +#: judge/models/message.py:16 +msgid "read" +msgstr "" + #: judge/models/message.py:20 msgid "messages in the thread" msgstr "" @@ -1358,7 +1270,7 @@ msgid "" "are supported." msgstr "" -#: judge/models/problem.py:123 judge/models/problem.py:417 +#: judge/models/problem.py:123 judge/models/problem.py:380 msgid "memory limit" msgstr "" @@ -1431,188 +1343,188 @@ msgstr "" msgid "If private, only these organizations may see the problem." msgstr "" -#: judge/models/problem.py:395 judge/models/problem.py:413 -#: judge/models/runtime.py:111 +#: judge/models/problem.py:358 judge/models/problem.py:376 +#: judge/models/runtime.py:108 msgid "language" msgstr "" -#: judge/models/problem.py:396 +#: judge/models/problem.py:359 msgid "translated name" msgstr "" -#: judge/models/problem.py:397 +#: judge/models/problem.py:360 msgid "translated description" msgstr "" -#: judge/models/problem.py:401 +#: judge/models/problem.py:364 msgid "problem translation" msgstr "" -#: judge/models/problem.py:402 +#: judge/models/problem.py:365 msgid "problem translations" msgstr "" -#: judge/models/problem.py:406 +#: judge/models/problem.py:369 msgid "clarified problem" msgstr "" -#: judge/models/problem.py:407 +#: judge/models/problem.py:370 msgid "clarification body" msgstr "" -#: judge/models/problem.py:408 +#: judge/models/problem.py:371 msgid "clarification timestamp" msgstr "" -#: judge/models/problem.py:423 +#: judge/models/problem.py:386 msgid "language-specific resource limit" msgstr "" -#: judge/models/problem.py:424 +#: judge/models/problem.py:387 msgid "language-specific resource limits" msgstr "" -#: judge/models/problem.py:428 +#: judge/models/problem.py:391 msgid "associated problem" msgstr "" -#: judge/models/problem.py:431 +#: judge/models/problem.py:394 msgid "publish date" msgstr "" -#: judge/models/problem.py:433 +#: judge/models/problem.py:396 msgid "editorial content" msgstr "" -#: judge/models/problem.py:449 +#: judge/models/problem.py:412 msgid "solution" msgstr "" -#: judge/models/problem.py:450 +#: judge/models/problem.py:413 msgid "solutions" msgstr "" -#: judge/models/problem_data.py:26 +#: judge/models/problem_data.py:24 msgid "Standard" msgstr "" -#: judge/models/problem_data.py:27 +#: judge/models/problem_data.py:25 msgid "Floats" msgstr "" -#: judge/models/problem_data.py:28 +#: judge/models/problem_data.py:26 msgid "Floats (absolute)" msgstr "" -#: judge/models/problem_data.py:29 +#: judge/models/problem_data.py:27 msgid "Floats (relative)" msgstr "" -#: judge/models/problem_data.py:30 +#: judge/models/problem_data.py:28 msgid "Non-trailing spaces" msgstr "" -#: judge/models/problem_data.py:31 +#: judge/models/problem_data.py:29 msgid "Unordered" msgstr "" -#: judge/models/problem_data.py:32 +#: judge/models/problem_data.py:30 msgid "Byte identical" msgstr "" -#: judge/models/problem_data.py:33 +#: judge/models/problem_data.py:31 msgid "Line-by-line" msgstr "" -#: judge/models/problem_data.py:34 +#: judge/models/problem_data.py:32 msgid "Custom checker (PY)" msgstr "" -#: judge/models/problem_data.py:35 +#: judge/models/problem_data.py:33 msgid "Custom validator (CPP)" msgstr "" -#: judge/models/problem_data.py:42 +#: judge/models/problem_data.py:40 msgid "data zip file" msgstr "" -#: judge/models/problem_data.py:44 +#: judge/models/problem_data.py:42 msgid "generator file" msgstr "" -#: judge/models/problem_data.py:46 judge/models/problem_data.py:121 +#: judge/models/problem_data.py:44 judge/models/problem_data.py:110 msgid "output prefix length" msgstr "" -#: judge/models/problem_data.py:47 judge/models/problem_data.py:122 +#: judge/models/problem_data.py:45 judge/models/problem_data.py:111 msgid "output limit length" msgstr "" -#: judge/models/problem_data.py:48 +#: judge/models/problem_data.py:46 msgid "init.yml generation feedback" msgstr "" -#: judge/models/problem_data.py:49 judge/models/problem_data.py:123 +#: judge/models/problem_data.py:47 judge/models/problem_data.py:112 msgid "checker" msgstr "" -#: judge/models/problem_data.py:50 judge/models/problem_data.py:124 +#: judge/models/problem_data.py:48 judge/models/problem_data.py:113 msgid "checker arguments" msgstr "" -#: judge/models/problem_data.py:51 judge/models/problem_data.py:125 +#: judge/models/problem_data.py:49 judge/models/problem_data.py:114 msgid "checker arguments as a JSON object" msgstr "" -#: judge/models/problem_data.py:52 +#: judge/models/problem_data.py:50 msgid "custom checker file" msgstr "" -#: judge/models/problem_data.py:58 +#: judge/models/problem_data.py:56 msgid "custom validator file" msgstr "" -#: judge/models/problem_data.py:108 +#: judge/models/problem_data.py:97 msgid "problem data set" msgstr "" -#: judge/models/problem_data.py:110 +#: judge/models/problem_data.py:99 msgid "case position" msgstr "" -#: judge/models/problem_data.py:111 +#: judge/models/problem_data.py:100 msgid "case type" msgstr "" -#: judge/models/problem_data.py:112 +#: judge/models/problem_data.py:101 msgid "Normal case" msgstr "" -#: judge/models/problem_data.py:113 +#: judge/models/problem_data.py:102 msgid "Batch start" msgstr "" -#: judge/models/problem_data.py:114 +#: judge/models/problem_data.py:103 msgid "Batch end" msgstr "" -#: judge/models/problem_data.py:116 +#: judge/models/problem_data.py:105 msgid "input file name" msgstr "" -#: judge/models/problem_data.py:117 +#: judge/models/problem_data.py:106 msgid "output file name" msgstr "" -#: judge/models/problem_data.py:118 +#: judge/models/problem_data.py:107 msgid "generator arguments" msgstr "" -#: judge/models/problem_data.py:119 +#: judge/models/problem_data.py:108 msgid "point value" msgstr "" -#: judge/models/problem_data.py:120 +#: judge/models/problem_data.py:109 msgid "case is pretest?" msgstr "" @@ -1685,7 +1597,7 @@ msgid "" msgstr "" #: judge/models/profile.py:76 judge/models/profile.py:93 -#: judge/models/profile.py:212 +#: judge/models/profile.py:192 msgid "organization" msgstr "" @@ -1781,31 +1693,31 @@ msgstr "" msgid "Notes for administrators regarding this user." msgstr "" -#: judge/models/profile.py:206 +#: judge/models/profile.py:186 msgid "user profile" msgstr "" -#: judge/models/profile.py:207 +#: judge/models/profile.py:187 msgid "user profiles" msgstr "" -#: judge/models/profile.py:214 +#: judge/models/profile.py:194 msgid "request time" msgstr "" -#: judge/models/profile.py:215 +#: judge/models/profile.py:195 msgid "state" msgstr "" -#: judge/models/profile.py:220 +#: judge/models/profile.py:200 msgid "reason" msgstr "" -#: judge/models/profile.py:223 +#: judge/models/profile.py:203 msgid "organization join request" msgstr "" -#: judge/models/profile.py:224 +#: judge/models/profile.py:204 msgid "organization join requests" msgstr "" @@ -1896,86 +1808,86 @@ msgstr "" msgid "The extension of source files, e.g., \"py\" or \"cpp\"." msgstr "" -#: judge/models/runtime.py:112 +#: judge/models/runtime.py:109 msgid "languages" msgstr "" -#: judge/models/runtime.py:116 +#: judge/models/runtime.py:113 msgid "language to which this runtime belongs" msgstr "" -#: judge/models/runtime.py:117 +#: judge/models/runtime.py:114 msgid "judge on which this runtime exists" msgstr "" -#: judge/models/runtime.py:118 +#: judge/models/runtime.py:115 msgid "runtime name" msgstr "" -#: judge/models/runtime.py:119 +#: judge/models/runtime.py:116 msgid "runtime version" msgstr "" -#: judge/models/runtime.py:120 +#: judge/models/runtime.py:117 msgid "order in which to display this runtime" msgstr "" -#: judge/models/runtime.py:124 +#: judge/models/runtime.py:121 msgid "Server name, hostname-style" msgstr "" -#: judge/models/runtime.py:125 +#: judge/models/runtime.py:122 msgid "time of creation" msgstr "" -#: judge/models/runtime.py:126 +#: judge/models/runtime.py:123 msgid "A key to authenticate this judge" msgstr "" -#: judge/models/runtime.py:127 +#: judge/models/runtime.py:124 msgid "authentication key" msgstr "" -#: judge/models/runtime.py:128 +#: judge/models/runtime.py:125 msgid "block judge" msgstr "" -#: judge/models/runtime.py:129 +#: judge/models/runtime.py:126 msgid "" "Whether this judge should be blocked from connecting, even if its key is " "correct." msgstr "" -#: judge/models/runtime.py:131 +#: judge/models/runtime.py:128 msgid "judge online status" msgstr "" -#: judge/models/runtime.py:132 +#: judge/models/runtime.py:129 msgid "judge start time" msgstr "" -#: judge/models/runtime.py:133 +#: judge/models/runtime.py:130 msgid "response time" msgstr "" -#: judge/models/runtime.py:134 +#: judge/models/runtime.py:131 msgid "system load" msgstr "" -#: judge/models/runtime.py:135 +#: judge/models/runtime.py:132 msgid "Load for the last minute, divided by processors to be fair." msgstr "" -#: judge/models/runtime.py:139 judge/models/runtime.py:179 +#: judge/models/runtime.py:136 judge/models/runtime.py:176 msgid "judges" msgstr "" -#: judge/models/runtime.py:178 +#: judge/models/runtime.py:175 msgid "judge" msgstr "" #: judge/models/submission.py:20 judge/models/submission.py:47 -#: judge/utils/problems.py:79 +#: judge/utils/problems.py:77 msgid "Accepted" msgstr "" @@ -2004,7 +1916,7 @@ msgid "Runtime Error" msgstr "" #: judge/models/submission.py:27 judge/models/submission.py:41 -#: judge/models/submission.py:55 judge/utils/problems.py:81 +#: judge/models/submission.py:55 judge/utils/problems.py:79 msgid "Compile Error" msgstr "" @@ -2045,15 +1957,15 @@ msgstr "" msgid "submission time" msgstr "" -#: judge/models/submission.py:67 judge/models/submission.py:203 +#: judge/models/submission.py:67 judge/models/submission.py:201 msgid "execution time" msgstr "" -#: judge/models/submission.py:68 judge/models/submission.py:204 +#: judge/models/submission.py:68 judge/models/submission.py:202 msgid "memory usage" msgstr "" -#: judge/models/submission.py:69 judge/models/submission.py:205 +#: judge/models/submission.py:69 judge/models/submission.py:203 msgid "points granted" msgstr "" @@ -2090,62 +2002,58 @@ msgid "judged on" msgstr "" #: judge/models/submission.py:81 -msgid "submission judge time" -msgstr "" - -#: judge/models/submission.py:82 msgid "was rejudged by admin" msgstr "" -#: judge/models/submission.py:83 +#: judge/models/submission.py:82 msgid "was ran on pretests only" msgstr "" -#: judge/models/submission.py:184 templates/contest/moss.html:58 +#: judge/models/submission.py:182 templates/contest/moss.html:58 msgid "submissions" msgstr "" -#: judge/models/submission.py:188 judge/models/submission.py:199 +#: judge/models/submission.py:186 judge/models/submission.py:197 msgid "associated submission" msgstr "" -#: judge/models/submission.py:190 +#: judge/models/submission.py:188 msgid "source code" msgstr "" -#: judge/models/submission.py:201 +#: judge/models/submission.py:199 msgid "test case ID" msgstr "" -#: judge/models/submission.py:202 +#: judge/models/submission.py:200 msgid "status flag" msgstr "" -#: judge/models/submission.py:206 +#: judge/models/submission.py:204 msgid "points possible" msgstr "" -#: judge/models/submission.py:207 +#: judge/models/submission.py:205 msgid "batch number" msgstr "" -#: judge/models/submission.py:208 +#: judge/models/submission.py:206 msgid "judging feedback" msgstr "" -#: judge/models/submission.py:209 +#: judge/models/submission.py:207 msgid "extended judging feedback" msgstr "" -#: judge/models/submission.py:210 +#: judge/models/submission.py:208 msgid "program output" msgstr "" -#: judge/models/submission.py:218 +#: judge/models/submission.py:216 msgid "submission test case" msgstr "" -#: judge/models/submission.py:219 +#: judge/models/submission.py:217 msgid "submission test cases" msgstr "" @@ -2197,21 +2105,12 @@ msgstr "" msgid "message time" msgstr "" -#: judge/pdf_problems.py:147 judge/pdf_problems.py:199 -#: judge/pdf_problems.py:259 +#: judge/pdf_problems.py:134 judge/pdf_problems.py:186 +#: judge/pdf_problems.py:246 msgid "Page [page] of [topage]" msgstr "" -#: judge/pdf_problems.py:280 -#, python-format -msgid "Page %s of %s" -msgstr "" - -#: judge/tasks/contest.py:19 -msgid "Recalculating contest scores" -msgstr "" - -#: judge/tasks/contest.py:40 +#: judge/tasks/moss.py:25 msgid "Running MOSS" msgstr "" @@ -2223,60 +2122,60 @@ msgstr "" msgid "Recalculating user points" msgstr "" -#: judge/utils/problem_data.py:70 +#: judge/utils/problem_data.py:68 msgid "Empty batches not allowed." msgstr "" -#: judge/utils/problem_data.py:78 judge/utils/problem_data.py:99 +#: judge/utils/problem_data.py:76 judge/utils/problem_data.py:97 msgid "How did you corrupt the custom checker path?" msgstr "" -#: judge/utils/problem_data.py:120 +#: judge/utils/problem_data.py:118 #, python-format msgid "Points must be defined for non-batch case #%d." msgstr "" -#: judge/utils/problem_data.py:125 +#: judge/utils/problem_data.py:123 #, python-format msgid "Input file for case %d does not exist: %s" msgstr "" -#: judge/utils/problem_data.py:128 +#: judge/utils/problem_data.py:126 #, python-format msgid "Output file for case %d does not exist: %s" msgstr "" -#: judge/utils/problem_data.py:153 +#: judge/utils/problem_data.py:151 #, python-format msgid "Batch start case #%d requires points." msgstr "" -#: judge/utils/problem_data.py:174 +#: judge/utils/problem_data.py:172 #, python-format msgid "Attempt to end batch outside of one in case #%d" msgstr "" -#: judge/utils/problem_data.py:192 +#: judge/utils/problem_data.py:190 msgid "How did you corrupt the zip path?" msgstr "" -#: judge/utils/problem_data.py:198 +#: judge/utils/problem_data.py:196 msgid "How did you corrupt the generator path?" msgstr "" -#: judge/utils/problems.py:80 +#: judge/utils/problems.py:78 msgid "Wrong" msgstr "" -#: judge/utils/problems.py:82 +#: judge/utils/problems.py:80 msgid "Timeout" msgstr "" -#: judge/utils/problems.py:83 +#: judge/utils/problems.py:81 msgid "Error" msgstr "" -#: judge/utils/problems.py:94 +#: judge/utils/problems.py:92 msgid "Can't pass both queryset and keyword filters" msgstr "" @@ -2319,8 +2218,7 @@ msgctxt "hours and minutes" msgid "%h:%m" msgstr "" -#: judge/views/about.py:7 templates/organization/home.html:112 -#: templates/user/user-about.html:83 templates/user/user-tabs.html:4 +#: judge/views/about.py:7 templates/user/user-about.html:33 msgid "About" msgstr "" @@ -2328,165 +2226,156 @@ msgstr "" msgid "Custom Checker Sample" msgstr "" -#: judge/views/blog.py:45 +#: judge/views/blog.py:38 #, python-format msgid "Page %d of Posts" msgstr "" -#: judge/views/comment.py:28 +#: judge/views/comment.py:27 msgid "Messing around, are we?" msgstr "" -#: judge/views/comment.py:37 +#: judge/views/comment.py:36 msgid "You must solve at least one problem before you can vote." msgstr "" -#: judge/views/comment.py:64 +#: judge/views/comment.py:63 msgid "You already voted." msgstr "" -#: judge/views/comment.py:126 judge/views/organization.py:344 +#: judge/views/comment.py:120 judge/views/organization.py:299 msgid "Edited from site" msgstr "" -#: judge/views/comment.py:147 +#: judge/views/comment.py:141 msgid "Editing comment" msgstr "" -#: judge/views/contests.py:57 judge/views/contests.py:247 -#: judge/views/contests.py:250 judge/views/contests.py:424 +#: judge/views/contests.py:55 judge/views/contests.py:215 +#: judge/views/contests.py:218 judge/views/contests.py:389 msgid "No such contest" msgstr "" -#: judge/views/contests.py:58 judge/views/contests.py:248 +#: judge/views/contests.py:56 judge/views/contests.py:216 #, python-format msgid "Could not find a contest with the key \"%s\"." msgstr "" -#: judge/views/contests.py:71 +#: judge/views/contests.py:81 msgid "Contests" msgstr "" -#: judge/views/contests.py:251 +#: judge/views/contests.py:219 msgid "Could not find such contest." msgstr "" -#: judge/views/contests.py:254 +#: judge/views/contests.py:222 #, python-format msgid "Access to contest \"%s\" denied" msgstr "" -#: judge/views/contests.py:278 +#: judge/views/contests.py:246 msgid "Clone Contest" msgstr "" -#: judge/views/contests.py:343 +#: judge/views/contests.py:309 msgid "Contest not ongoing" msgstr "" -#: judge/views/contests.py:344 +#: judge/views/contests.py:310 #, python-format msgid "\"%s\" is not currently ongoing." msgstr "" -#: judge/views/contests.py:348 +#: judge/views/contests.py:314 msgid "Already in contest" msgstr "" -#: judge/views/contests.py:349 +#: judge/views/contests.py:315 #, python-format msgid "You are already in a contest: \"%s\"." msgstr "" -#: judge/views/contests.py:352 +#: judge/views/contests.py:318 msgid "Banned from joining" msgstr "" -#: judge/views/contests.py:353 +#: judge/views/contests.py:319 msgid "" "You have been declared persona non grata for this contest. You are " "permanently barred from joining this contest." msgstr "" -#: judge/views/contests.py:414 +#: judge/views/contests.py:379 #, python-format msgid "Enter access code for \"%s\"" msgstr "" -#: judge/views/contests.py:425 +#: judge/views/contests.py:390 #, python-format msgid "You are not in contest \"%s\"." msgstr "" -#: judge/views/contests.py:444 +#: judge/views/contests.py:409 msgid "ContestCalendar requires integer year and month" msgstr "" -#: judge/views/contests.py:484 +#: judge/views/contests.py:449 #, python-format msgid "Contests in %(month)s" msgstr "" -#: judge/views/contests.py:484 +#: judge/views/contests.py:449 msgid "F Y" msgstr "" -#: judge/views/contests.py:532 +#: judge/views/contests.py:496 #, python-format msgid "%s Statistics" msgstr "" -#: judge/views/contests.py:717 +#: judge/views/contests.py:601 +msgid "???" +msgstr "" + +#: judge/views/contests.py:664 #, python-format msgid "%s Rankings" msgstr "" -#: judge/views/contests.py:725 -msgid "???" -msgstr "" - -#: judge/views/contests.py:741 +#: judge/views/contests.py:680 #, python-format msgid "Your participation in %s" msgstr "" -#: judge/views/contests.py:742 +#: judge/views/contests.py:681 #, python-format msgid "%s's participation in %s" msgstr "" -#: judge/views/contests.py:749 +#: judge/views/contests.py:685 msgid "Live" msgstr "" -#: judge/views/contests.py:761 templates/contest/contest-tabs.html:13 +#: judge/views/contests.py:697 msgid "Participation" msgstr "" -#: judge/views/contests.py:808 +#: judge/views/contests.py:743 #, python-format msgid "%s MOSS Results" msgstr "" -#: judge/views/contests.py:835 +#: judge/views/contests.py:770 #, python-format msgid "Running MOSS for %s..." msgstr "" -#: judge/views/contests.py:858 +#: judge/views/contests.py:793 #, python-format msgid "Contest tag: %s" msgstr "" -#: judge/views/contests.py:868 judge/views/ticket.py:57 -msgid "Issue description" -msgstr "" - -#: judge/views/contests.py:911 -#, python-format -msgid "New clarification for %s" -msgstr "" - #: judge/views/error.py:14 msgid "404 error" msgstr "" @@ -2507,122 +2396,115 @@ msgid "corrupt page %s" msgstr "" #: judge/views/language.py:12 templates/status/judge-status-table.html:9 -#: templates/status/status-tabs.html:5 msgid "Runtimes" msgstr "" -#: judge/views/notification.py:40 -#, python-format -msgid "Notifications (%d unseen)" -msgstr "" - -#: judge/views/organization.py:59 judge/views/organization.py:62 +#: judge/views/organization.py:44 judge/views/organization.py:47 msgid "No such organization" msgstr "" -#: judge/views/organization.py:60 +#: judge/views/organization.py:45 #, python-format msgid "Could not find an organization with the key \"%s\"." msgstr "" -#: judge/views/organization.py:63 +#: judge/views/organization.py:48 msgid "Could not find such organization." msgstr "" -#: judge/views/organization.py:79 judge/views/register.py:34 -#: templates/organization/list.html:32 templates/user/import/table_csv.html:9 -#: templates/user/user-list-tabs.html:6 +#: judge/views/organization.py:72 judge/views/register.py:34 +#: templates/organization/list.html:15 msgid "Organizations" msgstr "" -#: judge/views/organization.py:130 +#: judge/views/organization.py:93 #, python-format msgid "%s Members" msgstr "" -#: judge/views/organization.py:159 judge/views/organization.py:162 -#: judge/views/organization.py:167 +#: judge/views/organization.py:118 judge/views/organization.py:121 +#: judge/views/organization.py:126 msgid "Joining organization" msgstr "" -#: judge/views/organization.py:159 +#: judge/views/organization.py:118 msgid "You are already in the organization." msgstr "" -#: judge/views/organization.py:162 +#: judge/views/organization.py:121 msgid "This organization is not open." msgstr "" -#: judge/views/organization.py:179 +#: judge/views/organization.py:138 msgid "Leaving organization" msgstr "" -#: judge/views/organization.py:179 +#: judge/views/organization.py:138 #, python-format msgid "You are not in \"%s\"." msgstr "" -#: judge/views/organization.py:203 +#: judge/views/organization.py:162 #, python-format msgid "Request to join %s" msgstr "" -#: judge/views/organization.py:221 +#: judge/views/organization.py:180 msgid "Join request detail" msgstr "" -#: judge/views/organization.py:254 +#: judge/views/organization.py:209 #, python-format msgid "Managing join requests for %s" msgstr "" -#: judge/views/organization.py:285 +#: judge/views/organization.py:240 #, python-format msgid "" "Your organization can only receive %d more members. You cannot approve %d " "users." msgstr "" -#: judge/views/organization.py:297 +#: judge/views/organization.py:252 #, python-format msgid "Approved %d user." msgid_plural "Approved %d users." msgstr[0] "" msgstr[1] "" -#: judge/views/organization.py:298 +#: judge/views/organization.py:253 #, python-format msgid "Rejected %d user." msgid_plural "Rejected %d users." msgstr[0] "" msgstr[1] "" -#: judge/views/organization.py:328 +#: judge/views/organization.py:283 #, python-format msgid "Editing %s" msgstr "" -#: judge/views/organization.py:352 judge/views/organization.py:360 +#: judge/views/organization.py:307 judge/views/organization.py:315 msgid "Can't edit organization" msgstr "" -#: judge/views/organization.py:353 +#: judge/views/organization.py:308 msgid "You are not allowed to edit this organization." msgstr "" -#: judge/views/organization.py:361 +#: judge/views/organization.py:316 msgid "You are not allowed to kick people from this organization." msgstr "" -#: judge/views/organization.py:366 judge/views/organization.py:370 +#: judge/views/organization.py:321 judge/views/organization.py:325 msgid "Can't kick user" msgstr "" -#: judge/views/organization.py:367 +#: judge/views/organization.py:322 msgid "The user you are trying to kick does not exist!" msgstr "" -#: judge/views/organization.py:371 +#: judge/views/organization.py:326 #, python-format msgid "The user you are trying to kick is not in organization: %s." msgstr "" @@ -2646,36 +2528,35 @@ msgstr "" msgid "Editorial for {0}" msgstr "" -#: judge/views/problem.py:285 templates/contest/contest.html:79 -#: templates/user/user-about.html:28 templates/user/user-tabs.html:5 -#: templates/user/users-table.html:31 +#: judge/views/problem.py:286 templates/contest/contest.html:79 +#: templates/user/users-table.html:23 msgid "Problems" msgstr "" -#: judge/views/problem.py:585 +#: judge/views/problem.py:547 msgid "Banned from submitting" msgstr "" -#: judge/views/problem.py:586 +#: judge/views/problem.py:548 msgid "" "You have been declared persona non grata for this problem. You are " "permanently barred from submitting this problem." msgstr "" -#: judge/views/problem.py:600 +#: judge/views/problem.py:562 msgid "Too many submissions" msgstr "" -#: judge/views/problem.py:601 +#: judge/views/problem.py:563 msgid "You have exceeded the submission limit for this problem." msgstr "" -#: judge/views/problem.py:661 judge/views/problem.py:664 +#: judge/views/problem.py:633 judge/views/problem.py:636 #, python-format msgid "Submit to %(problem)s" msgstr "" -#: judge/views/problem.py:679 +#: judge/views/problem.py:652 msgid "Clone Problem" msgstr "" @@ -2716,22 +2597,22 @@ msgstr "" msgid "Generated init.yml for %s" msgstr "" -#: judge/views/problem_manage.py:52 judge/views/problem_manage.py:55 +#: judge/views/problem_manage.py:50 judge/views/problem_manage.py:53 #, python-format msgid "Managing submissions for %s" msgstr "" -#: judge/views/problem_manage.py:97 +#: judge/views/problem_manage.py:95 #, python-format msgid "Rejudging selected submissions for %s..." msgstr "" -#: judge/views/problem_manage.py:141 +#: judge/views/problem_manage.py:110 #, python-format msgid "Rescoring all submissions for %s..." msgstr "" -#: judge/views/problem_manage.py:150 +#: judge/views/problem_manage.py:119 #, python-format msgid "Successfully scheduled %d submission for rejudging." msgid_plural "Successfully scheduled %d submissions for rejudging." @@ -2780,24 +2661,24 @@ msgstr "" msgid "Subscribe to newsletter?" msgstr "" -#: judge/views/register.py:55 +#: judge/views/register.py:45 #, python-format msgid "" "The email address \"%s\" is already taken. Only one registration is allowed " "per address." msgstr "" -#: judge/views/register.py:61 +#: judge/views/register.py:51 msgid "" "Your email provider is not allowed due to history of abuse. Please use a " "reputable email provider." msgstr "" -#: judge/views/register.py:67 judge/views/register.py:105 +#: judge/views/register.py:57 judge/views/register.py:95 msgid "Registration" msgstr "" -#: judge/views/register.py:116 +#: judge/views/register.py:106 msgid "Authentication failure" msgstr "" @@ -2813,100 +2694,104 @@ msgstr "" msgid "Version matrix" msgstr "" -#: judge/views/submission.py:84 judge/views/submission.py:91 +#: judge/views/submission.py:83 judge/views/submission.py:90 #, python-format msgid "Submission of %(problem)s by %(user)s" msgstr "" -#: judge/views/submission.py:244 judge/views/submission.py:245 -#: templates/problem/problem.html:167 +#: judge/views/submission.py:227 judge/views/submission.py:228 +#: templates/problem/problem.html:127 msgid "All submissions" msgstr "" -#: judge/views/submission.py:404 +#: judge/views/submission.py:384 msgid "All my submissions" msgstr "" -#: judge/views/submission.py:405 +#: judge/views/submission.py:385 #, python-format msgid "All submissions by %s" msgstr "" -#: judge/views/submission.py:436 +#: judge/views/submission.py:416 #, python-format msgid "All submissions for %s" msgstr "" -#: judge/views/submission.py:455 +#: judge/views/submission.py:435 msgid "Must pass a problem" msgstr "" -#: judge/views/submission.py:501 +#: judge/views/submission.py:481 #, python-format msgid "My submissions for %(problem)s" msgstr "" -#: judge/views/submission.py:502 +#: judge/views/submission.py:482 #, python-format msgid "%(user)s's submissions for %(problem)s" msgstr "" -#: judge/views/submission.py:603 +#: judge/views/submission.py:583 msgid "Must pass a contest" msgstr "" -#: judge/views/submission.py:622 +#: judge/views/submission.py:602 #, python-brace-format msgid "" "{0}'s submissions for {2} in {4}" msgstr "" -#: judge/views/submission.py:629 +#: judge/views/submission.py:609 #, python-brace-format msgid "" "{0}'s submissions for problem {2} in {3}" "" msgstr "" -#: judge/views/ticket.py:50 judge/views/ticket.py:56 +#: judge/views/ticket.py:33 judge/views/ticket.py:39 msgid "Ticket title" msgstr "" -#: judge/views/ticket.py:107 judge/views/ticket.py:110 +#: judge/views/ticket.py:40 +msgid "Issue description" +msgstr "" + +#: judge/views/ticket.py:85 judge/views/ticket.py:88 #, python-format msgid "New ticket for %s" msgstr "" -#: judge/views/ticket.py:170 +#: judge/views/ticket.py:142 #, python-format msgid "%(title)s - Ticket %(id)d" msgstr "" -#: judge/views/ticket.py:279 +#: judge/views/ticket.py:251 #, python-format msgid "Tickets - Page %(number)d of %(total)d" msgstr "" -#: judge/views/ticket.py:328 +#: judge/views/ticket.py:300 #, python-format msgid "New Ticket: %s" msgstr "" -#: judge/views/ticket.py:329 +#: judge/views/ticket.py:301 #, python-format msgid "#%(id)d, assigned to: %(users)s" msgstr "" -#: judge/views/ticket.py:331 +#: judge/views/ticket.py:303 msgid ", " msgstr "" -#: judge/views/ticket.py:331 +#: judge/views/ticket.py:303 msgid "no one" msgstr "" -#: judge/views/ticket.py:351 +#: judge/views/ticket.py:323 #, python-format msgid "New Ticket Message For: %s" msgstr "" @@ -2923,50 +2808,41 @@ msgstr "" msgid "Perform Two Factor Authentication" msgstr "" -#: judge/views/user.py:74 +#: judge/views/user.py:68 msgid "No such user" msgstr "" -#: judge/views/user.py:74 +#: judge/views/user.py:68 #, python-format msgid "No user handle \"%s\"." msgstr "" -#: judge/views/user.py:78 +#: judge/views/user.py:72 msgid "My account" msgstr "" -#: judge/views/user.py:79 +#: judge/views/user.py:73 #, python-format msgid "User %s" msgstr "" -#: judge/views/user.py:148 -msgid "M j, Y" -msgstr "" - -#: judge/views/user.py:171 +#: judge/views/user.py:136 msgid "M j, Y, G:i" msgstr "" -#: judge/views/user.py:290 +#: judge/views/user.py:221 msgid "Updated on site" msgstr "" -#: judge/views/user.py:323 templates/admin/auth/user/change_form.html:14 -#: templates/admin/auth/user/change_form.html:17 templates/base.html:238 -#: templates/user/user-tabs.html:10 +#: judge/views/user.py:254 templates/admin/auth/user/change_form.html:14 +#: templates/admin/auth/user/change_form.html:17 templates/base.html:224 msgid "Edit profile" msgstr "" -#: judge/views/user.py:332 templates/user/user-list-tabs.html:4 +#: judge/views/user.py:263 msgid "Leaderboard" msgstr "" -#: judge/views/user.py:407 -msgid "Import Users" -msgstr "" - #: judge/views/widgets.py:48 judge/views/widgets.py:58 #, python-format msgid "Invalid upstream data: %s" @@ -3004,7 +2880,7 @@ msgid "View Submissions" msgstr "" #: templates/admin/judge/problem/change_form.html:17 -#: templates/user/user-base.html:112 +#: templates/user/user-base.html:61 msgid "View submissions" msgstr "" @@ -3019,145 +2895,90 @@ msgstr "" msgid "Rejudge" msgstr "" -#: templates/base.html:230 -#, python-format -msgid "Hello, %(username)s." -msgstr "" - -#: templates/base.html:236 templates/comments/list.html:89 -#: templates/contest/contest-list-tabs.html:24 -#: templates/contest/ranking-table.html:53 -#: templates/problem/problem-list-tabs.html:6 +#: templates/base.html:222 templates/comments/list.html:89 +#: templates/contest/ranking-table.html:39 #: templates/submission/info-base.html:12 -#: templates/submission/submission-list-tabs.html:15 msgid "Admin" msgstr "" -#: templates/base.html:245 +#: templates/base.html:231 msgid "Log out" msgstr "" -#: templates/base.html:254 +#: templates/base.html:240 #: templates/registration/password_reset_complete.html:4 msgid "Log in" msgstr "" -#: templates/base.html:255 templates/registration/registration_form.html:177 +#: templates/base.html:241 templates/registration/registration_form.html:177 msgid "or" msgstr "" -#: templates/base.html:256 +#: templates/base.html:242 msgid "Sign up" msgstr "" -#: templates/base.html:271 +#: templates/base.html:254 msgid "spectating" msgstr "" -#: templates/base.html:284 +#: templates/base.html:267 msgid "This site works best with JavaScript enabled." msgstr "" -#: templates/blog/blog.html:13 templates/comments/list.html:68 -#: templates/comments/list.html:83 templates/contest/contest-tabs.html:23 -#: templates/contest/tag-title.html:9 templates/flatpages/admin_link.html:3 -#: templates/license.html:10 templates/problem/editorial.html:14 +#: templates/blog/content.html:13 templates/comments/list.html:68 +#: templates/comments/list.html:83 templates/contest/tag-title.html:9 +#: templates/flatpages/admin_link.html:3 templates/license.html:10 +#: templates/problem/editorial.html:14 msgid "Edit" msgstr "" -#: templates/blog/blog.html:26 -#, python-format -msgid "" -"\n" -" posted on %(time)s\n" -" " -msgstr "" - -#: templates/blog/content.html:10 -#, python-brace-format -msgid "posted on {time}" -msgstr "" - -#: templates/blog/dashboard.html:21 -#, python-format -msgid "" -"\n" -" on %(time)s\n" -" " -msgstr "" - -#: templates/blog/list.html:93 +#: templates/blog/list.html:85 msgid "Blog" msgstr "" -#: templates/blog/list.html:95 +#: templates/blog/list.html:87 msgid "Events" msgstr "" -#: templates/blog/list.html:100 +#: templates/blog/list.html:92 msgid "News" msgstr "" -#: templates/blog/list.html:115 templates/problem/list.html:347 -#: templates/problem/problem.html:361 +#: templates/blog/list.html:130 templates/problem/problem.html:310 msgid "Clarifications" msgstr "" -#: templates/blog/list.html:121 -msgid "Add" -msgstr "" - -#: templates/blog/list.html:140 templates/problem/list.html:369 -#: templates/problem/problem.html:372 +#: templates/blog/list.html:146 templates/problem/problem.html:321 msgid "No clarifications have been made at this time." msgstr "" -#: templates/blog/list.html:148 +#: templates/blog/list.html:154 msgid "Ongoing contests" msgstr "" -#: templates/blog/list.html:166 +#: templates/blog/list.html:172 msgid "Upcoming contests" msgstr "" -#: templates/blog/list.html:184 -msgid "My open tickets" -msgstr "" - -#: templates/blog/list.html:206 -msgid "New tickets" -msgstr "" - -#: templates/blog/list.html:227 -msgid "New problems" -msgstr "" - -#: templates/blog/list.html:244 +#: templates/blog/list.html:189 msgid "Comment stream" msgstr "" -#: templates/chat/chat.html:305 -msgid "Chat" +#: templates/blog/list.html:208 +msgid "New problems" msgstr "" -#: templates/chat/chat.html:307 templates/chat/chat.html:314 -msgid "Online Users" +#: templates/blog/list.html:225 +msgid "My open tickets" msgstr "" -#: templates/chat/chat.html:315 -msgid "Refresh" +#: templates/blog/list.html:246 +msgid "New tickets" msgstr "" -#: templates/chat/chat.html:333 -msgid "Emoji" -msgstr "" - -#: templates/chat/chat.html:334 -msgid "Enter your message" -msgstr "" - -#: templates/chat/message.html:20 -msgid "Delete" +#: templates/chat/chat.html:167 +msgid "Your message" msgstr "" #: templates/comments/list.html:2 @@ -3168,21 +2989,11 @@ msgstr "" msgid "Please login to vote" msgstr "" -#: templates/comments/list.html:40 -#, python-brace-format -msgid "commented on {time}" -msgstr "" - -#: templates/comments/list.html:49 -#, python-format -msgid "edit %(edits)s" -msgstr "" - -#: templates/comments/list.html:51 templates/comments/media-js.html:92 +#: templates/comments/list.html:51 templates/comments/media-js.html:77 msgid "edited" msgstr "" -#: templates/comments/list.html:60 templates/notification/list.html:14 +#: templates/comments/list.html:60 msgid "Link" msgstr "" @@ -3190,52 +3001,36 @@ msgstr "" msgid "Reply" msgstr "" -#: templates/comments/list.html:86 templates/contest/list.html:91 -#: templates/contest/list.html:95 templates/contest/list.html:280 +#: templates/comments/list.html:86 msgid "Hide" msgstr "" -#: templates/comments/list.html:101 -#, python-format -msgid "" -"\n" -" This comment is hidden due " -"to too much negative feedback.\n" -" Click here to view it.\n" -" " -msgstr "" - -#: templates/comments/list.html:121 +#: templates/comments/list.html:120 msgid "There are no comments at the moment." msgstr "" -#: templates/comments/list.html:127 +#: templates/comments/list.html:126 msgid "New comment" msgstr "" -#: templates/comments/list.html:141 +#: templates/comments/list.html:140 msgid "Invalid comment body." msgstr "" -#: templates/comments/list.html:149 +#: templates/comments/list.html:148 msgid "Post!" msgstr "" -#: templates/comments/list.html:157 +#: templates/comments/list.html:156 msgid "Comments are disabled on this page." msgstr "" -#: templates/comments/media-js.html:38 -msgid "Replying to comment" -msgstr "" - -#: templates/comments/media-js.html:87 +#: templates/comments/media-js.html:72 #, python-brace-format msgid "edit {edits}" msgstr "" -#: templates/comments/media-js.html:90 +#: templates/comments/media-js.html:75 msgid "original" msgstr "" @@ -3279,11 +3074,6 @@ msgstr "" msgid "Saturday" msgstr "" -#: templates/contest/clarification.html:52 templates/organization/new.html:10 -#: templates/ticket/new.html:38 -msgid "Create" -msgstr "" - #: templates/contest/clone.html:37 msgid "Enter a new key for the cloned contest:" msgstr "" @@ -3304,171 +3094,97 @@ msgstr "" msgid "Next" msgstr "" -#: templates/contest/contest-list-tabs.html:21 -#: templates/problem/problem-list-tabs.html:5 -msgid "List" -msgstr "" - -#: templates/contest/contest-list-tabs.html:22 -msgid "Calendar" -msgstr "" - -#: templates/contest/contest-tabs.html:4 templates/organization/home.html:105 -msgid "Info" -msgstr "" - -#: templates/contest/contest-tabs.html:6 templates/stats/base.html:9 -#: templates/submission/list.html:339 -msgid "Statistics" -msgstr "" - -#: templates/contest/contest-tabs.html:11 -msgid "Rankings" -msgstr "" - -#: templates/contest/contest-tabs.html:16 -msgid "Hidden Rankings" -msgstr "" - -#: templates/contest/contest-tabs.html:21 -msgid "MOSS" -msgstr "" - -#: templates/contest/contest-tabs.html:26 -msgid "Clone" -msgstr "" - -#: templates/contest/contest-tabs.html:38 -#: templates/contest/contest-tabs.html:58 +#: templates/contest/contest-tabs.html:37 msgid "Leave contest" msgstr "" -#: templates/contest/contest-tabs.html:45 templates/contest/list.html:388 +#: templates/contest/contest-tabs.html:44 templates/contest/list.html:293 msgid "Virtual join" msgstr "" -#: templates/contest/contest-tabs.html:56 -msgid "Stop spectating" -msgstr "" - -#: templates/contest/contest-tabs.html:65 +#: templates/contest/contest-tabs.html:64 msgid "Spectate contest" msgstr "" -#: templates/contest/contest-tabs.html:72 +#: templates/contest/contest-tabs.html:70 +#: templates/contest/contest-tabs.html:76 msgid "Join contest" msgstr "" -#: templates/contest/contest-tabs.html:81 +#: templates/contest/contest-tabs.html:85 msgid "Login to participate" msgstr "" -#: templates/contest/contest.html:37 -msgid "Participating virtually." -msgstr "" - -#: templates/contest/contest.html:43 -msgid "Contest is over." -msgstr "" - #: templates/contest/contest.html:59 templates/contest/contest.html:63 msgid "F j, Y, G:i T" msgstr "" -#: templates/contest/contest.html:59 -#, python-format -msgid "" -"%(time_limit)s window between %(start_time)s and " -"%(end_time)s" -msgstr "" - -#: templates/contest/contest.html:63 -#, python-format -msgid "%(length)s long starting on %(start_time)s" -msgstr "" - #: templates/contest/contest.html:85 msgid "AC Rate" msgstr "" -#: templates/contest/contest.html:86 templates/contest/list.html:237 -#: templates/contest/list.html:289 templates/contest/list.html:366 -#: templates/problem/list.html:223 templates/problem/list.html:254 +#: templates/contest/contest.html:86 templates/contest/list.html:153 +#: templates/contest/list.html:195 templates/contest/list.html:271 +#: templates/problem/list.html:212 templates/problem/list.html:238 msgid "Users" msgstr "" -#: templates/contest/contest.html:111 templates/problem/list.html:330 +#: templates/contest/contest.html:111 msgid "Editorial" msgstr "" -#: templates/contest/list.html:83 templates/contest/media-js.html:9 +#: templates/contest/list.html:31 templates/contest/media-js.html:9 msgid "Are you sure you want to join?" msgstr "" -#: templates/contest/list.html:84 +#: templates/contest/list.html:32 msgid "" "Joining a contest for the first time starts your timer, after which it " "becomes unstoppable." msgstr "" -#: templates/contest/list.html:92 templates/contest/list.html:278 -msgid "Show" -msgstr "" - -#: templates/contest/list.html:102 templates/problem/list.html:68 -msgid "Organizations..." -msgstr "" - -#: templates/contest/list.html:135 +#: templates/contest/list.html:65 msgid "hidden" msgstr "" -#: templates/contest/list.html:140 +#: templates/contest/list.html:70 msgid "private" msgstr "" -#: templates/contest/list.html:154 +#: templates/contest/list.html:84 msgid "rated" msgstr "" -#: templates/contest/list.html:202 +#: templates/contest/list.html:132 msgid "Spectate" msgstr "" -#: templates/contest/list.html:208 +#: templates/contest/list.html:138 msgid "Join" msgstr "" -#: templates/contest/list.html:220 -msgid "Search contests..." -msgstr "" - -#: templates/contest/list.html:229 -msgid "Search" -msgstr "" - -#: templates/contest/list.html:232 +#: templates/contest/list.html:148 msgid "Active Contests" msgstr "" -#: templates/contest/list.html:236 templates/contest/list.html:288 -#: templates/contest/list.html:327 templates/contest/list.html:365 +#: templates/contest/list.html:152 templates/contest/list.html:194 +#: templates/contest/list.html:232 templates/contest/list.html:270 msgid "Contest" msgstr "" -#: templates/contest/list.html:275 +#: templates/contest/list.html:190 msgid "Ongoing Contests" msgstr "" -#: templates/contest/list.html:322 +#: templates/contest/list.html:227 msgid "Upcoming Contests" msgstr "" -#: templates/contest/list.html:350 +#: templates/contest/list.html:255 msgid "There are no scheduled contests at this time." msgstr "" -#: templates/contest/list.html:356 +#: templates/contest/list.html:261 msgid "Past Contests" msgstr "" @@ -3519,71 +3235,47 @@ msgstr "" msgid "Only the following organizations may access this contest:" msgstr "" -#: templates/contest/ranking-table.html:9 templates/problem/search-form.html:35 +#: templates/contest/ranking-table.html:7 msgid "Organization" msgstr "" -#: templates/contest/ranking-table.html:10 templates/user/users-table.html:13 -msgid "Full Name" -msgstr "" - -#: templates/contest/ranking-table.html:44 +#: templates/contest/ranking-table.html:30 msgid "Un-Disqualify" msgstr "" -#: templates/contest/ranking-table.html:47 +#: templates/contest/ranking-table.html:33 msgid "Disqualify" msgstr "" -#: templates/contest/ranking.html:187 +#: templates/contest/ranking.html:173 msgid "Are you sure you want to disqualify this participation?" msgstr "" -#: templates/contest/ranking.html:192 +#: templates/contest/ranking.html:178 msgid "Are you sure you want to un-disqualify this participation?" msgstr "" -#: templates/contest/ranking.html:463 +#: templates/contest/ranking.html:252 msgid "View user participation" msgstr "" -#: templates/contest/ranking.html:467 +#: templates/contest/ranking.html:256 msgid "Show organizations" msgstr "" -#: templates/contest/ranking.html:471 -msgid "Show full name" -msgstr "" - -#: templates/contest/ranking.html:474 -msgid "Show friends only" -msgstr "" - -#: templates/contest/ranking.html:477 -msgid "Total score only" -msgstr "" - -#: templates/contest/ranking.html:479 -msgid "Show virtual participation" -msgstr "" - -#: templates/contest/stats.html:51 +#: templates/contest/stats.html:38 msgid "Problem Status Distribution" msgstr "" -#: templates/contest/stats.html:56 +#: templates/contest/stats.html:43 msgid "Problem AC Rate" msgstr "" -#: templates/contest/stats.html:62 -msgid "Problem Point Distribution" -msgstr "" - -#: templates/contest/stats.html:76 templates/stats/language.html:16 +#: templates/contest/stats.html:48 templates/stats/language.html:16 msgid "Submissions by Language" msgstr "" -#: templates/contest/stats.html:82 templates/stats/language.html:26 +#: templates/contest/stats.html:54 templates/stats/language.html:26 msgid "Language AC Rate" msgstr "" @@ -3592,7 +3284,6 @@ msgid "Source:" msgstr "" #: templates/newsletter/common.html:6 -#: templates/newsletter/newsletter_list.html:15 #: templates/newsletter/subscription_unsubscribe_activated.html:3 #: templates/newsletter/subscription_unsubscribe_activated.html:6 #: templates/newsletter/subscription_update_activated.html:3 @@ -3600,23 +3291,6 @@ msgstr "" msgid "Newsletter" msgstr "" -#: templates/newsletter/newsletter_list.html:2 -#: templates/newsletter/newsletter_list.html:3 -msgid "Newsletter list" -msgstr "" - -#: templates/newsletter/newsletter_list.html:6 -msgid "Subscribe to get the latest emails about upcoming contests and events." -msgstr "" - -#: templates/newsletter/newsletter_list.html:16 -msgid "Subscribe" -msgstr "" - -#: templates/newsletter/newsletter_list.html:30 -msgid "Update subscriptions" -msgstr "" - #: templates/newsletter/subscription_unsubscribe_activated.html:3 #: templates/newsletter/subscription_unsubscribe_activated.html:6 #: templates/newsletter/subscription_update_activated.html:3 @@ -3678,97 +3352,64 @@ msgid "" "follow in order to update your subscription." msgstr "" -#: templates/notification/list.html:7 -msgid "You have no notifications" -msgstr "" - -#: templates/notification/list.html:13 -msgid "Activity" -msgstr "" - #: templates/organization/edit.html:46 #: templates/organization/requests/pending.html:34 #: templates/ticket/edit-notes.html:4 msgid "Update" msgstr "" -#: templates/organization/home.html:41 +#: templates/organization/home.html:7 msgid "Are you sure you want to leave this organization?" msgstr "" -#: templates/organization/home.html:43 +#: templates/organization/home.html:9 msgid "You will have to rejoin to show up on the organization leaderboard." msgstr "" -#: templates/organization/home.html:45 +#: templates/organization/home.html:11 msgid "You will have to request membership in order to join again." msgstr "" -#: templates/organization/home.html:88 -msgid "Join organization" -msgstr "" - -#: templates/organization/home.html:92 -msgid "Request membership" -msgstr "" - -#: templates/organization/home.html:122 -msgid "Organization news" -msgstr "" - -#: templates/organization/home.html:128 -msgid "There is no news at this time." -msgstr "" - -#: templates/organization/home.html:137 -msgid "Controls" -msgstr "" - -#: templates/organization/home.html:142 -msgid "Edit organization" -msgstr "" - -#: templates/organization/home.html:148 -msgid "View requests" -msgstr "" - -#: templates/organization/home.html:161 -msgid "Admin organization" -msgstr "" - -#: templates/organization/home.html:167 -msgid "View members" -msgstr "" - -#: templates/organization/home.html:174 +#: templates/organization/home.html:24 msgid "Leave organization" msgstr "" -#: templates/organization/home.html:183 -msgid "New private contests" +#: templates/organization/home.html:29 +msgid "Join organization" msgstr "" -#: templates/organization/home.html:193 templates/organization/home.html:208 -msgid "View all" +#: templates/organization/home.html:33 +msgid "Request membership" msgstr "" -#: templates/organization/home.html:199 -msgid "New private problems" +#: templates/organization/home.html:39 +msgid "Edit organization" msgstr "" -#: templates/organization/list.html:40 -msgid "Show my organizations only" +#: templates/organization/home.html:43 +msgid "View requests" msgstr "" -#: templates/organization/list.html:47 templates/status/language-list.html:34 -#: templates/user/import/table_csv.html:6 +#: templates/organization/home.html:50 +msgid "Admin organization" +msgstr "" + +#: templates/organization/home.html:55 +msgid "View members" +msgstr "" + +#: templates/organization/list.html:23 templates/status/language-list.html:34 msgid "Name" msgstr "" -#: templates/organization/list.html:48 +#: templates/organization/list.html:24 msgid "Members" msgstr "" +#: templates/organization/new.html:10 templates/ticket/new.html:38 +msgid "Create" +msgstr "" + #: templates/organization/requests/detail.html:13 msgid "User:" msgstr "" @@ -3801,7 +3442,7 @@ msgid "There are no requests to approve." msgstr "" #: templates/organization/requests/pending.html:17 -#: templates/problem/data.html:432 +#: templates/problem/data.html:452 msgid "Delete?" msgstr "" @@ -3837,35 +3478,35 @@ msgstr "" msgid "Enter a new code for the cloned problem:" msgstr "" -#: templates/problem/data.html:119 +#: templates/problem/data.html:108 msgid "Instruction" msgstr "" -#: templates/problem/data.html:390 +#: templates/problem/data.html:410 msgid "View YAML" msgstr "" -#: templates/problem/data.html:421 templates/problem/data.html:472 +#: templates/problem/data.html:441 templates/problem/data.html:491 msgid "Apply!" msgstr "" -#: templates/problem/data.html:426 +#: templates/problem/data.html:446 msgid "Type" msgstr "" -#: templates/problem/data.html:427 +#: templates/problem/data.html:447 msgid "Input file" msgstr "" -#: templates/problem/data.html:428 +#: templates/problem/data.html:448 msgid "Output file" msgstr "" -#: templates/problem/data.html:430 +#: templates/problem/data.html:450 msgid "Pretest?" msgstr "" -#: templates/problem/data.html:473 +#: templates/problem/data.html:492 msgid "Add new case" msgstr "" @@ -3877,32 +3518,28 @@ msgid "" "problem yourself is a bannable offence." msgstr "" -#: templates/problem/list.html:66 +#: templates/problem/list.html:62 msgid "Filter by type..." msgstr "" -#: templates/problem/list.html:193 +#: templates/problem/list.html:185 msgid "Hot problems" msgstr "" -#: templates/problem/list.html:218 templates/problem/list.html:240 -#: templates/problem/search-form.html:45 templates/user/user-problems.html:57 +#: templates/problem/list.html:207 templates/problem/list.html:224 +#: templates/problem/search-form.html:30 templates/user/user-problems.html:57 msgid "Category" msgstr "" -#: templates/problem/list.html:220 templates/problem/list.html:244 +#: templates/problem/list.html:209 templates/problem/list.html:228 msgid "Types" msgstr "" -#: templates/problem/list.html:251 +#: templates/problem/list.html:235 #, python-format msgid "AC %%" msgstr "" -#: templates/problem/list.html:342 -msgid "Add clarifications" -msgstr "" - #: templates/problem/manage_submission.html:55 msgid "Leave empty to not filter by language" msgstr "" @@ -3911,199 +3548,152 @@ msgstr "" msgid "Leave empty to not filter by result" msgstr "" -#: templates/problem/manage_submission.html:80 +#: templates/problem/manage_submission.html:79 msgid "Need valid values for both start and end IDs." msgstr "" -#: templates/problem/manage_submission.html:83 +#: templates/problem/manage_submission.html:82 msgid "End ID must be after start ID." msgstr "" +#: templates/problem/manage_submission.html:90 +#, python-brace-format +msgid "" +"You are about to rejudge {count} submissions. Are you sure you want to do " +"this?" +msgstr "" + #: templates/problem/manage_submission.html:96 -#, python-brace-format msgid "" -"You are about to {action} {count} submissions. Are you sure you want to do " -"this?" +"You are about to rejudge a few submissions. Are you sure you want to do this?" msgstr "" -#: templates/problem/manage_submission.html:103 -#, python-brace-format -msgid "" -"You are about to {action} a few submissions. Are you sure you want to do " -"this?" +#: templates/problem/manage_submission.html:115 +msgid "Rejudge Submissions" msgstr "" -#: templates/problem/manage_submission.html:127 -#: templates/submission/list.html:309 -msgid "Filter submissions" -msgstr "" - -#: templates/problem/manage_submission.html:132 +#: templates/problem/manage_submission.html:120 msgid "Filter by ID:" msgstr "" -#: templates/problem/manage_submission.html:135 +#: templates/problem/manage_submission.html:123 msgid "Starting ID:" msgstr "" -#: templates/problem/manage_submission.html:139 +#: templates/problem/manage_submission.html:127 msgid "Ending ID:" msgstr "" -#: templates/problem/manage_submission.html:143 +#: templates/problem/manage_submission.html:131 msgid "This range includes both endpoints." msgstr "" -#: templates/problem/manage_submission.html:146 +#: templates/problem/manage_submission.html:134 msgid "Filter by language:" msgstr "" -#: templates/problem/manage_submission.html:154 +#: templates/problem/manage_submission.html:142 msgid "Filter by result:" msgstr "" -#: templates/problem/manage_submission.html:164 -msgid "Action" -msgstr "" - -#: templates/problem/manage_submission.html:166 +#: templates/problem/manage_submission.html:150 msgid "Rejudge selected submissions" msgstr "" -#: templates/problem/manage_submission.html:171 -msgid "Download selected submissions" +#: templates/problem/manage_submission.html:157 +msgid "Rescore Everything" msgstr "" -#: templates/problem/manage_submission.html:177 -#, python-format -msgid "Are you sure you want to rescore %(count)d submissions?" -msgstr "" - -#: templates/problem/manage_submission.html:178 +#: templates/problem/manage_submission.html:163 msgid "Rescore all submissions" msgstr "" -#: templates/problem/problem.html:132 +#: templates/problem/problem.html:91 msgid "View as PDF" msgstr "" -#: templates/problem/problem.html:141 templates/problem/problem.html:151 -#: templates/problem/problem.html:156 +#: templates/problem/problem.html:101 templates/problem/problem.html:111 +#: templates/problem/problem.html:116 msgid "Submit solution" msgstr "" -#: templates/problem/problem.html:144 -#, python-format -msgid "%(counter)s submission left" -msgid_plural "%(counter)s submissions left" -msgstr[0] "" -msgstr[1] "" - -#: templates/problem/problem.html:152 +#: templates/problem/problem.html:112 msgid "0 submissions left" msgstr "" -#: templates/problem/problem.html:164 +#: templates/problem/problem.html:124 msgid "My submissions" msgstr "" -#: templates/problem/problem.html:168 +#: templates/problem/problem.html:128 msgid "Best submissions" msgstr "" -#: templates/problem/problem.html:172 +#: templates/problem/problem.html:132 msgid "Read editorial" msgstr "" -#: templates/problem/problem.html:177 +#: templates/problem/problem.html:137 msgid "Manage tickets" msgstr "" -#: templates/problem/problem.html:181 +#: templates/problem/problem.html:141 msgid "Edit problem" msgstr "" -#: templates/problem/problem.html:183 +#: templates/problem/problem.html:143 msgid "Edit test data" msgstr "" -#: templates/problem/problem.html:188 +#: templates/problem/problem.html:148 msgid "My tickets" msgstr "" -#: templates/problem/problem.html:196 +#: templates/problem/problem.html:156 msgid "Manage submissions" msgstr "" -#: templates/problem/problem.html:202 +#: templates/problem/problem.html:162 msgid "Clone problem" msgstr "" -#: templates/problem/problem.html:209 +#: templates/problem/problem.html:169 msgid "Points:" msgstr "" -#: templates/problem/problem.html:212 templates/problem/problem.html:214 +#: templates/problem/problem.html:172 templates/problem/problem.html:174 msgid "(partial)" msgstr "" -#: templates/problem/problem.html:219 +#: templates/problem/problem.html:179 msgid "Time limit:" msgstr "" -#: templates/problem/problem.html:231 +#: templates/problem/problem.html:191 msgid "Memory limit:" msgstr "" -#: templates/problem/problem.html:250 -msgid "Author:" -msgid_plural "Authors:" -msgstr[0] "" -msgstr[1] "" - -#: templates/problem/problem.html:265 -msgid "Problem type" -msgid_plural "Problem types" -msgstr[0] "" -msgstr[1] "" - -#: templates/problem/problem.html:278 +#: templates/problem/problem.html:238 msgid "Allowed languages" msgstr "" -#: templates/problem/problem.html:286 -#, python-format -msgid "No %(lang)s judge online" -msgstr "" - -#: templates/problem/problem.html:297 -msgid "Judge:" -msgid_plural "Judges:" -msgstr[0] "" -msgstr[1] "" - -#: templates/problem/problem.html:314 +#: templates/problem/problem.html:274 msgid "none available" msgstr "" -#: templates/problem/problem.html:326 -#, python-format -msgid "This problem has %(length)s clarification(s)" -msgstr "" - -#: templates/problem/problem.html:350 +#: templates/problem/problem.html:299 msgid "Request clarification" msgstr "" -#: templates/problem/problem.html:352 +#: templates/problem/problem.html:301 msgid "Report an issue" msgstr "" -#: templates/problem/raw.html:64 +#: templates/problem/raw.html:62 msgid "Time Limit:" msgstr "" -#: templates/problem/raw.html:73 +#: templates/problem/raw.html:71 msgid "Memory Limit:" msgstr "" @@ -4127,73 +3717,39 @@ msgstr "" msgid "Show problem types" msgstr "" -#: templates/problem/search-form.html:32 -msgid "Show editorial" -msgstr "" - -#: templates/problem/search-form.html:48 templates/problem/search-form.html:50 -#: templates/submission/submission-list-tabs.html:4 +#: templates/problem/search-form.html:33 templates/problem/search-form.html:35 msgid "All" msgstr "" -#: templates/problem/search-form.html:62 +#: templates/problem/search-form.html:46 msgid "Problem types" msgstr "" -#: templates/problem/search-form.html:73 +#: templates/problem/search-form.html:57 msgid "Point range" msgstr "" -#: templates/problem/search-form.html:79 templates/submission/list.html:331 +#: templates/problem/search-form.html:63 templates/submission/list.html:331 #: templates/ticket/list.html:248 msgid "Go" msgstr "" -#: templates/problem/search-form.html:80 +#: templates/problem/search-form.html:64 msgid "Random" msgstr "" -#: templates/problem/submit.html:117 -msgid "Your source code must contain at most 65536 characters." -msgstr "" - -#: templates/problem/submit.html:204 -#, python-format -msgid "" -"Warning! Your default language, %(default_language)s, is " -"unavailable for this problem and has been deselected." -msgstr "" - -#: templates/problem/submit.html:215 -#, python-format -msgid "" -"\n" -" You have %(left)s submission left\n" -" " -msgid_plural "" -"\n" -" You have %(left)s submissions left\n" -" " -msgstr[0] "" -msgstr[1] "" - -#: templates/problem/submit.html:224 +#: templates/problem/submit.html:212 msgid "You have 0 submissions left" msgstr "" -#: templates/problem/submit.html:258 +#: templates/problem/submit.html:250 msgid "No judge is available for this problem." msgstr "" -#: templates/problem/submit.html:262 +#: templates/problem/submit.html:252 msgid "Submit!" msgstr "" -#: templates/registration/activate.html:3 -#, python-format -msgid "%(key)s is an invalid activation key." -msgstr "" - #: templates/registration/activation_complete.html:3 msgid "Your account has been successfully activated." msgstr "" @@ -4251,13 +3807,6 @@ msgid "" "you registered with, and check your spam folder." msgstr "" -#: templates/registration/password_reset_email.txt:1 -#, python-format -msgid "" -"You're receiving this email because you requested a password reset for your " -"user account at %(site_name)s." -msgstr "" - #: templates/registration/password_reset_email.txt:3 msgid "Please go to the following page and choose a new password:" msgstr "" @@ -4270,16 +3819,6 @@ msgstr "" msgid "Thanks for using our site!" msgstr "" -#: templates/registration/password_reset_email.txt:11 -#, python-format -msgid "The %(site_name)s team" -msgstr "" - -#: templates/registration/password_reset_subject.txt:1 -#, python-format -msgid "Password reset on %(site_name)s" -msgstr "" - #: templates/registration/profile_creation.html:36 #: templates/registration/username_select.html:7 msgid "Continue >" @@ -4316,20 +3855,19 @@ msgstr "" msgid "Affiliated organizations" msgstr "" -#: templates/registration/registration_form.html:195 -#: templates/user/edit-profile.html:128 +#: templates/registration/registration_form.html:192 msgid "Notify me about upcoming contests" msgstr "" -#: templates/registration/registration_form.html:209 +#: templates/registration/registration_form.html:206 msgid "By registering, you agree to our" msgstr "" -#: templates/registration/registration_form.html:210 +#: templates/registration/registration_form.html:207 msgid "Terms & Conditions" msgstr "" -#: templates/registration/registration_form.html:213 +#: templates/registration/registration_form.html:210 msgid "Register!" msgstr "" @@ -4339,11 +3877,6 @@ msgstr "" msgid "Enter the 6-digit code generated by your app:" msgstr "" -#: templates/registration/totp_auth.html:41 -#, python-format -msgid "If you lost your authentication device, please contact us at %(email)s." -msgstr "" - #: templates/registration/totp_disable.html:38 msgid "" "To protect your account, you must first authenticate before you can disable " @@ -4362,6 +3895,10 @@ msgstr "" msgid "Or enter this code manually:" msgstr "" +#: templates/stats/base.html:9 templates/submission/list.html:339 +msgid "Statistics" +msgstr "" + #: templates/stats/language.html:11 msgid "Submission Statistics" msgstr "" @@ -4387,7 +3924,6 @@ msgid "Ping" msgstr "" #: templates/status/judge-status-table.html:8 -#: templates/user/import/index.html:104 msgid "Load" msgstr "" @@ -4403,7 +3939,6 @@ msgid "There are no judges available at this time." msgstr "" #: templates/status/language-list.html:33 templates/ticket/list.html:261 -#: templates/user/import/table_csv.html:3 msgid "ID" msgstr "" @@ -4411,22 +3946,6 @@ msgstr "" msgid "Runtime Info" msgstr "" -#: templates/status/status-tabs.html:4 -msgid "Judges" -msgstr "" - -#: templates/status/status-tabs.html:6 -msgid "Version Matrix" -msgstr "" - -#: templates/submission/internal-error-message.html:3 -#, python-format -msgid "" -"An internal error occurred while grading, and the %(SITE_NAME)s " -"administrators have been notified.
In the meantime, try resubmitting in " -"a few seconds." -msgstr "" - #: templates/submission/internal-error-message.html:8 msgid "An internal error occurred while grading." msgstr "" @@ -4443,6 +3962,10 @@ msgstr "" msgid "Filter by language..." msgstr "" +#: templates/submission/list.html:309 +msgid "Filter submissions" +msgstr "" + #: templates/submission/list.html:345 msgid "Total:" msgstr "" @@ -4499,64 +4022,63 @@ msgstr "" msgid "Execution Results" msgstr "" -#: templates/submission/status-testcases.html:34 -msgid "Overall: " -msgstr "" - -#: templates/submission/status-testcases.html:48 -msgid "Point: " -msgstr "" - -#: templates/submission/status-testcases.html:53 -msgid "Time: " -msgstr "" - -#: templates/submission/status-testcases.html:62 -msgid "Memory: " -msgstr "" - -#: templates/submission/status-testcases.html:73 +#: templates/submission/status-testcases.html:31 msgid "Batch " msgstr "" -#: templates/submission/status-testcases.html:84 -#: templates/submission/status-testcases.html:113 -msgid "Point" +#: templates/submission/status-testcases.html:43 +msgid "Overall: " msgstr "" -#: templates/submission/status-testcases.html:99 +#: templates/submission/status-testcases.html:57 +msgid "Point: " +msgstr "" + +#: templates/submission/status-testcases.html:62 +msgid "Time: " +msgstr "" + +#: templates/submission/status-testcases.html:71 +msgid "Memory: " +msgstr "" + +#: templates/submission/status-testcases.html:84 msgid "Case" msgstr "" -#: templates/submission/status-testcases.html:101 +#: templates/submission/status-testcases.html:86 msgid "Pretest" msgstr "" -#: templates/submission/status-testcases.html:103 +#: templates/submission/status-testcases.html:88 msgid "Test case" msgstr "" -#: templates/submission/status-testcases.html:141 +#: templates/submission/status-testcases.html:99 +msgid "Point" +msgstr "" + +#: templates/submission/status-testcases.html:121 msgid "Input:" msgstr "" -#: templates/submission/status-testcases.html:145 +#: templates/submission/status-testcases.html:125 msgid "Output:" msgstr "" -#: templates/submission/status-testcases.html:149 +#: templates/submission/status-testcases.html:129 msgid "Answer:" msgstr "" -#: templates/submission/status-testcases.html:154 +#: templates/submission/status-testcases.html:134 msgid "Judge feedback:" msgstr "" -#: templates/submission/status-testcases.html:175 +#: templates/submission/status-testcases.html:157 msgid "Passing pretests does not guarantee a full score on system tests." msgstr "" -#: templates/submission/status-testcases.html:178 +#: templates/submission/status-testcases.html:160 msgid "Submission aborted!" msgstr "" @@ -4568,24 +4090,11 @@ msgstr "" msgid "Abort" msgstr "" -#: templates/submission/submission-list-tabs.html:6 -msgid "Mine" -msgstr "" - -#: templates/submission/submission-list-tabs.html:9 -msgid "Best" -msgstr "" - -#: templates/submission/submission-list-tabs.html:12 -#, python-format -msgid "%(user)s's" -msgstr "" - -#: templates/ticket/list.html:135 templates/ticket/ticket.html:273 +#: templates/ticket/list.html:135 templates/ticket/ticket.html:257 msgid "Reopened: " msgstr "" -#: templates/ticket/list.html:138 templates/ticket/ticket.html:274 +#: templates/ticket/list.html:138 templates/ticket/ticket.html:258 msgid "Closed: " msgstr "" @@ -4609,7 +4118,7 @@ msgstr "" msgid "Title" msgstr "" -#: templates/ticket/list.html:264 templates/ticket/ticket.html:369 +#: templates/ticket/list.html:264 templates/ticket/ticket.html:328 msgid "Assignees" msgstr "" @@ -4624,36 +4133,32 @@ msgid "" "a problem, ask in the comments instead." msgstr "" -#: templates/ticket/ticket.html:355 -msgid "Post" -msgstr "" - -#: templates/ticket/ticket.html:363 +#: templates/ticket/ticket.html:322 msgid "Associated object" msgstr "" -#: templates/ticket/ticket.html:374 +#: templates/ticket/ticket.html:333 msgid "No one is assigned." msgstr "" -#: templates/ticket/ticket.html:380 +#: templates/ticket/ticket.html:339 msgid "Close ticket" msgstr "" -#: templates/ticket/ticket.html:382 +#: templates/ticket/ticket.html:341 msgid "Reopen ticket" msgstr "" -#: templates/ticket/ticket.html:386 +#: templates/ticket/ticket.html:345 msgid "Assignee notes" msgstr "" -#: templates/ticket/ticket.html:393 templates/widgets/select_all.html:4 +#: templates/ticket/ticket.html:352 templates/widgets/select_all.html:4 msgid "Nothing here." msgstr "" -#: templates/user/base-users-table.html:3 -msgid "Rank" +#: templates/ticket/ticket.html:385 +msgid "Post" msgstr "" #: templates/user/base-users.html:14 templates/user/base-users.html:69 @@ -4700,168 +4205,50 @@ msgstr "" msgid "Update profile" msgstr "" -#: templates/user/import/index.html:31 -msgid "Upload CSV only" -msgstr "" - -#: templates/user/import/index.html:100 -msgid "User File" -msgstr "" - -#: templates/user/import/index.html:102 -msgid "Sample" -msgstr "" - -#: templates/user/import/index.html:105 templates/user/user-list-tabs.html:8 -msgid "Import" -msgstr "" - -#: templates/user/import/table_csv.html:7 -msgid "School" -msgstr "" - -#: templates/user/pp-row.html:22 -#, python-format -msgid "" -"\n" -" weighted %(weight)s%%\n" -" " -msgstr "" - -#: templates/user/pp-row.html:27 -#, python-format -msgid "%(pp).1fpp" -msgstr "" - -#: templates/user/pp-row.html:29 -#, python-format -msgid "%(pp).0fpp" -msgstr "" - -#: templates/user/user-about.html:23 -#, python-format -msgid "%(counter)s problem solved" -msgid_plural "%(counter)s problems solved" -msgstr[0] "" -msgstr[1] "" - -#: templates/user/user-about.html:35 -msgid "Total points" -msgstr "" - -#: templates/user/user-about.html:45 -msgid "Rank by rating" -msgstr "" - -#: templates/user/user-about.html:52 -msgid "Rank by points" -msgstr "" - -#: templates/user/user-about.html:64 +#: templates/user/user-about.html:14 msgid "From" msgstr "" -#: templates/user/user-about.html:75 +#: templates/user/user-about.html:25 msgid "Admin Notes" msgstr "" -#: templates/user/user-about.html:90 +#: templates/user/user-about.html:40 msgid "You have not shared any information." msgstr "" -#: templates/user/user-about.html:92 +#: templates/user/user-about.html:42 msgid "This user has not shared any information." msgstr "" -#: templates/user/user-about.html:101 -msgid "Awards" +#: templates/user/user-base.html:50 +msgid "Rank by points:" msgstr "" -#: templates/user/user-about.html:112 -#, python-format -msgid "%(label)s (%(date)s)" +#: templates/user/user-base.html:53 +msgid "Total points:" msgstr "" -#: templates/user/user-about.html:130 -msgid "Mon" +#: templates/user/user-base.html:68 +msgid "Rank by rating:" msgstr "" -#: templates/user/user-about.html:135 -msgid "Tues" +#: templates/user/user-base.html:70 +msgid "Rating:" msgstr "" -#: templates/user/user-about.html:140 -msgid "Wed" -msgstr "" - -#: templates/user/user-about.html:145 -msgid "Thurs" -msgstr "" - -#: templates/user/user-about.html:150 -msgid "Fri" -msgstr "" - -#: templates/user/user-about.html:155 -msgid "Sat" -msgstr "" - -#: templates/user/user-about.html:160 -msgid "Sun" -msgstr "" - -#: templates/user/user-about.html:169 -msgid "Less" -msgstr "" - -#: templates/user/user-about.html:175 -msgid "More" -msgstr "" - -#: templates/user/user-about.html:184 -msgid "Rating History" -msgstr "" - -#: templates/user/user-about.html:255 -msgid "past year" -msgstr "" - -#: templates/user/user-about.html:272 -msgid "total submission(s)" -msgstr "" - -#: templates/user/user-about.html:276 -msgid "submissions in the last year" -msgstr "" - -#: templates/user/user-base.html:101 -msgid "Unfollow" -msgstr "" - -#: templates/user/user-base.html:104 -msgid "Follow" -msgstr "" - -#: templates/user/user-base.html:120 -msgid "Contests written" -msgstr "" - -#: templates/user/user-base.html:124 +#: templates/user/user-base.html:71 msgid "Volatility:" msgstr "" -#: templates/user/user-base.html:128 +#: templates/user/user-base.html:72 msgid "Min. rating:" msgstr "" -#: templates/user/user-base.html:132 +#: templates/user/user-base.html:73 msgid "Max rating:" msgstr "" -#: templates/user/user-list-tabs.html:5 -msgid "Friends" -msgstr "" - #: templates/user/user-problems.html:35 msgid "Points Breakdown" msgstr "" @@ -4882,32 +4269,10 @@ msgstr "" msgid "Hide problems I've solved" msgstr "" -#: templates/user/user-problems.html:93 -#, python-format -msgid "%(points).1f points" -msgstr "" - #: templates/user/user-problems.html:99 msgid "Score" msgstr "" -#: templates/user/user-problems.html:110 -#, python-format -msgid "%(points)s / %(total)s" -msgstr "" - -#: templates/user/user-tabs.html:7 -msgid "Impersonate" -msgstr "" - -#: templates/user/user-tabs.html:13 -msgid "Admin User" -msgstr "" - -#: templates/user/user-tabs.html:16 -msgid "Admin Profile" -msgstr "" - #: templates/widgets/select_all.html:8 msgid "Check all" msgstr "" diff --git a/locale/nl/LC_MESSAGES/djangojs.po b/locale/nl/LC_MESSAGES/djangojs.po index 76dc02d..0f23d9b 100644 --- a/locale/nl/LC_MESSAGES/djangojs.po +++ b/locale/nl/LC_MESSAGES/djangojs.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: dmoj\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-07-20 23:30+0700\n" +"POT-Creation-Date: 2019-10-01 23:12+0000\n" "PO-Revision-Date: 2019-11-11 22:05\n" "Last-Translator: Icyene\n" "Language-Team: Dutch\n" @@ -27,3 +27,4 @@ msgstr[1] "" msgctxt "time format without day" msgid "%h:%m:%s" msgstr "" + diff --git a/locale/pl/LC_MESSAGES/django.po b/locale/pl/LC_MESSAGES/django.po index c85a4bf..87e4955 100644 --- a/locale/pl/LC_MESSAGES/django.po +++ b/locale/pl/LC_MESSAGES/django.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: dmoj\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-10-25 05:59+0700\n" +"POT-Creation-Date: 2020-04-10 01:26-0500\n" "PO-Revision-Date: 2019-11-11 22:05\n" "Last-Translator: Icyene\n" "Language-Team: Polish\n" @@ -18,93 +18,93 @@ msgstr "" "X-Crowdin-Language: pl\n" "X-Crowdin-File: django.po\n" -#: chat_box/models.py:16 judge/admin/interface.py:110 -#: judge/models/contest.py:403 judge/models/contest.py:528 -#: judge/models/profile.py:211 +#: chat_box/models.py:15 judge/admin/interface.py:107 +#: judge/models/contest.py:257 judge/models/contest.py:381 +#: judge/models/profile.py:191 msgid "user" msgstr "" -#: chat_box/models.py:17 judge/models/comment.py:43 judge/models/comment.py:191 +#: chat_box/models.py:16 judge/models/comment.py:42 msgid "posted time" msgstr "" -#: chat_box/models.py:18 judge/models/comment.py:47 +#: chat_box/models.py:17 judge/models/comment.py:46 msgid "body of comment" msgstr "" -#: chat_box/views.py:29 templates/chat/chat.html:4 +#: chat_box/views.py:29 msgid "Chat Box" msgstr "" -#: dmoj/settings.py:355 +#: dmoj/settings.py:349 msgid "German" msgstr "Niemiecki" -#: dmoj/settings.py:356 +#: dmoj/settings.py:350 msgid "English" msgstr "Angielski" -#: dmoj/settings.py:357 +#: dmoj/settings.py:351 msgid "Spanish" msgstr "Hiszpański" -#: dmoj/settings.py:358 +#: dmoj/settings.py:352 msgid "French" msgstr "Francuski" -#: dmoj/settings.py:359 +#: dmoj/settings.py:353 msgid "Croatian" msgstr "Chorwacki" -#: dmoj/settings.py:360 +#: dmoj/settings.py:354 msgid "Hungarian" msgstr "Węgierski" -#: dmoj/settings.py:361 +#: dmoj/settings.py:355 msgid "Japanese" msgstr "" -#: dmoj/settings.py:362 +#: dmoj/settings.py:356 msgid "Korean" msgstr "Koreański" -#: dmoj/settings.py:363 +#: dmoj/settings.py:357 msgid "Brazilian Portuguese" msgstr "" -#: dmoj/settings.py:364 +#: dmoj/settings.py:358 msgid "Romanian" msgstr "Rumuński" -#: dmoj/settings.py:365 +#: dmoj/settings.py:359 msgid "Russian" msgstr "Rosyjski" -#: dmoj/settings.py:366 +#: dmoj/settings.py:360 msgid "Serbian (Latin)" msgstr "Serbski (alfabet łaciński)" -#: dmoj/settings.py:367 +#: dmoj/settings.py:361 msgid "Turkish" msgstr "Turecki" -#: dmoj/settings.py:368 +#: dmoj/settings.py:362 msgid "Vietnamese" msgstr "Wietnamski" -#: dmoj/settings.py:369 +#: dmoj/settings.py:363 msgid "Simplified Chinese" msgstr "Chiński Uproszczony" -#: dmoj/settings.py:370 +#: dmoj/settings.py:364 msgid "Traditional Chinese" msgstr "" -#: dmoj/urls.py:58 +#: dmoj/urls.py:57 msgid "Login" msgstr "Logowanie" -#: dmoj/urls.py:106 templates/base.html:193 +#: dmoj/urls.py:105 templates/base.html:190 msgid "Home" msgstr "Strona główna" @@ -138,48 +138,46 @@ msgstr "Pokaż komentarze" msgid "Associated page" msgstr "Dołączona strona" -#: judge/admin/contest.py:30 +#: judge/admin/contest.py:28 msgid "Included contests" msgstr "Załączniki" -#: judge/admin/contest.py:66 templates/contest/clarification.html:42 -#: templates/contest/contest.html:83 templates/contest/moss.html:43 -#: templates/problem/list.html:214 templates/problem/list.html:232 -#: templates/problem/list.html:350 templates/user/user-problems.html:56 +#: judge/admin/contest.py:64 templates/contest/contest.html:83 +#: templates/contest/moss.html:43 templates/problem/list.html:206 +#: templates/problem/list.html:221 templates/user/user-problems.html:56 #: templates/user/user-problems.html:98 msgid "Problem" msgstr "Problem" -#: judge/admin/contest.py:119 +#: judge/admin/contest.py:112 msgid "Settings" msgstr "" -#: judge/admin/contest.py:121 +#: judge/admin/contest.py:114 msgid "Scheduling" msgstr "Planowanie" -#: judge/admin/contest.py:122 templates/organization/home.html:107 +#: judge/admin/contest.py:115 msgid "Details" msgstr "Szczegóły" -#: judge/admin/contest.py:123 +#: judge/admin/contest.py:116 msgid "Format" msgstr "" -#: judge/admin/contest.py:124 templates/contest/ranking-table.html:7 -#: templates/user/user-about.html:15 templates/user/user-about.html:45 +#: judge/admin/contest.py:117 templates/contest/ranking-table.html:5 msgid "Rating" msgstr "Ocena" -#: judge/admin/contest.py:125 +#: judge/admin/contest.py:118 msgid "Access" msgstr "" -#: judge/admin/contest.py:127 judge/admin/problem.py:131 +#: judge/admin/contest.py:120 judge/admin/problem.py:131 msgid "Justice" msgstr "" -#: judge/admin/contest.py:207 +#: judge/admin/contest.py:158 #, python-format msgid "%d contest successfully marked as visible." msgid_plural "%d contests successfully marked as visible." @@ -188,11 +186,11 @@ msgstr[1] "" msgstr[2] "" msgstr[3] "" -#: judge/admin/contest.py:210 +#: judge/admin/contest.py:161 msgid "Mark contests as visible" msgstr "" -#: judge/admin/contest.py:216 +#: judge/admin/contest.py:165 #, python-format msgid "%d contest successfully marked as hidden." msgid_plural "%d contests successfully marked as hidden." @@ -201,11 +199,11 @@ msgstr[1] "" msgstr[2] "" msgstr[3] "" -#: judge/admin/contest.py:219 +#: judge/admin/contest.py:168 msgid "Mark contests as hidden" msgstr "" -#: judge/admin/contest.py:233 judge/admin/submission.py:164 +#: judge/admin/contest.py:182 judge/admin/submission.py:164 #, python-format msgid "%d submission was successfully scheduled for rejudging." msgid_plural "%d submissions were successfully scheduled for rejudging." @@ -214,7 +212,7 @@ msgstr[1] "" msgstr[2] "" msgstr[3] "" -#: judge/admin/contest.py:308 +#: judge/admin/contest.py:256 #, python-format msgid "%d participation recalculated." msgid_plural "%d participations recalculated." @@ -223,15 +221,15 @@ msgstr[1] "" msgstr[2] "" msgstr[3] "" -#: judge/admin/contest.py:311 +#: judge/admin/contest.py:259 msgid "Recalculate results" msgstr "" -#: judge/admin/contest.py:315 judge/admin/organization.py:65 +#: judge/admin/contest.py:263 judge/admin/organization.py:65 msgid "username" msgstr "" -#: judge/admin/contest.py:320 templates/base.html:277 +#: judge/admin/contest.py:268 templates/base.html:260 msgid "virtual" msgstr "" @@ -239,15 +237,15 @@ msgstr "" msgid "link path" msgstr "" -#: judge/admin/interface.py:65 +#: judge/admin/interface.py:62 msgid "Content" msgstr "" -#: judge/admin/interface.py:66 +#: judge/admin/interface.py:63 msgid "Summary" msgstr "" -#: judge/admin/interface.py:151 +#: judge/admin/interface.py:148 msgid "object" msgstr "" @@ -269,9 +267,8 @@ msgid "Taxonomy" msgstr "" #: judge/admin/problem.py:128 templates/contest/contest.html:84 -#: templates/problem/data.html:429 templates/problem/list.html:222 -#: templates/problem/list.html:248 templates/user/base-users-table.html:10 -#: templates/user/user-about.html:36 templates/user/user-about.html:52 +#: templates/problem/data.html:449 templates/problem/list.html:211 +#: templates/problem/list.html:232 templates/user/base-users-table.html:10 #: templates/user/user-problems.html:58 msgid "Points" msgstr "" @@ -324,7 +321,6 @@ msgid "timezone" msgstr "" #: judge/admin/profile.py:86 judge/admin/submission.py:211 -#: templates/notification/list.html:12 #: templates/organization/requests/log.html:9 #: templates/organization/requests/pending.html:12 #: templates/ticket/list.html:263 @@ -332,7 +328,6 @@ msgid "User" msgstr "" #: judge/admin/profile.py:91 templates/registration/registration_form.html:145 -#: templates/user/import/table_csv.html:8 msgid "Email" msgstr "" @@ -367,7 +362,7 @@ msgstr "" msgid "These problems are NOT allowed to be submitted in this language" msgstr "" -#: judge/admin/runtime.py:83 templates/problem/list.html:352 +#: judge/admin/runtime.py:83 msgid "Description" msgstr "" @@ -414,7 +409,7 @@ msgstr "" msgid "Rejudge the selected submissions" msgstr "" -#: judge/admin/submission.py:193 judge/views/problem_manage.py:159 +#: judge/admin/submission.py:193 judge/views/problem_manage.py:128 #, python-format msgid "%d submission were successfully rescored." msgid_plural "%d submissions were successfully rescored." @@ -427,8 +422,7 @@ msgstr[3] "" msgid "Rescore the selected submissions" msgstr "" -#: judge/admin/submission.py:200 templates/problem/list.html:216 -#: templates/problem/list.html:236 +#: judge/admin/submission.py:200 msgid "Problem code" msgstr "" @@ -436,12 +430,10 @@ msgstr "" msgid "Problem name" msgstr "" -#: judge/admin/submission.py:215 templates/notification/list.html:15 -#: templates/organization/requests/log.html:10 +#: judge/admin/submission.py:215 templates/organization/requests/log.html:10 #: templates/organization/requests/pending.html:13 -#: templates/problem/list.html:351 -#: templates/submission/status-testcases.html:125 -#: templates/submission/status-testcases.html:127 +#: templates/submission/status-testcases.html:105 +#: templates/submission/status-testcases.html:107 msgid "Time" msgstr "" @@ -455,7 +447,7 @@ msgstr "" msgid "%.2f MB" msgstr "" -#: judge/admin/submission.py:227 templates/submission/status-testcases.html:132 +#: judge/admin/submission.py:227 templates/submission/status-testcases.html:112 msgid "Memory" msgstr "" @@ -475,20 +467,20 @@ msgstr "" msgid "Online Judge" msgstr "" -#: judge/comments.py:60 +#: judge/comments.py:41 msgid "Comment body" msgstr "" -#: judge/comments.py:66 judge/views/ticket.py:63 +#: judge/comments.py:47 judge/views/ticket.py:46 msgid "Your part is silent, little toad." msgstr "" -#: judge/comments.py:69 templates/comments/list.html:132 +#: judge/comments.py:50 templates/comments/list.html:131 msgid "" "You need to have solved at least one problem before your voice can be heard." msgstr "" -#: judge/comments.py:113 +#: judge/comments.py:92 msgid "Posted comment" msgstr "" @@ -504,10 +496,6 @@ msgstr "" msgid "ECOO" msgstr "" -#: judge/contest_format/icpc.py:19 -msgid "ICPC" -msgstr "" - #: judge/contest_format/ioi.py:19 msgid "IOI" msgstr "" @@ -520,58 +508,52 @@ msgstr "" msgid "Enable experimental features" msgstr "" -#: judge/forms.py:57 judge/views/organization.py:168 judge/views/register.py:49 +#: judge/forms.py:57 judge/views/organization.py:127 #, python-brace-format msgid "You may not be part of more than {count} public organizations." msgstr "" -#: judge/forms.py:82 -msgid "Any judge" -msgstr "" - -#: judge/forms.py:112 judge/views/register.py:26 +#: judge/forms.py:107 judge/views/register.py:26 #: templates/registration/registration_form.html:139 #: templates/user/base-users-table.html:5 -#: templates/user/import/table_csv.html:4 msgid "Username" msgstr "" -#: judge/forms.py:113 templates/registration/registration_form.html:151 +#: judge/forms.py:108 templates/registration/registration_form.html:151 #: templates/registration/registration_form.html:165 -#: templates/user/import/table_csv.html:5 msgid "Password" msgstr "" -#: judge/forms.py:135 +#: judge/forms.py:130 msgid "Two Factor Authentication tokens must be 6 decimal digits." msgstr "" -#: judge/forms.py:144 templates/registration/totp_auth.html:32 +#: judge/forms.py:139 templates/registration/totp_auth.html:32 msgid "Invalid Two Factor Authentication token." msgstr "" -#: judge/forms.py:148 judge/models/problem.py:97 +#: judge/forms.py:143 judge/models/problem.py:97 msgid "Problem code must be ^[a-z0-9]+$" msgstr "" -#: judge/forms.py:153 +#: judge/forms.py:148 msgid "Problem with code already exists." msgstr "" -#: judge/forms.py:158 judge/models/contest.py:61 +#: judge/forms.py:153 judge/models/contest.py:52 msgid "Contest id must be ^[a-z0-9]+$" msgstr "" -#: judge/forms.py:163 +#: judge/forms.py:158 msgid "Contest with key already exists." msgstr "" -#: judge/jinja2/datetime.py:26 templates/blog/blog.html:26 +#: judge/jinja2/datetime.py:26 templates/blog/content.html:27 #: templates/blog/dashboard.html:21 msgid "N j, Y, g:i a" msgstr "" -#: judge/jinja2/datetime.py:26 templates/chat/message.html:13 +#: judge/jinja2/datetime.py:26 #, python-brace-format msgid "{time}" msgstr "" @@ -601,542 +583,472 @@ msgstr "" msgid "Detect best quality" msgstr "" -#: judge/models/comment.py:26 +#: judge/models/comment.py:25 msgid "Page code must be ^[pcs]:[a-z0-9]+$|^b:\\d+$" msgstr "" -#: judge/models/comment.py:42 +#: judge/models/comment.py:41 msgid "commenter" msgstr "" -#: judge/models/comment.py:44 judge/models/comment.py:177 +#: judge/models/comment.py:43 judge/models/comment.py:176 msgid "associated page" msgstr "" -#: judge/models/comment.py:46 +#: judge/models/comment.py:45 msgid "votes" msgstr "" -#: judge/models/comment.py:48 +#: judge/models/comment.py:47 msgid "hide the comment" msgstr "" -#: judge/models/comment.py:49 +#: judge/models/comment.py:48 msgid "parent" msgstr "" -#: judge/models/comment.py:54 judge/models/comment.py:192 +#: judge/models/comment.py:53 msgid "comment" msgstr "" -#: judge/models/comment.py:55 +#: judge/models/comment.py:54 msgid "comments" msgstr "" -#: judge/models/comment.py:137 judge/models/problem.py:443 +#: judge/models/comment.py:136 judge/models/problem.py:406 #, python-format msgid "Editorial for %s" msgstr "" -#: judge/models/comment.py:172 +#: judge/models/comment.py:171 msgid "comment vote" msgstr "" -#: judge/models/comment.py:173 +#: judge/models/comment.py:172 msgid "comment votes" msgstr "" -#: judge/models/comment.py:182 +#: judge/models/comment.py:181 msgid "Override comment lock" msgstr "" -#: judge/models/comment.py:190 -msgid "owner" -msgstr "" - -#: judge/models/comment.py:193 judge/models/message.py:16 -msgid "read" -msgstr "" - -#: judge/models/comment.py:194 -msgid "category" -msgstr "" - -#: judge/models/comment.py:195 -msgid "html link to comments, used for non-comments" -msgstr "" - -#: judge/models/comment.py:196 -msgid "who trigger, used for non-comment" -msgstr "" - -#: judge/models/contest.py:23 +#: judge/models/contest.py:22 msgid "Invalid colour." msgstr "" -#: judge/models/contest.py:25 +#: judge/models/contest.py:24 msgid "tag name" msgstr "" -#: judge/models/contest.py:26 +#: judge/models/contest.py:25 msgid "Lowercase letters and hyphens only." msgstr "" -#: judge/models/contest.py:27 +#: judge/models/contest.py:26 msgid "tag colour" msgstr "" -#: judge/models/contest.py:28 +#: judge/models/contest.py:27 msgid "tag description" msgstr "" -#: judge/models/contest.py:47 +#: judge/models/contest.py:46 msgid "contest tag" msgstr "" -#: judge/models/contest.py:48 judge/models/contest.py:118 +#: judge/models/contest.py:47 judge/models/contest.py:101 msgid "contest tags" msgstr "" -#: judge/models/contest.py:56 -msgid "Visible" -msgstr "" - -#: judge/models/contest.py:57 -msgid "Hidden for duration of contest" -msgstr "" - -#: judge/models/contest.py:58 -msgid "Hidden for duration of participation" -msgstr "" - -#: judge/models/contest.py:60 +#: judge/models/contest.py:51 msgid "contest id" msgstr "" -#: judge/models/contest.py:62 +#: judge/models/contest.py:53 msgid "contest name" msgstr "" -#: judge/models/contest.py:63 -msgid "These users will be able to edit the contest." +#: judge/models/contest.py:54 +msgid "These people will be able to edit the contest." msgstr "" -#: judge/models/contest.py:65 -msgid "" -"These users will be able to edit the contest, but will not be listed as " -"authors." -msgstr "" - -#: judge/models/contest.py:68 -msgid "These users will be able to view the contest, but not edit it." -msgstr "" - -#: judge/models/contest.py:71 judge/models/runtime.py:136 +#: judge/models/contest.py:56 judge/models/runtime.py:133 msgid "description" msgstr "" -#: judge/models/contest.py:72 judge/models/problem.py:390 -#: judge/models/runtime.py:138 +#: judge/models/contest.py:57 judge/models/problem.py:353 +#: judge/models/runtime.py:135 msgid "problems" msgstr "" -#: judge/models/contest.py:73 judge/models/contest.py:404 +#: judge/models/contest.py:58 judge/models/contest.py:258 msgid "start time" msgstr "" -#: judge/models/contest.py:74 +#: judge/models/contest.py:59 msgid "end time" msgstr "" -#: judge/models/contest.py:75 judge/models/problem.py:118 -#: judge/models/problem.py:414 +#: judge/models/contest.py:60 judge/models/problem.py:118 +#: judge/models/problem.py:377 msgid "time limit" msgstr "" -#: judge/models/contest.py:76 judge/models/problem.py:136 +#: judge/models/contest.py:61 judge/models/problem.py:136 msgid "publicly visible" msgstr "" -#: judge/models/contest.py:77 +#: judge/models/contest.py:62 msgid "" "Should be set even for organization-private contests, where it determines " "whether the contest is visible to members of the specified organizations." msgstr "" -#: judge/models/contest.py:80 +#: judge/models/contest.py:65 msgid "contest rated" msgstr "" -#: judge/models/contest.py:80 +#: judge/models/contest.py:65 msgid "Whether this contest can be rated." msgstr "" -#: judge/models/contest.py:82 -msgid "scoreboard visibility" +#: judge/models/contest.py:67 +msgid "hide scoreboard" msgstr "" -#: judge/models/contest.py:83 -msgid "Scoreboard visibility through the duration of the contest" +#: judge/models/contest.py:68 +msgid "" +"Whether the scoreboard should remain hidden for the duration of the contest." msgstr "" -#: judge/models/contest.py:85 -msgid "view contest scoreboard" -msgstr "" - -#: judge/models/contest.py:87 -msgid "These users will be able to view the scoreboard." -msgstr "" - -#: judge/models/contest.py:88 +#: judge/models/contest.py:71 msgid "no comments" msgstr "" -#: judge/models/contest.py:89 +#: judge/models/contest.py:72 msgid "Use clarification system instead of comments." msgstr "" -#: judge/models/contest.py:91 +#: judge/models/contest.py:74 msgid "Rating floor for contest" msgstr "" -#: judge/models/contest.py:93 +#: judge/models/contest.py:76 msgid "Rating ceiling for contest" msgstr "" -#: judge/models/contest.py:95 +#: judge/models/contest.py:78 msgid "rate all" msgstr "" -#: judge/models/contest.py:95 +#: judge/models/contest.py:78 msgid "Rate all users who joined." msgstr "" -#: judge/models/contest.py:96 +#: judge/models/contest.py:79 msgid "exclude from ratings" msgstr "" -#: judge/models/contest.py:98 +#: judge/models/contest.py:81 msgid "private to specific users" msgstr "" -#: judge/models/contest.py:99 +#: judge/models/contest.py:82 msgid "private contestants" msgstr "" -#: judge/models/contest.py:100 +#: judge/models/contest.py:83 msgid "If private, only these users may see the contest" msgstr "" -#: judge/models/contest.py:102 +#: judge/models/contest.py:85 msgid "hide problem tags" msgstr "" -#: judge/models/contest.py:103 +#: judge/models/contest.py:86 msgid "Whether problem tags should be hidden by default." msgstr "" -#: judge/models/contest.py:105 +#: judge/models/contest.py:88 msgid "run pretests only" msgstr "" -#: judge/models/contest.py:106 +#: judge/models/contest.py:89 msgid "" "Whether judges should grade pretests only, versus all testcases. Commonly " "set during a contest, then unset prior to rejudging user submissions when " "the contest ends." msgstr "" -#: judge/models/contest.py:110 judge/models/interface.py:77 -#: judge/models/problem.py:157 +#: judge/models/contest.py:93 judge/models/problem.py:157 msgid "private to organizations" msgstr "" -#: judge/models/contest.py:111 judge/models/interface.py:75 -#: judge/models/problem.py:155 judge/models/profile.py:77 +#: judge/models/contest.py:94 judge/models/problem.py:155 +#: judge/models/profile.py:77 msgid "organizations" msgstr "" -#: judge/models/contest.py:112 +#: judge/models/contest.py:95 msgid "If private, only these organizations may see the contest" msgstr "" -#: judge/models/contest.py:113 judge/models/problem.py:145 +#: judge/models/contest.py:96 judge/models/problem.py:145 msgid "OpenGraph image" msgstr "" -#: judge/models/contest.py:114 judge/models/profile.py:48 +#: judge/models/contest.py:97 judge/models/profile.py:48 msgid "Logo override image" msgstr "" -#: judge/models/contest.py:116 +#: judge/models/contest.py:99 msgid "" "This image will replace the default site logo for users inside the contest." msgstr "" -#: judge/models/contest.py:119 +#: judge/models/contest.py:102 msgid "the amount of live participants" msgstr "" -#: judge/models/contest.py:120 +#: judge/models/contest.py:103 msgid "contest summary" msgstr "" -#: judge/models/contest.py:121 judge/models/problem.py:147 +#: judge/models/contest.py:104 judge/models/problem.py:147 msgid "Plain-text, shown in meta description tag, e.g. for social media." msgstr "" -#: judge/models/contest.py:122 judge/models/profile.py:47 +#: judge/models/contest.py:105 judge/models/profile.py:47 msgid "access code" msgstr "" -#: judge/models/contest.py:123 +#: judge/models/contest.py:106 msgid "" "An optional code to prompt contestants before they are allowed to join the " "contest. Leave it blank to disable." msgstr "" -#: judge/models/contest.py:125 judge/models/problem.py:141 +#: judge/models/contest.py:108 judge/models/problem.py:141 msgid "personae non gratae" msgstr "" -#: judge/models/contest.py:126 +#: judge/models/contest.py:109 msgid "Bans the selected users from joining this contest." msgstr "" -#: judge/models/contest.py:127 +#: judge/models/contest.py:110 msgid "contest format" msgstr "" -#: judge/models/contest.py:128 +#: judge/models/contest.py:111 msgid "The contest format module to use." msgstr "" -#: judge/models/contest.py:129 +#: judge/models/contest.py:112 msgid "contest format configuration" msgstr "" -#: judge/models/contest.py:130 +#: judge/models/contest.py:113 msgid "" "A JSON object to serve as the configuration for the chosen contest format " "module. Leave empty to use None. Exact format depends on the contest format " "selected." msgstr "" -#: judge/models/contest.py:137 -msgid "precision points" -msgstr "" - -#: judge/models/contest.py:139 -msgid "Number of digits to round points to." -msgstr "" - -#: judge/models/contest.py:383 +#: judge/models/contest.py:239 msgid "See private contests" msgstr "" -#: judge/models/contest.py:384 +#: judge/models/contest.py:240 msgid "Edit own contests" msgstr "" -#: judge/models/contest.py:385 +#: judge/models/contest.py:241 msgid "Edit all contests" msgstr "" -#: judge/models/contest.py:386 +#: judge/models/contest.py:242 msgid "Clone contest" msgstr "" -#: judge/models/contest.py:387 templates/contest/moss.html:74 +#: judge/models/contest.py:243 templates/contest/moss.html:74 msgid "MOSS contest" msgstr "" -#: judge/models/contest.py:388 +#: judge/models/contest.py:244 msgid "Rate contests" msgstr "" -#: judge/models/contest.py:389 +#: judge/models/contest.py:245 msgid "Contest access codes" msgstr "" -#: judge/models/contest.py:390 +#: judge/models/contest.py:246 msgid "Create private contests" msgstr "" -#: judge/models/contest.py:391 -msgid "Change contest visibility" -msgstr "" - -#: judge/models/contest.py:392 -msgid "Edit contest problem label script" -msgstr "" - -#: judge/models/contest.py:394 judge/models/contest.py:492 -#: judge/models/contest.py:529 judge/models/contest.py:552 -#: judge/models/submission.py:84 +#: judge/models/contest.py:248 judge/models/contest.py:345 +#: judge/models/contest.py:382 judge/models/contest.py:404 +#: judge/models/submission.py:83 msgid "contest" msgstr "" -#: judge/models/contest.py:395 +#: judge/models/contest.py:249 msgid "contests" msgstr "" -#: judge/models/contest.py:402 +#: judge/models/contest.py:256 msgid "associated contest" msgstr "" -#: judge/models/contest.py:405 +#: judge/models/contest.py:259 msgid "score" msgstr "" -#: judge/models/contest.py:406 +#: judge/models/contest.py:260 msgid "cumulative time" msgstr "" -#: judge/models/contest.py:407 +#: judge/models/contest.py:261 msgid "is disqualified" msgstr "" -#: judge/models/contest.py:408 +#: judge/models/contest.py:262 msgid "Whether this participation is disqualified." msgstr "" -#: judge/models/contest.py:409 -msgid "tie-breaking field" -msgstr "" - -#: judge/models/contest.py:410 +#: judge/models/contest.py:263 msgid "virtual participation id" msgstr "" -#: judge/models/contest.py:411 +#: judge/models/contest.py:264 msgid "0 means non-virtual, otherwise the n-th virtual participation." msgstr "" -#: judge/models/contest.py:412 +#: judge/models/contest.py:265 msgid "contest format specific data" msgstr "" -#: judge/models/contest.py:478 +#: judge/models/contest.py:331 #, python-format msgid "%s spectating in %s" msgstr "" -#: judge/models/contest.py:480 +#: judge/models/contest.py:333 #, python-format msgid "%s in %s, v%d" msgstr "" -#: judge/models/contest.py:481 +#: judge/models/contest.py:334 #, python-format msgid "%s in %s" msgstr "" -#: judge/models/contest.py:484 +#: judge/models/contest.py:337 msgid "contest participation" msgstr "" -#: judge/models/contest.py:485 +#: judge/models/contest.py:338 msgid "contest participations" msgstr "" -#: judge/models/contest.py:491 judge/models/contest.py:513 -#: judge/models/contest.py:553 judge/models/problem.py:389 -#: judge/models/problem.py:394 judge/models/problem.py:412 -#: judge/models/problem_data.py:40 +#: judge/models/contest.py:344 judge/models/contest.py:366 +#: judge/models/contest.py:405 judge/models/problem.py:352 +#: judge/models/problem.py:357 judge/models/problem.py:375 +#: judge/models/problem_data.py:38 msgid "problem" msgstr "" -#: judge/models/contest.py:493 judge/models/contest.py:517 +#: judge/models/contest.py:346 judge/models/contest.py:370 #: judge/models/problem.py:129 msgid "points" msgstr "" -#: judge/models/contest.py:494 +#: judge/models/contest.py:347 msgid "partial" msgstr "" -#: judge/models/contest.py:495 judge/models/contest.py:518 +#: judge/models/contest.py:348 judge/models/contest.py:371 msgid "is pretested" msgstr "" -#: judge/models/contest.py:496 judge/models/interface.py:43 +#: judge/models/contest.py:349 judge/models/interface.py:43 msgid "order" msgstr "" -#: judge/models/contest.py:497 +#: judge/models/contest.py:350 msgid "0 to not show testcases, 1 to show" msgstr "" -#: judge/models/contest.py:498 +#: judge/models/contest.py:351 msgid "visible testcases" msgstr "" -#: judge/models/contest.py:499 +#: judge/models/contest.py:352 msgid "Maximum number of submissions for this problem, or 0 for no limit." msgstr "" -#: judge/models/contest.py:501 +#: judge/models/contest.py:354 msgid "Why include a problem you can't submit to?" msgstr "" -#: judge/models/contest.py:506 +#: judge/models/contest.py:359 msgid "contest problem" msgstr "" -#: judge/models/contest.py:507 +#: judge/models/contest.py:360 msgid "contest problems" msgstr "" -#: judge/models/contest.py:511 judge/models/submission.py:183 +#: judge/models/contest.py:364 judge/models/submission.py:181 msgid "submission" msgstr "" -#: judge/models/contest.py:515 judge/models/contest.py:530 +#: judge/models/contest.py:368 judge/models/contest.py:383 msgid "participation" msgstr "" -#: judge/models/contest.py:519 +#: judge/models/contest.py:372 msgid "Whether this submission was ran only on pretests." msgstr "" -#: judge/models/contest.py:523 +#: judge/models/contest.py:376 msgid "contest submission" msgstr "" -#: judge/models/contest.py:524 +#: judge/models/contest.py:377 msgid "contest submissions" msgstr "" -#: judge/models/contest.py:532 +#: judge/models/contest.py:385 msgid "rank" msgstr "" -#: judge/models/contest.py:533 +#: judge/models/contest.py:386 msgid "rating" msgstr "" -#: judge/models/contest.py:534 +#: judge/models/contest.py:387 msgid "volatility" msgstr "" -#: judge/models/contest.py:535 +#: judge/models/contest.py:388 msgid "last rated" msgstr "" -#: judge/models/contest.py:539 +#: judge/models/contest.py:392 msgid "contest rating" msgstr "" -#: judge/models/contest.py:540 +#: judge/models/contest.py:393 msgid "contest ratings" msgstr "" -#: judge/models/contest.py:560 +#: judge/models/contest.py:412 msgid "contest moss result" msgstr "" -#: judge/models/contest.py:561 +#: judge/models/contest.py:413 msgid "contest moss results" msgstr "" @@ -1176,7 +1088,7 @@ msgstr "" msgid "post title" msgstr "" -#: judge/models/interface.py:67 judge/models/problem.py:432 +#: judge/models/interface.py:67 judge/models/problem.py:395 msgid "authors" msgstr "" @@ -1184,7 +1096,7 @@ msgstr "" msgid "slug" msgstr "" -#: judge/models/interface.py:69 judge/models/problem.py:430 +#: judge/models/interface.py:69 judge/models/problem.py:393 msgid "public visibility" msgstr "" @@ -1208,19 +1120,15 @@ msgstr "" msgid "openGraph image" msgstr "" -#: judge/models/interface.py:76 -msgid "If private, only these organizations may see the blog post." -msgstr "" - -#: judge/models/interface.py:105 +#: judge/models/interface.py:91 msgid "Edit all posts" msgstr "" -#: judge/models/interface.py:107 +#: judge/models/interface.py:93 msgid "blog post" msgstr "" -#: judge/models/interface.py:108 +#: judge/models/interface.py:94 msgid "blog posts" msgstr "" @@ -1244,6 +1152,10 @@ msgstr "" msgid "message timestamp" msgstr "" +#: judge/models/message.py:16 +msgid "read" +msgstr "" + #: judge/models/message.py:20 msgid "messages in the thread" msgstr "" @@ -1380,7 +1292,7 @@ msgid "" "are supported." msgstr "" -#: judge/models/problem.py:123 judge/models/problem.py:417 +#: judge/models/problem.py:123 judge/models/problem.py:380 msgid "memory limit" msgstr "" @@ -1453,188 +1365,188 @@ msgstr "" msgid "If private, only these organizations may see the problem." msgstr "" -#: judge/models/problem.py:395 judge/models/problem.py:413 -#: judge/models/runtime.py:111 +#: judge/models/problem.py:358 judge/models/problem.py:376 +#: judge/models/runtime.py:108 msgid "language" msgstr "" -#: judge/models/problem.py:396 +#: judge/models/problem.py:359 msgid "translated name" msgstr "" -#: judge/models/problem.py:397 +#: judge/models/problem.py:360 msgid "translated description" msgstr "" -#: judge/models/problem.py:401 +#: judge/models/problem.py:364 msgid "problem translation" msgstr "" -#: judge/models/problem.py:402 +#: judge/models/problem.py:365 msgid "problem translations" msgstr "" -#: judge/models/problem.py:406 +#: judge/models/problem.py:369 msgid "clarified problem" msgstr "" -#: judge/models/problem.py:407 +#: judge/models/problem.py:370 msgid "clarification body" msgstr "" -#: judge/models/problem.py:408 +#: judge/models/problem.py:371 msgid "clarification timestamp" msgstr "" -#: judge/models/problem.py:423 +#: judge/models/problem.py:386 msgid "language-specific resource limit" msgstr "" -#: judge/models/problem.py:424 +#: judge/models/problem.py:387 msgid "language-specific resource limits" msgstr "" -#: judge/models/problem.py:428 +#: judge/models/problem.py:391 msgid "associated problem" msgstr "" -#: judge/models/problem.py:431 +#: judge/models/problem.py:394 msgid "publish date" msgstr "" -#: judge/models/problem.py:433 +#: judge/models/problem.py:396 msgid "editorial content" msgstr "" -#: judge/models/problem.py:449 +#: judge/models/problem.py:412 msgid "solution" msgstr "" -#: judge/models/problem.py:450 +#: judge/models/problem.py:413 msgid "solutions" msgstr "" -#: judge/models/problem_data.py:26 +#: judge/models/problem_data.py:24 msgid "Standard" msgstr "" -#: judge/models/problem_data.py:27 +#: judge/models/problem_data.py:25 msgid "Floats" msgstr "" -#: judge/models/problem_data.py:28 +#: judge/models/problem_data.py:26 msgid "Floats (absolute)" msgstr "" -#: judge/models/problem_data.py:29 +#: judge/models/problem_data.py:27 msgid "Floats (relative)" msgstr "" -#: judge/models/problem_data.py:30 +#: judge/models/problem_data.py:28 msgid "Non-trailing spaces" msgstr "" -#: judge/models/problem_data.py:31 +#: judge/models/problem_data.py:29 msgid "Unordered" msgstr "" -#: judge/models/problem_data.py:32 +#: judge/models/problem_data.py:30 msgid "Byte identical" msgstr "" -#: judge/models/problem_data.py:33 +#: judge/models/problem_data.py:31 msgid "Line-by-line" msgstr "" -#: judge/models/problem_data.py:34 +#: judge/models/problem_data.py:32 msgid "Custom checker (PY)" msgstr "" -#: judge/models/problem_data.py:35 +#: judge/models/problem_data.py:33 msgid "Custom validator (CPP)" msgstr "" -#: judge/models/problem_data.py:42 +#: judge/models/problem_data.py:40 msgid "data zip file" msgstr "" -#: judge/models/problem_data.py:44 +#: judge/models/problem_data.py:42 msgid "generator file" msgstr "" -#: judge/models/problem_data.py:46 judge/models/problem_data.py:121 +#: judge/models/problem_data.py:44 judge/models/problem_data.py:110 msgid "output prefix length" msgstr "" -#: judge/models/problem_data.py:47 judge/models/problem_data.py:122 +#: judge/models/problem_data.py:45 judge/models/problem_data.py:111 msgid "output limit length" msgstr "" -#: judge/models/problem_data.py:48 +#: judge/models/problem_data.py:46 msgid "init.yml generation feedback" msgstr "" -#: judge/models/problem_data.py:49 judge/models/problem_data.py:123 +#: judge/models/problem_data.py:47 judge/models/problem_data.py:112 msgid "checker" msgstr "" -#: judge/models/problem_data.py:50 judge/models/problem_data.py:124 +#: judge/models/problem_data.py:48 judge/models/problem_data.py:113 msgid "checker arguments" msgstr "" -#: judge/models/problem_data.py:51 judge/models/problem_data.py:125 +#: judge/models/problem_data.py:49 judge/models/problem_data.py:114 msgid "checker arguments as a JSON object" msgstr "" -#: judge/models/problem_data.py:52 +#: judge/models/problem_data.py:50 msgid "custom checker file" msgstr "" -#: judge/models/problem_data.py:58 +#: judge/models/problem_data.py:56 msgid "custom validator file" msgstr "" -#: judge/models/problem_data.py:108 +#: judge/models/problem_data.py:97 msgid "problem data set" msgstr "" -#: judge/models/problem_data.py:110 +#: judge/models/problem_data.py:99 msgid "case position" msgstr "" -#: judge/models/problem_data.py:111 +#: judge/models/problem_data.py:100 msgid "case type" msgstr "" -#: judge/models/problem_data.py:112 +#: judge/models/problem_data.py:101 msgid "Normal case" msgstr "" -#: judge/models/problem_data.py:113 +#: judge/models/problem_data.py:102 msgid "Batch start" msgstr "" -#: judge/models/problem_data.py:114 +#: judge/models/problem_data.py:103 msgid "Batch end" msgstr "" -#: judge/models/problem_data.py:116 +#: judge/models/problem_data.py:105 msgid "input file name" msgstr "" -#: judge/models/problem_data.py:117 +#: judge/models/problem_data.py:106 msgid "output file name" msgstr "" -#: judge/models/problem_data.py:118 +#: judge/models/problem_data.py:107 msgid "generator arguments" msgstr "" -#: judge/models/problem_data.py:119 +#: judge/models/problem_data.py:108 msgid "point value" msgstr "" -#: judge/models/problem_data.py:120 +#: judge/models/problem_data.py:109 msgid "case is pretest?" msgstr "" @@ -1707,7 +1619,7 @@ msgid "" msgstr "" #: judge/models/profile.py:76 judge/models/profile.py:93 -#: judge/models/profile.py:212 +#: judge/models/profile.py:192 msgid "organization" msgstr "" @@ -1803,31 +1715,31 @@ msgstr "" msgid "Notes for administrators regarding this user." msgstr "" -#: judge/models/profile.py:206 +#: judge/models/profile.py:186 msgid "user profile" msgstr "" -#: judge/models/profile.py:207 +#: judge/models/profile.py:187 msgid "user profiles" msgstr "" -#: judge/models/profile.py:214 +#: judge/models/profile.py:194 msgid "request time" msgstr "" -#: judge/models/profile.py:215 +#: judge/models/profile.py:195 msgid "state" msgstr "" -#: judge/models/profile.py:220 +#: judge/models/profile.py:200 msgid "reason" msgstr "" -#: judge/models/profile.py:223 +#: judge/models/profile.py:203 msgid "organization join request" msgstr "" -#: judge/models/profile.py:224 +#: judge/models/profile.py:204 msgid "organization join requests" msgstr "" @@ -1918,86 +1830,86 @@ msgstr "" msgid "The extension of source files, e.g., \"py\" or \"cpp\"." msgstr "" -#: judge/models/runtime.py:112 +#: judge/models/runtime.py:109 msgid "languages" msgstr "" -#: judge/models/runtime.py:116 +#: judge/models/runtime.py:113 msgid "language to which this runtime belongs" msgstr "" -#: judge/models/runtime.py:117 +#: judge/models/runtime.py:114 msgid "judge on which this runtime exists" msgstr "" -#: judge/models/runtime.py:118 +#: judge/models/runtime.py:115 msgid "runtime name" msgstr "" -#: judge/models/runtime.py:119 +#: judge/models/runtime.py:116 msgid "runtime version" msgstr "" -#: judge/models/runtime.py:120 +#: judge/models/runtime.py:117 msgid "order in which to display this runtime" msgstr "" -#: judge/models/runtime.py:124 +#: judge/models/runtime.py:121 msgid "Server name, hostname-style" msgstr "" -#: judge/models/runtime.py:125 +#: judge/models/runtime.py:122 msgid "time of creation" msgstr "" -#: judge/models/runtime.py:126 +#: judge/models/runtime.py:123 msgid "A key to authenticate this judge" msgstr "" -#: judge/models/runtime.py:127 +#: judge/models/runtime.py:124 msgid "authentication key" msgstr "" -#: judge/models/runtime.py:128 +#: judge/models/runtime.py:125 msgid "block judge" msgstr "" -#: judge/models/runtime.py:129 +#: judge/models/runtime.py:126 msgid "" "Whether this judge should be blocked from connecting, even if its key is " "correct." msgstr "" -#: judge/models/runtime.py:131 +#: judge/models/runtime.py:128 msgid "judge online status" msgstr "" -#: judge/models/runtime.py:132 +#: judge/models/runtime.py:129 msgid "judge start time" msgstr "" -#: judge/models/runtime.py:133 +#: judge/models/runtime.py:130 msgid "response time" msgstr "" -#: judge/models/runtime.py:134 +#: judge/models/runtime.py:131 msgid "system load" msgstr "" -#: judge/models/runtime.py:135 +#: judge/models/runtime.py:132 msgid "Load for the last minute, divided by processors to be fair." msgstr "" -#: judge/models/runtime.py:139 judge/models/runtime.py:179 +#: judge/models/runtime.py:136 judge/models/runtime.py:176 msgid "judges" msgstr "" -#: judge/models/runtime.py:178 +#: judge/models/runtime.py:175 msgid "judge" msgstr "" #: judge/models/submission.py:20 judge/models/submission.py:47 -#: judge/utils/problems.py:79 +#: judge/utils/problems.py:77 msgid "Accepted" msgstr "" @@ -2026,7 +1938,7 @@ msgid "Runtime Error" msgstr "" #: judge/models/submission.py:27 judge/models/submission.py:41 -#: judge/models/submission.py:55 judge/utils/problems.py:81 +#: judge/models/submission.py:55 judge/utils/problems.py:79 msgid "Compile Error" msgstr "" @@ -2067,15 +1979,15 @@ msgstr "" msgid "submission time" msgstr "" -#: judge/models/submission.py:67 judge/models/submission.py:203 +#: judge/models/submission.py:67 judge/models/submission.py:201 msgid "execution time" msgstr "" -#: judge/models/submission.py:68 judge/models/submission.py:204 +#: judge/models/submission.py:68 judge/models/submission.py:202 msgid "memory usage" msgstr "" -#: judge/models/submission.py:69 judge/models/submission.py:205 +#: judge/models/submission.py:69 judge/models/submission.py:203 msgid "points granted" msgstr "" @@ -2112,62 +2024,58 @@ msgid "judged on" msgstr "" #: judge/models/submission.py:81 -msgid "submission judge time" -msgstr "" - -#: judge/models/submission.py:82 msgid "was rejudged by admin" msgstr "" -#: judge/models/submission.py:83 +#: judge/models/submission.py:82 msgid "was ran on pretests only" msgstr "" -#: judge/models/submission.py:184 templates/contest/moss.html:58 +#: judge/models/submission.py:182 templates/contest/moss.html:58 msgid "submissions" msgstr "" -#: judge/models/submission.py:188 judge/models/submission.py:199 +#: judge/models/submission.py:186 judge/models/submission.py:197 msgid "associated submission" msgstr "" -#: judge/models/submission.py:190 +#: judge/models/submission.py:188 msgid "source code" msgstr "" -#: judge/models/submission.py:201 +#: judge/models/submission.py:199 msgid "test case ID" msgstr "" -#: judge/models/submission.py:202 +#: judge/models/submission.py:200 msgid "status flag" msgstr "" -#: judge/models/submission.py:206 +#: judge/models/submission.py:204 msgid "points possible" msgstr "" -#: judge/models/submission.py:207 +#: judge/models/submission.py:205 msgid "batch number" msgstr "" -#: judge/models/submission.py:208 +#: judge/models/submission.py:206 msgid "judging feedback" msgstr "" -#: judge/models/submission.py:209 +#: judge/models/submission.py:207 msgid "extended judging feedback" msgstr "" -#: judge/models/submission.py:210 +#: judge/models/submission.py:208 msgid "program output" msgstr "" -#: judge/models/submission.py:218 +#: judge/models/submission.py:216 msgid "submission test case" msgstr "" -#: judge/models/submission.py:219 +#: judge/models/submission.py:217 msgid "submission test cases" msgstr "" @@ -2219,21 +2127,12 @@ msgstr "" msgid "message time" msgstr "" -#: judge/pdf_problems.py:147 judge/pdf_problems.py:199 -#: judge/pdf_problems.py:259 +#: judge/pdf_problems.py:134 judge/pdf_problems.py:186 +#: judge/pdf_problems.py:246 msgid "Page [page] of [topage]" msgstr "" -#: judge/pdf_problems.py:280 -#, python-format -msgid "Page %s of %s" -msgstr "" - -#: judge/tasks/contest.py:19 -msgid "Recalculating contest scores" -msgstr "" - -#: judge/tasks/contest.py:40 +#: judge/tasks/moss.py:25 msgid "Running MOSS" msgstr "" @@ -2245,60 +2144,60 @@ msgstr "" msgid "Recalculating user points" msgstr "" -#: judge/utils/problem_data.py:70 +#: judge/utils/problem_data.py:68 msgid "Empty batches not allowed." msgstr "" -#: judge/utils/problem_data.py:78 judge/utils/problem_data.py:99 +#: judge/utils/problem_data.py:76 judge/utils/problem_data.py:97 msgid "How did you corrupt the custom checker path?" msgstr "" -#: judge/utils/problem_data.py:120 +#: judge/utils/problem_data.py:118 #, python-format msgid "Points must be defined for non-batch case #%d." msgstr "" -#: judge/utils/problem_data.py:125 +#: judge/utils/problem_data.py:123 #, python-format msgid "Input file for case %d does not exist: %s" msgstr "" -#: judge/utils/problem_data.py:128 +#: judge/utils/problem_data.py:126 #, python-format msgid "Output file for case %d does not exist: %s" msgstr "" -#: judge/utils/problem_data.py:153 +#: judge/utils/problem_data.py:151 #, python-format msgid "Batch start case #%d requires points." msgstr "" -#: judge/utils/problem_data.py:174 +#: judge/utils/problem_data.py:172 #, python-format msgid "Attempt to end batch outside of one in case #%d" msgstr "" -#: judge/utils/problem_data.py:192 +#: judge/utils/problem_data.py:190 msgid "How did you corrupt the zip path?" msgstr "" -#: judge/utils/problem_data.py:198 +#: judge/utils/problem_data.py:196 msgid "How did you corrupt the generator path?" msgstr "" -#: judge/utils/problems.py:80 +#: judge/utils/problems.py:78 msgid "Wrong" msgstr "" -#: judge/utils/problems.py:82 +#: judge/utils/problems.py:80 msgid "Timeout" msgstr "" -#: judge/utils/problems.py:83 +#: judge/utils/problems.py:81 msgid "Error" msgstr "" -#: judge/utils/problems.py:94 +#: judge/utils/problems.py:92 msgid "Can't pass both queryset and keyword filters" msgstr "" @@ -2347,8 +2246,7 @@ msgctxt "hours and minutes" msgid "%h:%m" msgstr "" -#: judge/views/about.py:7 templates/organization/home.html:112 -#: templates/user/user-about.html:83 templates/user/user-tabs.html:4 +#: judge/views/about.py:7 templates/user/user-about.html:33 msgid "About" msgstr "" @@ -2356,165 +2254,156 @@ msgstr "" msgid "Custom Checker Sample" msgstr "" -#: judge/views/blog.py:45 +#: judge/views/blog.py:38 #, python-format msgid "Page %d of Posts" msgstr "" -#: judge/views/comment.py:28 +#: judge/views/comment.py:27 msgid "Messing around, are we?" msgstr "" -#: judge/views/comment.py:37 +#: judge/views/comment.py:36 msgid "You must solve at least one problem before you can vote." msgstr "" -#: judge/views/comment.py:64 +#: judge/views/comment.py:63 msgid "You already voted." msgstr "" -#: judge/views/comment.py:126 judge/views/organization.py:344 +#: judge/views/comment.py:120 judge/views/organization.py:299 msgid "Edited from site" msgstr "" -#: judge/views/comment.py:147 +#: judge/views/comment.py:141 msgid "Editing comment" msgstr "" -#: judge/views/contests.py:57 judge/views/contests.py:247 -#: judge/views/contests.py:250 judge/views/contests.py:424 +#: judge/views/contests.py:55 judge/views/contests.py:215 +#: judge/views/contests.py:218 judge/views/contests.py:389 msgid "No such contest" msgstr "" -#: judge/views/contests.py:58 judge/views/contests.py:248 +#: judge/views/contests.py:56 judge/views/contests.py:216 #, python-format msgid "Could not find a contest with the key \"%s\"." msgstr "" -#: judge/views/contests.py:71 +#: judge/views/contests.py:81 msgid "Contests" msgstr "" -#: judge/views/contests.py:251 +#: judge/views/contests.py:219 msgid "Could not find such contest." msgstr "" -#: judge/views/contests.py:254 +#: judge/views/contests.py:222 #, python-format msgid "Access to contest \"%s\" denied" msgstr "" -#: judge/views/contests.py:278 +#: judge/views/contests.py:246 msgid "Clone Contest" msgstr "" -#: judge/views/contests.py:343 +#: judge/views/contests.py:309 msgid "Contest not ongoing" msgstr "" -#: judge/views/contests.py:344 +#: judge/views/contests.py:310 #, python-format msgid "\"%s\" is not currently ongoing." msgstr "" -#: judge/views/contests.py:348 +#: judge/views/contests.py:314 msgid "Already in contest" msgstr "" -#: judge/views/contests.py:349 +#: judge/views/contests.py:315 #, python-format msgid "You are already in a contest: \"%s\"." msgstr "" -#: judge/views/contests.py:352 +#: judge/views/contests.py:318 msgid "Banned from joining" msgstr "" -#: judge/views/contests.py:353 +#: judge/views/contests.py:319 msgid "" "You have been declared persona non grata for this contest. You are " "permanently barred from joining this contest." msgstr "" -#: judge/views/contests.py:414 +#: judge/views/contests.py:379 #, python-format msgid "Enter access code for \"%s\"" msgstr "" -#: judge/views/contests.py:425 +#: judge/views/contests.py:390 #, python-format msgid "You are not in contest \"%s\"." msgstr "" -#: judge/views/contests.py:444 +#: judge/views/contests.py:409 msgid "ContestCalendar requires integer year and month" msgstr "" -#: judge/views/contests.py:484 +#: judge/views/contests.py:449 #, python-format msgid "Contests in %(month)s" msgstr "" -#: judge/views/contests.py:484 +#: judge/views/contests.py:449 msgid "F Y" msgstr "" -#: judge/views/contests.py:532 +#: judge/views/contests.py:496 #, python-format msgid "%s Statistics" msgstr "" -#: judge/views/contests.py:717 +#: judge/views/contests.py:601 +msgid "???" +msgstr "" + +#: judge/views/contests.py:664 #, python-format msgid "%s Rankings" msgstr "" -#: judge/views/contests.py:725 -msgid "???" -msgstr "" - -#: judge/views/contests.py:741 +#: judge/views/contests.py:680 #, python-format msgid "Your participation in %s" msgstr "" -#: judge/views/contests.py:742 +#: judge/views/contests.py:681 #, python-format msgid "%s's participation in %s" msgstr "" -#: judge/views/contests.py:749 +#: judge/views/contests.py:685 msgid "Live" msgstr "" -#: judge/views/contests.py:761 templates/contest/contest-tabs.html:13 +#: judge/views/contests.py:697 msgid "Participation" msgstr "" -#: judge/views/contests.py:808 +#: judge/views/contests.py:743 #, python-format msgid "%s MOSS Results" msgstr "" -#: judge/views/contests.py:835 +#: judge/views/contests.py:770 #, python-format msgid "Running MOSS for %s..." msgstr "" -#: judge/views/contests.py:858 +#: judge/views/contests.py:793 #, python-format msgid "Contest tag: %s" msgstr "" -#: judge/views/contests.py:868 judge/views/ticket.py:57 -msgid "Issue description" -msgstr "" - -#: judge/views/contests.py:911 -#, python-format -msgid "New clarification for %s" -msgstr "" - #: judge/views/error.py:14 msgid "404 error" msgstr "" @@ -2535,83 +2424,76 @@ msgid "corrupt page %s" msgstr "" #: judge/views/language.py:12 templates/status/judge-status-table.html:9 -#: templates/status/status-tabs.html:5 msgid "Runtimes" msgstr "" -#: judge/views/notification.py:40 -#, python-format -msgid "Notifications (%d unseen)" -msgstr "" - -#: judge/views/organization.py:59 judge/views/organization.py:62 +#: judge/views/organization.py:44 judge/views/organization.py:47 msgid "No such organization" msgstr "" -#: judge/views/organization.py:60 +#: judge/views/organization.py:45 #, python-format msgid "Could not find an organization with the key \"%s\"." msgstr "" -#: judge/views/organization.py:63 +#: judge/views/organization.py:48 msgid "Could not find such organization." msgstr "" -#: judge/views/organization.py:79 judge/views/register.py:34 -#: templates/organization/list.html:32 templates/user/import/table_csv.html:9 -#: templates/user/user-list-tabs.html:6 +#: judge/views/organization.py:72 judge/views/register.py:34 +#: templates/organization/list.html:15 msgid "Organizations" msgstr "" -#: judge/views/organization.py:130 +#: judge/views/organization.py:93 #, python-format msgid "%s Members" msgstr "" -#: judge/views/organization.py:159 judge/views/organization.py:162 -#: judge/views/organization.py:167 +#: judge/views/organization.py:118 judge/views/organization.py:121 +#: judge/views/organization.py:126 msgid "Joining organization" msgstr "" -#: judge/views/organization.py:159 +#: judge/views/organization.py:118 msgid "You are already in the organization." msgstr "" -#: judge/views/organization.py:162 +#: judge/views/organization.py:121 msgid "This organization is not open." msgstr "" -#: judge/views/organization.py:179 +#: judge/views/organization.py:138 msgid "Leaving organization" msgstr "" -#: judge/views/organization.py:179 +#: judge/views/organization.py:138 #, python-format msgid "You are not in \"%s\"." msgstr "" -#: judge/views/organization.py:203 +#: judge/views/organization.py:162 #, python-format msgid "Request to join %s" msgstr "" -#: judge/views/organization.py:221 +#: judge/views/organization.py:180 msgid "Join request detail" msgstr "" -#: judge/views/organization.py:254 +#: judge/views/organization.py:209 #, python-format msgid "Managing join requests for %s" msgstr "" -#: judge/views/organization.py:285 +#: judge/views/organization.py:240 #, python-format msgid "" "Your organization can only receive %d more members. You cannot approve %d " "users." msgstr "" -#: judge/views/organization.py:297 +#: judge/views/organization.py:252 #, python-format msgid "Approved %d user." msgid_plural "Approved %d users." @@ -2620,7 +2502,7 @@ msgstr[1] "" msgstr[2] "" msgstr[3] "" -#: judge/views/organization.py:298 +#: judge/views/organization.py:253 #, python-format msgid "Rejected %d user." msgid_plural "Rejected %d users." @@ -2629,32 +2511,32 @@ msgstr[1] "" msgstr[2] "" msgstr[3] "" -#: judge/views/organization.py:328 +#: judge/views/organization.py:283 #, python-format msgid "Editing %s" msgstr "" -#: judge/views/organization.py:352 judge/views/organization.py:360 +#: judge/views/organization.py:307 judge/views/organization.py:315 msgid "Can't edit organization" msgstr "" -#: judge/views/organization.py:353 +#: judge/views/organization.py:308 msgid "You are not allowed to edit this organization." msgstr "" -#: judge/views/organization.py:361 +#: judge/views/organization.py:316 msgid "You are not allowed to kick people from this organization." msgstr "" -#: judge/views/organization.py:366 judge/views/organization.py:370 +#: judge/views/organization.py:321 judge/views/organization.py:325 msgid "Can't kick user" msgstr "" -#: judge/views/organization.py:367 +#: judge/views/organization.py:322 msgid "The user you are trying to kick does not exist!" msgstr "" -#: judge/views/organization.py:371 +#: judge/views/organization.py:326 #, python-format msgid "The user you are trying to kick is not in organization: %s." msgstr "" @@ -2678,36 +2560,35 @@ msgstr "" msgid "Editorial for {0}" msgstr "" -#: judge/views/problem.py:285 templates/contest/contest.html:79 -#: templates/user/user-about.html:28 templates/user/user-tabs.html:5 -#: templates/user/users-table.html:31 +#: judge/views/problem.py:286 templates/contest/contest.html:79 +#: templates/user/users-table.html:23 msgid "Problems" msgstr "" -#: judge/views/problem.py:585 +#: judge/views/problem.py:547 msgid "Banned from submitting" msgstr "" -#: judge/views/problem.py:586 +#: judge/views/problem.py:548 msgid "" "You have been declared persona non grata for this problem. You are " "permanently barred from submitting this problem." msgstr "" -#: judge/views/problem.py:600 +#: judge/views/problem.py:562 msgid "Too many submissions" msgstr "" -#: judge/views/problem.py:601 +#: judge/views/problem.py:563 msgid "You have exceeded the submission limit for this problem." msgstr "" -#: judge/views/problem.py:661 judge/views/problem.py:664 +#: judge/views/problem.py:633 judge/views/problem.py:636 #, python-format msgid "Submit to %(problem)s" msgstr "" -#: judge/views/problem.py:679 +#: judge/views/problem.py:652 msgid "Clone Problem" msgstr "" @@ -2748,22 +2629,22 @@ msgstr "" msgid "Generated init.yml for %s" msgstr "" -#: judge/views/problem_manage.py:52 judge/views/problem_manage.py:55 +#: judge/views/problem_manage.py:50 judge/views/problem_manage.py:53 #, python-format msgid "Managing submissions for %s" msgstr "" -#: judge/views/problem_manage.py:97 +#: judge/views/problem_manage.py:95 #, python-format msgid "Rejudging selected submissions for %s..." msgstr "" -#: judge/views/problem_manage.py:141 +#: judge/views/problem_manage.py:110 #, python-format msgid "Rescoring all submissions for %s..." msgstr "" -#: judge/views/problem_manage.py:150 +#: judge/views/problem_manage.py:119 #, python-format msgid "Successfully scheduled %d submission for rejudging." msgid_plural "Successfully scheduled %d submissions for rejudging." @@ -2814,24 +2695,24 @@ msgstr "" msgid "Subscribe to newsletter?" msgstr "" -#: judge/views/register.py:55 +#: judge/views/register.py:45 #, python-format msgid "" "The email address \"%s\" is already taken. Only one registration is allowed " "per address." msgstr "" -#: judge/views/register.py:61 +#: judge/views/register.py:51 msgid "" "Your email provider is not allowed due to history of abuse. Please use a " "reputable email provider." msgstr "" -#: judge/views/register.py:67 judge/views/register.py:105 +#: judge/views/register.py:57 judge/views/register.py:95 msgid "Registration" msgstr "" -#: judge/views/register.py:116 +#: judge/views/register.py:106 msgid "Authentication failure" msgstr "" @@ -2847,100 +2728,104 @@ msgstr "" msgid "Version matrix" msgstr "" -#: judge/views/submission.py:84 judge/views/submission.py:91 +#: judge/views/submission.py:83 judge/views/submission.py:90 #, python-format msgid "Submission of %(problem)s by %(user)s" msgstr "" -#: judge/views/submission.py:244 judge/views/submission.py:245 -#: templates/problem/problem.html:167 +#: judge/views/submission.py:227 judge/views/submission.py:228 +#: templates/problem/problem.html:127 msgid "All submissions" msgstr "" -#: judge/views/submission.py:404 +#: judge/views/submission.py:384 msgid "All my submissions" msgstr "" -#: judge/views/submission.py:405 +#: judge/views/submission.py:385 #, python-format msgid "All submissions by %s" msgstr "" -#: judge/views/submission.py:436 +#: judge/views/submission.py:416 #, python-format msgid "All submissions for %s" msgstr "" -#: judge/views/submission.py:455 +#: judge/views/submission.py:435 msgid "Must pass a problem" msgstr "" -#: judge/views/submission.py:501 +#: judge/views/submission.py:481 #, python-format msgid "My submissions for %(problem)s" msgstr "" -#: judge/views/submission.py:502 +#: judge/views/submission.py:482 #, python-format msgid "%(user)s's submissions for %(problem)s" msgstr "" -#: judge/views/submission.py:603 +#: judge/views/submission.py:583 msgid "Must pass a contest" msgstr "" -#: judge/views/submission.py:622 +#: judge/views/submission.py:602 #, python-brace-format msgid "" "{0}'s submissions for {2} in {4}" msgstr "" -#: judge/views/submission.py:629 +#: judge/views/submission.py:609 #, python-brace-format msgid "" "{0}'s submissions for problem {2} in {3}" "" msgstr "" -#: judge/views/ticket.py:50 judge/views/ticket.py:56 +#: judge/views/ticket.py:33 judge/views/ticket.py:39 msgid "Ticket title" msgstr "" -#: judge/views/ticket.py:107 judge/views/ticket.py:110 +#: judge/views/ticket.py:40 +msgid "Issue description" +msgstr "" + +#: judge/views/ticket.py:85 judge/views/ticket.py:88 #, python-format msgid "New ticket for %s" msgstr "" -#: judge/views/ticket.py:170 +#: judge/views/ticket.py:142 #, python-format msgid "%(title)s - Ticket %(id)d" msgstr "" -#: judge/views/ticket.py:279 +#: judge/views/ticket.py:251 #, python-format msgid "Tickets - Page %(number)d of %(total)d" msgstr "" -#: judge/views/ticket.py:328 +#: judge/views/ticket.py:300 #, python-format msgid "New Ticket: %s" msgstr "" -#: judge/views/ticket.py:329 +#: judge/views/ticket.py:301 #, python-format msgid "#%(id)d, assigned to: %(users)s" msgstr "" -#: judge/views/ticket.py:331 +#: judge/views/ticket.py:303 msgid ", " msgstr "" -#: judge/views/ticket.py:331 +#: judge/views/ticket.py:303 msgid "no one" msgstr "" -#: judge/views/ticket.py:351 +#: judge/views/ticket.py:323 #, python-format msgid "New Ticket Message For: %s" msgstr "" @@ -2957,50 +2842,41 @@ msgstr "" msgid "Perform Two Factor Authentication" msgstr "" -#: judge/views/user.py:74 +#: judge/views/user.py:68 msgid "No such user" msgstr "" -#: judge/views/user.py:74 +#: judge/views/user.py:68 #, python-format msgid "No user handle \"%s\"." msgstr "" -#: judge/views/user.py:78 +#: judge/views/user.py:72 msgid "My account" msgstr "" -#: judge/views/user.py:79 +#: judge/views/user.py:73 #, python-format msgid "User %s" msgstr "" -#: judge/views/user.py:148 -msgid "M j, Y" -msgstr "" - -#: judge/views/user.py:171 +#: judge/views/user.py:136 msgid "M j, Y, G:i" msgstr "" -#: judge/views/user.py:290 +#: judge/views/user.py:221 msgid "Updated on site" msgstr "" -#: judge/views/user.py:323 templates/admin/auth/user/change_form.html:14 -#: templates/admin/auth/user/change_form.html:17 templates/base.html:238 -#: templates/user/user-tabs.html:10 +#: judge/views/user.py:254 templates/admin/auth/user/change_form.html:14 +#: templates/admin/auth/user/change_form.html:17 templates/base.html:224 msgid "Edit profile" msgstr "" -#: judge/views/user.py:332 templates/user/user-list-tabs.html:4 +#: judge/views/user.py:263 msgid "Leaderboard" msgstr "" -#: judge/views/user.py:407 -msgid "Import Users" -msgstr "" - #: judge/views/widgets.py:48 judge/views/widgets.py:58 #, python-format msgid "Invalid upstream data: %s" @@ -3038,7 +2914,7 @@ msgid "View Submissions" msgstr "" #: templates/admin/judge/problem/change_form.html:17 -#: templates/user/user-base.html:112 +#: templates/user/user-base.html:61 msgid "View submissions" msgstr "" @@ -3053,145 +2929,90 @@ msgstr "" msgid "Rejudge" msgstr "" -#: templates/base.html:230 -#, python-format -msgid "Hello, %(username)s." -msgstr "" - -#: templates/base.html:236 templates/comments/list.html:89 -#: templates/contest/contest-list-tabs.html:24 -#: templates/contest/ranking-table.html:53 -#: templates/problem/problem-list-tabs.html:6 +#: templates/base.html:222 templates/comments/list.html:89 +#: templates/contest/ranking-table.html:39 #: templates/submission/info-base.html:12 -#: templates/submission/submission-list-tabs.html:15 msgid "Admin" msgstr "" -#: templates/base.html:245 +#: templates/base.html:231 msgid "Log out" msgstr "" -#: templates/base.html:254 +#: templates/base.html:240 #: templates/registration/password_reset_complete.html:4 msgid "Log in" msgstr "" -#: templates/base.html:255 templates/registration/registration_form.html:177 +#: templates/base.html:241 templates/registration/registration_form.html:177 msgid "or" msgstr "" -#: templates/base.html:256 +#: templates/base.html:242 msgid "Sign up" msgstr "" -#: templates/base.html:271 +#: templates/base.html:254 msgid "spectating" msgstr "" -#: templates/base.html:284 +#: templates/base.html:267 msgid "This site works best with JavaScript enabled." msgstr "" -#: templates/blog/blog.html:13 templates/comments/list.html:68 -#: templates/comments/list.html:83 templates/contest/contest-tabs.html:23 -#: templates/contest/tag-title.html:9 templates/flatpages/admin_link.html:3 -#: templates/license.html:10 templates/problem/editorial.html:14 +#: templates/blog/content.html:13 templates/comments/list.html:68 +#: templates/comments/list.html:83 templates/contest/tag-title.html:9 +#: templates/flatpages/admin_link.html:3 templates/license.html:10 +#: templates/problem/editorial.html:14 msgid "Edit" msgstr "" -#: templates/blog/blog.html:26 -#, python-format -msgid "" -"\n" -" posted on %(time)s\n" -" " -msgstr "" - -#: templates/blog/content.html:10 -#, python-brace-format -msgid "posted on {time}" -msgstr "" - -#: templates/blog/dashboard.html:21 -#, python-format -msgid "" -"\n" -" on %(time)s\n" -" " -msgstr "" - -#: templates/blog/list.html:93 +#: templates/blog/list.html:85 msgid "Blog" msgstr "" -#: templates/blog/list.html:95 +#: templates/blog/list.html:87 msgid "Events" msgstr "" -#: templates/blog/list.html:100 +#: templates/blog/list.html:92 msgid "News" msgstr "" -#: templates/blog/list.html:115 templates/problem/list.html:347 -#: templates/problem/problem.html:361 +#: templates/blog/list.html:130 templates/problem/problem.html:310 msgid "Clarifications" msgstr "" -#: templates/blog/list.html:121 -msgid "Add" -msgstr "" - -#: templates/blog/list.html:140 templates/problem/list.html:369 -#: templates/problem/problem.html:372 +#: templates/blog/list.html:146 templates/problem/problem.html:321 msgid "No clarifications have been made at this time." msgstr "" -#: templates/blog/list.html:148 +#: templates/blog/list.html:154 msgid "Ongoing contests" msgstr "" -#: templates/blog/list.html:166 +#: templates/blog/list.html:172 msgid "Upcoming contests" msgstr "" -#: templates/blog/list.html:184 -msgid "My open tickets" -msgstr "" - -#: templates/blog/list.html:206 -msgid "New tickets" -msgstr "" - -#: templates/blog/list.html:227 -msgid "New problems" -msgstr "" - -#: templates/blog/list.html:244 +#: templates/blog/list.html:189 msgid "Comment stream" msgstr "" -#: templates/chat/chat.html:305 -msgid "Chat" +#: templates/blog/list.html:208 +msgid "New problems" msgstr "" -#: templates/chat/chat.html:307 templates/chat/chat.html:314 -msgid "Online Users" +#: templates/blog/list.html:225 +msgid "My open tickets" msgstr "" -#: templates/chat/chat.html:315 -msgid "Refresh" +#: templates/blog/list.html:246 +msgid "New tickets" msgstr "" -#: templates/chat/chat.html:333 -msgid "Emoji" -msgstr "" - -#: templates/chat/chat.html:334 -msgid "Enter your message" -msgstr "" - -#: templates/chat/message.html:20 -msgid "Delete" +#: templates/chat/chat.html:167 +msgid "Your message" msgstr "" #: templates/comments/list.html:2 @@ -3202,21 +3023,11 @@ msgstr "" msgid "Please login to vote" msgstr "" -#: templates/comments/list.html:40 -#, python-brace-format -msgid "commented on {time}" -msgstr "" - -#: templates/comments/list.html:49 -#, python-format -msgid "edit %(edits)s" -msgstr "" - -#: templates/comments/list.html:51 templates/comments/media-js.html:92 +#: templates/comments/list.html:51 templates/comments/media-js.html:77 msgid "edited" msgstr "" -#: templates/comments/list.html:60 templates/notification/list.html:14 +#: templates/comments/list.html:60 msgid "Link" msgstr "" @@ -3224,52 +3035,36 @@ msgstr "" msgid "Reply" msgstr "" -#: templates/comments/list.html:86 templates/contest/list.html:91 -#: templates/contest/list.html:95 templates/contest/list.html:280 +#: templates/comments/list.html:86 msgid "Hide" msgstr "" -#: templates/comments/list.html:101 -#, python-format -msgid "" -"\n" -" This comment is hidden due " -"to too much negative feedback.\n" -" Click here to view it.\n" -" " -msgstr "" - -#: templates/comments/list.html:121 +#: templates/comments/list.html:120 msgid "There are no comments at the moment." msgstr "" -#: templates/comments/list.html:127 +#: templates/comments/list.html:126 msgid "New comment" msgstr "" -#: templates/comments/list.html:141 +#: templates/comments/list.html:140 msgid "Invalid comment body." msgstr "" -#: templates/comments/list.html:149 +#: templates/comments/list.html:148 msgid "Post!" msgstr "" -#: templates/comments/list.html:157 +#: templates/comments/list.html:156 msgid "Comments are disabled on this page." msgstr "" -#: templates/comments/media-js.html:38 -msgid "Replying to comment" -msgstr "" - -#: templates/comments/media-js.html:87 +#: templates/comments/media-js.html:72 #, python-brace-format msgid "edit {edits}" msgstr "" -#: templates/comments/media-js.html:90 +#: templates/comments/media-js.html:75 msgid "original" msgstr "" @@ -3313,11 +3108,6 @@ msgstr "" msgid "Saturday" msgstr "" -#: templates/contest/clarification.html:52 templates/organization/new.html:10 -#: templates/ticket/new.html:38 -msgid "Create" -msgstr "" - #: templates/contest/clone.html:37 msgid "Enter a new key for the cloned contest:" msgstr "" @@ -3338,173 +3128,97 @@ msgstr "" msgid "Next" msgstr "" -#: templates/contest/contest-list-tabs.html:21 -#: templates/problem/problem-list-tabs.html:5 -msgid "List" -msgstr "" - -#: templates/contest/contest-list-tabs.html:22 -msgid "Calendar" -msgstr "" - -#: templates/contest/contest-tabs.html:4 templates/organization/home.html:105 -msgid "Info" -msgstr "" - -#: templates/contest/contest-tabs.html:6 templates/stats/base.html:9 -#: templates/submission/list.html:339 -msgid "Statistics" -msgstr "" - -#: templates/contest/contest-tabs.html:11 -msgid "Rankings" -msgstr "" - -#: templates/contest/contest-tabs.html:16 -msgid "Hidden Rankings" -msgstr "" - -#: templates/contest/contest-tabs.html:21 -msgid "MOSS" -msgstr "" - -#: templates/contest/contest-tabs.html:26 -msgid "Clone" -msgstr "" - -#: templates/contest/contest-tabs.html:38 -#: templates/contest/contest-tabs.html:58 +#: templates/contest/contest-tabs.html:37 msgid "Leave contest" msgstr "" -#: templates/contest/contest-tabs.html:45 templates/contest/list.html:388 +#: templates/contest/contest-tabs.html:44 templates/contest/list.html:293 msgid "Virtual join" msgstr "" -#: templates/contest/contest-tabs.html:56 -msgid "Stop spectating" -msgstr "" - -#: templates/contest/contest-tabs.html:65 +#: templates/contest/contest-tabs.html:64 msgid "Spectate contest" msgstr "" -#: templates/contest/contest-tabs.html:72 +#: templates/contest/contest-tabs.html:70 +#: templates/contest/contest-tabs.html:76 msgid "Join contest" msgstr "" -#: templates/contest/contest-tabs.html:81 +#: templates/contest/contest-tabs.html:85 msgid "Login to participate" msgstr "" -#: templates/contest/contest.html:37 -msgid "Participating virtually." -msgstr "" - -#: templates/contest/contest.html:43 -msgid "Contest is over." -msgstr "" - #: templates/contest/contest.html:59 templates/contest/contest.html:63 msgid "F j, Y, G:i T" msgstr "" -#: templates/contest/contest.html:59 -#, python-format -msgid "" -"%(time_limit)s window between %(start_time)s and " -"%(end_time)s" -msgstr "" - -#: templates/contest/contest.html:63 -#, python-format -msgid "%(length)s long starting on %(start_time)s" -msgstr "" - #: templates/contest/contest.html:85 msgid "AC Rate" msgstr "" -#: templates/contest/contest.html:86 templates/contest/list.html:237 -#: templates/contest/list.html:289 templates/contest/list.html:366 -#: templates/problem/list.html:223 templates/problem/list.html:254 +#: templates/contest/contest.html:86 templates/contest/list.html:153 +#: templates/contest/list.html:195 templates/contest/list.html:271 +#: templates/problem/list.html:212 templates/problem/list.html:238 msgid "Users" msgstr "" -#: templates/contest/contest.html:111 templates/problem/list.html:330 +#: templates/contest/contest.html:111 msgid "Editorial" msgstr "" -#: templates/contest/list.html:83 templates/contest/media-js.html:9 +#: templates/contest/list.html:31 templates/contest/media-js.html:9 msgid "Are you sure you want to join?" msgstr "" -#: templates/contest/list.html:84 +#: templates/contest/list.html:32 msgid "" "Joining a contest for the first time starts your timer, after which it " "becomes unstoppable." msgstr "" -#: templates/contest/list.html:92 templates/contest/list.html:278 -msgid "Show" -msgstr "" - -#: templates/contest/list.html:102 templates/problem/list.html:68 -#, fuzzy -#| msgid "Organization" -msgid "Organizations..." -msgstr "Organizacja" - -#: templates/contest/list.html:135 +#: templates/contest/list.html:65 msgid "hidden" msgstr "" -#: templates/contest/list.html:140 +#: templates/contest/list.html:70 msgid "private" msgstr "" -#: templates/contest/list.html:154 +#: templates/contest/list.html:84 msgid "rated" msgstr "" -#: templates/contest/list.html:202 +#: templates/contest/list.html:132 msgid "Spectate" msgstr "" -#: templates/contest/list.html:208 +#: templates/contest/list.html:138 msgid "Join" msgstr "" -#: templates/contest/list.html:220 -msgid "Search contests..." -msgstr "" - -#: templates/contest/list.html:229 -msgid "Search" -msgstr "" - -#: templates/contest/list.html:232 +#: templates/contest/list.html:148 msgid "Active Contests" msgstr "" -#: templates/contest/list.html:236 templates/contest/list.html:288 -#: templates/contest/list.html:327 templates/contest/list.html:365 +#: templates/contest/list.html:152 templates/contest/list.html:194 +#: templates/contest/list.html:232 templates/contest/list.html:270 msgid "Contest" msgstr "" -#: templates/contest/list.html:275 +#: templates/contest/list.html:190 msgid "Ongoing Contests" msgstr "" -#: templates/contest/list.html:322 +#: templates/contest/list.html:227 msgid "Upcoming Contests" msgstr "" -#: templates/contest/list.html:350 +#: templates/contest/list.html:255 msgid "There are no scheduled contests at this time." msgstr "" -#: templates/contest/list.html:356 +#: templates/contest/list.html:261 msgid "Past Contests" msgstr "" @@ -3555,73 +3269,49 @@ msgstr "" msgid "Only the following organizations may access this contest:" msgstr "" -#: templates/contest/ranking-table.html:9 templates/problem/search-form.html:35 +#: templates/contest/ranking-table.html:7 msgid "Organization" msgstr "Organizacja" -#: templates/contest/ranking-table.html:10 templates/user/users-table.html:13 -msgid "Full Name" -msgstr "" - -#: templates/contest/ranking-table.html:44 +#: templates/contest/ranking-table.html:30 msgid "Un-Disqualify" msgstr "" -#: templates/contest/ranking-table.html:47 +#: templates/contest/ranking-table.html:33 msgid "Disqualify" msgstr "" -#: templates/contest/ranking.html:187 +#: templates/contest/ranking.html:173 msgid "Are you sure you want to disqualify this participation?" msgstr "" -#: templates/contest/ranking.html:192 +#: templates/contest/ranking.html:178 msgid "Are you sure you want to un-disqualify this participation?" msgstr "" -#: templates/contest/ranking.html:463 +#: templates/contest/ranking.html:252 msgid "View user participation" msgstr "" -#: templates/contest/ranking.html:467 +#: templates/contest/ranking.html:256 msgid "Show organizations" msgstr "" -#: templates/contest/ranking.html:471 -msgid "Show full name" -msgstr "" - -#: templates/contest/ranking.html:474 -msgid "Show friends only" -msgstr "" - -#: templates/contest/ranking.html:477 -msgid "Total score only" -msgstr "" - -#: templates/contest/ranking.html:479 -msgid "Show virtual participation" -msgstr "" - -#: templates/contest/stats.html:51 +#: templates/contest/stats.html:38 msgid "Problem Status Distribution" msgstr "" -#: templates/contest/stats.html:56 +#: templates/contest/stats.html:43 #, fuzzy #| msgid "Problem" msgid "Problem AC Rate" msgstr "Problem" -#: templates/contest/stats.html:62 -msgid "Problem Point Distribution" -msgstr "" - -#: templates/contest/stats.html:76 templates/stats/language.html:16 +#: templates/contest/stats.html:48 templates/stats/language.html:16 msgid "Submissions by Language" msgstr "" -#: templates/contest/stats.html:82 templates/stats/language.html:26 +#: templates/contest/stats.html:54 templates/stats/language.html:26 msgid "Language AC Rate" msgstr "" @@ -3630,7 +3320,6 @@ msgid "Source:" msgstr "" #: templates/newsletter/common.html:6 -#: templates/newsletter/newsletter_list.html:15 #: templates/newsletter/subscription_unsubscribe_activated.html:3 #: templates/newsletter/subscription_unsubscribe_activated.html:6 #: templates/newsletter/subscription_update_activated.html:3 @@ -3638,23 +3327,6 @@ msgstr "" msgid "Newsletter" msgstr "" -#: templates/newsletter/newsletter_list.html:2 -#: templates/newsletter/newsletter_list.html:3 -msgid "Newsletter list" -msgstr "" - -#: templates/newsletter/newsletter_list.html:6 -msgid "Subscribe to get the latest emails about upcoming contests and events." -msgstr "" - -#: templates/newsletter/newsletter_list.html:16 -msgid "Subscribe" -msgstr "" - -#: templates/newsletter/newsletter_list.html:30 -msgid "Update subscriptions" -msgstr "" - #: templates/newsletter/subscription_unsubscribe_activated.html:3 #: templates/newsletter/subscription_unsubscribe_activated.html:6 #: templates/newsletter/subscription_update_activated.html:3 @@ -3716,99 +3388,64 @@ msgid "" "follow in order to update your subscription." msgstr "" -#: templates/notification/list.html:7 -msgid "You have no notifications" -msgstr "" - -#: templates/notification/list.html:13 -msgid "Activity" -msgstr "" - #: templates/organization/edit.html:46 #: templates/organization/requests/pending.html:34 #: templates/ticket/edit-notes.html:4 msgid "Update" msgstr "" -#: templates/organization/home.html:41 +#: templates/organization/home.html:7 msgid "Are you sure you want to leave this organization?" msgstr "" -#: templates/organization/home.html:43 +#: templates/organization/home.html:9 msgid "You will have to rejoin to show up on the organization leaderboard." msgstr "" -#: templates/organization/home.html:45 +#: templates/organization/home.html:11 msgid "You will have to request membership in order to join again." msgstr "" -#: templates/organization/home.html:88 -msgid "Join organization" -msgstr "" - -#: templates/organization/home.html:92 -msgid "Request membership" -msgstr "" - -#: templates/organization/home.html:122 -#, fuzzy -#| msgid "Organization" -msgid "Organization news" -msgstr "Organizacja" - -#: templates/organization/home.html:128 -msgid "There is no news at this time." -msgstr "" - -#: templates/organization/home.html:137 -msgid "Controls" -msgstr "" - -#: templates/organization/home.html:142 -msgid "Edit organization" -msgstr "" - -#: templates/organization/home.html:148 -msgid "View requests" -msgstr "" - -#: templates/organization/home.html:161 -msgid "Admin organization" -msgstr "" - -#: templates/organization/home.html:167 -msgid "View members" -msgstr "" - -#: templates/organization/home.html:174 +#: templates/organization/home.html:24 msgid "Leave organization" msgstr "" -#: templates/organization/home.html:183 -msgid "New private contests" +#: templates/organization/home.html:29 +msgid "Join organization" msgstr "" -#: templates/organization/home.html:193 templates/organization/home.html:208 -msgid "View all" +#: templates/organization/home.html:33 +msgid "Request membership" msgstr "" -#: templates/organization/home.html:199 -msgid "New private problems" +#: templates/organization/home.html:39 +msgid "Edit organization" msgstr "" -#: templates/organization/list.html:40 -msgid "Show my organizations only" +#: templates/organization/home.html:43 +msgid "View requests" msgstr "" -#: templates/organization/list.html:47 templates/status/language-list.html:34 -#: templates/user/import/table_csv.html:6 +#: templates/organization/home.html:50 +msgid "Admin organization" +msgstr "" + +#: templates/organization/home.html:55 +msgid "View members" +msgstr "" + +#: templates/organization/list.html:23 templates/status/language-list.html:34 msgid "Name" msgstr "" -#: templates/organization/list.html:48 +#: templates/organization/list.html:24 msgid "Members" msgstr "" +#: templates/organization/new.html:10 templates/ticket/new.html:38 +msgid "Create" +msgstr "" + #: templates/organization/requests/detail.html:13 msgid "User:" msgstr "" @@ -3841,7 +3478,7 @@ msgid "There are no requests to approve." msgstr "" #: templates/organization/requests/pending.html:17 -#: templates/problem/data.html:432 +#: templates/problem/data.html:452 msgid "Delete?" msgstr "" @@ -3877,35 +3514,35 @@ msgstr "" msgid "Enter a new code for the cloned problem:" msgstr "" -#: templates/problem/data.html:119 +#: templates/problem/data.html:108 msgid "Instruction" msgstr "" -#: templates/problem/data.html:390 +#: templates/problem/data.html:410 msgid "View YAML" msgstr "" -#: templates/problem/data.html:421 templates/problem/data.html:472 +#: templates/problem/data.html:441 templates/problem/data.html:491 msgid "Apply!" msgstr "" -#: templates/problem/data.html:426 +#: templates/problem/data.html:446 msgid "Type" msgstr "" -#: templates/problem/data.html:427 +#: templates/problem/data.html:447 msgid "Input file" msgstr "" -#: templates/problem/data.html:428 +#: templates/problem/data.html:448 msgid "Output file" msgstr "" -#: templates/problem/data.html:430 +#: templates/problem/data.html:450 msgid "Pretest?" msgstr "" -#: templates/problem/data.html:473 +#: templates/problem/data.html:492 msgid "Add new case" msgstr "" @@ -3917,32 +3554,28 @@ msgid "" "problem yourself is a bannable offence." msgstr "" -#: templates/problem/list.html:66 +#: templates/problem/list.html:62 msgid "Filter by type..." msgstr "" -#: templates/problem/list.html:193 +#: templates/problem/list.html:185 msgid "Hot problems" msgstr "" -#: templates/problem/list.html:218 templates/problem/list.html:240 -#: templates/problem/search-form.html:45 templates/user/user-problems.html:57 +#: templates/problem/list.html:207 templates/problem/list.html:224 +#: templates/problem/search-form.html:30 templates/user/user-problems.html:57 msgid "Category" msgstr "" -#: templates/problem/list.html:220 templates/problem/list.html:244 +#: templates/problem/list.html:209 templates/problem/list.html:228 msgid "Types" msgstr "" -#: templates/problem/list.html:251 +#: templates/problem/list.html:235 #, python-format msgid "AC %%" msgstr "" -#: templates/problem/list.html:342 -msgid "Add clarifications" -msgstr "" - #: templates/problem/manage_submission.html:55 msgid "Leave empty to not filter by language" msgstr "" @@ -3951,209 +3584,152 @@ msgstr "" msgid "Leave empty to not filter by result" msgstr "" -#: templates/problem/manage_submission.html:80 +#: templates/problem/manage_submission.html:79 msgid "Need valid values for both start and end IDs." msgstr "" -#: templates/problem/manage_submission.html:83 +#: templates/problem/manage_submission.html:82 msgid "End ID must be after start ID." msgstr "" +#: templates/problem/manage_submission.html:90 +#, python-brace-format +msgid "" +"You are about to rejudge {count} submissions. Are you sure you want to do " +"this?" +msgstr "" + #: templates/problem/manage_submission.html:96 -#, python-brace-format msgid "" -"You are about to {action} {count} submissions. Are you sure you want to do " -"this?" +"You are about to rejudge a few submissions. Are you sure you want to do this?" msgstr "" -#: templates/problem/manage_submission.html:103 -#, python-brace-format -msgid "" -"You are about to {action} a few submissions. Are you sure you want to do " -"this?" +#: templates/problem/manage_submission.html:115 +msgid "Rejudge Submissions" msgstr "" -#: templates/problem/manage_submission.html:127 -#: templates/submission/list.html:309 -msgid "Filter submissions" -msgstr "" - -#: templates/problem/manage_submission.html:132 +#: templates/problem/manage_submission.html:120 msgid "Filter by ID:" msgstr "" -#: templates/problem/manage_submission.html:135 +#: templates/problem/manage_submission.html:123 msgid "Starting ID:" msgstr "" -#: templates/problem/manage_submission.html:139 +#: templates/problem/manage_submission.html:127 msgid "Ending ID:" msgstr "" -#: templates/problem/manage_submission.html:143 +#: templates/problem/manage_submission.html:131 msgid "This range includes both endpoints." msgstr "" -#: templates/problem/manage_submission.html:146 +#: templates/problem/manage_submission.html:134 msgid "Filter by language:" msgstr "" -#: templates/problem/manage_submission.html:154 +#: templates/problem/manage_submission.html:142 msgid "Filter by result:" msgstr "" -#: templates/problem/manage_submission.html:164 -msgid "Action" -msgstr "" - -#: templates/problem/manage_submission.html:166 +#: templates/problem/manage_submission.html:150 msgid "Rejudge selected submissions" msgstr "" -#: templates/problem/manage_submission.html:171 -msgid "Download selected submissions" +#: templates/problem/manage_submission.html:157 +msgid "Rescore Everything" msgstr "" -#: templates/problem/manage_submission.html:177 -#, python-format -msgid "Are you sure you want to rescore %(count)d submissions?" -msgstr "" - -#: templates/problem/manage_submission.html:178 +#: templates/problem/manage_submission.html:163 msgid "Rescore all submissions" msgstr "" -#: templates/problem/problem.html:132 +#: templates/problem/problem.html:91 msgid "View as PDF" msgstr "" -#: templates/problem/problem.html:141 templates/problem/problem.html:151 -#: templates/problem/problem.html:156 +#: templates/problem/problem.html:101 templates/problem/problem.html:111 +#: templates/problem/problem.html:116 msgid "Submit solution" msgstr "" -#: templates/problem/problem.html:144 -#, python-format -msgid "%(counter)s submission left" -msgid_plural "%(counter)s submissions left" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" -msgstr[3] "" - -#: templates/problem/problem.html:152 +#: templates/problem/problem.html:112 msgid "0 submissions left" msgstr "" -#: templates/problem/problem.html:164 +#: templates/problem/problem.html:124 msgid "My submissions" msgstr "" -#: templates/problem/problem.html:168 +#: templates/problem/problem.html:128 msgid "Best submissions" msgstr "" -#: templates/problem/problem.html:172 +#: templates/problem/problem.html:132 msgid "Read editorial" msgstr "" -#: templates/problem/problem.html:177 +#: templates/problem/problem.html:137 msgid "Manage tickets" msgstr "" -#: templates/problem/problem.html:181 +#: templates/problem/problem.html:141 msgid "Edit problem" msgstr "" -#: templates/problem/problem.html:183 +#: templates/problem/problem.html:143 msgid "Edit test data" msgstr "" -#: templates/problem/problem.html:188 +#: templates/problem/problem.html:148 msgid "My tickets" msgstr "" -#: templates/problem/problem.html:196 +#: templates/problem/problem.html:156 msgid "Manage submissions" msgstr "" -#: templates/problem/problem.html:202 +#: templates/problem/problem.html:162 msgid "Clone problem" msgstr "" -#: templates/problem/problem.html:209 +#: templates/problem/problem.html:169 msgid "Points:" msgstr "" -#: templates/problem/problem.html:212 templates/problem/problem.html:214 +#: templates/problem/problem.html:172 templates/problem/problem.html:174 msgid "(partial)" msgstr "" -#: templates/problem/problem.html:219 +#: templates/problem/problem.html:179 msgid "Time limit:" msgstr "" -#: templates/problem/problem.html:231 +#: templates/problem/problem.html:191 msgid "Memory limit:" msgstr "" -#: templates/problem/problem.html:250 -msgid "Author:" -msgid_plural "Authors:" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" -msgstr[3] "" - -#: templates/problem/problem.html:265 -#, fuzzy -#| msgid "Problem" -msgid "Problem type" -msgid_plural "Problem types" -msgstr[0] "Problem" -msgstr[1] "Problem" -msgstr[2] "Problem" -msgstr[3] "Problem" - -#: templates/problem/problem.html:278 +#: templates/problem/problem.html:238 msgid "Allowed languages" msgstr "" -#: templates/problem/problem.html:286 -#, python-format -msgid "No %(lang)s judge online" -msgstr "" - -#: templates/problem/problem.html:297 -msgid "Judge:" -msgid_plural "Judges:" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" -msgstr[3] "" - -#: templates/problem/problem.html:314 +#: templates/problem/problem.html:274 msgid "none available" msgstr "" -#: templates/problem/problem.html:326 -#, python-format -msgid "This problem has %(length)s clarification(s)" -msgstr "" - -#: templates/problem/problem.html:350 +#: templates/problem/problem.html:299 msgid "Request clarification" msgstr "" -#: templates/problem/problem.html:352 +#: templates/problem/problem.html:301 msgid "Report an issue" msgstr "" -#: templates/problem/raw.html:64 +#: templates/problem/raw.html:62 msgid "Time Limit:" msgstr "" -#: templates/problem/raw.html:73 +#: templates/problem/raw.html:71 msgid "Memory Limit:" msgstr "" @@ -4177,75 +3753,39 @@ msgstr "" msgid "Show problem types" msgstr "" -#: templates/problem/search-form.html:32 -msgid "Show editorial" -msgstr "" - -#: templates/problem/search-form.html:48 templates/problem/search-form.html:50 -#: templates/submission/submission-list-tabs.html:4 +#: templates/problem/search-form.html:33 templates/problem/search-form.html:35 msgid "All" msgstr "" -#: templates/problem/search-form.html:62 +#: templates/problem/search-form.html:46 msgid "Problem types" msgstr "" -#: templates/problem/search-form.html:73 +#: templates/problem/search-form.html:57 msgid "Point range" msgstr "" -#: templates/problem/search-form.html:79 templates/submission/list.html:331 +#: templates/problem/search-form.html:63 templates/submission/list.html:331 #: templates/ticket/list.html:248 msgid "Go" msgstr "" -#: templates/problem/search-form.html:80 +#: templates/problem/search-form.html:64 msgid "Random" msgstr "" -#: templates/problem/submit.html:117 -msgid "Your source code must contain at most 65536 characters." -msgstr "" - -#: templates/problem/submit.html:204 -#, python-format -msgid "" -"Warning! Your default language, %(default_language)s, is " -"unavailable for this problem and has been deselected." -msgstr "" - -#: templates/problem/submit.html:215 -#, python-format -msgid "" -"\n" -" You have %(left)s submission left\n" -" " -msgid_plural "" -"\n" -" You have %(left)s submissions left\n" -" " -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" -msgstr[3] "" - -#: templates/problem/submit.html:224 +#: templates/problem/submit.html:212 msgid "You have 0 submissions left" msgstr "" -#: templates/problem/submit.html:258 +#: templates/problem/submit.html:250 msgid "No judge is available for this problem." msgstr "" -#: templates/problem/submit.html:262 +#: templates/problem/submit.html:252 msgid "Submit!" msgstr "" -#: templates/registration/activate.html:3 -#, python-format -msgid "%(key)s is an invalid activation key." -msgstr "" - #: templates/registration/activation_complete.html:3 msgid "Your account has been successfully activated." msgstr "" @@ -4303,13 +3843,6 @@ msgid "" "you registered with, and check your spam folder." msgstr "" -#: templates/registration/password_reset_email.txt:1 -#, python-format -msgid "" -"You're receiving this email because you requested a password reset for your " -"user account at %(site_name)s." -msgstr "" - #: templates/registration/password_reset_email.txt:3 msgid "Please go to the following page and choose a new password:" msgstr "" @@ -4322,16 +3855,6 @@ msgstr "" msgid "Thanks for using our site!" msgstr "" -#: templates/registration/password_reset_email.txt:11 -#, python-format -msgid "The %(site_name)s team" -msgstr "" - -#: templates/registration/password_reset_subject.txt:1 -#, python-format -msgid "Password reset on %(site_name)s" -msgstr "" - #: templates/registration/profile_creation.html:36 #: templates/registration/username_select.html:7 msgid "Continue >" @@ -4368,20 +3891,19 @@ msgstr "" msgid "Affiliated organizations" msgstr "" -#: templates/registration/registration_form.html:195 -#: templates/user/edit-profile.html:128 +#: templates/registration/registration_form.html:192 msgid "Notify me about upcoming contests" msgstr "" -#: templates/registration/registration_form.html:209 +#: templates/registration/registration_form.html:206 msgid "By registering, you agree to our" msgstr "" -#: templates/registration/registration_form.html:210 +#: templates/registration/registration_form.html:207 msgid "Terms & Conditions" msgstr "" -#: templates/registration/registration_form.html:213 +#: templates/registration/registration_form.html:210 msgid "Register!" msgstr "" @@ -4391,11 +3913,6 @@ msgstr "" msgid "Enter the 6-digit code generated by your app:" msgstr "" -#: templates/registration/totp_auth.html:41 -#, python-format -msgid "If you lost your authentication device, please contact us at %(email)s." -msgstr "" - #: templates/registration/totp_disable.html:38 msgid "" "To protect your account, you must first authenticate before you can disable " @@ -4414,6 +3931,10 @@ msgstr "" msgid "Or enter this code manually:" msgstr "" +#: templates/stats/base.html:9 templates/submission/list.html:339 +msgid "Statistics" +msgstr "" + #: templates/stats/language.html:11 msgid "Submission Statistics" msgstr "" @@ -4439,7 +3960,6 @@ msgid "Ping" msgstr "" #: templates/status/judge-status-table.html:8 -#: templates/user/import/index.html:104 msgid "Load" msgstr "" @@ -4455,7 +3975,6 @@ msgid "There are no judges available at this time." msgstr "" #: templates/status/language-list.html:33 templates/ticket/list.html:261 -#: templates/user/import/table_csv.html:3 msgid "ID" msgstr "" @@ -4463,22 +3982,6 @@ msgstr "" msgid "Runtime Info" msgstr "" -#: templates/status/status-tabs.html:4 -msgid "Judges" -msgstr "" - -#: templates/status/status-tabs.html:6 -msgid "Version Matrix" -msgstr "" - -#: templates/submission/internal-error-message.html:3 -#, python-format -msgid "" -"An internal error occurred while grading, and the %(SITE_NAME)s " -"administrators have been notified.
In the meantime, try resubmitting in " -"a few seconds." -msgstr "" - #: templates/submission/internal-error-message.html:8 msgid "An internal error occurred while grading." msgstr "" @@ -4495,6 +3998,10 @@ msgstr "" msgid "Filter by language..." msgstr "" +#: templates/submission/list.html:309 +msgid "Filter submissions" +msgstr "" + #: templates/submission/list.html:345 msgid "Total:" msgstr "" @@ -4551,64 +4058,63 @@ msgstr "" msgid "Execution Results" msgstr "" -#: templates/submission/status-testcases.html:34 -msgid "Overall: " -msgstr "" - -#: templates/submission/status-testcases.html:48 -msgid "Point: " -msgstr "" - -#: templates/submission/status-testcases.html:53 -msgid "Time: " -msgstr "" - -#: templates/submission/status-testcases.html:62 -msgid "Memory: " -msgstr "" - -#: templates/submission/status-testcases.html:73 +#: templates/submission/status-testcases.html:31 msgid "Batch " msgstr "" -#: templates/submission/status-testcases.html:84 -#: templates/submission/status-testcases.html:113 -msgid "Point" +#: templates/submission/status-testcases.html:43 +msgid "Overall: " msgstr "" -#: templates/submission/status-testcases.html:99 +#: templates/submission/status-testcases.html:57 +msgid "Point: " +msgstr "" + +#: templates/submission/status-testcases.html:62 +msgid "Time: " +msgstr "" + +#: templates/submission/status-testcases.html:71 +msgid "Memory: " +msgstr "" + +#: templates/submission/status-testcases.html:84 msgid "Case" msgstr "" -#: templates/submission/status-testcases.html:101 +#: templates/submission/status-testcases.html:86 msgid "Pretest" msgstr "" -#: templates/submission/status-testcases.html:103 +#: templates/submission/status-testcases.html:88 msgid "Test case" msgstr "" -#: templates/submission/status-testcases.html:141 +#: templates/submission/status-testcases.html:99 +msgid "Point" +msgstr "" + +#: templates/submission/status-testcases.html:121 msgid "Input:" msgstr "" -#: templates/submission/status-testcases.html:145 +#: templates/submission/status-testcases.html:125 msgid "Output:" msgstr "" -#: templates/submission/status-testcases.html:149 +#: templates/submission/status-testcases.html:129 msgid "Answer:" msgstr "" -#: templates/submission/status-testcases.html:154 +#: templates/submission/status-testcases.html:134 msgid "Judge feedback:" msgstr "" -#: templates/submission/status-testcases.html:175 +#: templates/submission/status-testcases.html:157 msgid "Passing pretests does not guarantee a full score on system tests." msgstr "" -#: templates/submission/status-testcases.html:178 +#: templates/submission/status-testcases.html:160 msgid "Submission aborted!" msgstr "" @@ -4620,24 +4126,11 @@ msgstr "" msgid "Abort" msgstr "" -#: templates/submission/submission-list-tabs.html:6 -msgid "Mine" -msgstr "" - -#: templates/submission/submission-list-tabs.html:9 -msgid "Best" -msgstr "" - -#: templates/submission/submission-list-tabs.html:12 -#, python-format -msgid "%(user)s's" -msgstr "" - -#: templates/ticket/list.html:135 templates/ticket/ticket.html:273 +#: templates/ticket/list.html:135 templates/ticket/ticket.html:257 msgid "Reopened: " msgstr "" -#: templates/ticket/list.html:138 templates/ticket/ticket.html:274 +#: templates/ticket/list.html:138 templates/ticket/ticket.html:258 msgid "Closed: " msgstr "" @@ -4661,7 +4154,7 @@ msgstr "" msgid "Title" msgstr "" -#: templates/ticket/list.html:264 templates/ticket/ticket.html:369 +#: templates/ticket/list.html:264 templates/ticket/ticket.html:328 msgid "Assignees" msgstr "" @@ -4676,36 +4169,32 @@ msgid "" "a problem, ask in the comments instead." msgstr "" -#: templates/ticket/ticket.html:355 -msgid "Post" -msgstr "" - -#: templates/ticket/ticket.html:363 +#: templates/ticket/ticket.html:322 msgid "Associated object" msgstr "" -#: templates/ticket/ticket.html:374 +#: templates/ticket/ticket.html:333 msgid "No one is assigned." msgstr "" -#: templates/ticket/ticket.html:380 +#: templates/ticket/ticket.html:339 msgid "Close ticket" msgstr "" -#: templates/ticket/ticket.html:382 +#: templates/ticket/ticket.html:341 msgid "Reopen ticket" msgstr "" -#: templates/ticket/ticket.html:386 +#: templates/ticket/ticket.html:345 msgid "Assignee notes" msgstr "" -#: templates/ticket/ticket.html:393 templates/widgets/select_all.html:4 +#: templates/ticket/ticket.html:352 templates/widgets/select_all.html:4 msgid "Nothing here." msgstr "" -#: templates/user/base-users-table.html:3 -msgid "Rank" +#: templates/ticket/ticket.html:385 +msgid "Post" msgstr "" #: templates/user/base-users.html:14 templates/user/base-users.html:69 @@ -4752,174 +4241,50 @@ msgstr "" msgid "Update profile" msgstr "" -#: templates/user/import/index.html:31 -msgid "Upload CSV only" -msgstr "" - -#: templates/user/import/index.html:100 -msgid "User File" -msgstr "" - -#: templates/user/import/index.html:102 -msgid "Sample" -msgstr "" - -#: templates/user/import/index.html:105 templates/user/user-list-tabs.html:8 -msgid "Import" -msgstr "" - -#: templates/user/import/table_csv.html:7 -msgid "School" -msgstr "" - -#: templates/user/pp-row.html:22 -#, python-format -msgid "" -"\n" -" weighted %(weight)s%%\n" -" " -msgstr "" - -#: templates/user/pp-row.html:27 -#, python-format -msgid "%(pp).1fpp" -msgstr "" - -#: templates/user/pp-row.html:29 -#, python-format -msgid "%(pp).0fpp" -msgstr "" - -#: templates/user/user-about.html:23 -#, python-format -msgid "%(counter)s problem solved" -msgid_plural "%(counter)s problems solved" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" -msgstr[3] "" - -#: templates/user/user-about.html:35 -msgid "Total points" -msgstr "" - -#: templates/user/user-about.html:45 -#, fuzzy -#| msgid "Rating" -msgid "Rank by rating" -msgstr "Ocena" - -#: templates/user/user-about.html:52 -msgid "Rank by points" -msgstr "" - -#: templates/user/user-about.html:64 +#: templates/user/user-about.html:14 msgid "From" msgstr "" -#: templates/user/user-about.html:75 +#: templates/user/user-about.html:25 msgid "Admin Notes" msgstr "" -#: templates/user/user-about.html:90 +#: templates/user/user-about.html:40 msgid "You have not shared any information." msgstr "" -#: templates/user/user-about.html:92 +#: templates/user/user-about.html:42 msgid "This user has not shared any information." msgstr "" -#: templates/user/user-about.html:101 -msgid "Awards" +#: templates/user/user-base.html:50 +msgid "Rank by points:" msgstr "" -#: templates/user/user-about.html:112 -#, python-format -msgid "%(label)s (%(date)s)" +#: templates/user/user-base.html:53 +msgid "Total points:" msgstr "" -#: templates/user/user-about.html:130 -msgid "Mon" +#: templates/user/user-base.html:68 +msgid "Rank by rating:" msgstr "" -#: templates/user/user-about.html:135 -msgid "Tues" +#: templates/user/user-base.html:70 +msgid "Rating:" msgstr "" -#: templates/user/user-about.html:140 -msgid "Wed" -msgstr "" - -#: templates/user/user-about.html:145 -msgid "Thurs" -msgstr "" - -#: templates/user/user-about.html:150 -msgid "Fri" -msgstr "" - -#: templates/user/user-about.html:155 -msgid "Sat" -msgstr "" - -#: templates/user/user-about.html:160 -msgid "Sun" -msgstr "" - -#: templates/user/user-about.html:169 -msgid "Less" -msgstr "" - -#: templates/user/user-about.html:175 -msgid "More" -msgstr "" - -#: templates/user/user-about.html:184 -#, fuzzy -#| msgid "Rating" -msgid "Rating History" -msgstr "Ocena" - -#: templates/user/user-about.html:255 -msgid "past year" -msgstr "" - -#: templates/user/user-about.html:272 -msgid "total submission(s)" -msgstr "" - -#: templates/user/user-about.html:276 -msgid "submissions in the last year" -msgstr "" - -#: templates/user/user-base.html:101 -msgid "Unfollow" -msgstr "" - -#: templates/user/user-base.html:104 -msgid "Follow" -msgstr "" - -#: templates/user/user-base.html:120 -msgid "Contests written" -msgstr "" - -#: templates/user/user-base.html:124 +#: templates/user/user-base.html:71 msgid "Volatility:" msgstr "" -#: templates/user/user-base.html:128 +#: templates/user/user-base.html:72 msgid "Min. rating:" msgstr "" -#: templates/user/user-base.html:132 +#: templates/user/user-base.html:73 msgid "Max rating:" msgstr "" -#: templates/user/user-list-tabs.html:5 -msgid "Friends" -msgstr "" - #: templates/user/user-problems.html:35 msgid "Points Breakdown" msgstr "" @@ -4940,32 +4305,10 @@ msgstr "" msgid "Hide problems I've solved" msgstr "" -#: templates/user/user-problems.html:93 -#, python-format -msgid "%(points).1f points" -msgstr "" - #: templates/user/user-problems.html:99 msgid "Score" msgstr "" -#: templates/user/user-problems.html:110 -#, python-format -msgid "%(points)s / %(total)s" -msgstr "" - -#: templates/user/user-tabs.html:7 -msgid "Impersonate" -msgstr "" - -#: templates/user/user-tabs.html:13 -msgid "Admin User" -msgstr "" - -#: templates/user/user-tabs.html:16 -msgid "Admin Profile" -msgstr "" - #: templates/widgets/select_all.html:8 msgid "Check all" msgstr "" diff --git a/locale/pl/LC_MESSAGES/djangojs.po b/locale/pl/LC_MESSAGES/djangojs.po index 77ffced..f30632e 100644 --- a/locale/pl/LC_MESSAGES/djangojs.po +++ b/locale/pl/LC_MESSAGES/djangojs.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: dmoj\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-07-20 23:30+0700\n" +"POT-Creation-Date: 2019-10-01 23:12+0000\n" "PO-Revision-Date: 2019-11-11 22:05\n" "Last-Translator: Icyene\n" "Language-Team: Polish\n" @@ -10,9 +10,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n" -"%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n" -"%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n" +"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: dmoj\n" "X-Crowdin-Language: pl\n" @@ -31,3 +29,4 @@ msgstr[3] "" msgctxt "time format without day" msgid "%h:%m:%s" msgstr "" + diff --git a/locale/pt/LC_MESSAGES/django.po b/locale/pt/LC_MESSAGES/django.po index 9c6b116..30de349 100644 --- a/locale/pt/LC_MESSAGES/django.po +++ b/locale/pt/LC_MESSAGES/django.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: dmoj\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-10-25 05:59+0700\n" +"POT-Creation-Date: 2020-04-10 01:26-0500\n" "PO-Revision-Date: 2019-11-11 22:05\n" "Last-Translator: Icyene\n" "Language-Team: Portuguese, Brazilian\n" @@ -16,93 +16,93 @@ msgstr "" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: django.po\n" -#: chat_box/models.py:16 judge/admin/interface.py:110 -#: judge/models/contest.py:403 judge/models/contest.py:528 -#: judge/models/profile.py:211 +#: chat_box/models.py:15 judge/admin/interface.py:107 +#: judge/models/contest.py:257 judge/models/contest.py:381 +#: judge/models/profile.py:191 msgid "user" msgstr "" -#: chat_box/models.py:17 judge/models/comment.py:43 judge/models/comment.py:191 +#: chat_box/models.py:16 judge/models/comment.py:42 msgid "posted time" msgstr "" -#: chat_box/models.py:18 judge/models/comment.py:47 +#: chat_box/models.py:17 judge/models/comment.py:46 msgid "body of comment" msgstr "" -#: chat_box/views.py:29 templates/chat/chat.html:4 +#: chat_box/views.py:29 msgid "Chat Box" msgstr "" -#: dmoj/settings.py:355 +#: dmoj/settings.py:349 msgid "German" msgstr "" -#: dmoj/settings.py:356 +#: dmoj/settings.py:350 msgid "English" msgstr "" -#: dmoj/settings.py:357 +#: dmoj/settings.py:351 msgid "Spanish" msgstr "" -#: dmoj/settings.py:358 +#: dmoj/settings.py:352 msgid "French" msgstr "" -#: dmoj/settings.py:359 +#: dmoj/settings.py:353 msgid "Croatian" msgstr "" -#: dmoj/settings.py:360 +#: dmoj/settings.py:354 msgid "Hungarian" msgstr "" -#: dmoj/settings.py:361 +#: dmoj/settings.py:355 msgid "Japanese" msgstr "" -#: dmoj/settings.py:362 +#: dmoj/settings.py:356 msgid "Korean" msgstr "" -#: dmoj/settings.py:363 +#: dmoj/settings.py:357 msgid "Brazilian Portuguese" msgstr "" -#: dmoj/settings.py:364 +#: dmoj/settings.py:358 msgid "Romanian" msgstr "" -#: dmoj/settings.py:365 +#: dmoj/settings.py:359 msgid "Russian" msgstr "" -#: dmoj/settings.py:366 +#: dmoj/settings.py:360 msgid "Serbian (Latin)" msgstr "" -#: dmoj/settings.py:367 +#: dmoj/settings.py:361 msgid "Turkish" msgstr "" -#: dmoj/settings.py:368 +#: dmoj/settings.py:362 msgid "Vietnamese" msgstr "" -#: dmoj/settings.py:369 +#: dmoj/settings.py:363 msgid "Simplified Chinese" msgstr "" -#: dmoj/settings.py:370 +#: dmoj/settings.py:364 msgid "Traditional Chinese" msgstr "" -#: dmoj/urls.py:58 +#: dmoj/urls.py:57 msgid "Login" msgstr "" -#: dmoj/urls.py:106 templates/base.html:193 +#: dmoj/urls.py:105 templates/base.html:190 msgid "Home" msgstr "" @@ -132,92 +132,90 @@ msgstr "" msgid "Associated page" msgstr "" -#: judge/admin/contest.py:30 +#: judge/admin/contest.py:28 msgid "Included contests" msgstr "" -#: judge/admin/contest.py:66 templates/contest/clarification.html:42 -#: templates/contest/contest.html:83 templates/contest/moss.html:43 -#: templates/problem/list.html:214 templates/problem/list.html:232 -#: templates/problem/list.html:350 templates/user/user-problems.html:56 +#: judge/admin/contest.py:64 templates/contest/contest.html:83 +#: templates/contest/moss.html:43 templates/problem/list.html:206 +#: templates/problem/list.html:221 templates/user/user-problems.html:56 #: templates/user/user-problems.html:98 msgid "Problem" msgstr "" -#: judge/admin/contest.py:119 +#: judge/admin/contest.py:112 msgid "Settings" msgstr "" -#: judge/admin/contest.py:121 +#: judge/admin/contest.py:114 msgid "Scheduling" msgstr "" -#: judge/admin/contest.py:122 templates/organization/home.html:107 +#: judge/admin/contest.py:115 msgid "Details" msgstr "" -#: judge/admin/contest.py:123 +#: judge/admin/contest.py:116 msgid "Format" msgstr "" -#: judge/admin/contest.py:124 templates/contest/ranking-table.html:7 -#: templates/user/user-about.html:15 templates/user/user-about.html:45 +#: judge/admin/contest.py:117 templates/contest/ranking-table.html:5 msgid "Rating" msgstr "" -#: judge/admin/contest.py:125 +#: judge/admin/contest.py:118 msgid "Access" msgstr "" -#: judge/admin/contest.py:127 judge/admin/problem.py:131 +#: judge/admin/contest.py:120 judge/admin/problem.py:131 msgid "Justice" msgstr "" -#: judge/admin/contest.py:207 +#: judge/admin/contest.py:158 #, python-format msgid "%d contest successfully marked as visible." msgid_plural "%d contests successfully marked as visible." msgstr[0] "" msgstr[1] "" -#: judge/admin/contest.py:210 +#: judge/admin/contest.py:161 msgid "Mark contests as visible" msgstr "" -#: judge/admin/contest.py:216 +#: judge/admin/contest.py:165 #, python-format msgid "%d contest successfully marked as hidden." msgid_plural "%d contests successfully marked as hidden." msgstr[0] "" msgstr[1] "" -#: judge/admin/contest.py:219 +#: judge/admin/contest.py:168 msgid "Mark contests as hidden" msgstr "" -#: judge/admin/contest.py:233 judge/admin/submission.py:164 +#: judge/admin/contest.py:182 judge/admin/submission.py:164 #, python-format msgid "%d submission was successfully scheduled for rejudging." msgid_plural "%d submissions were successfully scheduled for rejudging." msgstr[0] "" msgstr[1] "" -#: judge/admin/contest.py:308 +#: judge/admin/contest.py:256 #, python-format msgid "%d participation recalculated." msgid_plural "%d participations recalculated." msgstr[0] "" msgstr[1] "" -#: judge/admin/contest.py:311 +#: judge/admin/contest.py:259 msgid "Recalculate results" msgstr "" -#: judge/admin/contest.py:315 judge/admin/organization.py:65 +#: judge/admin/contest.py:263 judge/admin/organization.py:65 msgid "username" msgstr "" -#: judge/admin/contest.py:320 templates/base.html:277 +#: judge/admin/contest.py:268 templates/base.html:260 msgid "virtual" msgstr "" @@ -225,15 +223,15 @@ msgstr "" msgid "link path" msgstr "" -#: judge/admin/interface.py:65 +#: judge/admin/interface.py:62 msgid "Content" msgstr "" -#: judge/admin/interface.py:66 +#: judge/admin/interface.py:63 msgid "Summary" msgstr "" -#: judge/admin/interface.py:151 +#: judge/admin/interface.py:148 msgid "object" msgstr "" @@ -255,9 +253,8 @@ msgid "Taxonomy" msgstr "" #: judge/admin/problem.py:128 templates/contest/contest.html:84 -#: templates/problem/data.html:429 templates/problem/list.html:222 -#: templates/problem/list.html:248 templates/user/base-users-table.html:10 -#: templates/user/user-about.html:36 templates/user/user-about.html:52 +#: templates/problem/data.html:449 templates/problem/list.html:211 +#: templates/problem/list.html:232 templates/user/base-users-table.html:10 #: templates/user/user-problems.html:58 msgid "Points" msgstr "" @@ -306,7 +303,6 @@ msgid "timezone" msgstr "" #: judge/admin/profile.py:86 judge/admin/submission.py:211 -#: templates/notification/list.html:12 #: templates/organization/requests/log.html:9 #: templates/organization/requests/pending.html:12 #: templates/ticket/list.html:263 @@ -314,7 +310,6 @@ msgid "User" msgstr "" #: judge/admin/profile.py:91 templates/registration/registration_form.html:145 -#: templates/user/import/table_csv.html:8 msgid "Email" msgstr "" @@ -347,7 +342,7 @@ msgstr "" msgid "These problems are NOT allowed to be submitted in this language" msgstr "" -#: judge/admin/runtime.py:83 templates/problem/list.html:352 +#: judge/admin/runtime.py:83 msgid "Description" msgstr "" @@ -394,7 +389,7 @@ msgstr "" msgid "Rejudge the selected submissions" msgstr "" -#: judge/admin/submission.py:193 judge/views/problem_manage.py:159 +#: judge/admin/submission.py:193 judge/views/problem_manage.py:128 #, python-format msgid "%d submission were successfully rescored." msgid_plural "%d submissions were successfully rescored." @@ -405,8 +400,7 @@ msgstr[1] "" msgid "Rescore the selected submissions" msgstr "" -#: judge/admin/submission.py:200 templates/problem/list.html:216 -#: templates/problem/list.html:236 +#: judge/admin/submission.py:200 msgid "Problem code" msgstr "" @@ -414,12 +408,10 @@ msgstr "" msgid "Problem name" msgstr "" -#: judge/admin/submission.py:215 templates/notification/list.html:15 -#: templates/organization/requests/log.html:10 +#: judge/admin/submission.py:215 templates/organization/requests/log.html:10 #: templates/organization/requests/pending.html:13 -#: templates/problem/list.html:351 -#: templates/submission/status-testcases.html:125 -#: templates/submission/status-testcases.html:127 +#: templates/submission/status-testcases.html:105 +#: templates/submission/status-testcases.html:107 msgid "Time" msgstr "" @@ -433,7 +425,7 @@ msgstr "" msgid "%.2f MB" msgstr "" -#: judge/admin/submission.py:227 templates/submission/status-testcases.html:132 +#: judge/admin/submission.py:227 templates/submission/status-testcases.html:112 msgid "Memory" msgstr "" @@ -453,20 +445,20 @@ msgstr "" msgid "Online Judge" msgstr "" -#: judge/comments.py:60 +#: judge/comments.py:41 msgid "Comment body" msgstr "" -#: judge/comments.py:66 judge/views/ticket.py:63 +#: judge/comments.py:47 judge/views/ticket.py:46 msgid "Your part is silent, little toad." msgstr "" -#: judge/comments.py:69 templates/comments/list.html:132 +#: judge/comments.py:50 templates/comments/list.html:131 msgid "" "You need to have solved at least one problem before your voice can be heard." msgstr "" -#: judge/comments.py:113 +#: judge/comments.py:92 msgid "Posted comment" msgstr "" @@ -482,10 +474,6 @@ msgstr "" msgid "ECOO" msgstr "" -#: judge/contest_format/icpc.py:19 -msgid "ICPC" -msgstr "" - #: judge/contest_format/ioi.py:19 msgid "IOI" msgstr "" @@ -498,58 +486,52 @@ msgstr "" msgid "Enable experimental features" msgstr "" -#: judge/forms.py:57 judge/views/organization.py:168 judge/views/register.py:49 +#: judge/forms.py:57 judge/views/organization.py:127 #, python-brace-format msgid "You may not be part of more than {count} public organizations." msgstr "" -#: judge/forms.py:82 -msgid "Any judge" -msgstr "" - -#: judge/forms.py:112 judge/views/register.py:26 +#: judge/forms.py:107 judge/views/register.py:26 #: templates/registration/registration_form.html:139 #: templates/user/base-users-table.html:5 -#: templates/user/import/table_csv.html:4 msgid "Username" msgstr "" -#: judge/forms.py:113 templates/registration/registration_form.html:151 +#: judge/forms.py:108 templates/registration/registration_form.html:151 #: templates/registration/registration_form.html:165 -#: templates/user/import/table_csv.html:5 msgid "Password" msgstr "" -#: judge/forms.py:135 +#: judge/forms.py:130 msgid "Two Factor Authentication tokens must be 6 decimal digits." msgstr "" -#: judge/forms.py:144 templates/registration/totp_auth.html:32 +#: judge/forms.py:139 templates/registration/totp_auth.html:32 msgid "Invalid Two Factor Authentication token." msgstr "" -#: judge/forms.py:148 judge/models/problem.py:97 +#: judge/forms.py:143 judge/models/problem.py:97 msgid "Problem code must be ^[a-z0-9]+$" msgstr "" -#: judge/forms.py:153 +#: judge/forms.py:148 msgid "Problem with code already exists." msgstr "" -#: judge/forms.py:158 judge/models/contest.py:61 +#: judge/forms.py:153 judge/models/contest.py:52 msgid "Contest id must be ^[a-z0-9]+$" msgstr "" -#: judge/forms.py:163 +#: judge/forms.py:158 msgid "Contest with key already exists." msgstr "" -#: judge/jinja2/datetime.py:26 templates/blog/blog.html:26 +#: judge/jinja2/datetime.py:26 templates/blog/content.html:27 #: templates/blog/dashboard.html:21 msgid "N j, Y, g:i a" msgstr "" -#: judge/jinja2/datetime.py:26 templates/chat/message.html:13 +#: judge/jinja2/datetime.py:26 #, python-brace-format msgid "{time}" msgstr "" @@ -579,542 +561,472 @@ msgstr "" msgid "Detect best quality" msgstr "" -#: judge/models/comment.py:26 +#: judge/models/comment.py:25 msgid "Page code must be ^[pcs]:[a-z0-9]+$|^b:\\d+$" msgstr "" -#: judge/models/comment.py:42 +#: judge/models/comment.py:41 msgid "commenter" msgstr "" -#: judge/models/comment.py:44 judge/models/comment.py:177 +#: judge/models/comment.py:43 judge/models/comment.py:176 msgid "associated page" msgstr "" -#: judge/models/comment.py:46 +#: judge/models/comment.py:45 msgid "votes" msgstr "" -#: judge/models/comment.py:48 +#: judge/models/comment.py:47 msgid "hide the comment" msgstr "" -#: judge/models/comment.py:49 +#: judge/models/comment.py:48 msgid "parent" msgstr "" -#: judge/models/comment.py:54 judge/models/comment.py:192 +#: judge/models/comment.py:53 msgid "comment" msgstr "" -#: judge/models/comment.py:55 +#: judge/models/comment.py:54 msgid "comments" msgstr "" -#: judge/models/comment.py:137 judge/models/problem.py:443 +#: judge/models/comment.py:136 judge/models/problem.py:406 #, python-format msgid "Editorial for %s" msgstr "" -#: judge/models/comment.py:172 +#: judge/models/comment.py:171 msgid "comment vote" msgstr "" -#: judge/models/comment.py:173 +#: judge/models/comment.py:172 msgid "comment votes" msgstr "" -#: judge/models/comment.py:182 +#: judge/models/comment.py:181 msgid "Override comment lock" msgstr "" -#: judge/models/comment.py:190 -msgid "owner" -msgstr "" - -#: judge/models/comment.py:193 judge/models/message.py:16 -msgid "read" -msgstr "" - -#: judge/models/comment.py:194 -msgid "category" -msgstr "" - -#: judge/models/comment.py:195 -msgid "html link to comments, used for non-comments" -msgstr "" - -#: judge/models/comment.py:196 -msgid "who trigger, used for non-comment" -msgstr "" - -#: judge/models/contest.py:23 +#: judge/models/contest.py:22 msgid "Invalid colour." msgstr "" -#: judge/models/contest.py:25 +#: judge/models/contest.py:24 msgid "tag name" msgstr "" -#: judge/models/contest.py:26 +#: judge/models/contest.py:25 msgid "Lowercase letters and hyphens only." msgstr "" -#: judge/models/contest.py:27 +#: judge/models/contest.py:26 msgid "tag colour" msgstr "" -#: judge/models/contest.py:28 +#: judge/models/contest.py:27 msgid "tag description" msgstr "" -#: judge/models/contest.py:47 +#: judge/models/contest.py:46 msgid "contest tag" msgstr "" -#: judge/models/contest.py:48 judge/models/contest.py:118 +#: judge/models/contest.py:47 judge/models/contest.py:101 msgid "contest tags" msgstr "" -#: judge/models/contest.py:56 -msgid "Visible" -msgstr "" - -#: judge/models/contest.py:57 -msgid "Hidden for duration of contest" -msgstr "" - -#: judge/models/contest.py:58 -msgid "Hidden for duration of participation" -msgstr "" - -#: judge/models/contest.py:60 +#: judge/models/contest.py:51 msgid "contest id" msgstr "" -#: judge/models/contest.py:62 +#: judge/models/contest.py:53 msgid "contest name" msgstr "" -#: judge/models/contest.py:63 -msgid "These users will be able to edit the contest." +#: judge/models/contest.py:54 +msgid "These people will be able to edit the contest." msgstr "" -#: judge/models/contest.py:65 -msgid "" -"These users will be able to edit the contest, but will not be listed as " -"authors." -msgstr "" - -#: judge/models/contest.py:68 -msgid "These users will be able to view the contest, but not edit it." -msgstr "" - -#: judge/models/contest.py:71 judge/models/runtime.py:136 +#: judge/models/contest.py:56 judge/models/runtime.py:133 msgid "description" msgstr "" -#: judge/models/contest.py:72 judge/models/problem.py:390 -#: judge/models/runtime.py:138 +#: judge/models/contest.py:57 judge/models/problem.py:353 +#: judge/models/runtime.py:135 msgid "problems" msgstr "" -#: judge/models/contest.py:73 judge/models/contest.py:404 +#: judge/models/contest.py:58 judge/models/contest.py:258 msgid "start time" msgstr "" -#: judge/models/contest.py:74 +#: judge/models/contest.py:59 msgid "end time" msgstr "" -#: judge/models/contest.py:75 judge/models/problem.py:118 -#: judge/models/problem.py:414 +#: judge/models/contest.py:60 judge/models/problem.py:118 +#: judge/models/problem.py:377 msgid "time limit" msgstr "" -#: judge/models/contest.py:76 judge/models/problem.py:136 +#: judge/models/contest.py:61 judge/models/problem.py:136 msgid "publicly visible" msgstr "" -#: judge/models/contest.py:77 +#: judge/models/contest.py:62 msgid "" "Should be set even for organization-private contests, where it determines " "whether the contest is visible to members of the specified organizations." msgstr "" -#: judge/models/contest.py:80 +#: judge/models/contest.py:65 msgid "contest rated" msgstr "" -#: judge/models/contest.py:80 +#: judge/models/contest.py:65 msgid "Whether this contest can be rated." msgstr "" -#: judge/models/contest.py:82 -msgid "scoreboard visibility" +#: judge/models/contest.py:67 +msgid "hide scoreboard" msgstr "" -#: judge/models/contest.py:83 -msgid "Scoreboard visibility through the duration of the contest" +#: judge/models/contest.py:68 +msgid "" +"Whether the scoreboard should remain hidden for the duration of the contest." msgstr "" -#: judge/models/contest.py:85 -msgid "view contest scoreboard" -msgstr "" - -#: judge/models/contest.py:87 -msgid "These users will be able to view the scoreboard." -msgstr "" - -#: judge/models/contest.py:88 +#: judge/models/contest.py:71 msgid "no comments" msgstr "" -#: judge/models/contest.py:89 +#: judge/models/contest.py:72 msgid "Use clarification system instead of comments." msgstr "" -#: judge/models/contest.py:91 +#: judge/models/contest.py:74 msgid "Rating floor for contest" msgstr "" -#: judge/models/contest.py:93 +#: judge/models/contest.py:76 msgid "Rating ceiling for contest" msgstr "" -#: judge/models/contest.py:95 +#: judge/models/contest.py:78 msgid "rate all" msgstr "" -#: judge/models/contest.py:95 +#: judge/models/contest.py:78 msgid "Rate all users who joined." msgstr "" -#: judge/models/contest.py:96 +#: judge/models/contest.py:79 msgid "exclude from ratings" msgstr "" -#: judge/models/contest.py:98 +#: judge/models/contest.py:81 msgid "private to specific users" msgstr "" -#: judge/models/contest.py:99 +#: judge/models/contest.py:82 msgid "private contestants" msgstr "" -#: judge/models/contest.py:100 +#: judge/models/contest.py:83 msgid "If private, only these users may see the contest" msgstr "" -#: judge/models/contest.py:102 +#: judge/models/contest.py:85 msgid "hide problem tags" msgstr "" -#: judge/models/contest.py:103 +#: judge/models/contest.py:86 msgid "Whether problem tags should be hidden by default." msgstr "" -#: judge/models/contest.py:105 +#: judge/models/contest.py:88 msgid "run pretests only" msgstr "" -#: judge/models/contest.py:106 +#: judge/models/contest.py:89 msgid "" "Whether judges should grade pretests only, versus all testcases. Commonly " "set during a contest, then unset prior to rejudging user submissions when " "the contest ends." msgstr "" -#: judge/models/contest.py:110 judge/models/interface.py:77 -#: judge/models/problem.py:157 +#: judge/models/contest.py:93 judge/models/problem.py:157 msgid "private to organizations" msgstr "" -#: judge/models/contest.py:111 judge/models/interface.py:75 -#: judge/models/problem.py:155 judge/models/profile.py:77 +#: judge/models/contest.py:94 judge/models/problem.py:155 +#: judge/models/profile.py:77 msgid "organizations" msgstr "" -#: judge/models/contest.py:112 +#: judge/models/contest.py:95 msgid "If private, only these organizations may see the contest" msgstr "" -#: judge/models/contest.py:113 judge/models/problem.py:145 +#: judge/models/contest.py:96 judge/models/problem.py:145 msgid "OpenGraph image" msgstr "" -#: judge/models/contest.py:114 judge/models/profile.py:48 +#: judge/models/contest.py:97 judge/models/profile.py:48 msgid "Logo override image" msgstr "" -#: judge/models/contest.py:116 +#: judge/models/contest.py:99 msgid "" "This image will replace the default site logo for users inside the contest." msgstr "" -#: judge/models/contest.py:119 +#: judge/models/contest.py:102 msgid "the amount of live participants" msgstr "" -#: judge/models/contest.py:120 +#: judge/models/contest.py:103 msgid "contest summary" msgstr "" -#: judge/models/contest.py:121 judge/models/problem.py:147 +#: judge/models/contest.py:104 judge/models/problem.py:147 msgid "Plain-text, shown in meta description tag, e.g. for social media." msgstr "" -#: judge/models/contest.py:122 judge/models/profile.py:47 +#: judge/models/contest.py:105 judge/models/profile.py:47 msgid "access code" msgstr "" -#: judge/models/contest.py:123 +#: judge/models/contest.py:106 msgid "" "An optional code to prompt contestants before they are allowed to join the " "contest. Leave it blank to disable." msgstr "" -#: judge/models/contest.py:125 judge/models/problem.py:141 +#: judge/models/contest.py:108 judge/models/problem.py:141 msgid "personae non gratae" msgstr "" -#: judge/models/contest.py:126 +#: judge/models/contest.py:109 msgid "Bans the selected users from joining this contest." msgstr "" -#: judge/models/contest.py:127 +#: judge/models/contest.py:110 msgid "contest format" msgstr "" -#: judge/models/contest.py:128 +#: judge/models/contest.py:111 msgid "The contest format module to use." msgstr "" -#: judge/models/contest.py:129 +#: judge/models/contest.py:112 msgid "contest format configuration" msgstr "" -#: judge/models/contest.py:130 +#: judge/models/contest.py:113 msgid "" "A JSON object to serve as the configuration for the chosen contest format " "module. Leave empty to use None. Exact format depends on the contest format " "selected." msgstr "" -#: judge/models/contest.py:137 -msgid "precision points" -msgstr "" - -#: judge/models/contest.py:139 -msgid "Number of digits to round points to." -msgstr "" - -#: judge/models/contest.py:383 +#: judge/models/contest.py:239 msgid "See private contests" msgstr "" -#: judge/models/contest.py:384 +#: judge/models/contest.py:240 msgid "Edit own contests" msgstr "" -#: judge/models/contest.py:385 +#: judge/models/contest.py:241 msgid "Edit all contests" msgstr "" -#: judge/models/contest.py:386 +#: judge/models/contest.py:242 msgid "Clone contest" msgstr "" -#: judge/models/contest.py:387 templates/contest/moss.html:74 +#: judge/models/contest.py:243 templates/contest/moss.html:74 msgid "MOSS contest" msgstr "" -#: judge/models/contest.py:388 +#: judge/models/contest.py:244 msgid "Rate contests" msgstr "" -#: judge/models/contest.py:389 +#: judge/models/contest.py:245 msgid "Contest access codes" msgstr "" -#: judge/models/contest.py:390 +#: judge/models/contest.py:246 msgid "Create private contests" msgstr "" -#: judge/models/contest.py:391 -msgid "Change contest visibility" -msgstr "" - -#: judge/models/contest.py:392 -msgid "Edit contest problem label script" -msgstr "" - -#: judge/models/contest.py:394 judge/models/contest.py:492 -#: judge/models/contest.py:529 judge/models/contest.py:552 -#: judge/models/submission.py:84 +#: judge/models/contest.py:248 judge/models/contest.py:345 +#: judge/models/contest.py:382 judge/models/contest.py:404 +#: judge/models/submission.py:83 msgid "contest" msgstr "" -#: judge/models/contest.py:395 +#: judge/models/contest.py:249 msgid "contests" msgstr "" -#: judge/models/contest.py:402 +#: judge/models/contest.py:256 msgid "associated contest" msgstr "" -#: judge/models/contest.py:405 +#: judge/models/contest.py:259 msgid "score" msgstr "" -#: judge/models/contest.py:406 +#: judge/models/contest.py:260 msgid "cumulative time" msgstr "" -#: judge/models/contest.py:407 +#: judge/models/contest.py:261 msgid "is disqualified" msgstr "" -#: judge/models/contest.py:408 +#: judge/models/contest.py:262 msgid "Whether this participation is disqualified." msgstr "" -#: judge/models/contest.py:409 -msgid "tie-breaking field" -msgstr "" - -#: judge/models/contest.py:410 +#: judge/models/contest.py:263 msgid "virtual participation id" msgstr "" -#: judge/models/contest.py:411 +#: judge/models/contest.py:264 msgid "0 means non-virtual, otherwise the n-th virtual participation." msgstr "" -#: judge/models/contest.py:412 +#: judge/models/contest.py:265 msgid "contest format specific data" msgstr "" -#: judge/models/contest.py:478 +#: judge/models/contest.py:331 #, python-format msgid "%s spectating in %s" msgstr "" -#: judge/models/contest.py:480 +#: judge/models/contest.py:333 #, python-format msgid "%s in %s, v%d" msgstr "" -#: judge/models/contest.py:481 +#: judge/models/contest.py:334 #, python-format msgid "%s in %s" msgstr "" -#: judge/models/contest.py:484 +#: judge/models/contest.py:337 msgid "contest participation" msgstr "" -#: judge/models/contest.py:485 +#: judge/models/contest.py:338 msgid "contest participations" msgstr "" -#: judge/models/contest.py:491 judge/models/contest.py:513 -#: judge/models/contest.py:553 judge/models/problem.py:389 -#: judge/models/problem.py:394 judge/models/problem.py:412 -#: judge/models/problem_data.py:40 +#: judge/models/contest.py:344 judge/models/contest.py:366 +#: judge/models/contest.py:405 judge/models/problem.py:352 +#: judge/models/problem.py:357 judge/models/problem.py:375 +#: judge/models/problem_data.py:38 msgid "problem" msgstr "" -#: judge/models/contest.py:493 judge/models/contest.py:517 +#: judge/models/contest.py:346 judge/models/contest.py:370 #: judge/models/problem.py:129 msgid "points" msgstr "" -#: judge/models/contest.py:494 +#: judge/models/contest.py:347 msgid "partial" msgstr "" -#: judge/models/contest.py:495 judge/models/contest.py:518 +#: judge/models/contest.py:348 judge/models/contest.py:371 msgid "is pretested" msgstr "" -#: judge/models/contest.py:496 judge/models/interface.py:43 +#: judge/models/contest.py:349 judge/models/interface.py:43 msgid "order" msgstr "" -#: judge/models/contest.py:497 +#: judge/models/contest.py:350 msgid "0 to not show testcases, 1 to show" msgstr "" -#: judge/models/contest.py:498 +#: judge/models/contest.py:351 msgid "visible testcases" msgstr "" -#: judge/models/contest.py:499 +#: judge/models/contest.py:352 msgid "Maximum number of submissions for this problem, or 0 for no limit." msgstr "" -#: judge/models/contest.py:501 +#: judge/models/contest.py:354 msgid "Why include a problem you can't submit to?" msgstr "" -#: judge/models/contest.py:506 +#: judge/models/contest.py:359 msgid "contest problem" msgstr "" -#: judge/models/contest.py:507 +#: judge/models/contest.py:360 msgid "contest problems" msgstr "" -#: judge/models/contest.py:511 judge/models/submission.py:183 +#: judge/models/contest.py:364 judge/models/submission.py:181 msgid "submission" msgstr "" -#: judge/models/contest.py:515 judge/models/contest.py:530 +#: judge/models/contest.py:368 judge/models/contest.py:383 msgid "participation" msgstr "" -#: judge/models/contest.py:519 +#: judge/models/contest.py:372 msgid "Whether this submission was ran only on pretests." msgstr "" -#: judge/models/contest.py:523 +#: judge/models/contest.py:376 msgid "contest submission" msgstr "" -#: judge/models/contest.py:524 +#: judge/models/contest.py:377 msgid "contest submissions" msgstr "" -#: judge/models/contest.py:532 +#: judge/models/contest.py:385 msgid "rank" msgstr "" -#: judge/models/contest.py:533 +#: judge/models/contest.py:386 msgid "rating" msgstr "" -#: judge/models/contest.py:534 +#: judge/models/contest.py:387 msgid "volatility" msgstr "" -#: judge/models/contest.py:535 +#: judge/models/contest.py:388 msgid "last rated" msgstr "" -#: judge/models/contest.py:539 +#: judge/models/contest.py:392 msgid "contest rating" msgstr "" -#: judge/models/contest.py:540 +#: judge/models/contest.py:393 msgid "contest ratings" msgstr "" -#: judge/models/contest.py:560 +#: judge/models/contest.py:412 msgid "contest moss result" msgstr "" -#: judge/models/contest.py:561 +#: judge/models/contest.py:413 msgid "contest moss results" msgstr "" @@ -1154,7 +1066,7 @@ msgstr "" msgid "post title" msgstr "" -#: judge/models/interface.py:67 judge/models/problem.py:432 +#: judge/models/interface.py:67 judge/models/problem.py:395 msgid "authors" msgstr "" @@ -1162,7 +1074,7 @@ msgstr "" msgid "slug" msgstr "" -#: judge/models/interface.py:69 judge/models/problem.py:430 +#: judge/models/interface.py:69 judge/models/problem.py:393 msgid "public visibility" msgstr "" @@ -1186,19 +1098,15 @@ msgstr "" msgid "openGraph image" msgstr "" -#: judge/models/interface.py:76 -msgid "If private, only these organizations may see the blog post." -msgstr "" - -#: judge/models/interface.py:105 +#: judge/models/interface.py:91 msgid "Edit all posts" msgstr "" -#: judge/models/interface.py:107 +#: judge/models/interface.py:93 msgid "blog post" msgstr "" -#: judge/models/interface.py:108 +#: judge/models/interface.py:94 msgid "blog posts" msgstr "" @@ -1222,6 +1130,10 @@ msgstr "" msgid "message timestamp" msgstr "" +#: judge/models/message.py:16 +msgid "read" +msgstr "" + #: judge/models/message.py:20 msgid "messages in the thread" msgstr "" @@ -1358,7 +1270,7 @@ msgid "" "are supported." msgstr "" -#: judge/models/problem.py:123 judge/models/problem.py:417 +#: judge/models/problem.py:123 judge/models/problem.py:380 msgid "memory limit" msgstr "" @@ -1431,188 +1343,188 @@ msgstr "" msgid "If private, only these organizations may see the problem." msgstr "" -#: judge/models/problem.py:395 judge/models/problem.py:413 -#: judge/models/runtime.py:111 +#: judge/models/problem.py:358 judge/models/problem.py:376 +#: judge/models/runtime.py:108 msgid "language" msgstr "" -#: judge/models/problem.py:396 +#: judge/models/problem.py:359 msgid "translated name" msgstr "" -#: judge/models/problem.py:397 +#: judge/models/problem.py:360 msgid "translated description" msgstr "" -#: judge/models/problem.py:401 +#: judge/models/problem.py:364 msgid "problem translation" msgstr "" -#: judge/models/problem.py:402 +#: judge/models/problem.py:365 msgid "problem translations" msgstr "" -#: judge/models/problem.py:406 +#: judge/models/problem.py:369 msgid "clarified problem" msgstr "" -#: judge/models/problem.py:407 +#: judge/models/problem.py:370 msgid "clarification body" msgstr "" -#: judge/models/problem.py:408 +#: judge/models/problem.py:371 msgid "clarification timestamp" msgstr "" -#: judge/models/problem.py:423 +#: judge/models/problem.py:386 msgid "language-specific resource limit" msgstr "" -#: judge/models/problem.py:424 +#: judge/models/problem.py:387 msgid "language-specific resource limits" msgstr "" -#: judge/models/problem.py:428 +#: judge/models/problem.py:391 msgid "associated problem" msgstr "" -#: judge/models/problem.py:431 +#: judge/models/problem.py:394 msgid "publish date" msgstr "" -#: judge/models/problem.py:433 +#: judge/models/problem.py:396 msgid "editorial content" msgstr "" -#: judge/models/problem.py:449 +#: judge/models/problem.py:412 msgid "solution" msgstr "" -#: judge/models/problem.py:450 +#: judge/models/problem.py:413 msgid "solutions" msgstr "" -#: judge/models/problem_data.py:26 +#: judge/models/problem_data.py:24 msgid "Standard" msgstr "" -#: judge/models/problem_data.py:27 +#: judge/models/problem_data.py:25 msgid "Floats" msgstr "" -#: judge/models/problem_data.py:28 +#: judge/models/problem_data.py:26 msgid "Floats (absolute)" msgstr "" -#: judge/models/problem_data.py:29 +#: judge/models/problem_data.py:27 msgid "Floats (relative)" msgstr "" -#: judge/models/problem_data.py:30 +#: judge/models/problem_data.py:28 msgid "Non-trailing spaces" msgstr "" -#: judge/models/problem_data.py:31 +#: judge/models/problem_data.py:29 msgid "Unordered" msgstr "" -#: judge/models/problem_data.py:32 +#: judge/models/problem_data.py:30 msgid "Byte identical" msgstr "" -#: judge/models/problem_data.py:33 +#: judge/models/problem_data.py:31 msgid "Line-by-line" msgstr "" -#: judge/models/problem_data.py:34 +#: judge/models/problem_data.py:32 msgid "Custom checker (PY)" msgstr "" -#: judge/models/problem_data.py:35 +#: judge/models/problem_data.py:33 msgid "Custom validator (CPP)" msgstr "" -#: judge/models/problem_data.py:42 +#: judge/models/problem_data.py:40 msgid "data zip file" msgstr "" -#: judge/models/problem_data.py:44 +#: judge/models/problem_data.py:42 msgid "generator file" msgstr "" -#: judge/models/problem_data.py:46 judge/models/problem_data.py:121 +#: judge/models/problem_data.py:44 judge/models/problem_data.py:110 msgid "output prefix length" msgstr "" -#: judge/models/problem_data.py:47 judge/models/problem_data.py:122 +#: judge/models/problem_data.py:45 judge/models/problem_data.py:111 msgid "output limit length" msgstr "" -#: judge/models/problem_data.py:48 +#: judge/models/problem_data.py:46 msgid "init.yml generation feedback" msgstr "" -#: judge/models/problem_data.py:49 judge/models/problem_data.py:123 +#: judge/models/problem_data.py:47 judge/models/problem_data.py:112 msgid "checker" msgstr "" -#: judge/models/problem_data.py:50 judge/models/problem_data.py:124 +#: judge/models/problem_data.py:48 judge/models/problem_data.py:113 msgid "checker arguments" msgstr "" -#: judge/models/problem_data.py:51 judge/models/problem_data.py:125 +#: judge/models/problem_data.py:49 judge/models/problem_data.py:114 msgid "checker arguments as a JSON object" msgstr "" -#: judge/models/problem_data.py:52 +#: judge/models/problem_data.py:50 msgid "custom checker file" msgstr "" -#: judge/models/problem_data.py:58 +#: judge/models/problem_data.py:56 msgid "custom validator file" msgstr "" -#: judge/models/problem_data.py:108 +#: judge/models/problem_data.py:97 msgid "problem data set" msgstr "" -#: judge/models/problem_data.py:110 +#: judge/models/problem_data.py:99 msgid "case position" msgstr "" -#: judge/models/problem_data.py:111 +#: judge/models/problem_data.py:100 msgid "case type" msgstr "" -#: judge/models/problem_data.py:112 +#: judge/models/problem_data.py:101 msgid "Normal case" msgstr "" -#: judge/models/problem_data.py:113 +#: judge/models/problem_data.py:102 msgid "Batch start" msgstr "" -#: judge/models/problem_data.py:114 +#: judge/models/problem_data.py:103 msgid "Batch end" msgstr "" -#: judge/models/problem_data.py:116 +#: judge/models/problem_data.py:105 msgid "input file name" msgstr "" -#: judge/models/problem_data.py:117 +#: judge/models/problem_data.py:106 msgid "output file name" msgstr "" -#: judge/models/problem_data.py:118 +#: judge/models/problem_data.py:107 msgid "generator arguments" msgstr "" -#: judge/models/problem_data.py:119 +#: judge/models/problem_data.py:108 msgid "point value" msgstr "" -#: judge/models/problem_data.py:120 +#: judge/models/problem_data.py:109 msgid "case is pretest?" msgstr "" @@ -1685,7 +1597,7 @@ msgid "" msgstr "" #: judge/models/profile.py:76 judge/models/profile.py:93 -#: judge/models/profile.py:212 +#: judge/models/profile.py:192 msgid "organization" msgstr "" @@ -1781,31 +1693,31 @@ msgstr "" msgid "Notes for administrators regarding this user." msgstr "" -#: judge/models/profile.py:206 +#: judge/models/profile.py:186 msgid "user profile" msgstr "" -#: judge/models/profile.py:207 +#: judge/models/profile.py:187 msgid "user profiles" msgstr "" -#: judge/models/profile.py:214 +#: judge/models/profile.py:194 msgid "request time" msgstr "" -#: judge/models/profile.py:215 +#: judge/models/profile.py:195 msgid "state" msgstr "" -#: judge/models/profile.py:220 +#: judge/models/profile.py:200 msgid "reason" msgstr "" -#: judge/models/profile.py:223 +#: judge/models/profile.py:203 msgid "organization join request" msgstr "" -#: judge/models/profile.py:224 +#: judge/models/profile.py:204 msgid "organization join requests" msgstr "" @@ -1896,86 +1808,86 @@ msgstr "" msgid "The extension of source files, e.g., \"py\" or \"cpp\"." msgstr "" -#: judge/models/runtime.py:112 +#: judge/models/runtime.py:109 msgid "languages" msgstr "" -#: judge/models/runtime.py:116 +#: judge/models/runtime.py:113 msgid "language to which this runtime belongs" msgstr "" -#: judge/models/runtime.py:117 +#: judge/models/runtime.py:114 msgid "judge on which this runtime exists" msgstr "" -#: judge/models/runtime.py:118 +#: judge/models/runtime.py:115 msgid "runtime name" msgstr "" -#: judge/models/runtime.py:119 +#: judge/models/runtime.py:116 msgid "runtime version" msgstr "" -#: judge/models/runtime.py:120 +#: judge/models/runtime.py:117 msgid "order in which to display this runtime" msgstr "" -#: judge/models/runtime.py:124 +#: judge/models/runtime.py:121 msgid "Server name, hostname-style" msgstr "" -#: judge/models/runtime.py:125 +#: judge/models/runtime.py:122 msgid "time of creation" msgstr "" -#: judge/models/runtime.py:126 +#: judge/models/runtime.py:123 msgid "A key to authenticate this judge" msgstr "" -#: judge/models/runtime.py:127 +#: judge/models/runtime.py:124 msgid "authentication key" msgstr "" -#: judge/models/runtime.py:128 +#: judge/models/runtime.py:125 msgid "block judge" msgstr "" -#: judge/models/runtime.py:129 +#: judge/models/runtime.py:126 msgid "" "Whether this judge should be blocked from connecting, even if its key is " "correct." msgstr "" -#: judge/models/runtime.py:131 +#: judge/models/runtime.py:128 msgid "judge online status" msgstr "" -#: judge/models/runtime.py:132 +#: judge/models/runtime.py:129 msgid "judge start time" msgstr "" -#: judge/models/runtime.py:133 +#: judge/models/runtime.py:130 msgid "response time" msgstr "" -#: judge/models/runtime.py:134 +#: judge/models/runtime.py:131 msgid "system load" msgstr "" -#: judge/models/runtime.py:135 +#: judge/models/runtime.py:132 msgid "Load for the last minute, divided by processors to be fair." msgstr "" -#: judge/models/runtime.py:139 judge/models/runtime.py:179 +#: judge/models/runtime.py:136 judge/models/runtime.py:176 msgid "judges" msgstr "" -#: judge/models/runtime.py:178 +#: judge/models/runtime.py:175 msgid "judge" msgstr "" #: judge/models/submission.py:20 judge/models/submission.py:47 -#: judge/utils/problems.py:79 +#: judge/utils/problems.py:77 msgid "Accepted" msgstr "" @@ -2004,7 +1916,7 @@ msgid "Runtime Error" msgstr "" #: judge/models/submission.py:27 judge/models/submission.py:41 -#: judge/models/submission.py:55 judge/utils/problems.py:81 +#: judge/models/submission.py:55 judge/utils/problems.py:79 msgid "Compile Error" msgstr "" @@ -2045,15 +1957,15 @@ msgstr "" msgid "submission time" msgstr "" -#: judge/models/submission.py:67 judge/models/submission.py:203 +#: judge/models/submission.py:67 judge/models/submission.py:201 msgid "execution time" msgstr "" -#: judge/models/submission.py:68 judge/models/submission.py:204 +#: judge/models/submission.py:68 judge/models/submission.py:202 msgid "memory usage" msgstr "" -#: judge/models/submission.py:69 judge/models/submission.py:205 +#: judge/models/submission.py:69 judge/models/submission.py:203 msgid "points granted" msgstr "" @@ -2090,62 +2002,58 @@ msgid "judged on" msgstr "" #: judge/models/submission.py:81 -msgid "submission judge time" -msgstr "" - -#: judge/models/submission.py:82 msgid "was rejudged by admin" msgstr "" -#: judge/models/submission.py:83 +#: judge/models/submission.py:82 msgid "was ran on pretests only" msgstr "" -#: judge/models/submission.py:184 templates/contest/moss.html:58 +#: judge/models/submission.py:182 templates/contest/moss.html:58 msgid "submissions" msgstr "" -#: judge/models/submission.py:188 judge/models/submission.py:199 +#: judge/models/submission.py:186 judge/models/submission.py:197 msgid "associated submission" msgstr "" -#: judge/models/submission.py:190 +#: judge/models/submission.py:188 msgid "source code" msgstr "" -#: judge/models/submission.py:201 +#: judge/models/submission.py:199 msgid "test case ID" msgstr "" -#: judge/models/submission.py:202 +#: judge/models/submission.py:200 msgid "status flag" msgstr "" -#: judge/models/submission.py:206 +#: judge/models/submission.py:204 msgid "points possible" msgstr "" -#: judge/models/submission.py:207 +#: judge/models/submission.py:205 msgid "batch number" msgstr "" -#: judge/models/submission.py:208 +#: judge/models/submission.py:206 msgid "judging feedback" msgstr "" -#: judge/models/submission.py:209 +#: judge/models/submission.py:207 msgid "extended judging feedback" msgstr "" -#: judge/models/submission.py:210 +#: judge/models/submission.py:208 msgid "program output" msgstr "" -#: judge/models/submission.py:218 +#: judge/models/submission.py:216 msgid "submission test case" msgstr "" -#: judge/models/submission.py:219 +#: judge/models/submission.py:217 msgid "submission test cases" msgstr "" @@ -2197,21 +2105,12 @@ msgstr "" msgid "message time" msgstr "" -#: judge/pdf_problems.py:147 judge/pdf_problems.py:199 -#: judge/pdf_problems.py:259 +#: judge/pdf_problems.py:134 judge/pdf_problems.py:186 +#: judge/pdf_problems.py:246 msgid "Page [page] of [topage]" msgstr "" -#: judge/pdf_problems.py:280 -#, python-format -msgid "Page %s of %s" -msgstr "" - -#: judge/tasks/contest.py:19 -msgid "Recalculating contest scores" -msgstr "" - -#: judge/tasks/contest.py:40 +#: judge/tasks/moss.py:25 msgid "Running MOSS" msgstr "" @@ -2223,60 +2122,60 @@ msgstr "" msgid "Recalculating user points" msgstr "" -#: judge/utils/problem_data.py:70 +#: judge/utils/problem_data.py:68 msgid "Empty batches not allowed." msgstr "" -#: judge/utils/problem_data.py:78 judge/utils/problem_data.py:99 +#: judge/utils/problem_data.py:76 judge/utils/problem_data.py:97 msgid "How did you corrupt the custom checker path?" msgstr "" -#: judge/utils/problem_data.py:120 +#: judge/utils/problem_data.py:118 #, python-format msgid "Points must be defined for non-batch case #%d." msgstr "" -#: judge/utils/problem_data.py:125 +#: judge/utils/problem_data.py:123 #, python-format msgid "Input file for case %d does not exist: %s" msgstr "" -#: judge/utils/problem_data.py:128 +#: judge/utils/problem_data.py:126 #, python-format msgid "Output file for case %d does not exist: %s" msgstr "" -#: judge/utils/problem_data.py:153 +#: judge/utils/problem_data.py:151 #, python-format msgid "Batch start case #%d requires points." msgstr "" -#: judge/utils/problem_data.py:174 +#: judge/utils/problem_data.py:172 #, python-format msgid "Attempt to end batch outside of one in case #%d" msgstr "" -#: judge/utils/problem_data.py:192 +#: judge/utils/problem_data.py:190 msgid "How did you corrupt the zip path?" msgstr "" -#: judge/utils/problem_data.py:198 +#: judge/utils/problem_data.py:196 msgid "How did you corrupt the generator path?" msgstr "" -#: judge/utils/problems.py:80 +#: judge/utils/problems.py:78 msgid "Wrong" msgstr "" -#: judge/utils/problems.py:82 +#: judge/utils/problems.py:80 msgid "Timeout" msgstr "" -#: judge/utils/problems.py:83 +#: judge/utils/problems.py:81 msgid "Error" msgstr "" -#: judge/utils/problems.py:94 +#: judge/utils/problems.py:92 msgid "Can't pass both queryset and keyword filters" msgstr "" @@ -2319,8 +2218,7 @@ msgctxt "hours and minutes" msgid "%h:%m" msgstr "" -#: judge/views/about.py:7 templates/organization/home.html:112 -#: templates/user/user-about.html:83 templates/user/user-tabs.html:4 +#: judge/views/about.py:7 templates/user/user-about.html:33 msgid "About" msgstr "" @@ -2328,165 +2226,156 @@ msgstr "" msgid "Custom Checker Sample" msgstr "" -#: judge/views/blog.py:45 +#: judge/views/blog.py:38 #, python-format msgid "Page %d of Posts" msgstr "" -#: judge/views/comment.py:28 +#: judge/views/comment.py:27 msgid "Messing around, are we?" msgstr "" -#: judge/views/comment.py:37 +#: judge/views/comment.py:36 msgid "You must solve at least one problem before you can vote." msgstr "" -#: judge/views/comment.py:64 +#: judge/views/comment.py:63 msgid "You already voted." msgstr "" -#: judge/views/comment.py:126 judge/views/organization.py:344 +#: judge/views/comment.py:120 judge/views/organization.py:299 msgid "Edited from site" msgstr "" -#: judge/views/comment.py:147 +#: judge/views/comment.py:141 msgid "Editing comment" msgstr "" -#: judge/views/contests.py:57 judge/views/contests.py:247 -#: judge/views/contests.py:250 judge/views/contests.py:424 +#: judge/views/contests.py:55 judge/views/contests.py:215 +#: judge/views/contests.py:218 judge/views/contests.py:389 msgid "No such contest" msgstr "" -#: judge/views/contests.py:58 judge/views/contests.py:248 +#: judge/views/contests.py:56 judge/views/contests.py:216 #, python-format msgid "Could not find a contest with the key \"%s\"." msgstr "" -#: judge/views/contests.py:71 +#: judge/views/contests.py:81 msgid "Contests" msgstr "" -#: judge/views/contests.py:251 +#: judge/views/contests.py:219 msgid "Could not find such contest." msgstr "" -#: judge/views/contests.py:254 +#: judge/views/contests.py:222 #, python-format msgid "Access to contest \"%s\" denied" msgstr "" -#: judge/views/contests.py:278 +#: judge/views/contests.py:246 msgid "Clone Contest" msgstr "" -#: judge/views/contests.py:343 +#: judge/views/contests.py:309 msgid "Contest not ongoing" msgstr "" -#: judge/views/contests.py:344 +#: judge/views/contests.py:310 #, python-format msgid "\"%s\" is not currently ongoing." msgstr "" -#: judge/views/contests.py:348 +#: judge/views/contests.py:314 msgid "Already in contest" msgstr "" -#: judge/views/contests.py:349 +#: judge/views/contests.py:315 #, python-format msgid "You are already in a contest: \"%s\"." msgstr "" -#: judge/views/contests.py:352 +#: judge/views/contests.py:318 msgid "Banned from joining" msgstr "" -#: judge/views/contests.py:353 +#: judge/views/contests.py:319 msgid "" "You have been declared persona non grata for this contest. You are " "permanently barred from joining this contest." msgstr "" -#: judge/views/contests.py:414 +#: judge/views/contests.py:379 #, python-format msgid "Enter access code for \"%s\"" msgstr "" -#: judge/views/contests.py:425 +#: judge/views/contests.py:390 #, python-format msgid "You are not in contest \"%s\"." msgstr "" -#: judge/views/contests.py:444 +#: judge/views/contests.py:409 msgid "ContestCalendar requires integer year and month" msgstr "" -#: judge/views/contests.py:484 +#: judge/views/contests.py:449 #, python-format msgid "Contests in %(month)s" msgstr "" -#: judge/views/contests.py:484 +#: judge/views/contests.py:449 msgid "F Y" msgstr "" -#: judge/views/contests.py:532 +#: judge/views/contests.py:496 #, python-format msgid "%s Statistics" msgstr "" -#: judge/views/contests.py:717 +#: judge/views/contests.py:601 +msgid "???" +msgstr "" + +#: judge/views/contests.py:664 #, python-format msgid "%s Rankings" msgstr "" -#: judge/views/contests.py:725 -msgid "???" -msgstr "" - -#: judge/views/contests.py:741 +#: judge/views/contests.py:680 #, python-format msgid "Your participation in %s" msgstr "" -#: judge/views/contests.py:742 +#: judge/views/contests.py:681 #, python-format msgid "%s's participation in %s" msgstr "" -#: judge/views/contests.py:749 +#: judge/views/contests.py:685 msgid "Live" msgstr "" -#: judge/views/contests.py:761 templates/contest/contest-tabs.html:13 +#: judge/views/contests.py:697 msgid "Participation" msgstr "" -#: judge/views/contests.py:808 +#: judge/views/contests.py:743 #, python-format msgid "%s MOSS Results" msgstr "" -#: judge/views/contests.py:835 +#: judge/views/contests.py:770 #, python-format msgid "Running MOSS for %s..." msgstr "" -#: judge/views/contests.py:858 +#: judge/views/contests.py:793 #, python-format msgid "Contest tag: %s" msgstr "" -#: judge/views/contests.py:868 judge/views/ticket.py:57 -msgid "Issue description" -msgstr "" - -#: judge/views/contests.py:911 -#, python-format -msgid "New clarification for %s" -msgstr "" - #: judge/views/error.py:14 msgid "404 error" msgstr "" @@ -2507,122 +2396,115 @@ msgid "corrupt page %s" msgstr "" #: judge/views/language.py:12 templates/status/judge-status-table.html:9 -#: templates/status/status-tabs.html:5 msgid "Runtimes" msgstr "" -#: judge/views/notification.py:40 -#, python-format -msgid "Notifications (%d unseen)" -msgstr "" - -#: judge/views/organization.py:59 judge/views/organization.py:62 +#: judge/views/organization.py:44 judge/views/organization.py:47 msgid "No such organization" msgstr "" -#: judge/views/organization.py:60 +#: judge/views/organization.py:45 #, python-format msgid "Could not find an organization with the key \"%s\"." msgstr "" -#: judge/views/organization.py:63 +#: judge/views/organization.py:48 msgid "Could not find such organization." msgstr "" -#: judge/views/organization.py:79 judge/views/register.py:34 -#: templates/organization/list.html:32 templates/user/import/table_csv.html:9 -#: templates/user/user-list-tabs.html:6 +#: judge/views/organization.py:72 judge/views/register.py:34 +#: templates/organization/list.html:15 msgid "Organizations" msgstr "" -#: judge/views/organization.py:130 +#: judge/views/organization.py:93 #, python-format msgid "%s Members" msgstr "" -#: judge/views/organization.py:159 judge/views/organization.py:162 -#: judge/views/organization.py:167 +#: judge/views/organization.py:118 judge/views/organization.py:121 +#: judge/views/organization.py:126 msgid "Joining organization" msgstr "" -#: judge/views/organization.py:159 +#: judge/views/organization.py:118 msgid "You are already in the organization." msgstr "" -#: judge/views/organization.py:162 +#: judge/views/organization.py:121 msgid "This organization is not open." msgstr "" -#: judge/views/organization.py:179 +#: judge/views/organization.py:138 msgid "Leaving organization" msgstr "" -#: judge/views/organization.py:179 +#: judge/views/organization.py:138 #, python-format msgid "You are not in \"%s\"." msgstr "" -#: judge/views/organization.py:203 +#: judge/views/organization.py:162 #, python-format msgid "Request to join %s" msgstr "" -#: judge/views/organization.py:221 +#: judge/views/organization.py:180 msgid "Join request detail" msgstr "" -#: judge/views/organization.py:254 +#: judge/views/organization.py:209 #, python-format msgid "Managing join requests for %s" msgstr "" -#: judge/views/organization.py:285 +#: judge/views/organization.py:240 #, python-format msgid "" "Your organization can only receive %d more members. You cannot approve %d " "users." msgstr "" -#: judge/views/organization.py:297 +#: judge/views/organization.py:252 #, python-format msgid "Approved %d user." msgid_plural "Approved %d users." msgstr[0] "" msgstr[1] "" -#: judge/views/organization.py:298 +#: judge/views/organization.py:253 #, python-format msgid "Rejected %d user." msgid_plural "Rejected %d users." msgstr[0] "" msgstr[1] "" -#: judge/views/organization.py:328 +#: judge/views/organization.py:283 #, python-format msgid "Editing %s" msgstr "" -#: judge/views/organization.py:352 judge/views/organization.py:360 +#: judge/views/organization.py:307 judge/views/organization.py:315 msgid "Can't edit organization" msgstr "" -#: judge/views/organization.py:353 +#: judge/views/organization.py:308 msgid "You are not allowed to edit this organization." msgstr "" -#: judge/views/organization.py:361 +#: judge/views/organization.py:316 msgid "You are not allowed to kick people from this organization." msgstr "" -#: judge/views/organization.py:366 judge/views/organization.py:370 +#: judge/views/organization.py:321 judge/views/organization.py:325 msgid "Can't kick user" msgstr "" -#: judge/views/organization.py:367 +#: judge/views/organization.py:322 msgid "The user you are trying to kick does not exist!" msgstr "" -#: judge/views/organization.py:371 +#: judge/views/organization.py:326 #, python-format msgid "The user you are trying to kick is not in organization: %s." msgstr "" @@ -2646,36 +2528,35 @@ msgstr "" msgid "Editorial for {0}" msgstr "" -#: judge/views/problem.py:285 templates/contest/contest.html:79 -#: templates/user/user-about.html:28 templates/user/user-tabs.html:5 -#: templates/user/users-table.html:31 +#: judge/views/problem.py:286 templates/contest/contest.html:79 +#: templates/user/users-table.html:23 msgid "Problems" msgstr "" -#: judge/views/problem.py:585 +#: judge/views/problem.py:547 msgid "Banned from submitting" msgstr "" -#: judge/views/problem.py:586 +#: judge/views/problem.py:548 msgid "" "You have been declared persona non grata for this problem. You are " "permanently barred from submitting this problem." msgstr "" -#: judge/views/problem.py:600 +#: judge/views/problem.py:562 msgid "Too many submissions" msgstr "" -#: judge/views/problem.py:601 +#: judge/views/problem.py:563 msgid "You have exceeded the submission limit for this problem." msgstr "" -#: judge/views/problem.py:661 judge/views/problem.py:664 +#: judge/views/problem.py:633 judge/views/problem.py:636 #, python-format msgid "Submit to %(problem)s" msgstr "" -#: judge/views/problem.py:679 +#: judge/views/problem.py:652 msgid "Clone Problem" msgstr "" @@ -2716,22 +2597,22 @@ msgstr "" msgid "Generated init.yml for %s" msgstr "" -#: judge/views/problem_manage.py:52 judge/views/problem_manage.py:55 +#: judge/views/problem_manage.py:50 judge/views/problem_manage.py:53 #, python-format msgid "Managing submissions for %s" msgstr "" -#: judge/views/problem_manage.py:97 +#: judge/views/problem_manage.py:95 #, python-format msgid "Rejudging selected submissions for %s..." msgstr "" -#: judge/views/problem_manage.py:141 +#: judge/views/problem_manage.py:110 #, python-format msgid "Rescoring all submissions for %s..." msgstr "" -#: judge/views/problem_manage.py:150 +#: judge/views/problem_manage.py:119 #, python-format msgid "Successfully scheduled %d submission for rejudging." msgid_plural "Successfully scheduled %d submissions for rejudging." @@ -2780,24 +2661,24 @@ msgstr "" msgid "Subscribe to newsletter?" msgstr "" -#: judge/views/register.py:55 +#: judge/views/register.py:45 #, python-format msgid "" "The email address \"%s\" is already taken. Only one registration is allowed " "per address." msgstr "" -#: judge/views/register.py:61 +#: judge/views/register.py:51 msgid "" "Your email provider is not allowed due to history of abuse. Please use a " "reputable email provider." msgstr "" -#: judge/views/register.py:67 judge/views/register.py:105 +#: judge/views/register.py:57 judge/views/register.py:95 msgid "Registration" msgstr "" -#: judge/views/register.py:116 +#: judge/views/register.py:106 msgid "Authentication failure" msgstr "" @@ -2813,100 +2694,104 @@ msgstr "" msgid "Version matrix" msgstr "" -#: judge/views/submission.py:84 judge/views/submission.py:91 +#: judge/views/submission.py:83 judge/views/submission.py:90 #, python-format msgid "Submission of %(problem)s by %(user)s" msgstr "" -#: judge/views/submission.py:244 judge/views/submission.py:245 -#: templates/problem/problem.html:167 +#: judge/views/submission.py:227 judge/views/submission.py:228 +#: templates/problem/problem.html:127 msgid "All submissions" msgstr "" -#: judge/views/submission.py:404 +#: judge/views/submission.py:384 msgid "All my submissions" msgstr "" -#: judge/views/submission.py:405 +#: judge/views/submission.py:385 #, python-format msgid "All submissions by %s" msgstr "" -#: judge/views/submission.py:436 +#: judge/views/submission.py:416 #, python-format msgid "All submissions for %s" msgstr "" -#: judge/views/submission.py:455 +#: judge/views/submission.py:435 msgid "Must pass a problem" msgstr "" -#: judge/views/submission.py:501 +#: judge/views/submission.py:481 #, python-format msgid "My submissions for %(problem)s" msgstr "" -#: judge/views/submission.py:502 +#: judge/views/submission.py:482 #, python-format msgid "%(user)s's submissions for %(problem)s" msgstr "" -#: judge/views/submission.py:603 +#: judge/views/submission.py:583 msgid "Must pass a contest" msgstr "" -#: judge/views/submission.py:622 +#: judge/views/submission.py:602 #, python-brace-format msgid "" "{0}'s submissions for {2} in {4}" msgstr "" -#: judge/views/submission.py:629 +#: judge/views/submission.py:609 #, python-brace-format msgid "" "{0}'s submissions for problem {2} in {3}" "" msgstr "" -#: judge/views/ticket.py:50 judge/views/ticket.py:56 +#: judge/views/ticket.py:33 judge/views/ticket.py:39 msgid "Ticket title" msgstr "" -#: judge/views/ticket.py:107 judge/views/ticket.py:110 +#: judge/views/ticket.py:40 +msgid "Issue description" +msgstr "" + +#: judge/views/ticket.py:85 judge/views/ticket.py:88 #, python-format msgid "New ticket for %s" msgstr "" -#: judge/views/ticket.py:170 +#: judge/views/ticket.py:142 #, python-format msgid "%(title)s - Ticket %(id)d" msgstr "" -#: judge/views/ticket.py:279 +#: judge/views/ticket.py:251 #, python-format msgid "Tickets - Page %(number)d of %(total)d" msgstr "" -#: judge/views/ticket.py:328 +#: judge/views/ticket.py:300 #, python-format msgid "New Ticket: %s" msgstr "" -#: judge/views/ticket.py:329 +#: judge/views/ticket.py:301 #, python-format msgid "#%(id)d, assigned to: %(users)s" msgstr "" -#: judge/views/ticket.py:331 +#: judge/views/ticket.py:303 msgid ", " msgstr "" -#: judge/views/ticket.py:331 +#: judge/views/ticket.py:303 msgid "no one" msgstr "" -#: judge/views/ticket.py:351 +#: judge/views/ticket.py:323 #, python-format msgid "New Ticket Message For: %s" msgstr "" @@ -2923,50 +2808,41 @@ msgstr "" msgid "Perform Two Factor Authentication" msgstr "" -#: judge/views/user.py:74 +#: judge/views/user.py:68 msgid "No such user" msgstr "" -#: judge/views/user.py:74 +#: judge/views/user.py:68 #, python-format msgid "No user handle \"%s\"." msgstr "" -#: judge/views/user.py:78 +#: judge/views/user.py:72 msgid "My account" msgstr "" -#: judge/views/user.py:79 +#: judge/views/user.py:73 #, python-format msgid "User %s" msgstr "" -#: judge/views/user.py:148 -msgid "M j, Y" -msgstr "" - -#: judge/views/user.py:171 +#: judge/views/user.py:136 msgid "M j, Y, G:i" msgstr "" -#: judge/views/user.py:290 +#: judge/views/user.py:221 msgid "Updated on site" msgstr "" -#: judge/views/user.py:323 templates/admin/auth/user/change_form.html:14 -#: templates/admin/auth/user/change_form.html:17 templates/base.html:238 -#: templates/user/user-tabs.html:10 +#: judge/views/user.py:254 templates/admin/auth/user/change_form.html:14 +#: templates/admin/auth/user/change_form.html:17 templates/base.html:224 msgid "Edit profile" msgstr "" -#: judge/views/user.py:332 templates/user/user-list-tabs.html:4 +#: judge/views/user.py:263 msgid "Leaderboard" msgstr "" -#: judge/views/user.py:407 -msgid "Import Users" -msgstr "" - #: judge/views/widgets.py:48 judge/views/widgets.py:58 #, python-format msgid "Invalid upstream data: %s" @@ -3004,7 +2880,7 @@ msgid "View Submissions" msgstr "" #: templates/admin/judge/problem/change_form.html:17 -#: templates/user/user-base.html:112 +#: templates/user/user-base.html:61 msgid "View submissions" msgstr "" @@ -3019,145 +2895,90 @@ msgstr "" msgid "Rejudge" msgstr "" -#: templates/base.html:230 -#, python-format -msgid "Hello, %(username)s." -msgstr "" - -#: templates/base.html:236 templates/comments/list.html:89 -#: templates/contest/contest-list-tabs.html:24 -#: templates/contest/ranking-table.html:53 -#: templates/problem/problem-list-tabs.html:6 +#: templates/base.html:222 templates/comments/list.html:89 +#: templates/contest/ranking-table.html:39 #: templates/submission/info-base.html:12 -#: templates/submission/submission-list-tabs.html:15 msgid "Admin" msgstr "" -#: templates/base.html:245 +#: templates/base.html:231 msgid "Log out" msgstr "" -#: templates/base.html:254 +#: templates/base.html:240 #: templates/registration/password_reset_complete.html:4 msgid "Log in" msgstr "" -#: templates/base.html:255 templates/registration/registration_form.html:177 +#: templates/base.html:241 templates/registration/registration_form.html:177 msgid "or" msgstr "" -#: templates/base.html:256 +#: templates/base.html:242 msgid "Sign up" msgstr "" -#: templates/base.html:271 +#: templates/base.html:254 msgid "spectating" msgstr "" -#: templates/base.html:284 +#: templates/base.html:267 msgid "This site works best with JavaScript enabled." msgstr "" -#: templates/blog/blog.html:13 templates/comments/list.html:68 -#: templates/comments/list.html:83 templates/contest/contest-tabs.html:23 -#: templates/contest/tag-title.html:9 templates/flatpages/admin_link.html:3 -#: templates/license.html:10 templates/problem/editorial.html:14 +#: templates/blog/content.html:13 templates/comments/list.html:68 +#: templates/comments/list.html:83 templates/contest/tag-title.html:9 +#: templates/flatpages/admin_link.html:3 templates/license.html:10 +#: templates/problem/editorial.html:14 msgid "Edit" msgstr "" -#: templates/blog/blog.html:26 -#, python-format -msgid "" -"\n" -" posted on %(time)s\n" -" " -msgstr "" - -#: templates/blog/content.html:10 -#, python-brace-format -msgid "posted on {time}" -msgstr "" - -#: templates/blog/dashboard.html:21 -#, python-format -msgid "" -"\n" -" on %(time)s\n" -" " -msgstr "" - -#: templates/blog/list.html:93 +#: templates/blog/list.html:85 msgid "Blog" msgstr "" -#: templates/blog/list.html:95 +#: templates/blog/list.html:87 msgid "Events" msgstr "" -#: templates/blog/list.html:100 +#: templates/blog/list.html:92 msgid "News" msgstr "" -#: templates/blog/list.html:115 templates/problem/list.html:347 -#: templates/problem/problem.html:361 +#: templates/blog/list.html:130 templates/problem/problem.html:310 msgid "Clarifications" msgstr "" -#: templates/blog/list.html:121 -msgid "Add" -msgstr "" - -#: templates/blog/list.html:140 templates/problem/list.html:369 -#: templates/problem/problem.html:372 +#: templates/blog/list.html:146 templates/problem/problem.html:321 msgid "No clarifications have been made at this time." msgstr "" -#: templates/blog/list.html:148 +#: templates/blog/list.html:154 msgid "Ongoing contests" msgstr "" -#: templates/blog/list.html:166 +#: templates/blog/list.html:172 msgid "Upcoming contests" msgstr "" -#: templates/blog/list.html:184 -msgid "My open tickets" -msgstr "" - -#: templates/blog/list.html:206 -msgid "New tickets" -msgstr "" - -#: templates/blog/list.html:227 -msgid "New problems" -msgstr "" - -#: templates/blog/list.html:244 +#: templates/blog/list.html:189 msgid "Comment stream" msgstr "" -#: templates/chat/chat.html:305 -msgid "Chat" +#: templates/blog/list.html:208 +msgid "New problems" msgstr "" -#: templates/chat/chat.html:307 templates/chat/chat.html:314 -msgid "Online Users" +#: templates/blog/list.html:225 +msgid "My open tickets" msgstr "" -#: templates/chat/chat.html:315 -msgid "Refresh" +#: templates/blog/list.html:246 +msgid "New tickets" msgstr "" -#: templates/chat/chat.html:333 -msgid "Emoji" -msgstr "" - -#: templates/chat/chat.html:334 -msgid "Enter your message" -msgstr "" - -#: templates/chat/message.html:20 -msgid "Delete" +#: templates/chat/chat.html:167 +msgid "Your message" msgstr "" #: templates/comments/list.html:2 @@ -3168,21 +2989,11 @@ msgstr "" msgid "Please login to vote" msgstr "" -#: templates/comments/list.html:40 -#, python-brace-format -msgid "commented on {time}" -msgstr "" - -#: templates/comments/list.html:49 -#, python-format -msgid "edit %(edits)s" -msgstr "" - -#: templates/comments/list.html:51 templates/comments/media-js.html:92 +#: templates/comments/list.html:51 templates/comments/media-js.html:77 msgid "edited" msgstr "" -#: templates/comments/list.html:60 templates/notification/list.html:14 +#: templates/comments/list.html:60 msgid "Link" msgstr "" @@ -3190,52 +3001,36 @@ msgstr "" msgid "Reply" msgstr "" -#: templates/comments/list.html:86 templates/contest/list.html:91 -#: templates/contest/list.html:95 templates/contest/list.html:280 +#: templates/comments/list.html:86 msgid "Hide" msgstr "" -#: templates/comments/list.html:101 -#, python-format -msgid "" -"\n" -" This comment is hidden due " -"to too much negative feedback.\n" -" Click here to view it.\n" -" " -msgstr "" - -#: templates/comments/list.html:121 +#: templates/comments/list.html:120 msgid "There are no comments at the moment." msgstr "" -#: templates/comments/list.html:127 +#: templates/comments/list.html:126 msgid "New comment" msgstr "" -#: templates/comments/list.html:141 +#: templates/comments/list.html:140 msgid "Invalid comment body." msgstr "" -#: templates/comments/list.html:149 +#: templates/comments/list.html:148 msgid "Post!" msgstr "" -#: templates/comments/list.html:157 +#: templates/comments/list.html:156 msgid "Comments are disabled on this page." msgstr "" -#: templates/comments/media-js.html:38 -msgid "Replying to comment" -msgstr "" - -#: templates/comments/media-js.html:87 +#: templates/comments/media-js.html:72 #, python-brace-format msgid "edit {edits}" msgstr "" -#: templates/comments/media-js.html:90 +#: templates/comments/media-js.html:75 msgid "original" msgstr "" @@ -3279,11 +3074,6 @@ msgstr "" msgid "Saturday" msgstr "" -#: templates/contest/clarification.html:52 templates/organization/new.html:10 -#: templates/ticket/new.html:38 -msgid "Create" -msgstr "" - #: templates/contest/clone.html:37 msgid "Enter a new key for the cloned contest:" msgstr "" @@ -3304,171 +3094,97 @@ msgstr "" msgid "Next" msgstr "" -#: templates/contest/contest-list-tabs.html:21 -#: templates/problem/problem-list-tabs.html:5 -msgid "List" -msgstr "" - -#: templates/contest/contest-list-tabs.html:22 -msgid "Calendar" -msgstr "" - -#: templates/contest/contest-tabs.html:4 templates/organization/home.html:105 -msgid "Info" -msgstr "" - -#: templates/contest/contest-tabs.html:6 templates/stats/base.html:9 -#: templates/submission/list.html:339 -msgid "Statistics" -msgstr "" - -#: templates/contest/contest-tabs.html:11 -msgid "Rankings" -msgstr "" - -#: templates/contest/contest-tabs.html:16 -msgid "Hidden Rankings" -msgstr "" - -#: templates/contest/contest-tabs.html:21 -msgid "MOSS" -msgstr "" - -#: templates/contest/contest-tabs.html:26 -msgid "Clone" -msgstr "" - -#: templates/contest/contest-tabs.html:38 -#: templates/contest/contest-tabs.html:58 +#: templates/contest/contest-tabs.html:37 msgid "Leave contest" msgstr "" -#: templates/contest/contest-tabs.html:45 templates/contest/list.html:388 +#: templates/contest/contest-tabs.html:44 templates/contest/list.html:293 msgid "Virtual join" msgstr "" -#: templates/contest/contest-tabs.html:56 -msgid "Stop spectating" -msgstr "" - -#: templates/contest/contest-tabs.html:65 +#: templates/contest/contest-tabs.html:64 msgid "Spectate contest" msgstr "" -#: templates/contest/contest-tabs.html:72 +#: templates/contest/contest-tabs.html:70 +#: templates/contest/contest-tabs.html:76 msgid "Join contest" msgstr "" -#: templates/contest/contest-tabs.html:81 +#: templates/contest/contest-tabs.html:85 msgid "Login to participate" msgstr "" -#: templates/contest/contest.html:37 -msgid "Participating virtually." -msgstr "" - -#: templates/contest/contest.html:43 -msgid "Contest is over." -msgstr "" - #: templates/contest/contest.html:59 templates/contest/contest.html:63 msgid "F j, Y, G:i T" msgstr "" -#: templates/contest/contest.html:59 -#, python-format -msgid "" -"%(time_limit)s window between %(start_time)s and " -"%(end_time)s" -msgstr "" - -#: templates/contest/contest.html:63 -#, python-format -msgid "%(length)s long starting on %(start_time)s" -msgstr "" - #: templates/contest/contest.html:85 msgid "AC Rate" msgstr "" -#: templates/contest/contest.html:86 templates/contest/list.html:237 -#: templates/contest/list.html:289 templates/contest/list.html:366 -#: templates/problem/list.html:223 templates/problem/list.html:254 +#: templates/contest/contest.html:86 templates/contest/list.html:153 +#: templates/contest/list.html:195 templates/contest/list.html:271 +#: templates/problem/list.html:212 templates/problem/list.html:238 msgid "Users" msgstr "" -#: templates/contest/contest.html:111 templates/problem/list.html:330 +#: templates/contest/contest.html:111 msgid "Editorial" msgstr "" -#: templates/contest/list.html:83 templates/contest/media-js.html:9 +#: templates/contest/list.html:31 templates/contest/media-js.html:9 msgid "Are you sure you want to join?" msgstr "" -#: templates/contest/list.html:84 +#: templates/contest/list.html:32 msgid "" "Joining a contest for the first time starts your timer, after which it " "becomes unstoppable." msgstr "" -#: templates/contest/list.html:92 templates/contest/list.html:278 -msgid "Show" -msgstr "" - -#: templates/contest/list.html:102 templates/problem/list.html:68 -msgid "Organizations..." -msgstr "" - -#: templates/contest/list.html:135 +#: templates/contest/list.html:65 msgid "hidden" msgstr "" -#: templates/contest/list.html:140 +#: templates/contest/list.html:70 msgid "private" msgstr "" -#: templates/contest/list.html:154 +#: templates/contest/list.html:84 msgid "rated" msgstr "" -#: templates/contest/list.html:202 +#: templates/contest/list.html:132 msgid "Spectate" msgstr "" -#: templates/contest/list.html:208 +#: templates/contest/list.html:138 msgid "Join" msgstr "" -#: templates/contest/list.html:220 -msgid "Search contests..." -msgstr "" - -#: templates/contest/list.html:229 -msgid "Search" -msgstr "" - -#: templates/contest/list.html:232 +#: templates/contest/list.html:148 msgid "Active Contests" msgstr "" -#: templates/contest/list.html:236 templates/contest/list.html:288 -#: templates/contest/list.html:327 templates/contest/list.html:365 +#: templates/contest/list.html:152 templates/contest/list.html:194 +#: templates/contest/list.html:232 templates/contest/list.html:270 msgid "Contest" msgstr "" -#: templates/contest/list.html:275 +#: templates/contest/list.html:190 msgid "Ongoing Contests" msgstr "" -#: templates/contest/list.html:322 +#: templates/contest/list.html:227 msgid "Upcoming Contests" msgstr "" -#: templates/contest/list.html:350 +#: templates/contest/list.html:255 msgid "There are no scheduled contests at this time." msgstr "" -#: templates/contest/list.html:356 +#: templates/contest/list.html:261 msgid "Past Contests" msgstr "" @@ -3519,71 +3235,47 @@ msgstr "" msgid "Only the following organizations may access this contest:" msgstr "" -#: templates/contest/ranking-table.html:9 templates/problem/search-form.html:35 +#: templates/contest/ranking-table.html:7 msgid "Organization" msgstr "" -#: templates/contest/ranking-table.html:10 templates/user/users-table.html:13 -msgid "Full Name" -msgstr "" - -#: templates/contest/ranking-table.html:44 +#: templates/contest/ranking-table.html:30 msgid "Un-Disqualify" msgstr "" -#: templates/contest/ranking-table.html:47 +#: templates/contest/ranking-table.html:33 msgid "Disqualify" msgstr "" -#: templates/contest/ranking.html:187 +#: templates/contest/ranking.html:173 msgid "Are you sure you want to disqualify this participation?" msgstr "" -#: templates/contest/ranking.html:192 +#: templates/contest/ranking.html:178 msgid "Are you sure you want to un-disqualify this participation?" msgstr "" -#: templates/contest/ranking.html:463 +#: templates/contest/ranking.html:252 msgid "View user participation" msgstr "" -#: templates/contest/ranking.html:467 +#: templates/contest/ranking.html:256 msgid "Show organizations" msgstr "" -#: templates/contest/ranking.html:471 -msgid "Show full name" -msgstr "" - -#: templates/contest/ranking.html:474 -msgid "Show friends only" -msgstr "" - -#: templates/contest/ranking.html:477 -msgid "Total score only" -msgstr "" - -#: templates/contest/ranking.html:479 -msgid "Show virtual participation" -msgstr "" - -#: templates/contest/stats.html:51 +#: templates/contest/stats.html:38 msgid "Problem Status Distribution" msgstr "" -#: templates/contest/stats.html:56 +#: templates/contest/stats.html:43 msgid "Problem AC Rate" msgstr "" -#: templates/contest/stats.html:62 -msgid "Problem Point Distribution" -msgstr "" - -#: templates/contest/stats.html:76 templates/stats/language.html:16 +#: templates/contest/stats.html:48 templates/stats/language.html:16 msgid "Submissions by Language" msgstr "" -#: templates/contest/stats.html:82 templates/stats/language.html:26 +#: templates/contest/stats.html:54 templates/stats/language.html:26 msgid "Language AC Rate" msgstr "" @@ -3592,7 +3284,6 @@ msgid "Source:" msgstr "" #: templates/newsletter/common.html:6 -#: templates/newsletter/newsletter_list.html:15 #: templates/newsletter/subscription_unsubscribe_activated.html:3 #: templates/newsletter/subscription_unsubscribe_activated.html:6 #: templates/newsletter/subscription_update_activated.html:3 @@ -3600,23 +3291,6 @@ msgstr "" msgid "Newsletter" msgstr "" -#: templates/newsletter/newsletter_list.html:2 -#: templates/newsletter/newsletter_list.html:3 -msgid "Newsletter list" -msgstr "" - -#: templates/newsletter/newsletter_list.html:6 -msgid "Subscribe to get the latest emails about upcoming contests and events." -msgstr "" - -#: templates/newsletter/newsletter_list.html:16 -msgid "Subscribe" -msgstr "" - -#: templates/newsletter/newsletter_list.html:30 -msgid "Update subscriptions" -msgstr "" - #: templates/newsletter/subscription_unsubscribe_activated.html:3 #: templates/newsletter/subscription_unsubscribe_activated.html:6 #: templates/newsletter/subscription_update_activated.html:3 @@ -3678,97 +3352,64 @@ msgid "" "follow in order to update your subscription." msgstr "" -#: templates/notification/list.html:7 -msgid "You have no notifications" -msgstr "" - -#: templates/notification/list.html:13 -msgid "Activity" -msgstr "" - #: templates/organization/edit.html:46 #: templates/organization/requests/pending.html:34 #: templates/ticket/edit-notes.html:4 msgid "Update" msgstr "" -#: templates/organization/home.html:41 +#: templates/organization/home.html:7 msgid "Are you sure you want to leave this organization?" msgstr "" -#: templates/organization/home.html:43 +#: templates/organization/home.html:9 msgid "You will have to rejoin to show up on the organization leaderboard." msgstr "" -#: templates/organization/home.html:45 +#: templates/organization/home.html:11 msgid "You will have to request membership in order to join again." msgstr "" -#: templates/organization/home.html:88 -msgid "Join organization" -msgstr "" - -#: templates/organization/home.html:92 -msgid "Request membership" -msgstr "" - -#: templates/organization/home.html:122 -msgid "Organization news" -msgstr "" - -#: templates/organization/home.html:128 -msgid "There is no news at this time." -msgstr "" - -#: templates/organization/home.html:137 -msgid "Controls" -msgstr "" - -#: templates/organization/home.html:142 -msgid "Edit organization" -msgstr "" - -#: templates/organization/home.html:148 -msgid "View requests" -msgstr "" - -#: templates/organization/home.html:161 -msgid "Admin organization" -msgstr "" - -#: templates/organization/home.html:167 -msgid "View members" -msgstr "" - -#: templates/organization/home.html:174 +#: templates/organization/home.html:24 msgid "Leave organization" msgstr "" -#: templates/organization/home.html:183 -msgid "New private contests" +#: templates/organization/home.html:29 +msgid "Join organization" msgstr "" -#: templates/organization/home.html:193 templates/organization/home.html:208 -msgid "View all" +#: templates/organization/home.html:33 +msgid "Request membership" msgstr "" -#: templates/organization/home.html:199 -msgid "New private problems" +#: templates/organization/home.html:39 +msgid "Edit organization" msgstr "" -#: templates/organization/list.html:40 -msgid "Show my organizations only" +#: templates/organization/home.html:43 +msgid "View requests" msgstr "" -#: templates/organization/list.html:47 templates/status/language-list.html:34 -#: templates/user/import/table_csv.html:6 +#: templates/organization/home.html:50 +msgid "Admin organization" +msgstr "" + +#: templates/organization/home.html:55 +msgid "View members" +msgstr "" + +#: templates/organization/list.html:23 templates/status/language-list.html:34 msgid "Name" msgstr "" -#: templates/organization/list.html:48 +#: templates/organization/list.html:24 msgid "Members" msgstr "" +#: templates/organization/new.html:10 templates/ticket/new.html:38 +msgid "Create" +msgstr "" + #: templates/organization/requests/detail.html:13 msgid "User:" msgstr "" @@ -3801,7 +3442,7 @@ msgid "There are no requests to approve." msgstr "" #: templates/organization/requests/pending.html:17 -#: templates/problem/data.html:432 +#: templates/problem/data.html:452 msgid "Delete?" msgstr "" @@ -3837,35 +3478,35 @@ msgstr "" msgid "Enter a new code for the cloned problem:" msgstr "" -#: templates/problem/data.html:119 +#: templates/problem/data.html:108 msgid "Instruction" msgstr "" -#: templates/problem/data.html:390 +#: templates/problem/data.html:410 msgid "View YAML" msgstr "" -#: templates/problem/data.html:421 templates/problem/data.html:472 +#: templates/problem/data.html:441 templates/problem/data.html:491 msgid "Apply!" msgstr "" -#: templates/problem/data.html:426 +#: templates/problem/data.html:446 msgid "Type" msgstr "" -#: templates/problem/data.html:427 +#: templates/problem/data.html:447 msgid "Input file" msgstr "" -#: templates/problem/data.html:428 +#: templates/problem/data.html:448 msgid "Output file" msgstr "" -#: templates/problem/data.html:430 +#: templates/problem/data.html:450 msgid "Pretest?" msgstr "" -#: templates/problem/data.html:473 +#: templates/problem/data.html:492 msgid "Add new case" msgstr "" @@ -3877,32 +3518,28 @@ msgid "" "problem yourself is a bannable offence." msgstr "" -#: templates/problem/list.html:66 +#: templates/problem/list.html:62 msgid "Filter by type..." msgstr "" -#: templates/problem/list.html:193 +#: templates/problem/list.html:185 msgid "Hot problems" msgstr "" -#: templates/problem/list.html:218 templates/problem/list.html:240 -#: templates/problem/search-form.html:45 templates/user/user-problems.html:57 +#: templates/problem/list.html:207 templates/problem/list.html:224 +#: templates/problem/search-form.html:30 templates/user/user-problems.html:57 msgid "Category" msgstr "" -#: templates/problem/list.html:220 templates/problem/list.html:244 +#: templates/problem/list.html:209 templates/problem/list.html:228 msgid "Types" msgstr "" -#: templates/problem/list.html:251 +#: templates/problem/list.html:235 #, python-format msgid "AC %%" msgstr "" -#: templates/problem/list.html:342 -msgid "Add clarifications" -msgstr "" - #: templates/problem/manage_submission.html:55 msgid "Leave empty to not filter by language" msgstr "" @@ -3911,199 +3548,152 @@ msgstr "" msgid "Leave empty to not filter by result" msgstr "" -#: templates/problem/manage_submission.html:80 +#: templates/problem/manage_submission.html:79 msgid "Need valid values for both start and end IDs." msgstr "" -#: templates/problem/manage_submission.html:83 +#: templates/problem/manage_submission.html:82 msgid "End ID must be after start ID." msgstr "" +#: templates/problem/manage_submission.html:90 +#, python-brace-format +msgid "" +"You are about to rejudge {count} submissions. Are you sure you want to do " +"this?" +msgstr "" + #: templates/problem/manage_submission.html:96 -#, python-brace-format msgid "" -"You are about to {action} {count} submissions. Are you sure you want to do " -"this?" +"You are about to rejudge a few submissions. Are you sure you want to do this?" msgstr "" -#: templates/problem/manage_submission.html:103 -#, python-brace-format -msgid "" -"You are about to {action} a few submissions. Are you sure you want to do " -"this?" +#: templates/problem/manage_submission.html:115 +msgid "Rejudge Submissions" msgstr "" -#: templates/problem/manage_submission.html:127 -#: templates/submission/list.html:309 -msgid "Filter submissions" -msgstr "" - -#: templates/problem/manage_submission.html:132 +#: templates/problem/manage_submission.html:120 msgid "Filter by ID:" msgstr "" -#: templates/problem/manage_submission.html:135 +#: templates/problem/manage_submission.html:123 msgid "Starting ID:" msgstr "" -#: templates/problem/manage_submission.html:139 +#: templates/problem/manage_submission.html:127 msgid "Ending ID:" msgstr "" -#: templates/problem/manage_submission.html:143 +#: templates/problem/manage_submission.html:131 msgid "This range includes both endpoints." msgstr "" -#: templates/problem/manage_submission.html:146 +#: templates/problem/manage_submission.html:134 msgid "Filter by language:" msgstr "" -#: templates/problem/manage_submission.html:154 +#: templates/problem/manage_submission.html:142 msgid "Filter by result:" msgstr "" -#: templates/problem/manage_submission.html:164 -msgid "Action" -msgstr "" - -#: templates/problem/manage_submission.html:166 +#: templates/problem/manage_submission.html:150 msgid "Rejudge selected submissions" msgstr "" -#: templates/problem/manage_submission.html:171 -msgid "Download selected submissions" +#: templates/problem/manage_submission.html:157 +msgid "Rescore Everything" msgstr "" -#: templates/problem/manage_submission.html:177 -#, python-format -msgid "Are you sure you want to rescore %(count)d submissions?" -msgstr "" - -#: templates/problem/manage_submission.html:178 +#: templates/problem/manage_submission.html:163 msgid "Rescore all submissions" msgstr "" -#: templates/problem/problem.html:132 +#: templates/problem/problem.html:91 msgid "View as PDF" msgstr "" -#: templates/problem/problem.html:141 templates/problem/problem.html:151 -#: templates/problem/problem.html:156 +#: templates/problem/problem.html:101 templates/problem/problem.html:111 +#: templates/problem/problem.html:116 msgid "Submit solution" msgstr "" -#: templates/problem/problem.html:144 -#, python-format -msgid "%(counter)s submission left" -msgid_plural "%(counter)s submissions left" -msgstr[0] "" -msgstr[1] "" - -#: templates/problem/problem.html:152 +#: templates/problem/problem.html:112 msgid "0 submissions left" msgstr "" -#: templates/problem/problem.html:164 +#: templates/problem/problem.html:124 msgid "My submissions" msgstr "" -#: templates/problem/problem.html:168 +#: templates/problem/problem.html:128 msgid "Best submissions" msgstr "" -#: templates/problem/problem.html:172 +#: templates/problem/problem.html:132 msgid "Read editorial" msgstr "" -#: templates/problem/problem.html:177 +#: templates/problem/problem.html:137 msgid "Manage tickets" msgstr "" -#: templates/problem/problem.html:181 +#: templates/problem/problem.html:141 msgid "Edit problem" msgstr "" -#: templates/problem/problem.html:183 +#: templates/problem/problem.html:143 msgid "Edit test data" msgstr "" -#: templates/problem/problem.html:188 +#: templates/problem/problem.html:148 msgid "My tickets" msgstr "" -#: templates/problem/problem.html:196 +#: templates/problem/problem.html:156 msgid "Manage submissions" msgstr "" -#: templates/problem/problem.html:202 +#: templates/problem/problem.html:162 msgid "Clone problem" msgstr "" -#: templates/problem/problem.html:209 +#: templates/problem/problem.html:169 msgid "Points:" msgstr "" -#: templates/problem/problem.html:212 templates/problem/problem.html:214 +#: templates/problem/problem.html:172 templates/problem/problem.html:174 msgid "(partial)" msgstr "" -#: templates/problem/problem.html:219 +#: templates/problem/problem.html:179 msgid "Time limit:" msgstr "" -#: templates/problem/problem.html:231 +#: templates/problem/problem.html:191 msgid "Memory limit:" msgstr "" -#: templates/problem/problem.html:250 -msgid "Author:" -msgid_plural "Authors:" -msgstr[0] "" -msgstr[1] "" - -#: templates/problem/problem.html:265 -msgid "Problem type" -msgid_plural "Problem types" -msgstr[0] "" -msgstr[1] "" - -#: templates/problem/problem.html:278 +#: templates/problem/problem.html:238 msgid "Allowed languages" msgstr "" -#: templates/problem/problem.html:286 -#, python-format -msgid "No %(lang)s judge online" -msgstr "" - -#: templates/problem/problem.html:297 -msgid "Judge:" -msgid_plural "Judges:" -msgstr[0] "" -msgstr[1] "" - -#: templates/problem/problem.html:314 +#: templates/problem/problem.html:274 msgid "none available" msgstr "" -#: templates/problem/problem.html:326 -#, python-format -msgid "This problem has %(length)s clarification(s)" -msgstr "" - -#: templates/problem/problem.html:350 +#: templates/problem/problem.html:299 msgid "Request clarification" msgstr "" -#: templates/problem/problem.html:352 +#: templates/problem/problem.html:301 msgid "Report an issue" msgstr "" -#: templates/problem/raw.html:64 +#: templates/problem/raw.html:62 msgid "Time Limit:" msgstr "" -#: templates/problem/raw.html:73 +#: templates/problem/raw.html:71 msgid "Memory Limit:" msgstr "" @@ -4127,73 +3717,39 @@ msgstr "" msgid "Show problem types" msgstr "" -#: templates/problem/search-form.html:32 -msgid "Show editorial" -msgstr "" - -#: templates/problem/search-form.html:48 templates/problem/search-form.html:50 -#: templates/submission/submission-list-tabs.html:4 +#: templates/problem/search-form.html:33 templates/problem/search-form.html:35 msgid "All" msgstr "" -#: templates/problem/search-form.html:62 +#: templates/problem/search-form.html:46 msgid "Problem types" msgstr "" -#: templates/problem/search-form.html:73 +#: templates/problem/search-form.html:57 msgid "Point range" msgstr "" -#: templates/problem/search-form.html:79 templates/submission/list.html:331 +#: templates/problem/search-form.html:63 templates/submission/list.html:331 #: templates/ticket/list.html:248 msgid "Go" msgstr "" -#: templates/problem/search-form.html:80 +#: templates/problem/search-form.html:64 msgid "Random" msgstr "" -#: templates/problem/submit.html:117 -msgid "Your source code must contain at most 65536 characters." -msgstr "" - -#: templates/problem/submit.html:204 -#, python-format -msgid "" -"Warning! Your default language, %(default_language)s, is " -"unavailable for this problem and has been deselected." -msgstr "" - -#: templates/problem/submit.html:215 -#, python-format -msgid "" -"\n" -" You have %(left)s submission left\n" -" " -msgid_plural "" -"\n" -" You have %(left)s submissions left\n" -" " -msgstr[0] "" -msgstr[1] "" - -#: templates/problem/submit.html:224 +#: templates/problem/submit.html:212 msgid "You have 0 submissions left" msgstr "" -#: templates/problem/submit.html:258 +#: templates/problem/submit.html:250 msgid "No judge is available for this problem." msgstr "" -#: templates/problem/submit.html:262 +#: templates/problem/submit.html:252 msgid "Submit!" msgstr "" -#: templates/registration/activate.html:3 -#, python-format -msgid "%(key)s is an invalid activation key." -msgstr "" - #: templates/registration/activation_complete.html:3 msgid "Your account has been successfully activated." msgstr "" @@ -4251,13 +3807,6 @@ msgid "" "you registered with, and check your spam folder." msgstr "" -#: templates/registration/password_reset_email.txt:1 -#, python-format -msgid "" -"You're receiving this email because you requested a password reset for your " -"user account at %(site_name)s." -msgstr "" - #: templates/registration/password_reset_email.txt:3 msgid "Please go to the following page and choose a new password:" msgstr "" @@ -4270,16 +3819,6 @@ msgstr "" msgid "Thanks for using our site!" msgstr "" -#: templates/registration/password_reset_email.txt:11 -#, python-format -msgid "The %(site_name)s team" -msgstr "" - -#: templates/registration/password_reset_subject.txt:1 -#, python-format -msgid "Password reset on %(site_name)s" -msgstr "" - #: templates/registration/profile_creation.html:36 #: templates/registration/username_select.html:7 msgid "Continue >" @@ -4316,20 +3855,19 @@ msgstr "" msgid "Affiliated organizations" msgstr "" -#: templates/registration/registration_form.html:195 -#: templates/user/edit-profile.html:128 +#: templates/registration/registration_form.html:192 msgid "Notify me about upcoming contests" msgstr "" -#: templates/registration/registration_form.html:209 +#: templates/registration/registration_form.html:206 msgid "By registering, you agree to our" msgstr "" -#: templates/registration/registration_form.html:210 +#: templates/registration/registration_form.html:207 msgid "Terms & Conditions" msgstr "" -#: templates/registration/registration_form.html:213 +#: templates/registration/registration_form.html:210 msgid "Register!" msgstr "" @@ -4339,11 +3877,6 @@ msgstr "" msgid "Enter the 6-digit code generated by your app:" msgstr "" -#: templates/registration/totp_auth.html:41 -#, python-format -msgid "If you lost your authentication device, please contact us at %(email)s." -msgstr "" - #: templates/registration/totp_disable.html:38 msgid "" "To protect your account, you must first authenticate before you can disable " @@ -4362,6 +3895,10 @@ msgstr "" msgid "Or enter this code manually:" msgstr "" +#: templates/stats/base.html:9 templates/submission/list.html:339 +msgid "Statistics" +msgstr "" + #: templates/stats/language.html:11 msgid "Submission Statistics" msgstr "" @@ -4387,7 +3924,6 @@ msgid "Ping" msgstr "" #: templates/status/judge-status-table.html:8 -#: templates/user/import/index.html:104 msgid "Load" msgstr "" @@ -4403,7 +3939,6 @@ msgid "There are no judges available at this time." msgstr "" #: templates/status/language-list.html:33 templates/ticket/list.html:261 -#: templates/user/import/table_csv.html:3 msgid "ID" msgstr "" @@ -4411,22 +3946,6 @@ msgstr "" msgid "Runtime Info" msgstr "" -#: templates/status/status-tabs.html:4 -msgid "Judges" -msgstr "" - -#: templates/status/status-tabs.html:6 -msgid "Version Matrix" -msgstr "" - -#: templates/submission/internal-error-message.html:3 -#, python-format -msgid "" -"An internal error occurred while grading, and the %(SITE_NAME)s " -"administrators have been notified.
In the meantime, try resubmitting in " -"a few seconds." -msgstr "" - #: templates/submission/internal-error-message.html:8 msgid "An internal error occurred while grading." msgstr "" @@ -4443,6 +3962,10 @@ msgstr "" msgid "Filter by language..." msgstr "" +#: templates/submission/list.html:309 +msgid "Filter submissions" +msgstr "" + #: templates/submission/list.html:345 msgid "Total:" msgstr "" @@ -4499,64 +4022,63 @@ msgstr "" msgid "Execution Results" msgstr "" -#: templates/submission/status-testcases.html:34 -msgid "Overall: " -msgstr "" - -#: templates/submission/status-testcases.html:48 -msgid "Point: " -msgstr "" - -#: templates/submission/status-testcases.html:53 -msgid "Time: " -msgstr "" - -#: templates/submission/status-testcases.html:62 -msgid "Memory: " -msgstr "" - -#: templates/submission/status-testcases.html:73 +#: templates/submission/status-testcases.html:31 msgid "Batch " msgstr "" -#: templates/submission/status-testcases.html:84 -#: templates/submission/status-testcases.html:113 -msgid "Point" +#: templates/submission/status-testcases.html:43 +msgid "Overall: " msgstr "" -#: templates/submission/status-testcases.html:99 +#: templates/submission/status-testcases.html:57 +msgid "Point: " +msgstr "" + +#: templates/submission/status-testcases.html:62 +msgid "Time: " +msgstr "" + +#: templates/submission/status-testcases.html:71 +msgid "Memory: " +msgstr "" + +#: templates/submission/status-testcases.html:84 msgid "Case" msgstr "" -#: templates/submission/status-testcases.html:101 +#: templates/submission/status-testcases.html:86 msgid "Pretest" msgstr "" -#: templates/submission/status-testcases.html:103 +#: templates/submission/status-testcases.html:88 msgid "Test case" msgstr "" -#: templates/submission/status-testcases.html:141 +#: templates/submission/status-testcases.html:99 +msgid "Point" +msgstr "" + +#: templates/submission/status-testcases.html:121 msgid "Input:" msgstr "" -#: templates/submission/status-testcases.html:145 +#: templates/submission/status-testcases.html:125 msgid "Output:" msgstr "" -#: templates/submission/status-testcases.html:149 +#: templates/submission/status-testcases.html:129 msgid "Answer:" msgstr "" -#: templates/submission/status-testcases.html:154 +#: templates/submission/status-testcases.html:134 msgid "Judge feedback:" msgstr "" -#: templates/submission/status-testcases.html:175 +#: templates/submission/status-testcases.html:157 msgid "Passing pretests does not guarantee a full score on system tests." msgstr "" -#: templates/submission/status-testcases.html:178 +#: templates/submission/status-testcases.html:160 msgid "Submission aborted!" msgstr "" @@ -4568,24 +4090,11 @@ msgstr "" msgid "Abort" msgstr "" -#: templates/submission/submission-list-tabs.html:6 -msgid "Mine" -msgstr "" - -#: templates/submission/submission-list-tabs.html:9 -msgid "Best" -msgstr "" - -#: templates/submission/submission-list-tabs.html:12 -#, python-format -msgid "%(user)s's" -msgstr "" - -#: templates/ticket/list.html:135 templates/ticket/ticket.html:273 +#: templates/ticket/list.html:135 templates/ticket/ticket.html:257 msgid "Reopened: " msgstr "" -#: templates/ticket/list.html:138 templates/ticket/ticket.html:274 +#: templates/ticket/list.html:138 templates/ticket/ticket.html:258 msgid "Closed: " msgstr "" @@ -4609,7 +4118,7 @@ msgstr "" msgid "Title" msgstr "" -#: templates/ticket/list.html:264 templates/ticket/ticket.html:369 +#: templates/ticket/list.html:264 templates/ticket/ticket.html:328 msgid "Assignees" msgstr "" @@ -4624,36 +4133,32 @@ msgid "" "a problem, ask in the comments instead." msgstr "" -#: templates/ticket/ticket.html:355 -msgid "Post" -msgstr "" - -#: templates/ticket/ticket.html:363 +#: templates/ticket/ticket.html:322 msgid "Associated object" msgstr "" -#: templates/ticket/ticket.html:374 +#: templates/ticket/ticket.html:333 msgid "No one is assigned." msgstr "" -#: templates/ticket/ticket.html:380 +#: templates/ticket/ticket.html:339 msgid "Close ticket" msgstr "" -#: templates/ticket/ticket.html:382 +#: templates/ticket/ticket.html:341 msgid "Reopen ticket" msgstr "" -#: templates/ticket/ticket.html:386 +#: templates/ticket/ticket.html:345 msgid "Assignee notes" msgstr "" -#: templates/ticket/ticket.html:393 templates/widgets/select_all.html:4 +#: templates/ticket/ticket.html:352 templates/widgets/select_all.html:4 msgid "Nothing here." msgstr "" -#: templates/user/base-users-table.html:3 -msgid "Rank" +#: templates/ticket/ticket.html:385 +msgid "Post" msgstr "" #: templates/user/base-users.html:14 templates/user/base-users.html:69 @@ -4700,168 +4205,50 @@ msgstr "" msgid "Update profile" msgstr "" -#: templates/user/import/index.html:31 -msgid "Upload CSV only" -msgstr "" - -#: templates/user/import/index.html:100 -msgid "User File" -msgstr "" - -#: templates/user/import/index.html:102 -msgid "Sample" -msgstr "" - -#: templates/user/import/index.html:105 templates/user/user-list-tabs.html:8 -msgid "Import" -msgstr "" - -#: templates/user/import/table_csv.html:7 -msgid "School" -msgstr "" - -#: templates/user/pp-row.html:22 -#, python-format -msgid "" -"\n" -" weighted %(weight)s%%\n" -" " -msgstr "" - -#: templates/user/pp-row.html:27 -#, python-format -msgid "%(pp).1fpp" -msgstr "" - -#: templates/user/pp-row.html:29 -#, python-format -msgid "%(pp).0fpp" -msgstr "" - -#: templates/user/user-about.html:23 -#, python-format -msgid "%(counter)s problem solved" -msgid_plural "%(counter)s problems solved" -msgstr[0] "" -msgstr[1] "" - -#: templates/user/user-about.html:35 -msgid "Total points" -msgstr "" - -#: templates/user/user-about.html:45 -msgid "Rank by rating" -msgstr "" - -#: templates/user/user-about.html:52 -msgid "Rank by points" -msgstr "" - -#: templates/user/user-about.html:64 +#: templates/user/user-about.html:14 msgid "From" msgstr "" -#: templates/user/user-about.html:75 +#: templates/user/user-about.html:25 msgid "Admin Notes" msgstr "" -#: templates/user/user-about.html:90 +#: templates/user/user-about.html:40 msgid "You have not shared any information." msgstr "" -#: templates/user/user-about.html:92 +#: templates/user/user-about.html:42 msgid "This user has not shared any information." msgstr "" -#: templates/user/user-about.html:101 -msgid "Awards" +#: templates/user/user-base.html:50 +msgid "Rank by points:" msgstr "" -#: templates/user/user-about.html:112 -#, python-format -msgid "%(label)s (%(date)s)" +#: templates/user/user-base.html:53 +msgid "Total points:" msgstr "" -#: templates/user/user-about.html:130 -msgid "Mon" +#: templates/user/user-base.html:68 +msgid "Rank by rating:" msgstr "" -#: templates/user/user-about.html:135 -msgid "Tues" +#: templates/user/user-base.html:70 +msgid "Rating:" msgstr "" -#: templates/user/user-about.html:140 -msgid "Wed" -msgstr "" - -#: templates/user/user-about.html:145 -msgid "Thurs" -msgstr "" - -#: templates/user/user-about.html:150 -msgid "Fri" -msgstr "" - -#: templates/user/user-about.html:155 -msgid "Sat" -msgstr "" - -#: templates/user/user-about.html:160 -msgid "Sun" -msgstr "" - -#: templates/user/user-about.html:169 -msgid "Less" -msgstr "" - -#: templates/user/user-about.html:175 -msgid "More" -msgstr "" - -#: templates/user/user-about.html:184 -msgid "Rating History" -msgstr "" - -#: templates/user/user-about.html:255 -msgid "past year" -msgstr "" - -#: templates/user/user-about.html:272 -msgid "total submission(s)" -msgstr "" - -#: templates/user/user-about.html:276 -msgid "submissions in the last year" -msgstr "" - -#: templates/user/user-base.html:101 -msgid "Unfollow" -msgstr "" - -#: templates/user/user-base.html:104 -msgid "Follow" -msgstr "" - -#: templates/user/user-base.html:120 -msgid "Contests written" -msgstr "" - -#: templates/user/user-base.html:124 +#: templates/user/user-base.html:71 msgid "Volatility:" msgstr "" -#: templates/user/user-base.html:128 +#: templates/user/user-base.html:72 msgid "Min. rating:" msgstr "" -#: templates/user/user-base.html:132 +#: templates/user/user-base.html:73 msgid "Max rating:" msgstr "" -#: templates/user/user-list-tabs.html:5 -msgid "Friends" -msgstr "" - #: templates/user/user-problems.html:35 msgid "Points Breakdown" msgstr "" @@ -4882,32 +4269,10 @@ msgstr "" msgid "Hide problems I've solved" msgstr "" -#: templates/user/user-problems.html:93 -#, python-format -msgid "%(points).1f points" -msgstr "" - #: templates/user/user-problems.html:99 msgid "Score" msgstr "" -#: templates/user/user-problems.html:110 -#, python-format -msgid "%(points)s / %(total)s" -msgstr "" - -#: templates/user/user-tabs.html:7 -msgid "Impersonate" -msgstr "" - -#: templates/user/user-tabs.html:13 -msgid "Admin User" -msgstr "" - -#: templates/user/user-tabs.html:16 -msgid "Admin Profile" -msgstr "" - #: templates/widgets/select_all.html:8 msgid "Check all" msgstr "" diff --git a/locale/pt/LC_MESSAGES/djangojs.po b/locale/pt/LC_MESSAGES/djangojs.po index 24c5cf2..0bcbd6f 100644 --- a/locale/pt/LC_MESSAGES/djangojs.po +++ b/locale/pt/LC_MESSAGES/djangojs.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: dmoj\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-07-20 23:30+0700\n" +"POT-Creation-Date: 2019-10-01 23:12+0000\n" "PO-Revision-Date: 2019-11-11 22:05\n" "Last-Translator: Icyene\n" "Language-Team: Portuguese, Brazilian\n" @@ -27,3 +27,4 @@ msgstr[1] "" msgctxt "time format without day" msgid "%h:%m:%s" msgstr "" + diff --git a/locale/ro/LC_MESSAGES/django.po b/locale/ro/LC_MESSAGES/django.po index c1dc332..531149c 100644 --- a/locale/ro/LC_MESSAGES/django.po +++ b/locale/ro/LC_MESSAGES/django.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: dmoj\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-10-25 05:59+0700\n" +"POT-Creation-Date: 2020-04-10 01:26-0500\n" "PO-Revision-Date: 2019-11-11 22:05\n" "Last-Translator: Icyene\n" "Language-Team: Romanian\n" @@ -17,93 +17,93 @@ msgstr "" "X-Crowdin-Language: ro\n" "X-Crowdin-File: django.po\n" -#: chat_box/models.py:16 judge/admin/interface.py:110 -#: judge/models/contest.py:403 judge/models/contest.py:528 -#: judge/models/profile.py:211 +#: chat_box/models.py:15 judge/admin/interface.py:107 +#: judge/models/contest.py:257 judge/models/contest.py:381 +#: judge/models/profile.py:191 msgid "user" msgstr "" -#: chat_box/models.py:17 judge/models/comment.py:43 judge/models/comment.py:191 +#: chat_box/models.py:16 judge/models/comment.py:42 msgid "posted time" msgstr "" -#: chat_box/models.py:18 judge/models/comment.py:47 +#: chat_box/models.py:17 judge/models/comment.py:46 msgid "body of comment" msgstr "" -#: chat_box/views.py:29 templates/chat/chat.html:4 +#: chat_box/views.py:29 msgid "Chat Box" msgstr "" -#: dmoj/settings.py:355 +#: dmoj/settings.py:349 msgid "German" msgstr "Germană" -#: dmoj/settings.py:356 +#: dmoj/settings.py:350 msgid "English" msgstr "Engleză" -#: dmoj/settings.py:357 +#: dmoj/settings.py:351 msgid "Spanish" msgstr "" -#: dmoj/settings.py:358 +#: dmoj/settings.py:352 msgid "French" msgstr "Franceză" -#: dmoj/settings.py:359 +#: dmoj/settings.py:353 msgid "Croatian" msgstr "" -#: dmoj/settings.py:360 +#: dmoj/settings.py:354 msgid "Hungarian" msgstr "" -#: dmoj/settings.py:361 +#: dmoj/settings.py:355 msgid "Japanese" msgstr "" -#: dmoj/settings.py:362 +#: dmoj/settings.py:356 msgid "Korean" msgstr "" -#: dmoj/settings.py:363 +#: dmoj/settings.py:357 msgid "Brazilian Portuguese" msgstr "" -#: dmoj/settings.py:364 +#: dmoj/settings.py:358 msgid "Romanian" msgstr "Română" -#: dmoj/settings.py:365 +#: dmoj/settings.py:359 msgid "Russian" msgstr "Rusă" -#: dmoj/settings.py:366 +#: dmoj/settings.py:360 msgid "Serbian (Latin)" msgstr "" -#: dmoj/settings.py:367 +#: dmoj/settings.py:361 msgid "Turkish" msgstr "" -#: dmoj/settings.py:368 +#: dmoj/settings.py:362 msgid "Vietnamese" msgstr "" -#: dmoj/settings.py:369 +#: dmoj/settings.py:363 msgid "Simplified Chinese" msgstr "Chineză simplificată" -#: dmoj/settings.py:370 +#: dmoj/settings.py:364 msgid "Traditional Chinese" msgstr "" -#: dmoj/urls.py:58 +#: dmoj/urls.py:57 msgid "Login" msgstr "Login" -#: dmoj/urls.py:106 templates/base.html:193 +#: dmoj/urls.py:105 templates/base.html:190 msgid "Home" msgstr "Start" @@ -135,48 +135,46 @@ msgstr "Reafişează comentariile" msgid "Associated page" msgstr "Pagină associată" -#: judge/admin/contest.py:30 +#: judge/admin/contest.py:28 msgid "Included contests" msgstr "Concursuri incluse" -#: judge/admin/contest.py:66 templates/contest/clarification.html:42 -#: templates/contest/contest.html:83 templates/contest/moss.html:43 -#: templates/problem/list.html:214 templates/problem/list.html:232 -#: templates/problem/list.html:350 templates/user/user-problems.html:56 +#: judge/admin/contest.py:64 templates/contest/contest.html:83 +#: templates/contest/moss.html:43 templates/problem/list.html:206 +#: templates/problem/list.html:221 templates/user/user-problems.html:56 #: templates/user/user-problems.html:98 msgid "Problem" msgstr "Problemă" -#: judge/admin/contest.py:119 +#: judge/admin/contest.py:112 msgid "Settings" msgstr "" -#: judge/admin/contest.py:121 +#: judge/admin/contest.py:114 msgid "Scheduling" msgstr "Programare" -#: judge/admin/contest.py:122 templates/organization/home.html:107 +#: judge/admin/contest.py:115 msgid "Details" msgstr "Detalii" -#: judge/admin/contest.py:123 +#: judge/admin/contest.py:116 msgid "Format" msgstr "" -#: judge/admin/contest.py:124 templates/contest/ranking-table.html:7 -#: templates/user/user-about.html:15 templates/user/user-about.html:45 +#: judge/admin/contest.py:117 templates/contest/ranking-table.html:5 msgid "Rating" msgstr "Rating" -#: judge/admin/contest.py:125 +#: judge/admin/contest.py:118 msgid "Access" msgstr "" -#: judge/admin/contest.py:127 judge/admin/problem.py:131 +#: judge/admin/contest.py:120 judge/admin/problem.py:131 msgid "Justice" msgstr "Justiţie" -#: judge/admin/contest.py:207 +#: judge/admin/contest.py:158 #, python-format msgid "%d contest successfully marked as visible." msgid_plural "%d contests successfully marked as visible." @@ -184,11 +182,11 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: judge/admin/contest.py:210 +#: judge/admin/contest.py:161 msgid "Mark contests as visible" msgstr "" -#: judge/admin/contest.py:216 +#: judge/admin/contest.py:165 #, python-format msgid "%d contest successfully marked as hidden." msgid_plural "%d contests successfully marked as hidden." @@ -196,11 +194,11 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: judge/admin/contest.py:219 +#: judge/admin/contest.py:168 msgid "Mark contests as hidden" msgstr "" -#: judge/admin/contest.py:233 judge/admin/submission.py:164 +#: judge/admin/contest.py:182 judge/admin/submission.py:164 #, python-format msgid "%d submission was successfully scheduled for rejudging." msgid_plural "%d submissions were successfully scheduled for rejudging." @@ -208,7 +206,7 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: judge/admin/contest.py:308 +#: judge/admin/contest.py:256 #, python-format msgid "%d participation recalculated." msgid_plural "%d participations recalculated." @@ -216,15 +214,15 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: judge/admin/contest.py:311 +#: judge/admin/contest.py:259 msgid "Recalculate results" msgstr "" -#: judge/admin/contest.py:315 judge/admin/organization.py:65 +#: judge/admin/contest.py:263 judge/admin/organization.py:65 msgid "username" msgstr "" -#: judge/admin/contest.py:320 templates/base.html:277 +#: judge/admin/contest.py:268 templates/base.html:260 msgid "virtual" msgstr "" @@ -232,15 +230,15 @@ msgstr "" msgid "link path" msgstr "" -#: judge/admin/interface.py:65 +#: judge/admin/interface.py:62 msgid "Content" msgstr "Conţinut" -#: judge/admin/interface.py:66 +#: judge/admin/interface.py:63 msgid "Summary" msgstr "Rezumat" -#: judge/admin/interface.py:151 +#: judge/admin/interface.py:148 msgid "object" msgstr "" @@ -262,9 +260,8 @@ msgid "Taxonomy" msgstr "Taxonomie" #: judge/admin/problem.py:128 templates/contest/contest.html:84 -#: templates/problem/data.html:429 templates/problem/list.html:222 -#: templates/problem/list.html:248 templates/user/base-users-table.html:10 -#: templates/user/user-about.html:36 templates/user/user-about.html:52 +#: templates/problem/data.html:449 templates/problem/list.html:211 +#: templates/problem/list.html:232 templates/user/base-users-table.html:10 #: templates/user/user-problems.html:58 msgid "Points" msgstr "Puncte" @@ -315,7 +312,6 @@ msgid "timezone" msgstr "" #: judge/admin/profile.py:86 judge/admin/submission.py:211 -#: templates/notification/list.html:12 #: templates/organization/requests/log.html:9 #: templates/organization/requests/pending.html:12 #: templates/ticket/list.html:263 @@ -323,7 +319,6 @@ msgid "User" msgstr "Utilizator" #: judge/admin/profile.py:91 templates/registration/registration_form.html:145 -#: templates/user/import/table_csv.html:8 msgid "Email" msgstr "Email" @@ -357,7 +352,7 @@ msgstr "Probleme nepermise" msgid "These problems are NOT allowed to be submitted in this language" msgstr "Aceste probleme NU pot fi transmise în acest limbaj" -#: judge/admin/runtime.py:83 templates/problem/list.html:352 +#: judge/admin/runtime.py:83 msgid "Description" msgstr "Descriere" @@ -404,7 +399,7 @@ msgstr "Nu aveţi permisiunea de a rejuriza ATÂT de multe submisii." msgid "Rejudge the selected submissions" msgstr "Rejurizează submisiile selectate" -#: judge/admin/submission.py:193 judge/views/problem_manage.py:159 +#: judge/admin/submission.py:193 judge/views/problem_manage.py:128 #, python-format msgid "%d submission were successfully rescored." msgid_plural "%d submissions were successfully rescored." @@ -416,8 +411,7 @@ msgstr[2] "%d submisii au fost repunctate cu succes." msgid "Rescore the selected submissions" msgstr "Repunctează submisiile selectate" -#: judge/admin/submission.py:200 templates/problem/list.html:216 -#: templates/problem/list.html:236 +#: judge/admin/submission.py:200 msgid "Problem code" msgstr "Codul problemei" @@ -425,12 +419,10 @@ msgstr "Codul problemei" msgid "Problem name" msgstr "" -#: judge/admin/submission.py:215 templates/notification/list.html:15 -#: templates/organization/requests/log.html:10 +#: judge/admin/submission.py:215 templates/organization/requests/log.html:10 #: templates/organization/requests/pending.html:13 -#: templates/problem/list.html:351 -#: templates/submission/status-testcases.html:125 -#: templates/submission/status-testcases.html:127 +#: templates/submission/status-testcases.html:105 +#: templates/submission/status-testcases.html:107 msgid "Time" msgstr "Ora" @@ -444,7 +436,7 @@ msgstr "%d KB" msgid "%.2f MB" msgstr "%.2f MB" -#: judge/admin/submission.py:227 templates/submission/status-testcases.html:132 +#: judge/admin/submission.py:227 templates/submission/status-testcases.html:112 msgid "Memory" msgstr "" @@ -464,20 +456,20 @@ msgstr "Aceste probleme sunt incluse în acest tip de probleme" msgid "Online Judge" msgstr "Online Judge" -#: judge/comments.py:60 +#: judge/comments.py:41 msgid "Comment body" msgstr "Comentariu" -#: judge/comments.py:66 judge/views/ticket.py:63 +#: judge/comments.py:47 judge/views/ticket.py:46 msgid "Your part is silent, little toad." msgstr "" -#: judge/comments.py:69 templates/comments/list.html:132 +#: judge/comments.py:50 templates/comments/list.html:131 msgid "" "You need to have solved at least one problem before your voice can be heard." msgstr "" -#: judge/comments.py:113 +#: judge/comments.py:92 msgid "Posted comment" msgstr "Comentariu postat" @@ -493,10 +485,6 @@ msgstr "" msgid "ECOO" msgstr "ECOO" -#: judge/contest_format/icpc.py:19 -msgid "ICPC" -msgstr "" - #: judge/contest_format/ioi.py:19 msgid "IOI" msgstr "IOI" @@ -509,60 +497,52 @@ msgstr "" msgid "Enable experimental features" msgstr "" -#: judge/forms.py:57 judge/views/organization.py:168 judge/views/register.py:49 +#: judge/forms.py:57 judge/views/organization.py:127 #, python-brace-format msgid "You may not be part of more than {count} public organizations." msgstr "" -#: judge/forms.py:82 -#, fuzzy -#| msgid "judge" -msgid "Any judge" -msgstr "evaluator" - -#: judge/forms.py:112 judge/views/register.py:26 +#: judge/forms.py:107 judge/views/register.py:26 #: templates/registration/registration_form.html:139 #: templates/user/base-users-table.html:5 -#: templates/user/import/table_csv.html:4 msgid "Username" msgstr "Nume de utilizator" -#: judge/forms.py:113 templates/registration/registration_form.html:151 +#: judge/forms.py:108 templates/registration/registration_form.html:151 #: templates/registration/registration_form.html:165 -#: templates/user/import/table_csv.html:5 msgid "Password" msgstr "" -#: judge/forms.py:135 +#: judge/forms.py:130 msgid "Two Factor Authentication tokens must be 6 decimal digits." msgstr "" -#: judge/forms.py:144 templates/registration/totp_auth.html:32 +#: judge/forms.py:139 templates/registration/totp_auth.html:32 msgid "Invalid Two Factor Authentication token." msgstr "" -#: judge/forms.py:148 judge/models/problem.py:97 +#: judge/forms.py:143 judge/models/problem.py:97 msgid "Problem code must be ^[a-z0-9]+$" msgstr "Codul problemei trebuie să fie ^[a-z0-9]+$" -#: judge/forms.py:153 +#: judge/forms.py:148 msgid "Problem with code already exists." msgstr "" -#: judge/forms.py:158 judge/models/contest.py:61 +#: judge/forms.py:153 judge/models/contest.py:52 msgid "Contest id must be ^[a-z0-9]+$" msgstr "Identificatorul de concurs trebuie să fie ^[a-z0-9]+$" -#: judge/forms.py:163 +#: judge/forms.py:158 msgid "Contest with key already exists." msgstr "" -#: judge/jinja2/datetime.py:26 templates/blog/blog.html:26 +#: judge/jinja2/datetime.py:26 templates/blog/content.html:27 #: templates/blog/dashboard.html:21 msgid "N j, Y, g:i a" msgstr "N j, Y, g:i a" -#: judge/jinja2/datetime.py:26 templates/chat/message.html:13 +#: judge/jinja2/datetime.py:26 #, python-brace-format msgid "{time}" msgstr "" @@ -592,556 +572,474 @@ msgstr "" msgid "Detect best quality" msgstr "" -#: judge/models/comment.py:26 +#: judge/models/comment.py:25 msgid "Page code must be ^[pcs]:[a-z0-9]+$|^b:\\d+$" msgstr "" -#: judge/models/comment.py:42 +#: judge/models/comment.py:41 msgid "commenter" msgstr "" -#: judge/models/comment.py:44 judge/models/comment.py:177 +#: judge/models/comment.py:43 judge/models/comment.py:176 msgid "associated page" msgstr "" -#: judge/models/comment.py:46 +#: judge/models/comment.py:45 msgid "votes" msgstr "" -#: judge/models/comment.py:48 +#: judge/models/comment.py:47 msgid "hide the comment" msgstr "ascunde comentariul" -#: judge/models/comment.py:49 +#: judge/models/comment.py:48 msgid "parent" msgstr "" -#: judge/models/comment.py:54 judge/models/comment.py:192 +#: judge/models/comment.py:53 msgid "comment" msgstr "comentariu" -#: judge/models/comment.py:55 +#: judge/models/comment.py:54 msgid "comments" msgstr "comentarii" -#: judge/models/comment.py:137 judge/models/problem.py:443 +#: judge/models/comment.py:136 judge/models/problem.py:406 #, python-format msgid "Editorial for %s" msgstr "" -#: judge/models/comment.py:172 +#: judge/models/comment.py:171 msgid "comment vote" msgstr "votul comentariului" -#: judge/models/comment.py:173 +#: judge/models/comment.py:172 msgid "comment votes" msgstr "voturile comentariului" -#: judge/models/comment.py:182 +#: judge/models/comment.py:181 msgid "Override comment lock" msgstr "" -#: judge/models/comment.py:190 -msgid "owner" -msgstr "" - -#: judge/models/comment.py:193 judge/models/message.py:16 -msgid "read" -msgstr "" - -#: judge/models/comment.py:194 -#, fuzzy -#| msgid "Category" -msgid "category" -msgstr "Categorie" - -#: judge/models/comment.py:195 -msgid "html link to comments, used for non-comments" -msgstr "" - -#: judge/models/comment.py:196 -msgid "who trigger, used for non-comment" -msgstr "" - -#: judge/models/contest.py:23 +#: judge/models/contest.py:22 msgid "Invalid colour." msgstr "Culoare invalida." -#: judge/models/contest.py:25 +#: judge/models/contest.py:24 msgid "tag name" msgstr "nume de etichetă" -#: judge/models/contest.py:26 +#: judge/models/contest.py:25 msgid "Lowercase letters and hyphens only." msgstr "" -#: judge/models/contest.py:27 +#: judge/models/contest.py:26 msgid "tag colour" msgstr "culoare de eticheta" -#: judge/models/contest.py:28 +#: judge/models/contest.py:27 msgid "tag description" msgstr "descrierea etichetei" -#: judge/models/contest.py:47 +#: judge/models/contest.py:46 msgid "contest tag" msgstr "eticheta concursului" -#: judge/models/contest.py:48 judge/models/contest.py:118 +#: judge/models/contest.py:47 judge/models/contest.py:101 msgid "contest tags" msgstr "etichetele concursului" -#: judge/models/contest.py:56 -msgid "Visible" -msgstr "" - -#: judge/models/contest.py:57 -msgid "Hidden for duration of contest" -msgstr "" - -#: judge/models/contest.py:58 -msgid "Hidden for duration of participation" -msgstr "" - -#: judge/models/contest.py:60 +#: judge/models/contest.py:51 msgid "contest id" msgstr "" -#: judge/models/contest.py:62 +#: judge/models/contest.py:53 msgid "contest name" msgstr "" -#: judge/models/contest.py:63 -#, fuzzy -#| msgid "These people will be able to edit the contest." -msgid "These users will be able to edit the contest." +#: judge/models/contest.py:54 +msgid "These people will be able to edit the contest." msgstr "Aceste persoane vor putea să editeze concursul." -#: judge/models/contest.py:65 -#, fuzzy -#| msgid "These people will be able to edit the contest." -msgid "" -"These users will be able to edit the contest, but will not be listed as " -"authors." -msgstr "Aceste persoane vor putea să editeze concursul." - -#: judge/models/contest.py:68 -#, fuzzy -#| msgid "These people will be able to edit the contest." -msgid "These users will be able to view the contest, but not edit it." -msgstr "Aceste persoane vor putea să editeze concursul." - -#: judge/models/contest.py:71 judge/models/runtime.py:136 +#: judge/models/contest.py:56 judge/models/runtime.py:133 msgid "description" msgstr "" -#: judge/models/contest.py:72 judge/models/problem.py:390 -#: judge/models/runtime.py:138 +#: judge/models/contest.py:57 judge/models/problem.py:353 +#: judge/models/runtime.py:135 msgid "problems" msgstr "probleme" -#: judge/models/contest.py:73 judge/models/contest.py:404 +#: judge/models/contest.py:58 judge/models/contest.py:258 msgid "start time" msgstr "" -#: judge/models/contest.py:74 +#: judge/models/contest.py:59 msgid "end time" msgstr "" -#: judge/models/contest.py:75 judge/models/problem.py:118 -#: judge/models/problem.py:414 +#: judge/models/contest.py:60 judge/models/problem.py:118 +#: judge/models/problem.py:377 msgid "time limit" msgstr "" -#: judge/models/contest.py:76 judge/models/problem.py:136 +#: judge/models/contest.py:61 judge/models/problem.py:136 msgid "publicly visible" msgstr "" -#: judge/models/contest.py:77 +#: judge/models/contest.py:62 msgid "" "Should be set even for organization-private contests, where it determines " "whether the contest is visible to members of the specified organizations." msgstr "" -#: judge/models/contest.py:80 +#: judge/models/contest.py:65 msgid "contest rated" msgstr "" -#: judge/models/contest.py:80 +#: judge/models/contest.py:65 msgid "Whether this contest can be rated." msgstr "Dacă acest concurs poate fi evaluat." -#: judge/models/contest.py:82 -msgid "scoreboard visibility" +#: judge/models/contest.py:67 +msgid "hide scoreboard" msgstr "" -#: judge/models/contest.py:83 -msgid "Scoreboard visibility through the duration of the contest" +#: judge/models/contest.py:68 +msgid "" +"Whether the scoreboard should remain hidden for the duration of the contest." msgstr "" -#: judge/models/contest.py:85 -msgid "view contest scoreboard" -msgstr "" - -#: judge/models/contest.py:87 -#, fuzzy -#| msgid "These people will be able to edit the contest." -msgid "These users will be able to view the scoreboard." -msgstr "Aceste persoane vor putea să editeze concursul." - -#: judge/models/contest.py:88 +#: judge/models/contest.py:71 msgid "no comments" msgstr "" -#: judge/models/contest.py:89 +#: judge/models/contest.py:72 msgid "Use clarification system instead of comments." msgstr "" -#: judge/models/contest.py:91 +#: judge/models/contest.py:74 msgid "Rating floor for contest" msgstr "" -#: judge/models/contest.py:93 +#: judge/models/contest.py:76 msgid "Rating ceiling for contest" msgstr "" -#: judge/models/contest.py:95 +#: judge/models/contest.py:78 msgid "rate all" msgstr "" -#: judge/models/contest.py:95 +#: judge/models/contest.py:78 msgid "Rate all users who joined." msgstr "Evaluează toţi utilizatorii care s-au inscris." -#: judge/models/contest.py:96 +#: judge/models/contest.py:79 msgid "exclude from ratings" msgstr "" -#: judge/models/contest.py:98 +#: judge/models/contest.py:81 msgid "private to specific users" msgstr "" -#: judge/models/contest.py:99 +#: judge/models/contest.py:82 msgid "private contestants" msgstr "" -#: judge/models/contest.py:100 +#: judge/models/contest.py:83 msgid "If private, only these users may see the contest" msgstr "" -#: judge/models/contest.py:102 +#: judge/models/contest.py:85 msgid "hide problem tags" msgstr "" -#: judge/models/contest.py:103 +#: judge/models/contest.py:86 msgid "Whether problem tags should be hidden by default." msgstr "" -#: judge/models/contest.py:105 +#: judge/models/contest.py:88 msgid "run pretests only" msgstr "" -#: judge/models/contest.py:106 +#: judge/models/contest.py:89 msgid "" "Whether judges should grade pretests only, versus all testcases. Commonly " "set during a contest, then unset prior to rejudging user submissions when " "the contest ends." msgstr "" -#: judge/models/contest.py:110 judge/models/interface.py:77 -#: judge/models/problem.py:157 +#: judge/models/contest.py:93 judge/models/problem.py:157 msgid "private to organizations" msgstr "" -#: judge/models/contest.py:111 judge/models/interface.py:75 -#: judge/models/problem.py:155 judge/models/profile.py:77 +#: judge/models/contest.py:94 judge/models/problem.py:155 +#: judge/models/profile.py:77 msgid "organizations" msgstr "organizații" -#: judge/models/contest.py:112 +#: judge/models/contest.py:95 msgid "If private, only these organizations may see the contest" msgstr "Dacă e privat, doar aceste organizaţii pot vedea acest concurs" -#: judge/models/contest.py:113 judge/models/problem.py:145 +#: judge/models/contest.py:96 judge/models/problem.py:145 msgid "OpenGraph image" msgstr "Imagine OpenGraph" -#: judge/models/contest.py:114 judge/models/profile.py:48 +#: judge/models/contest.py:97 judge/models/profile.py:48 msgid "Logo override image" msgstr "" -#: judge/models/contest.py:116 +#: judge/models/contest.py:99 msgid "" "This image will replace the default site logo for users inside the contest." msgstr "" -#: judge/models/contest.py:119 +#: judge/models/contest.py:102 msgid "the amount of live participants" msgstr "" -#: judge/models/contest.py:120 +#: judge/models/contest.py:103 msgid "contest summary" msgstr "" -#: judge/models/contest.py:121 judge/models/problem.py:147 +#: judge/models/contest.py:104 judge/models/problem.py:147 msgid "Plain-text, shown in meta description tag, e.g. for social media." msgstr "" -#: judge/models/contest.py:122 judge/models/profile.py:47 +#: judge/models/contest.py:105 judge/models/profile.py:47 msgid "access code" msgstr "" -#: judge/models/contest.py:123 +#: judge/models/contest.py:106 msgid "" "An optional code to prompt contestants before they are allowed to join the " "contest. Leave it blank to disable." msgstr "" -#: judge/models/contest.py:125 judge/models/problem.py:141 +#: judge/models/contest.py:108 judge/models/problem.py:141 msgid "personae non gratae" msgstr "" -#: judge/models/contest.py:126 +#: judge/models/contest.py:109 msgid "Bans the selected users from joining this contest." msgstr "" -#: judge/models/contest.py:127 +#: judge/models/contest.py:110 msgid "contest format" msgstr "" -#: judge/models/contest.py:128 +#: judge/models/contest.py:111 msgid "The contest format module to use." msgstr "" -#: judge/models/contest.py:129 +#: judge/models/contest.py:112 msgid "contest format configuration" msgstr "" -#: judge/models/contest.py:130 +#: judge/models/contest.py:113 msgid "" "A JSON object to serve as the configuration for the chosen contest format " "module. Leave empty to use None. Exact format depends on the contest format " "selected." msgstr "" -#: judge/models/contest.py:137 -msgid "precision points" -msgstr "" - -#: judge/models/contest.py:139 -msgid "Number of digits to round points to." -msgstr "" - -#: judge/models/contest.py:383 +#: judge/models/contest.py:239 msgid "See private contests" msgstr "" -#: judge/models/contest.py:384 +#: judge/models/contest.py:240 msgid "Edit own contests" msgstr "" -#: judge/models/contest.py:385 +#: judge/models/contest.py:241 msgid "Edit all contests" msgstr "" -#: judge/models/contest.py:386 +#: judge/models/contest.py:242 msgid "Clone contest" msgstr "" -#: judge/models/contest.py:387 templates/contest/moss.html:74 +#: judge/models/contest.py:243 templates/contest/moss.html:74 msgid "MOSS contest" msgstr "" -#: judge/models/contest.py:388 +#: judge/models/contest.py:244 msgid "Rate contests" msgstr "" -#: judge/models/contest.py:389 +#: judge/models/contest.py:245 msgid "Contest access codes" msgstr "" -#: judge/models/contest.py:390 +#: judge/models/contest.py:246 msgid "Create private contests" msgstr "" -#: judge/models/contest.py:391 -msgid "Change contest visibility" -msgstr "" - -#: judge/models/contest.py:392 -#, fuzzy -#| msgid "contest problems" -msgid "Edit contest problem label script" -msgstr "problemele din concurs" - -#: judge/models/contest.py:394 judge/models/contest.py:492 -#: judge/models/contest.py:529 judge/models/contest.py:552 -#: judge/models/submission.py:84 +#: judge/models/contest.py:248 judge/models/contest.py:345 +#: judge/models/contest.py:382 judge/models/contest.py:404 +#: judge/models/submission.py:83 msgid "contest" msgstr "concurs" -#: judge/models/contest.py:395 +#: judge/models/contest.py:249 msgid "contests" msgstr "concursuri" -#: judge/models/contest.py:402 +#: judge/models/contest.py:256 msgid "associated contest" msgstr "" -#: judge/models/contest.py:405 +#: judge/models/contest.py:259 msgid "score" msgstr "scor" -#: judge/models/contest.py:406 +#: judge/models/contest.py:260 msgid "cumulative time" msgstr "" -#: judge/models/contest.py:407 +#: judge/models/contest.py:261 msgid "is disqualified" msgstr "" -#: judge/models/contest.py:408 +#: judge/models/contest.py:262 msgid "Whether this participation is disqualified." msgstr "" -#: judge/models/contest.py:409 -msgid "tie-breaking field" -msgstr "" - -#: judge/models/contest.py:410 +#: judge/models/contest.py:263 msgid "virtual participation id" msgstr "" -#: judge/models/contest.py:411 +#: judge/models/contest.py:264 msgid "0 means non-virtual, otherwise the n-th virtual participation." msgstr "" -#: judge/models/contest.py:412 +#: judge/models/contest.py:265 msgid "contest format specific data" msgstr "" -#: judge/models/contest.py:478 +#: judge/models/contest.py:331 #, python-format msgid "%s spectating in %s" msgstr "" -#: judge/models/contest.py:480 +#: judge/models/contest.py:333 #, python-format msgid "%s in %s, v%d" msgstr "" -#: judge/models/contest.py:481 +#: judge/models/contest.py:334 #, python-format msgid "%s in %s" msgstr "" -#: judge/models/contest.py:484 +#: judge/models/contest.py:337 msgid "contest participation" msgstr "participarea la concurs" -#: judge/models/contest.py:485 +#: judge/models/contest.py:338 msgid "contest participations" msgstr "participările la concurs" -#: judge/models/contest.py:491 judge/models/contest.py:513 -#: judge/models/contest.py:553 judge/models/problem.py:389 -#: judge/models/problem.py:394 judge/models/problem.py:412 -#: judge/models/problem_data.py:40 +#: judge/models/contest.py:344 judge/models/contest.py:366 +#: judge/models/contest.py:405 judge/models/problem.py:352 +#: judge/models/problem.py:357 judge/models/problem.py:375 +#: judge/models/problem_data.py:38 msgid "problem" msgstr "problemă" -#: judge/models/contest.py:493 judge/models/contest.py:517 +#: judge/models/contest.py:346 judge/models/contest.py:370 #: judge/models/problem.py:129 msgid "points" msgstr "puncte" -#: judge/models/contest.py:494 +#: judge/models/contest.py:347 msgid "partial" msgstr "" -#: judge/models/contest.py:495 judge/models/contest.py:518 +#: judge/models/contest.py:348 judge/models/contest.py:371 msgid "is pretested" msgstr "" -#: judge/models/contest.py:496 judge/models/interface.py:43 +#: judge/models/contest.py:349 judge/models/interface.py:43 msgid "order" msgstr "" -#: judge/models/contest.py:497 +#: judge/models/contest.py:350 msgid "0 to not show testcases, 1 to show" msgstr "" -#: judge/models/contest.py:498 +#: judge/models/contest.py:351 #, fuzzy #| msgid "submission test cases" msgid "visible testcases" msgstr "testele submisiei" -#: judge/models/contest.py:499 +#: judge/models/contest.py:352 msgid "Maximum number of submissions for this problem, or 0 for no limit." msgstr "" -#: judge/models/contest.py:501 +#: judge/models/contest.py:354 msgid "Why include a problem you can't submit to?" msgstr "" -#: judge/models/contest.py:506 +#: judge/models/contest.py:359 msgid "contest problem" msgstr "problema din concurs" -#: judge/models/contest.py:507 +#: judge/models/contest.py:360 msgid "contest problems" msgstr "problemele din concurs" -#: judge/models/contest.py:511 judge/models/submission.py:183 +#: judge/models/contest.py:364 judge/models/submission.py:181 msgid "submission" msgstr "submisie" -#: judge/models/contest.py:515 judge/models/contest.py:530 +#: judge/models/contest.py:368 judge/models/contest.py:383 msgid "participation" msgstr "" -#: judge/models/contest.py:519 +#: judge/models/contest.py:372 msgid "Whether this submission was ran only on pretests." msgstr "" -#: judge/models/contest.py:523 +#: judge/models/contest.py:376 msgid "contest submission" msgstr "submisie de concurs" -#: judge/models/contest.py:524 +#: judge/models/contest.py:377 msgid "contest submissions" msgstr "submisii de concurs" -#: judge/models/contest.py:532 +#: judge/models/contest.py:385 msgid "rank" msgstr "" -#: judge/models/contest.py:533 +#: judge/models/contest.py:386 msgid "rating" msgstr "" -#: judge/models/contest.py:534 +#: judge/models/contest.py:387 msgid "volatility" msgstr "" -#: judge/models/contest.py:535 +#: judge/models/contest.py:388 msgid "last rated" msgstr "" -#: judge/models/contest.py:539 +#: judge/models/contest.py:392 msgid "contest rating" msgstr "rating de la concurs" -#: judge/models/contest.py:540 +#: judge/models/contest.py:393 msgid "contest ratings" msgstr "ratinguri de la concurs" -#: judge/models/contest.py:560 +#: judge/models/contest.py:412 msgid "contest moss result" msgstr "" -#: judge/models/contest.py:561 +#: judge/models/contest.py:413 msgid "contest moss results" msgstr "" @@ -1181,7 +1079,7 @@ msgstr "" msgid "post title" msgstr "" -#: judge/models/interface.py:67 judge/models/problem.py:432 +#: judge/models/interface.py:67 judge/models/problem.py:395 msgid "authors" msgstr "" @@ -1189,7 +1087,7 @@ msgstr "" msgid "slug" msgstr "" -#: judge/models/interface.py:69 judge/models/problem.py:430 +#: judge/models/interface.py:69 judge/models/problem.py:393 msgid "public visibility" msgstr "" @@ -1213,21 +1111,15 @@ msgstr "" msgid "openGraph image" msgstr "" -#: judge/models/interface.py:76 -#, fuzzy -#| msgid "If private, only these organizations may see the contest" -msgid "If private, only these organizations may see the blog post." -msgstr "Dacă e privat, doar aceste organizaţii pot vedea acest concurs" - -#: judge/models/interface.py:105 +#: judge/models/interface.py:91 msgid "Edit all posts" msgstr "" -#: judge/models/interface.py:107 +#: judge/models/interface.py:93 msgid "blog post" msgstr "postare pe blog" -#: judge/models/interface.py:108 +#: judge/models/interface.py:94 msgid "blog posts" msgstr "postări pe blog" @@ -1251,6 +1143,10 @@ msgstr "" msgid "message timestamp" msgstr "" +#: judge/models/message.py:16 +msgid "read" +msgstr "" + #: judge/models/message.py:20 msgid "messages in the thread" msgstr "" @@ -1387,7 +1283,7 @@ msgid "" "are supported." msgstr "" -#: judge/models/problem.py:123 judge/models/problem.py:417 +#: judge/models/problem.py:123 judge/models/problem.py:380 msgid "memory limit" msgstr "" @@ -1460,188 +1356,188 @@ msgstr "" msgid "If private, only these organizations may see the problem." msgstr "" -#: judge/models/problem.py:395 judge/models/problem.py:413 -#: judge/models/runtime.py:111 +#: judge/models/problem.py:358 judge/models/problem.py:376 +#: judge/models/runtime.py:108 msgid "language" msgstr "limbaj" -#: judge/models/problem.py:396 +#: judge/models/problem.py:359 msgid "translated name" msgstr "" -#: judge/models/problem.py:397 +#: judge/models/problem.py:360 msgid "translated description" msgstr "" -#: judge/models/problem.py:401 +#: judge/models/problem.py:364 msgid "problem translation" msgstr "" -#: judge/models/problem.py:402 +#: judge/models/problem.py:365 msgid "problem translations" msgstr "" -#: judge/models/problem.py:406 +#: judge/models/problem.py:369 msgid "clarified problem" msgstr "" -#: judge/models/problem.py:407 +#: judge/models/problem.py:370 msgid "clarification body" msgstr "" -#: judge/models/problem.py:408 +#: judge/models/problem.py:371 msgid "clarification timestamp" msgstr "" -#: judge/models/problem.py:423 +#: judge/models/problem.py:386 msgid "language-specific resource limit" msgstr "limita de resurse specifică limbii" -#: judge/models/problem.py:424 +#: judge/models/problem.py:387 msgid "language-specific resource limits" msgstr "limite de resurse specifică limbii" -#: judge/models/problem.py:428 +#: judge/models/problem.py:391 msgid "associated problem" msgstr "" -#: judge/models/problem.py:431 +#: judge/models/problem.py:394 msgid "publish date" msgstr "" -#: judge/models/problem.py:433 +#: judge/models/problem.py:396 msgid "editorial content" msgstr "" -#: judge/models/problem.py:449 +#: judge/models/problem.py:412 msgid "solution" msgstr "soluţie" -#: judge/models/problem.py:450 +#: judge/models/problem.py:413 msgid "solutions" msgstr "soluţii" -#: judge/models/problem_data.py:26 +#: judge/models/problem_data.py:24 msgid "Standard" msgstr "" -#: judge/models/problem_data.py:27 +#: judge/models/problem_data.py:25 msgid "Floats" msgstr "" -#: judge/models/problem_data.py:28 +#: judge/models/problem_data.py:26 msgid "Floats (absolute)" msgstr "" -#: judge/models/problem_data.py:29 +#: judge/models/problem_data.py:27 msgid "Floats (relative)" msgstr "" -#: judge/models/problem_data.py:30 +#: judge/models/problem_data.py:28 msgid "Non-trailing spaces" msgstr "" -#: judge/models/problem_data.py:31 +#: judge/models/problem_data.py:29 msgid "Unordered" msgstr "" -#: judge/models/problem_data.py:32 +#: judge/models/problem_data.py:30 msgid "Byte identical" msgstr "" -#: judge/models/problem_data.py:33 +#: judge/models/problem_data.py:31 msgid "Line-by-line" msgstr "" -#: judge/models/problem_data.py:34 +#: judge/models/problem_data.py:32 msgid "Custom checker (PY)" msgstr "" -#: judge/models/problem_data.py:35 +#: judge/models/problem_data.py:33 msgid "Custom validator (CPP)" msgstr "" -#: judge/models/problem_data.py:42 +#: judge/models/problem_data.py:40 msgid "data zip file" msgstr "" -#: judge/models/problem_data.py:44 +#: judge/models/problem_data.py:42 msgid "generator file" msgstr "" -#: judge/models/problem_data.py:46 judge/models/problem_data.py:121 +#: judge/models/problem_data.py:44 judge/models/problem_data.py:110 msgid "output prefix length" msgstr "" -#: judge/models/problem_data.py:47 judge/models/problem_data.py:122 +#: judge/models/problem_data.py:45 judge/models/problem_data.py:111 msgid "output limit length" msgstr "" -#: judge/models/problem_data.py:48 +#: judge/models/problem_data.py:46 msgid "init.yml generation feedback" msgstr "" -#: judge/models/problem_data.py:49 judge/models/problem_data.py:123 +#: judge/models/problem_data.py:47 judge/models/problem_data.py:112 msgid "checker" msgstr "" -#: judge/models/problem_data.py:50 judge/models/problem_data.py:124 +#: judge/models/problem_data.py:48 judge/models/problem_data.py:113 msgid "checker arguments" msgstr "" -#: judge/models/problem_data.py:51 judge/models/problem_data.py:125 +#: judge/models/problem_data.py:49 judge/models/problem_data.py:114 msgid "checker arguments as a JSON object" msgstr "" -#: judge/models/problem_data.py:52 +#: judge/models/problem_data.py:50 msgid "custom checker file" msgstr "" -#: judge/models/problem_data.py:58 +#: judge/models/problem_data.py:56 msgid "custom validator file" msgstr "" -#: judge/models/problem_data.py:108 +#: judge/models/problem_data.py:97 msgid "problem data set" msgstr "" -#: judge/models/problem_data.py:110 +#: judge/models/problem_data.py:99 msgid "case position" msgstr "" -#: judge/models/problem_data.py:111 +#: judge/models/problem_data.py:100 msgid "case type" msgstr "" -#: judge/models/problem_data.py:112 +#: judge/models/problem_data.py:101 msgid "Normal case" msgstr "" -#: judge/models/problem_data.py:113 +#: judge/models/problem_data.py:102 msgid "Batch start" msgstr "" -#: judge/models/problem_data.py:114 +#: judge/models/problem_data.py:103 msgid "Batch end" msgstr "" -#: judge/models/problem_data.py:116 +#: judge/models/problem_data.py:105 msgid "input file name" msgstr "" -#: judge/models/problem_data.py:117 +#: judge/models/problem_data.py:106 msgid "output file name" msgstr "" -#: judge/models/problem_data.py:118 +#: judge/models/problem_data.py:107 msgid "generator arguments" msgstr "" -#: judge/models/problem_data.py:119 +#: judge/models/problem_data.py:108 msgid "point value" msgstr "" -#: judge/models/problem_data.py:120 +#: judge/models/problem_data.py:109 msgid "case is pretest?" msgstr "" @@ -1714,7 +1610,7 @@ msgid "" msgstr "" #: judge/models/profile.py:76 judge/models/profile.py:93 -#: judge/models/profile.py:212 +#: judge/models/profile.py:192 msgid "organization" msgstr "organizație" @@ -1810,31 +1706,31 @@ msgstr "" msgid "Notes for administrators regarding this user." msgstr "" -#: judge/models/profile.py:206 +#: judge/models/profile.py:186 msgid "user profile" msgstr "profil utilizator" -#: judge/models/profile.py:207 +#: judge/models/profile.py:187 msgid "user profiles" msgstr "profiluri utilizatori" -#: judge/models/profile.py:214 +#: judge/models/profile.py:194 msgid "request time" msgstr "" -#: judge/models/profile.py:215 +#: judge/models/profile.py:195 msgid "state" msgstr "" -#: judge/models/profile.py:220 +#: judge/models/profile.py:200 msgid "reason" msgstr "" -#: judge/models/profile.py:223 +#: judge/models/profile.py:203 msgid "organization join request" msgstr "cerere de a se alătura organizaţiei" -#: judge/models/profile.py:224 +#: judge/models/profile.py:204 msgid "organization join requests" msgstr "cereri de a se alătura organizaţiei" @@ -1925,88 +1821,88 @@ msgstr "" msgid "The extension of source files, e.g., \"py\" or \"cpp\"." msgstr "" -#: judge/models/runtime.py:112 +#: judge/models/runtime.py:109 msgid "languages" msgstr "limbaje" -#: judge/models/runtime.py:116 +#: judge/models/runtime.py:113 msgid "language to which this runtime belongs" msgstr "" -#: judge/models/runtime.py:117 +#: judge/models/runtime.py:114 msgid "judge on which this runtime exists" msgstr "" -#: judge/models/runtime.py:118 +#: judge/models/runtime.py:115 msgid "runtime name" msgstr "" -#: judge/models/runtime.py:119 +#: judge/models/runtime.py:116 msgid "runtime version" msgstr "" -#: judge/models/runtime.py:120 +#: judge/models/runtime.py:117 msgid "order in which to display this runtime" msgstr "" -#: judge/models/runtime.py:124 +#: judge/models/runtime.py:121 msgid "Server name, hostname-style" msgstr "Numele server-ului, in stil de hostname" -#: judge/models/runtime.py:125 +#: judge/models/runtime.py:122 msgid "time of creation" msgstr "" -#: judge/models/runtime.py:126 +#: judge/models/runtime.py:123 #, fuzzy #| msgid "A key to authenticated this judge" msgid "A key to authenticate this judge" msgstr "O cheie de autentificare pentru acest judge" -#: judge/models/runtime.py:127 +#: judge/models/runtime.py:124 msgid "authentication key" msgstr "" -#: judge/models/runtime.py:128 +#: judge/models/runtime.py:125 msgid "block judge" msgstr "" -#: judge/models/runtime.py:129 +#: judge/models/runtime.py:126 msgid "" "Whether this judge should be blocked from connecting, even if its key is " "correct." msgstr "" -#: judge/models/runtime.py:131 +#: judge/models/runtime.py:128 msgid "judge online status" msgstr "" -#: judge/models/runtime.py:132 +#: judge/models/runtime.py:129 msgid "judge start time" msgstr "" -#: judge/models/runtime.py:133 +#: judge/models/runtime.py:130 msgid "response time" msgstr "" -#: judge/models/runtime.py:134 +#: judge/models/runtime.py:131 msgid "system load" msgstr "" -#: judge/models/runtime.py:135 +#: judge/models/runtime.py:132 msgid "Load for the last minute, divided by processors to be fair." msgstr "Încărcarea in ultimul minut, împărţită la numarul de procesoare." -#: judge/models/runtime.py:139 judge/models/runtime.py:179 +#: judge/models/runtime.py:136 judge/models/runtime.py:176 msgid "judges" msgstr "evaluatoare" -#: judge/models/runtime.py:178 +#: judge/models/runtime.py:175 msgid "judge" msgstr "evaluator" #: judge/models/submission.py:20 judge/models/submission.py:47 -#: judge/utils/problems.py:79 +#: judge/utils/problems.py:77 msgid "Accepted" msgstr "Accepted" @@ -2035,7 +1931,7 @@ msgid "Runtime Error" msgstr "Runtime Error" #: judge/models/submission.py:27 judge/models/submission.py:41 -#: judge/models/submission.py:55 judge/utils/problems.py:81 +#: judge/models/submission.py:55 judge/utils/problems.py:79 msgid "Compile Error" msgstr "Compile Error" @@ -2076,15 +1972,15 @@ msgstr "Internal Error (judging server error)" msgid "submission time" msgstr "" -#: judge/models/submission.py:67 judge/models/submission.py:203 +#: judge/models/submission.py:67 judge/models/submission.py:201 msgid "execution time" msgstr "" -#: judge/models/submission.py:68 judge/models/submission.py:204 +#: judge/models/submission.py:68 judge/models/submission.py:202 msgid "memory usage" msgstr "" -#: judge/models/submission.py:69 judge/models/submission.py:205 +#: judge/models/submission.py:69 judge/models/submission.py:203 msgid "points granted" msgstr "" @@ -2121,64 +2017,58 @@ msgid "judged on" msgstr "" #: judge/models/submission.py:81 -#, fuzzy -#| msgid "submission test case" -msgid "submission judge time" -msgstr "testul submisiei" - -#: judge/models/submission.py:82 msgid "was rejudged by admin" msgstr "" -#: judge/models/submission.py:83 +#: judge/models/submission.py:82 msgid "was ran on pretests only" msgstr "" -#: judge/models/submission.py:184 templates/contest/moss.html:58 +#: judge/models/submission.py:182 templates/contest/moss.html:58 msgid "submissions" msgstr "submisii" -#: judge/models/submission.py:188 judge/models/submission.py:199 +#: judge/models/submission.py:186 judge/models/submission.py:197 msgid "associated submission" msgstr "" -#: judge/models/submission.py:190 +#: judge/models/submission.py:188 msgid "source code" msgstr "" -#: judge/models/submission.py:201 +#: judge/models/submission.py:199 msgid "test case ID" msgstr "" -#: judge/models/submission.py:202 +#: judge/models/submission.py:200 msgid "status flag" msgstr "" -#: judge/models/submission.py:206 +#: judge/models/submission.py:204 msgid "points possible" msgstr "" -#: judge/models/submission.py:207 +#: judge/models/submission.py:205 msgid "batch number" msgstr "" -#: judge/models/submission.py:208 +#: judge/models/submission.py:206 msgid "judging feedback" msgstr "" -#: judge/models/submission.py:209 +#: judge/models/submission.py:207 msgid "extended judging feedback" msgstr "" -#: judge/models/submission.py:210 +#: judge/models/submission.py:208 msgid "program output" msgstr "" -#: judge/models/submission.py:218 +#: judge/models/submission.py:216 msgid "submission test case" msgstr "testul submisiei" -#: judge/models/submission.py:219 +#: judge/models/submission.py:217 msgid "submission test cases" msgstr "testele submisiei" @@ -2230,24 +2120,12 @@ msgstr "" msgid "message time" msgstr "" -#: judge/pdf_problems.py:147 judge/pdf_problems.py:199 -#: judge/pdf_problems.py:259 +#: judge/pdf_problems.py:134 judge/pdf_problems.py:186 +#: judge/pdf_problems.py:246 msgid "Page [page] of [topage]" msgstr "" -#: judge/pdf_problems.py:280 -#, fuzzy, python-format -#| msgid "Page %d of Posts" -msgid "Page %s of %s" -msgstr "Pagina %d din Posturi" - -#: judge/tasks/contest.py:19 -#, fuzzy -#| msgid "Recalculate scores" -msgid "Recalculating contest scores" -msgstr "Recalculați scorurile" - -#: judge/tasks/contest.py:40 +#: judge/tasks/moss.py:25 msgid "Running MOSS" msgstr "" @@ -2259,60 +2137,60 @@ msgstr "" msgid "Recalculating user points" msgstr "" -#: judge/utils/problem_data.py:70 +#: judge/utils/problem_data.py:68 msgid "Empty batches not allowed." msgstr "" -#: judge/utils/problem_data.py:78 judge/utils/problem_data.py:99 +#: judge/utils/problem_data.py:76 judge/utils/problem_data.py:97 msgid "How did you corrupt the custom checker path?" msgstr "" -#: judge/utils/problem_data.py:120 +#: judge/utils/problem_data.py:118 #, python-format msgid "Points must be defined for non-batch case #%d." msgstr "" -#: judge/utils/problem_data.py:125 +#: judge/utils/problem_data.py:123 #, python-format msgid "Input file for case %d does not exist: %s" msgstr "" -#: judge/utils/problem_data.py:128 +#: judge/utils/problem_data.py:126 #, python-format msgid "Output file for case %d does not exist: %s" msgstr "" -#: judge/utils/problem_data.py:153 +#: judge/utils/problem_data.py:151 #, python-format msgid "Batch start case #%d requires points." msgstr "" -#: judge/utils/problem_data.py:174 +#: judge/utils/problem_data.py:172 #, python-format msgid "Attempt to end batch outside of one in case #%d" msgstr "" -#: judge/utils/problem_data.py:192 +#: judge/utils/problem_data.py:190 msgid "How did you corrupt the zip path?" msgstr "" -#: judge/utils/problem_data.py:198 +#: judge/utils/problem_data.py:196 msgid "How did you corrupt the generator path?" msgstr "" -#: judge/utils/problems.py:80 +#: judge/utils/problems.py:78 msgid "Wrong" msgstr "" -#: judge/utils/problems.py:82 +#: judge/utils/problems.py:80 msgid "Timeout" msgstr "" -#: judge/utils/problems.py:83 +#: judge/utils/problems.py:81 msgid "Error" msgstr "" -#: judge/utils/problems.py:94 +#: judge/utils/problems.py:92 msgid "Can't pass both queryset and keyword filters" msgstr "Nu se poate trece amândoua queryset şi filtrele cu cuvinte cheie" @@ -2358,8 +2236,7 @@ msgctxt "hours and minutes" msgid "%h:%m" msgstr "%h:%m" -#: judge/views/about.py:7 templates/organization/home.html:112 -#: templates/user/user-about.html:83 templates/user/user-tabs.html:4 +#: judge/views/about.py:7 templates/user/user-about.html:33 msgid "About" msgstr "Despre" @@ -2367,167 +2244,157 @@ msgstr "Despre" msgid "Custom Checker Sample" msgstr "" -#: judge/views/blog.py:45 +#: judge/views/blog.py:38 #, python-format msgid "Page %d of Posts" msgstr "Pagina %d din Posturi" -#: judge/views/comment.py:28 +#: judge/views/comment.py:27 msgid "Messing around, are we?" msgstr "Ne facem de cap, nu-i așa?" -#: judge/views/comment.py:37 +#: judge/views/comment.py:36 msgid "You must solve at least one problem before you can vote." msgstr "" -#: judge/views/comment.py:64 +#: judge/views/comment.py:63 msgid "You already voted." msgstr "Ai votat deja." -#: judge/views/comment.py:126 judge/views/organization.py:344 +#: judge/views/comment.py:120 judge/views/organization.py:299 msgid "Edited from site" msgstr "Editat de pe site" -#: judge/views/comment.py:147 +#: judge/views/comment.py:141 msgid "Editing comment" msgstr "" -#: judge/views/contests.py:57 judge/views/contests.py:247 -#: judge/views/contests.py:250 judge/views/contests.py:424 +#: judge/views/contests.py:55 judge/views/contests.py:215 +#: judge/views/contests.py:218 judge/views/contests.py:389 msgid "No such contest" msgstr "Niciun concurs de acest fel" -#: judge/views/contests.py:58 judge/views/contests.py:248 +#: judge/views/contests.py:56 judge/views/contests.py:216 #, python-format msgid "Could not find a contest with the key \"%s\"." msgstr "Niciun concurs găsit cu cheia \"%s\"." -#: judge/views/contests.py:71 +#: judge/views/contests.py:81 msgid "Contests" msgstr "Concursuri" -#: judge/views/contests.py:251 +#: judge/views/contests.py:219 msgid "Could not find such contest." msgstr "Nu am putut găsi un concurs de acest fel." -#: judge/views/contests.py:254 +#: judge/views/contests.py:222 #, python-format msgid "Access to contest \"%s\" denied" msgstr "Nu aveți acces la concursul \"%s\"" -#: judge/views/contests.py:278 +#: judge/views/contests.py:246 msgid "Clone Contest" msgstr "" -#: judge/views/contests.py:343 +#: judge/views/contests.py:309 msgid "Contest not ongoing" msgstr "Concursul nu este în curs de desfăşurare" -#: judge/views/contests.py:344 +#: judge/views/contests.py:310 #, python-format msgid "\"%s\" is not currently ongoing." msgstr "Momentan, \"%s\" nu este în curs de desfăşurare." -#: judge/views/contests.py:348 +#: judge/views/contests.py:314 msgid "Already in contest" msgstr "Deja în concurs" -#: judge/views/contests.py:349 +#: judge/views/contests.py:315 #, python-format msgid "You are already in a contest: \"%s\"." msgstr "Sunteţi deja într-un concurs: \"%s\"." -#: judge/views/contests.py:352 +#: judge/views/contests.py:318 msgid "Banned from joining" msgstr "" -#: judge/views/contests.py:353 +#: judge/views/contests.py:319 msgid "" "You have been declared persona non grata for this contest. You are " "permanently barred from joining this contest." msgstr "" -#: judge/views/contests.py:414 +#: judge/views/contests.py:379 #, python-format msgid "Enter access code for \"%s\"" msgstr "" -#: judge/views/contests.py:425 +#: judge/views/contests.py:390 #, python-format msgid "You are not in contest \"%s\"." msgstr "Nu sunteţi în concursul \"%s\"." -#: judge/views/contests.py:444 +#: judge/views/contests.py:409 msgid "ContestCalendar requires integer year and month" msgstr "" -#: judge/views/contests.py:484 +#: judge/views/contests.py:449 #, python-format msgid "Contests in %(month)s" msgstr "Concursuri în %(month)s" -#: judge/views/contests.py:484 +#: judge/views/contests.py:449 msgid "F Y" msgstr "" -#: judge/views/contests.py:532 +#: judge/views/contests.py:496 #, fuzzy, python-format #| msgid "Statistics" msgid "%s Statistics" msgstr "Stastici" -#: judge/views/contests.py:717 +#: judge/views/contests.py:601 +msgid "???" +msgstr "" + +#: judge/views/contests.py:664 #, python-format msgid "%s Rankings" msgstr "" -#: judge/views/contests.py:725 -msgid "???" -msgstr "" - -#: judge/views/contests.py:741 +#: judge/views/contests.py:680 #, python-format msgid "Your participation in %s" msgstr "" -#: judge/views/contests.py:742 +#: judge/views/contests.py:681 #, python-format msgid "%s's participation in %s" msgstr "" -#: judge/views/contests.py:749 +#: judge/views/contests.py:685 msgid "Live" msgstr "" -#: judge/views/contests.py:761 templates/contest/contest-tabs.html:13 +#: judge/views/contests.py:697 msgid "Participation" msgstr "" -#: judge/views/contests.py:808 +#: judge/views/contests.py:743 #, python-format msgid "%s MOSS Results" msgstr "" -#: judge/views/contests.py:835 +#: judge/views/contests.py:770 #, python-format msgid "Running MOSS for %s..." msgstr "" -#: judge/views/contests.py:858 +#: judge/views/contests.py:793 #, python-format msgid "Contest tag: %s" msgstr "" -#: judge/views/contests.py:868 judge/views/ticket.py:57 -msgid "Issue description" -msgstr "" - -#: judge/views/contests.py:911 -#, fuzzy, python-format -#| msgid "Best solutions for %s" -msgid "New clarification for %s" -msgstr "Cele mai bune soluţii pentru %s" - #: judge/views/error.py:14 msgid "404 error" msgstr "eroare 404" @@ -2548,83 +2415,76 @@ msgid "corrupt page %s" msgstr "pagina corupta %s" #: judge/views/language.py:12 templates/status/judge-status-table.html:9 -#: templates/status/status-tabs.html:5 msgid "Runtimes" msgstr "Limbaje" -#: judge/views/notification.py:40 -#, python-format -msgid "Notifications (%d unseen)" -msgstr "" - -#: judge/views/organization.py:59 judge/views/organization.py:62 +#: judge/views/organization.py:44 judge/views/organization.py:47 msgid "No such organization" msgstr "Nicio organizaţie de acest fel" -#: judge/views/organization.py:60 +#: judge/views/organization.py:45 #, python-format msgid "Could not find an organization with the key \"%s\"." msgstr "Nicio organizaţie găsită cu cheia \"%s\"." -#: judge/views/organization.py:63 +#: judge/views/organization.py:48 msgid "Could not find such organization." msgstr "Nu am putut găsi organizaţii de acest fel." -#: judge/views/organization.py:79 judge/views/register.py:34 -#: templates/organization/list.html:32 templates/user/import/table_csv.html:9 -#: templates/user/user-list-tabs.html:6 +#: judge/views/organization.py:72 judge/views/register.py:34 +#: templates/organization/list.html:15 msgid "Organizations" msgstr "Organizaţii" -#: judge/views/organization.py:130 +#: judge/views/organization.py:93 #, python-format msgid "%s Members" msgstr "%s Membri" -#: judge/views/organization.py:159 judge/views/organization.py:162 -#: judge/views/organization.py:167 +#: judge/views/organization.py:118 judge/views/organization.py:121 +#: judge/views/organization.py:126 msgid "Joining organization" msgstr "Aderarea la organizaţie" -#: judge/views/organization.py:159 +#: judge/views/organization.py:118 msgid "You are already in the organization." msgstr "Sunteţi deja în organizaţie." -#: judge/views/organization.py:162 +#: judge/views/organization.py:121 msgid "This organization is not open." msgstr "Această organizaţie nu este deschisă." -#: judge/views/organization.py:179 +#: judge/views/organization.py:138 msgid "Leaving organization" msgstr "Părăsire organizaţie" -#: judge/views/organization.py:179 +#: judge/views/organization.py:138 #, python-format msgid "You are not in \"%s\"." msgstr "Nu sunteţi în \"%s\"." -#: judge/views/organization.py:203 +#: judge/views/organization.py:162 #, python-format msgid "Request to join %s" msgstr "Cerere de adăugare la %s" -#: judge/views/organization.py:221 +#: judge/views/organization.py:180 msgid "Join request detail" msgstr "Detalii despre cererea de adăugare" -#: judge/views/organization.py:254 +#: judge/views/organization.py:209 #, python-format msgid "Managing join requests for %s" msgstr "Gestionarea cererilor de asociere cu %s" -#: judge/views/organization.py:285 +#: judge/views/organization.py:240 #, python-format msgid "" "Your organization can only receive %d more members. You cannot approve %d " "users." msgstr "" -#: judge/views/organization.py:297 +#: judge/views/organization.py:252 #, python-format msgid "Approved %d user." msgid_plural "Approved %d users." @@ -2632,7 +2492,7 @@ msgstr[0] "Aprobat %d utilizator." msgstr[1] "Aprobat %d utilizatori." msgstr[2] "Aprobat %d utilizatori." -#: judge/views/organization.py:298 +#: judge/views/organization.py:253 #, python-format msgid "Rejected %d user." msgid_plural "Rejected %d users." @@ -2640,32 +2500,32 @@ msgstr[0] "Respins %d utilizator." msgstr[1] "Respins %d utilizatori." msgstr[2] "Respins %d utilizatori." -#: judge/views/organization.py:328 +#: judge/views/organization.py:283 #, python-format msgid "Editing %s" msgstr "Editare %s" -#: judge/views/organization.py:352 judge/views/organization.py:360 +#: judge/views/organization.py:307 judge/views/organization.py:315 msgid "Can't edit organization" msgstr "Nu puteţi edita organizaţia" -#: judge/views/organization.py:353 +#: judge/views/organization.py:308 msgid "You are not allowed to edit this organization." msgstr "Nu aveţi permisiunea pentru a edita această organizaţie." -#: judge/views/organization.py:361 +#: judge/views/organization.py:316 msgid "You are not allowed to kick people from this organization." msgstr "" -#: judge/views/organization.py:366 judge/views/organization.py:370 +#: judge/views/organization.py:321 judge/views/organization.py:325 msgid "Can't kick user" msgstr "" -#: judge/views/organization.py:367 +#: judge/views/organization.py:322 msgid "The user you are trying to kick does not exist!" msgstr "" -#: judge/views/organization.py:371 +#: judge/views/organization.py:326 #, python-format msgid "The user you are trying to kick is not in organization: %s." msgstr "" @@ -2689,17 +2549,16 @@ msgstr "" msgid "Editorial for {0}" msgstr "" -#: judge/views/problem.py:285 templates/contest/contest.html:79 -#: templates/user/user-about.html:28 templates/user/user-tabs.html:5 -#: templates/user/users-table.html:31 +#: judge/views/problem.py:286 templates/contest/contest.html:79 +#: templates/user/users-table.html:23 msgid "Problems" msgstr "Probleme" -#: judge/views/problem.py:585 +#: judge/views/problem.py:547 msgid "Banned from submitting" msgstr "" -#: judge/views/problem.py:586 +#: judge/views/problem.py:548 msgid "" "You have been declared persona non grata for this problem. You are " "permanently barred from submitting this problem." @@ -2707,20 +2566,20 @@ msgstr "" "Ați fost declarat \"persoană neacceptată\" pentru această problemă. Sunteți " "exclus definitiv de la submiterea acestei probleme." -#: judge/views/problem.py:600 +#: judge/views/problem.py:562 msgid "Too many submissions" msgstr "" -#: judge/views/problem.py:601 +#: judge/views/problem.py:563 msgid "You have exceeded the submission limit for this problem." msgstr "" -#: judge/views/problem.py:661 judge/views/problem.py:664 +#: judge/views/problem.py:633 judge/views/problem.py:636 #, python-format msgid "Submit to %(problem)s" msgstr "" -#: judge/views/problem.py:679 +#: judge/views/problem.py:652 msgid "Clone Problem" msgstr "" @@ -2761,22 +2620,22 @@ msgstr "" msgid "Generated init.yml for %s" msgstr "" -#: judge/views/problem_manage.py:52 judge/views/problem_manage.py:55 +#: judge/views/problem_manage.py:50 judge/views/problem_manage.py:53 #, python-format msgid "Managing submissions for %s" msgstr "" -#: judge/views/problem_manage.py:97 +#: judge/views/problem_manage.py:95 #, python-format msgid "Rejudging selected submissions for %s..." msgstr "" -#: judge/views/problem_manage.py:141 +#: judge/views/problem_manage.py:110 #, python-format msgid "Rescoring all submissions for %s..." msgstr "" -#: judge/views/problem_manage.py:150 +#: judge/views/problem_manage.py:119 #, python-format msgid "Successfully scheduled %d submission for rejudging." msgid_plural "Successfully scheduled %d submissions for rejudging." @@ -2830,7 +2689,7 @@ msgstr "Limba preferată" msgid "Subscribe to newsletter?" msgstr "" -#: judge/views/register.py:55 +#: judge/views/register.py:45 #, python-format msgid "" "The email address \"%s\" is already taken. Only one registration is allowed " @@ -2839,7 +2698,7 @@ msgstr "" "Adresa de email \"%s\" a fost deja folosită. O singură înregistrare este " "permisă pe fiecare adresă." -#: judge/views/register.py:61 +#: judge/views/register.py:51 msgid "" "Your email provider is not allowed due to history of abuse. Please use a " "reputable email provider." @@ -2847,11 +2706,11 @@ msgstr "" "Furnizorul dvs. de e-mail nu este permis datorită istoriei de abuz. Vă rugăm " "să folosiţi un furnizor de e-mail respectabil." -#: judge/views/register.py:67 judge/views/register.py:105 +#: judge/views/register.py:57 judge/views/register.py:95 msgid "Registration" msgstr "Înregistrare" -#: judge/views/register.py:116 +#: judge/views/register.py:106 msgid "Authentication failure" msgstr "Problemă la autentificare" @@ -2867,49 +2726,49 @@ msgstr "Stare" msgid "Version matrix" msgstr "" -#: judge/views/submission.py:84 judge/views/submission.py:91 +#: judge/views/submission.py:83 judge/views/submission.py:90 #, python-format msgid "Submission of %(problem)s by %(user)s" msgstr "Soluţia problemei %(problem)s de %(user)s" -#: judge/views/submission.py:244 judge/views/submission.py:245 -#: templates/problem/problem.html:167 +#: judge/views/submission.py:227 judge/views/submission.py:228 +#: templates/problem/problem.html:127 msgid "All submissions" msgstr "Toate soluţile" -#: judge/views/submission.py:404 +#: judge/views/submission.py:384 msgid "All my submissions" msgstr "" -#: judge/views/submission.py:405 +#: judge/views/submission.py:385 #, python-format msgid "All submissions by %s" msgstr "Toate soluţiile submise de %s" -#: judge/views/submission.py:436 +#: judge/views/submission.py:416 #, python-format msgid "All submissions for %s" msgstr "Toate soluţiile pentru %s" -#: judge/views/submission.py:455 +#: judge/views/submission.py:435 msgid "Must pass a problem" msgstr "Trebuie să rezolvaţi o problemă" -#: judge/views/submission.py:501 +#: judge/views/submission.py:481 #, python-format msgid "My submissions for %(problem)s" msgstr "" -#: judge/views/submission.py:502 +#: judge/views/submission.py:482 #, python-format msgid "%(user)s's submissions for %(problem)s" msgstr "Soluţiile lui %(user)s pentru %(problem)s" -#: judge/views/submission.py:603 +#: judge/views/submission.py:583 msgid "Must pass a contest" msgstr "Trebuie să completaţi un concurs" -#: judge/views/submission.py:622 +#: judge/views/submission.py:602 #, python-brace-format msgid "" "{0}'s submissions for {2} in {0} pentru {2} în {4}" -#: judge/views/submission.py:629 +#: judge/views/submission.py:609 #, python-brace-format msgid "" "{0}'s submissions for problem {2} in {3}" "" msgstr "" -#: judge/views/ticket.py:50 judge/views/ticket.py:56 +#: judge/views/ticket.py:33 judge/views/ticket.py:39 msgid "Ticket title" msgstr "" -#: judge/views/ticket.py:107 judge/views/ticket.py:110 +#: judge/views/ticket.py:40 +msgid "Issue description" +msgstr "" + +#: judge/views/ticket.py:85 judge/views/ticket.py:88 #, python-format msgid "New ticket for %s" msgstr "" -#: judge/views/ticket.py:170 +#: judge/views/ticket.py:142 #, python-format msgid "%(title)s - Ticket %(id)d" msgstr "" -#: judge/views/ticket.py:279 +#: judge/views/ticket.py:251 #, python-format msgid "Tickets - Page %(number)d of %(total)d" msgstr "" -#: judge/views/ticket.py:328 +#: judge/views/ticket.py:300 #, python-format msgid "New Ticket: %s" msgstr "" -#: judge/views/ticket.py:329 +#: judge/views/ticket.py:301 #, python-format msgid "#%(id)d, assigned to: %(users)s" msgstr "" -#: judge/views/ticket.py:331 +#: judge/views/ticket.py:303 msgid ", " msgstr "" -#: judge/views/ticket.py:331 +#: judge/views/ticket.py:303 msgid "no one" msgstr "" -#: judge/views/ticket.py:351 +#: judge/views/ticket.py:323 #, python-format msgid "New Ticket Message For: %s" msgstr "" @@ -2979,52 +2842,41 @@ msgstr "" msgid "Perform Two Factor Authentication" msgstr "" -#: judge/views/user.py:74 +#: judge/views/user.py:68 msgid "No such user" msgstr "Niciun astfel de utilizator" -#: judge/views/user.py:74 +#: judge/views/user.py:68 #, python-format msgid "No user handle \"%s\"." msgstr "Porecla de utilizator \"%s\" nu există." -#: judge/views/user.py:78 +#: judge/views/user.py:72 msgid "My account" msgstr "" -#: judge/views/user.py:79 +#: judge/views/user.py:73 #, python-format msgid "User %s" msgstr "Utilizatorul %s" -#: judge/views/user.py:148 -#, fuzzy -#| msgid "M j, Y, G:i" -msgid "M j, Y" -msgstr "M j, Y, G:i" - -#: judge/views/user.py:171 +#: judge/views/user.py:136 msgid "M j, Y, G:i" msgstr "M j, Y, G:i" -#: judge/views/user.py:290 +#: judge/views/user.py:221 msgid "Updated on site" msgstr "Actualizat pe loc" -#: judge/views/user.py:323 templates/admin/auth/user/change_form.html:14 -#: templates/admin/auth/user/change_form.html:17 templates/base.html:238 -#: templates/user/user-tabs.html:10 +#: judge/views/user.py:254 templates/admin/auth/user/change_form.html:14 +#: templates/admin/auth/user/change_form.html:17 templates/base.html:224 msgid "Edit profile" msgstr "Editează-ți profilul" -#: judge/views/user.py:332 templates/user/user-list-tabs.html:4 +#: judge/views/user.py:263 msgid "Leaderboard" msgstr "" -#: judge/views/user.py:407 -msgid "Import Users" -msgstr "" - #: judge/views/widgets.py:48 judge/views/widgets.py:58 #, python-format msgid "Invalid upstream data: %s" @@ -3062,7 +2914,7 @@ msgid "View Submissions" msgstr "" #: templates/admin/judge/problem/change_form.html:17 -#: templates/user/user-base.html:112 +#: templates/user/user-base.html:61 msgid "View submissions" msgstr "Vezi soluții" @@ -3077,152 +2929,92 @@ msgstr "Editează utilizator" msgid "Rejudge" msgstr "Rejurizeză" -#: templates/base.html:230 -#, python-format -msgid "Hello, %(username)s." -msgstr "Bună ziua, %(username)s." - -#: templates/base.html:236 templates/comments/list.html:89 -#: templates/contest/contest-list-tabs.html:24 -#: templates/contest/ranking-table.html:53 -#: templates/problem/problem-list-tabs.html:6 +#: templates/base.html:222 templates/comments/list.html:89 +#: templates/contest/ranking-table.html:39 #: templates/submission/info-base.html:12 -#: templates/submission/submission-list-tabs.html:15 msgid "Admin" msgstr "Administrare" -#: templates/base.html:245 +#: templates/base.html:231 msgid "Log out" msgstr "Log out" -#: templates/base.html:254 +#: templates/base.html:240 #: templates/registration/password_reset_complete.html:4 msgid "Log in" msgstr "Autentificare" -#: templates/base.html:255 templates/registration/registration_form.html:177 +#: templates/base.html:241 templates/registration/registration_form.html:177 msgid "or" msgstr "sau" -#: templates/base.html:256 +#: templates/base.html:242 msgid "Sign up" msgstr "" -#: templates/base.html:271 +#: templates/base.html:254 msgid "spectating" msgstr "" -#: templates/base.html:284 +#: templates/base.html:267 msgid "This site works best with JavaScript enabled." msgstr "Acest site funcționează cel mai bine cu JavaScript activat." -#: templates/blog/blog.html:13 templates/comments/list.html:68 -#: templates/comments/list.html:83 templates/contest/contest-tabs.html:23 -#: templates/contest/tag-title.html:9 templates/flatpages/admin_link.html:3 -#: templates/license.html:10 templates/problem/editorial.html:14 +#: templates/blog/content.html:13 templates/comments/list.html:68 +#: templates/comments/list.html:83 templates/contest/tag-title.html:9 +#: templates/flatpages/admin_link.html:3 templates/license.html:10 +#: templates/problem/editorial.html:14 msgid "Edit" msgstr "Modifică" -#: templates/blog/blog.html:26 -#, python-format -msgid "" -"\n" -" posted on %(time)s\n" -" " -msgstr "" - -#: templates/blog/content.html:10 -#, fuzzy, python-brace-format -#| msgid "Updated on site" -msgid "posted on {time}" -msgstr "Actualizat pe loc" - -#: templates/blog/dashboard.html:21 -#, python-format -msgid "" -"\n" -" on %(time)s\n" -" " -msgstr "" - -#: templates/blog/list.html:93 +#: templates/blog/list.html:85 msgid "Blog" msgstr "Blog" -#: templates/blog/list.html:95 +#: templates/blog/list.html:87 msgid "Events" msgstr "Evenimente" -#: templates/blog/list.html:100 +#: templates/blog/list.html:92 msgid "News" msgstr "" -#: templates/blog/list.html:115 templates/problem/list.html:347 -#: templates/problem/problem.html:361 +#: templates/blog/list.html:130 templates/problem/problem.html:310 msgid "Clarifications" msgstr "" -#: templates/blog/list.html:121 -msgid "Add" -msgstr "" - -#: templates/blog/list.html:140 templates/problem/list.html:369 -#: templates/problem/problem.html:372 +#: templates/blog/list.html:146 templates/problem/problem.html:321 msgid "No clarifications have been made at this time." msgstr "" -#: templates/blog/list.html:148 +#: templates/blog/list.html:154 msgid "Ongoing contests" msgstr "Concursuri in desfășurare" -#: templates/blog/list.html:166 +#: templates/blog/list.html:172 msgid "Upcoming contests" msgstr "Concursuri programate" -#: templates/blog/list.html:184 -msgid "My open tickets" -msgstr "" - -#: templates/blog/list.html:206 -msgid "New tickets" -msgstr "" - -#: templates/blog/list.html:227 -msgid "New problems" -msgstr "Probleme noi" - -#: templates/blog/list.html:244 +#: templates/blog/list.html:189 msgid "Comment stream" msgstr "Comentarii" -#: templates/chat/chat.html:305 -msgid "Chat" +#: templates/blog/list.html:208 +msgid "New problems" +msgstr "Probleme noi" + +#: templates/blog/list.html:225 +msgid "My open tickets" msgstr "" -#: templates/chat/chat.html:307 templates/chat/chat.html:314 -#, fuzzy -#| msgid "Online Judge" -msgid "Online Users" -msgstr "Online Judge" - -#: templates/chat/chat.html:315 -msgid "Refresh" +#: templates/blog/list.html:246 +msgid "New tickets" msgstr "" -#: templates/chat/chat.html:333 -msgid "Emoji" +#: templates/chat/chat.html:167 +msgid "Your message" msgstr "" -#: templates/chat/chat.html:334 -msgid "Enter your message" -msgstr "" - -#: templates/chat/message.html:20 -#, fuzzy -#| msgid "Delete?" -msgid "Delete" -msgstr "Ştergeţi?" - #: templates/comments/list.html:2 msgid "Comments" msgstr "Comentarii" @@ -3231,22 +3023,11 @@ msgstr "Comentarii" msgid "Please login to vote" msgstr "" -#: templates/comments/list.html:40 -#, fuzzy, python-brace-format -#| msgid "comment vote" -msgid "commented on {time}" -msgstr "votul comentariului" - -#: templates/comments/list.html:49 -#, python-format -msgid "edit %(edits)s" -msgstr "" - -#: templates/comments/list.html:51 templates/comments/media-js.html:92 +#: templates/comments/list.html:51 templates/comments/media-js.html:77 msgid "edited" msgstr "" -#: templates/comments/list.html:60 templates/notification/list.html:14 +#: templates/comments/list.html:60 msgid "Link" msgstr "" @@ -3254,54 +3035,36 @@ msgstr "" msgid "Reply" msgstr "" -#: templates/comments/list.html:86 templates/contest/list.html:91 -#: templates/contest/list.html:95 templates/contest/list.html:280 +#: templates/comments/list.html:86 msgid "Hide" msgstr "" -#: templates/comments/list.html:101 -#, python-format -msgid "" -"\n" -" This comment is hidden due " -"to too much negative feedback.\n" -" Click here to view it.\n" -" " -msgstr "" - -#: templates/comments/list.html:121 +#: templates/comments/list.html:120 msgid "There are no comments at the moment." msgstr "Nu sunt comentarii în acest moment." -#: templates/comments/list.html:127 +#: templates/comments/list.html:126 msgid "New comment" msgstr "Comentariu nou" -#: templates/comments/list.html:141 +#: templates/comments/list.html:140 msgid "Invalid comment body." msgstr "Invalid comment body." -#: templates/comments/list.html:149 +#: templates/comments/list.html:148 msgid "Post!" msgstr "Postează!" -#: templates/comments/list.html:157 +#: templates/comments/list.html:156 msgid "Comments are disabled on this page." msgstr "" -#: templates/comments/media-js.html:38 -#, fuzzy -#| msgid "hide the comment" -msgid "Replying to comment" -msgstr "ascunde comentariul" - -#: templates/comments/media-js.html:87 +#: templates/comments/media-js.html:72 #, python-brace-format msgid "edit {edits}" msgstr "" -#: templates/comments/media-js.html:90 +#: templates/comments/media-js.html:75 msgid "original" msgstr "" @@ -3345,11 +3108,6 @@ msgstr "Vineri" msgid "Saturday" msgstr "Sâmbătă" -#: templates/contest/clarification.html:52 templates/organization/new.html:10 -#: templates/ticket/new.html:38 -msgid "Create" -msgstr "Crează" - #: templates/contest/clone.html:37 msgid "Enter a new key for the cloned contest:" msgstr "" @@ -3370,178 +3128,97 @@ msgstr "" msgid "Next" msgstr "Următor" -#: templates/contest/contest-list-tabs.html:21 -#: templates/problem/problem-list-tabs.html:5 -msgid "List" -msgstr "" - -#: templates/contest/contest-list-tabs.html:22 -msgid "Calendar" -msgstr "" - -#: templates/contest/contest-tabs.html:4 templates/organization/home.html:105 -msgid "Info" -msgstr "" - -#: templates/contest/contest-tabs.html:6 templates/stats/base.html:9 -#: templates/submission/list.html:339 -msgid "Statistics" -msgstr "Stastici" - -#: templates/contest/contest-tabs.html:11 -#, fuzzy -#| msgid "Rank" -msgid "Rankings" -msgstr "Rang" - -#: templates/contest/contest-tabs.html:16 -msgid "Hidden Rankings" -msgstr "" - -#: templates/contest/contest-tabs.html:21 -msgid "MOSS" -msgstr "" - -#: templates/contest/contest-tabs.html:26 -msgid "Clone" -msgstr "" - -#: templates/contest/contest-tabs.html:38 -#: templates/contest/contest-tabs.html:58 +#: templates/contest/contest-tabs.html:37 msgid "Leave contest" msgstr "Părăsiți concursul" -#: templates/contest/contest-tabs.html:45 templates/contest/list.html:388 +#: templates/contest/contest-tabs.html:44 templates/contest/list.html:293 msgid "Virtual join" msgstr "" -#: templates/contest/contest-tabs.html:56 -msgid "Stop spectating" -msgstr "" - -#: templates/contest/contest-tabs.html:65 +#: templates/contest/contest-tabs.html:64 msgid "Spectate contest" msgstr "" -#: templates/contest/contest-tabs.html:72 +#: templates/contest/contest-tabs.html:70 +#: templates/contest/contest-tabs.html:76 msgid "Join contest" msgstr "Intră în concurs" -#: templates/contest/contest-tabs.html:81 +#: templates/contest/contest-tabs.html:85 msgid "Login to participate" msgstr "" -#: templates/contest/contest.html:37 -msgid "Participating virtually." -msgstr "" - -#: templates/contest/contest.html:43 -msgid "Contest is over." -msgstr "Concursul s-a terminat." - #: templates/contest/contest.html:59 templates/contest/contest.html:63 msgid "F j, Y, G:i T" msgstr "F j, Y, G:i T" -#: templates/contest/contest.html:59 -#, fuzzy, python-format -#| msgid "%(length)s long starting on %(start_time)s" -msgid "" -"%(time_limit)s window between %(start_time)s and " -"%(end_time)s" -msgstr "%(length)s lung începând la %(start_time)s" - -#: templates/contest/contest.html:63 -#, python-format -msgid "%(length)s long starting on %(start_time)s" -msgstr "%(length)s lung începând la %(start_time)s" - #: templates/contest/contest.html:85 msgid "AC Rate" msgstr "" -#: templates/contest/contest.html:86 templates/contest/list.html:237 -#: templates/contest/list.html:289 templates/contest/list.html:366 -#: templates/problem/list.html:223 templates/problem/list.html:254 +#: templates/contest/contest.html:86 templates/contest/list.html:153 +#: templates/contest/list.html:195 templates/contest/list.html:271 +#: templates/problem/list.html:212 templates/problem/list.html:238 msgid "Users" msgstr "Utilizatori" -#: templates/contest/contest.html:111 templates/problem/list.html:330 +#: templates/contest/contest.html:111 msgid "Editorial" msgstr "" -#: templates/contest/list.html:83 templates/contest/media-js.html:9 +#: templates/contest/list.html:31 templates/contest/media-js.html:9 msgid "Are you sure you want to join?" msgstr "" -#: templates/contest/list.html:84 +#: templates/contest/list.html:32 msgid "" "Joining a contest for the first time starts your timer, after which it " "becomes unstoppable." msgstr "" -#: templates/contest/list.html:92 templates/contest/list.html:278 -msgid "Show" -msgstr "" - -#: templates/contest/list.html:102 templates/problem/list.html:68 -#, fuzzy -#| msgid "Organizations" -msgid "Organizations..." -msgstr "Organizaţii" - -#: templates/contest/list.html:135 +#: templates/contest/list.html:65 msgid "hidden" msgstr "" -#: templates/contest/list.html:140 +#: templates/contest/list.html:70 msgid "private" msgstr "" -#: templates/contest/list.html:154 +#: templates/contest/list.html:84 msgid "rated" msgstr "" -#: templates/contest/list.html:202 +#: templates/contest/list.html:132 msgid "Spectate" msgstr "" -#: templates/contest/list.html:208 +#: templates/contest/list.html:138 msgid "Join" msgstr "Intră" -#: templates/contest/list.html:220 -#, fuzzy -#| msgid "Search problems..." -msgid "Search contests..." -msgstr "Căutaţi problemele..." - -#: templates/contest/list.html:229 -msgid "Search" -msgstr "" - -#: templates/contest/list.html:232 +#: templates/contest/list.html:148 msgid "Active Contests" msgstr "" -#: templates/contest/list.html:236 templates/contest/list.html:288 -#: templates/contest/list.html:327 templates/contest/list.html:365 +#: templates/contest/list.html:152 templates/contest/list.html:194 +#: templates/contest/list.html:232 templates/contest/list.html:270 msgid "Contest" msgstr "Concurs" -#: templates/contest/list.html:275 +#: templates/contest/list.html:190 msgid "Ongoing Contests" msgstr "Concursuri in desfășurare" -#: templates/contest/list.html:322 +#: templates/contest/list.html:227 msgid "Upcoming Contests" msgstr "Concursuri programate" -#: templates/contest/list.html:350 +#: templates/contest/list.html:255 msgid "There are no scheduled contests at this time." msgstr "Nu există concursuri programate în acest moment." -#: templates/contest/list.html:356 +#: templates/contest/list.html:261 msgid "Past Contests" msgstr "Concursuri terminate" @@ -3592,80 +3269,50 @@ msgstr "" msgid "Only the following organizations may access this contest:" msgstr "Numai următoarele organizații pot accesa acest concurs:" -#: templates/contest/ranking-table.html:9 templates/problem/search-form.html:35 +#: templates/contest/ranking-table.html:7 msgid "Organization" msgstr "Organizație" -#: templates/contest/ranking-table.html:10 templates/user/users-table.html:13 -#, fuzzy -#| msgid "full name" -msgid "Full Name" -msgstr "nume complet" - -#: templates/contest/ranking-table.html:44 +#: templates/contest/ranking-table.html:30 msgid "Un-Disqualify" msgstr "" -#: templates/contest/ranking-table.html:47 +#: templates/contest/ranking-table.html:33 msgid "Disqualify" msgstr "" -#: templates/contest/ranking.html:187 +#: templates/contest/ranking.html:173 msgid "Are you sure you want to disqualify this participation?" msgstr "" -#: templates/contest/ranking.html:192 +#: templates/contest/ranking.html:178 msgid "Are you sure you want to un-disqualify this participation?" msgstr "" -#: templates/contest/ranking.html:463 +#: templates/contest/ranking.html:252 msgid "View user participation" msgstr "" -#: templates/contest/ranking.html:467 +#: templates/contest/ranking.html:256 msgid "Show organizations" msgstr "" -#: templates/contest/ranking.html:471 -#, fuzzy -#| msgid "full name" -msgid "Show full name" -msgstr "nume complet" - -#: templates/contest/ranking.html:474 -msgid "Show friends only" -msgstr "" - -#: templates/contest/ranking.html:477 -msgid "Total score only" -msgstr "" - -#: templates/contest/ranking.html:479 -#, fuzzy -#| msgid "contest participation" -msgid "Show virtual participation" -msgstr "participarea la concurs" - -#: templates/contest/stats.html:51 +#: templates/contest/stats.html:38 msgid "Problem Status Distribution" msgstr "" -#: templates/contest/stats.html:56 +#: templates/contest/stats.html:43 #, fuzzy #| msgid "Problem type" #| msgid_plural "Problem types" msgid "Problem AC Rate" msgstr "Tip de problemă" -#: templates/contest/stats.html:62 -msgid "Problem Point Distribution" -msgstr "" - -#: templates/contest/stats.html:76 templates/stats/language.html:16 +#: templates/contest/stats.html:48 templates/stats/language.html:16 msgid "Submissions by Language" msgstr "Soluții după limbă" -#: templates/contest/stats.html:82 templates/stats/language.html:26 +#: templates/contest/stats.html:54 templates/stats/language.html:26 msgid "Language AC Rate" msgstr "Procent soluții corecte (AC) după limbă" @@ -3674,7 +3321,6 @@ msgid "Source:" msgstr "Sursă:" #: templates/newsletter/common.html:6 -#: templates/newsletter/newsletter_list.html:15 #: templates/newsletter/subscription_unsubscribe_activated.html:3 #: templates/newsletter/subscription_unsubscribe_activated.html:6 #: templates/newsletter/subscription_update_activated.html:3 @@ -3682,29 +3328,6 @@ msgstr "Sursă:" msgid "Newsletter" msgstr "Buletin" -#: templates/newsletter/newsletter_list.html:2 -#: templates/newsletter/newsletter_list.html:3 -#, fuzzy -#| msgid "Newsletter" -msgid "Newsletter list" -msgstr "Buletin" - -#: templates/newsletter/newsletter_list.html:6 -msgid "Subscribe to get the latest emails about upcoming contests and events." -msgstr "" - -#: templates/newsletter/newsletter_list.html:16 -#, fuzzy -#| msgid "Unsubscribe" -msgid "Subscribe" -msgstr "Dezabonare" - -#: templates/newsletter/newsletter_list.html:30 -#, fuzzy -#| msgid "Update subscription" -msgid "Update subscriptions" -msgstr "Actualizează abonamentul" - #: templates/newsletter/subscription_unsubscribe_activated.html:3 #: templates/newsletter/subscription_unsubscribe_activated.html:6 #: templates/newsletter/subscription_update_activated.html:3 @@ -3775,115 +3398,64 @@ msgstr "" "fost trimis către dumneavoastră. Urmaţi link-ul de activare din acel email " "pentru a actualiza abonamentul." -#: templates/notification/list.html:7 -#, fuzzy -#| msgid "You have not shared any information." -msgid "You have no notifications" -msgstr "Nu aţi împărtăşit nicio informaţie." - -#: templates/notification/list.html:13 -#, fuzzy -#| msgid "activate" -msgid "Activity" -msgstr "activează" - #: templates/organization/edit.html:46 #: templates/organization/requests/pending.html:34 #: templates/ticket/edit-notes.html:4 msgid "Update" msgstr "Actualizare" -#: templates/organization/home.html:41 +#: templates/organization/home.html:7 msgid "Are you sure you want to leave this organization?" msgstr "" -#: templates/organization/home.html:43 +#: templates/organization/home.html:9 msgid "You will have to rejoin to show up on the organization leaderboard." msgstr "" -#: templates/organization/home.html:45 +#: templates/organization/home.html:11 msgid "You will have to request membership in order to join again." msgstr "" -#: templates/organization/home.html:88 -msgid "Join organization" -msgstr "Alăturaţi-vă organizaţiei" - -#: templates/organization/home.html:92 -msgid "Request membership" -msgstr "Cerere de membru" - -#: templates/organization/home.html:122 -#, fuzzy -#| msgid "Organizations" -msgid "Organization news" -msgstr "Organizaţii" - -#: templates/organization/home.html:128 -#, fuzzy -#| msgid "There are no scheduled contests at this time." -msgid "There is no news at this time." -msgstr "Nu există concursuri programate în acest moment." - -#: templates/organization/home.html:137 -#, fuzzy -#| msgid "Contest" -msgid "Controls" -msgstr "Concurs" - -#: templates/organization/home.html:142 -msgid "Edit organization" -msgstr "Editează organizaţia" - -#: templates/organization/home.html:148 -msgid "View requests" -msgstr "Vezi solicitări" - -#: templates/organization/home.html:161 -msgid "Admin organization" -msgstr "" - -#: templates/organization/home.html:167 -msgid "View members" -msgstr "Vezi membrii" - -#: templates/organization/home.html:174 +#: templates/organization/home.html:24 msgid "Leave organization" msgstr "Părăsiţi organizaţia" -#: templates/organization/home.html:183 -#, fuzzy -#| msgid "Rate all ratable contests" -msgid "New private contests" -msgstr "Dă o notă la toate concursurile adecvate" +#: templates/organization/home.html:29 +msgid "Join organization" +msgstr "Alăturaţi-vă organizaţiei" -#: templates/organization/home.html:193 templates/organization/home.html:208 -#, fuzzy -#| msgid "View as PDF" -msgid "View all" -msgstr "Versiune PDF" +#: templates/organization/home.html:33 +msgid "Request membership" +msgstr "Cerere de membru" -#: templates/organization/home.html:199 -#, fuzzy -#| msgid "New problems" -msgid "New private problems" -msgstr "Probleme noi" +#: templates/organization/home.html:39 +msgid "Edit organization" +msgstr "Editează organizaţia" -#: templates/organization/list.html:40 -#, fuzzy -#| msgid "organizations" -msgid "Show my organizations only" -msgstr "organizații" +#: templates/organization/home.html:43 +msgid "View requests" +msgstr "Vezi solicitări" -#: templates/organization/list.html:47 templates/status/language-list.html:34 -#: templates/user/import/table_csv.html:6 +#: templates/organization/home.html:50 +msgid "Admin organization" +msgstr "" + +#: templates/organization/home.html:55 +msgid "View members" +msgstr "Vezi membrii" + +#: templates/organization/list.html:23 templates/status/language-list.html:34 msgid "Name" msgstr "Nume" -#: templates/organization/list.html:48 +#: templates/organization/list.html:24 msgid "Members" msgstr "Membrii" +#: templates/organization/new.html:10 templates/ticket/new.html:38 +msgid "Create" +msgstr "Crează" + #: templates/organization/requests/detail.html:13 msgid "User:" msgstr "Nume de utilizator:" @@ -3916,7 +3488,7 @@ msgid "There are no requests to approve." msgstr "Nu aveți cereri de aprobare." #: templates/organization/requests/pending.html:17 -#: templates/problem/data.html:432 +#: templates/problem/data.html:452 msgid "Delete?" msgstr "Ştergeţi?" @@ -3952,37 +3524,37 @@ msgstr "" msgid "Enter a new code for the cloned problem:" msgstr "" -#: templates/problem/data.html:119 +#: templates/problem/data.html:108 #, fuzzy #| msgid "Information" msgid "Instruction" msgstr "Informație" -#: templates/problem/data.html:390 +#: templates/problem/data.html:410 msgid "View YAML" msgstr "" -#: templates/problem/data.html:421 templates/problem/data.html:472 +#: templates/problem/data.html:441 templates/problem/data.html:491 msgid "Apply!" msgstr "" -#: templates/problem/data.html:426 +#: templates/problem/data.html:446 msgid "Type" msgstr "" -#: templates/problem/data.html:427 +#: templates/problem/data.html:447 msgid "Input file" msgstr "" -#: templates/problem/data.html:428 +#: templates/problem/data.html:448 msgid "Output file" msgstr "" -#: templates/problem/data.html:430 +#: templates/problem/data.html:450 msgid "Pretest?" msgstr "" -#: templates/problem/data.html:473 +#: templates/problem/data.html:492 msgid "Add new case" msgstr "" @@ -3994,34 +3566,28 @@ msgid "" "problem yourself is a bannable offence." msgstr "" -#: templates/problem/list.html:66 +#: templates/problem/list.html:62 msgid "Filter by type..." msgstr "" -#: templates/problem/list.html:193 +#: templates/problem/list.html:185 msgid "Hot problems" msgstr "" -#: templates/problem/list.html:218 templates/problem/list.html:240 -#: templates/problem/search-form.html:45 templates/user/user-problems.html:57 +#: templates/problem/list.html:207 templates/problem/list.html:224 +#: templates/problem/search-form.html:30 templates/user/user-problems.html:57 msgid "Category" msgstr "Categorie" -#: templates/problem/list.html:220 templates/problem/list.html:244 +#: templates/problem/list.html:209 templates/problem/list.html:228 msgid "Types" msgstr "Tipuri" -#: templates/problem/list.html:251 +#: templates/problem/list.html:235 #, python-format msgid "AC %%" msgstr "" -#: templates/problem/list.html:342 -#, fuzzy -#| msgid "Best solutions for %s" -msgid "Add clarifications" -msgstr "Cele mai bune soluţii pentru %s" - #: templates/problem/manage_submission.html:55 msgid "Leave empty to not filter by language" msgstr "" @@ -4030,210 +3596,152 @@ msgstr "" msgid "Leave empty to not filter by result" msgstr "" -#: templates/problem/manage_submission.html:80 +#: templates/problem/manage_submission.html:79 msgid "Need valid values for both start and end IDs." msgstr "" -#: templates/problem/manage_submission.html:83 +#: templates/problem/manage_submission.html:82 msgid "End ID must be after start ID." msgstr "" +#: templates/problem/manage_submission.html:90 +#, python-brace-format +msgid "" +"You are about to rejudge {count} submissions. Are you sure you want to do " +"this?" +msgstr "" + #: templates/problem/manage_submission.html:96 -#, python-brace-format msgid "" -"You are about to {action} {count} submissions. Are you sure you want to do " -"this?" +"You are about to rejudge a few submissions. Are you sure you want to do this?" msgstr "" -#: templates/problem/manage_submission.html:103 -#, python-brace-format -msgid "" -"You are about to {action} a few submissions. Are you sure you want to do " -"this?" +#: templates/problem/manage_submission.html:115 +msgid "Rejudge Submissions" msgstr "" -#: templates/problem/manage_submission.html:127 -#: templates/submission/list.html:309 -msgid "Filter submissions" -msgstr "" - -#: templates/problem/manage_submission.html:132 +#: templates/problem/manage_submission.html:120 msgid "Filter by ID:" msgstr "" -#: templates/problem/manage_submission.html:135 +#: templates/problem/manage_submission.html:123 msgid "Starting ID:" msgstr "" -#: templates/problem/manage_submission.html:139 +#: templates/problem/manage_submission.html:127 msgid "Ending ID:" msgstr "" -#: templates/problem/manage_submission.html:143 +#: templates/problem/manage_submission.html:131 msgid "This range includes both endpoints." msgstr "" -#: templates/problem/manage_submission.html:146 +#: templates/problem/manage_submission.html:134 msgid "Filter by language:" msgstr "" -#: templates/problem/manage_submission.html:154 +#: templates/problem/manage_submission.html:142 msgid "Filter by result:" msgstr "" -#: templates/problem/manage_submission.html:164 -msgid "Action" -msgstr "" - -#: templates/problem/manage_submission.html:166 +#: templates/problem/manage_submission.html:150 msgid "Rejudge selected submissions" msgstr "" -#: templates/problem/manage_submission.html:171 -#, fuzzy -#| msgid "All submissions" -msgid "Download selected submissions" -msgstr "Toate soluţile" - -#: templates/problem/manage_submission.html:177 -#, python-format -msgid "Are you sure you want to rescore %(count)d submissions?" +#: templates/problem/manage_submission.html:157 +msgid "Rescore Everything" msgstr "" -#: templates/problem/manage_submission.html:178 +#: templates/problem/manage_submission.html:163 msgid "Rescore all submissions" msgstr "" -#: templates/problem/problem.html:132 +#: templates/problem/problem.html:91 msgid "View as PDF" msgstr "Versiune PDF" -#: templates/problem/problem.html:141 templates/problem/problem.html:151 -#: templates/problem/problem.html:156 +#: templates/problem/problem.html:101 templates/problem/problem.html:111 +#: templates/problem/problem.html:116 msgid "Submit solution" msgstr "Trimite soluţie" -#: templates/problem/problem.html:144 -#, fuzzy, python-format -#| msgid "contest submission" -msgid "%(counter)s submission left" -msgid_plural "%(counter)s submissions left" -msgstr[0] "submisie de concurs" -msgstr[1] "submisie de concurs" -msgstr[2] "submisie de concurs" - -#: templates/problem/problem.html:152 +#: templates/problem/problem.html:112 msgid "0 submissions left" msgstr "" -#: templates/problem/problem.html:164 +#: templates/problem/problem.html:124 msgid "My submissions" msgstr "Soluţiile mele" -#: templates/problem/problem.html:168 +#: templates/problem/problem.html:128 msgid "Best submissions" msgstr "Cele mai bune soluţii" -#: templates/problem/problem.html:172 +#: templates/problem/problem.html:132 msgid "Read editorial" msgstr "" -#: templates/problem/problem.html:177 +#: templates/problem/problem.html:137 msgid "Manage tickets" msgstr "" -#: templates/problem/problem.html:181 +#: templates/problem/problem.html:141 msgid "Edit problem" msgstr "Schimbă problema" -#: templates/problem/problem.html:183 +#: templates/problem/problem.html:143 msgid "Edit test data" msgstr "" -#: templates/problem/problem.html:188 +#: templates/problem/problem.html:148 msgid "My tickets" msgstr "" -#: templates/problem/problem.html:196 +#: templates/problem/problem.html:156 msgid "Manage submissions" msgstr "" -#: templates/problem/problem.html:202 +#: templates/problem/problem.html:162 msgid "Clone problem" msgstr "Duplică problemă" -#: templates/problem/problem.html:209 +#: templates/problem/problem.html:169 msgid "Points:" msgstr "Puncte:" -#: templates/problem/problem.html:212 templates/problem/problem.html:214 +#: templates/problem/problem.html:172 templates/problem/problem.html:174 msgid "(partial)" msgstr "(parţial)" -#: templates/problem/problem.html:219 +#: templates/problem/problem.html:179 msgid "Time limit:" msgstr "Limita de timp:" -#: templates/problem/problem.html:231 +#: templates/problem/problem.html:191 msgid "Memory limit:" msgstr "Limita de memorie:" -#: templates/problem/problem.html:250 -msgid "Author:" -msgid_plural "Authors:" -msgstr[0] "Autor:" -msgstr[1] "Autori:" -msgstr[2] "Autori:" - -#: templates/problem/problem.html:265 -#, fuzzy -#| msgid "problem type" -msgid "Problem type" -msgid_plural "Problem types" -msgstr[0] "tipul problemei" -msgstr[1] "tipul problemei" -msgstr[2] "tipul problemei" - -#: templates/problem/problem.html:278 +#: templates/problem/problem.html:238 msgid "Allowed languages" msgstr "Limbajele acceptate" -#: templates/problem/problem.html:286 -#, python-format -msgid "No %(lang)s judge online" -msgstr "Nici un judge pentru %(lang)s e online" - -#: templates/problem/problem.html:297 -#, fuzzy -#| msgid "Judges" -msgid "Judge:" -msgid_plural "Judges:" -msgstr[0] "Judges" -msgstr[1] "Judges" -msgstr[2] "Judges" - -#: templates/problem/problem.html:314 +#: templates/problem/problem.html:274 msgid "none available" msgstr "" -#: templates/problem/problem.html:326 -#, python-format -msgid "This problem has %(length)s clarification(s)" -msgstr "" - -#: templates/problem/problem.html:350 +#: templates/problem/problem.html:299 msgid "Request clarification" msgstr "" -#: templates/problem/problem.html:352 +#: templates/problem/problem.html:301 msgid "Report an issue" msgstr "" -#: templates/problem/raw.html:64 +#: templates/problem/raw.html:62 msgid "Time Limit:" msgstr "" -#: templates/problem/raw.html:73 +#: templates/problem/raw.html:71 msgid "Memory Limit:" msgstr "" @@ -4257,74 +3765,39 @@ msgstr "Ascunde probleme rezolvate" msgid "Show problem types" msgstr "" -#: templates/problem/search-form.html:32 -msgid "Show editorial" -msgstr "" - -#: templates/problem/search-form.html:48 templates/problem/search-form.html:50 -#: templates/submission/submission-list-tabs.html:4 +#: templates/problem/search-form.html:33 templates/problem/search-form.html:35 msgid "All" msgstr "Toate" -#: templates/problem/search-form.html:62 +#: templates/problem/search-form.html:46 msgid "Problem types" msgstr "" -#: templates/problem/search-form.html:73 +#: templates/problem/search-form.html:57 msgid "Point range" msgstr "" -#: templates/problem/search-form.html:79 templates/submission/list.html:331 +#: templates/problem/search-form.html:63 templates/submission/list.html:331 #: templates/ticket/list.html:248 msgid "Go" msgstr "Caută" -#: templates/problem/search-form.html:80 +#: templates/problem/search-form.html:64 msgid "Random" msgstr "Aleatoriu" -#: templates/problem/submit.html:117 -msgid "Your source code must contain at most 65536 characters." -msgstr "" - -#: templates/problem/submit.html:204 -#, python-format -msgid "" -"Warning! Your default language, %(default_language)s, is " -"unavailable for this problem and has been deselected." -msgstr "" - -#: templates/problem/submit.html:215 -#, python-format -msgid "" -"\n" -" You have %(left)s submission left\n" -" " -msgid_plural "" -"\n" -" You have %(left)s submissions left\n" -" " -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" - -#: templates/problem/submit.html:224 +#: templates/problem/submit.html:212 msgid "You have 0 submissions left" msgstr "" -#: templates/problem/submit.html:258 +#: templates/problem/submit.html:250 msgid "No judge is available for this problem." msgstr "Nici un judge nu este disponibil pentru această problemă." -#: templates/problem/submit.html:262 +#: templates/problem/submit.html:252 msgid "Submit!" msgstr "Trimiteți!" -#: templates/registration/activate.html:3 -#, python-format -msgid "%(key)s is an invalid activation key." -msgstr "%(key)s este o cheie de activare invalidă." - #: templates/registration/activation_complete.html:3 msgid "Your account has been successfully activated." msgstr "Contul a fost activat cu succes." @@ -4382,15 +3855,6 @@ msgid "" "you registered with, and check your spam folder." msgstr "" -#: templates/registration/password_reset_email.txt:1 -#, python-format -msgid "" -"You're receiving this email because you requested a password reset for your " -"user account at %(site_name)s." -msgstr "" -"Ați primit acest email pentru că aţi solicitat resetarea parolei pentru " -"contul dumneavoastră de utilizator pe %(site_name)s." - #: templates/registration/password_reset_email.txt:3 msgid "Please go to the following page and choose a new password:" msgstr "Vă rugăm să accesați următoarea pagină şi să alegeţi o parolă nouă:" @@ -4403,16 +3867,6 @@ msgstr "Numele de utilizator, în cazul in care aţi uitat:" msgid "Thanks for using our site!" msgstr "Vă mulţumim pentru utilizarea site-ului nostru!" -#: templates/registration/password_reset_email.txt:11 -#, python-format -msgid "The %(site_name)s team" -msgstr "Echipa %(site_name)s" - -#: templates/registration/password_reset_subject.txt:1 -#, python-format -msgid "Password reset on %(site_name)s" -msgstr "Parola resetată pe %(site_name)s" - #: templates/registration/profile_creation.html:36 #: templates/registration/username_select.html:7 msgid "Continue >" @@ -4451,20 +3905,19 @@ msgstr "" msgid "Affiliated organizations" msgstr "" -#: templates/registration/registration_form.html:195 -#: templates/user/edit-profile.html:128 +#: templates/registration/registration_form.html:192 msgid "Notify me about upcoming contests" msgstr "" -#: templates/registration/registration_form.html:209 +#: templates/registration/registration_form.html:206 msgid "By registering, you agree to our" msgstr "" -#: templates/registration/registration_form.html:210 +#: templates/registration/registration_form.html:207 msgid "Terms & Conditions" msgstr "" -#: templates/registration/registration_form.html:213 +#: templates/registration/registration_form.html:210 msgid "Register!" msgstr "Înscrie-te!" @@ -4474,11 +3927,6 @@ msgstr "Înscrie-te!" msgid "Enter the 6-digit code generated by your app:" msgstr "" -#: templates/registration/totp_auth.html:41 -#, python-format -msgid "If you lost your authentication device, please contact us at %(email)s." -msgstr "" - #: templates/registration/totp_disable.html:38 msgid "" "To protect your account, you must first authenticate before you can disable " @@ -4497,6 +3945,10 @@ msgstr "" msgid "Or enter this code manually:" msgstr "" +#: templates/stats/base.html:9 templates/submission/list.html:339 +msgid "Statistics" +msgstr "Stastici" + #: templates/stats/language.html:11 msgid "Submission Statistics" msgstr "" @@ -4522,7 +3974,6 @@ msgid "Ping" msgstr "Ping" #: templates/status/judge-status-table.html:8 -#: templates/user/import/index.html:104 msgid "Load" msgstr "Încărcare" @@ -4538,7 +3989,6 @@ msgid "There are no judges available at this time." msgstr "" #: templates/status/language-list.html:33 templates/ticket/list.html:261 -#: templates/user/import/table_csv.html:3 msgid "ID" msgstr "ID" @@ -4546,22 +3996,6 @@ msgstr "ID" msgid "Runtime Info" msgstr "Runtime Info" -#: templates/status/status-tabs.html:4 -msgid "Judges" -msgstr "Judges" - -#: templates/status/status-tabs.html:6 -msgid "Version Matrix" -msgstr "" - -#: templates/submission/internal-error-message.html:3 -#, python-format -msgid "" -"An internal error occurred while grading, and the %(SITE_NAME)s " -"administrators have been notified.
In the meantime, try resubmitting in " -"a few seconds." -msgstr "" - #: templates/submission/internal-error-message.html:8 msgid "An internal error occurred while grading." msgstr "O eroare internă a apărut în timpul notării." @@ -4578,6 +4012,10 @@ msgstr "" msgid "Filter by language..." msgstr "" +#: templates/submission/list.html:309 +msgid "Filter submissions" +msgstr "" + #: templates/submission/list.html:345 msgid "Total:" msgstr "" @@ -4634,74 +4072,73 @@ msgstr "" msgid "Execution Results" msgstr "Rezultate de executare" -#: templates/submission/status-testcases.html:34 +#: templates/submission/status-testcases.html:31 +msgid "Batch " +msgstr "Lot " + +#: templates/submission/status-testcases.html:43 msgid "Overall: " msgstr "" -#: templates/submission/status-testcases.html:48 +#: templates/submission/status-testcases.html:57 #, fuzzy #| msgid "Points:" msgid "Point: " msgstr "Puncte:" -#: templates/submission/status-testcases.html:53 +#: templates/submission/status-testcases.html:62 #, fuzzy #| msgid "Time:" msgid "Time: " msgstr "Ora:" -#: templates/submission/status-testcases.html:62 +#: templates/submission/status-testcases.html:71 #, fuzzy #| msgid "Memory limit:" msgid "Memory: " msgstr "Limita de memorie:" -#: templates/submission/status-testcases.html:73 -msgid "Batch " -msgstr "Lot " - #: templates/submission/status-testcases.html:84 -#: templates/submission/status-testcases.html:113 +msgid "Case" +msgstr "Caz" + +#: templates/submission/status-testcases.html:86 +msgid "Pretest" +msgstr "Pretest" + +#: templates/submission/status-testcases.html:88 +msgid "Test case" +msgstr "Caz de test" + +#: templates/submission/status-testcases.html:99 #, fuzzy #| msgid "Points" msgid "Point" msgstr "Puncte" -#: templates/submission/status-testcases.html:99 -msgid "Case" -msgstr "Caz" - -#: templates/submission/status-testcases.html:101 -msgid "Pretest" -msgstr "Pretest" - -#: templates/submission/status-testcases.html:103 -msgid "Test case" -msgstr "Caz de test" - -#: templates/submission/status-testcases.html:141 +#: templates/submission/status-testcases.html:121 msgid "Input:" msgstr "" -#: templates/submission/status-testcases.html:145 +#: templates/submission/status-testcases.html:125 msgid "Output:" msgstr "" -#: templates/submission/status-testcases.html:149 +#: templates/submission/status-testcases.html:129 #, fuzzy #| msgid "Wrong Answer" msgid "Answer:" msgstr "Wrong Answer" -#: templates/submission/status-testcases.html:154 +#: templates/submission/status-testcases.html:134 msgid "Judge feedback:" msgstr "" -#: templates/submission/status-testcases.html:175 +#: templates/submission/status-testcases.html:157 msgid "Passing pretests does not guarantee a full score on system tests." msgstr "" -#: templates/submission/status-testcases.html:178 +#: templates/submission/status-testcases.html:160 msgid "Submission aborted!" msgstr "Soluția a fost anulată!" @@ -4713,24 +4150,11 @@ msgstr "Vezi sursa" msgid "Abort" msgstr "Anuleaza" -#: templates/submission/submission-list-tabs.html:6 -msgid "Mine" -msgstr "" - -#: templates/submission/submission-list-tabs.html:9 -msgid "Best" -msgstr "" - -#: templates/submission/submission-list-tabs.html:12 -#, python-format -msgid "%(user)s's" -msgstr "" - -#: templates/ticket/list.html:135 templates/ticket/ticket.html:273 +#: templates/ticket/list.html:135 templates/ticket/ticket.html:257 msgid "Reopened: " msgstr "" -#: templates/ticket/list.html:138 templates/ticket/ticket.html:274 +#: templates/ticket/list.html:138 templates/ticket/ticket.html:258 msgid "Closed: " msgstr "" @@ -4754,7 +4178,7 @@ msgstr "" msgid "Title" msgstr "" -#: templates/ticket/list.html:264 templates/ticket/ticket.html:369 +#: templates/ticket/list.html:264 templates/ticket/ticket.html:328 msgid "Assignees" msgstr "" @@ -4769,37 +4193,33 @@ msgid "" "a problem, ask in the comments instead." msgstr "" -#: templates/ticket/ticket.html:355 -msgid "Post" -msgstr "" - -#: templates/ticket/ticket.html:363 +#: templates/ticket/ticket.html:322 msgid "Associated object" msgstr "" -#: templates/ticket/ticket.html:374 +#: templates/ticket/ticket.html:333 msgid "No one is assigned." msgstr "" -#: templates/ticket/ticket.html:380 +#: templates/ticket/ticket.html:339 msgid "Close ticket" msgstr "" -#: templates/ticket/ticket.html:382 +#: templates/ticket/ticket.html:341 msgid "Reopen ticket" msgstr "" -#: templates/ticket/ticket.html:386 +#: templates/ticket/ticket.html:345 msgid "Assignee notes" msgstr "" -#: templates/ticket/ticket.html:393 templates/widgets/select_all.html:4 +#: templates/ticket/ticket.html:352 templates/widgets/select_all.html:4 msgid "Nothing here." msgstr "Nimic aici." -#: templates/user/base-users-table.html:3 -msgid "Rank" -msgstr "Rang" +#: templates/ticket/ticket.html:385 +msgid "Post" +msgstr "" #: templates/user/base-users.html:14 templates/user/base-users.html:69 msgid "Search by handle..." @@ -4845,200 +4265,50 @@ msgstr "Script de utilizator" msgid "Update profile" msgstr "Actualizați profilul" -#: templates/user/import/index.html:31 -msgid "Upload CSV only" -msgstr "" - -#: templates/user/import/index.html:100 -#, fuzzy -#| msgid "user profile" -msgid "User File" -msgstr "profil utilizator" - -#: templates/user/import/index.html:102 -msgid "Sample" -msgstr "" - -#: templates/user/import/index.html:105 templates/user/user-list-tabs.html:8 -msgid "Import" -msgstr "" - -#: templates/user/import/table_csv.html:7 -msgid "School" -msgstr "" - -#: templates/user/pp-row.html:22 -#, python-format -msgid "" -"\n" -" weighted %(weight)s%%\n" -" " -msgstr "" - -#: templates/user/pp-row.html:27 -#, python-format -msgid "%(pp).1fpp" -msgstr "" - -#: templates/user/pp-row.html:29 -#, python-format -msgid "%(pp).0fpp" -msgstr "" - -#: templates/user/user-about.html:23 -#, fuzzy, python-format -#| msgid "contest problems" -msgid "%(counter)s problem solved" -msgid_plural "%(counter)s problems solved" -msgstr[0] "problemele din concurs" -msgstr[1] "problemele din concurs" -msgstr[2] "problemele din concurs" - -#: templates/user/user-about.html:35 -#, fuzzy -#| msgid "Total points:" -msgid "Total points" -msgstr "Numărul total de puncte:" - -#: templates/user/user-about.html:45 -#, fuzzy -#| msgid "Rank by rating:" -msgid "Rank by rating" -msgstr "Clasament după rating:" - -#: templates/user/user-about.html:52 -#, fuzzy -#| msgid "Rank by points:" -msgid "Rank by points" -msgstr "Clasament după puncte:" - -#: templates/user/user-about.html:64 +#: templates/user/user-about.html:14 msgid "From" msgstr "De la" -#: templates/user/user-about.html:75 +#: templates/user/user-about.html:25 msgid "Admin Notes" msgstr "" -#: templates/user/user-about.html:90 +#: templates/user/user-about.html:40 msgid "You have not shared any information." msgstr "Nu aţi împărtăşit nicio informaţie." -#: templates/user/user-about.html:92 +#: templates/user/user-about.html:42 msgid "This user has not shared any information." msgstr "Acest utilizator nu a împărtăşit nicio informaţie." -#: templates/user/user-about.html:101 -msgid "Awards" -msgstr "" +#: templates/user/user-base.html:50 +msgid "Rank by points:" +msgstr "Clasament după puncte:" -#: templates/user/user-about.html:112 -#, fuzzy, python-format -#| msgctxt "contest problem" -#| msgid "%(problem)s in %(contest)s" -msgid "%(label)s (%(date)s)" -msgstr "%(problem)s în %(contest)s" +#: templates/user/user-base.html:53 +msgid "Total points:" +msgstr "Numărul total de puncte:" -#: templates/user/user-about.html:130 -#, fuzzy -#| msgid "Monday" -msgid "Mon" -msgstr "Luni" +#: templates/user/user-base.html:68 +msgid "Rank by rating:" +msgstr "Clasament după rating:" -#: templates/user/user-about.html:135 -#, fuzzy -#| msgid "Tuesday" -msgid "Tues" -msgstr "Marți" +#: templates/user/user-base.html:70 +msgid "Rating:" +msgstr "Rating:" -#: templates/user/user-about.html:140 -msgid "Wed" -msgstr "" - -#: templates/user/user-about.html:145 -#, fuzzy -#| msgid "Thursday" -msgid "Thurs" -msgstr "Joi" - -#: templates/user/user-about.html:150 -#, fuzzy -#| msgid "Friday" -msgid "Fri" -msgstr "Vineri" - -#: templates/user/user-about.html:155 -#, fuzzy -#| msgid "State" -msgid "Sat" -msgstr "Stare" - -#: templates/user/user-about.html:160 -#, fuzzy -#| msgid "Sunday" -msgid "Sun" -msgstr "Duminică" - -#: templates/user/user-about.html:169 -msgid "Less" -msgstr "" - -#: templates/user/user-about.html:175 -msgid "More" -msgstr "" - -#: templates/user/user-about.html:184 -#, fuzzy -#| msgid "History" -msgid "Rating History" -msgstr "Istoric" - -#: templates/user/user-about.html:255 -msgid "past year" -msgstr "" - -#: templates/user/user-about.html:272 -#, fuzzy -#| msgid "All submissions" -msgid "total submission(s)" -msgstr "Toate soluţile" - -#: templates/user/user-about.html:276 -#, fuzzy -#| msgid "submission test case" -msgid "submissions in the last year" -msgstr "testul submisiei" - -#: templates/user/user-base.html:101 -msgid "Unfollow" -msgstr "" - -#: templates/user/user-base.html:104 -msgid "Follow" -msgstr "" - -#: templates/user/user-base.html:120 -#, fuzzy -#| msgid "Contests" -msgid "Contests written" -msgstr "Concursuri" - -#: templates/user/user-base.html:124 +#: templates/user/user-base.html:71 msgid "Volatility:" msgstr "Volatilitate:" -#: templates/user/user-base.html:128 +#: templates/user/user-base.html:72 msgid "Min. rating:" msgstr "" -#: templates/user/user-base.html:132 +#: templates/user/user-base.html:73 msgid "Max rating:" msgstr "" -#: templates/user/user-list-tabs.html:5 -msgid "Friends" -msgstr "" - #: templates/user/user-problems.html:35 msgid "Points Breakdown" msgstr "" @@ -5059,63 +4329,56 @@ msgstr "Probleme create" msgid "Hide problems I've solved" msgstr "Ascunde probleme care am rezolvat" -#: templates/user/user-problems.html:93 -#, python-format -msgid "%(points).1f points" -msgstr "" - #: templates/user/user-problems.html:99 msgid "Score" msgstr "" -#: templates/user/user-problems.html:110 -#, python-format -msgid "%(points)s / %(total)s" -msgstr "" - -#: templates/user/user-tabs.html:7 -msgid "Impersonate" -msgstr "" - -#: templates/user/user-tabs.html:13 -#, fuzzy -#| msgid "Admin" -msgid "Admin User" -msgstr "Administrare" - -#: templates/user/user-tabs.html:16 -#, fuzzy -#| msgid "Edit profile" -msgid "Admin Profile" -msgstr "Editează-ți profilul" - #: templates/widgets/select_all.html:8 msgid "Check all" msgstr "Selectează tot" -#, fuzzy -#~| msgid "contest submission" -#~ msgid "%(cnt)d submission on %(date)s" -#~ msgid_plural "%(cnt)d submissions on %(date)s" -#~ msgstr[0] "submisie de concurs" -#~ msgstr[1] "submisie de concurs" -#~ msgstr[2] "submisie de concurs" +#~ msgid "Hello, %(username)s." +#~ msgstr "Bună ziua, %(username)s." -#~ msgid "Rating:" -#~ msgstr "Rating:" +#~ msgid "Contest is over." +#~ msgstr "Concursul s-a terminat." -#, fuzzy -#~| msgid "Admin" -#~ msgid "Admins" -#~ msgstr "Administrare" +#~ msgid "%(length)s long starting on %(start_time)s" +#~ msgstr "%(length)s lung începând la %(start_time)s" -#, fuzzy -#~| msgid "Rescore the selected submissions" -#~ msgid "This will rescore %(count)d submissions." -#~ msgstr "Repunctează submisiile selectate" +#~ msgid "Author:" +#~ msgid_plural "Authors:" +#~ msgstr[0] "Autor:" +#~ msgstr[1] "Autori:" +#~ msgstr[2] "Autori:" + +#~ msgid "No %(lang)s judge online" +#~ msgstr "Nici un judge pentru %(lang)s e online" + +#~ msgid "%(key)s is an invalid activation key." +#~ msgstr "%(key)s este o cheie de activare invalidă." + +#~ msgid "" +#~ "You're receiving this email because you requested a password reset for " +#~ "your user account at %(site_name)s." +#~ msgstr "" +#~ "Ați primit acest email pentru că aţi solicitat resetarea parolei pentru " +#~ "contul dumneavoastră de utilizator pe %(site_name)s." + +#~ msgid "The %(site_name)s team" +#~ msgstr "Echipa %(site_name)s" + +#~ msgid "Password reset on %(site_name)s" +#~ msgstr "Parola resetată pe %(site_name)s" + +#~ msgid "Judges" +#~ msgstr "Judges" #~ msgid "Your output (clipped)" #~ msgstr "Output-ul tau (micșorat)" #~ msgid "Final score:" #~ msgstr "Scor final:" + +#~ msgid "Rank" +#~ msgstr "Rang" diff --git a/locale/ro/LC_MESSAGES/djangojs.po b/locale/ro/LC_MESSAGES/djangojs.po index 19ea47d..18cb4f6 100644 --- a/locale/ro/LC_MESSAGES/djangojs.po +++ b/locale/ro/LC_MESSAGES/djangojs.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: dmoj\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-07-20 23:30+0700\n" +"POT-Creation-Date: 2019-10-01 23:12+0000\n" "PO-Revision-Date: 2019-11-11 22:05\n" "Last-Translator: Icyene\n" "Language-Team: Romanian\n" @@ -10,8 +10,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : (n==0 || (n%100>0 && n" -"%100<20)) ? 1 : 2);\n" +"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : (n==0 || (n%100>0 && n%100<20)) ? 1 : 2);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: dmoj\n" "X-Crowdin-Language: ro\n" @@ -29,3 +28,4 @@ msgstr[2] "%d zile %h:%m:%s" msgctxt "time format without day" msgid "%h:%m:%s" msgstr "%h:%m:%s" + diff --git a/locale/ru/LC_MESSAGES/django.po b/locale/ru/LC_MESSAGES/django.po index 45d6e25..9ba34ee 100644 --- a/locale/ru/LC_MESSAGES/django.po +++ b/locale/ru/LC_MESSAGES/django.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: dmoj\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-10-25 05:59+0700\n" +"POT-Creation-Date: 2020-04-10 01:26-0500\n" "PO-Revision-Date: 2019-11-11 22:05\n" "Last-Translator: Icyene\n" "Language-Team: Russian\n" @@ -18,93 +18,93 @@ msgstr "" "X-Crowdin-Language: ru\n" "X-Crowdin-File: django.po\n" -#: chat_box/models.py:16 judge/admin/interface.py:110 -#: judge/models/contest.py:403 judge/models/contest.py:528 -#: judge/models/profile.py:211 +#: chat_box/models.py:15 judge/admin/interface.py:107 +#: judge/models/contest.py:257 judge/models/contest.py:381 +#: judge/models/profile.py:191 msgid "user" msgstr "пользователь" -#: chat_box/models.py:17 judge/models/comment.py:43 judge/models/comment.py:191 +#: chat_box/models.py:16 judge/models/comment.py:42 msgid "posted time" msgstr "время публикации" -#: chat_box/models.py:18 judge/models/comment.py:47 +#: chat_box/models.py:17 judge/models/comment.py:46 msgid "body of comment" msgstr "тело комментария" -#: chat_box/views.py:29 templates/chat/chat.html:4 +#: chat_box/views.py:29 msgid "Chat Box" msgstr "" -#: dmoj/settings.py:355 +#: dmoj/settings.py:349 msgid "German" msgstr "немецкий" -#: dmoj/settings.py:356 +#: dmoj/settings.py:350 msgid "English" msgstr "английский" -#: dmoj/settings.py:357 +#: dmoj/settings.py:351 msgid "Spanish" msgstr "Испанский" -#: dmoj/settings.py:358 +#: dmoj/settings.py:352 msgid "French" msgstr "французский" -#: dmoj/settings.py:359 +#: dmoj/settings.py:353 msgid "Croatian" msgstr "Хорватский" -#: dmoj/settings.py:360 +#: dmoj/settings.py:354 msgid "Hungarian" msgstr "" -#: dmoj/settings.py:361 +#: dmoj/settings.py:355 msgid "Japanese" msgstr "" -#: dmoj/settings.py:362 +#: dmoj/settings.py:356 msgid "Korean" msgstr "Корейский" -#: dmoj/settings.py:363 +#: dmoj/settings.py:357 msgid "Brazilian Portuguese" msgstr "" -#: dmoj/settings.py:364 +#: dmoj/settings.py:358 msgid "Romanian" msgstr "Румынский" -#: dmoj/settings.py:365 +#: dmoj/settings.py:359 msgid "Russian" msgstr "русский" -#: dmoj/settings.py:366 +#: dmoj/settings.py:360 msgid "Serbian (Latin)" msgstr "Сербский (латиница)" -#: dmoj/settings.py:367 +#: dmoj/settings.py:361 msgid "Turkish" msgstr "Турецкий" -#: dmoj/settings.py:368 +#: dmoj/settings.py:362 msgid "Vietnamese" msgstr "Вьетнамский" -#: dmoj/settings.py:369 +#: dmoj/settings.py:363 msgid "Simplified Chinese" msgstr "Упрощенный китайский" -#: dmoj/settings.py:370 +#: dmoj/settings.py:364 msgid "Traditional Chinese" msgstr "" -#: dmoj/urls.py:58 +#: dmoj/urls.py:57 msgid "Login" msgstr "Войти" -#: dmoj/urls.py:106 templates/base.html:193 +#: dmoj/urls.py:105 templates/base.html:190 msgid "Home" msgstr "Главная" @@ -138,48 +138,46 @@ msgstr "Показать комментарии" msgid "Associated page" msgstr "Связанная страница" -#: judge/admin/contest.py:30 +#: judge/admin/contest.py:28 msgid "Included contests" msgstr "Включены конкурсы" -#: judge/admin/contest.py:66 templates/contest/clarification.html:42 -#: templates/contest/contest.html:83 templates/contest/moss.html:43 -#: templates/problem/list.html:214 templates/problem/list.html:232 -#: templates/problem/list.html:350 templates/user/user-problems.html:56 +#: judge/admin/contest.py:64 templates/contest/contest.html:83 +#: templates/contest/moss.html:43 templates/problem/list.html:206 +#: templates/problem/list.html:221 templates/user/user-problems.html:56 #: templates/user/user-problems.html:98 msgid "Problem" msgstr "Проблема" -#: judge/admin/contest.py:119 +#: judge/admin/contest.py:112 msgid "Settings" msgstr "" -#: judge/admin/contest.py:121 +#: judge/admin/contest.py:114 msgid "Scheduling" msgstr "Расписание" -#: judge/admin/contest.py:122 templates/organization/home.html:107 +#: judge/admin/contest.py:115 msgid "Details" msgstr "Детали" -#: judge/admin/contest.py:123 +#: judge/admin/contest.py:116 msgid "Format" msgstr "" -#: judge/admin/contest.py:124 templates/contest/ranking-table.html:7 -#: templates/user/user-about.html:15 templates/user/user-about.html:45 +#: judge/admin/contest.py:117 templates/contest/ranking-table.html:5 msgid "Rating" msgstr "Рейтинг" -#: judge/admin/contest.py:125 +#: judge/admin/contest.py:118 msgid "Access" msgstr "" -#: judge/admin/contest.py:127 judge/admin/problem.py:131 +#: judge/admin/contest.py:120 judge/admin/problem.py:131 msgid "Justice" msgstr "Судья" -#: judge/admin/contest.py:207 +#: judge/admin/contest.py:158 #, python-format msgid "%d contest successfully marked as visible." msgid_plural "%d contests successfully marked as visible." @@ -188,11 +186,11 @@ msgstr[1] "" msgstr[2] "" msgstr[3] "" -#: judge/admin/contest.py:210 +#: judge/admin/contest.py:161 msgid "Mark contests as visible" msgstr "" -#: judge/admin/contest.py:216 +#: judge/admin/contest.py:165 #, python-format msgid "%d contest successfully marked as hidden." msgid_plural "%d contests successfully marked as hidden." @@ -201,11 +199,11 @@ msgstr[1] "" msgstr[2] "" msgstr[3] "" -#: judge/admin/contest.py:219 +#: judge/admin/contest.py:168 msgid "Mark contests as hidden" msgstr "" -#: judge/admin/contest.py:233 judge/admin/submission.py:164 +#: judge/admin/contest.py:182 judge/admin/submission.py:164 #, python-format msgid "%d submission was successfully scheduled for rejudging." msgid_plural "%d submissions were successfully scheduled for rejudging." @@ -214,7 +212,7 @@ msgstr[1] "" msgstr[2] "" msgstr[3] "" -#: judge/admin/contest.py:308 +#: judge/admin/contest.py:256 #, python-format msgid "%d participation recalculated." msgid_plural "%d participations recalculated." @@ -223,15 +221,15 @@ msgstr[1] "" msgstr[2] "" msgstr[3] "" -#: judge/admin/contest.py:311 +#: judge/admin/contest.py:259 msgid "Recalculate results" msgstr "" -#: judge/admin/contest.py:315 judge/admin/organization.py:65 +#: judge/admin/contest.py:263 judge/admin/organization.py:65 msgid "username" msgstr "имя пользователя" -#: judge/admin/contest.py:320 templates/base.html:277 +#: judge/admin/contest.py:268 templates/base.html:260 msgid "virtual" msgstr "виртуальный" @@ -239,15 +237,15 @@ msgstr "виртуальный" msgid "link path" msgstr "адресс ссылки" -#: judge/admin/interface.py:65 +#: judge/admin/interface.py:62 msgid "Content" msgstr "Содержание" -#: judge/admin/interface.py:66 +#: judge/admin/interface.py:63 msgid "Summary" msgstr "Сводка" -#: judge/admin/interface.py:151 +#: judge/admin/interface.py:148 msgid "object" msgstr "" @@ -269,9 +267,8 @@ msgid "Taxonomy" msgstr "" #: judge/admin/problem.py:128 templates/contest/contest.html:84 -#: templates/problem/data.html:429 templates/problem/list.html:222 -#: templates/problem/list.html:248 templates/user/base-users-table.html:10 -#: templates/user/user-about.html:36 templates/user/user-about.html:52 +#: templates/problem/data.html:449 templates/problem/list.html:211 +#: templates/problem/list.html:232 templates/user/base-users-table.html:10 #: templates/user/user-problems.html:58 msgid "Points" msgstr "Очки" @@ -324,7 +321,6 @@ msgid "timezone" msgstr "часовой пояс" #: judge/admin/profile.py:86 judge/admin/submission.py:211 -#: templates/notification/list.html:12 #: templates/organization/requests/log.html:9 #: templates/organization/requests/pending.html:12 #: templates/ticket/list.html:263 @@ -332,7 +328,6 @@ msgid "User" msgstr "Пользователь" #: judge/admin/profile.py:91 templates/registration/registration_form.html:145 -#: templates/user/import/table_csv.html:8 msgid "Email" msgstr "Эл. почта" @@ -367,7 +362,7 @@ msgstr "" msgid "These problems are NOT allowed to be submitted in this language" msgstr "Решения этих задач нельзя сдавать на этом языке" -#: judge/admin/runtime.py:83 templates/problem/list.html:352 +#: judge/admin/runtime.py:83 msgid "Description" msgstr "Описание" @@ -414,7 +409,7 @@ msgstr "У вас нет доступа перетестировать ТАК м msgid "Rejudge the selected submissions" msgstr "Перетестировать выбранные посылки" -#: judge/admin/submission.py:193 judge/views/problem_manage.py:159 +#: judge/admin/submission.py:193 judge/views/problem_manage.py:128 #, python-format msgid "%d submission were successfully rescored." msgid_plural "%d submissions were successfully rescored." @@ -427,8 +422,7 @@ msgstr[3] "" msgid "Rescore the selected submissions" msgstr "" -#: judge/admin/submission.py:200 templates/problem/list.html:216 -#: templates/problem/list.html:236 +#: judge/admin/submission.py:200 msgid "Problem code" msgstr "Исходный код" @@ -436,12 +430,10 @@ msgstr "Исходный код" msgid "Problem name" msgstr "Название задачи" -#: judge/admin/submission.py:215 templates/notification/list.html:15 -#: templates/organization/requests/log.html:10 +#: judge/admin/submission.py:215 templates/organization/requests/log.html:10 #: templates/organization/requests/pending.html:13 -#: templates/problem/list.html:351 -#: templates/submission/status-testcases.html:125 -#: templates/submission/status-testcases.html:127 +#: templates/submission/status-testcases.html:105 +#: templates/submission/status-testcases.html:107 msgid "Time" msgstr "Время" @@ -455,7 +447,7 @@ msgstr "%d KB" msgid "%.2f MB" msgstr "%.2f MB" -#: judge/admin/submission.py:227 templates/submission/status-testcases.html:132 +#: judge/admin/submission.py:227 templates/submission/status-testcases.html:112 msgid "Memory" msgstr "Память" @@ -475,20 +467,20 @@ msgstr "Эти задачи включены в этот тип задач" msgid "Online Judge" msgstr "Онлайн Judge" -#: judge/comments.py:60 +#: judge/comments.py:41 msgid "Comment body" msgstr "Содержание комментария" -#: judge/comments.py:66 judge/views/ticket.py:63 +#: judge/comments.py:47 judge/views/ticket.py:46 msgid "Your part is silent, little toad." msgstr "" -#: judge/comments.py:69 templates/comments/list.html:132 +#: judge/comments.py:50 templates/comments/list.html:131 msgid "" "You need to have solved at least one problem before your voice can be heard." msgstr "Вам нужно решить хотя бы одну задачу, чтобы оставить комментарий." -#: judge/comments.py:113 +#: judge/comments.py:92 msgid "Posted comment" msgstr "" @@ -504,10 +496,6 @@ msgstr "" msgid "ECOO" msgstr "" -#: judge/contest_format/icpc.py:19 -msgid "ICPC" -msgstr "" - #: judge/contest_format/ioi.py:19 msgid "IOI" msgstr "" @@ -520,58 +508,52 @@ msgstr "Уведомлять об изменениях в соревновани msgid "Enable experimental features" msgstr "Включить экспериментальные возможности" -#: judge/forms.py:57 judge/views/organization.py:168 judge/views/register.py:49 +#: judge/forms.py:57 judge/views/organization.py:127 #, python-brace-format msgid "You may not be part of more than {count} public organizations." msgstr "Вы не можете состоять более чем в {count} публичных организациях." -#: judge/forms.py:82 -msgid "Any judge" -msgstr "" - -#: judge/forms.py:112 judge/views/register.py:26 +#: judge/forms.py:107 judge/views/register.py:26 #: templates/registration/registration_form.html:139 #: templates/user/base-users-table.html:5 -#: templates/user/import/table_csv.html:4 msgid "Username" msgstr "Имя пользователя" -#: judge/forms.py:113 templates/registration/registration_form.html:151 +#: judge/forms.py:108 templates/registration/registration_form.html:151 #: templates/registration/registration_form.html:165 -#: templates/user/import/table_csv.html:5 msgid "Password" msgstr "Пароль" -#: judge/forms.py:135 +#: judge/forms.py:130 msgid "Two Factor Authentication tokens must be 6 decimal digits." msgstr "" -#: judge/forms.py:144 templates/registration/totp_auth.html:32 +#: judge/forms.py:139 templates/registration/totp_auth.html:32 msgid "Invalid Two Factor Authentication token." msgstr "" -#: judge/forms.py:148 judge/models/problem.py:97 +#: judge/forms.py:143 judge/models/problem.py:97 msgid "Problem code must be ^[a-z0-9]+$" msgstr "" -#: judge/forms.py:153 +#: judge/forms.py:148 msgid "Problem with code already exists." msgstr "" -#: judge/forms.py:158 judge/models/contest.py:61 +#: judge/forms.py:153 judge/models/contest.py:52 msgid "Contest id must be ^[a-z0-9]+$" msgstr "" -#: judge/forms.py:163 +#: judge/forms.py:158 msgid "Contest with key already exists." msgstr "" -#: judge/jinja2/datetime.py:26 templates/blog/blog.html:26 +#: judge/jinja2/datetime.py:26 templates/blog/content.html:27 #: templates/blog/dashboard.html:21 msgid "N j, Y, g:i a" msgstr "" -#: judge/jinja2/datetime.py:26 templates/chat/message.html:13 +#: judge/jinja2/datetime.py:26 #, python-brace-format msgid "{time}" msgstr "{time}" @@ -601,558 +583,472 @@ msgstr "" msgid "Detect best quality" msgstr "" -#: judge/models/comment.py:26 +#: judge/models/comment.py:25 msgid "Page code must be ^[pcs]:[a-z0-9]+$|^b:\\d+$" msgstr "" -#: judge/models/comment.py:42 +#: judge/models/comment.py:41 msgid "commenter" msgstr "комментатор" -#: judge/models/comment.py:44 judge/models/comment.py:177 +#: judge/models/comment.py:43 judge/models/comment.py:176 msgid "associated page" msgstr "" -#: judge/models/comment.py:46 +#: judge/models/comment.py:45 msgid "votes" msgstr "" -#: judge/models/comment.py:48 +#: judge/models/comment.py:47 msgid "hide the comment" msgstr "скрыть комментарий" -#: judge/models/comment.py:49 +#: judge/models/comment.py:48 msgid "parent" msgstr "родитель" -#: judge/models/comment.py:54 judge/models/comment.py:192 +#: judge/models/comment.py:53 msgid "comment" msgstr "комментарий" -#: judge/models/comment.py:55 +#: judge/models/comment.py:54 msgid "comments" msgstr "комментарии" -#: judge/models/comment.py:137 judge/models/problem.py:443 +#: judge/models/comment.py:136 judge/models/problem.py:406 #, python-format msgid "Editorial for %s" msgstr "Разбор задач для %s" -#: judge/models/comment.py:172 +#: judge/models/comment.py:171 msgid "comment vote" msgstr "" -#: judge/models/comment.py:173 +#: judge/models/comment.py:172 msgid "comment votes" msgstr "" -#: judge/models/comment.py:182 +#: judge/models/comment.py:181 msgid "Override comment lock" msgstr "" -#: judge/models/comment.py:190 -msgid "owner" -msgstr "" - -#: judge/models/comment.py:193 judge/models/message.py:16 -msgid "read" -msgstr "" - -#: judge/models/comment.py:194 -#, fuzzy -#| msgid "Category" -msgid "category" -msgstr "Категория" - -#: judge/models/comment.py:195 -msgid "html link to comments, used for non-comments" -msgstr "" - -#: judge/models/comment.py:196 -msgid "who trigger, used for non-comment" -msgstr "" - -#: judge/models/contest.py:23 +#: judge/models/contest.py:22 msgid "Invalid colour." msgstr "Недопустимый цвет." -#: judge/models/contest.py:25 +#: judge/models/contest.py:24 msgid "tag name" msgstr "" -#: judge/models/contest.py:26 +#: judge/models/contest.py:25 msgid "Lowercase letters and hyphens only." msgstr "Только буквы нижнего регистра и дефисы." -#: judge/models/contest.py:27 +#: judge/models/contest.py:26 msgid "tag colour" msgstr "цвет тега" -#: judge/models/contest.py:28 +#: judge/models/contest.py:27 msgid "tag description" msgstr "описание тега" -#: judge/models/contest.py:47 +#: judge/models/contest.py:46 msgid "contest tag" msgstr "тег соревнования" -#: judge/models/contest.py:48 judge/models/contest.py:118 +#: judge/models/contest.py:47 judge/models/contest.py:101 msgid "contest tags" msgstr "теги соревнования" -#: judge/models/contest.py:56 -msgid "Visible" -msgstr "" - -#: judge/models/contest.py:57 -msgid "Hidden for duration of contest" -msgstr "" - -#: judge/models/contest.py:58 -msgid "Hidden for duration of participation" -msgstr "" - -#: judge/models/contest.py:60 +#: judge/models/contest.py:51 msgid "contest id" msgstr "" -#: judge/models/contest.py:62 +#: judge/models/contest.py:53 msgid "contest name" msgstr "название соревнования" -#: judge/models/contest.py:63 -#, fuzzy -#| msgid "These people will be able to edit the contest." -msgid "These users will be able to edit the contest." +#: judge/models/contest.py:54 +msgid "These people will be able to edit the contest." msgstr "Эти люди будут иметь право изменять соревнование." -#: judge/models/contest.py:65 -#, fuzzy -#| msgid "These people will be able to edit the contest." -msgid "" -"These users will be able to edit the contest, but will not be listed as " -"authors." -msgstr "Эти люди будут иметь право изменять соревнование." - -#: judge/models/contest.py:68 -#, fuzzy -#| msgid "These people will be able to edit the contest." -msgid "These users will be able to view the contest, but not edit it." -msgstr "Эти люди будут иметь право изменять соревнование." - -#: judge/models/contest.py:71 judge/models/runtime.py:136 +#: judge/models/contest.py:56 judge/models/runtime.py:133 msgid "description" msgstr "описание" -#: judge/models/contest.py:72 judge/models/problem.py:390 -#: judge/models/runtime.py:138 +#: judge/models/contest.py:57 judge/models/problem.py:353 +#: judge/models/runtime.py:135 msgid "problems" msgstr "задачи" -#: judge/models/contest.py:73 judge/models/contest.py:404 +#: judge/models/contest.py:58 judge/models/contest.py:258 msgid "start time" msgstr "время начала" -#: judge/models/contest.py:74 +#: judge/models/contest.py:59 msgid "end time" msgstr "время конца" -#: judge/models/contest.py:75 judge/models/problem.py:118 -#: judge/models/problem.py:414 +#: judge/models/contest.py:60 judge/models/problem.py:118 +#: judge/models/problem.py:377 msgid "time limit" msgstr "ограничение по памяти" -#: judge/models/contest.py:76 judge/models/problem.py:136 +#: judge/models/contest.py:61 judge/models/problem.py:136 msgid "publicly visible" msgstr "" -#: judge/models/contest.py:77 +#: judge/models/contest.py:62 msgid "" "Should be set even for organization-private contests, where it determines " "whether the contest is visible to members of the specified organizations." msgstr "" -#: judge/models/contest.py:80 +#: judge/models/contest.py:65 msgid "contest rated" msgstr "соревнование рейтинговое" -#: judge/models/contest.py:80 +#: judge/models/contest.py:65 msgid "Whether this contest can be rated." msgstr "Будте ли соревнование рейтинговым." -#: judge/models/contest.py:82 -msgid "scoreboard visibility" -msgstr "" - -#: judge/models/contest.py:83 -#, fuzzy -#| msgid "" -#| "Whether the scoreboard should remain hidden for the duration of the " -#| "contest." -msgid "Scoreboard visibility through the duration of the contest" -msgstr "Должна ли таблица быть скрыта на протяжении соревнования." - -#: judge/models/contest.py:85 -#, fuzzy -#| msgid "hide scoreboard" -msgid "view contest scoreboard" +#: judge/models/contest.py:67 +msgid "hide scoreboard" msgstr "скрыть таблицу" -#: judge/models/contest.py:87 -#, fuzzy -#| msgid "These people will be able to edit the contest." -msgid "These users will be able to view the scoreboard." -msgstr "Эти люди будут иметь право изменять соревнование." +#: judge/models/contest.py:68 +msgid "" +"Whether the scoreboard should remain hidden for the duration of the contest." +msgstr "Должна ли таблица быть скрыта на протяжении соревнования." -#: judge/models/contest.py:88 +#: judge/models/contest.py:71 msgid "no comments" msgstr "без комментариев" -#: judge/models/contest.py:89 +#: judge/models/contest.py:72 msgid "Use clarification system instead of comments." msgstr "Используйте систему кларов вместо комментариев." -#: judge/models/contest.py:91 +#: judge/models/contest.py:74 msgid "Rating floor for contest" msgstr "" -#: judge/models/contest.py:93 +#: judge/models/contest.py:76 msgid "Rating ceiling for contest" msgstr "" -#: judge/models/contest.py:95 +#: judge/models/contest.py:78 msgid "rate all" msgstr "" -#: judge/models/contest.py:95 +#: judge/models/contest.py:78 msgid "Rate all users who joined." msgstr "" -#: judge/models/contest.py:96 +#: judge/models/contest.py:79 msgid "exclude from ratings" msgstr "" -#: judge/models/contest.py:98 +#: judge/models/contest.py:81 msgid "private to specific users" msgstr "" -#: judge/models/contest.py:99 +#: judge/models/contest.py:82 msgid "private contestants" msgstr "" -#: judge/models/contest.py:100 +#: judge/models/contest.py:83 msgid "If private, only these users may see the contest" msgstr "" -#: judge/models/contest.py:102 +#: judge/models/contest.py:85 msgid "hide problem tags" msgstr "спрятать тэги задач" -#: judge/models/contest.py:103 +#: judge/models/contest.py:86 msgid "Whether problem tags should be hidden by default." msgstr "" -#: judge/models/contest.py:105 +#: judge/models/contest.py:88 msgid "run pretests only" msgstr "запустить только претесты" -#: judge/models/contest.py:106 +#: judge/models/contest.py:89 msgid "" "Whether judges should grade pretests only, versus all testcases. Commonly " "set during a contest, then unset prior to rejudging user submissions when " "the contest ends." msgstr "" -#: judge/models/contest.py:110 judge/models/interface.py:77 -#: judge/models/problem.py:157 +#: judge/models/contest.py:93 judge/models/problem.py:157 msgid "private to organizations" msgstr "" -#: judge/models/contest.py:111 judge/models/interface.py:75 -#: judge/models/problem.py:155 judge/models/profile.py:77 +#: judge/models/contest.py:94 judge/models/problem.py:155 +#: judge/models/profile.py:77 msgid "organizations" msgstr "организации" -#: judge/models/contest.py:112 +#: judge/models/contest.py:95 msgid "If private, only these organizations may see the contest" msgstr "" -#: judge/models/contest.py:113 judge/models/problem.py:145 +#: judge/models/contest.py:96 judge/models/problem.py:145 msgid "OpenGraph image" msgstr "" -#: judge/models/contest.py:114 judge/models/profile.py:48 +#: judge/models/contest.py:97 judge/models/profile.py:48 msgid "Logo override image" msgstr "" -#: judge/models/contest.py:116 +#: judge/models/contest.py:99 msgid "" "This image will replace the default site logo for users inside the contest." msgstr "" -#: judge/models/contest.py:119 +#: judge/models/contest.py:102 msgid "the amount of live participants" msgstr "" -#: judge/models/contest.py:120 +#: judge/models/contest.py:103 msgid "contest summary" msgstr "" -#: judge/models/contest.py:121 judge/models/problem.py:147 +#: judge/models/contest.py:104 judge/models/problem.py:147 msgid "Plain-text, shown in meta description tag, e.g. for social media." msgstr "" -#: judge/models/contest.py:122 judge/models/profile.py:47 +#: judge/models/contest.py:105 judge/models/profile.py:47 msgid "access code" msgstr "" -#: judge/models/contest.py:123 +#: judge/models/contest.py:106 msgid "" "An optional code to prompt contestants before they are allowed to join the " "contest. Leave it blank to disable." msgstr "" -#: judge/models/contest.py:125 judge/models/problem.py:141 +#: judge/models/contest.py:108 judge/models/problem.py:141 msgid "personae non gratae" msgstr "" -#: judge/models/contest.py:126 +#: judge/models/contest.py:109 msgid "Bans the selected users from joining this contest." msgstr "" -#: judge/models/contest.py:127 +#: judge/models/contest.py:110 msgid "contest format" msgstr "" -#: judge/models/contest.py:128 +#: judge/models/contest.py:111 msgid "The contest format module to use." msgstr "" -#: judge/models/contest.py:129 +#: judge/models/contest.py:112 msgid "contest format configuration" msgstr "" -#: judge/models/contest.py:130 +#: judge/models/contest.py:113 msgid "" "A JSON object to serve as the configuration for the chosen contest format " "module. Leave empty to use None. Exact format depends on the contest format " "selected." msgstr "" -#: judge/models/contest.py:137 -msgid "precision points" -msgstr "" - -#: judge/models/contest.py:139 -msgid "Number of digits to round points to." -msgstr "" - -#: judge/models/contest.py:383 +#: judge/models/contest.py:239 msgid "See private contests" msgstr "" -#: judge/models/contest.py:384 +#: judge/models/contest.py:240 msgid "Edit own contests" msgstr "" -#: judge/models/contest.py:385 +#: judge/models/contest.py:241 msgid "Edit all contests" msgstr "" -#: judge/models/contest.py:386 +#: judge/models/contest.py:242 msgid "Clone contest" msgstr "" -#: judge/models/contest.py:387 templates/contest/moss.html:74 +#: judge/models/contest.py:243 templates/contest/moss.html:74 msgid "MOSS contest" msgstr "" -#: judge/models/contest.py:388 +#: judge/models/contest.py:244 msgid "Rate contests" msgstr "" -#: judge/models/contest.py:389 +#: judge/models/contest.py:245 msgid "Contest access codes" msgstr "" -#: judge/models/contest.py:390 +#: judge/models/contest.py:246 msgid "Create private contests" msgstr "" -#: judge/models/contest.py:391 -msgid "Change contest visibility" -msgstr "" - -#: judge/models/contest.py:392 -msgid "Edit contest problem label script" -msgstr "" - -#: judge/models/contest.py:394 judge/models/contest.py:492 -#: judge/models/contest.py:529 judge/models/contest.py:552 -#: judge/models/submission.py:84 +#: judge/models/contest.py:248 judge/models/contest.py:345 +#: judge/models/contest.py:382 judge/models/contest.py:404 +#: judge/models/submission.py:83 msgid "contest" msgstr "соревнование" -#: judge/models/contest.py:395 +#: judge/models/contest.py:249 msgid "contests" msgstr "соревнования" -#: judge/models/contest.py:402 +#: judge/models/contest.py:256 msgid "associated contest" msgstr "" -#: judge/models/contest.py:405 +#: judge/models/contest.py:259 msgid "score" msgstr "" -#: judge/models/contest.py:406 +#: judge/models/contest.py:260 msgid "cumulative time" msgstr "" -#: judge/models/contest.py:407 +#: judge/models/contest.py:261 msgid "is disqualified" msgstr "" -#: judge/models/contest.py:408 +#: judge/models/contest.py:262 msgid "Whether this participation is disqualified." msgstr "" -#: judge/models/contest.py:409 -msgid "tie-breaking field" -msgstr "" - -#: judge/models/contest.py:410 +#: judge/models/contest.py:263 msgid "virtual participation id" msgstr "" -#: judge/models/contest.py:411 +#: judge/models/contest.py:264 msgid "0 means non-virtual, otherwise the n-th virtual participation." msgstr "" -#: judge/models/contest.py:412 +#: judge/models/contest.py:265 msgid "contest format specific data" msgstr "" -#: judge/models/contest.py:478 +#: judge/models/contest.py:331 #, python-format msgid "%s spectating in %s" msgstr "" -#: judge/models/contest.py:480 +#: judge/models/contest.py:333 #, python-format msgid "%s in %s, v%d" msgstr "" -#: judge/models/contest.py:481 +#: judge/models/contest.py:334 #, python-format msgid "%s in %s" msgstr "" -#: judge/models/contest.py:484 +#: judge/models/contest.py:337 msgid "contest participation" msgstr "участие в соревновании" -#: judge/models/contest.py:485 +#: judge/models/contest.py:338 msgid "contest participations" msgstr "" -#: judge/models/contest.py:491 judge/models/contest.py:513 -#: judge/models/contest.py:553 judge/models/problem.py:389 -#: judge/models/problem.py:394 judge/models/problem.py:412 -#: judge/models/problem_data.py:40 +#: judge/models/contest.py:344 judge/models/contest.py:366 +#: judge/models/contest.py:405 judge/models/problem.py:352 +#: judge/models/problem.py:357 judge/models/problem.py:375 +#: judge/models/problem_data.py:38 msgid "problem" msgstr "задача" -#: judge/models/contest.py:493 judge/models/contest.py:517 +#: judge/models/contest.py:346 judge/models/contest.py:370 #: judge/models/problem.py:129 msgid "points" msgstr "очки" -#: judge/models/contest.py:494 +#: judge/models/contest.py:347 msgid "partial" msgstr "частичный" -#: judge/models/contest.py:495 judge/models/contest.py:518 +#: judge/models/contest.py:348 judge/models/contest.py:371 msgid "is pretested" msgstr "" -#: judge/models/contest.py:496 judge/models/interface.py:43 +#: judge/models/contest.py:349 judge/models/interface.py:43 msgid "order" msgstr "порядок" -#: judge/models/contest.py:497 +#: judge/models/contest.py:350 msgid "0 to not show testcases, 1 to show" msgstr "" -#: judge/models/contest.py:498 +#: judge/models/contest.py:351 msgid "visible testcases" msgstr "" -#: judge/models/contest.py:499 +#: judge/models/contest.py:352 msgid "Maximum number of submissions for this problem, or 0 for no limit." msgstr "" -#: judge/models/contest.py:501 +#: judge/models/contest.py:354 msgid "Why include a problem you can't submit to?" msgstr "" -#: judge/models/contest.py:506 +#: judge/models/contest.py:359 msgid "contest problem" msgstr "" -#: judge/models/contest.py:507 +#: judge/models/contest.py:360 msgid "contest problems" msgstr "" -#: judge/models/contest.py:511 judge/models/submission.py:183 +#: judge/models/contest.py:364 judge/models/submission.py:181 msgid "submission" msgstr "посылка" -#: judge/models/contest.py:515 judge/models/contest.py:530 +#: judge/models/contest.py:368 judge/models/contest.py:383 msgid "participation" msgstr "участие" -#: judge/models/contest.py:519 +#: judge/models/contest.py:372 msgid "Whether this submission was ran only on pretests." msgstr "" -#: judge/models/contest.py:523 +#: judge/models/contest.py:376 msgid "contest submission" msgstr "" -#: judge/models/contest.py:524 +#: judge/models/contest.py:377 msgid "contest submissions" msgstr "" -#: judge/models/contest.py:532 +#: judge/models/contest.py:385 msgid "rank" msgstr "ранг" -#: judge/models/contest.py:533 +#: judge/models/contest.py:386 msgid "rating" msgstr "рейтинг" -#: judge/models/contest.py:534 +#: judge/models/contest.py:387 msgid "volatility" msgstr "" -#: judge/models/contest.py:535 +#: judge/models/contest.py:388 msgid "last rated" msgstr "" -#: judge/models/contest.py:539 +#: judge/models/contest.py:392 msgid "contest rating" msgstr "" -#: judge/models/contest.py:540 +#: judge/models/contest.py:393 msgid "contest ratings" msgstr "" -#: judge/models/contest.py:560 +#: judge/models/contest.py:412 msgid "contest moss result" msgstr "" -#: judge/models/contest.py:561 +#: judge/models/contest.py:413 msgid "contest moss results" msgstr "" @@ -1192,7 +1088,7 @@ msgstr "" msgid "post title" msgstr "" -#: judge/models/interface.py:67 judge/models/problem.py:432 +#: judge/models/interface.py:67 judge/models/problem.py:395 msgid "authors" msgstr "авторы" @@ -1200,7 +1096,7 @@ msgstr "авторы" msgid "slug" msgstr "" -#: judge/models/interface.py:69 judge/models/problem.py:430 +#: judge/models/interface.py:69 judge/models/problem.py:393 msgid "public visibility" msgstr "" @@ -1224,19 +1120,15 @@ msgstr "" msgid "openGraph image" msgstr "" -#: judge/models/interface.py:76 -msgid "If private, only these organizations may see the blog post." -msgstr "" - -#: judge/models/interface.py:105 +#: judge/models/interface.py:91 msgid "Edit all posts" msgstr "" -#: judge/models/interface.py:107 +#: judge/models/interface.py:93 msgid "blog post" msgstr "" -#: judge/models/interface.py:108 +#: judge/models/interface.py:94 msgid "blog posts" msgstr "" @@ -1260,6 +1152,10 @@ msgstr "" msgid "message timestamp" msgstr "" +#: judge/models/message.py:16 +msgid "read" +msgstr "" + #: judge/models/message.py:20 msgid "messages in the thread" msgstr "" @@ -1396,7 +1292,7 @@ msgid "" "are supported." msgstr "" -#: judge/models/problem.py:123 judge/models/problem.py:417 +#: judge/models/problem.py:123 judge/models/problem.py:380 msgid "memory limit" msgstr "" @@ -1469,188 +1365,188 @@ msgstr "" msgid "If private, only these organizations may see the problem." msgstr "" -#: judge/models/problem.py:395 judge/models/problem.py:413 -#: judge/models/runtime.py:111 +#: judge/models/problem.py:358 judge/models/problem.py:376 +#: judge/models/runtime.py:108 msgid "language" msgstr "язык" -#: judge/models/problem.py:396 +#: judge/models/problem.py:359 msgid "translated name" msgstr "" -#: judge/models/problem.py:397 +#: judge/models/problem.py:360 msgid "translated description" msgstr "" -#: judge/models/problem.py:401 +#: judge/models/problem.py:364 msgid "problem translation" msgstr "" -#: judge/models/problem.py:402 +#: judge/models/problem.py:365 msgid "problem translations" msgstr "" -#: judge/models/problem.py:406 +#: judge/models/problem.py:369 msgid "clarified problem" msgstr "" -#: judge/models/problem.py:407 +#: judge/models/problem.py:370 msgid "clarification body" msgstr "" -#: judge/models/problem.py:408 +#: judge/models/problem.py:371 msgid "clarification timestamp" msgstr "" -#: judge/models/problem.py:423 +#: judge/models/problem.py:386 msgid "language-specific resource limit" msgstr "" -#: judge/models/problem.py:424 +#: judge/models/problem.py:387 msgid "language-specific resource limits" msgstr "" -#: judge/models/problem.py:428 +#: judge/models/problem.py:391 msgid "associated problem" msgstr "" -#: judge/models/problem.py:431 +#: judge/models/problem.py:394 msgid "publish date" msgstr "" -#: judge/models/problem.py:433 +#: judge/models/problem.py:396 msgid "editorial content" msgstr "" -#: judge/models/problem.py:449 +#: judge/models/problem.py:412 msgid "solution" msgstr "" -#: judge/models/problem.py:450 +#: judge/models/problem.py:413 msgid "solutions" msgstr "" -#: judge/models/problem_data.py:26 +#: judge/models/problem_data.py:24 msgid "Standard" msgstr "" -#: judge/models/problem_data.py:27 +#: judge/models/problem_data.py:25 msgid "Floats" msgstr "" -#: judge/models/problem_data.py:28 +#: judge/models/problem_data.py:26 msgid "Floats (absolute)" msgstr "" -#: judge/models/problem_data.py:29 +#: judge/models/problem_data.py:27 msgid "Floats (relative)" msgstr "" -#: judge/models/problem_data.py:30 +#: judge/models/problem_data.py:28 msgid "Non-trailing spaces" msgstr "" -#: judge/models/problem_data.py:31 +#: judge/models/problem_data.py:29 msgid "Unordered" msgstr "" -#: judge/models/problem_data.py:32 +#: judge/models/problem_data.py:30 msgid "Byte identical" msgstr "" -#: judge/models/problem_data.py:33 +#: judge/models/problem_data.py:31 msgid "Line-by-line" msgstr "" -#: judge/models/problem_data.py:34 +#: judge/models/problem_data.py:32 msgid "Custom checker (PY)" msgstr "" -#: judge/models/problem_data.py:35 +#: judge/models/problem_data.py:33 msgid "Custom validator (CPP)" msgstr "" -#: judge/models/problem_data.py:42 +#: judge/models/problem_data.py:40 msgid "data zip file" msgstr "" -#: judge/models/problem_data.py:44 +#: judge/models/problem_data.py:42 msgid "generator file" msgstr "" -#: judge/models/problem_data.py:46 judge/models/problem_data.py:121 +#: judge/models/problem_data.py:44 judge/models/problem_data.py:110 msgid "output prefix length" msgstr "" -#: judge/models/problem_data.py:47 judge/models/problem_data.py:122 +#: judge/models/problem_data.py:45 judge/models/problem_data.py:111 msgid "output limit length" msgstr "" -#: judge/models/problem_data.py:48 +#: judge/models/problem_data.py:46 msgid "init.yml generation feedback" msgstr "" -#: judge/models/problem_data.py:49 judge/models/problem_data.py:123 +#: judge/models/problem_data.py:47 judge/models/problem_data.py:112 msgid "checker" msgstr "" -#: judge/models/problem_data.py:50 judge/models/problem_data.py:124 +#: judge/models/problem_data.py:48 judge/models/problem_data.py:113 msgid "checker arguments" msgstr "" -#: judge/models/problem_data.py:51 judge/models/problem_data.py:125 +#: judge/models/problem_data.py:49 judge/models/problem_data.py:114 msgid "checker arguments as a JSON object" msgstr "" -#: judge/models/problem_data.py:52 +#: judge/models/problem_data.py:50 msgid "custom checker file" msgstr "" -#: judge/models/problem_data.py:58 +#: judge/models/problem_data.py:56 msgid "custom validator file" msgstr "" -#: judge/models/problem_data.py:108 +#: judge/models/problem_data.py:97 msgid "problem data set" msgstr "" -#: judge/models/problem_data.py:110 +#: judge/models/problem_data.py:99 msgid "case position" msgstr "" -#: judge/models/problem_data.py:111 +#: judge/models/problem_data.py:100 msgid "case type" msgstr "" -#: judge/models/problem_data.py:112 +#: judge/models/problem_data.py:101 msgid "Normal case" msgstr "" -#: judge/models/problem_data.py:113 +#: judge/models/problem_data.py:102 msgid "Batch start" msgstr "" -#: judge/models/problem_data.py:114 +#: judge/models/problem_data.py:103 msgid "Batch end" msgstr "" -#: judge/models/problem_data.py:116 +#: judge/models/problem_data.py:105 msgid "input file name" msgstr "" -#: judge/models/problem_data.py:117 +#: judge/models/problem_data.py:106 msgid "output file name" msgstr "" -#: judge/models/problem_data.py:118 +#: judge/models/problem_data.py:107 msgid "generator arguments" msgstr "" -#: judge/models/problem_data.py:119 +#: judge/models/problem_data.py:108 msgid "point value" msgstr "" -#: judge/models/problem_data.py:120 +#: judge/models/problem_data.py:109 msgid "case is pretest?" msgstr "" @@ -1723,7 +1619,7 @@ msgid "" msgstr "" #: judge/models/profile.py:76 judge/models/profile.py:93 -#: judge/models/profile.py:212 +#: judge/models/profile.py:192 msgid "organization" msgstr "" @@ -1819,31 +1715,31 @@ msgstr "" msgid "Notes for administrators regarding this user." msgstr "" -#: judge/models/profile.py:206 +#: judge/models/profile.py:186 msgid "user profile" msgstr "" -#: judge/models/profile.py:207 +#: judge/models/profile.py:187 msgid "user profiles" msgstr "" -#: judge/models/profile.py:214 +#: judge/models/profile.py:194 msgid "request time" msgstr "" -#: judge/models/profile.py:215 +#: judge/models/profile.py:195 msgid "state" msgstr "" -#: judge/models/profile.py:220 +#: judge/models/profile.py:200 msgid "reason" msgstr "" -#: judge/models/profile.py:223 +#: judge/models/profile.py:203 msgid "organization join request" msgstr "" -#: judge/models/profile.py:224 +#: judge/models/profile.py:204 msgid "organization join requests" msgstr "" @@ -1934,86 +1830,86 @@ msgstr "" msgid "The extension of source files, e.g., \"py\" or \"cpp\"." msgstr "" -#: judge/models/runtime.py:112 +#: judge/models/runtime.py:109 msgid "languages" msgstr "Языки" -#: judge/models/runtime.py:116 +#: judge/models/runtime.py:113 msgid "language to which this runtime belongs" msgstr "" -#: judge/models/runtime.py:117 +#: judge/models/runtime.py:114 msgid "judge on which this runtime exists" msgstr "" -#: judge/models/runtime.py:118 +#: judge/models/runtime.py:115 msgid "runtime name" msgstr "" -#: judge/models/runtime.py:119 +#: judge/models/runtime.py:116 msgid "runtime version" msgstr "" -#: judge/models/runtime.py:120 +#: judge/models/runtime.py:117 msgid "order in which to display this runtime" msgstr "" -#: judge/models/runtime.py:124 +#: judge/models/runtime.py:121 msgid "Server name, hostname-style" msgstr "" -#: judge/models/runtime.py:125 +#: judge/models/runtime.py:122 msgid "time of creation" msgstr "" -#: judge/models/runtime.py:126 +#: judge/models/runtime.py:123 msgid "A key to authenticate this judge" msgstr "" -#: judge/models/runtime.py:127 +#: judge/models/runtime.py:124 msgid "authentication key" msgstr "" -#: judge/models/runtime.py:128 +#: judge/models/runtime.py:125 msgid "block judge" msgstr "" -#: judge/models/runtime.py:129 +#: judge/models/runtime.py:126 msgid "" "Whether this judge should be blocked from connecting, even if its key is " "correct." msgstr "" -#: judge/models/runtime.py:131 +#: judge/models/runtime.py:128 msgid "judge online status" msgstr "" -#: judge/models/runtime.py:132 +#: judge/models/runtime.py:129 msgid "judge start time" msgstr "" -#: judge/models/runtime.py:133 +#: judge/models/runtime.py:130 msgid "response time" msgstr "" -#: judge/models/runtime.py:134 +#: judge/models/runtime.py:131 msgid "system load" msgstr "" -#: judge/models/runtime.py:135 +#: judge/models/runtime.py:132 msgid "Load for the last minute, divided by processors to be fair." msgstr "" -#: judge/models/runtime.py:139 judge/models/runtime.py:179 +#: judge/models/runtime.py:136 judge/models/runtime.py:176 msgid "judges" msgstr "" -#: judge/models/runtime.py:178 +#: judge/models/runtime.py:175 msgid "judge" msgstr "" #: judge/models/submission.py:20 judge/models/submission.py:47 -#: judge/utils/problems.py:79 +#: judge/utils/problems.py:77 msgid "Accepted" msgstr "" @@ -2042,7 +1938,7 @@ msgid "Runtime Error" msgstr "" #: judge/models/submission.py:27 judge/models/submission.py:41 -#: judge/models/submission.py:55 judge/utils/problems.py:81 +#: judge/models/submission.py:55 judge/utils/problems.py:79 msgid "Compile Error" msgstr "" @@ -2083,15 +1979,15 @@ msgstr "" msgid "submission time" msgstr "" -#: judge/models/submission.py:67 judge/models/submission.py:203 +#: judge/models/submission.py:67 judge/models/submission.py:201 msgid "execution time" msgstr "" -#: judge/models/submission.py:68 judge/models/submission.py:204 +#: judge/models/submission.py:68 judge/models/submission.py:202 msgid "memory usage" msgstr "" -#: judge/models/submission.py:69 judge/models/submission.py:205 +#: judge/models/submission.py:69 judge/models/submission.py:203 msgid "points granted" msgstr "" @@ -2128,64 +2024,58 @@ msgid "judged on" msgstr "" #: judge/models/submission.py:81 -#, fuzzy -#| msgid "submission" -msgid "submission judge time" -msgstr "посылка" - -#: judge/models/submission.py:82 msgid "was rejudged by admin" msgstr "" -#: judge/models/submission.py:83 +#: judge/models/submission.py:82 msgid "was ran on pretests only" msgstr "" -#: judge/models/submission.py:184 templates/contest/moss.html:58 +#: judge/models/submission.py:182 templates/contest/moss.html:58 msgid "submissions" msgstr "" -#: judge/models/submission.py:188 judge/models/submission.py:199 +#: judge/models/submission.py:186 judge/models/submission.py:197 msgid "associated submission" msgstr "" -#: judge/models/submission.py:190 +#: judge/models/submission.py:188 msgid "source code" msgstr "" -#: judge/models/submission.py:201 +#: judge/models/submission.py:199 msgid "test case ID" msgstr "" -#: judge/models/submission.py:202 +#: judge/models/submission.py:200 msgid "status flag" msgstr "" -#: judge/models/submission.py:206 +#: judge/models/submission.py:204 msgid "points possible" msgstr "" -#: judge/models/submission.py:207 +#: judge/models/submission.py:205 msgid "batch number" msgstr "" -#: judge/models/submission.py:208 +#: judge/models/submission.py:206 msgid "judging feedback" msgstr "" -#: judge/models/submission.py:209 +#: judge/models/submission.py:207 msgid "extended judging feedback" msgstr "" -#: judge/models/submission.py:210 +#: judge/models/submission.py:208 msgid "program output" msgstr "" -#: judge/models/submission.py:218 +#: judge/models/submission.py:216 msgid "submission test case" msgstr "" -#: judge/models/submission.py:219 +#: judge/models/submission.py:217 msgid "submission test cases" msgstr "" @@ -2237,23 +2127,12 @@ msgstr "" msgid "message time" msgstr "" -#: judge/pdf_problems.py:147 judge/pdf_problems.py:199 -#: judge/pdf_problems.py:259 +#: judge/pdf_problems.py:134 judge/pdf_problems.py:186 +#: judge/pdf_problems.py:246 msgid "Page [page] of [topage]" msgstr "" -#: judge/pdf_problems.py:280 -#, python-format -msgid "Page %s of %s" -msgstr "" - -#: judge/tasks/contest.py:19 -#, fuzzy -#| msgid "Recalculate scores" -msgid "Recalculating contest scores" -msgstr "Пересчитать баллы" - -#: judge/tasks/contest.py:40 +#: judge/tasks/moss.py:25 msgid "Running MOSS" msgstr "" @@ -2265,60 +2144,60 @@ msgstr "" msgid "Recalculating user points" msgstr "" -#: judge/utils/problem_data.py:70 +#: judge/utils/problem_data.py:68 msgid "Empty batches not allowed." msgstr "" -#: judge/utils/problem_data.py:78 judge/utils/problem_data.py:99 +#: judge/utils/problem_data.py:76 judge/utils/problem_data.py:97 msgid "How did you corrupt the custom checker path?" msgstr "" -#: judge/utils/problem_data.py:120 +#: judge/utils/problem_data.py:118 #, python-format msgid "Points must be defined for non-batch case #%d." msgstr "" -#: judge/utils/problem_data.py:125 +#: judge/utils/problem_data.py:123 #, python-format msgid "Input file for case %d does not exist: %s" msgstr "" -#: judge/utils/problem_data.py:128 +#: judge/utils/problem_data.py:126 #, python-format msgid "Output file for case %d does not exist: %s" msgstr "" -#: judge/utils/problem_data.py:153 +#: judge/utils/problem_data.py:151 #, python-format msgid "Batch start case #%d requires points." msgstr "" -#: judge/utils/problem_data.py:174 +#: judge/utils/problem_data.py:172 #, python-format msgid "Attempt to end batch outside of one in case #%d" msgstr "" -#: judge/utils/problem_data.py:192 +#: judge/utils/problem_data.py:190 msgid "How did you corrupt the zip path?" msgstr "" -#: judge/utils/problem_data.py:198 +#: judge/utils/problem_data.py:196 msgid "How did you corrupt the generator path?" msgstr "" -#: judge/utils/problems.py:80 +#: judge/utils/problems.py:78 msgid "Wrong" msgstr "" -#: judge/utils/problems.py:82 +#: judge/utils/problems.py:80 msgid "Timeout" msgstr "" -#: judge/utils/problems.py:83 +#: judge/utils/problems.py:81 msgid "Error" msgstr "" -#: judge/utils/problems.py:94 +#: judge/utils/problems.py:92 msgid "Can't pass both queryset and keyword filters" msgstr "" @@ -2367,8 +2246,7 @@ msgctxt "hours and minutes" msgid "%h:%m" msgstr "%h:%m" -#: judge/views/about.py:7 templates/organization/home.html:112 -#: templates/user/user-about.html:83 templates/user/user-tabs.html:4 +#: judge/views/about.py:7 templates/user/user-about.html:33 msgid "About" msgstr "О нас" @@ -2376,166 +2254,157 @@ msgstr "О нас" msgid "Custom Checker Sample" msgstr "" -#: judge/views/blog.py:45 +#: judge/views/blog.py:38 #, python-format msgid "Page %d of Posts" msgstr "" -#: judge/views/comment.py:28 +#: judge/views/comment.py:27 msgid "Messing around, are we?" msgstr "" -#: judge/views/comment.py:37 +#: judge/views/comment.py:36 msgid "You must solve at least one problem before you can vote." msgstr "" -#: judge/views/comment.py:64 +#: judge/views/comment.py:63 msgid "You already voted." msgstr "" -#: judge/views/comment.py:126 judge/views/organization.py:344 +#: judge/views/comment.py:120 judge/views/organization.py:299 msgid "Edited from site" msgstr "" -#: judge/views/comment.py:147 +#: judge/views/comment.py:141 msgid "Editing comment" msgstr "" -#: judge/views/contests.py:57 judge/views/contests.py:247 -#: judge/views/contests.py:250 judge/views/contests.py:424 +#: judge/views/contests.py:55 judge/views/contests.py:215 +#: judge/views/contests.py:218 judge/views/contests.py:389 msgid "No such contest" msgstr "" -#: judge/views/contests.py:58 judge/views/contests.py:248 +#: judge/views/contests.py:56 judge/views/contests.py:216 #, python-format msgid "Could not find a contest with the key \"%s\"." msgstr "" -#: judge/views/contests.py:71 +#: judge/views/contests.py:81 msgid "Contests" msgstr "" -#: judge/views/contests.py:251 +#: judge/views/contests.py:219 msgid "Could not find such contest." msgstr "" -#: judge/views/contests.py:254 +#: judge/views/contests.py:222 #, python-format msgid "Access to contest \"%s\" denied" msgstr "" -#: judge/views/contests.py:278 +#: judge/views/contests.py:246 msgid "Clone Contest" msgstr "" -#: judge/views/contests.py:343 +#: judge/views/contests.py:309 msgid "Contest not ongoing" msgstr "" -#: judge/views/contests.py:344 +#: judge/views/contests.py:310 #, python-format msgid "\"%s\" is not currently ongoing." msgstr "" -#: judge/views/contests.py:348 +#: judge/views/contests.py:314 msgid "Already in contest" msgstr "" -#: judge/views/contests.py:349 +#: judge/views/contests.py:315 #, python-format msgid "You are already in a contest: \"%s\"." msgstr "" -#: judge/views/contests.py:352 +#: judge/views/contests.py:318 msgid "Banned from joining" msgstr "" -#: judge/views/contests.py:353 +#: judge/views/contests.py:319 msgid "" "You have been declared persona non grata for this contest. You are " "permanently barred from joining this contest." msgstr "" -#: judge/views/contests.py:414 +#: judge/views/contests.py:379 #, python-format msgid "Enter access code for \"%s\"" msgstr "" -#: judge/views/contests.py:425 +#: judge/views/contests.py:390 #, python-format msgid "You are not in contest \"%s\"." msgstr "" -#: judge/views/contests.py:444 +#: judge/views/contests.py:409 msgid "ContestCalendar requires integer year and month" msgstr "" -#: judge/views/contests.py:484 +#: judge/views/contests.py:449 #, python-format msgid "Contests in %(month)s" msgstr "" -#: judge/views/contests.py:484 +#: judge/views/contests.py:449 msgid "F Y" msgstr "" -#: judge/views/contests.py:532 +#: judge/views/contests.py:496 #, fuzzy, python-format #| msgid "Statistics" msgid "%s Statistics" msgstr "Статистика" -#: judge/views/contests.py:717 +#: judge/views/contests.py:601 +msgid "???" +msgstr "" + +#: judge/views/contests.py:664 #, python-format msgid "%s Rankings" msgstr "" -#: judge/views/contests.py:725 -msgid "???" -msgstr "" - -#: judge/views/contests.py:741 +#: judge/views/contests.py:680 #, python-format msgid "Your participation in %s" msgstr "" -#: judge/views/contests.py:742 +#: judge/views/contests.py:681 #, python-format msgid "%s's participation in %s" msgstr "" -#: judge/views/contests.py:749 +#: judge/views/contests.py:685 msgid "Live" msgstr "Онлайн" -#: judge/views/contests.py:761 templates/contest/contest-tabs.html:13 +#: judge/views/contests.py:697 msgid "Participation" msgstr "" -#: judge/views/contests.py:808 +#: judge/views/contests.py:743 #, python-format msgid "%s MOSS Results" msgstr "" -#: judge/views/contests.py:835 +#: judge/views/contests.py:770 #, python-format msgid "Running MOSS for %s..." msgstr "" -#: judge/views/contests.py:858 +#: judge/views/contests.py:793 #, python-format msgid "Contest tag: %s" msgstr "" -#: judge/views/contests.py:868 judge/views/ticket.py:57 -msgid "Issue description" -msgstr "" - -#: judge/views/contests.py:911 -#, python-format -msgid "New clarification for %s" -msgstr "" - #: judge/views/error.py:14 msgid "404 error" msgstr "" @@ -2556,83 +2425,76 @@ msgid "corrupt page %s" msgstr "" #: judge/views/language.py:12 templates/status/judge-status-table.html:9 -#: templates/status/status-tabs.html:5 msgid "Runtimes" msgstr "" -#: judge/views/notification.py:40 -#, python-format -msgid "Notifications (%d unseen)" -msgstr "" - -#: judge/views/organization.py:59 judge/views/organization.py:62 +#: judge/views/organization.py:44 judge/views/organization.py:47 msgid "No such organization" msgstr "" -#: judge/views/organization.py:60 +#: judge/views/organization.py:45 #, python-format msgid "Could not find an organization with the key \"%s\"." msgstr "" -#: judge/views/organization.py:63 +#: judge/views/organization.py:48 msgid "Could not find such organization." msgstr "" -#: judge/views/organization.py:79 judge/views/register.py:34 -#: templates/organization/list.html:32 templates/user/import/table_csv.html:9 -#: templates/user/user-list-tabs.html:6 +#: judge/views/organization.py:72 judge/views/register.py:34 +#: templates/organization/list.html:15 msgid "Organizations" msgstr "" -#: judge/views/organization.py:130 +#: judge/views/organization.py:93 #, python-format msgid "%s Members" msgstr "" -#: judge/views/organization.py:159 judge/views/organization.py:162 -#: judge/views/organization.py:167 +#: judge/views/organization.py:118 judge/views/organization.py:121 +#: judge/views/organization.py:126 msgid "Joining organization" msgstr "" -#: judge/views/organization.py:159 +#: judge/views/organization.py:118 msgid "You are already in the organization." msgstr "" -#: judge/views/organization.py:162 +#: judge/views/organization.py:121 msgid "This organization is not open." msgstr "" -#: judge/views/organization.py:179 +#: judge/views/organization.py:138 msgid "Leaving organization" msgstr "" -#: judge/views/organization.py:179 +#: judge/views/organization.py:138 #, python-format msgid "You are not in \"%s\"." msgstr "" -#: judge/views/organization.py:203 +#: judge/views/organization.py:162 #, python-format msgid "Request to join %s" msgstr "" -#: judge/views/organization.py:221 +#: judge/views/organization.py:180 msgid "Join request detail" msgstr "" -#: judge/views/organization.py:254 +#: judge/views/organization.py:209 #, python-format msgid "Managing join requests for %s" msgstr "" -#: judge/views/organization.py:285 +#: judge/views/organization.py:240 #, python-format msgid "" "Your organization can only receive %d more members. You cannot approve %d " "users." msgstr "" -#: judge/views/organization.py:297 +#: judge/views/organization.py:252 #, python-format msgid "Approved %d user." msgid_plural "Approved %d users." @@ -2641,7 +2503,7 @@ msgstr[1] "" msgstr[2] "" msgstr[3] "" -#: judge/views/organization.py:298 +#: judge/views/organization.py:253 #, python-format msgid "Rejected %d user." msgid_plural "Rejected %d users." @@ -2650,32 +2512,32 @@ msgstr[1] "" msgstr[2] "" msgstr[3] "" -#: judge/views/organization.py:328 +#: judge/views/organization.py:283 #, python-format msgid "Editing %s" msgstr "" -#: judge/views/organization.py:352 judge/views/organization.py:360 +#: judge/views/organization.py:307 judge/views/organization.py:315 msgid "Can't edit organization" msgstr "" -#: judge/views/organization.py:353 +#: judge/views/organization.py:308 msgid "You are not allowed to edit this organization." msgstr "" -#: judge/views/organization.py:361 +#: judge/views/organization.py:316 msgid "You are not allowed to kick people from this organization." msgstr "" -#: judge/views/organization.py:366 judge/views/organization.py:370 +#: judge/views/organization.py:321 judge/views/organization.py:325 msgid "Can't kick user" msgstr "" -#: judge/views/organization.py:367 +#: judge/views/organization.py:322 msgid "The user you are trying to kick does not exist!" msgstr "" -#: judge/views/organization.py:371 +#: judge/views/organization.py:326 #, python-format msgid "The user you are trying to kick is not in organization: %s." msgstr "" @@ -2699,36 +2561,35 @@ msgstr "" msgid "Editorial for {0}" msgstr "" -#: judge/views/problem.py:285 templates/contest/contest.html:79 -#: templates/user/user-about.html:28 templates/user/user-tabs.html:5 -#: templates/user/users-table.html:31 +#: judge/views/problem.py:286 templates/contest/contest.html:79 +#: templates/user/users-table.html:23 msgid "Problems" msgstr "Задачи" -#: judge/views/problem.py:585 +#: judge/views/problem.py:547 msgid "Banned from submitting" msgstr "" -#: judge/views/problem.py:586 +#: judge/views/problem.py:548 msgid "" "You have been declared persona non grata for this problem. You are " "permanently barred from submitting this problem." msgstr "" -#: judge/views/problem.py:600 +#: judge/views/problem.py:562 msgid "Too many submissions" msgstr "" -#: judge/views/problem.py:601 +#: judge/views/problem.py:563 msgid "You have exceeded the submission limit for this problem." msgstr "" -#: judge/views/problem.py:661 judge/views/problem.py:664 +#: judge/views/problem.py:633 judge/views/problem.py:636 #, python-format msgid "Submit to %(problem)s" msgstr "" -#: judge/views/problem.py:679 +#: judge/views/problem.py:652 msgid "Clone Problem" msgstr "" @@ -2769,22 +2630,22 @@ msgstr "" msgid "Generated init.yml for %s" msgstr "" -#: judge/views/problem_manage.py:52 judge/views/problem_manage.py:55 +#: judge/views/problem_manage.py:50 judge/views/problem_manage.py:53 #, python-format msgid "Managing submissions for %s" msgstr "" -#: judge/views/problem_manage.py:97 +#: judge/views/problem_manage.py:95 #, python-format msgid "Rejudging selected submissions for %s..." msgstr "" -#: judge/views/problem_manage.py:141 +#: judge/views/problem_manage.py:110 #, python-format msgid "Rescoring all submissions for %s..." msgstr "" -#: judge/views/problem_manage.py:150 +#: judge/views/problem_manage.py:119 #, python-format msgid "Successfully scheduled %d submission for rejudging." msgid_plural "Successfully scheduled %d submissions for rejudging." @@ -2835,24 +2696,24 @@ msgstr "Предпочитаемый язык" msgid "Subscribe to newsletter?" msgstr "" -#: judge/views/register.py:55 +#: judge/views/register.py:45 #, python-format msgid "" "The email address \"%s\" is already taken. Only one registration is allowed " "per address." msgstr "" -#: judge/views/register.py:61 +#: judge/views/register.py:51 msgid "" "Your email provider is not allowed due to history of abuse. Please use a " "reputable email provider." msgstr "" -#: judge/views/register.py:67 judge/views/register.py:105 +#: judge/views/register.py:57 judge/views/register.py:95 msgid "Registration" msgstr "Регистрация" -#: judge/views/register.py:116 +#: judge/views/register.py:106 msgid "Authentication failure" msgstr "Ошибка авторизации" @@ -2868,100 +2729,104 @@ msgstr "Статус" msgid "Version matrix" msgstr "" -#: judge/views/submission.py:84 judge/views/submission.py:91 +#: judge/views/submission.py:83 judge/views/submission.py:90 #, python-format msgid "Submission of %(problem)s by %(user)s" msgstr "" -#: judge/views/submission.py:244 judge/views/submission.py:245 -#: templates/problem/problem.html:167 +#: judge/views/submission.py:227 judge/views/submission.py:228 +#: templates/problem/problem.html:127 msgid "All submissions" msgstr "" -#: judge/views/submission.py:404 +#: judge/views/submission.py:384 msgid "All my submissions" msgstr "" -#: judge/views/submission.py:405 +#: judge/views/submission.py:385 #, python-format msgid "All submissions by %s" msgstr "" -#: judge/views/submission.py:436 +#: judge/views/submission.py:416 #, python-format msgid "All submissions for %s" msgstr "" -#: judge/views/submission.py:455 +#: judge/views/submission.py:435 msgid "Must pass a problem" msgstr "" -#: judge/views/submission.py:501 +#: judge/views/submission.py:481 #, python-format msgid "My submissions for %(problem)s" msgstr "" -#: judge/views/submission.py:502 +#: judge/views/submission.py:482 #, python-format msgid "%(user)s's submissions for %(problem)s" msgstr "" -#: judge/views/submission.py:603 +#: judge/views/submission.py:583 msgid "Must pass a contest" msgstr "" -#: judge/views/submission.py:622 +#: judge/views/submission.py:602 #, python-brace-format msgid "" "{0}'s submissions for {2} in {4}" msgstr "" -#: judge/views/submission.py:629 +#: judge/views/submission.py:609 #, python-brace-format msgid "" "{0}'s submissions for problem {2} in {3}" "" msgstr "" -#: judge/views/ticket.py:50 judge/views/ticket.py:56 +#: judge/views/ticket.py:33 judge/views/ticket.py:39 msgid "Ticket title" msgstr "" -#: judge/views/ticket.py:107 judge/views/ticket.py:110 +#: judge/views/ticket.py:40 +msgid "Issue description" +msgstr "" + +#: judge/views/ticket.py:85 judge/views/ticket.py:88 #, python-format msgid "New ticket for %s" msgstr "" -#: judge/views/ticket.py:170 +#: judge/views/ticket.py:142 #, python-format msgid "%(title)s - Ticket %(id)d" msgstr "" -#: judge/views/ticket.py:279 +#: judge/views/ticket.py:251 #, python-format msgid "Tickets - Page %(number)d of %(total)d" msgstr "" -#: judge/views/ticket.py:328 +#: judge/views/ticket.py:300 #, python-format msgid "New Ticket: %s" msgstr "" -#: judge/views/ticket.py:329 +#: judge/views/ticket.py:301 #, python-format msgid "#%(id)d, assigned to: %(users)s" msgstr "" -#: judge/views/ticket.py:331 +#: judge/views/ticket.py:303 msgid ", " msgstr "" -#: judge/views/ticket.py:331 +#: judge/views/ticket.py:303 msgid "no one" msgstr "" -#: judge/views/ticket.py:351 +#: judge/views/ticket.py:323 #, python-format msgid "New Ticket Message For: %s" msgstr "" @@ -2978,50 +2843,41 @@ msgstr "" msgid "Perform Two Factor Authentication" msgstr "" -#: judge/views/user.py:74 +#: judge/views/user.py:68 msgid "No such user" msgstr "" -#: judge/views/user.py:74 +#: judge/views/user.py:68 #, python-format msgid "No user handle \"%s\"." msgstr "" -#: judge/views/user.py:78 +#: judge/views/user.py:72 msgid "My account" msgstr "" -#: judge/views/user.py:79 +#: judge/views/user.py:73 #, python-format msgid "User %s" msgstr "Пользователь %s" -#: judge/views/user.py:148 -msgid "M j, Y" -msgstr "" - -#: judge/views/user.py:171 +#: judge/views/user.py:136 msgid "M j, Y, G:i" msgstr "" -#: judge/views/user.py:290 +#: judge/views/user.py:221 msgid "Updated on site" msgstr "" -#: judge/views/user.py:323 templates/admin/auth/user/change_form.html:14 -#: templates/admin/auth/user/change_form.html:17 templates/base.html:238 -#: templates/user/user-tabs.html:10 +#: judge/views/user.py:254 templates/admin/auth/user/change_form.html:14 +#: templates/admin/auth/user/change_form.html:17 templates/base.html:224 msgid "Edit profile" msgstr "" -#: judge/views/user.py:332 templates/user/user-list-tabs.html:4 +#: judge/views/user.py:263 msgid "Leaderboard" msgstr "" -#: judge/views/user.py:407 -msgid "Import Users" -msgstr "" - #: judge/views/widgets.py:48 judge/views/widgets.py:58 #, python-format msgid "Invalid upstream data: %s" @@ -3059,7 +2915,7 @@ msgid "View Submissions" msgstr "" #: templates/admin/judge/problem/change_form.html:17 -#: templates/user/user-base.html:112 +#: templates/user/user-base.html:61 msgid "View submissions" msgstr "" @@ -3074,148 +2930,90 @@ msgstr "" msgid "Rejudge" msgstr "" -#: templates/base.html:230 -#, python-format -msgid "Hello, %(username)s." -msgstr "" - -#: templates/base.html:236 templates/comments/list.html:89 -#: templates/contest/contest-list-tabs.html:24 -#: templates/contest/ranking-table.html:53 -#: templates/problem/problem-list-tabs.html:6 +#: templates/base.html:222 templates/comments/list.html:89 +#: templates/contest/ranking-table.html:39 #: templates/submission/info-base.html:12 -#: templates/submission/submission-list-tabs.html:15 msgid "Admin" msgstr "" -#: templates/base.html:245 +#: templates/base.html:231 msgid "Log out" msgstr "Bыйти" -#: templates/base.html:254 +#: templates/base.html:240 #: templates/registration/password_reset_complete.html:4 msgid "Log in" msgstr "Войти" -#: templates/base.html:255 templates/registration/registration_form.html:177 +#: templates/base.html:241 templates/registration/registration_form.html:177 msgid "or" msgstr "" -#: templates/base.html:256 +#: templates/base.html:242 msgid "Sign up" msgstr "" -#: templates/base.html:271 +#: templates/base.html:254 msgid "spectating" msgstr "" -#: templates/base.html:284 +#: templates/base.html:267 msgid "This site works best with JavaScript enabled." msgstr "" -#: templates/blog/blog.html:13 templates/comments/list.html:68 -#: templates/comments/list.html:83 templates/contest/contest-tabs.html:23 -#: templates/contest/tag-title.html:9 templates/flatpages/admin_link.html:3 -#: templates/license.html:10 templates/problem/editorial.html:14 +#: templates/blog/content.html:13 templates/comments/list.html:68 +#: templates/comments/list.html:83 templates/contest/tag-title.html:9 +#: templates/flatpages/admin_link.html:3 templates/license.html:10 +#: templates/problem/editorial.html:14 msgid "Edit" msgstr "Редактировать" -#: templates/blog/blog.html:26 -#, python-format -msgid "" -"\n" -" posted on %(time)s\n" -" " -msgstr "" - -#: templates/blog/content.html:10 -#, fuzzy, python-brace-format -#| msgid "posted time" -msgid "posted on {time}" -msgstr "время публикации" - -#: templates/blog/dashboard.html:21 -#, python-format -msgid "" -"\n" -" on %(time)s\n" -" " -msgstr "" - -#: templates/blog/list.html:93 +#: templates/blog/list.html:85 msgid "Blog" msgstr "Блог" -#: templates/blog/list.html:95 +#: templates/blog/list.html:87 msgid "Events" msgstr "События" -#: templates/blog/list.html:100 +#: templates/blog/list.html:92 msgid "News" msgstr "Новости" -#: templates/blog/list.html:115 templates/problem/list.html:347 -#: templates/problem/problem.html:361 +#: templates/blog/list.html:130 templates/problem/problem.html:310 msgid "Clarifications" msgstr "" -#: templates/blog/list.html:121 -msgid "Add" -msgstr "" - -#: templates/blog/list.html:140 templates/problem/list.html:369 -#: templates/problem/problem.html:372 +#: templates/blog/list.html:146 templates/problem/problem.html:321 msgid "No clarifications have been made at this time." msgstr "" -#: templates/blog/list.html:148 +#: templates/blog/list.html:154 msgid "Ongoing contests" msgstr "Текущие соревнования" -#: templates/blog/list.html:166 +#: templates/blog/list.html:172 msgid "Upcoming contests" msgstr "Предстоящие соревнования" -#: templates/blog/list.html:184 -msgid "My open tickets" -msgstr "" - -#: templates/blog/list.html:206 -msgid "New tickets" -msgstr "" - -#: templates/blog/list.html:227 -msgid "New problems" -msgstr "" - -#: templates/blog/list.html:244 +#: templates/blog/list.html:189 msgid "Comment stream" msgstr "" -#: templates/chat/chat.html:305 -msgid "Chat" +#: templates/blog/list.html:208 +msgid "New problems" msgstr "" -#: templates/chat/chat.html:307 templates/chat/chat.html:314 -#, fuzzy -#| msgid "Online Judge" -msgid "Online Users" -msgstr "Онлайн Judge" - -#: templates/chat/chat.html:315 -msgid "Refresh" +#: templates/blog/list.html:225 +msgid "My open tickets" msgstr "" -#: templates/chat/chat.html:333 -msgid "Emoji" +#: templates/blog/list.html:246 +msgid "New tickets" msgstr "" -#: templates/chat/chat.html:334 -msgid "Enter your message" -msgstr "" - -#: templates/chat/message.html:20 -msgid "Delete" +#: templates/chat/chat.html:167 +msgid "Your message" msgstr "" #: templates/comments/list.html:2 @@ -3226,23 +3024,11 @@ msgstr "" msgid "Please login to vote" msgstr "" -#: templates/comments/list.html:40 -#, fuzzy, python-brace-format -#| msgid "posted time" -msgid "commented on {time}" -msgstr "время публикации" - -#: templates/comments/list.html:49 -#, fuzzy, python-format -#| msgid "edited" -msgid "edit %(edits)s" -msgstr "отредактирован" - -#: templates/comments/list.html:51 templates/comments/media-js.html:92 +#: templates/comments/list.html:51 templates/comments/media-js.html:77 msgid "edited" msgstr "отредактирован" -#: templates/comments/list.html:60 templates/notification/list.html:14 +#: templates/comments/list.html:60 msgid "Link" msgstr "Ссылка" @@ -3250,54 +3036,36 @@ msgstr "Ссылка" msgid "Reply" msgstr "Ответить" -#: templates/comments/list.html:86 templates/contest/list.html:91 -#: templates/contest/list.html:95 templates/contest/list.html:280 +#: templates/comments/list.html:86 msgid "Hide" msgstr "" -#: templates/comments/list.html:101 -#, python-format -msgid "" -"\n" -" This comment is hidden due " -"to too much negative feedback.\n" -" Click here to view it.\n" -" " -msgstr "" - -#: templates/comments/list.html:121 +#: templates/comments/list.html:120 msgid "There are no comments at the moment." msgstr "Еще нет ни одного комментария." -#: templates/comments/list.html:127 +#: templates/comments/list.html:126 msgid "New comment" msgstr "Добавить комментарий" -#: templates/comments/list.html:141 +#: templates/comments/list.html:140 msgid "Invalid comment body." msgstr "" -#: templates/comments/list.html:149 +#: templates/comments/list.html:148 msgid "Post!" msgstr "" -#: templates/comments/list.html:157 +#: templates/comments/list.html:156 msgid "Comments are disabled on this page." msgstr "" -#: templates/comments/media-js.html:38 -#, fuzzy -#| msgid "no comments" -msgid "Replying to comment" -msgstr "без комментариев" - -#: templates/comments/media-js.html:87 +#: templates/comments/media-js.html:72 #, python-brace-format msgid "edit {edits}" msgstr "" -#: templates/comments/media-js.html:90 +#: templates/comments/media-js.html:75 msgid "original" msgstr "" @@ -3341,11 +3109,6 @@ msgstr "Пятница" msgid "Saturday" msgstr "Суббота" -#: templates/contest/clarification.html:52 templates/organization/new.html:10 -#: templates/ticket/new.html:38 -msgid "Create" -msgstr "Создать" - #: templates/contest/clone.html:37 msgid "Enter a new key for the cloned contest:" msgstr "" @@ -3366,177 +3129,97 @@ msgstr "Сегодня" msgid "Next" msgstr "Следующая" -#: templates/contest/contest-list-tabs.html:21 -#: templates/problem/problem-list-tabs.html:5 -msgid "List" -msgstr "" - -#: templates/contest/contest-list-tabs.html:22 -msgid "Calendar" -msgstr "" - -#: templates/contest/contest-tabs.html:4 templates/organization/home.html:105 -msgid "Info" -msgstr "" - -#: templates/contest/contest-tabs.html:6 templates/stats/base.html:9 -#: templates/submission/list.html:339 -msgid "Statistics" -msgstr "Статистика" - -#: templates/contest/contest-tabs.html:11 -msgid "Rankings" -msgstr "Рейтинг" - -#: templates/contest/contest-tabs.html:16 -#, fuzzy -#| msgid "Rankings" -msgid "Hidden Rankings" -msgstr "Рейтинг" - -#: templates/contest/contest-tabs.html:21 -msgid "MOSS" -msgstr "" - -#: templates/contest/contest-tabs.html:26 -msgid "Clone" -msgstr "" - -#: templates/contest/contest-tabs.html:38 -#: templates/contest/contest-tabs.html:58 +#: templates/contest/contest-tabs.html:37 msgid "Leave contest" msgstr "Покинуть соревнование" -#: templates/contest/contest-tabs.html:45 templates/contest/list.html:388 +#: templates/contest/contest-tabs.html:44 templates/contest/list.html:293 msgid "Virtual join" msgstr "Виртуальное участие" -#: templates/contest/contest-tabs.html:56 -msgid "Stop spectating" -msgstr "" - -#: templates/contest/contest-tabs.html:65 +#: templates/contest/contest-tabs.html:64 msgid "Spectate contest" msgstr "" -#: templates/contest/contest-tabs.html:72 +#: templates/contest/contest-tabs.html:70 +#: templates/contest/contest-tabs.html:76 msgid "Join contest" msgstr "Присоединиться к соревнованию" -#: templates/contest/contest-tabs.html:81 +#: templates/contest/contest-tabs.html:85 msgid "Login to participate" msgstr "" -#: templates/contest/contest.html:37 -msgid "Participating virtually." -msgstr "" - -#: templates/contest/contest.html:43 -msgid "Contest is over." -msgstr "Соревнование завершено." - #: templates/contest/contest.html:59 templates/contest/contest.html:63 msgid "F j, Y, G:i T" msgstr "" -#: templates/contest/contest.html:59 -#, python-format -msgid "" -"%(time_limit)s window between %(start_time)s and " -"%(end_time)s" -msgstr "" - -#: templates/contest/contest.html:63 -#, python-format -msgid "%(length)s long starting on %(start_time)s" -msgstr "" - #: templates/contest/contest.html:85 msgid "AC Rate" msgstr "" -#: templates/contest/contest.html:86 templates/contest/list.html:237 -#: templates/contest/list.html:289 templates/contest/list.html:366 -#: templates/problem/list.html:223 templates/problem/list.html:254 +#: templates/contest/contest.html:86 templates/contest/list.html:153 +#: templates/contest/list.html:195 templates/contest/list.html:271 +#: templates/problem/list.html:212 templates/problem/list.html:238 msgid "Users" msgstr "Пользователи" -#: templates/contest/contest.html:111 templates/problem/list.html:330 +#: templates/contest/contest.html:111 msgid "Editorial" msgstr "" -#: templates/contest/list.html:83 templates/contest/media-js.html:9 +#: templates/contest/list.html:31 templates/contest/media-js.html:9 msgid "Are you sure you want to join?" msgstr "" -#: templates/contest/list.html:84 +#: templates/contest/list.html:32 msgid "" "Joining a contest for the first time starts your timer, after which it " "becomes unstoppable." msgstr "" -#: templates/contest/list.html:92 templates/contest/list.html:278 -msgid "Show" -msgstr "" - -#: templates/contest/list.html:102 templates/problem/list.html:68 -#, fuzzy -#| msgid "Organization" -msgid "Organizations..." -msgstr "Организация" - -#: templates/contest/list.html:135 +#: templates/contest/list.html:65 msgid "hidden" msgstr "" -#: templates/contest/list.html:140 +#: templates/contest/list.html:70 msgid "private" msgstr "" -#: templates/contest/list.html:154 +#: templates/contest/list.html:84 msgid "rated" msgstr "" -#: templates/contest/list.html:202 +#: templates/contest/list.html:132 msgid "Spectate" msgstr "" -#: templates/contest/list.html:208 +#: templates/contest/list.html:138 msgid "Join" msgstr "Присоединиться" -#: templates/contest/list.html:220 -#, fuzzy -#| msgid "Leave contest" -msgid "Search contests..." -msgstr "Покинуть соревнование" - -#: templates/contest/list.html:229 -msgid "Search" -msgstr "" - -#: templates/contest/list.html:232 +#: templates/contest/list.html:148 msgid "Active Contests" msgstr "" -#: templates/contest/list.html:236 templates/contest/list.html:288 -#: templates/contest/list.html:327 templates/contest/list.html:365 +#: templates/contest/list.html:152 templates/contest/list.html:194 +#: templates/contest/list.html:232 templates/contest/list.html:270 msgid "Contest" msgstr "Соревнование" -#: templates/contest/list.html:275 +#: templates/contest/list.html:190 msgid "Ongoing Contests" msgstr "Текущие Соревнования" -#: templates/contest/list.html:322 +#: templates/contest/list.html:227 msgid "Upcoming Contests" msgstr "Предстоящие соревнования" -#: templates/contest/list.html:350 +#: templates/contest/list.html:255 msgid "There are no scheduled contests at this time." msgstr "" -#: templates/contest/list.html:356 +#: templates/contest/list.html:261 msgid "Past Contests" msgstr "Прошедшие соревнования" @@ -3588,81 +3271,53 @@ msgstr "" msgid "Only the following organizations may access this contest:" msgstr "" -#: templates/contest/ranking-table.html:9 templates/problem/search-form.html:35 +#: templates/contest/ranking-table.html:7 msgid "Organization" msgstr "Организация" -#: templates/contest/ranking-table.html:10 templates/user/users-table.html:13 -#, fuzzy -#| msgid "Name" -msgid "Full Name" -msgstr "Имя" - -#: templates/contest/ranking-table.html:44 +#: templates/contest/ranking-table.html:30 msgid "Un-Disqualify" msgstr "" -#: templates/contest/ranking-table.html:47 +#: templates/contest/ranking-table.html:33 msgid "Disqualify" msgstr "" -#: templates/contest/ranking.html:187 +#: templates/contest/ranking.html:173 #, fuzzy #| msgid "Are you sure you want to leave?" msgid "Are you sure you want to disqualify this participation?" msgstr "Вы уверены, что вы хотите выйти?" -#: templates/contest/ranking.html:192 +#: templates/contest/ranking.html:178 #, fuzzy #| msgid "Are you sure you want to leave?" msgid "Are you sure you want to un-disqualify this participation?" msgstr "Вы уверены, что вы хотите выйти?" -#: templates/contest/ranking.html:463 +#: templates/contest/ranking.html:252 msgid "View user participation" msgstr "" -#: templates/contest/ranking.html:467 +#: templates/contest/ranking.html:256 msgid "Show organizations" msgstr "" -#: templates/contest/ranking.html:471 -msgid "Show full name" -msgstr "" - -#: templates/contest/ranking.html:474 -msgid "Show friends only" -msgstr "" - -#: templates/contest/ranking.html:477 -msgid "Total score only" -msgstr "" - -#: templates/contest/ranking.html:479 -#, fuzzy -#| msgid "contest participation" -msgid "Show virtual participation" -msgstr "участие в соревновании" - -#: templates/contest/stats.html:51 +#: templates/contest/stats.html:38 msgid "Problem Status Distribution" msgstr "" -#: templates/contest/stats.html:56 +#: templates/contest/stats.html:43 #, fuzzy #| msgid "Problem name" msgid "Problem AC Rate" msgstr "Название задачи" -#: templates/contest/stats.html:62 -msgid "Problem Point Distribution" -msgstr "" - -#: templates/contest/stats.html:76 templates/stats/language.html:16 +#: templates/contest/stats.html:48 templates/stats/language.html:16 msgid "Submissions by Language" msgstr "" -#: templates/contest/stats.html:82 templates/stats/language.html:26 +#: templates/contest/stats.html:54 templates/stats/language.html:26 msgid "Language AC Rate" msgstr "" @@ -3671,7 +3326,6 @@ msgid "Source:" msgstr "" #: templates/newsletter/common.html:6 -#: templates/newsletter/newsletter_list.html:15 #: templates/newsletter/subscription_unsubscribe_activated.html:3 #: templates/newsletter/subscription_unsubscribe_activated.html:6 #: templates/newsletter/subscription_update_activated.html:3 @@ -3679,29 +3333,6 @@ msgstr "" msgid "Newsletter" msgstr "Рассылка" -#: templates/newsletter/newsletter_list.html:2 -#: templates/newsletter/newsletter_list.html:3 -#, fuzzy -#| msgid "Newsletter" -msgid "Newsletter list" -msgstr "Рассылка" - -#: templates/newsletter/newsletter_list.html:6 -msgid "Subscribe to get the latest emails about upcoming contests and events." -msgstr "" - -#: templates/newsletter/newsletter_list.html:16 -#, fuzzy -#| msgid "Unsubscribe" -msgid "Subscribe" -msgstr "Отписаться" - -#: templates/newsletter/newsletter_list.html:30 -#, fuzzy -#| msgid "description" -msgid "Update subscriptions" -msgstr "описание" - #: templates/newsletter/subscription_unsubscribe_activated.html:3 #: templates/newsletter/subscription_unsubscribe_activated.html:6 #: templates/newsletter/subscription_update_activated.html:3 @@ -3763,113 +3394,64 @@ msgid "" "follow in order to update your subscription." msgstr "" -#: templates/notification/list.html:7 -msgid "You have no notifications" -msgstr "" - -#: templates/notification/list.html:13 -#, fuzzy -#| msgid "activate" -msgid "Activity" -msgstr "активировать" - #: templates/organization/edit.html:46 #: templates/organization/requests/pending.html:34 #: templates/ticket/edit-notes.html:4 msgid "Update" msgstr "Обновить" -#: templates/organization/home.html:41 +#: templates/organization/home.html:7 msgid "Are you sure you want to leave this organization?" msgstr "" -#: templates/organization/home.html:43 +#: templates/organization/home.html:9 msgid "You will have to rejoin to show up on the organization leaderboard." msgstr "" -#: templates/organization/home.html:45 +#: templates/organization/home.html:11 msgid "You will have to request membership in order to join again." msgstr "" -#: templates/organization/home.html:88 -msgid "Join organization" -msgstr "Присоединиться к организации" - -#: templates/organization/home.html:92 -msgid "Request membership" -msgstr "" - -#: templates/organization/home.html:122 -#, fuzzy -#| msgid "Organization" -msgid "Organization news" -msgstr "Организация" - -#: templates/organization/home.html:128 -#, fuzzy -#| msgid "There are no comments at the moment." -msgid "There is no news at this time." -msgstr "Еще нет ни одного комментария." - -#: templates/organization/home.html:137 -#, fuzzy -#| msgid "Contest" -msgid "Controls" -msgstr "Соревнование" - -#: templates/organization/home.html:142 -msgid "Edit organization" -msgstr "Редактировать организацию" - -#: templates/organization/home.html:148 -msgid "View requests" -msgstr "Просмотр запросов" - -#: templates/organization/home.html:161 -msgid "Admin organization" -msgstr "" - -#: templates/organization/home.html:167 -msgid "View members" -msgstr "" - -#: templates/organization/home.html:174 +#: templates/organization/home.html:24 msgid "Leave organization" msgstr "Покинуть организацию" -#: templates/organization/home.html:183 -#, fuzzy -#| msgid "Leave contest" -msgid "New private contests" -msgstr "Покинуть соревнование" +#: templates/organization/home.html:29 +msgid "Join organization" +msgstr "Присоединиться к организации" -#: templates/organization/home.html:193 templates/organization/home.html:208 -#, fuzzy -#| msgid "View as PDF" -msgid "View all" -msgstr "Просмотр в формате PDF" +#: templates/organization/home.html:33 +msgid "Request membership" +msgstr "" -#: templates/organization/home.html:199 -#, fuzzy -#| msgid "Edit problem" -msgid "New private problems" -msgstr "Редактировать задачу" +#: templates/organization/home.html:39 +msgid "Edit organization" +msgstr "Редактировать организацию" -#: templates/organization/list.html:40 -#, fuzzy -#| msgid "organizations" -msgid "Show my organizations only" -msgstr "организации" +#: templates/organization/home.html:43 +msgid "View requests" +msgstr "Просмотр запросов" -#: templates/organization/list.html:47 templates/status/language-list.html:34 -#: templates/user/import/table_csv.html:6 +#: templates/organization/home.html:50 +msgid "Admin organization" +msgstr "" + +#: templates/organization/home.html:55 +msgid "View members" +msgstr "" + +#: templates/organization/list.html:23 templates/status/language-list.html:34 msgid "Name" msgstr "Имя" -#: templates/organization/list.html:48 +#: templates/organization/list.html:24 msgid "Members" msgstr "" +#: templates/organization/new.html:10 templates/ticket/new.html:38 +msgid "Create" +msgstr "Создать" + #: templates/organization/requests/detail.html:13 msgid "User:" msgstr "Пользователь:" @@ -3902,7 +3484,7 @@ msgid "There are no requests to approve." msgstr "" #: templates/organization/requests/pending.html:17 -#: templates/problem/data.html:432 +#: templates/problem/data.html:452 msgid "Delete?" msgstr "" @@ -3938,37 +3520,37 @@ msgstr "" msgid "Enter a new code for the cloned problem:" msgstr "" -#: templates/problem/data.html:119 +#: templates/problem/data.html:108 #, fuzzy #| msgid "Information" msgid "Instruction" msgstr "Информация" -#: templates/problem/data.html:390 +#: templates/problem/data.html:410 msgid "View YAML" msgstr "" -#: templates/problem/data.html:421 templates/problem/data.html:472 +#: templates/problem/data.html:441 templates/problem/data.html:491 msgid "Apply!" msgstr "" -#: templates/problem/data.html:426 +#: templates/problem/data.html:446 msgid "Type" msgstr "Тип" -#: templates/problem/data.html:427 +#: templates/problem/data.html:447 msgid "Input file" msgstr "" -#: templates/problem/data.html:428 +#: templates/problem/data.html:448 msgid "Output file" msgstr "" -#: templates/problem/data.html:430 +#: templates/problem/data.html:450 msgid "Pretest?" msgstr "" -#: templates/problem/data.html:473 +#: templates/problem/data.html:492 msgid "Add new case" msgstr "Добавить новый пример" @@ -3980,32 +3562,28 @@ msgid "" "problem yourself is a bannable offence." msgstr "" -#: templates/problem/list.html:66 +#: templates/problem/list.html:62 msgid "Filter by type..." msgstr "" -#: templates/problem/list.html:193 +#: templates/problem/list.html:185 msgid "Hot problems" msgstr "" -#: templates/problem/list.html:218 templates/problem/list.html:240 -#: templates/problem/search-form.html:45 templates/user/user-problems.html:57 +#: templates/problem/list.html:207 templates/problem/list.html:224 +#: templates/problem/search-form.html:30 templates/user/user-problems.html:57 msgid "Category" msgstr "Категория" -#: templates/problem/list.html:220 templates/problem/list.html:244 +#: templates/problem/list.html:209 templates/problem/list.html:228 msgid "Types" msgstr "Типы" -#: templates/problem/list.html:251 +#: templates/problem/list.html:235 #, python-format msgid "AC %%" msgstr "" -#: templates/problem/list.html:342 -msgid "Add clarifications" -msgstr "" - #: templates/problem/manage_submission.html:55 msgid "Leave empty to not filter by language" msgstr "" @@ -4014,214 +3592,152 @@ msgstr "" msgid "Leave empty to not filter by result" msgstr "" -#: templates/problem/manage_submission.html:80 +#: templates/problem/manage_submission.html:79 msgid "Need valid values for both start and end IDs." msgstr "" -#: templates/problem/manage_submission.html:83 +#: templates/problem/manage_submission.html:82 msgid "End ID must be after start ID." msgstr "" +#: templates/problem/manage_submission.html:90 +#, python-brace-format +msgid "" +"You are about to rejudge {count} submissions. Are you sure you want to do " +"this?" +msgstr "" + #: templates/problem/manage_submission.html:96 -#, python-brace-format msgid "" -"You are about to {action} {count} submissions. Are you sure you want to do " -"this?" +"You are about to rejudge a few submissions. Are you sure you want to do this?" msgstr "" -#: templates/problem/manage_submission.html:103 -#, python-brace-format -msgid "" -"You are about to {action} a few submissions. Are you sure you want to do " -"this?" +#: templates/problem/manage_submission.html:115 +msgid "Rejudge Submissions" msgstr "" -#: templates/problem/manage_submission.html:127 -#: templates/submission/list.html:309 -msgid "Filter submissions" -msgstr "" - -#: templates/problem/manage_submission.html:132 +#: templates/problem/manage_submission.html:120 msgid "Filter by ID:" msgstr "" -#: templates/problem/manage_submission.html:135 +#: templates/problem/manage_submission.html:123 msgid "Starting ID:" msgstr "" -#: templates/problem/manage_submission.html:139 +#: templates/problem/manage_submission.html:127 msgid "Ending ID:" msgstr "" -#: templates/problem/manage_submission.html:143 +#: templates/problem/manage_submission.html:131 msgid "This range includes both endpoints." msgstr "" -#: templates/problem/manage_submission.html:146 +#: templates/problem/manage_submission.html:134 msgid "Filter by language:" msgstr "" -#: templates/problem/manage_submission.html:154 +#: templates/problem/manage_submission.html:142 msgid "Filter by result:" msgstr "" -#: templates/problem/manage_submission.html:164 -msgid "Action" -msgstr "" - -#: templates/problem/manage_submission.html:166 +#: templates/problem/manage_submission.html:150 msgid "Rejudge selected submissions" msgstr "" -#: templates/problem/manage_submission.html:171 -#, fuzzy -#| msgid "submission" -msgid "Download selected submissions" -msgstr "посылка" +#: templates/problem/manage_submission.html:157 +msgid "Rescore Everything" +msgstr "" -#: templates/problem/manage_submission.html:177 -#, fuzzy, python-format -#| msgid "Are you sure you want to leave?" -msgid "Are you sure you want to rescore %(count)d submissions?" -msgstr "Вы уверены, что вы хотите выйти?" - -#: templates/problem/manage_submission.html:178 +#: templates/problem/manage_submission.html:163 msgid "Rescore all submissions" msgstr "" -#: templates/problem/problem.html:132 +#: templates/problem/problem.html:91 msgid "View as PDF" msgstr "Просмотр в формате PDF" -#: templates/problem/problem.html:141 templates/problem/problem.html:151 -#: templates/problem/problem.html:156 +#: templates/problem/problem.html:101 templates/problem/problem.html:111 +#: templates/problem/problem.html:116 msgid "Submit solution" msgstr "" -#: templates/problem/problem.html:144 -#, python-format -msgid "%(counter)s submission left" -msgid_plural "%(counter)s submissions left" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" -msgstr[3] "" - -#: templates/problem/problem.html:152 +#: templates/problem/problem.html:112 msgid "0 submissions left" msgstr "" -#: templates/problem/problem.html:164 +#: templates/problem/problem.html:124 msgid "My submissions" msgstr "" -#: templates/problem/problem.html:168 +#: templates/problem/problem.html:128 msgid "Best submissions" msgstr "" -#: templates/problem/problem.html:172 +#: templates/problem/problem.html:132 msgid "Read editorial" msgstr "" -#: templates/problem/problem.html:177 +#: templates/problem/problem.html:137 msgid "Manage tickets" msgstr "" -#: templates/problem/problem.html:181 +#: templates/problem/problem.html:141 msgid "Edit problem" msgstr "Редактировать задачу" -#: templates/problem/problem.html:183 +#: templates/problem/problem.html:143 msgid "Edit test data" msgstr "" -#: templates/problem/problem.html:188 +#: templates/problem/problem.html:148 msgid "My tickets" msgstr "" -#: templates/problem/problem.html:196 +#: templates/problem/problem.html:156 msgid "Manage submissions" msgstr "" -#: templates/problem/problem.html:202 +#: templates/problem/problem.html:162 msgid "Clone problem" msgstr "" -#: templates/problem/problem.html:209 +#: templates/problem/problem.html:169 msgid "Points:" msgstr "" -#: templates/problem/problem.html:212 templates/problem/problem.html:214 +#: templates/problem/problem.html:172 templates/problem/problem.html:174 msgid "(partial)" msgstr "" -#: templates/problem/problem.html:219 +#: templates/problem/problem.html:179 msgid "Time limit:" msgstr "" -#: templates/problem/problem.html:231 +#: templates/problem/problem.html:191 msgid "Memory limit:" msgstr "" -#: templates/problem/problem.html:250 -#, fuzzy -#| msgid "Authors" -msgid "Author:" -msgid_plural "Authors:" -msgstr[0] "Авторы" -msgstr[1] "Авторы" -msgstr[2] "Авторы" -msgstr[3] "Авторы" - -#: templates/problem/problem.html:265 -#, fuzzy -#| msgid "Problem code" -msgid "Problem type" -msgid_plural "Problem types" -msgstr[0] "Исходный код" -msgstr[1] "Исходный код" -msgstr[2] "Исходный код" -msgstr[3] "Исходный код" - -#: templates/problem/problem.html:278 +#: templates/problem/problem.html:238 msgid "Allowed languages" msgstr "" -#: templates/problem/problem.html:286 -#, python-format -msgid "No %(lang)s judge online" -msgstr "" - -#: templates/problem/problem.html:297 -msgid "Judge:" -msgid_plural "Judges:" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" -msgstr[3] "" - -#: templates/problem/problem.html:314 +#: templates/problem/problem.html:274 msgid "none available" msgstr "" -#: templates/problem/problem.html:326 -#, python-format -msgid "This problem has %(length)s clarification(s)" -msgstr "" - -#: templates/problem/problem.html:350 +#: templates/problem/problem.html:299 msgid "Request clarification" msgstr "" -#: templates/problem/problem.html:352 +#: templates/problem/problem.html:301 msgid "Report an issue" msgstr "" -#: templates/problem/raw.html:64 +#: templates/problem/raw.html:62 msgid "Time Limit:" msgstr "" -#: templates/problem/raw.html:73 +#: templates/problem/raw.html:71 msgid "Memory Limit:" msgstr "" @@ -4245,75 +3761,39 @@ msgstr "" msgid "Show problem types" msgstr "" -#: templates/problem/search-form.html:32 -msgid "Show editorial" -msgstr "" - -#: templates/problem/search-form.html:48 templates/problem/search-form.html:50 -#: templates/submission/submission-list-tabs.html:4 +#: templates/problem/search-form.html:33 templates/problem/search-form.html:35 msgid "All" msgstr "Все" -#: templates/problem/search-form.html:62 +#: templates/problem/search-form.html:46 msgid "Problem types" msgstr "" -#: templates/problem/search-form.html:73 +#: templates/problem/search-form.html:57 msgid "Point range" msgstr "" -#: templates/problem/search-form.html:79 templates/submission/list.html:331 +#: templates/problem/search-form.html:63 templates/submission/list.html:331 #: templates/ticket/list.html:248 msgid "Go" msgstr "" -#: templates/problem/search-form.html:80 +#: templates/problem/search-form.html:64 msgid "Random" msgstr "Случайная задача" -#: templates/problem/submit.html:117 -msgid "Your source code must contain at most 65536 characters." -msgstr "" - -#: templates/problem/submit.html:204 -#, python-format -msgid "" -"Warning! Your default language, %(default_language)s, is " -"unavailable for this problem and has been deselected." -msgstr "" - -#: templates/problem/submit.html:215 -#, python-format -msgid "" -"\n" -" You have %(left)s submission left\n" -" " -msgid_plural "" -"\n" -" You have %(left)s submissions left\n" -" " -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" -msgstr[3] "" - -#: templates/problem/submit.html:224 +#: templates/problem/submit.html:212 msgid "You have 0 submissions left" msgstr "" -#: templates/problem/submit.html:258 +#: templates/problem/submit.html:250 msgid "No judge is available for this problem." msgstr "" -#: templates/problem/submit.html:262 +#: templates/problem/submit.html:252 msgid "Submit!" msgstr "Отправить!" -#: templates/registration/activate.html:3 -#, python-format -msgid "%(key)s is an invalid activation key." -msgstr "" - #: templates/registration/activation_complete.html:3 msgid "Your account has been successfully activated." msgstr "" @@ -4371,13 +3851,6 @@ msgid "" "you registered with, and check your spam folder." msgstr "" -#: templates/registration/password_reset_email.txt:1 -#, python-format -msgid "" -"You're receiving this email because you requested a password reset for your " -"user account at %(site_name)s." -msgstr "" - #: templates/registration/password_reset_email.txt:3 msgid "Please go to the following page and choose a new password:" msgstr "" @@ -4390,16 +3863,6 @@ msgstr "" msgid "Thanks for using our site!" msgstr "" -#: templates/registration/password_reset_email.txt:11 -#, python-format -msgid "The %(site_name)s team" -msgstr "" - -#: templates/registration/password_reset_subject.txt:1 -#, python-format -msgid "Password reset on %(site_name)s" -msgstr "" - #: templates/registration/profile_creation.html:36 #: templates/registration/username_select.html:7 msgid "Continue >" @@ -4436,20 +3899,19 @@ msgstr "" msgid "Affiliated organizations" msgstr "" -#: templates/registration/registration_form.html:195 -#: templates/user/edit-profile.html:128 +#: templates/registration/registration_form.html:192 msgid "Notify me about upcoming contests" msgstr "Уведомлять меня о предстоящих соревнованиях" -#: templates/registration/registration_form.html:209 +#: templates/registration/registration_form.html:206 msgid "By registering, you agree to our" msgstr "" -#: templates/registration/registration_form.html:210 +#: templates/registration/registration_form.html:207 msgid "Terms & Conditions" msgstr "Условия использования" -#: templates/registration/registration_form.html:213 +#: templates/registration/registration_form.html:210 msgid "Register!" msgstr "Зарегистрироваться!" @@ -4459,11 +3921,6 @@ msgstr "Зарегистрироваться!" msgid "Enter the 6-digit code generated by your app:" msgstr "" -#: templates/registration/totp_auth.html:41 -#, python-format -msgid "If you lost your authentication device, please contact us at %(email)s." -msgstr "" - #: templates/registration/totp_disable.html:38 msgid "" "To protect your account, you must first authenticate before you can disable " @@ -4482,6 +3939,10 @@ msgstr "" msgid "Or enter this code manually:" msgstr "" +#: templates/stats/base.html:9 templates/submission/list.html:339 +msgid "Statistics" +msgstr "Статистика" + #: templates/stats/language.html:11 msgid "Submission Statistics" msgstr "" @@ -4507,7 +3968,6 @@ msgid "Ping" msgstr "Пинг" #: templates/status/judge-status-table.html:8 -#: templates/user/import/index.html:104 msgid "Load" msgstr "Загрузка" @@ -4523,7 +3983,6 @@ msgid "There are no judges available at this time." msgstr "" #: templates/status/language-list.html:33 templates/ticket/list.html:261 -#: templates/user/import/table_csv.html:3 msgid "ID" msgstr "ID" @@ -4531,22 +3990,6 @@ msgstr "ID" msgid "Runtime Info" msgstr "" -#: templates/status/status-tabs.html:4 -msgid "Judges" -msgstr "" - -#: templates/status/status-tabs.html:6 -msgid "Version Matrix" -msgstr "" - -#: templates/submission/internal-error-message.html:3 -#, python-format -msgid "" -"An internal error occurred while grading, and the %(SITE_NAME)s " -"administrators have been notified.
In the meantime, try resubmitting in " -"a few seconds." -msgstr "" - #: templates/submission/internal-error-message.html:8 msgid "An internal error occurred while grading." msgstr "" @@ -4563,6 +4006,10 @@ msgstr "" msgid "Filter by language..." msgstr "" +#: templates/submission/list.html:309 +msgid "Filter submissions" +msgstr "" + #: templates/submission/list.html:345 msgid "Total:" msgstr "" @@ -4619,72 +4066,71 @@ msgstr "" msgid "Execution Results" msgstr "" -#: templates/submission/status-testcases.html:34 +#: templates/submission/status-testcases.html:31 +msgid "Batch " +msgstr "" + +#: templates/submission/status-testcases.html:43 msgid "Overall: " msgstr "" -#: templates/submission/status-testcases.html:48 +#: templates/submission/status-testcases.html:57 #, fuzzy #| msgid "Points" msgid "Point: " msgstr "Очки" -#: templates/submission/status-testcases.html:53 +#: templates/submission/status-testcases.html:62 #, fuzzy #| msgid "Time:" msgid "Time: " msgstr "Время:" -#: templates/submission/status-testcases.html:62 +#: templates/submission/status-testcases.html:71 #, fuzzy #| msgid "Memory" msgid "Memory: " msgstr "Память" -#: templates/submission/status-testcases.html:73 -msgid "Batch " +#: templates/submission/status-testcases.html:84 +msgid "Case" msgstr "" -#: templates/submission/status-testcases.html:84 -#: templates/submission/status-testcases.html:113 +#: templates/submission/status-testcases.html:86 +msgid "Pretest" +msgstr "" + +#: templates/submission/status-testcases.html:88 +msgid "Test case" +msgstr "" + +#: templates/submission/status-testcases.html:99 #, fuzzy #| msgid "Points" msgid "Point" msgstr "Очки" -#: templates/submission/status-testcases.html:99 -msgid "Case" -msgstr "" - -#: templates/submission/status-testcases.html:101 -msgid "Pretest" -msgstr "" - -#: templates/submission/status-testcases.html:103 -msgid "Test case" -msgstr "" - -#: templates/submission/status-testcases.html:141 +#: templates/submission/status-testcases.html:121 msgid "Input:" msgstr "" -#: templates/submission/status-testcases.html:145 +#: templates/submission/status-testcases.html:125 msgid "Output:" msgstr "" -#: templates/submission/status-testcases.html:149 +#: templates/submission/status-testcases.html:129 msgid "Answer:" msgstr "" -#: templates/submission/status-testcases.html:154 +#: templates/submission/status-testcases.html:134 msgid "Judge feedback:" msgstr "" -#: templates/submission/status-testcases.html:175 +#: templates/submission/status-testcases.html:157 msgid "Passing pretests does not guarantee a full score on system tests." msgstr "" -#: templates/submission/status-testcases.html:178 +#: templates/submission/status-testcases.html:160 msgid "Submission aborted!" msgstr "" @@ -4696,24 +4142,11 @@ msgstr "" msgid "Abort" msgstr "" -#: templates/submission/submission-list-tabs.html:6 -msgid "Mine" -msgstr "" - -#: templates/submission/submission-list-tabs.html:9 -msgid "Best" -msgstr "" - -#: templates/submission/submission-list-tabs.html:12 -#, python-format -msgid "%(user)s's" -msgstr "" - -#: templates/ticket/list.html:135 templates/ticket/ticket.html:273 +#: templates/ticket/list.html:135 templates/ticket/ticket.html:257 msgid "Reopened: " msgstr "" -#: templates/ticket/list.html:138 templates/ticket/ticket.html:274 +#: templates/ticket/list.html:138 templates/ticket/ticket.html:258 msgid "Closed: " msgstr "" @@ -4737,7 +4170,7 @@ msgstr "" msgid "Title" msgstr "" -#: templates/ticket/list.html:264 templates/ticket/ticket.html:369 +#: templates/ticket/list.html:264 templates/ticket/ticket.html:328 msgid "Assignees" msgstr "" @@ -4752,39 +4185,33 @@ msgid "" "a problem, ask in the comments instead." msgstr "" -#: templates/ticket/ticket.html:355 -msgid "Post" -msgstr "" - -#: templates/ticket/ticket.html:363 +#: templates/ticket/ticket.html:322 msgid "Associated object" msgstr "" -#: templates/ticket/ticket.html:374 +#: templates/ticket/ticket.html:333 msgid "No one is assigned." msgstr "" -#: templates/ticket/ticket.html:380 +#: templates/ticket/ticket.html:339 msgid "Close ticket" msgstr "" -#: templates/ticket/ticket.html:382 +#: templates/ticket/ticket.html:341 msgid "Reopen ticket" msgstr "" -#: templates/ticket/ticket.html:386 +#: templates/ticket/ticket.html:345 msgid "Assignee notes" msgstr "" -#: templates/ticket/ticket.html:393 templates/widgets/select_all.html:4 +#: templates/ticket/ticket.html:352 templates/widgets/select_all.html:4 msgid "Nothing here." msgstr "" -#: templates/user/base-users-table.html:3 -#, fuzzy -#| msgid "Rankings" -msgid "Rank" -msgstr "Рейтинг" +#: templates/ticket/ticket.html:385 +msgid "Post" +msgstr "" #: templates/user/base-users.html:14 templates/user/base-users.html:69 msgid "Search by handle..." @@ -4830,200 +4257,50 @@ msgstr "" msgid "Update profile" msgstr "" -#: templates/user/import/index.html:31 -msgid "Upload CSV only" -msgstr "" - -#: templates/user/import/index.html:100 -#, fuzzy -#| msgid "User %s" -msgid "User File" -msgstr "Пользователь %s" - -#: templates/user/import/index.html:102 -msgid "Sample" -msgstr "" - -#: templates/user/import/index.html:105 templates/user/user-list-tabs.html:8 -msgid "Import" -msgstr "" - -#: templates/user/import/table_csv.html:7 -msgid "School" -msgstr "" - -#: templates/user/pp-row.html:22 -#, python-format -msgid "" -"\n" -" weighted %(weight)s%%\n" -" " -msgstr "" - -#: templates/user/pp-row.html:27 -#, python-format -msgid "%(pp).1fpp" -msgstr "" - -#: templates/user/pp-row.html:29 -#, python-format -msgid "%(pp).0fpp" -msgstr "" - -#: templates/user/user-about.html:23 -#, python-format -msgid "%(counter)s problem solved" -msgid_plural "%(counter)s problems solved" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" -msgstr[3] "" - -#: templates/user/user-about.html:35 -#, fuzzy -#| msgid "points" -msgid "Total points" -msgstr "очки" - -#: templates/user/user-about.html:45 -#, fuzzy -#| msgid "Max rating:" -msgid "Rank by rating" -msgstr "Макс рейтинг:" - -#: templates/user/user-about.html:52 -#, fuzzy -#| msgid "Rankings" -msgid "Rank by points" -msgstr "Рейтинг" - -#: templates/user/user-about.html:64 +#: templates/user/user-about.html:14 msgid "From" msgstr "От" -#: templates/user/user-about.html:75 +#: templates/user/user-about.html:25 msgid "Admin Notes" msgstr "" -#: templates/user/user-about.html:90 +#: templates/user/user-about.html:40 msgid "You have not shared any information." msgstr "" -#: templates/user/user-about.html:92 +#: templates/user/user-about.html:42 msgid "This user has not shared any information." msgstr "" -#: templates/user/user-about.html:101 -msgid "Awards" +#: templates/user/user-base.html:50 +msgid "Rank by points:" msgstr "" -#: templates/user/user-about.html:112 -#, fuzzy, python-format -#| msgctxt "contest problem" -#| msgid "%(problem)s in %(contest)s" -msgid "%(label)s (%(date)s)" -msgstr "%(problem)s в %(contest)s" - -#: templates/user/user-about.html:130 -#, fuzzy -#| msgid "Monday" -msgid "Mon" -msgstr "Понедельник" - -#: templates/user/user-about.html:135 -#, fuzzy -#| msgid "Tuesday" -msgid "Tues" -msgstr "Вторник" - -#: templates/user/user-about.html:140 -msgid "Wed" +#: templates/user/user-base.html:53 +msgid "Total points:" msgstr "" -#: templates/user/user-about.html:145 -#, fuzzy -#| msgid "Thursday" -msgid "Thurs" -msgstr "Четверг" - -#: templates/user/user-about.html:150 -#, fuzzy -#| msgid "Friday" -msgid "Fri" -msgstr "Пятница" - -#: templates/user/user-about.html:155 -#, fuzzy -#| msgid "Status" -msgid "Sat" -msgstr "Статус" - -#: templates/user/user-about.html:160 -#, fuzzy -#| msgid "Sunday" -msgid "Sun" -msgstr "Воскресенье" - -#: templates/user/user-about.html:169 -msgid "Less" +#: templates/user/user-base.html:68 +msgid "Rank by rating:" msgstr "" -#: templates/user/user-about.html:175 -msgid "More" -msgstr "" +#: templates/user/user-base.html:70 +msgid "Rating:" +msgstr "Рейтинг:" -#: templates/user/user-about.html:184 -#, fuzzy -#| msgid "History" -msgid "Rating History" -msgstr "История" - -#: templates/user/user-about.html:255 -msgid "past year" -msgstr "" - -#: templates/user/user-about.html:272 -#, fuzzy -#| msgid "submission" -msgid "total submission(s)" -msgstr "посылка" - -#: templates/user/user-about.html:276 -#, fuzzy -#| msgid "submission" -msgid "submissions in the last year" -msgstr "посылка" - -#: templates/user/user-base.html:101 -msgid "Unfollow" -msgstr "" - -#: templates/user/user-base.html:104 -msgid "Follow" -msgstr "" - -#: templates/user/user-base.html:120 -#, fuzzy -#| msgid "contest rated" -msgid "Contests written" -msgstr "соревнование рейтинговое" - -#: templates/user/user-base.html:124 +#: templates/user/user-base.html:71 msgid "Volatility:" msgstr "" -#: templates/user/user-base.html:128 +#: templates/user/user-base.html:72 msgid "Min. rating:" msgstr "Мин рейтинг:" -#: templates/user/user-base.html:132 +#: templates/user/user-base.html:73 msgid "Max rating:" msgstr "Макс рейтинг:" -#: templates/user/user-list-tabs.html:5 -msgid "Friends" -msgstr "" - #: templates/user/user-problems.html:35 msgid "Points Breakdown" msgstr "" @@ -5044,40 +4321,22 @@ msgstr "" msgid "Hide problems I've solved" msgstr "" -#: templates/user/user-problems.html:93 -#, python-format -msgid "%(points).1f points" -msgstr "" - #: templates/user/user-problems.html:99 msgid "Score" msgstr "" -#: templates/user/user-problems.html:110 -#, python-format -msgid "%(points)s / %(total)s" -msgstr "" - -#: templates/user/user-tabs.html:7 -msgid "Impersonate" -msgstr "" - -#: templates/user/user-tabs.html:13 -msgid "Admin User" -msgstr "Администратор" - -#: templates/user/user-tabs.html:16 -msgid "Admin Profile" -msgstr "Профиль администратора" - #: templates/widgets/select_all.html:8 msgid "Check all" msgstr "Выбрать всё" -#~ msgid "Rating:" -#~ msgstr "Рейтинг:" +#~ msgid "Rankings" +#~ msgstr "Рейтинг" -#, fuzzy -#~| msgid "Admin User" -#~ msgid "Admins" +#~ msgid "Contest is over." +#~ msgstr "Соревнование завершено." + +#~ msgid "Admin User" #~ msgstr "Администратор" + +#~ msgid "Admin Profile" +#~ msgstr "Профиль администратора" diff --git a/locale/ru/LC_MESSAGES/djangojs.po b/locale/ru/LC_MESSAGES/djangojs.po index 3b8eac2..ba308f5 100644 --- a/locale/ru/LC_MESSAGES/djangojs.po +++ b/locale/ru/LC_MESSAGES/djangojs.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: dmoj\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-07-20 23:30+0700\n" +"POT-Creation-Date: 2019-10-01 23:12+0000\n" "PO-Revision-Date: 2019-11-11 22:06\n" "Last-Translator: Icyene\n" "Language-Team: Russian\n" @@ -10,9 +10,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " -"&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " -"&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" +"Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 && n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 && n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: dmoj\n" "X-Crowdin-Language: ru\n" @@ -31,3 +29,4 @@ msgstr[3] "%d дней %h:%m:%s" msgctxt "time format without day" msgid "%h:%m:%s" msgstr "%h:%m:%s" + diff --git a/locale/sr/LC_MESSAGES/django.po b/locale/sr/LC_MESSAGES/django.po index 94f6760..42af51d 100644 --- a/locale/sr/LC_MESSAGES/django.po +++ b/locale/sr/LC_MESSAGES/django.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: dmoj\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-10-25 05:59+0700\n" +"POT-Creation-Date: 2020-04-10 01:26-0500\n" "PO-Revision-Date: 2016-12-22 21:23-0500\n" "Last-Translator: Icyene \n" "Language-Team: Serbian (Latin)\n" @@ -17,93 +17,93 @@ msgstr "" "X-Crowdin-Language: sr-CS\n" "X-Crowdin-File: django.po\n" -#: chat_box/models.py:16 judge/admin/interface.py:110 -#: judge/models/contest.py:403 judge/models/contest.py:528 -#: judge/models/profile.py:211 +#: chat_box/models.py:15 judge/admin/interface.py:107 +#: judge/models/contest.py:257 judge/models/contest.py:381 +#: judge/models/profile.py:191 msgid "user" msgstr "" -#: chat_box/models.py:17 judge/models/comment.py:43 judge/models/comment.py:191 +#: chat_box/models.py:16 judge/models/comment.py:42 msgid "posted time" msgstr "" -#: chat_box/models.py:18 judge/models/comment.py:47 +#: chat_box/models.py:17 judge/models/comment.py:46 msgid "body of comment" msgstr "" -#: chat_box/views.py:29 templates/chat/chat.html:4 +#: chat_box/views.py:29 msgid "Chat Box" msgstr "" -#: dmoj/settings.py:355 +#: dmoj/settings.py:349 msgid "German" msgstr "" -#: dmoj/settings.py:356 +#: dmoj/settings.py:350 msgid "English" msgstr "" -#: dmoj/settings.py:357 +#: dmoj/settings.py:351 msgid "Spanish" msgstr "" -#: dmoj/settings.py:358 +#: dmoj/settings.py:352 msgid "French" msgstr "" -#: dmoj/settings.py:359 +#: dmoj/settings.py:353 msgid "Croatian" msgstr "" -#: dmoj/settings.py:360 +#: dmoj/settings.py:354 msgid "Hungarian" msgstr "" -#: dmoj/settings.py:361 +#: dmoj/settings.py:355 msgid "Japanese" msgstr "" -#: dmoj/settings.py:362 +#: dmoj/settings.py:356 msgid "Korean" msgstr "" -#: dmoj/settings.py:363 +#: dmoj/settings.py:357 msgid "Brazilian Portuguese" msgstr "" -#: dmoj/settings.py:364 +#: dmoj/settings.py:358 msgid "Romanian" msgstr "" -#: dmoj/settings.py:365 +#: dmoj/settings.py:359 msgid "Russian" msgstr "" -#: dmoj/settings.py:366 +#: dmoj/settings.py:360 msgid "Serbian (Latin)" msgstr "" -#: dmoj/settings.py:367 +#: dmoj/settings.py:361 msgid "Turkish" msgstr "" -#: dmoj/settings.py:368 +#: dmoj/settings.py:362 msgid "Vietnamese" msgstr "" -#: dmoj/settings.py:369 +#: dmoj/settings.py:363 msgid "Simplified Chinese" msgstr "" -#: dmoj/settings.py:370 +#: dmoj/settings.py:364 msgid "Traditional Chinese" msgstr "" -#: dmoj/urls.py:58 +#: dmoj/urls.py:57 msgid "Login" msgstr "" -#: dmoj/urls.py:106 templates/base.html:193 +#: dmoj/urls.py:105 templates/base.html:190 msgid "Home" msgstr "" @@ -135,48 +135,46 @@ msgstr "" msgid "Associated page" msgstr "" -#: judge/admin/contest.py:30 +#: judge/admin/contest.py:28 msgid "Included contests" msgstr "" -#: judge/admin/contest.py:66 templates/contest/clarification.html:42 -#: templates/contest/contest.html:83 templates/contest/moss.html:43 -#: templates/problem/list.html:214 templates/problem/list.html:232 -#: templates/problem/list.html:350 templates/user/user-problems.html:56 +#: judge/admin/contest.py:64 templates/contest/contest.html:83 +#: templates/contest/moss.html:43 templates/problem/list.html:206 +#: templates/problem/list.html:221 templates/user/user-problems.html:56 #: templates/user/user-problems.html:98 msgid "Problem" msgstr "" -#: judge/admin/contest.py:119 +#: judge/admin/contest.py:112 msgid "Settings" msgstr "" -#: judge/admin/contest.py:121 +#: judge/admin/contest.py:114 msgid "Scheduling" msgstr "" -#: judge/admin/contest.py:122 templates/organization/home.html:107 +#: judge/admin/contest.py:115 msgid "Details" msgstr "" -#: judge/admin/contest.py:123 +#: judge/admin/contest.py:116 msgid "Format" msgstr "" -#: judge/admin/contest.py:124 templates/contest/ranking-table.html:7 -#: templates/user/user-about.html:15 templates/user/user-about.html:45 +#: judge/admin/contest.py:117 templates/contest/ranking-table.html:5 msgid "Rating" msgstr "" -#: judge/admin/contest.py:125 +#: judge/admin/contest.py:118 msgid "Access" msgstr "" -#: judge/admin/contest.py:127 judge/admin/problem.py:131 +#: judge/admin/contest.py:120 judge/admin/problem.py:131 msgid "Justice" msgstr "" -#: judge/admin/contest.py:207 +#: judge/admin/contest.py:158 #, python-format msgid "%d contest successfully marked as visible." msgid_plural "%d contests successfully marked as visible." @@ -184,11 +182,11 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: judge/admin/contest.py:210 +#: judge/admin/contest.py:161 msgid "Mark contests as visible" msgstr "" -#: judge/admin/contest.py:216 +#: judge/admin/contest.py:165 #, python-format msgid "%d contest successfully marked as hidden." msgid_plural "%d contests successfully marked as hidden." @@ -196,11 +194,11 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: judge/admin/contest.py:219 +#: judge/admin/contest.py:168 msgid "Mark contests as hidden" msgstr "" -#: judge/admin/contest.py:233 judge/admin/submission.py:164 +#: judge/admin/contest.py:182 judge/admin/submission.py:164 #, python-format msgid "%d submission was successfully scheduled for rejudging." msgid_plural "%d submissions were successfully scheduled for rejudging." @@ -208,7 +206,7 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: judge/admin/contest.py:308 +#: judge/admin/contest.py:256 #, python-format msgid "%d participation recalculated." msgid_plural "%d participations recalculated." @@ -216,15 +214,15 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: judge/admin/contest.py:311 +#: judge/admin/contest.py:259 msgid "Recalculate results" msgstr "" -#: judge/admin/contest.py:315 judge/admin/organization.py:65 +#: judge/admin/contest.py:263 judge/admin/organization.py:65 msgid "username" msgstr "" -#: judge/admin/contest.py:320 templates/base.html:277 +#: judge/admin/contest.py:268 templates/base.html:260 msgid "virtual" msgstr "" @@ -232,15 +230,15 @@ msgstr "" msgid "link path" msgstr "" -#: judge/admin/interface.py:65 +#: judge/admin/interface.py:62 msgid "Content" msgstr "" -#: judge/admin/interface.py:66 +#: judge/admin/interface.py:63 msgid "Summary" msgstr "" -#: judge/admin/interface.py:151 +#: judge/admin/interface.py:148 msgid "object" msgstr "" @@ -262,9 +260,8 @@ msgid "Taxonomy" msgstr "" #: judge/admin/problem.py:128 templates/contest/contest.html:84 -#: templates/problem/data.html:429 templates/problem/list.html:222 -#: templates/problem/list.html:248 templates/user/base-users-table.html:10 -#: templates/user/user-about.html:36 templates/user/user-about.html:52 +#: templates/problem/data.html:449 templates/problem/list.html:211 +#: templates/problem/list.html:232 templates/user/base-users-table.html:10 #: templates/user/user-problems.html:58 msgid "Points" msgstr "" @@ -315,7 +312,6 @@ msgid "timezone" msgstr "" #: judge/admin/profile.py:86 judge/admin/submission.py:211 -#: templates/notification/list.html:12 #: templates/organization/requests/log.html:9 #: templates/organization/requests/pending.html:12 #: templates/ticket/list.html:263 @@ -323,7 +319,6 @@ msgid "User" msgstr "" #: judge/admin/profile.py:91 templates/registration/registration_form.html:145 -#: templates/user/import/table_csv.html:8 msgid "Email" msgstr "" @@ -357,7 +352,7 @@ msgstr "" msgid "These problems are NOT allowed to be submitted in this language" msgstr "" -#: judge/admin/runtime.py:83 templates/problem/list.html:352 +#: judge/admin/runtime.py:83 msgid "Description" msgstr "" @@ -404,7 +399,7 @@ msgstr "" msgid "Rejudge the selected submissions" msgstr "" -#: judge/admin/submission.py:193 judge/views/problem_manage.py:159 +#: judge/admin/submission.py:193 judge/views/problem_manage.py:128 #, python-format msgid "%d submission were successfully rescored." msgid_plural "%d submissions were successfully rescored." @@ -416,8 +411,7 @@ msgstr[2] "" msgid "Rescore the selected submissions" msgstr "" -#: judge/admin/submission.py:200 templates/problem/list.html:216 -#: templates/problem/list.html:236 +#: judge/admin/submission.py:200 msgid "Problem code" msgstr "" @@ -425,12 +419,10 @@ msgstr "" msgid "Problem name" msgstr "" -#: judge/admin/submission.py:215 templates/notification/list.html:15 -#: templates/organization/requests/log.html:10 +#: judge/admin/submission.py:215 templates/organization/requests/log.html:10 #: templates/organization/requests/pending.html:13 -#: templates/problem/list.html:351 -#: templates/submission/status-testcases.html:125 -#: templates/submission/status-testcases.html:127 +#: templates/submission/status-testcases.html:105 +#: templates/submission/status-testcases.html:107 msgid "Time" msgstr "" @@ -444,7 +436,7 @@ msgstr "" msgid "%.2f MB" msgstr "" -#: judge/admin/submission.py:227 templates/submission/status-testcases.html:132 +#: judge/admin/submission.py:227 templates/submission/status-testcases.html:112 msgid "Memory" msgstr "" @@ -464,20 +456,20 @@ msgstr "" msgid "Online Judge" msgstr "" -#: judge/comments.py:60 +#: judge/comments.py:41 msgid "Comment body" msgstr "" -#: judge/comments.py:66 judge/views/ticket.py:63 +#: judge/comments.py:47 judge/views/ticket.py:46 msgid "Your part is silent, little toad." msgstr "" -#: judge/comments.py:69 templates/comments/list.html:132 +#: judge/comments.py:50 templates/comments/list.html:131 msgid "" "You need to have solved at least one problem before your voice can be heard." msgstr "" -#: judge/comments.py:113 +#: judge/comments.py:92 msgid "Posted comment" msgstr "" @@ -493,10 +485,6 @@ msgstr "" msgid "ECOO" msgstr "" -#: judge/contest_format/icpc.py:19 -msgid "ICPC" -msgstr "" - #: judge/contest_format/ioi.py:19 msgid "IOI" msgstr "" @@ -509,58 +497,52 @@ msgstr "" msgid "Enable experimental features" msgstr "" -#: judge/forms.py:57 judge/views/organization.py:168 judge/views/register.py:49 +#: judge/forms.py:57 judge/views/organization.py:127 #, python-brace-format msgid "You may not be part of more than {count} public organizations." msgstr "" -#: judge/forms.py:82 -msgid "Any judge" -msgstr "" - -#: judge/forms.py:112 judge/views/register.py:26 +#: judge/forms.py:107 judge/views/register.py:26 #: templates/registration/registration_form.html:139 #: templates/user/base-users-table.html:5 -#: templates/user/import/table_csv.html:4 msgid "Username" msgstr "" -#: judge/forms.py:113 templates/registration/registration_form.html:151 +#: judge/forms.py:108 templates/registration/registration_form.html:151 #: templates/registration/registration_form.html:165 -#: templates/user/import/table_csv.html:5 msgid "Password" msgstr "" -#: judge/forms.py:135 +#: judge/forms.py:130 msgid "Two Factor Authentication tokens must be 6 decimal digits." msgstr "" -#: judge/forms.py:144 templates/registration/totp_auth.html:32 +#: judge/forms.py:139 templates/registration/totp_auth.html:32 msgid "Invalid Two Factor Authentication token." msgstr "" -#: judge/forms.py:148 judge/models/problem.py:97 +#: judge/forms.py:143 judge/models/problem.py:97 msgid "Problem code must be ^[a-z0-9]+$" msgstr "" -#: judge/forms.py:153 +#: judge/forms.py:148 msgid "Problem with code already exists." msgstr "" -#: judge/forms.py:158 judge/models/contest.py:61 +#: judge/forms.py:153 judge/models/contest.py:52 msgid "Contest id must be ^[a-z0-9]+$" msgstr "" -#: judge/forms.py:163 +#: judge/forms.py:158 msgid "Contest with key already exists." msgstr "" -#: judge/jinja2/datetime.py:26 templates/blog/blog.html:26 +#: judge/jinja2/datetime.py:26 templates/blog/content.html:27 #: templates/blog/dashboard.html:21 msgid "N j, Y, g:i a" msgstr "" -#: judge/jinja2/datetime.py:26 templates/chat/message.html:13 +#: judge/jinja2/datetime.py:26 #, python-brace-format msgid "{time}" msgstr "" @@ -590,542 +572,472 @@ msgstr "" msgid "Detect best quality" msgstr "" -#: judge/models/comment.py:26 +#: judge/models/comment.py:25 msgid "Page code must be ^[pcs]:[a-z0-9]+$|^b:\\d+$" msgstr "" -#: judge/models/comment.py:42 +#: judge/models/comment.py:41 msgid "commenter" msgstr "" -#: judge/models/comment.py:44 judge/models/comment.py:177 +#: judge/models/comment.py:43 judge/models/comment.py:176 msgid "associated page" msgstr "" -#: judge/models/comment.py:46 +#: judge/models/comment.py:45 msgid "votes" msgstr "" -#: judge/models/comment.py:48 +#: judge/models/comment.py:47 msgid "hide the comment" msgstr "" -#: judge/models/comment.py:49 +#: judge/models/comment.py:48 msgid "parent" msgstr "" -#: judge/models/comment.py:54 judge/models/comment.py:192 +#: judge/models/comment.py:53 msgid "comment" msgstr "" -#: judge/models/comment.py:55 +#: judge/models/comment.py:54 msgid "comments" msgstr "" -#: judge/models/comment.py:137 judge/models/problem.py:443 +#: judge/models/comment.py:136 judge/models/problem.py:406 #, python-format msgid "Editorial for %s" msgstr "" -#: judge/models/comment.py:172 +#: judge/models/comment.py:171 msgid "comment vote" msgstr "" -#: judge/models/comment.py:173 +#: judge/models/comment.py:172 msgid "comment votes" msgstr "" -#: judge/models/comment.py:182 +#: judge/models/comment.py:181 msgid "Override comment lock" msgstr "" -#: judge/models/comment.py:190 -msgid "owner" -msgstr "" - -#: judge/models/comment.py:193 judge/models/message.py:16 -msgid "read" -msgstr "" - -#: judge/models/comment.py:194 -msgid "category" -msgstr "" - -#: judge/models/comment.py:195 -msgid "html link to comments, used for non-comments" -msgstr "" - -#: judge/models/comment.py:196 -msgid "who trigger, used for non-comment" -msgstr "" - -#: judge/models/contest.py:23 +#: judge/models/contest.py:22 msgid "Invalid colour." msgstr "" -#: judge/models/contest.py:25 +#: judge/models/contest.py:24 msgid "tag name" msgstr "" -#: judge/models/contest.py:26 +#: judge/models/contest.py:25 msgid "Lowercase letters and hyphens only." msgstr "" -#: judge/models/contest.py:27 +#: judge/models/contest.py:26 msgid "tag colour" msgstr "" -#: judge/models/contest.py:28 +#: judge/models/contest.py:27 msgid "tag description" msgstr "" -#: judge/models/contest.py:47 +#: judge/models/contest.py:46 msgid "contest tag" msgstr "" -#: judge/models/contest.py:48 judge/models/contest.py:118 +#: judge/models/contest.py:47 judge/models/contest.py:101 msgid "contest tags" msgstr "" -#: judge/models/contest.py:56 -msgid "Visible" -msgstr "" - -#: judge/models/contest.py:57 -msgid "Hidden for duration of contest" -msgstr "" - -#: judge/models/contest.py:58 -msgid "Hidden for duration of participation" -msgstr "" - -#: judge/models/contest.py:60 +#: judge/models/contest.py:51 msgid "contest id" msgstr "" -#: judge/models/contest.py:62 +#: judge/models/contest.py:53 msgid "contest name" msgstr "" -#: judge/models/contest.py:63 -msgid "These users will be able to edit the contest." +#: judge/models/contest.py:54 +msgid "These people will be able to edit the contest." msgstr "" -#: judge/models/contest.py:65 -msgid "" -"These users will be able to edit the contest, but will not be listed as " -"authors." -msgstr "" - -#: judge/models/contest.py:68 -msgid "These users will be able to view the contest, but not edit it." -msgstr "" - -#: judge/models/contest.py:71 judge/models/runtime.py:136 +#: judge/models/contest.py:56 judge/models/runtime.py:133 msgid "description" msgstr "" -#: judge/models/contest.py:72 judge/models/problem.py:390 -#: judge/models/runtime.py:138 +#: judge/models/contest.py:57 judge/models/problem.py:353 +#: judge/models/runtime.py:135 msgid "problems" msgstr "" -#: judge/models/contest.py:73 judge/models/contest.py:404 +#: judge/models/contest.py:58 judge/models/contest.py:258 msgid "start time" msgstr "" -#: judge/models/contest.py:74 +#: judge/models/contest.py:59 msgid "end time" msgstr "" -#: judge/models/contest.py:75 judge/models/problem.py:118 -#: judge/models/problem.py:414 +#: judge/models/contest.py:60 judge/models/problem.py:118 +#: judge/models/problem.py:377 msgid "time limit" msgstr "" -#: judge/models/contest.py:76 judge/models/problem.py:136 +#: judge/models/contest.py:61 judge/models/problem.py:136 msgid "publicly visible" msgstr "" -#: judge/models/contest.py:77 +#: judge/models/contest.py:62 msgid "" "Should be set even for organization-private contests, where it determines " "whether the contest is visible to members of the specified organizations." msgstr "" -#: judge/models/contest.py:80 +#: judge/models/contest.py:65 msgid "contest rated" msgstr "" -#: judge/models/contest.py:80 +#: judge/models/contest.py:65 msgid "Whether this contest can be rated." msgstr "" -#: judge/models/contest.py:82 -msgid "scoreboard visibility" +#: judge/models/contest.py:67 +msgid "hide scoreboard" msgstr "" -#: judge/models/contest.py:83 -msgid "Scoreboard visibility through the duration of the contest" +#: judge/models/contest.py:68 +msgid "" +"Whether the scoreboard should remain hidden for the duration of the contest." msgstr "" -#: judge/models/contest.py:85 -msgid "view contest scoreboard" -msgstr "" - -#: judge/models/contest.py:87 -msgid "These users will be able to view the scoreboard." -msgstr "" - -#: judge/models/contest.py:88 +#: judge/models/contest.py:71 msgid "no comments" msgstr "" -#: judge/models/contest.py:89 +#: judge/models/contest.py:72 msgid "Use clarification system instead of comments." msgstr "" -#: judge/models/contest.py:91 +#: judge/models/contest.py:74 msgid "Rating floor for contest" msgstr "" -#: judge/models/contest.py:93 +#: judge/models/contest.py:76 msgid "Rating ceiling for contest" msgstr "" -#: judge/models/contest.py:95 +#: judge/models/contest.py:78 msgid "rate all" msgstr "" -#: judge/models/contest.py:95 +#: judge/models/contest.py:78 msgid "Rate all users who joined." msgstr "" -#: judge/models/contest.py:96 +#: judge/models/contest.py:79 msgid "exclude from ratings" msgstr "" -#: judge/models/contest.py:98 +#: judge/models/contest.py:81 msgid "private to specific users" msgstr "" -#: judge/models/contest.py:99 +#: judge/models/contest.py:82 msgid "private contestants" msgstr "" -#: judge/models/contest.py:100 +#: judge/models/contest.py:83 msgid "If private, only these users may see the contest" msgstr "" -#: judge/models/contest.py:102 +#: judge/models/contest.py:85 msgid "hide problem tags" msgstr "" -#: judge/models/contest.py:103 +#: judge/models/contest.py:86 msgid "Whether problem tags should be hidden by default." msgstr "" -#: judge/models/contest.py:105 +#: judge/models/contest.py:88 msgid "run pretests only" msgstr "" -#: judge/models/contest.py:106 +#: judge/models/contest.py:89 msgid "" "Whether judges should grade pretests only, versus all testcases. Commonly " "set during a contest, then unset prior to rejudging user submissions when " "the contest ends." msgstr "" -#: judge/models/contest.py:110 judge/models/interface.py:77 -#: judge/models/problem.py:157 +#: judge/models/contest.py:93 judge/models/problem.py:157 msgid "private to organizations" msgstr "" -#: judge/models/contest.py:111 judge/models/interface.py:75 -#: judge/models/problem.py:155 judge/models/profile.py:77 +#: judge/models/contest.py:94 judge/models/problem.py:155 +#: judge/models/profile.py:77 msgid "organizations" msgstr "" -#: judge/models/contest.py:112 +#: judge/models/contest.py:95 msgid "If private, only these organizations may see the contest" msgstr "" -#: judge/models/contest.py:113 judge/models/problem.py:145 +#: judge/models/contest.py:96 judge/models/problem.py:145 msgid "OpenGraph image" msgstr "" -#: judge/models/contest.py:114 judge/models/profile.py:48 +#: judge/models/contest.py:97 judge/models/profile.py:48 msgid "Logo override image" msgstr "" -#: judge/models/contest.py:116 +#: judge/models/contest.py:99 msgid "" "This image will replace the default site logo for users inside the contest." msgstr "" -#: judge/models/contest.py:119 +#: judge/models/contest.py:102 msgid "the amount of live participants" msgstr "" -#: judge/models/contest.py:120 +#: judge/models/contest.py:103 msgid "contest summary" msgstr "" -#: judge/models/contest.py:121 judge/models/problem.py:147 +#: judge/models/contest.py:104 judge/models/problem.py:147 msgid "Plain-text, shown in meta description tag, e.g. for social media." msgstr "" -#: judge/models/contest.py:122 judge/models/profile.py:47 +#: judge/models/contest.py:105 judge/models/profile.py:47 msgid "access code" msgstr "" -#: judge/models/contest.py:123 +#: judge/models/contest.py:106 msgid "" "An optional code to prompt contestants before they are allowed to join the " "contest. Leave it blank to disable." msgstr "" -#: judge/models/contest.py:125 judge/models/problem.py:141 +#: judge/models/contest.py:108 judge/models/problem.py:141 msgid "personae non gratae" msgstr "" -#: judge/models/contest.py:126 +#: judge/models/contest.py:109 msgid "Bans the selected users from joining this contest." msgstr "" -#: judge/models/contest.py:127 +#: judge/models/contest.py:110 msgid "contest format" msgstr "" -#: judge/models/contest.py:128 +#: judge/models/contest.py:111 msgid "The contest format module to use." msgstr "" -#: judge/models/contest.py:129 +#: judge/models/contest.py:112 msgid "contest format configuration" msgstr "" -#: judge/models/contest.py:130 +#: judge/models/contest.py:113 msgid "" "A JSON object to serve as the configuration for the chosen contest format " "module. Leave empty to use None. Exact format depends on the contest format " "selected." msgstr "" -#: judge/models/contest.py:137 -msgid "precision points" -msgstr "" - -#: judge/models/contest.py:139 -msgid "Number of digits to round points to." -msgstr "" - -#: judge/models/contest.py:383 +#: judge/models/contest.py:239 msgid "See private contests" msgstr "" -#: judge/models/contest.py:384 +#: judge/models/contest.py:240 msgid "Edit own contests" msgstr "" -#: judge/models/contest.py:385 +#: judge/models/contest.py:241 msgid "Edit all contests" msgstr "" -#: judge/models/contest.py:386 +#: judge/models/contest.py:242 msgid "Clone contest" msgstr "" -#: judge/models/contest.py:387 templates/contest/moss.html:74 +#: judge/models/contest.py:243 templates/contest/moss.html:74 msgid "MOSS contest" msgstr "" -#: judge/models/contest.py:388 +#: judge/models/contest.py:244 msgid "Rate contests" msgstr "" -#: judge/models/contest.py:389 +#: judge/models/contest.py:245 msgid "Contest access codes" msgstr "" -#: judge/models/contest.py:390 +#: judge/models/contest.py:246 msgid "Create private contests" msgstr "" -#: judge/models/contest.py:391 -msgid "Change contest visibility" -msgstr "" - -#: judge/models/contest.py:392 -msgid "Edit contest problem label script" -msgstr "" - -#: judge/models/contest.py:394 judge/models/contest.py:492 -#: judge/models/contest.py:529 judge/models/contest.py:552 -#: judge/models/submission.py:84 +#: judge/models/contest.py:248 judge/models/contest.py:345 +#: judge/models/contest.py:382 judge/models/contest.py:404 +#: judge/models/submission.py:83 msgid "contest" msgstr "" -#: judge/models/contest.py:395 +#: judge/models/contest.py:249 msgid "contests" msgstr "" -#: judge/models/contest.py:402 +#: judge/models/contest.py:256 msgid "associated contest" msgstr "" -#: judge/models/contest.py:405 +#: judge/models/contest.py:259 msgid "score" msgstr "" -#: judge/models/contest.py:406 +#: judge/models/contest.py:260 msgid "cumulative time" msgstr "" -#: judge/models/contest.py:407 +#: judge/models/contest.py:261 msgid "is disqualified" msgstr "" -#: judge/models/contest.py:408 +#: judge/models/contest.py:262 msgid "Whether this participation is disqualified." msgstr "" -#: judge/models/contest.py:409 -msgid "tie-breaking field" -msgstr "" - -#: judge/models/contest.py:410 +#: judge/models/contest.py:263 msgid "virtual participation id" msgstr "" -#: judge/models/contest.py:411 +#: judge/models/contest.py:264 msgid "0 means non-virtual, otherwise the n-th virtual participation." msgstr "" -#: judge/models/contest.py:412 +#: judge/models/contest.py:265 msgid "contest format specific data" msgstr "" -#: judge/models/contest.py:478 +#: judge/models/contest.py:331 #, python-format msgid "%s spectating in %s" msgstr "" -#: judge/models/contest.py:480 +#: judge/models/contest.py:333 #, python-format msgid "%s in %s, v%d" msgstr "" -#: judge/models/contest.py:481 +#: judge/models/contest.py:334 #, python-format msgid "%s in %s" msgstr "" -#: judge/models/contest.py:484 +#: judge/models/contest.py:337 msgid "contest participation" msgstr "" -#: judge/models/contest.py:485 +#: judge/models/contest.py:338 msgid "contest participations" msgstr "" -#: judge/models/contest.py:491 judge/models/contest.py:513 -#: judge/models/contest.py:553 judge/models/problem.py:389 -#: judge/models/problem.py:394 judge/models/problem.py:412 -#: judge/models/problem_data.py:40 +#: judge/models/contest.py:344 judge/models/contest.py:366 +#: judge/models/contest.py:405 judge/models/problem.py:352 +#: judge/models/problem.py:357 judge/models/problem.py:375 +#: judge/models/problem_data.py:38 msgid "problem" msgstr "" -#: judge/models/contest.py:493 judge/models/contest.py:517 +#: judge/models/contest.py:346 judge/models/contest.py:370 #: judge/models/problem.py:129 msgid "points" msgstr "" -#: judge/models/contest.py:494 +#: judge/models/contest.py:347 msgid "partial" msgstr "" -#: judge/models/contest.py:495 judge/models/contest.py:518 +#: judge/models/contest.py:348 judge/models/contest.py:371 msgid "is pretested" msgstr "" -#: judge/models/contest.py:496 judge/models/interface.py:43 +#: judge/models/contest.py:349 judge/models/interface.py:43 msgid "order" msgstr "" -#: judge/models/contest.py:497 +#: judge/models/contest.py:350 msgid "0 to not show testcases, 1 to show" msgstr "" -#: judge/models/contest.py:498 +#: judge/models/contest.py:351 msgid "visible testcases" msgstr "" -#: judge/models/contest.py:499 +#: judge/models/contest.py:352 msgid "Maximum number of submissions for this problem, or 0 for no limit." msgstr "" -#: judge/models/contest.py:501 +#: judge/models/contest.py:354 msgid "Why include a problem you can't submit to?" msgstr "" -#: judge/models/contest.py:506 +#: judge/models/contest.py:359 msgid "contest problem" msgstr "" -#: judge/models/contest.py:507 +#: judge/models/contest.py:360 msgid "contest problems" msgstr "" -#: judge/models/contest.py:511 judge/models/submission.py:183 +#: judge/models/contest.py:364 judge/models/submission.py:181 msgid "submission" msgstr "" -#: judge/models/contest.py:515 judge/models/contest.py:530 +#: judge/models/contest.py:368 judge/models/contest.py:383 msgid "participation" msgstr "" -#: judge/models/contest.py:519 +#: judge/models/contest.py:372 msgid "Whether this submission was ran only on pretests." msgstr "" -#: judge/models/contest.py:523 +#: judge/models/contest.py:376 msgid "contest submission" msgstr "" -#: judge/models/contest.py:524 +#: judge/models/contest.py:377 msgid "contest submissions" msgstr "" -#: judge/models/contest.py:532 +#: judge/models/contest.py:385 msgid "rank" msgstr "" -#: judge/models/contest.py:533 +#: judge/models/contest.py:386 msgid "rating" msgstr "" -#: judge/models/contest.py:534 +#: judge/models/contest.py:387 msgid "volatility" msgstr "" -#: judge/models/contest.py:535 +#: judge/models/contest.py:388 msgid "last rated" msgstr "" -#: judge/models/contest.py:539 +#: judge/models/contest.py:392 msgid "contest rating" msgstr "" -#: judge/models/contest.py:540 +#: judge/models/contest.py:393 msgid "contest ratings" msgstr "" -#: judge/models/contest.py:560 +#: judge/models/contest.py:412 msgid "contest moss result" msgstr "" -#: judge/models/contest.py:561 +#: judge/models/contest.py:413 msgid "contest moss results" msgstr "" @@ -1165,7 +1077,7 @@ msgstr "" msgid "post title" msgstr "" -#: judge/models/interface.py:67 judge/models/problem.py:432 +#: judge/models/interface.py:67 judge/models/problem.py:395 msgid "authors" msgstr "" @@ -1173,7 +1085,7 @@ msgstr "" msgid "slug" msgstr "" -#: judge/models/interface.py:69 judge/models/problem.py:430 +#: judge/models/interface.py:69 judge/models/problem.py:393 msgid "public visibility" msgstr "" @@ -1197,19 +1109,15 @@ msgstr "" msgid "openGraph image" msgstr "" -#: judge/models/interface.py:76 -msgid "If private, only these organizations may see the blog post." -msgstr "" - -#: judge/models/interface.py:105 +#: judge/models/interface.py:91 msgid "Edit all posts" msgstr "" -#: judge/models/interface.py:107 +#: judge/models/interface.py:93 msgid "blog post" msgstr "" -#: judge/models/interface.py:108 +#: judge/models/interface.py:94 msgid "blog posts" msgstr "" @@ -1233,6 +1141,10 @@ msgstr "" msgid "message timestamp" msgstr "" +#: judge/models/message.py:16 +msgid "read" +msgstr "" + #: judge/models/message.py:20 msgid "messages in the thread" msgstr "" @@ -1369,7 +1281,7 @@ msgid "" "are supported." msgstr "" -#: judge/models/problem.py:123 judge/models/problem.py:417 +#: judge/models/problem.py:123 judge/models/problem.py:380 msgid "memory limit" msgstr "" @@ -1442,188 +1354,188 @@ msgstr "" msgid "If private, only these organizations may see the problem." msgstr "" -#: judge/models/problem.py:395 judge/models/problem.py:413 -#: judge/models/runtime.py:111 +#: judge/models/problem.py:358 judge/models/problem.py:376 +#: judge/models/runtime.py:108 msgid "language" msgstr "" -#: judge/models/problem.py:396 +#: judge/models/problem.py:359 msgid "translated name" msgstr "" -#: judge/models/problem.py:397 +#: judge/models/problem.py:360 msgid "translated description" msgstr "" -#: judge/models/problem.py:401 +#: judge/models/problem.py:364 msgid "problem translation" msgstr "" -#: judge/models/problem.py:402 +#: judge/models/problem.py:365 msgid "problem translations" msgstr "" -#: judge/models/problem.py:406 +#: judge/models/problem.py:369 msgid "clarified problem" msgstr "" -#: judge/models/problem.py:407 +#: judge/models/problem.py:370 msgid "clarification body" msgstr "" -#: judge/models/problem.py:408 +#: judge/models/problem.py:371 msgid "clarification timestamp" msgstr "" -#: judge/models/problem.py:423 +#: judge/models/problem.py:386 msgid "language-specific resource limit" msgstr "" -#: judge/models/problem.py:424 +#: judge/models/problem.py:387 msgid "language-specific resource limits" msgstr "" -#: judge/models/problem.py:428 +#: judge/models/problem.py:391 msgid "associated problem" msgstr "" -#: judge/models/problem.py:431 +#: judge/models/problem.py:394 msgid "publish date" msgstr "" -#: judge/models/problem.py:433 +#: judge/models/problem.py:396 msgid "editorial content" msgstr "" -#: judge/models/problem.py:449 +#: judge/models/problem.py:412 msgid "solution" msgstr "" -#: judge/models/problem.py:450 +#: judge/models/problem.py:413 msgid "solutions" msgstr "" -#: judge/models/problem_data.py:26 +#: judge/models/problem_data.py:24 msgid "Standard" msgstr "" -#: judge/models/problem_data.py:27 +#: judge/models/problem_data.py:25 msgid "Floats" msgstr "" -#: judge/models/problem_data.py:28 +#: judge/models/problem_data.py:26 msgid "Floats (absolute)" msgstr "" -#: judge/models/problem_data.py:29 +#: judge/models/problem_data.py:27 msgid "Floats (relative)" msgstr "" -#: judge/models/problem_data.py:30 +#: judge/models/problem_data.py:28 msgid "Non-trailing spaces" msgstr "" -#: judge/models/problem_data.py:31 +#: judge/models/problem_data.py:29 msgid "Unordered" msgstr "" -#: judge/models/problem_data.py:32 +#: judge/models/problem_data.py:30 msgid "Byte identical" msgstr "" -#: judge/models/problem_data.py:33 +#: judge/models/problem_data.py:31 msgid "Line-by-line" msgstr "" -#: judge/models/problem_data.py:34 +#: judge/models/problem_data.py:32 msgid "Custom checker (PY)" msgstr "" -#: judge/models/problem_data.py:35 +#: judge/models/problem_data.py:33 msgid "Custom validator (CPP)" msgstr "" -#: judge/models/problem_data.py:42 +#: judge/models/problem_data.py:40 msgid "data zip file" msgstr "" -#: judge/models/problem_data.py:44 +#: judge/models/problem_data.py:42 msgid "generator file" msgstr "" -#: judge/models/problem_data.py:46 judge/models/problem_data.py:121 +#: judge/models/problem_data.py:44 judge/models/problem_data.py:110 msgid "output prefix length" msgstr "" -#: judge/models/problem_data.py:47 judge/models/problem_data.py:122 +#: judge/models/problem_data.py:45 judge/models/problem_data.py:111 msgid "output limit length" msgstr "" -#: judge/models/problem_data.py:48 +#: judge/models/problem_data.py:46 msgid "init.yml generation feedback" msgstr "" -#: judge/models/problem_data.py:49 judge/models/problem_data.py:123 +#: judge/models/problem_data.py:47 judge/models/problem_data.py:112 msgid "checker" msgstr "" -#: judge/models/problem_data.py:50 judge/models/problem_data.py:124 +#: judge/models/problem_data.py:48 judge/models/problem_data.py:113 msgid "checker arguments" msgstr "" -#: judge/models/problem_data.py:51 judge/models/problem_data.py:125 +#: judge/models/problem_data.py:49 judge/models/problem_data.py:114 msgid "checker arguments as a JSON object" msgstr "" -#: judge/models/problem_data.py:52 +#: judge/models/problem_data.py:50 msgid "custom checker file" msgstr "" -#: judge/models/problem_data.py:58 +#: judge/models/problem_data.py:56 msgid "custom validator file" msgstr "" -#: judge/models/problem_data.py:108 +#: judge/models/problem_data.py:97 msgid "problem data set" msgstr "" -#: judge/models/problem_data.py:110 +#: judge/models/problem_data.py:99 msgid "case position" msgstr "" -#: judge/models/problem_data.py:111 +#: judge/models/problem_data.py:100 msgid "case type" msgstr "" -#: judge/models/problem_data.py:112 +#: judge/models/problem_data.py:101 msgid "Normal case" msgstr "" -#: judge/models/problem_data.py:113 +#: judge/models/problem_data.py:102 msgid "Batch start" msgstr "" -#: judge/models/problem_data.py:114 +#: judge/models/problem_data.py:103 msgid "Batch end" msgstr "" -#: judge/models/problem_data.py:116 +#: judge/models/problem_data.py:105 msgid "input file name" msgstr "" -#: judge/models/problem_data.py:117 +#: judge/models/problem_data.py:106 msgid "output file name" msgstr "" -#: judge/models/problem_data.py:118 +#: judge/models/problem_data.py:107 msgid "generator arguments" msgstr "" -#: judge/models/problem_data.py:119 +#: judge/models/problem_data.py:108 msgid "point value" msgstr "" -#: judge/models/problem_data.py:120 +#: judge/models/problem_data.py:109 msgid "case is pretest?" msgstr "" @@ -1696,7 +1608,7 @@ msgid "" msgstr "" #: judge/models/profile.py:76 judge/models/profile.py:93 -#: judge/models/profile.py:212 +#: judge/models/profile.py:192 msgid "organization" msgstr "" @@ -1792,31 +1704,31 @@ msgstr "" msgid "Notes for administrators regarding this user." msgstr "" -#: judge/models/profile.py:206 +#: judge/models/profile.py:186 msgid "user profile" msgstr "" -#: judge/models/profile.py:207 +#: judge/models/profile.py:187 msgid "user profiles" msgstr "" -#: judge/models/profile.py:214 +#: judge/models/profile.py:194 msgid "request time" msgstr "" -#: judge/models/profile.py:215 +#: judge/models/profile.py:195 msgid "state" msgstr "" -#: judge/models/profile.py:220 +#: judge/models/profile.py:200 msgid "reason" msgstr "" -#: judge/models/profile.py:223 +#: judge/models/profile.py:203 msgid "organization join request" msgstr "" -#: judge/models/profile.py:224 +#: judge/models/profile.py:204 msgid "organization join requests" msgstr "" @@ -1907,86 +1819,86 @@ msgstr "" msgid "The extension of source files, e.g., \"py\" or \"cpp\"." msgstr "" -#: judge/models/runtime.py:112 +#: judge/models/runtime.py:109 msgid "languages" msgstr "" -#: judge/models/runtime.py:116 +#: judge/models/runtime.py:113 msgid "language to which this runtime belongs" msgstr "" -#: judge/models/runtime.py:117 +#: judge/models/runtime.py:114 msgid "judge on which this runtime exists" msgstr "" -#: judge/models/runtime.py:118 +#: judge/models/runtime.py:115 msgid "runtime name" msgstr "" -#: judge/models/runtime.py:119 +#: judge/models/runtime.py:116 msgid "runtime version" msgstr "" -#: judge/models/runtime.py:120 +#: judge/models/runtime.py:117 msgid "order in which to display this runtime" msgstr "" -#: judge/models/runtime.py:124 +#: judge/models/runtime.py:121 msgid "Server name, hostname-style" msgstr "" -#: judge/models/runtime.py:125 +#: judge/models/runtime.py:122 msgid "time of creation" msgstr "" -#: judge/models/runtime.py:126 +#: judge/models/runtime.py:123 msgid "A key to authenticate this judge" msgstr "" -#: judge/models/runtime.py:127 +#: judge/models/runtime.py:124 msgid "authentication key" msgstr "" -#: judge/models/runtime.py:128 +#: judge/models/runtime.py:125 msgid "block judge" msgstr "" -#: judge/models/runtime.py:129 +#: judge/models/runtime.py:126 msgid "" "Whether this judge should be blocked from connecting, even if its key is " "correct." msgstr "" -#: judge/models/runtime.py:131 +#: judge/models/runtime.py:128 msgid "judge online status" msgstr "" -#: judge/models/runtime.py:132 +#: judge/models/runtime.py:129 msgid "judge start time" msgstr "" -#: judge/models/runtime.py:133 +#: judge/models/runtime.py:130 msgid "response time" msgstr "" -#: judge/models/runtime.py:134 +#: judge/models/runtime.py:131 msgid "system load" msgstr "" -#: judge/models/runtime.py:135 +#: judge/models/runtime.py:132 msgid "Load for the last minute, divided by processors to be fair." msgstr "" -#: judge/models/runtime.py:139 judge/models/runtime.py:179 +#: judge/models/runtime.py:136 judge/models/runtime.py:176 msgid "judges" msgstr "" -#: judge/models/runtime.py:178 +#: judge/models/runtime.py:175 msgid "judge" msgstr "" #: judge/models/submission.py:20 judge/models/submission.py:47 -#: judge/utils/problems.py:79 +#: judge/utils/problems.py:77 msgid "Accepted" msgstr "" @@ -2015,7 +1927,7 @@ msgid "Runtime Error" msgstr "" #: judge/models/submission.py:27 judge/models/submission.py:41 -#: judge/models/submission.py:55 judge/utils/problems.py:81 +#: judge/models/submission.py:55 judge/utils/problems.py:79 msgid "Compile Error" msgstr "" @@ -2056,15 +1968,15 @@ msgstr "" msgid "submission time" msgstr "" -#: judge/models/submission.py:67 judge/models/submission.py:203 +#: judge/models/submission.py:67 judge/models/submission.py:201 msgid "execution time" msgstr "" -#: judge/models/submission.py:68 judge/models/submission.py:204 +#: judge/models/submission.py:68 judge/models/submission.py:202 msgid "memory usage" msgstr "" -#: judge/models/submission.py:69 judge/models/submission.py:205 +#: judge/models/submission.py:69 judge/models/submission.py:203 msgid "points granted" msgstr "" @@ -2101,62 +2013,58 @@ msgid "judged on" msgstr "" #: judge/models/submission.py:81 -msgid "submission judge time" -msgstr "" - -#: judge/models/submission.py:82 msgid "was rejudged by admin" msgstr "" -#: judge/models/submission.py:83 +#: judge/models/submission.py:82 msgid "was ran on pretests only" msgstr "" -#: judge/models/submission.py:184 templates/contest/moss.html:58 +#: judge/models/submission.py:182 templates/contest/moss.html:58 msgid "submissions" msgstr "" -#: judge/models/submission.py:188 judge/models/submission.py:199 +#: judge/models/submission.py:186 judge/models/submission.py:197 msgid "associated submission" msgstr "" -#: judge/models/submission.py:190 +#: judge/models/submission.py:188 msgid "source code" msgstr "" -#: judge/models/submission.py:201 +#: judge/models/submission.py:199 msgid "test case ID" msgstr "" -#: judge/models/submission.py:202 +#: judge/models/submission.py:200 msgid "status flag" msgstr "" -#: judge/models/submission.py:206 +#: judge/models/submission.py:204 msgid "points possible" msgstr "" -#: judge/models/submission.py:207 +#: judge/models/submission.py:205 msgid "batch number" msgstr "" -#: judge/models/submission.py:208 +#: judge/models/submission.py:206 msgid "judging feedback" msgstr "" -#: judge/models/submission.py:209 +#: judge/models/submission.py:207 msgid "extended judging feedback" msgstr "" -#: judge/models/submission.py:210 +#: judge/models/submission.py:208 msgid "program output" msgstr "" -#: judge/models/submission.py:218 +#: judge/models/submission.py:216 msgid "submission test case" msgstr "" -#: judge/models/submission.py:219 +#: judge/models/submission.py:217 msgid "submission test cases" msgstr "" @@ -2208,21 +2116,12 @@ msgstr "" msgid "message time" msgstr "" -#: judge/pdf_problems.py:147 judge/pdf_problems.py:199 -#: judge/pdf_problems.py:259 +#: judge/pdf_problems.py:134 judge/pdf_problems.py:186 +#: judge/pdf_problems.py:246 msgid "Page [page] of [topage]" msgstr "" -#: judge/pdf_problems.py:280 -#, python-format -msgid "Page %s of %s" -msgstr "" - -#: judge/tasks/contest.py:19 -msgid "Recalculating contest scores" -msgstr "" - -#: judge/tasks/contest.py:40 +#: judge/tasks/moss.py:25 msgid "Running MOSS" msgstr "" @@ -2234,60 +2133,60 @@ msgstr "" msgid "Recalculating user points" msgstr "" -#: judge/utils/problem_data.py:70 +#: judge/utils/problem_data.py:68 msgid "Empty batches not allowed." msgstr "" -#: judge/utils/problem_data.py:78 judge/utils/problem_data.py:99 +#: judge/utils/problem_data.py:76 judge/utils/problem_data.py:97 msgid "How did you corrupt the custom checker path?" msgstr "" -#: judge/utils/problem_data.py:120 +#: judge/utils/problem_data.py:118 #, python-format msgid "Points must be defined for non-batch case #%d." msgstr "" -#: judge/utils/problem_data.py:125 +#: judge/utils/problem_data.py:123 #, python-format msgid "Input file for case %d does not exist: %s" msgstr "" -#: judge/utils/problem_data.py:128 +#: judge/utils/problem_data.py:126 #, python-format msgid "Output file for case %d does not exist: %s" msgstr "" -#: judge/utils/problem_data.py:153 +#: judge/utils/problem_data.py:151 #, python-format msgid "Batch start case #%d requires points." msgstr "" -#: judge/utils/problem_data.py:174 +#: judge/utils/problem_data.py:172 #, python-format msgid "Attempt to end batch outside of one in case #%d" msgstr "" -#: judge/utils/problem_data.py:192 +#: judge/utils/problem_data.py:190 msgid "How did you corrupt the zip path?" msgstr "" -#: judge/utils/problem_data.py:198 +#: judge/utils/problem_data.py:196 msgid "How did you corrupt the generator path?" msgstr "" -#: judge/utils/problems.py:80 +#: judge/utils/problems.py:78 msgid "Wrong" msgstr "" -#: judge/utils/problems.py:82 +#: judge/utils/problems.py:80 msgid "Timeout" msgstr "" -#: judge/utils/problems.py:83 +#: judge/utils/problems.py:81 msgid "Error" msgstr "" -#: judge/utils/problems.py:94 +#: judge/utils/problems.py:92 msgid "Can't pass both queryset and keyword filters" msgstr "" @@ -2333,8 +2232,7 @@ msgctxt "hours and minutes" msgid "%h:%m" msgstr "" -#: judge/views/about.py:7 templates/organization/home.html:112 -#: templates/user/user-about.html:83 templates/user/user-tabs.html:4 +#: judge/views/about.py:7 templates/user/user-about.html:33 msgid "About" msgstr "" @@ -2342,165 +2240,156 @@ msgstr "" msgid "Custom Checker Sample" msgstr "" -#: judge/views/blog.py:45 +#: judge/views/blog.py:38 #, python-format msgid "Page %d of Posts" msgstr "" -#: judge/views/comment.py:28 +#: judge/views/comment.py:27 msgid "Messing around, are we?" msgstr "" -#: judge/views/comment.py:37 +#: judge/views/comment.py:36 msgid "You must solve at least one problem before you can vote." msgstr "" -#: judge/views/comment.py:64 +#: judge/views/comment.py:63 msgid "You already voted." msgstr "" -#: judge/views/comment.py:126 judge/views/organization.py:344 +#: judge/views/comment.py:120 judge/views/organization.py:299 msgid "Edited from site" msgstr "" -#: judge/views/comment.py:147 +#: judge/views/comment.py:141 msgid "Editing comment" msgstr "" -#: judge/views/contests.py:57 judge/views/contests.py:247 -#: judge/views/contests.py:250 judge/views/contests.py:424 +#: judge/views/contests.py:55 judge/views/contests.py:215 +#: judge/views/contests.py:218 judge/views/contests.py:389 msgid "No such contest" msgstr "" -#: judge/views/contests.py:58 judge/views/contests.py:248 +#: judge/views/contests.py:56 judge/views/contests.py:216 #, python-format msgid "Could not find a contest with the key \"%s\"." msgstr "" -#: judge/views/contests.py:71 +#: judge/views/contests.py:81 msgid "Contests" msgstr "" -#: judge/views/contests.py:251 +#: judge/views/contests.py:219 msgid "Could not find such contest." msgstr "" -#: judge/views/contests.py:254 +#: judge/views/contests.py:222 #, python-format msgid "Access to contest \"%s\" denied" msgstr "" -#: judge/views/contests.py:278 +#: judge/views/contests.py:246 msgid "Clone Contest" msgstr "" -#: judge/views/contests.py:343 +#: judge/views/contests.py:309 msgid "Contest not ongoing" msgstr "" -#: judge/views/contests.py:344 +#: judge/views/contests.py:310 #, python-format msgid "\"%s\" is not currently ongoing." msgstr "" -#: judge/views/contests.py:348 +#: judge/views/contests.py:314 msgid "Already in contest" msgstr "" -#: judge/views/contests.py:349 +#: judge/views/contests.py:315 #, python-format msgid "You are already in a contest: \"%s\"." msgstr "" -#: judge/views/contests.py:352 +#: judge/views/contests.py:318 msgid "Banned from joining" msgstr "" -#: judge/views/contests.py:353 +#: judge/views/contests.py:319 msgid "" "You have been declared persona non grata for this contest. You are " "permanently barred from joining this contest." msgstr "" -#: judge/views/contests.py:414 +#: judge/views/contests.py:379 #, python-format msgid "Enter access code for \"%s\"" msgstr "" -#: judge/views/contests.py:425 +#: judge/views/contests.py:390 #, python-format msgid "You are not in contest \"%s\"." msgstr "" -#: judge/views/contests.py:444 +#: judge/views/contests.py:409 msgid "ContestCalendar requires integer year and month" msgstr "" -#: judge/views/contests.py:484 +#: judge/views/contests.py:449 #, python-format msgid "Contests in %(month)s" msgstr "" -#: judge/views/contests.py:484 +#: judge/views/contests.py:449 msgid "F Y" msgstr "" -#: judge/views/contests.py:532 +#: judge/views/contests.py:496 #, python-format msgid "%s Statistics" msgstr "" -#: judge/views/contests.py:717 +#: judge/views/contests.py:601 +msgid "???" +msgstr "" + +#: judge/views/contests.py:664 #, python-format msgid "%s Rankings" msgstr "" -#: judge/views/contests.py:725 -msgid "???" -msgstr "" - -#: judge/views/contests.py:741 +#: judge/views/contests.py:680 #, python-format msgid "Your participation in %s" msgstr "" -#: judge/views/contests.py:742 +#: judge/views/contests.py:681 #, python-format msgid "%s's participation in %s" msgstr "" -#: judge/views/contests.py:749 +#: judge/views/contests.py:685 msgid "Live" msgstr "" -#: judge/views/contests.py:761 templates/contest/contest-tabs.html:13 +#: judge/views/contests.py:697 msgid "Participation" msgstr "" -#: judge/views/contests.py:808 +#: judge/views/contests.py:743 #, python-format msgid "%s MOSS Results" msgstr "" -#: judge/views/contests.py:835 +#: judge/views/contests.py:770 #, python-format msgid "Running MOSS for %s..." msgstr "" -#: judge/views/contests.py:858 +#: judge/views/contests.py:793 #, python-format msgid "Contest tag: %s" msgstr "" -#: judge/views/contests.py:868 judge/views/ticket.py:57 -msgid "Issue description" -msgstr "" - -#: judge/views/contests.py:911 -#, python-format -msgid "New clarification for %s" -msgstr "" - #: judge/views/error.py:14 msgid "404 error" msgstr "" @@ -2521,83 +2410,76 @@ msgid "corrupt page %s" msgstr "" #: judge/views/language.py:12 templates/status/judge-status-table.html:9 -#: templates/status/status-tabs.html:5 msgid "Runtimes" msgstr "" -#: judge/views/notification.py:40 -#, python-format -msgid "Notifications (%d unseen)" -msgstr "" - -#: judge/views/organization.py:59 judge/views/organization.py:62 +#: judge/views/organization.py:44 judge/views/organization.py:47 msgid "No such organization" msgstr "" -#: judge/views/organization.py:60 +#: judge/views/organization.py:45 #, python-format msgid "Could not find an organization with the key \"%s\"." msgstr "" -#: judge/views/organization.py:63 +#: judge/views/organization.py:48 msgid "Could not find such organization." msgstr "" -#: judge/views/organization.py:79 judge/views/register.py:34 -#: templates/organization/list.html:32 templates/user/import/table_csv.html:9 -#: templates/user/user-list-tabs.html:6 +#: judge/views/organization.py:72 judge/views/register.py:34 +#: templates/organization/list.html:15 msgid "Organizations" msgstr "" -#: judge/views/organization.py:130 +#: judge/views/organization.py:93 #, python-format msgid "%s Members" msgstr "" -#: judge/views/organization.py:159 judge/views/organization.py:162 -#: judge/views/organization.py:167 +#: judge/views/organization.py:118 judge/views/organization.py:121 +#: judge/views/organization.py:126 msgid "Joining organization" msgstr "" -#: judge/views/organization.py:159 +#: judge/views/organization.py:118 msgid "You are already in the organization." msgstr "" -#: judge/views/organization.py:162 +#: judge/views/organization.py:121 msgid "This organization is not open." msgstr "" -#: judge/views/organization.py:179 +#: judge/views/organization.py:138 msgid "Leaving organization" msgstr "" -#: judge/views/organization.py:179 +#: judge/views/organization.py:138 #, python-format msgid "You are not in \"%s\"." msgstr "" -#: judge/views/organization.py:203 +#: judge/views/organization.py:162 #, python-format msgid "Request to join %s" msgstr "" -#: judge/views/organization.py:221 +#: judge/views/organization.py:180 msgid "Join request detail" msgstr "" -#: judge/views/organization.py:254 +#: judge/views/organization.py:209 #, python-format msgid "Managing join requests for %s" msgstr "" -#: judge/views/organization.py:285 +#: judge/views/organization.py:240 #, python-format msgid "" "Your organization can only receive %d more members. You cannot approve %d " "users." msgstr "" -#: judge/views/organization.py:297 +#: judge/views/organization.py:252 #, python-format msgid "Approved %d user." msgid_plural "Approved %d users." @@ -2605,7 +2487,7 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: judge/views/organization.py:298 +#: judge/views/organization.py:253 #, python-format msgid "Rejected %d user." msgid_plural "Rejected %d users." @@ -2613,32 +2495,32 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: judge/views/organization.py:328 +#: judge/views/organization.py:283 #, python-format msgid "Editing %s" msgstr "" -#: judge/views/organization.py:352 judge/views/organization.py:360 +#: judge/views/organization.py:307 judge/views/organization.py:315 msgid "Can't edit organization" msgstr "" -#: judge/views/organization.py:353 +#: judge/views/organization.py:308 msgid "You are not allowed to edit this organization." msgstr "" -#: judge/views/organization.py:361 +#: judge/views/organization.py:316 msgid "You are not allowed to kick people from this organization." msgstr "" -#: judge/views/organization.py:366 judge/views/organization.py:370 +#: judge/views/organization.py:321 judge/views/organization.py:325 msgid "Can't kick user" msgstr "" -#: judge/views/organization.py:367 +#: judge/views/organization.py:322 msgid "The user you are trying to kick does not exist!" msgstr "" -#: judge/views/organization.py:371 +#: judge/views/organization.py:326 #, python-format msgid "The user you are trying to kick is not in organization: %s." msgstr "" @@ -2662,36 +2544,35 @@ msgstr "" msgid "Editorial for {0}" msgstr "" -#: judge/views/problem.py:285 templates/contest/contest.html:79 -#: templates/user/user-about.html:28 templates/user/user-tabs.html:5 -#: templates/user/users-table.html:31 +#: judge/views/problem.py:286 templates/contest/contest.html:79 +#: templates/user/users-table.html:23 msgid "Problems" msgstr "" -#: judge/views/problem.py:585 +#: judge/views/problem.py:547 msgid "Banned from submitting" msgstr "" -#: judge/views/problem.py:586 +#: judge/views/problem.py:548 msgid "" "You have been declared persona non grata for this problem. You are " "permanently barred from submitting this problem." msgstr "" -#: judge/views/problem.py:600 +#: judge/views/problem.py:562 msgid "Too many submissions" msgstr "" -#: judge/views/problem.py:601 +#: judge/views/problem.py:563 msgid "You have exceeded the submission limit for this problem." msgstr "" -#: judge/views/problem.py:661 judge/views/problem.py:664 +#: judge/views/problem.py:633 judge/views/problem.py:636 #, python-format msgid "Submit to %(problem)s" msgstr "" -#: judge/views/problem.py:679 +#: judge/views/problem.py:652 msgid "Clone Problem" msgstr "" @@ -2732,22 +2613,22 @@ msgstr "" msgid "Generated init.yml for %s" msgstr "" -#: judge/views/problem_manage.py:52 judge/views/problem_manage.py:55 +#: judge/views/problem_manage.py:50 judge/views/problem_manage.py:53 #, python-format msgid "Managing submissions for %s" msgstr "" -#: judge/views/problem_manage.py:97 +#: judge/views/problem_manage.py:95 #, python-format msgid "Rejudging selected submissions for %s..." msgstr "" -#: judge/views/problem_manage.py:141 +#: judge/views/problem_manage.py:110 #, python-format msgid "Rescoring all submissions for %s..." msgstr "" -#: judge/views/problem_manage.py:150 +#: judge/views/problem_manage.py:119 #, python-format msgid "Successfully scheduled %d submission for rejudging." msgid_plural "Successfully scheduled %d submissions for rejudging." @@ -2797,24 +2678,24 @@ msgstr "" msgid "Subscribe to newsletter?" msgstr "" -#: judge/views/register.py:55 +#: judge/views/register.py:45 #, python-format msgid "" "The email address \"%s\" is already taken. Only one registration is allowed " "per address." msgstr "" -#: judge/views/register.py:61 +#: judge/views/register.py:51 msgid "" "Your email provider is not allowed due to history of abuse. Please use a " "reputable email provider." msgstr "" -#: judge/views/register.py:67 judge/views/register.py:105 +#: judge/views/register.py:57 judge/views/register.py:95 msgid "Registration" msgstr "" -#: judge/views/register.py:116 +#: judge/views/register.py:106 msgid "Authentication failure" msgstr "" @@ -2830,100 +2711,104 @@ msgstr "" msgid "Version matrix" msgstr "" -#: judge/views/submission.py:84 judge/views/submission.py:91 +#: judge/views/submission.py:83 judge/views/submission.py:90 #, python-format msgid "Submission of %(problem)s by %(user)s" msgstr "" -#: judge/views/submission.py:244 judge/views/submission.py:245 -#: templates/problem/problem.html:167 +#: judge/views/submission.py:227 judge/views/submission.py:228 +#: templates/problem/problem.html:127 msgid "All submissions" msgstr "" -#: judge/views/submission.py:404 +#: judge/views/submission.py:384 msgid "All my submissions" msgstr "" -#: judge/views/submission.py:405 +#: judge/views/submission.py:385 #, python-format msgid "All submissions by %s" msgstr "" -#: judge/views/submission.py:436 +#: judge/views/submission.py:416 #, python-format msgid "All submissions for %s" msgstr "" -#: judge/views/submission.py:455 +#: judge/views/submission.py:435 msgid "Must pass a problem" msgstr "" -#: judge/views/submission.py:501 +#: judge/views/submission.py:481 #, python-format msgid "My submissions for %(problem)s" msgstr "" -#: judge/views/submission.py:502 +#: judge/views/submission.py:482 #, python-format msgid "%(user)s's submissions for %(problem)s" msgstr "" -#: judge/views/submission.py:603 +#: judge/views/submission.py:583 msgid "Must pass a contest" msgstr "" -#: judge/views/submission.py:622 +#: judge/views/submission.py:602 #, python-brace-format msgid "" "{0}'s submissions for {2} in {4}" msgstr "" -#: judge/views/submission.py:629 +#: judge/views/submission.py:609 #, python-brace-format msgid "" "{0}'s submissions for problem {2} in {3}" "" msgstr "" -#: judge/views/ticket.py:50 judge/views/ticket.py:56 +#: judge/views/ticket.py:33 judge/views/ticket.py:39 msgid "Ticket title" msgstr "" -#: judge/views/ticket.py:107 judge/views/ticket.py:110 +#: judge/views/ticket.py:40 +msgid "Issue description" +msgstr "" + +#: judge/views/ticket.py:85 judge/views/ticket.py:88 #, python-format msgid "New ticket for %s" msgstr "" -#: judge/views/ticket.py:170 +#: judge/views/ticket.py:142 #, python-format msgid "%(title)s - Ticket %(id)d" msgstr "" -#: judge/views/ticket.py:279 +#: judge/views/ticket.py:251 #, python-format msgid "Tickets - Page %(number)d of %(total)d" msgstr "" -#: judge/views/ticket.py:328 +#: judge/views/ticket.py:300 #, python-format msgid "New Ticket: %s" msgstr "" -#: judge/views/ticket.py:329 +#: judge/views/ticket.py:301 #, python-format msgid "#%(id)d, assigned to: %(users)s" msgstr "" -#: judge/views/ticket.py:331 +#: judge/views/ticket.py:303 msgid ", " msgstr "" -#: judge/views/ticket.py:331 +#: judge/views/ticket.py:303 msgid "no one" msgstr "" -#: judge/views/ticket.py:351 +#: judge/views/ticket.py:323 #, python-format msgid "New Ticket Message For: %s" msgstr "" @@ -2940,50 +2825,41 @@ msgstr "" msgid "Perform Two Factor Authentication" msgstr "" -#: judge/views/user.py:74 +#: judge/views/user.py:68 msgid "No such user" msgstr "" -#: judge/views/user.py:74 +#: judge/views/user.py:68 #, python-format msgid "No user handle \"%s\"." msgstr "" -#: judge/views/user.py:78 +#: judge/views/user.py:72 msgid "My account" msgstr "" -#: judge/views/user.py:79 +#: judge/views/user.py:73 #, python-format msgid "User %s" msgstr "" -#: judge/views/user.py:148 -msgid "M j, Y" -msgstr "" - -#: judge/views/user.py:171 +#: judge/views/user.py:136 msgid "M j, Y, G:i" msgstr "" -#: judge/views/user.py:290 +#: judge/views/user.py:221 msgid "Updated on site" msgstr "" -#: judge/views/user.py:323 templates/admin/auth/user/change_form.html:14 -#: templates/admin/auth/user/change_form.html:17 templates/base.html:238 -#: templates/user/user-tabs.html:10 +#: judge/views/user.py:254 templates/admin/auth/user/change_form.html:14 +#: templates/admin/auth/user/change_form.html:17 templates/base.html:224 msgid "Edit profile" msgstr "" -#: judge/views/user.py:332 templates/user/user-list-tabs.html:4 +#: judge/views/user.py:263 msgid "Leaderboard" msgstr "" -#: judge/views/user.py:407 -msgid "Import Users" -msgstr "" - #: judge/views/widgets.py:48 judge/views/widgets.py:58 #, python-format msgid "Invalid upstream data: %s" @@ -3021,7 +2897,7 @@ msgid "View Submissions" msgstr "" #: templates/admin/judge/problem/change_form.html:17 -#: templates/user/user-base.html:112 +#: templates/user/user-base.html:61 msgid "View submissions" msgstr "" @@ -3036,145 +2912,90 @@ msgstr "" msgid "Rejudge" msgstr "" -#: templates/base.html:230 -#, python-format -msgid "Hello, %(username)s." -msgstr "" - -#: templates/base.html:236 templates/comments/list.html:89 -#: templates/contest/contest-list-tabs.html:24 -#: templates/contest/ranking-table.html:53 -#: templates/problem/problem-list-tabs.html:6 +#: templates/base.html:222 templates/comments/list.html:89 +#: templates/contest/ranking-table.html:39 #: templates/submission/info-base.html:12 -#: templates/submission/submission-list-tabs.html:15 msgid "Admin" msgstr "" -#: templates/base.html:245 +#: templates/base.html:231 msgid "Log out" msgstr "" -#: templates/base.html:254 +#: templates/base.html:240 #: templates/registration/password_reset_complete.html:4 msgid "Log in" msgstr "" -#: templates/base.html:255 templates/registration/registration_form.html:177 +#: templates/base.html:241 templates/registration/registration_form.html:177 msgid "or" msgstr "" -#: templates/base.html:256 +#: templates/base.html:242 msgid "Sign up" msgstr "" -#: templates/base.html:271 +#: templates/base.html:254 msgid "spectating" msgstr "" -#: templates/base.html:284 +#: templates/base.html:267 msgid "This site works best with JavaScript enabled." msgstr "" -#: templates/blog/blog.html:13 templates/comments/list.html:68 -#: templates/comments/list.html:83 templates/contest/contest-tabs.html:23 -#: templates/contest/tag-title.html:9 templates/flatpages/admin_link.html:3 -#: templates/license.html:10 templates/problem/editorial.html:14 +#: templates/blog/content.html:13 templates/comments/list.html:68 +#: templates/comments/list.html:83 templates/contest/tag-title.html:9 +#: templates/flatpages/admin_link.html:3 templates/license.html:10 +#: templates/problem/editorial.html:14 msgid "Edit" msgstr "" -#: templates/blog/blog.html:26 -#, python-format -msgid "" -"\n" -" posted on %(time)s\n" -" " -msgstr "" - -#: templates/blog/content.html:10 -#, python-brace-format -msgid "posted on {time}" -msgstr "" - -#: templates/blog/dashboard.html:21 -#, python-format -msgid "" -"\n" -" on %(time)s\n" -" " -msgstr "" - -#: templates/blog/list.html:93 +#: templates/blog/list.html:85 msgid "Blog" msgstr "" -#: templates/blog/list.html:95 +#: templates/blog/list.html:87 msgid "Events" msgstr "" -#: templates/blog/list.html:100 +#: templates/blog/list.html:92 msgid "News" msgstr "" -#: templates/blog/list.html:115 templates/problem/list.html:347 -#: templates/problem/problem.html:361 +#: templates/blog/list.html:130 templates/problem/problem.html:310 msgid "Clarifications" msgstr "" -#: templates/blog/list.html:121 -msgid "Add" -msgstr "" - -#: templates/blog/list.html:140 templates/problem/list.html:369 -#: templates/problem/problem.html:372 +#: templates/blog/list.html:146 templates/problem/problem.html:321 msgid "No clarifications have been made at this time." msgstr "" -#: templates/blog/list.html:148 +#: templates/blog/list.html:154 msgid "Ongoing contests" msgstr "" -#: templates/blog/list.html:166 +#: templates/blog/list.html:172 msgid "Upcoming contests" msgstr "" -#: templates/blog/list.html:184 -msgid "My open tickets" -msgstr "" - -#: templates/blog/list.html:206 -msgid "New tickets" -msgstr "" - -#: templates/blog/list.html:227 -msgid "New problems" -msgstr "" - -#: templates/blog/list.html:244 +#: templates/blog/list.html:189 msgid "Comment stream" msgstr "" -#: templates/chat/chat.html:305 -msgid "Chat" +#: templates/blog/list.html:208 +msgid "New problems" msgstr "" -#: templates/chat/chat.html:307 templates/chat/chat.html:314 -msgid "Online Users" +#: templates/blog/list.html:225 +msgid "My open tickets" msgstr "" -#: templates/chat/chat.html:315 -msgid "Refresh" +#: templates/blog/list.html:246 +msgid "New tickets" msgstr "" -#: templates/chat/chat.html:333 -msgid "Emoji" -msgstr "" - -#: templates/chat/chat.html:334 -msgid "Enter your message" -msgstr "" - -#: templates/chat/message.html:20 -msgid "Delete" +#: templates/chat/chat.html:167 +msgid "Your message" msgstr "" #: templates/comments/list.html:2 @@ -3185,21 +3006,11 @@ msgstr "" msgid "Please login to vote" msgstr "" -#: templates/comments/list.html:40 -#, python-brace-format -msgid "commented on {time}" -msgstr "" - -#: templates/comments/list.html:49 -#, python-format -msgid "edit %(edits)s" -msgstr "" - -#: templates/comments/list.html:51 templates/comments/media-js.html:92 +#: templates/comments/list.html:51 templates/comments/media-js.html:77 msgid "edited" msgstr "" -#: templates/comments/list.html:60 templates/notification/list.html:14 +#: templates/comments/list.html:60 msgid "Link" msgstr "" @@ -3207,52 +3018,36 @@ msgstr "" msgid "Reply" msgstr "" -#: templates/comments/list.html:86 templates/contest/list.html:91 -#: templates/contest/list.html:95 templates/contest/list.html:280 +#: templates/comments/list.html:86 msgid "Hide" msgstr "" -#: templates/comments/list.html:101 -#, python-format -msgid "" -"\n" -" This comment is hidden due " -"to too much negative feedback.\n" -" Click here to view it.\n" -" " -msgstr "" - -#: templates/comments/list.html:121 +#: templates/comments/list.html:120 msgid "There are no comments at the moment." msgstr "" -#: templates/comments/list.html:127 +#: templates/comments/list.html:126 msgid "New comment" msgstr "" -#: templates/comments/list.html:141 +#: templates/comments/list.html:140 msgid "Invalid comment body." msgstr "" -#: templates/comments/list.html:149 +#: templates/comments/list.html:148 msgid "Post!" msgstr "" -#: templates/comments/list.html:157 +#: templates/comments/list.html:156 msgid "Comments are disabled on this page." msgstr "" -#: templates/comments/media-js.html:38 -msgid "Replying to comment" -msgstr "" - -#: templates/comments/media-js.html:87 +#: templates/comments/media-js.html:72 #, python-brace-format msgid "edit {edits}" msgstr "" -#: templates/comments/media-js.html:90 +#: templates/comments/media-js.html:75 msgid "original" msgstr "" @@ -3296,11 +3091,6 @@ msgstr "" msgid "Saturday" msgstr "" -#: templates/contest/clarification.html:52 templates/organization/new.html:10 -#: templates/ticket/new.html:38 -msgid "Create" -msgstr "" - #: templates/contest/clone.html:37 msgid "Enter a new key for the cloned contest:" msgstr "" @@ -3321,171 +3111,97 @@ msgstr "" msgid "Next" msgstr "" -#: templates/contest/contest-list-tabs.html:21 -#: templates/problem/problem-list-tabs.html:5 -msgid "List" -msgstr "" - -#: templates/contest/contest-list-tabs.html:22 -msgid "Calendar" -msgstr "" - -#: templates/contest/contest-tabs.html:4 templates/organization/home.html:105 -msgid "Info" -msgstr "" - -#: templates/contest/contest-tabs.html:6 templates/stats/base.html:9 -#: templates/submission/list.html:339 -msgid "Statistics" -msgstr "" - -#: templates/contest/contest-tabs.html:11 -msgid "Rankings" -msgstr "" - -#: templates/contest/contest-tabs.html:16 -msgid "Hidden Rankings" -msgstr "" - -#: templates/contest/contest-tabs.html:21 -msgid "MOSS" -msgstr "" - -#: templates/contest/contest-tabs.html:26 -msgid "Clone" -msgstr "" - -#: templates/contest/contest-tabs.html:38 -#: templates/contest/contest-tabs.html:58 +#: templates/contest/contest-tabs.html:37 msgid "Leave contest" msgstr "" -#: templates/contest/contest-tabs.html:45 templates/contest/list.html:388 +#: templates/contest/contest-tabs.html:44 templates/contest/list.html:293 msgid "Virtual join" msgstr "" -#: templates/contest/contest-tabs.html:56 -msgid "Stop spectating" -msgstr "" - -#: templates/contest/contest-tabs.html:65 +#: templates/contest/contest-tabs.html:64 msgid "Spectate contest" msgstr "" -#: templates/contest/contest-tabs.html:72 +#: templates/contest/contest-tabs.html:70 +#: templates/contest/contest-tabs.html:76 msgid "Join contest" msgstr "" -#: templates/contest/contest-tabs.html:81 +#: templates/contest/contest-tabs.html:85 msgid "Login to participate" msgstr "" -#: templates/contest/contest.html:37 -msgid "Participating virtually." -msgstr "" - -#: templates/contest/contest.html:43 -msgid "Contest is over." -msgstr "" - #: templates/contest/contest.html:59 templates/contest/contest.html:63 msgid "F j, Y, G:i T" msgstr "" -#: templates/contest/contest.html:59 -#, python-format -msgid "" -"%(time_limit)s window between %(start_time)s and " -"%(end_time)s" -msgstr "" - -#: templates/contest/contest.html:63 -#, python-format -msgid "%(length)s long starting on %(start_time)s" -msgstr "" - #: templates/contest/contest.html:85 msgid "AC Rate" msgstr "" -#: templates/contest/contest.html:86 templates/contest/list.html:237 -#: templates/contest/list.html:289 templates/contest/list.html:366 -#: templates/problem/list.html:223 templates/problem/list.html:254 +#: templates/contest/contest.html:86 templates/contest/list.html:153 +#: templates/contest/list.html:195 templates/contest/list.html:271 +#: templates/problem/list.html:212 templates/problem/list.html:238 msgid "Users" msgstr "" -#: templates/contest/contest.html:111 templates/problem/list.html:330 +#: templates/contest/contest.html:111 msgid "Editorial" msgstr "" -#: templates/contest/list.html:83 templates/contest/media-js.html:9 +#: templates/contest/list.html:31 templates/contest/media-js.html:9 msgid "Are you sure you want to join?" msgstr "" -#: templates/contest/list.html:84 +#: templates/contest/list.html:32 msgid "" "Joining a contest for the first time starts your timer, after which it " "becomes unstoppable." msgstr "" -#: templates/contest/list.html:92 templates/contest/list.html:278 -msgid "Show" -msgstr "" - -#: templates/contest/list.html:102 templates/problem/list.html:68 -msgid "Organizations..." -msgstr "" - -#: templates/contest/list.html:135 +#: templates/contest/list.html:65 msgid "hidden" msgstr "" -#: templates/contest/list.html:140 +#: templates/contest/list.html:70 msgid "private" msgstr "" -#: templates/contest/list.html:154 +#: templates/contest/list.html:84 msgid "rated" msgstr "" -#: templates/contest/list.html:202 +#: templates/contest/list.html:132 msgid "Spectate" msgstr "" -#: templates/contest/list.html:208 +#: templates/contest/list.html:138 msgid "Join" msgstr "" -#: templates/contest/list.html:220 -msgid "Search contests..." -msgstr "" - -#: templates/contest/list.html:229 -msgid "Search" -msgstr "" - -#: templates/contest/list.html:232 +#: templates/contest/list.html:148 msgid "Active Contests" msgstr "" -#: templates/contest/list.html:236 templates/contest/list.html:288 -#: templates/contest/list.html:327 templates/contest/list.html:365 +#: templates/contest/list.html:152 templates/contest/list.html:194 +#: templates/contest/list.html:232 templates/contest/list.html:270 msgid "Contest" msgstr "" -#: templates/contest/list.html:275 +#: templates/contest/list.html:190 msgid "Ongoing Contests" msgstr "" -#: templates/contest/list.html:322 +#: templates/contest/list.html:227 msgid "Upcoming Contests" msgstr "" -#: templates/contest/list.html:350 +#: templates/contest/list.html:255 msgid "There are no scheduled contests at this time." msgstr "" -#: templates/contest/list.html:356 +#: templates/contest/list.html:261 msgid "Past Contests" msgstr "" @@ -3536,71 +3252,47 @@ msgstr "" msgid "Only the following organizations may access this contest:" msgstr "" -#: templates/contest/ranking-table.html:9 templates/problem/search-form.html:35 +#: templates/contest/ranking-table.html:7 msgid "Organization" msgstr "" -#: templates/contest/ranking-table.html:10 templates/user/users-table.html:13 -msgid "Full Name" -msgstr "" - -#: templates/contest/ranking-table.html:44 +#: templates/contest/ranking-table.html:30 msgid "Un-Disqualify" msgstr "" -#: templates/contest/ranking-table.html:47 +#: templates/contest/ranking-table.html:33 msgid "Disqualify" msgstr "" -#: templates/contest/ranking.html:187 +#: templates/contest/ranking.html:173 msgid "Are you sure you want to disqualify this participation?" msgstr "" -#: templates/contest/ranking.html:192 +#: templates/contest/ranking.html:178 msgid "Are you sure you want to un-disqualify this participation?" msgstr "" -#: templates/contest/ranking.html:463 +#: templates/contest/ranking.html:252 msgid "View user participation" msgstr "" -#: templates/contest/ranking.html:467 +#: templates/contest/ranking.html:256 msgid "Show organizations" msgstr "" -#: templates/contest/ranking.html:471 -msgid "Show full name" -msgstr "" - -#: templates/contest/ranking.html:474 -msgid "Show friends only" -msgstr "" - -#: templates/contest/ranking.html:477 -msgid "Total score only" -msgstr "" - -#: templates/contest/ranking.html:479 -msgid "Show virtual participation" -msgstr "" - -#: templates/contest/stats.html:51 +#: templates/contest/stats.html:38 msgid "Problem Status Distribution" msgstr "" -#: templates/contest/stats.html:56 +#: templates/contest/stats.html:43 msgid "Problem AC Rate" msgstr "" -#: templates/contest/stats.html:62 -msgid "Problem Point Distribution" -msgstr "" - -#: templates/contest/stats.html:76 templates/stats/language.html:16 +#: templates/contest/stats.html:48 templates/stats/language.html:16 msgid "Submissions by Language" msgstr "" -#: templates/contest/stats.html:82 templates/stats/language.html:26 +#: templates/contest/stats.html:54 templates/stats/language.html:26 msgid "Language AC Rate" msgstr "" @@ -3609,7 +3301,6 @@ msgid "Source:" msgstr "" #: templates/newsletter/common.html:6 -#: templates/newsletter/newsletter_list.html:15 #: templates/newsletter/subscription_unsubscribe_activated.html:3 #: templates/newsletter/subscription_unsubscribe_activated.html:6 #: templates/newsletter/subscription_update_activated.html:3 @@ -3617,23 +3308,6 @@ msgstr "" msgid "Newsletter" msgstr "" -#: templates/newsletter/newsletter_list.html:2 -#: templates/newsletter/newsletter_list.html:3 -msgid "Newsletter list" -msgstr "" - -#: templates/newsletter/newsletter_list.html:6 -msgid "Subscribe to get the latest emails about upcoming contests and events." -msgstr "" - -#: templates/newsletter/newsletter_list.html:16 -msgid "Subscribe" -msgstr "" - -#: templates/newsletter/newsletter_list.html:30 -msgid "Update subscriptions" -msgstr "" - #: templates/newsletter/subscription_unsubscribe_activated.html:3 #: templates/newsletter/subscription_unsubscribe_activated.html:6 #: templates/newsletter/subscription_update_activated.html:3 @@ -3695,97 +3369,64 @@ msgid "" "follow in order to update your subscription." msgstr "" -#: templates/notification/list.html:7 -msgid "You have no notifications" -msgstr "" - -#: templates/notification/list.html:13 -msgid "Activity" -msgstr "" - #: templates/organization/edit.html:46 #: templates/organization/requests/pending.html:34 #: templates/ticket/edit-notes.html:4 msgid "Update" msgstr "" -#: templates/organization/home.html:41 +#: templates/organization/home.html:7 msgid "Are you sure you want to leave this organization?" msgstr "" -#: templates/organization/home.html:43 +#: templates/organization/home.html:9 msgid "You will have to rejoin to show up on the organization leaderboard." msgstr "" -#: templates/organization/home.html:45 +#: templates/organization/home.html:11 msgid "You will have to request membership in order to join again." msgstr "" -#: templates/organization/home.html:88 -msgid "Join organization" -msgstr "" - -#: templates/organization/home.html:92 -msgid "Request membership" -msgstr "" - -#: templates/organization/home.html:122 -msgid "Organization news" -msgstr "" - -#: templates/organization/home.html:128 -msgid "There is no news at this time." -msgstr "" - -#: templates/organization/home.html:137 -msgid "Controls" -msgstr "" - -#: templates/organization/home.html:142 -msgid "Edit organization" -msgstr "" - -#: templates/organization/home.html:148 -msgid "View requests" -msgstr "" - -#: templates/organization/home.html:161 -msgid "Admin organization" -msgstr "" - -#: templates/organization/home.html:167 -msgid "View members" -msgstr "" - -#: templates/organization/home.html:174 +#: templates/organization/home.html:24 msgid "Leave organization" msgstr "" -#: templates/organization/home.html:183 -msgid "New private contests" +#: templates/organization/home.html:29 +msgid "Join organization" msgstr "" -#: templates/organization/home.html:193 templates/organization/home.html:208 -msgid "View all" +#: templates/organization/home.html:33 +msgid "Request membership" msgstr "" -#: templates/organization/home.html:199 -msgid "New private problems" +#: templates/organization/home.html:39 +msgid "Edit organization" msgstr "" -#: templates/organization/list.html:40 -msgid "Show my organizations only" +#: templates/organization/home.html:43 +msgid "View requests" msgstr "" -#: templates/organization/list.html:47 templates/status/language-list.html:34 -#: templates/user/import/table_csv.html:6 +#: templates/organization/home.html:50 +msgid "Admin organization" +msgstr "" + +#: templates/organization/home.html:55 +msgid "View members" +msgstr "" + +#: templates/organization/list.html:23 templates/status/language-list.html:34 msgid "Name" msgstr "" -#: templates/organization/list.html:48 +#: templates/organization/list.html:24 msgid "Members" msgstr "" +#: templates/organization/new.html:10 templates/ticket/new.html:38 +msgid "Create" +msgstr "" + #: templates/organization/requests/detail.html:13 msgid "User:" msgstr "" @@ -3818,7 +3459,7 @@ msgid "There are no requests to approve." msgstr "" #: templates/organization/requests/pending.html:17 -#: templates/problem/data.html:432 +#: templates/problem/data.html:452 msgid "Delete?" msgstr "" @@ -3854,35 +3495,35 @@ msgstr "" msgid "Enter a new code for the cloned problem:" msgstr "" -#: templates/problem/data.html:119 +#: templates/problem/data.html:108 msgid "Instruction" msgstr "" -#: templates/problem/data.html:390 +#: templates/problem/data.html:410 msgid "View YAML" msgstr "" -#: templates/problem/data.html:421 templates/problem/data.html:472 +#: templates/problem/data.html:441 templates/problem/data.html:491 msgid "Apply!" msgstr "" -#: templates/problem/data.html:426 +#: templates/problem/data.html:446 msgid "Type" msgstr "" -#: templates/problem/data.html:427 +#: templates/problem/data.html:447 msgid "Input file" msgstr "" -#: templates/problem/data.html:428 +#: templates/problem/data.html:448 msgid "Output file" msgstr "" -#: templates/problem/data.html:430 +#: templates/problem/data.html:450 msgid "Pretest?" msgstr "" -#: templates/problem/data.html:473 +#: templates/problem/data.html:492 msgid "Add new case" msgstr "" @@ -3894,32 +3535,28 @@ msgid "" "problem yourself is a bannable offence." msgstr "" -#: templates/problem/list.html:66 +#: templates/problem/list.html:62 msgid "Filter by type..." msgstr "" -#: templates/problem/list.html:193 +#: templates/problem/list.html:185 msgid "Hot problems" msgstr "" -#: templates/problem/list.html:218 templates/problem/list.html:240 -#: templates/problem/search-form.html:45 templates/user/user-problems.html:57 +#: templates/problem/list.html:207 templates/problem/list.html:224 +#: templates/problem/search-form.html:30 templates/user/user-problems.html:57 msgid "Category" msgstr "" -#: templates/problem/list.html:220 templates/problem/list.html:244 +#: templates/problem/list.html:209 templates/problem/list.html:228 msgid "Types" msgstr "" -#: templates/problem/list.html:251 +#: templates/problem/list.html:235 #, python-format msgid "AC %%" msgstr "" -#: templates/problem/list.html:342 -msgid "Add clarifications" -msgstr "" - #: templates/problem/manage_submission.html:55 msgid "Leave empty to not filter by language" msgstr "" @@ -3928,203 +3565,152 @@ msgstr "" msgid "Leave empty to not filter by result" msgstr "" -#: templates/problem/manage_submission.html:80 +#: templates/problem/manage_submission.html:79 msgid "Need valid values for both start and end IDs." msgstr "" -#: templates/problem/manage_submission.html:83 +#: templates/problem/manage_submission.html:82 msgid "End ID must be after start ID." msgstr "" +#: templates/problem/manage_submission.html:90 +#, python-brace-format +msgid "" +"You are about to rejudge {count} submissions. Are you sure you want to do " +"this?" +msgstr "" + #: templates/problem/manage_submission.html:96 -#, python-brace-format msgid "" -"You are about to {action} {count} submissions. Are you sure you want to do " -"this?" +"You are about to rejudge a few submissions. Are you sure you want to do this?" msgstr "" -#: templates/problem/manage_submission.html:103 -#, python-brace-format -msgid "" -"You are about to {action} a few submissions. Are you sure you want to do " -"this?" +#: templates/problem/manage_submission.html:115 +msgid "Rejudge Submissions" msgstr "" -#: templates/problem/manage_submission.html:127 -#: templates/submission/list.html:309 -msgid "Filter submissions" -msgstr "" - -#: templates/problem/manage_submission.html:132 +#: templates/problem/manage_submission.html:120 msgid "Filter by ID:" msgstr "" -#: templates/problem/manage_submission.html:135 +#: templates/problem/manage_submission.html:123 msgid "Starting ID:" msgstr "" -#: templates/problem/manage_submission.html:139 +#: templates/problem/manage_submission.html:127 msgid "Ending ID:" msgstr "" -#: templates/problem/manage_submission.html:143 +#: templates/problem/manage_submission.html:131 msgid "This range includes both endpoints." msgstr "" -#: templates/problem/manage_submission.html:146 +#: templates/problem/manage_submission.html:134 msgid "Filter by language:" msgstr "" -#: templates/problem/manage_submission.html:154 +#: templates/problem/manage_submission.html:142 msgid "Filter by result:" msgstr "" -#: templates/problem/manage_submission.html:164 -msgid "Action" -msgstr "" - -#: templates/problem/manage_submission.html:166 +#: templates/problem/manage_submission.html:150 msgid "Rejudge selected submissions" msgstr "" -#: templates/problem/manage_submission.html:171 -msgid "Download selected submissions" +#: templates/problem/manage_submission.html:157 +msgid "Rescore Everything" msgstr "" -#: templates/problem/manage_submission.html:177 -#, python-format -msgid "Are you sure you want to rescore %(count)d submissions?" -msgstr "" - -#: templates/problem/manage_submission.html:178 +#: templates/problem/manage_submission.html:163 msgid "Rescore all submissions" msgstr "" -#: templates/problem/problem.html:132 +#: templates/problem/problem.html:91 msgid "View as PDF" msgstr "" -#: templates/problem/problem.html:141 templates/problem/problem.html:151 -#: templates/problem/problem.html:156 +#: templates/problem/problem.html:101 templates/problem/problem.html:111 +#: templates/problem/problem.html:116 msgid "Submit solution" msgstr "" -#: templates/problem/problem.html:144 -#, python-format -msgid "%(counter)s submission left" -msgid_plural "%(counter)s submissions left" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" - -#: templates/problem/problem.html:152 +#: templates/problem/problem.html:112 msgid "0 submissions left" msgstr "" -#: templates/problem/problem.html:164 +#: templates/problem/problem.html:124 msgid "My submissions" msgstr "" -#: templates/problem/problem.html:168 +#: templates/problem/problem.html:128 msgid "Best submissions" msgstr "" -#: templates/problem/problem.html:172 +#: templates/problem/problem.html:132 msgid "Read editorial" msgstr "" -#: templates/problem/problem.html:177 +#: templates/problem/problem.html:137 msgid "Manage tickets" msgstr "" -#: templates/problem/problem.html:181 +#: templates/problem/problem.html:141 msgid "Edit problem" msgstr "" -#: templates/problem/problem.html:183 +#: templates/problem/problem.html:143 msgid "Edit test data" msgstr "" -#: templates/problem/problem.html:188 +#: templates/problem/problem.html:148 msgid "My tickets" msgstr "" -#: templates/problem/problem.html:196 +#: templates/problem/problem.html:156 msgid "Manage submissions" msgstr "" -#: templates/problem/problem.html:202 +#: templates/problem/problem.html:162 msgid "Clone problem" msgstr "" -#: templates/problem/problem.html:209 +#: templates/problem/problem.html:169 msgid "Points:" msgstr "" -#: templates/problem/problem.html:212 templates/problem/problem.html:214 +#: templates/problem/problem.html:172 templates/problem/problem.html:174 msgid "(partial)" msgstr "" -#: templates/problem/problem.html:219 +#: templates/problem/problem.html:179 msgid "Time limit:" msgstr "" -#: templates/problem/problem.html:231 +#: templates/problem/problem.html:191 msgid "Memory limit:" msgstr "" -#: templates/problem/problem.html:250 -msgid "Author:" -msgid_plural "Authors:" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" - -#: templates/problem/problem.html:265 -msgid "Problem type" -msgid_plural "Problem types" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" - -#: templates/problem/problem.html:278 +#: templates/problem/problem.html:238 msgid "Allowed languages" msgstr "" -#: templates/problem/problem.html:286 -#, python-format -msgid "No %(lang)s judge online" -msgstr "" - -#: templates/problem/problem.html:297 -msgid "Judge:" -msgid_plural "Judges:" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" - -#: templates/problem/problem.html:314 +#: templates/problem/problem.html:274 msgid "none available" msgstr "" -#: templates/problem/problem.html:326 -#, python-format -msgid "This problem has %(length)s clarification(s)" -msgstr "" - -#: templates/problem/problem.html:350 +#: templates/problem/problem.html:299 msgid "Request clarification" msgstr "" -#: templates/problem/problem.html:352 +#: templates/problem/problem.html:301 msgid "Report an issue" msgstr "" -#: templates/problem/raw.html:64 +#: templates/problem/raw.html:62 msgid "Time Limit:" msgstr "" -#: templates/problem/raw.html:73 +#: templates/problem/raw.html:71 msgid "Memory Limit:" msgstr "" @@ -4148,74 +3734,39 @@ msgstr "" msgid "Show problem types" msgstr "" -#: templates/problem/search-form.html:32 -msgid "Show editorial" -msgstr "" - -#: templates/problem/search-form.html:48 templates/problem/search-form.html:50 -#: templates/submission/submission-list-tabs.html:4 +#: templates/problem/search-form.html:33 templates/problem/search-form.html:35 msgid "All" msgstr "" -#: templates/problem/search-form.html:62 +#: templates/problem/search-form.html:46 msgid "Problem types" msgstr "" -#: templates/problem/search-form.html:73 +#: templates/problem/search-form.html:57 msgid "Point range" msgstr "" -#: templates/problem/search-form.html:79 templates/submission/list.html:331 +#: templates/problem/search-form.html:63 templates/submission/list.html:331 #: templates/ticket/list.html:248 msgid "Go" msgstr "" -#: templates/problem/search-form.html:80 +#: templates/problem/search-form.html:64 msgid "Random" msgstr "" -#: templates/problem/submit.html:117 -msgid "Your source code must contain at most 65536 characters." -msgstr "" - -#: templates/problem/submit.html:204 -#, python-format -msgid "" -"Warning! Your default language, %(default_language)s, is " -"unavailable for this problem and has been deselected." -msgstr "" - -#: templates/problem/submit.html:215 -#, python-format -msgid "" -"\n" -" You have %(left)s submission left\n" -" " -msgid_plural "" -"\n" -" You have %(left)s submissions left\n" -" " -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" - -#: templates/problem/submit.html:224 +#: templates/problem/submit.html:212 msgid "You have 0 submissions left" msgstr "" -#: templates/problem/submit.html:258 +#: templates/problem/submit.html:250 msgid "No judge is available for this problem." msgstr "" -#: templates/problem/submit.html:262 +#: templates/problem/submit.html:252 msgid "Submit!" msgstr "" -#: templates/registration/activate.html:3 -#, python-format -msgid "%(key)s is an invalid activation key." -msgstr "" - #: templates/registration/activation_complete.html:3 msgid "Your account has been successfully activated." msgstr "" @@ -4273,13 +3824,6 @@ msgid "" "you registered with, and check your spam folder." msgstr "" -#: templates/registration/password_reset_email.txt:1 -#, python-format -msgid "" -"You're receiving this email because you requested a password reset for your " -"user account at %(site_name)s." -msgstr "" - #: templates/registration/password_reset_email.txt:3 msgid "Please go to the following page and choose a new password:" msgstr "" @@ -4292,16 +3836,6 @@ msgstr "" msgid "Thanks for using our site!" msgstr "" -#: templates/registration/password_reset_email.txt:11 -#, python-format -msgid "The %(site_name)s team" -msgstr "" - -#: templates/registration/password_reset_subject.txt:1 -#, python-format -msgid "Password reset on %(site_name)s" -msgstr "" - #: templates/registration/profile_creation.html:36 #: templates/registration/username_select.html:7 msgid "Continue >" @@ -4338,20 +3872,19 @@ msgstr "" msgid "Affiliated organizations" msgstr "" -#: templates/registration/registration_form.html:195 -#: templates/user/edit-profile.html:128 +#: templates/registration/registration_form.html:192 msgid "Notify me about upcoming contests" msgstr "" -#: templates/registration/registration_form.html:209 +#: templates/registration/registration_form.html:206 msgid "By registering, you agree to our" msgstr "" -#: templates/registration/registration_form.html:210 +#: templates/registration/registration_form.html:207 msgid "Terms & Conditions" msgstr "" -#: templates/registration/registration_form.html:213 +#: templates/registration/registration_form.html:210 msgid "Register!" msgstr "" @@ -4361,11 +3894,6 @@ msgstr "" msgid "Enter the 6-digit code generated by your app:" msgstr "" -#: templates/registration/totp_auth.html:41 -#, python-format -msgid "If you lost your authentication device, please contact us at %(email)s." -msgstr "" - #: templates/registration/totp_disable.html:38 msgid "" "To protect your account, you must first authenticate before you can disable " @@ -4384,6 +3912,10 @@ msgstr "" msgid "Or enter this code manually:" msgstr "" +#: templates/stats/base.html:9 templates/submission/list.html:339 +msgid "Statistics" +msgstr "" + #: templates/stats/language.html:11 msgid "Submission Statistics" msgstr "" @@ -4409,7 +3941,6 @@ msgid "Ping" msgstr "" #: templates/status/judge-status-table.html:8 -#: templates/user/import/index.html:104 msgid "Load" msgstr "" @@ -4425,7 +3956,6 @@ msgid "There are no judges available at this time." msgstr "" #: templates/status/language-list.html:33 templates/ticket/list.html:261 -#: templates/user/import/table_csv.html:3 msgid "ID" msgstr "" @@ -4433,22 +3963,6 @@ msgstr "" msgid "Runtime Info" msgstr "" -#: templates/status/status-tabs.html:4 -msgid "Judges" -msgstr "" - -#: templates/status/status-tabs.html:6 -msgid "Version Matrix" -msgstr "" - -#: templates/submission/internal-error-message.html:3 -#, python-format -msgid "" -"An internal error occurred while grading, and the %(SITE_NAME)s " -"administrators have been notified.
In the meantime, try resubmitting in " -"a few seconds." -msgstr "" - #: templates/submission/internal-error-message.html:8 msgid "An internal error occurred while grading." msgstr "" @@ -4465,6 +3979,10 @@ msgstr "" msgid "Filter by language..." msgstr "" +#: templates/submission/list.html:309 +msgid "Filter submissions" +msgstr "" + #: templates/submission/list.html:345 msgid "Total:" msgstr "" @@ -4521,64 +4039,63 @@ msgstr "" msgid "Execution Results" msgstr "" -#: templates/submission/status-testcases.html:34 -msgid "Overall: " -msgstr "" - -#: templates/submission/status-testcases.html:48 -msgid "Point: " -msgstr "" - -#: templates/submission/status-testcases.html:53 -msgid "Time: " -msgstr "" - -#: templates/submission/status-testcases.html:62 -msgid "Memory: " -msgstr "" - -#: templates/submission/status-testcases.html:73 +#: templates/submission/status-testcases.html:31 msgid "Batch " msgstr "" -#: templates/submission/status-testcases.html:84 -#: templates/submission/status-testcases.html:113 -msgid "Point" +#: templates/submission/status-testcases.html:43 +msgid "Overall: " msgstr "" -#: templates/submission/status-testcases.html:99 +#: templates/submission/status-testcases.html:57 +msgid "Point: " +msgstr "" + +#: templates/submission/status-testcases.html:62 +msgid "Time: " +msgstr "" + +#: templates/submission/status-testcases.html:71 +msgid "Memory: " +msgstr "" + +#: templates/submission/status-testcases.html:84 msgid "Case" msgstr "" -#: templates/submission/status-testcases.html:101 +#: templates/submission/status-testcases.html:86 msgid "Pretest" msgstr "" -#: templates/submission/status-testcases.html:103 +#: templates/submission/status-testcases.html:88 msgid "Test case" msgstr "" -#: templates/submission/status-testcases.html:141 +#: templates/submission/status-testcases.html:99 +msgid "Point" +msgstr "" + +#: templates/submission/status-testcases.html:121 msgid "Input:" msgstr "" -#: templates/submission/status-testcases.html:145 +#: templates/submission/status-testcases.html:125 msgid "Output:" msgstr "" -#: templates/submission/status-testcases.html:149 +#: templates/submission/status-testcases.html:129 msgid "Answer:" msgstr "" -#: templates/submission/status-testcases.html:154 +#: templates/submission/status-testcases.html:134 msgid "Judge feedback:" msgstr "" -#: templates/submission/status-testcases.html:175 +#: templates/submission/status-testcases.html:157 msgid "Passing pretests does not guarantee a full score on system tests." msgstr "" -#: templates/submission/status-testcases.html:178 +#: templates/submission/status-testcases.html:160 msgid "Submission aborted!" msgstr "" @@ -4590,24 +4107,11 @@ msgstr "" msgid "Abort" msgstr "" -#: templates/submission/submission-list-tabs.html:6 -msgid "Mine" -msgstr "" - -#: templates/submission/submission-list-tabs.html:9 -msgid "Best" -msgstr "" - -#: templates/submission/submission-list-tabs.html:12 -#, python-format -msgid "%(user)s's" -msgstr "" - -#: templates/ticket/list.html:135 templates/ticket/ticket.html:273 +#: templates/ticket/list.html:135 templates/ticket/ticket.html:257 msgid "Reopened: " msgstr "" -#: templates/ticket/list.html:138 templates/ticket/ticket.html:274 +#: templates/ticket/list.html:138 templates/ticket/ticket.html:258 msgid "Closed: " msgstr "" @@ -4631,7 +4135,7 @@ msgstr "" msgid "Title" msgstr "" -#: templates/ticket/list.html:264 templates/ticket/ticket.html:369 +#: templates/ticket/list.html:264 templates/ticket/ticket.html:328 msgid "Assignees" msgstr "" @@ -4646,36 +4150,32 @@ msgid "" "a problem, ask in the comments instead." msgstr "" -#: templates/ticket/ticket.html:355 -msgid "Post" -msgstr "" - -#: templates/ticket/ticket.html:363 +#: templates/ticket/ticket.html:322 msgid "Associated object" msgstr "" -#: templates/ticket/ticket.html:374 +#: templates/ticket/ticket.html:333 msgid "No one is assigned." msgstr "" -#: templates/ticket/ticket.html:380 +#: templates/ticket/ticket.html:339 msgid "Close ticket" msgstr "" -#: templates/ticket/ticket.html:382 +#: templates/ticket/ticket.html:341 msgid "Reopen ticket" msgstr "" -#: templates/ticket/ticket.html:386 +#: templates/ticket/ticket.html:345 msgid "Assignee notes" msgstr "" -#: templates/ticket/ticket.html:393 templates/widgets/select_all.html:4 +#: templates/ticket/ticket.html:352 templates/widgets/select_all.html:4 msgid "Nothing here." msgstr "" -#: templates/user/base-users-table.html:3 -msgid "Rank" +#: templates/ticket/ticket.html:385 +msgid "Post" msgstr "" #: templates/user/base-users.html:14 templates/user/base-users.html:69 @@ -4722,169 +4222,50 @@ msgstr "" msgid "Update profile" msgstr "" -#: templates/user/import/index.html:31 -msgid "Upload CSV only" -msgstr "" - -#: templates/user/import/index.html:100 -msgid "User File" -msgstr "" - -#: templates/user/import/index.html:102 -msgid "Sample" -msgstr "" - -#: templates/user/import/index.html:105 templates/user/user-list-tabs.html:8 -msgid "Import" -msgstr "" - -#: templates/user/import/table_csv.html:7 -msgid "School" -msgstr "" - -#: templates/user/pp-row.html:22 -#, python-format -msgid "" -"\n" -" weighted %(weight)s%%\n" -" " -msgstr "" - -#: templates/user/pp-row.html:27 -#, python-format -msgid "%(pp).1fpp" -msgstr "" - -#: templates/user/pp-row.html:29 -#, python-format -msgid "%(pp).0fpp" -msgstr "" - -#: templates/user/user-about.html:23 -#, python-format -msgid "%(counter)s problem solved" -msgid_plural "%(counter)s problems solved" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" - -#: templates/user/user-about.html:35 -msgid "Total points" -msgstr "" - -#: templates/user/user-about.html:45 -msgid "Rank by rating" -msgstr "" - -#: templates/user/user-about.html:52 -msgid "Rank by points" -msgstr "" - -#: templates/user/user-about.html:64 +#: templates/user/user-about.html:14 msgid "From" msgstr "" -#: templates/user/user-about.html:75 +#: templates/user/user-about.html:25 msgid "Admin Notes" msgstr "" -#: templates/user/user-about.html:90 +#: templates/user/user-about.html:40 msgid "You have not shared any information." msgstr "" -#: templates/user/user-about.html:92 +#: templates/user/user-about.html:42 msgid "This user has not shared any information." msgstr "" -#: templates/user/user-about.html:101 -msgid "Awards" +#: templates/user/user-base.html:50 +msgid "Rank by points:" msgstr "" -#: templates/user/user-about.html:112 -#, python-format -msgid "%(label)s (%(date)s)" +#: templates/user/user-base.html:53 +msgid "Total points:" msgstr "" -#: templates/user/user-about.html:130 -msgid "Mon" +#: templates/user/user-base.html:68 +msgid "Rank by rating:" msgstr "" -#: templates/user/user-about.html:135 -msgid "Tues" +#: templates/user/user-base.html:70 +msgid "Rating:" msgstr "" -#: templates/user/user-about.html:140 -msgid "Wed" -msgstr "" - -#: templates/user/user-about.html:145 -msgid "Thurs" -msgstr "" - -#: templates/user/user-about.html:150 -msgid "Fri" -msgstr "" - -#: templates/user/user-about.html:155 -msgid "Sat" -msgstr "" - -#: templates/user/user-about.html:160 -msgid "Sun" -msgstr "" - -#: templates/user/user-about.html:169 -msgid "Less" -msgstr "" - -#: templates/user/user-about.html:175 -msgid "More" -msgstr "" - -#: templates/user/user-about.html:184 -msgid "Rating History" -msgstr "" - -#: templates/user/user-about.html:255 -msgid "past year" -msgstr "" - -#: templates/user/user-about.html:272 -msgid "total submission(s)" -msgstr "" - -#: templates/user/user-about.html:276 -msgid "submissions in the last year" -msgstr "" - -#: templates/user/user-base.html:101 -msgid "Unfollow" -msgstr "" - -#: templates/user/user-base.html:104 -msgid "Follow" -msgstr "" - -#: templates/user/user-base.html:120 -msgid "Contests written" -msgstr "" - -#: templates/user/user-base.html:124 +#: templates/user/user-base.html:71 msgid "Volatility:" msgstr "" -#: templates/user/user-base.html:128 +#: templates/user/user-base.html:72 msgid "Min. rating:" msgstr "" -#: templates/user/user-base.html:132 +#: templates/user/user-base.html:73 msgid "Max rating:" msgstr "" -#: templates/user/user-list-tabs.html:5 -msgid "Friends" -msgstr "" - #: templates/user/user-problems.html:35 msgid "Points Breakdown" msgstr "" @@ -4905,32 +4286,10 @@ msgstr "" msgid "Hide problems I've solved" msgstr "" -#: templates/user/user-problems.html:93 -#, python-format -msgid "%(points).1f points" -msgstr "" - #: templates/user/user-problems.html:99 msgid "Score" msgstr "" -#: templates/user/user-problems.html:110 -#, python-format -msgid "%(points)s / %(total)s" -msgstr "" - -#: templates/user/user-tabs.html:7 -msgid "Impersonate" -msgstr "" - -#: templates/user/user-tabs.html:13 -msgid "Admin User" -msgstr "" - -#: templates/user/user-tabs.html:16 -msgid "Admin Profile" -msgstr "" - #: templates/widgets/select_all.html:8 msgid "Check all" msgstr "" diff --git a/locale/sr/LC_MESSAGES/djangojs.po b/locale/sr/LC_MESSAGES/djangojs.po index 8276129..db00c34 100644 --- a/locale/sr/LC_MESSAGES/djangojs.po +++ b/locale/sr/LC_MESSAGES/djangojs.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: dmoj\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-07-20 23:30+0700\n" +"POT-Creation-Date: 2016-11-12 01:20-0500\n" "PO-Revision-Date: 2016-12-22 21:23-0500\n" "Last-Translator: Icyene \n" "Language-Team: Serbian (Latin)\n" @@ -10,14 +10,13 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" -"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: dmoj\n" "X-Crowdin-Language: sr-CS\n" "X-Crowdin-File: djangojs.po\n" -#: resources/common.js:207 +#: .\resources\common.js:185 msgctxt "time format with day" msgid "%d day %h:%m:%s" msgid_plural "%d days %h:%m:%s" @@ -25,7 +24,8 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: resources/common.js:210 +#: .\resources\common.js:188 msgctxt "time format without day" msgid "%h:%m:%s" msgstr "" + diff --git a/locale/sr_Latn/LC_MESSAGES/django.po b/locale/sr_Latn/LC_MESSAGES/django.po index 8c5db5a..dacc8ec 100644 --- a/locale/sr_Latn/LC_MESSAGES/django.po +++ b/locale/sr_Latn/LC_MESSAGES/django.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: dmoj\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-10-25 05:59+0700\n" +"POT-Creation-Date: 2020-04-10 01:26-0500\n" "PO-Revision-Date: 2019-11-11 22:06\n" "Last-Translator: Icyene\n" "Language-Team: Serbian (Latin)\n" @@ -17,93 +17,93 @@ msgstr "" "X-Crowdin-Language: sr-CS\n" "X-Crowdin-File: django.po\n" -#: chat_box/models.py:16 judge/admin/interface.py:110 -#: judge/models/contest.py:403 judge/models/contest.py:528 -#: judge/models/profile.py:211 +#: chat_box/models.py:15 judge/admin/interface.py:107 +#: judge/models/contest.py:257 judge/models/contest.py:381 +#: judge/models/profile.py:191 msgid "user" msgstr "" -#: chat_box/models.py:17 judge/models/comment.py:43 judge/models/comment.py:191 +#: chat_box/models.py:16 judge/models/comment.py:42 msgid "posted time" msgstr "" -#: chat_box/models.py:18 judge/models/comment.py:47 +#: chat_box/models.py:17 judge/models/comment.py:46 msgid "body of comment" msgstr "" -#: chat_box/views.py:29 templates/chat/chat.html:4 +#: chat_box/views.py:29 msgid "Chat Box" msgstr "" -#: dmoj/settings.py:355 +#: dmoj/settings.py:349 msgid "German" msgstr "" -#: dmoj/settings.py:356 +#: dmoj/settings.py:350 msgid "English" msgstr "" -#: dmoj/settings.py:357 +#: dmoj/settings.py:351 msgid "Spanish" msgstr "" -#: dmoj/settings.py:358 +#: dmoj/settings.py:352 msgid "French" msgstr "" -#: dmoj/settings.py:359 +#: dmoj/settings.py:353 msgid "Croatian" msgstr "" -#: dmoj/settings.py:360 +#: dmoj/settings.py:354 msgid "Hungarian" msgstr "" -#: dmoj/settings.py:361 +#: dmoj/settings.py:355 msgid "Japanese" msgstr "" -#: dmoj/settings.py:362 +#: dmoj/settings.py:356 msgid "Korean" msgstr "" -#: dmoj/settings.py:363 +#: dmoj/settings.py:357 msgid "Brazilian Portuguese" msgstr "" -#: dmoj/settings.py:364 +#: dmoj/settings.py:358 msgid "Romanian" msgstr "" -#: dmoj/settings.py:365 +#: dmoj/settings.py:359 msgid "Russian" msgstr "" -#: dmoj/settings.py:366 +#: dmoj/settings.py:360 msgid "Serbian (Latin)" msgstr "" -#: dmoj/settings.py:367 +#: dmoj/settings.py:361 msgid "Turkish" msgstr "" -#: dmoj/settings.py:368 +#: dmoj/settings.py:362 msgid "Vietnamese" msgstr "" -#: dmoj/settings.py:369 +#: dmoj/settings.py:363 msgid "Simplified Chinese" msgstr "" -#: dmoj/settings.py:370 +#: dmoj/settings.py:364 msgid "Traditional Chinese" msgstr "" -#: dmoj/urls.py:58 +#: dmoj/urls.py:57 msgid "Login" msgstr "" -#: dmoj/urls.py:106 templates/base.html:193 +#: dmoj/urls.py:105 templates/base.html:190 msgid "Home" msgstr "" @@ -135,48 +135,46 @@ msgstr "" msgid "Associated page" msgstr "" -#: judge/admin/contest.py:30 +#: judge/admin/contest.py:28 msgid "Included contests" msgstr "" -#: judge/admin/contest.py:66 templates/contest/clarification.html:42 -#: templates/contest/contest.html:83 templates/contest/moss.html:43 -#: templates/problem/list.html:214 templates/problem/list.html:232 -#: templates/problem/list.html:350 templates/user/user-problems.html:56 +#: judge/admin/contest.py:64 templates/contest/contest.html:83 +#: templates/contest/moss.html:43 templates/problem/list.html:206 +#: templates/problem/list.html:221 templates/user/user-problems.html:56 #: templates/user/user-problems.html:98 msgid "Problem" msgstr "" -#: judge/admin/contest.py:119 +#: judge/admin/contest.py:112 msgid "Settings" msgstr "" -#: judge/admin/contest.py:121 +#: judge/admin/contest.py:114 msgid "Scheduling" msgstr "" -#: judge/admin/contest.py:122 templates/organization/home.html:107 +#: judge/admin/contest.py:115 msgid "Details" msgstr "" -#: judge/admin/contest.py:123 +#: judge/admin/contest.py:116 msgid "Format" msgstr "" -#: judge/admin/contest.py:124 templates/contest/ranking-table.html:7 -#: templates/user/user-about.html:15 templates/user/user-about.html:45 +#: judge/admin/contest.py:117 templates/contest/ranking-table.html:5 msgid "Rating" msgstr "" -#: judge/admin/contest.py:125 +#: judge/admin/contest.py:118 msgid "Access" msgstr "" -#: judge/admin/contest.py:127 judge/admin/problem.py:131 +#: judge/admin/contest.py:120 judge/admin/problem.py:131 msgid "Justice" msgstr "" -#: judge/admin/contest.py:207 +#: judge/admin/contest.py:158 #, python-format msgid "%d contest successfully marked as visible." msgid_plural "%d contests successfully marked as visible." @@ -184,11 +182,11 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: judge/admin/contest.py:210 +#: judge/admin/contest.py:161 msgid "Mark contests as visible" msgstr "" -#: judge/admin/contest.py:216 +#: judge/admin/contest.py:165 #, python-format msgid "%d contest successfully marked as hidden." msgid_plural "%d contests successfully marked as hidden." @@ -196,11 +194,11 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: judge/admin/contest.py:219 +#: judge/admin/contest.py:168 msgid "Mark contests as hidden" msgstr "" -#: judge/admin/contest.py:233 judge/admin/submission.py:164 +#: judge/admin/contest.py:182 judge/admin/submission.py:164 #, python-format msgid "%d submission was successfully scheduled for rejudging." msgid_plural "%d submissions were successfully scheduled for rejudging." @@ -208,7 +206,7 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: judge/admin/contest.py:308 +#: judge/admin/contest.py:256 #, python-format msgid "%d participation recalculated." msgid_plural "%d participations recalculated." @@ -216,15 +214,15 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: judge/admin/contest.py:311 +#: judge/admin/contest.py:259 msgid "Recalculate results" msgstr "" -#: judge/admin/contest.py:315 judge/admin/organization.py:65 +#: judge/admin/contest.py:263 judge/admin/organization.py:65 msgid "username" msgstr "" -#: judge/admin/contest.py:320 templates/base.html:277 +#: judge/admin/contest.py:268 templates/base.html:260 msgid "virtual" msgstr "" @@ -232,15 +230,15 @@ msgstr "" msgid "link path" msgstr "" -#: judge/admin/interface.py:65 +#: judge/admin/interface.py:62 msgid "Content" msgstr "" -#: judge/admin/interface.py:66 +#: judge/admin/interface.py:63 msgid "Summary" msgstr "" -#: judge/admin/interface.py:151 +#: judge/admin/interface.py:148 msgid "object" msgstr "" @@ -262,9 +260,8 @@ msgid "Taxonomy" msgstr "" #: judge/admin/problem.py:128 templates/contest/contest.html:84 -#: templates/problem/data.html:429 templates/problem/list.html:222 -#: templates/problem/list.html:248 templates/user/base-users-table.html:10 -#: templates/user/user-about.html:36 templates/user/user-about.html:52 +#: templates/problem/data.html:449 templates/problem/list.html:211 +#: templates/problem/list.html:232 templates/user/base-users-table.html:10 #: templates/user/user-problems.html:58 msgid "Points" msgstr "" @@ -315,7 +312,6 @@ msgid "timezone" msgstr "" #: judge/admin/profile.py:86 judge/admin/submission.py:211 -#: templates/notification/list.html:12 #: templates/organization/requests/log.html:9 #: templates/organization/requests/pending.html:12 #: templates/ticket/list.html:263 @@ -323,7 +319,6 @@ msgid "User" msgstr "" #: judge/admin/profile.py:91 templates/registration/registration_form.html:145 -#: templates/user/import/table_csv.html:8 msgid "Email" msgstr "" @@ -357,7 +352,7 @@ msgstr "" msgid "These problems are NOT allowed to be submitted in this language" msgstr "" -#: judge/admin/runtime.py:83 templates/problem/list.html:352 +#: judge/admin/runtime.py:83 msgid "Description" msgstr "" @@ -404,7 +399,7 @@ msgstr "" msgid "Rejudge the selected submissions" msgstr "" -#: judge/admin/submission.py:193 judge/views/problem_manage.py:159 +#: judge/admin/submission.py:193 judge/views/problem_manage.py:128 #, python-format msgid "%d submission were successfully rescored." msgid_plural "%d submissions were successfully rescored." @@ -416,8 +411,7 @@ msgstr[2] "" msgid "Rescore the selected submissions" msgstr "" -#: judge/admin/submission.py:200 templates/problem/list.html:216 -#: templates/problem/list.html:236 +#: judge/admin/submission.py:200 msgid "Problem code" msgstr "" @@ -425,12 +419,10 @@ msgstr "" msgid "Problem name" msgstr "" -#: judge/admin/submission.py:215 templates/notification/list.html:15 -#: templates/organization/requests/log.html:10 +#: judge/admin/submission.py:215 templates/organization/requests/log.html:10 #: templates/organization/requests/pending.html:13 -#: templates/problem/list.html:351 -#: templates/submission/status-testcases.html:125 -#: templates/submission/status-testcases.html:127 +#: templates/submission/status-testcases.html:105 +#: templates/submission/status-testcases.html:107 msgid "Time" msgstr "" @@ -444,7 +436,7 @@ msgstr "" msgid "%.2f MB" msgstr "" -#: judge/admin/submission.py:227 templates/submission/status-testcases.html:132 +#: judge/admin/submission.py:227 templates/submission/status-testcases.html:112 msgid "Memory" msgstr "" @@ -464,20 +456,20 @@ msgstr "" msgid "Online Judge" msgstr "" -#: judge/comments.py:60 +#: judge/comments.py:41 msgid "Comment body" msgstr "" -#: judge/comments.py:66 judge/views/ticket.py:63 +#: judge/comments.py:47 judge/views/ticket.py:46 msgid "Your part is silent, little toad." msgstr "" -#: judge/comments.py:69 templates/comments/list.html:132 +#: judge/comments.py:50 templates/comments/list.html:131 msgid "" "You need to have solved at least one problem before your voice can be heard." msgstr "" -#: judge/comments.py:113 +#: judge/comments.py:92 msgid "Posted comment" msgstr "" @@ -493,10 +485,6 @@ msgstr "" msgid "ECOO" msgstr "" -#: judge/contest_format/icpc.py:19 -msgid "ICPC" -msgstr "" - #: judge/contest_format/ioi.py:19 msgid "IOI" msgstr "" @@ -509,58 +497,52 @@ msgstr "" msgid "Enable experimental features" msgstr "" -#: judge/forms.py:57 judge/views/organization.py:168 judge/views/register.py:49 +#: judge/forms.py:57 judge/views/organization.py:127 #, python-brace-format msgid "You may not be part of more than {count} public organizations." msgstr "" -#: judge/forms.py:82 -msgid "Any judge" -msgstr "" - -#: judge/forms.py:112 judge/views/register.py:26 +#: judge/forms.py:107 judge/views/register.py:26 #: templates/registration/registration_form.html:139 #: templates/user/base-users-table.html:5 -#: templates/user/import/table_csv.html:4 msgid "Username" msgstr "" -#: judge/forms.py:113 templates/registration/registration_form.html:151 +#: judge/forms.py:108 templates/registration/registration_form.html:151 #: templates/registration/registration_form.html:165 -#: templates/user/import/table_csv.html:5 msgid "Password" msgstr "" -#: judge/forms.py:135 +#: judge/forms.py:130 msgid "Two Factor Authentication tokens must be 6 decimal digits." msgstr "" -#: judge/forms.py:144 templates/registration/totp_auth.html:32 +#: judge/forms.py:139 templates/registration/totp_auth.html:32 msgid "Invalid Two Factor Authentication token." msgstr "" -#: judge/forms.py:148 judge/models/problem.py:97 +#: judge/forms.py:143 judge/models/problem.py:97 msgid "Problem code must be ^[a-z0-9]+$" msgstr "" -#: judge/forms.py:153 +#: judge/forms.py:148 msgid "Problem with code already exists." msgstr "" -#: judge/forms.py:158 judge/models/contest.py:61 +#: judge/forms.py:153 judge/models/contest.py:52 msgid "Contest id must be ^[a-z0-9]+$" msgstr "" -#: judge/forms.py:163 +#: judge/forms.py:158 msgid "Contest with key already exists." msgstr "" -#: judge/jinja2/datetime.py:26 templates/blog/blog.html:26 +#: judge/jinja2/datetime.py:26 templates/blog/content.html:27 #: templates/blog/dashboard.html:21 msgid "N j, Y, g:i a" msgstr "" -#: judge/jinja2/datetime.py:26 templates/chat/message.html:13 +#: judge/jinja2/datetime.py:26 #, python-brace-format msgid "{time}" msgstr "" @@ -590,542 +572,472 @@ msgstr "" msgid "Detect best quality" msgstr "" -#: judge/models/comment.py:26 +#: judge/models/comment.py:25 msgid "Page code must be ^[pcs]:[a-z0-9]+$|^b:\\d+$" msgstr "" -#: judge/models/comment.py:42 +#: judge/models/comment.py:41 msgid "commenter" msgstr "" -#: judge/models/comment.py:44 judge/models/comment.py:177 +#: judge/models/comment.py:43 judge/models/comment.py:176 msgid "associated page" msgstr "" -#: judge/models/comment.py:46 +#: judge/models/comment.py:45 msgid "votes" msgstr "" -#: judge/models/comment.py:48 +#: judge/models/comment.py:47 msgid "hide the comment" msgstr "" -#: judge/models/comment.py:49 +#: judge/models/comment.py:48 msgid "parent" msgstr "" -#: judge/models/comment.py:54 judge/models/comment.py:192 +#: judge/models/comment.py:53 msgid "comment" msgstr "" -#: judge/models/comment.py:55 +#: judge/models/comment.py:54 msgid "comments" msgstr "" -#: judge/models/comment.py:137 judge/models/problem.py:443 +#: judge/models/comment.py:136 judge/models/problem.py:406 #, python-format msgid "Editorial for %s" msgstr "" -#: judge/models/comment.py:172 +#: judge/models/comment.py:171 msgid "comment vote" msgstr "" -#: judge/models/comment.py:173 +#: judge/models/comment.py:172 msgid "comment votes" msgstr "" -#: judge/models/comment.py:182 +#: judge/models/comment.py:181 msgid "Override comment lock" msgstr "" -#: judge/models/comment.py:190 -msgid "owner" -msgstr "" - -#: judge/models/comment.py:193 judge/models/message.py:16 -msgid "read" -msgstr "" - -#: judge/models/comment.py:194 -msgid "category" -msgstr "" - -#: judge/models/comment.py:195 -msgid "html link to comments, used for non-comments" -msgstr "" - -#: judge/models/comment.py:196 -msgid "who trigger, used for non-comment" -msgstr "" - -#: judge/models/contest.py:23 +#: judge/models/contest.py:22 msgid "Invalid colour." msgstr "" -#: judge/models/contest.py:25 +#: judge/models/contest.py:24 msgid "tag name" msgstr "" -#: judge/models/contest.py:26 +#: judge/models/contest.py:25 msgid "Lowercase letters and hyphens only." msgstr "" -#: judge/models/contest.py:27 +#: judge/models/contest.py:26 msgid "tag colour" msgstr "" -#: judge/models/contest.py:28 +#: judge/models/contest.py:27 msgid "tag description" msgstr "" -#: judge/models/contest.py:47 +#: judge/models/contest.py:46 msgid "contest tag" msgstr "" -#: judge/models/contest.py:48 judge/models/contest.py:118 +#: judge/models/contest.py:47 judge/models/contest.py:101 msgid "contest tags" msgstr "" -#: judge/models/contest.py:56 -msgid "Visible" -msgstr "" - -#: judge/models/contest.py:57 -msgid "Hidden for duration of contest" -msgstr "" - -#: judge/models/contest.py:58 -msgid "Hidden for duration of participation" -msgstr "" - -#: judge/models/contest.py:60 +#: judge/models/contest.py:51 msgid "contest id" msgstr "" -#: judge/models/contest.py:62 +#: judge/models/contest.py:53 msgid "contest name" msgstr "" -#: judge/models/contest.py:63 -msgid "These users will be able to edit the contest." +#: judge/models/contest.py:54 +msgid "These people will be able to edit the contest." msgstr "" -#: judge/models/contest.py:65 -msgid "" -"These users will be able to edit the contest, but will not be listed as " -"authors." -msgstr "" - -#: judge/models/contest.py:68 -msgid "These users will be able to view the contest, but not edit it." -msgstr "" - -#: judge/models/contest.py:71 judge/models/runtime.py:136 +#: judge/models/contest.py:56 judge/models/runtime.py:133 msgid "description" msgstr "" -#: judge/models/contest.py:72 judge/models/problem.py:390 -#: judge/models/runtime.py:138 +#: judge/models/contest.py:57 judge/models/problem.py:353 +#: judge/models/runtime.py:135 msgid "problems" msgstr "" -#: judge/models/contest.py:73 judge/models/contest.py:404 +#: judge/models/contest.py:58 judge/models/contest.py:258 msgid "start time" msgstr "" -#: judge/models/contest.py:74 +#: judge/models/contest.py:59 msgid "end time" msgstr "" -#: judge/models/contest.py:75 judge/models/problem.py:118 -#: judge/models/problem.py:414 +#: judge/models/contest.py:60 judge/models/problem.py:118 +#: judge/models/problem.py:377 msgid "time limit" msgstr "" -#: judge/models/contest.py:76 judge/models/problem.py:136 +#: judge/models/contest.py:61 judge/models/problem.py:136 msgid "publicly visible" msgstr "" -#: judge/models/contest.py:77 +#: judge/models/contest.py:62 msgid "" "Should be set even for organization-private contests, where it determines " "whether the contest is visible to members of the specified organizations." msgstr "" -#: judge/models/contest.py:80 +#: judge/models/contest.py:65 msgid "contest rated" msgstr "" -#: judge/models/contest.py:80 +#: judge/models/contest.py:65 msgid "Whether this contest can be rated." msgstr "" -#: judge/models/contest.py:82 -msgid "scoreboard visibility" +#: judge/models/contest.py:67 +msgid "hide scoreboard" msgstr "" -#: judge/models/contest.py:83 -msgid "Scoreboard visibility through the duration of the contest" +#: judge/models/contest.py:68 +msgid "" +"Whether the scoreboard should remain hidden for the duration of the contest." msgstr "" -#: judge/models/contest.py:85 -msgid "view contest scoreboard" -msgstr "" - -#: judge/models/contest.py:87 -msgid "These users will be able to view the scoreboard." -msgstr "" - -#: judge/models/contest.py:88 +#: judge/models/contest.py:71 msgid "no comments" msgstr "" -#: judge/models/contest.py:89 +#: judge/models/contest.py:72 msgid "Use clarification system instead of comments." msgstr "" -#: judge/models/contest.py:91 +#: judge/models/contest.py:74 msgid "Rating floor for contest" msgstr "" -#: judge/models/contest.py:93 +#: judge/models/contest.py:76 msgid "Rating ceiling for contest" msgstr "" -#: judge/models/contest.py:95 +#: judge/models/contest.py:78 msgid "rate all" msgstr "" -#: judge/models/contest.py:95 +#: judge/models/contest.py:78 msgid "Rate all users who joined." msgstr "" -#: judge/models/contest.py:96 +#: judge/models/contest.py:79 msgid "exclude from ratings" msgstr "" -#: judge/models/contest.py:98 +#: judge/models/contest.py:81 msgid "private to specific users" msgstr "" -#: judge/models/contest.py:99 +#: judge/models/contest.py:82 msgid "private contestants" msgstr "" -#: judge/models/contest.py:100 +#: judge/models/contest.py:83 msgid "If private, only these users may see the contest" msgstr "" -#: judge/models/contest.py:102 +#: judge/models/contest.py:85 msgid "hide problem tags" msgstr "" -#: judge/models/contest.py:103 +#: judge/models/contest.py:86 msgid "Whether problem tags should be hidden by default." msgstr "" -#: judge/models/contest.py:105 +#: judge/models/contest.py:88 msgid "run pretests only" msgstr "" -#: judge/models/contest.py:106 +#: judge/models/contest.py:89 msgid "" "Whether judges should grade pretests only, versus all testcases. Commonly " "set during a contest, then unset prior to rejudging user submissions when " "the contest ends." msgstr "" -#: judge/models/contest.py:110 judge/models/interface.py:77 -#: judge/models/problem.py:157 +#: judge/models/contest.py:93 judge/models/problem.py:157 msgid "private to organizations" msgstr "" -#: judge/models/contest.py:111 judge/models/interface.py:75 -#: judge/models/problem.py:155 judge/models/profile.py:77 +#: judge/models/contest.py:94 judge/models/problem.py:155 +#: judge/models/profile.py:77 msgid "organizations" msgstr "" -#: judge/models/contest.py:112 +#: judge/models/contest.py:95 msgid "If private, only these organizations may see the contest" msgstr "" -#: judge/models/contest.py:113 judge/models/problem.py:145 +#: judge/models/contest.py:96 judge/models/problem.py:145 msgid "OpenGraph image" msgstr "" -#: judge/models/contest.py:114 judge/models/profile.py:48 +#: judge/models/contest.py:97 judge/models/profile.py:48 msgid "Logo override image" msgstr "" -#: judge/models/contest.py:116 +#: judge/models/contest.py:99 msgid "" "This image will replace the default site logo for users inside the contest." msgstr "" -#: judge/models/contest.py:119 +#: judge/models/contest.py:102 msgid "the amount of live participants" msgstr "" -#: judge/models/contest.py:120 +#: judge/models/contest.py:103 msgid "contest summary" msgstr "" -#: judge/models/contest.py:121 judge/models/problem.py:147 +#: judge/models/contest.py:104 judge/models/problem.py:147 msgid "Plain-text, shown in meta description tag, e.g. for social media." msgstr "" -#: judge/models/contest.py:122 judge/models/profile.py:47 +#: judge/models/contest.py:105 judge/models/profile.py:47 msgid "access code" msgstr "" -#: judge/models/contest.py:123 +#: judge/models/contest.py:106 msgid "" "An optional code to prompt contestants before they are allowed to join the " "contest. Leave it blank to disable." msgstr "" -#: judge/models/contest.py:125 judge/models/problem.py:141 +#: judge/models/contest.py:108 judge/models/problem.py:141 msgid "personae non gratae" msgstr "" -#: judge/models/contest.py:126 +#: judge/models/contest.py:109 msgid "Bans the selected users from joining this contest." msgstr "" -#: judge/models/contest.py:127 +#: judge/models/contest.py:110 msgid "contest format" msgstr "" -#: judge/models/contest.py:128 +#: judge/models/contest.py:111 msgid "The contest format module to use." msgstr "" -#: judge/models/contest.py:129 +#: judge/models/contest.py:112 msgid "contest format configuration" msgstr "" -#: judge/models/contest.py:130 +#: judge/models/contest.py:113 msgid "" "A JSON object to serve as the configuration for the chosen contest format " "module. Leave empty to use None. Exact format depends on the contest format " "selected." msgstr "" -#: judge/models/contest.py:137 -msgid "precision points" -msgstr "" - -#: judge/models/contest.py:139 -msgid "Number of digits to round points to." -msgstr "" - -#: judge/models/contest.py:383 +#: judge/models/contest.py:239 msgid "See private contests" msgstr "" -#: judge/models/contest.py:384 +#: judge/models/contest.py:240 msgid "Edit own contests" msgstr "" -#: judge/models/contest.py:385 +#: judge/models/contest.py:241 msgid "Edit all contests" msgstr "" -#: judge/models/contest.py:386 +#: judge/models/contest.py:242 msgid "Clone contest" msgstr "" -#: judge/models/contest.py:387 templates/contest/moss.html:74 +#: judge/models/contest.py:243 templates/contest/moss.html:74 msgid "MOSS contest" msgstr "" -#: judge/models/contest.py:388 +#: judge/models/contest.py:244 msgid "Rate contests" msgstr "" -#: judge/models/contest.py:389 +#: judge/models/contest.py:245 msgid "Contest access codes" msgstr "" -#: judge/models/contest.py:390 +#: judge/models/contest.py:246 msgid "Create private contests" msgstr "" -#: judge/models/contest.py:391 -msgid "Change contest visibility" -msgstr "" - -#: judge/models/contest.py:392 -msgid "Edit contest problem label script" -msgstr "" - -#: judge/models/contest.py:394 judge/models/contest.py:492 -#: judge/models/contest.py:529 judge/models/contest.py:552 -#: judge/models/submission.py:84 +#: judge/models/contest.py:248 judge/models/contest.py:345 +#: judge/models/contest.py:382 judge/models/contest.py:404 +#: judge/models/submission.py:83 msgid "contest" msgstr "" -#: judge/models/contest.py:395 +#: judge/models/contest.py:249 msgid "contests" msgstr "" -#: judge/models/contest.py:402 +#: judge/models/contest.py:256 msgid "associated contest" msgstr "" -#: judge/models/contest.py:405 +#: judge/models/contest.py:259 msgid "score" msgstr "" -#: judge/models/contest.py:406 +#: judge/models/contest.py:260 msgid "cumulative time" msgstr "" -#: judge/models/contest.py:407 +#: judge/models/contest.py:261 msgid "is disqualified" msgstr "" -#: judge/models/contest.py:408 +#: judge/models/contest.py:262 msgid "Whether this participation is disqualified." msgstr "" -#: judge/models/contest.py:409 -msgid "tie-breaking field" -msgstr "" - -#: judge/models/contest.py:410 +#: judge/models/contest.py:263 msgid "virtual participation id" msgstr "" -#: judge/models/contest.py:411 +#: judge/models/contest.py:264 msgid "0 means non-virtual, otherwise the n-th virtual participation." msgstr "" -#: judge/models/contest.py:412 +#: judge/models/contest.py:265 msgid "contest format specific data" msgstr "" -#: judge/models/contest.py:478 +#: judge/models/contest.py:331 #, python-format msgid "%s spectating in %s" msgstr "" -#: judge/models/contest.py:480 +#: judge/models/contest.py:333 #, python-format msgid "%s in %s, v%d" msgstr "" -#: judge/models/contest.py:481 +#: judge/models/contest.py:334 #, python-format msgid "%s in %s" msgstr "" -#: judge/models/contest.py:484 +#: judge/models/contest.py:337 msgid "contest participation" msgstr "" -#: judge/models/contest.py:485 +#: judge/models/contest.py:338 msgid "contest participations" msgstr "" -#: judge/models/contest.py:491 judge/models/contest.py:513 -#: judge/models/contest.py:553 judge/models/problem.py:389 -#: judge/models/problem.py:394 judge/models/problem.py:412 -#: judge/models/problem_data.py:40 +#: judge/models/contest.py:344 judge/models/contest.py:366 +#: judge/models/contest.py:405 judge/models/problem.py:352 +#: judge/models/problem.py:357 judge/models/problem.py:375 +#: judge/models/problem_data.py:38 msgid "problem" msgstr "" -#: judge/models/contest.py:493 judge/models/contest.py:517 +#: judge/models/contest.py:346 judge/models/contest.py:370 #: judge/models/problem.py:129 msgid "points" msgstr "" -#: judge/models/contest.py:494 +#: judge/models/contest.py:347 msgid "partial" msgstr "" -#: judge/models/contest.py:495 judge/models/contest.py:518 +#: judge/models/contest.py:348 judge/models/contest.py:371 msgid "is pretested" msgstr "" -#: judge/models/contest.py:496 judge/models/interface.py:43 +#: judge/models/contest.py:349 judge/models/interface.py:43 msgid "order" msgstr "" -#: judge/models/contest.py:497 +#: judge/models/contest.py:350 msgid "0 to not show testcases, 1 to show" msgstr "" -#: judge/models/contest.py:498 +#: judge/models/contest.py:351 msgid "visible testcases" msgstr "" -#: judge/models/contest.py:499 +#: judge/models/contest.py:352 msgid "Maximum number of submissions for this problem, or 0 for no limit." msgstr "" -#: judge/models/contest.py:501 +#: judge/models/contest.py:354 msgid "Why include a problem you can't submit to?" msgstr "" -#: judge/models/contest.py:506 +#: judge/models/contest.py:359 msgid "contest problem" msgstr "" -#: judge/models/contest.py:507 +#: judge/models/contest.py:360 msgid "contest problems" msgstr "" -#: judge/models/contest.py:511 judge/models/submission.py:183 +#: judge/models/contest.py:364 judge/models/submission.py:181 msgid "submission" msgstr "" -#: judge/models/contest.py:515 judge/models/contest.py:530 +#: judge/models/contest.py:368 judge/models/contest.py:383 msgid "participation" msgstr "" -#: judge/models/contest.py:519 +#: judge/models/contest.py:372 msgid "Whether this submission was ran only on pretests." msgstr "" -#: judge/models/contest.py:523 +#: judge/models/contest.py:376 msgid "contest submission" msgstr "" -#: judge/models/contest.py:524 +#: judge/models/contest.py:377 msgid "contest submissions" msgstr "" -#: judge/models/contest.py:532 +#: judge/models/contest.py:385 msgid "rank" msgstr "" -#: judge/models/contest.py:533 +#: judge/models/contest.py:386 msgid "rating" msgstr "" -#: judge/models/contest.py:534 +#: judge/models/contest.py:387 msgid "volatility" msgstr "" -#: judge/models/contest.py:535 +#: judge/models/contest.py:388 msgid "last rated" msgstr "" -#: judge/models/contest.py:539 +#: judge/models/contest.py:392 msgid "contest rating" msgstr "" -#: judge/models/contest.py:540 +#: judge/models/contest.py:393 msgid "contest ratings" msgstr "" -#: judge/models/contest.py:560 +#: judge/models/contest.py:412 msgid "contest moss result" msgstr "" -#: judge/models/contest.py:561 +#: judge/models/contest.py:413 msgid "contest moss results" msgstr "" @@ -1165,7 +1077,7 @@ msgstr "" msgid "post title" msgstr "" -#: judge/models/interface.py:67 judge/models/problem.py:432 +#: judge/models/interface.py:67 judge/models/problem.py:395 msgid "authors" msgstr "" @@ -1173,7 +1085,7 @@ msgstr "" msgid "slug" msgstr "" -#: judge/models/interface.py:69 judge/models/problem.py:430 +#: judge/models/interface.py:69 judge/models/problem.py:393 msgid "public visibility" msgstr "" @@ -1197,19 +1109,15 @@ msgstr "" msgid "openGraph image" msgstr "" -#: judge/models/interface.py:76 -msgid "If private, only these organizations may see the blog post." -msgstr "" - -#: judge/models/interface.py:105 +#: judge/models/interface.py:91 msgid "Edit all posts" msgstr "" -#: judge/models/interface.py:107 +#: judge/models/interface.py:93 msgid "blog post" msgstr "" -#: judge/models/interface.py:108 +#: judge/models/interface.py:94 msgid "blog posts" msgstr "" @@ -1233,6 +1141,10 @@ msgstr "" msgid "message timestamp" msgstr "" +#: judge/models/message.py:16 +msgid "read" +msgstr "" + #: judge/models/message.py:20 msgid "messages in the thread" msgstr "" @@ -1369,7 +1281,7 @@ msgid "" "are supported." msgstr "" -#: judge/models/problem.py:123 judge/models/problem.py:417 +#: judge/models/problem.py:123 judge/models/problem.py:380 msgid "memory limit" msgstr "" @@ -1442,188 +1354,188 @@ msgstr "" msgid "If private, only these organizations may see the problem." msgstr "" -#: judge/models/problem.py:395 judge/models/problem.py:413 -#: judge/models/runtime.py:111 +#: judge/models/problem.py:358 judge/models/problem.py:376 +#: judge/models/runtime.py:108 msgid "language" msgstr "" -#: judge/models/problem.py:396 +#: judge/models/problem.py:359 msgid "translated name" msgstr "" -#: judge/models/problem.py:397 +#: judge/models/problem.py:360 msgid "translated description" msgstr "" -#: judge/models/problem.py:401 +#: judge/models/problem.py:364 msgid "problem translation" msgstr "" -#: judge/models/problem.py:402 +#: judge/models/problem.py:365 msgid "problem translations" msgstr "" -#: judge/models/problem.py:406 +#: judge/models/problem.py:369 msgid "clarified problem" msgstr "" -#: judge/models/problem.py:407 +#: judge/models/problem.py:370 msgid "clarification body" msgstr "" -#: judge/models/problem.py:408 +#: judge/models/problem.py:371 msgid "clarification timestamp" msgstr "" -#: judge/models/problem.py:423 +#: judge/models/problem.py:386 msgid "language-specific resource limit" msgstr "" -#: judge/models/problem.py:424 +#: judge/models/problem.py:387 msgid "language-specific resource limits" msgstr "" -#: judge/models/problem.py:428 +#: judge/models/problem.py:391 msgid "associated problem" msgstr "" -#: judge/models/problem.py:431 +#: judge/models/problem.py:394 msgid "publish date" msgstr "" -#: judge/models/problem.py:433 +#: judge/models/problem.py:396 msgid "editorial content" msgstr "" -#: judge/models/problem.py:449 +#: judge/models/problem.py:412 msgid "solution" msgstr "" -#: judge/models/problem.py:450 +#: judge/models/problem.py:413 msgid "solutions" msgstr "" -#: judge/models/problem_data.py:26 +#: judge/models/problem_data.py:24 msgid "Standard" msgstr "" -#: judge/models/problem_data.py:27 +#: judge/models/problem_data.py:25 msgid "Floats" msgstr "" -#: judge/models/problem_data.py:28 +#: judge/models/problem_data.py:26 msgid "Floats (absolute)" msgstr "" -#: judge/models/problem_data.py:29 +#: judge/models/problem_data.py:27 msgid "Floats (relative)" msgstr "" -#: judge/models/problem_data.py:30 +#: judge/models/problem_data.py:28 msgid "Non-trailing spaces" msgstr "" -#: judge/models/problem_data.py:31 +#: judge/models/problem_data.py:29 msgid "Unordered" msgstr "" -#: judge/models/problem_data.py:32 +#: judge/models/problem_data.py:30 msgid "Byte identical" msgstr "" -#: judge/models/problem_data.py:33 +#: judge/models/problem_data.py:31 msgid "Line-by-line" msgstr "" -#: judge/models/problem_data.py:34 +#: judge/models/problem_data.py:32 msgid "Custom checker (PY)" msgstr "" -#: judge/models/problem_data.py:35 +#: judge/models/problem_data.py:33 msgid "Custom validator (CPP)" msgstr "" -#: judge/models/problem_data.py:42 +#: judge/models/problem_data.py:40 msgid "data zip file" msgstr "" -#: judge/models/problem_data.py:44 +#: judge/models/problem_data.py:42 msgid "generator file" msgstr "" -#: judge/models/problem_data.py:46 judge/models/problem_data.py:121 +#: judge/models/problem_data.py:44 judge/models/problem_data.py:110 msgid "output prefix length" msgstr "" -#: judge/models/problem_data.py:47 judge/models/problem_data.py:122 +#: judge/models/problem_data.py:45 judge/models/problem_data.py:111 msgid "output limit length" msgstr "" -#: judge/models/problem_data.py:48 +#: judge/models/problem_data.py:46 msgid "init.yml generation feedback" msgstr "" -#: judge/models/problem_data.py:49 judge/models/problem_data.py:123 +#: judge/models/problem_data.py:47 judge/models/problem_data.py:112 msgid "checker" msgstr "" -#: judge/models/problem_data.py:50 judge/models/problem_data.py:124 +#: judge/models/problem_data.py:48 judge/models/problem_data.py:113 msgid "checker arguments" msgstr "" -#: judge/models/problem_data.py:51 judge/models/problem_data.py:125 +#: judge/models/problem_data.py:49 judge/models/problem_data.py:114 msgid "checker arguments as a JSON object" msgstr "" -#: judge/models/problem_data.py:52 +#: judge/models/problem_data.py:50 msgid "custom checker file" msgstr "" -#: judge/models/problem_data.py:58 +#: judge/models/problem_data.py:56 msgid "custom validator file" msgstr "" -#: judge/models/problem_data.py:108 +#: judge/models/problem_data.py:97 msgid "problem data set" msgstr "" -#: judge/models/problem_data.py:110 +#: judge/models/problem_data.py:99 msgid "case position" msgstr "" -#: judge/models/problem_data.py:111 +#: judge/models/problem_data.py:100 msgid "case type" msgstr "" -#: judge/models/problem_data.py:112 +#: judge/models/problem_data.py:101 msgid "Normal case" msgstr "" -#: judge/models/problem_data.py:113 +#: judge/models/problem_data.py:102 msgid "Batch start" msgstr "" -#: judge/models/problem_data.py:114 +#: judge/models/problem_data.py:103 msgid "Batch end" msgstr "" -#: judge/models/problem_data.py:116 +#: judge/models/problem_data.py:105 msgid "input file name" msgstr "" -#: judge/models/problem_data.py:117 +#: judge/models/problem_data.py:106 msgid "output file name" msgstr "" -#: judge/models/problem_data.py:118 +#: judge/models/problem_data.py:107 msgid "generator arguments" msgstr "" -#: judge/models/problem_data.py:119 +#: judge/models/problem_data.py:108 msgid "point value" msgstr "" -#: judge/models/problem_data.py:120 +#: judge/models/problem_data.py:109 msgid "case is pretest?" msgstr "" @@ -1696,7 +1608,7 @@ msgid "" msgstr "" #: judge/models/profile.py:76 judge/models/profile.py:93 -#: judge/models/profile.py:212 +#: judge/models/profile.py:192 msgid "organization" msgstr "" @@ -1792,31 +1704,31 @@ msgstr "" msgid "Notes for administrators regarding this user." msgstr "" -#: judge/models/profile.py:206 +#: judge/models/profile.py:186 msgid "user profile" msgstr "" -#: judge/models/profile.py:207 +#: judge/models/profile.py:187 msgid "user profiles" msgstr "" -#: judge/models/profile.py:214 +#: judge/models/profile.py:194 msgid "request time" msgstr "" -#: judge/models/profile.py:215 +#: judge/models/profile.py:195 msgid "state" msgstr "" -#: judge/models/profile.py:220 +#: judge/models/profile.py:200 msgid "reason" msgstr "" -#: judge/models/profile.py:223 +#: judge/models/profile.py:203 msgid "organization join request" msgstr "" -#: judge/models/profile.py:224 +#: judge/models/profile.py:204 msgid "organization join requests" msgstr "" @@ -1907,86 +1819,86 @@ msgstr "" msgid "The extension of source files, e.g., \"py\" or \"cpp\"." msgstr "" -#: judge/models/runtime.py:112 +#: judge/models/runtime.py:109 msgid "languages" msgstr "" -#: judge/models/runtime.py:116 +#: judge/models/runtime.py:113 msgid "language to which this runtime belongs" msgstr "" -#: judge/models/runtime.py:117 +#: judge/models/runtime.py:114 msgid "judge on which this runtime exists" msgstr "" -#: judge/models/runtime.py:118 +#: judge/models/runtime.py:115 msgid "runtime name" msgstr "" -#: judge/models/runtime.py:119 +#: judge/models/runtime.py:116 msgid "runtime version" msgstr "" -#: judge/models/runtime.py:120 +#: judge/models/runtime.py:117 msgid "order in which to display this runtime" msgstr "" -#: judge/models/runtime.py:124 +#: judge/models/runtime.py:121 msgid "Server name, hostname-style" msgstr "" -#: judge/models/runtime.py:125 +#: judge/models/runtime.py:122 msgid "time of creation" msgstr "" -#: judge/models/runtime.py:126 +#: judge/models/runtime.py:123 msgid "A key to authenticate this judge" msgstr "" -#: judge/models/runtime.py:127 +#: judge/models/runtime.py:124 msgid "authentication key" msgstr "" -#: judge/models/runtime.py:128 +#: judge/models/runtime.py:125 msgid "block judge" msgstr "" -#: judge/models/runtime.py:129 +#: judge/models/runtime.py:126 msgid "" "Whether this judge should be blocked from connecting, even if its key is " "correct." msgstr "" -#: judge/models/runtime.py:131 +#: judge/models/runtime.py:128 msgid "judge online status" msgstr "" -#: judge/models/runtime.py:132 +#: judge/models/runtime.py:129 msgid "judge start time" msgstr "" -#: judge/models/runtime.py:133 +#: judge/models/runtime.py:130 msgid "response time" msgstr "" -#: judge/models/runtime.py:134 +#: judge/models/runtime.py:131 msgid "system load" msgstr "" -#: judge/models/runtime.py:135 +#: judge/models/runtime.py:132 msgid "Load for the last minute, divided by processors to be fair." msgstr "" -#: judge/models/runtime.py:139 judge/models/runtime.py:179 +#: judge/models/runtime.py:136 judge/models/runtime.py:176 msgid "judges" msgstr "" -#: judge/models/runtime.py:178 +#: judge/models/runtime.py:175 msgid "judge" msgstr "" #: judge/models/submission.py:20 judge/models/submission.py:47 -#: judge/utils/problems.py:79 +#: judge/utils/problems.py:77 msgid "Accepted" msgstr "" @@ -2015,7 +1927,7 @@ msgid "Runtime Error" msgstr "" #: judge/models/submission.py:27 judge/models/submission.py:41 -#: judge/models/submission.py:55 judge/utils/problems.py:81 +#: judge/models/submission.py:55 judge/utils/problems.py:79 msgid "Compile Error" msgstr "" @@ -2056,15 +1968,15 @@ msgstr "" msgid "submission time" msgstr "" -#: judge/models/submission.py:67 judge/models/submission.py:203 +#: judge/models/submission.py:67 judge/models/submission.py:201 msgid "execution time" msgstr "" -#: judge/models/submission.py:68 judge/models/submission.py:204 +#: judge/models/submission.py:68 judge/models/submission.py:202 msgid "memory usage" msgstr "" -#: judge/models/submission.py:69 judge/models/submission.py:205 +#: judge/models/submission.py:69 judge/models/submission.py:203 msgid "points granted" msgstr "" @@ -2101,62 +2013,58 @@ msgid "judged on" msgstr "" #: judge/models/submission.py:81 -msgid "submission judge time" -msgstr "" - -#: judge/models/submission.py:82 msgid "was rejudged by admin" msgstr "" -#: judge/models/submission.py:83 +#: judge/models/submission.py:82 msgid "was ran on pretests only" msgstr "" -#: judge/models/submission.py:184 templates/contest/moss.html:58 +#: judge/models/submission.py:182 templates/contest/moss.html:58 msgid "submissions" msgstr "" -#: judge/models/submission.py:188 judge/models/submission.py:199 +#: judge/models/submission.py:186 judge/models/submission.py:197 msgid "associated submission" msgstr "" -#: judge/models/submission.py:190 +#: judge/models/submission.py:188 msgid "source code" msgstr "" -#: judge/models/submission.py:201 +#: judge/models/submission.py:199 msgid "test case ID" msgstr "" -#: judge/models/submission.py:202 +#: judge/models/submission.py:200 msgid "status flag" msgstr "" -#: judge/models/submission.py:206 +#: judge/models/submission.py:204 msgid "points possible" msgstr "" -#: judge/models/submission.py:207 +#: judge/models/submission.py:205 msgid "batch number" msgstr "" -#: judge/models/submission.py:208 +#: judge/models/submission.py:206 msgid "judging feedback" msgstr "" -#: judge/models/submission.py:209 +#: judge/models/submission.py:207 msgid "extended judging feedback" msgstr "" -#: judge/models/submission.py:210 +#: judge/models/submission.py:208 msgid "program output" msgstr "" -#: judge/models/submission.py:218 +#: judge/models/submission.py:216 msgid "submission test case" msgstr "" -#: judge/models/submission.py:219 +#: judge/models/submission.py:217 msgid "submission test cases" msgstr "" @@ -2208,21 +2116,12 @@ msgstr "" msgid "message time" msgstr "" -#: judge/pdf_problems.py:147 judge/pdf_problems.py:199 -#: judge/pdf_problems.py:259 +#: judge/pdf_problems.py:134 judge/pdf_problems.py:186 +#: judge/pdf_problems.py:246 msgid "Page [page] of [topage]" msgstr "" -#: judge/pdf_problems.py:280 -#, python-format -msgid "Page %s of %s" -msgstr "" - -#: judge/tasks/contest.py:19 -msgid "Recalculating contest scores" -msgstr "" - -#: judge/tasks/contest.py:40 +#: judge/tasks/moss.py:25 msgid "Running MOSS" msgstr "" @@ -2234,60 +2133,60 @@ msgstr "" msgid "Recalculating user points" msgstr "" -#: judge/utils/problem_data.py:70 +#: judge/utils/problem_data.py:68 msgid "Empty batches not allowed." msgstr "" -#: judge/utils/problem_data.py:78 judge/utils/problem_data.py:99 +#: judge/utils/problem_data.py:76 judge/utils/problem_data.py:97 msgid "How did you corrupt the custom checker path?" msgstr "" -#: judge/utils/problem_data.py:120 +#: judge/utils/problem_data.py:118 #, python-format msgid "Points must be defined for non-batch case #%d." msgstr "" -#: judge/utils/problem_data.py:125 +#: judge/utils/problem_data.py:123 #, python-format msgid "Input file for case %d does not exist: %s" msgstr "" -#: judge/utils/problem_data.py:128 +#: judge/utils/problem_data.py:126 #, python-format msgid "Output file for case %d does not exist: %s" msgstr "" -#: judge/utils/problem_data.py:153 +#: judge/utils/problem_data.py:151 #, python-format msgid "Batch start case #%d requires points." msgstr "" -#: judge/utils/problem_data.py:174 +#: judge/utils/problem_data.py:172 #, python-format msgid "Attempt to end batch outside of one in case #%d" msgstr "" -#: judge/utils/problem_data.py:192 +#: judge/utils/problem_data.py:190 msgid "How did you corrupt the zip path?" msgstr "" -#: judge/utils/problem_data.py:198 +#: judge/utils/problem_data.py:196 msgid "How did you corrupt the generator path?" msgstr "" -#: judge/utils/problems.py:80 +#: judge/utils/problems.py:78 msgid "Wrong" msgstr "" -#: judge/utils/problems.py:82 +#: judge/utils/problems.py:80 msgid "Timeout" msgstr "" -#: judge/utils/problems.py:83 +#: judge/utils/problems.py:81 msgid "Error" msgstr "" -#: judge/utils/problems.py:94 +#: judge/utils/problems.py:92 msgid "Can't pass both queryset and keyword filters" msgstr "" @@ -2333,8 +2232,7 @@ msgctxt "hours and minutes" msgid "%h:%m" msgstr "" -#: judge/views/about.py:7 templates/organization/home.html:112 -#: templates/user/user-about.html:83 templates/user/user-tabs.html:4 +#: judge/views/about.py:7 templates/user/user-about.html:33 msgid "About" msgstr "" @@ -2342,165 +2240,156 @@ msgstr "" msgid "Custom Checker Sample" msgstr "" -#: judge/views/blog.py:45 +#: judge/views/blog.py:38 #, python-format msgid "Page %d of Posts" msgstr "" -#: judge/views/comment.py:28 +#: judge/views/comment.py:27 msgid "Messing around, are we?" msgstr "" -#: judge/views/comment.py:37 +#: judge/views/comment.py:36 msgid "You must solve at least one problem before you can vote." msgstr "" -#: judge/views/comment.py:64 +#: judge/views/comment.py:63 msgid "You already voted." msgstr "" -#: judge/views/comment.py:126 judge/views/organization.py:344 +#: judge/views/comment.py:120 judge/views/organization.py:299 msgid "Edited from site" msgstr "" -#: judge/views/comment.py:147 +#: judge/views/comment.py:141 msgid "Editing comment" msgstr "" -#: judge/views/contests.py:57 judge/views/contests.py:247 -#: judge/views/contests.py:250 judge/views/contests.py:424 +#: judge/views/contests.py:55 judge/views/contests.py:215 +#: judge/views/contests.py:218 judge/views/contests.py:389 msgid "No such contest" msgstr "" -#: judge/views/contests.py:58 judge/views/contests.py:248 +#: judge/views/contests.py:56 judge/views/contests.py:216 #, python-format msgid "Could not find a contest with the key \"%s\"." msgstr "" -#: judge/views/contests.py:71 +#: judge/views/contests.py:81 msgid "Contests" msgstr "" -#: judge/views/contests.py:251 +#: judge/views/contests.py:219 msgid "Could not find such contest." msgstr "" -#: judge/views/contests.py:254 +#: judge/views/contests.py:222 #, python-format msgid "Access to contest \"%s\" denied" msgstr "" -#: judge/views/contests.py:278 +#: judge/views/contests.py:246 msgid "Clone Contest" msgstr "" -#: judge/views/contests.py:343 +#: judge/views/contests.py:309 msgid "Contest not ongoing" msgstr "" -#: judge/views/contests.py:344 +#: judge/views/contests.py:310 #, python-format msgid "\"%s\" is not currently ongoing." msgstr "" -#: judge/views/contests.py:348 +#: judge/views/contests.py:314 msgid "Already in contest" msgstr "" -#: judge/views/contests.py:349 +#: judge/views/contests.py:315 #, python-format msgid "You are already in a contest: \"%s\"." msgstr "" -#: judge/views/contests.py:352 +#: judge/views/contests.py:318 msgid "Banned from joining" msgstr "" -#: judge/views/contests.py:353 +#: judge/views/contests.py:319 msgid "" "You have been declared persona non grata for this contest. You are " "permanently barred from joining this contest." msgstr "" -#: judge/views/contests.py:414 +#: judge/views/contests.py:379 #, python-format msgid "Enter access code for \"%s\"" msgstr "" -#: judge/views/contests.py:425 +#: judge/views/contests.py:390 #, python-format msgid "You are not in contest \"%s\"." msgstr "" -#: judge/views/contests.py:444 +#: judge/views/contests.py:409 msgid "ContestCalendar requires integer year and month" msgstr "" -#: judge/views/contests.py:484 +#: judge/views/contests.py:449 #, python-format msgid "Contests in %(month)s" msgstr "" -#: judge/views/contests.py:484 +#: judge/views/contests.py:449 msgid "F Y" msgstr "" -#: judge/views/contests.py:532 +#: judge/views/contests.py:496 #, python-format msgid "%s Statistics" msgstr "" -#: judge/views/contests.py:717 +#: judge/views/contests.py:601 +msgid "???" +msgstr "" + +#: judge/views/contests.py:664 #, python-format msgid "%s Rankings" msgstr "" -#: judge/views/contests.py:725 -msgid "???" -msgstr "" - -#: judge/views/contests.py:741 +#: judge/views/contests.py:680 #, python-format msgid "Your participation in %s" msgstr "" -#: judge/views/contests.py:742 +#: judge/views/contests.py:681 #, python-format msgid "%s's participation in %s" msgstr "" -#: judge/views/contests.py:749 +#: judge/views/contests.py:685 msgid "Live" msgstr "" -#: judge/views/contests.py:761 templates/contest/contest-tabs.html:13 +#: judge/views/contests.py:697 msgid "Participation" msgstr "" -#: judge/views/contests.py:808 +#: judge/views/contests.py:743 #, python-format msgid "%s MOSS Results" msgstr "" -#: judge/views/contests.py:835 +#: judge/views/contests.py:770 #, python-format msgid "Running MOSS for %s..." msgstr "" -#: judge/views/contests.py:858 +#: judge/views/contests.py:793 #, python-format msgid "Contest tag: %s" msgstr "" -#: judge/views/contests.py:868 judge/views/ticket.py:57 -msgid "Issue description" -msgstr "" - -#: judge/views/contests.py:911 -#, python-format -msgid "New clarification for %s" -msgstr "" - #: judge/views/error.py:14 msgid "404 error" msgstr "" @@ -2521,83 +2410,76 @@ msgid "corrupt page %s" msgstr "" #: judge/views/language.py:12 templates/status/judge-status-table.html:9 -#: templates/status/status-tabs.html:5 msgid "Runtimes" msgstr "" -#: judge/views/notification.py:40 -#, python-format -msgid "Notifications (%d unseen)" -msgstr "" - -#: judge/views/organization.py:59 judge/views/organization.py:62 +#: judge/views/organization.py:44 judge/views/organization.py:47 msgid "No such organization" msgstr "" -#: judge/views/organization.py:60 +#: judge/views/organization.py:45 #, python-format msgid "Could not find an organization with the key \"%s\"." msgstr "" -#: judge/views/organization.py:63 +#: judge/views/organization.py:48 msgid "Could not find such organization." msgstr "" -#: judge/views/organization.py:79 judge/views/register.py:34 -#: templates/organization/list.html:32 templates/user/import/table_csv.html:9 -#: templates/user/user-list-tabs.html:6 +#: judge/views/organization.py:72 judge/views/register.py:34 +#: templates/organization/list.html:15 msgid "Organizations" msgstr "" -#: judge/views/organization.py:130 +#: judge/views/organization.py:93 #, python-format msgid "%s Members" msgstr "" -#: judge/views/organization.py:159 judge/views/organization.py:162 -#: judge/views/organization.py:167 +#: judge/views/organization.py:118 judge/views/organization.py:121 +#: judge/views/organization.py:126 msgid "Joining organization" msgstr "" -#: judge/views/organization.py:159 +#: judge/views/organization.py:118 msgid "You are already in the organization." msgstr "" -#: judge/views/organization.py:162 +#: judge/views/organization.py:121 msgid "This organization is not open." msgstr "" -#: judge/views/organization.py:179 +#: judge/views/organization.py:138 msgid "Leaving organization" msgstr "" -#: judge/views/organization.py:179 +#: judge/views/organization.py:138 #, python-format msgid "You are not in \"%s\"." msgstr "" -#: judge/views/organization.py:203 +#: judge/views/organization.py:162 #, python-format msgid "Request to join %s" msgstr "" -#: judge/views/organization.py:221 +#: judge/views/organization.py:180 msgid "Join request detail" msgstr "" -#: judge/views/organization.py:254 +#: judge/views/organization.py:209 #, python-format msgid "Managing join requests for %s" msgstr "" -#: judge/views/organization.py:285 +#: judge/views/organization.py:240 #, python-format msgid "" "Your organization can only receive %d more members. You cannot approve %d " "users." msgstr "" -#: judge/views/organization.py:297 +#: judge/views/organization.py:252 #, python-format msgid "Approved %d user." msgid_plural "Approved %d users." @@ -2605,7 +2487,7 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: judge/views/organization.py:298 +#: judge/views/organization.py:253 #, python-format msgid "Rejected %d user." msgid_plural "Rejected %d users." @@ -2613,32 +2495,32 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: judge/views/organization.py:328 +#: judge/views/organization.py:283 #, python-format msgid "Editing %s" msgstr "" -#: judge/views/organization.py:352 judge/views/organization.py:360 +#: judge/views/organization.py:307 judge/views/organization.py:315 msgid "Can't edit organization" msgstr "" -#: judge/views/organization.py:353 +#: judge/views/organization.py:308 msgid "You are not allowed to edit this organization." msgstr "" -#: judge/views/organization.py:361 +#: judge/views/organization.py:316 msgid "You are not allowed to kick people from this organization." msgstr "" -#: judge/views/organization.py:366 judge/views/organization.py:370 +#: judge/views/organization.py:321 judge/views/organization.py:325 msgid "Can't kick user" msgstr "" -#: judge/views/organization.py:367 +#: judge/views/organization.py:322 msgid "The user you are trying to kick does not exist!" msgstr "" -#: judge/views/organization.py:371 +#: judge/views/organization.py:326 #, python-format msgid "The user you are trying to kick is not in organization: %s." msgstr "" @@ -2662,36 +2544,35 @@ msgstr "" msgid "Editorial for {0}" msgstr "" -#: judge/views/problem.py:285 templates/contest/contest.html:79 -#: templates/user/user-about.html:28 templates/user/user-tabs.html:5 -#: templates/user/users-table.html:31 +#: judge/views/problem.py:286 templates/contest/contest.html:79 +#: templates/user/users-table.html:23 msgid "Problems" msgstr "" -#: judge/views/problem.py:585 +#: judge/views/problem.py:547 msgid "Banned from submitting" msgstr "" -#: judge/views/problem.py:586 +#: judge/views/problem.py:548 msgid "" "You have been declared persona non grata for this problem. You are " "permanently barred from submitting this problem." msgstr "" -#: judge/views/problem.py:600 +#: judge/views/problem.py:562 msgid "Too many submissions" msgstr "" -#: judge/views/problem.py:601 +#: judge/views/problem.py:563 msgid "You have exceeded the submission limit for this problem." msgstr "" -#: judge/views/problem.py:661 judge/views/problem.py:664 +#: judge/views/problem.py:633 judge/views/problem.py:636 #, python-format msgid "Submit to %(problem)s" msgstr "" -#: judge/views/problem.py:679 +#: judge/views/problem.py:652 msgid "Clone Problem" msgstr "" @@ -2732,22 +2613,22 @@ msgstr "" msgid "Generated init.yml for %s" msgstr "" -#: judge/views/problem_manage.py:52 judge/views/problem_manage.py:55 +#: judge/views/problem_manage.py:50 judge/views/problem_manage.py:53 #, python-format msgid "Managing submissions for %s" msgstr "" -#: judge/views/problem_manage.py:97 +#: judge/views/problem_manage.py:95 #, python-format msgid "Rejudging selected submissions for %s..." msgstr "" -#: judge/views/problem_manage.py:141 +#: judge/views/problem_manage.py:110 #, python-format msgid "Rescoring all submissions for %s..." msgstr "" -#: judge/views/problem_manage.py:150 +#: judge/views/problem_manage.py:119 #, python-format msgid "Successfully scheduled %d submission for rejudging." msgid_plural "Successfully scheduled %d submissions for rejudging." @@ -2797,24 +2678,24 @@ msgstr "" msgid "Subscribe to newsletter?" msgstr "" -#: judge/views/register.py:55 +#: judge/views/register.py:45 #, python-format msgid "" "The email address \"%s\" is already taken. Only one registration is allowed " "per address." msgstr "" -#: judge/views/register.py:61 +#: judge/views/register.py:51 msgid "" "Your email provider is not allowed due to history of abuse. Please use a " "reputable email provider." msgstr "" -#: judge/views/register.py:67 judge/views/register.py:105 +#: judge/views/register.py:57 judge/views/register.py:95 msgid "Registration" msgstr "" -#: judge/views/register.py:116 +#: judge/views/register.py:106 msgid "Authentication failure" msgstr "" @@ -2830,100 +2711,104 @@ msgstr "" msgid "Version matrix" msgstr "" -#: judge/views/submission.py:84 judge/views/submission.py:91 +#: judge/views/submission.py:83 judge/views/submission.py:90 #, python-format msgid "Submission of %(problem)s by %(user)s" msgstr "" -#: judge/views/submission.py:244 judge/views/submission.py:245 -#: templates/problem/problem.html:167 +#: judge/views/submission.py:227 judge/views/submission.py:228 +#: templates/problem/problem.html:127 msgid "All submissions" msgstr "" -#: judge/views/submission.py:404 +#: judge/views/submission.py:384 msgid "All my submissions" msgstr "" -#: judge/views/submission.py:405 +#: judge/views/submission.py:385 #, python-format msgid "All submissions by %s" msgstr "" -#: judge/views/submission.py:436 +#: judge/views/submission.py:416 #, python-format msgid "All submissions for %s" msgstr "" -#: judge/views/submission.py:455 +#: judge/views/submission.py:435 msgid "Must pass a problem" msgstr "" -#: judge/views/submission.py:501 +#: judge/views/submission.py:481 #, python-format msgid "My submissions for %(problem)s" msgstr "" -#: judge/views/submission.py:502 +#: judge/views/submission.py:482 #, python-format msgid "%(user)s's submissions for %(problem)s" msgstr "" -#: judge/views/submission.py:603 +#: judge/views/submission.py:583 msgid "Must pass a contest" msgstr "" -#: judge/views/submission.py:622 +#: judge/views/submission.py:602 #, python-brace-format msgid "" "{0}'s submissions for {2} in {4}" msgstr "" -#: judge/views/submission.py:629 +#: judge/views/submission.py:609 #, python-brace-format msgid "" "{0}'s submissions for problem {2} in {3}" "" msgstr "" -#: judge/views/ticket.py:50 judge/views/ticket.py:56 +#: judge/views/ticket.py:33 judge/views/ticket.py:39 msgid "Ticket title" msgstr "" -#: judge/views/ticket.py:107 judge/views/ticket.py:110 +#: judge/views/ticket.py:40 +msgid "Issue description" +msgstr "" + +#: judge/views/ticket.py:85 judge/views/ticket.py:88 #, python-format msgid "New ticket for %s" msgstr "" -#: judge/views/ticket.py:170 +#: judge/views/ticket.py:142 #, python-format msgid "%(title)s - Ticket %(id)d" msgstr "" -#: judge/views/ticket.py:279 +#: judge/views/ticket.py:251 #, python-format msgid "Tickets - Page %(number)d of %(total)d" msgstr "" -#: judge/views/ticket.py:328 +#: judge/views/ticket.py:300 #, python-format msgid "New Ticket: %s" msgstr "" -#: judge/views/ticket.py:329 +#: judge/views/ticket.py:301 #, python-format msgid "#%(id)d, assigned to: %(users)s" msgstr "" -#: judge/views/ticket.py:331 +#: judge/views/ticket.py:303 msgid ", " msgstr "" -#: judge/views/ticket.py:331 +#: judge/views/ticket.py:303 msgid "no one" msgstr "" -#: judge/views/ticket.py:351 +#: judge/views/ticket.py:323 #, python-format msgid "New Ticket Message For: %s" msgstr "" @@ -2940,50 +2825,41 @@ msgstr "" msgid "Perform Two Factor Authentication" msgstr "" -#: judge/views/user.py:74 +#: judge/views/user.py:68 msgid "No such user" msgstr "" -#: judge/views/user.py:74 +#: judge/views/user.py:68 #, python-format msgid "No user handle \"%s\"." msgstr "" -#: judge/views/user.py:78 +#: judge/views/user.py:72 msgid "My account" msgstr "" -#: judge/views/user.py:79 +#: judge/views/user.py:73 #, python-format msgid "User %s" msgstr "" -#: judge/views/user.py:148 -msgid "M j, Y" -msgstr "" - -#: judge/views/user.py:171 +#: judge/views/user.py:136 msgid "M j, Y, G:i" msgstr "" -#: judge/views/user.py:290 +#: judge/views/user.py:221 msgid "Updated on site" msgstr "" -#: judge/views/user.py:323 templates/admin/auth/user/change_form.html:14 -#: templates/admin/auth/user/change_form.html:17 templates/base.html:238 -#: templates/user/user-tabs.html:10 +#: judge/views/user.py:254 templates/admin/auth/user/change_form.html:14 +#: templates/admin/auth/user/change_form.html:17 templates/base.html:224 msgid "Edit profile" msgstr "" -#: judge/views/user.py:332 templates/user/user-list-tabs.html:4 +#: judge/views/user.py:263 msgid "Leaderboard" msgstr "" -#: judge/views/user.py:407 -msgid "Import Users" -msgstr "" - #: judge/views/widgets.py:48 judge/views/widgets.py:58 #, python-format msgid "Invalid upstream data: %s" @@ -3021,7 +2897,7 @@ msgid "View Submissions" msgstr "" #: templates/admin/judge/problem/change_form.html:17 -#: templates/user/user-base.html:112 +#: templates/user/user-base.html:61 msgid "View submissions" msgstr "" @@ -3036,145 +2912,90 @@ msgstr "" msgid "Rejudge" msgstr "" -#: templates/base.html:230 -#, python-format -msgid "Hello, %(username)s." -msgstr "" - -#: templates/base.html:236 templates/comments/list.html:89 -#: templates/contest/contest-list-tabs.html:24 -#: templates/contest/ranking-table.html:53 -#: templates/problem/problem-list-tabs.html:6 +#: templates/base.html:222 templates/comments/list.html:89 +#: templates/contest/ranking-table.html:39 #: templates/submission/info-base.html:12 -#: templates/submission/submission-list-tabs.html:15 msgid "Admin" msgstr "" -#: templates/base.html:245 +#: templates/base.html:231 msgid "Log out" msgstr "" -#: templates/base.html:254 +#: templates/base.html:240 #: templates/registration/password_reset_complete.html:4 msgid "Log in" msgstr "" -#: templates/base.html:255 templates/registration/registration_form.html:177 +#: templates/base.html:241 templates/registration/registration_form.html:177 msgid "or" msgstr "" -#: templates/base.html:256 +#: templates/base.html:242 msgid "Sign up" msgstr "" -#: templates/base.html:271 +#: templates/base.html:254 msgid "spectating" msgstr "" -#: templates/base.html:284 +#: templates/base.html:267 msgid "This site works best with JavaScript enabled." msgstr "" -#: templates/blog/blog.html:13 templates/comments/list.html:68 -#: templates/comments/list.html:83 templates/contest/contest-tabs.html:23 -#: templates/contest/tag-title.html:9 templates/flatpages/admin_link.html:3 -#: templates/license.html:10 templates/problem/editorial.html:14 +#: templates/blog/content.html:13 templates/comments/list.html:68 +#: templates/comments/list.html:83 templates/contest/tag-title.html:9 +#: templates/flatpages/admin_link.html:3 templates/license.html:10 +#: templates/problem/editorial.html:14 msgid "Edit" msgstr "" -#: templates/blog/blog.html:26 -#, python-format -msgid "" -"\n" -" posted on %(time)s\n" -" " -msgstr "" - -#: templates/blog/content.html:10 -#, python-brace-format -msgid "posted on {time}" -msgstr "" - -#: templates/blog/dashboard.html:21 -#, python-format -msgid "" -"\n" -" on %(time)s\n" -" " -msgstr "" - -#: templates/blog/list.html:93 +#: templates/blog/list.html:85 msgid "Blog" msgstr "" -#: templates/blog/list.html:95 +#: templates/blog/list.html:87 msgid "Events" msgstr "" -#: templates/blog/list.html:100 +#: templates/blog/list.html:92 msgid "News" msgstr "" -#: templates/blog/list.html:115 templates/problem/list.html:347 -#: templates/problem/problem.html:361 +#: templates/blog/list.html:130 templates/problem/problem.html:310 msgid "Clarifications" msgstr "" -#: templates/blog/list.html:121 -msgid "Add" -msgstr "" - -#: templates/blog/list.html:140 templates/problem/list.html:369 -#: templates/problem/problem.html:372 +#: templates/blog/list.html:146 templates/problem/problem.html:321 msgid "No clarifications have been made at this time." msgstr "" -#: templates/blog/list.html:148 +#: templates/blog/list.html:154 msgid "Ongoing contests" msgstr "" -#: templates/blog/list.html:166 +#: templates/blog/list.html:172 msgid "Upcoming contests" msgstr "" -#: templates/blog/list.html:184 -msgid "My open tickets" -msgstr "" - -#: templates/blog/list.html:206 -msgid "New tickets" -msgstr "" - -#: templates/blog/list.html:227 -msgid "New problems" -msgstr "" - -#: templates/blog/list.html:244 +#: templates/blog/list.html:189 msgid "Comment stream" msgstr "" -#: templates/chat/chat.html:305 -msgid "Chat" +#: templates/blog/list.html:208 +msgid "New problems" msgstr "" -#: templates/chat/chat.html:307 templates/chat/chat.html:314 -msgid "Online Users" +#: templates/blog/list.html:225 +msgid "My open tickets" msgstr "" -#: templates/chat/chat.html:315 -msgid "Refresh" +#: templates/blog/list.html:246 +msgid "New tickets" msgstr "" -#: templates/chat/chat.html:333 -msgid "Emoji" -msgstr "" - -#: templates/chat/chat.html:334 -msgid "Enter your message" -msgstr "" - -#: templates/chat/message.html:20 -msgid "Delete" +#: templates/chat/chat.html:167 +msgid "Your message" msgstr "" #: templates/comments/list.html:2 @@ -3185,21 +3006,11 @@ msgstr "" msgid "Please login to vote" msgstr "" -#: templates/comments/list.html:40 -#, python-brace-format -msgid "commented on {time}" -msgstr "" - -#: templates/comments/list.html:49 -#, python-format -msgid "edit %(edits)s" -msgstr "" - -#: templates/comments/list.html:51 templates/comments/media-js.html:92 +#: templates/comments/list.html:51 templates/comments/media-js.html:77 msgid "edited" msgstr "" -#: templates/comments/list.html:60 templates/notification/list.html:14 +#: templates/comments/list.html:60 msgid "Link" msgstr "" @@ -3207,52 +3018,36 @@ msgstr "" msgid "Reply" msgstr "" -#: templates/comments/list.html:86 templates/contest/list.html:91 -#: templates/contest/list.html:95 templates/contest/list.html:280 +#: templates/comments/list.html:86 msgid "Hide" msgstr "" -#: templates/comments/list.html:101 -#, python-format -msgid "" -"\n" -" This comment is hidden due " -"to too much negative feedback.\n" -" Click here to view it.\n" -" " -msgstr "" - -#: templates/comments/list.html:121 +#: templates/comments/list.html:120 msgid "There are no comments at the moment." msgstr "" -#: templates/comments/list.html:127 +#: templates/comments/list.html:126 msgid "New comment" msgstr "" -#: templates/comments/list.html:141 +#: templates/comments/list.html:140 msgid "Invalid comment body." msgstr "" -#: templates/comments/list.html:149 +#: templates/comments/list.html:148 msgid "Post!" msgstr "" -#: templates/comments/list.html:157 +#: templates/comments/list.html:156 msgid "Comments are disabled on this page." msgstr "" -#: templates/comments/media-js.html:38 -msgid "Replying to comment" -msgstr "" - -#: templates/comments/media-js.html:87 +#: templates/comments/media-js.html:72 #, python-brace-format msgid "edit {edits}" msgstr "" -#: templates/comments/media-js.html:90 +#: templates/comments/media-js.html:75 msgid "original" msgstr "" @@ -3296,11 +3091,6 @@ msgstr "" msgid "Saturday" msgstr "" -#: templates/contest/clarification.html:52 templates/organization/new.html:10 -#: templates/ticket/new.html:38 -msgid "Create" -msgstr "" - #: templates/contest/clone.html:37 msgid "Enter a new key for the cloned contest:" msgstr "" @@ -3321,171 +3111,97 @@ msgstr "" msgid "Next" msgstr "" -#: templates/contest/contest-list-tabs.html:21 -#: templates/problem/problem-list-tabs.html:5 -msgid "List" -msgstr "" - -#: templates/contest/contest-list-tabs.html:22 -msgid "Calendar" -msgstr "" - -#: templates/contest/contest-tabs.html:4 templates/organization/home.html:105 -msgid "Info" -msgstr "" - -#: templates/contest/contest-tabs.html:6 templates/stats/base.html:9 -#: templates/submission/list.html:339 -msgid "Statistics" -msgstr "" - -#: templates/contest/contest-tabs.html:11 -msgid "Rankings" -msgstr "" - -#: templates/contest/contest-tabs.html:16 -msgid "Hidden Rankings" -msgstr "" - -#: templates/contest/contest-tabs.html:21 -msgid "MOSS" -msgstr "" - -#: templates/contest/contest-tabs.html:26 -msgid "Clone" -msgstr "" - -#: templates/contest/contest-tabs.html:38 -#: templates/contest/contest-tabs.html:58 +#: templates/contest/contest-tabs.html:37 msgid "Leave contest" msgstr "" -#: templates/contest/contest-tabs.html:45 templates/contest/list.html:388 +#: templates/contest/contest-tabs.html:44 templates/contest/list.html:293 msgid "Virtual join" msgstr "" -#: templates/contest/contest-tabs.html:56 -msgid "Stop spectating" -msgstr "" - -#: templates/contest/contest-tabs.html:65 +#: templates/contest/contest-tabs.html:64 msgid "Spectate contest" msgstr "" -#: templates/contest/contest-tabs.html:72 +#: templates/contest/contest-tabs.html:70 +#: templates/contest/contest-tabs.html:76 msgid "Join contest" msgstr "" -#: templates/contest/contest-tabs.html:81 +#: templates/contest/contest-tabs.html:85 msgid "Login to participate" msgstr "" -#: templates/contest/contest.html:37 -msgid "Participating virtually." -msgstr "" - -#: templates/contest/contest.html:43 -msgid "Contest is over." -msgstr "" - #: templates/contest/contest.html:59 templates/contest/contest.html:63 msgid "F j, Y, G:i T" msgstr "" -#: templates/contest/contest.html:59 -#, python-format -msgid "" -"%(time_limit)s window between %(start_time)s and " -"%(end_time)s" -msgstr "" - -#: templates/contest/contest.html:63 -#, python-format -msgid "%(length)s long starting on %(start_time)s" -msgstr "" - #: templates/contest/contest.html:85 msgid "AC Rate" msgstr "" -#: templates/contest/contest.html:86 templates/contest/list.html:237 -#: templates/contest/list.html:289 templates/contest/list.html:366 -#: templates/problem/list.html:223 templates/problem/list.html:254 +#: templates/contest/contest.html:86 templates/contest/list.html:153 +#: templates/contest/list.html:195 templates/contest/list.html:271 +#: templates/problem/list.html:212 templates/problem/list.html:238 msgid "Users" msgstr "" -#: templates/contest/contest.html:111 templates/problem/list.html:330 +#: templates/contest/contest.html:111 msgid "Editorial" msgstr "" -#: templates/contest/list.html:83 templates/contest/media-js.html:9 +#: templates/contest/list.html:31 templates/contest/media-js.html:9 msgid "Are you sure you want to join?" msgstr "" -#: templates/contest/list.html:84 +#: templates/contest/list.html:32 msgid "" "Joining a contest for the first time starts your timer, after which it " "becomes unstoppable." msgstr "" -#: templates/contest/list.html:92 templates/contest/list.html:278 -msgid "Show" -msgstr "" - -#: templates/contest/list.html:102 templates/problem/list.html:68 -msgid "Organizations..." -msgstr "" - -#: templates/contest/list.html:135 +#: templates/contest/list.html:65 msgid "hidden" msgstr "" -#: templates/contest/list.html:140 +#: templates/contest/list.html:70 msgid "private" msgstr "" -#: templates/contest/list.html:154 +#: templates/contest/list.html:84 msgid "rated" msgstr "" -#: templates/contest/list.html:202 +#: templates/contest/list.html:132 msgid "Spectate" msgstr "" -#: templates/contest/list.html:208 +#: templates/contest/list.html:138 msgid "Join" msgstr "" -#: templates/contest/list.html:220 -msgid "Search contests..." -msgstr "" - -#: templates/contest/list.html:229 -msgid "Search" -msgstr "" - -#: templates/contest/list.html:232 +#: templates/contest/list.html:148 msgid "Active Contests" msgstr "" -#: templates/contest/list.html:236 templates/contest/list.html:288 -#: templates/contest/list.html:327 templates/contest/list.html:365 +#: templates/contest/list.html:152 templates/contest/list.html:194 +#: templates/contest/list.html:232 templates/contest/list.html:270 msgid "Contest" msgstr "" -#: templates/contest/list.html:275 +#: templates/contest/list.html:190 msgid "Ongoing Contests" msgstr "" -#: templates/contest/list.html:322 +#: templates/contest/list.html:227 msgid "Upcoming Contests" msgstr "" -#: templates/contest/list.html:350 +#: templates/contest/list.html:255 msgid "There are no scheduled contests at this time." msgstr "" -#: templates/contest/list.html:356 +#: templates/contest/list.html:261 msgid "Past Contests" msgstr "" @@ -3536,71 +3252,47 @@ msgstr "" msgid "Only the following organizations may access this contest:" msgstr "" -#: templates/contest/ranking-table.html:9 templates/problem/search-form.html:35 +#: templates/contest/ranking-table.html:7 msgid "Organization" msgstr "" -#: templates/contest/ranking-table.html:10 templates/user/users-table.html:13 -msgid "Full Name" -msgstr "" - -#: templates/contest/ranking-table.html:44 +#: templates/contest/ranking-table.html:30 msgid "Un-Disqualify" msgstr "" -#: templates/contest/ranking-table.html:47 +#: templates/contest/ranking-table.html:33 msgid "Disqualify" msgstr "" -#: templates/contest/ranking.html:187 +#: templates/contest/ranking.html:173 msgid "Are you sure you want to disqualify this participation?" msgstr "" -#: templates/contest/ranking.html:192 +#: templates/contest/ranking.html:178 msgid "Are you sure you want to un-disqualify this participation?" msgstr "" -#: templates/contest/ranking.html:463 +#: templates/contest/ranking.html:252 msgid "View user participation" msgstr "" -#: templates/contest/ranking.html:467 +#: templates/contest/ranking.html:256 msgid "Show organizations" msgstr "" -#: templates/contest/ranking.html:471 -msgid "Show full name" -msgstr "" - -#: templates/contest/ranking.html:474 -msgid "Show friends only" -msgstr "" - -#: templates/contest/ranking.html:477 -msgid "Total score only" -msgstr "" - -#: templates/contest/ranking.html:479 -msgid "Show virtual participation" -msgstr "" - -#: templates/contest/stats.html:51 +#: templates/contest/stats.html:38 msgid "Problem Status Distribution" msgstr "" -#: templates/contest/stats.html:56 +#: templates/contest/stats.html:43 msgid "Problem AC Rate" msgstr "" -#: templates/contest/stats.html:62 -msgid "Problem Point Distribution" -msgstr "" - -#: templates/contest/stats.html:76 templates/stats/language.html:16 +#: templates/contest/stats.html:48 templates/stats/language.html:16 msgid "Submissions by Language" msgstr "" -#: templates/contest/stats.html:82 templates/stats/language.html:26 +#: templates/contest/stats.html:54 templates/stats/language.html:26 msgid "Language AC Rate" msgstr "" @@ -3609,7 +3301,6 @@ msgid "Source:" msgstr "" #: templates/newsletter/common.html:6 -#: templates/newsletter/newsletter_list.html:15 #: templates/newsletter/subscription_unsubscribe_activated.html:3 #: templates/newsletter/subscription_unsubscribe_activated.html:6 #: templates/newsletter/subscription_update_activated.html:3 @@ -3617,23 +3308,6 @@ msgstr "" msgid "Newsletter" msgstr "" -#: templates/newsletter/newsletter_list.html:2 -#: templates/newsletter/newsletter_list.html:3 -msgid "Newsletter list" -msgstr "" - -#: templates/newsletter/newsletter_list.html:6 -msgid "Subscribe to get the latest emails about upcoming contests and events." -msgstr "" - -#: templates/newsletter/newsletter_list.html:16 -msgid "Subscribe" -msgstr "" - -#: templates/newsletter/newsletter_list.html:30 -msgid "Update subscriptions" -msgstr "" - #: templates/newsletter/subscription_unsubscribe_activated.html:3 #: templates/newsletter/subscription_unsubscribe_activated.html:6 #: templates/newsletter/subscription_update_activated.html:3 @@ -3695,97 +3369,64 @@ msgid "" "follow in order to update your subscription." msgstr "" -#: templates/notification/list.html:7 -msgid "You have no notifications" -msgstr "" - -#: templates/notification/list.html:13 -msgid "Activity" -msgstr "" - #: templates/organization/edit.html:46 #: templates/organization/requests/pending.html:34 #: templates/ticket/edit-notes.html:4 msgid "Update" msgstr "" -#: templates/organization/home.html:41 +#: templates/organization/home.html:7 msgid "Are you sure you want to leave this organization?" msgstr "" -#: templates/organization/home.html:43 +#: templates/organization/home.html:9 msgid "You will have to rejoin to show up on the organization leaderboard." msgstr "" -#: templates/organization/home.html:45 +#: templates/organization/home.html:11 msgid "You will have to request membership in order to join again." msgstr "" -#: templates/organization/home.html:88 -msgid "Join organization" -msgstr "" - -#: templates/organization/home.html:92 -msgid "Request membership" -msgstr "" - -#: templates/organization/home.html:122 -msgid "Organization news" -msgstr "" - -#: templates/organization/home.html:128 -msgid "There is no news at this time." -msgstr "" - -#: templates/organization/home.html:137 -msgid "Controls" -msgstr "" - -#: templates/organization/home.html:142 -msgid "Edit organization" -msgstr "" - -#: templates/organization/home.html:148 -msgid "View requests" -msgstr "" - -#: templates/organization/home.html:161 -msgid "Admin organization" -msgstr "" - -#: templates/organization/home.html:167 -msgid "View members" -msgstr "" - -#: templates/organization/home.html:174 +#: templates/organization/home.html:24 msgid "Leave organization" msgstr "" -#: templates/organization/home.html:183 -msgid "New private contests" +#: templates/organization/home.html:29 +msgid "Join organization" msgstr "" -#: templates/organization/home.html:193 templates/organization/home.html:208 -msgid "View all" +#: templates/organization/home.html:33 +msgid "Request membership" msgstr "" -#: templates/organization/home.html:199 -msgid "New private problems" +#: templates/organization/home.html:39 +msgid "Edit organization" msgstr "" -#: templates/organization/list.html:40 -msgid "Show my organizations only" +#: templates/organization/home.html:43 +msgid "View requests" msgstr "" -#: templates/organization/list.html:47 templates/status/language-list.html:34 -#: templates/user/import/table_csv.html:6 +#: templates/organization/home.html:50 +msgid "Admin organization" +msgstr "" + +#: templates/organization/home.html:55 +msgid "View members" +msgstr "" + +#: templates/organization/list.html:23 templates/status/language-list.html:34 msgid "Name" msgstr "" -#: templates/organization/list.html:48 +#: templates/organization/list.html:24 msgid "Members" msgstr "" +#: templates/organization/new.html:10 templates/ticket/new.html:38 +msgid "Create" +msgstr "" + #: templates/organization/requests/detail.html:13 msgid "User:" msgstr "" @@ -3818,7 +3459,7 @@ msgid "There are no requests to approve." msgstr "" #: templates/organization/requests/pending.html:17 -#: templates/problem/data.html:432 +#: templates/problem/data.html:452 msgid "Delete?" msgstr "" @@ -3854,35 +3495,35 @@ msgstr "" msgid "Enter a new code for the cloned problem:" msgstr "" -#: templates/problem/data.html:119 +#: templates/problem/data.html:108 msgid "Instruction" msgstr "" -#: templates/problem/data.html:390 +#: templates/problem/data.html:410 msgid "View YAML" msgstr "" -#: templates/problem/data.html:421 templates/problem/data.html:472 +#: templates/problem/data.html:441 templates/problem/data.html:491 msgid "Apply!" msgstr "" -#: templates/problem/data.html:426 +#: templates/problem/data.html:446 msgid "Type" msgstr "" -#: templates/problem/data.html:427 +#: templates/problem/data.html:447 msgid "Input file" msgstr "" -#: templates/problem/data.html:428 +#: templates/problem/data.html:448 msgid "Output file" msgstr "" -#: templates/problem/data.html:430 +#: templates/problem/data.html:450 msgid "Pretest?" msgstr "" -#: templates/problem/data.html:473 +#: templates/problem/data.html:492 msgid "Add new case" msgstr "" @@ -3894,32 +3535,28 @@ msgid "" "problem yourself is a bannable offence." msgstr "" -#: templates/problem/list.html:66 +#: templates/problem/list.html:62 msgid "Filter by type..." msgstr "" -#: templates/problem/list.html:193 +#: templates/problem/list.html:185 msgid "Hot problems" msgstr "" -#: templates/problem/list.html:218 templates/problem/list.html:240 -#: templates/problem/search-form.html:45 templates/user/user-problems.html:57 +#: templates/problem/list.html:207 templates/problem/list.html:224 +#: templates/problem/search-form.html:30 templates/user/user-problems.html:57 msgid "Category" msgstr "" -#: templates/problem/list.html:220 templates/problem/list.html:244 +#: templates/problem/list.html:209 templates/problem/list.html:228 msgid "Types" msgstr "" -#: templates/problem/list.html:251 +#: templates/problem/list.html:235 #, python-format msgid "AC %%" msgstr "" -#: templates/problem/list.html:342 -msgid "Add clarifications" -msgstr "" - #: templates/problem/manage_submission.html:55 msgid "Leave empty to not filter by language" msgstr "" @@ -3928,203 +3565,152 @@ msgstr "" msgid "Leave empty to not filter by result" msgstr "" -#: templates/problem/manage_submission.html:80 +#: templates/problem/manage_submission.html:79 msgid "Need valid values for both start and end IDs." msgstr "" -#: templates/problem/manage_submission.html:83 +#: templates/problem/manage_submission.html:82 msgid "End ID must be after start ID." msgstr "" +#: templates/problem/manage_submission.html:90 +#, python-brace-format +msgid "" +"You are about to rejudge {count} submissions. Are you sure you want to do " +"this?" +msgstr "" + #: templates/problem/manage_submission.html:96 -#, python-brace-format msgid "" -"You are about to {action} {count} submissions. Are you sure you want to do " -"this?" +"You are about to rejudge a few submissions. Are you sure you want to do this?" msgstr "" -#: templates/problem/manage_submission.html:103 -#, python-brace-format -msgid "" -"You are about to {action} a few submissions. Are you sure you want to do " -"this?" +#: templates/problem/manage_submission.html:115 +msgid "Rejudge Submissions" msgstr "" -#: templates/problem/manage_submission.html:127 -#: templates/submission/list.html:309 -msgid "Filter submissions" -msgstr "" - -#: templates/problem/manage_submission.html:132 +#: templates/problem/manage_submission.html:120 msgid "Filter by ID:" msgstr "" -#: templates/problem/manage_submission.html:135 +#: templates/problem/manage_submission.html:123 msgid "Starting ID:" msgstr "" -#: templates/problem/manage_submission.html:139 +#: templates/problem/manage_submission.html:127 msgid "Ending ID:" msgstr "" -#: templates/problem/manage_submission.html:143 +#: templates/problem/manage_submission.html:131 msgid "This range includes both endpoints." msgstr "" -#: templates/problem/manage_submission.html:146 +#: templates/problem/manage_submission.html:134 msgid "Filter by language:" msgstr "" -#: templates/problem/manage_submission.html:154 +#: templates/problem/manage_submission.html:142 msgid "Filter by result:" msgstr "" -#: templates/problem/manage_submission.html:164 -msgid "Action" -msgstr "" - -#: templates/problem/manage_submission.html:166 +#: templates/problem/manage_submission.html:150 msgid "Rejudge selected submissions" msgstr "" -#: templates/problem/manage_submission.html:171 -msgid "Download selected submissions" +#: templates/problem/manage_submission.html:157 +msgid "Rescore Everything" msgstr "" -#: templates/problem/manage_submission.html:177 -#, python-format -msgid "Are you sure you want to rescore %(count)d submissions?" -msgstr "" - -#: templates/problem/manage_submission.html:178 +#: templates/problem/manage_submission.html:163 msgid "Rescore all submissions" msgstr "" -#: templates/problem/problem.html:132 +#: templates/problem/problem.html:91 msgid "View as PDF" msgstr "" -#: templates/problem/problem.html:141 templates/problem/problem.html:151 -#: templates/problem/problem.html:156 +#: templates/problem/problem.html:101 templates/problem/problem.html:111 +#: templates/problem/problem.html:116 msgid "Submit solution" msgstr "" -#: templates/problem/problem.html:144 -#, python-format -msgid "%(counter)s submission left" -msgid_plural "%(counter)s submissions left" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" - -#: templates/problem/problem.html:152 +#: templates/problem/problem.html:112 msgid "0 submissions left" msgstr "" -#: templates/problem/problem.html:164 +#: templates/problem/problem.html:124 msgid "My submissions" msgstr "" -#: templates/problem/problem.html:168 +#: templates/problem/problem.html:128 msgid "Best submissions" msgstr "" -#: templates/problem/problem.html:172 +#: templates/problem/problem.html:132 msgid "Read editorial" msgstr "" -#: templates/problem/problem.html:177 +#: templates/problem/problem.html:137 msgid "Manage tickets" msgstr "" -#: templates/problem/problem.html:181 +#: templates/problem/problem.html:141 msgid "Edit problem" msgstr "" -#: templates/problem/problem.html:183 +#: templates/problem/problem.html:143 msgid "Edit test data" msgstr "" -#: templates/problem/problem.html:188 +#: templates/problem/problem.html:148 msgid "My tickets" msgstr "" -#: templates/problem/problem.html:196 +#: templates/problem/problem.html:156 msgid "Manage submissions" msgstr "" -#: templates/problem/problem.html:202 +#: templates/problem/problem.html:162 msgid "Clone problem" msgstr "" -#: templates/problem/problem.html:209 +#: templates/problem/problem.html:169 msgid "Points:" msgstr "" -#: templates/problem/problem.html:212 templates/problem/problem.html:214 +#: templates/problem/problem.html:172 templates/problem/problem.html:174 msgid "(partial)" msgstr "" -#: templates/problem/problem.html:219 +#: templates/problem/problem.html:179 msgid "Time limit:" msgstr "" -#: templates/problem/problem.html:231 +#: templates/problem/problem.html:191 msgid "Memory limit:" msgstr "" -#: templates/problem/problem.html:250 -msgid "Author:" -msgid_plural "Authors:" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" - -#: templates/problem/problem.html:265 -msgid "Problem type" -msgid_plural "Problem types" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" - -#: templates/problem/problem.html:278 +#: templates/problem/problem.html:238 msgid "Allowed languages" msgstr "" -#: templates/problem/problem.html:286 -#, python-format -msgid "No %(lang)s judge online" -msgstr "" - -#: templates/problem/problem.html:297 -msgid "Judge:" -msgid_plural "Judges:" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" - -#: templates/problem/problem.html:314 +#: templates/problem/problem.html:274 msgid "none available" msgstr "" -#: templates/problem/problem.html:326 -#, python-format -msgid "This problem has %(length)s clarification(s)" -msgstr "" - -#: templates/problem/problem.html:350 +#: templates/problem/problem.html:299 msgid "Request clarification" msgstr "" -#: templates/problem/problem.html:352 +#: templates/problem/problem.html:301 msgid "Report an issue" msgstr "" -#: templates/problem/raw.html:64 +#: templates/problem/raw.html:62 msgid "Time Limit:" msgstr "" -#: templates/problem/raw.html:73 +#: templates/problem/raw.html:71 msgid "Memory Limit:" msgstr "" @@ -4148,74 +3734,39 @@ msgstr "" msgid "Show problem types" msgstr "" -#: templates/problem/search-form.html:32 -msgid "Show editorial" -msgstr "" - -#: templates/problem/search-form.html:48 templates/problem/search-form.html:50 -#: templates/submission/submission-list-tabs.html:4 +#: templates/problem/search-form.html:33 templates/problem/search-form.html:35 msgid "All" msgstr "" -#: templates/problem/search-form.html:62 +#: templates/problem/search-form.html:46 msgid "Problem types" msgstr "" -#: templates/problem/search-form.html:73 +#: templates/problem/search-form.html:57 msgid "Point range" msgstr "" -#: templates/problem/search-form.html:79 templates/submission/list.html:331 +#: templates/problem/search-form.html:63 templates/submission/list.html:331 #: templates/ticket/list.html:248 msgid "Go" msgstr "" -#: templates/problem/search-form.html:80 +#: templates/problem/search-form.html:64 msgid "Random" msgstr "" -#: templates/problem/submit.html:117 -msgid "Your source code must contain at most 65536 characters." -msgstr "" - -#: templates/problem/submit.html:204 -#, python-format -msgid "" -"Warning! Your default language, %(default_language)s, is " -"unavailable for this problem and has been deselected." -msgstr "" - -#: templates/problem/submit.html:215 -#, python-format -msgid "" -"\n" -" You have %(left)s submission left\n" -" " -msgid_plural "" -"\n" -" You have %(left)s submissions left\n" -" " -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" - -#: templates/problem/submit.html:224 +#: templates/problem/submit.html:212 msgid "You have 0 submissions left" msgstr "" -#: templates/problem/submit.html:258 +#: templates/problem/submit.html:250 msgid "No judge is available for this problem." msgstr "" -#: templates/problem/submit.html:262 +#: templates/problem/submit.html:252 msgid "Submit!" msgstr "" -#: templates/registration/activate.html:3 -#, python-format -msgid "%(key)s is an invalid activation key." -msgstr "" - #: templates/registration/activation_complete.html:3 msgid "Your account has been successfully activated." msgstr "" @@ -4273,13 +3824,6 @@ msgid "" "you registered with, and check your spam folder." msgstr "" -#: templates/registration/password_reset_email.txt:1 -#, python-format -msgid "" -"You're receiving this email because you requested a password reset for your " -"user account at %(site_name)s." -msgstr "" - #: templates/registration/password_reset_email.txt:3 msgid "Please go to the following page and choose a new password:" msgstr "" @@ -4292,16 +3836,6 @@ msgstr "" msgid "Thanks for using our site!" msgstr "" -#: templates/registration/password_reset_email.txt:11 -#, python-format -msgid "The %(site_name)s team" -msgstr "" - -#: templates/registration/password_reset_subject.txt:1 -#, python-format -msgid "Password reset on %(site_name)s" -msgstr "" - #: templates/registration/profile_creation.html:36 #: templates/registration/username_select.html:7 msgid "Continue >" @@ -4338,20 +3872,19 @@ msgstr "" msgid "Affiliated organizations" msgstr "" -#: templates/registration/registration_form.html:195 -#: templates/user/edit-profile.html:128 +#: templates/registration/registration_form.html:192 msgid "Notify me about upcoming contests" msgstr "" -#: templates/registration/registration_form.html:209 +#: templates/registration/registration_form.html:206 msgid "By registering, you agree to our" msgstr "" -#: templates/registration/registration_form.html:210 +#: templates/registration/registration_form.html:207 msgid "Terms & Conditions" msgstr "" -#: templates/registration/registration_form.html:213 +#: templates/registration/registration_form.html:210 msgid "Register!" msgstr "" @@ -4361,11 +3894,6 @@ msgstr "" msgid "Enter the 6-digit code generated by your app:" msgstr "" -#: templates/registration/totp_auth.html:41 -#, python-format -msgid "If you lost your authentication device, please contact us at %(email)s." -msgstr "" - #: templates/registration/totp_disable.html:38 msgid "" "To protect your account, you must first authenticate before you can disable " @@ -4384,6 +3912,10 @@ msgstr "" msgid "Or enter this code manually:" msgstr "" +#: templates/stats/base.html:9 templates/submission/list.html:339 +msgid "Statistics" +msgstr "" + #: templates/stats/language.html:11 msgid "Submission Statistics" msgstr "" @@ -4409,7 +3941,6 @@ msgid "Ping" msgstr "" #: templates/status/judge-status-table.html:8 -#: templates/user/import/index.html:104 msgid "Load" msgstr "" @@ -4425,7 +3956,6 @@ msgid "There are no judges available at this time." msgstr "" #: templates/status/language-list.html:33 templates/ticket/list.html:261 -#: templates/user/import/table_csv.html:3 msgid "ID" msgstr "" @@ -4433,22 +3963,6 @@ msgstr "" msgid "Runtime Info" msgstr "" -#: templates/status/status-tabs.html:4 -msgid "Judges" -msgstr "" - -#: templates/status/status-tabs.html:6 -msgid "Version Matrix" -msgstr "" - -#: templates/submission/internal-error-message.html:3 -#, python-format -msgid "" -"An internal error occurred while grading, and the %(SITE_NAME)s " -"administrators have been notified.
In the meantime, try resubmitting in " -"a few seconds." -msgstr "" - #: templates/submission/internal-error-message.html:8 msgid "An internal error occurred while grading." msgstr "" @@ -4465,6 +3979,10 @@ msgstr "" msgid "Filter by language..." msgstr "" +#: templates/submission/list.html:309 +msgid "Filter submissions" +msgstr "" + #: templates/submission/list.html:345 msgid "Total:" msgstr "" @@ -4521,64 +4039,63 @@ msgstr "" msgid "Execution Results" msgstr "" -#: templates/submission/status-testcases.html:34 -msgid "Overall: " -msgstr "" - -#: templates/submission/status-testcases.html:48 -msgid "Point: " -msgstr "" - -#: templates/submission/status-testcases.html:53 -msgid "Time: " -msgstr "" - -#: templates/submission/status-testcases.html:62 -msgid "Memory: " -msgstr "" - -#: templates/submission/status-testcases.html:73 +#: templates/submission/status-testcases.html:31 msgid "Batch " msgstr "" -#: templates/submission/status-testcases.html:84 -#: templates/submission/status-testcases.html:113 -msgid "Point" +#: templates/submission/status-testcases.html:43 +msgid "Overall: " msgstr "" -#: templates/submission/status-testcases.html:99 +#: templates/submission/status-testcases.html:57 +msgid "Point: " +msgstr "" + +#: templates/submission/status-testcases.html:62 +msgid "Time: " +msgstr "" + +#: templates/submission/status-testcases.html:71 +msgid "Memory: " +msgstr "" + +#: templates/submission/status-testcases.html:84 msgid "Case" msgstr "" -#: templates/submission/status-testcases.html:101 +#: templates/submission/status-testcases.html:86 msgid "Pretest" msgstr "" -#: templates/submission/status-testcases.html:103 +#: templates/submission/status-testcases.html:88 msgid "Test case" msgstr "" -#: templates/submission/status-testcases.html:141 +#: templates/submission/status-testcases.html:99 +msgid "Point" +msgstr "" + +#: templates/submission/status-testcases.html:121 msgid "Input:" msgstr "" -#: templates/submission/status-testcases.html:145 +#: templates/submission/status-testcases.html:125 msgid "Output:" msgstr "" -#: templates/submission/status-testcases.html:149 +#: templates/submission/status-testcases.html:129 msgid "Answer:" msgstr "" -#: templates/submission/status-testcases.html:154 +#: templates/submission/status-testcases.html:134 msgid "Judge feedback:" msgstr "" -#: templates/submission/status-testcases.html:175 +#: templates/submission/status-testcases.html:157 msgid "Passing pretests does not guarantee a full score on system tests." msgstr "" -#: templates/submission/status-testcases.html:178 +#: templates/submission/status-testcases.html:160 msgid "Submission aborted!" msgstr "" @@ -4590,24 +4107,11 @@ msgstr "" msgid "Abort" msgstr "" -#: templates/submission/submission-list-tabs.html:6 -msgid "Mine" -msgstr "" - -#: templates/submission/submission-list-tabs.html:9 -msgid "Best" -msgstr "" - -#: templates/submission/submission-list-tabs.html:12 -#, python-format -msgid "%(user)s's" -msgstr "" - -#: templates/ticket/list.html:135 templates/ticket/ticket.html:273 +#: templates/ticket/list.html:135 templates/ticket/ticket.html:257 msgid "Reopened: " msgstr "" -#: templates/ticket/list.html:138 templates/ticket/ticket.html:274 +#: templates/ticket/list.html:138 templates/ticket/ticket.html:258 msgid "Closed: " msgstr "" @@ -4631,7 +4135,7 @@ msgstr "" msgid "Title" msgstr "" -#: templates/ticket/list.html:264 templates/ticket/ticket.html:369 +#: templates/ticket/list.html:264 templates/ticket/ticket.html:328 msgid "Assignees" msgstr "" @@ -4646,36 +4150,32 @@ msgid "" "a problem, ask in the comments instead." msgstr "" -#: templates/ticket/ticket.html:355 -msgid "Post" -msgstr "" - -#: templates/ticket/ticket.html:363 +#: templates/ticket/ticket.html:322 msgid "Associated object" msgstr "" -#: templates/ticket/ticket.html:374 +#: templates/ticket/ticket.html:333 msgid "No one is assigned." msgstr "" -#: templates/ticket/ticket.html:380 +#: templates/ticket/ticket.html:339 msgid "Close ticket" msgstr "" -#: templates/ticket/ticket.html:382 +#: templates/ticket/ticket.html:341 msgid "Reopen ticket" msgstr "" -#: templates/ticket/ticket.html:386 +#: templates/ticket/ticket.html:345 msgid "Assignee notes" msgstr "" -#: templates/ticket/ticket.html:393 templates/widgets/select_all.html:4 +#: templates/ticket/ticket.html:352 templates/widgets/select_all.html:4 msgid "Nothing here." msgstr "" -#: templates/user/base-users-table.html:3 -msgid "Rank" +#: templates/ticket/ticket.html:385 +msgid "Post" msgstr "" #: templates/user/base-users.html:14 templates/user/base-users.html:69 @@ -4722,169 +4222,50 @@ msgstr "" msgid "Update profile" msgstr "" -#: templates/user/import/index.html:31 -msgid "Upload CSV only" -msgstr "" - -#: templates/user/import/index.html:100 -msgid "User File" -msgstr "" - -#: templates/user/import/index.html:102 -msgid "Sample" -msgstr "" - -#: templates/user/import/index.html:105 templates/user/user-list-tabs.html:8 -msgid "Import" -msgstr "" - -#: templates/user/import/table_csv.html:7 -msgid "School" -msgstr "" - -#: templates/user/pp-row.html:22 -#, python-format -msgid "" -"\n" -" weighted %(weight)s%%\n" -" " -msgstr "" - -#: templates/user/pp-row.html:27 -#, python-format -msgid "%(pp).1fpp" -msgstr "" - -#: templates/user/pp-row.html:29 -#, python-format -msgid "%(pp).0fpp" -msgstr "" - -#: templates/user/user-about.html:23 -#, python-format -msgid "%(counter)s problem solved" -msgid_plural "%(counter)s problems solved" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" - -#: templates/user/user-about.html:35 -msgid "Total points" -msgstr "" - -#: templates/user/user-about.html:45 -msgid "Rank by rating" -msgstr "" - -#: templates/user/user-about.html:52 -msgid "Rank by points" -msgstr "" - -#: templates/user/user-about.html:64 +#: templates/user/user-about.html:14 msgid "From" msgstr "" -#: templates/user/user-about.html:75 +#: templates/user/user-about.html:25 msgid "Admin Notes" msgstr "" -#: templates/user/user-about.html:90 +#: templates/user/user-about.html:40 msgid "You have not shared any information." msgstr "" -#: templates/user/user-about.html:92 +#: templates/user/user-about.html:42 msgid "This user has not shared any information." msgstr "" -#: templates/user/user-about.html:101 -msgid "Awards" +#: templates/user/user-base.html:50 +msgid "Rank by points:" msgstr "" -#: templates/user/user-about.html:112 -#, python-format -msgid "%(label)s (%(date)s)" +#: templates/user/user-base.html:53 +msgid "Total points:" msgstr "" -#: templates/user/user-about.html:130 -msgid "Mon" +#: templates/user/user-base.html:68 +msgid "Rank by rating:" msgstr "" -#: templates/user/user-about.html:135 -msgid "Tues" +#: templates/user/user-base.html:70 +msgid "Rating:" msgstr "" -#: templates/user/user-about.html:140 -msgid "Wed" -msgstr "" - -#: templates/user/user-about.html:145 -msgid "Thurs" -msgstr "" - -#: templates/user/user-about.html:150 -msgid "Fri" -msgstr "" - -#: templates/user/user-about.html:155 -msgid "Sat" -msgstr "" - -#: templates/user/user-about.html:160 -msgid "Sun" -msgstr "" - -#: templates/user/user-about.html:169 -msgid "Less" -msgstr "" - -#: templates/user/user-about.html:175 -msgid "More" -msgstr "" - -#: templates/user/user-about.html:184 -msgid "Rating History" -msgstr "" - -#: templates/user/user-about.html:255 -msgid "past year" -msgstr "" - -#: templates/user/user-about.html:272 -msgid "total submission(s)" -msgstr "" - -#: templates/user/user-about.html:276 -msgid "submissions in the last year" -msgstr "" - -#: templates/user/user-base.html:101 -msgid "Unfollow" -msgstr "" - -#: templates/user/user-base.html:104 -msgid "Follow" -msgstr "" - -#: templates/user/user-base.html:120 -msgid "Contests written" -msgstr "" - -#: templates/user/user-base.html:124 +#: templates/user/user-base.html:71 msgid "Volatility:" msgstr "" -#: templates/user/user-base.html:128 +#: templates/user/user-base.html:72 msgid "Min. rating:" msgstr "" -#: templates/user/user-base.html:132 +#: templates/user/user-base.html:73 msgid "Max rating:" msgstr "" -#: templates/user/user-list-tabs.html:5 -msgid "Friends" -msgstr "" - #: templates/user/user-problems.html:35 msgid "Points Breakdown" msgstr "" @@ -4905,32 +4286,10 @@ msgstr "" msgid "Hide problems I've solved" msgstr "" -#: templates/user/user-problems.html:93 -#, python-format -msgid "%(points).1f points" -msgstr "" - #: templates/user/user-problems.html:99 msgid "Score" msgstr "" -#: templates/user/user-problems.html:110 -#, python-format -msgid "%(points)s / %(total)s" -msgstr "" - -#: templates/user/user-tabs.html:7 -msgid "Impersonate" -msgstr "" - -#: templates/user/user-tabs.html:13 -msgid "Admin User" -msgstr "" - -#: templates/user/user-tabs.html:16 -msgid "Admin Profile" -msgstr "" - #: templates/widgets/select_all.html:8 msgid "Check all" msgstr "" diff --git a/locale/sr_Latn/LC_MESSAGES/djangojs.po b/locale/sr_Latn/LC_MESSAGES/djangojs.po index faeec8a..4ce08be 100644 --- a/locale/sr_Latn/LC_MESSAGES/djangojs.po +++ b/locale/sr_Latn/LC_MESSAGES/djangojs.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: dmoj\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-07-20 23:30+0700\n" +"POT-Creation-Date: 2019-10-01 23:12+0000\n" "PO-Revision-Date: 2019-11-11 22:06\n" "Last-Translator: Icyene\n" "Language-Team: Serbian (Latin)\n" @@ -10,8 +10,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" -"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: dmoj\n" "X-Crowdin-Language: sr-CS\n" @@ -29,3 +28,4 @@ msgstr[2] "" msgctxt "time format without day" msgid "%h:%m:%s" msgstr "" + diff --git a/locale/tr/LC_MESSAGES/django.po b/locale/tr/LC_MESSAGES/django.po index 4e2e4e3..6e003e5 100644 --- a/locale/tr/LC_MESSAGES/django.po +++ b/locale/tr/LC_MESSAGES/django.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: dmoj\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-10-25 05:59+0700\n" +"POT-Creation-Date: 2020-04-10 01:26-0500\n" "PO-Revision-Date: 2019-11-11 22:06\n" "Last-Translator: Icyene\n" "Language-Team: Turkish\n" @@ -16,93 +16,93 @@ msgstr "" "X-Crowdin-Language: tr\n" "X-Crowdin-File: django.po\n" -#: chat_box/models.py:16 judge/admin/interface.py:110 -#: judge/models/contest.py:403 judge/models/contest.py:528 -#: judge/models/profile.py:211 +#: chat_box/models.py:15 judge/admin/interface.py:107 +#: judge/models/contest.py:257 judge/models/contest.py:381 +#: judge/models/profile.py:191 msgid "user" msgstr "kullanıcı" -#: chat_box/models.py:17 judge/models/comment.py:43 judge/models/comment.py:191 +#: chat_box/models.py:16 judge/models/comment.py:42 msgid "posted time" msgstr "gönderi zamanı" -#: chat_box/models.py:18 judge/models/comment.py:47 +#: chat_box/models.py:17 judge/models/comment.py:46 msgid "body of comment" msgstr "yorum metni" -#: chat_box/views.py:29 templates/chat/chat.html:4 +#: chat_box/views.py:29 msgid "Chat Box" msgstr "" -#: dmoj/settings.py:355 +#: dmoj/settings.py:349 msgid "German" msgstr "" -#: dmoj/settings.py:356 +#: dmoj/settings.py:350 msgid "English" msgstr "" -#: dmoj/settings.py:357 +#: dmoj/settings.py:351 msgid "Spanish" msgstr "" -#: dmoj/settings.py:358 +#: dmoj/settings.py:352 msgid "French" msgstr "" -#: dmoj/settings.py:359 +#: dmoj/settings.py:353 msgid "Croatian" msgstr "" -#: dmoj/settings.py:360 +#: dmoj/settings.py:354 msgid "Hungarian" msgstr "" -#: dmoj/settings.py:361 +#: dmoj/settings.py:355 msgid "Japanese" msgstr "" -#: dmoj/settings.py:362 +#: dmoj/settings.py:356 msgid "Korean" msgstr "" -#: dmoj/settings.py:363 +#: dmoj/settings.py:357 msgid "Brazilian Portuguese" msgstr "" -#: dmoj/settings.py:364 +#: dmoj/settings.py:358 msgid "Romanian" msgstr "" -#: dmoj/settings.py:365 +#: dmoj/settings.py:359 msgid "Russian" msgstr "" -#: dmoj/settings.py:366 +#: dmoj/settings.py:360 msgid "Serbian (Latin)" msgstr "" -#: dmoj/settings.py:367 +#: dmoj/settings.py:361 msgid "Turkish" msgstr "" -#: dmoj/settings.py:368 +#: dmoj/settings.py:362 msgid "Vietnamese" msgstr "" -#: dmoj/settings.py:369 +#: dmoj/settings.py:363 msgid "Simplified Chinese" msgstr "" -#: dmoj/settings.py:370 +#: dmoj/settings.py:364 msgid "Traditional Chinese" msgstr "" -#: dmoj/urls.py:58 +#: dmoj/urls.py:57 msgid "Login" msgstr "Giriş" -#: dmoj/urls.py:106 templates/base.html:193 +#: dmoj/urls.py:105 templates/base.html:190 msgid "Home" msgstr "Ana sayfa" @@ -132,92 +132,90 @@ msgstr "Yorumları göster" msgid "Associated page" msgstr "İlişkili sayfa" -#: judge/admin/contest.py:30 +#: judge/admin/contest.py:28 msgid "Included contests" msgstr "Yarışmalar" -#: judge/admin/contest.py:66 templates/contest/clarification.html:42 -#: templates/contest/contest.html:83 templates/contest/moss.html:43 -#: templates/problem/list.html:214 templates/problem/list.html:232 -#: templates/problem/list.html:350 templates/user/user-problems.html:56 +#: judge/admin/contest.py:64 templates/contest/contest.html:83 +#: templates/contest/moss.html:43 templates/problem/list.html:206 +#: templates/problem/list.html:221 templates/user/user-problems.html:56 #: templates/user/user-problems.html:98 msgid "Problem" msgstr "" -#: judge/admin/contest.py:119 +#: judge/admin/contest.py:112 msgid "Settings" msgstr "" -#: judge/admin/contest.py:121 +#: judge/admin/contest.py:114 msgid "Scheduling" msgstr "Planlama" -#: judge/admin/contest.py:122 templates/organization/home.html:107 +#: judge/admin/contest.py:115 msgid "Details" msgstr "Ayrıntılar" -#: judge/admin/contest.py:123 +#: judge/admin/contest.py:116 msgid "Format" msgstr "" -#: judge/admin/contest.py:124 templates/contest/ranking-table.html:7 -#: templates/user/user-about.html:15 templates/user/user-about.html:45 +#: judge/admin/contest.py:117 templates/contest/ranking-table.html:5 msgid "Rating" msgstr "Derecelendirme" -#: judge/admin/contest.py:125 +#: judge/admin/contest.py:118 msgid "Access" msgstr "" -#: judge/admin/contest.py:127 judge/admin/problem.py:131 +#: judge/admin/contest.py:120 judge/admin/problem.py:131 msgid "Justice" msgstr "Demir yumruk" -#: judge/admin/contest.py:207 +#: judge/admin/contest.py:158 #, python-format msgid "%d contest successfully marked as visible." msgid_plural "%d contests successfully marked as visible." msgstr[0] "" msgstr[1] "" -#: judge/admin/contest.py:210 +#: judge/admin/contest.py:161 msgid "Mark contests as visible" msgstr "" -#: judge/admin/contest.py:216 +#: judge/admin/contest.py:165 #, python-format msgid "%d contest successfully marked as hidden." msgid_plural "%d contests successfully marked as hidden." msgstr[0] "" msgstr[1] "" -#: judge/admin/contest.py:219 +#: judge/admin/contest.py:168 msgid "Mark contests as hidden" msgstr "" -#: judge/admin/contest.py:233 judge/admin/submission.py:164 +#: judge/admin/contest.py:182 judge/admin/submission.py:164 #, python-format msgid "%d submission was successfully scheduled for rejudging." msgid_plural "%d submissions were successfully scheduled for rejudging." msgstr[0] "" msgstr[1] "" -#: judge/admin/contest.py:308 +#: judge/admin/contest.py:256 #, python-format msgid "%d participation recalculated." msgid_plural "%d participations recalculated." msgstr[0] "" msgstr[1] "" -#: judge/admin/contest.py:311 +#: judge/admin/contest.py:259 msgid "Recalculate results" msgstr "" -#: judge/admin/contest.py:315 judge/admin/organization.py:65 +#: judge/admin/contest.py:263 judge/admin/organization.py:65 msgid "username" msgstr "kullanıcı adı" -#: judge/admin/contest.py:320 templates/base.html:277 +#: judge/admin/contest.py:268 templates/base.html:260 msgid "virtual" msgstr "sanal" @@ -225,15 +223,15 @@ msgstr "sanal" msgid "link path" msgstr "link ucu" -#: judge/admin/interface.py:65 +#: judge/admin/interface.py:62 msgid "Content" msgstr "İçerik" -#: judge/admin/interface.py:66 +#: judge/admin/interface.py:63 msgid "Summary" msgstr "Özet" -#: judge/admin/interface.py:151 +#: judge/admin/interface.py:148 msgid "object" msgstr "" @@ -255,9 +253,8 @@ msgid "Taxonomy" msgstr "Tasnif" #: judge/admin/problem.py:128 templates/contest/contest.html:84 -#: templates/problem/data.html:429 templates/problem/list.html:222 -#: templates/problem/list.html:248 templates/user/base-users-table.html:10 -#: templates/user/user-about.html:36 templates/user/user-about.html:52 +#: templates/problem/data.html:449 templates/problem/list.html:211 +#: templates/problem/list.html:232 templates/user/base-users-table.html:10 #: templates/user/user-problems.html:58 msgid "Points" msgstr "Puanlar" @@ -306,7 +303,6 @@ msgid "timezone" msgstr "saat dilimi" #: judge/admin/profile.py:86 judge/admin/submission.py:211 -#: templates/notification/list.html:12 #: templates/organization/requests/log.html:9 #: templates/organization/requests/pending.html:12 #: templates/ticket/list.html:263 @@ -314,7 +310,6 @@ msgid "User" msgstr "Kullanıcı" #: judge/admin/profile.py:91 templates/registration/registration_form.html:145 -#: templates/user/import/table_csv.html:8 msgid "Email" msgstr "E-posta" @@ -347,7 +342,7 @@ msgstr "Yasaklı problemler" msgid "These problems are NOT allowed to be submitted in this language" msgstr "Bu problemler için bu dilde çözüm gönderilemez" -#: judge/admin/runtime.py:83 templates/problem/list.html:352 +#: judge/admin/runtime.py:83 msgid "Description" msgstr "Tanım" @@ -394,7 +389,7 @@ msgstr "Bu miktarda çözümü yeniden değerlendirme yetkin yok." msgid "Rejudge the selected submissions" msgstr "Seçili çözümleri yeniden değerlendir" -#: judge/admin/submission.py:193 judge/views/problem_manage.py:159 +#: judge/admin/submission.py:193 judge/views/problem_manage.py:128 #, python-format msgid "%d submission were successfully rescored." msgid_plural "%d submissions were successfully rescored." @@ -405,8 +400,7 @@ msgstr[1] "%d çözüm yeniden puanlandı." msgid "Rescore the selected submissions" msgstr "Seçili çözümleri yeniden puanla" -#: judge/admin/submission.py:200 templates/problem/list.html:216 -#: templates/problem/list.html:236 +#: judge/admin/submission.py:200 msgid "Problem code" msgstr "Problem anahtarı" @@ -414,12 +408,10 @@ msgstr "Problem anahtarı" msgid "Problem name" msgstr "Problem adı" -#: judge/admin/submission.py:215 templates/notification/list.html:15 -#: templates/organization/requests/log.html:10 +#: judge/admin/submission.py:215 templates/organization/requests/log.html:10 #: templates/organization/requests/pending.html:13 -#: templates/problem/list.html:351 -#: templates/submission/status-testcases.html:125 -#: templates/submission/status-testcases.html:127 +#: templates/submission/status-testcases.html:105 +#: templates/submission/status-testcases.html:107 msgid "Time" msgstr "Zaman" @@ -433,7 +425,7 @@ msgstr "%d KB" msgid "%.2f MB" msgstr "%.2f MB" -#: judge/admin/submission.py:227 templates/submission/status-testcases.html:132 +#: judge/admin/submission.py:227 templates/submission/status-testcases.html:112 msgid "Memory" msgstr "Bellek" @@ -453,20 +445,20 @@ msgstr "Bu problemler bu problem tipinin içindedir" msgid "Online Judge" msgstr "Online Değerlendirme Sistemi" -#: judge/comments.py:60 +#: judge/comments.py:41 msgid "Comment body" msgstr "Yorum" -#: judge/comments.py:66 judge/views/ticket.py:63 +#: judge/comments.py:47 judge/views/ticket.py:46 msgid "Your part is silent, little toad." msgstr "Senin rolün sessiz, küçük kurbağa." -#: judge/comments.py:69 templates/comments/list.html:132 +#: judge/comments.py:50 templates/comments/list.html:131 msgid "" "You need to have solved at least one problem before your voice can be heard." msgstr "Sesini duyurabilmen için bir problem çözmüş olman gerekiyor." -#: judge/comments.py:113 +#: judge/comments.py:92 msgid "Posted comment" msgstr "Gönderilmiş yorum" @@ -482,10 +474,6 @@ msgstr "" msgid "ECOO" msgstr "" -#: judge/contest_format/icpc.py:19 -msgid "ICPC" -msgstr "" - #: judge/contest_format/ioi.py:19 msgid "IOI" msgstr "" @@ -498,60 +486,52 @@ msgstr "Yarışma güncellemelerine abone ol" msgid "Enable experimental features" msgstr "Deneysel özellikleri aç" -#: judge/forms.py:57 judge/views/organization.py:168 judge/views/register.py:49 +#: judge/forms.py:57 judge/views/organization.py:127 #, python-brace-format msgid "You may not be part of more than {count} public organizations." msgstr "{count} açık organizasyondan daha fazlasına üye olamazsın." -#: judge/forms.py:82 -#, fuzzy -#| msgid "judges" -msgid "Any judge" -msgstr "judge'lar" - -#: judge/forms.py:112 judge/views/register.py:26 +#: judge/forms.py:107 judge/views/register.py:26 #: templates/registration/registration_form.html:139 #: templates/user/base-users-table.html:5 -#: templates/user/import/table_csv.html:4 msgid "Username" msgstr "Kullanıcı Adı" -#: judge/forms.py:113 templates/registration/registration_form.html:151 +#: judge/forms.py:108 templates/registration/registration_form.html:151 #: templates/registration/registration_form.html:165 -#: templates/user/import/table_csv.html:5 msgid "Password" msgstr "Şifre" -#: judge/forms.py:135 +#: judge/forms.py:130 msgid "Two Factor Authentication tokens must be 6 decimal digits." msgstr "" -#: judge/forms.py:144 templates/registration/totp_auth.html:32 +#: judge/forms.py:139 templates/registration/totp_auth.html:32 msgid "Invalid Two Factor Authentication token." msgstr "" -#: judge/forms.py:148 judge/models/problem.py:97 +#: judge/forms.py:143 judge/models/problem.py:97 msgid "Problem code must be ^[a-z0-9]+$" msgstr "Problem kodu ^[a-z0-9]+$ olmalıdır" -#: judge/forms.py:153 +#: judge/forms.py:148 msgid "Problem with code already exists." msgstr "" -#: judge/forms.py:158 judge/models/contest.py:61 +#: judge/forms.py:153 judge/models/contest.py:52 msgid "Contest id must be ^[a-z0-9]+$" msgstr "Yarışma ID'si ^[a-z0-9]+$ olmalıdır" -#: judge/forms.py:163 +#: judge/forms.py:158 msgid "Contest with key already exists." msgstr "" -#: judge/jinja2/datetime.py:26 templates/blog/blog.html:26 +#: judge/jinja2/datetime.py:26 templates/blog/content.html:27 #: templates/blog/dashboard.html:21 msgid "N j, Y, g:i a" msgstr "j M Y, H:i" -#: judge/jinja2/datetime.py:26 templates/chat/message.html:13 +#: judge/jinja2/datetime.py:26 #, python-brace-format msgid "{time}" msgstr "" @@ -581,174 +561,122 @@ msgstr "MathJax, fallback olarak SVG/PNG" msgid "Detect best quality" msgstr "En iyi kaliteyi tespit et" -#: judge/models/comment.py:26 +#: judge/models/comment.py:25 msgid "Page code must be ^[pcs]:[a-z0-9]+$|^b:\\d+$" msgstr "" -#: judge/models/comment.py:42 +#: judge/models/comment.py:41 msgid "commenter" msgstr "yorum yazan" -#: judge/models/comment.py:44 judge/models/comment.py:177 +#: judge/models/comment.py:43 judge/models/comment.py:176 msgid "associated page" msgstr "" -#: judge/models/comment.py:46 +#: judge/models/comment.py:45 msgid "votes" msgstr "oy" -#: judge/models/comment.py:48 +#: judge/models/comment.py:47 msgid "hide the comment" msgstr "yorumu gizle" -#: judge/models/comment.py:49 +#: judge/models/comment.py:48 msgid "parent" msgstr "üst yorum" -#: judge/models/comment.py:54 judge/models/comment.py:192 +#: judge/models/comment.py:53 msgid "comment" msgstr "yorum" -#: judge/models/comment.py:55 +#: judge/models/comment.py:54 msgid "comments" msgstr "yorumlar" -#: judge/models/comment.py:137 judge/models/problem.py:443 +#: judge/models/comment.py:136 judge/models/problem.py:406 #, python-format msgid "Editorial for %s" msgstr "%s problemi için editorial" -#: judge/models/comment.py:172 +#: judge/models/comment.py:171 msgid "comment vote" msgstr "yorum oyu" -#: judge/models/comment.py:173 +#: judge/models/comment.py:172 msgid "comment votes" msgstr "yorum oyları" -#: judge/models/comment.py:182 +#: judge/models/comment.py:181 msgid "Override comment lock" msgstr "" -#: judge/models/comment.py:190 -msgid "owner" -msgstr "" - -#: judge/models/comment.py:193 judge/models/message.py:16 -msgid "read" -msgstr "okundu" - -#: judge/models/comment.py:194 -#, fuzzy -#| msgid "Category" -msgid "category" -msgstr "Kategori" - -#: judge/models/comment.py:195 -msgid "html link to comments, used for non-comments" -msgstr "" - -#: judge/models/comment.py:196 -msgid "who trigger, used for non-comment" -msgstr "" - -#: judge/models/contest.py:23 +#: judge/models/contest.py:22 msgid "Invalid colour." msgstr "Geçersiz renk." -#: judge/models/contest.py:25 +#: judge/models/contest.py:24 msgid "tag name" msgstr "etiket adı" -#: judge/models/contest.py:26 +#: judge/models/contest.py:25 msgid "Lowercase letters and hyphens only." msgstr "Yalnızca küçük harfler ve tire kullanılabilir." -#: judge/models/contest.py:27 +#: judge/models/contest.py:26 msgid "tag colour" msgstr "etiket rengi" -#: judge/models/contest.py:28 +#: judge/models/contest.py:27 msgid "tag description" msgstr "etiket tanımı" -#: judge/models/contest.py:47 +#: judge/models/contest.py:46 msgid "contest tag" msgstr "yarışma etiketi" -#: judge/models/contest.py:48 judge/models/contest.py:118 +#: judge/models/contest.py:47 judge/models/contest.py:101 msgid "contest tags" msgstr "yarışma etiketleri" -#: judge/models/contest.py:56 -msgid "Visible" -msgstr "" - -#: judge/models/contest.py:57 -msgid "Hidden for duration of contest" -msgstr "" - -#: judge/models/contest.py:58 -#, fuzzy -#| msgid "View user participation" -msgid "Hidden for duration of participation" -msgstr "Kullanıcı katılımını göster" - -#: judge/models/contest.py:60 +#: judge/models/contest.py:51 msgid "contest id" msgstr "yarışma ID'si" -#: judge/models/contest.py:62 +#: judge/models/contest.py:53 msgid "contest name" msgstr "yarışma adı" -#: judge/models/contest.py:63 -#, fuzzy -#| msgid "These people will be able to edit the contest." -msgid "These users will be able to edit the contest." +#: judge/models/contest.py:54 +msgid "These people will be able to edit the contest." msgstr "Bu kişiler yarışmayı düzenleyebilecekler." -#: judge/models/contest.py:65 -#, fuzzy -#| msgid "These people will be able to edit the contest." -msgid "" -"These users will be able to edit the contest, but will not be listed as " -"authors." -msgstr "Bu kişiler yarışmayı düzenleyebilecekler." - -#: judge/models/contest.py:68 -#, fuzzy -#| msgid "These people will be able to edit the contest." -msgid "These users will be able to view the contest, but not edit it." -msgstr "Bu kişiler yarışmayı düzenleyebilecekler." - -#: judge/models/contest.py:71 judge/models/runtime.py:136 +#: judge/models/contest.py:56 judge/models/runtime.py:133 msgid "description" msgstr "Tanım" -#: judge/models/contest.py:72 judge/models/problem.py:390 -#: judge/models/runtime.py:138 +#: judge/models/contest.py:57 judge/models/problem.py:353 +#: judge/models/runtime.py:135 msgid "problems" msgstr "problemler" -#: judge/models/contest.py:73 judge/models/contest.py:404 +#: judge/models/contest.py:58 judge/models/contest.py:258 msgid "start time" msgstr "başlangıç" -#: judge/models/contest.py:74 +#: judge/models/contest.py:59 msgid "end time" msgstr "bitiş" -#: judge/models/contest.py:75 judge/models/problem.py:118 -#: judge/models/problem.py:414 +#: judge/models/contest.py:60 judge/models/problem.py:118 +#: judge/models/problem.py:377 msgid "time limit" msgstr "zaman sınırı" -#: judge/models/contest.py:76 judge/models/problem.py:136 +#: judge/models/contest.py:61 judge/models/problem.py:136 msgid "publicly visible" msgstr "herkese açık" -#: judge/models/contest.py:77 +#: judge/models/contest.py:62 msgid "" "Should be set even for organization-private contests, where it determines " "whether the contest is visible to members of the specified organizations." @@ -757,93 +685,76 @@ msgstr "" "organizasyona özel ise bu seçenek yarışmanın üyelere açılıp açılmayacağını " "belirler." -#: judge/models/contest.py:80 +#: judge/models/contest.py:65 msgid "contest rated" msgstr "dereceli yarışma" -#: judge/models/contest.py:80 +#: judge/models/contest.py:65 msgid "Whether this contest can be rated." msgstr "Bu yarışma derecelendirilebilir mi?" -#: judge/models/contest.py:82 -#, fuzzy -#| msgid "public visibility" -msgid "scoreboard visibility" -msgstr "halka açık mı?" - -#: judge/models/contest.py:83 -#, fuzzy -#| msgid "" -#| "Whether the scoreboard should remain hidden for the duration of the " -#| "contest." -msgid "Scoreboard visibility through the duration of the contest" -msgstr "Puan tablosu yarışma boyunca gizli kalmalı mı?" - -#: judge/models/contest.py:85 -#, fuzzy -#| msgid "hide scoreboard" -msgid "view contest scoreboard" +#: judge/models/contest.py:67 +msgid "hide scoreboard" msgstr "puan tablosunu gizle" -#: judge/models/contest.py:87 -#, fuzzy -#| msgid "These people will be able to edit the contest." -msgid "These users will be able to view the scoreboard." -msgstr "Bu kişiler yarışmayı düzenleyebilecekler." +#: judge/models/contest.py:68 +msgid "" +"Whether the scoreboard should remain hidden for the duration of the contest." +msgstr "Puan tablosu yarışma boyunca gizli kalmalı mı?" -#: judge/models/contest.py:88 +#: judge/models/contest.py:71 msgid "no comments" msgstr "yorum yok" -#: judge/models/contest.py:89 +#: judge/models/contest.py:72 msgid "Use clarification system instead of comments." msgstr "Yorumlar yerine açıklama sistemini kullanın." -#: judge/models/contest.py:91 +#: judge/models/contest.py:74 msgid "Rating floor for contest" msgstr "" -#: judge/models/contest.py:93 +#: judge/models/contest.py:76 msgid "Rating ceiling for contest" msgstr "" -#: judge/models/contest.py:95 +#: judge/models/contest.py:78 msgid "rate all" msgstr "herkesi derecelendir" -#: judge/models/contest.py:95 +#: judge/models/contest.py:78 msgid "Rate all users who joined." msgstr "Katılan tüm kullanıcıları derecelendir" -#: judge/models/contest.py:96 +#: judge/models/contest.py:79 msgid "exclude from ratings" msgstr "derecelendirme dışı kullanıcılar" -#: judge/models/contest.py:98 +#: judge/models/contest.py:81 msgid "private to specific users" msgstr "" -#: judge/models/contest.py:99 +#: judge/models/contest.py:82 msgid "private contestants" msgstr "" -#: judge/models/contest.py:100 +#: judge/models/contest.py:83 msgid "If private, only these users may see the contest" msgstr "" -#: judge/models/contest.py:102 +#: judge/models/contest.py:85 msgid "hide problem tags" msgstr "problem etiketlerini gizle" -#: judge/models/contest.py:103 +#: judge/models/contest.py:86 msgid "Whether problem tags should be hidden by default." msgstr "Problem etiketleri varsayılan olarak gizli olmalı mı?" -#: judge/models/contest.py:105 +#: judge/models/contest.py:88 msgid "run pretests only" msgstr "yalnızca ön testleri çalıştır" -#: judge/models/contest.py:106 +#: judge/models/contest.py:89 msgid "" "Whether judges should grade pretests only, versus all testcases. Commonly " "set during a contest, then unset prior to rejudging user submissions when " @@ -853,51 +764,50 @@ msgstr "" "yarışma sırasında açılır, yarışma bittiğinde kapatılır ve çözümler yeniden " "puanlanır." -#: judge/models/contest.py:110 judge/models/interface.py:77 -#: judge/models/problem.py:157 +#: judge/models/contest.py:93 judge/models/problem.py:157 msgid "private to organizations" msgstr "organizasyonlara özel" -#: judge/models/contest.py:111 judge/models/interface.py:75 -#: judge/models/problem.py:155 judge/models/profile.py:77 +#: judge/models/contest.py:94 judge/models/problem.py:155 +#: judge/models/profile.py:77 msgid "organizations" msgstr "organizasyonlar" -#: judge/models/contest.py:112 +#: judge/models/contest.py:95 msgid "If private, only these organizations may see the contest" msgstr "Özel ise, sadece bu organizasyonlar yarışmayı görebilirler" -#: judge/models/contest.py:113 judge/models/problem.py:145 +#: judge/models/contest.py:96 judge/models/problem.py:145 msgid "OpenGraph image" msgstr "OpenGraph resmi" -#: judge/models/contest.py:114 judge/models/profile.py:48 +#: judge/models/contest.py:97 judge/models/profile.py:48 msgid "Logo override image" msgstr "" -#: judge/models/contest.py:116 +#: judge/models/contest.py:99 msgid "" "This image will replace the default site logo for users inside the contest." msgstr "" -#: judge/models/contest.py:119 +#: judge/models/contest.py:102 msgid "the amount of live participants" msgstr "anlık katılımcı sayısı" -#: judge/models/contest.py:120 +#: judge/models/contest.py:103 msgid "contest summary" msgstr "yarışma özeti" -#: judge/models/contest.py:121 judge/models/problem.py:147 +#: judge/models/contest.py:104 judge/models/problem.py:147 msgid "Plain-text, shown in meta description tag, e.g. for social media." msgstr "" "Düz yazı, sosyal medya vb. için \"meta description\" tag'inde görünecektir." -#: judge/models/contest.py:122 judge/models/profile.py:47 +#: judge/models/contest.py:105 judge/models/profile.py:47 msgid "access code" msgstr "erişim kodu" -#: judge/models/contest.py:123 +#: judge/models/contest.py:106 msgid "" "An optional code to prompt contestants before they are allowed to join the " "contest. Leave it blank to disable." @@ -905,255 +815,231 @@ msgstr "" "Yarışmaya katılabilmek için girilmesi gereken, isteğe bağlı bir kod. Boş " "bırakılırsa devre dışı kalır." -#: judge/models/contest.py:125 judge/models/problem.py:141 +#: judge/models/contest.py:108 judge/models/problem.py:141 msgid "personae non gratae" msgstr "istenmeyen kişiler" -#: judge/models/contest.py:126 +#: judge/models/contest.py:109 msgid "Bans the selected users from joining this contest." msgstr "" -#: judge/models/contest.py:127 +#: judge/models/contest.py:110 msgid "contest format" msgstr "" -#: judge/models/contest.py:128 +#: judge/models/contest.py:111 msgid "The contest format module to use." msgstr "" -#: judge/models/contest.py:129 +#: judge/models/contest.py:112 msgid "contest format configuration" msgstr "" -#: judge/models/contest.py:130 +#: judge/models/contest.py:113 msgid "" "A JSON object to serve as the configuration for the chosen contest format " "module. Leave empty to use None. Exact format depends on the contest format " "selected." msgstr "" -#: judge/models/contest.py:137 -#, fuzzy -#| msgid "test case points" -msgid "precision points" -msgstr "test puanı" - -#: judge/models/contest.py:139 -msgid "Number of digits to round points to." -msgstr "" - -#: judge/models/contest.py:383 +#: judge/models/contest.py:239 msgid "See private contests" msgstr "Özel yarışmaları gör" -#: judge/models/contest.py:384 +#: judge/models/contest.py:240 msgid "Edit own contests" msgstr "Kendi yarışmalarını düzenle" -#: judge/models/contest.py:385 +#: judge/models/contest.py:241 msgid "Edit all contests" msgstr "Tüm yarışmaları düzenle" -#: judge/models/contest.py:386 +#: judge/models/contest.py:242 msgid "Clone contest" msgstr "" -#: judge/models/contest.py:387 templates/contest/moss.html:74 +#: judge/models/contest.py:243 templates/contest/moss.html:74 msgid "MOSS contest" msgstr "" -#: judge/models/contest.py:388 +#: judge/models/contest.py:244 msgid "Rate contests" msgstr "Yarışmaları derecelendir" -#: judge/models/contest.py:389 +#: judge/models/contest.py:245 msgid "Contest access codes" msgstr "Yarışma erişim kodları" -#: judge/models/contest.py:390 +#: judge/models/contest.py:246 msgid "Create private contests" msgstr "" -#: judge/models/contest.py:391 -msgid "Change contest visibility" -msgstr "" - -#: judge/models/contest.py:392 -#, fuzzy -#| msgid "contest problems" -msgid "Edit contest problem label script" -msgstr "yarışma problemleri" - -#: judge/models/contest.py:394 judge/models/contest.py:492 -#: judge/models/contest.py:529 judge/models/contest.py:552 -#: judge/models/submission.py:84 +#: judge/models/contest.py:248 judge/models/contest.py:345 +#: judge/models/contest.py:382 judge/models/contest.py:404 +#: judge/models/submission.py:83 msgid "contest" msgstr "yarışma" -#: judge/models/contest.py:395 +#: judge/models/contest.py:249 msgid "contests" msgstr "yarışmalar" -#: judge/models/contest.py:402 +#: judge/models/contest.py:256 msgid "associated contest" msgstr "ilişkili yarışma" -#: judge/models/contest.py:405 +#: judge/models/contest.py:259 msgid "score" msgstr "puan" -#: judge/models/contest.py:406 +#: judge/models/contest.py:260 msgid "cumulative time" msgstr "kümülatif süre" -#: judge/models/contest.py:407 +#: judge/models/contest.py:261 msgid "is disqualified" msgstr "" -#: judge/models/contest.py:408 +#: judge/models/contest.py:262 msgid "Whether this participation is disqualified." msgstr "" -#: judge/models/contest.py:409 -msgid "tie-breaking field" -msgstr "" - -#: judge/models/contest.py:410 +#: judge/models/contest.py:263 msgid "virtual participation id" msgstr "sanal katılım ID'si" -#: judge/models/contest.py:411 +#: judge/models/contest.py:264 #, fuzzy #| msgid "0 means non-virtual, otherwise the n-th virtual participation" msgid "0 means non-virtual, otherwise the n-th virtual participation." msgstr "0 sanal olmayan katılım, diğer sayılar n'inci sanal katılım" -#: judge/models/contest.py:412 +#: judge/models/contest.py:265 msgid "contest format specific data" msgstr "" -#: judge/models/contest.py:478 +#: judge/models/contest.py:331 #, python-format msgid "%s spectating in %s" msgstr "%s, \"%s\" yarışmasında gözlemci" -#: judge/models/contest.py:480 +#: judge/models/contest.py:333 #, python-format msgid "%s in %s, v%d" msgstr "%s, \"%s\" yarışmasında, sanal: %d" -#: judge/models/contest.py:481 +#: judge/models/contest.py:334 #, python-format msgid "%s in %s" msgstr "%s, \"%s\" yarışmasında" -#: judge/models/contest.py:484 +#: judge/models/contest.py:337 msgid "contest participation" msgstr "yarışma katılımı" -#: judge/models/contest.py:485 +#: judge/models/contest.py:338 msgid "contest participations" msgstr "yarışma katılımı" -#: judge/models/contest.py:491 judge/models/contest.py:513 -#: judge/models/contest.py:553 judge/models/problem.py:389 -#: judge/models/problem.py:394 judge/models/problem.py:412 -#: judge/models/problem_data.py:40 +#: judge/models/contest.py:344 judge/models/contest.py:366 +#: judge/models/contest.py:405 judge/models/problem.py:352 +#: judge/models/problem.py:357 judge/models/problem.py:375 +#: judge/models/problem_data.py:38 msgid "problem" msgstr "" -#: judge/models/contest.py:493 judge/models/contest.py:517 +#: judge/models/contest.py:346 judge/models/contest.py:370 #: judge/models/problem.py:129 msgid "points" msgstr "puan" -#: judge/models/contest.py:494 +#: judge/models/contest.py:347 msgid "partial" msgstr "kısmi" -#: judge/models/contest.py:495 judge/models/contest.py:518 +#: judge/models/contest.py:348 judge/models/contest.py:371 msgid "is pretested" msgstr "ön testli" -#: judge/models/contest.py:496 judge/models/interface.py:43 +#: judge/models/contest.py:349 judge/models/interface.py:43 msgid "order" msgstr "sıra" -#: judge/models/contest.py:497 +#: judge/models/contest.py:350 msgid "0 to not show testcases, 1 to show" msgstr "" -#: judge/models/contest.py:498 +#: judge/models/contest.py:351 #, fuzzy #| msgid "submission test cases" msgid "visible testcases" msgstr "çözüm testleri" -#: judge/models/contest.py:499 +#: judge/models/contest.py:352 msgid "Maximum number of submissions for this problem, or 0 for no limit." msgstr "Bu probleme gönderilebilen maksimum çözüm sayısı. 0 sınırsız demektir." -#: judge/models/contest.py:501 +#: judge/models/contest.py:354 msgid "Why include a problem you can't submit to?" msgstr "Neden çözüm gönderemediğin bir problemi ekleyesin ki?" -#: judge/models/contest.py:506 +#: judge/models/contest.py:359 msgid "contest problem" msgstr "yarışma problemi" -#: judge/models/contest.py:507 +#: judge/models/contest.py:360 msgid "contest problems" msgstr "yarışma problemleri" -#: judge/models/contest.py:511 judge/models/submission.py:183 +#: judge/models/contest.py:364 judge/models/submission.py:181 msgid "submission" msgstr "çözüm" -#: judge/models/contest.py:515 judge/models/contest.py:530 +#: judge/models/contest.py:368 judge/models/contest.py:383 msgid "participation" msgstr "katılım" -#: judge/models/contest.py:519 +#: judge/models/contest.py:372 msgid "Whether this submission was ran only on pretests." msgstr "Bu çözüm yalnızca pretest'lerde mi çalıştı?" -#: judge/models/contest.py:523 +#: judge/models/contest.py:376 msgid "contest submission" msgstr "yarışma çözümü" -#: judge/models/contest.py:524 +#: judge/models/contest.py:377 msgid "contest submissions" msgstr "yarışma çözümleri" -#: judge/models/contest.py:532 +#: judge/models/contest.py:385 msgid "rank" msgstr "sıralama" -#: judge/models/contest.py:533 +#: judge/models/contest.py:386 msgid "rating" msgstr "derece" -#: judge/models/contest.py:534 +#: judge/models/contest.py:387 msgid "volatility" msgstr "değişkenlik" -#: judge/models/contest.py:535 +#: judge/models/contest.py:388 msgid "last rated" msgstr "son derecelendirme" -#: judge/models/contest.py:539 +#: judge/models/contest.py:392 msgid "contest rating" msgstr "yarışma derecesi" -#: judge/models/contest.py:540 +#: judge/models/contest.py:393 msgid "contest ratings" msgstr "yarışma derecesi" -#: judge/models/contest.py:560 +#: judge/models/contest.py:412 msgid "contest moss result" msgstr "" -#: judge/models/contest.py:561 +#: judge/models/contest.py:413 msgid "contest moss results" msgstr "" @@ -1193,7 +1079,7 @@ msgstr "üst nesne" msgid "post title" msgstr "gönderi başlığı" -#: judge/models/interface.py:67 judge/models/problem.py:432 +#: judge/models/interface.py:67 judge/models/problem.py:395 msgid "authors" msgstr "yazarlar" @@ -1201,7 +1087,7 @@ msgstr "yazarlar" msgid "slug" msgstr "" -#: judge/models/interface.py:69 judge/models/problem.py:430 +#: judge/models/interface.py:69 judge/models/problem.py:393 msgid "public visibility" msgstr "halka açık mı?" @@ -1225,21 +1111,15 @@ msgstr "gönderi özeti" msgid "openGraph image" msgstr "openGraph resmi" -#: judge/models/interface.py:76 -#, fuzzy -#| msgid "If private, only these organizations may see the contest" -msgid "If private, only these organizations may see the blog post." -msgstr "Özel ise, sadece bu organizasyonlar yarışmayı görebilirler" - -#: judge/models/interface.py:105 +#: judge/models/interface.py:91 msgid "Edit all posts" msgstr "Tüm gönderileri düzenle" -#: judge/models/interface.py:107 +#: judge/models/interface.py:93 msgid "blog post" msgstr "blog gönderisi" -#: judge/models/interface.py:108 +#: judge/models/interface.py:94 msgid "blog posts" msgstr "blog gönderisi" @@ -1263,6 +1143,10 @@ msgstr "alıcı" msgid "message timestamp" msgstr "mesaj zaman damgası(timestamp)" +#: judge/models/message.py:16 +msgid "read" +msgstr "okundu" + #: judge/models/message.py:20 msgid "messages in the thread" msgstr "konudaki mesajlar" @@ -1401,7 +1285,7 @@ msgstr "" "Bu problem için saniye cinsinden zaman sınırı. Küsuratlı saniyeler(örn. 1.5) " "desteklenmektedir." -#: judge/models/problem.py:123 judge/models/problem.py:417 +#: judge/models/problem.py:123 judge/models/problem.py:380 msgid "memory limit" msgstr "bellek sınırı" @@ -1475,188 +1359,188 @@ msgstr "" msgid "If private, only these organizations may see the problem." msgstr "" -#: judge/models/problem.py:395 judge/models/problem.py:413 -#: judge/models/runtime.py:111 +#: judge/models/problem.py:358 judge/models/problem.py:376 +#: judge/models/runtime.py:108 msgid "language" msgstr "dil" -#: judge/models/problem.py:396 +#: judge/models/problem.py:359 msgid "translated name" msgstr "çevrilmiş ad" -#: judge/models/problem.py:397 +#: judge/models/problem.py:360 msgid "translated description" msgstr "çevrilmiş tanım" -#: judge/models/problem.py:401 +#: judge/models/problem.py:364 msgid "problem translation" msgstr "problem çevirisi" -#: judge/models/problem.py:402 +#: judge/models/problem.py:365 msgid "problem translations" msgstr "problem çevirisi" -#: judge/models/problem.py:406 +#: judge/models/problem.py:369 msgid "clarified problem" msgstr "açıklık getirilmiş problem" -#: judge/models/problem.py:407 +#: judge/models/problem.py:370 msgid "clarification body" msgstr "açıklama içeriği" -#: judge/models/problem.py:408 +#: judge/models/problem.py:371 msgid "clarification timestamp" msgstr "açıklama zaman damgası(timestamp)" -#: judge/models/problem.py:423 +#: judge/models/problem.py:386 msgid "language-specific resource limit" msgstr "Dile özel kaynak sınırı" -#: judge/models/problem.py:424 +#: judge/models/problem.py:387 msgid "language-specific resource limits" msgstr "Dile özel kaynak sınırları" -#: judge/models/problem.py:428 +#: judge/models/problem.py:391 msgid "associated problem" msgstr "ilgili problem" -#: judge/models/problem.py:431 +#: judge/models/problem.py:394 msgid "publish date" msgstr "yayın tarihi" -#: judge/models/problem.py:433 +#: judge/models/problem.py:396 msgid "editorial content" msgstr "problem analizi içeriği" -#: judge/models/problem.py:449 +#: judge/models/problem.py:412 msgid "solution" msgstr "çözüm" -#: judge/models/problem.py:450 +#: judge/models/problem.py:413 msgid "solutions" msgstr "çözümler" -#: judge/models/problem_data.py:26 +#: judge/models/problem_data.py:24 msgid "Standard" msgstr "Standart" -#: judge/models/problem_data.py:27 +#: judge/models/problem_data.py:25 msgid "Floats" msgstr "" -#: judge/models/problem_data.py:28 +#: judge/models/problem_data.py:26 msgid "Floats (absolute)" msgstr "" -#: judge/models/problem_data.py:29 +#: judge/models/problem_data.py:27 msgid "Floats (relative)" msgstr "" -#: judge/models/problem_data.py:30 +#: judge/models/problem_data.py:28 msgid "Non-trailing spaces" msgstr "" -#: judge/models/problem_data.py:31 +#: judge/models/problem_data.py:29 msgid "Unordered" msgstr "" -#: judge/models/problem_data.py:32 +#: judge/models/problem_data.py:30 msgid "Byte identical" msgstr "" -#: judge/models/problem_data.py:33 +#: judge/models/problem_data.py:31 msgid "Line-by-line" msgstr "" -#: judge/models/problem_data.py:34 +#: judge/models/problem_data.py:32 msgid "Custom checker (PY)" msgstr "" -#: judge/models/problem_data.py:35 +#: judge/models/problem_data.py:33 msgid "Custom validator (CPP)" msgstr "" -#: judge/models/problem_data.py:42 +#: judge/models/problem_data.py:40 msgid "data zip file" msgstr "data zip dosyası" -#: judge/models/problem_data.py:44 +#: judge/models/problem_data.py:42 msgid "generator file" msgstr "generator dosyası" -#: judge/models/problem_data.py:46 judge/models/problem_data.py:121 +#: judge/models/problem_data.py:44 judge/models/problem_data.py:110 msgid "output prefix length" msgstr "çıktı öneki uzunluğu" -#: judge/models/problem_data.py:47 judge/models/problem_data.py:122 +#: judge/models/problem_data.py:45 judge/models/problem_data.py:111 msgid "output limit length" msgstr "çıktı sınır uzunluğu" -#: judge/models/problem_data.py:48 +#: judge/models/problem_data.py:46 msgid "init.yml generation feedback" msgstr "init.yml oluşturma mesajı" -#: judge/models/problem_data.py:49 judge/models/problem_data.py:123 +#: judge/models/problem_data.py:47 judge/models/problem_data.py:112 msgid "checker" msgstr "" -#: judge/models/problem_data.py:50 judge/models/problem_data.py:124 +#: judge/models/problem_data.py:48 judge/models/problem_data.py:113 msgid "checker arguments" msgstr "checker değişkenleri" -#: judge/models/problem_data.py:51 judge/models/problem_data.py:125 +#: judge/models/problem_data.py:49 judge/models/problem_data.py:114 msgid "checker arguments as a JSON object" msgstr "checker değişkenleri, JSON nesnesi olarak" -#: judge/models/problem_data.py:52 +#: judge/models/problem_data.py:50 msgid "custom checker file" msgstr "" -#: judge/models/problem_data.py:58 +#: judge/models/problem_data.py:56 msgid "custom validator file" msgstr "" -#: judge/models/problem_data.py:108 +#: judge/models/problem_data.py:97 msgid "problem data set" msgstr "" -#: judge/models/problem_data.py:110 +#: judge/models/problem_data.py:99 msgid "case position" msgstr "test konumu" -#: judge/models/problem_data.py:111 +#: judge/models/problem_data.py:100 msgid "case type" msgstr "test tipi" -#: judge/models/problem_data.py:112 +#: judge/models/problem_data.py:101 msgid "Normal case" msgstr "Normal test" -#: judge/models/problem_data.py:113 +#: judge/models/problem_data.py:102 msgid "Batch start" msgstr "Küme başlangıcı" -#: judge/models/problem_data.py:114 +#: judge/models/problem_data.py:103 msgid "Batch end" msgstr "küme sonu" -#: judge/models/problem_data.py:116 +#: judge/models/problem_data.py:105 msgid "input file name" msgstr "girdi dosya adı" -#: judge/models/problem_data.py:117 +#: judge/models/problem_data.py:106 msgid "output file name" msgstr "çıktı dosya adı" -#: judge/models/problem_data.py:118 +#: judge/models/problem_data.py:107 msgid "generator arguments" msgstr "generator değişkenleri" -#: judge/models/problem_data.py:119 +#: judge/models/problem_data.py:108 msgid "point value" msgstr "puan değeri" -#: judge/models/problem_data.py:120 +#: judge/models/problem_data.py:109 msgid "case is pretest?" msgstr "ön test mi?" @@ -1731,7 +1615,7 @@ msgid "" msgstr "" #: judge/models/profile.py:76 judge/models/profile.py:93 -#: judge/models/profile.py:212 +#: judge/models/profile.py:192 msgid "organization" msgstr "Organizasyon" @@ -1827,31 +1711,31 @@ msgstr "" msgid "Notes for administrators regarding this user." msgstr "" -#: judge/models/profile.py:206 +#: judge/models/profile.py:186 msgid "user profile" msgstr "Kullanıcı Profili" -#: judge/models/profile.py:207 +#: judge/models/profile.py:187 msgid "user profiles" msgstr "Kullanıcı Profilleri" -#: judge/models/profile.py:214 +#: judge/models/profile.py:194 msgid "request time" msgstr "istek zamanı" -#: judge/models/profile.py:215 +#: judge/models/profile.py:195 msgid "state" msgstr "durum" -#: judge/models/profile.py:220 +#: judge/models/profile.py:200 msgid "reason" msgstr "sebep" -#: judge/models/profile.py:223 +#: judge/models/profile.py:203 msgid "organization join request" msgstr "organizasyona katılma isteği" -#: judge/models/profile.py:224 +#: judge/models/profile.py:204 msgid "organization join requests" msgstr "organizasyona katılma istekleri" @@ -1954,89 +1838,89 @@ msgstr "uzantı" msgid "The extension of source files, e.g., \"py\" or \"cpp\"." msgstr "Kaynak kodlarının uzantıları, \"py\", \"cpp\" vb." -#: judge/models/runtime.py:112 +#: judge/models/runtime.py:109 msgid "languages" msgstr "diller" -#: judge/models/runtime.py:116 +#: judge/models/runtime.py:113 msgid "language to which this runtime belongs" msgstr "bu dil sürümünün ait olduğu dil" -#: judge/models/runtime.py:117 +#: judge/models/runtime.py:114 msgid "judge on which this runtime exists" msgstr "bu dil sürümünün bulunduğu judge" -#: judge/models/runtime.py:118 +#: judge/models/runtime.py:115 msgid "runtime name" msgstr "dil sürümü" -#: judge/models/runtime.py:119 +#: judge/models/runtime.py:116 msgid "runtime version" msgstr "dil sürümü versiyonu" -#: judge/models/runtime.py:120 +#: judge/models/runtime.py:117 msgid "order in which to display this runtime" msgstr "dil sürümünün gösterim sırası" -#: judge/models/runtime.py:124 +#: judge/models/runtime.py:121 msgid "Server name, hostname-style" msgstr "Server adı, hostname şeklinde" -#: judge/models/runtime.py:125 +#: judge/models/runtime.py:122 msgid "time of creation" msgstr "oluşturulma zamanı" -#: judge/models/runtime.py:126 +#: judge/models/runtime.py:123 #, fuzzy #| msgid "A key to authenticated this judge" msgid "A key to authenticate this judge" msgstr "Bu judge'ın kimliğini doğrulamak için bir anahtar" -#: judge/models/runtime.py:127 +#: judge/models/runtime.py:124 msgid "authentication key" msgstr "kimlik doğrulama anahtarı" -#: judge/models/runtime.py:128 +#: judge/models/runtime.py:125 msgid "block judge" msgstr "" -#: judge/models/runtime.py:129 +#: judge/models/runtime.py:126 msgid "" "Whether this judge should be blocked from connecting, even if its key is " "correct." msgstr "" -#: judge/models/runtime.py:131 +#: judge/models/runtime.py:128 msgid "judge online status" msgstr "judge'ın çevrimiçi durumu" -#: judge/models/runtime.py:132 +#: judge/models/runtime.py:129 msgid "judge start time" msgstr "başlangıç" -#: judge/models/runtime.py:133 +#: judge/models/runtime.py:130 msgid "response time" msgstr "yanıt süresi" -#: judge/models/runtime.py:134 +#: judge/models/runtime.py:131 msgid "system load" msgstr "sistem yükü" -#: judge/models/runtime.py:135 +#: judge/models/runtime.py:132 msgid "Load for the last minute, divided by processors to be fair." msgstr "" "Son bir dakikadaki sistem yükü. Adil olması için işlemci sayısına bölünür." -#: judge/models/runtime.py:139 judge/models/runtime.py:179 +#: judge/models/runtime.py:136 judge/models/runtime.py:176 msgid "judges" msgstr "judge'lar" -#: judge/models/runtime.py:178 +#: judge/models/runtime.py:175 msgid "judge" msgstr "" #: judge/models/submission.py:20 judge/models/submission.py:47 -#: judge/utils/problems.py:79 +#: judge/utils/problems.py:77 msgid "Accepted" msgstr "Kabul edildi" @@ -2065,7 +1949,7 @@ msgid "Runtime Error" msgstr "Çalışma Hatası" #: judge/models/submission.py:27 judge/models/submission.py:41 -#: judge/models/submission.py:55 judge/utils/problems.py:81 +#: judge/models/submission.py:55 judge/utils/problems.py:79 msgid "Compile Error" msgstr "Derleme Hatası" @@ -2106,15 +1990,15 @@ msgstr "İç Hata (judge sunucusu hatası)" msgid "submission time" msgstr "çözüm süresi" -#: judge/models/submission.py:67 judge/models/submission.py:203 +#: judge/models/submission.py:67 judge/models/submission.py:201 msgid "execution time" msgstr "çalışma süresi" -#: judge/models/submission.py:68 judge/models/submission.py:204 +#: judge/models/submission.py:68 judge/models/submission.py:202 msgid "memory usage" msgstr "bellek kullanımı" -#: judge/models/submission.py:69 judge/models/submission.py:205 +#: judge/models/submission.py:69 judge/models/submission.py:203 msgid "points granted" msgstr "verilen puan" @@ -2151,64 +2035,58 @@ msgid "judged on" msgstr "değerlendirildiği sunucu" #: judge/models/submission.py:81 -#, fuzzy -#| msgid "submission time" -msgid "submission judge time" -msgstr "çözüm süresi" - -#: judge/models/submission.py:82 msgid "was rejudged by admin" msgstr "admin tarafından yeniden değerlendirildi" -#: judge/models/submission.py:83 +#: judge/models/submission.py:82 msgid "was ran on pretests only" msgstr "sadece ön testlerde çalıştı" -#: judge/models/submission.py:184 templates/contest/moss.html:58 +#: judge/models/submission.py:182 templates/contest/moss.html:58 msgid "submissions" msgstr "çözümler" -#: judge/models/submission.py:188 judge/models/submission.py:199 +#: judge/models/submission.py:186 judge/models/submission.py:197 msgid "associated submission" msgstr "ilişkili çözüm gönderisi" -#: judge/models/submission.py:190 +#: judge/models/submission.py:188 msgid "source code" msgstr "kaynak kodu" -#: judge/models/submission.py:201 +#: judge/models/submission.py:199 msgid "test case ID" msgstr "test ID" -#: judge/models/submission.py:202 +#: judge/models/submission.py:200 msgid "status flag" msgstr "durum kodu" -#: judge/models/submission.py:206 +#: judge/models/submission.py:204 msgid "points possible" msgstr "alınabilecek puan" -#: judge/models/submission.py:207 +#: judge/models/submission.py:205 msgid "batch number" msgstr "küme #" -#: judge/models/submission.py:208 +#: judge/models/submission.py:206 msgid "judging feedback" msgstr "" -#: judge/models/submission.py:209 +#: judge/models/submission.py:207 msgid "extended judging feedback" msgstr "" -#: judge/models/submission.py:210 +#: judge/models/submission.py:208 msgid "program output" msgstr "program çıktısı" -#: judge/models/submission.py:218 +#: judge/models/submission.py:216 msgid "submission test case" msgstr "çözüm testi" -#: judge/models/submission.py:219 +#: judge/models/submission.py:217 msgid "submission test cases" msgstr "çözüm testleri" @@ -2260,24 +2138,12 @@ msgstr "gönderen" msgid "message time" msgstr "mesaj zamanı" -#: judge/pdf_problems.py:147 judge/pdf_problems.py:199 -#: judge/pdf_problems.py:259 +#: judge/pdf_problems.py:134 judge/pdf_problems.py:186 +#: judge/pdf_problems.py:246 msgid "Page [page] of [topage]" msgstr "[page]/[topage]" -#: judge/pdf_problems.py:280 -#, fuzzy, python-format -#| msgid "Page %d of Posts" -msgid "Page %s of %s" -msgstr "Sayfa %d" - -#: judge/tasks/contest.py:19 -#, fuzzy -#| msgid "Recalculate scores" -msgid "Recalculating contest scores" -msgstr "Puanları yeniden hesapla" - -#: judge/tasks/contest.py:40 +#: judge/tasks/moss.py:25 msgid "Running MOSS" msgstr "" @@ -2289,62 +2155,62 @@ msgstr "" msgid "Recalculating user points" msgstr "" -#: judge/utils/problem_data.py:70 +#: judge/utils/problem_data.py:68 msgid "Empty batches not allowed." msgstr "Kümeler boş olamaz." -#: judge/utils/problem_data.py:78 judge/utils/problem_data.py:99 +#: judge/utils/problem_data.py:76 judge/utils/problem_data.py:97 #, fuzzy #| msgid "How did you corrupt the generator path?" msgid "How did you corrupt the custom checker path?" msgstr "Generator yolunu bozmayı nasıl becerdin?" -#: judge/utils/problem_data.py:120 +#: judge/utils/problem_data.py:118 #, python-format msgid "Points must be defined for non-batch case #%d." msgstr "Küme olmayan test #%d için puan tanımlanmalıdır." -#: judge/utils/problem_data.py:125 +#: judge/utils/problem_data.py:123 #, python-format msgid "Input file for case %d does not exist: %s" msgstr "Test #%d için girdi dosyası yok: %s" -#: judge/utils/problem_data.py:128 +#: judge/utils/problem_data.py:126 #, python-format msgid "Output file for case %d does not exist: %s" msgstr "Test #%d için çıktı dosyası yok: %s" -#: judge/utils/problem_data.py:153 +#: judge/utils/problem_data.py:151 #, python-format msgid "Batch start case #%d requires points." msgstr "Küme başlangıç testi #%d puan değerine sahip olmalıdır." -#: judge/utils/problem_data.py:174 +#: judge/utils/problem_data.py:172 #, python-format msgid "Attempt to end batch outside of one in case #%d" msgstr "Test #%d bir kümenin içinde değil, ancak küme bitişini işaret ediyor." -#: judge/utils/problem_data.py:192 +#: judge/utils/problem_data.py:190 msgid "How did you corrupt the zip path?" msgstr "Zip yolunu bozmayı nasıl becerdin?" -#: judge/utils/problem_data.py:198 +#: judge/utils/problem_data.py:196 msgid "How did you corrupt the generator path?" msgstr "Generator yolunu bozmayı nasıl becerdin?" -#: judge/utils/problems.py:80 +#: judge/utils/problems.py:78 msgid "Wrong" msgstr "" -#: judge/utils/problems.py:82 +#: judge/utils/problems.py:80 msgid "Timeout" msgstr "" -#: judge/utils/problems.py:83 +#: judge/utils/problems.py:81 msgid "Error" msgstr "" -#: judge/utils/problems.py:94 +#: judge/utils/problems.py:92 msgid "Can't pass both queryset and keyword filters" msgstr "Queryset ve keyword filtreleri aynı anda verilemez." @@ -2387,8 +2253,7 @@ msgctxt "hours and minutes" msgid "%h:%m" msgstr "%h:%m" -#: judge/views/about.py:7 templates/organization/home.html:112 -#: templates/user/user-about.html:83 templates/user/user-tabs.html:4 +#: judge/views/about.py:7 templates/user/user-about.html:33 msgid "About" msgstr "Hakkında" @@ -2396,167 +2261,157 @@ msgstr "Hakkında" msgid "Custom Checker Sample" msgstr "" -#: judge/views/blog.py:45 +#: judge/views/blog.py:38 #, python-format msgid "Page %d of Posts" msgstr "Sayfa %d" -#: judge/views/comment.py:28 +#: judge/views/comment.py:27 msgid "Messing around, are we?" msgstr "Ooo, bakıyorum da etrafı karıştırıyoruz." -#: judge/views/comment.py:37 +#: judge/views/comment.py:36 msgid "You must solve at least one problem before you can vote." msgstr "" -#: judge/views/comment.py:64 +#: judge/views/comment.py:63 msgid "You already voted." msgstr "Zaten oy verdin." -#: judge/views/comment.py:126 judge/views/organization.py:344 +#: judge/views/comment.py:120 judge/views/organization.py:299 msgid "Edited from site" msgstr "Site aracılığıyla düzenlendi" -#: judge/views/comment.py:147 +#: judge/views/comment.py:141 msgid "Editing comment" msgstr "Yorum düzenleniyor" -#: judge/views/contests.py:57 judge/views/contests.py:247 -#: judge/views/contests.py:250 judge/views/contests.py:424 +#: judge/views/contests.py:55 judge/views/contests.py:215 +#: judge/views/contests.py:218 judge/views/contests.py:389 msgid "No such contest" msgstr "Böyle bir yarışma yok :(" -#: judge/views/contests.py:58 judge/views/contests.py:248 +#: judge/views/contests.py:56 judge/views/contests.py:216 #, python-format msgid "Could not find a contest with the key \"%s\"." msgstr "\"%s\" anahtarıyla bir yarışma bulunamadı." -#: judge/views/contests.py:71 +#: judge/views/contests.py:81 msgid "Contests" msgstr "Yarışmalar" -#: judge/views/contests.py:251 +#: judge/views/contests.py:219 msgid "Could not find such contest." msgstr "Yarışma bulunamadı." -#: judge/views/contests.py:254 +#: judge/views/contests.py:222 #, python-format msgid "Access to contest \"%s\" denied" msgstr "\"%s\" yarışmasına erişimin yok " -#: judge/views/contests.py:278 +#: judge/views/contests.py:246 msgid "Clone Contest" msgstr "" -#: judge/views/contests.py:343 +#: judge/views/contests.py:309 msgid "Contest not ongoing" msgstr "Yarışma devam etmiyor" -#: judge/views/contests.py:344 +#: judge/views/contests.py:310 #, python-format msgid "\"%s\" is not currently ongoing." msgstr "\"%s\" şu anda devam etmiyor." -#: judge/views/contests.py:348 +#: judge/views/contests.py:314 msgid "Already in contest" msgstr "Zaten yarışmadasın" -#: judge/views/contests.py:349 +#: judge/views/contests.py:315 #, python-format msgid "You are already in a contest: \"%s\"." msgstr "Zaten bir yarışmadasın: \"%s\"." -#: judge/views/contests.py:352 +#: judge/views/contests.py:318 msgid "Banned from joining" msgstr "" -#: judge/views/contests.py:353 +#: judge/views/contests.py:319 msgid "" "You have been declared persona non grata for this contest. You are " "permanently barred from joining this contest." msgstr "" -#: judge/views/contests.py:414 +#: judge/views/contests.py:379 #, python-format msgid "Enter access code for \"%s\"" msgstr "“%s” için erişim kodunu gir" -#: judge/views/contests.py:425 +#: judge/views/contests.py:390 #, python-format msgid "You are not in contest \"%s\"." msgstr "\"%s\" yarışmasında değilsin." -#: judge/views/contests.py:444 +#: judge/views/contests.py:409 msgid "ContestCalendar requires integer year and month" msgstr "" -#: judge/views/contests.py:484 +#: judge/views/contests.py:449 #, python-format msgid "Contests in %(month)s" msgstr "%(month)s ayındaki yarışmalar" -#: judge/views/contests.py:484 +#: judge/views/contests.py:449 msgid "F Y" msgstr "" -#: judge/views/contests.py:532 +#: judge/views/contests.py:496 #, fuzzy, python-format #| msgid "Statistics" msgid "%s Statistics" msgstr "İstatistikler" -#: judge/views/contests.py:717 +#: judge/views/contests.py:601 +msgid "???" +msgstr "???" + +#: judge/views/contests.py:664 #, python-format msgid "%s Rankings" msgstr "%s - Sıralama" -#: judge/views/contests.py:725 -msgid "???" -msgstr "???" - -#: judge/views/contests.py:741 +#: judge/views/contests.py:680 #, python-format msgid "Your participation in %s" msgstr "\"%s\" yarışmasına katılımın" -#: judge/views/contests.py:742 +#: judge/views/contests.py:681 #, python-format msgid "%s's participation in %s" msgstr "%s adlı kullanıcının \"%s\" yarışmasına katılımı" -#: judge/views/contests.py:749 +#: judge/views/contests.py:685 msgid "Live" msgstr "Canlı" -#: judge/views/contests.py:761 templates/contest/contest-tabs.html:13 +#: judge/views/contests.py:697 msgid "Participation" msgstr "Katılım" -#: judge/views/contests.py:808 +#: judge/views/contests.py:743 #, python-format msgid "%s MOSS Results" msgstr "" -#: judge/views/contests.py:835 +#: judge/views/contests.py:770 #, python-format msgid "Running MOSS for %s..." msgstr "" -#: judge/views/contests.py:858 +#: judge/views/contests.py:793 #, python-format msgid "Contest tag: %s" msgstr "Yarışma etiketi: %s" -#: judge/views/contests.py:868 judge/views/ticket.py:57 -msgid "Issue description" -msgstr "Sorun açıklaması" - -#: judge/views/contests.py:911 -#, fuzzy, python-format -#| msgid "clarification body" -msgid "New clarification for %s" -msgstr "açıklama içeriği" - #: judge/views/error.py:14 msgid "404 error" msgstr "404 Hatası" @@ -2577,76 +2432,69 @@ msgid "corrupt page %s" msgstr "bozuk sayfa \"%s\"" #: judge/views/language.py:12 templates/status/judge-status-table.html:9 -#: templates/status/status-tabs.html:5 msgid "Runtimes" msgstr "Dil sürümleri" -#: judge/views/notification.py:40 -#, python-format -msgid "Notifications (%d unseen)" -msgstr "" - -#: judge/views/organization.py:59 judge/views/organization.py:62 +#: judge/views/organization.py:44 judge/views/organization.py:47 msgid "No such organization" msgstr "Böyle bir organizasyon yok :(" -#: judge/views/organization.py:60 +#: judge/views/organization.py:45 #, python-format msgid "Could not find an organization with the key \"%s\"." msgstr "\"%s\" anahtarına sahip bir organizasyon bulunamadı." -#: judge/views/organization.py:63 +#: judge/views/organization.py:48 msgid "Could not find such organization." msgstr "Böyle bir organizasyon bulunamadı." -#: judge/views/organization.py:79 judge/views/register.py:34 -#: templates/organization/list.html:32 templates/user/import/table_csv.html:9 -#: templates/user/user-list-tabs.html:6 +#: judge/views/organization.py:72 judge/views/register.py:34 +#: templates/organization/list.html:15 msgid "Organizations" msgstr "Organizasyonlar" -#: judge/views/organization.py:130 +#: judge/views/organization.py:93 #, python-format msgid "%s Members" msgstr "%s üye" -#: judge/views/organization.py:159 judge/views/organization.py:162 -#: judge/views/organization.py:167 +#: judge/views/organization.py:118 judge/views/organization.py:121 +#: judge/views/organization.py:126 msgid "Joining organization" msgstr "Organizasyona katılım" -#: judge/views/organization.py:159 +#: judge/views/organization.py:118 msgid "You are already in the organization." msgstr "Bu organizasyonda zaten varsın." -#: judge/views/organization.py:162 +#: judge/views/organization.py:121 msgid "This organization is not open." msgstr "Bu organizasyon açık değil." -#: judge/views/organization.py:179 +#: judge/views/organization.py:138 msgid "Leaving organization" msgstr "Organizasyondan çık" -#: judge/views/organization.py:179 +#: judge/views/organization.py:138 #, python-format msgid "You are not in \"%s\"." msgstr "\"%s\" içinde değilsin." -#: judge/views/organization.py:203 +#: judge/views/organization.py:162 #, python-format msgid "Request to join %s" msgstr "%s'ye katılma isteği" -#: judge/views/organization.py:221 +#: judge/views/organization.py:180 msgid "Join request detail" msgstr "Katılma isteği detayı" -#: judge/views/organization.py:254 +#: judge/views/organization.py:209 #, python-format msgid "Managing join requests for %s" msgstr "%s - Katılım isteklerini yönet" -#: judge/views/organization.py:285 +#: judge/views/organization.py:240 #, python-format msgid "" "Your organization can only receive %d more members. You cannot approve %d " @@ -2655,46 +2503,46 @@ msgstr "" "Organizasyon yalnızca %d üye daha alabilir. %d üyenin katılımını " "onaylayamazsın." -#: judge/views/organization.py:297 +#: judge/views/organization.py:252 #, python-format msgid "Approved %d user." msgid_plural "Approved %d users." msgstr[0] "%d kullanıcı onaylandı" msgstr[1] "%d kullanıcı onaylandı" -#: judge/views/organization.py:298 +#: judge/views/organization.py:253 #, python-format msgid "Rejected %d user." msgid_plural "Rejected %d users." msgstr[0] "%d kullanıcı onaylandı" msgstr[1] "%d kullanıcı onaylandı" -#: judge/views/organization.py:328 +#: judge/views/organization.py:283 #, python-format msgid "Editing %s" msgstr "%s düzenleniyor" -#: judge/views/organization.py:352 judge/views/organization.py:360 +#: judge/views/organization.py:307 judge/views/organization.py:315 msgid "Can't edit organization" msgstr "Bu organizasyon düzenlenemiyor" -#: judge/views/organization.py:353 +#: judge/views/organization.py:308 msgid "You are not allowed to edit this organization." msgstr "Bu organizasyonu düzenleme yetkisine sahip değilsin." -#: judge/views/organization.py:361 +#: judge/views/organization.py:316 msgid "You are not allowed to kick people from this organization." msgstr "Üyeleri bu organizasyondan atma yetkisine sahip değilsin." -#: judge/views/organization.py:366 judge/views/organization.py:370 +#: judge/views/organization.py:321 judge/views/organization.py:325 msgid "Can't kick user" msgstr "Bu üyeyi atamazsın." -#: judge/views/organization.py:367 +#: judge/views/organization.py:322 msgid "The user you are trying to kick does not exist!" msgstr "Atmaya çalıştığın üye bulunamıyor!" -#: judge/views/organization.py:371 +#: judge/views/organization.py:326 #, python-format msgid "The user you are trying to kick is not in organization: %s." msgstr "Atmaya çalıştığın üye \"%s\" organizasyonunda değil." @@ -2718,37 +2566,36 @@ msgstr " {0} - Problem analizi" msgid "Editorial for {0}" msgstr "{0} için problem analizi" -#: judge/views/problem.py:285 templates/contest/contest.html:79 -#: templates/user/user-about.html:28 templates/user/user-tabs.html:5 -#: templates/user/users-table.html:31 +#: judge/views/problem.py:286 templates/contest/contest.html:79 +#: templates/user/users-table.html:23 msgid "Problems" msgstr "Problemler" -#: judge/views/problem.py:585 +#: judge/views/problem.py:547 msgid "Banned from submitting" msgstr "Çözüm gönderme engellendi" -#: judge/views/problem.py:586 +#: judge/views/problem.py:548 msgid "" "You have been declared persona non grata for this problem. You are " "permanently barred from submitting this problem." msgstr "" "Bu problem için istenmeyen adam olarak işaretlendin. Çözüm gönderemezsin." -#: judge/views/problem.py:600 +#: judge/views/problem.py:562 msgid "Too many submissions" msgstr "Çok fazla çözüm gönderisi" -#: judge/views/problem.py:601 +#: judge/views/problem.py:563 msgid "You have exceeded the submission limit for this problem." msgstr "Bu soru için çözüm gönderi sınırını geçtin." -#: judge/views/problem.py:661 judge/views/problem.py:664 +#: judge/views/problem.py:633 judge/views/problem.py:636 #, python-format msgid "Submit to %(problem)s" msgstr "Çözüm gönder -%(problem)s" -#: judge/views/problem.py:679 +#: judge/views/problem.py:652 msgid "Clone Problem" msgstr "" @@ -2789,22 +2636,22 @@ msgstr "%s için verileri düzenle" msgid "Generated init.yml for %s" msgstr "%s için init.yml oluşturuldu" -#: judge/views/problem_manage.py:52 judge/views/problem_manage.py:55 +#: judge/views/problem_manage.py:50 judge/views/problem_manage.py:53 #, python-format msgid "Managing submissions for %s" msgstr "" -#: judge/views/problem_manage.py:97 +#: judge/views/problem_manage.py:95 #, python-format msgid "Rejudging selected submissions for %s..." msgstr "" -#: judge/views/problem_manage.py:141 +#: judge/views/problem_manage.py:110 #, python-format msgid "Rescoring all submissions for %s..." msgstr "" -#: judge/views/problem_manage.py:150 +#: judge/views/problem_manage.py:119 #, python-format msgid "Successfully scheduled %d submission for rejudging." msgid_plural "Successfully scheduled %d submissions for rejudging." @@ -2853,7 +2700,7 @@ msgstr "Tercih edilen dil" msgid "Subscribe to newsletter?" msgstr "Haber bültenine abone ol" -#: judge/views/register.py:55 +#: judge/views/register.py:45 #, python-format msgid "" "The email address \"%s\" is already taken. Only one registration is allowed " @@ -2861,7 +2708,7 @@ msgid "" msgstr "" "\"%s\" zaten kullanımda. E-posta adresleri yalnızca bir kez kullanılabilir." -#: judge/views/register.py:61 +#: judge/views/register.py:51 msgid "" "Your email provider is not allowed due to history of abuse. Please use a " "reputable email provider." @@ -2869,11 +2716,11 @@ msgstr "" "E-posta sağlayıcın geçmişte yaşanan suistimallerden dolayı geçersizdir. " "Lütfen bilinen bir e-posta sağlayıcısı kullan." -#: judge/views/register.py:67 judge/views/register.py:105 +#: judge/views/register.py:57 judge/views/register.py:95 msgid "Registration" msgstr "Kayıt" -#: judge/views/register.py:116 +#: judge/views/register.py:106 msgid "Authentication failure" msgstr "Kimlik doğrulama hatası" @@ -2889,49 +2736,49 @@ msgstr "Durum" msgid "Version matrix" msgstr "Sürüm matrisi" -#: judge/views/submission.py:84 judge/views/submission.py:91 +#: judge/views/submission.py:83 judge/views/submission.py:90 #, python-format msgid "Submission of %(problem)s by %(user)s" msgstr "%(user)s tarafından %(problem)s için gönderilen çözüm" -#: judge/views/submission.py:244 judge/views/submission.py:245 -#: templates/problem/problem.html:167 +#: judge/views/submission.py:227 judge/views/submission.py:228 +#: templates/problem/problem.html:127 msgid "All submissions" msgstr "Tüm çözümler" -#: judge/views/submission.py:404 +#: judge/views/submission.py:384 msgid "All my submissions" msgstr "Tüm çözümlerim" -#: judge/views/submission.py:405 +#: judge/views/submission.py:385 #, python-format msgid "All submissions by %s" msgstr "%s'nin tüm çözümleri" -#: judge/views/submission.py:436 +#: judge/views/submission.py:416 #, python-format msgid "All submissions for %s" msgstr "%s için tüm çözümler" -#: judge/views/submission.py:455 +#: judge/views/submission.py:435 msgid "Must pass a problem" msgstr "Bir problem tanımlanmalı" -#: judge/views/submission.py:501 +#: judge/views/submission.py:481 #, python-format msgid "My submissions for %(problem)s" msgstr "%(problem)s için çözümlerim" -#: judge/views/submission.py:502 +#: judge/views/submission.py:482 #, python-format msgid "%(user)s's submissions for %(problem)s" msgstr "%(user)s tarafından %(problem)s için gönderilen çözümler" -#: judge/views/submission.py:603 +#: judge/views/submission.py:583 msgid "Must pass a contest" msgstr "Bir yarışma tanımlanmalı" -#: judge/views/submission.py:622 +#: judge/views/submission.py:602 #, python-brace-format msgid "" "{0}'s submissions for {2} in {0} tarafından {2} için gönderilen " "çözüm - {4}" -#: judge/views/submission.py:629 +#: judge/views/submission.py:609 #, python-brace-format msgid "" "{0}'s submissions for problem {2} in {3}" @@ -2949,44 +2796,48 @@ msgstr "" "{0} tarafından problem {2} için gönderilen çözüm - {3}" -#: judge/views/ticket.py:50 judge/views/ticket.py:56 +#: judge/views/ticket.py:33 judge/views/ticket.py:39 msgid "Ticket title" msgstr "Bilet başlığı" -#: judge/views/ticket.py:107 judge/views/ticket.py:110 +#: judge/views/ticket.py:40 +msgid "Issue description" +msgstr "Sorun açıklaması" + +#: judge/views/ticket.py:85 judge/views/ticket.py:88 #, python-format msgid "New ticket for %s" msgstr "%s için yeni bilet" -#: judge/views/ticket.py:170 +#: judge/views/ticket.py:142 #, python-format msgid "%(title)s - Ticket %(id)d" msgstr "%(title)s - Bilet %(id)d" -#: judge/views/ticket.py:279 +#: judge/views/ticket.py:251 #, python-format msgid "Tickets - Page %(number)d of %(total)d" msgstr "Biletler - Sayfa %(number)d/%(total)d" -#: judge/views/ticket.py:328 +#: judge/views/ticket.py:300 #, python-format msgid "New Ticket: %s" msgstr "Yeni Bilet: %s" -#: judge/views/ticket.py:329 +#: judge/views/ticket.py:301 #, python-format msgid "#%(id)d, assigned to: %(users)s" msgstr "#%(id)d, sorumlular: %(users)s" -#: judge/views/ticket.py:331 +#: judge/views/ticket.py:303 msgid ", " msgstr "," -#: judge/views/ticket.py:331 +#: judge/views/ticket.py:303 msgid "no one" msgstr "kimse" -#: judge/views/ticket.py:351 +#: judge/views/ticket.py:323 #, fuzzy, python-format #| msgid "New Ticket: %s" msgid "New Ticket Message For: %s" @@ -3004,52 +2855,41 @@ msgstr "" msgid "Perform Two Factor Authentication" msgstr "" -#: judge/views/user.py:74 +#: judge/views/user.py:68 msgid "No such user" msgstr "Böyle bir kullanıcı yok" -#: judge/views/user.py:74 +#: judge/views/user.py:68 #, python-format msgid "No user handle \"%s\"." msgstr "\"%s\" adında bir kullanıcı yok." -#: judge/views/user.py:78 +#: judge/views/user.py:72 msgid "My account" msgstr "Hesabım" -#: judge/views/user.py:79 +#: judge/views/user.py:73 #, python-format msgid "User %s" msgstr "Kullanıcı %s" -#: judge/views/user.py:148 -#, fuzzy -#| msgid "M j, Y, G:i" -msgid "M j, Y" -msgstr "j M Y, G:i" - -#: judge/views/user.py:171 +#: judge/views/user.py:136 msgid "M j, Y, G:i" msgstr "j M Y, G:i" -#: judge/views/user.py:290 +#: judge/views/user.py:221 msgid "Updated on site" msgstr "Sitede güncellendi" -#: judge/views/user.py:323 templates/admin/auth/user/change_form.html:14 -#: templates/admin/auth/user/change_form.html:17 templates/base.html:238 -#: templates/user/user-tabs.html:10 +#: judge/views/user.py:254 templates/admin/auth/user/change_form.html:14 +#: templates/admin/auth/user/change_form.html:17 templates/base.html:224 msgid "Edit profile" msgstr "Profili düzenle" -#: judge/views/user.py:332 templates/user/user-list-tabs.html:4 +#: judge/views/user.py:263 msgid "Leaderboard" msgstr "Sıralama" -#: judge/views/user.py:407 -msgid "Import Users" -msgstr "" - #: judge/views/widgets.py:48 judge/views/widgets.py:58 #, python-format msgid "Invalid upstream data: %s" @@ -3087,7 +2927,7 @@ msgid "View Submissions" msgstr "" #: templates/admin/judge/problem/change_form.html:17 -#: templates/user/user-base.html:112 +#: templates/user/user-base.html:61 msgid "View submissions" msgstr "Gönderileri görüntüle" @@ -3102,155 +2942,92 @@ msgstr "Kullanıcı düzenle" msgid "Rejudge" msgstr "Yeniden değerlendir" -#: templates/base.html:230 -#, python-format -msgid "Hello, %(username)s." -msgstr "Merhaba, %(username)s." - -#: templates/base.html:236 templates/comments/list.html:89 -#: templates/contest/contest-list-tabs.html:24 -#: templates/contest/ranking-table.html:53 -#: templates/problem/problem-list-tabs.html:6 +#: templates/base.html:222 templates/comments/list.html:89 +#: templates/contest/ranking-table.html:39 #: templates/submission/info-base.html:12 -#: templates/submission/submission-list-tabs.html:15 msgid "Admin" msgstr "Yönetici" -#: templates/base.html:245 +#: templates/base.html:231 msgid "Log out" msgstr "Çıkış yap" -#: templates/base.html:254 +#: templates/base.html:240 #: templates/registration/password_reset_complete.html:4 msgid "Log in" msgstr "Giriş yap" -#: templates/base.html:255 templates/registration/registration_form.html:177 +#: templates/base.html:241 templates/registration/registration_form.html:177 msgid "or" msgstr "ya da" -#: templates/base.html:256 +#: templates/base.html:242 msgid "Sign up" msgstr "" -#: templates/base.html:271 +#: templates/base.html:254 msgid "spectating" msgstr "izleniyor" -#: templates/base.html:284 +#: templates/base.html:267 msgid "This site works best with JavaScript enabled." msgstr "Bu sitenin düzgün görüntülenmesi için JavaScript etkin olmalıdır." -#: templates/blog/blog.html:13 templates/comments/list.html:68 -#: templates/comments/list.html:83 templates/contest/contest-tabs.html:23 -#: templates/contest/tag-title.html:9 templates/flatpages/admin_link.html:3 -#: templates/license.html:10 templates/problem/editorial.html:14 +#: templates/blog/content.html:13 templates/comments/list.html:68 +#: templates/comments/list.html:83 templates/contest/tag-title.html:9 +#: templates/flatpages/admin_link.html:3 templates/license.html:10 +#: templates/problem/editorial.html:14 msgid "Edit" msgstr "Düzenle" -#: templates/blog/blog.html:26 -#, python-format -msgid "" -"\n" -" posted on %(time)s\n" -" " -msgstr "" -"\n" -"%(time)s" - -#: templates/blog/content.html:10 -#, python-brace-format -msgid "posted on {time}" -msgstr "{time}" - -#: templates/blog/dashboard.html:21 -#, python-format -msgid "" -"\n" -" on %(time)s\n" -" " -msgstr "" -"\n" -"%(time)s" - -#: templates/blog/list.html:93 +#: templates/blog/list.html:85 msgid "Blog" msgstr "" -#: templates/blog/list.html:95 +#: templates/blog/list.html:87 msgid "Events" msgstr "Etkinlikler" -#: templates/blog/list.html:100 +#: templates/blog/list.html:92 msgid "News" msgstr "Haberler" -#: templates/blog/list.html:115 templates/problem/list.html:347 -#: templates/problem/problem.html:361 +#: templates/blog/list.html:130 templates/problem/problem.html:310 msgid "Clarifications" msgstr "Açıklamalar" -#: templates/blog/list.html:121 -msgid "Add" -msgstr "" - -#: templates/blog/list.html:140 templates/problem/list.html:369 -#: templates/problem/problem.html:372 +#: templates/blog/list.html:146 templates/problem/problem.html:321 msgid "No clarifications have been made at this time." msgstr "Henüz bir açıklama yapılmadı." -#: templates/blog/list.html:148 +#: templates/blog/list.html:154 msgid "Ongoing contests" msgstr "Devam eden yarışmalar" -#: templates/blog/list.html:166 +#: templates/blog/list.html:172 msgid "Upcoming contests" msgstr "Gelecek yarışmalar" -#: templates/blog/list.html:184 -msgid "My open tickets" -msgstr "Açık biletlerim" - -#: templates/blog/list.html:206 -msgid "New tickets" -msgstr "Yeni biletler" - -#: templates/blog/list.html:227 -msgid "New problems" -msgstr "Yeni problemler" - -#: templates/blog/list.html:244 +#: templates/blog/list.html:189 msgid "Comment stream" msgstr "Son yorumlar" -#: templates/chat/chat.html:305 -msgid "Chat" +#: templates/blog/list.html:208 +msgid "New problems" +msgstr "Yeni problemler" + +#: templates/blog/list.html:225 +msgid "My open tickets" +msgstr "Açık biletlerim" + +#: templates/blog/list.html:246 +msgid "New tickets" +msgstr "Yeni biletler" + +#: templates/chat/chat.html:167 +msgid "Your message" msgstr "" -#: templates/chat/chat.html:307 templates/chat/chat.html:314 -#, fuzzy -#| msgid "Online Judge" -msgid "Online Users" -msgstr "Online Değerlendirme Sistemi" - -#: templates/chat/chat.html:315 -msgid "Refresh" -msgstr "" - -#: templates/chat/chat.html:333 -msgid "Emoji" -msgstr "" - -#: templates/chat/chat.html:334 -msgid "Enter your message" -msgstr "" - -#: templates/chat/message.html:20 -#, fuzzy -#| msgid "Delete?" -msgid "Delete" -msgstr "Sil?" - #: templates/comments/list.html:2 msgid "Comments" msgstr "Yorumlar" @@ -3259,21 +3036,11 @@ msgstr "Yorumlar" msgid "Please login to vote" msgstr "Oylamak için lütfen giriş yap" -#: templates/comments/list.html:40 -#, python-brace-format -msgid "commented on {time}" -msgstr "{time} " - -#: templates/comments/list.html:49 -#, python-format -msgid "edit %(edits)s" -msgstr "düzenleme %(edits)s" - -#: templates/comments/list.html:51 templates/comments/media-js.html:92 +#: templates/comments/list.html:51 templates/comments/media-js.html:77 msgid "edited" msgstr "düzenlendi" -#: templates/comments/list.html:60 templates/notification/list.html:14 +#: templates/comments/list.html:60 msgid "Link" msgstr "" @@ -3281,54 +3048,36 @@ msgstr "" msgid "Reply" msgstr "Yanıtla" -#: templates/comments/list.html:86 templates/contest/list.html:91 -#: templates/contest/list.html:95 templates/contest/list.html:280 +#: templates/comments/list.html:86 msgid "Hide" msgstr "Gizle" -#: templates/comments/list.html:101 -#, python-format -msgid "" -"\n" -" This comment is hidden due " -"to too much negative feedback.\n" -" Click here to view it.\n" -" " -msgstr "" - -#: templates/comments/list.html:121 +#: templates/comments/list.html:120 msgid "There are no comments at the moment." msgstr "Şu anda hiç yorum yok." -#: templates/comments/list.html:127 +#: templates/comments/list.html:126 msgid "New comment" msgstr "Yeni yorum" -#: templates/comments/list.html:141 +#: templates/comments/list.html:140 msgid "Invalid comment body." msgstr "Yorum metninde hata!" -#: templates/comments/list.html:149 +#: templates/comments/list.html:148 msgid "Post!" msgstr "Yayınla!" -#: templates/comments/list.html:157 +#: templates/comments/list.html:156 msgid "Comments are disabled on this page." msgstr "" -#: templates/comments/media-js.html:38 -#, fuzzy -#| msgid "no comments" -msgid "Replying to comment" -msgstr "yorum yok" - -#: templates/comments/media-js.html:87 +#: templates/comments/media-js.html:72 #, python-brace-format msgid "edit {edits}" msgstr "düzenleme {edits}" -#: templates/comments/media-js.html:90 +#: templates/comments/media-js.html:75 msgid "original" msgstr "orijinal" @@ -3372,11 +3121,6 @@ msgstr "Cuma" msgid "Saturday" msgstr "Cumartesi" -#: templates/contest/clarification.html:52 templates/organization/new.html:10 -#: templates/ticket/new.html:38 -msgid "Create" -msgstr "Oluştur" - #: templates/contest/clone.html:37 msgid "Enter a new key for the cloned contest:" msgstr "" @@ -3397,110 +3141,50 @@ msgstr "" msgid "Next" msgstr "Sonraki" -#: templates/contest/contest-list-tabs.html:21 -#: templates/problem/problem-list-tabs.html:5 -msgid "List" -msgstr "Liste" - -#: templates/contest/contest-list-tabs.html:22 -msgid "Calendar" -msgstr "Takvim" - -#: templates/contest/contest-tabs.html:4 templates/organization/home.html:105 -msgid "Info" -msgstr "Hakkında" - -#: templates/contest/contest-tabs.html:6 templates/stats/base.html:9 -#: templates/submission/list.html:339 -msgid "Statistics" -msgstr "İstatistikler" - -#: templates/contest/contest-tabs.html:11 -msgid "Rankings" -msgstr "Sıralamalar" - -#: templates/contest/contest-tabs.html:16 -msgid "Hidden Rankings" -msgstr "Gizli Sıralamalar" - -#: templates/contest/contest-tabs.html:21 -msgid "MOSS" -msgstr "" - -#: templates/contest/contest-tabs.html:26 -msgid "Clone" -msgstr "" - -#: templates/contest/contest-tabs.html:38 -#: templates/contest/contest-tabs.html:58 +#: templates/contest/contest-tabs.html:37 msgid "Leave contest" msgstr "Yarışmadan ayrıl" -#: templates/contest/contest-tabs.html:45 templates/contest/list.html:388 +#: templates/contest/contest-tabs.html:44 templates/contest/list.html:293 msgid "Virtual join" msgstr "Sanal katılım" -#: templates/contest/contest-tabs.html:56 -msgid "Stop spectating" -msgstr "İzlemeyi bırak" - -#: templates/contest/contest-tabs.html:65 +#: templates/contest/contest-tabs.html:64 msgid "Spectate contest" msgstr "Yarışmayı izle" -#: templates/contest/contest-tabs.html:72 +#: templates/contest/contest-tabs.html:70 +#: templates/contest/contest-tabs.html:76 msgid "Join contest" msgstr "Yarışmaya katıl" -#: templates/contest/contest-tabs.html:81 +#: templates/contest/contest-tabs.html:85 msgid "Login to participate" msgstr "Katılmak için giriş yap" -#: templates/contest/contest.html:37 -msgid "Participating virtually." -msgstr "Sanal olarak katılınıyor. " - -#: templates/contest/contest.html:43 -msgid "Contest is over." -msgstr "Yarışma sona erdi" - #: templates/contest/contest.html:59 templates/contest/contest.html:63 msgid "F j, Y, G:i T" msgstr "j F Y, G:i T" -#: templates/contest/contest.html:59 -#, python-format -msgid "" -"%(time_limit)s window between %(start_time)s and " -"%(end_time)s" -msgstr "" -" %(start_time)s ile %(end_time)s arasında, süre sınırı " -"%(time_limit)s" - -#: templates/contest/contest.html:63 -#, python-format -msgid "%(length)s long starting on %(start_time)s" -msgstr "başlangıç %(start_time)s, yarışma süresi %(length)s" - #: templates/contest/contest.html:85 msgid "AC Rate" msgstr "AC Oranı" -#: templates/contest/contest.html:86 templates/contest/list.html:237 -#: templates/contest/list.html:289 templates/contest/list.html:366 -#: templates/problem/list.html:223 templates/problem/list.html:254 +#: templates/contest/contest.html:86 templates/contest/list.html:153 +#: templates/contest/list.html:195 templates/contest/list.html:271 +#: templates/problem/list.html:212 templates/problem/list.html:238 msgid "Users" msgstr "Kullanıcılar" -#: templates/contest/contest.html:111 templates/problem/list.html:330 +#: templates/contest/contest.html:111 msgid "Editorial" msgstr "Problem analizi" -#: templates/contest/list.html:83 templates/contest/media-js.html:9 +#: templates/contest/list.html:31 templates/contest/media-js.html:9 msgid "Are you sure you want to join?" msgstr "Katılmak istediğine emin misin?" -#: templates/contest/list.html:84 +#: templates/contest/list.html:32 msgid "" "Joining a contest for the first time starts your timer, after which it " "becomes unstoppable." @@ -3508,68 +3192,48 @@ msgstr "" "Bir yarışmaya ilk defa katılmak süreni başlatır, süren başladıktan sonra " "durdurulamaz. " -#: templates/contest/list.html:92 templates/contest/list.html:278 -msgid "Show" -msgstr "" - -#: templates/contest/list.html:102 templates/problem/list.html:68 -#, fuzzy -#| msgid "Organizations" -msgid "Organizations..." -msgstr "Organizasyonlar" - -#: templates/contest/list.html:135 +#: templates/contest/list.html:65 msgid "hidden" msgstr "" -#: templates/contest/list.html:140 +#: templates/contest/list.html:70 msgid "private" msgstr "" -#: templates/contest/list.html:154 +#: templates/contest/list.html:84 msgid "rated" msgstr "" -#: templates/contest/list.html:202 +#: templates/contest/list.html:132 msgid "Spectate" msgstr "İzle" -#: templates/contest/list.html:208 +#: templates/contest/list.html:138 msgid "Join" msgstr "Katıl" -#: templates/contest/list.html:220 -#, fuzzy -#| msgid "Search problems..." -msgid "Search contests..." -msgstr "Problemlerde ara..." - -#: templates/contest/list.html:229 -msgid "Search" -msgstr "" - -#: templates/contest/list.html:232 +#: templates/contest/list.html:148 msgid "Active Contests" msgstr "" -#: templates/contest/list.html:236 templates/contest/list.html:288 -#: templates/contest/list.html:327 templates/contest/list.html:365 +#: templates/contest/list.html:152 templates/contest/list.html:194 +#: templates/contest/list.html:232 templates/contest/list.html:270 msgid "Contest" msgstr "Yarışma" -#: templates/contest/list.html:275 +#: templates/contest/list.html:190 msgid "Ongoing Contests" msgstr "Devam Eden Yarışmalar" -#: templates/contest/list.html:322 +#: templates/contest/list.html:227 msgid "Upcoming Contests" msgstr "Gelecek yarışmalar" -#: templates/contest/list.html:350 +#: templates/contest/list.html:255 msgid "There are no scheduled contests at this time." msgstr "Şu anda planlanmış yarışma bulunmuyor." -#: templates/contest/list.html:356 +#: templates/contest/list.html:261 msgid "Past Contests" msgstr "Eski Yarışmalar" @@ -3620,89 +3284,55 @@ msgstr "" msgid "Only the following organizations may access this contest:" msgstr "Yarışmaya yalnızca şu organizasyonlar erişebilir:" -#: templates/contest/ranking-table.html:9 templates/problem/search-form.html:35 +#: templates/contest/ranking-table.html:7 msgid "Organization" msgstr "Organizasyon" -#: templates/contest/ranking-table.html:10 templates/user/users-table.html:13 -#, fuzzy -#| msgid "full name" -msgid "Full Name" -msgstr "Tam ad" - -#: templates/contest/ranking-table.html:44 +#: templates/contest/ranking-table.html:30 msgid "Un-Disqualify" msgstr "" -#: templates/contest/ranking-table.html:47 +#: templates/contest/ranking-table.html:33 msgid "Disqualify" msgstr "" -#: templates/contest/ranking.html:187 +#: templates/contest/ranking.html:173 #, fuzzy #| msgid "Are you sure you want to join?" msgid "Are you sure you want to disqualify this participation?" msgstr "Katılmak istediğine emin misin?" -#: templates/contest/ranking.html:192 +#: templates/contest/ranking.html:178 #, fuzzy #| msgid "Are you sure you want to join?" msgid "Are you sure you want to un-disqualify this participation?" msgstr "Katılmak istediğine emin misin?" -#: templates/contest/ranking.html:463 +#: templates/contest/ranking.html:252 msgid "View user participation" msgstr "Kullanıcı katılımını göster" -#: templates/contest/ranking.html:467 +#: templates/contest/ranking.html:256 msgid "Show organizations" msgstr "Organizasyonları göster" -#: templates/contest/ranking.html:471 -#, fuzzy -#| msgid "full name" -msgid "Show full name" -msgstr "Tam ad" - -#: templates/contest/ranking.html:474 -#, fuzzy -#| msgid "Show my tickets only" -msgid "Show friends only" -msgstr "Sadece benim biletlerimi göster" - -#: templates/contest/ranking.html:477 -msgid "Total score only" -msgstr "" - -#: templates/contest/ranking.html:479 -#, fuzzy -#| msgid "virtual participation id" -msgid "Show virtual participation" -msgstr "sanal katılım ID'si" - -#: templates/contest/stats.html:51 +#: templates/contest/stats.html:38 #, fuzzy #| msgid "problem translation" msgid "Problem Status Distribution" msgstr "problem çevirisi" -#: templates/contest/stats.html:56 +#: templates/contest/stats.html:43 #, fuzzy #| msgid "Problem name" msgid "Problem AC Rate" msgstr "Problem adı" -#: templates/contest/stats.html:62 -#, fuzzy -#| msgid "problem translation" -msgid "Problem Point Distribution" -msgstr "problem çevirisi" - -#: templates/contest/stats.html:76 templates/stats/language.html:16 +#: templates/contest/stats.html:48 templates/stats/language.html:16 msgid "Submissions by Language" msgstr "Dillere Göre Çözümler" -#: templates/contest/stats.html:82 templates/stats/language.html:26 +#: templates/contest/stats.html:54 templates/stats/language.html:26 msgid "Language AC Rate" msgstr "Dil AC Oranı" @@ -3711,7 +3341,6 @@ msgid "Source:" msgstr "Kaynak:" #: templates/newsletter/common.html:6 -#: templates/newsletter/newsletter_list.html:15 #: templates/newsletter/subscription_unsubscribe_activated.html:3 #: templates/newsletter/subscription_unsubscribe_activated.html:6 #: templates/newsletter/subscription_update_activated.html:3 @@ -3719,29 +3348,6 @@ msgstr "Kaynak:" msgid "Newsletter" msgstr "Haber bülteni" -#: templates/newsletter/newsletter_list.html:2 -#: templates/newsletter/newsletter_list.html:3 -#, fuzzy -#| msgid "Newsletter" -msgid "Newsletter list" -msgstr "Haber bülteni" - -#: templates/newsletter/newsletter_list.html:6 -msgid "Subscribe to get the latest emails about upcoming contests and events." -msgstr "" - -#: templates/newsletter/newsletter_list.html:16 -#, fuzzy -#| msgid "Unsubscribe" -msgid "Subscribe" -msgstr "Abonelikten çık" - -#: templates/newsletter/newsletter_list.html:30 -#, fuzzy -#| msgid "Update subscription" -msgid "Update subscriptions" -msgstr "Aboneliği güncelle" - #: templates/newsletter/subscription_unsubscribe_activated.html:3 #: templates/newsletter/subscription_unsubscribe_activated.html:6 #: templates/newsletter/subscription_update_activated.html:3 @@ -3809,115 +3415,64 @@ msgstr "" "Güncelleme isteğin alındı ve adresine aktivasyon e-postası gönderildi. E-" "postadaki bağlantıyı izleyerek aboneliğini güncelleyebilirsin." -#: templates/notification/list.html:7 -#, fuzzy -#| msgid "You have not shared any information." -msgid "You have no notifications" -msgstr "Henüz hiçbir bilgi paylaşmadın." - -#: templates/notification/list.html:13 -#, fuzzy -#| msgid "activate" -msgid "Activity" -msgstr "aktifleştir" - #: templates/organization/edit.html:46 #: templates/organization/requests/pending.html:34 #: templates/ticket/edit-notes.html:4 msgid "Update" msgstr "Güncelle" -#: templates/organization/home.html:41 +#: templates/organization/home.html:7 msgid "Are you sure you want to leave this organization?" msgstr "" -#: templates/organization/home.html:43 +#: templates/organization/home.html:9 msgid "You will have to rejoin to show up on the organization leaderboard." msgstr "" -#: templates/organization/home.html:45 +#: templates/organization/home.html:11 msgid "You will have to request membership in order to join again." msgstr "" -#: templates/organization/home.html:88 -msgid "Join organization" -msgstr "Organizasyona katıl" - -#: templates/organization/home.html:92 -msgid "Request membership" -msgstr "Üyelik talep et" - -#: templates/organization/home.html:122 -#, fuzzy -#| msgid "Organizations" -msgid "Organization news" -msgstr "Organizasyonlar" - -#: templates/organization/home.html:128 -#, fuzzy -#| msgid "There are no scheduled contests at this time." -msgid "There is no news at this time." -msgstr "Şu anda planlanmış yarışma bulunmuyor." - -#: templates/organization/home.html:137 -#, fuzzy -#| msgid "Contest" -msgid "Controls" -msgstr "Yarışma" - -#: templates/organization/home.html:142 -msgid "Edit organization" -msgstr "Organizasyonu düzenle" - -#: templates/organization/home.html:148 -msgid "View requests" -msgstr "İstekleri göster" - -#: templates/organization/home.html:161 -msgid "Admin organization" -msgstr "Organizasyonu düzenle" - -#: templates/organization/home.html:167 -msgid "View members" -msgstr "Üyeleri göster" - -#: templates/organization/home.html:174 +#: templates/organization/home.html:24 msgid "Leave organization" msgstr "Organizasyondan ayrıl" -#: templates/organization/home.html:183 -#, fuzzy -#| msgid "See private contests" -msgid "New private contests" -msgstr "Özel yarışmaları gör" +#: templates/organization/home.html:29 +msgid "Join organization" +msgstr "Organizasyona katıl" -#: templates/organization/home.html:193 templates/organization/home.html:208 -#, fuzzy -#| msgid "View as PDF" -msgid "View all" -msgstr "PDF olarak göster" +#: templates/organization/home.html:33 +msgid "Request membership" +msgstr "Üyelik talep et" -#: templates/organization/home.html:199 -#, fuzzy -#| msgid "New problems" -msgid "New private problems" -msgstr "Yeni problemler" +#: templates/organization/home.html:39 +msgid "Edit organization" +msgstr "Organizasyonu düzenle" -#: templates/organization/list.html:40 -#, fuzzy -#| msgid "Show organizations" -msgid "Show my organizations only" -msgstr "Organizasyonları göster" +#: templates/organization/home.html:43 +msgid "View requests" +msgstr "İstekleri göster" -#: templates/organization/list.html:47 templates/status/language-list.html:34 -#: templates/user/import/table_csv.html:6 +#: templates/organization/home.html:50 +msgid "Admin organization" +msgstr "Organizasyonu düzenle" + +#: templates/organization/home.html:55 +msgid "View members" +msgstr "Üyeleri göster" + +#: templates/organization/list.html:23 templates/status/language-list.html:34 msgid "Name" msgstr "İsim" -#: templates/organization/list.html:48 +#: templates/organization/list.html:24 msgid "Members" msgstr "Üyeler" +#: templates/organization/new.html:10 templates/ticket/new.html:38 +msgid "Create" +msgstr "Oluştur" + #: templates/organization/requests/detail.html:13 msgid "User:" msgstr "Kullanıcı:" @@ -3950,7 +3505,7 @@ msgid "There are no requests to approve." msgstr "Onaylanacak istek yok." #: templates/organization/requests/pending.html:17 -#: templates/problem/data.html:432 +#: templates/problem/data.html:452 msgid "Delete?" msgstr "Sil?" @@ -3986,37 +3541,37 @@ msgstr "At" msgid "Enter a new code for the cloned problem:" msgstr "" -#: templates/problem/data.html:119 +#: templates/problem/data.html:108 #, fuzzy #| msgid "Information" msgid "Instruction" msgstr "Bilgi" -#: templates/problem/data.html:390 +#: templates/problem/data.html:410 msgid "View YAML" msgstr "YAML'i görüntüle" -#: templates/problem/data.html:421 templates/problem/data.html:472 +#: templates/problem/data.html:441 templates/problem/data.html:491 msgid "Apply!" msgstr "" -#: templates/problem/data.html:426 +#: templates/problem/data.html:446 msgid "Type" msgstr "Tip" -#: templates/problem/data.html:427 +#: templates/problem/data.html:447 msgid "Input file" msgstr "Girdi dosyası" -#: templates/problem/data.html:428 +#: templates/problem/data.html:448 msgid "Output file" msgstr "Çıktı dosyası" -#: templates/problem/data.html:430 +#: templates/problem/data.html:450 msgid "Pretest?" msgstr "Ön test?" -#: templates/problem/data.html:473 +#: templates/problem/data.html:492 msgid "Add new case" msgstr "Yeni test ekle" @@ -4031,34 +3586,28 @@ msgstr "" "Lütfen analizden kod kopyalayıp yapıştırma.

Problemi çözmeden " "resmi çözümü kopyalayıp yapıştırmak engellenmene neden olabilir." -#: templates/problem/list.html:66 +#: templates/problem/list.html:62 msgid "Filter by type..." msgstr "Tipe göre filtrele..." -#: templates/problem/list.html:193 +#: templates/problem/list.html:185 msgid "Hot problems" msgstr "Popüler problemler" -#: templates/problem/list.html:218 templates/problem/list.html:240 -#: templates/problem/search-form.html:45 templates/user/user-problems.html:57 +#: templates/problem/list.html:207 templates/problem/list.html:224 +#: templates/problem/search-form.html:30 templates/user/user-problems.html:57 msgid "Category" msgstr "Kategori" -#: templates/problem/list.html:220 templates/problem/list.html:244 +#: templates/problem/list.html:209 templates/problem/list.html:228 msgid "Types" msgstr "Tipler" -#: templates/problem/list.html:251 +#: templates/problem/list.html:235 #, python-format msgid "AC %%" msgstr "AC %%" -#: templates/problem/list.html:342 -#, fuzzy -#| msgid "Clarifications" -msgid "Add clarifications" -msgstr "Açıklamalar" - #: templates/problem/manage_submission.html:55 msgid "Leave empty to not filter by language" msgstr "" @@ -4067,206 +3616,152 @@ msgstr "" msgid "Leave empty to not filter by result" msgstr "" -#: templates/problem/manage_submission.html:80 +#: templates/problem/manage_submission.html:79 msgid "Need valid values for both start and end IDs." msgstr "" -#: templates/problem/manage_submission.html:83 +#: templates/problem/manage_submission.html:82 msgid "End ID must be after start ID." msgstr "" +#: templates/problem/manage_submission.html:90 +#, python-brace-format +msgid "" +"You are about to rejudge {count} submissions. Are you sure you want to do " +"this?" +msgstr "" + #: templates/problem/manage_submission.html:96 -#, python-brace-format msgid "" -"You are about to {action} {count} submissions. Are you sure you want to do " -"this?" +"You are about to rejudge a few submissions. Are you sure you want to do this?" msgstr "" -#: templates/problem/manage_submission.html:103 -#, python-brace-format -msgid "" -"You are about to {action} a few submissions. Are you sure you want to do " -"this?" +#: templates/problem/manage_submission.html:115 +msgid "Rejudge Submissions" msgstr "" -#: templates/problem/manage_submission.html:127 -#: templates/submission/list.html:309 -msgid "Filter submissions" -msgstr "Çözümleri filtrele" - -#: templates/problem/manage_submission.html:132 +#: templates/problem/manage_submission.html:120 msgid "Filter by ID:" msgstr "" -#: templates/problem/manage_submission.html:135 +#: templates/problem/manage_submission.html:123 msgid "Starting ID:" msgstr "" -#: templates/problem/manage_submission.html:139 +#: templates/problem/manage_submission.html:127 msgid "Ending ID:" msgstr "" -#: templates/problem/manage_submission.html:143 +#: templates/problem/manage_submission.html:131 msgid "This range includes both endpoints." msgstr "" -#: templates/problem/manage_submission.html:146 +#: templates/problem/manage_submission.html:134 msgid "Filter by language:" msgstr "" -#: templates/problem/manage_submission.html:154 +#: templates/problem/manage_submission.html:142 msgid "Filter by result:" msgstr "" -#: templates/problem/manage_submission.html:164 -#, fuzzy -#| msgid "location" -msgid "Action" -msgstr "konum" - -#: templates/problem/manage_submission.html:166 +#: templates/problem/manage_submission.html:150 msgid "Rejudge selected submissions" msgstr "" -#: templates/problem/manage_submission.html:171 -#, fuzzy -#| msgid "Too many submissions" -msgid "Download selected submissions" -msgstr "Çok fazla çözüm gönderisi" +#: templates/problem/manage_submission.html:157 +msgid "Rescore Everything" +msgstr "" -#: templates/problem/manage_submission.html:177 -#, fuzzy, python-format -#| msgid "Are you sure you want to join?" -msgid "Are you sure you want to rescore %(count)d submissions?" -msgstr "Katılmak istediğine emin misin?" - -#: templates/problem/manage_submission.html:178 +#: templates/problem/manage_submission.html:163 msgid "Rescore all submissions" msgstr "" -#: templates/problem/problem.html:132 +#: templates/problem/problem.html:91 msgid "View as PDF" msgstr "PDF olarak göster" -#: templates/problem/problem.html:141 templates/problem/problem.html:151 -#: templates/problem/problem.html:156 +#: templates/problem/problem.html:101 templates/problem/problem.html:111 +#: templates/problem/problem.html:116 msgid "Submit solution" msgstr "Çözüm yolla" -#: templates/problem/problem.html:144 -#, python-format -msgid "%(counter)s submission left" -msgid_plural "%(counter)s submissions left" -msgstr[0] "%(counter)s gönderi kaldı" -msgstr[1] "%(counter)s gönderi kaldı" - -#: templates/problem/problem.html:152 +#: templates/problem/problem.html:112 msgid "0 submissions left" msgstr "0 çözüm kaldı" -#: templates/problem/problem.html:164 +#: templates/problem/problem.html:124 msgid "My submissions" msgstr "Benim çözümlerim" -#: templates/problem/problem.html:168 +#: templates/problem/problem.html:128 msgid "Best submissions" msgstr "En iyi çözümler" -#: templates/problem/problem.html:172 +#: templates/problem/problem.html:132 msgid "Read editorial" msgstr "Problem analizine git" -#: templates/problem/problem.html:177 +#: templates/problem/problem.html:137 msgid "Manage tickets" msgstr "Biletleri yönet" -#: templates/problem/problem.html:181 +#: templates/problem/problem.html:141 msgid "Edit problem" msgstr "Soruyu düzenle" -#: templates/problem/problem.html:183 +#: templates/problem/problem.html:143 msgid "Edit test data" msgstr "Test verisini düzenle" -#: templates/problem/problem.html:188 +#: templates/problem/problem.html:148 msgid "My tickets" msgstr "" -#: templates/problem/problem.html:196 +#: templates/problem/problem.html:156 msgid "Manage submissions" msgstr "" -#: templates/problem/problem.html:202 +#: templates/problem/problem.html:162 msgid "Clone problem" msgstr "Soruyu çoğalt" -#: templates/problem/problem.html:209 +#: templates/problem/problem.html:169 msgid "Points:" msgstr "Puan:" -#: templates/problem/problem.html:212 templates/problem/problem.html:214 +#: templates/problem/problem.html:172 templates/problem/problem.html:174 msgid "(partial)" msgstr "(kısmi)" -#: templates/problem/problem.html:219 +#: templates/problem/problem.html:179 msgid "Time limit:" msgstr "Zaman sınırı:" -#: templates/problem/problem.html:231 +#: templates/problem/problem.html:191 msgid "Memory limit:" msgstr "Bellek sınırı:" -#: templates/problem/problem.html:250 -msgid "Author:" -msgid_plural "Authors:" -msgstr[0] "Yazar" -msgstr[1] "Yazarlar" - -#: templates/problem/problem.html:265 -msgid "Problem type" -msgid_plural "Problem types" -msgstr[0] "Soru tipi" -msgstr[1] "Soru tipleri" - -#: templates/problem/problem.html:278 +#: templates/problem/problem.html:238 msgid "Allowed languages" msgstr "İzin verilen diller" -#: templates/problem/problem.html:286 -#, python-format -msgid "No %(lang)s judge online" -msgstr "%(lang)s için çevrimiçi judge yok" - -#: templates/problem/problem.html:297 -#, fuzzy -#| msgid "Judges" -msgid "Judge:" -msgid_plural "Judges:" -msgstr[0] "Judge'lar" -msgstr[1] "Judge'lar" - -#: templates/problem/problem.html:314 +#: templates/problem/problem.html:274 msgid "none available" msgstr "" -#: templates/problem/problem.html:326 -#, python-format -msgid "This problem has %(length)s clarification(s)" -msgstr "" - -#: templates/problem/problem.html:350 +#: templates/problem/problem.html:299 msgid "Request clarification" msgstr "Açıklama talebi" -#: templates/problem/problem.html:352 +#: templates/problem/problem.html:301 msgid "Report an issue" msgstr "Bir sorun bildir" -#: templates/problem/raw.html:64 +#: templates/problem/raw.html:62 msgid "Time Limit:" msgstr "" -#: templates/problem/raw.html:73 +#: templates/problem/raw.html:71 msgid "Memory Limit:" msgstr "" @@ -4290,81 +3785,39 @@ msgstr "Çözülmüş problemleri gizle" msgid "Show problem types" msgstr "Problem tiplerini göster" -#: templates/problem/search-form.html:32 -#, fuzzy -#| msgid "Read editorial" -msgid "Show editorial" -msgstr "Problem analizine git" - -#: templates/problem/search-form.html:48 templates/problem/search-form.html:50 -#: templates/submission/submission-list-tabs.html:4 +#: templates/problem/search-form.html:33 templates/problem/search-form.html:35 msgid "All" msgstr "Tümü" -#: templates/problem/search-form.html:62 +#: templates/problem/search-form.html:46 msgid "Problem types" msgstr "Problem tipleri" -#: templates/problem/search-form.html:73 +#: templates/problem/search-form.html:57 msgid "Point range" msgstr "Puan aralığı" -#: templates/problem/search-form.html:79 templates/submission/list.html:331 +#: templates/problem/search-form.html:63 templates/submission/list.html:331 #: templates/ticket/list.html:248 msgid "Go" msgstr "Git" -#: templates/problem/search-form.html:80 +#: templates/problem/search-form.html:64 msgid "Random" msgstr "Rastgele" -#: templates/problem/submit.html:117 -msgid "Your source code must contain at most 65536 characters." -msgstr "" - -#: templates/problem/submit.html:204 -#, python-format -msgid "" -"Warning! Your default language, %(default_language)s, is " -"unavailable for this problem and has been deselected." -msgstr "" -"Uyarı Varsayılan dilin, %(default_language)s, bu soru için " -"kullanılamıyor." - -#: templates/problem/submit.html:215 -#, python-format -msgid "" -"\n" -" You have %(left)s submission left\n" -" " -msgid_plural "" -"\n" -" You have %(left)s submissions left\n" -" " -msgstr[0] "" -"\n" -"Geriye %(left)s çözümün kaldı" -msgstr[1] "" -"\n" -"Geriye %(left)s çözümün kaldı" - -#: templates/problem/submit.html:224 +#: templates/problem/submit.html:212 msgid "You have 0 submissions left" msgstr "Geriye 0 çözümün kaldı" -#: templates/problem/submit.html:258 +#: templates/problem/submit.html:250 msgid "No judge is available for this problem." msgstr "Bu problem için herhangi bir judge mevcut değil." -#: templates/problem/submit.html:262 +#: templates/problem/submit.html:252 msgid "Submit!" msgstr "Gönder!" -#: templates/registration/activate.html:3 -#, python-format -msgid "%(key)s is an invalid activation key." -msgstr "Geçersiz aktivasyon kodu: %(key)s." - #: templates/registration/activation_complete.html:3 msgid "Your account has been successfully activated." msgstr "Hesabın başarıyla aktifleştirildi." @@ -4426,13 +3879,6 @@ msgstr "" "Eğer bir e-posta almadıysan, kaydolduğun e-posta adresini girdiğinden emin " "ol ve spam klasörünü kontrol et." -#: templates/registration/password_reset_email.txt:1 -#, python-format -msgid "" -"You're receiving this email because you requested a password reset for your " -"user account at %(site_name)s." -msgstr "Bu e-posta %(site_name)s üyeliğinin şifre sıfırlaması için gönderildi." - #: templates/registration/password_reset_email.txt:3 msgid "Please go to the following page and choose a new password:" msgstr "Lütfen bu sayfaya git ve yeni bir şifre seç:" @@ -4445,16 +3891,6 @@ msgstr "Unuttuysan diye, kullanıcı adın:" msgid "Thanks for using our site!" msgstr "Sitemizi kullandığın için teşekkür ederiz!" -#: templates/registration/password_reset_email.txt:11 -#, python-format -msgid "The %(site_name)s team" -msgstr "%(site_name)s takımı" - -#: templates/registration/password_reset_subject.txt:1 -#, python-format -msgid "Password reset on %(site_name)s" -msgstr "%(site_name)s şifre sıfırlaması" - #: templates/registration/profile_creation.html:36 #: templates/registration/username_select.html:7 msgid "Continue >" @@ -4493,20 +3929,19 @@ msgstr "Varsayılan dil" msgid "Affiliated organizations" msgstr "Organizasyon üyelikleri" -#: templates/registration/registration_form.html:195 -#: templates/user/edit-profile.html:128 +#: templates/registration/registration_form.html:192 msgid "Notify me about upcoming contests" msgstr "Gelecek yarışmalar hakkında beni bilgilendir" -#: templates/registration/registration_form.html:209 +#: templates/registration/registration_form.html:206 msgid "By registering, you agree to our" msgstr "Kayıt olmakla birlikte şunları kabul edersin:" -#: templates/registration/registration_form.html:210 +#: templates/registration/registration_form.html:207 msgid "Terms & Conditions" msgstr "Şartlar & Koşullar" -#: templates/registration/registration_form.html:213 +#: templates/registration/registration_form.html:210 msgid "Register!" msgstr "Kaydol!" @@ -4516,11 +3951,6 @@ msgstr "Kaydol!" msgid "Enter the 6-digit code generated by your app:" msgstr "" -#: templates/registration/totp_auth.html:41 -#, python-format -msgid "If you lost your authentication device, please contact us at %(email)s." -msgstr "" - #: templates/registration/totp_disable.html:38 msgid "" "To protect your account, you must first authenticate before you can disable " @@ -4539,6 +3969,10 @@ msgstr "" msgid "Or enter this code manually:" msgstr "" +#: templates/stats/base.html:9 templates/submission/list.html:339 +msgid "Statistics" +msgstr "İstatistikler" + #: templates/stats/language.html:11 msgid "Submission Statistics" msgstr "Çözüm İstatistikleri" @@ -4564,7 +3998,6 @@ msgid "Ping" msgstr "" #: templates/status/judge-status-table.html:8 -#: templates/user/import/index.html:104 msgid "Load" msgstr "Yükle" @@ -4580,7 +4013,6 @@ msgid "There are no judges available at this time." msgstr "Şu an mevcut hiçbir judge bulunmuyor." #: templates/status/language-list.html:33 templates/ticket/list.html:261 -#: templates/user/import/table_csv.html:3 msgid "ID" msgstr "" @@ -4588,22 +4020,6 @@ msgstr "" msgid "Runtime Info" msgstr "Dil sürümü bilgileri" -#: templates/status/status-tabs.html:4 -msgid "Judges" -msgstr "Judge'lar" - -#: templates/status/status-tabs.html:6 -msgid "Version Matrix" -msgstr "Sürüm Matrisi" - -#: templates/submission/internal-error-message.html:3 -#, python-format -msgid "" -"An internal error occurred while grading, and the %(SITE_NAME)s " -"administrators have been notified.
In the meantime, try resubmitting in " -"a few seconds." -msgstr "" - #: templates/submission/internal-error-message.html:8 msgid "An internal error occurred while grading." msgstr "Değerlendirme sırasında bir hata oluştu." @@ -4620,6 +4036,10 @@ msgstr "Duruma göre filtrele..." msgid "Filter by language..." msgstr "Dile göre filtrele..." +#: templates/submission/list.html:309 +msgid "Filter submissions" +msgstr "Çözümleri filtrele" + #: templates/submission/list.html:345 msgid "Total:" msgstr "" @@ -4676,78 +4096,77 @@ msgstr "Ön Test Sonuçları" msgid "Execution Results" msgstr "Sonuçlar" -#: templates/submission/status-testcases.html:34 +#: templates/submission/status-testcases.html:31 +msgid "Batch " +msgstr "Küme" + +#: templates/submission/status-testcases.html:43 msgid "Overall: " msgstr "" -#: templates/submission/status-testcases.html:48 +#: templates/submission/status-testcases.html:57 #, fuzzy #| msgid "Points:" msgid "Point: " msgstr "Puan:" -#: templates/submission/status-testcases.html:53 +#: templates/submission/status-testcases.html:62 #, fuzzy #| msgid "Time:" msgid "Time: " msgstr "Zaman:" -#: templates/submission/status-testcases.html:62 +#: templates/submission/status-testcases.html:71 #, fuzzy #| msgid "Memory" msgid "Memory: " msgstr "Bellek" -#: templates/submission/status-testcases.html:73 -msgid "Batch " -msgstr "Küme" - #: templates/submission/status-testcases.html:84 -#: templates/submission/status-testcases.html:113 +msgid "Case" +msgstr "Test" + +#: templates/submission/status-testcases.html:86 +msgid "Pretest" +msgstr "Ön test" + +#: templates/submission/status-testcases.html:88 +msgid "Test case" +msgstr "Test" + +#: templates/submission/status-testcases.html:99 #, fuzzy #| msgid "Points" msgid "Point" msgstr "Puanlar" -#: templates/submission/status-testcases.html:99 -msgid "Case" -msgstr "Test" - -#: templates/submission/status-testcases.html:101 -msgid "Pretest" -msgstr "Ön test" - -#: templates/submission/status-testcases.html:103 -msgid "Test case" -msgstr "Test" - -#: templates/submission/status-testcases.html:141 +#: templates/submission/status-testcases.html:121 #, fuzzy #| msgid "Input file" msgid "Input:" msgstr "Girdi dosyası" -#: templates/submission/status-testcases.html:145 +#: templates/submission/status-testcases.html:125 #, fuzzy #| msgid "Output file" msgid "Output:" msgstr "Çıktı dosyası" -#: templates/submission/status-testcases.html:149 +#: templates/submission/status-testcases.html:129 #, fuzzy #| msgid "Wrong Answer" msgid "Answer:" msgstr "Yanlış cevap" -#: templates/submission/status-testcases.html:154 +#: templates/submission/status-testcases.html:134 msgid "Judge feedback:" msgstr "" -#: templates/submission/status-testcases.html:175 +#: templates/submission/status-testcases.html:157 msgid "Passing pretests does not guarantee a full score on system tests." msgstr "Ön testleri geçmek sistem testlerinde tam puan almayı garantilemez." -#: templates/submission/status-testcases.html:178 +#: templates/submission/status-testcases.html:160 msgid "Submission aborted!" msgstr "Çözüm iptal edildi!" @@ -4759,24 +4178,11 @@ msgstr "Kaynağı görüntüle" msgid "Abort" msgstr "İptal et" -#: templates/submission/submission-list-tabs.html:6 -msgid "Mine" -msgstr "Çözümlerim" - -#: templates/submission/submission-list-tabs.html:9 -msgid "Best" -msgstr "En iyi" - -#: templates/submission/submission-list-tabs.html:12 -#, python-format -msgid "%(user)s's" -msgstr "%(user)s" - -#: templates/ticket/list.html:135 templates/ticket/ticket.html:273 +#: templates/ticket/list.html:135 templates/ticket/ticket.html:257 msgid "Reopened: " msgstr "Yeniden açıldı:" -#: templates/ticket/list.html:138 templates/ticket/ticket.html:274 +#: templates/ticket/list.html:138 templates/ticket/ticket.html:258 msgid "Closed: " msgstr "Kapatıldı:" @@ -4800,7 +4206,7 @@ msgstr "Sorumlu" msgid "Title" msgstr "Başlık" -#: templates/ticket/list.html:264 templates/ticket/ticket.html:369 +#: templates/ticket/list.html:264 templates/ticket/ticket.html:328 msgid "Assignees" msgstr "Sorumlular" @@ -4818,37 +4224,33 @@ msgstr "" "dikkate al. Bu form yardım istemek için değildir. Yardıma ihtiyacın varsa, " "sorunu yorumlarda sormayı deneyebilirsin." -#: templates/ticket/ticket.html:355 -msgid "Post" -msgstr "Gönderi" - -#: templates/ticket/ticket.html:363 +#: templates/ticket/ticket.html:322 msgid "Associated object" msgstr "İlişkili nesne" -#: templates/ticket/ticket.html:374 +#: templates/ticket/ticket.html:333 msgid "No one is assigned." msgstr "Kimse atanmamış." -#: templates/ticket/ticket.html:380 +#: templates/ticket/ticket.html:339 msgid "Close ticket" msgstr "Bileti kapat" -#: templates/ticket/ticket.html:382 +#: templates/ticket/ticket.html:341 msgid "Reopen ticket" msgstr "Bileti yeniden aç" -#: templates/ticket/ticket.html:386 +#: templates/ticket/ticket.html:345 msgid "Assignee notes" msgstr "Sorumlu notları" -#: templates/ticket/ticket.html:393 templates/widgets/select_all.html:4 +#: templates/ticket/ticket.html:352 templates/widgets/select_all.html:4 msgid "Nothing here." msgstr "Burada hiçbir şey yok :(" -#: templates/user/base-users-table.html:3 -msgid "Rank" -msgstr "Sıralama" +#: templates/ticket/ticket.html:385 +msgid "Post" +msgstr "Gönderi" #: templates/user/base-users.html:14 templates/user/base-users.html:69 msgid "Search by handle..." @@ -4894,210 +4296,50 @@ msgstr "Userscript" msgid "Update profile" msgstr "Profilini güncelle" -#: templates/user/import/index.html:31 -msgid "Upload CSV only" -msgstr "" - -#: templates/user/import/index.html:100 -#, fuzzy -#| msgid "user profile" -msgid "User File" -msgstr "Kullanıcı Profili" - -#: templates/user/import/index.html:102 -msgid "Sample" -msgstr "" - -#: templates/user/import/index.html:105 templates/user/user-list-tabs.html:8 -msgid "Import" -msgstr "" - -#: templates/user/import/table_csv.html:7 -msgid "School" -msgstr "" - -#: templates/user/pp-row.html:22 -#, python-format -msgid "" -"\n" -" weighted %(weight)s%%\n" -" " -msgstr "" -"\n" -"ağırlık %(weight)s%%" - -#: templates/user/pp-row.html:27 -#, python-format -msgid "%(pp).1fpp" -msgstr "%(pp).1fpp" - -#: templates/user/pp-row.html:29 -#, python-format -msgid "%(pp).0fpp" -msgstr "%(pp).0fpp" - -#: templates/user/user-about.html:23 -#, fuzzy, python-format -#| msgid "contest problems" -msgid "%(counter)s problem solved" -msgid_plural "%(counter)s problems solved" -msgstr[0] "yarışma problemleri" -msgstr[1] "yarışma problemleri" - -#: templates/user/user-about.html:35 -#, fuzzy -#| msgid "Total points:" -msgid "Total points" -msgstr "Toplam puan:" - -#: templates/user/user-about.html:45 -#, fuzzy -#| msgid "Rank by rating:" -msgid "Rank by rating" -msgstr "Derece sırası:" - -#: templates/user/user-about.html:52 -#, fuzzy -#| msgid "Rank by points:" -msgid "Rank by points" -msgstr "Puan sırası:" - -#: templates/user/user-about.html:64 +#: templates/user/user-about.html:14 msgid "From" msgstr "Organizasyonlar" -#: templates/user/user-about.html:75 +#: templates/user/user-about.html:25 msgid "Admin Notes" msgstr "" -#: templates/user/user-about.html:90 +#: templates/user/user-about.html:40 msgid "You have not shared any information." msgstr "Henüz hiçbir bilgi paylaşmadın." -#: templates/user/user-about.html:92 +#: templates/user/user-about.html:42 msgid "This user has not shared any information." msgstr "Bu kullanıcı henüz hiçbir bilgi paylaşmadı." -#: templates/user/user-about.html:101 -msgid "Awards" +#: templates/user/user-base.html:50 +msgid "Rank by points:" +msgstr "Puan sırası:" + +#: templates/user/user-base.html:53 +msgid "Total points:" +msgstr "Toplam puan:" + +#: templates/user/user-base.html:68 +msgid "Rank by rating:" +msgstr "Derece sırası:" + +#: templates/user/user-base.html:70 +msgid "Rating:" msgstr "" -#: templates/user/user-about.html:112 -#, fuzzy, python-format -#| msgctxt "contest problem" -#| msgid "%(problem)s in %(contest)s" -msgid "%(label)s (%(date)s)" -msgstr "%(problem)s - %(contest)s" - -#: templates/user/user-about.html:130 -#, fuzzy -#| msgid "Monday" -msgid "Mon" -msgstr "Pazartesi" - -#: templates/user/user-about.html:135 -#, fuzzy -#| msgid "Tuesday" -msgid "Tues" -msgstr "Salı" - -#: templates/user/user-about.html:140 -msgid "Wed" -msgstr "" - -#: templates/user/user-about.html:145 -#, fuzzy -#| msgid "Thursday" -msgid "Thurs" -msgstr "Perşembe " - -#: templates/user/user-about.html:150 -#, fuzzy -#| msgid "Friday" -msgid "Fri" -msgstr "Cuma" - -#: templates/user/user-about.html:155 -#, fuzzy -#| msgid "State" -msgid "Sat" -msgstr "Durum" - -#: templates/user/user-about.html:160 -#, fuzzy -#| msgid "Sunday" -msgid "Sun" -msgstr "Pazar" - -#: templates/user/user-about.html:169 -msgid "Less" -msgstr "" - -#: templates/user/user-about.html:175 -msgid "More" -msgstr "" - -#: templates/user/user-about.html:184 -#, fuzzy -#| msgid "History" -msgid "Rating History" -msgstr "Geçmiş" - -#: templates/user/user-about.html:255 -msgid "past year" -msgstr "" - -#: templates/user/user-about.html:272 -#, fuzzy -#| msgid "All submissions" -msgid "total submission(s)" -msgstr "Tüm çözümler" - -#: templates/user/user-about.html:276 -#, fuzzy -#| msgid "submission test case" -msgid "submissions in the last year" -msgstr "çözüm testi" - -#: templates/user/user-base.html:101 -msgid "Unfollow" -msgstr "" - -#: templates/user/user-base.html:104 -msgid "Follow" -msgstr "" - -#: templates/user/user-base.html:120 -#, fuzzy -#| msgid "" -#| "\n" -#| " You have %(left)s submission left\n" -#| " " -#| msgid_plural "" -#| "\n" -#| " You have %(left)s submissions left\n" -#| " " -msgid "Contests written" -msgstr "" -"\n" -"Geriye %(left)s çözümün kaldı" - -#: templates/user/user-base.html:124 +#: templates/user/user-base.html:71 msgid "Volatility:" msgstr "Değişkenlik:" -#: templates/user/user-base.html:128 +#: templates/user/user-base.html:72 msgid "Min. rating:" msgstr "En düşük derece:" -#: templates/user/user-base.html:132 +#: templates/user/user-base.html:73 msgid "Max rating:" msgstr "En yüksek derece:" -#: templates/user/user-list-tabs.html:5 -msgid "Friends" -msgstr "" - #: templates/user/user-problems.html:35 msgid "Points Breakdown" msgstr "Puan Dağılımı" @@ -5118,58 +4360,75 @@ msgstr "Yazılan Problemler" msgid "Hide problems I've solved" msgstr "Çözdüğüm soruları gizle" -#: templates/user/user-problems.html:93 -#, python-format -msgid "%(points).1f points" -msgstr "%(points).1f puan" - #: templates/user/user-problems.html:99 msgid "Score" msgstr "Puan" -#: templates/user/user-problems.html:110 -#, python-format -msgid "%(points)s / %(total)s" -msgstr "%(points)s/%(total)s" - -#: templates/user/user-tabs.html:7 -msgid "Impersonate" -msgstr "Yerine geç" - -#: templates/user/user-tabs.html:13 -msgid "Admin User" -msgstr "Yönetici kullanıcı" - -#: templates/user/user-tabs.html:16 -msgid "Admin Profile" -msgstr "Yönetici Profili" - #: templates/widgets/select_all.html:8 msgid "Check all" msgstr "Tümünü seç" -#, fuzzy -#~| msgid "%(counter)s submission left" -#~| msgid_plural "%(counter)s submissions left" -#~ msgid "%(cnt)d submission on %(date)s" -#~ msgid_plural "%(cnt)d submissions on %(date)s" -#~ msgstr[0] "%(counter)s gönderi kaldı" -#~ msgstr[1] "%(counter)s gönderi kaldı" +#~ msgid "Hello, %(username)s." +#~ msgstr "Merhaba, %(username)s." -#, fuzzy -#~| msgid "Admin" -#~ msgid "Admins" -#~ msgstr "Yönetici" +#~ msgid "" +#~ "\n" +#~ " posted on %(time)s\n" +#~ " " +#~ msgstr "" +#~ "\n" +#~ "%(time)s" -#, fuzzy -#~| msgid "Rescore the selected submissions" -#~ msgid "This will rescore %(count)d submissions." -#~ msgstr "Seçili çözümleri yeniden puanla" +#~ msgid "" +#~ "\n" +#~ " on %(time)s\n" +#~ " " +#~ msgstr "" +#~ "\n" +#~ "%(time)s" -#, fuzzy -#~| msgid "%(points)s / %(total)s" -#~ msgid "Point %(point)s / Case #%(case)s" -#~ msgstr "%(points)s/%(total)s" +#~ msgid "posted on {time}" +#~ msgstr "{time}" + +#~ msgid "commented on {time}" +#~ msgstr "{time} " + +#~ msgid "edit %(edits)s" +#~ msgstr "düzenleme %(edits)s" + +#~ msgid "List" +#~ msgstr "Liste" + +#~ msgid "Calendar" +#~ msgstr "Takvim" + +#~ msgid "Info" +#~ msgstr "Hakkında" + +#~ msgid "Rankings" +#~ msgstr "Sıralamalar" + +#~ msgid "Hidden Rankings" +#~ msgstr "Gizli Sıralamalar" + +#~ msgid "Stop spectating" +#~ msgstr "İzlemeyi bırak" + +#~ msgid "Participating virtually." +#~ msgstr "Sanal olarak katılınıyor. " + +#~ msgid "Contest is over." +#~ msgstr "Yarışma sona erdi" + +#~ msgid "" +#~ "%(time_limit)s window between %(start_time)s and " +#~ "%(end_time)s" +#~ msgstr "" +#~ " %(start_time)s ile %(end_time)s arasında, süre sınırı " +#~ "%(time_limit)s" + +#~ msgid "%(length)s long starting on %(start_time)s" +#~ msgstr "başlangıç %(start_time)s, yarışma süresi %(length)s" #~ msgid "Started on {time}" #~ msgstr "Başlangıç: {time}" @@ -5189,6 +4448,67 @@ msgstr "Tümünü seç" #~ msgid "Generator args" #~ msgstr "Generator değişkenleri" +#~ msgid "%(counter)s submission left" +#~ msgid_plural "%(counter)s submissions left" +#~ msgstr[0] "%(counter)s gönderi kaldı" +#~ msgstr[1] "%(counter)s gönderi kaldı" + +#~ msgid "Author:" +#~ msgid_plural "Authors:" +#~ msgstr[0] "Yazar" +#~ msgstr[1] "Yazarlar" + +#~ msgid "Problem type" +#~ msgid_plural "Problem types" +#~ msgstr[0] "Soru tipi" +#~ msgstr[1] "Soru tipleri" + +#~ msgid "No %(lang)s judge online" +#~ msgstr "%(lang)s için çevrimiçi judge yok" + +#~ msgid "" +#~ "Warning! Your default language, %(default_language)s, is " +#~ "unavailable for this problem and has been deselected." +#~ msgstr "" +#~ "Uyarı Varsayılan dilin, %(default_language)s, bu soru için " +#~ "kullanılamıyor." + +#~ msgid "" +#~ "\n" +#~ " You have %(left)s submission left\n" +#~ " " +#~ msgid_plural "" +#~ "\n" +#~ " You have %(left)s submissions left\n" +#~ " " +#~ msgstr[0] "" +#~ "\n" +#~ "Geriye %(left)s çözümün kaldı" +#~ msgstr[1] "" +#~ "\n" +#~ "Geriye %(left)s çözümün kaldı" + +#~ msgid "%(key)s is an invalid activation key." +#~ msgstr "Geçersiz aktivasyon kodu: %(key)s." + +#~ msgid "" +#~ "You're receiving this email because you requested a password reset for " +#~ "your user account at %(site_name)s." +#~ msgstr "" +#~ "Bu e-posta %(site_name)s üyeliğinin şifre sıfırlaması için gönderildi." + +#~ msgid "The %(site_name)s team" +#~ msgstr "%(site_name)s takımı" + +#~ msgid "Password reset on %(site_name)s" +#~ msgstr "%(site_name)s şifre sıfırlaması" + +#~ msgid "Judges" +#~ msgstr "Judge'lar" + +#~ msgid "Version Matrix" +#~ msgstr "Sürüm Matrisi" + #~ msgid "Case #%(case)s" #~ msgstr "Test #%(case)s" @@ -5200,3 +4520,44 @@ msgstr "Tümünü seç" #~ msgid "Final score:" #~ msgstr "Puan:" + +#~ msgid "Mine" +#~ msgstr "Çözümlerim" + +#~ msgid "Best" +#~ msgstr "En iyi" + +#~ msgid "%(user)s's" +#~ msgstr "%(user)s" + +#~ msgid "Rank" +#~ msgstr "Sıralama" + +#~ msgid "" +#~ "\n" +#~ " weighted %(weight)s%%\n" +#~ " " +#~ msgstr "" +#~ "\n" +#~ "ağırlık %(weight)s%%" + +#~ msgid "%(pp).1fpp" +#~ msgstr "%(pp).1fpp" + +#~ msgid "%(pp).0fpp" +#~ msgstr "%(pp).0fpp" + +#~ msgid "%(points).1f points" +#~ msgstr "%(points).1f puan" + +#~ msgid "%(points)s / %(total)s" +#~ msgstr "%(points)s/%(total)s" + +#~ msgid "Impersonate" +#~ msgstr "Yerine geç" + +#~ msgid "Admin User" +#~ msgstr "Yönetici kullanıcı" + +#~ msgid "Admin Profile" +#~ msgstr "Yönetici Profili" diff --git a/locale/tr/LC_MESSAGES/djangojs.po b/locale/tr/LC_MESSAGES/djangojs.po index c38421e..387b0b4 100644 --- a/locale/tr/LC_MESSAGES/djangojs.po +++ b/locale/tr/LC_MESSAGES/djangojs.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: dmoj\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-07-20 23:30+0700\n" +"POT-Creation-Date: 2019-10-01 23:12+0000\n" "PO-Revision-Date: 2019-11-11 22:06\n" "Last-Translator: Icyene\n" "Language-Team: Turkish\n" @@ -27,3 +27,4 @@ msgstr[1] "%d gün, %h:%m:%s" msgctxt "time format without day" msgid "%h:%m:%s" msgstr "%h:%m:%s" + diff --git a/locale/vi/LC_MESSAGES/django.po b/locale/vi/LC_MESSAGES/django.po index 60a2668..34dac33 100644 --- a/locale/vi/LC_MESSAGES/django.po +++ b/locale/vi/LC_MESSAGES/django.po @@ -1,9 +1,9 @@ msgid "" msgstr "" -"Project-Id-Version: lqdoj2\n" +"Project-Id-Version: lqdoj\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-10-03 02:46+0700\n" -"PO-Revision-Date: 2021-07-20 03:44\n" +"POT-Creation-Date: 2020-04-10 01:26-0500\n" +"PO-Revision-Date: 2020-04-09 02:21\n" "Last-Translator: Icyene\n" "Language-Team: Vietnamese\n" "Language: vi_VN\n" @@ -12,483 +12,449 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" -"X-Crowdin-Project: lqdoj2\n" +"X-Crowdin-Project: lqdoj\n" "X-Crowdin-Language: vi\n" "X-Crowdin-File: django.po\n" -"X-Crowdin-Project-ID: 466004\n" -"X-Crowdin-File-ID: 5\n" -#: chat_box/models.py:22 chat_box/models.py:84 -msgid "last seen" -msgstr "xem lần cuối" - -#: chat_box/models.py:55 chat_box/models.py:80 chat_box/models.py:96 -#: judge/admin/interface.py:151 judge/models/contest.py:722 -#: judge/models/contest.py:928 judge/models/course.py:129 -#: judge/models/profile.py:465 judge/models/profile.py:539 +#: chat_box/models.py:15 judge/admin/interface.py:107 +#: judge/models/contest.py:257 judge/models/contest.py:381 +#: judge/models/profile.py:191 msgid "user" msgstr "người dùng" -#: chat_box/models.py:57 judge/models/comment.py:45 -#: judge/models/notification.py:31 +#: chat_box/models.py:16 judge/models/comment.py:42 msgid "posted time" msgstr "thời gian đăng" -#: chat_box/models.py:59 judge/models/comment.py:50 +#: chat_box/models.py:17 judge/models/comment.py:46 msgid "body of comment" -msgstr "nội dung bình luận" +msgstr "bình luận" -#: chat_box/views.py:46 -msgid "LQDOJ Chat" +#: chat_box/views.py:29 +msgid "Chat Box" msgstr "" -#: chat_box/views.py:173 -msgid "Mute chat" -msgstr "" +#: dmoj/settings.py:349 +msgid "German" +msgstr "Tiếng Đức" -#: chat_box/views.py:450 -msgid "Recent" -msgstr "Gần đây" +#: dmoj/settings.py:350 +msgid "English" +msgstr "Tiếng Anh" -#: chat_box/views.py:454 templates/base.html:198 -#: templates/comments/content-list.html:72 -#: templates/contest/contest-list-tabs.html:6 -#: templates/contest/ranking-table.html:52 templates/course/left_sidebar.html:9 -#: templates/internal/problem/problem.html:63 -#: templates/organization/org-left-sidebar.html:12 -#: templates/organization/users-table.html:19 -#: templates/problem/left-sidebar.html:13 -#: templates/problem/problem-list-tabs.html:6 -#: templates/submission/info-base.html:12 templates/submission/list.html:394 -#: templates/submission/submission-list-tabs.html:15 -msgid "Admin" -msgstr "Admin" +#: dmoj/settings.py:351 +msgid "Spanish" +msgstr "Tiếng Tây Ban Nha" -#: dmoj/settings.py:366 +#: dmoj/settings.py:352 +msgid "French" +msgstr "Tiếng Pháp" + +#: dmoj/settings.py:353 +msgid "Croatian" +msgstr "Tiếng Croatia" + +#: dmoj/settings.py:354 +msgid "Hungarian" +msgstr "Tiếng Hung-ga-ri" + +#: dmoj/settings.py:355 +msgid "Japanese" +msgstr "Tiếng Nhật Bản" + +#: dmoj/settings.py:356 +msgid "Korean" +msgstr "Tiếng Hàn Quốc" + +#: dmoj/settings.py:357 +msgid "Brazilian Portuguese" +msgstr "Tiếng Braxin-Bồ Đào Nha" + +#: dmoj/settings.py:358 +msgid "Romanian" +msgstr "Tiếng Romania" + +#: dmoj/settings.py:359 +msgid "Russian" +msgstr "Tiếng Nga" + +#: dmoj/settings.py:360 +msgid "Serbian (Latin)" +msgstr "Tiếng Séc-bi (Latin)" + +#: dmoj/settings.py:361 +msgid "Turkish" +msgstr "Tiếng Thổ Nhĩ Kỳ" + +#: dmoj/settings.py:362 msgid "Vietnamese" msgstr "Tiếng Việt" -#: dmoj/settings.py:367 -msgid "English" +#: dmoj/settings.py:363 +msgid "Simplified Chinese" +msgstr "Tiếng Trung (Giản thể)" + +#: dmoj/settings.py:364 +msgid "Traditional Chinese" msgstr "" -#: dmoj/urls.py:107 -msgid "Activation key invalid" -msgstr "Mã kích hoạt không hợp lệ" - -#: dmoj/urls.py:112 -msgid "Register" -msgstr "Đăng ký" - -#: dmoj/urls.py:119 -msgid "Registration Completed" -msgstr "Đăng ký hoàn thành" - -#: dmoj/urls.py:127 -msgid "Registration not allowed" -msgstr "Đăng ký không thành công" - -#: dmoj/urls.py:135 +#: dmoj/urls.py:57 msgid "Login" msgstr "Đăng nhập" -#: dmoj/urls.py:221 templates/base.html:120 -#: templates/course/left_sidebar.html:2 -#: templates/organization/org-left-sidebar.html:2 +#: dmoj/urls.py:105 templates/base.html:190 msgid "Home" msgstr "Trang chủ" -#: judge/admin/comments.py:57 +#: judge/admin/comments.py:40 #, python-format msgid "%d comment successfully hidden." msgid_plural "%d comments successfully hidden." -msgstr[0] "Đã ẩn %d bình luận." +msgstr[0] "%d bình luận đã được ẩn." -#: judge/admin/comments.py:64 +#: judge/admin/comments.py:43 msgid "Hide comments" msgstr "Ẩn bình luận" -#: judge/admin/comments.py:71 +#: judge/admin/comments.py:47 #, python-format msgid "%d comment successfully unhidden." msgid_plural "%d comments successfully unhidden." -msgstr[0] "Không ẩn được %d bình luận." +msgstr[0] "%d bình luận đã được hiện lại." -#: judge/admin/comments.py:78 +#: judge/admin/comments.py:50 msgid "Unhide comments" msgstr "Hiện bình luận" -#: judge/admin/contest.py:45 +#: judge/admin/comments.py:58 +msgid "Associated page" +msgstr "Trang liên quan" + +#: judge/admin/contest.py:28 msgid "Included contests" -msgstr "" +msgstr "Các cuộc thi" -#: judge/admin/contest.py:87 judge/admin/volunteer.py:54 -#: templates/contest/clarification.html:42 templates/contest/contest.html:121 -#: templates/contest/moss.html:41 templates/internal/left-sidebar.html:2 -#: templates/internal/problem/problem.html:41 templates/problem/list.html:17 -#: templates/problem/list.html:34 templates/problem/list.html:153 -#: templates/user/user-problems.html:56 templates/user/user-problems.html:98 +#: judge/admin/contest.py:64 templates/contest/contest.html:83 +#: templates/contest/moss.html:43 templates/problem/list.html:206 +#: templates/problem/list.html:221 templates/user/user-problems.html:56 +#: templates/user/user-problems.html:98 msgid "Problem" -msgstr "Bài tập" +msgstr "Đề bài" -#: judge/admin/contest.py:183 templates/base.html:213 -#: templates/user/user-tabs.html:12 +#: judge/admin/contest.py:112 msgid "Settings" msgstr "Cài đặt" -#: judge/admin/contest.py:198 +#: judge/admin/contest.py:114 msgid "Scheduling" -msgstr "" +msgstr "Kế hoạch" -#: judge/admin/contest.py:202 +#: judge/admin/contest.py:115 msgid "Details" msgstr "Chi tiết" -#: judge/admin/contest.py:214 templates/contest/macros.html:83 -#: templates/contest/macros.html:93 +#: judge/admin/contest.py:116 msgid "Format" -msgstr "Thể thức" +msgstr "Định dạng" -#: judge/admin/contest.py:218 templates/contest/ranking-table.html:5 -#: templates/profile-table.html:14 templates/profile-table.html:37 -#: templates/user/user-about.html:15 templates/user/user-about.html:44 +#: judge/admin/contest.py:117 templates/contest/ranking-table.html:5 msgid "Rating" -msgstr "" +msgstr "Rating" -#: judge/admin/contest.py:230 +#: judge/admin/contest.py:118 msgid "Access" msgstr "Truy cập" -#: judge/admin/contest.py:240 judge/admin/problem.py:233 +#: judge/admin/contest.py:120 judge/admin/problem.py:131 msgid "Justice" -msgstr "Xử phạt" +msgstr "Luật" -#: judge/admin/contest.py:368 +#: judge/admin/contest.py:158 #, python-format msgid "%d contest successfully marked as visible." msgid_plural "%d contests successfully marked as visible." -msgstr[0] "%d kỳ thi đã được đánh dấu hiển thị." +msgstr[0] "%d kỳ thi đã được hiển thị." -#: judge/admin/contest.py:375 +#: judge/admin/contest.py:161 msgid "Mark contests as visible" -msgstr "Đánh dấu hiển thị các kỳ thi" +msgstr "Hiển thị các kỳ thị" -#: judge/admin/contest.py:386 +#: judge/admin/contest.py:165 #, python-format msgid "%d contest successfully marked as hidden." msgid_plural "%d contests successfully marked as hidden." -msgstr[0] "%d kỳ thi đã được đánh dấu ẩn." +msgstr[0] "%d kỳ thi đã được ẩn." -#: judge/admin/contest.py:393 +#: judge/admin/contest.py:168 msgid "Mark contests as hidden" -msgstr "Ẩn các kỳ thi" +msgstr "Ẩn kỳ thi" -#: judge/admin/contest.py:414 judge/admin/submission.py:241 +#: judge/admin/contest.py:182 judge/admin/submission.py:164 #, python-format msgid "%d submission was successfully scheduled for rejudging." msgid_plural "%d submissions were successfully scheduled for rejudging." -msgstr[0] "%d bài nộp đã được lên lịch thành công để chấm lại." +msgstr[0] "%d bài nộp đã được lên lịch để chấm lại." -#: judge/admin/contest.py:522 +#: judge/admin/contest.py:256 #, python-format msgid "%d participation recalculated." msgid_plural "%d participations recalculated." -msgstr[0] "%d thí sinh đã được tính điểm lại." +msgstr[0] "%d số người tham gia đã được tính lại." -#: judge/admin/contest.py:529 +#: judge/admin/contest.py:259 msgid "Recalculate results" -msgstr "Tính toán lại kết quả" +msgstr "Kết quả tính lại" -#: judge/admin/contest.py:534 judge/admin/organization.py:98 +#: judge/admin/contest.py:263 judge/admin/organization.py:65 msgid "username" -msgstr "tên đăng nhập" +msgstr "người dùng" -#: judge/admin/contest.py:540 templates/base.html:253 +#: judge/admin/contest.py:268 templates/base.html:260 msgid "virtual" -msgstr "ảo" +msgstr "thử" -#: judge/admin/interface.py:35 judge/models/interface.py:51 +#: judge/admin/interface.py:28 judge/models/interface.py:46 msgid "link path" -msgstr "đường dẫn" +msgstr "đường dẫn liên kết" -#: judge/admin/interface.py:95 templates/course/lesson.html:10 +#: judge/admin/interface.py:62 msgid "Content" msgstr "Nội dung" -#: judge/admin/interface.py:96 +#: judge/admin/interface.py:63 msgid "Summary" -msgstr "Tổng kết" +msgstr "Tóm tắt" -#: judge/admin/interface.py:218 +#: judge/admin/interface.py:148 msgid "object" -msgstr "" +msgstr "đối tượng" -#: judge/admin/interface.py:228 -msgid "Diff" -msgstr "" - -#: judge/admin/interface.py:233 -msgid "diff" -msgstr "" - -#: judge/admin/organization.py:60 judge/admin/problem.py:290 -#: judge/admin/profile.py:128 +#: judge/admin/organization.py:34 judge/admin/problem.py:171 +#: judge/admin/profile.py:80 msgid "View on site" -msgstr "Xem trên trang" +msgstr "Xem trên trang web" -#: judge/admin/problem.py:56 +#: judge/admin/problem.py:28 msgid "Describe the changes you made (optional)" -msgstr "Mô tả các thay đổi (tùy chọn)" +msgstr "Mô tả những thay đổi đã thực hiện (tùy chọn)" -#: judge/admin/problem.py:66 -#, fuzzy -#| msgid "Problem with code already exists." -msgid "A problem with this code already exists." -msgstr "Mã bài đã tồn tại." - -#: judge/admin/problem.py:122 -msgid "Memory unit" -msgstr "Đơn vị bộ nhớ" - -#: judge/admin/problem.py:226 +#: judge/admin/problem.py:126 msgid "Social Media" -msgstr "Mạng Xã Hội" +msgstr "Mạng xã hội" -#: judge/admin/problem.py:229 +#: judge/admin/problem.py:127 msgid "Taxonomy" -msgstr "" +msgstr "Phân loại" -#: judge/admin/problem.py:230 judge/admin/problem.py:463 -#: judge/views/course.py:494 judge/views/course.py:579 -#: templates/contest/contest.html:122 -#: templates/contest/contests_summary.html:41 -#: templates/course/contest_list.html:21 templates/problem/data.html:535 -#: templates/problem/list.html:22 templates/problem/list.html:48 -#: templates/profile-table.html:31 templates/profile-table.html:41 -#: templates/user/base-users-table.html:10 templates/user/user-about.html:36 -#: templates/user/user-about.html:50 templates/user/user-problems.html:58 +#: judge/admin/problem.py:128 templates/contest/contest.html:84 +#: templates/problem/data.html:449 templates/problem/list.html:211 +#: templates/problem/list.html:232 templates/user/base-users-table.html:10 +#: templates/user/user-problems.html:58 msgid "Points" msgstr "Điểm" -#: judge/admin/problem.py:231 +#: judge/admin/problem.py:129 msgid "Limits" msgstr "Giới hạn" -#: judge/admin/problem.py:232 judge/admin/submission.py:351 -#: templates/base.html:164 templates/stats/tab.html:4 -#: templates/submission/list.html:345 +#: judge/admin/problem.py:130 judge/admin/submission.py:232 +#: templates/stats/base.html:14 templates/submission/list.html:322 msgid "Language" msgstr "Ngôn ngữ" -#: judge/admin/problem.py:234 +#: judge/admin/problem.py:132 msgid "History" msgstr "Lịch sử" -#: judge/admin/problem.py:286 templates/problem/list-base.html:93 +#: judge/admin/problem.py:168 msgid "Authors" -msgstr "Các tác giả" +msgstr "Tác giả" -#: judge/admin/problem.py:307 +#: judge/admin/problem.py:183 #, python-format msgid "%d problem successfully marked as public." msgid_plural "%d problems successfully marked as public." -msgstr[0] "%d bài tập đã được đánh dấu công khai." +msgstr[0] "%d bài toán đã được public." -#: judge/admin/problem.py:314 +#: judge/admin/problem.py:187 msgid "Mark problems as public" -msgstr "Công khai bài tập" +msgstr "Public đề bài" -#: judge/admin/problem.py:323 +#: judge/admin/problem.py:193 #, python-format msgid "%d problem successfully marked as private." msgid_plural "%d problems successfully marked as private." -msgstr[0] "%d bài tập đã được đánh dấu riêng tư." +msgstr[0] "%d bài toán đã được unpublic." -#: judge/admin/problem.py:330 +#: judge/admin/problem.py:197 msgid "Mark problems as private" -msgstr "Đánh dấu các bài tập là riêng tư" +msgstr "Unpublic đề bài" -#: judge/admin/problem.py:457 judge/admin/submission.py:314 -#: templates/problem/list.html:18 templates/problem/list.html:37 -msgid "Problem code" -msgstr "Mã bài" - -#: judge/admin/problem.py:469 judge/admin/submission.py:320 -msgid "Problem name" -msgstr "Tên bài" - -#: judge/admin/problem.py:475 -#, fuzzy -#| msgid "contest rating" -msgid "Voter rating" -msgstr "rating kỳ thi" - -#: judge/admin/problem.py:481 -#, fuzzy -#| msgid "Total points" -msgid "Voter point" -msgstr "Tổng điểm" - -#: judge/admin/problem.py:487 -msgid "Vote" -msgstr "" - -#: judge/admin/profile.py:47 +#: judge/admin/profile.py:34 msgid "timezone" msgstr "múi giờ" -#: judge/admin/profile.py:137 judge/admin/submission.py:327 -#: templates/notification/list.html:9 +#: judge/admin/profile.py:86 judge/admin/submission.py:211 #: templates/organization/requests/log.html:9 -#: templates/organization/requests/pending.html:19 -#: templates/ticket/list.html:265 +#: templates/organization/requests/pending.html:12 +#: templates/ticket/list.html:263 msgid "User" -msgstr "Thành viên" +msgstr "Người dùng" -#: judge/admin/profile.py:143 templates/registration/registration_form.html:40 -#: templates/user/edit-profile.html:123 templates/user/import/table_csv.html:8 +#: judge/admin/profile.py:91 templates/registration/registration_form.html:145 msgid "Email" msgstr "Email" -#: judge/admin/profile.py:149 judge/views/register.py:36 -#: templates/registration/registration_form.html:68 -#: templates/user/edit-profile.html:147 +#: judge/admin/profile.py:96 judge/views/register.py:29 +#: templates/registration/registration_form.html:173 +#: templates/user/edit-profile.html:106 msgid "Timezone" msgstr "Múi giờ" -#: judge/admin/profile.py:155 +#: judge/admin/profile.py:101 msgid "date joined" msgstr "ngày tham gia" -#: judge/admin/profile.py:165 +#: judge/admin/profile.py:108 #, python-format msgid "%d user have scores recalculated." msgid_plural "%d users have scores recalculated." -msgstr[0] "%d người dùng đã được tính điểm lại." +msgstr[0] "%d người dùng đã được tính lại điểm." -#: judge/admin/profile.py:172 +#: judge/admin/profile.py:111 msgid "Recalculate scores" -msgstr "Tính điểm lại" - -#: judge/admin/profile.py:179 judge/admin/profile.py:186 -msgid "Username can only contain letters, digits, and underscores." -msgstr "Tên đăng nhập phải chứa ký tự, chữ số, hoặc dấu gạch dưới" +msgstr "Tính lại điểm" #: judge/admin/runtime.py:19 msgid "Disallowed problems" -msgstr "Các bài tập không được cho phép" +msgstr "Bài tập không được cho phép" #: judge/admin/runtime.py:22 msgid "These problems are NOT allowed to be submitted in this language" -msgstr "Các bài này không cho phép sử dụng ngôn ngữ này" +msgstr "Bài tập không hỗ trợ ngôn ngữ này" -#: judge/admin/runtime.py:117 templates/problem/list.html:155 +#: judge/admin/runtime.py:83 msgid "Description" -msgstr "Mô tả" +msgstr "Miêu tả" -#: judge/admin/runtime.py:119 +#: judge/admin/runtime.py:84 msgid "Information" msgstr "Thông tin" -#: judge/admin/runtime.py:122 +#: judge/admin/runtime.py:85 msgid "Capabilities" msgstr "Khả năng" -#: judge/admin/submission.py:31 judge/admin/submission.py:53 -#: judge/admin/submission.py:338 +#: judge/admin/submission.py:23 judge/admin/submission.py:42 +#: judge/admin/submission.py:221 msgid "None" -msgstr "None" +msgstr "Không" -#: judge/admin/submission.py:32 +#: judge/admin/submission.py:23 msgid "Not done" -msgstr "Chưa xong" +msgstr "Chưa hoàn thành" -#: judge/admin/submission.py:33 +#: judge/admin/submission.py:23 msgid "Exceptional" -msgstr "Đặc biệt" +msgstr "Lỗi" -#: judge/admin/submission.py:53 +#: judge/admin/submission.py:42 msgid "Unaccepted" -msgstr "" +msgstr "Không chấp nhận" -#: judge/admin/submission.py:104 +#: judge/admin/submission.py:89 #, python-format msgctxt "contest problem" msgid "%(problem)s in %(contest)s" msgstr "%(problem)s trong %(contest)s" -#: judge/admin/submission.py:213 judge/admin/submission.py:254 +#: judge/admin/submission.py:149 judge/admin/submission.py:171 msgid "You do not have the permission to rejudge submissions." msgstr "Bạn không có quyền chấm lại bài." -#: judge/admin/submission.py:225 +#: judge/admin/submission.py:155 msgid "You do not have the permission to rejudge THAT many submissions." -msgstr "Bạn không có quyền chấm lại nhiều bài nộp như vậy." +msgstr "Bạn không có quyền chấm lại QUÁ NHIỀU bài nộp." -#: judge/admin/submission.py:248 +#: judge/admin/submission.py:167 msgid "Rejudge the selected submissions" -msgstr "Chấm lại các bài nộp đã chọn" +msgstr "Chấm lại các bài đã chọn" -#: judge/admin/submission.py:302 judge/views/problem_manage.py:218 +#: judge/admin/submission.py:193 judge/views/problem_manage.py:128 #, python-format msgid "%d submission were successfully rescored." msgid_plural "%d submissions were successfully rescored." -msgstr[0] "%d bài nộp đã được tính điểm lại." +msgstr[0] "%d bài đã được tính điểm lại." -#: judge/admin/submission.py:309 +#: judge/admin/submission.py:196 msgid "Rescore the selected submissions" -msgstr "Tính điểm lại cái bài nộp" +msgstr "Tính điểm lại các bài đã chọn" -#: judge/admin/submission.py:332 templates/contest/list.html:175 -#: templates/contest/list.html:217 templates/contest/list.html:254 -#: templates/contest/list.html:288 templates/notification/list.html:12 -#: templates/organization/requests/log.html:10 -#: templates/organization/requests/pending.html:20 -#: templates/problem/list.html:154 -#: templates/submission/status-testcases.html:139 -#: templates/submission/status-testcases.html:141 -#: templates/user/user-bookmarks.html:84 +#: judge/admin/submission.py:200 +msgid "Problem code" +msgstr "Mã bài tập" + +#: judge/admin/submission.py:205 +msgid "Problem name" +msgstr "Tên bài" + +#: judge/admin/submission.py:215 templates/organization/requests/log.html:10 +#: templates/organization/requests/pending.html:13 +#: templates/submission/status-testcases.html:105 +#: templates/submission/status-testcases.html:107 msgid "Time" msgstr "Thời gian" -#: judge/admin/submission.py:340 +#: judge/admin/submission.py:223 #, python-format msgid "%d KB" msgstr "%d KB" -#: judge/admin/submission.py:342 +#: judge/admin/submission.py:225 #, python-format msgid "%.2f MB" -msgstr "" +msgstr "%.2f MB" -#: judge/admin/submission.py:345 templates/submission/status-testcases.html:146 +#: judge/admin/submission.py:227 templates/submission/status-testcases.html:112 msgid "Memory" msgstr "Bộ nhớ" -#: judge/admin/taxon.py:11 judge/admin/taxon.py:37 +#: judge/admin/taxon.py:11 judge/admin/taxon.py:34 msgid "Included problems" -msgstr "" +msgstr "Các bài tập" #: judge/admin/taxon.py:14 msgid "These problems are included in this group of problems" -msgstr "Các bài tập trong nhóm này" +msgstr "Các bài tập này đã được bao gồm trong nhóm bài" -#: judge/admin/taxon.py:40 +#: judge/admin/taxon.py:37 msgid "These problems are included in this type of problems" -msgstr "Các bài tập dạng này" - -#: judge/admin/volunteer.py:60 templates/internal/problem/votes.html:17 -#: templates/problem/list.html:20 templates/problem/list.html:44 -msgid "Types" -msgstr "Dạng" +msgstr "Các bài chọn đã được bao gồm trong loại bài này" #: judge/apps.py:8 msgid "Online Judge" -msgstr "" +msgstr "Online Judge" + +#: judge/comments.py:41 +msgid "Comment body" +msgstr "Bình luận" + +#: judge/comments.py:47 judge/views/ticket.py:46 +msgid "Your part is silent, little toad." +msgstr "Bạn đã bị câm lặng." + +#: judge/comments.py:50 templates/comments/list.html:131 +msgid "" +"You need to have solved at least one problem before your voice can be heard." +msgstr "Bạn cần giải được ít nhất một bài tập trước khi bình luận." + +#: judge/comments.py:92 +msgid "Posted comment" +msgstr "Đăng bình luận" #: judge/contest_format/atcoder.py:19 msgid "AtCoder" -msgstr "" +msgstr "AtCoder" #: judge/contest_format/default.py:18 msgid "Default" @@ -496,1994 +462,1507 @@ msgstr "Mặc định" #: judge/contest_format/ecoo.py:19 msgid "ECOO" -msgstr "" +msgstr "ECOO" -#: judge/contest_format/icpc.py:19 -msgid "ICPC" -msgstr "" - -#: judge/contest_format/ioi.py:20 +#: judge/contest_format/ioi.py:19 msgid "IOI" -msgstr "" +msgstr "IOI" -#: judge/contest_format/new_ioi.py:11 -msgid "New IOI" -msgstr "IOI mới" +#: judge/forms.py:27 +msgid "Subscribe to contest updates" +msgstr "Đăng ký để nhận cập nhật về các cuộc thi" -#: judge/contest_format/ultimate.py:12 -msgid "Ultimate" -msgstr "" +#: judge/forms.py:28 +msgid "Enable experimental features" +msgstr "Bật các tính năng đang thử nghiệm" -#: judge/custom_translations.py:8 -#, python-format -msgid "" -"This password is too short. It must contain at least %(min_length)d " -"character." -msgid_plural "" -"This password is too short. It must contain at least %(min_length)d " -"characters." -msgstr[0] "Mật khẩu phải chứa ít nhất %(min_length)d ký tự." - -#: judge/custom_translations.py:13 -#, python-format -msgid "Your password must contain at least %(min_length)d character." -msgid_plural "Your password must contain at least %(min_length)d characters." -msgstr[0] "Mật khẩu phải chứa ít nhất %(min_length)d ký tự." - -#: judge/custom_translations.py:17 -msgid "The two password fields didn’t match." -msgstr "Mật khẩu xác nhận không khớp." - -#: judge/custom_translations.py:18 -msgid "Your password can’t be entirely numeric." -msgstr "Mật khẩu không được toàn chữ số." - -#: judge/custom_translations.py:20 -msgid "Bug Report" -msgstr "Báo cáo lỗi" - -#: judge/custom_translations.py:21 judge/views/course.py:164 -#: templates/course/list.html:8 -msgid "Courses" -msgstr "Khóa học" - -#: judge/forms.py:120 judge/forms.py:220 -msgid "File size exceeds the maximum allowed limit of 5MB." -msgstr "File tải lên không được quá 5MB." - -#: judge/forms.py:151 -msgid "Any judge" -msgstr "" - -#: judge/forms.py:368 -msgid "Enter usernames separating by space" -msgstr "Nhập các tên đăng nhập, cách nhau bởi dấu cách" - -#: judge/forms.py:369 judge/views/stats.py:166 templates/stats/site.html:27 -msgid "New users" -msgstr "Thành viên mới" - -#: judge/forms.py:386 +#: judge/forms.py:57 judge/views/organization.py:127 #, python-brace-format -msgid "These usernames don't exist: {usernames}" -msgstr "Các tên đăng nhập này không tồn tại: {usernames}" +msgid "You may not be part of more than {count} public organizations." +msgstr "Bạn không thể là thành viên của nhiều hơn {count} tổ chức công khai." -#: judge/forms.py:445 -msgid "Username/Email" -msgstr "Tên đăng nhập / Email" +#: judge/forms.py:107 judge/views/register.py:26 +#: templates/registration/registration_form.html:139 +#: templates/user/base-users-table.html:5 +msgid "Username" +msgstr "Tên truy cập" -#: judge/forms.py:447 judge/views/email.py:22 -#: templates/registration/registration_form.html:46 -#: templates/registration/registration_form.html:60 -#: templates/user/edit-profile.html:115 templates/user/import/table_csv.html:5 +#: judge/forms.py:108 templates/registration/registration_form.html:151 +#: templates/registration/registration_form.html:165 msgid "Password" msgstr "Mật khẩu" -#: judge/forms.py:473 +#: judge/forms.py:130 msgid "Two Factor Authentication tokens must be 6 decimal digits." -msgstr "Two Factor Authentication phải chứa 6 chữ số." +msgstr "Mã xác thực hai lớp phải có 6 chữ số thập phân." -#: judge/forms.py:486 templates/registration/totp_auth.html:32 +#: judge/forms.py:139 templates/registration/totp_auth.html:32 msgid "Invalid Two Factor Authentication token." -msgstr "Token Two Factor Authentication không hợp lệ." +msgstr "Mã xác thực hai lớp không hợp lệ." -#: judge/forms.py:493 judge/models/problem.py:133 +#: judge/forms.py:143 judge/models/problem.py:97 msgid "Problem code must be ^[a-z0-9]+$" -msgstr "Mã bài phải có dạng ^[a-z0-9]+$" +msgstr "Mã đầu bài chỉ bao gồm ^[a-z0-9] + $" -#: judge/forms.py:500 +#: judge/forms.py:148 msgid "Problem with code already exists." -msgstr "Mã bài đã tồn tại." +msgstr "Mã bài tập đã tồn tại." -#: judge/forms.py:507 judge/models/contest.py:103 +#: judge/forms.py:153 judge/models/contest.py:52 msgid "Contest id must be ^[a-z0-9]+$" -msgstr "Mã kỳ thi phải có dạng ^[a-z0-9]+$" +msgstr "Id cuộc thi phải bao gồm ^[a-z0-9] + $" -#: judge/forms.py:514 templates/contest/clone.html:47 -#: templates/contest/search-form.html:12 templates/problem/search-form.html:39 -msgid "Group" -msgstr "Nhóm" - -#: judge/forms.py:522 +#: judge/forms.py:158 msgid "Contest with key already exists." msgstr "Mã kỳ thi đã tồn tại." -#: judge/forms.py:530 -msgid "Group doesn't exist." -msgstr "Nhóm không tồn tại." - -#: judge/forms.py:532 -msgid "You don't have permission in this group." -msgstr "Bạn không có quyền trong nhóm này." - -#: judge/forms.py:582 -msgid "This problem is duplicated." -msgstr "Bài này bị lặp" - -#: judge/jinja2/datetime.py:26 templates/blog/blog.html:28 +#: judge/jinja2/datetime.py:26 templates/blog/content.html:27 #: templates/blog/dashboard.html:21 msgid "N j, Y, g:i a" -msgstr "g:i a j b, Y" +msgstr "N j, Y, g:i a" -#: judge/jinja2/datetime.py:26 templates/chat/message.html:13 -#: templates/comments/content-list.html:28 +#: judge/jinja2/datetime.py:26 #, python-brace-format msgid "{time}" msgstr "{time}" -#: judge/middleware.py:135 -msgid "No permission" -msgstr "Không có quyền truy cập" +#: judge/jinja2/datetime.py:26 +#, python-brace-format +msgid "on {time}" +msgstr "vào lúc {time}" -#: judge/middleware.py:136 -msgid "You need to join this group first" -msgstr "Bạn phải là thành viên của nhóm." +#: judge/models/choices.py:59 +msgid "Leave as LaTeX" +msgstr "Giữ nguyên dạng LaTeX" -#: judge/middleware.py:146 judge/middleware.py:147 -msgid "No such group" -msgstr "Nhóm không tồn tại" +#: judge/models/choices.py:60 +msgid "SVG with PNG fallback" +msgstr "SVG với PNG dự phòng" -#: judge/models/bookmark.py:17 judge/models/comment.py:164 -#: judge/models/pagevote.py:16 -msgid "associated page" -msgstr "trang tương ứng" +#: judge/models/choices.py:61 +msgid "MathML only" +msgstr "Chỉ dùng dạng MathML" -#: judge/models/bookmark.py:20 judge/models/comment.py:49 -#: judge/models/pagevote.py:19 judge/models/problem.py:744 -msgid "votes" -msgstr "bình chọn" +#: judge/models/choices.py:62 +msgid "MathJax with SVG/PNG fallback" +msgstr "MathJax với SVG/PNG dự phòng" -#: judge/models/bookmark.py:30 -msgid "bookmark" -msgstr "Lưu" +#: judge/models/choices.py:63 +msgid "Detect best quality" +msgstr "Tự chọn chất lượng tốt nhất" -#: judge/models/bookmark.py:31 -msgid "bookmarks" -msgstr "Lưu" +#: judge/models/comment.py:25 +msgid "Page code must be ^[pcs]:[a-z0-9]+$|^b:\\d+$" +msgstr "Mã trang phải bao gồm ^[pcs]:[a-z0-9]+$|^b:\\d+$" -#: judge/models/bookmark.py:52 -msgid "make bookmark" -msgstr "Lưu" - -#: judge/models/bookmark.py:53 -msgid "make bookmarks" -msgstr "Lưu" - -#: judge/models/comment.py:44 +#: judge/models/comment.py:41 msgid "commenter" msgstr "người bình luận" -#: judge/models/comment.py:51 +#: judge/models/comment.py:43 judge/models/comment.py:176 +msgid "associated page" +msgstr "trang liên kết" + +#: judge/models/comment.py:45 +msgid "votes" +msgstr "đánh giá" + +#: judge/models/comment.py:47 msgid "hide the comment" msgstr "ẩn bình luận" -#: judge/models/comment.py:54 +#: judge/models/comment.py:48 msgid "parent" -msgstr "" +msgstr "bình luận cha" -#: judge/models/comment.py:65 +#: judge/models/comment.py:53 msgid "comment" msgstr "bình luận" -#: judge/models/comment.py:66 +#: judge/models/comment.py:54 msgid "comments" -msgstr "" +msgstr "các bình luận" -#: judge/models/comment.py:125 -msgid "Editorial for " -msgstr "Hướng dẫn cho {0}" +#: judge/models/comment.py:136 judge/models/problem.py:406 +#, python-format +msgid "Editorial for %s" +msgstr "Đáp án cho %s" -#: judge/models/comment.py:157 +#: judge/models/comment.py:171 msgid "comment vote" -msgstr "" +msgstr "đánh giá bình luận" -#: judge/models/comment.py:158 +#: judge/models/comment.py:172 msgid "comment votes" -msgstr "" +msgstr "đánh giá bình luận" -#: judge/models/comment.py:169 +#: judge/models/comment.py:181 msgid "Override comment lock" -msgstr "" +msgstr "Ghi đè khóa nhận xét" -#: judge/models/contest.py:50 +#: judge/models/contest.py:22 msgid "Invalid colour." -msgstr "" +msgstr "Màu sắc không hợp lệ." -#: judge/models/contest.py:54 +#: judge/models/contest.py:24 msgid "tag name" -msgstr "" +msgstr "tên thẻ" -#: judge/models/contest.py:58 +#: judge/models/contest.py:25 msgid "Lowercase letters and hyphens only." -msgstr "" +msgstr "Chỉ bao gồm chữ thường và dấu gạch ngang." -#: judge/models/contest.py:63 +#: judge/models/contest.py:26 msgid "tag colour" -msgstr "" +msgstr "màu thẻ" -#: judge/models/contest.py:65 +#: judge/models/contest.py:27 msgid "tag description" -msgstr "" +msgstr "mô tả thẻ" -#: judge/models/contest.py:86 +#: judge/models/contest.py:46 msgid "contest tag" -msgstr "" +msgstr "thẻ kỳ thi" -#: judge/models/contest.py:87 judge/models/contest.py:267 +#: judge/models/contest.py:47 judge/models/contest.py:101 msgid "contest tags" -msgstr "nhãn kỳ thi" +msgstr "thẻ kỳ thi" -#: judge/models/contest.py:95 -msgid "Visible" -msgstr "Hiển thị" - -#: judge/models/contest.py:96 -msgid "Hidden for duration of contest" -msgstr "Ẩn trong thời gian kỳ thi" - -#: judge/models/contest.py:97 -msgid "Hidden for duration of participation" -msgstr "Ẩn trong thời gian tham gia" - -#: judge/models/contest.py:101 +#: judge/models/contest.py:51 msgid "contest id" -msgstr "ID kỳ thi" +msgstr "id kỳ thi" -#: judge/models/contest.py:106 +#: judge/models/contest.py:53 msgid "contest name" msgstr "tên kỳ thi" -#: judge/models/contest.py:110 judge/models/interface.py:80 -#: judge/models/problem.py:694 -msgid "authors" -msgstr "tác giả" +#: judge/models/contest.py:54 +msgid "These people will be able to edit the contest." +msgstr "Những người này sẽ có thể chỉnh sửa kỳ thi." -#: judge/models/contest.py:111 -msgid "These users will be able to edit the contest." -msgstr "Những người dùng này có quyền chỉnh sửa kỳ thi." - -#: judge/models/contest.py:116 judge/models/problem.py:157 -msgid "curators" -msgstr "quản lý" - -#: judge/models/contest.py:118 -msgid "" -"These users will be able to edit the contest, but will not be listed as " -"authors." -msgstr "Những người dùng này là tác giả và có quyền chỉnh sửa kỳ thi." - -#: judge/models/contest.py:126 judge/models/problem.py:167 -msgid "testers" -msgstr "" - -#: judge/models/contest.py:128 -msgid "These users will be able to view the contest, but not edit it." -msgstr "" -"Những người dùng này có thể thấy kỳ thi nhưng không có quyền chỉnh sửa." - -#: judge/models/contest.py:133 judge/models/runtime.py:217 +#: judge/models/contest.py:56 judge/models/runtime.py:133 msgid "description" msgstr "mô tả" -#: judge/models/contest.py:135 judge/models/problem.py:610 -#: judge/models/runtime.py:222 +#: judge/models/contest.py:57 judge/models/problem.py:353 +#: judge/models/runtime.py:135 msgid "problems" -msgstr "bài tập" +msgstr "đề bài" -#: judge/models/contest.py:137 judge/models/contest.py:727 +#: judge/models/contest.py:58 judge/models/contest.py:258 msgid "start time" msgstr "thời gian bắt đầu" -#: judge/models/contest.py:138 +#: judge/models/contest.py:59 msgid "end time" msgstr "thời gian kết thúc" -#: judge/models/contest.py:140 judge/models/problem.py:186 -#: judge/models/problem.py:645 +#: judge/models/contest.py:60 judge/models/problem.py:118 +#: judge/models/problem.py:377 msgid "time limit" msgstr "giới hạn thời gian" -#: judge/models/contest.py:144 -msgid "" -"Format hh:mm:ss. For example, if you want a 2-hour contest, enter 02:00:00" -msgstr "" -"Định dạng hh:mm:ss (giờ:phút:giây). Ví dụ, nếu muốn tạo kỳ thi dài 2h, hãy " -"nhập 02:00:00" - -#: judge/models/contest.py:148 -msgid "freeze after" -msgstr "đóng băng sau" - -#: judge/models/contest.py:152 -msgid "" -"Format hh:mm:ss. For example, if you want to freeze contest after 2 hours, " -"enter 02:00:00" -msgstr "" -"Định dạng hh:mm:ss (giờ:phút:giây). Ví dụ, nếu muốn đóng băng kỳ thi sau 2h, " -"hãy nhập 02:00:00" - -#: judge/models/contest.py:156 judge/models/course.py:27 -#: judge/models/course.py:167 judge/models/problem.py:225 +#: judge/models/contest.py:61 judge/models/problem.py:136 msgid "publicly visible" msgstr "công khai" -#: judge/models/contest.py:159 +#: judge/models/contest.py:62 msgid "" "Should be set even for organization-private contests, where it determines " "whether the contest is visible to members of the specified organizations." msgstr "" -"Đánh dấu ngay cả với các kỳ thi riêng tư của nhóm, quyết định việc kỳ thi có " -"được hiển thị với các thành viên hay không." +"Nên được đặt ngay cả đối với các kỳ thi riêng, chỉ các thành viên trong nhóm " +"mới thấy được kỳ thi này." -#: judge/models/contest.py:165 +#: judge/models/contest.py:65 msgid "contest rated" -msgstr "kỳ thi được xếp hạng" +msgstr "kỳ thi có tính rating" -#: judge/models/contest.py:166 +#: judge/models/contest.py:65 msgid "Whether this contest can be rated." -msgstr "Quyết định kỳ thi có được xếp hạng không." +msgstr "Liệu kỳ thi có được tính rating." -#: judge/models/contest.py:170 -msgid "scoreboard visibility" -msgstr "khả năng hiển thị của bảng điểm" +#: judge/models/contest.py:67 +msgid "hide scoreboard" +msgstr "ẩn bảng điểm" -#: judge/models/contest.py:173 -msgid "Scoreboard visibility through the duration of the contest" -msgstr "Khả năng hiển thị của bảng điểm trong thời gian kỳ thi" +#: judge/models/contest.py:68 +msgid "" +"Whether the scoreboard should remain hidden for the duration of the contest." +msgstr "Liệu bảng điểm có được ẩn trong thời gian thi." -#: judge/models/contest.py:178 -msgid "view contest scoreboard" -msgstr "xem bảng điểm kỳ thi" - -#: judge/models/contest.py:181 -msgid "These users will be able to view the scoreboard." -msgstr "Những người dùng này được phép xem bảng điểm." - -#: judge/models/contest.py:184 -msgid "public scoreboard" -msgstr "công khai bảng điểm" - -#: judge/models/contest.py:185 -msgid "Ranking page is public even for private contests." -msgstr "Trang xếp hạng được công khai, kể cả cho kỳ thi riêng tư." - -#: judge/models/contest.py:189 +#: judge/models/contest.py:71 msgid "no comments" -msgstr "không bình luận" +msgstr "không có bình luận" -#: judge/models/contest.py:190 +#: judge/models/contest.py:72 msgid "Use clarification system instead of comments." -msgstr "Dùng hệ thống thông báo thay vì bình luận." +msgstr "Dùng hệ thống hỏi đáp thay vì bình luận." -#: judge/models/contest.py:195 +#: judge/models/contest.py:74 msgid "Rating floor for contest" -msgstr "Cận dưới rating được xếp hạng trong kỳ thi" +msgstr "Rating thấp nhất được tham gia kỳ thi" -#: judge/models/contest.py:201 +#: judge/models/contest.py:76 msgid "Rating ceiling for contest" -msgstr "Cận trên rating được xếp hạng trong kỳ thi" +msgstr "Rating cao nhất được tham gia kỳ thi" -#: judge/models/contest.py:206 +#: judge/models/contest.py:78 msgid "rate all" -msgstr "xếp hạng tất cả" +msgstr "tính rating cho tất cả" -#: judge/models/contest.py:207 +#: judge/models/contest.py:78 msgid "Rate all users who joined." -msgstr "Xếp hạng tất cả người dùng đã tham gia (kể cả không nộp)." +msgstr "Tính rating cho tất cả thí sinh." -#: judge/models/contest.py:212 +#: judge/models/contest.py:79 msgid "exclude from ratings" -msgstr "không xếp hạng" +msgstr "không tính rating" -#: judge/models/contest.py:217 +#: judge/models/contest.py:81 msgid "private to specific users" -msgstr "riêng tư với các người dùng này" +msgstr "chỉ riêng tư cho các thành viên cụ thể" -#: judge/models/contest.py:222 +#: judge/models/contest.py:82 msgid "private contestants" -msgstr "thí sinh riêng tư" +msgstr "thí sinh thi riêng" -#: judge/models/contest.py:223 +#: judge/models/contest.py:83 msgid "If private, only these users may see the contest" -msgstr "Nếu riêng tư, chỉ những người dùng này mới thấy kỳ thi" +msgstr "Nếu riêng tư, chỉ những người dùng này có thể xem kỳ thi" -#: judge/models/contest.py:227 +#: judge/models/contest.py:85 msgid "hide problem tags" -msgstr "ẩn nhãn kỳ thi" +msgstr "ẩn thẻ bài tập" -#: judge/models/contest.py:228 +#: judge/models/contest.py:86 msgid "Whether problem tags should be hidden by default." -msgstr "" -"Quyết định việc nhãn bài tập (DP, Tham lam, ...) được ẩn trong kỳ thi không." +msgstr "Các thẻ bài tập có được ẩn mặc định?" -#: judge/models/contest.py:232 +#: judge/models/contest.py:88 msgid "run pretests only" -msgstr "chỉ chạy pretests" +msgstr "chỉ chạy pretest" -#: judge/models/contest.py:234 +#: judge/models/contest.py:89 msgid "" "Whether judges should grade pretests only, versus all testcases. Commonly " "set during a contest, then unset prior to rejudging user submissions when " "the contest ends." msgstr "" -"Quyết định việc các máy chấm chỉ chấm pretests thay vì tất cả các test. Sau " -"kỳ thi, hãy bỏ đánh dấu ô này và chấm lại tất cả các bài." +"Chỉ chấm pretest. Chọn trong lúc thi, sau đó bỏ chọn để chấm lại ở cuối cuộc " +"thi." -#: judge/models/contest.py:241 judge/models/interface.py:97 -#: judge/models/problem.py:285 +#: judge/models/contest.py:93 judge/models/problem.py:157 msgid "private to organizations" -msgstr "riêng tư với các tổ chức" +msgstr "dành riêng cho nhóm" -#: judge/models/contest.py:246 judge/models/course.py:33 -#: judge/models/interface.py:93 judge/models/problem.py:281 -#: judge/models/profile.py:167 +#: judge/models/contest.py:94 judge/models/problem.py:155 +#: judge/models/profile.py:77 msgid "organizations" -msgstr "tổ chức" +msgstr "nhóm" -#: judge/models/contest.py:247 +#: judge/models/contest.py:95 msgid "If private, only these organizations may see the contest" -msgstr "Nếu riêng tư, chỉ những tổ chức này thấy được kỳ thi" +msgstr "Nếu là riêng tư, chỉ các nhóm này mới có thể thấy kỳ thi" -#: judge/models/contest.py:250 -#, fuzzy -#| msgid "contest name" -msgid "contest in course" -msgstr "tên kỳ thi" - -#: judge/models/contest.py:254 judge/models/problem.py:256 +#: judge/models/contest.py:96 judge/models/problem.py:145 msgid "OpenGraph image" -msgstr "Hình ảnh OpenGraph" +msgstr "Ảnh OpenGraph" -#: judge/models/contest.py:257 +#: judge/models/contest.py:97 judge/models/profile.py:48 msgid "Logo override image" -msgstr "Hình ảnh ghi đè logo" +msgstr "Ghi đè logo" -#: judge/models/contest.py:262 +#: judge/models/contest.py:99 msgid "" "This image will replace the default site logo for users inside the contest." -msgstr "Ảnh này sẽ thay thế cho logo mặc định trong kỳ thi." +msgstr "Ảnh này sẽ thay thế logo mặc định trong kỳ thi." -#: judge/models/contest.py:270 +#: judge/models/contest.py:102 msgid "the amount of live participants" -msgstr "số lượng thí sinh thi trực tiếp" +msgstr "số lượng người tham gia" -#: judge/models/contest.py:274 +#: judge/models/contest.py:103 msgid "contest summary" -msgstr "tổng kết kỳ thi" +msgstr "tổng kết cuộc thi" -#: judge/models/contest.py:276 judge/models/problem.py:262 +#: judge/models/contest.py:104 judge/models/problem.py:147 msgid "Plain-text, shown in meta description tag, e.g. for social media." -msgstr "" +msgstr "Văn bản thuần, hiển thị trong thẻ meta, ví dụ như cho mạng xã hội." -#: judge/models/contest.py:280 judge/models/profile.py:109 +#: judge/models/contest.py:105 judge/models/profile.py:47 msgid "access code" -msgstr "mật khẩu truy cập" +msgstr "mã truy cập" -#: judge/models/contest.py:285 +#: judge/models/contest.py:106 msgid "" "An optional code to prompt contestants before they are allowed to join the " "contest. Leave it blank to disable." -msgstr "" -"Mật khẩu truy cập cho các thí sinh muốn tham gia kỳ thi. Để trống nếu không " -"dùng." +msgstr "Mật khẩu để cho phép tham gia kỳ thi. Để trống nếu không dùng." -#: judge/models/contest.py:291 judge/models/problem.py:244 +#: judge/models/contest.py:108 judge/models/problem.py:141 msgid "personae non gratae" -msgstr "Chặn tham gia" +msgstr "cá nhân - không tính điểm" -#: judge/models/contest.py:293 +#: judge/models/contest.py:109 msgid "Bans the selected users from joining this contest." -msgstr "Cấm những người dùng được chọn tham gia kỳ thi." +msgstr "Cấm những người dùng đã chọn tham gia kỳ thi này." -#: judge/models/contest.py:296 +#: judge/models/contest.py:110 msgid "contest format" -msgstr "format kỳ thi" +msgstr "định dạng kỳ thi" -#: judge/models/contest.py:300 +#: judge/models/contest.py:111 msgid "The contest format module to use." -msgstr "Format kỳ thi sử dụng." +msgstr "Loại kỳ thi." -#: judge/models/contest.py:303 +#: judge/models/contest.py:112 msgid "contest format configuration" -msgstr "Tùy chỉnh format kỳ thi" +msgstr "cấu hình format kỳ thi" -#: judge/models/contest.py:307 +#: judge/models/contest.py:113 msgid "" "A JSON object to serve as the configuration for the chosen contest format " "module. Leave empty to use None. Exact format depends on the contest format " "selected." msgstr "" +"File JSON để cấu hình loại kỳ thi. Để trống nếu không dùng. Định dạng chính " +"xác phụ thuộc vào định dạng kỳ thi được chọn." -#: judge/models/contest.py:320 -msgid "precision points" -msgstr "Hiển thị điểm" - -#: judge/models/contest.py:323 -msgid "Number of digits to round points to." -msgstr "Số chữ số thập phân trên bảng điểm." - -#: judge/models/contest.py:326 -msgid "rate limit" -msgstr "giới hạn bài nộp" - -#: judge/models/contest.py:331 -msgid "" -"Maximum number of submissions per minute. Leave empty if you don't want rate " -"limit." -msgstr "Số bài nộp tối đa mỗi phút. Để trống nếu không muốn giới hạn." - -#: judge/models/contest.py:362 -msgid "End time must be after start time" -msgstr "Thời gian kết thúc phải sau thời gian bắt đầu" - -#: judge/models/contest.py:681 +#: judge/models/contest.py:239 msgid "See private contests" -msgstr "" +msgstr "Xem các kỳ thi riêng tư" -#: judge/models/contest.py:682 +#: judge/models/contest.py:240 msgid "Edit own contests" -msgstr "" +msgstr "Sửa các kỳ thi của bạn" -#: judge/models/contest.py:683 +#: judge/models/contest.py:241 msgid "Edit all contests" -msgstr "" +msgstr "Chỉnh sửa tất cả các kỳ thi" -#: judge/models/contest.py:684 +#: judge/models/contest.py:242 msgid "Clone contest" -msgstr "" +msgstr "Nhân bản kỳ thi" -#: judge/models/contest.py:685 templates/contest/moss.html:72 +#: judge/models/contest.py:243 templates/contest/moss.html:74 msgid "MOSS contest" -msgstr "" +msgstr "Kỳ thi dùng MOSS" -#: judge/models/contest.py:686 +#: judge/models/contest.py:244 msgid "Rate contests" -msgstr "" +msgstr "Đánh gia các kỳ thi" -#: judge/models/contest.py:687 +#: judge/models/contest.py:245 msgid "Contest access codes" -msgstr "" +msgstr "Mã truy cập kỳ thi" -#: judge/models/contest.py:688 +#: judge/models/contest.py:246 msgid "Create private contests" -msgstr "" +msgstr "Tạo kỳ thi riêng tư" -#: judge/models/contest.py:689 -msgid "Change contest visibility" -msgstr "" - -#: judge/models/contest.py:690 -msgid "Edit contest problem label script" -msgstr "Cách hiển thị thứ tự bài tập" - -#: judge/models/contest.py:692 judge/models/contest.py:853 -#: judge/models/contest.py:931 judge/models/contest.py:961 -#: judge/models/contest.py:1040 judge/models/submission.py:116 +#: judge/models/contest.py:248 judge/models/contest.py:345 +#: judge/models/contest.py:382 judge/models/contest.py:404 +#: judge/models/submission.py:83 msgid "contest" msgstr "kỳ thi" -#: judge/models/contest.py:693 +#: judge/models/contest.py:249 msgid "contests" msgstr "kỳ thi" -#: judge/models/contest.py:716 +#: judge/models/contest.py:256 msgid "associated contest" -msgstr "" +msgstr "kỳ thi liên quan" -#: judge/models/contest.py:729 judge/models/course.py:185 +#: judge/models/contest.py:259 msgid "score" msgstr "điểm" -#: judge/models/contest.py:730 +#: judge/models/contest.py:260 msgid "cumulative time" msgstr "tổng thời gian" -#: judge/models/contest.py:732 +#: judge/models/contest.py:261 msgid "is disqualified" -msgstr "đã bị loại" +msgstr "" -#: judge/models/contest.py:734 +#: judge/models/contest.py:262 msgid "Whether this participation is disqualified." -msgstr "Quyết định thí sinh có bị loại không." - -#: judge/models/contest.py:736 -msgid "tie-breaking field" msgstr "" -#: judge/models/contest.py:738 +#: judge/models/contest.py:263 msgid "virtual participation id" -msgstr "id lần tham gia ảo" +msgstr "mã số tham gia thử" -#: judge/models/contest.py:740 +#: judge/models/contest.py:264 +#, fuzzy +#| msgid "0 means non-virtual, otherwise the n-th virtual participation" msgid "0 means non-virtual, otherwise the n-th virtual participation." -msgstr "0 nghĩa là tham gia chính thức, ngược lại là lần tham gia ảo thứ n." +msgstr "0 có nghĩa là thi thật, n là lần tham gia thử thứ n" -#: judge/models/contest.py:743 +#: judge/models/contest.py:265 msgid "contest format specific data" -msgstr "" +msgstr "định dạng dữ liệu cụ thể của kỳ thi" -#: judge/models/contest.py:746 -msgid "same as format_data, but including frozen results" -msgstr "" - -#: judge/models/contest.py:750 -msgid "final score" -msgstr "điểm" - -#: judge/models/contest.py:752 -msgid "final cumulative time" -msgstr "tổng thời gian" - -#: judge/models/contest.py:828 +#: judge/models/contest.py:331 #, python-format msgid "%s spectating in %s" -msgstr "%s đang theo dõi trong %s" +msgstr "%s quan sát trong %s" -#: judge/models/contest.py:833 +#: judge/models/contest.py:333 #, python-format msgid "%s in %s, v%d" msgstr "%s trong %s, v%d" -#: judge/models/contest.py:838 +#: judge/models/contest.py:334 #, python-format msgid "%s in %s" msgstr "%s trong %s" -#: judge/models/contest.py:841 +#: judge/models/contest.py:337 msgid "contest participation" -msgstr "lần tham gia kỳ thi" +msgstr "thí sinh" -#: judge/models/contest.py:842 +#: judge/models/contest.py:338 msgid "contest participations" -msgstr "lần tham gia kỳ thi" +msgstr "thí sinh" -#: judge/models/contest.py:849 judge/models/contest.py:902 -#: judge/models/contest.py:964 judge/models/problem.py:609 -#: judge/models/problem.py:616 judge/models/problem.py:637 -#: judge/models/problem.py:668 judge/models/problem_data.py:50 +#: judge/models/contest.py:344 judge/models/contest.py:366 +#: judge/models/contest.py:405 judge/models/problem.py:352 +#: judge/models/problem.py:357 judge/models/problem.py:375 +#: judge/models/problem_data.py:38 msgid "problem" msgstr "bài tập" -#: judge/models/contest.py:857 judge/models/contest.py:914 -#: judge/models/course.py:166 judge/models/course.py:199 -#: judge/models/problem.py:209 +#: judge/models/contest.py:346 judge/models/contest.py:370 +#: judge/models/problem.py:129 msgid "points" msgstr "điểm" -#: judge/models/contest.py:858 +#: judge/models/contest.py:347 msgid "partial" msgstr "thành phần" -#: judge/models/contest.py:859 judge/models/contest.py:916 +#: judge/models/contest.py:348 judge/models/contest.py:371 msgid "is pretested" -msgstr "dùng pretest" +msgstr "là pretest" -#: judge/models/contest.py:860 judge/models/course.py:165 -#: judge/models/course.py:184 judge/models/course.py:198 -#: judge/models/interface.py:48 +#: judge/models/contest.py:349 judge/models/interface.py:43 msgid "order" msgstr "thứ tự" -#: judge/models/contest.py:862 +#: judge/models/contest.py:350 +msgid "0 to not show testcases, 1 to show" +msgstr "0 để ẩn test đối với thí sinh, 1 để hiện" + +#: judge/models/contest.py:351 msgid "visible testcases" -msgstr "hiển thị test" +msgstr "hiển thị tests" -#: judge/models/contest.py:867 +#: judge/models/contest.py:352 msgid "Maximum number of submissions for this problem, or 0 for no limit." -msgstr "Số lần nộp tối đa, đặt là 0 nếu không có giới hạn." +msgstr "Số lượng tối đa lần nộp cho bài này, hoặc 0 nếu không giới hạn." -#: judge/models/contest.py:869 -msgid "max submissions" -msgstr "số lần nộp tối đa" - -#: judge/models/contest.py:872 +#: judge/models/contest.py:354 msgid "Why include a problem you can't submit to?" -msgstr "" +msgstr "Tại sao lại có một bài mà bạn không thể nộp?" -#: judge/models/contest.py:876 -#, fuzzy -#| msgid "Only for format new IOI. Separated by commas, e.g: 2, 3" -msgid "Separated by commas, e.g: 2, 3" -msgstr "" -"Chỉ dùng với format IOI mới. Các sub cách nhau bởi dấu phẩy. Ví dụ: 2, 3" - -#: judge/models/contest.py:877 -msgid "hidden subtasks" -msgstr "Đóng băng subtasks" - -#: judge/models/contest.py:889 +#: judge/models/contest.py:359 msgid "contest problem" -msgstr "bài trong kỳ thi" +msgstr "đề bài kỳ thi" -#: judge/models/contest.py:890 +#: judge/models/contest.py:360 msgid "contest problems" -msgstr "bài trong kỳ thi" +msgstr "đề bài kỳ thi" -#: judge/models/contest.py:896 judge/models/submission.py:274 +#: judge/models/contest.py:364 judge/models/submission.py:181 msgid "submission" msgstr "bài nộp" -#: judge/models/contest.py:909 judge/models/contest.py:935 +#: judge/models/contest.py:368 judge/models/contest.py:383 msgid "participation" -msgstr "lần tham gia" +msgstr "tham gia" -#: judge/models/contest.py:917 +#: judge/models/contest.py:372 msgid "Whether this submission was ran only on pretests." -msgstr "Quyết định bài nộp chỉ được chạy trên pretest không." +msgstr "Bài nộp này chỉ chạy với pretest." -#: judge/models/contest.py:922 +#: judge/models/contest.py:376 msgid "contest submission" msgstr "bài nộp kỳ thi" -#: judge/models/contest.py:923 +#: judge/models/contest.py:377 msgid "contest submissions" msgstr "bài nộp kỳ thi" -#: judge/models/contest.py:939 +#: judge/models/contest.py:385 msgid "rank" -msgstr "rank" +msgstr "xếp hạng" -#: judge/models/contest.py:940 +#: judge/models/contest.py:386 msgid "rating" msgstr "rating" -#: judge/models/contest.py:941 -msgid "raw rating" -msgstr "rating thật" +#: judge/models/contest.py:387 +msgid "volatility" +msgstr "biến động" -#: judge/models/contest.py:942 -msgid "contest performance" -msgstr "" - -#: judge/models/contest.py:943 +#: judge/models/contest.py:388 msgid "last rated" -msgstr "lần cuối được xếp hạng" +msgstr "lần thi cuối" -#: judge/models/contest.py:947 +#: judge/models/contest.py:392 msgid "contest rating" msgstr "rating kỳ thi" -#: judge/models/contest.py:948 +#: judge/models/contest.py:393 msgid "contest ratings" msgstr "rating kỳ thi" -#: judge/models/contest.py:972 +#: judge/models/contest.py:412 msgid "contest moss result" -msgstr "kết quả MOSS kỳ thi" +msgstr "kết quả kỳ thi moss" -#: judge/models/contest.py:973 +#: judge/models/contest.py:413 msgid "contest moss results" -msgstr "kết quả MOSS kỳ thi" +msgstr "kết quả kỳ thi moss" -#: judge/models/contest.py:978 -msgid "clarified problem" -msgstr "" - -#: judge/models/contest.py:980 -msgid "clarification body" -msgstr "" - -#: judge/models/contest.py:982 -msgid "clarification timestamp" -msgstr "" - -#: judge/models/contest.py:1001 -msgid "contests summary" -msgstr "tổng kết kỳ thi" - -#: judge/models/contest.py:1002 -msgid "contests summaries" -msgstr "tổng kết kỳ thi" - -#: judge/models/contest.py:1013 judge/models/contest.py:1020 -msgid "official contest category" -msgstr "loại kỳ thi chính thức" - -#: judge/models/contest.py:1021 -msgid "official contest categories" -msgstr "các loại kỳ thi chính thức" - -#: judge/models/contest.py:1026 judge/models/contest.py:1033 -msgid "official contest location" -msgstr "địa điểm kỳ thi chính thức" - -#: judge/models/contest.py:1034 -msgid "official contest locations" -msgstr "các địa điểm kỳ thi chính thức" - -#: judge/models/contest.py:1046 -msgid "contest category" -msgstr "loại kỳ thi" - -#: judge/models/contest.py:1049 -msgid "year" -msgstr "năm" - -#: judge/models/contest.py:1052 -msgid "contest location" -msgstr "địa điểm kỳ thi" - -#: judge/models/contest.py:1057 -msgid "official contest" -msgstr "kỳ thi chính thức" - -#: judge/models/contest.py:1058 -msgid "official contests" -msgstr "các kỳ thi chính thức" - -#: judge/models/course.py:12 templates/course/grades.html:88 -#: templates/course/grades_lesson.html:88 -msgid "Student" -msgstr "Học sinh" - -#: judge/models/course.py:13 -msgid "Assistant" -msgstr "Trợ giảng" - -#: judge/models/course.py:14 -msgid "Teacher" -msgstr "Giáo viên" - -#: judge/models/course.py:23 -msgid "course name" -msgstr "tên khóa học" - -#: judge/models/course.py:25 -msgid "course description" -msgstr "Mô tả khóa học" - -#: judge/models/course.py:34 -msgid "If private, only these organizations may see the course" -msgstr "Nếu riêng tư, chỉ những tổ chức này thấy được khóa học" - -#: judge/models/course.py:38 -msgid "course slug" -msgstr "url khóa học" - -#: judge/models/course.py:39 -msgid "Course name shown in URL" -msgstr "Tên được hiển thị trong đường dẫn" - -#: judge/models/course.py:42 judge/models/profile.py:65 -msgid "Only alphanumeric and hyphens" -msgstr "Chỉ chứa chữ cái và dấu gạch ngang (-)" - -#: judge/models/course.py:46 -msgid "public registration" -msgstr "Cho phép đăng ký" - -#: judge/models/course.py:50 -msgid "course image" -msgstr "hình ảnh khóa học" - -#: judge/models/course.py:123 judge/models/course.py:159 -msgid "course" -msgstr "khóa học" - -#: judge/models/course.py:163 -#, fuzzy -#| msgid "message title" -msgid "lesson title" -msgstr "tiêu đề tin nhắn" - -#: judge/models/course.py:164 -#, fuzzy -#| msgid "post content" -msgid "lesson content" -msgstr "đăng nội dung" - -#: judge/models/interface.py:29 +#: judge/models/interface.py:24 msgid "configuration item" -msgstr "" +msgstr "cấu hình" -#: judge/models/interface.py:30 +#: judge/models/interface.py:25 msgid "miscellaneous configuration" -msgstr "" +msgstr "cấu hình khác" -#: judge/models/interface.py:42 +#: judge/models/interface.py:37 msgid "navigation item" msgstr "mục điều hướng" -#: judge/models/interface.py:43 +#: judge/models/interface.py:38 msgid "navigation bar" msgstr "thanh điều hướng" -#: judge/models/interface.py:49 +#: judge/models/interface.py:44 msgid "identifier" -msgstr "" +msgstr "định danh" -#: judge/models/interface.py:50 +#: judge/models/interface.py:45 msgid "label" msgstr "nhãn" -#: judge/models/interface.py:53 +#: judge/models/interface.py:47 msgid "highlight regex" -msgstr "" +msgstr "regex" -#: judge/models/interface.py:57 +#: judge/models/interface.py:48 msgid "parent item" msgstr "mục cha" -#: judge/models/interface.py:79 +#: judge/models/interface.py:66 msgid "post title" -msgstr "tiêu đề bài đăng" +msgstr "tiêu đề bài viết" -#: judge/models/interface.py:81 +#: judge/models/interface.py:67 judge/models/problem.py:395 +msgid "authors" +msgstr "tác giả" + +#: judge/models/interface.py:68 msgid "slug" -msgstr "slug" +msgstr "" -#: judge/models/interface.py:82 judge/models/problem.py:692 +#: judge/models/interface.py:69 judge/models/problem.py:393 msgid "public visibility" -msgstr "khả năng hiển thị công khai" +msgstr "hiển thị công khai" -#: judge/models/interface.py:83 +#: judge/models/interface.py:70 msgid "sticky" -msgstr "nổi lên đầu" +msgstr "dán lên đầu trang" -#: judge/models/interface.py:84 +#: judge/models/interface.py:71 msgid "publish after" -msgstr "đăng sau khi" +msgstr "đăng sau" -#: judge/models/interface.py:85 +#: judge/models/interface.py:72 msgid "post content" msgstr "đăng nội dung" -#: judge/models/interface.py:86 +#: judge/models/interface.py:73 msgid "post summary" -msgstr "đăng tổng kết" +msgstr "đăng tóm tắt" -#: judge/models/interface.py:88 +#: judge/models/interface.py:74 msgid "openGraph image" -msgstr "hình ảnh openGraph" +msgstr "ảnh OpenGraph" + +#: judge/models/interface.py:91 +msgid "Edit all posts" +msgstr "Chỉnh sửa tất cả bài viết" + +#: judge/models/interface.py:93 +msgid "blog post" +msgstr "bài đăng blog" #: judge/models/interface.py:94 -msgid "If private, only these organizations may see the blog post." -msgstr "Nếu riêng tư, chỉ những tổ chức này thấy được bài đăng." - -#: judge/models/interface.py:141 -msgid "Edit all posts" -msgstr "Chỉnh sửa tất cả bài đăng" - -#: judge/models/interface.py:142 -msgid "blog post" -msgstr "bài đăng" - -#: judge/models/interface.py:143 msgid "blog posts" -msgstr "bài đăng" +msgstr "bài đăng blog" #: judge/models/message.py:11 msgid "message title" -msgstr "tiêu đề tin nhắn" +msgstr "tiêu đề thư" -#: judge/models/message.py:12 judge/models/ticket.py:48 +#: judge/models/message.py:12 judge/models/ticket.py:29 msgid "message body" -msgstr "nội dung tin nhắn" +msgstr "nội dung thư" -#: judge/models/message.py:15 +#: judge/models/message.py:13 msgid "sender" msgstr "người gửi" -#: judge/models/message.py:21 +#: judge/models/message.py:14 msgid "target" msgstr "người nhận" -#: judge/models/message.py:26 +#: judge/models/message.py:15 msgid "message timestamp" -msgstr "thời gian gửi" +msgstr "thời gian tin nhắn" -#: judge/models/message.py:28 +#: judge/models/message.py:16 msgid "read" -msgstr "" +msgstr "đọc" -#: judge/models/message.py:33 +#: judge/models/message.py:20 msgid "messages in the thread" -msgstr "tin nhắn trong chuỗi" +msgstr "các tin nhắn trong luồng" -#: judge/models/notification.py:11 -msgid "Added a post" -msgstr "Thêm bài đăng" - -#: judge/models/notification.py:12 -msgid "You are added to a group" -msgstr "Bạn đã được thêm vào nhóm." - -#: judge/models/notification.py:13 -msgid "You have a new comment" -msgstr "Bạn có bình luận mới" - -#: judge/models/notification.py:14 -msgid "Deleted a post" -msgstr "Đã xóa bài đăng" - -#: judge/models/notification.py:15 -msgid "Rejected a post" -msgstr "Đã từ chối bài đăng" - -#: judge/models/notification.py:16 -msgid "Approved a post" -msgstr "Đã chấp thuận bài đăng" - -#: judge/models/notification.py:17 -msgid "Edited a post" -msgstr "Đã chỉnh sửa bài đăng" - -#: judge/models/notification.py:18 -msgid "Mentioned you" -msgstr "Đã nhắc đến bạn" - -#: judge/models/notification.py:19 -msgid "Replied you" -msgstr "Đã phản hồi bạn" - -#: judge/models/notification.py:20 templates/blog/list.html:47 -msgid "Ticket" -msgstr "Báo cáo" - -#: judge/models/notification.py:27 -msgid "owner" -msgstr "" - -#: judge/models/notification.py:32 -msgid "category" -msgstr "" - -#: judge/models/notification.py:35 -msgid "html link to comments, used for non-comments" -msgstr "" - -#: judge/models/notification.py:41 -msgid "who trigger, used for non-comment" -msgstr "" - -#: judge/models/notification.py:54 -msgid "The problem is public to: " -msgstr "Bài tập được công khai trong: " - -#: judge/models/notification.py:56 -msgid "The problem is private to: " -msgstr "Bài tập riêng tư trong: " - -#: judge/models/notification.py:59 -msgid "The problem is public to everyone." -msgstr "Bài tập được công khai với mọi người." - -#: judge/models/notification.py:61 -msgid "The problem is private." -msgstr "Bài tập được đánh dấu riêng tư." - -#: judge/models/pagevote.py:25 -#, fuzzy -#| msgid "votes" -msgid "pagevote" -msgstr "bình chọn" - -#: judge/models/pagevote.py:26 -#, fuzzy -#| msgid "votes" -msgid "pagevotes" -msgstr "bình chọn" - -#: judge/models/pagevote.py:48 -#, fuzzy -#| msgid "volunteer vote" -msgid "pagevote vote" -msgstr "vote từ TNV" - -#: judge/models/pagevote.py:49 -#, fuzzy -#| msgid "volunteer votes" -msgid "pagevote votes" -msgstr "vote từ TNV" - -#: judge/models/problem.py:46 +#: judge/models/problem.py:26 msgid "problem category ID" -msgstr "mã của nhóm bài" +msgstr "ID loại bài tập" -#: judge/models/problem.py:49 +#: judge/models/problem.py:27 msgid "problem category name" -msgstr "tên nhóm bài" +msgstr "tên loại bài" -#: judge/models/problem.py:57 +#: judge/models/problem.py:34 msgid "problem type" -msgstr "dạng bài" +msgstr "loại bài" -#: judge/models/problem.py:58 judge/models/problem.py:176 -#: judge/models/volunteer.py:28 +#: judge/models/problem.py:35 judge/models/problem.py:113 msgid "problem types" -msgstr "dạng bài" +msgstr "loại bài" -#: judge/models/problem.py:63 +#: judge/models/problem.py:39 msgid "problem group ID" -msgstr "mã của nhóm bài" +msgstr "ID nhóm bài" -#: judge/models/problem.py:65 +#: judge/models/problem.py:40 msgid "problem group name" -msgstr "tên nhóm bài" +msgstr "tên nhóm đề bài" -#: judge/models/problem.py:72 judge/models/problem.py:181 +#: judge/models/problem.py:47 judge/models/problem.py:116 msgid "problem group" msgstr "nhóm bài" -#: judge/models/problem.py:73 +#: judge/models/problem.py:48 msgid "problem groups" msgstr "nhóm bài" -#: judge/models/problem.py:80 +#: judge/models/problem.py:52 msgid "key" -msgstr "" +msgstr "khóa" -#: judge/models/problem.py:83 +#: judge/models/problem.py:54 msgid "link" -msgstr "đường dẫn" +msgstr "liên kết" -#: judge/models/problem.py:84 +#: judge/models/problem.py:55 msgid "full name" msgstr "tên đầy đủ" -#: judge/models/problem.py:88 judge/models/profile.py:70 -#: judge/models/runtime.py:35 +#: judge/models/problem.py:56 judge/models/profile.py:33 +#: judge/models/runtime.py:24 msgid "short name" -msgstr "tên ngắn" +msgstr "tên viết tắt" -#: judge/models/problem.py:89 +#: judge/models/problem.py:57 msgid "Displayed on pages under this license" -msgstr "Được hiển thị trên các trang theo giấy phép này" +msgstr "Được hiển thị theo giấy phép này" -#: judge/models/problem.py:94 +#: judge/models/problem.py:58 msgid "icon" -msgstr "icon" +msgstr "biểu tượng" -#: judge/models/problem.py:95 +#: judge/models/problem.py:58 msgid "URL to the icon" -msgstr "Đường dẫn icon" +msgstr "URL cho biểu tượng" -#: judge/models/problem.py:97 +#: judge/models/problem.py:59 msgid "license text" -msgstr "văn bản giấy phép" +msgstr "văn bản cấp phép" -#: judge/models/problem.py:106 +#: judge/models/problem.py:68 msgid "license" -msgstr "" +msgstr "giấy phép" -#: judge/models/problem.py:107 +#: judge/models/problem.py:69 msgid "licenses" -msgstr "" +msgstr "giấy phép" -#: judge/models/problem.py:130 +#: judge/models/problem.py:96 msgid "problem code" msgstr "mã bài" -#: judge/models/problem.py:136 +#: judge/models/problem.py:98 msgid "A short, unique code for the problem, used in the url after /problem/" -msgstr "Mã bài ngắn, độc nhất cho bài tập, được dùng trong url sau /problem/" +msgstr "Một mã ngắn duy nhất cho bài, sử dụng sau /problem/ trong url" -#: judge/models/problem.py:141 +#: judge/models/problem.py:100 msgid "problem name" -msgstr "Tên bài" +msgstr "tên bài tập" -#: judge/models/problem.py:143 +#: judge/models/problem.py:101 msgid "The full name of the problem, as shown in the problem list." -msgstr "Tên đầy đủ của bài, như được hiển thị trên danh sách bài tập" +msgstr "Tên đầy đủ của bài tập, được hiển thị trong dánh sách đề bài." -#: judge/models/problem.py:145 +#: judge/models/problem.py:103 msgid "problem body" -msgstr "Nội dung" +msgstr "bài tập" -#: judge/models/problem.py:148 +#: judge/models/problem.py:104 msgid "creators" -msgstr "" +msgstr "người tạo" -#: judge/models/problem.py:152 +#: judge/models/problem.py:105 msgid "These users will be able to edit the problem, and be listed as authors." msgstr "" -"Những người dùng này sẽ có thể chỉnh sửa bài tập, và nằm trong danh sách các " -"tác giả" +"Những người này có thể chỉnh sửa bài tập và được liệt kê trong danh sách tác " +"giả." -#: judge/models/problem.py:161 +#: judge/models/problem.py:107 +msgid "curators" +msgstr "người đóng góp" + +#: judge/models/problem.py:108 msgid "" "These users will be able to edit the problem, but not be listed as authors." msgstr "" -"Những người dùng này sẽ có thể chỉnh sửa bài tập, nhưng không nằm trong danh " -"sách các tác giả" +"Những người này có thể chỉnh sửa bài tập nhưng không được liệt kê trong danh " +"sách tác giả." -#: judge/models/problem.py:171 +#: judge/models/problem.py:110 +msgid "testers" +msgstr "người kiểm tra" + +#: judge/models/problem.py:112 msgid "These users will be able to view the private problem, but not edit it." msgstr "" -"Những người dùng này sẽ thấy được bài tập này (dù riêng tư), nhưng không " -"chỉnh sửa được" +"Những người này có thể xem bài tập riêng tư nhưng không thể chỉnh sửa chúng." -#: judge/models/problem.py:177 judge/models/volunteer.py:29 +#: judge/models/problem.py:114 msgid "The type of problem, as shown on the problem's page." -msgstr "Dạng bài, giống như trên trang bài tập" +msgstr "Loại bài tập, được hiển thị trong trang đề bài." -#: judge/models/problem.py:183 +#: judge/models/problem.py:117 msgid "The group of problem, shown under Category in the problem list." -msgstr "Nhóm bài, hiện ở mục Nhóm bài trong danh sách bài tập" +msgstr "Nhóm bài tập, hiển thị trong danh sách bài tập." -#: judge/models/problem.py:188 +#: judge/models/problem.py:119 msgid "" "The time limit for this problem, in seconds. Fractional seconds (e.g. 1.5) " "are supported." msgstr "" -"Giới hạn thời gian cho bài tập này, theo đơn vị giây. Có thể nhập số thực " -"(ví dụ 1.5)" +"Giới hạn thời gian (tính bằng giây) cho bài tập này. Phần lẻ giây (chẳng hạn " +"1.5) được hỗ trợ." -#: judge/models/problem.py:197 judge/models/problem.py:652 +#: judge/models/problem.py:123 judge/models/problem.py:380 msgid "memory limit" -msgstr "Giới hạn bộ nhớ" +msgstr "giới hạn bộ nhớ" -#: judge/models/problem.py:199 +#: judge/models/problem.py:124 msgid "" -"The memory limit for this problem, in kilobytes (e.g. 256mb = 262144 " +"The memory limit for this problem, in kilobytes (e.g. 64mb = 65536 " "kilobytes)." msgstr "" -"Giới hạn bộ nhớ cho bài này, theo đơn vị kilobytes (ví dụ 256mb = 262144 " -"kilobytes)" +"Giới hạn bộ nhớ (kilobytes) cho bài tập này (chẳng hạn 64mb = 65536 " +"kilobytes)." -#: judge/models/problem.py:211 +#: judge/models/problem.py:130 msgid "" "Points awarded for problem completion. Points are displayed with a 'p' " "suffix if partial." msgstr "" -"Điểm thưởng khi hoàn thành bài tập. Điểm có thêm chữ 'p' ở sau cùng nếu như " -"chấp nhận cho điểm thành phần (có điểm ngay khi không đúng toàn bộ test)" +"Điểm thưởng khi hoàn thành bài tập. Điểm được hiển thị với hậu tố 'p' nếu là " +"được tính thành phần." -#: judge/models/problem.py:217 +#: judge/models/problem.py:133 msgid "allows partial points" -msgstr "cho phép điểm thành phần" +msgstr "cho phép cho điểm thành phần" -#: judge/models/problem.py:221 +#: judge/models/problem.py:134 msgid "allowed languages" -msgstr "các ngôn ngữ được cho phép" +msgstr "ngôn ngữ cho phép" -#: judge/models/problem.py:222 +#: judge/models/problem.py:135 msgid "List of allowed submission languages." -msgstr "Danh sách các ngôn ngữ lập trình cho phép" +msgstr "Danh sách các ngôn ngữ cho phép nộp bài." -#: judge/models/problem.py:228 +#: judge/models/problem.py:137 msgid "manually managed" -msgstr "" +msgstr "quản lý thủ công" -#: judge/models/problem.py:231 +#: judge/models/problem.py:138 msgid "Whether judges should be allowed to manage data or not." -msgstr "" +msgstr "Liệu trình chấm có được phép quản lý dữ liệu hay không." -#: judge/models/problem.py:234 +#: judge/models/problem.py:139 msgid "date of publishing" -msgstr "Ngày công bố" +msgstr "ngày xuất bản" -#: judge/models/problem.py:239 +#: judge/models/problem.py:140 msgid "" "Doesn't have magic ability to auto-publish due to backward compatibility" -msgstr "" +msgstr "Không có khả năng tự động công khai vì vấn đề tương thích ngược" -#: judge/models/problem.py:246 +#: judge/models/problem.py:142 msgid "Bans the selected users from submitting to this problem." -msgstr "Cấm những người dùng được chọn nộp bài tập này." +msgstr "Cấm những người dùng được chọn nộp bài cho bài tập này." -#: judge/models/problem.py:253 +#: judge/models/problem.py:144 msgid "The license under which this problem is published." -msgstr "Giấy phép xuất bản bài tập" +msgstr "Giấy phép mà theo đó bài tập này được công bố." -#: judge/models/problem.py:260 +#: judge/models/problem.py:146 msgid "problem summary" -msgstr "Tóm tắt bài tập" +msgstr "tổng quan bài tập" -#: judge/models/problem.py:266 +#: judge/models/problem.py:148 msgid "number of users" -msgstr "" +msgstr "số thành viên" -#: judge/models/problem.py:268 +#: judge/models/problem.py:149 msgid "The number of users who solved the problem." -msgstr "Số lượng người dùng đã giải được bài" +msgstr "Số thành viên đã giải được bài tập." -#: judge/models/problem.py:270 +#: judge/models/problem.py:150 msgid "solve rate" -msgstr "Tỉ lệ giải đúng" +msgstr "tỉ lệ giải được" -#: judge/models/problem.py:282 +#: judge/models/problem.py:156 msgid "If private, only these organizations may see the problem." -msgstr "Nếu bài riêng tư, chỉ những tổ chức này thấy được" +msgstr "Nếu riêng tư, chỉ những tổ chức này có thể xem bài tập." -#: judge/models/problem.py:288 -msgid "pdf statement" -msgstr "Đề bài bằng file pdf" - -#: judge/models/problem.py:621 judge/models/problem.py:642 -#: judge/models/problem.py:673 judge/models/runtime.py:159 +#: judge/models/problem.py:358 judge/models/problem.py:376 +#: judge/models/runtime.py:108 msgid "language" -msgstr "" +msgstr "ngôn ngữ" -#: judge/models/problem.py:624 +#: judge/models/problem.py:359 msgid "translated name" -msgstr "" +msgstr "tên bộ dịch" -#: judge/models/problem.py:626 +#: judge/models/problem.py:360 msgid "translated description" -msgstr "" +msgstr "mô tả bộ dịch" -#: judge/models/problem.py:630 +#: judge/models/problem.py:364 msgid "problem translation" -msgstr "" +msgstr "dịch đầu bài" -#: judge/models/problem.py:631 +#: judge/models/problem.py:365 msgid "problem translations" -msgstr "" +msgstr "dịch đầu bài" -#: judge/models/problem.py:661 +#: judge/models/problem.py:369 +msgid "clarified problem" +msgstr "bài tập được làm rõ" + +#: judge/models/problem.py:370 +msgid "clarification body" +msgstr "nội dung làm rõ" + +#: judge/models/problem.py:371 +msgid "clarification timestamp" +msgstr "thời gian làm rõ" + +#: judge/models/problem.py:386 msgid "language-specific resource limit" -msgstr "" +msgstr "giới hạn tài nguyên theo ngôn ngữ" -#: judge/models/problem.py:662 +#: judge/models/problem.py:387 msgid "language-specific resource limits" -msgstr "" +msgstr "giới hạn tài nguyên theo ngôn ngữ" -#: judge/models/problem.py:675 judge/models/submission.py:291 -msgid "source code" -msgstr "mã nguồn" - -#: judge/models/problem.py:679 -msgid "language-specific template" -msgstr "" - -#: judge/models/problem.py:680 -msgid "language-specific templates" -msgstr "" - -#: judge/models/problem.py:687 +#: judge/models/problem.py:391 msgid "associated problem" -msgstr "" +msgstr "đầu bài liên quan" -#: judge/models/problem.py:693 +#: judge/models/problem.py:394 msgid "publish date" -msgstr "" +msgstr "ngày công bố" -#: judge/models/problem.py:695 +#: judge/models/problem.py:396 msgid "editorial content" -msgstr "nội dung lời giải" +msgstr "biên tập kỳ thi" -#: judge/models/problem.py:712 -#, python-format -msgid "Editorial for %s" -msgstr "" - -#: judge/models/problem.py:716 +#: judge/models/problem.py:412 msgid "solution" msgstr "lời giải" -#: judge/models/problem.py:717 +#: judge/models/problem.py:413 msgid "solutions" msgstr "lời giải" -#: judge/models/problem.py:722 -#, fuzzy -#| msgid "point value" -msgid "proposed point value" -msgstr "điểm" - -#: judge/models/problem.py:723 -msgid "The amount of points you think this problem deserves." -msgstr "Bạn nghĩ bài này đáng bao nhiêu điểm?" - -#: judge/models/problem.py:737 -msgid "The time this vote was cast" -msgstr "" - -#: judge/models/problem.py:743 -msgid "vote" -msgstr "" - -#: judge/models/problem_data.py:32 +#: judge/models/problem_data.py:24 msgid "Standard" -msgstr "Tiêu chuẩn" +msgstr "Mặc định" -#: judge/models/problem_data.py:33 +#: judge/models/problem_data.py:25 msgid "Floats" msgstr "Số thực" -#: judge/models/problem_data.py:34 +#: judge/models/problem_data.py:26 msgid "Floats (absolute)" -msgstr "Số thực (chênh lệch tuyệt đối)" +msgstr "Số thực (tuyệt đối)" -#: judge/models/problem_data.py:35 +#: judge/models/problem_data.py:27 msgid "Floats (relative)" -msgstr "Số thực (chênh lệch tương đối)" +msgstr "Số thực (tương đối)" -#: judge/models/problem_data.py:36 +#: judge/models/problem_data.py:28 msgid "Non-trailing spaces" -msgstr "Không xét dấu cách cuối dòng" +msgstr "Dấu cách liền" -#: judge/models/problem_data.py:37 +#: judge/models/problem_data.py:29 msgid "Unordered" -msgstr "Không thứ tự" +msgstr "Không sắp xếp" -#: judge/models/problem_data.py:38 +#: judge/models/problem_data.py:30 msgid "Byte identical" -msgstr "Giống từng byte" +msgstr "Byte tương tự" -#: judge/models/problem_data.py:39 +#: judge/models/problem_data.py:31 msgid "Line-by-line" -msgstr "Chấm theo dòng (điểm = số dòng đúng)" +msgstr "Dòng với dòng" + +#: judge/models/problem_data.py:32 +msgid "Custom checker (PY)" +msgstr "" + +#: judge/models/problem_data.py:33 +msgid "Custom validator (CPP)" +msgstr "" #: judge/models/problem_data.py:40 -msgid "Custom checker (PY)" -msgstr "Trình chấm tự viết (Python)" - -#: judge/models/problem_data.py:41 -msgid "Custom checker (CPP)" -msgstr "Trình chấm tự viết (CPP)" +msgid "data zip file" +msgstr "tập tin dữ liệu nén dạng zip" #: judge/models/problem_data.py:42 -msgid "Interactive" -msgstr "" - -#: judge/models/problem_data.py:43 -msgid "Testlib" -msgstr "" - -#: judge/models/problem_data.py:55 -msgid "data zip file" -msgstr "file zip chứa test" - -#: judge/models/problem_data.py:62 msgid "generator file" -msgstr "file tạo test" +msgstr "file tạo mã" -#: judge/models/problem_data.py:69 judge/models/problem_data.py:238 +#: judge/models/problem_data.py:44 judge/models/problem_data.py:110 msgid "output prefix length" -msgstr "độ dài hiển thị output" +msgstr "độ dài prefix" -#: judge/models/problem_data.py:72 judge/models/problem_data.py:241 +#: judge/models/problem_data.py:45 judge/models/problem_data.py:111 msgid "output limit length" -msgstr "giới hạn hiển thị output" +msgstr "hạn chế chiều dài đầu ra" -#: judge/models/problem_data.py:75 +#: judge/models/problem_data.py:46 msgid "init.yml generation feedback" -msgstr "phản hồi của quá trình tạo file init.yml" +msgstr "phải hồi init.yml" -#: judge/models/problem_data.py:78 judge/models/problem_data.py:244 +#: judge/models/problem_data.py:47 judge/models/problem_data.py:112 msgid "checker" -msgstr "trình chấm" +msgstr "kiểm tra" -#: judge/models/problem_data.py:81 judge/models/problem_data.py:247 +#: judge/models/problem_data.py:48 judge/models/problem_data.py:113 msgid "checker arguments" -msgstr "các biến trong trình chấm" +msgstr "đối số kiểm tra" -#: judge/models/problem_data.py:83 judge/models/problem_data.py:249 +#: judge/models/problem_data.py:49 judge/models/problem_data.py:114 msgid "checker arguments as a JSON object" -msgstr "các biến trong trình chấm theo dạng JSON" +msgstr "kiểm tra đối số như là một đối tượng JSON" -#: judge/models/problem_data.py:86 +#: judge/models/problem_data.py:50 msgid "custom checker file" -msgstr "trình chấm" +msgstr "" -#: judge/models/problem_data.py:94 -msgid "custom cpp checker file" -msgstr "trình chấm C++" +#: judge/models/problem_data.py:56 +msgid "custom validator file" +msgstr "" + +#: judge/models/problem_data.py:97 +msgid "problem data set" +msgstr "tập dữ liệu đề bài" + +#: judge/models/problem_data.py:99 +msgid "case position" +msgstr "vị trí phép thử" + +#: judge/models/problem_data.py:100 +msgid "case type" +msgstr "kiểu phép thử" + +#: judge/models/problem_data.py:101 +msgid "Normal case" +msgstr "Test đơn" #: judge/models/problem_data.py:102 -msgid "interactive judge" -msgstr "trình chấm interactive" - -#: judge/models/problem_data.py:110 judge/models/problem_data.py:229 -msgid "input file name" -msgstr "tên file input" - -#: judge/models/problem_data.py:113 -msgid "Leave empty for stdin" -msgstr "Để trống nếu nhập từ bàn phím" - -#: judge/models/problem_data.py:116 judge/models/problem_data.py:232 -msgid "output file name" -msgstr "tên file output" - -#: judge/models/problem_data.py:119 -msgid "Leave empty for stdout" -msgstr "Để trống nếu xuất ra màn hình" - -#: judge/models/problem_data.py:122 -msgid "is output only" -msgstr "Output-only?" - -#: judge/models/problem_data.py:123 -msgid "Support output-only problem" -msgstr "Dùng cho các bài output-only (nộp bằng file zip)" - -#: judge/models/problem_data.py:127 -msgid "is IOI signature" -msgstr "Nộp bài bằng hàm?" - -#: judge/models/problem_data.py:128 -msgid "Use IOI Signature" -msgstr "Nộp bài bằng hàm như IOI" - -#: judge/models/problem_data.py:132 -msgid "signature handler" -msgstr "File xử lý hàm" - -#: judge/models/problem_data.py:140 -msgid "signature header" -msgstr "File định nghĩa hàm" - -#: judge/models/problem_data.py:213 -msgid "problem data set" -msgstr "tập hợp dữ liệu bài" - -#: judge/models/problem_data.py:217 -msgid "case position" -msgstr "vị trí test" - -#: judge/models/problem_data.py:220 -msgid "case type" -msgstr "loại test" - -#: judge/models/problem_data.py:222 -msgid "Normal case" -msgstr "Test bình thường" - -#: judge/models/problem_data.py:223 msgid "Batch start" -msgstr "Bắt đầu nhóm" +msgstr "Bắt đầu lô" -#: judge/models/problem_data.py:224 +#: judge/models/problem_data.py:103 msgid "Batch end" -msgstr "Kết thúc nhóm" +msgstr "Hết lô" -#: judge/models/problem_data.py:234 +#: judge/models/problem_data.py:105 +msgid "input file name" +msgstr "tên tập tin đầu vào" + +#: judge/models/problem_data.py:106 +msgid "output file name" +msgstr "tên tập tin đầu ra" + +#: judge/models/problem_data.py:107 msgid "generator arguments" -msgstr "biến trong file sinh test" +msgstr "bộ sinh đối số" -#: judge/models/problem_data.py:235 +#: judge/models/problem_data.py:108 msgid "point value" -msgstr "điểm" +msgstr "giá trị điểm" -#: judge/models/problem_data.py:236 +#: judge/models/problem_data.py:109 msgid "case is pretest?" -msgstr "test là pretest?" +msgstr "test mẫu?" -#: judge/models/profile.py:58 +#: judge/models/profile.py:30 msgid "organization title" -msgstr "tiêu đề tổ chức" +msgstr "tiêu đề của tổ chức" -#: judge/models/profile.py:61 +#: judge/models/profile.py:31 msgid "organization slug" -msgstr "tên ngắn đường dẫn" +msgstr "" -#: judge/models/profile.py:62 +#: judge/models/profile.py:32 msgid "Organization name shown in URL" -msgstr "Tên được hiển thị trong đường dẫn" +msgstr "Tên tổ chức thể hiện trong URL" -#: judge/models/profile.py:71 +#: judge/models/profile.py:34 msgid "Displayed beside user name during contests" -msgstr "Hiển thị bên cạnh tên người dùng trong kỳ thi" +msgstr "Hiển thị bên cạnh tên trong cuộc thi" -#: judge/models/profile.py:74 +#: judge/models/profile.py:35 msgid "organization description" msgstr "mô tả tổ chức" -#: judge/models/profile.py:78 +#: judge/models/profile.py:36 msgid "registrant" -msgstr "người tạo" +msgstr "người đăng ký" -#: judge/models/profile.py:81 +#: judge/models/profile.py:37 msgid "User who registered this organization" -msgstr "Người tạo tổ chức" +msgstr "Người dùng đã đăng ký tổ chức này" -#: judge/models/profile.py:85 +#: judge/models/profile.py:38 msgid "administrators" -msgstr "người quản lý" +msgstr "quản trị viên" -#: judge/models/profile.py:87 +#: judge/models/profile.py:39 msgid "Those who can edit this organization" msgstr "Những người có thể chỉnh sửa tổ chức" -#: judge/models/profile.py:90 +#: judge/models/profile.py:40 msgid "creation date" msgstr "ngày tạo" -#: judge/models/profile.py:93 +#: judge/models/profile.py:41 msgid "is open organization?" -msgstr "tổ chức mở?" +msgstr "là tổ chức mở?" -#: judge/models/profile.py:94 +#: judge/models/profile.py:42 msgid "Allow joining organization" -msgstr "Cho phép mọi người tham gia tổ chức" +msgstr "Cho phép tham gia tổ chức" -#: judge/models/profile.py:98 +#: judge/models/profile.py:43 msgid "maximum size" -msgstr "số lượng thành viên tối đa" +msgstr "dung lượng tối đa" -#: judge/models/profile.py:102 +#: judge/models/profile.py:44 msgid "" "Maximum amount of users in this organization, only applicable to private " "organizations" -msgstr "Số người tối đa trong tổ chức, chỉ áp dụng với tổ chức riêng tư" +msgstr "" +"Số người dùng tối đa trong tổ chức này, chỉ áp dụng đối với tổ chức tư nhân" + +#: judge/models/profile.py:46 +msgid "Student access code" +msgstr "Mã truy cập sinh viên" + +#: judge/models/profile.py:50 +msgid "" +"This image will replace the default site logo for users viewing the " +"organization." +msgstr "" +"Ảnh này sẽ thay thế logo mặc định của trang khi thành viên xem tổ chức." + +#: judge/models/profile.py:76 judge/models/profile.py:93 +#: judge/models/profile.py:192 +msgid "organization" +msgstr "tổ chức" + +#: judge/models/profile.py:81 +msgid "user associated" +msgstr "liên kết với người sử dụng" + +#: judge/models/profile.py:82 +msgid "self-description" +msgstr "tự mô tả" + +#: judge/models/profile.py:83 +msgid "location" +msgstr "vị trí" + +#: judge/models/profile.py:85 +msgid "preferred language" +msgstr "ngôn ngữ" + +#: judge/models/profile.py:91 +msgid "last access time" +msgstr "lần truy cập cuối cùng" + +#: judge/models/profile.py:92 +msgid "last IP" +msgstr "IP" + +#: judge/models/profile.py:95 +msgid "display rank" +msgstr "hiển thị xếp hạng" + +#: judge/models/profile.py:97 +msgid "comment mute" +msgstr "bình luận tắt" + +#: judge/models/profile.py:97 +msgid "Some users are at their best when silent." +msgstr "Một vài người tốt nhất là khi im lặng." + +#: judge/models/profile.py:99 +msgid "unlisted user" +msgstr "thành viên không được liệt kê" + +#: judge/models/profile.py:99 +msgid "User will not be ranked." +msgstr "Thành viên không được xếp hạng." + +#: judge/models/profile.py:102 +msgid "user script" +msgstr "script tự định nghĩa" + +#: judge/models/profile.py:103 +msgid "User-defined JavaScript for site customization." +msgstr "JavaScript tự định nghĩa để tùy chỉnh trang web" + +#: judge/models/profile.py:104 +msgid "current contest" +msgstr "cuộc thi hiện tại" + +#: judge/models/profile.py:106 +msgid "math engine" +msgstr "bộ xử lý toán học" #: judge/models/profile.py:108 -msgid "Student access code" -msgstr "Mã truy cập cho học sinh" +msgid "the rendering engine used to render math" +msgstr "công cụ được sử dụng để render toán học" -#: judge/models/profile.py:166 judge/models/profile.py:198 -#: judge/models/profile.py:471 judge/models/profile.py:546 -msgid "organization" -msgstr "" - -#: judge/models/profile.py:173 -msgid "user associated" -msgstr "" - -#: judge/models/profile.py:176 -msgid "self-description" -msgstr "" - -#: judge/models/profile.py:180 -msgid "location" -msgstr "" - -#: judge/models/profile.py:186 -msgid "preferred language" -msgstr "" - -#: judge/models/profile.py:194 -msgid "last access time" -msgstr "" - -#: judge/models/profile.py:195 -msgid "last IP" -msgstr "" - -#: judge/models/profile.py:206 -msgid "display rank" -msgstr "" - -#: judge/models/profile.py:215 -msgid "comment mute" -msgstr "" - -#: judge/models/profile.py:216 -msgid "Some users are at their best when silent." -msgstr "" - -#: judge/models/profile.py:220 -msgid "unlisted user" -msgstr "" - -#: judge/models/profile.py:221 -msgid "User will not be ranked." -msgstr "" - -#: judge/models/profile.py:227 -msgid "current contest" -msgstr "kỳ thi hiện tại" - -#: judge/models/profile.py:234 +#: judge/models/profile.py:109 msgid "2FA enabled" -msgstr "" +msgstr "2FA có hiệu lực" -#: judge/models/profile.py:236 +#: judge/models/profile.py:110 msgid "check to enable TOTP-based two factor authentication" -msgstr "đánh dấu để sử dụng TOTP-based two factor authentication" +msgstr "đánh dấu để hiệu lực hóa xác minh hai yếu tố TOTP-based" -#: judge/models/profile.py:242 +#: judge/models/profile.py:111 msgid "TOTP key" -msgstr "mã TOTP" +msgstr "Mã TOTP" -#: judge/models/profile.py:243 +#: judge/models/profile.py:112 msgid "32 character base32-encoded key for TOTP" -msgstr "" +msgstr "mã 32 ký tự base32-encoded cho TOTP" -#: judge/models/profile.py:245 +#: judge/models/profile.py:114 msgid "TOTP key must be empty or base32" -msgstr "" +msgstr "Mã TOTP cần rỗng hoặc base32" -#: judge/models/profile.py:249 +#: judge/models/profile.py:115 msgid "internal notes" msgstr "ghi chú nội bộ" -#: judge/models/profile.py:252 +#: judge/models/profile.py:116 msgid "Notes for administrators regarding this user." -msgstr "Ghi chú riêng cho quản trị viên." +msgstr "Ghi chú cho quản trị viên chấm lại cho thành viên này." -#: judge/models/profile.py:257 -msgid "Custom background" -msgstr "Background tự chọn" - -#: judge/models/profile.py:260 -msgid "CSS custom background properties: url(\"image_url\"), color, etc" -msgstr "CSS background tự chọn. Ví dụ: url(\"image_url\"), white, ..." - -#: judge/models/profile.py:428 +#: judge/models/profile.py:186 msgid "user profile" -msgstr "thông tin người dùng" +msgstr "hồ sơ người dùng" -#: judge/models/profile.py:429 +#: judge/models/profile.py:187 msgid "user profiles" -msgstr "thông tin người dùng" +msgstr "hồ sơ người dùng" -#: judge/models/profile.py:435 -#, fuzzy -#| msgid "associated page" -msgid "profile associated" -msgstr "trang tương ứng" - -#: judge/models/profile.py:442 -msgid "t-shirt size" -msgstr "" - -#: judge/models/profile.py:447 -#, fuzzy -#| msgid "date of publishing" -msgid "date of birth" -msgstr "Ngày công bố" - -#: judge/models/profile.py:453 -msgid "address" -msgstr "" - -#: judge/models/profile.py:475 +#: judge/models/profile.py:194 msgid "request time" -msgstr "thời gian đăng ký" +msgstr "thời gian yêu cầu" -#: judge/models/profile.py:478 +#: judge/models/profile.py:195 msgid "state" msgstr "trạng thái" -#: judge/models/profile.py:485 +#: judge/models/profile.py:200 msgid "reason" msgstr "lý do" -#: judge/models/profile.py:488 +#: judge/models/profile.py:203 msgid "organization join request" -msgstr "đơn đăng ký tham gia" +msgstr "yêu cầu tham gia tổ chức" -#: judge/models/profile.py:489 +#: judge/models/profile.py:204 msgid "organization join requests" -msgstr "đơn đăng ký tham gia" +msgstr "yêu cầu tham gia tổ chức" -#: judge/models/profile.py:551 -#, fuzzy -#| msgid "last seen" -msgid "last visit" -msgstr "xem lần cuối" - -#: judge/models/runtime.py:22 +#: judge/models/runtime.py:19 msgid "short identifier" -msgstr "tên ngắn" +msgstr "nhận dạng ngắn" -#: judge/models/runtime.py:24 +#: judge/models/runtime.py:20 msgid "" "The identifier for this language; the same as its executor id for judges." -msgstr "" +msgstr "Mã định danh ngôn ngữ này; giống như id chấp hành cho bộ chấm." -#: judge/models/runtime.py:30 +#: judge/models/runtime.py:22 msgid "long name" msgstr "tên dài" -#: judge/models/runtime.py:31 +#: judge/models/runtime.py:23 msgid "Longer name for the language, e.g. \"Python 2\" or \"C++11\"." -msgstr "Tên dài, ví dụ \"Python 2\" or \"C++11\"." +msgstr "Tên dài của ngôn ngữ, ví dụ như \"Python 2\" hay \"C ++ 11\"." -#: judge/models/runtime.py:37 +#: judge/models/runtime.py:25 msgid "" "More readable, but short, name to display publicly; e.g. \"PY2\" or \"C+" "+11\". If left blank, it will default to the short identifier." msgstr "" +"Tên ngắn, dễ đọc hơn, để hiển thị công khai; Ví dụ: \"PY2\" hoặc \"C ++ " +"11\". Nếu để trống, nó sẽ sử dụng ID ngắn." -#: judge/models/runtime.py:46 +#: judge/models/runtime.py:29 msgid "common name" -msgstr "" +msgstr "tên chung" -#: judge/models/runtime.py:48 +#: judge/models/runtime.py:30 msgid "" "Common name for the language. For example, the common name for C++03, C++11, " "and C++14 would be \"C++\"" msgstr "" +"Tên phổ biến cho các ngôn ngữ. Ví dụ, tên gọi chung cho C ++ 03, 11 C ++ và " +"C ++ 14 sẽ là \"C++\"" -#: judge/models/runtime.py:54 +#: judge/models/runtime.py:32 msgid "ace mode name" -msgstr "" +msgstr "chế độ tên ace" -#: judge/models/runtime.py:56 +#: judge/models/runtime.py:33 msgid "" "Language ID for Ace.js editor highlighting, appended to \"mode-\" to " "determine the Ace JavaScript file to use, e.g., \"python\"." msgstr "" +"ID cho ngôn ngữ Ace.js, được nối thêm vào \"mode-\" để xác định tập tin Ace " +"JavaScript để sử dụng, ví dụ như, \"python\"." -#: judge/models/runtime.py:62 +#: judge/models/runtime.py:35 msgid "pygments name" -msgstr "" +msgstr "tên pygments" -#: judge/models/runtime.py:63 +#: judge/models/runtime.py:36 msgid "Language ID for Pygments highlighting in source windows." -msgstr "" +msgstr "Highligh ID cho Pygments trong cửa sổ mã nguồn." -#: judge/models/runtime.py:66 +#: judge/models/runtime.py:37 msgid "code template" -msgstr "" +msgstr "code mẫu" -#: judge/models/runtime.py:67 +#: judge/models/runtime.py:38 msgid "Code template to display in submission editor." -msgstr "" +msgstr "Mẫu mã nguồn hiển thị trong trình soạn thảo khi nộp bài." -#: judge/models/runtime.py:72 +#: judge/models/runtime.py:39 msgid "runtime info override" -msgstr "" +msgstr "ghi đè thời gian chạy" -#: judge/models/runtime.py:75 +#: judge/models/runtime.py:40 msgid "" "Do not set this unless you know what you're doing! It will override the " "usually more specific, judge-provided runtime info!" msgstr "" +"Không đặt này trừ khi bạn biết những gì bạn đang làm! Nó sẽ thiết lập các " +"thông tin thời gian chạy, cung cấp cho chương trình chấm!" -#: judge/models/runtime.py:80 +#: judge/models/runtime.py:42 msgid "language description" -msgstr "" +msgstr "mô tả ngôn ngữ" -#: judge/models/runtime.py:82 +#: judge/models/runtime.py:43 +#, fuzzy +#| msgid "" +#| "Use field this to inform users of quirks with your environment, " +#| "additional restrictions, etc." msgid "" "Use this field to inform users of quirks with your environment, additional " "restrictions, etc." msgstr "" +"Sử dụng trường này để thông báo cho người dùng quirks môi trường, hạn chế bổ " +"sung, vv." -#: judge/models/runtime.py:89 +#: judge/models/runtime.py:45 msgid "extension" -msgstr "" +msgstr "phần mở rộng" -#: judge/models/runtime.py:90 +#: judge/models/runtime.py:46 msgid "The extension of source files, e.g., \"py\" or \"cpp\"." -msgstr "" +msgstr "Phần mở rộng tập tin mã nguồn, ví dụ như, \"py\" hay \"cpp\"." -#: judge/models/runtime.py:160 +#: judge/models/runtime.py:109 msgid "languages" msgstr "ngôn ngữ" -#: judge/models/runtime.py:174 +#: judge/models/runtime.py:113 msgid "language to which this runtime belongs" -msgstr "" +msgstr "ngôn ngữ tạo ra runtime" -#: judge/models/runtime.py:178 +#: judge/models/runtime.py:114 msgid "judge on which this runtime exists" -msgstr "" +msgstr "máy chấm tạo ra runtime" -#: judge/models/runtime.py:180 +#: judge/models/runtime.py:115 msgid "runtime name" -msgstr "" +msgstr "tên runtime" -#: judge/models/runtime.py:182 +#: judge/models/runtime.py:116 msgid "runtime version" -msgstr "" +msgstr "phiên bản runtime" -#: judge/models/runtime.py:185 +#: judge/models/runtime.py:117 msgid "order in which to display this runtime" -msgstr "" +msgstr "thứ tự hiện thị runtime" -#: judge/models/runtime.py:191 +#: judge/models/runtime.py:121 msgid "Server name, hostname-style" -msgstr "Tên web" +msgstr "Tên server, tên host" -#: judge/models/runtime.py:194 +#: judge/models/runtime.py:122 msgid "time of creation" -msgstr "ngày tạo" +msgstr "thời gian tạo" -#: judge/models/runtime.py:198 +#: judge/models/runtime.py:123 +#, fuzzy +#| msgid "A key to authenticated this judge" msgid "A key to authenticate this judge" -msgstr "Chìa khóa xác thực" +msgstr "Mã truy cập chấm bài" -#: judge/models/runtime.py:199 +#: judge/models/runtime.py:124 msgid "authentication key" msgstr "mã xác thực" -#: judge/models/runtime.py:202 +#: judge/models/runtime.py:125 msgid "block judge" -msgstr "chặn máy chấm" +msgstr "khóa trình chấm" -#: judge/models/runtime.py:205 +#: judge/models/runtime.py:126 msgid "" "Whether this judge should be blocked from connecting, even if its key is " "correct." -msgstr "Quyết định có chặn máy chấm, ngay cả khi mã xác thực đúng." +msgstr "" -#: judge/models/runtime.py:209 +#: judge/models/runtime.py:128 msgid "judge online status" -msgstr "trạng thái online của máy chấm" +msgstr "trạng thái bộ chấm online" -#: judge/models/runtime.py:210 +#: judge/models/runtime.py:129 msgid "judge start time" -msgstr "thời gian khởi đầu máy chấm" +msgstr "thời gian bắt đầu chấm" -#: judge/models/runtime.py:211 +#: judge/models/runtime.py:130 msgid "response time" -msgstr "thời gian trả lời" +msgstr "thời gian đáp ứng" -#: judge/models/runtime.py:213 +#: judge/models/runtime.py:131 msgid "system load" -msgstr "lưu lượng xử lý" +msgstr "mức tải của hệ thống" -#: judge/models/runtime.py:215 +#: judge/models/runtime.py:132 msgid "Load for the last minute, divided by processors to be fair." -msgstr "Lưu lượng được chia đều." +msgstr "Tải cho phút cuối cùng, chia cho số bộ vi xử lý." -#: judge/models/runtime.py:225 judge/models/runtime.py:267 +#: judge/models/runtime.py:136 judge/models/runtime.py:176 msgid "judges" -msgstr "máy chấm" +msgstr "chấm điểm" -#: judge/models/runtime.py:266 +#: judge/models/runtime.py:175 msgid "judge" msgstr "máy chấm" #: judge/models/submission.py:20 judge/models/submission.py:47 -#: judge/utils/problems.py:116 +#: judge/utils/problems.py:77 msgid "Accepted" -msgstr "Accepted" +msgstr "Chấp nhận (AC)" #: judge/models/submission.py:21 judge/models/submission.py:48 -#: judge/utils/problems.py:119 msgid "Wrong Answer" -msgstr "Wrong Answer" +msgstr "Kết quả sai (WA)" #: judge/models/submission.py:22 judge/models/submission.py:50 -#: judge/utils/problems.py:129 msgid "Time Limit Exceeded" -msgstr "Time Limit Exceeded" +msgstr "Quá thời gian (TLE)" #: judge/models/submission.py:23 judge/models/submission.py:51 msgid "Memory Limit Exceeded" -msgstr "Memory Limit Exceeded" +msgstr "Tràn bộ nhớ (MLE)" #: judge/models/submission.py:24 judge/models/submission.py:52 msgid "Output Limit Exceeded" -msgstr "Output Limit Exceeded" +msgstr "Kết xuất dữ liệu ra quá nhiều" #: judge/models/submission.py:25 judge/models/submission.py:53 msgid "Invalid Return" -msgstr "Invalid Return" +msgstr "Lỗi khi chạy chương trình (IR)" #: judge/models/submission.py:26 judge/models/submission.py:54 msgid "Runtime Error" -msgstr "Runtime Error" +msgstr "Lỗi Runtime" #: judge/models/submission.py:27 judge/models/submission.py:41 -#: judge/models/submission.py:55 judge/utils/problems.py:124 +#: judge/models/submission.py:55 judge/utils/problems.py:79 msgid "Compile Error" -msgstr "Compile Error" +msgstr "Lỗi dịch (CE)" #: judge/models/submission.py:28 judge/models/submission.py:40 msgid "Internal Error" -msgstr "Internal Error" +msgstr "Lỗi Nội Bộ" #: judge/models/submission.py:29 msgid "Short circuit" -msgstr "Short circuit" +msgstr "Ngắn mạch" #: judge/models/submission.py:30 judge/models/submission.py:42 #: judge/models/submission.py:61 msgid "Aborted" -msgstr "Đã hủy" +msgstr "Bị hủy bỏ" #: judge/models/submission.py:36 judge/models/submission.py:57 msgid "Queued" -msgstr "Trong hàng đợi" +msgstr "Đang chờ" #: judge/models/submission.py:37 judge/models/submission.py:58 msgid "Processing" @@ -2491,1399 +1970,935 @@ msgstr "Đang xử lý" #: judge/models/submission.py:38 judge/models/submission.py:59 msgid "Grading" -msgstr "Đang chấm" +msgstr "Chấm điểm" #: judge/models/submission.py:39 judge/models/submission.py:60 msgid "Completed" -msgstr "Chấm xong" +msgstr "Đã Hoàn Thành" #: judge/models/submission.py:56 msgid "Internal Error (judging server error)" -msgstr "Lỗi máy chấm" +msgstr "Lỗi nội bộ (máy chủ chấm bài lỗi)" -#: judge/models/submission.py:67 +#: judge/models/submission.py:66 msgid "submission time" -msgstr "thời gian bài nộp" +msgstr "ngày nộp bài" -#: judge/models/submission.py:69 judge/models/submission.py:310 +#: judge/models/submission.py:67 judge/models/submission.py:201 msgid "execution time" -msgstr "thời gian chạy" +msgstr "thời gian thực hiện tối đa" -#: judge/models/submission.py:70 judge/models/submission.py:311 +#: judge/models/submission.py:68 judge/models/submission.py:202 msgid "memory usage" msgstr "bộ nhớ sử dụng" -#: judge/models/submission.py:72 judge/models/submission.py:312 +#: judge/models/submission.py:69 judge/models/submission.py:203 msgid "points granted" -msgstr "điểm" +msgstr "điểm được cho" -#: judge/models/submission.py:75 +#: judge/models/submission.py:70 msgid "submission language" -msgstr "ngôn ngữ bài nộp" +msgstr "ngôn ngữ lập trình" -#: judge/models/submission.py:78 +#: judge/models/submission.py:71 msgid "status" msgstr "trạng thái" -#: judge/models/submission.py:85 +#: judge/models/submission.py:72 msgid "result" msgstr "kết quả" -#: judge/models/submission.py:93 +#: judge/models/submission.py:74 msgid "compile errors" -msgstr "biên dịch lỗi" +msgstr "lỗi dịch" -#: judge/models/submission.py:95 +#: judge/models/submission.py:76 msgid "batched cases" msgstr "nhóm test" -#: judge/models/submission.py:96 +#: judge/models/submission.py:77 msgid "test case points" -msgstr "điểm test" +msgstr "điểm cho testcase" -#: judge/models/submission.py:97 +#: judge/models/submission.py:78 msgid "test case total points" -msgstr "tổng điểm các test" +msgstr "tổng điểm test case" -#: judge/models/submission.py:100 +#: judge/models/submission.py:79 msgid "judged on" -msgstr "chấm trên" +msgstr "đánh giá trên" -#: judge/models/submission.py:106 -msgid "submission judge time" -msgstr "thời điểm được chấm" - -#: judge/models/submission.py:109 +#: judge/models/submission.py:81 msgid "was rejudged by admin" msgstr "được chấm lại bởi admin" -#: judge/models/submission.py:112 +#: judge/models/submission.py:82 msgid "was ran on pretests only" -msgstr "chỉ chấm pretest" +msgstr "chỉ được chạy bởi test sơ bộ" -#: judge/models/submission.py:275 templates/contest/moss.html:56 +#: judge/models/submission.py:182 templates/contest/moss.html:58 msgid "submissions" -msgstr "bài nộp" +msgstr "nộp bài" -#: judge/models/submission.py:288 judge/models/submission.py:302 +#: judge/models/submission.py:186 judge/models/submission.py:197 msgid "associated submission" -msgstr "bài nộp tương ứng" +msgstr "bài nộp liên quan" -#: judge/models/submission.py:306 +#: judge/models/submission.py:188 +msgid "source code" +msgstr "mã nguồn" + +#: judge/models/submission.py:199 msgid "test case ID" -msgstr "test case ID" +msgstr "mã testcase" -#: judge/models/submission.py:308 +#: judge/models/submission.py:200 msgid "status flag" -msgstr "" +msgstr "cờ trạng thái" -#: judge/models/submission.py:313 +#: judge/models/submission.py:204 msgid "points possible" +msgstr "khả năng điểm" + +#: judge/models/submission.py:205 +msgid "batch number" +msgstr "lô số" + +#: judge/models/submission.py:206 +msgid "judging feedback" +msgstr "phản hồi chấm thi" + +#: judge/models/submission.py:207 +msgid "extended judging feedback" msgstr "" -#: judge/models/submission.py:314 -msgid "batch number" -msgstr "số thứ tự của nhóm" - -#: judge/models/submission.py:316 -msgid "judging feedback" -msgstr "phản hồi từ máy chấm" - -#: judge/models/submission.py:319 -msgid "extended judging feedback" -msgstr "phản hồi thêm từ máy chấm" - -#: judge/models/submission.py:321 +#: judge/models/submission.py:208 msgid "program output" -msgstr "output chương trình" +msgstr "lập trình đầu ra" -#: judge/models/submission.py:329 +#: judge/models/submission.py:216 msgid "submission test case" -msgstr "cái testcase trong bài nộp" +msgstr "test case của bài" -#: judge/models/submission.py:330 +#: judge/models/submission.py:217 msgid "submission test cases" -msgstr "cái testcase trong bài nộp" - -#: judge/models/test_formatter.py:22 -#, fuzzy -#| msgid "test case ID" -msgid "testcase file" -msgstr "test case ID" +msgstr "các test case của bài" #: judge/models/ticket.py:10 msgid "ticket title" -msgstr "tiêu đề báo cáo" +msgstr "" + +#: judge/models/ticket.py:11 +msgid "ticket creator" +msgstr "" #: judge/models/ticket.py:13 -msgid "ticket creator" -msgstr "người báo cáo" - -#: judge/models/ticket.py:17 msgid "creation time" -msgstr "thời gian tạo" +msgstr "" -#: judge/models/ticket.py:19 +#: judge/models/ticket.py:14 msgid "assignees" -msgstr "người được ủy thác" +msgstr "" -#: judge/models/ticket.py:22 +#: judge/models/ticket.py:15 msgid "quick notes" msgstr "" -#: judge/models/ticket.py:24 +#: judge/models/ticket.py:16 msgid "Staff notes for this issue to aid in processing." msgstr "" -#: judge/models/ticket.py:27 +#: judge/models/ticket.py:17 msgid "linked item type" msgstr "" -#: judge/models/ticket.py:29 +#: judge/models/ticket.py:19 msgid "linked item ID" msgstr "" -#: judge/models/ticket.py:31 +#: judge/models/ticket.py:21 msgid "is ticket open?" msgstr "" -#: judge/models/ticket.py:37 +#: judge/models/ticket.py:25 msgid "ticket" msgstr "" -#: judge/models/ticket.py:44 +#: judge/models/ticket.py:27 msgid "poster" msgstr "" -#: judge/models/ticket.py:49 +#: judge/models/ticket.py:30 msgid "message time" msgstr "" -#: judge/models/volunteer.py:19 -msgid "knowledge points" -msgstr "Độ khó kiến thức" - -#: judge/models/volunteer.py:20 -msgid "Points awarded by knowledge difficulty" -msgstr "" - -#: judge/models/volunteer.py:23 -msgid "thinking points" -msgstr "Độ khó nghĩ" - -#: judge/models/volunteer.py:24 -msgid "Points awarded by thinking difficulty" -msgstr "" - -#: judge/models/volunteer.py:31 -msgid "feedback" -msgstr "phản hồi" - -#: judge/models/volunteer.py:34 -msgid "volunteer vote" -msgstr "vote từ TNV" - -#: judge/models/volunteer.py:35 -msgid "volunteer votes" -msgstr "vote từ TNV" - -#: judge/pdf_problems.py:161 judge/pdf_problems.py:221 -#: judge/pdf_problems.py:294 +#: judge/pdf_problems.py:134 judge/pdf_problems.py:186 +#: judge/pdf_problems.py:246 msgid "Page [page] of [topage]" -msgstr "Trang [page]/[topage]" +msgstr "Trang [page] /[topage]" -#: judge/pdf_problems.py:324 -#, python-format -msgid "Page %s of %s" -msgstr "Trang %s/%s" - -#: judge/social_auth.py:69 judge/views/register.py:32 -msgid "A username must contain letters, numbers, or underscores" -msgstr "Tên đăng nhập phải chứa ký tự, chữ số, hoặc dấu gạch dưới" - -#: judge/social_auth.py:75 -msgid "Sorry, the username is taken." -msgstr "Xin lỗi, tên đăng nhập đã bị trùng." - -#: judge/social_auth.py:93 -msgid "Choose a username" -msgstr "Chọn tên đăng nhập" - -#: judge/social_auth.py:122 -msgid "Create your profile" -msgstr "Khởi tạo thông tin" - -#: judge/tasks/contest.py:20 -msgid "Recalculating contest scores" -msgstr "Tính lại điểm kỳ thi" - -#: judge/tasks/contest.py:59 +#: judge/tasks/moss.py:25 msgid "Running MOSS" -msgstr "Đang chạy MOSS" +msgstr "" -#: judge/tasks/submission.py:47 +#: judge/tasks/submission.py:43 msgid "Modifying submissions" -msgstr "Chỉnh sửa bài nộp" +msgstr "" -#: judge/tasks/submission.py:67 +#: judge/tasks/submission.py:56 msgid "Recalculating user points" -msgstr "Tính lại điểm người dùng" +msgstr "" -#: judge/utils/problem_data.py:81 +#: judge/utils/problem_data.py:68 msgid "Empty batches not allowed." -msgstr "Nhóm test trống là không hợp lệ." +msgstr "Lệnh theo lô trống là không được phép." -#: judge/utils/problem_data.py:89 judge/utils/problem_data.py:97 -#: judge/utils/problem_data.py:112 +#: judge/utils/problem_data.py:76 judge/utils/problem_data.py:97 +#, fuzzy +#| msgid "How did you corrupt the zip path?" msgid "How did you corrupt the custom checker path?" -msgstr "How did you corrupt the custom checker path?" +msgstr "Bạn đã làm hỏng đường dẫn zip?" -#: judge/utils/problem_data.py:140 +#: judge/utils/problem_data.py:118 #, python-format msgid "Points must be defined for non-batch case #%d." -msgstr "Ô điểm số cho test #%d phải được điền." +msgstr "Điểm phải được xác định cho các trường hợp không theo lô #%d." -#: judge/utils/problem_data.py:147 +#: judge/utils/problem_data.py:123 #, python-format msgid "Input file for case %d does not exist: %s" -msgstr "File input cho test %d không tồn tại: %s" +msgstr "Các tập tin đầu vào cho trường hợp %d không tồn tại: %s" -#: judge/utils/problem_data.py:152 +#: judge/utils/problem_data.py:126 #, python-format msgid "Output file for case %d does not exist: %s" -msgstr "File output cho test %d không tồn tại: %s" +msgstr "Các tập tin đầu vào cho trường hợp %d không tồn tại: %s" -#: judge/utils/problem_data.py:179 +#: judge/utils/problem_data.py:151 #, python-format msgid "Batch start case #%d requires points." -msgstr "Nhóm test #%d cần được điền điểm số." +msgstr "Phép thử theo lô #%d yêu cầu điểm." -#: judge/utils/problem_data.py:202 +#: judge/utils/problem_data.py:172 #, python-format msgid "Attempt to end batch outside of one in case #%d" -msgstr "Nhóm test #%d kết thúc không hợp lệ" +msgstr "Cố gắng để kết thúc bộ số liệu nằm ngoài một trong các trường hợp #%d" -#: judge/utils/problem_data.py:221 +#: judge/utils/problem_data.py:190 msgid "How did you corrupt the zip path?" -msgstr "" +msgstr "Bạn đã làm hỏng đường dẫn zip?" -#: judge/utils/problem_data.py:227 +#: judge/utils/problem_data.py:196 msgid "How did you corrupt the generator path?" msgstr "" -#: judge/utils/problem_data.py:245 -msgid "Invalid interactor judge" +#: judge/utils/problems.py:78 +msgid "Wrong" msgstr "" -#: judge/utils/problem_data.py:269 -#, fuzzy -#| msgid "Invalid Return" -msgid "Invalid signature handler" -msgstr "Invalid Return" - -#: judge/utils/problem_data.py:272 -msgid "Invalid signature header" +#: judge/utils/problems.py:80 +msgid "Timeout" msgstr "" -#: judge/utils/problems.py:134 +#: judge/utils/problems.py:81 msgid "Error" -msgstr "Lỗi" - -#: judge/utils/problems.py:151 -msgid "Can't pass both queryset and keyword filters" msgstr "" +#: judge/utils/problems.py:92 +msgid "Can't pass both queryset and keyword filters" +msgstr "Không thể bỏ qua cả bộ lọc queryset và keyword" + #: judge/utils/pwned.py:101 msgid "Your password can't be a commonly used password." -msgstr "Mật khẩu không được quá phổ biến." +msgstr "" #: judge/utils/pwned.py:102 msgid "This password is too common." msgstr "Mật khẩu này quá phổ biến." -#: judge/utils/timedelta.py:59 +#: judge/utils/timedelta.py:49 msgctxt "time format with day" msgid "%d day %h:%m:%s" msgid_plural "%d days %h:%m:%s" msgstr[0] "%d ngày %h:%m:%s" -#: judge/utils/timedelta.py:68 +#: judge/utils/timedelta.py:53 msgctxt "time format without day" msgid "%h:%m:%s" -msgstr "%h:%m:%s" +msgstr "" -#: judge/utils/timedelta.py:80 +#: judge/utils/timedelta.py:59 msgctxt "time format no seconds with day" msgid "%d day %h:%m" msgid_plural "%d days %h:%m" msgstr[0] "%d ngày %h:%m" -#: judge/utils/timedelta.py:88 +#: judge/utils/timedelta.py:61 #, python-format msgid "%d day" msgid_plural "%d days" msgstr[0] "%d ngày" -#: judge/utils/timedelta.py:91 +#: judge/utils/timedelta.py:63 msgctxt "hours and minutes" msgid "%h:%m" -msgstr "%h:%m" +msgstr "" -#: judge/utils/users.py:61 -msgid "M j, Y" -msgstr "j M, Y" - -#: judge/views/about.py:10 templates/course/course.html:27 -#: templates/organization/home.html:44 -#: templates/organization/org-right-sidebar.html:74 -#: templates/user/user-about.html:70 templates/user/user-tabs.html:4 -#: templates/user/users-table.html:22 +#: judge/views/about.py:7 templates/user/user-about.html:33 msgid "About" msgstr "Giới thiệu" -#: judge/views/about.py:251 +#: judge/views/about.py:13 msgid "Custom Checker Sample" -msgstr "Hướng dẫn viết trình chấm" +msgstr "" -#: judge/views/blog.py:131 +#: judge/views/blog.py:38 #, python-format msgid "Page %d of Posts" -msgstr "Trang %d" +msgstr "Trang %d của bài viết" -#: judge/views/blog.py:171 -msgid "Ticket feed" -msgstr "Báo cáo" - -#: judge/views/blog.py:188 -msgid "Comment feed" -msgstr "Bình luận" - -#: judge/views/comment.py:71 judge/views/pagevote.py:32 +#: judge/views/comment.py:27 msgid "Messing around, are we?" -msgstr "Messing around, are we?" +msgstr "Bị rối?" -#: judge/views/comment.py:87 judge/views/pagevote.py:48 +#: judge/views/comment.py:36 msgid "You must solve at least one problem before you can vote." -msgstr "Bạn phải giải ít nhất 1 bài trước khi được vote." +msgstr "" -#: judge/views/comment.py:113 +#: judge/views/comment.py:63 msgid "You already voted." -msgstr "Bạn đã vote." +msgstr "Bạn đã bỏ phiếu rồi." -#: judge/views/comment.py:272 judge/views/organization.py:882 -#: judge/views/organization.py:1035 judge/views/organization.py:1208 +#: judge/views/comment.py:120 judge/views/organization.py:299 msgid "Edited from site" -msgstr "Chỉnh sửa từ web" +msgstr "Biên tập từ trang web" -#: judge/views/comment.py:293 +#: judge/views/comment.py:141 msgid "Editing comment" -msgstr "Chỉnh sửa bình luận" +msgstr "Đang chỉnh sửa bình luận" -#: judge/views/comment.py:345 -msgid "Comment body" -msgstr "Nội dung bình luận" - -#: judge/views/comment.py:351 judge/views/ticket.py:73 -msgid "Your part is silent, little toad." -msgstr "Bạn không được phép bình luận." - -#: judge/views/comment.py:360 templates/comments/list.html:17 -msgid "" -"You need to have solved at least one problem before your voice can be heard." -msgstr "Bạn phải giải ít nhất một bài trước khi được phép bình luận." - -#: judge/views/comment.py:403 -msgid "Posted comment" -msgstr "Bình luận đã đăng" - -#: judge/views/contests.py:124 judge/views/contests.py:471 -#: judge/views/contests.py:476 judge/views/contests.py:784 +#: judge/views/contests.py:55 judge/views/contests.py:215 +#: judge/views/contests.py:218 judge/views/contests.py:389 msgid "No such contest" -msgstr "Không có contest nào như vậy" +msgstr "Không có cuộc thi như vậy" -#: judge/views/contests.py:125 judge/views/contests.py:472 +#: judge/views/contests.py:56 judge/views/contests.py:216 #, python-format msgid "Could not find a contest with the key \"%s\"." -msgstr "Không tìm thấy kỳ thi với mã \"%s\"." +msgstr "Không thể tìm thấy một cuộc thi với khóa \"%s\"." -#: judge/views/contests.py:153 judge/views/contests.py:1561 -#: judge/views/stats.py:178 templates/contest/list.html:171 -#: templates/contest/list.html:213 templates/contest/list.html:250 -#: templates/contest/list.html:284 templates/course/course.html:59 -#: templates/course/left_sidebar.html:5 -#: templates/organization/org-left-sidebar.html:5 templates/stats/site.html:21 -#: templates/user/user-bookmarks.html:19 templates/user/user-bookmarks.html:80 +#: judge/views/contests.py:81 msgid "Contests" -msgstr "Kỳ thi" +msgstr "Cuộc thi" -#: judge/views/contests.py:331 -msgid "Start time (asc.)" -msgstr "Thời gian bắt đầu (tăng)" - -#: judge/views/contests.py:332 -msgid "Start time (desc.)" -msgstr "Thời gian bắt đầu (giảm)" - -#: judge/views/contests.py:333 judge/views/organization.py:314 -msgid "Name (asc.)" -msgstr "Tên (tăng)" - -#: judge/views/contests.py:334 judge/views/organization.py:315 -msgid "Name (desc.)" -msgstr "Tên (giảm)" - -#: judge/views/contests.py:335 -msgid "User count (asc.)" -msgstr "Số lượng tham gia (tăng)" - -#: judge/views/contests.py:336 -msgid "User count (desc.)" -msgstr "Số lượng tham gia (giảm)" - -#: judge/views/contests.py:476 +#: judge/views/contests.py:219 msgid "Could not find such contest." -msgstr "Không tìm thấy kỳ thi nào như vậy." +msgstr "Không thể tìm thấy các cuộc thi như vậy." -#: judge/views/contests.py:484 +#: judge/views/contests.py:222 #, python-format msgid "Access to contest \"%s\" denied" -msgstr "Truy cập tới kỳ thi \"%s\" bị từ chối" +msgstr "Truy cập vào cuộc thi \"%s\" từ chối" -#: judge/views/contests.py:570 +#: judge/views/contests.py:246 msgid "Clone Contest" -msgstr "Nhân bản kỳ thi" +msgstr "" -#: judge/views/contests.py:662 +#: judge/views/contests.py:309 msgid "Contest not ongoing" -msgstr "Kỳ thi đang không diễn ra" +msgstr "Cuộc thi không đang diễn ra" -#: judge/views/contests.py:663 +#: judge/views/contests.py:310 #, python-format msgid "\"%s\" is not currently ongoing." -msgstr "\"%s\" kỳ thi đang không diễn ra." +msgstr "\"%s\" không đang diễn ra." -#: judge/views/contests.py:676 +#: judge/views/contests.py:314 +msgid "Already in contest" +msgstr "Đang trong cuộc thi" + +#: judge/views/contests.py:315 +#, python-format +msgid "You are already in a contest: \"%s\"." +msgstr "Bạn đang ở một cuộc thi: \"%s\"." + +#: judge/views/contests.py:318 msgid "Banned from joining" -msgstr "Bị cấm tham gia" +msgstr "" -#: judge/views/contests.py:678 +#: judge/views/contests.py:319 msgid "" "You have been declared persona non grata for this contest. You are " "permanently barred from joining this contest." -msgstr "Bạn không được phép tham gia kỳ thi này." +msgstr "" -#: judge/views/contests.py:768 +#: judge/views/contests.py:379 #, python-format msgid "Enter access code for \"%s\"" -msgstr "Nhập mật khẩu truy cập cho \"%s\"" +msgstr "" -#: judge/views/contests.py:785 +#: judge/views/contests.py:390 #, python-format msgid "You are not in contest \"%s\"." -msgstr "Bạn không ở trong kỳ thi \"%s\"." +msgstr "Bạn đang không tham gia cuộc thi \"%s\"." -#: judge/views/contests.py:808 +#: judge/views/contests.py:409 msgid "ContestCalendar requires integer year and month" -msgstr "Lịch thi yêu cầu giá trị cho năm và tháng là số nguyên" +msgstr "" -#: judge/views/contests.py:866 +#: judge/views/contests.py:449 #, python-format msgid "Contests in %(month)s" -msgstr "Các kỳ thi trong %(month)s" +msgstr "Cuộc thi tại %(month)s" -#: judge/views/contests.py:867 +#: judge/views/contests.py:449 msgid "F Y" -msgstr "F Y" +msgstr "" -#: judge/views/contests.py:927 -#, python-format +#: judge/views/contests.py:496 +#, fuzzy, python-format +#| msgid "Statistics" msgid "%s Statistics" -msgstr "%s Thống kê" +msgstr "Thống kê" -#: judge/views/contests.py:1206 +#: judge/views/contests.py:601 +msgid "???" +msgstr "" + +#: judge/views/contests.py:664 #, python-format msgid "%s Rankings" -msgstr "%s Bảng điểm" +msgstr "%s xếp hạng" -#: judge/views/contests.py:1217 -msgid "???" -msgstr "???" - -#: judge/views/contests.py:1281 +#: judge/views/contests.py:680 #, python-format msgid "Your participation in %s" -msgstr "Lần tham gia trong %s" +msgstr "Tham gia của bạn vào %s" -#: judge/views/contests.py:1282 +#: judge/views/contests.py:681 #, python-format msgid "%s's participation in %s" -msgstr "Lần tham gia của %s trong %s" +msgstr "%s tham gia vào %s" -#: judge/views/contests.py:1296 +#: judge/views/contests.py:685 msgid "Live" -msgstr "Trực tiếp" +msgstr "Trực tuyến" -#: judge/views/contests.py:1314 templates/contest/contest-tabs.html:21 +#: judge/views/contests.py:697 msgid "Participation" -msgstr "Lần tham gia" +msgstr "Tham gia" -#: judge/views/contests.py:1363 +#: judge/views/contests.py:743 #, python-format msgid "%s MOSS Results" -msgstr "%s Kết quả MOSS" +msgstr "" -#: judge/views/contests.py:1399 +#: judge/views/contests.py:770 #, python-format msgid "Running MOSS for %s..." -msgstr "Đang chạy MOSS cho %s..." +msgstr "" -#: judge/views/contests.py:1422 +#: judge/views/contests.py:793 #, python-format msgid "Contest tag: %s" -msgstr "Nhãn kỳ thi: %s" +msgstr "Thẻ cuộc thi %s" -#: judge/views/contests.py:1437 judge/views/ticket.py:67 -msgid "Issue description" -msgstr "Mô tả vấn đề" - -#: judge/views/contests.py:1480 -#, python-format -msgid "New clarification for %s" -msgstr "Thông báo mới cho %s" - -#: judge/views/course.py:350 -#, python-format -msgid "Edit lessons for %(course_name)s" -msgstr "Chỉnh sửa bài học cho %(course_name)s" - -#: judge/views/course.py:354 -#, python-format -msgid "Edit lessons for %(course_name)s" -msgstr "Chỉnh sửa bài học cho %(course_name)s" - -#: judge/views/course.py:414 -#, fuzzy, python-format -#| msgid "Edit lessons for %(course_name)s" -msgid "Grades in %(course_name)s" -msgstr "Chỉnh sửa bài học cho %(course_name)s" - -#: judge/views/course.py:418 -#, python-format -msgid "Grades in %(course_name)s" -msgstr "Điểm trong %(course_name)s" - -#: judge/views/course.py:472 -#, fuzzy, python-format -msgid "Grades of %(lesson_name)s in %(course_name)s" -msgstr "Chỉnh sửa bài học cho %(course_name)s" - -#: judge/views/course.py:478 -#, fuzzy, python-format -msgid "" -"Grades of %(lesson_name)s in %(course_name)s" -msgstr "Điểm trong %(course_name)s" - -#: judge/views/course.py:493 judge/views/course.py:578 -#: templates/course/contest_list.html:20 -#, fuzzy -#| msgid "order" -msgid "Order" -msgstr "thứ tự" - -#: judge/views/course.py:540 judge/views/organization.py:930 -#: templates/organization/org-right-sidebar.html:47 -msgid "Add contest" -msgstr "Thêm kỳ thi" - -#: judge/views/course.py:549 -#, fuzzy -#| msgid "Added from site" -msgid "Added from course" -msgstr "Thêm từ web" - -#: judge/views/course.py:569 -#, fuzzy -#| msgid "Contests" -msgid "Contest list" -msgstr "Kỳ thi" - -#: judge/views/course.py:691 -#, fuzzy -#| msgid "Out contest" -msgid "Edit contest" -msgstr "Ngoài kỳ thi" - -#: judge/views/course.py:695 -#, fuzzy -#| msgid "Edited from site" -msgid "Edited from course" -msgstr "Chỉnh sửa từ web" - -#: judge/views/course.py:717 -#, fuzzy, python-format -#| msgid "Grades in %(course_name)s" -msgid "Edit %(contest_name)s" -msgstr "Điểm trong %(course_name)s" - -#: judge/views/custom_file_upload.py:42 -msgid "File Upload" -msgstr "Tải file lên" - -#: judge/views/email.py:21 -msgid "New Email" -msgstr "Email mới" - -#: judge/views/email.py:31 -msgid "An account with this email already exists." -msgstr "Email đã được dùng cho tài khoản khác." - -#: judge/views/email.py:55 -msgid "Email Change Request" -msgstr "Thay đổi Email" - -#: judge/views/email.py:58 -msgid "" -"We have received a request to change your email to this email. Click the " -"button below to change your email:" -msgstr "" -"Chúng tôi đã nhận được yêu cầu thay đổi địa chỉ email của bạn thành địa chỉ " -"email này. Vui lòng nhấp vào nút bên dưới để thay đổi địa chỉ email của bạn:" - -#: judge/views/email.py:60 -msgid "Email Change" -msgstr "Thay đổi Email" - -#: judge/views/email.py:61 -msgid "Change Email" -msgstr "Thay đổi Email" - -#: judge/views/email.py:83 templates/user/edit-profile.html:127 -msgid "Change email" -msgstr "Thay đổi email" - -#: judge/views/email.py:106 -msgid "Success" -msgstr "Thành công" - -#: judge/views/email.py:110 -msgid "Invalid" -msgstr "Không hợp lệ" - -#: judge/views/email.py:119 -msgid "Email change pending" -msgstr "Yêu cầu thay đổi email đang đợi xác thực." - -#: judge/views/error.py:17 +#: judge/views/error.py:14 msgid "404 error" -msgstr "Lỗi 404" +msgstr "lỗi 404" -#: judge/views/error.py:18 +#: judge/views/error.py:15 #, python-format msgid "Could not find page \"%s\"" msgstr "Không thể tìm thấy trang \"%s\"" -#: judge/views/error.py:29 +#: judge/views/error.py:22 #, python-format msgid "no permission for %s" -msgstr "không có quyền cho %s" +msgstr "không cho phép %s" -#: judge/views/error.py:41 +#: judge/views/error.py:30 #, python-format msgid "corrupt page %s" -msgstr "trang bị sập %s" - -#: judge/views/internal.py:24 -#, fuzzy -#| msgid "contest problems" -msgid "Internal problems" -msgstr "bài trong kỳ thi" - -#: judge/views/internal.py:106 -#, fuzzy -#| msgid "request time" -msgid "Request times" -msgstr "thời gian đăng ký" +msgstr "trang lỗi %s" #: judge/views/language.py:12 templates/status/judge-status-table.html:9 -#: templates/status/status-tabs.html:5 msgid "Runtimes" -msgstr "Runtimes" +msgstr "Đang chạy" -#: judge/views/markdown_editor.py:12 -msgid "Markdown Editor" -msgstr "" - -#: judge/views/notification.py:32 -#, python-format -msgid "Notifications (%d unseen)" -msgstr "Thông báo (%d chưa xem)" - -#: judge/views/organization.py:157 judge/views/organization.py:164 +#: judge/views/organization.py:44 judge/views/organization.py:47 msgid "No such organization" msgstr "Không có tổ chức như vậy" -#: judge/views/organization.py:158 +#: judge/views/organization.py:45 #, python-format msgid "Could not find an organization with the key \"%s\"." -msgstr "Không tìm thấy tổ chức với mã \"%s\"." +msgstr "Không thể tìm thấy một tổ chức với khóa \"%s\"." -#: judge/views/organization.py:165 +#: judge/views/organization.py:48 msgid "Could not find such organization." -msgstr "" +msgstr "Không thể tìm thấy các tổ chức như vậy." -#: judge/views/organization.py:189 -msgid "Can't edit organization" -msgstr "Không thể chỉnh sửa tổ chức" +#: judge/views/organization.py:72 judge/views/register.py:34 +#: templates/organization/list.html:15 +msgid "Organizations" +msgstr "Tổ chức" -#: judge/views/organization.py:190 -msgid "You are not allowed to edit this organization." -msgstr "Bạn không được phép chỉnh sửa tổ chức này." - -#: judge/views/organization.py:202 judge/views/organization.py:400 -msgid "Can't access organization" -msgstr "Không thể truy cập nhóm" - -#: judge/views/organization.py:203 judge/views/organization.py:401 -msgid "You are not allowed to access this organization." -msgstr "Bạn không được phép chỉnh sửa tổ chức này." - -#: judge/views/organization.py:248 judge/views/stats.py:184 -#: templates/contest/list.html:78 templates/problem/list-base.html:90 -#: templates/stats/site.html:33 templates/user/user-list-tabs.html:6 -msgid "Groups" -msgstr "Nhóm" - -#: judge/views/organization.py:316 -msgid "Member count (asc.)" -msgstr "Số lượng thành viên (tăng)" - -#: judge/views/organization.py:317 -msgid "Member count (desc.)" -msgstr "Số lượng thành viên (giảm)" - -#: judge/views/organization.py:407 +#: judge/views/organization.py:93 #, python-format msgid "%s Members" -msgstr "%s Thành viên" +msgstr "%s thành viên" -#: judge/views/organization.py:529 -#, python-brace-format -msgid "All submissions in {0}" -msgstr "Bài nộp trong {0}" +#: judge/views/organization.py:118 judge/views/organization.py:121 +#: judge/views/organization.py:126 +msgid "Joining organization" +msgstr "Đang tham gia tổ chức" -#: judge/views/organization.py:537 judge/views/submission.py:858 -msgid "Submissions in" -msgstr "Bài nộp trong" +#: judge/views/organization.py:118 +msgid "You are already in the organization." +msgstr "Bạn đã trong tổ chức." -#: judge/views/organization.py:562 judge/views/organization.py:568 -#: judge/views/organization.py:575 -msgid "Joining group" -msgstr "Tham gia nhóm" +#: judge/views/organization.py:121 +msgid "This organization is not open." +msgstr "Tổ chức này không phải là mở." -#: judge/views/organization.py:563 -msgid "You are already in the group." -msgstr "Bạn đã ở trong nhóm." +#: judge/views/organization.py:138 +msgid "Leaving organization" +msgstr "Rời khỏi tổ chức" -#: judge/views/organization.py:568 -msgid "This group is not open." -msgstr "Nhóm này là nhóm kín." - -#: judge/views/organization.py:576 -#, python-brace-format -msgid "You may not be part of more than {count} public groups." -msgstr "Bạn không thể tham gia nhiều hơn {count} nhóm công khai." - -#: judge/views/organization.py:591 -msgid "Leaving group" -msgstr "Rời nhóm" - -#: judge/views/organization.py:592 +#: judge/views/organization.py:138 #, python-format msgid "You are not in \"%s\"." -msgstr "Bạn không ở trong \"%s\"." +msgstr "Bạn đang không ở trong \"%s\"." -#: judge/views/organization.py:617 +#: judge/views/organization.py:162 #, python-format msgid "Request to join %s" -msgstr "Đăng ký tham gia %s" +msgstr "Yêu cầu tham gia %s" -#: judge/views/organization.py:647 +#: judge/views/organization.py:180 msgid "Join request detail" -msgstr "Chi tiết đơn đăng ký" +msgstr "Chi tiết yêu cầu tham gia" -#: judge/views/organization.py:681 -msgid "Manage join requests" -msgstr "Quản lý đơn đăng ký" - -#: judge/views/organization.py:685 +#: judge/views/organization.py:209 #, python-format msgid "Managing join requests for %s" -msgstr "Quản lý đơn đăng ký cho %s" +msgstr "Quản lý các yêu cầu tham gia %s" -#: judge/views/organization.py:725 +#: judge/views/organization.py:240 #, python-format msgid "" "Your organization can only receive %d more members. You cannot approve %d " "users." msgstr "" -"Tổ chức chỉ có thể chứa %d thành viên. Bạn không thể chấp thuận nhiều hơn %d " -"người." +"Tổ chức của bạn có thể chỉ nhận được %d thêm các thành viên. Bạn không thể " +"chấp nhận người dùng %d." -#: judge/views/organization.py:743 +#: judge/views/organization.py:252 #, python-format msgid "Approved %d user." msgid_plural "Approved %d users." -msgstr[0] "Đã chấp thuận %d người." +msgstr[0] "Chấp nhận %d thành viên." -#: judge/views/organization.py:746 +#: judge/views/organization.py:253 #, python-format msgid "Rejected %d user." msgid_plural "Rejected %d users." -msgstr[0] "Đã từ chối %d người." +msgstr[0] "Từ chối %d thành viên." -#: judge/views/organization.py:786 +#: judge/views/organization.py:283 #, python-format -msgid "Add member for %s" -msgstr "Thêm thành viên cho %s" +msgid "Editing %s" +msgstr "Đang chỉnh sửa %s" -#: judge/views/organization.py:802 -#, fuzzy -#| msgid "Edited from site" -msgid "Added members from site" -msgstr "Chỉnh sửa từ web" +#: judge/views/organization.py:307 judge/views/organization.py:315 +msgid "Can't edit organization" +msgstr "Không thể chỉnh sửa tổ chức" -#: judge/views/organization.py:822 judge/views/organization.py:830 -#: judge/views/organization.py:839 +#: judge/views/organization.py:308 +msgid "You are not allowed to edit this organization." +msgstr "Bạn không có quyền chỉnh sửa tổ chức này." + +#: judge/views/organization.py:316 +msgid "You are not allowed to kick people from this organization." +msgstr "Bạn không có quyền loại người từ tổ chức này." + +#: judge/views/organization.py:321 judge/views/organization.py:325 msgid "Can't kick user" -msgstr "Không thể đuổi" +msgstr "Không thể loại thành viên" -#: judge/views/organization.py:823 +#: judge/views/organization.py:322 msgid "The user you are trying to kick does not exist!" -msgstr "" +msgstr "Thành viên bạn muốn loại không tồn tại!" -#: judge/views/organization.py:831 +#: judge/views/organization.py:326 #, python-format msgid "The user you are trying to kick is not in organization: %s." -msgstr "" +msgstr "Thành viên mà bạn muốn loại không thuộc tổ chức: %s." -#: judge/views/organization.py:840 -#, fuzzy -#| msgid "Are you sure you want to leave this organization?" -msgid "The user you are trying to kick is an organization admin." -msgstr "Bạn có chắc muốn rời tổ chức?" - -#: judge/views/organization.py:845 -#, fuzzy -#| msgid "Add members" -msgid "Kicked member" -msgstr "Thêm thành viên" - -#: judge/views/organization.py:865 judge/views/organization.py:1024 -#, python-format -msgid "Edit %s" -msgstr "Chỉnh sửa %s" - -#: judge/views/organization.py:893 templates/organization/search-form.html:19 -msgid "Create group" -msgstr "Tạo nhóm" - -#: judge/views/organization.py:908 -msgid "Exceeded limit" -msgstr "" - -#: judge/views/organization.py:909 -#, python-format -msgid "You created too many groups. You can only create at most %d groups" -msgstr "" - -#: judge/views/organization.py:914 judge/views/organization.py:939 -#: judge/views/organization.py:1093 -msgid "Added from site" -msgstr "Thêm từ web" - -#: judge/views/organization.py:973 judge/views/organization.py:1140 -msgid "Permission denied" -msgstr "Truy cập bị từ chối" - -#: judge/views/organization.py:974 -#, fuzzy -#| msgid "You are not allowed to edit this organization." -msgid "You are not allowed to edit this contest" -msgstr "Bạn không được phép chỉnh sửa tổ chức này." - -#: judge/views/organization.py:1028 templates/blog/blog.html:31 -#: templates/comments/content-list.html:53 -#: templates/comments/content-list.html:66 -#: templates/contest/contest-tabs.html:36 templates/contest/macros.html:14 -#: templates/contest/tag-title.html:9 templates/course/contest_list.html:25 -#: templates/flatpages/admin_link.html:3 templates/license.html:10 -#: templates/organization/blog/pending.html:56 -#: templates/problem/editorial.html:15 templates/problem/feed/items.html:50 -#: templates/test_formatter/download_test_formatter.html:83 -msgid "Edit" -msgstr "Chỉnh sửa" - -#: judge/views/organization.py:1082 -#, python-format -msgid "Add blog for %s" -msgstr "Thêm bài đăng cho %s" - -#: judge/views/organization.py:1134 -#, fuzzy -#| msgid "Those who can edit this organization" -msgid "This blog does not belong to this organization" -msgstr "Những người có thể chỉnh sửa tổ chức" - -#: judge/views/organization.py:1136 -msgid "Not allowed to edit this blog" -msgstr "Bạn không được phép chỉnh sửa bài đăng này." - -#: judge/views/organization.py:1193 -#, python-format -msgid "Edit blog %s" -msgstr "Chỉnh sửa %s" - -#: judge/views/organization.py:1239 -#, python-format -msgid "Pending blogs in %s" -msgstr "Bài đang đợi duyệt trong %s" - -#: judge/views/problem.py:135 +#: judge/views/problem.py:68 msgid "No such problem" -msgstr "Không có bài nào như vậy" +msgstr "Không có vấn đề như vậy" -#: judge/views/problem.py:136 +#: judge/views/problem.py:69 #, python-format msgid "Could not find a problem with the code \"%s\"." -msgstr "Không tìm thấy bài tập với mã bài \"%s\"." +msgstr "Không thể tìm thấy một đề bài với mã \"%s\"." -#: judge/views/problem.py:203 +#: judge/views/problem.py:111 #, python-brace-format msgid "Editorial for {0}" -msgstr "Hướng dẫn cho {0}" +msgstr "Hướng giải của {0}" -#: judge/views/problem.py:207 +#: judge/views/problem.py:114 #, python-brace-format msgid "Editorial for {0}" -msgstr "Hướng dẫn cho {0}" +msgstr "Hướng giải của {0}" -#: judge/views/problem.py:460 templates/contest/contest.html:117 -#: templates/course/lesson.html:14 -#: templates/organization/org-left-sidebar.html:4 -#: templates/profile-table.html:25 templates/user/user-about.html:28 -#: templates/user/user-bookmarks.html:16 templates/user/user-tabs.html:5 -#: templates/user/users-table.html:19 +#: judge/views/problem.py:286 templates/contest/contest.html:79 +#: templates/user/users-table.html:23 msgid "Problems" -msgstr "Bài tập" +msgstr "Đề bài" -#: judge/views/problem.py:842 -msgid "Problem feed" -msgstr "Bài tập" - -#: judge/views/problem.py:1046 judge/views/problem.py:1079 -msgid "

You have submitted too many submissions.

" -msgstr "

Bạn nộp quá nhiều bài.

" - -#: judge/views/problem.py:1058 +#: judge/views/problem.py:547 msgid "Banned from submitting" -msgstr "Bị cấm nộp bài" +msgstr "" -#: judge/views/problem.py:1060 +#: judge/views/problem.py:548 msgid "" "You have been declared persona non grata for this problem. You are " "permanently barred from submitting this problem." -msgstr "Bạn đã bị cấm nộp bài này." +msgstr "" +"Bạn đã được coi là cá nhận không tính điểm cho đề này. Bạn không thể nộp bài." -#: judge/views/problem.py:1098 +#: judge/views/problem.py:562 msgid "Too many submissions" -msgstr "Quá nhiều lần nộp" +msgstr "Quá nhiều bài nộp" -#: judge/views/problem.py:1100 +#: judge/views/problem.py:563 msgid "You have exceeded the submission limit for this problem." -msgstr "Bạn đã vượt quá số lần nộp cho bài này." +msgstr "Bạn đã vượt quá giới hạn lần nộp của bài này." -#: judge/views/problem.py:1185 judge/views/problem.py:1190 +#: judge/views/problem.py:633 judge/views/problem.py:636 #, python-format msgid "Submit to %(problem)s" -msgstr "Nộp bài cho %(problem)s" +msgstr "Nộp lời giải cho %(problem)s" -#: judge/views/problem.py:1217 +#: judge/views/problem.py:652 msgid "Clone Problem" msgstr "Nhân bản bài tập" -#: judge/views/problem_data.py:71 +#: judge/views/problem_data.py:37 msgid "Checker arguments must be a JSON object" -msgstr "" +msgstr "Đối số kiểm tra phải là đối tượng JSON" -#: judge/views/problem_data.py:73 +#: judge/views/problem_data.py:39 msgid "Checker arguments is invalid JSON" -msgstr "" +msgstr "Đối số kiểm tra là đối tượng JSON không hợp lệ" -#: judge/views/problem_data.py:80 +#: judge/views/problem_data.py:46 msgid "Your zip file is invalid!" -msgstr "File Zip không hợp lệ!" +msgstr "File nén bị lỗi!" -#: judge/views/problem_data.py:170 +#: judge/views/problem_data.py:107 #, python-brace-format msgid "Comparing submissions for {0}" msgstr "So sánh các bài nộp cho {0}" -#: judge/views/problem_data.py:174 +#: judge/views/problem_data.py:110 #, python-brace-format msgid "Comparing submissions for {0}" msgstr "So sánh các bài nộp cho {0}" -#: judge/views/problem_data.py:211 +#: judge/views/problem_data.py:145 #, python-brace-format msgid "Editing data for {0}" -msgstr "Chỉnh sửa dữ liệu cho {0}" +msgstr "Sửa dữ liệu cho {0}" -#: judge/views/problem_data.py:215 +#: judge/views/problem_data.py:148 #, python-format msgid "Editing data for %s" -msgstr "Chỉnh sửa dữ liệu cho %s" +msgstr "Chỉnh sửa các dữ liệu cho %s" -#: judge/views/problem_data.py:348 judge/views/problem_data.py:350 +#: judge/views/problem_data.py:240 judge/views/problem_data.py:241 #, python-format msgid "Generated init.yml for %s" -msgstr "File init.yml cho %s" +msgstr "Tạo file Init.yml cho %s" -#: judge/views/problem_manage.py:57 judge/views/problem_manage.py:61 +#: judge/views/problem_manage.py:50 judge/views/problem_manage.py:53 #, python-format msgid "Managing submissions for %s" -msgstr "Quản lý bài nộp cho %s" +msgstr "Quản lí các bài nộp cho %s" -#: judge/views/problem_manage.py:127 +#: judge/views/problem_manage.py:95 #, python-format msgid "Rejudging selected submissions for %s..." -msgstr "Đang chấm lại các bài nộp cho %s..." +msgstr "Chấm lại các bài nộp đã chọn cho %s..." -#: judge/views/problem_manage.py:187 +#: judge/views/problem_manage.py:110 #, python-format msgid "Rescoring all submissions for %s..." -msgstr "Đang tính điểm lại các bài nộp cho %s..." +msgstr "Tính lại điểm cho %s..." -#: judge/views/problem_manage.py:202 +#: judge/views/problem_manage.py:119 #, python-format msgid "Successfully scheduled %d submission for rejudging." msgid_plural "Successfully scheduled %d submissions for rejudging." -msgstr[0] "Đã lên lịch chấm lại cho %d bài nộp." +msgstr[0] "" -#: judge/views/ranked_submission.py:68 +#: judge/views/ranked_submission.py:58 #, python-format msgid "Best solutions for %s" -msgstr "Các bài nộp tốt nhất cho %s" +msgstr "Các giải pháp tốt nhất cho %s" -#: judge/views/ranked_submission.py:72 +#: judge/views/ranked_submission.py:61 #, python-brace-format msgid "Best solutions for {0}" -msgstr "Các bài nộp tốt nhất cho {0}" +msgstr "Các giải pháp tốt nhất cho {0}" -#: judge/views/register.py:30 templates/course/grades.html:80 -#: templates/course/grades_lesson.html:81 -#: templates/registration/registration_form.html:34 -#: templates/user/base-users-table.html:5 -#: templates/user/import/table_csv.html:4 -msgid "Username" -msgstr "Tên đăng nhập" +#: judge/views/ranked_submission.py:71 +#, python-format +msgid "Best solutions for %(problem)s in %(contest)s" +msgstr "Các giải pháp tốt nhất cho %(problem)s trong %(contest)s" -#: judge/views/register.py:42 templates/user/edit-profile.html:151 +#: judge/views/ranked_submission.py:74 +#, python-format +msgid "Best solutions for problem %(number)s in %(contest)s" +msgstr "Những lời giải tốt nhất cho bài %(number)s trong cuộc thi %(contest)s" + +#: judge/views/ranked_submission.py:80 +#, python-brace-format +msgid "Best solutions for {0} in {2}" +msgstr "" +"Các giải pháp tốt nhất cho {0} trong {2}" +"" + +#: judge/views/ranked_submission.py:83 +#, python-brace-format +msgid "Best solutions for problem {0} in {1}" +msgstr "Những lời giải tốt nhất cho bài {0} trong {1}" + +#: judge/views/register.py:27 +msgid "A username must contain letters, numbers, or underscores" +msgstr "Tên người dùng phải chứa chữ cái, số hoặc dấu gạch chân" + +#: judge/views/register.py:31 templates/user/edit-profile.html:110 msgid "Preferred language" msgstr "Ngôn ngữ ưa thích" -#: judge/views/register.py:54 +#: judge/views/register.py:38 +msgid "Subscribe to newsletter?" +msgstr "Đăng ký nhận bản tin?" + +#: judge/views/register.py:45 #, python-format msgid "" "The email address \"%s\" is already taken. Only one registration is allowed " "per address." msgstr "" -"Email \"%s\" đã được sử dụng. Mỗi email chỉ có thể đăng ký một tài khoản." +"Địa chỉ email \"%s\" đã được sử dụng. Chỉ có một đăng ký được cho phép cho " +"mỗi địa chỉ mail." -#: judge/views/register.py:66 +#: judge/views/register.py:51 msgid "" "Your email provider is not allowed due to history of abuse. Please use a " "reputable email provider." msgstr "" -"Your email provider is not allowed due to history of abuse. Please use a " -"reputable email provider." +"Nhà cung cấp email của bạn không được phép do phát tán thư rác. Xin vui lòng " +"sử dụng một nhà cung cấp email có uy tín." -#: judge/views/register.py:74 judge/views/register.py:111 +#: judge/views/register.py:57 judge/views/register.py:95 msgid "Registration" msgstr "Đăng ký" -#: judge/views/register.py:125 +#: judge/views/register.py:106 msgid "Authentication failure" -msgstr "Xác thực thất bại" +msgstr "Xác thực không thành công" -#: judge/views/resolver.py:11 templates/contest/contest-tabs.html:27 -#, fuzzy -#| msgid "solve rate" -msgid "Resolver" -msgstr "Tỉ lệ giải đúng" - -#: judge/views/stats.py:105 +#: judge/views/stats.py:67 msgid "Language statistics" -msgstr "Thống kê ngôn ngữ" +msgstr "Thống kê theo ngôn ngữ" -#: judge/views/stats.py:154 templates/contest/contest-tabs.html:22 -#: templates/organization/org-left-sidebar.html:6 templates/stats/site.html:15 -#: templates/user/user-tabs.html:6 -msgid "Submissions" -msgstr "Bài nộp" - -#: judge/views/stats.py:160 templates/comments/list.html:4 -#: templates/stats/site.html:39 -msgid "Comments" -msgstr "Bình luận" - -#: judge/views/stats.py:172 templates/stats/site.html:45 -#, fuzzy -#| msgid "New message(s)" -msgid "Chat messages" -msgstr "Tin nhắn mới" - -#: judge/views/stats.py:193 -#, fuzzy -#| msgid "Statistics" -msgid "Site statistics" -msgstr "Thống kê" - -#: judge/views/status.py:26 templates/submission/list.html:336 +#: judge/views/status.py:24 templates/submission/list.html:313 msgid "Status" -msgstr "Kết quả chấm" +msgstr "Trạng thái" -#: judge/views/status.py:119 +#: judge/views/status.py:107 msgid "Version matrix" msgstr "Ma trận phiên bản" -#: judge/views/submission.py:99 judge/views/submission.py:107 +#: judge/views/submission.py:83 judge/views/submission.py:90 #, python-format msgid "Submission of %(problem)s by %(user)s" -msgstr "Bài nộp của %(user)s cho bài %(problem)s" +msgstr "Nộp %(problem)s bởi %(user)s" -#: judge/views/submission.py:291 judge/views/submission.py:292 -#: templates/problem/problem.html:192 +#: judge/views/submission.py:227 judge/views/submission.py:228 +#: templates/problem/problem.html:127 msgid "All submissions" -msgstr "Tất cả bài nộp" +msgstr "Tất cả các bài nộp" -#: judge/views/submission.py:569 judge/views/submission.py:574 +#: judge/views/submission.py:384 msgid "All my submissions" -msgstr "Tất cả bài nộp của tôi" +msgstr "Tất cả những lần nộp bài của tôi" -#: judge/views/submission.py:570 +#: judge/views/submission.py:385 #, python-format msgid "All submissions by %s" -msgstr "Tất cả bài nộp của %s" +msgstr "Tất cả các bài nộp bởi %s" -#: judge/views/submission.py:576 -#, python-brace-format -msgid "All submissions by {0}" -msgstr "Tất cả bài nộp của {0}" - -#: judge/views/submission.py:599 -#, fuzzy -#| msgid "All submissions" -msgid "All friend submissions" -msgstr "Tất cả bài nộp" - -#: judge/views/submission.py:628 +#: judge/views/submission.py:416 #, python-format msgid "All submissions for %s" -msgstr "Tất cả bài nộp cho %s" +msgstr "Tất cả các bài nộp bởi %s" -#: judge/views/submission.py:656 +#: judge/views/submission.py:435 msgid "Must pass a problem" -msgstr "Phải làm được một bài" +msgstr "Phải giải được 1 bài" -#: judge/views/submission.py:714 +#: judge/views/submission.py:481 #, python-format msgid "My submissions for %(problem)s" -msgstr "Bài nộp của tôi cho %(problem)s" +msgstr "Các bài nộp của tôi cho %(problem)s" -#: judge/views/submission.py:715 +#: judge/views/submission.py:482 #, python-format msgid "%(user)s's submissions for %(problem)s" -msgstr "Các bài nộp của %(user)s cho %(problem)s" +msgstr "bài nộp của %(user)s cho %(problem)s" -#: judge/views/submission.py:838 +#: judge/views/submission.py:583 msgid "Must pass a contest" -msgstr "Phải qua một kỳ thi" +msgstr "Phải vượt qua một cuộc thi" -#: judge/views/submission.py:862 -#, python-brace-format -msgid "Submissions in {1}" -msgstr "Bài nộp trong {1}" - -#: judge/views/submission.py:900 +#: judge/views/submission.py:602 #, python-brace-format msgid "" -"{0}'s submissions for {2} in {4}" +"{0}'s submissions for {2} in {4}" msgstr "" -"Các bài nộp của {0} cho {2} trong {4}" +"{0} gửi cho {2} trong {4}" -#: judge/views/submission.py:912 +#: judge/views/submission.py:609 #, python-brace-format msgid "" "{0}'s submissions for problem {2} in {3}" "" msgstr "" -"Các bài nộp của {0} cho bài {2} trong {3}" -"" -#: judge/views/submission.py:1046 -msgid "You don't have permission to access." -msgstr "Bạn không có quyền truy cập." - -#: judge/views/test_formatter/test_formatter.py:64 -#: judge/views/test_formatter/test_formatter.py:107 -#: judge/views/test_formatter/test_formatter.py:190 -#, fuzzy -#| msgid "contest format" -msgid "Test Formatter" -msgstr "format kỳ thi" - -#: judge/views/ticket.py:60 judge/views/ticket.py:66 +#: judge/views/ticket.py:33 judge/views/ticket.py:39 msgid "Ticket title" -msgstr "Tiêu đề báo cáo" +msgstr "" -#: judge/views/ticket.py:124 judge/views/ticket.py:128 +#: judge/views/ticket.py:40 +msgid "Issue description" +msgstr "" + +#: judge/views/ticket.py:85 judge/views/ticket.py:88 #, python-format msgid "New ticket for %s" -msgstr "Báo cáo mới cho %s" +msgstr "" -#: judge/views/ticket.py:205 +#: judge/views/ticket.py:142 #, python-format msgid "%(title)s - Ticket %(id)d" -msgstr "%(title)s - Báo cáo %(id)d" +msgstr "" -#: judge/views/ticket.py:334 +#: judge/views/ticket.py:251 #, python-format msgid "Tickets - Page %(number)d of %(total)d" -msgstr "Báo cáo - Trang %(number)d trên %(total)d" +msgstr "" -#: judge/views/ticket.py:400 +#: judge/views/ticket.py:300 #, python-format msgid "New Ticket: %s" -msgstr "Báo cáo mới: %s" +msgstr "" -#: judge/views/ticket.py:403 +#: judge/views/ticket.py:301 #, python-format msgid "#%(id)d, assigned to: %(users)s" -msgstr "#%(id)d, được phân cho: %(users)s" +msgstr "" -#: judge/views/ticket.py:407 +#: judge/views/ticket.py:303 msgid ", " -msgstr ", " +msgstr "" -#: judge/views/ticket.py:412 +#: judge/views/ticket.py:303 msgid "no one" -msgstr "không người nào" +msgstr "không có ai" -#: judge/views/ticket.py:439 +#: judge/views/ticket.py:323 #, python-format msgid "New Ticket Message For: %s" -msgstr "Tin nhắn báo cáo mới cho: %s" +msgstr "" #: judge/views/totp.py:42 templates/registration/totp_enable.html:86 msgid "Enable Two Factor Authentication" -msgstr "Kích hoạt Two Factor Authentication" +msgstr "Bật Xác thực Hai Yếu tố" -#: judge/views/totp.py:93 templates/registration/totp_disable.html:48 +#: judge/views/totp.py:89 templates/registration/totp_disable.html:48 msgid "Disable Two Factor Authentication" -msgstr "Hủy kích hoạt Two Factor Authentication" +msgstr "" -#: judge/views/totp.py:109 +#: judge/views/totp.py:105 msgid "Perform Two Factor Authentication" -msgstr "Thực hiện Two Factor Authentication" +msgstr "" -#: judge/views/user.py:115 +#: judge/views/user.py:68 msgid "No such user" -msgstr "Không người dùng nào như vậy" +msgstr "Không có thư mục này" -#: judge/views/user.py:116 +#: judge/views/user.py:68 #, python-format msgid "No user handle \"%s\"." -msgstr "Không tồn tại tên người dùng \"%s\"." +msgstr "Không xử lý người dùng \"%s\"." -#: judge/views/user.py:121 +#: judge/views/user.py:72 msgid "My account" msgstr "Tài khoản của tôi" -#: judge/views/user.py:123 +#: judge/views/user.py:73 #, python-format msgid "User %s" -msgstr "Thành viên %s" +msgstr "Người dùng %s" -#: judge/views/user.py:213 +#: judge/views/user.py:136 msgid "M j, Y, G:i" -msgstr "j M, Y, G:i" - -#: judge/views/user.py:414 -msgid "Updated on site" -msgstr "Được cập nhật trên web" - -#: judge/views/user.py:431 templates/admin/auth/user/change_form.html:14 -#: templates/admin/auth/user/change_form.html:17 -msgid "Edit profile" -msgstr "Chỉnh sửa thông tin" - -#: judge/views/user.py:441 templates/user/user-left-sidebar.html:2 -#: templates/user/user-list-tabs.html:4 -msgid "Leaderboard" -msgstr "Xếp hạng" - -#: judge/views/user.py:541 -msgid "Import Users" msgstr "" -#: judge/views/widgets.py:69 judge/views/widgets.py:85 +#: judge/views/user.py:221 +msgid "Updated on site" +msgstr "Cập Nhật trên trang web" + +#: judge/views/user.py:254 templates/admin/auth/user/change_form.html:14 +#: templates/admin/auth/user/change_form.html:17 templates/base.html:224 +msgid "Edit profile" +msgstr "Chỉnh sửa tiểu sử" + +#: judge/views/user.py:263 +msgid "Leaderboard" +msgstr "" + +#: judge/views/widgets.py:48 judge/views/widgets.py:58 #, python-format msgid "Invalid upstream data: %s" -msgstr "Dữ liệu không hợp lệ: %s" +msgstr "Dữ liệu nguồn không hợp lệ %s" -#: judge/views/widgets.py:99 +#: judge/views/widgets.py:68 msgid "Bad latitude or longitude" -msgstr "Kinh độ / Vĩ độ không hợp lệ" - -#: templates/actionbar/list.html:15 -msgid "Like" -msgstr "Thích" - -#: templates/actionbar/list.html:28 templates/blog/list.html:46 -msgid "Comment" -msgstr "Bình luận" - -#: templates/actionbar/list.html:43 -msgid "Bookmark" -msgstr "Lưu" - -#: templates/actionbar/list.html:50 -msgid "Share" -msgstr "Chia sẻ" - -#: templates/actionbar/list.html:57 -msgid "Report" -msgstr "Báo cáo" - -#: templates/actionbar/media-js.html:116 -msgid "Copied link" -msgstr "Đã sao chép link" +msgstr "Sai tọa độ" #: templates/admin/judge/contest/change_form.html:9 msgid "Are you sure you want to rejudge ALL the submissions?" -msgstr "Bạn có muốn chấm lại tất cả bài nộp?" +msgstr "Bạn có chắc chắn muốn chấm lại TẤT CẢ các bài nộp?" #: templates/admin/judge/contest/change_form.html:17 #: templates/admin/judge/contest/change_form.html:20 msgid "Rate" -msgstr "Rate" +msgstr "Đánh giá" #: templates/admin/judge/contest/change_list.html:9 msgid "Rate all ratable contests" -msgstr "Rate tất cả kỳ thi xếp hạng" +msgstr "Đánh giá các cuộc thi" #: templates/admin/judge/judge/change_form.html:15 #: templates/admin/judge/judge/change_form.html:18 @@ -3893,1730 +2908,926 @@ msgstr "Ngắt kết nối" #: templates/admin/judge/judge/change_form.html:20 #: templates/admin/judge/judge/change_form.html:23 msgid "Terminate" -msgstr "Dừng" +msgstr "Chấm dứt" -#: templates/admin/judge/problem/change_form.html:15 +#: templates/admin/judge/problem/change_form.html:14 msgid "View Submissions" -msgstr "Xem Bài Nộp" +msgstr "Xem các bài nộp" -#: templates/admin/judge/problem/change_form.html:18 +#: templates/admin/judge/problem/change_form.html:17 +#: templates/user/user-base.html:61 msgid "View submissions" -msgstr "Xem bài nộp" - -#: templates/admin/judge/problem/change_form.html:19 -#: templates/admin/judge/problem/change_form.html:22 -msgid "View votes" -msgstr "Xem bình chọn" +msgstr "Xem các bài nộp" #: templates/admin/judge/profile/change_form.html:14 #: templates/admin/judge/profile/change_form.html:17 msgid "Edit user" -msgstr "Chỉnh sửa thông tin" +msgstr "Cập nhật người dùng" #: templates/admin/judge/submission/change_form.html:14 #: templates/admin/judge/submission/change_form.html:17 -#: templates/submission/status.html:148 +#: templates/submission/source.html:34 templates/submission/status.html:67 msgid "Rejudge" msgstr "Chấm lại" -#: templates/base.html:146 -msgid "Chat" -msgstr "Chat" +#: templates/base.html:222 templates/comments/list.html:89 +#: templates/contest/ranking-table.html:39 +#: templates/submission/info-base.html:12 +msgid "Admin" +msgstr "Quản trị" -#: templates/base.html:156 -msgid "Notification" -msgstr "Thông báo" - -#: templates/base.html:183 -msgid "Dark Mode" -msgstr "" - -#: templates/base.html:194 templates/profile-table.html:3 -msgid "Profile" -msgstr "Trang cá nhân" - -#: templates/base.html:203 -msgid "Internal" -msgstr "Nội bộ" - -#: templates/base.html:206 -msgid "Stats" -msgstr "Thống kê" - -#: templates/base.html:210 templates/user/user-tabs.html:11 -msgid "Bookmarks" -msgstr "Đã lưu" - -#: templates/base.html:217 -#, fuzzy -#| msgid "Stop spectating" -msgid "Stop impersonating" -msgstr "Ngừng theo dõi" - -#: templates/base.html:222 +#: templates/base.html:231 msgid "Log out" msgstr "Đăng xuất" -#: templates/base.html:232 +#: templates/base.html:240 #: templates/registration/password_reset_complete.html:4 msgid "Log in" msgstr "Đăng nhập" -#: templates/base.html:233 +#: templates/base.html:241 templates/registration/registration_form.html:177 +msgid "or" +msgstr "hoặc" + +#: templates/base.html:242 msgid "Sign up" msgstr "Đăng ký" -#: templates/base.html:247 +#: templates/base.html:254 msgid "spectating" -msgstr "đang theo dõi" +msgstr "" -#: templates/base.html:259 templates/contest/list.html:111 -msgid "In contest" -msgstr "Trong kỳ thi" - -#: templates/base.html:261 -msgid "Out contest" -msgstr "Ngoài kỳ thi" - -#: templates/base.html:271 +#: templates/base.html:267 msgid "This site works best with JavaScript enabled." +msgstr "Trang web này hoạt động tốt nhất với JavaScript được cho phép." + +#: templates/blog/content.html:13 templates/comments/list.html:68 +#: templates/comments/list.html:83 templates/contest/tag-title.html:9 +#: templates/flatpages/admin_link.html:3 templates/license.html:10 +#: templates/problem/editorial.html:14 +msgid "Edit" +msgstr "Soạn thảo" + +#: templates/blog/list.html:85 +msgid "Blog" msgstr "" -#: templates/blog/blog.html:28 -#, python-format -msgid " posted on %(time)s" -msgstr "đã đăng vào %(time)s" - -#: templates/blog/blog.html:35 templates/contest/contest.html:93 -#: templates/contest/contest.html:97 -msgid "Edit in" -msgstr "Chỉnh sửa trong" - -#: templates/blog/content.html:43 templates/comments/feed.html:18 -#: templates/organization/blog/pending.html:42 -#: templates/problem/feed/items.html:109 templates/ticket/feed.html:26 -#: templates/user/user-bookmarks.html:61 templates/user/user-bookmarks.html:131 -#: templates/user/user-bookmarks.html:180 -msgid "...More" -msgstr "...Xem thêm" - -#: templates/blog/dashboard.html:21 -#, fuzzy, python-format -#| msgid "" -#| "\n" -#| " on %(time)s\n" -#| " " -msgid "" -"\n" -" on %(time)s\n" -" " -msgstr "" -"\n" -" vào %(time)s\n" -" " - -#: templates/blog/list.html:45 -msgid "News" -msgstr "Tin tức" - -#: templates/blog/list.html:48 +#: templates/blog/list.html:87 msgid "Events" msgstr "Sự kiện" -#: templates/blog/list.html:60 -msgid "You have no ticket" -msgstr "Bạn không có báo cáo" +#: templates/blog/list.html:92 +msgid "News" +msgstr "Tin tức" -#: templates/blog/list.html:73 templates/problem/list.html:150 -#: templates/problem/problem.html:448 +#: templates/blog/list.html:130 templates/problem/problem.html:310 msgid "Clarifications" -msgstr "Thông báo" +msgstr "Làm rõ" -#: templates/blog/list.html:78 templates/course/contest_list.html:32 -msgid "Add" -msgstr "Thêm mới" - -#: templates/blog/list.html:98 templates/problem/list.html:172 -#: templates/problem/problem.html:459 +#: templates/blog/list.html:146 templates/problem/problem.html:321 msgid "No clarifications have been made at this time." -msgstr "Không có thông báo nào." +msgstr "Chưa có lời làm rõ nào được đưa ra ở thời điểm này." -#: templates/chat/chat.html:5 templates/chat/chat_js.html:570 -msgid "Chat Box" -msgstr "Chat Box" +#: templates/blog/list.html:154 +msgid "Ongoing contests" +msgstr "Cuộc thi đang diễn ra" -#: templates/chat/chat.html:68 templates/chat/chat_js.html:530 -#: templates/user/base-users-js.html:10 -#: templates/user/base-users-two-col.html:19 -msgid "Search by handle..." -msgstr "Tìm kiếm theo tên..." +#: templates/blog/list.html:172 +msgid "Upcoming contests" +msgstr "Sự kiện sắp tới" -#: templates/chat/chat.html:89 -msgid "Enter your message" -msgstr "Nhập tin nhắn" +#: templates/blog/list.html:189 +msgid "Comment stream" +msgstr "Dòng bình luận" -#: templates/chat/chat.html:90 -msgid "Emoji" -msgstr "" +#: templates/blog/list.html:208 +msgid "New problems" +msgstr "Đề bài mới" -#: templates/chat/chat_js.html:133 -msgid "New message(s)" -msgstr "Tin nhắn mới" +#: templates/blog/list.html:225 +msgid "My open tickets" +msgstr "Thẻ mở của tôi" -#: templates/chat/chat_js.html:440 -msgid "Mute this user and delete all messages?" -msgstr "Mute người dùng này và xóa tất cả tin nhắn chung?" +#: templates/blog/list.html:246 +msgid "New tickets" +msgstr "Thẻ mới" -#: templates/chat/message.html:20 templates/fine_uploader/script.html:25 -#: templates/organization/blog/edit.html:37 -msgid "Delete" -msgstr "Xóa" +#: templates/chat/chat.html:167 +msgid "Your message" +msgstr "Tin nhắn" -#: templates/chat/message.html:25 -msgid "Mute" -msgstr "" +#: templates/comments/list.html:2 +msgid "Comments" +msgstr "Nhận xét" -#: templates/chat/message_list.html:8 -msgid "You are connect now. Say something to start the conversation." -msgstr "Các bạn đã kết nối. Nhắn gì đó để bắt đầu cuộc trò chuyện." - -#: templates/chat/online_status.html:6 -#: templates/chat/user_online_status.html:21 -msgid "Lobby" -msgstr "Sảnh chung" - -#: templates/chat/online_status.html:52 -#: templates/chat/user_online_status.html:39 -msgid "Ignore" -msgstr "Tắt thông báo" - -#: templates/chat/user_online_status.html:26 -#, python-brace-format -msgid "Last online on {time}" -msgstr "Trực tuyến vào {time}" - -#: templates/chat/user_online_status.html:37 -msgid "Unignore" -msgstr "Mở lại thông báo" - -#: templates/chat/user_online_status.html:45 -msgid "users are online" -msgstr "người đang trực tuyến" - -#: templates/comments/content-list.html:11 -#: templates/comments/content-list.html:12 -#: templates/comments/content-list.html:20 -#: templates/comments/content-list.html:21 +#: templates/comments/list.html:18 templates/comments/list.html:27 msgid "Please login to vote" -msgstr "Đăng nhập để vote" +msgstr "Hãy đăng nhập để bình chọn" -#: templates/comments/content-list.html:36 -#, python-format -msgid "edit %(edits)s" -msgstr "chỉnh sửa %(edits)s" - -#: templates/comments/content-list.html:38 templates/comments/media-js.html:67 +#: templates/comments/list.html:51 templates/comments/media-js.html:77 msgid "edited" -msgstr "đã chỉnh sửa" +msgstr "chỉnh sửa" -#: templates/comments/content-list.html:47 templates/notification/list.html:11 +#: templates/comments/list.html:60 msgid "Link" -msgstr "Đường dẫn" +msgstr "Liên kết" -#: templates/comments/content-list.html:57 -#: templates/comments/content-list.html:63 +#: templates/comments/list.html:73 templates/comments/list.html:80 msgid "Reply" msgstr "Phản hồi" -#: templates/comments/content-list.html:70 +#: templates/comments/list.html:86 msgid "Hide" msgstr "Ẩn" -#: templates/comments/content-list.html:85 -#, python-format -msgid "" -"This comment is hidden due to too much negative feedback. Click here " -"to view it." -msgstr "" -"Bình luận bị ẩn vì nhiều phản hồi tiêu cực. Nhấp vào đây để mở." +#: templates/comments/list.html:120 +msgid "There are no comments at the moment." +msgstr "Không có ý kiến tại thời điểm này." -#: templates/comments/content-list.html:102 -msgid "reply" -msgid_plural "replies" -msgstr[0] "phản hồi" - -#: templates/comments/content-list.html:127 -msgid "more comment" -msgid_plural "more comments" -msgstr[0] "bình luận nữa" - -#: templates/comments/list.html:6 -msgid "Write comment" -msgstr "Thêm bình luận" - -#: templates/comments/list.html:12 +#: templates/comments/list.html:126 msgid "New comment" msgstr "Bình luận mới" -#: templates/comments/list.html:26 +#: templates/comments/list.html:140 msgid "Invalid comment body." -msgstr "Nội dung không hợp lệ." +msgstr "Bình luận không hợp lệ." -#: templates/comments/list.html:34 +#: templates/comments/list.html:148 msgid "Post!" msgstr "Đăng!" -#: templates/comments/list.html:44 -msgid "There are no comments at the moment." -msgstr "Không có bình luận nào." - -#: templates/comments/list.html:49 +#: templates/comments/list.html:156 msgid "Comments are disabled on this page." -msgstr "Bình luận bị tắt trong trang này." +msgstr "Bình luận đã bị vô hiệu hóa trên trang này." -#: templates/comments/media-js.html:12 -msgid "Replying to comment" -msgstr "Trả lời bình luận" - -#: templates/comments/media-js.html:62 +#: templates/comments/media-js.html:72 #, python-brace-format msgid "edit {edits}" msgstr "chỉnh sửa {edits}" -#: templates/comments/media-js.html:65 +#: templates/comments/media-js.html:75 msgid "original" -msgstr "original" +msgstr "nguyên bản" #: templates/contest/access_code.html:26 msgid "Invalid access code." -msgstr "Mật khẩu truy cập không hợp lệ." +msgstr "Mã truy cập không hợp lệ." #: templates/contest/access_code.html:29 msgid "Please enter your access code:" -msgstr "Nhập mật khẩu truy cập:" +msgstr "Hãy nhập mã truy cập của bạn:" #: templates/contest/access_code.html:32 msgid "Join Contest" msgstr "Tham gia kỳ thi" -#: templates/contest/calendar.html:11 -msgid "Prev" -msgstr "Trước" - -#: templates/contest/calendar.html:14 -msgid "Today" -msgstr "Hôm nay" - -#: templates/contest/calendar.html:17 -msgid "Next" -msgstr "Tiếp" - -#: templates/contest/calendar.html:22 +#: templates/contest/calendar.html:12 msgid "Sunday" msgstr "Chủ nhật" -#: templates/contest/calendar.html:23 +#: templates/contest/calendar.html:13 msgid "Monday" -msgstr "Thứ hai" +msgstr "Thứ Hai" -#: templates/contest/calendar.html:24 +#: templates/contest/calendar.html:14 msgid "Tuesday" -msgstr "Thứ ba" +msgstr "Thứ Ba" -#: templates/contest/calendar.html:25 +#: templates/contest/calendar.html:15 msgid "Wednesday" msgstr "Thứ tư" -#: templates/contest/calendar.html:26 +#: templates/contest/calendar.html:16 msgid "Thursday" -msgstr "Thứ năm" +msgstr "Thứ Năm" -#: templates/contest/calendar.html:27 +#: templates/contest/calendar.html:17 msgid "Friday" -msgstr "Thứ sáu" +msgstr "Thứ Sáu" -#: templates/contest/calendar.html:28 +#: templates/contest/calendar.html:18 msgid "Saturday" -msgstr "Thứ bảy" +msgstr "Thứ Bảy" -#: templates/contest/clarification.html:52 -#: templates/contest/search-form.html:35 templates/organization/new.html:10 -#: templates/ticket/new.html:38 -msgid "Create" -msgstr "Tạo mới" - -#: templates/contest/clone.html:45 +#: templates/contest/clone.html:37 msgid "Enter a new key for the cloned contest:" -msgstr "Nhập mã kỳ thi cho kỳ thi nhân bản:" +msgstr "Nhập mã mới cho kỳ thi đã nhân bản:" -#: templates/contest/clone.html:55 templates/problem/clone.html:40 +#: templates/contest/clone.html:40 templates/problem/clone.html:40 msgid "Clone!" msgstr "Nhân bản!" -#: templates/contest/contest-datetime.html:6 -#, python-format -msgid "Spectating, contest ends in %(countdown)s." -msgstr "Đang theo dõi, kỳ thi còn %(countdown)s." +#: templates/contest/contest-list-tabs.html:7 +msgid "Prev" +msgstr "Trước" -#: templates/contest/contest-datetime.html:8 -#, python-format -msgid "Participating virtually, %(countdown)s remaining." -msgstr "Đang tham gia ảo, còn %(countdown)s." +#: templates/contest/contest-list-tabs.html:10 +msgid "Today" +msgstr "Hôm nay" -#: templates/contest/contest-datetime.html:10 -msgid "Participating virtually." -msgstr "Đang tham gia ảo." +#: templates/contest/contest-list-tabs.html:13 +msgid "Next" +msgstr "Kế tiếp" -#: templates/contest/contest-datetime.html:14 -#, python-format -msgid "Starting in %(countdown)s." -msgstr "Kỳ thi bắt đầu trong %(countdown)s nữa." - -#: templates/contest/contest-datetime.html:16 -msgid "Contest is over." -msgstr "Kỳ thi đã kết thúc." - -#: templates/contest/contest-datetime.html:20 -#, python-format -msgid "Your time is up! Contest ends in %(countdown)s." -msgstr "Hết giờ! Kỳ thi kết thúc trong %(countdown)s." - -#: templates/contest/contest-datetime.html:22 -#, python-format -msgid "You have %(countdown)s remaining." -msgstr "Bạn còn %(countdown)s." - -#: templates/contest/contest-datetime.html:25 -#, python-format -msgid "Contest ends in %(countdown)s." -msgstr "Kỳ thi kết thúc trong %(countdown)s" - -#: templates/contest/contest-datetime.html:32 -#: templates/contest/contest-datetime.html:36 -msgid "F j, Y, G:i T" -msgstr "G:i T, j F, Y" - -#: templates/contest/contest-datetime.html:32 -#, python-format -msgid "" -"%(time_limit)s window between %(start_time)s and " -"%(end_time)s" -msgstr "" -"Dài %(time_limit)s từ %(start_time)s đến %(end_time)s" - -#: templates/contest/contest-datetime.html:36 -#, python-format -msgid "%(length)s long starting on %(start_time)s" -msgstr "Dài %(length)s bắt đầu từ %(start_time)s" - -#: templates/contest/contest-datetime.html:43 -msgid "Standing was frozen" -msgstr "Bảng điểm đã đóng băng" - -#: templates/contest/contest-datetime.html:43 -msgid "at" -msgstr "lúc" - -#: templates/contest/contest-list-tabs.html:2 -#: templates/problem/search-form.html:75 templates/problem/search-form.html:77 -#: templates/submission/list.html:380 -#: templates/submission/submission-list-tabs.html:4 -msgid "All" -msgstr "Tất cả" - -#: templates/contest/contest-list-tabs.html:3 -msgid "Official" -msgstr "Chính thức" - -#: templates/contest/contest-list-tabs.html:4 -msgid "Calendar" -msgstr "Lịch" - -#: templates/contest/contest-tabs.html:11 -msgid "Info" -msgstr "Thông tin" - -#: templates/contest/contest-tabs.html:13 templates/submission/list.html:362 -msgid "Statistics" -msgstr "Thống kê" - -#: templates/contest/contest-tabs.html:19 -msgid "Rankings" -msgstr "Bảng xếp hạng" - -#: templates/contest/contest-tabs.html:30 -msgid "Final rankings" -msgstr "BXH chung cuộc" - -#: templates/contest/contest-tabs.html:34 -msgid "MOSS" -msgstr "MOSS" - -#: templates/contest/contest.html:36 templates/contest/contest.html:56 +#: templates/contest/contest-tabs.html:37 msgid "Leave contest" -msgstr "Rời kỳ thi" +msgstr "Rời khỏi cuộc thi" -#: templates/contest/contest.html:43 templates/contest/list.html:116 +#: templates/contest/contest-tabs.html:44 templates/contest/list.html:293 msgid "Virtual join" msgstr "Tham gia ảo" -#: templates/contest/contest.html:54 -msgid "Stop spectating" -msgstr "Ngừng theo dõi" - -#: templates/contest/contest.html:62 +#: templates/contest/contest-tabs.html:64 msgid "Spectate contest" -msgstr "Theo dõi kỳ thi" +msgstr "Theo dõi cuộc thi" -#: templates/contest/contest.html:68 +#: templates/contest/contest-tabs.html:70 +#: templates/contest/contest-tabs.html:76 msgid "Join contest" -msgstr "Tham gia kỳ thi" +msgstr "Tham gia cuộc thi" -#: templates/contest/contest.html:77 +#: templates/contest/contest-tabs.html:85 msgid "Login to participate" msgstr "Đăng nhập để tham gia" -#: templates/contest/contest.html:102 -msgid "Clone" -msgstr "Nhân bản" +#: templates/contest/contest.html:59 templates/contest/contest.html:63 +msgid "F j, Y, G:i T" +msgstr "" -#: templates/contest/contest.html:123 +#: templates/contest/contest.html:85 msgid "AC Rate" msgstr "Tỷ lệ AC" -#: templates/contest/contest.html:124 templates/problem/list.html:24 +#: templates/contest/contest.html:86 templates/contest/list.html:153 +#: templates/contest/list.html:195 templates/contest/list.html:271 +#: templates/problem/list.html:212 templates/problem/list.html:238 msgid "Users" -msgstr "Người nộp" +msgstr "Thành viên" -#: templates/contest/contest.html:149 templates/problem/list.html:58 -#: templates/problem/list.html:133 +#: templates/contest/contest.html:111 msgid "Editorial" -msgstr "Hướng dẫn" +msgstr "Hướng dẫn giải" -#: templates/contest/contests_summary.html:36 -msgid "Rank" -msgstr "Rank" - -#: templates/contest/contests_summary.html:37 templates/course/course.html:64 -#: templates/status/language-list.html:34 -#: templates/user/import/table_csv.html:6 -msgid "Name" -msgstr "Tên" - -#: templates/contest/list.html:58 templates/contest/media-js.html:116 +#: templates/contest/list.html:31 templates/contest/media-js.html:9 msgid "Are you sure you want to join?" -msgstr "Bạn có chắc tham gia?" +msgstr "Bạn có chắc bạn muốn tham gia?" -#: templates/contest/list.html:59 +#: templates/contest/list.html:32 msgid "" "Joining a contest for the first time starts your timer, after which it " "becomes unstoppable." msgstr "" -"Tham gia kỳ thi lần đầu sẽ kích hoạt thời gian đếm ngược, không thể dừng lại " -"sau đó." +"Truy cập vào một cuộc thi lần đầu tiên sẽ bắt đầu việc đếm ngược thời gian " +"cuộc thi và không thể dừng lại được." -#: templates/contest/list.html:61 templates/contest/media-js.html:119 -msgid "By joining in this contest, you will automatically leave contest" -msgstr "Khi tham gia kỳ thi này, bạn sẽ tự động rời khỏi kỳ thi" +#: templates/contest/list.html:65 +msgid "hidden" +msgstr "" -#: templates/contest/list.html:122 +#: templates/contest/list.html:70 +msgid "private" +msgstr "" + +#: templates/contest/list.html:84 +msgid "rated" +msgstr "" + +#: templates/contest/list.html:132 msgid "Spectate" -msgstr "Theo dõi" +msgstr "Hóng" -#: templates/contest/list.html:128 templates/organization/home.html:26 -#: templates/organization/list.html:70 +#: templates/contest/list.html:138 msgid "Join" msgstr "Tham gia" -#: templates/contest/list.html:138 -msgid "Active" -msgstr "Đang tham gia" +#: templates/contest/list.html:148 +msgid "Active Contests" +msgstr "" -#: templates/contest/list.html:146 -msgid "Ongoing" -msgstr "Đang diễn ra" +#: templates/contest/list.html:152 templates/contest/list.html:194 +#: templates/contest/list.html:232 templates/contest/list.html:270 +msgid "Contest" +msgstr "Cuộc thi" -#: templates/contest/list.html:153 -msgid "Upcoming" -msgstr "Sắp diễn ra" +#: templates/contest/list.html:190 +msgid "Ongoing Contests" +msgstr "Cuộc thi đang diễn ra" -#: templates/contest/list.html:160 -msgid "Past" -msgstr "Đã diễn ra" +#: templates/contest/list.html:227 +msgid "Upcoming Contests" +msgstr "Sự kiện sắp tới" -#: templates/contest/list.html:181 -#, python-format -msgid "Window ends in %(countdown)s" -msgstr "Cửa số thi còn %(countdown)s" +#: templates/contest/list.html:255 +msgid "There are no scheduled contests at this time." +msgstr "Không có không có cuộc thi dự kiến tại thời điểm này." -#: templates/contest/list.html:184 templates/contest/list.html:222 -#: templates/course/course.html:91 -#, python-format -msgid "Ends in %(countdown)s" -msgstr "Kết thúc trong %(countdown)s" +#: templates/contest/list.html:261 +msgid "Past Contests" +msgstr "Cuộc thi đã qua" -#: templates/contest/list.html:204 -msgid "There is no active contest at this time." -msgstr "Không có kỳ thi nào đang tham gia." - -#: templates/contest/list.html:241 -msgid "There is no ongoing contest at this time." -msgstr "Không có kỳ thi nào đang diễn ra hiện tại." - -#: templates/contest/list.html:275 -msgid "There is no scheduled contest at this time." -msgstr "Không có kỳ thi nào được lên lịch hiện tại." - -#: templates/contest/list.html:307 -msgid "There is no past contest." -msgstr "Không có kỳ thi nào trong quá khứ." - -#: templates/contest/macros.html:8 -msgid "hidden" -msgstr "ẩn" - -#: templates/contest/macros.html:20 -msgid "private" -msgstr "riêng tư" - -#: templates/contest/macros.html:32 -msgid "rated" -msgstr "rated" - -#: templates/contest/macros.html:51 templates/contest/macros.html:58 -#: templates/course/contest_list.html:22 templates/course/course.html:65 -msgid "Start" -msgstr "Bắt đầu" - -#: templates/contest/macros.html:54 templates/course/contest_list.html:23 -#: templates/course/course.html:66 -msgid "End" -msgstr "Kết thúc" - -#: templates/contest/macros.html:62 templates/course/course.html:67 -msgid "Length" -msgstr "Dài" - -#: templates/contest/macros.html:64 templates/course/course.html:97 -#, python-format -msgid "%(time_limit)s" -msgstr "%(time_limit)s" - -#: templates/contest/macros.html:66 templates/course/course.html:99 -#, python-format -msgid "%(duration)s" -msgstr "%(duration)s" - -#: templates/contest/macros.html:84 -#: templates/contest/official-search-form.html:19 -#: templates/problem/list.html:40 templates/problem/search-form.html:72 -#: templates/user/user-problems.html:57 -msgid "Category" -msgstr "Loại" - -#: templates/contest/macros.html:85 -#: templates/contest/official-search-form.html:30 -msgid "Location" -msgstr "Địa điểm" - -#: templates/contest/macros.html:86 -#: templates/contest/official-search-form.html:9 -msgid "Year" -msgstr "Năm" - -#: templates/contest/media-js.html:111 +#: templates/contest/media-js.html:4 msgid "Are you sure you want to leave?" -msgstr "Bạn có chắc muốn rời?" +msgstr "Bạn có chắc bạn muốn bỏ qua?" -#: templates/contest/media-js.html:112 +#: templates/contest/media-js.html:5 msgid "" "You cannot come back to a virtual participation. You will have to start a " "new one." msgstr "" -"Bạn không thể quay lại lần tham gia ảo này. Bạn sẽ phải tham gia ảo lại từ " -"đầu." +"Bạn không thể trở lại với việc tham gia ảo. Bạn phải bắt đầu một tham gia ảo " +"mới." -#: templates/contest/media-js.html:117 +#: templates/contest/media-js.html:10 msgid "" "Joining a contest starts your timer, after which it becomes unstoppable." -msgstr "Tham gia kỳ thi sẽ khởi động đồng hồ đếm ngược, và không thể dừng lại." +msgstr "" +"Truy cập một cuộc thi sẽ bắt đầu đếm ngược thời gian cuộc thi đó, và không " +"thể dừng lại được." -#: templates/contest/moss.html:25 +#: templates/contest/moss.html:28 msgid "Are you sure you want MOSS the contest?" -msgstr "Bạn có chắc muốn MOSS kỳ thi này?" +msgstr "" -#: templates/contest/moss.html:30 +#: templates/contest/moss.html:33 msgid "Are you sure you want to delete the MOSS results?" -msgstr "Bạn có chắc muốn xóa kết quả MOSS?" +msgstr "" -#: templates/contest/moss.html:58 +#: templates/contest/moss.html:60 msgid "No submissions" -msgstr "Không có bài nộp" +msgstr "" -#: templates/contest/moss.html:72 +#: templates/contest/moss.html:74 msgid "Re-MOSS contest" -msgstr "MOSS lại kỳ thi" +msgstr "" -#: templates/contest/moss.html:80 +#: templates/contest/moss.html:82 msgid "Delete MOSS results" -msgstr "Xóa kết quả MOSS" - -#: templates/contest/official-search-form.html:2 -#: templates/contest/search-form.html:2 -msgid "Contest search" -msgstr "Tìm kiếm kỳ thi" - -#: templates/contest/official-search-form.html:6 -#: templates/contest/search-form.html:6 -msgid "Search contests..." -msgstr "Tìm kiếm kỳ thi..." - -#: templates/contest/official-search-form.html:12 -msgid "From" -msgstr "Từ" - -#: templates/contest/official-search-form.html:14 -msgid "To" -msgstr "Đến" - -#: templates/contest/official-search-form.html:41 -#: templates/contest/search-form.html:22 -#: templates/organization/search-form.html:8 -msgid "Order by" -msgstr "Sắp xếp theo" - -#: templates/contest/official-search-form.html:53 -#: templates/contest/search-form.html:33 -#: templates/organization/search-form.html:20 -#: templates/problem/search-form.html:95 templates/submission/list.html:354 -#: templates/ticket/list.html:250 -msgid "Go" -msgstr "Lọc" +msgstr "" #: templates/contest/private.html:5 msgid "This contest is private to specific users." -msgstr "Kỳ thi riêng tư với các thành viên này." +msgstr "" #: templates/contest/private.html:10 msgid "Additionally, only the following organizations may access this contest:" -msgstr "Thêm vào đó, chỉ những tổ chức này mới được tham gia kỳ thi:" +msgstr "" #: templates/contest/private.html:12 msgid "Only the following organizations may access this contest:" -msgstr "Chỉ những tổ chức sau được tham gia kỳ thi:" +msgstr "Chỉ có các tổ chức sau có thể truy cập vào cuộc thi này:" -#: templates/contest/ranking-table.html:43 +#: templates/contest/ranking-table.html:7 +msgid "Organization" +msgstr "Tổ chức" + +#: templates/contest/ranking-table.html:30 msgid "Un-Disqualify" -msgstr "Khôi phục kết quả" +msgstr "" -#: templates/contest/ranking-table.html:46 +#: templates/contest/ranking-table.html:33 msgid "Disqualify" -msgstr "Hủy kết quả" +msgstr "" -#: templates/contest/ranking-table.html:59 -msgid "Fullname" -msgstr "Tên đầy đủ" - -#: templates/contest/ranking-table.html:60 templates/user/edit-profile.html:99 -#: templates/user/import/table_csv.html:7 -msgid "School" -msgstr "Trường" - -#: templates/contest/ranking.html:18 +#: templates/contest/ranking.html:173 +#, fuzzy +#| msgid "Are you sure you want to join?" msgid "Are you sure you want to disqualify this participation?" -msgstr "Bạn có chắc muốn hủy kết quả này?" +msgstr "Bạn có chắc bạn muốn tham gia?" -#: templates/contest/ranking.html:23 +#: templates/contest/ranking.html:178 +#, fuzzy +#| msgid "Are you sure you want to rejudge ALL the submissions?" msgid "Are you sure you want to un-disqualify this participation?" -msgstr "Bạn có chắc muốn khôi phục kết quả này?" +msgstr "Bạn có chắc chắn muốn chấm lại TẤT CẢ các bài nộp?" -#: templates/contest/ranking.html:134 +#: templates/contest/ranking.html:252 msgid "View user participation" -msgstr "Xem các lần tham gia" +msgstr "Xem thành viên tham gia" -#: templates/contest/ranking.html:140 -msgid "Show schools" -msgstr "Hiển thị trường" +#: templates/contest/ranking.html:256 +msgid "Show organizations" +msgstr "Hiển thị các tổ chức" -#: templates/contest/ranking.html:144 -msgid "Show full name" -msgstr "Hiển thị họ tên" - -#: templates/contest/ranking.html:147 -msgid "Show friends only" -msgstr "Chỉ hiển thị bạn bè" - -#: templates/contest/ranking.html:150 -msgid "Total score only" -msgstr "Chỉ hiển thị tổng điểm" - -#: templates/contest/ranking.html:152 -msgid "Show virtual participation" -msgstr "Hiển thị tham gia ảo" - -#: templates/contest/ranking.html:156 -msgid "Download as CSV" -msgstr "Tải file CSV" - -#: templates/contest/search-form.html:10 -msgid "Hide organization contests" -msgstr "Ẩn các kỳ thi riêng tư của nhóm" - -#: templates/contest/stats.html:48 +#: templates/contest/stats.html:38 +#, fuzzy +#| msgid "problem translation" msgid "Problem Status Distribution" -msgstr "Phân bố theo kết quả" +msgstr "dịch đầu bài" -#: templates/contest/stats.html:53 +#: templates/contest/stats.html:43 +#, fuzzy +#| msgid "Problem name" msgid "Problem AC Rate" -msgstr "Tỷ lệ AC" +msgstr "Tên bài" -#: templates/contest/stats.html:59 -msgid "Problem Point Distribution" -msgstr "Phân bố điểm" - -#: templates/contest/stats.html:73 templates/stats/language.html:16 +#: templates/contest/stats.html:48 templates/stats/language.html:16 msgid "Submissions by Language" -msgstr "Số bài nộp theo ngôn ngữ" +msgstr "Bài nộp theo ngôn ngữ" -#: templates/contest/stats.html:79 templates/stats/language.html:26 +#: templates/contest/stats.html:54 templates/stats/language.html:26 msgid "Language AC Rate" -msgstr "Tỷ lệ AC theo ngôn ngữ" - -#: templates/contests-countdown.html:3 -msgid "Ongoing contests" -msgstr "Kỳ thi đang diễn ra" - -#: templates/contests-countdown.html:11 -msgid "Ends in" -msgstr "Còn" - -#: templates/contests-countdown.html:21 -msgid "Upcoming contests" -msgstr "Kỳ thi sắp diễn ra" - -#: templates/course/contest_list.html:29 -msgid "No contests available" -msgstr "Không có kì thi nào!" - -#: templates/course/course.html:33 -msgid "Lessons" -msgstr "Bài học" - -#: templates/course/course.html:68 templates/course/grades.html:81 -#: templates/course/grades_lesson.html:82 templates/user/user-problems.html:99 -msgid "Score" -msgstr "Điểm" - -#: templates/course/course.html:119 -msgid "Total achieved points" -msgstr "Tổng điểm" - -#: templates/course/edit_contest.html:44 templates/course/edit_lesson.html:65 -#: templates/organization/contest/edit.html:41 -#: templates/organization/form.html:6 -msgid "Please fix below errors" -msgstr "Vui lòng sửa các lỗi bên dưới" - -#: templates/course/edit_contest.html:64 -#: templates/organization/contest/edit.html:61 -msgid "If you run out of rows, click Save" -msgstr "Ấn nút lưu lại nếu cần thêm hàng" - -#: templates/course/edit_contest.html:90 templates/course/edit_lesson.html:114 -#: templates/markdown_editor/markdown_editor.html:122 -#: templates/organization/blog/edit.html:36 -#: templates/organization/contest/edit.html:87 -#: templates/organization/form.html:30 templates/pagedown.html:31 -msgid "Save" -msgstr "Lưu" - -#: templates/course/edit_lesson.html:57 -msgid "Add new" -msgstr "Thêm mới" - -#: templates/course/grades.html:78 templates/course/grades_lesson.html:79 -msgid "Sort by" -msgstr "Sắp xếp theo" - -#: templates/course/grades.html:83 templates/course/grades_lesson.html:84 -#: templates/internal/problem/problem.html:34 -msgid "Search" -msgstr "Tìm kiếm" - -#: templates/course/grades.html:89 templates/course/grades_lesson.html:99 -#: templates/submission/user-ajax.html:33 -msgid "Total" -msgstr "Tổng điểm" - -#: templates/course/left_sidebar.html:4 -msgid "Edit lessons" -msgstr "Chỉnh sửa bài học" - -#: templates/course/left_sidebar.html:6 -msgid "Grades" -msgstr "Điểm" - -#: templates/course/list.html:23 -msgid "Teachers" -msgstr "Giáo viên" - -#: templates/custom_file_upload.html:6 -msgid "Your file has been uploaded successfully" -msgstr "File đã được tải lên thành công" - -#: templates/custom_file_upload.html:7 -msgid "Upload another file" -msgstr "Tải file khác lên" - -#: templates/custom_file_upload.html:12 templates/fine_uploader/script.html:7 -msgid "Upload file" -msgstr "Tải file lên" - -#: templates/email_change/email_change.html:15 -msgid "Verify Email" -msgstr "Xác thực Email" - -#: templates/email_change/email_change_failure.html:3 -msgid "Invalid reset link." -msgstr "Đường dẫn không hợp lệ" - -#: templates/email_change/email_change_pending.html:4 -msgid "An email was sent to" -msgstr "Email đã được gửi đến" - -#: templates/email_change/email_change_pending.html:4 -msgid "If you don't see it, kindly check your spam folder as well." -msgstr "Nếu bạn không tìm thấy nó, vui lòng kiểm tra thư mục spam của bạn." - -#: templates/email_change/email_change_success.html:3 -msgid "Your email was sucessfully changed to" -msgstr "Bạn đã đổi email thành công." - -#: templates/feed/has_next.html:3 -msgid "View more" -msgstr "Xem thêm" - -#: templates/fine_uploader/script.html:4 -msgid "Drop files here to upload" -msgstr "Kéo file vào đây để tải lên" - -#: templates/fine_uploader/script.html:23 -#: templates/markdown_editor/markdown_editor.html:123 -#: templates/pagedown.html:32 -msgid "Cancel" -msgstr "Hủy" - -#: templates/fine_uploader/script.html:24 -msgid "Retry" -msgstr "Thử lại" - -#: templates/fine_uploader/script.html:26 -msgid "Pause" -msgstr "Dừng" - -#: templates/fine_uploader/script.html:27 -msgid "Continue" -msgstr "Tiếp tục" - -#: templates/general_email.html:15 -msgid "Dear" -msgstr "Xin chào" - -#: templates/internal/left-sidebar.html:3 -msgid "Average speed" -msgstr "Tốc độ trung bình" - -#: templates/internal/left-sidebar.html:4 -msgid "Slow requests" -msgstr "Requests chậm" - -#: templates/internal/problem/problem.html:42 -msgid "Code" -msgstr "" - -#: templates/internal/problem/problem.html:43 -#, fuzzy -#| msgid "Total points" -msgid "Vote count" -msgstr "Tổng điểm" - -#: templates/internal/problem/votes.html:1 -#, fuzzy -#| msgid "contest problem" -msgid "Votes for problem" -msgstr "bài trong kỳ thi" - -#: templates/internal/problem/votes.html:9 -msgid "Knowledge" -msgstr "" - -#: templates/internal/problem/votes.html:13 -#, fuzzy -#| msgid "Rankings" -msgid "Thinking" -msgstr "Bảng xếp hạng" - -#: templates/internal/problem/votes.html:21 -#: templates/problem/feed/items.html:97 -#, fuzzy -#| msgid "Feed" -msgid "Feedback" -msgstr "Gợi ý" +msgstr "Tỉ lệ AC của ngôn ngữ" #: templates/license.html:12 msgid "Source:" msgstr "Nguồn:" -#: templates/markdown_editor/markdown_editor.html:103 templates/pagedown.html:9 -msgid "Update Preview" -msgstr "Cập nhật xem trước" +#: templates/newsletter/common.html:6 +#: templates/newsletter/subscription_unsubscribe_activated.html:3 +#: templates/newsletter/subscription_unsubscribe_activated.html:6 +#: templates/newsletter/subscription_update_activated.html:3 +#: templates/newsletter/subscription_update_activated.html:6 +msgid "Newsletter" +msgstr "Bản tin" -#: templates/markdown_editor/markdown_editor.html:107 -#: templates/pagedown.html:15 -msgid "Insert Image" -msgstr "Chèn hình ảnh" +#: templates/newsletter/subscription_unsubscribe_activated.html:3 +#: templates/newsletter/subscription_unsubscribe_activated.html:6 +#: templates/newsletter/subscription_update_activated.html:3 +#: templates/newsletter/subscription_update_activated.html:6 +msgid "activate" +msgstr "hoạt động" -#: templates/markdown_editor/markdown_editor.html:110 -#: templates/pagedown.html:18 -msgid "From the web" -msgstr "Từ web" +#: templates/newsletter/subscription_unsubscribe_activated.html:8 +msgid "You have successfully been unsubscribed." +msgstr "Bạn đã bỏ đăng ký thành công." -#: templates/markdown_editor/markdown_editor.html:116 -#: templates/pagedown.html:25 -msgid "From your computer" -msgstr "Từ máy tính của bạn" +#: templates/newsletter/subscription_unsubscribe_email_sent.html:3 +#: templates/newsletter/subscription_unsubscribe_email_sent.html:6 +#: templates/newsletter/subscription_unsubscribe_user.html:3 +#: templates/newsletter/subscription_unsubscribe_user.html:6 +msgid "Newsletter unsubscribe" +msgstr "Bỏ đăng ký bản tin" -#: templates/notification/list.html:5 -msgid "You have no notifications" -msgstr "Bạn không có thông báo" +#: templates/newsletter/subscription_unsubscribe_email_sent.html:8 +msgid "" +"Your unsubscription request has successfully been received. An email has " +"been sent to you with a link you need to follow in order to confirm your " +"unsubscription." +msgstr "" +"Đã nhận yêu cầu hủy đăng ký của bạn. Email đã được gửi cho bạn với một liên " +"kết bạn cần phải làm theo để xác nhận hủy đăng ký." -#: templates/notification/list.html:10 -msgid "Activity" -msgstr "Hoạt động" +#: templates/newsletter/subscription_unsubscribe_user.html:17 +msgid "Do you want to unsubscribe from this newsletter?" +msgstr "Bạn có muốn hủy đăng ký bản tin này?" -#: templates/organization/blog/pending.html:50 -msgid "Approve" -msgstr "Chấp thuận" +#: templates/newsletter/subscription_unsubscribe_user.html:21 +msgid "Unsubscribe" +msgstr "Hủy đăng ký" -#: templates/organization/blog/pending.html:62 -msgid "Reject" -msgstr "Từ chối" +#: templates/newsletter/subscription_update.html:3 +#: templates/newsletter/subscription_update.html:6 +#: templates/newsletter/subscription_update_email_sent.html:3 +#: templates/newsletter/subscription_update_email_sent.html:6 +msgid "Newsletter update" +msgstr "Bản tin Cập Nhật" -#: templates/organization/home-js.html:4 +#: templates/newsletter/subscription_update.html:9 +msgid "" +"Due to a technical error we were not able to submit your confirmation email. " +"This could be because your email address is invalid." +msgstr "" +"Do một lỗi kỹ thuật chúng tôi đã không thể gửi email xác nhận. Điều này có " +"thể bởi vì địa chỉ email không hợp lệ." + +#: templates/newsletter/subscription_update.html:14 +msgid "Update subscription" +msgstr "Cập nhật bài nộp của tôi" + +#: templates/newsletter/subscription_update_activated.html:8 +msgid "Your subscription has successfully been updated." +msgstr "Đăng ký của bạn đã được cập nhật thành công." + +#: templates/newsletter/subscription_update_email_sent.html:8 +msgid "" +"Your update request was successfully received and an activation email has " +"been sent to you. In that email you will find a link which you need to " +"follow in order to update your subscription." +msgstr "" +"Yêu cầu bản Cập Nhật của bạn đã được nhận thành công và kích hoạt email đã " +"được gửi đến bạn. Trong email đó, bạn sẽ tìm thấy một liên kết mà bạn cần " +"phải làm theo để cập nhật đăng ký của bạn." + +#: templates/organization/edit.html:46 +#: templates/organization/requests/pending.html:34 +#: templates/ticket/edit-notes.html:4 +msgid "Update" +msgstr "Cập Nhật" + +#: templates/organization/home.html:7 msgid "Are you sure you want to leave this organization?" -msgstr "Bạn có chắc muốn rời tổ chức?" +msgstr "" -#: templates/organization/home-js.html:6 +#: templates/organization/home.html:9 msgid "You will have to rejoin to show up on the organization leaderboard." -msgstr "Bạn phải tham gia lại để được hiển thị trong bảng xếp hạng tổ chức." +msgstr "" -#: templates/organization/home-js.html:8 +#: templates/organization/home.html:11 msgid "You will have to request membership in order to join again." -msgstr "Bạn phải đăng ký thành viên để được tham gia lại." +msgstr "" -#: templates/organization/home.html:31 templates/organization/list.html:73 +#: templates/organization/home.html:24 +msgid "Leave organization" +msgstr "Rời khỏi tổ chức" + +#: templates/organization/home.html:29 +msgid "Join organization" +msgstr "Tham gia tổ chức" + +#: templates/organization/home.html:33 msgid "Request membership" -msgstr "Đăng ký thành viên" +msgstr "Yêu cầu tư cách thành viên" -#: templates/organization/list.html:38 templates/submission/list.html:382 -#: templates/submission/submission-list-tabs.html:6 -msgid "Mine" -msgstr "Tôi" +#: templates/organization/home.html:39 +msgid "Edit organization" +msgstr "Chỉnh sửa các tổ chức" -#: templates/organization/list.html:40 -msgid "Public" -msgstr "Nhóm mở" - -#: templates/organization/list.html:41 -msgid "Private" -msgstr "Nhóm kín" - -#: templates/organization/list.html:63 -msgid "members" -msgstr "thành viên" - -#: templates/organization/list.html:66 -msgid "View" -msgstr "Xem" - -#: templates/organization/list.html:89 -msgid "You have not joined any organization yet." -msgstr "Bạn chưa tham gia nhóm nào." - -#: templates/organization/list.html:97 -msgid "There is no public organization." -msgstr "Không có nhóm mở nào" - -#: templates/organization/list.html:105 -msgid "There is no private organization." -msgstr "Không có nhóm kín nào" - -#: templates/organization/org-left-sidebar.html:9 -msgid "Members" -msgstr "Thành viên" - -#: templates/organization/org-right-sidebar.html:4 -msgid "Controls" -msgstr "Quản lý" - -#: templates/organization/org-right-sidebar.html:9 -msgid "Edit group" -msgstr "Chỉnh sửa nhóm" - -#: templates/organization/org-right-sidebar.html:15 +#: templates/organization/home.html:43 msgid "View requests" -msgstr "Đơn đăng ký" +msgstr "Xem yêu cầu" -#: templates/organization/org-right-sidebar.html:26 -msgid "Add members" -msgstr "Thêm thành viên" +#: templates/organization/home.html:50 +msgid "Admin organization" +msgstr "Tổ chức người quản trị" -#: templates/organization/org-right-sidebar.html:32 -msgid "Add blog" -msgstr "Thêm bài đăng" +#: templates/organization/home.html:55 +msgid "View members" +msgstr "Xem các thành viên" -#: templates/organization/org-right-sidebar.html:37 -msgid "Pending blogs" -msgstr "Bài đăng đang chờ" +#: templates/organization/list.html:23 templates/status/language-list.html:34 +msgid "Name" +msgstr "Tên" -#: templates/organization/org-right-sidebar.html:53 -msgid "Subdomain" -msgstr "Site riêng cho nhóm" +#: templates/organization/list.html:24 +msgid "Members" +msgstr "Các thành viên" -#: templates/organization/org-right-sidebar.html:62 -msgid "Leave group" -msgstr "Rời nhóm" +#: templates/organization/new.html:10 templates/ticket/new.html:38 +msgid "Create" +msgstr "Tạo" -#: templates/organization/requests/detail.html:6 +#: templates/organization/requests/detail.html:13 msgid "User:" -msgstr "Thành viên:" +msgstr "Người dùng:" -#: templates/organization/requests/detail.html:10 +#: templates/organization/requests/detail.html:17 msgid "Organization:" msgstr "Tổ chức:" -#: templates/organization/requests/detail.html:18 +#: templates/organization/requests/detail.html:25 msgid "Time:" msgstr "Thời gian:" -#: templates/organization/requests/detail.html:22 +#: templates/organization/requests/detail.html:29 msgid "Reason:" -msgstr "Lý do:" +msgstr "Lý Do:" #: templates/organization/requests/log.html:11 -#: templates/organization/requests/pending.html:21 +#: templates/organization/requests/pending.html:14 msgid "State" msgstr "Trạng thái" #: templates/organization/requests/log.html:12 -#: templates/organization/requests/pending.html:22 +#: templates/organization/requests/pending.html:15 msgid "Reason" msgstr "Lý do" #: templates/organization/requests/log.html:28 -#: templates/organization/requests/pending.html:44 +#: templates/organization/requests/pending.html:37 msgid "There are no requests to approve." -msgstr "Không có đơn đăng ký." +msgstr "Không có yêu cầu để chấp nhận." -#: templates/organization/requests/pending.html:24 -#: templates/problem/data.html:538 +#: templates/organization/requests/pending.html:17 +#: templates/problem/data.html:452 msgid "Delete?" -msgstr "Xóa?" - -#: templates/organization/requests/pending.html:41 -#: templates/ticket/edit-notes.html:4 -msgid "Update" -msgstr "Cập nhật" +msgstr "Xoá?" #: templates/organization/requests/request.html:18 msgid "Your reason for joining:" -msgstr "Lý do tham gia:" +msgstr "Lý do của bạn để tham gia:" #: templates/organization/requests/request.html:20 msgid "Request" -msgstr "Đăng ký" +msgstr "Yêu cầu" #: templates/organization/requests/tabs.html:4 msgid "Pending" -msgstr "Đang chờ duyệt" +msgstr "Đang chờ" #: templates/organization/requests/tabs.html:7 msgid "Log" -msgstr "Ghi chép" +msgstr "Nhật ký" #: templates/organization/requests/tabs.html:10 msgid "Approved" -msgstr "Chấp thuận" +msgstr "Phê duyệt" #: templates/organization/requests/tabs.html:13 msgid "Rejected" -msgstr "Từ chối" +msgstr "Bị từ chối" -#: templates/organization/search-form.html:2 -msgid "Organization search" -msgstr "Tìm kiếm nhóm" - -#: templates/organization/search-form.html:6 -msgid "Search organizations..." -msgstr "Tìm kiếm nhóm" - -#: templates/organization/users-table.html:16 +#: templates/organization/users-table.html:15 msgid "Kick" -msgstr "Đuổi" +msgstr "Loại" #: templates/problem/clone.html:37 msgid "Enter a new code for the cloned problem:" -msgstr "Nhập mã bài mới cho bài tập được nhân bản:" +msgstr "" -#: templates/problem/data.html:156 templates/problem/data.html:163 +#: templates/problem/data.html:108 +#, fuzzy +#| msgid "Administration" msgid "Instruction" -msgstr "Hướng dẫn" +msgstr "Quản trị viên" -#: templates/problem/data.html:487 +#: templates/problem/data.html:410 msgid "View YAML" msgstr "Xem YAML" -#: templates/problem/data.html:504 -msgid "Autofill testcases" -msgstr "Tự động điền test" - -#: templates/problem/data.html:508 templates/problem/problem.html:307 -msgid "Problem type" -msgid_plural "Problem types" -msgstr[0] "Dạng bài" - -#: templates/problem/data.html:515 -msgid "Fill testcases" -msgstr "Điền test" - -#: templates/problem/data.html:519 -msgid "Batch start positions" -msgstr "Vị trí bắt đầu nhóm" - -#: templates/problem/data.html:523 -msgid "" -"Leave empty if not use batch. If you want to divide to three batches [1, 4], " -"[5, 8], [9, 10], enter: 1, 5, 9" -msgstr "" -"Để trống nếu không dùng nhóm. Nếu muốn chia test thành các nhóm [1, 4], [5, " -"8], [9, 10], nhập: 1, 5, 9" - -#: templates/problem/data.html:527 templates/problem/data.html:578 +#: templates/problem/data.html:441 templates/problem/data.html:491 msgid "Apply!" -msgstr "Lưu!" +msgstr "" -#: templates/problem/data.html:532 +#: templates/problem/data.html:446 msgid "Type" msgstr "Kiểu" -#: templates/problem/data.html:533 +#: templates/problem/data.html:447 msgid "Input file" -msgstr "File Input" +msgstr "Tập tin đầu vào" -#: templates/problem/data.html:534 +#: templates/problem/data.html:448 msgid "Output file" -msgstr "File Output" +msgstr "Tập tin đầu ra" -#: templates/problem/data.html:536 +#: templates/problem/data.html:450 msgid "Pretest?" -msgstr "Pretest?" +msgstr "Thử sơ bộ?" -#: templates/problem/data.html:579 +#: templates/problem/data.html:492 msgid "Add new case" -msgstr "Thêm test mới" +msgstr "Thêm mới trường hợp" -#: templates/problem/editorial.html:23 +#: templates/problem/editorial.html:22 msgid "" "Remember to use this editorial only when stuck, and not to copy-" "paste code from it. Please be respectful to the problem author and " "editorialist.

Submitting an official solution before solving the " "problem yourself is a bannable offence." msgstr "" -"Chỉ sử dụng khi thực sự cần thiết như một cách tôn trọng tác giả và người " -"viết hướng dẫn này.

Chép code từ bài hướng dẫn để nộp bài là " -"hành vi có thể dẫn đến khóa tài khoản." -#: templates/problem/feed.html:13 -msgid "FOR YOU" -msgstr "DÀNH CHO BẠN" - -#: templates/problem/feed.html:16 -msgid "NEW" -msgstr "MỚI NHẤT" - -#: templates/problem/feed.html:20 -msgid "VOLUNTEER" -msgstr "TÌNH NGUYỆN" - -#: templates/problem/feed.html:27 -msgid "View your votes" -msgstr "Xem các đơn đã điền của bạn" - -#: templates/problem/feed/items.html:43 -msgid "View source" -msgstr "Xem mã nguồn" - -#: templates/problem/feed/items.html:47 -msgid "Volunteer form" -msgstr "Phiếu tình nguyện" - -#: templates/problem/feed/items.html:53 templates/problem/problem.html:148 -#: templates/problem/problem.html:163 templates/problem/problem.html:173 -msgid "Submit" -msgstr "Nộp bài" - -#: templates/problem/feed/items.html:60 -msgid "Value" -msgstr "Giá trị" - -#: templates/problem/feed/items.html:67 -msgid "Knowledge point" -msgstr "Độ khó kiến thức" - -#: templates/problem/feed/items.html:75 -msgid "Thinking point" -msgstr "Độ khó nghĩ" - -#: templates/problem/feed/items.html:83 templates/problem/search-form.html:61 -msgid "Problem types" -msgstr "Dạng bài" - -#: templates/problem/feed/items.html:101 -msgid "Any additional note here" -msgstr "Lưu ý thêm cho admin" - -#: templates/problem/left-sidebar.html:10 -msgid "Feed" -msgstr "Gợi ý" - -#: templates/problem/left-sidebar.html:11 -#: templates/problem/problem-list-tabs.html:5 -msgid "List" -msgstr "Danh sách" - -#: templates/problem/list-base.html:89 +#: templates/problem/list.html:62 msgid "Filter by type..." -msgstr "Lọc theo dạng..." +msgstr "Lọc theo loại..." -#: templates/problem/list-base.html:157 templates/problem/list-base.html:182 -msgid "Add types..." -msgstr "Thêm dạng" +#: templates/problem/list.html:185 +msgid "Hot problems" +msgstr "Những bài tập nổi bật" -#: templates/problem/list-base.html:198 -msgid "Fail to vote!" -msgstr "Hệ thống lỗi!" +#: templates/problem/list.html:207 templates/problem/list.html:224 +#: templates/problem/search-form.html:30 templates/user/user-problems.html:57 +msgid "Category" +msgstr "Thuộc Danh mục" -#: templates/problem/list-base.html:201 -msgid "Successful vote! Thank you!" -msgstr "Đã gửi thành công! Cảm ơn bạn!" +#: templates/problem/list.html:209 templates/problem/list.html:228 +msgid "Types" +msgstr "Kiểu" -#: templates/problem/list.html:51 +#: templates/problem/list.html:235 #, python-format msgid "AC %%" -msgstr "AC %%" - -#: templates/problem/list.html:54 -msgid "AC #" msgstr "" -#: templates/problem/list.html:145 -msgid "Add clarifications" -msgstr "Thêm thông báo" - -#: templates/problem/manage_submission.html:54 +#: templates/problem/manage_submission.html:55 msgid "Leave empty to not filter by language" -msgstr "Để trống nếu không lọc theo ngôn ngữ" +msgstr "" -#: templates/problem/manage_submission.html:59 +#: templates/problem/manage_submission.html:60 msgid "Leave empty to not filter by result" -msgstr "Để trống nếu không lọc theo kết quả" +msgstr "" -#: templates/problem/manage_submission.html:64 -msgid "Leave empty to not filter by contest" -msgstr "Để trống nếu không lọc theo kỳ thi" - -#: templates/problem/manage_submission.html:94 +#: templates/problem/manage_submission.html:79 msgid "Need valid values for both start and end IDs." -msgstr "Cần số liệu hợp lệ cho ID bắt đầu và kết thúc." +msgstr "" -#: templates/problem/manage_submission.html:97 +#: templates/problem/manage_submission.html:82 msgid "End ID must be after start ID." -msgstr "ID kết thúc phải lớn hơn hoặc bằng ID khởi đầu." +msgstr "" -#: templates/problem/manage_submission.html:110 +#: templates/problem/manage_submission.html:90 #, python-brace-format msgid "" -"You are about to {action} {count} submissions. Are you sure you want to do " +"You are about to rejudge {count} submissions. Are you sure you want to do " "this?" -msgstr "Bạn chuẩn bị {action} {count} bài nộp. Tiếp tục?" +msgstr "" -#: templates/problem/manage_submission.html:117 -#, python-brace-format +#: templates/problem/manage_submission.html:96 msgid "" -"You are about to {action} a few submissions. Are you sure you want to do " -"this?" -msgstr "Bạn chuẩn bị {action} vài bài nộp. Tiếp tục?" +"You are about to rejudge a few submissions. Are you sure you want to do this?" +msgstr "" -#: templates/problem/manage_submission.html:141 -#: templates/submission/list.html:332 -msgid "Filter submissions" -msgstr "Lọc bài nộp" +#: templates/problem/manage_submission.html:115 +msgid "Rejudge Submissions" +msgstr "" -#: templates/problem/manage_submission.html:146 +#: templates/problem/manage_submission.html:120 msgid "Filter by ID:" -msgstr "Lọc theo ID:" +msgstr "" -#: templates/problem/manage_submission.html:149 +#: templates/problem/manage_submission.html:123 msgid "Starting ID:" -msgstr "ID bắt đầu:" +msgstr "" -#: templates/problem/manage_submission.html:153 +#: templates/problem/manage_submission.html:127 msgid "Ending ID:" -msgstr "ID kết thúc:" +msgstr "" + +#: templates/problem/manage_submission.html:131 +msgid "This range includes both endpoints." +msgstr "" + +#: templates/problem/manage_submission.html:134 +msgid "Filter by language:" +msgstr "" + +#: templates/problem/manage_submission.html:142 +msgid "Filter by result:" +msgstr "" + +#: templates/problem/manage_submission.html:150 +msgid "Rejudge selected submissions" +msgstr "" #: templates/problem/manage_submission.html:157 -msgid "This range includes both endpoints." -msgstr "Bao gồm hai đầu mút." +msgid "Rescore Everything" +msgstr "" -#: templates/problem/manage_submission.html:160 -msgid "Filter by language:" -msgstr "Lọc theo ngôn ngữ:" - -#: templates/problem/manage_submission.html:168 -msgid "Filter by result:" -msgstr "Lọc theo kết quả:" - -#: templates/problem/manage_submission.html:176 -msgid "Filter by contest:" -msgstr "Lọc theo kỳ thi:" - -#: templates/problem/manage_submission.html:186 -msgid "Action" -msgstr "Hành động" - -#: templates/problem/manage_submission.html:188 -msgid "Rejudge selected submissions" -msgstr "Chấm lại những bài nộp này" - -#: templates/problem/manage_submission.html:193 -msgid "Download selected submissions" -msgstr "Tải các bài nộp này" - -#: templates/problem/manage_submission.html:199 -#, python-format -msgid "Are you sure you want to rescore %(count)d submissions?" -msgstr "Bạn có chắc muốn tính điểm lại %(count)d bài nộp?" - -#: templates/problem/manage_submission.html:200 +#: templates/problem/manage_submission.html:163 msgid "Rescore all submissions" -msgstr "Tính điểm lại các bài nộp" +msgstr "" -#: templates/problem/problem.html:137 +#: templates/problem/problem.html:91 msgid "View as PDF" -msgstr "Xem PDF" +msgstr "Xem dạng PDF" -#: templates/problem/problem.html:155 -#, python-format -msgid "%(counter)s submission left" -msgid_plural "%(counter)s submissions left" -msgstr[0] "Còn %(counter)s lần nộp" +#: templates/problem/problem.html:101 templates/problem/problem.html:111 +#: templates/problem/problem.html:116 +msgid "Submit solution" +msgstr "Gửi bài giải" -#: templates/problem/problem.html:168 +#: templates/problem/problem.html:112 msgid "0 submissions left" msgstr "Còn 0 lần nộp" -#: templates/problem/problem.html:186 +#: templates/problem/problem.html:124 msgid "My submissions" -msgstr "Bài nộp của tôi" +msgstr "Lời giải của tôi" -#: templates/problem/problem.html:197 +#: templates/problem/problem.html:128 msgid "Best submissions" -msgstr "Các bài nộp tốt nhất" +msgstr "Lời giải tốt nhất" -#: templates/problem/problem.html:204 +#: templates/problem/problem.html:132 msgid "Read editorial" -msgstr "Xem hướng dẫn" +msgstr "" -#: templates/problem/problem.html:213 +#: templates/problem/problem.html:137 msgid "Manage tickets" -msgstr "Xử lý báo cáo" +msgstr "Quản lý thẻ" -#: templates/problem/problem.html:220 +#: templates/problem/problem.html:141 msgid "Edit problem" -msgstr "Chỉnh sửa bài" +msgstr "Sửa đề bài" -#: templates/problem/problem.html:226 +#: templates/problem/problem.html:143 msgid "Edit test data" -msgstr "Chỉnh sửa test" +msgstr "Sửa đổi test" -#: templates/problem/problem.html:234 +#: templates/problem/problem.html:148 msgid "My tickets" -msgstr "Báo cáo của tôi" +msgstr "" -#: templates/problem/problem.html:244 +#: templates/problem/problem.html:156 msgid "Manage submissions" -msgstr "Quản lý bài nộp" +msgstr "" -#: templates/problem/problem.html:252 +#: templates/problem/problem.html:162 msgid "Clone problem" -msgstr "Nhân bản bài" +msgstr "Copy sang bài mới" -#: templates/problem/problem.html:262 templates/problem/problem.html:389 -msgid "Time limit:" -msgstr "Thời gian:" - -#: templates/problem/problem.html:275 templates/problem/problem.html:394 -msgid "Memory limit:" -msgstr "Bộ nhớ:" - -#: templates/problem/problem.html:293 -msgid "Author:" -msgid_plural "Authors:" -msgstr[0] "Tác giả:" - -#: templates/problem/problem.html:320 -msgid "Allowed languages" -msgstr "Ngôn ngữ cho phép" - -#: templates/problem/problem.html:328 -#, python-format -msgid "No %(lang)s judge online" -msgstr "Không có máy chấm cho %(lang)s" - -#: templates/problem/problem.html:340 -#: templates/status/judge-status-table.html:2 -msgid "Judge" -msgid_plural "Judges" -msgstr[0] "Máy chấm" - -#: templates/problem/problem.html:358 -msgid "none available" -msgstr "Bài này chưa có máy chấm" - -#: templates/problem/problem.html:370 -#, python-format -msgid "This problem has %(length)s clarification(s)" -msgstr "Bài này có %(length)s thông báo" - -#: templates/problem/problem.html:378 +#: templates/problem/problem.html:169 msgid "Points:" msgstr "Điểm:" -#: templates/problem/problem.html:399 templates/problem/raw.html:67 -#: templates/submission/status-testcases.html:155 -msgid "Input:" -msgstr "Input:" +#: templates/problem/problem.html:172 templates/problem/problem.html:174 +msgid "(partial)" +msgstr "(một phần)" -#: templates/problem/problem.html:401 templates/problem/raw.html:67 -msgid "stdin" -msgstr "bàn phím" - -#: templates/problem/problem.html:406 templates/problem/raw.html:70 -#: templates/submission/status-testcases.html:159 -msgid "Output:" -msgstr "Output:" - -#: templates/problem/problem.html:407 templates/problem/raw.html:70 -msgid "stdout" -msgstr "màn hình" - -#: templates/problem/problem.html:434 -msgid "Request clarification" -msgstr "Yêu cầu làm rõ đề" - -#: templates/problem/raw.html:73 -msgid "Time Limit:" +#: templates/problem/problem.html:179 +msgid "Time limit:" msgstr "Giới hạn thời gian:" -#: templates/problem/raw.html:82 -msgid "Memory Limit:" +#: templates/problem/problem.html:191 +msgid "Memory limit:" msgstr "Giới hạn bộ nhớ:" -#: templates/problem/recent-attempt.html:3 -msgid "Last unsolved" -msgstr "Nộp gần đây" +#: templates/problem/problem.html:238 +msgid "Allowed languages" +msgstr "Ngôn ngữ cho phép" -#: templates/problem/related_problems.html:3 -msgid "Recommended problems" -msgstr "Bài tập gợi ý" +#: templates/problem/problem.html:274 +msgid "none available" +msgstr "" + +#: templates/problem/problem.html:299 +msgid "Request clarification" +msgstr "Gửi thắc mắc" + +#: templates/problem/problem.html:301 +msgid "Report an issue" +msgstr "Báo cáo vấn đề" + +#: templates/problem/raw.html:62 +msgid "Time Limit:" +msgstr "" + +#: templates/problem/raw.html:71 +msgid "Memory Limit:" +msgstr "" #: templates/problem/search-form.html:2 msgid "Problem search" msgstr "Tìm kiếm bài tập" -#: templates/problem/search-form.html:7 +#: templates/problem/search-form.html:8 msgid "Search problems..." -msgstr "Tìm bài tập..." +msgstr "Tìm đề bài..." -#: templates/problem/search-form.html:13 +#: templates/problem/search-form.html:14 +msgid "Full text search" +msgstr "Tìm kiếm" + +#: templates/problem/search-form.html:21 msgid "Hide solved problems" -msgstr "Ẩn các bài đã giải" - -#: templates/problem/search-form.html:20 -msgid "Show solved problems" -msgstr "Hiện các bài đã giải" +msgstr "Ẩn các bài đã có lời giải" #: templates/problem/search-form.html:27 msgid "Show problem types" -msgstr "Hiển thị dạng bài" +msgstr "Hiện loại đề" -#: templates/problem/search-form.html:34 -msgid "Show editorial" -msgstr "Hiển thị hướng dẫn" +#: templates/problem/search-form.html:33 templates/problem/search-form.html:35 +msgid "All" +msgstr "Tất cả" -#: templates/problem/search-form.html:50 -msgid "Author" -msgstr "Tác giả" +#: templates/problem/search-form.html:46 +msgid "Problem types" +msgstr "Kiểu bài tập" -#: templates/problem/search-form.html:88 +#: templates/problem/search-form.html:57 msgid "Point range" -msgstr "Mốc điểm" +msgstr "" -#: templates/problem/search-form.html:96 +#: templates/problem/search-form.html:63 templates/submission/list.html:331 +#: templates/ticket/list.html:248 +msgid "Go" +msgstr "Tìm" + +#: templates/problem/search-form.html:64 msgid "Random" msgstr "Ngẫu nhiên" -#: templates/problem/submit.html:48 -msgid "Wait" -msgstr "Đợi" - -#: templates/problem/submit.html:148 -msgid "Your source code must contain at most 65536 characters." -msgstr "Code phải chứa không quá 65536 ký tự." - -#: templates/problem/submit.html:195 -#, python-format -msgid "" -"Warning! Your default language, %(default_language)s, is " -"unavailable for this problem and has been deselected." -msgstr "" -"Cẩn thận! Ngôn ngữ ưa thích của bạn, %(default_language)s, " -"không được sử dụng trong bài này." - -#: templates/problem/submit.html:206 -#, fuzzy, python-format -#| msgid "" -#| "\n" -#| " You have %(left)s submission left\n" -#| " " -#| msgid_plural "" -#| "\n" -#| " You have %(left)s submissions left\n" -#| " " -msgid "" -"\n" -" You have %(left)s submission left\n" -" " -msgid_plural "" -"\n" -" You have %(left)s submissions left\n" -" " -msgstr[0] "" -"\n" -" Bạn còn %(left)s lần nộp\n" -" " - -#: templates/problem/submit.html:215 +#: templates/problem/submit.html:212 msgid "You have 0 submissions left" -msgstr "Bạn đã hết lần nộp" +msgstr "Bạn còn 0 lần nộp" -#: templates/problem/submit.html:249 +#: templates/problem/submit.html:250 msgid "No judge is available for this problem." -msgstr "Không có máy chấm có thể chấm bài này." +msgstr "Bài tập này hiện không sẵn sàng để chấm." -#: templates/problem/submit.html:255 +#: templates/problem/submit.html:252 msgid "Submit!" msgstr "Nộp bài!" -#: templates/profile-table.html:20 templates/user/user-about.html:23 -#, python-format -msgid "%(counter)s problem solved" -msgid_plural "%(counter)s problems solved" -msgstr[0] "Đã giải %(counter)s bài" - -#: templates/profile-table.html:30 templates/user/user-about.html:35 -msgid "Total points" -msgstr "Tổng điểm" - -#: templates/profile-table.html:37 templates/user/user-about.html:44 -msgid "Rank by rating" -msgstr "Rank theo rating" - -#: templates/profile-table.html:41 templates/user/user-about.html:50 -msgid "Rank by points" -msgstr "Rank theo điểm" - -#: templates/profile-table.html:47 templates/user/user-about.html:86 -msgid "Awards" -msgstr "Thành tích" - -#: templates/recent-organization.html:3 -msgid "Recent groups" -msgstr "Nhóm gần đây" - -#: templates/registration/activate.html:3 -#, python-format -msgid "%(key)s is an invalid activation key." -msgstr "%(key)s không phải mã xác thực hợp lệ." - #: templates/registration/activation_complete.html:3 msgid "Your account has been successfully activated." -msgstr "Tài khoản được kích hoạt thành công." +msgstr "Tài khoản của bạn đã được kích hoạt thành công." -#: templates/registration/activation_email.html:2 -msgid "Account activation" -msgstr "Kích hoạt tài khoản" +#: templates/registration/login.html:43 +msgid "Invalid username or password." +msgstr "Tên người dùng hoặc mật khẩu không hợp lệ." -#: templates/registration/activation_email.html:3 -#, python-format -msgid "" -"Thanks for registering! We're glad to have you. The last step is activating " -"your account. Please activate your account in the next %(expiration_days)d " -"days." -msgstr "" -"Cảm ơn bạn đã đăng ký! Chúng tôi rất vui được chào đón bạn. Bước cuối cùng " -"là kích hoạt tài khoản của bạn. Vui lòng kích hoạt tài khoản trong vòng " -"%(expiration_days)d ngày." - -#: templates/registration/activation_email.html:5 -msgid "Activate" -msgstr "Kích hoạt" - -#: templates/registration/activation_email.html:10 -msgid "" -"Alternatively, you can reply to this message to activate your account. Your " -"reply must keep the following text intact for this to work:" -msgstr "" -"Hoặc bạn có thể trả lời tin nhắn này để kích hoạt tài khoản của bạn. Email " -"trả lời của bạn phải giữ nguyên đoạn văn sau đây:" - -#: templates/registration/activation_email.html:16 -msgid "See you soon!" -msgstr "Hẹn sớm gặp lại bạn!" - -#: templates/registration/activation_email_subject.txt:1 -#, python-format -msgid "Activate your %(SITE_NAME)s account" -msgstr "Kích hoạt tài khoản %(SITE_NAME)s" - -#: templates/registration/login.html:9 -msgid "Invalid username/email or password." -msgstr "Tên đăng nhập/email hoặc mật khẩu không hợp lệ." - -#: templates/registration/login.html:27 +#: templates/registration/login.html:61 #: templates/registration/totp_auth.html:39 msgid "Login!" msgstr "Đăng nhập!" -#: templates/registration/login.html:30 +#: templates/registration/login.html:64 msgid "Forgot your password?" msgstr "Quên mật khẩu?" -#: templates/registration/login.html:33 +#: templates/registration/login.html:67 msgid "Or log in with..." -msgstr "Đăng nhập với..." +msgstr "Hoặc đăng nhập bằng..." #: templates/registration/logout.html:3 msgid "See you later!" @@ -5624,7 +3835,7 @@ msgstr "Hẹn gặp lại!" #: templates/registration/password_change_done.html:3 msgid "Your password was sucessfully changed." -msgstr "Đổi mật khẩu thành công." +msgstr "Mật khẩu của bạn đã được thay đổi." #: templates/registration/password_change_form.html:8 msgid "Change Password" @@ -5632,153 +3843,135 @@ msgstr "Đổi mật khẩu" #: templates/registration/password_reset.html:7 msgid "Send Reset Email" -msgstr "Gửi email reset" +msgstr "Gửi email đặt lại mật khẩu" #: templates/registration/password_reset_complete.html:3 msgid "Your password has been set. You may go ahead and log in now" -msgstr "Mật khẩu đã được cập nhật. Hãy thử đăng nhập lại" +msgstr "Mật khẩu của bạn đã được đặt. Giờ bạn đã có thể đăng nhập" #: templates/registration/password_reset_confirm.html:9 -#: templates/registration/password_reset_email.html:5 msgid "Reset Password" -msgstr "Reset mật khẩu" +msgstr "Đặt lại mật khẩu" #: templates/registration/password_reset_done.html:4 msgid "" "We've emailed you instructions for setting your password. You should be " "receiving them shortly." -msgstr "Chúng tôi đã gửi email cho bạn để đặt lại mật khẩu." +msgstr "" #: templates/registration/password_reset_done.html:5 msgid "" "If you don't receive an email, please make sure you've entered the address " "you registered with, and check your spam folder." -msgstr "Nếu bạn không nhận được email, hãy kiểm tra hộp thư rác (spam)." - -#: templates/registration/password_reset_email.html:2 -msgid "Password Reset" -msgstr "Đặt lại mật khẩu" - -#: templates/registration/password_reset_email.html:3 -msgid "" -"We have received a request to reset your password. Click the button below to " -"reset your password:" msgstr "" -"Chúng tôi đã nhận được yêu cầu đặt lại mật khẩu của bạn. Nhấn vào nút bên " -"dưới để đặt lại mật khẩu của bạn:" - -#: templates/registration/password_reset_email.txt:1 -#, python-format -msgid "" -"You're receiving this email because you requested a password reset for your " -"user account at %(site_name)s." -msgstr "" -"Bạn nhận được email này vì bạn đã yêu cầu đặt lại mật khẩu tại %(site_name)s." #: templates/registration/password_reset_email.txt:3 msgid "Please go to the following page and choose a new password:" -msgstr "Đến trang tiếp theo và chọn mật khẩu mới:" +msgstr "Hãy đi đến trang sau và chọn một mật khẩu mới:" #: templates/registration/password_reset_email.txt:7 msgid "Your username, in case you've forgotten:" -msgstr "Tên đăng nhập, trong trường hợp bạn quên:" +msgstr "Tên người dùng của bạn, trong trường hợp bạn quên:" #: templates/registration/password_reset_email.txt:9 msgid "Thanks for using our site!" -msgstr "Cảm ơn bạn đã đồng hành!" +msgstr "Cảm ơn đã sử dụng hệ thống của chúng tôi!" -#: templates/registration/password_reset_email.txt:11 -#, python-format -msgid "The %(site_name)s team" -msgstr "%(site_name)s team" - -#: templates/registration/password_reset_subject.txt:1 -#, python-format -msgid "Password reset on %(site_name)s" -msgstr "Đặt lại mật khẩu trên %(site_name)s" - -#: templates/registration/profile_creation.html:37 +#: templates/registration/profile_creation.html:36 #: templates/registration/username_select.html:7 msgid "Continue >" msgstr "Tiếp tục >" #: templates/registration/registration_closed.html:3 msgid "Registration is currently closed. Please contact an administrator." -msgstr "Đăng ký hiện tại đã bị dừng. Hãy liên hệ admin." +msgstr "Việc đăng ký hiện đã đóng. Vui lòng liên hệ với quản trị viên." #: templates/registration/registration_complete.html:3 msgid "" "You have successfully been registered. An email has been sent to the email " -"address you provided to confirm your registration. If you don't see it, " -"kindly check your spam folder as well." +"address you provided to confirm your registration." msgstr "" -"Bạn đã đăng ký thành công. Kiểm tra email để hoàn thành việc xác thực. Nếu " -"bạn không tìm thấy nó, vui lòng kiểm tra thư mục spam của bạn." +"Chúc mừng bạn đã đăng ký thành công. Một Email đã được gửi đến cho bạn để " +"xác nhận đăng ký của bạn." -#: templates/registration/registration_form.html:61 +#: templates/registration/registration_form.html:166 msgid "(again, for confirmation)" -msgstr "(một lần nữa)" +msgstr "(một lần nữa, để xác nhận)" -#: templates/registration/registration_form.html:68 +#: templates/registration/registration_form.html:173 msgid "(select your closest major city)" -msgstr "(chọn thành phố gần nhất)" +msgstr "(chọn thành phố gần bạn nhất)" -#: templates/registration/registration_form.html:72 -msgid "or" -msgstr "hoặc" - -#: templates/registration/registration_form.html:73 +#: templates/registration/registration_form.html:178 msgid "pick from map" msgstr "chọn từ bản đồ" -#: templates/registration/registration_form.html:78 +#: templates/registration/registration_form.html:183 msgid "Default language" msgstr "Ngôn ngữ mặc định" -#: templates/registration/registration_form.html:89 +#: templates/registration/registration_form.html:186 +#: templates/user/edit-profile.html:173 +msgid "Affiliated organizations" +msgstr "Tổ chức đại diện" + +#: templates/registration/registration_form.html:192 +msgid "Notify me about upcoming contests" +msgstr "Thông báo cho tôi về các cuộc thi sắp tới" + +#: templates/registration/registration_form.html:206 +msgid "By registering, you agree to our" +msgstr "Để đăng ký, bạn đồng ý với chúng tôi" + +#: templates/registration/registration_form.html:207 +msgid "Terms & Conditions" +msgstr "Điều khoản & Điều kiện" + +#: templates/registration/registration_form.html:210 msgid "Register!" -msgstr "Đăng ký!" +msgstr "Đăng ký!" #: templates/registration/totp_auth.html:36 #: templates/registration/totp_disable.html:45 #: templates/registration/totp_enable.html:83 msgid "Enter the 6-digit code generated by your app:" -msgstr "Nhập mã xác thực gồm 6 chữ số từ app bạn chọn" - -#: templates/registration/totp_auth.html:41 -#, python-format -msgid "If you lost your authentication device, please contact us at %(email)s." -msgstr "" +msgstr "Nhập mã 6 chữ số sinh ra bởi ứng dụng của bạn:" #: templates/registration/totp_disable.html:38 msgid "" "To protect your account, you must first authenticate before you can disable " "Two Factor Authentication." msgstr "" +"Để bảo vệ tài khoản của bạn, bạn cần xác thực trước khi bạn có thể vô hiệu " +"hóa 2FA." #: templates/registration/totp_enable.html:71 msgid "Scan this code with your authenticator app:" -msgstr "" +msgstr "Quét mã này với ứng dụng xác thực của bạn:" #: templates/registration/totp_enable.html:72 msgid "QR code" -msgstr "" +msgstr "Mã QR" #: templates/registration/totp_enable.html:73 msgid "Or enter this code manually:" -msgstr "" +msgstr "Hoặc nhập mã này thủ công:" + +#: templates/stats/base.html:9 templates/submission/list.html:339 +msgid "Statistics" +msgstr "Thống kê" #: templates/stats/language.html:11 msgid "Submission Statistics" -msgstr "Thống kê" +msgstr "Thống kê bài nộp" #: templates/stats/language.html:21 msgid "AC Submissions by Language" -msgstr "Thống kê AC theo ngôn ngữ" +msgstr "Các bài nộp đã AC theo ngôn ngữ" -#: templates/stats/tab.html:5 -msgid "Site" -msgstr "Trang" +#: templates/status/judge-status-table.html:2 +msgid "Judge" +msgstr "Máy chấm" #: templates/status/judge-status-table.html:4 msgid "Online" @@ -5786,329 +3979,235 @@ msgstr "Trực tuyến" #: templates/status/judge-status-table.html:6 msgid "Uptime" -msgstr "" +msgstr "Thời gian hoạt động" #: templates/status/judge-status-table.html:7 msgid "Ping" -msgstr "Ping" +msgstr "" #: templates/status/judge-status-table.html:8 -#: templates/user/import/index.html:104 msgid "Load" -msgstr "Load" +msgstr "Tải" #: templates/status/judge-status-table.html:34 #: templates/status/judge-status-table.html:41 #: templates/status/judge-status-table.html:48 #: templates/status/judge-status-table.html:59 msgid "N/A" -msgstr "N/A" +msgstr "Không có thông tin" #: templates/status/judge-status-table.html:64 msgid "There are no judges available at this time." -msgstr "Không có máy chấm nào hoạt động." +msgstr "Không có máy chấm nào tại thời điểm này." -#: templates/status/language-list.html:33 templates/ticket/list.html:263 -#: templates/user/import/table_csv.html:3 +#: templates/status/language-list.html:33 templates/ticket/list.html:261 msgid "ID" -msgstr "ID" +msgstr "" #: templates/status/language-list.html:35 msgid "Runtime Info" -msgstr "Thông tin Runtime" - -#: templates/status/status-tabs.html:4 -msgid "Judges" -msgstr "Máy chấm" - -#: templates/status/status-tabs.html:6 -msgid "Version Matrix" -msgstr "Phiên bản" - -#: templates/submission/internal-error-message.html:3 -#, python-format -msgid "" -"An internal error occurred while grading, and the %(SITE_NAME)s " -"administrators have been notified.
In the meantime, try resubmitting in " -"a few seconds." -msgstr "" -"Lỗi hệ thống đã xảy ra trong lúc chấm bài và các admin %(SITE_NAME)s đã được " -"thông báo.
Hãy thử nộp lại bài sau vài giây." +msgstr "Thông tin thời gian chạy" #: templates/submission/internal-error-message.html:8 msgid "An internal error occurred while grading." -msgstr "Lỗi hệ thống xảy ra trong quá trình chấm." +msgstr "Một lỗi hệ thống vừa xảy ra trong quá trình chấm bài." #: templates/submission/internal-error-message.html:15 msgid "Error information" -msgstr "Thông tin lỗi" +msgstr "Thông tin về lỗi" -#: templates/submission/list.html:119 +#: templates/submission/list.html:76 msgid "Filter by status..." -msgstr "Lọc theo kết quả..." +msgstr "Lọc theo trạng thái..." -#: templates/submission/list.html:125 +#: templates/submission/list.html:82 msgid "Filter by language..." msgstr "Lọc theo ngôn ngữ..." #: templates/submission/list.html:309 -msgid "You were disconnected. Refresh to show latest updates." -msgstr "Bạn bị ngắt kết nối. Hãy làm mới để xem cập nhật mới nhất." +msgid "Filter submissions" +msgstr "Lọc các bài nộp" -#: templates/submission/list.html:368 +#: templates/submission/list.html:345 msgid "Total:" msgstr "Tổng:" -#: templates/submission/list.html:385 -#: templates/submission/submission-list-tabs.html:9 -msgid "Best" -msgstr "Tốt nhất" - -#: templates/submission/list.html:388 -#, fuzzy, python-format -#| msgid "user" -msgid "%(user)s" -msgstr "người dùng" - -#: templates/submission/list.html:391 templates/user/user-left-sidebar.html:3 -#: templates/user/user-list-tabs.html:5 -msgid "Friends" -msgstr "Bạn bè" - -#: templates/submission/row.html:57 -msgid "d/m/Y" +#: templates/submission/list.html:355 +msgid "You were disconnected. Refresh to show latest updates." msgstr "" +"Bạn đã bị ngắt kết nối. Tải lại trang để hiển thị thông tin cập nhật mới " +"nhất." -#: templates/submission/row.html:84 +#: templates/submission/row.html:49 msgid "view" msgstr "xem" -#: templates/submission/row.html:88 +#: templates/submission/row.html:53 msgid "rejudge" msgstr "chấm lại" -#: templates/submission/row.html:93 +#: templates/submission/row.html:58 msgid "admin" -msgstr "admin" +msgstr "quản trị" -#: templates/submission/status-testcases.html:5 +#: templates/submission/source.html:25 +msgid "View status" +msgstr "Xem trạng thái" + +#: templates/submission/source.html:26 +msgid "View raw source" +msgstr "Xem mã nguồn" + +#: templates/submission/source.html:28 templates/submission/status.html:61 +msgid "Resubmit" +msgstr "Gửi lại" + +#: templates/submission/status-testcases.html:10 msgid "We are waiting for a suitable judge to process your submission..." -msgstr "Các máy chấm đang bận. Hãy kiên nhẫn chờ đợi một chút..." +msgstr "" +"Chúng tôi đang chờ đợi cho một máy chấm phù hợp để xử lý thông tin của bạn..." -#: templates/submission/status-testcases.html:7 +#: templates/submission/status-testcases.html:12 msgid "Your submission is being processed..." -msgstr "Đang chấm..." +msgstr "Bài nộp của bạn đang được xử lý..." -#: templates/submission/status-testcases.html:9 +#: templates/submission/status-testcases.html:14 msgid "Compilation Error" -msgstr "Lỗi biên dịch" - -#: templates/submission/status-testcases.html:13 -msgid "Compilation Warnings" -msgstr "Cảnh báo khi biên dịch" +msgstr "Lỗi dịch" #: templates/submission/status-testcases.html:18 +msgid "Compilation Warnings" +msgstr "Các cảnh báo Biên dịch" + +#: templates/submission/status-testcases.html:23 msgid "Pretest Execution Results" -msgstr "Kết quả chấm Pretest" +msgstr "Kết quả thực hiện Pretest" -#: templates/submission/status-testcases.html:20 +#: templates/submission/status-testcases.html:25 msgid "Execution Results" -msgstr "Kết quả chấm" +msgstr "Kết quả thực hiện" -#: templates/submission/status-testcases.html:27 -#: templates/submission/status-testcases.html:42 -#: templates/submission/status-testcases.html:93 +#: templates/submission/status-testcases.html:31 msgid "Batch " -msgstr "Nhóm " +msgstr "Hàng loạt " -#: templates/submission/status-testcases.html:32 -#: templates/submission/status-testcases.html:34 -#: templates/submission/status-testcases.html:119 -msgid "Case" -msgstr "Test" - -#: templates/submission/status-testcases.html:53 +#: templates/submission/status-testcases.html:43 msgid "Overall: " -msgstr "Tổng cộng: " +msgstr "" -#: templates/submission/status-testcases.html:67 +#: templates/submission/status-testcases.html:57 +#, fuzzy +#| msgid "Points:" msgid "Point: " -msgstr "Điểm: " +msgstr "Điểm:" -#: templates/submission/status-testcases.html:72 +#: templates/submission/status-testcases.html:62 +#, fuzzy +#| msgid "Time:" msgid "Time: " -msgstr "Thời gian: " +msgstr "Thời gian:" -#: templates/submission/status-testcases.html:81 +#: templates/submission/status-testcases.html:71 +#, fuzzy +#| msgid "Memory" msgid "Memory: " -msgstr "Bộ nhớ: " +msgstr "Bộ nhớ" -#: templates/submission/status-testcases.html:104 -#: templates/submission/status-testcases.html:133 +#: templates/submission/status-testcases.html:84 +msgid "Case" +msgstr "Trường hợp" + +#: templates/submission/status-testcases.html:86 +msgid "Pretest" +msgstr "Test đề bài" + +#: templates/submission/status-testcases.html:88 +msgid "Test case" +msgstr "Bộ test" + +#: templates/submission/status-testcases.html:99 +#, fuzzy +#| msgid "Points" msgid "Point" msgstr "Điểm" #: templates/submission/status-testcases.html:121 -msgid "Pretest" -msgstr "Pretest" +#, fuzzy +#| msgid "Input file" +msgid "Input:" +msgstr "Tập tin đầu vào" -#: templates/submission/status-testcases.html:123 -msgid "Test case" -msgstr "Test" +#: templates/submission/status-testcases.html:125 +#, fuzzy +#| msgid "Output file" +msgid "Output:" +msgstr "Tập tin đầu ra" -#: templates/submission/status-testcases.html:163 +#: templates/submission/status-testcases.html:129 +#, fuzzy +#| msgid "Wrong Answer" msgid "Answer:" -msgstr "Kết quả:" +msgstr "Kết quả sai (WA)" -#: templates/submission/status-testcases.html:168 +#: templates/submission/status-testcases.html:134 +#, fuzzy +#| msgid "Judge feedback" msgid "Judge feedback:" -msgstr "Phản hồi từ máy chấm:" +msgstr "Phản hồi trình chấm" -#: templates/submission/status-testcases.html:190 +#: templates/submission/status-testcases.html:157 msgid "Passing pretests does not guarantee a full score on system tests." -msgstr "AC pretest không đồng nghĩa AC cả bài nhé :))" +msgstr "" +"Vượt qua các bộ test thử không chắc chắn được toàn bộ số điểm từ các bộ test " +"hệ thống." -#: templates/submission/status-testcases.html:193 +#: templates/submission/status-testcases.html:160 msgid "Submission aborted!" -msgstr "Đã hủy chấm bài nộp!" +msgstr "Bài nộp đã bị huỷ!" -#: templates/submission/status.html:141 -msgid "Resubmit" -msgstr "Nộp lại" +#: templates/submission/status.html:59 +msgid "View source" +msgstr "Xem nguồn" -#: templates/submission/status.html:157 -msgid "Source code" -msgstr "Mã nguồn" - -#: templates/submission/status.html:171 +#: templates/submission/status.html:88 msgid "Abort" -msgstr "Hủy chấm" +msgstr "Huỷ bỏ" -#: templates/submission/submission-list-tabs.html:12 -#, python-format -msgid "%(user)s's" -msgstr "" - -#: templates/submission/user-ajax.html:2 -msgid "Contest submissions of" -msgstr "Các bài nộp của" - -#: templates/submission/user-ajax.html:11 -msgid "Subtask" -msgstr "Subtask" - -#: templates/submission/user-ajax.html:51 -msgid "g:i a d/m/Y" -msgstr "" - -#: templates/submission/user-ajax.html:51 -#, fuzzy, python-format -#| msgid "" -#| "\n" -#| " on %(time)s\n" -#| " " -msgid "" -"\n" -" %(time)s\n" -" " -msgstr "" -"\n" -" vào %(time)s\n" -" " - -#: templates/submission/user-ajax.html:60 -msgid "pretests" -msgstr "pretests" - -#: templates/submission/user-ajax.html:62 -msgid "main tests" -msgstr "test chính thức" - -#: templates/test_formatter/download_test_formatter.html:75 -#: templates/test_formatter/download_test_formatter.html:82 -#: templates/test_formatter/edit_test_formatter.html:134 -msgid "Download" -msgstr "Tải xuống" - -#: templates/test_formatter/download_test_formatter.html:86 -#: templates/test_formatter/edit_test_formatter.html:137 -#: templates/test_formatter/test_formatter.html:20 -msgid "Copyright" -msgstr "" - -#: templates/test_formatter/edit_test_formatter.html:105 -msgid "Before" -msgstr "Trước" - -#: templates/test_formatter/edit_test_formatter.html:106 -#: templates/test_formatter/edit_test_formatter.html:114 -msgid "Input format" -msgstr "Định dạng đầu vào" - -#: templates/test_formatter/edit_test_formatter.html:108 -#: templates/test_formatter/edit_test_formatter.html:116 -msgid "Output format" -msgstr "Định dạng đầu ra" - -#: templates/test_formatter/edit_test_formatter.html:113 -msgid "After" -msgstr "Sau" - -#: templates/test_formatter/edit_test_formatter.html:122 -msgid "Preview" -msgstr "Xem trước" - -#: templates/test_formatter/edit_test_formatter.html:129 -msgid "File name" -msgstr "Tên file" - -#: templates/test_formatter/edit_test_formatter.html:133 -msgid "Convert" -msgstr "Chuyển đổi" - -#: templates/test_formatter/test_formatter.html:17 -msgid "Upload" -msgstr "Tải lên" - -#: templates/ticket/feed.html:22 -msgid "replied" -msgstr "phản hồi" - -#: templates/ticket/list.html:135 templates/ticket/ticket.html:96 +#: templates/ticket/list.html:135 templates/ticket/ticket.html:257 msgid "Reopened: " -msgstr "Mở lại: " +msgstr "Đã mở lại: " -#: templates/ticket/list.html:138 templates/ticket/ticket.html:97 +#: templates/ticket/list.html:138 templates/ticket/ticket.html:258 msgid "Closed: " -msgstr "Đóng: " +msgstr "Đã đóng: " -#: templates/ticket/list.html:223 +#: templates/ticket/list.html:221 msgid "Use desktop notification" -msgstr "Sử dụng thông báo từ desktop" +msgstr "Sử dụng thông báo trên màn hình" -#: templates/ticket/list.html:229 +#: templates/ticket/list.html:227 msgid "Show my tickets only" -msgstr "Chỉ hiển thị các báo cáo dành cho tôi" +msgstr "Chỉ hiện thẻ của tôi" -#: templates/ticket/list.html:233 +#: templates/ticket/list.html:231 msgid "Filing user" -msgstr "Người báo cáo" +msgstr "" -#: templates/ticket/list.html:242 +#: templates/ticket/list.html:240 msgid "Assignee" -msgstr "Người định uỷ thác" +msgstr "" -#: templates/ticket/list.html:264 +#: templates/ticket/list.html:262 msgid "Title" msgstr "Tiêu đề" -#: templates/ticket/list.html:266 templates/ticket/ticket.html:192 +#: templates/ticket/list.html:264 templates/ticket/ticket.html:328 msgid "Assignees" -msgstr "Người được ủy thác" +msgstr "" #: templates/ticket/new_problem.html:7 msgid "Thanks for opening a ticket!" -msgstr "Cảm ơn bạn đã báo cáo!" +msgstr "" #: templates/ticket/new_problem.html:9 msgid "" @@ -6116,489 +4215,163 @@ msgid "" "statement, and not for asking for help. If you require assistance on solving " "a problem, ask in the comments instead." msgstr "" -"Lưu ý rằng đây là đơn báo cáo các vấn đề trong đề bài, không phải nơi để hỏi " -"bài hay nộp bài." +"Xin lưu ý rằng biểu mẫu này dành cho việc báo cáo các vấn đề của đề bài, và " +"không dành cho việc hỏi xin trợ giúp. Nếu bạn cần hỗ trợ về việc giải bài, " +"hỏi trong phần bình luận." -#: templates/ticket/ticket.html:178 -msgid "Post" -msgstr "Đăng" - -#: templates/ticket/ticket.html:186 +#: templates/ticket/ticket.html:322 msgid "Associated object" msgstr "" -#: templates/ticket/ticket.html:197 +#: templates/ticket/ticket.html:333 msgid "No one is assigned." -msgstr "Không ai được ủy thác." +msgstr "" -#: templates/ticket/ticket.html:203 +#: templates/ticket/ticket.html:339 msgid "Close ticket" -msgstr "Đóng báo cáo" +msgstr "" -#: templates/ticket/ticket.html:205 +#: templates/ticket/ticket.html:341 msgid "Reopen ticket" -msgstr "Mở lại báo cáo" +msgstr "" -#: templates/ticket/ticket.html:209 +#: templates/ticket/ticket.html:345 msgid "Assignee notes" -msgstr "Lưu ý cho người ủy thác" +msgstr "" -#: templates/ticket/ticket.html:216 templates/widgets/select_all.html:4 +#: templates/ticket/ticket.html:352 templates/widgets/select_all.html:4 msgid "Nothing here." -msgstr "Không có gì." +msgstr "Không có gì ở đây." -#: templates/top-users.html:3 -msgid "Top Rating" -msgstr "Top Rating" +#: templates/ticket/ticket.html:385 +msgid "Post" +msgstr "Bài viết" -#: templates/top-users.html:22 -msgid "Top Score" -msgstr "Top Score" +#: templates/user/base-users.html:14 templates/user/base-users.html:69 +msgid "Search by handle..." +msgstr "" -#: templates/user/edit-profile.html:95 -msgid "Full name" -msgstr "Họ tên" - -#: templates/user/edit-profile.html:103 -msgid "Date of birth" -msgstr "Ngày sinh" - -#: templates/user/edit-profile.html:107 -msgid "Address" -msgstr "Địa chỉ" - -#: templates/user/edit-profile.html:111 -msgid "T-Shirt size" -msgstr "Kích cỡ áo" - -#: templates/user/edit-profile.html:118 -msgid "Change your password" -msgstr "Đổi mật khẩu" - -#: templates/user/edit-profile.html:132 -msgid "Avatar" -msgstr "Ảnh đại diện" - -#: templates/user/edit-profile.html:138 +#: templates/user/edit-profile.html:97 msgid "Self-description" -msgstr "Tự giới thiệu" +msgstr "" -#: templates/user/edit-profile.html:146 +#: templates/user/edit-profile.html:105 msgid "Select your closest major city" -msgstr "Chọn thành phố gần nhất" +msgstr "" -#: templates/user/edit-profile.html:155 +#: templates/user/edit-profile.html:114 msgid "Editor theme" -msgstr "Giao diện cho code editor" +msgstr "Giao diện khung viết code" -#: templates/user/edit-profile.html:165 +#: templates/user/edit-profile.html:119 +msgid "Math engine" +msgstr "" + +#: templates/user/edit-profile.html:143 templates/user/edit-profile.html:144 +msgid "Change your avatar" +msgstr "Đổi ảnh đại diện của bạn" + +#: templates/user/edit-profile.html:150 +msgid "Change your password" +msgstr "Đổi mật khẩu của bạn" + +#: templates/user/edit-profile.html:157 msgid "Two Factor Authentication is enabled." -msgstr "Two Factor Authentication đã được kích hoạt." +msgstr "" -#: templates/user/edit-profile.html:169 -msgid "Disable" -msgstr "Tắt" - -#: templates/user/edit-profile.html:172 +#: templates/user/edit-profile.html:164 msgid "Two Factor Authentication is disabled." -msgstr "Two Factor Authentication chưa kích hoạt." - -#: templates/user/edit-profile.html:173 -msgid "Enable" -msgstr "Bật" - -#: templates/user/edit-profile.html:177 -msgid "CSS background" msgstr "" #: templates/user/edit-profile.html:181 +msgid "User-script" +msgstr "" + +#: templates/user/edit-profile.html:185 msgid "Update profile" -msgstr "Cập nhật thông tin" +msgstr "Cập nhật profile" -#: templates/user/import/index.html:31 -msgid "Upload CSV only" +#: templates/user/user-about.html:14 +msgid "From" msgstr "" -#: templates/user/import/index.html:100 -msgid "User File" -msgstr "File người dùng" - -#: templates/user/import/index.html:102 -msgid "Sample" -msgstr "" - -#: templates/user/import/index.html:105 templates/user/user-left-sidebar.html:5 -#: templates/user/user-list-tabs.html:8 -msgid "Import" -msgstr "" - -#: templates/user/import/table_csv.html:9 -msgid "Organizations" -msgstr "Tổ chức" - -#: templates/user/pp-row.html:21 -#, python-format -msgid "" -"\n" -" weighted %(weight)s%%\n" -" " -msgstr "" - -#: templates/user/pp-row.html:26 -#, python-format -msgid "%(pp).1fpp" -msgstr "%(pp).1fpp" - -#: templates/user/pp-row.html:28 -#, python-format -msgid "%(pp).0fpp" -msgstr "%(pp).0fpp" - -#: templates/user/user-about.html:63 +#: templates/user/user-about.html:25 msgid "Admin Notes" -msgstr "Lưu ý của admin" +msgstr "" -#: templates/user/user-about.html:75 +#: templates/user/user-about.html:40 msgid "You have not shared any information." -msgstr "Bạn chưa chia sẻ thông tin nào." +msgstr "" -#: templates/user/user-about.html:77 +#: templates/user/user-about.html:42 msgid "This user has not shared any information." -msgstr "Người dùng này chưa chia sẻ thông tin nào." +msgstr "" -#: templates/user/user-about.html:97 -#, python-format -msgid "%(label)s (%(date)s)" -msgstr "%(label)s (%(date)s)" +#: templates/user/user-base.html:50 +msgid "Rank by points:" +msgstr "" -#: templates/user/user-about.html:115 -msgid "Mon" -msgstr "Thứ 2" +#: templates/user/user-base.html:53 +msgid "Total points:" +msgstr "" -#: templates/user/user-about.html:120 -msgid "Tues" -msgstr "Thứ 3" +#: templates/user/user-base.html:68 +msgid "Rank by rating:" +msgstr "Xếp hạng theo điểm số:" -#: templates/user/user-about.html:125 -msgid "Wed" -msgstr "Thứ 4" +#: templates/user/user-base.html:70 +msgid "Rating:" +msgstr "Điểm số:" -#: templates/user/user-about.html:130 -msgid "Thurs" -msgstr "Thứ 5" +#: templates/user/user-base.html:71 +msgid "Volatility:" +msgstr "Độ biến động:" -#: templates/user/user-about.html:135 -msgid "Fri" -msgstr "Thứ 6" - -#: templates/user/user-about.html:140 -msgid "Sat" -msgstr "Thứ 7" - -#: templates/user/user-about.html:145 -msgid "Sun" -msgstr "CN" - -#: templates/user/user-about.html:154 -msgid "Less" -msgstr "Ít" - -#: templates/user/user-about.html:160 -msgid "More" -msgstr "Nhiều" - -#: templates/user/user-about.html:169 -msgid "Rating History" -msgstr "Các lần thi" - -#: templates/user/user-about.html:236 -msgid "past year" -msgstr "năm ngoái" - -#: templates/user/user-about.html:253 -msgid "total submission(s)" -msgstr "bài nộp" - -#: templates/user/user-about.html:257 -msgid "submissions in the last year" -msgstr "bài nộp trong năm qua" - -#: templates/user/user-base.html:104 -msgid "Unfollow" -msgstr "Bỏ theo dõi" - -#: templates/user/user-base.html:107 -msgid "Follow" -msgstr "Theo dõi" - -#: templates/user/user-base.html:115 -msgid "Message" -msgstr "Nhắn tin" - -#: templates/user/user-base.html:123 -msgid "Contests written" -msgstr "Số kỳ thi" - -#: templates/user/user-base.html:127 +#: templates/user/user-base.html:72 msgid "Min. rating:" -msgstr "Min. rating:" +msgstr "Điểm số thấp nhất:" -#: templates/user/user-base.html:131 +#: templates/user/user-base.html:73 msgid "Max rating:" -msgstr "Max rating:" - -#: templates/user/user-bookmarks.html:22 -msgid "Editorials" -msgstr "Lời giải" - -#: templates/user/user-bookmarks.html:25 -msgid "Posts" -msgstr "Bài đăng" - -#: templates/user/user-bookmarks.html:71 -msgid "There is no saved problem." -msgstr "Không có bài tập nào đã lưu." - -#: templates/user/user-bookmarks.html:100 -msgid "There is no saved contest." -msgstr "Không có kỳ thi đã lưu." - -#: templates/user/user-bookmarks.html:141 -msgid "There is no saved editorial." -msgstr "Không có lời giải nào đã lưu." - -#: templates/user/user-bookmarks.html:190 -msgid "There is no saved post." -msgstr "Không có bài đăng nào đã lưu." +msgstr "Điểm số cao nhất:" #: templates/user/user-problems.html:35 msgid "Points Breakdown" -msgstr "Phân tích điểm" +msgstr "" #: templates/user/user-problems.html:41 msgid "Load more..." -msgstr "Tải thêm..." +msgstr "Xem thêm..." #: templates/user/user-problems.html:45 msgid "This user has not yet solved any problems." -msgstr "Người dùng này chưa giải bài nào." +msgstr "Người dùng này chưa giải bài tập nào." #: templates/user/user-problems.html:51 msgid "Authored Problems" -msgstr "Các bài tập đã ra" +msgstr "" #: templates/user/user-problems.html:83 msgid "Hide problems I've solved" -msgstr "Ẩn các bài đã giải" +msgstr "Ẩn các bài tôi đã giải được" -#: templates/user/user-problems.html:93 -#, python-format -msgid "%(points).1f points" -msgstr "%(points).1f điểm" - -#: templates/user/user-problems.html:110 -#, python-format -msgid "%(points)s / %(total)s" -msgstr "%(points)s / %(total)s" - -#: templates/user/user-tabs.html:8 -msgid "Impersonate" -msgstr "Giả danh" - -#: templates/user/user-tabs.html:15 -msgid "Admin User" -msgstr "Người dùng" - -#: templates/user/user-tabs.html:18 -msgid "Admin Profile" -msgstr "Thông tin" +#: templates/user/user-problems.html:99 +msgid "Score" +msgstr "Điểm" #: templates/widgets/select_all.html:8 msgid "Check all" msgstr "Chọn tất cả" -#~ msgid "course title" -#~ msgstr "tiêu đề khóa học" - -#~ msgid "course content" -#~ msgstr "nội dung khóa học" - -#~ msgid "" -#~ "This image will replace the default site logo for users viewing the " -#~ "organization." -#~ msgstr "Ảnh này sẽ thay thế logo mặc định khi ở trong tổ chức." - -#~ msgid "A ticket is added or updated" -#~ msgstr "Báo cáo" - -#~ msgid "Post time" -#~ msgstr "Thời gian đăng" - -#~ msgid "My groups" -#~ msgstr "Nhóm của tôi" - -#~ msgid "Open groups" -#~ msgstr "Nhóm mở" - -#~ msgid "Private groups" -#~ msgstr "Nhóm kín" - -#~ msgid "Send message" -#~ msgstr "Nhắn tin" - -#~ msgid "Wrong" -#~ msgstr "Sai" - -#~ msgid "Timeout" -#~ msgstr "Quá thời gian" - -#~ msgid "Active Contests" -#~ msgstr "Kỳ thi bạn đang tham gia" - -#~ msgid "Past Contests" -#~ msgstr "Kỳ thi trong quá khứ" - -#~ msgid "Duration" -#~ msgstr "Thời hạn" - -#~ msgid "Submissions in {0}" -#~ msgstr "Bài nộp trong {0}" - -#~ msgid "Submissions in %s" -#~ msgstr "Bài nộp trong %s" - -#~ msgid "Hidden Rankings" -#~ msgstr "Bảng xếp hạng ẩn" - -#, fuzzy -#~| msgid "Banned from joining" -#~ msgid "banned from voting" -#~ msgstr "Bị cấm tham gia" - -#~ msgid "Already in contest" -#~ msgstr "Đã ở trong kỳ thi" - -#~ msgid "You are already in a contest: \"%s\"." -#~ msgstr "Bạn đã ở trong kỳ thi: \"%s\"." - -#~ msgid "Compete" -#~ msgstr "Thi" - -#~ msgid "General" -#~ msgstr "Chung" - -#~ msgid "custom validator file" -#~ msgstr "file trình chấm" - -#~ msgid "Leave as LaTeX" -#~ msgstr "Để định dạng LaTeX" - -#~ msgid "MathML only" -#~ msgstr "chỉ dùng MathML" - -#~ msgid "Custom validator (CPP)" -#~ msgstr "Trình chấm tự viết (C++)" - -#, fuzzy -#~| msgid "From the web" -#~ msgid "From the Web" -#~ msgstr "Từ web" - -#~ msgid "on {time}" -#~ msgstr "vào {time}" - -#, fuzzy -#~| msgid "end time" -#~ msgid "ending time" -#~ msgstr "thời gian kết thúc" - -#~ msgid "In current contest" -#~ msgstr "Trong kỳ thi hiện tại" - -#~ msgid "View status" -#~ msgstr "Xem kết quả chấm" - -#~ msgid "View raw source" -#~ msgstr "Xem mã nguồn" - -#, fuzzy -#~| msgid "contest summary" -#~ msgid "Contests Summary" -#~ msgstr "tổng kết kỳ thi" - -#~ msgid "Submit solution" -#~ msgstr "Nộp bài" - -#~ msgid "(partial)" -#~ msgstr "(thành phần)" - -#~ msgid "Following" -#~ msgstr "Bạn bè" - -#~ msgid "Other" -#~ msgstr "Thành viên khác" - -#~ msgid "Online Users" -#~ msgstr "Trực tuyến" - -#~ msgid "Group:" -#~ msgstr "Nhóm:" - -#~ msgid "Have editorial" -#~ msgstr "Có hướng dẫn" - -#~ msgid "Contest" -#~ msgstr "Kỳ thi" - -#~ msgid "0 to not show testcases, 1 to show" -#~ msgstr "0 để ẩn test, 1 để hiện" - -#~ msgid "{settings.SITE_NAME} - Email Change Request" -#~ msgstr "{settings.SITE_NAME} - Thay đổi email" - -#~ msgid "Affiliated organizations" -#~ msgstr "Tổ chức bạn muốn tham gia" - -#~ msgid "By registering, you agree to our" -#~ msgstr "Bạn đồng ý với" - -#~ msgid "Terms & Conditions" -#~ msgstr "Điều khoản của chúng tôi" - -#~ msgid "Change your avatar" -#~ msgstr "Đổi ảnh đại diện" - -#, fuzzy -#~| msgid "How did you corrupt the custom checker path?" -#~ msgid "How did you corrupt the interactor path?" -#~ msgstr "How did you corrupt the custom checker path?" - -#~ msgid "comment more" -#~ msgstr "bình luận nữa" - -#~ msgid "comments more" -#~ msgstr "bình luận nữa" - -#~ msgid "" -#~ "This comment is hidden due to too much negative feedback. Click here to view it." -#~ msgstr "" -#~ "Bình luận bị ẩn vì nhiều phản hồi tiêu cực. Nhấp vào đây để mở." - -#, fuzzy -#~| msgid "short name" -#~ msgid "first name" -#~ msgstr "tên ngắn" - -#, fuzzy -#~| msgid "short name" -#~ msgid "last name" -#~ msgstr "tên ngắn" +#~ msgid "output prefix length override" +#~ msgstr "ghi đè độ dài output prefix" #~ msgid "biography" #~ msgstr "tiểu sử" +#~ msgid "owner" +#~ msgstr "chủ sở hữu" + #~ msgid "name" #~ msgstr "tên" @@ -6611,6 +4384,9 @@ msgstr "Chọn tất cả" #~ msgid "title" #~ msgstr "tiêu đề" +#~ msgid "category" +#~ msgstr "thể loại" + #~ msgid "author" #~ msgstr "tác giả" @@ -6652,57 +4428,32 @@ msgstr "Chọn tất cả" #~ "Hãy nhập %(username)s và mật khẩu hợp lệ cho tài khoản thành viên. Chú ý " #~ "cả hai trường có phân biệt chữ Hoa-thường." +#~ msgid "Site" +#~ msgstr "Trang" + #~ msgid "Dashboard" #~ msgstr "Bảng điều khiển" #~ msgid "Applications" #~ msgstr "Ứng dụng" -#, fuzzy -#~| msgid "administrators" -#~ msgid "Administration" -#~ msgstr "người quản lý" - #~ msgid "Color theme" #~ msgstr "Chủ đề màu sắc" -#~ msgid "commented on {time}" -#~ msgstr "bình luận vào {time}" +#~ msgid "Change color theme" +#~ msgstr "Đổi chủ đề màu sắc" -#~ msgid "Associated page" -#~ msgstr "Trang liên kết" - -#~ msgid "Page code must be ^[pcs]:[a-z0-9]+$|^b:\\d+$" -#~ msgstr "Mã trang phải có dạng ^[pcs]:[a-z0-9]+$|^b:\\d+$" - -#~ msgid "Best solutions for %(problem)s in %(contest)s" -#~ msgstr "Các bài nộp tốt nhất cho %(problem)s trong %(contest)s" - -#~ msgid "Best solutions for problem %(number)s in %(contest)s" -#~ msgstr "Các bài nộp tốt nhất cho bài %(number)s trong %(contest)s" +#~ msgid "Hello, %(username)s." +#~ msgstr "Xin chào, %(username)s." #~ msgid "" -#~ "Best solutions for {0} in {2}" +#~ "\n" +#~ " posted on %(time)s\n" +#~ " " #~ msgstr "" -#~ "Các bài nộp tốt nhất cho {0} trong {2}" -#~ "" - -#~ msgid "Best solutions for problem {0} in {1}" -#~ msgstr "Các bài nộp tốt nhất cho bài {0} trong {1}" - -#~ msgid "Refresh" -#~ msgstr "Làm mới" - -#~ msgid "View comments" -#~ msgstr "Xem bình luận" - -#~ msgid "Be the first to comment" -#~ msgstr "Bình luận đầu tiên" - -#, fuzzy -#~| msgid "Default" -#~ msgid "default" -#~ msgstr "Mặc định" +#~ "\n" +#~ " đăng vào lúc %(time)s\n" +#~ " " #~ msgid "" #~ "\n" @@ -6710,141 +4461,119 @@ msgstr "Chọn tất cả" #~ " " #~ msgstr "" #~ "\n" -#~ " vào %(time)s\n" +#~ " vào lúc %(time)s\n" #~ " " -#~ msgid "Subscribe to contest updates" -#~ msgstr "Đăng ký để nhận thông báo về các kỳ thi" +#~ msgid "posted on {time}" +#~ msgstr "đã đăng lúc {time}" -#~ msgid "Enable experimental features" -#~ msgstr "Sử dụng các tính năng thử nghiệm" +#~ msgid "commented on {time}" +#~ msgstr "đã bình luận lúc {time}" -#~ msgid "Subscribe to newsletter?" -#~ msgstr "Đăng ký để nhận thông báo?" +#~ msgid "edit %(edits)s" +#~ msgstr "sửa %(edits)s" -#~ msgid "Notify me about upcoming contests" -#~ msgstr "Nhận thông báo về các kỳ thi tương lai" +#~ msgid "Calendar" +#~ msgstr "Lịch" -#~ msgid "Frozen" -#~ msgstr "Đã đóng băng" +#~ msgid "Info" +#~ msgstr "Thông tin" -#~ msgid "Dislike" -#~ msgstr "Không thích" +#~ msgid "Rankings" +#~ msgstr "Bảng xếp hạng" -#~ msgid "Hello, %(username)s." -#~ msgstr "Xin chào, %(username)s." +#~ msgid "Stop spectating" +#~ msgstr "Ngừng theo dõi" -#~ msgid "Report an issue" -#~ msgstr "Báo cáo một vấn đề" +#~ msgid "Contest is over." +#~ msgstr "Cuộc thi kết thúc." -#~ msgid "Edit in %(org_slug)s" -#~ msgstr "Chỉnh sửa trong %(org_slug)s" +#~ msgid "" +#~ "%(time_limit)s window between %(start_time)s and " +#~ "%(end_time)s" +#~ msgstr "" +#~ "cửa sổ %(time_limit)s giữa %(start_time)s" +#~ "%(end_time)s" -#~ msgid "Name and School" -#~ msgstr "Họ tên và Trường" +#~ msgid "%(length)s long starting on %(start_time)s" +#~ msgstr "%(length)s tính từ %(start_time)s" -#~ msgid "Enter this form" -#~ msgstr "Điền vào link này" +#~ msgid "Participation ended." +#~ msgstr "Kết thúc tham gia." -#~ msgid "It takes some time for admin to approve" -#~ msgstr "Ban quản trị sẽ phê duyệt" +#~ msgid "Show columns:" +#~ msgstr "Hiển thị các cột:" -#~ msgid "Show" -#~ msgstr "Hiển thị" +#~ msgid "Output prefix" +#~ msgstr "Tiền tố đầu ra" -#~ msgid "Judge:" -#~ msgid_plural "Judges:" -#~ msgstr[0] "Máy chấm:" +#~ msgid "Output limit" +#~ msgstr "Giới hạn đầu ra" -#~ msgid "Organization" -#~ msgstr "Tổ chức" +#~ msgid "Checker" +#~ msgstr "Kiểm tra" -#~ msgid "Full Name" -#~ msgstr "Họ tên" +#~ msgid "Generator args" +#~ msgstr "Bộ sinh args" -#~ msgid "Show my groups only" -#~ msgstr "Chỉ hiển thị nhóm đang tham gia" +#~ msgid "%(counter)s submission left" +#~ msgid_plural "%(counter)s submissions left" +#~ msgstr[0] "Còn %(counter)s lần nộp" -#~ msgid "Edit difficulty" -#~ msgstr "Thay đổi độ khó" +#~ msgid "Author:" +#~ msgid_plural "Authors:" +#~ msgstr[0] "Tác giả:" -#~ msgid "Vote difficulty" -#~ msgstr "Bình chọn độ khó" +#~ msgid "Problem type" +#~ msgid_plural "Problem types" +#~ msgstr[0] "Loại đề bài" -#~ msgid "How difficult is this problem?" -#~ msgstr "Bạn thấy độ khó bài này thế nào?" +#~ msgid "No %(lang)s judge online" +#~ msgstr "Không có máy chấm %(lang)s đang online" -#~ msgid "This helps us improve the site" -#~ msgstr "Bình chọn giúp admin cải thiện bài tập." +#~ msgid "%(key)s is an invalid activation key." +#~ msgstr "%(key)s là một mã kích hoạt không hợp lệ." -#~ msgid "Voting Statistics" -#~ msgstr "Thống kê" +#~ msgid "" +#~ "You're receiving this email because you requested a password reset for " +#~ "your user account at %(site_name)s." +#~ msgstr "" +#~ "Bạn nhận được email này bởi vì bạn đã yêu cầu đặt lại mật khẩu cho tài " +#~ "khoản của mình tại %(site_name)s." -#~ msgid "Median:" -#~ msgstr "Trung vị:" +#~ msgid "The %(site_name)s team" +#~ msgstr "Đội ngũ %(site_name)s" -#~ msgid "Mean:" -#~ msgstr "Trung bình:" +#~ msgid "Password reset on %(site_name)s" +#~ msgstr "Đặt lại mật khẩu tại %(site_name)s" -#~ msgid "Edit organization" -#~ msgstr "Chỉnh sửa" +#~ msgid "" +#~ "If you lost your authentication device, please contact us at %(email)s." +#~ msgstr "Nếu bạn mất thiết bị xác thực, liên hệ với chúng tội tại %(email)s." -#~ msgid "You may not be part of more than {count} public organizations." -#~ msgstr "Bạn không thể tham gia nhiều hơn {count} tổ chức công khai." +#~ msgid "Judges" +#~ msgstr "Máy chấm" -#~ msgid "Join organization" -#~ msgstr "Tham gia tổ chức" +#~ msgid "Version Matrix" +#~ msgstr "Mã trận phiên bản" -#~ msgid "Organizations..." -#~ msgstr "Tổ chức..." +#~ msgid "Case #%(case)s" +#~ msgstr "Trường hợp #%(case)s" -#~ msgid "Show my organizations only" -#~ msgstr "Chỉ hiển thị tổ chức của tôi" +#~ msgid "Your output (clipped)" +#~ msgstr "Output của bạn (cắt xén)" -#~ msgid "Leave organization" -#~ msgstr "Rời tổ chức" +#~ msgid "Resources:" +#~ msgstr "Tài nguyên:" -#~ msgid "You are not allowed to kick people from this organization." -#~ msgstr "Bạn không được phép đuổi người." +#~ msgid "Final score:" +#~ msgstr "Điểm cuối cùng:" -#~ msgid "Organization news" -#~ msgstr "Tin tức tổ chức" +#~ msgid "Mine" +#~ msgstr "Bài của tôi" -#~ msgid "Admin organization" -#~ msgstr "Trang admin tổ chức" +#~ msgid "Best" +#~ msgstr "Tốt nhất" -#~ msgid "New private contests" -#~ msgstr "Kỳ thi riêng tư mới" - -#~ msgid "New private problems" -#~ msgstr "Bài tập riêng tư mới" - -#~ msgid "Hot problems" -#~ msgstr "Bài tập mới" - -#~ msgid "Discuss {0}" -#~ msgstr "Thảo luận {0}" - -#~ msgid "posted" -#~ msgstr "đã đăng" - -#~ msgid "My open tickets" -#~ msgstr "Báo cáo dành cho tôi" - -#~ msgid "New tickets" -#~ msgstr "Báo cáo mới" - -#~ msgid "New problems" -#~ msgstr "Bài tập mới" - -#~ msgid "Comment stream" -#~ msgstr "Dòng bình luận" - -#~ msgid "Discuss" -#~ msgstr "Thảo luận" - -#~ msgid "Easy" -#~ msgstr "Dễ" - -#~ msgid "Hard" -#~ msgstr "Khó" +#~ msgid "Rank" +#~ msgstr "Xếp hạng" diff --git a/locale/vi/LC_MESSAGES/djangojs.po b/locale/vi/LC_MESSAGES/djangojs.po index 7d54bf0..c6f4afa 100644 --- a/locale/vi/LC_MESSAGES/djangojs.po +++ b/locale/vi/LC_MESSAGES/djangojs.po @@ -1,9 +1,9 @@ msgid "" msgstr "" -"Project-Id-Version: lqdoj2\n" +"Project-Id-Version: dmoj\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-07-20 23:30+0700\n" -"PO-Revision-Date: 2021-07-20 03:45\n" +"POT-Creation-Date: 2020-04-08 21:06-0500\n" +"PO-Revision-Date: 2019-11-11 22:06\n" "Last-Translator: Icyene\n" "Language-Team: Vietnamese\n" "Language: vi_VN\n" @@ -12,11 +12,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" -"X-Crowdin-Project: lqdoj2\n" +"X-Crowdin-Project: dmoj\n" "X-Crowdin-Language: vi\n" "X-Crowdin-File: djangojs.po\n" -"X-Crowdin-Project-ID: 466004\n" -"X-Crowdin-File-ID: 7\n" #: resources/common.js:207 msgctxt "time format with day" diff --git a/locale/vi/LC_MESSAGES/dmoj-user.po b/locale/vi/LC_MESSAGES/dmoj-user.po deleted file mode 100644 index 29ad707..0000000 --- a/locale/vi/LC_MESSAGES/dmoj-user.po +++ /dev/null @@ -1,607 +0,0 @@ -msgid "" -msgstr "" -"Content-Type: text/plain; charset=UTF-8\n" -"Plural-Forms: nplurals=1; plural=0;\n" - -msgid "Problems" -msgstr "Bài tập" - -msgid "Submissions" -msgstr "Bài nộp" - -msgid "Users" -msgstr "Thành viên" - -msgid "Contests" -msgstr "Kỳ thi" - -msgid "Groups" -msgstr "Nhóm" - -msgid "About" -msgstr "Giới thiệu" - -msgid "Status" -msgstr "Máy chấm" - -msgid "Courses" -msgstr "Khóa học" - -msgid "Suggestions" -msgstr "Đề xuất ý tưởng" - -msgid "Proposal" -msgstr "Đề xuất bài tập" - -msgid "TanKhoa" -msgstr "Tân Khoa" - -msgid "Name" -msgstr "Đăng ký tên" - -msgid "Report" -msgstr "Báo cáo tiêu cực" - -msgid "2sat" -msgstr "" - -msgid "adhoc" -msgstr "" - -msgid "aho-corasick" -msgstr "" - -msgid "articulation-point" -msgstr "" - -msgid "backtrack" -msgstr "" - -msgid "bellman-ford" -msgstr "" - -msgid "bfs-01" -msgstr "" - -msgid "biconnected-component" -msgstr "" - -msgid "bignum" -msgstr "" - -msgid "binary-lifting" -msgstr "" - -msgid "binary-search" -msgstr "" - -msgid "binary-search-parallel" -msgstr "" - -msgid "bit" -msgstr "" - -msgid "bit2d" -msgstr "" - -msgid "bitset" -msgstr "" - -msgid "bitwise" -msgstr "" - -msgid "block-cut-tree" -msgstr "" - -msgid "boruvka" -msgstr "" - -msgid "branch&bound" -msgstr "" - -msgid "bridge" -msgstr "" - -msgid "brute force" -msgstr "" - -msgid "cactus-graph" -msgstr "" - -msgid "casework" -msgstr "" - -msgid "centroid" -msgstr "" - -msgid "chinese-remainder" -msgstr "" - -msgid "combinatorics" -msgstr "" - -msgid "constructive" -msgstr "" - -msgid "convex-hull" -msgstr "" - -msgid "counting" -msgstr "" - -msgid "cycle" -msgstr "" - -msgid "data structures" -msgstr "" - -msgid "deep-optimization" -msgstr "" - -msgid "dfs/bfs/pfs" -msgstr "" - -msgid "dijkstra" -msgstr "" - -msgid "divide and conquer" -msgstr "" - -msgid "dp-alien" -msgstr "" - -msgid "dp-bitmask" -msgstr "" - -msgid "dp-cc" -msgstr "" - -msgid "dp-convexhull" -msgstr "" - -msgid "dp-count" -msgstr "" - -msgid "dp-dag" -msgstr "" - -msgid "dp-digit" -msgstr "" - -msgid "dp-dnc" -msgstr "" - -msgid "dp-general" -msgstr "" - -msgid "dp-knuth" -msgstr "" - -msgid "dp-matrix" -msgstr "" - -msgid "dp-openclose" -msgstr "" - -msgid "dp-permutation" -msgstr "" - -msgid "dp-slope" -msgstr "" - -msgid "dp-sos" -msgstr "" - -msgid "dp-swap-label" -msgstr "" - -msgid "dp-tree" -msgstr "" - -msgid "dsu" -msgstr "" - -msgid "dsu-roll-back" -msgstr "" - -msgid "dynamic programming" -msgstr "" - -msgid "euler-path" -msgstr "" - -msgid "euler-theorem" -msgstr "" - -msgid "euler-tour" -msgstr "" - -msgid "extgcd" -msgstr "" - -msgid "Fenwick Tree (Binary Indexed Tree)" -msgstr "" - -msgid "fft/ntt" -msgstr "" - -msgid "flow-demands" -msgstr "" - -msgid "flow-general" -msgstr "" - -msgid "flow-mincost" -msgstr "" - -msgid "flows" -msgstr "" - -msgid "floyd" -msgstr "" - -msgid "function-graph" -msgstr "" - -msgid "game theory" -msgstr "" - -msgid "game-ad-hoc" -msgstr "" - -msgid "game-minimax" -msgstr "" - -msgid "game-nim" -msgstr "" - -msgid "game-sprague-grundy" -msgstr "" - -msgid "gauss-elim" -msgstr "" - -msgid "genetic" -msgstr "" - -msgid "geometry" -msgstr "" - -msgid "geometry-general" -msgstr "" - -msgid "gomory-hu-tree" -msgstr "" - -msgid "graph" -msgstr "" - -msgid "graph theory" -msgstr "" - -msgid "greedy" -msgstr "" - -msgid "greedy-exchange" -msgstr "" - -msgid "greedy-general" -msgstr "" - -msgid "greedy-moore" -msgstr "" - -msgid "hashing" -msgstr "" - -msgid "heuristic" -msgstr "" - -msgid "hld" -msgstr "" - -msgid "HSG" -msgstr "" - -msgid "ICPC" -msgstr "" - -msgid "implementation" -msgstr "" - -msgid "inclusion-exclusion" -msgstr "" - -msgid "interactive" -msgstr "" - -msgid "inversive-geometry" -msgstr "" - -msgid "kd-tree" -msgstr "" - -msgid "kirchoff" -msgstr "" - -msgid "kmp" -msgstr "" - -msgid "kruskal" -msgstr "" - -msgid "lagrange-inter" -msgstr "" - -msgid "language" -msgstr "" - -msgid "lca" -msgstr "" - -msgid "lichao-tree" -msgstr "" - -msgid "local-search" -msgstr "" - -msgid "ltt" -msgstr "" - -msgid "manacher" -msgstr "" - -msgid "matching-bipartie" -msgstr "" - -msgid "matching-general" -msgstr "" - -msgid "matching-hall" -msgstr "" - -msgid "matching-hungarian" -msgstr "" - -msgid "matching-konig" -msgstr "" - -msgid "math" -msgstr "" - -msgid "math-general" -msgstr "" - -msgid "matrix multiplication" -msgstr "" - -msgid "max-clique" -msgstr "" - -msgid "meet-in-the-middle" -msgstr "" - -msgid "Miscellaneous" -msgstr "" - -msgid "mo-general" -msgstr "" - -msgid "mo-tree" -msgstr "" - -msgid "mo-update" -msgstr "" - -msgid "mobius" -msgstr "" - -msgid "modular" -msgstr "" - -msgid "modular-inverse" -msgstr "" - -msgid "monotonic-queue" -msgstr "" - -msgid "mst" -msgstr "" - -msgid "multiplicative" -msgstr "" - -msgid "NEW" -msgstr "" - -msgid "number theory" -msgstr "" - -msgid "offline" -msgstr "" - -msgid "order-statistic" -msgstr "" - -msgid "output-only" -msgstr "" - -msgid "palin-tree" -msgstr "" - -msgid "picks-theorem" -msgstr "" - -msgid "planar-graph" -msgstr "" - -msgid "polygon-triangulation" -msgstr "" - -msgid "precision-issue" -msgstr "" - -msgid "prefix-sum" -msgstr "" - -msgid "primality-test" -msgstr "" - -msgid "probability" -msgstr "" - -msgid "randomized" -msgstr "" - -msgid "Range Queries" -msgstr "" - -msgid "recursion" -msgstr "" - -msgid "rmq" -msgstr "" - -msgid "rmq-2d" -msgstr "" - -msgid "rmq2d" -msgstr "" - -msgid "scc" -msgstr "" - -msgid "scheduling" -msgstr "" - -msgid "search" -msgstr "" - -msgid "segtree-2d" -msgstr "" - -msgid "segtree-beats" -msgstr "" - -msgid "segtree-dynamic" -msgstr "" - -msgid "segtree-general" -msgstr "" - -msgid "segtree-persistent" -msgstr "" - -msgid "segtree-walk" -msgstr "" - -msgid "sequence" -msgstr "" - -msgid "sieve" -msgstr "" - -msgid "sieve-segment" -msgstr "" - -msgid "small-to-large" -msgstr "" - -msgid "sortings" -msgstr "" - -msgid "spanning-tree" -msgstr "" - -msgid "sparse-table" -msgstr "" - -msgid "spfa" -msgstr "" - -msgid "sqrt" -msgstr "" - -msgid "sqrt-babygiant" -msgstr "" - -msgid "sqrt-buckets" -msgstr "" - -msgid "sqrt-buffer" -msgstr "" - -msgid "sqrt-time" -msgstr "" - -msgid "stack-queue" -msgstr "" - -msgid "static-data" -msgstr "" - -msgid "stl" -msgstr "" - -msgid "string" -msgstr "" - -msgid "suffix-array" -msgstr "" - -msgid "sweep-line" -msgstr "" - -msgid "ternary-search" -msgstr "" - -msgid "topo-sort" -msgstr "" - -msgid "tortoise-hare" -msgstr "" - -msgid "Training" -msgstr "" - -msgid "treap/splay" -msgstr "" - -msgid "Tree - general" -msgstr "" - -msgid "tree-isomorphism" -msgstr "" - -msgid "trie" -msgstr "" - -msgid "TSP" -msgstr "" - -msgid "TST" -msgstr "" - -msgid "two-pointers" -msgstr "" - -msgid "unlabelled" -msgstr "" - -msgid "VOI" -msgstr "" - -msgid "voronoi" -msgstr "" - -msgid "z-function" -msgstr "" - -#~ msgid "Bug Report" -#~ msgstr "Báo cáo lỗi" - -#~ msgid "Insert Image" -#~ msgstr "Chèn hình ảnh" - -#~ msgid "Save" -#~ msgstr "Lưu" diff --git a/locale/zh_Hans/LC_MESSAGES/django.po b/locale/zh_Hans/LC_MESSAGES/django.po index ad14d52..f388cb5 100644 --- a/locale/zh_Hans/LC_MESSAGES/django.po +++ b/locale/zh_Hans/LC_MESSAGES/django.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: dmoj\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-10-25 05:59+0700\n" +"POT-Creation-Date: 2020-04-10 01:26-0500\n" "PO-Revision-Date: 2019-11-11 22:05\n" "Last-Translator: Icyene\n" "Language-Team: Chinese Simplified\n" @@ -16,93 +16,93 @@ msgstr "" "X-Crowdin-Language: zh-CN\n" "X-Crowdin-File: django.po\n" -#: chat_box/models.py:16 judge/admin/interface.py:110 -#: judge/models/contest.py:403 judge/models/contest.py:528 -#: judge/models/profile.py:211 +#: chat_box/models.py:15 judge/admin/interface.py:107 +#: judge/models/contest.py:257 judge/models/contest.py:381 +#: judge/models/profile.py:191 msgid "user" msgstr "用户" -#: chat_box/models.py:17 judge/models/comment.py:43 judge/models/comment.py:191 +#: chat_box/models.py:16 judge/models/comment.py:42 msgid "posted time" msgstr "发布时间" -#: chat_box/models.py:18 judge/models/comment.py:47 +#: chat_box/models.py:17 judge/models/comment.py:46 msgid "body of comment" msgstr "评论正文" -#: chat_box/views.py:29 templates/chat/chat.html:4 +#: chat_box/views.py:29 msgid "Chat Box" msgstr "" -#: dmoj/settings.py:355 +#: dmoj/settings.py:349 msgid "German" msgstr "德语" -#: dmoj/settings.py:356 +#: dmoj/settings.py:350 msgid "English" msgstr "英语" -#: dmoj/settings.py:357 +#: dmoj/settings.py:351 msgid "Spanish" msgstr "西班牙语" -#: dmoj/settings.py:358 +#: dmoj/settings.py:352 msgid "French" msgstr "法语" -#: dmoj/settings.py:359 +#: dmoj/settings.py:353 msgid "Croatian" msgstr "克罗地亚语" -#: dmoj/settings.py:360 +#: dmoj/settings.py:354 msgid "Hungarian" msgstr "匈牙利语" -#: dmoj/settings.py:361 +#: dmoj/settings.py:355 msgid "Japanese" msgstr "" -#: dmoj/settings.py:362 +#: dmoj/settings.py:356 msgid "Korean" msgstr "韩语" -#: dmoj/settings.py:363 +#: dmoj/settings.py:357 msgid "Brazilian Portuguese" msgstr "" -#: dmoj/settings.py:364 +#: dmoj/settings.py:358 msgid "Romanian" msgstr "罗马尼亚语" -#: dmoj/settings.py:365 +#: dmoj/settings.py:359 msgid "Russian" msgstr "俄语" -#: dmoj/settings.py:366 +#: dmoj/settings.py:360 msgid "Serbian (Latin)" msgstr "塞尔维亚文(拉丁字母)" -#: dmoj/settings.py:367 +#: dmoj/settings.py:361 msgid "Turkish" msgstr "土耳其语" -#: dmoj/settings.py:368 +#: dmoj/settings.py:362 msgid "Vietnamese" msgstr "越南语" -#: dmoj/settings.py:369 +#: dmoj/settings.py:363 msgid "Simplified Chinese" msgstr "简体中文" -#: dmoj/settings.py:370 +#: dmoj/settings.py:364 msgid "Traditional Chinese" msgstr "" -#: dmoj/urls.py:58 +#: dmoj/urls.py:57 msgid "Login" msgstr "登录" -#: dmoj/urls.py:106 templates/base.html:193 +#: dmoj/urls.py:105 templates/base.html:190 msgid "Home" msgstr "首页" @@ -130,88 +130,86 @@ msgstr "取消隐藏选定评论" msgid "Associated page" msgstr "关联页" -#: judge/admin/contest.py:30 +#: judge/admin/contest.py:28 msgid "Included contests" msgstr "带标签的竞赛" -#: judge/admin/contest.py:66 templates/contest/clarification.html:42 -#: templates/contest/contest.html:83 templates/contest/moss.html:43 -#: templates/problem/list.html:214 templates/problem/list.html:232 -#: templates/problem/list.html:350 templates/user/user-problems.html:56 +#: judge/admin/contest.py:64 templates/contest/contest.html:83 +#: templates/contest/moss.html:43 templates/problem/list.html:206 +#: templates/problem/list.html:221 templates/user/user-problems.html:56 #: templates/user/user-problems.html:98 msgid "Problem" msgstr "题目" -#: judge/admin/contest.py:119 +#: judge/admin/contest.py:112 msgid "Settings" msgstr "" -#: judge/admin/contest.py:121 +#: judge/admin/contest.py:114 msgid "Scheduling" msgstr "时间计划" -#: judge/admin/contest.py:122 templates/organization/home.html:107 +#: judge/admin/contest.py:115 msgid "Details" msgstr "详细信息" -#: judge/admin/contest.py:123 +#: judge/admin/contest.py:116 msgid "Format" msgstr "" -#: judge/admin/contest.py:124 templates/contest/ranking-table.html:7 -#: templates/user/user-about.html:15 templates/user/user-about.html:45 +#: judge/admin/contest.py:117 templates/contest/ranking-table.html:5 msgid "Rating" msgstr "评分" -#: judge/admin/contest.py:125 +#: judge/admin/contest.py:118 msgid "Access" msgstr "" -#: judge/admin/contest.py:127 judge/admin/problem.py:131 +#: judge/admin/contest.py:120 judge/admin/problem.py:131 msgid "Justice" msgstr "司法" -#: judge/admin/contest.py:207 +#: judge/admin/contest.py:158 #, python-format msgid "%d contest successfully marked as visible." msgid_plural "%d contests successfully marked as visible." msgstr[0] "" -#: judge/admin/contest.py:210 +#: judge/admin/contest.py:161 msgid "Mark contests as visible" msgstr "" -#: judge/admin/contest.py:216 +#: judge/admin/contest.py:165 #, python-format msgid "%d contest successfully marked as hidden." msgid_plural "%d contests successfully marked as hidden." msgstr[0] "" -#: judge/admin/contest.py:219 +#: judge/admin/contest.py:168 msgid "Mark contests as hidden" msgstr "" -#: judge/admin/contest.py:233 judge/admin/submission.py:164 +#: judge/admin/contest.py:182 judge/admin/submission.py:164 #, python-format msgid "%d submission was successfully scheduled for rejudging." msgid_plural "%d submissions were successfully scheduled for rejudging." msgstr[0] "" -#: judge/admin/contest.py:308 +#: judge/admin/contest.py:256 #, python-format msgid "%d participation recalculated." msgid_plural "%d participations recalculated." msgstr[0] "" -#: judge/admin/contest.py:311 +#: judge/admin/contest.py:259 msgid "Recalculate results" msgstr "" -#: judge/admin/contest.py:315 judge/admin/organization.py:65 +#: judge/admin/contest.py:263 judge/admin/organization.py:65 msgid "username" msgstr "用户名" -#: judge/admin/contest.py:320 templates/base.html:277 +#: judge/admin/contest.py:268 templates/base.html:260 msgid "virtual" msgstr "模拟竞赛" @@ -219,15 +217,15 @@ msgstr "模拟竞赛" msgid "link path" msgstr "链接路径" -#: judge/admin/interface.py:65 +#: judge/admin/interface.py:62 msgid "Content" msgstr "内容" -#: judge/admin/interface.py:66 +#: judge/admin/interface.py:63 msgid "Summary" msgstr "概要" -#: judge/admin/interface.py:151 +#: judge/admin/interface.py:148 msgid "object" msgstr "" @@ -249,9 +247,8 @@ msgid "Taxonomy" msgstr "分类" #: judge/admin/problem.py:128 templates/contest/contest.html:84 -#: templates/problem/data.html:429 templates/problem/list.html:222 -#: templates/problem/list.html:248 templates/user/base-users-table.html:10 -#: templates/user/user-about.html:36 templates/user/user-about.html:52 +#: templates/problem/data.html:449 templates/problem/list.html:211 +#: templates/problem/list.html:232 templates/user/base-users-table.html:10 #: templates/user/user-problems.html:58 msgid "Points" msgstr "分数" @@ -298,7 +295,6 @@ msgid "timezone" msgstr "时区" #: judge/admin/profile.py:86 judge/admin/submission.py:211 -#: templates/notification/list.html:12 #: templates/organization/requests/log.html:9 #: templates/organization/requests/pending.html:12 #: templates/ticket/list.html:263 @@ -306,7 +302,6 @@ msgid "User" msgstr "用户" #: judge/admin/profile.py:91 templates/registration/registration_form.html:145 -#: templates/user/import/table_csv.html:8 msgid "Email" msgstr "电子邮箱" @@ -338,7 +333,7 @@ msgstr "排除题目" msgid "These problems are NOT allowed to be submitted in this language" msgstr "这些题目不允许使用该语言解决" -#: judge/admin/runtime.py:83 templates/problem/list.html:352 +#: judge/admin/runtime.py:83 msgid "Description" msgstr "描述" @@ -385,7 +380,7 @@ msgstr "您没有为这么多程序重新评分的权利。" msgid "Rejudge the selected submissions" msgstr "重新评分选定的程序" -#: judge/admin/submission.py:193 judge/views/problem_manage.py:159 +#: judge/admin/submission.py:193 judge/views/problem_manage.py:128 #, python-format msgid "%d submission were successfully rescored." msgid_plural "%d submissions were successfully rescored." @@ -395,8 +390,7 @@ msgstr[0] "%d个程序提交的分数已被重新计算。" msgid "Rescore the selected submissions" msgstr "重新计算选定程序的分数" -#: judge/admin/submission.py:200 templates/problem/list.html:216 -#: templates/problem/list.html:236 +#: judge/admin/submission.py:200 msgid "Problem code" msgstr "题目代码" @@ -404,12 +398,10 @@ msgstr "题目代码" msgid "Problem name" msgstr "题目名称" -#: judge/admin/submission.py:215 templates/notification/list.html:15 -#: templates/organization/requests/log.html:10 +#: judge/admin/submission.py:215 templates/organization/requests/log.html:10 #: templates/organization/requests/pending.html:13 -#: templates/problem/list.html:351 -#: templates/submission/status-testcases.html:125 -#: templates/submission/status-testcases.html:127 +#: templates/submission/status-testcases.html:105 +#: templates/submission/status-testcases.html:107 msgid "Time" msgstr "时间" @@ -423,7 +415,7 @@ msgstr "%d KB" msgid "%.2f MB" msgstr "%.2f MB" -#: judge/admin/submission.py:227 templates/submission/status-testcases.html:132 +#: judge/admin/submission.py:227 templates/submission/status-testcases.html:112 msgid "Memory" msgstr "内存" @@ -443,20 +435,20 @@ msgstr "这些题目属于该题目类型" msgid "Online Judge" msgstr "在线评测系统" -#: judge/comments.py:60 +#: judge/comments.py:41 msgid "Comment body" msgstr "评论正文" -#: judge/comments.py:66 judge/views/ticket.py:63 +#: judge/comments.py:47 judge/views/ticket.py:46 msgid "Your part is silent, little toad." msgstr "你已被静音……" -#: judge/comments.py:69 templates/comments/list.html:132 +#: judge/comments.py:50 templates/comments/list.html:131 msgid "" "You need to have solved at least one problem before your voice can be heard." msgstr "只有解决了一个题目以后你才能有发言权。" -#: judge/comments.py:113 +#: judge/comments.py:92 msgid "Posted comment" msgstr "发布了评论" @@ -472,10 +464,6 @@ msgstr "" msgid "ECOO" msgstr "" -#: judge/contest_format/icpc.py:19 -msgid "ICPC" -msgstr "" - #: judge/contest_format/ioi.py:19 msgid "IOI" msgstr "" @@ -488,60 +476,52 @@ msgstr "订阅有关于竞赛的资讯" msgid "Enable experimental features" msgstr "允许使用实验性功能" -#: judge/forms.py:57 judge/views/organization.py:168 judge/views/register.py:49 +#: judge/forms.py:57 judge/views/organization.py:127 #, python-brace-format msgid "You may not be part of more than {count} public organizations." msgstr "你不能参与超过 {count} 个组织" -#: judge/forms.py:82 -#, fuzzy -#| msgid "judge" -msgid "Any judge" -msgstr "裁判服务器" - -#: judge/forms.py:112 judge/views/register.py:26 +#: judge/forms.py:107 judge/views/register.py:26 #: templates/registration/registration_form.html:139 #: templates/user/base-users-table.html:5 -#: templates/user/import/table_csv.html:4 msgid "Username" msgstr "用户名" -#: judge/forms.py:113 templates/registration/registration_form.html:151 +#: judge/forms.py:108 templates/registration/registration_form.html:151 #: templates/registration/registration_form.html:165 -#: templates/user/import/table_csv.html:5 msgid "Password" msgstr "密码" -#: judge/forms.py:135 +#: judge/forms.py:130 msgid "Two Factor Authentication tokens must be 6 decimal digits." msgstr "" -#: judge/forms.py:144 templates/registration/totp_auth.html:32 +#: judge/forms.py:139 templates/registration/totp_auth.html:32 msgid "Invalid Two Factor Authentication token." msgstr "" -#: judge/forms.py:148 judge/models/problem.py:97 +#: judge/forms.py:143 judge/models/problem.py:97 msgid "Problem code must be ^[a-z0-9]+$" msgstr "题目代码必须匹配 ^[a-z0-9]+$" -#: judge/forms.py:153 +#: judge/forms.py:148 msgid "Problem with code already exists." msgstr "" -#: judge/forms.py:158 judge/models/contest.py:61 +#: judge/forms.py:153 judge/models/contest.py:52 msgid "Contest id must be ^[a-z0-9]+$" msgstr "竞赛标识必须匹配 ^[a-z0-9]+$" -#: judge/forms.py:163 +#: judge/forms.py:158 msgid "Contest with key already exists." msgstr "" -#: judge/jinja2/datetime.py:26 templates/blog/blog.html:26 +#: judge/jinja2/datetime.py:26 templates/blog/content.html:27 #: templates/blog/dashboard.html:21 msgid "N j, Y, g:i a" msgstr "Y年n月j日 G:i" -#: judge/jinja2/datetime.py:26 templates/chat/message.html:13 +#: judge/jinja2/datetime.py:26 #, python-brace-format msgid "{time}" msgstr "{time}" @@ -571,266 +551,197 @@ msgstr "MathJax,自动SVG/PNG切换" msgid "Detect best quality" msgstr "检测最佳质量" -#: judge/models/comment.py:26 +#: judge/models/comment.py:25 msgid "Page code must be ^[pcs]:[a-z0-9]+$|^b:\\d+$" msgstr "" -#: judge/models/comment.py:42 +#: judge/models/comment.py:41 msgid "commenter" msgstr "评论者" -#: judge/models/comment.py:44 judge/models/comment.py:177 +#: judge/models/comment.py:43 judge/models/comment.py:176 msgid "associated page" msgstr "" -#: judge/models/comment.py:46 +#: judge/models/comment.py:45 msgid "votes" msgstr "投票" -#: judge/models/comment.py:48 +#: judge/models/comment.py:47 msgid "hide the comment" msgstr "隐藏评论" -#: judge/models/comment.py:49 +#: judge/models/comment.py:48 msgid "parent" msgstr "母评论" -#: judge/models/comment.py:54 judge/models/comment.py:192 +#: judge/models/comment.py:53 msgid "comment" msgstr "评论" -#: judge/models/comment.py:55 +#: judge/models/comment.py:54 msgid "comments" msgstr "评论" -#: judge/models/comment.py:137 judge/models/problem.py:443 +#: judge/models/comment.py:136 judge/models/problem.py:406 #, python-format msgid "Editorial for %s" msgstr "%s 的题解" -#: judge/models/comment.py:172 +#: judge/models/comment.py:171 msgid "comment vote" msgstr "评论投票" -#: judge/models/comment.py:173 +#: judge/models/comment.py:172 msgid "comment votes" msgstr "评论投票" -#: judge/models/comment.py:182 +#: judge/models/comment.py:181 msgid "Override comment lock" msgstr "" -#: judge/models/comment.py:190 -msgid "owner" -msgstr "" - -#: judge/models/comment.py:193 judge/models/message.py:16 -msgid "read" -msgstr "查看" - -#: judge/models/comment.py:194 -#, fuzzy -#| msgid "Category" -msgid "category" -msgstr "分类" - -#: judge/models/comment.py:195 -msgid "html link to comments, used for non-comments" -msgstr "" - -#: judge/models/comment.py:196 -msgid "who trigger, used for non-comment" -msgstr "" - -#: judge/models/contest.py:23 +#: judge/models/contest.py:22 msgid "Invalid colour." msgstr "无效的颜色。" -#: judge/models/contest.py:25 +#: judge/models/contest.py:24 msgid "tag name" msgstr "标签名称" -#: judge/models/contest.py:26 +#: judge/models/contest.py:25 msgid "Lowercase letters and hyphens only." msgstr "只允许小写字母和连字号(-)。" -#: judge/models/contest.py:27 +#: judge/models/contest.py:26 msgid "tag colour" msgstr "标签颜色" -#: judge/models/contest.py:28 +#: judge/models/contest.py:27 msgid "tag description" msgstr "标签说明" -#: judge/models/contest.py:47 +#: judge/models/contest.py:46 msgid "contest tag" msgstr "竞赛标签" -#: judge/models/contest.py:48 judge/models/contest.py:118 +#: judge/models/contest.py:47 judge/models/contest.py:101 msgid "contest tags" msgstr "竞赛标签" -#: judge/models/contest.py:56 -msgid "Visible" -msgstr "" - -#: judge/models/contest.py:57 -msgid "Hidden for duration of contest" -msgstr "" - -#: judge/models/contest.py:58 -#, fuzzy -#| msgid "View user participation" -msgid "Hidden for duration of participation" -msgstr "查看用户参与历史" - -#: judge/models/contest.py:60 +#: judge/models/contest.py:51 msgid "contest id" msgstr "竞赛标识" -#: judge/models/contest.py:62 +#: judge/models/contest.py:53 msgid "contest name" msgstr "竞赛名称" -#: judge/models/contest.py:63 -#, fuzzy -#| msgid "These people will be able to edit the contest." -msgid "These users will be able to edit the contest." +#: judge/models/contest.py:54 +msgid "These people will be able to edit the contest." msgstr "这些人将可以编辑竞赛。" -#: judge/models/contest.py:65 -#, fuzzy -#| msgid "These people will be able to edit the contest." -msgid "" -"These users will be able to edit the contest, but will not be listed as " -"authors." -msgstr "这些人将可以编辑竞赛。" - -#: judge/models/contest.py:68 -#, fuzzy -#| msgid "These people will be able to edit the contest." -msgid "These users will be able to view the contest, but not edit it." -msgstr "这些人将可以编辑竞赛。" - -#: judge/models/contest.py:71 judge/models/runtime.py:136 +#: judge/models/contest.py:56 judge/models/runtime.py:133 msgid "description" msgstr "描述" -#: judge/models/contest.py:72 judge/models/problem.py:390 -#: judge/models/runtime.py:138 +#: judge/models/contest.py:57 judge/models/problem.py:353 +#: judge/models/runtime.py:135 msgid "problems" msgstr "题目" -#: judge/models/contest.py:73 judge/models/contest.py:404 +#: judge/models/contest.py:58 judge/models/contest.py:258 msgid "start time" msgstr "开始时间" -#: judge/models/contest.py:74 +#: judge/models/contest.py:59 msgid "end time" msgstr "结束时间" -#: judge/models/contest.py:75 judge/models/problem.py:118 -#: judge/models/problem.py:414 +#: judge/models/contest.py:60 judge/models/problem.py:118 +#: judge/models/problem.py:377 msgid "time limit" msgstr "时间限制" -#: judge/models/contest.py:76 judge/models/problem.py:136 +#: judge/models/contest.py:61 judge/models/problem.py:136 msgid "publicly visible" msgstr "公开" -#: judge/models/contest.py:77 +#: judge/models/contest.py:62 msgid "" "Should be set even for organization-private contests, where it determines " "whether the contest is visible to members of the specified organizations." msgstr "组织内竞赛也需公开,否则责组织成员无法查看本竞赛。" -#: judge/models/contest.py:80 +#: judge/models/contest.py:65 msgid "contest rated" msgstr "竞赛参与评分" -#: judge/models/contest.py:80 +#: judge/models/contest.py:65 msgid "Whether this contest can be rated." msgstr "竞赛是否参与用户评分" -#: judge/models/contest.py:82 -#, fuzzy -#| msgid "public visibility" -msgid "scoreboard visibility" -msgstr "公共可见性" - -#: judge/models/contest.py:83 -#, fuzzy -#| msgid "" -#| "Whether the scoreboard should remain hidden for the duration of the " -#| "contest." -msgid "Scoreboard visibility through the duration of the contest" -msgstr "记分牌是否在比赛期间保持隐藏。" - -#: judge/models/contest.py:85 -#, fuzzy -#| msgid "hide scoreboard" -msgid "view contest scoreboard" +#: judge/models/contest.py:67 +msgid "hide scoreboard" msgstr "隐藏记分板" -#: judge/models/contest.py:87 -#, fuzzy -#| msgid "These people will be able to edit the contest." -msgid "These users will be able to view the scoreboard." -msgstr "这些人将可以编辑竞赛。" +#: judge/models/contest.py:68 +msgid "" +"Whether the scoreboard should remain hidden for the duration of the contest." +msgstr "记分牌是否在比赛期间保持隐藏。" -#: judge/models/contest.py:88 +#: judge/models/contest.py:71 msgid "no comments" msgstr "没有评论" -#: judge/models/contest.py:89 +#: judge/models/contest.py:72 msgid "Use clarification system instead of comments." msgstr "请使用澄清系统,而不是评论" -#: judge/models/contest.py:91 +#: judge/models/contest.py:74 msgid "Rating floor for contest" msgstr "" -#: judge/models/contest.py:93 +#: judge/models/contest.py:76 msgid "Rating ceiling for contest" msgstr "" -#: judge/models/contest.py:95 +#: judge/models/contest.py:78 msgid "rate all" msgstr "为所有用户评分" -#: judge/models/contest.py:95 +#: judge/models/contest.py:78 msgid "Rate all users who joined." msgstr "所有参与竞赛的用户,包含没有提交任何程序的用户,都将被评分。" -#: judge/models/contest.py:96 +#: judge/models/contest.py:79 msgid "exclude from ratings" msgstr "不会被评分" -#: judge/models/contest.py:98 +#: judge/models/contest.py:81 msgid "private to specific users" msgstr "" -#: judge/models/contest.py:99 +#: judge/models/contest.py:82 msgid "private contestants" msgstr "" -#: judge/models/contest.py:100 +#: judge/models/contest.py:83 msgid "If private, only these users may see the contest" msgstr "" -#: judge/models/contest.py:102 +#: judge/models/contest.py:85 msgid "hide problem tags" msgstr "隐藏题目标签" -#: judge/models/contest.py:103 +#: judge/models/contest.py:86 msgid "Whether problem tags should be hidden by default." msgstr "设置竞赛内题目标签是否默认被隐藏。" -#: judge/models/contest.py:105 +#: judge/models/contest.py:88 msgid "run pretests only" msgstr "只运行预测试" -#: judge/models/contest.py:106 +#: judge/models/contest.py:89 msgid "" "Whether judges should grade pretests only, versus all testcases. Commonly " "set during a contest, then unset prior to rejudging user submissions when " @@ -839,304 +750,279 @@ msgstr "" "设置裁判服务器是否只运行预测试而不是所有测试。通常在竞赛进行时启动,然后在竞" "赛结束后重新评分前关闭。" -#: judge/models/contest.py:110 judge/models/interface.py:77 -#: judge/models/problem.py:157 +#: judge/models/contest.py:93 judge/models/problem.py:157 msgid "private to organizations" msgstr "只对组织可见" -#: judge/models/contest.py:111 judge/models/interface.py:75 -#: judge/models/problem.py:155 judge/models/profile.py:77 +#: judge/models/contest.py:94 judge/models/problem.py:155 +#: judge/models/profile.py:77 msgid "organizations" msgstr "组织" -#: judge/models/contest.py:112 +#: judge/models/contest.py:95 msgid "If private, only these organizations may see the contest" msgstr "选中时,只对选择的组织才可见" -#: judge/models/contest.py:113 judge/models/problem.py:145 +#: judge/models/contest.py:96 judge/models/problem.py:145 msgid "OpenGraph image" msgstr "OpenGraph 图像" -#: judge/models/contest.py:114 judge/models/profile.py:48 +#: judge/models/contest.py:97 judge/models/profile.py:48 msgid "Logo override image" msgstr "" -#: judge/models/contest.py:116 +#: judge/models/contest.py:99 msgid "" "This image will replace the default site logo for users inside the contest." msgstr "" -#: judge/models/contest.py:119 +#: judge/models/contest.py:102 msgid "the amount of live participants" msgstr "实时参与者数" -#: judge/models/contest.py:120 +#: judge/models/contest.py:103 msgid "contest summary" msgstr "竞赛简介" -#: judge/models/contest.py:121 judge/models/problem.py:147 +#: judge/models/contest.py:104 judge/models/problem.py:147 msgid "Plain-text, shown in meta description tag, e.g. for social media." msgstr "在meta description标签内显示的纯文本介绍。" -#: judge/models/contest.py:122 judge/models/profile.py:47 +#: judge/models/contest.py:105 judge/models/profile.py:47 msgid "access code" msgstr "访问码" -#: judge/models/contest.py:123 +#: judge/models/contest.py:106 msgid "" "An optional code to prompt contestants before they are allowed to join the " "contest. Leave it blank to disable." msgstr "在参赛者被允许参加比赛之前的一个可选代码。如无需要请留空白禁用。" -#: judge/models/contest.py:125 judge/models/problem.py:141 +#: judge/models/contest.py:108 judge/models/problem.py:141 msgid "personae non gratae" msgstr "不受欢迎人物" -#: judge/models/contest.py:126 +#: judge/models/contest.py:109 msgid "Bans the selected users from joining this contest." msgstr "" -#: judge/models/contest.py:127 +#: judge/models/contest.py:110 msgid "contest format" msgstr "" -#: judge/models/contest.py:128 +#: judge/models/contest.py:111 msgid "The contest format module to use." msgstr "" -#: judge/models/contest.py:129 +#: judge/models/contest.py:112 msgid "contest format configuration" msgstr "" -#: judge/models/contest.py:130 +#: judge/models/contest.py:113 msgid "" "A JSON object to serve as the configuration for the chosen contest format " "module. Leave empty to use None. Exact format depends on the contest format " "selected." msgstr "" -#: judge/models/contest.py:137 -#, fuzzy -#| msgid "test case points" -msgid "precision points" -msgstr "测试点分值" - -#: judge/models/contest.py:139 -msgid "Number of digits to round points to." -msgstr "" - -#: judge/models/contest.py:383 +#: judge/models/contest.py:239 msgid "See private contests" msgstr "查看私人竞赛" -#: judge/models/contest.py:384 +#: judge/models/contest.py:240 msgid "Edit own contests" msgstr "编辑我的竞赛" -#: judge/models/contest.py:385 +#: judge/models/contest.py:241 msgid "Edit all contests" msgstr "编辑全部竞赛" -#: judge/models/contest.py:386 +#: judge/models/contest.py:242 msgid "Clone contest" msgstr "" -#: judge/models/contest.py:387 templates/contest/moss.html:74 +#: judge/models/contest.py:243 templates/contest/moss.html:74 msgid "MOSS contest" msgstr "" -#: judge/models/contest.py:388 +#: judge/models/contest.py:244 msgid "Rate contests" msgstr "计算积分的比赛" -#: judge/models/contest.py:389 +#: judge/models/contest.py:245 msgid "Contest access codes" msgstr "比赛访问码" -#: judge/models/contest.py:390 +#: judge/models/contest.py:246 msgid "Create private contests" msgstr "" -#: judge/models/contest.py:391 -msgid "Change contest visibility" -msgstr "" - -#: judge/models/contest.py:392 -#, fuzzy -#| msgid "contest problems" -msgid "Edit contest problem label script" -msgstr "竞赛题目" - -#: judge/models/contest.py:394 judge/models/contest.py:492 -#: judge/models/contest.py:529 judge/models/contest.py:552 -#: judge/models/submission.py:84 +#: judge/models/contest.py:248 judge/models/contest.py:345 +#: judge/models/contest.py:382 judge/models/contest.py:404 +#: judge/models/submission.py:83 msgid "contest" msgstr "竞赛" -#: judge/models/contest.py:395 +#: judge/models/contest.py:249 msgid "contests" msgstr "竞赛" -#: judge/models/contest.py:402 +#: judge/models/contest.py:256 msgid "associated contest" msgstr "关联的竞赛" -#: judge/models/contest.py:405 +#: judge/models/contest.py:259 msgid "score" msgstr "得分" -#: judge/models/contest.py:406 +#: judge/models/contest.py:260 msgid "cumulative time" msgstr "累积时间" -#: judge/models/contest.py:407 +#: judge/models/contest.py:261 msgid "is disqualified" msgstr "" -#: judge/models/contest.py:408 +#: judge/models/contest.py:262 msgid "Whether this participation is disqualified." msgstr "" -#: judge/models/contest.py:409 -msgid "tie-breaking field" -msgstr "" - -#: judge/models/contest.py:410 +#: judge/models/contest.py:263 msgid "virtual participation id" msgstr "虚拟参与信息编号" -#: judge/models/contest.py:411 +#: judge/models/contest.py:264 #, fuzzy #| msgid "0 means non-virtual, otherwise the n-th virtual participation" msgid "0 means non-virtual, otherwise the n-th virtual participation." msgstr "0 表示正式参与,否则表示第n次虚拟参与。" -#: judge/models/contest.py:412 +#: judge/models/contest.py:265 msgid "contest format specific data" msgstr "" -#: judge/models/contest.py:478 +#: judge/models/contest.py:331 #, python-format msgid "%s spectating in %s" msgstr "%s旁观%s中" -#: judge/models/contest.py:480 +#: judge/models/contest.py:333 #, python-format msgid "%s in %s, v%d" msgstr "%s于%s的第%d次虚拟参与" -#: judge/models/contest.py:481 +#: judge/models/contest.py:334 #, python-format msgid "%s in %s" msgstr "%s参与%s中" -#: judge/models/contest.py:484 +#: judge/models/contest.py:337 msgid "contest participation" msgstr "竞赛参与信息" -#: judge/models/contest.py:485 +#: judge/models/contest.py:338 msgid "contest participations" msgstr "竞赛参与信息" -#: judge/models/contest.py:491 judge/models/contest.py:513 -#: judge/models/contest.py:553 judge/models/problem.py:389 -#: judge/models/problem.py:394 judge/models/problem.py:412 -#: judge/models/problem_data.py:40 +#: judge/models/contest.py:344 judge/models/contest.py:366 +#: judge/models/contest.py:405 judge/models/problem.py:352 +#: judge/models/problem.py:357 judge/models/problem.py:375 +#: judge/models/problem_data.py:38 msgid "problem" msgstr "题目" -#: judge/models/contest.py:493 judge/models/contest.py:517 +#: judge/models/contest.py:346 judge/models/contest.py:370 #: judge/models/problem.py:129 msgid "points" msgstr "分" -#: judge/models/contest.py:494 +#: judge/models/contest.py:347 msgid "partial" msgstr "部分" -#: judge/models/contest.py:495 judge/models/contest.py:518 +#: judge/models/contest.py:348 judge/models/contest.py:371 msgid "is pretested" msgstr "仅通过预测试" -#: judge/models/contest.py:496 judge/models/interface.py:43 +#: judge/models/contest.py:349 judge/models/interface.py:43 msgid "order" msgstr "顺序" -#: judge/models/contest.py:497 +#: judge/models/contest.py:350 msgid "0 to not show testcases, 1 to show" msgstr "" -#: judge/models/contest.py:498 +#: judge/models/contest.py:351 #, fuzzy #| msgid "submission test cases" msgid "visible testcases" msgstr "程序测试" -#: judge/models/contest.py:499 +#: judge/models/contest.py:352 msgid "Maximum number of submissions for this problem, or 0 for no limit." msgstr "此问题的最大提交数量,或输入0表示无限制" -#: judge/models/contest.py:501 +#: judge/models/contest.py:354 msgid "Why include a problem you can't submit to?" msgstr "为什么包括一个你不能提交的问题?" -#: judge/models/contest.py:506 +#: judge/models/contest.py:359 msgid "contest problem" msgstr "竞赛题目" -#: judge/models/contest.py:507 +#: judge/models/contest.py:360 msgid "contest problems" msgstr "竞赛题目" -#: judge/models/contest.py:511 judge/models/submission.py:183 +#: judge/models/contest.py:364 judge/models/submission.py:181 msgid "submission" msgstr "提交信息" -#: judge/models/contest.py:515 judge/models/contest.py:530 +#: judge/models/contest.py:368 judge/models/contest.py:383 msgid "participation" msgstr "参与" -#: judge/models/contest.py:519 +#: judge/models/contest.py:372 msgid "Whether this submission was ran only on pretests." msgstr "该程序是否只通过预测试。" -#: judge/models/contest.py:523 +#: judge/models/contest.py:376 msgid "contest submission" msgstr "竞赛提交信息" -#: judge/models/contest.py:524 +#: judge/models/contest.py:377 msgid "contest submissions" msgstr "竞赛提交历史" -#: judge/models/contest.py:532 +#: judge/models/contest.py:385 msgid "rank" msgstr "排名" -#: judge/models/contest.py:533 +#: judge/models/contest.py:386 msgid "rating" msgstr "评分" -#: judge/models/contest.py:534 +#: judge/models/contest.py:387 msgid "volatility" msgstr "波动性" -#: judge/models/contest.py:535 +#: judge/models/contest.py:388 msgid "last rated" msgstr "上次评分" -#: judge/models/contest.py:539 +#: judge/models/contest.py:392 msgid "contest rating" msgstr "竞赛评分信息" -#: judge/models/contest.py:540 +#: judge/models/contest.py:393 msgid "contest ratings" msgstr "竞赛评分历史" -#: judge/models/contest.py:560 +#: judge/models/contest.py:412 msgid "contest moss result" msgstr "" -#: judge/models/contest.py:561 +#: judge/models/contest.py:413 msgid "contest moss results" msgstr "" @@ -1176,7 +1062,7 @@ msgstr "父项" msgid "post title" msgstr "文章标题" -#: judge/models/interface.py:67 judge/models/problem.py:432 +#: judge/models/interface.py:67 judge/models/problem.py:395 msgid "authors" msgstr "作者" @@ -1184,7 +1070,7 @@ msgstr "作者" msgid "slug" msgstr "网址标识" -#: judge/models/interface.py:69 judge/models/problem.py:430 +#: judge/models/interface.py:69 judge/models/problem.py:393 msgid "public visibility" msgstr "公共可见性" @@ -1208,21 +1094,15 @@ msgstr "发布摘要" msgid "openGraph image" msgstr "openGraph 图像" -#: judge/models/interface.py:76 -#, fuzzy -#| msgid "If private, only these organizations may see the contest" -msgid "If private, only these organizations may see the blog post." -msgstr "选中时,只对选择的组织才可见" - -#: judge/models/interface.py:105 +#: judge/models/interface.py:91 msgid "Edit all posts" msgstr "编辑所有的帖子" -#: judge/models/interface.py:107 +#: judge/models/interface.py:93 msgid "blog post" msgstr "博客文章" -#: judge/models/interface.py:108 +#: judge/models/interface.py:94 msgid "blog posts" msgstr "博客文章" @@ -1246,6 +1126,10 @@ msgstr "目标" msgid "message timestamp" msgstr "消息时间戳" +#: judge/models/message.py:16 +msgid "read" +msgstr "查看" + #: judge/models/message.py:20 msgid "messages in the thread" msgstr "话题中的消息" @@ -1382,7 +1266,7 @@ msgid "" "are supported." msgstr "这个问题的时间限制(以秒为单位。支持小数秒计时方式(例如1.5)。" -#: judge/models/problem.py:123 judge/models/problem.py:417 +#: judge/models/problem.py:123 judge/models/problem.py:380 msgid "memory limit" msgstr "内存限制" @@ -1455,188 +1339,188 @@ msgstr "" msgid "If private, only these organizations may see the problem." msgstr "" -#: judge/models/problem.py:395 judge/models/problem.py:413 -#: judge/models/runtime.py:111 +#: judge/models/problem.py:358 judge/models/problem.py:376 +#: judge/models/runtime.py:108 msgid "language" msgstr "语言" -#: judge/models/problem.py:396 +#: judge/models/problem.py:359 msgid "translated name" msgstr "翻译题目名" -#: judge/models/problem.py:397 +#: judge/models/problem.py:360 msgid "translated description" msgstr "翻译题目正文" -#: judge/models/problem.py:401 +#: judge/models/problem.py:364 msgid "problem translation" msgstr "题目翻译" -#: judge/models/problem.py:402 +#: judge/models/problem.py:365 msgid "problem translations" msgstr "题目翻译" -#: judge/models/problem.py:406 +#: judge/models/problem.py:369 msgid "clarified problem" msgstr "已澄清的问题" -#: judge/models/problem.py:407 +#: judge/models/problem.py:370 msgid "clarification body" msgstr "澄清的身体" -#: judge/models/problem.py:408 +#: judge/models/problem.py:371 msgid "clarification timestamp" msgstr "澄清时间戳" -#: judge/models/problem.py:423 +#: judge/models/problem.py:386 msgid "language-specific resource limit" msgstr "语言特定资源限制" -#: judge/models/problem.py:424 +#: judge/models/problem.py:387 msgid "language-specific resource limits" msgstr "语言特定资源限制" -#: judge/models/problem.py:428 +#: judge/models/problem.py:391 msgid "associated problem" msgstr "关联的题目" -#: judge/models/problem.py:431 +#: judge/models/problem.py:394 msgid "publish date" msgstr "发布日期" -#: judge/models/problem.py:433 +#: judge/models/problem.py:396 msgid "editorial content" msgstr "可编辑的内容" -#: judge/models/problem.py:449 +#: judge/models/problem.py:412 msgid "solution" msgstr "题目讲解" -#: judge/models/problem.py:450 +#: judge/models/problem.py:413 msgid "solutions" msgstr "题目讲解" -#: judge/models/problem_data.py:26 +#: judge/models/problem_data.py:24 msgid "Standard" msgstr "标准" -#: judge/models/problem_data.py:27 +#: judge/models/problem_data.py:25 msgid "Floats" msgstr "浮点数" -#: judge/models/problem_data.py:28 +#: judge/models/problem_data.py:26 msgid "Floats (absolute)" msgstr "浮点数(仅绝对值)" -#: judge/models/problem_data.py:29 +#: judge/models/problem_data.py:27 msgid "Floats (relative)" msgstr "浮点数(仅相对值)" -#: judge/models/problem_data.py:30 +#: judge/models/problem_data.py:28 msgid "Non-trailing spaces" msgstr "无尾随空格" -#: judge/models/problem_data.py:31 +#: judge/models/problem_data.py:29 msgid "Unordered" msgstr "无序的" -#: judge/models/problem_data.py:32 +#: judge/models/problem_data.py:30 msgid "Byte identical" msgstr "字节全等" -#: judge/models/problem_data.py:33 +#: judge/models/problem_data.py:31 msgid "Line-by-line" msgstr "" -#: judge/models/problem_data.py:34 +#: judge/models/problem_data.py:32 msgid "Custom checker (PY)" msgstr "" -#: judge/models/problem_data.py:35 +#: judge/models/problem_data.py:33 msgid "Custom validator (CPP)" msgstr "" -#: judge/models/problem_data.py:42 +#: judge/models/problem_data.py:40 msgid "data zip file" msgstr "zip数据文件" -#: judge/models/problem_data.py:44 +#: judge/models/problem_data.py:42 msgid "generator file" msgstr "生成器文件" -#: judge/models/problem_data.py:46 judge/models/problem_data.py:121 +#: judge/models/problem_data.py:44 judge/models/problem_data.py:110 msgid "output prefix length" msgstr "输出前缀长度" -#: judge/models/problem_data.py:47 judge/models/problem_data.py:122 +#: judge/models/problem_data.py:45 judge/models/problem_data.py:111 msgid "output limit length" msgstr "输出限制长度" -#: judge/models/problem_data.py:48 +#: judge/models/problem_data.py:46 msgid "init.yml generation feedback" msgstr "init.yml生成反馈" -#: judge/models/problem_data.py:49 judge/models/problem_data.py:123 +#: judge/models/problem_data.py:47 judge/models/problem_data.py:112 msgid "checker" msgstr "检查器" -#: judge/models/problem_data.py:50 judge/models/problem_data.py:124 +#: judge/models/problem_data.py:48 judge/models/problem_data.py:113 msgid "checker arguments" msgstr "检查器参数" -#: judge/models/problem_data.py:51 judge/models/problem_data.py:125 +#: judge/models/problem_data.py:49 judge/models/problem_data.py:114 msgid "checker arguments as a JSON object" msgstr "检查器参数作为JSON对象" -#: judge/models/problem_data.py:52 +#: judge/models/problem_data.py:50 msgid "custom checker file" msgstr "" -#: judge/models/problem_data.py:58 +#: judge/models/problem_data.py:56 msgid "custom validator file" msgstr "" -#: judge/models/problem_data.py:108 +#: judge/models/problem_data.py:97 msgid "problem data set" msgstr "题目数据集" -#: judge/models/problem_data.py:110 +#: judge/models/problem_data.py:99 msgid "case position" msgstr "测试编号" -#: judge/models/problem_data.py:111 +#: judge/models/problem_data.py:100 msgid "case type" msgstr "测试类型" -#: judge/models/problem_data.py:112 +#: judge/models/problem_data.py:101 msgid "Normal case" msgstr "正常测试" -#: judge/models/problem_data.py:113 +#: judge/models/problem_data.py:102 msgid "Batch start" msgstr "测试组开始" -#: judge/models/problem_data.py:114 +#: judge/models/problem_data.py:103 msgid "Batch end" msgstr "测试组结束" -#: judge/models/problem_data.py:116 +#: judge/models/problem_data.py:105 msgid "input file name" msgstr "输入的文件的名称" -#: judge/models/problem_data.py:117 +#: judge/models/problem_data.py:106 msgid "output file name" msgstr "输出文件的名称" -#: judge/models/problem_data.py:118 +#: judge/models/problem_data.py:107 msgid "generator arguments" msgstr "生成器参数" -#: judge/models/problem_data.py:119 +#: judge/models/problem_data.py:108 msgid "point value" msgstr "分数" -#: judge/models/problem_data.py:120 +#: judge/models/problem_data.py:109 msgid "case is pretest?" msgstr "是否为预测试?" @@ -1709,7 +1593,7 @@ msgid "" msgstr "" #: judge/models/profile.py:76 judge/models/profile.py:93 -#: judge/models/profile.py:212 +#: judge/models/profile.py:192 msgid "organization" msgstr "组织" @@ -1805,31 +1689,31 @@ msgstr "" msgid "Notes for administrators regarding this user." msgstr "" -#: judge/models/profile.py:206 +#: judge/models/profile.py:186 msgid "user profile" msgstr "用户信息" -#: judge/models/profile.py:207 +#: judge/models/profile.py:187 msgid "user profiles" msgstr "用户信息" -#: judge/models/profile.py:214 +#: judge/models/profile.py:194 msgid "request time" msgstr "请求时间" -#: judge/models/profile.py:215 +#: judge/models/profile.py:195 msgid "state" msgstr "状态" -#: judge/models/profile.py:220 +#: judge/models/profile.py:200 msgid "reason" msgstr "原因" -#: judge/models/profile.py:223 +#: judge/models/profile.py:203 msgid "organization join request" msgstr "组织加入请求" -#: judge/models/profile.py:224 +#: judge/models/profile.py:204 msgid "organization join requests" msgstr "组织加入请求" @@ -1927,88 +1811,88 @@ msgstr "扩展" msgid "The extension of source files, e.g., \"py\" or \"cpp\"." msgstr "源文件扩展名,例如:\"py\"或\"cpp\"。" -#: judge/models/runtime.py:112 +#: judge/models/runtime.py:109 msgid "languages" msgstr "语言" -#: judge/models/runtime.py:116 +#: judge/models/runtime.py:113 msgid "language to which this runtime belongs" msgstr "软件属于的语言" -#: judge/models/runtime.py:117 +#: judge/models/runtime.py:114 msgid "judge on which this runtime exists" msgstr "拥有次语言的裁判服务器" -#: judge/models/runtime.py:118 +#: judge/models/runtime.py:115 msgid "runtime name" msgstr "软件名称" -#: judge/models/runtime.py:119 +#: judge/models/runtime.py:116 msgid "runtime version" msgstr "软件版本" -#: judge/models/runtime.py:120 +#: judge/models/runtime.py:117 msgid "order in which to display this runtime" msgstr "软件显示顺序" -#: judge/models/runtime.py:124 +#: judge/models/runtime.py:121 msgid "Server name, hostname-style" msgstr "服务器名称" -#: judge/models/runtime.py:125 +#: judge/models/runtime.py:122 msgid "time of creation" msgstr "创建时间" -#: judge/models/runtime.py:126 +#: judge/models/runtime.py:123 #, fuzzy #| msgid "A key to authenticated this judge" msgid "A key to authenticate this judge" msgstr "裁判服务器连接密匙" -#: judge/models/runtime.py:127 +#: judge/models/runtime.py:124 msgid "authentication key" msgstr "连接密匙" -#: judge/models/runtime.py:128 +#: judge/models/runtime.py:125 msgid "block judge" msgstr "" -#: judge/models/runtime.py:129 +#: judge/models/runtime.py:126 msgid "" "Whether this judge should be blocked from connecting, even if its key is " "correct." msgstr "" -#: judge/models/runtime.py:131 +#: judge/models/runtime.py:128 msgid "judge online status" msgstr "裁判在线状态" -#: judge/models/runtime.py:132 +#: judge/models/runtime.py:129 msgid "judge start time" msgstr "裁判启动时间" -#: judge/models/runtime.py:133 +#: judge/models/runtime.py:130 msgid "response time" msgstr "响应时间" -#: judge/models/runtime.py:134 +#: judge/models/runtime.py:131 msgid "system load" msgstr "系统负载" -#: judge/models/runtime.py:135 +#: judge/models/runtime.py:132 msgid "Load for the last minute, divided by processors to be fair." msgstr "最后一分钟的系统负载(每处理器平均值)" -#: judge/models/runtime.py:139 judge/models/runtime.py:179 +#: judge/models/runtime.py:136 judge/models/runtime.py:176 msgid "judges" msgstr "裁判服务器" -#: judge/models/runtime.py:178 +#: judge/models/runtime.py:175 msgid "judge" msgstr "裁判服务器" #: judge/models/submission.py:20 judge/models/submission.py:47 -#: judge/utils/problems.py:79 +#: judge/utils/problems.py:77 msgid "Accepted" msgstr "接受" @@ -2037,7 +1921,7 @@ msgid "Runtime Error" msgstr "运行错误" #: judge/models/submission.py:27 judge/models/submission.py:41 -#: judge/models/submission.py:55 judge/utils/problems.py:81 +#: judge/models/submission.py:55 judge/utils/problems.py:79 msgid "Compile Error" msgstr "编译错误" @@ -2078,15 +1962,15 @@ msgstr "内部错误 (裁判服务器错误)" msgid "submission time" msgstr "提交时间" -#: judge/models/submission.py:67 judge/models/submission.py:203 +#: judge/models/submission.py:67 judge/models/submission.py:201 msgid "execution time" msgstr "执行时间" -#: judge/models/submission.py:68 judge/models/submission.py:204 +#: judge/models/submission.py:68 judge/models/submission.py:202 msgid "memory usage" msgstr "内存使用" -#: judge/models/submission.py:69 judge/models/submission.py:205 +#: judge/models/submission.py:69 judge/models/submission.py:203 msgid "points granted" msgstr "获得分数" @@ -2123,64 +2007,58 @@ msgid "judged on" msgstr "裁判服务器" #: judge/models/submission.py:81 -#, fuzzy -#| msgid "submission time" -msgid "submission judge time" -msgstr "提交时间" - -#: judge/models/submission.py:82 msgid "was rejudged by admin" msgstr "被管理员重新评分" -#: judge/models/submission.py:83 +#: judge/models/submission.py:82 msgid "was ran on pretests only" msgstr "只进行过预测试" -#: judge/models/submission.py:184 templates/contest/moss.html:58 +#: judge/models/submission.py:182 templates/contest/moss.html:58 msgid "submissions" msgstr "提交历史" -#: judge/models/submission.py:188 judge/models/submission.py:199 +#: judge/models/submission.py:186 judge/models/submission.py:197 msgid "associated submission" msgstr "相关提交" -#: judge/models/submission.py:190 +#: judge/models/submission.py:188 msgid "source code" msgstr "源码" -#: judge/models/submission.py:201 +#: judge/models/submission.py:199 msgid "test case ID" msgstr "测试编号" -#: judge/models/submission.py:202 +#: judge/models/submission.py:200 msgid "status flag" msgstr "状态标志" -#: judge/models/submission.py:206 +#: judge/models/submission.py:204 msgid "points possible" msgstr "满分" -#: judge/models/submission.py:207 +#: judge/models/submission.py:205 msgid "batch number" msgstr "批号" -#: judge/models/submission.py:208 +#: judge/models/submission.py:206 msgid "judging feedback" msgstr "评测反馈" -#: judge/models/submission.py:209 +#: judge/models/submission.py:207 msgid "extended judging feedback" msgstr "" -#: judge/models/submission.py:210 +#: judge/models/submission.py:208 msgid "program output" msgstr "程序输出" -#: judge/models/submission.py:218 +#: judge/models/submission.py:216 msgid "submission test case" msgstr "程序测试" -#: judge/models/submission.py:219 +#: judge/models/submission.py:217 msgid "submission test cases" msgstr "程序测试" @@ -2232,24 +2110,12 @@ msgstr "海报" msgid "message time" msgstr "消息时间" -#: judge/pdf_problems.py:147 judge/pdf_problems.py:199 -#: judge/pdf_problems.py:259 +#: judge/pdf_problems.py:134 judge/pdf_problems.py:186 +#: judge/pdf_problems.py:246 msgid "Page [page] of [topage]" msgstr "第[page]页,共[topage]页" -#: judge/pdf_problems.py:280 -#, fuzzy, python-format -#| msgid "Page %d of Posts" -msgid "Page %s of %s" -msgstr "帖子第%d页" - -#: judge/tasks/contest.py:19 -#, fuzzy -#| msgid "Recalculate scores" -msgid "Recalculating contest scores" -msgstr "重新计算总分" - -#: judge/tasks/contest.py:40 +#: judge/tasks/moss.py:25 msgid "Running MOSS" msgstr "" @@ -2261,62 +2127,62 @@ msgstr "" msgid "Recalculating user points" msgstr "" -#: judge/utils/problem_data.py:70 +#: judge/utils/problem_data.py:68 msgid "Empty batches not allowed." msgstr "不允许测试组为空。" -#: judge/utils/problem_data.py:78 judge/utils/problem_data.py:99 +#: judge/utils/problem_data.py:76 judge/utils/problem_data.py:97 #, fuzzy #| msgid "How did you corrupt the generator path?" msgid "How did you corrupt the custom checker path?" msgstr "你怎么使生成器路径崩溃?" -#: judge/utils/problem_data.py:120 +#: judge/utils/problem_data.py:118 #, python-format msgid "Points must be defined for non-batch case #%d." msgstr "编号为%d的组外测试必须设置分数。" -#: judge/utils/problem_data.py:125 +#: judge/utils/problem_data.py:123 #, python-format msgid "Input file for case %d does not exist: %s" msgstr "编号为%d的测试输入文件不存在:%s" -#: judge/utils/problem_data.py:128 +#: judge/utils/problem_data.py:126 #, python-format msgid "Output file for case %d does not exist: %s" msgstr "编号为%d的测试输出文件不存在:%s" -#: judge/utils/problem_data.py:153 +#: judge/utils/problem_data.py:151 #, python-format msgid "Batch start case #%d requires points." msgstr "编号为%d的测试组必须设置分数。" -#: judge/utils/problem_data.py:174 +#: judge/utils/problem_data.py:172 #, python-format msgid "Attempt to end batch outside of one in case #%d" msgstr "测试编号%d:试图在组外结束测试组。" -#: judge/utils/problem_data.py:192 +#: judge/utils/problem_data.py:190 msgid "How did you corrupt the zip path?" msgstr "你怎么损坏zip文件路径???" -#: judge/utils/problem_data.py:198 +#: judge/utils/problem_data.py:196 msgid "How did you corrupt the generator path?" msgstr "你怎么使生成器路径崩溃?" -#: judge/utils/problems.py:80 +#: judge/utils/problems.py:78 msgid "Wrong" msgstr "" -#: judge/utils/problems.py:82 +#: judge/utils/problems.py:80 msgid "Timeout" msgstr "" -#: judge/utils/problems.py:83 +#: judge/utils/problems.py:81 msgid "Error" msgstr "" -#: judge/utils/problems.py:94 +#: judge/utils/problems.py:92 msgid "Can't pass both queryset and keyword filters" msgstr "无法同时使用 queryset 和关键字筛选" @@ -2356,8 +2222,7 @@ msgctxt "hours and minutes" msgid "%h:%m" msgstr "%h:%m" -#: judge/views/about.py:7 templates/organization/home.html:112 -#: templates/user/user-about.html:83 templates/user/user-tabs.html:4 +#: judge/views/about.py:7 templates/user/user-about.html:33 msgid "About" msgstr "自我介绍" @@ -2365,167 +2230,157 @@ msgstr "自我介绍" msgid "Custom Checker Sample" msgstr "" -#: judge/views/blog.py:45 +#: judge/views/blog.py:38 #, python-format msgid "Page %d of Posts" msgstr "帖子第%d页" -#: judge/views/comment.py:28 +#: judge/views/comment.py:27 msgid "Messing around, are we?" msgstr "请别捣乱。" -#: judge/views/comment.py:37 +#: judge/views/comment.py:36 msgid "You must solve at least one problem before you can vote." msgstr "" -#: judge/views/comment.py:64 +#: judge/views/comment.py:63 msgid "You already voted." msgstr "你已经投了票。" -#: judge/views/comment.py:126 judge/views/organization.py:344 +#: judge/views/comment.py:120 judge/views/organization.py:299 msgid "Edited from site" msgstr "从网站中上编辑" -#: judge/views/comment.py:147 +#: judge/views/comment.py:141 msgid "Editing comment" msgstr "编辑评论" -#: judge/views/contests.py:57 judge/views/contests.py:247 -#: judge/views/contests.py:250 judge/views/contests.py:424 +#: judge/views/contests.py:55 judge/views/contests.py:215 +#: judge/views/contests.py:218 judge/views/contests.py:389 msgid "No such contest" msgstr "该竞赛不存在" -#: judge/views/contests.py:58 judge/views/contests.py:248 +#: judge/views/contests.py:56 judge/views/contests.py:216 #, python-format msgid "Could not find a contest with the key \"%s\"." msgstr "找不到标识符为“%s“的竞赛。" -#: judge/views/contests.py:71 +#: judge/views/contests.py:81 msgid "Contests" msgstr "竞赛" -#: judge/views/contests.py:251 +#: judge/views/contests.py:219 msgid "Could not find such contest." msgstr "找不到该竞赛。" -#: judge/views/contests.py:254 +#: judge/views/contests.py:222 #, python-format msgid "Access to contest \"%s\" denied" msgstr "对竞赛”%s“的访问被拒绝" -#: judge/views/contests.py:278 +#: judge/views/contests.py:246 msgid "Clone Contest" msgstr "" -#: judge/views/contests.py:343 +#: judge/views/contests.py:309 msgid "Contest not ongoing" msgstr "竞赛不在进行" -#: judge/views/contests.py:344 +#: judge/views/contests.py:310 #, python-format msgid "\"%s\" is not currently ongoing." msgstr "“%s“不在进行。" -#: judge/views/contests.py:348 +#: judge/views/contests.py:314 msgid "Already in contest" msgstr "已经参与了竞赛" -#: judge/views/contests.py:349 +#: judge/views/contests.py:315 #, python-format msgid "You are already in a contest: \"%s\"." msgstr "您已经参与了竞赛:”%s“。" -#: judge/views/contests.py:352 +#: judge/views/contests.py:318 msgid "Banned from joining" msgstr "" -#: judge/views/contests.py:353 +#: judge/views/contests.py:319 msgid "" "You have been declared persona non grata for this contest. You are " "permanently barred from joining this contest." msgstr "" -#: judge/views/contests.py:414 +#: judge/views/contests.py:379 #, python-format msgid "Enter access code for \"%s\"" msgstr "输入”%s“的访问码" -#: judge/views/contests.py:425 +#: judge/views/contests.py:390 #, python-format msgid "You are not in contest \"%s\"." msgstr "你不是在竞赛\"%s\"中。" -#: judge/views/contests.py:444 +#: judge/views/contests.py:409 msgid "ContestCalendar requires integer year and month" msgstr "" -#: judge/views/contests.py:484 +#: judge/views/contests.py:449 #, python-format msgid "Contests in %(month)s" msgstr "%(month)s的竞赛" -#: judge/views/contests.py:484 +#: judge/views/contests.py:449 msgid "F Y" msgstr "" -#: judge/views/contests.py:532 +#: judge/views/contests.py:496 #, fuzzy, python-format #| msgid "Statistics" msgid "%s Statistics" msgstr "统计数据" -#: judge/views/contests.py:717 +#: judge/views/contests.py:601 +msgid "???" +msgstr "???" + +#: judge/views/contests.py:664 #, python-format msgid "%s Rankings" msgstr "%s 排行榜" -#: judge/views/contests.py:725 -msgid "???" -msgstr "???" - -#: judge/views/contests.py:741 +#: judge/views/contests.py:680 #, python-format msgid "Your participation in %s" msgstr "你在%s中的参与历史" -#: judge/views/contests.py:742 +#: judge/views/contests.py:681 #, python-format msgid "%s's participation in %s" msgstr "%s在%s中的参与历史" -#: judge/views/contests.py:749 +#: judge/views/contests.py:685 msgid "Live" msgstr "实时" -#: judge/views/contests.py:761 templates/contest/contest-tabs.html:13 +#: judge/views/contests.py:697 msgid "Participation" msgstr "参与历史" -#: judge/views/contests.py:808 +#: judge/views/contests.py:743 #, python-format msgid "%s MOSS Results" msgstr "" -#: judge/views/contests.py:835 +#: judge/views/contests.py:770 #, python-format msgid "Running MOSS for %s..." msgstr "" -#: judge/views/contests.py:858 +#: judge/views/contests.py:793 #, python-format msgid "Contest tag: %s" msgstr "竞赛标签:%s" -#: judge/views/contests.py:868 judge/views/ticket.py:57 -msgid "Issue description" -msgstr "问题说明" - -#: judge/views/contests.py:911 -#, fuzzy, python-format -#| msgid "clarification body" -msgid "New clarification for %s" -msgstr "澄清的身体" - #: judge/views/error.py:14 msgid "404 error" msgstr "404 错误" @@ -2546,120 +2401,113 @@ msgid "corrupt page %s" msgstr "页面错误 %s" #: judge/views/language.py:12 templates/status/judge-status-table.html:9 -#: templates/status/status-tabs.html:5 msgid "Runtimes" msgstr "语言" -#: judge/views/notification.py:40 -#, python-format -msgid "Notifications (%d unseen)" -msgstr "" - -#: judge/views/organization.py:59 judge/views/organization.py:62 +#: judge/views/organization.py:44 judge/views/organization.py:47 msgid "No such organization" msgstr "无该组织" -#: judge/views/organization.py:60 +#: judge/views/organization.py:45 #, python-format msgid "Could not find an organization with the key \"%s\"." msgstr "找不到标识符为”%s“的组织。" -#: judge/views/organization.py:63 +#: judge/views/organization.py:48 msgid "Could not find such organization." msgstr "找不到该组织。" -#: judge/views/organization.py:79 judge/views/register.py:34 -#: templates/organization/list.html:32 templates/user/import/table_csv.html:9 -#: templates/user/user-list-tabs.html:6 +#: judge/views/organization.py:72 judge/views/register.py:34 +#: templates/organization/list.html:15 msgid "Organizations" msgstr "组织" -#: judge/views/organization.py:130 +#: judge/views/organization.py:93 #, python-format msgid "%s Members" msgstr "%s 成员列表" -#: judge/views/organization.py:159 judge/views/organization.py:162 -#: judge/views/organization.py:167 +#: judge/views/organization.py:118 judge/views/organization.py:121 +#: judge/views/organization.py:126 msgid "Joining organization" msgstr "加入组织" -#: judge/views/organization.py:159 +#: judge/views/organization.py:118 msgid "You are already in the organization." msgstr "你已经是该组织的成员。" -#: judge/views/organization.py:162 +#: judge/views/organization.py:121 msgid "This organization is not open." msgstr "该组织不开放。" -#: judge/views/organization.py:179 +#: judge/views/organization.py:138 msgid "Leaving organization" msgstr "离开组织" -#: judge/views/organization.py:179 +#: judge/views/organization.py:138 #, python-format msgid "You are not in \"%s\"." msgstr "你不是是“%s”的成员。" -#: judge/views/organization.py:203 +#: judge/views/organization.py:162 #, python-format msgid "Request to join %s" msgstr "请求加入 %s" -#: judge/views/organization.py:221 +#: judge/views/organization.py:180 msgid "Join request detail" msgstr "组织加入请求详细信息" -#: judge/views/organization.py:254 +#: judge/views/organization.py:209 #, python-format msgid "Managing join requests for %s" msgstr "管理 %s 的加入请求" -#: judge/views/organization.py:285 +#: judge/views/organization.py:240 #, python-format msgid "" "Your organization can only receive %d more members. You cannot approve %d " "users." msgstr "你的组织只能再接受%d个用户,无法接受%d个。" -#: judge/views/organization.py:297 +#: judge/views/organization.py:252 #, python-format msgid "Approved %d user." msgid_plural "Approved %d users." msgstr[0] "批准了%d个用户。" -#: judge/views/organization.py:298 +#: judge/views/organization.py:253 #, python-format msgid "Rejected %d user." msgid_plural "Rejected %d users." msgstr[0] "拒绝了%d个用户。" -#: judge/views/organization.py:328 +#: judge/views/organization.py:283 #, python-format msgid "Editing %s" msgstr "编辑 %s" -#: judge/views/organization.py:352 judge/views/organization.py:360 +#: judge/views/organization.py:307 judge/views/organization.py:315 msgid "Can't edit organization" msgstr "无法编辑组织" -#: judge/views/organization.py:353 +#: judge/views/organization.py:308 msgid "You are not allowed to edit this organization." msgstr "您没有编辑该组织的权利。" -#: judge/views/organization.py:361 +#: judge/views/organization.py:316 msgid "You are not allowed to kick people from this organization." msgstr "你没有踢组织成员的权利。" -#: judge/views/organization.py:366 judge/views/organization.py:370 +#: judge/views/organization.py:321 judge/views/organization.py:325 msgid "Can't kick user" msgstr "无法踢用户" -#: judge/views/organization.py:367 +#: judge/views/organization.py:322 msgid "The user you are trying to kick does not exist!" msgstr "你想踢的用户不存在!" -#: judge/views/organization.py:371 +#: judge/views/organization.py:326 #, python-format msgid "The user you are trying to kick is not in organization: %s." msgstr "你想踢的用户不是组织成员:%s" @@ -2683,36 +2531,35 @@ msgstr "{0} 的题解" msgid "Editorial for {0}" msgstr "{0}的题解" -#: judge/views/problem.py:285 templates/contest/contest.html:79 -#: templates/user/user-about.html:28 templates/user/user-tabs.html:5 -#: templates/user/users-table.html:31 +#: judge/views/problem.py:286 templates/contest/contest.html:79 +#: templates/user/users-table.html:23 msgid "Problems" msgstr "题目" -#: judge/views/problem.py:585 +#: judge/views/problem.py:547 msgid "Banned from submitting" msgstr "禁止提交" -#: judge/views/problem.py:586 +#: judge/views/problem.py:548 msgid "" "You have been declared persona non grata for this problem. You are " "permanently barred from submitting this problem." msgstr "您在该题目不受欢迎。您被永久禁止为该题目提交解决程序。" -#: judge/views/problem.py:600 +#: judge/views/problem.py:562 msgid "Too many submissions" msgstr "提交太多了" -#: judge/views/problem.py:601 +#: judge/views/problem.py:563 msgid "You have exceeded the submission limit for this problem." msgstr "您已超出此问题的提交限制。" -#: judge/views/problem.py:661 judge/views/problem.py:664 +#: judge/views/problem.py:633 judge/views/problem.py:636 #, python-format msgid "Submit to %(problem)s" msgstr "提交于 %(problem)s" -#: judge/views/problem.py:679 +#: judge/views/problem.py:652 msgid "Clone Problem" msgstr "" @@ -2753,22 +2600,22 @@ msgstr "编辑%s的测试数据" msgid "Generated init.yml for %s" msgstr "为%s生成的init.yml" -#: judge/views/problem_manage.py:52 judge/views/problem_manage.py:55 +#: judge/views/problem_manage.py:50 judge/views/problem_manage.py:53 #, python-format msgid "Managing submissions for %s" msgstr "" -#: judge/views/problem_manage.py:97 +#: judge/views/problem_manage.py:95 #, python-format msgid "Rejudging selected submissions for %s..." msgstr "" -#: judge/views/problem_manage.py:141 +#: judge/views/problem_manage.py:110 #, python-format msgid "Rescoring all submissions for %s..." msgstr "" -#: judge/views/problem_manage.py:150 +#: judge/views/problem_manage.py:119 #, python-format msgid "Successfully scheduled %d submission for rejudging." msgid_plural "Successfully scheduled %d submissions for rejudging." @@ -2816,25 +2663,25 @@ msgstr "首选语言" msgid "Subscribe to newsletter?" msgstr "订阅简讯" -#: judge/views/register.py:55 +#: judge/views/register.py:45 #, python-format msgid "" "The email address \"%s\" is already taken. Only one registration is allowed " "per address." msgstr "电子邮件地址“%s“已被使用。每个电子邮件地址只允许一个账户。" -#: judge/views/register.py:61 +#: judge/views/register.py:51 msgid "" "Your email provider is not allowed due to history of abuse. Please use a " "reputable email provider." msgstr "" "由于滥用历史,我们不允许您的电子邮件提供商。请使用有信誉的电子邮件提供商。" -#: judge/views/register.py:67 judge/views/register.py:105 +#: judge/views/register.py:57 judge/views/register.py:95 msgid "Registration" msgstr "注册" -#: judge/views/register.py:116 +#: judge/views/register.py:106 msgid "Authentication failure" msgstr "身份验证失败" @@ -2850,49 +2697,49 @@ msgstr "状态" msgid "Version matrix" msgstr "版本矩阵" -#: judge/views/submission.py:84 judge/views/submission.py:91 +#: judge/views/submission.py:83 judge/views/submission.py:90 #, python-format msgid "Submission of %(problem)s by %(user)s" msgstr "%(user)s 在 %(problem)s 的提交结果" -#: judge/views/submission.py:244 judge/views/submission.py:245 -#: templates/problem/problem.html:167 +#: judge/views/submission.py:227 judge/views/submission.py:228 +#: templates/problem/problem.html:127 msgid "All submissions" msgstr "所有提交历史" -#: judge/views/submission.py:404 +#: judge/views/submission.py:384 msgid "All my submissions" msgstr "我提交的程序" -#: judge/views/submission.py:405 +#: judge/views/submission.py:385 #, python-format msgid "All submissions by %s" msgstr "%s 的提交历史" -#: judge/views/submission.py:436 +#: judge/views/submission.py:416 #, python-format msgid "All submissions for %s" msgstr "%s 的提交历史" -#: judge/views/submission.py:455 +#: judge/views/submission.py:435 msgid "Must pass a problem" msgstr "必须给予题目" -#: judge/views/submission.py:501 +#: judge/views/submission.py:481 #, python-format msgid "My submissions for %(problem)s" msgstr "我对 %(problem)s 提交的程序" -#: judge/views/submission.py:502 +#: judge/views/submission.py:482 #, python-format msgid "%(user)s's submissions for %(problem)s" msgstr "%(user)s 在 %(problem)s 的提交历史" -#: judge/views/submission.py:603 +#: judge/views/submission.py:583 msgid "Must pass a contest" msgstr "必须给予竞赛" -#: judge/views/submission.py:622 +#: judge/views/submission.py:602 #, python-brace-format msgid "" "{0}'s submissions for {2} in {4}{0}{2} 的提交历史" -#: judge/views/submission.py:629 +#: judge/views/submission.py:609 #, python-brace-format msgid "" "{0}'s submissions for problem {2} in {3}" "" msgstr "{0}{3} 第 {2} 题提交的程序" -#: judge/views/ticket.py:50 judge/views/ticket.py:56 +#: judge/views/ticket.py:33 judge/views/ticket.py:39 msgid "Ticket title" msgstr "工单标题" -#: judge/views/ticket.py:107 judge/views/ticket.py:110 +#: judge/views/ticket.py:40 +msgid "Issue description" +msgstr "问题说明" + +#: judge/views/ticket.py:85 judge/views/ticket.py:88 #, python-format msgid "New ticket for %s" msgstr "新工单:%s" -#: judge/views/ticket.py:170 +#: judge/views/ticket.py:142 #, python-format msgid "%(title)s - Ticket %(id)d" msgstr "%(title)s -工单 %(id)d" -#: judge/views/ticket.py:279 +#: judge/views/ticket.py:251 #, python-format msgid "Tickets - Page %(number)d of %(total)d" msgstr "工单 - 第 %(number)d 页,共 %(total)d 页" -#: judge/views/ticket.py:328 +#: judge/views/ticket.py:300 #, python-format msgid "New Ticket: %s" msgstr "新工单:%s" -#: judge/views/ticket.py:329 +#: judge/views/ticket.py:301 #, python-format msgid "#%(id)d, assigned to: %(users)s" msgstr "#%(id)d, 分配给: %(users)s" -#: judge/views/ticket.py:331 +#: judge/views/ticket.py:303 msgid ", " msgstr ", " -#: judge/views/ticket.py:331 +#: judge/views/ticket.py:303 msgid "no one" msgstr "没人" -#: judge/views/ticket.py:351 +#: judge/views/ticket.py:323 #, fuzzy, python-format #| msgid "New Ticket: %s" msgid "New Ticket Message For: %s" @@ -2963,52 +2814,41 @@ msgstr "" msgid "Perform Two Factor Authentication" msgstr "" -#: judge/views/user.py:74 +#: judge/views/user.py:68 msgid "No such user" msgstr "无该用户" -#: judge/views/user.py:74 +#: judge/views/user.py:68 #, python-format msgid "No user handle \"%s\"." msgstr "无名为“%s“的用户" -#: judge/views/user.py:78 +#: judge/views/user.py:72 msgid "My account" msgstr "我的帐户" -#: judge/views/user.py:79 +#: judge/views/user.py:73 #, python-format msgid "User %s" msgstr "用户 %s" -#: judge/views/user.py:148 -#, fuzzy -#| msgid "M j, Y, G:i" -msgid "M j, Y" -msgstr "Y年n月j日 G:i" - -#: judge/views/user.py:171 +#: judge/views/user.py:136 msgid "M j, Y, G:i" msgstr "Y年n月j日 G:i" -#: judge/views/user.py:290 +#: judge/views/user.py:221 msgid "Updated on site" msgstr "在网站上更新" -#: judge/views/user.py:323 templates/admin/auth/user/change_form.html:14 -#: templates/admin/auth/user/change_form.html:17 templates/base.html:238 -#: templates/user/user-tabs.html:10 +#: judge/views/user.py:254 templates/admin/auth/user/change_form.html:14 +#: templates/admin/auth/user/change_form.html:17 templates/base.html:224 msgid "Edit profile" msgstr "编辑个人资料" -#: judge/views/user.py:332 templates/user/user-list-tabs.html:4 +#: judge/views/user.py:263 msgid "Leaderboard" msgstr "排行榜" -#: judge/views/user.py:407 -msgid "Import Users" -msgstr "" - #: judge/views/widgets.py:48 judge/views/widgets.py:58 #, python-format msgid "Invalid upstream data: %s" @@ -3046,7 +2886,7 @@ msgid "View Submissions" msgstr "" #: templates/admin/judge/problem/change_form.html:17 -#: templates/user/user-base.html:112 +#: templates/user/user-base.html:61 msgid "View submissions" msgstr "查看提交历史" @@ -3061,157 +2901,92 @@ msgstr "编辑用户" msgid "Rejudge" msgstr "重新评分" -#: templates/base.html:230 -#, python-format -msgid "Hello, %(username)s." -msgstr "你好,%(username)s。" - -#: templates/base.html:236 templates/comments/list.html:89 -#: templates/contest/contest-list-tabs.html:24 -#: templates/contest/ranking-table.html:53 -#: templates/problem/problem-list-tabs.html:6 +#: templates/base.html:222 templates/comments/list.html:89 +#: templates/contest/ranking-table.html:39 #: templates/submission/info-base.html:12 -#: templates/submission/submission-list-tabs.html:15 msgid "Admin" msgstr "管理" -#: templates/base.html:245 +#: templates/base.html:231 msgid "Log out" msgstr "登出" -#: templates/base.html:254 +#: templates/base.html:240 #: templates/registration/password_reset_complete.html:4 msgid "Log in" msgstr "登录" -#: templates/base.html:255 templates/registration/registration_form.html:177 +#: templates/base.html:241 templates/registration/registration_form.html:177 msgid "or" msgstr "或" -#: templates/base.html:256 +#: templates/base.html:242 msgid "Sign up" msgstr "" -#: templates/base.html:271 +#: templates/base.html:254 msgid "spectating" msgstr "旁观中" -#: templates/base.html:284 +#: templates/base.html:267 msgid "This site works best with JavaScript enabled." msgstr "本网站启用 JavaScript 效果最好。" -#: templates/blog/blog.html:13 templates/comments/list.html:68 -#: templates/comments/list.html:83 templates/contest/contest-tabs.html:23 -#: templates/contest/tag-title.html:9 templates/flatpages/admin_link.html:3 -#: templates/license.html:10 templates/problem/editorial.html:14 +#: templates/blog/content.html:13 templates/comments/list.html:68 +#: templates/comments/list.html:83 templates/contest/tag-title.html:9 +#: templates/flatpages/admin_link.html:3 templates/license.html:10 +#: templates/problem/editorial.html:14 msgid "Edit" msgstr "编辑" -#: templates/blog/blog.html:26 -#, python-format -msgid "" -"\n" -" posted on %(time)s\n" -" " -msgstr "" -"\n" -" 于 %(time)s 张贴 \n" -" " - -#: templates/blog/content.html:10 -#, python-brace-format -msgid "posted on {time}" -msgstr "贴在 {time}" - -#: templates/blog/dashboard.html:21 -#, python-format -msgid "" -"\n" -" on %(time)s\n" -" " -msgstr "" -"\n" -" 在 %(time)s\n" -" " - -#: templates/blog/list.html:93 +#: templates/blog/list.html:85 msgid "Blog" msgstr "更新" -#: templates/blog/list.html:95 +#: templates/blog/list.html:87 msgid "Events" msgstr "活动" -#: templates/blog/list.html:100 +#: templates/blog/list.html:92 msgid "News" msgstr "新闻" -#: templates/blog/list.html:115 templates/problem/list.html:347 -#: templates/problem/problem.html:361 +#: templates/blog/list.html:130 templates/problem/problem.html:310 msgid "Clarifications" msgstr "澄清" -#: templates/blog/list.html:121 -msgid "Add" -msgstr "" - -#: templates/blog/list.html:140 templates/problem/list.html:369 -#: templates/problem/problem.html:372 +#: templates/blog/list.html:146 templates/problem/problem.html:321 msgid "No clarifications have been made at this time." msgstr "目前还没有作出任何澄清。" -#: templates/blog/list.html:148 +#: templates/blog/list.html:154 msgid "Ongoing contests" msgstr "进行中的竞赛" -#: templates/blog/list.html:166 +#: templates/blog/list.html:172 msgid "Upcoming contests" msgstr "未来的竞赛" -#: templates/blog/list.html:184 -msgid "My open tickets" -msgstr "我的活动工单" - -#: templates/blog/list.html:206 -msgid "New tickets" -msgstr "新工单" - -#: templates/blog/list.html:227 -msgid "New problems" -msgstr "新题目" - -#: templates/blog/list.html:244 +#: templates/blog/list.html:189 msgid "Comment stream" msgstr "评论流" -#: templates/chat/chat.html:305 -msgid "Chat" +#: templates/blog/list.html:208 +msgid "New problems" +msgstr "新题目" + +#: templates/blog/list.html:225 +msgid "My open tickets" +msgstr "我的活动工单" + +#: templates/blog/list.html:246 +msgid "New tickets" +msgstr "新工单" + +#: templates/chat/chat.html:167 +msgid "Your message" msgstr "" -#: templates/chat/chat.html:307 templates/chat/chat.html:314 -#, fuzzy -#| msgid "Online Judge" -msgid "Online Users" -msgstr "在线评测系统" - -#: templates/chat/chat.html:315 -msgid "Refresh" -msgstr "" - -#: templates/chat/chat.html:333 -msgid "Emoji" -msgstr "" - -#: templates/chat/chat.html:334 -msgid "Enter your message" -msgstr "" - -#: templates/chat/message.html:20 -#, fuzzy -#| msgid "Delete?" -msgid "Delete" -msgstr "删除?" - #: templates/comments/list.html:2 msgid "Comments" msgstr "评论" @@ -3220,21 +2995,11 @@ msgstr "评论" msgid "Please login to vote" msgstr "登录后才可投票" -#: templates/comments/list.html:40 -#, python-brace-format -msgid "commented on {time}" -msgstr "于 {time} 时评论" - -#: templates/comments/list.html:49 -#, python-format -msgid "edit %(edits)s" -msgstr "编辑 %(edits)s" - -#: templates/comments/list.html:51 templates/comments/media-js.html:92 +#: templates/comments/list.html:51 templates/comments/media-js.html:77 msgid "edited" msgstr "已编辑" -#: templates/comments/list.html:60 templates/notification/list.html:14 +#: templates/comments/list.html:60 msgid "Link" msgstr "链接" @@ -3242,54 +3007,36 @@ msgstr "链接" msgid "Reply" msgstr "回复" -#: templates/comments/list.html:86 templates/contest/list.html:91 -#: templates/contest/list.html:95 templates/contest/list.html:280 +#: templates/comments/list.html:86 msgid "Hide" msgstr "隐藏" -#: templates/comments/list.html:101 -#, python-format -msgid "" -"\n" -" This comment is hidden due " -"to too much negative feedback.\n" -" Click here to view it.\n" -" " -msgstr "" - -#: templates/comments/list.html:121 +#: templates/comments/list.html:120 msgid "There are no comments at the moment." msgstr "目前没有评论。" -#: templates/comments/list.html:127 +#: templates/comments/list.html:126 msgid "New comment" msgstr "新评论" -#: templates/comments/list.html:141 +#: templates/comments/list.html:140 msgid "Invalid comment body." msgstr "无效的评论内容。" -#: templates/comments/list.html:149 +#: templates/comments/list.html:148 msgid "Post!" msgstr "发布" -#: templates/comments/list.html:157 +#: templates/comments/list.html:156 msgid "Comments are disabled on this page." msgstr "" -#: templates/comments/media-js.html:38 -#, fuzzy -#| msgid "no comments" -msgid "Replying to comment" -msgstr "没有评论" - -#: templates/comments/media-js.html:87 +#: templates/comments/media-js.html:72 #, python-brace-format msgid "edit {edits}" msgstr "编辑 {edits}" -#: templates/comments/media-js.html:90 +#: templates/comments/media-js.html:75 msgid "original" msgstr "源语言" @@ -3333,11 +3080,6 @@ msgstr "星期五" msgid "Saturday" msgstr "星期六" -#: templates/contest/clarification.html:52 templates/organization/new.html:10 -#: templates/ticket/new.html:38 -msgid "Create" -msgstr "创建" - #: templates/contest/clone.html:37 msgid "Enter a new key for the cloned contest:" msgstr "" @@ -3358,176 +3100,97 @@ msgstr "" msgid "Next" msgstr "下个月" -#: templates/contest/contest-list-tabs.html:21 -#: templates/problem/problem-list-tabs.html:5 -msgid "List" -msgstr "清单" - -#: templates/contest/contest-list-tabs.html:22 -msgid "Calendar" -msgstr "日历" - -#: templates/contest/contest-tabs.html:4 templates/organization/home.html:105 -msgid "Info" -msgstr "资料和信息" - -#: templates/contest/contest-tabs.html:6 templates/stats/base.html:9 -#: templates/submission/list.html:339 -msgid "Statistics" -msgstr "统计数据" - -#: templates/contest/contest-tabs.html:11 -msgid "Rankings" -msgstr "排行榜" - -#: templates/contest/contest-tabs.html:16 -msgid "Hidden Rankings" -msgstr "隐藏的排名" - -#: templates/contest/contest-tabs.html:21 -msgid "MOSS" -msgstr "" - -#: templates/contest/contest-tabs.html:26 -msgid "Clone" -msgstr "" - -#: templates/contest/contest-tabs.html:38 -#: templates/contest/contest-tabs.html:58 +#: templates/contest/contest-tabs.html:37 msgid "Leave contest" msgstr "离开竞赛" -#: templates/contest/contest-tabs.html:45 templates/contest/list.html:388 +#: templates/contest/contest-tabs.html:44 templates/contest/list.html:293 msgid "Virtual join" msgstr "参加虚拟竞赛" -#: templates/contest/contest-tabs.html:56 -msgid "Stop spectating" -msgstr "停止旁观" - -#: templates/contest/contest-tabs.html:65 +#: templates/contest/contest-tabs.html:64 msgid "Spectate contest" msgstr "旁观竞赛" -#: templates/contest/contest-tabs.html:72 +#: templates/contest/contest-tabs.html:70 +#: templates/contest/contest-tabs.html:76 msgid "Join contest" msgstr "参加竞赛" -#: templates/contest/contest-tabs.html:81 +#: templates/contest/contest-tabs.html:85 msgid "Login to participate" msgstr "登录即可进入" -#: templates/contest/contest.html:37 -msgid "Participating virtually." -msgstr "虚拟参与中。" - -#: templates/contest/contest.html:43 -msgid "Contest is over." -msgstr "竞赛已结束。" - #: templates/contest/contest.html:59 templates/contest/contest.html:63 msgid "F j, Y, G:i T" msgstr "Y年n月j日 G:i T" -#: templates/contest/contest.html:59 -#, python-format -msgid "" -"%(time_limit)s window between %(start_time)s and " -"%(end_time)s" -msgstr "" -"%(start_time)s%(end_time)s中的%(time_limit)s小时窗口" - -#: templates/contest/contest.html:63 -#, python-format -msgid "%(length)s long starting on %(start_time)s" -msgstr "从 %(start_time)s 开始的 %(length)s 时间段" - #: templates/contest/contest.html:85 msgid "AC Rate" msgstr "AC率" -#: templates/contest/contest.html:86 templates/contest/list.html:237 -#: templates/contest/list.html:289 templates/contest/list.html:366 -#: templates/problem/list.html:223 templates/problem/list.html:254 +#: templates/contest/contest.html:86 templates/contest/list.html:153 +#: templates/contest/list.html:195 templates/contest/list.html:271 +#: templates/problem/list.html:212 templates/problem/list.html:238 msgid "Users" msgstr "用户" -#: templates/contest/contest.html:111 templates/problem/list.html:330 +#: templates/contest/contest.html:111 msgid "Editorial" msgstr "编辑" -#: templates/contest/list.html:83 templates/contest/media-js.html:9 +#: templates/contest/list.html:31 templates/contest/media-js.html:9 msgid "Are you sure you want to join?" msgstr "你确定你想要加入吗?" -#: templates/contest/list.html:84 +#: templates/contest/list.html:32 msgid "" "Joining a contest for the first time starts your timer, after which it " "becomes unstoppable." msgstr "计时器在你第一次参加比赛的时候就会启动,比赛开始后将不会停止" -#: templates/contest/list.html:92 templates/contest/list.html:278 -msgid "Show" -msgstr "" - -#: templates/contest/list.html:102 templates/problem/list.html:68 -#, fuzzy -#| msgid "Organizations" -msgid "Organizations..." -msgstr "组织" - -#: templates/contest/list.html:135 +#: templates/contest/list.html:65 msgid "hidden" msgstr "" -#: templates/contest/list.html:140 +#: templates/contest/list.html:70 msgid "private" msgstr "" -#: templates/contest/list.html:154 +#: templates/contest/list.html:84 msgid "rated" msgstr "" -#: templates/contest/list.html:202 +#: templates/contest/list.html:132 msgid "Spectate" msgstr "旁观" -#: templates/contest/list.html:208 +#: templates/contest/list.html:138 msgid "Join" msgstr "加入!" -#: templates/contest/list.html:220 -#, fuzzy -#| msgid "Search problems..." -msgid "Search contests..." -msgstr "搜索题目…" - -#: templates/contest/list.html:229 -msgid "Search" -msgstr "" - -#: templates/contest/list.html:232 +#: templates/contest/list.html:148 msgid "Active Contests" msgstr "" -#: templates/contest/list.html:236 templates/contest/list.html:288 -#: templates/contest/list.html:327 templates/contest/list.html:365 +#: templates/contest/list.html:152 templates/contest/list.html:194 +#: templates/contest/list.html:232 templates/contest/list.html:270 msgid "Contest" msgstr "竞赛" -#: templates/contest/list.html:275 +#: templates/contest/list.html:190 msgid "Ongoing Contests" msgstr "进行中的竞赛" -#: templates/contest/list.html:322 +#: templates/contest/list.html:227 msgid "Upcoming Contests" msgstr "未来的竞赛" -#: templates/contest/list.html:350 +#: templates/contest/list.html:255 msgid "There are no scheduled contests at this time." msgstr "现在没有预定的竞赛。" -#: templates/contest/list.html:356 +#: templates/contest/list.html:261 msgid "Past Contests" msgstr "过去的竞赛" @@ -3578,89 +3241,55 @@ msgstr "" msgid "Only the following organizations may access this contest:" msgstr "只有下列组织可能访问此竞赛:" -#: templates/contest/ranking-table.html:9 templates/problem/search-form.html:35 +#: templates/contest/ranking-table.html:7 msgid "Organization" msgstr "组织" -#: templates/contest/ranking-table.html:10 templates/user/users-table.html:13 -#, fuzzy -#| msgid "full name" -msgid "Full Name" -msgstr "全名字" - -#: templates/contest/ranking-table.html:44 +#: templates/contest/ranking-table.html:30 msgid "Un-Disqualify" msgstr "" -#: templates/contest/ranking-table.html:47 +#: templates/contest/ranking-table.html:33 msgid "Disqualify" msgstr "" -#: templates/contest/ranking.html:187 +#: templates/contest/ranking.html:173 #, fuzzy #| msgid "Are you sure you want to join?" msgid "Are you sure you want to disqualify this participation?" msgstr "你确定你想要加入吗?" -#: templates/contest/ranking.html:192 +#: templates/contest/ranking.html:178 #, fuzzy #| msgid "Are you sure you want to join?" msgid "Are you sure you want to un-disqualify this participation?" msgstr "你确定你想要加入吗?" -#: templates/contest/ranking.html:463 +#: templates/contest/ranking.html:252 msgid "View user participation" msgstr "查看用户参与历史" -#: templates/contest/ranking.html:467 +#: templates/contest/ranking.html:256 msgid "Show organizations" msgstr "显示机构" -#: templates/contest/ranking.html:471 -#, fuzzy -#| msgid "full name" -msgid "Show full name" -msgstr "全名字" - -#: templates/contest/ranking.html:474 -#, fuzzy -#| msgid "Show my tickets only" -msgid "Show friends only" -msgstr "只显示我的工单" - -#: templates/contest/ranking.html:477 -msgid "Total score only" -msgstr "" - -#: templates/contest/ranking.html:479 -#, fuzzy -#| msgid "virtual participation id" -msgid "Show virtual participation" -msgstr "虚拟参与信息编号" - -#: templates/contest/stats.html:51 +#: templates/contest/stats.html:38 #, fuzzy #| msgid "problem translation" msgid "Problem Status Distribution" msgstr "题目翻译" -#: templates/contest/stats.html:56 +#: templates/contest/stats.html:43 #, fuzzy #| msgid "Problem name" msgid "Problem AC Rate" msgstr "题目名称" -#: templates/contest/stats.html:62 -#, fuzzy -#| msgid "problem translation" -msgid "Problem Point Distribution" -msgstr "题目翻译" - -#: templates/contest/stats.html:76 templates/stats/language.html:16 +#: templates/contest/stats.html:48 templates/stats/language.html:16 msgid "Submissions by Language" msgstr "按语言的提交数量" -#: templates/contest/stats.html:82 templates/stats/language.html:26 +#: templates/contest/stats.html:54 templates/stats/language.html:26 msgid "Language AC Rate" msgstr "语言提交接受率" @@ -3669,7 +3298,6 @@ msgid "Source:" msgstr "来源:" #: templates/newsletter/common.html:6 -#: templates/newsletter/newsletter_list.html:15 #: templates/newsletter/subscription_unsubscribe_activated.html:3 #: templates/newsletter/subscription_unsubscribe_activated.html:6 #: templates/newsletter/subscription_update_activated.html:3 @@ -3677,29 +3305,6 @@ msgstr "来源:" msgid "Newsletter" msgstr "电子简报" -#: templates/newsletter/newsletter_list.html:2 -#: templates/newsletter/newsletter_list.html:3 -#, fuzzy -#| msgid "Newsletter" -msgid "Newsletter list" -msgstr "电子简报" - -#: templates/newsletter/newsletter_list.html:6 -msgid "Subscribe to get the latest emails about upcoming contests and events." -msgstr "" - -#: templates/newsletter/newsletter_list.html:16 -#, fuzzy -#| msgid "Unsubscribe" -msgid "Subscribe" -msgstr "取消订阅" - -#: templates/newsletter/newsletter_list.html:30 -#, fuzzy -#| msgid "Update subscription" -msgid "Update subscriptions" -msgstr "更新订阅" - #: templates/newsletter/subscription_unsubscribe_activated.html:3 #: templates/newsletter/subscription_unsubscribe_activated.html:6 #: templates/newsletter/subscription_update_activated.html:3 @@ -3764,115 +3369,64 @@ msgstr "" "您的更新请求成功已被成功接收。我们已经发送了激活电子邮件。该电子邮件中包含了" "更新您的订阅的链接。" -#: templates/notification/list.html:7 -#, fuzzy -#| msgid "You have not shared any information." -msgid "You have no notifications" -msgstr "您还没有共享的任何信息。" - -#: templates/notification/list.html:13 -#, fuzzy -#| msgid "activate" -msgid "Activity" -msgstr "激活" - #: templates/organization/edit.html:46 #: templates/organization/requests/pending.html:34 #: templates/ticket/edit-notes.html:4 msgid "Update" msgstr "升级" -#: templates/organization/home.html:41 +#: templates/organization/home.html:7 msgid "Are you sure you want to leave this organization?" msgstr "" -#: templates/organization/home.html:43 +#: templates/organization/home.html:9 msgid "You will have to rejoin to show up on the organization leaderboard." msgstr "" -#: templates/organization/home.html:45 +#: templates/organization/home.html:11 msgid "You will have to request membership in order to join again." msgstr "" -#: templates/organization/home.html:88 -msgid "Join organization" -msgstr "加入组织" - -#: templates/organization/home.html:92 -msgid "Request membership" -msgstr "申请加入" - -#: templates/organization/home.html:122 -#, fuzzy -#| msgid "Organizations" -msgid "Organization news" -msgstr "组织" - -#: templates/organization/home.html:128 -#, fuzzy -#| msgid "There are no scheduled contests at this time." -msgid "There is no news at this time." -msgstr "现在没有预定的竞赛。" - -#: templates/organization/home.html:137 -#, fuzzy -#| msgid "Contest" -msgid "Controls" -msgstr "竞赛" - -#: templates/organization/home.html:142 -msgid "Edit organization" -msgstr "编辑组织" - -#: templates/organization/home.html:148 -msgid "View requests" -msgstr "查看请求" - -#: templates/organization/home.html:161 -msgid "Admin organization" -msgstr "管理组织" - -#: templates/organization/home.html:167 -msgid "View members" -msgstr "查看成员" - -#: templates/organization/home.html:174 +#: templates/organization/home.html:24 msgid "Leave organization" msgstr "离开组织" -#: templates/organization/home.html:183 -#, fuzzy -#| msgid "See private contests" -msgid "New private contests" -msgstr "查看私人竞赛" +#: templates/organization/home.html:29 +msgid "Join organization" +msgstr "加入组织" -#: templates/organization/home.html:193 templates/organization/home.html:208 -#, fuzzy -#| msgid "View as PDF" -msgid "View all" -msgstr "PDF 视图" +#: templates/organization/home.html:33 +msgid "Request membership" +msgstr "申请加入" -#: templates/organization/home.html:199 -#, fuzzy -#| msgid "New problems" -msgid "New private problems" -msgstr "新题目" +#: templates/organization/home.html:39 +msgid "Edit organization" +msgstr "编辑组织" -#: templates/organization/list.html:40 -#, fuzzy -#| msgid "Show organizations" -msgid "Show my organizations only" -msgstr "显示机构" +#: templates/organization/home.html:43 +msgid "View requests" +msgstr "查看请求" -#: templates/organization/list.html:47 templates/status/language-list.html:34 -#: templates/user/import/table_csv.html:6 +#: templates/organization/home.html:50 +msgid "Admin organization" +msgstr "管理组织" + +#: templates/organization/home.html:55 +msgid "View members" +msgstr "查看成员" + +#: templates/organization/list.html:23 templates/status/language-list.html:34 msgid "Name" msgstr "名称" -#: templates/organization/list.html:48 +#: templates/organization/list.html:24 msgid "Members" msgstr "成员" +#: templates/organization/new.html:10 templates/ticket/new.html:38 +msgid "Create" +msgstr "创建" + #: templates/organization/requests/detail.html:13 msgid "User:" msgstr "用户:" @@ -3905,7 +3459,7 @@ msgid "There are no requests to approve." msgstr "没有请求批准。" #: templates/organization/requests/pending.html:17 -#: templates/problem/data.html:432 +#: templates/problem/data.html:452 msgid "Delete?" msgstr "删除?" @@ -3941,37 +3495,37 @@ msgstr "踢出" msgid "Enter a new code for the cloned problem:" msgstr "" -#: templates/problem/data.html:119 +#: templates/problem/data.html:108 #, fuzzy #| msgid "Information" msgid "Instruction" msgstr "信息" -#: templates/problem/data.html:390 +#: templates/problem/data.html:410 msgid "View YAML" msgstr "查看 YAML" -#: templates/problem/data.html:421 templates/problem/data.html:472 +#: templates/problem/data.html:441 templates/problem/data.html:491 msgid "Apply!" msgstr "" -#: templates/problem/data.html:426 +#: templates/problem/data.html:446 msgid "Type" msgstr "类型" -#: templates/problem/data.html:427 +#: templates/problem/data.html:447 msgid "Input file" msgstr "输入文件" -#: templates/problem/data.html:428 +#: templates/problem/data.html:448 msgid "Output file" msgstr "输出文件" -#: templates/problem/data.html:430 +#: templates/problem/data.html:450 msgid "Pretest?" msgstr "预测试?" -#: templates/problem/data.html:473 +#: templates/problem/data.html:492 msgid "Add new case" msgstr "添加新的用例" @@ -3986,34 +3540,28 @@ msgstr "" "和题解的作者。

在真正解决问题之前提交题解的代码是可以封禁的罪行。" "" -#: templates/problem/list.html:66 +#: templates/problem/list.html:62 msgid "Filter by type..." msgstr "根据类型过滤" -#: templates/problem/list.html:193 +#: templates/problem/list.html:185 msgid "Hot problems" msgstr "热门问题" -#: templates/problem/list.html:218 templates/problem/list.html:240 -#: templates/problem/search-form.html:45 templates/user/user-problems.html:57 +#: templates/problem/list.html:207 templates/problem/list.html:224 +#: templates/problem/search-form.html:30 templates/user/user-problems.html:57 msgid "Category" msgstr "分类" -#: templates/problem/list.html:220 templates/problem/list.html:244 +#: templates/problem/list.html:209 templates/problem/list.html:228 msgid "Types" msgstr "类型" -#: templates/problem/list.html:251 +#: templates/problem/list.html:235 #, python-format msgid "AC %%" msgstr "AC%%" -#: templates/problem/list.html:342 -#, fuzzy -#| msgid "Clarifications" -msgid "Add clarifications" -msgstr "澄清" - #: templates/problem/manage_submission.html:55 msgid "Leave empty to not filter by language" msgstr "" @@ -4022,202 +3570,152 @@ msgstr "" msgid "Leave empty to not filter by result" msgstr "" -#: templates/problem/manage_submission.html:80 +#: templates/problem/manage_submission.html:79 msgid "Need valid values for both start and end IDs." msgstr "" -#: templates/problem/manage_submission.html:83 +#: templates/problem/manage_submission.html:82 msgid "End ID must be after start ID." msgstr "" +#: templates/problem/manage_submission.html:90 +#, python-brace-format +msgid "" +"You are about to rejudge {count} submissions. Are you sure you want to do " +"this?" +msgstr "" + #: templates/problem/manage_submission.html:96 -#, python-brace-format msgid "" -"You are about to {action} {count} submissions. Are you sure you want to do " -"this?" +"You are about to rejudge a few submissions. Are you sure you want to do this?" msgstr "" -#: templates/problem/manage_submission.html:103 -#, python-brace-format -msgid "" -"You are about to {action} a few submissions. Are you sure you want to do " -"this?" +#: templates/problem/manage_submission.html:115 +msgid "Rejudge Submissions" msgstr "" -#: templates/problem/manage_submission.html:127 -#: templates/submission/list.html:309 -msgid "Filter submissions" -msgstr "提交筛选" - -#: templates/problem/manage_submission.html:132 +#: templates/problem/manage_submission.html:120 msgid "Filter by ID:" msgstr "" -#: templates/problem/manage_submission.html:135 +#: templates/problem/manage_submission.html:123 msgid "Starting ID:" msgstr "" -#: templates/problem/manage_submission.html:139 +#: templates/problem/manage_submission.html:127 msgid "Ending ID:" msgstr "" -#: templates/problem/manage_submission.html:143 +#: templates/problem/manage_submission.html:131 msgid "This range includes both endpoints." msgstr "" -#: templates/problem/manage_submission.html:146 +#: templates/problem/manage_submission.html:134 msgid "Filter by language:" msgstr "" -#: templates/problem/manage_submission.html:154 +#: templates/problem/manage_submission.html:142 msgid "Filter by result:" msgstr "" -#: templates/problem/manage_submission.html:164 -#, fuzzy -#| msgid "location" -msgid "Action" -msgstr "位置" - -#: templates/problem/manage_submission.html:166 +#: templates/problem/manage_submission.html:150 msgid "Rejudge selected submissions" msgstr "" -#: templates/problem/manage_submission.html:171 -#, fuzzy -#| msgid "Too many submissions" -msgid "Download selected submissions" -msgstr "提交太多了" +#: templates/problem/manage_submission.html:157 +msgid "Rescore Everything" +msgstr "" -#: templates/problem/manage_submission.html:177 -#, fuzzy, python-format -#| msgid "Are you sure you want to join?" -msgid "Are you sure you want to rescore %(count)d submissions?" -msgstr "你确定你想要加入吗?" - -#: templates/problem/manage_submission.html:178 +#: templates/problem/manage_submission.html:163 msgid "Rescore all submissions" msgstr "" -#: templates/problem/problem.html:132 +#: templates/problem/problem.html:91 msgid "View as PDF" msgstr "PDF 视图" -#: templates/problem/problem.html:141 templates/problem/problem.html:151 -#: templates/problem/problem.html:156 +#: templates/problem/problem.html:101 templates/problem/problem.html:111 +#: templates/problem/problem.html:116 msgid "Submit solution" msgstr "提交程序" -#: templates/problem/problem.html:144 -#, python-format -msgid "%(counter)s submission left" -msgid_plural "%(counter)s submissions left" -msgstr[0] "还剩%(counter)s 提交数" - -#: templates/problem/problem.html:152 +#: templates/problem/problem.html:112 msgid "0 submissions left" msgstr "还剩下 0 次提交" -#: templates/problem/problem.html:164 +#: templates/problem/problem.html:124 msgid "My submissions" msgstr "我的提交历史" -#: templates/problem/problem.html:168 +#: templates/problem/problem.html:128 msgid "Best submissions" msgstr "提交排行" -#: templates/problem/problem.html:172 +#: templates/problem/problem.html:132 msgid "Read editorial" msgstr "阅读题解" -#: templates/problem/problem.html:177 +#: templates/problem/problem.html:137 msgid "Manage tickets" msgstr "管理工单" -#: templates/problem/problem.html:181 +#: templates/problem/problem.html:141 msgid "Edit problem" msgstr "编辑题目" -#: templates/problem/problem.html:183 +#: templates/problem/problem.html:143 msgid "Edit test data" msgstr "编辑测试数据" -#: templates/problem/problem.html:188 +#: templates/problem/problem.html:148 msgid "My tickets" msgstr "" -#: templates/problem/problem.html:196 +#: templates/problem/problem.html:156 msgid "Manage submissions" msgstr "" -#: templates/problem/problem.html:202 +#: templates/problem/problem.html:162 msgid "Clone problem" msgstr "复制题目" -#: templates/problem/problem.html:209 +#: templates/problem/problem.html:169 msgid "Points:" msgstr "分数:" -#: templates/problem/problem.html:212 templates/problem/problem.html:214 +#: templates/problem/problem.html:172 templates/problem/problem.html:174 msgid "(partial)" msgstr "(部分)" -#: templates/problem/problem.html:219 +#: templates/problem/problem.html:179 msgid "Time limit:" msgstr "时间限制:" -#: templates/problem/problem.html:231 +#: templates/problem/problem.html:191 msgid "Memory limit:" msgstr "内存限制:" -#: templates/problem/problem.html:250 -msgid "Author:" -msgid_plural "Authors:" -msgstr[0] "作者:" - -#: templates/problem/problem.html:265 -msgid "Problem type" -msgid_plural "Problem types" -msgstr[0] "题目类型" - -#: templates/problem/problem.html:278 +#: templates/problem/problem.html:238 msgid "Allowed languages" msgstr "允许的语言" -#: templates/problem/problem.html:286 -#, python-format -msgid "No %(lang)s judge online" -msgstr "没有支持 %(lang)s 的裁判服务器。" - -#: templates/problem/problem.html:297 -#, fuzzy -#| msgid "Judge" -msgid "Judge:" -msgid_plural "Judges:" -msgstr[0] "评测" - -#: templates/problem/problem.html:314 +#: templates/problem/problem.html:274 msgid "none available" msgstr "" -#: templates/problem/problem.html:326 -#, python-format -msgid "This problem has %(length)s clarification(s)" -msgstr "" - -#: templates/problem/problem.html:350 +#: templates/problem/problem.html:299 msgid "Request clarification" msgstr "提出问题" -#: templates/problem/problem.html:352 +#: templates/problem/problem.html:301 msgid "Report an issue" msgstr "反馈问题" -#: templates/problem/raw.html:64 +#: templates/problem/raw.html:62 msgid "Time Limit:" msgstr "" -#: templates/problem/raw.html:73 +#: templates/problem/raw.html:71 msgid "Memory Limit:" msgstr "" @@ -4241,79 +3739,39 @@ msgstr "隐藏已解决的题目" msgid "Show problem types" msgstr "显示题目类型" -#: templates/problem/search-form.html:32 -#, fuzzy -#| msgid "Read editorial" -msgid "Show editorial" -msgstr "阅读题解" - -#: templates/problem/search-form.html:48 templates/problem/search-form.html:50 -#: templates/submission/submission-list-tabs.html:4 +#: templates/problem/search-form.html:33 templates/problem/search-form.html:35 msgid "All" msgstr "所有" -#: templates/problem/search-form.html:62 +#: templates/problem/search-form.html:46 msgid "Problem types" msgstr "题目类型" -#: templates/problem/search-form.html:73 +#: templates/problem/search-form.html:57 msgid "Point range" msgstr "分数范围" -#: templates/problem/search-form.html:79 templates/submission/list.html:331 +#: templates/problem/search-form.html:63 templates/submission/list.html:331 #: templates/ticket/list.html:248 msgid "Go" msgstr "搜索" -#: templates/problem/search-form.html:80 +#: templates/problem/search-form.html:64 msgid "Random" msgstr "随机" -#: templates/problem/submit.html:117 -msgid "Your source code must contain at most 65536 characters." -msgstr "" - -#: templates/problem/submit.html:204 -#, python-format -msgid "" -"Warning! Your default language, %(default_language)s, is " -"unavailable for this problem and has been deselected." -msgstr "" -"警告! 您的默认编程语言, %(default_language)s, 在此问题不可用," -"且已取消选择。" - -#: templates/problem/submit.html:215 -#, python-format -msgid "" -"\n" -" You have %(left)s submission left\n" -" " -msgid_plural "" -"\n" -" You have %(left)s submissions left\n" -" " -msgstr[0] "" -"\n" -" 您还剩下 %(left)s 次提交机会 \n" -" " - -#: templates/problem/submit.html:224 +#: templates/problem/submit.html:212 msgid "You have 0 submissions left" msgstr "你還可以提交0次" -#: templates/problem/submit.html:258 +#: templates/problem/submit.html:250 msgid "No judge is available for this problem." msgstr "此题目没有可用的裁判服务器。" -#: templates/problem/submit.html:262 +#: templates/problem/submit.html:252 msgid "Submit!" msgstr "提交!" -#: templates/registration/activate.html:3 -#, python-format -msgid "%(key)s is an invalid activation key." -msgstr "%(key)s 是一个无效的激活密钥。" - #: templates/registration/activation_complete.html:3 msgid "Your account has been successfully activated." msgstr "已成功激活您的帐户。" @@ -4373,14 +3831,6 @@ msgstr "" "如果您没有收到电子邮件,请确保您打开的是您注册时所用的邮箱,并检查您的垃圾邮" "件文件夹。" -#: templates/registration/password_reset_email.txt:1 -#, python-format -msgid "" -"You're receiving this email because you requested a password reset for your " -"user account at %(site_name)s." -msgstr "" -"因为您要求您的用户帐户在 %(site_name)s 重置密码,所以您收到这封电子邮件。" - #: templates/registration/password_reset_email.txt:3 msgid "Please go to the following page and choose a new password:" msgstr "请转到以下页面以设置新密码:" @@ -4393,16 +3843,6 @@ msgstr "您的用户名:" msgid "Thanks for using our site!" msgstr "感谢您使用我们的网站!" -#: templates/registration/password_reset_email.txt:11 -#, python-format -msgid "The %(site_name)s team" -msgstr "%(site_name)s 团队" - -#: templates/registration/password_reset_subject.txt:1 -#, python-format -msgid "Password reset on %(site_name)s" -msgstr "在 %(site_name)s 上重置密码" - #: templates/registration/profile_creation.html:36 #: templates/registration/username_select.html:7 msgid "Continue >" @@ -4439,20 +3879,19 @@ msgstr "默认语言" msgid "Affiliated organizations" msgstr "关联的组织" -#: templates/registration/registration_form.html:195 -#: templates/user/edit-profile.html:128 +#: templates/registration/registration_form.html:192 msgid "Notify me about upcoming contests" msgstr "通过Email发送未来竞赛的通知" -#: templates/registration/registration_form.html:209 +#: templates/registration/registration_form.html:206 msgid "By registering, you agree to our" msgstr "注册即表示您同意我们的" -#: templates/registration/registration_form.html:210 +#: templates/registration/registration_form.html:207 msgid "Terms & Conditions" msgstr "使用条款" -#: templates/registration/registration_form.html:213 +#: templates/registration/registration_form.html:210 msgid "Register!" msgstr "注册!" @@ -4462,11 +3901,6 @@ msgstr "注册!" msgid "Enter the 6-digit code generated by your app:" msgstr "" -#: templates/registration/totp_auth.html:41 -#, python-format -msgid "If you lost your authentication device, please contact us at %(email)s." -msgstr "" - #: templates/registration/totp_disable.html:38 msgid "" "To protect your account, you must first authenticate before you can disable " @@ -4485,6 +3919,10 @@ msgstr "" msgid "Or enter this code manually:" msgstr "" +#: templates/stats/base.html:9 templates/submission/list.html:339 +msgid "Statistics" +msgstr "统计数据" + #: templates/stats/language.html:11 msgid "Submission Statistics" msgstr "提交统计" @@ -4510,7 +3948,6 @@ msgid "Ping" msgstr "延迟" #: templates/status/judge-status-table.html:8 -#: templates/user/import/index.html:104 msgid "Load" msgstr "负载" @@ -4526,7 +3963,6 @@ msgid "There are no judges available at this time." msgstr "本语言没有可用的裁判服务器。" #: templates/status/language-list.html:33 templates/ticket/list.html:261 -#: templates/user/import/table_csv.html:3 msgid "ID" msgstr "ID" @@ -4534,22 +3970,6 @@ msgstr "ID" msgid "Runtime Info" msgstr "软件信息" -#: templates/status/status-tabs.html:4 -msgid "Judges" -msgstr "裁判服务器" - -#: templates/status/status-tabs.html:6 -msgid "Version Matrix" -msgstr "版本矩阵" - -#: templates/submission/internal-error-message.html:3 -#, python-format -msgid "" -"An internal error occurred while grading, and the %(SITE_NAME)s " -"administrators have been notified.
In the meantime, try resubmitting in " -"a few seconds." -msgstr "" - #: templates/submission/internal-error-message.html:8 msgid "An internal error occurred while grading." msgstr "评分时裁判服务端发生了内部错误。" @@ -4566,6 +3986,10 @@ msgstr "按状态过滤" msgid "Filter by language..." msgstr "按语言筛选......" +#: templates/submission/list.html:309 +msgid "Filter submissions" +msgstr "提交筛选" + #: templates/submission/list.html:345 msgid "Total:" msgstr "" @@ -4622,80 +4046,79 @@ msgstr "预测试执行结果" msgid "Execution Results" msgstr "执行结果" -#: templates/submission/status-testcases.html:34 +#: templates/submission/status-testcases.html:31 +msgid "Batch " +msgstr "批" + +#: templates/submission/status-testcases.html:43 msgid "Overall: " msgstr "" -#: templates/submission/status-testcases.html:48 +#: templates/submission/status-testcases.html:57 #, fuzzy #| msgid "Points:" msgid "Point: " msgstr "分数:" -#: templates/submission/status-testcases.html:53 +#: templates/submission/status-testcases.html:62 #, fuzzy #| msgid "Time:" msgid "Time: " msgstr "时间:" -#: templates/submission/status-testcases.html:62 +#: templates/submission/status-testcases.html:71 #, fuzzy #| msgid "Memory" msgid "Memory: " msgstr "内存" -#: templates/submission/status-testcases.html:73 -msgid "Batch " -msgstr "批" - #: templates/submission/status-testcases.html:84 -#: templates/submission/status-testcases.html:113 +msgid "Case" +msgstr "测试" + +#: templates/submission/status-testcases.html:86 +msgid "Pretest" +msgstr "预测试" + +#: templates/submission/status-testcases.html:88 +msgid "Test case" +msgstr "测试情况" + +#: templates/submission/status-testcases.html:99 #, fuzzy #| msgid "Points" msgid "Point" msgstr "分数" -#: templates/submission/status-testcases.html:99 -msgid "Case" -msgstr "测试" - -#: templates/submission/status-testcases.html:101 -msgid "Pretest" -msgstr "预测试" - -#: templates/submission/status-testcases.html:103 -msgid "Test case" -msgstr "测试情况" - -#: templates/submission/status-testcases.html:141 +#: templates/submission/status-testcases.html:121 #, fuzzy #| msgid "Input file" msgid "Input:" msgstr "输入文件" -#: templates/submission/status-testcases.html:145 +#: templates/submission/status-testcases.html:125 #, fuzzy #| msgid "Output file" msgid "Output:" msgstr "输出文件" -#: templates/submission/status-testcases.html:149 +#: templates/submission/status-testcases.html:129 #, fuzzy #| msgid "Wrong Answer" msgid "Answer:" msgstr "答案错误" -#: templates/submission/status-testcases.html:154 +#: templates/submission/status-testcases.html:134 #, fuzzy #| msgid "judging feedback" msgid "Judge feedback:" msgstr "评测反馈" -#: templates/submission/status-testcases.html:175 +#: templates/submission/status-testcases.html:157 msgid "Passing pretests does not guarantee a full score on system tests." msgstr "通过预测试不代表程序可以通过完整测试。" -#: templates/submission/status-testcases.html:178 +#: templates/submission/status-testcases.html:160 msgid "Submission aborted!" msgstr "评分终止!" @@ -4707,24 +4130,11 @@ msgstr "查看源代码" msgid "Abort" msgstr "停止" -#: templates/submission/submission-list-tabs.html:6 -msgid "Mine" -msgstr "我的" - -#: templates/submission/submission-list-tabs.html:9 -msgid "Best" -msgstr "最佳" - -#: templates/submission/submission-list-tabs.html:12 -#, python-format -msgid "%(user)s's" -msgstr "%(user)s 的" - -#: templates/ticket/list.html:135 templates/ticket/ticket.html:273 +#: templates/ticket/list.html:135 templates/ticket/ticket.html:257 msgid "Reopened: " msgstr "重新打开状态: " -#: templates/ticket/list.html:138 templates/ticket/ticket.html:274 +#: templates/ticket/list.html:138 templates/ticket/ticket.html:258 msgid "Closed: " msgstr "已关闭: " @@ -4748,7 +4158,7 @@ msgstr "被分配的人" msgid "Title" msgstr "标题" -#: templates/ticket/list.html:264 templates/ticket/ticket.html:369 +#: templates/ticket/list.html:264 templates/ticket/ticket.html:328 msgid "Assignees" msgstr "被分配的人" @@ -4765,37 +4175,33 @@ msgstr "" "请注意, 此表单用于报告题目描述中的问题, 而不是寻求帮助。如果您需要询问解题方" "法, 请在评论中进行提问。" -#: templates/ticket/ticket.html:355 -msgid "Post" -msgstr "帖子" - -#: templates/ticket/ticket.html:363 +#: templates/ticket/ticket.html:322 msgid "Associated object" msgstr "相关的项目" -#: templates/ticket/ticket.html:374 +#: templates/ticket/ticket.html:333 msgid "No one is assigned." msgstr "没有人被分配到这个工单。" -#: templates/ticket/ticket.html:380 +#: templates/ticket/ticket.html:339 msgid "Close ticket" msgstr "关闭工单" -#: templates/ticket/ticket.html:382 +#: templates/ticket/ticket.html:341 msgid "Reopen ticket" msgstr "重开工单" -#: templates/ticket/ticket.html:386 +#: templates/ticket/ticket.html:345 msgid "Assignee notes" msgstr "受让人说明" -#: templates/ticket/ticket.html:393 templates/widgets/select_all.html:4 +#: templates/ticket/ticket.html:352 templates/widgets/select_all.html:4 msgid "Nothing here." msgstr "暂无内容!" -#: templates/user/base-users-table.html:3 -msgid "Rank" -msgstr "排名" +#: templates/ticket/ticket.html:385 +msgid "Post" +msgstr "帖子" #: templates/user/base-users.html:14 templates/user/base-users.html:69 msgid "Search by handle..." @@ -4841,211 +4247,50 @@ msgstr "用户脚本" msgid "Update profile" msgstr "更新资料" -#: templates/user/import/index.html:31 -msgid "Upload CSV only" -msgstr "" - -#: templates/user/import/index.html:100 -#, fuzzy -#| msgid "user profile" -msgid "User File" -msgstr "用户信息" - -#: templates/user/import/index.html:102 -msgid "Sample" -msgstr "" - -#: templates/user/import/index.html:105 templates/user/user-list-tabs.html:8 -msgid "Import" -msgstr "" - -#: templates/user/import/table_csv.html:7 -msgid "School" -msgstr "" - -#: templates/user/pp-row.html:22 -#, python-format -msgid "" -"\n" -" weighted %(weight)s%%\n" -" " -msgstr "" -"\n" -" 比重 %(weight)s%%\n" -" " - -#: templates/user/pp-row.html:27 -#, python-format -msgid "%(pp).1fpp" -msgstr "%(pp).1fpp" - -#: templates/user/pp-row.html:29 -#, python-format -msgid "%(pp).0fpp" -msgstr "%(pp).0fpp" - -#: templates/user/user-about.html:23 -#, fuzzy, python-format -#| msgid "contest problems" -msgid "%(counter)s problem solved" -msgid_plural "%(counter)s problems solved" -msgstr[0] "竞赛题目" - -#: templates/user/user-about.html:35 -#, fuzzy -#| msgid "Total points:" -msgid "Total points" -msgstr "总得分:" - -#: templates/user/user-about.html:45 -#, fuzzy -#| msgid "Rank by rating:" -msgid "Rank by rating" -msgstr "竞赛评分排名:" - -#: templates/user/user-about.html:52 -#, fuzzy -#| msgid "Rank by points:" -msgid "Rank by points" -msgstr "得分排名:" - -#: templates/user/user-about.html:64 +#: templates/user/user-about.html:14 msgid "From" msgstr "组织" -#: templates/user/user-about.html:75 +#: templates/user/user-about.html:25 msgid "Admin Notes" msgstr "" -#: templates/user/user-about.html:90 +#: templates/user/user-about.html:40 msgid "You have not shared any information." msgstr "您还没有共享的任何信息。" -#: templates/user/user-about.html:92 +#: templates/user/user-about.html:42 msgid "This user has not shared any information." msgstr "此用户没有共享的任何信息。" -#: templates/user/user-about.html:101 -msgid "Awards" -msgstr "" +#: templates/user/user-base.html:50 +msgid "Rank by points:" +msgstr "得分排名:" -#: templates/user/user-about.html:112 -#, fuzzy, python-format -#| msgctxt "contest problem" -#| msgid "%(problem)s in %(contest)s" -msgid "%(label)s (%(date)s)" -msgstr "%(contest)s 中的 %(problem)s" +#: templates/user/user-base.html:53 +msgid "Total points:" +msgstr "总得分:" -#: templates/user/user-about.html:130 -#, fuzzy -#| msgid "Monday" -msgid "Mon" -msgstr "星期一" +#: templates/user/user-base.html:68 +msgid "Rank by rating:" +msgstr "竞赛评分排名:" -#: templates/user/user-about.html:135 -#, fuzzy -#| msgid "Tuesday" -msgid "Tues" -msgstr "星期二" +#: templates/user/user-base.html:70 +msgid "Rating:" +msgstr "竞赛评分:" -#: templates/user/user-about.html:140 -msgid "Wed" -msgstr "" - -#: templates/user/user-about.html:145 -#, fuzzy -#| msgid "Thursday" -msgid "Thurs" -msgstr "星期四" - -#: templates/user/user-about.html:150 -#, fuzzy -#| msgid "Friday" -msgid "Fri" -msgstr "星期五" - -#: templates/user/user-about.html:155 -#, fuzzy -#| msgid "State" -msgid "Sat" -msgstr "状态" - -#: templates/user/user-about.html:160 -#, fuzzy -#| msgid "Sunday" -msgid "Sun" -msgstr "星期日" - -#: templates/user/user-about.html:169 -msgid "Less" -msgstr "" - -#: templates/user/user-about.html:175 -msgid "More" -msgstr "" - -#: templates/user/user-about.html:184 -#, fuzzy -#| msgid "History" -msgid "Rating History" -msgstr "编辑历史" - -#: templates/user/user-about.html:255 -msgid "past year" -msgstr "" - -#: templates/user/user-about.html:272 -#, fuzzy -#| msgid "All submissions" -msgid "total submission(s)" -msgstr "所有提交历史" - -#: templates/user/user-about.html:276 -#, fuzzy -#| msgid "submission test case" -msgid "submissions in the last year" -msgstr "程序测试" - -#: templates/user/user-base.html:101 -msgid "Unfollow" -msgstr "" - -#: templates/user/user-base.html:104 -msgid "Follow" -msgstr "" - -#: templates/user/user-base.html:120 -#, fuzzy -#| msgid "" -#| "\n" -#| " You have %(left)s submission left\n" -#| " " -#| msgid_plural "" -#| "\n" -#| " You have %(left)s submissions left\n" -#| " " -msgid "Contests written" -msgstr "" -"\n" -" 您还剩下 %(left)s 次提交机会 \n" -" " - -#: templates/user/user-base.html:124 +#: templates/user/user-base.html:71 msgid "Volatility:" msgstr "波动性:" -#: templates/user/user-base.html:128 +#: templates/user/user-base.html:72 msgid "Min. rating:" msgstr "最低评分:" -#: templates/user/user-base.html:132 +#: templates/user/user-base.html:73 msgid "Max rating:" msgstr "最高评分:" -#: templates/user/user-list-tabs.html:5 -msgid "Friends" -msgstr "" - #: templates/user/user-problems.html:35 msgid "Points Breakdown" msgstr "分数细分" @@ -5066,64 +4311,81 @@ msgstr "创作的题目" msgid "Hide problems I've solved" msgstr "隐藏我已经解决的题目" -#: templates/user/user-problems.html:93 -#, python-format -msgid "%(points).1f points" -msgstr "%(points).1f 分" - #: templates/user/user-problems.html:99 msgid "Score" msgstr "得分" -#: templates/user/user-problems.html:110 -#, python-format -msgid "%(points)s / %(total)s" -msgstr "%(points)s / %(total)s" - -#: templates/user/user-tabs.html:7 -msgid "Impersonate" -msgstr "假冒用户" - -#: templates/user/user-tabs.html:13 -msgid "Admin User" -msgstr "管理用户" - -#: templates/user/user-tabs.html:16 -msgid "Admin Profile" -msgstr "管理资料" - #: templates/widgets/select_all.html:8 msgid "Check all" msgstr "全选" -#, fuzzy -#~| msgid "%(counter)s submission left" -#~| msgid_plural "%(counter)s submissions left" -#~ msgid "%(cnt)d submission on %(date)s" -#~ msgid_plural "%(cnt)d submissions on %(date)s" -#~ msgstr[0] "还剩%(counter)s 提交数" - -#~ msgid "Rating:" -#~ msgstr "竞赛评分:" - -#, fuzzy -#~| msgid "Admin" -#~ msgid "Admins" -#~ msgstr "管理" - -#, fuzzy -#~| msgid "Rescore the selected submissions" -#~ msgid "This will rescore %(count)d submissions." -#~ msgstr "重新计算选定程序的分数" - -#, fuzzy -#~| msgid "%(points)s / %(total)s" -#~ msgid "Point %(point)s / Case #%(case)s" -#~ msgstr "%(points)s / %(total)s" - #~ msgid "output prefix length override" #~ msgstr "输出前缀替换" +#~ msgid "Hello, %(username)s." +#~ msgstr "你好,%(username)s。" + +#~ msgid "" +#~ "\n" +#~ " posted on %(time)s\n" +#~ " " +#~ msgstr "" +#~ "\n" +#~ " 于 %(time)s 张贴 \n" +#~ " " + +#~ msgid "" +#~ "\n" +#~ " on %(time)s\n" +#~ " " +#~ msgstr "" +#~ "\n" +#~ " 在 %(time)s\n" +#~ " " + +#~ msgid "posted on {time}" +#~ msgstr "贴在 {time}" + +#~ msgid "commented on {time}" +#~ msgstr "于 {time} 时评论" + +#~ msgid "edit %(edits)s" +#~ msgstr "编辑 %(edits)s" + +#~ msgid "List" +#~ msgstr "清单" + +#~ msgid "Calendar" +#~ msgstr "日历" + +#~ msgid "Info" +#~ msgstr "资料和信息" + +#~ msgid "Rankings" +#~ msgstr "排行榜" + +#~ msgid "Hidden Rankings" +#~ msgstr "隐藏的排名" + +#~ msgid "Stop spectating" +#~ msgstr "停止旁观" + +#~ msgid "Participating virtually." +#~ msgstr "虚拟参与中。" + +#~ msgid "Contest is over." +#~ msgstr "竞赛已结束。" + +#~ msgid "" +#~ "%(time_limit)s window between %(start_time)s and " +#~ "%(end_time)s" +#~ msgstr "" +#~ "%(start_time)s%(end_time)s中的%(time_limit)s小时窗" +#~ "口" + +#~ msgid "%(length)s long starting on %(start_time)s" +#~ msgstr "从 %(start_time)s 开始的 %(length)s 时间段" + #~ msgid "Started on {time}" #~ msgstr "开始时间{time}" @@ -5145,6 +4407,62 @@ msgstr "全选" #~ msgid "Generator args" #~ msgstr "生成器参数" +#~ msgid "%(counter)s submission left" +#~ msgid_plural "%(counter)s submissions left" +#~ msgstr[0] "还剩%(counter)s 提交数" + +#~ msgid "Author:" +#~ msgid_plural "Authors:" +#~ msgstr[0] "作者:" + +#~ msgid "Problem type" +#~ msgid_plural "Problem types" +#~ msgstr[0] "题目类型" + +#~ msgid "No %(lang)s judge online" +#~ msgstr "没有支持 %(lang)s 的裁判服务器。" + +#~ msgid "" +#~ "Warning! Your default language, %(default_language)s, is " +#~ "unavailable for this problem and has been deselected." +#~ msgstr "" +#~ "警告! 您的默认编程语言, %(default_language)s, 在此问题不可" +#~ "用,且已取消选择。" + +#~ msgid "" +#~ "\n" +#~ " You have %(left)s submission left\n" +#~ " " +#~ msgid_plural "" +#~ "\n" +#~ " You have %(left)s submissions left\n" +#~ " " +#~ msgstr[0] "" +#~ "\n" +#~ " 您还剩下 %(left)s 次提交机会 \n" +#~ " " + +#~ msgid "%(key)s is an invalid activation key." +#~ msgstr "%(key)s 是一个无效的激活密钥。" + +#~ msgid "" +#~ "You're receiving this email because you requested a password reset for " +#~ "your user account at %(site_name)s." +#~ msgstr "" +#~ "因为您要求您的用户帐户在 %(site_name)s 重置密码,所以您收到这封电子邮件。" + +#~ msgid "The %(site_name)s team" +#~ msgstr "%(site_name)s 团队" + +#~ msgid "Password reset on %(site_name)s" +#~ msgstr "在 %(site_name)s 上重置密码" + +#~ msgid "Judges" +#~ msgstr "裁判服务器" + +#~ msgid "Version Matrix" +#~ msgstr "版本矩阵" + #~ msgid "Case #%(case)s" #~ msgstr "测试数据 #%(case)s" @@ -5156,3 +4474,45 @@ msgstr "全选" #~ msgid "Final score:" #~ msgstr "最终得分:" + +#~ msgid "Mine" +#~ msgstr "我的" + +#~ msgid "Best" +#~ msgstr "最佳" + +#~ msgid "%(user)s's" +#~ msgstr "%(user)s 的" + +#~ msgid "Rank" +#~ msgstr "排名" + +#~ msgid "" +#~ "\n" +#~ " weighted %(weight)s%%\n" +#~ " " +#~ msgstr "" +#~ "\n" +#~ " 比重 %(weight)s%%\n" +#~ " " + +#~ msgid "%(pp).1fpp" +#~ msgstr "%(pp).1fpp" + +#~ msgid "%(pp).0fpp" +#~ msgstr "%(pp).0fpp" + +#~ msgid "%(points).1f points" +#~ msgstr "%(points).1f 分" + +#~ msgid "%(points)s / %(total)s" +#~ msgstr "%(points)s / %(total)s" + +#~ msgid "Impersonate" +#~ msgstr "假冒用户" + +#~ msgid "Admin User" +#~ msgstr "管理用户" + +#~ msgid "Admin Profile" +#~ msgstr "管理资料" diff --git a/locale/zh_Hans/LC_MESSAGES/djangojs.po b/locale/zh_Hans/LC_MESSAGES/djangojs.po index 8b46b5f..6531402 100644 --- a/locale/zh_Hans/LC_MESSAGES/djangojs.po +++ b/locale/zh_Hans/LC_MESSAGES/djangojs.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: dmoj\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-07-20 23:30+0700\n" +"POT-Creation-Date: 2019-10-01 23:12+0000\n" "PO-Revision-Date: 2019-11-11 22:05\n" "Last-Translator: Icyene\n" "Language-Team: Chinese Simplified\n" @@ -26,3 +26,4 @@ msgstr[0] "%d 天 %h:%m:%s" msgctxt "time format without day" msgid "%h:%m:%s" msgstr "%h:%m:%s" + diff --git a/locale/zh_Hant/LC_MESSAGES/django.po b/locale/zh_Hant/LC_MESSAGES/django.po index 24bd3ae..675a4ce 100644 --- a/locale/zh_Hant/LC_MESSAGES/django.po +++ b/locale/zh_Hant/LC_MESSAGES/django.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: dmoj\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-10-25 05:59+0700\n" +"POT-Creation-Date: 2020-04-10 01:26-0500\n" "PO-Revision-Date: 2019-11-11 22:05\n" "Last-Translator: Icyene\n" "Language-Team: Chinese Traditional\n" @@ -16,93 +16,93 @@ msgstr "" "X-Crowdin-Language: zh-TW\n" "X-Crowdin-File: django.po\n" -#: chat_box/models.py:16 judge/admin/interface.py:110 -#: judge/models/contest.py:403 judge/models/contest.py:528 -#: judge/models/profile.py:211 +#: chat_box/models.py:15 judge/admin/interface.py:107 +#: judge/models/contest.py:257 judge/models/contest.py:381 +#: judge/models/profile.py:191 msgid "user" msgstr "使用者" -#: chat_box/models.py:17 judge/models/comment.py:43 judge/models/comment.py:191 +#: chat_box/models.py:16 judge/models/comment.py:42 msgid "posted time" msgstr "發佈時間" -#: chat_box/models.py:18 judge/models/comment.py:47 +#: chat_box/models.py:17 judge/models/comment.py:46 msgid "body of comment" msgstr "" -#: chat_box/views.py:29 templates/chat/chat.html:4 +#: chat_box/views.py:29 msgid "Chat Box" msgstr "" -#: dmoj/settings.py:355 +#: dmoj/settings.py:349 msgid "German" msgstr "德文" -#: dmoj/settings.py:356 +#: dmoj/settings.py:350 msgid "English" msgstr "英文" -#: dmoj/settings.py:357 +#: dmoj/settings.py:351 msgid "Spanish" msgstr "西班牙文" -#: dmoj/settings.py:358 +#: dmoj/settings.py:352 msgid "French" msgstr "法文" -#: dmoj/settings.py:359 +#: dmoj/settings.py:353 msgid "Croatian" msgstr "克羅地亞文" -#: dmoj/settings.py:360 +#: dmoj/settings.py:354 msgid "Hungarian" msgstr "匈牙利文" -#: dmoj/settings.py:361 +#: dmoj/settings.py:355 msgid "Japanese" msgstr "" -#: dmoj/settings.py:362 +#: dmoj/settings.py:356 msgid "Korean" msgstr "韓文" -#: dmoj/settings.py:363 +#: dmoj/settings.py:357 msgid "Brazilian Portuguese" msgstr "" -#: dmoj/settings.py:364 +#: dmoj/settings.py:358 msgid "Romanian" msgstr "羅馬尼亞文" -#: dmoj/settings.py:365 +#: dmoj/settings.py:359 msgid "Russian" msgstr "俄文" -#: dmoj/settings.py:366 +#: dmoj/settings.py:360 msgid "Serbian (Latin)" msgstr "塞爾維亞文 (拉丁語系)" -#: dmoj/settings.py:367 +#: dmoj/settings.py:361 msgid "Turkish" msgstr "土耳其文" -#: dmoj/settings.py:368 +#: dmoj/settings.py:362 msgid "Vietnamese" msgstr "越南文" -#: dmoj/settings.py:369 +#: dmoj/settings.py:363 msgid "Simplified Chinese" msgstr "簡體中文" -#: dmoj/settings.py:370 +#: dmoj/settings.py:364 msgid "Traditional Chinese" msgstr "" -#: dmoj/urls.py:58 +#: dmoj/urls.py:57 msgid "Login" msgstr "登入" -#: dmoj/urls.py:106 templates/base.html:193 +#: dmoj/urls.py:105 templates/base.html:190 msgid "Home" msgstr "首頁" @@ -130,88 +130,86 @@ msgstr "取消隱藏回應" msgid "Associated page" msgstr "關聯頁" -#: judge/admin/contest.py:30 +#: judge/admin/contest.py:28 msgid "Included contests" msgstr "" -#: judge/admin/contest.py:66 templates/contest/clarification.html:42 -#: templates/contest/contest.html:83 templates/contest/moss.html:43 -#: templates/problem/list.html:214 templates/problem/list.html:232 -#: templates/problem/list.html:350 templates/user/user-problems.html:56 +#: judge/admin/contest.py:64 templates/contest/contest.html:83 +#: templates/contest/moss.html:43 templates/problem/list.html:206 +#: templates/problem/list.html:221 templates/user/user-problems.html:56 #: templates/user/user-problems.html:98 msgid "Problem" msgstr "題目" -#: judge/admin/contest.py:119 +#: judge/admin/contest.py:112 msgid "Settings" msgstr "" -#: judge/admin/contest.py:121 +#: judge/admin/contest.py:114 msgid "Scheduling" msgstr "排程" -#: judge/admin/contest.py:122 templates/organization/home.html:107 +#: judge/admin/contest.py:115 msgid "Details" msgstr "詳細資訊" -#: judge/admin/contest.py:123 +#: judge/admin/contest.py:116 msgid "Format" msgstr "" -#: judge/admin/contest.py:124 templates/contest/ranking-table.html:7 -#: templates/user/user-about.html:15 templates/user/user-about.html:45 +#: judge/admin/contest.py:117 templates/contest/ranking-table.html:5 msgid "Rating" msgstr "評分" -#: judge/admin/contest.py:125 +#: judge/admin/contest.py:118 msgid "Access" msgstr "" -#: judge/admin/contest.py:127 judge/admin/problem.py:131 +#: judge/admin/contest.py:120 judge/admin/problem.py:131 msgid "Justice" msgstr "" -#: judge/admin/contest.py:207 +#: judge/admin/contest.py:158 #, python-format msgid "%d contest successfully marked as visible." msgid_plural "%d contests successfully marked as visible." msgstr[0] "" -#: judge/admin/contest.py:210 +#: judge/admin/contest.py:161 msgid "Mark contests as visible" msgstr "" -#: judge/admin/contest.py:216 +#: judge/admin/contest.py:165 #, python-format msgid "%d contest successfully marked as hidden." msgid_plural "%d contests successfully marked as hidden." msgstr[0] "" -#: judge/admin/contest.py:219 +#: judge/admin/contest.py:168 msgid "Mark contests as hidden" msgstr "" -#: judge/admin/contest.py:233 judge/admin/submission.py:164 +#: judge/admin/contest.py:182 judge/admin/submission.py:164 #, python-format msgid "%d submission was successfully scheduled for rejudging." msgid_plural "%d submissions were successfully scheduled for rejudging." msgstr[0] "" -#: judge/admin/contest.py:308 +#: judge/admin/contest.py:256 #, python-format msgid "%d participation recalculated." msgid_plural "%d participations recalculated." msgstr[0] "" -#: judge/admin/contest.py:311 +#: judge/admin/contest.py:259 msgid "Recalculate results" msgstr "" -#: judge/admin/contest.py:315 judge/admin/organization.py:65 +#: judge/admin/contest.py:263 judge/admin/organization.py:65 msgid "username" msgstr "使用者名稱" -#: judge/admin/contest.py:320 templates/base.html:277 +#: judge/admin/contest.py:268 templates/base.html:260 msgid "virtual" msgstr "" @@ -219,15 +217,15 @@ msgstr "" msgid "link path" msgstr "" -#: judge/admin/interface.py:65 +#: judge/admin/interface.py:62 msgid "Content" msgstr "内容" -#: judge/admin/interface.py:66 +#: judge/admin/interface.py:63 msgid "Summary" msgstr "概要" -#: judge/admin/interface.py:151 +#: judge/admin/interface.py:148 msgid "object" msgstr "" @@ -249,9 +247,8 @@ msgid "Taxonomy" msgstr "" #: judge/admin/problem.py:128 templates/contest/contest.html:84 -#: templates/problem/data.html:429 templates/problem/list.html:222 -#: templates/problem/list.html:248 templates/user/base-users-table.html:10 -#: templates/user/user-about.html:36 templates/user/user-about.html:52 +#: templates/problem/data.html:449 templates/problem/list.html:211 +#: templates/problem/list.html:232 templates/user/base-users-table.html:10 #: templates/user/user-problems.html:58 msgid "Points" msgstr "分數" @@ -298,7 +295,6 @@ msgid "timezone" msgstr "時區" #: judge/admin/profile.py:86 judge/admin/submission.py:211 -#: templates/notification/list.html:12 #: templates/organization/requests/log.html:9 #: templates/organization/requests/pending.html:12 #: templates/ticket/list.html:263 @@ -306,7 +302,6 @@ msgid "User" msgstr "使用者" #: judge/admin/profile.py:91 templates/registration/registration_form.html:145 -#: templates/user/import/table_csv.html:8 msgid "Email" msgstr "電子郵件" @@ -338,7 +333,7 @@ msgstr "" msgid "These problems are NOT allowed to be submitted in this language" msgstr "" -#: judge/admin/runtime.py:83 templates/problem/list.html:352 +#: judge/admin/runtime.py:83 msgid "Description" msgstr "描述說明" @@ -385,7 +380,7 @@ msgstr "" msgid "Rejudge the selected submissions" msgstr "" -#: judge/admin/submission.py:193 judge/views/problem_manage.py:159 +#: judge/admin/submission.py:193 judge/views/problem_manage.py:128 #, python-format msgid "%d submission were successfully rescored." msgid_plural "%d submissions were successfully rescored." @@ -395,8 +390,7 @@ msgstr[0] "" msgid "Rescore the selected submissions" msgstr "" -#: judge/admin/submission.py:200 templates/problem/list.html:216 -#: templates/problem/list.html:236 +#: judge/admin/submission.py:200 msgid "Problem code" msgstr "" @@ -404,12 +398,10 @@ msgstr "" msgid "Problem name" msgstr "題目名稱" -#: judge/admin/submission.py:215 templates/notification/list.html:15 -#: templates/organization/requests/log.html:10 +#: judge/admin/submission.py:215 templates/organization/requests/log.html:10 #: templates/organization/requests/pending.html:13 -#: templates/problem/list.html:351 -#: templates/submission/status-testcases.html:125 -#: templates/submission/status-testcases.html:127 +#: templates/submission/status-testcases.html:105 +#: templates/submission/status-testcases.html:107 msgid "Time" msgstr "時間" @@ -423,7 +415,7 @@ msgstr "%d KB" msgid "%.2f MB" msgstr "%.2f MB" -#: judge/admin/submission.py:227 templates/submission/status-testcases.html:132 +#: judge/admin/submission.py:227 templates/submission/status-testcases.html:112 msgid "Memory" msgstr "記憶體" @@ -443,20 +435,20 @@ msgstr "" msgid "Online Judge" msgstr "線上裁判" -#: judge/comments.py:60 +#: judge/comments.py:41 msgid "Comment body" msgstr "" -#: judge/comments.py:66 judge/views/ticket.py:63 +#: judge/comments.py:47 judge/views/ticket.py:46 msgid "Your part is silent, little toad." msgstr "" -#: judge/comments.py:69 templates/comments/list.html:132 +#: judge/comments.py:50 templates/comments/list.html:131 msgid "" "You need to have solved at least one problem before your voice can be heard." msgstr "" -#: judge/comments.py:113 +#: judge/comments.py:92 msgid "Posted comment" msgstr "" @@ -472,10 +464,6 @@ msgstr "" msgid "ECOO" msgstr "" -#: judge/contest_format/icpc.py:19 -msgid "ICPC" -msgstr "" - #: judge/contest_format/ioi.py:19 msgid "IOI" msgstr "" @@ -488,58 +476,52 @@ msgstr "" msgid "Enable experimental features" msgstr "" -#: judge/forms.py:57 judge/views/organization.py:168 judge/views/register.py:49 +#: judge/forms.py:57 judge/views/organization.py:127 #, python-brace-format msgid "You may not be part of more than {count} public organizations." msgstr "" -#: judge/forms.py:82 -msgid "Any judge" -msgstr "" - -#: judge/forms.py:112 judge/views/register.py:26 +#: judge/forms.py:107 judge/views/register.py:26 #: templates/registration/registration_form.html:139 #: templates/user/base-users-table.html:5 -#: templates/user/import/table_csv.html:4 msgid "Username" msgstr "使用者名稱" -#: judge/forms.py:113 templates/registration/registration_form.html:151 +#: judge/forms.py:108 templates/registration/registration_form.html:151 #: templates/registration/registration_form.html:165 -#: templates/user/import/table_csv.html:5 msgid "Password" msgstr "密碼" -#: judge/forms.py:135 +#: judge/forms.py:130 msgid "Two Factor Authentication tokens must be 6 decimal digits." msgstr "" -#: judge/forms.py:144 templates/registration/totp_auth.html:32 +#: judge/forms.py:139 templates/registration/totp_auth.html:32 msgid "Invalid Two Factor Authentication token." msgstr "" -#: judge/forms.py:148 judge/models/problem.py:97 +#: judge/forms.py:143 judge/models/problem.py:97 msgid "Problem code must be ^[a-z0-9]+$" msgstr "" -#: judge/forms.py:153 +#: judge/forms.py:148 msgid "Problem with code already exists." msgstr "" -#: judge/forms.py:158 judge/models/contest.py:61 +#: judge/forms.py:153 judge/models/contest.py:52 msgid "Contest id must be ^[a-z0-9]+$" msgstr "" -#: judge/forms.py:163 +#: judge/forms.py:158 msgid "Contest with key already exists." msgstr "" -#: judge/jinja2/datetime.py:26 templates/blog/blog.html:26 +#: judge/jinja2/datetime.py:26 templates/blog/content.html:27 #: templates/blog/dashboard.html:21 msgid "N j, Y, g:i a" msgstr "" -#: judge/jinja2/datetime.py:26 templates/chat/message.html:13 +#: judge/jinja2/datetime.py:26 #, python-brace-format msgid "{time}" msgstr "" @@ -569,542 +551,472 @@ msgstr "" msgid "Detect best quality" msgstr "" -#: judge/models/comment.py:26 +#: judge/models/comment.py:25 msgid "Page code must be ^[pcs]:[a-z0-9]+$|^b:\\d+$" msgstr "" -#: judge/models/comment.py:42 +#: judge/models/comment.py:41 msgid "commenter" msgstr "" -#: judge/models/comment.py:44 judge/models/comment.py:177 +#: judge/models/comment.py:43 judge/models/comment.py:176 msgid "associated page" msgstr "" -#: judge/models/comment.py:46 +#: judge/models/comment.py:45 msgid "votes" msgstr "投票" -#: judge/models/comment.py:48 +#: judge/models/comment.py:47 msgid "hide the comment" msgstr "" -#: judge/models/comment.py:49 +#: judge/models/comment.py:48 msgid "parent" msgstr "" -#: judge/models/comment.py:54 judge/models/comment.py:192 +#: judge/models/comment.py:53 msgid "comment" msgstr "" -#: judge/models/comment.py:55 +#: judge/models/comment.py:54 msgid "comments" msgstr "" -#: judge/models/comment.py:137 judge/models/problem.py:443 +#: judge/models/comment.py:136 judge/models/problem.py:406 #, python-format msgid "Editorial for %s" msgstr "" -#: judge/models/comment.py:172 +#: judge/models/comment.py:171 msgid "comment vote" msgstr "" -#: judge/models/comment.py:173 +#: judge/models/comment.py:172 msgid "comment votes" msgstr "" -#: judge/models/comment.py:182 +#: judge/models/comment.py:181 msgid "Override comment lock" msgstr "" -#: judge/models/comment.py:190 -msgid "owner" -msgstr "" - -#: judge/models/comment.py:193 judge/models/message.py:16 -msgid "read" -msgstr "" - -#: judge/models/comment.py:194 -msgid "category" -msgstr "" - -#: judge/models/comment.py:195 -msgid "html link to comments, used for non-comments" -msgstr "" - -#: judge/models/comment.py:196 -msgid "who trigger, used for non-comment" -msgstr "" - -#: judge/models/contest.py:23 +#: judge/models/contest.py:22 msgid "Invalid colour." msgstr "" -#: judge/models/contest.py:25 +#: judge/models/contest.py:24 msgid "tag name" msgstr "" -#: judge/models/contest.py:26 +#: judge/models/contest.py:25 msgid "Lowercase letters and hyphens only." msgstr "" -#: judge/models/contest.py:27 +#: judge/models/contest.py:26 msgid "tag colour" msgstr "" -#: judge/models/contest.py:28 +#: judge/models/contest.py:27 msgid "tag description" msgstr "" -#: judge/models/contest.py:47 +#: judge/models/contest.py:46 msgid "contest tag" msgstr "" -#: judge/models/contest.py:48 judge/models/contest.py:118 +#: judge/models/contest.py:47 judge/models/contest.py:101 msgid "contest tags" msgstr "" -#: judge/models/contest.py:56 -msgid "Visible" -msgstr "" - -#: judge/models/contest.py:57 -msgid "Hidden for duration of contest" -msgstr "" - -#: judge/models/contest.py:58 -msgid "Hidden for duration of participation" -msgstr "" - -#: judge/models/contest.py:60 +#: judge/models/contest.py:51 msgid "contest id" msgstr "" -#: judge/models/contest.py:62 +#: judge/models/contest.py:53 msgid "contest name" msgstr "" -#: judge/models/contest.py:63 -msgid "These users will be able to edit the contest." +#: judge/models/contest.py:54 +msgid "These people will be able to edit the contest." msgstr "" -#: judge/models/contest.py:65 -msgid "" -"These users will be able to edit the contest, but will not be listed as " -"authors." -msgstr "" - -#: judge/models/contest.py:68 -msgid "These users will be able to view the contest, but not edit it." -msgstr "" - -#: judge/models/contest.py:71 judge/models/runtime.py:136 +#: judge/models/contest.py:56 judge/models/runtime.py:133 msgid "description" msgstr "" -#: judge/models/contest.py:72 judge/models/problem.py:390 -#: judge/models/runtime.py:138 +#: judge/models/contest.py:57 judge/models/problem.py:353 +#: judge/models/runtime.py:135 msgid "problems" msgstr "" -#: judge/models/contest.py:73 judge/models/contest.py:404 +#: judge/models/contest.py:58 judge/models/contest.py:258 msgid "start time" msgstr "" -#: judge/models/contest.py:74 +#: judge/models/contest.py:59 msgid "end time" msgstr "" -#: judge/models/contest.py:75 judge/models/problem.py:118 -#: judge/models/problem.py:414 +#: judge/models/contest.py:60 judge/models/problem.py:118 +#: judge/models/problem.py:377 msgid "time limit" msgstr "" -#: judge/models/contest.py:76 judge/models/problem.py:136 +#: judge/models/contest.py:61 judge/models/problem.py:136 msgid "publicly visible" msgstr "" -#: judge/models/contest.py:77 +#: judge/models/contest.py:62 msgid "" "Should be set even for organization-private contests, where it determines " "whether the contest is visible to members of the specified organizations." msgstr "" -#: judge/models/contest.py:80 +#: judge/models/contest.py:65 msgid "contest rated" msgstr "" -#: judge/models/contest.py:80 +#: judge/models/contest.py:65 msgid "Whether this contest can be rated." msgstr "" -#: judge/models/contest.py:82 -msgid "scoreboard visibility" +#: judge/models/contest.py:67 +msgid "hide scoreboard" msgstr "" -#: judge/models/contest.py:83 -msgid "Scoreboard visibility through the duration of the contest" +#: judge/models/contest.py:68 +msgid "" +"Whether the scoreboard should remain hidden for the duration of the contest." msgstr "" -#: judge/models/contest.py:85 -msgid "view contest scoreboard" -msgstr "" - -#: judge/models/contest.py:87 -msgid "These users will be able to view the scoreboard." -msgstr "" - -#: judge/models/contest.py:88 +#: judge/models/contest.py:71 msgid "no comments" msgstr "" -#: judge/models/contest.py:89 +#: judge/models/contest.py:72 msgid "Use clarification system instead of comments." msgstr "" -#: judge/models/contest.py:91 +#: judge/models/contest.py:74 msgid "Rating floor for contest" msgstr "" -#: judge/models/contest.py:93 +#: judge/models/contest.py:76 msgid "Rating ceiling for contest" msgstr "" -#: judge/models/contest.py:95 +#: judge/models/contest.py:78 msgid "rate all" msgstr "" -#: judge/models/contest.py:95 +#: judge/models/contest.py:78 msgid "Rate all users who joined." msgstr "" -#: judge/models/contest.py:96 +#: judge/models/contest.py:79 msgid "exclude from ratings" msgstr "" -#: judge/models/contest.py:98 +#: judge/models/contest.py:81 msgid "private to specific users" msgstr "" -#: judge/models/contest.py:99 +#: judge/models/contest.py:82 msgid "private contestants" msgstr "" -#: judge/models/contest.py:100 +#: judge/models/contest.py:83 msgid "If private, only these users may see the contest" msgstr "" -#: judge/models/contest.py:102 +#: judge/models/contest.py:85 msgid "hide problem tags" msgstr "" -#: judge/models/contest.py:103 +#: judge/models/contest.py:86 msgid "Whether problem tags should be hidden by default." msgstr "" -#: judge/models/contest.py:105 +#: judge/models/contest.py:88 msgid "run pretests only" msgstr "" -#: judge/models/contest.py:106 +#: judge/models/contest.py:89 msgid "" "Whether judges should grade pretests only, versus all testcases. Commonly " "set during a contest, then unset prior to rejudging user submissions when " "the contest ends." msgstr "" -#: judge/models/contest.py:110 judge/models/interface.py:77 -#: judge/models/problem.py:157 +#: judge/models/contest.py:93 judge/models/problem.py:157 msgid "private to organizations" msgstr "" -#: judge/models/contest.py:111 judge/models/interface.py:75 -#: judge/models/problem.py:155 judge/models/profile.py:77 +#: judge/models/contest.py:94 judge/models/problem.py:155 +#: judge/models/profile.py:77 msgid "organizations" msgstr "" -#: judge/models/contest.py:112 +#: judge/models/contest.py:95 msgid "If private, only these organizations may see the contest" msgstr "" -#: judge/models/contest.py:113 judge/models/problem.py:145 +#: judge/models/contest.py:96 judge/models/problem.py:145 msgid "OpenGraph image" msgstr "" -#: judge/models/contest.py:114 judge/models/profile.py:48 +#: judge/models/contest.py:97 judge/models/profile.py:48 msgid "Logo override image" msgstr "" -#: judge/models/contest.py:116 +#: judge/models/contest.py:99 msgid "" "This image will replace the default site logo for users inside the contest." msgstr "" -#: judge/models/contest.py:119 +#: judge/models/contest.py:102 msgid "the amount of live participants" msgstr "" -#: judge/models/contest.py:120 +#: judge/models/contest.py:103 msgid "contest summary" msgstr "" -#: judge/models/contest.py:121 judge/models/problem.py:147 +#: judge/models/contest.py:104 judge/models/problem.py:147 msgid "Plain-text, shown in meta description tag, e.g. for social media." msgstr "" -#: judge/models/contest.py:122 judge/models/profile.py:47 +#: judge/models/contest.py:105 judge/models/profile.py:47 msgid "access code" msgstr "" -#: judge/models/contest.py:123 +#: judge/models/contest.py:106 msgid "" "An optional code to prompt contestants before they are allowed to join the " "contest. Leave it blank to disable." msgstr "" -#: judge/models/contest.py:125 judge/models/problem.py:141 +#: judge/models/contest.py:108 judge/models/problem.py:141 msgid "personae non gratae" msgstr "" -#: judge/models/contest.py:126 +#: judge/models/contest.py:109 msgid "Bans the selected users from joining this contest." msgstr "" -#: judge/models/contest.py:127 +#: judge/models/contest.py:110 msgid "contest format" msgstr "" -#: judge/models/contest.py:128 +#: judge/models/contest.py:111 msgid "The contest format module to use." msgstr "" -#: judge/models/contest.py:129 +#: judge/models/contest.py:112 msgid "contest format configuration" msgstr "" -#: judge/models/contest.py:130 +#: judge/models/contest.py:113 msgid "" "A JSON object to serve as the configuration for the chosen contest format " "module. Leave empty to use None. Exact format depends on the contest format " "selected." msgstr "" -#: judge/models/contest.py:137 -msgid "precision points" -msgstr "" - -#: judge/models/contest.py:139 -msgid "Number of digits to round points to." -msgstr "" - -#: judge/models/contest.py:383 +#: judge/models/contest.py:239 msgid "See private contests" msgstr "" -#: judge/models/contest.py:384 +#: judge/models/contest.py:240 msgid "Edit own contests" msgstr "" -#: judge/models/contest.py:385 +#: judge/models/contest.py:241 msgid "Edit all contests" msgstr "" -#: judge/models/contest.py:386 +#: judge/models/contest.py:242 msgid "Clone contest" msgstr "" -#: judge/models/contest.py:387 templates/contest/moss.html:74 +#: judge/models/contest.py:243 templates/contest/moss.html:74 msgid "MOSS contest" msgstr "" -#: judge/models/contest.py:388 +#: judge/models/contest.py:244 msgid "Rate contests" msgstr "" -#: judge/models/contest.py:389 +#: judge/models/contest.py:245 msgid "Contest access codes" msgstr "" -#: judge/models/contest.py:390 +#: judge/models/contest.py:246 msgid "Create private contests" msgstr "" -#: judge/models/contest.py:391 -msgid "Change contest visibility" -msgstr "" - -#: judge/models/contest.py:392 -msgid "Edit contest problem label script" -msgstr "" - -#: judge/models/contest.py:394 judge/models/contest.py:492 -#: judge/models/contest.py:529 judge/models/contest.py:552 -#: judge/models/submission.py:84 +#: judge/models/contest.py:248 judge/models/contest.py:345 +#: judge/models/contest.py:382 judge/models/contest.py:404 +#: judge/models/submission.py:83 msgid "contest" msgstr "" -#: judge/models/contest.py:395 +#: judge/models/contest.py:249 msgid "contests" msgstr "" -#: judge/models/contest.py:402 +#: judge/models/contest.py:256 msgid "associated contest" msgstr "" -#: judge/models/contest.py:405 +#: judge/models/contest.py:259 msgid "score" msgstr "得分" -#: judge/models/contest.py:406 +#: judge/models/contest.py:260 msgid "cumulative time" msgstr "累計時間" -#: judge/models/contest.py:407 +#: judge/models/contest.py:261 msgid "is disqualified" msgstr "" -#: judge/models/contest.py:408 +#: judge/models/contest.py:262 msgid "Whether this participation is disqualified." msgstr "" -#: judge/models/contest.py:409 -msgid "tie-breaking field" -msgstr "" - -#: judge/models/contest.py:410 +#: judge/models/contest.py:263 msgid "virtual participation id" msgstr "" -#: judge/models/contest.py:411 +#: judge/models/contest.py:264 msgid "0 means non-virtual, otherwise the n-th virtual participation." msgstr "" -#: judge/models/contest.py:412 +#: judge/models/contest.py:265 msgid "contest format specific data" msgstr "" -#: judge/models/contest.py:478 +#: judge/models/contest.py:331 #, python-format msgid "%s spectating in %s" msgstr "" -#: judge/models/contest.py:480 +#: judge/models/contest.py:333 #, python-format msgid "%s in %s, v%d" msgstr "" -#: judge/models/contest.py:481 +#: judge/models/contest.py:334 #, python-format msgid "%s in %s" msgstr "" -#: judge/models/contest.py:484 +#: judge/models/contest.py:337 msgid "contest participation" msgstr "" -#: judge/models/contest.py:485 +#: judge/models/contest.py:338 msgid "contest participations" msgstr "" -#: judge/models/contest.py:491 judge/models/contest.py:513 -#: judge/models/contest.py:553 judge/models/problem.py:389 -#: judge/models/problem.py:394 judge/models/problem.py:412 -#: judge/models/problem_data.py:40 +#: judge/models/contest.py:344 judge/models/contest.py:366 +#: judge/models/contest.py:405 judge/models/problem.py:352 +#: judge/models/problem.py:357 judge/models/problem.py:375 +#: judge/models/problem_data.py:38 msgid "problem" msgstr "題目" -#: judge/models/contest.py:493 judge/models/contest.py:517 +#: judge/models/contest.py:346 judge/models/contest.py:370 #: judge/models/problem.py:129 msgid "points" msgstr "分" -#: judge/models/contest.py:494 +#: judge/models/contest.py:347 msgid "partial" msgstr "部分" -#: judge/models/contest.py:495 judge/models/contest.py:518 +#: judge/models/contest.py:348 judge/models/contest.py:371 msgid "is pretested" msgstr "" -#: judge/models/contest.py:496 judge/models/interface.py:43 +#: judge/models/contest.py:349 judge/models/interface.py:43 msgid "order" msgstr "" -#: judge/models/contest.py:497 +#: judge/models/contest.py:350 msgid "0 to not show testcases, 1 to show" msgstr "" -#: judge/models/contest.py:498 +#: judge/models/contest.py:351 msgid "visible testcases" msgstr "" -#: judge/models/contest.py:499 +#: judge/models/contest.py:352 msgid "Maximum number of submissions for this problem, or 0 for no limit." msgstr "" -#: judge/models/contest.py:501 +#: judge/models/contest.py:354 msgid "Why include a problem you can't submit to?" msgstr "" -#: judge/models/contest.py:506 +#: judge/models/contest.py:359 msgid "contest problem" msgstr "" -#: judge/models/contest.py:507 +#: judge/models/contest.py:360 msgid "contest problems" msgstr "" -#: judge/models/contest.py:511 judge/models/submission.py:183 +#: judge/models/contest.py:364 judge/models/submission.py:181 msgid "submission" msgstr "" -#: judge/models/contest.py:515 judge/models/contest.py:530 +#: judge/models/contest.py:368 judge/models/contest.py:383 msgid "participation" msgstr "" -#: judge/models/contest.py:519 +#: judge/models/contest.py:372 msgid "Whether this submission was ran only on pretests." msgstr "" -#: judge/models/contest.py:523 +#: judge/models/contest.py:376 msgid "contest submission" msgstr "" -#: judge/models/contest.py:524 +#: judge/models/contest.py:377 msgid "contest submissions" msgstr "" -#: judge/models/contest.py:532 +#: judge/models/contest.py:385 msgid "rank" msgstr "排名" -#: judge/models/contest.py:533 +#: judge/models/contest.py:386 msgid "rating" msgstr "" -#: judge/models/contest.py:534 +#: judge/models/contest.py:387 msgid "volatility" msgstr "" -#: judge/models/contest.py:535 +#: judge/models/contest.py:388 msgid "last rated" msgstr "" -#: judge/models/contest.py:539 +#: judge/models/contest.py:392 msgid "contest rating" msgstr "" -#: judge/models/contest.py:540 +#: judge/models/contest.py:393 msgid "contest ratings" msgstr "" -#: judge/models/contest.py:560 +#: judge/models/contest.py:412 msgid "contest moss result" msgstr "" -#: judge/models/contest.py:561 +#: judge/models/contest.py:413 msgid "contest moss results" msgstr "" @@ -1144,7 +1056,7 @@ msgstr "" msgid "post title" msgstr "" -#: judge/models/interface.py:67 judge/models/problem.py:432 +#: judge/models/interface.py:67 judge/models/problem.py:395 msgid "authors" msgstr "" @@ -1152,7 +1064,7 @@ msgstr "" msgid "slug" msgstr "" -#: judge/models/interface.py:69 judge/models/problem.py:430 +#: judge/models/interface.py:69 judge/models/problem.py:393 msgid "public visibility" msgstr "" @@ -1176,19 +1088,15 @@ msgstr "" msgid "openGraph image" msgstr "" -#: judge/models/interface.py:76 -msgid "If private, only these organizations may see the blog post." -msgstr "" - -#: judge/models/interface.py:105 +#: judge/models/interface.py:91 msgid "Edit all posts" msgstr "" -#: judge/models/interface.py:107 +#: judge/models/interface.py:93 msgid "blog post" msgstr "" -#: judge/models/interface.py:108 +#: judge/models/interface.py:94 msgid "blog posts" msgstr "" @@ -1212,6 +1120,10 @@ msgstr "" msgid "message timestamp" msgstr "" +#: judge/models/message.py:16 +msgid "read" +msgstr "" + #: judge/models/message.py:20 msgid "messages in the thread" msgstr "" @@ -1348,7 +1260,7 @@ msgid "" "are supported." msgstr "" -#: judge/models/problem.py:123 judge/models/problem.py:417 +#: judge/models/problem.py:123 judge/models/problem.py:380 msgid "memory limit" msgstr "記憶體限制" @@ -1421,188 +1333,188 @@ msgstr "" msgid "If private, only these organizations may see the problem." msgstr "" -#: judge/models/problem.py:395 judge/models/problem.py:413 -#: judge/models/runtime.py:111 +#: judge/models/problem.py:358 judge/models/problem.py:376 +#: judge/models/runtime.py:108 msgid "language" msgstr "" -#: judge/models/problem.py:396 +#: judge/models/problem.py:359 msgid "translated name" msgstr "" -#: judge/models/problem.py:397 +#: judge/models/problem.py:360 msgid "translated description" msgstr "" -#: judge/models/problem.py:401 +#: judge/models/problem.py:364 msgid "problem translation" msgstr "" -#: judge/models/problem.py:402 +#: judge/models/problem.py:365 msgid "problem translations" msgstr "" -#: judge/models/problem.py:406 +#: judge/models/problem.py:369 msgid "clarified problem" msgstr "" -#: judge/models/problem.py:407 +#: judge/models/problem.py:370 msgid "clarification body" msgstr "" -#: judge/models/problem.py:408 +#: judge/models/problem.py:371 msgid "clarification timestamp" msgstr "" -#: judge/models/problem.py:423 +#: judge/models/problem.py:386 msgid "language-specific resource limit" msgstr "" -#: judge/models/problem.py:424 +#: judge/models/problem.py:387 msgid "language-specific resource limits" msgstr "" -#: judge/models/problem.py:428 +#: judge/models/problem.py:391 msgid "associated problem" msgstr "" -#: judge/models/problem.py:431 +#: judge/models/problem.py:394 msgid "publish date" msgstr "" -#: judge/models/problem.py:433 +#: judge/models/problem.py:396 msgid "editorial content" msgstr "" -#: judge/models/problem.py:449 +#: judge/models/problem.py:412 msgid "solution" msgstr "題解" -#: judge/models/problem.py:450 +#: judge/models/problem.py:413 msgid "solutions" msgstr "題解" -#: judge/models/problem_data.py:26 +#: judge/models/problem_data.py:24 msgid "Standard" msgstr "標準" -#: judge/models/problem_data.py:27 +#: judge/models/problem_data.py:25 msgid "Floats" msgstr "浮點數" -#: judge/models/problem_data.py:28 +#: judge/models/problem_data.py:26 msgid "Floats (absolute)" msgstr "浮點數(絕對值)" -#: judge/models/problem_data.py:29 +#: judge/models/problem_data.py:27 msgid "Floats (relative)" msgstr "浮點數(相對值)" -#: judge/models/problem_data.py:30 +#: judge/models/problem_data.py:28 msgid "Non-trailing spaces" msgstr "" -#: judge/models/problem_data.py:31 +#: judge/models/problem_data.py:29 msgid "Unordered" msgstr "" -#: judge/models/problem_data.py:32 +#: judge/models/problem_data.py:30 msgid "Byte identical" msgstr "" -#: judge/models/problem_data.py:33 +#: judge/models/problem_data.py:31 msgid "Line-by-line" msgstr "" -#: judge/models/problem_data.py:34 +#: judge/models/problem_data.py:32 msgid "Custom checker (PY)" msgstr "" -#: judge/models/problem_data.py:35 +#: judge/models/problem_data.py:33 msgid "Custom validator (CPP)" msgstr "" -#: judge/models/problem_data.py:42 +#: judge/models/problem_data.py:40 msgid "data zip file" msgstr "" -#: judge/models/problem_data.py:44 +#: judge/models/problem_data.py:42 msgid "generator file" msgstr "" -#: judge/models/problem_data.py:46 judge/models/problem_data.py:121 +#: judge/models/problem_data.py:44 judge/models/problem_data.py:110 msgid "output prefix length" msgstr "" -#: judge/models/problem_data.py:47 judge/models/problem_data.py:122 +#: judge/models/problem_data.py:45 judge/models/problem_data.py:111 msgid "output limit length" msgstr "" -#: judge/models/problem_data.py:48 +#: judge/models/problem_data.py:46 msgid "init.yml generation feedback" msgstr "" -#: judge/models/problem_data.py:49 judge/models/problem_data.py:123 +#: judge/models/problem_data.py:47 judge/models/problem_data.py:112 msgid "checker" msgstr "" -#: judge/models/problem_data.py:50 judge/models/problem_data.py:124 +#: judge/models/problem_data.py:48 judge/models/problem_data.py:113 msgid "checker arguments" msgstr "" -#: judge/models/problem_data.py:51 judge/models/problem_data.py:125 +#: judge/models/problem_data.py:49 judge/models/problem_data.py:114 msgid "checker arguments as a JSON object" msgstr "" -#: judge/models/problem_data.py:52 +#: judge/models/problem_data.py:50 msgid "custom checker file" msgstr "" -#: judge/models/problem_data.py:58 +#: judge/models/problem_data.py:56 msgid "custom validator file" msgstr "" -#: judge/models/problem_data.py:108 +#: judge/models/problem_data.py:97 msgid "problem data set" msgstr "" -#: judge/models/problem_data.py:110 +#: judge/models/problem_data.py:99 msgid "case position" msgstr "" -#: judge/models/problem_data.py:111 +#: judge/models/problem_data.py:100 msgid "case type" msgstr "" -#: judge/models/problem_data.py:112 +#: judge/models/problem_data.py:101 msgid "Normal case" msgstr "" -#: judge/models/problem_data.py:113 +#: judge/models/problem_data.py:102 msgid "Batch start" msgstr "" -#: judge/models/problem_data.py:114 +#: judge/models/problem_data.py:103 msgid "Batch end" msgstr "" -#: judge/models/problem_data.py:116 +#: judge/models/problem_data.py:105 msgid "input file name" msgstr "" -#: judge/models/problem_data.py:117 +#: judge/models/problem_data.py:106 msgid "output file name" msgstr "" -#: judge/models/problem_data.py:118 +#: judge/models/problem_data.py:107 msgid "generator arguments" msgstr "" -#: judge/models/problem_data.py:119 +#: judge/models/problem_data.py:108 msgid "point value" msgstr "" -#: judge/models/problem_data.py:120 +#: judge/models/problem_data.py:109 msgid "case is pretest?" msgstr "" @@ -1675,7 +1587,7 @@ msgid "" msgstr "" #: judge/models/profile.py:76 judge/models/profile.py:93 -#: judge/models/profile.py:212 +#: judge/models/profile.py:192 msgid "organization" msgstr "" @@ -1771,31 +1683,31 @@ msgstr "" msgid "Notes for administrators regarding this user." msgstr "" -#: judge/models/profile.py:206 +#: judge/models/profile.py:186 msgid "user profile" msgstr "使用者個人檔案" -#: judge/models/profile.py:207 +#: judge/models/profile.py:187 msgid "user profiles" msgstr "使用者個人檔案" -#: judge/models/profile.py:214 +#: judge/models/profile.py:194 msgid "request time" msgstr "" -#: judge/models/profile.py:215 +#: judge/models/profile.py:195 msgid "state" msgstr "" -#: judge/models/profile.py:220 +#: judge/models/profile.py:200 msgid "reason" msgstr "" -#: judge/models/profile.py:223 +#: judge/models/profile.py:203 msgid "organization join request" msgstr "" -#: judge/models/profile.py:224 +#: judge/models/profile.py:204 msgid "organization join requests" msgstr "" @@ -1886,86 +1798,86 @@ msgstr "" msgid "The extension of source files, e.g., \"py\" or \"cpp\"." msgstr "" -#: judge/models/runtime.py:112 +#: judge/models/runtime.py:109 msgid "languages" msgstr "語言" -#: judge/models/runtime.py:116 +#: judge/models/runtime.py:113 msgid "language to which this runtime belongs" msgstr "" -#: judge/models/runtime.py:117 +#: judge/models/runtime.py:114 msgid "judge on which this runtime exists" msgstr "" -#: judge/models/runtime.py:118 +#: judge/models/runtime.py:115 msgid "runtime name" msgstr "" -#: judge/models/runtime.py:119 +#: judge/models/runtime.py:116 msgid "runtime version" msgstr "" -#: judge/models/runtime.py:120 +#: judge/models/runtime.py:117 msgid "order in which to display this runtime" msgstr "" -#: judge/models/runtime.py:124 +#: judge/models/runtime.py:121 msgid "Server name, hostname-style" msgstr "" -#: judge/models/runtime.py:125 +#: judge/models/runtime.py:122 msgid "time of creation" msgstr "" -#: judge/models/runtime.py:126 +#: judge/models/runtime.py:123 msgid "A key to authenticate this judge" msgstr "" -#: judge/models/runtime.py:127 +#: judge/models/runtime.py:124 msgid "authentication key" msgstr "" -#: judge/models/runtime.py:128 +#: judge/models/runtime.py:125 msgid "block judge" msgstr "" -#: judge/models/runtime.py:129 +#: judge/models/runtime.py:126 msgid "" "Whether this judge should be blocked from connecting, even if its key is " "correct." msgstr "" -#: judge/models/runtime.py:131 +#: judge/models/runtime.py:128 msgid "judge online status" msgstr "" -#: judge/models/runtime.py:132 +#: judge/models/runtime.py:129 msgid "judge start time" msgstr "" -#: judge/models/runtime.py:133 +#: judge/models/runtime.py:130 msgid "response time" msgstr "" -#: judge/models/runtime.py:134 +#: judge/models/runtime.py:131 msgid "system load" msgstr "" -#: judge/models/runtime.py:135 +#: judge/models/runtime.py:132 msgid "Load for the last minute, divided by processors to be fair." msgstr "" -#: judge/models/runtime.py:139 judge/models/runtime.py:179 +#: judge/models/runtime.py:136 judge/models/runtime.py:176 msgid "judges" msgstr "" -#: judge/models/runtime.py:178 +#: judge/models/runtime.py:175 msgid "judge" msgstr "" #: judge/models/submission.py:20 judge/models/submission.py:47 -#: judge/utils/problems.py:79 +#: judge/utils/problems.py:77 msgid "Accepted" msgstr "接受" @@ -1994,7 +1906,7 @@ msgid "Runtime Error" msgstr "運行時錯誤" #: judge/models/submission.py:27 judge/models/submission.py:41 -#: judge/models/submission.py:55 judge/utils/problems.py:81 +#: judge/models/submission.py:55 judge/utils/problems.py:79 msgid "Compile Error" msgstr "編譯錯誤" @@ -2035,15 +1947,15 @@ msgstr "" msgid "submission time" msgstr "提交時間" -#: judge/models/submission.py:67 judge/models/submission.py:203 +#: judge/models/submission.py:67 judge/models/submission.py:201 msgid "execution time" msgstr "執行時間" -#: judge/models/submission.py:68 judge/models/submission.py:204 +#: judge/models/submission.py:68 judge/models/submission.py:202 msgid "memory usage" msgstr "記憶體使用量" -#: judge/models/submission.py:69 judge/models/submission.py:205 +#: judge/models/submission.py:69 judge/models/submission.py:203 msgid "points granted" msgstr "獲得分數" @@ -2080,64 +1992,58 @@ msgid "judged on" msgstr "" #: judge/models/submission.py:81 -#, fuzzy -#| msgid "submission time" -msgid "submission judge time" -msgstr "提交時間" - -#: judge/models/submission.py:82 msgid "was rejudged by admin" msgstr "" -#: judge/models/submission.py:83 +#: judge/models/submission.py:82 msgid "was ran on pretests only" msgstr "" -#: judge/models/submission.py:184 templates/contest/moss.html:58 +#: judge/models/submission.py:182 templates/contest/moss.html:58 msgid "submissions" msgstr "" -#: judge/models/submission.py:188 judge/models/submission.py:199 +#: judge/models/submission.py:186 judge/models/submission.py:197 msgid "associated submission" msgstr "" -#: judge/models/submission.py:190 +#: judge/models/submission.py:188 msgid "source code" msgstr "源碼" -#: judge/models/submission.py:201 +#: judge/models/submission.py:199 msgid "test case ID" msgstr "" -#: judge/models/submission.py:202 +#: judge/models/submission.py:200 msgid "status flag" msgstr "" -#: judge/models/submission.py:206 +#: judge/models/submission.py:204 msgid "points possible" msgstr "" -#: judge/models/submission.py:207 +#: judge/models/submission.py:205 msgid "batch number" msgstr "" -#: judge/models/submission.py:208 +#: judge/models/submission.py:206 msgid "judging feedback" msgstr "" -#: judge/models/submission.py:209 +#: judge/models/submission.py:207 msgid "extended judging feedback" msgstr "" -#: judge/models/submission.py:210 +#: judge/models/submission.py:208 msgid "program output" msgstr "" -#: judge/models/submission.py:218 +#: judge/models/submission.py:216 msgid "submission test case" msgstr "" -#: judge/models/submission.py:219 +#: judge/models/submission.py:217 msgid "submission test cases" msgstr "" @@ -2189,21 +2095,12 @@ msgstr "" msgid "message time" msgstr "" -#: judge/pdf_problems.py:147 judge/pdf_problems.py:199 -#: judge/pdf_problems.py:259 +#: judge/pdf_problems.py:134 judge/pdf_problems.py:186 +#: judge/pdf_problems.py:246 msgid "Page [page] of [topage]" msgstr "" -#: judge/pdf_problems.py:280 -#, python-format -msgid "Page %s of %s" -msgstr "" - -#: judge/tasks/contest.py:19 -msgid "Recalculating contest scores" -msgstr "" - -#: judge/tasks/contest.py:40 +#: judge/tasks/moss.py:25 msgid "Running MOSS" msgstr "" @@ -2215,60 +2112,60 @@ msgstr "" msgid "Recalculating user points" msgstr "" -#: judge/utils/problem_data.py:70 +#: judge/utils/problem_data.py:68 msgid "Empty batches not allowed." msgstr "" -#: judge/utils/problem_data.py:78 judge/utils/problem_data.py:99 +#: judge/utils/problem_data.py:76 judge/utils/problem_data.py:97 msgid "How did you corrupt the custom checker path?" msgstr "" -#: judge/utils/problem_data.py:120 +#: judge/utils/problem_data.py:118 #, python-format msgid "Points must be defined for non-batch case #%d." msgstr "" -#: judge/utils/problem_data.py:125 +#: judge/utils/problem_data.py:123 #, python-format msgid "Input file for case %d does not exist: %s" msgstr "" -#: judge/utils/problem_data.py:128 +#: judge/utils/problem_data.py:126 #, python-format msgid "Output file for case %d does not exist: %s" msgstr "" -#: judge/utils/problem_data.py:153 +#: judge/utils/problem_data.py:151 #, python-format msgid "Batch start case #%d requires points." msgstr "" -#: judge/utils/problem_data.py:174 +#: judge/utils/problem_data.py:172 #, python-format msgid "Attempt to end batch outside of one in case #%d" msgstr "" -#: judge/utils/problem_data.py:192 +#: judge/utils/problem_data.py:190 msgid "How did you corrupt the zip path?" msgstr "" -#: judge/utils/problem_data.py:198 +#: judge/utils/problem_data.py:196 msgid "How did you corrupt the generator path?" msgstr "" -#: judge/utils/problems.py:80 +#: judge/utils/problems.py:78 msgid "Wrong" msgstr "" -#: judge/utils/problems.py:82 +#: judge/utils/problems.py:80 msgid "Timeout" msgstr "" -#: judge/utils/problems.py:83 +#: judge/utils/problems.py:81 msgid "Error" msgstr "" -#: judge/utils/problems.py:94 +#: judge/utils/problems.py:92 msgid "Can't pass both queryset and keyword filters" msgstr "" @@ -2308,8 +2205,7 @@ msgctxt "hours and minutes" msgid "%h:%m" msgstr "%h:%m" -#: judge/views/about.py:7 templates/organization/home.html:112 -#: templates/user/user-about.html:83 templates/user/user-tabs.html:4 +#: judge/views/about.py:7 templates/user/user-about.html:33 msgid "About" msgstr "" @@ -2317,165 +2213,156 @@ msgstr "" msgid "Custom Checker Sample" msgstr "" -#: judge/views/blog.py:45 +#: judge/views/blog.py:38 #, python-format msgid "Page %d of Posts" msgstr "" -#: judge/views/comment.py:28 +#: judge/views/comment.py:27 msgid "Messing around, are we?" msgstr "" -#: judge/views/comment.py:37 +#: judge/views/comment.py:36 msgid "You must solve at least one problem before you can vote." msgstr "" -#: judge/views/comment.py:64 +#: judge/views/comment.py:63 msgid "You already voted." msgstr "" -#: judge/views/comment.py:126 judge/views/organization.py:344 +#: judge/views/comment.py:120 judge/views/organization.py:299 msgid "Edited from site" msgstr "" -#: judge/views/comment.py:147 +#: judge/views/comment.py:141 msgid "Editing comment" msgstr "" -#: judge/views/contests.py:57 judge/views/contests.py:247 -#: judge/views/contests.py:250 judge/views/contests.py:424 +#: judge/views/contests.py:55 judge/views/contests.py:215 +#: judge/views/contests.py:218 judge/views/contests.py:389 msgid "No such contest" msgstr "" -#: judge/views/contests.py:58 judge/views/contests.py:248 +#: judge/views/contests.py:56 judge/views/contests.py:216 #, python-format msgid "Could not find a contest with the key \"%s\"." msgstr "" -#: judge/views/contests.py:71 +#: judge/views/contests.py:81 msgid "Contests" msgstr "" -#: judge/views/contests.py:251 +#: judge/views/contests.py:219 msgid "Could not find such contest." msgstr "" -#: judge/views/contests.py:254 +#: judge/views/contests.py:222 #, python-format msgid "Access to contest \"%s\" denied" msgstr "" -#: judge/views/contests.py:278 +#: judge/views/contests.py:246 msgid "Clone Contest" msgstr "" -#: judge/views/contests.py:343 +#: judge/views/contests.py:309 msgid "Contest not ongoing" msgstr "" -#: judge/views/contests.py:344 +#: judge/views/contests.py:310 #, python-format msgid "\"%s\" is not currently ongoing." msgstr "" -#: judge/views/contests.py:348 +#: judge/views/contests.py:314 msgid "Already in contest" msgstr "" -#: judge/views/contests.py:349 +#: judge/views/contests.py:315 #, python-format msgid "You are already in a contest: \"%s\"." msgstr "" -#: judge/views/contests.py:352 +#: judge/views/contests.py:318 msgid "Banned from joining" msgstr "" -#: judge/views/contests.py:353 +#: judge/views/contests.py:319 msgid "" "You have been declared persona non grata for this contest. You are " "permanently barred from joining this contest." msgstr "" -#: judge/views/contests.py:414 +#: judge/views/contests.py:379 #, python-format msgid "Enter access code for \"%s\"" msgstr "" -#: judge/views/contests.py:425 +#: judge/views/contests.py:390 #, python-format msgid "You are not in contest \"%s\"." msgstr "" -#: judge/views/contests.py:444 +#: judge/views/contests.py:409 msgid "ContestCalendar requires integer year and month" msgstr "" -#: judge/views/contests.py:484 +#: judge/views/contests.py:449 #, python-format msgid "Contests in %(month)s" msgstr "" -#: judge/views/contests.py:484 +#: judge/views/contests.py:449 msgid "F Y" msgstr "" -#: judge/views/contests.py:532 +#: judge/views/contests.py:496 #, python-format msgid "%s Statistics" msgstr "" -#: judge/views/contests.py:717 +#: judge/views/contests.py:601 +msgid "???" +msgstr "" + +#: judge/views/contests.py:664 #, python-format msgid "%s Rankings" msgstr "" -#: judge/views/contests.py:725 -msgid "???" -msgstr "" - -#: judge/views/contests.py:741 +#: judge/views/contests.py:680 #, python-format msgid "Your participation in %s" msgstr "" -#: judge/views/contests.py:742 +#: judge/views/contests.py:681 #, python-format msgid "%s's participation in %s" msgstr "" -#: judge/views/contests.py:749 +#: judge/views/contests.py:685 msgid "Live" msgstr "" -#: judge/views/contests.py:761 templates/contest/contest-tabs.html:13 +#: judge/views/contests.py:697 msgid "Participation" msgstr "" -#: judge/views/contests.py:808 +#: judge/views/contests.py:743 #, python-format msgid "%s MOSS Results" msgstr "" -#: judge/views/contests.py:835 +#: judge/views/contests.py:770 #, python-format msgid "Running MOSS for %s..." msgstr "" -#: judge/views/contests.py:858 +#: judge/views/contests.py:793 #, python-format msgid "Contest tag: %s" msgstr "" -#: judge/views/contests.py:868 judge/views/ticket.py:57 -msgid "Issue description" -msgstr "" - -#: judge/views/contests.py:911 -#, python-format -msgid "New clarification for %s" -msgstr "" - #: judge/views/error.py:14 msgid "404 error" msgstr "" @@ -2496,120 +2383,113 @@ msgid "corrupt page %s" msgstr "" #: judge/views/language.py:12 templates/status/judge-status-table.html:9 -#: templates/status/status-tabs.html:5 msgid "Runtimes" msgstr "" -#: judge/views/notification.py:40 -#, python-format -msgid "Notifications (%d unseen)" -msgstr "" - -#: judge/views/organization.py:59 judge/views/organization.py:62 +#: judge/views/organization.py:44 judge/views/organization.py:47 msgid "No such organization" msgstr "" -#: judge/views/organization.py:60 +#: judge/views/organization.py:45 #, python-format msgid "Could not find an organization with the key \"%s\"." msgstr "" -#: judge/views/organization.py:63 +#: judge/views/organization.py:48 msgid "Could not find such organization." msgstr "" -#: judge/views/organization.py:79 judge/views/register.py:34 -#: templates/organization/list.html:32 templates/user/import/table_csv.html:9 -#: templates/user/user-list-tabs.html:6 +#: judge/views/organization.py:72 judge/views/register.py:34 +#: templates/organization/list.html:15 msgid "Organizations" msgstr "" -#: judge/views/organization.py:130 +#: judge/views/organization.py:93 #, python-format msgid "%s Members" msgstr "" -#: judge/views/organization.py:159 judge/views/organization.py:162 -#: judge/views/organization.py:167 +#: judge/views/organization.py:118 judge/views/organization.py:121 +#: judge/views/organization.py:126 msgid "Joining organization" msgstr "" -#: judge/views/organization.py:159 +#: judge/views/organization.py:118 msgid "You are already in the organization." msgstr "" -#: judge/views/organization.py:162 +#: judge/views/organization.py:121 msgid "This organization is not open." msgstr "" -#: judge/views/organization.py:179 +#: judge/views/organization.py:138 msgid "Leaving organization" msgstr "" -#: judge/views/organization.py:179 +#: judge/views/organization.py:138 #, python-format msgid "You are not in \"%s\"." msgstr "" -#: judge/views/organization.py:203 +#: judge/views/organization.py:162 #, python-format msgid "Request to join %s" msgstr "" -#: judge/views/organization.py:221 +#: judge/views/organization.py:180 msgid "Join request detail" msgstr "" -#: judge/views/organization.py:254 +#: judge/views/organization.py:209 #, python-format msgid "Managing join requests for %s" msgstr "" -#: judge/views/organization.py:285 +#: judge/views/organization.py:240 #, python-format msgid "" "Your organization can only receive %d more members. You cannot approve %d " "users." msgstr "" -#: judge/views/organization.py:297 +#: judge/views/organization.py:252 #, python-format msgid "Approved %d user." msgid_plural "Approved %d users." msgstr[0] "" -#: judge/views/organization.py:298 +#: judge/views/organization.py:253 #, python-format msgid "Rejected %d user." msgid_plural "Rejected %d users." msgstr[0] "" -#: judge/views/organization.py:328 +#: judge/views/organization.py:283 #, python-format msgid "Editing %s" msgstr "" -#: judge/views/organization.py:352 judge/views/organization.py:360 +#: judge/views/organization.py:307 judge/views/organization.py:315 msgid "Can't edit organization" msgstr "" -#: judge/views/organization.py:353 +#: judge/views/organization.py:308 msgid "You are not allowed to edit this organization." msgstr "" -#: judge/views/organization.py:361 +#: judge/views/organization.py:316 msgid "You are not allowed to kick people from this organization." msgstr "" -#: judge/views/organization.py:366 judge/views/organization.py:370 +#: judge/views/organization.py:321 judge/views/organization.py:325 msgid "Can't kick user" msgstr "" -#: judge/views/organization.py:367 +#: judge/views/organization.py:322 msgid "The user you are trying to kick does not exist!" msgstr "" -#: judge/views/organization.py:371 +#: judge/views/organization.py:326 #, python-format msgid "The user you are trying to kick is not in organization: %s." msgstr "" @@ -2633,36 +2513,35 @@ msgstr "" msgid "Editorial for {0}" msgstr "" -#: judge/views/problem.py:285 templates/contest/contest.html:79 -#: templates/user/user-about.html:28 templates/user/user-tabs.html:5 -#: templates/user/users-table.html:31 +#: judge/views/problem.py:286 templates/contest/contest.html:79 +#: templates/user/users-table.html:23 msgid "Problems" msgstr "問題" -#: judge/views/problem.py:585 +#: judge/views/problem.py:547 msgid "Banned from submitting" msgstr "" -#: judge/views/problem.py:586 +#: judge/views/problem.py:548 msgid "" "You have been declared persona non grata for this problem. You are " "permanently barred from submitting this problem." msgstr "" -#: judge/views/problem.py:600 +#: judge/views/problem.py:562 msgid "Too many submissions" msgstr "" -#: judge/views/problem.py:601 +#: judge/views/problem.py:563 msgid "You have exceeded the submission limit for this problem." msgstr "" -#: judge/views/problem.py:661 judge/views/problem.py:664 +#: judge/views/problem.py:633 judge/views/problem.py:636 #, python-format msgid "Submit to %(problem)s" msgstr "" -#: judge/views/problem.py:679 +#: judge/views/problem.py:652 msgid "Clone Problem" msgstr "" @@ -2703,22 +2582,22 @@ msgstr "" msgid "Generated init.yml for %s" msgstr "" -#: judge/views/problem_manage.py:52 judge/views/problem_manage.py:55 +#: judge/views/problem_manage.py:50 judge/views/problem_manage.py:53 #, python-format msgid "Managing submissions for %s" msgstr "" -#: judge/views/problem_manage.py:97 +#: judge/views/problem_manage.py:95 #, python-format msgid "Rejudging selected submissions for %s..." msgstr "" -#: judge/views/problem_manage.py:141 +#: judge/views/problem_manage.py:110 #, python-format msgid "Rescoring all submissions for %s..." msgstr "" -#: judge/views/problem_manage.py:150 +#: judge/views/problem_manage.py:119 #, python-format msgid "Successfully scheduled %d submission for rejudging." msgid_plural "Successfully scheduled %d submissions for rejudging." @@ -2766,24 +2645,24 @@ msgstr "" msgid "Subscribe to newsletter?" msgstr "" -#: judge/views/register.py:55 +#: judge/views/register.py:45 #, python-format msgid "" "The email address \"%s\" is already taken. Only one registration is allowed " "per address." msgstr "" -#: judge/views/register.py:61 +#: judge/views/register.py:51 msgid "" "Your email provider is not allowed due to history of abuse. Please use a " "reputable email provider." msgstr "" -#: judge/views/register.py:67 judge/views/register.py:105 +#: judge/views/register.py:57 judge/views/register.py:95 msgid "Registration" msgstr "" -#: judge/views/register.py:116 +#: judge/views/register.py:106 msgid "Authentication failure" msgstr "" @@ -2799,100 +2678,104 @@ msgstr "" msgid "Version matrix" msgstr "" -#: judge/views/submission.py:84 judge/views/submission.py:91 +#: judge/views/submission.py:83 judge/views/submission.py:90 #, python-format msgid "Submission of %(problem)s by %(user)s" msgstr "" -#: judge/views/submission.py:244 judge/views/submission.py:245 -#: templates/problem/problem.html:167 +#: judge/views/submission.py:227 judge/views/submission.py:228 +#: templates/problem/problem.html:127 msgid "All submissions" msgstr "全部的提交" -#: judge/views/submission.py:404 +#: judge/views/submission.py:384 msgid "All my submissions" msgstr "我的提交" -#: judge/views/submission.py:405 +#: judge/views/submission.py:385 #, python-format msgid "All submissions by %s" msgstr "%s 的提交" -#: judge/views/submission.py:436 +#: judge/views/submission.py:416 #, python-format msgid "All submissions for %s" msgstr "" -#: judge/views/submission.py:455 +#: judge/views/submission.py:435 msgid "Must pass a problem" msgstr "" -#: judge/views/submission.py:501 +#: judge/views/submission.py:481 #, python-format msgid "My submissions for %(problem)s" msgstr "" -#: judge/views/submission.py:502 +#: judge/views/submission.py:482 #, python-format msgid "%(user)s's submissions for %(problem)s" msgstr "" -#: judge/views/submission.py:603 +#: judge/views/submission.py:583 msgid "Must pass a contest" msgstr "" -#: judge/views/submission.py:622 +#: judge/views/submission.py:602 #, python-brace-format msgid "" "{0}'s submissions for {2} in {4}" msgstr "" -#: judge/views/submission.py:629 +#: judge/views/submission.py:609 #, python-brace-format msgid "" "{0}'s submissions for problem {2} in {3}" "" msgstr "" -#: judge/views/ticket.py:50 judge/views/ticket.py:56 +#: judge/views/ticket.py:33 judge/views/ticket.py:39 msgid "Ticket title" msgstr "" -#: judge/views/ticket.py:107 judge/views/ticket.py:110 +#: judge/views/ticket.py:40 +msgid "Issue description" +msgstr "" + +#: judge/views/ticket.py:85 judge/views/ticket.py:88 #, python-format msgid "New ticket for %s" msgstr "" -#: judge/views/ticket.py:170 +#: judge/views/ticket.py:142 #, python-format msgid "%(title)s - Ticket %(id)d" msgstr "" -#: judge/views/ticket.py:279 +#: judge/views/ticket.py:251 #, python-format msgid "Tickets - Page %(number)d of %(total)d" msgstr "" -#: judge/views/ticket.py:328 +#: judge/views/ticket.py:300 #, python-format msgid "New Ticket: %s" msgstr "" -#: judge/views/ticket.py:329 +#: judge/views/ticket.py:301 #, python-format msgid "#%(id)d, assigned to: %(users)s" msgstr "" -#: judge/views/ticket.py:331 +#: judge/views/ticket.py:303 msgid ", " msgstr "" -#: judge/views/ticket.py:331 +#: judge/views/ticket.py:303 msgid "no one" msgstr "" -#: judge/views/ticket.py:351 +#: judge/views/ticket.py:323 #, python-format msgid "New Ticket Message For: %s" msgstr "" @@ -2909,50 +2792,41 @@ msgstr "" msgid "Perform Two Factor Authentication" msgstr "" -#: judge/views/user.py:74 +#: judge/views/user.py:68 msgid "No such user" msgstr "" -#: judge/views/user.py:74 +#: judge/views/user.py:68 #, python-format msgid "No user handle \"%s\"." msgstr "" -#: judge/views/user.py:78 +#: judge/views/user.py:72 msgid "My account" msgstr "我的帳戶" -#: judge/views/user.py:79 +#: judge/views/user.py:73 #, python-format msgid "User %s" msgstr "用戶 %s" -#: judge/views/user.py:148 -msgid "M j, Y" -msgstr "" - -#: judge/views/user.py:171 +#: judge/views/user.py:136 msgid "M j, Y, G:i" msgstr "" -#: judge/views/user.py:290 +#: judge/views/user.py:221 msgid "Updated on site" msgstr "" -#: judge/views/user.py:323 templates/admin/auth/user/change_form.html:14 -#: templates/admin/auth/user/change_form.html:17 templates/base.html:238 -#: templates/user/user-tabs.html:10 +#: judge/views/user.py:254 templates/admin/auth/user/change_form.html:14 +#: templates/admin/auth/user/change_form.html:17 templates/base.html:224 msgid "Edit profile" msgstr "" -#: judge/views/user.py:332 templates/user/user-list-tabs.html:4 +#: judge/views/user.py:263 msgid "Leaderboard" msgstr "" -#: judge/views/user.py:407 -msgid "Import Users" -msgstr "" - #: judge/views/widgets.py:48 judge/views/widgets.py:58 #, python-format msgid "Invalid upstream data: %s" @@ -2990,7 +2864,7 @@ msgid "View Submissions" msgstr "" #: templates/admin/judge/problem/change_form.html:17 -#: templates/user/user-base.html:112 +#: templates/user/user-base.html:61 msgid "View submissions" msgstr "" @@ -3005,148 +2879,90 @@ msgstr "" msgid "Rejudge" msgstr "" -#: templates/base.html:230 -#, python-format -msgid "Hello, %(username)s." -msgstr "" - -#: templates/base.html:236 templates/comments/list.html:89 -#: templates/contest/contest-list-tabs.html:24 -#: templates/contest/ranking-table.html:53 -#: templates/problem/problem-list-tabs.html:6 +#: templates/base.html:222 templates/comments/list.html:89 +#: templates/contest/ranking-table.html:39 #: templates/submission/info-base.html:12 -#: templates/submission/submission-list-tabs.html:15 msgid "Admin" msgstr "" -#: templates/base.html:245 +#: templates/base.html:231 msgid "Log out" msgstr "登出" -#: templates/base.html:254 +#: templates/base.html:240 #: templates/registration/password_reset_complete.html:4 msgid "Log in" msgstr "" -#: templates/base.html:255 templates/registration/registration_form.html:177 +#: templates/base.html:241 templates/registration/registration_form.html:177 msgid "or" msgstr "" -#: templates/base.html:256 +#: templates/base.html:242 msgid "Sign up" msgstr "" -#: templates/base.html:271 +#: templates/base.html:254 msgid "spectating" msgstr "" -#: templates/base.html:284 +#: templates/base.html:267 msgid "This site works best with JavaScript enabled." msgstr "" -#: templates/blog/blog.html:13 templates/comments/list.html:68 -#: templates/comments/list.html:83 templates/contest/contest-tabs.html:23 -#: templates/contest/tag-title.html:9 templates/flatpages/admin_link.html:3 -#: templates/license.html:10 templates/problem/editorial.html:14 +#: templates/blog/content.html:13 templates/comments/list.html:68 +#: templates/comments/list.html:83 templates/contest/tag-title.html:9 +#: templates/flatpages/admin_link.html:3 templates/license.html:10 +#: templates/problem/editorial.html:14 msgid "Edit" msgstr "" -#: templates/blog/blog.html:26 -#, python-format -msgid "" -"\n" -" posted on %(time)s\n" -" " -msgstr "" - -#: templates/blog/content.html:10 -#, fuzzy, python-brace-format -#| msgid "posted time" -msgid "posted on {time}" -msgstr "發佈時間" - -#: templates/blog/dashboard.html:21 -#, python-format -msgid "" -"\n" -" on %(time)s\n" -" " -msgstr "" - -#: templates/blog/list.html:93 +#: templates/blog/list.html:85 msgid "Blog" msgstr "" -#: templates/blog/list.html:95 +#: templates/blog/list.html:87 msgid "Events" msgstr "" -#: templates/blog/list.html:100 +#: templates/blog/list.html:92 msgid "News" msgstr "" -#: templates/blog/list.html:115 templates/problem/list.html:347 -#: templates/problem/problem.html:361 +#: templates/blog/list.html:130 templates/problem/problem.html:310 msgid "Clarifications" msgstr "" -#: templates/blog/list.html:121 -msgid "Add" -msgstr "" - -#: templates/blog/list.html:140 templates/problem/list.html:369 -#: templates/problem/problem.html:372 +#: templates/blog/list.html:146 templates/problem/problem.html:321 msgid "No clarifications have been made at this time." msgstr "" -#: templates/blog/list.html:148 +#: templates/blog/list.html:154 msgid "Ongoing contests" msgstr "" -#: templates/blog/list.html:166 +#: templates/blog/list.html:172 msgid "Upcoming contests" msgstr "" -#: templates/blog/list.html:184 -msgid "My open tickets" -msgstr "" - -#: templates/blog/list.html:206 -msgid "New tickets" -msgstr "" - -#: templates/blog/list.html:227 -msgid "New problems" -msgstr "" - -#: templates/blog/list.html:244 +#: templates/blog/list.html:189 msgid "Comment stream" msgstr "" -#: templates/chat/chat.html:305 -msgid "Chat" +#: templates/blog/list.html:208 +msgid "New problems" msgstr "" -#: templates/chat/chat.html:307 templates/chat/chat.html:314 -#, fuzzy -#| msgid "Online Judge" -msgid "Online Users" -msgstr "線上裁判" - -#: templates/chat/chat.html:315 -msgid "Refresh" +#: templates/blog/list.html:225 +msgid "My open tickets" msgstr "" -#: templates/chat/chat.html:333 -msgid "Emoji" +#: templates/blog/list.html:246 +msgid "New tickets" msgstr "" -#: templates/chat/chat.html:334 -msgid "Enter your message" -msgstr "" - -#: templates/chat/message.html:20 -msgid "Delete" +#: templates/chat/chat.html:167 +msgid "Your message" msgstr "" #: templates/comments/list.html:2 @@ -3157,22 +2973,11 @@ msgstr "" msgid "Please login to vote" msgstr "" -#: templates/comments/list.html:40 -#, fuzzy, python-brace-format -#| msgid "posted time" -msgid "commented on {time}" -msgstr "發佈時間" - -#: templates/comments/list.html:49 -#, python-format -msgid "edit %(edits)s" -msgstr "" - -#: templates/comments/list.html:51 templates/comments/media-js.html:92 +#: templates/comments/list.html:51 templates/comments/media-js.html:77 msgid "edited" msgstr "" -#: templates/comments/list.html:60 templates/notification/list.html:14 +#: templates/comments/list.html:60 msgid "Link" msgstr "" @@ -3180,52 +2985,36 @@ msgstr "" msgid "Reply" msgstr "" -#: templates/comments/list.html:86 templates/contest/list.html:91 -#: templates/contest/list.html:95 templates/contest/list.html:280 +#: templates/comments/list.html:86 msgid "Hide" msgstr "" -#: templates/comments/list.html:101 -#, python-format -msgid "" -"\n" -" This comment is hidden due " -"to too much negative feedback.\n" -" Click here to view it.\n" -" " -msgstr "" - -#: templates/comments/list.html:121 +#: templates/comments/list.html:120 msgid "There are no comments at the moment." msgstr "" -#: templates/comments/list.html:127 +#: templates/comments/list.html:126 msgid "New comment" msgstr "" -#: templates/comments/list.html:141 +#: templates/comments/list.html:140 msgid "Invalid comment body." msgstr "" -#: templates/comments/list.html:149 +#: templates/comments/list.html:148 msgid "Post!" msgstr "" -#: templates/comments/list.html:157 +#: templates/comments/list.html:156 msgid "Comments are disabled on this page." msgstr "" -#: templates/comments/media-js.html:38 -msgid "Replying to comment" -msgstr "" - -#: templates/comments/media-js.html:87 +#: templates/comments/media-js.html:72 #, python-brace-format msgid "edit {edits}" msgstr "" -#: templates/comments/media-js.html:90 +#: templates/comments/media-js.html:75 msgid "original" msgstr "" @@ -3269,11 +3058,6 @@ msgstr "星期五" msgid "Saturday" msgstr "星期六" -#: templates/contest/clarification.html:52 templates/organization/new.html:10 -#: templates/ticket/new.html:38 -msgid "Create" -msgstr "" - #: templates/contest/clone.html:37 msgid "Enter a new key for the cloned contest:" msgstr "" @@ -3294,175 +3078,97 @@ msgstr "" msgid "Next" msgstr "" -#: templates/contest/contest-list-tabs.html:21 -#: templates/problem/problem-list-tabs.html:5 -msgid "List" -msgstr "" - -#: templates/contest/contest-list-tabs.html:22 -#, fuzzy -#| msgid "Standard" -msgid "Calendar" -msgstr "標準" - -#: templates/contest/contest-tabs.html:4 templates/organization/home.html:105 -msgid "Info" -msgstr "" - -#: templates/contest/contest-tabs.html:6 templates/stats/base.html:9 -#: templates/submission/list.html:339 -msgid "Statistics" -msgstr "" - -#: templates/contest/contest-tabs.html:11 -msgid "Rankings" -msgstr "" - -#: templates/contest/contest-tabs.html:16 -msgid "Hidden Rankings" -msgstr "" - -#: templates/contest/contest-tabs.html:21 -msgid "MOSS" -msgstr "" - -#: templates/contest/contest-tabs.html:26 -msgid "Clone" -msgstr "" - -#: templates/contest/contest-tabs.html:38 -#: templates/contest/contest-tabs.html:58 +#: templates/contest/contest-tabs.html:37 msgid "Leave contest" msgstr "" -#: templates/contest/contest-tabs.html:45 templates/contest/list.html:388 +#: templates/contest/contest-tabs.html:44 templates/contest/list.html:293 msgid "Virtual join" msgstr "" -#: templates/contest/contest-tabs.html:56 -msgid "Stop spectating" -msgstr "" - -#: templates/contest/contest-tabs.html:65 +#: templates/contest/contest-tabs.html:64 msgid "Spectate contest" msgstr "" -#: templates/contest/contest-tabs.html:72 +#: templates/contest/contest-tabs.html:70 +#: templates/contest/contest-tabs.html:76 msgid "Join contest" msgstr "" -#: templates/contest/contest-tabs.html:81 +#: templates/contest/contest-tabs.html:85 msgid "Login to participate" msgstr "" -#: templates/contest/contest.html:37 -msgid "Participating virtually." -msgstr "" - -#: templates/contest/contest.html:43 -msgid "Contest is over." -msgstr "" - #: templates/contest/contest.html:59 templates/contest/contest.html:63 msgid "F j, Y, G:i T" msgstr "" -#: templates/contest/contest.html:59 -#, python-format -msgid "" -"%(time_limit)s window between %(start_time)s and " -"%(end_time)s" -msgstr "" - -#: templates/contest/contest.html:63 -#, python-format -msgid "%(length)s long starting on %(start_time)s" -msgstr "" - #: templates/contest/contest.html:85 msgid "AC Rate" msgstr "" -#: templates/contest/contest.html:86 templates/contest/list.html:237 -#: templates/contest/list.html:289 templates/contest/list.html:366 -#: templates/problem/list.html:223 templates/problem/list.html:254 +#: templates/contest/contest.html:86 templates/contest/list.html:153 +#: templates/contest/list.html:195 templates/contest/list.html:271 +#: templates/problem/list.html:212 templates/problem/list.html:238 msgid "Users" msgstr "" -#: templates/contest/contest.html:111 templates/problem/list.html:330 +#: templates/contest/contest.html:111 msgid "Editorial" msgstr "" -#: templates/contest/list.html:83 templates/contest/media-js.html:9 +#: templates/contest/list.html:31 templates/contest/media-js.html:9 msgid "Are you sure you want to join?" msgstr "" -#: templates/contest/list.html:84 +#: templates/contest/list.html:32 msgid "" "Joining a contest for the first time starts your timer, after which it " "becomes unstoppable." msgstr "" -#: templates/contest/list.html:92 templates/contest/list.html:278 -msgid "Show" -msgstr "" - -#: templates/contest/list.html:102 templates/problem/list.html:68 -#, fuzzy -#| msgid "Organization" -msgid "Organizations..." -msgstr "組織" - -#: templates/contest/list.html:135 +#: templates/contest/list.html:65 msgid "hidden" msgstr "" -#: templates/contest/list.html:140 +#: templates/contest/list.html:70 msgid "private" msgstr "" -#: templates/contest/list.html:154 +#: templates/contest/list.html:84 msgid "rated" msgstr "" -#: templates/contest/list.html:202 +#: templates/contest/list.html:132 msgid "Spectate" msgstr "" -#: templates/contest/list.html:208 +#: templates/contest/list.html:138 msgid "Join" msgstr "" -#: templates/contest/list.html:220 -msgid "Search contests..." -msgstr "" - -#: templates/contest/list.html:229 -msgid "Search" -msgstr "" - -#: templates/contest/list.html:232 +#: templates/contest/list.html:148 msgid "Active Contests" msgstr "" -#: templates/contest/list.html:236 templates/contest/list.html:288 -#: templates/contest/list.html:327 templates/contest/list.html:365 +#: templates/contest/list.html:152 templates/contest/list.html:194 +#: templates/contest/list.html:232 templates/contest/list.html:270 msgid "Contest" msgstr "" -#: templates/contest/list.html:275 +#: templates/contest/list.html:190 msgid "Ongoing Contests" msgstr "" -#: templates/contest/list.html:322 +#: templates/contest/list.html:227 msgid "Upcoming Contests" msgstr "" -#: templates/contest/list.html:350 +#: templates/contest/list.html:255 msgid "There are no scheduled contests at this time." msgstr "" -#: templates/contest/list.html:356 +#: templates/contest/list.html:261 msgid "Past Contests" msgstr "" @@ -3513,73 +3219,49 @@ msgstr "" msgid "Only the following organizations may access this contest:" msgstr "" -#: templates/contest/ranking-table.html:9 templates/problem/search-form.html:35 +#: templates/contest/ranking-table.html:7 msgid "Organization" msgstr "組織" -#: templates/contest/ranking-table.html:10 templates/user/users-table.html:13 -msgid "Full Name" -msgstr "" - -#: templates/contest/ranking-table.html:44 +#: templates/contest/ranking-table.html:30 msgid "Un-Disqualify" msgstr "" -#: templates/contest/ranking-table.html:47 +#: templates/contest/ranking-table.html:33 msgid "Disqualify" msgstr "" -#: templates/contest/ranking.html:187 +#: templates/contest/ranking.html:173 msgid "Are you sure you want to disqualify this participation?" msgstr "" -#: templates/contest/ranking.html:192 +#: templates/contest/ranking.html:178 msgid "Are you sure you want to un-disqualify this participation?" msgstr "" -#: templates/contest/ranking.html:463 +#: templates/contest/ranking.html:252 msgid "View user participation" msgstr "" -#: templates/contest/ranking.html:467 +#: templates/contest/ranking.html:256 msgid "Show organizations" msgstr "" -#: templates/contest/ranking.html:471 -msgid "Show full name" -msgstr "" - -#: templates/contest/ranking.html:474 -msgid "Show friends only" -msgstr "" - -#: templates/contest/ranking.html:477 -msgid "Total score only" -msgstr "" - -#: templates/contest/ranking.html:479 -msgid "Show virtual participation" -msgstr "" - -#: templates/contest/stats.html:51 +#: templates/contest/stats.html:38 msgid "Problem Status Distribution" msgstr "" -#: templates/contest/stats.html:56 +#: templates/contest/stats.html:43 #, fuzzy #| msgid "Problem name" msgid "Problem AC Rate" msgstr "題目名稱" -#: templates/contest/stats.html:62 -msgid "Problem Point Distribution" -msgstr "" - -#: templates/contest/stats.html:76 templates/stats/language.html:16 +#: templates/contest/stats.html:48 templates/stats/language.html:16 msgid "Submissions by Language" msgstr "" -#: templates/contest/stats.html:82 templates/stats/language.html:26 +#: templates/contest/stats.html:54 templates/stats/language.html:26 msgid "Language AC Rate" msgstr "" @@ -3588,7 +3270,6 @@ msgid "Source:" msgstr "" #: templates/newsletter/common.html:6 -#: templates/newsletter/newsletter_list.html:15 #: templates/newsletter/subscription_unsubscribe_activated.html:3 #: templates/newsletter/subscription_unsubscribe_activated.html:6 #: templates/newsletter/subscription_update_activated.html:3 @@ -3596,25 +3277,6 @@ msgstr "" msgid "Newsletter" msgstr "" -#: templates/newsletter/newsletter_list.html:2 -#: templates/newsletter/newsletter_list.html:3 -msgid "Newsletter list" -msgstr "" - -#: templates/newsletter/newsletter_list.html:6 -msgid "Subscribe to get the latest emails about upcoming contests and events." -msgstr "" - -#: templates/newsletter/newsletter_list.html:16 -msgid "Subscribe" -msgstr "" - -#: templates/newsletter/newsletter_list.html:30 -#, fuzzy -#| msgid "Description" -msgid "Update subscriptions" -msgstr "描述說明" - #: templates/newsletter/subscription_unsubscribe_activated.html:3 #: templates/newsletter/subscription_unsubscribe_activated.html:6 #: templates/newsletter/subscription_update_activated.html:3 @@ -3676,99 +3338,64 @@ msgid "" "follow in order to update your subscription." msgstr "" -#: templates/notification/list.html:7 -msgid "You have no notifications" -msgstr "" - -#: templates/notification/list.html:13 -msgid "Activity" -msgstr "" - #: templates/organization/edit.html:46 #: templates/organization/requests/pending.html:34 #: templates/ticket/edit-notes.html:4 msgid "Update" msgstr "" -#: templates/organization/home.html:41 +#: templates/organization/home.html:7 msgid "Are you sure you want to leave this organization?" msgstr "" -#: templates/organization/home.html:43 +#: templates/organization/home.html:9 msgid "You will have to rejoin to show up on the organization leaderboard." msgstr "" -#: templates/organization/home.html:45 +#: templates/organization/home.html:11 msgid "You will have to request membership in order to join again." msgstr "" -#: templates/organization/home.html:88 -msgid "Join organization" -msgstr "" - -#: templates/organization/home.html:92 -msgid "Request membership" -msgstr "" - -#: templates/organization/home.html:122 -#, fuzzy -#| msgid "Organization" -msgid "Organization news" -msgstr "組織" - -#: templates/organization/home.html:128 -msgid "There is no news at this time." -msgstr "" - -#: templates/organization/home.html:137 -msgid "Controls" -msgstr "" - -#: templates/organization/home.html:142 -msgid "Edit organization" -msgstr "" - -#: templates/organization/home.html:148 -msgid "View requests" -msgstr "" - -#: templates/organization/home.html:161 -msgid "Admin organization" -msgstr "" - -#: templates/organization/home.html:167 -msgid "View members" -msgstr "" - -#: templates/organization/home.html:174 +#: templates/organization/home.html:24 msgid "Leave organization" msgstr "" -#: templates/organization/home.html:183 -msgid "New private contests" +#: templates/organization/home.html:29 +msgid "Join organization" msgstr "" -#: templates/organization/home.html:193 templates/organization/home.html:208 -msgid "View all" +#: templates/organization/home.html:33 +msgid "Request membership" msgstr "" -#: templates/organization/home.html:199 -msgid "New private problems" +#: templates/organization/home.html:39 +msgid "Edit organization" msgstr "" -#: templates/organization/list.html:40 -msgid "Show my organizations only" +#: templates/organization/home.html:43 +msgid "View requests" msgstr "" -#: templates/organization/list.html:47 templates/status/language-list.html:34 -#: templates/user/import/table_csv.html:6 +#: templates/organization/home.html:50 +msgid "Admin organization" +msgstr "" + +#: templates/organization/home.html:55 +msgid "View members" +msgstr "" + +#: templates/organization/list.html:23 templates/status/language-list.html:34 msgid "Name" msgstr "" -#: templates/organization/list.html:48 +#: templates/organization/list.html:24 msgid "Members" msgstr "" +#: templates/organization/new.html:10 templates/ticket/new.html:38 +msgid "Create" +msgstr "" + #: templates/organization/requests/detail.html:13 msgid "User:" msgstr "" @@ -3801,7 +3428,7 @@ msgid "There are no requests to approve." msgstr "" #: templates/organization/requests/pending.html:17 -#: templates/problem/data.html:432 +#: templates/problem/data.html:452 msgid "Delete?" msgstr "" @@ -3837,37 +3464,37 @@ msgstr "" msgid "Enter a new code for the cloned problem:" msgstr "" -#: templates/problem/data.html:119 +#: templates/problem/data.html:108 #, fuzzy #| msgid "solution" msgid "Instruction" msgstr "題解" -#: templates/problem/data.html:390 +#: templates/problem/data.html:410 msgid "View YAML" msgstr "" -#: templates/problem/data.html:421 templates/problem/data.html:472 +#: templates/problem/data.html:441 templates/problem/data.html:491 msgid "Apply!" msgstr "" -#: templates/problem/data.html:426 +#: templates/problem/data.html:446 msgid "Type" msgstr "" -#: templates/problem/data.html:427 +#: templates/problem/data.html:447 msgid "Input file" msgstr "" -#: templates/problem/data.html:428 +#: templates/problem/data.html:448 msgid "Output file" msgstr "" -#: templates/problem/data.html:430 +#: templates/problem/data.html:450 msgid "Pretest?" msgstr "" -#: templates/problem/data.html:473 +#: templates/problem/data.html:492 msgid "Add new case" msgstr "" @@ -3879,32 +3506,28 @@ msgid "" "problem yourself is a bannable offence." msgstr "" -#: templates/problem/list.html:66 +#: templates/problem/list.html:62 msgid "Filter by type..." msgstr "" -#: templates/problem/list.html:193 +#: templates/problem/list.html:185 msgid "Hot problems" msgstr "" -#: templates/problem/list.html:218 templates/problem/list.html:240 -#: templates/problem/search-form.html:45 templates/user/user-problems.html:57 +#: templates/problem/list.html:207 templates/problem/list.html:224 +#: templates/problem/search-form.html:30 templates/user/user-problems.html:57 msgid "Category" msgstr "" -#: templates/problem/list.html:220 templates/problem/list.html:244 +#: templates/problem/list.html:209 templates/problem/list.html:228 msgid "Types" msgstr "" -#: templates/problem/list.html:251 +#: templates/problem/list.html:235 #, python-format msgid "AC %%" msgstr "" -#: templates/problem/list.html:342 -msgid "Add clarifications" -msgstr "" - #: templates/problem/manage_submission.html:55 msgid "Leave empty to not filter by language" msgstr "" @@ -3913,199 +3536,152 @@ msgstr "" msgid "Leave empty to not filter by result" msgstr "" -#: templates/problem/manage_submission.html:80 +#: templates/problem/manage_submission.html:79 msgid "Need valid values for both start and end IDs." msgstr "" -#: templates/problem/manage_submission.html:83 +#: templates/problem/manage_submission.html:82 msgid "End ID must be after start ID." msgstr "" +#: templates/problem/manage_submission.html:90 +#, python-brace-format +msgid "" +"You are about to rejudge {count} submissions. Are you sure you want to do " +"this?" +msgstr "" + #: templates/problem/manage_submission.html:96 -#, python-brace-format msgid "" -"You are about to {action} {count} submissions. Are you sure you want to do " -"this?" +"You are about to rejudge a few submissions. Are you sure you want to do this?" msgstr "" -#: templates/problem/manage_submission.html:103 -#, python-brace-format -msgid "" -"You are about to {action} a few submissions. Are you sure you want to do " -"this?" +#: templates/problem/manage_submission.html:115 +msgid "Rejudge Submissions" msgstr "" -#: templates/problem/manage_submission.html:127 -#: templates/submission/list.html:309 -msgid "Filter submissions" -msgstr "" - -#: templates/problem/manage_submission.html:132 +#: templates/problem/manage_submission.html:120 msgid "Filter by ID:" msgstr "" -#: templates/problem/manage_submission.html:135 +#: templates/problem/manage_submission.html:123 msgid "Starting ID:" msgstr "" -#: templates/problem/manage_submission.html:139 +#: templates/problem/manage_submission.html:127 msgid "Ending ID:" msgstr "" -#: templates/problem/manage_submission.html:143 +#: templates/problem/manage_submission.html:131 msgid "This range includes both endpoints." msgstr "" -#: templates/problem/manage_submission.html:146 +#: templates/problem/manage_submission.html:134 msgid "Filter by language:" msgstr "" -#: templates/problem/manage_submission.html:154 +#: templates/problem/manage_submission.html:142 msgid "Filter by result:" msgstr "" -#: templates/problem/manage_submission.html:164 -#, fuzzy -#| msgid "location" -msgid "Action" -msgstr "位置" - -#: templates/problem/manage_submission.html:166 +#: templates/problem/manage_submission.html:150 msgid "Rejudge selected submissions" msgstr "" -#: templates/problem/manage_submission.html:171 -#, fuzzy -#| msgid "All submissions" -msgid "Download selected submissions" -msgstr "全部的提交" - -#: templates/problem/manage_submission.html:177 -#, python-format -msgid "Are you sure you want to rescore %(count)d submissions?" +#: templates/problem/manage_submission.html:157 +msgid "Rescore Everything" msgstr "" -#: templates/problem/manage_submission.html:178 +#: templates/problem/manage_submission.html:163 msgid "Rescore all submissions" msgstr "" -#: templates/problem/problem.html:132 +#: templates/problem/problem.html:91 msgid "View as PDF" msgstr "" -#: templates/problem/problem.html:141 templates/problem/problem.html:151 -#: templates/problem/problem.html:156 +#: templates/problem/problem.html:101 templates/problem/problem.html:111 +#: templates/problem/problem.html:116 msgid "Submit solution" msgstr "" -#: templates/problem/problem.html:144 -#, python-format -msgid "%(counter)s submission left" -msgid_plural "%(counter)s submissions left" -msgstr[0] "" - -#: templates/problem/problem.html:152 +#: templates/problem/problem.html:112 msgid "0 submissions left" msgstr "" -#: templates/problem/problem.html:164 +#: templates/problem/problem.html:124 msgid "My submissions" msgstr "" -#: templates/problem/problem.html:168 +#: templates/problem/problem.html:128 msgid "Best submissions" msgstr "" -#: templates/problem/problem.html:172 +#: templates/problem/problem.html:132 msgid "Read editorial" msgstr "" -#: templates/problem/problem.html:177 +#: templates/problem/problem.html:137 msgid "Manage tickets" msgstr "" -#: templates/problem/problem.html:181 +#: templates/problem/problem.html:141 msgid "Edit problem" msgstr "" -#: templates/problem/problem.html:183 +#: templates/problem/problem.html:143 msgid "Edit test data" msgstr "" -#: templates/problem/problem.html:188 +#: templates/problem/problem.html:148 msgid "My tickets" msgstr "" -#: templates/problem/problem.html:196 +#: templates/problem/problem.html:156 msgid "Manage submissions" msgstr "" -#: templates/problem/problem.html:202 +#: templates/problem/problem.html:162 msgid "Clone problem" msgstr "" -#: templates/problem/problem.html:209 +#: templates/problem/problem.html:169 msgid "Points:" msgstr "" -#: templates/problem/problem.html:212 templates/problem/problem.html:214 +#: templates/problem/problem.html:172 templates/problem/problem.html:174 msgid "(partial)" msgstr "" -#: templates/problem/problem.html:219 +#: templates/problem/problem.html:179 msgid "Time limit:" msgstr "時間限制:" -#: templates/problem/problem.html:231 +#: templates/problem/problem.html:191 msgid "Memory limit:" msgstr "記憶體限制:" -#: templates/problem/problem.html:250 -msgid "Author:" -msgid_plural "Authors:" -msgstr[0] "作者:" - -#: templates/problem/problem.html:265 -msgid "Problem type" -msgid_plural "Problem types" -msgstr[0] "題目類型" - -#: templates/problem/problem.html:278 +#: templates/problem/problem.html:238 msgid "Allowed languages" msgstr "允許的語言" -#: templates/problem/problem.html:286 -#, python-format -msgid "No %(lang)s judge online" -msgstr "" - -#: templates/problem/problem.html:297 -msgid "Judge:" -msgid_plural "Judges:" -msgstr[0] "" - -#: templates/problem/problem.html:314 +#: templates/problem/problem.html:274 msgid "none available" msgstr "" -#: templates/problem/problem.html:326 -#, python-format -msgid "This problem has %(length)s clarification(s)" -msgstr "" - -#: templates/problem/problem.html:350 +#: templates/problem/problem.html:299 msgid "Request clarification" msgstr "" -#: templates/problem/problem.html:352 +#: templates/problem/problem.html:301 msgid "Report an issue" msgstr "" -#: templates/problem/raw.html:64 +#: templates/problem/raw.html:62 msgid "Time Limit:" msgstr "" -#: templates/problem/raw.html:73 +#: templates/problem/raw.html:71 msgid "Memory Limit:" msgstr "" @@ -4129,72 +3705,39 @@ msgstr "" msgid "Show problem types" msgstr "" -#: templates/problem/search-form.html:32 -msgid "Show editorial" -msgstr "" - -#: templates/problem/search-form.html:48 templates/problem/search-form.html:50 -#: templates/submission/submission-list-tabs.html:4 +#: templates/problem/search-form.html:33 templates/problem/search-form.html:35 msgid "All" msgstr "" -#: templates/problem/search-form.html:62 +#: templates/problem/search-form.html:46 msgid "Problem types" msgstr "" -#: templates/problem/search-form.html:73 +#: templates/problem/search-form.html:57 msgid "Point range" msgstr "" -#: templates/problem/search-form.html:79 templates/submission/list.html:331 +#: templates/problem/search-form.html:63 templates/submission/list.html:331 #: templates/ticket/list.html:248 msgid "Go" msgstr "" -#: templates/problem/search-form.html:80 +#: templates/problem/search-form.html:64 msgid "Random" msgstr "" -#: templates/problem/submit.html:117 -msgid "Your source code must contain at most 65536 characters." -msgstr "" - -#: templates/problem/submit.html:204 -#, python-format -msgid "" -"Warning! Your default language, %(default_language)s, is " -"unavailable for this problem and has been deselected." -msgstr "" - -#: templates/problem/submit.html:215 -#, python-format -msgid "" -"\n" -" You have %(left)s submission left\n" -" " -msgid_plural "" -"\n" -" You have %(left)s submissions left\n" -" " -msgstr[0] "" - -#: templates/problem/submit.html:224 +#: templates/problem/submit.html:212 msgid "You have 0 submissions left" msgstr "" -#: templates/problem/submit.html:258 +#: templates/problem/submit.html:250 msgid "No judge is available for this problem." msgstr "" -#: templates/problem/submit.html:262 +#: templates/problem/submit.html:252 msgid "Submit!" msgstr "" -#: templates/registration/activate.html:3 -#, python-format -msgid "%(key)s is an invalid activation key." -msgstr "" - #: templates/registration/activation_complete.html:3 msgid "Your account has been successfully activated." msgstr "" @@ -4252,13 +3795,6 @@ msgid "" "you registered with, and check your spam folder." msgstr "" -#: templates/registration/password_reset_email.txt:1 -#, python-format -msgid "" -"You're receiving this email because you requested a password reset for your " -"user account at %(site_name)s." -msgstr "" - #: templates/registration/password_reset_email.txt:3 msgid "Please go to the following page and choose a new password:" msgstr "" @@ -4271,16 +3807,6 @@ msgstr "" msgid "Thanks for using our site!" msgstr "" -#: templates/registration/password_reset_email.txt:11 -#, python-format -msgid "The %(site_name)s team" -msgstr "" - -#: templates/registration/password_reset_subject.txt:1 -#, python-format -msgid "Password reset on %(site_name)s" -msgstr "" - #: templates/registration/profile_creation.html:36 #: templates/registration/username_select.html:7 msgid "Continue >" @@ -4317,20 +3843,19 @@ msgstr "" msgid "Affiliated organizations" msgstr "" -#: templates/registration/registration_form.html:195 -#: templates/user/edit-profile.html:128 +#: templates/registration/registration_form.html:192 msgid "Notify me about upcoming contests" msgstr "" -#: templates/registration/registration_form.html:209 +#: templates/registration/registration_form.html:206 msgid "By registering, you agree to our" msgstr "" -#: templates/registration/registration_form.html:210 +#: templates/registration/registration_form.html:207 msgid "Terms & Conditions" msgstr "" -#: templates/registration/registration_form.html:213 +#: templates/registration/registration_form.html:210 msgid "Register!" msgstr "" @@ -4340,11 +3865,6 @@ msgstr "" msgid "Enter the 6-digit code generated by your app:" msgstr "" -#: templates/registration/totp_auth.html:41 -#, python-format -msgid "If you lost your authentication device, please contact us at %(email)s." -msgstr "" - #: templates/registration/totp_disable.html:38 msgid "" "To protect your account, you must first authenticate before you can disable " @@ -4363,6 +3883,10 @@ msgstr "" msgid "Or enter this code manually:" msgstr "" +#: templates/stats/base.html:9 templates/submission/list.html:339 +msgid "Statistics" +msgstr "" + #: templates/stats/language.html:11 msgid "Submission Statistics" msgstr "" @@ -4388,7 +3912,6 @@ msgid "Ping" msgstr "" #: templates/status/judge-status-table.html:8 -#: templates/user/import/index.html:104 msgid "Load" msgstr "" @@ -4404,7 +3927,6 @@ msgid "There are no judges available at this time." msgstr "" #: templates/status/language-list.html:33 templates/ticket/list.html:261 -#: templates/user/import/table_csv.html:3 msgid "ID" msgstr "" @@ -4412,22 +3934,6 @@ msgstr "" msgid "Runtime Info" msgstr "" -#: templates/status/status-tabs.html:4 -msgid "Judges" -msgstr "" - -#: templates/status/status-tabs.html:6 -msgid "Version Matrix" -msgstr "" - -#: templates/submission/internal-error-message.html:3 -#, python-format -msgid "" -"An internal error occurred while grading, and the %(SITE_NAME)s " -"administrators have been notified.
In the meantime, try resubmitting in " -"a few seconds." -msgstr "" - #: templates/submission/internal-error-message.html:8 msgid "An internal error occurred while grading." msgstr "" @@ -4444,6 +3950,10 @@ msgstr "" msgid "Filter by language..." msgstr "" +#: templates/submission/list.html:309 +msgid "Filter submissions" +msgstr "" + #: templates/submission/list.html:345 msgid "Total:" msgstr "" @@ -4500,74 +4010,73 @@ msgstr "" msgid "Execution Results" msgstr "" -#: templates/submission/status-testcases.html:34 +#: templates/submission/status-testcases.html:31 +msgid "Batch " +msgstr "" + +#: templates/submission/status-testcases.html:43 msgid "Overall: " msgstr "" -#: templates/submission/status-testcases.html:48 +#: templates/submission/status-testcases.html:57 #, fuzzy #| msgid "Points" msgid "Point: " msgstr "分數" -#: templates/submission/status-testcases.html:53 +#: templates/submission/status-testcases.html:62 #, fuzzy #| msgid "Time" msgid "Time: " msgstr "時間" -#: templates/submission/status-testcases.html:62 +#: templates/submission/status-testcases.html:71 #, fuzzy #| msgid "Memory" msgid "Memory: " msgstr "記憶體" -#: templates/submission/status-testcases.html:73 -msgid "Batch " +#: templates/submission/status-testcases.html:84 +msgid "Case" msgstr "" -#: templates/submission/status-testcases.html:84 -#: templates/submission/status-testcases.html:113 +#: templates/submission/status-testcases.html:86 +msgid "Pretest" +msgstr "" + +#: templates/submission/status-testcases.html:88 +msgid "Test case" +msgstr "" + +#: templates/submission/status-testcases.html:99 #, fuzzy #| msgid "Points" msgid "Point" msgstr "分數" -#: templates/submission/status-testcases.html:99 -msgid "Case" -msgstr "" - -#: templates/submission/status-testcases.html:101 -msgid "Pretest" -msgstr "" - -#: templates/submission/status-testcases.html:103 -msgid "Test case" -msgstr "" - -#: templates/submission/status-testcases.html:141 +#: templates/submission/status-testcases.html:121 msgid "Input:" msgstr "" -#: templates/submission/status-testcases.html:145 +#: templates/submission/status-testcases.html:125 msgid "Output:" msgstr "" -#: templates/submission/status-testcases.html:149 +#: templates/submission/status-testcases.html:129 #, fuzzy #| msgid "Wrong Answer" msgid "Answer:" msgstr "錯誤答案" -#: templates/submission/status-testcases.html:154 +#: templates/submission/status-testcases.html:134 msgid "Judge feedback:" msgstr "" -#: templates/submission/status-testcases.html:175 +#: templates/submission/status-testcases.html:157 msgid "Passing pretests does not guarantee a full score on system tests." msgstr "" -#: templates/submission/status-testcases.html:178 +#: templates/submission/status-testcases.html:160 msgid "Submission aborted!" msgstr "" @@ -4579,24 +4088,11 @@ msgstr "" msgid "Abort" msgstr "" -#: templates/submission/submission-list-tabs.html:6 -msgid "Mine" -msgstr "" - -#: templates/submission/submission-list-tabs.html:9 -msgid "Best" -msgstr "" - -#: templates/submission/submission-list-tabs.html:12 -#, python-format -msgid "%(user)s's" -msgstr "" - -#: templates/ticket/list.html:135 templates/ticket/ticket.html:273 +#: templates/ticket/list.html:135 templates/ticket/ticket.html:257 msgid "Reopened: " msgstr "" -#: templates/ticket/list.html:138 templates/ticket/ticket.html:274 +#: templates/ticket/list.html:138 templates/ticket/ticket.html:258 msgid "Closed: " msgstr "" @@ -4620,7 +4116,7 @@ msgstr "" msgid "Title" msgstr "" -#: templates/ticket/list.html:264 templates/ticket/ticket.html:369 +#: templates/ticket/list.html:264 templates/ticket/ticket.html:328 msgid "Assignees" msgstr "" @@ -4635,36 +4131,32 @@ msgid "" "a problem, ask in the comments instead." msgstr "" -#: templates/ticket/ticket.html:355 -msgid "Post" -msgstr "" - -#: templates/ticket/ticket.html:363 +#: templates/ticket/ticket.html:322 msgid "Associated object" msgstr "" -#: templates/ticket/ticket.html:374 +#: templates/ticket/ticket.html:333 msgid "No one is assigned." msgstr "" -#: templates/ticket/ticket.html:380 +#: templates/ticket/ticket.html:339 msgid "Close ticket" msgstr "" -#: templates/ticket/ticket.html:382 +#: templates/ticket/ticket.html:341 msgid "Reopen ticket" msgstr "" -#: templates/ticket/ticket.html:386 +#: templates/ticket/ticket.html:345 msgid "Assignee notes" msgstr "" -#: templates/ticket/ticket.html:393 templates/widgets/select_all.html:4 +#: templates/ticket/ticket.html:352 templates/widgets/select_all.html:4 msgid "Nothing here." msgstr "" -#: templates/user/base-users-table.html:3 -msgid "Rank" +#: templates/ticket/ticket.html:385 +msgid "Post" msgstr "" #: templates/user/base-users.html:14 templates/user/base-users.html:69 @@ -4711,191 +4203,50 @@ msgstr "" msgid "Update profile" msgstr "" -#: templates/user/import/index.html:31 -msgid "Upload CSV only" -msgstr "" - -#: templates/user/import/index.html:100 -#, fuzzy -#| msgid "user profile" -msgid "User File" -msgstr "使用者個人檔案" - -#: templates/user/import/index.html:102 -msgid "Sample" -msgstr "" - -#: templates/user/import/index.html:105 templates/user/user-list-tabs.html:8 -msgid "Import" -msgstr "" - -#: templates/user/import/table_csv.html:7 -msgid "School" -msgstr "" - -#: templates/user/pp-row.html:22 -#, python-format -msgid "" -"\n" -" weighted %(weight)s%%\n" -" " -msgstr "" - -#: templates/user/pp-row.html:27 -#, python-format -msgid "%(pp).1fpp" -msgstr "" - -#: templates/user/pp-row.html:29 -#, python-format -msgid "%(pp).0fpp" -msgstr "" - -#: templates/user/user-about.html:23 -#, python-format -msgid "%(counter)s problem solved" -msgid_plural "%(counter)s problems solved" -msgstr[0] "" - -#: templates/user/user-about.html:35 -#, fuzzy -#| msgid "points" -msgid "Total points" -msgstr "分" - -#: templates/user/user-about.html:45 -#, fuzzy -#| msgid "Rating" -msgid "Rank by rating" -msgstr "評分" - -#: templates/user/user-about.html:52 -#, fuzzy -#| msgid "points" -msgid "Rank by points" -msgstr "分" - -#: templates/user/user-about.html:64 +#: templates/user/user-about.html:14 msgid "From" msgstr "" -#: templates/user/user-about.html:75 +#: templates/user/user-about.html:25 msgid "Admin Notes" msgstr "" -#: templates/user/user-about.html:90 +#: templates/user/user-about.html:40 msgid "You have not shared any information." msgstr "" -#: templates/user/user-about.html:92 +#: templates/user/user-about.html:42 msgid "This user has not shared any information." msgstr "" -#: templates/user/user-about.html:101 -msgid "Awards" +#: templates/user/user-base.html:50 +msgid "Rank by points:" msgstr "" -#: templates/user/user-about.html:112 -#, python-format -msgid "%(label)s (%(date)s)" +#: templates/user/user-base.html:53 +msgid "Total points:" msgstr "" -#: templates/user/user-about.html:130 -#, fuzzy -#| msgid "Monday" -msgid "Mon" -msgstr "星期一" - -#: templates/user/user-about.html:135 -#, fuzzy -#| msgid "Tuesday" -msgid "Tues" -msgstr "星期二" - -#: templates/user/user-about.html:140 -msgid "Wed" +#: templates/user/user-base.html:68 +msgid "Rank by rating:" msgstr "" -#: templates/user/user-about.html:145 -#, fuzzy -#| msgid "Thursday" -msgid "Thurs" -msgstr "星期四" - -#: templates/user/user-about.html:150 -#, fuzzy -#| msgid "Friday" -msgid "Fri" -msgstr "星期五" - -#: templates/user/user-about.html:155 -msgid "Sat" +#: templates/user/user-base.html:70 +msgid "Rating:" msgstr "" -#: templates/user/user-about.html:160 -#, fuzzy -#| msgid "Sunday" -msgid "Sun" -msgstr "星期日" - -#: templates/user/user-about.html:169 -msgid "Less" -msgstr "" - -#: templates/user/user-about.html:175 -msgid "More" -msgstr "" - -#: templates/user/user-about.html:184 -#, fuzzy -#| msgid "History" -msgid "Rating History" -msgstr "歷史記錄" - -#: templates/user/user-about.html:255 -msgid "past year" -msgstr "" - -#: templates/user/user-about.html:272 -#, fuzzy -#| msgid "All submissions" -msgid "total submission(s)" -msgstr "全部的提交" - -#: templates/user/user-about.html:276 -#, fuzzy -#| msgid "submission time" -msgid "submissions in the last year" -msgstr "提交時間" - -#: templates/user/user-base.html:101 -msgid "Unfollow" -msgstr "" - -#: templates/user/user-base.html:104 -msgid "Follow" -msgstr "" - -#: templates/user/user-base.html:120 -msgid "Contests written" -msgstr "" - -#: templates/user/user-base.html:124 +#: templates/user/user-base.html:71 msgid "Volatility:" msgstr "" -#: templates/user/user-base.html:128 +#: templates/user/user-base.html:72 msgid "Min. rating:" msgstr "" -#: templates/user/user-base.html:132 +#: templates/user/user-base.html:73 msgid "Max rating:" msgstr "" -#: templates/user/user-list-tabs.html:5 -msgid "Friends" -msgstr "" - #: templates/user/user-problems.html:35 msgid "Points Breakdown" msgstr "" @@ -4916,32 +4267,18 @@ msgstr "" msgid "Hide problems I've solved" msgstr "" -#: templates/user/user-problems.html:93 -#, python-format -msgid "%(points).1f points" -msgstr "" - #: templates/user/user-problems.html:99 msgid "Score" msgstr "" -#: templates/user/user-problems.html:110 -#, python-format -msgid "%(points)s / %(total)s" -msgstr "" - -#: templates/user/user-tabs.html:7 -msgid "Impersonate" -msgstr "" - -#: templates/user/user-tabs.html:13 -msgid "Admin User" -msgstr "" - -#: templates/user/user-tabs.html:16 -msgid "Admin Profile" -msgstr "" - #: templates/widgets/select_all.html:8 msgid "Check all" msgstr "" + +#~ msgid "Author:" +#~ msgid_plural "Authors:" +#~ msgstr[0] "作者:" + +#~ msgid "Problem type" +#~ msgid_plural "Problem types" +#~ msgstr[0] "題目類型" diff --git a/locale/zh_Hant/LC_MESSAGES/djangojs.po b/locale/zh_Hant/LC_MESSAGES/djangojs.po index 832032c..42e679b 100644 --- a/locale/zh_Hant/LC_MESSAGES/djangojs.po +++ b/locale/zh_Hant/LC_MESSAGES/djangojs.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: dmoj\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-07-20 23:30+0700\n" +"POT-Creation-Date: 2019-10-01 23:12+0000\n" "PO-Revision-Date: 2019-11-11 22:05\n" "Last-Translator: Icyene\n" "Language-Team: Chinese Traditional\n" @@ -26,3 +26,4 @@ msgstr[0] "%d 天 %h:%m:%s" msgctxt "time format without day" msgid "%h:%m:%s" msgstr "%h:%m:%s" + diff --git a/logo.png b/logo.png index 4e1a813..82ebdc8 100644 Binary files a/logo.png and b/logo.png differ diff --git a/manage.py b/manage.py index f0470c1..498e387 100644 --- a/manage.py +++ b/manage.py @@ -11,7 +11,6 @@ if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dmoj.settings") from django.core.management import execute_from_command_line - # noinspection PyUnresolvedReferences import django_2_2_pymysql_patch # noqa: F401, imported for side effect diff --git a/requirements.txt b/requirements.txt index 99b2c0f..564fa30 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,16 +1,16 @@ -Django>=3.2.17,<4 -django_compressor>=3 -django-mptt>=0.13 -django-pagedown -django-registration-redux>=2.10 -django-reversion>=3.0.5,<4 -django-reversion-compare +Django>=2.2,<3 +django_compressor +django-mptt +django-pagedown<2 +django-registration-redux +django-reversion django-social-share -django-sortedm2m>=3.1.0 +-e git://github.com/DMOJ/django-sortedm2m.git#egg=django-sortedm2m django-impersonate -dmoj-wpadmin @ git+https://github.com/LQDJudge/dmoj-wpadmin.git +-e git://github.com/DMOJ/dmoj-wpadmin.git#egg=dmoj-wpadmin lxml Pygments +mistune social-auth-app-django pytz django-statici18n @@ -18,30 +18,19 @@ pika ua-parser pyyaml jinja2 -django_jinja>=2.5.0 +django_jinja llist requests django-fernet-fields pyotp qrcode[pil] -jsonfield @ git+https://github.com/DMOJ/jsonfield.git +jsonfield pymoss -packaging<22 +packaging celery -ansi2html @ git+https://github.com/DMOJ/ansi2html.git +-e git://github.com/DMOJ/ansi2html.git#egg=ansi2html sqlparse -netaddr -redis -lupa -websocket-client -python-memcached<1.60 -numpy -pandas -markdown -bleach -pymdown-extensions -mdx-breakless-lists -beautifulsoup4 -pre-commit -django-ratelimit -lxml_html_clean \ No newline at end of file +channels +channels-redis +docker + diff --git a/resources/admin/css/pagedown.css b/resources/admin/css/pagedown.css index ee29196..27732de 100644 --- a/resources/admin/css/pagedown.css +++ b/resources/admin/css/pagedown.css @@ -2,12 +2,9 @@ padding-right: 15px !important; } + .wmd-preview { margin-top: 15px; padding: 15px; word-wrap: break-word; } - -.md-typeset, .wmd-input { - line-height: 1.4em !important; -} diff --git a/resources/awards/bronze-medal.png b/resources/awards/bronze-medal.png deleted file mode 100644 index 3a6f63f..0000000 Binary files a/resources/awards/bronze-medal.png and /dev/null differ diff --git a/resources/awards/gold-medal.png b/resources/awards/gold-medal.png deleted file mode 100644 index 4b5bb05..0000000 Binary files a/resources/awards/gold-medal.png and /dev/null differ diff --git a/resources/awards/medals.png b/resources/awards/medals.png deleted file mode 100644 index d193ff0..0000000 Binary files a/resources/awards/medals.png and /dev/null differ diff --git a/resources/awards/silver-medal.png b/resources/awards/silver-medal.png deleted file mode 100644 index 9d91ac0..0000000 Binary files a/resources/awards/silver-medal.png and /dev/null differ diff --git a/resources/base.scss b/resources/base.scss index 525a50d..6c624ad 100644 --- a/resources/base.scss +++ b/resources/base.scss @@ -25,7 +25,7 @@ a { } &:active { - color: $theme_color; + color: #faa700; } } @@ -35,12 +35,8 @@ img { // height: auto } -* { - -webkit-tap-highlight-color: transparent; -} - .full { - width: 100% !important; + width: 100%; } table.sortable thead { @@ -112,10 +108,11 @@ body { position: relative; min-height: 100%; margin: 0 auto; + max-width: 107em; font-size: $base_font_size; line-height: 1.231; background: $background_light_gray; - font-family: "Noto Sans", Arial, "Lucida Grande", sans-serif; + font-family: "Segoe UI", "Lucida Grande", Arial, sans-serif; color: #000; height: 100%; overflow-x: hidden; @@ -139,7 +136,7 @@ b { h2 { font-weight: 400; - font-size: 1.7em; + font-size: 2em; border-radius: $widget_border_radius; padding: 0; margin: 0; @@ -170,27 +167,64 @@ header { } #user-links { - display: flex; - text-align: center; - padding: 4px; - margin-right: 1em; - gap: 5px; - &:hover { - color: black; - border-radius: 2px; - border: 0.5px solid black; - cursor: pointer; - padding: 3.5px; + top: 0; + right: 0; + position: absolute; + color: #5c5954; + + .anon { + padding-right: 10px; + display: inline-flex; + min-height: 100%; + align-items: center; + white-space: nowrap; + } + + a { + color: #9c3706; + } + + li { + text-transform: none; + } + + & > ul { + display: block; + margin: 0; + + & > li > a > span { + font-size: 13px; + height: 36px; + padding-top: 8px; + display: block; + white-space: nowrap; + + & > img { + vertical-align: middle; + border-radius: $widget_border_radius; + display: inline; + margin: 2px 6px 0 5px; + } + + & > span { + color: darkslateblue; + vertical-align: middle; + display: inline; + margin-top: 11px; + margin-right: 9px; + padding: 0; + } + } } } #nav-shadow { height: 2px; - background: linear-gradient(lightgray, transparent); + background: linear-gradient(#7dc7ff, transparent); } #nav-container { - background: white; + background: #7dc7ff; // opacity: 0.77; // filter: alpha(opacity=77) @@ -198,11 +232,10 @@ header { } #navigation { - position: fixed; + position: relative; top: 0; left: 0; - right: 10px; - height: $navbar_height; + right: 0; } nav { @@ -229,12 +262,6 @@ nav { text-transform: uppercase; position: relative; - &.home-nav-element { - display: flex; - align-items: center; - margin-right: 1em; - } - &.home-nav-element a { padding: 0; height: 44px; @@ -247,30 +274,27 @@ nav { } a, button { - display: flex; - height: 100%; - align-items: center; - gap: 2px; + display: inline-block; text-decoration: none; - color: black; - font-weight: bold; - font-size: initial; + vertical-align: middle; + color: #9c3706; + padding: 13px 7px; + height: 18px; &:link { - color: black; + color: #9c3706; } &:hover { - border-top: 2px solid $theme_color; - color: black; + color: #FFF; background: rgba(255, 255, 255, 0.25); margin: 0; } &.active { // color: #FFF; - border-top: 2px solid $theme_color; - color: $theme_color; + background: $highlight_blue; + color: black; } .nav-expand { @@ -284,28 +308,27 @@ nav { left: 5px; display: none; color: #fff; - background: white; + background: $widget_black; margin: 0 !important; box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.4); + li { + &:first-child { + a.active { + border-top: 1px solid $widget_black; + } + } + } li { - &:hover { - background: lightgray; - } - display: block; - a { - color: black !important; - } - a, button { padding: 8px 20px 8px 8px !important; font-size: 0.8em; line-height: 18px; display: block; - border-left: 4px solid black; + border-left: 4px solid $highlight_blue; white-space: nowrap; } } @@ -317,7 +340,7 @@ nav { border: none; width: 100%; border-radius: 0; - height: auto !important; + height: auto; } &:hover > ul, &:active > ul, &:focus > ul { @@ -332,6 +355,16 @@ nav { } } } + + .nav-divider { + width: 1px; + vertical-align: middle; + padding-left: 3px; + display: inline-block; + height: 32px; + margin-right: 1px; + border-right: 3px solid rgba(255, 255, 255, 0.15); + } } hr { @@ -339,8 +372,7 @@ hr { } #content { - margin: $navbar_height auto 1em auto; - padding-top: 1em; + margin: 1em auto auto; // Header width: 90%; @@ -410,7 +442,6 @@ noscript #noscript { .toggle { font-weight: bold; - cursor: pointer; .fa { transition: transform 0.4s; @@ -435,6 +466,7 @@ noscript #noscript { #nav-placeholder { height: 47px; + max-width: 107em; background: white; border-right: 1px solid $border_gray; border-left: 1px solid $border_gray; @@ -442,7 +474,13 @@ noscript #noscript { #contest-info { font-size: 1.25em; + border: 5px solid $highlight_blue; + border-left: 5px dotted white; + border-radius: 0 $widget_border_radius $widget_border_radius 0; + background: rgba(0, 0, 0, 0.77); z-index: 100000; + padding: 10px 12px; + color: white; cursor: move; position: fixed; left: 20px; @@ -458,34 +496,6 @@ noscript #noscript { } } -#contest-info-main { - border-left: 5px dotted white; - background: rgba(0, 0, 0, 0.77); - padding: 10px 12px; - color: white; - display: inline; -} - -#contest-info-toggle { - display: inline; - padding: 10px 12px; - border-radius: 0 10px 10px 0; - cursor: pointer; -} - -.contest-info-toggle-mode-on { - background: rgba(0, 205, 0, 0.57); -} -.contest-info-toggle-mode-on:hover { - background: rgba(0, 205, 0, 0.97); -} -.contest-info-toggle-mode-off { - background: rgba(255, 0, 0, 0.57); -} -.contest-info-toggle-mode-off:hover { - background: rgba(255, 0, 0, 0.97); -} - #contest-time-remaining { display: inline-block; } @@ -495,12 +505,32 @@ noscript #noscript { flex: 1 1 1px; } +#user-links { + height: 100%; + + ul { + margin: 0; + + li { + display: block; + height: 100%; + + a { + display: block; + padding: 0; + height: 100%; + } + } + } +} + #page-container { min-height: 100%; position: relative; margin: 0 auto; border-right: 1px solid $border_gray; border-left: 1px solid $border_gray; + background: white; } // border-bottom: 1px solid rgb(204, 204, 204) @@ -518,6 +548,16 @@ noscript #noscript { margin-top: 1.2em; } +math { + font-size: 1.155em; +} + +.MathJax { + &:focus { + outline: none; + } +} + @media(max-width: 1498px) { #page-container { border-left: none; @@ -527,24 +567,21 @@ noscript #noscript { } } -@media (max-width: 799px) { +@media (max-width: 760px) { #navigation { - height: $navbar_height_mobile; - } - - #content { - margin-top: $navbar_height_mobile; + height: 36px; } #navicon { transition-duration: 0.25s; - display: flex; + display: block; + line-height: 26px; font-size: 2em; - color: $widget_black; + color: #FFF; padding: 0 0.25em; margin: 4px 0.25em; white-space: nowrap; - flex-grow: 1; + float: left; &.hover { color: #4db7fe; @@ -557,25 +594,20 @@ noscript #noscript { display: none; padding: 0; margin-left: 0; - text-align: center; border-left: 4px solid $highlight_blue; position: fixed; top: 36px; - background: white; + background: $widget_black; bottom: 0; - width: fit-content; + width: 8em; left: 0; box-shadow: none; - border: 1px solid; li { display: block; a { display: block; - font-weight: normal; - text-align: left; - padding: 7px 13px; .nav-expand { float: right; @@ -598,13 +630,34 @@ noscript #noscript { } } } + + #user-links { + bottom: 6px; + right: 6px; + position: absolute; + + & > ul > li { + & > a > span { + padding-top: 4px; + height: 32px; + } + + & > ul { + left: 0 !important; + margin-top: 0 !important; + } + } + } + + #content { + width: auto; + padding: 0 5px; + } } -@media(min-width: 800px) { +@media not all and (max-width: 760px) { #nav-list { - display: flex !important; - gap: 1.5em; - flex-grow: 1; + display: block !important; li { &.home-menu-item { @@ -621,327 +674,3 @@ noscript #noscript { } } } - -#notification { - color: lightsteelblue; -} - -#notification:hover { - color: darkgray; -} - -#chat-icon { - color: darkgreen; -} - -#chat-icon:hover { - color: $theme_color; -} - -#nav-lang-icon { - color: blue; - cursor: pointer; -} -#nav-lang-icon:hover { - color: darkblue; -} - -#nav-darkmode-icon { - cursor: pointer; - &:hover { - color: gray; - } -} - -.dropdown { - display: none; - background-color: white; - min-width: 160px; - box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); - padding: 4px 0; - z-index: 1; - border-radius: 5px; - - a { - display: block; - text-decoration: none; - transition: background-color 0.3s; - color: black; - } -} - -.dropdown-item { - font-size: 16px; - padding: 6px 40px 6px 15px; - cursor: pointer; - color: black; - font-weight: 600; - border-top: 1px solid #ccc; - - i { - width: 1.5em; - } -} - -.dropdown-item:hover { - color: $theme_color; - background-color: #f8f8f2; -} - -.popper-arrow, -.popper-arrow::before { - position: absolute; - width: 8px; - height: 8px; - background: inherit; -} - -.popper-arrow { - visibility: hidden; -} - -.popper-arrow::before { - visibility: visible; - content: ''; - transform: rotate(45deg); -} - -.popper-arrow { - top: -4px; -} - -.unread_boxes { - background-color: red; - color: white; - border-radius: 50%; - padding: 1px 4px; - margin-left: -12px; - font-size: x-small; - font-family: monospace; -} - -.sub-lang { - color: black; - font-size: x-small; - margin-left: -12px; - font-family: monospace; - text-transform: uppercase; -} - -.featherlight { - z-index: 1001 !important; -} - -// @media (max-width: 500px) { - // #notification { - // margin-top: 0.6em; - // } - // } - -.notification-open #notification { - color: green !important; -} - -.title-row { - color: #393630; - display: inline; -} - -.gray { - color: gray; -} - -.white { - color: white; -} - -.black { - color: black; -} - -.red { - color: red; -} - -.green { - color: green; -} - -.grayed { - color: #666; -} - -.darkcyan { - color: darkcyan; -} - -.peru { - color: peru; -} - -.blue { - color: blue; -} - -.background-d6e8f7 { - background-color: #d6e8f7; -} - -.background-bisque { - background-color: bisque; -} - -.background-royalblue { - background-color: royalblue !important; -} - -.background-green { - background-color: #28a745 !important; -} - -.background-red { - background-color: #dc3545 !important; -} - -.background-footer { - color: #808080; -} - -.view-next-page { - margin-left: auto; - margin-right: auto; - margin-top: 1em; - margin-bottom: 1em; -} - -#loading-bar { - position: fixed; - top: 0; - left: 0; - height: 2px; - background-color: $theme_color; - width: 0; - z-index: 9999; -} - -.nav-right-text { - font-weight: normal; - font-size: small; - text-align: center; -} - -.anon { - display: flex; - gap: 1em; - padding-right: 1em; - a { - color: black; - } -} - -@media (max-width: 799px) { - .nav-fa-icon { - display: none; - } - - .page-title { - margin-left: 0.5em; - } -} - -@media(min-width: 800px) { - .normal-text { - font-weight: normal; - font-size: small; - text-align: left; - } - #page-container { - background: #f1f2f2; - } - #event-tab { - display: none; - } - #content.wrapper { - background: white; - padding: 2em; - border-radius: 1em; - } - .view-next-page { - display: none; - } -} - -.colored-text { - color: black; -} - -.bold-text { - font-weight: bold; -} - -.non-italics { - font-style: normal; -} - -.margin-label{ - margin-bottom: 2.5px; - padding-bottom: 0.25em; - display: block; -} - -::placeholder { /* Chrome, Firefox, Opera, Safari 10.1+ */ - color: $theme_color; - opacity: 1; /* Firefox */ - text-align: center; -} - -:-ms-input-placeholder { /* Internet Explorer 10-11 */ - color: $theme_color; - text-align: center; -} - -::-ms-input-placeholder { /* Microsoft Edge */ - color: $theme_color; - text-align: center; -} - -input::placeholder{ - color: $theme_color; - text-align: center; -} - -::-webkit-input-placeholder { - color: $theme_color; - text-align: center; -} - -:-moz-placeholder { /* Firefox 18- */ - color: $theme_color; - text-align: center; -} - -::-moz-placeholder { /* Firefox 19+ */ - color: $theme_color; - text-align: center; -} - -.nav-fa-icon { - i { - margin-right: 0.1em; - color: #000; - font-size: 21px; - } -} - -.nav-fa-icon-active { - i { - color: $theme_color; - font-size: 22.5px; - margin-right: 0.1em; - } -} - -.featherlight-content { - max-height: 80% !important; - border-radius: 10px; -} \ No newline at end of file diff --git a/resources/blog.scss b/resources/blog.scss index 1df8dc6..1a67fc2 100644 --- a/resources/blog.scss +++ b/resources/blog.scss @@ -1,21 +1,18 @@ @import "vars"; -.middle-content { +.blog-content { padding-right: 0em; + flex: 73.5%; vertical-align: top; margin-right: 0; - width: 100%; .post { - border: 1px dotted grey; - border-radius: 1em; - border-top: 0.125rem solid #9b9b9b; - padding: 1.25rem 1.25rem 1.563rem; - margin-bottom: 2em; + border-bottom: 2px solid $border_gray; + padding-top: 0.5em; .title { font-weight: 600; - font-size: 1.875em; + font-size: 1.7em; a { color: Maroon !important; @@ -27,19 +24,13 @@ } &:last-child { - // border-bottom: none; + border-bottom: none; } } } -.left-sidebar-item.active { - color: white; - font-weight: bold; - background-color: $theme_color; - - .sidebar-icon { - color: white; - } +.blog-sidebar { + flex: 26.5%; } .blog-sidebox { @@ -49,6 +40,7 @@ } ul { + list-style: none; padding-left: 1em; padding-right: 0.5em; @@ -81,25 +73,24 @@ } } -.no-dot-blog-sidebox { - ul { - list-style: none; +@media (min-width: 800px) { + .blog-content, .blog-sidebar { + display: block !important; + } + + .blog-content { + margin-right: 1em !important; + } + + #mobile.tabs { + display: none; + } + + #blog-container { + display: flex; } } -.blog-comment-count { - font-size: 12px; -} - -.blog-comment-icon { - padding: 0.1em 0.2em 0 0.5em; -} - -.blog-comment-count-link { - color: #555; -} - - #mobile.tabs { margin: 0; margin-bottom: 1em; @@ -129,275 +120,3 @@ } } } - -.blog-box { - border-bottom: 1.4px solid lightgray; - border-top: 1.4px solid lightgray; - margin-bottom: 1.5em; - padding: 1em 1.25em 0.5em 1.25em; - background-color: white; - margin-left: auto; - margin-right: auto; - box-shadow: 0 0 5px rgba(0, 0, 0, 0.2); - - .title { - margin-bottom: 0.2em; - font-weight: 500; - } -} - -.blog-box:hover, .blog-box:not(.pre-expand-blog) { - border-color: #8a8a8a; - box-shadow: 0 0 2px rgba(0, 0, 0, 0.1); -} - -.blog-description { - max-height: 30em; - overflow: hidden; - overflow-wrap: anywhere; - padding-bottom: 1em; - clear: both; - position: relative; -} - -.problem-feed-name { - display: inline; - font-weight: bold; -} - -.problem-feed-name a { - color: #0645ad; -} - -.problem-feed-info-entry { - display: inline; - float: right; -} - -.problem-feed-types { - color: gray; -} - -.left-sidebar-item { - display: flex; - align-items: center; - border-radius: .5em; - color: black; - - .sidebar-icon { - font-size: large; - display: inline-block; - - i { - width: 1.4em; - } - } -} - -.left-sidebar-item:hover { - background-color: #e3e3e3; - cursor: pointer; - color: black; -} - -.left-sidebar-item.active:hover { - background-color: $theme_color; - color: white; -} - -.sidebar-icon { - color: black; -} - -.left-sidebar-header { - text-align: center; - padding-bottom: 1em; - border-bottom: 1px solid black; - color: black; - border-radius: 0; -} - -.feed-table { - margin: 0; -} - -.pre-expand-blog { - position: relative; - padding-bottom: 0; -} - -.show-more { - display: flex; - color: black; - font-size: 16px; - font-weight: 700; - padding: 0px 12px; - margin-top: 5px; - position: absolute; - inset: 50% 0px 0px; - background: linear-gradient(transparent, white); - -webkit-box-pack: end; - justify-content: flex-end; - align-items: flex-end; - cursor: pointer; - padding: 16px 16px; -} - -.actionbar-box { - margin: 8px 16px; -} - -.post-full { - .post-title { - font-weight: bold; - margin-bottom: 10px; - font-family: serif; - } -} - -.middle-right-content.wrapper { - padding: 1em 0; - background: white; - border-radius: 1em; -} - -.post-content-header { - margin-left: 0; - display: inline-flex; - align-items: center; - gap: 0.2em; -} - - -@media (max-width: 799px) { - .blog-sidebar, - .right-sidebar { - width: 100%; - margin-left: auto; - margin-top: 2em; - } - - .actionbar-box { - margin: 8px 0; - } - - .left-sidebar-header { - display: none; - } - - .left-sidebar-item { - padding: 0.8em 0.2em 0.8em 0.2em; - display: inline-block; - flex: 1; - min-width: 5em; - overflow-wrap: anywhere; - - .sidebar-icon { - display: none; - } - } - - .left-sidebar { - text-align: center; - margin-bottom: 1em; - border-radius: 7px; - display: flex; - background: inherit; - gap: 0.3em; - overflow-x: auto; - } - - .blog-box { - padding-left: 5%; - padding-right: 5%; - margin-bottom: 0; - } - - .post-title { - font-size: 2em; - } -} - -@media (min-width: 800px) { - .left-sidebar-item { - margin-bottom: 10px; - margin-left: 10px; - border: 1px solid lightgray; - box-shadow: 0 0 5px rgba(0, 0, 0, 0.1); - background-color: white; - padding: 0.8em 0.2em 0.8em 0.8em; - } - - .sidebar-text { - overflow: hidden; - text-overflow: ellipsis; - } - - .middle-content, - .blog-sidebar, - .right-sidebar { - display: block !important; - } - - .blog-sidebar, - .right-sidebar { - flex: 25%; - max-width: 25%; - } - - .middle-content { - margin-right: 2% !important; - } - - #mobile.tabs { - display: none; - } - - #three-col-container { - display: flex; - flex-direction: column; - } - - .middle-content { - flex: 75%; - max-width: 75%; - } - - .left-sidebar { - width: 11%; - max-width: 11%; - min-width: 11%; - position: fixed; - height: calc(100vh - $navbar_height - 20px); - overflow-y: auto; - - &::-webkit-scrollbar { - width: 0; - background-color: transparent; - } - } - - .feed-table { - font-size: small; - } - - .blog-box { - border-left: 1.4px solid lightgray; - border-right: 1.4px solid lightgray; - border-radius: 16px; - } - - .post-full { - width: 80%; - margin-left: auto; - margin-right: auto; - - .content-description { - font-size: 18px; - } - - .post-title { - font-size: 2.5em; - } - } -} diff --git a/resources/bootstrap/bootstrap.min.css b/resources/bootstrap/bootstrap.min.css deleted file mode 100644 index d65c66b..0000000 --- a/resources/bootstrap/bootstrap.min.css +++ /dev/null @@ -1,5 +0,0 @@ -/*! - * Bootstrap v3.3.5 (http://getbootstrap.com) - * Copyright 2011-2015 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff2) format('woff2'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-eur:before,.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before{content:"\e227"}.glyphicon-btc:before{content:"\e227"}.glyphicon-xbt:before{content:"\e227"}.glyphicon-yen:before{content:"\00a5"}.glyphicon-jpy:before{content:"\00a5"}.glyphicon-ruble:before{content:"\20bd"}.glyphicon-rub:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:focus,a:hover{color:#23527c;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role=button]{cursor:pointer}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-size:18px}.h5,h5{font-size:14px}.h6,h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}.small,small{font-size:85%}.mark,mark{padding:.2em;background-color:#fcf8e3}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:focus,a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:focus,a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:focus,a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:focus,a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:focus,a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:focus,a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:focus,a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:focus,a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:focus,a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:focus,a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ol,ul{margin-top:0;margin-bottom:10px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;margin-left:-5px;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dd,dt{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote .small:before,blockquote footer:before,blockquote small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc}.table-responsive{min-height:.01%;overflow-x:auto}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px\9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=checkbox]:focus,input[type=radio]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date].form-control,input[type=time].form-control,input[type=datetime-local].form-control,input[type=month].form-control{line-height:34px}.input-group-sm input[type=date],.input-group-sm input[type=time],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}.input-group-lg input[type=date],.input-group-lg input[type=time],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-top:4px\9;margin-left:-20px}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}.checkbox-inline.disabled,.radio-inline.disabled,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio-inline{cursor:not-allowed}.checkbox.disabled label,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .radio label{cursor:not-allowed}.form-control-static{min-height:34px;padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.form-group-sm select.form-control{height:30px;line-height:30px}.form-group-sm select[multiple].form-control,.form-group-sm textarea.form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:6px 10px;font-size:12px;line-height:1.5}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-lg{height:46px;line-height:46px}select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.form-group-lg select.form-control{height:46px;line-height:46px}.form-group-lg select[multiple].form-control,.form-group-lg textarea.form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:11px 16px;font-size:18px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.form-group-lg .form-control+.form-control-feedback,.input-group-lg+.form-control-feedback,.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.form-group-sm .form-control+.form-control-feedback,.input-group-sm+.form-control-feedback,.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:14.33px;font-size:18px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px;font-size:12px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{color:#333;text-decoration:none}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default.focus,.btn-default:focus{color:#333;background-color:#e6e6e6;border-color:#8c8c8c}.btn-default:hover{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active.focus,.btn-default.active:focus,.btn-default.active:hover,.btn-default:active.focus,.btn-default:active:focus,.btn-default:active:hover,.open>.dropdown-toggle.btn-default.focus,.open>.dropdown-toggle.btn-default:focus,.open>.dropdown-toggle.btn-default:hover{color:#333;background-color:#d4d4d4;border-color:#8c8c8c}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled.focus,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled].focus,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#286090;border-color:#122b40}.btn-primary:hover{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.dropdown-toggle.btn-primary.focus,.open>.dropdown-toggle.btn-primary:focus,.open>.dropdown-toggle.btn-primary:hover{color:#fff;background-color:#204d74;border-color:#122b40}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled.focus,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled].focus,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success.focus,.btn-success:focus{color:#fff;background-color:#449d44;border-color:#255625}.btn-success:hover{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.dropdown-toggle.btn-success.focus,.open>.dropdown-toggle.btn-success:focus,.open>.dropdown-toggle.btn-success:hover{color:#fff;background-color:#398439;border-color:#255625}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled.focus,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled].focus,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info.focus,.btn-info:focus{color:#fff;background-color:#31b0d5;border-color:#1b6d85}.btn-info:hover{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.dropdown-toggle.btn-info.focus,.open>.dropdown-toggle.btn-info:focus,.open>.dropdown-toggle.btn-info:hover{color:#fff;background-color:#269abc;border-color:#1b6d85}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled.focus,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled].focus,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning.focus,.btn-warning:focus{color:#fff;background-color:#ec971f;border-color:#985f0d}.btn-warning:hover{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.dropdown-toggle.btn-warning.focus,.open>.dropdown-toggle.btn-warning:focus,.open>.dropdown-toggle.btn-warning:hover{color:#fff;background-color:#d58512;border-color:#985f0d}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled.focus,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled].focus,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#c9302c;border-color:#761c19}.btn-danger:hover{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.dropdown-toggle.btn-danger.focus,.open>.dropdown-toggle.btn-danger:focus,.open>.dropdown-toggle.btn-danger:hover{color:#fff;background-color:#ac2925;border-color:#761c19}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled.focus,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled].focus,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#337ab7;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-xs>.btn,.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-top:4px solid\9;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown,.dropup{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;background-color:#337ab7;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px dashed;border-bottom:4px solid\9}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn,.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{z-index:2;margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#337ab7}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#337ab7}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;height:50px;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{color:#555;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#333}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{color:#fff;background-color:#080808}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#337ab7;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{z-index:3;color:#23527c;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:2;color:#fff;cursor:default;background-color:#337ab7;border-color:#337ab7}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px;line-height:1.3333333}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px;line-height:1.5}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:focus,.label-default[href]:hover{background-color:#5e5e5e}.label-primary{background-color:#337ab7}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#286090}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:middle;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding-top:30px;padding-bottom:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron .h1,.jumbotron h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron,.container-fluid .jumbotron{padding-right:60px;padding-left:60px}.jumbotron .h1,.jumbotron h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail a>img,.thumbnail>img{margin-right:auto;margin-left:auto}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#337ab7}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-bar-striped,.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{overflow:hidden;zoom:1}.media-body{width:10000px}.media-object{display:block}.media-object.img-thumbnail{max-width:none}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}a.list-group-item,button.list-group-item{color:#555}a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover,button.list-group-item:focus,button.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5}button.list-group-item{width:100%;text-align:left}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#777;cursor:not-allowed;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#c7ddef}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success,button.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover,button.list-group-item-success.active,button.list-group-item-success.active:focus,button.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info,button.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover,button.list-group-item-info.active,button.list-group-item-info.active:focus,button.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover,button.list-group-item-warning.active,button.list-group-item-warning.active:focus,button.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger,button.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover,button.list-group-item-danger.active,button.list-group-item-danger.active:focus,button.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-left-radius:0;border-top-right-radius:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-collapse>.table caption,.panel>.table caption,.panel>.table-responsive>.table caption{padding-right:15px;padding-left:15px}.panel>.table-responsive:first-child>.table:first-child,.panel>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table:first-child>thead:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table-responsive:last-child>.table:last-child,.panel>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#337ab7}.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7}.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{min-height:16.43px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:12px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;filter:alpha(opacity=0);opacity:0;line-break:auto}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px;bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);line-break:auto}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>a>img,.carousel-inner>.item>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-inner>.item.active.right,.carousel-inner>.item.next{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.carousel-inner>.item.active.left,.carousel-inner>.item.prev{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9}.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block;margin-top:-10px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;font-family:serif;line-height:1}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000\9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-15px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-15px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-15px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{display:table;content:" "}.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-lg,.visible-md,.visible-sm,.visible-xs{display:none!important}.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table!important}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table!important}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table!important}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table!important}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table!important}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}} \ No newline at end of file diff --git a/resources/chatbox.scss b/resources/chatbox.scss index 6c4f671..3839fce 100644 --- a/resources/chatbox.scss +++ b/resources/chatbox.scss @@ -1,230 +1,71 @@ -@import "vars"; - -.chat { - background: white; -} -#chat-log p { - margin: 0; - padding-top: 0.1em; - padding-bottom: 0.1em; - overflow-wrap: anywhere; -} -.chatbtn_remove_mess { - float: right; - margin-right: 1em; -} -#chat-log { - padding: 0; - padding-top: 2em; - width: 100%; - font-size: 14px; -} -#chat-log li { - list-style-type: none; - margin: 0.5em; -} -#chat-submit { - margin-top: 1em; -} -.big-emoji { - font-size: 1.2em; -} -#chat-online { - border-right: 1px solid #ccc; - padding-bottom: 0 !important; - border-bottom: 0; - font-size: 1.2em; -} -#chat-online-content { - margin-bottom: 0; - overflow: hidden; - overflow-wrap: break-word; - overflow-y: auto; - max-height: 100%; -} #chat-box { - /*border: 1px solid #ccc;*/ - /*border-top-right-radius: 4px;*/ + border: 1px solid #ccc; + border-radius: 4px; + height: 20em; width: 100%; overflow: hidden; overflow-wrap: break-word; overflow-y: scroll; - border-bottom-left-radius: 0; - border-bottom-right-radius: 0; - flex-grow: 1; - padding-left: 0.5em; +} + +#loader { + display: block; + margin-left: auto; + margin-right: auto; + width: 4%; +} + +#chat-log { + padding: 0; + padding-top: 2em; + width: 100%; +} + +#chat-log li { + list-style-type: none; + margin: 0.5em; } #chat-input { - color: black; - border: 2px solid black; -} -#chat-input::placeholder { - color: grey; -} -#chat-online-content { - padding: 0; width: 100%; -} -.selected-status-row { - background-color: lightgray; -} -.status_last_message { - color: darkgray; - font-size: 0.8em; -} - -@media (min-width: 800px) { - #chat-container { - display: flex; - width: 100%; - height: calc(100vh - $navbar_height); - border: 1px solid #ccc; - /*border-radius: 0 4px 0 0;*/ - border-bottom: 0; - } - #chat-online { - margin: 0; - min-width: 30%; - max-width: 30%; - } - #chat-area { - flex-grow: 1; - min-width: 70%; - max-width: 70%; - } -} -#chat-input, #chat-log .content-message { - font-family: "Noto Sans", Arial, "Lucida Grande", sans-serif; -} -.info-pic { - height: 95%; - width: 100%; -} - -.info-name { - margin-left: 10px; - font-size: 1.8em; - font-weight: bold !important; - display: flex; - align-items: center; -} -.info-name a { - display: table-caption; -} -#chat-info { - display: flex; - align-items: center; - box-shadow: 0px 2px 3px rgb(0 0 0 / 20%); - position: relative; - z-index: 100; -} -.status-pic { - height: 32px; - width: 32px; - border-radius: 50%; -} -.status-container { - position: relative; - display: inline-flex; - flex: 0 0 auto; - align-items: center; -} -.status-circle { - position: absolute; - bottom: 0; - right: 0; - cx: 27px; - cy: 27px; - r: 4.5px; - stroke: white; - stroke-width: 1; -} -.status-row { - display: flex; - padding: 15px; - padding-right: 0; - gap: 0.5em; - border-radius: 6px; -} -.status-row:hover { - background: lightgray; - cursor: pointer; -} -.status-list { - padding: 0; - margin: 0; -} -.status-section-title { - cursor: pointer; - margin-top: 0.5em; -} -.message-text { - padding: 0.4em 0.6em 0.5em; - border-radius: 20px; - max-width: 70%; - width: fit-content; - font-size: 1rem; - line-height: 1.2; -} -.message-text-other { - background: #eeeeee; + padding: 0.4em; color: black; } -.message-text-myself { - background: rgb(0, 132, 255); - color: white; -} -.chat-input-icon { - color: white; - background-color: #3c8262; -} -.chat-input-icon:hover { - background: #57b28b; -} -.chat { - .active-span { - color: #636363; - margin-right: 1em; - } - .unread-count { - color: white; - background-color: darkcyan; - border-radius: 50%; - align-self: center; - flex: 0 0 1.25rem; - height: 1.25rem; - font-size: smaller; - display: flex; - align-items: center; - justify-content: center; - } - .setting-content { - display: none; - position: absolute; - background-color: #f1f1f1; - min-width: 160px; - box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); - z-index: 1; - right: 0; - } - .setting-content a { - padding: 12px 16px; - text-decoration: none; - display: block; - font-weight: bold; - font-size: 1rem; - } - .setting-content a:hover { - background-color: #ddd; - cursor: pointer; - } +#chat-submit { + margin-top: 1em; } -@media (max-width: 799px) { - #chat-area { - height: calc(100vh - $navbar_height_mobile); - max-height: -webkit-fill-available; - } +.profile-pic { + height: 2.6em; + width: 2.6em; + border-radius: 0.3em; + margin-top: 0.1em; + float: left; } + +.body-message { + padding-left: 3em; +} + +.user-time { + margin-bottom: 0.3em; +} + +.time { + margin-left: 0.5em; +} + +.user { + font-weight: bold; +} + +.clear { + clear: both; +} +.content-message { + word-wrap: break-word; + white-space: pre-line; +} + + diff --git a/resources/comments.scss b/resources/comments.scss index bceb225..2febe54 100644 --- a/resources/comments.scss +++ b/resources/comments.scss @@ -21,135 +21,6 @@ a { h2 { margin-bottom: 20px; } - - .revision-text p:first-child { - margin-top: 0; - } - - .revision-text p:last-child { - margin-bottom: 0; - } - - .featherlight-edit .featherlight-content { - background: #FAFAFA; - padding: 10px 15px 10px 10px; - border-radius: 10px; - border: 1px solid #CCC; - } - - .comment-img { - display: flex; - margin-right: 4px; - height: 1.5em; - width: 1.5em; - } - - .new-comments .comment-display { - display: flex; - margin-top: -0.25em !important; - padding-left: 1em; - padding-top: 0.5em !important; - border: 1px solid #ccc; - background: #fafafa; - } - - .new-comments .comment .detail { - width: 100%; - padding-right: 1em; - } - - .new-comments .comment-edits { - padding-right: 0.75em; - } - - .new-comments .comment .detail .header { - display: flex; - flex-wrap: wrap; - padding: 2px 0px; - font-weight: normal; - border-bottom: 1px #888 solid; - color: #888; - text-align: right; - align-items: center; - } - - .previous-revision, .next-revision { - color: #444; - } - - .new-comments .header i { - color: #888 !important; - } - - .new-comments .info { - padding-top: 0.4em; - display: flex; - } - - .new-comments .gravatar { - width: 1.5em; - border-radius: 50%; - } - - .new-comments .vote { - margin-right: 1em; - height: 75px; - padding-top: 0.4em; - } - - .new-comments .comment-display { - border-radius: 4px; - } - - .new-comments .comment:target > .comment-display { - border: 1px solid #2980b9; - border-left: 10px solid #2980b9; - padding-left: 5px; - } - - .comments.top-level-comments { - margin-bottom: -3px; - } - - .bad-comment { - opacity: 0.3; - } - - .bad-comment:hover { - opacity: 1; - /* This is necessary to prevent random flickering */ - -webkit-transform: translatez(0); - -moz-transform: translatez(0); - -ms-transform: translatez(0); - -o-transform: translatez(0); - transform: translatez(0); - } - .reply-comment { - margin: -50px 23px 10px -40px; - padding-top: 50px; - } - - .show_more_reply { - font-weight: bold; - display: flex; - margin: 16px 40px; - align-items: center; - - svg { - margin-right: 4px; - } - } - - .show_more_comment { - font-weight: bold; - display: flex; - margin: 16px -40px; - align-items: center; - - svg { - margin-right: 4px; - } - } } .no-comments-message { @@ -187,7 +58,6 @@ a { } .comment-operation { - flex: auto; float: right; .fa { @@ -208,10 +78,17 @@ a { } .comment-post-wrapper { + div { + padding-bottom: 2px; + padding-right: 10px; + } + input, textarea { min-width: 100%; max-width: 100%; - font-size: 15px; + + // Hack for 4k on Chrome + font-size: $base_font_size; } } @@ -257,71 +134,3 @@ a { .comment-body { word-wrap: break-word; } - -.actionbar { - display: flex; - - .actionbar-button { - cursor: pointer; - padding: 0.8em; - border-radius: 5em; - font-weight: bold; - display: inherit; - background: lightgray; - } - .actionbar-block { - display: flex; - flex: 1; - justify-content: center; - } - .pagevote-score { - margin-right: 0.3em; - } - .like-button { - padding-right: 0.5em; - border-radius: 5em 0 0 5em; - } - .actionbar-button:hover { - background: darkgray; - } - .dislike-button { - padding-left: 0.5em; - border-radius: 0 5em 5em 0; - border-left: 0; - } - .like-button.voted { - color: blue; - } - .dislike-button.voted { - color: red; - } - .actionbar-text { - padding-left: 0.4em; - } - .bookmarked { - color: rgb(180, 180, 7); - } -} - -.show_more_comment { - margin-left: -20px; -} - -.pagedown-image-upload { - .submit-input { - display: flex; - min-width: inherit; - float: right; - } - .deletelink-box { - position: absolute; - top: 2px; - right: 1em; - } -} - -@media (max-width: 799px) { - .hide_texts_on_mobile .actionbar-text { - display: none; - } -} \ No newline at end of file diff --git a/resources/common.js b/resources/common.js index 2cf67b9..40c07a2 100644 --- a/resources/common.js +++ b/resources/common.js @@ -28,6 +28,46 @@ if (!String.prototype.endsWith) { }; } +// http://stackoverflow.com/a/1060034/1090657 +$(function () { + var hidden = 'hidden'; + + // Standards: + if (hidden in document) + document.addEventListener('visibilitychange', onchange); + else if ((hidden = 'mozHidden') in document) + document.addEventListener('mozvisibilitychange', onchange); + else if ((hidden = 'webkitHidden') in document) + document.addEventListener('webkitvisibilitychange', onchange); + else if ((hidden = 'msHidden') in document) + document.addEventListener('msvisibilitychange', onchange); + // IE 9 and lower: + else if ('onfocusin' in document) + document.onfocusin = document.onfocusout = onchange; + // All others: + else + window.onpageshow = window.onpagehide + = window.onfocus = window.onblur = onchange; + + function onchange(evt) { + var v = 'window-visible', h = 'window-hidden', evtMap = { + focus: v, focusin: v, pageshow: v, blur: h, focusout: h, pagehide: h + }; + + evt = evt || window.event; + if (evt.type in evtMap) + document.body.className = evtMap[evt.type]; + else + document.body.className = this[hidden] ? 'window-hidden' : 'window-visible'; + + if ('$' in window) + $(window).trigger('dmoj:' + document.body.className); + } + + // set the initial state (but only if browser supports the Page Visibility API) + if (document[hidden] !== undefined) + onchange({type: document[hidden] ? 'blur' : 'focus'}); +}); function register_toggle(link) { link.click(function () { @@ -44,11 +84,11 @@ function register_toggle(link) { }); } -function register_all_toggles() { +$(function register_all_toggles() { $('.toggle').each(function () { register_toggle($(this)); }); -}; +}); function featureTest(property, value, noPrefixes) { var prop = property + ':', @@ -81,6 +121,61 @@ window.fix_div = function (div, height) { }); }; +$(function () { + if (typeof window.orientation !== 'undefined') { + $(window).resize(function () { + var width = Math.max(document.documentElement.clientWidth, window.innerWidth || 0); + $('#viewport').attr('content', width > 480 ? 'initial-scale=1' : 'width=480'); + }); + } + + var $nav_list = $('#nav-list'); + $('#navicon').click(function (event) { + event.stopPropagation(); + $nav_list.toggle(); + if ($nav_list.is(':hidden')) + $(this).blur().removeClass('hover'); + else { + $(this).addClass('hover'); + $nav_list.find('li ul').css('left', $('#nav-list').width()).hide(); + } + }).hover(function () { + $(this).addClass('hover'); + }, function () { + $(this).removeClass('hover'); + }); + + $nav_list.find('li a .nav-expand').click(function (event) { + event.preventDefault(); + $(this).parent().siblings('ul').css('display', 'block'); + }); + + $nav_list.find('li a').each(function () { + if (!$(this).siblings('ul').length) + return; + $(this).on('contextmenu', function (event) { + event.preventDefault(); + }).on('taphold', function () { + $(this).siblings('ul').css('display', 'block'); + }); + }); + + $nav_list.click(function (event) { + event.stopPropagation(); + }); + + $('html').click(function () { + $nav_list.hide(); + }); + + $.ajaxSetup({ + beforeSend: function (xhr, settings) { + if (!(/^(GET|HEAD|OPTIONS|TRACE)$/.test(settings.type)) && !this.crossDomain) + xhr.setRequestHeader('X-CSRFToken', $.cookie('csrftoken')); + } + }); +}); + if (!Date.now) { Date.now = function () { return new Date().getTime(); @@ -88,7 +183,8 @@ if (!Date.now) { } function count_down(label) { - var end_time = new Date(label.attr('data-secs').replace(' ', 'T')); + var initial = parseInt(label.attr('data-secs')); + var start = Date.now(); function format(num) { var s = "0" + num; @@ -96,7 +192,7 @@ function count_down(label) { } var timer = setInterval(function () { - var time = Math.round((end_time - Date.now()) / 1000); + var time = Math.round(initial - (Date.now() - start) / 1000); if (time <= 0) { clearInterval(timer); setTimeout(function() { @@ -116,9 +212,8 @@ function count_down(label) { }, 1000); } -function register_time(elems, limit) { // in hours - if ('limit_time' in window) limit = window.limit_time; - else limit = limit || 300 * 24; +function register_time(elems, limit) { + limit = limit || 300; elems.each(function () { var outdated = false; var $this = $(this); @@ -130,7 +225,7 @@ function register_time(elems, limit) { // in hours if ($('body').hasClass('window-hidden')) return outdated = true; outdated = false; - if (moment().diff(time, 'hours') > limit) { + if (moment().diff(time, 'days') > limit) { $this.text(abs); return; } @@ -147,8 +242,17 @@ function register_time(elems, limit) { // in hours }); } +$(function () { + register_time($('.time-with-rel')); + + $('form').submit(function (evt) { + // Prevent multiple submissions of forms, see #565 + $("input[type='submit']").prop('disabled', true); + }); +}); + window.notification_template = { - icon: '/logo.svg' + icon: '/logo.png' }; window.notification_timeout = 5000; @@ -218,29 +322,14 @@ window.register_notify = function (type, options) { status_change(); }; -window.notify_clarification = function(msg) { - var message = `Problem ${msg.order} (${msg.problem__name}):\n` + msg.description; - alert(message); -} -window.register_contest_notification = function(url) { - function get_clarifications() { - $.get(url) - .fail(function() { - console.log("Fail to update clarification"); - }) - .done(function(data) { - for (i of data) { - window.notify_clarification(i); - } - if (data.status == 403) { - console.log("Fail to retrieve data"); - } - }) - } - get_clarifications(); - setInterval(get_clarifications, 60 * 1000); -} +$(function () { + // Close dismissable boxes + $("a.close").click(function () { + var $closer = $(this); + $closer.parent().fadeOut(200); + }); +}); $.fn.textWidth = function () { var html_org = $(this).html(); @@ -251,375 +340,7 @@ $.fn.textWidth = function () { return width; }; -function registerPopper($trigger, $dropdown) { - const popper = Popper.createPopper($trigger[0], $dropdown[0], { - placement: 'bottom-end', - modifiers: [ - { - name: 'offset', - options: { - offset: [0, 8], - }, - }, - ], - }); - $trigger.click(function(e) { - $dropdown.toggle(); - popper.update(); - }); - $dropdown.css("min-width", $trigger.width() + 'px'); - - $(document).on("click touchend", function(e) { - var target = $(e.target); - if (target.closest($trigger).length === 0 && target.closest($dropdown).length === 0) { - $dropdown.hide(); - } - }) -} - -function populateCopyButton() { - var copyButton; - $('pre code').each(function () { - var copyButton = $('', { - 'class': 'btn-clipboard', - 'data-clipboard-text': $(this).text(), - 'title': 'Click to copy' - }).append(''); - - if ($(this).parent().width() > 100) { - copyButton.append('Copy'); - } - - $(this).before($('
', {'class': 'copy-clipboard'}) - .append(copyButton)); - - $(copyButton.get(0)).mouseleave(function () { - $(this).attr('class', 'btn-clipboard'); - $(this).removeAttr('aria-label'); - }); - - var curClipboard = new Clipboard(copyButton.get(0)); - - curClipboard.on('success', function (e) { - e.clearSelection(); - showTooltip(e.trigger, 'Copied!'); - }); - - curClipboard.on('error', function (e) { - showTooltip(e.trigger, fallbackMessage(e.action)); - }); - }); -} - -function register_copy_clipboard($elements, callback) { - $elements.on('paste', function(event) { - const items = (event.clipboardData || event.originalEvent.clipboardData).items; - for (const index in items) { - const item = items[index]; - if (item.kind === 'file' && item.type.indexOf('image') !== -1) { - const blob = item.getAsFile(); - const formData = new FormData(); - formData.append('image', blob); - - $(this).prop('disabled', true); - - $.ajax({ - url: '/pagedown/image-upload/', - type: 'POST', - data: formData, - processData: false, - contentType: false, - success: function(data) { - // Assuming the server returns the URL of the image - const imageUrl = data.url; - const editor = $(event.target); // Get the textarea where the event was triggered - let currentMarkdown = editor.val(); - const markdownImageText = '![](' + imageUrl + ')'; // Markdown for an image - - if (currentMarkdown) currentMarkdown += "\n"; - currentMarkdown += markdownImageText; - - editor.val(currentMarkdown); - callback?.(); - }, - error: function() { - alert('There was an error uploading the image.'); - }, - complete: () => { - // Re-enable the editor - $(this).prop('disabled', false).focus(); - } - }); - - // We only handle the first image in the clipboard data - break; - } - } - }); -} - -function activateBlogBoxOnClick() { - $('.blog-box').on('click', function () { - var $description = $(this).children('.blog-description'); - var max_height = $description.css('max-height'); - if (max_height !== 'fit-content') { - $description.css('max-height', 'fit-content'); - $(this).css('cursor', 'auto'); - $(this).removeClass('pre-expand-blog'); - $(this).children().children('.show-more').hide(); - } - }); - - $('.blog-box').each(function () { - var $precontent = $(this).children('.blog-description').height(); - var $content = $(this).children().children('.content-description').height(); - if ($content == undefined) { - $content = $(this).children().children('.md-typeset').height() - } - if ($content > $precontent - 30) { - $(this).addClass('pre-expand-blog'); - $(this).css('cursor', 'pointer'); - } else { - $(this).children().children('.show-more').hide(); - } - }); -} - -function changeTabParameter(newTab) { - const url = new URL(window.location); - const searchParams = new URLSearchParams(url.search); - searchParams.set('tab', newTab); - searchParams.delete('page'); - url.search = searchParams.toString(); - return url.href; -} - -function submitFormWithParams($form, method) { - const currentUrl = new URL(window.location.href); - const searchParams = new URLSearchParams(currentUrl.search); - const formData = $form.serialize(); - - const params = new URLSearchParams(formData); - - if (searchParams.has('tab')) { - params.set('tab', searchParams.get('tab')); - } - - const fullUrl = currentUrl.pathname + '?' + params.toString(); - - if (method === "GET") { - window.location.href = fullUrl; - } - else { - var $formToSubmit = $('
') - .attr('action', fullUrl) - .attr('method', 'POST') - .appendTo('body'); - - $formToSubmit.append($('').attr({ - type: 'hidden', - name: 'csrfmiddlewaretoken', - value: $.cookie('csrftoken') - })); - - $formToSubmit.submit(); - } -} - -function initPagedown(maxRetries=5) { - // There's a race condition so we want to retry several times - let attempts = 0; - - function tryInit() { - try { - // make sure pagedown_init.js was loaded - if ('DjangoPagedown' in window) { - DjangoPagedown.init(); - } else if (attempts < maxRetries) { - attempts++; - setTimeout(tryInit, 1000); - } - } catch (error) { - // this may happen if Markdown.xyz.js was not loaded - if (attempts < maxRetries) { - attempts++; - setTimeout(tryInit, 1000); - } - } - } - - setTimeout(tryInit, 100); -} - -function navigateTo(url, reload_container, force_new_page=false) { - if (url === '#') return; - if (force_new_page) { - window.location.href = url; - return; - } - - if (!reload_container || !$(reload_container).length) { - reload_container = "#content"; - } - - if (window.currentRequest) { - window.currentRequest.abort(); - } - - const controller = new AbortController(); - const signal = controller.signal; - window.currentRequest = controller; - - $(window).off("scroll"); - - replaceLoadingPage(reload_container); - - const toUpdateElements = [ - "#nav-container", - "#js_media", - "#media", - ".left-sidebar", - "#bodyend", - ]; - - $.ajax({ - url: url, - method: 'GET', - dataType: 'html', - signal: signal, - success: function (data) { - let reload_content = $(data).find(reload_container).first(); - if (!reload_content.length) { - reload_container = "#content"; - reload_content = $(data).find(reload_container).first(); - } - - if (reload_content.length) { - window.history.pushState("", "", url); - $(window).scrollTop(0); - $("#loading-bar").stop(true, true); - $("#loading-bar").hide().css({ width: 0}); - - for (let elem of toUpdateElements) { - $(elem).replaceWith($(data).find(elem).first()); - } - - $(reload_container).replaceWith(reload_content); - - $(document).prop('title', $(data).filter('title').text()); - renderKatex($(reload_container)[0]); - initPagedown(); - onWindowReady(); - registerNavList(); - $('.xdsoft_datetimepicker').hide(); - } else { - window.location.href = url; - } - }, - error: function (xhr, status, error) { - if (status !== 'abort') { // Ignore aborted requests - window.location.href = url; - } - } - }); -} - -function isEligibleLinkToRegister($e) { - if ($e.attr('target') === '_blank') { - return false; - } - if ($e.data('initialized_navigation')) { - return false; - } - const href = $e.attr('href'); - if (!href) return false; - return ( - href.startsWith('http') - || href.startsWith('/') - || href.startsWith('#') - || href.startsWith('?') - ); -}; - -function replaceLoadingPage(reload_container) { - const loadingPage = ` -
- -
- `; - $(reload_container).fadeOut(100, function() { - $(this).html(loadingPage).fadeIn(100); - }); -} - -function registerNavigation() { - const containerMap = { - '.left-sidebar-item': '.middle-right-content', - '.pagination li a': '.middle-content', - '.tabs li a': '.middle-content', - '#control-panel a': '.middle-content', - }; - - $.each(containerMap, function(selector, target) { - $(selector).each(function() { - const href = $(this).attr('href'); - const force_new_page = $(this).data('force_new_page'); - - if (isEligibleLinkToRegister($(this))) { - $(this).data('initialized_navigation', true); - - $(this).on('click', function(e) { - e.preventDefault(); - let containerSelector = null; - for (let key in containerMap) { - if ($(this).is(key)) { - containerSelector = containerMap[key]; - break; - } - } - navigateTo(href, containerSelector, force_new_page); - }); - } - }); - }); -} - -function onWindowReady() { - // http://stackoverflow.com/a/1060034/1090657 - var hidden = 'hidden'; - - // Standards: - if (hidden in document) - document.addEventListener('visibilitychange', onchange); - else if ((hidden = 'mozHidden') in document) - document.addEventListener('mozvisibilitychange', onchange); - else if ((hidden = 'webkitHidden') in document) - document.addEventListener('webkitvisibilitychange', onchange); - else if ((hidden = 'msHidden') in document) - document.addEventListener('msvisibilitychange', onchange); - // IE 9 and lower: - else if ('onfocusin' in document) - document.onfocusin = document.onfocusout = onchange; - // All others: - else - window.onpageshow = window.onpagehide - = window.onfocus = window.onblur = onchange; - - function onchange(evt) { - var v = 'window-visible', h = 'window-hidden', evtMap = { - focus: v, focusin: v, pageshow: v, blur: h, focusout: h, pagehide: h - }; - - evt = evt || window.event; - if (evt.type in evtMap) - document.body.className = evtMap[evt.type]; - else - document.body.className = this[hidden] ? 'window-hidden' : 'window-visible'; - - if ('$' in window) - $(window).trigger('dmoj:' + document.body.className); - } - +$(function () { $('.tabs').each(function () { var $this = $(this), $h2 = $(this).find('h2'), $ul = $(this).find('ul'); var cutoff = ($h2.textWidth() || 400) + 20, handler; @@ -631,124 +352,4 @@ function onWindowReady() { }); handler(); }); - - // set the initial state (but only if browser supports the Page Visibility API) - if (document[hidden] !== undefined) - onchange({type: document[hidden] ? 'blur' : 'focus'}); - - $("a.close").click(function () { - var $closer = $(this); - $closer.parent().fadeOut(200); - }); - - register_time($('.time-with-rel')); - - if (typeof window.orientation !== 'undefined') { - $(window).resize(function () { - var width = Math.max(document.documentElement.clientWidth, window.innerWidth || 0); - // $('#viewport').attr('content', width > 480 ? 'initial-scale=1' : 'width=480'); - }); - } - - $.ajaxSetup({ - beforeSend: function (xhr, settings) { - if (!(/^(GET|HEAD|OPTIONS|TRACE)$/.test(settings.type)) && !this.crossDomain) - xhr.setRequestHeader('X-CSRFToken', $.cookie('csrftoken')); - } - }); - - register_copy_clipboard($('textarea.wmd-input')); - - $('form').submit(function (evt) { - // Prevent multiple submissions of forms, see #565 - $("input[type='submit']").prop('disabled', true); - }); - - $('.lang-dropdown-item').click(function() { - $('select[name="language"]').val($(this).attr('value')); - $('#form-lang').submit(); - }) - $('#logout').on('click', () => $('#logout-form').submit()); - - populateCopyButton(); - - $('a').click(function() { - var href = $(this).attr('href'); - var target = $(this).attr('target'); - if (!href || href === '#' || href.startsWith("javascript") || - $(this).attr("data-featherlight") || - target === "_blank" - ) { - return; - } - - $("#loading-bar").show(); - $("#loading-bar").animate({ width: "100%" }, 2000, function() { - $(this).stop(true, true); - $(this).hide().css({ width: 0}); - }); - }); - - $('.errorlist').each(function() { - var errorList = $(this); - errorList.nextAll('input, select, textarea').first().after(errorList); - }); - register_all_toggles(); - activateBlogBoxOnClick(); - registerNavigation(); - registerPopper($('#nav-lang-icon'), $('#lang-dropdown')); - registerPopper($('#user-links'), $('#userlink_dropdown')); -} - -function registerNavList() { - var $nav_list = $('#nav-list'); - $('#navicon').click(function (event) { - event.stopPropagation(); - $nav_list.toggle(); - if ($nav_list.is(':hidden')) - $(this).blur().removeClass('hover'); - else { - $(this).addClass('hover'); - $nav_list.find('li ul').css('left', $('#nav-list').width()).hide(); - } - }).hover(function () { - $(this).addClass('hover'); - }, function () { - $(this).removeClass('hover'); - }); - - $nav_list.find('li a .nav-expand').click(function (event) { - event.preventDefault(); - $(this).parent().siblings('ul').css('display', 'block'); - }); - - $nav_list.find('li a').each(function () { - if (!$(this).siblings('ul').length) - return; - $(this).on('contextmenu', function (event) { - event.preventDefault(); - }).on('taphold', function () { - $(this).siblings('ul').css('display', 'block'); - }); - }); - - $nav_list.click(function (event) { - event.stopPropagation(); - }); - - $('html').click(function () { - $nav_list.hide(); - }); -} - -$(function() { - if (typeof window.currentRequest === 'undefined') { - window.currentRequest = null; - } - onWindowReady(); - registerNavList(); - - window.addEventListener('popstate', (e) => { - window.location.href = e.currentTarget.location.href; - }); -}); \ No newline at end of file +}); diff --git a/resources/content-description.scss b/resources/content-description.scss index 4b475f5..44ef8d2 100644 --- a/resources/content-description.scss +++ b/resources/content-description.scss @@ -1,19 +1,80 @@ @import "vars"; .content-description { - line-height: 1.6em; - font-size: 16px; - font-family: "Segoe UI", "Noto Sans", Arial, "Lucida Grande", sans-serif; - overflow-wrap: anywhere; + line-height: 1.5em; + font-size: 1em; + font-family: "Segoe UI", "Lucida Grande", Arial, sans-serif; - h1, h2, h3, h4, h5, .admonition-title, summary { - font-family: "Noto Sans", "Segoe UI", Arial, "Lucida Grande", sans-serif; + p { + margin: 1em 0 !important; + padding: 0 !important; } + img { max-width: 100%; height: auto; } + h1, h2, h3, h4, h5, h6 { + font-weight: normal; + color: #111; + margin-bottom: 0.75em; + padding: 0; + background: 0; + } + + h3, h4, h5, h6 { + font-weight: bold; + } + + h1 { + font-size: 2.5em; + } + + h2 { + font-size: 2em; + } + + h3 { + font-size: 1.6em; + margin: 0; + padding: 0; + } + + h4 { + font-size: 1.4em; + border-bottom: 1px solid #EEE; + line-height: 1.225; + padding-bottom: 0.3em; + padding-top: 0.5em; + } + + h5 { + font-size: 1.15em; + margin-top: 0; + } + + h6 { + font-size: 0.9em; + } + + blockquote { + color: #666; + margin: 0; + padding-left: 1.5em; + border-left: 0.5em #EEE solid; + } + + hr { + display: block; + height: 0; + border: 0; + font-style: italic; + border-bottom: 1px solid $border_gray; + margin: 25px 0 20px 0; + padding: 0; + } + pre, code, kbd, samp, span.code { color: #000; page-break-inside: avoid; @@ -25,9 +86,11 @@ font-family: $monospace-fonts !important; margin: 0 2px; padding: 0 5px; - background-color: var(--md-code-bg-color); + border: 1px solid $border_gray; + background-color: #f8f8f8; border-radius: $widget_border_radius; - color: var(--md-code-fg-color); + font-size: 0.95em; + color: #444; } pre { @@ -38,28 +101,17 @@ padding: 0; background: transparent; font-size: 1em; - color: var(--md-code-fg-color); - + color: black; } white-space: pre-wrap; word-wrap: break-word; - padding: 0.5em 1em; - background-color: var(--md-code-bg-color); - color: var(--md-code-fg-color); - border-radius: 3px; - } - - pre.no-border { - margin-top: 0.4em; - padding: 0.5em; - border: none; - background-color: inherit; - border-radius: none; - } - - .linenos pre { - padding-right: 0; + margin: 1.5em 0 1.5em 0; + padding: 1em; + border: 1px solid $border_gray; + background-color: #f8f8f8; + color: black; + border-radius: $widget_border_radius; } b, strong { @@ -132,53 +184,7 @@ margin-right: auto; } -.codehilitetable { - pre { - padding: 0.5em; - padding-right: 0; - background-color: hsla(0,0%,92.5%,.5); - } - - .linenos { - width: 4%; - - pre { - color: rgba(0,0,0,.26); - background-color: rgba(0,0,0,.07); - width: 100%; - border-right: 0; - - span { - margin-left: 0.4em; - } - } - } - - .code { - padding-left: 0.2em; - - pre { - padding-left: 1em; - border-top-left-radius: 0; - border-bottom-left-radius: 0; - } - } - - width: 100%; -} - -textarea, -pre { - -moz-tab-size : 4; - -o-tab-size : 4; - tab-size : 4; -} - - -@media (min-width: 800px) { - .content-description pre:has(code) { - min-width: 3em; - } +@media (min-width: 700px) { #common-content { display: flex; flex-direction: row-reverse; @@ -189,7 +195,7 @@ pre { width: 100%; &.split-common-content { - width: 70%; + max-width: 86%; } .content-description { @@ -214,7 +220,7 @@ pre { } } -@media not all and (min-width: 800px) { +@media not all and (min-width: 700px) { #content-right .info-float { float: none; width: 100% !important; @@ -223,13 +229,6 @@ pre { } } -@media (max-width: 799px) { - .content-description { - font-size: 16px; - line-height: 1.7em; - } -} - a.view-pdf { padding-top: 0.6em; display: inline-block; @@ -240,7 +239,6 @@ a.view-pdf { display: -webkit-flex; display: -ms-flexbox; display: flex; - align-items: center; .spacer { display: inline-block; @@ -258,6 +256,3 @@ a.view-pdf { margin-left: 1.3em; } } -details summary { - cursor: pointer; -} diff --git a/resources/contest.json b/resources/contest.json deleted file mode 100644 index 7f7f91b..0000000 --- a/resources/contest.json +++ /dev/null @@ -1,470 +0,0 @@ -{ - "problem_sub":[6, 3, 3], - "sub_frozen":[6, 3, 3], - "problems":{ - "1":{ - "1":30, - "2":10, - "3":11, - "4":17, - "5":10, - "6":22 - }, - "2":{ - "1":20, - "2":45, - "3":35 - }, - "3":{ - "1":50, - "2":15, - "3":35 - } - }, - "users":{ - "1":{ - "username":"user1", - "name":"Nguyen Van AA", - "school":"School A", - "last_submission":13, - "problems":{ - "1":{ - "points":{ - "1":-1, - "2":-1, - "3":-1, - "4":-1, - "5":-1, - "6":0 - }, - "frozen_points":{ - "1":0, - "2":0, - "3":0, - "4":0, - "5":0, - "6":0 - } - }, - "2":{ - "points":{ - "1":20, - "2":1, - "3":0 - }, - "frozen_points":{ - "1":20, - "2":0, - "3":0 - } - }, - "3":{ - "points":{ - "1":30, - "2":15, - "3":0 - }, - "frozen_points":{ - "1":29, - "2":0, - "3":0 - } - } - } - }, - "2":{ - "username":"user2", - "name":"Nguyen Van AB", - "school":"School B", - "last_submission":37, - "problems":{ - "1":{ - "points":{ - "1":-1, - "2":-1, - "3":-1, - "4":-1, - "5":-1, - "6":0 - }, - "frozen_points":{ - "1":0, - "2":4, - "3":5, - "4":0, - "5":7, - "6":0 - } - }, - "2":{ - "points":{ - "1":0, - "2":21, - "3":35 - }, - "frozen_points":{ - "1":0, - "2":1, - "3":0 - } - }, - "3":{ - "points":{ - "1":50, - "2":15, - "3":19 - }, - "frozen_points":{ - "1":45, - "2":1, - "3":1 - } - } - } - }, - "3":{ - "username":"user3", - "name":"Nguyen Van AC", - "school":"School C", - "last_submission":21, - "problems":{ - "1":{ - "points":{ - "1":14, - "2":7, - "3":0, - "4":17, - "5":10, - "6":22 - }, - "frozen_points":{ - "1":5, - "2":5, - "3":0, - "4":1, - "5":10, - "6":4 - } - }, - "3":{ - "points":{ - "1":-1, - "2":15, - "3":35 - }, - "frozen_points":{ - "1":50, - "2":15, - "3":35 - } - } - } - }, - "4":{ - "username":"user4", - "name":"Nguyen Van AD", - "school":"School D", - "last_submission":79, - "problems":{ - "1":{ - "points":{ - "1":30, - "2":10, - "3":3, - "4":17, - "5":4, - "6":10 - }, - "frozen_points":{ - "1":19, - "2":8, - "3":0, - "4":17, - "5":2, - "6":7 - } - }, - "2":{ - "points":{ - "1":20, - "2":45, - "3":35 - }, - "frozen_points":{ - "1":20, - "2":45, - "3":35 - } - }, - "3":{ - "points":{ - "1":50, - "2":15, - "3":35 - }, - "frozen_points":{ - "1":50, - "2":9, - "3":11 - } - } - } - }, - "5":{ - "username":"user5", - "name":"Nguyen Van AE", - "school":"School E", - "last_submission":36, - "problems":{ - "1":{ - "points":{ - "1":30, - "2":7, - "3":11, - "4":17, - "5":10, - "6":1 - }, - "frozen_points":{ - "1":3, - "2":7, - "3":0, - "4":1, - "5":10, - "6":0 - } - }, - "2":{ - "points":{ - "1":20, - "2":45, - "3":0 - }, - "frozen_points":{ - "1":11, - "2":0, - "3":0 - } - }, - "3":{ - "points":{ - "1":15, - "2":15, - "3":35 - }, - "frozen_points":{ - "1":3, - "2":10, - "3":15 - } - } - } - }, - "6":{ - "username":"user6", - "name":"Nguyen Van AF", - "school":"School F", - "last_submission":17, - "problems":{ - } - }, - "7":{ - "username":"user7", - "name":"Nguyen Van AG", - "school":"School G", - "last_submission":91, - "problems":{ - "1":{ - "points":{ - "1":28, - "2":1, - "3":11, - "4":17, - "5":6, - "6":22 - }, - "frozen_points":{ - "1":7, - "2":0, - "3":1, - "4":9, - "5":1, - "6":7 - } - }, - "2":{ - "points":{ - "1":20, - "2":45, - "3":24 - }, - "frozen_points":{ - "1":20, - "2":13, - "3":0 - } - }, - "3":{ - "points":{ - "1":29, - "2":13, - "3":35 - }, - "frozen_points":{ - "1":10, - "2":0, - "3":35 - } - } - } - }, - "8":{ - "username":"user8", - "name":"Nguyen Van AH", - "school":"School H", - "last_submission":60, - "problems":{ - } - }, - "9":{ - "username":"user9", - "name":"Nguyen Van AI", - "school":"School I", - "last_submission":89, - "problems":{ - "1":{ - "points":{ - "1":17, - "2":10, - "3":1, - "4":17, - "5":5, - "6":13 - }, - "frozen_points":{ - "1":0, - "2":10, - "3":0, - "4":3, - "5":4, - "6":11 - } - } - } - }, - "10":{ - "username":"user10", - "name":"Nguyen Van AJ", - "school":"School J", - "last_submission":10, - "problems":{ - "1":{ - "points":{ - "1":30, - "2":7, - "3":5, - "4":0, - "5":7, - "6":17 - }, - "frozen_points":{ - "1":12, - "2":1, - "3":0, - "4":0, - "5":3, - "6":0 - } - }, - "2":{ - "points":{ - "1":20, - "2":45, - "3":35 - }, - "frozen_points":{ - "1":20, - "2":0, - "3":35 - } - }, - "3":{ - "points":{ - "1":50, - "2":0, - "3":35 - }, - "frozen_points":{ - "1":12, - "2":0, - "3":31 - } - } - } - }, - "11":{ - "username":"user11", - "name":"Nguyen Van AK", - "school":"School K", - "last_submission":61, - "problems":{ - "1":{ - "points":{ - "1":30, - "2":10, - "3":11, - "4":17, - "5":10, - "6":0 - }, - "frozen_points":{ - "1":26, - "2":7, - "3":0, - "4":14, - "5":2, - "6":0 - } - }, - "2":{ - "points":{ - "1":20, - "2":45, - "3":23 - }, - "frozen_points":{ - "1":12, - "2":45, - "3":1 - } - } - } - }, - "12":{ - "username":"user12", - "name":"Nguyen Van AL", - "school":"School L", - "last_submission":49, - "problems":{ - "1":{ - "points":{ - "1":30, - "2":10, - "3":0, - "4":17, - "5":0, - "6":1 - }, - "frozen_points":{ - "1":19, - "2":1, - "3":0, - "4":10, - "5":0, - "6":0 - } - } - } - } - } -} diff --git a/resources/contest.scss b/resources/contest.scss index 30cbca5..a48bfb8 100644 --- a/resources/contest.scss +++ b/resources/contest.scss @@ -1,30 +1,5 @@ @import "vars"; -.list-contest { - box-shadow: 0px 1px 2px lightgrey, 0px 1px 5px lightgrey; - border-radius: 15px; - padding: 20px; - margin-bottom: 20px; - width: 100%; - box-sizing: border-box; - display: flex; - background: white; - - .info-contest:first-child, .info-contest:nth-child(2) { - margin-right: 15px; - } - - .info-contest { - flex: 1; - } - - .contest-title { - font-size: 1.1em; - font-weight: 600; - margin-bottom: 5px; - } -} - #contest-calendar { border-collapse: collapse; width: 100%; @@ -116,6 +91,7 @@ } #banner { + border-bottom: 1px solid rgba(0, 0, 0, 0.2); padding-bottom: 1em; a.date { @@ -123,7 +99,7 @@ text-decoration: none; text-align: center; line-height: 1.3; - font-size: 2em; + font-size: 2.3em; padding-bottom: 0.15em; &:link, &:visited { @@ -135,7 +111,7 @@ } } - .time { + #time { text-align: center; display: block; color: rgb(85, 85, 85); @@ -143,85 +119,89 @@ } } -.time-left { - text-align: left; - padding-bottom: 0.5em; -} +.contest-list { + td { + vertical-align: middle !important; + + &:nth-child(2) { + min-width: 4em; + } + + &:nth-child(3) { + min-width: 6em; + } + } + + tbody tr { + height: 4em; + } + + .floating-time-left { + position: absolute; + left: 0; + } + + .floating-time-right { + position: absolute; + right: 0; + line-height: 1.2em; + } + + .floating-time { + position: absolute; + right: 0; + bottom: 0; + } -.list-contest { .contest-tags { + padding-left: 0.75em; vertical-align: top; - display: flex; - flex-wrap: wrap; - margin-top: 5px; } - .contest-tag-hidden { - background-color: #000000; - color: #ffffff; + .participate-button { + display: inline-block; + width: 90px; } -} -.first-solve { - background: #00f9a1; + .contest-block { + text-align: left; + padding: 0.5em 0.5em 0.5em 1em; + } } .contest-tag { + box-shadow: inset 0 -0.1em 0 rgba(0, 0, 0, 0.12); padding: 0.15em 0.3em; border-radius: 0.15em; font-weight: 600; margin-right: 0.45em; position: relative; - display: flex; - align-items: center; - gap: 0.2em; -} - -.contest-tag-edit { - background-color: green -} - -.contest-tag-private { - background-color: #666666; - color: #ffffff; -} - -.contest-tag-org { - background-color: #cccccc; - - a { - color: #000000; - } -} - -.contest-tag-rated { - background-color: #e54c14; - color: #ffffff; } .contest-list-title { - font-size: 1.1em; + font-size: 18px; font-weight: 600; } -.contest-list-sort { - color: #7dc7ff; -} - form.contest-join-pseudotab { display: inline; + padding: 6px 8px !important; line-height: 1.7em; - margin-left: auto; - float: right; + margin-left: 0.5em; + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; input { - padding-left: 5px !important; - padding-right: 5px !important; + display: inline; + border: none; + padding: 0; + background: none; + font-weight: 600; } } .contest-participation-operation { - margin-left: auto; + float: right; .fa { color: #444; @@ -231,14 +211,5 @@ form.contest-join-pseudotab { padding-left: 1px; } - padding-left: 5px; -} - -#add-clarification { - float: left; - color: chartreuse; -} - -#add-clarification:hover { - color: cyan; + padding: 0 5px; } diff --git a/resources/course.scss b/resources/course.scss deleted file mode 100644 index f7c5b2d..0000000 --- a/resources/course.scss +++ /dev/null @@ -1,155 +0,0 @@ -@import "vars"; - -.course-content-title { - font-weight: bold; -} - -.course-list { - width: 100%; - margin: 0 auto; - list-style: none; - padding: 0; - - .course-item { - display: flex; - align-items: center; - border: 1px solid #ddd; - padding: 20px; - margin-bottom: 10px; - border-radius: 8px; - background-color: #fff; - box-shadow: 0 4px 6px rgba(0,0,0,0.1); - transition: transform 0.2s ease-in-out; - } - .course-item:hover { - transform: translateY(-2px); - box-shadow: 0 6px 12px rgba(0,0,0,0.15); - } - .course-image { - flex: 0 0 auto; - width: 50px; - height: 50px; - margin-right: 20px; - border-radius: 5px; - overflow: hidden; - } - .course-image img { - width: 100%; - height: 100%; - object-fit: cover; - border-radius: 5px; - } - .course-content { - flex: 1; - } - .course-name { - font-size: 1.5em; - margin-bottom: 5px; - } -} - -.lesson-list { - list-style: none; - padding: 0; - - li:hover { - box-shadow: 0 6px 12px rgba(0,0,0,0.15); - background: #ffffe0; - } - - li { - background: #fff; - border: 1px solid #ddd; - margin-bottom: 20px; - padding-top: 10px; - border-radius: 5px; - box-shadow: 0 2px 4px #ccc; - } - .lesson-title { - font-size: 1.25em; - margin-left: 1em; - margin-right: 1em; - color: initial; - display: flex; - gap: 1em; - - .lesson-points { - margin-left: auto; - font-size: 0.9em; - align-self: flex-end; - color: #636363; - } - } - .progress-container { - background: #e0e0e0; - border-radius: 3px; - height: 10px; - width: 100%; - margin-top: 10px; - } - .progress-bar { - background: forestgreen; - height: 10px; - border-radius: 3px; - line-height: 10px; - color: white; - text-align: right; - font-size: smaller; - } -} - -.course-problem-list { - list-style-type: none; - padding: 0; - font-size: 15px; - - i { - font-size: large; - } - - li { - display: flex; - align-items: center; - justify-content: space-between; - border-bottom: 1px solid #eee; - padding: 10px; - border-radius: 5px; - } - .problem-name { - margin-left: 10px; - } - - li:hover { - background: #e0e0e0; - } - .score { - font-weight: bold; - margin-left: auto; - } - a { - text-decoration: none; - color: inherit; - } -} - -.course-contest-card { - border: 1px solid #ddd; - border-radius: 8px; - margin-bottom: 20px; - padding: 15px; - box-shadow: 2px 2px 10px rgba(0, 0, 0, 0.1); - display: flex; - justify-content: space-between; - align-items: center; - - h5 { - margin: 0 0 10px; - font-size: 1.2em; - color: #333; - } - - p { - margin: 5px 0; - color: #555; - } -} \ No newline at end of file diff --git a/resources/darkmode-svg.css b/resources/darkmode-svg.css deleted file mode 100644 index 7a01444..0000000 --- a/resources/darkmode-svg.css +++ /dev/null @@ -1,25 +0,0 @@ -/* Add css `style="filter:invert(100%)"` for all , then use btoa to convert in js */ -.wmd-latex-button-display { - background-image: url("data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMTAwMCAxMDAwIiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCAxMDAwIDEwMDAiIHhtbDpzcGFjZT0icHJlc2VydmUiPgo8bWV0YWRhdGE+IFN2ZyBWZWN0b3IgSWNvbnMgOiBodHRwOi8vd3d3Lm9ubGluZXdlYmZvbnRzLmNvbS9pY29uIDwvbWV0YWRhdGE+CjxnPjxwYXRoIHN0eWxlPSJmaWx0ZXI6aW52ZXJ0KDEwMCUpIiBkPSJNMTk1LjMsNDI1LjZsLTAuNi04Ny44aDEyOS44bDgtNTguMWM2LjYtNjUuNCwyOC43LTEyNS44LDY2LjQtMTgxLjJDNDM2LjUsNDMsNDk5LjEsMTMuNSw1ODYuNywxMGM0MC4yLDEuOSw2OS45LDguMyw4OS4yLDE5LjFsLTIxLDgxLjRjLTE5LjUtOC00Mi4yLTEyLjItNjguMi0xMi42Yy00NC4xLDEuNS03Ny4xLDE5LTk5LDUyLjdjLTIxLjgsMzMuNy0zNS4yLDc0LjYtNDAsMTIyLjhsLTgsNjQuNGgxNDkuNnY4Ny44SDQyMy40bC0zMS4xLDI3My45Yy05LDg4LjUtMzAuMiwxNTguNy02My43LDIxMC43Yy0zMy41LDUyLTg3LjQsNzguNi0xNjEuOCw3OS44Yy00NC4xLTAuOS03Ny44LTguMy0xMDEuMS0yMi4zbDIwLjctODEuNmMyMS42LDEwLjMsNDUuOCwxNS4yLDcyLjYsMTQuOGMzOS40LTAuMiw2OC41LTE4LjIsODcuMi01NGMxOC43LTM1LjgsMzEuNS04OCwzOC42LTE1Ni43bDI5LjgtMjY0LjVIMTk1LjN6IE02ODEuMSw3MTguNmwtMTIuNS02MS44bC0xMy4zLTU1LjNMNjQ0LDU2Ny45bC0xMi42LTExLjdsLTYuNywxLjhsLTE1LDE0LjFsLTIxLjMsMzEuNEw1NDQsNTg2LjJjMTYuOS0yNy40LDMzLjItNDcuOSw0OC44LTYxLjVjMTUuNi0xMy41LDM0LTIwLjMsNzMuMy0yMC4zbDM4LjgsMTEuNmwyMy43LDQwLjhsOS45LDQwbDUuNiwzMy43TDgyNSw1MjcuMWM5LjItOC4zLDE4LTE0LjIsMjYuNC0xNy42YzguNC0zLjQsMTkuNi01LjEsMzMuNy01LjFjMy4xLDAsNDEuMiwxLjUsNDkuMyw0LjZsLTE2LjEsNjkuNkg5MDBoLTEwaC0xOC4yYy0xLTYuNS0zLTExLjEtNi4yLTEzLjhsLTcuMyw0bC0xNy4yLDE2LjRsLTgxLjgsMTAyLjlsMTMuOCw2Ny41bDExLjUsNDcuM2w4LjgsMjkuOWw4LjMsMTYuNGwxMS4yLDguMmMzLjktMS41LDcuNy0zLjksMTEuNS03LjJjNi44LTYsMTYuNy0xOS41LDI5LjYtNDAuNmw0NC40LDE3LjNjLTE4LjcsMzAtMzUuNyw1MS4xLTUwLjksNjMuNGMtMTUuMiwxMi4zLTMzLjMsMTguNC01NC4yLDE4LjRjLTMsMC0zOS42LTIuMS00Ny43LTYuM2MtOC00LjItMTUtMTAuOS0yMS0yMC4yYy01LjktOS4yLTExLjItMjMuNi0xNS43LTQzLjFjLTYuMS0yNS41LTEwLjUtNDYuNi0xMy4xLTYzLjRMNjEwLDg4NmMtOSw4LjUtMTcuNywxNC40LTI2LjIsMTcuOGMtOC41LDMuNC0xOS43LDUuMS0zMy43LDUuMWMtMy4xLDAtNDEuMS0xLjUtNDkuMi00LjZsMTYuMS02OS42aDQ2LjVjMC45LDYuNSwzLDExLjEsNi4xLDEzLjhsMS43LTAuNGwxNy45LTE1LjFMNjgxLjEsNzE4LjZ6Ii8+PC9nPgo8L3N2Zz4="); -} -.wmd-link-button { - background-image: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjxzdmcgaWQ9IkxheWVyXzIiIHZlcnNpb249IjEuMSIgdmlld0JveD0iMCAwIDMyIDMyIiB4bWw6c3BhY2U9InByZXNlcnZlIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIj48Zz48cGF0aCBzdHlsZT0iZmlsdGVyOmludmVydCgxMDAlKSIgZD0iTTIxLjAzOTg2LDAuNTAzM2MtMi43OTY0NSwwLTUuNDIyNjEsMS4wODUyNy03LjM5NDksMy4wNTgxMUwxMi4xMTkyLDUuMDg3NTkgICBjLTAuMzY2MTUsMC4zNjYxNS0wLjU2NzI2LDAuODUyNTQtMC41NjcyNiwxLjM3MDA2YzAsMC41MTg1NSwwLjIwMTU0LDEuMDA0ODgsMC41Njc3NSwxLjM3MDEyICAgYzAuNzMyNzksMC43MzIzNiwyLjAwODczLDAuNzMyMzYsMi43NDA2LDBsMS41MjUyNy0xLjUyNjE4YzIuNTY2MS0yLjU2NTEyLDYuNzQyMDctMi41NjQyMSw5LjMwODE3LDAgICBjMS4yNDUxOCwxLjI0NTE4LDEuOTMwNjYsMi44OTgxMywxLjkzMDY2LDQuNjU0M2MwLDEuNzU2MS0wLjY4NTk3LDMuNDA5MTItMS45MzExNSw0LjY1NDNsLTEuNTI1NzYsMS41MjYxOCAgIGMtMC4zNjYxNSwwLjM2NjIxLTAuNTY3MiwwLjg1MjU0LTAuNTY3MiwxLjM3MDEyYzAsMC41MTg0OSwwLjIwMTU0LDEuMDA0ODIsMC41Njc2OSwxLjM3MDA2ICAgYzAuMzY2MjEsMC4zNjYxNSwwLjg1MjU0LDAuNTY3NjksMS4zNzAxMiwwLjU2NzY5YzAuNTE3NTIsMCwxLjAwNDMzLTAuMjAxNTQsMS4zNzA1NC0wLjU2NzY5bDEuNTI1MjctMS41MjYxOCAgIEMzMC40MTA5NSwxNi4zNzI4LDMxLjUsMTMuNzQ3MTMsMzEuNSwxMC45NTU4N3MtMS4wODkwNS01LjQxNjkzLTMuMDY2MS03LjM5NDQ3QzI2LjQ2MjA0LDEuNTg4NTYsMjMuODM2MzYsMC41MDMzLDIxLjAzOTg2LDAuNTAzMyAgIHoiLz48cGF0aCBzdHlsZT0iZmlsdGVyOmludmVydCgxMDAlKSIgZD0iTTEwLjk1MTYsMzEuNDk2NjRjMi43OTYwMiwwLDUuNDIyMTItMS4wODYxOCw3LjM5NDk2LTMuMDU4MDRsMS41MjU3LTEuNTI2MTggICBjMC4zNjYyMS0wLjM2NjIxLDAuNTY3MjYtMC44NTI1NCwwLjU2NzI2LTEuMzcwMTJjMC0wLjUxODQ5LTAuMjAxNTQtMS4wMDQ4Mi0wLjU2NzY5LTEuMzcwMDYgICBjLTAuNzMyODUtMC43MzMzNC0yLjAwODc5LTAuNzMxNDUtMi43NDA2NiwwbC0xLjUyNTI3LDEuNTI2MThjLTIuNTY0MTUsMi41NjYwNC02Ljc0MDY2LDIuNTY3MDItOS4zMDg1OSwwICAgYy0yLjU2NjA0LTIuNTY2MDQtMi41NjYwNC02Ljc0MjU1LDAtOS4zMDg1OWwxLjUyNjE4LTEuNTI2MjVjMC43NTU1NS0wLjc1NSwwLjc1NTU1LTEuOTg1MTEsMC0yLjc0MDExICAgYy0wLjc1NTA3LTAuNzU1MDctMS45ODUxMS0wLjc1NTA3LTIuNzQwMTcsMGwtMS41MjYxOCwxLjUyNjE4Yy00LjA3NjE3LDQuMDc3MTUtNC4wNzYxNywxMC43MTE3OSwwLDE0Ljc4ODk0ICAgQzUuNTI4OTksMzAuNDEwNDYsOC4xNTUxNSwzMS40OTY2NCwxMC45NTE2LDMxLjQ5NjY0eiIvPjxwYXRoIHN0eWxlPSJmaWx0ZXI6aW52ZXJ0KDEwMCUpIiBkPSJNOS40MTY0NCwyMi41Nzk3N2MwLjM2NjE1LDAuMzY2MjEsMC44NTI0OCwwLjU2Nzc1LDEuMzcwMDYsMC41Njc3NWMwLjUxODA3LDAsMS4wMDQ4Mi0wLjIwMTU0LDEuMzcwMDYtMC41Njc3NSAgIGwxMC40MTg1Mi0xMC40MTk0M2MwLjM2NjE1LTAuMzY2MTUsMC41Njc2OS0wLjg1MjQ4LDAuNTY3NjktMS4zNzAwNnMtMC4yMDE1NC0xLjAwMzkxLTAuNTY3NjktMS4zNzAxMiAgIGMtMC43MzE4Ny0wLjczMjM2LTIuMDA5MjItMC43MzIzNi0yLjc0MDE3LDBMOS40MTY0NCwxOS44Mzk2Yy0wLjM2NjIxLDAuMzY2MjEtMC41Njc3NSwwLjg1MjU0LTAuNTY3NzUsMS4zNzAxMiAgIFM5LjA1MDIzLDIyLjIxMzYyLDkuNDE2NDQsMjIuNTc5Nzd6Ii8+PC9nPjwvc3ZnPg=="); -} -.wmd-code-button { - background-image: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pjxzdmcgdmlld0JveD0iMCAwIDY0MCA1MTIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggc3R5bGU9ImZpbHRlcjppbnZlcnQoMTAwJSkiIGQ9Ik00MTYgMzEuOTRDNDE2IDIxLjc1IDQwOC4xIDAgMzg0LjEgMGMtMTMuOTggMC0yNi44NyA5LjA3Mi0zMC44OSAyMy4xOGwtMTI4IDQ0OGMtLjg0MDQgMi45MzUtMS4yNDEgNS44OTItMS4yNDEgOC44MDFDMjIzLjEgNDkwLjMgMjMyIDUxMiAyNTYgNTEyYzEzLjkyIDAgMjYuNzMtOS4xNTcgMzAuNzUtMjMuMjJsMTI4LTQ0OEM0MTUuNiAzNy44MSA0MTYgMzQuODUgNDE2IDMxLjk0ek0xNzYgMTQzLjFjMC0xOC4yOC0xNC45NS0zMi0zMi0zMmMtOC4xODggMC0xNi4zOCAzLjEyNS0yMi42MiA5LjM3NmwtMTEyIDExMkMzLjEyNSAyMzkuNiAwIDI0Ny44IDAgMjU1LjFTMy4xMjUgMjcyLjQgOS4zNzUgMjc4LjZsMTEyIDExMkMxMjcuNiAzOTYuOSAxMzUuOCAzOTkuMSAxNDQgMzk5LjFjMTcuMDUgMCAzMi0xMy43MyAzMi0zMmMwLTguMTg4LTMuMTI1LTE2LjM4LTkuMzc1LTIyLjYzTDc3LjI1IDI1NS4xbDg5LjM4LTg5LjM4QzE3Mi45IDE2MC4zIDE3NiAxNTIuMiAxNzYgMTQzLjF6TTY0MCAyNTUuMWMwLTguMTg4LTMuMTI1LTE2LjM4LTkuMzc1LTIyLjYzbC0xMTItMTEyQzUxMi40IDExNS4xIDUwNC4yIDExMS4xIDQ5NiAxMTEuMWMtMTcuMDUgMC0zMiAxMy43My0zMiAzMmMwIDguMTg4IDMuMTI1IDE2LjM4IDkuMzc1IDIyLjYzbDg5LjM4IDg5LjM4bC04OS4zOCA4OS4zOEM0NjcuMSAzNTEuNiA0NjQgMzU5LjggNDY0IDM2Ny4xYzAgMTguMjggMTQuOTUgMzIgMzIgMzJjOC4xODggMCAxNi4zOC0zLjEyNSAyMi42Mi05LjM3NmwxMTItMTEyQzYzNi45IDI3Mi40IDY0MCAyNjQuMiA2NDAgMjU1LjF6Ii8+PC9zdmc+"); -} -.wmd-image-button { - background-image: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjxzdmcgaGVpZ2h0PSIxOHB4IiB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCAxOCAxOCIgd2lkdGg9IjE4cHgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6c2tldGNoPSJodHRwOi8vd3d3LmJvaGVtaWFuY29kaW5nLmNvbS9za2V0Y2gvbnMiIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIj48dGl0bGUvPjxkZXNjLz48ZGVmcy8+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiBpZD0iUGFnZS0xIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSI+PGcgZmlsbD0iIzAwMDAwMCIgaWQ9IkNvcmUiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0xNzEuMDAwMDAwLCAtMTcxLjAwMDAwMCkiPjxnIGlkPSJkcml2ZS1pbWFnZSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTcxLjAwMDAwMCwgMTcxLjAwMDAwMCkiPjxwYXRoIHN0eWxlPSJmaWx0ZXI6aW52ZXJ0KDEwMCUpIiBkPSJNMTgsMTYgTDE4LDIgQzE4LDAuOSAxNy4xLDAgMTYsMCBMMiwwIEMwLjksMCAwLDAuOSAwLDIgTDAsMTYgQzAsMTcuMSAwLjksMTggMiwxOCBMMTYsMTggQzE3LjEsMTggMTgsMTcuMSAxOCwxNiBMMTgsMTYgWiBNNS41LDEwLjUgTDgsMTMuNSBMMTEuNSw5IEwxNiwxNSBMMiwxNSBMNS41LDEwLjUgTDUuNSwxMC41IFoiIGlkPSJTaGFwZSIvPjwvZz48L2c+PC9nPjwvc3ZnPg=="); -} -.wmd-heading-button { - background-image: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjxzdmcgaGVpZ2h0PSIxNzkyIiB2aWV3Qm94PSIwIDAgMTc5MiAxNzkyIiB3aWR0aD0iMTc5MiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBzdHlsZT0iZmlsdGVyOmludmVydCgxMDAlKSIgZD0iTTE2ODIgMTY2NHEtNDQgMC0xMzIuNS0zLjV0LTEzMy41LTMuNXEtNDQgMC0xMzIgMy41dC0xMzIgMy41cS0yNCAwLTM3LTIwLjV0LTEzLTQ1LjVxMC0zMSAxNy00NnQzOS0xNyA1MS03IDQ1LTE1cTMzLTIxIDMzLTE0MGwtMS0zOTFxMC0yMS0xLTMxLTEzLTQtNTAtNGgtNjc1cS0zOCAwLTUxIDQtMSAxMC0xIDMxbC0xIDM3MXEwIDE0MiAzNyAxNjQgMTYgMTAgNDggMTN0NTcgMy41IDQ1IDE1IDIwIDQ1LjVxMCAyNi0xMi41IDQ4dC0zNi41IDIycS00NyAwLTEzOS41LTMuNXQtMTM4LjUtMy41cS00MyAwLTEyOCAzLjV0LTEyNyAzLjVxLTIzIDAtMzUuNS0yMXQtMTIuNS00NXEwLTMwIDE1LjUtNDV0MzYtMTcuNSA0Ny41LTcuNSA0Mi0xNXEzMy0yMyAzMy0xNDNsLTEtNTd2LTgxM3EwLTMgLjUtMjZ0MC0zNi41LTEuNS0zOC41LTMuNS00Mi02LjUtMzYuNS0xMS0zMS41LTE2LTE4cS0xNS0xMC00NS0xMnQtNTMtMi00MS0xNC0xOC00NXEwLTI2IDEyLTQ4dDM2LTIycTQ2IDAgMTM4LjUgMy41dDEzOC41IDMuNXE0MiAwIDEyNi41LTMuNXQxMjYuNS0zLjVxMjUgMCAzNy41IDIydDEyLjUgNDhxMCAzMC0xNyA0My41dC0zOC41IDE0LjUtNDkuNSA0LTQzIDEzcS0zNSAyMS0zNSAxNjBsMSAzMjBxMCAyMSAxIDMyIDEzIDMgMzkgM2g2OTlxMjUgMCAzOC0zIDEtMTEgMS0zMmwxLTMyMHEwLTEzOS0zNS0xNjAtMTgtMTEtNTguNS0xMi41dC02Ni0xMy0yNS41LTQ5LjVxMC0yNiAxMi41LTQ4dDM3LjUtMjJxNDQgMCAxMzIgMy41dDEzMiAzLjVxNDMgMCAxMjktMy41dDEyOS0zLjVxMjUgMCAzNy41IDIydDEyLjUgNDhxMCAzMC0xNy41IDQ0dC00MCAxNC41LTUxLjUgMy00NCAxMi41cS0zNSAyMy0zNSAxNjFsMSA5NDNxMCAxMTkgMzQgMTQwIDE2IDEwIDQ2IDEzLjV0NTMuNSA0LjUgNDEuNSAxNS41IDE4IDQ0LjVxMCAyNi0xMiA0OHQtMzYgMjJ6Ii8+PC9zdmc+"); -} -.wmd-undo-button { - background-image: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjxzdmcgaGVpZ2h0PSI0OHB4IiBpZD0ic3ZnMTEzMDAiIHdpZHRoPSI0OHB4IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIiB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+PGRlZnMgaWQ9ImRlZnMzIj48bGluZWFyR3JhZGllbnQgaWQ9ImxpbmVhckdyYWRpZW50MjMyNiI+PHN0b3AgaWQ9InN0b3AyMzI4IiBvZmZzZXQ9IjAiIHN0eWxlPSJzdG9wLWNvbG9yOiNmZmZmZmY7c3RvcC1vcGFjaXR5OjE7Ii8+PHN0b3AgaWQ9InN0b3AyMzMwIiBvZmZzZXQ9IjEiIHN0eWxlPSJzdG9wLWNvbG9yOiNmZmZmZmY7c3RvcC1vcGFjaXR5OjA7Ii8+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9ImxpbmVhckdyYWRpZW50MjMxNiI+PHN0b3AgaWQ9InN0b3AyMzE4IiBvZmZzZXQ9IjAiIHN0eWxlPSJzdG9wLWNvbG9yOiNjNGEwMDA7c3RvcC1vcGFjaXR5OjE7Ii8+PHN0b3AgaWQ9InN0b3AyMzIwIiBvZmZzZXQ9IjEiIHN0eWxlPSJzdG9wLWNvbG9yOiNjNGEwMDA7c3RvcC1vcGFjaXR5OjA7Ii8+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9ImxpbmVhckdyYWRpZW50MjMwOCI+PHN0b3AgaWQ9InN0b3AyMzEwIiBvZmZzZXQ9IjAiIHN0eWxlPSJzdG9wLWNvbG9yOiNlZGQ0MDA7c3RvcC1vcGFjaXR5OjE7Ii8+PHN0b3AgaWQ9InN0b3AyMzEyIiBvZmZzZXQ9IjEiIHN0eWxlPSJzdG9wLWNvbG9yOiNlZGQ0MDA7c3RvcC1vcGFjaXR5OjA7Ii8+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9ImxpbmVhckdyYWRpZW50ODY2MiI+PHN0b3AgaWQ9InN0b3A4NjY0IiBvZmZzZXQ9IjAiIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDAwMDA7c3RvcC1vcGFjaXR5OjE7Ii8+PHN0b3AgaWQ9InN0b3A4NjY2IiBvZmZzZXQ9IjEiIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDAwMDA7c3RvcC1vcGFjaXR5OjA7Ii8+PC9saW5lYXJHcmFkaWVudD48cmFkaWFsR3JhZGllbnQgY3g9IjI0LjgzNzEyNiIgY3k9IjM2LjQyMTEyNyIgZng9IjI0LjgzNzEyNiIgZnk9IjM2LjQyMTEyNyIgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxLjAwMDAwMCwwLjAwMDAwMCwwLjAwMDAwMCwwLjUzNjcyMywtNi4yMjcyNjVlLTE0LDE2Ljg3MzA2KSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIGlkPSJyYWRpYWxHcmFkaWVudDg2NjgiIHI9IjE1LjY0NDczNyIgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50ODY2MiIvPjxsaW5lYXJHcmFkaWVudCBpZD0ibGluZWFyR3JhZGllbnQyMTg3Ij48c3RvcCBpZD0ic3RvcDIxODkiIG9mZnNldD0iMCIgc3R5bGU9InN0b3AtY29sb3I6I2ZmZmZmZjtzdG9wLW9wYWNpdHk6MTsiLz48c3RvcCBpZD0ic3RvcDIxOTEiIG9mZnNldD0iMSIgc3R5bGU9InN0b3AtY29sb3I6I2ZmZmZmZjtzdG9wLW9wYWNpdHk6MDsiLz48L2xpbmVhckdyYWRpZW50PjxsaW5lYXJHcmFkaWVudCBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KC0xLjgxMzQ3MWUtMTYsLTEuMTcxOTI2LC0xLjE3MTkyNiwxLjgxMzQ3MWUtMTYsNDYuMTc0NDAsNTQuMTAxMTEpIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgaWQ9ImxpbmVhckdyYWRpZW50MTc2NCIgeDE9IjE3LjA2MDgwNiIgeDI9IjEyLjYyNDMzNyIgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50MjE4NyIgeTE9IjExLjM5NTAyIiB5Mj0iMTIuNTgzNzY5Ii8+PGxpbmVhckdyYWRpZW50IGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiBpZD0ibGluZWFyR3JhZGllbnQyMzE0IiB4MT0iMjYuNSIgeDI9IjI2LjI1IiB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQyMzA4IiB5MT0iMzQuMjUiIHkyPSI0My41NzE4MzEiLz48bGluZWFyR3JhZGllbnQgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIGlkPSJsaW5lYXJHcmFkaWVudDIzMjIiIHgxPSIyNi41IiB4Mj0iMjYuMjUiIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDIzMTYiIHkxPSIzNC4yNSIgeTI9IjQzLjU3MTgzMSIvPjxyYWRpYWxHcmFkaWVudCBjeD0iMTUuMDk0MDMiIGN5PSIxMy4yODI3MjEiIGZ4PSIxNS4wOTQwMyIgZnk9IjEzLjI4MjcyMSIgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgyLjQ5NjAzMSwtMS4xNTE5MDVlLTE2LDEuMDYxNzU2ZS0xNiwyLjMwMDY4OSwtMjUuMTI0MDIsLTE3LjgyNjM2KSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIGlkPSJyYWRpYWxHcmFkaWVudDIzMzIiIHI9IjEwLjE2NDY2IiB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQyMzI2Ii8+PC9kZWZzPjxnIGlkPSJsYXllcjEiPjxwYXRoIGQ9Ik0gNDAuNDgxODYzIDM2LjQyMTEyNyBBIDE1LjY0NDczNyA4LjM5Njg5MzUgMCAxIDEgIDkuMTkyMzg4NSwzNi40MjExMjcgQSAxNS42NDQ3MzcgOC4zOTY4OTM1IDAgMSAxICA0MC40ODE4NjMgMzYuNDIxMTI3IHoiIGlkPSJwYXRoODY2MCIgc3R5bGU9ImludmVydDoxMDAlO29wYWNpdHk6MC4xNDExNzY0Nztjb2xvcjojMDAwMDAwO2ZpbGw6dXJsKCNyYWRpYWxHcmFkaWVudDg2NjgpO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDoxO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO21hcmtlcjpub25lO21hcmtlci1zdGFydDpub25lO21hcmtlci1taWQ6bm9uZTttYXJrZXItZW5kOm5vbmU7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MTt2aXNpYmlsaXR5OnZpc2libGU7ZGlzcGxheTppbmxpbmU7b3ZlcmZsb3c6dmlzaWJsZSIgdHJhbnNmb3JtPSJtYXRyaXgoLTEuNDg5NzM2LDAuMDAwMDAwLDAuMDAwMDAwLC0xLjAwMTI1Miw2MC42MDQzNiw3NS4zMTI2MCkiLz48cGF0aCBkPSJNIDkuNTgyNDQxLDQ1LjAzNDM2OSBDIDQ5LjYwODI0OSw0Ni4zNTU1MDkgNDMuMjgyNDA1LDEyLjI5MzU1IDIyLjQ2MjQxMSwxMi40OTc2NSBMIDIyLjQ2MjQxMSwzLjEyMjIzOTYgTCA1LjgxMzkyOTgsMTcuNzA4ODE5IEwgMjIuNDYyNDExLDMzLjAwNjM0OSBDIDIyLjQ2MjQxMSwzMy4wMDYzNDkgMjIuNDYyNDExLDIzLjMzNzk2OSAyMi40NjI0MTEsMjMuMzM3OTY5IEMgMzYuNTI1NTIxLDIyLjc1MTk5OSA0MC42Mzk5MzksNDQuNzcwNTQ5IDkuNTgyNDQxLDQ1LjAzNDM2OSB6ICIgaWQ9InBhdGgxNDMyIiBzdHlsZT0iaW52ZXJ0OjEwMCU7b3BhY2l0eToxO2NvbG9yOiMwMDAwMDA7ZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50MjMxNCk7ZmlsbC1vcGFjaXR5OjEuMDtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6dXJsKCNsaW5lYXJHcmFkaWVudDIzMjIpO3N0cm9rZS13aWR0aDoxLjAwMDAwMDEyO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO21hcmtlcjpub25lO21hcmtlci1zdGFydDpub25lO21hcmtlci1taWQ6bm9uZTttYXJrZXItZW5kOm5vbmU7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxO3Zpc2liaWxpdHk6dmlzaWJsZTtkaXNwbGF5OmJsb2NrO292ZXJmbG93OnZpc2libGUiLz48cGF0aCBkPSJNIDMxLjAzMjI4MSwzOS4zMTU1MTkgQyA0Mi43NTUzOCwzMy4yMzU4OTIgMzkuMjIwMDczLDEzLjA4NzQ4OSAyMS40NDg3MDEsMTMuNTQ5OTU5IEwgMjEuNDQ4NzAxLDUuNDUwODY3OCBDIDIxLjQ0ODcwMSw1LjQ1MDg2NzggNy40MDA5NjI4LDE3LjcxNDU4OSA3LjQwMDk2MjgsMTcuNzE0NTg5IEwgMjEuNDQ4NzAxLDMwLjY1ODYxNyBDIDIxLjQ0ODcwMSwzMC42NTg2MTcgMjEuNDQ4NzAxLDIyLjM4MDk3OSAyMS40NDg3MDEsMjIuMzgwOTc5IEMgMzYuMjg4NTUxLDIyLjAzMjcwOSAzNS42MDg2MTEsMzUuMTM4NTc5IDMxLjAzMjI4MSwzOS4zMTU1MTkgeiAiIGlkPSJwYXRoMjE3NyIgc3R5bGU9ImludmVydDoxMDAlO29wYWNpdHk6MC42OTg4NjM2MTtjb2xvcjojMDAwMDAwO2ZpbGw6bm9uZTtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6dXJsKCNsaW5lYXJHcmFkaWVudDE3NjQpO3N0cm9rZS13aWR0aDowLjk5OTk5OTc7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7bWFya2VyOm5vbmU7bWFya2VyLXN0YXJ0Om5vbmU7bWFya2VyLW1pZDpub25lO21hcmtlci1lbmQ6bm9uZTtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxO3Zpc2liaWxpdHk6dmlzaWJsZTtkaXNwbGF5OmJsb2NrO292ZXJmbG93OnZpc2libGUiLz48cGF0aCBkPSJNIDYuNjI5MTI2MSwxNy42ODI3OTcgTCAxMi4yODU5OCwyMy4wNzQ0ODYgQyAxOC41NjE1NTMsMjIuODk3NzA5IDE1LjczMzEyNiwxNi43MTA1MjUgMjYuOTU4NDQ2LDEzLjYxNjkzMyBMIDIyLjAwODY5OSwxMi45OTgyMTQgTCAyMS45MjAzMSw0LjMzNjE1NjIgTCA2LjYyOTEyNjEsMTcuNjgyNzk3IHogIiBpZD0icGF0aDIzMjQiIHN0eWxlPSJpbnZlcnQ6MTAwJTtvcGFjaXR5OjAuNTExMzYzNjQ7Y29sb3I6IzAwMDAwMDtmaWxsOnVybCgjcmFkaWFsR3JhZGllbnQyMzMyKTtmaWxsLW9wYWNpdHk6MS4wO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDoxO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO21hcmtlcjpub25lO21hcmtlci1zdGFydDpub25lO21hcmtlci1taWQ6bm9uZTttYXJrZXItZW5kOm5vbmU7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxO3Zpc2liaWxpdHk6dmlzaWJsZTtkaXNwbGF5OmlubGluZTtvdmVyZmxvdzp2aXNpYmxlIi8+PC9nPjwvc3ZnPg=="); -} -.wmd-redo-button { - background-image: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjxzdmcgaGVpZ2h0PSI0OHB4IiBpZD0ic3ZnMTEzMDAiIHdpZHRoPSI0OHB4IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIiB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+PGRlZnMgaWQ9ImRlZnMzIj48bGluZWFyR3JhZGllbnQgaWQ9ImxpbmVhckdyYWRpZW50MjI0MCI+PHN0b3AgaWQ9InN0b3AyMjQyIiBvZmZzZXQ9IjAiIHN0eWxlPSJzdG9wLWNvbG9yOiM5OWIwMGI7c3RvcC1vcGFjaXR5OjE7Ii8+PHN0b3AgaWQ9InN0b3AyMjQ0IiBvZmZzZXQ9IjEiIHN0eWxlPSJzdG9wLWNvbG9yOiM5OWIwMGI7c3RvcC1vcGFjaXR5OjA7Ii8+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9ImxpbmVhckdyYWRpZW50MjIzMiI+PHN0b3AgaWQ9InN0b3AyMjM0IiBvZmZzZXQ9IjAiIHN0eWxlPSJzdG9wLWNvbG9yOiM3ODg2MDA7c3RvcC1vcGFjaXR5OjE7Ii8+PHN0b3AgaWQ9InN0b3AyMjM2IiBvZmZzZXQ9IjEiIHN0eWxlPSJzdG9wLWNvbG9yOiM3ODg2MDA7c3RvcC1vcGFjaXR5OjA7Ii8+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9ImxpbmVhckdyYWRpZW50NDk5MSI+PHN0b3AgaWQ9InN0b3A0OTkzIiBvZmZzZXQ9IjAiIHN0eWxlPSJzdG9wLWNvbG9yOiNmZmZmZmY7c3RvcC1vcGFjaXR5OjE7Ii8+PHN0b3AgaWQ9InN0b3A0OTk1IiBvZmZzZXQ9IjEiIHN0eWxlPSJzdG9wLWNvbG9yOiNmZmZmZmY7c3RvcC1vcGFjaXR5OjA7Ii8+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9ImxpbmVhckdyYWRpZW50ODY2MiI+PHN0b3AgaWQ9InN0b3A4NjY0IiBvZmZzZXQ9IjAiIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDAwMDA7c3RvcC1vcGFjaXR5OjE7Ii8+PHN0b3AgaWQ9InN0b3A4NjY2IiBvZmZzZXQ9IjEiIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDAwMDA7c3RvcC1vcGFjaXR5OjA7Ii8+PC9saW5lYXJHcmFkaWVudD48cmFkaWFsR3JhZGllbnQgY3g9IjI0LjgzNzEyNiIgY3k9IjM2LjQyMTEyNyIgZng9IjI0LjgzNzEyNiIgZnk9IjM2LjQyMTEyNyIgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxLjAwMDAwMCwwLjAwMDAwMCwwLjAwMDAwMCwwLjUzNjcyMywtNS44MjUzMjllLTE0LDE2Ljg3MzA2KSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIGlkPSJyYWRpYWxHcmFkaWVudDg2NjgiIHI9IjE1LjY0NDczNyIgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50ODY2MiIvPjxsaW5lYXJHcmFkaWVudCBpZD0ibGluZWFyR3JhZGllbnQyMTg3Ij48c3RvcCBpZD0ic3RvcDIxODkiIG9mZnNldD0iMCIgc3R5bGU9InN0b3AtY29sb3I6I2ZmZmZmZjtzdG9wLW9wYWNpdHk6MTsiLz48c3RvcCBpZD0ic3RvcDIxOTEiIG9mZnNldD0iMSIgc3R5bGU9InN0b3AtY29sb3I6I2ZmZmZmZjtzdG9wLW9wYWNpdHk6MDsiLz48L2xpbmVhckdyYWRpZW50PjxsaW5lYXJHcmFkaWVudCBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDEuODEzNDcxZS0xNiwtMS4xNzE5MjYsMS4xNzE5MjYsMS44MTM0NzFlLTE2LDEuNzgyODAxLDU0LjEwMTExKSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIGlkPSJsaW5lYXJHcmFkaWVudDE3NjQiIHgxPSIxNy4wNjA4MDYiIHgyPSIxMi42MjQzMzciIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDIxODciIHkxPSIxMS4zOTUwMiIgeTI9IjEyLjU4Mzc2OSIvPjxyYWRpYWxHcmFkaWVudCBjeD0iMTYuNTYzODM3IiBjeT0iMTEuMTMyMjM2IiBmeD0iMTYuNTYzODM3IiBmeT0iMTEuMTMyMjM2IiBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KC0xLjI5MDEyN2UtMiwxLjY4NTE5NywxLjcxMzA4MiwxLjMxMTQ3NWUtMiwtMS4wNDE0OTksLTEwLjExNTcxKSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIGlkPSJyYWRpYWxHcmFkaWVudDQ5OTciIHI9IjE5LjA2MjUiIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDQ5OTEiLz48bGluZWFyR3JhZGllbnQgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIGlkPSJsaW5lYXJHcmFkaWVudDIyMzgiIHgxPSIzMyIgeDI9IjMxLjUiIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDIyMzIiIHkxPSIzNS43NSIgeTI9IjQyLjUiLz48bGluZWFyR3JhZGllbnQgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIGlkPSJsaW5lYXJHcmFkaWVudDIyNDYiIHgxPSIzMyIgeDI9IjMxLjUiIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDIyNDAiIHkxPSIzNS43NSIgeTI9IjQyLjUiLz48L2RlZnM+PGcgaWQ9ImxheWVyMSI+PHBhdGggZD0iTSA0MC40ODE4NjMgMzYuNDIxMTI3IEEgMTUuNjQ0NzM3IDguMzk2ODkzNSAwIDEgMSAgOS4xOTIzODg1LDM2LjQyMTEyNyBBIDE1LjY0NDczNyA4LjM5Njg5MzUgMCAxIDEgIDQwLjQ4MTg2MyAzNi40MjExMjcgeiIgaWQ9InBhdGg4NjYwIiBzdHlsZT0iZmlsdGVyOmludmVydCgxMDAlKTtvcGFjaXR5OjAuMTQxMTc2NDc7Y29sb3I6IzAwMDAwMDtmaWxsOnVybCgjcmFkaWFsR3JhZGllbnQ4NjY4KTtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MTtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjttYXJrZXI6bm9uZTttYXJrZXItc3RhcnQ6bm9uZTttYXJrZXItbWlkOm5vbmU7bWFya2VyLWVuZDpub25lO3N0cm9rZS1taXRlcmxpbWl0OjEwO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjE7dmlzaWJpbGl0eTp2aXNpYmxlO2Rpc3BsYXk6aW5saW5lO292ZXJmbG93OnZpc2libGUiIHRyYW5zZm9ybT0ibWF0cml4KDEuNDg5NzM2LDAuMDAwMDAwLDAuMDAwMDAwLC0xLjAwMTI1MiwtMTIuNjQ3MTYsNzUuMzEyNjApIi8+PHBhdGggZD0iTSAzOC4zNzQ3Niw0NS4wMzQzNjkgQyAtMS42NTEwNDg2LDQ2LjM1NTUwOSA0LjY3NDc5NTQsMTIuMjkzNTUgMjUuNDk0NzksMTIuNDk3NjUgTCAyNS40OTQ3OSwzLjEyMjIzOTYgTCA0Mi4xNDMyNzEsMTcuNzA4ODE5IEwgMjUuNDk0NzksMzMuMDA2MzQ5IEMgMjUuNDk0NzksMzMuMDA2MzQ5IDI1LjQ5NDc5LDIzLjMzNzk2OSAyNS40OTQ3OSwyMy4zMzc5NjkgQyAxMS40MzE2OCwyMi43NTE5OTkgNy4zMTcyNjE0LDQ0Ljc3MDU0OSAzOC4zNzQ3Niw0NS4wMzQzNjkgeiAiIGlkPSJwYXRoMTQzMiIgc3R5bGU9ImZpbHRlcjppbnZlcnQoMTAwJSk7b3BhY2l0eToxO2NvbG9yOiMwMDAwMDA7ZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50MjI0Nik7ZmlsbC1vcGFjaXR5OjEuMDtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6dXJsKCNsaW5lYXJHcmFkaWVudDIyMzgpO3N0cm9rZS13aWR0aDoxLjAwMDAwMDEyO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO21hcmtlcjpub25lO21hcmtlci1zdGFydDpub25lO21hcmtlci1taWQ6bm9uZTttYXJrZXItZW5kOm5vbmU7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxO3Zpc2liaWxpdHk6dmlzaWJsZTtkaXNwbGF5OmJsb2NrO292ZXJmbG93OnZpc2libGUiLz48cGF0aCBkPSJNIDE2LjkyNDkyLDM5LjMxNTUxOSBDIDUuMjAxODIwNCwzMy4yMzU4OTIgOC43MzcxMjc0LDEzLjA4NzQ4OSAyNi41MDg1LDEzLjU0OTk1OSBMIDI2LjUwODUsNS40NTA4Njc4IEMgMjYuNTA4NSw1LjQ1MDg2NzggNDAuNTU2MjM4LDE3LjcxNDU4OSA0MC41NTYyMzgsMTcuNzE0NTg5IEwgMjYuNTA4NSwzMC42NTg2MTcgQyAyNi41MDg1LDMwLjY1ODYxNyAyNi41MDg1LDIyLjM4MDk3OSAyNi41MDg1LDIyLjM4MDk3OSBDIDExLjY2ODY1LDIyLjAzMjcwOSAxMi4zNDg1OSwzNS4xMzg1NzkgMTYuOTI0OTIsMzkuMzE1NTE5IHogIiBpZD0icGF0aDIxNzciIHN0eWxlPSJmaWx0ZXI6aW52ZXJ0KDEwMCUpO29wYWNpdHk6MC42OTg4NjM2MTtjb2xvcjojMDAwMDAwO2ZpbGw6bm9uZTtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6dXJsKCNsaW5lYXJHcmFkaWVudDE3NjQpO3N0cm9rZS13aWR0aDowLjk5OTk5OTc7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7bWFya2VyOm5vbmU7bWFya2VyLXN0YXJ0Om5vbmU7bWFya2VyLW1pZDpub25lO21hcmtlci1lbmQ6bm9uZTtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxO3Zpc2liaWxpdHk6dmlzaWJsZTtkaXNwbGF5OmJsb2NrO292ZXJmbG93OnZpc2libGUiLz48cGF0aCBkPSJNIDI2LjAzNjk4OSw0LjU2ODYwOTUgTCAzNi43MjM3MjcsMTQuNzk4MjQxIEMgMjkuNzg2MjI3LDE0Ljc5ODI0IDMyLjAzNjk4OSwyMy43MzU0MjQgMjUuOTExOTg5LDI2LjYxMDQyNCBMIDI1Ljk3NDQ4OSwyMi45NDM2MDkgQyAxMC43ODY5ODksMjIuODgxMTA5IDExLjY2MTk4OSwzOC40NDM2MDkgMjIuNzI0NDg5LDQyLjY5MzYwOSBDIDMuNjM2MzQxNCwzNy44MTE2ODEgNi4yODY5OTA0LDEzLjM4MTEwOSAyNS45MTE5ODksMTIuODgxMTEgTCAyNi4wMzY5ODksNC41Njg2MDk1IHogIiBpZD0icGF0aDQ5ODkiIHN0eWxlPSJmaWx0ZXI6aW52ZXJ0KDEwMCUpO29wYWNpdHk6MC40OTQzMTgxNztjb2xvcjojMDAwMDAwO2ZpbGw6dXJsKCNyYWRpYWxHcmFkaWVudDQ5OTcpO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDowLjk5OTk5OTc7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7bWFya2VyOm5vbmU7bWFya2VyLXN0YXJ0Om5vbmU7bWFya2VyLW1pZDpub25lO21hcmtlci1lbmQ6bm9uZTtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxO3Zpc2liaWxpdHk6dmlzaWJsZTtkaXNwbGF5OmlubGluZTtvdmVyZmxvdzp2aXNpYmxlIi8+PC9nPjwvc3ZnPg=="); -} -.wmd-italic-button { - background-image: url("data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSJDYXBhXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IgogICB3aWR0aD0iNTI1LjE0MnB4IiBoZWlnaHQ9IjUyNS4xNDJweCIgdmlld0JveD0iMCAwIDUyNS4xNDIgNTI1LjE0MiIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNTI1LjE0MiA1MjUuMTQyOyIKICAgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+CjxnPgogIDxnPgogICAgPHBhdGggc3R5bGU9ImZpbHRlcjppbnZlcnQoMTAwJSkiIGQ9Ik0zNzUuNTQsMC4yNDRjLTEzLjMzNiwxLjY4OS0yNi44MywyLjg3LTQwLjQ5NiwzLjU1NmMtMTUuNzQxLDAuNzk2LTI3Ljk4NywxLjE4OC0zNi43MjcsMS4xODgKICAgICAgYy0xMC4wNjcsMC0yMi4wODctMC41MTQtMzYuMDcxLTEuNTc5Yy0xMi4yMjgtMC45MTgtMjUuMjgyLTIuMDUtMzkuMTYyLTMuMzc4Yy0zLjM2Ni0wLjMyNC02Ljk1OCwyLjAxNC03LjgwMyw1LjI4OAogICAgICBjLTEuMDUzLDQuMDg4LTEuNTczLDcuNDE4LTEuNTczLDkuOTc2YzAsNi44NzMsNC44MDQsMTEuMDk1LDE0LjQyNSwxMi42OGMxMi42ODEsMS41NzksMjAuNjYxLDUuMDI1LDIzLjk0MSwxMC4zMDYKICAgICAgYzMuMjgsNS4yODIsNC4wMzksMTIuNjc1LDIuMjk1LDIyLjE5MWwtNjQuMjY2LDQwMy4zOTRjLTEuNzU2LDEwLjA0My01LjQ3OCwxNy41NzYtMTEuMTU3LDIyLjU4OQogICAgICBjLTUuNjg2LDUuMDI0LTE0LjIxLDguNTk5LTI1LjU3NSwxMC42OTdjLTQuODE2LDEuMDY1LTcuOTg3LDIuNjYyLTkuNTA0LDQuNzU1Yy0xLjU0MiwyLjExOC0yLjI5NSw1LjI4Mi0yLjI5NSw5LjUxOAogICAgICBjMCwyLjU2MywwLjI0NSw1LjMyNCwwLjcyOCw4LjI4YzAuNTQ1LDMuMzM1LDMuOTY2LDUuNjk3LDcuMzI2LDUuMzU0YzEyLjc0OC0xLjMxLDI1LjI1Ny0yLjQyNCwzNy41MjgtMy4zMjkKICAgICAgYzE0LjE5OC0xLjA2NSwyNS42NzMtMS41NzksMzQuNDI1LTEuNTc5YzEwLjA1NSwwLDIyLjk1NywwLjUxNCwzOC42OTcsMS41NzljMTMuNzY0LDAuOTI0LDI3LjY4MSwyLjA1LDQxLjc4MSwzLjM4NAogICAgICBjMy4zNjYsMC4zMTgsNi43ODctMi4wNjgsNy4zMzItNS40MDNjMC40ODMtMi45NTYsMC43MjktNS43MSwwLjcyOS04LjI4YzAtNy4zOTQtNC4xNjItMTIuMTQ4LTEyLjQ2MS0xNC4yNzIKICAgICAgYy0xMS44MDYtMi42MzgtMTkuODk2LTUuOTQyLTI0LjI2Ni05LjkwMWMtNC4zNzYtMy45Ni01LjY4Ni0xMS4yMjUtMy45MzUtMjEuNzk0TDMzMi40MTgsNjIuMDUKICAgICAgYzEuNzM4LTEwLjU2Myw1LjEyOS0xOC4yMjUsMTAuMTY1LTIyLjk4YzUuMDE5LTQuNzU1LDEzLjY2LTguMTgyLDI1LjkwNi0xMC4zMDZjNi4xMi0xLjA1MywxMC4xNzItMi42MzgsMTIuMTMtNC43NTUKICAgICAgYzEuOTcxLTIuMTA1LDIuOTUtNS4yNzUsMi45NS05LjUxMWMwLTIuNjkzLTAuMjY0LTUuNzEtMC44MDItOS4wNTFDMzgyLjI0MSwyLjExMSwzNzguODk0LTAuMTg0LDM3NS41NCwwLjI0NHoiLz4KICA8L2c+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPC9zdmc+"); -} \ No newline at end of file diff --git a/resources/darkmode.css b/resources/darkmode.css deleted file mode 100644 index 81f4975..0000000 --- a/resources/darkmode.css +++ /dev/null @@ -1,3834 +0,0 @@ -/*! Dark reader generated CSS | Licensed under MIT https://github.com/darkreader/darkreader/blob/main/LICENSE */ - -/* User-Agent Style */ -@layer { -html { - background-color: #181a1b !important; -} -html { - color-scheme: dark !important; -} -iframe { - color-scheme: dark !important; -} -html, body, input, textarea, select, button, dialog { - background-color: #181a1b; -} -html, body, input, textarea, select, button { - border-color: #736b5e; - color: #e8e6e3; -} -a { - color: #3391ff; -} -table { - border-color: #545b5e; -} -mark { - color: #e8e6e3; -} -::placeholder { - color: #b2aba1; -} -input:-webkit-autofill, -textarea:-webkit-autofill, -select:-webkit-autofill { - background-color: #404400 !important; - color: #e8e6e3 !important; -} -* { - scrollbar-color: #454a4d #202324; -} -::selection { - background-color: #004daa !important; - color: #e8e6e3 !important; -} -::-moz-selection { - background-color: #004daa !important; - color: #e8e6e3 !important; -} -} - -/* Invert Style */ -.jfk-bubble.gtx-bubble, .captcheck_answer_label > input + img, span#closed_text > img[src^="https://www.gstatic.com/images/branding/googlelogo"], span[data-href^="https://www.hcaptcha.com/"] > #icon, img.Wirisformula { - filter: invert(100%) hue-rotate(180deg) contrast(90%) !important; -} - -/* Variables Style */ -:root { - --darkreader-neutral-background: #181a1b; - --darkreader-neutral-text: #e8e6e3; - --darkreader-selection-background: #004daa; - --darkreader-selection-text: #e8e6e3; -} - -/* Modified CSS */ -:root, -[data-md-color-scheme="default"] { - --darkreader-bg--md-accent-bg-color: #181a1b; - --darkreader-bg--md-accent-fg-color: #01189b; - --darkreader-bg--md-accent-fg-color--transparent: rgba(1, 24, 155, 0.1); - --darkreader-bg--md-admonition-bg-color: var(--darkreader-bg--md-default-bg-color); - --darkreader-bg--md-code-bg-color: #1e2021; - --darkreader-bg--md-code-hl-color: rgba(153, 153, 0, 0.5); - --darkreader-bg--md-default-bg-color: #181a1b; - --darkreader-bg--md-default-fg-color: rgba(0, 0, 0, 0.87); - --darkreader-bg--md-default-fg-color--light: rgba(0, 0, 0, 0.54); - --darkreader-bg--md-default-fg-color--lighter: rgba(0, 0, 0, 0.32); - --darkreader-bg--md-default-fg-color--lightest: rgba(0, 0, 0, 0.07); - --darkreader-bg--md-footer-bg-color: rgba(0, 0, 0, 0.87); - --darkreader-bg--md-footer-bg-color--dark: rgba(0, 0, 0, 0.32); - --darkreader-bg--md-primary-fg-color: #334191; - --darkreader-bg--md-primary-fg-color--dark: #263281; - --darkreader-bg--md-shadow-z1: 0 0.2rem 0.5rem rgba(0,0,0,.05),0 0 0.05rem rgba(0,0,0,.1); - --darkreader-bg--md-shadow-z2: 0 0.2rem 0.5rem rgba(0,0,0,.1),0 0 0.05rem rgba(0,0,0,.25); - --darkreader-bg--md-shadow-z3: 0 0.2rem 0.5rem rgba(0,0,0,.2),0 0 0.05rem rgba(0,0,0,.35); - --darkreader-bg--md-typeset-del-color: rgba(165, 25, 9, 0.15); - --darkreader-bg--md-typeset-ins-color: rgba(9, 170, 90, 0.15); - --darkreader-bg--md-typeset-kbd-accent-color: #181a1b; - --darkreader-bg--md-typeset-kbd-border-color: #404548; - --darkreader-bg--md-typeset-kbd-color: #1b1d1e; - --darkreader-bg--md-typeset-mark-color: rgba(153, 153, 0, 0.5); - --darkreader-border--md-accent-fg-color: #011899; - --darkreader-border--md-default-bg-color: #303436; - --darkreader-border--md-default-fg-color--light: rgba(140, 130, 115, 0.54); - --darkreader-border--md-default-fg-color--lighter: rgba(140, 130, 115, 0.32); - --darkreader-border--md-default-fg-color--lightest: rgba(140, 130, 115, 0.07); - --darkreader-border--md-primary-fg-color: #2f3c86; - --darkreader-border--md-typeset-table-color: rgba(140, 130, 115, 0.12); - --darkreader-text--md-accent-bg-color: #e8e6e3; - --darkreader-text--md-accent-fg-color: #539bfe; - --darkreader-text--md-admonition-fg-color: var(--darkreader-text--md-default-fg-color); - --darkreader-text--md-code-fg-color: #beb9b0; - --darkreader-text--md-code-hl-comment-color: var(--darkreader-text--md-default-fg-color--light); - --darkreader-text--md-code-hl-constant-color: #7561db; - --darkreader-text--md-code-hl-function-color: #b159c0; - --darkreader-text--md-code-hl-generic-color: var(--darkreader-text--md-default-fg-color--light); - --darkreader-text--md-code-hl-keyword-color: #518ecb; - --darkreader-text--md-code-hl-name-color: var(--darkreader-text--md-code-fg-color); - --darkreader-text--md-code-hl-number-color: #d93f3f; - --darkreader-text--md-code-hl-operator-color: var(--darkreader-text--md-default-fg-color--light); - --darkreader-text--md-code-hl-punctuation-color: var(--darkreader-text--md-default-fg-color--light); - --darkreader-text--md-code-hl-special-color: #ed3774; - --darkreader-text--md-code-hl-string-color: #7ee2b0; - --darkreader-text--md-code-hl-variable-color: var(--darkreader-text--md-default-fg-color--light); - --darkreader-text--md-default-bg-color: #e8e6e3; - --darkreader-text--md-default-fg-color: rgba(232, 230, 227, 0.87); - --darkreader-text--md-default-fg-color--light: rgba(232, 230, 227, 0.54); - --darkreader-text--md-default-fg-color--lighter: rgba(232, 230, 227, 0.32); - --darkreader-text--md-default-fg-color--lightest: rgba(232, 230, 227, 0.07); - --darkreader-text--md-footer-fg-color: #e8e6e3; - --darkreader-text--md-footer-fg-color--light: rgba(232, 230, 227, 0.7); - --darkreader-text--md-footer-fg-color--lighter: rgba(232, 230, 227, 0.3); - --darkreader-text--md-primary-bg-color: #e8e6e3; - --darkreader-text--md-primary-bg-color--light: rgba(232, 230, 227, 0.7); - --darkreader-text--md-primary-fg-color: #6d94cb; - --darkreader-text--md-typeset-a-color: var(--darkreader-text--md-primary-fg-color); - --md-accent-bg-color--light: hsla(0,0%,100%,.7); - --md-default-bg-color--light: hsla(0,0%,100%,.7); - --md-default-bg-color--lighter: hsla(0,0%,100%,.3); - --md-default-bg-color--lightest: hsla(0,0%,100%,.12); - --md-primary-fg-color--light: #5d6cc0; - --md-typeset-color: var(--md-default-fg-color); -} -.md-icon svg { - fill: currentcolor; -} -body { - --md-code-font-family: var(--md-code-font,_),SFMono-Regular,Consolas,Menlo,monospace; - --md-text-font-family: var(--md-text-font,_),-apple-system,BlinkMacSystemFont,Helvetica,Arial,sans-serif; -} -:root { - --darkreader-bgimg--md-typeset-table-sort-icon: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0ibTE4IDIxLTQtNGgzVjdoLTNsNC00IDQgNGgtM3YxMGgzTTIgMTl2LTJoMTB2Mk0yIDEzdi0yaDd2Mk0yIDdWNWg0djJIMloiLz48L3N2Zz4="); - --darkreader-bgimg--md-typeset-table-sort-icon--asc: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0iTTE5IDE3aDNsLTQgNC00LTRoM1YzaDJNMiAxN2gxMHYySDJNNiA1djJIMlY1bTAgNmg3djJIMnYtMloiLz48L3N2Zz4="); - --darkreader-bgimg--md-typeset-table-sort-icon--desc: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0iTTE5IDdoM2wtNC00LTQgNGgzdjE0aDJNMiAxN2gxMHYySDJNNiA1djJIMlY1bTAgNmg3djJIMnYtMloiLz48L3N2Zz4="); -} -.md-typeset h1 { - color: var(--darkreader-text--md-default-fg-color--light, #e8e6e3); -} -.md-typeset h5, -.md-typeset h6 { - color: var(--darkreader-text--md-default-fg-color--light, #e8e6e3); -} -.md-typeset hr { - border-bottom: .05rem solid var(--darkreader-border--md-default-fg-color--lightest); -} -.md-typeset code, -.md-typeset kbd, -.md-typeset pre { - color: var(--darkreader-text--md-code-fg-color, #e8e6e3); -} -.md-typeset kbd { - background-color: var(--darkreader-bg--md-typeset-kbd-color, #181a1b); - box-shadow: 0 .1rem 0 .05rem var(--darkreader-bg--md-typeset-kbd-border-color),0 .1rem 0 var(--darkreader-bg--md-typeset-kbd-border-color),0 -.1rem .2rem var(--darkreader-bg--md-typeset-kbd-accent-color) inset; - color: var(--darkreader-text--md-default-fg-color, #e8e6e3); -} -.md-typeset mark { - background-color: var(--darkreader-bg--md-typeset-mark-color, #181a1b); - color: inherit; -} -.md-typeset abbr { - border-bottom: .05rem dotted var(--darkreader-border--md-default-fg-color--light); - text-decoration-color: initial; -} -@media (hover: none) { - .md-typeset abbr[title]:-webkit-any(:focus, :hover)::after { - background-color: var(--darkreader-bg--md-default-fg-color, #181a1b); - box-shadow: var(--darkreader-bg--md-shadow-z3); - color: var(--darkreader-text--md-default-bg-color, #e8e6e3); - } - .md-typeset abbr[title]:is(:focus, :hover)::after { - background-color: var(--darkreader-bg--md-default-fg-color, #181a1b); - box-shadow: var(--darkreader-bg--md-shadow-z3); - color: var(--darkreader-text--md-default-bg-color, #e8e6e3); - } -} -.md-typeset blockquote { - border-left: .2rem solid var(--darkreader-border--md-default-fg-color--lighter); -} -[dir="rtl"] .md-typeset blockquote { - border-right: .2rem solid var(--darkreader-border--md-default-fg-color--lighter); -} -.md-typeset blockquote { - color: var(--darkreader-text--md-default-fg-color--light, #e8e6e3); -} -.md-typeset table:not([class]) { - background-color: var(--darkreader-bg--md-default-bg-color, #181a1b); - border: .05rem solid var(--darkreader-border--md-typeset-table-color); -} -.md-typeset table:not([class]) td { - border-top: .05rem solid var(--darkreader-border--md-typeset-table-color); -} -.md-typeset table:not([class]) tbody tr:hover { - background-color: rgba(0, 0, 0, 0.04); - box-shadow: 0 .05rem 0 var(--darkreader-bg--md-default-bg-color) inset; -} -.md-typeset table th[role="columnheader"]:hover::after { - background-color: var(--darkreader-bg--md-default-fg-color--lighter, #181a1b); -} -.md-typeset table th[role="columnheader"][aria-sort="ascending"]::after { - background-color: var(--darkreader-bg--md-default-fg-color--light, #181a1b); -} -.md-typeset table th[role="columnheader"][aria-sort="descending"]::after { - background-color: var(--darkreader-bg--md-default-fg-color--light, #181a1b); -} -.md-banner { - background-color: var(--darkreader-bg--md-footer-bg-color, #181a1b); - color: var(--darkreader-text--md-footer-fg-color, #e8e6e3); -} -.md-banner--warning { - background: var(--darkreader-bg--md-typeset-mark-color); - color: var(--darkreader-text--md-default-fg-color, #e8e6e3); -} -.md-banner__button { - color: inherit; -} -.md-option.focus-visible + label { - outline-color: var(--darkreader-border--md-accent-fg-color); -} -.md-skip { - background-color: var(--darkreader-bg--md-default-fg-color, #181a1b); - color: var(--darkreader-text--md-default-bg-color, #e8e6e3); - outline-color: var(--darkreader-border--md-accent-fg-color); -} -:root { - --darkreader-bgimg--md-clipboard-icon: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMTUwIiBoZWlnaHQ9IjE1MCI+PGRlZnM+PGZpbHRlciBpZD0iZGFya3JlYWRlci1pbWFnZS1maWx0ZXIiPjxmZUNvbG9yTWF0cml4IHR5cGU9Im1hdHJpeCIgdmFsdWVzPSIwLjI0OSAtMC42MTQgLTAuNjcyIDAuMDAwIDEuMDM1IC0wLjY0NiAwLjI4OCAtMC42NjQgMC4wMDAgMS4wMjAgLTAuNjM2IC0wLjYwOSAwLjI1MCAwLjAwMCAwLjk5NCAwLjAwMCAwLjAwMCAwLjAwMCAxLjAwMCAwLjAwMCIgLz48L2ZpbHRlcj48L2RlZnM+PGltYWdlIHdpZHRoPSIxNTAiIGhlaWdodD0iMTUwIiBmaWx0ZXI9InVybCgjZGFya3JlYWRlci1pbWFnZS1maWx0ZXIpIiB4bGluazpocmVmPSJkYXRhOmltYWdlL3N2Zyt4bWw7Y2hhcnNldD11dGYtOCwmbHQ7c3ZnIHhtbG5zPSZxdW90O2h0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnJnF1b3Q7IHZpZXdCb3g9JnF1b3Q7MCAwIDI0IDI0JnF1b3Q7Jmd0OyZsdDtwYXRoIGQ9JnF1b3Q7TTE5IDIxSDhWN2gxMW0wLTJIOGEyIDIgMCAwIDAtMiAydjE0YTIgMiAwIDAgMCAyIDJoMTFhMiAyIDAgMCAwIDItMlY3YTIgMiAwIDAgMC0yLTJtLTMtNEg0YTIgMiAwIDAgMC0yIDJ2MTRoMlYzaDEyVjFaJnF1b3Q7LyZndDsmbHQ7L3N2ZyZndDsiIC8+PC9zdmc+"); -} -.md-clipboard { - color: var(--darkreader-text--md-default-fg-color--lightest, #e8e6e3); - outline-color: var(--darkreader-border--md-accent-fg-color); -} -.md-clipboard:not(.focus-visible) { - -webkit-tap-highlight-color: transparent; - outline-color: initial; -} -:hover > .md-clipboard { - color: var(--darkreader-text--md-default-fg-color--light, #e8e6e3); -} -.md-clipboard:-webkit-any(:focus, :hover) { - color: var(--darkreader-text--md-accent-fg-color, #e8e6e3); -} -.md-clipboard:is(:focus, :hover) { - color: var(--darkreader-text--md-accent-fg-color, #e8e6e3); -} -.md-clipboard::after { - background-color: currentcolor; -} -.md-clipboard--inline:-webkit-any(:focus, :hover) code { - background-color: var(--darkreader-bg--md-accent-fg-color--transparent, #181a1b); - color: var(--darkreader-text--md-accent-fg-color, #e8e6e3); -} -.md-clipboard--inline:is(:focus, :hover) code { - background-color: var(--darkreader-bg--md-accent-fg-color--transparent, #181a1b); - color: var(--darkreader-text--md-accent-fg-color, #e8e6e3); -} -.md-consent__overlay { - background-color: rgba(0, 0, 0, 0.54); -} -.md-consent__inner { - background-color: var(--darkreader-bg--md-default-bg-color, #181a1b); - border-color: initial; - border-style: initial; - border-width: 0px; - box-shadow: rgba(0, 0, 0, 0.1) 0px 0px 0.2rem, rgba(0, 0, 0, 0.2) 0px 0.2rem 0.4rem; -} -.md-typeset .md-content__button { - color: var(--darkreader-text--md-default-fg-color--lighter, #e8e6e3); -} -.md-dialog { - background-color: var(--darkreader-bg--md-default-fg-color, #181a1b); - box-shadow: var(--darkreader-bg--md-shadow-z3); -} -.md-dialog__inner { - color: var(--darkreader-text--md-default-bg-color, #e8e6e3); -} -.md-feedback fieldset { - border-color: initial; - border-style: none; - border-width: initial; -} -.md-feedback__list:hover .md-icon:not(:disabled) { - color: var(--darkreader-text--md-default-fg-color--lighter, #e8e6e3); -} -.md-feedback__icon { - color: var(--darkreader-text--md-default-fg-color--light, #e8e6e3); -} -.md-feedback__icon:not(:disabled).md-icon:hover { - color: var(--darkreader-text--md-accent-fg-color, #e8e6e3); -} -.md-feedback__icon:disabled { - color: var(--darkreader-text--md-default-fg-color--lightest, #e8e6e3); -} -.md-footer { - background-color: var(--darkreader-bg--md-footer-bg-color, #181a1b); - color: var(--darkreader-text--md-footer-fg-color, #e8e6e3); -} -.md-footer__link { - outline-color: var(--darkreader-border--md-accent-fg-color); -} -.md-footer-meta { - background-color: var(--darkreader-bg--md-footer-bg-color--dark, #181a1b); -} -html .md-footer-meta.md-typeset a { - color: var(--darkreader-text--md-footer-fg-color--light, #e8e6e3); -} -html .md-footer-meta.md-typeset a:-webkit-any(:focus, :hover) { - color: var(--darkreader-text--md-footer-fg-color, #e8e6e3); -} -html .md-footer-meta.md-typeset a:is(:focus, :hover) { - color: var(--darkreader-text--md-footer-fg-color, #e8e6e3); -} -.md-copyright { - color: var(--darkreader-text--md-footer-fg-color--lighter, #e8e6e3); -} -.md-copyright__highlight { - color: var(--darkreader-text--md-footer-fg-color--light, #e8e6e3); -} -.md-social__link svg { - fill: currentcolor; -} -.md-typeset .md-button { - border-color: initial; - color: var(--darkreader-text--md-primary-fg-color, #e8e6e3); -} -.md-typeset .md-button--primary { - background-color: var(--darkreader-bg--md-primary-fg-color, #181a1b); - border-color: var(--darkreader-border--md-primary-fg-color); - color: var(--darkreader-text--md-primary-bg-color, #e8e6e3); -} -.md-typeset .md-button:-webkit-any(:focus, :hover) { - background-color: var(--darkreader-bg--md-accent-fg-color, #181a1b); - border-color: var(--darkreader-border--md-accent-fg-color); - color: var(--darkreader-text--md-accent-bg-color, #e8e6e3); -} -.md-typeset .md-button:is(:focus, :hover) { - background-color: var(--darkreader-bg--md-accent-fg-color, #181a1b); - border-color: var(--darkreader-border--md-accent-fg-color); - color: var(--darkreader-text--md-accent-bg-color, #e8e6e3); -} -.md-typeset .md-input { - border-bottom: .1rem solid var(--darkreader-border--md-default-fg-color--lighter); - box-shadow: var(--darkreader-bg--md-shadow-z1); -} -.md-typeset .md-input:-webkit-any(:focus, :hover) { - border-bottom-color: var(--darkreader-border--md-accent-fg-color); - box-shadow: var(--darkreader-bg--md-shadow-z2); -} -.md-typeset .md-input:is(:focus, :hover) { - border-bottom-color: var(--darkreader-border--md-accent-fg-color); - box-shadow: var(--darkreader-bg--md-shadow-z2); -} -.md-header { - background-color: var(--darkreader-bg--md-primary-fg-color, #181a1b); - box-shadow: rgba(0, 0, 0, 0) 0px 0px 0.2rem, rgba(0, 0, 0, 0) 0px 0.2rem 0.4rem; - color: var(--darkreader-text--md-primary-bg-color, #e8e6e3); -} -.md-header--shadow { - box-shadow: rgba(0, 0, 0, 0.1) 0px 0px 0.2rem, rgba(0, 0, 0, 0.2) 0px 0.2rem 0.4rem; -} -.md-header__button { - color: currentcolor; - outline-color: var(--darkreader-border--md-accent-fg-color); -} -.md-header__button:not(.focus-visible) { - -webkit-tap-highlight-color: transparent; - outline-color: initial; -} -.md-header__button.md-logo :-webkit-any(img, svg) { - fill: currentcolor; -} -.md-header__button.md-logo :is(img, svg) { - fill: currentcolor; -} -:root { - --darkreader-bgimg--md-nav-icon--next: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0iTTguNTkgMTYuNTggMTMuMTcgMTIgOC41OSA3LjQxIDEwIDZsNiA2LTYgNi0xLjQxLTEuNDJaIi8+PC9zdmc+"); - --darkreader-bgimg--md-nav-icon--prev: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0iTTIwIDExdjJIOGw1LjUgNS41LTEuNDIgMS40Mkw0LjE2IDEybDcuOTItNy45MkwxMy41IDUuNSA4IDExaDEyWiIvPjwvc3ZnPg=="); - --darkreader-bgimg--md-toc-icon: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0iTTMgOWgxNFY3SDN2Mm0wIDRoMTR2LTJIM3YybTAgNGgxNHYtMkgzdjJtMTYgMGgydi0yaC0ydjJtMC0xMHYyaDJWN2gtMm0wIDZoMnYtMmgtMnYyWiIvPjwvc3ZnPg=="); -} -.md-nav__title .md-nav__button.md-logo :-webkit-any(img, svg) { - fill: currentcolor; -} -.md-nav__title .md-nav__button.md-logo :is(img, svg) { - fill: currentcolor; -} -.md-nav__list { - list-style-image: initial; -} -.md-nav__link--passed { - color: var(--darkreader-text--md-default-fg-color--light, #e8e6e3); -} -.md-nav__item .md-nav__link--active { - color: var(--darkreader-text--md-typeset-a-color, #e8e6e3); -} -.md-nav__link:-webkit-any(:focus, :hover) { - color: var(--darkreader-text--md-accent-fg-color, #e8e6e3); -} -.md-nav__link:is(:focus, :hover) { - color: var(--darkreader-text--md-accent-fg-color, #e8e6e3); -} -.md-nav__link.focus-visible { - outline-color: var(--darkreader-border--md-accent-fg-color); -} -.md-nav--primary .md-nav__link[for="__toc"] .md-icon::after { - background-color: currentcolor; -} -@media screen and (max-width: 76.1875em) { - .md-nav--primary, - .md-nav--primary .md-nav { - background-color: var(--darkreader-bg--md-default-bg-color, #181a1b); - } - .md-nav--primary .md-nav__title { - background-color: var(--darkreader-bg--md-default-fg-color--lightest, #181a1b); - color: var(--darkreader-text--md-default-fg-color--light, #e8e6e3); - } - .md-nav--primary .md-nav__title .md-nav__icon::after { - background-color: currentcolor; - } - .md-nav--primary .md-nav__title ~ .md-nav__list { - background-color: var(--darkreader-bg--md-default-bg-color, #181a1b); - box-shadow: 0 .05rem 0 var(--darkreader-bg--md-default-fg-color--lightest) inset; - } - .md-nav--primary .md-nav__title ~ .md-nav__list > :first-child { - border-top: 0px; - } - .md-nav--primary .md-nav__title[for="__drawer"] { - background-color: var(--darkreader-bg--md-primary-fg-color, #181a1b); - color: var(--darkreader-text--md-primary-bg-color, #e8e6e3); - } - .md-nav--primary .md-nav__item { - border-top: .05rem solid var(--darkreader-border--md-default-fg-color--lightest); - } - .md-nav--primary .md-nav__item--active > .md-nav__link { - color: var(--darkreader-text--md-typeset-a-color, #e8e6e3); - } - .md-nav--primary .md-nav__item--active > .md-nav__link:-webkit-any(:focus, :hover) { - color: var(--darkreader-text--md-accent-fg-color, #e8e6e3); - } - .md-nav--primary .md-nav__item--active > .md-nav__link:is(:focus, :hover) { - color: var(--darkreader-text--md-accent-fg-color, #e8e6e3); - } - .md-nav--primary .md-nav__link .md-nav__icon::after { - background-color: currentcolor; - } - .md-nav--primary .md-nav--secondary .md-nav { - background-color: initial; - } - .md-nav--secondary { - background-color: initial; - } -} -@media screen and (max-width: 59.9375em) { - .md-nav__source { - background-color: var(--darkreader-bg--md-primary-fg-color--dark, #181a1b); - color: var(--darkreader-text--md-primary-bg-color, #e8e6e3); - } -} -@media screen and (min-width: 60em) { - .md-nav--secondary .md-nav__title { - background: var(--darkreader-bg--md-default-bg-color); - box-shadow: 0 0 .4rem .4rem var(--darkreader-bg--md-default-bg-color); - } -} -@media screen and (min-width: 76.25em) { - .md-nav--primary .md-nav__title { - background: var(--darkreader-bg--md-default-bg-color); - box-shadow: 0 0 .4rem .4rem var(--darkreader-bg--md-default-bg-color); - } - .md-nav__icon:hover { - background-color: var(--darkreader-bg--md-accent-fg-color--transparent, #181a1b); - } - .md-nav__icon::after { - background-color: currentcolor; - } - .md-nav--lifted > .md-nav__list > .md-nav__item--active > .md-nav__link { - background: var(--darkreader-bg--md-default-bg-color); - box-shadow: 0 0 .4rem .4rem var(--darkreader-bg--md-default-bg-color); - } - .md-nav--integrated > .md-nav__list > .md-nav__item--active .md-nav--secondary { - border-left: .05rem solid var(--darkreader-border--md-primary-fg-color); - } - [dir="rtl"] .md-nav--integrated > .md-nav__list > .md-nav__item--active .md-nav--secondary { - border-right: .05rem solid var(--darkreader-border--md-primary-fg-color); - } -} -:root { - --darkreader-bgimg--md-search-result-icon: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0iTTE0IDJINmEyIDIgMCAwIDAtMiAydjE2YTIgMiAwIDAgMCAyIDJoN2MtLjQxLS4yNS0uOC0uNTYtMS4xNC0uOS0uMzMtLjMzLS42MS0uNy0uODYtMS4xSDZWNGg3djVoNXYxLjE4Yy43MS4xNiAxLjM5LjQzIDIgLjgyVjhsLTYtNm02LjMxIDE2LjljMS4zMy0yLjExLjY5LTQuOS0xLjQtNi4yMi0yLjExLTEuMzMtNC45MS0uNjgtNi4yMiAxLjQtMS4zNCAyLjExLS42OSA0Ljg5IDEuNCA2LjIyIDEuNDYuOTMgMy4zMi45MyA0Ljc5LjAyTDIyIDIzLjM5IDIzLjM5IDIybC0zLjA4LTMuMW0tMy44MS4xYTIuNSAyLjUgMCAwIDEtMi41LTIuNSAyLjUgMi41IDAgMCAxIDIuNS0yLjUgMi41IDIuNSAwIDAgMSAyLjUgMi41IDIuNSAyLjUgMCAwIDEtMi41IDIuNVoiLz48L3N2Zz4="); -} -@media screen and (max-width: 59.9375em) { - .md-search__overlay { - background-color: var(--darkreader-bg--md-default-bg-color, #181a1b); - } -} -@media screen and (min-width: 60em) { - .md-search__overlay { - background-color: rgba(0, 0, 0, 0.54); - } -} -.md-search__form { - background-color: var(--darkreader-bg--md-default-bg-color, #181a1b); - box-shadow: rgba(0, 0, 0, 0) 0px 0px 0.6rem; -} -@media screen and (min-width: 60em) { - .md-search__form { - background-color: rgba(0, 0, 0, 0.26); - } - .md-search__form:hover { - background-color: rgba(24, 26, 27, 0.12); - } -} -[data-md-toggle="search"]:checked ~ .md-header .md-search__form { - background-color: var(--darkreader-bg--md-default-bg-color, #181a1b); - box-shadow: rgba(0, 0, 0, 0.07) 0px 0px 0.6rem; - color: var(--darkreader-text--md-default-fg-color, #e8e6e3); -} -.md-search__input { - background-color: transparent; - background-image: initial; -} -.md-search__input::placeholder, -.md-search__input ~ .md-search__icon { - color: var(--darkreader-text--md-default-fg-color--light, #e8e6e3); -} -@media screen and (min-width: 60em) { - .md-search__input { - color: inherit; - } - .md-search__input::placeholder { - color: var(--darkreader-text--md-primary-bg-color--light, #e8e6e3); - } - .md-search__input + .md-search__icon { - color: var(--darkreader-text--md-primary-bg-color, #e8e6e3); - } - [data-md-toggle="search"]:checked ~ .md-header .md-search__input + .md-search__icon, - [data-md-toggle="search"]:checked ~ .md-header .md-search__input::placeholder { - color: var(--darkreader-text--md-default-fg-color--light, #e8e6e3); - } -} -.md-search__options > * { - color: var(--darkreader-text--md-default-fg-color--light, #e8e6e3); -} -.md-search__options > :not(.focus-visible) { - -webkit-tap-highlight-color: transparent; - outline-color: initial; -} -.md-search__suggest { - color: var(--darkreader-text--md-default-fg-color--lighter, #e8e6e3); -} -@media screen and (min-width: 60em) { - [data-md-toggle="search"]:checked ~ .md-header .md-search__output { - box-shadow: var(--darkreader-bg--md-shadow-z3); - } -} -.md-search__scrollwrap { - background-color: var(--darkreader-bg--md-default-bg-color, #181a1b); -} -@media screen and (min-width: 60em) { - .md-search__scrollwrap::-webkit-scrollbar-thumb { - background-color: var(--darkreader-bg--md-default-fg-color--lighter, #181a1b); - } - .md-search__scrollwrap::-webkit-scrollbar-thumb:hover { - background-color: var(--darkreader-bg--md-accent-fg-color, #181a1b); - } -} -.md-search-result { - color: var(--darkreader-text--md-default-fg-color, #e8e6e3); -} -.md-search-result__meta { - background-color: var(--darkreader-bg--md-default-fg-color--lightest, #181a1b); - color: var(--darkreader-text--md-default-fg-color--light, #e8e6e3); -} -.md-search-result__list { - list-style-image: initial; -} -.md-search-result__item { - box-shadow: 0 -.05rem var(--darkreader-bg--md-default-fg-color--lightest); -} -.md-search-result__item:first-child { - box-shadow: none; -} -.md-search-result__link { - outline-color: initial; -} -.md-search-result__link:-webkit-any(:focus, :hover) { - background-color: var(--darkreader-bg--md-accent-fg-color--transparent, #181a1b); -} -.md-search-result__link:is(:focus, :hover) { - background-color: var(--darkreader-bg--md-accent-fg-color--transparent, #181a1b); -} -.md-search-result__more summary { - color: var(--darkreader-text--md-typeset-a-color, #e8e6e3); - outline-color: initial; -} -.md-search-result__more summary:-webkit-any(:focus, :hover) { - background-color: var(--darkreader-bg--md-accent-fg-color--transparent, #181a1b); - color: var(--darkreader-text--md-accent-fg-color, #e8e6e3); -} -.md-search-result__more summary:is(:focus, :hover) { - background-color: var(--darkreader-bg--md-accent-fg-color--transparent, #181a1b); - color: var(--darkreader-text--md-accent-fg-color, #e8e6e3); -} -.md-search-result__icon { - color: var(--darkreader-text--md-default-fg-color--light, #e8e6e3); -} -.md-search-result__icon::after { - background-color: currentcolor; -} -.md-search-result__teaser { - color: var(--darkreader-text--md-default-fg-color--light, #e8e6e3); -} -.md-search-result__teaser mark { - background-color: initial; - text-decoration-color: initial; -} -.md-search-result mark { - background-color: initial; - color: var(--darkreader-text--md-accent-fg-color, #e8e6e3); -} -.md-select__inner { - background-color: var(--darkreader-bg--md-default-bg-color, #181a1b); - box-shadow: var(--darkreader-bg--md-shadow-z2); - color: var(--darkreader-text--md-default-fg-color, #e8e6e3); -} -.md-select__inner::after { - border-bottom-color: var(--darkreader-border--md-default-bg-color); - border-left-color: transparent; - border-right-color: transparent; - border-top: 0px; -} -.md-select__link { - outline-color: initial; -} -.md-select__link:-webkit-any(:focus, :hover) { - color: var(--darkreader-text--md-accent-fg-color, #e8e6e3); -} -.md-select__link:is(:focus, :hover) { - color: var(--darkreader-text--md-accent-fg-color, #e8e6e3); -} -.md-select__link:focus { - background-color: var(--darkreader-bg--md-default-fg-color--lightest, #181a1b); -} -@media screen and (max-width: 76.1875em) { - .md-sidebar--primary { - background-color: var(--darkreader-bg--md-default-bg-color, #181a1b); - } - [data-md-toggle="drawer"]:checked ~ .md-container .md-sidebar--primary { - box-shadow: var(--darkreader-bg--md-shadow-z3); - } -} -.md-sidebar__scrollwrap::-webkit-scrollbar-thumb { - background-color: var(--darkreader-bg--md-default-fg-color--lighter, #181a1b); -} -.md-sidebar__scrollwrap::-webkit-scrollbar-thumb:hover { - background-color: var(--darkreader-bg--md-accent-fg-color, #181a1b); -} -@media screen and (max-width: 76.1875em) { - .md-overlay { - background-color: rgba(0, 0, 0, 0.54); - } -} -:root { - --darkreader-bgimg--md-source-forks-icon: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMTUwIiBoZWlnaHQ9IjE1MCI+PGRlZnM+PGZpbHRlciBpZD0iZGFya3JlYWRlci1pbWFnZS1maWx0ZXIiPjxmZUNvbG9yTWF0cml4IHR5cGU9Im1hdHJpeCIgdmFsdWVzPSIwLjI0OSAtMC42MTQgLTAuNjcyIDAuMDAwIDEuMDM1IC0wLjY0NiAwLjI4OCAtMC42NjQgMC4wMDAgMS4wMjAgLTAuNjM2IC0wLjYwOSAwLjI1MCAwLjAwMCAwLjk5NCAwLjAwMCAwLjAwMCAwLjAwMCAxLjAwMCAwLjAwMCIgLz48L2ZpbHRlcj48L2RlZnM+PGltYWdlIHdpZHRoPSIxNTAiIGhlaWdodD0iMTUwIiBmaWx0ZXI9InVybCgjZGFya3JlYWRlci1pbWFnZS1maWx0ZXIpIiB4bGluazpocmVmPSJkYXRhOmltYWdlL3N2Zyt4bWw7Y2hhcnNldD11dGYtOCwmbHQ7c3ZnIHhtbG5zPSZxdW90O2h0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnJnF1b3Q7IHZpZXdCb3g9JnF1b3Q7MCAwIDE2IDE2JnF1b3Q7Jmd0OyZsdDtwYXRoIGZpbGwtcnVsZT0mcXVvdDtldmVub2RkJnF1b3Q7IGQ9JnF1b3Q7TTUgMy4yNWEuNzUuNzUgMCAxIDEtMS41IDAgLjc1Ljc1IDAgMCAxIDEuNSAwem0wIDIuMTIyYTIuMjUgMi4yNSAwIDEgMC0xLjUgMHYuODc4QTIuMjUgMi4yNSAwIDAgMCA1Ljc1IDguNWgxLjV2Mi4xMjhhMi4yNTEgMi4yNTEgMCAxIDAgMS41IDBWOC41aDEuNWEyLjI1IDIuMjUgMCAwIDAgMi4yNS0yLjI1di0uODc4YTIuMjUgMi4yNSAwIDEgMC0xLjUgMHYuODc4YS43NS43NSAwIDAgMS0uNzUuNzVoLTQuNUEuNzUuNzUgMCAwIDEgNSA2LjI1di0uODc4em0zLjc1IDcuMzc4YS43NS43NSAwIDEgMS0xLjUgMCAuNzUuNzUgMCAwIDEgMS41IDB6bTMtOC43NWEuNzUuNzUgMCAxIDAgMC0xLjUuNzUuNzUgMCAwIDAgMCAxLjV6JnF1b3Q7LyZndDsmbHQ7L3N2ZyZndDsiIC8+PC9zdmc+"); - --darkreader-bgimg--md-source-repositories-icon: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMTUwIiBoZWlnaHQ9IjE1MCI+PGRlZnM+PGZpbHRlciBpZD0iZGFya3JlYWRlci1pbWFnZS1maWx0ZXIiPjxmZUNvbG9yTWF0cml4IHR5cGU9Im1hdHJpeCIgdmFsdWVzPSIwLjI0OSAtMC42MTQgLTAuNjcyIDAuMDAwIDEuMDM1IC0wLjY0NiAwLjI4OCAtMC42NjQgMC4wMDAgMS4wMjAgLTAuNjM2IC0wLjYwOSAwLjI1MCAwLjAwMCAwLjk5NCAwLjAwMCAwLjAwMCAwLjAwMCAxLjAwMCAwLjAwMCIgLz48L2ZpbHRlcj48L2RlZnM+PGltYWdlIHdpZHRoPSIxNTAiIGhlaWdodD0iMTUwIiBmaWx0ZXI9InVybCgjZGFya3JlYWRlci1pbWFnZS1maWx0ZXIpIiB4bGluazpocmVmPSJkYXRhOmltYWdlL3N2Zyt4bWw7Y2hhcnNldD11dGYtOCwmbHQ7c3ZnIHhtbG5zPSZxdW90O2h0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnJnF1b3Q7IHZpZXdCb3g9JnF1b3Q7MCAwIDE2IDE2JnF1b3Q7Jmd0OyZsdDtwYXRoIGZpbGwtcnVsZT0mcXVvdDtldmVub2RkJnF1b3Q7IGQ9JnF1b3Q7TTIgMi41QTIuNSAyLjUgMCAwIDEgNC41IDBoOC43NWEuNzUuNzUgMCAwIDEgLjc1Ljc1djEyLjVhLjc1Ljc1IDAgMCAxLS43NS43NWgtMi41YS43NS43NSAwIDEgMSAwLTEuNWgxLjc1di0yaC04YTEgMSAwIDAgMC0uNzE0IDEuNy43NS43NSAwIDAgMS0xLjA3MiAxLjA1QTIuNDk1IDIuNDk1IDAgMCAxIDIgMTEuNXYtOXptMTAuNS0xVjloLThjLS4zNTYgMC0uNjk0LjA3NC0xIC4yMDhWMi41YTEgMSAwIDAgMSAxLTFoOHpNNSAxMi4yNXYzLjI1YS4yNS4yNSAwIDAgMCAuNC4ybDEuNDUtMS4wODdhLjI1LjI1IDAgMCAxIC4zIDBMOC42IDE1LjdhLjI1LjI1IDAgMCAwIC40LS4ydi0zLjI1YS4yNS4yNSAwIDAgMC0uMjUtLjI1aC0zLjVhLjI1LjI1IDAgMCAwLS4yNS4yNXomcXVvdDsvJmd0OyZsdDsvc3ZnJmd0OyIgLz48L3N2Zz4="); - --darkreader-bgimg--md-source-stars-icon: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNiAxNiI+PHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNOCAuMjVhLjc1Ljc1IDAgMCAxIC42NzMuNDE4bDEuODgyIDMuODE1IDQuMjEuNjEyYS43NS43NSAwIDAgMSAuNDE2IDEuMjc5bC0zLjA0NiAyLjk3LjcxOSA0LjE5MmEuNzUuNzUgMCAwIDEtMS4wODguNzkxTDggMTIuMzQ3bC0zLjc2NiAxLjk4YS43NS43NSAwIDAgMS0xLjA4OC0uNzlsLjcyLTQuMTk0TC44MTggNi4zNzRhLjc1Ljc1IDAgMCAxIC40MTYtMS4yOGw0LjIxLS42MTFMNy4zMjcuNjY4QS43NS43NSAwIDAgMSA4IC4yNXptMCAyLjQ0NUw2LjYxNSA1LjVhLjc1Ljc1IDAgMCAxLS41NjQuNDFsLTMuMDk3LjQ1IDIuMjQgMi4xODRhLjc1Ljc1IDAgMCAxIC4yMTYuNjY0bC0uNTI4IDMuMDg0IDIuNzY5LTEuNDU2YS43NS43NSAwIDAgMSAuNjk4IDBsMi43NyAxLjQ1Ni0uNTMtMy4wODRhLjc1Ljc1IDAgMCAxIC4yMTYtLjY2NGwyLjI0LTIuMTgzLTMuMDk2LS40NWEuNzUuNzUgMCAwIDEtLjU2NC0uNDFMOCAyLjY5NHYuMDAxeiIvPjwvc3ZnPg=="); - --darkreader-bgimg--md-source-version-icon: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMTUwIiBoZWlnaHQ9IjE1MCI+PGRlZnM+PGZpbHRlciBpZD0iZGFya3JlYWRlci1pbWFnZS1maWx0ZXIiPjxmZUNvbG9yTWF0cml4IHR5cGU9Im1hdHJpeCIgdmFsdWVzPSIwLjI0OSAtMC42MTQgLTAuNjcyIDAuMDAwIDEuMDM1IC0wLjY0NiAwLjI4OCAtMC42NjQgMC4wMDAgMS4wMjAgLTAuNjM2IC0wLjYwOSAwLjI1MCAwLjAwMCAwLjk5NCAwLjAwMCAwLjAwMCAwLjAwMCAxLjAwMCAwLjAwMCIgLz48L2ZpbHRlcj48L2RlZnM+PGltYWdlIHdpZHRoPSIxNTAiIGhlaWdodD0iMTUwIiBmaWx0ZXI9InVybCgjZGFya3JlYWRlci1pbWFnZS1maWx0ZXIpIiB4bGluazpocmVmPSJkYXRhOmltYWdlL3N2Zyt4bWw7Y2hhcnNldD11dGYtOCwmbHQ7c3ZnIHhtbG5zPSZxdW90O2h0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnJnF1b3Q7IHZpZXdCb3g9JnF1b3Q7MCAwIDE2IDE2JnF1b3Q7Jmd0OyZsdDtwYXRoIGZpbGwtcnVsZT0mcXVvdDtldmVub2RkJnF1b3Q7IGQ9JnF1b3Q7TTIuNSA3Ljc3NVYyLjc1YS4yNS4yNSAwIDAgMSAuMjUtLjI1aDUuMDI1YS4yNS4yNSAwIDAgMSAuMTc3LjA3M2w2LjI1IDYuMjVhLjI1LjI1IDAgMCAxIDAgLjM1NGwtNS4wMjUgNS4wMjVhLjI1LjI1IDAgMCAxLS4zNTQgMGwtNi4yNS02LjI1YS4yNS4yNSAwIDAgMS0uMDczLS4xNzd6bS0xLjUgMFYyLjc1QzEgMS43ODQgMS43ODQgMSAyLjc1IDFoNS4wMjVjLjQ2NCAwIC45MS4xODQgMS4yMzguNTEzbDYuMjUgNi4yNWExLjc1IDEuNzUgMCAwIDEgMCAyLjQ3NGwtNS4wMjYgNS4wMjZhMS43NSAxLjc1IDAgMCAxLTIuNDc0IDBsLTYuMjUtNi4yNUExLjc1IDEuNzUgMCAwIDEgMSA3Ljc3NXpNNiA1YTEgMSAwIDEgMCAwIDIgMSAxIDAgMCAwIDAtMnomcXVvdDsvJmd0OyZsdDsvc3ZnJmd0OyIgLz48L3N2Zz4="); -} -.md-source { - outline-color: var(--darkreader-border--md-accent-fg-color); -} -.md-source__fact::before { - background-color: currentcolor; -} -.md-tabs { - background-color: var(--darkreader-bg--md-primary-fg-color, #181a1b); - color: var(--darkreader-text--md-primary-bg-color, #e8e6e3); -} -.md-tabs__list { - list-style-image: initial; -} -.md-tabs__link { - outline-color: var(--darkreader-border--md-accent-fg-color); -} -.md-tabs__link--active, -.md-tabs__link:-webkit-any(:focus, :hover) { - color: inherit; -} -.md-tabs__link--active, -.md-tabs__link:is(:focus, :hover) { - color: inherit; -} -:root { - --darkreader-bgimg--md-tag-icon: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0ibTUuNDEgMjEgLjcxLTRoLTRsLjM1LTJoNGwxLjA2LTZoLTRsLjM1LTJoNGwuNzEtNGgybC0uNzEgNGg2bC43MS00aDJsLS43MSA0aDRsLS4zNSAyaC00bC0xLjA2IDZoNGwtLjM1IDJoLTRsLS43MSA0aC0ybC43MS00aC02bC0uNzEgNGgtMk05LjUzIDlsLTEuMDYgNmg2bDEuMDYtNmgtNloiLz48L3N2Zz4="); -} -.md-typeset .md-tag { - background: var(--darkreader-bg--md-default-fg-color--lightest); -} -.md-typeset .md-tag[href] { - -webkit-tap-highlight-color: transparent; - color: inherit; - outline-color: initial; -} -.md-typeset .md-tag[href]:focus, -.md-typeset .md-tag[href]:hover { - background-color: var(--darkreader-bg--md-accent-fg-color, #181a1b); - color: var(--darkreader-text--md-accent-bg-color, #e8e6e3); -} -.md-typeset .md-tag-icon::before { - background-color: var(--darkreader-bg--md-default-fg-color--lighter, #181a1b); -} -.md-typeset .md-tag-icon:-webkit-any(a:focus, a:hover)::before { - background-color: var(--darkreader-bg--md-accent-bg-color, #181a1b); -} -.md-typeset .md-tag-icon:is(a:focus, a:hover)::before { - background-color: var(--darkreader-bg--md-accent-bg-color, #181a1b); -} -:root { - --md-tooltip-width: 20rem; -} -.md-tooltip { - background-color: var(--darkreader-bg--md-default-bg-color, #181a1b); - box-shadow: var(--darkreader-bg--md-shadow-z2); - color: var(--darkreader-text--md-default-fg-color, #e8e6e3); -} -:is(.focus-visible > .md-tooltip, .md-tooltip:target) { - outline: var(--darkreader-border--md-accent-fg-color) auto; -} -.md-annotation { - outline-color: initial; -} -.md-annotation__index { - outline-color: initial; -} -.md-annotation .md-annotation__index { - color: rgb(232, 230, 227); -} -.md-annotation .md-annotation__index:-webkit-any(:focus, :hover) { - color: rgb(232, 230, 227); -} -.md-annotation .md-annotation__index:is(:focus, :hover) { - color: rgb(232, 230, 227); -} -.md-annotation__index::after { - background-color: var(--darkreader-bg--md-default-fg-color--lighter, #181a1b); -} -:is(.md-tooltip--active + .md-annotation__index, :hover > .md-annotation__index) { - color: var(--darkreader-text--md-accent-bg-color, #e8e6e3); -} -:is(.md-tooltip--active + .md-annotation__index, :hover > .md-annotation__index)::after { - background-color: var(--darkreader-bg--md-accent-fg-color, #181a1b); -} -.md-top { - background-color: var(--darkreader-bg--md-default-bg-color, #181a1b); - box-shadow: var(--darkreader-bg--md-shadow-z2); - color: var(--darkreader-text--md-default-fg-color--light, #e8e6e3); - outline-color: initial; -} -.md-top:-webkit-any(:focus, :hover) { - background-color: var(--darkreader-bg--md-accent-fg-color, #181a1b); - color: var(--darkreader-text--md-accent-bg-color, #e8e6e3); -} -.md-top:is(:focus, :hover) { - background-color: var(--darkreader-bg--md-accent-fg-color, #181a1b); - color: var(--darkreader-text--md-accent-bg-color, #e8e6e3); -} -:root { - --darkreader-bgimg--md-version-icon: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMjAgNTEyIj48IS0tISBGb250IEF3ZXNvbWUgRnJlZSA2LjIuMCBieSBAZm9udGF3ZXNvbWUgLSBodHRwczovL2ZvbnRhd2Vzb21lLmNvbSBMaWNlbnNlIC0gaHR0cHM6Ly9mb250YXdlc29tZS5jb20vbGljZW5zZS9mcmVlIChJY29uczogQ0MgQlkgNC4wLCBGb250czogU0lMIE9GTCAxLjEsIENvZGU6IE1JVCBMaWNlbnNlKSBDb3B5cmlnaHQgMjAyMiBGb250aWNvbnMsIEluYy4tLT48cGF0aCBkPSJNMTM3LjQgMzc0LjZjMTIuNSAxMi41IDMyLjggMTIuNSA0NS4zIDBsMTI4LTEyOGM5LjItOS4yIDExLjktMjIuOSA2LjktMzQuOVMzMDEgMTkxLjkgMjg4IDE5MS45TDMyIDE5MmMtMTIuOSAwLTI0LjYgNy44LTI5LjYgMTkuOHMtMi4yIDI1LjcgNi45IDM0LjlsMTI4IDEyOHoiLz48L3N2Zz4="); -} -.md-version__current { - color: inherit; - outline-color: initial; -} -.md-version__current::after { - background-color: currentcolor; -} -.md-version__list { - background-color: var(--darkreader-bg--md-default-bg-color, #181a1b); - box-shadow: var(--darkreader-bg--md-shadow-z2); - color: var(--darkreader-text--md-default-fg-color, #e8e6e3); -} -.md-version__link { - outline-color: initial; -} -.md-version__link:-webkit-any(:focus, :hover) { - color: var(--darkreader-text--md-accent-fg-color, #e8e6e3); -} -.md-version__link:is(:focus, :hover) { - color: var(--darkreader-text--md-accent-fg-color, #e8e6e3); -} -.md-version__link:focus { - background-color: var(--darkreader-bg--md-default-fg-color--lightest, #181a1b); -} -:root { - --darkreader-bgimg--md-admonition-icon--abstract: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0iTTE3IDlIN1Y3aDEwbTAgNkg3di0yaDEwbS0zIDZIN3YtMmg3TTEyIDNhMSAxIDAgMCAxIDEgMSAxIDEgMCAwIDEtMSAxIDEgMSAwIDAgMS0xLTEgMSAxIDAgMCAxIDEtMW03IDBoLTQuMThDMTQuNCAxLjg0IDEzLjMgMSAxMiAxYy0xLjMgMC0yLjQuODQtMi44MiAySDVhMiAyIDAgMCAwLTIgMnYxNGEyIDIgMCAwIDAgMiAyaDE0YTIgMiAwIDAgMCAyLTJWNWEyIDIgMCAwIDAtMi0yWiIvPjwvc3ZnPg=="); - --darkreader-bgimg--md-admonition-icon--bug: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0iTTExIDEzaDJ2MWgtMnYtMW0xMC04djZjMCA1LjUtMy44IDEwLjctOSAxMi01LjItMS4zLTktNi41LTktMTJWNWw5LTQgOSA0bS00IDVoLTIuMmMtLjItLjYtLjYtMS4xLTEuMS0xLjVsMS4yLTEuMi0uNy0uN0wxMi44IDhIMTJjLS4yIDAtLjUgMC0uNy4xTDkuOSA2LjZsLS44LjggMS4yIDEuMmMtLjUuMy0uOS44LTEuMSAxLjRIN3YxaDJ2MUg3djFoMnYxSDd2MWgyLjJjLjQgMS4yIDEuNSAyIDIuOCAyczIuNC0uOCAyLjgtMkgxN3YtMWgtMnYtMWgydi0xaC0ydi0xaDJ2LTFtLTYgMmgydi0xaC0ydjFaIi8+PC9zdmc+"); - --darkreader-bgimg--md-admonition-icon--danger: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0ibTExLjUgMjAgNC44Ni05LjczSDEzVjRsLTUgOS43M2gzLjVWMjBNMTIgMmMyLjc1IDAgNS4xIDEgNy4wNSAyLjk1QzIxIDYuOSAyMiA5LjI1IDIyIDEycy0xIDUuMS0yLjk1IDcuMDVDMTcuMSAyMSAxNC43NSAyMiAxMiAyMnMtNS4xLTEtNy4wNS0yLjk1QzMgMTcuMSAyIDE0Ljc1IDIgMTJzMS01LjEgMi45NS03LjA1QzYuOSAzIDkuMjUgMiAxMiAyWiIvPjwvc3ZnPg=="); - --darkreader-bgimg--md-admonition-icon--example: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0iTTcgMnYyaDF2MTRhNCA0IDAgMCAwIDQgNCA0IDQgMCAwIDAgNC00VjRoMVYySDdtNCAxNGMtLjYgMC0xLS40LTEtMXMuNC0xIDEtMSAxIC40IDEgMS0uNCAxLTEgMW0yLTRjLS42IDAtMS0uNC0xLTFzLjQtMSAxLTEgMSAuNCAxIDEtLjQgMS0xIDFtMS01aC00VjRoNHYzWiIvPjwvc3ZnPg=="); - --darkreader-bgimg--md-admonition-icon--failure: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0iTTE5IDYuNDEgMTcuNTkgNSAxMiAxMC41OSA2LjQxIDUgNSA2LjQxIDEwLjU5IDEyIDUgMTcuNTkgNi40MSAxOSAxMiAxMy40MSAxNy41OSAxOSAxOSAxNy41OSAxMy40MSAxMiAxOSA2LjQxWiIvPjwvc3ZnPg=="); - --darkreader-bgimg--md-admonition-icon--info: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0iTTEzIDloLTJWN2gybTAgMTBoLTJ2LTZoMm0tMS05QTEwIDEwIDAgMCAwIDIgMTJhMTAgMTAgMCAwIDAgMTAgMTAgMTAgMTAgMCAwIDAgMTAtMTBBMTAgMTAgMCAwIDAgMTIgMloiLz48L3N2Zz4="); - --darkreader-bgimg--md-admonition-icon--note: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0iTTEyIDJDNi40NyAyIDIgNi40NyAyIDEyczQuNDcgMTAgMTAgMTAgMTAtNC40NyAxMC0xMFMxNy41MyAyIDEyIDJtMy4xIDUuMDdjLjE0IDAgLjI4LjA1LjQuMTZsMS4yNyAxLjI3Yy4yMy4yMi4yMy41NyAwIC43OGwtMSAxLTIuMDUtMi4wNSAxLTFjLjEtLjExLjI0LS4xNi4zOC0uMTZtLTEuOTcgMS43NCAyLjA2IDIuMDYtNi4wNiA2LjA2SDcuMDd2LTIuMDZsNi4wNi02LjA2WiIvPjwvc3ZnPg=="); - --darkreader-bgimg--md-admonition-icon--question: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0ibTE1LjA3IDExLjI1LS45LjkyQzEzLjQ1IDEyLjg5IDEzIDEzLjUgMTMgMTVoLTJ2LS41YzAtMS4xMS40NS0yLjExIDEuMTctMi44M2wxLjI0LTEuMjZjLjM3LS4zNi41OS0uODYuNTktMS40MWEyIDIgMCAwIDAtMi0yIDIgMiAwIDAgMC0yIDJIOGE0IDQgMCAwIDEgNC00IDQgNCAwIDAgMSA0IDQgMy4yIDMuMiAwIDAgMS0uOTMgMi4yNU0xMyAxOWgtMnYtMmgyTTEyIDJBMTAgMTAgMCAwIDAgMiAxMmExMCAxMCAwIDAgMCAxMCAxMCAxMCAxMCAwIDAgMCAxMC0xMGMwLTUuNTMtNC41LTEwLTEwLTEwWiIvPjwvc3ZnPg=="); - --darkreader-bgimg--md-admonition-icon--quote: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0iTTE0IDE3aDNsMi00VjdoLTZ2NmgzTTYgMTdoM2wyLTRWN0g1djZoM2wtMiA0WiIvPjwvc3ZnPg=="); - --darkreader-bgimg--md-admonition-icon--success: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0iTTIxIDcgOSAxOWwtNS41LTUuNSAxLjQxLTEuNDFMOSAxNi4xNyAxOS41OSA1LjU5IDIxIDdaIi8+PC9zdmc+"); - --darkreader-bgimg--md-admonition-icon--tip: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0iTTE3LjY2IDExLjJjLS4yMy0uMy0uNTEtLjU2LS43Ny0uODItLjY3LS42LTEuNDMtMS4wMy0yLjA3LTEuNjZDMTMuMzMgNy4yNiAxMyA0Ljg1IDEzLjk1IDNjLS45NS4yMy0xLjc4Ljc1LTIuNDkgMS4zMi0yLjU5IDIuMDgtMy42MSA1Ljc1LTIuMzkgOC45LjA0LjEuMDguMi4wOC4zMyAwIC4yMi0uMTUuNDItLjM1LjUtLjIzLjEtLjQ3LjA0LS42Ni0uMTJhLjU4LjU4IDAgMCAxLS4xNC0uMTdjLTEuMTMtMS40My0xLjMxLTMuNDgtLjU1LTUuMTJDNS43OCAxMCA0Ljg3IDEyLjMgNSAxNC40N2MuMDYuNS4xMiAxIC4yOSAxLjUuMTQuNi40MSAxLjIuNzEgMS43MyAxLjA4IDEuNzMgMi45NSAyLjk3IDQuOTYgMy4yMiAyLjE0LjI3IDQuNDMtLjEyIDYuMDctMS42IDEuODMtMS42NiAyLjQ3LTQuMzIgMS41My02LjZsLS4xMy0uMjZjLS4yMS0uNDYtLjc3LTEuMjYtLjc3LTEuMjZtLTMuMTYgNi4zYy0uMjguMjQtLjc0LjUtMS4xLjYtMS4xMi40LTIuMjQtLjE2LTIuOS0uODIgMS4xOS0uMjggMS45LTEuMTYgMi4xMS0yLjA1LjE3LS44LS4xNS0xLjQ2LS4yOC0yLjIzLS4xMi0uNzQtLjEtMS4zNy4xNy0yLjA2LjE5LjM4LjM5Ljc2LjYzIDEuMDYuNzcgMSAxLjk4IDEuNDQgMi4yNCAyLjguMDQuMTQuMDYuMjguMDYuNDMuMDMuODItLjMzIDEuNzItLjkzIDIuMjdaIi8+PC9zdmc+"); - --darkreader-bgimg--md-admonition-icon--warning: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0iTTEzIDE0aC0yVjloMm0wIDloLTJ2LTJoMk0xIDIxaDIyTDEyIDIgMSAyMVoiLz48L3N2Zz4="); -} -.md-typeset .admonition, -.md-typeset details { - background-color: var(--darkreader-bg--md-admonition-bg-color, #181a1b); - border-color: rgb(0, 59, 158); - box-shadow: var(--darkreader-bg--md-shadow-z1); - color: var(--darkreader-text--md-admonition-fg-color, #e8e6e3); -} -.md-typeset .admonition-title, -.md-typeset summary { - background-color: rgba(0, 61, 163, 0.1); - border-color: initial; - border-style: none; - border-width: initial; -} -.md-typeset .admonition-title::before, -.md-typeset summary::before { - background-color: rgb(73, 165, 255); -} -.md-typeset .admonition-title code, -.md-typeset summary code { - box-shadow: 0 0 0 .05rem var(--darkreader-bg--md-default-fg-color--lightest); -} -.md-typeset :-webkit-any(.admonition, details):-webkit-any(.note) { - border-color: rgb(0, 59, 158); -} -.md-typeset :is(.admonition, details):is(.note) { - border-color: rgb(0, 59, 158); -} -.md-typeset :-webkit-any(.note) > :-webkit-any(.admonition-title, summary) { - background-color: rgba(0, 61, 163, 0.1); -} -.md-typeset :is(.note) > :is(.admonition-title, summary) { - background-color: rgba(0, 61, 163, 0.1); -} -.md-typeset :-webkit-any(.note) > :-webkit-any(.admonition-title, summary)::before { - background-color: rgb(73, 165, 255); -} -.md-typeset :is(.note) > :is(.admonition-title, summary)::before { - background-color: rgb(73, 165, 255); -} -.md-typeset :-webkit-any(.note) > :-webkit-any(.admonition-title, summary)::after { - color: rgb(73, 165, 255); -} -.md-typeset :is(.note) > :is(.admonition-title, summary)::after { - color: rgb(73, 165, 255); -} -.md-typeset :-webkit-any(.admonition, details):-webkit-any(.abstract, .summary, .tldr) { - border-color: rgb(0, 123, 179); -} -.md-typeset :is(.admonition, details):is(.abstract, .summary, .tldr) { - border-color: rgb(0, 123, 179); -} -.md-typeset :-webkit-any(.abstract, .summary, .tldr) > :-webkit-any(.admonition-title, summary) { - background-color: rgba(0, 141, 204, 0.1); -} -.md-typeset :is(.abstract, .summary, .tldr) > :is(.admonition-title, summary) { - background-color: rgba(0, 141, 204, 0.1); -} -.md-typeset :-webkit-any(.abstract, .summary, .tldr) > :-webkit-any(.admonition-title, summary)::before { - background-color: rgb(26, 184, 255); -} -.md-typeset :is(.abstract, .summary, .tldr) > :is(.admonition-title, summary)::before { - background-color: rgb(26, 184, 255); -} -.md-typeset :-webkit-any(.abstract, .summary, .tldr) > :-webkit-any(.admonition-title, summary)::after { - color: rgb(26, 184, 255); -} -.md-typeset :is(.abstract, .summary, .tldr) > :is(.admonition-title, summary)::after { - color: rgb(26, 184, 255); -} -.md-typeset :-webkit-any(.admonition, details):-webkit-any(.info, .todo) { - border-color: rgb(0, 166, 191); -} -.md-typeset :is(.admonition, details):is(.info, .todo) { - border-color: rgb(0, 166, 191); -} -.md-typeset :-webkit-any(.info, .todo) > :-webkit-any(.admonition-title, summary) { - background-color: rgba(0, 147, 170, 0.1); -} -.md-typeset :is(.info, .todo) > :is(.admonition-title, summary) { - background-color: rgba(0, 147, 170, 0.1); -} -.md-typeset :-webkit-any(.info, .todo) > :-webkit-any(.admonition-title, summary)::before { - background-color: rgb(56, 229, 255); -} -.md-typeset :is(.info, .todo) > :is(.admonition-title, summary)::before { - background-color: rgb(56, 229, 255); -} -.md-typeset :-webkit-any(.info, .todo) > :-webkit-any(.admonition-title, summary)::after { - color: rgb(56, 229, 255); -} -.md-typeset :is(.info, .todo) > :is(.admonition-title, summary)::after { - color: rgb(56, 229, 255); -} -.md-typeset :-webkit-any(.admonition, details):-webkit-any(.tip, .hint, .important) { - border-color: rgb(0, 198, 171); -} -.md-typeset :is(.admonition, details):is(.tip, .hint, .important) { - border-color: rgb(0, 198, 171); -} -.md-typeset :-webkit-any(.tip, .hint, .important) > :-webkit-any(.admonition-title, summary) { - background-color: rgba(0, 153, 132, 0.1); -} -.md-typeset :is(.tip, .hint, .important) > :is(.admonition-title, summary) { - background-color: rgba(0, 153, 132, 0.1); -} -.md-typeset :-webkit-any(.tip, .hint, .important) > :-webkit-any(.admonition-title, summary)::before { - background-color: rgb(70, 255, 230); -} -.md-typeset :is(.tip, .hint, .important) > :is(.admonition-title, summary)::before { - background-color: rgb(70, 255, 230); -} -.md-typeset :-webkit-any(.tip, .hint, .important) > :-webkit-any(.admonition-title, summary)::after { - color: rgb(70, 255, 230); -} -.md-typeset :is(.tip, .hint, .important) > :is(.admonition-title, summary)::after { - color: rgb(70, 255, 230); -} -.md-typeset :-webkit-any(.admonition, details):-webkit-any(.success, .check, .done) { - border-color: rgb(0, 195, 81); -} -.md-typeset :is(.admonition, details):is(.success, .check, .done) { - border-color: rgb(0, 195, 81); -} -.md-typeset :-webkit-any(.success, .check, .done) > :-webkit-any(.admonition-title, summary) { - background-color: rgba(0, 160, 66, 0.1); -} -.md-typeset :is(.success, .check, .done) > :is(.admonition-title, summary) { - background-color: rgba(0, 160, 66, 0.1); -} -.md-typeset :-webkit-any(.success, .check, .done) > :-webkit-any(.admonition-title, summary)::before { - background-color: rgb(64, 255, 143); -} -.md-typeset :is(.success, .check, .done) > :is(.admonition-title, summary)::before { - background-color: rgb(64, 255, 143); -} -.md-typeset :-webkit-any(.success, .check, .done) > :-webkit-any(.admonition-title, summary)::after { - color: rgb(64, 255, 143); -} -.md-typeset :is(.success, .check, .done) > :is(.admonition-title, summary)::after { - color: rgb(64, 255, 143); -} -.md-typeset :-webkit-any(.admonition, details):-webkit-any(.question, .help, .faq) { - border-color: rgb(75, 165, 17); -} -.md-typeset :is(.admonition, details):is(.question, .help, .faq) { - border-color: rgb(75, 165, 17); -} -.md-typeset :-webkit-any(.question, .help, .faq) > :-webkit-any(.admonition-title, summary) { - background-color: rgba(80, 177, 18, 0.1); -} -.md-typeset :is(.question, .help, .faq) > :is(.admonition-title, summary) { - background-color: rgba(80, 177, 18, 0.1); -} -.md-typeset :-webkit-any(.question, .help, .faq) > :-webkit-any(.admonition-title, summary)::before { - background-color: rgb(124, 234, 54); -} -.md-typeset :is(.question, .help, .faq) > :is(.admonition-title, summary)::before { - background-color: rgb(124, 234, 54); -} -.md-typeset :-webkit-any(.question, .help, .faq) > :-webkit-any(.admonition-title, summary)::after { - color: rgb(124, 234, 54); -} -.md-typeset :is(.question, .help, .faq) > :is(.admonition-title, summary)::after { - color: rgb(124, 234, 54); -} -.md-typeset :-webkit-any(.admonition, details):-webkit-any(.warning, .caution, .attention) { - border-color: rgb(179, 102, 0); -} -.md-typeset :is(.admonition, details):is(.warning, .caution, .attention) { - border-color: rgb(179, 102, 0); -} -.md-typeset :-webkit-any(.warning, .caution, .attention) > :-webkit-any(.admonition-title, summary) { - background-color: rgba(204, 116, 0, 0.1); -} -.md-typeset :is(.warning, .caution, .attention) > :is(.admonition-title, summary) { - background-color: rgba(204, 116, 0, 0.1); -} -.md-typeset :-webkit-any(.warning, .caution, .attention) > :-webkit-any(.admonition-title, summary)::before { - background-color: rgb(255, 156, 26); -} -.md-typeset :is(.warning, .caution, .attention) > :is(.admonition-title, summary)::before { - background-color: rgb(255, 156, 26); -} -.md-typeset :-webkit-any(.warning, .caution, .attention) > :-webkit-any(.admonition-title, summary)::after { - color: rgb(255, 156, 26); -} -.md-typeset :is(.warning, .caution, .attention) > :is(.admonition-title, summary)::after { - color: rgb(255, 156, 26); -} -.md-typeset :-webkit-any(.admonition, details):-webkit-any(.failure, .fail, .missing) { - border-color: rgb(154, 0, 0); -} -.md-typeset :is(.admonition, details):is(.failure, .fail, .missing) { - border-color: rgb(154, 0, 0); -} -.md-typeset :-webkit-any(.failure, .fail, .missing) > :-webkit-any(.admonition-title, summary) { - background-color: rgba(155, 0, 0, 0.1); -} -.md-typeset :is(.failure, .fail, .missing) > :is(.admonition-title, summary) { - background-color: rgba(155, 0, 0, 0.1); -} -.md-typeset :-webkit-any(.failure, .fail, .missing) > :-webkit-any(.admonition-title, summary)::before { - background-color: rgb(255, 83, 83); -} -.md-typeset :is(.failure, .fail, .missing) > :is(.admonition-title, summary)::before { - background-color: rgb(255, 83, 83); -} -.md-typeset :-webkit-any(.failure, .fail, .missing) > :-webkit-any(.admonition-title, summary)::after { - color: rgb(255, 83, 83); -} -.md-typeset :is(.failure, .fail, .missing) > :is(.admonition-title, summary)::after { - color: rgb(255, 83, 83); -} -.md-typeset :-webkit-any(.admonition, details):-webkit-any(.danger, .error) { - border-color: rgb(172, 0, 33); -} -.md-typeset :is(.admonition, details):is(.danger, .error) { - border-color: rgb(172, 0, 33); -} -.md-typeset :-webkit-any(.danger, .error) > :-webkit-any(.admonition-title, summary) { - background-color: rgba(190, 0, 37, 0.1); -} -.md-typeset :is(.danger, .error) > :is(.admonition-title, summary) { - background-color: rgba(190, 0, 37, 0.1); -} -.md-typeset :-webkit-any(.danger, .error) > :-webkit-any(.admonition-title, summary)::before { - background-color: rgb(255, 42, 83); -} -.md-typeset :is(.danger, .error) > :is(.admonition-title, summary)::before { - background-color: rgb(255, 42, 83); -} -.md-typeset :-webkit-any(.danger, .error) > :-webkit-any(.admonition-title, summary)::after { - color: rgb(255, 42, 83); -} -.md-typeset :is(.danger, .error) > :is(.admonition-title, summary)::after { - color: rgb(255, 42, 83); -} -.md-typeset :-webkit-any(.admonition, details):-webkit-any(.bug) { - border-color: rgb(182, 0, 64); -} -.md-typeset :is(.admonition, details):is(.bug) { - border-color: rgb(182, 0, 64); -} -.md-typeset :-webkit-any(.bug) > :-webkit-any(.admonition-title, summary) { - background-color: rgba(196, 0, 70, 0.1); -} -.md-typeset :is(.bug) > :is(.admonition-title, summary) { - background-color: rgba(196, 0, 70, 0.1); -} -.md-typeset :-webkit-any(.bug) > :-webkit-any(.admonition-title, summary)::before { - background-color: rgb(255, 33, 112); -} -.md-typeset :is(.bug) > :is(.admonition-title, summary)::before { - background-color: rgb(255, 33, 112); -} -.md-typeset :-webkit-any(.bug) > :-webkit-any(.admonition-title, summary)::after { - color: rgb(255, 33, 112); -} -.md-typeset :is(.bug) > :is(.admonition-title, summary)::after { - color: rgb(255, 33, 112); -} -.md-typeset :-webkit-any(.admonition, details):-webkit-any(.example) { - border-color: rgb(41, 0, 155); -} -.md-typeset :is(.admonition, details):is(.example) { - border-color: rgb(41, 0, 155); -} -.md-typeset :-webkit-any(.example) > :-webkit-any(.admonition-title, summary) { - background-color: rgba(42, 0, 158, 0.1); -} -.md-typeset :is(.example) > :is(.admonition-title, summary) { - background-color: rgba(42, 0, 158, 0.1); -} -.md-typeset :-webkit-any(.example) > :-webkit-any(.admonition-title, summary)::before { - background-color: rgb(126, 79, 255); -} -.md-typeset :is(.example) > :is(.admonition-title, summary)::before { - background-color: rgb(126, 79, 255); -} -.md-typeset :-webkit-any(.example) > :-webkit-any(.admonition-title, summary)::after { - color: rgb(126, 79, 255); -} -.md-typeset :is(.example) > :is(.admonition-title, summary)::after { - color: rgb(126, 79, 255); -} -.md-typeset :-webkit-any(.admonition, details):-webkit-any(.quote, .cite) { - border-color: rgb(75, 82, 85); -} -.md-typeset :is(.admonition, details):is(.quote, .cite) { - border-color: rgb(75, 82, 85); -} -.md-typeset :-webkit-any(.quote, .cite) > :-webkit-any(.admonition-title, summary) { - background-color: rgba(79, 85, 89, 0.1); -} -.md-typeset :is(.quote, .cite) > :is(.admonition-title, summary) { - background-color: rgba(79, 85, 89, 0.1); -} -.md-typeset :-webkit-any(.quote, .cite) > :-webkit-any(.admonition-title, summary)::before { - background-color: rgb(171, 163, 152); -} -.md-typeset :is(.quote, .cite) > :is(.admonition-title, summary)::before { - background-color: rgb(171, 163, 152); -} -.md-typeset :-webkit-any(.quote, .cite) > :-webkit-any(.admonition-title, summary)::after { - color: rgb(171, 163, 152); -} -.md-typeset :is(.quote, .cite) > :is(.admonition-title, summary)::after { - color: rgb(171, 163, 152); -} -:root { - --darkreader-bgimg--md-footnotes-icon: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0iTTE5IDd2NEg1LjgzbDMuNTgtMy41OUw4IDZsLTYgNiA2IDYgMS40MS0xLjQyTDUuODMgMTNIMjFWN2gtMloiLz48L3N2Zz4="); -} -.md-typeset .footnote { - color: var(--darkreader-text--md-default-fg-color--light, #e8e6e3); -} -.md-typeset .footnote > ol > li:target { - color: var(--darkreader-text--md-default-fg-color, #e8e6e3); -} -.md-typeset [id^="fnref:"]:target > .footnote-ref { - outline-color: initial; -} -.md-typeset .footnote-backref { - color: var(--darkreader-text--md-typeset-a-color, #e8e6e3); -} -.md-typeset .footnote-backref:hover { - color: var(--darkreader-text--md-accent-fg-color, #e8e6e3); -} -.md-typeset .footnote-backref::before { - background-color: currentcolor; -} -.md-typeset .headerlink { - color: var(--darkreader-text--md-default-fg-color--lighter, #e8e6e3); -} -.md-typeset .headerlink:-webkit-any(:focus, :hover), -.md-typeset :target > .headerlink { - color: var(--darkreader-text--md-accent-fg-color, #e8e6e3); -} -.md-typeset .headerlink:is(:focus, :hover), -.md-typeset :target > .headerlink { - color: var(--darkreader-text--md-accent-fg-color, #e8e6e3); -} -.md-typeset :target { - --md-scroll-margin: 3.6rem; - --md-scroll-offset: 0rem; -} -@media screen and (min-width: 76.25em) { - .md-header--lifted ~ .md-container .md-typeset :target { - --md-scroll-margin: 6rem; - } -} -.md-typeset :-webkit-any(h1, h2, h3):target { - --md-scroll-offset: 0.2rem; -} -.md-typeset :is(h1, h2, h3):target { - --md-scroll-offset: 0.2rem; -} -.md-typeset h4:target { - --md-scroll-offset: 0.15rem; -} -.md-typeset del.critic { - background-color: var(--darkreader-bg--md-typeset-del-color, #181a1b); -} -.md-typeset ins.critic { - background-color: var(--darkreader-bg--md-typeset-ins-color, #181a1b); -} -.md-typeset .critic.comment { - color: var(--darkreader-text--md-code-hl-comment-color, #e8e6e3); -} -.md-typeset .critic.block { - box-shadow: none; -} -:root { - --darkreader-bgimg--md-details-icon: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0iTTguNTkgMTYuNTggMTMuMTcgMTIgOC41OSA3LjQxIDEwIDZsNiA2LTYgNi0xLjQxLTEuNDJaIi8+PC9zdmc+"); -} -.md-typeset details:not([open]) { - box-shadow: none; -} -.md-typeset summary.focus-visible { - outline-color: var(--darkreader-border--md-accent-fg-color); -} -.md-typeset summary:not(.focus-visible) { - -webkit-tap-highlight-color: transparent; - outline-color: initial; -} -.md-typeset summary::after { - background-color: currentcolor; -} -.md-typeset :-webkit-any(.emojione, .twemoji, .gemoji) svg { - fill: currentcolor; -} -.md-typeset :is(.emojione, .twemoji, .gemoji) svg { - fill: currentcolor; -} -.highlight :-webkit-any(.o, .ow) { - color: var(--darkreader-text--md-code-hl-operator-color, #e8e6e3); -} -.highlight :is(.o, .ow) { - color: var(--darkreader-text--md-code-hl-operator-color, #e8e6e3); -} -.highlight .p { - color: var(--darkreader-text--md-code-hl-punctuation-color, #e8e6e3); -} -.highlight :-webkit-any(.cpf, .l, .s, .sb, .sc, .s2, .si, .s1, .ss) { - color: var(--darkreader-text--md-code-hl-string-color, #e8e6e3); -} -.highlight :is(.cpf, .l, .s, .sb, .sc, .s2, .si, .s1, .ss) { - color: var(--darkreader-text--md-code-hl-string-color, #e8e6e3); -} -.highlight :-webkit-any(.cp, .se, .sh, .sr, .sx) { - color: var(--darkreader-text--md-code-hl-special-color, #e8e6e3); -} -.highlight :is(.cp, .se, .sh, .sr, .sx) { - color: var(--darkreader-text--md-code-hl-special-color, #e8e6e3); -} -.highlight :-webkit-any(.m, .mb, .mf, .mh, .mi, .il, .mo) { - color: var(--darkreader-text--md-code-hl-number-color, #e8e6e3); -} -.highlight :is(.m, .mb, .mf, .mh, .mi, .il, .mo) { - color: var(--darkreader-text--md-code-hl-number-color, #e8e6e3); -} -.highlight :-webkit-any(.k, .kd, .kn, .kp, .kr, .kt) { - color: var(--darkreader-text--md-code-hl-keyword-color, #e8e6e3); -} -.highlight :is(.k, .kd, .kn, .kp, .kr, .kt) { - color: var(--darkreader-text--md-code-hl-keyword-color, #e8e6e3); -} -.highlight :-webkit-any(.kc, .n) { - color: var(--darkreader-text--md-code-hl-name-color, #e8e6e3); -} -.highlight :is(.kc, .n) { - color: var(--darkreader-text--md-code-hl-name-color, #e8e6e3); -} -.highlight :-webkit-any(.no, .nb, .bp) { - color: var(--darkreader-text--md-code-hl-constant-color, #e8e6e3); -} -.highlight :is(.no, .nb, .bp) { - color: var(--darkreader-text--md-code-hl-constant-color, #e8e6e3); -} -.highlight :-webkit-any(.nc, .ne, .nf, .nn) { - color: var(--darkreader-text--md-code-hl-function-color, #e8e6e3); -} -.highlight :is(.nc, .ne, .nf, .nn) { - color: var(--darkreader-text--md-code-hl-function-color, #e8e6e3); -} -.highlight :-webkit-any(.nd, .ni, .nl, .nt) { - color: var(--darkreader-text--md-code-hl-keyword-color, #e8e6e3); -} -.highlight :is(.nd, .ni, .nl, .nt) { - color: var(--darkreader-text--md-code-hl-keyword-color, #e8e6e3); -} -.highlight :-webkit-any(.c, .cm, .c1, .ch, .cs, .sd) { - color: var(--darkreader-text--md-code-hl-comment-color, #e8e6e3); -} -.highlight :is(.c, .cm, .c1, .ch, .cs, .sd) { - color: var(--darkreader-text--md-code-hl-comment-color, #e8e6e3); -} -.highlight :-webkit-any(.na, .nv, .vc, .vg, .vi) { - color: var(--darkreader-text--md-code-hl-variable-color, #e8e6e3); -} -.highlight :is(.na, .nv, .vc, .vg, .vi) { - color: var(--darkreader-text--md-code-hl-variable-color, #e8e6e3); -} -.highlight :-webkit-any(.ge, .gr, .gh, .go, .gp, .gs, .gu, .gt) { - color: var(--darkreader-text--md-code-hl-generic-color, #e8e6e3); -} -.highlight :is(.ge, .gr, .gh, .go, .gp, .gs, .gu, .gt) { - color: var(--darkreader-text--md-code-hl-generic-color, #e8e6e3); -} -.highlight .gd { - background-color: var(--darkreader-bg--md-typeset-del-color, #181a1b); -} -.highlight .gi { - background-color: var(--darkreader-bg--md-typeset-ins-color, #181a1b); -} -.highlight .hll { - background-color: var(--darkreader-bg--md-code-hl-color, #181a1b); -} -.highlight span.filename { - background-color: var(--darkreader-bg--md-default-fg-color--lighter, #181a1b); - border-bottom: .05rem solid var(--darkreader-border--md-default-fg-color--lightest); -} -.highlight [data-linenos]::before { - background-color: var(--darkreader-bg--md-code-bg-color, #181a1b); - box-shadow: -.05rem 0 var(--darkreader-bg--md-default-fg-color--lightest) inset; - color: var(--darkreader-text--md-default-fg-color--light, #e8e6e3); -} -.highlighttable .linenos { - background-color: var(--darkreader-bg--md-code-bg-color, #181a1b); -} -.highlighttable .linenodiv { - box-shadow: -.05rem 0 var(--darkreader-bg--md-default-fg-color--lightest) inset; -} -.highlighttable .linenodiv pre { - color: var(--darkreader-text--md-default-fg-color--light, #e8e6e3); -} -.linenodiv a { - color: inherit; -} -.md-typeset .keys span { - color: var(--darkreader-text--md-default-fg-color--light, #e8e6e3); -} -:root { - --darkreader-bgimg--md-tabbed-icon--next: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0iTTguNTkgMTYuNTggMTMuMTcgMTIgOC41OSA3LjQxIDEwIDZsNiA2LTYgNi0xLjQxLTEuNDJaIi8+PC9zdmc+"); - --darkreader-bgimg--md-tabbed-icon--prev: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0iTTE1LjQxIDE2LjU4IDEwLjgzIDEybDQuNTgtNC41OUwxNCA2bC02IDYgNiA2IDEuNDEtMS40MloiLz48L3N2Zz4="); -} -.md-typeset .tabbed-set > input:target { - --md-scroll-offset: 0.625em; -} -.md-typeset .tabbed-labels { - box-shadow: 0 -.05rem var(--darkreader-bg--md-default-fg-color--lightest) inset; -} -@media screen { - .js .md-typeset .tabbed-labels::before { - background: var(--darkreader-bg--md-accent-fg-color); - } -} -.md-typeset .tabbed-labels > label { - border-bottom-color: transparent; - color: var(--darkreader-text--md-default-fg-color--light, #e8e6e3); -} -.md-typeset .tabbed-labels > label:hover { - color: var(--darkreader-text--md-accent-fg-color, #e8e6e3); -} -.md-typeset .tabbed-button { - color: var(--darkreader-text--md-default-fg-color--light, #e8e6e3); -} -.md-typeset .tabbed-button:hover { - background-color: var(--darkreader-bg--md-accent-fg-color--transparent, #181a1b); - color: var(--darkreader-text--md-accent-fg-color, #e8e6e3); -} -.md-typeset .tabbed-button::after { - background-color: currentcolor; -} -.md-typeset .tabbed-control { - background: linear-gradient(to right,var(--darkreader-bg--md-default-bg-color) 60%,transparent); -} -.md-typeset .tabbed-control--next { - background: linear-gradient(to left,var(--darkreader-bg--md-default-bg-color) 60%,transparent); -} -@media screen { - .md-typeset .tabbed-set > input:first-child:checked ~ .tabbed-labels > :first-child, - .md-typeset .tabbed-set > input:nth-child(10):checked ~ .tabbed-labels > :nth-child(10), - .md-typeset .tabbed-set > input:nth-child(11):checked ~ .tabbed-labels > :nth-child(11), - .md-typeset .tabbed-set > input:nth-child(12):checked ~ .tabbed-labels > :nth-child(12), - .md-typeset .tabbed-set > input:nth-child(13):checked ~ .tabbed-labels > :nth-child(13), - .md-typeset .tabbed-set > input:nth-child(14):checked ~ .tabbed-labels > :nth-child(14), - .md-typeset .tabbed-set > input:nth-child(15):checked ~ .tabbed-labels > :nth-child(15), - .md-typeset .tabbed-set > input:nth-child(16):checked ~ .tabbed-labels > :nth-child(16), - .md-typeset .tabbed-set > input:nth-child(17):checked ~ .tabbed-labels > :nth-child(17), - .md-typeset .tabbed-set > input:nth-child(18):checked ~ .tabbed-labels > :nth-child(18), - .md-typeset .tabbed-set > input:nth-child(19):checked ~ .tabbed-labels > :nth-child(19), - .md-typeset .tabbed-set > input:nth-child(2):checked ~ .tabbed-labels > :nth-child(2), - .md-typeset .tabbed-set > input:nth-child(20):checked ~ .tabbed-labels > :nth-child(20), - .md-typeset .tabbed-set > input:nth-child(3):checked ~ .tabbed-labels > :nth-child(3), - .md-typeset .tabbed-set > input:nth-child(4):checked ~ .tabbed-labels > :nth-child(4), - .md-typeset .tabbed-set > input:nth-child(5):checked ~ .tabbed-labels > :nth-child(5), - .md-typeset .tabbed-set > input:nth-child(6):checked ~ .tabbed-labels > :nth-child(6), - .md-typeset .tabbed-set > input:nth-child(7):checked ~ .tabbed-labels > :nth-child(7), - .md-typeset .tabbed-set > input:nth-child(8):checked ~ .tabbed-labels > :nth-child(8), - .md-typeset .tabbed-set > input:nth-child(9):checked ~ .tabbed-labels > :nth-child(9) { - color: var(--darkreader-text--md-accent-fg-color, #e8e6e3); - } - .md-typeset .no-js .tabbed-set > input:first-child:checked ~ .tabbed-labels > :first-child, - .md-typeset .no-js .tabbed-set > input:nth-child(10):checked ~ .tabbed-labels > :nth-child(10), - .md-typeset .no-js .tabbed-set > input:nth-child(11):checked ~ .tabbed-labels > :nth-child(11), - .md-typeset .no-js .tabbed-set > input:nth-child(12):checked ~ .tabbed-labels > :nth-child(12), - .md-typeset .no-js .tabbed-set > input:nth-child(13):checked ~ .tabbed-labels > :nth-child(13), - .md-typeset .no-js .tabbed-set > input:nth-child(14):checked ~ .tabbed-labels > :nth-child(14), - .md-typeset .no-js .tabbed-set > input:nth-child(15):checked ~ .tabbed-labels > :nth-child(15), - .md-typeset .no-js .tabbed-set > input:nth-child(16):checked ~ .tabbed-labels > :nth-child(16), - .md-typeset .no-js .tabbed-set > input:nth-child(17):checked ~ .tabbed-labels > :nth-child(17), - .md-typeset .no-js .tabbed-set > input:nth-child(18):checked ~ .tabbed-labels > :nth-child(18), - .md-typeset .no-js .tabbed-set > input:nth-child(19):checked ~ .tabbed-labels > :nth-child(19), - .md-typeset .no-js .tabbed-set > input:nth-child(2):checked ~ .tabbed-labels > :nth-child(2), - .md-typeset .no-js .tabbed-set > input:nth-child(20):checked ~ .tabbed-labels > :nth-child(20), - .md-typeset .no-js .tabbed-set > input:nth-child(3):checked ~ .tabbed-labels > :nth-child(3), - .md-typeset .no-js .tabbed-set > input:nth-child(4):checked ~ .tabbed-labels > :nth-child(4), - .md-typeset .no-js .tabbed-set > input:nth-child(5):checked ~ .tabbed-labels > :nth-child(5), - .md-typeset .no-js .tabbed-set > input:nth-child(6):checked ~ .tabbed-labels > :nth-child(6), - .md-typeset .no-js .tabbed-set > input:nth-child(7):checked ~ .tabbed-labels > :nth-child(7), - .md-typeset .no-js .tabbed-set > input:nth-child(8):checked ~ .tabbed-labels > :nth-child(8), - .md-typeset .no-js .tabbed-set > input:nth-child(9):checked ~ .tabbed-labels > :nth-child(9), - .no-js .md-typeset .tabbed-set > input:first-child:checked ~ .tabbed-labels > :first-child, - .no-js .md-typeset .tabbed-set > input:nth-child(10):checked ~ .tabbed-labels > :nth-child(10), - .no-js .md-typeset .tabbed-set > input:nth-child(11):checked ~ .tabbed-labels > :nth-child(11), - .no-js .md-typeset .tabbed-set > input:nth-child(12):checked ~ .tabbed-labels > :nth-child(12), - .no-js .md-typeset .tabbed-set > input:nth-child(13):checked ~ .tabbed-labels > :nth-child(13), - .no-js .md-typeset .tabbed-set > input:nth-child(14):checked ~ .tabbed-labels > :nth-child(14), - .no-js .md-typeset .tabbed-set > input:nth-child(15):checked ~ .tabbed-labels > :nth-child(15), - .no-js .md-typeset .tabbed-set > input:nth-child(16):checked ~ .tabbed-labels > :nth-child(16), - .no-js .md-typeset .tabbed-set > input:nth-child(17):checked ~ .tabbed-labels > :nth-child(17), - .no-js .md-typeset .tabbed-set > input:nth-child(18):checked ~ .tabbed-labels > :nth-child(18), - .no-js .md-typeset .tabbed-set > input:nth-child(19):checked ~ .tabbed-labels > :nth-child(19), - .no-js .md-typeset .tabbed-set > input:nth-child(2):checked ~ .tabbed-labels > :nth-child(2), - .no-js .md-typeset .tabbed-set > input:nth-child(20):checked ~ .tabbed-labels > :nth-child(20), - .no-js .md-typeset .tabbed-set > input:nth-child(3):checked ~ .tabbed-labels > :nth-child(3), - .no-js .md-typeset .tabbed-set > input:nth-child(4):checked ~ .tabbed-labels > :nth-child(4), - .no-js .md-typeset .tabbed-set > input:nth-child(5):checked ~ .tabbed-labels > :nth-child(5), - .no-js .md-typeset .tabbed-set > input:nth-child(6):checked ~ .tabbed-labels > :nth-child(6), - .no-js .md-typeset .tabbed-set > input:nth-child(7):checked ~ .tabbed-labels > :nth-child(7), - .no-js .md-typeset .tabbed-set > input:nth-child(8):checked ~ .tabbed-labels > :nth-child(8), - .no-js .md-typeset .tabbed-set > input:nth-child(9):checked ~ .tabbed-labels > :nth-child(9) { - border-color: var(--darkreader-border--md-accent-fg-color); - } -} -.md-typeset .tabbed-set > input:first-child.focus-visible ~ .tabbed-labels > :first-child, -.md-typeset .tabbed-set > input:nth-child(10).focus-visible ~ .tabbed-labels > :nth-child(10), -.md-typeset .tabbed-set > input:nth-child(11).focus-visible ~ .tabbed-labels > :nth-child(11), -.md-typeset .tabbed-set > input:nth-child(12).focus-visible ~ .tabbed-labels > :nth-child(12), -.md-typeset .tabbed-set > input:nth-child(13).focus-visible ~ .tabbed-labels > :nth-child(13), -.md-typeset .tabbed-set > input:nth-child(14).focus-visible ~ .tabbed-labels > :nth-child(14), -.md-typeset .tabbed-set > input:nth-child(15).focus-visible ~ .tabbed-labels > :nth-child(15), -.md-typeset .tabbed-set > input:nth-child(16).focus-visible ~ .tabbed-labels > :nth-child(16), -.md-typeset .tabbed-set > input:nth-child(17).focus-visible ~ .tabbed-labels > :nth-child(17), -.md-typeset .tabbed-set > input:nth-child(18).focus-visible ~ .tabbed-labels > :nth-child(18), -.md-typeset .tabbed-set > input:nth-child(19).focus-visible ~ .tabbed-labels > :nth-child(19), -.md-typeset .tabbed-set > input:nth-child(2).focus-visible ~ .tabbed-labels > :nth-child(2), -.md-typeset .tabbed-set > input:nth-child(20).focus-visible ~ .tabbed-labels > :nth-child(20), -.md-typeset .tabbed-set > input:nth-child(3).focus-visible ~ .tabbed-labels > :nth-child(3), -.md-typeset .tabbed-set > input:nth-child(4).focus-visible ~ .tabbed-labels > :nth-child(4), -.md-typeset .tabbed-set > input:nth-child(5).focus-visible ~ .tabbed-labels > :nth-child(5), -.md-typeset .tabbed-set > input:nth-child(6).focus-visible ~ .tabbed-labels > :nth-child(6), -.md-typeset .tabbed-set > input:nth-child(7).focus-visible ~ .tabbed-labels > :nth-child(7), -.md-typeset .tabbed-set > input:nth-child(8).focus-visible ~ .tabbed-labels > :nth-child(8), -.md-typeset .tabbed-set > input:nth-child(9).focus-visible ~ .tabbed-labels > :nth-child(9) { - background-color: var(--darkreader-bg--md-accent-fg-color--transparent, #181a1b); -} -:root { - --darkreader-bgimg--md-tasklist-icon: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMSAxMkMxIDUuOTI1IDUuOTI1IDEgMTIgMXMxMSA0LjkyNSAxMSAxMS00LjkyNSAxMS0xMSAxMVMxIDE4LjA3NSAxIDEyem0xNi4yOC0yLjcyYS43NS43NSAwIDAgMC0xLjA2LTEuMDZsLTUuOTcgNS45Ny0yLjQ3LTIuNDdhLjc1Ljc1IDAgMCAwLTEuMDYgMS4wNmwzIDNhLjc1Ljc1IDAgMCAwIDEuMDYgMGw2LjUtNi41eiIvPjwvc3ZnPg=="); - --darkreader-bgimg--md-tasklist-icon--checked: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMSAxMkMxIDUuOTI1IDUuOTI1IDEgMTIgMXMxMSA0LjkyNSAxMSAxMS00LjkyNSAxMS0xMSAxMVMxIDE4LjA3NSAxIDEyem0xNi4yOC0yLjcyYS43NS43NSAwIDAgMC0xLjA2LTEuMDZsLTUuOTcgNS45Ny0yLjQ3LTIuNDdhLjc1Ljc1IDAgMCAwLTEuMDYgMS4wNmwzIDNhLjc1Ljc1IDAgMCAwIDEuMDYgMGw2LjUtNi41eiIvPjwvc3ZnPg=="); -} -.md-typeset .task-list-indicator::before { - background-color: var(--darkreader-bg--md-default-fg-color--lightest, #181a1b); -} -.md-typeset [type="checkbox"]:checked + .task-list-indicator::before { - background-color: rgb(43, 255, 152); -} -:root > * { - --md-mermaid-edge-color: var(--md-code-fg-color); - --md-mermaid-font-family: var(--md-text-font-family),sans-serif; - --md-mermaid-label-bg-color: var(--md-default-bg-color); - --md-mermaid-label-fg-color: var(--md-code-fg-color); - --md-mermaid-node-bg-color: var(--md-accent-fg-color--transparent); - --md-mermaid-node-fg-color: var(--md-accent-fg-color); -} -a { - color: rgb(94, 165, 234); -} -a:hover { - color: rgb(102, 177, 250); -} -a:active { - color: rgb(249, 146, 97); -} -* { - -webkit-tap-highlight-color: transparent; -} -table.sortable thead { - background-color: rgb(34, 37, 38); - color: rgb(168, 160, 149); -} -hr { - border-bottom-color: rgb(62, 68, 70); - border-left: 0px; - border-right: 0px; - border-top: 0px; -} -.dashed { - border-bottom-color: rgb(62, 68, 70); -} -.form-area { - background-color: rgb(27, 29, 30); - background-image: initial; - border-color: rgb(62, 68, 70); -} -footer { - color: rgb(152, 143, 129); -} -body { - background-color: rgb(27, 29, 30); - background-image: initial; - color: rgb(232, 230, 227); -} -header { - background-color: rgb(13, 14, 14); - background-image: initial; - color: rgb(178, 172, 162); -} -#user-links:hover { - border-color: rgb(140, 130, 115); - color: rgb(232, 230, 227); -} -#nav-shadow { - background-color: initial; - background-image: linear-gradient(rgb(49, 53, 55), rgba(0, 0, 0, 0)); -} -#nav-container { - background-color: rgb(24, 26, 27); - background-image: initial; -} -nav ul { - background-color: transparent; - background-image: initial; - list-style-image: initial; -} -nav ul li { - color: rgb(232, 230, 227); -} -nav ul li.home-nav-element a:hover { - border-bottom: none; -} -nav ul li a, -nav ul li button { - color: rgb(232, 230, 227); - text-decoration-color: initial; -} -nav ul li a:link, -nav ul li button:link { - color: rgb(232, 230, 227); -} -nav ul li a:hover, -nav ul li button:hover { - background-color: rgba(24, 26, 27, 0.25); - background-image: initial; - border-top-color: rgb(199, 70, 8); - color: rgb(232, 230, 227); -} -nav ul li a.active, -nav ul li button.active { - border-top-color: rgb(199, 70, 8); - color: rgb(249, 146, 97); -} -nav ul li ul { - background-color: rgb(24, 26, 27); - background-image: initial; - box-shadow: rgba(0, 0, 0, 0.4) 2px 2px 4px; - color: rgb(232, 230, 227); -} -nav ul li ul li:hover { - background-color: rgb(49, 53, 55); - background-image: initial; -} -nav ul li ul li a { - color: rgb(232, 230, 227) !important; -} -nav ul li ul li a, -nav ul li ul li button { - border-left-color: rgb(140, 130, 115); -} -nav ul li button { - background-color: initial; - background-image: none; - border-color: initial; - border-style: none; - border-width: initial; -} -nav ul li.home-nav-element a:hover { - background-color: transparent; - background-image: initial; - border-bottom: 0px; -} -hr { - color: rgba(232, 230, 227, 0.2); -} -#content .title { - color: rgb(199, 194, 187); -} -footer { - background-color: rgb(34, 37, 38); - background-image: initial; - border-top-color: rgb(62, 68, 70); -} -a { - text-decoration-color: initial; -} -noscript #noscript { - background-color: rgb(139, 0, 0); - background-image: initial; - color: rgb(232, 230, 227); -} -#announcement { - background-color: rgb(139, 0, 0); - background-image: initial; - color: rgb(232, 230, 227); -} -#announcement a { - color: rgb(255, 174, 26); -} -.time { - color: rgb(178, 172, 162); -} -#form-errors, -.form-errors { - background-color: rgba(204, 0, 0, 0.3); - background-image: initial; - border-color: rgb(179, 0, 0); -} -#nav-placeholder { - background-color: rgb(24, 26, 27); - background-image: initial; - border-left-color: rgb(62, 68, 70); - border-right-color: rgb(62, 68, 70); -} -#contest-info a { - color: rgb(232, 230, 227); -} -#contest-info-main { - background-color: rgba(0, 0, 0, 0.77); - background-image: initial; - border-left-color: rgb(48, 52, 54); - color: rgb(232, 230, 227); -} -.contest-info-toggle-mode-on { - background-color: rgba(0, 164, 0, 0.57); - background-image: initial; -} -.contest-info-toggle-mode-on:hover { - background-color: rgba(0, 164, 0, 0.97); - background-image: initial; -} -.contest-info-toggle-mode-off { - background-color: rgba(204, 0, 0, 0.57); - background-image: initial; -} -.contest-info-toggle-mode-off:hover { - background-color: rgba(204, 0, 0, 0.97); - background-image: initial; -} -#page-container { - border-left-color: rgb(62, 68, 70); - border-right-color: rgb(62, 68, 70); -} -@media (max-width: 1498px) { - #page-container { - border-left: none; - border-right: none; - } -} -@media (max-width: 799px) { - #navicon { - color: rgb(129, 175, 255); - } - #navicon.hover { - color: rgb(80, 184, 254); - text-shadow: rgb(24, 26, 27) 0px 0px 5px; - } - #nav-list { - background-color: rgb(24, 26, 27); - background-image: initial; - border-color: initial; - box-shadow: none; - } -} -#notification { - color: rgb(164, 192, 217); -} -#notification:hover { - color: rgb(178, 171, 161); -} -#chat-icon { - color: rgb(200, 196, 189); -} -#chat-icon:hover { - color: rgb(249, 146, 97); -} -#nav-lang-icon { - color: rgb(51, 125, 255); -} -#nav-lang-icon:hover { - color: rgb(121, 170, 255); -} -#nav-darkmode-icon:hover { - color: rgb(152, 143, 129); -} -.dropdown { - background-color: rgb(24, 26, 27); - box-shadow: rgba(0, 0, 0, 0.2) 0px 8px 16px 0px; -} -.dropdown a { - color: rgb(232, 230, 227); - text-decoration-color: initial; -} -.dropdown-item { - border-top-color: rgb(62, 68, 70); - color: rgb(232, 230, 227); -} -.dropdown-item:hover { - background-color: rgb(31, 31, 17); - color: rgb(249, 146, 97); -} -.popper-arrow, -.popper-arrow::before { - background-color: inherit; - background-image: inherit; -} -.unread_boxes { - background-color: rgb(204, 0, 0); - color: rgb(232, 230, 227); -} -.sub-lang { - color: rgb(232, 230, 227); -} -.notification-open #notification { - color: rgb(114, 255, 114) !important; -} -.title-row { - color: rgb(199, 194, 187); -} -.gray { - color: rgb(152, 143, 129); -} -.white { - color: rgb(232, 230, 227); -} -.black { - color: rgb(232, 230, 227); -} -.red { - color: rgb(255, 26, 26); -} -.green { - color: rgb(114, 255, 114); -} -.grayed { - color: rgb(168, 160, 149); -} -.darkcyan { - color: rgb(107, 255, 255); -} -.peru { - color: rgb(209, 144, 80); -} -.blue { - color: rgb(51, 125, 255); -} -.background-d6e8f7 { - background-color: rgb(38, 41, 43); -} -.background-bisque { - background-color: rgb(86, 47, 0); -} -.background-royalblue { - background-color: rgb(25, 58, 158) !important; -} -.background-green { - background-color: rgb(32, 134, 55) !important; -} -.background-red { - background-color: rgb(165, 29, 42) !important; -} -.background-footer { - color: rgb(152, 143, 129); -} -#loading-bar { - background-color: rgb(125, 44, 5); -} -.anon a { - color: rgb(232, 230, 227); -} -@media (min-width: 800px) { - #page-container { - background-color: rgb(32, 34, 36); - background-image: initial; - } - #content.wrapper { - background-color: rgb(24, 26, 27); - background-image: initial; - } -} -.colored-text { - color: rgb(232, 230, 227); -} -::-webkit-input-placeholder { - color: rgb(249, 146, 97); -} -::placeholder { - color: rgb(249, 146, 97); -} -input::-webkit-input-placeholder { - color: rgb(249, 146, 97); -} -input::placeholder { - color: rgb(249, 146, 97); -} -::-webkit-input-placeholder { - color: rgb(249, 146, 97); -} -.nav-fa-icon i { - color: rgb(232, 230, 227); -} -.nav-fa-icon-active i { - color: rgb(249, 146, 97); -} -.table { - background-color: rgba(0, 0, 0, 0.01); - background-image: initial; -} -.table.striped tr:nth-child(2n) { - background-color: rgb(29, 31, 32); - background-image: initial; -} -.table.striped tr:nth-child(2n+1) { - background-color: rgb(24, 26, 27); - background-image: initial; -} -.table.no-border td, -.table.no-border th { - border-color: initial; - border-style: none; - border-width: initial; -} -.table td:first-child { - border-color: rgb(62, 68, 70); -} -.table tr:last-child td { - border-color: rgb(62, 68, 70); -} -.table th { - background-color: rgb(174, 132, 26); - border-color: rgb(62, 68, 70); - color: rgb(232, 230, 227); -} -.table td { - border-color: rgb(62, 68, 70); -} -#users-table th a { - color: rgb(232, 230, 227); -} -.AB { - background-color: rgb(53, 57, 59); - color: rgb(232, 230, 227); -} -.AC { - background-color: rgb(0, 102, 0); - color: rgb(232, 230, 227); -} -._AC { - background-color: rgb(93, 132, 0); - color: rgb(232, 230, 227); -} -.WA { - background-color: rgb(204, 0, 0); - color: rgb(232, 230, 227); -} -.TLE, -.MLE { - background-color: rgb(53, 57, 59); - color: rgb(232, 230, 227); -} -.OLE, -.IR, -.RTE, -.OTH { - background-color: rgb(136, 94, 3); - color: rgb(232, 230, 227); -} -.CE { - background-color: rgb(53, 57, 59); - color: rgb(232, 230, 227); -} -.IE { - background-color: rgb(204, 0, 0); - color: rgb(232, 230, 227); -} -.QU, -.G { - background-color: rgb(24, 26, 27); - background-image: initial; - color: rgb(232, 230, 227); -} -.judge-online { - color: rgb(100, 196, 97); -} -.judge-offline { - color: rgb(225, 55, 55); -} -.middle-content .post { - border-color: rgb(76, 83, 86) rgb(84, 91, 94) rgb(84, 91, 94); -} -.middle-content .post .title a { - color: rgb(255, 114, 114) !important; -} -.middle-content .post .title a:hover { - color: rgb(255, 70, 70) !important; -} -.left-sidebar-item.active { - background-color: rgb(125, 44, 5); - color: rgb(232, 230, 227); -} -.left-sidebar-item.active .sidebar-icon { - color: rgb(232, 230, 227); -} -.blog-sidebox .contest { - border-bottom-color: rgb(62, 68, 70); -} -.blog-sidebox .contest:last-child { - border-bottom: none; -} -.blog-sidebox .contest .name a { - color: rgb(104, 149, 191) !important; -} -.blog-sidebox .contest .name a:hover { - color: rgb(102, 177, 250) !important; -} -.no-dot-blog-sidebox ul { - list-style-image: initial; -} -.blog-comment-count-link { - color: rgb(178, 172, 162); -} -.rssatom span { - background-color: initial; - background-image: linear-gradient(135deg, rgb(175, 79, 22) 0px, rgb(169, 90, 3) 47%, rgb(175, 79, 22) 100%); - border-color: rgb(174, 78, 16); - color: rgb(232, 230, 227); -} -.blog-box { - background-color: rgb(24, 26, 27); - border-bottom-color: rgb(60, 65, 68); - border-top-color: rgb(60, 65, 68); - box-shadow: rgba(0, 0, 0, 0.2) 0px 0px 5px; -} -.blog-box:hover, -.blog-box:not(.pre-expand-blog) { - border-color: rgb(81, 88, 91); - box-shadow: rgba(0, 0, 0, 0.1) 0px 0px 2px; -} -.problem-feed-name a { - color: rgb(102, 177, 250); -} -.problem-feed-types { - color: rgb(152, 143, 129); -} -.left-sidebar-item { - color: rgb(232, 230, 227); -} -.left-sidebar-item:hover { - background-color: rgb(40, 43, 45); - color: rgb(232, 230, 227); -} -.left-sidebar-item.active:hover { - background-color: rgb(125, 44, 5); - color: rgb(232, 230, 227); -} -.sidebar-icon { - color: rgb(232, 230, 227); -} -.left-sidebar-header { - border-bottom-color: rgb(140, 130, 115); - color: rgb(232, 230, 227); -} -.show-more { - background-color: initial; - background-image: linear-gradient(rgba(0, 0, 0, 0), rgb(24, 26, 27)); - color: rgb(232, 230, 227); -} -.middle-right-content.wrapper { - background-color: rgb(24, 26, 27); - background-image: initial; -} -@media (max-width: 799px) { - .left-sidebar { - background-color: inherit; - background-image: inherit; - } -} -@media (min-width: 800px) { - .left-sidebar-item { - background-color: rgb(24, 26, 27); - border-color: rgb(60, 65, 68); - box-shadow: rgba(0, 0, 0, 0.1) 0px 0px 5px; - } - .left-sidebar::-webkit-scrollbar { - background-color: transparent; - } - .blog-box { - border-left-color: rgb(60, 65, 68); - border-right-color: rgb(60, 65, 68); - } -} -#problem-table tr:hover { - background-color: rgb(36, 39, 40); - background-image: initial; -} -ul.problem-list { - list-style-image: initial; -} -.solved-problem-color { - color: rgb(100, 196, 97); -} -.unsolved-problem-color { - color: rgb(225, 55, 55); -} -.attempted-problem-color { - color: rgb(255, 174, 26); -} -.submissions-left { - color: rgb(232, 230, 227); -} -.no-submissions-left { - color: rgb(255, 26, 26); -} -.organization-tag { - background-color: rgb(53, 57, 59); - color: initial; -} -.organization-tag a { - color: rgb(232, 230, 227); -} -.pdf-icon .pdf-icon-logo { - color: rgb(242, 59, 63); -} -.pdf-icon .pdf-icon-bar { - background-color: rgb(170, 11, 15); - background-image: initial; -} -.license a { - color: rgb(152, 143, 129); - text-decoration-color: initial; -} -#problem_submit #result-version-info { - border-bottom-color: rgb(78, 85, 88); - color: rgb(158, 150, 137); -} -#problem_submit #language-select2 .select2-results__option { - background-color: rgb(24, 26, 27) !important; - background-image: initial !important; - color: rgb(158, 150, 137) !important; -} -#problem_submit #language-select2 .select2-results__option--highlighted { - text-decoration-color: initial; -} -#problem_submit #language-select2 .select2-results__option[aria-selected="true"] { - color: rgb(232, 230, 227) !important; -} -#problem-table th a { - color: inherit; -} -.problem-data-form .bad-file input, -.problem-data-form .bad-file .select2-selection { - border-color: rgb(179, 0, 0); -} -.problem-clarification { - border-bottom-color: rgb(62, 68, 70); -} -#clarification_header { - color: rgb(255, 26, 26); -} -#clarification_header:hover { - color: rgb(255, 174, 26); -} -#comment-announcement { - background-color: rgb(49, 53, 55); - color: rgb(166, 158, 146); -} -#comment-announcement:hover { - background-color: rgb(96, 104, 108); -} -.new-problem-info { - background-color: rgb(54, 39, 0); - border-color: rgb(140, 130, 115); -} -.admin a, -.admin { - color: rgb(232, 230, 227) !important; -} -svg.rate-box circle { - fill: none; -} -svg.rate-box.rate-newbie circle { - stroke: rgb(168, 160, 149); -} -svg.rate-box.rate-newbie path { - fill: rgb(168, 160, 149); -} -svg.rate-box.rate-amateur circle { - stroke: rgb(86, 255, 86); -} -svg.rate-box.rate-amateur path { - fill: rgb(86, 255, 86); -} -svg.rate-box.rate-specialist circle { - stroke: rgb(87, 252, 242); -} -svg.rate-box.rate-specialist path { - fill: rgb(87, 252, 242); -} -svg.rate-box.rate-expert circle { - stroke: rgb(97, 155, 255); -} -svg.rate-box.rate-expert path { - fill: rgb(97, 155, 255); -} -svg.rate-box.rate-candidate-master circle { - stroke: rgb(255, 97, 255); -} -svg.rate-box.rate-candidate-master path { - fill: rgb(255, 97, 255); -} -svg.rate-box.rate-master circle { - stroke: rgb(255, 239, 49); -} -svg.rate-box.rate-master path { - fill: rgb(255, 239, 49); -} -svg.rate-box.rate-grandmaster circle, -svg.rate-box.rate-target circle { - stroke: rgb(255, 37, 37); -} -svg.rate-box.rate-grandmaster path, -svg.rate-box.rate-target path { - fill: rgb(255, 37, 37); -} -svg.rate-box.rate-target circle:last-child { - fill: rgb(255, 37, 37); - stroke: none; -} -.rate-none, -.rate-none a { - color: rgb(232, 230, 227); -} -.rate-newbie, -.rate-newbie a { - color: rgb(168, 160, 149); -} -.rate-amateur, -.rate-amateur a { - color: rgb(86, 255, 86); -} -.rate-specialist, -.rate-specialist a { - color: rgb(107, 255, 255); -} -.rate-expert, -.rate-expert a { - color: rgb(51, 125, 255); -} -.rate-candidate-master, -.rate-candidate-master a { - color: rgb(255, 85, 255); -} -.rate-master, -.rate-master a { - color: rgb(255, 152, 26); -} -.rate-grandmaster, -.rate-grandmaster a, -.rate-target, -.rate-target a { - color: rgb(255, 37, 37); -} -.rate-group { - color: rgb(232, 230, 227); -} -#users-table th a, -#users-table th a:link, -#users-table th a:visited { - color: rgb(232, 230, 227); -} -#users-table th a:hover { - color: rgb(255, 211, 147); -} -#users-table tr:hover { - background-color: rgb(36, 39, 40); - background-image: initial; -} -#users-table tr.highlight { - background-color: rgb(85, 79, 0); - background-image: initial; -} -#users-table tr:target { - background-color: rgb(85, 79, 0); - background-image: initial; -} -#users-table .organization-column a { - color: rgb(152, 143, 129) !important; -} -#users-table .disqualified { - background-color: rgb(103, 0, 0) !important; -} -#users-table .frozen { - background-color: rgb(5, 77, 121) !important; - background-image: initial !important; -} -#users-table .full-score, -#users-table .full-score a { - color: rgb(114, 255, 114); -} -#users-table .partial-score, -#users-table .partial-score a { - color: rgb(114, 255, 114); -} -#users-table .failed-score, -#users-table .failed-score a { - color: rgb(255, 26, 26); -} -#users-table .pretest-full-score, -#users-table .pretest-full-score a { - color: rgb(84, 164, 217); -} -#users-table .pretest-partial-score, -#users-table .pretest-partial-score a { - color: rgb(84, 164, 217); -} -#users-table .pretest-failed-score, -#users-table .pretest-failed-score a { - color: rgb(255, 26, 26); -} -#users-table .user-points { - color: rgb(232, 230, 227); -} -#users-table .solving-time { - color: rgb(152, 143, 129); -} -#users-table .point-denominator { - border-top-color: rgb(84, 91, 94); -} -#users-table .fullname-column { - border-right: none !important; -} -#users-table .fullname-column span { - color: rgb(152, 143, 129) !important; -} -#search-form .select2-results__option--highlighted { - background-color: rgb(43, 46, 48) !important; -} -a.user-redirect { - color: rgb(84, 164, 217); -} -a.user-redirect:hover { - text-shadow: rgb(0, 0, 204) 0px 0px 2px; -} -.user-info-cell { - border-left-color: rgb(62, 68, 70); -} -.contest-history-cell { - border-left-color: rgb(62, 68, 70); -} -.hide-solved-problems > span::before { - background-color: rgba(0, 0, 0, 0.2); - background-image: initial; -} -.user-img { - background-color: rgb(43, 47, 49); -} -.pp-table .pp-weighted { - color: rgb(157, 148, 136); -} -.pp-table div.sub-pp { - border-left: none; -} -#pp-load-link-wrapper { - border-color: rgb(62, 68, 70); -} -#rating-tooltip { - background-color: rgba(0, 0, 0, 0.7); - background-image: initial; - color: rgb(232, 230, 227); -} -#rating-tooltip.rate-group { - color: rgb(232, 230, 227); -} -.follow { - background-color: rgb(0, 102, 0); - background-image: initial; - border-color: rgb(19, 122, 19); -} -.follow:hover { - background-color: rgb(0, 80, 0); - background-image: initial; -} -.unfollow { - background-color: rgb(204, 0, 0); - background-image: initial; - border-color: rgb(121, 0, 21); -} -.unfollow:hover { - background-color: rgb(111, 0, 0); - background-image: initial; -} -#submission-activity #submission-activity-actions #year { - color: rgb(189, 183, 175); -} -#submission-activity #submission-activity-display { - border-color: rgb(62, 68, 70); -} -#submission-activity #submission-activity-display .info-text { - color: rgb(189, 183, 175); -} -#submission-activity #submission-activity-display table td.activity-blank { - background-color: rgb(24, 26, 27); -} -#submission-activity #submission-activity-display table td.activity-0 { - background-color: rgb(43, 47, 49); -} -#submission-activity #submission-activity-display table td.activity-1 { - background-color: rgb(22, 102, 52); -} -#submission-activity #submission-activity-display table td.activity-2 { - background-color: rgb(47, 154, 95); -} -#submission-activity #submission-activity-display table td.activity-3 { - background-color: rgb(38, 125, 61); -} -#submission-activity #submission-activity-display table td.activity-4 { - background-color: rgb(26, 88, 46); -} -.user-info-header { - color: rgb(152, 143, 129); -} -.user-stat-header { - color: rgb(152, 143, 129); -} -.profile-card { - border-color: rgb(58, 62, 65); - box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 8px; -} -.profile-card:hover { - box-shadow: rgba(0, 0, 0, 0.2) 0px 8px 16px; -} -.profile-card .card-header { - background-color: rgb(29, 31, 32); -} -.profile-card .medal-count { - background-color: rgba(37, 40, 42, 0.7); - color: rgb(232, 230, 227); -} -.content-description pre, -.content-description code, -.content-description kbd, -.content-description samp, -.content-description span.code { - color: rgb(232, 230, 227); -} -.content-description code, -.content-description span.code { - background-color: var(--darkreader-bg--md-code-bg-color, #181a1b); - color: var(--darkreader-text--md-code-fg-color, #e8e6e3); -} -.content-description pre { - background-color: var(--darkreader-bg--md-code-bg-color, #181a1b); - color: var(--darkreader-text--md-code-fg-color, #e8e6e3); -} -.content-description pre code, -.content-description pre div.code { - background-color: transparent; - background-image: initial; - border-color: initial; - border-style: initial; - border-width: 0px; - color: var(--darkreader-text--md-code-fg-color, #e8e6e3); -} -.content-description pre.no-border { - background-color: inherit; - border-color: initial; - border-style: none; - border-width: initial; -} -.content-description ins { - background-color: rgb(84, 84, 0); - background-image: initial; - color: rgb(232, 230, 227); - text-decoration-color: initial; -} -.content-description mark { - background-color: rgb(153, 153, 0); - background-image: initial; - color: rgb(232, 230, 227); -} -.content-description img { - border-color: initial; - border-style: initial; - border-width: 0px; -} -.codehilitetable pre { - background-color: rgba(35, 38, 39, 0.5); -} -.codehilitetable .linenos pre { - background-color: rgba(0, 0, 0, 0.07); - border-right: 0px; - color: rgba(232, 230, 227, 0.26); -} -.info-float .fa { - color: rgb(232, 230, 227); -} -.tweet-this i { - color: rgb(90, 176, 238); -} -.facebook-this it { - color: rgb(132, 183, 237); -} -.gplus-this i { - color: rgb(224, 90, 72); -} -.button, -button, -input[type="submit"] { - background-color: rgb(125, 44, 5); - border-color: transparent; - box-shadow: rgba(0, 0, 0, 0.02) 0px 1px 3px 0px; - color: rgb(232, 230, 227) !important; - text-decoration-color: initial; -} -.button.disabled, -.button[disabled], -button.disabled, -button[disabled], -input[type="submit"].disabled, -input[type="submit"][disabled] { - background-color: initial !important; - background-image: linear-gradient(rgb(73, 79, 82) 0px, rgb(96, 104, 108) 100%) !important; - border-color: rgb(84, 91, 94) !important; -} -.button.btn-gray, -button.btn-gray, -input[type="submit"].btn-gray { - background-color: rgb(96, 104, 108); - background-image: initial; -} -.button.btn-hovergray:hover, -button.btn-hovergray:hover, -input[type="submit"].btn-hovergray:hover { - background-color: rgb(49, 53, 55); - background-image: initial; -} -.button.btn-green, -button.btn-green, -input[type="submit"].btn-green { - background-color: rgb(32, 134, 55); - background-image: initial; -} -.button.btn-green:hover, -button.btn-green:hover, -input[type="submit"].btn-green:hover { - background-color: rgb(0, 102, 0); - background-image: initial; -} -.button.btn-darkred, -button.btn-darkred, -input[type="submit"].btn-darkred { - background-color: rgb(111, 0, 0); - background-image: initial; -} -.button.btn-darkred:hover, -button.btn-darkred:hover, -input[type="submit"].btn-darkred:hover { - background-color: rgb(132, 34, 34); - background-image: initial; -} -.button.btn-midnightblue, -button.btn-midnightblue, -input[type="submit"].btn-midnightblue { - background-color: rgb(20, 20, 90); - background-image: initial; -} -.button.btn-midnightblue:hover, -button.btn-midnightblue:hover, -input[type="submit"].btn-midnightblue:hover { - background-color: rgb(0, 0, 111); - background-image: initial; -} -.button.btn-darkGreen, -button.btn-darkGreen, -input[type="submit"].btn-darkGreen { - background-color: rgb(125, 44, 5); - background-image: initial; -} -.button:hover, -button:hover, -input[type="submit"]:hover { - background-color: rgb(125, 44, 5); - box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px; -} -.button:focus, -button:focus, -input[type="submit"]:focus { - background-color: rgb(125, 44, 5); - box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px; -} -.button:active, -button:active, -input[type="submit"]:hover { - background-color: rgb(125, 44, 5); - box-shadow: rgba(0, 0, 0, 0.06) 0px 2px 4px; -} -input[type="text"], -input[type="password"], -input[type="email"], -input[type="number"], -input[type="datetime-local"], -input[type="date"] { - background-color: rgb(24, 26, 27); - background-image: none; - border-color: rgb(62, 68, 70); - box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 1px inset; - color: rgb(178, 172, 162); -} -textarea { - background-color: rgb(24, 26, 27); - background-image: none; - border-color: rgb(62, 68, 70); - box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 1px inset; -} -textarea:hover { - border-color: rgb(140, 130, 115); -} -input[type="text"]:hover, -input[type="password"]:hover { - border-color: rgba(16, 87, 144, 0.8); - box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 1px inset, rgba(16, 91, 150, 0.6) 0px 0px 4px; -} -textarea:focus { - border-color: rgb(140, 130, 115); - outline-color: initial; -} -input[type="text"]:focus, -input[type="password"]:focus { - border-color: rgba(16, 87, 144, 0.8); - box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 1px inset, rgba(16, 91, 150, 0.6) 0px 0px 8px; - outline-color: initial; -} -.btn-clipboard:hover { - background-color: rgb(24, 26, 27); - border-color: rgb(55, 60, 62); -} -.ul_tab_a_active, -.tabs > ul > li.active > a:focus, -.tabs > ul > li.active > span:focus, -.tabs > ul > li.active > a:hover, -.tabs > ul > li.active > span:hover, -.tabs > ul > li.active > a, -.tabs > ul > li.active > span { - background-color: transparent; - background-image: initial; - border-bottom-color: rgb(199, 70, 8); - color: rgb(249, 146, 97); -} -.tabs { - border-bottom-color: rgb(62, 68, 70); -} -.tabs .tab .tab-icon { - color: rgb(152, 143, 129); -} -.tabs .tab.active a, -.tabs .tab.active span { - border-top-color: rgb(48, 52, 54) !important; -} -.tabs .tab.active .tab-icon { - color: rgb(232, 230, 227); -} -.tabs h2 { - color: rgb(199, 194, 187); -} -.tabs > ul { - list-style-image: none; -} -.tabs > ul::-webkit-scrollbar { - background-color: transparent; -} -.tabs > ul::-webkit-scrollbar-thumb { - background-color: transparent; -} -.tabs > ul > li > a, -.tabs > ul > li > span { - color: rgb(178, 172, 162); - text-decoration-color: initial; -} -.tabs > ul > li > a:hover, -.tabs > ul > li > span:hover { - border-bottom-color: rgb(0, 217, 0); -} -ul.pagination a:hover { - background-color: rgb(163, 62, 18); - background-image: initial; - color: rgb(232, 230, 227); -} -ul.pagination > li > a, -ul.pagination > li > span { - background-color: rgb(24, 26, 27); - border-color: rgb(199, 70, 8); - color: rgb(249, 146, 97); - text-decoration-color: initial; -} -ul.pagination > .disabled-page > a { - background-color: rgb(137, 78, 57); - border-color: rgb(199, 68, 21); - color: rgb(223, 220, 215); -} -ul.pagination > .disabled-page > span { - background-color: rgb(137, 78, 57); - border-color: rgb(199, 68, 21); - color: rgb(223, 220, 215); -} -ul.pagination > .active-page > a { - background-color: rgb(125, 44, 5); - border-color: transparent; - color: rgb(232, 230, 227); -} -ul.pagination > .active-page > span { - background-color: rgb(24, 26, 27); - border-color: transparent; - color: rgb(232, 230, 227); -} -.alert { - border-color: transparent; -} -.alert-info { - background-color: rgb(14, 48, 65); - border-color: rgb(22, 90, 104); - color: rgb(117, 178, 208); -} -.alert-warning { - background-color: rgb(47, 40, 5); - border-color: rgb(108, 76, 11); - color: rgb(198, 171, 123); -} -.alert-danger { - background-color: rgb(56, 22, 22); - border-color: rgb(89, 35, 43); - color: rgb(194, 102, 100); -} -.alert-dismissable .close, -.alert-dismissible .close { - color: inherit; -} -.close { - color: rgb(232, 230, 227); - text-shadow: rgb(24, 26, 27) 0px 1px 0px; -} -a.close { - text-decoration-color: initial !important; -} -a.close:hover { - color: rgb(232, 230, 227) !important; -} -.close:focus, -.close:hover { - color: rgb(232, 230, 227); - text-decoration-color: initial; -} -.badge { - background-color: rgb(155, 19, 19); - color: rgb(232, 230, 227); -} -.form-submit-group { - border-top-color: rgb(53, 57, 59); -} -.sidebox h3 { - background-color: rgb(24, 26, 27); - background-image: initial; -} -.sidebox h3 .fa { - background-color: rgb(125, 44, 5); - background-image: initial; - color: rgb(232, 230, 227); -} -.sidebox-content { - background-color: rgb(24, 26, 27); - background-image: initial; - border-top: none; -} -.sidebox-content.sidebox-table { - border-color: initial; - border-style: none; - border-width: initial; -} -.sidebox { - box-shadow: rgba(0, 0, 0, 0.2) 0px 0px 5px; -} -.ws-closed { - background-color: rgb(139, 0, 0); - background-image: initial; -} -.ws-closed a { - color: rgb(232, 230, 227); -} -.messages li { - border-color: transparent; -} -.messages li.debug { - background-color: rgb(40, 43, 44); - border-color: rgb(59, 64, 66); - color: rgb(194, 188, 180); -} -.messages li.info { - background-color: rgb(20, 59, 67); - border-color: rgb(30, 89, 97); - color: rgb(142, 227, 241); -} -.messages li.success { - background-color: rgb(26, 62, 41); - border-color: rgb(37, 90, 50); - color: rgb(153, 230, 171); -} -.messages li.warning { - background-color: rgb(61, 46, 0); - border-color: rgb(123, 92, 0); - color: rgb(251, 215, 112); -} -.messages li.error { - background-color: rgb(67, 12, 17); - border-color: rgb(104, 18, 27); - color: rgb(225, 134, 143); -} -.spoiler-text { - background-color: rgb(34, 36, 38); - background-image: initial; - border-color: rgb(140, 130, 115); -} -.spoiler-summary { - text-decoration-color: initial; -} -.control-button { - border-color: initial; - border-style: initial; - border-width: 0px; - color: rgb(232, 230, 227) !important; -} -.control-button:hover { - background-color: rgb(96, 104, 108); - background-image: initial; -} -ul.errorlist { - color: rgb(255, 26, 26); - list-style-image: initial; -} -.registration-form .block-header { - color: rgb(178, 172, 162); -} -.registration-form .fullwidth-error input { - border-color: rgb(179, 0, 0); -} -.registration-form .form-field-error { - color: rgb(255, 26, 26); -} -.registration-form #edit-form { - background-color: unset; - background-image: unset; - border-color: unset; -} -#login-panel .google-icon i { - color: rgb(224, 90, 72); -} -#login-panel .facebook-icon i { - color: rgb(132, 183, 237); -} -#login-panel .github-icon i { - color: rgb(232, 230, 227); -} -.btn:hover { - color: rgb(209, 205, 199); - text-decoration-color: initial; -} -.link-row a { - color: inherit; - text-decoration-color: initial; -} -.link-row:hover { - background-color: rgb(31, 31, 17); - color: rgb(249, 146, 97); -} -button:hover, -button:focus { - box-shadow: none; - outline-color: initial; - text-decoration-color: initial; -} -.btn { - box-shadow: rgba(0, 0, 0, 0.12) 0px 10px 20px -6px; -} -.btn .icon { - background-color: rgb(24, 26, 27); - background-image: initial; -} -.btn:hover, -.btn:active, -.btn:focus { - outline-color: initial; -} -.btn.btn-primary { - color: rgb(232, 230, 227); -} -.btn.btn-primary .icon i { - color: rgb(97, 217, 124); -} -.btn.btn-disabled { - background-color: rgb(96, 104, 108); - background-image: initial; - border-color: rgb(84, 91, 94); - color: rgb(232, 230, 227); -} -a.upvote-link, -a.downvote-link { - color: rgb(232, 230, 227); -} -a.voted { - text-shadow: rgb(0, 0, 0) 0px 0px 4px, rgb(0, 0, 204) 0px 0px 9px; -} -.comment-area .featherlight-edit .featherlight-content { - background-color: rgb(27, 29, 30); - background-image: initial; - border-color: rgb(62, 68, 70); -} -.comment-area .new-comments .comment-display { - background-color: rgb(27, 29, 30); - background-image: initial; - border-color: rgb(62, 68, 70); -} -.comment-area .new-comments .comment .detail .header { - border-bottom-color: rgb(82, 88, 92); - color: rgb(157, 148, 136); -} -.comment-area .previous-revision, -.comment-area .next-revision { - color: rgb(189, 183, 175); -} -.comment-area .new-comments .header i { - color: rgb(157, 148, 136) !important; -} -.comment-area .new-comments .comment:target > .comment-display { - border-color: rgb(34, 106, 153); -} -.comment-author { - color: rgb(200, 195, 188); -} -.comment-header { - background-color: rgba(0, 0, 0, 0.1); - background-image: initial; - border-color: rgb(62, 68, 70); - color: rgb(231, 229, 226); -} -.comment-edits:not(:empty) { - color: rgb(189, 183, 175); -} -.comment-operation .fa { - color: rgb(189, 183, 175); -} -.comment-box { - background-color: rgba(0, 0, 0, 0.01); - background-image: initial; - border-color: rgb(62, 68, 70); -} -.comment { - list-style-image: none; -} -.comment:target > .comment-box { - border-left-color: rgb(48, 52, 54); -} -.actionbar .actionbar-button { - background-color: rgb(49, 53, 55); - background-image: initial; -} -.actionbar .actionbar-button:hover { - background-color: rgb(73, 79, 82); - background-image: initial; -} -.actionbar .dislike-button { - border-left: 0px; -} -.actionbar .like-button.voted { - color: rgb(51, 125, 255); -} -.actionbar .dislike-button.voted { - color: rgb(255, 26, 26); -} -.actionbar .bookmarked { - color: rgb(248, 248, 80); -} -.submission-row { - background-color: rgb(24, 26, 27); - background-image: initial; - box-shadow: rgba(0, 0, 0, 0.1) 0px 2px 4px; -} -.submission-row .sub-result .language { - background-color: rgb(41, 44, 46); -} -.submission-row .sub-info .sub-problem:hover { - text-decoration-color: initial; -} -.submission-row .sub-testcase { - color: rgb(178, 172, 162); -} -#statistics-table tr:not(:first-child) td { - border-top-color: rgb(48, 52, 54) !important; -} -#statistics-table tr:not(:last-child) td:not(:last-child) { - border-right-color: rgb(48, 52, 54); -} -.submission-contest { - color: rgb(178, 172, 162); -} -.statistics-table .count { - color: rgb(232, 230, 227); -} -#test-cases .case-info { - border-color: rgb(34, 106, 153); - color: rgb(211, 207, 201); -} -#test-cases .case-output { - border-color: rgba(128, 119, 105, 0.15); - box-shadow: rgba(27, 29, 30, 0.15) 0px 1px 2px 0px; -} -#test-cases .testcases-table { - border-color: initial; -} -.overall-result-AC { - background-color: initial; - background-image: linear-gradient(45deg, rgb(68, 132, 0), rgb(0, 132, 102)); -} -.overall-result-WA { - background-color: initial; - background-image: linear-gradient(45deg, rgb(153, 153, 0), rgb(204, 0, 0)); -} -.overall-result-TLE { - background-color: initial; - background-image: linear-gradient(45deg, rgb(42, 45, 47), rgb(83, 91, 112)); -} -.overall-result-RTE, -.overall-result-MLE { - background-color: initial; - background-image: linear-gradient(45deg, rgb(67, 49, 3), rgb(198, 145, 0)); -} -.case-AC { - color: rgb(114, 255, 114); -} -.case-_AC { - color: rgb(255, 26, 26); -} -.case-WA { - color: rgb(255, 26, 26); -} -.case-TLE, -.case-SC { - color: rgb(152, 143, 129); -} -.case-MLE, -.case-OLE, -.case-RTE, -.case-IR { - color: rgb(255, 174, 26); -} -.source-wrap a:active .line .highlighter { - background-color: rgba(153, 127, 0, 0.48); - background-image: initial; -} -.submission-info .submission-date { - color: rgb(152, 143, 129); -} -.list-contest { - background-color: rgb(24, 26, 27); - background-image: initial; - box-shadow: rgb(49, 53, 55) 0px 1px 2px, rgb(49, 53, 55) 0px 1px 5px; -} -#contest-calendar th { - border-bottom-color: rgb(62, 68, 70); -} -#contest-calendar th.sun { - border-left-color: rgb(62, 68, 70); -} -#contest-calendar th.sun, -#contest-calendar th.mon, -#contest-calendar th.tue, -#contest-calendar th.wed, -#contest-calendar th.thu, -#contest-calendar th.fri, -#contest-calendar th.sat { - background-color: rgb(27, 29, 30); - background-image: initial; - border-right-color: rgb(62, 68, 70); -} -#contest-calendar td { - border-bottom-color: rgb(62, 68, 70); - border-right-color: rgb(62, 68, 70); - color: rgb(232, 230, 227); -} -#contest-calendar td .num { - border-bottom-color: rgb(62, 68, 70); -} -#contest-calendar td ul { - text-decoration-color: initial; -} -#contest-calendar td ul li i.fa { - color: rgb(255, 174, 26); -} -#contest-calendar td ul li a { - color: rgb(211, 207, 201); - text-decoration-color: initial; -} -#contest-calendar td ul li a:hover { - text-decoration-color: initial; -} -#contest-calendar td:hover { - background-color: rgba(0, 0, 204, 0.3); - background-image: initial; - color: rgb(232, 230, 227); -} -#contest-calendar .noday { - background-color: rgb(32, 35, 36); - background-image: initial; -} -#contest-calendar .today { - background-color: rgba(108, 108, 0, 0.5); - background-image: initial; -} -#contest-calendar tr td:first-child { - border-left-color: rgb(72, 78, 81); -} -#banner a.date { - text-decoration-color: initial; -} -#banner a.date:link, -#banner a.date:visited { - color: rgb(104, 149, 191); -} -#banner a.date:hover { - color: rgb(102, 177, 250); -} -#banner .time { - color: rgb(178, 172, 162); -} -.list-contest .contest-tag-hidden { - background-color: rgb(0, 0, 0); - color: rgb(232, 230, 227); -} -.first-solve { - background-color: rgb(0, 199, 129); - background-image: initial; -} -.contest-tag-edit { - background-color: rgb(0, 102, 0); -} -.contest-tag-private { - background-color: rgb(77, 83, 86); - color: rgb(232, 230, 227); -} -.contest-tag-org { - background-color: rgb(53, 57, 59); -} -.contest-tag-org a { - color: rgb(232, 230, 227); -} -.contest-tag-rated { - background-color: rgb(183, 61, 16); - color: rgb(232, 230, 227); -} -.contest-list-sort { - color: rgb(113, 195, 255); -} -.contest-participation-operation .fa { - color: rgb(189, 183, 175); -} -#add-clarification { - color: rgb(140, 255, 26); -} -#add-clarification:hover { - color: rgb(26, 255, 255); -} -#judge-versions .version-blank { - background-color: rgb(34, 36, 38); - background-image: initial; -} -#judge-versions .version-latest { - background-color: rgba(88, 125, 0, 0.9); - background-image: initial; -} -#judge-versions .version-outdated { - background-color: rgba(204, 0, 0, 0.8); - background-image: initial; - color: rgb(232, 230, 227); -} -.chat { - background-color: rgb(24, 26, 27); - background-image: initial; -} -#chat-online { - border-bottom: 0px; - border-right-color: rgb(62, 68, 70); -} -#chat-input { - border-color: rgb(140, 130, 115); - color: rgb(232, 230, 227); -} -#chat-input::-webkit-input-placeholder { - color: rgb(152, 143, 129); -} -#chat-input::placeholder { - color: rgb(152, 143, 129); -} -.selected-status-row { - background-color: rgb(49, 53, 55); -} -.status_last_message { - color: rgb(178, 171, 161); -} -@media (min-width: 800px) { - #chat-container { - border-bottom: 0px; - border-left-color: rgb(62, 68, 70); - border-right-color: rgb(62, 68, 70); - border-top-color: rgb(62, 68, 70); - } -} -#chat-info { - box-shadow: rgba(0, 0, 0, 0.2) 0px 2px 3px; -} -.status-circle { - stroke: rgb(232, 230, 227); -} -.status-row:hover { - background-color: rgb(49, 53, 55); - background-image: initial; -} -.message-text-other { - background-color: rgb(34, 36, 38); - background-image: initial; - color: rgb(232, 230, 227); -} -.message-text-myself { - background-color: rgb(0, 106, 204); - background-image: initial; - color: rgb(232, 230, 227); -} -.chat-input-icon { - background-color: rgb(48, 104, 78); - color: rgb(232, 230, 227); -} -.chat-input-icon:hover { - background-color: rgb(62, 136, 112); - background-image: initial; -} -.chat .active-span { - color: rgb(169, 162, 151); -} -.chat .unread-count { - background-color: rgb(0, 111, 111); - color: rgb(232, 230, 227); -} -.chat .setting-content { - background-color: rgb(32, 35, 36); - box-shadow: rgba(0, 0, 0, 0.2) 0px 8px 16px 0px; -} -.chat .setting-content a { - text-decoration-color: initial; -} -.chat .setting-content a:hover { - background-color: rgb(43, 47, 49); -} -.leave-organization, -.leave-organization:hover { - color: rgb(255, 26, 26); -} -#control-list li { - border-bottom-color: rgb(140, 130, 115); -} -#pending-count-box { - background-color: rgb(204, 0, 0); - background-image: initial; - color: rgb(232, 230, 227); -} -.organization-card { - background-color: rgb(24, 26, 27); - border-color: rgb(58, 62, 65); - box-shadow: rgba(0, 0, 0, 0.1) 0px 2px 4px; - color: inherit; - text-decoration-color: initial; -} -.organization-card:hover { - color: rgb(249, 146, 97); -} -.organization-card img.org-logo { - background-color: rgb(32, 35, 37); -} -.organization-row { - border-bottom-color: rgb(62, 68, 70); - border-top: none; - color: rgb(232, 230, 227); -} -.organization-row:hover { - background-color: rgb(31, 33, 35); -} -.org-help-text { - color: rgb(152, 143, 129); -} -.ticket-container #content > h2:first-child small { - color: rgb(168, 160, 149); -} -.ticket-container #content > h2:first-child .fa-check-circle { - color: rgb(86, 255, 86); -} -.ticket-container #content > h2:first-child .fa-exclamation-circle { - color: rgb(255, 107, 107); -} -.ticket-container .info-box { - border-color: rgb(77, 83, 86); -} -.ticket-container .info-title { - background-color: rgb(34, 36, 38); - background-image: initial; - border-bottom-color: rgb(77, 83, 86); -} -.ticket-container .info-empty { - color: rgb(168, 160, 149); -} -.ticket-container .close-ticket { - background-color: initial; - background-image: linear-gradient(rgb(60, 138, 0) 0%, rgb(31, 109, 14) 100%); - border-color: rgb(61, 193, 24); -} -.ticket-container .close-ticket:hover { - background-color: rgb(29, 90, 11); - background-image: initial; -} -.ticket-container .open-ticket { - background-color: initial; - background-image: linear-gradient(rgb(195, 3, 0), rgb(141, 49, 18)); - border-color: rgb(186, 67, 24); -} -.ticket-container .open-ticket:hover { - background-color: rgb(106, 38, 14); - background-image: initial; -} -.ticket-container .message .detail { - border-color: rgb(77, 83, 86); -} -.ticket-container .message .header { - background-color: rgb(34, 36, 38); - background-image: initial; - border-bottom-color: rgb(77, 83, 86); - color: rgb(157, 148, 136); -} -.wmd-button-bar { - background-color: rgb(24, 26, 27); -} -.wmd-input { - background-color: rgb(24, 26, 27); - background-image: initial; - border-color: rgb(72, 78, 81); -} -.wmd-preview { - background-color: initial; - background-image: none; -} -.wmd-button { - list-style-image: initial; -} -.wmd-bold-button { - background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iOCIgaGVpZ2h0PSI4Ij48ZGVmcz48ZmlsdGVyIGlkPSJkYXJrcmVhZGVyLWltYWdlLWZpbHRlciI+PGZlQ29sb3JNYXRyaXggdHlwZT0ibWF0cml4IiB2YWx1ZXM9IjAuMjQ5IC0wLjYxNCAtMC42NzIgMC4wMDAgMS4wMzUgLTAuNjQ2IDAuMjg4IC0wLjY2NCAwLjAwMCAxLjAyMCAtMC42MzYgLTAuNjA5IDAuMjUwIDAuMDAwIDAuOTk0IDAuMDAwIDAuMDAwIDAuMDAwIDEuMDAwIDAuMDAwIiAvPjwvZmlsdGVyPjwvZGVmcz48aW1hZ2Ugd2lkdGg9IjgiIGhlaWdodD0iOCIgZmlsdGVyPSJ1cmwoI2RhcmtyZWFkZXItaW1hZ2UtZmlsdGVyKSIgeGxpbms6aHJlZj0iZGF0YTppbWFnZS9zdmcreG1sO2Jhc2U2NCxQSE4yWnlCM2FXUjBhRDBpT0hCNElpQm9aV2xuYUhROUlqaHdlQ0lnZG1sbGQwSnZlRDBpTUNBd0lEZ2dPQ0lnZUcxc2JuTTlJbWgwZEhBNkx5OTNkM2N1ZHpNdWIzSm5Mekl3TURBdmMzWm5JajROQ2lBZ1BIQmhkR2dnWkQwaVRUQWdNSFl4WXk0MU5TQXdJREVnTGpRMUlERWdNWFkwWXpBZ0xqVTFMUzQwTlNBeExURWdNWFl4YURVdU5XTXhMak00SURBZ01pNDFMVEV1TVRJZ01pNDFMVEl1TlNBd0xURXRMalU1TFRFdU9EVXRNUzQwTkMweUxqSTFMakkzTFM0ek5DNDBOQzB1TnpndU5EUXRNUzR5TlNBd0xURXVNUzB1T0RrdE1pMHlMVEpvTFRWNmJUTWdNV2d4WXk0MU5TQXdJREVnTGpRMUlERWdNWE10TGpRMUlERXRNU0F4YUMweGRpMHllbTB3SUROb01TNDFZeTQ0TXlBd0lERXVOUzQyTnlBeExqVWdNUzQxY3kwdU5qY2dNUzQxTFRFdU5TQXhMalZvTFRFdU5YWXRNM29pSUM4K0RRbzhMM04yWno0PSIgLz48L3N2Zz4="); -} -.wmd-italic-button { - background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iNTI1IiBoZWlnaHQ9IjUyNSI+PGRlZnM+PGZpbHRlciBpZD0iZGFya3JlYWRlci1pbWFnZS1maWx0ZXIiPjxmZUNvbG9yTWF0cml4IHR5cGU9Im1hdHJpeCIgdmFsdWVzPSIwLjI0OSAtMC42MTQgLTAuNjcyIDAuMDAwIDEuMDM1IC0wLjY0NiAwLjI4OCAtMC42NjQgMC4wMDAgMS4wMjAgLTAuNjM2IC0wLjYwOSAwLjI1MCAwLjAwMCAwLjk5NCAwLjAwMCAwLjAwMCAwLjAwMCAxLjAwMCAwLjAwMCIgLz48L2ZpbHRlcj48L2RlZnM+PGltYWdlIHdpZHRoPSI1MjUiIGhlaWdodD0iNTI1IiBmaWx0ZXI9InVybCgjZGFya3JlYWRlci1pbWFnZS1maWx0ZXIpIiB4bGluazpocmVmPSIiIC8+PC9zdmc+"); -} -.wmd-latex-button { - background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iNjQiIGhlaWdodD0iNjQiPjxkZWZzPjxmaWx0ZXIgaWQ9ImRhcmtyZWFkZXItaW1hZ2UtZmlsdGVyIj48ZmVDb2xvck1hdHJpeCB0eXBlPSJtYXRyaXgiIHZhbHVlcz0iMC4yNDkgLTAuNjE0IC0wLjY3MiAwLjAwMCAxLjAzNSAtMC42NDYgMC4yODggLTAuNjY0IDAuMDAwIDEuMDIwIC0wLjYzNiAtMC42MDkgMC4yNTAgMC4wMDAgMC45OTQgMC4wMDAgMC4wMDAgMC4wMDAgMS4wMDAgMC4wMDAiIC8+PC9maWx0ZXI+PC9kZWZzPjxpbWFnZSB3aWR0aD0iNjQiIGhlaWdodD0iNjQiIGZpbHRlcj0idXJsKCNkYXJrcmVhZGVyLWltYWdlLWZpbHRlcikiIHhsaW5rOmhyZWY9ImRhdGE6aW1hZ2Uvc3ZnK3htbDtiYXNlNjQsUEhOMlp5QmxibUZpYkdVdFltRmphMmR5YjNWdVpEMGlibVYzSURBZ01DQTJOQ0EyTkNJZ2FHVnBaMmgwUFNJMk5IQjRJaUJwWkQwaVRHRjVaWEpmTVNJZ2RtVnljMmx2YmowaU1TNHhJaUIyYVdWM1FtOTRQU0l3SURBZ05qUWdOalFpSUhkcFpIUm9QU0kyTkhCNElpQjRiV3c2YzNCaFkyVTlJbkJ5WlhObGNuWmxJaUI0Yld4dWN6MGlhSFIwY0RvdkwzZDNkeTUzTXk1dmNtY3ZNakF3TUM5emRtY2lJSGh0Ykc1ek9uaHNhVzVyUFNKb2RIUndPaTh2ZDNkM0xuY3pMbTl5Wnk4eE9UazVMM2hzYVc1cklqNDhjR0YwYUNCa1BTSk5ORFV1TnpNc05qUklNelF1TnpVeVl5MHdMamN4TlN3d0xURXVNamsxTFRBdU1UY3pMVEV1TnpNNExUQXVOVEp6TFRBdU56azBMVEF1TnpVNExURXVNRFUyTFRFdU1qTTBiQzA1TGpRNE5DMHhOaTQxTmpRZ0lHTXRNQzR4TnpRc01DNDBOemd0TUM0ek5qa3NNQzQ0T0RjdE1DNDFPRFFzTVM0eU16UnNMVGd1T0RNMUxERTFMak16WXkwd0xqTXdOQ3d3TGpRek5DMHdMalkyTVN3d0xqZ3pOQzB4TGpBM01pd3hMakl3TVVNeE1TNDFOeklzTmpNdU9ERTJMREV4TGpBME1TdzJOQ3d4TUM0ek9URXNOalJJTUM0eE1qY2dJRXd4TlM0ek5pd3pPUzQyTkRGTU1DNDNNVElzTVRZdU5qYzFTREV4TGpZNVl6QXVOekUwTERBc01TNHlOQ3d3TGpBNU15d3hMalUzTml3d0xqSTNObU13TGpNek5Td3dMakU0TlN3d0xqWXpOQ3d3TGpRNU15d3dMamc1TXl3d0xqa3lObXc1TGpReUxERTFMamswT0NBZ1l6QXVNVEE0TFRBdU1qZ3NNQzR5TXpJdE1DNDFOVElzTUM0ek56UXRNQzQ0TVRKak1DNHhOQzB3TGpJMk1pd3dMakk1Tnkwd0xqVXpNU3d3TGpRM01TMHdMamd4TTJ3NExqSTFMVEUwTGpFMk1XTXdMak13TlMwd0xqUTNOeXd3TGpZeU1pMHdMamd5TXl3d0xqazFPQzB4TGpBMElDQmpNQzR6TXpZdE1DNHlNVGNzTUM0M05USXRNQzR6TWpVc01TNHlOVEV0TUM0ek1qVm9NVEF1TlRJMFRETXdMalUyTWl3ek9TNHhPRFpNTkRVdU56TXNOalI2SWk4K1BIQmhkR2dnWkQwaVRUWXhMamcwTERJekxqZzJZekF1TmpZM0xEQXNNUzR4T1RNc01DNHhPRE1zTVM0MU9Dd3dMalUxWXpBdU16ZzNMREF1TXpZMkxEQXVOVGdzTUM0NE5Td3dMalU0TERFdU5EVjJNeTQyU0RRekxqVXlNWFl0TW1Nd0xUQXVNemczTERBdU1EYzVMVEF1T0N3d0xqSXpPUzB4TGpJMElDQmpNQzR4Tmkwd0xqUXpPU3d3TGpRMExUQXVPRFFzTUM0NE5DMHhMakpzT0M0MExUZ3VORFpqTUM0M01qRXRNQzQzTWl3eExqTTBOeTB4TGpRd05pd3hMamc0TVMweUxqQTJZekF1TlRNekxUQXVOalV6TERBdU9UY3pMVEV1TWprM0xERXVNekU1TFRFdU9UTWdJR013TGpNME55MHdMall6TkN3d0xqWXdOaTB4TGpJMk55d3dMamM0TFRFdU9XTXdMakUzTXkwd0xqWXpNeXd3TGpJMkxURXVNekEwTERBdU1qWXRNaTR3TVdNd0xURXVNVFl0TUM0eU56Y3RNaTR3TlMwd0xqZ3pMVEl1TmpjZ0lHTXRNQzQxTlRNdE1DNDJNaTB4TGpNNU5pMHdMamt6TFRJdU5USTVMVEF1T1ROakxUQXVPVElzTUMweExqWTVOeXd3TGpJME15MHlMak16TERBdU56TmpMVEF1TmpNMExEQXVORGczTFRFdU1EY3NNUzR3T1MweExqTXhNU3d4TGpneElDQmpMVEF1TWpjNUxEQXVOek16TFRBdU5qUTJMREV1TWpJdE1TNHhMREV1TkRaakxUQXVORFV6TERBdU1qUXRNUzR4TERBdU1qa3pMVEV1T1RRc01DNHhObXd0TXk0eU9DMHdMalU0WXpBdU1qRXpMVEV1TkRVekxEQXVOakl6TFRJdU56SXNNUzR5TXkwekxqZ2dJR013TGpZd05pMHhMakE0TERFdU16VTVMVEV1T1Rnc01pNHlOaTB5TGpkak1DNDVMVEF1TnpJc01TNDVNeTB4TGpJMU55d3pMakE1TFRFdU5qRkROVEV1TmpZc01DNHhOemNzTlRJdU9UQTJMREFzTlRRdU1qUXNNR014TGpRek9Td3dMREl1TnpNMkxEQXVNakVzTXk0NE9URXNNQzQyTXlBZ1l6RXVNVFV5TERBdU5ESXNNaTR4TXpjc01TNHdNRE1zTWk0NU5Ea3NNUzQzTldNd0xqZ3hNeXd3TGpjME55d3hMalF6T0N3eExqWXpOeXd4TGpnM0xESXVOamRETmpNdU16Z3pMRFl1TURnekxEWXpMallzTnk0eU1pdzJNeTQyTERndU5EWWdJR013TERFdU1EWTJMVEF1TVRRNUxESXVNRFUwTFRBdU5EUTVMREl1T1RaakxUQXVNekF4TERBdU9UQTNMVEF1TnpFc01TNDNOekV0TVM0eU15d3lMalU1WXkwd0xqVXlMREF1T0RJdE1TNHhNak1zTVM0Mk1UTXRNUzQ0TVN3eUxqTTRJQ0JqTFRBdU5qZzNMREF1TnpZNExURXVOREUzTERFdU5UUTBMVEl1TVRrc01pNHpNMnd0TlM0Mk9Ua3NOUzQ0TkdNd0xqY3pNaTB3TGpJeU55d3hMalExT1Mwd0xqTTVPU3d5TGpFNExUQXVOVEpqTUM0M01pMHdMakV5TERFdU16ZzNMVEF1TVRnc01pMHdMakU0U0RZeExqZzBlaUl2UGp3dmMzWm5QZz09IiAvPjwvc3ZnPg=="); -} -.wmd-latex-button-display { - background-image: url("http://127.0.0.1:8000/static/pagedown/resources/latex-display.svg"); -} -.wmd-link-button { - background-image: url("http://127.0.0.1:8000/static/pagedown/resources/link.svg"); -} -.wmd-user-reference-button { - background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiPjxkZWZzPjxmaWx0ZXIgaWQ9ImRhcmtyZWFkZXItaW1hZ2UtZmlsdGVyIj48ZmVDb2xvck1hdHJpeCB0eXBlPSJtYXRyaXgiIHZhbHVlcz0iMC4yNDkgLTAuNjE0IC0wLjY3MiAwLjAwMCAxLjAzNSAtMC42NDYgMC4yODggLTAuNjY0IDAuMDAwIDEuMDIwIC0wLjYzNiAtMC42MDkgMC4yNTAgMC4wMDAgMC45OTQgMC4wMDAgMC4wMDAgMC4wMDAgMS4wMDAgMC4wMDAiIC8+PC9maWx0ZXI+PC9kZWZzPjxpbWFnZSB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIGZpbHRlcj0idXJsKCNkYXJrcmVhZGVyLWltYWdlLWZpbHRlcikiIHhsaW5rOmhyZWY9ImRhdGE6aW1hZ2Uvc3ZnK3htbDtiYXNlNjQsUEQ5NGJXd2dkbVZ5YzJsdmJqMGlNUzR3SWlBL1BqeHpkbWNnYUdWcFoyaDBQU0l5TkNJZ2RtVnljMmx2YmowaU1TNHhJaUIzYVdSMGFEMGlNalFpSUhodGJHNXpQU0pvZEhSd09pOHZkM2QzTG5jekxtOXlaeTh5TURBd0wzTjJaeUlnZUcxc2JuTTZZMk05SW1oMGRIQTZMeTlqY21WaGRHbDJaV052YlcxdmJuTXViM0puTDI1ekl5SWdlRzFzYm5NNlpHTTlJbWgwZEhBNkx5OXdkWEpzTG05eVp5OWtZeTlsYkdWdFpXNTBjeTh4TGpFdklpQjRiV3h1Y3pweVpHWTlJbWgwZEhBNkx5OTNkM2N1ZHpNdWIzSm5MekU1T1Rrdk1ESXZNakl0Y21SbUxYTjViblJoZUMxdWN5TWlQanhuSUhSeVlXNXpabTl5YlQwaWRISmhibk5zWVhSbEtEQWdMVEV3TWpndU5Da2lQanh3WVhSb0lHUTlJbTB4TWlBd1l5MHdMalF3TlNBd0xUQXVPREExSURBdU1EWXdNekkyTFRFdU1UZzRJREF1TVRVMk1qVXRNQzR5TWpRZ01DNHdOVFkzT0Mwd0xqUTBJREF1TVRNeE16VXRNQzQyTlRZZ01DNHlNVGczTlMwd0xqQTRNeUF3TGpBek5EQXhMVEF1TVRZM09TQXdMakExTlRNMExUQXVNalE1T0NBd0xqQTVNemMxTFRBdU1ETTBJREF1TURFMU9ETXRNQzR3TmlBd0xqQTBOVGswTFRBdU1Ea3pOeUF3TGpBMk1qVXRNQzR5TURNeUlEQXVNVEF3TlRndE1DNDBNREl4SURBdU1qRTNNRFF0TUM0MU9UTTNJREF1TXpRek56VXRNQzR3TWpjZ01DNHdNVGMwTFRBdU1EWTNNU0F3TGpBeE16TTVMVEF1TURrek9DQXdMakF6TVRJMUxUQXVNRFUyTXlBd0xqQXpPRFkwTFRBdU1UQXhJREF1TURnME1Ua3RNQzR4TlRZeUlEQXVNVEkwT1RVdE1DNHhOVFk1SURBdU1URXlOaTB3TGpNeU1UWWdNQzR5TVRZdE1DNDBOamc0SURBdU16UXpPQzB3TGpFek5ESWdNQzR4TWpBM0xUQXVNalE1TkNBd0xqSTNNalF0TUM0ek56VWdNQzQwTURZeUxUQXVOREkxTVNBd0xqUXpOVGt0TUM0M09UTTJJREF1T0RrM01TMHhMakE1TXpnZ01TNDBNemMyTFRBdU5URTFOQ0F3TGprd016UXRNQzQ1TURBeUlERXVPVEl3TlMweExqQTJNalFnTWk0NU5qZzNMVEF1TURjNE15MHdMakF4TmpVdE1DNHhOVEF4TFRBdU1ESXlOQzB3TGpJeE9EZ2dNQzB3TGpVeU5URWdNQzR4TnpFdE1DNDJOVFExSURFdU1UWTROUzB3TGpNeE1qVWdNaTR5TVRnM0lEQXVNakF3TnlBd0xqWXhOak1nTUM0MU16UTJJREV1TVRBeE5TQXdMamczTlNBeExqTTNOU0F3TGpRMU56TWdNUzQzTnpjNElERXVOREkxTnlBekxqSTFPVGdnTWk0Mk9EYzFJRFF1TVRnM09IWXhMakF6TVd3dE1TQXhMVElnTVdNdE1TNDJNVGN6SURBdU9EQXhMVE11TWpJNE5DQXhMall3TlMwMExqZzBNemdnTWk0ME1EWXRNQzQ0T1RVeE15QXdMalUwTFRFdU1qUXhOU0F4TGpZdE1TNHhOVFl5SURJdU5UazBJREF1TURReE5qWTBJREF1TmpJMkxUQXVNVGcwTkRnZ01TNDBNamNnTUM0ME16YzFJREV1T0RRMElEQXVOVGt3T1NBd0xqTXdOQ0F4TGpJNU5Ua2dNQzR4TURZZ01TNDVNemMxSURBdU1UVTJJREV1T0RjMk5pMHdMakF3TVNBekxqYzBPRFFnTUNBMUxqWXlOU0F3SURJdU5qWTVJREF1TURBeElEVXVNek14SURBZ09DQXdJREl1TXpZM0lEQWdOQzQzTWpjZ01DNHdNRFFnTnk0d09UUWdNQ0F3TGpjMk9DMHdMakExTkNBd0xqazRNUzB3TGpnMk5TQXdMamt3TmkweExqVWdNQzR3TVRRdE1DNDVNeklnTUM0d05qa3RNUzQ1TnpZdE1DNDJOVFl0TWk0Mk9EZ3RNQzQxT1RJdE1DNDJNREl0TVM0ME16UXRNQzQ0TkMweUxqRTFOaTB4TGpJMUxURXVNRFl4TFRBdU5USTFMVEl1TVRJNExURXVNRE0zTFRNdU1UZzRMVEV1TlRZeWJDMHlMVEV0TVMweGRpMHhMakF6TVdNeExqSTJNaTB3TGpreU9DQXlMakl6TFRJdU5ERWdNaTQyT0RndE5DNHhPRGM0SURBdU16UXRNQzR5TnpNMklEQXVOamMwTFRBdU56VTRPQ0F3TGpnM05DMHhMak0zTlNBd0xqTTBNaTB4TGpBMU1ESWdNQzR5TVRNdE1pNHdORGMzTFRBdU16RXlMVEl1TWpFNE55MHdMakEyT1Mwd0xqQXlNalF0TUM0eE5DMHdMakF4TmpVdE1DNHlNVGtnTUMwd0xqRTJNaTB4TGpBME9ESXRNQzQxTkRjdE1pNHdOalV6TFRFdU1EWXlMVEl1T1RZNE55MHdMak10TUM0MU5EQTFMVEF1TmpZNUxURXVNREF4TnkweExqQTVOQzB4TGpRek56WXRNQzR4TWpZdE1DNHhNek00TFRBdU1qUXhMVEF1TWpnMU5TMHdMak0zTlMwd0xqUXdOakl0TUM0d01EWXRNQzR3TURVMUxUQXVNREkxSURBdU1EQTFOUzB3TGpBek1TQXdMVEF1TXpreUxUQXVNelE1T1Mwd0xqZ3lOeTB3TGpZeE9EazBMVEV1TWpneExUQXVPRFF6TnpVdE1DNHhNVFV0TUM0d05UWXlNaTB3TGpJeU55MHdMakV3T0RVMExUQXVNelEwTFRBdU1UVTJNalV0TUM0d09EUXRNQzR3TXpRd01TMHdMakUyTlMwd0xqQTJOREkyTFRBdU1qVXRNQzR3T1RNM05TMHdMakkxTlMwd0xqQTRPRFE0TFRBdU5URTJMVEF1TVRjek5UWXRNQzQzT0RJdE1DNHlNVGczTlMwd0xqQXlMVEF1TURBek5EQTFMVEF1TURReUlEQXVNREF6TVRRNExUQXVNRFl5SURBdE1DNHlORGt0TUM0d016a3hORFF0TUM0ME9UVXRNQzR3TmpVeU5TMHdMamMxTFRBdU1EWXlOWG9pSUdacGJHdzlJaU16TkRRNU5XVWlJSFJ5WVc1elptOXliVDBpZEhKaGJuTnNZWFJsS0RBZ01UQXlPQzQwS1NJdlBqeHdZWFJvSUdROUltMHdJREV3TlRFdU5HTXdMakF5TmpReE9TQXdMak1nTUM0eE1qWTFNU0F3TGpZZ01DNDBNemMxSURBdU9DQXdMalU1TURrZ01DNHpJREV1TWprMU9TQXdMakVnTVM0NU16YzFJREF1TW1nMUxqWXlOU0E0SURjdU1EazBZekF1TlRjMkxUQXVNU0F3TGpnME1pMHdMalVnTUM0NU1EWXRNV2d0TWpSNklpQm1hV3hzUFNJak1tTXpaVFV3SWk4K1BDOW5Qand2YzNablBnPT0iIC8+PC9zdmc+"); -} -.wmd-quote-button { - background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iNDgiIGhlaWdodD0iNDgiPjxkZWZzPjxmaWx0ZXIgaWQ9ImRhcmtyZWFkZXItaW1hZ2UtZmlsdGVyIj48ZmVDb2xvck1hdHJpeCB0eXBlPSJtYXRyaXgiIHZhbHVlcz0iMC4yNDkgLTAuNjE0IC0wLjY3MiAwLjAwMCAxLjAzNSAtMC42NDYgMC4yODggLTAuNjY0IDAuMDAwIDEuMDIwIC0wLjYzNiAtMC42MDkgMC4yNTAgMC4wMDAgMC45OTQgMC4wMDAgMC4wMDAgMC4wMDAgMS4wMDAgMC4wMDAiIC8+PC9maWx0ZXI+PC9kZWZzPjxpbWFnZSB3aWR0aD0iNDgiIGhlaWdodD0iNDgiIGZpbHRlcj0idXJsKCNkYXJrcmVhZGVyLWltYWdlLWZpbHRlcikiIHhsaW5rOmhyZWY9ImRhdGE6aW1hZ2Uvc3ZnK3htbDtiYXNlNjQsUEQ5NGJXd2dkbVZ5YzJsdmJqMGlNUzR3SWlBL1Bqd2hSRTlEVkZsUVJTQnpkbWNnSUZCVlFreEpReUFuTFM4dlZ6TkRMeTlFVkVRZ1UxWkhJREV1TVM4dlJVNG5JQ0FuYUhSMGNEb3ZMM2QzZHk1M015NXZjbWN2UjNKaGNHaHBZM012VTFaSEx6RXVNUzlFVkVRdmMzWm5NVEV1WkhSa0p6NDhjM1puSUdWdVlXSnNaUzFpWVdOclozSnZkVzVrUFNKdVpYY2dNQ0F3SURRNElEUTRJaUJvWldsbmFIUTlJalE0Y0hnaUlHbGtQU0pNWVhsbGNsOHpJaUIyWlhKemFXOXVQU0l4TGpFaUlIWnBaWGRDYjNnOUlqQWdNQ0EwT0NBME9DSWdkMmxrZEdnOUlqUTRjSGdpSUhodGJEcHpjR0ZqWlQwaWNISmxjMlZ5ZG1VaUlIaHRiRzV6UFNKb2RIUndPaTh2ZDNkM0xuY3pMbTl5Wnk4eU1EQXdMM04yWnlJZ2VHMXNibk02ZUd4cGJtczlJbWgwZEhBNkx5OTNkM2N1ZHpNdWIzSm5MekU1T1RrdmVHeHBibXNpUGp4blBqeHdZWFJvSUdROUlrMHdMREk0TGpNM05XZ3hNaTQyTjJNdE1DNHdOaklzTXk0ek1TMHhMak16T0N3MkxqTXhNeTB6TGpRd015dzRMalpqTFRBdU9UUTFMREF1T0RreUxURXVPVGd5TERFdU5EQTRMVEl1T0RjNUxERXVOekEySUNBZ1l5MHhMakVzTUM0ek1qZ3RNaTR5Tml3d0xqTTVOaTB5TGpnNE15d3dMalF3T0Vnd2RqSXVNamcyYURndU56VjJMVEF1TURBell6Y3VNakExTFRBdU1ETXlMREV6TGpBME15MDFMamd4Tml3eE15NHhOemN0TVRJdU9UazNTREl5ZGkweU1rZ3dWakk0TGpNM05Yb2lJR1pwYkd3OUlpTXlOREZHTWpBaUx6NDhjR0YwYUNCa1BTSk5NallzTmk0ek56VjJNakpvTVRJdU56UmpNQ3d5TGprNU1TMHhMRFV1TnpReUxUSXVOamMwTERjdU9UVTJZeTB3TGpnek9Td3hMakE0T1MweExqZ3lPQ3d4TGpjNU1pMHlMamMyTVN3eUxqSXpNeUFnSUdNdE1DNHdNRGdzTUM0d01EUXRNQzR3TVRZc01DNHdNRGd0TUM0d01qTXNNQzR3TVRKakxUQXVNVE01TERBdU1EWTFMVEF1TWpjMExEQXVNVEl5TFRBdU5EQTVMREF1TVRjMll5MHhMalV4TkN3d0xqVTFOeTB6TGpreE5Td3dMalU0Tnkwekxqa3hOU3d3TGpVNE4wZ3lObll5TGpJNE5tZzRMamMxSUNBZ1l6Y3VNekUzTERBc01UTXVNalV0TlM0NU16TXNNVE11TWpVdE1UTXVNalYyTFRJeVNESTJlaUlnWm1sc2JEMGlJekkwTVVZeU1DSXZQand2Wno0OEwzTjJaejQ9IiAvPjwvc3ZnPg=="); -} -.wmd-code-button { - background-image: url("http://127.0.0.1:8000/static/pagedown/resources/code.svg"); -} -.wmd-image-button { - background-image: url("http://127.0.0.1:8000/static/pagedown/resources/image.svg"); -} -.wmd-olist-button { - background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiPjxkZWZzPjxmaWx0ZXIgaWQ9ImRhcmtyZWFkZXItaW1hZ2UtZmlsdGVyIj48ZmVDb2xvck1hdHJpeCB0eXBlPSJtYXRyaXgiIHZhbHVlcz0iMC4yNDkgLTAuNjE0IC0wLjY3MiAwLjAwMCAxLjAzNSAtMC42NDYgMC4yODggLTAuNjY0IDAuMDAwIDEuMDIwIC0wLjYzNiAtMC42MDkgMC4yNTAgMC4wMDAgMC45OTQgMC4wMDAgMC4wMDAgMC4wMDAgMS4wMDAgMC4wMDAiIC8+PC9maWx0ZXI+PC9kZWZzPjxpbWFnZSB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIGZpbHRlcj0idXJsKCNkYXJrcmVhZGVyLWltYWdlLWZpbHRlcikiIHhsaW5rOmhyZWY9ImRhdGE6aW1hZ2Uvc3ZnK3htbDtiYXNlNjQsUEQ5NGJXd2dkbVZ5YzJsdmJqMGlNUzR3SWlBL1BqeHpkbWNnWm1sc2JEMGlibTl1WlNJZ2FHVnBaMmgwUFNJeU5DSWdkbWxsZDBKdmVEMGlNQ0F3SURJMElESTBJaUIzYVdSMGFEMGlNalFpSUhodGJHNXpQU0pvZEhSd09pOHZkM2QzTG5jekxtOXlaeTh5TURBd0wzTjJaeUkrUEhCaGRHZ2daRDBpVFRZdU1EQXdNU0F5TGpjMVF6WXVNREF3TVNBeUxqTTVOVGMzSURVdU56VXlNamNnTWk0d09EazROQ0ExTGpRd05UYzJJREl1TURFMk16TkROUzR3TmpBeE1TQXhMamswTXlBMExqY3hNRE1nTWk0eE1qQTROaUEwTGpVMk5UZ2dNaTQwTkRNd00wdzBMalUyTkRJMklESXVORFEyTXpkRE5DNDFOakl5TmlBeUxqUTFNRFkzSURRdU5UVTRORElnTWk0ME5UZzRNU0EwTGpVMU1qYzFJREl1TkRjd05ESkROQzQxTkRFMElESXVORGt6TmpZZ05DNDFNakk0TWlBeUxqVXpNRFUxSURRdU5EazNNRFFnTWk0MU56Z3dPRU0wTGpRME5USTNJREl1Tmpjek5UWWdOQzR6TmpVNE5DQXlMamd3T1RRMUlEUXVNalU1TkNBeUxqazJNalE0UXpRdU1EUXhOellnTXk0eU56VXpOeUF6TGpjek5UTTRJRE11TmpJME9EZ2dNeTR6TlRJM05TQXpMamcyTXpreFF6TXVNREF4TkRRZ05DNHdPRE16TmlBeUxqZzVORFUySURRdU5UUTJNRFVnTXk0eE1UUXdNU0EwTGpnNU56TTFRek11TXpNek5EWWdOUzR5TkRnMk5pQXpMamM1TmpFMUlEVXVNelUxTlRRZ05DNHhORGMwTmlBMUxqRXpOakE1UXpRdU1qY3lNRFVnTlM0d05UZ3lOaUEwTGpNNE9UVTJJRFF1T1RjME56TWdOQzQxTURBeElEUXVPRGczTmpWV055NHlOVU0wTGpVd01ERWdOeTQyTmpReU1TQTBMamd6TlRnNUlEZ2dOUzR5TlRBeElEaEROUzQyTmpRek1TQTRJRFl1TURBd01TQTNMalkyTkRJeElEWXVNREF3TVNBM0xqSTFWakl1TnpWYUlpQm1hV3hzUFNJak1qRXlNVEl4SWk4K1BIQmhkR2dnWkQwaVRURTVMalE1T1RVZ01UaElNVEF1T1RrNU5Vd3hNQzQ0T0RJNUlERTRMakF3TmpkRE1UQXVNemcxTmlBeE9DNHdOalExSURrdU9UazVOVEVnTVRndU5EZzNNaUE1TGprNU9UVXhJREU1UXprdU9UazVOVEVnTVRrdU5UVXlNeUF4TUM0ME5EY3lJREl3SURFd0xqazVPVFVnTWpCSU1Ua3VORGs1TlV3eE9TNDJNVFl4SURFNUxqazVNek5ETWpBdU1URXpOU0F4T1M0NU16VTFJREl3TGpRNU9UVWdNVGt1TlRFeU9DQXlNQzQwT1RrMUlERTVRekl3TGpRNU9UVWdNVGd1TkRRM055QXlNQzR3TlRFNElERTRJREU1TGpRNU9UVWdNVGhhSWlCbWFXeHNQU0lqTWpFeU1USXhJaTgrUEhCaGRHZ2daRDBpVFRFNUxqUTVPVFVnTVRFdU5VZ3hNQzQ1T1RrMVRERXdMamc0TWprZ01URXVOVEEyTjBNeE1DNHpPRFUySURFeExqVTJORFVnT1M0NU9UazFNU0F4TVM0NU9EY3lJRGt1T1RrNU5URWdNVEl1TlVNNUxqazVPVFV4SURFekxqQTFNak1nTVRBdU5EUTNNaUF4TXk0MUlERXdMams1T1RVZ01UTXVOVWd4T1M0ME9UazFUREU1TGpZeE5qRWdNVE11TkRrek0wTXlNQzR4TVRNMUlERXpMalF6TlRVZ01qQXVORGs1TlNBeE15NHdNVEk0SURJd0xqUTVPVFVnTVRJdU5VTXlNQzQwT1RrMUlERXhMamswTnpjZ01qQXVNRFV4T0NBeE1TNDFJREU1TGpRNU9UVWdNVEV1TlZvaUlHWnBiR3c5SWlNeU1USXhNakVpTHo0OGNHRjBhQ0JrUFNKTk1Ua3VORGs1TlNBMVNERXdMams1T1RWTU1UQXVPRGd5T1NBMUxqQXdOamN6UXpFd0xqTTROVFlnTlM0d05qUTBPU0E1TGprNU9UVXhJRFV1TkRnM01UWWdPUzQ1T1RrMU1TQTJRemt1T1RrNU5URWdOaTQxTlRJeU9DQXhNQzQwTkRjeUlEY2dNVEF1T1RrNU5TQTNTREU1TGpRNU9UVk1NVGt1TmpFMk1TQTJMams1TXpJM1F6SXdMakV4TXpVZ05pNDVNelUxTVNBeU1DNDBPVGsxSURZdU5URXlPRFFnTWpBdU5EazVOU0EyUXpJd0xqUTVPVFVnTlM0ME5EYzNNaUF5TUM0d05URTRJRFVnTVRrdU5EazVOU0ExV2lJZ1ptbHNiRDBpSXpJeE1qRXlNU0l2UGp4d1lYUm9JR1E5SWswMUxqRTFNRGt6SURFd0xqVXhPVGxETkM0NE5EazFOeUF4TUM0ME5qWTNJRFF1TkRjME5EUWdNVEF1TlRnMk15QTBMakk0TURNeElERXdMamM0TURSRE15NDVPRGMwTVNBeE1TNHdOek16SURNdU5URXlOVE1nTVRFdU1EY3pNeUF6TGpJeE9UWTFJREV3TGpjNE1EUkRNaTQ1TWpZM055QXhNQzQwT0RjMElESXVPVEkyTnpnZ01UQXVNREV5TmlBekxqSXhPVFk1SURrdU56RTVOamxETXk0M056VTFOaUE1TGpFMk16ZzFJRFF1TmpVd05EUWdPQzQ1TURnMElEVXVOREV4TlRjZ09TNHdOREkzUXpVdU9EQTVJRGt1TVRFeU9ETWdOaTR5TVRjeklEa3VNamszTVNBMkxqVXlOekl5SURrdU5qUTRNelJETmk0NE5ESTJJREV3TGpBd05UZ2dOeUF4TUM0ME56STNJRGNnTVRGRE55QXhNUzQyTVRrMUlEWXVOekk0T1RVZ01USXVNRGdnTmk0ek9UUXdOaUF4TWk0ME1qQTFRell1TVRFMk15QXhNaTQzTURJNUlEVXVOell6TVRVZ01USXVPVE14SURVdU5EZzRNallnTVRNdU1UQTROa3cxTGpRd09EYzBJREV6TGpFMk1ERkROUzR5TVRNME9DQXhNeTR5T0RjZ05TNHdOVFF5T0NBeE15NHpPVGNnTkM0NU1qWTROaUF4TXk0MVNEWXVNalZETmk0Mk5qUXlNU0F4TXk0MUlEY2dNVE11T0RNMU9DQTNJREUwTGpJMVF6Y2dNVFF1TmpZME1pQTJMalkyTkRJZ01UVWdOaTR5TkRrNU9TQXhOVWd6TGpjMVF6TXVNek0xTnprZ01UVWdNeUF4TkM0Mk5qUXlJRE1nTVRRdU1qVkRNeUF4TWk0NU16WTBJRE11T1Rnek9EVWdNVEl1TWprM01TQTBMalUzTlRBMUlERXhMamt4TTB3MExqWXpOVEl5SURFeExqZzNNemxETkM0NU5USTFPU0F4TVM0Mk5qYzNJRFV1TVRZNE5ETWdNVEV1TlRJM05TQTFMak15TkRZNUlERXhMak0yT0RaRE5TNDBOVGcxTlNBeE1TNHlNekkxSURVdU5TQXhNUzR4TXpBMklEVXVOU0F4TVVNMUxqVWdNVEF1TnpjM05DQTFMalF6T0RZMUlERXdMalk0TVRnZ05TNDBNREkwTnlBeE1DNDJOREE0UXpVdU16WXdPRE1nTVRBdU5Ua3pOaUExTGpJNE5EYzFJREV3TGpVME16VWdOUzR4TlRBNU15QXhNQzQxTVRrNVdpSWdabWxzYkQwaUl6SXhNakV5TVNJdlBqeHdZWFJvSUdROUlrMHlMamsyT1RZM0lESXhMakk0TURORE1pNDVOamsyTnlBeU1TNHlPREF6SURNdU1EWXlOVEVnTWpFdU16WTBNU0F5TGprM05ESTJJREl4TGpJNE5EbE1NaTQ1TnprMk1pQXlNUzR5T1RBeFRESXVPVGt5T1NBeU1TNHpNREk0UXpNdU1EQXlPRGNnTWpFdU16RXlNU0F6TGpBeE5UQTVJREl4TGpNeU16TWdNeTR3TWprMU5pQXlNUzR6TXpVNVF6TXVNRFU0TkRnZ01qRXVNell4TWlBekxqQTVOalV6SURJeExqTTVNamNnTXk0eE5ETTNOU0F5TVM0ME1qZ3hRek11TWpNNE1TQXlNUzQwT1RnNUlETXVNelk1T1RZZ01qRXVOVGcySURNdU5UTTVOVGtnTWpFdU5qY3dPRU16TGpnNE1UTXhJREl4TGpnME1UY2dOQzR6TnpBME15QXlNaUExSURJeVF6VXVOak01TWpFZ01qSWdOaTR4T1RVNU5pQXlNUzQ0TVRnMklEWXVOakF4TXpJZ01qRXVORFl3TlVNM0xqQXdPVEl5SURJeExqRXdNREVnTnk0eU1URTJNeUF5TUM0Mk1ETXlJRGN1TVRrMU5UTWdNakF1TVRBeFF6Y3VNVGd5TVRrZ01Ua3VOamcwTmlBM0xqQXlPVEF6SURFNUxqTXdOVE1nTmk0M05qazROaUF4T1VNM0xqQXlPVEF6SURFNExqWTVORGNnTnk0eE9ESXhPU0F4T0M0ek1UVTBJRGN1TVRrMU5UTWdNVGN1T0RrNVF6Y3VNakV4TmpNZ01UY3VNemsyT0NBM0xqQXdPVEl5SURFMkxqZzVPVGtnTmk0Mk1ERXpNaUF4Tmk0MU16azFRell1TVRrMU9UWWdNVFl1TVRneE5DQTFMall6T1RJeElERTJJRFVnTVRaRE5DNHpOekEwTXlBeE5pQXpMamc0TVRNeElERTJMakUxT0RNZ015NDFNemsxT1NBeE5pNHpNamt5UXpNdU16WTVPVFlnTVRZdU5ERTBJRE11TWpNNE1TQXhOaTQxTURFeElETXVNVFF6TnpVZ01UWXVOVGN4T1VNekxqQTVOalV6SURFMkxqWXdOek1nTXk0d05UZzBPQ0F4Tmk0Mk16ZzRJRE11TURJNU5UWWdNVFl1TmpZME1VTXpMakF4TlRBNUlERTJMalkzTmpjZ015NHdNREk0TnlBeE5pNDJPRGM1SURJdU9Ua3lPU0F4Tmk0Mk9UY3lUREl1T1RjNU5qSWdNVFl1TnpBNU9Vd3lMamszTkRJeklERTJMamN4TlRGTU1pNDVOekU0T1NBeE5pNDNNVGMxVERJdU9UY3dPVEVnTVRZdU56RTROVXd5TGprMk9UWTNJREUyTGpjeE9UZERNaTQyTnpZM09DQXhOeTR3TVRJMklESXVOamMyTnpnZ01UY3VORGczTkNBeUxqazJPVFkzSURFM0xqYzRNRE5ETXk0eU5UZzJJREU0TGpBMk9UTWdNeTQzTWpRMk1pQXhPQzR3TnpNeUlEUXVNREU0TXpRZ01UY3VOemt5TVVNMExqQXlNVGNnTVRjdU56ZzVNaUEwTGpBek1ERTRJREUzTGpjNE1pQTBMakEwTXpjMUlERTNMamMzTVRsRE5DNHdOelEwSURFM0xqYzBPRGtnTkM0eE16QXdOQ0F4Tnk0M01URWdOQzR5TVRBME1TQXhOeTQyTnpBNFF6UXVNelk0TmprZ01UY3VOVGt4TnlBMExqWXlPVFUzSURFM0xqVWdOU0F4Tnk0MVF6VXVNell3TnprZ01UY3VOU0ExTGpVek5qQXhJREUzTGpVNU9Ua2dOUzQyTURneE1pQXhOeTQyTmpNMlF6VXVOamMzTmpnZ01UY3VOekkxTVNBMUxqWTVPREl6SURFM0xqYzVNRGNnTlM0Mk9UWXpJREUzTGpnMU1VTTFMalk1TkRJeklERTNMamt4TlRVZ05TNDJOalF3TXlBeE9DNHdNREkzSURVdU5UY3lOemdnTVRndU1EZ3hPRU0xTGpRNE5EVWdNVGd1TVRVNE5DQTFMak13T1RZeUlERTRMakkxSURVZ01UZ3VNalZETkM0MU9EVTNPU0F4T0M0eU5TQTBMakkxSURFNExqVTROVGdnTkM0eU5TQXhPVU0wTGpJMUlERTVMalF4TkRJZ05DNDFPRFUzT1NBeE9TNDNOU0ExSURFNUxqYzFRelV1TXpBNU5qSWdNVGt1TnpVZ05TNDBPRFExSURFNUxqZzBNVFlnTlM0MU56STNPQ0F4T1M0NU1UZ3lRelV1TmpZME1ETWdNVGt1T1RrM015QTFMalk1TkRJeklESXdMakE0TkRVZ05TNDJPVFl6SURJd0xqRTBPVU0xTGpZNU9ESXpJREl3TGpJd09UTWdOUzQyTnpjMk9DQXlNQzR5TnpRNUlEVXVOakE0TVRJZ01qQXVNek0yTkVNMUxqVXpOakF4SURJd0xqUXdNREVnTlM0ek5qQTNPU0F5TUM0MUlEVWdNakF1TlVNMExqWXlPVFUzSURJd0xqVWdOQzR6TmpnMk9TQXlNQzQwTURneklEUXVNakV3TkRFZ01qQXVNekk1TWtNMExqRXpNREEwSURJd0xqSTRPU0EwTGpBM05EUWdNakF1TWpVeE1TQTBMakEwTXpjMUlESXdMakl5T0RGRE5DNHdNekF4T0NBeU1DNHlNVGdnTkM0d01qRTNJREl3TGpJeE1EZ2dOQzR3TVRnek5DQXlNQzR5TURjNVF6TXVOekkwTmpJZ01Ua3VPVEkyT0NBekxqSTFPRFlnTVRrdU9UTXdOeUF5TGprMk9UWTNJREl3TGpJeE9UZERNaTQyTnpZM09DQXlNQzQxTVRJMklESXVOamMyTnpnZ01qQXVPVGczTkNBeUxqazJPVFkzSURJeExqSTRNRE5hVFRJdU9UY3hPRGtnTVRZdU56RTNOVXd5TGprM01Ea3hJREUyTGpjeE9EVkRNaTQ1TnpjMklERTJMamN4TWprZ015NHhOekU0TWlBeE5pNDFOVEUxSURJdU9UY3hPRGtnTVRZdU56RTNOVm9pSUdacGJHdzlJaU15TVRJeE1qRWlMejQ4TDNOMlp6ND0iIC8+PC9zdmc+"); -} -.wmd-ulist-button { - background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMjAiIGhlaWdodD0iMjAiPjxkZWZzPjxmaWx0ZXIgaWQ9ImRhcmtyZWFkZXItaW1hZ2UtZmlsdGVyIj48ZmVDb2xvck1hdHJpeCB0eXBlPSJtYXRyaXgiIHZhbHVlcz0iMC4yNDkgLTAuNjE0IC0wLjY3MiAwLjAwMCAxLjAzNSAtMC42NDYgMC4yODggLTAuNjY0IDAuMDAwIDEuMDIwIC0wLjYzNiAtMC42MDkgMC4yNTAgMC4wMDAgMC45OTQgMC4wMDAgMC4wMDAgMC4wMDAgMS4wMDAgMC4wMDAiIC8+PC9maWx0ZXI+PC9kZWZzPjxpbWFnZSB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIGZpbHRlcj0idXJsKCNkYXJrcmVhZGVyLWltYWdlLWZpbHRlcikiIHhsaW5rOmhyZWY9ImRhdGE6aW1hZ2Uvc3ZnK3htbDtiYXNlNjQsUEQ5NGJXd2dkbVZ5YzJsdmJqMGlNUzR3SWlBL1BqeHpkbWNnWm1sc2JEMGlibTl1WlNJZ2FHVnBaMmgwUFNJeU1DSWdkbWxsZDBKdmVEMGlNQ0F3SURJd0lESXdJaUIzYVdSMGFEMGlNakFpSUhodGJHNXpQU0pvZEhSd09pOHZkM2QzTG5jekxtOXlaeTh5TURBd0wzTjJaeUkrUEhCaGRHZ2daRDBpVFRNdU1qVWdOME16TGprME1ETTJJRGNnTkM0MUlEWXVORFF3TXpZZ05DNDFJRFV1TnpWRE5DNDFJRFV1TURVNU5qUWdNeTQ1TkRBek5pQTBMalVnTXk0eU5TQTBMalZETWk0MU5UazJOQ0EwTGpVZ01pQTFMakExT1RZMElESWdOUzQzTlVNeUlEWXVORFF3TXpZZ01pNDFOVGsyTkNBM0lETXVNalVnTjFwTk55QTFMamMxUXpjZ05TNHpNelUzT1NBM0xqTXpOVGM1SURVZ055NDNOU0ExU0RFM0xqSTFRekUzTGpZMk5ESWdOU0F4T0NBMUxqTXpOVGM1SURFNElEVXVOelZETVRnZ05pNHhOalF5TVNBeE55NDJOalF5SURZdU5TQXhOeTR5TlNBMkxqVklOeTQzTlVNM0xqTXpOVGM1SURZdU5TQTNJRFl1TVRZME1qRWdOeUExTGpjMVdrMDNMamMxSURFd1F6Y3VNek0xTnprZ01UQWdOeUF4TUM0ek16VTRJRGNnTVRBdU56VkROeUF4TVM0eE5qUXlJRGN1TXpNMU56a2dNVEV1TlNBM0xqYzFJREV4TGpWSU1UY3VNalZETVRjdU5qWTBNaUF4TVM0MUlERTRJREV4TGpFMk5ESWdNVGdnTVRBdU56VkRNVGdnTVRBdU16TTFPQ0F4Tnk0Mk5qUXlJREV3SURFM0xqSTFJREV3U0RjdU56VmFUVGN1TnpVZ01UVkROeTR6TXpVM09TQXhOU0EzSURFMUxqTXpOVGdnTnlBeE5TNDNOVU0zSURFMkxqRTJORElnTnk0ek16VTNPU0F4Tmk0MUlEY3VOelVnTVRZdU5VZ3hOeTR5TlVNeE55NDJOalF5SURFMkxqVWdNVGdnTVRZdU1UWTBNaUF4T0NBeE5TNDNOVU14T0NBeE5TNHpNelU0SURFM0xqWTJORElnTVRVZ01UY3VNalVnTVRWSU55NDNOVnBOTkM0MUlERXdMamMxUXpRdU5TQXhNUzQwTkRBMElETXVPVFF3TXpZZ01USWdNeTR5TlNBeE1rTXlMalUxT1RZMElERXlJRElnTVRFdU5EUXdOQ0F5SURFd0xqYzFReklnTVRBdU1EVTVOaUF5TGpVMU9UWTBJRGt1TlNBekxqSTFJRGt1TlVNekxqazBNRE0ySURrdU5TQTBMalVnTVRBdU1EVTVOaUEwTGpVZ01UQXVOelZhVFRNdU1qVWdNVGRETXk0NU5EQXpOaUF4TnlBMExqVWdNVFl1TkRRd05DQTBMalVnTVRVdU56VkROQzQxSURFMUxqQTFPVFlnTXk0NU5EQXpOaUF4TkM0MUlETXVNalVnTVRRdU5VTXlMalUxT1RZMElERTBMalVnTWlBeE5TNHdOVGsySURJZ01UVXVOelZETWlBeE5pNDBOREEwSURJdU5UVTVOalFnTVRjZ015NHlOU0F4TjFvaUlHWnBiR3c5SWlNeU1USXhNakVpTHo0OEwzTjJaejQ9IiAvPjwvc3ZnPg=="); -} -.wmd-heading-button { - background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMTc5MiIgaGVpZ2h0PSIxNzkyIj48ZGVmcz48ZmlsdGVyIGlkPSJkYXJrcmVhZGVyLWltYWdlLWZpbHRlciI+PGZlQ29sb3JNYXRyaXggdHlwZT0ibWF0cml4IiB2YWx1ZXM9IjAuMjQ5IC0wLjYxNCAtMC42NzIgMC4wMDAgMS4wMzUgLTAuNjQ2IDAuMjg4IC0wLjY2NCAwLjAwMCAxLjAyMCAtMC42MzYgLTAuNjA5IDAuMjUwIDAuMDAwIDAuOTk0IDAuMDAwIDAuMDAwIDAuMDAwIDEuMDAwIDAuMDAwIiAvPjwvZmlsdGVyPjwvZGVmcz48aW1hZ2Ugd2lkdGg9IjE3OTIiIGhlaWdodD0iMTc5MiIgZmlsdGVyPSJ1cmwoI2RhcmtyZWFkZXItaW1hZ2UtZmlsdGVyKSIgeGxpbms6aHJlZj0iIiAvPjwvc3ZnPg=="); -} -.wmd-hr-button { - background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMTUwIiBoZWlnaHQ9IjE1MCI+PGRlZnM+PGZpbHRlciBpZD0iZGFya3JlYWRlci1pbWFnZS1maWx0ZXIiPjxmZUNvbG9yTWF0cml4IHR5cGU9Im1hdHJpeCIgdmFsdWVzPSIwLjI0OSAtMC42MTQgLTAuNjcyIDAuMDAwIDEuMDM1IC0wLjY0NiAwLjI4OCAtMC42NjQgMC4wMDAgMS4wMjAgLTAuNjM2IC0wLjYwOSAwLjI1MCAwLjAwMCAwLjk5NCAwLjAwMCAwLjAwMCAwLjAwMCAxLjAwMCAwLjAwMCIgLz48L2ZpbHRlcj48L2RlZnM+PGltYWdlIHdpZHRoPSIxNTAiIGhlaWdodD0iMTUwIiBmaWx0ZXI9InVybCgjZGFya3JlYWRlci1pbWFnZS1maWx0ZXIpIiB4bGluazpocmVmPSJkYXRhOmltYWdlL3N2Zyt4bWw7YmFzZTY0LFBEOTRiV3dnZG1WeWMybHZiajBpTVM0d0lpQS9Qanh6ZG1jZ2RtbGxkMEp2ZUQwaU1DQXdJREl3SURJd0lpQjRiV3h1Y3owaWFIUjBjRG92TDNkM2R5NTNNeTV2Y21jdk1qQXdNQzl6ZG1jaVBqeHdZWFJvSUdROUlrMHhJREZvTW5ZeVNERldNWHB0TUNBMGFESjJNa2d4VmpWNmJUQWdOR2d4T0hZeVNERldPWHB0TUNBMGFESjJNa2d4ZGkweWVtMHdJRFJvTW5ZeVNERjJMVEo2VFRVZ01XZ3lkakpJTlZZeGVtMHdJREUyYURKMk1rZzFkaTB5ZWswNUlERm9Nbll5U0RsV01YcHRNQ0EwYURKMk1rZzVWalY2YlRBZ09HZ3lkakpJT1hZdE1ucHRNQ0EwYURKMk1rZzVkaTB5ZW0wMExURTJhREoyTW1ndE1sWXhlbTB3SURFMmFESjJNbWd0TW5ZdE1ucHROQzB4Tm1neWRqSm9MVEpXTVhwdE1DQTBhREoyTW1ndE1sWTFlbTB3SURob01uWXlhQzB5ZGkweWVtMHdJRFJvTW5ZeWFDMHlkaTB5ZWlJdlBqd3ZjM1puUGc9PSIgLz48L3N2Zz4="); -} -.wmd-undo-button { - background-image: url("http://127.0.0.1:8000/static/pagedown/resources/undo.svg"); -} -.wmd-redo-button { - background-image: url("http://127.0.0.1:8000/static/pagedown/resources/redo.svg"); -} -.wmd-admonition-button { - background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMTUwIiBoZWlnaHQ9IjE1MCI+PGRlZnM+PGZpbHRlciBpZD0iZGFya3JlYWRlci1pbWFnZS1maWx0ZXIiPjxmZUNvbG9yTWF0cml4IHR5cGU9Im1hdHJpeCIgdmFsdWVzPSIwLjI0OSAtMC42MTQgLTAuNjcyIDAuMDAwIDEuMDM1IC0wLjY0NiAwLjI4OCAtMC42NjQgMC4wMDAgMS4wMjAgLTAuNjM2IC0wLjYwOSAwLjI1MCAwLjAwMCAwLjk5NCAwLjAwMCAwLjAwMCAwLjAwMCAxLjAwMCAwLjAwMCIgLz48L2ZpbHRlcj48L2RlZnM+PGltYWdlIHdpZHRoPSIxNTAiIGhlaWdodD0iMTUwIiBmaWx0ZXI9InVybCgjZGFya3JlYWRlci1pbWFnZS1maWx0ZXIpIiB4bGluazpocmVmPSJkYXRhOmltYWdlL3N2Zyt4bWw7YmFzZTY0LFBEOTRiV3dnZG1WeWMybHZiajBpTVM0d0lpQS9QandoUkU5RFZGbFFSU0J6ZG1jZ0lGQlZRa3hKUXlBbkxTOHZWek5ETHk5RVZFUWdVMVpISURFdU1TOHZSVTRuSUNBbmFIUjBjRG92TDNkM2R5NTNNeTV2Y21jdlIzSmhjR2hwWTNNdlUxWkhMekV1TVM5RVZFUXZjM1puTVRFdVpIUmtKejQ4YzNabklHVnVZV0pzWlMxaVlXTnJaM0p2ZFc1a1BTSnVaWGNnTUNBd0lEVXhNaUExTVRJaUlHbGtQU0pNWVhsbGNsOHhJaUIyWlhKemFXOXVQU0l4TGpFaUlIWnBaWGRDYjNnOUlqQWdNQ0ExTVRJZ05URXlJaUI0Yld3NmMzQmhZMlU5SW5CeVpYTmxjblpsSWlCNGJXeHVjejBpYUhSMGNEb3ZMM2QzZHk1M015NXZjbWN2TWpBd01DOXpkbWNpSUhodGJHNXpPbmhzYVc1clBTSm9kSFJ3T2k4dmQzZDNMbmN6TG05eVp5OHhPVGs1TDNoc2FXNXJJajQ4Wno0OFp6NDhjR0YwYUNCa1BTSk5NelkxTERFMk55NDRTREl5T0M0eVl5MDFMamNzTUMweE1DNDBMVFF1TnkweE1DNDBMVEV3TGpSMkxUQXVPR013TFRVdU55dzBMamN0TVRBdU5Dd3hNQzQwTFRFd0xqUklNelkxWXpVdU55d3dMREV3TGpRc05DNDNMREV3TGpRc01UQXVOQ0FnSUNCMk1DNDRRek0zTlM0MUxERTJNeTR4TERNM01DNDRMREUyTnk0NExETTJOU3d4TmpjdU9Ib2lJR1pwYkd3OUlpTXpNRE5CTTBZaUx6NDhjR0YwYUNCa1BTSk5NelkxTERJeU9DNDRTREUxTXk0NVl5MDFMamNzTUMweE1DNDBMVFF1TnkweE1DNDBMVEV3TGpSMkxUQXVPR013TFRVdU55dzBMamN0TVRBdU5Dd3hNQzQwTFRFd0xqUklNelkxWXpVdU55d3dMREV3TGpRc05DNDNMREV3TGpRc01UQXVOQ0FnSUNCMk1DNDRRek0zTlM0MUxESXlOQzR4TERNM01DNDRMREl5T0M0NExETTJOU3d5TWpndU9Ib2lJR1pwYkd3OUlpTXpNRE5CTTBZaUx6NDhjR0YwYUNCa1BTSk5NelkxTERJNE9TNDRTREUxTXk0NVl5MDFMamNzTUMweE1DNDBMVFF1TnkweE1DNDBMVEV3TGpSMkxUQXVPR013TFRVdU55dzBMamN0TVRBdU5Dd3hNQzQwTFRFd0xqUklNelkxWXpVdU55d3dMREV3TGpRc05DNDNMREV3TGpRc01UQXVOQ0FnSUNCMk1DNDRRek0zTlM0MUxESTROUzR4TERNM01DNDRMREk0T1M0NExETTJOU3d5T0RrdU9Ib2lJR1pwYkd3OUlpTXpNRE5CTTBZaUx6NDhjR0YwYUNCa1BTSk5NelkxTERNMU1DNDVTREUxTXk0NVl5MDFMamNzTUMweE1DNDBMVFF1TnkweE1DNDBMVEV3TGpSMkxUQXVPR013TFRVdU55dzBMamN0TVRBdU5Dd3hNQzQwTFRFd0xqUklNelkxWXpVdU55d3dMREV3TGpRc05DNDNMREV3TGpRc01UQXVOQ0FnSUNCMk1DNDRRek0zTlM0MUxETTBOaTR5TERNM01DNDRMRE0xTUM0NUxETTJOU3d6TlRBdU9Yb2lJR1pwYkd3OUlpTXpNRE5CTTBZaUx6NDhjR0YwYUNCa1BTSk5NelkxTERReE1TNDVTREUxTXk0NVl5MDFMamNzTUMweE1DNDBMVFF1TnkweE1DNDBMVEV3TGpSMkxUQXVPR013TFRVdU55dzBMamN0TVRBdU5Dd3hNQzQwTFRFd0xqUklNelkxWXpVdU55d3dMREV3TGpRc05DNDNMREV3TGpRc01UQXVOQ0FnSUNCMk1DNDRRek0zTlM0MUxEUXdOeTR5TERNM01DNDRMRFF4TVM0NUxETTJOU3cwTVRFdU9Yb2lJR1pwYkd3OUlpTXpNRE5CTTBZaUx6NDhMMmMrUEhCaGRHZ2daRDBpVFRNNU1pdzBNeTQxU0RFM09TNHliRE00TGpZc05URXVOR2d4TkRRdU4yTXlOeTR5TERBc05Ea3VOU3d5TWk0ekxEUTVMalVzTkRrdU5YWXlOamt1TTJNd0xESTNMakl0TWpJdU15dzBPUzQxTFRRNUxqVXNORGt1TlVneE5UUXVOQ0FnSUdNdE1qY3VNaXd3TFRRNUxqVXRNakl1TXkwME9TNDFMVFE1TGpWV01UVXdMamxNTmpVdU15dzVPQzQwWXkwd0xqTXNNaTQzTFRBdU9DdzFMak10TUM0NExEaDJNelF5TGpOak1Dd3pOQzQyTERJNExqTXNOak1zTmpNc05qTklNemt5WXpNMExqWXNNQ3cyTXkweU9DNHpMRFl6TFRZelZqRXdOaTQwSUNBZ1F6UTFOQzQ1TERjeExqZ3NOREkyTGpZc05ETXVOU3d6T1RJc05ETXVOWG9pSUdacGJHdzlJaU16TUROQk0wWWlMejQ4Wno0OGNHRjBhQ0JrUFNKTk1USTFMalVzTVRRNUxqaHNOamd1TXl3eU5XTXpMallzTVM0ekxEWXVOUzB3TGpjc05pNHpMVFF1Tm13dE15NHlMVGN5TGpkakxUQXVNUzB4TGpVdE1DNDFMVEl1T1MweExqTXROQzR6YkRBdU1TMHdMakVnSUNBZ1l5MHdMakV0TUM0eUxUQXVNeTB3TGpRdE1DNDBMVEF1Tm13dE5EZ3VPQzAyTmk0MmJDMHhOaXd4TVM0M2JEUTBMakVzTmpBdU1tTXhMamdzTWk0MExERXVNaXcxTGpndE1TNHlMRGN1Tm13dE15NDRMREl1T0dNdE1pNDBMREV1T0MwMUxqZ3NNUzR5TFRjdU5pMHhMakpNTVRFNExEUTJMamtnSUNBZ2JDMHhOUzQ0TERFeExqWnNORFF1TkN3Mk1DNDNZekV1Tml3eUxqSXNNUzR4TERVdU1pMHhMakVzTmk0NGJDMDBMamNzTXk0MVl5MHlMaklzTVM0MkxUVXVNaXd4TGpFdE5pNDRMVEV1TVV3NE9TNDJMRFkzTGpaTU56SXVOaXc0TUd3ME55NHlMRFkwTGpRZ0lDQWdRekV5TVN3eE5EWXVPQ3d4TWpNc01UUTRMamtzTVRJMUxqVXNNVFE1TGpoNklFMHhNemdzTVRReExqbHNORGN1Tmkwek5DNDVZekl1T1MweUxqRXNOeTQyTERFdU15dzNMamdzTlM0NGJERXVNU3d6T1M0M1l5MHdMamNzTUM0eUxURXVOQ3d3TGpNdE1pd3dMamRzTFRFMExqSXNNVEF1TkNBZ0lDQmpMVEF1TVN3d0xqRXRNQzR6TERBdE1DNHpMREF1TVd3dE16WXVPQzB4TWk0MlF6RXpOeXd4TkRrdU5pd3hNelV1TVN3eE5EUXNNVE00TERFME1TNDVlaUlnWm1sc2JEMGlJek13TTBFelJpSXZQanh3WVhSb0lHUTlJazAyT0M0NUxEYzFMak5zTFRVdU55MDNMamRqTFRFd0xqVXRNVFF1TXkwM0xqTXRNelF1TlN3M0xUUTFiREl5TFRFMkxqRmpNVFF1TXkweE1DNDFMRE0wTGpVdE55NHpMRFExTERkc05TNDNMRGN1TjB3Mk9DNDVMRGMxTGpONklpQm1hV3hzUFNJak16QXpRVE5HSWk4K1BDOW5Qand2Wno0OEwzTjJaejQ9IiAvPjwvc3ZnPg=="); -} -.wmd-spoiler-button { - background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMTUwIiBoZWlnaHQ9IjE1MCI+PGRlZnM+PGZpbHRlciBpZD0iZGFya3JlYWRlci1pbWFnZS1maWx0ZXIiPjxmZUNvbG9yTWF0cml4IHR5cGU9Im1hdHJpeCIgdmFsdWVzPSIwLjI0OSAtMC42MTQgLTAuNjcyIDAuMDAwIDEuMDM1IC0wLjY0NiAwLjI4OCAtMC42NjQgMC4wMDAgMS4wMjAgLTAuNjM2IC0wLjYwOSAwLjI1MCAwLjAwMCAwLjk5NCAwLjAwMCAwLjAwMCAwLjAwMCAxLjAwMCAwLjAwMCIgLz48L2ZpbHRlcj48L2RlZnM+PGltYWdlIHdpZHRoPSIxNTAiIGhlaWdodD0iMTUwIiBmaWx0ZXI9InVybCgjZGFya3JlYWRlci1pbWFnZS1maWx0ZXIpIiB4bGluazpocmVmPSJkYXRhOmltYWdlL3N2Zyt4bWw7YmFzZTY0LFBEOTRiV3dnZG1WeWMybHZiajBpTVM0d0lpQS9Qanh6ZG1jZ1pHRjBZUzF1WVcxbFBTSk1ZWGxsY2lBeElpQnBaRDBpVEdGNVpYSmZNU0lnZG1sbGQwSnZlRDBpTUNBd0lETXlJRE15SWlCNGJXeHVjejBpYUhSMGNEb3ZMM2QzZHk1M015NXZjbWN2TWpBd01DOXpkbWNpUGp4MGFYUnNaUzgrUEhCaGRHZ2daRDBpVFRJM0xqTTNMREpJTVRRdU1EVmhPQzR3Tnl3NExqQTNMREFzTUN3eExESXVOemNzTmk0eExEY3VPVEVzTnk0NU1Td3dMREFzTVMwdU5qTXNNeTR4TW1nM0xqUTRZUzQ1TkM0NU5Dd3dMREVzTVN3d0xERXVPRGRJTVRVdU1XTXRMakUyTGpJdExqTTBMalF0TGpVeUxqVTVZVGd1TVRJc09DNHhNaXd3TERBc01TMDFMamcxTERJdU5URXNNaTR4Tnl3eUxqRTNMREFzTUN3eExTNHpOaXd3VmpJNFlUSXNNaXd3TERBc01Dd3lMREpvTVRkaE1pd3lMREFzTUN3d0xESXRNbFkwUVRJc01pd3dMREFzTUN3eU55NHpOeXd5V20wdE15NDNMREU0TGpjNGFDMDVMalpoTGprMExqazBMREFzTVN3eExEQXRNUzQ0TjJnNUxqWmhMamswTGprMExEQXNNU3d4TERBc01TNDROMXB0TUMwekxqZzFhQzA1TGpaaExqa3pMamt6TERBc01Td3hMREF0TVM0NE5tZzVMalpoTGprekxqa3pMREFzTVN3eExEQXNNUzQ0TmxvaUx6NDhjR0YwYUNCa1BTSk5PQzQzTXl3eE5DNHhPV0UyTGpBM0xEWXVNRGNzTUN3d0xEQXNOQzQwTVMweExqbEJOUzQyTVN3MUxqWXhMREFzTUN3d0xERTBMREV4TGpJellUWXNOaXd3TERBc01Dd3VPRGN0TXk0eE15dzJMakVzTmk0eExEQXNNQ3d3TFRVdE5tZ3dZVFlzTml3d0xEQXNNQzB4TFM0d09TdzJMakE1TERZdU1Ea3NNQ3d3TERBdExqTTJMREV5TGpFM1FUSXVNVGNzTWk0eE55d3dMREFzTUN3NExqY3pMREUwTGpFNVdtMHRNeTAyTGpBNVlURXNNU3d3TERBc01Td3hMVEZvTkdFeExERXNNQ3d3TERFc01Dd3lhQzAwUVRFc01Td3dMREFzTVN3MUxqY3pMRGd1TVZvaUx6NDhMM04yWno0PSIgLz48L3N2Zz4="); -} -.wmd-button-active:hover { - background-color: rgb(49, 53, 55); -} -.wmd-prompt-background { - background-color: rgb(0, 0, 0); -} -.wmd-prompt-dialog { - background-color: rgb(30, 32, 33); - border-color: rgb(77, 83, 86); -} -.wmd-prompt-dialog > form > input[type="text"] { - border-color: rgb(77, 83, 86); - color: rgb(232, 230, 227); -} -.wmd-prompt-dialog > form > input[type="button"] { - border-color: rgb(82, 88, 92); -} -.wmd-preview { - background-color: rgb(24, 26, 27); - background-image: initial; - border-color: rgb(72, 78, 81); -} -.pagedown-image-upload { - background-color: rgb(24, 26, 27); - background-image: initial; - box-shadow: rgba(0, 0, 0, 0.5) 2px 2px 10px 0px; -} -.pagedown-image-upload .submit-loading { - border-color: rgb(46, 91, 113) rgb(51, 56, 58) rgb(51, 56, 58); -} -div.dmmd-preview-update { - background-color: rgb(53, 57, 59); - background-image: initial; - color: rgb(200, 195, 188); -} -div.dmmd-preview-stale { - background-color: initial; - background-image: repeating-linear-gradient(-45deg, rgb(24, 26, 27), rgb(24, 26, 27) 10px, rgb(28, 30, 31) 10px, rgb(28, 30, 31) 20px); -} -.course-list { - list-style-image: initial; -} -.course-list .course-item { - background-color: rgb(24, 26, 27); - border-color: rgb(58, 62, 65); - box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 6px; -} -.course-list .course-item:hover { - box-shadow: rgba(0, 0, 0, 0.15) 0px 6px 12px; -} -.lesson-list { - list-style-image: initial; -} -.lesson-list li:hover { - background-color: rgb(52, 52, 0); - background-image: initial; - box-shadow: rgba(0, 0, 0, 0.15) 0px 6px 12px; -} -.lesson-list li { - background-color: rgb(24, 26, 27); - background-image: initial; - border-color: rgb(58, 62, 65); - box-shadow: rgb(53, 57, 59) 0px 2px 4px; -} -.lesson-list .lesson-title { - color: initial; -} -.lesson-list .lesson-title .lesson-points { - color: rgb(169, 162, 151); -} -.lesson-list .progress-container { - background-color: rgb(42, 45, 47); - background-image: initial; -} -.lesson-list .progress-bar { - background-color: rgb(27, 111, 27); - background-image: initial; - color: rgb(232, 230, 227); -} -.course-problem-list li { - border-bottom-color: rgb(53, 57, 59); -} -.course-problem-list li:hover { - background-color: rgb(42, 45, 47); - background-image: initial; -} -.course-problem-list a { - color: inherit; - text-decoration-color: initial; -} -.course-contest-card { - border-color: rgb(58, 62, 65); - box-shadow: rgba(0, 0, 0, 0.1) 2px 2px 10px; -} -.course-contest-card h5 { - color: rgb(200, 195, 188); -} -.course-contest-card p { - color: rgb(178, 172, 162); -} -.fa-border { - border: var(--darkreader-border--fa-border-width, .08em) var(--darkreader-border--fa-border-style, solid) var(--darkreader-border--fa-border-color, #35393b); -} -.fa-spin-reverse { - --fa-animation-direction: reverse; -} -.fa-inverse { - color: var(--darkreader-text--fa-inverse, #e8e6e3); -} -:host, -:root { - --fa-font-brands: normal 400 1em/1 "Font Awesome 6 Brands"; - --fa-style-family-brands: "Font Awesome 6 Brands"; -} -:host, -:root { - --fa-font-regular: normal 400 1em/1 "Font Awesome 6 Free"; -} -:host, -:root { - --fa-font-solid: normal 900 1em/1 "Font Awesome 6 Free"; - --fa-style-family-classic: "Font Awesome 6 Free"; -} -@media all { - .featherlight { - background-color: rgba(0, 0, 0, 0); - background-image: initial; - } - .featherlight:last-of-type { - background-color: rgba(0, 0, 0, 0.8); - background-image: initial; - } - .featherlight .featherlight-content { - background-color: rgb(24, 26, 27); - background-image: initial; - border-bottom-color: transparent; - } - .featherlight .featherlight-close-icon { - background-color: rgba(24, 26, 27, 0.3); - background-image: initial; - color: rgb(232, 230, 227); - } - .featherlight-iframe .featherlight-content { - border-bottom: 0px; - } - .featherlight iframe { - border-color: initial; - border-style: initial; - border-width: 0px; - } -} -@media only screen and (max-width: 1024px) { - .featherlight .featherlight-content { - border-bottom-color: transparent; - } -} -.tooltipped::after { - background-color: rgba(0, 0, 0, 0.8); - background-image: initial; - color: rgb(232, 230, 227); - text-decoration-color: initial; - text-shadow: none; -} -.tooltipped::before { - border-color: transparent; - color: rgba(232, 230, 227, 0.8); -} -.tooltipped:hover::before, -.tooltipped:hover::after, -.tooltipped:active::before, -.tooltipped:active::after, -.tooltipped:focus::before, -.tooltipped:focus::after { - text-decoration-color: initial; -} -.tooltipped-s::before, -.tooltipped-se::before, -.tooltipped-sw::before { - border-bottom-color: rgba(140, 130, 115, 0.8); -} -.tooltipped-n::before, -.tooltipped-ne::before, -.tooltipped-nw::before { - border-top-color: rgba(140, 130, 115, 0.8); -} -.tooltipped-w::before { - border-left-color: rgba(140, 130, 115, 0.8); -} -.tooltipped-e::before { - border-right-color: rgba(140, 130, 115, 0.8); -} -.select2-container .select2-search--inline .select2-search__field { - border-color: initial; - border-style: none; - border-width: initial; -} -.select2-dropdown { - background-color: rgb(24, 26, 27); - border-color: rgb(72, 78, 81); -} -.select2-results__options { - list-style-image: initial; -} -.select2-container--open .select2-dropdown--above { - border-bottom: none; -} -.select2-container--open .select2-dropdown--below { - border-top: none; -} -.select2-close-mask { - background-color: rgb(24, 26, 27); - border-color: initial; - border-style: initial; - border-width: 0px; -} -.select2-hidden-accessible { - border-color: initial !important; - border-style: initial !important; - border-width: 0px !important; -} -.select2-container--default .select2-selection--single { - background-color: rgb(24, 26, 27); - border-color: rgb(72, 78, 81); -} -.select2-container--default .select2-selection--single .select2-selection__rendered { - color: rgb(189, 183, 175); -} -.select2-container--default .select2-selection--single .select2-selection__placeholder { - color: rgb(168, 160, 149); -} -.select2-container--default .select2-selection--single .select2-selection__arrow b { - border-color: rgb(82, 88, 92) transparent transparent; -} -.select2-container--default.select2-container--disabled .select2-selection--single { - background-color: rgb(34, 36, 38); -} -.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b { - border-color: transparent transparent rgb(82, 88, 92); -} -.select2-container--default .select2-selection--multiple { - background-color: rgb(24, 26, 27); - border-color: rgb(72, 78, 81); -} -.select2-container--default .select2-selection--multiple .select2-selection__rendered { - list-style-image: initial; -} -.select2-container--default .select2-selection--multiple .select2-selection__placeholder { - color: rgb(168, 160, 149); -} -.select2-container--default .select2-selection--multiple .select2-selection__choice { - background-color: rgb(39, 43, 44); - border-color: rgb(72, 78, 81); -} -.select2-container--default .select2-selection--multiple .select2-selection__choice__remove { - color: rgb(168, 160, 149); -} -.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover { - color: rgb(200, 195, 188); -} -.select2-container--default.select2-container--focus .select2-selection--multiple { - border-color: rgb(140, 130, 115); - outline-color: initial; -} -.select2-container--default.select2-container--disabled .select2-selection--multiple { - background-color: rgb(34, 36, 38); -} -.select2-container--default .select2-search--dropdown .select2-search__field { - border-color: rgb(72, 78, 81); -} -.select2-container--default .select2-search--inline .select2-search__field { - background-color: transparent; - background-image: initial; - border-color: initial; - border-style: none; - border-width: initial; - box-shadow: none; - outline-color: initial; -} -.select2-container--default .select2-results__option[aria-disabled="true"] { - color: rgb(168, 160, 149); -} -.select2-container--default .select2-results__option[aria-selected="true"] { - background-color: rgb(43, 47, 49); -} -.select2-container--default .select2-results__option--highlighted[aria-selected] { - background-color: rgb(4, 60, 150); - color: rgb(232, 230, 227); -} -.select2-container--classic .select2-selection--single { - background-color: rgb(29, 31, 32); - background-image: linear-gradient(rgb(24, 26, 27) 50%, rgb(34, 36, 38) 100%); - border-color: rgb(72, 78, 81); - outline-color: initial; -} -.select2-container--classic .select2-selection--single:focus { - border-color: rgb(4, 60, 150); -} -.select2-container--classic .select2-selection--single .select2-selection__rendered { - color: rgb(189, 183, 175); -} -.select2-container--classic .select2-selection--single .select2-selection__placeholder { - color: rgb(168, 160, 149); -} -.select2-container--classic .select2-selection--single .select2-selection__arrow { - background-color: rgb(43, 47, 49); - background-image: linear-gradient(rgb(34, 36, 38) 50%, rgb(53, 57, 59) 100%); - border-bottom: none; - border-left-color: rgb(72, 78, 81); - border-right: none; - border-top: none; -} -.select2-container--classic .select2-selection--single .select2-selection__arrow b { - border-color: rgb(82, 88, 92) transparent transparent; -} -.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__arrow { - border-bottom: none; - border-left: none; - border-right-color: rgb(72, 78, 81); - border-top: none; -} -.select2-container--classic.select2-container--open .select2-selection--single { - border-color: rgb(4, 60, 150); -} -.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow { - background-color: transparent; - background-image: initial; - border-color: initial; - border-style: none; - border-width: initial; -} -.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b { - border-color: transparent transparent rgb(82, 88, 92); -} -.select2-container--classic.select2-container--open.select2-container--above .select2-selection--single { - background-image: linear-gradient(rgb(24, 26, 27) 0%, rgb(34, 36, 38) 50%); - border-top: none; -} -.select2-container--classic.select2-container--open.select2-container--below .select2-selection--single { - background-image: linear-gradient(rgb(34, 36, 38) 50%, rgb(24, 26, 27) 100%); - border-bottom: none; -} -.select2-container--classic .select2-selection--multiple { - background-color: rgb(24, 26, 27); - border-color: rgb(72, 78, 81); - outline-color: initial; -} -.select2-container--classic .select2-selection--multiple:focus { - border-color: rgb(4, 60, 150); -} -.select2-container--classic .select2-selection--multiple .select2-selection__rendered { - list-style-image: initial; -} -.select2-container--classic .select2-selection--multiple .select2-selection__choice { - background-color: rgb(39, 43, 44); - border-color: rgb(72, 78, 81); -} -.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove { - color: rgb(157, 148, 136); -} -.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover { - color: rgb(178, 172, 162); -} -.select2-container--classic.select2-container--open .select2-selection--multiple { - border-color: rgb(4, 60, 150); -} -.select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple { - border-top: none; -} -.select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple { - border-bottom: none; -} -.select2-container--classic .select2-search--dropdown .select2-search__field { - border-color: rgb(72, 78, 81); - outline-color: initial; -} -.select2-container--classic .select2-search--inline .select2-search__field { - box-shadow: none; - outline-color: initial; -} -.select2-container--classic .select2-dropdown { - background-color: rgb(24, 26, 27); - border-color: transparent; -} -.select2-container--classic .select2-dropdown--above { - border-bottom: none; -} -.select2-container--classic .select2-dropdown--below { - border-top: none; -} -.select2-container--classic .select2-results__option[aria-disabled="true"] { - color: rgb(152, 143, 129); -} -.select2-container--classic .select2-results__option--highlighted[aria-selected] { - background-color: rgb(33, 82, 162); - color: rgb(232, 230, 227); -} -.select2-container--classic.select2-container--open .select2-dropdown { - border-color: rgb(4, 60, 150); -} -.icofont-border { - border-color: rgb(52, 56, 58); -} -.icofont-inverse { - color: rgb(232, 230, 227); -} -.sr-only { - border-color: initial; - border-style: initial; - border-width: 0px; -} -.katex * { - border-color: currentcolor; -} -.katex .katex-mathml { - border-color: initial; - border-style: initial; - border-width: 0px; -} -.katex .rule { - border-color: initial; - border-style: solid; - border-width: 0px; -} -.katex svg { - fill: currentcolor; - stroke: currentcolor; -} -.katex svg path { - stroke: none; -} -.katex .fbox, -.katex .fcolorbox { - border-color: initial; -} -.katex .angl { - border-right-color: initial; - border-top-color: initial; -} - -/* Override Style */ -.vimvixen-hint { - background-color: #684b00 !important; - border-color: #9e7e00 !important; - color: #d7d4cf !important; -} -#vimvixen-console-frame { - color-scheme: light !important; -} -::placeholder { - opacity: 0.5 !important; -} -#edge-translate-panel-body, -.MuiTypography-body1, -.nfe-quote-text { - color: var(--darkreader-neutral-text) !important; -} -gr-main-header { - background-color: #1b4958 !important; -} -.tou-z65h9k, -.tou-mignzq, -.tou-1b6i2ox, -.tou-lnqlqk { - background-color: var(--darkreader-neutral-background) !important; -} -.tou-75mvi { - background-color: #0f3a47 !important; -} -.tou-ta9e87, -.tou-1w3fhi0, -.tou-1b8t2us, -.tou-py7lfi, -.tou-1lpmd9d, -.tou-1frrtv8, -.tou-17ezmgn { - background-color: #1e2021 !important; -} -.tou-uknfeu { - background-color: #432c09 !important; -} -.tou-6i3zyv { - background-color: #245d70 !important; -} -div.mermaid-viewer-control-panel .btn { - background-color: var(--darkreader-neutral-background); - fill: var(--darkreader-neutral-text); -} -svg g rect.er { - fill: var(--darkreader-neutral-background) !important; -} -svg g rect.er.entityBox { - fill: var(--darkreader-neutral-background) !important; -} -svg g rect.er.attributeBoxOdd { - fill: var(--darkreader-neutral-background) !important; -} -svg g rect.er.attributeBoxEven { - fill: var(--darkreader-selection-background); - fill-opacity: 0.8 !important; -} -svg rect.er.relationshipLabelBox { - fill: var(--darkreader-neutral-background) !important; -} -svg g g.nodes rect, -svg g g.nodes polygon { - fill: var(--darkreader-neutral-background) !important; -} -svg g rect.task { - fill: var(--darkreader-selection-background) !important; -} -svg line.messageLine0, -svg line.messageLine1 { - stroke: var(--darkreader-neutral-text) !important; -} -div.mermaid .actor { - fill: var(--darkreader-neutral-background) !important; -} -mitid-authenticators-code-app > .code-app-container { - background-color: white !important; - padding-top: 1rem; -} -iframe#unpaywall[src$="unpaywall.html"] { - color-scheme: light !important; -} diff --git a/resources/datetime-picker/datetimepicker.full.min.js b/resources/datetime-picker/datetimepicker.full.min.js deleted file mode 100644 index a2a09c6..0000000 --- a/resources/datetime-picker/datetimepicker.full.min.js +++ /dev/null @@ -1 +0,0 @@ -var DateFormatter;!function(){"use strict";var e,t,a,r,n,o,i;o=864e5,i=3600,e=function(e,t){return"string"==typeof e&&"string"==typeof t&&e.toLowerCase()===t.toLowerCase()},t=function(e,a,r){var n=r||"0",o=e.toString();return o.lengths?"20":"19")+i):s,h=!0;break;case"m":case"n":case"M":case"F":if(isNaN(s)){if(!((u=m.getMonth(i))>0))return null;D.month=u}else{if(!(s>=1&&12>=s))return null;D.month=s}h=!0;break;case"d":case"j":if(!(s>=1&&31>=s))return null;D.day=s,h=!0;break;case"g":case"h":if(d=r.indexOf("a")>-1?r.indexOf("a"):r.indexOf("A")>-1?r.indexOf("A"):-1,c=n[d],d>-1)l=e(c,p.meridiem[0])?0:e(c,p.meridiem[1])?12:-1,s>=1&&12>=s&&l>-1?D.hour=s+l-1:s>=0&&23>=s&&(D.hour=s);else{if(!(s>=0&&23>=s))return null;D.hour=s}g=!0;break;case"G":case"H":if(!(s>=0&&23>=s))return null;D.hour=s,g=!0;break;case"i":if(!(s>=0&&59>=s))return null;D.min=s,g=!0;break;case"s":if(!(s>=0&&59>=s))return null;D.sec=s,g=!0}if(!0===h&&D.year&&D.month&&D.day)D.date=new Date(D.year,D.month-1,D.day,D.hour,D.min,D.sec,0);else{if(!0!==g)return null;D.date=new Date(0,0,0,D.hour,D.min,D.sec,0)}return D.date},guessDate:function(e,t){if("string"!=typeof e)return e;var a,r,n,o,i,s,u=this,d=e.replace(u.separators,"\0").split("\0"),l=/^[djmn]/g,f=t.match(u.validParts),c=new Date,m=0;if(!l.test(f[0]))return e;for(n=0;na?a:4,!(r=parseInt(4>a?r.toString().substr(0,4-a)+i:i.substr(0,4))))return null;c.setFullYear(r);break;case 3:c.setHours(s);break;case 4:c.setMinutes(s);break;case 5:c.setSeconds(s)}(o=i.substr(m)).length>0&&d.splice(n+1,0,o)}return c},parseFormat:function(e,a){var r,n=this,s=n.dateSettings,u=/\\?(.?)/gi,d=function(e,t){return r[e]?r[e]():t};return r={d:function(){return t(r.j(),2)},D:function(){return s.daysShort[r.w()]},j:function(){return a.getDate()},l:function(){return s.days[r.w()]},N:function(){return r.w()||7},w:function(){return a.getDay()},z:function(){var e=new Date(r.Y(),r.n()-1,r.j()),t=new Date(r.Y(),0,1);return Math.round((e-t)/o)},W:function(){var e=new Date(r.Y(),r.n()-1,r.j()-r.N()+3),a=new Date(e.getFullYear(),0,4);return t(1+Math.round((e-a)/o/7),2)},F:function(){return s.months[a.getMonth()]},m:function(){return t(r.n(),2)},M:function(){return s.monthsShort[a.getMonth()]},n:function(){return a.getMonth()+1},t:function(){return new Date(r.Y(),r.n(),0).getDate()},L:function(){var e=r.Y();return e%4==0&&e%100!=0||e%400==0?1:0},o:function(){var e=r.n(),t=r.W();return r.Y()+(12===e&&9>t?1:1===e&&t>9?-1:0)},Y:function(){return a.getFullYear()},y:function(){return r.Y().toString().slice(-2)},a:function(){return r.A().toLowerCase()},A:function(){var e=r.G()<12?0:1;return s.meridiem[e]},B:function(){var e=a.getUTCHours()*i,r=60*a.getUTCMinutes(),n=a.getUTCSeconds();return t(Math.floor((e+r+n+i)/86.4)%1e3,3)},g:function(){return r.G()%12||12},G:function(){return a.getHours()},h:function(){return t(r.g(),2)},H:function(){return t(r.G(),2)},i:function(){return t(a.getMinutes(),2)},s:function(){return t(a.getSeconds(),2)},u:function(){return t(1e3*a.getMilliseconds(),6)},e:function(){return/\((.*)\)/.exec(String(a))[1]||"Coordinated Universal Time"},I:function(){return new Date(r.Y(),0)-Date.UTC(r.Y(),0)!=new Date(r.Y(),6)-Date.UTC(r.Y(),6)?1:0},O:function(){var e=a.getTimezoneOffset(),r=Math.abs(e);return(e>0?"-":"+")+t(100*Math.floor(r/60)+r%60,4)},P:function(){var e=r.O();return e.substr(0,3)+":"+e.substr(3,2)},T:function(){return(String(a).match(n.tzParts)||[""]).pop().replace(n.tzClip,"")||"UTC"},Z:function(){return 60*-a.getTimezoneOffset()},c:function(){return"Y-m-d\\TH:i:sP".replace(u,d)},r:function(){return"D, d M Y H:i:s O".replace(u,d)},U:function(){return a.getTime()/1e3||0}},d(e,e)},formatDate:function(e,t){var a,r,n,o,i,s=this,u="";if("string"==typeof e&&!(e=s.parseDate(e,t)))return null;if(e instanceof Date){for(n=t.length,a=0;n>a;a++)"S"!==(i=t.charAt(a))&&"\\"!==i&&(a>0&&"\\"===t.charAt(a-1)?u+=i:(o=s.parseFormat(i,e),a!==n-1&&s.intParts.test(i)&&"S"===t.charAt(a+1)&&(r=parseInt(o)||0,o+=s.dateSettings.ordinal(r)),u+=o));return u}return""}}}();var datetimepickerFactory=function(e){"use strict";function t(e,t,a){this.date=e,this.desc=t,this.style=a}var a={i18n:{ar:{months:["كانون الثاني","شباط","آذار","نيسان","مايو","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول"],dayOfWeekShort:["ن","ث","ع","خ","ج","س","ح"],dayOfWeek:["الأحد","الاثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت","الأحد"]},ro:{months:["Ianuarie","Februarie","Martie","Aprilie","Mai","Iunie","Iulie","August","Septembrie","Octombrie","Noiembrie","Decembrie"],dayOfWeekShort:["Du","Lu","Ma","Mi","Jo","Vi","Sâ"],dayOfWeek:["Duminică","Luni","Marţi","Miercuri","Joi","Vineri","Sâmbătă"]},id:{months:["Januari","Februari","Maret","April","Mei","Juni","Juli","Agustus","September","Oktober","November","Desember"],dayOfWeekShort:["Min","Sen","Sel","Rab","Kam","Jum","Sab"],dayOfWeek:["Minggu","Senin","Selasa","Rabu","Kamis","Jumat","Sabtu"]},is:{months:["Janúar","Febrúar","Mars","Apríl","Maí","Júní","Júlí","Ágúst","September","Október","Nóvember","Desember"],dayOfWeekShort:["Sun","Mán","Þrið","Mið","Fim","Fös","Lau"],dayOfWeek:["Sunnudagur","Mánudagur","Þriðjudagur","Miðvikudagur","Fimmtudagur","Föstudagur","Laugardagur"]},bg:{months:["Януари","Февруари","Март","Април","Май","Юни","Юли","Август","Септември","Октомври","Ноември","Декември"],dayOfWeekShort:["Нд","Пн","Вт","Ср","Чт","Пт","Сб"],dayOfWeek:["Неделя","Понеделник","Вторник","Сряда","Четвъртък","Петък","Събота"]},fa:{months:["فروردین","اردیبهشت","خرداد","تیر","مرداد","شهریور","مهر","آبان","آذر","دی","بهمن","اسفند"],dayOfWeekShort:["یکشنبه","دوشنبه","سه شنبه","چهارشنبه","پنجشنبه","جمعه","شنبه"],dayOfWeek:["یک‌شنبه","دوشنبه","سه‌شنبه","چهارشنبه","پنج‌شنبه","جمعه","شنبه","یک‌شنبه"]},ru:{months:["Январь","Февраль","Март","Апрель","Май","Июнь","Июль","Август","Сентябрь","Октябрь","Ноябрь","Декабрь"],dayOfWeekShort:["Вс","Пн","Вт","Ср","Чт","Пт","Сб"],dayOfWeek:["Воскресенье","Понедельник","Вторник","Среда","Четверг","Пятница","Суббота"]},uk:{months:["Січень","Лютий","Березень","Квітень","Травень","Червень","Липень","Серпень","Вересень","Жовтень","Листопад","Грудень"],dayOfWeekShort:["Ндл","Пнд","Втр","Срд","Чтв","Птн","Сбт"],dayOfWeek:["Неділя","Понеділок","Вівторок","Середа","Четвер","П'ятниця","Субота"]},en:{months:["January","February","March","April","May","June","July","August","September","October","November","December"],dayOfWeekShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayOfWeek:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"]},el:{months:["Ιανουάριος","Φεβρουάριος","Μάρτιος","Απρίλιος","Μάιος","Ιούνιος","Ιούλιος","Αύγουστος","Σεπτέμβριος","Οκτώβριος","Νοέμβριος","Δεκέμβριος"],dayOfWeekShort:["Κυρ","Δευ","Τρι","Τετ","Πεμ","Παρ","Σαβ"],dayOfWeek:["Κυριακή","Δευτέρα","Τρίτη","Τετάρτη","Πέμπτη","Παρασκευή","Σάββατο"]},de:{months:["Januar","Februar","März","April","Mai","Juni","Juli","August","September","Oktober","November","Dezember"],dayOfWeekShort:["So","Mo","Di","Mi","Do","Fr","Sa"],dayOfWeek:["Sonntag","Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag"]},nl:{months:["januari","februari","maart","april","mei","juni","juli","augustus","september","oktober","november","december"],dayOfWeekShort:["zo","ma","di","wo","do","vr","za"],dayOfWeek:["zondag","maandag","dinsdag","woensdag","donderdag","vrijdag","zaterdag"]},tr:{months:["Ocak","Şubat","Mart","Nisan","Mayıs","Haziran","Temmuz","Ağustos","Eylül","Ekim","Kasım","Aralık"],dayOfWeekShort:["Paz","Pts","Sal","Çar","Per","Cum","Cts"],dayOfWeek:["Pazar","Pazartesi","Salı","Çarşamba","Perşembe","Cuma","Cumartesi"]},fr:{months:["Janvier","Février","Mars","Avril","Mai","Juin","Juillet","Août","Septembre","Octobre","Novembre","Décembre"],dayOfWeekShort:["Dim","Lun","Mar","Mer","Jeu","Ven","Sam"],dayOfWeek:["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"]},es:{months:["Enero","Febrero","Marzo","Abril","Mayo","Junio","Julio","Agosto","Septiembre","Octubre","Noviembre","Diciembre"],dayOfWeekShort:["Dom","Lun","Mar","Mié","Jue","Vie","Sáb"],dayOfWeek:["Domingo","Lunes","Martes","Miércoles","Jueves","Viernes","Sábado"]},th:{months:["มกราคม","กุมภาพันธ์","มีนาคม","เมษายน","พฤษภาคม","มิถุนายน","กรกฎาคม","สิงหาคม","กันยายน","ตุลาคม","พฤศจิกายน","ธันวาคม"],dayOfWeekShort:["อา.","จ.","อ.","พ.","พฤ.","ศ.","ส."],dayOfWeek:["อาทิตย์","จันทร์","อังคาร","พุธ","พฤหัส","ศุกร์","เสาร์","อาทิตย์"]},pl:{months:["styczeń","luty","marzec","kwiecień","maj","czerwiec","lipiec","sierpień","wrzesień","październik","listopad","grudzień"],dayOfWeekShort:["nd","pn","wt","śr","cz","pt","sb"],dayOfWeek:["niedziela","poniedziałek","wtorek","środa","czwartek","piątek","sobota"]},pt:{months:["Janeiro","Fevereiro","Março","Abril","Maio","Junho","Julho","Agosto","Setembro","Outubro","Novembro","Dezembro"],dayOfWeekShort:["Dom","Seg","Ter","Qua","Qui","Sex","Sab"],dayOfWeek:["Domingo","Segunda","Terça","Quarta","Quinta","Sexta","Sábado"]},ch:{months:["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"],dayOfWeekShort:["日","一","二","三","四","五","六"]},se:{months:["Januari","Februari","Mars","April","Maj","Juni","Juli","Augusti","September","Oktober","November","December"],dayOfWeekShort:["Sön","Mån","Tis","Ons","Tor","Fre","Lör"]},km:{months:["មករា​","កុម្ភៈ","មិនា​","មេសា​","ឧសភា​","មិថុនា​","កក្កដា​","សីហា​","កញ្ញា​","តុលា​","វិច្ឆិកា","ធ្នូ​"],dayOfWeekShort:["អាទិ​","ច័ន្ទ​","អង្គារ​","ពុធ​","ព្រហ​​","សុក្រ​","សៅរ៍"],dayOfWeek:["អាទិត្យ​","ច័ន្ទ​","អង្គារ​","ពុធ​","ព្រហស្បតិ៍​","សុក្រ​","សៅរ៍"]},kr:{months:["1월","2월","3월","4월","5월","6월","7월","8월","9월","10월","11월","12월"],dayOfWeekShort:["일","월","화","수","목","금","토"],dayOfWeek:["일요일","월요일","화요일","수요일","목요일","금요일","토요일"]},it:{months:["Gennaio","Febbraio","Marzo","Aprile","Maggio","Giugno","Luglio","Agosto","Settembre","Ottobre","Novembre","Dicembre"],dayOfWeekShort:["Dom","Lun","Mar","Mer","Gio","Ven","Sab"],dayOfWeek:["Domenica","Lunedì","Martedì","Mercoledì","Giovedì","Venerdì","Sabato"]},da:{months:["Januar","Februar","Marts","April","Maj","Juni","Juli","August","September","Oktober","November","December"],dayOfWeekShort:["Søn","Man","Tir","Ons","Tor","Fre","Lør"],dayOfWeek:["søndag","mandag","tirsdag","onsdag","torsdag","fredag","lørdag"]},no:{months:["Januar","Februar","Mars","April","Mai","Juni","Juli","August","September","Oktober","November","Desember"],dayOfWeekShort:["Søn","Man","Tir","Ons","Tor","Fre","Lør"],dayOfWeek:["Søndag","Mandag","Tirsdag","Onsdag","Torsdag","Fredag","Lørdag"]},ja:{months:["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月"],dayOfWeekShort:["日","月","火","水","木","金","土"],dayOfWeek:["日曜","月曜","火曜","水曜","木曜","金曜","土曜"]},vi:{months:["Tháng 1","Tháng 2","Tháng 3","Tháng 4","Tháng 5","Tháng 6","Tháng 7","Tháng 8","Tháng 9","Tháng 10","Tháng 11","Tháng 12"],dayOfWeekShort:["CN","T2","T3","T4","T5","T6","T7"],dayOfWeek:["Chủ nhật","Thứ hai","Thứ ba","Thứ tư","Thứ năm","Thứ sáu","Thứ bảy"]},sl:{months:["Januar","Februar","Marec","April","Maj","Junij","Julij","Avgust","September","Oktober","November","December"],dayOfWeekShort:["Ned","Pon","Tor","Sre","Čet","Pet","Sob"],dayOfWeek:["Nedelja","Ponedeljek","Torek","Sreda","Četrtek","Petek","Sobota"]},cs:{months:["Leden","Únor","Březen","Duben","Květen","Červen","Červenec","Srpen","Září","Říjen","Listopad","Prosinec"],dayOfWeekShort:["Ne","Po","Út","St","Čt","Pá","So"]},hu:{months:["Január","Február","Március","Április","Május","Június","Július","Augusztus","Szeptember","Október","November","December"],dayOfWeekShort:["Va","Hé","Ke","Sze","Cs","Pé","Szo"],dayOfWeek:["vasárnap","hétfő","kedd","szerda","csütörtök","péntek","szombat"]},az:{months:["Yanvar","Fevral","Mart","Aprel","May","Iyun","Iyul","Avqust","Sentyabr","Oktyabr","Noyabr","Dekabr"],dayOfWeekShort:["B","Be","Ça","Ç","Ca","C","Ş"],dayOfWeek:["Bazar","Bazar ertəsi","Çərşənbə axşamı","Çərşənbə","Cümə axşamı","Cümə","Şənbə"]},bs:{months:["Januar","Februar","Mart","April","Maj","Jun","Jul","Avgust","Septembar","Oktobar","Novembar","Decembar"],dayOfWeekShort:["Ned","Pon","Uto","Sri","Čet","Pet","Sub"],dayOfWeek:["Nedjelja","Ponedjeljak","Utorak","Srijeda","Četvrtak","Petak","Subota"]},ca:{months:["Gener","Febrer","Març","Abril","Maig","Juny","Juliol","Agost","Setembre","Octubre","Novembre","Desembre"],dayOfWeekShort:["Dg","Dl","Dt","Dc","Dj","Dv","Ds"],dayOfWeek:["Diumenge","Dilluns","Dimarts","Dimecres","Dijous","Divendres","Dissabte"]},"en-GB":{months:["January","February","March","April","May","June","July","August","September","October","November","December"],dayOfWeekShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayOfWeek:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"]},et:{months:["Jaanuar","Veebruar","Märts","Aprill","Mai","Juuni","Juuli","August","September","Oktoober","November","Detsember"],dayOfWeekShort:["P","E","T","K","N","R","L"],dayOfWeek:["Pühapäev","Esmaspäev","Teisipäev","Kolmapäev","Neljapäev","Reede","Laupäev"]},eu:{months:["Urtarrila","Otsaila","Martxoa","Apirila","Maiatza","Ekaina","Uztaila","Abuztua","Iraila","Urria","Azaroa","Abendua"],dayOfWeekShort:["Ig.","Al.","Ar.","Az.","Og.","Or.","La."],dayOfWeek:["Igandea","Astelehena","Asteartea","Asteazkena","Osteguna","Ostirala","Larunbata"]},fi:{months:["Tammikuu","Helmikuu","Maaliskuu","Huhtikuu","Toukokuu","Kesäkuu","Heinäkuu","Elokuu","Syyskuu","Lokakuu","Marraskuu","Joulukuu"],dayOfWeekShort:["Su","Ma","Ti","Ke","To","Pe","La"],dayOfWeek:["sunnuntai","maanantai","tiistai","keskiviikko","torstai","perjantai","lauantai"]},gl:{months:["Xan","Feb","Maz","Abr","Mai","Xun","Xul","Ago","Set","Out","Nov","Dec"],dayOfWeekShort:["Dom","Lun","Mar","Mer","Xov","Ven","Sab"],dayOfWeek:["Domingo","Luns","Martes","Mércores","Xoves","Venres","Sábado"]},hr:{months:["Siječanj","Veljača","Ožujak","Travanj","Svibanj","Lipanj","Srpanj","Kolovoz","Rujan","Listopad","Studeni","Prosinac"],dayOfWeekShort:["Ned","Pon","Uto","Sri","Čet","Pet","Sub"],dayOfWeek:["Nedjelja","Ponedjeljak","Utorak","Srijeda","Četvrtak","Petak","Subota"]},ko:{months:["1월","2월","3월","4월","5월","6월","7월","8월","9월","10월","11월","12월"],dayOfWeekShort:["일","월","화","수","목","금","토"],dayOfWeek:["일요일","월요일","화요일","수요일","목요일","금요일","토요일"]},lt:{months:["Sausio","Vasario","Kovo","Balandžio","Gegužės","Birželio","Liepos","Rugpjūčio","Rugsėjo","Spalio","Lapkričio","Gruodžio"],dayOfWeekShort:["Sek","Pir","Ant","Tre","Ket","Pen","Šeš"],dayOfWeek:["Sekmadienis","Pirmadienis","Antradienis","Trečiadienis","Ketvirtadienis","Penktadienis","Šeštadienis"]},lv:{months:["Janvāris","Februāris","Marts","Aprīlis ","Maijs","Jūnijs","Jūlijs","Augusts","Septembris","Oktobris","Novembris","Decembris"],dayOfWeekShort:["Sv","Pr","Ot","Tr","Ct","Pk","St"],dayOfWeek:["Svētdiena","Pirmdiena","Otrdiena","Trešdiena","Ceturtdiena","Piektdiena","Sestdiena"]},mk:{months:["јануари","февруари","март","април","мај","јуни","јули","август","септември","октомври","ноември","декември"],dayOfWeekShort:["нед","пон","вто","сре","чет","пет","саб"],dayOfWeek:["Недела","Понеделник","Вторник","Среда","Четврток","Петок","Сабота"]},mn:{months:["1-р сар","2-р сар","3-р сар","4-р сар","5-р сар","6-р сар","7-р сар","8-р сар","9-р сар","10-р сар","11-р сар","12-р сар"],dayOfWeekShort:["Дав","Мяг","Лха","Пүр","Бсн","Бям","Ням"],dayOfWeek:["Даваа","Мягмар","Лхагва","Пүрэв","Баасан","Бямба","Ням"]},"pt-BR":{months:["Janeiro","Fevereiro","Março","Abril","Maio","Junho","Julho","Agosto","Setembro","Outubro","Novembro","Dezembro"],dayOfWeekShort:["Dom","Seg","Ter","Qua","Qui","Sex","Sáb"],dayOfWeek:["Domingo","Segunda","Terça","Quarta","Quinta","Sexta","Sábado"]},sk:{months:["Január","Február","Marec","Apríl","Máj","Jún","Júl","August","September","Október","November","December"],dayOfWeekShort:["Ne","Po","Ut","St","Št","Pi","So"],dayOfWeek:["Nedeľa","Pondelok","Utorok","Streda","Štvrtok","Piatok","Sobota"]},sq:{months:["Janar","Shkurt","Mars","Prill","Maj","Qershor","Korrik","Gusht","Shtator","Tetor","Nëntor","Dhjetor"],dayOfWeekShort:["Die","Hën","Mar","Mër","Enj","Pre","Shtu"],dayOfWeek:["E Diel","E Hënë","E Martē","E Mërkurë","E Enjte","E Premte","E Shtunë"]},"sr-YU":{months:["Januar","Februar","Mart","April","Maj","Jun","Jul","Avgust","Septembar","Oktobar","Novembar","Decembar"],dayOfWeekShort:["Ned","Pon","Uto","Sre","čet","Pet","Sub"],dayOfWeek:["Nedelja","Ponedeljak","Utorak","Sreda","Četvrtak","Petak","Subota"]},sr:{months:["јануар","фебруар","март","април","мај","јун","јул","август","септембар","октобар","новембар","децембар"],dayOfWeekShort:["нед","пон","уто","сре","чет","пет","суб"],dayOfWeek:["Недеља","Понедељак","Уторак","Среда","Четвртак","Петак","Субота"]},sv:{months:["Januari","Februari","Mars","April","Maj","Juni","Juli","Augusti","September","Oktober","November","December"],dayOfWeekShort:["Sön","Mån","Tis","Ons","Tor","Fre","Lör"],dayOfWeek:["Söndag","Måndag","Tisdag","Onsdag","Torsdag","Fredag","Lördag"]},"zh-TW":{months:["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"],dayOfWeekShort:["日","一","二","三","四","五","六"],dayOfWeek:["星期日","星期一","星期二","星期三","星期四","星期五","星期六"]},zh:{months:["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"],dayOfWeekShort:["日","一","二","三","四","五","六"],dayOfWeek:["星期日","星期一","星期二","星期三","星期四","星期五","星期六"]},ug:{months:["1-ئاي","2-ئاي","3-ئاي","4-ئاي","5-ئاي","6-ئاي","7-ئاي","8-ئاي","9-ئاي","10-ئاي","11-ئاي","12-ئاي"],dayOfWeek:["يەكشەنبە","دۈشەنبە","سەيشەنبە","چارشەنبە","پەيشەنبە","جۈمە","شەنبە"]},he:{months:["ינואר","פברואר","מרץ","אפריל","מאי","יוני","יולי","אוגוסט","ספטמבר","אוקטובר","נובמבר","דצמבר"],dayOfWeekShort:["א'","ב'","ג'","ד'","ה'","ו'","שבת"],dayOfWeek:["ראשון","שני","שלישי","רביעי","חמישי","שישי","שבת","ראשון"]},hy:{months:["Հունվար","Փետրվար","Մարտ","Ապրիլ","Մայիս","Հունիս","Հուլիս","Օգոստոս","Սեպտեմբեր","Հոկտեմբեր","Նոյեմբեր","Դեկտեմբեր"],dayOfWeekShort:["Կի","Երկ","Երք","Չոր","Հնգ","Ուրբ","Շբթ"],dayOfWeek:["Կիրակի","Երկուշաբթի","Երեքշաբթի","Չորեքշաբթի","Հինգշաբթի","Ուրբաթ","Շաբաթ"]},kg:{months:["Үчтүн айы","Бирдин айы","Жалган Куран","Чын Куран","Бугу","Кулжа","Теке","Баш Оона","Аяк Оона","Тогуздун айы","Жетинин айы","Бештин айы"],dayOfWeekShort:["Жек","Дүй","Шей","Шар","Бей","Жум","Ише"],dayOfWeek:["Жекшемб","Дүйшөмб","Шейшемб","Шаршемб","Бейшемби","Жума","Ишенб"]},rm:{months:["Schaner","Favrer","Mars","Avrigl","Matg","Zercladur","Fanadur","Avust","Settember","October","November","December"],dayOfWeekShort:["Du","Gli","Ma","Me","Gie","Ve","So"],dayOfWeek:["Dumengia","Glindesdi","Mardi","Mesemna","Gievgia","Venderdi","Sonda"]},ka:{months:["იანვარი","თებერვალი","მარტი","აპრილი","მაისი","ივნისი","ივლისი","აგვისტო","სექტემბერი","ოქტომბერი","ნოემბერი","დეკემბერი"],dayOfWeekShort:["კვ","ორშ","სამშ","ოთხ","ხუთ","პარ","შაბ"],dayOfWeek:["კვირა","ორშაბათი","სამშაბათი","ოთხშაბათი","ხუთშაბათი","პარასკევი","შაბათი"]}},ownerDocument:document,contentWindow:window,value:"",rtl:!1,format:"Y/m/d H:i",formatTime:"H:i",formatDate:"Y/m/d",startDate:!1,step:60,monthChangeSpinner:!0,closeOnDateSelect:!1,closeOnTimeSelect:!0,closeOnWithoutClick:!0,closeOnInputClick:!0,openOnFocus:!0,timepicker:!0,datepicker:!0,weeks:!1,defaultTime:!1,defaultDate:!1,minDate:!1,maxDate:!1,minTime:!1,maxTime:!1,minDateTime:!1,maxDateTime:!1,allowTimes:[],opened:!1,initTime:!0,inline:!1,theme:"",touchMovedThreshold:5,onSelectDate:function(){},onSelectTime:function(){},onChangeMonth:function(){},onGetWeekOfYear:function(){},onChangeYear:function(){},onChangeDateTime:function(){},onShow:function(){},onClose:function(){},onGenerate:function(){},withoutCopyright:!0,inverseButton:!1,hours12:!1,next:"xdsoft_next",prev:"xdsoft_prev",dayOfWeekStart:0,parentID:"body",timeHeightInTimePicker:25,timepickerScrollbar:!0,todayButton:!0,prevButton:!0,nextButton:!0,defaultSelect:!0,scrollMonth:!0,scrollTime:!0,scrollInput:!0,lazyInit:!1,mask:!1,validateOnBlur:!0,allowBlank:!0,yearStart:1950,yearEnd:2050,monthStart:0,monthEnd:11,style:"",id:"",fixed:!1,roundTime:"round",className:"",weekends:[],highlightedDates:[],highlightedPeriods:[],allowDates:[],allowDateRe:null,disabledDates:[],disabledWeekDays:[],yearOffset:0,beforeShowDay:null,enterLikeTab:!0,showApplyButton:!1},r=null,n=null,o="en",i={meridiem:["AM","PM"]},s=function(){var t=a.i18n[o],s={days:t.dayOfWeek,daysShort:t.dayOfWeekShort,months:t.months,monthsShort:e.map(t.months,function(e){return e.substring(0,3)})};"function"==typeof DateFormatter&&(r=n=new DateFormatter({dateSettings:e.extend({},i,s)}))},u={moment:{default_options:{format:"YYYY/MM/DD HH:mm",formatDate:"YYYY/MM/DD",formatTime:"HH:mm"},formatter:{parseDate:function(e,t){if(l(t))return n.parseDate(e,t);var a=moment(e,t);return!!a.isValid()&&a.toDate()},formatDate:function(e,t){return l(t)?n.formatDate(e,t):moment(e).format(t)},formatMask:function(e){return e.replace(/Y{4}/g,"9999").replace(/Y{2}/g,"99").replace(/M{2}/g,"19").replace(/D{2}/g,"39").replace(/H{2}/g,"29").replace(/m{2}/g,"59").replace(/s{2}/g,"59")}}}};e.datetimepicker={setLocale:function(e){var t=a.i18n[e]?e:"en";o!==t&&(o=t,s())},setDateFormatter:function(t){if("string"==typeof t&&u.hasOwnProperty(t)){var n=u[t];e.extend(a,n.default_options),r=n.formatter}else r=t}};var d={RFC_2822:"D, d M Y H:i:s O",ATOM:"Y-m-dTH:i:sP",ISO_8601:"Y-m-dTH:i:sO",RFC_822:"D, d M y H:i:s O",RFC_850:"l, d-M-y H:i:s T",RFC_1036:"D, d M y H:i:s O",RFC_1123:"D, d M Y H:i:s O",RSS:"D, d M Y H:i:s O",W3C:"Y-m-dTH:i:sP"},l=function(e){return-1!==Object.values(d).indexOf(e)};e.extend(e.datetimepicker,d),s(),window.getComputedStyle||(window.getComputedStyle=function(e){return this.el=e,this.getPropertyValue=function(t){var a=/(-([a-z]))/g;return"float"===t&&(t="styleFloat"),a.test(t)&&(t=t.replace(a,function(e,t,a){return a.toUpperCase()})),e.currentStyle[t]||null},this}),Array.prototype.indexOf||(Array.prototype.indexOf=function(e,t){var a,r;for(a=t||0,r=this.length;a
'),s=e('
'),i.append(s),u.addClass("xdsoft_scroller_box").append(i),D=function(e){var t=d(e).y-c+p;t<0&&(t=0),t+s[0].offsetHeight>h&&(t=h-s[0].offsetHeight),u.trigger("scroll_element.xdsoft_scroller",[l?t/l:0])},s.on("touchstart.xdsoft_scroller mousedown.xdsoft_scroller",function(r){n||u.trigger("resize_scroll.xdsoft_scroller",[a]),c=d(r).y,p=parseInt(s.css("margin-top"),10),h=i[0].offsetHeight,"mousedown"===r.type||"touchstart"===r.type?(t.ownerDocument&&e(t.ownerDocument.body).addClass("xdsoft_noselect"),e([t.ownerDocument.body,t.contentWindow]).on("touchend mouseup.xdsoft_scroller",function a(){e([t.ownerDocument.body,t.contentWindow]).off("touchend mouseup.xdsoft_scroller",a).off("mousemove.xdsoft_scroller",D).removeClass("xdsoft_noselect")}),e(t.ownerDocument.body).on("mousemove.xdsoft_scroller",D)):(g=!0,r.stopPropagation(),r.preventDefault())}).on("touchmove",function(e){g&&(e.preventDefault(),D(e))}).on("touchend touchcancel",function(){g=!1,p=0}),u.on("scroll_element.xdsoft_scroller",function(e,t){n||u.trigger("resize_scroll.xdsoft_scroller",[t,!0]),t=t>1?1:t<0||isNaN(t)?0:t,s.css("margin-top",l*t),setTimeout(function(){r.css("marginTop",-parseInt((r[0].offsetHeight-n)*t,10))},10)}).on("resize_scroll.xdsoft_scroller",function(e,t,a){var d,f;n=u[0].clientHeight,o=r[0].offsetHeight,f=(d=n/o)*i[0].offsetHeight,d>1?s.hide():(s.show(),s.css("height",parseInt(f>10?f:10,10)),l=i[0].offsetHeight-s[0].offsetHeight,!0!==a&&u.trigger("scroll_element.xdsoft_scroller",[t||Math.abs(parseInt(r.css("marginTop"),10))/(o-n)]))}),u.on("mousewheel",function(e){var t=Math.abs(parseInt(r.css("marginTop"),10));return(t-=20*e.deltaY)<0&&(t=0),u.trigger("scroll_element.xdsoft_scroller",[t/(o-n)]),e.stopPropagation(),!1}),u.on("touchstart",function(e){f=d(e),m=Math.abs(parseInt(r.css("marginTop"),10))}),u.on("touchmove",function(e){if(f){e.preventDefault();var t=d(e);u.trigger("scroll_element.xdsoft_scroller",[(m-(t.y-f.y))/(o-n)])}}),u.on("touchend touchcancel",function(){f=!1,m=0})),u.trigger("resize_scroll.xdsoft_scroller",[a])):u.find(".xdsoft_scrollbar").hide()})},e.fn.datetimepicker=function(n,i){var s,u,d=this,l=48,f=57,c=96,m=105,h=17,g=46,p=13,D=27,v=8,y=37,b=38,k=39,x=40,T=9,S=116,M=65,w=67,O=86,W=90,_=89,F=!1,C=e.isPlainObject(n)||!n?e.extend(!0,{},a,n):e.extend(!0,{},a),P=0,Y=function(e){e.on("open.xdsoft focusin.xdsoft mousedown.xdsoft touchstart",function t(){e.is(":disabled")||e.data("xdsoft_datetimepicker")||(clearTimeout(P),P=setTimeout(function(){e.data("xdsoft_datetimepicker")||s(e),e.off("open.xdsoft focusin.xdsoft mousedown.xdsoft touchstart",t).trigger("open.xdsoft")},100))})};return s=function(a){function i(){var e,t=!1;return C.startDate?t=A.strToDate(C.startDate):(t=C.value||(a&&a.val&&a.val()?a.val():""))?(t=A.strToDateTime(t),C.yearOffset&&(t=new Date(t.getFullYear()-C.yearOffset,t.getMonth(),t.getDate(),t.getHours(),t.getMinutes(),t.getSeconds(),t.getMilliseconds()))):C.defaultDate&&(t=A.strToDateTime(C.defaultDate),C.defaultTime&&(e=A.strtotime(C.defaultTime),t.setHours(e.getHours()),t.setMinutes(e.getMinutes()))),t&&A.isValidDate(t)?j.data("changed",!0):t="",t||0}function s(t){var n=function(e,t){var a=e.replace(/([\[\]\/\{\}\(\)\-\.\+]{1})/g,"\\$1").replace(/_/g,"{digit+}").replace(/([0-9]{1})/g,"{digit$1}").replace(/\{digit([0-9]{1})\}/g,"[0-$1_]{1}").replace(/\{digit[\+]\}/g,"[0-9_]{1}");return new RegExp(a).test(t)},o=function(e,a){if(!(e="string"==typeof e||e instanceof String?t.ownerDocument.getElementById(e):e))return!1;if(e.createTextRange){var r=e.createTextRange();return r.collapse(!0),r.moveEnd("character",a),r.moveStart("character",a),r.select(),!0}return!!e.setSelectionRange&&(e.setSelectionRange(a,a),!0)};t.mask&&a.off("keydown.xdsoft"),!0===t.mask&&(r.formatMask?t.mask=r.formatMask(t.format):t.mask=t.format.replace(/Y/g,"9999").replace(/F/g,"9999").replace(/m/g,"19").replace(/d/g,"39").replace(/H/g,"29").replace(/i/g,"59").replace(/s/g,"59")),"string"===e.type(t.mask)&&(n(t.mask,a.val())||(a.val(t.mask.replace(/[0-9]/g,"_")),o(a[0],0)),a.on("paste.xdsoft",function(r){var i=(r.clipboardData||r.originalEvent.clipboardData||window.clipboardData).getData("text"),s=this.value,u=this.selectionStart;return s=s.substr(0,u)+i+s.substr(u+i.length),u+=i.length,n(t.mask,s)?(this.value=s,o(this,u)):""===e.trim(s)?this.value=t.mask.replace(/[0-9]/g,"_"):a.trigger("error_input.xdsoft"),r.preventDefault(),!1}),a.on("keydown.xdsoft",function(r){var i,s=this.value,u=r.which,d=this.selectionStart,C=this.selectionEnd,P=d!==C;if(u>=l&&u<=f||u>=c&&u<=m||u===v||u===g){for(i=u===v||u===g?"_":String.fromCharCode(c<=u&&u<=m?u-l:u),u===v&&d&&!P&&(d-=1);;){var Y=t.mask.substr(d,1),A=d0;if(!(/[^0-9_]/.test(Y)&&A&&H))break;d+=u!==v||P?1:-1}if(P){var j=C-d,J=t.mask.replace(/[0-9]/g,"_"),z=J.substr(d,j).substr(1);s=s.substr(0,d)+(i+z)+s.substr(d+j)}else s=s.substr(0,d)+i+s.substr(d+1);if(""===e.trim(s))s=J;else if(d===t.mask.length)return r.preventDefault(),!1;for(d+=u===v?0:1;/[^0-9_]/.test(t.mask.substr(d,1))&&d0;)d+=u===v?0:1;n(t.mask,s)?(this.value=s,o(this,d)):""===e.trim(s)?this.value=t.mask.replace(/[0-9]/g,"_"):a.trigger("error_input.xdsoft")}else if(-1!==[M,w,O,W,_].indexOf(u)&&F||-1!==[D,b,x,y,k,S,h,T,p].indexOf(u))return!0;return r.preventDefault(),!1}))}var u,d,P,Y,A,H,j=e('
'),J=e(''),z=e('
'),I=e('
'),N=e('
'),L=e('
'),E=L.find(".xdsoft_time_box").eq(0),R=e('
'),V=e(''),B=e('
'),G=e('
'),U=!1,q=0;C.id&&j.attr("id",C.id),C.style&&j.attr("style",C.style),C.weeks&&j.addClass("xdsoft_showweeks"),C.rtl&&j.addClass("xdsoft_rtl"),j.addClass("xdsoft_"+C.theme),j.addClass(C.className),I.find(".xdsoft_month span").after(B),I.find(".xdsoft_year span").after(G),I.find(".xdsoft_month,.xdsoft_year").on("touchstart mousedown.xdsoft",function(t){var a,r,n=e(this).find(".xdsoft_select").eq(0),o=0,i=0,s=n.is(":visible");for(I.find(".xdsoft_select").hide(),A.currentTime&&(o=A.currentTime[e(this).hasClass("xdsoft_month")?"getMonth":"getFullYear"]()),n[s?"hide":"show"](),a=n.find("div.xdsoft_option"),r=0;rC.touchMovedThreshold&&(this.touchMoved=!0)};I.find(".xdsoft_select").xdsoftScroller(C).on("touchstart mousedown.xdsoft",function(e){var t=e.originalEvent;this.touchMoved=!1,this.touchStartPosition=t.touches?t.touches[0]:t,e.stopPropagation(),e.preventDefault()}).on("touchmove",".xdsoft_option",X).on("touchend mousedown.xdsoft",".xdsoft_option",function(){if(!this.touchMoved){void 0!==A.currentTime&&null!==A.currentTime||(A.currentTime=A.now());var t=A.currentTime.getFullYear();A&&A.currentTime&&A.currentTime[e(this).parent().parent().hasClass("xdsoft_monthselect")?"setMonth":"setFullYear"](e(this).data("value")),e(this).parent().parent().hide(),j.trigger("xchange.xdsoft"),C.onChangeMonth&&e.isFunction(C.onChangeMonth)&&C.onChangeMonth.call(j,A.currentTime,j.data("input")),t!==A.currentTime.getFullYear()&&e.isFunction(C.onChangeYear)&&C.onChangeYear.call(j,A.currentTime,j.data("input"))}}),j.getValue=function(){return A.getCurrentTime()},j.setOptions=function(n){var o={};C=e.extend(!0,{},C,n),n.allowTimes&&e.isArray(n.allowTimes)&&n.allowTimes.length&&(C.allowTimes=e.extend(!0,[],n.allowTimes)),n.weekends&&e.isArray(n.weekends)&&n.weekends.length&&(C.weekends=e.extend(!0,[],n.weekends)),n.allowDates&&e.isArray(n.allowDates)&&n.allowDates.length&&(C.allowDates=e.extend(!0,[],n.allowDates)),n.allowDateRe&&"[object String]"===Object.prototype.toString.call(n.allowDateRe)&&(C.allowDateRe=new RegExp(n.allowDateRe)),n.highlightedDates&&e.isArray(n.highlightedDates)&&n.highlightedDates.length&&(e.each(n.highlightedDates,function(a,n){var i,s=e.map(n.split(","),e.trim),u=new t(r.parseDate(s[0],C.formatDate),s[1],s[2]),d=r.formatDate(u.date,C.formatDate);void 0!==o[d]?(i=o[d].desc)&&i.length&&u.desc&&u.desc.length&&(o[d].desc=i+"\n"+u.desc):o[d]=u}),C.highlightedDates=e.extend(!0,[],o)),n.highlightedPeriods&&e.isArray(n.highlightedPeriods)&&n.highlightedPeriods.length&&(o=e.extend(!0,[],C.highlightedDates),e.each(n.highlightedPeriods,function(a,n){var i,s,u,d,l,f,c;if(e.isArray(n))i=n[0],s=n[1],u=n[2],c=n[3];else{var m=e.map(n.split(","),e.trim);i=r.parseDate(m[0],C.formatDate),s=r.parseDate(m[1],C.formatDate),u=m[2],c=m[3]}for(;i<=s;)d=new t(i,u,c),l=r.formatDate(i,C.formatDate),i.setDate(i.getDate()+1),void 0!==o[l]?(f=o[l].desc)&&f.length&&d.desc&&d.desc.length&&(o[l].desc=f+"\n"+d.desc):o[l]=d}),C.highlightedDates=e.extend(!0,[],o)),n.disabledDates&&e.isArray(n.disabledDates)&&n.disabledDates.length&&(C.disabledDates=e.extend(!0,[],n.disabledDates)),n.disabledWeekDays&&e.isArray(n.disabledWeekDays)&&n.disabledWeekDays.length&&(C.disabledWeekDays=e.extend(!0,[],n.disabledWeekDays)),!C.open&&!C.opened||C.inline||a.trigger("open.xdsoft"),C.inline&&(U=!0,j.addClass("xdsoft_inline"),a.after(j).hide()),C.inverseButton&&(C.next="xdsoft_prev",C.prev="xdsoft_next"),C.datepicker?z.addClass("active"):z.removeClass("active"),C.timepicker?L.addClass("active"):L.removeClass("active"),C.value&&(A.setCurrentTime(C.value),a&&a.val&&a.val(A.str)),isNaN(C.dayOfWeekStart)?C.dayOfWeekStart=0:C.dayOfWeekStart=parseInt(C.dayOfWeekStart,10)%7,C.timepickerScrollbar||E.xdsoftScroller(C,"hide"),C.minDate&&/^[\+\-](.*)$/.test(C.minDate)&&(C.minDate=r.formatDate(A.strToDateTime(C.minDate),C.formatDate)),C.maxDate&&/^[\+\-](.*)$/.test(C.maxDate)&&(C.maxDate=r.formatDate(A.strToDateTime(C.maxDate),C.formatDate)),C.minDateTime&&/^\+(.*)$/.test(C.minDateTime)&&(C.minDateTime=A.strToDateTime(C.minDateTime).dateFormat(C.formatDate)),C.maxDateTime&&/^\+(.*)$/.test(C.maxDateTime)&&(C.maxDateTime=A.strToDateTime(C.maxDateTime).dateFormat(C.formatDate)),V.toggle(C.showApplyButton),I.find(".xdsoft_today_button").css("visibility",C.todayButton?"visible":"hidden"),I.find("."+C.prev).css("visibility",C.prevButton?"visible":"hidden"),I.find("."+C.next).css("visibility",C.nextButton?"visible":"hidden"),s(C),C.validateOnBlur&&a.off("blur.xdsoft").on("blur.xdsoft",function(){if(C.allowBlank&&(!e.trim(e(this).val()).length||"string"==typeof C.mask&&e.trim(e(this).val())===C.mask.replace(/[0-9]/g,"_")))e(this).val(null),j.data("xdsoft_datetime").empty();else{var t=r.parseDate(e(this).val(),C.format);if(t)e(this).val(r.formatDate(t,C.format));else{var a=+[e(this).val()[0],e(this).val()[1]].join(""),n=+[e(this).val()[2],e(this).val()[3]].join("");!C.datepicker&&C.timepicker&&a>=0&&a<24&&n>=0&&n<60?e(this).val([a,n].map(function(e){return e>9?e:"0"+e}).join(":")):e(this).val(r.formatDate(A.now(),C.format))}j.data("xdsoft_datetime").setCurrentTime(e(this).val())}j.trigger("changedatetime.xdsoft"),j.trigger("close.xdsoft")}),C.dayOfWeekStartPrev=0===C.dayOfWeekStart?6:C.dayOfWeekStart-1,j.trigger("xchange.xdsoft").trigger("afterOpen.xdsoft")},j.data("options",C).on("touchstart mousedown.xdsoft",function(e){return e.stopPropagation(),e.preventDefault(),G.hide(),B.hide(),!1}),E.append(R),E.xdsoftScroller(C),j.on("afterOpen.xdsoft",function(){E.xdsoftScroller(C)}),j.append(z).append(L),!0!==C.withoutCopyright&&j.append(J),z.append(I).append(N).append(V),e(C.parentID).append(j),A=new function(){var t=this;t.now=function(e){var a,r,n=new Date;return!e&&C.defaultDate&&(a=t.strToDateTime(C.defaultDate),n.setFullYear(a.getFullYear()),n.setMonth(a.getMonth()),n.setDate(a.getDate())),n.setFullYear(n.getFullYear()),!e&&C.defaultTime&&(r=t.strtotime(C.defaultTime),n.setHours(r.getHours()),n.setMinutes(r.getMinutes()),n.setSeconds(r.getSeconds()),n.setMilliseconds(r.getMilliseconds())),n},t.isValidDate=function(e){return"[object Date]"===Object.prototype.toString.call(e)&&!isNaN(e.getTime())},t.setCurrentTime=function(e,a){"string"==typeof e?t.currentTime=t.strToDateTime(e):t.isValidDate(e)?t.currentTime=e:e||a||!C.allowBlank||C.inline?t.currentTime=t.now():t.currentTime=null,j.trigger("xchange.xdsoft")},t.empty=function(){t.currentTime=null},t.getCurrentTime=function(){return t.currentTime},t.nextMonth=function(){void 0!==t.currentTime&&null!==t.currentTime||(t.currentTime=t.now());var a,r=t.currentTime.getMonth()+1;return 12===r&&(t.currentTime.setFullYear(t.currentTime.getFullYear()+1),r=0),a=t.currentTime.getFullYear(),t.currentTime.setDate(Math.min(new Date(t.currentTime.getFullYear(),r+1,0).getDate(),t.currentTime.getDate())),t.currentTime.setMonth(r),C.onChangeMonth&&e.isFunction(C.onChangeMonth)&&C.onChangeMonth.call(j,A.currentTime,j.data("input")),a!==t.currentTime.getFullYear()&&e.isFunction(C.onChangeYear)&&C.onChangeYear.call(j,A.currentTime,j.data("input")),j.trigger("xchange.xdsoft"),r},t.prevMonth=function(){void 0!==t.currentTime&&null!==t.currentTime||(t.currentTime=t.now());var a=t.currentTime.getMonth()-1;return-1===a&&(t.currentTime.setFullYear(t.currentTime.getFullYear()-1),a=11),t.currentTime.setDate(Math.min(new Date(t.currentTime.getFullYear(),a+1,0).getDate(),t.currentTime.getDate())),t.currentTime.setMonth(a),C.onChangeMonth&&e.isFunction(C.onChangeMonth)&&C.onChangeMonth.call(j,A.currentTime,j.data("input")),j.trigger("xchange.xdsoft"),a},t.getWeekOfYear=function(t){if(C.onGetWeekOfYear&&e.isFunction(C.onGetWeekOfYear)){var a=C.onGetWeekOfYear.call(j,t);if(void 0!==a)return a}var r=new Date(t.getFullYear(),0,1);return 4!==r.getDay()&&r.setMonth(0,1+(4-r.getDay()+7)%7),Math.ceil(((t-r)/864e5+r.getDay()+1)/7)},t.strToDateTime=function(e){var a,n,o=[];return e&&e instanceof Date&&t.isValidDate(e)?e:((o=/^([+-]{1})(.*)$/.exec(e))&&(o[2]=r.parseDate(o[2],C.formatDate)),o&&o[2]?(a=o[2].getTime()-6e4*o[2].getTimezoneOffset(),n=new Date(t.now(!0).getTime()+parseInt(o[1]+"1",10)*a)):n=e?r.parseDate(e,C.format):t.now(),t.isValidDate(n)||(n=t.now()),n)},t.strToDate=function(e){if(e&&e instanceof Date&&t.isValidDate(e))return e;var a=e?r.parseDate(e,C.formatDate):t.now(!0);return t.isValidDate(a)||(a=t.now(!0)),a},t.strtotime=function(e){if(e&&e instanceof Date&&t.isValidDate(e))return e;var a=e?r.parseDate(e,C.formatTime):t.now(!0);return t.isValidDate(a)||(a=t.now(!0)),a},t.str=function(){var e=C.format;return C.yearOffset&&(e=(e=e.replace("Y",t.currentTime.getFullYear()+C.yearOffset)).replace("y",String(t.currentTime.getFullYear()+C.yearOffset).substring(2,4))),r.formatDate(t.currentTime,e)},t.currentTime=this.now()},V.on("touchend click",function(e){e.preventDefault(),j.data("changed",!0),A.setCurrentTime(i()),a.val(A.str()),j.trigger("close.xdsoft")}),I.find(".xdsoft_today_button").on("touchend mousedown.xdsoft",function(){j.data("changed",!0),A.setCurrentTime(0,!0),j.trigger("afterOpen.xdsoft")}).on("dblclick.xdsoft",function(){var e,t,r=A.getCurrentTime();r=new Date(r.getFullYear(),r.getMonth(),r.getDate()),e=A.strToDate(C.minDate),r<(e=new Date(e.getFullYear(),e.getMonth(),e.getDate()))||(t=A.strToDate(C.maxDate),r>(t=new Date(t.getFullYear(),t.getMonth(),t.getDate()))||(a.val(A.str()),a.trigger("change"),j.trigger("close.xdsoft")))}),I.find(".xdsoft_prev,.xdsoft_next").on("touchend mousedown.xdsoft",function(){var t=e(this),a=0,r=!1;!function e(n){t.hasClass(C.next)?A.nextMonth():t.hasClass(C.prev)&&A.prevMonth(),C.monthChangeSpinner&&(r||(a=setTimeout(e,n||100)))}(500),e([C.ownerDocument.body,C.contentWindow]).on("touchend mouseup.xdsoft",function t(){clearTimeout(a),r=!0,e([C.ownerDocument.body,C.contentWindow]).off("touchend mouseup.xdsoft",t)})}),L.find(".xdsoft_prev,.xdsoft_next").on("touchend mousedown.xdsoft",function(){var t=e(this),a=0,r=!1,n=110;!function e(o){var i=E[0].clientHeight,s=R[0].offsetHeight,u=Math.abs(parseInt(R.css("marginTop"),10));t.hasClass(C.next)&&s-i-C.timeHeightInTimePicker>=u?R.css("marginTop","-"+(u+C.timeHeightInTimePicker)+"px"):t.hasClass(C.prev)&&u-C.timeHeightInTimePicker>=0&&R.css("marginTop","-"+(u-C.timeHeightInTimePicker)+"px"),E.trigger("scroll_element.xdsoft_scroller",[Math.abs(parseInt(R[0].style.marginTop,10)/(s-i))]),n=n>10?10:n-10,r||(a=setTimeout(e,o||n))}(500),e([C.ownerDocument.body,C.contentWindow]).on("touchend mouseup.xdsoft",function t(){clearTimeout(a),r=!0,e([C.ownerDocument.body,C.contentWindow]).off("touchend mouseup.xdsoft",t)})}),u=0,j.on("xchange.xdsoft",function(t){clearTimeout(u),u=setTimeout(function(){void 0!==A.currentTime&&null!==A.currentTime||(A.currentTime=A.now());for(var t,i,s,u,d,l,f,c,m,h,g="",p=new Date(A.currentTime.getFullYear(),A.currentTime.getMonth(),1,12,0,0),D=0,v=A.now(),y=!1,b=!1,k=!1,x=!1,T=[],S=!0,M="";p.getDay()!==C.dayOfWeekStart;)p.setDate(p.getDate()-1);for(g+="",C.weeks&&(g+=""),t=0;t<7;t+=1)g+="";g+="",g+="",!1!==C.maxDate&&(y=A.strToDate(C.maxDate),y=new Date(y.getFullYear(),y.getMonth(),y.getDate(),23,59,59,999)),!1!==C.minDate&&(b=A.strToDate(C.minDate),b=new Date(b.getFullYear(),b.getMonth(),b.getDate())),!1!==C.minDateTime&&(k=A.strToDate(C.minDateTime),k=new Date(k.getFullYear(),k.getMonth(),k.getDate(),k.getHours(),k.getMinutes(),k.getSeconds())),!1!==C.maxDateTime&&(x=A.strToDate(C.maxDateTime),x=new Date(x.getFullYear(),x.getMonth(),x.getDate(),x.getHours(),x.getMinutes(),x.getSeconds()));var w;for(!1!==x&&(w=31*(12*x.getFullYear()+x.getMonth())+x.getDate());D0&&-1===C.allowDates.indexOf(r.formatDate(p,C.formatDate))&&T.push("xdsoft_disabled");var O=31*(12*p.getFullYear()+p.getMonth())+p.getDate();(!1!==y&&p>y||!1!==k&&pw||c&&!1===c[0])&&T.push("xdsoft_disabled"),-1!==C.disabledDates.indexOf(r.formatDate(p,C.formatDate))&&T.push("xdsoft_disabled"),-1!==C.disabledWeekDays.indexOf(s)&&T.push("xdsoft_disabled"),a.is("[disabled]")&&T.push("xdsoft_disabled"),c&&""!==c[1]&&T.push(c[1]),A.currentTime.getMonth()!==l&&T.push("xdsoft_other_month"),(C.defaultSelect||j.data("changed"))&&r.formatDate(A.currentTime,C.formatDate)===r.formatDate(p,C.formatDate)&&T.push("xdsoft_current"),r.formatDate(v,C.formatDate)===r.formatDate(p,C.formatDate)&&T.push("xdsoft_today"),0!==p.getDay()&&6!==p.getDay()&&-1===C.weekends.indexOf(r.formatDate(p,C.formatDate))||T.push("xdsoft_weekend"),void 0!==C.highlightedDates[r.formatDate(p,C.formatDate)]&&(i=C.highlightedDates[r.formatDate(p,C.formatDate)],T.push(void 0===i.style?"xdsoft_highlighted_default":i.style),h=void 0===i.desc?"":i.desc),C.beforeShowDay&&e.isFunction(C.beforeShowDay)&&T.push(C.beforeShowDay(p)),S&&(g+="",S=!1,C.weeks&&(g+="")),g+='",p.getDay()===C.dayOfWeekStartPrev&&(g+="",S=!0),p.setDate(u+1)}g+="
"+C.i18n[o].dayOfWeekShort[(t+C.dayOfWeekStart)%7]+"
"+f+"
'+u+"
",N.html(g),I.find(".xdsoft_label span").eq(0).text(C.i18n[o].months[A.currentTime.getMonth()]),I.find(".xdsoft_label span").eq(1).text(A.currentTime.getFullYear()+C.yearOffset),M="",l="";var W=0;if(!1!==C.minTime){F=A.strtotime(C.minTime);W=60*F.getHours()+F.getMinutes()}var _=1440;if(!1!==C.maxTime){F=A.strtotime(C.maxTime);_=60*F.getHours()+F.getMinutes()}if(!1!==C.minDateTime){F=A.strToDateTime(C.minDateTime);r.formatDate(A.currentTime,C.formatDate)===r.formatDate(F,C.formatDate)&&(l=60*F.getHours()+F.getMinutes())>W&&(W=l)}if(!1!==C.maxDateTime){var F=A.strToDateTime(C.maxDateTime);r.formatDate(A.currentTime,C.formatDate)===r.formatDate(F,C.formatDate)&&(l=60*F.getHours()+F.getMinutes())<_&&(_=l)}if(m=function(t,n){var o,i=A.now(),s=C.allowTimes&&e.isArray(C.allowTimes)&&C.allowTimes.length;i.setHours(t),t=parseInt(i.getHours(),10),i.setMinutes(n),n=parseInt(i.getMinutes(),10),T=[];var u=60*t+n;(a.is("[disabled]")||u>=_||u59||o.getMinutes()===parseInt(n,10))&&(C.defaultSelect||j.data("changed")?T.push("xdsoft_current"):C.initTime&&T.push("xdsoft_init_time")),parseInt(v.getHours(),10)===parseInt(t,10)&&parseInt(v.getMinutes(),10)===parseInt(n,10)&&T.push("xdsoft_today"),M+='
'+r.formatDate(i,C.formatTime)+"
"},C.allowTimes&&e.isArray(C.allowTimes)&&C.allowTimes.length)for(D=0;D=_||m((D<10?"0":"")+D,l=(t<10?"0":"")+t))}for(R.html(M),n="",D=parseInt(C.yearStart,10);D<=parseInt(C.yearEnd,10);D+=1)n+='
'+(D+C.yearOffset)+"
";for(G.children().eq(0).html(n),D=parseInt(C.monthStart,10),n="";D<=parseInt(C.monthEnd,10);D+=1)n+='
'+C.i18n[o].months[D]+"
";B.children().eq(0).html(n),e(j).trigger("generate.xdsoft")},10),t.stopPropagation()}).on("afterOpen.xdsoft",function(){if(C.timepicker){var e,t,a,r;R.find(".xdsoft_current").length?e=".xdsoft_current":R.find(".xdsoft_init_time").length&&(e=".xdsoft_init_time"),e?(t=E[0].clientHeight,(a=R[0].offsetHeight)-t<(r=R.find(e).index()*C.timeHeightInTimePicker+1)&&(r=a-t),E.trigger("scroll_element.xdsoft_scroller",[parseInt(r,10)/(a-t)])):E.trigger("scroll_element.xdsoft_scroller",[0])}}),d=0,N.on("touchend click.xdsoft","td",function(t){t.stopPropagation(),d+=1;var r=e(this),n=A.currentTime;if(void 0!==n&&null!==n||(A.currentTime=A.now(),n=A.currentTime),r.hasClass("xdsoft_disabled"))return!1;n.setDate(1),n.setFullYear(r.data("year")),n.setMonth(r.data("month")),n.setDate(r.data("date")),j.trigger("select.xdsoft",[n]),a.val(A.str()),C.onSelectDate&&e.isFunction(C.onSelectDate)&&C.onSelectDate.call(j,A.currentTime,j.data("input"),t),j.data("changed",!0),j.trigger("xchange.xdsoft"),j.trigger("changedatetime.xdsoft"),(d>1||!0===C.closeOnDateSelect||!1===C.closeOnDateSelect&&!C.timepicker)&&!C.inline&&j.trigger("close.xdsoft"),setTimeout(function(){d=0},200)}),R.on("touchstart","div",function(e){this.touchMoved=!1}).on("touchmove","div",X).on("touchend click.xdsoft","div",function(t){if(!this.touchMoved){t.stopPropagation();var a=e(this),r=A.currentTime;if(void 0!==r&&null!==r||(A.currentTime=A.now(),r=A.currentTime),a.hasClass("xdsoft_disabled"))return!1;r.setHours(a.data("hour")),r.setMinutes(a.data("minute")),j.trigger("select.xdsoft",[r]),j.data("input").val(A.str()),C.onSelectTime&&e.isFunction(C.onSelectTime)&&C.onSelectTime.call(j,A.currentTime,j.data("input"),t),j.data("changed",!0),j.trigger("xchange.xdsoft"),j.trigger("changedatetime.xdsoft"),!0!==C.inline&&!0===C.closeOnTimeSelect&&j.trigger("close.xdsoft")}}),z.on("mousewheel.xdsoft",function(e){return!C.scrollMonth||(e.deltaY<0?A.nextMonth():A.prevMonth(),!1)}),a.on("mousewheel.xdsoft",function(e){return!C.scrollInput||(!C.datepicker&&C.timepicker?((P=R.find(".xdsoft_current").length?R.find(".xdsoft_current").eq(0).index():0)+e.deltaY>=0&&P+e.deltaYc+m?(l="bottom",r=c+m-t.top):r-=m):r+j[0].offsetHeight>c+m&&(r=t.top-j[0].offsetHeight+1),r<0&&(r=0),n+a.offsetWidth>d&&(n=d-a.offsetWidth)),i=j[0],H(i,function(e){if("relative"===C.contentWindow.getComputedStyle(e).getPropertyValue("position")&&d>=e.offsetWidth)return n-=(d-e.offsetWidth)/2,!1}),(f={position:o,left:n,top:"",bottom:""})[l]=r,j.css(f)},j.on("open.xdsoft",function(t){var a=!0;C.onShow&&e.isFunction(C.onShow)&&(a=C.onShow.call(j,A.currentTime,j.data("input"),t)),!1!==a&&(j.show(),Y(),e(C.contentWindow).off("resize.xdsoft",Y).on("resize.xdsoft",Y),C.closeOnWithoutClick&&e([C.ownerDocument.body,C.contentWindow]).on("touchstart mousedown.xdsoft",function t(){j.trigger("close.xdsoft"),e([C.ownerDocument.body,C.contentWindow]).off("touchstart mousedown.xdsoft",t)}))}).on("close.xdsoft",function(t){var a=!0;I.find(".xdsoft_month,.xdsoft_year").find(".xdsoft_select").hide(),C.onClose&&e.isFunction(C.onClose)&&(a=C.onClose.call(j,A.currentTime,j.data("input"),t)),!1===a||C.opened||C.inline||j.hide(),t.stopPropagation()}).on("toggle.xdsoft",function(){j.is(":visible")?j.trigger("close.xdsoft"):j.trigger("open.xdsoft")}).data("input",a),q=0,j.data("xdsoft_datetime",A),j.setOptions(C),A.setCurrentTime(i()),a.data("xdsoft_datetimepicker",j).on("open.xdsoft focusin.xdsoft mousedown.xdsoft touchstart",function(){a.is(":disabled")||a.data("xdsoft_datetimepicker").is(":visible")&&C.closeOnInputClick||C.openOnFocus&&(clearTimeout(q),q=setTimeout(function(){a.is(":disabled")||(U=!0,A.setCurrentTime(i(),!0),C.mask&&s(C),j.trigger("open.xdsoft"))},100))}).on("keydown.xdsoft",function(t){var a,r=t.which;return-1!==[p].indexOf(r)&&C.enterLikeTab?(a=e("input:visible,textarea:visible,button:visible,a:visible"),j.trigger("close.xdsoft"),a.eq(a.index(this)+1).focus(),!1):-1!==[T].indexOf(r)?(j.trigger("close.xdsoft"),!0):void 0}).on("blur.xdsoft",function(){j.trigger("close.xdsoft")})},u=function(t){var a=t.data("xdsoft_datetimepicker");a&&(a.data("xdsoft_datetime",null),a.remove(),t.data("xdsoft_datetimepicker",null).off(".xdsoft"),e(C.contentWindow).off("resize.xdsoft"),e([C.contentWindow,C.ownerDocument.body]).off("mousedown.xdsoft touchstart"),t.unmousewheel&&t.unmousewheel())},e(C.ownerDocument).off("keydown.xdsoftctrl keyup.xdsoftctrl").on("keydown.xdsoftctrl",function(e){e.keyCode===h&&(F=!0)}).on("keyup.xdsoftctrl",function(e){e.keyCode===h&&(F=!1)}),this.each(function(){var t=e(this).data("xdsoft_datetimepicker");if(t){if("string"===e.type(n))switch(n){case"show":e(this).select().focus(),t.trigger("open.xdsoft");break;case"hide":t.trigger("close.xdsoft");break;case"toggle":t.trigger("toggle.xdsoft");break;case"destroy":u(e(this));break;case"reset":this.value=this.defaultValue,this.value&&t.data("xdsoft_datetime").isValidDate(r.parseDate(this.value,C.format))||t.data("changed",!1),t.data("xdsoft_datetime").setCurrentTime(this.value);break;case"validate":t.data("input").trigger("blur.xdsoft");break;default:t[n]&&e.isFunction(t[n])&&(d=t[n](i))}else t.setOptions(n);return 0}"string"!==e.type(n)&&(!C.lazyInit||C.open||C.inline?s(e(this)):Y(e(this)))}),d},e.fn.datetimepicker.defaults=a};!function(e){"function"==typeof define&&define.amd?define(["jquery","jquery-mousewheel"],e):"object"==typeof exports?module.exports=e(require("jquery")):e(jQuery)}(datetimepickerFactory),function(e){"function"==typeof define&&define.amd?define(["jquery"],e):"object"==typeof exports?module.exports=e:e(jQuery)}(function(e){function t(t){var i=t||window.event,s=u.call(arguments,1),d=0,f=0,c=0,m=0,h=0,g=0;if(t=e.event.fix(i),t.type="mousewheel","detail"in i&&(c=-1*i.detail),"wheelDelta"in i&&(c=i.wheelDelta),"wheelDeltaY"in i&&(c=i.wheelDeltaY),"wheelDeltaX"in i&&(f=-1*i.wheelDeltaX),"axis"in i&&i.axis===i.HORIZONTAL_AXIS&&(f=-1*c,c=0),d=0===c?f:c,"deltaY"in i&&(d=c=-1*i.deltaY),"deltaX"in i&&(f=i.deltaX,0===c&&(d=-1*f)),0!==c||0!==f){if(1===i.deltaMode){var p=e.data(this,"mousewheel-line-height");d*=p,c*=p,f*=p}else if(2===i.deltaMode){var D=e.data(this,"mousewheel-page-height");d*=D,c*=D,f*=D}if(m=Math.max(Math.abs(c),Math.abs(f)),(!o||m=1?"floor":"ceil"](d/o),f=Math[f>=1?"floor":"ceil"](f/o),c=Math[c>=1?"floor":"ceil"](c/o),l.settings.normalizeOffset&&this.getBoundingClientRect){var v=this.getBoundingClientRect();h=t.clientX-v.left,g=t.clientY-v.top}return t.deltaX=f,t.deltaY=c,t.deltaFactor=o,t.offsetX=h,t.offsetY=g,t.deltaMode=0,s.unshift(t,d,f,c),n&&clearTimeout(n),n=setTimeout(a,200),(e.event.dispatch||e.event.handle).apply(this,s)}}function a(){o=null}function r(e,t){return l.settings.adjustOldDeltas&&"mousewheel"===e.type&&t%120==0}var n,o,i=["wheel","mousewheel","DOMMouseScroll","MozMousePixelScroll"],s="onwheel"in document||document.documentMode>=9?["wheel"]:["mousewheel","DomMouseScroll","MozMousePixelScroll"],u=Array.prototype.slice;if(e.event.fixHooks)for(var d=i.length;d;)e.event.fixHooks[i[--d]]=e.event.mouseHooks;var l=e.event.special.mousewheel={version:"3.1.12",setup:function(){if(this.addEventListener)for(var a=s.length;a;)this.addEventListener(s[--a],t,!1);else this.onmousewheel=t;e.data(this,"mousewheel-line-height",l.getLineHeight(this)),e.data(this,"mousewheel-page-height",l.getPageHeight(this))},teardown:function(){if(this.removeEventListener)for(var a=s.length;a;)this.removeEventListener(s[--a],t,!1);else this.onmousewheel=null;e.removeData(this,"mousewheel-line-height"),e.removeData(this,"mousewheel-page-height")},getLineHeight:function(t){var a=e(t),r=a["offsetParent"in e.fn?"offsetParent":"parent"]();return r.length||(r=e("body")),parseInt(r.css("fontSize"),10)||parseInt(a.css("fontSize"),10)||16},getPageHeight:function(t){return e(t).height()},settings:{adjustOldDeltas:!0,normalizeOffset:!0}};e.fn.extend({mousewheel:function(e){return e?this.bind("mousewheel",e):this.trigger("mousewheel")},unmousewheel:function(e){return this.unbind("mousewheel",e)}})}); \ No newline at end of file diff --git a/resources/datetime-picker/datetimepicker.min.css b/resources/datetime-picker/datetimepicker.min.css deleted file mode 100644 index 14a08a1..0000000 --- a/resources/datetime-picker/datetimepicker.min.css +++ /dev/null @@ -1 +0,0 @@ -.xdsoft_datetimepicker{box-shadow:0 5px 15px -5px rgba(0,0,0,0.506);background:#fff;border-bottom:1px solid #bbb;border-left:1px solid #ccc;border-right:1px solid #ccc;border-top:1px solid #ccc;color:#333;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;padding:8px;padding-left:0;padding-top:2px;position:absolute;z-index:9999;-moz-box-sizing:border-box;box-sizing:border-box;display:none}.xdsoft_datetimepicker.xdsoft_rtl{padding:8px 0 8px 8px}.xdsoft_datetimepicker iframe{position:absolute;left:0;top:0;width:75px;height:210px;background:transparent;border:0}.xdsoft_datetimepicker button{border:none !important}.xdsoft_noselect{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}.xdsoft_noselect::selection{background:transparent}.xdsoft_noselect::-moz-selection{background:transparent}.xdsoft_datetimepicker.xdsoft_inline{display:inline-block;position:static;box-shadow:none}.xdsoft_datetimepicker *{-moz-box-sizing:border-box;box-sizing:border-box;padding:0;margin:0}.xdsoft_datetimepicker .xdsoft_datepicker,.xdsoft_datetimepicker .xdsoft_timepicker{display:none}.xdsoft_datetimepicker .xdsoft_datepicker.active,.xdsoft_datetimepicker .xdsoft_timepicker.active{display:block}.xdsoft_datetimepicker .xdsoft_datepicker{width:224px;float:left;margin-left:8px}.xdsoft_datetimepicker.xdsoft_rtl .xdsoft_datepicker{float:right;margin-right:8px;margin-left:0}.xdsoft_datetimepicker.xdsoft_showweeks .xdsoft_datepicker{width:256px}.xdsoft_datetimepicker .xdsoft_timepicker{width:58px;float:left;text-align:center;margin-left:8px;margin-top:0}.xdsoft_datetimepicker.xdsoft_rtl .xdsoft_timepicker{float:right;margin-right:8px;margin-left:0}.xdsoft_datetimepicker .xdsoft_datepicker.active+.xdsoft_timepicker{margin-top:8px;margin-bottom:3px}.xdsoft_datetimepicker .xdsoft_monthpicker{position:relative;text-align:center}.xdsoft_datetimepicker .xdsoft_label i,.xdsoft_datetimepicker .xdsoft_prev,.xdsoft_datetimepicker .xdsoft_next,.xdsoft_datetimepicker .xdsoft_today_button{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAAAeCAYAAADaW7vzAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6Q0NBRjI1NjM0M0UwMTFFNDk4NkFGMzJFQkQzQjEwRUIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6Q0NBRjI1NjQ0M0UwMTFFNDk4NkFGMzJFQkQzQjEwRUIiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpDQ0FGMjU2MTQzRTAxMUU0OTg2QUYzMkVCRDNCMTBFQiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpDQ0FGMjU2MjQzRTAxMUU0OTg2QUYzMkVCRDNCMTBFQiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PoNEP54AAAIOSURBVHja7Jq9TsMwEMcxrZD4WpBYeKUCe+kTMCACHZh4BFfHO/AAIHZGFhYkBBsSEqxsLCAgXKhbXYOTxh9pfJVP+qutnZ5s/5Lz2Y5I03QhWji2GIcgAokWgfCxNvcOCCGKqiSqhUp0laHOne05vdEyGMfkdxJDVjgwDlEQgYQBgx+ULJaWSXXS6r/ER5FBVR8VfGftTKcITNs+a1XpcFoExREIDF14AVIFxgQUS+h520cdud6wNkC0UBw6BCO/HoCYwBhD8QCkQ/x1mwDyD4plh4D6DDV0TAGyo4HcawLIBBSLDkHeH0Mg2yVP3l4TQMZQDDsEOl/MgHQqhMNuE0D+oBh0CIr8MAKyazBH9WyBuKxDWgbXfjNf32TZ1KWm/Ap1oSk/R53UtQ5xTh3LUlMmT8gt6g51Q9p+SobxgJQ/qmsfZhWywGFSl0yBjCLJCMgXail3b7+rumdVJ2YRss4cN+r6qAHDkPWjPjdJCF4n9RmAD/V9A/Wp4NQassDjwlB6XBiCxcJQWmZZb8THFilfy/lfrTvLghq2TqTHrRMTKNJ0sIhdo15RT+RpyWwFdY96UZ/LdQKBGjcXpcc1AlSFEfLmouD+1knuxBDUVrvOBmoOC/rEcN7OQxKVeJTCiAdUzUJhA2Oez9QTkp72OTVcxDcXY8iKNkxGAJXmJCOQwOa6dhyXsOa6XwEGAKdeb5ET3rQdAAAAAElFTkSuQmCC)}.xdsoft_datetimepicker .xdsoft_label i{opacity:.5;background-position:-92px -19px;display:inline-block;width:9px;height:20px;vertical-align:middle}.xdsoft_datetimepicker .xdsoft_prev{float:left;background-position:-20px 0}.xdsoft_datetimepicker .xdsoft_today_button{float:left;background-position:-70px 0;margin-left:5px}.xdsoft_datetimepicker .xdsoft_next{float:right;background-position:0 0}.xdsoft_datetimepicker .xdsoft_next,.xdsoft_datetimepicker .xdsoft_prev,.xdsoft_datetimepicker .xdsoft_today_button{background-color:transparent;background-repeat:no-repeat;border:0 none;cursor:pointer;display:block;height:30px;opacity:.5;-ms-filter:"alpha(opacity=50)";outline:medium none;overflow:hidden;padding:0;position:relative;text-indent:100%;white-space:nowrap;width:20px;min-width:0}.xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_prev,.xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_next{float:none;background-position:-40px -15px;height:15px;width:30px;display:block;margin-left:14px;margin-top:7px}.xdsoft_datetimepicker.xdsoft_rtl .xdsoft_timepicker .xdsoft_prev,.xdsoft_datetimepicker.xdsoft_rtl .xdsoft_timepicker .xdsoft_next{float:none;margin-left:0;margin-right:14px}.xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_prev{background-position:-40px 0;margin-bottom:7px;margin-top:0}.xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box{height:151px;overflow:hidden;border-bottom:1px solid #ddd}.xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box>div>div{background:#f5f5f5;border-top:1px solid #ddd;color:#666;font-size:12px;text-align:center;border-collapse:collapse;cursor:pointer;border-bottom-width:0;height:25px;line-height:25px}.xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box>div>div:first-child{border-top-width:0}.xdsoft_datetimepicker .xdsoft_today_button:hover,.xdsoft_datetimepicker .xdsoft_next:hover,.xdsoft_datetimepicker .xdsoft_prev:hover{opacity:1;-ms-filter:"alpha(opacity=100)"}.xdsoft_datetimepicker .xdsoft_label{display:inline;position:relative;z-index:9999;margin:0;padding:5px 3px;font-size:14px;line-height:20px;font-weight:bold;background-color:#fff;float:left;width:182px;text-align:center;cursor:pointer}.xdsoft_datetimepicker .xdsoft_label:hover>span{text-decoration:underline}.xdsoft_datetimepicker .xdsoft_label:hover i{opacity:1.0}.xdsoft_datetimepicker .xdsoft_label>.xdsoft_select{border:1px solid #ccc;position:absolute;right:0;top:30px;z-index:101;display:none;background:#fff;max-height:160px;overflow-y:hidden}.xdsoft_datetimepicker .xdsoft_label>.xdsoft_select.xdsoft_monthselect{right:-7px}.xdsoft_datetimepicker .xdsoft_label>.xdsoft_select.xdsoft_yearselect{right:2px}.xdsoft_datetimepicker .xdsoft_label>.xdsoft_select>div>.xdsoft_option:hover{color:#fff;background:#ff8000}.xdsoft_datetimepicker .xdsoft_label>.xdsoft_select>div>.xdsoft_option{padding:2px 10px 2px 5px;text-decoration:none !important}.xdsoft_datetimepicker .xdsoft_label>.xdsoft_select>div>.xdsoft_option.xdsoft_current{background:#3af;box-shadow:#178fe5 0 1px 3px 0 inset;color:#fff;font-weight:700}.xdsoft_datetimepicker .xdsoft_month{width:100px;text-align:right}.xdsoft_datetimepicker .xdsoft_calendar{clear:both}.xdsoft_datetimepicker .xdsoft_year{width:48px;margin-left:5px}.xdsoft_datetimepicker .xdsoft_calendar table{border-collapse:collapse;width:100%}.xdsoft_datetimepicker .xdsoft_calendar td>div{padding-right:5px}.xdsoft_datetimepicker .xdsoft_calendar th{height:25px}.xdsoft_datetimepicker .xdsoft_calendar td,.xdsoft_datetimepicker .xdsoft_calendar th{width:14.2857142%;background:#f5f5f5;border:1px solid #ddd;color:#666;font-size:12px;text-align:right;vertical-align:middle;padding:0;border-collapse:collapse;cursor:pointer;height:25px}.xdsoft_datetimepicker.xdsoft_showweeks .xdsoft_calendar td,.xdsoft_datetimepicker.xdsoft_showweeks .xdsoft_calendar th{width:12.5%}.xdsoft_datetimepicker .xdsoft_calendar th{background:#f1f1f1}.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_today{color:#3af}.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_highlighted_default{background:#ffe9d2;box-shadow:#ffb871 0 1px 4px 0 inset;color:#000}.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_highlighted_mint{background:#c1ffc9;box-shadow:#00dd1c 0 1px 4px 0 inset;color:#000}.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_default,.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_current,.xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box>div>div.xdsoft_current{background:#3af;box-shadow:#178fe5 0 1px 3px 0 inset;color:#fff;font-weight:700}.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_other_month,.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_disabled,.xdsoft_datetimepicker .xdsoft_time_box>div>div.xdsoft_disabled{opacity:.5;-ms-filter:"alpha(opacity=50)";cursor:default}.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_other_month.xdsoft_disabled{opacity:.2;-ms-filter:"alpha(opacity=20)"}.xdsoft_datetimepicker .xdsoft_calendar td:hover,.xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box>div>div:hover{color:#fff !important;background:#ff8000 !important;box-shadow:none !important}.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_current.xdsoft_disabled:hover,.xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box>div>div.xdsoft_current.xdsoft_disabled:hover{background:#3af !important;box-shadow:#178fe5 0 1px 3px 0 inset !important;color:#fff !important}.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_disabled:hover,.xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box>div>div.xdsoft_disabled:hover{color:inherit !important;background:inherit !important;box-shadow:inherit !important}.xdsoft_datetimepicker .xdsoft_calendar th{font-weight:700;text-align:center;color:#999;cursor:default}.xdsoft_datetimepicker .xdsoft_copyright{color:#ccc !important;font-size:10px;clear:both;float:none;margin-left:8px}.xdsoft_datetimepicker .xdsoft_copyright a{color:#eee !important}.xdsoft_datetimepicker .xdsoft_copyright a:hover{color:#aaa !important}.xdsoft_time_box{position:relative;border:1px solid #ccc}.xdsoft_scrollbar>.xdsoft_scroller{background:#ccc !important;height:20px;border-radius:3px}.xdsoft_scrollbar{position:absolute;width:7px;right:0;top:0;bottom:0;cursor:pointer}.xdsoft_datetimepicker.xdsoft_rtl .xdsoft_scrollbar{left:0;right:auto}.xdsoft_scroller_box{position:relative}.xdsoft_datetimepicker.xdsoft_dark{box-shadow:0 5px 15px -5px rgba(255,255,255,0.506);background:#000;border-bottom:1px solid #444;border-left:1px solid #333;border-right:1px solid #333;border-top:1px solid #333;color:#ccc}.xdsoft_datetimepicker.xdsoft_dark .xdsoft_timepicker .xdsoft_time_box{border-bottom:1px solid #222}.xdsoft_datetimepicker.xdsoft_dark .xdsoft_timepicker .xdsoft_time_box>div>div{background:#0a0a0a;border-top:1px solid #222;color:#999}.xdsoft_datetimepicker.xdsoft_dark .xdsoft_label{background-color:#000}.xdsoft_datetimepicker.xdsoft_dark .xdsoft_label>.xdsoft_select{border:1px solid #333;background:#000}.xdsoft_datetimepicker.xdsoft_dark .xdsoft_label>.xdsoft_select>div>.xdsoft_option:hover{color:#000;background:#007fff}.xdsoft_datetimepicker.xdsoft_dark .xdsoft_label>.xdsoft_select>div>.xdsoft_option.xdsoft_current{background:#c50;box-shadow:#b03e00 0 1px 3px 0 inset;color:#000}.xdsoft_datetimepicker.xdsoft_dark .xdsoft_label i,.xdsoft_datetimepicker.xdsoft_dark .xdsoft_prev,.xdsoft_datetimepicker.xdsoft_dark .xdsoft_next,.xdsoft_datetimepicker.xdsoft_dark .xdsoft_today_button{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAAAeCAYAAADaW7vzAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6QUExQUUzOTA0M0UyMTFFNDlBM0FFQTJENTExRDVBODYiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6QUExQUUzOTE0M0UyMTFFNDlBM0FFQTJENTExRDVBODYiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpBQTFBRTM4RTQzRTIxMUU0OUEzQUVBMkQ1MTFENUE4NiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpBQTFBRTM4RjQzRTIxMUU0OUEzQUVBMkQ1MTFENUE4NiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pp0VxGEAAAIASURBVHja7JrNSgMxEMebtgh+3MSLr1T1Xn2CHoSKB08+QmR8Bx9A8e7RixdB9CKCoNdexIugxFlJa7rNZneTbLIpM/CnNLsdMvNjM8l0mRCiQ9Ye61IKCAgZAUnH+mU3MMZaHYChBnJUDzWOFZdVfc5+ZFLbrWDeXPwbxIqrLLfaeS0hEBVGIRQCEiZoHQwtlGSByCCdYBl8g8egTTAWoKQMRBRBcZxYlhzhKegqMOageErsCHVkk3hXIFooDgHB1KkHIHVgzKB4ADJQ/A1jAFmAYhkQqA5TOBtocrKrgXwQA8gcFIuAIO8sQSA7hidvPwaQGZSaAYHOUWJABhWWw2EMIH9QagQERU4SArJXo0ZZL18uvaxejXt/Em8xjVBXmvFr1KVm/AJ10tRe2XnraNqaJvKE3KHuUbfK1E+VHB0q40/y3sdQSxY4FHWeKJCunP8UyDdqJZenT3ntVV5jIYCAh20vT7ioP8tpf6E2lfEMwERe+whV1MHjwZB7PBiCxcGQWwKZKD62lfGNnP/1poFAA60T7rF1UgcKd2id3KDeUS+oLWV8DfWAepOfq00CgQabi9zjcgJVYVD7PVzQUAUGAQkbNJTBICDhgwYTjDYD6XeW08ZKh+A4pYkzenOxXUbvZcWz7E8ykRMnIHGX1XPl+1m2vPYpL+2qdb8CDAARlKFEz/ZVkAAAAABJRU5ErkJggg==)}.xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar td,.xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar th{background:#0a0a0a;border:1px solid #222;color:#999}.xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar th{background:#0e0e0e}.xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar td.xdsoft_today{color:#c50}.xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar td.xdsoft_highlighted_default{background:#ffe9d2;box-shadow:#ffb871 0 1px 4px 0 inset;color:#000}.xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar td.xdsoft_highlighted_mint{background:#c1ffc9;box-shadow:#00dd1c 0 1px 4px 0 inset;color:#000}.xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar td.xdsoft_default,.xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar td.xdsoft_current,.xdsoft_datetimepicker.xdsoft_dark .xdsoft_timepicker .xdsoft_time_box>div>div.xdsoft_current{background:#c50;box-shadow:#b03e00 0 1px 3px 0 inset;color:#000}.xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar td:hover,.xdsoft_datetimepicker.xdsoft_dark .xdsoft_timepicker .xdsoft_time_box>div>div:hover{color:#000 !important;background:#007fff !important}.xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar th{color:#666}.xdsoft_datetimepicker.xdsoft_dark .xdsoft_copyright{color:#333 !important}.xdsoft_datetimepicker.xdsoft_dark .xdsoft_copyright a{color:#111 !important}.xdsoft_datetimepicker.xdsoft_dark .xdsoft_copyright a:hover{color:#555 !important}.xdsoft_dark .xdsoft_time_box{border:1px solid #333}.xdsoft_dark .xdsoft_scrollbar>.xdsoft_scroller{background:#333 !important}.xdsoft_datetimepicker .xdsoft_save_selected{display:block;border:1px solid #ddd !important;margin-top:5px;width:100%;color:#454551;font-size:13px}.xdsoft_datetimepicker .blue-gradient-button{font-family:"museo-sans","Book Antiqua",sans-serif;font-size:12px;font-weight:300;color:#82878c;height:28px;position:relative;padding:4px 17px 4px 33px;border:1px solid #d7d8da;background:-moz-linear-gradient(top,#fff 0,#f4f8fa 73%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#fff),color-stop(73%,#f4f8fa));background:-webkit-linear-gradient(top,#fff 0,#f4f8fa 73%);background:-o-linear-gradient(top,#fff 0,#f4f8fa 73%);background:-ms-linear-gradient(top,#fff 0,#f4f8fa 73%);background:linear-gradient(to bottom,#fff 0,#f4f8fa 73%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff',endColorstr='#f4f8fa',GradientType=0)}.xdsoft_datetimepicker .blue-gradient-button:hover,.xdsoft_datetimepicker .blue-gradient-button:focus,.xdsoft_datetimepicker .blue-gradient-button:hover span,.xdsoft_datetimepicker .blue-gradient-button:focus span{color:#454551;background:-moz-linear-gradient(top,#f4f8fa 0,#FFF 73%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#f4f8fa),color-stop(73%,#FFF));background:-webkit-linear-gradient(top,#f4f8fa 0,#FFF 73%);background:-o-linear-gradient(top,#f4f8fa 0,#FFF 73%);background:-ms-linear-gradient(top,#f4f8fa 0,#FFF 73%);background:linear-gradient(to bottom,#f4f8fa 0,#FFF 73%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f4f8fa',endColorstr='#FFF',GradientType=0)} \ No newline at end of file diff --git a/resources/dmmd-preview.css b/resources/dmmd-preview.css index c768a0e..a3236b7 100644 --- a/resources/dmmd-preview.css +++ b/resources/dmmd-preview.css @@ -1,44 +1,41 @@ div.dmmd-preview { - padding: 0; + padding: 0; } div.dmmd-preview-update { - background: #ccc; - color: #333; - text-align: center; - cursor: pointer; - border-radius: 4px; - height: 2em; - line-height: 2em; + background: #ccc; + color: #333; + text-align: center; + cursor: pointer; + border-radius: 4px; + height: 2em; + line-height: 2em; } div.dmmd-preview-content { - padding: 0 8px; + padding: 0 7px; } div.dmmd-preview.dmmd-preview-has-content div.dmmd-preview-update { - border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; } div.dmmd-preview-has-content div.dmmd-preview-content { - padding-bottom: 8px; - padding-top: 8px; + padding-bottom: 7px; } div.dmmd-no-button div.dmmd-preview-update { - display: none; + display: none; } div.dmmd-no-button div.dmmd-preview-content { - padding-bottom: 0; + padding-bottom: 0; } div.dmmd-no-button:not(.dmmd-preview-has-content) { - display: none; + display: none; } div.dmmd-preview-stale { - background: repeating-linear-gradient(-45deg, #fff, #fff 10px, #f8f8f8 10px, #f8f8f8 20px); + background: repeating-linear-gradient(-45deg, #fff, #fff 10px, #f8f8f8 10px, #f8f8f8 20px); } - -/*# sourceMappingURL=dmmd-preview.css.map */ diff --git a/resources/dmmd-preview.js b/resources/dmmd-preview.js index 2646503..fa6dc87 100644 --- a/resources/dmmd-preview.js +++ b/resources/dmmd-preview.js @@ -24,7 +24,37 @@ $(function () { }, function (result) { $content.html(result); $preview.addClass('dmmd-preview-has-content').removeClass('dmmd-preview-stale'); - renderKatex($content[0]); + + var $jax = $content.find('.require-mathjax-support'); + if ($jax.length) { + if (!('MathJax' in window)) { + $.ajax({ + type: 'GET', + url: $jax.attr('data-config'), + dataType: 'script', + cache: true, + success: function () { + $.ajax({ + type: 'GET', + url: 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS_HTML', + dataType: 'script', + cache: true, + success: function () { + MathJax.Hub.Queue(function () { + $content.find('.tex-image').hide(); + $content.find('.tex-text').show(); + }); + } + }); + } + }); + } else { + MathJax.Hub.Queue(['Typeset', MathJax.Hub, $content[0]], function () { + $content.find('.tex-image').hide(); + $content.find('.tex-text').show(); + }); + } + } }); } else { $content.empty(); diff --git a/resources/dmmd-preview.scss b/resources/dmmd-preview.scss deleted file mode 100644 index 98cdbaa..0000000 --- a/resources/dmmd-preview.scss +++ /dev/null @@ -1,41 +0,0 @@ -div.dmmd-preview { - padding: 0; -} - -div.dmmd-preview-update { - background: #ccc; - color: #333; - text-align: center; - cursor: pointer; - border-radius: 4px; - height: 2em; - line-height: 2em; -} - -div.dmmd-preview-content { - padding: 0 7px; -} - -div.dmmd-preview.dmmd-preview-has-content div.dmmd-preview-update { - border-radius: 4px 4px 0 0; -} - -div.dmmd-preview-has-content div.dmmd-preview-content { - padding-bottom: 7px; -} - -div.dmmd-no-button div.dmmd-preview-update { - display: none; -} - -div.dmmd-no-button div.dmmd-preview-content { - padding-bottom: 0; -} - -div.dmmd-no-button:not(.dmmd-preview-has-content) { - display: none; -} - -div.dmmd-preview-stale { - background: repeating-linear-gradient(-45deg, #fff, #fff 10px, #f8f8f8 10px, #f8f8f8 20px); -} diff --git a/resources/event.js b/resources/event.js index 73f9302..170940b 100644 --- a/resources/event.js +++ b/resources/event.js @@ -7,7 +7,6 @@ function EventReceiver(websocket, poller, channels, last_msg, onmessage) { if (onmessage) this.onmessage = onmessage; var receiver = this; - var time_retry = 1000; function init_poll() { function long_poll() { @@ -36,39 +35,32 @@ function EventReceiver(websocket, poller, channels, last_msg, onmessage) { this.onwsclose = null; if (window.WebSocket) { - function connect() { - this.websocket = new WebSocket(websocket); - var timeout = setTimeout(function () { - receiver.websocket.close(); - receiver.websocket = null; - init_poll(); - }, 2000); - this.websocket.onopen = function (event) { - clearTimeout(timeout); - this.send(JSON.stringify({ - command: 'start-msg', - start: last_msg - })); - this.send(JSON.stringify({ - command: 'set-filter', - filter: channels - })); - }; - this.websocket.onmessage = function (event) { - var data = JSON.parse(event.data); - receiver.onmessage(data.message); - receiver.last_msg = data.id; - }; - this.websocket.onclose = function (event) { - if (event.code != 1000 && receiver.onwsclose !== null) - receiver.onwsclose(event); - if (event.code == 1006) { - setTimeout(connect, time_retry); - time_retry += 2000; - } - } + this.websocket = new WebSocket(websocket); + var timeout = setTimeout(function () { + receiver.websocket.close(); + receiver.websocket = null; + init_poll(); + }, 2000); + this.websocket.onopen = function (event) { + clearTimeout(timeout); + this.send(JSON.stringify({ + command: 'start-msg', + start: last_msg + })); + this.send(JSON.stringify({ + command: 'set-filter', + filter: channels + })); + }; + this.websocket.onmessage = function (event) { + var data = JSON.parse(event.data); + receiver.onmessage(data.message); + receiver.last_msg = data.id; + }; + this.websocket.onclose = function (event) { + if (event.code != 1000 && receiver.onwsclose !== null) + receiver.onwsclose(event); } - connect(); } else { this.websocket = null; init_poll(); diff --git a/resources/fine-uploader/LICENSE b/resources/fine-uploader/LICENSE deleted file mode 100644 index 070caa6..0000000 --- a/resources/fine-uploader/LICENSE +++ /dev/null @@ -1,23 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2010-2012, Andrew Valums -Copyright (c) 2012-2013, Andrew Valums and Raymond S. Nicholus, III -Copyright (c) 2013-present, Widen Enterprises, Inc. - -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/resources/fine-uploader/continue.gif b/resources/fine-uploader/continue.gif deleted file mode 100644 index 303b7fb..0000000 Binary files a/resources/fine-uploader/continue.gif and /dev/null differ diff --git a/resources/fine-uploader/dnd.js b/resources/fine-uploader/dnd.js deleted file mode 100644 index 4beb736..0000000 --- a/resources/fine-uploader/dnd.js +++ /dev/null @@ -1,1100 +0,0 @@ -// Fine Uploader 5.16.2 - MIT licensed. http://fineuploader.com -(function(global) { - var qq = function(element) { - "use strict"; - return { - hide: function() { - element.style.display = "none"; - return this; - }, - attach: function(type, fn) { - if (element.addEventListener) { - element.addEventListener(type, fn, false); - } else if (element.attachEvent) { - element.attachEvent("on" + type, fn); - } - return function() { - qq(element).detach(type, fn); - }; - }, - detach: function(type, fn) { - if (element.removeEventListener) { - element.removeEventListener(type, fn, false); - } else if (element.attachEvent) { - element.detachEvent("on" + type, fn); - } - return this; - }, - contains: function(descendant) { - if (!descendant) { - return false; - } - if (element === descendant) { - return true; - } - if (element.contains) { - return element.contains(descendant); - } else { - return !!(descendant.compareDocumentPosition(element) & 8); - } - }, - insertBefore: function(elementB) { - elementB.parentNode.insertBefore(element, elementB); - return this; - }, - remove: function() { - element.parentNode.removeChild(element); - return this; - }, - css: function(styles) { - if (element.style == null) { - throw new qq.Error("Can't apply style to node as it is not on the HTMLElement prototype chain!"); - } - if (styles.opacity != null) { - if (typeof element.style.opacity !== "string" && typeof element.filters !== "undefined") { - styles.filter = "alpha(opacity=" + Math.round(100 * styles.opacity) + ")"; - } - } - qq.extend(element.style, styles); - return this; - }, - hasClass: function(name, considerParent) { - var re = new RegExp("(^| )" + name + "( |$)"); - return re.test(element.className) || !!(considerParent && re.test(element.parentNode.className)); - }, - addClass: function(name) { - if (!qq(element).hasClass(name)) { - element.className += " " + name; - } - return this; - }, - removeClass: function(name) { - var re = new RegExp("(^| )" + name + "( |$)"); - element.className = element.className.replace(re, " ").replace(/^\s+|\s+$/g, ""); - return this; - }, - getByClass: function(className, first) { - var candidates, result = []; - if (first && element.querySelector) { - return element.querySelector("." + className); - } else if (element.querySelectorAll) { - return element.querySelectorAll("." + className); - } - candidates = element.getElementsByTagName("*"); - qq.each(candidates, function(idx, val) { - if (qq(val).hasClass(className)) { - result.push(val); - } - }); - return first ? result[0] : result; - }, - getFirstByClass: function(className) { - return qq(element).getByClass(className, true); - }, - children: function() { - var children = [], child = element.firstChild; - while (child) { - if (child.nodeType === 1) { - children.push(child); - } - child = child.nextSibling; - } - return children; - }, - setText: function(text) { - element.innerText = text; - element.textContent = text; - return this; - }, - clearText: function() { - return qq(element).setText(""); - }, - hasAttribute: function(attrName) { - var attrVal; - if (element.hasAttribute) { - if (!element.hasAttribute(attrName)) { - return false; - } - return /^false$/i.exec(element.getAttribute(attrName)) == null; - } else { - attrVal = element[attrName]; - if (attrVal === undefined) { - return false; - } - return /^false$/i.exec(attrVal) == null; - } - } - }; - }; - (function() { - "use strict"; - qq.canvasToBlob = function(canvas, mime, quality) { - return qq.dataUriToBlob(canvas.toDataURL(mime, quality)); - }; - qq.dataUriToBlob = function(dataUri) { - var arrayBuffer, byteString, createBlob = function(data, mime) { - var BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder, blobBuilder = BlobBuilder && new BlobBuilder(); - if (blobBuilder) { - blobBuilder.append(data); - return blobBuilder.getBlob(mime); - } else { - return new Blob([ data ], { - type: mime - }); - } - }, intArray, mimeString; - if (dataUri.split(",")[0].indexOf("base64") >= 0) { - byteString = atob(dataUri.split(",")[1]); - } else { - byteString = decodeURI(dataUri.split(",")[1]); - } - mimeString = dataUri.split(",")[0].split(":")[1].split(";")[0]; - arrayBuffer = new ArrayBuffer(byteString.length); - intArray = new Uint8Array(arrayBuffer); - qq.each(byteString, function(idx, character) { - intArray[idx] = character.charCodeAt(0); - }); - return createBlob(arrayBuffer, mimeString); - }; - qq.log = function(message, level) { - if (window.console) { - if (!level || level === "info") { - window.console.log(message); - } else { - if (window.console[level]) { - window.console[level](message); - } else { - window.console.log("<" + level + "> " + message); - } - } - } - }; - qq.isObject = function(variable) { - return variable && !variable.nodeType && Object.prototype.toString.call(variable) === "[object Object]"; - }; - qq.isFunction = function(variable) { - return typeof variable === "function"; - }; - qq.isArray = function(value) { - return Object.prototype.toString.call(value) === "[object Array]" || value && window.ArrayBuffer && value.buffer && value.buffer.constructor === ArrayBuffer; - }; - qq.isItemList = function(maybeItemList) { - return Object.prototype.toString.call(maybeItemList) === "[object DataTransferItemList]"; - }; - qq.isNodeList = function(maybeNodeList) { - return Object.prototype.toString.call(maybeNodeList) === "[object NodeList]" || maybeNodeList.item && maybeNodeList.namedItem; - }; - qq.isString = function(maybeString) { - return Object.prototype.toString.call(maybeString) === "[object String]"; - }; - qq.trimStr = function(string) { - if (String.prototype.trim) { - return string.trim(); - } - return string.replace(/^\s+|\s+$/g, ""); - }; - qq.format = function(str) { - var args = Array.prototype.slice.call(arguments, 1), newStr = str, nextIdxToReplace = newStr.indexOf("{}"); - qq.each(args, function(idx, val) { - var strBefore = newStr.substring(0, nextIdxToReplace), strAfter = newStr.substring(nextIdxToReplace + 2); - newStr = strBefore + val + strAfter; - nextIdxToReplace = newStr.indexOf("{}", nextIdxToReplace + val.length); - if (nextIdxToReplace < 0) { - return false; - } - }); - return newStr; - }; - qq.isFile = function(maybeFile) { - return window.File && Object.prototype.toString.call(maybeFile) === "[object File]"; - }; - qq.isFileList = function(maybeFileList) { - return window.FileList && Object.prototype.toString.call(maybeFileList) === "[object FileList]"; - }; - qq.isFileOrInput = function(maybeFileOrInput) { - return qq.isFile(maybeFileOrInput) || qq.isInput(maybeFileOrInput); - }; - qq.isInput = function(maybeInput, notFile) { - var evaluateType = function(type) { - var normalizedType = type.toLowerCase(); - if (notFile) { - return normalizedType !== "file"; - } - return normalizedType === "file"; - }; - if (window.HTMLInputElement) { - if (Object.prototype.toString.call(maybeInput) === "[object HTMLInputElement]") { - if (maybeInput.type && evaluateType(maybeInput.type)) { - return true; - } - } - } - if (maybeInput.tagName) { - if (maybeInput.tagName.toLowerCase() === "input") { - if (maybeInput.type && evaluateType(maybeInput.type)) { - return true; - } - } - } - return false; - }; - qq.isBlob = function(maybeBlob) { - if (window.Blob && Object.prototype.toString.call(maybeBlob) === "[object Blob]") { - return true; - } - }; - qq.isXhrUploadSupported = function() { - var input = document.createElement("input"); - input.type = "file"; - return input.multiple !== undefined && typeof File !== "undefined" && typeof FormData !== "undefined" && typeof qq.createXhrInstance().upload !== "undefined"; - }; - qq.createXhrInstance = function() { - if (window.XMLHttpRequest) { - return new XMLHttpRequest(); - } - try { - return new ActiveXObject("MSXML2.XMLHTTP.3.0"); - } catch (error) { - qq.log("Neither XHR or ActiveX are supported!", "error"); - return null; - } - }; - qq.isFolderDropSupported = function(dataTransfer) { - return dataTransfer.items && dataTransfer.items.length > 0 && dataTransfer.items[0].webkitGetAsEntry; - }; - qq.isFileChunkingSupported = function() { - return !qq.androidStock() && qq.isXhrUploadSupported() && (File.prototype.slice !== undefined || File.prototype.webkitSlice !== undefined || File.prototype.mozSlice !== undefined); - }; - qq.sliceBlob = function(fileOrBlob, start, end) { - var slicer = fileOrBlob.slice || fileOrBlob.mozSlice || fileOrBlob.webkitSlice; - return slicer.call(fileOrBlob, start, end); - }; - qq.arrayBufferToHex = function(buffer) { - var bytesAsHex = "", bytes = new Uint8Array(buffer); - qq.each(bytes, function(idx, byt) { - var byteAsHexStr = byt.toString(16); - if (byteAsHexStr.length < 2) { - byteAsHexStr = "0" + byteAsHexStr; - } - bytesAsHex += byteAsHexStr; - }); - return bytesAsHex; - }; - qq.readBlobToHex = function(blob, startOffset, length) { - var initialBlob = qq.sliceBlob(blob, startOffset, startOffset + length), fileReader = new FileReader(), promise = new qq.Promise(); - fileReader.onload = function() { - promise.success(qq.arrayBufferToHex(fileReader.result)); - }; - fileReader.onerror = promise.failure; - fileReader.readAsArrayBuffer(initialBlob); - return promise; - }; - qq.extend = function(first, second, extendNested) { - qq.each(second, function(prop, val) { - if (extendNested && qq.isObject(val)) { - if (first[prop] === undefined) { - first[prop] = {}; - } - qq.extend(first[prop], val, true); - } else { - first[prop] = val; - } - }); - return first; - }; - qq.override = function(target, sourceFn) { - var super_ = {}, source = sourceFn(super_); - qq.each(source, function(srcPropName, srcPropVal) { - if (target[srcPropName] !== undefined) { - super_[srcPropName] = target[srcPropName]; - } - target[srcPropName] = srcPropVal; - }); - return target; - }; - qq.indexOf = function(arr, elt, from) { - if (arr.indexOf) { - return arr.indexOf(elt, from); - } - from = from || 0; - var len = arr.length; - if (from < 0) { - from += len; - } - for (;from < len; from += 1) { - if (arr.hasOwnProperty(from) && arr[from] === elt) { - return from; - } - } - return -1; - }; - qq.getUniqueId = function() { - return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) { - var r = Math.random() * 16 | 0, v = c == "x" ? r : r & 3 | 8; - return v.toString(16); - }); - }; - qq.ie = function() { - return navigator.userAgent.indexOf("MSIE") !== -1 || navigator.userAgent.indexOf("Trident") !== -1; - }; - qq.ie7 = function() { - return navigator.userAgent.indexOf("MSIE 7") !== -1; - }; - qq.ie8 = function() { - return navigator.userAgent.indexOf("MSIE 8") !== -1; - }; - qq.ie10 = function() { - return navigator.userAgent.indexOf("MSIE 10") !== -1; - }; - qq.ie11 = function() { - return qq.ie() && navigator.userAgent.indexOf("rv:11") !== -1; - }; - qq.edge = function() { - return navigator.userAgent.indexOf("Edge") >= 0; - }; - qq.safari = function() { - return navigator.vendor !== undefined && navigator.vendor.indexOf("Apple") !== -1; - }; - qq.chrome = function() { - return navigator.vendor !== undefined && navigator.vendor.indexOf("Google") !== -1; - }; - qq.opera = function() { - return navigator.vendor !== undefined && navigator.vendor.indexOf("Opera") !== -1; - }; - qq.firefox = function() { - return !qq.edge() && !qq.ie11() && navigator.userAgent.indexOf("Mozilla") !== -1 && navigator.vendor !== undefined && navigator.vendor === ""; - }; - qq.windows = function() { - return navigator.platform === "Win32"; - }; - qq.android = function() { - return navigator.userAgent.toLowerCase().indexOf("android") !== -1; - }; - qq.androidStock = function() { - return qq.android() && navigator.userAgent.toLowerCase().indexOf("chrome") < 0; - }; - qq.ios6 = function() { - return qq.ios() && navigator.userAgent.indexOf(" OS 6_") !== -1; - }; - qq.ios7 = function() { - return qq.ios() && navigator.userAgent.indexOf(" OS 7_") !== -1; - }; - qq.ios8 = function() { - return qq.ios() && navigator.userAgent.indexOf(" OS 8_") !== -1; - }; - qq.ios800 = function() { - return qq.ios() && navigator.userAgent.indexOf(" OS 8_0 ") !== -1; - }; - qq.ios = function() { - return navigator.userAgent.indexOf("iPad") !== -1 || navigator.userAgent.indexOf("iPod") !== -1 || navigator.userAgent.indexOf("iPhone") !== -1; - }; - qq.iosChrome = function() { - return qq.ios() && navigator.userAgent.indexOf("CriOS") !== -1; - }; - qq.iosSafari = function() { - return qq.ios() && !qq.iosChrome() && navigator.userAgent.indexOf("Safari") !== -1; - }; - qq.iosSafariWebView = function() { - return qq.ios() && !qq.iosChrome() && !qq.iosSafari(); - }; - qq.preventDefault = function(e) { - if (e.preventDefault) { - e.preventDefault(); - } else { - e.returnValue = false; - } - }; - qq.toElement = function() { - var div = document.createElement("div"); - return function(html) { - div.innerHTML = html; - var element = div.firstChild; - div.removeChild(element); - return element; - }; - }(); - qq.each = function(iterableItem, callback) { - var keyOrIndex, retVal; - if (iterableItem) { - if (window.Storage && iterableItem.constructor === window.Storage) { - for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) { - retVal = callback(iterableItem.key(keyOrIndex), iterableItem.getItem(iterableItem.key(keyOrIndex))); - if (retVal === false) { - break; - } - } - } else if (qq.isArray(iterableItem) || qq.isItemList(iterableItem) || qq.isNodeList(iterableItem)) { - for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) { - retVal = callback(keyOrIndex, iterableItem[keyOrIndex]); - if (retVal === false) { - break; - } - } - } else if (qq.isString(iterableItem)) { - for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) { - retVal = callback(keyOrIndex, iterableItem.charAt(keyOrIndex)); - if (retVal === false) { - break; - } - } - } else { - for (keyOrIndex in iterableItem) { - if (Object.prototype.hasOwnProperty.call(iterableItem, keyOrIndex)) { - retVal = callback(keyOrIndex, iterableItem[keyOrIndex]); - if (retVal === false) { - break; - } - } - } - } - } - }; - qq.bind = function(oldFunc, context) { - if (qq.isFunction(oldFunc)) { - var args = Array.prototype.slice.call(arguments, 2); - return function() { - var newArgs = qq.extend([], args); - if (arguments.length) { - newArgs = newArgs.concat(Array.prototype.slice.call(arguments)); - } - return oldFunc.apply(context, newArgs); - }; - } - throw new Error("first parameter must be a function!"); - }; - qq.obj2url = function(obj, temp, prefixDone) { - var uristrings = [], prefix = "&", add = function(nextObj, i) { - var nextTemp = temp ? /\[\]$/.test(temp) ? temp : temp + "[" + i + "]" : i; - if (nextTemp !== "undefined" && i !== "undefined") { - uristrings.push(typeof nextObj === "object" ? qq.obj2url(nextObj, nextTemp, true) : Object.prototype.toString.call(nextObj) === "[object Function]" ? encodeURIComponent(nextTemp) + "=" + encodeURIComponent(nextObj()) : encodeURIComponent(nextTemp) + "=" + encodeURIComponent(nextObj)); - } - }; - if (!prefixDone && temp) { - prefix = /\?/.test(temp) ? /\?$/.test(temp) ? "" : "&" : "?"; - uristrings.push(temp); - uristrings.push(qq.obj2url(obj)); - } else if (Object.prototype.toString.call(obj) === "[object Array]" && typeof obj !== "undefined") { - qq.each(obj, function(idx, val) { - add(val, idx); - }); - } else if (typeof obj !== "undefined" && obj !== null && typeof obj === "object") { - qq.each(obj, function(prop, val) { - add(val, prop); - }); - } else { - uristrings.push(encodeURIComponent(temp) + "=" + encodeURIComponent(obj)); - } - if (temp) { - return uristrings.join(prefix); - } else { - return uristrings.join(prefix).replace(/^&/, "").replace(/%20/g, "+"); - } - }; - qq.obj2FormData = function(obj, formData, arrayKeyName) { - if (!formData) { - formData = new FormData(); - } - qq.each(obj, function(key, val) { - key = arrayKeyName ? arrayKeyName + "[" + key + "]" : key; - if (qq.isObject(val)) { - qq.obj2FormData(val, formData, key); - } else if (qq.isFunction(val)) { - formData.append(key, val()); - } else { - formData.append(key, val); - } - }); - return formData; - }; - qq.obj2Inputs = function(obj, form) { - var input; - if (!form) { - form = document.createElement("form"); - } - qq.obj2FormData(obj, { - append: function(key, val) { - input = document.createElement("input"); - input.setAttribute("name", key); - input.setAttribute("value", val); - form.appendChild(input); - } - }); - return form; - }; - qq.parseJson = function(json) { - if (window.JSON && qq.isFunction(JSON.parse)) { - return JSON.parse(json); - } else { - return eval("(" + json + ")"); - } - }; - qq.getExtension = function(filename) { - var extIdx = filename.lastIndexOf(".") + 1; - if (extIdx > 0) { - return filename.substr(extIdx, filename.length - extIdx); - } - }; - qq.getFilename = function(blobOrFileInput) { - if (qq.isInput(blobOrFileInput)) { - return blobOrFileInput.value.replace(/.*(\/|\\)/, ""); - } else if (qq.isFile(blobOrFileInput)) { - if (blobOrFileInput.fileName !== null && blobOrFileInput.fileName !== undefined) { - return blobOrFileInput.fileName; - } - } - return blobOrFileInput.name; - }; - qq.DisposeSupport = function() { - var disposers = []; - return { - dispose: function() { - var disposer; - do { - disposer = disposers.shift(); - if (disposer) { - disposer(); - } - } while (disposer); - }, - attach: function() { - var args = arguments; - this.addDisposer(qq(args[0]).attach.apply(this, Array.prototype.slice.call(arguments, 1))); - }, - addDisposer: function(disposeFunction) { - disposers.push(disposeFunction); - } - }; - }; - })(); - (function() { - "use strict"; - if (typeof define === "function" && define.amd) { - define(function() { - return qq; - }); - } else if (typeof module !== "undefined" && module.exports) { - module.exports = qq; - } else { - global.qq = qq; - } - })(); - qq.version = "5.16.2"; - qq.supportedFeatures = function() { - "use strict"; - var supportsUploading, supportsUploadingBlobs, supportsFileDrop, supportsAjaxFileUploading, supportsFolderDrop, supportsChunking, supportsResume, supportsUploadViaPaste, supportsUploadCors, supportsDeleteFileXdr, supportsDeleteFileCorsXhr, supportsDeleteFileCors, supportsFolderSelection, supportsImagePreviews, supportsUploadProgress; - function testSupportsFileInputElement() { - var supported = true, tempInput; - try { - tempInput = document.createElement("input"); - tempInput.type = "file"; - qq(tempInput).hide(); - if (tempInput.disabled) { - supported = false; - } - } catch (ex) { - supported = false; - } - return supported; - } - function isChrome14OrHigher() { - return (qq.chrome() || qq.opera()) && navigator.userAgent.match(/Chrome\/[1][4-9]|Chrome\/[2-9][0-9]/) !== undefined; - } - function isCrossOriginXhrSupported() { - if (window.XMLHttpRequest) { - var xhr = qq.createXhrInstance(); - return xhr.withCredentials !== undefined; - } - return false; - } - function isXdrSupported() { - return window.XDomainRequest !== undefined; - } - function isCrossOriginAjaxSupported() { - if (isCrossOriginXhrSupported()) { - return true; - } - return isXdrSupported(); - } - function isFolderSelectionSupported() { - return document.createElement("input").webkitdirectory !== undefined; - } - function isLocalStorageSupported() { - try { - return !!window.localStorage && qq.isFunction(window.localStorage.setItem); - } catch (error) { - return false; - } - } - function isDragAndDropSupported() { - var span = document.createElement("span"); - return ("draggable" in span || "ondragstart" in span && "ondrop" in span) && !qq.android() && !qq.ios(); - } - supportsUploading = testSupportsFileInputElement(); - supportsAjaxFileUploading = supportsUploading && qq.isXhrUploadSupported(); - supportsUploadingBlobs = supportsAjaxFileUploading && !qq.androidStock(); - supportsFileDrop = supportsAjaxFileUploading && isDragAndDropSupported(); - supportsFolderDrop = supportsFileDrop && function() { - var input = document.createElement("input"); - input.type = "file"; - return !!("webkitdirectory" in (input || document.querySelectorAll("input[type=file]")[0])); - }(); - supportsChunking = supportsAjaxFileUploading && qq.isFileChunkingSupported(); - supportsResume = supportsAjaxFileUploading && supportsChunking && isLocalStorageSupported(); - supportsUploadViaPaste = supportsAjaxFileUploading && isChrome14OrHigher(); - supportsUploadCors = supportsUploading && (window.postMessage !== undefined || supportsAjaxFileUploading); - supportsDeleteFileCorsXhr = isCrossOriginXhrSupported(); - supportsDeleteFileXdr = isXdrSupported(); - supportsDeleteFileCors = isCrossOriginAjaxSupported(); - supportsFolderSelection = isFolderSelectionSupported(); - supportsImagePreviews = supportsAjaxFileUploading && window.FileReader !== undefined; - supportsUploadProgress = function() { - if (supportsAjaxFileUploading) { - return !qq.androidStock() && !qq.iosChrome(); - } - return false; - }(); - return { - ajaxUploading: supportsAjaxFileUploading, - blobUploading: supportsUploadingBlobs, - canDetermineSize: supportsAjaxFileUploading, - chunking: supportsChunking, - deleteFileCors: supportsDeleteFileCors, - deleteFileCorsXdr: supportsDeleteFileXdr, - deleteFileCorsXhr: supportsDeleteFileCorsXhr, - dialogElement: !!window.HTMLDialogElement, - fileDrop: supportsFileDrop, - folderDrop: supportsFolderDrop, - folderSelection: supportsFolderSelection, - imagePreviews: supportsImagePreviews, - imageValidation: supportsImagePreviews, - itemSizeValidation: supportsAjaxFileUploading, - pause: supportsChunking, - progressBar: supportsUploadProgress, - resume: supportsResume, - scaling: supportsImagePreviews && supportsUploadingBlobs, - tiffPreviews: qq.safari(), - unlimitedScaledImageSize: !qq.ios(), - uploading: supportsUploading, - uploadCors: supportsUploadCors, - uploadCustomHeaders: supportsAjaxFileUploading, - uploadNonMultipart: supportsAjaxFileUploading, - uploadViaPaste: supportsUploadViaPaste - }; - }(); - qq.isGenericPromise = function(maybePromise) { - "use strict"; - return !!(maybePromise && maybePromise.then && qq.isFunction(maybePromise.then)); - }; - qq.Promise = function() { - "use strict"; - var successArgs, failureArgs, successCallbacks = [], failureCallbacks = [], doneCallbacks = [], state = 0; - qq.extend(this, { - then: function(onSuccess, onFailure) { - if (state === 0) { - if (onSuccess) { - successCallbacks.push(onSuccess); - } - if (onFailure) { - failureCallbacks.push(onFailure); - } - } else if (state === -1) { - onFailure && onFailure.apply(null, failureArgs); - } else if (onSuccess) { - onSuccess.apply(null, successArgs); - } - return this; - }, - done: function(callback) { - if (state === 0) { - doneCallbacks.push(callback); - } else { - callback.apply(null, failureArgs === undefined ? successArgs : failureArgs); - } - return this; - }, - success: function() { - state = 1; - successArgs = arguments; - if (successCallbacks.length) { - qq.each(successCallbacks, function(idx, callback) { - callback.apply(null, successArgs); - }); - } - if (doneCallbacks.length) { - qq.each(doneCallbacks, function(idx, callback) { - callback.apply(null, successArgs); - }); - } - return this; - }, - failure: function() { - state = -1; - failureArgs = arguments; - if (failureCallbacks.length) { - qq.each(failureCallbacks, function(idx, callback) { - callback.apply(null, failureArgs); - }); - } - if (doneCallbacks.length) { - qq.each(doneCallbacks, function(idx, callback) { - callback.apply(null, failureArgs); - }); - } - return this; - } - }); - }; - qq.DragAndDrop = function(o) { - "use strict"; - var options, HIDE_ZONES_EVENT_NAME = "qq-hidezones", HIDE_BEFORE_ENTER_ATTR = "qq-hide-dropzone", uploadDropZones = [], droppedFiles = [], disposeSupport = new qq.DisposeSupport(); - options = { - dropZoneElements: [], - allowMultipleItems: true, - classes: { - dropActive: null - }, - callbacks: new qq.DragAndDrop.callbacks() - }; - qq.extend(options, o, true); - function uploadDroppedFiles(files, uploadDropZone) { - var filesAsArray = Array.prototype.slice.call(files); - options.callbacks.dropLog("Grabbed " + files.length + " dropped files."); - uploadDropZone.dropDisabled(false); - options.callbacks.processingDroppedFilesComplete(filesAsArray, uploadDropZone.getElement()); - } - function traverseFileTree(entry) { - var parseEntryPromise = new qq.Promise(); - if (entry.isFile) { - entry.file(function(file) { - file.qqPath = extractDirectoryPath(entry); - droppedFiles.push(file); - parseEntryPromise.success(); - }, function(fileError) { - options.callbacks.dropLog("Problem parsing '" + entry.fullPath + "'. FileError code " + fileError.code + ".", "error"); - parseEntryPromise.failure(); - }); - } else if (entry.isDirectory) { - getFilesInDirectory(entry).then(function allEntriesRead(entries) { - var entriesLeft = entries.length; - qq.each(entries, function(idx, entry) { - traverseFileTree(entry).done(function() { - entriesLeft -= 1; - if (entriesLeft === 0) { - parseEntryPromise.success(); - } - }); - }); - if (!entries.length) { - parseEntryPromise.success(); - } - }, function readFailure(fileError) { - options.callbacks.dropLog("Problem parsing '" + entry.fullPath + "'. FileError code " + fileError.code + ".", "error"); - parseEntryPromise.failure(); - }); - } - return parseEntryPromise; - } - function extractDirectoryPath(entry) { - var name = entry.name, fullPath = entry.fullPath, indexOfNameInFullPath = fullPath.lastIndexOf(name); - fullPath = fullPath.substr(0, indexOfNameInFullPath); - if (fullPath.charAt(0) === "/") { - fullPath = fullPath.substr(1); - } - return fullPath; - } - function getFilesInDirectory(entry, reader, accumEntries, existingPromise) { - var promise = existingPromise || new qq.Promise(), dirReader = reader || entry.createReader(); - dirReader.readEntries(function readSuccess(entries) { - var newEntries = accumEntries ? accumEntries.concat(entries) : entries; - if (entries.length) { - setTimeout(function() { - getFilesInDirectory(entry, dirReader, newEntries, promise); - }, 0); - } else { - promise.success(newEntries); - } - }, promise.failure); - return promise; - } - function handleDataTransfer(dataTransfer, uploadDropZone) { - var pendingFolderPromises = [], handleDataTransferPromise = new qq.Promise(); - options.callbacks.processingDroppedFiles(); - uploadDropZone.dropDisabled(true); - if (dataTransfer.files.length > 1 && !options.allowMultipleItems) { - options.callbacks.processingDroppedFilesComplete([]); - options.callbacks.dropError("tooManyFilesError", ""); - uploadDropZone.dropDisabled(false); - handleDataTransferPromise.failure(); - } else { - droppedFiles = []; - if (qq.isFolderDropSupported(dataTransfer)) { - qq.each(dataTransfer.items, function(idx, item) { - var entry = item.webkitGetAsEntry(); - if (entry) { - if (entry.isFile) { - droppedFiles.push(item.getAsFile()); - } else { - pendingFolderPromises.push(traverseFileTree(entry).done(function() { - pendingFolderPromises.pop(); - if (pendingFolderPromises.length === 0) { - handleDataTransferPromise.success(); - } - })); - } - } - }); - } else { - droppedFiles = dataTransfer.files; - } - if (pendingFolderPromises.length === 0) { - handleDataTransferPromise.success(); - } - } - return handleDataTransferPromise; - } - function setupDropzone(dropArea) { - var dropZone = new qq.UploadDropZone({ - HIDE_ZONES_EVENT_NAME: HIDE_ZONES_EVENT_NAME, - element: dropArea, - onEnter: function(e) { - qq(dropArea).addClass(options.classes.dropActive); - e.stopPropagation(); - }, - onLeaveNotDescendants: function(e) { - qq(dropArea).removeClass(options.classes.dropActive); - }, - onDrop: function(e) { - handleDataTransfer(e.dataTransfer, dropZone).then(function() { - uploadDroppedFiles(droppedFiles, dropZone); - }, function() { - options.callbacks.dropLog("Drop event DataTransfer parsing failed. No files will be uploaded.", "error"); - }); - } - }); - disposeSupport.addDisposer(function() { - dropZone.dispose(); - }); - qq(dropArea).hasAttribute(HIDE_BEFORE_ENTER_ATTR) && qq(dropArea).hide(); - uploadDropZones.push(dropZone); - return dropZone; - } - function isFileDrag(dragEvent) { - var fileDrag; - qq.each(dragEvent.dataTransfer.types, function(key, val) { - if (val === "Files") { - fileDrag = true; - return false; - } - }); - return fileDrag; - } - function leavingDocumentOut(e) { - if (qq.safari()) { - return e.x < 0 || e.y < 0; - } - return e.x === 0 && e.y === 0; - } - function setupDragDrop() { - var dropZones = options.dropZoneElements, maybeHideDropZones = function() { - setTimeout(function() { - qq.each(dropZones, function(idx, dropZone) { - qq(dropZone).hasAttribute(HIDE_BEFORE_ENTER_ATTR) && qq(dropZone).hide(); - qq(dropZone).removeClass(options.classes.dropActive); - }); - }, 10); - }; - qq.each(dropZones, function(idx, dropZone) { - var uploadDropZone = setupDropzone(dropZone); - if (dropZones.length && qq.supportedFeatures.fileDrop) { - disposeSupport.attach(document, "dragenter", function(e) { - if (!uploadDropZone.dropDisabled() && isFileDrag(e)) { - qq.each(dropZones, function(idx, dropZone) { - if (dropZone instanceof HTMLElement && qq(dropZone).hasAttribute(HIDE_BEFORE_ENTER_ATTR)) { - qq(dropZone).css({ - display: "block" - }); - } - }); - } - }); - } - }); - disposeSupport.attach(document, "dragleave", function(e) { - if (leavingDocumentOut(e)) { - maybeHideDropZones(); - } - }); - disposeSupport.attach(qq(document).children()[0], "mouseenter", function(e) { - maybeHideDropZones(); - }); - disposeSupport.attach(document, "drop", function(e) { - if (isFileDrag(e)) { - e.preventDefault(); - maybeHideDropZones(); - } - }); - disposeSupport.attach(document, HIDE_ZONES_EVENT_NAME, maybeHideDropZones); - } - setupDragDrop(); - qq.extend(this, { - setupExtraDropzone: function(element) { - options.dropZoneElements.push(element); - setupDropzone(element); - }, - removeDropzone: function(element) { - var i, dzs = options.dropZoneElements; - for (i in dzs) { - if (dzs[i] === element) { - return dzs.splice(i, 1); - } - } - }, - dispose: function() { - disposeSupport.dispose(); - qq.each(uploadDropZones, function(idx, dropZone) { - dropZone.dispose(); - }); - } - }); - this._testing = {}; - this._testing.extractDirectoryPath = extractDirectoryPath; - }; - qq.DragAndDrop.callbacks = function() { - "use strict"; - return { - processingDroppedFiles: function() {}, - processingDroppedFilesComplete: function(files, targetEl) {}, - dropError: function(code, errorSpecifics) { - qq.log("Drag & drop error code '" + code + " with these specifics: '" + errorSpecifics + "'", "error"); - }, - dropLog: function(message, level) { - qq.log(message, level); - } - }; - }; - qq.UploadDropZone = function(o) { - "use strict"; - var disposeSupport = new qq.DisposeSupport(), options, element, preventDrop, dropOutsideDisabled; - options = { - element: null, - onEnter: function(e) {}, - onLeave: function(e) {}, - onLeaveNotDescendants: function(e) {}, - onDrop: function(e) {} - }; - qq.extend(options, o); - element = options.element; - function dragoverShouldBeCanceled() { - return qq.safari() || qq.firefox() && qq.windows(); - } - function disableDropOutside(e) { - if (!dropOutsideDisabled) { - if (dragoverShouldBeCanceled) { - disposeSupport.attach(document, "dragover", function(e) { - e.preventDefault(); - }); - } else { - disposeSupport.attach(document, "dragover", function(e) { - if (e.dataTransfer) { - e.dataTransfer.dropEffect = "none"; - e.preventDefault(); - } - }); - } - dropOutsideDisabled = true; - } - } - function isValidFileDrag(e) { - if (!qq.supportedFeatures.fileDrop) { - return false; - } - var effectTest, dt = e.dataTransfer, isSafari = qq.safari(); - effectTest = qq.ie() && qq.supportedFeatures.fileDrop ? true : dt.effectAllowed !== "none"; - return dt && effectTest && (dt.files && dt.files.length || !isSafari && dt.types.contains && dt.types.contains("Files") || dt.types.includes && dt.types.includes("Files")); - } - function isOrSetDropDisabled(isDisabled) { - if (isDisabled !== undefined) { - preventDrop = isDisabled; - } - return preventDrop; - } - function triggerHidezonesEvent() { - var hideZonesEvent; - function triggerUsingOldApi() { - hideZonesEvent = document.createEvent("Event"); - hideZonesEvent.initEvent(options.HIDE_ZONES_EVENT_NAME, true, true); - } - if (window.CustomEvent) { - try { - hideZonesEvent = new CustomEvent(options.HIDE_ZONES_EVENT_NAME); - } catch (err) { - triggerUsingOldApi(); - } - } else { - triggerUsingOldApi(); - } - document.dispatchEvent(hideZonesEvent); - } - function attachEvents() { - disposeSupport.attach(element, "dragover", function(e) { - if (!isValidFileDrag(e)) { - return; - } - var effect = qq.ie() && qq.supportedFeatures.fileDrop ? null : e.dataTransfer.effectAllowed; - if (effect === "move" || effect === "linkMove") { - e.dataTransfer.dropEffect = "move"; - } else { - e.dataTransfer.dropEffect = "copy"; - } - e.stopPropagation(); - e.preventDefault(); - }); - disposeSupport.attach(element, "dragenter", function(e) { - if (!isOrSetDropDisabled()) { - if (!isValidFileDrag(e)) { - return; - } - options.onEnter(e); - } - }); - disposeSupport.attach(element, "dragleave", function(e) { - if (!isValidFileDrag(e)) { - return; - } - options.onLeave(e); - var relatedTarget = document.elementFromPoint(e.clientX, e.clientY); - if (qq(this).contains(relatedTarget)) { - return; - } - options.onLeaveNotDescendants(e); - }); - disposeSupport.attach(element, "drop", function(e) { - if (!isOrSetDropDisabled()) { - if (!isValidFileDrag(e)) { - return; - } - e.preventDefault(); - e.stopPropagation(); - options.onDrop(e); - triggerHidezonesEvent(); - } - }); - } - disableDropOutside(); - attachEvents(); - qq.extend(this, { - dropDisabled: function(isDisabled) { - return isOrSetDropDisabled(isDisabled); - }, - dispose: function() { - disposeSupport.dispose(); - }, - getElement: function() { - return element; - } - }); - this._testing = {}; - this._testing.isValidFileDrag = isValidFileDrag; - }; -})(window); -//# sourceMappingURL=dnd.js.map \ No newline at end of file diff --git a/resources/fine-uploader/dnd.js.map b/resources/fine-uploader/dnd.js.map deleted file mode 100644 index 853391d..0000000 --- a/resources/fine-uploader/dnd.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["?","../client/js/util.js","../client/js/export.js","../client/js/version.js","../client/js/features.js","../client/js/promise.js","../client/js/dnd.js"],"names":["global","qq","element","hide","style","display","this","attach","type","fn","addEventListener","attachEvent","detach","removeEventListener","detachEvent","contains","descendant","compareDocumentPosition","insertBefore","elementB","parentNode","remove","removeChild","css","styles","Error","opacity","filter","Math","round","extend","hasClass","name","considerParent","re","RegExp","test","className","addClass","removeClass","replace","getByClass","first","candidates","result","querySelector","querySelectorAll","getElementsByTagName","each","idx","val","push","getFirstByClass","children","child","firstChild","nodeType","nextSibling","setText","text","innerText","textContent","clearText","hasAttribute","attrName","attrVal","exec","getAttribute","undefined","canvasToBlob","canvas","mime","quality","dataUriToBlob","toDataURL","dataUri","arrayBuffer","byteString","createBlob","data","BlobBuilder","window","WebKitBlobBuilder","MozBlobBuilder","MSBlobBuilder","blobBuilder","append","getBlob","Blob","intArray","mimeString","split","indexOf","atob","decodeURI","ArrayBuffer","length","Uint8Array","character","charCodeAt","log","message","level","console","isObject","variable","Object","prototype","toString","call","isFunction","isArray","value","buffer","constructor","isItemList","maybeItemList","isNodeList","maybeNodeList","item","namedItem","isString","maybeString","trimStr","string","String","trim","format","str","args","Array","slice","arguments","newStr","nextIdxToReplace","strBefore","substring","strAfter","isFile","maybeFile","File","isFileList","maybeFileList","FileList","isFileOrInput","maybeFileOrInput","isInput","maybeInput","notFile","evaluateType","normalizedType","toLowerCase","HTMLInputElement","tagName","isBlob","maybeBlob","isXhrUploadSupported","input","document","createElement","multiple","FormData","createXhrInstance","upload","XMLHttpRequest","ActiveXObject","error","isFolderDropSupported","dataTransfer","items","webkitGetAsEntry","isFileChunkingSupported","androidStock","webkitSlice","mozSlice","sliceBlob","fileOrBlob","start","end","slicer","arrayBufferToHex","bytesAsHex","bytes","byt","byteAsHexStr","readBlobToHex","blob","startOffset","initialBlob","fileReader","FileReader","promise","Promise","onload","success","onerror","failure","readAsArrayBuffer","second","extendNested","prop","override","target","sourceFn","super_","source","srcPropName","srcPropVal","arr","elt","from","len","hasOwnProperty","getUniqueId","c","r","random","v","ie","navigator","userAgent","ie7","ie8","ie10","ie11","edge","safari","vendor","chrome","opera","firefox","windows","platform","android","ios6","ios","ios7","ios8","ios800","iosChrome","iosSafari","iosSafariWebView","preventDefault","e","returnValue","toElement","div","html","innerHTML","iterableItem","callback","keyOrIndex","retVal","Storage","key","getItem","charAt","bind","oldFunc","context","newArgs","concat","apply","obj2url","obj","temp","prefixDone","uristrings","prefix","add","nextObj","i","nextTemp","encodeURIComponent","join","obj2FormData","formData","arrayKeyName","obj2Inputs","form","setAttribute","appendChild","parseJson","json","JSON","parse","eval","getExtension","filename","extIdx","lastIndexOf","substr","getFilename","blobOrFileInput","fileName","DisposeSupport","disposers","dispose","disposer","shift","addDisposer","disposeFunction","define","amd","module","exports","version","supportedFeatures","supportsUploading","supportsUploadingBlobs","supportsFileDrop","supportsAjaxFileUploading","supportsFolderDrop","supportsChunking","supportsResume","supportsUploadViaPaste","supportsUploadCors","supportsDeleteFileXdr","supportsDeleteFileCorsXhr","supportsDeleteFileCors","supportsFolderSelection","supportsImagePreviews","supportsUploadProgress","testSupportsFileInputElement","supported","tempInput","disabled","ex","isChrome14OrHigher","match","isCrossOriginXhrSupported","xhr","withCredentials","isXdrSupported","XDomainRequest","isCrossOriginAjaxSupported","isFolderSelectionSupported","webkitdirectory","isLocalStorageSupported","localStorage","setItem","isDragAndDropSupported","span","postMessage","ajaxUploading","blobUploading","canDetermineSize","chunking","deleteFileCors","deleteFileCorsXdr","deleteFileCorsXhr","dialogElement","HTMLDialogElement","fileDrop","folderDrop","folderSelection","imagePreviews","imageValidation","itemSizeValidation","pause","progressBar","resume","scaling","tiffPreviews","unlimitedScaledImageSize","uploading","uploadCors","uploadCustomHeaders","uploadNonMultipart","uploadViaPaste","isGenericPromise","maybePromise","then","successArgs","failureArgs","successCallbacks","failureCallbacks","doneCallbacks","state","onSuccess","onFailure","done","DragAndDrop","o","options","HIDE_ZONES_EVENT_NAME","HIDE_BEFORE_ENTER_ATTR","uploadDropZones","droppedFiles","disposeSupport","dropZoneElements","allowMultipleItems","classes","dropActive","callbacks","uploadDroppedFiles","files","uploadDropZone","filesAsArray","dropLog","dropDisabled","processingDroppedFilesComplete","getElement","traverseFileTree","entry","parseEntryPromise","file","qqPath","extractDirectoryPath","fileError","fullPath","code","isDirectory","getFilesInDirectory","allEntriesRead","entries","entriesLeft","readFailure","indexOfNameInFullPath","reader","accumEntries","existingPromise","dirReader","createReader","readEntries","readSuccess","newEntries","setTimeout","handleDataTransfer","pendingFolderPromises","handleDataTransferPromise","processingDroppedFiles","dropError","getAsFile","pop","setupDropzone","dropArea","dropZone","UploadDropZone","onEnter","stopPropagation","onLeaveNotDescendants","onDrop","isFileDrag","dragEvent","fileDrag","types","leavingDocumentOut","x","y","setupDragDrop","dropZones","maybeHideDropZones","HTMLElement","setupExtraDropzone","removeDropzone","dzs","splice","_testing","targetEl","errorSpecifics","preventDrop","dropOutsideDisabled","onLeave","dragoverShouldBeCanceled","disableDropOutside","dropEffect","isValidFileDrag","effectTest","dt","isSafari","effectAllowed","includes","isOrSetDropDisabled","isDisabled","triggerHidezonesEvent","hideZonesEvent","triggerUsingOldApi","createEvent","initEvent","CustomEvent","err","dispatchEvent","attachEvents","effect","relatedTarget","elementFromPoint","clientX","clientY"],"mappings":";CAAA,SAAUA;ICEV,IAAIC,KAAK,SAASC;QACd;QAEA;YACIC,MAAM;gBACFD,QAAQE,MAAMC,UAAU;gBACxB,OAAOC;;YAIXC,QAAQ,SAASC,MAAMC;gBACnB,IAAIP,QAAQQ,kBAAkB;oBAC1BR,QAAQQ,iBAAiBF,MAAMC,IAAI;uBAChC,IAAIP,QAAQS,aAAa;oBAC5BT,QAAQS,YAAY,OAAOH,MAAMC;;gBAErC,OAAO;oBACHR,GAAGC,SAASU,OAAOJ,MAAMC;;;YAIjCG,QAAQ,SAASJ,MAAMC;gBACnB,IAAIP,QAAQW,qBAAqB;oBAC7BX,QAAQW,oBAAoBL,MAAMC,IAAI;uBACnC,IAAIP,QAAQS,aAAa;oBAC5BT,QAAQY,YAAY,OAAON,MAAMC;;gBAErC,OAAOH;;YAGXS,UAAU,SAASC;gBAKf,KAAKA,YAAY;oBACb,OAAO;;gBAIX,IAAId,YAAYc,YAAY;oBACxB,OAAO;;gBAGX,IAAId,QAAQa,UAAU;oBAClB,OAAOb,QAAQa,SAASC;uBACrB;oBAEH,UAAUA,WAAWC,wBAAwBf,WAAW;;;YAOhEgB,cAAc,SAASC;gBACnBA,SAASC,WAAWF,aAAahB,SAASiB;gBAC1C,OAAOb;;YAGXe,QAAQ;gBACJnB,QAAQkB,WAAWE,YAAYpB;gBAC/B,OAAOI;;YAOXiB,KAAK,SAASC;gBAEV,IAAItB,QAAQE,SAAS,MAAM;oBACvB,MAAM,IAAIH,GAAGwB,MAAM;;gBAIvB,IAAID,OAAOE,WAAW,MAAM;oBACxB,WAAWxB,QAAQE,MAAMsB,YAAY,mBAAoBxB,QAAe,YAAM,aAAa;wBACvFsB,OAAOG,SAAS,mBAAmBC,KAAKC,MAAM,MAAML,OAAOE,WAAW;;;gBAG9EzB,GAAG6B,OAAO5B,QAAQE,OAAOoB;gBAEzB,OAAOlB;;YAGXyB,UAAU,SAASC,MAAMC;gBACrB,IAAIC,KAAK,IAAIC,OAAO,UAAUH,OAAO;gBACrC,OAAOE,GAAGE,KAAKlC,QAAQmC,iBAAiBJ,kBAAkBC,GAAGE,KAAKlC,QAAQkB,WAAWiB;;YAGzFC,UAAU,SAASN;gBACf,KAAK/B,GAAGC,SAAS6B,SAASC,OAAO;oBAC7B9B,QAAQmC,aAAa,MAAML;;gBAE/B,OAAO1B;;YAGXiC,aAAa,SAASP;gBAClB,IAAIE,KAAK,IAAIC,OAAO,UAAUH,OAAO;gBACrC9B,QAAQmC,YAAYnC,QAAQmC,UAAUG,QAAQN,IAAI,KAAKM,QAAQ,cAAc;gBAC7E,OAAOlC;;YAGXmC,YAAY,SAASJ,WAAWK;gBAC5B,IAAIC,YACAC;gBAEJ,IAAIF,SAASxC,QAAQ2C,eAAe;oBAChC,OAAO3C,QAAQ2C,cAAc,MAAMR;uBAElC,IAAInC,QAAQ4C,kBAAkB;oBAC/B,OAAO5C,QAAQ4C,iBAAiB,MAAMT;;gBAG1CM,aAAazC,QAAQ6C,qBAAqB;gBAE1C9C,GAAG+C,KAAKL,YAAY,SAASM,KAAKC;oBAC9B,IAAIjD,GAAGiD,KAAKnB,SAASM,YAAY;wBAC7BO,OAAOO,KAAKD;;;gBAGpB,OAAOR,QAAQE,OAAO,KAAKA;;YAG/BQ,iBAAiB,SAASf;gBACtB,OAAOpC,GAAGC,SAASuC,WAAWJ,WAAW;;YAG7CgB,UAAU;gBACN,IAAIA,eACAC,QAAQpD,QAAQqD;gBAEpB,OAAOD,OAAO;oBACV,IAAIA,MAAME,aAAa,GAAG;wBACtBH,SAASF,KAAKG;;oBAElBA,QAAQA,MAAMG;;gBAGlB,OAAOJ;;YAGXK,SAAS,SAASC;gBACdzD,QAAQ0D,YAAYD;gBACpBzD,QAAQ2D,cAAcF;gBACtB,OAAOrD;;YAGXwD,WAAW;gBACP,OAAO7D,GAAGC,SAASwD,QAAQ;;YAK/BK,cAAc,SAASC;gBACnB,IAAIC;gBAEJ,IAAI/D,QAAQ6D,cAAc;oBAEtB,KAAK7D,QAAQ6D,aAAaC,WAAW;wBACjC,OAAO;;oBAIX,OAAO,WAAaE,KAAKhE,QAAQiE,aAAaH,cAAc;uBAE3D;oBACDC,UAAU/D,QAAQ8D;oBAElB,IAAIC,YAAYG,WAAW;wBACvB,OAAO;;oBAIX,OAAO,WAAaF,KAAKD,YAAY;;;;;KAMpD;QACG;QAEAhE,GAAGoE,eAAe,SAASC,QAAQC,MAAMC;YACrC,OAAOvE,GAAGwE,cAAcH,OAAOI,UAAUH,MAAMC;;QAGnDvE,GAAGwE,gBAAgB,SAASE;YACxB,IAAIC,aAAaC,YACbC,aAAa,SAASC,MAAMR;gBACxB,IAAIS,cAAcC,OAAOD,eACjBC,OAAOC,qBACPD,OAAOE,kBACPF,OAAOG,eACXC,cAAcL,eAAe,IAAIA;gBAErC,IAAIK,aAAa;oBACbA,YAAYC,OAAOP;oBACnB,OAAOM,YAAYE,QAAQhB;uBAE1B;oBACD,OAAO,IAAIiB,OAAMT;wBAAQvE,MAAM+D;;;eAGvCkB,UAAUC;YAGd,IAAIf,QAAQgB,MAAM,KAAK,GAAGC,QAAQ,aAAa,GAAG;gBAC9Cf,aAAagB,KAAKlB,QAAQgB,MAAM,KAAK;mBAEpC;gBACDd,aAAaiB,UAAUnB,QAAQgB,MAAM,KAAK;;YAI9CD,aAAaf,QAAQgB,MAAM,KAAK,GAC3BA,MAAM,KAAK,GACXA,MAAM,KAAK;YAGhBf,cAAc,IAAImB,YAAYlB,WAAWmB;YACzCP,WAAW,IAAIQ,WAAWrB;YAC1B3E,GAAG+C,KAAK6B,YAAY,SAAS5B,KAAKiD;gBAC9BT,SAASxC,OAAOiD,UAAUC,WAAW;;YAGzC,OAAOrB,WAAWF,aAAac;;QAGnCzF,GAAGmG,MAAM,SAASC,SAASC;YACvB,IAAIrB,OAAOsB,SAAS;gBAChB,KAAKD,SAASA,UAAU,QAAQ;oBAC5BrB,OAAOsB,QAAQH,IAAIC;uBAGvB;oBACI,IAAIpB,OAAOsB,QAAQD,QAAQ;wBACvBrB,OAAOsB,QAAQD,OAAOD;2BAErB;wBACDpB,OAAOsB,QAAQH,IAAI,MAAME,QAAQ,OAAOD;;;;;QAMxDpG,GAAGuG,WAAW,SAASC;YACnB,OAAOA,aAAaA,SAASjD,YAAYkD,OAAOC,UAAUC,SAASC,KAAKJ,cAAc;;QAG1FxG,GAAG6G,aAAa,SAASL;YACrB,cAAc,aAAe;;QASjCxG,GAAG8G,UAAU,SAASC;YAClB,OAAON,OAAOC,UAAUC,SAASC,KAAKG,WAAW,oBAC5CA,SAAS/B,OAAOc,eAAeiB,MAAMC,UAAUD,MAAMC,OAAOC,gBAAgBnB;;QAIrF9F,GAAGkH,aAAa,SAASC;YACrB,OAAOV,OAAOC,UAAUC,SAASC,KAAKO,mBAAmB;;QAK7DnH,GAAGoH,aAAa,SAASC;YACrB,OAAOZ,OAAOC,UAAUC,SAASC,KAAKS,mBAAmB,uBAGpDA,cAAcC,QAAQD,cAAcE;;QAG7CvH,GAAGwH,WAAW,SAASC;YACnB,OAAOhB,OAAOC,UAAUC,SAASC,KAAKa,iBAAiB;;QAG3DzH,GAAG0H,UAAU,SAASC;YAClB,IAAIC,OAAOlB,UAAUmB,MAAM;gBACvB,OAAOF,OAAOE;;YAGlB,OAAOF,OAAOpF,QAAQ,cAAc;;QAOxCvC,GAAG8H,SAAS,SAASC;YAEjB,IAAIC,OAAQC,MAAMvB,UAAUwB,MAAMtB,KAAKuB,WAAW,IAC9CC,SAASL,KACTM,mBAAmBD,OAAOzC,QAAQ;YAEtC3F,GAAG+C,KAAKiF,MAAM,SAAShF,KAAKC;gBACxB,IAAIqF,YAAYF,OAAOG,UAAU,GAAGF,mBAChCG,WAAWJ,OAAOG,UAAUF,mBAAmB;gBAEnDD,SAASE,YAAYrF,MAAMuF;gBAC3BH,mBAAmBD,OAAOzC,QAAQ,MAAM0C,mBAAmBpF,IAAI8C;gBAG/D,IAAIsC,mBAAmB,GAAG;oBACtB,OAAO;;;YAIf,OAAOD;;QAGXpI,GAAGyI,SAAS,SAASC;YACjB,OAAO1D,OAAO2D,QAAQlC,OAAOC,UAAUC,SAASC,KAAK8B,eAAe;;QAGxE1I,GAAG4I,aAAa,SAASC;YACrB,OAAO7D,OAAO8D,YAAYrC,OAAOC,UAAUC,SAASC,KAAKiC,mBAAmB;;QAGhF7I,GAAG+I,gBAAgB,SAASC;YACxB,OAAOhJ,GAAGyI,OAAOO,qBAAqBhJ,GAAGiJ,QAAQD;;QAGrDhJ,GAAGiJ,UAAU,SAASC,YAAYC;YAC9B,IAAIC,eAAe,SAAS7I;gBACxB,IAAI8I,iBAAiB9I,KAAK+I;gBAE1B,IAAIH,SAAS;oBACT,OAAOE,mBAAmB;;gBAG9B,OAAOA,mBAAmB;;YAG9B,IAAIrE,OAAOuE,kBAAkB;gBACzB,IAAI9C,OAAOC,UAAUC,SAASC,KAAKsC,gBAAgB,6BAA6B;oBAC5E,IAAIA,WAAW3I,QAAQ6I,aAAaF,WAAW3I,OAAO;wBAClD,OAAO;;;;YAInB,IAAI2I,WAAWM,SAAS;gBACpB,IAAIN,WAAWM,QAAQF,kBAAkB,SAAS;oBAC9C,IAAIJ,WAAW3I,QAAQ6I,aAAaF,WAAW3I,OAAO;wBAClD,OAAO;;;;YAKnB,OAAO;;QAGXP,GAAGyJ,SAAS,SAASC;YACjB,IAAI1E,OAAOO,QAAQkB,OAAOC,UAAUC,SAASC,KAAK8C,eAAe,iBAAiB;gBAC9E,OAAO;;;QAIf1J,GAAG2J,uBAAuB;YACtB,IAAIC,QAAQC,SAASC,cAAc;YACnCF,MAAMrJ,OAAO;YAEb,OACIqJ,MAAMG,aAAa5F,oBACRwE,SAAS,sBACTqB,aAAa,sBACZhK,GAAGiK,oBAAqBC,WAAW;;QAIvDlK,GAAGiK,oBAAoB;YACnB,IAAIjF,OAAOmF,gBAAgB;gBACvB,OAAO,IAAIA;;YAGf;gBACI,OAAO,IAAIC,cAAc;cAE7B,OAAOC;gBACHrK,GAAGmG,IAAI,yCAAyC;gBAChD,OAAO;;;QAIfnG,GAAGsK,wBAAwB,SAASC;YAChC,OAAOA,aAAaC,SAChBD,aAAaC,MAAMzE,SAAS,KAC5BwE,aAAaC,MAAM,GAAGC;;QAG9BzK,GAAG0K,0BAA0B;YACzB,QAAQ1K,GAAG2K,kBACP3K,GAAG2J,2BACFhB,KAAKjC,UAAUwB,UAAU/D,aAAawE,KAAKjC,UAAUkE,gBAAgBzG,aAAawE,KAAKjC,UAAUmE,aAAa1G;;QAGvHnE,GAAG8K,YAAY,SAASC,YAAYC,OAAOC;YACvC,IAAIC,SAASH,WAAW7C,SAAS6C,WAAWF,YAAYE,WAAWH;YAEnE,OAAOM,OAAOtE,KAAKmE,YAAYC,OAAOC;;QAG1CjL,GAAGmL,mBAAmB,SAASnE;YAC3B,IAAIoE,aAAa,IACbC,QAAQ,IAAIrF,WAAWgB;YAE3BhH,GAAG+C,KAAKsI,OAAO,SAASrI,KAAKsI;gBACzB,IAAIC,eAAeD,IAAI3E,SAAS;gBAEhC,IAAI4E,aAAaxF,SAAS,GAAG;oBACzBwF,eAAe,MAAMA;;gBAGzBH,cAAcG;;YAGlB,OAAOH;;QAGXpL,GAAGwL,gBAAgB,SAASC,MAAMC,aAAa3F;YAC3C,IAAI4F,cAAc3L,GAAG8K,UAAUW,MAAMC,aAAaA,cAAc3F,SAC5D6F,aAAa,IAAIC,cACjBC,UAAU,IAAI9L,GAAG+L;YAErBH,WAAWI,SAAS;gBAChBF,QAAQG,QAAQjM,GAAGmL,iBAAiBS,WAAWjJ;;YAGnDiJ,WAAWM,UAAUJ,QAAQK;YAE7BP,WAAWQ,kBAAkBT;YAE7B,OAAOG;;QAGX9L,GAAG6B,SAAS,SAASY,OAAO4J,QAAQC;YAChCtM,GAAG+C,KAAKsJ,QAAQ,SAASE,MAAMtJ;gBAC3B,IAAIqJ,gBAAgBtM,GAAGuG,SAAStD,MAAM;oBAClC,IAAIR,MAAM8J,UAAUpI,WAAW;wBAC3B1B,MAAM8J;;oBAEVvM,GAAG6B,OAAOY,MAAM8J,OAAOtJ,KAAK;uBAE3B;oBACDR,MAAM8J,QAAQtJ;;;YAItB,OAAOR;;QAaXzC,GAAGwM,WAAW,SAASC,QAAQC;YAC3B,IAAIC,aACAC,SAASF,SAASC;YAEtB3M,GAAG+C,KAAK6J,QAAQ,SAASC,aAAaC;gBAClC,IAAIL,OAAOI,iBAAiB1I,WAAW;oBACnCwI,OAAOE,eAAeJ,OAAOI;;gBAGjCJ,OAAOI,eAAeC;;YAG1B,OAAOL;;QAMXzM,GAAG2F,UAAU,SAASoH,KAAKC,KAAKC;YAC5B,IAAIF,IAAIpH,SAAS;gBACb,OAAOoH,IAAIpH,QAAQqH,KAAKC;;YAG5BA,OAAOA,QAAQ;YACf,IAAIC,MAAMH,IAAIhH;YAEd,IAAIkH,OAAO,GAAG;gBACVA,QAAQC;;YAGZ,MAAOD,OAAOC,KAAKD,QAAQ,GAAG;gBAC1B,IAAIF,IAAII,eAAeF,SAASF,IAAIE,UAAUD,KAAK;oBAC/C,OAAOC;;;YAGf,QAAQ;;QAIZjN,GAAGoN,cAAc;YACb,OAAO,uCAAuC7K,QAAQ,SAAS,SAAS8K;gBAEpE,IAAIC,IAAI3L,KAAK4L,WAAW,KAAK,GAAGC,IAAIH,KAAK,MAAMC,IAAKA,IAAI,IAAM;gBAC9D,OAAOE,EAAE7G,SAAS;;;QAM1B3G,GAAGyN,KAAK;YACJ,OAAOC,UAAUC,UAAUhI,QAAQ,aAAa,KAC5C+H,UAAUC,UAAUhI,QAAQ,gBAAgB;;QAGpD3F,GAAG4N,MAAM;YACL,OAAOF,UAAUC,UAAUhI,QAAQ,eAAe;;QAGtD3F,GAAG6N,MAAM;YACL,OAAOH,UAAUC,UAAUhI,QAAQ,eAAe;;QAGtD3F,GAAG8N,OAAO;YACN,OAAOJ,UAAUC,UAAUhI,QAAQ,gBAAgB;;QAGvD3F,GAAG+N,OAAO;YACN,OAAO/N,GAAGyN,QAAQC,UAAUC,UAAUhI,QAAQ,cAAc;;QAGhE3F,GAAGgO,OAAO;YACN,OAAON,UAAUC,UAAUhI,QAAQ,WAAW;;QAGlD3F,GAAGiO,SAAS;YACR,OAAOP,UAAUQ,WAAW/J,aAAauJ,UAAUQ,OAAOvI,QAAQ,cAAc;;QAGpF3F,GAAGmO,SAAS;YACR,OAAOT,UAAUQ,WAAW/J,aAAauJ,UAAUQ,OAAOvI,QAAQ,eAAe;;QAGrF3F,GAAGoO,QAAQ;YACP,OAAOV,UAAUQ,WAAW/J,aAAauJ,UAAUQ,OAAOvI,QAAQ,cAAc;;QAGpF3F,GAAGqO,UAAU;YACT,QAASrO,GAAGgO,WAAWhO,GAAG+N,UAAUL,UAAUC,UAAUhI,QAAQ,gBAAgB,KAAK+H,UAAUQ,WAAW/J,aAAauJ,UAAUQ,WAAW;;QAGhJlO,GAAGsO,UAAU;YACT,OAAOZ,UAAUa,aAAa;;QAGlCvO,GAAGwO,UAAU;YACT,OAAOd,UAAUC,UAAUrE,cAAc3D,QAAQ,gBAAgB;;QAKrE3F,GAAG2K,eAAe;YACd,OAAO3K,GAAGwO,aAAad,UAAUC,UAAUrE,cAAc3D,QAAQ,YAAY;;QAGjF3F,GAAGyO,OAAO;YACN,OAAOzO,GAAG0O,SAAShB,UAAUC,UAAUhI,QAAQ,eAAe;;QAGlE3F,GAAG2O,OAAO;YACN,OAAO3O,GAAG0O,SAAShB,UAAUC,UAAUhI,QAAQ,eAAe;;QAGlE3F,GAAG4O,OAAO;YACN,OAAO5O,GAAG0O,SAAShB,UAAUC,UAAUhI,QAAQ,eAAe;;QAIlE3F,GAAG6O,SAAS;YACR,OAAO7O,GAAG0O,SAAShB,UAAUC,UAAUhI,QAAQ,iBAAiB;;QAGpE3F,GAAG0O,MAAM;YAEL,OAAOhB,UAAUC,UAAUhI,QAAQ,aAAa,KACzC+H,UAAUC,UAAUhI,QAAQ,aAAa,KACzC+H,UAAUC,UAAUhI,QAAQ,eAAe;;QAGtD3F,GAAG8O,YAAY;YACX,OAAO9O,GAAG0O,SAAShB,UAAUC,UAAUhI,QAAQ,cAAc;;QAGjE3F,GAAG+O,YAAY;YACX,OAAO/O,GAAG0O,UAAU1O,GAAG8O,eAAepB,UAAUC,UAAUhI,QAAQ,eAAe;;QAGrF3F,GAAGgP,mBAAmB;YAClB,OAAOhP,GAAG0O,UAAU1O,GAAG8O,gBAAgB9O,GAAG+O;;QAM9C/O,GAAGiP,iBAAiB,SAASC;YACzB,IAAIA,EAAED,gBAAgB;gBAClBC,EAAED;mBACC;gBACHC,EAAEC,cAAc;;;QAQxBnP,GAAGoP,YAAa;YACZ,IAAIC,MAAMxF,SAASC,cAAc;YACjC,OAAO,SAASwF;gBACZD,IAAIE,YAAYD;gBAChB,IAAIrP,UAAUoP,IAAI/L;gBAClB+L,IAAIhO,YAAYpB;gBAChB,OAAOA;;;QAKfD,GAAG+C,OAAO,SAASyM,cAAcC;YAC7B,IAAIC,YAAYC;YAEhB,IAAIH,cAAc;gBAEd,IAAIxK,OAAO4K,WAAWJ,aAAavI,gBAAgBjC,OAAO4K,SAAS;oBAC/D,KAAKF,aAAa,GAAGA,aAAaF,aAAazJ,QAAQ2J,cAAc;wBACjEC,SAASF,SAASD,aAAaK,IAAIH,aAAaF,aAAaM,QAAQN,aAAaK,IAAIH;wBACtF,IAAIC,WAAW,OAAO;4BAClB;;;uBAMP,IAAI3P,GAAG8G,QAAQ0I,iBAAiBxP,GAAGkH,WAAWsI,iBAAiBxP,GAAGoH,WAAWoI,eAAe;oBAC7F,KAAKE,aAAa,GAAGA,aAAaF,aAAazJ,QAAQ2J,cAAc;wBACjEC,SAASF,SAASC,YAAYF,aAAaE;wBAC3C,IAAIC,WAAW,OAAO;4BAClB;;;uBAIP,IAAI3P,GAAGwH,SAASgI,eAAe;oBAChC,KAAKE,aAAa,GAAGA,aAAaF,aAAazJ,QAAQ2J,cAAc;wBACjEC,SAASF,SAASC,YAAYF,aAAaO,OAAOL;wBAClD,IAAIC,WAAW,OAAO;4BAClB;;;uBAIP;oBACD,KAAKD,cAAcF,cAAc;wBAC7B,IAAI/I,OAAOC,UAAUyG,eAAevG,KAAK4I,cAAcE,aAAa;4BAChEC,SAASF,SAASC,YAAYF,aAAaE;4BAC3C,IAAIC,WAAW,OAAO;gCAClB;;;;;;;QASxB3P,GAAGgQ,OAAO,SAASC,SAASC;YACxB,IAAIlQ,GAAG6G,WAAWoJ,UAAU;gBACxB,IAAIjI,OAAQC,MAAMvB,UAAUwB,MAAMtB,KAAKuB,WAAW;gBAElD,OAAO;oBACH,IAAIgI,UAAUnQ,GAAG6B,WAAWmG;oBAC5B,IAAIG,UAAUpC,QAAQ;wBAClBoK,UAAUA,QAAQC,OAAOnI,MAAMvB,UAAUwB,MAAMtB,KAAKuB;;oBAExD,OAAO8H,QAAQI,MAAMH,SAASC;;;YAItC,MAAM,IAAI3O,MAAM;;QAmBpBxB,GAAGsQ,UAAU,SAASC,KAAKC,MAAMC;YAE7B,IAAIC,iBACAC,SAAS,KACTC,MAAM,SAASC,SAASC;gBACpB,IAAIC,WAAWP,OACR,QAAQrO,KAAKqO,QACdA,OACAA,OAAO,MAAMM,IAAI,MACjBA;gBACN,IAAKC,aAAa,eAAiBD,MAAM,aAAc;oBACnDJ,WAAWxN,YACC2N,YAAY,WACd7Q,GAAGsQ,QAAQO,SAASE,UAAU,QAC7BtK,OAAOC,UAAUC,SAASC,KAAKiK,aAAa,sBAC7CG,mBAAmBD,YAAY,MAAMC,mBAAmBH,aACxDG,mBAAmBD,YAAY,MAAMC,mBAAmBH;;;YAK9E,KAAKJ,cAAcD,MAAM;gBACrBG,SAAU,KAAKxO,KAAKqO,QAAU,MAAMrO,KAAKqO,QAAS,KAAK,MAAM;gBAC7DE,WAAWxN,KAAKsN;gBAChBE,WAAWxN,KAAKlD,GAAGsQ,QAAQC;mBACxB,IAAK9J,OAAOC,UAAUC,SAASC,KAAK2J,SAAS,2BAA6BA,QAAQ,aAAc;gBACnGvQ,GAAG+C,KAAKwN,KAAK,SAASvN,KAAKC;oBACvB2N,IAAI3N,KAAKD;;mBAEV,WAAYuN,QAAQ,eAAiBA,QAAQ,eAAiBA,QAAQ,UAAW;gBACpFvQ,GAAG+C,KAAKwN,KAAK,SAAShE,MAAMtJ;oBACxB2N,IAAI3N,KAAKsJ;;mBAEV;gBACHmE,WAAWxN,KAAK8N,mBAAmBR,QAAQ,MAAMQ,mBAAmBT;;YAGxE,IAAIC,MAAM;gBACN,OAAOE,WAAWO,KAAKN;mBACpB;gBACH,OAAOD,WAAWO,KAAKN,QAClBpO,QAAQ,MAAM,IACdA,QAAQ,QAAQ;;;QAI7BvC,GAAGkR,eAAe,SAASX,KAAKY,UAAUC;YACtC,KAAKD,UAAU;gBACXA,WAAW,IAAInH;;YAGnBhK,GAAG+C,KAAKwN,KAAK,SAASV,KAAK5M;gBACvB4M,MAAMuB,eAAeA,eAAe,MAAMvB,MAAM,MAAMA;gBAEtD,IAAI7P,GAAGuG,SAAStD,MAAM;oBAClBjD,GAAGkR,aAAajO,KAAKkO,UAAUtB;uBAE9B,IAAI7P,GAAG6G,WAAW5D,MAAM;oBACzBkO,SAAS9L,OAAOwK,KAAK5M;uBAEpB;oBACDkO,SAAS9L,OAAOwK,KAAK5M;;;YAI7B,OAAOkO;;QAGXnR,GAAGqR,aAAa,SAASd,KAAKe;YAC1B,IAAI1H;YAEJ,KAAK0H,MAAM;gBACPA,OAAOzH,SAASC,cAAc;;YAGlC9J,GAAGkR,aAAaX;gBACZlL,QAAQ,SAASwK,KAAK5M;oBAClB2G,QAAQC,SAASC,cAAc;oBAC/BF,MAAM2H,aAAa,QAAQ1B;oBAC3BjG,MAAM2H,aAAa,SAAStO;oBAC5BqO,KAAKE,YAAY5H;;;YAIzB,OAAO0H;;QAOXtR,GAAGyR,YAAY,SAASC;YAEpB,IAAI1M,OAAO2M,QAAQ3R,GAAG6G,WAAW8K,KAAKC,QAAQ;gBAC1C,OAAOD,KAAKC,MAAMF;mBACf;gBACH,OAAOG,KAAK,MAAMH,OAAO;;;QAUjC1R,GAAG8R,eAAe,SAASC;YACvB,IAAIC,SAASD,SAASE,YAAY,OAAO;YAEzC,IAAID,SAAS,GAAG;gBACZ,OAAOD,SAASG,OAAOF,QAAQD,SAAShM,SAASiM;;;QAIzDhS,GAAGmS,cAAc,SAASC;YAGtB,IAAIpS,GAAGiJ,QAAQmJ,kBAAkB;gBAE7B,OAAOA,gBAAgBrL,MAAMxE,QAAQ,aAAa;mBAEjD,IAAIvC,GAAGyI,OAAO2J,kBAAkB;gBACjC,IAAIA,gBAAgBC,aAAa,QAAQD,gBAAgBC,aAAalO,WAAW;oBAC7E,OAAOiO,gBAAgBC;;;YAI/B,OAAOD,gBAAgBrQ;;QAM3B/B,GAAGsS,iBAAiB;YAChB,IAAIC;YAEJ;gBAEIC,SAAS;oBACL,IAAIC;oBACJ,GAAG;wBACCA,WAAWF,UAAUG;wBACrB,IAAID,UAAU;4BACVA;;6BAGDA;;gBAIXnS,QAAQ;oBACJ,IAAI0H,OAAOG;oBAEX9H,KAAKsS,YAAY3S,GAAGgI,KAAK,IAAI1H,OAAO+P,MAAMhQ,MAAM4H,MAAMvB,UAAUwB,MAAMtB,KAAKuB,WAAW;;gBAI1FwK,aAAa,SAASC;oBAClBL,UAAUrP,KAAK0P;;;;;KCt2B9B;QACG;QACA,WAAWC,WAAW,cAAcA,OAAOC,KAAK;YAC5CD,OAAO;gBACH,OAAO7S;;eAGV,WAAW+S,WAAW,eAAeA,OAAOC,SAAS;YACtDD,OAAOC,UAAUhT;eAEhB;YACDD,OAAOC,KAAKA;;;ICXpBA,GAAGiT,UAAU;ICAbjT,GAAGkT,oBAAqB;QACpB;QAEA,IAAIC,mBACAC,wBACAC,kBACAC,2BACAC,oBACAC,kBACAC,gBACAC,wBACAC,oBACAC,uBACAC,2BACAC,wBACAC,yBACAC,uBACAC;QAEJ,SAASC;YACL,IAAIC,YAAY,MACZC;YAEJ;gBACIA,YAAYvK,SAASC,cAAc;gBACnCsK,UAAU7T,OAAO;gBACjBP,GAAGoU,WAAWlU;gBAEd,IAAIkU,UAAUC,UAAU;oBACpBF,YAAY;;cAGpB,OAAOG;gBACHH,YAAY;;YAGhB,OAAOA;;QAIX,SAASI;YACL,QAAQvU,GAAGmO,YAAYnO,GAAGoO,YACtBV,UAAUC,UAAU6G,MAAM,2CAA2CrQ;;QAI7E,SAASsQ;YACL,IAAIzP,OAAOmF,gBAAgB;gBACvB,IAAIuK,MAAM1U,GAAGiK;gBAGb,OAAOyK,IAAIC,oBAAoBxQ;;YAGnC,OAAO;;QAIX,SAASyQ;YACL,OAAO5P,OAAO6P,mBAAmB1Q;;QAKrC,SAAS2Q;YACL,IAAIL,6BAA6B;gBAC7B,OAAO;;YAGX,OAAOG;;QAGX,SAASG;YAEL,OAAOlL,SAASC,cAAc,SAASkL,oBAAoB7Q;;QAG/D,SAAS8Q;YACL;gBACI,SAASjQ,OAAOkQ,gBAEZlV,GAAG6G,WAAW7B,OAAOkQ,aAAaC;cAE1C,OAAO9K;gBAEH,OAAO;;;QAIf,SAAS+K;YACL,IAAIC,OAAOxL,SAASC,cAAc;YAElC,QAAQ,eAAeuL,QAAS,iBAAiBA,QAAQ,YAAYA,UAChErV,GAAGwO,cAAcxO,GAAG0O;;QAG7ByE,oBAAoBe;QAEpBZ,4BAA4BH,qBAAqBnT,GAAG2J;QAEpDyJ,yBAAyBE,8BAA8BtT,GAAG2K;QAE1D0I,mBAAmBC,6BAA6B8B;QAGhD7B,qBAAqBF,oBAAqB;YACtC,IAAIzJ,QAAQC,SAASC,cAAc;YAEnCF,MAAMrJ,OAAO;YACb,UAAU,sBAAsBqJ,SAASC,SAAShH,iBAAiB,oBAAoB;;QAG3F2Q,mBAAmBF,6BAA6BtT,GAAG0K;QAEnD+I,iBAAiBH,6BAA6BE,oBAAoByB;QAElEvB,yBAAyBJ,6BAA6BiB;QAEtDZ,qBAAqBR,sBAAsBnO,OAAOsQ,gBAAgBnR,aAAamP;QAE/EO,4BAA4BY;QAE5Bb,wBAAwBgB;QAExBd,yBAAyBgB;QAEzBf,0BAA0BgB;QAE1Bf,wBAAwBV,6BAA6BtO,OAAO6G,eAAe1H;QAE3E8P,yBAA0B;YACtB,IAAIX,2BAA2B;gBAC3B,QAAQtT,GAAG2K,mBAAmB3K,GAAG8O;;YAErC,OAAO;;QAGX;YACIyG,eAAejC;YACfkC,eAAepC;YACfqC,kBAAkBnC;YAClBoC,UAAUlC;YACVmC,gBAAgB7B;YAChB8B,mBAAmBhC;YACnBiC,mBAAmBhC;YACnBiC,iBAAiB9Q,OAAO+Q;YACxBC,UAAU3C;YACV4C,YAAY1C;YACZ2C,iBAAiBnC;YACjBoC,eAAenC;YACfoC,iBAAiBpC;YACjBqC,oBAAoB/C;YACpBgD,OAAO9C;YACP+C,aAAatC;YACbuC,QAAQ/C;YACRgD,SAASzC,yBAAyBZ;YAClCsD,cAAc1W,GAAGiO;YACjB0I,2BAA2B3W,GAAG0O;YAC9BkI,WAAWzD;YACX0D,YAAYlD;YACZmD,qBAAqBxD;YACrByD,oBAAoBzD;YACpB0D,gBAAgBtD;;;IChKxB1T,GAAGiX,mBAAmB,SAASC;QAC3B;QACA,UAAUA,gBAAgBA,aAAaC,QAAQnX,GAAG6G,WAAWqQ,aAAaC;;IAG9EnX,GAAG+L,UAAU;QACT;QAEA,IAAIqL,aAAaC,aACbC,uBACAC,uBACAC,oBACAC,QAAQ;QAEZzX,GAAG6B,OAAOxB;YACN8W,MAAM,SAASO,WAAWC;gBACtB,IAAIF,UAAU,GAAG;oBACb,IAAIC,WAAW;wBACXJ,iBAAiBpU,KAAKwU;;oBAE1B,IAAIC,WAAW;wBACXJ,iBAAiBrU,KAAKyU;;uBAGzB,IAAIF,WAAW,GAAG;oBACnBE,aAAaA,UAAUtH,MAAM,MAAMgH;uBAElC,IAAIK,WAAW;oBAChBA,UAAUrH,MAAM,MAAM+G;;gBAG1B,OAAO/W;;YAGXuX,MAAM,SAASnI;gBACX,IAAIgI,UAAU,GAAG;oBACbD,cAActU,KAAKuM;uBAElB;oBACDA,SAASY,MAAM,MAAMgH,gBAAgBlT,YAAYiT,cAAcC;;gBAGnE,OAAOhX;;YAGX4L,SAAS;gBACLwL,QAAQ;gBACRL,cAAcjP;gBAEd,IAAImP,iBAAiBvR,QAAQ;oBACzB/F,GAAG+C,KAAKuU,kBAAkB,SAAStU,KAAKyM;wBACpCA,SAASY,MAAM,MAAM+G;;;gBAI7B,IAAII,cAAczR,QAAQ;oBACtB/F,GAAG+C,KAAKyU,eAAe,SAASxU,KAAKyM;wBACjCA,SAASY,MAAM,MAAM+G;;;gBAI7B,OAAO/W;;YAGX8L,SAAS;gBACLsL,SAAS;gBACTJ,cAAclP;gBAEd,IAAIoP,iBAAiBxR,QAAQ;oBACzB/F,GAAG+C,KAAKwU,kBAAkB,SAASvU,KAAKyM;wBACpCA,SAASY,MAAM,MAAMgH;;;gBAI7B,IAAIG,cAAczR,QAAQ;oBACtB/F,GAAG+C,KAAKyU,eAAe,SAASxU,KAAKyM;wBACjCA,SAASY,MAAM,MAAMgH;;;gBAI7B,OAAOhX;;;;IClFnBL,GAAG6X,cAAc,SAASC;QACtB;QAEA,IAAIC,SACAC,wBAAwB,gBACxBC,yBAAyB,oBACzBC,sBACAC,mBACAC,iBAAiB,IAAIpY,GAAGsS;QAE5ByF;YACIM;YACAC,oBAAoB;YACpBC;gBACIC,YAAY;;YAEhBC,WAAW,IAAIzY,GAAG6X,YAAYY;;QAGlCzY,GAAG6B,OAAOkW,SAASD,GAAG;QAEtB,SAASY,mBAAmBC,OAAOC;YAE/B,IAAIC,eAAe5Q,MAAMvB,UAAUwB,MAAMtB,KAAK+R;YAE9CZ,QAAQU,UAAUK,QAAQ,aAAaH,MAAM5S,SAAS;YACtD6S,eAAeG,aAAa;YAC5BhB,QAAQU,UAAUO,+BAA+BH,cAAcD,eAAeK;;QAGlF,SAASC,iBAAiBC;YACtB,IAAIC,oBAAoB,IAAIpZ,GAAG+L;YAE/B,IAAIoN,MAAM1Q,QAAQ;gBACd0Q,MAAME,KAAK,SAASA;oBAChBA,KAAKC,SAASC,qBAAqBJ;oBACnChB,aAAajV,KAAKmW;oBAClBD,kBAAkBnN;mBAEtB,SAASuN;oBACLzB,QAAQU,UAAUK,QAAQ,sBAAsBK,MAAMM,WAAW,wBAAwBD,UAAUE,OAAO,KAAK;oBAC/GN,kBAAkBjN;;mBAGrB,IAAIgN,MAAMQ,aAAa;gBACxBC,oBAAoBT,OAAOhC,KACvB,SAAS0C,eAAeC;oBACpB,IAAIC,cAAcD,QAAQ/T;oBAE1B/F,GAAG+C,KAAK+W,SAAS,SAAS9W,KAAKmW;wBAC3BD,iBAAiBC,OAAOvB,KAAK;4BACzBmC,eAAe;4BAEf,IAAIA,gBAAgB,GAAG;gCACnBX,kBAAkBnN;;;;oBAK9B,KAAK6N,QAAQ/T,QAAQ;wBACjBqT,kBAAkBnN;;mBAI1B,SAAS+N,YAAYR;oBACjBzB,QAAQU,UAAUK,QAAQ,sBAAsBK,MAAMM,WAAW,wBAAwBD,UAAUE,OAAO,KAAK;oBAC/GN,kBAAkBjN;;;YAK9B,OAAOiN;;QAGX,SAASG,qBAAqBJ;YAC1B,IAAIpX,OAAOoX,MAAMpX,MACb0X,WAAWN,MAAMM,UACjBQ,wBAAwBR,SAASxH,YAAYlQ;YAGjD0X,WAAWA,SAASvH,OAAO,GAAG+H;YAG9B,IAAIR,SAAS1J,OAAO,OAAO,KAAK;gBAC5B0J,WAAWA,SAASvH,OAAO;;YAG/B,OAAOuH;;QAIX,SAASG,oBAAoBT,OAAOe,QAAQC,cAAcC;YACtD,IAAItO,UAAUsO,mBAAmB,IAAIpa,GAAG+L,WACpCsO,YAAYH,UAAUf,MAAMmB;YAEhCD,UAAUE,YACN,SAASC,YAAYV;gBACjB,IAAIW,aAAaN,eAAeA,aAAa/J,OAAO0J,WAAWA;gBAE/D,IAAIA,QAAQ/T,QAAQ;oBAChB2U,WAAW;wBACPd,oBAAoBT,OAAOkB,WAAWI,YAAY3O;uBACnD;uBAEF;oBACDA,QAAQG,QAAQwO;;eAIxB3O,QAAQK;YAGZ,OAAOL;;QAGX,SAAS6O,mBAAmBpQ,cAAcqO;YACtC,IAAIgC,4BACAC,4BAA4B,IAAI7a,GAAG+L;YAEvCgM,QAAQU,UAAUqC;YAClBlC,eAAeG,aAAa;YAE5B,IAAIxO,aAAaoO,MAAM5S,SAAS,MAAMgS,QAAQO,oBAAoB;gBAC9DP,QAAQU,UAAUO;gBAClBjB,QAAQU,UAAUsC,UAAU,qBAAqB;gBACjDnC,eAAeG,aAAa;gBAC5B8B,0BAA0B1O;mBAEzB;gBACDgM;gBAEA,IAAInY,GAAGsK,sBAAsBC,eAAe;oBACxCvK,GAAG+C,KAAKwH,aAAaC,OAAO,SAASxH,KAAKsE;wBACtC,IAAI6R,QAAQ7R,KAAKmD;wBAEjB,IAAI0O,OAAO;4BAEP,IAAIA,MAAM1Q,QAAQ;gCACd0P,aAAajV,KAAKoE,KAAK0T;mCAGtB;gCACDJ,sBAAsB1X,KAAKgW,iBAAiBC,OAAOvB,KAAK;oCACpDgD,sBAAsBK;oCACtB,IAAIL,sBAAsB7U,WAAW,GAAG;wCACpC8U,0BAA0B5O;;;;;;uBAO7C;oBACDkM,eAAe5N,aAAaoO;;gBAGhC,IAAIiC,sBAAsB7U,WAAW,GAAG;oBACpC8U,0BAA0B5O;;;YAIlC,OAAO4O;;QAGX,SAASK,cAAcC;YACnB,IAAIC,WAAW,IAAIpb,GAAGqb;gBAClBrD,uBAAuBA;gBACvB/X,SAASkb;gBACTG,SAAS,SAASpM;oBACdlP,GAAGmb,UAAU9Y,SAAS0V,QAAQQ,QAAQC;oBACtCtJ,EAAEqM;;gBAENC,uBAAuB,SAAStM;oBAC5BlP,GAAGmb,UAAU7Y,YAAYyV,QAAQQ,QAAQC;;gBAE7CiD,QAAQ,SAASvM;oBACbyL,mBAAmBzL,EAAE3E,cAAc6Q,UAAUjE,KACzC;wBACIuB,mBAAmBP,cAAciD;uBAErC;wBACIrD,QAAQU,UAAUK,QAAQ,uEAAuE;;;;YAMjHV,eAAezF,YAAY;gBACvByI,SAAS5I;;YAGbxS,GAAGmb,UAAUrX,aAAamU,2BAA2BjY,GAAGmb,UAAUjb;YAElEgY,gBAAgBhV,KAAKkY;YAErB,OAAOA;;QAGX,SAASM,WAAWC;YAChB,IAAIC;YAEJ5b,GAAG+C,KAAK4Y,UAAUpR,aAAasR,OAAO,SAAShM,KAAK5M;gBAChD,IAAIA,QAAQ,SAAS;oBACjB2Y,WAAW;oBACX,OAAO;;;YAIf,OAAOA;;QAWX,SAASE,mBAAmB5M;YACxB,IAAIlP,GAAGiO,UAAU;gBACb,OAAOiB,EAAE6M,IAAI,KAAK7M,EAAE8M,IAAI;;YAG5B,OAAO9M,EAAE6M,MAAM,KAAK7M,EAAE8M,MAAM;;QAGhC,SAASC;YACL,IAAIC,YAAYnE,QAAQM,kBAEpB8D,qBAAqB;gBACjBzB,WAAW;oBACP1a,GAAG+C,KAAKmZ,WAAW,SAASlZ,KAAKoY;wBAC7Bpb,GAAGob,UAAUtX,aAAamU,2BAA2BjY,GAAGob,UAAUlb;wBAClEF,GAAGob,UAAU9Y,YAAYyV,QAAQQ,QAAQC;;mBAE9C;;YAGXxY,GAAG+C,KAAKmZ,WAAW,SAASlZ,KAAKoY;gBAC7B,IAAIxC,iBAAiBsC,cAAcE;gBAGnC,IAAIc,UAAUnW,UAAU/F,GAAGkT,kBAAkB8C,UAAU;oBACnDoC,eAAe9X,OAAOuJ,UAAU,aAAa,SAASqF;wBAClD,KAAK0J,eAAeG,kBAAkB2C,WAAWxM,IAAI;4BACjDlP,GAAG+C,KAAKmZ,WAAW,SAASlZ,KAAKoY;gCAG7B,IAAIA,oBAAoBgB,eACpBpc,GAAGob,UAAUtX,aAAamU,yBAAyB;oCAEnDjY,GAAGob,UAAU9Z;wCAAKlB,SAAS;;;;;;;;YAQnDgY,eAAe9X,OAAOuJ,UAAU,aAAa,SAASqF;gBAClD,IAAI4M,mBAAmB5M,IAAI;oBACvBiN;;;YAOR/D,eAAe9X,OAAON,GAAG6J,UAAUzG,WAAW,IAAI,cAAc,SAAS8L;gBACrEiN;;YAGJ/D,eAAe9X,OAAOuJ,UAAU,QAAQ,SAASqF;gBAC7C,IAAIwM,WAAWxM,IAAI;oBACfA,EAAED;oBACFkN;;;YAIR/D,eAAe9X,OAAOuJ,UAAUmO,uBAAuBmE;;QAG3DF;QAEAjc,GAAG6B,OAAOxB;YACNgc,oBAAoB,SAASpc;gBACzB8X,QAAQM,iBAAiBnV,KAAKjD;gBAC9Bib,cAAcjb;;YAGlBqc,gBAAgB,SAASrc;gBACrB,IAAI6Q,GACAyL,MAAMxE,QAAQM;gBAElB,KAAKvH,KAAKyL,KAAK;oBACX,IAAIA,IAAIzL,OAAO7Q,SAAS;wBACpB,OAAOsc,IAAIC,OAAO1L,GAAG;;;;YAKjC0B,SAAS;gBACL4F,eAAe5F;gBACfxS,GAAG+C,KAAKmV,iBAAiB,SAASlV,KAAKoY;oBACnCA,SAAS5I;;;;QAKrBnS,KAAKoc;QACLpc,KAAKoc,SAASlD,uBAAuBA;;IAGzCvZ,GAAG6X,YAAYY,YAAY;QACvB;QAEA;YACIqC,wBAAwB;YACxB9B,gCAAgC,SAASL,OAAO+D;YAChD3B,WAAW,SAASrB,MAAMiD;gBACtB3c,GAAGmG,IAAI,6BAA6BuT,OAAO,6BAA6BiD,iBAAiB,KAAK;;YAElG7D,SAAS,SAAS1S,SAASC;gBACvBrG,GAAGmG,IAAIC,SAASC;;;;IAK5BrG,GAAGqb,iBAAiB,SAASvD;QACzB;QAEA,IAAIM,iBAAiB,IAAIpY,GAAGsS,kBACxByF,SAAS9X,SAAS2c,aAAaC;QAEnC9E;YACI9X,SAAS;YACTqb,SAAS,SAASpM;YAClB4N,SAAS,SAAS5N;YAElBsM,uBAAuB,SAAStM;YAChCuM,QAAQ,SAASvM;;QAGrBlP,GAAG6B,OAAOkW,SAASD;QACnB7X,UAAU8X,QAAQ9X;QAElB,SAAS8c;YACL,OAAO/c,GAAGiO,YAAajO,GAAGqO,aAAarO,GAAGsO;;QAG9C,SAAS0O,mBAAmB9N;YAExB,KAAK2N,qBAAqB;gBAGtB,IAAIE,0BAA0B;oBAC1B3E,eAAe9X,OAAOuJ,UAAU,YAAY,SAASqF;wBACjDA,EAAED;;uBAEH;oBACHmJ,eAAe9X,OAAOuJ,UAAU,YAAY,SAASqF;wBACjD,IAAIA,EAAE3E,cAAc;4BAChB2E,EAAE3E,aAAa0S,aAAa;4BAC5B/N,EAAED;;;;gBAKd4N,sBAAsB;;;QAI9B,SAASK,gBAAgBhO;YAGrB,KAAKlP,GAAGkT,kBAAkB8C,UAAU;gBAChC,OAAO;;YAGX,IAAImH,YAAYC,KAAKlO,EAAE3E,cAEvB8S,WAAWrd,GAAGiO;YAMdkP,aAAand,GAAGyN,QAAQzN,GAAGkT,kBAAkB8C,WAAW,OAAOoH,GAAGE,kBAAkB;YACpF,OAAOF,MAAMD,eAEAC,GAAGzE,SAASyE,GAAGzE,MAAM5S,WACpBsX,YAAYD,GAAGvB,MAAM/a,YAAYsc,GAAGvB,MAAM/a,SAAS,YACpDsc,GAAGvB,MAAM0B,YAAYH,GAAGvB,MAAM0B,SAAS;;QAIxD,SAASC,oBAAoBC;YACzB,IAAIA,eAAetZ,WAAW;gBAC1ByY,cAAca;;YAElB,OAAOb;;QAGX,SAASc;YACL,IAAIC;YAEJ,SAASC;gBACLD,iBAAiB9T,SAASgU,YAAY;gBACtCF,eAAeG,UAAU/F,QAAQC,uBAAuB,MAAM;;YAGlE,IAAIhT,OAAO+Y,aAAa;gBACpB;oBACIJ,iBAAiB,IAAII,YAAYhG,QAAQC;kBAE7C,OAAOgG;oBACHJ;;mBAGH;gBACDA;;YAGJ/T,SAASoU,cAAcN;;QAG3B,SAASO;YACL9F,eAAe9X,OAAOL,SAAS,YAAY,SAASiP;gBAChD,KAAKgO,gBAAgBhO,IAAI;oBACrB;;gBAKJ,IAAIiP,SAASne,GAAGyN,QAAQzN,GAAGkT,kBAAkB8C,WAAW,OAAO9G,EAAE3E,aAAa+S;gBAC9E,IAAIa,WAAW,UAAUA,WAAW,YAAY;oBAC5CjP,EAAE3E,aAAa0S,aAAa;uBACzB;oBACH/N,EAAE3E,aAAa0S,aAAa;;gBAGhC/N,EAAEqM;gBACFrM,EAAED;;YAGNmJ,eAAe9X,OAAOL,SAAS,aAAa,SAASiP;gBACjD,KAAKsO,uBAAuB;oBACxB,KAAKN,gBAAgBhO,IAAI;wBACrB;;oBAEJ6I,QAAQuD,QAAQpM;;;YAIxBkJ,eAAe9X,OAAOL,SAAS,aAAa,SAASiP;gBACjD,KAAKgO,gBAAgBhO,IAAI;oBACrB;;gBAGJ6I,QAAQ+E,QAAQ5N;gBAEhB,IAAIkP,gBAAgBvU,SAASwU,iBAAiBnP,EAAEoP,SAASpP,EAAEqP;gBAE3D,IAAIve,GAAGK,MAAMS,SAASsd,gBAAgB;oBAClC;;gBAGJrG,QAAQyD,sBAAsBtM;;YAGlCkJ,eAAe9X,OAAOL,SAAS,QAAQ,SAASiP;gBAC5C,KAAKsO,uBAAuB;oBACxB,KAAKN,gBAAgBhO,IAAI;wBACrB;;oBAGJA,EAAED;oBACFC,EAAEqM;oBACFxD,QAAQ0D,OAAOvM;oBAEfwO;;;;QAKZV;QACAkB;QAEAle,GAAG6B,OAAOxB;YACN0Y,cAAc,SAAS0E;gBACnB,OAAOD,oBAAoBC;;YAG/BjL,SAAS;gBACL4F,eAAe5F;;YAGnByG,YAAY;gBACR,OAAOhZ;;;QAIfI,KAAKoc;QACLpc,KAAKoc,SAASS,kBAAkBA;;GNzfLlY","file":"dnd.js","sourcesContent":[null,"/*globals window, navigator, document, FormData, File, HTMLInputElement, XMLHttpRequest, Blob, Storage, ActiveXObject */\n/* jshint -W079 */\nvar qq = function(element) {\n \"use strict\";\n\n return {\n hide: function() {\n element.style.display = \"none\";\n return this;\n },\n\n /** Returns the function which detaches attached event */\n attach: function(type, fn) {\n if (element.addEventListener) {\n element.addEventListener(type, fn, false);\n } else if (element.attachEvent) {\n element.attachEvent(\"on\" + type, fn);\n }\n return function() {\n qq(element).detach(type, fn);\n };\n },\n\n detach: function(type, fn) {\n if (element.removeEventListener) {\n element.removeEventListener(type, fn, false);\n } else if (element.attachEvent) {\n element.detachEvent(\"on\" + type, fn);\n }\n return this;\n },\n\n contains: function(descendant) {\n // The [W3C spec](http://www.w3.org/TR/domcore/#dom-node-contains)\n // says a `null` (or ostensibly `undefined`) parameter\n // passed into `Node.contains` should result in a false return value.\n // IE7 throws an exception if the parameter is `undefined` though.\n if (!descendant) {\n return false;\n }\n\n // compareposition returns false in this case\n if (element === descendant) {\n return true;\n }\n\n if (element.contains) {\n return element.contains(descendant);\n } else {\n /*jslint bitwise: true*/\n return !!(descendant.compareDocumentPosition(element) & 8);\n }\n },\n\n /**\n * Insert this element before elementB.\n */\n insertBefore: function(elementB) {\n elementB.parentNode.insertBefore(element, elementB);\n return this;\n },\n\n remove: function() {\n element.parentNode.removeChild(element);\n return this;\n },\n\n /**\n * Sets styles for an element.\n * Fixes opacity in IE6-8.\n */\n css: function(styles) {\n /*jshint eqnull: true*/\n if (element.style == null) {\n throw new qq.Error(\"Can't apply style to node as it is not on the HTMLElement prototype chain!\");\n }\n\n /*jshint -W116*/\n if (styles.opacity != null) {\n if (typeof element.style.opacity !== \"string\" && typeof (element.filters) !== \"undefined\") {\n styles.filter = \"alpha(opacity=\" + Math.round(100 * styles.opacity) + \")\";\n }\n }\n qq.extend(element.style, styles);\n\n return this;\n },\n\n hasClass: function(name, considerParent) {\n var re = new RegExp(\"(^| )\" + name + \"( |$)\");\n return re.test(element.className) || !!(considerParent && re.test(element.parentNode.className));\n },\n\n addClass: function(name) {\n if (!qq(element).hasClass(name)) {\n element.className += \" \" + name;\n }\n return this;\n },\n\n removeClass: function(name) {\n var re = new RegExp(\"(^| )\" + name + \"( |$)\");\n element.className = element.className.replace(re, \" \").replace(/^\\s+|\\s+$/g, \"\");\n return this;\n },\n\n getByClass: function(className, first) {\n var candidates,\n result = [];\n\n if (first && element.querySelector) {\n return element.querySelector(\".\" + className);\n }\n else if (element.querySelectorAll) {\n return element.querySelectorAll(\".\" + className);\n }\n\n candidates = element.getElementsByTagName(\"*\");\n\n qq.each(candidates, function(idx, val) {\n if (qq(val).hasClass(className)) {\n result.push(val);\n }\n });\n return first ? result[0] : result;\n },\n\n getFirstByClass: function(className) {\n return qq(element).getByClass(className, true);\n },\n\n children: function() {\n var children = [],\n child = element.firstChild;\n\n while (child) {\n if (child.nodeType === 1) {\n children.push(child);\n }\n child = child.nextSibling;\n }\n\n return children;\n },\n\n setText: function(text) {\n element.innerText = text;\n element.textContent = text;\n return this;\n },\n\n clearText: function() {\n return qq(element).setText(\"\");\n },\n\n // Returns true if the attribute exists on the element\n // AND the value of the attribute is NOT \"false\" (case-insensitive)\n hasAttribute: function(attrName) {\n var attrVal;\n\n if (element.hasAttribute) {\n\n if (!element.hasAttribute(attrName)) {\n return false;\n }\n\n /*jshint -W116*/\n return (/^false$/i).exec(element.getAttribute(attrName)) == null;\n }\n else {\n attrVal = element[attrName];\n\n if (attrVal === undefined) {\n return false;\n }\n\n /*jshint -W116*/\n return (/^false$/i).exec(attrVal) == null;\n }\n }\n };\n};\n\n(function() {\n \"use strict\";\n\n qq.canvasToBlob = function(canvas, mime, quality) {\n return qq.dataUriToBlob(canvas.toDataURL(mime, quality));\n };\n\n qq.dataUriToBlob = function(dataUri) {\n var arrayBuffer, byteString,\n createBlob = function(data, mime) {\n var BlobBuilder = window.BlobBuilder ||\n window.WebKitBlobBuilder ||\n window.MozBlobBuilder ||\n window.MSBlobBuilder,\n blobBuilder = BlobBuilder && new BlobBuilder();\n\n if (blobBuilder) {\n blobBuilder.append(data);\n return blobBuilder.getBlob(mime);\n }\n else {\n return new Blob([data], {type: mime});\n }\n },\n intArray, mimeString;\n\n // convert base64 to raw binary data held in a string\n if (dataUri.split(\",\")[0].indexOf(\"base64\") >= 0) {\n byteString = atob(dataUri.split(\",\")[1]);\n }\n else {\n byteString = decodeURI(dataUri.split(\",\")[1]);\n }\n\n // extract the MIME\n mimeString = dataUri.split(\",\")[0]\n .split(\":\")[1]\n .split(\";\")[0];\n\n // write the bytes of the binary string to an ArrayBuffer\n arrayBuffer = new ArrayBuffer(byteString.length);\n intArray = new Uint8Array(arrayBuffer);\n qq.each(byteString, function(idx, character) {\n intArray[idx] = character.charCodeAt(0);\n });\n\n return createBlob(arrayBuffer, mimeString);\n };\n\n qq.log = function(message, level) {\n if (window.console) {\n if (!level || level === \"info\") {\n window.console.log(message);\n }\n else\n {\n if (window.console[level]) {\n window.console[level](message);\n }\n else {\n window.console.log(\"<\" + level + \"> \" + message);\n }\n }\n }\n };\n\n qq.isObject = function(variable) {\n return variable && !variable.nodeType && Object.prototype.toString.call(variable) === \"[object Object]\";\n };\n\n qq.isFunction = function(variable) {\n return typeof (variable) === \"function\";\n };\n\n /**\n * Check the type of a value. Is it an \"array\"?\n *\n * @param value value to test.\n * @returns true if the value is an array or associated with an `ArrayBuffer`\n */\n qq.isArray = function(value) {\n return Object.prototype.toString.call(value) === \"[object Array]\" ||\n (value && window.ArrayBuffer && value.buffer && value.buffer.constructor === ArrayBuffer);\n };\n\n // Looks for an object on a `DataTransfer` object that is associated with drop events when utilizing the Filesystem API.\n qq.isItemList = function(maybeItemList) {\n return Object.prototype.toString.call(maybeItemList) === \"[object DataTransferItemList]\";\n };\n\n // Looks for an object on a `NodeList` or an `HTMLCollection`|`HTMLFormElement`|`HTMLSelectElement`\n // object that is associated with collections of Nodes.\n qq.isNodeList = function(maybeNodeList) {\n return Object.prototype.toString.call(maybeNodeList) === \"[object NodeList]\" ||\n // If `HTMLCollection` is the actual type of the object, we must determine this\n // by checking for expected properties/methods on the object\n (maybeNodeList.item && maybeNodeList.namedItem);\n };\n\n qq.isString = function(maybeString) {\n return Object.prototype.toString.call(maybeString) === \"[object String]\";\n };\n\n qq.trimStr = function(string) {\n if (String.prototype.trim) {\n return string.trim();\n }\n\n return string.replace(/^\\s+|\\s+$/g, \"\");\n };\n\n /**\n * @param str String to format.\n * @returns {string} A string, swapping argument values with the associated occurrence of {} in the passed string.\n */\n qq.format = function(str) {\n\n var args = Array.prototype.slice.call(arguments, 1),\n newStr = str,\n nextIdxToReplace = newStr.indexOf(\"{}\");\n\n qq.each(args, function(idx, val) {\n var strBefore = newStr.substring(0, nextIdxToReplace),\n strAfter = newStr.substring(nextIdxToReplace + 2);\n\n newStr = strBefore + val + strAfter;\n nextIdxToReplace = newStr.indexOf(\"{}\", nextIdxToReplace + val.length);\n\n // End the loop if we have run out of tokens (when the arguments exceed the # of tokens)\n if (nextIdxToReplace < 0) {\n return false;\n }\n });\n\n return newStr;\n };\n\n qq.isFile = function(maybeFile) {\n return window.File && Object.prototype.toString.call(maybeFile) === \"[object File]\";\n };\n\n qq.isFileList = function(maybeFileList) {\n return window.FileList && Object.prototype.toString.call(maybeFileList) === \"[object FileList]\";\n };\n\n qq.isFileOrInput = function(maybeFileOrInput) {\n return qq.isFile(maybeFileOrInput) || qq.isInput(maybeFileOrInput);\n };\n\n qq.isInput = function(maybeInput, notFile) {\n var evaluateType = function(type) {\n var normalizedType = type.toLowerCase();\n\n if (notFile) {\n return normalizedType !== \"file\";\n }\n\n return normalizedType === \"file\";\n };\n\n if (window.HTMLInputElement) {\n if (Object.prototype.toString.call(maybeInput) === \"[object HTMLInputElement]\") {\n if (maybeInput.type && evaluateType(maybeInput.type)) {\n return true;\n }\n }\n }\n if (maybeInput.tagName) {\n if (maybeInput.tagName.toLowerCase() === \"input\") {\n if (maybeInput.type && evaluateType(maybeInput.type)) {\n return true;\n }\n }\n }\n\n return false;\n };\n\n qq.isBlob = function(maybeBlob) {\n if (window.Blob && Object.prototype.toString.call(maybeBlob) === \"[object Blob]\") {\n return true;\n }\n };\n\n qq.isXhrUploadSupported = function() {\n var input = document.createElement(\"input\");\n input.type = \"file\";\n\n return (\n input.multiple !== undefined &&\n typeof File !== \"undefined\" &&\n typeof FormData !== \"undefined\" &&\n typeof (qq.createXhrInstance()).upload !== \"undefined\");\n };\n\n // Fall back to ActiveX is native XHR is disabled (possible in any version of IE).\n qq.createXhrInstance = function() {\n if (window.XMLHttpRequest) {\n return new XMLHttpRequest();\n }\n\n try {\n return new ActiveXObject(\"MSXML2.XMLHTTP.3.0\");\n }\n catch (error) {\n qq.log(\"Neither XHR or ActiveX are supported!\", \"error\");\n return null;\n }\n };\n\n qq.isFolderDropSupported = function(dataTransfer) {\n return dataTransfer.items &&\n dataTransfer.items.length > 0 &&\n dataTransfer.items[0].webkitGetAsEntry;\n };\n\n qq.isFileChunkingSupported = function() {\n return !qq.androidStock() && //Android's stock browser cannot upload Blobs correctly\n qq.isXhrUploadSupported() &&\n (File.prototype.slice !== undefined || File.prototype.webkitSlice !== undefined || File.prototype.mozSlice !== undefined);\n };\n\n qq.sliceBlob = function(fileOrBlob, start, end) {\n var slicer = fileOrBlob.slice || fileOrBlob.mozSlice || fileOrBlob.webkitSlice;\n\n return slicer.call(fileOrBlob, start, end);\n };\n\n qq.arrayBufferToHex = function(buffer) {\n var bytesAsHex = \"\",\n bytes = new Uint8Array(buffer);\n\n qq.each(bytes, function(idx, byt) {\n var byteAsHexStr = byt.toString(16);\n\n if (byteAsHexStr.length < 2) {\n byteAsHexStr = \"0\" + byteAsHexStr;\n }\n\n bytesAsHex += byteAsHexStr;\n });\n\n return bytesAsHex;\n };\n\n qq.readBlobToHex = function(blob, startOffset, length) {\n var initialBlob = qq.sliceBlob(blob, startOffset, startOffset + length),\n fileReader = new FileReader(),\n promise = new qq.Promise();\n\n fileReader.onload = function() {\n promise.success(qq.arrayBufferToHex(fileReader.result));\n };\n\n fileReader.onerror = promise.failure;\n\n fileReader.readAsArrayBuffer(initialBlob);\n\n return promise;\n };\n\n qq.extend = function(first, second, extendNested) {\n qq.each(second, function(prop, val) {\n if (extendNested && qq.isObject(val)) {\n if (first[prop] === undefined) {\n first[prop] = {};\n }\n qq.extend(first[prop], val, true);\n }\n else {\n first[prop] = val;\n }\n });\n\n return first;\n };\n\n /**\n * Allow properties in one object to override properties in another,\n * keeping track of the original values from the target object.\n *\n * Note that the pre-overriden properties to be overriden by the source will be passed into the `sourceFn` when it is invoked.\n *\n * @param target Update properties in this object from some source\n * @param sourceFn A function that, when invoked, will return properties that will replace properties with the same name in the target.\n * @returns {object} The target object\n */\n qq.override = function(target, sourceFn) {\n var super_ = {},\n source = sourceFn(super_);\n\n qq.each(source, function(srcPropName, srcPropVal) {\n if (target[srcPropName] !== undefined) {\n super_[srcPropName] = target[srcPropName];\n }\n\n target[srcPropName] = srcPropVal;\n });\n\n return target;\n };\n\n /**\n * Searches for a given element (elt) in the array, returns -1 if it is not present.\n */\n qq.indexOf = function(arr, elt, from) {\n if (arr.indexOf) {\n return arr.indexOf(elt, from);\n }\n\n from = from || 0;\n var len = arr.length;\n\n if (from < 0) {\n from += len;\n }\n\n for (; from < len; from += 1) {\n if (arr.hasOwnProperty(from) && arr[from] === elt) {\n return from;\n }\n }\n return -1;\n };\n\n //this is a version 4 UUID\n qq.getUniqueId = function() {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, function(c) {\n /*jslint eqeq: true, bitwise: true*/\n var r = Math.random() * 16 | 0, v = c == \"x\" ? r : (r & 0x3 | 0x8);\n return v.toString(16);\n });\n };\n\n //\n // Browsers and platforms detection\n qq.ie = function() {\n return navigator.userAgent.indexOf(\"MSIE\") !== -1 ||\n navigator.userAgent.indexOf(\"Trident\") !== -1;\n };\n\n qq.ie7 = function() {\n return navigator.userAgent.indexOf(\"MSIE 7\") !== -1;\n };\n\n qq.ie8 = function() {\n return navigator.userAgent.indexOf(\"MSIE 8\") !== -1;\n };\n\n qq.ie10 = function() {\n return navigator.userAgent.indexOf(\"MSIE 10\") !== -1;\n };\n\n qq.ie11 = function() {\n return qq.ie() && navigator.userAgent.indexOf(\"rv:11\") !== -1;\n };\n\n qq.edge = function() {\n return navigator.userAgent.indexOf(\"Edge\") >= 0;\n };\n\n qq.safari = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Apple\") !== -1;\n };\n\n qq.chrome = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Google\") !== -1;\n };\n\n qq.opera = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Opera\") !== -1;\n };\n\n qq.firefox = function() {\n return (!qq.edge() && !qq.ie11() && navigator.userAgent.indexOf(\"Mozilla\") !== -1 && navigator.vendor !== undefined && navigator.vendor === \"\");\n };\n\n qq.windows = function() {\n return navigator.platform === \"Win32\";\n };\n\n qq.android = function() {\n return navigator.userAgent.toLowerCase().indexOf(\"android\") !== -1;\n };\n\n // We need to identify the Android stock browser via the UA string to work around various bugs in this browser,\n // such as the one that prevents a `Blob` from being uploaded.\n qq.androidStock = function() {\n return qq.android() && navigator.userAgent.toLowerCase().indexOf(\"chrome\") < 0;\n };\n\n qq.ios6 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 6_\") !== -1;\n };\n\n qq.ios7 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 7_\") !== -1;\n };\n\n qq.ios8 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 8_\") !== -1;\n };\n\n // iOS 8.0.0\n qq.ios800 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 8_0 \") !== -1;\n };\n\n qq.ios = function() {\n /*jshint -W014 */\n return navigator.userAgent.indexOf(\"iPad\") !== -1\n || navigator.userAgent.indexOf(\"iPod\") !== -1\n || navigator.userAgent.indexOf(\"iPhone\") !== -1;\n };\n\n qq.iosChrome = function() {\n return qq.ios() && navigator.userAgent.indexOf(\"CriOS\") !== -1;\n };\n\n qq.iosSafari = function() {\n return qq.ios() && !qq.iosChrome() && navigator.userAgent.indexOf(\"Safari\") !== -1;\n };\n\n qq.iosSafariWebView = function() {\n return qq.ios() && !qq.iosChrome() && !qq.iosSafari();\n };\n\n //\n // Events\n\n qq.preventDefault = function(e) {\n if (e.preventDefault) {\n e.preventDefault();\n } else {\n e.returnValue = false;\n }\n };\n\n /**\n * Creates and returns element from html string\n * Uses innerHTML to create an element\n */\n qq.toElement = (function() {\n var div = document.createElement(\"div\");\n return function(html) {\n div.innerHTML = html;\n var element = div.firstChild;\n div.removeChild(element);\n return element;\n };\n }());\n\n //key and value are passed to callback for each entry in the iterable item\n qq.each = function(iterableItem, callback) {\n var keyOrIndex, retVal;\n\n if (iterableItem) {\n // Iterate through [`Storage`](http://www.w3.org/TR/webstorage/#the-storage-interface) items\n if (window.Storage && iterableItem.constructor === window.Storage) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(iterableItem.key(keyOrIndex), iterableItem.getItem(iterableItem.key(keyOrIndex)));\n if (retVal === false) {\n break;\n }\n }\n }\n // `DataTransferItemList` & `NodeList` objects are array-like and should be treated as arrays\n // when iterating over items inside the object.\n else if (qq.isArray(iterableItem) || qq.isItemList(iterableItem) || qq.isNodeList(iterableItem)) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);\n if (retVal === false) {\n break;\n }\n }\n }\n else if (qq.isString(iterableItem)) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(keyOrIndex, iterableItem.charAt(keyOrIndex));\n if (retVal === false) {\n break;\n }\n }\n }\n else {\n for (keyOrIndex in iterableItem) {\n if (Object.prototype.hasOwnProperty.call(iterableItem, keyOrIndex)) {\n retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);\n if (retVal === false) {\n break;\n }\n }\n }\n }\n }\n };\n\n //include any args that should be passed to the new function after the context arg\n qq.bind = function(oldFunc, context) {\n if (qq.isFunction(oldFunc)) {\n var args = Array.prototype.slice.call(arguments, 2);\n\n return function() {\n var newArgs = qq.extend([], args);\n if (arguments.length) {\n newArgs = newArgs.concat(Array.prototype.slice.call(arguments));\n }\n return oldFunc.apply(context, newArgs);\n };\n }\n\n throw new Error(\"first parameter must be a function!\");\n };\n\n /**\n * obj2url() takes a json-object as argument and generates\n * a querystring. pretty much like jQuery.param()\n *\n * how to use:\n *\n * `qq.obj2url({a:'b',c:'d'},'http://any.url/upload?otherParam=value');`\n *\n * will result in:\n *\n * `http://any.url/upload?otherParam=value&a=b&c=d`\n *\n * @param Object JSON-Object\n * @param String current querystring-part\n * @return String encoded querystring\n */\n qq.obj2url = function(obj, temp, prefixDone) {\n /*jshint laxbreak: true*/\n var uristrings = [],\n prefix = \"&\",\n add = function(nextObj, i) {\n var nextTemp = temp\n ? (/\\[\\]$/.test(temp)) // prevent double-encoding\n ? temp\n : temp + \"[\" + i + \"]\"\n : i;\n if ((nextTemp !== \"undefined\") && (i !== \"undefined\")) {\n uristrings.push(\n (typeof nextObj === \"object\")\n ? qq.obj2url(nextObj, nextTemp, true)\n : (Object.prototype.toString.call(nextObj) === \"[object Function]\")\n ? encodeURIComponent(nextTemp) + \"=\" + encodeURIComponent(nextObj())\n : encodeURIComponent(nextTemp) + \"=\" + encodeURIComponent(nextObj)\n );\n }\n };\n\n if (!prefixDone && temp) {\n prefix = (/\\?/.test(temp)) ? (/\\?$/.test(temp)) ? \"\" : \"&\" : \"?\";\n uristrings.push(temp);\n uristrings.push(qq.obj2url(obj));\n } else if ((Object.prototype.toString.call(obj) === \"[object Array]\") && (typeof obj !== \"undefined\")) {\n qq.each(obj, function(idx, val) {\n add(val, idx);\n });\n } else if ((typeof obj !== \"undefined\") && (obj !== null) && (typeof obj === \"object\")) {\n qq.each(obj, function(prop, val) {\n add(val, prop);\n });\n } else {\n uristrings.push(encodeURIComponent(temp) + \"=\" + encodeURIComponent(obj));\n }\n\n if (temp) {\n return uristrings.join(prefix);\n } else {\n return uristrings.join(prefix)\n .replace(/^&/, \"\")\n .replace(/%20/g, \"+\");\n }\n };\n\n qq.obj2FormData = function(obj, formData, arrayKeyName) {\n if (!formData) {\n formData = new FormData();\n }\n\n qq.each(obj, function(key, val) {\n key = arrayKeyName ? arrayKeyName + \"[\" + key + \"]\" : key;\n\n if (qq.isObject(val)) {\n qq.obj2FormData(val, formData, key);\n }\n else if (qq.isFunction(val)) {\n formData.append(key, val());\n }\n else {\n formData.append(key, val);\n }\n });\n\n return formData;\n };\n\n qq.obj2Inputs = function(obj, form) {\n var input;\n\n if (!form) {\n form = document.createElement(\"form\");\n }\n\n qq.obj2FormData(obj, {\n append: function(key, val) {\n input = document.createElement(\"input\");\n input.setAttribute(\"name\", key);\n input.setAttribute(\"value\", val);\n form.appendChild(input);\n }\n });\n\n return form;\n };\n\n /**\n * Not recommended for use outside of Fine Uploader since this falls back to an unchecked eval if JSON.parse is not\n * implemented. For a more secure JSON.parse polyfill, use Douglas Crockford's json2.js.\n */\n qq.parseJson = function(json) {\n /*jshint evil: true*/\n if (window.JSON && qq.isFunction(JSON.parse)) {\n return JSON.parse(json);\n } else {\n return eval(\"(\" + json + \")\");\n }\n };\n\n /**\n * Retrieve the extension of a file, if it exists.\n *\n * @param filename\n * @returns {string || undefined}\n */\n qq.getExtension = function(filename) {\n var extIdx = filename.lastIndexOf(\".\") + 1;\n\n if (extIdx > 0) {\n return filename.substr(extIdx, filename.length - extIdx);\n }\n };\n\n qq.getFilename = function(blobOrFileInput) {\n /*jslint regexp: true*/\n\n if (qq.isInput(blobOrFileInput)) {\n // get input value and remove path to normalize\n return blobOrFileInput.value.replace(/.*(\\/|\\\\)/, \"\");\n }\n else if (qq.isFile(blobOrFileInput)) {\n if (blobOrFileInput.fileName !== null && blobOrFileInput.fileName !== undefined) {\n return blobOrFileInput.fileName;\n }\n }\n\n return blobOrFileInput.name;\n };\n\n /**\n * A generic module which supports object disposing in dispose() method.\n * */\n qq.DisposeSupport = function() {\n var disposers = [];\n\n return {\n /** Run all registered disposers */\n dispose: function() {\n var disposer;\n do {\n disposer = disposers.shift();\n if (disposer) {\n disposer();\n }\n }\n while (disposer);\n },\n\n /** Attach event handler and register de-attacher as a disposer */\n attach: function() {\n var args = arguments;\n /*jslint undef:true*/\n this.addDisposer(qq(args[0]).attach.apply(this, Array.prototype.slice.call(arguments, 1)));\n },\n\n /** Add disposer to the collection */\n addDisposer: function(disposeFunction) {\n disposers.push(disposeFunction);\n }\n };\n };\n}());\n","/* globals define, module, global, qq */\n(function() {\n \"use strict\";\n if (typeof define === \"function\" && define.amd) {\n define(function() {\n return qq;\n });\n }\n else if (typeof module !== \"undefined\" && module.exports) {\n module.exports = qq;\n }\n else {\n global.qq = qq;\n }\n}());\n","/*global qq */\nqq.version = \"5.16.2\";\n","/* globals qq */\nqq.supportedFeatures = (function() {\n \"use strict\";\n\n var supportsUploading,\n supportsUploadingBlobs,\n supportsFileDrop,\n supportsAjaxFileUploading,\n supportsFolderDrop,\n supportsChunking,\n supportsResume,\n supportsUploadViaPaste,\n supportsUploadCors,\n supportsDeleteFileXdr,\n supportsDeleteFileCorsXhr,\n supportsDeleteFileCors,\n supportsFolderSelection,\n supportsImagePreviews,\n supportsUploadProgress;\n\n function testSupportsFileInputElement() {\n var supported = true,\n tempInput;\n\n try {\n tempInput = document.createElement(\"input\");\n tempInput.type = \"file\";\n qq(tempInput).hide();\n\n if (tempInput.disabled) {\n supported = false;\n }\n }\n catch (ex) {\n supported = false;\n }\n\n return supported;\n }\n\n //only way to test for complete Clipboard API support at this time\n function isChrome14OrHigher() {\n return (qq.chrome() || qq.opera()) &&\n navigator.userAgent.match(/Chrome\\/[1][4-9]|Chrome\\/[2-9][0-9]/) !== undefined;\n }\n\n //Ensure we can send cross-origin `XMLHttpRequest`s\n function isCrossOriginXhrSupported() {\n if (window.XMLHttpRequest) {\n var xhr = qq.createXhrInstance();\n\n //Commonly accepted test for XHR CORS support.\n return xhr.withCredentials !== undefined;\n }\n\n return false;\n }\n\n //Test for (terrible) cross-origin ajax transport fallback for IE9 and IE8\n function isXdrSupported() {\n return window.XDomainRequest !== undefined;\n }\n\n // CORS Ajax requests are supported if it is either possible to send credentialed `XMLHttpRequest`s,\n // or if `XDomainRequest` is an available alternative.\n function isCrossOriginAjaxSupported() {\n if (isCrossOriginXhrSupported()) {\n return true;\n }\n\n return isXdrSupported();\n }\n\n function isFolderSelectionSupported() {\n // We know that folder selection is only supported in Chrome via this proprietary attribute for now\n return document.createElement(\"input\").webkitdirectory !== undefined;\n }\n\n function isLocalStorageSupported() {\n try {\n return !!window.localStorage &&\n // unpatched versions of IE10/11 have buggy impls of localStorage where setItem is a string\n qq.isFunction(window.localStorage.setItem);\n }\n catch (error) {\n // probably caught a security exception, so no localStorage for you\n return false;\n }\n }\n\n function isDragAndDropSupported() {\n var span = document.createElement(\"span\");\n\n return (\"draggable\" in span || (\"ondragstart\" in span && \"ondrop\" in span)) &&\n !qq.android() && !qq.ios();\n }\n\n supportsUploading = testSupportsFileInputElement();\n\n supportsAjaxFileUploading = supportsUploading && qq.isXhrUploadSupported();\n\n supportsUploadingBlobs = supportsAjaxFileUploading && !qq.androidStock();\n\n supportsFileDrop = supportsAjaxFileUploading && isDragAndDropSupported();\n\n // adapted from https://stackoverflow.com/a/23278460/486979\n supportsFolderDrop = supportsFileDrop && (function() {\n var input = document.createElement(\"input\");\n\n input.type = \"file\";\n return !!(\"webkitdirectory\" in (input || document.querySelectorAll(\"input[type=file]\")[0]));\n }());\n\n supportsChunking = supportsAjaxFileUploading && qq.isFileChunkingSupported();\n\n supportsResume = supportsAjaxFileUploading && supportsChunking && isLocalStorageSupported();\n\n supportsUploadViaPaste = supportsAjaxFileUploading && isChrome14OrHigher();\n\n supportsUploadCors = supportsUploading && (window.postMessage !== undefined || supportsAjaxFileUploading);\n\n supportsDeleteFileCorsXhr = isCrossOriginXhrSupported();\n\n supportsDeleteFileXdr = isXdrSupported();\n\n supportsDeleteFileCors = isCrossOriginAjaxSupported();\n\n supportsFolderSelection = isFolderSelectionSupported();\n\n supportsImagePreviews = supportsAjaxFileUploading && window.FileReader !== undefined;\n\n supportsUploadProgress = (function() {\n if (supportsAjaxFileUploading) {\n return !qq.androidStock() && !qq.iosChrome();\n }\n return false;\n }());\n\n return {\n ajaxUploading: supportsAjaxFileUploading,\n blobUploading: supportsUploadingBlobs,\n canDetermineSize: supportsAjaxFileUploading,\n chunking: supportsChunking,\n deleteFileCors: supportsDeleteFileCors,\n deleteFileCorsXdr: supportsDeleteFileXdr, //NOTE: will also return true in IE10, where XDR is also supported\n deleteFileCorsXhr: supportsDeleteFileCorsXhr,\n dialogElement: !!window.HTMLDialogElement,\n fileDrop: supportsFileDrop,\n folderDrop: supportsFolderDrop,\n folderSelection: supportsFolderSelection,\n imagePreviews: supportsImagePreviews,\n imageValidation: supportsImagePreviews,\n itemSizeValidation: supportsAjaxFileUploading,\n pause: supportsChunking,\n progressBar: supportsUploadProgress,\n resume: supportsResume,\n scaling: supportsImagePreviews && supportsUploadingBlobs,\n tiffPreviews: qq.safari(), // Not the best solution, but simple and probably accurate enough (for now)\n unlimitedScaledImageSize: !qq.ios(), // false simply indicates that there is some known limit\n uploading: supportsUploading,\n uploadCors: supportsUploadCors,\n uploadCustomHeaders: supportsAjaxFileUploading,\n uploadNonMultipart: supportsAjaxFileUploading,\n uploadViaPaste: supportsUploadViaPaste\n };\n\n}());\n","/*globals qq*/\n\n// Is the passed object a promise instance?\nqq.isGenericPromise = function(maybePromise) {\n \"use strict\";\n return !!(maybePromise && maybePromise.then && qq.isFunction(maybePromise.then));\n};\n\nqq.Promise = function() {\n \"use strict\";\n\n var successArgs, failureArgs,\n successCallbacks = [],\n failureCallbacks = [],\n doneCallbacks = [],\n state = 0;\n\n qq.extend(this, {\n then: function(onSuccess, onFailure) {\n if (state === 0) {\n if (onSuccess) {\n successCallbacks.push(onSuccess);\n }\n if (onFailure) {\n failureCallbacks.push(onFailure);\n }\n }\n else if (state === -1) {\n onFailure && onFailure.apply(null, failureArgs);\n }\n else if (onSuccess) {\n onSuccess.apply(null, successArgs);\n }\n\n return this;\n },\n\n done: function(callback) {\n if (state === 0) {\n doneCallbacks.push(callback);\n }\n else {\n callback.apply(null, failureArgs === undefined ? successArgs : failureArgs);\n }\n\n return this;\n },\n\n success: function() {\n state = 1;\n successArgs = arguments;\n\n if (successCallbacks.length) {\n qq.each(successCallbacks, function(idx, callback) {\n callback.apply(null, successArgs);\n });\n }\n\n if (doneCallbacks.length) {\n qq.each(doneCallbacks, function(idx, callback) {\n callback.apply(null, successArgs);\n });\n }\n\n return this;\n },\n\n failure: function() {\n state = -1;\n failureArgs = arguments;\n\n if (failureCallbacks.length) {\n qq.each(failureCallbacks, function(idx, callback) {\n callback.apply(null, failureArgs);\n });\n }\n\n if (doneCallbacks.length) {\n qq.each(doneCallbacks, function(idx, callback) {\n callback.apply(null, failureArgs);\n });\n }\n\n return this;\n }\n });\n};\n","/*globals qq, document, CustomEvent*/\nqq.DragAndDrop = function(o) {\n \"use strict\";\n\n var options,\n HIDE_ZONES_EVENT_NAME = \"qq-hidezones\",\n HIDE_BEFORE_ENTER_ATTR = \"qq-hide-dropzone\",\n uploadDropZones = [],\n droppedFiles = [],\n disposeSupport = new qq.DisposeSupport();\n\n options = {\n dropZoneElements: [],\n allowMultipleItems: true,\n classes: {\n dropActive: null\n },\n callbacks: new qq.DragAndDrop.callbacks()\n };\n\n qq.extend(options, o, true);\n\n function uploadDroppedFiles(files, uploadDropZone) {\n // We need to convert the `FileList` to an actual `Array` to avoid iteration issues\n var filesAsArray = Array.prototype.slice.call(files);\n\n options.callbacks.dropLog(\"Grabbed \" + files.length + \" dropped files.\");\n uploadDropZone.dropDisabled(false);\n options.callbacks.processingDroppedFilesComplete(filesAsArray, uploadDropZone.getElement());\n }\n\n function traverseFileTree(entry) {\n var parseEntryPromise = new qq.Promise();\n\n if (entry.isFile) {\n entry.file(function(file) {\n file.qqPath = extractDirectoryPath(entry);\n droppedFiles.push(file);\n parseEntryPromise.success();\n },\n function(fileError) {\n options.callbacks.dropLog(\"Problem parsing '\" + entry.fullPath + \"'. FileError code \" + fileError.code + \".\", \"error\");\n parseEntryPromise.failure();\n });\n }\n else if (entry.isDirectory) {\n getFilesInDirectory(entry).then(\n function allEntriesRead(entries) {\n var entriesLeft = entries.length;\n\n qq.each(entries, function(idx, entry) {\n traverseFileTree(entry).done(function() {\n entriesLeft -= 1;\n\n if (entriesLeft === 0) {\n parseEntryPromise.success();\n }\n });\n });\n\n if (!entries.length) {\n parseEntryPromise.success();\n }\n },\n\n function readFailure(fileError) {\n options.callbacks.dropLog(\"Problem parsing '\" + entry.fullPath + \"'. FileError code \" + fileError.code + \".\", \"error\");\n parseEntryPromise.failure();\n }\n );\n }\n\n return parseEntryPromise;\n }\n\n function extractDirectoryPath(entry) {\n var name = entry.name,\n fullPath = entry.fullPath,\n indexOfNameInFullPath = fullPath.lastIndexOf(name);\n\n // remove file name from full path string\n fullPath = fullPath.substr(0, indexOfNameInFullPath);\n\n // remove leading slash in full path string\n if (fullPath.charAt(0) === \"/\") {\n fullPath = fullPath.substr(1);\n }\n\n return fullPath;\n }\n\n // Promissory. Guaranteed to read all files in the root of the passed directory.\n function getFilesInDirectory(entry, reader, accumEntries, existingPromise) {\n var promise = existingPromise || new qq.Promise(),\n dirReader = reader || entry.createReader();\n\n dirReader.readEntries(\n function readSuccess(entries) {\n var newEntries = accumEntries ? accumEntries.concat(entries) : entries;\n\n if (entries.length) {\n setTimeout(function() { // prevent stack overflow, however unlikely\n getFilesInDirectory(entry, dirReader, newEntries, promise);\n }, 0);\n }\n else {\n promise.success(newEntries);\n }\n },\n\n promise.failure\n );\n\n return promise;\n }\n\n function handleDataTransfer(dataTransfer, uploadDropZone) {\n var pendingFolderPromises = [],\n handleDataTransferPromise = new qq.Promise();\n\n options.callbacks.processingDroppedFiles();\n uploadDropZone.dropDisabled(true);\n\n if (dataTransfer.files.length > 1 && !options.allowMultipleItems) {\n options.callbacks.processingDroppedFilesComplete([]);\n options.callbacks.dropError(\"tooManyFilesError\", \"\");\n uploadDropZone.dropDisabled(false);\n handleDataTransferPromise.failure();\n }\n else {\n droppedFiles = [];\n\n if (qq.isFolderDropSupported(dataTransfer)) {\n qq.each(dataTransfer.items, function(idx, item) {\n var entry = item.webkitGetAsEntry();\n\n if (entry) {\n //due to a bug in Chrome's File System API impl - #149735\n if (entry.isFile) {\n droppedFiles.push(item.getAsFile());\n }\n\n else {\n pendingFolderPromises.push(traverseFileTree(entry).done(function() {\n pendingFolderPromises.pop();\n if (pendingFolderPromises.length === 0) {\n handleDataTransferPromise.success();\n }\n }));\n }\n }\n });\n }\n else {\n droppedFiles = dataTransfer.files;\n }\n\n if (pendingFolderPromises.length === 0) {\n handleDataTransferPromise.success();\n }\n }\n\n return handleDataTransferPromise;\n }\n\n function setupDropzone(dropArea) {\n var dropZone = new qq.UploadDropZone({\n HIDE_ZONES_EVENT_NAME: HIDE_ZONES_EVENT_NAME,\n element: dropArea,\n onEnter: function(e) {\n qq(dropArea).addClass(options.classes.dropActive);\n e.stopPropagation();\n },\n onLeaveNotDescendants: function(e) {\n qq(dropArea).removeClass(options.classes.dropActive);\n },\n onDrop: function(e) {\n handleDataTransfer(e.dataTransfer, dropZone).then(\n function() {\n uploadDroppedFiles(droppedFiles, dropZone);\n },\n function() {\n options.callbacks.dropLog(\"Drop event DataTransfer parsing failed. No files will be uploaded.\", \"error\");\n }\n );\n }\n });\n\n disposeSupport.addDisposer(function() {\n dropZone.dispose();\n });\n\n qq(dropArea).hasAttribute(HIDE_BEFORE_ENTER_ATTR) && qq(dropArea).hide();\n\n uploadDropZones.push(dropZone);\n\n return dropZone;\n }\n\n function isFileDrag(dragEvent) {\n var fileDrag;\n\n qq.each(dragEvent.dataTransfer.types, function(key, val) {\n if (val === \"Files\") {\n fileDrag = true;\n return false;\n }\n });\n\n return fileDrag;\n }\n\n // Attempt to determine when the file has left the document. It is not always possible to detect this\n // in all cases, but it is generally possible in all browsers, with a few exceptions.\n //\n // Exceptions:\n // * IE10+ & Safari: We can't detect a file leaving the document if the Explorer window housing the file\n // overlays the browser window.\n // * IE10+: If the file is dragged out of the window too quickly, IE does not set the expected values of the\n // event's X & Y properties.\n function leavingDocumentOut(e) {\n if (qq.safari()) {\n return e.x < 0 || e.y < 0;\n }\n\n return e.x === 0 && e.y === 0;\n }\n\n function setupDragDrop() {\n var dropZones = options.dropZoneElements,\n\n maybeHideDropZones = function() {\n setTimeout(function() {\n qq.each(dropZones, function(idx, dropZone) {\n qq(dropZone).hasAttribute(HIDE_BEFORE_ENTER_ATTR) && qq(dropZone).hide();\n qq(dropZone).removeClass(options.classes.dropActive);\n });\n }, 10);\n };\n\n qq.each(dropZones, function(idx, dropZone) {\n var uploadDropZone = setupDropzone(dropZone);\n\n // IE <= 9 does not support the File API used for drag+drop uploads\n if (dropZones.length && qq.supportedFeatures.fileDrop) {\n disposeSupport.attach(document, \"dragenter\", function(e) {\n if (!uploadDropZone.dropDisabled() && isFileDrag(e)) {\n qq.each(dropZones, function(idx, dropZone) {\n // We can't apply styles to non-HTMLElements, since they lack the `style` property.\n // Also, if the drop zone isn't initially hidden, let's not mess with `style.display`.\n if (dropZone instanceof HTMLElement &&\n qq(dropZone).hasAttribute(HIDE_BEFORE_ENTER_ATTR)) {\n\n qq(dropZone).css({display: \"block\"});\n }\n });\n }\n });\n }\n });\n\n disposeSupport.attach(document, \"dragleave\", function(e) {\n if (leavingDocumentOut(e)) {\n maybeHideDropZones();\n }\n });\n\n // Just in case we were not able to detect when a dragged file has left the document,\n // hide all relevant drop zones the next time the mouse enters the document.\n // Note that mouse events such as this one are not fired during drag operations.\n disposeSupport.attach(qq(document).children()[0], \"mouseenter\", function(e) {\n maybeHideDropZones();\n });\n\n disposeSupport.attach(document, \"drop\", function(e) {\n if (isFileDrag(e)) {\n e.preventDefault();\n maybeHideDropZones();\n }\n });\n\n disposeSupport.attach(document, HIDE_ZONES_EVENT_NAME, maybeHideDropZones);\n }\n\n setupDragDrop();\n\n qq.extend(this, {\n setupExtraDropzone: function(element) {\n options.dropZoneElements.push(element);\n setupDropzone(element);\n },\n\n removeDropzone: function(element) {\n var i,\n dzs = options.dropZoneElements;\n\n for (i in dzs) {\n if (dzs[i] === element) {\n return dzs.splice(i, 1);\n }\n }\n },\n\n dispose: function() {\n disposeSupport.dispose();\n qq.each(uploadDropZones, function(idx, dropZone) {\n dropZone.dispose();\n });\n }\n });\n\n this._testing = {};\n this._testing.extractDirectoryPath = extractDirectoryPath;\n};\n\nqq.DragAndDrop.callbacks = function() {\n \"use strict\";\n\n return {\n processingDroppedFiles: function() {},\n processingDroppedFilesComplete: function(files, targetEl) {},\n dropError: function(code, errorSpecifics) {\n qq.log(\"Drag & drop error code '\" + code + \" with these specifics: '\" + errorSpecifics + \"'\", \"error\");\n },\n dropLog: function(message, level) {\n qq.log(message, level);\n }\n };\n};\n\nqq.UploadDropZone = function(o) {\n \"use strict\";\n\n var disposeSupport = new qq.DisposeSupport(),\n options, element, preventDrop, dropOutsideDisabled;\n\n options = {\n element: null,\n onEnter: function(e) {},\n onLeave: function(e) {},\n // is not fired when leaving element by hovering descendants\n onLeaveNotDescendants: function(e) {},\n onDrop: function(e) {}\n };\n\n qq.extend(options, o);\n element = options.element;\n\n function dragoverShouldBeCanceled() {\n return qq.safari() || (qq.firefox() && qq.windows());\n }\n\n function disableDropOutside(e) {\n // run only once for all instances\n if (!dropOutsideDisabled) {\n\n // for these cases we need to catch onDrop to reset dropArea\n if (dragoverShouldBeCanceled) {\n disposeSupport.attach(document, \"dragover\", function(e) {\n e.preventDefault();\n });\n } else {\n disposeSupport.attach(document, \"dragover\", function(e) {\n if (e.dataTransfer) {\n e.dataTransfer.dropEffect = \"none\";\n e.preventDefault();\n }\n });\n }\n\n dropOutsideDisabled = true;\n }\n }\n\n function isValidFileDrag(e) {\n // e.dataTransfer currently causing IE errors\n // IE9 does NOT support file API, so drag-and-drop is not possible\n if (!qq.supportedFeatures.fileDrop) {\n return false;\n }\n\n var effectTest, dt = e.dataTransfer,\n // do not check dt.types.contains in webkit, because it crashes safari 4\n isSafari = qq.safari();\n\n // dt.effectAllowed is none in Safari 5\n\n // dt.effectAllowed crashes IE 11 & 10 when files have been dragged from\n // the filesystem\n effectTest = qq.ie() && qq.supportedFeatures.fileDrop ? true : dt.effectAllowed !== \"none\";\n return dt && effectTest &&\n (\n (dt.files && dt.files.length) || // Valid for drop events with files\n (!isSafari && dt.types.contains && dt.types.contains(\"Files\")) || // Valid in Chrome/Firefox\n (dt.types.includes && dt.types.includes(\"Files\")) // Valid in IE\n );\n }\n\n function isOrSetDropDisabled(isDisabled) {\n if (isDisabled !== undefined) {\n preventDrop = isDisabled;\n }\n return preventDrop;\n }\n\n function triggerHidezonesEvent() {\n var hideZonesEvent;\n\n function triggerUsingOldApi() {\n hideZonesEvent = document.createEvent(\"Event\");\n hideZonesEvent.initEvent(options.HIDE_ZONES_EVENT_NAME, true, true);\n }\n\n if (window.CustomEvent) {\n try {\n hideZonesEvent = new CustomEvent(options.HIDE_ZONES_EVENT_NAME);\n }\n catch (err) {\n triggerUsingOldApi();\n }\n }\n else {\n triggerUsingOldApi();\n }\n\n document.dispatchEvent(hideZonesEvent);\n }\n\n function attachEvents() {\n disposeSupport.attach(element, \"dragover\", function(e) {\n if (!isValidFileDrag(e)) {\n return;\n }\n\n // dt.effectAllowed crashes IE 11 & 10 when files have been dragged from\n // the filesystem\n var effect = qq.ie() && qq.supportedFeatures.fileDrop ? null : e.dataTransfer.effectAllowed;\n if (effect === \"move\" || effect === \"linkMove\") {\n e.dataTransfer.dropEffect = \"move\"; // for FF (only move allowed)\n } else {\n e.dataTransfer.dropEffect = \"copy\"; // for Chrome\n }\n\n e.stopPropagation();\n e.preventDefault();\n });\n\n disposeSupport.attach(element, \"dragenter\", function(e) {\n if (!isOrSetDropDisabled()) {\n if (!isValidFileDrag(e)) {\n return;\n }\n options.onEnter(e);\n }\n });\n\n disposeSupport.attach(element, \"dragleave\", function(e) {\n if (!isValidFileDrag(e)) {\n return;\n }\n\n options.onLeave(e);\n\n var relatedTarget = document.elementFromPoint(e.clientX, e.clientY);\n // do not fire when moving a mouse over a descendant\n if (qq(this).contains(relatedTarget)) {\n return;\n }\n\n options.onLeaveNotDescendants(e);\n });\n\n disposeSupport.attach(element, \"drop\", function(e) {\n if (!isOrSetDropDisabled()) {\n if (!isValidFileDrag(e)) {\n return;\n }\n\n e.preventDefault();\n e.stopPropagation();\n options.onDrop(e);\n\n triggerHidezonesEvent();\n }\n });\n }\n\n disableDropOutside();\n attachEvents();\n\n qq.extend(this, {\n dropDisabled: function(isDisabled) {\n return isOrSetDropDisabled(isDisabled);\n },\n\n dispose: function() {\n disposeSupport.dispose();\n },\n\n getElement: function() {\n return element;\n }\n });\n\n this._testing = {};\n this._testing.isValidFileDrag = isValidFileDrag;\n};\n"]} \ No newline at end of file diff --git a/resources/fine-uploader/dnd.min.js b/resources/fine-uploader/dnd.min.js deleted file mode 100644 index bad4e2d..0000000 --- a/resources/fine-uploader/dnd.min.js +++ /dev/null @@ -1,3 +0,0 @@ -// Fine Uploader 5.16.2 - MIT licensed. http://fineuploader.com -!function(global){var qq=function(e){"use strict";return{hide:function(){return e.style.display="none",this},attach:function(t,n){return e.addEventListener?e.addEventListener(t,n,!1):e.attachEvent&&e.attachEvent("on"+t,n),function(){qq(e).detach(t,n)}},detach:function(t,n){return e.removeEventListener?e.removeEventListener(t,n,!1):e.attachEvent&&e.detachEvent("on"+t,n),this},contains:function(t){return!!t&&(e===t||(e.contains?e.contains(t):!!(8&t.compareDocumentPosition(e))))},insertBefore:function(t){return t.parentNode.insertBefore(e,t),this},remove:function(){return e.parentNode.removeChild(e),this},css:function(t){if(null==e.style)throw new qq.Error("Can't apply style to node as it is not on the HTMLElement prototype chain!");return null!=t.opacity&&"string"!=typeof e.style.opacity&&void 0!==e.filters&&(t.filter="alpha(opacity="+Math.round(100*t.opacity)+")"),qq.extend(e.style,t),this},hasClass:function(t,n){var r=new RegExp("(^| )"+t+"( |$)");return r.test(e.className)||!(!n||!r.test(e.parentNode.className))},addClass:function(t){return qq(e).hasClass(t)||(e.className+=" "+t),this},removeClass:function(t){var n=new RegExp("(^| )"+t+"( |$)");return e.className=e.className.replace(n," ").replace(/^\s+|\s+$/g,""),this},getByClass:function(t,n){var r,o=[];return n&&e.querySelector?e.querySelector("."+t):e.querySelectorAll?e.querySelectorAll("."+t):(r=e.getElementsByTagName("*"),qq.each(r,function(e,n){qq(n).hasClass(t)&&o.push(n)}),n?o[0]:o)},getFirstByClass:function(t){return qq(e).getByClass(t,!0)},children:function(){for(var t=[],n=e.firstChild;n;)1===n.nodeType&&t.push(n),n=n.nextSibling;return t},setText:function(t){return e.innerText=t,e.textContent=t,this},clearText:function(){return qq(e).setText("")},hasAttribute:function(t){var n;return e.hasAttribute?!!e.hasAttribute(t)&&null==/^false$/i.exec(e.getAttribute(t)):(n=e[t],void 0!==n&&null==/^false$/i.exec(n))}}};!function(){"use strict";qq.canvasToBlob=function(e,t,n){return qq.dataUriToBlob(e.toDataURL(t,n))},qq.dataUriToBlob=function(e){var t,n,r,o,i=function(e,t){var n=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder||window.MSBlobBuilder,r=n&&new n;return r?(r.append(e),r.getBlob(t)):new Blob([e],{type:t})};return n=e.split(",")[0].indexOf("base64")>=0?atob(e.split(",")[1]):decodeURI(e.split(",")[1]),o=e.split(",")[0].split(":")[1].split(";")[0],t=new ArrayBuffer(n.length),r=new Uint8Array(t),qq.each(n,function(e,t){r[e]=t.charCodeAt(0)}),i(t,o)},qq.log=function(e,t){window.console&&(t&&"info"!==t?window.console[t]?window.console[t](e):window.console.log("<"+t+"> "+e):window.console.log(e))},qq.isObject=function(e){return e&&!e.nodeType&&"[object Object]"===Object.prototype.toString.call(e)},qq.isFunction=function(e){return"function"==typeof e},qq.isArray=function(e){return"[object Array]"===Object.prototype.toString.call(e)||e&&window.ArrayBuffer&&e.buffer&&e.buffer.constructor===ArrayBuffer},qq.isItemList=function(e){return"[object DataTransferItemList]"===Object.prototype.toString.call(e)},qq.isNodeList=function(e){return"[object NodeList]"===Object.prototype.toString.call(e)||e.item&&e.namedItem},qq.isString=function(e){return"[object String]"===Object.prototype.toString.call(e)},qq.trimStr=function(e){return String.prototype.trim?e.trim():e.replace(/^\s+|\s+$/g,"")},qq.format=function(e){var t=Array.prototype.slice.call(arguments,1),n=e,r=n.indexOf("{}");return qq.each(t,function(e,t){if(n=n.substring(0,r)+t+n.substring(r+2),r=n.indexOf("{}",r+t.length),r<0)return!1}),n},qq.isFile=function(e){return window.File&&"[object File]"===Object.prototype.toString.call(e)},qq.isFileList=function(e){return window.FileList&&"[object FileList]"===Object.prototype.toString.call(e)},qq.isFileOrInput=function(e){return qq.isFile(e)||qq.isInput(e)},qq.isInput=function(e,t){var n=function(e){var n=e.toLowerCase();return t?"file"!==n:"file"===n};return!!(window.HTMLInputElement&&"[object HTMLInputElement]"===Object.prototype.toString.call(e)&&e.type&&n(e.type))||!!(e.tagName&&"input"===e.tagName.toLowerCase()&&e.type&&n(e.type))},qq.isBlob=function(e){if(window.Blob&&"[object Blob]"===Object.prototype.toString.call(e))return!0},qq.isXhrUploadSupported=function(){var e=document.createElement("input");return e.type="file",void 0!==e.multiple&&"undefined"!=typeof File&&"undefined"!=typeof FormData&&void 0!==qq.createXhrInstance().upload},qq.createXhrInstance=function(){if(window.XMLHttpRequest)return new XMLHttpRequest;try{return new ActiveXObject("MSXML2.XMLHTTP.3.0")}catch(e){return qq.log("Neither XHR or ActiveX are supported!","error"),null}},qq.isFolderDropSupported=function(e){return e.items&&e.items.length>0&&e.items[0].webkitGetAsEntry},qq.isFileChunkingSupported=function(){return!qq.androidStock()&&qq.isXhrUploadSupported()&&(void 0!==File.prototype.slice||void 0!==File.prototype.webkitSlice||void 0!==File.prototype.mozSlice)},qq.sliceBlob=function(e,t,n){return(e.slice||e.mozSlice||e.webkitSlice).call(e,t,n)},qq.arrayBufferToHex=function(e){var t="",n=new Uint8Array(e);return qq.each(n,function(e,n){var r=n.toString(16);r.length<2&&(r="0"+r),t+=r}),t},qq.readBlobToHex=function(e,t,n){var r=qq.sliceBlob(e,t,t+n),o=new FileReader,i=new qq.Promise;return o.onload=function(){i.success(qq.arrayBufferToHex(o.result))},o.onerror=i.failure,o.readAsArrayBuffer(r),i},qq.extend=function(e,t,n){return qq.each(t,function(t,r){n&&qq.isObject(r)?(void 0===e[t]&&(e[t]={}),qq.extend(e[t],r,!0)):e[t]=r}),e},qq.override=function(e,t){var n={},r=t(n);return qq.each(r,function(t,r){void 0!==e[t]&&(n[t]=e[t]),e[t]=r}),e},qq.indexOf=function(e,t,n){if(e.indexOf)return e.indexOf(t,n);n=n||0;var r=e.length;for(n<0&&(n+=r);n=0},qq.safari=function(){return void 0!==navigator.vendor&&navigator.vendor.indexOf("Apple")!==-1},qq.chrome=function(){return void 0!==navigator.vendor&&navigator.vendor.indexOf("Google")!==-1},qq.opera=function(){return void 0!==navigator.vendor&&navigator.vendor.indexOf("Opera")!==-1},qq.firefox=function(){return!qq.edge()&&!qq.ie11()&&navigator.userAgent.indexOf("Mozilla")!==-1&&void 0!==navigator.vendor&&""===navigator.vendor},qq.windows=function(){return"Win32"===navigator.platform},qq.android=function(){return navigator.userAgent.toLowerCase().indexOf("android")!==-1},qq.androidStock=function(){return qq.android()&&navigator.userAgent.toLowerCase().indexOf("chrome")<0},qq.ios6=function(){return qq.ios()&&navigator.userAgent.indexOf(" OS 6_")!==-1},qq.ios7=function(){return qq.ios()&&navigator.userAgent.indexOf(" OS 7_")!==-1},qq.ios8=function(){return qq.ios()&&navigator.userAgent.indexOf(" OS 8_")!==-1},qq.ios800=function(){return qq.ios()&&navigator.userAgent.indexOf(" OS 8_0 ")!==-1},qq.ios=function(){return navigator.userAgent.indexOf("iPad")!==-1||navigator.userAgent.indexOf("iPod")!==-1||navigator.userAgent.indexOf("iPhone")!==-1},qq.iosChrome=function(){return qq.ios()&&navigator.userAgent.indexOf("CriOS")!==-1},qq.iosSafari=function(){return qq.ios()&&!qq.iosChrome()&&navigator.userAgent.indexOf("Safari")!==-1},qq.iosSafariWebView=function(){return qq.ios()&&!qq.iosChrome()&&!qq.iosSafari()},qq.preventDefault=function(e){e.preventDefault?e.preventDefault():e.returnValue=!1},qq.toElement=function(){var e=document.createElement("div");return function(t){e.innerHTML=t;var n=e.firstChild;return e.removeChild(n),n}}(),qq.each=function(e,t){var n,r;if(e)if(window.Storage&&e.constructor===window.Storage)for(n=0;n0)return e.substr(t,e.length-t)},qq.getFilename=function(e){return qq.isInput(e)?e.value.replace(/.*(\/|\\)/,""):qq.isFile(e)&&null!==e.fileName&&void 0!==e.fileName?e.fileName:e.name},qq.DisposeSupport=function(){var e=[];return{dispose:function(){var t;do t=e.shift(),t&&t();while(t)},attach:function(){var e=arguments;this.addDisposer(qq(e[0]).attach.apply(this,Array.prototype.slice.call(arguments,1)))},addDisposer:function(t){e.push(t)}}}}(),function(){"use strict";"function"==typeof define&&define.amd?define(function(){return qq}):"undefined"!=typeof module&&module.exports?module.exports=qq:global.qq=qq}(),qq.version="5.16.2",qq.supportedFeatures=function(){"use strict";function e(){var e,t=!0;try{e=document.createElement("input"),e.type="file",qq(e).hide(),e.disabled&&(t=!1)}catch(e){t=!1}return t}function t(){return(qq.chrome()||qq.opera())&&void 0!==navigator.userAgent.match(/Chrome\/[1][4-9]|Chrome\/[2-9][0-9]/)}function n(){if(window.XMLHttpRequest){return void 0!==qq.createXhrInstance().withCredentials}return!1}function r(){return void 0!==window.XDomainRequest}function o(){return!!n()||r()}function i(){return void 0!==document.createElement("input").webkitdirectory}function a(){try{return!!window.localStorage&&qq.isFunction(window.localStorage.setItem)}catch(e){return!1}}function u(){var e=document.createElement("span");return("draggable"in e||"ondragstart"in e&&"ondrop"in e)&&!qq.android()&&!qq.ios()}var c,s,l,q,f,d,p,g,h,v,m,y,b,w,x;return c=e(),q=c&&qq.isXhrUploadSupported(),s=q&&!qq.androidStock(),l=q&&u(),f=l&&function(){var e=document.createElement("input");return e.type="file",!!("webkitdirectory"in(e||document.querySelectorAll("input[type=file]")[0]))}(),d=q&&qq.isFileChunkingSupported(),p=q&&d&&a(),g=q&&t(),h=c&&(void 0!==window.postMessage||q),m=n(),v=r(),y=o(),b=i(),w=q&&void 0!==window.FileReader,x=function(){return!!q&&(!qq.androidStock()&&!qq.iosChrome())}(),{ajaxUploading:q,blobUploading:s,canDetermineSize:q,chunking:d,deleteFileCors:y,deleteFileCorsXdr:v,deleteFileCorsXhr:m,dialogElement:!!window.HTMLDialogElement,fileDrop:l,folderDrop:f,folderSelection:b,imagePreviews:w,imageValidation:w,itemSizeValidation:q,pause:d,progressBar:x,resume:p,scaling:w&&s,tiffPreviews:qq.safari(),unlimitedScaledImageSize:!qq.ios(),uploading:c,uploadCors:h,uploadCustomHeaders:q,uploadNonMultipart:q,uploadViaPaste:g}}(),qq.isGenericPromise=function(e){"use strict";return!!(e&&e.then&&qq.isFunction(e.then))},qq.Promise=function(){"use strict";var e,t,n=[],r=[],o=[],i=0;qq.extend(this,{then:function(o,a){return 0===i?(o&&n.push(o),a&&r.push(a)):i===-1?a&&a.apply(null,t):o&&o.apply(null,e),this},done:function(n){return 0===i?o.push(n):n.apply(null,void 0===t?e:t),this},success:function(){return i=1,e=arguments,n.length&&qq.each(n,function(t,n){n.apply(null,e)}),o.length&&qq.each(o,function(t,n){n.apply(null,e)}),this},failure:function(){return i=-1,t=arguments,r.length&&qq.each(r,function(e,n){n.apply(null,t)}),o.length&&qq.each(o,function(e,n){n.apply(null,t)}),this}})},qq.DragAndDrop=function(e){"use strict";function t(e,t){var n=Array.prototype.slice.call(e);l.callbacks.dropLog("Grabbed "+e.length+" dropped files."),t.dropDisabled(!1),l.callbacks.processingDroppedFilesComplete(n,t.getElement())}function n(e){var t=new qq.Promise;return e.isFile?e.file(function(n){n.qqPath=r(e),f.push(n),t.success()},function(n){l.callbacks.dropLog("Problem parsing '"+e.fullPath+"'. FileError code "+n.code+".","error"),t.failure()}):e.isDirectory&&o(e).then(function(e){var r=e.length;qq.each(e,function(e,o){n(o).done(function(){r-=1,0===r&&t.success()})}),e.length||t.success()},function(n){l.callbacks.dropLog("Problem parsing '"+e.fullPath+"'. FileError code "+n.code+".","error"),t.failure()}),t}function r(e){var t=e.name,n=e.fullPath,r=n.lastIndexOf(t);return n=n.substr(0,r),"/"===n.charAt(0)&&(n=n.substr(1)),n}function o(e,t,n,r){var i=r||new qq.Promise,a=t||e.createReader();return a.readEntries(function(t){var r=n?n.concat(t):t;t.length?setTimeout(function(){o(e,a,r,i)},0):i.success(r)},i.failure),i}function i(e,t){var r=[],o=new qq.Promise;return l.callbacks.processingDroppedFiles(),t.dropDisabled(!0),e.files.length>1&&!l.allowMultipleItems?(l.callbacks.processingDroppedFilesComplete([]),l.callbacks.dropError("tooManyFilesError",""),t.dropDisabled(!1),o.failure()):(f=[],qq.isFolderDropSupported(e)?qq.each(e.items,function(e,t){var i=t.webkitGetAsEntry();i&&(i.isFile?f.push(t.getAsFile()):r.push(n(i).done(function(){r.pop(),0===r.length&&o.success()})))}):f=e.files,0===r.length&&o.success()),o}function a(e){var n=new qq.UploadDropZone({HIDE_ZONES_EVENT_NAME:"qq-hidezones",element:e,onEnter:function(t){qq(e).addClass(l.classes.dropActive),t.stopPropagation()},onLeaveNotDescendants:function(t){qq(e).removeClass(l.classes.dropActive)},onDrop:function(e){i(e.dataTransfer,n).then(function(){t(f,n)},function(){l.callbacks.dropLog("Drop event DataTransfer parsing failed. No files will be uploaded.","error")})}});return d.addDisposer(function(){n.dispose()}),qq(e).hasAttribute("qq-hide-dropzone")&&qq(e).hide(),q.push(n),n}function u(e){var t;return qq.each(e.dataTransfer.types,function(e,n){if("Files"===n)return t=!0,!1}),t}function c(e){return qq.safari()?e.x<0||e.y<0:0===e.x&&0===e.y}function s(){var e=l.dropZoneElements,t=function(){setTimeout(function(){qq.each(e,function(e,t){qq(t).hasAttribute("qq-hide-dropzone")&&qq(t).hide(),qq(t).removeClass(l.classes.dropActive)})},10)};qq.each(e,function(t,n){var r=a(n);e.length&&qq.supportedFeatures.fileDrop&&d.attach(document,"dragenter",function(t){!r.dropDisabled()&&u(t)&&qq.each(e,function(e,t){t instanceof HTMLElement&&qq(t).hasAttribute("qq-hide-dropzone")&&qq(t).css({display:"block"})})})}),d.attach(document,"dragleave",function(e){c(e)&&t()}),d.attach(qq(document).children()[0],"mouseenter",function(e){t()}),d.attach(document,"drop",function(e){u(e)&&(e.preventDefault(),t())}),d.attach(document,"qq-hidezones",t)}var l,q=[],f=[],d=new qq.DisposeSupport;l={dropZoneElements:[],allowMultipleItems:!0,classes:{dropActive:null},callbacks:new qq.DragAndDrop.callbacks},qq.extend(l,e,!0),s(),qq.extend(this,{setupExtraDropzone:function(e){l.dropZoneElements.push(e),a(e)},removeDropzone:function(e){var t,n=l.dropZoneElements;for(t in n)if(n[t]===e)return n.splice(t,1)},dispose:function(){d.dispose(),qq.each(q,function(e,t){t.dispose()})}}),this._testing={},this._testing.extractDirectoryPath=r},qq.DragAndDrop.callbacks=function(){"use strict";return{processingDroppedFiles:function(){},processingDroppedFilesComplete:function(e,t){},dropError:function(e,t){qq.log("Drag & drop error code '"+e+" with these specifics: '"+t+"'","error")},dropLog:function(e,t){qq.log(e,t)}}},qq.UploadDropZone=function(e){"use strict";function t(){return qq.safari()||qq.firefox()&&qq.windows()}function n(e){l||(t?q.attach(document,"dragover",function(e){e.preventDefault()}):q.attach(document,"dragover",function(e){e.dataTransfer&&(e.dataTransfer.dropEffect="none",e.preventDefault())}),l=!0)}function r(e){if(!qq.supportedFeatures.fileDrop)return!1;var t,n=e.dataTransfer,r=qq.safari();return t=!(!qq.ie()||!qq.supportedFeatures.fileDrop)||"none"!==n.effectAllowed,n&&t&&(n.files&&n.files.length||!r&&n.types.contains&&n.types.contains("Files")||n.types.includes&&n.types.includes("Files"))}function o(e){return void 0!==e&&(s=e),s}function i(){function e(){t=document.createEvent("Event"),t.initEvent(u.HIDE_ZONES_EVENT_NAME,!0,!0)}var t;if(window.CustomEvent)try{t=new CustomEvent(u.HIDE_ZONES_EVENT_NAME)}catch(t){e()}else e();document.dispatchEvent(t)}function a(){q.attach(c,"dragover",function(e){if(r(e)){var t=qq.ie()&&qq.supportedFeatures.fileDrop?null:e.dataTransfer.effectAllowed;e.dataTransfer.dropEffect="move"===t||"linkMove"===t?"move":"copy",e.stopPropagation(),e.preventDefault()}}),q.attach(c,"dragenter",function(e){if(!o()){if(!r(e))return;u.onEnter(e)}}),q.attach(c,"dragleave",function(e){if(r(e)){u.onLeave(e);var t=document.elementFromPoint(e.clientX,e.clientY);qq(this).contains(t)||u.onLeaveNotDescendants(e)}}),q.attach(c,"drop",function(e){if(!o()){if(!r(e))return;e.preventDefault(),e.stopPropagation(),u.onDrop(e),i()}})}var u,c,s,l,q=new qq.DisposeSupport;u={element:null,onEnter:function(e){},onLeave:function(e){},onLeaveNotDescendants:function(e){},onDrop:function(e){}},qq.extend(u,e),c=u.element,n(),a(),qq.extend(this,{dropDisabled:function(e){return o(e)},dispose:function(){q.dispose()},getElement:function(){return c}}),this._testing={},this._testing.isValidFileDrag=r}}(window); -//# sourceMappingURL=dnd.min.js.map \ No newline at end of file diff --git a/resources/fine-uploader/dnd.min.js.map b/resources/fine-uploader/dnd.min.js.map deleted file mode 100644 index 3927f66..0000000 --- a/resources/fine-uploader/dnd.min.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["?","../client/js/util.js","../client/js/export.js","../client/js/version.js","../client/js/features.js","../client/js/promise.js","../client/js/dnd.js"],"names":["global","qq","element","hide","style","display","this","attach","type","fn","addEventListener","attachEvent","detach","removeEventListener","detachEvent","contains","descendant","compareDocumentPosition","insertBefore","elementB","parentNode","remove","removeChild","css","styles","Error","opacity","filter","Math","round","extend","hasClass","name","considerParent","re","RegExp","test","className","addClass","removeClass","replace","getByClass","first","candidates","result","querySelector","querySelectorAll","getElementsByTagName","each","idx","val","push","getFirstByClass","children","child","firstChild","nodeType","nextSibling","setText","text","innerText","textContent","clearText","hasAttribute","attrName","attrVal","exec","getAttribute","undefined","canvasToBlob","canvas","mime","quality","dataUriToBlob","toDataURL","dataUri","arrayBuffer","byteString","intArray","mimeString","createBlob","data","BlobBuilder","window","WebKitBlobBuilder","MozBlobBuilder","MSBlobBuilder","blobBuilder","append","getBlob","Blob","split","indexOf","atob","decodeURI","ArrayBuffer","length","Uint8Array","character","charCodeAt","log","message","level","console","isObject","variable","Object","prototype","toString","call","isFunction","isArray","value","buffer","constructor","isItemList","maybeItemList","isNodeList","maybeNodeList","item","namedItem","isString","maybeString","trimStr","string","String","trim","format","str","args","Array","slice","arguments","newStr","nextIdxToReplace","substring","isFile","maybeFile","File","isFileList","maybeFileList","FileList","isFileOrInput","maybeFileOrInput","isInput","maybeInput","notFile","evaluateType","normalizedType","toLowerCase","HTMLInputElement","tagName","isBlob","maybeBlob","isXhrUploadSupported","input","document","createElement","multiple","FormData","createXhrInstance","upload","XMLHttpRequest","ActiveXObject","error","isFolderDropSupported","dataTransfer","items","webkitGetAsEntry","isFileChunkingSupported","androidStock","webkitSlice","mozSlice","sliceBlob","fileOrBlob","start","end","arrayBufferToHex","bytesAsHex","bytes","byt","byteAsHexStr","readBlobToHex","blob","startOffset","initialBlob","fileReader","FileReader","promise","Promise","onload","success","onerror","failure","readAsArrayBuffer","second","extendNested","prop","override","target","sourceFn","super_","source","srcPropName","srcPropVal","arr","elt","from","len","hasOwnProperty","getUniqueId","c","r","random","ie","navigator","userAgent","ie7","ie8","ie10","ie11","edge","safari","vendor","chrome","opera","firefox","windows","platform","android","ios6","ios","ios7","ios8","ios800","iosChrome","iosSafari","iosSafariWebView","preventDefault","e","returnValue","toElement","div","html","innerHTML","iterableItem","callback","keyOrIndex","retVal","Storage","key","getItem","charAt","bind","oldFunc","context","newArgs","concat","apply","obj2url","obj","temp","prefixDone","uristrings","prefix","add","nextObj","i","nextTemp","encodeURIComponent","join","obj2FormData","formData","arrayKeyName","obj2Inputs","form","setAttribute","appendChild","parseJson","json","JSON","parse","eval","getExtension","filename","extIdx","lastIndexOf","substr","getFilename","blobOrFileInput","fileName","DisposeSupport","disposers","dispose","disposer","shift","addDisposer","disposeFunction","define","amd","module","exports","version","supportedFeatures","testSupportsFileInputElement","tempInput","supported","disabled","ex","isChrome14OrHigher","match","isCrossOriginXhrSupported","withCredentials","isXdrSupported","XDomainRequest","isCrossOriginAjaxSupported","isFolderSelectionSupported","webkitdirectory","isLocalStorageSupported","localStorage","setItem","isDragAndDropSupported","span","supportsUploading","supportsUploadingBlobs","supportsFileDrop","supportsAjaxFileUploading","supportsFolderDrop","supportsChunking","supportsResume","supportsUploadViaPaste","supportsUploadCors","supportsDeleteFileXdr","supportsDeleteFileCorsXhr","supportsDeleteFileCors","supportsFolderSelection","supportsImagePreviews","supportsUploadProgress","postMessage","ajaxUploading","blobUploading","canDetermineSize","chunking","deleteFileCors","deleteFileCorsXdr","deleteFileCorsXhr","dialogElement","HTMLDialogElement","fileDrop","folderDrop","folderSelection","imagePreviews","imageValidation","itemSizeValidation","pause","progressBar","resume","scaling","tiffPreviews","unlimitedScaledImageSize","uploading","uploadCors","uploadCustomHeaders","uploadNonMultipart","uploadViaPaste","isGenericPromise","maybePromise","then","successArgs","failureArgs","successCallbacks","failureCallbacks","doneCallbacks","state","onSuccess","onFailure","done","DragAndDrop","o","uploadDroppedFiles","files","uploadDropZone","filesAsArray","options","callbacks","dropLog","dropDisabled","processingDroppedFilesComplete","getElement","traverseFileTree","entry","parseEntryPromise","file","qqPath","extractDirectoryPath","droppedFiles","fileError","fullPath","code","isDirectory","getFilesInDirectory","entries","entriesLeft","indexOfNameInFullPath","reader","accumEntries","existingPromise","dirReader","createReader","readEntries","newEntries","setTimeout","handleDataTransfer","pendingFolderPromises","handleDataTransferPromise","processingDroppedFiles","allowMultipleItems","dropError","getAsFile","pop","setupDropzone","dropArea","dropZone","UploadDropZone","HIDE_ZONES_EVENT_NAME","onEnter","classes","dropActive","stopPropagation","onLeaveNotDescendants","onDrop","disposeSupport","uploadDropZones","isFileDrag","dragEvent","fileDrag","types","leavingDocumentOut","x","y","setupDragDrop","dropZones","dropZoneElements","maybeHideDropZones","HTMLElement","setupExtraDropzone","removeDropzone","dzs","splice","_testing","targetEl","errorSpecifics","dragoverShouldBeCanceled","disableDropOutside","dropOutsideDisabled","dropEffect","isValidFileDrag","effectTest","dt","isSafari","effectAllowed","includes","isOrSetDropDisabled","isDisabled","preventDrop","triggerHidezonesEvent","triggerUsingOldApi","hideZonesEvent","createEvent","initEvent","CustomEvent","err","dispatchEvent","attachEvents","effect","onLeave","relatedTarget","elementFromPoint","clientX","clientY"],"mappings":";CAAA,SAAUA,QCEV,GAAIC,IAAK,SAASC,GACd,YAEA,QACIC,KAAM,WAEF,MADAD,GAAQE,MAAMC,QAAU,OACjBC,MAIXC,OAAQ,SAASC,EAAMC,GAMnB,MALIP,GAAQQ,iBACRR,EAAQQ,iBAAiBF,EAAMC,GAAI,GAC5BP,EAAQS,aACfT,EAAQS,YAAY,KAAOH,EAAMC,GAE9B,WACHR,GAAGC,GAASU,OAAOJ,EAAMC,KAIjCG,OAAQ,SAASJ,EAAMC,GAMnB,MALIP,GAAQW,oBACRX,EAAQW,oBAAoBL,EAAMC,GAAI,GAC/BP,EAAQS,aACfT,EAAQY,YAAY,KAAON,EAAMC,GAE9BH,MAGXS,SAAU,SAASC,GAKf,QAAKA,IAKDd,IAAYc,IAIZd,EAAQa,SACDb,EAAQa,SAASC,MAGgC,EAA9CA,EAAWC,wBAAwBf,OAOrDgB,aAAc,SAASC,GAEnB,MADAA,GAASC,WAAWF,aAAahB,EAASiB,GACnCb,MAGXe,OAAQ,WAEJ,MADAnB,GAAQkB,WAAWE,YAAYpB,GACxBI,MAOXiB,IAAK,SAASC,GAEV,GAAqB,MAAjBtB,EAAQE,MACR,KAAM,IAAIH,IAAGwB,MAAM,6EAWvB,OAPsB,OAAlBD,EAAOE,SAC8B,gBAA1BxB,GAAQE,MAAMsB,SAAqD,SAArBxB,EAAe,UACpEsB,EAAOG,OAAS,iBAAmBC,KAAKC,MAAM,IAAML,EAAOE,SAAW,KAG9EzB,GAAG6B,OAAO5B,EAAQE,MAAOoB,GAElBlB,MAGXyB,SAAU,SAASC,EAAMC,GACrB,GAAIC,GAAK,GAAIC,QAAO,QAAUH,EAAO,QACrC,OAAOE,GAAGE,KAAKlC,EAAQmC,eAAiBJ,IAAkBC,EAAGE,KAAKlC,EAAQkB,WAAWiB,aAGzFC,SAAU,SAASN,GAIf,MAHK/B,IAAGC,GAAS6B,SAASC,KACtB9B,EAAQmC,WAAa,IAAML,GAExB1B,MAGXiC,YAAa,SAASP,GAClB,GAAIE,GAAK,GAAIC,QAAO,QAAUH,EAAO,QAErC,OADA9B,GAAQmC,UAAYnC,EAAQmC,UAAUG,QAAQN,EAAI,KAAKM,QAAQ,aAAc,IACtElC,MAGXmC,WAAY,SAASJ,EAAWK,GAC5B,GAAIC,GACAC,IAEJ,OAAIF,IAASxC,EAAQ2C,cACV3C,EAAQ2C,cAAc,IAAMR,GAE9BnC,EAAQ4C,iBACN5C,EAAQ4C,iBAAiB,IAAMT,IAG1CM,EAAazC,EAAQ6C,qBAAqB,KAE1C9C,GAAG+C,KAAKL,EAAY,SAASM,EAAKC,GAC1BjD,GAAGiD,GAAKnB,SAASM,IACjBO,EAAOO,KAAKD,KAGbR,EAAQE,EAAO,GAAKA,IAG/BQ,gBAAiB,SAASf,GACtB,MAAOpC,IAAGC,GAASuC,WAAWJ,GAAW,IAG7CgB,SAAU,WAIN,IAHA,GAAIA,MACAC,EAAQpD,EAAQqD,WAEbD,GACoB,IAAnBA,EAAME,UACNH,EAASF,KAAKG,GAElBA,EAAQA,EAAMG,WAGlB,OAAOJ,IAGXK,QAAS,SAASC,GAGd,MAFAzD,GAAQ0D,UAAYD,EACpBzD,EAAQ2D,YAAcF,EACfrD,MAGXwD,UAAW,WACP,MAAO7D,IAAGC,GAASwD,QAAQ,KAK/BK,aAAc,SAASC,GACnB,GAAIC,EAEJ,OAAI/D,GAAQ6D,eAEH7D,EAAQ6D,aAAaC,IAKkC,MAArD,WAAaE,KAAKhE,EAAQiE,aAAaH,KAG9CC,EAAU/D,EAAQ8D,GAEFI,SAAZH,GAKiC,MAA9B,WAAaC,KAAKD,QAMxC,WACG,YAEAhE,IAAGoE,aAAe,SAASC,EAAQC,EAAMC,GACrC,MAAOvE,IAAGwE,cAAcH,EAAOI,UAAUH,EAAMC,KAGnDvE,GAAGwE,cAAgB,SAASE,GACxB,GAAIC,GAAaC,EAgBbC,EAAUC,EAfVC,EAAa,SAASC,EAAMV,GACxB,GAAIW,GAAcC,OAAOD,aACjBC,OAAOC,mBACPD,OAAOE,gBACPF,OAAOG,cACXC,EAAcL,GAAe,GAAIA,EAErC,OAAIK,IACAA,EAAYC,OAAOP,GACZM,EAAYE,QAAQlB,IAGpB,GAAImB,OAAMT,IAAQzE,KAAM+D,IAyB3C,OAlBIM,GADAF,EAAQgB,MAAM,KAAK,GAAGC,QAAQ,WAAa,EAC9BC,KAAKlB,EAAQgB,MAAM,KAAK,IAGxBG,UAAUnB,EAAQgB,MAAM,KAAK,IAI9CZ,EAAaJ,EAAQgB,MAAM,KAAK,GAC3BA,MAAM,KAAK,GACXA,MAAM,KAAK,GAGhBf,EAAc,GAAImB,aAAYlB,EAAWmB,QACzClB,EAAW,GAAImB,YAAWrB,GAC1B3E,GAAG+C,KAAK6B,EAAY,SAAS5B,EAAKiD,GAC9BpB,EAAS7B,GAAOiD,EAAUC,WAAW,KAGlCnB,EAAWJ,EAAaG,IAGnC9E,GAAGmG,IAAM,SAASC,EAASC,GACnBnB,OAAOoB,UACFD,GAAmB,SAAVA,EAKNnB,OAAOoB,QAAQD,GACfnB,OAAOoB,QAAQD,GAAOD,GAGtBlB,OAAOoB,QAAQH,IAAI,IAAME,EAAQ,KAAOD,GAR5ClB,OAAOoB,QAAQH,IAAIC,KAc/BpG,GAAGuG,SAAW,SAASC,GACnB,MAAOA,KAAaA,EAASjD,UAAyD,oBAA7CkD,OAAOC,UAAUC,SAASC,KAAKJ,IAG5ExG,GAAG6G,WAAa,SAASL,GACrB,MAA6B,kBAAf,IASlBxG,GAAG8G,QAAU,SAASC,GAClB,MAAiD,mBAA1CN,OAAOC,UAAUC,SAASC,KAAKG,IACjCA,GAAS7B,OAAOY,aAAeiB,EAAMC,QAAUD,EAAMC,OAAOC,cAAgBnB,aAIrF9F,GAAGkH,WAAa,SAASC,GACrB,MAAyD,kCAAlDV,OAAOC,UAAUC,SAASC,KAAKO,IAK1CnH,GAAGoH,WAAa,SAASC,GACrB,MAAyD,sBAAlDZ,OAAOC,UAAUC,SAASC,KAAKS,IAGjCA,EAAcC,MAAQD,EAAcE,WAG7CvH,GAAGwH,SAAW,SAASC,GACnB,MAAuD,oBAAhDhB,OAAOC,UAAUC,SAASC,KAAKa,IAG1CzH,GAAG0H,QAAU,SAASC,GAClB,MAAIC,QAAOlB,UAAUmB,KACVF,EAAOE,OAGXF,EAAOpF,QAAQ,aAAc,KAOxCvC,GAAG8H,OAAS,SAASC,GAEjB,GAAIC,GAAQC,MAAMvB,UAAUwB,MAAMtB,KAAKuB,UAAW,GAC9CC,EAASL,EACTM,EAAmBD,EAAOzC,QAAQ,KAetC,OAbA3F,IAAG+C,KAAKiF,EAAM,SAAShF,EAAKC,GAQxB,GAJAmF,EAHgBA,EAAOE,UAAU,EAAGD,GAGfpF,EAFNmF,EAAOE,UAAUD,EAAmB,GAGnDA,EAAmBD,EAAOzC,QAAQ,KAAM0C,EAAmBpF,EAAI8C,QAG3DsC,EAAmB,EACnB,OAAO,IAIRD,GAGXpI,GAAGuI,OAAS,SAASC,GACjB,MAAOtD,QAAOuD,MAAsD,kBAA9ChC,OAAOC,UAAUC,SAASC,KAAK4B,IAGzDxI,GAAG0I,WAAa,SAASC,GACrB,MAAOzD,QAAO0D,UAA8D,sBAAlDnC,OAAOC,UAAUC,SAASC,KAAK+B,IAG7D3I,GAAG6I,cAAgB,SAASC,GACxB,MAAO9I,IAAGuI,OAAOO,IAAqB9I,GAAG+I,QAAQD,IAGrD9I,GAAG+I,QAAU,SAASC,EAAYC,GAC9B,GAAIC,GAAe,SAAS3I,GACxB,GAAI4I,GAAiB5I,EAAK6I,aAE1B,OAAIH,GAC0B,SAAnBE,EAGe,SAAnBA,EAGX,UAAIjE,OAAOmE,kBAC4C,8BAA/C5C,OAAOC,UAAUC,SAASC,KAAKoC,IAC3BA,EAAWzI,MAAQ2I,EAAaF,EAAWzI,WAKnDyI,EAAWM,SAC8B,UAArCN,EAAWM,QAAQF,eACfJ,EAAWzI,MAAQ2I,EAAaF,EAAWzI,QAS3DP,GAAGuJ,OAAS,SAASC,GACjB,GAAItE,OAAOO,MAAsD,kBAA9CgB,OAAOC,UAAUC,SAASC,KAAK4C,GAC9C,OAAO,GAIfxJ,GAAGyJ,qBAAuB,WACtB,GAAIC,GAAQC,SAASC,cAAc,QAGnC,OAFAF,GAAMnJ,KAAO,OAGU4D,SAAnBuF,EAAMG,UACc,mBAATpB,OACa,mBAAbqB,WACoC,SAAnC9J,GAAG+J,oBAAqBC,QAI5ChK,GAAG+J,kBAAoB,WACnB,GAAI7E,OAAO+E,eACP,MAAO,IAAIA,eAGf,KACI,MAAO,IAAIC,eAAc,sBAE7B,MAAOC,GAEH,MADAnK,IAAGmG,IAAI,wCAAyC,SACzC,OAIfnG,GAAGoK,sBAAwB,SAASC,GAChC,MAAOA,GAAaC,OAChBD,EAAaC,MAAMvE,OAAS,GAC5BsE,EAAaC,MAAM,GAAGC,kBAG9BvK,GAAGwK,wBAA0B,WACzB,OAAQxK,GAAGyK,gBACPzK,GAAGyJ,yBACuBtF,SAAzBsE,KAAK/B,UAAUwB,OAAsD/D,SAA/BsE,KAAK/B,UAAUgE,aAAyDvG,SAA5BsE,KAAK/B,UAAUiE,WAG1G3K,GAAG4K,UAAY,SAASC,EAAYC,EAAOC,GAGvC,OAFaF,EAAW3C,OAAS2C,EAAWF,UAAYE,EAAWH,aAErD9D,KAAKiE,EAAYC,EAAOC,IAG1C/K,GAAGgL,iBAAmB,SAAShE,GAC3B,GAAIiE,GAAa,GACbC,EAAQ,GAAIlF,YAAWgB,EAY3B,OAVAhH,IAAG+C,KAAKmI,EAAO,SAASlI,EAAKmI,GACzB,GAAIC,GAAeD,EAAIxE,SAAS,GAE5ByE,GAAarF,OAAS,IACtBqF,EAAe,IAAMA,GAGzBH,GAAcG,IAGXH,GAGXjL,GAAGqL,cAAgB,SAASC,EAAMC,EAAaxF,GAC3C,GAAIyF,GAAcxL,GAAG4K,UAAUU,EAAMC,EAAaA,EAAcxF,GAC5D0F,EAAa,GAAIC,YACjBC,EAAU,GAAI3L,IAAG4L,OAUrB,OARAH,GAAWI,OAAS,WAChBF,EAAQG,QAAQ9L,GAAGgL,iBAAiBS,EAAW9I,UAGnD8I,EAAWM,QAAUJ,EAAQK,QAE7BP,EAAWQ,kBAAkBT,GAEtBG,GAGX3L,GAAG6B,OAAS,SAASY,EAAOyJ,EAAQC,GAahC,MAZAnM,IAAG+C,KAAKmJ,EAAQ,SAASE,EAAMnJ,GACvBkJ,GAAgBnM,GAAGuG,SAAStD,IACRkB,SAAhB1B,EAAM2J,KACN3J,EAAM2J,OAEVpM,GAAG6B,OAAOY,EAAM2J,GAAOnJ,GAAK,IAG5BR,EAAM2J,GAAQnJ,IAIfR,GAaXzC,GAAGqM,SAAW,SAASC,EAAQC,GAC3B,GAAIC,MACAC,EAASF,EAASC,EAUtB,OARAxM,IAAG+C,KAAK0J,EAAQ,SAASC,EAAaC,GACNxI,SAAxBmI,EAAOI,KACPF,EAAOE,GAAeJ,EAAOI,IAGjCJ,EAAOI,GAAeC,IAGnBL,GAMXtM,GAAG2F,QAAU,SAASiH,EAAKC,EAAKC,GAC5B,GAAIF,EAAIjH,QACJ,MAAOiH,GAAIjH,QAAQkH,EAAKC,EAG5BA,GAAOA,GAAQ,CACf,IAAIC,GAAMH,EAAI7G,MAMd,KAJI+G,EAAO,IACPA,GAAQC,GAGLD,EAAOC,EAAKD,GAAQ,EACvB,GAAIF,EAAII,eAAeF,IAASF,EAAIE,KAAUD,EAC1C,MAAOC,EAGf,QAAO,GAIX9M,GAAGiN,YAAc,WACb,MAAO,uCAAuC1K,QAAQ,QAAS,SAAS2K,GAEpE,GAAIC,GAAoB,GAAhBxL,KAAKyL,SAAgB,CAC7B,QADyC,KAALF,EAAWC,EAAS,EAAJA,EAAU,GACrDxG,SAAS,OAM1B3G,GAAGqN,GAAK,WACJ,MAAOC,WAAUC,UAAU5H,QAAQ,WAAY,GAC3C2H,UAAUC,UAAU5H,QAAQ,cAAe,GAGnD3F,GAAGwN,IAAM,WACL,MAAOF,WAAUC,UAAU5H,QAAQ,aAAc,GAGrD3F,GAAGyN,IAAM,WACL,MAAOH,WAAUC,UAAU5H,QAAQ,aAAc,GAGrD3F,GAAG0N,KAAO,WACN,MAAOJ,WAAUC,UAAU5H,QAAQ,cAAe,GAGtD3F,GAAG2N,KAAO,WACN,MAAO3N,IAAGqN,MAAQC,UAAUC,UAAU5H,QAAQ,YAAa,GAG/D3F,GAAG4N,KAAO,WACN,MAAON,WAAUC,UAAU5H,QAAQ,SAAW,GAGlD3F,GAAG6N,OAAS,WACR,MAA4B1J,UAArBmJ,UAAUQ,QAAwBR,UAAUQ,OAAOnI,QAAQ,YAAa,GAGnF3F,GAAG+N,OAAS,WACR,MAA4B5J,UAArBmJ,UAAUQ,QAAwBR,UAAUQ,OAAOnI,QAAQ,aAAc,GAGpF3F,GAAGgO,MAAQ,WACP,MAA4B7J,UAArBmJ,UAAUQ,QAAwBR,UAAUQ,OAAOnI,QAAQ,YAAa,GAGnF3F,GAAGiO,QAAU,WACT,OAASjO,GAAG4N,SAAW5N,GAAG2N,QAAUL,UAAUC,UAAU5H,QAAQ,cAAe,GAA2BxB,SAArBmJ,UAAUQ,QAA6C,KAArBR,UAAUQ,QAGrI9N,GAAGkO,QAAU,WACT,MAA8B,UAAvBZ,UAAUa,UAGrBnO,GAAGoO,QAAU,WACT,MAAOd,WAAUC,UAAUnE,cAAczD,QAAQ,cAAe,GAKpE3F,GAAGyK,aAAe,WACd,MAAOzK,IAAGoO,WAAad,UAAUC,UAAUnE,cAAczD,QAAQ,UAAY,GAGjF3F,GAAGqO,KAAO,WACN,MAAOrO,IAAGsO,OAAShB,UAAUC,UAAU5H,QAAQ,aAAc,GAGjE3F,GAAGuO,KAAO,WACN,MAAOvO,IAAGsO,OAAShB,UAAUC,UAAU5H,QAAQ,aAAc,GAGjE3F,GAAGwO,KAAO,WACN,MAAOxO,IAAGsO,OAAShB,UAAUC,UAAU5H,QAAQ,aAAc,GAIjE3F,GAAGyO,OAAS,WACR,MAAOzO,IAAGsO,OAAShB,UAAUC,UAAU5H,QAAQ,eAAgB,GAGnE3F,GAAGsO,IAAM,WAEL,MAAOhB,WAAUC,UAAU5H,QAAQ,WAAY,GACxC2H,UAAUC,UAAU5H,QAAQ,WAAY,GACxC2H,UAAUC,UAAU5H,QAAQ,aAAc,GAGrD3F,GAAG0O,UAAY,WACX,MAAO1O,IAAGsO,OAAShB,UAAUC,UAAU5H,QAAQ,YAAa,GAGhE3F,GAAG2O,UAAY,WACX,MAAO3O,IAAGsO,QAAUtO,GAAG0O,aAAepB,UAAUC,UAAU5H,QAAQ,aAAc,GAGpF3F,GAAG4O,iBAAmB,WAClB,MAAO5O,IAAGsO,QAAUtO,GAAG0O,cAAgB1O,GAAG2O,aAM9C3O,GAAG6O,eAAiB,SAASC,GACrBA,EAAED,eACFC,EAAED,iBAEFC,EAAEC,aAAc,GAQxB/O,GAAGgP,UAAa,WACZ,GAAIC,GAAMtF,SAASC,cAAc,MACjC,OAAO,UAASsF,GACZD,EAAIE,UAAYD,CAChB,IAAIjP,GAAUgP,EAAI3L,UAElB,OADA2L,GAAI5N,YAAYpB,GACTA,MAKfD,GAAG+C,KAAO,SAASqM,EAAcC,GAC7B,GAAIC,GAAYC,CAEhB,IAAIH,EAEA,GAAIlK,OAAOsK,SAAWJ,EAAanI,cAAgB/B,OAAOsK,QACtD,IAAKF,EAAa,EAAGA,EAAaF,EAAarJ,SAC3CwJ,EAASF,EAASD,EAAaK,IAAIH,GAAaF,EAAaM,QAAQN,EAAaK,IAAIH,KAClFC,KAAW,GAFoCD,SAStD,IAAItP,GAAG8G,QAAQsI,IAAiBpP,GAAGkH,WAAWkI,IAAiBpP,GAAGoH,WAAWgI,GAC9E,IAAKE,EAAa,EAAGA,EAAaF,EAAarJ,SAC3CwJ,EAASF,EAASC,EAAYF,EAAaE,IACvCC,KAAW,GAFoCD,SAOtD,IAAItP,GAAGwH,SAAS4H,GACjB,IAAKE,EAAa,EAAGA,EAAaF,EAAarJ,SAC3CwJ,EAASF,EAASC,EAAYF,EAAaO,OAAOL,IAC9CC,KAAW,GAFoCD,SAQvD,KAAKA,IAAcF,GACf,GAAI3I,OAAOC,UAAUsG,eAAepG,KAAKwI,EAAcE,KACnDC,EAASF,EAASC,EAAYF,EAAaE,IACvCC,KAAW,GACX,OASxBvP,GAAG4P,KAAO,SAASC,EAASC,GACxB,GAAI9P,GAAG6G,WAAWgJ,GAAU,CACxB,GAAI7H,GAAQC,MAAMvB,UAAUwB,MAAMtB,KAAKuB,UAAW,EAElD,OAAO,YACH,GAAI4H,GAAU/P,GAAG6B,UAAWmG,EAI5B,OAHIG,WAAUpC,SACVgK,EAAUA,EAAQC,OAAO/H,MAAMvB,UAAUwB,MAAMtB,KAAKuB,aAEjD0H,EAAQI,MAAMH,EAASC,IAItC,KAAM,IAAIvO,OAAM,wCAmBpBxB,GAAGkQ,QAAU,SAASC,EAAKC,EAAMC,GAE7B,GAAIC,MACAC,EAAS,IACTC,EAAM,SAASC,EAASC,GACpB,GAAIC,GAAWP,EACR,QAAQjO,KAAKiO,GACdA,EACAA,EAAO,IAAMM,EAAI,IACjBA,CACY,eAAbC,GAAoC,cAAND,GAC/BJ,EAAWpN,KACa,gBAAZuN,GACFzQ,GAAGkQ,QAAQO,EAASE,GAAU,GACe,sBAA5ClK,OAAOC,UAAUC,SAASC,KAAK6J,GAChCG,mBAAmBD,GAAY,IAAMC,mBAAmBH,KACxDG,mBAAmBD,GAAY,IAAMC,mBAAmBH,IAqB9E,QAhBKJ,GAAcD,GACfG,EAAU,KAAKpO,KAAKiO,GAAU,MAAMjO,KAAKiO,GAAS,GAAK,IAAM,IAC7DE,EAAWpN,KAAKkN,GAChBE,EAAWpN,KAAKlD,GAAGkQ,QAAQC,KACqB,mBAAxC1J,OAAOC,UAAUC,SAASC,KAAKuJ,IAA8C,SAARA,EAC7EnQ,GAAG+C,KAAKoN,EAAK,SAASnN,EAAKC,GACvBuN,EAAIvN,EAAKD,KAEU,SAARmN,GAAiC,OAARA,GAAiC,gBAARA,GACjEnQ,GAAG+C,KAAKoN,EAAK,SAAS/D,EAAMnJ,GACxBuN,EAAIvN,EAAKmJ,KAGbkE,EAAWpN,KAAK0N,mBAAmBR,GAAQ,IAAMQ,mBAAmBT,IAGpEC,EACOE,EAAWO,KAAKN,GAEhBD,EAAWO,KAAKN,GAClBhO,QAAQ,KAAM,IACdA,QAAQ,OAAQ,MAI7BvC,GAAG8Q,aAAe,SAASX,EAAKY,EAAUC,GAmBtC,MAlBKD,KACDA,EAAW,GAAIjH,WAGnB9J,GAAG+C,KAAKoN,EAAK,SAASV,EAAKxM,GACvBwM,EAAMuB,EAAeA,EAAe,IAAMvB,EAAM,IAAMA,EAElDzP,GAAGuG,SAAStD,GACZjD,GAAG8Q,aAAa7N,EAAK8N,EAAUtB,GAE1BzP,GAAG6G,WAAW5D,GACnB8N,EAASxL,OAAOkK,EAAKxM,KAGrB8N,EAASxL,OAAOkK,EAAKxM,KAItB8N,GAGX/Q,GAAGiR,WAAa,SAASd,EAAKe,GAC1B,GAAIxH,EAeJ,OAbKwH,KACDA,EAAOvH,SAASC,cAAc,SAGlC5J,GAAG8Q,aAAaX,GACZ5K,OAAQ,SAASkK,EAAKxM,GAClByG,EAAQC,SAASC,cAAc,SAC/BF,EAAMyH,aAAa,OAAQ1B,GAC3B/F,EAAMyH,aAAa,QAASlO,GAC5BiO,EAAKE,YAAY1H,MAIlBwH,GAOXlR,GAAGqR,UAAY,SAASC,MAEpB,MAAIpM,QAAOqM,MAAQvR,GAAG6G,WAAW0K,KAAKC,OAC3BD,KAAKC,MAAMF,MAEXG,KAAK,IAAMH,KAAO,MAUjCtR,GAAG0R,aAAe,SAASC,GACvB,GAAIC,GAASD,EAASE,YAAY,KAAO,CAEzC,IAAID,EAAS,EACT,MAAOD,GAASG,OAAOF,EAAQD,EAAS5L,OAAS6L,IAIzD5R,GAAG+R,YAAc,SAASC,GAGtB,MAAIhS,IAAG+I,QAAQiJ,GAEJA,EAAgBjL,MAAMxE,QAAQ,YAAa,IAE7CvC,GAAGuI,OAAOyJ,IACkB,OAA7BA,EAAgBC,UAAkD9N,SAA7B6N,EAAgBC,SAC9CD,EAAgBC,SAIxBD,EAAgBjQ,MAM3B/B,GAAGkS,eAAiB,WAChB,GAAIC,KAEJ,QAEIC,QAAS,WACL,GAAIC,EACJ,GACIA,GAAWF,EAAUG,QACjBD,GACAA,UAGDA,IAIX/R,OAAQ,WACJ,GAAI0H,GAAOG,SAEX9H,MAAKkS,YAAYvS,GAAGgI,EAAK,IAAI1H,OAAO2P,MAAM5P,KAAM4H,MAAMvB,UAAUwB,MAAMtB,KAAKuB,UAAW,MAI1FoK,YAAa,SAASC,GAClBL,EAAUjP,KAAKsP,SCt2B9B,WACG,YACsB,mBAAXC,SAAyBA,OAAOC,IACvCD,OAAO,WACH,MAAOzS,MAGY,mBAAX2S,SAA0BA,OAAOC,QAC7CD,OAAOC,QAAU5S,GAGjBD,OAAOC,GAAKA,MCXpBA,GAAG6S,QAAU,SCAb7S,GAAG8S,kBAAqB,WACpB,YAkBA,SAASC,KACL,GACIC,GADAC,GAAY,CAGhB,KACID,EAAYrJ,SAASC,cAAc,SACnCoJ,EAAUzS,KAAO,OACjBP,GAAGgT,GAAW9S,OAEV8S,EAAUE,WACVD,GAAY,GAGpB,MAAOE,GACHF,GAAY,EAGhB,MAAOA,GAIX,QAASG,KACL,OAAQpT,GAAG+N,UAAY/N,GAAGgO,UAC+C7J,SAArEmJ,UAAUC,UAAU8F,MAAM,uCAIlC,QAASC,KACL,GAAIpO,OAAO+E,eAAgB,CAIvB,MAA+B9F,UAHrBnE,GAAG+J,oBAGFwJ,gBAGf,OAAO,EAIX,QAASC,KACL,MAAiCrP,UAA1Be,OAAOuO,eAKlB,QAASC,KACL,QAAIJ,KAIGE,IAGX,QAASG,KAEL,MAA2DxP,UAApDwF,SAASC,cAAc,SAASgK,gBAG3C,QAASC,KACL,IACI,QAAS3O,OAAO4O,cAEZ9T,GAAG6G,WAAW3B,OAAO4O,aAAaC,SAE1C,MAAO5J,GAEH,OAAO,GAIf,QAAS6J,KACL,GAAIC,GAAOtK,SAASC,cAAc,OAElC,QAAQ,aAAeqK,IAAS,eAAiBA,IAAQ,UAAYA,MAChEjU,GAAGoO,YAAcpO,GAAGsO,MA1F7B,GAAI4F,GACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,CAwHJ,OAzCAd,GAAoBnB,IAEpBsB,EAA4BH,GAAqBlU,GAAGyJ,uBAEpD0K,EAAyBE,IAA8BrU,GAAGyK,eAE1D2J,EAAmBC,GAA6BL,IAGhDM,EAAqBF,GAAqB,WACtC,GAAI1K,GAAQC,SAASC,cAAc,QAGnC,OADAF,GAAMnJ,KAAO,UACH,oBAAsBmJ,GAASC,SAAS9G,iBAAiB,oBAAoB,QAG3F0R,EAAmBF,GAA6BrU,GAAGwK,0BAEnDgK,EAAiBH,GAA6BE,GAAoBV,IAElEY,EAAyBJ,GAA6BjB,IAEtDsB,EAAqBR,IAA6C/P,SAAvBe,OAAO+P,aAA6BZ,GAE/EO,EAA4BtB,IAE5BqB,EAAwBnB,IAExBqB,EAAyBnB,IAEzBoB,EAA0BnB,IAE1BoB,EAAwBV,GAAmDlQ,SAAtBe,OAAOwG,WAE5DsJ,EAA0B,WACtB,QAAIX,KACQrU,GAAGyK,iBAAmBzK,GAAG0O,iBAMrCwG,cAAeb,EACfc,cAAehB,EACfiB,iBAAkBf,EAClBgB,SAAUd,EACVe,eAAgBT,EAChBU,kBAAmBZ,EACnBa,kBAAmBZ,EACnBa,gBAAiBvQ,OAAOwQ,kBACxBC,SAAUvB,EACVwB,WAAYtB,EACZuB,gBAAiBf,EACjBgB,cAAef,EACfgB,gBAAiBhB,EACjBiB,mBAAoB3B,EACpB4B,MAAO1B,EACP2B,YAAalB,EACbmB,OAAQ3B,EACR4B,QAASrB,GAAyBZ,EAClCkC,aAAcrW,GAAG6N,SACjByI,0BAA2BtW,GAAGsO,MAC9BiI,UAAWrC,EACXsC,WAAY9B,EACZ+B,oBAAqBpC,EACrBqC,mBAAoBrC,EACpBsC,eAAgBlC,MChKxBzU,GAAG4W,iBAAmB,SAASC,GAC3B,YACA,UAAUA,GAAgBA,EAAaC,MAAQ9W,GAAG6G,WAAWgQ,EAAaC,QAG9E9W,GAAG4L,QAAU,WACT,YAEA,IAAImL,GAAaC,EACbC,KACAC,KACAC,KACAC,EAAQ,CAEZpX,IAAG6B,OAAOxB,MACNyW,KAAM,SAASO,EAAWC,GAgBtB,MAfc,KAAVF,GACIC,GACAJ,EAAiB/T,KAAKmU,GAEtBC,GACAJ,EAAiBhU,KAAKoU,IAGrBF,KAAU,EACfE,GAAaA,EAAUrH,MAAM,KAAM+G,GAE9BK,GACLA,EAAUpH,MAAM,KAAM8G,GAGnB1W,MAGXkX,KAAM,SAASlI,GAQX,MAPc,KAAV+H,EACAD,EAAcjU,KAAKmM,GAGnBA,EAASY,MAAM,KAAsB9L,SAAhB6S,EAA4BD,EAAcC,GAG5D3W,MAGXyL,QAAS,WAgBL,MAfAsL,GAAQ,EACRL,EAAc5O,UAEV8O,EAAiBlR,QACjB/F,GAAG+C,KAAKkU,EAAkB,SAASjU,EAAKqM,GACpCA,EAASY,MAAM,KAAM8G,KAIzBI,EAAcpR,QACd/F,GAAG+C,KAAKoU,EAAe,SAASnU,EAAKqM,GACjCA,EAASY,MAAM,KAAM8G,KAItB1W,MAGX2L,QAAS,WAgBL,MAfAoL,IAAQ,EACRJ,EAAc7O,UAEV+O,EAAiBnR,QACjB/F,GAAG+C,KAAKmU,EAAkB,SAASlU,EAAKqM,GACpCA,EAASY,MAAM,KAAM+G,KAIzBG,EAAcpR,QACd/F,GAAG+C,KAAKoU,EAAe,SAASnU,EAAKqM,GACjCA,EAASY,MAAM,KAAM+G,KAItB3W,SClFnBL,GAAGwX,YAAc,SAASC,GACtB,YAoBA,SAASC,GAAmBC,EAAOC,GAE/B,GAAIC,GAAe5P,MAAMvB,UAAUwB,MAAMtB,KAAK+Q,EAE9CG,GAAQC,UAAUC,QAAQ,WAAaL,EAAM5R,OAAS,mBACtD6R,EAAeK,cAAa,GAC5BH,EAAQC,UAAUG,+BAA+BL,EAAcD,EAAeO,cAGlF,QAASC,GAAiBC,GACtB,GAAIC,GAAoB,GAAItY,IAAG4L,OAwC/B,OAtCIyM,GAAM9P,OACN8P,EAAME,KAAK,SAASA,GAChBA,EAAKC,OAASC,EAAqBJ,GACnCK,EAAaxV,KAAKqV,GAClBD,EAAkBxM,WAEtB,SAAS6M,GACLb,EAAQC,UAAUC,QAAQ,oBAAsBK,EAAMO,SAAW,sBAAwBD,EAAUE,KAAO,IAAK,SAC/GP,EAAkBtM,YAGjBqM,EAAMS,aACXC,EAAoBV,GAAOvB,KACvB,SAAwBkC,GACpB,GAAIC,GAAcD,EAAQjT,MAE1B/F,IAAG+C,KAAKiW,EAAS,SAAShW,EAAKqV,GAC3BD,EAAiBC,GAAOd,KAAK,WACzB0B,GAAe,EAEK,IAAhBA,GACAX,EAAkBxM,cAKzBkN,EAAQjT,QACTuS,EAAkBxM,WAI1B,SAAqB6M,GACjBb,EAAQC,UAAUC,QAAQ,oBAAsBK,EAAMO,SAAW,sBAAwBD,EAAUE,KAAO,IAAK,SAC/GP,EAAkBtM,YAKvBsM,EAGX,QAASG,GAAqBJ,GAC1B,GAAItW,GAAOsW,EAAMtW,KACb6W,EAAWP,EAAMO,SACjBM,EAAwBN,EAAS/G,YAAY9P,EAUjD,OAPA6W,GAAWA,EAAS9G,OAAO,EAAGoH,GAGH,MAAvBN,EAASjJ,OAAO,KAChBiJ,EAAWA,EAAS9G,OAAO,IAGxB8G,EAIX,QAASG,GAAoBV,EAAOc,EAAQC,EAAcC,GACtD,GAAI1N,GAAU0N,GAAmB,GAAIrZ,IAAG4L,QACpC0N,EAAYH,GAAUd,EAAMkB,cAmBhC,OAjBAD,GAAUE,YACN,SAAqBR,GACjB,GAAIS,GAAaL,EAAeA,EAAapJ,OAAOgJ,GAAWA,CAE3DA,GAAQjT,OACR2T,WAAW,WACPX,EAAoBV,EAAOiB,EAAWG,EAAY9N,IACnD,GAGHA,EAAQG,QAAQ2N,IAIxB9N,EAAQK,SAGLL,EAGX,QAASgO,GAAmBtP,EAAcuN,GACtC,GAAIgC,MACAC,EAA4B,GAAI7Z,IAAG4L,OA4CvC,OA1CAkM,GAAQC,UAAU+B,yBAClBlC,EAAeK,cAAa,GAExB5N,EAAasN,MAAM5R,OAAS,IAAM+R,EAAQiC,oBAC1CjC,EAAQC,UAAUG,mCAClBJ,EAAQC,UAAUiC,UAAU,oBAAqB,IACjDpC,EAAeK,cAAa,GAC5B4B,EAA0B7N,YAG1B0M,KAEI1Y,GAAGoK,sBAAsBC,GACzBrK,GAAG+C,KAAKsH,EAAaC,MAAO,SAAStH,EAAKsE,GACtC,GAAI+Q,GAAQ/Q,EAAKiD,kBAEb8N,KAEIA,EAAM9P,OACNmQ,EAAaxV,KAAKoE,EAAK2S,aAIvBL,EAAsB1W,KAAKkV,EAAiBC,GAAOd,KAAK,WACpDqC,EAAsBM,MACe,IAAjCN,EAAsB7T,QACtB8T,EAA0B/N,gBAQ9C4M,EAAerO,EAAasN,MAGK,IAAjCiC,EAAsB7T,QACtB8T,EAA0B/N,WAI3B+N,EAGX,QAASM,GAAcC,GACnB,GAAIC,GAAW,GAAIra,IAAGsa,gBAClBC,sBAlKoB,eAmKpBta,QAASma,EACTI,QAAS,SAAS1L,GACd9O,GAAGoa,GAAU/X,SAASyV,EAAQ2C,QAAQC,YACtC5L,EAAE6L,mBAENC,sBAAuB,SAAS9L,GAC5B9O,GAAGoa,GAAU9X,YAAYwV,EAAQ2C,QAAQC,aAE7CG,OAAQ,SAAS/L,GACb6K,EAAmB7K,EAAEzE,aAAcgQ,GAAUvD,KACzC,WACIY,EAAmBgB,EAAc2B,IAErC,WACIvC,EAAQC,UAAUC,QAAQ,sEAAuE,aAcjH,OARA8C,GAAevI,YAAY,WACvB8H,EAASjI,YAGbpS,GAAGoa,GAAUtW,aA1LY,qBA0L4B9D,GAAGoa,GAAUla,OAElE6a,EAAgB7X,KAAKmX,GAEdA,EAGX,QAASW,GAAWC,GAChB,GAAIC,EASJ,OAPAlb,IAAG+C,KAAKkY,EAAU5Q,aAAa8Q,MAAO,SAAS1L,EAAKxM,GAChD,GAAY,UAARA,EAEA,MADAiY,IAAW,GACJ,IAIRA,EAWX,QAASE,GAAmBtM,GACxB,MAAI9O,IAAG6N,SACIiB,EAAEuM,EAAI,GAAKvM,EAAEwM,EAAI,EAGb,IAARxM,EAAEuM,GAAmB,IAARvM,EAAEwM,EAG1B,QAASC,KACL,GAAIC,GAAY1D,EAAQ2D,iBAEpBC,EAAqB,WACjBhC,WAAW,WACP1Z,GAAG+C,KAAKyY,EAAW,SAASxY,EAAKqX,GAC7Bra,GAAGqa,GAAUvW,aApOJ,qBAoO4C9D,GAAGqa,GAAUna,OAClEF,GAAGqa,GAAU/X,YAAYwV,EAAQ2C,QAAQC,eAE9C,IAGX1a,IAAG+C,KAAKyY,EAAW,SAASxY,EAAKqX,GAC7B,GAAIzC,GAAiBuC,EAAcE,EAG/BmB,GAAUzV,QAAU/F,GAAG8S,kBAAkB6C,UACzCmF,EAAexa,OAAOqJ,SAAU,YAAa,SAASmF,IAC7C8I,EAAeK,gBAAkB+C,EAAWlM,IAC7C9O,GAAG+C,KAAKyY,EAAW,SAASxY,EAAKqX,GAGzBA,YAAoBsB,cACpB3b,GAAGqa,GAAUvW,aArPZ,qBAuPD9D,GAAGqa,GAAU/Y,KAAKlB,QAAS,gBAQnD0a,EAAexa,OAAOqJ,SAAU,YAAa,SAASmF,GAC9CsM,EAAmBtM,IACnB4M,MAORZ,EAAexa,OAAON,GAAG2J,UAAUvG,WAAW,GAAI,aAAc,SAAS0L,GACrE4M,MAGJZ,EAAexa,OAAOqJ,SAAU,OAAQ,SAASmF,GACzCkM,EAAWlM,KACXA,EAAED,iBACF6M,OAIRZ,EAAexa,OAAOqJ,SApRE,eAoR+B+R,GArR3D,GAAI5D,GAGAiD,KACArC,KACAoC,EAAiB,GAAI9a,IAAGkS,cAE5B4F,IACI2D,oBACA1B,oBAAoB,EACpBU,SACIC,WAAY,MAEhB3C,UAAW,GAAI/X,IAAGwX,YAAYO,WAGlC/X,GAAG6B,OAAOiW,EAASL,GAAG,GAwQtB8D,IAEAvb,GAAG6B,OAAOxB,MACNub,mBAAoB,SAAS3b,GACzB6X,EAAQ2D,iBAAiBvY,KAAKjD,GAC9Bka,EAAcla,IAGlB4b,eAAgB,SAAS5b,GACrB,GAAIyQ,GACAoL,EAAMhE,EAAQ2D,gBAElB,KAAK/K,IAAKoL,GACN,GAAIA,EAAIpL,KAAOzQ,EACX,MAAO6b,GAAIC,OAAOrL,EAAG,IAKjC0B,QAAS,WACL0I,EAAe1I,UACfpS,GAAG+C,KAAKgY,EAAiB,SAAS/X,EAAKqX,GACnCA,EAASjI,eAKrB/R,KAAK2b,YACL3b,KAAK2b,SAASvD,qBAAuBA,GAGzCzY,GAAGwX,YAAYO,UAAY,WACvB,YAEA,QACI+B,uBAAwB,aACxB5B,+BAAgC,SAASP,EAAOsE,KAChDjC,UAAW,SAASnB,EAAMqD,GACtBlc,GAAGmG,IAAI,2BAA6B0S,EAAO,2BAA6BqD,EAAiB,IAAK,UAElGlE,QAAS,SAAS5R,EAASC,GACvBrG,GAAGmG,IAAIC,EAASC,MAK5BrG,GAAGsa,eAAiB,SAAS7C,GACzB,YAiBA,SAAS0E,KACL,MAAOnc,IAAG6N,UAAa7N,GAAGiO,WAAajO,GAAGkO,UAG9C,QAASkO,GAAmBtN,GAEnBuN,IAGGF,EACArB,EAAexa,OAAOqJ,SAAU,WAAY,SAASmF,GACjDA,EAAED,mBAGNiM,EAAexa,OAAOqJ,SAAU,WAAY,SAASmF,GAC7CA,EAAEzE,eACFyE,EAAEzE,aAAaiS,WAAa,OAC5BxN,EAAED,oBAKdwN,GAAsB,GAI9B,QAASE,GAAgBzN,GAGrB,IAAK9O,GAAG8S,kBAAkB6C,SACtB,OAAO,CAGX,IAAI6G,GAAYC,EAAK3N,EAAEzE,aAEvBqS,EAAW1c,GAAG6N,QAOd,OADA2O,MAAaxc,GAAGqN,OAAQrN,GAAG8S,kBAAkB6C,WAAuC,SAArB8G,EAAGE,cAC3DF,GAAMD,IAEAC,EAAG9E,OAAS8E,EAAG9E,MAAM5R,SACpB2W,GAAYD,EAAGtB,MAAMra,UAAY2b,EAAGtB,MAAMra,SAAS,UACpD2b,EAAGtB,MAAMyB,UAAYH,EAAGtB,MAAMyB,SAAS,UAIxD,QAASC,GAAoBC,GAIzB,MAHmB3Y,UAAf2Y,IACAC,EAAcD,GAEXC,EAGX,QAASC,KAGL,QAASC,KACLC,EAAiBvT,SAASwT,YAAY,SACtCD,EAAeE,UAAUtF,EAAQyC,uBAAuB,GAAM,GAJlE,GAAI2C,EAOJ,IAAIhY,OAAOmY,YACP,IACIH,EAAiB,GAAIG,aAAYvF,EAAQyC,uBAE7C,MAAO+C,GACHL,QAIJA,IAGJtT,UAAS4T,cAAcL,GAG3B,QAASM,KACL1C,EAAexa,OAAOL,EAAS,WAAY,SAAS6O,GAChD,GAAKyN,EAAgBzN,GAArB,CAMA,GAAI2O,GAASzd,GAAGqN,MAAQrN,GAAG8S,kBAAkB6C,SAAW,KAAO7G,EAAEzE,aAAasS,aAE1E7N,GAAEzE,aAAaiS,WADJ,SAAXmB,GAAgC,aAAXA,EACO,OAEA,OAGhC3O,EAAE6L,kBACF7L,EAAED,oBAGNiM,EAAexa,OAAOL,EAAS,YAAa,SAAS6O,GACjD,IAAK+N,IAAuB,CACxB,IAAKN,EAAgBzN,GACjB,MAEJgJ,GAAQ0C,QAAQ1L,MAIxBgM,EAAexa,OAAOL,EAAS,YAAa,SAAS6O,GACjD,GAAKyN,EAAgBzN,GAArB,CAIAgJ,EAAQ4F,QAAQ5O,EAEhB,IAAI6O,GAAgBhU,SAASiU,iBAAiB9O,EAAE+O,QAAS/O,EAAEgP,QAEvD9d,IAAGK,MAAMS,SAAS6c,IAItB7F,EAAQ8C,sBAAsB9L,MAGlCgM,EAAexa,OAAOL,EAAS,OAAQ,SAAS6O,GAC5C,IAAK+N,IAAuB,CACxB,IAAKN,EAAgBzN,GACjB,MAGJA,GAAED,iBACFC,EAAE6L,kBACF7C,EAAQ+C,OAAO/L,GAEfkO,OArJZ,GACIlF,GAAS7X,EAAS8c,EAAaV,EAD/BvB,EAAiB,GAAI9a,IAAGkS,cAG5B4F,IACI7X,QAAS,KACTua,QAAS,SAAS1L,KAClB4O,QAAS,SAAS5O,KAElB8L,sBAAuB,SAAS9L,KAChC+L,OAAQ,SAAS/L,MAGrB9O,GAAG6B,OAAOiW,EAASL,GACnBxX,EAAU6X,EAAQ7X,QA6IlBmc,IACAoB,IAEAxd,GAAG6B,OAAOxB,MACN4X,aAAc,SAAS6E,GACnB,MAAOD,GAAoBC,IAG/B1K,QAAS,WACL0I,EAAe1I,WAGnB+F,WAAY,WACR,MAAOlY,MAIfI,KAAK2b,YACL3b,KAAK2b,SAASO,gBAAkBA,INzfLrX","file":"dnd.min.js","sourcesContent":[null,"/*globals window, navigator, document, FormData, File, HTMLInputElement, XMLHttpRequest, Blob, Storage, ActiveXObject */\n/* jshint -W079 */\nvar qq = function(element) {\n \"use strict\";\n\n return {\n hide: function() {\n element.style.display = \"none\";\n return this;\n },\n\n /** Returns the function which detaches attached event */\n attach: function(type, fn) {\n if (element.addEventListener) {\n element.addEventListener(type, fn, false);\n } else if (element.attachEvent) {\n element.attachEvent(\"on\" + type, fn);\n }\n return function() {\n qq(element).detach(type, fn);\n };\n },\n\n detach: function(type, fn) {\n if (element.removeEventListener) {\n element.removeEventListener(type, fn, false);\n } else if (element.attachEvent) {\n element.detachEvent(\"on\" + type, fn);\n }\n return this;\n },\n\n contains: function(descendant) {\n // The [W3C spec](http://www.w3.org/TR/domcore/#dom-node-contains)\n // says a `null` (or ostensibly `undefined`) parameter\n // passed into `Node.contains` should result in a false return value.\n // IE7 throws an exception if the parameter is `undefined` though.\n if (!descendant) {\n return false;\n }\n\n // compareposition returns false in this case\n if (element === descendant) {\n return true;\n }\n\n if (element.contains) {\n return element.contains(descendant);\n } else {\n /*jslint bitwise: true*/\n return !!(descendant.compareDocumentPosition(element) & 8);\n }\n },\n\n /**\n * Insert this element before elementB.\n */\n insertBefore: function(elementB) {\n elementB.parentNode.insertBefore(element, elementB);\n return this;\n },\n\n remove: function() {\n element.parentNode.removeChild(element);\n return this;\n },\n\n /**\n * Sets styles for an element.\n * Fixes opacity in IE6-8.\n */\n css: function(styles) {\n /*jshint eqnull: true*/\n if (element.style == null) {\n throw new qq.Error(\"Can't apply style to node as it is not on the HTMLElement prototype chain!\");\n }\n\n /*jshint -W116*/\n if (styles.opacity != null) {\n if (typeof element.style.opacity !== \"string\" && typeof (element.filters) !== \"undefined\") {\n styles.filter = \"alpha(opacity=\" + Math.round(100 * styles.opacity) + \")\";\n }\n }\n qq.extend(element.style, styles);\n\n return this;\n },\n\n hasClass: function(name, considerParent) {\n var re = new RegExp(\"(^| )\" + name + \"( |$)\");\n return re.test(element.className) || !!(considerParent && re.test(element.parentNode.className));\n },\n\n addClass: function(name) {\n if (!qq(element).hasClass(name)) {\n element.className += \" \" + name;\n }\n return this;\n },\n\n removeClass: function(name) {\n var re = new RegExp(\"(^| )\" + name + \"( |$)\");\n element.className = element.className.replace(re, \" \").replace(/^\\s+|\\s+$/g, \"\");\n return this;\n },\n\n getByClass: function(className, first) {\n var candidates,\n result = [];\n\n if (first && element.querySelector) {\n return element.querySelector(\".\" + className);\n }\n else if (element.querySelectorAll) {\n return element.querySelectorAll(\".\" + className);\n }\n\n candidates = element.getElementsByTagName(\"*\");\n\n qq.each(candidates, function(idx, val) {\n if (qq(val).hasClass(className)) {\n result.push(val);\n }\n });\n return first ? result[0] : result;\n },\n\n getFirstByClass: function(className) {\n return qq(element).getByClass(className, true);\n },\n\n children: function() {\n var children = [],\n child = element.firstChild;\n\n while (child) {\n if (child.nodeType === 1) {\n children.push(child);\n }\n child = child.nextSibling;\n }\n\n return children;\n },\n\n setText: function(text) {\n element.innerText = text;\n element.textContent = text;\n return this;\n },\n\n clearText: function() {\n return qq(element).setText(\"\");\n },\n\n // Returns true if the attribute exists on the element\n // AND the value of the attribute is NOT \"false\" (case-insensitive)\n hasAttribute: function(attrName) {\n var attrVal;\n\n if (element.hasAttribute) {\n\n if (!element.hasAttribute(attrName)) {\n return false;\n }\n\n /*jshint -W116*/\n return (/^false$/i).exec(element.getAttribute(attrName)) == null;\n }\n else {\n attrVal = element[attrName];\n\n if (attrVal === undefined) {\n return false;\n }\n\n /*jshint -W116*/\n return (/^false$/i).exec(attrVal) == null;\n }\n }\n };\n};\n\n(function() {\n \"use strict\";\n\n qq.canvasToBlob = function(canvas, mime, quality) {\n return qq.dataUriToBlob(canvas.toDataURL(mime, quality));\n };\n\n qq.dataUriToBlob = function(dataUri) {\n var arrayBuffer, byteString,\n createBlob = function(data, mime) {\n var BlobBuilder = window.BlobBuilder ||\n window.WebKitBlobBuilder ||\n window.MozBlobBuilder ||\n window.MSBlobBuilder,\n blobBuilder = BlobBuilder && new BlobBuilder();\n\n if (blobBuilder) {\n blobBuilder.append(data);\n return blobBuilder.getBlob(mime);\n }\n else {\n return new Blob([data], {type: mime});\n }\n },\n intArray, mimeString;\n\n // convert base64 to raw binary data held in a string\n if (dataUri.split(\",\")[0].indexOf(\"base64\") >= 0) {\n byteString = atob(dataUri.split(\",\")[1]);\n }\n else {\n byteString = decodeURI(dataUri.split(\",\")[1]);\n }\n\n // extract the MIME\n mimeString = dataUri.split(\",\")[0]\n .split(\":\")[1]\n .split(\";\")[0];\n\n // write the bytes of the binary string to an ArrayBuffer\n arrayBuffer = new ArrayBuffer(byteString.length);\n intArray = new Uint8Array(arrayBuffer);\n qq.each(byteString, function(idx, character) {\n intArray[idx] = character.charCodeAt(0);\n });\n\n return createBlob(arrayBuffer, mimeString);\n };\n\n qq.log = function(message, level) {\n if (window.console) {\n if (!level || level === \"info\") {\n window.console.log(message);\n }\n else\n {\n if (window.console[level]) {\n window.console[level](message);\n }\n else {\n window.console.log(\"<\" + level + \"> \" + message);\n }\n }\n }\n };\n\n qq.isObject = function(variable) {\n return variable && !variable.nodeType && Object.prototype.toString.call(variable) === \"[object Object]\";\n };\n\n qq.isFunction = function(variable) {\n return typeof (variable) === \"function\";\n };\n\n /**\n * Check the type of a value. Is it an \"array\"?\n *\n * @param value value to test.\n * @returns true if the value is an array or associated with an `ArrayBuffer`\n */\n qq.isArray = function(value) {\n return Object.prototype.toString.call(value) === \"[object Array]\" ||\n (value && window.ArrayBuffer && value.buffer && value.buffer.constructor === ArrayBuffer);\n };\n\n // Looks for an object on a `DataTransfer` object that is associated with drop events when utilizing the Filesystem API.\n qq.isItemList = function(maybeItemList) {\n return Object.prototype.toString.call(maybeItemList) === \"[object DataTransferItemList]\";\n };\n\n // Looks for an object on a `NodeList` or an `HTMLCollection`|`HTMLFormElement`|`HTMLSelectElement`\n // object that is associated with collections of Nodes.\n qq.isNodeList = function(maybeNodeList) {\n return Object.prototype.toString.call(maybeNodeList) === \"[object NodeList]\" ||\n // If `HTMLCollection` is the actual type of the object, we must determine this\n // by checking for expected properties/methods on the object\n (maybeNodeList.item && maybeNodeList.namedItem);\n };\n\n qq.isString = function(maybeString) {\n return Object.prototype.toString.call(maybeString) === \"[object String]\";\n };\n\n qq.trimStr = function(string) {\n if (String.prototype.trim) {\n return string.trim();\n }\n\n return string.replace(/^\\s+|\\s+$/g, \"\");\n };\n\n /**\n * @param str String to format.\n * @returns {string} A string, swapping argument values with the associated occurrence of {} in the passed string.\n */\n qq.format = function(str) {\n\n var args = Array.prototype.slice.call(arguments, 1),\n newStr = str,\n nextIdxToReplace = newStr.indexOf(\"{}\");\n\n qq.each(args, function(idx, val) {\n var strBefore = newStr.substring(0, nextIdxToReplace),\n strAfter = newStr.substring(nextIdxToReplace + 2);\n\n newStr = strBefore + val + strAfter;\n nextIdxToReplace = newStr.indexOf(\"{}\", nextIdxToReplace + val.length);\n\n // End the loop if we have run out of tokens (when the arguments exceed the # of tokens)\n if (nextIdxToReplace < 0) {\n return false;\n }\n });\n\n return newStr;\n };\n\n qq.isFile = function(maybeFile) {\n return window.File && Object.prototype.toString.call(maybeFile) === \"[object File]\";\n };\n\n qq.isFileList = function(maybeFileList) {\n return window.FileList && Object.prototype.toString.call(maybeFileList) === \"[object FileList]\";\n };\n\n qq.isFileOrInput = function(maybeFileOrInput) {\n return qq.isFile(maybeFileOrInput) || qq.isInput(maybeFileOrInput);\n };\n\n qq.isInput = function(maybeInput, notFile) {\n var evaluateType = function(type) {\n var normalizedType = type.toLowerCase();\n\n if (notFile) {\n return normalizedType !== \"file\";\n }\n\n return normalizedType === \"file\";\n };\n\n if (window.HTMLInputElement) {\n if (Object.prototype.toString.call(maybeInput) === \"[object HTMLInputElement]\") {\n if (maybeInput.type && evaluateType(maybeInput.type)) {\n return true;\n }\n }\n }\n if (maybeInput.tagName) {\n if (maybeInput.tagName.toLowerCase() === \"input\") {\n if (maybeInput.type && evaluateType(maybeInput.type)) {\n return true;\n }\n }\n }\n\n return false;\n };\n\n qq.isBlob = function(maybeBlob) {\n if (window.Blob && Object.prototype.toString.call(maybeBlob) === \"[object Blob]\") {\n return true;\n }\n };\n\n qq.isXhrUploadSupported = function() {\n var input = document.createElement(\"input\");\n input.type = \"file\";\n\n return (\n input.multiple !== undefined &&\n typeof File !== \"undefined\" &&\n typeof FormData !== \"undefined\" &&\n typeof (qq.createXhrInstance()).upload !== \"undefined\");\n };\n\n // Fall back to ActiveX is native XHR is disabled (possible in any version of IE).\n qq.createXhrInstance = function() {\n if (window.XMLHttpRequest) {\n return new XMLHttpRequest();\n }\n\n try {\n return new ActiveXObject(\"MSXML2.XMLHTTP.3.0\");\n }\n catch (error) {\n qq.log(\"Neither XHR or ActiveX are supported!\", \"error\");\n return null;\n }\n };\n\n qq.isFolderDropSupported = function(dataTransfer) {\n return dataTransfer.items &&\n dataTransfer.items.length > 0 &&\n dataTransfer.items[0].webkitGetAsEntry;\n };\n\n qq.isFileChunkingSupported = function() {\n return !qq.androidStock() && //Android's stock browser cannot upload Blobs correctly\n qq.isXhrUploadSupported() &&\n (File.prototype.slice !== undefined || File.prototype.webkitSlice !== undefined || File.prototype.mozSlice !== undefined);\n };\n\n qq.sliceBlob = function(fileOrBlob, start, end) {\n var slicer = fileOrBlob.slice || fileOrBlob.mozSlice || fileOrBlob.webkitSlice;\n\n return slicer.call(fileOrBlob, start, end);\n };\n\n qq.arrayBufferToHex = function(buffer) {\n var bytesAsHex = \"\",\n bytes = new Uint8Array(buffer);\n\n qq.each(bytes, function(idx, byt) {\n var byteAsHexStr = byt.toString(16);\n\n if (byteAsHexStr.length < 2) {\n byteAsHexStr = \"0\" + byteAsHexStr;\n }\n\n bytesAsHex += byteAsHexStr;\n });\n\n return bytesAsHex;\n };\n\n qq.readBlobToHex = function(blob, startOffset, length) {\n var initialBlob = qq.sliceBlob(blob, startOffset, startOffset + length),\n fileReader = new FileReader(),\n promise = new qq.Promise();\n\n fileReader.onload = function() {\n promise.success(qq.arrayBufferToHex(fileReader.result));\n };\n\n fileReader.onerror = promise.failure;\n\n fileReader.readAsArrayBuffer(initialBlob);\n\n return promise;\n };\n\n qq.extend = function(first, second, extendNested) {\n qq.each(second, function(prop, val) {\n if (extendNested && qq.isObject(val)) {\n if (first[prop] === undefined) {\n first[prop] = {};\n }\n qq.extend(first[prop], val, true);\n }\n else {\n first[prop] = val;\n }\n });\n\n return first;\n };\n\n /**\n * Allow properties in one object to override properties in another,\n * keeping track of the original values from the target object.\n *\n * Note that the pre-overriden properties to be overriden by the source will be passed into the `sourceFn` when it is invoked.\n *\n * @param target Update properties in this object from some source\n * @param sourceFn A function that, when invoked, will return properties that will replace properties with the same name in the target.\n * @returns {object} The target object\n */\n qq.override = function(target, sourceFn) {\n var super_ = {},\n source = sourceFn(super_);\n\n qq.each(source, function(srcPropName, srcPropVal) {\n if (target[srcPropName] !== undefined) {\n super_[srcPropName] = target[srcPropName];\n }\n\n target[srcPropName] = srcPropVal;\n });\n\n return target;\n };\n\n /**\n * Searches for a given element (elt) in the array, returns -1 if it is not present.\n */\n qq.indexOf = function(arr, elt, from) {\n if (arr.indexOf) {\n return arr.indexOf(elt, from);\n }\n\n from = from || 0;\n var len = arr.length;\n\n if (from < 0) {\n from += len;\n }\n\n for (; from < len; from += 1) {\n if (arr.hasOwnProperty(from) && arr[from] === elt) {\n return from;\n }\n }\n return -1;\n };\n\n //this is a version 4 UUID\n qq.getUniqueId = function() {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, function(c) {\n /*jslint eqeq: true, bitwise: true*/\n var r = Math.random() * 16 | 0, v = c == \"x\" ? r : (r & 0x3 | 0x8);\n return v.toString(16);\n });\n };\n\n //\n // Browsers and platforms detection\n qq.ie = function() {\n return navigator.userAgent.indexOf(\"MSIE\") !== -1 ||\n navigator.userAgent.indexOf(\"Trident\") !== -1;\n };\n\n qq.ie7 = function() {\n return navigator.userAgent.indexOf(\"MSIE 7\") !== -1;\n };\n\n qq.ie8 = function() {\n return navigator.userAgent.indexOf(\"MSIE 8\") !== -1;\n };\n\n qq.ie10 = function() {\n return navigator.userAgent.indexOf(\"MSIE 10\") !== -1;\n };\n\n qq.ie11 = function() {\n return qq.ie() && navigator.userAgent.indexOf(\"rv:11\") !== -1;\n };\n\n qq.edge = function() {\n return navigator.userAgent.indexOf(\"Edge\") >= 0;\n };\n\n qq.safari = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Apple\") !== -1;\n };\n\n qq.chrome = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Google\") !== -1;\n };\n\n qq.opera = function() {\n return navigator.vendor !== undefined && navigator.vendor.indexOf(\"Opera\") !== -1;\n };\n\n qq.firefox = function() {\n return (!qq.edge() && !qq.ie11() && navigator.userAgent.indexOf(\"Mozilla\") !== -1 && navigator.vendor !== undefined && navigator.vendor === \"\");\n };\n\n qq.windows = function() {\n return navigator.platform === \"Win32\";\n };\n\n qq.android = function() {\n return navigator.userAgent.toLowerCase().indexOf(\"android\") !== -1;\n };\n\n // We need to identify the Android stock browser via the UA string to work around various bugs in this browser,\n // such as the one that prevents a `Blob` from being uploaded.\n qq.androidStock = function() {\n return qq.android() && navigator.userAgent.toLowerCase().indexOf(\"chrome\") < 0;\n };\n\n qq.ios6 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 6_\") !== -1;\n };\n\n qq.ios7 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 7_\") !== -1;\n };\n\n qq.ios8 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 8_\") !== -1;\n };\n\n // iOS 8.0.0\n qq.ios800 = function() {\n return qq.ios() && navigator.userAgent.indexOf(\" OS 8_0 \") !== -1;\n };\n\n qq.ios = function() {\n /*jshint -W014 */\n return navigator.userAgent.indexOf(\"iPad\") !== -1\n || navigator.userAgent.indexOf(\"iPod\") !== -1\n || navigator.userAgent.indexOf(\"iPhone\") !== -1;\n };\n\n qq.iosChrome = function() {\n return qq.ios() && navigator.userAgent.indexOf(\"CriOS\") !== -1;\n };\n\n qq.iosSafari = function() {\n return qq.ios() && !qq.iosChrome() && navigator.userAgent.indexOf(\"Safari\") !== -1;\n };\n\n qq.iosSafariWebView = function() {\n return qq.ios() && !qq.iosChrome() && !qq.iosSafari();\n };\n\n //\n // Events\n\n qq.preventDefault = function(e) {\n if (e.preventDefault) {\n e.preventDefault();\n } else {\n e.returnValue = false;\n }\n };\n\n /**\n * Creates and returns element from html string\n * Uses innerHTML to create an element\n */\n qq.toElement = (function() {\n var div = document.createElement(\"div\");\n return function(html) {\n div.innerHTML = html;\n var element = div.firstChild;\n div.removeChild(element);\n return element;\n };\n }());\n\n //key and value are passed to callback for each entry in the iterable item\n qq.each = function(iterableItem, callback) {\n var keyOrIndex, retVal;\n\n if (iterableItem) {\n // Iterate through [`Storage`](http://www.w3.org/TR/webstorage/#the-storage-interface) items\n if (window.Storage && iterableItem.constructor === window.Storage) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(iterableItem.key(keyOrIndex), iterableItem.getItem(iterableItem.key(keyOrIndex)));\n if (retVal === false) {\n break;\n }\n }\n }\n // `DataTransferItemList` & `NodeList` objects are array-like and should be treated as arrays\n // when iterating over items inside the object.\n else if (qq.isArray(iterableItem) || qq.isItemList(iterableItem) || qq.isNodeList(iterableItem)) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);\n if (retVal === false) {\n break;\n }\n }\n }\n else if (qq.isString(iterableItem)) {\n for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) {\n retVal = callback(keyOrIndex, iterableItem.charAt(keyOrIndex));\n if (retVal === false) {\n break;\n }\n }\n }\n else {\n for (keyOrIndex in iterableItem) {\n if (Object.prototype.hasOwnProperty.call(iterableItem, keyOrIndex)) {\n retVal = callback(keyOrIndex, iterableItem[keyOrIndex]);\n if (retVal === false) {\n break;\n }\n }\n }\n }\n }\n };\n\n //include any args that should be passed to the new function after the context arg\n qq.bind = function(oldFunc, context) {\n if (qq.isFunction(oldFunc)) {\n var args = Array.prototype.slice.call(arguments, 2);\n\n return function() {\n var newArgs = qq.extend([], args);\n if (arguments.length) {\n newArgs = newArgs.concat(Array.prototype.slice.call(arguments));\n }\n return oldFunc.apply(context, newArgs);\n };\n }\n\n throw new Error(\"first parameter must be a function!\");\n };\n\n /**\n * obj2url() takes a json-object as argument and generates\n * a querystring. pretty much like jQuery.param()\n *\n * how to use:\n *\n * `qq.obj2url({a:'b',c:'d'},'http://any.url/upload?otherParam=value');`\n *\n * will result in:\n *\n * `http://any.url/upload?otherParam=value&a=b&c=d`\n *\n * @param Object JSON-Object\n * @param String current querystring-part\n * @return String encoded querystring\n */\n qq.obj2url = function(obj, temp, prefixDone) {\n /*jshint laxbreak: true*/\n var uristrings = [],\n prefix = \"&\",\n add = function(nextObj, i) {\n var nextTemp = temp\n ? (/\\[\\]$/.test(temp)) // prevent double-encoding\n ? temp\n : temp + \"[\" + i + \"]\"\n : i;\n if ((nextTemp !== \"undefined\") && (i !== \"undefined\")) {\n uristrings.push(\n (typeof nextObj === \"object\")\n ? qq.obj2url(nextObj, nextTemp, true)\n : (Object.prototype.toString.call(nextObj) === \"[object Function]\")\n ? encodeURIComponent(nextTemp) + \"=\" + encodeURIComponent(nextObj())\n : encodeURIComponent(nextTemp) + \"=\" + encodeURIComponent(nextObj)\n );\n }\n };\n\n if (!prefixDone && temp) {\n prefix = (/\\?/.test(temp)) ? (/\\?$/.test(temp)) ? \"\" : \"&\" : \"?\";\n uristrings.push(temp);\n uristrings.push(qq.obj2url(obj));\n } else if ((Object.prototype.toString.call(obj) === \"[object Array]\") && (typeof obj !== \"undefined\")) {\n qq.each(obj, function(idx, val) {\n add(val, idx);\n });\n } else if ((typeof obj !== \"undefined\") && (obj !== null) && (typeof obj === \"object\")) {\n qq.each(obj, function(prop, val) {\n add(val, prop);\n });\n } else {\n uristrings.push(encodeURIComponent(temp) + \"=\" + encodeURIComponent(obj));\n }\n\n if (temp) {\n return uristrings.join(prefix);\n } else {\n return uristrings.join(prefix)\n .replace(/^&/, \"\")\n .replace(/%20/g, \"+\");\n }\n };\n\n qq.obj2FormData = function(obj, formData, arrayKeyName) {\n if (!formData) {\n formData = new FormData();\n }\n\n qq.each(obj, function(key, val) {\n key = arrayKeyName ? arrayKeyName + \"[\" + key + \"]\" : key;\n\n if (qq.isObject(val)) {\n qq.obj2FormData(val, formData, key);\n }\n else if (qq.isFunction(val)) {\n formData.append(key, val());\n }\n else {\n formData.append(key, val);\n }\n });\n\n return formData;\n };\n\n qq.obj2Inputs = function(obj, form) {\n var input;\n\n if (!form) {\n form = document.createElement(\"form\");\n }\n\n qq.obj2FormData(obj, {\n append: function(key, val) {\n input = document.createElement(\"input\");\n input.setAttribute(\"name\", key);\n input.setAttribute(\"value\", val);\n form.appendChild(input);\n }\n });\n\n return form;\n };\n\n /**\n * Not recommended for use outside of Fine Uploader since this falls back to an unchecked eval if JSON.parse is not\n * implemented. For a more secure JSON.parse polyfill, use Douglas Crockford's json2.js.\n */\n qq.parseJson = function(json) {\n /*jshint evil: true*/\n if (window.JSON && qq.isFunction(JSON.parse)) {\n return JSON.parse(json);\n } else {\n return eval(\"(\" + json + \")\");\n }\n };\n\n /**\n * Retrieve the extension of a file, if it exists.\n *\n * @param filename\n * @returns {string || undefined}\n */\n qq.getExtension = function(filename) {\n var extIdx = filename.lastIndexOf(\".\") + 1;\n\n if (extIdx > 0) {\n return filename.substr(extIdx, filename.length - extIdx);\n }\n };\n\n qq.getFilename = function(blobOrFileInput) {\n /*jslint regexp: true*/\n\n if (qq.isInput(blobOrFileInput)) {\n // get input value and remove path to normalize\n return blobOrFileInput.value.replace(/.*(\\/|\\\\)/, \"\");\n }\n else if (qq.isFile(blobOrFileInput)) {\n if (blobOrFileInput.fileName !== null && blobOrFileInput.fileName !== undefined) {\n return blobOrFileInput.fileName;\n }\n }\n\n return blobOrFileInput.name;\n };\n\n /**\n * A generic module which supports object disposing in dispose() method.\n * */\n qq.DisposeSupport = function() {\n var disposers = [];\n\n return {\n /** Run all registered disposers */\n dispose: function() {\n var disposer;\n do {\n disposer = disposers.shift();\n if (disposer) {\n disposer();\n }\n }\n while (disposer);\n },\n\n /** Attach event handler and register de-attacher as a disposer */\n attach: function() {\n var args = arguments;\n /*jslint undef:true*/\n this.addDisposer(qq(args[0]).attach.apply(this, Array.prototype.slice.call(arguments, 1)));\n },\n\n /** Add disposer to the collection */\n addDisposer: function(disposeFunction) {\n disposers.push(disposeFunction);\n }\n };\n };\n}());\n","/* globals define, module, global, qq */\n(function() {\n \"use strict\";\n if (typeof define === \"function\" && define.amd) {\n define(function() {\n return qq;\n });\n }\n else if (typeof module !== \"undefined\" && module.exports) {\n module.exports = qq;\n }\n else {\n global.qq = qq;\n }\n}());\n","/*global qq */\nqq.version = \"5.16.2\";\n","/* globals qq */\nqq.supportedFeatures = (function() {\n \"use strict\";\n\n var supportsUploading,\n supportsUploadingBlobs,\n supportsFileDrop,\n supportsAjaxFileUploading,\n supportsFolderDrop,\n supportsChunking,\n supportsResume,\n supportsUploadViaPaste,\n supportsUploadCors,\n supportsDeleteFileXdr,\n supportsDeleteFileCorsXhr,\n supportsDeleteFileCors,\n supportsFolderSelection,\n supportsImagePreviews,\n supportsUploadProgress;\n\n function testSupportsFileInputElement() {\n var supported = true,\n tempInput;\n\n try {\n tempInput = document.createElement(\"input\");\n tempInput.type = \"file\";\n qq(tempInput).hide();\n\n if (tempInput.disabled) {\n supported = false;\n }\n }\n catch (ex) {\n supported = false;\n }\n\n return supported;\n }\n\n //only way to test for complete Clipboard API support at this time\n function isChrome14OrHigher() {\n return (qq.chrome() || qq.opera()) &&\n navigator.userAgent.match(/Chrome\\/[1][4-9]|Chrome\\/[2-9][0-9]/) !== undefined;\n }\n\n //Ensure we can send cross-origin `XMLHttpRequest`s\n function isCrossOriginXhrSupported() {\n if (window.XMLHttpRequest) {\n var xhr = qq.createXhrInstance();\n\n //Commonly accepted test for XHR CORS support.\n return xhr.withCredentials !== undefined;\n }\n\n return false;\n }\n\n //Test for (terrible) cross-origin ajax transport fallback for IE9 and IE8\n function isXdrSupported() {\n return window.XDomainRequest !== undefined;\n }\n\n // CORS Ajax requests are supported if it is either possible to send credentialed `XMLHttpRequest`s,\n // or if `XDomainRequest` is an available alternative.\n function isCrossOriginAjaxSupported() {\n if (isCrossOriginXhrSupported()) {\n return true;\n }\n\n return isXdrSupported();\n }\n\n function isFolderSelectionSupported() {\n // We know that folder selection is only supported in Chrome via this proprietary attribute for now\n return document.createElement(\"input\").webkitdirectory !== undefined;\n }\n\n function isLocalStorageSupported() {\n try {\n return !!window.localStorage &&\n // unpatched versions of IE10/11 have buggy impls of localStorage where setItem is a string\n qq.isFunction(window.localStorage.setItem);\n }\n catch (error) {\n // probably caught a security exception, so no localStorage for you\n return false;\n }\n }\n\n function isDragAndDropSupported() {\n var span = document.createElement(\"span\");\n\n return (\"draggable\" in span || (\"ondragstart\" in span && \"ondrop\" in span)) &&\n !qq.android() && !qq.ios();\n }\n\n supportsUploading = testSupportsFileInputElement();\n\n supportsAjaxFileUploading = supportsUploading && qq.isXhrUploadSupported();\n\n supportsUploadingBlobs = supportsAjaxFileUploading && !qq.androidStock();\n\n supportsFileDrop = supportsAjaxFileUploading && isDragAndDropSupported();\n\n // adapted from https://stackoverflow.com/a/23278460/486979\n supportsFolderDrop = supportsFileDrop && (function() {\n var input = document.createElement(\"input\");\n\n input.type = \"file\";\n return !!(\"webkitdirectory\" in (input || document.querySelectorAll(\"input[type=file]\")[0]));\n }());\n\n supportsChunking = supportsAjaxFileUploading && qq.isFileChunkingSupported();\n\n supportsResume = supportsAjaxFileUploading && supportsChunking && isLocalStorageSupported();\n\n supportsUploadViaPaste = supportsAjaxFileUploading && isChrome14OrHigher();\n\n supportsUploadCors = supportsUploading && (window.postMessage !== undefined || supportsAjaxFileUploading);\n\n supportsDeleteFileCorsXhr = isCrossOriginXhrSupported();\n\n supportsDeleteFileXdr = isXdrSupported();\n\n supportsDeleteFileCors = isCrossOriginAjaxSupported();\n\n supportsFolderSelection = isFolderSelectionSupported();\n\n supportsImagePreviews = supportsAjaxFileUploading && window.FileReader !== undefined;\n\n supportsUploadProgress = (function() {\n if (supportsAjaxFileUploading) {\n return !qq.androidStock() && !qq.iosChrome();\n }\n return false;\n }());\n\n return {\n ajaxUploading: supportsAjaxFileUploading,\n blobUploading: supportsUploadingBlobs,\n canDetermineSize: supportsAjaxFileUploading,\n chunking: supportsChunking,\n deleteFileCors: supportsDeleteFileCors,\n deleteFileCorsXdr: supportsDeleteFileXdr, //NOTE: will also return true in IE10, where XDR is also supported\n deleteFileCorsXhr: supportsDeleteFileCorsXhr,\n dialogElement: !!window.HTMLDialogElement,\n fileDrop: supportsFileDrop,\n folderDrop: supportsFolderDrop,\n folderSelection: supportsFolderSelection,\n imagePreviews: supportsImagePreviews,\n imageValidation: supportsImagePreviews,\n itemSizeValidation: supportsAjaxFileUploading,\n pause: supportsChunking,\n progressBar: supportsUploadProgress,\n resume: supportsResume,\n scaling: supportsImagePreviews && supportsUploadingBlobs,\n tiffPreviews: qq.safari(), // Not the best solution, but simple and probably accurate enough (for now)\n unlimitedScaledImageSize: !qq.ios(), // false simply indicates that there is some known limit\n uploading: supportsUploading,\n uploadCors: supportsUploadCors,\n uploadCustomHeaders: supportsAjaxFileUploading,\n uploadNonMultipart: supportsAjaxFileUploading,\n uploadViaPaste: supportsUploadViaPaste\n };\n\n}());\n","/*globals qq*/\n\n// Is the passed object a promise instance?\nqq.isGenericPromise = function(maybePromise) {\n \"use strict\";\n return !!(maybePromise && maybePromise.then && qq.isFunction(maybePromise.then));\n};\n\nqq.Promise = function() {\n \"use strict\";\n\n var successArgs, failureArgs,\n successCallbacks = [],\n failureCallbacks = [],\n doneCallbacks = [],\n state = 0;\n\n qq.extend(this, {\n then: function(onSuccess, onFailure) {\n if (state === 0) {\n if (onSuccess) {\n successCallbacks.push(onSuccess);\n }\n if (onFailure) {\n failureCallbacks.push(onFailure);\n }\n }\n else if (state === -1) {\n onFailure && onFailure.apply(null, failureArgs);\n }\n else if (onSuccess) {\n onSuccess.apply(null, successArgs);\n }\n\n return this;\n },\n\n done: function(callback) {\n if (state === 0) {\n doneCallbacks.push(callback);\n }\n else {\n callback.apply(null, failureArgs === undefined ? successArgs : failureArgs);\n }\n\n return this;\n },\n\n success: function() {\n state = 1;\n successArgs = arguments;\n\n if (successCallbacks.length) {\n qq.each(successCallbacks, function(idx, callback) {\n callback.apply(null, successArgs);\n });\n }\n\n if (doneCallbacks.length) {\n qq.each(doneCallbacks, function(idx, callback) {\n callback.apply(null, successArgs);\n });\n }\n\n return this;\n },\n\n failure: function() {\n state = -1;\n failureArgs = arguments;\n\n if (failureCallbacks.length) {\n qq.each(failureCallbacks, function(idx, callback) {\n callback.apply(null, failureArgs);\n });\n }\n\n if (doneCallbacks.length) {\n qq.each(doneCallbacks, function(idx, callback) {\n callback.apply(null, failureArgs);\n });\n }\n\n return this;\n }\n });\n};\n","/*globals qq, document, CustomEvent*/\nqq.DragAndDrop = function(o) {\n \"use strict\";\n\n var options,\n HIDE_ZONES_EVENT_NAME = \"qq-hidezones\",\n HIDE_BEFORE_ENTER_ATTR = \"qq-hide-dropzone\",\n uploadDropZones = [],\n droppedFiles = [],\n disposeSupport = new qq.DisposeSupport();\n\n options = {\n dropZoneElements: [],\n allowMultipleItems: true,\n classes: {\n dropActive: null\n },\n callbacks: new qq.DragAndDrop.callbacks()\n };\n\n qq.extend(options, o, true);\n\n function uploadDroppedFiles(files, uploadDropZone) {\n // We need to convert the `FileList` to an actual `Array` to avoid iteration issues\n var filesAsArray = Array.prototype.slice.call(files);\n\n options.callbacks.dropLog(\"Grabbed \" + files.length + \" dropped files.\");\n uploadDropZone.dropDisabled(false);\n options.callbacks.processingDroppedFilesComplete(filesAsArray, uploadDropZone.getElement());\n }\n\n function traverseFileTree(entry) {\n var parseEntryPromise = new qq.Promise();\n\n if (entry.isFile) {\n entry.file(function(file) {\n file.qqPath = extractDirectoryPath(entry);\n droppedFiles.push(file);\n parseEntryPromise.success();\n },\n function(fileError) {\n options.callbacks.dropLog(\"Problem parsing '\" + entry.fullPath + \"'. FileError code \" + fileError.code + \".\", \"error\");\n parseEntryPromise.failure();\n });\n }\n else if (entry.isDirectory) {\n getFilesInDirectory(entry).then(\n function allEntriesRead(entries) {\n var entriesLeft = entries.length;\n\n qq.each(entries, function(idx, entry) {\n traverseFileTree(entry).done(function() {\n entriesLeft -= 1;\n\n if (entriesLeft === 0) {\n parseEntryPromise.success();\n }\n });\n });\n\n if (!entries.length) {\n parseEntryPromise.success();\n }\n },\n\n function readFailure(fileError) {\n options.callbacks.dropLog(\"Problem parsing '\" + entry.fullPath + \"'. FileError code \" + fileError.code + \".\", \"error\");\n parseEntryPromise.failure();\n }\n );\n }\n\n return parseEntryPromise;\n }\n\n function extractDirectoryPath(entry) {\n var name = entry.name,\n fullPath = entry.fullPath,\n indexOfNameInFullPath = fullPath.lastIndexOf(name);\n\n // remove file name from full path string\n fullPath = fullPath.substr(0, indexOfNameInFullPath);\n\n // remove leading slash in full path string\n if (fullPath.charAt(0) === \"/\") {\n fullPath = fullPath.substr(1);\n }\n\n return fullPath;\n }\n\n // Promissory. Guaranteed to read all files in the root of the passed directory.\n function getFilesInDirectory(entry, reader, accumEntries, existingPromise) {\n var promise = existingPromise || new qq.Promise(),\n dirReader = reader || entry.createReader();\n\n dirReader.readEntries(\n function readSuccess(entries) {\n var newEntries = accumEntries ? accumEntries.concat(entries) : entries;\n\n if (entries.length) {\n setTimeout(function() { // prevent stack overflow, however unlikely\n getFilesInDirectory(entry, dirReader, newEntries, promise);\n }, 0);\n }\n else {\n promise.success(newEntries);\n }\n },\n\n promise.failure\n );\n\n return promise;\n }\n\n function handleDataTransfer(dataTransfer, uploadDropZone) {\n var pendingFolderPromises = [],\n handleDataTransferPromise = new qq.Promise();\n\n options.callbacks.processingDroppedFiles();\n uploadDropZone.dropDisabled(true);\n\n if (dataTransfer.files.length > 1 && !options.allowMultipleItems) {\n options.callbacks.processingDroppedFilesComplete([]);\n options.callbacks.dropError(\"tooManyFilesError\", \"\");\n uploadDropZone.dropDisabled(false);\n handleDataTransferPromise.failure();\n }\n else {\n droppedFiles = [];\n\n if (qq.isFolderDropSupported(dataTransfer)) {\n qq.each(dataTransfer.items, function(idx, item) {\n var entry = item.webkitGetAsEntry();\n\n if (entry) {\n //due to a bug in Chrome's File System API impl - #149735\n if (entry.isFile) {\n droppedFiles.push(item.getAsFile());\n }\n\n else {\n pendingFolderPromises.push(traverseFileTree(entry).done(function() {\n pendingFolderPromises.pop();\n if (pendingFolderPromises.length === 0) {\n handleDataTransferPromise.success();\n }\n }));\n }\n }\n });\n }\n else {\n droppedFiles = dataTransfer.files;\n }\n\n if (pendingFolderPromises.length === 0) {\n handleDataTransferPromise.success();\n }\n }\n\n return handleDataTransferPromise;\n }\n\n function setupDropzone(dropArea) {\n var dropZone = new qq.UploadDropZone({\n HIDE_ZONES_EVENT_NAME: HIDE_ZONES_EVENT_NAME,\n element: dropArea,\n onEnter: function(e) {\n qq(dropArea).addClass(options.classes.dropActive);\n e.stopPropagation();\n },\n onLeaveNotDescendants: function(e) {\n qq(dropArea).removeClass(options.classes.dropActive);\n },\n onDrop: function(e) {\n handleDataTransfer(e.dataTransfer, dropZone).then(\n function() {\n uploadDroppedFiles(droppedFiles, dropZone);\n },\n function() {\n options.callbacks.dropLog(\"Drop event DataTransfer parsing failed. No files will be uploaded.\", \"error\");\n }\n );\n }\n });\n\n disposeSupport.addDisposer(function() {\n dropZone.dispose();\n });\n\n qq(dropArea).hasAttribute(HIDE_BEFORE_ENTER_ATTR) && qq(dropArea).hide();\n\n uploadDropZones.push(dropZone);\n\n return dropZone;\n }\n\n function isFileDrag(dragEvent) {\n var fileDrag;\n\n qq.each(dragEvent.dataTransfer.types, function(key, val) {\n if (val === \"Files\") {\n fileDrag = true;\n return false;\n }\n });\n\n return fileDrag;\n }\n\n // Attempt to determine when the file has left the document. It is not always possible to detect this\n // in all cases, but it is generally possible in all browsers, with a few exceptions.\n //\n // Exceptions:\n // * IE10+ & Safari: We can't detect a file leaving the document if the Explorer window housing the file\n // overlays the browser window.\n // * IE10+: If the file is dragged out of the window too quickly, IE does not set the expected values of the\n // event's X & Y properties.\n function leavingDocumentOut(e) {\n if (qq.safari()) {\n return e.x < 0 || e.y < 0;\n }\n\n return e.x === 0 && e.y === 0;\n }\n\n function setupDragDrop() {\n var dropZones = options.dropZoneElements,\n\n maybeHideDropZones = function() {\n setTimeout(function() {\n qq.each(dropZones, function(idx, dropZone) {\n qq(dropZone).hasAttribute(HIDE_BEFORE_ENTER_ATTR) && qq(dropZone).hide();\n qq(dropZone).removeClass(options.classes.dropActive);\n });\n }, 10);\n };\n\n qq.each(dropZones, function(idx, dropZone) {\n var uploadDropZone = setupDropzone(dropZone);\n\n // IE <= 9 does not support the File API used for drag+drop uploads\n if (dropZones.length && qq.supportedFeatures.fileDrop) {\n disposeSupport.attach(document, \"dragenter\", function(e) {\n if (!uploadDropZone.dropDisabled() && isFileDrag(e)) {\n qq.each(dropZones, function(idx, dropZone) {\n // We can't apply styles to non-HTMLElements, since they lack the `style` property.\n // Also, if the drop zone isn't initially hidden, let's not mess with `style.display`.\n if (dropZone instanceof HTMLElement &&\n qq(dropZone).hasAttribute(HIDE_BEFORE_ENTER_ATTR)) {\n\n qq(dropZone).css({display: \"block\"});\n }\n });\n }\n });\n }\n });\n\n disposeSupport.attach(document, \"dragleave\", function(e) {\n if (leavingDocumentOut(e)) {\n maybeHideDropZones();\n }\n });\n\n // Just in case we were not able to detect when a dragged file has left the document,\n // hide all relevant drop zones the next time the mouse enters the document.\n // Note that mouse events such as this one are not fired during drag operations.\n disposeSupport.attach(qq(document).children()[0], \"mouseenter\", function(e) {\n maybeHideDropZones();\n });\n\n disposeSupport.attach(document, \"drop\", function(e) {\n if (isFileDrag(e)) {\n e.preventDefault();\n maybeHideDropZones();\n }\n });\n\n disposeSupport.attach(document, HIDE_ZONES_EVENT_NAME, maybeHideDropZones);\n }\n\n setupDragDrop();\n\n qq.extend(this, {\n setupExtraDropzone: function(element) {\n options.dropZoneElements.push(element);\n setupDropzone(element);\n },\n\n removeDropzone: function(element) {\n var i,\n dzs = options.dropZoneElements;\n\n for (i in dzs) {\n if (dzs[i] === element) {\n return dzs.splice(i, 1);\n }\n }\n },\n\n dispose: function() {\n disposeSupport.dispose();\n qq.each(uploadDropZones, function(idx, dropZone) {\n dropZone.dispose();\n });\n }\n });\n\n this._testing = {};\n this._testing.extractDirectoryPath = extractDirectoryPath;\n};\n\nqq.DragAndDrop.callbacks = function() {\n \"use strict\";\n\n return {\n processingDroppedFiles: function() {},\n processingDroppedFilesComplete: function(files, targetEl) {},\n dropError: function(code, errorSpecifics) {\n qq.log(\"Drag & drop error code '\" + code + \" with these specifics: '\" + errorSpecifics + \"'\", \"error\");\n },\n dropLog: function(message, level) {\n qq.log(message, level);\n }\n };\n};\n\nqq.UploadDropZone = function(o) {\n \"use strict\";\n\n var disposeSupport = new qq.DisposeSupport(),\n options, element, preventDrop, dropOutsideDisabled;\n\n options = {\n element: null,\n onEnter: function(e) {},\n onLeave: function(e) {},\n // is not fired when leaving element by hovering descendants\n onLeaveNotDescendants: function(e) {},\n onDrop: function(e) {}\n };\n\n qq.extend(options, o);\n element = options.element;\n\n function dragoverShouldBeCanceled() {\n return qq.safari() || (qq.firefox() && qq.windows());\n }\n\n function disableDropOutside(e) {\n // run only once for all instances\n if (!dropOutsideDisabled) {\n\n // for these cases we need to catch onDrop to reset dropArea\n if (dragoverShouldBeCanceled) {\n disposeSupport.attach(document, \"dragover\", function(e) {\n e.preventDefault();\n });\n } else {\n disposeSupport.attach(document, \"dragover\", function(e) {\n if (e.dataTransfer) {\n e.dataTransfer.dropEffect = \"none\";\n e.preventDefault();\n }\n });\n }\n\n dropOutsideDisabled = true;\n }\n }\n\n function isValidFileDrag(e) {\n // e.dataTransfer currently causing IE errors\n // IE9 does NOT support file API, so drag-and-drop is not possible\n if (!qq.supportedFeatures.fileDrop) {\n return false;\n }\n\n var effectTest, dt = e.dataTransfer,\n // do not check dt.types.contains in webkit, because it crashes safari 4\n isSafari = qq.safari();\n\n // dt.effectAllowed is none in Safari 5\n\n // dt.effectAllowed crashes IE 11 & 10 when files have been dragged from\n // the filesystem\n effectTest = qq.ie() && qq.supportedFeatures.fileDrop ? true : dt.effectAllowed !== \"none\";\n return dt && effectTest &&\n (\n (dt.files && dt.files.length) || // Valid for drop events with files\n (!isSafari && dt.types.contains && dt.types.contains(\"Files\")) || // Valid in Chrome/Firefox\n (dt.types.includes && dt.types.includes(\"Files\")) // Valid in IE\n );\n }\n\n function isOrSetDropDisabled(isDisabled) {\n if (isDisabled !== undefined) {\n preventDrop = isDisabled;\n }\n return preventDrop;\n }\n\n function triggerHidezonesEvent() {\n var hideZonesEvent;\n\n function triggerUsingOldApi() {\n hideZonesEvent = document.createEvent(\"Event\");\n hideZonesEvent.initEvent(options.HIDE_ZONES_EVENT_NAME, true, true);\n }\n\n if (window.CustomEvent) {\n try {\n hideZonesEvent = new CustomEvent(options.HIDE_ZONES_EVENT_NAME);\n }\n catch (err) {\n triggerUsingOldApi();\n }\n }\n else {\n triggerUsingOldApi();\n }\n\n document.dispatchEvent(hideZonesEvent);\n }\n\n function attachEvents() {\n disposeSupport.attach(element, \"dragover\", function(e) {\n if (!isValidFileDrag(e)) {\n return;\n }\n\n // dt.effectAllowed crashes IE 11 & 10 when files have been dragged from\n // the filesystem\n var effect = qq.ie() && qq.supportedFeatures.fileDrop ? null : e.dataTransfer.effectAllowed;\n if (effect === \"move\" || effect === \"linkMove\") {\n e.dataTransfer.dropEffect = \"move\"; // for FF (only move allowed)\n } else {\n e.dataTransfer.dropEffect = \"copy\"; // for Chrome\n }\n\n e.stopPropagation();\n e.preventDefault();\n });\n\n disposeSupport.attach(element, \"dragenter\", function(e) {\n if (!isOrSetDropDisabled()) {\n if (!isValidFileDrag(e)) {\n return;\n }\n options.onEnter(e);\n }\n });\n\n disposeSupport.attach(element, \"dragleave\", function(e) {\n if (!isValidFileDrag(e)) {\n return;\n }\n\n options.onLeave(e);\n\n var relatedTarget = document.elementFromPoint(e.clientX, e.clientY);\n // do not fire when moving a mouse over a descendant\n if (qq(this).contains(relatedTarget)) {\n return;\n }\n\n options.onLeaveNotDescendants(e);\n });\n\n disposeSupport.attach(element, \"drop\", function(e) {\n if (!isOrSetDropDisabled()) {\n if (!isValidFileDrag(e)) {\n return;\n }\n\n e.preventDefault();\n e.stopPropagation();\n options.onDrop(e);\n\n triggerHidezonesEvent();\n }\n });\n }\n\n disableDropOutside();\n attachEvents();\n\n qq.extend(this, {\n dropDisabled: function(isDisabled) {\n return isOrSetDropDisabled(isDisabled);\n },\n\n dispose: function() {\n disposeSupport.dispose();\n },\n\n getElement: function() {\n return element;\n }\n });\n\n this._testing = {};\n this._testing.isValidFileDrag = isValidFileDrag;\n};\n"]} \ No newline at end of file diff --git a/resources/fine-uploader/edit.gif b/resources/fine-uploader/edit.gif deleted file mode 100644 index 403e7c6..0000000 Binary files a/resources/fine-uploader/edit.gif and /dev/null differ diff --git a/resources/fine-uploader/fine-uploader-gallery.css b/resources/fine-uploader/fine-uploader-gallery.css deleted file mode 100644 index bdcca3b..0000000 --- a/resources/fine-uploader/fine-uploader-gallery.css +++ /dev/null @@ -1,471 +0,0 @@ -/* --------------------------------------- -/* Fine Uploader Gallery View Styles -/* --------------------------------------- - - -/* Buttons ------------------------------------------- */ -.qq-gallery .qq-btn -{ - float: right; - border: none; - padding: 0; - margin: 0; - box-shadow: none; -} - -/* Upload Button ------------------------------------------- */ -.qq-gallery .qq-upload-button { - display: inline; - width: 105px; - padding: 7px 10px; - float: left; - text-align: center; - background: #00ABC7; - color: #FFFFFF; - border-radius: 2px; - border: 1px solid #37B7CC; - box-shadow: 0 1px 1px rgba(255, 255, 255, 0.37) inset, - 1px 0 1px rgba(255, 255, 255, 0.07) inset, - 0 1px 0 rgba(0, 0, 0, 0.36), - 0 -2px 12px rgba(0, 0, 0, 0.08) inset -} -.qq-gallery .qq-upload-button-hover { - background: #33B6CC; -} -.qq-gallery .qq-upload-button-focus { - outline: 1px dotted #000000; -} - - -/* Drop Zone ------------------------------------------- */ -.qq-gallery.qq-uploader { - position: relative; - min-height: 200px; - max-height: 490px; - overflow-y: hidden; - width: inherit; - border-radius: 6px; - border: 1px dashed #CCCCCC; - background-color: #FAFAFA; - padding: 20px; -} -.qq-gallery.qq-uploader:before { - content: attr(qq-drop-area-text) " "; - position: absolute; - font-size: 200%; - left: 0; - width: 100%; - text-align: center; - top: 45%; - opacity: 0.25; - filter: alpha(opacity=25); -} -.qq-gallery .qq-upload-drop-area, .qq-upload-extra-drop-area { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - min-height: 30px; - z-index: 2; - background: #F9F9F9; - border-radius: 4px; - text-align: center; -} -.qq-gallery .qq-upload-drop-area span { - display: block; - position: absolute; - top: 50%; - width: 100%; - margin-top: -8px; - font-size: 16px; -} -.qq-gallery .qq-upload-extra-drop-area { - position: relative; - margin-top: 50px; - font-size: 16px; - padding-top: 30px; - height: 20px; - min-height: 40px; -} -.qq-gallery .qq-upload-drop-area-active { - background: #FDFDFD; - border-radius: 4px; -} -.qq-gallery .qq-upload-list { - margin: 0; - padding: 10px 0 0; - list-style: none; - max-height: 450px; - overflow-y: auto; - clear: both; - box-shadow: none; -} - - -/* Uploaded Elements ------------------------------------------- */ -.qq-gallery .qq-upload-list li { - display: inline-block; - position: relative; - max-width: 120px; - margin: 0 25px 25px 0; - padding: 0; - line-height: 16px; - font-size: 13px; - color: #424242; - background-color: #FFFFFF; - border-radius: 2px; - box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.22); - vertical-align: top; - - /* to ensure consistent size of tiles - may need to change if qq-max-size attr on preview img changes */ - height: 186px; -} - -.qq-gallery .qq-upload-spinner, -.qq-gallery .qq-upload-size, -.qq-gallery .qq-upload-retry, -.qq-gallery .qq-upload-failed-text, -.qq-gallery .qq-upload-delete, -.qq-gallery .qq-upload-pause, -.qq-gallery .qq-upload-continue { - display: inline; -} -.qq-gallery .qq-upload-retry:hover, -.qq-gallery .qq-upload-delete:hover, -.qq-gallery .qq-upload-pause:hover, -.qq-gallery .qq-upload-continue:hover { - background-color: transparent; -} -.qq-gallery .qq-upload-delete, -.qq-gallery .qq-upload-pause, -.qq-gallery .qq-upload-continue, -.qq-gallery .qq-upload-cancel { - cursor: pointer; -} -.qq-gallery .qq-upload-delete, -.qq-gallery .qq-upload-pause, -.qq-gallery .qq-upload-continue { - border:none; - background: none; - color: #00A0BA; - font-size: 12px; - padding: 0; -} -/* to ensure consistent size of tiles - only display status text before auto-retry or after failure */ -.qq-gallery .qq-upload-status-text { - color: #333333; - font-size: 12px; - padding-left: 3px; - padding-top: 2px; - width: inherit; - display: none; - width: 108px; -} -.qq-gallery .qq-upload-fail .qq-upload-status-text { - text-overflow: ellipsis; - white-space: nowrap; - overflow-x: hidden; - display: block; -} -.qq-gallery .qq-upload-retrying .qq-upload-status-text { - display: inline-block; -} -.qq-gallery .qq-upload-retrying .qq-progress-bar-container { - display: none; -} - -.qq-gallery .qq-upload-cancel { - background-color: #525252; - color: #F7F7F7; - font-weight: bold; - font-family: Arial, Helvetica, sans-serif; - border-radius: 12px; - border: none; - height: 22px; - width: 22px; - padding: 4px; - position: absolute; - right: -5px; - top: -6px; - margin: 0; - line-height: 17px; -} -.qq-gallery .qq-upload-cancel:hover { - background-color: #525252; -} -.qq-gallery .qq-upload-retry { - cursor: pointer; - position: absolute; - top: 30px; - left: 50%; - margin-left: -31px; - box-shadow: 0 1px 1px rgba(255, 255, 255, 0.37) inset, - 1px 0 1px rgba(255, 255, 255, 0.07) inset, - 0 4px 4px rgba(0, 0, 0, 0.5), - 0 -2px 12px rgba(0, 0, 0, 0.08) inset; - padding: 3px 4px; - border: 1px solid #d2ddc7; - border-radius: 2px; - color: inherit; - background-color: #EBF6E0; - z-index: 1; -} -.qq-gallery .qq-upload-retry:hover { - background-color: #f7ffec; -} - -.qq-gallery .qq-file-info { - padding: 10px 6px 4px; - margin-top: -3px; - border-radius: 0 0 2px 2px; - text-align: left; - overflow: hidden; -} - -.qq-gallery .qq-file-info .qq-file-name { - position: relative; -} - -.qq-gallery .qq-upload-file { - display: block; - margin-right: 0; - margin-bottom: 3px; - width: auto; - - /* to ensure consistent size of tiles - constrain text to single line */ - text-overflow: ellipsis; - white-space: nowrap; - overflow-x: hidden; -} -.qq-gallery .qq-upload-spinner { - display: inline-block; - background: url("loading.gif"); - position: absolute; - left: 50%; - margin-left: -7px; - top: 53px; - width: 15px; - height: 15px; - vertical-align: text-bottom; -} -.qq-gallery .qq-drop-processing { - display: block; -} -.qq-gallery .qq-drop-processing-spinner { - display: inline-block; - background: url("processing.gif"); - width: 24px; - height: 24px; - vertical-align: text-bottom; -} -.qq-gallery .qq-upload-failed-text { - display: none; - font-style: italic; - font-weight: bold; -} -.qq-gallery .qq-upload-failed-icon { - display:none; - width:15px; - height:15px; - vertical-align:text-bottom; -} -.qq-gallery .qq-upload-fail .qq-upload-failed-text { - display: inline; -} -.qq-gallery .qq-upload-retrying .qq-upload-failed-text { - display: inline; -} -.qq-gallery .qq-upload-list li.qq-upload-success { - background-color: #F2F7ED; -} -.qq-gallery .qq-upload-list li.qq-upload-fail { - background-color: #F5EDED; - box-shadow: 0 0 1px 0 red; - border: 0; -} -.qq-gallery .qq-progress-bar { - display: block; - background: #00abc7; - width: 0%; - height: 15px; - border-radius: 6px; - margin-bottom: 3px; -} - -.qq-gallery .qq-total-progress-bar { - height: 25px; - border-radius: 9px; -} - -.qq-gallery .qq-total-progress-bar-container { - margin-left: 9px; - display: inline; - float: right; - width: 500px; -} - -.qq-gallery .qq-upload-size { - float: left; - font-size: 11px; - color: #929292; - margin-bottom: 3px; - margin-right: 0; - display: inline-block; -} - -.qq-gallery INPUT.qq-edit-filename { - position: absolute; - opacity: 0; - filter: alpha(opacity=0); - z-index: -1; - -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; -} - -.qq-gallery .qq-upload-file.qq-editable { - cursor: pointer; - margin-right: 20px; -} - -.qq-gallery .qq-edit-filename-icon.qq-editable { - display: inline-block; - cursor: pointer; - position: absolute; - right: 0; - top: 0; -} - -.qq-gallery INPUT.qq-edit-filename.qq-editing { - position: static; - height: 28px; - width: 90px; - width: -moz-available; - padding: 0 8px; - margin-bottom: 3px; - border: 1px solid #ccc; - border-radius: 2px; - font-size: 13px; - - opacity: 1; - filter: alpha(opacity=100); - -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"; -} - -.qq-gallery .qq-edit-filename-icon { - display: none; - background: url("edit.gif"); - width: 15px; - height: 15px; - vertical-align: text-bottom; -} -.qq-gallery .qq-delete-icon { - background: url("trash.gif"); - width: 15px; - height: 15px; - vertical-align: sub; - display: inline-block; -} -.qq-gallery .qq-retry-icon { - background: url("retry.gif"); - width: 15px; - height: 15px; - vertical-align: sub; - display: inline-block; - float: none; -} -.qq-gallery .qq-continue-icon { - background: url("continue.gif"); - width: 15px; - height: 15px; - vertical-align: sub; - display: inline-block; -} -.qq-gallery .qq-pause-icon { - background: url("pause.gif"); - width: 15px; - height: 15px; - vertical-align: sub; - display: inline-block; -} - -.qq-gallery .qq-hide { - display: none; -} - - -/* Thumbnail ------------------------------------------- */ -.qq-gallery .qq-in-progress .qq-thumbnail-wrapper { - /* makes the spinner on top of the thumbnail more visible */ - opacity: 0.5; - filter: alpha(opacity=50); -} -.qq-gallery .qq-thumbnail-wrapper { - overflow: hidden; - position: relative; - - /* to ensure consistent size of tiles - should match qq-max-size attribute value on qq-thumbnail-selector IMG element */ - height: 120px; - width: 120px; -} -.qq-gallery .qq-thumbnail-selector { - border-radius: 2px 2px 0 0; - bottom: 0; - - /* we will override this in the :root thumbnail selector (to help center the preview) for everything other than IE8 */ - top: 0; - - /* center the thumb horizontally in the tile */ - margin:auto; - display: block; -} - -/* hack to ensure we don't try to center preview in IE8, since -ms-filter doesn't mimic translateY as expected in all cases */ -:root *> .qq-gallery .qq-thumbnail-selector { - /* vertically center preview image on tile */ - position: relative; - top: 50%; - transform: translateY(-50%); - -moz-transform: translateY(-50%); - -ms-transform: translateY(-50%); - -webkit-transform: translateY(-50%); -} - -/* element styles */ -.qq-gallery.qq-uploader DIALOG { - display: none; -} - -.qq-gallery.qq-uploader DIALOG[open] { - display: block; -} - -.qq-gallery.qq-uploader DIALOG { - display: none; -} - -.qq-gallery.qq-uploader DIALOG[open] { - display: block; -} - -.qq-gallery.qq-uploader DIALOG .qq-dialog-buttons { - text-align: center; - padding-top: 10px; -} - -.qq-gallery.qq-uploader DIALOG .qq-dialog-buttons BUTTON { - margin-left: 5px; - margin-right: 5px; -} - -.qq-gallery.qq-uploader DIALOG .qq-dialog-message-selector { - padding-bottom: 10px; -} - -.qq-gallery .qq-uploader DIALOG::backdrop { - background-color: rgba(0, 0, 0, 0.7); -} \ No newline at end of file diff --git a/resources/fine-uploader/fine-uploader-gallery.min.css b/resources/fine-uploader/fine-uploader-gallery.min.css deleted file mode 100644 index ecdadfe..0000000 --- a/resources/fine-uploader/fine-uploader-gallery.min.css +++ /dev/null @@ -1 +0,0 @@ -.qq-gallery .qq-btn{float:right;border:none;padding:0;margin:0;box-shadow:none}.qq-gallery .qq-upload-button{display:inline;width:105px;padding:7px 10px;float:left;text-align:center;background:#00abc7;color:#fff;border-radius:2px;border:1px solid #37b7cc;box-shadow:0 1px 1px rgba(255,255,255,.37) inset,1px 0 1px rgba(255,255,255,.07) inset,0 1px 0 rgba(0,0,0,.36),0 -2px 12px rgba(0,0,0,.08) inset}.qq-gallery .qq-upload-button-hover{background:#33b6cc}.qq-gallery .qq-upload-button-focus{outline:1px dotted #000}.qq-gallery.qq-uploader{position:relative;min-height:200px;max-height:490px;overflow-y:hidden;width:inherit;border-radius:6px;border:1px dashed #ccc;background-color:#fafafa;padding:20px}.qq-gallery.qq-uploader:before{content:attr(qq-drop-area-text) " ";position:absolute;font-size:200%;left:0;width:100%;text-align:center;top:45%;opacity:.25}.qq-gallery .qq-upload-drop-area,.qq-upload-extra-drop-area{position:absolute;top:0;left:0;width:100%;height:100%;min-height:30px;z-index:2;background:#f9f9f9;border-radius:4px;text-align:center}.qq-gallery .qq-upload-drop-area span{display:block;position:absolute;top:50%;width:100%;margin-top:-8px;font-size:16px}.qq-gallery .qq-upload-extra-drop-area{position:relative;margin-top:50px;font-size:16px;padding-top:30px;height:20px;min-height:40px}.qq-gallery .qq-upload-drop-area-active{background:#fdfdfd;border-radius:4px}.qq-gallery .qq-upload-list{margin:0;padding:10px 0 0;list-style:none;max-height:450px;overflow-y:auto;clear:both;box-shadow:none}.qq-gallery .qq-upload-list li{display:inline-block;position:relative;max-width:120px;margin:0 25px 25px 0;padding:0;line-height:16px;font-size:13px;color:#424242;background-color:#fff;border-radius:2px;box-shadow:0 1px 1px 0 rgba(0,0,0,.22);vertical-align:top;height:186px}.qq-gallery .qq-upload-continue,.qq-gallery .qq-upload-delete,.qq-gallery .qq-upload-failed-text,.qq-gallery .qq-upload-pause,.qq-gallery .qq-upload-retry,.qq-gallery .qq-upload-size,.qq-gallery .qq-upload-spinner{display:inline}.qq-gallery .qq-upload-continue:hover,.qq-gallery .qq-upload-delete:hover,.qq-gallery .qq-upload-pause:hover,.qq-gallery .qq-upload-retry:hover{background-color:transparent}.qq-gallery .qq-upload-cancel,.qq-gallery .qq-upload-continue,.qq-gallery .qq-upload-delete,.qq-gallery .qq-upload-pause{cursor:pointer}.qq-gallery .qq-upload-continue,.qq-gallery .qq-upload-delete,.qq-gallery .qq-upload-pause{border:none;background:0 0;color:#00a0ba;font-size:12px;padding:0}.qq-gallery .qq-upload-status-text{color:#333;font-size:12px;padding-left:3px;padding-top:2px;width:inherit;display:none;width:108px}.qq-gallery .qq-upload-fail .qq-upload-status-text{text-overflow:ellipsis;white-space:nowrap;overflow-x:hidden;display:block}.qq-gallery .qq-upload-retrying .qq-upload-status-text{display:inline-block}.qq-gallery .qq-upload-retrying .qq-progress-bar-container{display:none}.qq-gallery .qq-upload-cancel{background-color:#525252;color:#f7f7f7;font-weight:700;font-family:Arial,Helvetica,sans-serif;border-radius:12px;border:none;height:22px;width:22px;padding:4px;position:absolute;right:-5px;top:-6px;margin:0;line-height:17px}.qq-gallery .qq-upload-cancel:hover{background-color:#525252}.qq-gallery .qq-upload-retry{cursor:pointer;position:absolute;top:30px;left:50%;margin-left:-31px;box-shadow:0 1px 1px rgba(255,255,255,.37) inset,1px 0 1px rgba(255,255,255,.07) inset,0 4px 4px rgba(0,0,0,.5),0 -2px 12px rgba(0,0,0,.08) inset;padding:3px 4px;border:1px solid #d2ddc7;border-radius:2px;color:inherit;background-color:#ebf6e0;z-index:1}.qq-gallery .qq-upload-retry:hover{background-color:#f7ffec}.qq-gallery .qq-file-info{padding:10px 6px 4px;margin-top:-3px;border-radius:0 0 2px 2px;text-align:left;overflow:hidden}.qq-gallery .qq-file-info .qq-file-name{position:relative}.qq-gallery .qq-upload-file{display:block;margin-right:0;margin-bottom:3px;width:auto;text-overflow:ellipsis;white-space:nowrap;overflow-x:hidden}.qq-gallery .qq-upload-spinner{display:inline-block;background:url(loading.gif);position:absolute;left:50%;margin-left:-7px;top:53px;width:15px;height:15px;vertical-align:text-bottom}.qq-gallery .qq-drop-processing{display:block}.qq-gallery .qq-drop-processing-spinner{display:inline-block;background:url(processing.gif);width:24px;height:24px;vertical-align:text-bottom}.qq-gallery .qq-upload-failed-text{display:none;font-style:italic;font-weight:700}.qq-gallery .qq-upload-failed-icon{display:none;width:15px;height:15px;vertical-align:text-bottom}.qq-gallery .qq-upload-fail .qq-upload-failed-text{display:inline}.qq-gallery .qq-upload-retrying .qq-upload-failed-text{display:inline}.qq-gallery .qq-upload-list li.qq-upload-success{background-color:#f2f7ed}.qq-gallery .qq-upload-list li.qq-upload-fail{background-color:#f5eded;box-shadow:0 0 1px 0 red;border:0}.qq-gallery .qq-progress-bar{display:block;background:#00abc7;width:0;height:15px;border-radius:6px;margin-bottom:3px}.qq-gallery .qq-total-progress-bar{height:25px;border-radius:9px}.qq-gallery .qq-total-progress-bar-container{margin-left:9px;display:inline;float:right;width:500px}.qq-gallery .qq-upload-size{float:left;font-size:11px;color:#929292;margin-bottom:3px;margin-right:0;display:inline-block}.qq-gallery INPUT.qq-edit-filename{position:absolute;opacity:0;z-index:-1}.qq-gallery .qq-upload-file.qq-editable{cursor:pointer;margin-right:20px}.qq-gallery .qq-edit-filename-icon.qq-editable{display:inline-block;cursor:pointer;position:absolute;right:0;top:0}.qq-gallery INPUT.qq-edit-filename.qq-editing{position:static;height:28px;width:90px;width:-moz-available;padding:0 8px;margin-bottom:3px;border:1px solid #ccc;border-radius:2px;font-size:13px;opacity:1}.qq-gallery .qq-edit-filename-icon{display:none;background:url(edit.gif);width:15px;height:15px;vertical-align:text-bottom}.qq-gallery .qq-delete-icon{background:url(trash.gif);width:15px;height:15px;vertical-align:sub;display:inline-block}.qq-gallery .qq-retry-icon{background:url(retry.gif);width:15px;height:15px;vertical-align:sub;display:inline-block;float:none}.qq-gallery .qq-continue-icon{background:url(continue.gif);width:15px;height:15px;vertical-align:sub;display:inline-block}.qq-gallery .qq-pause-icon{background:url(pause.gif);width:15px;height:15px;vertical-align:sub;display:inline-block}.qq-gallery .qq-hide{display:none}.qq-gallery .qq-in-progress .qq-thumbnail-wrapper{/* makes the spinner on top of the thumbnail more visible */opacity:.5}.qq-gallery .qq-thumbnail-wrapper{overflow:hidden;position:relative;height:120px;width:120px}.qq-gallery .qq-thumbnail-selector{border-radius:2px 2px 0 0;bottom:0;top:0;margin:auto;display:block}:root *>.qq-gallery .qq-thumbnail-selector{position:relative;top:50%;transform:translateY(-50%);-moz-transform:translateY(-50%);-ms-transform:translateY(-50%);-webkit-transform:translateY(-50%)}.qq-gallery.qq-uploader DIALOG{display:none}.qq-gallery.qq-uploader DIALOG[open]{display:block}.qq-gallery.qq-uploader DIALOG{display:none}.qq-gallery.qq-uploader DIALOG[open]{display:block}.qq-gallery.qq-uploader DIALOG .qq-dialog-buttons{text-align:center;padding-top:10px}.qq-gallery.qq-uploader DIALOG .qq-dialog-buttons BUTTON{margin-left:5px;margin-right:5px}.qq-gallery.qq-uploader DIALOG .qq-dialog-message-selector{padding-bottom:10px}.qq-gallery .qq-uploader DIALOG::backdrop{background-color:rgba(0,0,0,.7)}/*# sourceMappingURL=fine-uploader-gallery.min.css.map */ \ No newline at end of file diff --git a/resources/fine-uploader/fine-uploader-gallery.min.css.map b/resources/fine-uploader/fine-uploader-gallery.min.css.map deleted file mode 100644 index 762454e..0000000 --- a/resources/fine-uploader/fine-uploader-gallery.min.css.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["_build/fine-uploader-gallery.css"],"names":[],"mappings":"AAOA,oBAEI,MAAO,MACP,OAAQ,KACR,QAAS,EACT,OAAQ,EACR,WAAY,KAKhB,8BACI,QAAS,OACT,MAAO,MACP,QAAS,IAAI,KACb,MAAO,KACP,WAAY,OACZ,WAAY,QACZ,MAAO,KACP,cAAe,IACf,OAAQ,IAAI,MAAM,QAClB,WAAY,EAAE,IAAI,IAAI,sBAA0B,KAAK,CACrD,IAAI,EAAE,IAAI,sBAA0B,KAAK,CACzC,EAAE,IAAI,EAAE,eAAmB,CAC3B,EAAE,KAAK,KAAK,gBAAoB,MAEpC,oCACI,WAAY,QAEhB,oCACI,QAAS,IAAI,OAAO,KAMxB,wBACI,SAAU,SACV,WAAY,MACZ,WAAY,MACZ,WAAY,OACZ,MAAO,QACP,cAAe,IACf,OAAQ,IAAI,OAAO,KACnB,iBAAkB,QAClB,QAAS,KAEb,+BACI,QAAS,wBAAwB,IACjC,SAAU,SACV,UAAW,KACX,KAAM,EACN,MAAO,KACP,WAAY,OACZ,IAAK,IACL,QAAS,IAGb,iCAAkC,2BAC9B,SAAU,SACV,IAAK,EACL,KAAM,EACN,MAAO,KACP,OAAQ,KACR,WAAY,KACZ,QAAS,EACT,WAAY,QACZ,cAAe,IACf,WAAY,OAEhB,sCACI,QAAS,MACT,SAAU,SACV,IAAK,IACL,MAAO,KACP,WAAY,KACZ,UAAW,KAEf,uCACI,SAAU,SACV,WAAY,KACZ,UAAW,KACX,YAAa,KACb,OAAQ,KACR,WAAY,KAEhB,wCACI,WAAY,QACZ,cAAe,IAEnB,4BACI,OAAQ,EACR,QAAS,KAAK,EAAE,EAChB,WAAY,KACZ,WAAY,MACZ,WAAY,KACZ,MAAO,KACP,WAAY,KAMhB,+BACI,QAAS,aACT,SAAU,SACV,UAAW,MACX,OAAQ,EAAE,KAAK,KAAK,EACpB,QAAS,EACT,YAAa,KACb,UAAW,KACX,MAAO,QACP,iBAAkB,KAClB,cAAe,IACf,WAAY,EAAE,IAAI,IAAI,EAAE,gBACxB,eAAgB,IAGhB,OAAQ,MASZ,gCAFA,8BADA,mCAEA,6BAHA,6BADA,4BADA,+BAOI,QAAS,OAKb,sCAFA,oCACA,mCAFA,mCAII,iBAAkB,YAKtB,8BADA,gCAFA,8BACA,6BAGI,OAAQ,QAIZ,gCAFA,8BACA,6BAEI,OAAO,KACP,WAAY,IACZ,MAAO,QACP,UAAW,KACX,QAAS,EAGb,mCACI,MAAO,KACP,UAAW,KACX,aAAc,IACd,YAAa,IACb,MAAO,QACP,QAAS,KACT,MAAO,MAEX,mDACI,cAAe,SACf,YAAa,OACb,WAAY,OACZ,QAAS,MAEb,uDACI,QAAS,aAEb,2DACI,QAAS,KAGb,8BACI,iBAAkB,QAClB,MAAO,QACP,YAAa,IACb,YAAa,KAAK,CAAE,SAAS,CAAE,WAC/B,cAAe,KACf,OAAQ,KACR,OAAQ,KACR,MAAO,KACP,QAAS,IACT,SAAU,SACV,MAAO,KACP,IAAK,KACL,OAAQ,EACR,YAAa,KAEjB,oCACI,iBAAkB,QAEtB,6BACI,OAAQ,QACR,SAAU,SACV,IAAK,KACL,KAAM,IACN,YAAa,MACb,WAAY,EAAE,IAAI,IAAI,sBAA0B,KAAK,CACzC,IAAI,EAAE,IAAI,sBAA0B,KAAK,CACzC,EAAE,IAAI,IAAI,cAAkB,CAC5B,EAAE,KAAK,KAAK,gBAAoB,MAC5C,QAAS,IAAI,IACb,OAAQ,IAAI,MAAM,QAClB,cAAe,IACf,MAAO,QACP,iBAAkB,QAClB,QAAS,EAEb,mCACI,iBAAkB,QAGtB,0BACI,QAAS,KAAK,IAAI,IAClB,WAAY,KACZ,cAAe,EAAE,EAAE,IAAI,IACvB,WAAY,KACZ,SAAU,OAGd,wCACI,SAAU,SAGd,4BACI,QAAS,MACT,aAAc,EACd,cAAe,IACf,MAAO,KAGP,cAAe,SACf,YAAa,OACb,WAAY,OAEhB,+BACI,QAAS,aACT,WAAY,iBACZ,SAAU,SACV,KAAM,IACN,YAAa,KACb,IAAK,KACL,MAAO,KACP,OAAQ,KACR,eAAgB,YAEpB,gCACI,QAAS,MAEb,wCACI,QAAS,aACT,WAAY,oBACZ,MAAO,KACP,OAAQ,KACR,eAAgB,YAEpB,mCACI,QAAS,KACT,WAAY,OACZ,YAAa,IAEjB,mCACI,QAAQ,KACR,MAAM,KACN,OAAO,KACP,eAAe,YAEnB,mDACI,QAAS,OAEb,uDACI,QAAS,OAEb,iDACI,iBAAkB,QAEtB,8CACI,iBAAkB,QAClB,WAAY,EAAE,EAAE,IAAI,EAAE,IACtB,OAAQ,EAEZ,6BACI,QAAS,MACT,WAAY,QACZ,MAAO,EACP,OAAQ,KACR,cAAe,IACf,cAAe,IAGnB,mCACI,OAAQ,KACR,cAAe,IAGnB,6CACI,YAAa,IACb,QAAS,OACT,MAAO,MACP,MAAO,MAGX,4BACI,MAAO,KACP,UAAW,KACX,MAAO,QACP,cAAe,IACf,aAAc,EACd,QAAS,aAGb,mCACI,SAAU,SACV,QAAS,EAET,QAAS,GAIb,wCACI,OAAQ,QACR,aAAc,KAGlB,+CACI,QAAS,aACT,OAAQ,QACR,SAAU,SACV,MAAO,EACP,IAAK,EAGT,8CACI,SAAU,OACV,OAAQ,KACR,MAAO,KACP,MAAO,eACP,QAAS,EAAE,IACX,cAAe,IACf,OAAQ,IAAI,MAAM,KAClB,cAAe,IACf,UAAW,KAEX,QAAS,EAKb,mCACI,QAAS,KACT,WAAY,cACZ,MAAO,KACP,OAAQ,KACR,eAAgB,YAEpB,4BACI,WAAY,eACZ,MAAO,KACP,OAAQ,KACR,eAAgB,IAChB,QAAS,aAEb,2BACI,WAAY,eACZ,MAAO,KACP,OAAQ,KACR,eAAgB,IAChB,QAAS,aACT,MAAO,KAEX,8BACI,WAAY,kBACZ,MAAO,KACP,OAAQ,KACR,eAAgB,IAChB,QAAS,aAEb,2BACI,WAAY,eACZ,MAAO,KACP,OAAQ,KACR,eAAgB,IAChB,QAAS,aAGb,qBACI,QAAS,KAMb,kDACI,4DACA,QAAS,GAGb,kCACI,SAAU,OACV,SAAU,SAGV,OAAQ,MACR,MAAO,MAEX,mCACI,cAAe,IAAI,IAAI,EAAE,EACzB,OAAQ,EAGR,IAAK,EAGL,OAAO,KACP,QAAS,MAIb,2CAEI,SAAU,SACV,IAAK,IACL,UAAW,iBACX,eAAgB,iBAChB,cAAe,iBACf,kBAAmB,iBAIvB,+BACI,QAAS,KAGb,qCACI,QAAS,MAGb,+BACI,QAAS,KAGb,qCACI,QAAS,MAGb,kDACI,WAAY,OACZ,YAAa,KAGjB,yDACI,YAAa,IACb,aAAc,IAGlB,2DACI,eAAgB,KAGpB,0CACI,iBAAkB"} \ No newline at end of file diff --git a/resources/fine-uploader/fine-uploader-new.css b/resources/fine-uploader/fine-uploader-new.css deleted file mode 100644 index c7678a3..0000000 --- a/resources/fine-uploader/fine-uploader-new.css +++ /dev/null @@ -1,354 +0,0 @@ -/* --------------------------------------- -/* Fine Uploader Styles -/* --------------------------------------- - -/* Buttons ------------------------------------------- */ -.qq-btn -{ - box-shadow: 0 1px 1px rgba(255, 255, 255, 0.37) inset, - 1px 0 1px rgba(255, 255, 255, 0.07) inset, - 0 1px 0 rgba(0, 0, 0, 0.36), - 0 -2px 12px rgba(0, 0, 0, 0.08) inset; - padding: 3px 4px; - border: 1px solid #CCCCCC; - border-radius: 2px; - color: inherit; - background-color: #FFFFFF; -} -.qq-upload-delete, .qq-upload-pause, .qq-upload-continue { - display: inline; -} -.qq-upload-delete -{ - background-color: #e65c47; - color: #FAFAFA; - border-color: #dc523d; - text-shadow: 0 1px 1px rgba(0, 0, 0, 0.55); -} -.qq-upload-delete:hover { - background-color: #f56b56; - } -.qq-upload-cancel -{ - background-color: #F5D7D7; - border-color: #e6c8c8; -} -.qq-upload-cancel:hover { - background-color: #ffe1e1; -} -.qq-upload-retry -{ - background-color: #EBF6E0; - border-color: #d2ddc7; -} -.qq-upload-retry:hover { - background-color: #f7ffec; -} -.qq-upload-pause, .qq-upload-continue { - background-color: #00ABC7; - color: #FAFAFA; - border-color: #2dadc2; - text-shadow: 0 1px 1px rgba(0, 0, 0, 0.55); -} -.qq-upload-pause:hover, .qq-upload-continue:hover { - background-color: #0fbad6; -} - -/* Upload Button ------------------------------------------- */ -.qq-upload-button { - display: inline; - width: 105px; - margin-bottom: 10px; - padding: 7px 10px; - text-align: center; - float: left; - background: #00ABC7; - color: #FFFFFF; - border-radius: 2px; - border: 1px solid #2dadc2; - box-shadow: 0 1px 1px rgba(255, 255, 255, 0.37) inset, - 1px 0 1px rgba(255, 255, 255, 0.07) inset, - 0 1px 0 rgba(0, 0, 0, 0.36), - 0 -2px 12px rgba(0, 0, 0, 0.08) inset; -} -.qq-upload-button-hover { - background: #33B6CC; -} -.qq-upload-button-focus { - outline: 1px dotted #000000; -} - - -/* Drop Zone ------------------------------------------- */ -.qq-uploader { - position: relative; - min-height: 200px; - max-height: 490px; - overflow-y: hidden; - width: inherit; - border-radius: 6px; - background-color: #FDFDFD; - border: 1px dashed #CCCCCC; - padding: 20px; -} -.qq-uploader:before { - content: attr(qq-drop-area-text) " "; - position: absolute; - font-size: 200%; - left: 0; - width: 100%; - text-align: center; - top: 45%; - opacity: 0.25; -} -.qq-upload-drop-area, .qq-upload-extra-drop-area { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - min-height: 30px; - z-index: 2; - background: #F9F9F9; - border-radius: 4px; - border: 1px dashed #CCCCCC; - text-align: center; -} -.qq-upload-drop-area span { - display: block; - position: absolute; - top: 50%; - width: 100%; - margin-top: -8px; - font-size: 16px; -} -.qq-upload-extra-drop-area { - position: relative; - margin-top: 50px; - font-size: 16px; - padding-top: 30px; - height: 20px; - min-height: 40px; -} -.qq-upload-drop-area-active { - background: #FDFDFD; - border-radius: 4px; - border: 1px dashed #CCCCCC; -} -.qq-upload-list { - margin: 0; - padding: 0; - list-style: none; - max-height: 450px; - overflow-y: auto; - box-shadow: 0px 1px 0px rgba(15, 15, 50, 0.14); - clear: both; -} - - -/* Uploaded Elements ------------------------------------------- */ -.qq-upload-list li { - margin: 0; - padding: 9px; - line-height: 15px; - font-size: 16px; - color: #424242; - background-color: #F6F6F6; - border-top: 1px solid #FFFFFF; - border-bottom: 1px solid #DDDDDD; -} -.qq-upload-list li:first-child { - border-top: none; -} -.qq-upload-list li:last-child { - border-bottom: none; -} - -.qq-upload-file, .qq-upload-spinner, .qq-upload-size, -.qq-upload-cancel, .qq-upload-retry, .qq-upload-failed-text, -.qq-upload-delete, .qq-upload-pause, .qq-upload-continue { - margin-right: 12px; - display: inline; -} -.qq-upload-file { - vertical-align: middle; - display: inline-block; - width: 300px; - text-overflow: ellipsis; - white-space: nowrap; - overflow-x: hidden; - height: 18px; -} -.qq-upload-spinner { - display: inline-block; - background: url("loading.gif"); - width: 15px; - height: 15px; - vertical-align: text-bottom; -} -.qq-drop-processing { - display: block; -} -.qq-drop-processing-spinner { - display: inline-block; - background: url("processing.gif"); - width: 24px; - height: 24px; - vertical-align: text-bottom; -} -.qq-upload-size, .qq-upload-cancel, .qq-upload-retry, -.qq-upload-delete, .qq-upload-pause, .qq-upload-continue { - font-size: 12px; - font-weight: normal; - cursor: pointer; - vertical-align: middle; -} -.qq-upload-status-text { - font-size: 14px; - font-weight: bold; - display: block; -} -.qq-upload-failed-text { - display: none; - font-style: italic; - font-weight: bold; -} -.qq-upload-failed-icon { - display:none; - width:15px; - height:15px; - vertical-align:text-bottom; -} -.qq-upload-fail .qq-upload-failed-text { - display: inline; -} -.qq-upload-retrying .qq-upload-failed-text { - display: inline; -} -.qq-upload-list li.qq-upload-success { - background-color: #EBF6E0; - color: #424242; - border-bottom: 1px solid #D3DED1; - border-top: 1px solid #F7FFF5; -} -.qq-upload-list li.qq-upload-fail { - background-color: #F5D7D7; - color: #424242; - border-bottom: 1px solid #DECACA; - border-top: 1px solid #FCE6E6; -} -.qq-progress-bar { - display: block; - display: block; - background: #00abc7; - width: 0%; - height: 15px; - border-radius: 6px; - margin-bottom: 3px; -} - -.qq-total-progress-bar { - height: 25px; - border-radius: 9px; -} - -.qq-total-progress-bar-container { - margin-left: 9px; - display: inline; - float: right; - width: 500px; -} - -INPUT.qq-edit-filename { - position: absolute; - opacity: 0; - filter: alpha(opacity=0); - z-index: -1; - -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; -} - -.qq-upload-file.qq-editable { - cursor: pointer; - margin-right: 4px; -} - -.qq-edit-filename-icon.qq-editable { - display: inline-block; - cursor: pointer; -} - -INPUT.qq-edit-filename.qq-editing { - position: static; - height: 28px; - padding: 0 8px; - margin-right: 10px; - margin-bottom: -5px; - border: 1px solid #ccc; - border-radius: 2px; - font-size: 16px; - - opacity: 1; - filter: alpha(opacity=100); - -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"; -} - -.qq-edit-filename-icon { - display: none; - background: url("edit.gif"); - width: 15px; - height: 15px; - vertical-align: text-bottom; - margin-right: 16px; -} - -.qq-hide { - display: none; -} - - -/* Thumbnail ------------------------------------------- */ -.qq-thumbnail-selector { - vertical-align: middle; - margin-right: 12px; -} - - -/* element styles */ -.qq-uploader DIALOG { - display: none; -} - -.qq-uploader DIALOG[open] { - display: block; -} - -.qq-uploader DIALOG { - display: none; -} - -.qq-uploader DIALOG[open] { - display: block; -} - -.qq-uploader DIALOG .qq-dialog-buttons { - text-align: center; - padding-top: 10px; -} - -.qq-uploader DIALOG .qq-dialog-buttons BUTTON { - margin-left: 5px; - margin-right: 5px; -} - -.qq-uploader DIALOG .qq-dialog-message-selector { - padding-bottom: 10px; -} - -.qq-uploader DIALOG::backdrop { - background-color: rgba(0, 0, 0, 0.7); -} \ No newline at end of file diff --git a/resources/fine-uploader/fine-uploader-new.min.css b/resources/fine-uploader/fine-uploader-new.min.css deleted file mode 100644 index 40bcea0..0000000 --- a/resources/fine-uploader/fine-uploader-new.min.css +++ /dev/null @@ -1 +0,0 @@ -.qq-btn{box-shadow:0 1px 1px rgba(255,255,255,.37) inset,1px 0 1px rgba(255,255,255,.07) inset,0 1px 0 rgba(0,0,0,.36),0 -2px 12px rgba(0,0,0,.08) inset;padding:3px 4px;border:1px solid #ccc;border-radius:2px;color:inherit;background-color:#fff}.qq-upload-continue,.qq-upload-delete,.qq-upload-pause{display:inline}.qq-upload-delete{background-color:#e65c47;color:#fafafa;border-color:#dc523d;text-shadow:0 1px 1px rgba(0,0,0,.55)}.qq-upload-delete:hover{background-color:#f56b56}.qq-upload-cancel{background-color:#f5d7d7;border-color:#e6c8c8}.qq-upload-cancel:hover{background-color:#ffe1e1}.qq-upload-retry{background-color:#ebf6e0;border-color:#d2ddc7}.qq-upload-retry:hover{background-color:#f7ffec}.qq-upload-continue,.qq-upload-pause{background-color:#00abc7;color:#fafafa;border-color:#2dadc2;text-shadow:0 1px 1px rgba(0,0,0,.55)}.qq-upload-continue:hover,.qq-upload-pause:hover{background-color:#0fbad6}.qq-upload-button{display:inline;width:105px;margin-bottom:10px;padding:7px 10px;text-align:center;float:left;background:#00abc7;color:#fff;border-radius:2px;border:1px solid #2dadc2;box-shadow:0 1px 1px rgba(255,255,255,.37) inset,1px 0 1px rgba(255,255,255,.07) inset,0 1px 0 rgba(0,0,0,.36),0 -2px 12px rgba(0,0,0,.08) inset}.qq-upload-button-hover{background:#33b6cc}.qq-upload-button-focus{outline:1px dotted #000}.qq-uploader{position:relative;min-height:200px;max-height:490px;overflow-y:hidden;width:inherit;border-radius:6px;background-color:#fdfdfd;border:1px dashed #ccc;padding:20px}.qq-uploader:before{content:attr(qq-drop-area-text) " ";position:absolute;font-size:200%;left:0;width:100%;text-align:center;top:45%;opacity:.25}.qq-upload-drop-area,.qq-upload-extra-drop-area{position:absolute;top:0;left:0;width:100%;height:100%;min-height:30px;z-index:2;background:#f9f9f9;border-radius:4px;border:1px dashed #ccc;text-align:center}.qq-upload-drop-area span{display:block;position:absolute;top:50%;width:100%;margin-top:-8px;font-size:16px}.qq-upload-extra-drop-area{position:relative;margin-top:50px;font-size:16px;padding-top:30px;height:20px;min-height:40px}.qq-upload-drop-area-active{background:#fdfdfd;border-radius:4px;border:1px dashed #ccc}.qq-upload-list{margin:0;padding:0;list-style:none;max-height:450px;overflow-y:auto;box-shadow:0 1px 0 rgba(15,15,50,.14);clear:both}.qq-upload-list li{margin:0;padding:9px;line-height:15px;font-size:16px;color:#424242;background-color:#f6f6f6;border-top:1px solid #fff;border-bottom:1px solid #ddd}.qq-upload-list li:first-child{border-top:none}.qq-upload-list li:last-child{border-bottom:none}.qq-upload-cancel,.qq-upload-continue,.qq-upload-delete,.qq-upload-failed-text,.qq-upload-file,.qq-upload-pause,.qq-upload-retry,.qq-upload-size,.qq-upload-spinner{margin-right:12px;display:inline}.qq-upload-file{vertical-align:middle;display:inline-block;width:300px;text-overflow:ellipsis;white-space:nowrap;overflow-x:hidden;height:18px}.qq-upload-spinner{display:inline-block;background:url(loading.gif);width:15px;height:15px;vertical-align:text-bottom}.qq-drop-processing{display:block}.qq-drop-processing-spinner{display:inline-block;background:url(processing.gif);width:24px;height:24px;vertical-align:text-bottom}.qq-upload-cancel,.qq-upload-continue,.qq-upload-delete,.qq-upload-pause,.qq-upload-retry,.qq-upload-size{font-size:12px;font-weight:400;cursor:pointer;vertical-align:middle}.qq-upload-status-text{font-size:14px;font-weight:700;display:block}.qq-upload-failed-text{display:none;font-style:italic;font-weight:700}.qq-upload-failed-icon{display:none;width:15px;height:15px;vertical-align:text-bottom}.qq-upload-fail .qq-upload-failed-text{display:inline}.qq-upload-retrying .qq-upload-failed-text{display:inline}.qq-upload-list li.qq-upload-success{background-color:#ebf6e0;color:#424242;border-bottom:1px solid #d3ded1;border-top:1px solid #f7fff5}.qq-upload-list li.qq-upload-fail{background-color:#f5d7d7;color:#424242;border-bottom:1px solid #decaca;border-top:1px solid #fce6e6}.qq-progress-bar{display:block;display:block;background:#00abc7;width:0;height:15px;border-radius:6px;margin-bottom:3px}.qq-total-progress-bar{height:25px;border-radius:9px}.qq-total-progress-bar-container{margin-left:9px;display:inline;float:right;width:500px}INPUT.qq-edit-filename{position:absolute;opacity:0;z-index:-1}.qq-upload-file.qq-editable{cursor:pointer;margin-right:4px}.qq-edit-filename-icon.qq-editable{display:inline-block;cursor:pointer}INPUT.qq-edit-filename.qq-editing{position:static;height:28px;padding:0 8px;margin-right:10px;margin-bottom:-5px;border:1px solid #ccc;border-radius:2px;font-size:16px;opacity:1}.qq-edit-filename-icon{display:none;background:url(edit.gif);width:15px;height:15px;vertical-align:text-bottom;margin-right:16px}.qq-hide{display:none}.qq-thumbnail-selector{vertical-align:middle;margin-right:12px}.qq-uploader DIALOG{display:none}.qq-uploader DIALOG[open]{display:block}.qq-uploader DIALOG{display:none}.qq-uploader DIALOG[open]{display:block}.qq-uploader DIALOG .qq-dialog-buttons{text-align:center;padding-top:10px}.qq-uploader DIALOG .qq-dialog-buttons BUTTON{margin-left:5px;margin-right:5px}.qq-uploader DIALOG .qq-dialog-message-selector{padding-bottom:10px}.qq-uploader DIALOG::backdrop{background-color:rgba(0,0,0,.7)}/*# sourceMappingURL=fine-uploader-new.min.css.map */ \ No newline at end of file diff --git a/resources/fine-uploader/fine-uploader-new.min.css.map b/resources/fine-uploader/fine-uploader-new.min.css.map deleted file mode 100644 index 4ef57d3..0000000 --- a/resources/fine-uploader/fine-uploader-new.min.css.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["_build/fine-uploader-new.css"],"names":[],"mappings":"AAMA,QAEI,WAAY,EAAE,IAAI,IAAI,sBAA0B,KAAK,CACzC,IAAI,EAAE,IAAI,sBAA0B,KAAK,CACzC,EAAE,IAAI,EAAE,eAAmB,CAC3B,EAAE,KAAK,KAAK,gBAAoB,MAC5C,QAAS,IAAI,IACb,OAAQ,IAAI,MAAM,KAClB,cAAe,IACf,MAAO,QACP,iBAAkB,KAEe,oBAArC,kBAAmB,iBACf,QAAS,OAEb,kBAEI,iBAAkB,QAClB,MAAO,QACP,aAAc,QACd,YAAa,EAAE,IAAI,IAAI,gBAE3B,wBACI,iBAAkB,QAEtB,kBAEI,iBAAkB,QAClB,aAAc,QAElB,wBACI,iBAAkB,QAEtB,iBAEI,iBAAkB,QAClB,aAAc,QAElB,uBACI,iBAAkB,QAEJ,oBAAlB,iBACI,iBAAkB,QAClB,MAAO,QACP,aAAc,QACd,YAAa,EAAE,IAAI,IAAI,gBAEH,0BAAxB,uBACI,iBAAkB,QAKtB,kBACI,QAAS,OACT,MAAO,MACP,cAAe,KACf,QAAS,IAAI,KACb,WAAY,OACZ,MAAO,KACP,WAAY,QACZ,MAAO,KACP,cAAe,IACf,OAAQ,IAAI,MAAM,QAClB,WAAY,EAAE,IAAI,IAAI,sBAA0B,KAAK,CACzC,IAAI,EAAE,IAAI,sBAA0B,KAAK,CACzC,EAAE,IAAI,EAAE,eAAmB,CAC3B,EAAE,KAAK,KAAK,gBAAoB,MAEhD,wBACI,WAAY,QAEhB,wBACI,QAAS,IAAI,OAAO,KAMxB,aACI,SAAU,SACV,WAAY,MACZ,WAAY,MACZ,WAAY,OACZ,MAAO,QACP,cAAe,IACf,iBAAkB,QAClB,OAAQ,IAAI,OAAO,KACnB,QAAS,KAEb,oBACI,QAAS,wBAAwB,IACjC,SAAU,SACV,UAAW,KACX,KAAM,EACN,MAAO,KACP,WAAY,OACZ,IAAK,IACL,QAAS,IAEb,qBAAsB,2BAClB,SAAU,SACV,IAAK,EACL,KAAM,EACN,MAAO,KACP,OAAQ,KACR,WAAY,KACZ,QAAS,EACT,WAAY,QACZ,cAAe,IACf,OAAQ,IAAI,OAAO,KACnB,WAAY,OAEhB,0BACI,QAAS,MACT,SAAU,SACV,IAAK,IACL,MAAO,KACP,WAAY,KACZ,UAAW,KAEf,2BACI,SAAU,SACV,WAAY,KACZ,UAAW,KACX,YAAa,KACb,OAAQ,KACR,WAAY,KAEhB,4BACI,WAAY,QACZ,cAAe,IACf,OAAQ,IAAI,OAAO,KAEvB,gBACI,OAAQ,EACR,QAAS,EACT,WAAY,KACZ,WAAY,MACZ,WAAY,KACZ,WAAY,EAAI,IAAI,EAAI,mBACxB,MAAO,KAMX,mBACI,OAAQ,EACR,QAAS,IACT,YAAa,KACb,UAAW,KACX,MAAO,QACP,iBAAkB,QAClB,WAAY,IAAI,MAAM,KACtB,cAAe,IAAI,MAAM,KAE7B,+BACI,WAAY,KAEhB,8BACI,cAAe,KAInB,kBACqC,oBAArC,kBADqC,uBADrC,gBAEmB,iBADA,iBADkB,gBAApB,mBAGb,aAAc,KACd,QAAS,OAEb,gBACI,eAAgB,OAChB,QAAS,aACT,MAAO,MACP,cAAe,SACf,YAAa,OACb,WAAY,OACZ,OAAQ,KAEZ,mBACI,QAAS,aACT,WAAY,iBACZ,MAAO,KACP,OAAQ,KACR,eAAgB,YAEpB,oBACI,QAAS,MAEb,4BACI,QAAS,aACT,WAAY,oBACZ,MAAO,KACP,OAAQ,KACR,eAAgB,YAEH,kBACoB,oBAArC,kBAAmB,iBADiB,iBAApC,gBAEI,UAAW,KACX,YAAa,IACb,OAAQ,QACR,eAAgB,OAEpB,uBACI,UAAW,KACX,YAAa,IACb,QAAS,MAEb,uBACI,QAAS,KACT,WAAY,OACZ,YAAa,IAEjB,uBACI,QAAQ,KACR,MAAM,KACN,OAAO,KACP,eAAe,YAEnB,uCACI,QAAS,OAEb,2CACI,QAAS,OAEb,qCACI,iBAAkB,QAClB,MAAO,QACP,cAAe,IAAI,MAAM,QACzB,WAAY,IAAI,MAAM,QAE1B,kCACI,iBAAkB,QAClB,MAAO,QACP,cAAe,IAAI,MAAM,QACzB,WAAY,IAAI,MAAM,QAE1B,iBACI,QAAS,MACT,QAAS,MACT,WAAY,QACZ,MAAO,EACP,OAAQ,KACR,cAAe,IACf,cAAe,IAGnB,uBACI,OAAQ,KACR,cAAe,IAGnB,iCACI,YAAa,IACb,QAAS,OACT,MAAO,MACP,MAAO,MAGX,uBACI,SAAU,SACV,QAAS,EAET,QAAS,GAIb,4BACI,OAAQ,QACR,aAAc,IAGlB,mCACI,QAAS,aACT,OAAQ,QAGZ,kCACI,SAAU,OACV,OAAQ,KACR,QAAS,EAAE,IACX,aAAc,KACd,cAAe,KACf,OAAQ,IAAI,MAAM,KAClB,cAAe,IACf,UAAW,KAEX,QAAS,EAKb,uBACI,QAAS,KACT,WAAY,cACZ,MAAO,KACP,OAAQ,KACR,eAAgB,YAChB,aAAc,KAGlB,SACI,QAAS,KAMb,uBACI,eAAgB,OAChB,aAAc,KAKlB,oBACI,QAAS,KAGb,0BACI,QAAS,MAGb,oBACI,QAAS,KAGb,0BACI,QAAS,MAGb,uCACI,WAAY,OACZ,YAAa,KAGjB,8CACI,YAAa,IACb,aAAc,IAGlB,gDACI,eAAgB,KAGpB,8BACI,iBAAkB"} \ No newline at end of file diff --git a/resources/fine-uploader/fine-uploader.core.js b/resources/fine-uploader/fine-uploader.core.js deleted file mode 100644 index 229a128..0000000 --- a/resources/fine-uploader/fine-uploader.core.js +++ /dev/null @@ -1,5775 +0,0 @@ -// Fine Uploader 5.16.2 - MIT licensed. http://fineuploader.com -(function(global) { - var qq = function(element) { - "use strict"; - return { - hide: function() { - element.style.display = "none"; - return this; - }, - attach: function(type, fn) { - if (element.addEventListener) { - element.addEventListener(type, fn, false); - } else if (element.attachEvent) { - element.attachEvent("on" + type, fn); - } - return function() { - qq(element).detach(type, fn); - }; - }, - detach: function(type, fn) { - if (element.removeEventListener) { - element.removeEventListener(type, fn, false); - } else if (element.attachEvent) { - element.detachEvent("on" + type, fn); - } - return this; - }, - contains: function(descendant) { - if (!descendant) { - return false; - } - if (element === descendant) { - return true; - } - if (element.contains) { - return element.contains(descendant); - } else { - return !!(descendant.compareDocumentPosition(element) & 8); - } - }, - insertBefore: function(elementB) { - elementB.parentNode.insertBefore(element, elementB); - return this; - }, - remove: function() { - element.parentNode.removeChild(element); - return this; - }, - css: function(styles) { - if (element.style == null) { - throw new qq.Error("Can't apply style to node as it is not on the HTMLElement prototype chain!"); - } - if (styles.opacity != null) { - if (typeof element.style.opacity !== "string" && typeof element.filters !== "undefined") { - styles.filter = "alpha(opacity=" + Math.round(100 * styles.opacity) + ")"; - } - } - qq.extend(element.style, styles); - return this; - }, - hasClass: function(name, considerParent) { - var re = new RegExp("(^| )" + name + "( |$)"); - return re.test(element.className) || !!(considerParent && re.test(element.parentNode.className)); - }, - addClass: function(name) { - if (!qq(element).hasClass(name)) { - element.className += " " + name; - } - return this; - }, - removeClass: function(name) { - var re = new RegExp("(^| )" + name + "( |$)"); - element.className = element.className.replace(re, " ").replace(/^\s+|\s+$/g, ""); - return this; - }, - getByClass: function(className, first) { - var candidates, result = []; - if (first && element.querySelector) { - return element.querySelector("." + className); - } else if (element.querySelectorAll) { - return element.querySelectorAll("." + className); - } - candidates = element.getElementsByTagName("*"); - qq.each(candidates, function(idx, val) { - if (qq(val).hasClass(className)) { - result.push(val); - } - }); - return first ? result[0] : result; - }, - getFirstByClass: function(className) { - return qq(element).getByClass(className, true); - }, - children: function() { - var children = [], child = element.firstChild; - while (child) { - if (child.nodeType === 1) { - children.push(child); - } - child = child.nextSibling; - } - return children; - }, - setText: function(text) { - element.innerText = text; - element.textContent = text; - return this; - }, - clearText: function() { - return qq(element).setText(""); - }, - hasAttribute: function(attrName) { - var attrVal; - if (element.hasAttribute) { - if (!element.hasAttribute(attrName)) { - return false; - } - return /^false$/i.exec(element.getAttribute(attrName)) == null; - } else { - attrVal = element[attrName]; - if (attrVal === undefined) { - return false; - } - return /^false$/i.exec(attrVal) == null; - } - } - }; - }; - (function() { - "use strict"; - qq.canvasToBlob = function(canvas, mime, quality) { - return qq.dataUriToBlob(canvas.toDataURL(mime, quality)); - }; - qq.dataUriToBlob = function(dataUri) { - var arrayBuffer, byteString, createBlob = function(data, mime) { - var BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder, blobBuilder = BlobBuilder && new BlobBuilder(); - if (blobBuilder) { - blobBuilder.append(data); - return blobBuilder.getBlob(mime); - } else { - return new Blob([ data ], { - type: mime - }); - } - }, intArray, mimeString; - if (dataUri.split(",")[0].indexOf("base64") >= 0) { - byteString = atob(dataUri.split(",")[1]); - } else { - byteString = decodeURI(dataUri.split(",")[1]); - } - mimeString = dataUri.split(",")[0].split(":")[1].split(";")[0]; - arrayBuffer = new ArrayBuffer(byteString.length); - intArray = new Uint8Array(arrayBuffer); - qq.each(byteString, function(idx, character) { - intArray[idx] = character.charCodeAt(0); - }); - return createBlob(arrayBuffer, mimeString); - }; - qq.log = function(message, level) { - if (window.console) { - if (!level || level === "info") { - window.console.log(message); - } else { - if (window.console[level]) { - window.console[level](message); - } else { - window.console.log("<" + level + "> " + message); - } - } - } - }; - qq.isObject = function(variable) { - return variable && !variable.nodeType && Object.prototype.toString.call(variable) === "[object Object]"; - }; - qq.isFunction = function(variable) { - return typeof variable === "function"; - }; - qq.isArray = function(value) { - return Object.prototype.toString.call(value) === "[object Array]" || value && window.ArrayBuffer && value.buffer && value.buffer.constructor === ArrayBuffer; - }; - qq.isItemList = function(maybeItemList) { - return Object.prototype.toString.call(maybeItemList) === "[object DataTransferItemList]"; - }; - qq.isNodeList = function(maybeNodeList) { - return Object.prototype.toString.call(maybeNodeList) === "[object NodeList]" || maybeNodeList.item && maybeNodeList.namedItem; - }; - qq.isString = function(maybeString) { - return Object.prototype.toString.call(maybeString) === "[object String]"; - }; - qq.trimStr = function(string) { - if (String.prototype.trim) { - return string.trim(); - } - return string.replace(/^\s+|\s+$/g, ""); - }; - qq.format = function(str) { - var args = Array.prototype.slice.call(arguments, 1), newStr = str, nextIdxToReplace = newStr.indexOf("{}"); - qq.each(args, function(idx, val) { - var strBefore = newStr.substring(0, nextIdxToReplace), strAfter = newStr.substring(nextIdxToReplace + 2); - newStr = strBefore + val + strAfter; - nextIdxToReplace = newStr.indexOf("{}", nextIdxToReplace + val.length); - if (nextIdxToReplace < 0) { - return false; - } - }); - return newStr; - }; - qq.isFile = function(maybeFile) { - return window.File && Object.prototype.toString.call(maybeFile) === "[object File]"; - }; - qq.isFileList = function(maybeFileList) { - return window.FileList && Object.prototype.toString.call(maybeFileList) === "[object FileList]"; - }; - qq.isFileOrInput = function(maybeFileOrInput) { - return qq.isFile(maybeFileOrInput) || qq.isInput(maybeFileOrInput); - }; - qq.isInput = function(maybeInput, notFile) { - var evaluateType = function(type) { - var normalizedType = type.toLowerCase(); - if (notFile) { - return normalizedType !== "file"; - } - return normalizedType === "file"; - }; - if (window.HTMLInputElement) { - if (Object.prototype.toString.call(maybeInput) === "[object HTMLInputElement]") { - if (maybeInput.type && evaluateType(maybeInput.type)) { - return true; - } - } - } - if (maybeInput.tagName) { - if (maybeInput.tagName.toLowerCase() === "input") { - if (maybeInput.type && evaluateType(maybeInput.type)) { - return true; - } - } - } - return false; - }; - qq.isBlob = function(maybeBlob) { - if (window.Blob && Object.prototype.toString.call(maybeBlob) === "[object Blob]") { - return true; - } - }; - qq.isXhrUploadSupported = function() { - var input = document.createElement("input"); - input.type = "file"; - return input.multiple !== undefined && typeof File !== "undefined" && typeof FormData !== "undefined" && typeof qq.createXhrInstance().upload !== "undefined"; - }; - qq.createXhrInstance = function() { - if (window.XMLHttpRequest) { - return new XMLHttpRequest(); - } - try { - return new ActiveXObject("MSXML2.XMLHTTP.3.0"); - } catch (error) { - qq.log("Neither XHR or ActiveX are supported!", "error"); - return null; - } - }; - qq.isFolderDropSupported = function(dataTransfer) { - return dataTransfer.items && dataTransfer.items.length > 0 && dataTransfer.items[0].webkitGetAsEntry; - }; - qq.isFileChunkingSupported = function() { - return !qq.androidStock() && qq.isXhrUploadSupported() && (File.prototype.slice !== undefined || File.prototype.webkitSlice !== undefined || File.prototype.mozSlice !== undefined); - }; - qq.sliceBlob = function(fileOrBlob, start, end) { - var slicer = fileOrBlob.slice || fileOrBlob.mozSlice || fileOrBlob.webkitSlice; - return slicer.call(fileOrBlob, start, end); - }; - qq.arrayBufferToHex = function(buffer) { - var bytesAsHex = "", bytes = new Uint8Array(buffer); - qq.each(bytes, function(idx, byt) { - var byteAsHexStr = byt.toString(16); - if (byteAsHexStr.length < 2) { - byteAsHexStr = "0" + byteAsHexStr; - } - bytesAsHex += byteAsHexStr; - }); - return bytesAsHex; - }; - qq.readBlobToHex = function(blob, startOffset, length) { - var initialBlob = qq.sliceBlob(blob, startOffset, startOffset + length), fileReader = new FileReader(), promise = new qq.Promise(); - fileReader.onload = function() { - promise.success(qq.arrayBufferToHex(fileReader.result)); - }; - fileReader.onerror = promise.failure; - fileReader.readAsArrayBuffer(initialBlob); - return promise; - }; - qq.extend = function(first, second, extendNested) { - qq.each(second, function(prop, val) { - if (extendNested && qq.isObject(val)) { - if (first[prop] === undefined) { - first[prop] = {}; - } - qq.extend(first[prop], val, true); - } else { - first[prop] = val; - } - }); - return first; - }; - qq.override = function(target, sourceFn) { - var super_ = {}, source = sourceFn(super_); - qq.each(source, function(srcPropName, srcPropVal) { - if (target[srcPropName] !== undefined) { - super_[srcPropName] = target[srcPropName]; - } - target[srcPropName] = srcPropVal; - }); - return target; - }; - qq.indexOf = function(arr, elt, from) { - if (arr.indexOf) { - return arr.indexOf(elt, from); - } - from = from || 0; - var len = arr.length; - if (from < 0) { - from += len; - } - for (;from < len; from += 1) { - if (arr.hasOwnProperty(from) && arr[from] === elt) { - return from; - } - } - return -1; - }; - qq.getUniqueId = function() { - return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) { - var r = Math.random() * 16 | 0, v = c == "x" ? r : r & 3 | 8; - return v.toString(16); - }); - }; - qq.ie = function() { - return navigator.userAgent.indexOf("MSIE") !== -1 || navigator.userAgent.indexOf("Trident") !== -1; - }; - qq.ie7 = function() { - return navigator.userAgent.indexOf("MSIE 7") !== -1; - }; - qq.ie8 = function() { - return navigator.userAgent.indexOf("MSIE 8") !== -1; - }; - qq.ie10 = function() { - return navigator.userAgent.indexOf("MSIE 10") !== -1; - }; - qq.ie11 = function() { - return qq.ie() && navigator.userAgent.indexOf("rv:11") !== -1; - }; - qq.edge = function() { - return navigator.userAgent.indexOf("Edge") >= 0; - }; - qq.safari = function() { - return navigator.vendor !== undefined && navigator.vendor.indexOf("Apple") !== -1; - }; - qq.chrome = function() { - return navigator.vendor !== undefined && navigator.vendor.indexOf("Google") !== -1; - }; - qq.opera = function() { - return navigator.vendor !== undefined && navigator.vendor.indexOf("Opera") !== -1; - }; - qq.firefox = function() { - return !qq.edge() && !qq.ie11() && navigator.userAgent.indexOf("Mozilla") !== -1 && navigator.vendor !== undefined && navigator.vendor === ""; - }; - qq.windows = function() { - return navigator.platform === "Win32"; - }; - qq.android = function() { - return navigator.userAgent.toLowerCase().indexOf("android") !== -1; - }; - qq.androidStock = function() { - return qq.android() && navigator.userAgent.toLowerCase().indexOf("chrome") < 0; - }; - qq.ios6 = function() { - return qq.ios() && navigator.userAgent.indexOf(" OS 6_") !== -1; - }; - qq.ios7 = function() { - return qq.ios() && navigator.userAgent.indexOf(" OS 7_") !== -1; - }; - qq.ios8 = function() { - return qq.ios() && navigator.userAgent.indexOf(" OS 8_") !== -1; - }; - qq.ios800 = function() { - return qq.ios() && navigator.userAgent.indexOf(" OS 8_0 ") !== -1; - }; - qq.ios = function() { - return navigator.userAgent.indexOf("iPad") !== -1 || navigator.userAgent.indexOf("iPod") !== -1 || navigator.userAgent.indexOf("iPhone") !== -1; - }; - qq.iosChrome = function() { - return qq.ios() && navigator.userAgent.indexOf("CriOS") !== -1; - }; - qq.iosSafari = function() { - return qq.ios() && !qq.iosChrome() && navigator.userAgent.indexOf("Safari") !== -1; - }; - qq.iosSafariWebView = function() { - return qq.ios() && !qq.iosChrome() && !qq.iosSafari(); - }; - qq.preventDefault = function(e) { - if (e.preventDefault) { - e.preventDefault(); - } else { - e.returnValue = false; - } - }; - qq.toElement = function() { - var div = document.createElement("div"); - return function(html) { - div.innerHTML = html; - var element = div.firstChild; - div.removeChild(element); - return element; - }; - }(); - qq.each = function(iterableItem, callback) { - var keyOrIndex, retVal; - if (iterableItem) { - if (window.Storage && iterableItem.constructor === window.Storage) { - for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) { - retVal = callback(iterableItem.key(keyOrIndex), iterableItem.getItem(iterableItem.key(keyOrIndex))); - if (retVal === false) { - break; - } - } - } else if (qq.isArray(iterableItem) || qq.isItemList(iterableItem) || qq.isNodeList(iterableItem)) { - for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) { - retVal = callback(keyOrIndex, iterableItem[keyOrIndex]); - if (retVal === false) { - break; - } - } - } else if (qq.isString(iterableItem)) { - for (keyOrIndex = 0; keyOrIndex < iterableItem.length; keyOrIndex++) { - retVal = callback(keyOrIndex, iterableItem.charAt(keyOrIndex)); - if (retVal === false) { - break; - } - } - } else { - for (keyOrIndex in iterableItem) { - if (Object.prototype.hasOwnProperty.call(iterableItem, keyOrIndex)) { - retVal = callback(keyOrIndex, iterableItem[keyOrIndex]); - if (retVal === false) { - break; - } - } - } - } - } - }; - qq.bind = function(oldFunc, context) { - if (qq.isFunction(oldFunc)) { - var args = Array.prototype.slice.call(arguments, 2); - return function() { - var newArgs = qq.extend([], args); - if (arguments.length) { - newArgs = newArgs.concat(Array.prototype.slice.call(arguments)); - } - return oldFunc.apply(context, newArgs); - }; - } - throw new Error("first parameter must be a function!"); - }; - qq.obj2url = function(obj, temp, prefixDone) { - var uristrings = [], prefix = "&", add = function(nextObj, i) { - var nextTemp = temp ? /\[\]$/.test(temp) ? temp : temp + "[" + i + "]" : i; - if (nextTemp !== "undefined" && i !== "undefined") { - uristrings.push(typeof nextObj === "object" ? qq.obj2url(nextObj, nextTemp, true) : Object.prototype.toString.call(nextObj) === "[object Function]" ? encodeURIComponent(nextTemp) + "=" + encodeURIComponent(nextObj()) : encodeURIComponent(nextTemp) + "=" + encodeURIComponent(nextObj)); - } - }; - if (!prefixDone && temp) { - prefix = /\?/.test(temp) ? /\?$/.test(temp) ? "" : "&" : "?"; - uristrings.push(temp); - uristrings.push(qq.obj2url(obj)); - } else if (Object.prototype.toString.call(obj) === "[object Array]" && typeof obj !== "undefined") { - qq.each(obj, function(idx, val) { - add(val, idx); - }); - } else if (typeof obj !== "undefined" && obj !== null && typeof obj === "object") { - qq.each(obj, function(prop, val) { - add(val, prop); - }); - } else { - uristrings.push(encodeURIComponent(temp) + "=" + encodeURIComponent(obj)); - } - if (temp) { - return uristrings.join(prefix); - } else { - return uristrings.join(prefix).replace(/^&/, "").replace(/%20/g, "+"); - } - }; - qq.obj2FormData = function(obj, formData, arrayKeyName) { - if (!formData) { - formData = new FormData(); - } - qq.each(obj, function(key, val) { - key = arrayKeyName ? arrayKeyName + "[" + key + "]" : key; - if (qq.isObject(val)) { - qq.obj2FormData(val, formData, key); - } else if (qq.isFunction(val)) { - formData.append(key, val()); - } else { - formData.append(key, val); - } - }); - return formData; - }; - qq.obj2Inputs = function(obj, form) { - var input; - if (!form) { - form = document.createElement("form"); - } - qq.obj2FormData(obj, { - append: function(key, val) { - input = document.createElement("input"); - input.setAttribute("name", key); - input.setAttribute("value", val); - form.appendChild(input); - } - }); - return form; - }; - qq.parseJson = function(json) { - if (window.JSON && qq.isFunction(JSON.parse)) { - return JSON.parse(json); - } else { - return eval("(" + json + ")"); - } - }; - qq.getExtension = function(filename) { - var extIdx = filename.lastIndexOf(".") + 1; - if (extIdx > 0) { - return filename.substr(extIdx, filename.length - extIdx); - } - }; - qq.getFilename = function(blobOrFileInput) { - if (qq.isInput(blobOrFileInput)) { - return blobOrFileInput.value.replace(/.*(\/|\\)/, ""); - } else if (qq.isFile(blobOrFileInput)) { - if (blobOrFileInput.fileName !== null && blobOrFileInput.fileName !== undefined) { - return blobOrFileInput.fileName; - } - } - return blobOrFileInput.name; - }; - qq.DisposeSupport = function() { - var disposers = []; - return { - dispose: function() { - var disposer; - do { - disposer = disposers.shift(); - if (disposer) { - disposer(); - } - } while (disposer); - }, - attach: function() { - var args = arguments; - this.addDisposer(qq(args[0]).attach.apply(this, Array.prototype.slice.call(arguments, 1))); - }, - addDisposer: function(disposeFunction) { - disposers.push(disposeFunction); - } - }; - }; - })(); - (function() { - "use strict"; - if (typeof define === "function" && define.amd) { - define(function() { - return qq; - }); - } else if (typeof module !== "undefined" && module.exports) { - module.exports = qq; - } else { - global.qq = qq; - } - })(); - (function() { - "use strict"; - qq.Error = function(message) { - this.message = "[Fine Uploader " + qq.version + "] " + message; - }; - qq.Error.prototype = new Error(); - })(); - qq.version = "5.16.2"; - qq.supportedFeatures = function() { - "use strict"; - var supportsUploading, supportsUploadingBlobs, supportsFileDrop, supportsAjaxFileUploading, supportsFolderDrop, supportsChunking, supportsResume, supportsUploadViaPaste, supportsUploadCors, supportsDeleteFileXdr, supportsDeleteFileCorsXhr, supportsDeleteFileCors, supportsFolderSelection, supportsImagePreviews, supportsUploadProgress; - function testSupportsFileInputElement() { - var supported = true, tempInput; - try { - tempInput = document.createElement("input"); - tempInput.type = "file"; - qq(tempInput).hide(); - if (tempInput.disabled) { - supported = false; - } - } catch (ex) { - supported = false; - } - return supported; - } - function isChrome14OrHigher() { - return (qq.chrome() || qq.opera()) && navigator.userAgent.match(/Chrome\/[1][4-9]|Chrome\/[2-9][0-9]/) !== undefined; - } - function isCrossOriginXhrSupported() { - if (window.XMLHttpRequest) { - var xhr = qq.createXhrInstance(); - return xhr.withCredentials !== undefined; - } - return false; - } - function isXdrSupported() { - return window.XDomainRequest !== undefined; - } - function isCrossOriginAjaxSupported() { - if (isCrossOriginXhrSupported()) { - return true; - } - return isXdrSupported(); - } - function isFolderSelectionSupported() { - return document.createElement("input").webkitdirectory !== undefined; - } - function isLocalStorageSupported() { - try { - return !!window.localStorage && qq.isFunction(window.localStorage.setItem); - } catch (error) { - return false; - } - } - function isDragAndDropSupported() { - var span = document.createElement("span"); - return ("draggable" in span || "ondragstart" in span && "ondrop" in span) && !qq.android() && !qq.ios(); - } - supportsUploading = testSupportsFileInputElement(); - supportsAjaxFileUploading = supportsUploading && qq.isXhrUploadSupported(); - supportsUploadingBlobs = supportsAjaxFileUploading && !qq.androidStock(); - supportsFileDrop = supportsAjaxFileUploading && isDragAndDropSupported(); - supportsFolderDrop = supportsFileDrop && function() { - var input = document.createElement("input"); - input.type = "file"; - return !!("webkitdirectory" in (input || document.querySelectorAll("input[type=file]")[0])); - }(); - supportsChunking = supportsAjaxFileUploading && qq.isFileChunkingSupported(); - supportsResume = supportsAjaxFileUploading && supportsChunking && isLocalStorageSupported(); - supportsUploadViaPaste = supportsAjaxFileUploading && isChrome14OrHigher(); - supportsUploadCors = supportsUploading && (window.postMessage !== undefined || supportsAjaxFileUploading); - supportsDeleteFileCorsXhr = isCrossOriginXhrSupported(); - supportsDeleteFileXdr = isXdrSupported(); - supportsDeleteFileCors = isCrossOriginAjaxSupported(); - supportsFolderSelection = isFolderSelectionSupported(); - supportsImagePreviews = supportsAjaxFileUploading && window.FileReader !== undefined; - supportsUploadProgress = function() { - if (supportsAjaxFileUploading) { - return !qq.androidStock() && !qq.iosChrome(); - } - return false; - }(); - return { - ajaxUploading: supportsAjaxFileUploading, - blobUploading: supportsUploadingBlobs, - canDetermineSize: supportsAjaxFileUploading, - chunking: supportsChunking, - deleteFileCors: supportsDeleteFileCors, - deleteFileCorsXdr: supportsDeleteFileXdr, - deleteFileCorsXhr: supportsDeleteFileCorsXhr, - dialogElement: !!window.HTMLDialogElement, - fileDrop: supportsFileDrop, - folderDrop: supportsFolderDrop, - folderSelection: supportsFolderSelection, - imagePreviews: supportsImagePreviews, - imageValidation: supportsImagePreviews, - itemSizeValidation: supportsAjaxFileUploading, - pause: supportsChunking, - progressBar: supportsUploadProgress, - resume: supportsResume, - scaling: supportsImagePreviews && supportsUploadingBlobs, - tiffPreviews: qq.safari(), - unlimitedScaledImageSize: !qq.ios(), - uploading: supportsUploading, - uploadCors: supportsUploadCors, - uploadCustomHeaders: supportsAjaxFileUploading, - uploadNonMultipart: supportsAjaxFileUploading, - uploadViaPaste: supportsUploadViaPaste - }; - }(); - qq.isGenericPromise = function(maybePromise) { - "use strict"; - return !!(maybePromise && maybePromise.then && qq.isFunction(maybePromise.then)); - }; - qq.Promise = function() { - "use strict"; - var successArgs, failureArgs, successCallbacks = [], failureCallbacks = [], doneCallbacks = [], state = 0; - qq.extend(this, { - then: function(onSuccess, onFailure) { - if (state === 0) { - if (onSuccess) { - successCallbacks.push(onSuccess); - } - if (onFailure) { - failureCallbacks.push(onFailure); - } - } else if (state === -1) { - onFailure && onFailure.apply(null, failureArgs); - } else if (onSuccess) { - onSuccess.apply(null, successArgs); - } - return this; - }, - done: function(callback) { - if (state === 0) { - doneCallbacks.push(callback); - } else { - callback.apply(null, failureArgs === undefined ? successArgs : failureArgs); - } - return this; - }, - success: function() { - state = 1; - successArgs = arguments; - if (successCallbacks.length) { - qq.each(successCallbacks, function(idx, callback) { - callback.apply(null, successArgs); - }); - } - if (doneCallbacks.length) { - qq.each(doneCallbacks, function(idx, callback) { - callback.apply(null, successArgs); - }); - } - return this; - }, - failure: function() { - state = -1; - failureArgs = arguments; - if (failureCallbacks.length) { - qq.each(failureCallbacks, function(idx, callback) { - callback.apply(null, failureArgs); - }); - } - if (doneCallbacks.length) { - qq.each(doneCallbacks, function(idx, callback) { - callback.apply(null, failureArgs); - }); - } - return this; - } - }); - }; - qq.BlobProxy = function(referenceBlob, onCreate) { - "use strict"; - qq.extend(this, { - referenceBlob: referenceBlob, - create: function() { - return onCreate(referenceBlob); - } - }); - }; - qq.UploadButton = function(o) { - "use strict"; - var self = this, disposeSupport = new qq.DisposeSupport(), options = { - acceptFiles: null, - element: null, - focusClass: "qq-upload-button-focus", - folders: false, - hoverClass: "qq-upload-button-hover", - ios8BrowserCrashWorkaround: false, - multiple: false, - name: "qqfile", - onChange: function(input) {}, - title: null - }, input, buttonId; - qq.extend(options, o); - buttonId = qq.getUniqueId(); - function createInput() { - var input = document.createElement("input"); - input.setAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME, buttonId); - input.setAttribute("title", options.title); - self.setMultiple(options.multiple, input); - if (options.folders && qq.supportedFeatures.folderSelection) { - input.setAttribute("webkitdirectory", ""); - } - if (options.acceptFiles) { - input.setAttribute("accept", options.acceptFiles); - } - input.setAttribute("type", "file"); - input.setAttribute("name", options.name); - qq(input).css({ - position: "absolute", - right: 0, - top: 0, - fontFamily: "Arial", - fontSize: qq.ie() && !qq.ie8() ? "3500px" : "118px", - margin: 0, - padding: 0, - cursor: "pointer", - opacity: 0 - }); - !qq.ie7() && qq(input).css({ - height: "100%" - }); - options.element.appendChild(input); - disposeSupport.attach(input, "change", function() { - options.onChange(input); - }); - disposeSupport.attach(input, "mouseover", function() { - qq(options.element).addClass(options.hoverClass); - }); - disposeSupport.attach(input, "mouseout", function() { - qq(options.element).removeClass(options.hoverClass); - }); - disposeSupport.attach(input, "focus", function() { - qq(options.element).addClass(options.focusClass); - }); - disposeSupport.attach(input, "blur", function() { - qq(options.element).removeClass(options.focusClass); - }); - return input; - } - qq(options.element).css({ - position: "relative", - overflow: "hidden", - direction: "ltr" - }); - qq.extend(this, { - getInput: function() { - return input; - }, - getButtonId: function() { - return buttonId; - }, - setMultiple: function(isMultiple, optInput) { - var input = optInput || this.getInput(); - if (options.ios8BrowserCrashWorkaround && qq.ios8() && (qq.iosChrome() || qq.iosSafariWebView())) { - input.setAttribute("multiple", ""); - } else { - if (isMultiple) { - input.setAttribute("multiple", ""); - } else { - input.removeAttribute("multiple"); - } - } - }, - setAcceptFiles: function(acceptFiles) { - if (acceptFiles !== options.acceptFiles) { - input.setAttribute("accept", acceptFiles); - } - }, - reset: function() { - if (input.parentNode) { - qq(input).remove(); - } - qq(options.element).removeClass(options.focusClass); - input = null; - input = createInput(); - } - }); - input = createInput(); - }; - qq.UploadButton.BUTTON_ID_ATTR_NAME = "qq-button-id"; - qq.UploadData = function(uploaderProxy) { - "use strict"; - var data = [], byUuid = {}, byStatus = {}, byProxyGroupId = {}, byBatchId = {}; - function getDataByIds(idOrIds) { - if (qq.isArray(idOrIds)) { - var entries = []; - qq.each(idOrIds, function(idx, id) { - entries.push(data[id]); - }); - return entries; - } - return data[idOrIds]; - } - function getDataByUuids(uuids) { - if (qq.isArray(uuids)) { - var entries = []; - qq.each(uuids, function(idx, uuid) { - entries.push(data[byUuid[uuid]]); - }); - return entries; - } - return data[byUuid[uuids]]; - } - function getDataByStatus(status) { - var statusResults = [], statuses = [].concat(status); - qq.each(statuses, function(index, statusEnum) { - var statusResultIndexes = byStatus[statusEnum]; - if (statusResultIndexes !== undefined) { - qq.each(statusResultIndexes, function(i, dataIndex) { - statusResults.push(data[dataIndex]); - }); - } - }); - return statusResults; - } - qq.extend(this, { - addFile: function(spec) { - var status = spec.status || qq.status.SUBMITTING, id = data.push({ - name: spec.name, - originalName: spec.name, - uuid: spec.uuid, - size: spec.size == null ? -1 : spec.size, - status: status, - file: spec.file - }) - 1; - if (spec.batchId) { - data[id].batchId = spec.batchId; - if (byBatchId[spec.batchId] === undefined) { - byBatchId[spec.batchId] = []; - } - byBatchId[spec.batchId].push(id); - } - if (spec.proxyGroupId) { - data[id].proxyGroupId = spec.proxyGroupId; - if (byProxyGroupId[spec.proxyGroupId] === undefined) { - byProxyGroupId[spec.proxyGroupId] = []; - } - byProxyGroupId[spec.proxyGroupId].push(id); - } - data[id].id = id; - byUuid[spec.uuid] = id; - if (byStatus[status] === undefined) { - byStatus[status] = []; - } - byStatus[status].push(id); - spec.onBeforeStatusChange && spec.onBeforeStatusChange(id); - uploaderProxy.onStatusChange(id, null, status); - return id; - }, - retrieve: function(optionalFilter) { - if (qq.isObject(optionalFilter) && data.length) { - if (optionalFilter.id !== undefined) { - return getDataByIds(optionalFilter.id); - } else if (optionalFilter.uuid !== undefined) { - return getDataByUuids(optionalFilter.uuid); - } else if (optionalFilter.status) { - return getDataByStatus(optionalFilter.status); - } - } else { - return qq.extend([], data, true); - } - }, - removeFileRef: function(id) { - var record = getDataByIds(id); - if (record) { - delete record.file; - } - }, - reset: function() { - data = []; - byUuid = {}; - byStatus = {}; - byBatchId = {}; - }, - setStatus: function(id, newStatus) { - var oldStatus = data[id].status, byStatusOldStatusIndex = qq.indexOf(byStatus[oldStatus], id); - byStatus[oldStatus].splice(byStatusOldStatusIndex, 1); - data[id].status = newStatus; - if (byStatus[newStatus] === undefined) { - byStatus[newStatus] = []; - } - byStatus[newStatus].push(id); - uploaderProxy.onStatusChange(id, oldStatus, newStatus); - }, - uuidChanged: function(id, newUuid) { - var oldUuid = data[id].uuid; - data[id].uuid = newUuid; - byUuid[newUuid] = id; - delete byUuid[oldUuid]; - }, - updateName: function(id, newName) { - data[id].name = newName; - }, - updateSize: function(id, newSize) { - data[id].size = newSize; - }, - setParentId: function(targetId, parentId) { - data[targetId].parentId = parentId; - }, - getIdsInProxyGroup: function(id) { - var proxyGroupId = data[id].proxyGroupId; - if (proxyGroupId) { - return byProxyGroupId[proxyGroupId]; - } - return []; - }, - getIdsInBatch: function(id) { - var batchId = data[id].batchId; - return byBatchId[batchId]; - } - }); - }; - qq.status = { - SUBMITTING: "submitting", - SUBMITTED: "submitted", - REJECTED: "rejected", - QUEUED: "queued", - CANCELED: "canceled", - PAUSED: "paused", - UPLOADING: "uploading", - UPLOAD_FINALIZING: "upload finalizing", - UPLOAD_RETRYING: "retrying upload", - UPLOAD_SUCCESSFUL: "upload successful", - UPLOAD_FAILED: "upload failed", - DELETE_FAILED: "delete failed", - DELETING: "deleting", - DELETED: "deleted" - }; - (function() { - "use strict"; - qq.basePublicApi = { - addBlobs: function(blobDataOrArray, params, endpoint) { - this.addFiles(blobDataOrArray, params, endpoint); - }, - addInitialFiles: function(cannedFileList) { - var self = this; - qq.each(cannedFileList, function(index, cannedFile) { - self._addCannedFile(cannedFile); - }); - }, - addFiles: function(data, params, endpoint) { - this._maybeHandleIos8SafariWorkaround(); - var batchId = this._storedIds.length === 0 ? qq.getUniqueId() : this._currentBatchId, processBlob = qq.bind(function(blob) { - this._handleNewFile({ - blob: blob, - name: this._options.blobs.defaultName - }, batchId, verifiedFiles); - }, this), processBlobData = qq.bind(function(blobData) { - this._handleNewFile(blobData, batchId, verifiedFiles); - }, this), processCanvas = qq.bind(function(canvas) { - var blob = qq.canvasToBlob(canvas); - this._handleNewFile({ - blob: blob, - name: this._options.blobs.defaultName + ".png" - }, batchId, verifiedFiles); - }, this), processCanvasData = qq.bind(function(canvasData) { - var normalizedQuality = canvasData.quality && canvasData.quality / 100, blob = qq.canvasToBlob(canvasData.canvas, canvasData.type, normalizedQuality); - this._handleNewFile({ - blob: blob, - name: canvasData.name - }, batchId, verifiedFiles); - }, this), processFileOrInput = qq.bind(function(fileOrInput) { - if (qq.isInput(fileOrInput) && qq.supportedFeatures.ajaxUploading) { - var files = Array.prototype.slice.call(fileOrInput.files), self = this; - qq.each(files, function(idx, file) { - self._handleNewFile(file, batchId, verifiedFiles); - }); - } else { - this._handleNewFile(fileOrInput, batchId, verifiedFiles); - } - }, this), normalizeData = function() { - if (qq.isFileList(data)) { - data = Array.prototype.slice.call(data); - } - data = [].concat(data); - }, self = this, verifiedFiles = []; - this._currentBatchId = batchId; - if (data) { - normalizeData(); - qq.each(data, function(idx, fileContainer) { - if (qq.isFileOrInput(fileContainer)) { - processFileOrInput(fileContainer); - } else if (qq.isBlob(fileContainer)) { - processBlob(fileContainer); - } else if (qq.isObject(fileContainer)) { - if (fileContainer.blob && fileContainer.name) { - processBlobData(fileContainer); - } else if (fileContainer.canvas && fileContainer.name) { - processCanvasData(fileContainer); - } - } else if (fileContainer.tagName && fileContainer.tagName.toLowerCase() === "canvas") { - processCanvas(fileContainer); - } else { - self.log(fileContainer + " is not a valid file container! Ignoring!", "warn"); - } - }); - this.log("Received " + verifiedFiles.length + " files."); - this._prepareItemsForUpload(verifiedFiles, params, endpoint); - } - }, - cancel: function(id) { - var uploadData = this._uploadData.retrieve({ - id: id - }); - if (uploadData && uploadData.status === qq.status.UPLOAD_FINALIZING) { - this.log(qq.format("Ignoring cancel for file ID {} ({}). Finalizing upload.", id, this.getName(id)), "error"); - } else { - this._handler.cancel(id); - } - }, - cancelAll: function() { - var storedIdsCopy = [], self = this; - qq.extend(storedIdsCopy, this._storedIds); - qq.each(storedIdsCopy, function(idx, storedFileId) { - self.cancel(storedFileId); - }); - this._handler.cancelAll(); - }, - clearStoredFiles: function() { - this._storedIds = []; - }, - continueUpload: function(id) { - var uploadData = this._uploadData.retrieve({ - id: id - }); - if (!qq.supportedFeatures.pause || !this._options.chunking.enabled) { - return false; - } - if (uploadData.status === qq.status.PAUSED) { - this.log(qq.format("Paused file ID {} ({}) will be continued. Not paused.", id, this.getName(id))); - this._uploadFile(id); - return true; - } else { - this.log(qq.format("Ignoring continue for file ID {} ({}). Not paused.", id, this.getName(id)), "error"); - } - return false; - }, - deleteFile: function(id) { - return this._onSubmitDelete(id); - }, - doesExist: function(fileOrBlobId) { - return this._handler.isValid(fileOrBlobId); - }, - drawThumbnail: function(fileId, imgOrCanvas, maxSize, fromServer, customResizeFunction) { - var promiseToReturn = new qq.Promise(), fileOrUrl, options; - if (this._imageGenerator) { - fileOrUrl = this._thumbnailUrls[fileId]; - options = { - customResizeFunction: customResizeFunction, - maxSize: maxSize > 0 ? maxSize : null, - scale: maxSize > 0 - }; - if (!fromServer && qq.supportedFeatures.imagePreviews) { - fileOrUrl = this.getFile(fileId); - } - if (fileOrUrl == null) { - promiseToReturn.failure({ - container: imgOrCanvas, - error: "File or URL not found." - }); - } else { - this._imageGenerator.generate(fileOrUrl, imgOrCanvas, options).then(function success(modifiedContainer) { - promiseToReturn.success(modifiedContainer); - }, function failure(container, reason) { - promiseToReturn.failure({ - container: container, - error: reason || "Problem generating thumbnail" - }); - }); - } - } else { - promiseToReturn.failure({ - container: imgOrCanvas, - error: "Missing image generator module" - }); - } - return promiseToReturn; - }, - getButton: function(fileId) { - return this._getButton(this._buttonIdsForFileIds[fileId]); - }, - getEndpoint: function(fileId) { - return this._endpointStore.get(fileId); - }, - getFile: function(fileOrBlobId) { - var file = this._handler.getFile(fileOrBlobId); - var uploadDataRecord; - if (!file) { - uploadDataRecord = this._uploadData.retrieve({ - id: fileOrBlobId - }); - if (uploadDataRecord) { - file = uploadDataRecord.file; - } - } - return file || null; - }, - getInProgress: function() { - return this._uploadData.retrieve({ - status: [ qq.status.UPLOADING, qq.status.UPLOAD_RETRYING, qq.status.QUEUED ] - }).length; - }, - getName: function(id) { - return this._uploadData.retrieve({ - id: id - }).name; - }, - getParentId: function(id) { - var uploadDataEntry = this.getUploads({ - id: id - }), parentId = null; - if (uploadDataEntry) { - if (uploadDataEntry.parentId !== undefined) { - parentId = uploadDataEntry.parentId; - } - } - return parentId; - }, - getResumableFilesData: function() { - return this._handler.getResumableFilesData(); - }, - getSize: function(id) { - return this._uploadData.retrieve({ - id: id - }).size; - }, - getNetUploads: function() { - return this._netUploaded; - }, - getRemainingAllowedItems: function() { - var allowedItems = this._currentItemLimit; - if (allowedItems > 0) { - return allowedItems - this._netUploadedOrQueued; - } - return null; - }, - getUploads: function(optionalFilter) { - return this._uploadData.retrieve(optionalFilter); - }, - getUuid: function(id) { - return this._uploadData.retrieve({ - id: id - }).uuid; - }, - isResumable: function(id) { - return this._handler.hasResumeRecord(id); - }, - log: function(str, level) { - if (this._options.debug && (!level || level === "info")) { - qq.log("[Fine Uploader " + qq.version + "] " + str); - } else if (level && level !== "info") { - qq.log("[Fine Uploader " + qq.version + "] " + str, level); - } - }, - pauseUpload: function(id) { - var uploadData = this._uploadData.retrieve({ - id: id - }); - if (!qq.supportedFeatures.pause || !this._options.chunking.enabled) { - return false; - } - if (qq.indexOf([ qq.status.UPLOADING, qq.status.UPLOAD_RETRYING ], uploadData.status) >= 0) { - if (this._handler.pause(id)) { - this._uploadData.setStatus(id, qq.status.PAUSED); - return true; - } else { - this.log(qq.format("Unable to pause file ID {} ({}).", id, this.getName(id)), "error"); - } - } else { - this.log(qq.format("Ignoring pause for file ID {} ({}). Not in progress.", id, this.getName(id)), "error"); - } - return false; - }, - removeFileRef: function(id) { - this._handler.expunge(id); - this._uploadData.removeFileRef(id); - }, - reset: function() { - this.log("Resetting uploader..."); - this._handler.reset(); - this._storedIds = []; - this._autoRetries = []; - this._retryTimeouts = []; - this._preventRetries = []; - this._thumbnailUrls = []; - qq.each(this._buttons, function(idx, button) { - button.reset(); - }); - this._paramsStore.reset(); - this._endpointStore.reset(); - this._netUploadedOrQueued = 0; - this._netUploaded = 0; - this._uploadData.reset(); - this._buttonIdsForFileIds = []; - this._pasteHandler && this._pasteHandler.reset(); - this._options.session.refreshOnReset && this._refreshSessionData(); - this._succeededSinceLastAllComplete = []; - this._failedSinceLastAllComplete = []; - this._totalProgress && this._totalProgress.reset(); - this._customResumeDataStore.reset(); - }, - retry: function(id) { - return this._manualRetry(id); - }, - scaleImage: function(id, specs) { - var self = this; - return qq.Scaler.prototype.scaleImage(id, specs, { - log: qq.bind(self.log, self), - getFile: qq.bind(self.getFile, self), - uploadData: self._uploadData - }); - }, - setCustomHeaders: function(headers, id) { - this._customHeadersStore.set(headers, id); - }, - setCustomResumeData: function(id, data) { - this._customResumeDataStore.set(data, id); - }, - setDeleteFileCustomHeaders: function(headers, id) { - this._deleteFileCustomHeadersStore.set(headers, id); - }, - setDeleteFileEndpoint: function(endpoint, id) { - this._deleteFileEndpointStore.set(endpoint, id); - }, - setDeleteFileParams: function(params, id) { - this._deleteFileParamsStore.set(params, id); - }, - setEndpoint: function(endpoint, id) { - this._endpointStore.set(endpoint, id); - }, - setForm: function(elementOrId) { - this._updateFormSupportAndParams(elementOrId); - }, - setItemLimit: function(newItemLimit) { - this._currentItemLimit = newItemLimit; - }, - setName: function(id, newName) { - this._uploadData.updateName(id, newName); - }, - setParams: function(params, id) { - this._paramsStore.set(params, id); - }, - setUuid: function(id, newUuid) { - return this._uploadData.uuidChanged(id, newUuid); - }, - setStatus: function(id, newStatus) { - var fileRecord = this.getUploads({ - id: id - }); - if (!fileRecord) { - throw new qq.Error(id + " is not a valid file ID."); - } - switch (newStatus) { - case qq.status.DELETED: - this._onDeleteComplete(id, null, false); - break; - - case qq.status.DELETE_FAILED: - this._onDeleteComplete(id, null, true); - break; - - default: - var errorMessage = "Method setStatus called on '" + name + "' not implemented yet for " + newStatus; - this.log(errorMessage); - throw new qq.Error(errorMessage); - } - }, - uploadStoredFiles: function() { - if (this._storedIds.length === 0) { - this._itemError("noFilesError"); - } else { - this._uploadStoredFiles(); - } - } - }; - qq.basePrivateApi = { - _addCannedFile: function(sessionData) { - var self = this; - return this._uploadData.addFile({ - uuid: sessionData.uuid, - name: sessionData.name, - size: sessionData.size, - status: qq.status.UPLOAD_SUCCESSFUL, - onBeforeStatusChange: function(id) { - sessionData.deleteFileEndpoint && self.setDeleteFileEndpoint(sessionData.deleteFileEndpoint, id); - sessionData.deleteFileParams && self.setDeleteFileParams(sessionData.deleteFileParams, id); - if (sessionData.thumbnailUrl) { - self._thumbnailUrls[id] = sessionData.thumbnailUrl; - } - self._netUploaded++; - self._netUploadedOrQueued++; - } - }); - }, - _annotateWithButtonId: function(file, associatedInput) { - if (qq.isFile(file)) { - file.qqButtonId = this._getButtonId(associatedInput); - } - }, - _batchError: function(message) { - this._options.callbacks.onError(null, null, message, undefined); - }, - _createDeleteHandler: function() { - var self = this; - return new qq.DeleteFileAjaxRequester({ - method: this._options.deleteFile.method.toUpperCase(), - maxConnections: this._options.maxConnections, - uuidParamName: this._options.request.uuidName, - customHeaders: this._deleteFileCustomHeadersStore, - paramsStore: this._deleteFileParamsStore, - endpointStore: this._deleteFileEndpointStore, - cors: this._options.cors, - log: qq.bind(self.log, self), - onDelete: function(id) { - self._onDelete(id); - self._options.callbacks.onDelete(id); - }, - onDeleteComplete: function(id, xhrOrXdr, isError) { - self._onDeleteComplete(id, xhrOrXdr, isError); - self._options.callbacks.onDeleteComplete(id, xhrOrXdr, isError); - } - }); - }, - _createPasteHandler: function() { - var self = this; - return new qq.PasteSupport({ - targetElement: this._options.paste.targetElement, - callbacks: { - log: qq.bind(self.log, self), - pasteReceived: function(blob) { - self._handleCheckedCallback({ - name: "onPasteReceived", - callback: qq.bind(self._options.callbacks.onPasteReceived, self, blob), - onSuccess: qq.bind(self._handlePasteSuccess, self, blob), - identifier: "pasted image" - }); - } - } - }); - }, - _createStore: function(initialValue, _readOnlyValues_) { - var store = {}, catchall = initialValue, perIdReadOnlyValues = {}, readOnlyValues = _readOnlyValues_, copy = function(orig) { - if (qq.isObject(orig)) { - return qq.extend({}, orig); - } - return orig; - }, getReadOnlyValues = function() { - if (qq.isFunction(readOnlyValues)) { - return readOnlyValues(); - } - return readOnlyValues; - }, includeReadOnlyValues = function(id, existing) { - if (readOnlyValues && qq.isObject(existing)) { - qq.extend(existing, getReadOnlyValues()); - } - if (perIdReadOnlyValues[id]) { - qq.extend(existing, perIdReadOnlyValues[id]); - } - }; - return { - set: function(val, id) { - if (id == null) { - store = {}; - catchall = copy(val); - } else { - store[id] = copy(val); - } - }, - get: function(id) { - var values; - if (id != null && store[id]) { - values = store[id]; - } else { - values = copy(catchall); - } - includeReadOnlyValues(id, values); - return copy(values); - }, - addReadOnly: function(id, values) { - if (qq.isObject(store)) { - if (id === null) { - if (qq.isFunction(values)) { - readOnlyValues = values; - } else { - readOnlyValues = readOnlyValues || {}; - qq.extend(readOnlyValues, values); - } - } else { - perIdReadOnlyValues[id] = perIdReadOnlyValues[id] || {}; - qq.extend(perIdReadOnlyValues[id], values); - } - } - }, - remove: function(fileId) { - return delete store[fileId]; - }, - reset: function() { - store = {}; - perIdReadOnlyValues = {}; - catchall = initialValue; - } - }; - }, - _createUploadDataTracker: function() { - var self = this; - return new qq.UploadData({ - getName: function(id) { - return self.getName(id); - }, - getUuid: function(id) { - return self.getUuid(id); - }, - getSize: function(id) { - return self.getSize(id); - }, - onStatusChange: function(id, oldStatus, newStatus) { - self._onUploadStatusChange(id, oldStatus, newStatus); - self._options.callbacks.onStatusChange(id, oldStatus, newStatus); - self._maybeAllComplete(id, newStatus); - if (self._totalProgress) { - setTimeout(function() { - self._totalProgress.onStatusChange(id, oldStatus, newStatus); - }, 0); - } - } - }); - }, - _createUploadButton: function(spec) { - var self = this, acceptFiles = spec.accept || this._options.validation.acceptFiles, allowedExtensions = spec.allowedExtensions || this._options.validation.allowedExtensions, button; - function allowMultiple() { - if (qq.supportedFeatures.ajaxUploading) { - if (self._options.workarounds.iosEmptyVideos && qq.ios() && !qq.ios6() && self._isAllowedExtension(allowedExtensions, ".mov")) { - return false; - } - if (spec.multiple === undefined) { - return self._options.multiple; - } - return spec.multiple; - } - return false; - } - button = new qq.UploadButton({ - acceptFiles: acceptFiles, - element: spec.element, - focusClass: this._options.classes.buttonFocus, - folders: spec.folders, - hoverClass: this._options.classes.buttonHover, - ios8BrowserCrashWorkaround: this._options.workarounds.ios8BrowserCrash, - multiple: allowMultiple(), - name: this._options.request.inputName, - onChange: function(input) { - self._onInputChange(input); - }, - title: spec.title == null ? this._options.text.fileInputTitle : spec.title - }); - this._disposeSupport.addDisposer(function() { - button.dispose(); - }); - self._buttons.push(button); - return button; - }, - _createUploadHandler: function(additionalOptions, namespace) { - var self = this, lastOnProgress = {}, options = { - debug: this._options.debug, - maxConnections: this._options.maxConnections, - cors: this._options.cors, - paramsStore: this._paramsStore, - endpointStore: this._endpointStore, - chunking: this._options.chunking, - resume: this._options.resume, - blobs: this._options.blobs, - log: qq.bind(self.log, self), - preventRetryParam: this._options.retry.preventRetryResponseProperty, - onProgress: function(id, name, loaded, total) { - if (loaded < 0 || total < 0) { - return; - } - if (lastOnProgress[id]) { - if (lastOnProgress[id].loaded !== loaded || lastOnProgress[id].total !== total) { - self._onProgress(id, name, loaded, total); - self._options.callbacks.onProgress(id, name, loaded, total); - } - } else { - self._onProgress(id, name, loaded, total); - self._options.callbacks.onProgress(id, name, loaded, total); - } - lastOnProgress[id] = { - loaded: loaded, - total: total - }; - }, - onComplete: function(id, name, result, xhr) { - delete lastOnProgress[id]; - var status = self.getUploads({ - id: id - }).status, retVal; - if (status === qq.status.UPLOAD_SUCCESSFUL || status === qq.status.UPLOAD_FAILED) { - return; - } - retVal = self._onComplete(id, name, result, xhr); - if (retVal instanceof qq.Promise) { - retVal.done(function() { - self._options.callbacks.onComplete(id, name, result, xhr); - }); - } else { - self._options.callbacks.onComplete(id, name, result, xhr); - } - }, - onCancel: function(id, name, cancelFinalizationEffort) { - var promise = new qq.Promise(); - self._handleCheckedCallback({ - name: "onCancel", - callback: qq.bind(self._options.callbacks.onCancel, self, id, name), - onFailure: promise.failure, - onSuccess: function() { - cancelFinalizationEffort.then(function() { - self._onCancel(id, name); - }); - promise.success(); - }, - identifier: id - }); - return promise; - }, - onUploadPrep: qq.bind(this._onUploadPrep, this), - onUpload: function(id, name) { - self._onUpload(id, name); - var onUploadResult = self._options.callbacks.onUpload(id, name); - if (qq.isGenericPromise(onUploadResult)) { - self.log(qq.format("onUpload for {} returned a Promise - waiting for resolution.", id)); - return onUploadResult; - } - return new qq.Promise().success(); - }, - onUploadChunk: function(id, name, chunkData) { - self._onUploadChunk(id, chunkData); - var onUploadChunkResult = self._options.callbacks.onUploadChunk(id, name, chunkData); - if (qq.isGenericPromise(onUploadChunkResult)) { - self.log(qq.format("onUploadChunk for {}.{} returned a Promise - waiting for resolution.", id, chunkData.partIndex)); - return onUploadChunkResult; - } - return new qq.Promise().success(); - }, - onUploadChunkSuccess: function(id, chunkData, result, xhr) { - self._onUploadChunkSuccess(id, chunkData); - self._options.callbacks.onUploadChunkSuccess.apply(self, arguments); - }, - onResume: function(id, name, chunkData, customResumeData) { - return self._options.callbacks.onResume(id, name, chunkData, customResumeData); - }, - onAutoRetry: function(id, name, responseJSON, xhr) { - return self._onAutoRetry.apply(self, arguments); - }, - onUuidChanged: function(id, newUuid) { - self.log("Server requested UUID change from '" + self.getUuid(id) + "' to '" + newUuid + "'"); - self.setUuid(id, newUuid); - }, - getName: qq.bind(self.getName, self), - getUuid: qq.bind(self.getUuid, self), - getSize: qq.bind(self.getSize, self), - setSize: qq.bind(self._setSize, self), - getDataByUuid: function(uuid) { - return self.getUploads({ - uuid: uuid - }); - }, - isQueued: function(id) { - var status = self.getUploads({ - id: id - }).status; - return status === qq.status.QUEUED || status === qq.status.SUBMITTED || status === qq.status.UPLOAD_RETRYING || status === qq.status.PAUSED; - }, - getIdsInProxyGroup: self._uploadData.getIdsInProxyGroup, - getIdsInBatch: self._uploadData.getIdsInBatch, - isInProgress: function(id) { - return self.getUploads({ - id: id - }).status === qq.status.UPLOADING; - }, - getCustomResumeData: qq.bind(self._getCustomResumeData, self), - setStatus: function(id, status) { - self._uploadData.setStatus(id, status); - } - }; - qq.each(this._options.request, function(prop, val) { - options[prop] = val; - }); - options.customHeaders = this._customHeadersStore; - if (additionalOptions) { - qq.each(additionalOptions, function(key, val) { - options[key] = val; - }); - } - return new qq.UploadHandlerController(options, namespace); - }, - _fileOrBlobRejected: function(id) { - this._netUploadedOrQueued--; - this._uploadData.setStatus(id, qq.status.REJECTED); - }, - _formatSize: function(bytes) { - if (bytes === 0) { - return bytes + this._options.text.sizeSymbols[0]; - } - var i = -1; - do { - bytes = bytes / 1e3; - i++; - } while (bytes > 999); - return Math.max(bytes, .1).toFixed(1) + this._options.text.sizeSymbols[i]; - }, - _generateExtraButtonSpecs: function() { - var self = this; - this._extraButtonSpecs = {}; - qq.each(this._options.extraButtons, function(idx, extraButtonOptionEntry) { - var multiple = extraButtonOptionEntry.multiple, validation = qq.extend({}, self._options.validation, true), extraButtonSpec = qq.extend({}, extraButtonOptionEntry); - if (multiple === undefined) { - multiple = self._options.multiple; - } - if (extraButtonSpec.validation) { - qq.extend(validation, extraButtonOptionEntry.validation, true); - } - qq.extend(extraButtonSpec, { - multiple: multiple, - validation: validation - }, true); - self._initExtraButton(extraButtonSpec); - }); - }, - _getButton: function(buttonId) { - var extraButtonsSpec = this._extraButtonSpecs[buttonId]; - if (extraButtonsSpec) { - return extraButtonsSpec.element; - } else if (buttonId === this._defaultButtonId) { - return this._options.button; - } - }, - _getButtonId: function(buttonOrFileInputOrFile) { - var inputs, fileInput, fileBlobOrInput = buttonOrFileInputOrFile; - if (fileBlobOrInput instanceof qq.BlobProxy) { - fileBlobOrInput = fileBlobOrInput.referenceBlob; - } - if (fileBlobOrInput && !qq.isBlob(fileBlobOrInput)) { - if (qq.isFile(fileBlobOrInput)) { - return fileBlobOrInput.qqButtonId; - } else if (fileBlobOrInput.tagName.toLowerCase() === "input" && fileBlobOrInput.type.toLowerCase() === "file") { - return fileBlobOrInput.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME); - } - inputs = fileBlobOrInput.getElementsByTagName("input"); - qq.each(inputs, function(idx, input) { - if (input.getAttribute("type") === "file") { - fileInput = input; - return false; - } - }); - if (fileInput) { - return fileInput.getAttribute(qq.UploadButton.BUTTON_ID_ATTR_NAME); - } - } - }, - _getCustomResumeData: function(fileId) { - return this._customResumeDataStore.get(fileId); - }, - _getNotFinished: function() { - return this._uploadData.retrieve({ - status: [ qq.status.UPLOADING, qq.status.UPLOAD_RETRYING, qq.status.QUEUED, qq.status.SUBMITTING, qq.status.SUBMITTED, qq.status.PAUSED ] - }).length; - }, - _getValidationBase: function(buttonId) { - var extraButtonSpec = this._extraButtonSpecs[buttonId]; - return extraButtonSpec ? extraButtonSpec.validation : this._options.validation; - }, - _getValidationDescriptor: function(fileWrapper) { - if (fileWrapper.file instanceof qq.BlobProxy) { - return { - name: qq.getFilename(fileWrapper.file.referenceBlob), - size: fileWrapper.file.referenceBlob.size - }; - } - return { - name: this.getUploads({ - id: fileWrapper.id - }).name, - size: this.getUploads({ - id: fileWrapper.id - }).size - }; - }, - _getValidationDescriptors: function(fileWrappers) { - var self = this, fileDescriptors = []; - qq.each(fileWrappers, function(idx, fileWrapper) { - fileDescriptors.push(self._getValidationDescriptor(fileWrapper)); - }); - return fileDescriptors; - }, - _handleCameraAccess: function() { - if (this._options.camera.ios && qq.ios()) { - var acceptIosCamera = "image/*;capture=camera", button = this._options.camera.button, buttonId = button ? this._getButtonId(button) : this._defaultButtonId, optionRoot = this._options; - if (buttonId && buttonId !== this._defaultButtonId) { - optionRoot = this._extraButtonSpecs[buttonId]; - } - optionRoot.multiple = false; - if (optionRoot.validation.acceptFiles === null) { - optionRoot.validation.acceptFiles = acceptIosCamera; - } else { - optionRoot.validation.acceptFiles += "," + acceptIosCamera; - } - qq.each(this._buttons, function(idx, button) { - if (button.getButtonId() === buttonId) { - button.setMultiple(optionRoot.multiple); - button.setAcceptFiles(optionRoot.acceptFiles); - return false; - } - }); - } - }, - _handleCheckedCallback: function(details) { - var self = this, callbackRetVal = details.callback(); - if (qq.isGenericPromise(callbackRetVal)) { - this.log(details.name + " - waiting for " + details.name + " promise to be fulfilled for " + details.identifier); - return callbackRetVal.then(function(successParam) { - self.log(details.name + " promise success for " + details.identifier); - details.onSuccess(successParam); - }, function() { - if (details.onFailure) { - self.log(details.name + " promise failure for " + details.identifier); - details.onFailure(); - } else { - self.log(details.name + " promise failure for " + details.identifier); - } - }); - } - if (callbackRetVal !== false) { - details.onSuccess(callbackRetVal); - } else { - if (details.onFailure) { - this.log(details.name + " - return value was 'false' for " + details.identifier + ". Invoking failure callback."); - details.onFailure(); - } else { - this.log(details.name + " - return value was 'false' for " + details.identifier + ". Will not proceed."); - } - } - return callbackRetVal; - }, - _handleNewFile: function(file, batchId, newFileWrapperList) { - var self = this, uuid = qq.getUniqueId(), size = -1, name = qq.getFilename(file), actualFile = file.blob || file, handler = this._customNewFileHandler ? this._customNewFileHandler : qq.bind(self._handleNewFileGeneric, self); - if (!qq.isInput(actualFile) && actualFile.size >= 0) { - size = actualFile.size; - } - handler(actualFile, name, uuid, size, newFileWrapperList, batchId, this._options.request.uuidName, { - uploadData: self._uploadData, - paramsStore: self._paramsStore, - addFileToHandler: function(id, file) { - self._handler.add(id, file); - self._netUploadedOrQueued++; - self._trackButton(id); - } - }); - }, - _handleNewFileGeneric: function(file, name, uuid, size, fileList, batchId) { - var id = this._uploadData.addFile({ - uuid: uuid, - name: name, - size: size, - batchId: batchId, - file: file - }); - this._handler.add(id, file); - this._trackButton(id); - this._netUploadedOrQueued++; - fileList.push({ - id: id, - file: file - }); - }, - _handlePasteSuccess: function(blob, extSuppliedName) { - var extension = blob.type.split("/")[1], name = extSuppliedName; - if (name == null) { - name = this._options.paste.defaultName; - } - name += "." + extension; - this.addFiles({ - name: name, - blob: blob - }); - }, - _handleDeleteSuccess: function(id) { - if (this.getUploads({ - id: id - }).status !== qq.status.DELETED) { - var name = this.getName(id); - this._netUploadedOrQueued--; - this._netUploaded--; - this._handler.expunge(id); - this._uploadData.setStatus(id, qq.status.DELETED); - this.log("Delete request for '" + name + "' has succeeded."); - } - }, - _handleDeleteFailed: function(id, xhrOrXdr) { - var name = this.getName(id); - this._uploadData.setStatus(id, qq.status.DELETE_FAILED); - this.log("Delete request for '" + name + "' has failed.", "error"); - if (!xhrOrXdr || xhrOrXdr.withCredentials === undefined) { - this._options.callbacks.onError(id, name, "Delete request failed", xhrOrXdr); - } else { - this._options.callbacks.onError(id, name, "Delete request failed with response code " + xhrOrXdr.status, xhrOrXdr); - } - }, - _initExtraButton: function(spec) { - var button = this._createUploadButton({ - accept: spec.validation.acceptFiles, - allowedExtensions: spec.validation.allowedExtensions, - element: spec.element, - folders: spec.folders, - multiple: spec.multiple, - title: spec.fileInputTitle - }); - this._extraButtonSpecs[button.getButtonId()] = spec; - }, - _initFormSupportAndParams: function() { - this._formSupport = qq.FormSupport && new qq.FormSupport(this._options.form, qq.bind(this.uploadStoredFiles, this), qq.bind(this.log, this)); - if (this._formSupport && this._formSupport.attachedToForm) { - this._paramsStore = this._createStore(this._options.request.params, this._formSupport.getFormInputsAsObject); - this._options.autoUpload = this._formSupport.newAutoUpload; - if (this._formSupport.newEndpoint) { - this._options.request.endpoint = this._formSupport.newEndpoint; - } - } else { - this._paramsStore = this._createStore(this._options.request.params); - } - }, - _isDeletePossible: function() { - if (!qq.DeleteFileAjaxRequester || !this._options.deleteFile.enabled) { - return false; - } - if (this._options.cors.expected) { - if (qq.supportedFeatures.deleteFileCorsXhr) { - return true; - } - if (qq.supportedFeatures.deleteFileCorsXdr && this._options.cors.allowXdr) { - return true; - } - return false; - } - return true; - }, - _isAllowedExtension: function(allowed, fileName) { - var valid = false; - if (!allowed.length) { - return true; - } - qq.each(allowed, function(idx, allowedExt) { - if (qq.isString(allowedExt)) { - var extRegex = new RegExp("\\." + allowedExt + "$", "i"); - if (fileName.match(extRegex) != null) { - valid = true; - return false; - } - } - }); - return valid; - }, - _itemError: function(code, maybeNameOrNames, item) { - var message = this._options.messages[code], allowedExtensions = [], names = [].concat(maybeNameOrNames), name = names[0], buttonId = this._getButtonId(item), validationBase = this._getValidationBase(buttonId), extensionsForMessage, placeholderMatch; - function r(name, replacement) { - message = message.replace(name, replacement); - } - qq.each(validationBase.allowedExtensions, function(idx, allowedExtension) { - if (qq.isString(allowedExtension)) { - allowedExtensions.push(allowedExtension); - } - }); - extensionsForMessage = allowedExtensions.join(", ").toLowerCase(); - r("{file}", this._options.formatFileName(name)); - r("{extensions}", extensionsForMessage); - r("{sizeLimit}", this._formatSize(validationBase.sizeLimit)); - r("{minSizeLimit}", this._formatSize(validationBase.minSizeLimit)); - placeholderMatch = message.match(/(\{\w+\})/g); - if (placeholderMatch !== null) { - qq.each(placeholderMatch, function(idx, placeholder) { - r(placeholder, names[idx]); - }); - } - this._options.callbacks.onError(null, name, message, undefined); - return message; - }, - _manualRetry: function(id, callback) { - if (this._onBeforeManualRetry(id)) { - this._netUploadedOrQueued++; - this._uploadData.setStatus(id, qq.status.UPLOAD_RETRYING); - if (callback) { - callback(id); - } else { - this._handler.retry(id); - } - return true; - } - }, - _maybeAllComplete: function(id, status) { - var self = this, notFinished = this._getNotFinished(); - if (status === qq.status.UPLOAD_SUCCESSFUL) { - this._succeededSinceLastAllComplete.push(id); - } else if (status === qq.status.UPLOAD_FAILED) { - this._failedSinceLastAllComplete.push(id); - } - if (notFinished === 0 && (this._succeededSinceLastAllComplete.length || this._failedSinceLastAllComplete.length)) { - setTimeout(function() { - self._onAllComplete(self._succeededSinceLastAllComplete, self._failedSinceLastAllComplete); - }, 0); - } - }, - _maybeHandleIos8SafariWorkaround: function() { - var self = this; - if (this._options.workarounds.ios8SafariUploads && qq.ios800() && qq.iosSafari()) { - setTimeout(function() { - window.alert(self._options.messages.unsupportedBrowserIos8Safari); - }, 0); - throw new qq.Error(this._options.messages.unsupportedBrowserIos8Safari); - } - }, - _maybeParseAndSendUploadError: function(id, name, response, xhr) { - if (!response.success) { - if (xhr && xhr.status !== 200 && !response.error) { - this._options.callbacks.onError(id, name, "XHR returned response code " + xhr.status, xhr); - } else { - var errorReason = response.error ? response.error : this._options.text.defaultResponseError; - this._options.callbacks.onError(id, name, errorReason, xhr); - } - } - }, - _maybeProcessNextItemAfterOnValidateCallback: function(validItem, items, index, params, endpoint) { - var self = this; - if (items.length > index) { - if (validItem || !this._options.validation.stopOnFirstInvalidFile) { - setTimeout(function() { - var validationDescriptor = self._getValidationDescriptor(items[index]), buttonId = self._getButtonId(items[index].file), button = self._getButton(buttonId); - self._handleCheckedCallback({ - name: "onValidate", - callback: qq.bind(self._options.callbacks.onValidate, self, validationDescriptor, button), - onSuccess: qq.bind(self._onValidateCallbackSuccess, self, items, index, params, endpoint), - onFailure: qq.bind(self._onValidateCallbackFailure, self, items, index, params, endpoint), - identifier: "Item '" + validationDescriptor.name + "', size: " + validationDescriptor.size - }); - }, 0); - } else if (!validItem) { - for (;index < items.length; index++) { - self._fileOrBlobRejected(items[index].id); - } - } - } - }, - _onAllComplete: function(successful, failed) { - this._totalProgress && this._totalProgress.onAllComplete(successful, failed, this._preventRetries); - this._options.callbacks.onAllComplete(qq.extend([], successful), qq.extend([], failed)); - this._succeededSinceLastAllComplete = []; - this._failedSinceLastAllComplete = []; - }, - _onAutoRetry: function(id, name, responseJSON, xhr, callback) { - var self = this; - self._preventRetries[id] = responseJSON[self._options.retry.preventRetryResponseProperty]; - if (self._shouldAutoRetry(id)) { - var retryWaitPeriod = self._options.retry.autoAttemptDelay * 1e3; - self._maybeParseAndSendUploadError.apply(self, arguments); - self._options.callbacks.onAutoRetry(id, name, self._autoRetries[id]); - self._onBeforeAutoRetry(id, name); - self._uploadData.setStatus(id, qq.status.UPLOAD_RETRYING); - self._retryTimeouts[id] = setTimeout(function() { - self.log("Starting retry for " + name + "..."); - if (callback) { - callback(id); - } else { - self._handler.retry(id); - } - }, retryWaitPeriod); - return true; - } - }, - _onBeforeAutoRetry: function(id, name) { - this.log("Waiting " + this._options.retry.autoAttemptDelay + " seconds before retrying " + name + "..."); - }, - _onBeforeManualRetry: function(id) { - var itemLimit = this._currentItemLimit, fileName; - if (this._preventRetries[id]) { - this.log("Retries are forbidden for id " + id, "warn"); - return false; - } else if (this._handler.isValid(id)) { - fileName = this.getName(id); - if (this._options.callbacks.onManualRetry(id, fileName) === false) { - return false; - } - if (itemLimit > 0 && this._netUploadedOrQueued + 1 > itemLimit) { - this._itemError("retryFailTooManyItems"); - return false; - } - this.log("Retrying upload for '" + fileName + "' (id: " + id + ")..."); - return true; - } else { - this.log("'" + id + "' is not a valid file ID", "error"); - return false; - } - }, - _onCancel: function(id, name) { - this._netUploadedOrQueued--; - clearTimeout(this._retryTimeouts[id]); - var storedItemIndex = qq.indexOf(this._storedIds, id); - if (!this._options.autoUpload && storedItemIndex >= 0) { - this._storedIds.splice(storedItemIndex, 1); - } - this._uploadData.setStatus(id, qq.status.CANCELED); - }, - _onComplete: function(id, name, result, xhr) { - if (!result.success) { - this._netUploadedOrQueued--; - this._uploadData.setStatus(id, qq.status.UPLOAD_FAILED); - if (result[this._options.retry.preventRetryResponseProperty] === true) { - this._preventRetries[id] = true; - } - } else { - if (result.thumbnailUrl) { - this._thumbnailUrls[id] = result.thumbnailUrl; - } - this._netUploaded++; - this._uploadData.setStatus(id, qq.status.UPLOAD_SUCCESSFUL); - } - this._maybeParseAndSendUploadError(id, name, result, xhr); - return result.success ? true : false; - }, - _onDelete: function(id) { - this._uploadData.setStatus(id, qq.status.DELETING); - }, - _onDeleteComplete: function(id, xhrOrXdr, isError) { - var name = this.getName(id); - if (isError) { - this._handleDeleteFailed(id, xhrOrXdr); - } else { - this._handleDeleteSuccess(id); - } - }, - _onInputChange: function(input) { - var fileIndex; - if (qq.supportedFeatures.ajaxUploading) { - for (fileIndex = 0; fileIndex < input.files.length; fileIndex++) { - this._annotateWithButtonId(input.files[fileIndex], input); - } - this.addFiles(input.files); - } else if (input.value.length > 0) { - this.addFiles(input); - } - qq.each(this._buttons, function(idx, button) { - button.reset(); - }); - }, - _onProgress: function(id, name, loaded, total) { - this._totalProgress && this._totalProgress.onIndividualProgress(id, loaded, total); - }, - _onSubmit: function(id, name) {}, - _onSubmitCallbackSuccess: function(id, name) { - this._onSubmit.apply(this, arguments); - this._uploadData.setStatus(id, qq.status.SUBMITTED); - this._onSubmitted.apply(this, arguments); - if (this._options.autoUpload) { - this._options.callbacks.onSubmitted.apply(this, arguments); - this._uploadFile(id); - } else { - this._storeForLater(id); - this._options.callbacks.onSubmitted.apply(this, arguments); - } - }, - _onSubmitDelete: function(id, onSuccessCallback, additionalMandatedParams) { - var uuid = this.getUuid(id), adjustedOnSuccessCallback; - if (onSuccessCallback) { - adjustedOnSuccessCallback = qq.bind(onSuccessCallback, this, id, uuid, additionalMandatedParams); - } - if (this._isDeletePossible()) { - this._handleCheckedCallback({ - name: "onSubmitDelete", - callback: qq.bind(this._options.callbacks.onSubmitDelete, this, id), - onSuccess: adjustedOnSuccessCallback || qq.bind(this._deleteHandler.sendDelete, this, id, uuid, additionalMandatedParams), - identifier: id - }); - return true; - } else { - this.log("Delete request ignored for ID " + id + ", delete feature is disabled or request not possible " + "due to CORS on a user agent that does not support pre-flighting.", "warn"); - return false; - } - }, - _onSubmitted: function(id) {}, - _onTotalProgress: function(loaded, total) { - this._options.callbacks.onTotalProgress(loaded, total); - }, - _onUploadPrep: function(id) {}, - _onUpload: function(id, name) { - this._uploadData.setStatus(id, qq.status.UPLOADING); - }, - _onUploadChunk: function(id, chunkData) {}, - _onUploadChunkSuccess: function(id, chunkData) { - if (!this._preventRetries[id] && this._options.retry.enableAuto) { - this._autoRetries[id] = 0; - } - }, - _onUploadStatusChange: function(id, oldStatus, newStatus) { - if (newStatus === qq.status.PAUSED) { - clearTimeout(this._retryTimeouts[id]); - } - }, - _onValidateBatchCallbackFailure: function(fileWrappers) { - var self = this; - qq.each(fileWrappers, function(idx, fileWrapper) { - self._fileOrBlobRejected(fileWrapper.id); - }); - }, - _onValidateBatchCallbackSuccess: function(validationDescriptors, items, params, endpoint, button) { - var errorMessage, itemLimit = this._currentItemLimit, proposedNetFilesUploadedOrQueued = this._netUploadedOrQueued; - if (itemLimit === 0 || proposedNetFilesUploadedOrQueued <= itemLimit) { - if (items.length > 0) { - this._handleCheckedCallback({ - name: "onValidate", - callback: qq.bind(this._options.callbacks.onValidate, this, validationDescriptors[0], button), - onSuccess: qq.bind(this._onValidateCallbackSuccess, this, items, 0, params, endpoint), - onFailure: qq.bind(this._onValidateCallbackFailure, this, items, 0, params, endpoint), - identifier: "Item '" + items[0].file.name + "', size: " + items[0].file.size - }); - } else { - this._itemError("noFilesError"); - } - } else { - this._onValidateBatchCallbackFailure(items); - errorMessage = this._options.messages.tooManyItemsError.replace(/\{netItems\}/g, proposedNetFilesUploadedOrQueued).replace(/\{itemLimit\}/g, itemLimit); - this._batchError(errorMessage); - } - }, - _onValidateCallbackFailure: function(items, index, params, endpoint) { - var nextIndex = index + 1; - this._fileOrBlobRejected(items[index].id, items[index].file.name); - this._maybeProcessNextItemAfterOnValidateCallback(false, items, nextIndex, params, endpoint); - }, - _onValidateCallbackSuccess: function(items, index, params, endpoint) { - var self = this, nextIndex = index + 1, validationDescriptor = this._getValidationDescriptor(items[index]); - this._validateFileOrBlobData(items[index], validationDescriptor).then(function() { - self._upload(items[index].id, params, endpoint); - self._maybeProcessNextItemAfterOnValidateCallback(true, items, nextIndex, params, endpoint); - }, function() { - self._maybeProcessNextItemAfterOnValidateCallback(false, items, nextIndex, params, endpoint); - }); - }, - _prepareItemsForUpload: function(items, params, endpoint) { - if (items.length === 0) { - this._itemError("noFilesError"); - return; - } - var validationDescriptors = this._getValidationDescriptors(items), buttonId = this._getButtonId(items[0].file), button = this._getButton(buttonId); - this._handleCheckedCallback({ - name: "onValidateBatch", - callback: qq.bind(this._options.callbacks.onValidateBatch, this, validationDescriptors, button), - onSuccess: qq.bind(this._onValidateBatchCallbackSuccess, this, validationDescriptors, items, params, endpoint, button), - onFailure: qq.bind(this._onValidateBatchCallbackFailure, this, items), - identifier: "batch validation" - }); - }, - _preventLeaveInProgress: function() { - var self = this; - this._disposeSupport.attach(window, "beforeunload", function(e) { - if (self.getInProgress()) { - e = e || window.event; - e.returnValue = self._options.messages.onLeave; - return self._options.messages.onLeave; - } - }); - }, - _refreshSessionData: function() { - var self = this, options = this._options.session; - if (qq.Session && this._options.session.endpoint != null) { - if (!this._session) { - qq.extend(options, { - cors: this._options.cors - }); - options.log = qq.bind(this.log, this); - options.addFileRecord = qq.bind(this._addCannedFile, this); - this._session = new qq.Session(options); - } - setTimeout(function() { - self._session.refresh().then(function(response, xhrOrXdr) { - self._sessionRequestComplete(); - self._options.callbacks.onSessionRequestComplete(response, true, xhrOrXdr); - }, function(response, xhrOrXdr) { - self._options.callbacks.onSessionRequestComplete(response, false, xhrOrXdr); - }); - }, 0); - } - }, - _sessionRequestComplete: function() {}, - _setSize: function(id, newSize) { - this._uploadData.updateSize(id, newSize); - this._totalProgress && this._totalProgress.onNewSize(id); - }, - _shouldAutoRetry: function(id) { - var uploadData = this._uploadData.retrieve({ - id: id - }); - if (!this._preventRetries[id] && this._options.retry.enableAuto && uploadData.status !== qq.status.PAUSED) { - if (this._autoRetries[id] === undefined) { - this._autoRetries[id] = 0; - } - if (this._autoRetries[id] < this._options.retry.maxAutoAttempts) { - this._autoRetries[id] += 1; - return true; - } - } - return false; - }, - _storeForLater: function(id) { - this._storedIds.push(id); - }, - _trackButton: function(id) { - var buttonId; - if (qq.supportedFeatures.ajaxUploading) { - buttonId = this._handler.getFile(id).qqButtonId; - } else { - buttonId = this._getButtonId(this._handler.getInput(id)); - } - if (buttonId) { - this._buttonIdsForFileIds[id] = buttonId; - } - }, - _updateFormSupportAndParams: function(formElementOrId) { - this._options.form.element = formElementOrId; - this._formSupport = qq.FormSupport && new qq.FormSupport(this._options.form, qq.bind(this.uploadStoredFiles, this), qq.bind(this.log, this)); - if (this._formSupport && this._formSupport.attachedToForm) { - this._paramsStore.addReadOnly(null, this._formSupport.getFormInputsAsObject); - this._options.autoUpload = this._formSupport.newAutoUpload; - if (this._formSupport.newEndpoint) { - this.setEndpoint(this._formSupport.newEndpoint); - } - } - }, - _upload: function(id, params, endpoint) { - var name = this.getName(id); - if (params) { - this.setParams(params, id); - } - if (endpoint) { - this.setEndpoint(endpoint, id); - } - this._handleCheckedCallback({ - name: "onSubmit", - callback: qq.bind(this._options.callbacks.onSubmit, this, id, name), - onSuccess: qq.bind(this._onSubmitCallbackSuccess, this, id, name), - onFailure: qq.bind(this._fileOrBlobRejected, this, id, name), - identifier: id - }); - }, - _uploadFile: function(id) { - if (!this._handler.upload(id)) { - this._uploadData.setStatus(id, qq.status.QUEUED); - } - }, - _uploadStoredFiles: function() { - var idToUpload, stillSubmitting, self = this; - while (this._storedIds.length) { - idToUpload = this._storedIds.shift(); - this._uploadFile(idToUpload); - } - stillSubmitting = this.getUploads({ - status: qq.status.SUBMITTING - }).length; - if (stillSubmitting) { - qq.log("Still waiting for " + stillSubmitting + " files to clear submit queue. Will re-parse stored IDs array shortly."); - setTimeout(function() { - self._uploadStoredFiles(); - }, 1e3); - } - }, - _validateFileOrBlobData: function(fileWrapper, validationDescriptor) { - var self = this, file = function() { - if (fileWrapper.file instanceof qq.BlobProxy) { - return fileWrapper.file.referenceBlob; - } - return fileWrapper.file; - }(), name = validationDescriptor.name, size = validationDescriptor.size, buttonId = this._getButtonId(fileWrapper.file), validationBase = this._getValidationBase(buttonId), validityChecker = new qq.Promise(); - validityChecker.then(function() {}, function() { - self._fileOrBlobRejected(fileWrapper.id, name); - }); - if (qq.isFileOrInput(file) && !this._isAllowedExtension(validationBase.allowedExtensions, name)) { - this._itemError("typeError", name, file); - return validityChecker.failure(); - } - if (!this._options.validation.allowEmpty && size === 0) { - this._itemError("emptyError", name, file); - return validityChecker.failure(); - } - if (size > 0 && validationBase.sizeLimit && size > validationBase.sizeLimit) { - this._itemError("sizeError", name, file); - return validityChecker.failure(); - } - if (size > 0 && size < validationBase.minSizeLimit) { - this._itemError("minSizeError", name, file); - return validityChecker.failure(); - } - if (qq.ImageValidation && qq.supportedFeatures.imagePreviews && qq.isFile(file)) { - new qq.ImageValidation(file, qq.bind(self.log, self)).validate(validationBase.image).then(validityChecker.success, function(errorCode) { - self._itemError(errorCode + "ImageError", name, file); - validityChecker.failure(); - }); - } else { - validityChecker.success(); - } - return validityChecker; - }, - _wrapCallbacks: function() { - var self, safeCallback, prop; - self = this; - safeCallback = function(name, callback, args) { - var errorMsg; - try { - return callback.apply(self, args); - } catch (exception) { - errorMsg = exception.message || exception.toString(); - self.log("Caught exception in '" + name + "' callback - " + errorMsg, "error"); - } - }; - for (prop in this._options.callbacks) { - (function() { - var callbackName, callbackFunc; - callbackName = prop; - callbackFunc = self._options.callbacks[callbackName]; - self._options.callbacks[callbackName] = function() { - return safeCallback(callbackName, callbackFunc, arguments); - }; - })(); - } - } - }; - })(); - (function() { - "use strict"; - qq.FineUploaderBasic = function(o) { - var self = this; - this._options = { - debug: false, - button: null, - multiple: true, - maxConnections: 3, - disableCancelForFormUploads: false, - autoUpload: true, - warnBeforeUnload: true, - request: { - customHeaders: {}, - endpoint: "/server/upload", - filenameParam: "qqfilename", - forceMultipart: true, - inputName: "qqfile", - method: "POST", - omitDefaultParams: false, - params: {}, - paramsInBody: true, - requireSuccessJson: true, - totalFileSizeName: "qqtotalfilesize", - uuidName: "qquuid" - }, - validation: { - allowedExtensions: [], - sizeLimit: 0, - minSizeLimit: 0, - itemLimit: 0, - stopOnFirstInvalidFile: true, - acceptFiles: null, - image: { - maxHeight: 0, - maxWidth: 0, - minHeight: 0, - minWidth: 0 - }, - allowEmpty: false - }, - callbacks: { - onSubmit: function(id, name) {}, - onSubmitted: function(id, name) {}, - onComplete: function(id, name, responseJSON, maybeXhr) {}, - onAllComplete: function(successful, failed) {}, - onCancel: function(id, name) {}, - onUpload: function(id, name) {}, - onUploadChunk: function(id, name, chunkData) {}, - onUploadChunkSuccess: function(id, chunkData, responseJSON, xhr) {}, - onResume: function(id, fileName, chunkData, customResumeData) {}, - onProgress: function(id, name, loaded, total) {}, - onTotalProgress: function(loaded, total) {}, - onError: function(id, name, reason, maybeXhrOrXdr) {}, - onAutoRetry: function(id, name, attemptNumber) {}, - onManualRetry: function(id, name) {}, - onValidateBatch: function(fileOrBlobData) {}, - onValidate: function(fileOrBlobData) {}, - onSubmitDelete: function(id) {}, - onDelete: function(id) {}, - onDeleteComplete: function(id, xhrOrXdr, isError) {}, - onPasteReceived: function(blob) {}, - onStatusChange: function(id, oldStatus, newStatus) {}, - onSessionRequestComplete: function(response, success, xhrOrXdr) {} - }, - messages: { - typeError: "{file} has an invalid extension. Valid extension(s): {extensions}.", - sizeError: "{file} is too large, maximum file size is {sizeLimit}.", - minSizeError: "{file} is too small, minimum file size is {minSizeLimit}.", - emptyError: "{file} is empty, please select files again without it.", - noFilesError: "No files to upload.", - tooManyItemsError: "Too many items ({netItems}) would be uploaded. Item limit is {itemLimit}.", - maxHeightImageError: "Image is too tall.", - maxWidthImageError: "Image is too wide.", - minHeightImageError: "Image is not tall enough.", - minWidthImageError: "Image is not wide enough.", - retryFailTooManyItems: "Retry failed - you have reached your file limit.", - onLeave: "The files are being uploaded, if you leave now the upload will be canceled.", - unsupportedBrowserIos8Safari: "Unrecoverable error - this browser does not permit file uploading of any kind due to serious bugs in iOS8 Safari. Please use iOS8 Chrome until Apple fixes these issues." - }, - retry: { - enableAuto: false, - maxAutoAttempts: 3, - autoAttemptDelay: 5, - preventRetryResponseProperty: "preventRetry" - }, - classes: { - buttonHover: "qq-upload-button-hover", - buttonFocus: "qq-upload-button-focus" - }, - chunking: { - enabled: false, - concurrent: { - enabled: false - }, - mandatory: false, - paramNames: { - partIndex: "qqpartindex", - partByteOffset: "qqpartbyteoffset", - chunkSize: "qqchunksize", - totalFileSize: "qqtotalfilesize", - totalParts: "qqtotalparts" - }, - partSize: function(id) { - return 2e6; - }, - success: { - endpoint: null, - headers: function(id) { - return null; - }, - jsonPayload: false, - method: "POST", - params: function(id) { - return null; - }, - resetOnStatus: [] - } - }, - resume: { - enabled: false, - recordsExpireIn: 7, - paramNames: { - resuming: "qqresume" - }, - customKeys: function(fileId) { - return []; - } - }, - formatFileName: function(fileOrBlobName) { - return fileOrBlobName; - }, - text: { - defaultResponseError: "Upload failure reason unknown", - fileInputTitle: "file input", - sizeSymbols: [ "kB", "MB", "GB", "TB", "PB", "EB" ] - }, - deleteFile: { - enabled: false, - method: "DELETE", - endpoint: "/server/upload", - customHeaders: {}, - params: {} - }, - cors: { - expected: false, - sendCredentials: false, - allowXdr: false - }, - blobs: { - defaultName: "misc_data" - }, - paste: { - targetElement: null, - defaultName: "pasted_image" - }, - camera: { - ios: false, - button: null - }, - extraButtons: [], - session: { - endpoint: null, - params: {}, - customHeaders: {}, - refreshOnReset: true - }, - form: { - element: "qq-form", - autoUpload: false, - interceptSubmit: true - }, - scaling: { - customResizer: null, - sendOriginal: true, - orient: true, - defaultType: null, - defaultQuality: 80, - failureText: "Failed to scale", - includeExif: false, - sizes: [] - }, - workarounds: { - iosEmptyVideos: true, - ios8SafariUploads: true, - ios8BrowserCrash: false - } - }; - qq.extend(this._options, o, true); - this._buttons = []; - this._extraButtonSpecs = {}; - this._buttonIdsForFileIds = []; - this._wrapCallbacks(); - this._disposeSupport = new qq.DisposeSupport(); - this._storedIds = []; - this._autoRetries = []; - this._retryTimeouts = []; - this._preventRetries = []; - this._thumbnailUrls = []; - this._netUploadedOrQueued = 0; - this._netUploaded = 0; - this._uploadData = this._createUploadDataTracker(); - this._initFormSupportAndParams(); - this._customHeadersStore = this._createStore(this._options.request.customHeaders); - this._deleteFileCustomHeadersStore = this._createStore(this._options.deleteFile.customHeaders); - this._deleteFileParamsStore = this._createStore(this._options.deleteFile.params); - this._endpointStore = this._createStore(this._options.request.endpoint); - this._deleteFileEndpointStore = this._createStore(this._options.deleteFile.endpoint); - this._handler = this._createUploadHandler(); - this._deleteHandler = qq.DeleteFileAjaxRequester && this._createDeleteHandler(); - if (this._options.button) { - this._defaultButtonId = this._createUploadButton({ - element: this._options.button, - title: this._options.text.fileInputTitle - }).getButtonId(); - } - this._generateExtraButtonSpecs(); - this._handleCameraAccess(); - if (this._options.paste.targetElement) { - if (qq.PasteSupport) { - this._pasteHandler = this._createPasteHandler(); - } else { - this.log("Paste support module not found", "error"); - } - } - this._options.warnBeforeUnload && this._preventLeaveInProgress(); - this._imageGenerator = qq.ImageGenerator && new qq.ImageGenerator(qq.bind(this.log, this)); - this._refreshSessionData(); - this._succeededSinceLastAllComplete = []; - this._failedSinceLastAllComplete = []; - this._scaler = qq.Scaler && new qq.Scaler(this._options.scaling, qq.bind(this.log, this)) || {}; - if (this._scaler.enabled) { - this._customNewFileHandler = qq.bind(this._scaler.handleNewFile, this._scaler); - } - if (qq.TotalProgress && qq.supportedFeatures.progressBar) { - this._totalProgress = new qq.TotalProgress(qq.bind(this._onTotalProgress, this), function(id) { - var entry = self._uploadData.retrieve({ - id: id - }); - return entry && entry.size || 0; - }); - } - this._currentItemLimit = this._options.validation.itemLimit; - this._customResumeDataStore = this._createStore(); - }; - qq.FineUploaderBasic.prototype = qq.basePublicApi; - qq.extend(qq.FineUploaderBasic.prototype, qq.basePrivateApi); - })(); - qq.AjaxRequester = function(o) { - "use strict"; - var log, shouldParamsBeInQueryString, queue = [], requestData = {}, options = { - acceptHeader: null, - validMethods: [ "PATCH", "POST", "PUT" ], - method: "POST", - contentType: "application/x-www-form-urlencoded", - maxConnections: 3, - customHeaders: {}, - endpointStore: {}, - paramsStore: {}, - mandatedParams: {}, - allowXRequestedWithAndCacheControl: true, - successfulResponseCodes: { - DELETE: [ 200, 202, 204 ], - PATCH: [ 200, 201, 202, 203, 204 ], - POST: [ 200, 201, 202, 203, 204 ], - PUT: [ 200, 201, 202, 203, 204 ], - GET: [ 200 ] - }, - cors: { - expected: false, - sendCredentials: false - }, - log: function(str, level) {}, - onSend: function(id) {}, - onComplete: function(id, xhrOrXdr, isError) {}, - onProgress: null - }; - qq.extend(options, o); - log = options.log; - if (qq.indexOf(options.validMethods, options.method) < 0) { - throw new Error("'" + options.method + "' is not a supported method for this type of request!"); - } - function isSimpleMethod() { - return qq.indexOf([ "GET", "POST", "HEAD" ], options.method) >= 0; - } - function containsNonSimpleHeaders(headers) { - var containsNonSimple = false; - qq.each(containsNonSimple, function(idx, header) { - if (qq.indexOf([ "Accept", "Accept-Language", "Content-Language", "Content-Type" ], header) < 0) { - containsNonSimple = true; - return false; - } - }); - return containsNonSimple; - } - function isXdr(xhr) { - return options.cors.expected && xhr.withCredentials === undefined; - } - function getCorsAjaxTransport() { - var xhrOrXdr; - if (window.XMLHttpRequest || window.ActiveXObject) { - xhrOrXdr = qq.createXhrInstance(); - if (xhrOrXdr.withCredentials === undefined) { - xhrOrXdr = new XDomainRequest(); - xhrOrXdr.onload = function() {}; - xhrOrXdr.onerror = function() {}; - xhrOrXdr.ontimeout = function() {}; - xhrOrXdr.onprogress = function() {}; - } - } - return xhrOrXdr; - } - function getXhrOrXdr(id, suppliedXhr) { - var xhrOrXdr = requestData[id] && requestData[id].xhr; - if (!xhrOrXdr) { - if (suppliedXhr) { - xhrOrXdr = suppliedXhr; - } else { - if (options.cors.expected) { - xhrOrXdr = getCorsAjaxTransport(); - } else { - xhrOrXdr = qq.createXhrInstance(); - } - } - requestData[id].xhr = xhrOrXdr; - } - return xhrOrXdr; - } - function dequeue(id) { - var i = qq.indexOf(queue, id), max = options.maxConnections, nextId; - delete requestData[id]; - queue.splice(i, 1); - if (queue.length >= max && i < max) { - nextId = queue[max - 1]; - sendRequest(nextId); - } - } - function onComplete(id, xdrError) { - var xhr = getXhrOrXdr(id), method = options.method, isError = xdrError === true; - dequeue(id); - if (isError) { - log(method + " request for " + id + " has failed", "error"); - } else if (!isXdr(xhr) && !isResponseSuccessful(xhr.status)) { - isError = true; - log(method + " request for " + id + " has failed - response code " + xhr.status, "error"); - } - options.onComplete(id, xhr, isError); - } - function getParams(id) { - var onDemandParams = requestData[id].additionalParams, mandatedParams = options.mandatedParams, params; - if (options.paramsStore.get) { - params = options.paramsStore.get(id); - } - if (onDemandParams) { - qq.each(onDemandParams, function(name, val) { - params = params || {}; - params[name] = val; - }); - } - if (mandatedParams) { - qq.each(mandatedParams, function(name, val) { - params = params || {}; - params[name] = val; - }); - } - return params; - } - function sendRequest(id, optXhr) { - var xhr = getXhrOrXdr(id, optXhr), method = options.method, params = getParams(id), payload = requestData[id].payload, url; - options.onSend(id); - url = createUrl(id, params, requestData[id].additionalQueryParams); - if (isXdr(xhr)) { - xhr.onload = getXdrLoadHandler(id); - xhr.onerror = getXdrErrorHandler(id); - } else { - xhr.onreadystatechange = getXhrReadyStateChangeHandler(id); - } - registerForUploadProgress(id); - xhr.open(method, url, true); - if (options.cors.expected && options.cors.sendCredentials && !isXdr(xhr)) { - xhr.withCredentials = true; - } - setHeaders(id); - log("Sending " + method + " request for " + id); - if (payload) { - xhr.send(payload); - } else if (shouldParamsBeInQueryString || !params) { - xhr.send(); - } else if (params && options.contentType && options.contentType.toLowerCase().indexOf("application/x-www-form-urlencoded") >= 0) { - xhr.send(qq.obj2url(params, "")); - } else if (params && options.contentType && options.contentType.toLowerCase().indexOf("application/json") >= 0) { - xhr.send(JSON.stringify(params)); - } else { - xhr.send(params); - } - return xhr; - } - function createUrl(id, params, additionalQueryParams) { - var endpoint = options.endpointStore.get(id), addToPath = requestData[id].addToPath; - if (addToPath != undefined) { - endpoint += "/" + addToPath; - } - if (shouldParamsBeInQueryString && params) { - endpoint = qq.obj2url(params, endpoint); - } - if (additionalQueryParams) { - endpoint = qq.obj2url(additionalQueryParams, endpoint); - } - return endpoint; - } - function getXhrReadyStateChangeHandler(id) { - return function() { - if (getXhrOrXdr(id).readyState === 4) { - onComplete(id); - } - }; - } - function registerForUploadProgress(id) { - var onProgress = options.onProgress; - if (onProgress) { - getXhrOrXdr(id).upload.onprogress = function(e) { - if (e.lengthComputable) { - onProgress(id, e.loaded, e.total); - } - }; - } - } - function getXdrLoadHandler(id) { - return function() { - onComplete(id); - }; - } - function getXdrErrorHandler(id) { - return function() { - onComplete(id, true); - }; - } - function setHeaders(id) { - var xhr = getXhrOrXdr(id), customHeaders = options.customHeaders, onDemandHeaders = requestData[id].additionalHeaders || {}, method = options.method, allHeaders = {}; - if (!isXdr(xhr)) { - options.acceptHeader && xhr.setRequestHeader("Accept", options.acceptHeader); - if (options.allowXRequestedWithAndCacheControl) { - if (!options.cors.expected || (!isSimpleMethod() || containsNonSimpleHeaders(customHeaders))) { - xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"); - xhr.setRequestHeader("Cache-Control", "no-cache"); - } - } - if (options.contentType && (method === "POST" || method === "PUT")) { - xhr.setRequestHeader("Content-Type", options.contentType); - } - qq.extend(allHeaders, qq.isFunction(customHeaders) ? customHeaders(id) : customHeaders); - qq.extend(allHeaders, onDemandHeaders); - qq.each(allHeaders, function(name, val) { - xhr.setRequestHeader(name, val); - }); - } - } - function isResponseSuccessful(responseCode) { - return qq.indexOf(options.successfulResponseCodes[options.method], responseCode) >= 0; - } - function prepareToSend(id, optXhr, addToPath, additionalParams, additionalQueryParams, additionalHeaders, payload) { - requestData[id] = { - addToPath: addToPath, - additionalParams: additionalParams, - additionalQueryParams: additionalQueryParams, - additionalHeaders: additionalHeaders, - payload: payload - }; - var len = queue.push(id); - if (len <= options.maxConnections) { - return sendRequest(id, optXhr); - } - } - shouldParamsBeInQueryString = options.method === "GET" || options.method === "DELETE"; - qq.extend(this, { - initTransport: function(id) { - var path, params, headers, payload, cacheBuster, additionalQueryParams; - return { - withPath: function(appendToPath) { - path = appendToPath; - return this; - }, - withParams: function(additionalParams) { - params = additionalParams; - return this; - }, - withQueryParams: function(_additionalQueryParams_) { - additionalQueryParams = _additionalQueryParams_; - return this; - }, - withHeaders: function(additionalHeaders) { - headers = additionalHeaders; - return this; - }, - withPayload: function(thePayload) { - payload = thePayload; - return this; - }, - withCacheBuster: function() { - cacheBuster = true; - return this; - }, - send: function(optXhr) { - if (cacheBuster && qq.indexOf([ "GET", "DELETE" ], options.method) >= 0) { - params.qqtimestamp = new Date().getTime(); - } - return prepareToSend(id, optXhr, path, params, additionalQueryParams, headers, payload); - } - }; - }, - canceled: function(id) { - dequeue(id); - } - }); - }; - qq.UploadHandler = function(spec) { - "use strict"; - var proxy = spec.proxy, fileState = {}, onCancel = proxy.onCancel, getName = proxy.getName; - qq.extend(this, { - add: function(id, fileItem) { - fileState[id] = fileItem; - fileState[id].temp = {}; - }, - cancel: function(id) { - var self = this, cancelFinalizationEffort = new qq.Promise(), onCancelRetVal = onCancel(id, getName(id), cancelFinalizationEffort); - onCancelRetVal.then(function() { - if (self.isValid(id)) { - fileState[id].canceled = true; - self.expunge(id); - } - cancelFinalizationEffort.success(); - }); - }, - expunge: function(id) { - delete fileState[id]; - }, - getThirdPartyFileId: function(id) { - return fileState[id].key; - }, - isValid: function(id) { - return fileState[id] !== undefined; - }, - reset: function() { - fileState = {}; - }, - _getFileState: function(id) { - return fileState[id]; - }, - _setThirdPartyFileId: function(id, thirdPartyFileId) { - fileState[id].key = thirdPartyFileId; - }, - _wasCanceled: function(id) { - return !!fileState[id].canceled; - } - }); - }; - qq.UploadHandlerController = function(o, namespace) { - "use strict"; - var controller = this, chunkingPossible = false, concurrentChunkingPossible = false, chunking, preventRetryResponse, log, handler, options = { - paramsStore: {}, - maxConnections: 3, - chunking: { - enabled: false, - multiple: { - enabled: false - } - }, - log: function(str, level) {}, - onProgress: function(id, fileName, loaded, total) {}, - onComplete: function(id, fileName, response, xhr) {}, - onCancel: function(id, fileName) {}, - onUploadPrep: function(id) {}, - onUpload: function(id, fileName) {}, - onUploadChunk: function(id, fileName, chunkData) {}, - onUploadChunkSuccess: function(id, chunkData, response, xhr) {}, - onAutoRetry: function(id, fileName, response, xhr) {}, - onResume: function(id, fileName, chunkData, customResumeData) {}, - onUuidChanged: function(id, newUuid) {}, - getName: function(id) {}, - setSize: function(id, newSize) {}, - isQueued: function(id) {}, - getIdsInProxyGroup: function(id) {}, - getIdsInBatch: function(id) {}, - isInProgress: function(id) {} - }, chunked = { - done: function(id, chunkIdx, response, xhr) { - var chunkData = handler._getChunkData(id, chunkIdx); - handler._getFileState(id).attemptingResume = false; - delete handler._getFileState(id).temp.chunkProgress[chunkIdx]; - handler._getFileState(id).loaded += chunkData.size; - options.onUploadChunkSuccess(id, handler._getChunkDataForCallback(chunkData), response, xhr); - }, - finalize: function(id) { - var size = options.getSize(id), name = options.getName(id); - log("All chunks have been uploaded for " + id + " - finalizing...."); - handler.finalizeChunks(id).then(function(response, xhr) { - log("Finalize successful for " + id); - var normaizedResponse = upload.normalizeResponse(response, true); - options.onProgress(id, name, size, size); - handler._maybeDeletePersistedChunkData(id); - upload.cleanup(id, normaizedResponse, xhr); - }, function(response, xhr) { - var normalizedResponse = upload.normalizeResponse(response, false); - log("Problem finalizing chunks for file ID " + id + " - " + normalizedResponse.error, "error"); - if (normalizedResponse.reset || xhr && options.chunking.success.resetOnStatus.indexOf(xhr.status) >= 0) { - chunked.reset(id); - } - if (!options.onAutoRetry(id, name, normalizedResponse, xhr)) { - upload.cleanup(id, normalizedResponse, xhr); - } - }); - }, - handleFailure: function(chunkIdx, id, response, xhr) { - var name = options.getName(id); - log("Chunked upload request failed for " + id + ", chunk " + chunkIdx); - handler.clearCachedChunk(id, chunkIdx); - var responseToReport = upload.normalizeResponse(response, false), inProgressIdx; - if (responseToReport.reset) { - chunked.reset(id); - } else { - var inProgressChunksArray = handler._getFileState(id).chunking.inProgress; - inProgressIdx = inProgressChunksArray ? qq.indexOf(inProgressChunksArray, chunkIdx) : -1; - if (inProgressIdx >= 0) { - handler._getFileState(id).chunking.inProgress.splice(inProgressIdx, 1); - handler._getFileState(id).chunking.remaining.unshift(chunkIdx); - } - } - if (!handler._getFileState(id).temp.ignoreFailure) { - if (concurrentChunkingPossible) { - handler._getFileState(id).temp.ignoreFailure = true; - log(qq.format("Going to attempt to abort these chunks: {}. These are currently in-progress: {}.", JSON.stringify(Object.keys(handler._getXhrs(id))), JSON.stringify(handler._getFileState(id).chunking.inProgress))); - qq.each(handler._getXhrs(id), function(ckid, ckXhr) { - log(qq.format("Attempting to abort file {}.{}. XHR readyState {}. ", id, ckid, ckXhr.readyState)); - ckXhr.abort(); - ckXhr._cancelled = true; - }); - handler.moveInProgressToRemaining(id); - connectionManager.free(id, true); - } - if (!options.onAutoRetry(id, name, responseToReport, xhr)) { - upload.cleanup(id, responseToReport, xhr); - } - } - }, - hasMoreParts: function(id) { - return !!handler._getFileState(id).chunking.remaining.length; - }, - nextPart: function(id) { - var nextIdx = handler._getFileState(id).chunking.remaining.shift(); - if (nextIdx >= handler._getTotalChunks(id)) { - nextIdx = null; - } - return nextIdx; - }, - reset: function(id) { - log("Server or callback has ordered chunking effort to be restarted on next attempt for item ID " + id, "error"); - handler._maybeDeletePersistedChunkData(id); - handler.reevaluateChunking(id); - handler._getFileState(id).loaded = 0; - handler._getFileState(id).attemptingResume = false; - }, - sendNext: function(id) { - var size = options.getSize(id), name = options.getName(id), chunkIdx = chunked.nextPart(id), chunkData = handler._getChunkData(id, chunkIdx), fileState = handler._getFileState(id), resuming = fileState.attemptingResume, inProgressChunks = fileState.chunking.inProgress || []; - if (fileState.loaded == null) { - fileState.loaded = 0; - } - if (resuming && options.onResume(id, name, chunkData, fileState.customResumeData) === false) { - chunked.reset(id); - chunkIdx = chunked.nextPart(id); - chunkData = handler._getChunkData(id, chunkIdx); - resuming = false; - } - if (chunkIdx == null && inProgressChunks.length === 0) { - chunked.finalize(id); - } else { - inProgressChunks.push(chunkIdx); - handler._getFileState(id).chunking.inProgress = inProgressChunks; - if (concurrentChunkingPossible) { - connectionManager.open(id, chunkIdx); - } - if (concurrentChunkingPossible && connectionManager.available() && handler._getFileState(id).chunking.remaining.length) { - chunked.sendNext(id); - } - if (chunkData.blob.size === 0) { - log(qq.format("Chunk {} for file {} will not be uploaded, zero sized chunk.", chunkIdx, id), "error"); - chunked.handleFailure(chunkIdx, id, "File is no longer available", null); - } - var onUploadChunkPromise = options.onUploadChunk(id, name, handler._getChunkDataForCallback(chunkData)); - onUploadChunkPromise.then(function(requestOverrides) { - if (!options.isInProgress(id)) { - log(qq.format("Not sending chunked upload request for item {}.{} - no longer in progress.", id, chunkIdx)); - } else { - log(qq.format("Sending chunked upload request for item {}.{}, bytes {}-{} of {}.", id, chunkIdx, chunkData.start + 1, chunkData.end, size)); - var uploadChunkData = { - chunkIdx: chunkIdx, - id: id, - overrides: requestOverrides, - resuming: resuming - }; - handler.uploadChunk(uploadChunkData).then(function success(response, xhr) { - log("Chunked upload request succeeded for " + id + ", chunk " + chunkIdx); - handler.clearCachedChunk(id, chunkIdx); - var inProgressChunks = handler._getFileState(id).chunking.inProgress || [], responseToReport = upload.normalizeResponse(response, true), inProgressChunkIdx = qq.indexOf(inProgressChunks, chunkIdx); - log(qq.format("Chunk {} for file {} uploaded successfully.", chunkIdx, id)); - chunked.done(id, chunkIdx, responseToReport, xhr); - if (inProgressChunkIdx >= 0) { - inProgressChunks.splice(inProgressChunkIdx, 1); - } - handler._maybePersistChunkedState(id); - if (!chunked.hasMoreParts(id) && inProgressChunks.length === 0) { - chunked.finalize(id); - } else if (chunked.hasMoreParts(id)) { - chunked.sendNext(id); - } else { - log(qq.format("File ID {} has no more chunks to send and these chunk indexes are still marked as in-progress: {}", id, JSON.stringify(inProgressChunks))); - } - }, function failure(response, xhr) { - chunked.handleFailure(chunkIdx, id, response, xhr); - }).done(function() { - handler.clearXhr(id, chunkIdx); - }); - } - }, function(error) { - chunked.handleFailure(chunkIdx, id, error, null); - }); - } - } - }, connectionManager = { - _open: [], - _openChunks: {}, - _waiting: [], - available: function() { - var max = options.maxConnections, openChunkEntriesCount = 0, openChunksCount = 0; - qq.each(connectionManager._openChunks, function(fileId, openChunkIndexes) { - openChunkEntriesCount++; - openChunksCount += openChunkIndexes.length; - }); - return max - (connectionManager._open.length - openChunkEntriesCount + openChunksCount); - }, - free: function(id, dontAllowNext) { - var allowNext = !dontAllowNext, waitingIndex = qq.indexOf(connectionManager._waiting, id), connectionsIndex = qq.indexOf(connectionManager._open, id), nextId; - delete connectionManager._openChunks[id]; - if (upload.getProxyOrBlob(id) instanceof qq.BlobProxy) { - log("Generated blob upload has ended for " + id + ", disposing generated blob."); - delete handler._getFileState(id).file; - } - if (waitingIndex >= 0) { - connectionManager._waiting.splice(waitingIndex, 1); - } else if (allowNext && connectionsIndex >= 0) { - connectionManager._open.splice(connectionsIndex, 1); - nextId = connectionManager._waiting.shift(); - if (nextId >= 0) { - connectionManager._open.push(nextId); - upload.start(nextId); - } - } - }, - getWaitingOrConnected: function() { - var waitingOrConnected = []; - qq.each(connectionManager._openChunks, function(fileId, chunks) { - if (chunks && chunks.length) { - waitingOrConnected.push(parseInt(fileId)); - } - }); - qq.each(connectionManager._open, function(idx, fileId) { - if (!connectionManager._openChunks[fileId]) { - waitingOrConnected.push(parseInt(fileId)); - } - }); - waitingOrConnected = waitingOrConnected.concat(connectionManager._waiting); - return waitingOrConnected; - }, - isUsingConnection: function(id) { - return qq.indexOf(connectionManager._open, id) >= 0; - }, - open: function(id, chunkIdx) { - if (chunkIdx == null) { - connectionManager._waiting.push(id); - } - if (connectionManager.available()) { - if (chunkIdx == null) { - connectionManager._waiting.pop(); - connectionManager._open.push(id); - } else { - (function() { - var openChunksEntry = connectionManager._openChunks[id] || []; - openChunksEntry.push(chunkIdx); - connectionManager._openChunks[id] = openChunksEntry; - })(); - } - return true; - } - return false; - }, - reset: function() { - connectionManager._waiting = []; - connectionManager._open = []; - } - }, simple = { - send: function(id, name) { - var fileState = handler._getFileState(id); - if (!fileState) { - log("Ignoring send request as this upload may have been cancelled, File ID " + id, "warn"); - return; - } - fileState.loaded = 0; - log("Sending simple upload request for " + id); - handler.uploadFile(id).then(function(response, optXhr) { - log("Simple upload request succeeded for " + id); - var responseToReport = upload.normalizeResponse(response, true), size = options.getSize(id); - options.onProgress(id, name, size, size); - upload.maybeNewUuid(id, responseToReport); - upload.cleanup(id, responseToReport, optXhr); - }, function(response, optXhr) { - log("Simple upload request failed for " + id); - var responseToReport = upload.normalizeResponse(response, false); - if (!options.onAutoRetry(id, name, responseToReport, optXhr)) { - upload.cleanup(id, responseToReport, optXhr); - } - }); - } - }, upload = { - cancel: function(id) { - log("Cancelling " + id); - options.paramsStore.remove(id); - connectionManager.free(id); - }, - cleanup: function(id, response, optXhr) { - var name = options.getName(id); - options.onComplete(id, name, response, optXhr); - if (handler._getFileState(id)) { - handler._clearXhrs && handler._clearXhrs(id); - } - connectionManager.free(id); - }, - getProxyOrBlob: function(id) { - return handler.getProxy && handler.getProxy(id) || handler.getFile && handler.getFile(id); - }, - initHandler: function() { - var handlerType = namespace ? qq[namespace] : qq.traditional, handlerModuleSubtype = qq.supportedFeatures.ajaxUploading ? "Xhr" : "Form"; - handler = new handlerType[handlerModuleSubtype + "UploadHandler"](options, { - getCustomResumeData: options.getCustomResumeData, - getDataByUuid: options.getDataByUuid, - getName: options.getName, - getSize: options.getSize, - getUuid: options.getUuid, - log: log, - onCancel: options.onCancel, - onProgress: options.onProgress, - onUuidChanged: options.onUuidChanged, - onFinalizing: function(id) { - options.setStatus(id, qq.status.UPLOAD_FINALIZING); - } - }); - if (handler._removeExpiredChunkingRecords) { - handler._removeExpiredChunkingRecords(); - } - }, - isDeferredEligibleForUpload: function(id) { - return options.isQueued(id); - }, - maybeDefer: function(id, blob) { - if (blob && !handler.getFile(id) && blob instanceof qq.BlobProxy) { - options.onUploadPrep(id); - log("Attempting to generate a blob on-demand for " + id); - blob.create().then(function(generatedBlob) { - log("Generated an on-demand blob for " + id); - handler.updateBlob(id, generatedBlob); - options.setSize(id, generatedBlob.size); - handler.reevaluateChunking(id); - upload.maybeSendDeferredFiles(id); - }, function(errorMessage) { - var errorResponse = {}; - if (errorMessage) { - errorResponse.error = errorMessage; - } - log(qq.format("Failed to generate blob for ID {}. Error message: {}.", id, errorMessage), "error"); - options.onComplete(id, options.getName(id), qq.extend(errorResponse, preventRetryResponse), null); - upload.maybeSendDeferredFiles(id); - connectionManager.free(id); - }); - } else { - return upload.maybeSendDeferredFiles(id); - } - return false; - }, - maybeSendDeferredFiles: function(id) { - var idsInGroup = options.getIdsInProxyGroup(id), uploadedThisId = false; - if (idsInGroup && idsInGroup.length) { - log("Maybe ready to upload proxy group file " + id); - qq.each(idsInGroup, function(idx, idInGroup) { - if (upload.isDeferredEligibleForUpload(idInGroup) && !!handler.getFile(idInGroup)) { - uploadedThisId = idInGroup === id; - upload.now(idInGroup); - } else if (upload.isDeferredEligibleForUpload(idInGroup)) { - return false; - } - }); - } else { - uploadedThisId = true; - upload.now(id); - } - return uploadedThisId; - }, - maybeNewUuid: function(id, response) { - if (response.newUuid !== undefined) { - options.onUuidChanged(id, response.newUuid); - } - }, - normalizeResponse: function(originalResponse, successful) { - var response = originalResponse; - if (!qq.isObject(originalResponse)) { - response = {}; - if (qq.isString(originalResponse) && !successful) { - response.error = originalResponse; - } - } - response.success = successful; - return response; - }, - now: function(id) { - var name = options.getName(id); - if (!controller.isValid(id)) { - throw new qq.Error(id + " is not a valid file ID to upload!"); - } - options.onUpload(id, name).then(function(response) { - if (response && response.pause) { - options.setStatus(id, qq.status.PAUSED); - handler.pause(id); - connectionManager.free(id); - } else { - if (chunkingPossible && handler._shouldChunkThisFile(id)) { - chunked.sendNext(id); - } else { - simple.send(id, name); - } - } - }, function(error) { - error = error || {}; - log(id + " upload start aborted due to rejected onUpload Promise - details: " + error, "error"); - if (!options.onAutoRetry(id, name, error.responseJSON || {})) { - var response = upload.normalizeResponse(error.responseJSON, false); - upload.cleanup(id, response); - } - }); - }, - start: function(id) { - var blobToUpload = upload.getProxyOrBlob(id); - if (blobToUpload) { - return upload.maybeDefer(id, blobToUpload); - } else { - upload.now(id); - return true; - } - } - }; - qq.extend(this, { - add: function(id, file) { - handler.add.apply(this, arguments); - }, - upload: function(id) { - if (connectionManager.open(id)) { - return upload.start(id); - } - return false; - }, - retry: function(id) { - if (concurrentChunkingPossible) { - handler._getFileState(id).temp.ignoreFailure = false; - } - if (connectionManager.isUsingConnection(id)) { - return upload.start(id); - } else { - return controller.upload(id); - } - }, - cancel: function(id) { - var cancelRetVal = handler.cancel(id); - if (qq.isGenericPromise(cancelRetVal)) { - cancelRetVal.then(function() { - upload.cancel(id); - }); - } else if (cancelRetVal !== false) { - upload.cancel(id); - } - }, - cancelAll: function() { - var waitingOrConnected = connectionManager.getWaitingOrConnected(), i; - if (waitingOrConnected.length) { - for (i = waitingOrConnected.length - 1; i >= 0; i--) { - controller.cancel(waitingOrConnected[i]); - } - } - connectionManager.reset(); - }, - getFile: function(id) { - if (handler.getProxy && handler.getProxy(id)) { - return handler.getProxy(id).referenceBlob; - } - return handler.getFile && handler.getFile(id); - }, - isProxied: function(id) { - return !!(handler.getProxy && handler.getProxy(id)); - }, - getInput: function(id) { - if (handler.getInput) { - return handler.getInput(id); - } - }, - reset: function() { - log("Resetting upload handler"); - controller.cancelAll(); - connectionManager.reset(); - handler.reset(); - }, - expunge: function(id) { - if (controller.isValid(id)) { - return handler.expunge(id); - } - }, - isValid: function(id) { - return handler.isValid(id); - }, - hasResumeRecord: function(id) { - var key = handler.isValid(id) && handler._getLocalStorageId && handler._getLocalStorageId(id); - if (key) { - return !!localStorage.getItem(key); - } - return false; - }, - getResumableFilesData: function() { - if (handler.getResumableFilesData) { - return handler.getResumableFilesData(); - } - return []; - }, - getThirdPartyFileId: function(id) { - if (controller.isValid(id)) { - return handler.getThirdPartyFileId(id); - } - }, - pause: function(id) { - if (controller.isResumable(id) && handler.pause && controller.isValid(id) && handler.pause(id)) { - connectionManager.free(id); - handler.moveInProgressToRemaining(id); - return true; - } - return false; - }, - isAttemptingResume: function(id) { - return !!handler.isAttemptingResume && handler.isAttemptingResume(id); - }, - isResumable: function(id) { - return !!handler.isResumable && handler.isResumable(id); - } - }); - qq.extend(options, o); - log = options.log; - chunkingPossible = options.chunking.enabled && qq.supportedFeatures.chunking; - concurrentChunkingPossible = chunkingPossible && options.chunking.concurrent.enabled; - preventRetryResponse = function() { - var response = {}; - response[options.preventRetryParam] = true; - return response; - }(); - upload.initHandler(); - }; - qq.WindowReceiveMessage = function(o) { - "use strict"; - var options = { - log: function(message, level) {} - }, callbackWrapperDetachers = {}; - qq.extend(options, o); - qq.extend(this, { - receiveMessage: function(id, callback) { - var onMessageCallbackWrapper = function(event) { - callback(event.data); - }; - if (window.postMessage) { - callbackWrapperDetachers[id] = qq(window).attach("message", onMessageCallbackWrapper); - } else { - log("iframe message passing not supported in this browser!", "error"); - } - }, - stopReceivingMessages: function(id) { - if (window.postMessage) { - var detacher = callbackWrapperDetachers[id]; - if (detacher) { - detacher(); - } - } - } - }); - }; - qq.FormUploadHandler = function(spec) { - "use strict"; - var options = spec.options, handler = this, proxy = spec.proxy, formHandlerInstanceId = qq.getUniqueId(), onloadCallbacks = {}, detachLoadEvents = {}, postMessageCallbackTimers = {}, isCors = options.isCors, inputName = options.inputName, getUuid = proxy.getUuid, log = proxy.log, corsMessageReceiver = new qq.WindowReceiveMessage({ - log: log - }); - function expungeFile(id) { - delete detachLoadEvents[id]; - if (isCors) { - clearTimeout(postMessageCallbackTimers[id]); - delete postMessageCallbackTimers[id]; - corsMessageReceiver.stopReceivingMessages(id); - } - var iframe = document.getElementById(handler._getIframeName(id)); - if (iframe) { - iframe.setAttribute("src", "javascript:false;"); - qq(iframe).remove(); - } - } - function getFileIdForIframeName(iframeName) { - return iframeName.split("_")[0]; - } - function initIframeForUpload(name) { - var iframe = qq.toElement(" + {% if contest_problem and contest_problem.contest.use_clarifications %} +
+

{{ _('Clarifications') }}

+ {% if has_clarifications %} + {% for clarification in clarifications %} +
+
{{ relative_time(clarification.date) }}
+ + {{ clarification.description|markdown('problem', MATH_ENGINE)|reference }} + +
+ {% endfor %} + {% else %} +

{{ _('No clarifications have been made at this time.') }}

+ {% endif %} +
+ {% else %} + {% include "comments/list.html" %} + {% endif %} +{% endblock %} + +{% block bodyend %} + {{ super() }} + {% include "comments/math.html" %} {% endblock %} diff --git a/templates/problem/raw.html b/templates/problem/raw.html index a769a24..573db37 100644 --- a/templates/problem/raw.html +++ b/templates/problem/raw.html @@ -1,98 +1,96 @@ - - - - + - - - + - -

{{ problem_name }}

-
-
-
- {{ _('Input:') }} {{ fileio_input or _('stdin') }} -
-
- {{ _('Output:') }} {{ fileio_output or _('stdout') }} -
-
+ +

{{ problem_name }}

+
+
+
{{ _('Time Limit:') }} {{ problem.time_limit }}s {% for name, limit in problem.language_time_limit %} -
- {{ name }} - {{ limit }}s -
+
+ {{ name }} + {{ limit }}s +
{% endfor %} -
-
+
+
{{ _('Memory Limit:') }} {{ problem.memory_limit|kbsimpleformat}} {% for name, limit in problem.language_memory_limit %} -
- {{ name }} - {{ limit|kbsimpleformat }} -
+
+ {{ name }} + {{ limit|kbsimpleformat }} +
{% endfor %} -
-
-
- {{ description|markdown|reference|absolutify(url)|str|safe }} -
- - {% include "katex-load.html" %} - +
+
+
+ {{ description|markdown('problem', 'tex' if math_engine == 'jax' else math_engine)|reference|absolutify(url)|str|safe }} +
+{% if math_engine == 'jax' %} + + + +{% endif %} + diff --git a/templates/problem/recent-attempt.html b/templates/problem/recent-attempt.html deleted file mode 100644 index 195fe27..0000000 --- a/templates/problem/recent-attempt.html +++ /dev/null @@ -1,21 +0,0 @@ -{% if last_attempted_problems%} - -{% endif %} \ No newline at end of file diff --git a/templates/problem/related_problems.html b/templates/problem/related_problems.html deleted file mode 100644 index a92a75b..0000000 --- a/templates/problem/related_problems.html +++ /dev/null @@ -1,19 +0,0 @@ -{% if request.user.is_authenticated and related_problems %} -
-

{{_('Recommended problems')}}:

-
    - {% for problem in related_problems %} -
  • - {% if problem.id in completed_problem_ids %} - - {% elif problem.id in attempted_problems %} - - {% else %} - - {% endif %} - {{ problem.name }} -
  • - {% endfor %} -
-
-{% endif %} \ No newline at end of file diff --git a/templates/problem/search-form.html b/templates/problem/search-form.html index 73a9288..e818630 100644 --- a/templates/problem/search-form.html +++ b/templates/problem/search-form.html @@ -1,100 +1,68 @@ \ No newline at end of file diff --git a/templates/problem/submission-diff.html b/templates/problem/submission-diff.html index 0a6515e..55dbd35 100644 --- a/templates/problem/submission-diff.html +++ b/templates/problem/submission-diff.html @@ -1,99 +1,100 @@ {% extends "common-content.html" %} {% block js_media %} - - + + + {% endblock %} {% block media %} - + .sub-case-status { + text-decoration: underline; + } + {% endblock %} {% block body %} - - - - - - - - - {% for case in range(num_cases) %} - - {% endfor %} - - - - {% for sub in submissions %} +
IDUsernameResultLanguageDate{{ loop.index }}
+ - - - - - - {% for case in sub.test_cases.all() %} - - {% endfor %} + + + + + + {% for case in range(num_cases) %} + + {% endfor %} - {% endfor %} - -
{{ sub.id }}{{ link_user(sub.user) }}{{ sub.result }}{{ sub.language.name }}{{ relative_time(sub.date) }} - {% if case.status == 'SC' %} - --- - {% else %} - - {% if case.status == 'AC' %} - {{ case.time|floatformat(2) }} - {% else %} - {{ case.status }} - {% endif %} - - {% endif %} - IDUsernameResultLanguageDate{{ loop.index }}
- + + + {% for sub in submissions %} + + {{ sub.id }} + {{ link_user(sub.user) }} + {{ sub.result }} + {{ sub.language.name }} + {{ relative_time(sub.date) }} + {% for case in sub.test_cases.all() %} + + {% if case.status == 'SC' %} + --- + {% else %} + + {% if case.status == 'AC' %} + {{ case.time|floatformat(2) }} + {% else %} + {{ case.status }} + {% endif %} + + {% endif %} + + {% endfor %} + + {% endfor %} + + + {% endblock %} \ No newline at end of file diff --git a/templates/problem/submit.html b/templates/problem/submit.html index af3b64b..cf24c3c 100644 --- a/templates/problem/submit.html +++ b/templates/problem/submit.html @@ -1,261 +1,256 @@ {% extends "base.html" %} {% block js_media %} - - {{ form.media.js }} - + {% compress js %} + {{ form.media.js }} + - - {% compress js %} - - {% endcompress %} + + {% endcompress %} {% endblock %} {% block media %} - {{ form.media.css }} + {% compress css %} + {{ form.media.css }} + + {% endcompress %} {% endblock %} {% block body %} -
- {% if not no_judges %} - {% if default_lang not in form.fields.language.queryset %} -
- x - {% trans trimmed default_language=default_lang.name %} - Warning! Your default language, {{ default_language }}, - is unavailable for this problem and has been deselected. - {% endtrans %} -
+
+ {% if not no_judges %} + {% if default_lang not in form.fields.language.queryset %} +
+ x + {% trans trimmed default_language=default_lang.name %} + Warning! Your default language, {{ default_language }}, + is unavailable for this problem and has been deselected. + {% endtrans %} +
+ {% endif %} + + {% if request.in_contest and submission_limit %} + {% if submissions_left > 0 %} +
+ x + {% trans left=submissions_left %} + You have {{ left }} submission left + {% pluralize %} + You have {{ left }} submissions left + {% endtrans %} +
+ {% else %} +
+ x + {{ _('You have 0 submissions left') }} +
+ {% endif %} + {% endif %} {% endif %} - {% if request.in_contest and submission_limit %} - {% if submissions_left > 0 %} -
- x - {% trans left=submissions_left %} - You have {{ left }} submission left - {% pluralize %} - You have {{ left }} submissions left - {% endtrans %} +
+ {% csrf_token %} + {{ form.non_field_errors() }} +
+
+ {{ form.problem.errors }} + {{ form.problem }} +
+
+ {{ form.source.errors }} + {{ form.source }} +
+ {% if not no_judges %} +
+ {{ form.language.errors }} +
+ +
+
+ {% endif %}
- {% else %} -
- x - {{ _('You have 0 submissions left') }} -
- {% endif %} - {% endif %} - {% endif %} - - {% csrf_token %} - {{ form.non_field_errors() }} -
-
- {{ form.source.errors }} - {{ form.source }} -
- {% if not no_judges %} -
- {{ form.language.errors }} -
- -
-
- {% endif %} -
+
-
- - {% if no_judges %} - {{ _('No judge is available for this problem.') }} - {% else %} - {{ form.source_file.errors }} - {{ form.source_file }} -
- {{ form.judge }} - - -
- {% endif %} -
-{% endblock %} \ No newline at end of file + {% if no_judges %} + {{ _('No judge is available for this problem.') }} + {% else %} + + {% endif %} + +{% endblock %} diff --git a/templates/problem/yaml.html b/templates/problem/yaml.html index 33c703f..8dee21c 100644 --- a/templates/problem/yaml.html +++ b/templates/problem/yaml.html @@ -1,5 +1,20 @@ {% extends "base.html" %} {% block body %} - {{ highlighted_source }} +
+ + + + + +
+
+ {% for line in raw_source.split('\n') %} + +
{{ loop.index }}
+
+ {% endfor %} +
+
{{ highlighted_source }}
+
{% endblock %} \ No newline at end of file diff --git a/templates/profile-table.html b/templates/profile-table.html deleted file mode 100644 index 8394843..0000000 --- a/templates/profile-table.html +++ /dev/null @@ -1,77 +0,0 @@ -{% if request.profile %} - -{% endif %} \ No newline at end of file diff --git a/templates/recent-organization.html b/templates/recent-organization.html deleted file mode 100644 index 9a627fe..0000000 --- a/templates/recent-organization.html +++ /dev/null @@ -1,17 +0,0 @@ -{% if recent_organizations %} - -{% endif %} \ No newline at end of file diff --git a/templates/registration/activate.html b/templates/registration/activate.html index 6d0db5c..8cee082 100644 --- a/templates/registration/activate.html +++ b/templates/registration/activate.html @@ -1,4 +1,4 @@ {% extends "base.html" %} {% block body %} -

{{ _('%(key)s is an invalid activation key.', key=activation_key) }}

+

{{ _('%(key)s is an invalid activation key.', key=activation_key) }}

{% endblock %} \ No newline at end of file diff --git a/templates/registration/activation_complete.html b/templates/registration/activation_complete.html index 6ee4c0d..6140ad7 100644 --- a/templates/registration/activation_complete.html +++ b/templates/registration/activation_complete.html @@ -1,4 +1,4 @@ {% extends "base.html" %} {% block body %} -

{{ _('Your account has been successfully activated.') }}

+

{{ _('Your account has been successfully activated.') }}

{% endblock %} \ No newline at end of file diff --git a/templates/registration/activation_email.html b/templates/registration/activation_email.html index 786bc11..a90b9fc 100644 --- a/templates/registration/activation_email.html +++ b/templates/registration/activation_email.html @@ -1,16 +1,23 @@ -{% set url_path = "/accounts/activate/" + activation_key %} -{% set title = _("Account activation") %} -{% set message = _("Thanks for registering! We're glad to have you. The last step is activating your account. Please activate your account in the next %(expiration_days)d days.", expiration_days=expiration_days) %} -{% set username = user.get_username() %} -{% set button_text = _("Activate") %} -{% set domain = site.domain %} -{% set protocol = "https" if request.is_secure() else "http" %} -{% include "general_email.html" %} -
-{{_("Alternatively, you can reply to this message to activate your account. Your reply must keep the following text intact for this to work:")}} +Thanks for registering on the {{ site.name }}! We're glad to have you. +

+The last step is activating your account. Please activate your {{ SITE_NAME }} account in the next {{ expiration_days }} days. +

+Please click on the following link to activate your account: +

+ http://{{ site.domain }}/accounts/activate/{{ activation_key }} +

+ +Alternatively, you can reply to this message to activate your account. +Your reply must keep the following text intact for this to work:
 {{ activation_key }}
 
-{{_("See you soon!")}} +{% if SITE_ADMIN_EMAIL %} +See you soon! +
+If you have problems activating your account, feel free to send us an email at {{ SITE_ADMIN_EMAIL }}. +{% else %} +See you soon! +{% endif %} diff --git a/templates/registration/activation_email_subject.txt b/templates/registration/activation_email_subject.txt index 5b3bd66..b0888c8 100644 --- a/templates/registration/activation_email_subject.txt +++ b/templates/registration/activation_email_subject.txt @@ -1 +1 @@ -{% trans %}Activate your {{ SITE_NAME }} account{% endtrans %} +Activate your {{ SITE_NAME }} account \ No newline at end of file diff --git a/templates/registration/login.html b/templates/registration/login.html index ce9040c..dafb087 100644 --- a/templates/registration/login.html +++ b/templates/registration/login.html @@ -1,51 +1,85 @@ {% extends "base.html" %} -{% block body %} -
-
- {% csrf_token %} - {% if form.errors %} -
-

{{ _('Invalid username/email or password.') }}

-
- {% endif %} - - - - - - - - - -
- {{ form.username }} -
- {{ form.password }} -
-
- - -
-
{{ _('Forgot your password?') }} +{% block media %} + +{% endblock %} + +{% block body %} +
+
+ {% csrf_token %} + {% if form.errors %} +
+

{{ _('Invalid username or password.') }}

+
+ {% endif %} + + + + + + + + + +
+ {{ form.username }} +
+ {{ form.password }} +
+
+ + +
+
{{ _('Forgot your password?') }} + + {% if form.has_google_auth or form.has_facebook_auth or form.has_github_auth %} +

{{ _('Or log in with...') }}

+ {% if form.has_google_auth %} + + {% endif %} + {% if form.has_facebook_auth %} + + {% endif %} + {% if form.has_github_auth %} + + {% endif %} + {% endif %} +
{% endblock %} diff --git a/templates/registration/logout.html b/templates/registration/logout.html index 76c6ec2..176a230 100644 --- a/templates/registration/logout.html +++ b/templates/registration/logout.html @@ -1,4 +1,4 @@ {% extends "base.html" %} {% block body %} -

{{ _('See you later!') }}

+

{{ _('See you later!') }}

{% endblock %} \ No newline at end of file diff --git a/templates/registration/password_change_done.html b/templates/registration/password_change_done.html index 3cd3e58..78a146c 100644 --- a/templates/registration/password_change_done.html +++ b/templates/registration/password_change_done.html @@ -1,4 +1,4 @@ {% extends "base.html" %} {% block body %} -

{{ _('Your password was sucessfully changed.') }}

+

{{ _('Your password was sucessfully changed.') }}

{% endblock %} \ No newline at end of file diff --git a/templates/registration/password_change_form.html b/templates/registration/password_change_form.html index 7d0642a..a8f56ae 100644 --- a/templates/registration/password_change_form.html +++ b/templates/registration/password_change_form.html @@ -1,10 +1,10 @@ {% extends "base.html" %} {% block body %} -
- {% csrf_token %} - {{ form.as_table() }}
-
- -
+
+ {% csrf_token %} + {{ form.as_table() }}
+
+ +
{% endblock %} diff --git a/templates/registration/password_reset.html b/templates/registration/password_reset.html index 0685935..4f5d738 100644 --- a/templates/registration/password_reset.html +++ b/templates/registration/password_reset.html @@ -1,9 +1,9 @@ {% extends "base.html" %} {% block body %} -
{% csrf_token %} - {{ form.as_table() }}
-
- -
+
{% csrf_token %} + {{ form.as_table() }}
+
+ +
{% endblock %} \ No newline at end of file diff --git a/templates/registration/password_reset_complete.html b/templates/registration/password_reset_complete.html index a456473..5727282 100644 --- a/templates/registration/password_reset_complete.html +++ b/templates/registration/password_reset_complete.html @@ -1,5 +1,5 @@ {% extends "base.html" %} {% block body %} -

{{ _('Your password has been set. You may go ahead and log in now') }}

- {{ _('Log in') }} +

{{ _('Your password has been set. You may go ahead and log in now') }}

+ {{ _('Log in') }} {% endblock %} \ No newline at end of file diff --git a/templates/registration/password_reset_confirm.html b/templates/registration/password_reset_confirm.html index d2d0d78..6f65215 100644 --- a/templates/registration/password_reset_confirm.html +++ b/templates/registration/password_reset_confirm.html @@ -1,14 +1,14 @@ {% extends "base.html" %} {% block body %} - {% if validlink %} -
- {% csrf_token %} - {{ form.as_table() }}
-
- -
- {% else %} -

Invalid password reset link.

- {% endif %} + {% if validlink %} +
+ {% csrf_token %} + {{ form.as_table() }}
+
+ +
+ {% else %} +

Invalid password reset link.

+ {% endif %} {% endblock %} diff --git a/templates/registration/password_reset_done.html b/templates/registration/password_reset_done.html index 5255864..8e415d1 100644 --- a/templates/registration/password_reset_done.html +++ b/templates/registration/password_reset_done.html @@ -1,6 +1,6 @@ {% extends "base.html" %} {% block body %} -

{{ _("We've emailed you instructions for setting your password. You should be receiving them shortly.") }}

-

{{ _("If you don't receive an email, please make sure you've entered the address you registered with, and check your spam folder.") }}

+

{{ _("We've emailed you instructions for setting your password. You should be receiving them shortly.") }}

+

{{ _("If you don't receive an email, please make sure you've entered the address you registered with, and check your spam folder.") }}

{% endblock %} \ No newline at end of file diff --git a/templates/registration/password_reset_email.html b/templates/registration/password_reset_email.html index 0b30eb3..8aeb454 100644 --- a/templates/registration/password_reset_email.html +++ b/templates/registration/password_reset_email.html @@ -1,6 +1,19 @@ -{% set url_path = url('password_reset_confirm', uidb64=uid, token=token) %} -{% set title = _("Password Reset") %} -{% set message = _("We have received a request to reset your password. Click the button below to reset your password:") %} -{% set username = user.get_username() %} -{% set button_text = _("Reset Password") %} -{% include "general_email.html" %} \ No newline at end of file + +
+

DM::OJ +

+
+
+
+ +Forgot your password on the {{ site_name }}? Don't worry!

+To reset the password for your account "{{ user.get_username() }}", click the below button. +

+Reset password +

+{% if SITE_ADMIN_EMAIL %} +See you soon! If you have problems resetting your email, feel free to shoot us an email at {{ SITE_ADMIN_EMAIL }} +{% else %} +See you soon! +{% endif %} +
diff --git a/templates/registration/profile_creation.html b/templates/registration/profile_creation.html index 60455b2..7641b65 100644 --- a/templates/registration/profile_creation.html +++ b/templates/registration/profile_creation.html @@ -1,60 +1,58 @@ {% extends "base.html" %} {% block media %} - - {{ form.media.css }} - + {% if TIMEZONE_BG %} + .map-wrap { + background: {{TIMEZONE_BG}} + } + {% endif %} + {% endblock %} {% block js_media %}{{ form.media.js }}{% endblock %} {% block body %} -
- {% csrf_token %} - {{ form.as_table() }}
- + {% csrf_token %} + {{ form.as_table() }}
+
-
-
-
-
-
+
+
+
+
+
-
{% endblock %} {% block bodyend %} - - + + {% endblock %} \ No newline at end of file diff --git a/templates/registration/registration_closed.html b/templates/registration/registration_closed.html index fcd1777..7c732b0 100644 --- a/templates/registration/registration_closed.html +++ b/templates/registration/registration_closed.html @@ -1,4 +1,4 @@ {% extends "base.html" %} {% block body %} -

{{ _('Registration is currently closed. Please contact an administrator.') }}

+

{{ _('Registration is currently closed. Please contact an administrator.') }}

{% endblock %} diff --git a/templates/registration/registration_complete.html b/templates/registration/registration_complete.html index b91a32d..25903d7 100644 --- a/templates/registration/registration_complete.html +++ b/templates/registration/registration_complete.html @@ -1,4 +1,4 @@ {% extends "base.html" %} {% block body %} -

{{ _('You have successfully been registered. An email has been sent to the email address you provided to confirm your registration. If you don\'t see it, kindly check your spam folder as well.') }}

+

{{ _('You have successfully been registered. An email has been sent to the email address you provided to confirm your registration.') }}

{% endblock %} \ No newline at end of file diff --git a/templates/registration/registration_form.html b/templates/registration/registration_form.html index cf5bc30..220aa43 100644 --- a/templates/registration/registration_form.html +++ b/templates/registration/registration_form.html @@ -1,99 +1,220 @@ {% extends "base.html" %} {% block media %} - {% include "timezone/media-css.html" %} - {{ form.media.css }} - + {% include "timezone/media-css.html" %} + {{ form.media.css }} + {% endblock %} {% block js_media %} - {% include "timezone/media-js.html" %} - {{ form.media.js }} - - {% if form.captcha %} - {{ recaptcha_init(LANGUAGE_CODE) }} - {% endif %} + {% include "timezone/media-js.html" %} + {{ form.media.js }} + + {% if form.captcha %} + {{ recaptcha_init(LANGUAGE_CODE) }} + {% endif %} {% endblock %} {% block body %} -
-
- {% csrf_token %} +
+ + {% csrf_token %} -
{{ _('Username') }}
- {{ form.username }} - {% if form.username.errors %} -
{{ form.username.errors }}
- {% endif %} +
{{ _('Username') }}
+ {{ form.username }} + {% if form.username.errors %} +
{{ form.username.errors }}
+ {% endif %} -
{{ _('Email') }}
- {{ form.email }} - {% if form.email.errors %} -
{{ form.email.errors }}
- {% endif %} +
{{ _('Email') }}
+ {{ form.email }} + {% if form.email.errors %} +
{{ form.email.errors }}
+ {% endif %} -
{{ _('Password') -}} - (?) -
- - {{ form.password1 }} - {% if form.password1.errors %} -
{{ form.password1.errors }}
- {% endif %} -
{{ _('Password') }}2{# -#} - {{ _('(again, for confirmation)') }} -
- {{ form.password2 }} - {% if form.password2.errors %} -
{{ form.password2.errors }}
- {% endif %} +
{{ _('Password') -}} + (?) +
+ + {{ form.password1 }} + {% if form.password1.errors %} +
{{ form.password1.errors }}
+ {% endif %} +
{{ _('Password') }}2{# -#} + {{ _('(again, for confirmation)') }} +
+ {{ form.password2 }} + {% if form.password2.errors %} +
{{ form.password2.errors }}
+ {% endif %} -
{{ _('Timezone') }}{{ _('(select your closest major city)') }}
-
-
{{ form.timezone }} -
- {{ _('or') }} - {{ _('pick from map') }} -
-
-
+
{{ _('Timezone') }}{{ _('(select your closest major city)') }}
+
+
{{ form.timezone }} +
+ {{ _('or') }} + {{ _('pick from map') }} +
+
+
-
{{ _('Default language') }}
- {{ form.language }} +
{{ _('Default language') }}
+ {{ form.language }} - {% if form.captcha %} -
{{ form.captcha }}
- {% if form.captcha.errors %} -
{{ form.captcha.errors }}
- {% endif %} - {% endif %} +
{{ _('Affiliated organizations') }}
+ {{ form.organizations }} -
- - -
+ {% if form.newsletter %} +
{{ form.newsletter }} + +
+ {% endif %} -
-
-
-
+ {% if form.captcha %} +
{{ form.captcha }}
+ {% if form.captcha.errors %} +
{{ form.captcha.errors }}
+ {% endif %} + {% endif %} + +
+ {% if tos_url %} + + {{ _('By registering, you agree to our') }} + {{ _('Terms & Conditions') }}. + + {% endif %} + + +
+ +
+
+
+
+
-
{% endblock %} diff --git a/templates/registration/totp_auth.html b/templates/registration/totp_auth.html index 7fc596b..2c6ac4e 100644 --- a/templates/registration/totp_auth.html +++ b/templates/registration/totp_auth.html @@ -1,43 +1,43 @@ {% extends "base.html" %} {% block media %} - + .totp-panel-message { + width: 300px; + } + {% endblock %} {% block body %} -
-
- {% csrf_token %} - {% if form.errors %} -
-

{{ _('Invalid Two Factor Authentication token.') }}

-
- {% endif %} +
+ + {% csrf_token %} + {% if form.errors %} +
+

{{ _('Invalid Two Factor Authentication token.') }}

+
+ {% endif %} -
-
{{ form.totp_token }}
-
- - -

{{ _('If you lost your authentication device, please contact us at %(email)s.', email=SITE_ADMIN_EMAIL)|urlize }}

-
+
+
{{ form.totp_token }}
+
+ + +

{{ _('If you lost your authentication device, please contact us at %(email)s.', email=SITE_ADMIN_EMAIL)|urlize }}

+
{% endblock %} diff --git a/templates/registration/totp_disable.html b/templates/registration/totp_disable.html index 4aab628..9919bb6 100644 --- a/templates/registration/totp_disable.html +++ b/templates/registration/totp_disable.html @@ -1,51 +1,51 @@ {% extends "base.html" %} {% block media %} - + #totp-disable-form { + border: unset; + background: unset; + max-width: 700px; + } + {% endblock %} {% block body %} -
-
- {% csrf_token %} -
{{ _('To protect your account, you must first authenticate before you can disable Two Factor Authentication.') }}
- {% if form.totp_token.errors %} -
- {{ form.totp_token.errors }} -
- {% endif %} -
- - {{ form.totp_token }} -
- -
-
+
+
+ {% csrf_token %} +
{{ _('To protect your account, you must first authenticate before you can disable Two Factor Authentication.') }}
+ {% if form.totp_token.errors %} +
+ {{ form.totp_token.errors }} +
+ {% endif %} +
+ + {{ form.totp_token }} +
+ +
+
{% endblock %} diff --git a/templates/registration/totp_enable.html b/templates/registration/totp_enable.html index 4ade865..c291353 100644 --- a/templates/registration/totp_enable.html +++ b/templates/registration/totp_enable.html @@ -1,89 +1,89 @@ {% extends "base.html" %} {% block media %} - + .totp-qr-code img, .totp-qr-code canvas { + width: 400px; + max-width: 100%; + margin: 0 auto; + display: block; + -ms-interpolation-mode: nearest-neighbor; + image-rendering: -webkit-optimize-contrast; + image-rendering: -webkit-crisp-edges; + image-rendering: -o-crisp-edges; + image-rendering: pixelated; + image-rendering: -moz-crisp-edges; + image-rendering: crisp-edges; + } + {% endblock %} {% block js_media %} - + {% endblock %} {% block body %} -
-
- {% csrf_token %} +
+ + {% csrf_token %} -
{{ _('Scan this code with your authenticator app:') }}
-
{{ _('QR code') }}
-
{{ _('Or enter this code manually:') }} - {{ totp_key }} -
-
- {% if form.totp_token.errors %} -
- {{ form.totp_token.errors }} -
- {% endif %} -
- - {{ form.totp_token }} -
- - -
+
{{ _('Scan this code with your authenticator app:') }}
+
{{ _('QR code') }}
+
{{ _('Or enter this code manually:') }} + {{ totp_key }} +
+
+ {% if form.totp_token.errors %} +
+ {{ form.totp_token.errors }} +
+ {% endif %} +
+ + {{ form.totp_token }} +
+ + +
{% endblock %} diff --git a/templates/registration/username_select.html b/templates/registration/username_select.html index 8eb66e4..c3df4d4 100644 --- a/templates/registration/username_select.html +++ b/templates/registration/username_select.html @@ -1,9 +1,9 @@ {% extends "base.html" %} {% block body %} -
- {% csrf_token %} - {{ form.as_table() }}
- -
+
+ {% csrf_token %} + {{ form.as_table() }}
+ +
{% endblock %} diff --git a/templates/resolver/media-js.html b/templates/resolver/media-js.html deleted file mode 100644 index 07e40e2..0000000 --- a/templates/resolver/media-js.html +++ /dev/null @@ -1,427 +0,0 @@ -{% compress js %} - -{% endcompress %} \ No newline at end of file diff --git a/templates/resolver/resolver.html b/templates/resolver/resolver.html deleted file mode 100644 index b0008d8..0000000 --- a/templates/resolver/resolver.html +++ /dev/null @@ -1,42 +0,0 @@ - - - - - Contest Resolver - - - - - - - - - - - - - - -
-
- -
-
Rank
-
-
Name
-
-
Score
-
- -
-
- -
-
X
-
Y
-
Z
-
- {% include "resolver/media-js.html" %} - - - \ No newline at end of file diff --git a/templates/runtime-version-fragment.html b/templates/runtime-version-fragment.html index 321ecee..0457b83 100644 --- a/templates/runtime-version-fragment.html +++ b/templates/runtime-version-fragment.html @@ -1,12 +1,12 @@ {% for name, versions in runtime_versions -%} - {%- if versions -%} - {%- if versions[0] != versions|last -%} - {{ name }} {{ versions[0] }} - {{ versions|last }} + {%- if versions -%} + {%- if versions[0] != versions|last -%} + {{ name }} {{ versions[0] }} - {{ versions|last }} + {%- else -%} + {{ name }} {{ versions[0] }} + {%- endif -%} {%- else -%} - {{ name }} {{ versions[0] }} + {{ name }} {%- endif -%} - {%- else -%} - {{ name }} - {%- endif -%} - {%- if not loop.last %}, {% endif -%} + {%- if not loop.last %}, {% endif -%} {%- endfor -%} diff --git a/templates/site-logo-fragment.html b/templates/site-logo-fragment.html index 7b47f7b..67425e0 100644 --- a/templates/site-logo-fragment.html +++ b/templates/site-logo-fragment.html @@ -1,12 +1,8 @@ -{% if request.in_contest_mode and request.participation.contest.logo_override_image %} - {{ SITE_NAME }} -{% elif request.organization and request.organization.organization_image %} - {{ SITE_NAME }} -{% elif organization_image is defined and organization_image %} - {{ SITE_NAME }} +{% if request.in_contest and request.participation.contest.logo_override_image %} + {{ SITE_NAME }} {% elif logo_override_image is defined and logo_override_image %} - {{ SITE_NAME }} + {{ SITE_NAME }} {% else %} - {{ SITE_NAME }} + {{ SITE_NAME }} {% endif %} diff --git a/templates/solution-preview.html b/templates/solution-preview.html index 8dc6f6e..90004b6 100644 --- a/templates/solution-preview.html +++ b/templates/solution-preview.html @@ -1 +1,4 @@ -{{ preview_data|markdown|reference|str|safe }} +{{ preview_data|markdown('solution', MATH_ENGINE)|reference|str|safe }} +{% if REQUIRE_JAX %} +
+{% endif %} \ No newline at end of file diff --git a/templates/stats/base.html b/templates/stats/base.html index 406b6c3..d83ac96 100644 --- a/templates/stats/base.html +++ b/templates/stats/base.html @@ -1,15 +1,18 @@ {% extends "base.html" %} {% block js_media %} - {% compress js %} - {% include "stats/media-js.html" %} - {% endcompress %} + {% compress js %} + {% include "stats/media-js.html" %} + {% endcompress %} {% endblock %} -{% block content_title %}{% endblock %} -{% block title_ruler %}{% endblock %} +{% block content_title %}{{ _('Statistics') }}{% endblock %} {% block body %} - {% include "stats/tab.html" %} - {% block chart_body %}{% endblock %} + + {% block chart_body %}{% endblock %} {% endblock %} diff --git a/templates/stats/language.html b/templates/stats/language.html index aaa9e9d..d142c62 100644 --- a/templates/stats/language.html +++ b/templates/stats/language.html @@ -1,45 +1,55 @@ {% extends "stats/base.html" %} {% block media %} - + {% endblock %} {% block chart_body %} -

{{ _('Submission Statistics') }}

-
- -
+

{{ _('Submission Statistics') }}

+
+ +
-

{{ _('Submissions by Language') }}

-
- -
+

{{ _('Submissions by Language') }}

+
+ +
-

{{ _('AC Submissions by Language') }}

-
- -
+

{{ _('AC Submissions by Language') }}

+
+ +
-

{{ _('Language AC Rate') }}

-
- +

{{ _('Language AC Rate') }}

+
+
{% endblock %} {% block bodyend %} - + {% endblock %} diff --git a/templates/stats/media-js.html b/templates/stats/media-js.html index cba5683..981ddff 100644 --- a/templates/stats/media-js.html +++ b/templates/stats/media-js.html @@ -1,110 +1,68 @@ diff --git a/templates/stats/site.html b/templates/stats/site.html deleted file mode 100644 index e622b9d..0000000 --- a/templates/stats/site.html +++ /dev/null @@ -1,65 +0,0 @@ -{% extends "stats/base.html" %} -{% block media %} - -{% endblock %} - -{% block chart_body %} -
-
- -
-

{{ _('Submissions') }}

-
-
-
- -
-

{{ _('Contests') }}

-
-
-
- -
-

{{ _('New users') }}

-
-
-
- -
-

{{ _('Groups') }}

-
-
-
- -
-

{{ _('Comments') }}

-
-
-
- -
-

{{ _('Chat messages') }}

-
-{% endblock %} - -{% block bodyend %} - -{% endblock %} diff --git a/templates/stats/tab.html b/templates/stats/tab.html deleted file mode 100644 index 5dfef09..0000000 --- a/templates/stats/tab.html +++ /dev/null @@ -1,6 +0,0 @@ -{% extends "tabs-base.html" %} - -{% block tabs %} - {{ make_tab('language', 'fa-list', url('language_stats'), _('Language')) }} - {{ make_tab('site', 'fa-list', url('site_stats'), _('Site')) }} -{% endblock %} \ No newline at end of file diff --git a/templates/status/judge-status-table.html b/templates/status/judge-status-table.html index 7a86514..5968819 100644 --- a/templates/status/judge-status-table.html +++ b/templates/status/judge-status-table.html @@ -1,67 +1,67 @@ - {{ _('Judge') }} - {% if see_all_judges %} - {{ _('Online') }} - {% endif %} - {{ _('Uptime') }} - {{ _('Ping') }} - {{ _('Load') }} - {{ _('Runtimes') }} + {{ _('Judge') }} + {% if see_all_judges %} + {{ _('Online') }} + {% endif %} + {{ _('Uptime') }} + {{ _('Ping') }} + {{ _('Load') }} + {{ _('Runtimes') }} {% for judge in judges %} - - - {% if perms.judge.change_judge %} - {{ judge.name }} - {% else %} - {{ judge.name }} - {% endif %} - - {% if see_all_judges %} - - {% if judge.online %} - - {% else %} - + + + {% if perms.judge.change_judge %} + {{ judge.name }} + {% else %} + {{ judge.name }} + {% endif %} + + {% if see_all_judges %} + + {% if judge.online %} + + {% else %} + + {% endif %} + {% endif %} - - {% endif %} - - {% if judge.online %} - {{ judge.uptime|timedelta("simple") }} - {% else %} - {{ _('N/A') }} - {% endif %} - - - {% if judge.online and judge.ping_ms %} - {{ judge.ping_ms|floatformat(3) }} ms - {% else %} - {{ _('N/A') }} - {% endif %} - - - {% if judge.online %} - {{ judge.load|floatformat(3) }} - {% else %} - {{ _('N/A') }} - {% endif %} - - - {% if judge.online %} - {% for key, info in judge.runtime_versions -%} - {{ info.name }} - {%- if not loop.last %}, {% endif %} - {%- endfor %} - {% else %}{{ _('N/A') }}{% endif %} - - + + {% if judge.online %} + {{ judge.uptime|timedelta("simple") }} + {% else %} + {{ _('N/A') }} + {% endif %} + + + {% if judge.online and judge.ping_ms %} + {{ judge.ping_ms|floatformat(3) }} ms + {% else %} + {{ _('N/A') }} + {% endif %} + + + {% if judge.online %} + {{ judge.load|floatformat(3) }} + {% else %} + {{ _('N/A') }} + {% endif %} + + + {% if judge.online %} + {% for key, info in judge.runtime_versions -%} + {{ info.name }} + {%- if not loop.last %}, {% endif %} + {%- endfor %} + {% else %}{{ _('N/A') }}{% endif %} + + {% else %} - - {{ _('There are no judges available at this time.') }} - - + + {{ _('There are no judges available at this time.') }} + + {% endfor %} diff --git a/templates/status/judge-status.html b/templates/status/judge-status.html index 4e8f87f..dac5cb1 100644 --- a/templates/status/judge-status.html +++ b/templates/status/judge-status.html @@ -1,23 +1,23 @@ {% extends "base.html" %} {% block js_media %} - {% include "status/media-js.html" %} + {% include "status/media-js.html" %} {% endblock %} {% block media %} - {% include "status/media-css.html" %} - {% block content_media %}{% endblock %} + {% include "status/media-css.html" %} + {% block content_media %}{% endblock %} {% endblock %} {% block title_ruler %}{% endblock %} {% block title_row %} - {% set tab = 'judges' %} - {% include "status/status-tabs.html" %} + {% set tab = 'judges' %} + {% include "status/status-tabs.html" %} {% endblock %} {% block body %} - - {% include "status/judge-status-table.html" %} -
+ + {% include "status/judge-status-table.html" %} +
{% endblock %} \ No newline at end of file diff --git a/templates/status/language-list.html b/templates/status/language-list.html index bb08829..298633b 100644 --- a/templates/status/language-list.html +++ b/templates/status/language-list.html @@ -1,58 +1,60 @@ {% extends "base.html" %} {% block media %} - + .table td { + text-align: left; + } + {% endblock %} {% block title_ruler %}{% endblock %} {% block title_row %} - {% set tab = 'runtimes' %} - {% include "status/status-tabs.html" %} + {% set tab = 'runtimes' %} + {% include "status/status-tabs.html" %} {% endblock %} {% block body %} - - - - - - - - - - {% for language in languages %} - {# All online languages have runtime_versions, even if we're not going to display them #} - {% if language.runtime_versions %} - - - - - - {% endif %} - {% endfor %} - -
{{ _('ID') }}{{ _('Name') }}{{ _('Runtime Info') }}
{{ language.short_display_name }}{{ language.name }} - {{ runtime_versions(language.runtime_versions()) }} - {% if language.description %} -
- {{ language.description|markdown|safe }} -
- {% endif %} -
+ + + + + + + + + + {% for language in languages %} + {# All online languages have runtime_versions, even if we're not going to display them #} + {% if language.runtime_versions %} + + + + + + {% endif %} + {% endfor %} + +
{{ _('ID') }}{{ _('Name') }}{{ _('Runtime Info') }}
{{ language.short_display_name }}{{ language.name }} + {{ runtime_versions(language.runtime_versions()) }} + {% if language.description %} +
+ {% cache 86400 'language_html' language.id %} + {{ language.description|markdown('language') }} + {% endcache %} +
+ {% endif %} +
{% endblock %} \ No newline at end of file diff --git a/templates/status/media-css.html b/templates/status/media-css.html index a60fb41..49658bf 100644 --- a/templates/status/media-css.html +++ b/templates/status/media-css.html @@ -1,14 +1,14 @@ \ No newline at end of file diff --git a/templates/status/media-js.html b/templates/status/media-js.html index 6d3df3c..a5b1cb1 100644 --- a/templates/status/media-js.html +++ b/templates/status/media-js.html @@ -1,62 +1,62 @@ \ No newline at end of file diff --git a/templates/status/status-tabs.html b/templates/status/status-tabs.html index 6381810..1dd737e 100644 --- a/templates/status/status-tabs.html +++ b/templates/status/status-tabs.html @@ -1,7 +1,7 @@ {% extends "tabs-base.html" %} {% block tabs %} - {{ make_tab('judges', 'fa-server', url('status_all'), _('Judges')) }} - {{ make_tab('runtimes', 'fa-code', url('runtime_list'), _('Runtimes')) }} - {{ make_tab('matrix', 'fa-table', url('version_matrix'), _('Version Matrix')) }} + {{ make_tab('judges', 'fa-server', url('status_all'), _('Judges')) }} + {{ make_tab('runtimes', 'fa-code', url('runtime_list'), _('Runtimes')) }} + {{ make_tab('matrix', 'fa-table', url('version_matrix'), _('Version Matrix')) }} {% endblock %} diff --git a/templates/status/versions.html b/templates/status/versions.html index 1f56e03..1c0a991 100644 --- a/templates/status/versions.html +++ b/templates/status/versions.html @@ -3,40 +3,40 @@ {% block title_ruler %}{% endblock %} {% block title_row %} - {% set tab = 'matrix' %} - {% include "status/status-tabs.html" %} + {% set tab = 'matrix' %} + {% include "status/status-tabs.html" %} {% endblock %} {% block body %} - - - - {% for judge in judges %} - - {% endfor %} - - {% for language in languages %} - - - {% for judge in judges %} - {% set versions = matrix[judge][language.id] %} - +
{{ judge }}
{{ language.name }} - {%- for version in versions -%} - {{ version.name }}{% if version.version %} {{ version.version }}{% endif %} - {% if not loop.last %}
{% endif %} - {%- else -%} - — - {%- endfor -%} -
+ + + {% for judge in judges %} + + {% endfor %} + + {% for language in languages %} + + + {% for judge in judges %} + {% set versions = matrix[judge][language.id] %} + + {% endfor %} + {% endfor %} - - {% endfor %} -
{{ judge }}
{{ language.name }} + {%- for version in versions -%} + {{ version.name }}{% if version.version %} {{ version.version }}{% endif %} + {% if not loop.last %}
{% endif %} + {%- else -%} + — + {%- endfor -%} +
+ {% endblock %} diff --git a/templates/submission/info-base.html b/templates/submission/info-base.html index d6c8961..53a5a4e 100644 --- a/templates/submission/info-base.html +++ b/templates/submission/info-base.html @@ -1,16 +1,16 @@ -{% extends "common-content.html" %} +{% extends "base.html" %} {% block header %} - - {{ submission.date|date(_("N j, Y, g:i a")) }} - {%- if perms.judge.change_submission and submission.judged_on %} - on {{ submission.judged_on.name }} - {% endif %} -
- {{ submission.language }} - {% if perms.judge.change_submission %} - [{{ _('Admin') }}] - {% endif %} + + {{ submission.date|date(_("N j, Y, g:i a")) }} + {%- if perms.judge.change_submission and submission.judged_on %} + on {{ submission.judged_on.name }} + {% endif %} +
+ {{ submission.language }} + {% if perms.judge.change_submission %} + [{{ _('Admin') }}] + {% endif %} +
-
{% endblock %} diff --git a/templates/submission/internal-error-message.html b/templates/submission/internal-error-message.html index f47c50a..2b2e5b0 100644 --- a/templates/submission/internal-error-message.html +++ b/templates/submission/internal-error-message.html @@ -1,18 +1,18 @@ -

- {% if request.user == submission.user.user %} - {% trans trimmed %} - An internal error occurred while grading, and the {{ SITE_NAME }} administrators have been notified.
- In the meantime, try resubmitting in a few seconds. - {% endtrans %} - {% else %} - {{ _('An internal error occurred while grading.') }} - {% endif %} +

+ {% if request.user == submission.user.user %} + {% trans trimmed %} + An internal error occurred while grading, and the {{ SITE_NAME }} administrators have been notified.
+ In the meantime, try resubmitting in a few seconds. + {% endtrans %} + {% else %} + {{ _('An internal error occurred while grading.') }} + {% endif %}

{% if submission.error and request.user.is_authenticated %} - {% if request.profile.id in submission.problem.editor_ids or perms.judge.edit_all_problem %} -

-

{{ _('Error information') }}

- {{ submission.error|highlight('pytb', linenos=True) }} - {% endif %} + {% if request.profile.id in submission.problem.editor_ids or perms.judge.edit_all_problem %} +

+

{{ _('Error information') }}

+
{{ submission.error|highlight('pytb') }}
+ {% endif %} {% endif %} \ No newline at end of file diff --git a/templates/submission/list.html b/templates/submission/list.html index e36576d..c1f52a0 100644 --- a/templates/submission/list.html +++ b/templates/submission/list.html @@ -1,397 +1,377 @@ -{% extends "three-column-content.html" %} - -{% set has_hidden_subtasks = request.in_contest_mode and request.participation.contest.format.has_hidden_subtasks %} - +{% extends "common-content.html" %} {% block js_media %} - - - {% compress js %} - - {% if request.user.is_authenticated and perms.judge.rejudge_submission %} - - {% endif %} - - - {% endcompress %} - {% if dynamic_update and last_msg and not has_hidden_subtasks %} - + {% if request.user.is_authenticated and perms.judge.rejudge_submission %} + + {% endif %} - var table = $('#submissions-table'); - var statistics = $("#statistics-table"); - var doing_ajax = false; - var first = parseInt(table.find('>div:first-child').attr('id')); - - var update_submission = function (message, force) { - if (language_filter.length && 'language' in message && - language_filter.indexOf(message.language) == -1) - return; - if (status_filter.length && 'status' in message && - status_filter.indexOf(message.status) == -1) - return; - var id = message.id; - var row = table.find('div#' + id); - if (row.length < 1) { - if (id < first) - return; - first = id; - row = $('
', {id: id, 'class': 'submission-row'}).hide().prependTo(table); - if (table.find('>div').length >= {{ paginator.per_page }}) - table.find('>div:last-child').hide('slow', function () { - $(this).remove(); - }); - } - if (force || !doing_ajax) { - if (!force) doing_ajax = true; - $.ajax({ - url: '{{ url('submission_single_query') }}', - data: {id: id, show_problem: show_problem} - }).done(function (data) { - var was_shown = row.is(':visible'); - row.html(data); - register_time(row.find('.time-with-rel')); - if (!was_shown) { - row.slideDown('slow'); + + - {% endif %} + + {% endcompress %} + + {% if dynamic_update and last_msg %} + + {% endif %} {% endblock %} {% block title_ruler %}{% endblock %} -{% block title_row %}{% endblock %} +{% block title_row %} + {% include "submission/submission-list-tabs.html" %} +{% endblock %} + +{% block media %} + {% if perms.judge.change_submission and perms.judge.rejudge_submission %} + + {% endif %} -{% block three_col_media %} - {% if perms.judge.change_submission and perms.judge.rejudge_submission %} - {% endif %} - - {% endblock %} -{% block middle_title %} -
-
-

{{content_title}}

-
-
-{% endblock %} - -{% block middle_content %} -
- - -
- {% set profile_id = request.profile.id if request.user.is_authenticated else 0 %} - {% for submission in submissions %} -
- {% with problem_name=show_problem and submission.problem.i18n_name %} - {% include "submission/row.html" %} - {% endwith %} -
- {% endfor %} -
+{% block body %} {% if page_obj.num_pages > 1 %} -
{% include "list-pages.html" %}
+
+ {% include "list-pages.html" %} +
{% endif %} -
-{% endblock %} -{% block right_sidebar %} -