Hatred's Log Place

DON'T PANIC!

Mar 24, 2011 - 1 minute read - projects programming

Qt Creator и CMake - продолжение

Некоторое время я поднимал тему связки Qt Creator и CMake, тогда всё показалось не очень хорошо.

В общем, собрался и сделал несколько лучше: малость допилил плагин CMakeProjectManager, реализовав следующие фичи:

  • Дерево проекта берётся не из .cbp файла, а сканированием дерева проекта. Как вариант может оказаться медленно на больших проектах, с другой стороны, релоадинг дерева происходит не каждый раз, а при смене CMakeLists.txt или при добавлении, удалении, переименовывании файлов (этого, кстати, в базовом плагине нет)
  • Теперь можно создавать новые файлы в дереве проектов непосредственно из Qt Creator’а
  • Появилась возможность переименовывать файлы
  • Появилась возможность удалять файлы с диска

Изменения оформлены в виде отдельного плагина (основано на GIT версии Qt Creator, 2.2.81) - CMakeProjectManager2 доступного на Gitorious: http://gitorious.org/hatred-qt-creator-plugins/cmakeprojectmanager2, как устанавливать - читать README.txt, написано моим дряным английским, но, в общем, должно быть понятно.

Кроме того, в основное дерево Qt Creator я подал мёрж-реквест: http://qt.gitorious.org/qt-creator/qt-creator/merge_requests/280

Кроме того, случайно наткнулся мастера новых проектов на CMake: http://apachelog.wordpress.com/2010/09/27/qt-creator-cmake-wizards/ устанавливаются просто.

Mar 18, 2011 - 2 minute read - linux

Примитивный SMTP клиент

Про SMTP протокол знают все: текстовый, простой, можно почту отослать и при помощи telnet. Собственно, при помощи оного и сделан скрипт ниже.

Mar 16, 2011 - 1 minute read - programming

Консоль, скрипты, XML и XPath

Иногда в скриптах нужно мало-мало добраться до внутрянки XML файлов – к тегам или свойствам тегов. Для сих целей бывает удобно использовать XPath . Вопрос: а как это делать-то из скриптов?

На помощь приходит утилитка xmllint из состава libxml2. Начиная с версии 2.7.7 или 2.7.8 там появилась опция --xpath которая задаёт выражение для выборки. В более ранних версиях (2.7.6, к примеру) этой опции нет, но есть (в последних тоже) возможность вызова “консоли” и интерактивного разбора XML.

В общем два варианта:

xmllint --xpath '//File/@Name' test.xml

и

echo 'cat //File/@Name' | xmllint --shell test.xml

Остальное - фантазия.

Mar 15, 2011 - 1 minute read - programming

Qt Creator и CMake

Пакость: Qt Creator умеет импортировать CMake проекты, проблема в том, что в дереве далеко не все файлы отображаются.

Причина: делается этот импорт через откровенную задницу: вызывает cmake с генератором “-G’CodeBlocks - Unix Makefiles’”, генерируя тем самым XML-файл проекта формата CodeBlocks. Но тут накладывается вторая задница: сам генератор обрабатывает файлы только для таргетов: executable, static_library, shared_library, module_library, всё остальное он забывает запихнуть в результирующий ‘.cbp’.

Решение

Для начала накладываем патч на CMake и пересобираем его:

--- cmExtraCodeBlocksGenerator.cxx.orig 2011-03-15 14:28:30.692010962 +1000
@@ -410,12 +410,14 @@
     for (cmTargets::iterator ti = targets.begin();
          ti != targets.end(); ti++)
       {
+      //std::cout << "Type: " << ti->second.GetType() << std::endl;
       switch(ti->second.GetType())
         {
         case cmTarget::EXECUTABLE:
         case cmTarget::STATIC_LIBRARY:
         case cmTarget::SHARED_LIBRARY:
         case cmTarget::MODULE_LIBRARY:
+        case cmTarget::UTILITY:
           {
           const std::vector<cmSourceFile*>&sources=ti->second.GetSourceFiles();
           for (std::vector<cmSourceFile*>::const_iterator si=sources.begin();

Потом, для тех файлов, которые хотим видеть в дереве создаём фейковый таргет, примерно так:

set(script-files
    process-filelist.sh
)
# hack for display in Qt Creator (with patch for CMake)
add_custom_target(scripts true SOURCES ${script-files})

Всё, после регенерации файлы появятся в списке.

Решение костыльное, но время переписывать импортёр CMake в Qt Creator просто нет, будем надеяться, что разработчики обратят на это внимание.

Mar 6, 2011 - 1 minute read -

Исследование блоков кода в Emacs

Всегда мучался вопросом: как сделать так, что бы блок между фигурными скобками в сишном файле с исходным кодом оставался подсвеченным пока я делаю скролинг - визуально посмотреть его границы размеры и прочее. Проблем в том, что курсор в Emacs может находиться только в видимой части, соответственно, если блок большой, он никак на экран поместиться не может, значит курсор перескочит с начал/конца блока и подсветка исчезнет.

Сегодня случайно нашел небольшой хак, частично решающий эту проблему: http://www.physics.utah.edu/~detar/lessons/emacs/emacs/node7.html, процитирую:

Parenthesis checking can also be done with the mouse. Double left click on any parenthesis, brace, or bracket. Emacs then shows the matching symbol and highlights the code between them.

Краткий перевод: двойным щелчком мыши по скобке - блок между ней и парной подсветится, выделение будет динамическим от скобки до второй парной или до курсора на экране. Мышкой можно скролить, выделение останется.

Mar 5, 2011 - 1 minute read -

Поиск от Google

Добавил поиск от Google, а то встроенный в DokuWiki не всегда отрабатывает должным образом, а, судя по логам, робот гугла почти не покидает мой сайт :)

Для поиска сделал кастомный: http://www.google.com/cse/. С рекламой даётся бесплатно.

Что бы разделить запрос и результаты, пользовался этим хинтом: http://googleajaxsearchapi.blogspot.com/2010/03/search-form-and-results-on-two.html

Для поиска нужен JavaScript, поэтому пользователям NoScript, хотя бы временно, его нужно отключить для сайта.

Mar 5, 2011 - 2 minute read -

Emacs Muse

Наконец нашёл удобное средство для html/pdf публикации без излишней навороченности.

Вести сайт при помощи него я не собираюсь, но вот использовать как инструмент для создания отдельных HTML или PDF документов - вполне (первым, наверное, станет перевод документации для crowns на muse).

Что такое Muse и с чем его едят есть даже в русских интернетах:

Ну и официальные источники:

За основу своих настроек взял оные из статьи Алекса Отта. Единственно, из коробки взял только его шаблоны для генерации PDF (да и то, наверное, пересмотрю со временем). Для генерации html использую дефолтный шаблон xhtml1.1 – пока не определюсь со своими собственными, так как, по сути, собираюсь только использовать для статей, которые нужно куда-то отправить после.

Ну и для затравки сделал небольшой документ-шпаргалку по muse при помощи самого muse:

Так же стоит обратить внимание на режим org-mode, подробно рассписывать не буду, ограничусь ссылками:

На последок: muse есть как в основных репозиториях ArchLinux (кстати, разработчик оного - арчевод :)), так и в AUR ( emacs-muse-git); режим org-mode есть только в AUR: emacs-org-mode (если не хотите стареньким, идущим вместе с Emacs, пользоваться).

Mar 2, 2011 - 2 minute read - programming

Hightide

Hightide (High Tide - большая вода) - сборка Jetty с включенными дополнительными библиотеками и сервисами JavaEE (эдакий не совсем JavaEE Application Server). Решили попробовать его для своих нужд, пока возможностей JBoss нам не нужно.

Последняя стабильная версия - 7.3.0 (поддерживается Java5), нестабильная - 8.0.0.M2 (нумерация по версии Jetty, поддерживает Java6).

Скачать можно отсюда: http://dist.codehaus.org/jetty/

Для удобной работы потребуется адаптер для WTP, который поддерживает Jetty 7 и 8: http://wiki.eclipse.org/Jetty_WTP_Plugin/Jetty_WTP_Install

Единственный нюанс: адаптер рассчитан чисто на Jetty, поэтому в дефолтной конфигурации просто не запустится - не будет хватать jar-ников. Пока выход нашёл ровным счётом один: по двойному клику на вкладке Servers по Jetty открываем диалог конфигурации, там идём в “Open launch configuration” и далее двигаемся на вкладку Classpath и в категории User Entries добавляем External JARs, которые ищем в lib директории и поддиректориях в jetty.home.

Если есть другие пожелания - в каментах жду ответов.

При работе с Maven поможет эта статья: http://docs.codehaus.org/display/JETTY/Fast+WebApps+with+Hightide

А про мой “любимый” JAAS почитать можно тут: http://docs.codehaus.org/display/JETTY/JAAS, а вообще по документации:

По вопросам горячего деплоя можно почитать тут: http://phishbouncer.com/trac/browser/trunk/jetty/demo/webapps/jetty/faq/HotDeploy.html, где сказано, цитирую:

Q: Can Jetty Hot Deploy?

A: Jetty is fully hot deployable, but does not have any native hot deployers. What this means is that Jetty contexts, servlets and filters may be added, stopped, started and reloaded dynamically, but that Jetty does not have any services that trigger these events.

Далее по тексту идут причины такого поведения. Ну и полезным по этой теме будет:

Feb 20, 2011 - 1 minute read - programming

Си, прекрасное

http://eli.thegreenplace.net/2011/02/15/array-initialization-with-enum-indices-in-c-but-not-c/ - это воистину прекрасно! Использовать enum для именованной инициализации массива. Можно делать в C99, не работает в C++

Ну и ссылки, на правах мемориза:

  • http://www.advancedlinuxprogramming.com/alp-folder - по названию сайта уже понятно, что это такое :) книжка “Advanced Linux Programming” в сободном доступе. На просторах интернета встречается русский перевод, можно поискать.
  • http://mij.oltrelinux.com/devel/unixprg/ - “UNIX programming examples” - примеры кода на Си для unix, в частности - сокеты, IPC, потоки.

Feb 18, 2011 - 2 minute read -

Dokuwiki Bookmark и Firefox

Внимание: статья полностью неактуальна ввиду переезда на статику в 2019 году.

Какое-то время назад я поднял у себя на wiki систему веб-закладок. Из браузеров подобные закладки добавляются при помощи так называемых bookmarklets - javascript вводящихся через адресную строку.

Естественно что, по сути, единственная удобная возможность использования веб-закладок - это создать на панели закладок (каламбууур!) закладку с URL с текстом букмарклета.

Но мне что-то не понравилось: держать открытую панель закладок ради этого, тратить драгоценное экранное место моего EeePC 1000HA… Решил покурить тему.

Задачу сформулировал так: создать кнопку, которую можно поместить на любую активную панель, и вызывать диалог сохраненя веб-закладки по нажатию на неё.

Приступил к поиску. Результат не заставил себя долго ждать: почти сразу нашел расширение Custom Buttons.

Следующим шагом - придумать код кнопки. Атака “в лоб”, то есть подстановкой кода букмарклета в команду openURI не увенчалась успехом. Но, благодаря этим документам:

  • Custom Buttons Documentation
  • Tabbed browser (особенно про получение объекта document для текущей открытой вкладки)
  • Pages tagged with “DOM” (тут вообще читать не перечитать, но оставим это любителям ваять расширения для FF) был составлен следующий код (помещается во вкладке Code (Код) редактора новой кнопки):
/*CODE*/
host  = 'http://hatred.homelinux.net/wiki';

doc   = content.document;
title = doc.title;
url   = doc.location.href;
sel   = doc.selection ? doc.selection.createRange().text : doc.getSelection();

target_url = host + '/doku.php?do=dokubookmark&te=' + encodeURI(sel) + 
                    '&ur=' + encodeURI(url) + '&ti=' + encodeURI(title);

// Open in new Window
window.open(target_url, 'dokuwikiadd',
    'scrollbars=yes,resizable=yes,toolbars=yes,width=680,height=520,left=210,top=150,status=yes');
// Open in new Tab
//gBrowser.selectedTab = gBrowser.addTab(target_url);

Адрес сайта, естественно, исправляете на свой. Так же можете выбрать способ открытия окна сохранения: по умолчанию - новое окно, а можно - в новой вкладке.

На скриншоте процесс редактирования выглядит так:

Кнопку после создания помещаем на любую открытую панель и пользуемся.

Из замеченных косяков: при включенном No script при открытии окна сохранения ругается на возможную XSS атаку и малость коверкает выделение при вставке, приходится перечитывать.

Feb 14, 2011 - 1 minute read - programming

Maven и WTP

WTP - Eclipse Web Tools Platform. Набор расширений для удобной работы с WEB проектами. Деплой на различные серверы приложений, отладка, профилирование и много всего другого вкусного.

Про Maven не пишу, многим понятно. В последних версиях плагина для Eclipse в extra есть модули для j2ee проектов различных версий соглашений (j2ee 5/6 и младше). Но статья по ссылке:

http://www.devx.com/Java/Article/36785

будет полезна как инструкция по переводу существующего проекта, созданного средсвами Eclipse и WTP на сборку maven’ом.

Feb 14, 2011 - 1 minute read - programming

Java и LDAP. Малость заметок

Помаленьку, понемножку, на уровне ссылок.

Заметка первая: LDAP как JNDI ресурс в context.xml

Читать тут: http://old.nabble.com/LDAP-as-resource-in-context.xml-td14204908.html

Из бяк: при использовании пула подключений, само подключение создаётся в момент new InitialDirContext(env); или первого обращения поиска атрибутов. Для подключения создаётся поток, который не завершается при редеплое. Tomcat ругается при этом на потенциальную утечку памяти. Раздражает.

Заметка вторая: использование DN в фильтрах

Не сразу прокурил как, вот статейка на русском языка, поясняющая - как это нужно делать: http://sysadminblog.ru/ldap/2011/01/18/tipichnye-primery-ispolzovaniya-entrydn-v-ldap-filtrah.html

Feb 8, 2011 - 2 minute read - programming

ThreadLocal Memory Leak

Использовать ThreadLocal переменные удобно, для расшаривания данных между разными частями одного потока (допустим достучаться из POJO объекта к HTTP сессии и т.п.). Другое дело, что чревато в контексте использования сервера приложений: тут треды не уничтожаются, а возвращаются в пул потоков, как следствие: GC не собирает их, они остаются в памяти, а тут, помимо явной утечки, есть ещё и потенциальная дырка в безопасности.

По ссылке статья на английском на эту тематику. Как решить теперь буду думать.

По этой ссылке:

http://wiki.apache.org/tomcat/MemoryLeakProtection

Можно почитать про разные MemLeaks в веб-приложениях (точнее про технологию защиты от оных в Tomcat)

UPD: подкатом решение (???)

Решение

Найдено тут: http://weblogs.java.net/blog/jjviana/archive/2010/06/09/dealing-glassfish-301-memory-leak-or-threadlocal-thread-pool-bad-ide

какое выбирать, решать вам, я выбрал второй вариант с наследованием класса. Скопирую его тут с форматированием:


import java.lang.ref.SoftReference;

public abstract class SoftThreadLocal<T> extends ThreadLocal<T>
{
    // Encapsulation required because Generics is stupid about references, and there is no interface for ThreadLocal, 
    //so I can't simply extend a single ThreadLocal, grr! Java has so many brittle design mistakes in it.
    private final ThreadLocal<SoftReference<T>> local = new ThreadLocal<SoftReference<T>>();

    
    @Override
    public T get() 
    {
        SoftReference<T> ref = local.get();
        T result = null;
        
        if (null != ref) 
        {
            result = ref.get();
        }
        
        if (null == result) 
        {
            result = initialValue();
            ref = new SoftReference<T>(result);
            local.set(ref);
        }
        
        return result;
    }
    
    
    @Override
    public void set(T value) 
    {
        if (null == value) 
        {
            remove();
        } 
        else 
        {
            local.set(new SoftReference<T>(value));
        }
    }
    
    
    @Override
    public void remove() 
    {
        local.remove();
    }
}

Далее работа классическая, к примеру, как у меня через ThreadLocal Singleton:

import java.util.HashMap;

/**
 * Небольшой вспомогательный статический класс
 * для расшариванить локальных для треда переменных. Значение будет для каждого треда своё.
 * 
 * Допустим, получая в методе doPost()/doGet() сервлета значение сессии и для проброса во все дочерние
 * классы, без необходимости передачи оных параметром, что, собственно говоря, не всегда возможно.
 *
 * @author hatred
 * 2011-01-27
 */
public class ThreadContext
{
    private /*static*/ final SoftThreadLocal<HashMap<Object, Object>> _context = new SoftThreadLocal<HashMap<Object, Object>>()
    {
        protected HashMap<Object,Object> initialValue()
        {
            return new HashMap<Object,Object>();
        }
    };

    private static ThreadContext _instance = null;
    //
    
    synchronized public static ThreadContext getContext()
    {
        if (_instance == null)
        {
            _instance = new ThreadContext();
        }
        
        return _instance;
    }
    
    synchronized public static void releaseContext()
    {
        if (_instance != null)
        {
            _instance.clear();
            _instance.contextRemove();
        }
        
        _instance = null;
    }
    
    public void put(Object key, Object value)
    {
        _context.get().put(key, value);
    }
    
    public Object get(Object key)
    {
        return _context.get().get(key);
    }
    
    public void remove(Object key)
    {
        _context.get().remove(key);
    }
    
    public void clear()
    {
        _context.get().clear();
    }
    
    protected void contextRemove()
    {
        _context.remove();
    }
}

Кстати, не могу понять, насколько правильно делать getContext() и releaseContext() synchronized?