среда, 3 декабря 2014 г.

Когда виснет Git под Windows XP

http://billauer.co.il/blog/2012/10/git-pull-windows-freeze-receive-pack/ Я правда просто заменил все вхождения. Работает, проблем не вижу. Что забавнее всего - баг не починен до сих пор.

суббота, 22 ноября 2014 г.

Qt + Ruby, Windows XP

Чтобы Qt в Ruby нормально работало по Windows XP сначала нужно поставить гем qtbindings-qt, а уже потом qtbindings. Иначе придется собирать qtbindings вручную, что, к сожалению, очень часто падает и почти никогда не срабатывает нормально. А еще лучше ставить версию 2.0.0 - она пока на Windows XP работает лучше всего.

понедельник, 30 июня 2014 г.

Qt Palette Color Picker

Нашел хороший пример для приема из предыдущего поста.


вторник, 3 июня 2014 г.

Комплексные виджеты в Qt

В довольно древней книге-туториалу по VB.NET описывалось то, как можно создать свой комплексный виджет, состоящий из нескольких подвиджетов на основе встроенного в систему UserControl.

В туториалах по Qt есть свой туториал по созданию своих сложных виджетов на основе QWidget. Но он довольно сложный, так как рассчитан на интеграцию в Qt Designer. В итоге разработка своего виджета может показаться сложным и неблагодарным занятием. 

Но есть более простой путь. Он заключается в наследовании класса QWidget и переопределении методов void resizeEvent( QResizeEvent * e ), а также void moveEvent( QMoveEvent * e );

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

Мини-пример такого виджета на C++ показан ниже.


#include <QWidget>
#include <QTreeWidget>
#include <QTableWidget>


class MyWidget: public QWidget
{
    Q_OBJECT
public: 
        MyWidget(QWidget * parent = NULL);        
        ~MyWidget();
protected:
        virtual void resizeEvent(QResizeEvent * e);
        virtual void moveEvent(QMoveEvent * e);
        void resizeWidgets(const QRect & r);

        QTreeWidget  * m_tree_view;
        QTableWidget * m_element_view;
};

MyWidget::MyWidget(QWidget * parent) 
: QWidget(parent)
{
        m_tree_view = new QTreeWidget(parent);
        m_element_view = new QTableWidget(parent);

        resizeWidgets(this->geometry());
}

MyWidget::~MyWidget()
{
        delete m_tree_view;
        delete m_element_view;
}

void MyWidget::resizeEvent( QResizeEvent * e )
{
        QRect oldrect = this->geometry();
        QRect r(oldrect.x(), oldrect.y(), e->size().width(), e->size().height());
        resizeWidgets(r);
}

void MyWidget::moveEvent( QMoveEvent * e )
{
        QRect oldrect = this->geometry();       
        QRect r(e->pos().x(), e->pos().y(), oldrect.width(), oldrect.height());
        resizeWidgets(r);       
}

void MyWidget::resizeWidgets(const QRect & r)
{
        double halfsizenopad = r.width() / 2.0;
        m_tree_view->setGeometry(r.x(), r.y(), halfsizenopad, r.height());
        double element_view_x = r.x() + r.width() / 2.0;
        m_element_view->setGeometry(element_view_x, r.y(), 
                                    halfsizenopad , r.height());
}

Код более серьезного виджета на С++, использующего этот же подход можно посмотреть по ссылкам: [1] [2].

UPD: Можно обойтись и без реализации resizeEvent и moveEvent, если использовать один из наследников QLayout, а виджеты добавлять в него. Спасибо degeron!

пятница, 16 мая 2014 г.

Пишем простую альтернативу для проверки списка фолловеров

Не так давно, я начал пользоваться сервисом flwrs, который отслеживает данные о том, как изменяется список фолловеров и показывает, кто зафолловил, кто расфолловил. Довольно забавная штука. Но есть у него один недостаток - эту инфу он пишет прямо в ленту. В принципе, для меня, это не важно. Но некоторым людям, которые фолловят меня может быть неприятно. В качестве альтернативы, которая почему-то не используется сервисом является посылка данных на E-mail.  Однако, она почему-то не реализована в данном сервисе.

Исходя из этого, я решил сделать простую альтернативу. В качестве языка взял PHP, чтобы сделать это побыстрее, ибо не имел никакого желания тратить на это много времени.  В качестве библиотеки для взаимодействия с Twitter был взят Twitter-php .

Нужно отметить, что само по себе встраивание библиотеки и настройки приложения потребует регистрации приложения на dev.twitter.com и прописывания сертификата OpenSSL. который можно достать, к примеру, с офф. сайта CURL и записать в php.ini:

[curl]
; A default value for the CURLOPT_CAINFO option. This is required to be an
; absolute path.
curl.cainfo = "C:\PHP\cacert.pem";

Что же до реального скрипта, то здесь я не стал заморачиваться с БД и просто сериализовывал предыдущее состояние списка отдельно в файл с расширением *.php, который просто перезаписывался при сравнении.
Сам же код скрипта при этом, выглядит проще некуда.


После вписывания требуемых данных в скрипт достаточно только взять и записать его периодическое выполнение в crontab. И - вуаля, у нас свой flwrs. 

суббота, 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 - нет.