11 октября 2011 г.

Плагин Google для Eclipse: обновления о которых не просят

Обнаружил интересную особенность у плагина Google для Eclipse, позволяющего разрабатывать приложения с использованием GWT и App Engine.

После очередного перезапуска контейнера сервлетов Jetty, который используется плагином для запуска GWT приложений на локальном хосте, он как-то необычно призадумался на старте. Вывел мне на консоль "Initializing App Engine server" и замолчал. Понимаю, что тужится, но не понимаю с чего это вдруг. Подождал я его несколько минут и он выдавил на консоль что-то вроде этого:
INFO: Unable to access http://appengine.google.com/api/updatecheck?runtime=java&release=1.5.4×tamp=1315604504&api_versions=['1.0']
Оказалось, что этот негодяй при каждом старте проверяет наличие обновлений, а у меня тут как раз отвалился интернет. Мне в принципе не жалко, пусть проверяет, но ждать его по несколько минут при каждом перезапуске когда нет сети как-то не особо хочется.

Первым делом я, конечно, полез в настройки Eclipse (Window -> Preferences -> Google) и убрал галку с пункта "Notify me about updates", но ничего не изменилось. Немного пошарив по интернету, я наткнулся на забавное описание метода allowedToCheckForUpdates() класса UpdateCheck в пакете com.google.appengine.tools.info. По названию пакета можно сделать некоторые выводы о том, для чего он нужен. Вот описание этого метода:
Returns true if the user wants to check for updates even when we don't need to. We assume that users will want this functionality, but they can opt out by creating an .appcfg_no_nag file in their home directory.
В общем, надо или не надо, этот метод все равно возвращает true, т.к. разработчики уверены что, если пользователь даже отключил проверку обновлений, то он всё равно хочет обновлений. Как-то так получается :) Однако, всё-таки можно эту проверку отключить, создав в домашнем каталоге пользователя, под которым запускается контейнер, файл .appcfg_no_nag. После того, как я это сделал, "задумчивость" контейнера на старте прошла, но tcpdump показывает, что он всё равно продолжает стучаться на appengine.google.com.

29 сентября 2011 г.

Основы использования системы сборки Apache Ant

Когда ведется разработка программного продукта, он может состоять из множества исходных частей. Например, разработка может вестись несколькими людьми практически независимо друг от друга, а файлы с исходным кодом, за который они отвечают, могут находится в совершенно разных местах файловой системы и даже на разных машинах. Кроме файлов исходного кода, в проекте могут использоваться также и готовые библиотеки от сторонних разработчиков (например, файлы jar, dll или so), файлы конфигурации, различные картинки и иконки, звуковые файлы и куча всего остального. Все эти штуки могут так же изменяться в ходе разработки проекта другими людьми.

А теперь представьте, что из всего этого безобразия необходимо собрать всего один файл сжатого архива, который пользователь мог бы скачать с вашего сайта, распакавать и сразу же запустить ваш продукт. Вам нужно будет собрать вместе все файлы с исходным кодом Java и скомпилировать их, прогнать тесты, чтобы убедиться что проект никто не поломал, полученные class-файлы упаковать в JAR (или несколько JAR'ов), для которого ещё необходимо сгенерировать правильный манифест, содержащий CLASSPATH, имя главного класса, номер версии и т.п., затем собрать вместе все остальные файлы вроде библиотек, картинок и конфигов, распихать это все в правильные каталоги, сгенерировать документацию, создать из всего этого архив и залить его на ваш вэб-сервер, а всё произошедшее записать в лог и сохранить его в базе данных, которая хранит информацию о различных сборках. Делать всё это руками довольно уныло, да и не должен психически здоровый человек этим заниматься.

Системы сборки, такие как Apache Ant, были созданы для того, чтобы автоматизировать весь этот порой достаточно сложный и рутиный процесс по сборке проекта. Причем, в случае с Apache Ant проект не обязательно должен быть на Java, и не обязательно должен быть вообще программным обеспечением. Это может быть что угодно, хотя ориентирован он, конечно же, в первую очередь на Java. В данной статье я хочу на очень простом примере показать, как можно облегчить себе жизнь с помощью Apache Ant.

14 августа 2011 г.

Вычисление БПФ на GPU с использованием Java и CUDA

В последнее время у меня на работе встала задача создания спектрограмм для довольно большого объема данных. Главным инструментом для этого является алгоритм Быстрого Преобразования Фурье. На сегодняшний день для Java написано уже множество библиотек, реализующих вычисление БПФ и другие математические инструменты, например, мне нравится Commons Math от Apache project. Но для того, чтобы обрабатывать большие объемы данных с помощью этой библиотеки за более или менее разумное время, нужна довольно мощная и недешевая машина, которой у меня нет. Поэтому я и обратил свой взор на технологию NVIDIA CUDA, которая позволяет очень шустро производить расчеты с плавающей точкой на чипе видеокарты. А, как известно, БПФ это очень даже плавающая точка :) Вдвойне приятно то, что хорошие люди уже давно написали Java-интерфейс JCuda для нативной библиотеки CUDA. И ещё больше я обрадовался, когда обнаружил, что библиотека CUDA имеет в своем составе модуль CUFFT, который предоставляет средства для расчета БПФ, использующие по полной программе возможности видеокарты для выполнения параллельных вычислений с плавающей точкой.

CUDA поддерживается видеокартами NVIDIA GeForce начиная с чипа G80, т.е. с восьмой серии. Машина, на которой я тестирую в данный момент связку Java + CUDA довольно старенькая и имеет на борту процессор AMD Athlon X2 4200+, видеокарту NVIDIA GeForce 8800 GTS 640 Mb, всего 2 Gb оперативной памяти и управляется операционной системой openSUSE 11.4.

23 июля 2011 г.

Баг kdesu в openSUSE 11.4

Столкнулся в openSUSE 11.4 с тем, что мои замечательные скрипты выбора конфигурации сети, вдруг перестали нормально работать. Довольно быстро мне стало понятно, что сердце неприятности заключается в программе kdesu. Здравствуй, новый KDE! Суть проблемы была в том, что после ввода в диалоговом окне пароля суперпользователя ничего не происходило, а должен был запуститься скрипт с соответствующими правами. Я перекопал весь интернет и не нашел ничего лучше, чем удалить (а точнее просто переименовать на всякий случай) файл /usr/lib/kde4/libexec/kdesud. После этого всё вроде бы заработало, но теперь kdesu стал ругаться, что не может найти своего друга-демона и что это вроде как небезопасно. Ну и хрен с ним, пусть боится.

22 июля 2011 г.

Instant Messenger'ы в Linux. Сборка qutIM 0.3 beta в openSUSE 11.4

По моему сугубо личному мнению, в Linux, если рассматривать его как систему для десктопного использования, существует две бросающихся в глаза проблемы: отсутствие приятных в использовании мультимедиа проигрывателей и отсутствие таких же приятных Instant Messenger'ов. В этой статье я хочу поговорить о последних.

Не знаю кому как, но мне всем известные Kopete и Pidgin кажутся страшненькими и неудобными. Хочется что-то попроще, но симпатичное. Что-то вроде того, чем раньше был QIP, только многопротокольное. И достаточно давно я открыл для себя qutIM. Думаю, что сегодня у него уже достаточно много пользователей. Первая версия, которую я себе поставил была 0.1 (то ли альфа то ли бета). Когда я её увидел, то сразу понял, что это то, чего мне так не хватало для счастья. Конечно, глючило это создание прилично, но мне было всё равно, главное, что глаз радовало.

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

Несколько дней назад я решил попробовать 0.3 beta, и тут меня поджидало разочарование. Внешне всё сильно изменилось, и для меня не в лучшую сторону. Вдобавок появилось очень много новеньких глюков. Понятно, конечно, что это бета-версия, но дело даже не в глюках. Я по-прежнему готов с ними мириться. Такое чувство, что проект пошел в ту же сторону, где сидят Kopete и Pidgin. Я говорю, главным образом, о простоте и органичности интерфейса, а также о понятности настроек. Пока что я решил остаться на версии 0.2, но продолжу следить за проектом, вдруг снова станет лучше. А пока расскажу, как собрать 0.3b в openSUSE 11.4, и делается это довольно просто, что приятно.

21 апреля 2011 г.

Как узнать полный путь до запущенного bash-скрипта

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

Можно, конечно, поступить просто и в самом скрипте в переменной жёстко прописать полный путь до каталога, в котором этот скрипт лежит. Получится что-то вроде этого:
#!/bin/bash

DIRECTORY="/home/user/my_scripts"
cd $DIRECTORY

# запуск "соседних" скриптов
./script1.sh
./script2.sh
Вполне рабочий вариант и две обозначенные выше проблемы будут решены, но если надо будет переместить скрипт в другой каталог, то и значение переменной придётся руками поменять в самом скрипте. Не очень удобно.

Для красивого решения проблемы нужно знать всего три вещи:
  1. Путь до выполняющегося скрипта можно узнать с помощью $0, но проблема в том, что он относительный, т.е. если вы запустите скрипт как ./script.sh, то и $0 будет содержать ./script.sh
  2. Команда readlink с параметром -e решит сразу две проблемы: во-первых она вернет полный путь до файла скрипта, если вы воспользовались для запуска символической ссылкой (даже если это была цепочка симлинков), а во-вторых преобразует относительный путь, если такой получен с помощью $0, в абсолютный
  3. Чтобы избавиться от имени файла скрипта в конце абсолютного пути, нужно воспользоваться командой dirname
    Пример:
    #!/bin/bash
    
    # полный путь до скрипта
    ABSOLUTE_FILENAME=`readlink -e "$0"`
    # каталог в котором лежит скрипт
    DIRECTORY=`dirname "$ABSOLUTE_FILENAME"`
    
    # запуск "соседних" скриптов
    $DIRECTORY/script1.sh
    $DIRECTORY/script2.sh
    

    4 апреля 2011 г.

    Прикручиваем кнопки "Поделиться" от Яндекса к www.blogger.com

    Захотелось мне прикрутить к блогу эти самые кнопочки. Напишу пару слов о том, как я это сделал.

    Сначала идём по адресу http://api.yandex.ru/share/, настраиваем вид блока "Поделиться" и выбираем сервисы, в которые хочется постить с его помощью. Получаем код, вроде этого:

    Теперь заходим в Панель инструментов -> Дизайн -> Изменить HTML. Ставим галку рядом с "Расширить шаблоны виджета".

    Между тегами <head> и </head> где-нибудь втыкаем первую строку из листинга выше. Короче эту:

    Дальше надо выбрать место, где хочется разместить эти кнопки. Я решил вставить их под сообщением, ниже автора и времени создания сообщения. Если вас устраивает это место, то ищите в шаблоне строку <span class="post-icons"> и над ней вставляйте оставшуюся часть полученного кода:

    Если вы сохраните шаблон и зайдёте на блог, то кнопочки должны будут появиться и будут даже работать, только не всегда правильно. Например, если отдельно открыть страницу с конкретным сообщением блога и там нажать на какую-либо из кнопок "поделиться", то всё отработает правильно. А вот если нажать на одну из этих кнопок под каким-либо сообщением на главной странице, то делёжка будет осуществляться не ссылкой на это сообщение, а ссылкой на главную страницу блога. Для того, чтобы такого безобразия не происходило, нужно элементу DIV добавить атрибуты data-yashareLink и data-yashareTitle, которые позволяют установить ссылку, которой нужно поделиться и заголовок сообщения, соответственно. Но для того, чтобы динамически получать ссылку и заголовок нужно использовать хитрые выражения, которые понимает движок блоггера.

    Вот как это выглядит:

    В процессе генерации страниц блога выражение expr:data-yashareLink='data:post.url' будет заменено блоггером на data-yashareLink='http://myblog.blogspot.com/путь_до_сообщения', а expr:yashareTitle='data:post.title' на yashareTitle='Заголовок_сообщения'.

    Кстати, контейнером для кнопок может быть не обязательно элемент DIV, я использую SPAN. Вот код, который я добавил себе в шаблон:


    25 марта 2011 г.

    Красивое использование косвенной адресации в bash-скриптах

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

    Итак, допустим у нас есть переменная X, которая содержит строку "значение". Так же есть переменная Y, которая в качестве значения содержит имя переменной X. Красивость заключается в том, что с помощью прямой и косвенной адресации, используя переменную Y, можно получить соответственно имя и значение переменной X.

    Простой пример:
    X="значение"
    Y=X
    echo "$Y: ${!Y}"
    
    В этом примере с помощью прямой адресации $Y мы получаем доступ к имени переменной X, а с помощью косвенной ${!Y} - к её значению. В старых версиях bash косвенная адресация могла использоваться только так eval Z=\$$Y, а начиная со 2 версии она стала выглядеть проще, хотя старый вариант так же может использоваться.

    Теперь приведу более жизненный пример. У меня есть скрипт, который настраивает iptables. Косвенная адресация в нем используется для того, чтобы сделать проще изменение настроек скрипта и создать красивый вывод. Приведу пример поясняющий основную суть.
    #!/bin/bash
    
    # список сервисов и их портов
    SSH=22
    HTTP=80
    HTTPS=443
    SAMBA="137 138 139 445"
    
    # локальные сервисы на которые разрешен доступ снаружи
    INPUT_PORTS_ACCEPT="SSH SAMBA HTTP HTTPS"
    
    echo "Удаленный доступ к сервисам хоста:"
    # открываем доступ на разрешенные сервисы
    for SERVICE_NAME in $INPUT_PORTS_ACCEPT
    do
        # для каждого порта сервиса добавляем разрешающие правила в iptables
        PORTS=${!SERVICE_NAME} # устаревший вариант: eval PORTS=\$$SERVICE_NAME
        for PORT in $PORTS
        do
            iptables -t filter -A INPUT -i eth0 -p tcp --dport $PORT -j ACCEPT
            iptables -t filter -A INPUT -i eth0 -p udp --dport $PORT -j ACCEPT
        done
    
        # выводим имя и порты сервиса
        echo "$SERVICE_NAME: $PORTS --accept"
    done
    
    Вывод скрипта:

    Удаленный доступ к сервисам хоста:
    SSH: 22 --accept
    SAMBA: 137 138 139 445 --accept
    HTTP: 80 --accept
    HTTPS: 443 --accept

    Таким образом, для настройки скрипта в переменной INPUT_PORTS_ACCEPT нужно указывать не номера портов, а просто имена сервисов, и в выводе наглядно показано на какие локальные сервисы открыт доступ и какие порты им соответствуют. Красиво :)

    11 марта 2011 г.

    JDOM: работа с XML на Java - проще простого

    JDOM – это максимально упрощенная open source Java-библиотека для создания, парсинга, изменения и сериализации XML-документов. В отличие от других подобных DOM APIs, JDOM ориентированна на язык Java, а не на спецификации XML, что очень упрощает код и облегчает его интуитивное понимание. При этом JDOM не является "велосипедом" и не содержит в себе свой собственный парсер, а использует уже существующие наработки – стандартные пакеты javax.xml и org.xml.sax. Если вам понадобилось работать с XML, то обратите сначала внимание именно на эту библиотеку, скорее всего вам она понравится.

    Краткое описание модели библиотеки JDOM

    Так же, как и сам XML, JDOM APIs являются древовидными. Для представления XML в библиотеке, главным образом, используются классы Document, Element и Attribute.

    Документ XML в JDOM представляет из себя дерево, корнем которого является объект класса Document. Экземпляр Document является контейнером для всех остальных элементов и обязательно содержит один корневой элемент (экземпляр Element). Главной характеристикой объекта Element является его содержание (Content) и список атрибутов (Attribute). Класс Content является родительским для классов Element, Comment и Text (а так же для некоторых других), поэтому экземпляры перечисленных классов могут быть содержимым объекта Element. Объект Element есть ничто иное как XML-тег, у которого обязательно должно быть имя и могут быть атрибуты. Классы Comment и Text соответственно представляют комментарий и текст внутри тега. Экземпляры Attribute, Comment и Text не могут содержать внутри себя никаких элементов и по сути являются объектами, которые содержат только текстовые значения. Значение экземпляра Attribute может быть получено по имени в отличие от Comment и Text, у которых имени нет.

    1 февраля 2011 г.

    Работа со звуковыми WAVE-файлами на Java

    Мне на работе иногда приходится иметь дело с WAVE-файлами (или WAV по расширению) по той причине, что в них довольно удобно хранить научные данные и не надо выдумывать формат. Решил написать маленькую заметку о работе с этим форматом на Java. Сразу оговорюсь, что речь тут пойдет не о воспроизведении звуковых файлов с помощью Java, а о том как можно их создавать, изменять, и читать из них данные.