<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Virtual Web Laboratory</title>
	<atom:link href="http://vwlab.ru/feed/" rel="self" type="application/rss+xml" />
	<link>http://vwlab.ru</link>
	<description>&#169; Все права защищены</description>
	<lastBuildDate>Fri, 30 Mar 2012 13:40:27 +0000</lastBuildDate>
	<language>ru</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>Звонки из веб-интерфейса Gmail в Skype</title>
		<link>http://vwlab.ru/post/230/</link>
		<comments>http://vwlab.ru/post/230/#comments</comments>
		<pubDate>Fri, 30 Mar 2012 13:40:27 +0000</pubDate>
		<dc:creator>Niko</dc:creator>
				<category><![CDATA[Разное]]></category>

		<guid isPermaLink="false">http://vwlab.ru/?p=230</guid>
		<description><![CDATA[В статье описывается способ звонить в Skype через Google Voice из интерфейса Gmail с помощью sip-шлюза. Вместе с этим будет доступен прямой американский номер на который можно принимать любые входящие звонки и SMS и звонить на любые американские номера. Способ &#8230;<p class="read-more"><a href="http://vwlab.ru/post/230/">Читать далее &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<p><img src="http://habrastorage.org/storage2/3ee/1ef/689/3ee1ef689a2de4ccb37d59e81f23d71c.png"/><br/><br />
В статье описывается способ звонить в Skype через Google Voice из интерфейса Gmail с помощью sip-шлюза. Вместе с этим будет доступен прямой американский номер на который можно принимать любые входящие звонки и SMS и звонить на любые американские номера. <br/><br />
Способ несколько извращенный, но свою задачу выполняет. Изначальная задача была иметь возможность участвовать в скайп-конференции при этом не устанавливать Skype и обойтись только браузером. <br/><br />
 <span id="more-230"></span> <br/></p>
<h4>Google Voice </h4>
<p><br/><br />
Самый трудоемкий момент — это получение аккаунта в Google Voice. <br/><br />
Данная инструкция двухгодичной давности в принципе актуальна <a href="http://habrahabr.ru/post/94970/">habrahabr.ru/post/94970/</a> разве только американский прокси не обязателен, у меня получалось через нидерландский и немецкий.<br/><br />
За два года Google Voice научился нормально принимать SMS, переправлять их на почту (правда сообщения, содержащие кирилические символы, не доходят из некоторых сетей) и записывать разговоры. <br/><br />
Так же теперь при регистрации номера можно попытаться подобрать мнемонический номер из указанного слова, как например +1-800-MY-APPLE (call-центр Apple). На удивление, номеров довольно много и найти соответствие можно для большого количества слов.<br/><br />
Чтобы избежать путаницы при регистрации Google Voice я советую поступить так:<br/><br />
сначала в Gmail нажать «Набрать номер», если вы ранее не нажимали его, будет предложено принять пользовательское соглашение.<br/><br />
<img src="http://habrastorage.org/storage2/e95/73e/3ed/e9573e3ed7907d654219429486c9bf2a.png"/><br/><br />
После того как соглашение принято переходим на <a href="http://google.com/voice">google.com/voice</a>. Должен появится пункт Get a Voice number. Если его нет, меняем прокси и пробуем снова.<br/><br />
<img src="http://habrastorage.org/storage2/c93/ceb/25d/c93ceb25df0b2063bd1474d1e433e737.png"/><br/><br />
 <br/><br />
Жмем I want new number. На этом этапе можно подобрать мнемонический номер: <br/><br />
<img src="http://habrastorage.org/storage2/00e/e10/791/00ee1079182209798e492d15c073e758.png"/><br/><br />
Далее нас попросят подтвердить что мы имеем американский телефонный номер, на который позвонит робот и попросит ввести в тональном режиме двухзначный код. Номер можно получить по инструкции в приведенной выше ссылке, либо купить в Skype. На один номер можно активировать два Google Voice, поэтому если вы получили номер в ipkall, можете помочь другу. Бывает так что в ipkall выдается номер на который уже активировано два Google Voice, в таком случае нужно зарегистрировать заново. У меня осталось несколько не активированных номеров, поэтому если у вас совсем ничего не получится, я могу посодействовать.<br/><br />
После того как активация пройдена, и Google Voice выдал вам номер, первый номер больше не нужен, его можно удалить из списка привязанных. Теперь на этот номер можно бесплатно принимать любые звонки прямо в интерфейсе Gmail, звонить на любые американские номера, записывать разговоры, настроить голосовую почту и прием SMS.<br/><br />
В настройках Google Voice нужно указать Forwards calls to: Google chat. Чтобы звонки принимались сразу же, нужно отключить Call Screening в меню Calls, иначе всех звонящих робот будет просить представиться, пытаясь, распознать имя, чтобы вписать его в логах (русские имена не понимает).<br/><br />
В меню Voicemail &#038; Text отметить пункт Forward text messages to my email. <br/></p>
<h4>Sip to Skype</h4>
<p> <br/><br />
Чтобы звонить бесплатно в Skype нужнон айти американский номер, который перенаправит звонок на нужный skype-аккаунт… Из известных мне sip-операторов услугу переадресаци на Skype предоставляют <a href="http://www.sipnet.ru/">sipnet.ru</a> и <a href="http://zadarma.com/ru/">zadarma.com/ru/ </a> оба имеют шлюзы в америке, разница только в том что sipnet.ru взымает плату за входящие через шлюзы, а zadarma.com делает это беслпатно. <br/><br />
В панели zadarma в меню «Настройки SIP» можно добавить до трех SIP-аккаунтов, это значит переадресацию можно настроить только на три skype-логина.<br/><br />
В строке «Переадресация SIP на телефон» указываем желаемый аккаунт, где myskype — это skype-логин:<br/><br />
<img src="http://habrastorage.org/storage2/85f/c53/15b/85fc5315b930185b5935578515faa220.png"/><br/><br />
В результате для того, чтобы позвонить позвонить товарищу в Skype из Гугл почты, я звоню на +1 (718) 831-71-56 (американский шлюз задармы) и набираю добавочный пятизначный номер. Товарищ видит входящий звонок от skype-аккаунта skypegate.ru (его желательно добавить в контакты заранее) и добавляет его в конференцию.</p>
<p>© <a href="http://m.habrahabr.ru/post/141017/">Habrahabr.ru</a></p>
]]></content:encoded>
			<wfw:commentRss>http://vwlab.ru/post/230/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Новый SimCity будет работать только при подключении к Сети</title>
		<link>http://vwlab.ru/post/228/</link>
		<comments>http://vwlab.ru/post/228/#comments</comments>
		<pubDate>Fri, 30 Mar 2012 13:40:15 +0000</pubDate>
		<dc:creator>Niko</dc:creator>
				<category><![CDATA[Разное]]></category>

		<guid isPermaLink="false">http://vwlab.ru/?p=228</guid>
		<description><![CDATA[Лично я хорошо понимаю тех геймеров, кто ожидает появления новой версии SimCity, адаптированной под современное железо. Когда-то я несколько месяцев подряд играл в SimCity (версию уже и не помню), и игра поражала огромным вниманием к деталям со стороны разработчиков. Сейчас &#8230;<p class="read-more"><a href="http://vwlab.ru/post/228/">Читать далее &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<p><img src="http://habrastorage.org/storage2/2b6/bd5/232/2b6bd52323cac7507bd71936648e2113.jpg"/><br/><br />
Лично я хорошо понимаю тех геймеров, кто ожидает появления новой версии SimCity, адаптированной под современное железо. Когда-то я несколько месяцев подряд играл в SimCity (версию уже и не помню), и игра поражала огромным вниманием к деталям со стороны разработчиков. Сейчас уже практически ни во что не играю, но на днях попалась информация о том, что вскоре должна выйти новая версия этого симулятора градостроителя. При этом игрушка будет отличаться от предыдущих версий не только графикой или масштабами игрового мира. Есть и другие отличия.<br/><br />
 <span id="more-228"></span> Например, игрушка будет доступна только для геймеров, чьи ПК и ноутбуки подключены к Сети. Это не слухи, а заявление ведущего дизайнера проекта Стоуна Либранда. Он сообщил, что постоянное подключение к Сети обусловлено новыми условиями игры, моделью экономической инфраструктуры. Так, разные игроки смогут занимать соседние территории, и разные города будут влиять друг на друга. Например, если кто-то построит промышленный комплекс, выбрасывающий токсичные отходы, то соседний город примет на себя негативные последствия влияния «грязного» соседа. <br/><br />
Такого рода взаимодействий будет достаточно много, и без постоянного подключения к Сети нельзя будет получать полную картину о своих соседях и их действиях. Таким образом, Интернет нужен для постоянного просчета взаимодействия регионов, игроков, и их действий. Любые заметные действия игрока, или события, происходящие в городе, будут отражаться на внешнем виде населенного пункта. Как это все будет выглядеть, пока не очень ясно.<br/><br />
Разработчики, по их собственным словам, собираются сделать симулятор еще более детализированным, чем прошлые версии игры, но при этом играть в новый SimCity сможет даже неподготовленный игрок. Понятно, что хорошим градостроителем он станет только после продолжительной тренировки, но и начальный уровень игры не настолько сложен, насколько можно было бы подумать.<br/><br />
<iframe width="560" height="349" src="http://www.youtube.com/embed/zJx4RZq4Nw4" frameborder="0" allowfullscreen></iframe><br/><br />
<a href="http://news.cnet.com/8301-17938_105-57406192-1/next-simcity-requires-net-to-start/">Cnet</a></p>
<p>© <a href="http://m.habrahabr.ru/post/141018/">Habrahabr.ru</a></p>
]]></content:encoded>
			<wfw:commentRss>http://vwlab.ru/post/228/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Веб-разработка с ChicagoBoss framework</title>
		<link>http://vwlab.ru/post/226/</link>
		<comments>http://vwlab.ru/post/226/#comments</comments>
		<pubDate>Fri, 30 Mar 2012 13:38:33 +0000</pubDate>
		<dc:creator>Niko</dc:creator>
				<category><![CDATA[Разное]]></category>

		<guid isPermaLink="false">http://vwlab.ru/?p=226</guid>
		<description><![CDATA[«Chicago Boss — бескомпромиссный веб-фреймворк, любимый дизайнерами, инженерами и этим парнем с пейджером.» — © chicagoboss.org «Erlang — язык для создания отказоустойчивых распределенных приложений. Это — один из немногих функциональных языков, который давно и успешно применяется на практике. Например — &#8230;<p class="read-more"><a href="http://vwlab.ru/post/226/">Читать далее &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<p><img align="right" src="http://habrastorage.org/storage2/9cb/768/e91/9cb768e9175c3fdd3243bb7f50445fd8.jpg" alt="Chicago Boss"/><br/><br />
«Chicago Boss — бескомпромиссный веб-фреймворк, любимый дизайнерами, инженерами и этим парнем с пейджером.» — © <a href="http://www.chicagoboss.org">chicagoboss.org</a><br/><br />
«Erlang — язык для создания отказоустойчивых распределенных приложений. Это — один из немногих функциональных языков, который давно и успешно применяется на практике. Например — в телекомах (Ericsson AXD-301 switch), банковских системах, системах автоматизации, высоконагруженных веб-приложениях (Facebook Chat). При этом Erlang — продукт с открытым исходным кодом и распространяется бесплатно.» — говорит нам <a href="http://erlanger.ru/">сайт русскоязычного сообщества Erlang</a>. <br/><br />
Данный пост предназначен для расширения аудитории Erlang программистов. Если до этого вы считали что функциональное программирование не может быть использовано для бытовых целей, то пора расширить ваш кругозор. Этот пост писался при поддержке моего товарища — Ruby/C++ программиста с многолетним стажем, лично знакомого с <a href="http://www.evanmiller.org/">создателем данного фреймворка</a> (Эван Миллер) и последнее время фанатеющего от данного языка.<br/><br />
По заверению обоих разработка веб-приложений на базе этого фреймворка ничуть не медленнее разработки на тех же рельсах (Ruby on Rails). А в чем-то даже быстрее. Я с функциональным программированием до этого особо знаком не был, но под давлением товарища решил попробовать. Хочу сказать, что опыт был весьма удачным и у меня получилось создать мой первый веб-сайт быстрее, чем год назад с тем же Ruby on Rails.<br/><br />
 <span id="more-226"></span> <br/><br />
<img src="http://habrastorage.org/storage2/2fa/4a8/c70/2fa4a8c705836a00e90de0cab0f0bb2a.png"/><br/><br />
Предыстория:<br/><br />
Дело было в октябре 2010 года на очередном <a href="http://www.erlangcamp.com/">Erlang семинаре</a>, Чикаго, Иллинойс. Под конец лекции произошло следующее (со слов друга): I heard his voice across the room, saying, «I am working on a Rails for Erlang» and 99 people went, «Yeah, right!» (<i>перевод: Я услышал его голос через всю аудитории: «Я работаю над Рельсами для Erlang» и 99 человек сказало «Ага, конечно!»</i>). Звали этого парня Evan Miller. После семинара мой друг расспрашивал его о концепциях и идеях, вложенных в «функциональные рельсы». Идеи ему очень понравились, и с тех пор он все свободное время проводит над проектами с этим фреймворком, а также помогает с документацией Эвану. Он даже организовывал лекции по этому делу и внедрил некоторые вещи у себя в компании.<br/></p>
<ol>
<li>Вступление</li>
<li>Установка</li>
<li>Настройка рабочей среды (по желанию)</li>
<li>Создание первого проекта</li>
<li>Работа с БД</li>
<li>CRUD</li>
<li>Дополнение</li>
<li>Итоги</li>
<li>Ресурсы</li>
</ol>
<p><br/></p>
<h4>Вступление</h4>
<p><br/><br />
В этой статье мы сделаем веб сайт, который будет представлять собой адресную книгу (<b>addressbook</b>) с возможностью добавления/удаления/просмотра/редактирования записей. Т.е. реализуем стандартный <b>CRUD</b>.<br/><br />
Для интересующихся: <u>вся разработка отняла примерно 4-5 часов, включая установку, настройку инструментов и изучение.</u><br/><br />
Для достижения поставленной задачи были использованы следующие инструменты:<br/><br />
<a href="http://www.ubuntu.com/">Ubuntu 11.10</a> 32bit, <a href="http://www.erlang-solutions.com/section/132/erlang-otp-packages">Erlang R15B</a>, <a href="http://www.chicagoboss.org">ChicagoBoss</a> MVC фреймворк, документно-ориентированная база данных <a href="http://www.mongodb.org/">MongoDB</a>, Gedit с пакетом плагинов <a href="https://github.com/gmate/gmate">Gmate</a> от <a href="http://habrahabr.ru/users/iskin/" class="user_link">iskin</a> (Gedit — это просто текстовый редактор).<br/><br />
<i>Установка для Mac не сложнее установки для Ubuntu. Для Windows есть <a href="https://github.com/evanmiller/ChicagoBoss/wiki/Windows-instructions">отдельная инструкция</a>, но и она от приведенной здесь не особо отличается. Может быть найдутся добрые люди, которые поделятся своим опытом установки для Windows/Mac в комментариях.</i><br/><br />
По каждому из инструментов можно написать отдельную большую статью, да еще и не одну. Но чтобы не пугать читателя страшными словами и тоннами материала, скажу, что на самом деле для быстрого входа достаточно будет одной этой статьи.<br/><br />
Я лично никогда до этого не имел дела ни с функциональными языками, ни с документно-ориентированными базами данных, но это мне не помешало создать свое первое приложение с ними.<br/><br />
Все ссылки на полезные ресурсы, на исходники и на <a href="http://erlang-test.no-ip.biz">готовый веб сайт</a> в разделе Ресурсы. <br/><br />
Стоит упомянуть, что <u>сайт находится на моем личном ноуте</u> (Dual-Core CPU T4300 @ 2.10GHz, 2GB). Так что пожалуйста без фанатизма. О падениях (если такие будут) буду сообщать. Предвидя ваш вопрос: запустил я сайт локально, т.к. хотел проверить, при какой нагрузке рухнет сервер. Ну и дешевле получается, чтоб лишний хостинг не покупать. Может кто проявит желание и поделится нормальным сервером, разместим сайт там. <br/><br />
Если сайт не открывается, значит я химичу с ноутом, попробуйте открыть через пару минут.<br/><br />
Если какой-то из моментов не понятен, пишите в комментариях, буду править статью.<br/></p>
<h4>Установка</h4>
<p><br/></p>
<h5>Erlang</h5>
<p><br/><br />
Для начала нужно установить Erlang последней версии. Идем на <a href="http://www.erlang-solutions.com/section/132/download-erlang-otp">этот веб сайт</a> и следуем инструкции для вашей операционной системы. Там же можно скачать нужный дистрибутив или посмотреть необходимый репо.<br/><br />
У меня Убунту 11.10 32 битная. Для нее дистрибутива нет, только для 64х битной. Поэтому я просто скачал дистрибутив для Убунту 11.04 32 бит. Некоторые фишки в ней не работают, как например графический просмотр существующих потоков и процессов (<a href="http://www.erlang.org/doc/man/appmon.html#start-0">утилита appmon</a>).<br/><br />
<img src="http://habrastorage.org/storage2/b30/eb6/285/b30eb62855e03a731fde90d3eba2b582.png"/><br/><br />
Но обучению, и даже созданию нормальных проектов, это не мешает.<br/><br />
Ну и конечно всегда можно собрать нужную версию для своей версии ОС из исходников <img src='http://vwlab.ru/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  Мой товарищ свои версии уже раз 5 собирал для разных машин: Ubuntu и Mac. Говорит, что конечно геморойно, но вполне возможно за один вечер осилить.<br/><br />
Еще с проблемами можно обращаться в <a href="http://www.erlang-solutions.com/">Erlang-Solutions</a>. Говорят, ребята отзывчивые.<br/><br />
После скачивания файла и при запуске установки мне выдало следующее:<br/><br />
<code>installing esl-erlang 1:15.b</code><br/><br />
<code>size - 63.8 mb</code><br/><br />
После установки для проверки приложения открываем консоль и пишем команду erl. Которая выдает примерно следующее:<br/><br />
<code>Erlang R15B (erts-5.9) [source] [smp:2:2] [async-threads:0] [hipe] [kernel-poll:false]</code><br/><br />
<code>Eshell V5.9 </code><br/></p>
<h5>ChicagoBoss</h5>
<p><br/><br />
<i>Скачать framework можно и без Git, просто зайти на страницу разработки и стянуть последнюю версию.</i><br/><br />
Устанавливаем Git, если его у вас еще нет:<br/><br />
<code>apt-get install git-core</code><br/><br />
получаем копию ChicagoBoss framework:<br/><br />
<code>git clone git://github.com/evanmiller/ChicagoBoss.git</code><br/><br />
 <br/><br />
Заходим в дирректорию вашего репо:<br/><br />
 <code>cd ChicagoBoss</code><br/><br />
Компилируем:<br/><br />
 <code>./rebar get-deps clean compile</code><br/><br />
Чтобы завести новый проект (нужно находится в дирректории нашего фреймворка):<br/><br />
<code>make app PROJECT=your_project_name_here</code><br/><br />
Затем:<br/><br />
<code> cd ../your_project_name_here</code><br/><br />
Для запуска дебаг (developer) режима:<br/><br />
 <code> ./init-dev.sh</code><br/><br />
Для запуска в продакшн:<br/><br />
 <code>./init.sh start</code><br/><br />
Дождитесь, пока сообщения перестанут двигаться. Если отчетов об ошибках или крешах нет, то можно открывать localhost:8001<br/><br />
Теперь можно создавать новые модели, контроллеры, вьюшки и сразу смотреть результат без перекомпиляции и перезапуска сервера. <i>В некоторых случаях перекомпиляция все-таки нужна, например когда меняете маршруты (routes).</i><br/><br />
Компиляция вызывается командой:<br/><br />
<code>./rebar compile</code><br/><br />
ChicagoBoss по умолчанию использует веб-сервер на <a href="https://github.com/ostinelli/misultin/">Misultin</a> и при создании приложения в конфиге прописывается порт 8001. При желании сервер можно заменить на <a href="https://github.com/mochi/mochiweb">Mochiweb</a>, а возможно и на <a href="https://github.com/extend/cowboy">Cowboy</a>.<br/></p>
<h5>MongoDB</h5>
<p><br/><br />
Тут все очень просто. Качаем и устанавливаем. В Убунту вобще только одна команда:<br/><br />
<code>apt-get install mongodb</code><br/><br />
Для проверки работоспособности можно ввести одну из команд в консоль:<br/><br />
<code>mongo</code><br/><br />
или<br/><br />
<code>ps aux | grep mongo</code><br/><br />
А также можно попробовать постучаться по адресу localhost:28017. Родной порт, по которому приложения обычно работают с Монго — 27017. Для браузера по умолчанию используется 28017.<br/><br />
Для управления MongoDB сервером используются следующие команды:<br/><br />
<code>$ sudo status mongodb</code><br/><br />
<code>$ sudo stop mongodb</code><br/><br />
<code>$ sudo start mongodb</code><br/><br />
<code>$ sudo restart mongodb</code><br/><br />
После некорректного выключения сервера, например, при выключении/перезагрузке машины, при старте сервера БД он все равно остается выключенным. Сделано это специально созданием lock файла. Чтобы запустить сервер снова нужно сделать следующее:<br/><br />
 1. Удалить lock файл<br/><br />
 2. Запустить скрипт восстановления<br/><br />
<code>$ sudo rm /var/lib/mongodb/mongod.lock</code><br/><br />
<code>$ sudo -u mongodb mongod -f /etc/mongodb.conf --repair</code><br/><br />
Ну вот собственно и все, мы готовы к созданию наших собственных приложений. По большому счету приложения создавать можно и без базы данных, либо использовать другую БД. На ваше усмотрение. Поддерживаемые БД перечислены в документации.<br/></p>
<h4>Настройка рабочей среды (по желанию)</h4>
<p><br/><br />
Я скачал пакет плагинов <a href="https://github.com/gmate/gmate">Gmate</a>. Из них реально использую пока только <a href="http://code.google.com/p/zen-coding/">Zen Coding</a>. Отличное пособие по использованию этого плагина представлено в <a href="http://tutsplus.com/lesson/zen-coding/">этой видео лекции</a>. Реально упрощает жизнь.<br/><br />
Один мой друг сказал что это <a href="http://haml-lang.com/">HAML</a> для бедных, но меня использование этой прослойки пока «не вставляет».<br/><br />
И еще использую сниппеты (<a href="http://live.gnome.org/Gedit/Plugins/Snippets">Snippets</a>). Этот плагин поставляется с Gedit, но по умолчанию он выключен. Для включения идем Edit -> Preferences -> Plugins -> Snippets.<br/><br />
Он прост в использовании, просто открываете Tools -> Manage Snippets -> «your_language» и редактируете существующие или добавляете свои сниппеты. Инструкция по работе с ними находится <a href="http://live.gnome.org/Gedit/Plugins/Snippets">здесь</a>. У меня на их разбор ушло минуты 3 и потом еще минут 15 на создание своих собственных. Зато как удобно потом написать что-то типа div, нажать на Tab и получить следующее:<br/></p>
<pre><code class="html">
<div>
</div>

</code></pre>
<p><br/><br />
А при желании можно еще текста добавить, например дополнительных полей id, style и т.д. А также поставить значения по умолчанию и точки, куда курсор будет прыгать при следующем нажатии Tab.<br/><br />
Я работал со сниппетами в Visual Studio, ИМХО в Gedit с ними работать гораздо удобнее. <br/><br />
И да, подобные плагины есть для Emacs, Notepad++ и еще для кучи других редакторов.<br/></p>
<h4>Создание первого проекта</h4>
<p><br/><br />
Все поставлено, все работает. Можно приступать к созданию своего веб-сайта. Заходим в дирректорию с ChicagoBoss и пишем команду:<br/><br />
<code>make app PROJECT=addressbook</code><br/><br />
Да, названием проекта должен быть валидный атом. Атом — это именованная константа. Начинаться название должно только с маленькой буквы, название может содержать только буквы, цифры и символ подчерка.<br/><br />
Фреймворк создает новую директорию, по-умолчанию в домашнем каталоге. Весь проект находится внутри, если возникнет желание переместить/передать кому-то/удалить проект, достаточно будет манипуляций с этим каталогом. Переходим во вновь созданную директорию нашего проекта<br/><br />
<code>cd ../addressbook</code><br/><br />
Весь наш код/ресурсы лежат в каталоге src. Общая структура:<br/><br />
<img src="http://habrastorage.org/storage2/1db/c34/28e/1dbc3428ee3cd2c5f224b167f8f69b2b.png"/><br/><br />
Структура каталога src:<br/><br />
<img src="http://habrastorage.org/storage2/2f5/ec4/43f/2f5ec443f35a2fbc79afb330092f5ce0.png"/><br/><br />
Файлы ресурсов (javascript, css, медиафайлы) лежат в <i>/priv/static/</i>. Подключение файла стилей будет выглядеть так: <br/></p>
<pre><code class="html">
<link rel="stylesheet" href="/static/css/style.css" type="text/css" charset="utf-8" /></code></pre>
<p><br/><br />
Редактируем boss.config, добавляем данные о БД:<br/><br />
 {db_host, «localhost»},<br/><br />
 {db_port, 27017},<br/><br />
 {db_adapter, mongodb},<br/><br />
 {db_database, addressbook},<br/><br />
 {db_write_mode, safe},<br/><br />
 {db_read_mode, master},<br/><br />
Вот так выглядит мой конфиг (и вобще окружающая среда):<br/><br />
<img src="http://habrastorage.org/storage2/f48/d92/dd7/f48d92dd7aa0220ec6cfda20ffd5baf3.jpg"/><br/><br />
Я в первый раз слово addressbook неправильно написал, пришлось потом приложение пересоздавать с правильным именем, потому что к имени привязано многое.<br/><br />
Далее создаем файл address.erl в src/model/. Он нужен для доступа к БД. У меня он выглядит так:<br/></p>
<pre><code class="tex">-module(address, [Id, Firstname, Lastname, Address1, Address2, City, State, Country, Active, CreationTime, ModifictionTime ]).
-compile([export_all]).</code></pre>
<p><br/><br />
Cоздадим контроллер с именем addressbook_main_controller.erl (<i>appname_controllername_controller</i>) и напишем внутри такой код:<br/></p>
<pre><code class="text">-module(addressbook_main_controller, [Req, SessionID]).
-compile([export_all]).

index('GET', [])->{ok, [{data, "Hello World"}]}.</code></pre>
<p><br/><br />
index — это наша функция,<br/><br />
все что находится после &#171;->&#187; является телом функции.<br/><br />
Эта функция будет реагировать на запрос GET и при удачной обработке вернет нашу строку в переменной data.<br/><br />
ok — означает что все прошло хорошо. Для обработки ошибки используется слово error. Выглядеть это может так:<br/></p>
<pre><code class="text">index('GET', [])->
	{ok, [{data, "Hello World"}]};
	{error, Reason}->
			Reason.
</code></pre>
<p><br/><br />
Для того чтобы отобразить вернувшееся значение на странице, в нашей вьюшке нужно будет добавить тег {{data}}. Для проверки создадим наш первый html файл в каталоге /src/view/main/. Назовем его index.html:<br/></p>
<pre><code class="html"><!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />

  </head>
  <body>
<form>
<div id="main">
	  {{data}}
      </div>
</form>

  </body>
</html>
</code></pre>
<p><br/><br />
Последний штрих заключается в настройке маршрутов. Открываем файл /priv/addressbook.routes и дописываем наш новый маршрут (по умолчанию у нас еще нет ни одного маршрута, все строки закомментированы):<br/></p>
<pre><code class="text">{"/", [{controller, "main"}, {action, "index"}]}.</code></pre>
<p><br/><br />
Компилируем наше приложение ./rebar compile<br/><br />
И запускаем ./init-dev.sh<br/><br />
Если теперь перейти в браузер и открыть localhost:8001, можно будет увидеть наш Hello World.<br/><br />
Все последующие изменения, за исключением изменения маршрутов, будут применены без перекомпиляции и перезапуска сервера, т.е. на лету.<br/><br />
<b>Про маршруты:</b> можно жестко указать, при каком адресе какой контроллер и метод вызывать. Либо можно в адресе задавать полный путь вида /[controller name]/[action name]. Т.е. в нашем случае у нас есть контроллер с именем main. Если мы добавим в наш контроллер новый метод с именем create, то вызвать его можно будет, обратившись по адресу localhost:8001/main/create. Либо указав следующий маршрут:<br/></p>
<pre><code class="text">{"/create", [{controller, "main"}, {action, "create"}]}.</code></pre>
<p><br/><br />
И тогда вызов будет выглядеть как localhost:8001/create<br/></p>
<h4>Работа с БД</h4>
<p><br/><br />
Подключение к нашей БД уже состоялось. Вы даже можете выполнять запросы в консоли во время работы веб-сервера. Для этого достаточно перейти в консоль, где мы выполнили команду запуска приложения ./init-dev.sh, нажать, например, Ввод и в новой открытой строчке ввести, например это:<br/></p>
<pre><code class="text">boss_db:find(address, []).</code></pre>
<p><br/><br />
Данная команда выводит все записи, привязанные к модели address. Сейчас там нет ни одной записи (или есть пустая по-умолчанию).<br/><br />
Вы можете ввести <i>boss_db:</i> нажать Tab и посмотреть доступные команды.<br/><br />
[] — означает «параметры». Если внутри скобок пусто, значит вы передаете 0 параметров. В случае с командой find можно получить список записей, у которых firstname=«ivan»:<br/></p>
<pre><code class="text">boss_db:find(address, [{firstname, "ivan"}]).</code></pre>
<p><br/><br />
В консоли можно выполнять множество полезных команд, и не только с БД.<br/></p>
<h4>CRUD</h4>
<p><br/><br />
И так, наша модель готова к работе, теперь в контроллере можно добавлять новые функции. Добавим функцию create, которая будет добавлять новые записи:<br/></p>
<pre><code class="text">create('GET', [])->ok;
create('POST', [])->
	Firstname = Req:post_param("firstname"),
	Lastname = Req:post_param("lastname"),
	Address1 = Req:post_param("address1"),
	Address2 = Req:post_param("address2"),
	City = Req:post_param("city"),
	State = Req:post_param("state"),
	Country = Req:post_param("country"),
	Active = Req:post_param("active"),
	CreationTime = erlang:now(),
	ModificationTime = erlang:now(),
	NewAddress = address:new(id, Firstname, Lastname, Address1, Address2, City, State, Country, Active, CreationTime, ModificationTime),
	case NewAddress:save() of
		{ok, SavedAddress}->
			{redirect, [{action, "index"}]};
		{error, Reason}->
			Reason
	end.
</code></pre>
<p><br/><br />
Я думаю прочитать код для программиста не составляет труда, поэтому объяснять я тут ничего не буду. Единственное что могу сказать, что id создается автоматом.<br/><br />
id — зарезервированное слово.<br/><br />
Id — так можно назвать вашу переменную.<br/><br />
Да, язык регистрозависимый. <br/><br />
Теперь создадим html файл для этого метода. Назовем его create.html:<br/></p>
<pre><code class="html"><!DOCTYPE html>
<html>
   <head>

   </head>
   <body>
<form method="post">
<header></header>
<div id="main">
<table>
<tr>
<td>Frist name</td>
<td>
<input type="text" id="firstname" name="firstname" size="45" maxlength="255" value="" /></td>
</tr>
<tr>
<td>Last name</td>
<td>
<input type="text" id="lastname" name="lastname" size="45" maxlength="255" value="" /></td>
</tr>
<tr>
<td>Address1</td>
<td>
<input type="text" id="address1" name="address1" size="45" maxlength="255" value="" /></td>
</tr>
<tr>
<td>Address2</td>
<td>
<input type="text" id="address2" name="address2" size="45" maxlength="255" value="" /></td>
</tr>
<tr>
<td>City</td>
<td>
<input type="text" id="city" name="city" size="45" maxlength="255" value="" /></td>
</tr>
<tr>
<td>State</td>
<td>
<input type="text" id="state" name="state" size="45" maxlength="255" value="" /></td>
</tr>
<tr>
<td>Country</td>
<td>
<input type="text" id="country" name="country" size="45" maxlength="255" value="" /></td>
</tr>
<tr>
<td>Active</td>
<td>
<input type="checkbox" id="active" name="active" value="true" /></td>
</tr>
</table>

         <button type="submit">Submit</button>
      </div>
</form>

   </body>
</html>
</code></pre>
<p> <br/><br />
Тут важно отметить, что для наших контролов, которые передают значения, нужно указывать и id и name параметры. Каждый из них используется разными частями фрэймворка. По-моему Эван это дело хочет пофиксить и оставить только один обязательный параметр. Кстати, обновления выходят довольно часто, чуть ли не каждую неделю, так что не исключено что к моменту публикации этой статьи фикс уже будет выпущен.<br/><br />
Добавим еще одну функцию для просмотра всех записей в нашей базе (точнее заменим написанную ранее функцию index):<br/></p>
<pre><code class="text">index('GET', [])->Addresses = boss_db:find(address, []),
	{ok, [{addresses, Addresses}]}.
</code></pre>
<p><br/><br />
Также поменяем код нашей index.html страницы:<br/></p>
<pre><code class="html"><!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />

  </head>
  <body>
<form method="post">
<header></header>
<div id="main">
<table cellspacing="0" cellpadding="0">
<tr>
<th>First name</th>
<th>Last name</th>
<th>City</th>
<th>Address1</th>
<th>Address2</th>
<th>State</th>
<th>Country</th>
<th>Active</th>
</tr>

		{% if addresses %}
			{% for address in addresses %}
<tr>
<td>{{address.firstname}}</td>
<td>{{address.lastname}}</td>
<td>{{address.city}}</td>
<td>{{address.address1}}</td>
<td>{{address.address2}}</td>
<td>{{address.state}}</td>
<td>{{address.country}}</td>
<td>{{address.active}}</td>
</tr>

			{% endfor %}
		{% endif %}
	</table>
</div>
</form>

  </body>
</html>
</code></pre>
<p><br/><br />
<b>ChicagoBoss использует систему шаблонов Django, через библиотеку <a href="https://github.com/evanmiller/erlydtl">ErlyDTL</a>. <a href="https://docs.djangoproject.com/en/dev/topics/templates/">The Django Template language</a>.</b><br/><br />
Теперь при обращении по адресам /main/ и /main/create вы получите 2 формы: с вводом и выводом информации из БД.<br/><br />
Для удаления (delete) записи будет достаточно следующей функции в нашем контроллере:<br/></p>
<pre><code class="text">delete('GET', [Id])->
	boss_db:delete(Id),
		{redirect, [{action, "index"}]}.
</code></pre>
<p><br/><br />
Остается только его вызвать <i>localhost:8001/main/delete/[id]</i><br/><br />
Для отображения записи (show), добавим в контроллер эту функцию:<br/></p>
<pre><code class="text">show('GET', [Id])->
	Address = boss_db:find(Id),
		{ok, [{address, Address}]}.
</code></pre>
<p><br/><br />
Создадим view файл show.html:<br/></p>
<pre><code class="html"><!DOCTYPE html>
<html>
   <head>

   </head>
   <body>
<form method="post">
<div id="main">
<table cellspacing="0" cellpadding="0">
			{% if address %}
<tr>
<td>First name</td>
<td>{{address.firstname}}</td>
</tr>
<tr>
<td>Last name</td>
<td>{{address.lastname}}</td>
</tr>
<tr>
<td>City</td>
<td>{{address.city}}</td>
</tr>
<tr>
<td>Address1</td>
<td>{{address.address1}}</td>
</tr>
<tr>
<td>Address2</td>
<td>{{address.address2}}</td>
</tr>
<tr>
<td>State</td>
<td>{{address.state}}</td>
</tr>
<tr>
<td>Country</td>
<td>{{address.country}}</td>
</tr>
<tr>
<td>Modification time</td>
<td>{{address.modification_time}}</td>
</tr>
<tr>
<td>Creation time</td>
<td>{{address.creation_time}}</td>
</tr>
<tr>
<td>Active</td>
<td>{{address.active}}</td>
</tr>

			{% endif %}
			</table>
</div>
</form>

  </body>
</html>
</code></pre>
<p><br/><br />
Редактирование записи — это смесь create и show. Добавим еще две функции в наш контроллер:<br/></p>
<pre><code class="text">edit('GET', [Id])->
	Address = boss_db:find(Id),
		{ok, [{address, Address}]};

edit('POST', [Id])->
	Address = boss_db:find(Id),
	NewAddress = Address:set([{firstname, Req:post_param("firstname")}, {lastname, Req:post_param("lastname")}, {address1, Req:post_param("address1")}, {address2, Req:post_param("address2")}, {city, Req:post_param("city")}, {state, Req:post_param("state")}, {country, Req:post_param("country")}, {active, Req:post_param("active")}, {modification_time, erlang:now()}]),
	case NewAddress:save() of
	{ok, SavedAddress}->
		{redirect, [{action, "index"}]};
	{error, Reason}->
		Reason
	end.
</code></pre>
<p><br/><br />
Важно отметить, что в Erlang все переменные — неизменны! Поэтому сначала приходится получать Address, а затем измененное состояние этой переменной присваивать NewAddress.<br/><br />
Первая функция делает тоже самое, что и функция show, вторая обновляет информацию в БД после нажатия кнопки Submit в форме.<br/><br />
Добавляем эту самую форму edit.html:<br/></p>
<pre><code class="html"><!DOCTYPE html>
<html>
   <head>

   </head>
   <body>
<form method="post">
<table cellspacing="0" cellpadding="0">
		{% if address %}
<tr>
<td>First name</td>
<td>
<input type="text" id="firstname" name="firstname" size="45" maxlength="255" value="{{address.firstname}}" /></td>
</tr>
<tr>
<td>Last name</td>
<td>
<input type="text" id="lastname" name="lastname" size="45" maxlength="255" value="{{address.lastname}}" /></td>
</tr>
<tr>
<td>City</td>
<td>
<input type="text" id="city" name="city" size="45" maxlength="255" value="{{address.city}}" /></td>
</tr>
<tr>
<td>Address1</td>
<td>
<input type="text" id="address1" name="address1" size="45" maxlength="255" value="{{address.address1}}" /></td>
</tr>
<tr>
<td>Address2</td>
<td>
<input type="text" id="address2" name="address2" size="45" maxlength="255" value="{{address.address2}}" /></td>
</tr>
<tr>
<td>State</td>
<td>
<input type="text" id="state" name="state" size="45" maxlength="255" value="{{address.state}}" /></td>
</tr>
<tr>
<td>Country</td>
<td>
<input type="text" id="country" name="country" size="45" maxlength="255" value="{{address.country}}" /></td>
</tr>
<tr>
<td>Active</td>
<td>
<input type="checkbox" id="active" name="active" value="{{address.active}}" /></td>
</tr>

		{% endif %}
		</table>

		<button type="submit">Submit</button>
	</form>

  </body>
</html>
</code></pre>
<p><br/><br />
Ну вот собственно и все, наш CRUD готов.<br/></p>
<h4>Дополнение</h4>
<p><br/><br />
Пока писал статью, успел прикрутить логин, регистрацию, список зарегистрированных пользователей, чат, валидацию ввода, а также <a href="https://github.com/evanmiller/ChicagoBoss/wiki/Admin-interface">админку</a> (весь код сайта лежит на github, ссылка в разделе Ресурсы).<br/><br />
Чат без всяких наворотов, исключительно для теста и все еще содержит баги, особенно при работе под IE, поэтому специально для него я запретил логин, иначе он вызывает некоторые проблемы. Чатиться с ним можно, сервер не падает, но не комфортно. У меня задача показать работу Erlang, а не проблемы Ajax в IE решать.<br/><br />
<a href="https://github.com/evanmiller/ChicagoBoss/wiki/Admin-interface">Админку</a> можно установить на любой новый сайт, там работы минут на 5.<br/><br />
А также поигрался с шаблонами. В итоге у меня получился один мастер-шаблон, который выглядит вот так:<br/></p>
<pre><code class="html"><!DOCTYPE html>
<html lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="/static/css/style.css" type="text/css" charset="utf-8" />

    {% block res %} {% endblock %}
</head>

<body>
<header>
		{% if person %}
			Hello, {{person.name}}
			(<a href="/user/logout">Quick, Log Me Out!</a>)
			
		{% endif %}
		Your IP: {{ip}}
	</header>
<nav>
<ul class="nav">
<li class="nav"><a href="/">Home</a></li>
<li class="nav"><a href="/create">Create</a></li>
<li class="nav"><a href="/chat/live/public">Chat</a></li>
<li class="nav"><a href="/user/login">Login</a></li>
<li class="nav"><a href="/user/showall">Users</a></li>
</ul>
</nav>
<section>
	  {% block content %}{% endblock %}
	</section>
<footer>
	   {% block footer %}{% endblock %}
	</footer>

</body>
</html>
</code></pre>
<p><br/><br />
И вот так теперь выглядит мой show.html:<br/></p>
<pre><code class="html">{% extends "layout/application.html" %}

{% block title %}My addressbook{% endblock %}
{% block content %}
<table cellspacing="0" cellpadding="0">
	{% if address %}
<tr>
<td>First name</td>
<td>{{address.firstname}}</td>
</tr>
<tr>
<td>Last name</td>
<td>{{address.lastname}}</td>
</tr>
<tr>
<td>City</td>
<td>{{address.city}}</td>
</tr>
<tr>
<td>Address1</td>
<td>{{address.address1}}</td>
</tr>
<tr>
<td>Address2</td>
<td>{{address.address2}}</td>
</tr>
<tr>
<td>State</td>
<td>{{address.state}}</td>
</tr>
<tr>
<td>Country</td>
<td>{{address.country}}</td>
</tr>
<tr>
<td>Modification time</td>
<td>{{address.modification_time}}</td>
</tr>
<tr>
<td>Creation time</td>
<td>{{address.creation_time}}</td>
</tr>
<tr>
<td>Active</td>
<td>{{address.active}}</td>
</tr>

	{% endif %}
	</table>

{% endblock %}
</code></pre>
<p><br/><br />
Получается один каркас и разный контент.<br/><br />
Подробнее о Django шаблонах можно почитать на официальном сайте, ссылка есть в Ресурсах ниже.<br/><br />
Еще ChicagoBoss имеет в своем арсенале свои собственные шаблоны. Немного ниформации о них можно найти на <a href="http://chicagoboss.org/api-view.html">официальном сайте</a>. Там ничего сложного нет. Просто замена часто используемого кода тегами. Ну и еще некоторые плюшки.<br/></p>
<h4>Итоги</h4>
<p><br/><br />
Здесь будут итоги работы сервера по прошествии двух дней.<br/></p>
<h4>Ресурсы</h4>
<p><br/><br />
<a href="http://erlang-test.no-ip.biz">Ссылка на тестовый сайт</a><br/><br />
<a href="https://github.com/iSeiryu/Chicagoboss-Habratest">Ссылка на исходники</a><br/><br />
<a href="http://chicagoboss.org">Официальный веб-сайт ChicagoBoss</a>. <i>На этом же сайте вы найдете API документацию, ссылки на Wiki, обучение работы с фреймворком.</i><br/><br />
<a href="http://www.erlang.org/">Официальный веб-сайт Erlang</a><br/><br />
<a href="http://erlanger.ru/">Русское сообщество Erlang</a><br/><br />
<a href="http://learnyousomeerlang.com/">Отличный сайт для изучения Erlang</a><br/><br />
<a href="http://erldocs.com/">Erlang документация</a><br/><br />
<a href="http://www.erlang-solutions.com/section/132/download-erlang-otp">Erlang solutions</a>. <i>Отсюда можно скачать нужную версию Erlang.</i><br/><br />
Обучающее видео от Эвана: <a href="http://www.youtube.com/watch?v=pQq1_SGhcv0">эпизод 1</a>, <a href="http://www.youtube.com/watch?v=E7IKc8--_4Y">эпизод 2</a>, <a href="http://www.youtube.com/watch?v=fn8K0BXiaVI">эпизод 3</a><br/><br />
<a href="https://github.com/evanmiller/ChicagoBoss/wiki/Ruby-on-Rails-Versus-Chicago-Boss">Различия между Ruby on Rails и ChicagoBoss</a><br/><br />
<a href="http://blog.mysyncpad.com/post/2073441622/node-js-vs-erlang-syncpads-experience">Сравнение Nodejs и Erlang</a><br/><br />
<a href="http://www.metabrew.com/article/a-million-user-comet-application-with-mochiweb-part-1">How to serve a million users!</a><br/><br />
<a href="https://docs.djangoproject.com/en/dev/topics/templates/">The Django Template language</a>. <i>Система шаблонов Django.</i><br/><br />
<a href="http://groups.google.com/group/chicagoboss">ChicagoBoss Google Group</a></p>
<p>© <a href="http://m.habrahabr.ru/post/139316/">Habrahabr.ru</a></p>
]]></content:encoded>
			<wfw:commentRss>http://vwlab.ru/post/226/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Гугл использует reCaptcha для распознавания названий улиц и номеров домов</title>
		<link>http://vwlab.ru/post/224/</link>
		<comments>http://vwlab.ru/post/224/#comments</comments>
		<pubDate>Fri, 30 Mar 2012 13:38:07 +0000</pubDate>
		<dc:creator>Niko</dc:creator>
				<category><![CDATA[Разное]]></category>

		<guid isPermaLink="false">http://vwlab.ru/?p=224</guid>
		<description><![CDATA[Последнее время многие пользователи стали замечать reCaptcha с кусками фотографий, содержащих номера домов, названия улиц и даже дорожные знаки. Представитель Google подтвердил, что они проводят эксперименты над людьми по улучшению качества своей БД информации об адресах и предприятиях с помощью &#8230;<p class="read-more"><a href="http://vwlab.ru/post/224/">Читать далее &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<p>Последнее время многие пользователи стали замечать <a href="http://habrahabr.ru/post/121010/">reCaptcha</a> с кусками фотографий, содержащих номера домов, названия улиц и даже дорожные знаки. <br/><br />
<img src="http://habrastorage.org/storage2/6e3/aea/bb5/6e3aeabb5a2c8705e49c8d145ebe8b8d.png"/><br/><br />
Представитель Google подтвердил, что они проводят эксперименты <s>над людьми</s> по улучшению качества своей БД информации об адресах и предприятиях с помощью распознавания фотографий Street View.<br/><br />
По результатам этих <s>бесчеловечных</s> опытов будет принято решение по использованию reCaptcha для других задач.<br/><br />
 <span id="more-224"></span> <br/><br />
Небольшая коллекция таких капч, собранная пользователем форума <a href="http://www.blackhatworld.com/blackhat-seo/blackhat-lounge/423026-something-interesting-ive-noticed-recently-recaptcha.html">blackhatworld.com</a>:<br/><br />
<a href="http://habrastorage.org/storage2/1bd/2cf/854/1bd2cf854eccd1b72efb14d6b71216b1.jpg"><img src="http://habrastorage.org/storage2/414/65f/7a4/41465f7a4ec523ec03ae43e0ecbf08e4.jpg"/></a><br/><br />
(кликабельно)</p>
<p>© <a href="http://m.habrahabr.ru/post/141024/">Habrahabr.ru</a></p>
]]></content:encoded>
			<wfw:commentRss>http://vwlab.ru/post/224/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>LG начинает выпуск гибких дисплеев</title>
		<link>http://vwlab.ru/post/222/</link>
		<comments>http://vwlab.ru/post/222/#comments</comments>
		<pubDate>Fri, 30 Mar 2012 13:37:53 +0000</pubDate>
		<dc:creator>Niko</dc:creator>
				<category><![CDATA[Разное]]></category>

		<guid isPermaLink="false">http://vwlab.ru/?p=222</guid>
		<description><![CDATA[Южнокорейская компания LG Electronics объявила о начале серийного производства гибких экранов для электронных книг. В отличие от большинства современных дисплеев e-ink, в новинке будет использоваться не стеклянная, а пластиковая подложка похожая на «защитную пленку» для экранов сотовых телефонов. Пластиковые экраны &#8230;<p class="read-more"><a href="http://vwlab.ru/post/222/">Читать далее &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<p>Южнокорейская компания LG Electronics объявила о начале серийного производства гибких экранов для электронных книг. В отличие от большинства современных дисплеев e-ink, в новинке будет использоваться не стеклянная, а пластиковая подложка похожая на «защитную пленку» для экранов сотовых телефонов. <br/><br />
<img src="http://www.blogcdn.com/www.engadget.com/media/2012/03/ep.jpg" alt="image"/><br/><br />
Пластиковые экраны будут гибкими, более тонкими и прочными, чем их стеклянные собратья. В LG подчеркивают, что новый дисплей выдержал испытания на прочность, полностью сохранив работоспособность при падении с полутораметровой высоты.<br/><br />
Диагональ экрана составит 6 дюймов, а разрешение — 1024 на 768 пикселей. Он будет на треть тоньше, чем стеклянные экраны e-ink и в два раза легче (14 граммов). LG будет поставлять экраны производителям электроники в Китае. Отгрузка готовых «читалок» с гибкими экранами в Европу стартует в начале апреля.<br/><br />
 <span id="more-222"></span> <br/><br />
Старое видео с презентации прототипа:<br/><br />
<iframe width="560" height="349" src="http://www.youtube.com/embed/hZCiqkWCLqw" frameborder="0" allowfullscreen></iframe><br/><br />
Кстати, госкорпорация «Роснано» разрабатывает экраны с аналогичными свойствами и собирается открыть завод по их производству в Зеленограде. В конце 2013 года.</p>
<p>© <a href="http://m.habrahabr.ru/post/141047/">Habrahabr.ru</a></p>
]]></content:encoded>
			<wfw:commentRss>http://vwlab.ru/post/222/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Microsoft перевел в Open Source еще одну часть стека технологий ASP.NET</title>
		<link>http://vwlab.ru/post/220/</link>
		<comments>http://vwlab.ru/post/220/#comments</comments>
		<pubDate>Fri, 30 Mar 2012 13:37:36 +0000</pubDate>
		<dc:creator>Niko</dc:creator>
				<category><![CDATA[Разное]]></category>

		<guid isPermaLink="false">http://vwlab.ru/?p=220</guid>
		<description><![CDATA[Пару дней назад Microsoft анонсировал что еще один компонент .Net Framework будет доступен для скачивания в исходных текстах по лицензии Apache License 2.0. Таким образом, теперь весь ASP.NET стек распространяется в исходных текстах, включая Razor Engine, System.Json, Web API и &#8230;<p class="read-more"><a href="http://vwlab.ru/post/220/">Читать далее &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<p><img src="http://habrastorage.org/storage2/411/514/a2b/411514a2bd36dee09a6acc3af53a7f3f.png" align="left"/>Пару дней назад Microsoft анонсировал что еще один компонент .Net Framework будет доступен для скачивания в исходных текстах по лицензии <a href="http://aspnetwebstack.codeplex.com/license">Apache License 2.0</a>. Таким образом, теперь весь ASP.NET стек распространяется в исходных текстах, включая Razor Engine, System.Json, Web API и Web Pages. Он доступен как для скачивания так и для просмотра истории изменения. С этим релизом вся группа проектов будет работать по правилам Open Source, делая возможным включения своего собственного функционала и исправления ошибок любым членом сообщества, при полной поддержке кода со стороны Microsoft. <br/><br />
 <span id="more-220"></span> <br/></p>
<h4>Mono и новые стеки</h4>
<p><br/><br />
Мы импортировали копию дерева GIT с <a href="http://aspnetwebstack.codeplex.com/">Codeplex </a> в <a href="http://github.com/mono/">GitHub&#8217;s Mono organization</a> в модуль <a href="https://github.com/mono/aspnetwebstack">aspnetwebstack</a>.<br/><br />
Модуль Mono на данный момент имеет зависимость от модуля aspnetwebstack, так что когда вы в следующий раз выполните команду autogen.sh, то получите полную копию aspnetwebstack.<br/><br />
Также, с сегодняшнего дня мы заменили нашу реализацию System.Json (которая, изначально, была сделана для Moonlight) реализацией от Microsoft.<br/><br />
Другие библиотеки, такие как Razor будут следующими, т.к. по сути их импортирование тривиально. Однако есть проблема: ASP.NET MVC 4 сейчас зависит от нашей реализации стека ASP.NET, в которой необходимо доделать поддержку асинхронности.<br/><br />
Наша копия на github будет содержать главным образом изменения, направленные на интеграцию стека с Mono. Если мы будем делать какие-либо изменения в интеграции, мы будем отдавать код напрямую в Microsoft, чтобы тот включил его в проект aspnetwebstack. <br/></p>
<h4>Расширение Mono&#8217;s ASP.NET Engine</h4>
<p><br/><br />
Новая версия движка ASP.NET поддерживает асинхронное программирование C# 5.0 и это изменение требует поддержки со стороны ядра ASP.NET<br/><br />
На текущий момент мы не ожидаем что кто-нибудь будет работать над расширением функционала ядра ASP.NET, однако вы можете посоветовать новых и полных энтузиазма разработчиков, которые любят асинхронное программирование, чтобы сделать эти возможности в Моно</p>
<p>© <a href="http://m.habrahabr.ru/post/141052/">Habrahabr.ru</a></p>
]]></content:encoded>
			<wfw:commentRss>http://vwlab.ru/post/220/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>$1 млн убытков за оригинальную архитектуру Apple Store</title>
		<link>http://vwlab.ru/post/218/</link>
		<comments>http://vwlab.ru/post/218/#comments</comments>
		<pubDate>Fri, 30 Mar 2012 13:37:10 +0000</pubDate>
		<dc:creator>Niko</dc:creator>
				<category><![CDATA[Разное]]></category>

		<guid isPermaLink="false">http://vwlab.ru/?p=218</guid>
		<description><![CDATA[83-летняя жительница Нью-Йорка Эвелин Пасволл потребовала от Apple компенсации в миллион долларов. Пожилая женщина собиралась войти в один из магазинов компании Apple в Нью-Йорке, но не поняла, что подходит к стеклянной двери, и ударилась о нее лицом. Удар оказался сильным, &#8230;<p class="read-more"><a href="http://vwlab.ru/post/218/">Читать далее &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<p>83-летняя жительница Нью-Йорка Эвелин Пасволл потребовала от Apple компенсации в миллион долларов.<br/><br />
Пожилая женщина собиралась войти в один из магазинов компании Apple в Нью-Йорке, но не поняла, что подходит к стеклянной двери, и ударилась о нее лицом. Удар оказался сильным, и врачи констатировали перелом носа старушки.<br/><br />
<img src="http://habrastorage.org/storage2/3fe/ba9/cc5/3feba9cc503d1ac05c1f81bad858913b.jpg"/><br/><br />
Помимо оплаты лечения клиентки и компенсации морального ущерба адвокат Дерек Смит требует, чтобы компания делала отметки на стеклянных дверях своих магазинов. <br/><br />
«Хотя Apple и стремится привлечь покупателей современной архитектурой, компания не должна забывать при этом об угрозе, которую такие решения могут представлять для некоторых людей», — считает он. Дерек Смит подчеркнул, что пожилые люди — тоже покупатели, хотя Apple и ориентируется на молодежь.<br/><br />
Так что не отправляй в Apple Store свою бабушку одну, %username%.<br/><br />
 <span id="more-218"></span> </p>
<p>© <a href="http://m.habrahabr.ru/post/141065/">Habrahabr.ru</a></p>
]]></content:encoded>
			<wfw:commentRss>http://vwlab.ru/post/218/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Пишем веб-эмулятор терминала на Go, используя Websocket</title>
		<link>http://vwlab.ru/post/216/</link>
		<comments>http://vwlab.ru/post/216/#comments</comments>
		<pubDate>Fri, 30 Mar 2012 13:36:49 +0000</pubDate>
		<dc:creator>Niko</dc:creator>
				<category><![CDATA[Разное]]></category>

		<guid isPermaLink="false">http://vwlab.ru/?p=216</guid>
		<description><![CDATA[Что будем писать В прошлой статье мы писали простенький эмулятор терминала на PHP. Я думаю, теперь время написать что-нибудь более серьезное, на вебсокетах. Какой язык использовать для работы с вебсокетами..? Питон..? Руби..? JavaScript..? Нет! Раз уж зарелизился Go 1, давайте &#8230;<p class="read-more"><a href="http://vwlab.ru/post/216/">Читать далее &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<h4>Что будем писать</h4>
<p><br/><br />
В <a href="http://habrahabr.ru/post/139878/">прошлой статье</a> мы писали простенький эмулятор терминала на PHP. Я думаю, теперь время написать что-нибудь более серьезное, на вебсокетах. Какой язык использовать для работы с вебсокетами..? Питон..? Руби..? JavaScript..? Нет! Раз уж зарелизился Go 1, давайте на нём и напишем <img src='http://vwlab.ru/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> . Я постараюсь не повторяться и не писать сюда целиком код. Я приведу лишь интересные, на моей взгляд, фрагменты.<br/></p>
<h4>Демо</h4>
<p><br/><br />
Как и в прошлый раз, я не готов вам предоставить доступ к какому-либо серверу, поэтому я ограничусь видео (хостовая ОС — FreeBSD):<br/><br />
<iframe width="560" height="349" src="http://www.youtube.com/embed/dCqXSVPmlAM" frameborder="0" allowfullscreen></iframe><br/><br />
Исходный код веб-терминала доступен <a href="https://github.com/YuriyNasretdinov/WebTerm">на гитхабе</a>. Компилировать вебсокет-демон необходимо самостоятельно (командой <code>go build -o ws</code>) — это сделано в качестве небольшой защиты от «скрипт киддисов». Если кто-нибудь захочет выложить интерактивное демо терминала, буду очень признателен, бинарник для демона могу прислать отдельно.<br/><br />
 <span id="more-216"></span> <br/></p>
<h4>Ингредиенты</h4>
<p><br/><br />
Итак, нам понадобятся:<br/></p>
<ul>
<li>Установленный <a href="http://golang.org/doc/install">компилятор языка Go 1</a></li>
<li>Библиотека websocket (<code>go get code.google.com/p/go.net/websocket</code>)</li>
<li>Браузер, поддерживающий последнюю спецификацию Websocket (например последние Firefox и Chrome)</li>
<li>Любой веб-сервер с PHP (для автоматического запуска демона)</li>
</ul>
<p><br/></p>
<h4>Пишем вебсокет-демон</h4>
<p><br/><br />
В нашем демоне будет объединен вебсокет-сервер и эмулятор псевдотерминала. Несмотря на то, что нативной поддержки работы с псевдотерминалами в Go нет, этот язык легко интегрируется с Си, поэтому мы будем использовать соответствующие вызовы на Си для непосредственной работы с псевдотерминалом.<br/></p>
<h5>Работа с вебсокетами</h5>
<p><br/></p>
<pre><code class="go">package main
import (
	"code.google.com/p/go.net/websocket"
	"http"
	"log"
)
// наша функция-обработчик соединений
func PtyServer(ws *websocket.Conn) {
// ws — это название переменной типа *websocket.Conn, поддерживает
// простые вызовы Read() и Write() для чтения/записи в сокет
}

func main() {
	http.Handle("/ws", websocket.Handler(PtyServer)) // обрабатываем запросы на "/ws" как вебсокет
	log.Fatal(http.ListenAndServe(":12345", nil)) // слушаем на порту 12345
}
</code></pre>
<p><br/></p>
<h5>Работа с псевдотерминалом</h5>
<p><br/><br />
Напишем обвязку для forkpty() и ioctl() (в ioctl() мы будем менять размеры «окна» терминала): Go хоть и неплохо интегрируется с Си, но не понимает, что pid_t и int — это одно и то же, а также не умеет работать с переменным количеством параметров в функциях на Си.<br/></p>
<pre><code class="go">package main
/*
#cgo LDFLAGS: -lutil
#include <stdlib.h>
#include <sys/ioctl.h>
#...зависимые от системы заголовки и флаги...
int goForkpty(int *amaster, struct winsize *winp) {
	return forkpty(amaster, NULL, NULL, winp);
}
int goChangeWinsz(int fd, struct winsize *winp) {
	return ioctl(fd, TIOCSWINSZ, winp);
}
*/
import "C"
</code></pre>
<p><br/><br />
В обработчике это используем:<br/></p>
<pre><code class="go">func PtyServer(ws *websocket.Conn) {
	cols, rows := 80, 24
	var winsz = new(C.struct_winsize)
	winsz.ws_row = C.ushort(rows);
	winsz.ws_col = C.ushort(cols);
	winsz.ws_xpixel = C.ushort(cols * 9);
	winsz.ws_ypixel = C.ushort(rows * 16);
	cpttyno := C.int(-1)
	pid := int(C.goForkpty(&#038;cpttyno, winsz))
	pttyno := int(cpttyno)
	// ...
}
</code></pre>
<p><br/></p>
<h5>Общение между вебсокетом и псевдотерминалом</h5>
<p><br/><br />
Дальше мы должны запустить, к примеру, bash и посылать вывод с соответствующего дескриптора (pttyno) в вебсокет, и наоборот, ввод с вебсокета посылать на вход pttyno — это просто. Проблема возникает тогда, когда к нам от псевдотерминала приходит незавершенная последовательность UTF-8. Мы можем читать с псевдотерминала только блоками (скажем, по 2 Кб) и конец блока может «разрезать» UTF-8 символ на 2 части — этот «обрезок» не должны посылать браузеру, иначе он просто проигнорирует этот фрагмент. Вот небольшой фрагмент кода, который корректно обрабатывает эту ситуацию:<br/></p>
<pre><code class="go">for end = buflen - 1; end >= 0; end-- {
	if utf8.RuneStart(buf[end]) {
		ch, width := utf8.DecodeRune(buf[end:buflen])
		if ch != utf8.RuneError {
			end += width
		}
		break
	}
}
</code></pre>
<p><br/><br />
Мы должны найти в конце буфера (buf) байт, который может служить началом UTF-8 символа (в терминологии Go — rune), после чего посмотреть, цел ли этот символ. Если с последним символом всё хорошо, то возвращаем «конец» буфера обратно, иначе — уменьшаем размер буфера так, чтобы там остались только целые символы.<br/></p>
<h4>Отображаем вывод с псевдотерминала в браузер</h4>
<p><br/><br />
Сначала для отображения вывода я использовал JSLinux, но его автор не разрешает модификацию и распространение кода своих библиотек, поэтому давайте возьмем библиотеку <a href="https://github.com/selectel/pyte">selectel/pyte</a>, написанную товарищами из Селектела… Погодите, она на питоне <img src='http://vwlab.ru/wp-includes/images/smilies/icon_sad.gif' alt=':(' class='wp-smiley' /> ! Ещё одна зависимость нам ни к чему, давайте <a href="https://github.com/YuriyNasretdinov/pyte">перепишем её на Javascript</a> <img src='http://vwlab.ru/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> ! Порт с питона не идеален, к тому же я не особый знаток питона, но свою работу оно выполняет — Midnight Commander запускается и работает без проблем.<br/></p>
<h4>Принимаем ввод пользователя</h4>
<p><br/><br />
Для того, чтобы принимать пользовательский ввод, я всё же заимствовал некоторое количество кода у автора JSLinux, основные принципы <a href="http://unixpapa.com/js/key.html">описаны здесь</a>. Я также добавил возможность вставить какой-нибудь текст в поле ввода внизу (например, пароли) и добавил маппинги для клавиш F1 — F12, а также для Alt + (стрелочка налево/направо). Как оказалось, значения вводимых символов для F-клавиш зависят от переменной окружения $TERM и для vt100 вообще не определены, поскольку в VT100 их не было на клавиатуре <img src='http://vwlab.ru/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> . Поскольку для вывода используется pyte, переменная окружения $TERM должна быть равна linux, поэтому и маппинги этих клавиш мы будем использовать для этого терминала.<br/></p>
<h4>Запускаем демона «по требованию»</h4>
<p><br/><br />
Я реализовал вебсокет-демон таким образом, что он выходит через минуту после последнего коннекта, поэтому было бы удобно, если бы скрипт сам запускал вебсокет-демона, когда мы открываем страничку с терминалом. Код на PHP для этого очень простой:<br/></p>
<pre><code class="php"><?php
$PORT = 13923; // port terminal daemon will be run at
system('exec nohup ./ws '.$PORT.' </dev/null >>ws.log 2>&#038;1 &#038;');
</code></pre>
<p><br/><br />
Если вы не знаете, что такое <code>exec</code>, я объясню: это специальная builtin-команда в любых UNIX шеллах, которая заставляет shell заменить себя на вызываемый процесс. То есть, у нас не будет висеть «лишний» процесс <code>sh -c ./ws ...</code>.<br/></p>
<h4>Моменты, о которых я не рассказал</h4>
<p><br/><br />
Я не рассказал о следующих деталях в <a href="https://github.com/YuriyNasretdinov/WebTerm">реализации</a>:<br/></p>
<ul>
<li>протокол общения с клиентом был немного усложнен для поддержки ресайза окна, но появился баг с вводом русских букв</li>
<li>вебсокет-демон защищен паролем, который генерируется автоматически при запуске и используется при соединении</li>
<li>используется свой bashrc, чтобы установить нужные настройки терминала</li>
<li>поскольку на сервере не происходит никакой отрисовки, а только посылаются байты, демон нагружает сервер сравнимо с sshd (т.е. загрузка CPU близка к нулю)</li>
<li>реализация pyte на javascript работает исключительно быстро: нет видимой задержки при старте Midnight Commander, пропускная способность составляет несколько тысяч строк текста в секунду</li>
<li>при закрытии окна браузера сессия корректно завершается</li>
<li>один демон может обслуживать много клиентов одновременно без проблем</li>
<li>за счёт использования тега <audio> и звуков из ubuntu, терминал умеет «бибикать» <img src='http://vwlab.ru/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </li>
</ul>
<p><br/></p>
<h4>Проект на github</h4>
<p><br/><br />
Для интересующихся, повторю ссылки на гитхаб:<br/><br />
<a href="https://github.com/YuriyNasretdinov/WebTerm">github.com/YuriyNasretdinov/WebTerm</a> — эмулятор терминала, о котором я рассказал в статье<br/><br />
<a href="https://github.com/YuriyNasretdinov/pyte">github.com/YuriyNasretdinov/pyte</a> — моя реализация библиотеки selectel/pyte на Javascript (не принятая разработчиками, к сожалению)</p>
<p>© <a href="http://m.habrahabr.ru/post/141068/">Habrahabr.ru</a></p>
]]></content:encoded>
			<wfw:commentRss>http://vwlab.ru/post/216/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>jQuery Plugin — Scroll Sliders или Ползунки beta</title>
		<link>http://vwlab.ru/post/212/</link>
		<comments>http://vwlab.ru/post/212/#comments</comments>
		<pubDate>Sun, 15 Jan 2012 15:33:41 +0000</pubDate>
		<dc:creator>Niko</dc:creator>
				<category><![CDATA[Разное]]></category>

		<guid isPermaLink="false">http://vwlab.ru/?p=212</guid>
		<description><![CDATA[Введение В прошлой статье, вот ссылочка, я обещал выложить плагин по «ползункам», доработав его учитывая большинство комментариев получилось «это»: Из-за нехватки времени фичи для touch устройств были вырезаны, так что пока только для владельцев mouse устройств. Статью публикую для критики, &#8230;<p class="read-more"><a href="http://vwlab.ru/post/212/">Читать далее &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<h4>Введение</h4>
<p><br/><br />
В прошлой статье, <a href="http://habrahabr.ru/blogs/jquery/135952/">вот ссылочка</a>, я обещал выложить плагин по «ползункам», доработав его учитывая большинство комментариев получилось «это»:<br/><br />
<img src="http://clip2net.com/clip/m0/1326506945-clip-24kb.png" alt="image"/><br/><br />
Из-за нехватки времени фичи для touch устройств были вырезаны, так что пока только для владельцев mouse устройств. Статью публикую для критики, баг-репортов ну и конечно же ваших пожеланий.<br/><br />
 <span id="more-212"></span> <br/></p>
<h4>jQuery Plugin — Scroll Sliders</h4>
<p><br/><br />
Как всегда мои наработки имеют кучу настроек, так что начну пожалуй с них. Вот, немалый список:<br/></p>
<blockquote><table>
<tr>
<td><b>slider</b></td>
<td><i>Default: true</i></td>
<td>Вкл/Выкл функционал ползунка</td>
</tr>
<tr>
<td><b>sliderOuter</b></td>
<td><i>Default: true</i></td>
<td>Вкл/Выкл функционал блока вокруг ползунка (при нажатии на блок в котором расположен ползунок, ползунок «телепортируется» к нам)</td>
</tr>
<tr>
<td><b>speedMove</b></td>
<td><i>Default: 200</i></td>
<td>Время прохождения 1го элемента при использовании ползунка с его максимальным отклонением</td>
</tr>
<tr>
<td><b>speedMoveScroller</b></td>
<td><i>Default: 300</i></td>
<td>Временно не используется</td>
</tr>
<tr>
<td><b>speedMoveControl</b></td>
<td><i>Default: 250</i></td>
<td>Время прохождения 1го элемента при использовании кнопок вперед/назад</td>
</tr>
<tr>
<td><b>speedMoveWheel</b></td>
<td><i>Default: 150</i></td>
<td>Время прохождения 1го элемента при прокрутке колесом мыши</td>
</tr>
<tr>
<td><b>speedRevert</b></td>
<td><i>Default: 220</i></td>
<td>Время возврата ползунка в среднее положение</td>
</tr>
<tr>
<td><b>speedAnimation</b></td>
<td><i>Default: 13</i></td>
<td>Интервал для выполнения анимаций</td>
</tr>
<tr>
<td><b>revert</b></td>
<td><i>Default: true</i></td>
<td>Вкл/Выкл возвращение ползунка в центральное положение</td>
</tr>
<tr>
<td><b>sliderInverse</b></td>
<td><i>Default: false</i></td>
<td>Вкл/Выкл инверсию для ползунка</td>
</tr>
<tr>
<td><b>sliderOuterDiv</b></td>
<td><i>Default: &#8216;.scroll-outer&#8217;</i></td>
<td>Блок-рамка для ползунка</td>
</tr>
<tr>
<td><b>sliderToddlerDiv</b></td>
<td><i>Default: &#8216;.scroll-toddler&#8217;</i></td>
<td>Блок-ползунок… хм забавное описание</td>
</tr>
<tr>
<td><b>control</b></td>
<td><i>Default: true</i></td>
<td>Вкл/Выкл функционал для кнопок управления</td>
</tr>
<tr>
<td><b>controlNext</b></td>
<td><i>Default: &#8216;.scroll-control .next&#8217;</i></td>
<td>Блок-кнопка управления «вперед»</td>
</tr>
<tr>
<td><b>controlPrev</b></td>
<td><i>Default: &#8216;.scroll-control .prev&#8217;</i></td>
<td>Блок-кнопка управления «назад»</td>
</tr>
<tr>
<td><b>controlRevert</b></td>
<td><i>Default: false</i></td>
<td>Вкл/Выкл инверсию для кнопок управления</td>
</tr>
<tr>
<td><b>scroller</b></td>
<td><i>Default: true</i></td>
<td>Вкл/Выкл функционал скролла</td>
</tr>
<tr>
<td><b>scrollerOuter</b></td>
<td><i>Default: true</i></td>
<td>Вкл/Выкл функционал вокруг скролла (при нажатии на блок в котором расположен скролл, скролла «телепортируется» к нам)</td>
</tr>
<tr>
<td><b>mouseWheel</b></td>
<td><i>Default: true</i></td>
<td>Вкл/Выкл функционал колесика мыши</td>
</tr>
<tr>
<td><b>mouseWheelRevert</b></td>
<td><i>Default: false</i></td>
<td>Вкл/Выкл инверсию для колесика мыши</td>
</tr>
<tr>
<td><b>mouseWheelsDiv</b></td>
<td><i>Default: &#8216;.scroll-positions, .block-for-scroll&#8217;</i></td>
<td>Блоки в которых будет активен функционал скролла</td>
</tr>
<tr>
<td><b>scrollerOuterDiv</b></td>
<td><i>Default: &#8216;.scroll-positions&#8217;</i></td>
<td>Блок скролла</td>
</tr>
<tr>
<td><b>scrollerToddlerDiv</b></td>
<td><i>Default: &#8216;.scroll-positioner&#8217;</i></td>
<td>Блок-указатель скролла</td>
</tr>
<tr>
<td><b>slideDiv</b></td>
<td><i>Default: &#8216;.block-for-scroll&#8217;</i></td>
<td>Блок который будет имитировать наши перемещения им мы и будем орудовать</td>
</tr>
<tr>
<td><b>slideOuterDiv</b></td>
<td><i>Default: &#8216;.block-outer</i></td>
<td>Рамка внутри которой всё будет происходит</td>
</tr>
<tr>
<td><b>slideWidthDiv</b></td>
<td><i>Default: &#8216;.block-for-scroll-inter&#8217;</i></td>
<td>Сам блок внутри которого само содержимое</td>
</tr>
<tr>
<td><b>slideLiClass</b></td>
<td><i>Default: &#8216;li.li&#8217;</i></td>
<td>элемент внутрених списков</td>
</tr>
</table>
</blockquote>
<p><br/><br />
Использовать плагин довольно таки просто, он имеет только один метод scrollsliders:<br/></p>
<blockquote><p>$(&#8216;.my-scrolled-div&#8217;).scrollsliders();<br/>
</p></blockquote>
<p><br/><br />
или с параметрами ( можно и больше ^_^ ):<br/></p>
<blockquote><p>$(&#8216;.my-scrolled-div&#8217;).scrollsliders({<br/><br />
 speedMove: 200,<br/><br />
 speedMoveScroller: 300,<br/><br />
 speedMoveControl: 250,<br/><br />
 speedMoveWheel: 150,<br/><br />
 speedMoveRevert: 220,<br/><br />
 speedRevert: 300<br/><br />
 });<br/>
</p></blockquote>
<p><br/><br />
Скелет для этого тоже довольно таки прост:<br/></p>
<blockquote><p> <font color="#009900"><<font color="#000000">div</font> <font color="#000066">class</font><font color="#66cc66">=</font><font color="#ff0000">&#171;my-scrolled-div&#187;</font>></font><br/><br />
 <font color="#009900"><<font color="#000000">div</font> <font color="#000066">class</font><font color="#66cc66">=</font><font color="#ff0000">&#171;scroll-positions&#187;</font>></font><br/><br />
 <font color="#009900"><<font color="#000000">div</font> <font color="#000066">class</font><font color="#66cc66">=</font><font color="#ff0000">&#171;scroll-positioner&#187;</font>></font><br/><br />
 <font color="#009900"><<font color="#000000">div</font> <font color="#000066">class</font><font color="#66cc66">=</font><font color="#ff0000">&#171;scroll-positioner-inter&#187;</font>></font><br/><br />
 <font color="#009900"><<font color="#66cc66">/</font><font color="#000000">div</font>></font><br/><br />
 <font color="#009900"><<font color="#66cc66">/</font><font color="#000000">div</font>></font><br/><br />
 <font color="#009900"><<font color="#66cc66">/</font><font color="#000000">div</font>></font><br/><br />
 <font color="#009900"><<font color="#000000">div</font> <font color="#000066">class</font><font color="#66cc66">=</font><font color="#ff0000">&#171;block-outer&#187;</font>></font><br/><br />
 <font color="#009900"><<font color="#000000">div</font> <font color="#000066">class</font><font color="#66cc66">=</font><font color="#ff0000">&#171;block-for-scroll&#187;</font>></font><br/><br />
 <font color="#009900"><<font color="#000000">div</font> <font color="#000066">class</font><font color="#66cc66">=</font><font color="#ff0000">&#171;block-for-scroll-inter&#187;</font>></font><br/><br />
 <font color="#009900"><<font color="#000000">ul</font> <font color="#000066">class</font><font color="#66cc66">=</font><font color="#ff0000">&#171;style-ul&#187;</font>></font><br/><br />
<font color="#009900"><<font color="#000000">li</font> <font color="#000066">class</font><font color="#66cc66">=</font><font color="#ff0000">&#171;li li-n-1&#8243;</font>></font>li#1 inter text<font color="#009900"><<font color="#66cc66">/</font><font color="#000000">li</font>></font><br/><br />
…<br/><br />
 <font color="#009900"><<font color="#000000">li</font> <font color="#000066">class</font><font color="#66cc66">=</font><font color="#ff0000">&#171;li li-n-24&#8243;</font>></font>li#24 inter text<font color="#009900"><<font color="#66cc66">/</font><font color="#000000">li</font>></font> <br/><br />
 <font color="#009900"><<font color="#66cc66">/</font><font color="#000000">ul</font>></font><br/><br />
 <font color="#009900"><<font color="#66cc66">/</font><font color="#000000">div</font>></font><br/><br />
 <font color="#009900"><<font color="#66cc66">/</font><font color="#000000">div</font>></font><br/><br />
 <font color="#009900"><<font color="#66cc66">/</font><font color="#000000">div</font>></font><br/><br />
 <font color="#009900"><<font color="#000000">div</font> <font color="#000066">class</font><font color="#66cc66">=</font><font color="#ff0000">&#171;scroll-div&#187;</font>></font><br/><br />
 <font color="#009900"><<font color="#000000">div</font> <font color="#000066">class</font><font color="#66cc66">=</font><font color="#ff0000">&#171;scroll-outer&#187;</font>></font><br/><br />
<font color="#009900"><<font color="#000000">div</font> <font color="#000066">class</font><font color="#66cc66">=</font><font color="#ff0000">&#171;scroll-toddler&#187;</font>></font><br/><br />
 <font color="#009900"><<font color="#66cc66">/</font><font color="#000000">div</font>></font><br/><br />
 <font color="#009900"><<font color="#66cc66">/</font><font color="#000000">div</font>></font><br/><br />
 <font color="#009900"><<font color="#000000">div</font> <font color="#000066">class</font><font color="#66cc66">=</font><font color="#ff0000">&#171;scroll-control&#187;</font>></font><br/><br />
 <font color="#009900"><<font color="#000000">div</font> <font color="#000066">class</font><font color="#66cc66">=</font><font color="#ff0000">&#171;prev&#187;</font>></font><br/><br />
 <font color="#009900"><<font color="#66cc66">/</font><font color="#000000">div</font>></font><br/><br />
<font color="#009900"><<font color="#000000">div</font> <font color="#000066">class</font><font color="#66cc66">=</font><font color="#ff0000">&#171;next&#187;</font>></font><br/><br />
 <font color="#009900"><<font color="#66cc66">/</font><font color="#000000">div</font>></font><br/><br />
<font color="#009900"><<font color="#66cc66">/</font><font color="#000000">div</font>></font><br/><br />
<font color="#009900"><<font color="#66cc66">/</font><font color="#000000">div</font>></font><br/><br />
<font color="#009900"><<font color="#000000">div</font> <font color="#000066">class</font><font color="#66cc66">=</font><font color="#ff0000">&#171;block-outer&#187;</font>></font><br/><br />
 <font color="#009900"><<font color="#000000">div</font> <font color="#000066">class</font><font color="#66cc66">=</font><font color="#ff0000">&#171;block-for-scroll&#187;</font>></font><br/><br />
 <font color="#009900"><<font color="#000000">div</font> <font color="#000066">class</font><font color="#66cc66">=</font><font color="#ff0000">&#171;block-for-scroll-inter&#187;</font>></font><br/><br />
 <font color="#009900"><<font color="#000000">ul</font> <font color="#000066">class</font><font color="#66cc66">=</font><font color="#ff0000">&#171;style-ul&#187;</font>></font><br/><br />
 <font color="#009900"><<font color="#000000">li</font> <font color="#000066">class</font><font color="#66cc66">=</font><font color="#ff0000">&#171;li li-n-1&#8243;</font>></font>li#1 inter text<font color="#009900"><<font color="#66cc66">/</font><font color="#000000">li</font>></font><br/><br />
…<br/><br />
 <font color="#009900"><<font color="#000000">li</font> <font color="#000066">class</font><font color="#66cc66">=</font><font color="#ff0000">&#171;li li-n-24&#8243;</font>></font>li#24 inter text<font color="#009900"><<font color="#66cc66">/</font><font color="#000000">li</font>></font> <br/><br />
 <font color="#009900"><<font color="#66cc66">/</font><font color="#000000">ul</font>></font><br/><br />
 <font color="#009900"><<font color="#66cc66">/</font><font color="#000000">div</font>></font><br/><br />
 <font color="#009900"><<font color="#66cc66">/</font><font color="#000000">div</font>></font><br/><br />
 <font color="#009900"><<font color="#66cc66">/</font><font color="#000000">div</font>></font><br/><br />
 <font color="#009900"><<font color="#000000">div</font> <font color="#000066">class</font><font color="#66cc66">=</font><font color="#ff0000">&#171;scroll-positions&#187;</font>></font><br/><br />
 <font color="#009900"><<font color="#000000">div</font> <font color="#000066">class</font><font color="#66cc66">=</font><font color="#ff0000">&#171;scroll-positioner&#187;</font>></font><br/><br />
 <font color="#009900"><<font color="#000000">div</font> <font color="#000066">class</font><font color="#66cc66">=</font><font color="#ff0000">&#171;scroll-positioner-inter&#187;</font>></font><br/><br />
 <font color="#009900"><<font color="#66cc66">/</font><font color="#000000">div</font>></font><br/><br />
 <font color="#009900"><<font color="#66cc66">/</font><font color="#000000">div</font>></font><br/><br />
 <font color="#009900"><<font color="#66cc66">/</font><font color="#000000">div</font>></font><br/><br />
 <font color="#009900"><<font color="#66cc66">/</font><font color="#000000">div</font>></font></p></blockquote>
<p><br/><br />
Также и CSS:<br/></p>
<blockquote><p><font color="#00AA00">*</font><br/><br />
<font color="#00AA00">{</font><br/><br />
 <font color="#000000">margin</font><font color="#00AA00">:</font><font>0px</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">padding</font><font color="#00AA00">:</font><font>0px</font><font color="#00AA00">;</font><br/><br />
<font color="#00AA00">}</font><br/><br />
 <br/><br />
debug<font color="#00AA00">{</font><br/><br />
 <font color="#000000">position</font><font color="#00AA00">:</font><font color="#993333">fixed</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">display</font><font color="#00AA00">:</font><font color="#993333">block</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">color</font><font color="#00AA00">:</font><font color="#cc00cc">#fff</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">background</font><font color="#00AA00">:</font><font color="#cc00cc">#000</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">padding</font><font color="#00AA00">:</font><font>15px</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">top</font><font color="#00AA00">:</font><font>15px</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">left</font><font color="#00AA00">:</font><font>15px</font><font color="#00AA00">;</font><br/><br />
<font color="#00AA00">}</font><br/><br />
 <br/><br />
<font color="#6666ff">.block-outer</font><br/><br />
<font color="#00AA00">{</font><br/><br />
 <font color="#000000">position</font><font color="#00AA00">:</font><font color="#993333">relative</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">height</font><font color="#00AA00">:</font><font>200px</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">width</font><font color="#00AA00">:</font><font>800px</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">margin</font><font color="#00AA00">:</font><font color="#cc66cc">0</font> <font color="#993333">auto</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">border</font><font color="#00AA00">:</font><font>2px</font> <font color="#993333">dashed</font> <font color="#000000">blue</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">overflow</font><font color="#00AA00">:</font><font color="#993333">hidden</font><font color="#00AA00">;</font><br/><br />
<font color="#00AA00">}</font><br/><br />
.scroll-positions<font color="#00AA00">{</font><br/><br />
 <font color="#000000">position</font><font color="#00AA00">:</font><font color="#993333">relative</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">width</font><font color="#00AA00">:</font><font>800px</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">margin</font><font color="#00AA00">:</font><font color="#cc66cc">0</font> <font color="#993333">auto</font><font color="#00AA00">;</font><br/><br />
<font color="#000000">margin-top</font><font color="#00AA00">:</font><font>10px</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">margin-bottom</font><font color="#00AA00">:</font><font>10px</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">height</font><font color="#00AA00">:</font><font>15px</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">border</font><font color="#00AA00">:</font><font>1px</font> <font color="#993333">solid</font> <font color="#cc00cc">#aaa</font><font color="#00AA00">;</font><br/><br />
<font color="#000000">background</font><font color="#00AA00">:</font><font color="#cc00cc">#eee</font><font color="#00AA00">;</font><br/><br />
<font color="#00AA00">}</font><br/><br />
<font color="#6666ff">.scroll-positions</font> .scroll-positioner<font color="#00AA00">{</font><br/><br />
 <font color="#000000">height</font><font color="#00AA00">:</font><font>15px</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">width</font><font color="#00AA00">:</font><font>50px</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">background</font><font color="#00AA00">:</font><font color="#cc00cc">#ccc</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">position</font><font color="#00AA00">:</font><font color="#993333">absolute</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">top</font><font color="#00AA00">:</font><font>0px</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">left</font><font color="#00AA00">:</font><font>0px</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">cursor</font><font color="#00AA00">:</font><font color="#993333">pointer</font><font color="#00AA00">;</font><br/><br />
<font color="#00AA00">}</font><br/><br />
<font color="#6666ff">.block-outer</font> <font color="#6666ff">.block-for-scroll</font><br/><br />
<font color="#00AA00">{</font><br/><br />
 <font color="#000000">position</font><font color="#00AA00">:</font><font color="#993333">absolute</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">left</font><font color="#00AA00">:</font><font>0px</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">top</font><font color="#00AA00">:</font><font>0px</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">height</font><font color="#00AA00">:</font><font><font color="#cc66cc">100</font>%</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">width</font><font color="#00AA00">:</font><font>30000px</font><font color="#00AA00">;</font><br/><br />
<font color="#00AA00">}</font><br/><br />
<font color="#6666ff">.block-outer</font> <font color="#6666ff">.block-for-scroll</font> <font color="#6666ff">.block-for-scroll-inter</font><br/><br />
<font color="#00AA00">{</font><br/><br />
 <font color="#000000">position</font><font color="#00AA00">:</font><font color="#993333">absolute</font><font color="#00AA00">;</font><br/><br />
<font color="#00AA00">}</font><br/><br />
 <br/><br />
<font color="#6666ff">.block-for-scroll</font> <font color="#6666ff">.style-ul</font><br/><br />
<font color="#00AA00">{</font><br/><br />
 <font color="#000000">list-style</font><font color="#00AA00">:</font><font color="#993333">none</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">height</font><font color="#00AA00">:</font><font><font color="#cc66cc">100</font>%</font><font color="#00AA00">;</font><br/><br />
<font color="#00AA00">}</font><br/><br />
 <br/><br />
<font color="#6666ff">.block-for-scroll</font> <font color="#6666ff">.style-ul</font> .li<font color="#00AA00">{</font><br/><br />
 <font color="#000000">position</font><font color="#00AA00">:</font><font color="#993333">relative</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">float</font><font color="#00AA00">:</font><font color="#000000">left</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">margin</font><font color="#00AA00">:</font><font>5px</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">height</font><font color="#00AA00">:</font><font>186px</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">border</font><font color="#00AA00">:</font><font>2px</font> <font color="#993333">dotted</font> <font color="#993333">red</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">width</font><font color="#00AA00">:</font><font>186px</font><font color="#00AA00">;</font><br/><br />
<font color="#00AA00">}</font><br/><br />
 <br/><br />
<font color="#6666ff">.scroll-div</font><br/><br />
<font color="#00AA00">{</font><br/><br />
 <font color="#000000">position</font><font color="#00AA00">:</font><font color="#993333">relative</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">margin</font><font color="#00AA00">:</font><font>20px</font><font color="#00AA00">;</font><br/><br />
<font color="#00AA00">}</font><br/><br />
.scroll-control<font color="#00AA00">{</font><br/><br />
 <font color="#000000">position</font><font color="#00AA00">:</font><font color="#993333">relative</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">width</font><font color="#00AA00">:</font><font>600px</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">height</font><font color="#00AA00">:</font><font>0px</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">margin</font><font color="#00AA00">:</font><font color="#cc66cc">0</font> <font color="#993333">auto</font><font color="#00AA00">;</font><br/><br />
<font color="#00AA00">}</font><br/><br />
<font color="#6666ff">.scroll-control</font> .next<font color="#00AA00">{</font><br/><br />
<font color="#000000">position</font><font color="#00AA00">:</font><font color="#993333">absolute</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">right</font><font color="#00AA00">:</font><font>60px</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">top</font><font color="#00AA00">:</font><font>-30px</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">height</font><font color="#00AA00">:</font><font>40px</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">width</font><font color="#00AA00">:</font><font>40px</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">background</font><font color="#00AA00">:</font><font color="#000000">blue</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">cursor</font><font color="#00AA00">:</font><font color="#993333">pointer</font><font color="#00AA00">;</font><br/><br />
<font color="#00AA00">}</font><br/><br />
<font color="#6666ff">.scroll-control</font> .prev<font color="#00AA00">{</font><br/><br />
 <font color="#000000">position</font><font color="#00AA00">:</font><font color="#993333">absolute</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">left</font><font color="#00AA00">:</font><font>60px</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">top</font><font color="#00AA00">:</font><font>-30px</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">height</font><font color="#00AA00">:</font><font>40px</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">width</font><font color="#00AA00">:</font><font>40px</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">background</font><font color="#00AA00">:</font><font color="#000000">blue</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">cursor</font><font color="#00AA00">:</font><font color="#993333">pointer</font><font color="#00AA00">;</font><br/><br />
<font color="#00AA00">}</font><br/><br />
<font color="#6666ff">.scroll-div</font> <font color="#6666ff">.scroll-outer</font><br/><br />
<font color="#00AA00">{</font><br/><br />
 <font color="#000000">position</font><font color="#00AA00">:</font><font color="#993333">relative</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">width</font><font color="#00AA00">:</font><font>300px</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">height</font><font color="#00AA00">:</font><font>20px</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">margin</font><font color="#00AA00">:</font><font color="#cc66cc">0</font> <font color="#993333">auto</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">background</font><font color="#00AA00">:</font><font color="#993333">gray</font><font color="#00AA00">;</font><br/><br />
<font color="#00AA00">}</font><br/><br />
<font color="#6666ff">.scroll-div</font> <font color="#6666ff">.scroll-outer</font> <font color="#6666ff">.scroll-toddler</font><br/><br />
<font color="#00AA00">{</font><br/><br />
 <font color="#000000">position</font><font color="#00AA00">:</font><font color="#993333">absolute</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">height</font><font color="#00AA00">:</font><font>20px</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">width</font><font color="#00AA00">:</font><font>20px</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">left</font><font color="#00AA00">:</font><font>140px</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">top</font><font color="#00AA00">:</font><font>0px</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">background</font><font color="#00AA00">:</font><font color="#000000">blue</font><font color="#00AA00">;</font><br/><br />
 <font color="#000000">cursor</font><font color="#00AA00">:</font><font color="#993333">pointer</font><font color="#00AA00">;</font><br/><br />
<font color="#00AA00">}</font><br/><br />
 </p></blockquote>
<p><br/><br />
После применения скелета и таблицы стилей должны получить что-то наподобие:<br/><br />
<img src="http://clip2net.com/clip/m0/1326509893-clip-6kb.png" alt="image"/><br/></p>
<h4>Заключение</h4>
<p><br/><br />
Вот такие вот пироги с котятами, их кушаешь — они мяукают.<br/><br />
Скелет <a href="http://kodder.ru/scrollsliders/">тут</a>, демо версия <a href="http://kodder.ru/scrollsliders/demo.html">тут</a>, скачать тут. Архивом можно <a href="http://kodder.ru/scrollsliders/web.rar">тут</a>. Деньги слать <u><font color="#6DA3BD">сюда</font></u>, утка <img src='http://vwlab.ru/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  <br/><br />
С Ув. buna1991.<br/><br />
<img src="http://clip2net.com/clip/m0/1326510475-clip-102kb.jpg" alt="image"/></p>
<p>© <a href="http://m.habrahabr.ru/post/136212/">Habrahabr.ru</a></p>
]]></content:encoded>
			<wfw:commentRss>http://vwlab.ru/post/212/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Единый API на РНР для всех облачных push-сервисов</title>
		<link>http://vwlab.ru/post/210/</link>
		<comments>http://vwlab.ru/post/210/#comments</comments>
		<pubDate>Sun, 15 Jan 2012 15:33:24 +0000</pubDate>
		<dc:creator>Niko</dc:creator>
				<category><![CDATA[Разное]]></category>

		<guid isPermaLink="false">http://vwlab.ru/?p=210</guid>
		<description><![CDATA[Приветствую всех читателей. Сейчас в веб-разработках столько трендов, что не уследишь. Но вопрос о реал-тайм взаимодействии с пользователями сайта стоит остро прочти для любого проекта. Простейший способ — поставить один из широко доступных открытых comet-серверов, например, Dklab_Realplexor, Socket.IO или Faye &#8230;<p class="read-more"><a href="http://vwlab.ru/post/210/">Читать далее &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<p>Приветствую всех читателей. Сейчас в веб-разработках столько трендов, что не уследишь. Но вопрос о реал-тайм взаимодействии с пользователями сайта стоит остро прочти для любого проекта. Простейший способ — поставить один из широко доступных открытых comet-серверов, например, Dklab_Realplexor, Socket.IO или Faye — что кому по душе или в зависимости от стека технологий. Правда это путь достаточно сложных проектов, где команда может себе позволить такое решение. <br/><br />
Для многих проектов попроще (хотя это всегда вопрос конкретики приложения) логично будет использовать сторонние решения. А проще — арендовать как услугу функционал comet-сервера. Сегодня недостатка в таких сервисах нет, так что нам есть что обозревать. <br/><br />
И так, сначала давайте кратко ознакомимся с существующими push-сервисами, которые позволят нам без создания и поддержки своей серверной инфраструктуры поддерживать реал-тайм общение между клиентами проекта.<br/><br />
Таких сервисов всего 6: <b>Pusher</b>, <b>Pubnub</b>, <b>Partcl</b>, <b>BeaconPush</b>, <b>X-Stream.ly</b> и <b>ioBridge</b> (с некоторыми особенностями). Под катом — кратки обзор всех сервисов, особенностей РНР-библиотек для них и описание библиотеки pushBridge.IO для унификации работы со всеми облачными пуш-сервисами.<br/><br />
 <span id="more-210"></span> <br/><br />
<b><a href="http://pusher.com/">Pusher.com</a></b><br/><br />
<img src="http://habrastorage.org/storage2/aef/b21/624/aefb21624cafee2161ecd80d42f50293.png"/><br/><br />
Самый известный из подобных сервисов. Одновременно с этим и один из самых сложных из-за обилия возможностей. В общих чертах, коммуникация поделена на каналы, внутри которых есть пользовательские события, на которые подписывается клиентский код (javascript). Кроме этого есть ряд системных событий, а также система статусов и оповещений и подключениях/отключениях других пользователей канала. Возможна и работа с приватными каналами, так, что даже подключенный пользователь, но не знающий кодового идентификатора, не будет получать события. <br/><br />
Для взаимодействия с другими системами, Pusher использует REST-HTTP-API (впрочем, как и все подобные сервисы), и предоставляет ряд готовых библиотек для 11 языков, включая Clojure, Groovy и ColdFusion. Меня интересовал только РНР API, который представлен 4-мя плагинами — для Kohana, Code Igniter и бандл для Simfony 2 фреймворков, а также одним независимым классом (<a href="http://github.com/squeeks/Pusher-PHP">http://github.com/squeeks/Pusher-PHP</a>). Для работы он требует расширения cURL и json, а также sha256 в качестве алгоритма хеширования. <br/><br />
В качестве примечания скажу, что именно с этого сервиса возникла идея моей библиотеки. Буду честен — для одного проекта мне понадобился реалтайм, а в тестовой версии писать свой сервер не хотелось, поэтому за пару минут я думал подключить пушер, тем более, аккаунт у меня уже был. оказалось, что при всех достоинствах и обилии документации, система не такая простая, и не все моменты там удачно расписаны. очень помог режим дебага, когда на сайте в разделе консоли выводятся в реальном времени все ваши запросы, отправляемые через API. Но где-то я ступил и хотя запросы посылались, до клиента они не доходили. На этом месте, после часа отладки я забросил это дело. Перспектива снова переписывать код мне совсем не нравилась, к тому же, в финальной версии моего проекта все равно пришлось бы переходить на собственный сервер. Так и возникла идея — а зачем каждый раз все переписывать, если можно попробовать свести все в один унифицированный интерфейс. Забегая вперед, скажу, что идея успешно нашла свою реализацию!<br/><br />
<b><a href="http://pubnub.com/">PubNub.com</a></b><br/><br />
<img src="http://habrastorage.org/storage2/e6e/3e3/1c4/e6e3e31c4305c9323d0b1583dc6c02d4.png"/><br/><br />
Этот сервис проще и, в этом, я вижу его преимущество. API предельно прост — есть каналы, в них сообщения и все. Формат данных, конечно, везде JSON. Как в клиентской части, так и на серверной стороне, Pubnub имеет самое широкое покрытие, предоставляя доступ к сервису на любой платформе и языке программирования. Простота и мощная поддержка всех платформ делает этот сервис самым интересным из рассматриваемых, особенно, если вам надо обеспечить реалтайм везде и всюду. <br/><br />
PHP библиотека для доступа к сервису достаточно простая, позволяет как отправлять, так и получать сообщения, базируясь на cURL. Работает как на 5.2, так и на 5.3 версии РНР, позволяю использовать плюшки вроде callback функций. После исследования исходного кода остался большой вопрос — почему-то при отправке, после преобразования в JSON, длина сообщения не должна превышать 1800 символов! С чем связанно это ограничение пока не ясно, буду связываться с разработчиками и выяснять. <br/><br />
<b><a href="http://partcl.com/">Partcl.com</a></b><br/><br />
<img src="http://habrastorage.org/storage2/483/af0/403/483af0403332ff17ab1779ceba2f9337.png"/><br/><br />
Достаточно новый сервис на этом рынке, первоначально ориентирован на встраивание обновляемых в реальном времени тегов на веб-странице. В настоящее время API там достаточно расширен и позволяет получать историю изменения значений, строить графики, также работающие в реальном времени и т.п. В отличие от остальных сервисов, позиционируемых лишь как коммуникационные, Partcl работает и как контент-провайдер, сохраняя все сообщения и данные, что достаточно уникальная функция. Раскрывая некоторые подробности, скажу, что серверная часть написана на Node.JS+Redis (именно реал-тайм “раздавалка” — я ее непосредственный разработчик), а веб-часть на Zend Framework. <br/><br />
Хотя для системы уже был написан API на РНР, и даже плагин для интеграции в WordPress, он, по моим меркам, был достаточно примитивный и вполне мог не работать на некоторых хостингах. Так что я попытался еще и написано новую реализацию библиотеки для partcl-а. Получилось даже лучше, чем оригинальная. <br/><br />
<a href="http://beaconpush.com/"><b>BeaconPush.com</b></a><br/><br />
<img src="http://habrastorage.org/storage2/339/17f/27e/33917f27e5a6b03a5b8e67ef1e1df19c.png"/><br/><br />
Малоизвестный сервис, однако единственный, который предлагает выделенный сервер для требовательных клиентов (система, кстати, написана на Java). А так, он обычный, правда кроме каналов и сообщений выводит наверх еще и абстракцию пользователя, упрощая коммуникацию именно между конкретными подключенными клиентами. Кроме этого, интересный функционал веб-хуков, когда сервис сам дергает указанный вами URL, сигнализируя про вход/выход пользователей из канала. Также есть возможность управлять возможностями публикаций — если не включить ее, любой, зная публичный ид, сможет публиковать данные, иначе только имея секретный ключ. <br/><br />
А вот с РНР API у этого сервиса никак не сложилось. Он, конечно, есть (<a href="https://github.com/ImDom/BeaconPush-PHP">https://github.com/ImDom/BeaconPush-PHP</a> и даже модуль для Code Igniter-а), но качество… очень далекое от хорошего. Кстати, автор модуля зашил в исходник свой аккаунт. Честно попытавшись использовать готовый модуль, но так и не смог его настроить на правильную работу (тупо отказывался принимать мой ид аккаунта), я полностью переписал его API под Zend_Http. <br/><br />
<a href="http://x-stream.ly/"><b>X-Stream.ly</b></a><br/><br />
<img src="http://habrastorage.org/storage2/305/70e/748/30570e748396f9b33ae7196ad0fead8d.png"/><br/><br />
Еще один почти неизвестный сервис, однако обладающий рядом интересных фишек. Например, можно создавать специально ключи для регламентирования доступа конкретных юзеров к API (видимо из-за бизнес модель). Также, он единственный, кроме Partcl-а, обладает функционалом постоянного хранения сообщений. Другие возможности более-менее стандартные — каналы, события, приватные каналы с доступом по паролю, статусы пользователей. Уникальной фичей является твиттер-фид, когда сервис сам будет подключаться к указанному Twitter-аккаунту и транслировать новые сообщения всем подключенным пользователям. На событие появления сообщения в канала можно поставить калбеки, которыми также можно управлять через REST-API. Кстати, этот сервис единственный, кто для публикации (и вообще, доступа) к своему HTTP API, кроме ид и секретного ключа, требует и HTTP-авторизацию, используя логин и пароль вашего аккаунта, а также работу только через SSL-соединение, что вносит дополнительные требования к хостингу.<br/><br />
Родной серверный API у сервиса более чем скудный — C#, Ruby и Node.JS. Пришлось с нуля реализовать часть их API, так что здесь я первый, кто написал библиотеку. <br/><br />
<a href="http://www.iobridge.com/"><b>ioBridge.com</b></a><br/><br />
<img src="http://habrastorage.org/storage2/eb5/425/0cb/eb54250cb1595c4460dad2db26ebc0bf.png"/><br/><br />
Самый интересный и странный сервис, не совсем даже push. Он ориентирован на подключение к вебу всяких железок (контроллеров и плат), а также обеспечивает отображение данных, сбор и хранение, ну и управление через веб. Родного клиента на РНР также нет, в официальном форуме есть несколько предложений и набросков кода, однако они далеки от качественной реализации. Да и я понял почему, начав сам его делать — сервис местами очень уж странный, например, чтобы получить actionId виджета и ид сессии, надо сделать запрос к их серверу, который сразу возвращает кусок HTML+JavaScript, из которого тупым парсингом строк приходиться выуживать данные, которые потом нужны для подключения и отправки команд. К сожалению, дальше базового кода я не смог продвинуться, видимо, для полноценного тестирования надо и само устройство какое-нибудь подключить. Так что этот код не протестирован в реальных условиях, если кто имеет опыт работы с сервисом, буду благодарен за подсказки и посильную помощь.<br/></p>
<h4>А теперь о самом главном — pushBridge.IO PHP Library</h4>
<p><br/><br />
Моя библиотека для РНР призвана заменить все родные библиотеки для доступа к каждому из этих сервисов, обеспечивает единый и общий интерфейс к базовому функционалу, сохраняя при этом возможность работать напрямую с оригинальной библиотекой (для тех случаев, когда она есть). Для некоторых сервисов это первая или, не постыжусь, лучшая библиотека (по крайней мере на РНР). <br/><br />
Пока реализован только базовый функционал — соединение и авторизация, где это требуется, и отправка сообщения в указанный канал или генерацию пользовательского события. Все остальные специфические функции можно получить напрямую от экземпляра класса соединения. В следующей версии это также будет переписано, чтобы не зависеть от чужих библиотек и обеспечить единый интерфейс для всех операций (получение количества подключенных юзеров, история сообщений, чтение сообщений и т.п.).<br/><br />
Библиотека разделена на две части — базовый класс отвечает за инициализацию нужного адаптера, обрабатывает сообщение, при необходимости, сериализирует его. Для этого я использовал класс Zend_Serializer, таким образом, поддерживаются все его форматы — от обычного Json до экзотического Wddx. <br/><br />
За работу с конкретным сервисов отвечает класс адаптера, который, при необходимости, подключает родную библиотеку. Пока родные классы используются только для Pusher-а и PubNub-а, ввиду того, что сервисы предоставляют свои специфические функции, которые пока не перенесены. Зато после инициализации вы всегда можете продолжить работать напрямую, просто вызвав метод getConnection(). <br/><br />
Я так же попытался как-то унифицировать данные для авторизации. Одни сервисы используют app_id и секретный ключ, другие именуют их publish и subscribe/public ключами и т.п. Потому я попытался свести их к минимальному множеству и сохранить одно наименование для всех сервисов: <br/></p>
<ul>
<li><b>appId</b> — обычно это ид приложения или API-key, уникальный идентификатор аккаунта или приложения</li>
<li><b>authKey</b> — секретный ключ, дающий право на публикацию данных</li>
<li><b>secretKey</b> — пароль или другой секретный ключ для доступа к аккаунту</li>
<li><b>readKey</b> — публичный ключ для подключения в качестве клиента и чтения данных</li>
<li><b>emailKey</b> — логин пользователя в виде e-mail (пока это исключительно для x-Stream.ly)</li>
</ul>
<p><br/><br />
Для работы с библиотекой достаточно трех строк:<br/></p>
<h5>1. Инициализация и подключение.</h5>
<p><br/><br />
<code>$push = new pushBridge_IO( [ Adapter ], [serializer] ); </code><br/><br />
Первым параметром идет экземпляр адаптера для нужного вам сервиса, например:<br/><br />
<code>new pushBridge_Adapter_Pusher(Array('appId' => 'Your app Id', 'authKey' => 'Your key', 'secretKey' => 'Your secret key', 'debug' => true));<br/><br />
</code><br/><br />
Обычно, достаточно только данных для авторизации, набор которых специфичен для сервиса. Но библиотека, в отличие от родных классов, позволяет гибко управлять методами подключения, используя сетевой стек от Zend_Http. Для запросов можно использовать cURL, напрямую сокеты или адаптер для работы через прокси. По умолчанию используется cURL, но если вам надо, передайте в качестве параметра httpAdapter название нужно адаптера, а в httpAdapterConfig — любые его настройки согласно документации по ZF (<a href="http://framework.zend.com/manual/en/zend.http.client.adapters.html">например, вот здесь</a>). Каюсь, в этом моменте есть еще баг в текущей реализации библиотеки, пока опции, заданные пользователем для адаптера, не используются, это будет исправлено в следующей версии (на днях).<br/><br />
Так как разные сервисы требуют (или наоборот) разные методы, можно задать в параметре method каким образом адаптер будет подключаться к серверу. Обычно это GET, но иногда сервисы понимают только POST. Адаптер это учитывает, но вы можете переопределить этот параметр. <br/><br />
Библиотека вставляет свой кастомный хедер в запрос, X-Powered-By, идентифицируя себя, при желании это можно отключить для экономии сетевого трафика или просто из принципа. <br/><br />
Второй параметр — сериализатор, который будет обрабатывать сообщение. Все сервисы принимают или JSON, или (некоторые, например, Partcl) просто строку, без преобразования. Изначально там json, используя класс Zend_Serializer, однако вы можете переопределить на любой другой. Достаточно передать в качестве второго параметра или строку с названием сериализатора (сейчас поддерживаем: json, php и pickle) или сразу экземпляр класса Zend_Serializer с необходимыми вам опциями. <br/><br />
Примеры:<br/><br />
Partcl:<br/><br />
 <code>$push = new pushBridge_IO( new pushBridge_Adapter_Partcl(Array('secretKey' => 'Your secret key')) );</code><br/><br />
Pusher: <br/><br />
 <code>$push = new pushBridge_IO( new pushBridge_Adapter_Pusher(Array('appId' => 'Your app Id', 'authKey' => 'Your key', 'secretKey' => 'Your secret key', 'debug' => true)) );</code><br/><br />
Pubnub:<br/><br />
 <code>$push = new pushBridge_IO( new pushBridge_Adapter_Pubnub(Array('readKey' => 'Your subscribe key', 'authKey' => 'Your publish key', 'secretKey' => ' Your secret key')) );</code><br/><br />
BeaconPush: <br/><br />
 <code>$push = new pushBridge_IO( new pushBridge_Adapter_Beaconpush(Array('authKey' => 'Your API Key', 'secretKey' => 'Your secret key')) );</code><br/><br />
А во пример с кастомным сериализатором:<br/><br />
 <code>$push = new pushBridge_IO( new pushBridge_Adapter_Partcl(Array('secretKey' => ' Your secret key')), ‘php’ );</code><br/><br />
 или <br/><br />
 <code>$push = new pushBridge_IO( new pushBridge_Adapter_Partcl(Array('secretKey' => 'Your secret key')), Zend_Serializer::factory('Wddx', Array(‘comment’ => ‘Powered by ZF+pushBridge.IO’) );</code><br/></p>
<h5>2. Просто отправляем сообщение. </h5>
<p><br/><br />
На самом деле все не так и просто. Сервисы очень по разному работают с сообщениями. Самое простое — это модель канал->сообщение (или тег -> сообщение), другие же вносят новый уровень — канал -> событие -> сообщение. При этом только partcl очень толерантно относиться к содержимому сообщения, для него это просто строка, а ее понимание перекладываться полностью на клиента. Другие требуют специального оборачивания сообщений в json-структуры. Ни один из сервисов не поддерживает массовую отправку сообщений, когда в одном запросе можно было бы публиковать данные в разные каналы или несколько разных сообщений и событий в один канал. Этот момент мы уже учли и в следующей версии нашего сервиса Partcl.com такая возможность будет, параллельно в библиотеке появиться и эмуляция этого функционала для всех остальных (справедливости ради стоит сказать, что такой функционал реализован в классе для BeaconPush, но не портирован в мою библиотеку). <br/><br />
Общий метод отправки имеет такой вид: <br/><br />
<code>$push->send( 'сообщение', 'channel', 'config' );</code><br/><br />
В метод адаптера попадает уже преобразованная строка, так что он гарантированно получает данные и они нечто большее, чем пустая строка. Однако, если сервис этого требует, адаптер сформирует поверх данных сообщения необходимую Json-структуру. <br/><br />
Если в сервисе используются каналы, то второй параметр это строка (или массив) каналов, куда следует отправить сообщение. если каналов нет, это ид тега или другой ид.<br/><br />
При необходимости задать код события следует использовать конфиг — третий параметр всегда массив. Событие задается в параметре event. Дополнительно можно отключить сериализацию, передав параметр serialize = false. Если сервис принимает, можно указать и дополнительные параметры сообщения, например флаг сохранения данных для X-Stream.ly или включить/отключить дебаг-режим для сообщения в Pusher-е. <br/><br />
Пример отправки простого сообщения:<br/><br />
Partcl:<br/><br />
<code>$push->send('Hello world from pushBridge.IO', 'Your tag id', Array('serialize' => false));</code><br/><br />
Pusher: <br/><br />
<code>$push->send('Hello world from pushBridge.IO', 'test_channel', Array('serialize' => false, 'event' => 'push_test', ‘debug’ => true));</code><br/><br />
Pubnub:<br/><br />
 <code>$push->send('Hello world from pushBridge.IO', 'my_channel');</code><br/><br />
x-Stream.ly: <br/><br />
<code>$push->send('Hello world from pushBridge.IO', 'mychannel', Array('event' => 'my_event', ‘persisted’ => true));</code><br/><br />
Конечно, по дефолту, максимум параметров выставлено так, чтобы не было необходимости что-то задавать, часто даже имя канала или евента выставлено так, как они присваиваются сервисом после регистрации. Но для более полного понимания опций, следует обращаться к документации по конкретному сервису.<br/><br />
 <br/><br />
Исходный код библиотеки и краткие примеры:<a href="https://github.com/aleksraiden/pushBridge.IO/tree/ServiceWrapper"><b><a href="https://github.com/aleksraiden/pushBridge.IO/tree/ServiceWrapper">github.com/aleksraiden/pushBridge.IO/tree/ServiceWrapper</a></b></a> <br/><br />
В планах на ближайший релиз: исправление ошибок, унификация метода send, поддержка публикации сразу нескольких переменный, реализация метода чтения данных, а также поднятие сайта проекта на домене <a href="http://pushcloudapi.com/"><b>pushcloudapi.com</b></a>. Буду благодарен за замечания и дополнения.</p>
<p>© <a href="http://m.habrahabr.ru/post/136230/">Habrahabr.ru</a></p>
]]></content:encoded>
			<wfw:commentRss>http://vwlab.ru/post/210/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

