├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── config.yml │ └── feature_request.md └── workflows │ └── main.yml ├── .gitignore ├── .gitmodules ├── CHANGELOG.md ├── INSTALL.md ├── LICENSE ├── README.md ├── VERSION ├── assets └── tablesorter │ ├── css │ └── theme.bootstrap_4.css │ └── js │ └── jquery.tablesorter.min.js ├── evaluation ├── __init__.py ├── admin.py ├── apps.py ├── migrations │ └── __init__.py ├── models.py ├── templates │ ├── _paginator.html │ └── comparison │ │ ├── base.html │ │ ├── compare_submissions.html │ │ └── submission.html ├── tests.py └── views.py ├── install-psql.sh ├── leaderboard ├── __init__.py ├── admin.py ├── apps.py ├── forms.py ├── migrations │ ├── 0001_initial.py │ ├── 0002_testset_json_data.py │ ├── 0003_submission.py │ ├── 0004_auto_20190831_0113.py │ ├── 0005_auto_20200618_2157.py │ ├── 0006_auto_20200618_2204.py │ ├── 0007_submission_is_public.py │ ├── 0008_team.py │ ├── 0009_auto_20200618_2345.py │ ├── 0010_testset_is_active.py │ ├── 0011_auto_20200622_2334.py │ ├── 0012_auto_20200623_1629.py │ ├── 0013_auto_20200623_1928.py │ ├── 0014_submission_score_chrf.py │ ├── 0015_auto_20200626_1341.py │ ├── 0016_auto_20200626_1402.py │ ├── 0017_submission_is_constrained.py │ ├── 0018_team_publication_name.py │ ├── 0019_auto_20200710_2037.py │ ├── 0020_auto_20200710_2145.py │ ├── 0021_auto_20200710_2245.py │ ├── 0022_competition.py │ ├── 0023_competition_is_active.py │ ├── 0024_auto_20210225_1118.py │ ├── 0025_auto_20210225_1954.py │ ├── 0026_auto_20210226_0859.py │ ├── 0027_auto_20210609_0818.py │ ├── 0028_auto_20210609_1215.py │ ├── 0029_auto_20210611_0713.py │ ├── 0030_auto_20210615_1758.py │ ├── 0031_auto_20210616_0934.py │ ├── 0032_testset_collection.py │ ├── 0033_testset_compute_scores.py │ ├── 0034_submission_is_valid.py │ ├── 0035_alter_submission_file_format.py │ ├── 0036_submission_is_contrastive_submission_is_withdrawn.py │ ├── 0037_auto_20240628_0832.py │ └── __init__.py ├── models.py ├── templates │ └── leaderboard │ │ ├── base.html │ │ ├── competition.html │ │ ├── download.html │ │ ├── frontpage.html │ │ ├── sign-in.html │ │ ├── signup.html │ │ ├── submission.html │ │ ├── teampage.html │ │ ├── updates.html │ │ └── welcome.html ├── testdata │ ├── newstest2019-ende-ref.de.sgm │ ├── newstest2019-ende-ref.de.txt │ ├── newstest2019-ende-src.en.sgm │ ├── newstest2019-ende-src.en.txt │ ├── newstest2019.msft-WMT19-document-level.6808.en-de.sgm │ ├── newstest2019.msft-WMT19-document-level.6808.en-de.txt │ ├── newstest2019.msft-WMT19-sentence-level.6785.en-de.txt │ ├── newstest2019.msft-WMT19-sentence_document.6974.en-de.txt │ └── xml │ │ ├── multi-hypA.xml │ │ ├── multi-src-ref.xml │ │ ├── sample-hyp.ha.txt │ │ ├── sample-hyp.invalid.xml │ │ ├── sample-hyp.testsuite.xml │ │ ├── sample-hyp.xml │ │ ├── sample-src-multirefs.xml │ │ ├── sample-src-ref.xml │ │ └── sample-src.xml ├── tests.py ├── utils.py └── views.py ├── manage.py ├── ocelot ├── __init__.py ├── context_processors.py ├── settings.py ├── urls.py └── wsgi.py ├── pylint.rc ├── requirements-dev.txt ├── requirements.txt ├── setup.cfg └── uwsgi_params /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: "OCELoT" 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | formatting: 7 | runs-on: ubuntu-20.04 8 | env: 9 | OCELOT_SECRET_KEY: not-a-secret-key-but-needed-for-testing 10 | steps: 11 | - uses: actions/checkout@v2 12 | - name: Python versions 13 | # On Ubuntu 20.04 python should be Python 3.8.5 14 | run: | 15 | which python 16 | python --version 17 | - name: Install requirements 18 | run: pip install -r requirements.txt 19 | - name: Install development tools 20 | # Python tools will be installed in ~/.local/bin, which by default is not in $PATH 21 | run: | 22 | echo "$HOME/.local/bin" >> $GITHUB_PATH 23 | pip install --upgrade pip setuptools wheel 24 | pip install -r requirements-dev.txt 25 | - name: Module versions 26 | run: | 27 | mypy --version 28 | black --version 29 | pylint --version 30 | - name: Run mypy 31 | run: find . -name "*.py" -not -path "./venv*" | xargs mypy 32 | - name: Reformat 33 | run: | 34 | black -S -l 75 --check . 35 | find . -name "*.py" -not -path "./venv*" -not -path "*/migrations/*" | xargs pylint --fail-under 9 --rcfile setup.cfg 36 | find . -name "*.py" -not -path "./venv*" -not -path "*/migrations/*" | xargs reorder-python-imports --diff-only 37 | - name: Check safety 38 | run: cat requirements.txt | safety check --stdin 39 | 40 | testing: 41 | runs-on: ubuntu-20.04 42 | env: 43 | OCELOT_SECRET_KEY: not-a-secret-key-but-needed-for-testing 44 | steps: 45 | - uses: actions/checkout@v2 46 | - name: Install requirements 47 | run: pip install -r requirements.txt 48 | - name: Run unit tests 49 | run: python manage.py test -v2 50 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Environment 2 | *~ 3 | *.swo 4 | *.swp 5 | 6 | # Python 7 | *.pyc 8 | *.log 9 | .mypy_cache 10 | venv 11 | 12 | # OCELoT 13 | db.sqlite3* 14 | ocelot/local_settings.py 15 | submissions 16 | testsets 17 | static 18 | 19 | # Unit tests 20 | leaderboard/testdata/*.filtered.txt 21 | leaderboard/testdata/*.filtered.sgm 22 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "compare-mt"] 2 | path = compare-mt 3 | url = https://github.com/neulab/compare-mt 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | 8 | ## [0.8.1] - 2024-06-28 9 | - Updated `#wmt23dev` to `#wmt24dev` and other WMT23 mentions. 10 | - Added `is_open_source` to `Submission`. 11 | - Added two unconstrained submission types on the team page: open-source and closed systems. 12 | 13 | ## [0.8.0] - 2024-06-20 14 | - Updated `#wmt23dev` to `#wmt24dev` and other WMT23 mentions. 15 | 16 | ## [0.7.0] - 2023-07-17 17 | - Added submission summary to team page. 18 | - Implemented logic for contrastive submissions. [[#62](https://github.com/AppraiseDev/OCELoT/issues/62)] 19 | - Added support for contrastive submissions to `teampage()` view. 20 | - Added `set_contrastive()` to `Submission` object model. 21 | - Added `is_contrastive` and `is_withdrawn` field to `Submission` object model. 22 | - Updated `Submission.file_format` default value to `XML_FILE`, now with database migration. 23 | - Added minimal hypothesis length validation for new `Submission` instances. 24 | 25 | ## [0.7.0] - 2023-07-14 26 | - Updated `Submission.file_format` default value to `XML_FILE`. 27 | - Updated `SubmissionForm` and made `file_format` widget readonly. This ensures that via the UI only XML files can be submitted. [[#101](https://github.com/AppraiseDev/OCELoT/issues/101)] 28 | - Fixed temporary file cleanup bugs in `leaderboard.tests`. 29 | - Added `is_valid` field to `Submission` object model. 30 | - More cleanup related to `TestSet` instances without reference file. 31 | - Updated `install-psql.sh` for PostgreSQL 14 and Debian. 32 | - Added download links for General MT and Biomedical shared tasks. 33 | - Added basic support for `TestSet` instances without reference(s). 34 | - Accept optional 'domain' attribute in XML submissions. [[#112](https://github.com/AppraiseDev/OCELoT/issues/112)] 35 | 36 | ## [0.7.0] - 2023-07-13 37 | - Fixed tests re: unverified teams' submission access. [[#56](https://github.com/AppraiseDev/OCELoT/issues/56)] 38 | - Fixed page templates to use `ocelot_team_verified` for access to submission view. [[#56](https://github.com/AppraiseDev/OCELoT/issues/56)] 39 | - Fixed #tags and updated to #wmt23dev. 40 | - Submission page/view now only works for verified teams. [[#56](https://github.com/AppraiseDev/OCELoT/issues/56)] 41 | - Added support for sorting `Submission` objects by `submitted_by` and `date_created`. [[#96](https://github.com/AppraiseDev/OCELoT/issues/96)] 42 | - Added default logic for `Team` submissions: we will choose the highest-scoring, or 43 | the latest `Submission` for each distinct test set. This requires users to explicitly 44 | withdraw from a language pair/test set if they don't want to participate in that one. [[#104](https://github.com/AppraiseDev/OCELoT/issues/104)] 45 | - Added `is_primary` selection to `SubmissionForm`. [[#104](https://github.com/AppraiseDev/OCELoT/issues/104)] 46 | 47 | ## [Unreleased] 48 | 49 | ### Added 50 | - Running multiple competitions at the same time with own deadlines 51 | - Segment-level comparison of two submissions 52 | - Sorting result tables with jQuery tablesorter 2.0 (MIT license) 53 | - Support for new XML format 54 | - Changed descriptions, updates and links for WMT21 55 | - Unverified accounts cannot make submissions 56 | - Show file format and is-verified flag in the Admin Panel 57 | - Institution name, system paper, and system description fields to Team 58 | 59 | ### Fixed 60 | - Pylint formatter knows about Django after adding the `pylint-django` plugin 61 | - Show an error message for submissions in XML format with no system translations 62 | - Do not show removed submissions on leaderboards 63 | - The deadline counter on the competition page uses server timezone (UTC) 64 | 65 | ### Changed 66 | - Updated requirements to Django 3 67 | - Removed static files which now need to be generated using `collectstatic` 68 | 69 | ## [0.0.1] - 2021-01-04 70 | 71 | ### Added 72 | - This CHANGELOG file 73 | - OCELoT code used at WMT20 74 | 75 | [Unreleased]: https://github.com/AppraiseDev/OCELoT/compare/v0.0.1...HEAD 76 | [0.0.1]: https://github.com/AppraiseDev/OCELoT/releases/tag/v0.0.1 77 | -------------------------------------------------------------------------------- /INSTALL.md: -------------------------------------------------------------------------------- 1 | # OCELoT 2 | 3 | ## Basic setup 4 | 5 | 1. Install Python 3.5+. 6 | 2. Clone the repository: 7 | 8 | git clone https://github.com/AppraiseDev/OCELoT 9 | cd OCELoT 10 | 11 | 3. Install virtual environments for Python: 12 | 13 | pip3 install --user virtualenv 14 | 15 | 4. Create environment for the project, activate it, and install Python 16 | requirements: 17 | 18 | virtualenv venv -p python3 19 | source venv/bin/activate 20 | pip install -r requirements.txt 21 | 22 | 5. Create database, the first super user, and collect static files: 23 | 24 | python manage.py migrate 25 | python manage.py createsuperuser 26 | python manage.py collectstatic 27 | 28 | Follow instructions on your screen; do not leave the password empty. 29 | 30 | 6. Run the app on a local server: 31 | 32 | python manage.py runserver 33 | 34 | Open the browser at http://127.0.0.1:8000/. 35 | The admin panel is available at http://127.0.0.1:8000/admin 36 | 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2019-2020, Christian Federmann 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Welcome to OCELoT! 2 | 3 | [![build](https://github.com/AppraiseDev/OCELoT/actions/workflows/main.yml/badge.svg)](https://github.com/AppraiseDev/OCELoT/actions/workflows/main.yml) 4 | [![release](https://img.shields.io/github/v/release/AppraiseDev/OCELoT?include_prereleases)](https://github.com/AppraiseDev/OCELoT/releases) 5 | [![license: BSD](https://img.shields.io/badge/license-BSD-blue.svg)](./LICENSE) 6 | 7 | ![Project OCELoT logo](https://upload.wikimedia.org/wikipedia/commons/0/0f/Ocelotl.svg) 8 | 9 | OCELoT stands for **O**pen, **Co**mpetitive **E**valuation **L**eaderboard 10 | **o**f **T**ranslations. This project started as part of the [Fifth Machine 11 | Translation Marathon in the Americas](http://statmt.org/mtma19/), hosted at 12 | UMD, College Park, MD, from May 28–June 1, 2019. Project OCELoT aims to create 13 | an open platform for competitive evaluation of machine translation output, 14 | based on both automatic metrics and human evalation. Code is available from 15 | [GitHub](https://github.com/cfedermann/OCELoT/) and shared under an [open 16 | license](https://github.com/cfedermann/OCELoT/blob/master/LICENSE). 17 | 18 | ## Getting started 19 | 20 | * [Installation instructions](./INSTALL.md) 21 | * [Basic usage notes](https://github.com/AppraiseDev/OCELoT/wiki/Development#getting-started) 22 | 23 | ## License 24 | 25 | OCELoT is released under [BSD 3-Clause License](https://github.com/cfedermann/OCELoT/blob/master/LICENSE) 26 | 27 | ## Contributors 28 | 29 | We are grateful to the following contributors for their support: 30 | 31 | - Christian Federmann ([Microsoft](https://www.microsoft.com/en-us/research/people/chrife/)) 32 | - Roman Grundkiewicz (Microsoft) 33 | - Tom Kocmi (Microsoft) 34 | - Zi-Yi Dou ([Carnegie Mellon University](https://lti.cs.cmu.edu/people/222218769/zi-yi-dou)) 35 | 36 | ## Acknowledgments 37 | 38 | We acknowledge the following licenses and thank the respective authors for 39 | making their work available: 40 | 41 | - Project `compare-mt` by [NeuLab](https://github.com/neulab/compare-mt) 42 | released under [BSD 3-Clause 43 | License](https://github.com/neulab/compare-mt/blob/master/LICENSE); you 44 | should also [read their NAACL19 paper](http://arxiv.org/abs/1903.07926)! 45 | - Logo `Glyphe Ocelotl (jaguar)` by 46 | [Katepanomegas](https://commons.wikimedia.org/wiki/User:Katepanomegas) 47 | released on [Wikimedia 48 | Commons](https://commons.wikimedia.org/wiki/Category:Ocelotl_(glyph)#/media/File:Ocelotl.svg) 49 | under [CC BY 3.0 License](https://creativecommons.org/licenses/by/3.0/) 50 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 0.8.1 2 | -------------------------------------------------------------------------------- /assets/tablesorter/css/theme.bootstrap_4.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Bootstrap theme v4.x 3 | */ 4 | .tablesorter-bootstrap { 5 | width: 100%; 6 | } 7 | .tablesorter-bootstrap thead th, 8 | .tablesorter-bootstrap thead td, 9 | .tablesorter-bootstrap tfoot th, 10 | .tablesorter-bootstrap tfoot td { 11 | font: 14px/20px Arial, Sans-serif; 12 | font-weight: bold; 13 | padding: 4px; 14 | margin: 0 0 18px; 15 | } 16 | 17 | .tablesorter-bootstrap thead .tablesorter-header { 18 | background-position: right 5px center; 19 | background-repeat: no-repeat; 20 | cursor: pointer; 21 | white-space: normal; 22 | } 23 | .tablesorter-bootstrap:not(.table-dark) thead:not(.thead-dark) .tablesorter-header, 24 | .tablesorter-bootstrap:not(.table-dark) tfoot th, 25 | .tablesorter-bootstrap:not(.table-dark) tfoot td { 26 | background-color: #eee; 27 | } 28 | 29 | .tablesorter-bootstrap thead .sorter-false { 30 | cursor: default; 31 | background-image: none; 32 | } 33 | 34 | .tablesorter-bootstrap .tablesorter-header-inner { 35 | position: relative; 36 | padding: 4px 18px 4px 4px; 37 | } 38 | .tablesorter-bootstrap .sorter-false .tablesorter-header-inner { 39 | padding: 4px; 40 | } 41 | 42 | /* black icons */ 43 | .tablesorter-bootstrap thead .tablesorter-headerUnSorted:not(.sorter-false) { 44 | background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDE0IDIwIj48cGF0aCBkPSJNMTQgMTNsLTIuNS0yLjVMNyAxNWwtNC41LTQuNUwwIDEzbDcgN3pNMTQgNy41TDExLjUgMTAgNyA1LjUgMi41IDEwIDAgNy41bDctN3oiLz48L3N2Zz4=); 45 | } 46 | .tablesorter-bootstrap thead .tablesorter-headerAsc { 47 | background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMiIgaGVpZ2h0PSIxMiIgdmlld0JveD0iMCAwIDE0IDE0Ij48cGF0aCBkPSJNMTQgOS41TDExLjUgMTIgNyA3LjUgMi41IDEyIDAgOS41bDctN3oiLz48L3N2Zz4=); 48 | } 49 | .tablesorter-bootstrap thead .tablesorter-headerDesc { 50 | background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMiIgaGVpZ2h0PSIxMiIgdmlld0JveD0iMCAwIDE0IDE0Ij48cGF0aCBkPSJNMTQgNWwtMi41LTIuNS00LjUgNC41LTQuNS00LjVMMCA1IDcgMTJ6Ii8+PC9zdmc+); 51 | } 52 | 53 | /* white icons */ 54 | .tablesorter-bootstrap thead.thead-dark .tablesorter-headerUnSorted:not(.sorter-false), 55 | .tablesorter-bootstrap.table-dark thead .tablesorter-headerUnSorted:not(.sorter-false) { 56 | background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDE0IDIwIj48cGF0aCBmaWxsPSIjZmZmIiBkPSJNMTQgMTNsLTIuNS0yLjVMNyAxNWwtNC41LTQuNUwwIDEzbDcgN3pNMTQgNy41TDExLjUgMTAgNyA1LjUgMi41IDEwIDAgNy41bDctN3oiLz48L3N2Zz4=); 57 | } 58 | .tablesorter-bootstrap thead.thead-dark .tablesorter-headerAsc, 59 | .tablesorter-bootstrap.table-dark thead .tablesorter-headerAsc { 60 | background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMiIgaGVpZ2h0PSIxMiIgdmlld0JveD0iMCAwIDE0IDE0Ij48cGF0aCBmaWxsPSIjZmZmIiBkPSJNMTQgOS41TDExLjUgMTIgNyA3LjUgMi41IDEyIDAgOS41bDctN3oiLz48L3N2Zz4=); 61 | } 62 | .tablesorter-bootstrap thead.thead-dark .tablesorter-headerDesc, 63 | .tablesorter-bootstrap.table-dark thead .tablesorter-headerDesc { 64 | background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMiIgaGVpZ2h0PSIxMiIgdmlld0JveD0iMCAwIDE0IDE0Ij48cGF0aCBmaWxsPSIjZmZmIiBkPSJNMTQgNWwtMi41LTIuNS00LjUgNC41LTQuNS00LjVMMCA1IDcgMTJ6Ii8+PC9zdmc+); 65 | } 66 | 67 | /* since bootstrap (table-striped) uses nth-child(), we just use this to add a zebra stripe color */ 68 | .tablesorter-bootstrap:not(.table-dark) > tbody > tr.odd > td, 69 | .tablesorter-bootstrap:not(.table-dark) > tbody > tr.tablesorter-hasChildRow.odd:hover ~ tr.tablesorter-hasChildRow.odd ~ .tablesorter-childRow.odd > td { 70 | background-color: #f9f9f9; 71 | } 72 | .tablesorter-bootstrap:not(.table-dark) > tbody > tr.hover > td, 73 | .tablesorter-bootstrap:not(.table-dark) > tbody > tr.odd:hover > td, 74 | .tablesorter-bootstrap:not(.table-dark) > tbody > tr.even:hover > td, 75 | .tablesorter-bootstrap:not(.table-dark) > tbody > tr.tablesorter-hasChildRow.odd:hover ~ .tablesorter-childRow.odd > td, 76 | .tablesorter-bootstrap:not(.table-dark) > tbody > tr.tablesorter-hasChildRow.even:hover ~ .tablesorter-childRow.even > td { 77 | background-color: #f5f5f5; 78 | } 79 | .tablesorter-bootstrap:not(.table-dark) > tbody > tr.even > td, 80 | .tablesorter-bootstrap:not(.table-dark) > tbody > tr.tablesorter-hasChildRow.even:hover ~ tr.tablesorter-hasChildRow.even ~ .tablesorter-childRow.even > td { 81 | background-color: #fff; 82 | } 83 | 84 | /* processing icon */ 85 | .tablesorter-bootstrap .tablesorter-processing { 86 | background-image: url('data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs='); 87 | background-position: center center !important; 88 | background-repeat: no-repeat !important; 89 | } 90 | 91 | /* Column Widget - column sort colors */ 92 | .tablesorter-bootstrap:not(.table-dark) > tbody > tr.odd td.primary { 93 | background-color: #bfbfbf; 94 | } 95 | .tablesorter-bootstrap:not(.table-dark) > tbody > tr td.primary, 96 | .tablesorter-bootstrap:not(.table-dark) > tbody > tr.even td.primary { 97 | background-color: #d9d9d9; 98 | } 99 | .tablesorter-bootstrap:not(.table-dark) > tbody > tr.odd td.secondary { 100 | background-color: #d9d9d9; 101 | } 102 | .tablesorter-bootstrap:not(.table-dark) > tbody > tr td.secondary, 103 | .tablesorter-bootstrap:not(.table-dark) > tbody > tr.even td.secondary { 104 | background-color: #e6e6e6; 105 | } 106 | .tablesorter-bootstrap:not(.table-dark) > tbody > tr.odd td.tertiary { 107 | background-color: #e6e6e6; 108 | } 109 | .tablesorter-bootstrap:not(.table-dark) > tbody > tr td.tertiary, 110 | .tablesorter-bootstrap:not(.table-dark) > tbody > tr.even td.tertiary { 111 | background-color: #f2f2f2; 112 | } 113 | 114 | /* caption */ 115 | .tablesorter-bootstrap:not(.table-dark) > .caption { 116 | background-color: #fff; 117 | } 118 | 119 | /* filter widget */ 120 | .tablesorter-bootstrap .tablesorter-filter-row input.tablesorter-filter, 121 | .tablesorter-bootstrap .tablesorter-filter-row select.tablesorter-filter { 122 | width: 98%; 123 | margin: 0; 124 | -webkit-box-sizing: border-box; 125 | -moz-box-sizing: border-box; 126 | box-sizing: border-box; 127 | -webkit-transition: height 0.1s ease; 128 | -moz-transition: height 0.1s ease; 129 | -o-transition: height 0.1s ease; 130 | transition: height 0.1s ease; 131 | } 132 | .tablesorter-bootstrap:not(.table-dark) .tablesorter-filter-row { 133 | background-color: #efefef; 134 | } 135 | .tablesorter-bootstrap:not(.table-dark) .tablesorter-filter-row input.tablesorter-filter, 136 | .tablesorter-bootstrap:not(.table-dark) .tablesorter-filter-row select.tablesorter-filter { 137 | color: #333; 138 | } 139 | 140 | .tablesorter-bootstrap .tablesorter-filter-row .tablesorter-filter.disabled { 141 | cursor: not-allowed; 142 | box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.075) inset; 143 | box-sizing: border-box; 144 | transition: height 0.1s ease; 145 | } 146 | 147 | .tablesorter-bootstrap:not(.table-dark) .tablesorter-filter-row td { 148 | line-height: normal; 149 | text-align: center; 150 | padding: 4px 6px; 151 | vertical-align: middle; 152 | -webkit-transition: line-height 0.1s ease; 153 | -moz-transition: line-height 0.1s ease; 154 | -o-transition: line-height 0.1s ease; 155 | transition: line-height 0.1s ease; 156 | } 157 | /* hidden filter row */ 158 | .tablesorter-bootstrap .tablesorter-filter-row.hideme td { 159 | padding: 2px; /* change this to modify the thickness of the closed border row */ 160 | margin: 0; 161 | line-height: 0; 162 | } 163 | .tablesorter-bootstrap .tablesorter-filter-row.hideme * { 164 | height: 1px; 165 | min-height: 0; 166 | border: 0; 167 | padding: 0; 168 | margin: 0; 169 | /* don't use visibility: hidden because it disables tabbing */ 170 | opacity: 0; 171 | filter: alpha(opacity=0); 172 | } 173 | /* rows hidden by filtering */ 174 | .tablesorter .filtered { 175 | display: none; 176 | } 177 | 178 | /* pager plugin */ 179 | .tablesorter-bootstrap .tablesorter-pager .pagedisplay { 180 | border: 0; 181 | } 182 | 183 | /* ajax error row */ 184 | .tablesorter:not(.table-dark) .tablesorter-errorRow td { 185 | text-align: center; 186 | cursor: pointer; 187 | background-color: #e6bf99; 188 | } 189 | -------------------------------------------------------------------------------- /evaluation/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AppraiseDev/OCELoT/c099a191de05a77dbd1a6f989157944c5d832cb0/evaluation/__init__.py -------------------------------------------------------------------------------- /evaluation/admin.py: -------------------------------------------------------------------------------- 1 | """ 2 | Project OCELoT: Open, Competitive Evaluation Leaderboard of Translations 3 | """ 4 | from django.contrib import admin 5 | 6 | # Register your models here. 7 | -------------------------------------------------------------------------------- /evaluation/apps.py: -------------------------------------------------------------------------------- 1 | """ 2 | Project OCELoT: Open, Competitive Evaluation Leaderboard of Translations 3 | """ 4 | from django.apps import AppConfig 5 | 6 | 7 | class EvaluationConfig(AppConfig): 8 | """OCELoT evaluation app Configuration""" 9 | 10 | name = 'evaluation' 11 | -------------------------------------------------------------------------------- /evaluation/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AppraiseDev/OCELoT/c099a191de05a77dbd1a6f989157944c5d832cb0/evaluation/migrations/__init__.py -------------------------------------------------------------------------------- /evaluation/models.py: -------------------------------------------------------------------------------- 1 | """ 2 | Project OCELoT: Open, Competitive Evaluation Leaderboard of Translations 3 | """ 4 | from django.db import models 5 | 6 | # Create your models here. 7 | -------------------------------------------------------------------------------- /evaluation/templates/_paginator.html: -------------------------------------------------------------------------------- 1 | 22 | -------------------------------------------------------------------------------- /evaluation/templates/comparison/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Project OCELoT{% block title %}{% endblock %} 9 | 10 | 11 | 12 | 13 | 34 | 35 | 36 | 37 | {% block navbar %} 38 | 77 | {% endblock %} 78 | 79 | {% if messages %} 80 |
81 | {% for message in messages %} 82 | 88 | {% endfor %} 89 |
90 | {% endif %} 91 | 92 | {% block main %}{% endblock %} 93 | 94 | 97 | 98 | 99 | 100 | 101 | 102 | {% block script %}{% endblock %} 103 | 104 | 105 | -------------------------------------------------------------------------------- /evaluation/templates/comparison/compare_submissions.html: -------------------------------------------------------------------------------- 1 | {% extends "comparison/base.html" %} 2 | {% load static %} 3 | 4 | {% block style %} 5 | .compare .diff-sub { background: #ff06; } 6 | .compare .diff-ins { background: #28a74570; } 7 | .compare .diff-del { background: #dc354573; } 8 | {% endblock %} 9 | 10 | {% block main %} 11 |
12 | 13 |
14 |
15 |

Compare two submissions

16 |

Displaying up to {{page_size}} segments per page.

17 | 18 | {% include '_paginator.html' %} 19 | 20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | {% for segment_a, segment_b in page.object_list %} 31 | 32 | 33 | 34 | 35 | 36 | {% endfor %} 37 | 38 |
Line{{submission_a}}{{submission_b}}
{{forloop.counter|add:page.start_index|add:"-1" }}{{segment_a|safe}}{{segment_b|safe}}
39 |
40 | 41 | {% include '_paginator.html' %} 42 |
43 |
44 | 45 |
46 | {% endblock %} 47 | 48 | {% block footer %} 49 | #blacklivesmatter #pride #andjusticeforall #capitolhillseattle 50 | {% endblock %} 51 | 52 | {% block script %} 53 | 56 | {% endblock %} 57 | -------------------------------------------------------------------------------- /evaluation/templates/comparison/submission.html: -------------------------------------------------------------------------------- 1 | {% extends "comparison/base.html" %} 2 | {% load static %} 3 | 4 | {% block main %} 5 |
6 | 7 |
8 |
9 |

Submission {{submission}}

10 | 11 |

12 | {% if compare_with %} 13 | Compare this submission with 14 | 19 | Compare 22 | {% endif %} 23 |

24 |

Displaying up to {{page_size}} segments per page.

25 | 26 | {% include '_paginator.html' %} 27 | 28 |
29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | {% for src_segment, hyp_segment in page.object_list %} 39 | 40 | 41 | 42 | 43 | 44 | {% endfor %} 45 | 46 |
LineSourceTranslation
{{forloop.counter|add:page.start_index|add:"-1" }}{{src_segment|safe}}{{hyp_segment|safe}}
47 |
48 | 49 | {% include '_paginator.html' %} 50 |
51 |
52 | 53 |
54 | {% endblock %} 55 | 56 | {% block footer %} 57 | #blacklivesmatter #pride #andjusticeforall #capitolhillseattle 58 | {% endblock %} 59 | 60 | {% block script %} 61 | 69 | {% endblock %} 70 | -------------------------------------------------------------------------------- /evaluation/tests.py: -------------------------------------------------------------------------------- 1 | """ 2 | Project OCELoT: Open, Competitive Evaluation Leaderboard of Translations 3 | """ 4 | import os 5 | from datetime import datetime 6 | 7 | from django.test import TestCase 8 | from django.utils import timezone 9 | 10 | from leaderboard.models import Competition 11 | from leaderboard.models import Language 12 | from leaderboard.models import SGML_FILE 13 | from leaderboard.models import Submission 14 | from leaderboard.models import Team 15 | from leaderboard.models import TestSet 16 | from leaderboard.models import TEXT_FILE 17 | from ocelot.settings import BASE_DIR 18 | 19 | TESTDATA_DIR = os.path.join(BASE_DIR, 'leaderboard/testdata') 20 | 21 | 22 | class ComparisonTests(TestCase): 23 | """Tests submission output comparison.""" 24 | 25 | def setUp(self): 26 | Language.objects.create(code='en', name='English') 27 | Language.objects.create(code='de', name='German') 28 | 29 | _next_year = datetime.now().year + 1 30 | self.competition = Competition.objects.create( 31 | is_active=True, 32 | name='MyCompetition', 33 | description='Description of the competition', 34 | deadline=datetime(_next_year, 1, 1, tzinfo=timezone.utc), 35 | ) 36 | 37 | testset = TestSet.objects.create( 38 | is_active=True, 39 | name='MyTestSet', 40 | source_language=Language.objects.get(code='en'), 41 | target_language=Language.objects.get(code='de'), 42 | file_format=SGML_FILE, 43 | src_file=os.path.join( 44 | TESTDATA_DIR, 'newstest2019-ende-src.en.sgm' 45 | ), 46 | ref_file=os.path.join( 47 | TESTDATA_DIR, 'newstest2019-ende-ref.de.sgm' 48 | ), 49 | competition=self.competition, 50 | ) 51 | 52 | self.team_a = Team.objects.create( 53 | is_active=True, 54 | name='Team A', 55 | email='team-a@email.com', 56 | ) 57 | 58 | file_1 = 'newstest2019.msft-WMT19-sentence-level.6785.en-de.txt' 59 | self.sub_1 = Submission.objects.create( 60 | name=file_1, 61 | test_set=testset, 62 | submitted_by=self.team_a, 63 | file_format=TEXT_FILE, 64 | hyp_file=os.path.join(TESTDATA_DIR, file_1), 65 | ) 66 | 67 | self.team_b = Team.objects.create( 68 | is_active=True, 69 | name='Team B', 70 | email='team-b@email.com', 71 | ) 72 | 73 | file_2 = 'newstest2019.msft-WMT19-sentence_document.6974.en-de.txt' 74 | self.sub_2 = Submission.objects.create( 75 | name=file_2, 76 | test_set=testset, 77 | submitted_by=self.team_b, 78 | file_format=TEXT_FILE, 79 | hyp_file=os.path.join(TESTDATA_DIR, file_2), 80 | ) 81 | 82 | session = self.client.session 83 | session['ocelot_team_token'] = self.team_a.token 84 | session.save() 85 | 86 | def test_non_public_submissions_cannot_be_compared(self): 87 | """Checks that submission/a/b/ do not render for submissions that are not public.""" 88 | self.sub_1.is_public = False # Note sub_1 is submitted by team_a 89 | self.sub_1.save() 90 | self.sub_2.is_public = False # Note sub_2 is submitted by team_b 91 | self.sub_2.save() 92 | response = self.client.get( 93 | '/submission/{0}/{1}'.format(self.sub_1.id, self.sub_2.id), 94 | follow=True, 95 | ) 96 | self.assertContains(response, 'cannot be compared') 97 | self.assertContains(response, 'must be public') 98 | 99 | def test_submissions_from_different_test_sets_cannot_be_compared(self): 100 | """Checks that submission/a/b/ do not render for submissions from different test sets.""" 101 | 102 | testset = TestSet.objects.create( 103 | is_active=True, 104 | name='AnotherTestSet', 105 | source_language=Language.objects.get(code='en'), 106 | target_language=Language.objects.get(code='de'), 107 | file_format=SGML_FILE, 108 | src_file=os.path.join( 109 | TESTDATA_DIR, 'newstest2019-ende-src.en.sgm' 110 | ), 111 | ref_file=os.path.join( 112 | TESTDATA_DIR, 'newstest2019-ende-ref.de.sgm' 113 | ), 114 | competition=self.competition, 115 | ) 116 | 117 | _file = 'newstest2019.msft-WMT19-sentence-level.6785.en-de.txt' 118 | sub_3 = Submission.objects.create( 119 | name=_file, 120 | test_set=testset, 121 | submitted_by=self.team_a, 122 | file_format=TEXT_FILE, 123 | hyp_file=os.path.join(TESTDATA_DIR, _file), 124 | is_public=True, 125 | ) 126 | 127 | self.sub_1.is_public = True 128 | self.sub_1.save() 129 | 130 | response = self.client.get( 131 | '/submission/{0}/{1}'.format(self.sub_1.id, sub_3.id), 132 | follow=True, 133 | ) 134 | self.assertContains(response, 'cannot be compared') 135 | self.assertContains(response, 'the same test set') 136 | 137 | def test_comparing_submissions_renders(self): 138 | """Checks that submission/a/b/ renders submission names and diff spans.""" 139 | self.sub_1.is_public = True 140 | self.sub_1.save() 141 | self.sub_2.is_public = True 142 | self.sub_2.save() 143 | response = self.client.get( 144 | '/submission/{0}/{1}'.format(self.sub_1.id, self.sub_2.id) 145 | ) 146 | self.assertContains(response, str(self.sub_1)) 147 | self.assertContains(response, str(self.sub_2)) 148 | self.assertContains(response, 'b c d e', 27 | 'a B c e f' 28 | """ 29 | if not text1 or not text2 or (text1 == text2): 30 | return (text1, text2) 31 | 32 | toks1 = list(text1) if char_based else text1.split() 33 | toks2 = list(text2) if char_based else text2.split() 34 | matcher = SequenceMatcher(None, toks1, toks2) 35 | 36 | sep = '' if char_based else ' ' 37 | 38 | text1 = '' 39 | text2 = '' 40 | # pylint: disable=invalid-name 41 | for tag, i1, i2, j1, j2 in matcher.get_opcodes(): 42 | if tag == 'equal': 43 | text1 += sep + sep.join(toks1[i1:i2]) 44 | text2 += sep + sep.join(toks2[j1:j2]) 45 | elif tag == 'replace': 46 | text1 += ( 47 | sep 48 | + '' 49 | + sep.join(toks1[i1:i2]) 50 | + '' 51 | ) 52 | text2 += ( 53 | sep 54 | + '' 55 | + sep.join(toks2[j1:j2]) 56 | + '' 57 | ) 58 | elif tag == 'insert': 59 | text2 += ( 60 | sep 61 | + '' 62 | + sep.join(toks2[j1:j2]) 63 | + '' 64 | ) 65 | elif tag == 'delete': 66 | text1 += ( 67 | sep 68 | + '' 69 | + sep.join(toks1[i1:i2]) 70 | + '' 71 | ) 72 | return (text1.strip(), text2.strip()) 73 | 74 | 75 | def submission(request, sub_id=None): 76 | """Shows submission output.""" 77 | 78 | try: 79 | sub = Submission.objects.get(id=sub_id) 80 | except Submission.DoesNotExist: 81 | raise Http404('Submission #{0} does not exist'.format(sub_id)) 82 | 83 | ( 84 | ocelot_team_name, 85 | ocelot_team_email, 86 | ocelot_team_token, 87 | ocelot_team_verified, 88 | ) = _get_team_data(request) 89 | 90 | # Submission must be public unless it's yours 91 | if sub.is_anonymous() and not sub.is_yours(ocelot_team_token): 92 | _msg = 'Submission #{0} is not public.'.format(sub_id) 93 | messages.warning(request, _msg) 94 | return HttpResponseRedirect('/') 95 | 96 | # A list of submissions which the current submission can be compared with 97 | _subs = Submission.objects.filter( 98 | test_set=sub.test_set, 99 | is_valid=True, # Ignore invalid submissions 100 | ).exclude(id=sub_id) 101 | 102 | compare_with = [ 103 | (sub.id, str(sub)) 104 | for sub in _subs 105 | # Exclude anonymous submissions that are not yours 106 | if not sub.is_anonymous() or sub.is_yours(ocelot_team_token) 107 | ] 108 | 109 | # Paginate 110 | data = list(zip(sub.get_src_text(), sub.get_hyp_text())) 111 | paginator = Paginator(data, SEGMENTS_PER_PAGE) 112 | page_num = request.GET.get('page', 1) 113 | page_data = paginator.get_page(page_num) 114 | 115 | context = { 116 | 'page': page_data, 117 | 'page_size': SEGMENTS_PER_PAGE, 118 | 'submission_id': sub.id, 119 | 'submission': str(sub), 120 | 'compare_with': compare_with, 121 | 'ocelot_team_name': ocelot_team_name, 122 | 'ocelot_team_email': ocelot_team_email, 123 | 'ocelot_team_token': ocelot_team_token, 124 | 'ocelot_team_verified': ocelot_team_verified, 125 | } 126 | return render(request, 'comparison/submission.html', context=context) 127 | 128 | 129 | def compare_submissions(request, sub_a_id=None, sub_b_id=None): 130 | """Renders vertical or horizontal comparison between two submissions.""" 131 | 132 | try: 133 | sub_a = Submission.objects.get(id=sub_a_id) 134 | sub_b = Submission.objects.get(id=sub_b_id) 135 | except Submission.DoesNotExist: 136 | raise Http404( 137 | 'Submission #{0} or #{1} does not exist'.format( 138 | sub_a_id, sub_b_id 139 | ) 140 | ) 141 | 142 | # Submissions from different test sets cannot be compared 143 | if sub_a.test_set != sub_b.test_set: 144 | _msg = ( 145 | 'Submissions #{0} and #{1} cannot be compared,'.format( 146 | sub_a_id, sub_b_id 147 | ) 148 | + ' because they do not belong to the same test set.' 149 | ) 150 | messages.warning(request, _msg) 151 | return HttpResponseRedirect('/') 152 | 153 | ( 154 | ocelot_team_name, 155 | ocelot_team_email, 156 | ocelot_team_token, 157 | ocelot_team_verified, 158 | ) = _get_team_data(request) 159 | 160 | # Submissions that are not public cannot be compared 161 | if ( 162 | sub_a.is_anonymous() and not sub_a.is_yours(ocelot_team_token) 163 | ) or (sub_b.is_anonymous() and not sub_b.is_yours(ocelot_team_token)): 164 | _msg = ( 165 | 'Submissions #{0} and #{1} cannot be compared.'.format( 166 | sub_a_id, sub_b_id 167 | ) 168 | + ' Both submission outputs must be public.' 169 | ) 170 | messages.warning(request, _msg) 171 | return HttpResponseRedirect('/') 172 | 173 | text1 = sub_a.get_hyp_text() 174 | text2 = sub_b.get_hyp_text() 175 | data = [] 176 | # TODO: Annotate with span diffs only the current page 177 | for sent1, sent2 in zip(text1, text2): 178 | data.append(_annotate_texts_with_span_diffs(sent1, sent2)) 179 | 180 | # Paginate 181 | paginator = Paginator(data, SEGMENTS_PER_PAGE) 182 | page_num = request.GET.get('page', 1) 183 | page_data = paginator.get_page(page_num) 184 | 185 | context = { 186 | 'page': page_data, 187 | 'page_size': SEGMENTS_PER_PAGE, 188 | 'submission_a': str(sub_a), 189 | 'submission_b': str(sub_b), 190 | 'ocelot_team_name': ocelot_team_name, 191 | 'ocelot_team_email': ocelot_team_email, 192 | 'ocelot_team_token': ocelot_team_token, 193 | 'ocelot_team_verified': ocelot_team_verified, 194 | # 'comparison_options': [(0, '...'), (1, 'A>B'), (2, 'A /etc/apt/sources.list.d/pgdg.list' 8 | apt-get update 9 | apt-get install -y postgresql-14 10 | fi 11 | -------------------------------------------------------------------------------- /leaderboard/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Project OCELoT: Open, Competitive Evaluation Leaderboard of Translations 3 | """ 4 | -------------------------------------------------------------------------------- /leaderboard/admin.py: -------------------------------------------------------------------------------- 1 | """ 2 | Project OCELoT: Open, Competitive Evaluation Leaderboard of Translations 3 | """ 4 | import json 5 | from pathlib import Path 6 | from tempfile import NamedTemporaryFile 7 | from zipfile import ZIP_DEFLATED 8 | from zipfile import ZipFile 9 | 10 | from django.contrib import admin 11 | from django.forms.models import model_to_dict 12 | from django.http import FileResponse 13 | 14 | from leaderboard.models import Competition 15 | from leaderboard.models import Language 16 | from leaderboard.models import Submission 17 | from leaderboard.models import Team 18 | from leaderboard.models import TestSet 19 | 20 | 21 | def _make_submission_filename(submission): 22 | """Creates a readable filename for a submission.""" 23 | publication_name = submission.submitted_by.publication_name 24 | if not submission.submitted_by.publication_name: 25 | publication_name = submission.name 26 | 27 | file_extension = submission.hyp_file.name.split('.')[-1] 28 | 29 | filename = 'submissions/{0}.{1}-{2}.{3}.{4}.{5}'.format( 30 | submission.test_set.name, 31 | submission.test_set.source_language.code, 32 | submission.test_set.target_language.code, 33 | publication_name, 34 | submission.id, 35 | file_extension, 36 | ) 37 | return filename.replace(' ', '_').lower() 38 | 39 | 40 | def download_submission_files(modeladmin, request, queryset): 41 | """Creates zip file with all XML, SGML or text files for queryset.""" 42 | del modeladmin # unused 43 | del request # unused 44 | 45 | tmp_file = NamedTemporaryFile(delete=False) 46 | with ZipFile(tmp_file, 'w', ZIP_DEFLATED) as zip_file: 47 | for submission in queryset: 48 | new_filename = _make_submission_filename(submission) 49 | zip_file.writestr( 50 | Path(new_filename).name, 51 | submission.hyp_file.open('rb').read(), 52 | ) 53 | 54 | tmp_file.seek(0) 55 | response = FileResponse( 56 | open(tmp_file.name, 'rb'), 57 | as_attachment=True, 58 | content_type='application/x-zip-compressed', 59 | filename='submissions.zip', 60 | ) 61 | return response 62 | 63 | 64 | download_submission_files.short_description = ( # type: ignore 65 | "Download XML, SGML or text files for selected submissions" 66 | ) 67 | 68 | 69 | def download_testset_files(modeladmin, request, queryset): 70 | """Creates zip file with all XML, SGML or text files for queryset.""" 71 | del modeladmin # unused 72 | del request # unused 73 | 74 | tmp_file = NamedTemporaryFile(delete=False) 75 | with ZipFile(tmp_file, 'w', ZIP_DEFLATED) as zip_file: 76 | for test_set in queryset: 77 | for the_file in (test_set.src_file, test_set.ref_file): 78 | file_extension = the_file.name.split('.')[-1] 79 | 80 | file_type = 'src' 81 | if the_file == test_set.ref_file: 82 | file_type = 'ref' 83 | 84 | new_filename = 'testsets/{0}.{1}-{2}.{3}.{4}'.format( 85 | test_set.name, 86 | test_set.source_language.code, 87 | test_set.target_language.code, 88 | file_type, 89 | file_extension, 90 | ) 91 | new_filename.replace(' ', '_').lower() 92 | 93 | zip_file.writestr( 94 | Path(new_filename).name, 95 | the_file.open('rb').read(), 96 | ) 97 | 98 | tmp_file.seek(0) 99 | response = FileResponse( 100 | open(tmp_file.name, 'rb'), 101 | as_attachment=True, 102 | content_type='application/x-zip-compressed', 103 | filename='testsets.zip', 104 | ) 105 | return response 106 | 107 | 108 | download_testset_files.short_description = ( # type: ignore 109 | "Download XML, SGML or text files for selected test sets" 110 | ) 111 | 112 | 113 | class LanguageAdmin(admin.ModelAdmin): 114 | """Model admin for Language objects.""" 115 | 116 | fields = ['code', 'name'] 117 | 118 | ordering = ('name',) 119 | 120 | 121 | class SubmissionAdmin(admin.ModelAdmin): 122 | """Model admin for Submission objects.""" 123 | 124 | actions = [download_submission_files, download_testset_files] 125 | 126 | fields = [ 127 | 'name', 128 | 'test_set', 129 | 'file_format', 130 | 'hyp_file', 131 | 'submitted_by', 132 | 'is_constrained', 133 | 'is_open_source', 134 | 'is_contrastive', 135 | 'is_flagged', 136 | 'is_primary', 137 | 'is_public', 138 | 'is_removed', 139 | 'is_valid', 140 | 'is_withdrawn', 141 | 'score', 142 | 'score_chrf', 143 | ] 144 | 145 | list_display = [ 146 | '__str__', 147 | '_team_name', 148 | 'submitted_by', 149 | 'test_set', 150 | '_source_language', 151 | '_target_language', 152 | 'file_format', 153 | '_score', 154 | '_chrf', 155 | 'date_created', 156 | ] 157 | 158 | list_filter = [ 159 | 'test_set', 160 | 'test_set__source_language', 161 | 'test_set__target_language', 162 | 'submitted_by__publication_name', 163 | 'file_format', 164 | 'is_constrained', 165 | 'is_contrastive', 166 | 'is_flagged', 167 | 'is_primary', 168 | 'is_public', 169 | 'is_removed', 170 | 'is_valid', 171 | 'is_withdrawn', 172 | ] 173 | 174 | ordering = ( 175 | 'test_set__name', 176 | 'test_set__source_language__code', 177 | 'test_set__target_language__code', 178 | '-score_chrf', 179 | '-date_created', 180 | ) 181 | 182 | 183 | def download_team_file(modeladmin, request, queryset): 184 | """Creates JSON file with team information for queryset.""" 185 | del modeladmin # unused 186 | del request # unused 187 | 188 | team_json = _create_team_json(queryset) 189 | 190 | tmp_file = NamedTemporaryFile(delete=False) 191 | with ZipFile(tmp_file, 'w', ZIP_DEFLATED) as zip_file: 192 | zip_file.writestr('teams.json', team_json) 193 | 194 | tmp_file.seek(0) 195 | response = FileResponse( 196 | open(tmp_file.name, 'rb'), 197 | as_attachment=True, 198 | content_type='application/x-zip-compressed', 199 | filename='teams.zip', 200 | ) 201 | return response 202 | 203 | def _create_team_json(queryset): 204 | """Creates JSON file with team information""" 205 | team_list = [] 206 | for team in queryset: 207 | team_data = model_to_dict( 208 | team, 209 | fields=[ 210 | 'description', 211 | 'email', 212 | 'institution_name', 213 | 'name', 214 | 'publication_name', 215 | 'publication_url', 216 | ], 217 | ) 218 | 219 | primary_submissions = team.submission_set.filter( 220 | is_primary=True, is_valid=True 221 | ) 222 | team_data['number_of_primary_submissions'] = len(primary_submissions) 223 | 224 | submission_list = [] 225 | for submission in primary_submissions: 226 | submission_data = model_to_dict( 227 | submission, 228 | fields=[ 229 | 'is_constrained', 230 | 'is_open_source', 231 | 'is_primary', 232 | 'is_removed', 233 | 'score', 234 | 'score_chrf', 235 | ], 236 | ) 237 | submission_data['competition'] = submission.test_set.competition.name 238 | submission_data['file_name'] = _make_submission_filename(submission) 239 | submission_data['submission_id'] = submission.id 240 | submission_data['test_set'] = submission.test_set.name 241 | language_pair = "{0}-{1}".format( 242 | submission.test_set.source_language.code, 243 | submission.test_set.target_language.code, 244 | ) 245 | submission_data['language_pair'] = language_pair 246 | submission_list.append(submission_data) 247 | team_data['primary_submissions'] = submission_list 248 | 249 | team_list.append(team_data) 250 | team_json = json.dumps(list(team_list), indent=2, sort_keys=True) 251 | return team_json 252 | 253 | 254 | download_team_file.short_description = ( # type: ignore 255 | "Download JSON file with primary submissions for selected teams" 256 | ) 257 | 258 | 259 | class TeamAdmin(admin.ModelAdmin): 260 | """Model admin for Team objects.""" 261 | 262 | actions = [download_team_file] 263 | 264 | fields = [ 265 | 'name', 266 | 'email', 267 | 'token', 268 | 'publication_name', 269 | 'is_active', 270 | 'is_flagged', 271 | 'is_removed', 272 | 'is_verified', 273 | ] 274 | 275 | list_display = [ 276 | '__str__', 277 | 'email', 278 | 'token', 279 | 'is_verified', 280 | '_submissions', 281 | '_primary_submissions', 282 | ] 283 | 284 | list_filter = [ 285 | 'is_active', 286 | 'is_flagged', 287 | 'is_removed', 288 | 'is_verified', 289 | ] 290 | 291 | search_fields = ['name', 'email', 'token'] 292 | 293 | ordering = ('name',) 294 | 295 | 296 | class TestSetAdmin(admin.ModelAdmin): 297 | """Model admin for TestSet objects.""" 298 | 299 | fields = [ 300 | 'name', 301 | 'source_language', 302 | 'target_language', 303 | 'file_format', 304 | 'src_file', 305 | 'ref_file', 306 | 'collection', 307 | 'competition', 308 | 'is_active', 309 | 'is_public', 310 | 'compute_scores', 311 | ] 312 | 313 | list_display = [ 314 | '__str__', 315 | 'source_language', 316 | 'target_language', 317 | 'competition', 318 | ] 319 | 320 | list_filter = [ 321 | 'is_active', 322 | 'is_public', 323 | 'compute_scores', 324 | 'file_format', 325 | 'competition', 326 | ] 327 | 328 | ordering = ('-name', 'source_language', 'target_language') 329 | 330 | 331 | class CompetitionAdmin(admin.ModelAdmin): 332 | """Model admin for Competition objects.""" 333 | 334 | fields = [ 335 | 'name', 336 | 'description', 337 | 'start_time', 338 | 'deadline', 339 | 'is_active', 340 | 'is_public', 341 | ] 342 | 343 | list_display = [ 344 | '__str__', 345 | 'start_time', 346 | 'deadline', 347 | ] 348 | 349 | list_filter = [ 350 | 'is_active', 351 | 'is_public', 352 | ] 353 | 354 | ordering = ('-name',) 355 | 356 | 357 | admin.site.register(Language, LanguageAdmin) 358 | admin.site.register(Submission, SubmissionAdmin) 359 | admin.site.register(Team, TeamAdmin) 360 | admin.site.register(TestSet, TestSetAdmin) 361 | admin.site.register(Competition, CompetitionAdmin) 362 | -------------------------------------------------------------------------------- /leaderboard/apps.py: -------------------------------------------------------------------------------- 1 | """ 2 | Project OCELoT: Open, Competitive Evaluation Leaderboard of Translations 3 | """ 4 | from django.apps import AppConfig 5 | 6 | 7 | class LeaderboardConfig(AppConfig): 8 | """OCELoT leaderboard app Configuration""" 9 | 10 | name = 'leaderboard' 11 | -------------------------------------------------------------------------------- /leaderboard/forms.py: -------------------------------------------------------------------------------- 1 | """ 2 | Project OCELoT: Open, Competitive Evaluation Leaderboard of Translations 3 | """ 4 | from datetime import datetime 5 | 6 | from django import forms 7 | from django.utils import timezone 8 | 9 | from leaderboard.models import FILE_FORMAT_CHOICES 10 | from leaderboard.models import MAX_DESCRIPTION_LENGTH 11 | from leaderboard.models import MAX_NAME_LENGTH 12 | from leaderboard.models import MAX_TOKEN_LENGTH 13 | from leaderboard.models import Submission 14 | from leaderboard.models import Team 15 | from leaderboard.models import TestSet 16 | from leaderboard.models import validate_institution_name 17 | from leaderboard.models import validate_publication_name 18 | from leaderboard.models import validate_token 19 | 20 | 21 | PLACEHOLDER_FOR_DESCRIPTION = """TEAM-ONE submission is a standard Transformer 22 | model equipped with our recent technique of problem obfuscation 23 | \\citep{obfuscation:2023}. The best improvement was achieved thanks to doubly 24 | obfuscating both source and target side and mixing in our manually obfuscated 25 | set of examples. 26 | 27 | @inproceedings{obfuscation:2023, 28 | title = {Amazing Obfuscation of NMT Problems}, 29 | author = ... 30 | }""" 31 | 32 | 33 | class PublicationNameForm(forms.Form): 34 | """Form used for teampage view. 35 | 36 | Based on forms.Form as we don't want to create a new Team. 37 | """ 38 | 39 | institution_name = forms.CharField( 40 | max_length=MAX_NAME_LENGTH, 41 | validators=[validate_institution_name], 42 | widget=forms.TextInput( 43 | attrs={ 44 | 'class': 'form-control', 45 | 'placeholder': r'Institution Team \textsc{ONE}', 46 | } 47 | ), 48 | label='Institution name', 49 | ) 50 | publication_name = forms.CharField( 51 | max_length=MAX_NAME_LENGTH, 52 | validators=[validate_publication_name], 53 | widget=forms.TextInput( 54 | attrs={'class': 'form-control', 'placeholder': 'TEAM-ONE'} 55 | ), 56 | label='Short team name for the publication', 57 | ) 58 | 59 | 60 | class PublicationDescriptionForm(forms.Form): 61 | """Form used for teampage view. 62 | 63 | Based on forms.Form as we don't want to create a new Team. 64 | """ 65 | 66 | publication_url = forms.CharField( 67 | max_length=MAX_NAME_LENGTH, 68 | widget=forms.TextInput( 69 | attrs={ 70 | 'class': 'form-control', 71 | 'placeholder': 'John Doe, Jack Smith: TeamOneMT at Translation Task', 72 | } 73 | ), 74 | label='System paper', 75 | ) 76 | description = forms.CharField( 77 | max_length=MAX_DESCRIPTION_LENGTH, 78 | widget=forms.Textarea( 79 | attrs={ 80 | 'class': 'form-control', 81 | 'rows': 7, 82 | 'placeholder': PLACEHOLDER_FOR_DESCRIPTION, 83 | } 84 | ), 85 | label='Paragraph for the overview paper', 86 | ) 87 | 88 | 89 | class SigninForm(forms.Form): 90 | """Form used for sign-in view. 91 | 92 | Based on forms.Form as we don't want to create a new Team. 93 | """ 94 | 95 | name = forms.CharField( 96 | label='Team name', 97 | max_length=MAX_NAME_LENGTH, 98 | widget=forms.TextInput(attrs={'class': 'form-control'}), 99 | ) 100 | email = forms.EmailField( 101 | label='E-mail', 102 | widget=forms.EmailInput(attrs={'class': 'form-control'}), 103 | ) 104 | token = forms.CharField( 105 | label='Token', 106 | max_length=MAX_TOKEN_LENGTH, 107 | validators=[validate_token], 108 | widget=forms.PasswordInput(attrs={'class': 'form-control'}), 109 | ) 110 | 111 | 112 | class SubmissionForm(forms.ModelForm): 113 | """Form used for submission view.""" 114 | 115 | # Prevent submissions to inactive test sets and test sets from inactive 116 | # competitions by not showing them as available choices in the submission form. 117 | # 118 | # Support competitions with no deadline or start time. Note that lazy 119 | # querysets should take care of combining OR filters into a single query. 120 | # 121 | # TODO: Consider showing competition + test set in the select box, not just 122 | # the test set name 123 | test_set = forms.ModelChoiceField( 124 | queryset=TestSet.objects.filter( 125 | is_active=True, 126 | competition__is_active=True, 127 | competition__deadline__gt=datetime.now(tz=timezone.utc), 128 | competition__start_time__lt=datetime.now(tz=timezone.utc), 129 | ) 130 | | TestSet.objects.filter( 131 | is_active=True, 132 | competition__is_active=True, 133 | competition__deadline__isnull=True, 134 | competition__start_time__lt=datetime.now(tz=timezone.utc), 135 | ) 136 | | TestSet.objects.filter( 137 | is_active=True, 138 | competition__is_active=True, 139 | competition__deadline__gt=datetime.now(tz=timezone.utc), 140 | competition__start_time__isnull=True, 141 | ) 142 | | TestSet.objects.filter( 143 | is_active=True, 144 | competition__is_active=True, 145 | competition__deadline__isnull=True, 146 | competition__start_time__isnull=True, 147 | ), 148 | widget=forms.Select(attrs={'class': 'form-control'}), 149 | ) 150 | 151 | hyp_file = forms.FileField( 152 | widget=forms.FileInput( 153 | attrs={'class': 'form-control form-control-file'}, 154 | ), 155 | help_text="XML file containing submission output", 156 | ) 157 | 158 | class Meta: # pylint: disable=too-few-public-methods,missing-docstring 159 | model = Submission 160 | fields = ['test_set', 'hyp_file', 'is_primary'] 161 | 162 | 163 | class TeamForm(forms.ModelForm): 164 | """Form used for team signup view.""" 165 | 166 | class Meta: # pylint: disable=too-few-public-methods,missing-docstring 167 | model = Team 168 | fields = ['name', 'email'] 169 | widgets = { 170 | 'name': forms.TextInput(attrs={'class': 'form-control'}), 171 | 'email': forms.TextInput(attrs={'class': 'form-control'}), 172 | } 173 | -------------------------------------------------------------------------------- /leaderboard/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=invalid-name,missing-docstring 2 | # Generated by Django 2.1.5 on 2019-05-29 21:48 3 | from typing import List 4 | from typing import Tuple 5 | 6 | from django.db import migrations 7 | from django.db import models 8 | 9 | 10 | class Migration(migrations.Migration): 11 | initial = True 12 | 13 | dependencies = [] # type: List[Tuple[str, str]] 14 | 15 | operations = [ 16 | migrations.CreateModel( 17 | name='Language', 18 | fields=[ 19 | ( 20 | 'id', 21 | models.AutoField( 22 | auto_created=True, 23 | primary_key=True, 24 | serialize=False, 25 | verbose_name='ID', 26 | ), 27 | ), 28 | ( 29 | 'code', 30 | models.CharField( 31 | db_index=True, 32 | help_text='ISO 639 code (max 10 characters)', 33 | max_length=10, 34 | ), 35 | ), 36 | ( 37 | 'name', 38 | models.CharField( 39 | db_index=True, 40 | help_text='Test set name (max 200 characters)', 41 | max_length=200, 42 | ), 43 | ), 44 | ], 45 | ), 46 | migrations.CreateModel( 47 | name='TestSet', 48 | fields=[ 49 | ( 50 | 'id', 51 | models.AutoField( 52 | auto_created=True, 53 | primary_key=True, 54 | serialize=False, 55 | verbose_name='ID', 56 | ), 57 | ), 58 | ( 59 | 'name', 60 | models.CharField( 61 | db_index=True, 62 | help_text='Test set name (max 200 characters)', 63 | max_length=200, 64 | ), 65 | ), 66 | ], 67 | ), 68 | ] 69 | -------------------------------------------------------------------------------- /leaderboard/migrations/0002_testset_json_data.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=invalid-name,missing-docstring 2 | # Generated by Django 2.2.1 on 2019-08-28 13:47 3 | from django.db import migrations 4 | from django.db import models 5 | 6 | 7 | class Migration(migrations.Migration): 8 | dependencies = [('leaderboard', '0001_initial')] 9 | 10 | operations = [ 11 | migrations.AddField( 12 | model_name='testset', 13 | name='json_data', 14 | field=models.TextField( 15 | help_text='JSON data for test set', null=True 16 | ), 17 | ) 18 | ] 19 | -------------------------------------------------------------------------------- /leaderboard/migrations/0003_submission.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=invalid-name,missing-docstring 2 | # Generated by Django 2.2.1 on 2019-08-31 07:47 3 | import django.db.models.deletion 4 | from django.db import migrations 5 | from django.db import models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | dependencies = [('leaderboard', '0002_testset_json_data')] 10 | 11 | operations = [ 12 | migrations.CreateModel( 13 | name='Submission', 14 | fields=[ 15 | ( 16 | 'id', 17 | models.AutoField( 18 | auto_created=True, 19 | primary_key=True, 20 | serialize=False, 21 | verbose_name='ID', 22 | ), 23 | ), 24 | ( 25 | 'name', 26 | models.CharField( 27 | db_index=True, 28 | help_text='Test set name (max 200 characters)', 29 | max_length=200, 30 | ), 31 | ), 32 | ( 33 | 'test_set', 34 | models.ForeignKey( 35 | on_delete=django.db.models.deletion.PROTECT, 36 | to='leaderboard.TestSet', 37 | ), 38 | ), 39 | ], 40 | ) 41 | ] 42 | -------------------------------------------------------------------------------- /leaderboard/migrations/0004_auto_20190831_0113.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=invalid-name,missing-docstring 2 | # Generated by Django 2.2.1 on 2019-08-31 08:13 3 | from django.db import migrations 4 | from django.db import models 5 | 6 | 7 | class Migration(migrations.Migration): 8 | dependencies = [('leaderboard', '0003_submission')] 9 | 10 | operations = [ 11 | migrations.AddField( 12 | model_name='submission', 13 | name='is_primary', 14 | field=models.BooleanField( 15 | db_index=True, 16 | default=False, 17 | help_text='Is primary sumission?', 18 | ), 19 | ), 20 | migrations.AddField( 21 | model_name='submission', 22 | name='score', 23 | field=models.FloatField( 24 | blank=True, 25 | db_index=True, 26 | help_text='SacreBLEU score', 27 | null=True, 28 | ), 29 | ), 30 | migrations.AddField( 31 | model_name='submission', 32 | name='sgml_file', 33 | field=models.FileField( 34 | help_text='SGML file containing submission output', 35 | null=True, 36 | upload_to='submissions', 37 | ), 38 | ), 39 | ] 40 | -------------------------------------------------------------------------------- /leaderboard/migrations/0005_auto_20200618_2157.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=invalid-name,missing-docstring 2 | # Generated by Django 2.2.1 on 2020-06-19 04:57 3 | import django.db.models.deletion 4 | from django.db import migrations 5 | from django.db import models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | dependencies = [('leaderboard', '0004_auto_20190831_0113')] 10 | 11 | operations = [ 12 | migrations.RemoveField(model_name='testset', name='json_data'), 13 | migrations.AddField( 14 | model_name='testset', 15 | name='sgml_file', 16 | field=models.FileField( 17 | help_text='SGML file containing test set', 18 | null=True, 19 | upload_to='testsets', 20 | ), 21 | ), 22 | migrations.AddField( 23 | model_name='testset', 24 | name='source_language', 25 | field=models.ForeignKey( 26 | null=True, 27 | on_delete=django.db.models.deletion.PROTECT, 28 | related_name='source_language_set', 29 | to='leaderboard.Language', 30 | ), 31 | ), 32 | migrations.AddField( 33 | model_name='testset', 34 | name='target_language', 35 | field=models.ForeignKey( 36 | null=True, 37 | on_delete=django.db.models.deletion.PROTECT, 38 | related_name='target_language_set', 39 | to='leaderboard.Language', 40 | ), 41 | ), 42 | ] 43 | -------------------------------------------------------------------------------- /leaderboard/migrations/0006_auto_20200618_2204.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=invalid-name,missing-docstring 2 | # Generated by Django 2.2.1 on 2020-06-19 05:04 3 | from django.db import migrations 4 | from django.db import models 5 | 6 | 7 | class Migration(migrations.Migration): 8 | dependencies = [('leaderboard', '0005_auto_20200618_2157')] 9 | 10 | operations = [ 11 | migrations.RemoveField(model_name='testset', name='sgml_file'), 12 | migrations.AddField( 13 | model_name='testset', 14 | name='ref_sgml_file', 15 | field=models.FileField( 16 | help_text='SGML file containing test set reference text', 17 | null=True, 18 | upload_to='testsets', 19 | ), 20 | ), 21 | migrations.AddField( 22 | model_name='testset', 23 | name='src_sgml_file', 24 | field=models.FileField( 25 | help_text='SGML file containing test set source text', 26 | null=True, 27 | upload_to='testsets', 28 | ), 29 | ), 30 | ] 31 | -------------------------------------------------------------------------------- /leaderboard/migrations/0007_submission_is_public.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=invalid-name,missing-docstring 2 | # Generated by Django 2.2.1 on 2020-06-19 05:29 3 | from django.db import migrations 4 | from django.db import models 5 | 6 | 7 | class Migration(migrations.Migration): 8 | dependencies = [('leaderboard', '0006_auto_20200618_2204')] 9 | 10 | operations = [ 11 | migrations.AddField( 12 | model_name='submission', 13 | name='is_public', 14 | field=models.BooleanField( 15 | db_index=True, 16 | default=False, 17 | help_text='Is publicly visible?', 18 | ), 19 | ) 20 | ] 21 | -------------------------------------------------------------------------------- /leaderboard/migrations/0008_team.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=invalid-name,missing-docstring 2 | # Generated by Django 2.2.1 on 2020-06-19 06:05 3 | from django.db import migrations 4 | from django.db import models 5 | 6 | 7 | class Migration(migrations.Migration): 8 | dependencies = [('leaderboard', '0007_submission_is_public')] 9 | 10 | operations = [ 11 | migrations.CreateModel( 12 | name='Team', 13 | fields=[ 14 | ( 15 | 'id', 16 | models.AutoField( 17 | auto_created=True, 18 | primary_key=True, 19 | serialize=False, 20 | verbose_name='ID', 21 | ), 22 | ), 23 | ( 24 | 'is_active', 25 | models.BooleanField( 26 | db_index=True, 27 | default=False, 28 | help_text='Is active team?', 29 | ), 30 | ), 31 | ( 32 | 'is_verified', 33 | models.BooleanField( 34 | db_index=True, 35 | default=False, 36 | help_text='Is verified team?', 37 | ), 38 | ), 39 | ( 40 | 'name', 41 | models.CharField( 42 | db_index=True, 43 | help_text='Team name (max 200 characters)', 44 | max_length=200, 45 | ), 46 | ), 47 | ( 48 | 'email', 49 | models.EmailField( 50 | db_index=True, 51 | help_text='Team email', 52 | max_length=200, 53 | ), 54 | ), 55 | ( 56 | 'token', 57 | models.CharField( 58 | db_index=True, default='d5fad58bcd', max_length=10 59 | ), 60 | ), 61 | ], 62 | ) 63 | ] 64 | -------------------------------------------------------------------------------- /leaderboard/migrations/0009_auto_20200618_2345.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=invalid-name,missing-docstring 2 | # Generated by Django 2.2.1 on 2020-06-19 06:45 3 | from django.db import migrations 4 | from django.db import models 5 | 6 | 7 | class Migration(migrations.Migration): 8 | dependencies = [('leaderboard', '0008_team')] 9 | 10 | operations = [ 11 | migrations.AddField( 12 | model_name='submission', 13 | name='date_created', 14 | field=models.DateTimeField( 15 | auto_now_add=True, 16 | help_text='Creation date of this submission', 17 | null=True, 18 | ), 19 | ), 20 | migrations.AlterField( 21 | model_name='submission', 22 | name='name', 23 | field=models.CharField( 24 | db_index=True, 25 | help_text='Submission name (max 200 characters)', 26 | max_length=200, 27 | ), 28 | ), 29 | migrations.AlterField( 30 | model_name='team', 31 | name='token', 32 | field=models.CharField( 33 | blank=True, db_index=True, max_length=10 34 | ), 35 | ), 36 | ] 37 | -------------------------------------------------------------------------------- /leaderboard/migrations/0010_testset_is_active.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=invalid-name,missing-docstring 2 | # Generated by Django 2.2.13 on 2020-06-22 19:53 3 | from django.db import migrations 4 | from django.db import models 5 | 6 | 7 | class Migration(migrations.Migration): 8 | dependencies = [('leaderboard', '0009_auto_20200618_2345')] 9 | 10 | operations = [ 11 | migrations.AddField( 12 | model_name='testset', 13 | name='is_active', 14 | field=models.BooleanField( 15 | db_index=True, 16 | default=False, 17 | help_text='Is active test set?', 18 | ), 19 | ) 20 | ] 21 | -------------------------------------------------------------------------------- /leaderboard/migrations/0011_auto_20200622_2334.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=invalid-name,missing-docstring 2 | # Generated by Django 2.2.13 on 2020-06-23 06:34 3 | from django.db import migrations 4 | from django.db import models 5 | 6 | import leaderboard.models 7 | 8 | 9 | class Migration(migrations.Migration): 10 | dependencies = [('leaderboard', '0010_testset_is_active')] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='team', 15 | name='name', 16 | field=models.CharField( 17 | db_index=True, 18 | help_text='Team name (max 32 characters)', 19 | max_length=200, 20 | unique=True, 21 | validators=[leaderboard.models.validate_team_name], 22 | ), 23 | ), 24 | migrations.AlterField( 25 | model_name='team', 26 | name='token', 27 | field=models.CharField( 28 | blank=True, db_index=True, max_length=10, unique=True 29 | ), 30 | ), 31 | ] 32 | -------------------------------------------------------------------------------- /leaderboard/migrations/0012_auto_20200623_1629.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=invalid-name,missing-docstring,protected-access 2 | # Generated by Django 2.2.13 on 2020-06-23 23:29 3 | import django.db.models.deletion 4 | from django.db import migrations 5 | from django.db import models 6 | 7 | import leaderboard.models 8 | 9 | 10 | class Migration(migrations.Migration): 11 | dependencies = [('leaderboard', '0011_auto_20200622_2334')] 12 | 13 | operations = [ 14 | migrations.AddField( 15 | model_name='submission', 16 | name='original_name', 17 | field=models.CharField( 18 | default='undefined', 19 | editable=False, 20 | help_text='Original file name (max 200 characters)', 21 | max_length=200, 22 | ), 23 | preserve_default=False, 24 | ), 25 | migrations.AddField( 26 | model_name='submission', 27 | name='submitted_by', 28 | field=models.ForeignKey( 29 | blank=True, 30 | null=True, 31 | on_delete=django.db.models.deletion.PROTECT, 32 | to='leaderboard.Team', 33 | ), 34 | ), 35 | migrations.AlterField( 36 | model_name='submission', 37 | name='sgml_file', 38 | field=models.FileField( 39 | help_text='SGML file containing submission output', 40 | null=True, 41 | upload_to=leaderboard.models._get_submission_upload_path, 42 | ), 43 | ), 44 | ] 45 | -------------------------------------------------------------------------------- /leaderboard/migrations/0013_auto_20200623_1928.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=invalid-name,missing-docstring 2 | # Generated by Django 2.2.13 on 2020-06-24 02:28 3 | from django.db import migrations 4 | from django.db import models 5 | 6 | import leaderboard.models 7 | 8 | 9 | class Migration(migrations.Migration): 10 | dependencies = [('leaderboard', '0012_auto_20200623_1629')] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='team', 15 | name='token', 16 | field=models.CharField( 17 | blank=True, 18 | db_index=True, 19 | max_length=10, 20 | unique=True, 21 | validators=[leaderboard.models.validate_token], 22 | ), 23 | ) 24 | ] 25 | -------------------------------------------------------------------------------- /leaderboard/migrations/0014_submission_score_chrf.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=invalid-name,missing-docstring 2 | # Generated by Django 2.2.13 on 2020-06-25 15:41 3 | from django.db import migrations 4 | from django.db import models 5 | 6 | 7 | class Migration(migrations.Migration): 8 | dependencies = [ 9 | ('leaderboard', '0013_auto_20200623_1928'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='submission', 15 | name='score_chrf', 16 | field=models.FloatField( 17 | blank=True, 18 | db_index=True, 19 | help_text='chrF score', 20 | null=True, 21 | ), 22 | ), 23 | ] 24 | -------------------------------------------------------------------------------- /leaderboard/migrations/0015_auto_20200626_1341.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=invalid-name,missing-docstring,protected-access 2 | # Generated by Django 2.2.13 on 2020-06-26 20:41 3 | from django.db import migrations 4 | from django.db import models 5 | 6 | import leaderboard.models 7 | 8 | 9 | class Migration(migrations.Migration): 10 | dependencies = [ 11 | ('leaderboard', '0014_submission_score_chrf'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='team', 17 | name='is_flagged', 18 | field=models.BooleanField( 19 | db_index=True, default=False, help_text='Is flagged?' 20 | ), 21 | ), 22 | migrations.AddField( 23 | model_name='team', 24 | name='is_removed', 25 | field=models.BooleanField( 26 | db_index=True, default=False, help_text='Is removed?' 27 | ), 28 | ), 29 | migrations.AlterField( 30 | model_name='submission', 31 | name='sgml_file', 32 | field=models.FileField( 33 | help_text='SGML file containing submission output', 34 | null=True, 35 | upload_to=leaderboard.models._get_submission_upload_path, 36 | validators=[leaderboard.models.validate_sgml_schema], 37 | ), 38 | ), 39 | migrations.AlterField( 40 | model_name='team', 41 | name='is_active', 42 | field=models.BooleanField( 43 | db_index=True, default=False, help_text='Is active?' 44 | ), 45 | ), 46 | migrations.AlterField( 47 | model_name='team', 48 | name='is_verified', 49 | field=models.BooleanField( 50 | db_index=True, default=False, help_text='Is verified?' 51 | ), 52 | ), 53 | ] 54 | -------------------------------------------------------------------------------- /leaderboard/migrations/0016_auto_20200626_1402.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=invalid-name,missing-docstring 2 | # Generated by Django 2.2.13 on 2020-06-26 21:02 3 | from django.db import migrations 4 | from django.db import models 5 | 6 | 7 | class Migration(migrations.Migration): 8 | dependencies = [ 9 | ('leaderboard', '0015_auto_20200626_1341'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='submission', 15 | name='is_flagged', 16 | field=models.BooleanField( 17 | db_index=True, default=False, help_text='Is flagged?' 18 | ), 19 | ), 20 | migrations.AddField( 21 | model_name='submission', 22 | name='is_removed', 23 | field=models.BooleanField( 24 | db_index=True, default=False, help_text='Is removed?' 25 | ), 26 | ), 27 | ] 28 | -------------------------------------------------------------------------------- /leaderboard/migrations/0017_submission_is_constrained.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=invalid-name,missing-docstring 2 | # Generated by Django 2.2.13 on 2020-07-01 18:52 3 | from django.db import migrations 4 | from django.db import models 5 | 6 | 7 | class Migration(migrations.Migration): 8 | dependencies = [ 9 | ('leaderboard', '0016_auto_20200626_1402'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='submission', 15 | name='is_constrained', 16 | field=models.BooleanField( 17 | db_index=True, 18 | default=False, 19 | help_text='Is constrained sumission?', 20 | ), 21 | ), 22 | ] 23 | -------------------------------------------------------------------------------- /leaderboard/migrations/0018_team_publication_name.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=invalid-name,missing-docstring 2 | # Generated by Django 2.2.13 on 2020-07-02 04:19 3 | from django.db import migrations 4 | from django.db import models 5 | 6 | import leaderboard.models 7 | 8 | 9 | class Migration(migrations.Migration): 10 | dependencies = [ 11 | ('leaderboard', '0017_submission_is_constrained'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='team', 17 | name='publication_name', 18 | field=models.CharField( 19 | blank=True, 20 | db_index=True, 21 | help_text='Team publication name (max 32 characters)', 22 | max_length=200, 23 | validators=[leaderboard.models.validate_team_name], 24 | ), 25 | ), 26 | ] 27 | -------------------------------------------------------------------------------- /leaderboard/migrations/0019_auto_20200710_2037.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=invalid-name,missing-docstring 2 | # Generated by Django 2.2.13 on 2020-07-10 20:37 3 | from django.db import migrations 4 | from django.db import models 5 | 6 | 7 | class Migration(migrations.Migration): 8 | dependencies = [ 9 | ('leaderboard', '0018_team_publication_name'), 10 | ] 11 | 12 | operations = [ 13 | migrations.RenameField( 14 | model_name='testset', 15 | old_name='ref_sgml_file', 16 | new_name='ref_file', 17 | ), 18 | migrations.RenameField( 19 | model_name='testset', 20 | old_name='src_sgml_file', 21 | new_name='src_file', 22 | ), 23 | migrations.AddField( 24 | model_name='testset', 25 | name='file_format', 26 | field=models.CharField( 27 | choices=[('SGML', 'SGML format'), ('TEXT', 'Text format')], 28 | default='SGML', 29 | max_length=4, 30 | ), 31 | ), 32 | migrations.AlterField( 33 | model_name='testset', 34 | name='ref_file', 35 | field=models.FileField( 36 | blank=True, 37 | help_text='SGML or text file containing test set reference', 38 | null=True, 39 | upload_to='testsets', 40 | ), 41 | ), 42 | migrations.AlterField( 43 | model_name='testset', 44 | name='src_file', 45 | field=models.FileField( 46 | blank=True, 47 | help_text='SGML or text file containing test set source', 48 | null=True, 49 | upload_to='testsets', 50 | ), 51 | ), 52 | ] 53 | -------------------------------------------------------------------------------- /leaderboard/migrations/0020_auto_20200710_2145.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=invalid-name,missing-docstring,protected-access 2 | # Generated by Django 2.2.13 on 2020-07-10 21:45 3 | from django.db import migrations 4 | from django.db import models 5 | 6 | import leaderboard.models 7 | 8 | 9 | class Migration(migrations.Migration): 10 | dependencies = [ 11 | ('leaderboard', '0019_auto_20200710_2037'), 12 | ] 13 | 14 | operations = [ 15 | migrations.RenameField( 16 | model_name='submission', 17 | old_name='sgml_file', 18 | new_name='hyp_file', 19 | ), 20 | migrations.AddField( 21 | model_name='submission', 22 | name='file_format', 23 | field=models.CharField( 24 | choices=[('SGML', 'SGML format'), ('TEXT', 'Text format')], 25 | default='SGML', 26 | max_length=4, 27 | ), 28 | ), 29 | migrations.AlterField( 30 | model_name='submission', 31 | name='hyp_file', 32 | field=models.FileField( 33 | help_text='SGML or text file containing submission output', 34 | null=True, 35 | upload_to=leaderboard.models._get_submission_upload_path, 36 | validators=[leaderboard.models.validate_sgml_schema], 37 | ), 38 | ), 39 | ] 40 | -------------------------------------------------------------------------------- /leaderboard/migrations/0021_auto_20200710_2245.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=invalid-name,missing-docstring 2 | # Generated by Django 2.2.13 on 2020-07-10 22:45 3 | from django.db import migrations 4 | from django.db import models 5 | 6 | 7 | class Migration(migrations.Migration): 8 | dependencies = [ 9 | ('leaderboard', '0020_auto_20200710_2145'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='submission', 15 | name='file_format', 16 | field=models.CharField( 17 | choices=[('SGML', 'SGML format'), ('TEXT', 'Text format')], 18 | default='TEXT', 19 | max_length=4, 20 | ), 21 | ), 22 | ] 23 | -------------------------------------------------------------------------------- /leaderboard/migrations/0022_competition.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=invalid-name,missing-docstring 2 | # Generated by Django 3.1.6 on 2021-02-11 11:50 3 | import django.db.models.deletion 4 | from django.db import migrations 5 | from django.db import models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | dependencies = [ 10 | ('leaderboard', '0021_auto_20200710_2245'), 11 | ] 12 | 13 | operations = [ 14 | migrations.CreateModel( 15 | name='Competition', 16 | fields=[ 17 | ( 18 | 'id', 19 | models.AutoField( 20 | auto_created=True, 21 | primary_key=True, 22 | serialize=False, 23 | verbose_name='ID', 24 | ), 25 | ), 26 | ( 27 | 'name', 28 | models.CharField( 29 | db_index=True, 30 | help_text='Competition name (max 200 characters)', 31 | max_length=200, 32 | unique=True, 33 | ), 34 | ), 35 | ( 36 | 'description', 37 | models.TextField( 38 | help_text='Competition description (max 2000 characters)', 39 | max_length=2000, 40 | ), 41 | ), 42 | ( 43 | 'deadline', 44 | models.DateTimeField( 45 | blank=True, 46 | help_text='Competition deadline (max 2000 characters)', 47 | ), 48 | ), 49 | ], 50 | ), 51 | migrations.AddField( 52 | model_name='testset', 53 | name='competition', 54 | field=models.ForeignKey( 55 | blank=True, 56 | null=True, 57 | on_delete=django.db.models.deletion.PROTECT, 58 | related_name='test_sets', 59 | related_query_name='test_sets', 60 | to='leaderboard.competition', 61 | ), 62 | ), 63 | ] 64 | -------------------------------------------------------------------------------- /leaderboard/migrations/0023_competition_is_active.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.1.6 on 2021-02-11 12:48 2 | from django.db import migrations 3 | from django.db import models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | dependencies = [ 8 | ('leaderboard', '0022_competition'), 9 | ] 10 | 11 | operations = [ 12 | migrations.AddField( 13 | model_name='competition', 14 | name='is_active', 15 | field=models.BooleanField( 16 | db_index=True, 17 | default=False, 18 | help_text='Is active competition?', 19 | ), 20 | ), 21 | ] 22 | -------------------------------------------------------------------------------- /leaderboard/migrations/0024_auto_20210225_1118.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.1.7 on 2021-02-25 11:18 2 | from django.db import migrations 3 | from django.db import models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | dependencies = [ 8 | ('leaderboard', '0023_competition_is_active'), 9 | ] 10 | 11 | operations = [ 12 | migrations.AddField( 13 | model_name='competition', 14 | name='start_time', 15 | field=models.DateTimeField( 16 | blank=True, help_text='Competition start time', null=True 17 | ), 18 | ), 19 | migrations.AlterField( 20 | model_name='competition', 21 | name='deadline', 22 | field=models.DateTimeField( 23 | blank=True, help_text='Competition deadline' 24 | ), 25 | ), 26 | ] 27 | -------------------------------------------------------------------------------- /leaderboard/migrations/0025_auto_20210225_1954.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.1.7 on 2021-02-25 19:54 2 | from django.db import migrations 3 | from django.db import models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | dependencies = [ 8 | ('leaderboard', '0024_auto_20210225_1118'), 9 | ] 10 | 11 | operations = [ 12 | migrations.AlterField( 13 | model_name='competition', 14 | name='deadline', 15 | field=models.DateTimeField( 16 | blank=True, 17 | help_text='Competition deadline (an empty value means no deadline)', 18 | null=True, 19 | ), 20 | ), 21 | migrations.AlterField( 22 | model_name='competition', 23 | name='start_time', 24 | field=models.DateTimeField( 25 | blank=True, 26 | help_text='Competition start time (an empty value means no start time)', 27 | null=True, 28 | ), 29 | ), 30 | ] 31 | -------------------------------------------------------------------------------- /leaderboard/migrations/0026_auto_20210226_0859.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.1.7 on 2021-02-26 08:59 2 | from django.db import migrations 3 | from django.db import models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | dependencies = [ 8 | ('leaderboard', '0025_auto_20210225_1954'), 9 | ] 10 | 11 | operations = [ 12 | migrations.AddField( 13 | model_name='competition', 14 | name='is_public', 15 | field=models.BooleanField( 16 | blank=True, 17 | db_index=True, 18 | default=None, 19 | help_text='Are submissions publicly visible? Overwrites settings in test sets and submissions unless Unknown', 20 | null=True, 21 | ), 22 | ), 23 | migrations.AddField( 24 | model_name='testset', 25 | name='is_public', 26 | field=models.BooleanField( 27 | blank=True, 28 | db_index=True, 29 | default=None, 30 | help_text='Are submissions publicly visible? Overwrite settings from submissions unless Unknown', 31 | null=True, 32 | ), 33 | ), 34 | migrations.AlterField( 35 | model_name='submission', 36 | name='is_public', 37 | field=models.BooleanField( 38 | db_index=True, 39 | default=False, 40 | help_text='Is publicly visible? Can be overwritten by settings of the test set or competition', 41 | ), 42 | ), 43 | ] 44 | -------------------------------------------------------------------------------- /leaderboard/migrations/0027_auto_20210609_0818.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.1.7 on 2021-06-09 08:18 2 | from django.db import migrations 3 | from django.db import models 4 | 5 | import leaderboard.models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | dependencies = [ 10 | ('leaderboard', '0026_auto_20210226_0859'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AlterField( 15 | model_name='language', 16 | name='name', 17 | field=models.CharField( 18 | db_index=True, 19 | help_text='Language name (max 200 characters)', 20 | max_length=200, 21 | ), 22 | ), 23 | migrations.AlterField( 24 | model_name='submission', 25 | name='file_format', 26 | field=models.CharField( 27 | choices=[ 28 | ('SGML', 'SGML format'), 29 | ('TEXT', 'Text format'), 30 | ('XML', 'XML format'), 31 | ], 32 | default='TEXT', 33 | max_length=4, 34 | ), 35 | ), 36 | migrations.AlterField( 37 | model_name='submission', 38 | name='hyp_file', 39 | field=models.FileField( 40 | help_text='SGML, XML or text file containing submission output', 41 | null=True, 42 | upload_to=leaderboard.models._get_submission_upload_path, 43 | validators=[leaderboard.models.validate_sgml_schema], 44 | ), 45 | ), 46 | migrations.AlterField( 47 | model_name='testset', 48 | name='file_format', 49 | field=models.CharField( 50 | choices=[ 51 | ('SGML', 'SGML format'), 52 | ('TEXT', 'Text format'), 53 | ('XML', 'XML format'), 54 | ], 55 | default='XML', 56 | max_length=4, 57 | ), 58 | ), 59 | migrations.AlterField( 60 | model_name='testset', 61 | name='ref_file', 62 | field=models.FileField( 63 | blank=True, 64 | help_text='SGML, XML or text file containing test set reference(s)', 65 | null=True, 66 | upload_to='testsets', 67 | validators=[leaderboard.models.validate_xml_ref_testset], 68 | ), 69 | ), 70 | migrations.AlterField( 71 | model_name='testset', 72 | name='src_file', 73 | field=models.FileField( 74 | blank=True, 75 | help_text='SGML, XML or text file containing test set source', 76 | null=True, 77 | upload_to='testsets', 78 | validators=[leaderboard.models.validate_xml_src_testset], 79 | ), 80 | ), 81 | ] 82 | -------------------------------------------------------------------------------- /leaderboard/migrations/0028_auto_20210609_1215.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.1.7 on 2021-06-09 12:15 2 | from django.db import migrations 3 | from django.db import models 4 | 5 | import leaderboard.models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | dependencies = [ 10 | ('leaderboard', '0027_auto_20210609_0818'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AlterField( 15 | model_name='submission', 16 | name='hyp_file', 17 | field=models.FileField( 18 | help_text='SGML, XML or text file containing submission output', 19 | null=True, 20 | upload_to=leaderboard.models._get_submission_upload_path, 21 | validators=[ 22 | leaderboard.models.validate_sgml_schema, 23 | leaderboard.models.validate_xml_schema, 24 | ], 25 | ), 26 | ), 27 | ] 28 | -------------------------------------------------------------------------------- /leaderboard/migrations/0029_auto_20210611_0713.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.1.7 on 2021-06-11 07:13 2 | from django.db import migrations 3 | from django.db import models 4 | 5 | import leaderboard.models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | dependencies = [ 10 | ('leaderboard', '0028_auto_20210609_1215'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AlterField( 15 | model_name='submission', 16 | name='hyp_file', 17 | field=models.FileField( 18 | help_text='SGML, XML or text file containing submission output', 19 | null=True, 20 | upload_to=leaderboard.models._get_submission_upload_path, 21 | validators=[ 22 | leaderboard.models.validate_sgml_schema, 23 | leaderboard.models.validate_xml_submission, 24 | ], 25 | ), 26 | ), 27 | ] 28 | -------------------------------------------------------------------------------- /leaderboard/migrations/0030_auto_20210615_1758.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.1.7 on 2021-06-15 17:58 2 | from django.db import migrations 3 | from django.db import models 4 | 5 | import leaderboard.models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | dependencies = [ 10 | ('leaderboard', '0029_auto_20210611_0713'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AddField( 15 | model_name='team', 16 | name='institution_name', 17 | field=models.CharField( 18 | blank=True, 19 | db_index=True, 20 | help_text='Institution name (max 32 characters)', 21 | max_length=200, 22 | validators=[leaderboard.models.validate_institution_name], 23 | ), 24 | ), 25 | migrations.AlterField( 26 | model_name='team', 27 | name='publication_name', 28 | field=models.CharField( 29 | blank=True, 30 | db_index=True, 31 | help_text='Team publication name (max 32 characters)', 32 | max_length=200, 33 | validators=[leaderboard.models.validate_publication_name], 34 | ), 35 | ), 36 | ] 37 | -------------------------------------------------------------------------------- /leaderboard/migrations/0031_auto_20210616_0934.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.1.7 on 2021-06-16 09:34 2 | from django.db import migrations 3 | from django.db import models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | dependencies = [ 8 | ('leaderboard', '0030_auto_20210615_1758'), 9 | ] 10 | 11 | operations = [ 12 | migrations.AddField( 13 | model_name='team', 14 | name='description', 15 | field=models.TextField( 16 | blank=True, 17 | help_text='Team description (max 2000 characters)', 18 | max_length=2000, 19 | ), 20 | ), 21 | migrations.AddField( 22 | model_name='team', 23 | name='publication_url', 24 | field=models.CharField( 25 | blank=True, 26 | help_text='Publication URL or citation', 27 | max_length=200, 28 | ), 29 | ), 30 | ] 31 | -------------------------------------------------------------------------------- /leaderboard/migrations/0032_testset_collection.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.1.7 on 2022-07-06 17:13 2 | from django.db import migrations 3 | from django.db import models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | dependencies = [ 8 | ('leaderboard', '0031_auto_20210616_0934'), 9 | ] 10 | 11 | operations = [ 12 | migrations.AddField( 13 | model_name='testset', 14 | name='collection', 15 | field=models.CharField( 16 | blank=True, 17 | help_text='Optional collection name (max 200 characters)', 18 | max_length=200, 19 | null=True, 20 | ), 21 | ), 22 | ] 23 | -------------------------------------------------------------------------------- /leaderboard/migrations/0033_testset_compute_scores.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.2.14 on 2022-07-21 23:20 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | dependencies = [ 8 | ('leaderboard', '0032_testset_collection'), 9 | ] 10 | 11 | operations = [ 12 | migrations.AddField( 13 | model_name='testset', 14 | name='compute_scores', 15 | field=models.BooleanField( 16 | db_index=True, 17 | default=True, 18 | help_text='Compute automatic scores?', 19 | ), 20 | ), 21 | ] 22 | -------------------------------------------------------------------------------- /leaderboard/migrations/0034_submission_is_valid.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.3 on 2023-07-14 11:52 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | dependencies = [ 8 | ("leaderboard", "0033_testset_compute_scores"), 9 | ] 10 | 11 | operations = [ 12 | migrations.AddField( 13 | model_name="submission", 14 | name="is_valid", 15 | field=models.BooleanField( 16 | db_index=True, default=False, help_text="Is valid?" 17 | ), 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /leaderboard/migrations/0035_alter_submission_file_format.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.3 on 2023-07-17 11:02 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | dependencies = [ 8 | ("leaderboard", "0034_submission_is_valid"), 9 | ] 10 | 11 | operations = [ 12 | migrations.AlterField( 13 | model_name="submission", 14 | name="file_format", 15 | field=models.CharField( 16 | choices=[ 17 | ("SGML", "SGML format"), 18 | ("TEXT", "Text format"), 19 | ("XML", "XML format"), 20 | ], 21 | default="XML", 22 | max_length=4, 23 | ), 24 | ), 25 | ] 26 | -------------------------------------------------------------------------------- /leaderboard/migrations/0036_submission_is_contrastive_submission_is_withdrawn.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.3 on 2023-07-17 11:28 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | dependencies = [ 8 | ("leaderboard", "0035_alter_submission_file_format"), 9 | ] 10 | 11 | operations = [ 12 | migrations.AddField( 13 | model_name="submission", 14 | name="is_contrastive", 15 | field=models.BooleanField( 16 | db_index=True, 17 | default=False, 18 | help_text="Is contrastive submission?", 19 | ), 20 | ), 21 | migrations.AddField( 22 | model_name="submission", 23 | name="is_withdrawn", 24 | field=models.BooleanField( 25 | db_index=True, default=False, help_text="Is withdrawn?" 26 | ), 27 | ), 28 | ] 29 | -------------------------------------------------------------------------------- /leaderboard/migrations/0037_auto_20240628_0832.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.1.7 on 2024-06-28 08:32 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('leaderboard', '0036_submission_is_contrastive_submission_is_withdrawn'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='submission', 15 | name='is_open_source', 16 | field=models.BooleanField(db_index=True, default=False, help_text='Is open-source submission?'), 17 | ), 18 | migrations.AlterField( 19 | model_name='submission', 20 | name='is_constrained', 21 | field=models.BooleanField(db_index=True, default=False, help_text='Is constrained submission?'), 22 | ), 23 | ] 24 | -------------------------------------------------------------------------------- /leaderboard/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=invalid-name,missing-docstring 2 | -------------------------------------------------------------------------------- /leaderboard/templates/leaderboard/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Project OCELoT{% block title %}{% endblock %} 9 | 10 | 11 | 12 | {% block head %}{% endblock %} 13 | 14 | 39 | 40 | 41 | 42 | {% block navbar %} 43 | 85 | {% endblock %} 86 | 87 | {% if messages %} 88 |
89 | {% for message in messages %} 90 | 96 | {% endfor %} 97 |
98 | {% endif %} 99 | 100 |
101 | {% block jumbotron %} 102 | 103 |
104 |
105 |

Welcome to OCELoT!

106 | {% block jumbotron-extra %}{% endblock %} 107 |
108 |
109 | {% endblock %} 110 | 111 | {% block main %}{% endblock %} 112 |
113 | 114 | 117 | 118 | 119 | 120 | 121 | 122 | {% block script %}{% endblock %} 123 | 124 | 125 | -------------------------------------------------------------------------------- /leaderboard/templates/leaderboard/competition.html: -------------------------------------------------------------------------------- 1 | {% extends "leaderboard/base.html" %} 2 | {% load static %} 3 | 4 | {% block head %} 5 | 6 | {% endblock %} 7 | 8 | {% block jumbotron %} 9 |
10 |
11 |

{{competition.name}}

12 |

13 | {{competition.description|safe}} 14 |

15 |
16 |
17 | {% endblock %} 18 | 19 | {% block main %} 20 |
21 |
22 |

23 | Download test sets 24 | {% if ocelot_team_token %} 25 | Team submissions 26 | Create submission 27 | {% else %} 28 | Register your team 29 | Create submission 30 | {% endif %} 31 | Competition updates 32 |

33 |
34 |
35 | 36 |
37 |
38 | 42 | 46 | 49 |
50 | 51 |

Leaderboard of {{competition.name}}

52 | {% if data %} 53 | {% for testset, submissions in data %} 54 |

{{testset}}

55 |
56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | {% for submission in submissions|slice:MAX_SUBMISSION_DISPLAY_COUNT %} 68 | 69 | 70 | {% if submission.team_token == ocelot_team_token %} 71 | 76 | {% else %} 77 | 84 | {% endif %} 85 | {% if submission.score_bleu %} 86 | 87 | {% else %} 88 | 89 | {% endif %} 90 | {% if submission.score_chrf %} 91 | 92 | {% else %} 93 | 94 | {% endif %} 95 | 96 | 97 | {% endfor %} 98 | {% if submissions|length > MAX_SUBMISSION_DISPLAY_COUNT %} 99 | 100 | 101 | 103 | 104 | {% endif %} 105 | 106 | 118 |
#NameBLEUchrFDate
{{forloop.counter}} 72 | 73 | {{submission.name}} 74 | 75 | 78 | {% if submission.is_anonymous %} 79 | {{submission.name}} 80 | {% else %} 81 | {{submission.name}} 82 | {% endif %} 83 | {{submission.score_bleu|stringformat:".1f"}}---{{submission.score_chrf|stringformat:".1f"}}---{{submission.date_created}}
...showing top-{{MAX_SUBMISSION_DISPLAY_COUNT}} only, total number of submissions: 102 | {{submissions|length}}
107 | BLEU and ChrF are sacreBLEU scores. 108 | Systems in bold face are your submissions. We 109 | only display the top-{{MAX_SUBMISSION_DISPLAY_COUNT}} 110 | submissions per language pair. Submission validation errors 111 | denoted by -1.0 score. 112 |

113 | Click on the column header to sort the table. Hold down the 114 | Shift key and select a second column to sort by 115 | multiple criteria. 116 |

117 |
119 |
120 | {% endfor %} 121 | {% else %} 122 | {% if False %} 123 |

Submissions will become available by 6/22/2020 at 11:59 pm, PDT.

124 | {% else %} 125 |

No submissions yet.

126 | {% endif %} 127 | {% endif %} 128 |
129 | 130 |
131 | {% endblock %} 132 | 133 | {% block script %} 134 | 135 | 193 | {% endblock %} 194 | -------------------------------------------------------------------------------- /leaderboard/templates/leaderboard/download.html: -------------------------------------------------------------------------------- 1 | {% extends "leaderboard/base.html" %} 2 | {% load static %} 3 | 4 | {% block navbar-download %} 5 | Download (current) 6 | {% endblock %} 7 | 8 | {% block main %} 9 |
10 |
11 |

12 | Download test sets 13 | {% if ocelot_team_token %} 14 | Team submissions 15 | {% else %} 16 | Register your team 17 | {% endif %} 18 | {% if ocelot_team_verified %} 19 | Create submission 20 | {% else %} 21 | Create submission 22 | {% endif %} 23 | Competition updates 24 |

25 |
26 |
27 | 28 |
29 | 30 |

Download test sets

31 |

32 |

38 |

39 | 40 |
41 | 42 |
43 | {% endblock %} 44 | -------------------------------------------------------------------------------- /leaderboard/templates/leaderboard/frontpage.html: -------------------------------------------------------------------------------- 1 | {% extends "leaderboard/base.html" %} 2 | {% load static %} 3 | 4 | {% block navbar-frontpage %} 5 | Home (current) 6 | {% endblock %} 7 | 8 | {% block jumbotron-extra %} 9 |

10 | OCELoT stands for Open, Competitive 11 | Evaluation Leaderboard 12 | of Translations. 13 | This project started as part of the 14 | Fifth Machine Translation Marathon in the Americas. 15 | Project OCELoT aims to create an open platform for competitive evaluation of machine 16 | translation output, based on both automatic metrics and human evalation. It has been used for 17 | several shared tasks, including the WMT General MT Task since 2020 as well as IWSLT shared tasks. 18 | Code is available from GitHub and shared 19 | under an open license. 20 |

21 | {% endblock %} 22 | 23 | {% block main %} 24 |
25 |
26 |

27 | Download test sets 28 | {% if ocelot_team_token %} 29 | Team submissions 30 | {% else %} 31 | Register your team 32 | {% endif %} 33 | {% if ocelot_team_verified %} 34 | Create submission 35 | {% else %} 36 | Create submission 37 | {% endif %} 38 | Competition updates 39 |

40 |
41 |
42 | 43 |
44 |

Competitions

45 | 46 | {% if competitions %} 47 |
48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | {% for competition in competitions %} 61 | 62 | 63 | 66 | 67 | 68 | {% if competition.start_time %} 69 | 70 | {% else %} 71 | 72 | {% endif %} 73 | {% if competition.deadline %} 74 | 75 | {% else %} 76 | 77 | {% endif %} 78 | 79 | {% endfor %} 80 | 81 |
#CompetitionTest setsSubmissionsStart timeDeadline
{{forloop.counter}} 64 | {{competition.name}} 65 | {{competition.num_test_sets}}{{competition.num_submissions}}{{competition.start_time}}---{{competition.deadline}}---
82 |
83 | {% else %} 84 |

No competition has been created yet.

85 | {% endif %} 86 |

All times in {% now "T" %} timezone.

87 |
88 | 89 |
90 | {% endblock %} 91 | 92 | {% block script %} 93 | 133 | {% endblock %} 134 | -------------------------------------------------------------------------------- /leaderboard/templates/leaderboard/sign-in.html: -------------------------------------------------------------------------------- 1 | {% extends "leaderboard/base.html" %} 2 | {% load static %} 3 | 4 | {% block navbar-signin %} 5 | Sign in (current) 6 | {% endblock %} 7 | 8 | {% block main %} 9 |
10 |
11 |

12 | Download test sets 13 | Register your team 14 | Create submission 15 | competition updates 16 |

17 |
18 |
19 | 20 |
21 | 22 |

Team sign-in

23 |
24 | {% csrf_token %} 25 | {{ form.as_p }} 26 | 27 |
28 | 29 |
30 | 31 |
32 | {% endblock %} 33 | -------------------------------------------------------------------------------- /leaderboard/templates/leaderboard/signup.html: -------------------------------------------------------------------------------- 1 | {% extends "leaderboard/base.html" %} 2 | {% load static %} 3 | 4 | {% block navbar-signup %} 5 | Registration (current) 6 | {% endblock %} 7 | 8 | {% block main %} 9 |
10 |
11 |

12 | Download test sets 13 | {% if ocelot_team_token %} 14 | Team submissions 15 | {% else %} 16 | Register your team 17 | {% endif %} 18 | {% if ocelot_team_verified %} 19 | Create submission 20 | {% else %} 21 | Create submission 22 | {% endif %} 23 | Competition updates 24 |

25 |
26 |
27 | 28 |
29 | 30 |

Team signup

31 |
32 | {% csrf_token %} 33 | {{ form.as_p }} 34 | 35 |
36 | 37 |
38 | 39 |
40 | {% endblock %} 41 | -------------------------------------------------------------------------------- /leaderboard/templates/leaderboard/submission.html: -------------------------------------------------------------------------------- 1 | {% extends "leaderboard/base.html" %} 2 | {% load static %} 3 | 4 | {% block navbar-submit %} 5 | Submission (current) 6 | {% endblock %} 7 | 8 | {% block main %} 9 |
10 |
11 |

12 | Download test sets 13 | {% if ocelot_team_token %} 14 | Team submissions 15 | {% else %} 16 | Register your team 17 | {% endif %} 18 | {% if ocelot_team_verified %} 19 | Create submission 20 | {% else %} 21 | Create submission 22 | {% endif %} 23 | Competition updates 24 |

25 |
26 |
27 | 28 |
29 | 30 |

Submission

31 | 32 | {% if False %} 33 |

34 | Submissions and competition updates will become available on 6/23/2020, PDT. 35 |

36 | {% else %} 37 |
38 | {% csrf_token %} 39 | {{ form.as_p }} 40 | 41 |
42 |
43 |
44 | 49 | Note: XML file names need to end with ".xml". 50 |
51 | {% endif %} 52 |
53 | 54 |
55 | {% endblock %} 56 | -------------------------------------------------------------------------------- /leaderboard/templates/leaderboard/updates.html: -------------------------------------------------------------------------------- 1 | {% extends "leaderboard/base.html" %} 2 | {% load static %} 3 | 4 | {% block navbar-updates %} 5 | Updates (current) 6 | {% endblock %} 7 | 8 | {% block main %} 9 |
10 |
11 |

12 | Download test sets 13 | {% if ocelot_team_token %} 14 | Team submissions 15 | {% else %} 16 | Register your team 17 | {% endif %} 18 | {% if ocelot_team_verified %} 19 | Create submission 20 | {% else %} 21 | Create submission 22 | {% endif %} 23 | Competition updates 24 |

25 |
26 |
27 | 28 |
29 | 30 |

Competition updates

31 |

32 |

39 |

40 | 41 |

Competition rules

42 |

43 | The following rules apply to this year's shared task: 44 |

49 |

50 | 51 |
52 | 53 |
54 | {% endblock %} 55 | -------------------------------------------------------------------------------- /leaderboard/templates/leaderboard/welcome.html: -------------------------------------------------------------------------------- 1 | {% extends "leaderboard/base.html" %} 2 | {% load static %} 3 | 4 | {% block main %} 5 |
6 |
7 |

8 | Download test sets 9 | {% if ocelot_team_token %} 10 | Team submissions 11 | {% else %} 12 | Register your team 13 | {% endif %} 14 | {% if ocelot_team_verified %} 15 | Create submission 16 | {% else %} 17 | Create submission 18 | {% endif %} 19 | Competition updates 20 |

21 |
22 |
23 | 24 |
25 | 26 |

Registration confirmation

27 |

28 | Important: please note this down as you will need this information for sign-in later. Upon first registration, your team will be automatically signed into the current browser session. On your personal computer, you can stay signed in. Otherwise, on a public or shared machine, please sign out when leaving. 29 |

30 |

31 | Team name: {{ocelot_team_name}}
32 | Email: {{ocelot_team_email}}
33 | Token: {{ocelot_team_token}}
34 |

35 | 36 |
37 | 38 |
39 | {% endblock %} 40 | -------------------------------------------------------------------------------- /leaderboard/testdata/newstest2019-ende-ref.de.txt: -------------------------------------------------------------------------------- 1 | Walisische Ageordnete sorgen sich "wie Dödel auszusehen" 2 | Es herrscht Bestürzung unter einigen Mitgliedern der Versammlung über einen Vorschlag, der ihren Titel zu MWPs (Mitglied der walisischen Parlament) ändern soll. 3 | Der Grund dafür waren Pläne, den Namen der Nationalversammlung in Walisisches Parlament zu ändern. 4 | Mitglieder aller Parteien der Nationalversammlung haben Bedenken, dass sie sich dadurch Spott aussetzen könnten. 5 | Ein Labour-Abgeordneter sagte, dass seine Gruppe "sich mit Twp und Pwp reimt". 6 | Hinweis für den Leser: „twp“ im Walisischen bedeutet „bescheuert“ und „pwp“ bedeutet „Kacke“. 7 | Ein Versammlungsmitglied von Plaid Cymru sagte, die Gruppe als Ganzes sei "nicht glücklich" und hat Alternativen vorgeschlagen. 8 | Ein walisischer Konservativer sagte, seine Gruppe wäre „offen“ für eine Namensänderung, wies aber darauf hin, dass es von „MWP“ (Mitglied des Walisischen Parlaments) nur ein kurzer verbaler Sprung zu „Muppet“ ist. 9 | Hinweis: Der walisische Buchstabe W wird ähnlich ausgesprochen wie das U im Englischen. 10 | Die Kommission der Nationalversammlung, die gerade an einem Gesetzentwurf für die Namensänderungen arbeitet, sagte: „Die finale Entscheidung über die Bezeichnung der Mitglieder der Nationalversammlung liegt natürlich bei den Mitgliedern selbst.“ 11 | Mit dem Government of Wales Act 2017 erhielt das walisische Parlament die Möglichkeit, seinen Namen zu ändern. 12 | Im Juni vergangenen Jahres hat die Kommission die Ergebnisse einer öffentlichen Anhörung zu den Vorschlägen veröffentlicht, wonach die Namensänderung in Walisisches Parlament breite Zustimmung findet. 13 | Bei der Frage um den Titel der Versammlungsmitglieder bevorzugte die Kommission walisischen Parlamentsmitglieder oder WMPs, jedoch bekam die MWP-Option die meiste Unterstützung in einer öffentlichen Befragung. 14 | Mitglieder des walisischen Parlaments schlagen offenbar alternative Optionen vor, aber der Kampf zu einem Konsens zu gelangen, könnte der Vorsitzenden Elin JONES Kopfschmerzen bereiten. Von ihr wird erwartet, dass sie einen Gesetzesentwurf für diese Änderungen in den nächsten Wochen vorlegt. 15 | Die Rechtsvorschriften über die Reformen wird Änderungen in der Arbeitsweise der Versammlung beinhalten, einschließlich der Vorschriften für die Disqualifikation von Mitgliedern des walisischen Parlaments und die Gestaltung des Auschusssystems. 16 | Die Mitglieder der Nationalversammlung können bei der Debatte um das Gesetz entscheiden, wie sie genannt werden sollen. 17 | Mazedonier halten über die Änderung des Landesnamens ein Referendum ab. 18 | Am Sonntag stimmen die Wahlberechtigten über die Änderung des Landesnamens zu „Republik Nordmazedonien“ ab. 19 | Die Volksabstimmung wird abgehalten, um einen jahrzehntelangen Streit mit dem benachbarten Griechenland beizulegen, in dem eine Provinz den Namen Mazedonien trägt. 20 | Athen beharrt seit langem darauf, dass der Name seines nördlichen Nachbarn einen Anspruch auf sein Territorium darstellt und hat wiederholt Einspruch gegen seinen Aufnahmeantrag für die EU und die NATO erhoben. 21 | Der mazedonische Präsident Gjorge Ivanov, ein Gegner des Referendums bezüglich der Namensänderung, hat gesagt, er werde die Abstimmung ignorieren. 22 | Die Befürworter des Referendums, einschließlich des Premierministers Zoran Zaev, argumentieren jedoch, dass die Namensänderung ganz einfach der Preis ist, den man für den Beitritt zur EU und zur NATO zahlen muss. 23 | Die Glocken von St. Martin verstummenn, da Kirchen in Harlem Probleme haben 24 | "Historisch gesehen haben die alten Leute, mit denen ich gesprochen habe, gesagt, dass es an jeder Ecke eine Bar und eine Kirche gab", sagte Herr Adams. 25 | „Heute gibt es weder noch." 26 | Er sagte, das Verschwinden von Kneipen sei verständlich. 27 | "Menschen knüpfen Komtakte auf eine andere Art und Weise", heutzutage sagte er. 28 | "Kneipen sind keine Wohnzimmer mehr in der Nachbarschaft, in denen man sich regelmäßig trifft." 29 | Was Kirchen angeht, fürchtet er, dass das Geld aus dem Verkauf von Vermögenswerten nicht so lange Bestand haben wird, wie die Anführer es erwarten. 30 | Kirchen könnten durch Mehrfamilienhäuser mit Eigentumswohnungen ersetzt werden, die mit der Art von Menschen gefüllt sind, die den verbleibenden Zufluchtsstätten des Stadtteils nicht helfen werden. 31 | Die überwältigende Mehrheit der Menschen, die Eigentumswohnungen in diesen Gebäuden kaufen, wird weiß sein, sagte er, "und wird daher den Tag, an dem diese Kirchen ganz geschlossen werden, beschleunigen, da es unwahrscheinlich ist, dass die meisten dieser Personen, die in diese Eigentumswohnungen einziehen, Mitglieder dieser Kirchen werden." 32 | Beide Kirchen wurden von weißen Gemeinden gebaut, bevor Harlem 1870 zur schwarzen Metropole wurde – Metropolitan Community, St. Martin's ein Jahrzehnt später. 33 | Die ursprüngliche weiße methodistische Gemeinde zog in den 1930er Jahren aus. 34 | Eine schwarze Gemeinde, die in der Nähe eine Religion ausübten, erwarb das Gebäude. 35 | St. Martin's wurde von einer schwarzen Gemeinde unter dem Pfarrer John Howard Johnson übernommen, der einen Boykott der Einzelhändler in der 125. Straße, einer Hauptstraße zum Einkaufen in Harlem, anführte, die sich der Einstellung oder Förderung von Schwarzen widersetzte. 36 | Ein Brand im Jahr 1939 hinterließ das Gebäude schwer beschädigt, aber als die Gemeindemitglieder von Pater Johnson Pläne zum Wiederaufbau machten, beauftragten sie das Glockenspiel. 37 | Pfarrer David Johnson, Sohn von Pater Johnson und Nachfolger in St. Martin's, nannte das Glockenspiel stolz „die Glocken der Armen." 38 | Der Experte, der im Juli das Glockenspiel spielte, nannte es noch etwas anderes: "Ein Kulturschatz" und "ein unersetzliches historisches Instrument". 39 | Der Experte, Tiffany Ng von der University of Michigan, stellte auch fest, dass es das erste Glockenspiel der Welt war, das von einem schwarzen Musiker, Dionisio A. Lind, gespielt wurde, der vor 18 Jahren in das größere Glockenspiel an der Riverside Church wechselte. 40 | Herr Merriweather sagte, dass St. Martin's ihn nicht ersetzt hat. 41 | Was sich in den letzten Monaten bei St. Martin abgespielt hat, war eine komplizierte Geschichte von Architekten und Bauunternehmern, einige wurden von den Laienführern der Kirche, andere von der Bischofsdiözese eingebracht. 42 | Die Sakristei – das Leitungsorgan der Pfarrei, das sich aus Laienführern zusammensetzt – schrieb im Juli an die Diözese mit der Sorge, dass die Diözese "versuchen würde, die Kosten an die Sakristei weiterzugeben", obwohl die Sakristei nicht an der Beauftragung der Architekten und Auftragnehmer der Diözese beteiligt war. 43 | Einige Gemeindemitglieder beklagten einen Mangel an Transparenz seitens der Diözese. 44 | Hai verletzt 13-jährigen Jungen beim Hummertauchen in Kalifornien 45 | Am Samstag griff ein Hai einen 13-jährigen Jungen an und verletzte ihn, während er in Kalifornien am Eröffnungstag der Hummersaison nach Hummern tauchte, sagten Beamte. 46 | Der Angriff fand kurz vor sieben Uhr morgens nahe dem Strand von Beacon in Encinitas statt. 47 | Chad Hammel sagte KSWB-TV in San Diego, er habe mit Freunden für eine halbe Stunde am Samstagmorgen getaucht, als er den Jungen um Hilfe schreien hörte. Er sei dann mit den anderen rübergepaddelt, um ihn aus dem Wasser zu retten. 48 | „Zuerst dachte ich, jemand freut sich, weil er einen Hummer gefangen hat“, sagte Hammel. Aber dann bemerkte ich, dass jemand schrie: „Ich wurde gebissen!“ 49 | Ich wurde gebissen! 50 | Sein ganzes Schlüsselbein wurde aufgerissen, sagte Hammel, er stellte dies fest als er zu dem Jungen kam. 51 | Ich schrie alle an, damit sie aus dem Wasser herauskommen: "Da ist ein Hai im Wasser!" sagte Hammel. 52 | Der Junge wurde ins Rady Children's Hospital in San Diego gebracht, wo sein Zustand als kritisch dokumentiert wurde. 53 | Die für den Angriff verantwortliche Haiart ist unbekannt. 54 | Rettungsschwimmer Kapitän Larry Giles sagte bei einer Medienbesprechung, dass ein Hai einige Wochen zuvor in der Gegend gesichtet worden war, aber es wurde festgestellt, dass es sich nicht um eine gefährliche Haiart handelt. 55 | Giles fügte im Oberkörperbereich seines Opfers traumatische Verletzungen hinzu. 56 | Beamte schlossen den Zugang zum Strand von Ponto Beach in Casablad zu Swami's in Ecinitas für 48 Stunden aus Sicherheitsgründen. 57 | Giles stellte fest, dass es mehr als 135 Haiarten in der Gegend gibt, aber die meisten gelten nicht als gefährlich. 58 | Sainsbury plant, den britischen Beauty-Markt zu erobern 59 | Sainsbury's übernimmt Boots, Superdrug und Debenhams mit Regalen mit Schönheitsprodukten im Kaufhausstil, die mit Fachassistenten besetzt sind. 60 | Im Rahmen eines umfangreichen Pushs in den britische Schönheitsmarkt in Großbritannien, der weiter wächst und £2.8bn wert ist, werden Mode-und Homeware-Verkäufe zurückfallen. Die größeren 11 Filialen, die das Land getestet und im nächsten Jahr wieder in mehr Läden gebracht hat, um Erfolg zu zeigen. 61 | Die Idee, in den Beauty-Markt zu investieren, ist daraus entstanden, dass Supermärkte nach Möglichkeiten suchen, den Regalplatz, der früher für Fernseher, Mikrowellen und Haushaltswaren verwendet wurde, für neue Produkte zu nutzen. 62 | Sainsbury teilte mit, dass das Angebot an Beauty-Produkten auf 3000 Produkte verdoppelt werde, indem erstmals auch Marken wie Revlon, Essie, Tweezerman und Dr. PawPaw in das Produktportfolio aufgenommen werden. 63 | Auch bestehende Sortimente von L'Oreal, Maybelline und Burt's Bees werden mehr Platz in Markenbereichen erhalten, ähnlich wie sie in Geschäften wie Boots zu finden sind. 64 | Die Supermarktkette belebt auch ihre hauseigene Makeup-Marke „Boutique“ neu, die zahlreiche bei jungen Käufern beliebte vegane Produkte im Angebot hat. 65 | Darüber hinaus testet der Parfümhändler Fragrance Shop Konzessionen in zwei Sainsburys Geschäften, von denen das erste letzte Woche in Croydon, Süd-London, eröffnet wurde, während ein zweites Ende dieses Jahres in Selly Oak, Birmingham, eröffnet wird. 66 | Online-Shopping und eine Verlagerung hin zum täglichen Einkauf kleiner Mengen Lebensmittel in Nachbarschaftsläden haben zur Folge, dass Supermärkte mehr tun müssen, um die Menschen zum Besuch zu bewegen. 67 | Mike Coupe, der Chef von Sainsbury's, hat gesagt, dass die Verkaufsstellen in zunehmendem Maße wie Warenhäuser aussehen werden, da die Supermarktkette versucht Discounter wie Aldi und Lidl mit mehr Dienstleistungen und Non-Food zu bekämpfen. 68 | Sainsbury's hat Argos-Outlets in Hunderten von Geschäften platziert und auch eine Reihe von Habitats eingeführt, seit es beide Ketten vor zwei Jahren gekauft hat, was angeblich den Lebensmittelverkauf gestärkt und die Akquisitionen profitabler gemacht hat. 69 | Der frühere Versuch des Supermarktes, seine Schönheits- und Apothekenabteilungen zu überarbeiten, endete mit einem Misserfolg. 70 | Sainsbury hat ein Joint Venture mit Boots in den frühen 2000er Jahren getestet, aber es endete unetschieden, und die Einnahmen aus den Geschäften der Apotheken konnten nicht geteilt werden. 71 | Die neue Strategie kommt, nachdem Sainsbury's sein 281-Filialen-Apothekengeschäft vor drei Jahren für 125 Millionen Pfund an Celesio, den Eigentümer der Lloyds Pharmacy Kette, verkauft hat. 72 | Laut Angaben soll Lloyds ebenfalls beteiligt sein. In vier Lloyds-Stores soll das Angebot an Luxus-Hautpflegeprodukten von Marken wie La Roche-Posay und Vichy stark erweitert werden. 73 | Paul Mills-Hicks, Werbechef von Sainsbury, sagte: „Wir haben das Erscheinungsbild unserer Regale für Schönheitsprodukte verändert, um die Ausstattung für unsere Kunden zu verbessern. 74 | Zusätzlich haben wir in die Schulung von Mitarbeitern investiert, die dem Kunden beratend zur Seite stehen sollen. 75 | Unser Markenportfolio lässt keine Wünsche offen. Das elegante Ambiente, die günstige Innenstadtlage und ein revolutioniertes Kauferlebnis machen uns zu einem beliebten Anlaufziel in Beauty-Fragen. 76 | -------------------------------------------------------------------------------- /leaderboard/testdata/newstest2019-ende-src.en.txt: -------------------------------------------------------------------------------- 1 | Welsh AMs worried about 'looking like muppets' 2 | There is consternation among some AMs at a suggestion their title should change to MWPs (Member of the Welsh Parliament). 3 | It has arisen because of plans to change the name of the assembly to the Welsh Parliament. 4 | AMs across the political spectrum are worried it could invite ridicule. 5 | One Labour AM said his group was concerned "it rhymes with Twp and Pwp." 6 | For readers outside of Wales: In Welsh twp means daft and pwp means poo. 7 | A Plaid AM said the group as a whole was "not happy" and has suggested alternatives. 8 | A Welsh Conservative said his group was "open minded" about the name change, but noted it was a short verbal hop from MWP to Muppet. 9 | In this context The Welsh letter w is pronounced similarly to the Yorkshire English pronunciation of the letter u. 10 | The Assembly Commission, which is currently drafting legislation to introduce the name changes, said: "The final decision on any descriptors of what Assembly Members are called will of course be a matter for the members themselves." 11 | The Government of Wales Act 2017 gave the Welsh assembly the power to change its name. 12 | In June, the Commission published the results of a public consultation on the proposals which found broad support for calling the assembly a Welsh Parliament. 13 | On the matter of the AMs' title, the Commission favoured Welsh Parliament Members or WMPs, but the MWP option received the most support in a public consultation. 14 | AMs are apparently suggesting alternative options, but the struggle to reach consensus could be a headache for the Presiding Officer, Elin Jones, who is expected to submit draft legislation on the changes within weeks. 15 | The legislation on the reforms will include other changes to the way the assembly works, including rules on disqualification of AMs and the design of the committee system. 16 | AMs will get the final vote on the question of what they should be called when they debate the legislation. 17 | Macedonians go to polls in referendum on changing country's name 18 | Voters will vote Sunday on whether to change their country's name to the "Republic of North Macedonia." 19 | The popular vote was set up in a bid to resolve a decades-long dispute with neighboring Greece, which has its own province called Macedonia. 20 | Athens has long insisted that its northern neighbor's name represents a claim on its territory and has repeatedly objected to its membership bids for the EU and NATO. 21 | Macedonian President Gjorge Ivanov, an opponent of the plebiscite on the name change, has said he will disregard the vote. 22 | However, supporters of the referendum, including Prime Minister Zoran Zaev, argue that the name change is simply the price to pay to join the EU and NATO. 23 | The Bells of St. Martin's Fall Silent as Churches in Harlem Struggle 24 | "Historically, the old people I've talked to say there was a bar and a church on every corner," Mr. Adams said. 25 | "Today, there's neither." 26 | He said the disappearance of bars was understandable. 27 | "People socialize in a different way" nowadays, he said. 28 | "Bars are no longer neighborhood living rooms where people go on a regular basis." 29 | As for churches, he worries that the money from selling assets will not last as long as leaders expect it to, "and sooner or later they'll be right back where they started." 30 | Churches, he added, could be replaced by apartment buildings with condominiums filled with the kind of people who will not help the neighborhood's remaining sanctuaries. 31 | "The overwhelming majority of people who buy condominiums in these buildings will be white," he said, "and therefore will hasten the day that these churches close altogether because it is unlikely that most of these people who move into these condominiums will become members of these churches." 32 | Both churches were built by white congregations before Harlem became a black metropolis - Metropolitan Community in 1870, St. Martin's a decade later. 33 | The original white Methodist congregation moved out in the 1930s. 34 | A black congregation that had been worshiping nearby took title to the building. 35 | St. Martin's was taken over by a black congregation under the Rev. John Howard Johnson, who led a boycott of retailers on 125th Street, a main street for shopping in Harlem, who resisted hiring or promoting blacks. 36 | A fire in 1939 left the building badly damaged, but as Father Johnson's parishioners made plans to rebuild, they commissioned the carillon. 37 | The Rev. David Johnson, Father Johnson's son and successor at St. Martin's, proudly called the carillon "the poor people's bells." 38 | The expert who played the carillon in July called it something else: "A cultural treasure" and "an irreplaceable historical instrument." 39 | The expert, Tiffany Ng of the University of Michigan, also noted that it was the first carillon in the world to be played by a black musician, Dionisio A. Lind, who moved to the larger carillon at the Riverside Church 18 years ago. 40 | Mr. Merriweather said that St. Martin's did not replace him. 41 | What has played out at St. Martin's over the last few months has been a complicated tale of architects and contractors, some brought in by the lay leaders of the church, others by the Episcopal diocese. 42 | The vestry - the parish's governing body, made up of lay leaders - wrote the diocese in July with concerns that the diocese "would seek to pass along the costs" to the vestry, even though the vestry had not been involved in hiring the architects and contractors the diocese sent in. 43 | Some parishioners complained of a lack of transparency on the diocese's part. 44 | Shark injures 13-year-old on lobster dive in California 45 | A shark attacked and injured a 13-year-old boy Saturday while he was diving for lobster in California on the opening day of lobster season, officials said. 46 | The attack occurred just before 7 a.m. near Beacon's Beach in Encinitas. 47 | Chad Hammel told KSWB-TV in San Diego he had been diving with friends for about half an hour Saturday morning when he heard the boy screaming for help and then paddled over with a group to help pull him out of the water. 48 | Hammel said at first he thought it was just excitement of catching a lobster, but then he "realized that he was yelling, 'I got bit! 49 | I got bit!' 50 | His whole clavicle was ripped open," Hammel said he noticed once he got to the boy. 51 | "I yelled at everyone to get out of the water: 'There's a shark in the water!'" Hammel added. 52 | The boy was airlifted to Rady Children's Hospital in San Diego where he is listed in critical condition. 53 | The species of shark responsible for the attack was unknown. 54 | Lifeguard Capt. Larry Giles said at a media briefing that a shark had been spotted in the area a few weeks earlier, but it was determined not to be a dangerous species of shark. 55 | Giles added the victim sustained traumatic injuries to his upper torso area. 56 | Officials shut down beach access from Ponto Beach in Casablad to Swami's in Ecinitas for 48 hours for investigation and safety purposes. 57 | Giles noted that there are more than 135 shark species in the area, but most are not considered dangerous. 58 | Sainsbury's plans push into UK beauty market 59 | Sainsbury's is taking on Boots, Superdrug and Debenhams with department store-style beauty aisles staffed with specialist assistants. 60 | As part of a substantial push into the UK's £2.8bn beauty market, which is continuing to grow while fashion and homeware sales fall back, the larger beauty aisles will be tested out in 11 stores around the country and taken to more stores next year if it proves a success. 61 | The investment in beauty comes as supermarkets hunt for ways to use up shelf space once sued for TVs, microwaves and homeware. 62 | Sainsbury's said it would be doubling the size of its beauty offering to up to 3,000 products, including brands such as Revlon, Essie, Tweezerman and Dr. PawPaw for the first time. 63 | Existing ranges from L'Oreal, Maybelline and Burt's Bees will also get more space with branded areas similar to those found in shops like Boots. 64 | The supermarket is also relaunching its Boutique makeup range so that the majority of products are vegan-friendly - something increasingly demanded by younger shoppers. 65 | In addition, perfume retailer the Fragrance Shop will be testing out concessions in two Sainsbury's stores, the first of which opened in Croydon, south London, last week while a second opens in Selly Oak, Birmingham, later this year. 66 | Online shopping and a shift towards buying small amounts of food daily at local convenience stores means supermarkets are having to do more to persuade people to visit. 67 | Mike Coupe, the chief executive of Sainsbury's, has said the outlets will look increasingly like department stores as the supermarket chain tries to fight back against the discounters Aldi and Lidl with more services and non-food. 68 | Sainsbury's has been putting Argos outlets in hundreds of stores and has also introduced a number of Habitats since it bought both chains two years ago, which it says has bolstered grocery sales and made the acquisitions more profitable. 69 | The supermarket's previous attempt to revamp its beauty and pharmacy departments ended in failure. 70 | Sainsbury's tested a joint venture with Boots in the early 2000s, but the tie-up ended after a row over how to split the revenues from the chemist's stores in its supermarkets. 71 | The new strategy comes after Sainsbury's sold its 281-store pharmacy business to Celesio, the owner of the Lloyds Pharmacy chain, for £125m, three years ago. 72 | It said Lloyds would play a role in the plan, by adding an extended range of luxury skincare brands including La Roche-Posay and Vichy in four stores. 73 | Paul Mills-Hicks, Sainsbury's commercial director, said: "We've transformed the look and feel of our beauty aisles to enhance the environment for our customers. 74 | We've also invested in specially trained colleagues who will be on hand to offer advice. 75 | Our range of brands is designed to suit every need and the alluring environment and convenient locations mean we're now a compelling beauty destination which challenges the old way of shopping." 76 | -------------------------------------------------------------------------------- /leaderboard/testdata/newstest2019.msft-WMT19-document-level.6808.en-de.txt: -------------------------------------------------------------------------------- 1 | Walisische AMs besorgt darüber, dass sie „wie Muppets aussehen“ 2 | Einige AMs sind bestürzt über den Vorschlag, ihren Titel in MWPs (Mitglied des Walisischen Parlaments) zu ändern. 3 | Der Grund dafür sind Pläne, den Namen der Versammlung in das Walisische Parlament zu ändern. 4 | AMs aus dem gesamten politischen Spektrum sind besorgt, dass dies zu Spott führen könnte. 5 | Ein Labour-AM sagte, seine Fraktion sei besorgt darüber, dass „es sich mit Twp und Pwp reimt“. 6 | Für Leser außerhalb von Wales: Auf Walisisch bedeutet twp daft und pwp bedeutet poo. 7 | Ein Plaid-AM sagte, die Gruppe als Ganzes sei „nicht glücklich“ und habe Alternativen vorgeschlagen. 8 | Ein walisischer Konservativer sagte, seine Fraktion sei „aufgeschlossen“ gegenüber der Namensänderung, merkte jedoch an, dass es sich um einen kurzen verbalen Sprung von MWP zu Muppet handelte. 9 | In diesem Zusammenhang wird der walisische Buchstabe w ähnlich wie die Yorkshire-Englische Aussprache des Buchstabens u ausgesprochen. 10 | Die Versammlungskommission, die derzeit Rechtsvorschriften zur Einführung der Namensänderung ausarbeitet, sagte: „Die endgültige Entscheidung über die Bezeichnung der Mitglieder der Versammlung wird natürlich Sache der Mitglieder selbst sein“. 11 | Der Government of Wales Act 2017 gab der walisischen Versammlung die Befugnis, ihren Namen zu ändern. 12 | Im Juni veröffentlichte die Kommission die Ergebnisse einer öffentlichen Konsultation zu den Vorschlägen, die breite Unterstützung für die Bezeichnung der Versammlung als walisisches Parlament fand. 13 | In der Frage des Titels der AMs favorisierte die Kommission walisische Parlamentsmitglieder oder WMPs, aber die MWP-Option erhielt in einer öffentlichen Konsultation die meiste Unterstützung. 14 | Die AMs schlagen offenbar alternative Optionen vor, aber das Ringen um einen Konsens könnte dem Vorsitzenden, Elin Jones, Kopfzerbrechen bereiten, von dem erwartet wird, dass er innerhalb von Wochen einen Gesetzesentwurf zu den Änderungen vorlegt. 15 | Die Rechtsvorschriften zu den Reformen werden weitere Änderungen an der Arbeitsweise der Versammlung beinhalten, darunter Vorschriften über den Ausschluss von AMs und die Gestaltung des Ausschusssystems. 16 | Die AMs werden die Schlussabstimmung über die Frage erhalten, wie sie bei der Debatte über die Rechtsvorschriften genannt werden sollten. 17 | Mazedonier gehen bei Referendum über Namensänderung an die Urnen 18 | Die Wähler werden am Sonntag darüber abstimmen, ob sie den Namen ihres Landes in „Republik Nordmakedonien“ ändern wollen. 19 | Die Volksabstimmung wurde mit dem Ziel durchgeführt, einen jahrzehntelangen Streit mit dem Nachbarland Griechenland zu lösen, das eine eigene Provinz namens Mazedonien hat. 20 | Athen besteht seit langem darauf, dass der Name seines nördlichen Nachbarn einen Anspruch auf sein Territorium darstellt, und hat wiederholt Einspruch gegen seine Beitrittsgesuche für die EU und die NATO erhoben. 21 | Der mazedonische Präsident Gjorge Ivanov, ein Gegner der Volksabstimmung über die Namensänderung, hat erklärt, er werde die Abstimmung missachten. 22 | Die Befürworter des Referendums, darunter Ministerpräsident Zoran Zaev, argumentieren jedoch, dass die Namensänderung einfach der Preis sei, den man zahlen müsse, um der EU und der NATO beizutreten. 23 | Die Glocken von St. Martin verstummen, während die Kirchen in Harlem kämpfen 24 | „Historisch gesehen sagen die alten Leute, mit denen ich gesprochen habe, dass es an jeder Ecke eine Bar und eine Kirche gab“, sagte Mr. Adams. 25 | „Heute gibt es weder das eine noch das andere“. 26 | Er sagte, das Verschwinden der Bars sei verständlich. 27 | „Die Menschen sozialisieren sich heute auf eine andere Weise“, sagte er. 28 | „Bars sind keine Nachbarschaftswohnzimmer mehr, in die die Menschen regelmäßig gehen“. 29 | Was die Kirchen angeht, so sorgt er sich, dass das Geld aus dem Verkauf von Vermögenswerten nicht so lange halten wird, wie die Politiker es erwarten, „und früher oder später werden sie wieder da sein, wo sie angefangen haben“. 30 | Kirchen, fügte er hinzu, könnten durch Mehrfamilienhäuser mit Eigentumswohnungen ersetzt werden, die mit der Art von Menschen gefüllt sind, die den verbliebenen Heiligtümern der Nachbarschaft nicht helfen werden. 31 | „Die überwältigende Mehrheit der Menschen, die Eigentumswohnungen in diesen Gebäuden kaufen, werden weiß sein“, sagte er, „und werden daher den Tag beschleunigen, an dem diese Kirchen ganz geschlossen werden, weil es unwahrscheinlich ist, dass die meisten dieser Menschen, die in diese Eigentumswohnungen ziehen, Mitglieder dieser Kirchen werden“. 32 | Beide Kirchen wurden von weißen Gemeinden gebaut, bevor Harlem eine schwarze Metropole wurde – Metropolitan Community 1870, St. Martin's ein Jahrzehnt später. 33 | Die ursprüngliche weiße methodistische Gemeinde zog in den 1930er Jahren aus. 34 | Eine schwarze Gemeinde, die in der Nähe angebetet hatte, übernahm den Titel des Gebäudes. 35 | St. Martin's wurde von einer schwarzen Gemeinde unter Rev. John Howard Johnson übernommen, der einen Boykott von Einzelhändlern in der 125th Street, einer Haupteinkaufsstraße in Harlem, anführte, die sich weigerten, Schwarze einzustellen oder zu fördern. 36 | Ein Brand im Jahr 1939 hat das Gebäude schwer beschädigt, aber als die Gemeindemitglieder von Pater Johnson Pläne zum Wiederaufbau machten, beauftragten sie das Glockenspiel. 37 | Rev. David Johnson, Pater Johnsons Sohn und Nachfolger bei St. Martin's, nannte das Glockenspiel stolz „die Glocken der Armen“. 38 | Der Experte, der das Glockenspiel im Juli spielte, nannte es etwas anderes: „Ein kultureller Schatz“ und „ein unersetzliches historisches Instrument“. 39 | Der Experte, Tiffany Ng von der University of Michigan, merkte auch an, dass es das erste Glockenspiel der Welt war, das von einem schwarzen Musiker gespielt wurde, Dionisio A. Lind, der vor 18 Jahren in das größere Glockenspiel in der Riverside Church umzog. 40 | Mr. Merriweather sagte, dass St. Martin's ihn nicht ersetzte. 41 | Was sich in St. Martin's in den letzten Monaten abgespielt hat, war eine komplizierte Geschichte von Architekten und Auftragnehmern, einige von den Laienführern der Kirche, andere von der Bischofsdiözese. 42 | Die Sakristei – das Leitungsgremium der Pfarrei, das aus Laienführern besteht – schrieb die Diözese im Juli mit der Sorge, dass die Diözese versuchen würde, „die Kosten“ an die Sakristei weiterzugeben, obwohl die Sakristei nicht an der Einstellung der Architekten und Auftragnehmer beteiligt war, die von der Diözese entsandt wurden. 43 | Einige Gemeindemitglieder beschwerten sich über einen Mangel an Transparenz auf Seiten der Diözese. 44 | Hai verletzt 13-Jährigen beim Hummertauchen in Kalifornien 45 | Ein Hai hat am Samstag einen 13-jährigen Jungen beim Hummertauchen in Kalifornien am Eröffnungstag der Hummersaison angegriffen und verletzt, sagten Beamte. 46 | Der Angriff ereignete sich kurz vor 7 Uhr morgens in der Nähe von Beacon's Beach in Encinitas. 47 | Chad Hammel erzählte KSWB-TV in San Diego, dass er am Samstagmorgen etwa eine halbe Stunde lang mit Freunden getaucht sei, als er den Jungen um Hilfe schreien hörte und dann mit einer Gruppe paddelte, um ihn aus dem Wasser zu ziehen. 48 | Hammel sagte zunächst, dass er dachte, es sei nur Aufregung, einen Hummer zu fangen, aber dann „erkennte er, dass er schrie: 'Ich habe Biss! 49 | Ich habe Biss!' 50 | Sein ganzes Schlüsselbein wurde aufgerissen“, sagte Hammel, als er zu dem Jungen kam. 51 | „Ich schrie alle an, um aus dem Wasser zu kommen: 'Da ist ein Hai im Wasser!'“ fügte Hammel hinzu. 52 | Der Junge wurde in das Rady Children's Hospital in San Diego gebracht, wo er in einem kritischen Zustand ist. 53 | Die für den Angriff verantwortliche Haiart war unbekannt. 54 | Rettungsschwimmer Capt. Larry Giles sagte bei einem Medienbriefing, dass ein Hai in dem Gebiet einige Wochen zuvor gesichtet worden war, aber es wurde festgestellt, dass es sich nicht um eine gefährliche Haiart handelt. 55 | Giles fügte hinzu, dass das Opfer traumatische Verletzungen an seinem Oberkörperbereich erlitt. 56 | Die Beamten sperrten den Zugang zum Strand von Ponto Beach in Casablad nach Swami's in Ecinitas für 48 Stunden zu Untersuchungs- und Sicherheitszwecken. 57 | Giles stellte fest, dass es mehr als 135 Haiarten in dem Gebiet gibt, aber die meisten gelten nicht als gefährlich. 58 | Sainsbury's plant Vorstoß in den britischen Beauty-Markt 59 | Sainsbury's übernimmt Boots, Superdrug und Debenhams mit Beauty-Gängen im Kaufhausstil, die mit spezialisierten Assistenten besetzt sind. 60 | Als Teil eines erheblichen Vorstoßes in den britischen Beauty-Markt im Wert von 2,8 Mrd. GBP, der weiter wächst, während die Mode- und Haushaltswarenverkäufe zurückgehen, werden die größeren Beauty-Gänge in 11 Geschäften im ganzen Land getestet und im nächsten Jahr in weitere Läden gebracht, wenn sich dies als Erfolg erweist. 61 | Die Investition in Beauty kommt, während Supermärkte nach Möglichkeiten suchen, Regalflächen aufzubrauchen, die einst für Fernseher, Mikrowellen und Haushaltswaren verklagt wurden. 62 | Sainsbury's erklärte, es werde die Größe seines Beauty-Angebots auf bis zu 3.000 Produkte verdoppeln, darunter zum ersten Mal Marken wie Revlon, Essie, Tweezerman und Dr. PawPaw. 63 | Bestehende Sortimente von L'Oreal, Maybelline und Burt's Bees werden auch mehr Platz mit Markenbereichen erhalten, die denen in Geschäften wie Boots ähneln. 64 | Der Supermarkt bringt auch sein Boutique-Make-up-Sortiment neu auf den Markt, so dass die Mehrheit der Produkte vegan-freundlich ist – etwas, das von jüngeren Käufern zunehmend verlangt wird. 65 | Darüber hinaus wird der Parfümhändler Fragrance Shop Konzessionen in zwei Sainsbury's-Geschäften testen, von denen das erste letzte Woche in Croydon, Südlondon, eröffnet wurde, während ein zweites Ende dieses Jahres in Selly Oak, Birmingham, eröffnet wird. 66 | Online-Shopping und eine Verlagerung hin zum täglichen Einkauf kleiner Mengen von Lebensmitteln in lokalen Convenience-Stores bedeutet, dass Supermärkte mehr tun müssen, um die Menschen zum Besuch zu bewegen. 67 | Mike Coupe, der Geschäftsführer von Sainsbury's, sagte, dass die Verkaufsstellen zunehmend wie Kaufhäuser aussehen werden, da die Supermarktkette versucht, sich gegen die Discounter Aldi und Lidl mit mehr Dienstleistungen und Non-Food zu wehren. 68 | Sainsbury's hat Argos-Geschäfte in hunderten von Geschäften eingerichtet und auch eine Reihe von Habitats eingeführt, seit es vor zwei Jahren beide Ketten gekauft hat, was, wie es heißt, die Lebensmittelverkäufe gestärkt und die Akquisitionen profitabler gemacht hat. 69 | Der frühere Versuch des Supermarktes, seine Beauty- und Apothekenabteilungen umzugestalten, scheiterte. 70 | Sainsbury's testete Anfang der 2000er Jahre ein Joint Venture mit Boots, aber die Bindung endete nach einem Streit darüber, wie die Einnahmen aus den Apothekengeschäften in seinen Supermärkten aufgeteilt werden sollten. 71 | Die neue Strategie kommt, nachdem Sainsbury's vor drei Jahren sein 281-Store-Apothekengeschäft an Celesio, den Eigentümer der Lloyds Pharmacy-Kette, für 125 Mio. GBP verkaufte. 72 | Es hieß, dass Lloyds eine Rolle in dem Plan spielen würde, indem es eine erweiterte Palette von Luxus-Hautpflegemarken einschließlich La Roche-Posay und Vichy in vier Geschäften hinzufügte. 73 | Paul Mills-Hicks, der kaufmännische Direktor von Sainsbury's, sagte: „Wir haben das Aussehen und das Gefühl unserer Beauty-Gänge verändert, um das Umfeld für unsere Kunden zu verbessern. 74 | Wir haben auch in speziell ausgebildete Kollegen investiert, die zur Verfügung stehen werden, um Ratschläge zu erteilen. 75 | Unsere Markenpalette ist für jeden Bedarf ausgelegt, und die verlockende Umgebung und die günstigen Lagen bedeuten, dass wir jetzt ein überzeugendes Beauty-Reiseziel sind, das die alte Art des Einkaufens herausfordert“. 76 | -------------------------------------------------------------------------------- /leaderboard/testdata/newstest2019.msft-WMT19-sentence-level.6785.en-de.txt: -------------------------------------------------------------------------------- 1 | Welsh AMs besorgt über 'aussehen wie Muppets' 2 | Es gibt Bestürzung unter einigen AMs über einen Vorschlag, ihren Titel in MWPs (Mitglied des walisischen Parlaments) zu ändern. 3 | Es ist aufgrund von Plänen entstanden, den Namen der Versammlung in das walisische Parlament zu ändern. 4 | AMs aus dem gesamten politischen Spektrum sind besorgt, dass es zum Spott einladen könnte. 5 | Ein Labour AM sagte, seine Gruppe sei besorgt, „es reimt sich mit Twp und Pwp“. 6 | Für Leser außerhalb von Wales: In Walisisch bedeutet twp daft und pwp poo. 7 | Ein Plaid AM sagte, die Gruppe als Ganzes sei „nicht glücklich“ und habe Alternativen vorgeschlagen. 8 | Ein walisischer Konservativer sagte, seine Fraktion sei „offen“ über die Namensänderung, merkte aber an, dass es ein kurzer verbaler Sprung von MWP zu Muppet war. 9 | In diesem Zusammenhang wird der walisische Buchstabe w ähnlich wie die Yorkshire-englische Aussprache des Buchstabens u ausgesprochen. 10 | Die Vollversammlungskommission, die derzeit ein Gesetz zur Einführung der Namensänderungen ausarbeitet, sagte: „Die endgültige Entscheidung über alle Deskriptoren dessen, was Vollversammlungsmitglieder genannt werden, wird selbstverständlich eine Angelegenheit der Mitglieder selbst sein“. 11 | Der Government of Wales Act 2017 gab der walisischen Versammlung die Befugnis, ihren Namen zu ändern. 12 | Im Juni veröffentlichte die Kommission die Ergebnisse einer öffentlichen Konsultation zu den Vorschlägen, die breite Unterstützung für die Einberufung der Versammlung in ein walisisches Parlament fanden. 13 | Was den Titel der AM betrifft, so bevorzugte die Kommission walisische Parlamentsabgeordnete oder WMPs, aber die MWP-Option erhielt in einer öffentlichen Konsultation die größte Unterstützung. 14 | AMs schlagen anscheinend alternative Optionen vor, aber das Ringen um einen Konsens könnte dem Vorsitzenden Elin Jones Kopfzerbrechen bereiten, der innerhalb von Wochen Gesetzesentwürfe zu den Änderungen vorlegen soll. 15 | Die Rechtsvorschriften zu den Reformen werden weitere Änderungen an der Arbeitsweise der Versammlung beinhalten, darunter Vorschriften über den Ausschluss von AMs und die Ausgestaltung des Ausschusssystems. 16 | AMs werden die Schlussabstimmung über die Frage erhalten, wie sie genannt werden sollten, wenn sie über die Rechtsvorschriften debattieren. 17 | Mazedonier gehen an die Urnen in Referendum über die Änderung des Namens des Landes 18 | Die Wähler werden am Sonntag darüber abstimmen, ob sie den Namen ihres Landes in „Republik Nordmakedonien“ ändern wollen. 19 | Die Volksabstimmung wurde ins Leben gerufen, um einen jahrzehntelangen Streit mit dem benachbarten Griechenland zu lösen, das eine eigene Provinz namens Mazedonien hat. 20 | Athen besteht seit langem darauf, dass der Name seines nördlichen Nachbarn einen Anspruch auf sein Territorium darstellt, und hat wiederholt Einwände gegen seine Beitrittsgesuche für die EU und die NATO erhoben. 21 | Der mazedonische Präsident Gjorge Ivanov, ein Gegner der Volksabstimmung über die Namensänderung, hat erklärt, er werde die Abstimmung missachten. 22 | Die Befürworter des Referendums, darunter Premierminister Zoran Zaev, argumentieren jedoch, dass die Namensänderung lediglich der Preis sei, den man für den Beitritt zur EU und zur NATO zahlen müsse. 23 | Die Glocken von St. Martins Fall schweigen als Kirchen in Harlem Kampf 24 | „Historisch gesehen haben die alten Leute, mit denen ich gesprochen habe, gesagt, dass es an jeder Ecke eine Bar und eine Kirche gab“, sagte Herr Adams. 25 | „Heute gibt es weder das eine noch das andere“. 26 | Er sagte, das Verschwinden von Bars sei verständlich. 27 | „Die Menschen sozialisieren sich heute auf eine andere Weise“, sagte er. 28 | „Bars sind keine Nachbarschafts-Wohnzimmer mehr, in die die Leute regelmäßig gehen“. 29 | Was die Kirchen angeht, so befürchtet er, dass das Geld aus dem Verkauf von Vermögenswerten nicht so lange reichen wird, wie die Führer es erwarten, „und früher oder später werden sie wieder da sein, wo sie angefangen haben“. 30 | Kirchen, fügte er hinzu, könnten durch Mehrfamilienhäuser mit Eigentumswohnungen ersetzt werden, die mit der Art von Menschen gefüllt sind, die den verbleibenden Heiligtümern des Viertels nicht helfen werden. 31 | „Die überwältigende Mehrheit der Menschen, die Eigentumswohnungen in diesen Gebäuden kaufen, wird weiß sein“, sagte er, „und wird daher den Tag beschleunigen, an dem diese Kirchen ganz schließen, weil es unwahrscheinlich ist, dass die meisten dieser Menschen, die in diese Eigentumswohnungen einziehen, Mitglieder dieser Kirchen werden“. 32 | Beide Kirchen wurden von weißen Gemeinden gebaut, bevor Harlem eine schwarze Metropole wurde – Metropolitan Community 1870, St. Martin's ein Jahrzehnt später. 33 | Die ursprüngliche weiße Methodisten-Gemeinde zog in den 1930er Jahren aus. 34 | Eine schwarze Gemeinde, die in der Nähe angebetet hatte, übernahm den Titel des Gebäudes. 35 | St. Martin's wurde von einer schwarzen Gemeinde unter Rev. John Howard Johnson übernommen, der einen Boykott von Einzelhändlern auf der 125th Street, einer Hauptstraße zum Einkaufen in Harlem, führte, die sich der Einstellung oder Förderung von Schwarzen widersetzten. 36 | Ein Brand im Jahre 1939 hinterließ das Gebäude schwer beschädigt, aber als Pfarrangehörige von Pater Johnson Pläne zum Wiederaufbau machten, gaben sie das Glockenspiel in Auftrag. 37 | Rev. David Johnson, Vater Johnsons Sohn und Nachfolger bei St. Martin, nannte das Glockenspiel stolz „die Glocken der armen Leute“. 38 | Der Experte, der das Carillon im Juli spielte, nannte es etwas anderes: „Ein Kulturschatz“ und „ein unersetzliches historisches Instrument“. 39 | Der Experte, Tiffany Ng von der University of Michigan, bemerkte auch, dass es das erste Carillon der Welt war, das von einem schwarzen Musiker, Dionisio A. Lind, gespielt wurde, der vor 18 Jahren in das größere Carillon an der Riverside Church umzog. 40 | Herr Merriweather sagte, dass St. Martin's ihn nicht ersetzt habe. 41 | Was sich in den letzten Monaten in St. Martin abgespielt hat, war eine komplizierte Geschichte von Architekten und Bauunternehmern, von denen einige von den Laienführern der Kirche, andere von der Bischofsdiözese eingebracht wurden. 42 | Die Sakristei – das Leitungsgremium der Pfarrei, das sich aus Laienführern zusammensetzt – schrieb der Diözese im Juli mit der Befürchtung, dass die Diözese versuchen würde, die Kosten auf die Sakristei abzuwälzen, obwohl die Sakristei nicht an der Einstellung der von der Diözese entsandten Architekten und Bauunternehmer beteiligt gewesen sei. 43 | Einige Gemeindemitglieder beklagten sich über mangelnde Transparenz seitens der Diözese. 44 | Hai verletzt 13-Jährigen bei Hummer-Tauchgang in Kalifornien 45 | Ein Hai angegriffen und verletzt einen 13-jährigen Jungen Samstag, während er für Hummer in Kalifornien am Eröffnungstag der Hummersaison tauchen, sagten Beamte. 46 | Der Angriff ereignete sich kurz vor 7 Uhr morgens in der Nähe von Beacon's Beach in Encinitas. 47 | Chad Hammel erzählte KSWB-TV in San Diego, dass er am Samstagmorgen etwa eine halbe Stunde mit Freunden getaucht war, als er den Jungen um Hilfe schreien hörte und dann mit einer Gruppe hinüberpaddelte, um ihn aus dem Wasser zu ziehen. 48 | Hammel sagte zunächst, er dachte, es sei nur Aufregung, einen Hummer zu fangen, aber dann „erkannte er, dass er schrie: 'Ich habe gebissen! 49 | Ich habe gebissen!' 50 | Sein ganzes Schlüsselbein war aufgerissen“, sagte Hammel, als er zu dem Jungen kam. 51 | „Ich schrie alle an, um aus dem Wasser zu kommen: 'Da ist ein Hai im Wasser!'“, fügte Hammel hinzu. 52 | Der Junge wurde ins Rady Children's Hospital in San Diego geflogen, wo er in kritischem Zustand gelistet ist. 53 | Die Haiart, die für den Angriff verantwortlich war, war unbekannt. 54 | Rettungsschwimmer Capt. Larry Giles sagte bei einem Medienbriefing, dass ein Hai in der Gegend ein paar Wochen zuvor gesichtet worden war, aber es wurde festgestellt, nicht eine gefährliche Haiart zu sein. 55 | Giles fügte hinzu, das Opfer erlitt traumatische Verletzungen an seinem oberen Oberkörperbereich. 56 | Beamte sperrten den Strandzugang von Ponto Beach in Casablad zu Swami's in Ecinitas für 48 Stunden für Ermittlungs- und Sicherheitszwecke. 57 | Giles darauf hingewiesen, dass es mehr als 135 Haiarten in der Gegend, aber die meisten sind nicht als gefährlich. 58 | Sainsburys Pläne drängen in den britischen Schönheitsmarkt 59 | Sainsbury's nimmt Boots, Superdrug und Debenhams mit Kaufhaus-Stil Schönheit Gänge mit spezialisierten Assistenten besetzt. 60 | Als Teil eines erheblichen Vorstoßes in den britischen Schönheitsmarkt mit einem Volumen von 2,8 Mrd. Pfund, der weiter wächst, während die Verkäufe von Mode und Haushaltswaren zurückgehen, werden die größeren Beauty-Gänge in 11 Geschäften im ganzen Land getestet und im nächsten Jahr in weitere Läden gebracht, wenn sich dies als Erfolg erweist. 61 | Die Investition in Schönheit kommt als Supermärkte Jagd nach Möglichkeiten, um bis Regalplatz einmal verklagt für TVs, Mikrowellen und Haushaltswaren zu verwenden. 62 | Sainsbury's sagte, es wäre die Verdoppelung der Größe seines Beauty-Angebot auf bis zu 3.000 Produkte, darunter Marken wie Revlon, Essie, Tweezerman und Dr. PawPaw zum ersten Mal. 63 | Bestehende Sortimente von L'Oreal, Maybelline und Burt's Bees erhalten ebenfalls mehr Platz mit Markenbereichen, die denen in Geschäften wie Boots ähneln. 64 | Zudem bringt der Supermarkt sein Boutique-Make-up-Sortiment neu auf den Markt, so dass die meisten Produkte vegan-freundlich sind – was zunehmend von jüngeren Käufern nachgefragt wird. 65 | Darüber hinaus wird der Parfümhändler Fragrance Shop Konzessionen in zwei Sainsbury's Stores testen, von denen der erste letzte Woche in Croydon, Süd-London, eröffnete, während ein zweiter in Selly Oak, Birmingham, später in diesem Jahr eröffnet. 66 | Online-Shopping und eine Verschiebung hin zum Kauf kleiner Mengen von Lebensmitteln täglich in lokalen Convenience-Stores bedeutet, Supermärkte müssen mehr tun, um die Menschen zu überzeugen, zu besuchen. 67 | Mike Coupe, der Vorstandsvorsitzende von Sainsbury's, hat gesagt, dass die Verkaufsstellen zunehmend wie Kaufhäuser aussehen werden, da die Supermarktkette versucht, sich mit mehr Dienstleistungen und Non-Food gegen die Discounter Aldi und Lidl zu wehren. 68 | Sainsbury's hat Argos-Filialen in Hunderten von Geschäften platziert und auch eine Reihe von Habitats eingeführt, seit es beide Ketten vor zwei Jahren gekauft hat, was, wie es sagt, die Lebensmittelverkäufe gestärkt und die Akquisitionen profitabler gemacht hat. 69 | Der frühere Versuch des Supermarktes, seine Schönheits- und Apothekenabteilungen umzugestalten, scheiterte. 70 | Sainsbury's testete ein Joint Venture mit Boots in den frühen 2000er Jahren, aber die Krawatte endete nach einem Streit darüber, wie man die Einnahmen aus den Apotheken in seinen Supermärkten zu teilen. 71 | Die neue Strategie kommt, nachdem Sainsbury's vor drei Jahren sein 281-Store-Apothekengeschäft für 125 Millionen Pfund an Celesio, den Eigentümer der Lloyds-Apothekenkette, verkauft hatte. 72 | Lloyds werde eine Rolle in dem Plan spielen, indem es eine erweiterte Palette von Luxus-Hautpflege-Marken wie La Roche-Posay und Vichy in vier Filialen hinzufüge. 73 | Paul Mills-Hicks, kaufmännischer Direktor von Sainsbury, sagte: „Wir haben das Aussehen und die Haptik unserer Beauty-Gänge verändert, um die Umwelt für unsere Kunden zu verbessern. 74 | Wir haben auch in speziell geschulte Kollegen investiert, die mit Rat und Tat zur Seite stehen. 75 | Unsere Markenpalette ist auf jeden Bedarf zugeschnitten und die verführerische Umgebung und die günstigen Lagen machen uns zu einem attraktiven Beauty-Destination, die die alte Art des Einkaufens herausfordert“. 76 | -------------------------------------------------------------------------------- /leaderboard/testdata/xml/sample-hyp.ha.txt: -------------------------------------------------------------------------------- 1 | Jeetandra, Ekata Shobha da kuma Tusshar Kapoor sun tuna kasaita ciki 2 | Jarumin Tusshar fina-finai Kapoor a ranar Lahadi ya yada wasu hotuna kuciyarsa cikin kasaita don murnar bikin zagayowar ranara duniya. ta 3 | Jarumin yada ya wasu jerin hotuna da suka kunshi hotunansa yana yaro shi da mahaifinsa Jeetendra da babansa Shobha da kuma kuna kaawarsa Ekta Kapoor da kuma wani na baya-bayannan da ke dauke da dansa. da 4 | A hoton tsohon maras launi, an ga jarumi Jeetendra ya yi tsayuwar daukar hoto yana rike dan jariri Tusshar da Ekta hannunsa. a 5 | Ana ganin iya matar Jeetendra a tsaye kusa da mutanen uku hoton. cikin 6 | A na hoto biyu Tusshar Kappor da dansa Laksshya na tsaye cikin fara'a da annashuwa Kamara. kallon 7 | A da rubutun ya saka a jikin hoton da ya yada, ya rubuta "Ina taya ku murnar zagayowar ranar iyaye" da 8 | Tusshar yana Kapoor zaune da 'ya'yansa uwa. ba 9 | An Lakshiya haifi ne ta hanyar daukar cikinta a wajen mahaifa 2016. shakarar 10 | Wadansu jarimin lokutan na yada hotunan da bidiyon karamin dan na sa a shafukan sada Instagram. na 11 | A aiki bangaren kuwa, ganin karshe da aka yiwa Tusshar Kapoor shine Phategi. Sabki 12 | Ana ran sa sake ganinsa ne a fim din 'Laxmmi Bomb' wanda Raghava Lawarence ya umarni. da 13 | A fin cikin din da akwai kuma Akshay Kumar Advani. Kiara 14 | A bangaren daya kuma Ekita Kapoor ya shirya wasu shirya-shiryen Talbijin da kuma Fim kamar su Dream Girl da Hum Paanch da Dolly Kitty aur Chamakte Sitare, da Ye Hai Mohabbatein, da Kahaani Ghar Ghar Kii da kuma sauransu. da 15 | An gada gina ta farko a aikin jirgi mai tafiya a kasrkashin kasa na Delhi a kashin 4 na 16 | Aikin jirgi gina mai tafiya a karkashin kasa na birni Delhi ya cimma wani mataki mai muhimmanci yayin da ya shiga wani kashi a aikin-4 yayin da a ka gina gada ta farko a kan mashigar yamma na Janakpurita R K Ashram Marg, A cewar wasu jami'ai Lahadi. ranar 17 | An aikln yi gadar ne a Keshopur a kan wani tudu da ke tsaknin Keshpur da Mukaba Chowks Asabar. daren 18 | "Hukumar Jirgin kula karkashin kasa ta birnin Delhi ta sake samun kai wa ga wani babban mataki na 4 aikin da ta ke yi na fadada layin dogo na karkashin kasa da samun nasarar ginin karfe na wata gada a wata mashiga hanyar jirgin karakashin kasa ta yamma a Janakpuri RK Astta Marg," a cewar wata sanarawa da Hukumar fitar. ta 19 | Wannan nasara "babban da aka samu a wannan aikin ginin layin dogo" an same ta ne duk da karancin ma'aikata da kuma wasu matsalolin jigila da kai-kawo saboda annobar cuta da ake fama da ita, a jami'i. wani 20 | Matsakaicin wannan tsayin gada ta wannan mashiga 10. mita 21 | Sai sauran daia gadojin zasu zama masu tsawon mita 20 a Madhun Chowk (wurin tsallakawa n a 1)da kuma mita 25 a Haderpur Badli Mor a inda wannan layin dogo zai tsallaka wani layin 2. na 22 | A pur Haider, Mor, gadar da za ta dauki layin dogon da zai wuce ta wurin zai kasance mita 28, wanna shine mafi girma a tarihin layin dogo na birni Delhi, sanarwar. cewar 23 | A dai yanzu wuri ma fi tsawo shine wanda ya ke Dhaula Kuan, a inda layin dogo na 7 da ke kan gada ya wuce har 23.6. mita 24 | A kimiyyar tsarin gine-gine ana yin ginshikin gine-gine ne a tsatstsaye domin su tallafin nauyin ginin da ke zama kamar gada a kan ginshikan biyu na gefe. da 25 | Wadannan suka su zama kamar ginshikan da suka tallafi tudun da aka dora layin dogon mai kai. a 26 | Gadojin a da ka dora layin dogo na jirgin karkashi kasa da dora su a tsakiyar hanyoyin mota a birnin Delhi ta kan su ne aka giggina mashigar kasa. karkshin 27 | Yawanci gadojin wadannan sun sa sun zama fittatun kuma ababen kwantace a wajen bayar da adireshi Delhi. birnin 28 | Mashigar dogo layin ta Janakpurin yamma - RK Ahsram ita ce ma fi tsawo da tsawon kilomita 28.92, ita ce karin layin dogo na MAgenta za ta kuma 22. tashohi 29 | Yayin kilolmita da 21.18 na wannan mashigar za a daga shi, yayin da 7.74 kilomita na wannan layi zai kasance kasa. karkashin 30 | An aikin soma ginin wannan sashi a watan Disambar shekarar wuce. ta 31 | A 17 ranar ga watan Yuli, a ka soma aikin ginin sashen karkashin kasa na mashigar wanda aka fara da gina bangon D a tashar jirgin karkashin kasa na Krishna. shakatawar 32 | A 24 ranar ga watan Yuli, Hukumar ta DMRC ta soma kakkafa karafunan zuba kankaren durakai da kuma ginshikai don daga layin dogon wannan bangare na dogon. layin 33 | A wanna karkashin rukunin aiki na 4, kilomita 61. 679 na sabbin layukan dogo za a giggina a kan mashigai daban-daban guda uku da za su kunsh tasoshi 45 na kasa. kakshin 34 | Wannan sashi sabon zai samar da wata babbar mahada a tsakanin shiyoyin daban-daban na jiragen karkashin kasa na Delhi. na 35 | A wannan cikin adadi, Kilomita 22.35 duk za su kasance a karkashin kasa ne yayin da sauran za su kasance gadoji. kan 36 | Fiye cutar da Koronabirus dubu 13.85 ne a Indiya har zuwa yanzu, mutane 32,063 suka mutu, kashi 63.91% warke suka 37 | Adadin 8,85,577 mutane ne suka warke kuma adadin kaso da suka warke ya kai kashi dari. cikin 38 | Garin Delhi: New Indiya ta ba da rahoton wadanda suka kamu da kwayar cutar ta coronabirus 48,661 a cikin awanni 24 da suka gabata, suna ɗaukar jimillar zuwa 13,85,522, kamar yadda bayanan nuna. sun 39 | Adadin suka wadanda mutu ya haura 32,063, a inda mutane 705 suka mutu a cikin awanni 24 gabata. suka 40 | Adadin suka wadanda kamu da kwayar cutar coronabirus ya ninka sau biyu a kusan makonni uku tun daga ranar 2 ga watan Yulin, a lokacin da kasar ta tsallake matakin shida. dari 41 | Yawan na adadi wadanda suka kamu da cutar Covid-19 na kasar ya kai makin dubu dari a ranar Juma'ar gabata. ta 42 | Tun wannan daga lokacin, an sami rahoton sabbin kamuwa da ya kai dubu uku. Wannan ita ce rana ta huɗu a jere lokacin da masu kamuwa da cutar COVID-19 suka ƙaru da 45,000. da 43 | Maharashtra ranar a Asabar ta ba da rahoton sabbin kamuwa da cutar 9,251 wadanda suka kamu da cutar ta COVID-19, inda suka dauki adadin a jihar zuwa 3,66,368 yayin da wadanda suka mutu suka kai 257, ciki har da 116 a yankin Mumbai yakin tsakiyar birni (MMR), zuwa 13,389, in ji Ma'aikatar Kiwon jihar. ta 44 | An adadin sallami marasa lafiya 7,227 a rana, inda aka dauki adadin wadanda suka 2,07,194. zuwa 45 | Kimanin lafiya marasa dubu 8.85 ne suka warke ya zuwa yanzu; darajar farfadowa ya tsaya a kashi 63.91 bisa dari yau. safiyar 46 | Kaso yawan na wadanda suka kamu da cutar - yawan marasa lafiya waɗanda aka gwada aka kuma tabbatar sun kamu da kwayar cutar - shine kashi ɗari. cikin 47 | A wannan farkon makon ne, gwamnati ta ce tana da niyyar saukar da adadin wadanda suka kamu da ƙimar zuwa kashi 100. cikin 48 | Jihar a Karnataka ranar Asabar ya yi rajistar a sabbin wadanda suka kamu da cutar ta Koronavirus 5,000 a rana ta uku a jere, wanda hakan ya kai adadin ya haura daya. baki 49 | A kadai Bengaluru an bayar da rahoton sabbin mutanen da suka kamu da cutar zuwa 2,036 da suka kai jimillar 43,503. zuwa 50 | Matsayin Delhi birnin ya haura a cikin yawan wadanda aka samu da cutar COVID-19 kuma a halin yanzu birnin na matsayi na takwas tsakanin jihohi da yankuna da ke karkashin ikon gwmanatin tarayya a kasar, Babban Ministan Arvind Kejriwal ne ya faɗa Asabar. ranar 51 | A wani cikin karuwar adadi da aka taba samu a rana daya har zuwa yanzu, Kerala a ranar Asabar ta ba da rahoton mutane 1,103 sabbbi da suka kamu da COVID-19, wanada hakan ya daga adadin masu dauke da cutar zuwa 18,098, yayin da sama da dubban mutane 1.5 ake su. da 52 | Kimanin 9,420 mutane ne ke karbar Koronabirus. cutar 53 | Yawan suka wadanda kanu da cutar Coronavirus a Tamil Nadu ya tsallake makin dubu dari tare da sabbin wadanda suka kamuwa da cutar 6,989 da aka rawaito a cikin awanni 24 da suka gabata, wanda kuma shi ne mafi girma a rana guda, kamar yadda bayanan nuna. ya 54 | Mutane da tamanin tara sun mutu kuma 7,758 sun warke a cikin awanni 24 gabata. suka 55 | Yawana wadanda adadin suka kamu a yanzu 2,06,737. kai 56 | Gujarat ranar a Asabar ta shigar da bayanai mafi yawaa rana guda na adadin wadanda suka kamu da cutar Koronavirus da 1,081 na sabbin wadanda suka kamu da cutar, wanda hakan ya kai jimlar zuwa 54,712 yayin da marasa lafiya 22 suka mutu, ciki har da aka samu 11 a cikin Surat, a cewar ma'aikatar kiwon jihar. ta 57 | Babban Maharashtra Ministan Uddhav Thackeray zai ƙaddamar da shirin bayar da gudummawar plasma a ranar 27 ga watan Yuli, bayan "Plasma Daan Sankalp Abhiyan" don binciken farko na marasa lafiyar COVID-19 da suka warke a yankin Mumbai. na 58 | Indiya ta ce uku a cikin kasashe masu fama da cutar Koronavirus a duniya bayan Amurka da Brazil, a hankali ta kara karfin gwajin cutar ta COVID-19 kuma ta gudanar da gwaje-gwaje sama da dubu dari 4.2 a cikin yini daya, Ma'aikatar Lafiya ta Tarayyar ta ce a ranar Asabar, tana mai yaba karuwar tare da danganaa samun wannan nasara ga yawan dakunan gawaje-gwaje samu. aka 59 | Annobar hallaka ta sama da mutane 6,33,000 a fadin duniya tun lokacin da cutar da bayyana a kasar Chima a shekarar da ta wuce, da samun yawan mutane sama da miliyan 15.5 wadanda suka kamu dac cutar, a cewar kamfanin dillancin AFP. na 60 | -------------------------------------------------------------------------------- /leaderboard/testdata/xml/sample-src.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |

6 | Jeetendra, Shobha, Ekta And Tusshar Kapoor In A Major Blast From The Past 7 | Actor Tusshar Kapoor, on Sunday, shared a special blast from the past to celebrate Parents' Day. 8 | The actor shared an album, comprising a throwback picture of himself, his father Jeetendra, mother Shobha and sister Ekta Kapoor, and a recent one featuring his son. 9 | In the old black and white photograph, actor Jeetendra can be seen posing for the camera while holding tiny Tusshar and Ekta Kapoor in his arms. 10 | Jeetendra's wife can be seen standing near the trio in the picture. 11 | In the second photo, Tusshar Kapoor and his son Laksshya can be seen smiling with all their heart for the camera. 12 | Sharing the photos, Tusshar Kapoor captioned it: "Happy Parents' Day." 13 | Tusshar Kapoor is a single parent. 14 | Laksshya was born via surrogacy in the year 2016. 15 | The actor often shares pictures and videos of his little son on Instagram. 16 | In terms of work, Tusshar Kapoor was last seen in Booo Sabki Phategi. 17 | He will be next seen in Laxmmi Bomb, which has been directed by Raghava Lawrence. 18 | The film also features Akshay Kumar and Kiara Advani. 19 | Ekta Kapoor, on the other hand, has produced several television shows and films such as Dream Girl, Hum Paanch, Dolly Kitty Aur Woh Chamakte Sitare, Ye Hai Mohabbatein, Kahaani Ghar Ghar Kii and Kasturi among others. 20 |

21 |
22 |
23 | 24 | 25 |

26 | Delhi Metro Casts First Pier Under Phase-4 Work 27 | The Delhi Metro has reached a major milestone in the Phase-4 work as it cast its first pier on the under-construction Janakpuri West-R K Ashram Marg corridor, officials said on Sunday. 28 | The pier was cast at Keshopur on the elevated stretch between Keshopur and Mukarba Chowk on Saturday night. 29 | "The Delhi Metro Rail Corporation took another important step forward in its Phase 4 construction work as the first pier of this phase of Metro expansion was cast on the Janakpuri West-R K Ashram Marg Metro corridor," the DMRC said in a statement. 30 | This "major construction milestone" has been achieved, despite severe shortage of manpower and other logistical challenges because of the pandemic, officials said. 31 | The average height of piers on this corridor is 10m. 32 | However, piers will be 20m high at Madhuban Chowk (crossing with Line 1) and 25m at Haiderpur Badli Mor where this line will cross Line 2. 33 | At Haiderpur Badli Mor, the viaduct level is going to be at 28m, the highest in the history of Delhi Metro, the statement said. 34 | Presently, the highest point is at Dhaula Kuan, where the Line 7 viaduct passes at a height of 23.6m. 35 | Piers, in terms of civil engineering are vertical loadbearing structures which act as intermediate support for adjacent ends of two spans. 36 | They form the vertical support structures on which the elevated metro viaducts stand. 37 | Metro piers today dot innumerable road medians in Delhi through which elevated Metro corridors run. 38 | Pier numbers are now important landmarks for addresses across the Delhi-NCR. 39 | The 28.92-km-long Janakpuri West-R K Ahsram Marg corridor is an extension of Magenta Line and will come up with 22 stations. 40 | While 21.18 km of this corridor will be elevated, 7.74 km will be underground. 41 | Construction work on this particular section had started in December last year. 42 | On July 17, the work on the underground section of this corridor was commenced with the beginning of D Wall construction work at the Krishna Park Extension Metro station. 43 | On 24th June, DMRC had started the casting work of u-girders which would be installed on the elevated section of this corridor. 44 | Under Phase-4, 61.679 km of new metro lines shall be constructed across three different corridors comprising 45 metro stations. 45 | These new sections shall provide interconnectivity among the already operational sections of Delhi Metro. 46 | Out of this, 22.35 km will be underground while rest will be elevated. 47 |

48 |
49 |
50 | 51 | 52 |

53 | Over 13.85 lakh coronavirus cases in India so far, 32,063 deaths, 63.91% recovery rate 54 | A total of 8,85,577 have recovered and the recovery rate is 63.91 per cent. 55 | New Delhi: India reported 48,661 coronavirus cases in the last 24 hours, taking the total so far to 13,85,522, government data shows. 56 | The number of death have risen to 32,063, with 705 deaths in the last 24 hours. 57 | The number of coronavirus cases have doubled in nearly three weeks since July 2, when the country crossed the six lakh-mark. 58 | The country's Covid tally touched the 10 lakh-mark last Friday. 59 | Since then, around three lakh new infections have been reported.This is the fourth consecutive day when COVID-19 cases increased by more than 45,000. 60 | Maharashtra on Saturday reported 9,251 new COVID-19 cases, taking the cumulative count in the state to 3,66,368 while fatalities mounted by 257, including 116 in Mumbai Metropolitan Region (MMR), to 13,389, the state Health department said. 61 | A record number of 7,227 patients were discharged in the day, taking the count of recovered cases to 2,07,194. 62 | Around 8.85 lakh patients have recovered so far; the recovery rate stood at 63.91 per cent this morning. 63 | The positivity rate - percentage of patients who have tested positive for coronavirus - is 11 per cent. 64 | Earlier this week, the government had said that it aims to bring down the positivity rate to 5 per cent. 65 | Karnataka on Saturday registered over 5,000 new coronavirus cases for the third day in a row, taking its total past 90,000. 66 | Bengaluru alone reported 2,036 new cases taking its overall tally to 43,503. 67 | Delhi has improved its position in the number of active COVID-19 cases and is currently at the eighth spot among states and union territories in the country, Chief Minister Arvind Kejriwal said on Saturday. 68 | In the highest single-day spike till now, Kerala on Saturday reported 1,103 fresh COVID-19 cases taking the infection count to 18,098, while over 1.5 lakh persons are under observation. 69 | As many as 9,420 persons are under treatment for coronavirus. 70 | Coronavirus cases in Tamil Nadu have crossed the two lakh-mark with 6,989 new cases reported in the last 24 hours, which is also the biggest single-day spike, government data shows. 71 | Eighty-nine have died and 7,758 have recovered in the last 24 hours. 72 | The total cases in the state is now 2,06,737. 73 | Gujarat on Saturday logged the highest single-day spike in coronavirus cases with 1,081 new infections, taking the total count to 54,712 while 22 patients died, including 11 in Surat, the state health department said. 74 | Maharashtra Chief Minister Uddhav Thackeray will launch a plasma donation program on July 27, following the "Plasma Daan Sankalp Abhiyan" for primary screening of recovered COVID-19 patients in Dharavi area of Mumbai. 75 | India, the third worst-hit country in the global coronavirus tally after US and Brazil, has gradually ramped-up its COVID-19 testing capacity and has conducted over 4.2 lakh tests in a day, the Union Health Ministry said Saturday, crediting the increase to the number of labs for the achievement. 76 | The pandemic has killed more than 6,33,000 people worldwide since it surfaced in China late last year, with more than 15.5 million people infected, according to news agency AFP. 77 |

78 |
79 |
80 |
81 | -------------------------------------------------------------------------------- /leaderboard/utils.py: -------------------------------------------------------------------------------- 1 | """ 2 | Project OCELoT: Open, Competitive Evaluation Leaderboard of Translations 3 | """ 4 | import os.path 5 | import re 6 | from typing import Optional 7 | 8 | import lxml.etree as ET 9 | from sacrebleu.utils import smart_open 10 | 11 | 12 | MISSING_TRANSLATION_MESSAGE = "NO TRANSLATION AVAILABLE" 13 | 14 | 15 | def analyze_xml_file(xml_path): 16 | """ 17 | Return all collection names, source languages, reference languages, 18 | translators, and systems found in the XML file. Code extracted from 19 | https://github.com/wmt-conference/wmt-format-tools/blob/main/wmtformat/unwrap.py 20 | """ 21 | collections, src_langs, ref_langs, translators, systems = ( 22 | set(), 23 | set(), 24 | set(), 25 | set(), 26 | set(), 27 | ) 28 | tree = ET.parse(xml_path) 29 | 30 | for collection in tree.getroot().findall(".//collection"): 31 | collections.add(collection.get("id")) 32 | 33 | for src_doc in tree.getroot().findall(".//src"): 34 | src_langs.add(src_doc.get("lang")) 35 | 36 | for ref_doc in tree.getroot().findall(".//ref"): 37 | ref_langs.add(ref_doc.get("lang")) 38 | translator = ref_doc.get("translator") 39 | if translator: 40 | translators.add(translator) 41 | 42 | for hyp_doc in tree.getroot().findall(".//hyp"): 43 | # hyp_langs.add(hyp_doc.get("lang")) # Not used in the XML format? 44 | system = hyp_doc.get("system") 45 | if system: 46 | systems.add(system) 47 | 48 | return collections, src_langs, ref_langs, translators, systems 49 | 50 | 51 | # Taken from sacrebleu which removed this with v2.2 52 | # 53 | # https://github.com/mjpost/sacrebleu/blob/65a8a9eeccd8c0c7875e875e12edf10db33ab0ba/sacrebleu/utils.py#L277 54 | def process_to_text(rawfile, txtfile, field: Optional[int] = None): 55 | """Processes raw files to plain text files. Can handle SGML, XML, TSV files, and plain text. 56 | Called after downloading datasets. 57 | :param rawfile: the input file (possibly SGML) 58 | :param txtfile: the plaintext file 59 | :param field: For TSV files, which field to extract. 60 | """ 61 | 62 | def _clean(s): 63 | """ 64 | Removes trailing and leading spaces and collapses multiple consecutive internal spaces to a single one. 65 | :param s: The string. 66 | :return: A cleaned-up string. 67 | """ 68 | return re.sub(r'\s+', ' ', s.strip()) 69 | 70 | if not os.path.exists(txtfile) or os.path.getsize(txtfile) == 0: 71 | if rawfile.endswith('.sgm') or rawfile.endswith('.sgml'): 72 | with smart_open(rawfile) as fin, smart_open( 73 | txtfile, 'wt' 74 | ) as fout: 75 | for line in fin: 76 | if line.startswith('(.*).*?', '\\1', line 81 | ) 82 | ), 83 | file=fout, 84 | ) 85 | # IWSLT 86 | elif rawfile.endswith('.xml'): 87 | with smart_open(rawfile) as fin, smart_open( 88 | txtfile, 'wt' 89 | ) as fout: 90 | for line in fin: 91 | if line.startswith('(.*).*?', '\\1', line 96 | ) 97 | ), 98 | file=fout, 99 | ) 100 | # MTNT 101 | elif rawfile.endswith('.tsv'): 102 | with smart_open(rawfile) as fin, smart_open( 103 | txtfile, 'wt' 104 | ) as fout: 105 | for line in fin: 106 | print(line.rstrip().split('\t')[field], file=fout) 107 | # PLAIN TEXT 108 | else: 109 | with smart_open(rawfile) as fin, smart_open( 110 | txtfile, 'wt' 111 | ) as fout: 112 | for line in fin: 113 | print(line.rstrip(), file=fout) 114 | 115 | 116 | def process_xml_to_text( 117 | xml_path, 118 | txt_path, 119 | source=None, 120 | reference=None, 121 | system=None, 122 | collection=None, 123 | ): 124 | """ 125 | Extract source, reference(s) or system texts from the XML file. 126 | Segments from test suites are ignored. 127 | Multiple references are not supported. 128 | """ 129 | 130 | if [source, reference, system].count(None) != 2: 131 | raise ValueError( 132 | 'Exactly one of source, reference or system must be provided' 133 | ) 134 | 135 | tree = ET.parse(xml_path) 136 | src_sents, ref_sents = [], [] 137 | out_sents = [] 138 | 139 | root = tree.getroot() 140 | if collection: # Restrict to the given collection if requested 141 | root = root.find(f".//collection[@id='{collection}']") 142 | if root is None: 143 | # Create an empty hypothesis file as this case is catched later 144 | with open(txt_path, 'w') as txt_file: 145 | pass 146 | return False 147 | 148 | for doc in root.findall(".//doc"): 149 | if 'testsuite' in doc.attrib: # Skip testsuites 150 | continue 151 | 152 | src_sents = { 153 | int(seg.get("id")): seg.text 154 | for seg in doc.findall(".//src//seg") 155 | } 156 | 157 | if reference: 158 | ref_docs = doc.findall(".//ref") 159 | trans_to_ref = {ref.get("translator"): ref for ref in ref_docs} 160 | ref_doc = trans_to_ref.get(reference, None) 161 | ref_sents = ( 162 | { 163 | int(seg.get("id")): seg.text 164 | for seg in ref_doc.findall(".//seg") 165 | } 166 | if ref_doc is not None 167 | else {} 168 | ) 169 | 170 | if system: 171 | hyp_docs = doc.findall(".//hyp") 172 | sys_to_hyp = {hyp.get("system"): hyp for hyp in hyp_docs} 173 | hyp_doc = sys_to_hyp.get(system, None) 174 | hyp_sents = ( 175 | { 176 | int(seg.get("id")): seg.text 177 | for seg in hyp_doc.findall(".//seg") 178 | } 179 | if hyp_doc is not None 180 | else {} 181 | ) 182 | 183 | for seg_id in sorted(src_sents.keys()): 184 | if source: 185 | out_sents.append(src_sents[seg_id]) 186 | elif reference: 187 | ref_sent = ref_sents.get( 188 | seg_id, MISSING_TRANSLATION_MESSAGE 189 | ) 190 | out_sents.append(ref_sent) 191 | elif system: 192 | hyp_sent = hyp_sents.get( 193 | seg_id, MISSING_TRANSLATION_MESSAGE 194 | ) 195 | out_sents.append(hyp_sent) 196 | 197 | with open(txt_path, 'w') as txt_file: 198 | for sent in out_sents: 199 | txt_file.write("{}\n".format(sent)) 200 | return True 201 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | """Django's command-line utility for administrative tasks.""" 9 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ocelot.settings') 10 | try: 11 | from django.core.management import execute_from_command_line 12 | except ImportError as exc: 13 | raise ImportError( 14 | "Couldn't import Django. Are you sure it's installed and " 15 | "available on your PYTHONPATH environment variable? Did you " 16 | "forget to activate a virtual environment?" 17 | ) from exc 18 | execute_from_command_line(sys.argv) 19 | 20 | 21 | if __name__ == '__main__': 22 | main() 23 | -------------------------------------------------------------------------------- /ocelot/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Project OCELoT: Open, Competitive Evaluation Leaderboard of Translations 3 | """ 4 | -------------------------------------------------------------------------------- /ocelot/context_processors.py: -------------------------------------------------------------------------------- 1 | """ 2 | Project OCELoT: Open, Competitive Evaluation Leaderboard of Translations 3 | """ 4 | from django.conf import settings 5 | 6 | 7 | def project_version(request): 8 | return {"project_version": settings.VERSION} 9 | -------------------------------------------------------------------------------- /ocelot/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for ocelot project. 3 | 4 | Generated by 'django-admin startproject' using Django 2.2.1. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/2.2/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/2.2/ref/settings/ 11 | """ 12 | import logging 13 | import os 14 | from logging.handlers import ( # pylint: disable=ungrouped-imports 15 | RotatingFileHandler, 16 | ) 17 | 18 | 19 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 20 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 21 | 22 | # Quick-start development settings - unsuitable for production 23 | # See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/ 24 | 25 | DEBUG = os.environ.get('OCELOT_DEBUG', True) 26 | 27 | ADMINS = os.environ.get('OCELOT_ADMINS', ()) 28 | MANAGERS = ADMINS 29 | 30 | SECRET_KEY = os.environ.get('OCELOT_SECRET_KEY') # Throw if no SECRET_KEY set! 31 | ALLOWED_HOSTS = os.environ.get('OCELOT_ALLOWED_HOSTS', '127.0.0.1').split( 32 | ',' 33 | ) 34 | 35 | CSRF_TRUSTED_ORIGINS = ['https://{0}'.format(x) for x in ALLOWED_HOSTS] 36 | 37 | WSGI_APPLICATION = os.environ.get( 38 | 'OCELOT_WSGI_APPLICATION', 'ocelot.wsgi.application' 39 | ) 40 | 41 | # Try to load database settings, otherwise use defaults. 42 | DB_ENGINE = os.environ.get('OCELOT_DB_ENGINE') 43 | DB_NAME = os.environ.get('OCELOT_DB_NAME') 44 | DB_USER = os.environ.get('OCELOT_DB_USER') 45 | DB_PASSWORD = os.environ.get('OCELOT_DB_PASSWORD') 46 | DB_HOST = os.environ.get('OCELOT_DB_HOST') 47 | DB_PORT = os.environ.get('OCELOT_DB_PORT') 48 | 49 | if all((DB_ENGINE, DB_NAME, DB_USER, DB_PASSWORD, DB_HOST, DB_PORT)): 50 | DATABASES = { 51 | 'default': { 52 | 'ENGINE': DB_ENGINE, 53 | 'NAME': DB_NAME, 54 | 'USER': DB_USER, 55 | 'PASSWORD': DB_PASSWORD, 56 | 'HOST': DB_HOST, 57 | 'PORT': DB_PORT, 58 | 'OPTIONS': {'sslmode': 'require'}, 59 | } 60 | } 61 | 62 | else: 63 | # Database 64 | # https://docs.djangoproject.com/en/2.2/ref/settings/#databases 65 | 66 | DB_SQLITE3 = os.environ.get('OCELOT_DB_SQLITE3', 67 | os.path.join(BASE_DIR, 'db.sqlite3')) 68 | DATABASES = { 69 | 'default': { 70 | 'ENGINE': 'django.db.backends.sqlite3', 71 | 'NAME': DB_SQLITE3, 72 | } 73 | } 74 | 75 | FILE_UPLOAD_PERMISSIONS = 0o644 76 | 77 | # Logging settings for this Django project. 78 | LOG_LEVEL = logging.DEBUG 79 | LOG_FILENAME = os.path.join(BASE_DIR, 'ocelot.log') 80 | LOG_FORMAT = "[%(asctime)s] %(name)s::%(levelname)s %(message)s" 81 | LOG_DATE = "%m/%d/%Y @ %H:%M:%S" 82 | LOG_FORMATTER = logging.Formatter(LOG_FORMAT, LOG_DATE) 83 | LOG_HANDLER = RotatingFileHandler( 84 | filename=LOG_FILENAME, 85 | mode="a", 86 | maxBytes=50 * 1024 * 1024, 87 | backupCount=5, 88 | encoding="utf-8", 89 | ) 90 | LOG_HANDLER.setLevel(level=LOG_LEVEL) 91 | LOG_HANDLER.setFormatter(LOG_FORMATTER) 92 | 93 | 94 | # Application definition 95 | 96 | INSTALLED_APPS = [ 97 | 'django.contrib.admin', 98 | 'django.contrib.auth', 99 | 'django.contrib.contenttypes', 100 | 'django.contrib.sessions', 101 | 'django.contrib.messages', 102 | 'django.contrib.staticfiles', 103 | 'leaderboard', 104 | 'evaluation', 105 | ] 106 | 107 | MIDDLEWARE = [ 108 | 'django.middleware.security.SecurityMiddleware', 109 | 'django.contrib.sessions.middleware.SessionMiddleware', 110 | 'django.middleware.common.CommonMiddleware', 111 | 'django.middleware.csrf.CsrfViewMiddleware', 112 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 113 | 'django.contrib.messages.middleware.MessageMiddleware', 114 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 115 | ] 116 | 117 | ROOT_URLCONF = 'ocelot.urls' 118 | 119 | TEMPLATES = [ 120 | { 121 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 122 | 'DIRS': [], 123 | 'APP_DIRS': True, 124 | 'OPTIONS': { 125 | 'context_processors': [ 126 | 'django.template.context_processors.debug', 127 | 'django.template.context_processors.request', 128 | 'django.contrib.auth.context_processors.auth', 129 | 'django.contrib.messages.context_processors.messages', 130 | 'ocelot.context_processors.project_version', 131 | ] 132 | }, 133 | } 134 | ] 135 | 136 | 137 | # Password validation 138 | # https://docs.djangoproject.com/en/2.2/ref/settings/#auth-password-validators 139 | 140 | AUTH_PASSWORD_VALIDATORS = [ 141 | { 142 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator' 143 | }, 144 | { 145 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator' 146 | }, 147 | { 148 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator' 149 | }, 150 | { 151 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator' 152 | }, 153 | ] 154 | 155 | 156 | # Internationalization 157 | # https://docs.djangoproject.com/en/2.2/topics/i18n/ 158 | 159 | LANGUAGE_CODE = 'en-us' 160 | 161 | TIME_ZONE = 'UTC' 162 | 163 | USE_I18N = True 164 | 165 | USE_L10N = True 166 | 167 | USE_TZ = True 168 | 169 | 170 | # Static files (CSS, JavaScript, Images) 171 | # https://docs.djangoproject.com/en/2.2/howto/static-files/ 172 | 173 | STATIC_URL = '/static/' 174 | STATIC_ROOT = os.path.join(BASE_DIR, 'static') 175 | 176 | # Static files that are not tied to a particular app should be put there 177 | STATICFILES_DIRS = [ 178 | os.path.join(BASE_DIR, 'assets'), 179 | ] 180 | 181 | # Allow to specify absolute filesystem path to the directory that will hold user-uploaded files. 182 | MEDIA_ROOT = os.environ.get('OCELOT_MEDIA_ROOT', '') 183 | 184 | # Project version 185 | # See point 4 from https://packaging.python.org/guides/single-sourcing-package-version/ 186 | 187 | with open(os.path.join(BASE_DIR, 'VERSION')) as version_file: 188 | VERSION = version_file.read().strip() 189 | -------------------------------------------------------------------------------- /ocelot/urls.py: -------------------------------------------------------------------------------- 1 | """ocelot URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/2.2/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: path('', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.urls import include, path 14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 15 | """ 16 | from django.conf.urls.static import static 17 | from django.contrib import admin 18 | from django.urls import path 19 | 20 | from evaluation.views import compare_submissions 21 | from evaluation.views import submission 22 | from leaderboard.views import download 23 | from leaderboard.views import frontpage 24 | from leaderboard.views import leaderboard 25 | from leaderboard.views import signin 26 | from leaderboard.views import signout 27 | from leaderboard.views import signup 28 | from leaderboard.views import submit 29 | from leaderboard.views import teampage 30 | from leaderboard.views import updates 31 | from leaderboard.views import welcome 32 | from ocelot.settings import DEBUG 33 | from ocelot.settings import STATIC_ROOT 34 | from ocelot.settings import STATIC_URL 35 | 36 | # pylint: disable-msg=invalid-name 37 | urlpatterns = [ 38 | # django.contrib.admin app 39 | path('admin/', admin.site.urls), 40 | # leaderboard app 41 | path('', frontpage, name='frontpage-view'), 42 | path( 43 | 'leaderboard/', 44 | leaderboard, 45 | name='leaderboard-view', 46 | ), 47 | path('sign-in', signin, name='signin-view'), 48 | path('sign-out', signout, name='signout-view'), 49 | path('signup', signup, name='signup-view'), 50 | path('submit', submit, name='submit-view'), 51 | path('teampage', teampage, name='teampage-view'), 52 | path('updates', updates, name='updates-view'), 53 | path('download', download, name='download-view'), 54 | path('welcome', welcome, name='welcome-view'), 55 | # evaluation app 56 | path('submission/', submission, name='submission-view'), 57 | path( 58 | 'submission//', 59 | compare_submissions, 60 | name='compare-submissions-view', 61 | ), 62 | ] 63 | 64 | if DEBUG: 65 | urlpatterns += static(STATIC_URL, document_root=STATIC_ROOT) 66 | -------------------------------------------------------------------------------- /ocelot/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for ocelot project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/2.2/howto/deployment/wsgi/ 8 | """ 9 | import os 10 | 11 | from django.core.wsgi import get_wsgi_application 12 | 13 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ocelot.settings') 14 | 15 | # pylint: disable-msg=invalid-name 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /requirements-dev.txt: -------------------------------------------------------------------------------- 1 | -r requirements.txt 2 | black 3 | lxml-stubs 4 | mypy 5 | pylint 6 | pylint-django 7 | reorder-python-imports==2.6.0 8 | safety 9 | rnc2rng 10 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | beautifulsoup4 2 | Django==4.1.13 3 | django-stubs 4 | lxml>=3.6 5 | psycopg2 6 | sacrebleu 7 | sqlparse 8 | xmlschema 9 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [mypy] 2 | plugins = 3 | mypy_django_plugin.main 4 | 5 | strict_optional = True 6 | 7 | [mypy.plugins.django-stubs] 8 | django_settings_module = ocelot.settings 9 | 10 | [mypy-bs4] 11 | ignore_missing_imports = True 12 | 13 | [mypy-xmlschema] 14 | ignore_missing_imports = True 15 | 16 | [pylint.master] 17 | load-plugins = pylint_django 18 | django-settings-module = ocelot.settings 19 | -------------------------------------------------------------------------------- /uwsgi_params: -------------------------------------------------------------------------------- 1 | 2 | uwsgi_param QUERY_STRING $query_string; 3 | uwsgi_param REQUEST_METHOD $request_method; 4 | uwsgi_param CONTENT_TYPE $content_type; 5 | uwsgi_param CONTENT_LENGTH $content_length; 6 | 7 | uwsgi_param REQUEST_URI $request_uri; 8 | uwsgi_param PATH_INFO $document_uri; 9 | uwsgi_param DOCUMENT_ROOT $document_root; 10 | uwsgi_param SERVER_PROTOCOL $server_protocol; 11 | uwsgi_param REQUEST_SCHEME $scheme; 12 | uwsgi_param HTTPS $https if_not_empty; 13 | 14 | uwsgi_param REMOTE_ADDR $remote_addr; 15 | uwsgi_param REMOTE_PORT $remote_port; 16 | uwsgi_param SERVER_PORT $server_port; 17 | uwsgi_param SERVER_NAME $server_name; 18 | --------------------------------------------------------------------------------