29 января 2010 г.
13 января 2010 г.
Цитаты Бердяева под настроение
1. Нет ничего более злого, чем стремление осуществить во что бы то ни было благо.
2. В институте брака есть бесстыдство обнаружения для общества того, что должно было бы быть скрыто, охранено от посторонних взоров.
3. У женщин есть необыкновенная способность порождать иллюзии, не быть такими, каковы они на самом деле.
4. Любовь всегда нелегальна. Легальная любовь есть любовь умершая. Легальность существует лишь для обыденности, любовь же выходит из обыденности.
5. Творчество - победа над похотью жизни.
6. Творчество - переход небытия в бытие через акт свободы.
7. Ад нужен не для того, чтобы злые получили воздаяние, а для того, чтобы человек не был изнасилован добром и принудительно внедрен в рай.
8. В любви есть деспотизм и рабство. И наиболее деспотична любовь женская, требующая себе всего!
9. Ревность не соединена со свободой человека. В ревности есть инстинкт собственности и господства, но в состоянии унижения. Нужно признавать право любви и отрицать право ревности, перестав ее идеализировать... Ревность есть тирания человека над человеком. Особенно отвратительна женская ревность, превращая женщину в фурию.
(с) Николай Александрович Бердяев
2. В институте брака есть бесстыдство обнаружения для общества того, что должно было бы быть скрыто, охранено от посторонних взоров.
3. У женщин есть необыкновенная способность порождать иллюзии, не быть такими, каковы они на самом деле.
4. Любовь всегда нелегальна. Легальная любовь есть любовь умершая. Легальность существует лишь для обыденности, любовь же выходит из обыденности.
5. Творчество - победа над похотью жизни.
6. Творчество - переход небытия в бытие через акт свободы.
7. Ад нужен не для того, чтобы злые получили воздаяние, а для того, чтобы человек не был изнасилован добром и принудительно внедрен в рай.
8. В любви есть деспотизм и рабство. И наиболее деспотична любовь женская, требующая себе всего!
9. Ревность не соединена со свободой человека. В ревности есть инстинкт собственности и господства, но в состоянии унижения. Нужно признавать право любви и отрицать право ревности, перестав ее идеализировать... Ревность есть тирания человека над человеком. Особенно отвратительна женская ревность, превращая женщину в фурию.
(с) Николай Александрович Бердяев
Любовь живет три года
Любовь - это битва. Заранее проигранная.
Сначала все прекрасно, даже вы сами. Вы только диву даетесь, что можно быть таким влюбленным. Каждый день приносит новую порцию чудес. Никому на Земле никогда еще не было так хорошо. Счастье есть, оно проще простого: это чье-то лицо. Весь мир улыбается. Целый год ваша жизнь - одно сплошное солнечное утро, даже в сумерки и когда идет снег. Вы пишете об этом книги. Торопитесь жениться - чего тянуть, если вы так счастливы? Думать не хочется, от этого грустно; пусть жизнь сама решит за вас.
На второй год кое-что меняется. Вы стали нежнее. Гордитесь тем, как хорошо вы с вашей половиной притерлись друг к другу. Вы понимаете жену "с полуслова"; как здорово быть единым целым. Супругу принимают на улице за вашу сестру - вам это льстит, но и на психику действует. Вы занимаетесь любовью все реже и думаете: ничего страшного. Самонадеянно полагаете, что эта самая любовь крепнет с каждым днем, когда конец света уже не за горами. Вы выступаете в защиту брака перед приятелями-холостяками - те вас не узнают. А вы-то сами уверены, что узнаете себя, когда талдычите заученный урок, изо всех сил стараясь не смотреть на свеженьких девочек, от которых светлее на улице.
На третий год вы уже не стараетесь не смотреть на свеженьких девочек, от которых светлее на улице. Вы больше не разговариваете с женой. Проводите с ней долгие часы в ресторане, слушая, что лопочут соседи по столу. Вы с ней все чаще бываете вне дома: это повод, чтобы не трахаться. А вскоре наступает момент, когда вы не можете больше выносить свою половину ни секунды лишней, потому что влюбились в другую. Только в одном вы не ошиблись: последнее слово действительно всегда остается за жизнью. На третий год у вас две новости - хорошая и плохая. Хорошая новость: вашей жене все обрыдло и она от вас уходит. Плохая новость: вы начинаете новую книгу.
(c) Фредерик Бегбедер. "Любовь живет три года"
SmartGwt. Первые проблемы (ListGrid)
Неприятно, когда в самом начале работы с фреймворком начинаются небольшие косяки. Сразу появляется желание перейти на что-либо еще. А проблема вот в чем:
Есть код:
и набор:
Eclipse + GWT Plugin, Smart GWT 2.0, Google Chrome 4.0.288.1 dev (and previous).
В debug режиме он отрабатывает нормально, но после компиляции ListGrid не отображает строки в Хроме (отображает только одну пустую строку), в остальных браузерах нормально (IE 7, Last Firefox, Opera 10), но так как я пользуюсь хромом - сразу наткнулся на данный баг.
Тему на форуме поддержки создал, посмотрим, что подскажут разработчики.
Update. Ничего не подсказали, но я нашел проблему. Она в функции convertToRecordArray.
Точнее в условии "if (JSOHelper.isArray(nativeArray))".
public static native boolean isArray(JavaScriptObject jsObj)/*-{
return $wnd.isA.Array(jsObj);
}-*/;
В hosted mode функция возвращает true, а после компиляции в браузерах с webkit возвращает false в моем случае.
Даже не знаю почему это происходит, не хочу лезть в дебри, это занимает много времени, может напишут разработчики.
Update2. Посоветовали писать тесты. Ну хоть на этом спасибо :)
Есть код:
ListGrid catsGrid = new ListGrid();
catsGrid.setEmptyMessage("Load...");
catsGrid.setWidth("30%");
ListGridField nameField = new ListGridField("name", "Category");
catsGrid.setFields(new ListGridField[] {nameField});
String result="{\"error\": null, \"id\": 1, \"result\": [{\"name\": \"\u0420\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e\u0442\"}, {\"name\": \"\u0418\u0441\u0442\u043e\u0440\u0438\u044f \u043e\u0446\u0435\u043d\u043e\u043a\"}]}";
JSONValue value = JSONParser.parse(result).isObject().get("result");
JSONArray catsAry = value.isArray();
JavaScriptObject jsObj = catsAry.getJavaScriptObject();
Record[] recs = Record.convertToRecordArray(jsObj);
catsGrid.setData(recs);
catsGrid.draw();
и набор:
Eclipse + GWT Plugin, Smart GWT 2.0, Google Chrome 4.0.288.1 dev (and previous).
В debug режиме он отрабатывает нормально, но после компиляции ListGrid не отображает строки в Хроме (отображает только одну пустую строку), в остальных браузерах нормально (IE 7, Last Firefox, Opera 10), но так как я пользуюсь хромом - сразу наткнулся на данный баг.
Тему на форуме поддержки создал, посмотрим, что подскажут разработчики.
Update. Ничего не подсказали, но я нашел проблему. Она в функции convertToRecordArray.
Точнее в условии "if (JSOHelper.isArray(nativeArray))".
public static native boolean isArray(JavaScriptObject jsObj)/*-{
return $wnd.isA.Array(jsObj);
}-*/;
В hosted mode функция возвращает true, а после компиляции в браузерах с webkit возвращает false в моем случае.
Даже не знаю почему это происходит, не хочу лезть в дебри, это занимает много времени, может напишут разработчики.
Update2. Посоветовали писать тесты. Ну хоть на этом спасибо :)
Ярлыки:
SmartGWT
27 декабря 2009 г.
GWT. Взаимодействие с Django
Вся работа в GWT имеет подробную документацию. В ней все понятно и прозрачно. Но наше дело тормозится тем, что в качестве бекенда у нас выступает Django. То есть стандартный GWT RPC нам не подходит. Встает вопрос о том, как обмениваться данными между GWT и Django.
Я долго раздумывал, какой интерфейс взаимодействия выбрать. Технология-то одна - ajax, а вот какой инструмент более удобен? Можно попробовать использовать RequestBuilder, но этот метод не совсем удобен и не совсем универсален. Поэтому я выбрал json-rpc. Для него уже все создано, как на стороне django, так и на стороне GWT.
Json-rpc, это легкий протокол удаленного вызова процедур, использующий для своего функционирования формат Json.
Пример запроса и ответа:
Начнем с django. Добавляем поддержку json-rpc в наш проект.
Импортируем django-json-rpc и добавляем точку входа в urls.py.
Возьмем пример с readme:
Запускаем сервер, запускаем шел django
И тестируем:
В общем, в документе все написано. Также в приложении есть своей браузер, зайти на него можно по адресу http://localhost:8080/json/browse/ , добавив в urls.py, например так:
Я нашел несколько неточностей в документации, так, там name="jsonrpc_browser" без буквы "r" на конце, плюс url браузера
идет после r'^json/', который перекрывает его вызов.
Итак, rpc в django у нас теперь есть. Переходим к клиентской части rpc в gwt.
Проделываем все операции, указанные в readme и... у меня не заработало.
Судя по всему, в GWT 2.0 изменились какие-то механизмы в сервисах JSON. Наверное класс JSONServiceBase раньше не требовал реализации метода ServiceDefTarget.setRpcRequestBuilder.
Что ж, давайте взглянем на исходники.
Действительно, функции setRpcRequestBuilder нет.
Проект не обновляется, разбираться времени нет, так что пробуем еще один вариант gwt-json-rpc.
По инструкции подключаем библиотеку. В инструкции написано что библиотека использует свой JSON кодер/декодер, поэтому можно использовать простые типы java: String, int, boolean, Array, HashMap, ArrayList, Vector, вместо классов GWT. В общем, она даже проще, чем lovely-gwt-jsonrpc.
У меня получился следующий код.
Что такое SC смотрим здесь.
После запуска мы обнаруживаем, что все результаты попыток вызова функции попадают в onFailure. Обусловлено это скорее всего тем, что сервер Django и сервер gwt находятся на разных портах, а это противоречит Same Origin Policy.
Далее, я скомпилировал проект, чтобы скопировать его в статический путь в проекте Django, и запустить под сервером Django, чтобы не нарушать SOP. И обнаружил, что CsrfMiddleware не дает скомпилированному gwt приложению делать POST запросы. Но мы знаем, что фрейморки, вроде jQuery позволяли это с легкостью делать. А все потому, что gwt-json-rpc при создании RequestBuilder не создает заголовок вида "X-Requested-With: XMLHttpRequest", поэтому django (точнее middleware) считает, что запрос сделан с другого домена, и возвращает ошибку 403. Значит надо сообщить ему об этом. AJAX запросы считаются безопасными и не нуждаются в проверке, так как современные браузеры придерживаются SOP. Придется добавить данный заголовок в код библиотеки и пересобрать ее. Разработчику проблему описал. Может быть на момент прочтения статьи в ней будет прописан данный заголовок (функция JsonRpc.request):
Я его добавил сам и сделал новый jar. Компилируем проект, копируем в путь для статики в django, и проверяем - все должно работать.
Остался один ньюанс - работа в дебаг режиме и ajax запросы. Не будем же мы каждый раз компилировать проект, тем более терять все прелести дебага. Воспользуемся HTTP proxy servlet.
Качаем сервлет, копируем в папку WEB-INF/lib, правим web.xml, у меня примерно следующее:
Меняем путь запроса:
и проверяем работу в дебаг режиме.
Вот и все. Удачной разработки.
Я долго раздумывал, какой интерфейс взаимодействия выбрать. Технология-то одна - ajax, а вот какой инструмент более удобен? Можно попробовать использовать RequestBuilder, но этот метод не совсем удобен и не совсем универсален. Поэтому я выбрал json-rpc. Для него уже все создано, как на стороне django, так и на стороне GWT.
Json-rpc, это легкий протокол удаленного вызова процедур, использующий для своего функционирования формат Json.
Пример запроса и ответа:
--> { "method": "echo", "params": ["Hello JSON-RPC"], "id": 1}
<-- { "result": "Hello JSON-RPC", "error": null, "id": 1}
Начнем с django. Добавляем поддержку json-rpc в наш проект.
Импортируем django-json-rpc и добавляем точку входа в urls.py.
from jsonrpc import jsonrpc_site
import myproj.myapp.views # подключаем файл, в котором буду храниться rpc функции
urlpatterns += patterns('',
url(r'^json/', jsonrpc_site.dispatch, name="jsonrpc_mountpoint"),
)
Возьмем пример с readme:
from jsonrpc import jsonrpc_method
@jsonrpc_method('myapp.sayHello')
def whats_the_time(request, name='Lester'):
return "Hello %s" % name
Запускаем сервер, запускаем шел django
./manage.py runserver 8080
./manage.py shell
И тестируем:
>>> from jsonrpc.proxy import ServiceProxy
>>> s = ServiceProxy('http://localhost:8080/json/')
>>> s.myapp.sayHello('Sam')
{u'error': None, u'id': u'jsonrpc', u'result': u'Hello Sam'}
В общем, в документе все написано. Также в приложении есть своей браузер, зайти на него можно по адресу http://localhost:8080/json/browse/ , добавив в urls.py, например так:
if settings.DEBUG:
urlpatterns += patterns('',
url(r'^json/browse/', 'jsonrpc.views.browse', name="jsonrpc_browser"), # for the graphical browser/web console only, omissible
)
urlpatterns += patterns('',
url(r'^json/', jsonrpc_site.dispatch, name="jsonrpc_mountpoint"),
)
Я нашел несколько неточностей в документации, так, там name="jsonrpc_browser" без буквы "r" на конце, плюс url браузера
идет после r'^json/', который перекрывает его вызов.
Итак, rpc в django у нас теперь есть. Переходим к клиентской части rpc в gwt.
Проделываем все операции, указанные в readme и... у меня не заработало.
09:36:42.942 [ERROR] [myapp] Errors in 'jar:file:/lovely.gwt.jsonrpc-0.7.jar!/lovely/gwt/jsonrpc/client/JSONServiceBase.java'
09:36:42.957 [ERROR] [myapp] Line 29: The type JSONServiceBase must implement the inherited abstract method ServiceDefTarget.setRpcRequestBuilder(RpcRequestBuilder)
Судя по всему, в GWT 2.0 изменились какие-то механизмы в сервисах JSON. Наверное класс JSONServiceBase раньше не требовал реализации метода ServiceDefTarget.setRpcRequestBuilder.
Что ж, давайте взглянем на исходники.
Действительно, функции setRpcRequestBuilder нет.
Проект не обновляется, разбираться времени нет, так что пробуем еще один вариант gwt-json-rpc.
По инструкции подключаем библиотеку. В инструкции написано что библиотека использует свой JSON кодер/декодер, поэтому можно использовать простые типы java: String, int, boolean, Array, HashMap, ArrayList, Vector, вместо классов GWT. В общем, она даже проще, чем lovely-gwt-jsonrpc.
У меня получился следующий код.
//Create a new JsonRpc instance
JsonRpc jsonRpc = new JsonRpc();
//Create a callback handler
AsyncCallback
Что такое SC смотрим здесь.
После запуска мы обнаруживаем, что все результаты попыток вызова функции попадают в onFailure. Обусловлено это скорее всего тем, что сервер Django и сервер gwt находятся на разных портах, а это противоречит Same Origin Policy.
Далее, я скомпилировал проект, чтобы скопировать его в статический путь в проекте Django, и запустить под сервером Django, чтобы не нарушать SOP. И обнаружил, что CsrfMiddleware не дает скомпилированному gwt приложению делать POST запросы. Но мы знаем, что фрейморки, вроде jQuery позволяли это с легкостью делать. А все потому, что gwt-json-rpc при создании RequestBuilder не создает заголовок вида "X-Requested-With: XMLHttpRequest", поэтому django (точнее middleware) считает, что запрос сделан с другого домена, и возвращает ошибку 403. Значит надо сообщить ему об этом. AJAX запросы считаются безопасными и не нуждаются в проверке, так как современные браузеры придерживаются SOP. Придется добавить данный заголовок в код библиотеки и пересобрать ее. Разработчику проблему описал. Может быть на момент прочтения статьи в ней будет прописан данный заголовок (функция JsonRpc.request):
builder.setHeader("X-Requested-With", "XMLHttpRequest");
Я его добавил сам и сделал новый jar. Компилируем проект, копируем в путь для статики в django, и проверяем - все должно работать.
Остался один ньюанс - работа в дебаг режиме и ajax запросы. Не будем же мы каждый раз компилировать проект, тем более терять все прелести дебага. Воспользуемся HTTP proxy servlet.
Качаем сервлет, копируем в папку WEB-INF/lib, правим web.xml, у меня примерно следующее:
HttpProxy
com.jsos.httpproxy.HttpProxyServlet
host
http://localhost:8080/json/
HttpProxy
/json/
Меняем путь запроса:
jsonRpc.request(
"/json/",
"myapp.sayHello",
null,
callback);
и проверяем работу в дебаг режиме.
Вот и все. Удачной разработки.
Ярлыки:
django,
django-json-rpc,
Eclipse,
Google Web Toolkit,
gwt-json-rpc
22 декабря 2009 г.
GWT. Передача параметров в GWT
Этой серией буду учиться вместе с вами, как работать с GWT в виде фронтенда и Django в виде бекенда. Пишу простым языком, так как сам разбираюсь в процессе.
Для начала надо научиться передавать параметры в GWT. Первая и основная причина - идеология django - нельзя жестко использовать url адреса. Django для этого предоставляет множество средств, как то и специальный тег url в шаблонах, и специальную функцию reverse для использования в коде. То есть смысл определяется тем, что нельзя использовать url напрямую где бы-то ни было, кроме определения его в файле url.py. Любое изменение конфигурации url'ов в url.py не должно приводить к поломке приложения. В общем, для запуска GWT фронтенда нам необходим набор url-ов определенных в бекенде для ajax запросов.
На стороне Django мы используем тег {% url %}, и выводим url'ы ajax запросов с помощью него, с этим все понятно. Но как их передать в GWT?
Так как GWT и находится в клиентском окружении javascript окна, то мы можем передать параметры в темплейте Django как словарь javascript:
И получить эти url'ы в GWT:
Для начала надо научиться передавать параметры в GWT. Первая и основная причина - идеология django - нельзя жестко использовать url адреса. Django для этого предоставляет множество средств, как то и специальный тег url в шаблонах, и специальную функцию reverse для использования в коде. То есть смысл определяется тем, что нельзя использовать url напрямую где бы-то ни было, кроме определения его в файле url.py. Любое изменение конфигурации url'ов в url.py не должно приводить к поломке приложения. В общем, для запуска GWT фронтенда нам необходим набор url-ов определенных в бекенде для ajax запросов.
На стороне Django мы используем тег {% url %}, и выводим url'ы ajax запросов с помощью него, с этим все понятно. Но как их передать в GWT?
Так как GWT и находится в клиентском окружении javascript окна, то мы можем передать параметры в темплейте Django как словарь javascript:
И получить эти url'ы в GWT:
public void useURLsDictionary() {
Dictionary URLsDict = Dictionary.getDictionary("ajaxsUrls");
String ajaxUrl1 = URLsDict.get("ajaxUrl1");
String ajaxUrl2 = URLsDict.get("ajaxUrl2");
}
Ярлыки:
django,
Google Web Toolkit
16 декабря 2009 г.
Google Web Toolkit 2, Eclipse, SmartGWT
Google Web Toolkit - В Google Web Toolkit (GWT) интерфейс AJAX пишется на языке программирования Java, а затем GWT кросс-компилирует его в оптимизированный JavaScript, автоматически работающий во всех основных браузерах. При разработке можно быстро проходить по привычному для разработчиков JavaScript циклу "изменить – обновить – посмотреть", а также отлаживать код Java построчно.
Eclipse (/iˈklɪps/, от англ. затмение[1]) — свободный фреймворк для разработки модульных кроссплатформенных приложений. Разрабатывается и поддерживается Eclipse Foundation.
Наиболее известные приложения на основе Eclipse Platform — различные «Eclipse IDE» для разработки ПО на множестве языков (например, наиболее популярный «Java IDE», поддерживавшийся изначально, не полагается на какие-либо закрытые расширения, использует стандартный открытый API для доступа к Eclipse Platform).
SmartGWT - Полная библиотека виджетов, основана на JS библиотеке SmartClient. Главная особенность- позволяет связывать пользовательские виджеты с серверными компонентами. Что позволяет делать управление данными на стороне сервера. Серьезный конкурент библиотеке Ext GWT. Распространяется как по платной так и бесплатной лицензиям. В платной лицензии есть возможность использования Enterprise объектов и визуального редактора виджетов.
Смысл ясен. Надо соединить все это вместе.
1. Скачиваем eclipse для java.
http://www.eclipse.org/downloads/
2. Ставим поверх Web Tools Platform (WTP) Project.
http://www.eclipse.org/webtools/
3. Ставим GWT plugin для eclipse.
http://code.google.com/intl/ru/eclipse/docs/getting_started.html
4. Создаем проект Web Application Project.

5. Скачиваем SmartGWT.
http://code.google.com/p/smartgwt/
6. Заходим в свойства проекта, добавляем в Java Build Path -> Libraries - Add External JARs библиотеки:
smartgwt.jar
smartgwt-skins.jar (если вы планируете изменить скин, в обратном случае, скин по умолчанию находится в основной библиотеке)
7. Заходим в директорию war, добавляем в главном html файле перед основным подключенным js файлом следующее (для указания пути статики SmartGWT):
8. Добавляем в ModuleName.gwt.xml:
9. В классе EntryPoint (точка входа нашего приложения) ищем функцию onModuleLoad();
Пробуем SmartGMT, дописывая следующее:
Плюс импорт в начало:
10. Жмем Debug, переходим по адресу, который отображает консоль Develompment Mode, устанавливаем плагин для Вашего браузера.
Видим примерно следующее:

Далее работает в обычном режиме - точки останова, дебаггинг и прочее.
11. Компиляция для опубликования.

12. Ну и пощупать SmartGWT online можно здесь, а gwt - здесь.
ps. К сожалению плагина для Google Chrome под linux нет. Выражены некоторые надежды на появлении его в пятой версии браузера.
К счастью разработку это не затормозит, так как есть версия плагина для Firefox.
Eclipse (/iˈklɪps/, от англ. затмение[1]) — свободный фреймворк для разработки модульных кроссплатформенных приложений. Разрабатывается и поддерживается Eclipse Foundation.
Наиболее известные приложения на основе Eclipse Platform — различные «Eclipse IDE» для разработки ПО на множестве языков (например, наиболее популярный «Java IDE», поддерживавшийся изначально, не полагается на какие-либо закрытые расширения, использует стандартный открытый API для доступа к Eclipse Platform).
SmartGWT - Полная библиотека виджетов, основана на JS библиотеке SmartClient. Главная особенность- позволяет связывать пользовательские виджеты с серверными компонентами. Что позволяет делать управление данными на стороне сервера. Серьезный конкурент библиотеке Ext GWT. Распространяется как по платной так и бесплатной лицензиям. В платной лицензии есть возможность использования Enterprise объектов и визуального редактора виджетов.
Смысл ясен. Надо соединить все это вместе.
1. Скачиваем eclipse для java.
http://www.eclipse.org/downloads/
2. Ставим поверх Web Tools Platform (WTP) Project.
http://www.eclipse.org/webtools/
3. Ставим GWT plugin для eclipse.
http://code.google.com/intl/ru/eclipse/docs/getting_started.html
4. Создаем проект Web Application Project.

5. Скачиваем SmartGWT.
http://code.google.com/p/smartgwt/
6. Заходим в свойства проекта, добавляем в Java Build Path -> Libraries - Add External JARs библиотеки:
smartgwt.jar
smartgwt-skins.jar (если вы планируете изменить скин, в обратном случае, скин по умолчанию находится в основной библиотеке)
7. Заходим в директорию war, добавляем в главном html файле перед основным подключенным js файлом следующее (для указания пути статики SmartGWT):
8. Добавляем в ModuleName.gwt.xml:
9. В классе EntryPoint (точка входа нашего приложения) ищем функцию onModuleLoad();
Пробуем SmartGMT, дописывая следующее:
SC.say("Привет, мир!");
Плюс импорт в начало:
import com.smartgwt.client.util.SC;
10. Жмем Debug, переходим по адресу, который отображает консоль Develompment Mode, устанавливаем плагин для Вашего браузера.
Видим примерно следующее:

Далее работает в обычном режиме - точки останова, дебаггинг и прочее.
11. Компиляция для опубликования.

12. Ну и пощупать SmartGWT online можно здесь, а gwt - здесь.
ps. К сожалению плагина для Google Chrome под linux нет. Выражены некоторые надежды на появлении его в пятой версии браузера.
К счастью разработку это не затормозит, так как есть версия плагина для Firefox.
Ярлыки:
Eclipse,
Google Web Toolkit 2,
java,
javascript,
SmartGWT
Подписаться на:
Сообщения (Atom)
