<?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>Sun, 15 Jan 2012 15:33:41 +0000</lastBuildDate>
	<language>ru</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<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>
		<item>
		<title>Минималистичный скриншотер на .NET</title>
		<link>http://vwlab.ru/post/208/</link>
		<comments>http://vwlab.ru/post/208/#comments</comments>
		<pubDate>Sun, 15 Jan 2012 15:29:46 +0000</pubDate>
		<dc:creator>Niko</dc:creator>
				<category><![CDATA[Разное]]></category>

		<guid isPermaLink="false">http://vwlab.ru/?p=208</guid>
		<description><![CDATA[Лучше один раз увидеть, чем 100 раз услышать. Уверен, не я один часто делаю скриншоты. Проиллюстрировать баг, отправить смешную картинку знакомому, вставить в комментарий на каком-нибудь ресурсе, etc. А началось всё с разочарования в некогда любимом Gyazo, а именно сам &#8230;<p class="read-more"><a href="http://vwlab.ru/post/208/">Читать далее &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<p><b>Лучше один раз увидеть, чем 100 раз услышать.</b><br/><br />
Уверен, не я один часто делаю скриншоты.<br/><br />
Проиллюстрировать баг, отправить смешную картинку знакомому,<br/><br />
вставить в комментарий на каком-нибудь ресурсе, etc.<br/><br />
А началось всё с разочарования в некогда любимом Gyazo,<br/><br />
а именно сам скриншот уже трудно найти под кучей рекламных блоков.<br/><br />
Когда я пересмотрел аналоги, они мне показались чересчур громоздкими.<br/><br />
Пройти через несколько окон, чтобы просто сделать скриншот? Нет, спасибо.<br/><br />
И вот, желая облегчить себе жизнь, а заодно ответить на <a href="http://habrahabr.ru/qa/15131/">вопрос</a><br/><br />
было решено сделать всё самому.<br/></p>
<h5>Суть</h5>
<p><br/><br />
А хочется то предельно простого.<br/><br />
Один клик — запустить приложение, второй клик — выделить область на экране. <br/><br />
Всё — после этого видим скриншот уже в браузере (в PNG) и имеем ссылку на него в буфере обмена.<br/><br />
Примерный алгоритм работы видится мне таким:<br/></p>
<ul>
<li>При запуске программа делает скриншот.</li>
<li>Устанавливает его фоном для окна, развёрнутого на весь экран.</li>
<li>Мышкой выделяем нужную область на экране.</li>
<li>Готово, картинка улетает на сервер.</li>
</ul>
<p><br/><br />
 <span id="more-208"></span> <br/><br />
Как и ожидалось, возникла аналогичная проблема с мерцанием.<br/><br />
Для устранения установим форме свойство <a href="http://msdn.microsoft.com/ru-ru/library/system.windows.forms.control.doublebuffered.aspx">DoubleBuffered</a>.<br/></p>
<pre><code class="cs">
DoubleBuffered = true;
</code></pre>
<p><br/><br />
К сожалению помогло только частично. На просторах интернета был найден совет<br/><br />
отправить функции <a href="http://msdn.microsoft.com/en-us/library/ms908193.aspx">CreateWindowEx</a> сообщение WS_CLIPCHILDREN в параметре dwExStyle.<br/><br />
Сделать это можно переопределив <a href="http://msdn.microsoft.com/ru-ru/library/system.windows.forms.control.createparams.aspx">CreateParams</a>.<br/></p>
<pre><code class="cs">
protected override CreateParams CreateParams
{
   get
   {
      CreateParams cp = base.CreateParams;
      cp.ExStyle |= 0x02000000;
      return cp;
   }
}
</code></pre>
<p><br/><br />
Загружаются скриншоты на imgur, присутсвует простой апи.<br/><br />
Для использования нужен api key, регистрируем приложение — получаем тут же ключ.<br/><br />
Отправляем картинку:<br/></p>
<pre><code class="cs">
class Uploader
{
   private static string imgur_key = null;

   public static string IMGUR_KEY
   {
      set { imgur_key = value; }
   }
   public static string UploadToImgur(Bitmap bitmap, ImageFormat imgFormat)
   {
      MemoryStream memStream = new MemoryStream();
      bitmap.Save(memStream, imgFormat);
      using (WebClient wc = new WebClient())
      {
         NameValueCollection values = new NameValueCollection
         {
            { "key", imgur_key },
            { "image", Convert.ToBase64String(memStream.ToArray()) }
         };
         byte[] response = wc.UploadValues("http://api.imgur.com/2/upload.xml", values);
         XDocument xDocument = XDocument.Load(new MemoryStream(response));
         return (string)xDocument.Root.Element("links").Element("original");
      }
   }
}
</code></pre>
<p><br/><br />
И собственно код самой программы:<br/></p>
<pre><code class="cs">
public partial class ScreenForm : Form
   {
      Rectangle rect;
      Bitmap bmpScreenshot;
      //формат скриншотов
      ImageFormat imgFormat = ImageFormat.Png;

      public ScreenForm()
      {
         InitializeComponent()
         this.Paint += new System.Windows.Forms.PaintEventHandler(this.ScreenForms_Paint);
         this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.ScreenForm_KeyDown);
         this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.ScreenForm_MouseDown);
         this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.ScreenForm_MouseMove);
         this.MouseUp += new System.Windows.Forms.MouseEventHandler(this.ScreenForm_MouseUp);
         this.FormBorderStyle = FormBorderStyle.None;
         this.ShowInTaskbar = false;
         this.TopMost = true;
         this.DoubleBuffered = true;
         this.Height = Screen.PrimaryScreen.Bounds.Height;
         this.Width = Screen.PrimaryScreen.Bounds.Width;
         //Указываем полученный ключ
         Uploader.IMGUR_KEY = "83dd0aacde6c6fc74d16638d5724bf96";
         MakeScreenShot();
         this.BackgroundImage = (Image)bmpScreenshot;
         this.Cursor = Cursors.Cross;
      }
      protected override CreateParams CreateParams
      {
         get
         {
            CreateParams cp = base.CreateParams;
            cp.ExStyle |= 0x02000000;
            return cp;
         }
      }
      private void MakeScreenShot()
      {
         Graphics gfxScreenshot;
         bmpScreenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, PixelFormat.Format32bppArgb);
         gfxScreenshot = Graphics.FromImage(bmpScreenshot);
         gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);
         gfxScreenshot.Dispose();
      }
      public Bitmap CropImage(Bitmap source, Rectangle section)
      {
         Bitmap bmp = new Bitmap(section.Width, section.Height);
         Graphics g = Graphics.FromImage(bmp);
         g.DrawImage(source, 0, 0, section, GraphicsUnit.Pixel);
         return bmp;
      }
      private void ScreenForms_Paint(object sender, PaintEventArgs e)
      {
         //цвет заливаемой области
         using (SolidBrush b = new SolidBrush(Color.FromArgb(75, 100, 100, 100)))
         {
            e.Graphics.FillRectangle(b, rect);
         }
      }
      private void ScreenForm_KeyDown(object sender, KeyEventArgs e)
      {
         if (e.KeyCode == Keys.Escape)
            base.Close();
      }
      private void ScreenForm_MouseDown(object sender, MouseEventArgs e)
      {
         if (e.Button == MouseButtons.Left)
         {
            rect = new Rectangle(e.X, e.Y, 0, 0);
         }
         else if (e.Button == MouseButtons.Right)
         {
            base.Close();
         }
      }
      private void ScreenForm_MouseMove(object sender, MouseEventArgs e)
      {
         if (e.Button == MouseButtons.Left)
         {
            rect = new Rectangle(rect.Left, rect.Top, e.X - rect.Left, e.Y - rect.Top);
         }
         this.Invalidate();
      }
      private void ScreenForm_MouseUp(object sender, MouseEventArgs e)
      {
         this.Hide();
         //вырезаем выделенную область
         Bitmap croppedBmp = CropImage(bmpScreenshot, rect);
         //мне понадобилось указывать в углу  время скришнота, что и делаем
         StringFormat strFormat = new StringFormat();
         strFormat.Alignment = StringAlignment.Far;
         strFormat.LineAlignment = StringAlignment.Far;
         Graphics g = Graphics.FromImage(croppedBmp);
         g.DrawString(DateTime.Now.ToString(), new Font("Tahoma", 8), Brushes.Purple, new RectangleF(0, 0, croppedBmp.Width, croppedBmp.Height), strFormat);
         //загрузка на сервер, копирование ссылки в буфер и открытие url картинки в браузере
         string link = Uploader.UploadToImgur(croppedBmp, imgFormat);
         Clipboard.SetText(link);
         Process.Start(link);
         Application.Exit();
      }
}
</code></pre>
<p><br/></p>
<h5>Что же получилось?</h5>
<p><br/><br />
В результате имеем то, что хотели.<br/><br />
Простая быстрая программа, не делающая ничего лишнего.<br/><br />
<img src="http://i.imgur.com/WzIeX.png" alt="image"/><br/><br />
Никаких мусорных временных файлов не создаётся.<br/><br />
Минимальная базовая функциональность, как готовое законченное решение<br/><br />
рассматривать пока рано.<br/><br />
<a href="http://dl.dropbox.com/u/11381112/NET-ScreenShooter.zip">Проект</a> для VS2010.<br/><br />
<a href="http://dl.dropbox.com/u/11381112/SC.zip">ScreenShooter.exe</a> отдельно для .NET 4.0</p>
<p>© <a href="http://m.habrahabr.ru/post/136235/">Habrahabr.ru</a></p>
]]></content:encoded>
			<wfw:commentRss>http://vwlab.ru/post/208/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Великолепные стикеры с помощью CSS3</title>
		<link>http://vwlab.ru/post/206/</link>
		<comments>http://vwlab.ru/post/206/#comments</comments>
		<pubDate>Sun, 15 Jan 2012 15:28:33 +0000</pubDate>
		<dc:creator>Niko</dc:creator>
				<category><![CDATA[Разное]]></category>

		<guid isPermaLink="false">http://vwlab.ru/?p=206</guid>
		<description><![CDATA[Доброго времени суток! Введение В своё время было необходимо сделать заметки в форме стикеров для веб-сайта. Как вы понимаете, выбора большого особо не было и мой выбор пал на всеми нам любимый CSS3. С его появлением осуществление задуманного стало возможным &#8230;<p class="read-more"><a href="http://vwlab.ru/post/206/">Читать далее &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<p>Доброго времени суток!<br/></p>
<h4>Введение</h4>
<p><br/><br />
В своё время было необходимо сделать заметки в форме стикеров для веб-сайта. Как вы понимаете, выбора большого особо не было и мой выбор пал на всеми нам любимый CSS3. С его появлением осуществление задуманного стало возможным без какого-либо велосипедостроения. <s>Итак, моё решение проблемы под катом.</s> На самом деле, мопед не мой. Мне <a href="http://net.tutsplus.com/tutorials/html-css-techniques/create-a-sticky-note-effect-in-5-easy-steps-with-css3-and-html5/">дали</a> всего-лишь покататься.<br/><br />
 <span id="more-206"></span> <br/><br />
Данное решение работает в последних браузерах на движке Webkit (Safari и Chrome), Firefox и Opera. В остальных браузерах (читай, IE) есть шанс получить квадратный стикер жёлтого цвета без тени и анимации.<br/></p>
<h4>Шаг 1</h4>
<p><br/><br />
Давайте начнём с простейшего варианта, который будет работать во всех браузерах. Для того, чтобы сделать стикер, мы будем использовать HTML5 и CSS3, что логично. А начнём мы с обычной HTML разметки, в которой мы обозначим тексты и заголовки наших заметок, которые по сути являются списками.<br/></p>
<pre><code class="html">
<ul>
<li>
	  <a href = "#">
<h2>Title #1</h2>

Content #1

          </a>
	 </li>
<li>
	  <a href = "#">
<h2>Title #1</h2>

Content #2

	  </a>
     </li>
</ul>

</code></pre>
<p><br/><br />
Обратите внимание, что каждая заметка является ссылкой, что является достаточно хорошим подходом, т.к. это означает то, что если мы нажмём на нашу заметку, то в случае релевантной ссылке можем попасть на страницу, связанную непосредственно с заметкой.<br/><br />
Например, я записал «купить BMW X6» в воскресенье (тут хочется передать привет <a href="http://habrahabr.ru/users/boomburum/" class="user_link">Boomburum</a>, а по ссылке задал адрес, где найти эту машинку. Хе-хе!<br/><br />
CSS же, чтобы превратить этот списочек в жёлтые стикеры достаточно прост:<br/></p>
<pre><code class="css">* {
     margin: 0;
     padding : 0;
}

body {
           font-family: arial, sans-serif;
           font-size: 100%;
           margin: 3em;
           background: #666;
           color: #FFF;
}

h2, p {
           font-size: 100%;
           font-weight: normal;
}

ul, li {
         list-style: none;
}

ul {
      overflow: hidden;
      padding: 3em;
}

ul li a {
           text-decoration: none;
           color: #000;
           background: #FFC;
           display: block;
           height: 10em;
           width: 10em;
           padding: 1em;
}

ul li {
        margin: 1em;
        float: left;
}
</code></pre>
<p><br/><br />
Данный код настолько тривиален, что нет смысла его комментировать, т.к. мы тут производим стандартные манипуляции. Такие как избавление от пуль в списке, назначение отступов и т.д.<br/><br />
Кстати, вот результат:<br/><br />
<img src="http://habrastorage.org/storage2/b17/ae2/546/b17ae2546b89233392b479db33d6d3fa.png"/><br/><br />
Данный вариант будет работать в любом браузере. Даже (<b>!!!</b>) в IE6. На этом мы и закончим его поддержку, т.к. нам нужны краски, а не одноцветный прямоугольник. Так ведь?<br/></p>
<h4>Шаг 2</h4>
<p><br/><br />
Пора преукрасить наши стикеры. Давайте добавим к ним тени и зададим текстам заметок шрифт, похожий на рукописный. Для этого мы будем использовать <a href="http://code.google.com/apis/webfonts/docs/webfont_loader.html">Google Fonts API</a>. А использовать мы будем шрифт под именем <i>Reenie Beanie</i>. Самый простой способ использовать данный API — работать с <a href="http://code.google.com/webfonts/preview#font-family=Reenie+Beanie">Google Font previewer</a>:<br/><br />
<img src="http://habrastorage.org/storage2/751/0c5/7a0/7510c57a02b1f2fb63a0a1fed0ca3938.png"/><br/><br />
Используя его, мы получаем кусочек HTML кода, который нам нужно вставить в свою страницу, чтобы использовать шрифт. Такой вариант будет поддерживаться во всех современных браузерах:<br/><br />
<source lang=«html><br/></p>
<link href = „<a href="http://fonts.googleapis.com/css?family=Reenie+Beanie">fonts.googleapis.com/css?family=Reenie+Beanie</a>:regular“<br/><br />
 rel = „stylesheet“<br/><br />
 type = „text/css“><br/><br />
<br/><br />
Затем нам необходимо сделать отступ от заголовков к заметкам, чтобы наши заметки были читабельными. Познакомить абзацы с новым<s>Годом</s> шрифтом. Стоит обратить внимание, что размер шрифта должен быть достаточно крупным, чтобы можно было хорошо разглядеть наш <i>Reenie Beanie</i>.<br/></p>
<pre><code class="css">ul li h2 {
             font-size: 140%;
             font-weight: bold;
             padding-bottom: 10px;
}

ul li p {
           font-family: "Reenie Beanie", arial, sans-serif;
           font-size: 180%;
}
</code></pre>
<p><br/><br />
А теперь давайте зададим тень нашим стикерам. Да так, чтобы во всех (кроме IE) браузрах отображалось:<br/></p>
<pre><code class="css">ul li a {
           text-decoration: none;
           color: #000;
           background: #FFC;
           display: block;
           height: 10em;
           width: 10em;
           padding: 1em;
           -moz-box-shadow: 5px 5px 7px rgba(33, 33, 33, 1); /* для Firefox Грозного */
           -webkit-box-shadow: 5px 5px 7px rgba(33, 33, 33, 7); /* да для люда обычного, праведного */
           -box-shadow: 5px 5px 7px rgba(33, 33, 33, 7); /* и про Оперушку не забудем */
}
</code></pre>
<p><br/><br />
Смещение, цвет, ширина, высота — всё, как <s>доктор прописал</s> обычно. Вместе с новым шрифтом и нашими <s>финтифлюшками</s> тенями на стикеры теперь стало смотреть ещё приятнее. Выглядит они теперь вот так:<br/><br />
<img src="http://habrastorage.org/storage2/41f/92a/3f1/41f92a3f19ca89412e6c30f7a24de13c.png"/><br/></p>
<h4>Шаг 3</h4>
<p><br/><br />
Теперь я предлагаю вам заняться вещью ещё более увлекательной и интересной. Изменим углу поворота наших стикеров. Как? Используя свойство CSS3: <i><a href="http://www.w3.org/TR/css3-2d-transforms/">transform: rotate</a></i>. Вот так:<br/></p>
<pre><code class="css">ul li a {
           -webkit-transform: rotate(-6deg);
           -o-transform: rotate(-6deg);
           -moz-transform: rotate(-6deg);
}
</code></pre>
<p><br/><br />
Отлично. На самом деле, нет. Таким образом мы наклонили все стикеры под одним и тем же углом. Даже открывать пример не хочется. Давайте с вами внесём разнообразия и повернём стикеры в разные углы? Давайте:<br/></p>
<pre><code class="css">    ul li:nth-child(even) a{
      -o-transform:rotate(4deg);
      -webkit-transform:rotate(4deg);
      -moz-transform:rotate(4deg);
      position:relative;
      top:5px;
    }
    ul li:nth-child(3n) a{
      -o-transform:rotate(-3deg);
      -webkit-transform:rotate(-3deg);
      -moz-transform:rotate(-3deg);
      position:relative;
      top:-5px;
    }
    ul li:nth-child(5n) a{
      -o-transform:rotate(5deg);
      -webkit-transform:rotate(5deg);
      -moz-transform:rotate(5deg);
      position:relative;
      top:-10px;
    }
</code></pre>
<p><br/><br />
Теперь же каждая вторая ссылка будет наклонена на 4 градуса вправо, отступы по пятью Каждая третья будет отклонена на 3 градуса влево. И так далее… Пока не закончится фантазия.<br/></p>
<h4>Шаг 4</h4>
<p><br/><br />
Согласитесь, надо внести возможность увеличивать нашу заметку при наведении на неё курсором. <s>Тут мы опять воспользуемся CSS3, что не удивительно.</s> Сказано — сделано:<br/></p>
<pre><code class="css">    ul li a:hover,ul li a:focus{
      -moz-box-shadow:10px 10px 7px rgba(0,0,0,.7);
      -webkit-box-shadow: 10px 10px 7px rgba(0,0,0,.7);
      box-shadow:10px 10px 7px rgba(0,0,0,.7);
      -webkit-transform: scale(1.25);
      -moz-transform: scale(1.25);
      -o-transform: scale(1.25);
      position:relative;
      z-index:5;
    }
</code></pre>
<p><br/><br />
Мы добавили такой высокий <i>z-index</i> для того, чтобы при наведении наш стикер не ограничивал себя <s>в захвате земель</s> и перекрывал ближние стикеры. Собственно, при наведении мы увидим следующую картину:<br/><br />
<img src="http://habrastorage.org/storage2/4d0/a97/055/4d0a97055f0f60917c2a9a692e5195fc.png"/><br/></p>
<h4>Шаг 5</h4>
<p><br/><br />
Всё-таки надо доделать, чтобы было красиво. Понимаете, чего нам не хваиает? Правильно, анимации. Нужно сделать переходы плавными, а не каменными. <s>Такое ощущение, что ты в каменном веке или же тебе не хватает ЦП.</s> Что же, поехали:<br/></p>
<pre><code class="css">    ul li a{
      text-decoration:none;
      color:#000;
      background:#ffc;
      display:block;
      height:10em;
      width:10em;
      padding:1em;
      -moz-box-shadow:5px 5px 7px rgba(33,33,33,1);
      -webkit-box-shadow: 5px 5px 7px rgba(33,33,33,.7);
      box-shadow: 5px 5px 7px rgba(33,33,33,.7);
      -moz-transition: -moz-transform .15s linear;
      -o-transition: -o-transform .15s linear;
      -webkit-transition:-webkit-transform .15s linear;
    }
</code></pre>
<p><br/><br />
Вот она наша анимация. К сожалению, скриншот не может её передать также, как телефон не может передать запах свежеиспечённой <s>птицы</s> пиццы. <s>Какая жаль!</s><br/><br />
Но ещё бы хотелось разукрасить наши стикеры, а то как-то уж всё монотонно. Каждый второй стикер будет зелёным, каждый третий — синим. А что, неплохо.<br/></p>
<pre><code class="css">ul li:nth-child(even) a{
  -o-transform: rotate(4deg);
  -webkit-transform: rotate(4deg);
  -moz-transform: rotate(4deg);
  position: relative;
  top: 5px;
  background: #cfc;
}
ul li:nth-child(3n) a{
  -o-transform: rotate(-3deg);
  -webkit-transform: rotate(-3deg);
  -moz-transform: rotate(-3deg);
  position: relative;
  top: -5px;
  background: #ccf;
}
</code></pre>
<p><br/><br />
Опять же, анимацию мы на скриншоте увидеть не сможем, но нашу трёхцветную <s>зёбру</s> смесь — без проблем. А вообще, пример вы можете посмотреть <a href="http://d2o0t5hpnwv4c1.cloudfront.net/771_sticky/step5.html">здесь</a>.<br/><br />
<img src="http://habrastorage.org/storage2/bb5/4a9/1d6/bb54a91d69dd317f9471efe2d4e11011.png"/><br/></p>
<h4>Заключение</h4>
<p><br/><br />
Ну вот и всё на сегодня. Сегодня мы научились создавать красивые анимированные стикеры с помощью CSS3. Ведь красивые, правда?<br/><br />
Пример данного урока можно стянуть <a href="http://d2o0t5hpnwv4c1.cloudfront.net/771_sticky/stickynotes.zip">здесь</a>.<br/><br />
До скорых встреч!</p>
<p>© <a href="http://m.habrahabr.ru/post/136238/">Habrahabr.ru</a></p>
]]></content:encoded>
			<wfw:commentRss>http://vwlab.ru/post/206/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Плагин jQuery для сортировки таблиц: TableSorter.js. Как добиться постраничной навигации?</title>
		<link>http://vwlab.ru/post/204/</link>
		<comments>http://vwlab.ru/post/204/#comments</comments>
		<pubDate>Sun, 15 Jan 2012 15:28:11 +0000</pubDate>
		<dc:creator>Niko</dc:creator>
				<category><![CDATA[Разное]]></category>

		<guid isPermaLink="false">http://vwlab.ru/?p=204</guid>
		<description><![CDATA[Вступление При разработке одного проекта мне пришлось решать проблему с сортировкой данных в таблице. Не хотелось для этого использовать PHP, так как эффект теряется при перезагрузке страницы. Вот и наткнулся я на официальный сайт jQuery-плагина &#171;TableSorter.js&#187; — www.tablesorter.com. Немного покопавшись &#8230;<p class="read-more"><a href="http://vwlab.ru/post/204/">Читать далее &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<h4>Вступление</h4>
<p><br/><br />
<img src="http://habrastorage.org/storage2/118/8d7/0cf/1188d70cf63b6de7c16aa3d9460916c8.png" align="right"/>При разработке одного проекта мне пришлось решать проблему с сортировкой данных в таблице. Не хотелось для этого использовать <b>PHP</b>, так как эффект теряется при перезагрузке страницы. Вот и наткнулся я на официальный сайт jQuery-плагина &#171;<b>TableSorter.js</b>&#187; — <a href="http://www.tablesorter.com">www.tablesorter.com</a>. Немного покопавшись в англоязычной документации я с радостью обнаружил в новостях сайта ссылку на русскоязычный сайт: <a href="http://www.tablesorter.ru">www.tablesorter.ru</a>.<br/><br />
В принципе там всё предельно ясно было описано и я быстро понял как всё работает… <br/><br />
Но было в документации одно важное упущение: недостаточно описан принцип работы постраничной навигации, да и нужные файлы не выложены. А мне как-раз нужна была эта функция, так как в моих таблицах было минимум по 150 строк. Пришлось самому решить эту проблему. <br/><br />
 <span id="more-204"></span> <br/></p>
<h5>Необходимые материалы</h5>
<p><br/></p>
<ul>
<li>Качаем/подключаем к нашей странице следующие скрипты:</li>
<li>Сам jQuery: <a href="http://code.google.com/intl/ru-RU/apis/libraries/devguide.html#jquery">code.google.com/intl/ru-RU/apis/libraries/devguide.html#jquery</a></li>
<li>Плагин TableSorter: <a href="http://tablesorter.ru/jquery.tablesorter.min.js">tablesorter.ru/jquery.tablesorter.min.js</a></li>
<li>Плагин к TableSorter для постраничной навигации: <a href="http://tablesorter.ru/addons/pager/jquery.tablesorter.pager.js">tablesorter.ru/addons/pager/jquery.tablesorter.pager.js</a></li>
<li>Синеватая тема (есть и зеленая): <a href="http://tablesorter.ru/themes/blue/blue.zip">tablesorter.ru/themes/blue/blue.zip</a></li>
<li>Архив с картинками для постраничной навигации: <a href="http://bazmaster.ru/downloads/table.zip">bazmaster.ru/downloads/table.zip</a></li>
</ul>
<p><br/></p>
<h4>Постраничная навигация</h4>
<p><br/><br />
Сейчас я покажу вам как настроить постраничную навигацию с помощью этого плагина — на самом деле решение довольно простое, а вот на поиск этого решения у меня ушло немало времени. <br/><br />
Разобрался я с этой проблемой только тщательно изучив код данного там примера и скачав все рисунки и нужный мне код с кода самой страницы.<br/><br />
Картинки я собрал в отдельный архив, который вы сможете использовать.<br/><br />
Подключаем в теге <b>HEAD</b> нашей страницы все наши скрипты и стили. У меня они выглядели так:<br/></p>
<pre><code class="html">
<link type="text/css" rel="stylesheet" href="bluetable/style.css">
    <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
    <script type="text/javascript" src="/js/jquery.metadata.js"></script>
    <script type="text/javascript" src="/js/jquery.tablesorter.js"></script>
    <script type="text/javascript" src="/js/jquery.tablesorter.pager.js"></script>
</code></pre>
<p><br/><br />
Здесь же, в теге <b>HEAD</b>, пишем javascript-код, который и заставит нашу таблицу работать правильно:<br/></p>
<pre><code class="javascript">    <script type="text/javascript">
$(document).ready(function() { 
    $("table") 
    .tablesorter({widthFixed: true, widgets: ['zebra']}) 
    .tablesorterPager({container: $("#pager")}); 
});
    </script>
</code></pre>
<p><br/><br />
Далее распаковываем архив с картинками в папку <i>/images/table</i><br/><br />
Наша таблица будет выглядеть следующим образом:<br/></p>
<pre><code class="html">
<table cellspacing="1" class="tablesorter">
<thead>
<tr>
<th>имя</th>
<th>фамилия</th>
<th>возраст</th>
<th>итого</th>
<th>скидка</th>
<th>дата</th>
</tr>
</thead>
<tbody>
<tr>
<td>петр</td>
<td>сидоров</td>
<td>28</td>
<td>$9.99</td>
<td>20%</td>
<td>jul 6, 2006 8:14 am</td>
</tr>
<tr>
<td>иван</td>
<td>хайкин</td>
<td>33</td>
<td>$19.99</td>
<td>25%</td>
<td>dec 10, 2002 5:14 am</td>
</tr>
<tr>
<td>николай</td>
<td>котов</td>
<td>18</td>
<td>$15.89</td>
<td>44%</td>
<td>jan 12, 2003 11:14 am</td>
</tr>
<tr>
<td>борис</td>
<td>арнов</td>
<td>45</td>
<td>$153.19</td>
<td>44%</td>
<td>jan 18, 2001 9:12 am</td>
</tr>
<tr>
<td>борис</td>
<td>егоров</td>
<td>22</td>
<td>$13.19</td>
<td>11%</td>
<td>jan 18, 2007 9:12 am</td>
</tr>
</tbody>
</table>

</code></pre>
<p><br/><br />
И теперь подключаем те самые наши элементы навигации, которые в документации не указаны (без них будут ошибки на странице):<br/></p>
<pre><code class="html">
<div id="pager" class="pager" style="top: 652px; position: absolute; ">
<form>
		<img src="/images/table/first.png" class="first">
		<img src="/images/table/prev.png" class="prev"> 
<input type="text" class="pagedisplay">
		<img src="/images/table/next.png" class="next">
		<img src="/images/table/last.png" class="last"> 
<select class="pagesize">
<option selected="selected" value="10">10</option>
<option value="20">20</option>
<option value="30">30</option>
<option value="40">40</option>
</select></form>
</div>

</code></pre>
<p><br/><br />
Всё! Теперь наша таблица работает исправно!</p>
<p>© <a href="http://m.habrahabr.ru/post/136228/">Habrahabr.ru</a></p>
]]></content:encoded>
			<wfw:commentRss>http://vwlab.ru/post/204/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Британский студент проиграл дело об экстрадиции в США за пиратство</title>
		<link>http://vwlab.ru/post/202/</link>
		<comments>http://vwlab.ru/post/202/#comments</comments>
		<pubDate>Sun, 15 Jan 2012 15:27:38 +0000</pubDate>
		<dc:creator>Niko</dc:creator>
				<category><![CDATA[Разное]]></category>

		<guid isPermaLink="false">http://vwlab.ru/?p=202</guid>
		<description><![CDATA[Ричард О’Дваер и его мама 23-летний британский студент Ричард О’Дваер (Richard O&#8217;Dwyer) всё-таки проиграл судебную битву по поводу экстрадиции в США. Вестминстерский суд вынес вердикт (PDF), что О&#8217;Дваер подпадает под действие Extradition Act 2003 между Великобританией и США. Теперь адвокат &#8230;<p class="read-more"><a href="http://vwlab.ru/post/202/">Читать далее &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<p><img src="http://habrastorage.org/storage2/b80/beb/fd2/b80bebfd28d096ff8b34c203e56a9c3d.jpg"/><br/><br />
<sup>Ричард О’Дваер и его мама</sup><br/><br />
23-летний британский студент Ричард О’Дваер (Richard O&#8217;Dwyer) всё-таки <a href="http://www.bbc.co.uk/news/uk-england-south-yorkshire-16544335">проиграл</a> судебную битву по поводу экстрадиции в США. Вестминстерский суд вынес вердикт (<a href="http://www.judiciary.gov.uk/Resources/JCO/Documents/Judgments/us-v-odwyer-ruling.pdf">PDF</a>), что О&#8217;Дваер подпадает под действие Extradition Act 2003 между Великобританией и США. Теперь адвокат О&#8217;Дваера подаст апелляцию на это решение в суд высшей инстанции.<br/><br />
Ричард О’Дваер был арестован британской полицией <a href="http://habrahabr.ru/company/webnames/blog/123494/">в июне 2011 года</a> по наводке американского подразделения U.S. Immigration and Customs Enforcement. Он является основателем поискового сайта TVShack.net, где с 2007 по 2010 годы размещались ссылки на пиратские копии фильмов и телевизионных программ.<br/><br />
Хотя Ричард закрыл сайт ещё в ноябре 2010 года (после того, как к нему домой нагрянула полиция и конфисковала все компьютеры), но его случай является принципиальным для американских властей. В марте 2011 года они всё-таки отправили в Великобританию запрос на экстрадицию. Ричард О’Дваер может стать первым человеком в мире, который будет экстрадирован в США по подобному обвинению.</p>
<p>© <a href="http://m.habrahabr.ru/post/136260/">Habrahabr.ru</a></p>
]]></content:encoded>
			<wfw:commentRss>http://vwlab.ru/post/202/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Использование Table View</title>
		<link>http://vwlab.ru/post/200/</link>
		<comments>http://vwlab.ru/post/200/#comments</comments>
		<pubDate>Sun, 15 Jan 2012 15:27:09 +0000</pubDate>
		<dc:creator>Niko</dc:creator>
				<category><![CDATA[Разное]]></category>

		<guid isPermaLink="false">http://vwlab.ru/?p=200</guid>
		<description><![CDATA[Доброго времени суток! Уже достаточно давно пытаюсь заставить себя изучить очередной язык/платформу для программирования под Mac OS X/iOS. Интересует именно разработка приложений с нативным GUI, так как консольные приложения можно разрабатывать на чем угодно, начиная с C и C++ и &#8230;<p class="read-more"><a href="http://vwlab.ru/post/200/">Читать далее &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<p>Доброго времени суток!<br/><br />
Уже достаточно давно пытаюсь заставить себя изучить очередной язык/платформу для программирования под Mac OS X/iOS. Интересует именно разработка приложений с нативным GUI, так как консольные приложения можно разрабатывать на чем угодно, начиная с C и C++ и заканчивая модным сейчас Nodejs. Как показала практика, кроссплатформенные фреймворки вроде Qt тут мало подходят, хотя бы потому что не обеспечивают нативный Look and Feel, к которому привыкли пользователи этой ОС.<br/><br />
На хабре есть достаточное количество материалов по языку Objective-C и фреймворку Cocoa. С точки зрения GUI, интерес представляет именно Cocoa, а тут большинство статей ограничивается кнопочками и текстовыми полями. Постараюсь исправить это недоразумение и описать работу с Table View на примере приложения, отображающего список процессов.<br/><br />
Статья не претендует на полноту изложения и абсолютную корректность материала и ориентирована, прежде всего, на начинающих разработчиков. Ошибки и конструктивную критику с радостью выслушаю в комментариях. Кому интересно, добро пожаловать под кат.<br/><br />
 <span id="more-200"></span> <br/></p>
<h4>Теория</h4>
<p><br/><br />
Для разработки нам потребуются некоторые знания о Table View. Давайте с них и начнем. Подробное описание работы с Table View приведено в [1], здесь я ограничусь кратким изложением основных идей.<br/></p>
<h5>Типы Table View</h5>
<p><br/><br />
Существует два вида Table View:<br/></p>
<ul>
<li><b>cell-based</b> — каждая ячейка таблицы представлена подклассом <i>NSCell</i>. В большинстве случаев этого достаточно, но создает трудности при разработке таблиц с комплексными ячейками, т.к. требует создания подкласса <i>NSCell</i>. В версиях Mac OS X 10.6 и более ранних существовал только этот тип таблиц.</li>
<li><b>view-based</b> — каждая ячейка представляет собой отдельный view. Это позволяет строить комплексные таблицы даже с поддержкой анимации без особых трудностей. Данный тип таблицы появился только в Mac OS X 10.7.</li>
</ul>
<p><br/><br />
В этой статье мы рассмотрим работу с <b>cell-based table view</b>, так как нам достаточно его функций, решение получится более простым и будет работать не только с новыми версиями OS X.<br/></p>
<h5>Передача данных в Table View</h5>
<p><br/><br />
Данные в Table View можно передавать двумя способами:<br/></p>
<ul>
<li>С помощью реализация протоколов (интерфейсов) <i>NSTableViewDelegate</i>, <i>NSTableViewDataSource</i>, а затем связывать Table View с классом, реализующим эти протоколы посредством Interface Builder. Необходимо привязать Outlets <i>dataSource</i> и <i>delegate</i>. А в этом классе в самом простом случае необходимо реализовать два метода:<br/>
<ul>
<li><i>numberOfRowsInTableView:</i> — возвращает общее количество строк в таблице</li>
<li><i>tableView:objectValueForTableColumn:row:</i> — возвращает элемент для строки, переданной в аргументе <i>row</i>. Номер столбца в этом случае определяется различными способами, используя второй аргумент <i>objectValueForTableColumn</i>.</li>
</ul>
<p><br/>
 </li>
<li>С использованием контроллера и биндингов (Bindings). Эта техника основана на паттерне Model-View-Controller (MVC) [2] и технологии Cocoa Bindings. Про MVC, наверное, смысла рассказывать нет — про него все слышали, а кто не слышал, может ознакомиться по приведенной ссылке в Wiki. На Cocoa Bindings остановимся подробнее.</li>
</ul>
<p><br/></p>
<h5>Cocoa Bindings</h5>
<p><br/><br />
Cocoa Bindings появился в версии Mac OS X, начиная с версии 10.3. Основная его цель — сократить объем кода контроллера для связи объектов модели (Model) и представления (View).<br/><br />
Cocoa Bindings основан на двух механизмах:<br/></p>
<ul>
<li><b>Key-Value Coding (KVC)</b> — механизм для доступа к полям объекта по именам этих полей.</li>
<li><b>Key-Value Observing (KVO)</b> — механизм, позволяющий одним объектам следить за изменениями в других объектах.</li>
</ul>
<p><br/><br />
Более подробно о Cocoa Bindings можно почитать в [3].<br/><br />
На этом с теорией закончили, можно переходить к практике.<br/></p>
<h4>Практика</h4>
<p><br/><br />
Открываем Xcode и создаем новый проект «Cocoa Application». Назовем его «Process Monitor». Я использую последнюю на момент публикации версию Xcode (4.2.1), поэтому некоторые шаги могут отличаться.<br/></p>
<h5>Создание GUI</h5>
<p><br/><br />
Открываем файл MainMenu.xib, в нем выбираем Window. Установим для него размеры 480 на 500. Это делается в Size Inspector (значок линейки в правом сайдбаре). Там же установим минимальные размеры — чекбокс и нужные размеры.<br/><br />
Добавляем в окно элемент Table View из Object Library (значок куба в правом нижнем сайдбаре) (поиск по слову «table»). По умолчанию создается таблица cell-based. В этом можно убедиться, если открыть Attributes Inspector (в правом сайдбаре, слева от линейки). Изменяем размеры Table View так, чтобы она занимала все окно. Затем открываем Size inspector и на картинке Autosizing выбираем все элементы — это необходимо, чтобы Table View растягивалась вместе с окном.<br/><br />
Теперь нам необходимо добавить столбцы в таблицу. Будем отображать три столбца — PID процесса, иконку и название процесса. По умолчанию в таблицу добавлено два столбца. Нужно изменить это число на 3. Для этого выбираем таблицу (Table View) кликом в окне. Тут нужно сделать небольшое отступление. Дело в том, что объекты окна вложены друг в друга и выделить нужный совсем не просто. Есть два варианта: это либо выбор нужного элемента в иерархии объектов в окне Objects (думаю, он появился в Xcode 4, раньше я его не видел), либо Command+Control+Shift Click на окне с выбором нужного объекта. После выбора таблицы переходим в Attributes Inspector и устанавливаем значение Columns в 3.<br/><br />
Теперь присвоим имена столбцам. Это делается двойным кликом по заголовку столбца. Имя первого столбца — PID, второй оставим пустым, третий — Process Name.<br/><br />
Изменяем размер столбцов таблицы. Для этого выделяем столбец и в Size Inspector устанавливаем его размеры. Для первого (PID): 60, для второго (Icon): 40, для третьего (Process Name) — все оставшееся место.<br/><br />
Заменим тип второго столбца таблицы с текстового на изображение. Для этого в Object Library найдем Image Cell (поиск по «image») и перетащим ее на второй столбец. <br/><br />
После всех этих действий можно нажать кнопку Run и увидеть такое окно:<br/><br />
<img src="http://habrastorage.org/storage2/d51/bef/b09/d51befb09db673adf4d7f6552d533034.png"/><br/></p>
<h5>Добавление контроллера и биндингов</h5>
<p><br/><br />
Теперь добавим controller, который будет взаимодействовать с таблицей. Самый подходящий тип котроллера для таблицы это NSArrayController. Найдем его в Object Library (поиск по «array») и перетащим в список Objects.<br/><br />
Установим биндинги для таблицы. Для этого выделим Table View и перейдем в Bindings Inspector (предпоследняя вкладка в правом сайдбаре). Там в разделе Table Content выберем Content и установим Bind to: Array Controller с Controller Key: arrangedObjects.<br/><br />
Теперь воспользуемся техникой KVC и укажем какие данные должен отображать каждый столбец. Для этого мы по очереди выделяем каждый столбец (Table Column) и в Bindings Inspector устанавливаем Value в Bind to: Array Controller с Controller Key: arrangedObjects. А для каждого столбца значения Model Key Path соответственно: processIdentifier, icon, localizedName. Почему установлены такие значения, будет описано ниже.<br/><br />
Так мы связали таблицу с контроллером. Осталось связать контроллер с данными.<br/><br />
Первым делом определим эти самые данные. Откроем файл AppDelegate.h и определим свойство contents типа NSArray:<br/></p>
<pre><code class="cpp">@property (retain) NSArray* contents;
</code></pre>
<p><br/><br />
В файле AppDelegate.m напишем:<br/></p>
<pre><code class="cpp">@synthesize contents;
</code></pre>
<p><br/><br />
Теперь вернемся к MainMenu.xib и скажем контроллеру какие данные использовать. Идем в Bindings Inspector и в разделе Controller Content устанавливаем Content Array в Bind to: App Delegate, а Model Key Path: contents.<br/><br />
На этом установка биндингов окончена, нам осталось только заполнить массив contents в AppDelegate нужными данными.<br/></p>
<h5>Получение списка запущенных процессов</h5>
<p><br/><br />
Существует несколько способов получения списка всех запущенных процессов. Об этом я как-нибудь напишу в отдельной статье. А сейчас рассмотрим самый простой и очевидный способ — с использованием Cocoa. Он получает не полный список процессов, но пусть нас это пока не волнует.<br/><br />
Определим в AppDelegate метод updateProcessList:<br/></p>
<pre><code class="cpp">- (void)updateProcessList
{
    NSWorkspace* workspace = [NSWorkspace sharedWorkspace];
    self.contents = [NSArray arrayWithArray:[workspace runningApplications]];
}
</code></pre>
<p><br/><br />
Сделаем этот метод первым в классе, чтобы была возможность вызывать его из других методов без определения в заголовочном файле.<br/><br />
Немного прокомментирую код. В первой строчке мы получаем объект класса <i>NSWorkspace</i>. Объект этого класса существует в программе в единственном экземпляре, своеобразный синглтон, и получается методом <i>sharedWorkspace</i>.<br/><br />
У этого объекта есть метод <i>runningApplications</i>, возвращающий список запущенных приложений в массиве. Все просто. И этот массив мы используем в качестве данных для контроллера.<br/><br />
Каждый элемент этого массива представляет собой объект класса <i>NSRunningApplication</i>. У этого класса есть несколько свойств, среди которых есть <i>processIdentifier</i>, <i>icon</i>, <i>localizedName</i>. Помните, мы устанавливали их для столбцов таблицы? Так вот, благодаря KVC, во время отображения таблицы будут использоваться эти значения из <i>NSRunningApplication</i>.<br/><br />
Теперь добавим вызов созданного метода во время запуска приложения. Для этого нужно добавить строчку:<br/></p>
<pre><code class="cpp">[self updateProcessList];
</code></pre>
<p><br/><br />
в метод <i>applicationDidFinishLaunching</i>.<br/></p>
<h6>Завершение приложения</h6>
<p><br/><br />
В Mac OS X принято что приложение не обязательно должно завершаться после того как закрыто последнее окно. В нашем примере в этом большого смысла нет, поэтому добавим автоматическое завершение. Делается это очень просто — добавлением одного метода в AppDelegate.m:<br/></p>
<pre><code class="cpp">- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender
{
    return YES;
}
</code></pre>
<p><br/></p>
<h4>Заключение</h4>
<p><br/><br />
Теперь наше приложение готово. Если все сделано правильно, то после запуска можно увидеть что-то подобное:<br/><br />
<img src="http://habrastorage.org/storage2/513/543/1d6/5135431d6b5fabd31c56128bf8fd011c.png"/><br/><br />
В качестве упражнения, предлагаю читателю реализовать периодическое обновление списка процессов. Для этого можно использовать класс <i>NSTimer</i> и метод <i>scheduledTimerWithTimeInterval</i> этого класса [5].<br/><br />
Итак, в этой статье мы рассмотрели процесс создания простого приложения с использованием Table View. Большая часть действий проводилась в Interface Builder и не требовала программирования вообще. Все что можно было упростить, было упрощено — не были рассмотрены контроллеры окон (<i>NSWindowController</i>), контроллеры представлений (<i>NSViewController</i>), управление памятью и многое другое.<br/><br />
В следующей статье я планирую рассмотреть иерархический список (<i>NSOutlineView</i>) для отображения дерева процессов. И, если кода там наберется достаточно, сделаю репозиторий на github&#8217;е.<br/><br />
<b>Всем спасибо за внимание!</b><br/></p>
<h4>Ссылки</h4>
<p><br/></p>
<ol>
<li><a href="http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/TableView/Introduction/Introduction.html">Table View Programming Guide</a> (en)</li>
<li><a href="http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller">Model–view–controller pattern</a> (en)</li>
<li><a href="http://pyobjc.ru/2008/10/27/rabota-cocoa-bindings/">Работа Cocoa Bindings</a> (ru)</li>
<li><a href="http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/NSWorkspace_Class/Reference/Reference.html">NSWorkspace Class Reference</a> (en)</li>
<li><a href="http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSTask_Class/Reference/Reference.html">NSTask Class Reference</a> (en)</li>
</ol>
<p>© <a href="http://m.habrahabr.ru/post/136265/">Habrahabr.ru</a></p>
]]></content:encoded>
			<wfw:commentRss>http://vwlab.ru/post/200/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Новые спутниковые снимки на Яндекс.Картах</title>
		<link>http://vwlab.ru/post/197/</link>
		<comments>http://vwlab.ru/post/197/#comments</comments>
		<pubDate>Fri, 16 Dec 2011 15:39:51 +0000</pubDate>
		<dc:creator>Niko</dc:creator>
				<category><![CDATA[Разное]]></category>

		<guid isPermaLink="false">http://vwlab.ru/?p=197</guid>
		<description><![CDATA[На Яндекс.Картах появились новые спутниковые снимки общей площадью 147 тыс. кв. км. Теперь на Яндекс.Картах можно посмотреть, как из космоса выглядят Токио, Пекин, Сеул или Пхеньян. На спутниковой карте Турции появились такие крупные города как Чорлу, Текирдаг, Османие, а в &#8230;<p class="read-more"><a href="http://vwlab.ru/post/197/">Читать далее &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<p>На <a href="http://maps.yandex.ru">Яндекс.Картах</a> появились новые спутниковые снимки общей площадью 147 тыс. кв. км. Теперь на Яндекс.Картах можно посмотреть, как из космоса выглядят <a href="http://maps.yandex.ru/-/CFaTbTNN">Токио</a>, <a href="http://maps.yandex.ru/-/CFaTjYIK">Пекин</a>, <a href="http://maps.yandex.ru/-/CFaTjT0W">Сеул</a> или <a href="http://maps.yandex.ru/-/CFaTnViY">Пхеньян</a>. На спутниковой карте Турции появились такие крупные города как <a href="http://maps.yandex.ru/-/CFaTr46F">Чорлу</a>, <a href="http://maps.yandex.ru/-/CFaTrPZa">Текирдаг</a>, <a href="http://maps.yandex.ru/-/CFaTzU74">Османие</a>, а в Казахстане мы добавили снимки <a href="http://maps.yandex.ru/-/CFaT7F6u">Актобе</a>, <a href="http://maps.yandex.ru/-/CFaXAR53">Рудного</a>, <a href="http://maps.yandex.ru/-/CFaXECNc">Екибастуза</a>. Также на спутниковых снимках Яндекса появилось сразу 2 целых государства <a href="http://maps.yandex.ru/-/CFaXIFyA">Сан-Марино</a> и <a href="http://maps.yandex.ru/-/CFaX4YyE">Андорра</a>, население которых 31 тыс. и 91 тыс. человек.<br/><br />
Увидеть все новые спутниковые снимки можно на <a href="http://maps.yandex.ru/-/CFUGUF7U">карте релиза</a>. <br/><br />
В целом за прошедший год мы увеличили площадь покрытия наших спутниковых снимков в 12 раз – со 116 тыс. кв. км. до 1,4 млн кв. км. <br/><br />
Напоминаем, что новые спутниковые снимки можно использовать и для того, чтобы рисовать объекты на Народной Карте. <br/><br />
И в завершение хотим поделиться с вами некоторыми из интересных достопримечательностей, которые появились на новых спутниковых снимках: <br/><br />
<a href="http://maps.yandex.ru/-/CFaX684X">Северная Корея, Пхеньян, Строящаяся гостиница Рюгён</a><br/><br />
<a href="http://fotki.yandex.ru/users/sderevtsov/view/327207/"><img src="http://img-fotki.yandex.ru/get/4421/127811081.0/0_4fe27_c1fe3d06_L.jpg"/></a><br/>
</p>
<p><br/><br />
<a href="http://maps.yandex.ru/-/CFaXbGke">Корея, Сеул, Корейский военный музей</a><br/><br />
<a href="http://fotki.yandex.ru/users/sderevtsov/view/327206/"><img src="http://img-fotki.yandex.ru/get/5314/127811081.0/0_4fe26_84813657_L.jpg"/></a><br/><br />
<a href="http://maps.yandex.ru/-/CFaXfKZB">Китай, Пекин, Запретный город</a><br/><br />
<a href="http://fotki.yandex.ru/users/sderevtsov/view/327205/"><img src="http://img-fotki.yandex.ru/get/4526/127811081.0/0_4fe25_ee04962b_L.jpg"/></a><br/><br />
<a href="http://maps.yandex.ru/-/CFaXj4kk">Япония, Токио, Императорская резиденция</a><br/><br />
<a href="http://fotki.yandex.ru/users/sderevtsov/view/327204/"><img src="http://img-fotki.yandex.ru/get/5314/127811081.0/0_4fe24_b6d3934d_L.jpg"/></a><br/><br />
<a href="http://maps.yandex.ru/-/CFaXzIOU">США, Окленд, стадион «Колизей»</a><br/><br />
<a href="http://fotki.yandex.ru/users/sderevtsov/view/327203/"><img src="http://img-fotki.yandex.ru/get/4422/127811081.0/0_4fe23_4fc9b5aa_L.jpg"/></a><br/><br />
<b><i>Команда Яндекс.Карт</i></b><img src="http://clck.yandex.ru/click/dtype=blogpost/path=company.42475/*http%3A//clubs.ya.ru" alt="."/></p>
<p>© <a href="http://m.habrahabr.ru/post/134731/">Habrahabr.ru</a></p>
]]></content:encoded>
			<wfw:commentRss>http://vwlab.ru/post/197/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Настольные игры: во что играют в IT-офисах</title>
		<link>http://vwlab.ru/post/195/</link>
		<comments>http://vwlab.ru/post/195/#comments</comments>
		<pubDate>Fri, 16 Dec 2011 15:39:33 +0000</pubDate>
		<dc:creator>Niko</dc:creator>
				<category><![CDATA[Разное]]></category>

		<guid isPermaLink="false">http://vwlab.ru/?p=195</guid>
		<description><![CDATA[В январе прошлого года я делал обзор IT-настолок, который оказался постом выбора подарков. В этом году обзор — до Нового Года, как просили в комментариях. Раньше игры с компьютера «портировались» в настольные игры, например, так стало со Starcraft, Warcraft, Doom, &#8230;<p class="read-more"><a href="http://vwlab.ru/post/195/">Читать далее &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<p><img src="http://habrastorage.org/storage1/23df600f/1eac2673/9d95265c/c81f683f.jpg" title="Да, это спойлер"/><br/><br />
В январе прошлого года я делал <a href="http://habrahabr.ru/company/mosigra/blog/112118/">обзор IT-настолок</a>, который оказался постом выбора подарков. В этом году обзор — до Нового Года, как просили в комментариях.<br/><br />
Раньше игры с компьютера «портировались» в настольные игры, например, так стало со Starcraft, Warcraft, Doom, Civilization, Master of Orion и кучей других шедевров. <br/><br />
В этом году ситуация радикально поменялась: из-за огромного распространения планшетов и мобильных телефонов с хорошей поддержкой игр, настолки стали перекочёвывать в Appstore и Android Market. Под катом обзор наиболее интересных штук этого года, пример отечественного краудсорсингового проекта и традиционный <b>небольшой подарок</b> всем хабражителям.<br/><br />
 <span id="more-195"></span><br />
<h3>В атаку на мобильные рынки!</h3>
<p><br/><br />
Поиск по Аппстору показывает, что сейчас есть больше сотни разных портов настольных игр (не считая кучи разновидностей одинаковых и вспомогательных приложений типа счётчика жизней или подсказок по правилам). <br/><br />
Началось всё с компании Hasbro, выпускающей кучу игр и игрушек в Америке. На настольном рынке она засветилась благодаря Монополии и ещё многим хитам. Эта компания одна из первых начала выходить на мобильный рынок и портировать игры. Первой ласточкой стала как раз Монополия (благо на тот момент её много кто делал в компьютерном формате), второй весьма необычной штукой — Дженга в настольной версии. Юмор в том, что игра требует ловкости и умения вытаскивать реальные деревянные бруски из реальной деревянной башни. Тач позволил это, и позволил более чем круто. <br/><br />
Сейчас на мобильных устройствах можно поиграть вот в такие знаковые для настольного рынка вещи:<br/><br />
Монополию, причём с сетевым режимом, чтобы можно было поиграть в самолёте, например. <br/></p>
<ul>
<li><b>Скрабл</b> — наверное, самая хитовая штука из всех. Там можно положить айпад в центр стола, а с помощью айфонов таскать буквы.</li>
<li><b>Уно</b> — вторая после Монополии по продаваемости в мире игрушка, её порт был просто предсказуем.</li>
<li><b>Каркассон и Колонизаторы</b> — простые стратегии, базовые настольные версии которых вошли в топ стратегий на российском рынке.</li>
<li>Психоделичный <b>Диксит</b> (правда, он не взлетел, потому что встретиться с игроками можно только по договорённости). </li>
<li><b>Ticket to Ride</b> — очень удачное переложение настолки на планшет.</li>
<li>Плюс, конечно же, шахматы, нарды, реверси, Калаху, го, 4 в ряд и много других классических игр. Я видел даже порты Микадо (игры одесских карманников типа бирюлек), в которые вообще непонятно как играть без реальных физических палочек.</li>
</ul>
<p><br/><br />
Почти все эти игры входят в наш и американский топ-100 и отлично продаются. При этом, как я понимаю, они продаются там, где у людей уже есть физические версии таких штук (в частности, в США и Европе, где культура настолок сейчас чуть ли не важнее культуры чтения книг). Вообще, учитывая, что по Монополии собирались снимать фильм, а по Морскому бою <a href="http://lenta.ru/news/2011/01/11/degrade/">уже снимают</a>, становится понятно, насколько тема у них популярна. <br/></p>
<h3>А теперь обзор IT-подарков</h3>
<p><br/><br />
Во-первых, конечно же, <a href="http://habrahabr.ru/company/mosigra/blog/112118/">смотрите прошлый год</a>. Там перечислены почти все нестареющие хиты плюс есть несколько подсказок, как сделать игру самому из принтера и какой-то матери (в комментариях – альтернативный арт Куханделя + наши правила). Во-вторых, ниже — вышедшие в этом году штуки, которые обязательно стоит упомянуть. <br/><br />
<a href="http://www.mosigra.ru/Face/Show/hive/">Улей</a>. Игрушка весьма известная в кругах англоговорящих математиков: очень простая и красивая стратегия, которую многократно переносили в компьютерные версии. В этом году мы получили лицензию на её издание в России и начали продавать. Ощущение тяжеленных звонких фишек с насекомыми в руках очень радует.<br/><br />
<img src="http://habrastorage.org/storage1/3c42eb19/971e9493/934f3ba8/d27ae6a5.jpg"/><br/><br />
<i>Задача — окружить королеву противника. Вместо поля — бесконечная плоскость, разбитая на шестиугольники</i><br/><br />
В прошлый обзор не попал <a href="http://www.mosigra.ru/Face/Show/risk_new/">Риск</a>. Это глобальная стратегия, весьма любимая айтишниками в 90-х. Например, Марк Цукерберг начал свою карьеру разработчика не с сервиса сравнения девушек, как думают многие, а с переложения «Риска» в сетевой вариант. Если будете брать — лучше обратить внимание на ту версию, где вместо конкретных войск фишки сделаны в стиле инфографики: она в разы удобнее. <br/><br />
В начале года вышла долгожданная <a href="http://www.mosigra.ru/Face/Show/pandemic/">Пандемия</a> — игра про спасение мира. Она хороша тем, что вам не нужно конкурировать: игроки играют против игры, а не друг друга. Задача — метаться по планете и залечивать различные эпидемии. Игроки имеют разные функции: например, исследователь получает бонус при поиске вакцины, диспетчер умеет делать чартер куда угодно, а врач может вылечить сразу кучу больных одним махом. Грамотные договорки, хорошая оценка рисков и умение координироваться плюс толика удачи — и вы выигрываете. <br/><br />
<img src="http://habrastorage.org/storage1/a624af85/2e4de63a/796be6fd/a29ee7ed.jpg"/><br/><br />
<i>Пандемия</i><br/><br />
Те, кто помнит старый добрый сайт Ролемансер про настольные ролевые игры, помнит и «Эру Водолея» — отечественную систему, по которой играли в реале и на форумах. В этом году была выпущена вторая версия в виде <a href="http://www.mosigra.ru/Face/Show/era_vodoleya/">новой книги</a>. По ощущениям и отзывам — мало кто взял её играть, но много кто — по ностальгии. Книга оказалась очень хорошей, но взрыва активности на форумах, в отличие от первой, не вызвала.<br/><br />
Ещё в этом году вышло дополнение к Шакалу (игре с родословной в МГУ), вторая Эволюция, продолжение к кошмару проект-менеджера «За бортом!», куча новых Мафий и много других штук. Плюс я постоянно мониторю трафик с Хабра на предмет покупок и вижу, что особой популярностью в IT-среде стал пользоваться настольный хоккей, настольный футбол и Диксит (когда он был). Вообще, на Мосигре есть специальное место, где фигню не посоветуют: вот каталог подарков «<a href="http://www.mosigra.ru/allgames/gift_for_it/">Выбор Хабра</a>». <br/><br />
<img src="http://habrastorage.org/storage1/1ce8436e/d4c3e3b0/84e58602/99f9d3bd.jpg"/><br/><br />
<i><a href="http://www.mosigra.ru/search?q=%D0%B3%D0%BE">Го</a> — игра, в которой человеки пока лучше железных компьютеров.</i><br/></p>
<h3>Краудсорсинг-игра</h3>
<p><br/><br />
Красивый пример влияния сети на рынок — игрушка Имаджинариум. История началась так: есть достаточно популярный Диксит, который издают в Европе. Принцип игры очень простой: нужно брать карточку с психоделичным рисунком, загадывать ассоцицацию на неё и класть на стол. Каждый из игроков смотрит на свои карточки-рисунки, находит подходящий под ассоциацию и тоже кладёт на стол. Потом карты перемешиваются, а игроки пытаются понять, что именно из этого загадал ведущий. Штука очень творческая, весёлая и отлично подходит для тёплых дружеских встреч. <br/><br />
В России есть <i>элитни</i> сообщество людей, которые обожают в это играть. В какой-то момент эти люди понимают, что нужно делать свою игру, и начинают разрабатывать проект. Для рисования картинок привлекается сетевой краудсорсинг: в результате множество художников делают работы, которые входят в финальную версию. Игра закрывается крышкой, снабжается кучей пасхалок — и запускается в печать, причём очень быстро, буквально за пару месяцев от нуля до свежего тиража. Так появился <a href="http://www.mosigra.ru/Face/Show/imadjinarium/">Имаджинариум</a>. Если интересно, более ранний краудсорсинговый проект этой команды выглядит <a href="http://www.lubit.ru/Face/Show/vavilonskiy_razgovornik/">вот так</a>.<br/><br />
<img src="http://habrastorage.org/storage1/4211d3c8/e86d5428/e1846f34/46f1f8e7.jpg"/><br/><br />
<i>Вот оно</i><br/></p>
<h3>Что чаще всего стоит в офисах?</h3>
<p><br/><br />
Почти всегда есть Дженга (она засветилась у Лебедева плюс в куче разных офисов), много где есть футбол или хоккей на подставке, Яндекс, кажется, перетаскал все стратегии из нашего магазина около своего офиса, регулярно видно Свинтуса и Шакала. После специального издания для Epson популярным стал Бум, причём чаще брендированный под конкретную компанию. Постоянно и почти везде есть Мафия разных изданий, часто – с масками (да, был интересный хабратопик про эти маски). Иногда попадается «За бортом!», реже – Элиас и Активити. Вообще, за этот год игр в IT-офисах стало в разы больше, это заметно и очень радует. <br/><br />
<img src="http://habrastorage.org/storage1/0dcc3d10/19bd2c5f/69c299c6/d7367326.jpg"/> <br/><br />
<i>Дженга</i><br/></p>
<h3>Хей, а где мой маленький подарок?</h3>
<p><br/><br />
С теми, кто скажет пароль «<b>Хабрахабр</b>» в магазинах Мосигры или напишет это слово в примечаниях к заказу, сразу случится небольшая приятная скидка. <br/><br />
Акция действует с 15 по 25 декабря в Москве, Санкт-Петербурге, Киеве, Уфе, Оренбурге, Владивостоке, Ставрополе, Тюмени, Улан-Удэ, Норильске, Липецке, Казани, Нижнем Новгороде, Чебоксарах, Перми, Ярославле, Екатеринбурге, Астрахани, Омске, Твери, Томске, Воронеже, Тольятти, Харькове, Саратове и даже в Южно-Сахалинске, где сейчас очень-очень холодно. Есть момент: в Москве уже набирает обороты зерг-раш на магазины, поэтому акция относится только к интернет-магазину. <br/><br />
И да, тот спойлер сверху — он уже готов.</p>
<p>© <a href="http://m.habrahabr.ru/post/134710/">Habrahabr.ru</a></p>
]]></content:encoded>
			<wfw:commentRss>http://vwlab.ru/post/195/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Запускаем jQuery на движке Node.js вместо браузера</title>
		<link>http://vwlab.ru/post/193/</link>
		<comments>http://vwlab.ru/post/193/#comments</comments>
		<pubDate>Fri, 16 Dec 2011 15:38:39 +0000</pubDate>
		<dc:creator>Niko</dc:creator>
				<category><![CDATA[Разное]]></category>

		<guid isPermaLink="false">http://vwlab.ru/?p=193</guid>
		<description><![CDATA[Библиотека jQuery — это общепризнанное средство манипуляции сразу несколькими форматами данных (XML, HTML, объекты DOM, обыкновенные объекты), да притом работающее посредством удобного (цепного) вызова методов с удобными (краткими) названиями. Поэтому ничуть не удивляют попытки приспособить jQuery не только к одному клиентскому, но также ещё и к серверному джаваскрипту — в частности, к Node.js. Признаюсь честно, &#8230;<p class="read-more"><a href="http://vwlab.ru/post/193/">Читать далее &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<p><img src="http://upload.wikimedia.org/wikipedia/en/thumb/9/9e/JQuery_logo.svg/230px-JQuery_logo.svg.png" align="right"/>Библиотека jQuery — это общепризнанное средство манипуляции сразу несколькими форматами данных (XML, HTML, объекты DOM, обыкновенные объекты), да притом работающее посредством удобного (цепного) вызова методов с удобными (краткими) названиями. Поэтому ничуть не удивляют попытки приспособить jQuery не только к одному клиентскому, но также ещё и к серверному джаваскрипту — в частности, к Node.js.<br/><br />
Признаюсь честно, что когда разработчики jQuery превозмогли <a href="http://bugs.jquery.com/ticket/7102">проблему №7102</a>, то её название («Register jQuery as a CommonJS async module») <nobr>на какое-то</nobr> время даже заставило меня обмануться: я сперва подумал было, что и в Node.js (так как модули Node.js и СommonJS имеют немало общего) отныне jQuery станет работать невозбранно. Ан нет, <nobr>не тут-то</nobr> было. Пристальное вглядывание <nobr>в <a href="https://github.com/jquery/jquery/commit/bba3d610c7e3b611fe1eb89178c91106a156a5dc">коммит</a></nobr> <nobr>и в <a href="https://github.com/jquery/jquery/pull/331">запрос на слияние</a></nobr> позволяет осознать, что jQuery, в сущности, обрёл возможность регистрироваться только <nobr>как <a href="https://github.com/amdjs/amdjs-api/wiki/AMD">AMD</a>-модуль</nobr> и даже проверяет свойства <b>define.amd</b> <nobr>и <b>define.amd.jQuery</b></nobr> перед саморегистрацией.<br/><br />
<img src="http://upload.wikimedia.org/wikipedia/en/thumb/a/a7/Nodejs_logo_light.png/250px-Nodejs_logo_light.png" align="right"/>Собственно говоря, архитектура jQuery «затóчена» под употребление в условиях браузерной DOM: код jQuery полагается на существование объекта <b>window</b>, который служит аргументом главного замыкания, окаймляющего весь код jQuery. Прежде же таких неявных предположений было ещё больше, и только с устранением <a href="http://bugs.jquery.com/ticket/6690">проблемы №6690</a> библиотека jQuery перестала полагаться на существование глобальных объектов <b>navigator</b> <nobr>и <b>location</b>,</nobr> начав вместо того получать их как свойства объекта <b>window</b>. (Понятно, что такое предположение никак не подходило для Node.js, где глобальные объекты служат свойствами объекта <b>global</b>, а вовсе не <b>window</b>; а равно не подходило и ко многим прочим реализациям CommonJS.)<br/><br />
Потому для запуска jQuery <nobr>в Node.js</nobr> применяются готовые реализации <nobr>браузерной DOM —</nobr> такие, как пакет <a href="https://github.com/tmpvar/jsdom/">jsdom</a>, на основе которого невозбранно работает, например, вот какой код, предлагаемый в качестве примера:<br/><br />
 <span id="more-193"></span>
<pre><code class="javascript">// Print all of the news items on hackernews
var jsdom  = require('jsdom');
var fs     = require('fs');
var jquery = fs.readFileSync("./jquery-1.6.2.min.js").toString();

jsdom.env({
   html: 'http://news.ycombinator.com/',
   src: [
      jquery
   ],
   done: function(errors, window) {
      var $ = window.$;
      console.log('HN Links');
      $('td.title:not(:last) a').each(function() {
         console.log(' -', $(this).text());
      });
   }
});
</code></pre>
<p><br/><br />
А на jsdom, в свою очередь, основан пакет <nobr><a href="https://github.com/coolaj86/node-jquery">node-jQuery</a>,</nobr> отличающийся дополнительными обёртками из синтаксического сахара.<br/><br />
Другого метода, другого подхода к этой задаче нет, да пока что и быть не может.</p>
<p>© <a href="http://m.habrahabr.ru/post/134738/">Habrahabr.ru</a></p>
]]></content:encoded>
			<wfw:commentRss>http://vwlab.ru/post/193/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

