Уже четвёртый год я являюсь членом жюри и системным администратором регионального этапа школьной олимпиады по информатике. В мои задачи входит подготовка всей информационной системы для автоматизированной проверки решений. Это настройка необходимого количества рабочих станций (по числу участников + резерв), а также установка и настройка сервера. Сервер необходим для централизованной проверки решений всех участников в ходе олимпиады. Работает это так: участник решает задачи по программированию и тестирует их локально. После того, как он убедится, что программа работает верно, он загружает исходный код решения на сервер с помощью веб-интерфейса. На сервере код автоматически компилируется и прогоняется на большом наборе тестов, неизвестных участникам.
Для серверной части я выбрал систему Contester. Однако он уже давно не обновлялся и поэтому ничего не знает о новых версиях компиляторов. К тому же, каждый год требования меняются. Также отсутствуют какие-либо возможности изменения работы алгоритмов тестирования. В этой статье я решил опубликовать свои конфигурационные файлы, а также поделиться методами итоговой проверки. Вся информация представленная в статье является открытой.
Итак, для начала ставим на сервер Contester и все необходимые компиляторы. В моём случае список был такой:
- Borland Delphi 7;
- Microsoft Visual Studio 2013 Express;
- JDK 1.8.0.71;
- Python 2.7.9;
- Python 3.5.1;
- Free Pascal 2.6.4;
- CodeBlocks (он содержит необходимый GNU C++ MinGW).
Запускаем Contester и видим, что автоматически подхватился только Delphi. Ещё в списке присутствовал .NET 2.0 и 3.5 для C#, но по-положению у нас должна быть более поздняя версия, поэтому его уберём. Кстати, ещё проблема была при попытке заставить всё это работать на 64-битной винде (C# и Java нормально не подключались). На 32-битной всё завелось без проблем.
Теперь надо рассказать контестеру о всех наших компиляторах. Для этого редактируем файл contestercfg.xml (C:Program FilesContestercontestercfg.xml). Там мы указываем строки компиляции и запуска решений:
<?xml version="1.0" encoding="windows-1251"?> <ContesterConfiguration> <!-- Файл конфигурации. См. страницу "Помощь" --> <!-- Linux: Learn it from /opt/firebird/SYSDBA.password --> <DatabasePassword>masterkey</DatabasePassword> <Compiler syntax="csnet" state="set"> <CompilerName>Microsoft Visual C# 2013 Express</CompilerName> <SourceFile>solver.cs</SourceFile> <CompileLine1>csc.exe /o+ /d:ONLINE_JUDGE solver.cs</CompileLine1> <TargetFile1>solver.exe</TargetFile1> <ExecuteLine>solver.exe</ExecuteLine> <AddPathVariable>C:WindowsMicrosoft.NETFrameworkv4.0.30319</AddPathVariable> </Compiler> <Compiler syntax="java" state="set"> <CompilerName>Java Development Kit 1.8.0.71</CompilerName> <SourceFile>solver.java</SourceFile> <CompileLine1>javac.exe -g solver.java</CompileLine1> <TargetFile1>solver.class</TargetFile1> <ExecuteLine>java.exe -Xss32m solver</ExecuteLine> <AddPathVariable>C:Program FilesJavajdk1.8.0_71bin</AddPathVariable> </Compiler> <Compiler syntax="python" state="set"> <CompilerName>Python 2.7.9</CompilerName> <SourceFile>solver.py</SourceFile> <ExecuteLine>C:Python27python.exe solver.py</ExecuteLine> <AddPathVariable>C:Python27</AddPathVariable> </Compiler> <Compiler syntax="python" state="set"> <CompilerName>Python 3.5.1</CompilerName> <SourceFile>solver.py</SourceFile> <ExecuteLine>C:UsersusernameAppDataLocalProgramsPythonPython35-32python.exe solver.py</ExecuteLine> <AddPathVariable>C:UsersusernameAppDataLocalProgramsPythonPython35-32</AddPathVariable> </Compiler> <Compiler syntax="vbnet" state="set"> <CompilerName>Microsoft Visual Basic 2013 Express</CompilerName> <SourceFile>solver.vb</SourceFile> <CompileLine1>vbc.exe solver.vb</CompileLine1> <TargetFile1>solver.exe</TargetFile1> <ExecuteLine>solver.exe</ExecuteLine> <AddPathVariable>C:WindowsMicrosoft.NETFrameworkv4.0.30319</AddPathVariable> </Compiler> <Compiler syntax="pas" state="set"> <CompilerName>Free Pascal 2.6.4</CompilerName> <SourceFile>solver.pas</SourceFile> <CompileLine1>fpc.exe -Mtp -dONLINE_JUDGE -osolver.exe solver.pas</CompileLine1> <TargetFile1>solver.exe</TargetFile1> <ExecuteLine>solver.exe</ExecuteLine> <AddPathVariable>C:FPC2.6.4bini386-win32</AddPathVariable> </Compiler> <Compiler syntax="cpp" state="set"> <CompilerName>Microsoft Visual C++ 2013 Express</CompilerName> <SourceFile>solver.cpp</SourceFile> <CompileLine1>C:Program FilesMicrosoft Visual Studio 12.0VCvcvarsall.bat && cl.exe solver.cpp /EHsc /O2 /D "ONLINE_JUDGE" /I"C:Program FilesMicrosoft Visual Studio 12.0VCinclude"</CompileLine1> <TargetFile1>solver.exe</TargetFile1> <ExecuteLine>solver.exe</ExecuteLine> <AddPathVariable>C:Program FilesContesterutils</AddPathVariable> </Compiler> <Compiler syntax="cpp" state="set"> <CompilerName>GNU C++ MinGW</CompilerName> <SourceFile>solver.cpp</SourceFile> <CompileLine1>"C:Program FilesCodeBlocksMinGWmingwvars.bat" && mingw32-g++ solver.cpp -o solver.exe -DONLINE_JUDGE -std=c++11 -O2 -I "C:Program FilesCodeBlocksMinGWlibgccmingw324.7.1includec++"</CompileLine1> <TargetFile1>solver.exe</TargetFile1> <ExecuteLine>solver.exe</ExecuteLine> <AddPathVariable>C:Program FilesCodeBlocksMinGWbin</AddPathVariable> </Compiler> <Compiler syntax="csnet" state="deny"> <CompilerName>Microsoft .NET 3.5 Framework</CompilerName> </Compiler> <Compiler syntax="csnet" state="deny"> <CompilerName>Microsoft .NET 2.0 Framework</CompilerName> </Compiler> <Compiler syntax="vbnet" state="deny"> <CompilerName>Microsoft .NET 3.5 Framework</CompilerName> </Compiler> <Compiler syntax="vbnet" state="deny"> <CompilerName>Microsoft .NET 2.0 Framework</CompilerName> </Compiler> <Compiler syntax="cpp" state="deny"> <CompilerName>Microsoft Visual C++ 2005 Express</CompilerName> </Compiler> </ContesterConfiguration>
Обязательно сверьте пути к компиляторам со своими. Последние строки с параметром state=»deny» необходимы для отключения автоматически определённых компиляторов, но которые нам не нужны.
Теперь перезапускаем контестер, убеждаемся, что перечислены все компиляторы и проверяем работу их всех на какой-нибудь простой задаче. Например, «A+B». Если всё хорошо, то можно загружать задачи.
Здесь возникает вторая проблема: по-умолчанию поддерживаются только чекеры (тестирующие программы) на паскале. А в последнее время их всё больше стало на C++. Можно конечно попробовать переписать чекер на паскаль, а можно поискать библиотеку testlib.h. Последняя версия такой библиотеки находится здесь. Но она не подходит к самому контестеру. В Интернете я потом нашёл исправленную старую версию testlib для контестера (ссылку потерял), добавил в неё несколько функций из последней официальной версии. [drain file 107 url Скачать testlib.h] ([drain file 107 size]). Библиотеку надо поместить в папку utils контестера.
Так, теперь по изменениям в чекерах. В первую очередь меняем название библиотеки и путь до неё. Если чекер на паскале, то меняем «testlib» на
unJudge17 in '..utilsunJudge17.pas'
Было:
program checker1; uses testlib, sysutils; ...
Стало:
program checker1; uses unJudge17 in '..utilsunJudge17.pas', sysutils; ...
Если чекер на C++, то меняем так:
#include "testlib.h" using namespace std; int main(int argc, char * argv[]) { ...
на
#include "..utilstestlib.h" using namespace std; int main(int argc, char * argv[]) { ...
Теперь, если чекер на паскале, то необходимо внести ещё некоторые изменения. Список доступных функций можно посмотреть в файле utilsunJudge17.pas.
Чтение слова:
ja := ans.readword(blanks, blanks);
pa := ouf.readword(blanks, blanks);
меняем на
ja := ans.readstring;
pa := ouf.readstring;
Чтение действительного числа:
ja := ans.readreal;
pa := ouf.readreal;
меняем на
ja := ans.readfloat;
pa := ouf.readfloat;
и т.д.
Итогом должны получиться принятые (Approved!) чекеры для каждой задачи:
Теперь пробуем запускать «эталонные» решения жюри. При этом учитываем особенность контестера: Входные данные допускается читать как с консоли, так и из файла input.txt, выходные данные необходимо выводить в консоль. То есть, если решение выглядело так:
#include <cstdio> #include <iostream> #include <vector> using namespace std; int main() { freopen("zadacha.in", "rt", stdin); freopen("zadacha.out", "wt", stdout); ...
то его надо исправить примерно так:
#include <cstdio> #include <iostream> #include <vector> using namespace std; int main() { freopen("input.txt", "rt", stdin); //freopen("zadacha.out", "wt", stdout); ...
На всякий случай можно проверить решения жюри на разных языках (в этом году были C++, GNU C++, Python), естественно учитывая особенности ввода/вывода.
В результате, если всё хорошо, получаем вот такую картину:
Все задачи готовы и для каждой было проверено решение жюри (зелёные галочки). Так как олимпиада проходит в два этапа (два дня), то во избежании утечки, из второго тура названия задач пока убираем, оставим только цифры.
Устанавливаем для каждого тура время начала и окончания:
Теперь перенастраиваем сеть. На сервере (DHCP + DNS + ActiveDirectory) создаём отдельную подсеть, переносим в неё все компьютеры участвующие в олимпиаде, блокируем им Интернет. Создаём в домене отдельного пользователя («Олимпиада», «Olimp» и т.п.) с урезанными правами. Ещё раз проверяем работу всей системы, пробуем зайти с компьютеров на сервер контестера и идём отдыхать 🙂
Продолжение следует…
Сообщение | Кратко | Сообщается ли номер теста? | Значение вердикта | Возможная причина |
---|---|---|---|---|
OK | OK | Нет | Решение зачтено | Программа верно работает на соответствующем наборе тестов |
Compilation error | CE | Нет | Компиляция программы завершилась с ошибкой | 1. в программе допущена синтаксическая или семантическая ошибка 2. неправильно указан язык |
Wrong answer | WA | Да | Ответ неверен | 1. ошибка в программе 2. неверный алгоритм |
Presentation error | PE | Да | Тестирующая система не может проверить выходные данные, так как их формат не соответствует описанному в условиях задачи | 1. неверный формат вывода 2. программа не печатает результат 3. лишний вывод |
Time-limit exceeded | TL | Да | Программа превысила установленный лимит времени | 1. ошибка в программе 2. неэффективное решение |
Memory limit exceeded | ML | Да | Программа превысила установленный в условиях лимит памяти | 1. ошибка в программе (например, бесконечная рекурсия) 2. неэффективное решение |
Output limit exceeded | OL | Да | Программа превысила установленный в условиях лимит вывода | 1. программа выводит больше информации, чем установлено в ограничениях |
Run-time error | RE | Да | Программа завершила работу с ненулевым кодом возврата | 1. ошибка выполнения 2. программа на C или C++ не завершается оператором return 0 3. ненулевой код возврата указан явно 4. Программа на Java описана в пакете |
Precompile check failed | PCF | Нет | Программа не прошла проверку на качество кода перед компиляцией | 1. плохое качество кода 2. неправильно отформатированный код |
Idleness limit exceeded | IL | Да | Программа слишком долго не отвечала на запросы системы и не выполняла действий | 1. программа ожидает ввода с консоли, которого не должно быть 2. не использован flush() |
Разработчики и люди, профессионально работающие с веб-приложениями, боятся 500 Internal Server Error. Оптимальный способ её устранения зависит от сервера и того, что на нём запущено. В данной статье приводятся советы по диагностике и исправлению ошибки 500.
- Ошибка 500 Internal Server Error — диагностика
- Ошибка 500 Internal Server Error — устранение на популярных платформах
- Ошибка 500 Internal Server Error — устранение на стороне серверных скриптов
- Попросите помощи у системного администратора
- Ошибку 500 Internal Server Error довольно легко устранить
Важно помнить, что эта ошибка происходит на стороне сервера. Это значит, что HTML-код, выполняемый на стороне клиента, а также JavaScript или любые другие запущенные в браузере объекты, не могут быть причиной, по которой возникает ошибка 500 Internal Server Error. Само название (Internal Server Error – ‘внутренняя ошибка сервера’) говорит о том, что ошибка происходит на сервере.
Многие пользователи устанавливают на свой сервер популярные CMS-системы, такие как WordPress, Joomla, Drupal и они не должны вызывать ошибку 500, если всё настроено правильно. Однако она всё равно всплывает – из-за несовместимости версий, некачественных установок или сбоя прав доступа на сервере.
Вот некоторые распространённые проблемы, которые могут вызывать подобную ошибку в часто используемых CMS:
- Если вы только что обновили движок до новой версии, вероятно, обновление прошло с ошибками и необходимо провести его повторно. Скорее всего, на сайте разработчика есть инструкции, как это правильно сделать.
- Если вы только что активировали новый плагин или новую тему, стоит попробовать отменить эти изменения. Даже профессионально написанные плагины могут конфликтовать с другими и вызывать 500 Internal Server Error nginx
- Если вы обновляли CMS, старые плагины и темы могут быть с ней несовместимы. Единственное, что можно сделать в таком случае — отключать их по очереди, пока ошибка 500 не исчезнет.
- Неправильно заданные права доступа на сервере или ошибки в файле .htaccess. Серверу не удаётся получить доступ к скриптам, файлам и другим ресурсам, поэтому он выдаёт ошибку.
Когда причиной, по которой возникает ошибка 500 Internal Server Error являются скрипты и плагины, лучше всего искать ответы на сайтах их разработчиков.
Другой причиной по которой может возникнуть ошибка 500 Internal Server Error может стать разработка и тестирование собственных скриптов.
Чтобы справиться с такой ошибкой, попробуйте следующие решения:
- Настройка прав на сервере: часто неверная настройка прав доступа к файлу или папке приводит к тому, что сервером выдаётся ошибка 500 Internal Server Error. Из-за того, что ему не удаётся запустить скрипт. Выясните, какие права должны быть настроены, и выставьте их соответствующим образом.
- Превышено время ожидания: возможно, истекло время ожидания ответа от PHP или другого серверного скрипта. Это происходит из-за того, что недоступен определённый ресурс или коде была допущена ошибка, запускающая бесконечный цикл.
- Превышено время ожидания соединения с сервером: если сервер был занят, перезагружался или потерял соединение, скрипт может выдать ошибку 500 Internal Server Error. Возможно, в следующий раз ошибки не будет. Но если ошибка появляется при тестировании, велика вероятность того, что она встретится и пользователям.
- Ошибки в файле .htaccess: в некоторых случаях ошибку 500 может вызывать код, прописанный в файле .htaccess.
- Ошибки в скрипте: если ошибку выдаёт скрипт, можете запросить у него подробную информацию об ошибке. К примеру, в PHP можно включить вывод ошибок на экран или в лог-файл, добавив директиву display_errors. По умолчанию среда выполнения может скрывать ошибки, но это не очень удобно для отладки программы.
В некоторых случаях у разработчиков нет полного контроля над сервером.
Если скрипт запускается на сервере сторонней организации, она может помочь вам в следующем:
- Предоставить документацию о своём сервере и возможных причинах ошибки 500. В зависимости от используемой операционной системы и настройки оборудования, данная ошибка может возникать по разным причинам.
- Попросите службу поддержки хостинга посмотреть лог-файлы с ошибками — системный администратор сможет определить, был ли сервер во время возникновения ошибки загружен или вовсе «упал».
Ошибка 500 Internal Server Error — как исправить? В большинстве случаев причины возникновения ошибки 500 легко исправляются. Проблема заключается в том, что без конкретной информации определение причины возникновения сбоя усложняется. Легче всего справиться с ошибкой, когда разработчик выяснит, что изменилось перед возникновением ошибки.
Не забывайте, что произошедшие изменения могли быть осуществлены и другими людьми — например, администратором сервера. Если же ничего не менялось, вероятно, сам сервер стал причиной возникновения ошибки из-за несовместимости программного обеспечения или проблем с производительностью.