воскресенье, 2 августа 2009 г.

Richfaces / Trinidad совсемстно с Facelets

Проапргрейдил существующий проект с Java 1.4 до Java 1.5, JSF 1.1 до JSF 1.2, реализацию JSF с Myfaces на Sun RI... и решил использовать в проекте какой-нибудь фреймворк предоставляющий AJAX для JSF. Первым попробовал Richfaces. Но оно как-то нестабильно заработало - то работает, то нет. Потратил два дня пытаясь понять почему, но безрезультатно. Затем попробовал Trinidad.. и с тем же успехом. Фреймворк работал нестабильно. Например, я открывал JSF страницу, и если кликал на AJAX'овую кнопку сразу после загрузки страницы, то все было нормально, запрос шел и обрабатывался, а если спустя пару секунд кликал, то запрос не обрабатывался и нужная часть страницы не обновлялась. Через какое-то время обратил внимание на странное и уже привычное сообщение в логах "INFO: Facelet[/page/blah.xhtml] was modified @ 14:23:24 AM, flushing component applied...". Оказалось, что это и есть причина проблемы. Время в виртуальной машине было на три часа меньше времени на компе на котором я собирал WAR файлы. Соответственно время создания файлов выглядила для websphere'ы на три часа из будущего. И похоже, что странный алгоритм Facelets обнаружения изменений в файлах начал сбоить по этой причине и перечитывать файл сбрасывая при этом дерево компонент! Решил проблему, установив facelets.REFRESH_PERIOD контекстный параметр в web.xml. Теперь оба фреймворка работают нормально. Осталось только определится какой я хочу..

понедельник, 6 июля 2009 г.

Простое DSL на Scala

Недавно я начал использовать Scala для одного из моих домашних хобби проектов. Ранее я слышал, что Scala позволяет писать код таким образом, что он выглядит как DSL встроенный в саму Scala'у. Решил попробовать использовать эту фичу. Мне было необходимо придумать красивое API для шедулинга сообщений актерам (actors). Вот что из этого получилось:

final class TimeSpec[T] (number : Long, action : Long => T) {
def nanoseconds = action (number)
def microseconds = action (number * 1000L)
def miliseconds = action (number * 1000L * 1000L)
def seconds = action (number * 1000L * 1000L * 1000L)
def minutes = action (number * 1000L * 1000L * 1000L * 60L)
def hours = action (number * 1000L * 1000L * 1000L * 60L * 60L)
def days = action (number * 1000L * 1000L * 1000L * 60L * 60L * 24L)
}

final class Trigger (actor : MyActor, payload : Any) {
def in (number : Long) = new TimeSpec[Unit] (number, scheduleIn)
def every (number : Long) = new TimeSpec[Unit] (number, scheduleEvery)

private def scheduleIn (nanos : Long) = Scheduler.inNano (actor, payload, nanos)
private def scheduleEvery (nanos : Long) = Scheduler.everyNano (actor, payload, nanos)
}

final class ActorSchedule (actor : MyActor) {
def payload (payload : Any) = new Trigger (actor, payload)
}

trait MyActor ..... {
protected val schedule = new ActorSchedule (this)
....
}


В результате получил возможность писать вот такой код:

object TestActor extends MyActor {
schedule payload `Hi in 10 nanoseconds

schedule payload `HowAreYou every 5 seconds

schedule payload `Bye in 5 days

def act () = {
case `Hi => println ("Hello!")
case `HowAreYou => println ("I am fine")
case `Bye => println ("Bye-bye")
}
}

Идея в том, что schedule - это объект класса ActorSchedule. Этот класс предоставляет один метод payload имеющий один аргумент (собственно то, что будет послано актеру). В действительности "schedule payload `Hi" это вызов "schedule.payload(`Hi)". Этот вызов создаст объект класса Trigger. У класса Trigger есть два публичных метода in(Long) и every(Long). Так как эти методы не могут ничего полезного сделать до тех пор пока не будет известна единица измерения времени, то эти методы создают объекты TimeSpec передавая им в качестве параметра собственный метод, который будет вызван с количеством наносекнуд одним из методов класса TimeSpec.

Как мне кажется получился достаточно простой и удобный API без особых усилий.

воскресенье, 22 марта 2009 г.

CeBootLin - автозагрузка Linux/Android из WinCE на Loox 5XX (560/550)

Написал "bootloader" для загрузки Linux/Android из WinCE автоматически при включении КПК. Это не настоящий bootloader, так как он не имеет ничего общего с загрузочными секторами, это просто WinCE приложение, которое начинает свою работу как можно раньше, чтобы загрузить Linux. Я сделал это именно так, а не иначе, из-за того, что не хотел убить свою КПК изменением бут секторов или иметь сложный механизм перепрошивок, обновлений и т.д. Автозагрузка из WinCE мне показалась досточно неплохим решением, имеющим разве что 3-4 секундный проиграш, если сравнивать с нормальным bootloader'ом, который еще помучиться реализовать надо. Также, такая рализация позволяет достаточно легко пропустить загрузку Linux и продолжить загрузку WM5 или WM6.. Код основан на утилите Haret (спасибо им), но я удалил ненужные мне части. Так как загрузчик использует аппаратные регистры для работы с клавиатурой и подсветкой (GPIO/CPLD) Fujitsu Siemens Loox N560/C550, то без изменений кода данный загрузчик не заработает на другой модели КПК...
Когда КПК включается и начинается загрузка WinCE, то ядро WinCE читает список приложений из HKEY_LOCAL_MACHINE\init и запускает их. Таким способом загружается CeBootLin. CeBootLin начинает мигать подсветкой клавиатуры и ждет одну секунду. В то время, пока клавиатура подмигивает, пользователь может нажать и отпустить какую-нибудь кнопку КПК - это сигнал для CeBootLin не продолжать загрузку Linux. Если никакие кнопки нажаты не были, то CeBootLin попытается открыть \CeBootLin\default.txt и будет использовать его в качестве скрипта Haret для загрузки Linux'а.

Итого, чтобы поставить и настроить CeBootLin, надо проделать такие шаги:
1. Скачать CeBootLin.
2. Распаковать содержимое архива в корень основной памяти КПК. CeBootLin.exe должен быть доступен по пути \CeBootLin\CeBootLin.exe.
3. Поместить default.txt в каталог \CeBootLin. Файл default txt может например выглядеть так (для загрузки Andorid'а, например):

set MTYPE 1454
set KERNEL "\CeBootLin\zImage"
set CMDLINE "root=179:3 mem=62M rootdelay=3 boot_delay=0 init=/init console=tty0 fbcon=rotate:0 androidboot.console=tty0 android.checkjni=1"
set RAMADDR 0xA0200000
bootlinux

4. Поместить zImage в каталог \CeBootLin\.

5. Добавить в HKEY_LOCAL_MACHINE\init значение для Launch82 ="CeBootLin.exe" и Depend82 = 14 00.


6. Добавить в HKEY_LOCAL_MACHINE\Loader\SystemPath путь \CeBootLin\

7. Подождать 5 минут или типа того (WinCE нужно время, прежде чем она сохранит обновление в registry).
8. Перезагрузить КПК

Если возникнут какие-то проблемы, то первым делом стоит проверить, а грузит ли CeBootLin.exe вообще ядро... для этого достаточно просто его запустить.

В дальнейшем при желании можно сделать нормальный cab с setup'ом внутри, который, например, будет ставить андройд..

Здесь находятся исходные коды CeBootLinux. CeBootLinux лицензирован под GNU GPL.

воскресенье, 15 марта 2009 г.

Фотографии Android и Linux на Fujitsu-Siemens Loox N560


Сегодня судьба WM5 - загрузить Linux


Haret.. все что нужно - нажать Run


Android на Loox N560


Установка Debian'а на Loox N560


Установка Debian'а на Loox N560

Тестирование памяти на Loox N560/C550

Недавно набросал "утилиту" для тестирования памяти на Fujitsu-Siemens Loox N560/C550. Нужна она тем, кто перепаевает память (с 64М на 128М) и хочет проверить ее работоспособность "на месте" без переустановки WM5. Итак, для того, чтобы протестировать память КПК:
1. Качаем LooxMem128-v0.zip (чтобы тестировать 128Мб памяти) или LooxMem64-v0.zip (чтобы тестировать 64Мб памяти).
2. Заливаем распакованный архив на SD карточку.
3. Карточку вставляем в Loox и перегружаем КПК.
4. Не давая КПК заснуть, запускаем haret.exe из архива, что распаковывали на SD карточку.
5. После запуска haret.exe нужно нажать на Run.
6. Загрузится linux и появится предупреждение.
7. Читаем предупреждение и либо нажимаем на RESET (на попе у КПК) либо нажимаем enter..
ВНИМАНИЕ: Накачественная память при тестировании может сгореть (собственно "утилита" для этого и нужна, чтобы выявлять такую память). Ни я, ни авторы memtester ни кто иной кроме вас никакой ответственности за это нести не будет. Вы тестируете память на свой страх и риск!!

Замечание: При тестировании необходимо раз в 3-5 минут нажимать какую-нибудь кнопку КПК, чтобы КПК не заснула...
(Для портирования "утилиты" на другую платформу достаточно заменить ядро zImage и поправить default.txt.)

суббота, 14 марта 2009 г.

Ядро linux для Loox N560/C550 с рабочим CPLD и светодиодами

Добавил поддержку CPLD и светодиодов. Для CPLD был заюзан драйвер htc-gpio с перечислением адресов регистров CPLD на Fujitsu-Siemens Loox 5XX (N560/C550). Теперь CPLD доступен для других драйверов.

Примечательно, как в Linux'е реализована работа с CPLD. По сути, CPLD это чип, содержащий очень простую логику (за счет чего он очень быстр по сравнению с CPU), имеющий входные и выходные "ножки" (pins). Входные и выходные ножки - регистры - проецируются на определенную область памяти CPU. С логической точки зрения работа с CPLD заключается в переключении битов в регистрах CPLD в 0 или 1 (можно еще и читать оттуда, но я об этом тут не буду рассказывать..). Таким же образом выглядит работа с GPIO - общим вводом/выводом CPU: биты регистров CPU таким же образом принимают значение 0 или 1. В ядре Linux уже имеется драйвер GPIO, предоставляющий функции для работы с GPIO разработчикам платформенных драйверов. Также драйвер GPIO имеет механизм расширения, позволяющий другим драйверам/модулям проецировать заданные интервалы портов GPIO таким образом, что при обращении к такому порту произойдет вызов указанных при проецировании функций. Этот механизм используется CPLD драйвером htc-egpio для проецирования CPLD регистров на GPIO порты. Таким образом работа с CPLD идет через обыкновенные методы типа gpio_set_value.
На основе работающиго CPLD драйвера для Loox N560/C550 реализовал драйвер управления светодиодами КПК. Драйвер экспортирует методы и константы которые другие драйвера (wifi, gps, bluetooth, pm, ...) должны использовать для управления светодиодами. Также драйвер позволяет контролировать светодиоды из userspace пространства путем манипуляций с файлами sysfs.

Ниже перечисленны файлы и значения которые могут находиться:
/sys/devices/platform/loox5xx-leds.1/keyboard: on, off, any
- подсветка клавиатуры

/sys/devices/platform/loox5xx-leds.1/left_green: on, off, any
- зеленый светодиод с левой стороны. WM5 использует для индикации активности WiFi

/sys/devices/platform/loox5xx-leds.1/left_blue: on, off, any
- голубой светодиод с левой стороны. WM5 использует для индикации активности Bluetooth

/sys/devices/platform/loox5xx-leds.1/left_orange: on, off, any
- оранжевый светодиод с левой стороны. WM5 использует для индикации активности GPS на Loox N560

/sys/devices/platform/loox5xx-leds.1/right_green: on, off, any
- зеленый светодиод на правой стороне КПК. WM5 использует как светодиод доступный приложениям (нотификации и т.д.)

/sys/devices/platform/loox5xx-leds.1/right_orange: on, off, blink, any
- оранжевый светодиод с правой стороны КПК. WM5 использует для индикации процесса зарядки

Где:
on - светодиод включен независимо от желаний ядра,
off - светодиод выключен независимо от желаний ядра,
blink - светодиод мигает независимо от желаний ядра,
any - светодиод контролируется ядром.

Например, если установить right_orange в состояние on, то светодиод зарядки будет гореть независимо от того, заряжается КПК или нет. Это будет продолжаться до тех пор, пока в файл right_orange не будет записано значение any. После чего, первое же событие (установка КПК в крэдл и т.д.) переключит светодиод в соответствующее состояние. Sysfs интерфейс для светодиодов позволяет использовать светодиоды из программ для нотификации о событиях (пришла почта, кончается заряд и т.д.) с помощью всех доступных на устройстве светодиодов - насколько хватит фантазии. Например следующий shell код мигает подсветкой клавиатуры:

while true;
do echo on > /sys/devices/platform/loox5xx-leds.1/keyboard;
sleep 0.1;
echo off > /sys/devices/platform/loox5xx-leds.1/keyboard;
sleep 0.1;
# Condition for break...
done
echo any > /sys/devices/platform/loox5xx-leds.1/keyboard;


Актуальный патч на cupcake ядро андройда качать здесь.

вторник, 10 марта 2009 г.

Полезные команды для межплатформенной работы

Несмотря на то, что debian/emdebian уже содержат громадное количество пакетов под armel, иногда нужно собрать или пересобрать что-то из исходников.

Сборка пакетов в emdebian происходит например так:
emsource --arch armel -b memtester

Установка собранного пакета НЕ на целевом устройстве, а на хостовом, выполняется например вот так:

dpkg-cross -a armel -i zlib1g-dev_1.2.3.3.dfsg-13em1_armel.deb
При этом команда dpkg -l | grep zlib1g выдаст:

ii zlib1g-dev-armel-cross 1:1.2.3.3.dfsg-13em1

(dpkg-cross автоматически переназвала установленный пакет и разместила его содержимое в /usr/arm-linux-gnueabi)

Чтобы пользоваться командой emsource без привелегий root'а, надо настроить ~/.apt-cross/emsource например вот так:

workingdir: /home/akshaal/.apt-cross-working-dir

Сборка пакета под armel из исходников, которые уже развернуты и имеют каталог debian производится командой:

dpkg-buildpackage -aarmel

понедельник, 9 марта 2009 г.

Установка emdebian на PDA (C550/N560)

Последовательность действий, выполнив которую я без проблем установил debian на свой Fujitsu-Siemens Loox N560. Я предполагаю, что emdebian-tools уже установлен, а также стоят всякие кросскомпиляторы под arm платформу.

Первым делом необходимо собрать архив базовой системой:
cd /tmp;
mkdir grip/
sudo debootstrap --arch=arm --foreign lenny grip/ http://www.emdebian.org/grip/
cd grip/
sudo tar -czf /tmp/emdebian-grip-arm-debootstrap.tgz .
Теперь необходимо переразбить SD карточку выделив на ней раздел под linux:

cfdisk /dev/sdX
mkfs.ext3 /dev/sdXy

где sdX - это устройство с SD картой, а sdXy это раздел который предполагается использовать под linux. Теперь монтируем раздел и разворачиваем туда emdebian-grip-arm-debootstrap.tgz:

mount /dev/sdXy /mnt
cd /mnt
tar zxpvf /tmp/emdebian-grip-arm-debootstrap.tgz
ln -s bin/sh init
cd /tmp
umount /mnt

Теперь, когда раздел подготовлен, загружаем с него linux и выполняем следующие команды:
cd /debootstrap
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
run ./debootstrap --second-stage
dpkg --configure -a
rm /init
cd /
ln -s sbin/init init
Теперь перегружаем linux еще раз. В этот раз должно появится приглашение залогинится. Используем root без пароля. И конфигурируем основные настройки:

echo 'nameserver 1.1.1.1' > /etc/resolv.conf
echo '127.0.0.1 localhost' > /etc/hosts
echo '172.16.0.2 myhost 172.16.0.2' >> /etc/hosts
echo 'myhost' > /etc/hostname

Вместо 1.1.1.1 нужно использовать IP DNS сервера. И снова перегружаем КПК. Теперь конфигурирем сеть:

ifconfig usb0 172.16.0.1 netmask 255.255.255.0
route add default gw 172.16.0.1
Убеждаемся, что сеть работает. Апгрейдим пакеты:

echo 'deb http://www.emdebian.org/grip/ sid main' > /etc/apt/sources.list
echo 'deb http://ftp.debian.org/debian/ sid main contrib non-free' >> /etc/apt/sources.list
apt-get update
apt-get dist-upgrade
apt-get install ...что угодно...

И теперь настраеваем сеть так как это положено (собственно это можно было зделать и раньше, но тут можно уже залогинится через ssh и нормально все сделать с помощью copy&paste с ББ...):
cat > /etc/network/interfaces
auto lo
iface lo inet loopback
allow-hotplug usb0
iface usb0 inet static
address 172.16.0.2
netmask 255.255.255.0
network 127.16.0.0
broadcast 172.16.0.255
gateway 172.16.0.1
dns-nameservers 1.1.1.1
dns-search your.domain

суббота, 7 марта 2009 г.

Ядро linux для Loox N560/C550 с рабочим usbnet'ом

После 3х дней мучений все-таки собрал ядро linux для Fujitsu-Siemens Loox N560/C550. Ядро брал с http://www.asm32.ru. Потратив еще несколько часов разобрался как запустить usbnet (сеть через обычный usb шнурок). Для этого пришлось дополнительно пропатчить pxa27x_udc.c. Сделал diff между текущей версией ядра андройда и теми исходниками (за 02-03-09), что выложены на asm32. В дальнейшем при обновлении ядра в cupcake'овской ветке можно будет просто накладывать этот патч сверху имея в результате и изменения под c550/n560 и исправления/дополнения внесенные в cupcake ветку. Вот итоговый патч в который также включены изменения для работы usbnet. В патче уже имеется .config, но там не включена поддержка usbnet. Вот другой config, он отличается от того, что в патче (а там тот, что выложен на asm32) поддержкой usbnet, выключенной power management (зачем не знаю, потом надо будет включить обратно), и настройкой для более крупного шрифта в консоли.. может еще чем-то.

Собирать ядро можно с помощью любого toolchain'а. Я пробовал собирать с помощью: crosstool-ng, emdebian, а также того, что идет вместе с ядром андройда. Остановился на emdebian'е. Для сборки ядра emdebian'ом необходимо выполнить:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi-
Предварительно emdebian конечно же нужно установить, например так:

apt-get install emdebian-tool
emsetup --arch arm
Добавить:

deb http://www.emdebian.org/debian/ unstable main

в /etc/apt/sources.list и выполнить:
apt-get install linux-kernel-headers-arm-cross gcc-4.2-arm-linux-gnu


Готовое ядро запускается haret'ом с конфигом:

set MTYPE 1454
set KERNEL zImage
set CMDLINE "root=179:2 mem=60M rootdelay=3 boot_delay=0 init=/init console=tty0 fbcon=rotate:0 androidboot.console=tty0 android.checkjni=1"
set RAMADDR 0xA0200000
bootlinux

И самое главное! После того, как ядро закинуто на sd карточку, эту sd карточку нужно вставить в КПК и ребутнуть КПК. А уже только после этого грузить haret'ом ядро! Ибо ядро не грузится (либо грузится с вероятностью 10%), если:
1. КПК заснула, а потом ее разбудили.
2. Вы только что вставили в КПК карточку.
Наверное это бага драйвера wince...

P.S. Cupcake на который накладывается выложенный патч качается отсюда http://source.android.com/download

P.P.S. При сборке с поддержкой usbnet опцию CONFIG_USB_ETH_RNDIS
включать не следует! Ибо в этом случае ПК не может нормально соеденится с КПК.. ни cdc_ether ни cdc_subset не видят usb устройство.

пятница, 6 марта 2009 г.

Related Posts / Похожие темы

Написал расширение (widget) для тем blogger'а. Расширение отображает список постов похожих по меткам. Данное расширение отличается от всех прочих Related Posts Widget'ов тем, что очень легковесно и не замедляет загрузку страницы браузером, так как выполняет дополнительные запросы к серверу параллельно (асинхронно) с загрузкой страницы. Более того, записи сортируются не только с учетом даты написания постов, но и с учетом релевантности (по меткам). Так как у меня несколько блогов и мне не хочется заниматься рутиной, то я постарался написать виджет как можно более простым для установки.

Итак, чтобы установить это расширение в своем блоге, необходимо произвести две довольно простые модификации HTML шаблона (HTML Template'а). Для этого нужно открыть Настройки (Settings) -> Макет (Layout) -> Изменить HTML. Перед тем как менять что-то далее, сделайте резервную копию шаблона (Загрузить весь шаблон)! После чего нужно пометить галочкой Расширить шаблоны виджета (Expend Widget Templates). После чего можно приступать к редактированию:
1. В поле с текстом шаблона нужно найти строку <data:post.body/>. И вот сразу за этой строкой нужно аккуратно вставить следующий код:
<div caption='Похожие темы:' id='akRelatedPosts' max='8'/>
<b:if cond='data:blog.pageType == &quot;item&quot;'>
<script language='javascript' type='text/javascript'>
(function(_1,_2){var _3={};var _4=_2.length;var _5=function(_6){var _7=&quot;([0-9]{4})(-([0-9]{2})(-([0-9]{2})(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(.([0-9]+))?)?(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?&quot;;var d=_6.match(new RegExp(_7));var _9=0;var _a=new Date(d[1],0,1);if(d[3]){_a.setMonth(d[3]-1)}if(d[5]){_a.setDate(d[5])}if(d[7]){_a.setHours(d[7])}if(d[8]){_a.setMinutes(d[8])}if(d[10]){_a.setSeconds(d[10])}if(d[12]){_a.setMilliseconds(Number(&quot;0.&quot;+d[12])*1000)}if(d[14]){_9=(Number(d[16])*60)+Number(d[17]);_9*=((d[15]==&quot;-&quot;)?1:-1)}_9-=_a.getTimezoneOffset();time=(Number(_a)+(_9*60*1000));return Number(time)};var _b=function(){var _c=[];for(var i in _3){_c.push(_3[i])}if(_c.length&lt;1){return}var _e=document.getElementById(&quot;akRelatedPosts&quot;);if(!_e){return}var _f=_e.getAttribute(&quot;max&quot;)||5;_c=_c.sort(function(a,b){var _12=b.weight-a.weight;if(_12!=0){return _12}return b.date-a.date});var s=&quot;&lt;ul&gt;&quot;;for(var i in _c){if(_f--&lt;1){break}var _14=_c[i];s+=&quot;&lt;li&gt;&lt;a href=&#39;&quot;+_14.href+&quot;&#39;&gt;&quot;+_14.title+&quot;&lt;/a&gt;&lt;/li&gt;&quot;}s+=&quot;&lt;/ul&gt;&quot;;var _15=_e.getAttribute(&quot;caption&quot;);s=&quot;&lt;span class=&#39;caption&#39;&gt;&quot;+_15+&quot;&lt;/span&gt;&quot;+s;_e.innerHTML=s};var _16=function(_17){for(var i in _17.feed.entry){var _19=_17.feed.entry[i];var _1a=_19.id[&quot;$t&quot;];var _1b=_3[_1a];if(_1b){_1b.weight++}else{var _1c;for(var _1d in _19.link){if(_19.link[_1d].rel==&quot;alternate&quot;){_1c=_19.link[_1d].href;break}}if(_1c==_1){continue}_1b={weight:1,title:_19.title[&quot;$t&quot;],date:_5(_19.published[&quot;$t&quot;]),href:_1c};_3[_1a]=_1b}}if(--_4==0){_b()}};var _1e=function(_1f){var _20;try{_20=new XMLHttpRequest()}catch(excp1){try{_20=new ActiveXObject(&quot;Msxml2.XMLHTTP&quot;)}catch(excp2){try{_20=new ActiveXObject(&quot;Microsoft.XMLHTTP&quot;)}catch(excp3){_20=false}}}var _21=function(){if(_20.readyState==4){if(_20.status==200){_16(eval(&quot;(&quot;+_20.responseText+&quot;)&quot;))}}};_20.open(&quot;GET&quot;,_1f,true);_20.onreadystatechange=_21;_20.send(null)};for(var _22 in _2){_1e(_2[_22])}} <!-- = = = = = endoffunc = = = = = = -->
)(&quot;<data:blog.url/>&quot;,[
<b:loop values='data:post.labels' var='label'>
&quot;/feeds/posts/default/-/<data:label.name/>?alt=json&amp;max-results=5&quot;<b:if cond='data:label.isLast != &quot;true&quot;'>,</b:if>
</b:loop>
]);
</script>
</b:if>
Должно получиться что-то типа вот этого (на картинку можно нажать и нормально рассмотреть):
Обратите внимание на caption='...' и max='8' Значения в кавычках можно изменить. Значение для caption определяет текст, который будет высвечиватся над списком похожих постов. Значение max определяет максимальное количество элементов в списке.
2. Это изменение вобщем-то и не обязательно, все должно заработать и без него. Но выглядеть оно будет не очень. Поэтому, этим шагом производится настройка внешнего вида. Для этого необходимо найти строку ]]></b:skin>. И перед(!) этой строкой вставить вот такой кусок настроек:
#akRelatedPosts {
padding-top: 20px;
}

#akRelatedPosts .caption {
font-weight: bold;
}

#akRelatedPosts ul {
margin: 0;
}
Если есть желание и знание css, то можно тут подкрутить стили как душе угодно. Должно получиться как-то вот так:
Это все. Можно сохранять шаблон и пробовать.

четверг, 5 марта 2009 г.

Локальное тестирование AJAX запросов

Иногда бывает очень удобно отлаживать javascript сценарии без заливки на сервер, а просто путем запуска из локально html файла. Но таким образом не получается протестировать скрипты делающие асинхронные запросы. Связано это с тем, что firefox не дает выполнять запрос, если домен в запросе не соответствует домену с которого этот запрос выполняется - делается это из соображений безопасности.
uncaught exception: Access to restricted URI denied (NS_ERROR_DOM_BAD_URI)
Но если вы отдаете себе отчет в том что делаете, то никто не мешает отключить эту проверку. Для этого нужно открыть about:config и установить signed.applets.codebase_principal_support в true. Также перед выполнением запроса в javascript'е, необходимо выполнить следующий код:
netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");

Самое главное, по окончанию тестирования не забыть удалить эту строку из скрипта и установить signed.applets.codebase_principal_support в false!!

воскресенье, 22 февраля 2009 г.

Google Blogger после Livejournal

После 5 лет жизни в ЖЖ, переехал в Blogspot. Итак впечатление следующие:
1. Практически полная свобода творчества по оформлению блога. В ЖЖ огромное множество ограничений (на бесплатных аккаунтах).
2. Интеграция с сервисами Google решает. Очень удобно размещать фотографии в Google Picasa. Наблюдать статистику в Google Webtools и смотреть посещаемость в Google Analytics. А при желании можно добавить Google AdSense. На все про все один аккаунт от google.
3. Нет lj-cut. При желании это решается, но мне не особо и нужно.
4. С одного аккаунта можно вести множество блогов. В ЖЖ для этого надо было перелогиниваться. В блоггере отношение между журналами и авторами - многие ко многим. Тоесть один журнал может вести множество авторов и каждый автор может вести множество журналов.
5. Индивидуальность.

Основные заблуждения про Google Sites

Почитав форумы и попробовав Google Sites вживую, становится понятно, что основными заблуждениями являются:
1. Google Sites не поддерживают домены пользователя. Это не так. В Google Sites можно замэппить любую часть сайта на любой доступный домен.
2. Google Sites позволяет создавать сайт наполняя его любым легальным контентом. Это не так. Нужно быть осторожным, так как например размещение AdSense блоков запрещено соглашением. И при нарушении данного соглашения, ваш сайт будет удален.

суббота, 21 февраля 2009 г.

Google Blogger & AdSense

Blogspot имеет встроенные механизмы для размещения контекстной рекламмы AdSense. Но по ряду причин встроенный механизм мне не подошел (например, он не дает возможность прицепить каналы для мониторинга активности того или иного блока). С другой стороны, Google Blogger позволяет редактировать HTML Template блога и вставлять туда произвольный код в том числе и любой Javascript. Этим грех не воспользоваться для размещения AdSense кода, сгенерированного в панели управления Google Adsense. Казалось бы все просто, но я потерял 3 часа пытаясь понять, почему код блока, сгенерированный в Google Adsense и вставленный в окне HTML Template, не работает. Вместо рекламы или хотя бы социальной рекламы я наблюдал пустое пространство совсем даже не того размера, который задавал. Разбор полетов, в том числе с помощью firebug'а показал, что на запрос к http://googleads.g.doubleclick.net, гугл возвращал код 400 Bad Request. Почему это запрос плохой - adsense сервер сообщить не потрудился. Дальнейшее сравнение видов запроса с работающего блока и запроса с неработающего блока показало, что неработающий блок в запросе не сообщает идентификатор клиента и прочую информацию такого рода. Подозрение пало на джаваскрипт, в котором эти параметры определяются. Код, который генерирует AdSense выглядит примерно так:
<script type="text/javascript"><!--
[... код в стиле var бла=бла-бла-бла; ...]
//-->
</script>

На первый взгляд, все выглядит правильно. Но подозрение закралось на <!-- и //-->. Убрал эти элементы, которые по идее должны помогать браузерам, не поддерживающим джаваскрипт. И о чудо! Блок заработал. Но гугл говорит, что их код править нельзя. Тут у меня закралось еще одно подозрение и в окошке HTML Template гугловский код я записал вот так:
<script type="text/javascript">&lt;!--
[... код в стиле var бла=бла-бла-бла; ...]
//--&gt;
</script>

Это и оказалось правильным решением проблемы.

Вероятное обьяснение: судя повсему, сначало парсер Blogspot'а разбирает template, а потом его форматирует обратно в HTML. При этом переводы строк внутри комментариев <!-- --> он не сохраняет, а рендерит одной строкой в HTML. В результате весь java код выкусывает парсером браузера.

среда, 4 февраля 2009 г.

Microsoft Windows Environment

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

1. Установить http://virtuawin.sourceforge.net/ и назначить переключение рабочих столов на Win-0 ... Win-9 - как общие столы.
Win-C для стола с Eclipse.
Win-I для всяких чатов.

2. Установить http://www.skynergy.com/hotkeyz.html
Назначить Win-z для запуска rxtv с zsh
Назначить Ctrl-Shift-f12 на закрытие окна
Win-Enter - maximize window
Shift-Win-Enter - restore window

3. Установить http://www.cygwin.com/ с пакетами python, perl, zsh, diff, patch, make, mc и еще кучей ползеных программ и утилит.

4. Если вдруг оказалось, что cygwin считает домашней директорией сетевой диск и из-за этого тормозит, то незабыть поменять home директорию в /etc/passwd

5. В /etc/passwd прописать /usr/bin/zsh А в домашнюю директорию положить .zshrc следующего содержания:

alias ls='ls --color'
alias ll='ls -l --color'
alias dfh='df -h'
alias duh='du -h'
alias rm="rm -i"
alias mc="mc -a"

alias c="cd /cygdrive/c"

alias cdp='cd /cygdrive/c/projects/'

export INPUTRC=$HOME/.inputrc

export HISTSIZE=80000
export HISTFILE=~/.history
export SAVEHIST=80000

setopt hist_ignore_dups append_history bsd_echo multios
setopt hist_ignore_all_dups
setopt SHARE_HISTORY

prompt=`echo -ne "%{\033[31m%}%n@%M:%B%30<..<%~%#%b "`

export EDITOR=vim

unsetopt beep

# ##########################################################################3
# -+--+-+ --+-+-

bindkey "\e[1~" beginning-of-line
bindkey '\eOH' beginning-of-line
bindkey "\e[2~" end-of-history
bindkey "\e[3~" delete-char
bindkey "\e[4~" end-of-line
bindkey "\eOF" end-of-line
bindkey "\e[5~" history-incremental-search-backward
bindkey "\e[6~" history-incremental-search-forward
bindkey "\e[A" history-beginning-search-backward
bindkey "\e[B" history-beginning-search-forward
bindkey "\e[C" forward-char
bindkey "\e[D" backward-char
bindkey "\e[7~" beginning-of-line
bindkey "\e[8~" end-of-line
bindkey "\e[3~" backward-delete-char
bindkey "\e[3~" delete-char


# ###########################################################################
chpwd precmd () {
laststatus=$?
[[ $laststatus != 0 ]] && print "\033[1,33m**** \033[1,31mExit code: $laststatus\n"

[[ -t 1 ]] || return
case $TERM in
*xterm*|*rxvt*|*(dt|k|E)term*) print -Pn "\e]2;%n@%M:%15<..<%~%<<\a"
;;
esac
}

preexec () {
[[ -t 1 ]] || return
case $TERM in
*xterm*|*rxvt*|*(dt|k|E)term*) print -Pn "\e]2;%n@%M:%15<..<%~%<< (%15>..>$1%>>)\a"
;;
esac
}

chpwd

# The following lines were added by compinstall

zstyle ':completion:*' completer _expand _complete
zstyle ':completion:*' expand prefix suffix

autoload -Uz compinit
compinit -u
# End of lines added by compinstall

6. В c:/cygwin положить файлик rxvt.bat:
@echo off

C:
chdir C:\cygwin\bin

set CYGWIN=codepage:oem tty binmode title
set TERM=cygwin
rxvt -geometry 90x30 -bg black -fg white -sr -sl 5000 -fn 10x20 -e c:/cygwin/bin/zsh --login -i