среда, 19 августа 2009 г.

Last.fm recently played list by XternalX Userbars

Итак, наконец-то мой друг Виктор XternalX выпустил первую бета версию своих динамических юзербаров, с чем я его от всей души и поздравляю! :) И в этом блогпосте я постараюсь описать процесс создания юзербара отображающего списко последних пяти прослушанных мной на Last.FM композиций. Надо сказать, что родной сервис юзербаров от last.fm работает, мягко говоря, не корректно, поэтому сервис динамических юзербаров XternalX Userbars тут оказался, как нельзя кстати.

Last.FM XternalX Userbar

Первое, что мы делаем, регистрируем себе новый аккаунт в XternalX Userbars. Форма регистрации находится здесь. После чего войдя в XternalX Userbars под только что созданной учётной записью, мы попадаем в редактор юзербаров (Рис. 1).

Рис. 1 Панель управления XternalX Userbars


Не вдаваясь в подробности описания интерфейса, опишу непосредственно сам процесс создания моего юзербарчика.
Для начала, нам необходимо зайти в "Файловый менеджер" (Рис. 2) и выбрать там основу (или фон) нашего юзербара.

Рис. 2 Файловый менеджер

В файловом менеджере уже есть несколько картинок, которые можно использовать в качестве фона, но мы загрузим свою картинку. Для этого внизу окна файлового менеджера щёлкнем ссылку "Загрузить файл". Откроется диалог изображенный на рисунке 3.

Рис. 3 Диалог загрузки фона юзербара

Нажмём кнопку "Обзор..." и выберем нужный нам фон, в моём случае -- это давно заготовленная картинка, которую я безуспешно пытался, в своё время, скормить сервису юзербаров last.fm. Учтите, что картинка обязательно должна быть в формате PNG!
Теперь понравившийся нам фон выбран, жмём ссылку "Загрузить" внизу диалога загрузки фонового изображения. После загрузки мы снова окажемся в Файловом менеджере. Не спешите искать в списке файлов, только что загруженный нами, его там нет (бета версия как ни как ;)). Необходимо закрыть файловый менеджер, щелчком по крестику в его верхнем правом углу, и открыть его снова. Теперь список файлов в файловом менеджере обновился и мы можем спокойно найти только что загруженный нами файл и выбрать его (Рис. 4).

Рис. 4 Предпросмотр выбранного в файловом менеджере изображения

Теперь закрываем файловый менеджер (да-да, я не опечатался, именно закрываем). И в панели управления XternalX Userbars щёлкаем плюсик справа от поля "Основа юзербара". Теперь в текстовом поле "Основа юзербара" образовалось название только что загруженного нами файла. Для того, чтобы выбранный нами фон отобразился в предпросмотре юзербара нажмём кнопочку "Сохранить" внизу панели упарвления XternalX Userbars. Результат на рисунке 5.

Рис. 5 Предпросмотр юзербара

Теперь включим необходимые нам плагины. Для этого заходим в "Расширения" и приводим там всё в соответствие с рисунком 6.

Рис. 6 Менеджер расширений XternalX Userbars

Затем щёлкаем по гаечному ключу справа от расширения "Last.FM Track Feed" и настраиваем его (Рис. 7). В поле "Введите URL до Вашей RSS Ленты" вводим следующий адрес: http://ws.audioscrobbler.com/1.0/user/Akinfold/recenttracks.rss естественно, заменяя имя пользователя last.fm на своё. В поле "Формат даты и времени" вводим "H:i". И нажимаем "Сохранить".

Рис. 7 Настройки Last.FM Track Feed


Закрываем диалог менеджера расширений и теперь приступаем к написанию кода нашего юзербара. В листинге 1 приведён весь код, который я разберу подробно далее.

Листинг 1.
str(100,12,7,0,arial,000000,lastfm(1,date))
str(130,7,12,0,arial,000000,lastFm(1,title))

str(100,24,7,0,arial,666666,lastfm(2,date))
str(130,23,8,0,arial,666666,lastFm(2,title))

str(100,36,7,0,arial,666666,lastfm(3,date))
str(130,35,8,0,arial,666666,lastFm(3,title))

str(100,48,7,0,arial,666666,lastfm(4,date))
str(130,47,8,0,arial,666666,lastFm(4,title))

str(100,60,7,0,arial,666666,lastfm(5,date))
str(130,59,8,0,arial,666666,lastFm(5,title))
Как мы видим, код юзербара разбит на 5 однотипных блоков. Каждый блок кода отвечает за вывод одной строки формата <время> <композиция>. Каждый такой блок состоит из двух вызовов функции str, которая отвечает за вывод текста в XternalX Userbars. Эта функция принимает 7 параметров:
  1. Горизонтальное положение левой границы надписи относительно левого края юзербара. Или, проще говоря, координата текста по оси X.
  2. Вертикальное положение верхней границы надписи относительно верхнего края юзербара. Или, проще говоря, координата надписи по оси Y.
  3. Размер шрифта в пикселях.
  4. Угол поворота текста.
  5. Шрифт, которым будет отрисовываться текст на юзербаре.
  6. Цвет шрифта.
  7. Текст. В нашем случае текст возвращает функция lastFm речь о которой пойдёт далее.
Таким образом, каждая первая строка блока отображает время, когда была прослушана композиция, а каждая вторая строка отвечает за отображение названия и автора композиции. В нашем примере для вывода информации о композициях мы используем функцию lastfm, которая принимает два параметра:
  1. Номер композиции в списке недавно прослушанных композиций. Последняя прослушанная композиция имеет номер 1, прослушанная до неё композиция имеет номер 2 и так далее.
  2. Ключевое слово, сообщающее функции, какую информацию о композиции выводить. В нашем случае мы выводим время прослушивания композиции (ключевое слово date) и название композиции (ключевое слово title).
Ну вот, наконец-то всё готово и мы жмём ссылку "Сохранить" внизу панели управления XternalX Userbars. Теперь результат наших трудов отображается в предпросмотре юзербара (Рис. 8).

Рис. 8 Юзербар готов к употреблению

Теперь смело копируем ссылку на наш юзербар из поля "Ссылка на Ваш юзербар" и вставляем в подпись на форумах, в блогах и т.д. и т.п. кому на что фантазии хватит. ;)

Форум XternalX Userbars.

пятница, 14 августа 2009 г.

Google Sync, а счастье было так близко, казалось рукой подать...

... ан нет! Оказалось не всё так просто.

Google Sync -- это новый, хотя уже и не особо, сервис от google inc. Идея сервиса заключается в глобальной синхронизации контактов, календарей, почтовых ящиков и т.д. и т.п. на мобильных девайсах с гуглесервисами. На данный момент синхронизируются только контакты и календарь. Синхронизация происходит с помощью протокола Microsoft® Exchange ActiveSync®, поэтому google настоятельно рекомендует для синхронизации использовать спец. софтину Nokia Mail for Exchange. Хотя в интернете мелькают инструкции по настройке синхронизации и без неё (но у меня сей вариант не прошёл).

Скачав и установив на свой Nokia 3250 спец. софтину, я бэкапнул все настройки телефона с помощью Nokia PC Suite и полез в инструкцию по установке Google Sync. Первое и единственное на чём я споткнулся, было поле "Домен", которое по инструкции следовало бы оставить пустым, но mail for exchange категорически отказалась принимать настройки с пустым полем "Домен", пришлось написать там "m.google.com", не знаю на сколько это решение было верно, ибо после первого же запуска, залез в настройки и опустошил это поле, как того требует инструкция. В принципе, установка и настройка потребовали минимум времени и прошли легко и не принуждённо.

Далее, причесав контакты в Gmail аккаунте, я попытался синхронизировать контакты gmail'а и телефона. Залез в "Мои приложения", запустил Mail for Exchange, и начал синхронизацию. Порадовало, что и этот процесс прошел без малейших осложнений. Софтина аккуратно в течении всего процесса синхронизации показывала сколько записей она обновила и где, хотя вполне можно было и не следить за этим, закрыв приложение.

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

Итог. После экспериментов с контактами, пробовать тоже самое и на календаре желание как-то само собой отпало. Удалил с телефона Nokia Mail for Exchange и решил на полгодика-годик забыть о тотальной синхронизации девайсов, а там поглядим...

вторник, 11 августа 2009 г.

Следование стандартам...

Так сложилось, что вот уже несколько месяцев занимаюсь программированием на PHP, пишу свои классы и модули, попутно ковыряя чужие, верстаю и т.д. и т.п. И за всё это время я не видил НИ ОДНОГО продукта (естественно опенсорс) полностью соответствующего стандартам W3C и парадигмам ООП. Интересно, почему разработчики столь наплевательски относятся к стандартам, по сути писавшимся для них, дабы облегчить их нелёгкий труд?

С ООП всё, более или менее, понятно. PHP изначально был процедурным языком и ни о каком ООП в нём речи не шло. Да и сейчас в версии 5.1 часть парадигм ООП не полностью поддерживается или поддерживается с помощью всевозможных "костылей" выдаваемых за преимущества PHP.
Например в PHP нет т.н. акцессоров и мутаторов, точнее они "как бы" есть, предлагается пользоваться следующей конструкцией:
<?php
class MyClass {
private $properties;
function __set($name, $value) {
echo "задание нового свойства $name = $value";
$this->properties[$name]=$value;
}
function __get($name) {
echo "чтение значения свойства ", $name;
return $this->properties[$name];
}
}
$obj = new MyClass;
$obj->property = 1; // Выводит "задание нового свойства property=1"
$a = $obj->property; // Выводит "чтение значения свойства property"
echo $a; // выводит 1;
?>

Таким методом конечно можно обрабатывать изменения свойств объектов, но для того чтобы заставить класс принимать только нужные (запланированные) параметры придётся писать switch и в нём проверять имена указываемых пользователем параметров, что не слишком то удобно.

А вот со стандартами косорциума W3C всё не так просто. По какой то не ведомой мне причине практически все разработчики плюют на эти стандарты и воротят ТАКОЕ, что хватаешься за голову.
Вроде бы HTML все в школе/техникуме/институте изучают, да и W3C на месте не сидит, создавая для разработчиков всякие валидаторы, обнаруживающие ошибки в гипертексте странички и подробно разбирая каждую в соответствии со стандартом. В инете полно русско-язычных (и не только русско) ресурсов с подробным объяснением всех этих стандартов. И тем не менее разработчики продолжают испытывать браузеры на прочность своим бредом в гипертексте и жабаскрипте. Просто ради интереса зайдите вот сюда -> http://validator.w3.org/check?uri=http%3A%2F%2Fwww.lastfm.ru%2F&charset=%28detect+automatically%29&doctype=Inline&group=0&user-agent=W3C_Validator%2F1.654 и обалдейте от количества ошибок и варнингов найденных валидатором в коде странички (страничка подвернулась случайно, просто этот сайт упорно отказывается у меня работать под оперой уже в течении двух его версий).
А вот и тест любимого ВКонтакта -> http://validator.w3.org/check?uri=http%3A%2F%2Fvkontakte.ru&charset=%28detect+automatically%29&doctype=Inline&group=0
Причём заметьте, и тот и другой -- являются коммерческими проектами. Про не коммерческий код я вообще молчу...

SEF Service Map & UTF-8 encoded URLs

SEF Service Map это компонент, перед которым стоит задача создания полной карты сайта.
Кроме того компонент совместим со всеми стандартными расширениями Joomla! (статьи, RSS ленты, ссылки, контакты и т.д.),
SEF Service Map является открытым компонентом - это позволяет интегрировать его с другими компонентами,
такими как галереи, форумы, каталоги и другие, благодаря встроенным механизмам интеграции!

SEF Service Map создает не только карту сайта, но и карту совместимую со стандартом sitemaps.org :
- XML карта (например: для Google)
- TXT карта (например: для Yahoo)

Но эта зараза на отрез отказывается работать совместно с русскоязычными UTF-8 урликами вида: http://some.site/Новости/Новости-сайта/Превеееед-медвед.html
Точнее работать то она с ними работает и даже HTML-карту генерирует валидную, а вот с XML- и TXT- картами проблема. Все красивые русские урлики в них выглядят примерно так: http://some.site/Ð�овоÑ�ти/Ð�овоÑ�ти-Ñ�айта/

Порывшись в коде нашёл проблему. Разработчики при генерации XML- и TXT- карт выполняют перекодировку линка на статью в UTF-8. Вобщем проблема решается таким образом:
  1. Открываем файлик /components/com_sefservicemap/sefservicemap.html.php
  2. Закомменчиваем или удаляем все вхождения строки "$link = utf8_encode($link);" (их 2)
  3. Радуемся жизни... ;)

суббота, 8 августа 2009 г.

Автопрокрутка многострочного Textbox из .NET Framework

Понадобилось сегодня сделать автопрокрутку лога приложения, нашёл для себя два способа реализовать задуманное.
Первый и, пожалуй, самый простой способ:
Устанавливать, например в обработчике события TextChanged, позицию начала выделения текста равной длине текста в textbox'е и, затем, перематывать scrollbar textbox'а до текущей позиции каретки.
private void tbLog_TextChanged(object sender, EventArgs e)
{
this.tbLog.SelectionStart = this.tbLog.TextLength;
this.tbLog.ScrollToCaret();
}

Однако, у этого способа есть один недостаток: при такой перемотке scrollbar'а перемещается каретка ввода текста, что не всегда бывает приемлемо.

Второй способ немного интереснее и лишён вышеописанного недостатка, хотя и немного сложнее:
Посылать textbox'у, например всё в томже обработчике события TextChanged, сообщение WM_VSCROLL.
private const int WM_VSCROLL = 0x115;
private const int SB_BOTTOM = 7;

[DllImport("user32.dll", CharSet=CharSet.Auto)]
private static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);

private void tbLog_TextChanged(object sender, EventArgs e)
{
SendMessage(this.tbLog.Handle, WM_VSCROLL, (IntPtr) SB_BOTTOM, IntPtr.Zero);
}