Пояснительная записка (1231610), страница 5
Текст из файла (страница 5)
3.2.3 Реализация загрузки истории посылок
Как описано ранее, реализовано два варианта загрузки истории посылок:
– с компьютера пользователя;
– с сервера.
Для загрузки истории посылок с компьютера используется стандартный элемент оформления web-страниц – элемент input с типом file. После выбора файла (рисунок 3.2), он обрабатывается через JavaScript (листинг 3.4).
Рисунок 3.2 – Выбор истории посылок для загрузки
Листинг 3.4 – Обработка загружаемого файла
function loadLogFromUser() {
if( loadLog( function( log ) {
isLoadLog = false;
loadLogFromFile( log, teams, problems, submits );
createTable();
goStart();
} ) ) {
deleteTable();
}
}
function loadLog( onSuccess ) {
var files = document.getElementById( "fileLog" ).files;
if( !files.length ) {
return false;
}
var reader = new FileReader();
reader.onloadend = function( event ) {
onSuccess( event.target.result );
};
reader.onerror = function( event ) {
alert( "Файл не может быть прочитан! Код ошибки: " + event.target.error.code );
};
isLoadLog = true;
reader.readAsText( files[0] );
return true;
}
Функция loadLogFromUser() вызывается при загрузке истории посылок с компьютера. Данная функция с функцией onSuccess() в качестве аргумента, вызывает функцию loadLog(), которая в свою очередь, пытается считать файл с историей посылок. В случае успеха, функция loadLog() вызывает переданную функцию onSuccess(), которая отвечает за получение необходимых данных из истории посылок.
Выбор истории посылок для загрузки с сервера осуществляется через выпадающий список (рисунок 3.3).
Рисунок 3.3 – Выбор истории посылок для загрузки с сервера
Загрузка истории посылок с сервера реализована с помощью технологии AJAX, которая позволяет функциям JavaScript вызывать PHP-сценарии на стороне сервера и обрабатывать данные, полученные в ответ (листинг 3.5).
Листинг 3.5 – Загрузка истории посылок с сервера
function loadLogFromServer() {
deleteTable();
isLoadLog = true;
var file = document.getElementById( "fileLogFromServer" ).value;
$.get( "php/loadLog.php", {"file": file}, function(data) {
isLoadLog = false;
loadLogFromFile( data, teams, problems, submits );
createTable();
goStart();
} );
}
Функция loadLogFromServer() вызывает функцию get() и передаёт в неё функцию onSuccess(), которая рассматривалась ранее. Функция get() делает запрос на сервер с вызовом PHP-сценария loadLog.php (листинг 3.6).
Листинг 3.6 – Файл loadLog.php
<?php
$file = $_GET["file"];
echo file_get_contents( "C:/openServer/domains/table/log/".$file );
?>
PHP-сценарий loadLog.php считывает историю посылок из определённого файла, хранимого на сервере, и возвращает её в функцию onSuccess() для дальнейшей обработки.
Алгоритм обработки истории посылок будет рассмотрен в последующих подразделах.
3.2.4 Формат историй посылок
Истории посылок соревнований могут быть записаны в обычный текстовый файл. Но чаще всего для этого используются файлы формата XML (англ. eXtensible Markup Language – расширяемый язык разметки).
Как описано ранее, в системе Ejudge имеется возможность экспорта истории посылок в формате PCMS2. Именно такой формат реализован в модуле подведения итогов. Помимо этого, так же реализован и формат CATS+.
Формат CATS+
Формат CATS+ является расширенным по отношению к формату CATS. Формат CATS используется Дальневосточным Федеральным Университетом в местных соревнованиях по программированию.
Основным отличием формата CATS+ от CATS является наличие двух дополнительных блоков: с информацией по участникам соревнования и с информацией по задачам.
Истории посылок формата CATS+ представляют собой древообразную модель из тэгов (листинги 3.7-3.9), внутри которых заключена информация о соревновании.
Листинг 3.7 – Блок teams
<teams>
<team>
<id> Идентификатор команды </id>
<name> Название команды </name>
</team>
...
</teams>
Информация о каждой команде помещается в блок team. В качестве идентификатора команды должно выступать число. Название команды может быть любой строкой символов.
Листинг 3.8 – Блок problems
<problems>
<problem>
<code> Сокращенное обозначение задачи </code>
</problem>
</problems>
Информация о каждой задаче помещается в блок problem. В качестве сокращенного обозначения задачи может выступать как число, так и буква, или даже строка символов. Разумеется, лучше всего, если обозначение будет состоять из одного символа, чтобы в таблице c результатами оно не занимало много места, и не привело к увеличению ширины столбцов.
Листинг 3.9 – Блок reqs
<reqs>
<req>
<time_since_start> Время посылки </time_since_start>
<team_id> Идентификатор команды </team_id>
<code> Сокращенное обозначение задачи </code>
<state> Статус посылки </state>
</req>
...
</reqs>
Информация о каждой посылке помещается в блок req. Время посылки – время от начала соревнования в сутках. Идентификатор команды должен быть таким же, как в блоке teams. Сокращенное обозначение задачи должно быть таким же, как в блоке problems. Статус посылки может иметь различные значения, но за удачную посылку будет приниматься лишь статус «accepted».
Посылки из блока reqs с командами или задачами, которые отсутствуют в блоках teams и problems соответственно, игнорируются.
Стоит отметить, что в формате CATS+ в блоке reqs могут присутствовать и иные параметры, которые в текущей реализации модуля подведения итогов не используются.
Формат PCMS2
Формат PCMS2 используется в некоторых соревнования по программированию, проводимых на территории Российской федерации. Примером такого соревнования является NEERC ACM ICPC.
Формат PCMS2, так же как и формат CATS+, имеет древообразную модель из тэгов, но информация записывается не внутри тэгов, а в качестве параметров тэга.
Основным блоком является блок standings, внутри которого расположен блок contest (листинг 3.10).
Листинг 3.10 – Блоки standings и contest
<standings>
<contest name = "Название соревнования">
...
</contest>
</standings>
Внутри блока contest располагается один блок challenge (листинг 3.11) и несколько блоков session (листинг 3.12).
Листинг 3.11 – Блок challenge
<challenge>
<problem alias = "Сокращённое обозначение задачи" />
...
</challenge>
Блок challenge содержит в себе информацию о задачах соревнования. Информация о каждой задаче помещается в блок problem. Сокращенное обозначение задачи будет отображаться в таблице с результатами.
Листинг 3.12 – Блок session
<session party = "Название команды">
<problem>
...
</problem>
...
</session>
Блок session содержит в себе информацию только о посылках конкретного участника, причем все посылки распределены по задачам и заключены в блоки problem (листинг 3.13).
Листинг 3.13 – Блок problem
<problem alias = "Сокращенное обозначение задачи">
<run accepted = "Статус посылки" time = "Время" />
...
</problem>
Блок problem содержит в себе информацию о посылках по конкретной задаче. Сокращенное обозначение задачи должно быть таким же, как и в блоке challenge.
Информация о посылке заключена в блок run и имеет два параметра: статус посылки и время. Статус посылки может иметь два значения: «yes» или «no», первый из которых обозначает, что задача решена. Время – время в миллисекундах от начала соревнования до момента прихода посылки.
Стоит отметить, что в формате PCMS2 могут присутствовать и иные параметры, которые в текущей реализации модуля подведения итогов не используются.
3.2.5 Обработка историй посылок
Как описано ранее, истории посылок хранятся в файлах формата XML. Существует множество автоматизированных способов обработки файлов данного формата. Но для модуля подведения итогов написан свой собственный обработчик.
Для обработки файлов формата XML написан класс StringWithIndex (приложение А, листинг А.4), который имеет два поля – text и index. В поле text помещается содержимое файла XML, а в поле index – текущее положение курсора. Рассмотрим основные методы данного класса:
– методы getNextTagValue() и getTagValue() принимают в качестве аргумента наименование тэга, выполняют поиск этого тэга в поле text правее положения курсора index и возвращают содержимое этого тэга. Разница между методами заключается в том, что первый перемещает положение курсора index в конец найденного тэга;
– методы getNextTagText() и getTagText() принимают в качестве аргумента наименование тэга, а после вызывают методы getNextTagValue() и getTagValue() соответственно. Разница от работы последних заключается в том, что методы getNextTagText() и getTagText() возвращают не сам текст, а объект класса StringWithIndex;
– метод nextTagText() возвращает содержимое ближайшего к курсору тэга в виде объекта класса StringWithIndex, курсор при этом перемещается в конец найденного тэга;
– метод getTagName() возвращает наименование тэга, но поиск выполняется с начала поля text, курсор при этом не перемещается;
– метод getParamsValue() принимает в качестве аргумента наименование параметра, поиск которого выполняется внутри поля text. Если поиск успешен, то метод возвращает значение этого параметра.
Так как модуль подведения итогов поддерживает обработку историй посылок двух разных форматов CATS+ и PCMS2, реализовано два набора функций для работы с каждым из форматов (приложение А, листинги А.5-А.6).
Функции для обработки имеют одинаковые названия – loadLogFromFile(), которые в качестве аргументов принимают на вход содержимое файла XML, а также три массива teams, problems и submits.
Переключение между функциями для обработки для разных форматов осуществляется через меню с настройками (рисунок 3.1). Если произведено изменение формата с сервера загружается файл .js с необходимыми для обработки функциями (листинг 3.14).
Листинг 3.14 – Загрузка файла .js с функциями для обработки
function setScriptLoad( scriptName ) {
var div = document.getElementById( "scriptLoad" );
div.removeChild( div.firstChild );
var script = document.createElement( "script" );
script.setAttribute( "type", "text/javascript" );
script.setAttribute( "src", scriptName );
div.appendChild( script );
}
Функция loadLogFromFile() вызывает три другие функции – getTeamsFromFile(), getProblemsFromFile(), getSubmitsFromFile(), которые, в свою очередь, осуществляют обработку истории посылок и помещают необходимую информацию о командах, задачах и посылках в массивы teams, problems и submits соответственно. Структура данных массивов будет рассмотрена в следующем подразделе.
3.2.6 Хранение информации о командах, задачах и посылках
Как описано ранее, для хранения информации о командах, задачах и посылках в модуле подведения итогов используется три массива teams, problems и submits. Для каждого из массивов написан свой класс с необходимыми полями и методами. Стоит заранее отметить, что примеры использования методов связанных с информацией, отображаемой в таблице с результатами, будут приведены в следующих подразделах.
Класс Team
Класс Team (приложение А, листинг А.7) используется для хранения информации о командах и имеет следующие поля:
– поле id – идентификатор команды;
– поле name – название команды;
– массивы problemAllSubmit и problemSubmit – общее количество посылок и количество обработанных посылок по каждой из задач соответственно;
– массивы problemSolved и problemTime – для хранения информации о том, решена ли конкретная задача и, если решена, то за какое время;
– двумерный массив problemSubmits – для хранения списка идентификаторов посылок, совершенных командой, по каждой из задач;
– поле solved – количество решенных задач;
– поле time – суммарное время, истраченное на решение задач;