суббота, 19 апреля 2014 г.

Извлечение ответов на вопросы через MoodleXML

У Moodle есть довольно хороший механизм экспорта - MoodleXML, который позволяет экспортировать вопросы в одноименном формате. В нем хранятся текст вопроса, список ответов, их атрибуты - словом все, что необходимо при восстановлении вопроса.

Возникла задача - извлечь ответы на вопросы из данного формата. Вообще, на первый взгляд, для этого - достаточно регекса, который бы доставал текст из тегов вида "<text></text>". Беда в том, что такие теги не всегда относятся, к ответам на вопросы, а могут участвовать - например в тексте, который показывается в случае совпадения ответа студента с заданным.

Для решения такой задачи можно использовать XQuery и конкретно, такую вещь как MXQuery. Хоть она далека от идеальной, но выдернуть данные на ней - одна строка:



java -jar mxquery-15.jar -s omit-xml-declaration=true -i "for $act in doc(\"questions.xml\")/quiz/question/answer/text return $act" -o 1.txt


К большому сожалению - это не все. Дело в том, что данные вернутся с тегами и текст вопросов будет проэскапирован для работы с XML. При попытке, сделать все через MXQuery возникли определенные проблемы - он падал с ошибкой, альтернативный GNU Kawa работал еще хуже, ломаясь посередине. Для финального получения данных имеет смысл использовать скрипт на PHP, к примеру:

$data = file_get_contents("php://stdin");
$matches = array();
$result = preg_match_all("/<text>([^<]+)<\/text>/", $data, $matches); 
$a = function($o) { return html_entity_decode($o); }; 
$matches = array_map($a, $matches[1]); 
echo implode("\n", $matches); 

воскресенье, 23 февраля 2014 г.

Ruby 2.0 + DevIL + Windows

Есть такая библиотека для работы с изображениями - DevIL. Библиотека довольно старая, собрать её из исходников под виндой практически невозможно, но зато поддерживает кучу форматов и вообще замечательная.
У этой библиотеки есть биндинги для Ruby, чем я и воспользовался, написав небольшой генератор текстурных атласов.

Недавно заметил, что на новый Ruby он перестал ставиться, ввиду того, что во-первых либа под новую Ruby не собрана, а во-вторых -  из-за чуши в extconf.rb её вероятность собраться под Windows была крайне мала. На моё  issue было отвечено гробовой тишиной, так как автор походу перестал поддерживать его году в 2010.

Засучив рукава, форкнул репозиторий и принялся исправлять. Скажу сразу - в итоге справился.
Гем заработал и я его даже у себя протестировал.

Вкратце расскажу, что поразило. В первую очередь,  структура Rakefile сильно поменялась года за четыре, да и косяк в extconf.rb оказалось не так легко исправить. Хотя бы из-за проблемы разделителей путей, которые упорно в одних случаях нормально работают в GCC, хотя заданы слешами, а в других - нет и приходится перекраивать путь "вручную".

Вторая проблема - принудительная линковка, либо с либой от другого компилятора, либо с DLL. Это довольно глупый и костыльный хак, который поддерживается GCC и который частенько приходится использовать. Из-за обработки параметров в Makefile пришлось подхачить, но взлетело.

Самое главное - вот это вот . Потому что это может быть малопонятная ошибка в рантайме, которую руби показывает, как исключение, и она в командной строке непонятна совсем.  Убило три часа моей жизни и доставило много недовольства. Хинт: в таких случаях имеет смысл использовать Dependency Walker - он может показать, что случилось, почему не подгрузилось и избавить от гадания на ключах компилятора.

воскресенье, 2 февраля 2014 г.

Bicycle Way

Есть у меня небольшое хобби. Периодически от скуки, я хожу по всяким опенсурсным хостингам кода и разглядываю что там нового появилось.  Естественно, натыкаюсь на множество интересных вещиц, в том числе велосипедов.

К велосипедам сейчас у многих отношение неоднозначное. С одной стороны - они вредны, ибо отнимают время, которое можно было потратить на написание хороших интересных прикладных продуктов, изучить хаскеллекложурь или  еще чего-то. С другой стороны - на велосипедах можно многому научиться, осознать что не все так просто, увидеть как некоторые вещи работают плохо, а также узнать, почему существующие решения устроены так или иначе.

От этого захотелость составить список велосипедов, которые можно (должно) написать для саморазвития и которые часто встречаются. Список не претендует на полноту, ибо писался по ощущениям, а не по статистике. В первую очередь буду говорить о C++, как наиболее близком мне, и репозитории на котором чаще всего смотрю:

Рубрика "Основы"

  • Умные указатели (с подсчетом ссылок, своя реализация auto_ptr, unique_ptr, genius_ptr)
  • Библиотека шаблонных контейнеров (list, queue, vector)
  • Свой кроссплатформенный враппер сокетов
  • Свой протокол сериализации.
  • Своя система сборки проектов.
Рубрика "ЯП"

  • Интерпретатор языка программирования (компилятор тоже пойдет)
  • Виртуальная машина для этого же языка
Рубрика "Геймдев"

  • Игровой движок, куда ж без него.
  • Рандомная хелло-ворлд игра (Змейка-Тетрис-Пятнашки-whatever)
Рубрика "Сети"
В связи с зоопарком протоколов верхнего уровня тут много чего можно.

  • HTTP-сервер
  • FTP-сервер
  • POP3-сервер
  • CMS
  • ХХХ-хостинг, где под XXX - картинки, файлы и еще много всего интересного.
Замечу, что не хочу  никого обидеть этим списком, к тому же сам в написании подобных велосипедов был неоднократно уличен.

воскресенье, 26 января 2014 г.

ШИНAПN и бездны legacy

Есть у меня небольшой проект, по историческим причинам не использующий ни Qt, ни GTK, ни чего-либо другого. Только WinAPI или общение с WM через X11 под линем. И,  хотя X11 не лишен недостатков,  не буду оригинальным - WinAPI хуже его раз в стопятьсот.

Это не относится к новомодному интерфейсу  Metro и его API - честно говоря, не трогал и не имею желания. Просто потому что тайловые WM давно уже изобрели, и я нахожу подобные закосы либо шагом назад, либо желанием выпендриться шагом назад.

Сейчас Windows и WinAPI не ругал только ленивый, см.  [1] [2] [3]  и в этом я особо не оригинален. По последней ссылке, кстати есть некоторый список конкретных недостатков. Однако, мне довелось встретиться с несколько другими, значительно более раздражающими, и этот пост будет посвящен им. Замечу, что все они решаемые, но красоте коду они не прибавляют.

В первую очередь, SetWindowLong  с GWL_STYLE - это просто хаос и угар. Некоторые комбинации его флагов могут реально поломать окно ко всем чертям, в зависимости от версии Windows. К примеру, есть популярный хак вида

SetWindowLong(handle, GWL_STYLE,  oldstyle & ~WS_THICKFRAME);

Он запрещает пользователю изменять  размеры окна (почему вообще нет функции для этого?). В Windows 8 он ломает работу glViewport из-за того, что клиентская область начинает вычисляться неверно. И да, рамку она не убирает. Но более того - некоторые безобидные комбинации флагов стилей в вызове этой функции приводят к тому, что окно просто превращается в КРОВЬ КИШКИ МЯСО.

Ещё в недрах WinAPI есть замечательное событие WM_MOUSELEAVE . Ну, думается, если есть WM_MOUSEMOVE, который работает всегда и ловит перемещение мыши - оный должен работать также. Ничего подобного, если не вызвать TrackMouseEvent - сообщений не будет. Конечно, в X11 флаги перемещения мыши, входа и выхода из клиентской области задаются отдельно. НО! Ни один из них не включен по умолчанию.

Определённое неудобство может доставить  функция PeekMessage . Обратите внимание на второй аргумент её. В него должен передаваться дескриптор окна, для которого получается сообщение. Так вот, в него всегда надо передавать NULL. Иначе у вас не будет работать смена раскладки окна. Проверял на Windows XP, 7, 8 - нигде это не работает. Вообще, если сообщение всегда получается для окна текущего потока, имеет смысл задать себе - как часто у вас несколько окон обрабатывается в одном потоке?
UPD:  Оказывается в этом есть логика, см. статью.  И она тесно связана со следующим фактом, а именно...

CreateWindow, который создает не только окна, но и двери, шпаклевки, кирпичи, натяжные потолки - это классика нарушения принципа единственной обязанности и кроме как легаси не объясним.

Подводя итог, хочу сказать - используйте Qt, GTK, JUCE,  whatever. А WinAPI - нет.

четверг, 3 октября 2013 г.

Octave + Fuzzy Logic Toolkit

По этой связке хорошо помогают работать следующие ссылки:
http://octave.sourceforge.net/fuzzy-logic-toolkit/overview.html
http://radio.feld.cvut.cz/matlab/toolbox/fuzzy/fuzzyt23.html

Во второй ссылке описывается формат системы нечеткого вывода в Matlab,  который состоит из входов, выходов и правил соответствия, которым соответствуют веса. Треугольной функции принадлежности соответствует функция trimf, после которой должен идти список (в квадратных скобках из трех элементов).

Не совсем понятен, параметр connection - но значение 1 туда подходит.

Еще возможной проблемой является то, что нельзя в названии значений входов и выходов использовать пробелы. Octave тогда ломается и выдает стектрейс.

Для разработки имеет смысл использовать плагин для NetBeans - OctaveNB, который предоставляет чуть ли не REPL для Octave.

Сам скрипт будет состоять из трех команд:

% Читаем систему из файла в переменную fis
fis = readfis("system.fis"); 
% Проводим вывод на системе
results = evalfis([[0.5], [-0.5]], fis);
% Показываем результаты
disp(results);

Где [[0.5], [-0.5]] - матрица, в которой каждая строка - массив значений для входа N. На выходе, соответственно - матрица значений для выходов.

Довольно легко и просто!

четверг, 26 сентября 2013 г.

"Хранить" или "Являться"? О непонимании.

Сегодня столкнулся с довольно интересной ситуацией, , из которой вырос этот философский пост.

Для начала мне задали вопрос, по поводу одного тестового вопроса, который формировался таким образом - "В каких из заданных типов можно хранить число?". Вопрос этот был в рамках языка C++ и это довольно таки простой вопрос с простой формулировкой. Вариантами ответа были int, char, char[], float и еще пара других типов. Так вот, парень задавший мне вопрос выбрал, среди прочих, вариант char[]  и аргументировал это тем, что в принципе в массиве можно хранить число.

Дело в том, что тест больше касался синтаксиса языка, и под "хранить" подразумевалась возможность написать нечто вида "X a = 22;", где X  - имя типа (ну в общем случае, конечно). Очевидно, в рамках такого понятия - char[] полностью не подходит.
Однако, это приводит к самому вопросу о том, насколько размыто понятие "хранить" в голове программистов.

К примеру, я с позиций практика, который не так давно занимался оптимизацией недавно скажу что можно сделать memcpy  числа в массив, взяв от числа адрес и сохранить там число. Неважно зачем я делаю это глупое действие  - главное можно.

С более простой позиции обратится к первому элементу. и если число влезает - можно и записать число и хранить его.  А можно так и сохранить в указатель. И при должном извращении то и в указатель на функцию. И вообще как угодно.
Обобщить обе эти позиции довольно легко. Понятие "хранить" в них означает, что для данных двух типов есть прямое сюръективное отображение и обратное отображение (биекция не обязательна).

А вот с синтаксической позицией - все просто. Подразумевается, что данный тип должен описывать число. Указатели с точки зрения семантики не описывают числа, массивы - тоже.

А теперь самое интересное - однозначна ли фраза "должен описывать число"? И да, как можно переформулировать данный вопрос, чтобы его понял студент-младшекурсник? Можно сказать, что он должен описывать "множество чисел" или "подмножество чисел", но насколько это понятие популярно в среде младшекурсников - это остается для меня вопросом.

среда, 18 сентября 2013 г.

Ускоряем Moodle при помощи APC + Memcached

Не так давно (если не ошибаюсь, с версии 2.4-2.5) версия Moodle стала страшно тормозить в дефолтной поставке PHP. Нет не страшно тормозить, а  тратить 30 СЕКУНД на генерацию страницы.  Впрочем, это случается с любым неминималистичным веб-фреймворком рано или поздно, а Moodle никогда не был маленьким и легковесным, в силу своей предметной области. А значит - нет смысла ругаться, надо решать проблему :)

Я нашел около двух способов ускорения, однако есть и больше. Навскидку - можно использовать WinCache под Windows и другие (см. stores). Да и Memcached не так уж обязателен Вот здесь по идее можно скачать плагин и настроить для работы Moodle Universal Cache c APC (у меня оно кладется в Memcached).

Иными словами,  здесь описан мой путь, который несколько костыльный, однако - сработал. Результатом его является то, что главная сейчас отдается за 300мс, а  время генерации страницы в худшем случае - 4с. Данная конфигурация работает на двухядерном Intel Atom D2700 и 2Гб RAM под управлением Ubuntu 12.04

Cперва установим APC. Мануал взят по ссылке [1].

sudo apt-get install php-apc
service apache2 restart

У меня юзался php-fpm (в дефолте убунты это так) и его необходимо было перезагрузить:

service php5-fpm restart

Количество памяти можно смело поднимать до 256Мб - это дает позитивный эффект, и память сильно не фрагментируются в итоге. Прикладываю конфиг /etc/php5/conf.d/apc.ini для настройки

extension=apc.so
apc.shm_size=256M
apc.ttl=7200
apc.user_ttl=7200
apc.num_files_hint=1024
apc.enable_cli=1
apc.rfc1867=1


Вторым этапом настраивается Memcached. Мануал опять же взят по ссылке [2], однако есть небольшие отличия, связанные с версией. Ставим необходимые пакеты.

sudo apt-get install memcached php-pear php5-dev 
sudo apt-get install libmemcached-dev
sudo pecl install Memcache
service apache2 restart
service php-fpm restart 


Стоит добавить следующую строку в /etc/php5/apache2/php.ini (хотя по идее инсталлер это сделает сам, у меня почему-то не сделал):

extrension=memcache.so


И в config.php самого Moodle прописываем:

$CFG->cachetype='memcached';
$CFG->rcache = true;
$CFG->memcachedhosts= '127.0.0.1';
$CFG->memcachedpconn=true;


Для полной уверенности можно выполнить:

service memcached restart