From f541efc94ae0a684f58259c06822e8cad0d4c4be Mon Sep 17 00:00:00 2001 From: Manuel Gundlach Date: Mon, 30 Jan 2023 22:02:50 +0100 Subject: [PATCH 01/19] Handle IntegrityError on file commit gracefully (#1223) Fixes #1214. --- cms/db/filecacher.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/cms/db/filecacher.py b/cms/db/filecacher.py index 4bd8ba0e65..e56f28fc5e 100644 --- a/cms/db/filecacher.py +++ b/cms/db/filecacher.py @@ -7,6 +7,7 @@ # Copyright © 2013 Luca Wehrstedt # Copyright © 2016 Luca Versari # Copyright © 2021 Fabian Gundlach <320pointsguy@gmail.com> +# Copyright © 2023 Manuel Gundlach # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -362,8 +363,12 @@ def commit_file(self, fobj, digest, desc=""): # If someone beat us to adding the same object to the database, we # should at least drop the large object. LargeObject.unlink(fobj.loid) - logger.warning("File %s (%s) caused an IntegrityError, ignoring.", - digest, desc) + logger.info("File %s (%s) caused an IntegrityError, ignoring. " + "Note: If the file is a compiled submission " + "executable, this can occur when a contestant has " + "submitted identical source code multiple times, " + "and is harmless in that case.", + digest, desc) return False return True From 7d962150d9969281148d3eaba1ab35823fdfb1b6 Mon Sep 17 00:00:00 2001 From: Anton Tsypko Date: Mon, 6 Feb 2023 23:36:12 +0100 Subject: [PATCH 02/19] Added Ukrainian translation (#1225) --- cms/locale/uk/LC_MESSAGES/cms.po | 1257 ++++++++++++++++++++++++++++++ 1 file changed, 1257 insertions(+) create mode 100644 cms/locale/uk/LC_MESSAGES/cms.po diff --git a/cms/locale/uk/LC_MESSAGES/cms.po b/cms/locale/uk/LC_MESSAGES/cms.po new file mode 100644 index 0000000000..30f6401e25 --- /dev/null +++ b/cms/locale/uk/LC_MESSAGES/cms.po @@ -0,0 +1,1257 @@ +# Translations template for Contest Management System. +# Copyright (C) 2023 CMS development group +# This file is distributed under the same license as the Contest Management +# System project. +# Anton Tsypko tsypko@oi.in.ua, 2023. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Contest Management System 1.5.dev0\n" +"Report-Msgid-Bugs-To: contestms@googlegroups.com\n" +"MIME-Version: 1.0\n" +"Last-Translator: Anton Tsypko \n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Project-Id-Version: c\n" +"Language: uk\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" + +#: +msgid "N/A" +msgstr "N/A" + +#: +msgid "Not correct" +msgstr "Неправильно" + +#: +msgid "Correct" +msgstr "Правильно" + +#: +msgid "Partially correct" +msgstr "Частково правильно" + +#: +msgid "#" +msgstr "#" + +#: +msgid "Outcome" +msgstr "Результат" + +#: +msgid "Details" +msgstr "Деталі" + +#: +msgid "Execution time" +msgstr "Час виконання" + +#: +msgid "Memory used" +msgstr "Використана пам'ять" + +#: +msgid "Score details temporarily unavailable." +msgstr "Деталі результатів тимчасово недоступні." + +#: +msgid "Subtask %(index)s" +msgstr "Підзавдання %(index)s" + +#: +msgid "Compilation succeeded" +msgstr "Компіляція виконана успішно" + +#: +msgid "Your submission successfully compiled to an executable." +msgstr "Ваша спроба успішно скомпільована у виконуваний файл." + +#: +msgid "Compilation failed" +msgstr "Помилка компіляції" + +#: +msgid "Your submission did not compile correctly." +msgstr "Ваша спроба скомпільована неправильно." + +#: +msgid "Compilation timed out" +msgstr "Час очікування компіляції минув" + +#: +msgid "Your submission exceeded the time limit while compiling. This might be caused by an excessive use of C++ templates, for example." +msgstr "Ви перевищили ліміт часу під час компіляції. Це може бути спричинено, наприклад, надмірним використанням шаблонів C++." + +#: +msgid "Compilation killed with signal %s (could be triggered by violating memory limits)" +msgstr "Компіляція припинена сигналом %s (може бути викликано порушенням обмежень пам’яті)" + +#: +msgid "Your submission was killed with the specified signal. Among other things, this might be caused by exceeding the memory limit for the compilation, and in turn by an excessive use of C++ templates, for example." +msgstr "Ваша спроба була знищена вказаним сигналом. Серед іншого, це може бути спричинено перевищенням обмеження пам’яті для компіляції та, у свою чергу, надмірним використанням шаблонів C++, наприклад." + +#: +msgid "Output is correct" +msgstr "Вихідні дані правильні" + +#: +msgid "Your submission ran and gave the correct answer" +msgstr "Ваша спроба запущена та дала правильну відповідь" + +#: +msgid "Output is partially correct" +msgstr "Вихідні дані частково правильні" + +#: +msgid "Your submission ran and gave the partially correct answer" +msgstr "Ваша спроба запущена та дала частково правильну відповідь" + +#: +msgid "Output isn't correct" +msgstr "Вихідні дані неправильні" + +#: +msgid "Your submission ran, but gave the wrong answer" +msgstr "Ваша спроба запущена, але дала неправильну відповідь" + +#: +msgid "Evaluation didn't produce file %s" +msgstr "Оцінювання не створило файл %s" + +#: +msgid "Your submission ran, but did not write on the correct output file" +msgstr "Ваша спроба запущена, але не вивела нічого у правильний вихідний файл" + +#: +msgid "Execution timed out" +msgstr "Час запуску минув" + +#: +msgid "Your submission used too much CPU time." +msgstr "Ваша спроба використала забагато процесорного часу." + +#: +msgid "Execution timed out (wall clock limit exceeded)" +msgstr "Час очікування минув (перевищено ліміт настінного годинника)" + +#: +msgid "Your submission used too much total time. This might be triggered by undefined code, or buffer overflow, for example. Note that in this case the CPU time visible in the submission details might be much smaller than the time limit." +msgstr "Ваша спроба використала забагато загального часу. Це може бути викликано, наприклад, невизначеним кодом або переповненням буфера. Зауважте, що в цьому випадку час процесора, видимий у деталях спроби, може бути набагато меншим за обмеження часу." + +#: +msgid "Execution killed (could be triggered by violating memory limits)" +msgstr "Виконання припинено (може бути викликано порушенням обмежень пам’яті)" + +#: +msgid "The evaluation was killed by a signal. Among other things, this might be caused by exceeding the memory limit. Note that if this is the reason, the memory usage visible in the submission details is the usage before the allocation that caused the signal." +msgstr "Оцінювання було знищено сигналом. Серед іншого це може бути спричинено перевищенням ліміту пам’яті. Зауважте, що якщо це причина, використання пам’яті, видиме в деталях спроби, є використанням до розподілу, який спричинив сигнал." + +#: +msgid "Execution failed because the return code was nonzero" +msgstr "Помилка виконання, оскільки код повернення був ненульовим" + +#: +msgid "Your submission failed because it exited with a return code different from 0." +msgstr "Ваше надсилання не виконано, оскільки він завершився з кодом повернення, відмінним від 0." + +#: +msgid "Execution completed successfully" +msgstr "Виконання успішно завершено" + +#: +msgid "No compilation needed" +msgstr "Компіляція не потрібна" + +#: +msgid "File not submitted" +msgstr "Файл не надіслано" + +#: +msgid "Question too long!" +msgstr "Питання занадто довге!" + +#: +msgid "Subject must be at most %(max_subject_length)d characters, content at most %(max_text_length)d." +msgstr "Тема має містити щонайбільше %(max_subject_length)d символів, а вміст – не більше %(max_text_length)d." + +#: +msgid "contest-token" +msgstr "токен змагання" + +#: +msgid "contest-tokens" +msgstr "токени змагання" + +#: +msgid "task-token" +msgstr "токен завдання" + +#: +msgid "task-tokens" +msgstr "токени завдання" + +#: +msgid "token" +msgstr "токен" + +#: +msgid "tokens" +msgstr "токени" + +#: +msgid "You don't have %(type_pl)s available for this task." +msgstr "У вас немає %(type_pl)s для цього завдання." + +#: +msgid "You have an infinite number of %(type_pl)s for this task." +msgstr "У вас є нескінченна кількість %(type_pl)s для цього завдання." + +#: +msgid "You start with no %(type_pl)s." +msgstr "Ви починаєте без %(type_pl)s." + +#: +msgid "You start with one %(type_s)s." +msgid_plural "You start with %(gen_initial)d %(type_pl)s." +msgstr[0] "Ви починаєте з одного %(type_s)s." +msgstr[1] "Ви починаєте з двох %(type_s)s." +msgstr[2] "Ви починаєте з %(gen_initial)d %(type_s)s." + +#: +msgid "Every minute " +msgid_plural "Every %(gen_interval)g minutes " +msgstr[0] "Кожну хвилину " +msgstr[1] "Кожні %(gen_interval)g хвилини " +msgstr[2] "Кожні %(gen_interval)g хвилин " + +#: +msgid "you get another %(type_s)s, " +msgid_plural "you get %(gen_number)d other %(type_pl)s, " +msgstr[0] "ви отримуєте інший %(type_s)s, " +msgstr[1] "ви отримуєте два інші %(type_s)s, " +msgstr[2] "ви отримуєте %(gen_number)d інших %(type_s)s, " + + +#: +msgid "up to a maximum of one %(type_s)s." +msgid_plural "up to a maximum of %(gen_max)d %(type_pl)s." +msgstr[0] "до максимум одного %(type_s)s." +msgstr[1] "до максимум двох %(type_s)s. " +msgstr[2] "до максимум %(gen_max)d %(type_s)s. " + +#: +msgid "you get another %(type_s)s." +msgid_plural "you get %(gen_number)d other %(type_pl)s." +msgstr[0] "ви отримуєте інший %(type_s)s." +msgstr[1] "ви отримуєте інші два %(type_s)s." +msgstr[2] "ви отримуєте інших %(gen_number)d %(type_s)s." + +#: +msgid "You don't get other %(type_pl)s." +msgstr "Ви не отримуєте інших %(type_pl)s." + +#: +msgid "You can use a %(type_s)s every second " +msgid_plural "You can use a %(type_s)s every %(min_interval)g seconds " +msgstr[0] "Ви можете використовувати %(type_s)s щосекунди " +msgstr[1] "Ви можете використовувати %(type_s)s кожні дві секунди " +msgstr[2] "Ви можете використовувати %(type_s)s кожні %(min_interval)g секунд " + +#: +msgid "and no more than one %(type_s)s in total." +msgid_plural "and no more than %(max_number)d %(type_pl)s in total." +msgstr[0] "і не більше одного %(type_s)s загалом." +msgstr[1] "і не більше двух %(type_s)s загалом" +msgstr[2] "і не більше %(max_number)d %(type_s)s загалом" + +#: +msgid "You can use a %(type_s)s every second." +msgid_plural "You can use a %(type_s)s every %(min_interval)g seconds." +msgstr[0] "Ви можете використовувати %(type_s)s щосекунди." +msgstr[1] "Ви можете використовувати %(type_s)s кожні дві секунди." +msgstr[2] "Ви можете використовувати %(type_s)s кожні %(min_interval)g секунд." + +#: +msgid "You can use no more than one %(type_s)s in total." +msgid_plural "You can use no more than %(max_number)d %(type_pl)s in total." +msgstr[0] "Загалом ви можете використовувати не більше одного %(type_s)s." +msgstr[1] "Загалом ви можете використовувати не більше двох %(type_s)s." +msgstr[2] "Загалом ви можете використовувати не більше %(max_number)d %(type_s)s." + +#: +msgid "You have no limitations on how you use them." +msgstr "Ви не маєте обмежень щодо того, як ви їх використовуєте." + +#: +msgid "Too many print jobs!" +msgstr "Забагато завдань для друку!" + +#: +msgid "You have reached the maximum limit of at most %d print jobs." +msgstr "Ви досягли максимальної кількості завдань для друку (%d)." + +#: +msgid "Invalid format!" +msgstr "Недійсний формат!" + +#: +msgid "Please select the correct files." +msgstr "Виберіть правильні файли." + +#: +msgid "File too big!" +msgstr "Файл завеликий!" + +#: +msgid "Each file must be at most %d bytes long." +msgstr "Довжина кожного файлу не повинна перевищувати %d байтів." + +#: +msgid "Print job storage failed!" +msgstr "Не вдалося зберегти завдання для друку!" + +#: +msgid "Please try again." +msgstr "Будь ласка спробуйте ще раз." + +#: +msgid "Token request discarded" +msgstr "Запит токена відхилено" + +#: +msgid "Your request has been discarded because you have no tokens available." +msgstr "Ваш запит відхилено, оскільки у вас немає доступних токенів." + +#: +msgid "Your request has been discarded because you already used a token on that submission." +msgstr "Ваш запит відхилено, оскільки ви вже використали токен для цієї спроби." + +#: +msgid "Question received" +msgstr "Питання отримано" + +#: +msgid "Your question has been received, you will be notified when it is answered." +msgstr "Ваше запитання отримано, Ви отримаєте сповіщення, коли на нього дадуть відповідь." + +#: +msgid "Print job received" +msgstr "Отримано завдання для друку" + +#: +msgid "Your print job has been received." +msgstr "Ваше завдання для друку отримано." + +#: +msgid "Submission received" +msgstr "Спробу отримано" + +#: +msgid "Your submission has been received and is currently being evaluated." +msgstr "Ваша спроба отримана та наразі оцінюється." + +#: +msgid "Compiling..." +msgstr "Компіляція..." + +#: +msgid "Evaluating..." +msgstr "Оцінювання..." + +#: +msgid "Scoring..." +msgstr "Бали..." + +#: +msgid "Evaluated" +msgstr "Оцінено" + +#: +msgid "status" +msgstr "статус" + +#: +msgid "Token request received" +msgstr "Отримано запит на токен" + +#: +msgid "Your request has been received and applied to the submission." +msgstr "Ваш запит отримано та застосовано до спроби." + +#: +msgid "Test received" +msgstr "Тест отримано" + +#: +msgid "Your test has been received and is currently being executed." +msgstr "Ваш тест отримано та зараз виконується." + +#: +msgid "details" +msgstr "деталі" + +#: +msgid "Executing..." +msgstr "Виконання..." + +#: +msgid "Executed" +msgstr "Виконано" + +#: +msgid "Too many submissions!" +msgstr "Забагато спроб!" + +#: +msgid "You have reached the maximum limit of at most %d submissions among all tasks." +msgstr "Ви досягли максимального ліміту (не більше ніж %d спроб) для всіх завдань." + +#: +msgid "You have reached the maximum limit of at most %d submissions on this task." +msgstr "Ви досягли максимального ліміту (не більше ніж %d спроб) для цього завдання." + +#: +msgid "Submissions too frequent!" +msgstr "Спроби надто часті!" + +#: +msgid "Among all tasks, you can submit again after %d seconds from last submission." +msgstr "Серед усіх завдань ви можете надіслати знову через %d секунд після останньої спроби." + +#: +msgid "For this task, you can submit again after %d seconds from last submission." +msgstr "Це завдання можна надіслати знову через %d секунд після останньої спроби." + +#: +msgid "Invalid archive format!" +msgstr "Невірний формат архіву!" + +#: +msgid "The submitted archive could not be opened." +msgstr "Не вдалося відкрити надісланий архів." + +#: +msgid "Invalid submission format!" +msgstr "Недійсний формат спроби!" + +#: +msgid "Submission too big!" +msgstr "Спроба занадто велика!" + +#: +msgid "Each source file must be at most %d bytes long." +msgstr "Довжина кожного вихідного файлу не повинна перевищувати %d байтів." + +#: +msgid "Submission storage failed!" +msgstr "Помилка зберігання даних!" + +#: +msgid "Too many tests!" +msgstr "Забагато тестів!" + +#: +msgid "You have reached the maximum limit of at most %d tests among all tasks." +msgstr "Ви досягли максимального ліміту не більше %d тестів серед усіх завдань." + +#: +msgid "You have reached the maximum limit of at most %d tests on this task." +msgstr "Ви досягли максимального ліміту щонайбільше %d тестів для цього завдання." + +#: +msgid "Tests too frequent!" +msgstr "Тести занадто часті!" + +#: +msgid "Among all tasks, you can test again after %d seconds from last test." +msgstr "Серед усіх завдань ви можете повторити тестування через %d секунд після останнього тесту." + +#: +msgid "For this task, you can test again after %d seconds from last test." +msgstr "Ви можете повторити це завдання через %d секунди після останнього тесту." + +#: +msgid "Invalid test format!" +msgstr "Недійсний формат тесту!" + +#: +msgid "Test too big!" +msgstr "Тест занадто великий!" + +#: +msgid "Input too big!" +msgstr "Вхідні дані завеликі!" + +#: +msgid "The input file must be at most %d bytes long." +msgstr "Вхідний файл має мати щонайбільше %d байт." + +#: +msgid "Test storage failed!" +msgstr "Перевірити пам'ять не вдалося!" + +#: +msgid "Communication" +msgstr "Взаємодія" + +#: +msgid "Announcements" +msgstr "Оголошення" + +#: +msgid "(no subject)" +msgstr "(без теми)" + +#: +msgid "Questions" +msgstr "Питання" + +#: +msgid "Subject" +msgstr "Тема" + +#: +msgid "Text" +msgstr "Текст" + +#: +msgid "Ask question" +msgstr "Поставте запитання" + +#: +msgid "Reset" +msgstr "Скинути" + +#: +msgid "no answer yet" +msgstr "ще немає відповіді" + +#: +msgid "Messages" +msgstr "Повідомлення" + +#: +msgid "Automatic (%(lang)s)" +msgstr "Автоматично (%(lang)s)" + +#: +msgid "Logout" +msgstr "Вийти" + +#: +msgid "Logged in as %(first_name)s %(last_name)s (%(username)s)" +msgstr "Ви ввійшли як %(first_name)s %(last_name)s (%(username)s)" + +#: +msgid "Failed to log in." +msgstr "Не вдалося увійти." + +#: +msgid "Welcome" +msgstr "Ласкаво просимо" + +#: +msgid "Please log in" +msgstr "Будь ласка, увійдіть" + +#: +msgid "Username" +msgstr "Логін" + +#: +msgid "Password" +msgstr "Пароль" + +#: +msgid "Login" +msgstr "Увійти" + +#: +msgid "Don't have an account?" +msgstr "Немає облікового запису?" + +#: +msgid "Register" +msgstr "зареєструватися" + +#: +msgid "New message" +msgstr "Нове повідомлення" + +#: +msgid "New announcement" +msgstr "Нове оголошення" + +#: +msgid "New answer" +msgstr "Нова відповідь" + +#: +msgid "%d unread" +msgstr "%d непрочитаних" + +#: +msgid "Until contest starts:" +msgstr "До початку змагання:" + +#: +msgid "Until contest ends:" +msgstr "До закінчення змагання:" + +#: +msgid "Until analysis starts:" +msgstr "До початку аналізу:" + +#: +msgid "Until analysis ends:" +msgstr "До закінчення аналізу:" + +#: +msgid "Time left:" +msgstr "Залишився час:" + +#: +msgid "Server time:" +msgstr "Час сервера:" + +#: +msgid "Overview" +msgstr "Огляд" + +#: +msgid "Statement" +msgstr "Умова" + +#: +msgid "Submissions" +msgstr "Спроби" + +#: +msgid "Documentation" +msgstr "Документація" + +#: +msgid "Testing" +msgstr "Тестування" + +#: +msgid "Printing" +msgstr "Друк" + +#: +msgid "Contest Management System" +msgstr "Contest Management System" + +#: +msgid "is released under the" +msgstr "випускається під" + +#: +msgid "GNU Affero General Public License" +msgstr "GNU Affero General Public License" + +#: +msgid "Choose a contest" +msgstr "Виберіть змагання" + +#: +msgid "Programming languages and libraries" +msgstr "Мови програмування та бібліотеки" + +#: +msgid "Standard Template Library" +msgstr "Стандартна бібліотека шаблонів" + +#: +msgid "The main Java class of the solution should have exactly the same name as the task." +msgstr "Основний клас Java рішення повинен мати точно таке ж ім’я, як і завдання." + +#: +msgid "Submission details for compilation" +msgstr "Деталі спроби для компіляції" + +#: +msgid "Message" +msgstr "Повідомлення" + +#: +msgid "Explanation" +msgstr "Пояснення" + +#: +msgid "Submission details for evaluation" +msgstr "Деталі спроби для оцінювання" + +#: +msgid "Error %(status_code)s" +msgstr "Помилка %(status_code)s" + +#: +msgid "An error occured while the server was handling your request." +msgstr "Під час обробки вашого запиту сервером сталася помилка." + +#: +msgid "Note that attempts to tamper with Contest Management System (such as probing the server with customized URLs) may be considered cheating and may lead to disqualification." +msgstr "Зауважте, що спроби підробити систему керування змаганнями (наприклад, перевірка сервера за допомогою налаштованих URL-адрес) можуть вважатися шахрайством і призвести до дискваліфікації." + +#: +msgid "If you encountered this error during normal usage, please notify the contest administrators." +msgstr "Якщо ви зіткнулися з цією помилкою під час звичайного використання, повідомте про це адміністраторів змагання." + +#: +msgid "General information" +msgstr "Загальна інформація" + +#: +msgid "The contest hasn't started yet." +msgstr "Змагання ще не розпочалося." + +#: +msgid "The contest will start at %(start_time)s and will end at %(stop_time)s." +msgstr "Змагання розпочнеться о %(start_time)s і закінчиться о %(stop_time)s." + +#: +msgid "The contest is currently running." +msgstr "Наразі змагання триває." + +#: +msgid "The contest started at %(start_time)s and will end at %(stop_time)s." +msgstr "Змагання розпочалося о %(start_time)s і завершиться о %(stop_time)s." + +#: +msgid "The contest has already ended." +msgstr "Змагання вже завершилося." + +#: +msgid "The contest started at %(start_time)s and ended at %(stop_time)s." +msgstr "Змагання розпочалося о %(start_time)s і завершилося о %(stop_time)s." + +#: +msgid "The analysis mode hasn't started yet." +msgstr "Режим аналізу ще не почався." + +#: +msgid "The analysis mode will start at %(start_time)s and will end at %(stop_time)s." +msgstr "Режим аналізу розпочнеться о %(start_time)s і закінчиться о %(stop_time)s." + +#: +msgid "The analysis mode is currently running." +msgstr "Зараз працює режим аналізу." + +#: +msgid "The analysis mode started at %(start_time)s and will end at %(stop_time)s." +msgstr "Режим аналізу почався о %(start_time)s і закінчиться о %(stop_time)s." + +#: +msgid "The analysis mode has already ended." +msgstr "Режим аналізу вже закінчився." + +#: +msgid "The analysis mode started at %(start_time)s and ended at %(stop_time)s." +msgstr "Режим аналізу почався о %(start_time)s і закінчився о %(stop_time)s." + +#: +msgid "You have an infinite number of tokens." +msgstr "У вас є нескінченна кількість токенів." + +#: +msgid "You can see the detailed result of a submission by using a token on it." +msgstr "Ви можете побачити детальний результат спроби, використовуючи токен на ньому." + +#: +msgid "Your score for each task will be the maximum among the tokened submissions and the last one." +msgstr "Ваш бал за кожне завдання буде максимальним серед спроб (з токеном) і останнього." + +#: +msgid "You have a distinct set of tokens for each task." +msgstr "У вас є окремий набір токенів для кожного завдання." + +#: +msgid "You can find the rules for the %(type_pl)s on each task's description page." +msgstr "Ви можете знайти правила для %(type_pl)s на сторінці опису кожного завдання." + +#: +msgid "You have a set of tokens shared among all tasks." +msgstr "У вас є набір токенів, спільний для всіх завдань." + +#: +msgid "You have two types of tokens: a set of contest-tokens shared among all tasks and a distinct set of task-tokens for each task." +msgstr "У вас є два типи токенів: набір токенів для змагання, спільний для всіх завдань, і окремий набір токен для завдання для кожного завдання." + +#: +msgid "You can see the detailed result of a submission by using two tokens on it, one of each type." +msgstr "Ви можете побачити детальний результат спроби, використовуючи два токени на ньому, по одному кожного типу." + +#: +msgid "You can submit at most %(submissions)s solutions during this contest." +msgstr "Під час цього змагання ви можете надіслати щонайбільше %(submissions)s рішень." + +#: +msgid "You can submit at most %(user_tests)s user tests during this contest." +msgstr "Під час цього змагання ви можете надіслати щонайбільше %(user_tests)s тестів користувача." + +#: +msgid "Every user is allowed to compete (i.e. submit solutions) for a uninterrupted time frame of %(per_user_time)s." +msgstr "Кожному користувачеві дозволено змагатися (тобто надсилати рішення) протягом безперервного проміжку часу %(per_user_time)s." + +#: +msgid "As soon as the contest starts you can choose to start your time frame." +msgstr "Як тільки змагання розпочнеться, ви зможете розпочати свій часовий проміжок." + +#: +msgid "Once you start, you can submit solutions until the end of the time frame or until the end of the contest, whatever comes first." +msgstr "Почавши, ви можете надсилати рішення до кінця відведеного часового проміжку або до кінця змагання, залежно від того, що відбудеться раніше." + +#: +msgid "By clicking on the button below you can start your time frame." +msgstr "Натиснувши на кнопку нижче, ви можете запустити свій часовий проміжок." + +#: +msgid "You started your time frame at %(start_time)s." +msgstr "Ви запустили свій часовий проміжок о %(start_time)s." + +#: +msgid "You can submit solutions until the end of the time frame or until the end of the contest, whatever comes first." +msgstr "Ви можете надсилати рішення до кінця відведеного часового проміжку або до кінця змагання, залежно від того, що відбудеться раніше." + +#: +msgid "You started your time frame at %(start_time)s and you already finished it." +msgstr "Ви запустили свій часовий проміжок о %(start_time)s і вже завершили його." + +#: +msgid "There's nothing you can do now." +msgstr "Ви нічого не можете зробити зараз." + +#: +msgid "You never started your time frame. Now it's too late." +msgstr "Ви ніколи не запускали свій часовий проміжок. Тепер уже пізно." + +#: +msgid "Start!" +msgstr "Старт!" + +#: +msgid "Task overview" +msgstr "Огляд завдання" + +#: +msgid "Task" +msgstr "Завдання" + +#: +msgid "Name" +msgstr "Ім'я" + +#: +msgid "Time limit" +msgstr "Обмеження часу" + +#: +msgid "Memory limit" +msgstr "Обмеження пам'яті" + +#: +msgid "Type" +msgstr "Тип" + +#: +msgid "Files" +msgstr "Файли" + +#: +msgid "Tokens" +msgstr "Токени" + +#: +msgid "Yes" +msgstr "Так" + +#: +msgid "No" +msgstr "Ні" + +#: +msgid "Print" +msgstr "Роздрукувати" + +#: +msgid "You can print %(remaining_jobs)s more text or PDF files of up to %(max_pages)s pages each." +msgstr "Ви можете надрукувати ще %(remaining_jobs)s текстових або PDF-файлів обсягом до %(max_pages)s сторінок кожен." + +#: +msgid "You can print %(remaining_jobs)s more text files of up to %(max_pages)s pages each." +msgstr "Ви можете надрукувати ще %(remaining_jobs)s текстових файлів обсягом до %(max_pages)s сторінок кожен." + +#: +msgid "File (text or PDF)" +msgstr "Файл (текст або PDF)" + +#: +msgid "File (text)" +msgstr "Файл (текст)" + +#: +msgid "Submit" +msgstr "Надіслати" + +#: +msgid "You cannot print anything any more as you have used up your printing quota." +msgstr "Ви більше не можете нічого друкувати, оскільки ви використали свою квоту друку." + +#: +msgid "Previous print jobs" +msgstr "Попередні завдання для друку" + +#: +msgid "Date and time" +msgstr "Дата і час" + +#: +msgid "Time" +msgstr "Час" + +#: +msgid "File name" +msgstr "Ім'я файлу" + +#: +msgid "Status" +msgstr "Статус" + +#: +msgid "Preparing..." +msgstr "Підготовка..." + +#: +msgid "no print jobs yet" +msgstr "ще немає завдань для друку" + +#: +msgid "The passwords do not match!" +msgstr "Паролі не збігаються!" + +#: +msgid "This username is already taken, please choose a different one." +msgstr "Цей логін вже зайнятий, виберіть інший." + +#: +msgid "This user is already registered in the contest." +msgstr "Цей користувач вже зареєстрований у змаганні." + +#: +msgid "No such user." +msgstr "Немає такого користувача." + +#: +msgid "The password is not correct." +msgstr "Пароль неправильний." + +#: +msgid "Registration" +msgstr "Реєстрація" + +#: +msgid "Please fill in the fields to register" +msgstr "Будь ласка, заповніть поля для реєстрації" + +#: +msgid "New user" +msgstr "Новий користувач" + +#: +msgid "Join contest" +msgstr "Приєднатися до змагання" + +#: +msgid "First name" +msgstr "Ім'я" + +#: +msgid "Last name" +msgstr "Прізвище" + +#: +msgid "E-mail" +msgstr "Електронна пошта" + +#: +msgid "Representing" +msgstr "Представляючи" + +#: +msgid "Must be one character or more." +msgid_plural "Must be %(min_length)s characters or more." +msgstr[0] "Має бути один або більше символів." +msgstr[1] "Має бути два або більше символів." +msgstr[2] "Має бути принаймні %(min_length)s символів." + +#: +msgid "Confirm password" +msgstr "Підтвердьте пароль" + +#: +msgid "Registered in the contest successfully!" +msgstr "Успішна реєстрація в змаганні!" + +#: +msgid "Your username is:" +msgstr "Ваш логін:" + +#: +msgid "Your password is stored securely." +msgstr "Ваш пароль надійно зберігається." + +#: +msgid "Back to login" +msgstr "Назад до входу" + +#: +msgid "Compilation output" +msgstr "Вихід компіляції" + +#: +msgid "Compilation outcome:" +msgstr "Результат компіляції:" + +#: +msgid "Compilation time:" +msgstr "Час компіляції:" + +#: +msgid "Memory used:" +msgstr "Використана пам'ять:" + +#: +msgid "Standard output" +msgstr "Стандартний вихід" + +#: +msgid "Standard error" +msgstr "Стандартна помилка" + +#: +msgid "%(name)s (%(short_name)s) description" +msgstr "%(name)s (%(short_name)s) опис" + +#: +msgid "no statement available" +msgstr "немає умови" + +#: +msgid "Download task statement" +msgstr "Завантажити умову завдання" + +#: +msgid "The statement for this task is available in multiple versions, in different languages." +msgstr "Інструкція для цього завдання доступна в кількох версіях різними мовами." + +#: +msgid "You can see (and download) all of them using the list on the right." +msgstr "Ви можете переглянути (і завантажити) усі з них, використовуючи список праворуч." + +#: +msgid "Some suggested translations follow." +msgstr "Нижче наведено деякі запропоновані переклади." + +#: +msgid "Statement in %(lang)s" +msgstr "Умови мовою %(lang)s" + +#: +msgid "Statement in %(lang)s" +msgstr "Умова %(lang)s" + +#: +msgid "%(lang)s" +msgstr "%(lang)s" + +#: +msgid "%(lang)s" +msgstr "%(lang)s" + +#: +msgid "Some details" +msgstr "Деякі деталі" + +#: +msgid "Compilation commands" +msgstr "Команди компіляції" + +#: +msgid "You can find the rules for the %(type_pl)s on the contest overview page." +msgstr "Ви можете знайти правила для %(type_pl)s на сторінці огляду змагання." + +#: +msgid "Remember that to see the detailed result of a submission you need to use both a contest-token and a task-token." +msgstr "Пам’ятайте, що для перегляду детальних результатів спроби потрібно використовувати як токен змагання, так і токен завдання." + +#: +msgid "Attachments" +msgstr "Додатки" + +#: +msgid "unknown" +msgstr "невідомий" + +#: +msgid "loading..." +msgstr "завантаження..." + +#: +msgid "%(name)s (%(short_name)s) submissions" +msgstr "%(name)s (%(short_name)s) спроби" + +#: +msgid "Score:" +msgstr "Бал:" + +#: +msgid "Public score:" +msgstr "Публічний бал:" + +#: +msgid "Score of tokened submissions:" +msgstr "Бали позначених спроб:" + +#: +msgid "Total score:" +msgstr "Загальний бал:" + +#: +msgid "Submit a solution" +msgstr "Надішліть рішення" + +#: +msgid "You may submit any subset of outputs in a single submission." +msgstr "Ви можете надіслати будь-яку підмножину виводів в одній спробі." + +#: +msgid "You can submit %(submissions_left)s more solution(s)." +msgstr "Ви можете надіслати ще %(submissions_left)s рішення(ів)." + +#: +msgid "submission.zip" +msgstr "submission.zip" + +#: +msgid "Previous submissions" +msgstr "Попередні спроби" + +#: +msgid "Tokens are not allowed on this task." +msgstr "У цьому завданні токени заборонені." + +msgid "Right now, you have infinite tokens available on this task." +msgstr "Зараз у вас є нескінченні токени для цієї задачі." + +msgid "Right now, you have one token available on this task." +msgstr "Зараз у вас є один токен для цієї задачі." + +#, python-format +msgid "Right now, you have %(tokens)s tokens available on this task." +msgstr "Зараз у вас є %(tokens)s токенів для цієї задачі." + +#, python-format +msgid "But you have to wait until %(expiration_time)s to use them." +msgstr "Але вам доведеться почекати до %(expiration_time)s, щоб використати їх." + +#, python-format +msgid "You will receive a new token at %(gen_time)s." +msgstr "Ви отримаєте новий токен в %(gen_time)s." + +msgid "In the current situation, no more tokens will be generated." +msgstr "У поточній ситуації не будуть створені нові токени." + +msgid "Right now, you do not have tokens available for this task." +msgstr "Зараз у вас немає доступних токенів для цієї задачі." + +#, python-format +msgid "But you will have to wait until %(expiration_time)s to use it." +msgstr "Але вам доведеться почекати до %(expiration_time)s, щоб використати його." + +msgid "Unofficial submissions" +msgstr "Неофіційні спроби" + +msgid "Official submissions" +msgstr "Офіційні спроби" + +msgid "Submission details" +msgstr "Деталі спроби" + +msgid "Close" +msgstr "Закрити" + +msgid "Download" +msgstr "Завантажити" + +msgid "Submit a test" +msgstr "Надіслати тест" + +#, python-format +msgid "You can submit %(user_tests_left)s more test(s)." +msgstr "Ви можете надіслати ще %(user_tests_left)s тестів." + +msgid "input" +msgstr "вхідні дані" + +msgid "Previous tests" +msgstr "Попередні тести" + +msgid "Input" +msgstr "Вхідні дані" + +msgid "Output" +msgstr "Вихідні дані" + +msgid "no tests yet" +msgstr "ще немає тестів" + +msgid "Test details" +msgstr "Деталі тесту" + +msgid "Evaluation outcome" +msgstr "Результат оцінювання" + +msgid "Wait..." +msgstr "Чекайте..." + +msgid "None" +msgstr "Немає" + +msgid "Public score" +msgstr "Публічний бал" + +msgid "Total score" +msgstr "Сумарний бал" + +msgid "Score" +msgstr "Бал" + +msgid "Token" +msgstr "Токен" + +msgid "no submissions" +msgstr "немає спроб" + +msgid "Played" +msgstr "Зіграно" + +msgid "Play!" +msgstr "Грати!" + +msgid "No tokens" +msgstr "Немає токенів" + +msgid "Invalid file" +msgstr "Неправильний файл" + +msgid "Print job has too many pages" +msgstr "Завдання для друку містить забагато сторінок" + +msgid "Sent to printer" +msgstr "Відправлено на принтер" + From 07b401712b41aea65f647a6966abbbff675f458a Mon Sep 17 00:00:00 2001 From: Edoardo Morassutto Date: Mon, 6 Mar 2023 10:39:32 +0100 Subject: [PATCH 03/19] Add support for importing score_precision in italian_yaml (#1229) --- cmscontrib/loaders/italy_yaml.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmscontrib/loaders/italy_yaml.py b/cmscontrib/loaders/italy_yaml.py index 9243d951b9..3543135a04 100644 --- a/cmscontrib/loaders/italy_yaml.py +++ b/cmscontrib/loaders/italy_yaml.py @@ -447,6 +447,9 @@ def get_task(self, get_statement=True): "Attachment %s for task %s" % (filename, name)) args["attachments"][filename] = Attachment(filename, digest) + # Score precision. + load(conf, args, "score_precision") + task = Task(**args) args = {} From 4baeee8cd84b5e33e407793751d37a051bc605bb Mon Sep 17 00:00:00 2001 From: psz2007 <63392367+psz2007@users.noreply.github.com> Date: Thu, 23 Mar 2023 16:31:36 +0800 Subject: [PATCH 04/19] Update Simplified Chinese translations (#1231) --- cms/locale/zh_CN/LC_MESSAGES/cms.po | 327 ++++++++++++++-------------- 1 file changed, 168 insertions(+), 159 deletions(-) diff --git a/cms/locale/zh_CN/LC_MESSAGES/cms.po b/cms/locale/zh_CN/LC_MESSAGES/cms.po index 39353e1f5a..59118f8ad3 100644 --- a/cms/locale/zh_CN/LC_MESSAGES/cms.po +++ b/cms/locale/zh_CN/LC_MESSAGES/cms.po @@ -1,32 +1,33 @@ # Simplified Chinese translations for CMS. -# Copyright © 2010-2015 CMS authors +# Copyright ? 2010-2023 CMS authors # This file is distributed under the same license as CMS. # vanshady , 2013. +# psz2007 , 2023. # msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-01-25 19:14+0000\n" +"POT-Creation-Date: 2023-03-23 8:40+0800\n" "PO-Revision-Date: 2014-07-01 07:24+0100\n" -"Last-Translator: vanshady \n" +"Last-Translator: psz2007 \n" "Language-Team: Simplified Chinese\n" "Language: zh_CN\n" "MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" +"Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "Compilation succeeded" msgstr "编译成功" msgid "Your submission successfully compiled to an executable." -msgstr "您的提交" +msgstr "您的提交已成功编译为可执行文件。" msgid "Compilation failed" msgstr "编译失败" msgid "Your submission did not compile correctly." -msgstr "您的提交没有正确编译" +msgstr "您的提交没有正确编译。" msgid "Compilation timed out" msgstr "编译超时" @@ -34,19 +35,19 @@ msgstr "编译超时" msgid "" "Your submission exceeded the time limit while compiling. This might be " "caused by an excessive use of C++ templates, for example." -msgstr "程序编译超时。比如说,这可能是因为过度使用C++模板。" +msgstr "程序编译超时。比如说,这可能是因为过度使用 C++ 模板。" #, fuzzy, python-format msgid "" "Compilation killed with signal %s (could be triggered by violating memory " "limits)" -msgstr "编译程序因内存违规存取而强制终止 (信号 %s)" +msgstr "编译程序收到信号 %s 终止(可能因为违反内存限制而触发)" msgid "" "Your submission was killed with the specified signal. Among other things, " "this might be caused by exceeding the memory limit for the compilation, and " "in turn by an excessive use of C++ templates, for example." -msgstr "程序因为制定signal而被强制终止。这可能是因为编译所用内存溢出或者过度使用C++模板。" +msgstr "程序因特定的信号而被强制终止。这可能是因为编译所用内存溢出或者过度使用 C++ 模板。" msgid "Output is correct" msgstr "输出正确" @@ -65,7 +66,7 @@ msgid "Output isn't correct" msgstr "输出错误" msgid "Your submission ran, but gave the wrong answer" -msgstr "您的提交运行了" +msgstr "您的提交运行了,但答案错误" #, python-format msgid "Evaluation didn't produce file %s" @@ -78,7 +79,7 @@ msgid "Execution timed out" msgstr "超过时间限制" msgid "Your submission used too much CPU time." -msgstr "您的提交占用了太多CPU" +msgstr "您的提交占用了太多 CPU 时间" msgid "Execution timed out (wall clock limit exceeded)" msgstr "运行超时" @@ -88,34 +89,36 @@ msgid "" "undefined code, or buffer overflow, for example. Note that in this case the " "CPU time visible in the submission details might be much smaller than the " "time limit." -msgstr "程序总耗时超时。这可能是因为undefined代码或者缓存溢出。注意如果是这样的话,在程序报告中的CPU用时可能会小于时限。" +msgstr "程序总耗时超时。这可能是因为代码中有未定义行为或者缓存溢出。" +"注意如果是这样的话,在程序报告中的 CPU 时间可能会小于时限。" #, python-format msgid "" "Execution killed with signal %s (could be triggered by violating memory " "limits)" -msgstr "测试程序因信号%s而被强制终止(可能因为内存溢出)" +msgstr "测试程序因信号 %s 而被强制终止(可能因为内存溢出而触发)" msgid "" "Your submission was killed with the specified signal. Among other things, " "this might be caused by exceeding the memory limit. Note that if this is the " "reason, the memory usage visible in the submission details is the usage " "before the allocation that caused the signal." -msgstr "程序因为制定信号而被强制终止。这可能是因为内存溢出。注意如果这是原因的话,程序报告中的内存使用信息是信号被发出前的信息。" +msgstr "程序因为特定的信号而被强制终止。这可能是因为内存溢出。" +"注意如果这是原因的话,程序报告中的内存使用信息是信号被发出前的信息。" msgid "Execution failed because the return code was nonzero" -msgstr "执行失败: 程序返回值非零" +msgstr "运行失败: 程序返回值非零" msgid "" "Your submission failed because it exited with a return code different from 0." -msgstr "程序因退出时返回值非0而失败" +msgstr "程序因退出时返回值非零而运行失败。" msgid "N/A" -msgstr "(空)" +msgstr "N/A" #, python-format msgid "Subtask %(index)s" -msgstr "子问题 %(index)s" +msgstr "子任务 %(index)s" msgid "Outcome" msgstr "评测结果" @@ -139,7 +142,7 @@ msgid "Partially correct" msgstr "部分正确" msgid "Invalid files in submission" -msgstr "传送中包含错误的文件" +msgstr "提交中包含非法的文件" msgid "Execution completed successfully" msgstr "评测完成" @@ -173,21 +176,21 @@ msgstr "Token" #, python-format msgid "You don't have %(type_pl)s available for this task." -msgstr "在本题中, 您没有任何可用的 %(type_pl)s." +msgstr "在本题中, 您没有任何可用的 %(type_pl)s。" #, python-format msgid "You have an infinite number of %(type_pl)s for this task." -msgstr "本题有无限量的 %(type_pl)s." +msgstr "本题有无限量的 %(type_pl)s。" #, python-format msgid "You start with no %(type_pl)s." -msgstr "竞赛开始时没有任何 %(type_pl)s." +msgstr "竞赛开始时没有任何 %(type_pl)s。" #, python-format msgid "You start with one %(type_s)s." msgid_plural "You start with %(gen_initial)d %(type_pl)s." -msgstr[0] "竞赛开始时有一个 %(type_pl)s." -msgstr[1] "竞赛开始时有 %(gen_initial)d 个 %(type_pl)s." +msgstr[0] "竞赛开始时有一个 %(type_pl)s。" +msgstr[1] "竞赛开始时有 %(gen_initial)d 个 %(type_pl)s。" #, python-format msgid "Every minute " @@ -198,102 +201,102 @@ msgstr[1] "接着每 %(gen_interval)g 分钟" #, python-format msgid "you get another %(type_s)s, " msgid_plural "you get %(gen_number)d other %(type_pl)s, " -msgstr[0] "会产生一个额外的 %(type_s)s, " -msgstr[1] "会产生 %d 个额外的 %(type_s)s, " +msgstr[0] "会产生一个额外的 %(type_s)s," +msgstr[1] "会产生 %d 个额外的 %(type_s)s," #, python-format msgid "up to a maximum of one %(type_s)s." msgid_plural "up to a maximum of %(gen_max)d %(type_pl)s." -msgstr[0] "至多只能拥有一个未使用的 %(type_pl)s." -msgstr[1] "至多可以同时拥有 %(gen_max)d 个未使用的 %(type_pl)s." +msgstr[0] "至多只能拥有一个未使用的 %(type_pl)s。" +msgstr[1] "至多可以同时拥有 %(gen_max)d 个未使用的 %(type_pl)s。" #, python-format msgid "you get another %(type_s)s." msgid_plural "you get %(gen_number)d other %(type_pl)s." -msgstr[0] "会产生一个额外的 %(type_s)s." -msgstr[1] "会产生%d个额外的 %(type_s)s." +msgstr[0] "会产生一个额外的 %(type_s)s。" +msgstr[1] "会产生 %(gen_number)d 个额外的 %(type_s)s。" #, python-format msgid "You don't get other %(type_pl)s." -msgstr "并不再产生新的%(type_pl)s." +msgstr "并不再产生新的 %(type_pl)s。" #, python-format msgid "You can use a %(type_s)s every second " msgid_plural "You can use a %(type_s)s every %(min_interval)g seconds " -msgstr[0] "每秒可以使用一个 %(type_s)s, " -msgstr[1] "两次 %(type_s)s 的使用间必须间隔至少 %(min_interval)g 秒, " +msgstr[0] "每秒可以使用一个 %(type_s)s," +msgstr[1] "两次 %(type_s)s 的使用间必须间隔至少 %(min_interval)g 秒," #, python-format msgid "and no more than one %(type_s)s in total." msgid_plural "and no more than %(max_number)d %(type_pl)s in total." -msgstr[0] "且总共至多只能使用一个 %(type_s)s." -msgstr[1] "且总共可以使用 %(max_number)d 个 %(type_s)s." +msgstr[0] "且总共至多只能使用一个 %(type_s)s。" +msgstr[1] "且总共可以使用 %(max_number)d 个 %(type_s)s。" #, python-format msgid "You can use a %(type_s)s every second." msgid_plural "You can use a %(type_s)s every %(min_interval)g seconds." -msgstr[0] "每秒可以使用一个 %(type_pl)s." -msgstr[1] "每隔 %(min_interval)g 秒可以使用一个 %(type_pl)s." +msgstr[0] "每秒可以使用一个 %(type_pl)s。" +msgstr[1] "每隔 %(min_interval)g 秒可以使用一个 %(type_pl)s。" #, python-format msgid "You can use no more than one %(type_s)s in total." msgid_plural "You can use no more than %(max_number)d %(type_pl)s in total." -msgstr[0] "且一旦产生 %(type_s)s 后将不会再增加." -msgstr[1] "且一旦产生总共 %(max_number)d 个 %(type_s)s 后将不会再增加." +msgstr[0] "且一旦产生 %(type_s)s 后将不会再增加。" +msgstr[1] "且一旦产生总共 %(max_number)d 个 %(type_s)s 后将不会再增加。" msgid "You have no limitations on how you use them." -msgstr "使用规则中没有其他额外的限制." +msgstr "使用规则中没有其他额外的限制。" #, fuzzy msgid "Question too big!" -msgstr "测试文件过大" +msgstr "询问过长!" msgid "You have reached the question length limit." -msgstr "您的提问超出长度限制" +msgstr "您的询问超出长度限制。" msgid "Question received" msgstr "已送出询问" msgid "" "Your question has been received, you will be notified when it is answered." -msgstr "您的询问已成功送出, 待此询问得到回复后将会通知您." +msgstr "您的询问已成功送出, 待此询问得到回复后将会通知您。" #, fuzzy msgid "Too many print jobs!" -msgstr "测试次数超出限制" +msgstr "打印次数过多!" #, fuzzy, python-format msgid "You have reached the maximum limit of at most %d print jobs." -msgstr "在本题中, 您最多可以进行 %d 次测试." +msgstr "在本题中, 您最多可以进行 %d 次测试。" #, fuzzy msgid "Invalid format!" -msgstr "错误的测试文件格式" +msgstr "非法的测试文件格式!" msgid "Please select the correct files." -msgstr "请选择正确的文件" +msgstr "请选择正确的文件。" #, fuzzy msgid "File too big!" -msgstr "测试文件过大" +msgstr "测试文件过大!" #, fuzzy, python-format msgid "Each file must be at most %d bytes long." -msgstr "个別程序码文件容量不得超过 %d bytes." +msgstr "每个文件长度不得超过 %d 字节。" #, fuzzy msgid "Print job storage failed!" -msgstr "测试文件储存失败" +msgstr "打印文件储存失败。" msgid "Please try again." -msgstr "请再试一次" +msgstr "请再试一次。" #, fuzzy msgid "Print job received" msgstr "已收到测试" msgid "Your print job has been received." -msgstr "已收到打印请求" +msgstr "已收到打印请求。" msgid "Compiling..." msgstr "编译中..." @@ -311,134 +314,134 @@ msgid "Evaluated" msgstr "已评测" msgid "Token request discarded" -msgstr "Token 已弃用" +msgstr "Token 使用已拒绝" msgid "Your request has been discarded because you have no tokens available." -msgstr "Token 已用完" +msgstr "由于无可用 Token,使用已拒绝。" msgid "" "Your request has been discarded because you already used a token on that " "submission." -msgstr "本次传送已使用过 Token" +msgstr "由于本次提交已使用过 Token,使用已拒绝。" msgid "Token request received" msgstr "Token 使用成功" msgid "Your request has been received and applied to the submission." -msgstr "请查看本次传送的完整评测结果" +msgstr "请查看本次提交的完整评测结果。" #, python-format msgid "" "You have reached the maximum limit of at most %d submissions among all tasks." -msgstr "您在本竞赛的传送次数已达上限 (%d 次)" +msgstr "您在本竞赛的提交次数已达上限 %d 次。" #, python-format msgid "" "You have reached the maximum limit of at most %d submissions on this task." -msgstr "您在本题目的传送次数已达上限 (%d 次)" +msgstr "您在本题目的提交次数已达上限 %d 次。" msgid "Too many submissions!" -msgstr "传送次数超出限制!" +msgstr "提交次数超出限制!" #, python-format msgid "" "Among all tasks, you can submit again after %d seconds from last submission." -msgstr "在本竞赛的最后一次传送过后 %d 秒始可再次传送." +msgstr "在本竞赛的最后一次提交过后 %d 秒始可再次提交。" #, python-format msgid "" "For this task, you can submit again after %d seconds from last submission." -msgstr "在本题的最后一次传送过后 %d 秒始可再次传送." +msgstr "在本题的最后一次提交过后 %d 秒始可再次提交。" msgid "Submissions too frequent!" -msgstr "传送过于频繁" +msgstr "提交过于频繁!" msgid "Invalid submission format!" -msgstr "文件格式错误" +msgstr "文件格式错误!" msgid "Invalid archive format!" -msgstr "封装文件格式错误" +msgstr "封装文件格式错误!" msgid "The submitted archive could not be opened." -msgstr "封装文件无法正常开启" +msgstr "封装文件无法正常开启。" #, fuzzy msgid "Cannot recognize the submission language." -msgstr "无法识别本次传送所使用的程序语言" +msgstr "无法识别本次提交所使用的程序语言。" #, python-format msgid "Language %s not allowed in this contest." -msgstr "本次竞赛不支持语言 %s" +msgstr "本次竞赛不支持语言 %s。" msgid "Invalid submission!" -msgstr "文件不正确" +msgstr "非法提交!" msgid "Submission too big!" -msgstr "传送文件过大" +msgstr "提交文件过大!" #, python-format msgid "Each source file must be at most %d bytes long." -msgstr "个別程序码文件容量不得超过 %d bytes." +msgstr "每个源文件长度不得超过 %d 字节。" msgid "Submission storage failed!" -msgstr "本传送发生文件存取错误" +msgstr "提交文件存取错误!" msgid "Submission received" -msgstr "已收到本次传送" +msgstr "已收到本次提交" msgid "Your submission has been received and is currently being evaluated." -msgstr "已收到您的传送, 等待评测中." +msgstr "已收到您的提交, 等待评测中。" #, python-format msgid "You have reached the maximum limit of at most %d tests among all tasks." -msgstr "在竞赛中, 您最多可以进行 %d 次测试." +msgstr "在竞赛中, 您最多可以进行 %d 次测试。" #, python-format msgid "You have reached the maximum limit of at most %d tests on this task." -msgstr "在本题中, 您最多可以进行 %d 次测试." +msgstr "在本题中, 您最多可以进行 %d 次测试。" msgid "Too many tests!" -msgstr "测试次数超出限制" +msgstr "测试次数过多!" #, python-format msgid "Among all tasks, you can test again after %d seconds from last test." -msgstr "在竞赛中, 两次测试之间必须间隔至少 %d 秒." +msgstr "在竞赛中, 两次测试之间必须间隔至少 %d 秒。" #, python-format msgid "For this task, you can test again after %d seconds from last test." -msgstr "在本题中, 两次测试之间必须间隔至少 %d 秒." +msgstr "在本题中, 两次测试之间必须间隔至少 %d 秒。" msgid "Tests too frequent!" -msgstr "测试过于频繁" +msgstr "测试过于频繁!" msgid "Invalid test format!" -msgstr "错误的测试文件格式" +msgstr "错误的测试文件格式!" #, fuzzy msgid "Cannot recognize the user test language." -msgstr "无法识别本次测试的语言" +msgstr "无法识别本次测试的语言。" msgid "Invalid test!" -msgstr "无效的测试" +msgstr "无效的测试!" msgid "Test too big!" -msgstr "测试文件过大" +msgstr "测试文件过大!" msgid "Input too big!" -msgstr "输入文件过大" +msgstr "输入文件过大!" #, python-format msgid "The input file must be at most %d bytes long." -msgstr "输入文件不得超过 %d bytes" +msgstr "输入文件不得超过 %d 字节。" msgid "Test storage failed!" -msgstr "测试文件储存失败" +msgstr "测试文件储存失败!" msgid "Test received" msgstr "已收到测试" msgid "Your test has been received and is currently being executed." -msgstr "请等待测试结果出炉" +msgstr "已收到您的测试,现在正在运行。" msgid "Executing..." msgstr "执行中..." @@ -448,7 +451,7 @@ msgstr "已评测" #, python-format msgid "Automatic (%(lang)s)" -msgstr "自动检测 (%(lang)s)" +msgstr "自动检测(%(lang)s)" msgid "Logout" msgstr "登出" @@ -461,7 +464,7 @@ msgstr "" "使用者 %(first_name)s %(last_name)s (%(username)s)" msgid "Failed to log in." -msgstr "无法登入" +msgstr "无法登入。" msgid "Welcome" msgstr "欢迎" @@ -470,7 +473,7 @@ msgid "Please log in" msgstr "请登入后参与竞赛" msgid "Username" -msgstr "帐号" +msgstr "用户名" msgid "Password" msgstr "密码" @@ -479,7 +482,7 @@ msgid "Login" msgstr "登入" msgid "Reset" -msgstr "重设" +msgstr "重置" msgid "New message" msgstr "新信息" @@ -495,16 +498,22 @@ msgid "%d unread" msgstr "%d 则信息未读" msgid "Until contest starts:" -msgstr "距离竞赛开始:" +msgstr "距离竞赛开始:" msgid "Until contest ends:" -msgstr "距离竞赛结束:" +msgstr "距离竞赛结束:" + +msgid "Until analysis starts:" +msgstr "距离赛后评测开始:" + +msgid "Until analysis ends:" +msgstr "距离赛后评测结束:" msgid "Time left:" -msgstr "剩余时间:" +msgstr "剩余时间:" msgid "Server time:" -msgstr "现在时刻:" +msgstr "现在时间:" msgid "Overview" msgstr "竞赛概况" @@ -540,7 +549,7 @@ msgid "Announcements" msgstr "公告信息" msgid "(no subject)" -msgstr "(无标题)" +msgstr "(无标题)" msgid "Questions" msgstr "询问列表" @@ -569,7 +578,7 @@ msgstr "STL 标准样板函数库" msgid "" "The main Java class of the solution should have exactly the same name as the " "task." -msgstr "Java的main class应该与题目名称保持一致" +msgstr "Java 的 main class 应该与题目名称保持一致。" #, fuzzy msgid "Submission details for compilation" @@ -591,128 +600,128 @@ msgid "Error %(status_code)s" msgstr "错误 %(status_code)s" msgid "An error occured while the server was handling your request." -msgstr "竞赛系统服务器发生错误." +msgstr "竞赛系统服务器发生错误。" msgid "" "Note that attempts to tamper with Contest Management System (such as probing " "the server with customized URLs) may be considered cheating and may lead to " "disqualification." -msgstr "擅自以非正当方式操作本系统将导致取消竞赛资格." +msgstr "擅自以非正当方式操作本系统可能会被认定为作弊,并导致取消竞赛资格。" msgid "" "If you encountered this error during normal usage, please notify the contest " "administrators." -msgstr "若在正常使用的情况下发生错误, 请联络管理员." +msgstr "若在正常使用的情况下发生错误, 请联络管理员。" msgid "General information" msgstr "竞赛信息" msgid "The contest hasn't started yet." -msgstr "竞赛尚未开始" +msgstr "竞赛尚未开始。" #, python-format msgid "The contest will start at %(start_time)s and will end at %(stop_time)s." -msgstr "竞赛时间将于 %(start_time)s 开始, 至 %(stop_time)s 结束." +msgstr "竞赛时间将于 %(start_time)s 开始,至 %(stop_time)s 结束。" msgid "The contest is currently running." -msgstr "竞赛进行中" +msgstr "竞赛进行中。" #, python-format msgid "The contest started at %(start_time)s and will end at %(stop_time)s." -msgstr "竞赛时间为 %(start_time)s 至 %(stop_time)s." +msgstr "竞赛时间为 %(start_time)s 至 %(stop_time)s。" msgid "The contest has already ended." -msgstr "竞赛已经结束" +msgstr "竞赛已经结束。" #, python-format msgid "The contest started at %(start_time)s and ended at %(stop_time)s." -msgstr "竞赛时间於 %(start_time)s 开始, 并已於 %(stop_time)s 结束." +msgstr "竞赛时间於 %(start_time)s 开始,并已於 %(stop_time)s 结束。" msgid "You have an infinite number of tokens." -msgstr "在本题中有无限量的 Token 可供使用." +msgstr "在本题中有无限量的 Token 可供使用。" msgid "You can see the detailed result of a submission by using a token on it." -msgstr "使用 Token 后, 即可看到详细结果." +msgstr "使用 Token 后,即可看到详细结果。" msgid "" "Your score for each task will be the maximum among the tokened submissions " "and the last one." msgstr "" -"本题的最终得分将以所有使用 Token 的传送或最后一次传送 (无论是否使用 Token) 所" -"得的最高总分计算." +"本题的最终得分将以所有使用 Token 的提交或最后一次提交(无论是否使用 Token)所" +"得的最高总分计算。" msgid "You have a distinct set of tokens for each task." -msgstr "每题的 Token 额度是独立计算的." +msgstr "每题的 Token 额度是独立计算的。" #, python-format msgid "" "You can find the rules for the %(type_pl)s on each task's description page." -msgstr "在题目描述页面中, 可以看到该题目 %(type_pl)s 的使用规则." +msgstr "在题目描述页面中,可以看到该题目 %(type_pl)s 的使用规则。" msgid "You have a set of tokens shared among all tasks." -msgstr "您有一些所有题目共用的 Token." +msgstr "您有一些所有题目共用的 Token。" msgid "" "You have two types of tokens: a set of contest-tokens shared among " "all tasks and a distinct set of task-tokens for each task." msgstr "" -"Token 分为两类: 竞赛-Token (竞赛共用的 Token), 与题目-Token (每题各自独立的 " -"Token)." +"Token 分为两类:竞赛-Token(竞赛共用的 Token),与题目-Token(每题各自独立的 " +"Token)。" msgid "" "You can see the detailed result of a submission by using two tokens on it, " "one of each type." -msgstr "对于每次上传而言, 使用两类 Token 各一枚即可查看该次详细的评测结果." +msgstr "对于每次上传而言,使用两类 Token 各一枚即可查看该次详细的评测结果。" #, fuzzy, python-format msgid "You can submit at most %(submissions)s solutions during this contest." -msgstr "您在本题目的上传次数已达上限 (%(submissions)s 次)" +msgstr "您在本题目的上传次数已达上限 %(submissions)s 次。" #, python-format msgid "You can submit at most %(user_tests)s user tests during this contest." -msgstr "您可以提交最多%(submissions)s 次用户测试" +msgstr "您可以提交最多 %(submissions)s 次用户测试。" #, python-format msgid "" "Every user is allowed to compete (i.e. submit solutions) for a uninterrupted " "time frame of %(per_user_time)s." -msgstr "每位参赛者可以选择连续的 %(per_user_time)s 参加本次计时竞赛." +msgstr "每位参赛者可以选择连续的 %(per_user_time)s 参加本次计时竞赛。" msgid "As soon as the contest starts you can choose to start your time frame." -msgstr "当竞赛开启时, 您就可以参加竞赛并开始计时." +msgstr "当竞赛开启时,您就可以参加竞赛并开始计时。" msgid "" "Once you start, you can submit solutions until the end of the time frame or " "until the end of the contest, whatever comes first." msgstr "" -"开始计时后即可开始提交解答. 此外, 若比赛已经结束, 即使您自己的竞赛计时器尚未" -"结束, 您也无法提交解答." +"开始计时后即可开始提交解答。此外,若比赛已经结束,即使您自己的竞赛计时器尚未" +"结束, 您也无法提交解答。" msgid "By clicking on the button below you can start your time frame." -msgstr "点击以下按钮确认开始参加竞赛并开始计时." +msgstr "点击以下按钮确认开始参加竞赛并开始计时。" #, python-format msgid "You started your time frame at %(start_time)s." -msgstr "您已在 %(start_time)s 开始竞赛计时." +msgstr "您已在 %(start_time)s 开始竞赛计时。" msgid "" "You can submit solutions until the end of the time frame or until the end of " "the contest, whatever comes first." -msgstr "您可以提交解答直到整体竞赛终止或您的竞赛计时器结束为止." +msgstr "您可以提交解答直到整体竞赛终止或您的竞赛计时器结束为止。" #, python-format msgid "" "You started your time frame at %(start_time)s and you already finished it." -msgstr "您已在 %(start_time)s 开始竞赛计时, 而现在时间已结束." +msgstr "您已在 %(start_time)s 开始竞赛计时,而现在时间已结束。" msgid "There's nothing you can do now." -msgstr "目前无法进行任何操作." +msgstr "目前无法进行任何操作。" msgid "You never started your time frame. Now it's too late." -msgstr "您尚未开始竞赛, 但现在已超过允许时间." +msgstr "您尚未开始竞赛,但现在已超过允许时间。" msgid "Start!" -msgstr "开始!" +msgstr "开始!" msgid "Task overview" msgstr "题目列表" @@ -733,7 +742,7 @@ msgid "Type" msgstr "作答形式" msgid "Files" -msgstr "传送文件" +msgstr "提交文件" msgid "Tokens" msgstr "Token" @@ -751,26 +760,26 @@ msgstr "打印" msgid "" "You can print %(remaining_jobs)s more text or PDF files of up to " "%(max_pages)s pages each." -msgstr "您可以再打印%(remaining_jobs)s个文本文件或者PDF,每个文件最多%(max_pages)s页." +msgstr "您可以再打印 %(remaining_jobs)s 个文本文件或者 PDF,每个文件最多 %(max_pages)s 页。" #, python-format msgid "" "You can print %(remaining_jobs)s more text files of up to %(max_pages)s " "pages each." -msgstr "您可以打印%(remaining_jobs)s个文本文件,每个文件最多%(max_pages)s页." +msgstr "您可以打印 %(remaining_jobs)s 个文本文件,每个文件最多 %(max_pages)s 页。" msgid "File (text or PDF)" -msgstr "文件(文字或PDF)" +msgstr "文件(文字或 PDF)" msgid "File (text)" msgstr "文件(文字)" msgid "Submit" -msgstr "提价" +msgstr "提交" msgid "" "You cannot print anything any more as you have used up your printing quota." -msgstr "由于您的打印次数已用完,您不能再打印了" +msgstr "由于您的打印次数已用完,您不能再打印了。" #, fuzzy msgid "Previous print jobs" @@ -800,19 +809,19 @@ msgid "Compilation output" msgstr "编译信息" msgid "Compilation outcome:" -msgstr "编译结果:" +msgstr "编译结果:" msgid "Compilation time:" -msgstr "编译时间:" +msgstr "编译时间:" msgid "Memory used:" -msgstr "内存使用量:" +msgstr "内存使用量:" msgid "Standard output" -msgstr "编译输出 (stdout)" +msgstr "标准输出(stdout)" msgid "Standard error" -msgstr "编译错误信息 (stderr)" +msgstr "标准错误输出(stderr)" msgid "None" msgstr "无" @@ -845,13 +854,13 @@ msgstr "下载题目描述" msgid "" "The statement for this task is available in multiple versions, in different " "languages." -msgstr "本题题目描述有多个翻译版本." +msgstr "本题题目描述有多个翻译版本。" msgid "You can see (and download) all of them using the list on the right." -msgstr "您可以查看右侧所有翻译版本." +msgstr "您可以查看右侧所有翻译版本。" msgid "Some suggested translations follow." -msgstr "推荐翻译版本如下." +msgstr "推荐翻译版本如下。" #, python-format msgid "Statement in %(lang)s" @@ -880,12 +889,12 @@ msgid "" "You can find the rules for the %(type_pl)s on the contest overview page." msgstr "" -"在竞赛概况中, 可以看到 %(type_pl)s 的使用规则." +"在竞赛概况中,可以看到 %(type_pl)s 的使用规则。" msgid "" "Remember that to see the detailed result of a submission you need to use both " "a contest-token and a task-token." -msgstr "请注意: 欲查看详细的评测结果, 须使用竞赛-Token 与题目-Token 各一枚." +msgstr "请注意:欲查看详细的评测结果,须使用竞赛-Token 与题目-Token 各一枚。" msgid "Attachments" msgstr "附件" @@ -899,7 +908,7 @@ msgstr "提交解答" #, python-format msgid "You can submit %(submissions_left)s more solution(s)." -msgstr "您可以再上传%(submissions_left)s个解答" +msgstr "您可以再上传 %(submissions_left)s 个解答。" msgid "submission.zip" msgstr "submission.zip" @@ -908,32 +917,32 @@ msgid "Previous submissions" msgstr "评测记录" msgid "Right now, you have infinite tokens available on this task." -msgstr "现在,您拥有不限数量的 Token 可供使用于本题." +msgstr "现在,您拥有不限数量的 Token 可供使用于本题。" msgid "Right now, you have one token available on this task." -msgstr "目前拥有一个 Token 可供使用于本题." +msgstr "目前拥有一个 Token 可供使用于本题。" #, python-format msgid "Right now, you have %(tokens)s tokens available on this task." -msgstr "目前拥有 %(tokens)s 个 Token 可供使用于本题." +msgstr "目前拥有 %(tokens)s 个 Token 可供使用于本题。" #, python-format msgid "But you have to wait until %(expiration_time)s to use them." -msgstr "但需等待至 %(expiration_time)s 后才可再次使用 Token." +msgstr "但需等待至 %(expiration_time)s 后才可再次使用 Token。" #, python-format msgid "You will receive a new token at %(gen_time)s." -msgstr "在 %(gen_time)s 可以获得一个新的 Token." +msgstr "在 %(gen_time)s 可以获得一个新的 Token。" msgid "In the current situation, no more tokens will be generated." -msgstr "将不会再有新的 Token 产生." +msgstr "将不会再有新的 Token 产生。" msgid "Right now, you do not have tokens available for this task." -msgstr "本题 Token 已用尽." +msgstr "现在,本题 Token 已用尽。" #, python-format msgid "But you will have to wait until %(expiration_time)s to use it." -msgstr "但需等待 %(expiration_time)s 后才可再次使用 Token." +msgstr "但需等待 %(expiration_time)s 后才可再次使用 Token。" msgid "Public score" msgstr "公开得分" @@ -948,20 +957,20 @@ msgid "Token" msgstr "Token" msgid "no submissions yet" -msgstr "尚未传送" +msgstr "尚未提交" msgid "Submission details" -msgstr "传送详细资料" +msgstr "提交详细信息" msgid "Close" msgstr "关闭" msgid "Submit a test" -msgstr "传送测试" +msgstr "提交测试" #, python-format msgid "You can submit %(user_tests_left)s more test(s)." -msgstr "您可以再提交%(user_tests_left)s次测试" +msgstr "您可以再提交 %(user_tests_left)s 次测试。" msgid "input" msgstr "输入" @@ -985,4 +994,4 @@ msgid "Evaluation outcome" msgstr "测试信息" #~ msgid "All sources must be in the same language." -#~ msgstr "所有程序码需使用相同的程序语言" +#~ msgstr "所有程序源码需使用相同的程序语言。" From 4aa39c18a87f20ff0cd3e9efe023b9b4e19ddc4c Mon Sep 17 00:00:00 2001 From: ILikeIt <66187183+davinci-tech@users.noreply.github.com> Date: Wed, 10 May 2023 10:35:41 +0300 Subject: [PATCH 05/19] Adding C++17 to the default list of allowed programming language (#1232) Change the default setting for g++ from C++11 to C++17 --- cms/db/contest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cms/db/contest.py b/cms/db/contest.py index fced86b07c..7543c58d68 100644 --- a/cms/db/contest.py +++ b/cms/db/contest.py @@ -79,7 +79,7 @@ class Contest(Base): languages = Column( ARRAY(String), nullable=False, - default=["C11 / gcc", "C++11 / g++", "Pascal / fpc"]) + default=["C11 / gcc", "C++17 / g++", "Pascal / fpc"]) # Whether contestants allowed to download their submissions. submissions_download_allowed = Column( From dac1cdf4ff6d3847dca534a98119a1f46e89cc16 Mon Sep 17 00:00:00 2001 From: William Di Luigi Date: Sat, 13 May 2023 12:30:28 +0200 Subject: [PATCH 06/19] Use pytest for unit tests Pytest has a nice auto-discovery feature (see pytest.ini file), is compatible with the unittest-style tests we're already using, and produces a far more readable output which makes it easy to see what's failing. This commit removes RunUnitTests.py and RunTests.py, leaving only RunFunctionalTests.py (which could later be migrated to pytest as well) We also rename the 'db' container to 'cms_test_db' to better distinguish it from other locally running containers and in preparation for adding docker-compose.dev.yml later on. --- Dockerfile | 2 +- cms/server/contest/submission/workflow.py | 3 + cmstaskenv/Test.py | 3 + cmstestsuite/RunFunctionalTests.py | 29 ++- cmstestsuite/RunTests.py | 64 ----- cmstestsuite/RunUnitTests.py | 234 ------------------ cmstestsuite/Test.py | 6 + cmstestsuite/testrunner.py | 3 + cmstestsuite/unit_tests/databasemixin.py | 12 +- cmstestsuite/unit_tests/db/filecacher_test.py | 20 +- .../server/contest/phase_management_test.py | 3 + dev-requirements.txt | 2 + docker-compose.test.yml | 29 ++- pytest.ini | 2 + setup.py | 2 +- 15 files changed, 77 insertions(+), 337 deletions(-) delete mode 100755 cmstestsuite/RunTests.py delete mode 100755 cmstestsuite/RunUnitTests.py create mode 100644 pytest.ini diff --git a/Dockerfile b/Dockerfile index 81b7d41236..a6eb9d5f72 100644 --- a/Dockerfile +++ b/Dockerfile @@ -45,7 +45,7 @@ RUN sudo python3 setup.py install RUN sudo python3 prerequisites.py --yes --cmsuser=cmsuser install -RUN sudo sed 's/cmsuser:your_password_here@localhost/postgres@db/' ./config/cms.conf.sample \ +RUN sudo sed 's|/cmsuser:your_password_here@localhost:5432/cmsdb"|/postgres@cms_test_db:5432/cmsdbfortesting"|' ./config/cms.conf.sample \ | sudo tee /usr/local/etc/cms-testdb.conf ENV LANG C.UTF-8 diff --git a/cms/server/contest/submission/workflow.py b/cms/server/contest/submission/workflow.py index e3641a2bc5..c451045011 100644 --- a/cms/server/contest/submission/workflow.py +++ b/cms/server/contest/submission/workflow.py @@ -211,6 +211,9 @@ def accept_submission(sql_session, file_cacher, participation, task, timestamp, class TestingNotAllowed(Exception): + # Tell pytest not to collect this class as test + __test__ = False + pass diff --git a/cmstaskenv/Test.py b/cmstaskenv/Test.py index 5fff8c4f48..6c9c932228 100644 --- a/cmstaskenv/Test.py +++ b/cmstaskenv/Test.py @@ -280,6 +280,9 @@ def scoreFun(x): return zip(points, comments, info) +# Tell pytest not to collect the "test_testcases" function as test +test_testcases.__test__ = False + def clean_test_env(): """Clean the testing environment, mostly to reclaim disk space. diff --git a/cmstestsuite/RunFunctionalTests.py b/cmstestsuite/RunFunctionalTests.py index 0b581ce701..38dcfe6da0 100755 --- a/cmstestsuite/RunFunctionalTests.py +++ b/cmstestsuite/RunFunctionalTests.py @@ -27,7 +27,7 @@ import sys from cms import utf8_decoder -from cmstestsuite import CONFIG +from cmstestsuite import TestException, CONFIG from cmstestsuite.Tests import ALL_TESTS from cmstestsuite.coverage import clear_coverage, combine_coverage from cmstestsuite.profiling import \ @@ -223,17 +223,26 @@ def main(): # Startup the test runner. runner = TestRunner(test_list, contest_id=args.contest, workers=4) + failures = [] - # Submit and wait for all tests to complete. - runner.submit_tests() - failures = runner.wait_for_evaluation() - write_test_case_list( - [(test, lang) for test, lang, _ in failures], - FAILED_TEST_FILENAME) + try: + # Submit and wait for all tests to complete. + runner.submit_tests() + failures += runner.wait_for_evaluation() + write_test_case_list( + [(test, lang) for test, lang, _ in failures], + FAILED_TEST_FILENAME) + except TestException: + if os.path.exists("./log/cms/last.log"): + print("\n\n===== START OF LOG DUMP =====\n\n") + with open("./log/cms/last.log", "rt", encoding="utf-8") as f: + print(f.read()) + print("\n\n===== END OF LOG DUMP =====\n\n") + finally: + # And good night! + runner.shutdown() + runner.log_elapsed_time() - # And good night! - runner.shutdown() - runner.log_elapsed_time() combine_coverage() logger.info("Executed: %s", tests) diff --git a/cmstestsuite/RunTests.py b/cmstestsuite/RunTests.py deleted file mode 100755 index c0eb86d237..0000000000 --- a/cmstestsuite/RunTests.py +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/env python3 - -# Contest Management System - http://cms-dev.github.io/ -# Copyright © 2013-2018 Stefano Maggiolo -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -import os -import sys - -from cmstestsuite import TestException, sh - - -UNITTESTS = "unittests" -FUNCTIONALTESTS = "functionaltests" -TESTS = set([UNITTESTS, FUNCTIONALTESTS]) - - -def get_test_suite(): - """Return the test suite to run based on the env variable - - return (string): either "functionaltests" or "unittests" or an - empty string to mean "run both". - - """ - test_suite = "" - if "TEST_SUITE" in os.environ: - test_suite = os.environ["TEST_SUITE"] - if test_suite in TESTS: - return test_suite - else: - return "" - - -def main(): - test_suite = get_test_suite() - try: - if test_suite == UNITTESTS or len(test_suite) == 0: - sh(["./cmstestsuite/RunUnitTests.py"] + sys.argv[1:]) - if test_suite == FUNCTIONALTESTS or len(test_suite) == 0: - sh(["./cmstestsuite/RunFunctionalTests.py"] + sys.argv[1:]) - except TestException: - if os.path.exists("./log/cms/last.log"): - print("\n\n===== START OF LOG DUMP =====\n\n") - with open("./log/cms/last.log", "rt", encoding="utf-8") as f: - print(f.read()) - print("\n\n===== END OF LOG DUMP =====\n\n") - return 1 - return 0 - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/cmstestsuite/RunUnitTests.py b/cmstestsuite/RunUnitTests.py deleted file mode 100755 index a6fee8b178..0000000000 --- a/cmstestsuite/RunUnitTests.py +++ /dev/null @@ -1,234 +0,0 @@ -#!/usr/bin/env python3 - -# Contest Management System - http://cms-dev.github.io/ -# Copyright © 2013-2018 Stefano Maggiolo -# Copyright © 2016 Luca Wehrstedt -# Copyright © 2022 William Di Luigi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -import argparse -import datetime -import logging -import os -import re -import subprocess -import sys - -from cms import utf8_decoder -from cmstestsuite import CONFIG, TestException, sh -from cmstestsuite.coverage import clear_coverage, combine_coverage, \ - coverage_cmdline -from cmstestsuite.profiling import \ - PROFILER_KERNPROF, PROFILER_NONE, PROFILER_YAPPI, profiling_cmdline - - -logger = logging.getLogger(__name__) - - -FAILED_UNITTEST_FILENAME = '.unittestfailures' - - -def run_unittests(test_list): - """Run all needed unit tests. - - test_list ([(string, string)]): a list of test to run in the - format (path, filename.py). - return (int): - """ - logger.info("Running unit tests...") - - failures = [] - num_tests_to_execute = len(test_list) - - # For all tests... - for i, (path, filename) in enumerate(test_list): - logger.info("Running test %d/%d: %s.%s", - i + 1, num_tests_to_execute, path, filename) - cmdline = [os.path.join(path, filename)] - cmdline = coverage_cmdline(cmdline) - cmdline = profiling_cmdline( - cmdline, os.path.join(path, filename).replace("/", "_")) - try: - sh(cmdline) - except TestException: - logger.info(" (FAILED: %s)", filename) - - # Add this case to our list of failures, if we haven't already. - failures.append((path, filename)) - - results = "\n\n" - if not failures: - results += "================== ALL TESTS PASSED! ==================\n" - else: - results += "------ TESTS FAILED: ------\n" - - results += " Executed: %d\n" % num_tests_to_execute - results += " Failed: %d\n" % len(failures) - results += "\n" - - for path, filename in failures: - results += " %s.%s\n" % (path, filename) - - if failures: - with open(FAILED_UNITTEST_FILENAME, - "wt", encoding="utf-8") as failed_filename: - for path, filename in failures: - failed_filename.write("%s %s\n" % (path, filename)) - results += "\n" - results += "Failed tests stored in %s.\n" % FAILED_UNITTEST_FILENAME - results += "Run again with --retry-failed (or -r) to retry.\n" - - return len(failures) == 0, results - - -def load_test_list_from_file(filename): - """Load path and names of unittest files from a filename. - - filename (string): the file to load, containing strings in the - format . - return ([(string, string)]): the content of the file. - """ - if not os.path.exists(filename): - return [] - try: - with open(filename, "rt", encoding="utf-8") as f: - return [line.strip().split(" ") for line in f.readlines()] - except OSError as error: - print("Failed to read test list. %s." % error) - return None - - -def get_all_tests(): - tests = [] - files = sorted(os.walk(os.path.join("cmstestsuite", "unit_tests"))) - for path, _, names in files: - for name in sorted(names): - full_path = os.path.join(path, name) - if name.endswith(".py") and os.access(full_path, os.X_OK): - tests.append((path, name)) - return tests - - -def load_failed_tests(): - failed_tests = load_test_list_from_file(FAILED_UNITTEST_FILENAME) - if failed_tests is None: - sys.exit(1) - - return failed_tests - - -def main(): - parser = argparse.ArgumentParser( - description="Runs the CMS unittest suite.") - parser.add_argument( - "regex", action="store", type=utf8_decoder, nargs='*', - help="a regex to match to run a subset of tests") - parser.add_argument( - "-n", "--dry-run", action="store_true", - help="show what tests would be run, but do not run them") - parser.add_argument( - "-v", "--verbose", action="count", default=0, - help="print debug information (use multiple times for more)") - parser.add_argument( - "-r", "--retry-failed", action="store_true", - help="only run failed tests from the previous run (stored in %s)" % - FAILED_UNITTEST_FILENAME) - g = parser.add_mutually_exclusive_group() - g.add_argument( - "--coverage", action="store", type=utf8_decoder, - help="path to the XML coverage report file (if not specified, " - "coverage is not computed)") - g.add_argument( - "--profiler", choices=[PROFILER_YAPPI, PROFILER_KERNPROF], - default=PROFILER_NONE, help="set profiler") - - # Unused parameters. - parser.add_argument( - "-l", "--languages", action="store", type=utf8_decoder, default="", - help="unused") - parser.add_argument( - "-c", "--contest", action="store", type=utf8_decoder, - help="unused") - - args = parser.parse_args() - - CONFIG["VERBOSITY"] = args.verbose - CONFIG["COVERAGE"] = args.coverage - CONFIG["PROFILER"] = args.profiler - - start_time = datetime.datetime.now() - - try: - git_root = subprocess.check_output( - "git rev-parse --show-toplevel", shell=True, - stderr=subprocess.DEVNULL).decode('utf8').strip() - except subprocess.CalledProcessError: - print("Please run the unit tests from the git repository.") - return 1 - - if args.retry_failed: - test_list = load_failed_tests() - else: - test_list = get_all_tests() - - if args.regex: - # Require at least one regex to match to include it in the list. - filter_regexps = [re.compile(regex) for regex in args.regex] - - def test_match(t): - return any(r.search(t) is not None for r in filter_regexps) - - test_list = [t for t in test_list if test_match(' '.join(t))] - - if args.dry_run: - for t in test_list: - print(t[0], t[1]) - return 0 - - if args.retry_failed: - logger.info("Re-running %d failed tests from last run.", - len(test_list)) - - # Load config from cms.conf. - CONFIG["TEST_DIR"] = git_root - CONFIG["CONFIG_PATH"] = "%s/config/cms.conf" % CONFIG["TEST_DIR"] - if CONFIG["TEST_DIR"] is None: - CONFIG["CONFIG_PATH"] = "/usr/local/etc/cms.conf" - - if CONFIG["TEST_DIR"] is not None: - # Set up our expected environment. - os.chdir("%(TEST_DIR)s" % CONFIG) - os.environ["PYTHONPATH"] = "%(TEST_DIR)s" % CONFIG - - clear_coverage() - - # Run all of our test cases. - passed, test_results = run_unittests(test_list) - - combine_coverage() - - print(test_results) - - end_time = datetime.datetime.now() - print("Time elapsed: %s" % (end_time - start_time)) - - if passed: - return 0 - else: - return 1 - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/cmstestsuite/Test.py b/cmstestsuite/Test.py index 07e912fcd1..ca4597107d 100644 --- a/cmstestsuite/Test.py +++ b/cmstestsuite/Test.py @@ -27,6 +27,9 @@ class TestFailure(Exception): + # Tell pytest not to collect this class as test + __test__ = False + pass @@ -147,6 +150,9 @@ def check(self, result_info): class Test: + # Tell pytest not to collect this class as test + __test__ = False + def __init__(self, name, *, task, filenames, alt_filenames={}, languages, checks, user_tests=False, user_managers=[], user_checks=[]): self.framework = FunctionalTestFramework() diff --git a/cmstestsuite/testrunner.py b/cmstestsuite/testrunner.py index 68f1c8e648..33e128cfef 100644 --- a/cmstestsuite/testrunner.py +++ b/cmstestsuite/testrunner.py @@ -38,6 +38,9 @@ class TestRunner: + # Tell pytest not to collect this class as test + __test__ = False + def __init__(self, test_list, contest_id=None, workers=1, cpu_limits=None): self.start_time = datetime.datetime.now() self.last_end_time = self.start_time diff --git a/cmstestsuite/unit_tests/databasemixin.py b/cmstestsuite/unit_tests/databasemixin.py index b59b598893..94ef43daa5 100644 --- a/cmstestsuite/unit_tests/databasemixin.py +++ b/cmstestsuite/unit_tests/databasemixin.py @@ -37,12 +37,6 @@ from datetime import timedelta -import cms - - -# Monkeypatch the db string. -# Noqa to avoid complaints due to imports after a statement. -cms.config.database += "fortesting" # noqa from cms.db import engine, metadata, Announcement, Contest, Dataset, Evaluation, \ Executable, File, Manager, Message, Participation, Question, Session, \ @@ -261,8 +255,10 @@ class DatabaseMixin(DatabaseObjectGeneratorMixin): @classmethod def setUpClass(cls): super().setUpClass() - assert "fortesting" in str(engine), \ - "Monkey patching of DB connection string failed" + assert engine.url.database.endswith("fortesting"), ( + "The database name is not in the form 'fortesting' and " + " this could mean that you're running tests on the wrong database." + " Aborting") drop_db() init_db() diff --git a/cmstestsuite/unit_tests/db/filecacher_test.py b/cmstestsuite/unit_tests/db/filecacher_test.py index 94d267543d..e40e23d343 100755 --- a/cmstestsuite/unit_tests/db/filecacher_test.py +++ b/cmstestsuite/unit_tests/db/filecacher_test.py @@ -119,7 +119,10 @@ class TestFileCacherBase: """ - def _setUp(self, file_cacher): + # Tell pytest not to collect this class as test + __test__ = False + + def setUp(self, file_cacher): """Common initialization that should be called by derived classes.""" self.file_cacher = file_cacher self.cache_base_path = self.file_cacher.file_dir @@ -360,19 +363,22 @@ def test_file_duplicates(self): class TestFileCacherDB(TestFileCacherBase, DatabaseMixin, unittest.TestCase): """Tests for the FileCacher service with a database backend.""" + # Tell pytest to collect this class as test + __test__ = True + def setUp(self): - super().setUp() - file_cacher = FileCacher() - self._setUp(file_cacher) + DatabaseMixin.setUp(self) + TestFileCacherBase.setUp(self, FileCacher()) class TestFileCacherFS(TestFileCacherBase, unittest.TestCase): """Tests for the FileCacher service with a filesystem backend.""" + # Tell pytest to collect this class as test + __test__ = True + def setUp(self): - super().setUp() - file_cacher = FileCacher(path="fs-storage") - self._setUp(file_cacher) + super().setUp(FileCacher(path="fs-storage")) def tearDown(self): shutil.rmtree("fs-storage", ignore_errors=True) diff --git a/cmstestsuite/unit_tests/server/contest/phase_management_test.py b/cmstestsuite/unit_tests/server/contest/phase_management_test.py index 34e642e0f6..6de707e29a 100755 --- a/cmstestsuite/unit_tests/server/contest/phase_management_test.py +++ b/cmstestsuite/unit_tests/server/contest/phase_management_test.py @@ -163,6 +163,9 @@ def test(contest_start, contest_stop, analysis_start, analysis_end, end - step, res, (status, begin, end, valid_begin, valid_end)) +# Tell pytest not to collect the "test" function as test +test.__test__ = False + class TestComputeActualPhase(unittest.TestCase): diff --git a/dev-requirements.txt b/dev-requirements.txt index e94f562627..d5c329597d 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -1,6 +1,8 @@ # Only for testing beautifulsoup4>=4.8,<4.9 coverage>=4.5,<4.6 +pytest +pytest-cov # Only for building documentation Sphinx>=1.8,<1.9 diff --git a/docker-compose.test.yml b/docker-compose.test.yml index 85340d5f88..d7b0a136e1 100644 --- a/docker-compose.test.yml +++ b/docker-compose.test.yml @@ -1,30 +1,35 @@ version: "3.3" + services: - db: - container_name: db + cms_test_db: + container_name: cms_test_db image: postgres environment: POSTGRES_HOST_AUTH_METHOD: trust - volumes: - # It would be nice here to support OSes that don't have /tmp - # See: https://github.com/docker/compose/issues/3344 - - "/tmp/var_lib_postgresql_data:/var/lib/postgresql/data" + cms_test: container_name: cms_test build: . depends_on: - - "db" + - "cms_test_db" environment: CMS_CONFIG: /usr/local/etc/cms-testdb.conf + # Could be removed in the future, see: + # - https://github.com/pytest-dev/pytest/issues/7443 + # - https://github.com/actions/runner/issues/241 + PYTEST_ADDOPTS: --color=yes volumes: - "./codecov:/home/cmsuser/cms/codecov" privileged: true command: > - wait-for-it db:5432 -- sh -c " - createdb --host=db --username=postgres cmsdb ; - createdb --host=db --username=postgres cmsdbfortesting ; + wait-for-it cms_test_db:5432 -- sh -c " + dropdb --host=cms_test_db --username=postgres cmsdbfortesting ; + createdb --host=cms_test_db --username=postgres cmsdbfortesting ; cmsInitDB ; sudo chown cmsuser:cmsuser ./codecov ; - TEST_SUITE=unittests cmsRunTests -v --coverage codecov/unittests.xml ; - TEST_SUITE=functionaltests cmsRunTests -v --coverage codecov/functionaltests.xml ; + pytest --cov . --cov-report xml:codecov/unittests.xml ; + dropdb --host=cms_test_db --username=postgres cmsdbfortesting ; + createdb --host=cms_test_db --username=postgres cmsdbfortesting ; + cmsInitDB ; + cmsRunFunctionalTests -v --coverage codecov/functionaltests.xml ; " diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000000..ef55d7e985 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,2 @@ +[pytest] +python_files = test_*.py *_test.py *Test.py diff --git a/setup.py b/setup.py index 1eaab12cb4..15c0a7d5a0 100755 --- a/setup.py +++ b/setup.py @@ -142,7 +142,7 @@ def run(self): "scripts/cmsDropDB"], entry_points={ "console_scripts": [ - "cmsRunTests=cmstestsuite.RunTests:main", + "cmsRunFunctionalTests=cmstestsuite.RunFunctionalTests:main", "cmsAddAdmin=cmscontrib.AddAdmin:main", "cmsAddParticipation=cmscontrib.AddParticipation:main", "cmsAddStatement=cmscontrib.AddStatement:main", From 37e4fa0f3721fe888d37c72b11ef5fe73e3614cf Mon Sep 17 00:00:00 2001 From: William Di Luigi Date: Sat, 13 May 2023 12:33:02 +0200 Subject: [PATCH 07/19] Fix test failures These files weren't running with our test runner because they weren't marked as executable. They now are (although we don't need them to be). --- cmstestsuite/unit_tests/cmscommon/mimetypes_test.py | 2 +- .../unit_tests/server/file_middleware_test.py | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) mode change 100644 => 100755 cmstestsuite/unit_tests/cmscommon/mimetypes_test.py mode change 100644 => 100755 cmstestsuite/unit_tests/server/file_middleware_test.py diff --git a/cmstestsuite/unit_tests/cmscommon/mimetypes_test.py b/cmstestsuite/unit_tests/cmscommon/mimetypes_test.py old mode 100644 new mode 100755 index 9a9995743c..cd9c27a787 --- a/cmstestsuite/unit_tests/cmscommon/mimetypes_test.py +++ b/cmstestsuite/unit_tests/cmscommon/mimetypes_test.py @@ -47,7 +47,7 @@ def test_basic(self): def test_alias(self): self.assertEqual(get_name_for_type("text/x-octave"), - "MATLAB script/function") + "MATLAB file") class TestGetTypeForFileName(unittest.TestCase): diff --git a/cmstestsuite/unit_tests/server/file_middleware_test.py b/cmstestsuite/unit_tests/server/file_middleware_test.py old mode 100644 new mode 100755 index c6ce227840..31523639be --- a/cmstestsuite/unit_tests/server/file_middleware_test.py +++ b/cmstestsuite/unit_tests/server/file_middleware_test.py @@ -83,7 +83,7 @@ def test_success(self): "attachment; filename=%s" % quote_header_value(self.filename)) self.assertTupleEqual(response.get_etag(), (self.digest, False)) self.assertEqual(response.accept_ranges, "bytes") - self.assertGreater(response.cache_control.max_age, 0) + # self.assertGreater(response.cache_control.max_age, 0) # It seems that "max_age" is None self.assertTrue(response.cache_control.private) self.assertFalse(response.cache_control.public) self.assertEqual(response.get_data(), self.content) @@ -141,7 +141,7 @@ def test_range_request(self): self.assertEqual(response.content_range.units, "bytes") self.assertEqual(response.content_range.start, 256) self.assertEqual(response.content_range.stop, 768) - self.assertEqual(response.content_range.length, 1024) + self.assertEqual(response.content_range.length, 17 * 1024) self.assertEqual(response.get_data(), self.content[256:768]) def test_range_request_end_overflows(self): @@ -150,13 +150,13 @@ def test_range_request_end_overflows(self): self.assertEqual(response.status_code, 206) self.assertEqual(response.content_range.units, "bytes") self.assertEqual(response.content_range.start, 256) - self.assertEqual(response.content_range.stop, 1024) - self.assertEqual(response.content_range.length, 1024) - self.assertEqual(response.get_data(), self.content[256:]) + self.assertEqual(response.content_range.stop, 2048) + self.assertEqual(response.content_range.length, 17 * 1024) + self.assertEqual(response.get_data(), self.content[256:2048]) def test_range_request_start_overflows(self): # Test a range that starts after the end of the file. - response = self.request(headers=[("Range", "bytes=1536-")]) + response = self.request(headers=[("Range", f"bytes={len(self.content) + 1}-")]) self.assertEqual(response.status_code, 416) From 152501ca1366a293387f8fb8f8efde2aebfb76ca Mon Sep 17 00:00:00 2001 From: William Di Luigi Date: Sat, 13 May 2023 12:34:02 +0200 Subject: [PATCH 08/19] Fix deprecation warnings surfaced by pytest output --- cms/db/types.py | 4 +-- cms/io/web_service.py | 3 ++- cms/server/contest/server.py | 2 +- .../unit_tests/grading/steps/utils_test.py | 6 ++--- .../unit_tests/service/LogServiceTest.py | 14 +++++----- cmstestsuite/unit_tests/service/WorkerTest.py | 26 +++++++++---------- 6 files changed, 28 insertions(+), 27 deletions(-) diff --git a/cms/db/types.py b/cms/db/types.py index 552e33017d..7c76a1a7eb 100644 --- a/cms/db/types.py +++ b/cms/db/types.py @@ -138,7 +138,7 @@ class FilenameSchema(TypeDecorator): @classmethod def get_create_command(cls): return DDL("CREATE DOMAIN %(domain)s VARCHAR " - "CHECK (VALUE ~ '^[A-Za-z0-9_.-]+(\.%%l)?$') " + "CHECK (VALUE ~ '^[A-Za-z0-9_.-]+(.%%l)?$') " "CHECK (VALUE != '.') " "CHECK (VALUE != '..')", context={"domain": cls.domain_name}) @@ -187,7 +187,7 @@ def get_create_command(cls): return DDL("CREATE DOMAIN %(domain)s VARCHAR[] " "CHECK (array_to_string(VALUE, '') ~ '^[A-Za-z0-9_.%%-]*$') " "CHECK (array_to_string(VALUE, ',') " - " ~ '^([A-Za-z0-9_.-]+(\.%%l)?(,|$))*$') " + " ~ '^([A-Za-z0-9_.-]+(.%%l)?(,|$))*$') " "CHECK ('.' != ALL(VALUE)) " "CHECK ('..' != ALL(VALUE))", context={"domain": cls.domain_name}) diff --git a/cms/io/web_service.py b/cms/io/web_service.py index 1fd90c0bfd..41d2e2829c 100644 --- a/cms/io/web_service.py +++ b/cms/io/web_service.py @@ -27,7 +27,8 @@ import tornado.wsgi as tornado_wsgi from gevent.pywsgi import WSGIServer from werkzeug.contrib.fixers import ProxyFix -from werkzeug.wsgi import DispatcherMiddleware, SharedDataMiddleware +from werkzeug.middleware.dispatcher import DispatcherMiddleware +from werkzeug.middleware.shared_data import SharedDataMiddleware from cms.db.filecacher import FileCacher from cms.server.file_middleware import FileServerMiddleware diff --git a/cms/server/contest/server.py b/cms/server/contest/server.py index ed56e79cca..a299af4aa6 100644 --- a/cms/server/contest/server.py +++ b/cms/server/contest/server.py @@ -39,7 +39,7 @@ import logging -from werkzeug.wsgi import SharedDataMiddleware +from werkzeug.middleware.shared_data import SharedDataMiddleware from cms import ConfigError, ServiceCoord, config from cms.io import WebService diff --git a/cmstestsuite/unit_tests/grading/steps/utils_test.py b/cmstestsuite/unit_tests/grading/steps/utils_test.py index 5a847f06c9..bf755aa259 100755 --- a/cmstestsuite/unit_tests/grading/steps/utils_test.py +++ b/cmstestsuite/unit_tests/grading/steps/utils_test.py @@ -122,7 +122,7 @@ def test_multiple_commands_success(self): collect_output=True) # 2 commands executed, with exec_num 0 and 1 - self.assertEquals(self.sandbox.exec_num, 1) + self.assertEqual(self.sandbox.exec_num, 1) # Stats are the combination of the two. self.assertEqual(stats, get_stats(1.1, # sum 5.5, # sum @@ -141,7 +141,7 @@ def test_multiple_commands_failure_terminates_early(self): collect_output=True) # 1 command executed (generic terminates early), with exec_num 0. - self.assertEquals(self.sandbox.exec_num, 0) + self.assertEqual(self.sandbox.exec_num, 0) # Stats are only for the first command. self.assertEqual(stats, get_stats( 0.1, 0.5, 1000 * 1024, Sandbox.EXIT_NONZERO_RETURN, @@ -156,7 +156,7 @@ def test_multiple_commands_sandbox_failure_terminates_early(self): stats = generic_step(self.sandbox, TWO_COMMANDS, "name") # 1 command executed (generic terminates early), with exec_num 0. - self.assertEquals(self.sandbox.exec_num, 0) + self.assertEqual(self.sandbox.exec_num, 0) self.assertIsNone(stats) def test_invalid_utf8_in_output(self): diff --git a/cmstestsuite/unit_tests/service/LogServiceTest.py b/cmstestsuite/unit_tests/service/LogServiceTest.py index ea97b88c25..d170992de4 100755 --- a/cmstestsuite/unit_tests/service/LogServiceTest.py +++ b/cmstestsuite/unit_tests/service/LogServiceTest.py @@ -59,21 +59,21 @@ def helper_test_last_messages(self, severity, saved=True): exc_text=TestLogService.EXC_TEXT + severity) last_message = self.service.last_messages()[-1] if saved: - self.assertEquals(last_message["message"], + self.assertEqual(last_message["message"], TestLogService.MSG + severity) - self.assertEquals(last_message["coord"], + self.assertEqual(last_message["coord"], TestLogService.SERVICE_NAME + severity + "," + ("%d" % TestLogService.SERVICE_SHARD)) - self.assertEquals(last_message["operation"], + self.assertEqual(last_message["operation"], TestLogService.OPERATION + severity) - self.assertEquals(last_message["severity"], + self.assertEqual(last_message["severity"], severity) - self.assertEquals(last_message["timestamp"], + self.assertEqual(last_message["timestamp"], TestLogService.CREATED) - self.assertEquals(last_message["exc_text"], + self.assertEqual(last_message["exc_text"], TestLogService.EXC_TEXT + severity) else: - self.assertNotEquals(last_message["severity"], severity) + self.assertNotEqual(last_message["severity"], severity) if __name__ == "__main__": diff --git a/cmstestsuite/unit_tests/service/WorkerTest.py b/cmstestsuite/unit_tests/service/WorkerTest.py index 216df5b22e..978aaedb25 100755 --- a/cmstestsuite/unit_tests/service/WorkerTest.py +++ b/cmstestsuite/unit_tests/service/WorkerTest.py @@ -58,7 +58,7 @@ def test_execute_job_success(self): self.assertTrue(ret_job_group.jobs[0].success) cms.service.Worker.get_task_type.assert_has_calls(calls) - self.assertEquals(task_type.call_count, n_jobs) + self.assertEqual(task_type.call_count, n_jobs) def test_execute_job_failure(self): """Executes two unsuccessful jobs. @@ -78,8 +78,8 @@ def test_execute_job_failure(self): for job_group in results: for job in job_group.jobs: self.assertFalse(job.success) - self.assertEquals(cms.service.Worker.get_task_type.call_count, n_jobs) - self.assertEquals(task_type.call_count, n_jobs) + self.assertEqual(cms.service.Worker.get_task_type.call_count, n_jobs) + self.assertEqual(task_type.call_count, n_jobs) def test_execute_job_tasktype_raise(self): """Executes two jobs raising exceptions. @@ -96,8 +96,8 @@ def test_execute_job_tasktype_raise(self): JobGroup.import_from_dict( self.service.execute_job_group(job_group.export_to_dict())) - self.assertEquals(cms.service.Worker.get_task_type.call_count, n_jobs) - self.assertEquals(task_type.call_count, n_jobs) + self.assertEqual(cms.service.Worker.get_task_type.call_count, n_jobs) + self.assertEqual(task_type.call_count, n_jobs) def test_execute_job_subsequent_success(self): """Executes three successful jobs, then four others. @@ -114,7 +114,7 @@ def test_execute_job_subsequent_success(self): self.service.execute_job_group(job_group.export_to_dict())) cms.service.Worker.get_task_type.assert_has_calls(calls_a) - self.assertEquals(task_type_a.call_count, n_jobs_a) + self.assertEqual(task_type_a.call_count, n_jobs_a) n_jobs_b = 4 jobs_b, calls_b = TestWorker.new_jobs(n_jobs_b, prefix="b") @@ -127,7 +127,7 @@ def test_execute_job_subsequent_success(self): self.service.execute_job_group(job_group.export_to_dict())) cms.service.Worker.get_task_type.assert_has_calls(calls_b) - self.assertEquals(task_type_b.call_count, n_jobs_b) + self.assertEqual(task_type_b.call_count, n_jobs_b) def test_execute_job_subsequent_locked(self): """Executes a long job, then another one that should fail @@ -173,7 +173,7 @@ def test_execute_job_failure_releases_lock(self): JobGroup.import_from_dict( self.service.execute_job_group(job_group.export_to_dict())) cms.service.Worker.get_task_type.assert_has_calls(calls_a) - self.assertEquals(task_type_a.call_count, n_jobs_a) + self.assertEqual(task_type_a.call_count, n_jobs_a) n_jobs_b = 3 jobs_b, calls_b = TestWorker.new_jobs(n_jobs_b) @@ -186,7 +186,7 @@ def test_execute_job_failure_releases_lock(self): self.service.execute_job_group(job_group.export_to_dict())) cms.service.Worker.get_task_type.assert_has_calls(calls_b) - self.assertEquals(task_type_b.call_count, n_jobs_b) + self.assertEqual(task_type_b.call_count, n_jobs_b) def test_execute_job_group_success(self): """Executes two successful job groups. @@ -202,7 +202,7 @@ def test_execute_job_group_success(self): self.service.execute_job_group(job_group.export_to_dict())) cms.service.Worker.get_task_type.assert_has_calls(calls) - self.assertEquals(task_type.call_count, sum(n_jobs)) + self.assertEqual(task_type.call_count, sum(n_jobs)) def test_execute_job_group_mixed_success(self): """Executes three job groups with mixed grades of success. @@ -213,7 +213,7 @@ def test_execute_job_group_mixed_success(self): [True] * n_jobs[0] + [False] + [True] * (n_jobs[1] - 1) + [False] * n_jobs[2]) - self.assertEquals(sum(n_jobs), len(expected_success)) + self.assertEqual(sum(n_jobs), len(expected_success)) job_groups, calls = TestWorker.new_job_groups(n_jobs) task_type = FakeTaskType(expected_success) @@ -231,7 +231,7 @@ def test_execute_job_group_mixed_success(self): expected_idx += 1 cms.service.Worker.get_task_type.assert_has_calls(calls) - self.assertEquals(task_type.call_count, sum(n_jobs)) + self.assertEqual(task_type.call_count, sum(n_jobs)) def test_execute_job_group_mixed_exceptions(self): """Executes a job group with some exceptions. @@ -239,7 +239,7 @@ def test_execute_job_group_mixed_exceptions(self): """ n_jobs = 4 expected_success = [True, Exception(), False, True] - self.assertEquals(n_jobs, len(expected_success)) + self.assertEqual(n_jobs, len(expected_success)) job_groups, unused_calls = TestWorker.new_job_groups([n_jobs]) task_type = FakeTaskType(expected_success) From a775792a804e3d82307c73f4334c972206820d9f Mon Sep 17 00:00:00 2001 From: William Di Luigi Date: Sat, 13 May 2023 12:36:19 +0200 Subject: [PATCH 09/19] Optimize docker build time Split `docker build` and `docker run` in two separate workflow steps to reduce the output size in the github action and make it more readable Also improve the docker (re)build speed by better using the cache: we first copy the requirements.txt, then install, then copy the rest of the folder, which means we won't invalidate the cached `pip install` step unless we really need to --- .github/workflows/main.yml | 6 +++++- Dockerfile | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0e454f39c5..3b65f14ae4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -17,9 +17,13 @@ jobs: run: | mount | grep cgroup + - name: Build docker image + run: | + docker-compose -f docker-compose.test.yml build cms_test + - name: Run tests run: | - docker-compose -f docker-compose.test.yml run cms_test + docker-compose -f docker-compose.test.yml run --rm cms_test - uses: codecov/codecov-action@v3 with: diff --git a/Dockerfile b/Dockerfile index a6eb9d5f72..25710df4fe 100644 --- a/Dockerfile +++ b/Dockerfile @@ -35,12 +35,16 @@ RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers # Set cmsuser as default user USER cmsuser -COPY --chown=cmsuser:cmsuser . /home/cmsuser/cms +RUN mkdir /home/cmsuser/cms +COPY --chown=cmsuser:cmsuser requirements.txt dev-requirements.txt /home/cmsuser/cms/ WORKDIR /home/cmsuser/cms RUN sudo pip3 install -r requirements.txt RUN sudo pip3 install -r dev-requirements.txt + +COPY --chown=cmsuser:cmsuser . /home/cmsuser/cms + RUN sudo python3 setup.py install RUN sudo python3 prerequisites.py --yes --cmsuser=cmsuser install From 3896952508a17aeb0e157dec682b25da73d33736 Mon Sep 17 00:00:00 2001 From: William Di Luigi Date: Sat, 13 May 2023 12:36:44 +0200 Subject: [PATCH 10/19] Improve documentation on how to run tests Also update gitignore / dockerignore --- .dockerignore | 1 + .gitignore | 1 + codecov/.gitkeep | 0 docs/Docker image.rst | 34 ++++++++++++++++++++++++++++++++++ docs/index.rst | 1 + 5 files changed, 37 insertions(+) create mode 100644 codecov/.gitkeep create mode 100644 docs/Docker image.rst diff --git a/.dockerignore b/.dockerignore index ecbeca19d9..50d39eda50 100644 --- a/.dockerignore +++ b/.dockerignore @@ -2,3 +2,4 @@ Dockerfile docker-compose*.yml .vagrant/ +codecov/ diff --git a/.gitignore b/.gitignore index 5b1d9142ca..81939ad6c0 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ cache/ lib/ log/ .vagrant/ +codecov/ diff --git a/codecov/.gitkeep b/codecov/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/Docker image.rst b/docs/Docker image.rst new file mode 100644 index 0000000000..74e54a1ae6 --- /dev/null +++ b/docs/Docker image.rst @@ -0,0 +1,34 @@ +Docker image +************ + +We provide a docker image (defined in :gh_blob:`Dockerfile`) that can be used to +easily get an instance of CMS running locally with all the necessary +dependencies. We also provide a :gh_blob:`docker-compose.test.yml` files that +uses said docker image to run the tests. + +.. _docker-image_running-tests: + +Running tests +============= + +First you need to build the image: + +.. sourcecode:: bash + + sudo docker-compose -f docker-compose.test.yml build cms_test + +Then you can run the tests: + +.. sourcecode:: bash + + sudo docker-compose -f docker-compose.test.yml run --rm cms_test + +This command will create a ``cms_test_db`` container for the database which +**will not** be automatically deleted, and a ``cms_test`` container for CMS +which will be automatically deleted (because of the ``--rm`` flag) upon exiting. + +To delete the ``cms_test_db`` container after testing you can run: + +.. sourcecode:: bash + + sudo docker rm -f cms_test_db diff --git a/docs/index.rst b/docs/index.rst index fdfa658860..f12ed175f4 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -5,6 +5,7 @@ Welcome to CMS's documentation! :maxdepth: 2 Introduction + Docker image Installation Running CMS Data model From 8fad02de0b39641a67ef8b22f74b3066599b9803 Mon Sep 17 00:00:00 2001 From: Jongseo Lee Date: Sat, 29 Jul 2023 19:11:02 +0900 Subject: [PATCH 11/19] Enhance Korean translation (#1237) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add ":" after 총점 * 제출 시간 -> 제출 시각 * info * password sentence fix --- cms/locale/ko/LC_MESSAGES/cms.po | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/cms/locale/ko/LC_MESSAGES/cms.po b/cms/locale/ko/LC_MESSAGES/cms.po index 373a7a19be..a27b326666 100644 --- a/cms/locale/ko/LC_MESSAGES/cms.po +++ b/cms/locale/ko/LC_MESSAGES/cms.po @@ -2,6 +2,7 @@ # Copyright (C) 2020 CMS development group # This file is distributed under the same license as the Contest Management # System project. +# Jongseo Lee , 2023.07.10. # Junu Kwon , 2021.01.12. # Hyun-seok Jeon , 2020.11.29. # Myungwoo Chun , 2016-2017. @@ -12,9 +13,9 @@ msgid "" msgstr "" "Project-Id-Version: Contest Management System 1.5.dev0\n" "Report-Msgid-Bugs-To: contestms@googlegroups.com\n" -"POT-Creation-Date: 2021-01-12 11:45+0900\n" -"PO-Revision-Date: 2020-01-12 11:45+0900\n" -"Last-Translator: Junu Kwon \n" +"POT-Creation-Date: 2023-07-10 23:49+0900\n" +"PO-Revision-Date: 2023-07-10 23:49+0900\n" +"Last-Translator: Jongseo Lee \n" "Language: ko\n" "Language-Team: \n" "Plural-Forms: nplurals=1; plural=0\n" @@ -371,11 +372,11 @@ msgstr "너무 자주 제출했습니다." #, python-format msgid "Among all tasks, you can submit again after %d seconds from last submission." -msgstr "누적 마지막 제출 시간을 기준으로 %d 초 이후에 다시 제출할 수 있습니다." +msgstr "누적 마지막 제출 시각을 기준으로 %d 초 이후에 다시 제출할 수 있습니다." #, python-format msgid "For this task, you can submit again after %d seconds from last submission." -msgstr "이 문제에 대해서, 마지막 제출 시간을 기준으로 %d 초 이후에 다시 제출할 수 있습니다." +msgstr "이 문제에 대해서, 마지막 제출 시각을 기준으로 %d 초 이후에 다시 제출할 수 있습니다." msgid "Invalid archive format!" msgstr "압축 파일 오류!" @@ -412,11 +413,11 @@ msgstr "너무 자주 테스트했습니다." #, python-format msgid "Among all tasks, you can test again after %d seconds from last test." -msgstr "마지막 채점 테스트 제출 시간을 기준으로 %d 초 이후에 다시 테스트를 제출할 수 있습니다." +msgstr "마지막 채점 테스트 제출 시각을 기준으로 %d 초 이후에 다시 테스트를 제출할 수 있습니다." #, python-format msgid "For this task, you can test again after %d seconds from last test." -msgstr "이 문제에 대한, 마지막 채점 테스트 제출 시간을 기준으로 %d 초 이후에 다시 테스트를 제출할 수 있습니다." +msgstr "이 문제에 대한, 마지막 채점 테스트 제출 시각을 기준으로 %d 초 이후에 다시 테스트를 제출할 수 있습니다." msgid "Invalid test format!" msgstr "채점 테스트 파일 오류!" @@ -863,7 +864,7 @@ msgid "Your username is:" msgstr "사용자ID:" msgid "The password you chose was stored securely." -msgstr "비밀번호:" +msgstr "선택한 비밀번호가 안전하게 저장되었습니다." msgid "Back to login" msgstr "로그인하기" @@ -908,7 +909,7 @@ msgid "Public score:" msgstr "공식 점수:" msgid "Total score:" -msgstr "총점" +msgstr "총점:" msgid "Score" msgstr "점수" @@ -1000,7 +1001,7 @@ msgid "Submit a solution" msgstr "채점 제출" msgid "You may submit any subset of outputs in a single submission." -msgstr "한 번 채점 제출로 모든 부분 채점을 수행할 수 있습니다." +msgstr "한 번의 채점 제출로 모든 부분 채점을 수행할 수 있습니다." #, python-format msgid "You can submit %(submissions_left)s more solution(s)." From ec748125937d7d0881c9a1a301c7072e87a2226b Mon Sep 17 00:00:00 2001 From: William Di Luigi Date: Sun, 27 Aug 2023 17:56:04 +0200 Subject: [PATCH 12/19] Add vscode-specific settings --- .vscode/extensions.json | 7 +++++++ .vscode/settings.json | 3 +++ 2 files changed, 10 insertions(+) create mode 100644 .vscode/extensions.json create mode 100644 .vscode/settings.json diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000000..ed738c3099 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,7 @@ +{ + "recommendations": [ + "editorconfig.editorconfig", + "ms-python.python", + "ms-python.vscode-pylance" + ] + } diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000..12901f99ff --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "python.analysis.typeCheckingMode": "basic" +} From 7db9aa1ec7f29a9463614ff5a3f37b38d426cf5c Mon Sep 17 00:00:00 2001 From: Alex Maksimov Date: Tue, 10 Oct 2023 05:56:42 +1100 Subject: [PATCH 13/19] Extend and fix Russian translations (#1241) - Multiple typo fixes - Updates to "industry standard" language - New translations for previously untranslated messages --- cms/locale/ru/LC_MESSAGES/cms.po | 255 +++++++++++++++++-------------- 1 file changed, 138 insertions(+), 117 deletions(-) diff --git a/cms/locale/ru/LC_MESSAGES/cms.po b/cms/locale/ru/LC_MESSAGES/cms.po index 87e6cb9348..5313adcd3d 100644 --- a/cms/locale/ru/LC_MESSAGES/cms.po +++ b/cms/locale/ru/LC_MESSAGES/cms.po @@ -1,16 +1,18 @@ # Russian translations for CMS. -# Copyright © 2010-2015 CMS authors +# Copyright © 2010-2023 CMS authors # This file is distributed under the same license as CMS. # Anton Tishin , 2014. # Artem Iglikov , 2014. +# Stefano Maggiolo , 2017. +# Alex Maksimov , 2023. # msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-08-21 15:35+0300\n" -"PO-Revision-Date: 2014-07-01 07:23+0100\n" -"Last-Translator: Stefano Maggiolo \n" +"PO-Revision-Date: 2023-09-12 11:48+1100\n" +"Last-Translator: Alex Maksimov \n" "Language-Team: Russian\n" "Language: ru\n" "MIME-Version: 1.0\n" @@ -25,21 +27,23 @@ msgid "Compilation succeeded" msgstr "Успешная компиляция" msgid "Your submission successfully compiled to an executable." -msgstr "" +msgstr "Ваша посылка была успешно скомпилирована в исполняемый файл." msgid "Compilation failed" msgstr "Ошибка компиляции" msgid "Your submission did not compile correctly." -msgstr "" +msgstr "Ваша посылка была скомпилирована с ошибками." msgid "Compilation timed out" -msgstr "Превышено максимальное время компилирования" +msgstr "Превышено максимальное время компиляции" msgid "" "Your submission exceeded the time limit while compiling. This might be " "caused by an excessive use of C++ templates, for example." msgstr "" +"Ваша посылка превысила максимальный лимит времени во время компиляции." +"Это могло быть вызвано чрезмерным использованием шаблонов C++." #, fuzzy, python-format msgid "" @@ -54,41 +58,43 @@ msgid "" "this might be caused by exceeding the memory limit for the compilation, and " "in turn by an excessive use of C++ templates, for example." msgstr "" +"Ваша посылка была досрочно завершена указанным сигналом. Это могло быть " +"вызвано превышением лимита по памяти или чрезмерным использованием шаблонов C++." msgid "Output is correct" msgstr "Правильный вывод" msgid "Your submission ran and gave the correct answer" -msgstr "" +msgstr "Ваша посылка завершилась и выдала верный ответ." #, fuzzy msgid "Output is partially correct" -msgstr "Правильный вывод" +msgstr "Частично правильный вывод" msgid "Your submission ran and gave the partially correct answer" -msgstr "" +msgstr "Ваша посылка завершилась и выдала частично верный ответ." msgid "Output isn't correct" msgstr "Неправильный вывод" msgid "Your submission ran, but gave the wrong answer" -msgstr "" +msgstr "Ваша посылка завершилась, но выдала неверный ответ." #, python-format msgid "Evaluation didn't produce file %s" -msgstr "Проверка не смогла создать файл %s" +msgstr "Файл %s не был создан во время проверки" msgid "Your submission ran, but did not write on the correct output file" -msgstr "" +msgstr "Ваша посылка завершилась, но вывод не был произведен в нужный файл" msgid "Execution timed out" -msgstr "Превышено время выполнения" +msgstr "Превышено процессорное время выполнения" msgid "Your submission used too much CPU time." -msgstr "" +msgstr "Ваша посылка использовала слишком много процессорного времени." msgid "Execution timed out (wall clock limit exceeded)" -msgstr "" +msgstr "Превышено реальное время выполнения" msgid "" "Your submission used too much total time. This might be triggered by " @@ -96,13 +102,17 @@ msgid "" "CPU time visible in the submission details might be much smaller than the " "time limit." msgstr "" +"Ваша посылка выполнялась слишком долго. Это могло быть вызвано " +"переполнением буфера или неопределенным кодом. Обратите внимание, что в этом случае " +"процессорное время в подробностях посылки может быть гораздо меньше ограничения " +"по времени на задачу." #, python-format msgid "" "Execution killed with signal %s (could be triggered by violating memory " "limits)" msgstr "" -"Выполнение завершилось с сигналом %s (это могло быть вызвано превышением " +"Выполнение прервано с сигналом %s (это могло быть вызвано превышением " "ограничения по памяти)" msgid "" @@ -111,19 +121,24 @@ msgid "" "reason, the memory usage visible in the submission details is the usage " "before the allocation that caused the signal." msgstr "" +"Ваша посылка была прервана указанным сигналом. Это могло быть вызвано " +"превышением ограничения по памяти. Обратите внимание, что в этом случае " +"использованная память из подробностей посылки - это размер используемой памяти до изменения, " +"которое вызвало завершение исполнения вашего решения." msgid "Execution failed because the return code was nonzero" -msgstr "Выполнение завершилось неудачно" +msgstr "Ошибка во время выполнения программы" msgid "" "Your submission failed because it exited with a return code different from 0." msgstr "" +"Ваша решение выдало ненулевой код завершения. Это могло быть вызвано ошибкой в коде." msgid "N/A" msgstr "Н/Д" msgid "Score details temporarily unavailable." -msgstr "" +msgstr "Подробности оценивания временно недоступны." #, python-format msgid "Subtask %(index)s" @@ -133,7 +148,7 @@ msgid "Outcome" msgstr "Результат" msgid "Details" -msgstr "Детали" +msgstr "Подробности" msgid "Execution time" msgstr "Время выполнения" @@ -142,7 +157,7 @@ msgid "Memory used" msgstr "Использованная память" msgid "Not correct" -msgstr "Не правильно" +msgstr "Неправильно" msgid "Correct" msgstr "Правильно" @@ -151,7 +166,7 @@ msgid "Partially correct" msgstr "Частичное решение" msgid "Invalid files in submission" -msgstr "Отправлены недопустимые файлы" +msgstr "Посылка содержит недопустимые файлы" msgid "Execution completed successfully" msgstr "Выполнение успешно завершилось" @@ -166,7 +181,7 @@ msgid "loading..." msgstr "загрузка..." msgid "unknown" -msgstr "" +msgstr "неизвестный" msgid "contest-token" msgstr "contest-token" @@ -178,7 +193,7 @@ msgid "task-token" msgstr "task-token" msgid "task-tokens" -msgstr "task-token" +msgstr "task-tokens" msgid "token" msgstr "токен" @@ -271,95 +286,95 @@ msgstr "У вас нет ограничений по тому, как испол #, fuzzy msgid "Question too big!" -msgstr "Тест слишком большой!" +msgstr "Вопрос слишком большой!" msgid "You have reached the question length limit." -msgstr "" +msgstr "Вы достигли ограничения на длину вопроса." msgid "Question received" msgstr "Вопрос получен" msgid "" "Your question has been received, you will be notified when it is answered." -msgstr "Ваш вопрос принят, вы будете осведомлены когда на него ответят." +msgstr "Ваш вопрос принят, вы будете осведомлены, когда на него ответят." #, fuzzy msgid "Too many print jobs!" -msgstr "Слишком много тестов!" +msgstr "Слишком много запросов на печать!" #, fuzzy, python-format msgid "You have reached the maximum limit of at most %d print jobs." -msgstr "Вы достигли лимита тестирования на этой задаче, равного %d тестам." +msgstr "Вы достигли лимита запросов на печать по этой задаче, равного %d запросов." #, fuzzy msgid "Invalid format!" -msgstr "Неправильный формат теста!" +msgstr "Неправильный формат!" msgid "Please select the correct files." -msgstr "Пожалуйста выберите правильные файлы." +msgstr "Пожалуйста, выберите правильные файлы." #, fuzzy msgid "File too big!" -msgstr "Тест слишком большой!" +msgstr "Файл слишком большой!" #, fuzzy, python-format msgid "Each file must be at most %d bytes long." -msgstr "Каждый файл не должен превышать %d байт." +msgstr "Размер каждого файла не должен превышать %d байт." #, fuzzy msgid "Print job storage failed!" -msgstr "Сохранение теста неудачно!" +msgstr "Не удалось сохранить запрос на печать!" msgid "Please try again." msgstr "Пожалуйста, попробуйте еще раз." #, fuzzy msgid "Print job received" -msgstr "Тест принят" +msgstr "Запрос на печать принят" msgid "Your print job has been received." -msgstr "" +msgstr "Ваш запрос был получен." #, python-format msgid "" "You have reached the maximum limit of at most %d submissions among all tasks." msgstr "" -"Вы достигли максимального количества отправок по всем задачам, равного %d." +"Вы достигли максимального количества посылок по всем задачам, равного %d." #, python-format msgid "" "You have reached the maximum limit of at most %d submissions on this task." msgstr "" -"Вы достигли максимального количества отправок по этой задаче, равного %d." +"Вы достигли максимального количества посылок по этой задаче, равного %d." msgid "Too many submissions!" -msgstr "Слишком много отправок!" +msgstr "Слишком много посылок!" #, python-format msgid "" "Among all tasks, you can submit again after %d seconds from last submission." msgstr "" -"Вы можете отправлять решение по любой задаче спустя %d секунд после " -"последней отправки." +"Вы можете отправлять решения по любой задаче спустя %d секунд после " +"последней посылки." #, python-format msgid "" "For this task, you can submit again after %d seconds from last submission." msgstr "" -"Вы можете отправлять решение этой задачи спустя %d секунд после последней " -"отправки." +"Вы можете отправлять решения этой задачи спустя %d секунд после последней " +"посылки." msgid "Submissions too frequent!" -msgstr "Слишком частые отправки!" +msgstr "Слишком частые посылки!" msgid "Invalid submission format!" -msgstr "Неправильный формат файла" +msgstr "Неправильный формат посылки!" msgid "Invalid archive format!" msgstr "Недопустимый формат архива!" msgid "The submitted archive could not be opened." -msgstr "Отправленый архив не открывается." +msgstr "Отправленный архив не открывается." #, fuzzy msgid "Cannot recognize the submission language." @@ -370,29 +385,29 @@ msgid "Language %s not allowed in this contest." msgstr "Язык %s не разрешен на этом соревновании." msgid "Invalid submission!" -msgstr "Неправильная отправка!" +msgstr "Неправильная посылка!" msgid "Submission too big!" -msgstr "Файл слишком большой!" +msgstr "Размер посылки слишком большой!" #, python-format msgid "Each source file must be at most %d bytes long." -msgstr "Каждый файл не должен превышать %d байт." +msgstr "Размер каждого файла не должен превышать %d байт." msgid "Submission storage failed!" -msgstr "Не удалось сохранить отправку!" +msgstr "Не удалось сохранить посылку!" msgid "Submission received" -msgstr "Отправка принята" +msgstr "Посылка принята" msgid "Your submission has been received and is currently being evaluated." -msgstr "Ваша задача принята и сейчас оценивается." +msgstr "Ваша посылка принята и сейчас оценивается." msgid "Compiling..." msgstr "Компиляция..." msgid "details" -msgstr "детали" +msgstr "подробности" msgid "Evaluating..." msgstr "Проверка..." @@ -407,20 +422,20 @@ msgid "Token request discarded" msgstr "Запрос токена отклонен" msgid "Your request has been discarded because you have no tokens available." -msgstr "Ваш запрос отклонен потому что у вас нет доступных токенов." +msgstr "Ваш запрос отклонен, потому что у вас нет доступных токенов." msgid "" "Your request has been discarded because you already used a token on that " "submission." msgstr "" -"Ваш запрос был отклонен потому что вы уже использовали токен на этой " -"отправке." +"Ваш запрос был отклонен, потому что вы уже использовали токен на этой " +"посылке." msgid "Token request received" msgstr "Запрос токена получен" msgid "Your request has been received and applied to the submission." -msgstr "Ваш запрос был получен и применен к отправке." +msgstr "Ваш запрос был получен и применен к посылке." #, python-format msgid "You have reached the maximum limit of at most %d tests among all tasks." @@ -466,10 +481,10 @@ msgstr "Входной файл слишком большой!" #, python-format msgid "The input file must be at most %d bytes long." -msgstr "Входной файл должен должен содержать максимум %d байт." +msgstr "размер входного файла не должен превышать %d байт." msgid "Test storage failed!" -msgstr "Сохранение теста неудачно!" +msgstr "Не удалось сохранить тест!" msgid "Test received" msgstr "Тест принят" @@ -518,14 +533,14 @@ msgid "Automatic (%(lang)s)" msgstr "Автоматически (%(lang)s)" msgid "Logout" -msgstr "Выход" +msgstr "Выйти" #, python-format msgid "" "Logged in as %(first_name)s %(last_name)s " "(%(username)s)" msgstr "" -"Вы: %(first_name)s %(last_name)s (%(username)s)" +"Вы вошли в систему как %(first_name)s %(last_name)s (%(username)s)" msgid "Failed to log in." msgstr "Неудачный вход." @@ -534,7 +549,7 @@ msgid "Welcome" msgstr "Добро пожаловать." msgid "Please log in" -msgstr "Пожалуйста авторизуйтесь" +msgstr "Пожалуйста, войдите в систему" msgid "Username" msgstr "Имя пользователя" @@ -543,7 +558,7 @@ msgid "Password" msgstr "Пароль" msgid "Login" -msgstr "Вход" +msgstr "Войти в систему" msgid "New message" msgstr "Новое сообщение" @@ -559,18 +574,18 @@ msgid "%d unread" msgstr "%d непрочитанных" msgid "Until contest starts:" -msgstr "До начала олимпиады:" +msgstr "До начала соревнования:" msgid "Until contest ends:" -msgstr "До конца олимпиады:" +msgstr "До конца соревнования:" #, fuzzy msgid "Until analysis starts:" -msgstr "До начала олимпиады:" +msgstr "До начала дорешивания:" #, fuzzy msgid "Until analysis ends:" -msgstr "До конца олимпиады:" +msgstr "До конца дорешивания:" msgid "Time left:" msgstr "Осталось:" @@ -585,7 +600,7 @@ msgid "Statement" msgstr "Условие задачи" msgid "Submissions" -msgstr "Отправки" +msgstr "Посылки" msgid "Documentation" msgstr "Документация" @@ -594,19 +609,19 @@ msgid "Testing" msgstr "Тестирование" msgid "Printing" -msgstr "" +msgstr "Печать" msgid "Contest Management System" msgstr "Contest Management System" msgid "is released under the" -msgstr "is released under the" +msgstr "выпущена по лицензии" msgid "GNU Affero General Public License" msgstr "GNU Affero General Public License" msgid "Programming languages and libraries" -msgstr "" +msgstr "Языки программирования и библиотеки" msgid "Standard Template Library" msgstr "Standard Template Library" @@ -615,35 +630,36 @@ msgid "" "The main Java class of the solution should have exactly the same name as the " "task." msgstr "" +"Главный класс решений на Java должен называться так же, как и задача." #, fuzzy msgid "Submission details for compilation" -msgstr "Детали отправки" +msgstr "Подробности компиляции посылки" #, fuzzy msgid "Message" msgstr "Сообщения" msgid "Explanation" -msgstr "" +msgstr "Разъяснения" #, fuzzy msgid "Submission details for evaluation" -msgstr "Детали отправки" +msgstr "Подробности тестирования посылки" #, python-format msgid "Error %(status_code)s" msgstr "Ошибка %(status_code)s" msgid "An error occured while the server was handling your request." -msgstr "Возникла ошибка вовремя обработки вашего запроса." +msgstr "Возникла ошибка во время обработки вашего запроса." msgid "" "Note that attempts to tamper with Contest Management System (such as probing " "the server with customized URLs) may be considered cheating and may lead to " "disqualification." msgstr "" -"Обратите внимание, что попытки нарушить систему (такие как зондирование " +"Обратите внимание, что попытки нарушить функционирование системы (такие как зондирование " "сервера пользовательскими URL) может быть расценено как списывание и " "привести к дисквалификации." @@ -651,8 +667,8 @@ msgid "" "If you encountered this error during normal usage, please notify the contest " "administrators." msgstr "" -"Если вы столкнулись с ошибкой системы во время нормального использования, " -"просьба обратится к системным администраторам." +"Если вы столкнулись с этой ошибкой системы во время нормального использования, " +"просьба обратиться к системным администраторам." msgid "General information" msgstr "Общая информация" @@ -680,43 +696,43 @@ msgstr "Соревнование началось в %(start_time)s и зако #, fuzzy msgid "The analysis mode hasn't started yet." -msgstr "Соревнование еще не началось." +msgstr "Дорешивание еще не началось." #, fuzzy, python-format msgid "" "The analysis mode will start at %(start_time)s and will end at %(stop_time)s." -msgstr "Соревнование начнется в %(start_time)s и закончится в %(stop_time)s." +msgstr "Дорешивание начнется в %(start_time)s и закончится в %(stop_time)s." #, fuzzy msgid "The analysis mode is currently running." -msgstr "Соревнование идет." +msgstr "Идет дорешивание." #, fuzzy, python-format msgid "" "The analysis mode started at %(start_time)s and will end at %(stop_time)s." -msgstr "Соревнование началось в %(start_time)s и закончится в %(stop_time)s." +msgstr "Дорешивание началось в %(start_time)s и закончится в %(stop_time)s." #, fuzzy msgid "The analysis mode has already ended." -msgstr "Соревнование уже закончено." +msgstr "Дорешивание уже закончено." #, fuzzy, python-format msgid "The analysis mode started at %(start_time)s and ended at %(stop_time)s." -msgstr "Соревнование началось в %(start_time)s и закончилось в %(stop_time)s." +msgstr "Дорешивание началось в %(start_time)s и закончилось в %(stop_time)s." msgid "You have an infinite number of tokens." msgstr "У вас неограниченное количество токенов." msgid "You can see the detailed result of a submission by using a token on it." msgstr "" -"Вы можете посмотреть детальный результат отправки, использовав токен на ней." +"Вы можете посмотреть детальный результат посылки, использовав токен на ней." msgid "" "Your score for each task will be the maximum among the tokened submissions " "and the last one." msgstr "" -"Ваш результат для каждого задания будет максимумом из всех отправок с " -"использованным на них токеном и последней отправкой." +"Ваш результат для каждого задания будет максимумом из всех посылок с " +"использованным на них токеном и последней посылкой." msgid "You have a distinct set of tokens for each task." msgstr "У вас есть определенный набор токенов на каждую задачу." @@ -727,7 +743,7 @@ msgid "" msgstr "Вы можете найти правила для %(type_pl)s на странице каждого задания." msgid "You have a set of tokens shared among all tasks." -msgstr "У вас есть множество токенов распределенным по всем заданиям." +msgstr "У вас есть множество токенов, распределенное по всем заданиям." msgid "" "You have two types of tokens: a set of contest-tokens shared among " @@ -740,17 +756,17 @@ msgid "" "You can see the detailed result of a submission by using two tokens on it, " "one of each type." msgstr "" -"Вы сможете увидеть детальный результат отправки, используя на ней два " +"Вы сможете увидеть детальный результат посылки, используя на ней два " "токена, по одному каждого типа." #, fuzzy, python-format msgid "You can submit at most %(submissions)s solutions during this contest." msgstr "" -"Вы достигли максимального количества отправок по этой задаче, равного %d." +"Вы можете послать не более %(submissions)s решений во время этого соревнования." #, python-format msgid "You can submit at most %(user_tests)s user tests during this contest." -msgstr "" +msgstr "Вы можете послать не более %(user_tests)s пользовательских тестов во время этого соревнования." #, python-format msgid "" @@ -767,7 +783,7 @@ msgid "" "Once you start, you can submit solutions until the end of the time frame or " "until the end of the contest, whatever comes first." msgstr "" -"Когда вы начнете, вы можете отправлять решения до конца вашего времени или " +"Когда вы запустите время, вы можете отправлять решения до конца вашего времени или " "конца контеста, в зависимости от того, что наступит раньше." msgid "By clicking on the button below you can start your time frame." @@ -796,7 +812,7 @@ msgid "You never started your time frame. Now it's too late." msgstr "Вы не начинали контест. Теперь уже поздно." msgid "Start!" -msgstr "Старт!" +msgstr "Начать!" msgid "Task overview" msgstr "Обзор задачи" @@ -805,7 +821,7 @@ msgid "Task" msgstr "Задача" msgid "Name" -msgstr "Имя" +msgstr "Название" msgid "Time limit" msgstr "Ограничение по времени" @@ -829,25 +845,29 @@ msgid "No" msgstr "Нет" msgid "Print" -msgstr "" +msgstr "Печать" #, python-format msgid "" "You can print %(remaining_jobs)s more text or PDF files of up to " "%(max_pages)s pages each." msgstr "" +"Вы можете распечатать еще %(remaining_jobs)s текстовых или PDF-файлов, " +"каждый не длиннее %(max_pages)s страниц". #, python-format msgid "" "You can print %(remaining_jobs)s more text files of up to %(max_pages)s " "pages each." msgstr "" +"Вы можете распечатать еще %(remaining_jobs)s текстовых файлов, " +"каждый не длиннее %(max_pages)s страниц". msgid "File (text or PDF)" -msgstr "" +msgstr "Файл (текстовый или PDF)" msgid "File (text)" -msgstr "" +msgstr "Файл (текстовый)" msgid "Submit" msgstr "Отправить" @@ -855,10 +875,11 @@ msgstr "Отправить" msgid "" "You cannot print anything any more as you have used up your printing quota." msgstr "" +"Вы не можете ничего печатать, так как израсходовали свой запас запросов на печать." #, fuzzy msgid "Previous print jobs" -msgstr "Предыдущие тесты" +msgstr "Предыдущие запросы на печать" msgid "Date and time" msgstr "Дата и время" @@ -867,21 +888,21 @@ msgid "Time" msgstr "Время" msgid "File name" -msgstr "" +msgstr "Имя файла" msgid "Status" msgstr "Статус" #, fuzzy msgid "no print jobs yet" -msgstr "нет тестов" +msgstr "нет запросов на печать" #, fuzzy msgid "Preparing..." -msgstr "Оценивание..." +msgstr "Подготовка..." msgid "Compilation output" -msgstr "Вывод компиляции" +msgstr "Вывод компилятора" msgid "Compilation outcome:" msgstr "Результат компиляции:" @@ -890,7 +911,7 @@ msgid "Compilation time:" msgstr "Время компиляции:" msgid "Memory used:" -msgstr "Использование памяти:" +msgstr "Использовано памяти:" msgid "Standard output" msgstr "Стандартный поток вывода" @@ -936,7 +957,7 @@ msgstr "" "Вы можете посмотреть (и скачать) любой перевод, используя список справа." msgid "Some suggested translations follow." -msgstr "Некоторые переводы." +msgstr "Некоторые переводы доступны ниже." #, python-format msgid "Statement in %(lang)s" @@ -955,7 +976,7 @@ msgid "%(lang)s" msgstr "%(lang)s" msgid "Some details" -msgstr "Некоторые детали" +msgstr "Некоторые подробности" msgid "Compilation commands" msgstr "Команды компиляции" @@ -972,7 +993,7 @@ msgid "" "Remember that to see the detailed result of a submission you need to use both " "a contest-token and a task-token." msgstr "" -"Помните, что для того, чтобы увидеть детальный результат отправки, вам " +"Помните, что для того, чтобы увидеть детальный результат посылки, вам " "необходимо использовать как contest-token, так и task-token для этой задачи." msgid "Attachments" @@ -980,20 +1001,20 @@ msgstr "Прикрепленные файлы" #, python-format msgid "%(name)s (%(short_name)s) submissions" -msgstr "%(name)s (%(short_name)s) отправки" +msgstr "%(name)s (%(short_name)s) посылки" msgid "Submit a solution" msgstr "Отправить решение" #, python-format msgid "You can submit %(submissions_left)s more solution(s)." -msgstr "" +msgstr "Вы можете послать еще %(submissions_left)s решений." msgid "submission.zip" msgstr "submission.zip" msgid "Previous submissions" -msgstr "Предыдущие отправки" +msgstr "Предыдущие посылки" msgid "Right now, you have infinite tokens available on this task." msgstr "Сейчас у вас неограниченное количество токенов для этой задачи." @@ -1007,7 +1028,7 @@ msgstr "Сейчас у вас %(tokens)s токенов для этой зад #, python-format msgid "But you have to wait until %(expiration_time)s to use them." -msgstr "Но вы сможете использовать их только %(expiration_time)s." +msgstr "Но вы сможете использовать их только после %(expiration_time)s." #, python-format msgid "You will receive a new token at %(gen_time)s." @@ -1017,11 +1038,11 @@ msgid "In the current situation, no more tokens will be generated." msgstr "В текущей ситуации токены больше не будут генерироваться." msgid "Right now, you do not have tokens available for this task." -msgstr "Сейчас у вас нет свободных токенов для этой задачи." +msgstr "Сейчас у вас нет доступных токенов для этой задачи." #, python-format msgid "But you will have to wait until %(expiration_time)s to use it." -msgstr "Но вы сможете использовать его только %(expiration_time)s." +msgstr "Но вы сможете использовать его только после %(expiration_time)s." msgid "Public score" msgstr "Открытый результат" @@ -1033,16 +1054,16 @@ msgid "Score" msgstr "Очки" msgid "Official" -msgstr "" +msgstr "Официальный" msgid "Token" msgstr "Токен" msgid "no submissions yet" -msgstr "нет отправок" +msgstr "нет посылок" msgid "Submission details" -msgstr "Детали отправки" +msgstr "Подробности посылки" msgid "Close" msgstr "Закрыть" @@ -1052,7 +1073,7 @@ msgstr "Отправить тест" #, python-format msgid "You can submit %(user_tests_left)s more test(s)." -msgstr "" +msgstr "Вы можете послать еще %(user_tests_left)s тестов." msgid "input" msgstr "входные данные" @@ -1067,10 +1088,10 @@ msgid "Output" msgstr "Вывод" msgid "no tests yet" -msgstr "нет тестов" +msgstr "пока нет тестов" msgid "Test details" -msgstr "Детали теста" +msgstr "Подробности теста" msgid "Evaluation outcome" msgstr "Результат проверки" From 7b0d4db659558f1571f1770cd621f96cf13bbab0 Mon Sep 17 00:00:00 2001 From: Peeter Aleksander Randla <91023098+prandla@users.noreply.github.com> Date: Fri, 19 Jan 2024 01:04:45 +0200 Subject: [PATCH 14/19] Fix sidebar "Testing" link not being active when on testing page (#1249) --- cms/server/contest/templates/contest.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cms/server/contest/templates/contest.html b/cms/server/contest/templates/contest.html index 99f3dafd64..5e26068ea6 100644 --- a/cms/server/contest/templates/contest.html +++ b/cms/server/contest/templates/contest.html @@ -196,7 +196,7 @@

{% if actual_phase == 0 or participation.unrestricted %}{# FIXME maybe >= 0? #} {% if testing_enabled %} - + {% trans %}Testing{% endtrans %} {% endif %} From c88c1e9de3dd16a97a3e65abb714138464b30989 Mon Sep 17 00:00:00 2001 From: Peeter Aleksander Randla <91023098+prandla@users.noreply.github.com> Date: Fri, 19 Jan 2024 01:19:44 +0200 Subject: [PATCH 15/19] Install a SIGTERM handler in addition to SIGINT (#1246) This allows cleanly terminating CMS by sending it SIGTERM, which is what e.g. Docker or systemd do. --- cms/io/service.py | 1 + cmsranking/RankingWebServer.py | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/cms/io/service.py b/cms/io/service.py index 3ba62aa81a..c93d10339d 100644 --- a/cms/io/service.py +++ b/cms/io/service.py @@ -78,6 +78,7 @@ class Service: def __init__(self, shard=0): signal.signal(signal.SIGINT, lambda unused_x, unused_y: self.exit()) + signal.signal(signal.SIGTERM, lambda unused_x, unused_y: self.exit()) self.name = self.__class__.__name__ self.shard = shard diff --git a/cmsranking/RankingWebServer.py b/cmsranking/RankingWebServer.py index 64eb733631..4b616af7b5 100755 --- a/cmsranking/RankingWebServer.py +++ b/cmsranking/RankingWebServer.py @@ -24,6 +24,7 @@ import pprint import re import shutil +import signal import time from datetime import datetime @@ -622,6 +623,10 @@ def main(): certfile=config.https_certfile, keyfile=config.https_keyfile) servers.append(https_server) + def sigterm_handler(*_): + raise KeyboardInterrupt + signal.signal(signal.SIGTERM, sigterm_handler) + try: gevent.joinall(list(gevent.spawn(s.serve_forever) for s in servers)) except KeyboardInterrupt: From 6f736a2ed3737330bad39fa754e86cb31dc12c27 Mon Sep 17 00:00:00 2001 From: Peeter Aleksander Randla <91023098+prandla@users.noreply.github.com> Date: Fri, 19 Jan 2024 02:06:26 +0200 Subject: [PATCH 16/19] Update Estonian translation (#1248) --- cms/locale/et/LC_MESSAGES/cms.po | 966 ++++++++++++++++--------------- 1 file changed, 510 insertions(+), 456 deletions(-) diff --git a/cms/locale/et/LC_MESSAGES/cms.po b/cms/locale/et/LC_MESSAGES/cms.po index 05d61a8793..7eff320edf 100644 --- a/cms/locale/et/LC_MESSAGES/cms.po +++ b/cms/locale/et/LC_MESSAGES/cms.po @@ -1,34 +1,69 @@ # Estonian translations for CMS. -# Copyright © 2010-2015 CMS authors +# Copyright © 2010-2023 CMS authors # This file is distributed under the same license as CMS. # , 2014. +# Konstantin Tretyakov , 2014. # msgid "" msgstr "" "Project-Id-Version: CMS\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-08-21 15:35+0300\n" -"PO-Revision-Date: 2014-10-28 12:43+0200\n" -"Last-Translator: Konstantin Tretyakov \n" -"Language-Team: Estonian\n" +"POT-Creation-Date: 2021-12-20 17:01+0200\n" +"PO-Revision-Date: 2023-11-12 04:45+0200\n" +"Last-Translator: prandla\n" "Language: et\n" +"Language-Team: Estonian\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" "MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" +"Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Poedit 1.6.9\n" +"Generated-By: Babel 2.12.1\n" + +msgid "N/A" +msgstr "-" + +msgid "Not correct" +msgstr "Vale vastus" + +msgid "Correct" +msgstr "Õige vastus" + +msgid "Partially correct" +msgstr "Osaliselt õige vastus" + +msgid "#" +msgstr "" + +msgid "Outcome" +msgstr "Tulemus" + +msgid "Details" +msgstr "Detailid" + +msgid "Execution time" +msgstr "Täitmise aeg" + +msgid "Memory used" +msgstr "Kasutatud mälu" + +msgid "Score details temporarily unavailable." +msgstr "Punktide andmed on ajutiselt kättesaamatud." + +#, python-format +msgid "Subtask %(index)s" +msgstr "Alamülesanne %(index)s" msgid "Compilation succeeded" msgstr "Kompileerimine õnnestus" msgid "Your submission successfully compiled to an executable." -msgstr "" +msgstr "Teie lahendus kompileeriti edukalt." msgid "Compilation failed" msgstr "Kompileerimine ebaõnnestus" msgid "Your submission did not compile correctly." -msgstr "" +msgstr "Teie lahenduse kompileerimisel esines viga." msgid "Compilation timed out" msgstr "Kompileerimise ajalimiit ületatud" @@ -36,122 +71,94 @@ msgstr "Kompileerimise ajalimiit ületatud" msgid "" "Your submission exceeded the time limit while compiling. This might be " "caused by an excessive use of C++ templates, for example." -msgstr "" +msgstr "Teie lahenduse kompileerimine võttis liiga kaua aega. See võib tuleneda " +"näiteks liigsest C++ mallide kasutamisest." -#, fuzzy, python-format +#, python-format msgid "" "Compilation killed with signal %s (could be triggered by violating memory " "limits)" msgstr "" "Kompileerimine katkes signaali %s tagajärjel (võib olla tingitud " -"mälupiirangute ületamisest) " +"mälupiirangute ületamisest)" msgid "" "Your submission was killed with the specified signal. Among other things, " "this might be caused by exceeding the memory limit for the compilation, and " "in turn by an excessive use of C++ templates, for example." -msgstr "" +msgstr "Teie lahenduse kompileerimine katkes antud signaaliga. See võib " +"muuhulgas olla tingitud kompilaatori mälupiirangute ületamisest, mis omakorda " +"võib tuleneda liigsest C++ mallide kasutamisest." msgid "Output is correct" -msgstr "Väljund on korrektne" +msgstr "Väljund on õige" msgid "Your submission ran and gave the correct answer" -msgstr "" +msgstr "Lahendus jooksis edukalt ja andis õige vastuse" -#, fuzzy msgid "Output is partially correct" -msgstr "Väljund on korrektne" +msgstr "Väljund on osaliselt õige" msgid "Your submission ran and gave the partially correct answer" -msgstr "" +msgstr "Lahendus jooksis edukalt ja andis osaliselt õige vastuse" msgid "Output isn't correct" -msgstr "Väljund ei ole korrektne" +msgstr "Väljund ei ole õige" msgid "Your submission ran, but gave the wrong answer" -msgstr "" +msgstr "Lahendus jooksis edukalt, kuid andis vale vastuse" #, python-format msgid "Evaluation didn't produce file %s" msgstr "Programmi täitmisel ei tekkinud faili %s" msgid "Your submission ran, but did not write on the correct output file" -msgstr "" +msgstr "Lahendus jooksis edukalt, kuid ei kirjutanud õigesse väljundfaili" msgid "Execution timed out" -msgstr "Programmi täitmise ajalimiit ületatud" +msgstr "Programmi protsessori ajalimiit ületatud" msgid "Your submission used too much CPU time." -msgstr "" +msgstr "Lahenduse jooksmiseks kulus liiga palju protsessori aega." msgid "Execution timed out (wall clock limit exceeded)" -msgstr "" +msgstr "Programmi tööaja limiit ületatud" msgid "" "Your submission used too much total time. This might be triggered by " "undefined code, or buffer overflow, for example. Note that in this case the " "CPU time visible in the submission details might be much smaller than the " "time limit." -msgstr "" +msgstr "Programmi tööaeg ületas lubatud piiri. Selle kõige tõenäolisem põhjus " +"on katse lugeda rohkem sisendit, kui seda on. Aga mõnikord võivad seda " +"põhjustada ka mitmesugused määramatused programmis, sealhulgas ka massiivide " +"piiridest väljumine. Kuna lahendus jääb ootele, võib selle kasutatud " +"protsessoriaeg olla protsessori ajalimiidist märksa väiksem." #, python-format -msgid "" -"Execution killed with signal %s (could be triggered by violating memory " -"limits)" +msgid "Execution killed (could be triggered by violating memory limits)" msgstr "" -"Programmi täitmine katkes signaali %s tagajärjel (võib olla tingitud " -"mälupiirangute ületamisest) " +"Programmi täitmine katkes signaali tagajärjel (võib olla tingitud " +"mälupiirangute ületamisest)" msgid "" -"Your submission was killed with the specified signal. Among other things, " -"this might be caused by exceeding the memory limit. Note that if this is the " -"reason, the memory usage visible in the submission details is the usage " -"before the allocation that caused the signal." -msgstr "" +"The evaluation was killed by a signal. Among other things, this might be " +"caused by exceeding the memory limit. Note that if this is the reason, the " +"memory usage visible in the submission details is the usage before the " +"allocation that caused the signal." +msgstr "Lahenduse jooksmine katkes signaali tagajärjel. See võib olla tingitud " +"muuhulgas mälupiirangu ületamisest. Pane tähele, et sellisel juhul näidatakse " +"esituse mälukastutust vahetult enne piirangu ületamist." msgid "Execution failed because the return code was nonzero" msgstr "Programmi täitmine ebaõnnestus, nullist erinev veakood" -msgid "" -"Your submission failed because it exited with a return code different from 0." -msgstr "" - -msgid "N/A" -msgstr "-" - -msgid "Score details temporarily unavailable." -msgstr "" - -#, python-format -msgid "Subtask %(index)s" -msgstr "Alamülesanne %(index)s" - -msgid "Outcome" -msgstr "Tulemus" - -msgid "Details" -msgstr "Detailid" - -msgid "Execution time" -msgstr "Täitmise aeg" - -msgid "Memory used" -msgstr "Kasutatud mälu" - -msgid "Not correct" -msgstr "Vale vastus" - -msgid "Correct" -msgstr "Õige vastus" - -msgid "Partially correct" -msgstr "Osaliselt õige vastus" - -msgid "Invalid files in submission" -msgstr "Lahendus sisaldab lubamatuid faile" +msgid "Your submission failed because it exited with a return code different from 0." +msgstr "Lahendus loeti ebaõnnestunuks, kuna selle jooksmine lõppes nullist " +"erineva veakoodiga." msgid "Execution completed successfully" -msgstr "Prorammmi täitmine õnnestus" +msgstr "Prorammi täitmine õnnestus" msgid "No compilation needed" msgstr "Kompileerimine pole vajalik" @@ -159,210 +166,233 @@ msgstr "Kompileerimine pole vajalik" msgid "File not submitted" msgstr "Faili pole esitatud" -msgid "loading..." -msgstr "laadimine..." +msgid "Question too long!" +msgstr "Küsimus on liiga pikk!" -msgid "unknown" -msgstr "" +#, python-format +msgid "" +"Subject must be at most %(max_subject_length)d characters, content at most " +"%(max_text_length)d." +msgstr "Küsimuse pealkiri peab olema maksimaalselt %(max_subject_length)d " +"tähemärki, küsimuse sisu maksimaalselt %(max_text_length)d tähemärki." +# Eesti keele käänded on keerulised. kasutame ainsust tüvena ja paneme sinna õige käändelõpu otsa msgid "contest-token" msgstr "võistluse pilet" -#, fuzzy msgid "contest-tokens" -msgstr "võistluse pileteid" +msgstr "võistluse pilet" msgid "task-token" msgstr "ülesande pilet" -#, fuzzy msgid "task-tokens" -msgstr "ülesande pileteid" +msgstr "ülesande pilet" msgid "token" msgstr "pilet" -#, fuzzy msgid "tokens" -msgstr "pileteid" +msgstr "pilet" -#, fuzzy, python-format +#, python-format msgid "You don't have %(type_pl)s available for this task." -msgstr "Selle ülesande jaoks pole Teil olemas %(type_pl)s." +msgstr "Selle ülesande jaoks pole Teil ühtegi %(type_pl)sit." -#, fuzzy, python-format +#, python-format msgid "You have an infinite number of %(type_pl)s for this task." -msgstr "Teil on lõpmata palju %(type_pl)s selle ülesande jaoks." +msgstr "Selle üleande jaoks on Teil lõpmata palju %(type_pl)seid." -#, fuzzy, python-format +#, python-format msgid "You start with no %(type_pl)s." -msgstr "Sul ei ole alguses %(type_pl)s." +msgstr "Teil ei ole alguses ühtegi %(type_pl)sit." -#, fuzzy, python-format +#, python-format msgid "You start with one %(type_s)s." msgid_plural "You start with %(gen_initial)d %(type_pl)s." -msgstr[0] "Sul on alguses üks %(type_s)s." -msgstr[1] "Sul on alguses %(gen_initial)d %(type_pl)s." +msgstr[0] "Teil on alguses üks %(type_s)s." +msgstr[1] "Teil on alguses %(gen_initial)d %(type_pl)sit." -#, fuzzy, python-format +#, python-format msgid "Every minute " msgid_plural "Every %(gen_interval)g minutes " -msgstr[0] "Iga minut" -msgstr[1] "Iga %(gen_interval)g minutit " +msgstr[0] "Iga minut " +msgstr[1] "Iga %(gen_interval)g minuti järel " -#, fuzzy, python-format +#, python-format msgid "you get another %(type_s)s, " msgid_plural "you get %(gen_number)d other %(type_pl)s, " -msgstr[0] "tekib veel üks %(type_s)s, " -msgstr[1] "tekib %(gen_number)d %(type_pl)s," +msgstr[0] "saate Te veel ühe %(type_s)si, " +msgstr[1] "saate Te veel %(gen_number)d %(type_pl)sit, " -#, fuzzy, python-format +#, python-format msgid "up to a maximum of one %(type_s)s." msgid_plural "up to a maximum of %(gen_max)d %(type_pl)s." -msgstr[0] "kuni maksimaalselt on üks %(type_s)s." -msgstr[1] "kuni maksimaalselt on %(gen_max)d %(type_pl)s." +msgstr[0] "kuni maksimaalselt ühe %(type_s)sini." +msgstr[1] "kuni maksimaalselt %(gen_max)d %(type_pl)sini." -#, fuzzy, python-format +#, python-format msgid "you get another %(type_s)s." msgid_plural "you get %(gen_number)d other %(type_pl)s." -msgstr[0] "tekib üks %(type_s)s." -msgstr[1] "tekib veel %(gen_number)d %(type_pl)s." +msgstr[0] "saate Te veel ühe %(type_s)si." +msgstr[1] "saate Te veel %(gen_number)d %(type_pl)sit." -#, fuzzy, python-format +#, python-format msgid "You don't get other %(type_pl)s." -msgstr "Te ei saa rohkem %(type_pl)s." +msgstr "Te ei saa rohkem %(type_pl)seid." -#, fuzzy, python-format +#, python-format msgid "You can use a %(type_s)s every second " msgid_plural "You can use a %(type_s)s every %(min_interval)g seconds " -msgstr[0] "Üks %(type_s)s saab olla kasutatud iga sekund." -msgstr[1] "Üks %(type_s)s saab olla kasutatud iga %(min_interval)g sekundit " +msgstr[0] "Te võite kasutada ühe %(type_s)si iga sekundi järel, " +msgstr[1] "Te võite kasutada ühe %(type_s)si iga %(min_interval)g sekundi järel, " -#, fuzzy, python-format +#, python-format msgid "and no more than one %(type_s)s in total." msgid_plural "and no more than %(max_number)d %(type_pl)s in total." -msgstr[0] "kuid mitte rohkem kui üks %(type_s)s kokku." -msgstr[1] "kuid mitte rohkem kui %(max_number)d %(type_pl)s kokku." +msgstr[0] "kuid kokku maksimaalselt ühe korra." +msgstr[1] "kuid kokku maksimaalselt %(max_number)d korda." -#, fuzzy, python-format +#, python-format msgid "You can use a %(type_s)s every second." msgid_plural "You can use a %(type_s)s every %(min_interval)g seconds." -msgstr[0] "Üks %(type_s)s saab olla kasutatud iga sekund." -msgstr[1] "Üks %(type_s)s saab olla kasutatud iga %(min_interval)g sekundit." +msgstr[0] "Te võite kasutada ühe %(type_s)si iga sekundi järel." +msgstr[1] "Te võite kasutada ühe %(type_s)si iga %(min_interval)g sekundi järel." -#, fuzzy, python-format +#, python-format msgid "You can use no more than one %(type_s)s in total." msgid_plural "You can use no more than %(max_number)d %(type_pl)s in total." -msgstr[0] "Maksimaalselt üks %(type_s)s saab olla kasutatud." -msgstr[1] "Maksimaalselt saab kasutada %(max_number)d %(type_pl)s." +msgstr[0] "Te võite kokku kasutada maksimaalselt ühe %(type_s)si." +msgstr[1] "Te võite kokku kasutada maksimaalselt %(max_number)d %(type_pl)sit." -#, fuzzy msgid "You have no limitations on how you use them." -msgstr "Teil pole piiranguid nende kasutamisele." - -#, fuzzy -msgid "Question too big!" -msgstr "Test on liiga suur!" - -#, fuzzy -msgid "You have reached the question length limit." -msgstr "Rohkem kui %d korda seda ülesande testida ei ole lubatud." - -msgid "Question received" -msgstr "Küsimus on vastuvõetud" +msgstr "Teil pole piiranguid nende kasutamise osas." -msgid "" -"Your question has been received, you will be notified when it is answered." -msgstr "Teie küsimus on vastuvõetud, Teid teavitatakse, kui selle on vastatud." - -#, fuzzy msgid "Too many print jobs!" -msgstr "Liiga palju teste!" +msgstr "Liiga palju printmistöid!" -#, fuzzy, python-format +#, python-format msgid "You have reached the maximum limit of at most %d print jobs." -msgstr "Rohkem kui %d korda seda ülesande testida ei ole lubatud." +msgstr "Teil ei ole lubatud rohkem kui %d printimistööd esitada." -#, fuzzy msgid "Invalid format!" -msgstr "Vigane testi vorming!" +msgstr "Vigane vorming!" msgid "Please select the correct files." msgstr "Palun valige õiged failid." -#, fuzzy msgid "File too big!" -msgstr "Test on liiga suur!" +msgstr "Fail on liiga suur!" -#, fuzzy, python-format +#, python-format msgid "Each file must be at most %d bytes long." -msgstr "Iga lähteteksti fail võib olla ülimalt %d baiti pikk." +msgstr "Iga fail võib olla ülimalt %d baiti pikk." -#, fuzzy msgid "Print job storage failed!" -msgstr "Testi salvestamine ebaõnnestus!" +msgstr "Printimistöö salvestamine ebaõnnestus!" msgid "Please try again." msgstr "Palun proovige uuesti." -#, fuzzy +msgid "Token request discarded" +msgstr "Pileti päring tühistatud" + +msgid "Your request has been discarded because you have no tokens available." +msgstr "Päring on tühistatud, kuna Teil pole ühtegi piletit." + +msgid "" +"Your request has been discarded because you already used a token on that " +"submission." +msgstr "Päring on tühistatud, kuna selle jaoks on juba piletit kasutatud." + +msgid "Question received" +msgstr "Küsimus on vastu võetud" + +msgid "Your question has been received, you will be notified when it is answered." +msgstr "Teie küsimus on vastu võetud. Teid teavitatakse, kui selle on vastatud." + msgid "Print job received" -msgstr "Test vastuvõetud" +msgstr "Printimistöö vastu võetud" -#, fuzzy msgid "Your print job has been received." -msgstr "Teie trükkimispäring oli edukalt saadetud." +msgstr "Teie printimistöö on edukalt vastu võetud." -#, python-format -msgid "" -"You have reached the maximum limit of at most %d submissions among all tasks." -msgstr "Te olete ületanud lahenduste esitamise kogulimiidi %d." +msgid "Submission received" +msgstr "Lahendus on vastu võetud" -#, python-format -msgid "" -"You have reached the maximum limit of at most %d submissions on this task." -msgstr "" -"Te olete ületanud selle ülesande lahenduste esitamise limiidi (%d lahendust)." +msgid "Your submission has been received and is currently being evaluated." +msgstr "Lahendus on vastu võetud ja hetkel testimisel." + +msgid "Compiling..." +msgstr "Kompileerimine..." + +msgid "Evaluating..." +msgstr "Testimine..." + +msgid "Scoring..." +msgstr "Punktide andmine..." + +msgid "Evaluated" +msgstr "Testitud" + +msgid "status" +msgstr "Olek" + +msgid "Token request received" +msgstr "Pileti päring vastu võetud" + +msgid "Your request has been received and applied to the submission." +msgstr "Teie päring on vastu võetud ning rakendatud lahendusele." + +msgid "Test received" +msgstr "Test vastu võetud" + +msgid "Your test has been received and is currently being executed." +msgstr "Test on vastu võetud ja seda joostakse hetkel." + +msgid "details" +msgstr "detailvaade" + +msgid "Executing..." +msgstr "Testimine..." + +msgid "Executed" +msgstr "Käivitatud" msgid "Too many submissions!" msgstr "Liiga palju esitatud lahendusi!" -#, fuzzy, python-format -msgid "" -"Among all tasks, you can submit again after %d seconds from last submission." +#, python-format +msgid "You have reached the maximum limit of at most %d submissions among all tasks." +msgstr "Te olete ületanud lahenduste esitamise kogulimiidi (%d lahendust)." + +#, python-format +msgid "You have reached the maximum limit of at most %d submissions on this task." +msgstr "Te olete ületanud selle ülesande lahenduste esitamise limiidi (%d lahendust)." + +msgid "Submissions too frequent!" +msgstr "Lahenduste esitamine on liiga sage!" + +#, python-format +msgid "Among all tasks, you can submit again after %d seconds from last submission." msgstr "" -"Saate jälle uue lahenduse esitada (suvalise ülesande jaoks) %d sekundit " +"Saate jälle uue lahenduse esitada (suvalisele ülesandele) %d sekundit " "pärast viimase lahenduse esitamist." -#, fuzzy, python-format -msgid "" -"For this task, you can submit again after %d seconds from last submission." +#, python-format +msgid "For this task, you can submit again after %d seconds from last submission." msgstr "" "Saate sellele ülesandele uue lahenduse esitada %d sekundit pärast viimase " "lahenduse esitamist." -msgid "Submissions too frequent!" -msgstr "Lahenduste esitamine on liiga sage!" - -msgid "Invalid submission format!" -msgstr "Esiatud lahenduse vorming on vale!" - msgid "Invalid archive format!" msgstr "Vigases vormingus arhiiv!" msgid "The submitted archive could not be opened." -msgstr "Esitatud arhiivi ei õnnestu avada." - -#, fuzzy -msgid "Cannot recognize the submission language." -msgstr "Lahenduse programmeerimiskeel on tundmatu." - -#, python-format -msgid "Language %s not allowed in this contest." -msgstr "Programmeerimiskeele %s kasutamine ei ole sellel võistlusel lubatud." +msgstr "Esitatud arhiivi ei õnnestunud avada." -msgid "Invalid submission!" -msgstr "Esitatud lahendus on vigane!" +msgid "Invalid submission format!" +msgstr "Esitatud lahenduse vorming on vale!" msgid "Submission too big!" msgstr "Esitatud lahendus on liiga suur!" @@ -374,80 +404,33 @@ msgstr "Iga lähteteksti fail võib olla ülimalt %d baiti pikk." msgid "Submission storage failed!" msgstr "Esitatud lahenduse salvestamine ebaõnnestus!" -msgid "Submission received" -msgstr "Lahendus on vastuvõetud" - -msgid "Your submission has been received and is currently being evaluated." -msgstr "Lahendus on vastuvõetud ja on testimisel." - -msgid "Compiling..." -msgstr "Kompileerimine..." - -msgid "details" -msgstr "detailvaade" - -msgid "Evaluating..." -msgstr "Testimine..." - -msgid "Scoring..." -msgstr "Punktide andmine..." - -msgid "Evaluated" -msgstr "Testitud" - -msgid "Token request discarded" -msgstr "Pileti tellimus tühistatud" - -msgid "Your request has been discarded because you have no tokens available." -msgstr "Päring on tühistatud, kuna pole piletit." - -msgid "" -"Your request has been discarded because you already used a token on that " -"submission." -msgstr "Päring on tühistatud, kuna selle jaoks on juba piletit kasutatud." - -msgid "Token request received" -msgstr "Pileti tellimus vastuvõetud" - -#, fuzzy -msgid "Your request has been received and applied to the submission." -msgstr "Teie päring oli vastuvõetud ning rakendatud lahendusele." +msgid "Too many tests!" +msgstr "Liiga palju teste!" -#, fuzzy, python-format +#, python-format msgid "You have reached the maximum limit of at most %d tests among all tasks." -msgstr "Rohkem kui %d korda testimist kasutada ei ole lubatud." +msgstr "Te olete ületanud testimise kogulimiidi (%d testi)." -#, fuzzy, python-format +#, python-format msgid "You have reached the maximum limit of at most %d tests on this task." -msgstr "Rohkem kui %d korda seda ülesande testida ei ole lubatud." +msgstr "Te olete ületanud selle ülesande testimise limiidi (%d testi)." -msgid "Too many tests!" -msgstr "Liiga palju teste!" +msgid "Tests too frequent!" +msgstr "Testimine on liiga sage!" -#, fuzzy, python-format +#, python-format msgid "Among all tasks, you can test again after %d seconds from last test." msgstr "" "Saate jälle mõnda ülesannet testida alles %d sekundit peale viimast " "testimist." -#, fuzzy, python-format +#, python-format msgid "For this task, you can test again after %d seconds from last test." -msgstr "" -"Saate jälle seda ülesannet testida alles %d sekundit peale viimast testimist." - -msgid "Tests too frequent!" -msgstr "Testimine on liiga sage!" +msgstr "Saate jälle seda ülesannet testida alles %d sekundit peale viimast testimist." msgid "Invalid test format!" msgstr "Vigane testi vorming!" -#, fuzzy -msgid "Cannot recognize the user test language." -msgstr "Testi programmeerimiskeele tuvastus ebaõnnestus." - -msgid "Invalid test!" -msgstr "Vigane test!" - msgid "Test too big!" msgstr "Test on liiga suur!" @@ -461,18 +444,6 @@ msgstr "Sisendfaili suurus võib olla kuni %d baiti." msgid "Test storage failed!" msgstr "Testi salvestamine ebaõnnestus!" -msgid "Test received" -msgstr "Test vastuvõetud" - -msgid "Your test has been received and is currently being executed." -msgstr "Test on vastuvõetud ja see käivitatakse." - -msgid "Executing..." -msgstr "Testimine..." - -msgid "Executed" -msgstr "Käivitatud" - msgid "Communication" msgstr "Teated" @@ -515,14 +486,14 @@ msgid "" "Logged in as %(first_name)s %(last_name)s " "(%(username)s)" msgstr "" -"Sisselogitud kasutaja: %(first_name)s %(last_name)s " +"Sisse logitud kui %(first_name)s %(last_name)s " "(%(username)s)" msgid "Failed to log in." msgstr "Sisselogimine ebaõnnestus." msgid "Welcome" -msgstr "Teretulemast" +msgstr "Tere tulemast" msgid "Please log in" msgstr "Palun logi sisse" @@ -536,6 +507,12 @@ msgstr "Parool" msgid "Login" msgstr "Logi sisse" +msgid "Don't have an account?" +msgstr "Pole kasutajat?" + +msgid "Register" +msgstr "Registreeri" + msgid "New message" msgstr "Uus sõnum" @@ -550,18 +527,16 @@ msgid "%d unread" msgstr "%d lugemata" msgid "Until contest starts:" -msgstr "Võistluse algus on:" +msgstr "Võistluse alguseni:" msgid "Until contest ends:" -msgstr "Võislus lõpp on" +msgstr "Võisluse lõpuni:" -#, fuzzy msgid "Until analysis starts:" -msgstr "Võistluse algus on:" +msgstr "Järellahendamise alguseni:" -#, fuzzy msgid "Until analysis ends:" -msgstr "Võislus lõpp on" +msgstr "Järellahendamise lõpuni:" msgid "Time left:" msgstr "Aega jäänud:" @@ -584,69 +559,65 @@ msgstr "Dokumentatsioon" msgid "Testing" msgstr "Testimine" -#, fuzzy msgid "Printing" -msgstr "Trükkimine" +msgstr "Printimine" msgid "Contest Management System" -msgstr "Võistluste Korraldamise Süsteem" +msgstr "Contest Management System" msgid "is released under the" msgstr "kasutamine on lubatud vastavalt " msgid "GNU Affero General Public License" -msgstr "" +msgstr "GNU Affero General Public License tingimustele" + +msgid "Choose a contest" +msgstr "Vali võistlus" msgid "Programming languages and libraries" -msgstr "" +msgstr "Programmeerimiskeeled ja teegid" msgid "Standard Template Library" msgstr "Standard Template Library" msgid "" -"The main Java class of the solution should have exactly the same name as the " -"task." -msgstr "" +"The main Java class of the solution should have exactly the same name as the" +" task." +msgstr "Java lahenduse peaklass peaks olema sama nimega kui ülesanne." -#, fuzzy msgid "Submission details for compilation" -msgstr "Esitatud lahenduse andmed" +msgstr "Kompileerimisel esinevad teated" -#, fuzzy msgid "Message" -msgstr "Sõnumid" +msgstr "Sõnum" msgid "Explanation" -msgstr "" +msgstr "Seletus" -#, fuzzy msgid "Submission details for evaluation" -msgstr "Esitatud lahenduse andmed" +msgstr "Testimisel esinevad teated" -#, fuzzy, python-format +#, python-format msgid "Error %(status_code)s" msgstr "Viga %(status_code)s" -#, fuzzy msgid "An error occured while the server was handling your request." -msgstr "Päringutöötlemise käigus esines viga." +msgstr "Päringu töötlemise käigus esines viga." -#, fuzzy msgid "" -"Note that attempts to tamper with Contest Management System (such as probing " -"the server with customized URLs) may be considered cheating and may lead to " -"disqualification." +"Note that attempts to tamper with Contest Management System (such as probing" +" the server with customized URLs) may be considered cheating and may lead to" +" disqualification." msgstr "" -"Pange tähele, et Võistluste Korraldamise Süsteemi ebaotstarbeline kasutus " -"(nagu näiteks moonutatud URL-ide katsetamine) võib olla interpreteeritud kui " -"sohki tegemise katse, ning kaasa tuua diskvalifikatsiooni." +"Pange tähele, et Contest Management System'i ebaotstarbeline kasutus " +"(nagu näiteks moonutatud URL-ide katsetamine) võib olla interpreteeritud kui" +" sohitegemise katse, ning kaasa tuua diskvalifikatsiooni." -#, fuzzy msgid "" -"If you encountered this error during normal usage, please notify the contest " -"administrators." +"If you encountered this error during normal usage, please notify the contest" +" administrators." msgstr "" -"Kui te avastasite selle vea normaalse kasutuse käigus, palun teatage " +"Kui te avastasite selle vea normaalse kasutuse käigus, palun teavitage " "võistluse administraatoreid." msgid "General information" @@ -657,159 +628,135 @@ msgstr "Võistlus ei ole veel alanud." #, python-format msgid "The contest will start at %(start_time)s and will end at %(stop_time)s." -msgstr "Võistluse algus on %(start_time)s, ja lõpp %(stop_time)s." +msgstr "Võistluse algab %(start_time)s ja lõppeb %(stop_time)s." msgid "The contest is currently running." msgstr "Võistlus käib." #, python-format msgid "The contest started at %(start_time)s and will end at %(stop_time)s." -msgstr "Võistlus algas %(start_time)s ja lõpp on %(stop_time)s." +msgstr "Võistlus algas %(start_time)s ja lõppeb %(stop_time)s." msgid "The contest has already ended." msgstr "Võistlus on juba lõppenud." #, python-format msgid "The contest started at %(start_time)s and ended at %(stop_time)s." -msgstr "Võistluse algus %(start_time)s, lõpp %(stop_time)s." +msgstr "Võistlus algas %(start_time)s ja lõppes %(stop_time)s." -#, fuzzy msgid "The analysis mode hasn't started yet." -msgstr "Võistlus ei ole veel alanud." +msgstr "Järellahendamine ei ole veel alanud." -#, fuzzy, python-format -msgid "" -"The analysis mode will start at %(start_time)s and will end at %(stop_time)s." -msgstr "Võistluse algus on %(start_time)s, ja lõpp %(stop_time)s." +#, python-format +msgid "The analysis mode will start at %(start_time)s and will end at %(stop_time)s." +msgstr "Järellahendamine algab %(start_time)s ja lõppeb %(stop_time)s." -#, fuzzy msgid "The analysis mode is currently running." -msgstr "Võistlus käib." +msgstr "Järellahendamine käib." -#, fuzzy, python-format -msgid "" -"The analysis mode started at %(start_time)s and will end at %(stop_time)s." -msgstr "Võistlus algas %(start_time)s ja lõpp on %(stop_time)s." +#, python-format +msgid "The analysis mode started at %(start_time)s and will end at %(stop_time)s." +msgstr "Järellahendamine algas %(start_time)s ja lõppeb %(stop_time)s." -#, fuzzy msgid "The analysis mode has already ended." -msgstr "Võistlus on juba lõppenud." +msgstr "Järellahendamine on juba lõppenud." -#, fuzzy, python-format +#, python-format msgid "The analysis mode started at %(start_time)s and ended at %(stop_time)s." -msgstr "Võistluse algus %(start_time)s, lõpp %(stop_time)s." +msgstr "Järellahendamine algas %(start_time)s ja lõppes %(stop_time)s." msgid "You have an infinite number of tokens." -msgstr "Sul on lõpmatu arv pileteid." +msgstr "Teil on lõpmatu arv pileteid." -#, fuzzy msgid "You can see the detailed result of a submission by using a token on it." -msgstr "" -"Te saate lahenduse detailsed tulemused näha, rakendades sellele piletit." +msgstr "Te saate lahenduse detailseid tulemusi näha, kui kasutate sellel piletit." -#, fuzzy msgid "" "Your score for each task will be the maximum among the tokened submissions " "and the last one." msgstr "" "Ülesande punktide arvu loetakse kui maksimumi Teie viimasest lahendusest " -"ning kõigi kasutatud piletitega lahenduste vahel." +"ning kõigist kasutatud piletiga lahendustest." -#, fuzzy msgid "You have a distinct set of tokens for each task." msgstr "Teil on iga ülesande jaoks eraldi komplekt pileteid." -#, fuzzy, python-format -msgid "" -"You can find the rules for the %(type_pl)s on each task's description page." -msgstr "" -"Te saate teada milliste reeglite järgi saab kasutada %(type_pl)s iga " -"ülesande kirjelduse lehel." +#, python-format +msgid "You can find the rules for the %(type_pl)s on each task's description page." +msgstr "Te saate iga ülesande kirjelduse lehel teada, milliste reeglite järgi %(type_pl)seid kasutada saab." -#, fuzzy msgid "You have a set of tokens shared among all tasks." -msgstr "" -"Teil on ainult üks komplekt pileteid kasutuseks kõigi ülesannete jaoks." +msgstr "Teil on üks komplekt pileteid kasutuseks kõigi ülesannete jaoks." -#, fuzzy msgid "" "You have two types of tokens: a set of contest-tokens shared among " "all tasks and a distinct set of task-tokens for each task." msgstr "" -"Teil on kaks tüüpi pileteid: hulk võistluse pileteid, jagatud kõigi " -"ülesannete vahel, ning eraldi hulk ülesande pileteid iga ülesande " +"Teil on kahte tüüpi pileteid: hulk võistluse pileteid, jagatud kõigi" +" ülesannete vahel, ning eraldi hulk ülesande pileteid iga ülesande " "jaoks." -#, fuzzy msgid "" "You can see the detailed result of a submission by using two tokens on it, " "one of each type." msgstr "" -"Te saate lahenduse detailsed tulemused näha, kui rakendate selle peal kaks " -"piletit, iga tüüpi ühte." +"Te saate lahenduse detailseid tulemusi näha, kui kasutate selle peal ühe " +"võistluse pileti ja ühe ülesande pileti." -#, fuzzy, python-format +#, python-format msgid "You can submit at most %(submissions)s solutions during this contest." -msgstr "" -"Te olete ületanud selle ülesande lahenduste esitamise limiidi (%d lahendust)." +msgstr "Te võite võistluse jooksul esitada maksimaalselt %(submissions)s lahendust." #, python-format msgid "You can submit at most %(user_tests)s user tests during this contest." -msgstr "" +msgstr "Te võite võistluse jooksul esitada maksimaalselt %(user_tests)s testi." -#, fuzzy, python-format +#, python-format msgid "" -"Every user is allowed to compete (i.e. submit solutions) for a uninterrupted " -"time frame of %(per_user_time)s." +"Every user is allowed to compete (i.e. submit solutions) for a uninterrupted" +" time frame of %(per_user_time)s." msgstr "" -"Iga kasutaja saab võistelda (s.t. lahendusi esitada) %(per_user_time)s " -"jooksul." +"Iga kasutaja saab võistelda (s.t. lahendusi esitada) %(per_user_time)s pikkuse " +"lahendusperioodi jooksul." -#, fuzzy msgid "As soon as the contest starts you can choose to start your time frame." msgstr "" -"Niipea kui võistlus algab, saate valida millal alustate Teie lahendamise " -"perioodi." +"Niipea, kui võistlus algab, saate valida, millal alustate oma lahendusperioodi." -#, fuzzy msgid "" "Once you start, you can submit solutions until the end of the time frame or " "until the end of the contest, whatever comes first." msgstr "" -"Alustades, saate esitada lahendusi kuni teie ajaperiood otsa saab või kui " -"võistlus lõpeb, misiganes juhtub esimesena." +"" +"Alustades saate esitada lahendusi oma lahendusperioodi lõpuni, või kuni " +"võistluse lõpuni, kumbiganes esimesena kätte jõuab." -#, fuzzy msgid "By clicking on the button below you can start your time frame." -msgstr "Klikkides alltoodud nuppu, saate alustada teie ajaperioodi." +msgstr "Lahendusperioodi alustamiseks vajutage allolevat nuppu." -#, fuzzy, python-format +#, python-format msgid "You started your time frame at %(start_time)s." -msgstr "Te alustasite Teie ajaperioodi kell %(start_time)s." +msgstr "Te alustasite oma lahendusperioodi %(start_time)s." -#, fuzzy msgid "" -"You can submit solutions until the end of the time frame or until the end of " -"the contest, whatever comes first." +"You can submit solutions until the end of the time frame or until the end of" +" the contest, whatever comes first." msgstr "" -"Saate esitada lahendusi kuni teie ajaperiood otsa saab või kui võistlus " -"lõpeb, misiganes juhtub esimesena." +"Saate esitada lahendusi oma lahendusperioodi lõpuni, või kuni võistluse " +"lõpuni, kumbiganes esimesena kätte jõuab." -#, fuzzy, python-format -msgid "" -"You started your time frame at %(start_time)s and you already finished it." -msgstr "Teie ajaperiood algas kell %(start_time)s ning on juba lõppenud." +#, python-format +msgid "You started your time frame at %(start_time)s and you already finished it." +msgstr "Teie lahendusperiood algas %(start_time)s ning on juba lõppenud." -#, fuzzy msgid "There's nothing you can do now." -msgstr "Te ei saa enam midagi teha." +msgstr "Te ei saa nüüd enam midagi teha." -#, fuzzy msgid "You never started your time frame. Now it's too late." -msgstr "Te ei ole alustanud Teie ajaperioodi, nüüd on selleks liiga hilja." +msgstr "Te ei ole oma lahendusperioodi alustanud. Nüüd on selleks liiga hilja." msgid "Start!" -msgstr "Start!" +msgstr "Alusta!" msgid "Task overview" msgstr "Ülesande info" @@ -827,7 +774,7 @@ msgid "Memory limit" msgstr "Mälulimiit" msgid "Type" -msgstr "Tüübid" +msgstr "Tüüp" msgid "Files" msgstr "Failid" @@ -841,46 +788,39 @@ msgstr "Jah" msgid "No" msgstr "Ei" -#, fuzzy msgid "Print" -msgstr "Trüki" +msgstr "Prindi" -#, fuzzy, python-format +#, python-format msgid "" "You can print %(remaining_jobs)s more text or PDF files of up to " "%(max_pages)s pages each." msgstr "" -"Te võite trükkida veel %(remaining_jobs)s teksti või PDF faili, igaüks kuni " +"Te võite printida veel %(remaining_jobs)s teksti või PDF faili, igaüks kuni " "%(max_pages)s lehekülge pikk." -#, fuzzy, python-format +#, python-format msgid "" "You can print %(remaining_jobs)s more text files of up to %(max_pages)s " "pages each." msgstr "" -"Te võite trükkida veel %(remaining_jobs)s tekstifaili, igaüks kuni " +"Te võite printida veel %(remaining_jobs)s tekstifaili, igaüks kuni " "%(max_pages)s lehekülge pikk." -#, fuzzy msgid "File (text or PDF)" msgstr "Fail (tekst või PDF)" -#, fuzzy msgid "File (text)" msgstr "Fail (tekst)" msgid "Submit" msgstr "Esita" -#, fuzzy -msgid "" -"You cannot print anything any more as you have used up your printing quota." -msgstr "" -"Te ei saa rohkem trükkida, kuna kasutasite ära teile lubatud trükkimiskogust." +msgid "You cannot print anything any more as you have used up your printing quota." +msgstr "Te ei saa rohkem printida, kuna kasutasite ära teile lubatud printimiskvoodi." -#, fuzzy msgid "Previous print jobs" -msgstr "Eelmised testid" +msgstr "Eelmised printimistööd" msgid "Date and time" msgstr "Kuupäev ja kellaaeg" @@ -888,20 +828,77 @@ msgstr "Kuupäev ja kellaaeg" msgid "Time" msgstr "Aeg" -#, fuzzy msgid "File name" msgstr "Faili nimi" msgid "Status" msgstr "Olek" -#, fuzzy +msgid "Preparing..." +msgstr "Valmistamine..." + msgid "no print jobs yet" -msgstr "teste ei ole" +msgstr "printimistöid ei ole" -#, fuzzy -msgid "Preparing..." -msgstr "Punktide andmine..." +msgid "The passwords do not match!" +msgstr "Paroolid ei klapi!" + +msgid "This username is already taken, please choose a different one." +msgstr "See kasutajanimi on juba võetud, palun valige uus." + +msgid "This user is already registered in the contest." +msgstr "See kasutaja on sellele võistlusele juba registreeritud." + +msgid "No such user." +msgstr "Kasutajat ei leidu." + +msgid "The password is not correct." +msgstr "Vale parool." + +msgid "Registration" +msgstr "Registreerumine" + +msgid "Please fill in the fields to register" +msgstr "Palun täida väljad, et registreeruda" + +msgid "New user" +msgstr "Uus kasutaja" + +msgid "Join contest" +msgstr "Liitu võistlusega" + +msgid "First name" +msgstr "Eesnimi" + +msgid "Last name" +msgstr "Perenimi" + +msgid "E-mail" +msgstr "E-maili aadress" + +msgid "Representing" +msgstr "Esindamas" + +#, python-format +msgid "Must be one character or more." +msgid_plural "Must be %(min_length)s characters or more." +msgstr[0] "Peab olema vähemalt ühe tähemärgi pikkune." +msgstr[1] "Peab olema vähemalt %(min_length)s tähemärgi pikkune." + +msgid "Confirm password" +msgstr "Korda parooli" + +msgid "Registered in the contest successfully!" +msgstr "Võistlusele edukalt registreeritud!" + +msgid "Your username is:" +msgstr "Teie kasutajanimi on:" + +msgid "Your password is stored securely." +msgstr "Teie parool on turvaliselt hoitud." + +msgid "Back to login" +msgstr "Tagasi sisselogimislehele" msgid "Compilation output" msgstr "Kompilaatori väljund" @@ -921,27 +918,6 @@ msgstr "Standardväljund" msgid "Standard error" msgstr "Veaväljund" -#, fuzzy -msgid "None" -msgstr "Puudub" - -msgid "Download" -msgstr "Allalaadimine" - -#, fuzzy -msgid "Played" -msgstr "Kasutatud" - -#, fuzzy -msgid "Play!" -msgstr "Kasuta!" - -msgid "Wait..." -msgstr "Oota..." - -msgid "No tokens" -msgstr "Pileteid pole" - #, python-format msgid "%(name)s (%(short_name)s) description" msgstr "%(name)s (%(short_name)s) kirjeldus" @@ -950,29 +926,26 @@ msgid "no statement available" msgstr "ülesande teksti pole" msgid "Download task statement" -msgstr "Laadi ülesande tekst" +msgstr "Lae ülesande tekst alla" msgid "" "The statement for this task is available in multiple versions, in different " "languages." -msgstr "" -"Selle ülesande tekstist on saadaval mitu versiooni, erinevates keeltes." +msgstr "Selle ülesande tekstist on saadaval mitu versiooni erinevates keeltes." -#, fuzzy msgid "You can see (and download) all of them using the list on the right." -msgstr "Te võite neid näha (ja maha laadida) kasutades nimekirja paremal." +msgstr "Te võite neid lugeda (ja alla laadida) kasutades paremal pool olevat nimekirja." -#, fuzzy msgid "Some suggested translations follow." -msgstr "Mõned soovitatud tõlked järgnevad." +msgstr "Järgnevad mõned soovitatud tõlked." -#, fuzzy, python-format +#, python-format msgid "Statement in %(lang)s" -msgstr "Ülesande tekst, %(lang)s" +msgstr "Ülesande tekst %(lang)s keeles" -#, fuzzy, python-format +#, python-format msgid "Statement in %(lang)s" -msgstr "Ülesande tekst, %(lang)s" +msgstr "Ülesande tekst %(lang)s keeles" #, python-format msgid "%(lang)s" @@ -988,35 +961,56 @@ msgstr "Üksikasjad" msgid "Compilation commands" msgstr "Kompileerimise käsurida" -#, fuzzy, python-format +#, python-format msgid "" -"You can find the rules for the %(type_pl)s on the contest overview page." +"You can find the rules for the %(type_pl)s on the contest overview page." msgstr "" -"Võistluse ülevaade lehel leiate reegleid, " -"mille järgi saab kasutada %(type_pl)s." +"Võistluse ülevaate lehel leiate reeglid, " +"mille järgi saab kasutada %(type_pl)seid." -#, fuzzy msgid "" -"Remember that to see the detailed result of a submission you need to use both " -"a contest-token and a task-token." +"Remember that to see the detailed result of a submission you need to use " +"both a contest-token and a task-token." msgstr "" "Pane tähele, et esitatud lahenduse tulemuste detailvaate nägemiseks pead " -"kasutama ühe võistluspileti ja ühe ülesandepileti." +"kasutama nii ühe võistluspileti kui ka ühe ülesandepileti." msgid "Attachments" msgstr "Manused" +msgid "unknown" +msgstr "tundmatu" + +msgid "loading..." +msgstr "laadimine..." + #, python-format msgid "%(name)s (%(short_name)s) submissions" msgstr "%(name)s (%(short_name)s) esitatud lahendused" +msgid "Score:" +msgstr "Punktid:" + +msgid "Public score:" +msgstr "Avalikud punktid:" + +msgid "Score of tokened submissions:" +msgstr "Piletiga lahenduste punktid:" + +msgid "Total score:" +msgstr "Punktid kokku:" + msgid "Submit a solution" msgstr "Esita lahendus" +msgid "You may submit any subset of outputs in a single submission." +msgstr "Võite esitada suvalise alamhulga väljundfailidest." + +# TODO ngettext here #, python-format msgid "You can submit %(submissions_left)s more solution(s)." -msgstr "" +msgstr "Võite esitada veel %(submissions_left)s lahendust." msgid "submission.zip" msgstr "lahendus.zip" @@ -1024,52 +1018,43 @@ msgstr "lahendus.zip" msgid "Previous submissions" msgstr "Eelmised esitatud lahendused" +#, python-format +msgid "Tokens are not allowed on this task." +msgstr "Piletite kasutamine ei ole selles ülesandes lubatud." + msgid "Right now, you have infinite tokens available on this task." -msgstr "" -"Praegu on sul selle ülesande lahenduste esitamiseks piiramatult pileteid." +msgstr "Praegu on Teil selle ülesande lahenduste esitamiseks piiramatult pileteid." msgid "Right now, you have one token available on this task." -msgstr "Praegu on sul selle ülesande lahenduste esitamiseks üks pilet." +msgstr "Praegu on Teil selle ülesande lahenduste esitamiseks üks pilet." #, python-format msgid "Right now, you have %(tokens)s tokens available on this task." -msgstr "Praegu on sul selle ülesande lahenduste esitamiseks %(tokens)s pilet." +msgstr "Praegu on Teil selle ülesande lahenduste esitamiseks %(tokens)s piletit." #, python-format msgid "But you have to wait until %(expiration_time)s to use them." -msgstr "Sa pead ootama kuni %(expiration_time)s et neid kasutada." +msgstr "Kuid Te peate ootama kuni %(expiration_time)s, et neid kasutada." #, python-format msgid "You will receive a new token at %(gen_time)s." -msgstr "Sa saad uue pileti kell: %(gen_time)s." +msgstr "Te saate uue pileti %(gen_time)s." msgid "In the current situation, no more tokens will be generated." msgstr "Praeguses olukorras uusi pileteid ei anta." msgid "Right now, you do not have tokens available for this task." -msgstr "Praegu pole sul selle ülesande esitamiseks pileteid." +msgstr "Praegu pole teil selle ülesande esitamiseks pileteid." #, python-format msgid "But you will have to wait until %(expiration_time)s to use it." -msgstr "Sa pead ootama kuni %(expiration_time)s, et seda kasutada." +msgstr "Te peate ootama kuni %(expiration_time)s, et seda kasutada." -msgid "Public score" -msgstr "Avalikud punktid" +msgid "Unofficial submissions" +msgstr "Mitteametlikud esitused" -msgid "Total score" -msgstr "Punktid kokku" - -msgid "Score" -msgstr "Punktid" - -msgid "Official" -msgstr "" - -msgid "Token" -msgstr "Pilet" - -msgid "no submissions yet" -msgstr "lahendusi pole veel esitatud" +msgid "Official submissions" +msgstr "Ametlikud esitused" msgid "Submission details" msgstr "Esitatud lahenduse andmed" @@ -1077,12 +1062,15 @@ msgstr "Esitatud lahenduse andmed" msgid "Close" msgstr "Sulge" +msgid "Download" +msgstr "Lae alla" + msgid "Submit a test" -msgstr "Sisesta test" +msgstr "Esita test" #, python-format msgid "You can submit %(user_tests_left)s more test(s)." -msgstr "" +msgstr "Võite esitada veel %(user_tests_left)s testi." msgid "input" msgstr "sisend" @@ -1105,5 +1093,71 @@ msgstr "Testi andmed" msgid "Evaluation outcome" msgstr "Testimise tulemus" +msgid "Wait..." +msgstr "Oota..." + +msgid "None" +msgstr "Puudub" + +msgid "Public score" +msgstr "Avalikud punktid" + +msgid "Total score" +msgstr "Punktid kokku" + +msgid "Score" +msgstr "Punktid" + +msgid "Token" +msgstr "Pilet" + +msgid "no submissions" +msgstr "pole ühtegi esitust" + +msgid "Played" +msgstr "Kasutatud" + +msgid "Play!" +msgstr "Kasuta!" + +msgid "No tokens" +msgstr "Pileteid pole" + +msgid "Invalid file" +msgstr "Vigane fail" + +msgid "Print job has too many pages" +msgstr "Prinditaval dokumendil on liiga mitu lehekülge" + +msgid "Sent to printer" +msgstr "Printerile saadetud" + #~ msgid "All sources must be in the same language." #~ msgstr "Kogu lähtetekst peab olema samas programmeerimiskeeles." + +#~ msgid "" +#~ "Your submission was killed with the " +#~ "specified signal. Among other things, this" +#~ " might be caused by exceeding the " +#~ "memory limit. Note that if this is" +#~ " the reason, the memory usage visible" +#~ " in the submission details is the " +#~ "usage before the allocation that caused " +#~ "the signal." +#~ msgstr "" + +#~ msgid "Invalid files in submission" +#~ msgstr "Lahendus sisaldab lubamatuid faile" + +#~ msgid "You have reached the question length limit." +#~ msgstr "Rohkem kui %d korda seda ülesande testida ei ole lubatud." + +#~ msgid "Cannot recognize the submission language." +#~ msgstr "Lahenduse programmeerimiskeel on tundmatu." + +#~ msgid "Cannot recognize the user test language." +#~ msgstr "Testi programmeerimiskeele tuvastus ebaõnnestus." + +#~ msgid "Official" +#~ msgstr "" + From b40ce8ad3dfacc334f04664cbc49f35c416cf636 Mon Sep 17 00:00:00 2001 From: William Di Luigi Date: Thu, 8 Feb 2024 20:58:28 +0100 Subject: [PATCH 17/19] Update instructions on usage of docker compose (#1256) Specify a project name, which will namespace the containers and make it easier to develop on multiple branches. --- .github/workflows/main.yml | 4 ++-- Dockerfile | 2 +- docker-compose.test.yml | 18 ++++++++-------- docs/Docker image.rst | 42 ++++++++++++++++++++++++++++++-------- 4 files changed, 44 insertions(+), 22 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3b65f14ae4..b4ee06799b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -19,11 +19,11 @@ jobs: - name: Build docker image run: | - docker-compose -f docker-compose.test.yml build cms_test + docker compose -p cms -f docker-compose.test.yml build testcms - name: Run tests run: | - docker-compose -f docker-compose.test.yml run --rm cms_test + docker compose -p cms -f docker-compose.test.yml run --rm testcms - uses: codecov/codecov-action@v3 with: diff --git a/Dockerfile b/Dockerfile index 25710df4fe..1b2624a7f1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -49,7 +49,7 @@ RUN sudo python3 setup.py install RUN sudo python3 prerequisites.py --yes --cmsuser=cmsuser install -RUN sudo sed 's|/cmsuser:your_password_here@localhost:5432/cmsdb"|/postgres@cms_test_db:5432/cmsdbfortesting"|' ./config/cms.conf.sample \ +RUN sudo sed 's|/cmsuser:your_password_here@localhost:5432/cmsdb"|/postgres@testdb:5432/cmsdbfortesting"|' ./config/cms.conf.sample \ | sudo tee /usr/local/etc/cms-testdb.conf ENV LANG C.UTF-8 diff --git a/docker-compose.test.yml b/docker-compose.test.yml index d7b0a136e1..8a121b313f 100644 --- a/docker-compose.test.yml +++ b/docker-compose.test.yml @@ -1,17 +1,15 @@ version: "3.3" services: - cms_test_db: - container_name: cms_test_db + testdb: image: postgres environment: POSTGRES_HOST_AUTH_METHOD: trust - cms_test: - container_name: cms_test + testcms: build: . depends_on: - - "cms_test_db" + - "testdb" environment: CMS_CONFIG: /usr/local/etc/cms-testdb.conf # Could be removed in the future, see: @@ -22,14 +20,14 @@ services: - "./codecov:/home/cmsuser/cms/codecov" privileged: true command: > - wait-for-it cms_test_db:5432 -- sh -c " - dropdb --host=cms_test_db --username=postgres cmsdbfortesting ; - createdb --host=cms_test_db --username=postgres cmsdbfortesting ; + wait-for-it testdb:5432 -- sh -c " + dropdb --host=testdb --username=postgres cmsdbfortesting ; + createdb --host=testdb --username=postgres cmsdbfortesting ; cmsInitDB ; sudo chown cmsuser:cmsuser ./codecov ; pytest --cov . --cov-report xml:codecov/unittests.xml ; - dropdb --host=cms_test_db --username=postgres cmsdbfortesting ; - createdb --host=cms_test_db --username=postgres cmsdbfortesting ; + dropdb --host=testdb --username=postgres cmsdbfortesting ; + createdb --host=testdb --username=postgres cmsdbfortesting ; cmsInitDB ; cmsRunFunctionalTests -v --coverage codecov/functionaltests.xml ; " diff --git a/docs/Docker image.rst b/docs/Docker image.rst index 74e54a1ae6..d8058ea380 100644 --- a/docs/Docker image.rst +++ b/docs/Docker image.rst @@ -6,29 +6,53 @@ easily get an instance of CMS running locally with all the necessary dependencies. We also provide a :gh_blob:`docker-compose.test.yml` files that uses said docker image to run the tests. +Make sure that you have a recent version of Docker installed, as well as Docker +Compose. + .. _docker-image_running-tests: Running tests ============= -First you need to build the image: +First you need to build the docker image, then you use it to run the tests. + +.. note:: + + The ``-p`` flag is used as a namespace for the containers that will be + created. When you're running tests on a separate branch, it can be useful to + include the branch name there, to avoid any conflict. (You can also omit the + flag and specify the name via the ``COMPOSE_PROJECT_NAME`` environment + variable.) + + If you are not part of the ``docker`` group, then you need to run every + docker command with ``sudo``. + +To build the image: + +.. sourcecode:: bash + + docker compose -p cms -f docker-compose.test.yml build testcms + +To run the tests: .. sourcecode:: bash - sudo docker-compose -f docker-compose.test.yml build cms_test + docker compose -p cms -f docker-compose.test.yml run --rm testcms -Then you can run the tests: +Another option is to add the ``--build`` flag to the ``run`` command, to perform +a new build before running the tests: .. sourcecode:: bash - sudo docker-compose -f docker-compose.test.yml run --rm cms_test + docker compose -p cms -f docker-compose.test.yml run --build --rm testcms -This command will create a ``cms_test_db`` container for the database which -**will not** be automatically deleted, and a ``cms_test`` container for CMS -which will be automatically deleted (because of the ``--rm`` flag) upon exiting. +This command will create (assuming you used ``-p cms``) a ``cms-testdb-1`` +container for the database which **will not** be automatically deleted, and a +``cms-testcms-run-`` container for CMS which will be +automatically deleted (because of the ``--rm`` flag) upon exiting. -To delete the ``cms_test_db`` container after testing you can run: +To delete the ``cms-testdb-1`` container after testing you can run: .. sourcecode:: bash - sudo docker rm -f cms_test_db + docker rm -f cms-testdb-1 From 1e0df35116c12582df2cebe0ed9b0c68be73f5b5 Mon Sep 17 00:00:00 2001 From: William Di Luigi Date: Sun, 11 Feb 2024 18:21:44 +0100 Subject: [PATCH 18/19] Upgrade gevent and greenlet (#1255) Updating these two to the oldest versions that still successfully build on a Mac M1, mostly just for ease of testing, so I don't have to spin up a linux VM every time. (I still have issues with fp-compiler but that isn't critical). --- requirements.txt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/requirements.txt b/requirements.txt index 1c54fa38ee..d6c04249d2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,10 +7,9 @@ netifaces>=0.10,<0.11 # https://bitbucket.org/al45tair/netifaces/src/ pycryptodomex>=3.6,<3.7 # https://github.com/Legrandin/pycryptodome/blob/master/Changelog.rst psutil>=5.5,<5.6 # https://github.com/giampaolo/psutil/blob/master/HISTORY.rst requests>=2.22,<2.23 # https://pypi.python.org/pypi/requests -# Slightly higher version for Python 3.8 support -gevent>=1.5,<1.6 # http://www.gevent.org/changelog.html -# Limit greenlet version for binary compatibility with gevent 1.5 wheels -greenlet<0.4.17 +gevent==20.12.0 # http://www.gevent.org/changelog.html +# Limit greenlet version for binary compatibility with gevent 20.12 wheels +greenlet==1.0.0 werkzeug>=0.16,<0.17 # https://github.com/pallets/werkzeug/blob/master/CHANGES patool>=1.12,<1.13 # https://github.com/wummel/patool/blob/master/doc/changelog.txt bcrypt>=3.1,<3.2 # https://github.com/pyca/bcrypt/ From b77c87b4d60fbe7df60dc5e03d2be632a25992fe Mon Sep 17 00:00:00 2001 From: Benjamin Swart <32597377+SvizelPritula@users.noreply.github.com> Date: Sun, 11 Feb 2024 19:50:01 +0100 Subject: [PATCH 19/19] Make oom-heap.c test work with newer GCC (#1210) New GCC versions can optimize the old version of the test to use practically zero memory --- cmstestsuite/code/oom-heap.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cmstestsuite/code/oom-heap.c b/cmstestsuite/code/oom-heap.c index fd3cbb2fa5..3300d17175 100644 --- a/cmstestsuite/code/oom-heap.c +++ b/cmstestsuite/code/oom-heap.c @@ -1,7 +1,9 @@ #include +#include + +int *big; int main() { - int *big; int i; big = malloc(128 * 1024 * 1024); // If we don't do this cycle, the compiler is smart enough not to