<?xml version='1.0' encoding='UTF-8'?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/" xmlns:blogger="http://schemas.google.com/blogger/2008" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" version="2.0"><channel><atom:id>tag:blogger.com,1999:blog-439775273064312982</atom:id><lastBuildDate>Tue, 17 Sep 2024 03:00:17 +0000</lastBuildDate><category>linux</category><category>ruby</category><category>devel</category><category>rant</category><category>software</category><category>blog</category><category>live</category><category>mac</category><category>android</category><category>gentoo</category><category>google</category><category>browser</category><category>n810</category><category>rails</category><category>links</category><category>windows</category><category>camping</category><category>distr</category><category>hint</category><category>python</category><category>rss</category><category>PL/SQL</category><category>c/objc/c++</category><category>db</category><category>javascript</category><category>net</category><category>config</category><category>vim</category><category>vm</category><category>в номер</category><category>Qt</category><category>fun</category><category>iphone</category><category>java</category><category>misc</category><category>quote</category><category>social</category><category>git</category><category>mashup</category><category>microsoft</category><category>ppc</category><category>presentation</category><category>rake</category><category>testing</category><category>dvcs</category><category>music</category><category>n70</category><category>tutorial</category><category>wtf</category><title>PhoeniX, гикнутый птиц</title><description>Пролетая над гнездом пингвинов. Непопулярно от Linux и open-source до интернета и разработки.</description><link>http://thegeekbird.blogspot.com/</link><managingEditor>noreply@blogger.com (PhoeniX)</managingEditor><generator>Blogger</generator><openSearch:totalResults>221</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><item><guid isPermaLink="false">tag:blogger.com,1999:blog-439775273064312982.post-3510412876989536803</guid><pubDate>Wed, 02 Nov 2011 06:10:00 +0000</pubDate><atom:updated>2011-11-02T12:10:09.856+06:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">android</category><category domain="http://www.blogger.com/atom/ns#">rant</category><title>Безопасности в Android нет.</title><description>Навеяно &lt;a href=&quot;http://www.infoq.com/articles/mobile-attacks-and-defense&quot;&gt;статьёй про безопасность&lt;/a&gt; в двух нынешних главных мобильных осях. Там более глубоко копают, я же недавно понял вот что - безопасности в андроид нет. Совсем.&lt;br /&gt;
&lt;br /&gt;
Что делает пользователь iOS для запуска нового приложения на устройстве? Покупает приложение, запускает. Что делает пользователь Android? Покупает &lt;i&gt;неизвестно откуда взявшийся непроверенный кусок кода&lt;/i&gt;, смотрит на диалог &quot;а вот тут надо какие-то разрешения&quot;, кликает OK, запускает. Всё, больше ничего не надо. Зашиваем в malware какой-нибудь universal androot и делаем с девайсом всё, что хотим.&lt;br /&gt;
&lt;br /&gt;
Пользователю не нужны все эти &quot;разрешения&quot;. Кому они могли бы понадобиться, так это review отделу, который бы смотрел - ага, тут доступ к контактам и сети, не уплывают ли первые во вторую? Но такого нет.</description><link>http://thegeekbird.blogspot.com/2011/11/android.html</link><author>noreply@blogger.com (PhoeniX)</author><thr:total>4</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-439775273064312982.post-2531111377591493042</guid><pubDate>Fri, 30 Sep 2011 22:55:00 +0000</pubDate><atom:updated>2011-10-01T04:57:49.461+06:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">hint</category><category domain="http://www.blogger.com/atom/ns#">mac</category><title>Time machine on SMB (Windows) shares</title><description>Итак, благодаря некоторым событиям, я перешёл в категорию людей, которые делают бэкапы. Чем делать вопрос практически не вставал - Time machine. Она есть, она надёжна, самостоятельна и проста (а ещё &quot;путешествие во времени&quot; красиво выглядит). А вот куда... Каждый раз втыкать внешний USB винт надоело быстро, это был верный способ перестать бэкапиться вообще. Так что по сети, а ввиду отсутсвия Time Capsule - на SMB сетевой диск. И вот для этого придётся немного пошаманить.&lt;br /&gt;
Для начала берём панель настроек &lt;a href=&quot;http://code.google.com/p/blacktree-secrets/&quot;&gt;Secrets&lt;/a&gt; и разрешаем в ней показывать в Time Mаchine неподдерживаемые диски (Show unsupported network volumes in Time Machine). Монтируем диск. Качаем &lt;a href=&quot;https://gist.github.com/gists/1255005/download&quot;&gt;скрипт&lt;/a&gt;, и если файловая система не case sensitive (эй! 21 век!), то &lt;a href=&quot;http://www.insanelymac.com/forum/index.php?act=attach&amp;type=post&amp;id=55807&quot;&gt;оригинал&lt;/a&gt;. Запускаем:&lt;br /&gt;
&lt;blockquote&gt;sh  ./makeImage.sh 600 /Volumes/backup&lt;/blockquote&gt;где число - максимальный размер файла с бэкапом, а путь - его будущее расположение.&lt;br /&gt;
После этого выбираем диск в Time Machine и бэкапимся. Без проводов.&lt;br /&gt;
&lt;br /&gt;
Есть ещё lifehack как использовать несколько мест для бэкапа, например, на работе и дома на разные диски. Time Machine хранит свои настройки в /Library/Preferences/com.apple.TimeMachine.plist. Настроив бэкап дома, копируем этот файл куда-нибудь с суффиксом .home, настроив на работе - с суффиксом .work. Правим простой скриптик:&lt;br /&gt;
&lt;code class=&quot;prettyprint lang-shell&quot;&gt;#!/bin/sh&lt;br /&gt;
profile=`basename $0`&lt;br /&gt;
defaults write com.apple.TimeMachine AutoBackup -bool false&lt;br /&gt;
sudo cp /Users/phoenix/cfg/com.apple.TimeMachine.plist.$profile /Library/Preferences/com.apple.TimeMachine.plist&lt;br /&gt;
defaults write com.apple.TimeMachine AutoBackup -bool true&lt;/code&gt;&lt;br /&gt;
под свои нужды, делаем на него симлинки:&lt;br /&gt;
&lt;blockquote&gt;ln -s timeswitch.sh home&lt;br /&gt;
ln -s timeswitch.sh work&lt;br /&gt;
&lt;/blockquote&gt;и настраиваем &lt;a href=&quot;http://www.symonds.id.au/marcopolo/&quot;&gt;Marco Polo&lt;/a&gt;(кстати, а есть ли альтернативы? программа более не поддерживается) запускать их в нужных местах.&lt;br /&gt;
Всё, теперь ноут бэкапится сам, всегда и везде.</description><link>http://thegeekbird.blogspot.com/2011/10/time-machine-on-smb-windows-shares.html</link><author>noreply@blogger.com (PhoeniX)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-439775273064312982.post-2461893863204096831</guid><pubDate>Fri, 30 Sep 2011 16:01:00 +0000</pubDate><atom:updated>2011-09-30T22:01:12.356+06:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">android</category><category domain="http://www.blogger.com/atom/ns#">iphone</category><category domain="http://www.blogger.com/atom/ns#">software</category><title>Remotix video</title><description>Вышло видео про Remotix, мне очень понравилось.
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;object width=&quot;320&quot; height=&quot;266&quot; class=&quot;BLOGGER-youtube-video&quot; classid=&quot;clsid:D27CDB6E-AE6D-11cf-96B8-444553540000&quot; codebase=&quot;http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0&quot; data-thumbnail-src=&quot;http://2.gvt0.com/vi/bD0j1Yh_mk4/0.jpg&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://www.youtube.com/v/bD0j1Yh_mk4&amp;fs=1&amp;source=uds&quot; /&gt;
&lt;param name=&quot;bgcolor&quot; value=&quot;#FFFFFF&quot; /&gt;
&lt;embed width=&quot;320&quot; height=&quot;266&quot;  src=&quot;http://www.youtube.com/v/bD0j1Yh_mk4&amp;fs=1&amp;source=uds&quot; type=&quot;application/x-shockwave-flash&quot;&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/div&gt;
&lt;br /&gt;&lt;/div&gt;
</description><link>http://thegeekbird.blogspot.com/2011/09/remotix-video.html</link><author>noreply@blogger.com (PhoeniX)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-439775273064312982.post-5787964197254475741</guid><pubDate>Mon, 26 Sep 2011 17:44:00 +0000</pubDate><atom:updated>2011-09-27T00:56:43.912+06:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">android</category><category domain="http://www.blogger.com/atom/ns#">live</category><category domain="http://www.blogger.com/atom/ns#">mac</category><title>Remotix и новости россыпью</title><description>&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://www.gstatic.com/android/market/com.nulana.android.remotix/f-1024-0&quot;&gt;&lt;img style=&quot;cursor:pointer; cursor:hand; width:100%;&quot; src=&quot;https://www.gstatic.com/android/market/com.nulana.android.remotix/f-1024-0&quot; border=&quot;0&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;br /&gt;Ну вот и &lt;a href=&quot;http://nulana.com/blog/42&quot;&gt;зарелизили Remotix&lt;/a&gt; (&lt;a href=&quot;http://nulana.com/blog/41&quot;&gt;и для iOS тоже&lt;/a&gt;). В духе эппол уличшились стабилити, компатибилити и секурити, ну и на планшетках он теперь совсем как живой смотрится. И вообще он теперь &quot;как надо&quot;.&lt;br /&gt;&lt;br /&gt;Кроме того переехал на ssd, ssd оказался говно, так что у меня теперь 3 бэкапа и восстанавливаю я из них свой мак за пару часов практически не отвлекаясь. Time machine - отдельная басня в стиле эппол - просто работает. Но если тебе надо, чтобы работало не просто, а как-то затейливо... то это непросто.&lt;br /&gt;&lt;br /&gt;Переехал на другой mbp (тоже с ssd). 13&quot; это, конечно, мало. SSD - это просто a must, без него совершенно невозможно - мысль сто раз успеет прокрутиться по кругу и уйти в неведомые дали, пока что-то там запускается на традиционном HDD. Трекпады эппол - лучшие трекпады в мире, но мне пока мышка удобнее. Дизайн &lt;a href=&quot;http://www.apple.com/macbookpro/&quot;&gt;mbp&lt;/a&gt; немного неудачен - все нужные порты толпятся на одном торце, и рудиментарный dvd привод на другом.&lt;br /&gt;&lt;br /&gt;Съездил в Питер, с собой были только Acer Iconia Tab A500 &amp; Acer Liquid. Икония очень так даже ничего, со своими задачами (навигация и почитать в метро в основном) справилась. Liquid за год сдал и разряжается непростительно быстро и иногда внезапно.&lt;br /&gt;&lt;br /&gt;Жду Deus Ex: Human Revolution под мак. Такими темпами как раз до середины доберусь к его выходу. Свет очей цифровой дистрибуции Steam в 21 веке спустя год со своего выпуска не научился работать на case sensitive файловой системе. Что за болячка такая?&lt;br /&gt;&lt;br /&gt;Так и живём.</description><link>http://thegeekbird.blogspot.com/2011/09/remotix.html</link><author>noreply@blogger.com (PhoeniX)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-439775273064312982.post-5242345527524152550</guid><pubDate>Sat, 24 Sep 2011 09:16:00 +0000</pubDate><atom:updated>2011-09-24T15:46:04.221+06:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">hint</category><category domain="http://www.blogger.com/atom/ns#">mac</category><title>Опять курощение iTunes</title><description>После какого-то очердного обновления iTunes отказался работать, и тебя мативировал, и меня мативировал, примерно вот так:&lt;br /&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-k2kAlu_SI-8/Tn2gS22cwaI/AAAAAAAAAog/EP5xZNnrhFQ/s1600/Screen%2Bshot%2B2011-09-24%2Bat%2B15.14.21.PNG&quot; onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot;&gt;&lt;img style=&quot;cursor:pointer; cursor:hand;width: 200px; height: 77px;&quot; src=&quot;http://3.bp.blogspot.com/-k2kAlu_SI-8/Tn2gS22cwaI/AAAAAAAAAog/EP5xZNnrhFQ/s200/Screen%2Bshot%2B2011-09-24%2Bat%2B15.14.21.PNG&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5655852952869192098&quot; /&gt;&lt;/a&gt;&lt;br /&gt;При этом запустить его предложенным способом невозможно - указанной настройки тупо нет.&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Но подкастов-то надо! (Предпочитаю не использовать этого монстра ещё для чего-то, кроме как на ipod заливать подкасты.) И лайона ставить рано пока. Так что идём в сам iTunes и правим файл /Applications/iTunes.app/Contents/Info.plist, заменяя&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class=&quot;prettyprint lang-xml&quot;&gt; &amp;lt;key&amp;gt;LSMinimumSystemVersionByArchitecture&amp;lt;/key&amp;gt;&lt;br /&gt; &amp;lt;dict&amp;gt;&lt;br /&gt;  &amp;lt;key&amp;gt;i386&amp;lt;/key&amp;gt;&lt;br /&gt;  &amp;lt;string&amp;gt;10.5.0&amp;lt;/string&amp;gt;&lt;br /&gt;  &amp;lt;key&amp;gt;ppc&amp;lt;/key&amp;gt;&lt;br /&gt;  &amp;lt;string&amp;gt;10.5.0&amp;lt;/string&amp;gt;&lt;br /&gt;  &amp;lt;key&amp;gt;x86_64&amp;lt;/key&amp;gt;&lt;br /&gt;  &amp;lt;string&amp;gt;10.7.0&amp;lt;/string&amp;gt;&lt;br /&gt; &amp;lt;/dict&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;на&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class=&quot;prettyprint lang-xml&quot;&gt; &amp;lt;key&amp;gt;LSMinimumSystemVersionByArchitecture&amp;lt;/key&amp;gt;&lt;br /&gt; &amp;lt;dict&amp;gt;&lt;br /&gt;  &amp;lt;key&amp;gt;i386&amp;lt;/key&amp;gt;&lt;br /&gt;  &amp;lt;string&amp;gt;10.5.0&amp;lt;/string&amp;gt;&lt;br /&gt;  &amp;lt;key&amp;gt;ppc&amp;lt;/key&amp;gt;&lt;br /&gt;  &amp;lt;string&amp;gt;10.5.0&amp;lt;/string&amp;gt;&lt;br /&gt;  &amp;lt;key&amp;gt;x86_64&amp;lt;/key&amp;gt;&lt;br /&gt;  &amp;lt;string&amp;gt;10.6.7&amp;lt;/string&amp;gt;&lt;br /&gt; &amp;lt;/dict&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;ну или как-то так, смотря какая у вас там версия ирбиса стоит. Ну и первый запуск после колдунства должен быть непосредственно iTunes.app, а не через скрипт, который я уже &lt;a href=&quot;http://thegeekbird.blogspot.com/2010/10/itunes.html&quot;&gt;предлагал&lt;/a&gt;, то есть&lt;br /&gt;sudo chmod +x /Applications/iTunes.app/Contents/MacOS/iTunes&lt;br /&gt;ему таки временно надо сделать.</description><link>http://thegeekbird.blogspot.com/2011/09/itunes.html</link><author>noreply@blogger.com (PhoeniX)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-k2kAlu_SI-8/Tn2gS22cwaI/AAAAAAAAAog/EP5xZNnrhFQ/s72-c/Screen%2Bshot%2B2011-09-24%2Bat%2B15.14.21.PNG" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-439775273064312982.post-8215399458004847280</guid><pubDate>Fri, 27 May 2011 05:57:00 +0000</pubDate><atom:updated>2011-05-27T12:52:21.486+06:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">hint</category><category domain="http://www.blogger.com/atom/ns#">mac</category><category domain="http://www.blogger.com/atom/ns#">software</category><title>Flexiglass</title><description>Первое, о чём думаешь, когда после мака садишься работать за какой-то другой компьютер, это: &quot;Где мои хоткеи?&quot; - после чего идёшь за мышкой.&lt;br /&gt;&lt;br /&gt;Вчера окончательно и бесповоротно стал патриотом и зарегистрировал свою копию программы для управления окнами для мака под названием &lt;a href=&quot;http://nulana.com/flexiglass&quot;&gt;Flexiglass&lt;/a&gt;, после того как туда добавилась критичная для меня возможность по хоткею перекинуть окно на второй монитор. Но не хоткеями едиными, есть там и улучшения для жестов, вроде так не хватавшей после Linux&#39;овых DE возможности потаскать окно за любую его часть. И это с мышкой, трекпадом и графическими планшетами. И много чего ещё, вы лучше видео посмотрите. В общем, хороша, чертовка, умеет всё то, ради чего у меня стояли программы от конкурентов, и даже без учёта действующей сейчас скидки стоит дешевле. Среди первых в Top Paid категории Productivity и в общем Top Paid &lt;a href=&quot;http://itunes.com/mac/flexiglass&quot;&gt;в Mac App Store&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Это то, чего Apple не доложила в оконную среду. Удобство.&lt;br /&gt;&lt;br /&gt;PS.: любопытно, что финальным вариантом названия в ходе обсуждения стало моё предложение. Так что и мои 5 копеек там есть.</description><link>http://thegeekbird.blogspot.com/2011/05/flexiglass.html</link><author>noreply@blogger.com (PhoeniX)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-439775273064312982.post-3931598891010645079</guid><pubDate>Fri, 08 Apr 2011 07:20:00 +0000</pubDate><atom:updated>2011-04-08T13:28:36.204+06:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">android</category><category domain="http://www.blogger.com/atom/ns#">rant</category><title>Android: logout from google account</title><description>По работе приходится иметь дело со множеством девайсов на андроиде, меняться ими с коллегами, нужна возможность отвязать девайс от гугль аккаунта без factory reset (мало удовольствия вбивать пароль от офисного wi-fi, например, как и отдавать свой gmail кому-то).&lt;br /&gt;Официально (через API) основной аккаунт удалить нельзя. На рутованом аппарате это достигается удалением файла /data/system/accounts.db и перезагрузкой.</description><link>http://thegeekbird.blogspot.com/2011/04/android-logout-from-google-account.html</link><author>noreply@blogger.com (PhoeniX)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-439775273064312982.post-8950063203742361089</guid><pubDate>Fri, 01 Apr 2011 04:02:00 +0000</pubDate><atom:updated>2011-04-01T10:06:14.134+06:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">rant</category><title>SMO Hate</title><description>Вот пишет человек блог, и мнит себя великим сеошником-смошником, упоминает какую-то неведомую тебе технологию, а ссылка ведёт на тег в его блоге, по которому находится только тот пост, в котором ты на эту ссылку и кликнул. Смысл? Чмошники.</description><link>http://thegeekbird.blogspot.com/2011/04/smo-hate.html</link><author>noreply@blogger.com (PhoeniX)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-439775273064312982.post-1579637680565807880</guid><pubDate>Tue, 08 Mar 2011 06:09:00 +0000</pubDate><atom:updated>2011-03-08T11:14:49.171+05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">rails</category><title>Rails 3, virtual attr validations</title><description>Давненько собирался написать про валидацию виртуальных атрибутов в моделях Rails, а тут по случаю опробовал Rails 3, наступил на грабли в данном вопросе, так что повод появился.&lt;br /&gt;Зачем могут понадобиться виртуальные атрибуты модели? Затем, чтобы опять же отделить внутренний способ хранения данных от их отображения, например в базе дата хранится как соответствующий тип Date, а на клиенте должна быть представлена в американском формате mm/dd/yy. Вводить её будут так же. Нужно проверять и только потом конвертировать в свой внутренний формат.&lt;br /&gt;Немного о граблях. Были они вызваны тем, что в коде сеттера для такого виртуального атрибута я делал проверку valid? у модели. Модель пропускалась через валидации, некоторые поля модели к тому времени установлены не были (nil), соответственно валидаторы (в частности, один мой собственный) записывали в массив ошибок сообщение, что поле с нулевым значением неверно. Когда приходило время настоящей валидации, эта ошибка сохранялась, и, несмотря на то, что модель уже валидна, она считалась неверной.&lt;br /&gt;А теперь как надо.&lt;br /&gt;&lt;pre&gt;&lt;code class=&quot;prettyprint lang-ruby&quot;&gt;class SomeModel &amp;lt; ActiveRecord::Base&lt;br /&gt;  validates :v_field, :presence =&amp;gt; true, :custom_format =&amp;gt; true&lt;br /&gt;  before_save :set_attr&lt;br /&gt;&lt;br /&gt;  def set_attr&lt;br /&gt;    self.field = @v_field.convert_to_internal&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  def v_field&lt;br /&gt;    @v_field || field.convert_to_formatted&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  def v_field=(val)&lt;br /&gt;    @v_field = val&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;class CustomFormatValidator &amp;lt; ActiveModel::EachValidator&lt;br /&gt;  def validate_each(object, attribute, value)&lt;br /&gt;    real_attr = attribute.to_s.gsub /v_/, &#39;&#39;&lt;br /&gt;    begin&lt;br /&gt;      if( value.length &amp;gt; 0 )&lt;br /&gt;        return&lt;br /&gt;      else&lt;br /&gt;        object.errors[real_attr.to_sym] &amp;lt;&amp;lt; (options[:message] || &amp;quot;is not valid&amp;quot;)&lt;br /&gt;      end&lt;br /&gt;    rescue Exception =&amp;gt; e&lt;br /&gt;      Rails.logger.add(0, e.to_s )&lt;br /&gt;      object.errors[real_attr.to_sym] &amp;lt;&amp;lt; (options[:message] || &amp;quot;is not valid&amp;quot;)&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Теперь всё идёт как надо - форматированное значение лежит в отдельном поле, валидация происходит 1 раз после того, как модель полностью установлена, после валидации - конвертация во внутренний формат.</description><link>http://thegeekbird.blogspot.com/2011/03/rails-3-virtual-attr-validations.html</link><author>noreply@blogger.com (PhoeniX)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-439775273064312982.post-5067559283035256317</guid><pubDate>Fri, 17 Dec 2010 22:11:00 +0000</pubDate><atom:updated>2010-12-18T03:38:07.774+05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">git</category><category domain="http://www.blogger.com/atom/ns#">mac</category><category domain="http://www.blogger.com/atom/ns#">rant</category><title>Git svn &amp; Mac OS X</title><description>The world&#39;s most advanced operating system под названием Snow Leopard она же Mac OS 10.6, выпущенная в 2009 году, сегодня преподнесла мне сюрприз. Сюрприз был в виде стоического отказа git svn делать rebase, под предлогом того, что &quot;The following untracked working tree files would be overwritten by checkout...&quot; и далее путь к некоему файлу в репозитории, над которым работал коллега. Некоторое гугление и эксперименты показали, что коллега файл просто переименовал, обозвав в другом регистре, самая продвинутая операционная система макось в 21 веке имеет нечувствительную к регистру файловую систему по умолчанию, выполняя checkout на которой git видит странное - он этот файл и так, и этак, а он никак... Пришлось его немного сломать:&lt;br /&gt;sed -i &#39;&#39; &#39;s/checkout/checkout -f/g&#39; /usr/local/Cellar/git/1.7.3.1/libexec/git-core/git-rebase&lt;br /&gt;Аналогичный приём может применяться и к другим ситуациям с такими же симптомами. Просто нужно знать, где ударить и, главное, где забрать свои 100 рублей.</description><link>http://thegeekbird.blogspot.com/2010/12/git-svn-mac-os-x.html</link><author>noreply@blogger.com (PhoeniX)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-439775273064312982.post-4958796537831016184</guid><pubDate>Sun, 05 Dec 2010 08:30:00 +0000</pubDate><atom:updated>2010-12-05T13:47:26.619+05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">android</category><title>Android tricks</title><description>Не так давно возникла потребность узнать, запущено ли приложение в прямом смысле этого слова, а не в том, как его понимает андроид. То есть был ли это запуск из лончера, иконки на рабочем столе, нотификации после установки или же просто приложение было показано при переходе к нему по стеку истории. Определяет это вот такой код, помещённый в onCreate() главной Activity:&lt;pre&gt;&lt;code class=&quot;prettyprint lang-java&quot;&gt;protected boolean isLaunch()&lt;br /&gt;{&lt;br /&gt; Intent i = getIntent();&lt;br /&gt; return i != null &amp;amp;&amp;amp;&lt;br /&gt;   ((i.getCategories()!= null &amp;amp;&amp;amp; i.getCategories().contains(Intent.CATEGORY_LAUNCHER)) || // from launcher&lt;br /&gt;    Intent.ACTION_MAIN.equalsIgnoreCase(i.getAction())) &amp;amp;&amp;amp; // or first launch from notification panel&lt;br /&gt;   getLastNonConfigurationInstance() == null; // orientation change&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Другой небольшой трюк - как дать возможность послать что-то в Gmail, SMS, Twitter и пр. Пользователи Андроида знают это меню &quot;Отправить&quot;. А отправить вот как:&lt;pre&gt;&lt;code class=&quot;prettyprint lang-java&quot;&gt;Intent sendIntent = new Intent(Intent.ACTION_SEND);&lt;br /&gt;sendIntent.setType(&amp;quot;text/plain&amp;quot;);&lt;br /&gt;sendIntent.putExtra(Intent.EXTRA_SUBJECT, &amp;quot;title&amp;quot;);&lt;br /&gt;sendIntent.putExtra(Intent.EXTRA_TEXT, &amp;quot;description&amp;quot;);&lt;br /&gt;Intent intent = Intent.createChooser(sendIntent,&lt;br /&gt;  getString(R.string.AndroidProgramItemActionShare));&lt;br /&gt;startActivity(intent);&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Все программы, которые могут принять текст, будут показаны в этом списке.</description><link>http://thegeekbird.blogspot.com/2010/12/android-tricks.html</link><author>noreply@blogger.com (PhoeniX)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-439775273064312982.post-7964414047908792806</guid><pubDate>Tue, 23 Nov 2010 04:37:00 +0000</pubDate><atom:updated>2010-11-23T10:08:07.868+05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">android</category><category domain="http://www.blogger.com/atom/ns#">rant</category><title>Про Андроид 2</title><description>Стравив в прошлый раз яд, я, видимо, должен сейчас сочиться миррой и благовониями, посмотрим.&lt;br /&gt;&lt;br /&gt;Для начала я снова отошлю вас почитать &lt;a href=&quot;http://www.codeproject.com/Articles/73089/Comparison-of-Android-vs-iPhone-vs-Nokia-vs-BlackB.aspx&quot;&gt;три&lt;/a&gt; &lt;a href=&quot;http://greensopinion.blogspot.com/2009/07/android-versus-iphone-development.html&quot;&gt;неплохие&lt;/a&gt; &lt;a href=&quot;http://mobile.dzone.com/news/comparing-iphone-and-android&quot;&gt;статьи&lt;/a&gt; на тему.&lt;br /&gt;&lt;br /&gt;Первое, за что андроид может заслужить фавора - это открытость. Под этим я понимаю много разных вещей. Например, крайне широкие возможности для интеграции как с системой, так и с другими приложениями. Вот я сделал фото камерой и могу его теперь отправить в Gmail, Picasa, Twitter и кучу других приложений. Если я объявлю в своём приложении, что оно умеет принимать изображения - оно тоже окажется в этом списке. И обратно - чтобы реализовать кнопку &quot;Share&quot; мне не нужно волочить с собой библиотеку для Facebook, Twitter и прочего Вконтакта. Достаточно сделать один вызов к OS - она выберет те приложения, которые могут обработать то или иное содержимое. И, заметьте, только те приложения, которые установлены, которые пользователь сам себе поставил и, вероятно, где надо уже авторизован. При этом границы приложения пересекает только та информация, которой это приложение готово поделиться, никакого нарушения изоляции, sandboxing там не менее строгий. На том же механизме, например, реализована система плагинов к популярному приложению Locale - просто и красиво. Или интеграция в поиск по телефону. Хотите, чтобы ваши задачи из вашей новой ToDo&#39;шечки отображались в результатах поиска - вы можете реализовать поддержку этого. Или возможность всё заменить - приложение для контактов, телефона, почтовый клиент, плеер, камеру, рабочий стол... тысячи их (замен стандартным вариантам).&lt;br /&gt;&lt;br /&gt;Другое проявление открытости - доступность исходников. Это отдельная тема священных войн, открыт ли андроид в смысле отрытого ПО, но факт остаётся собой - исходники можно получить и пощупать, можно даже почитать. Увы, делать это иногда даже необходимо (про документацию см. пред. пост). Однако не стоит забывать о том, что в случае конкретных прошивок исходники могут не соответствовать реальности (см. пред. пост).&lt;br /&gt;&lt;br /&gt;Неплохим моментом можно считать и Java в качестве основного языка разработки под платформу. Конечно, это выливается в некоторые неудобства типа внезапного как понос GC (и я бы не сказал, что следить за памятью приходится меньше, чем с Objective-C), однако есть и преимущества. Для всего существует библиотека на Java - почти аксиома. Да и сама Java тут вполне нормальная, и SDK работать должен на всех основных платформах (RIM, тут вам нужно начать икать втрое интенсивнее). И да, декларировать пять раз свойство не приходится - объявил поле и автоматически сгенерировал методы доступа (это в тему того, что язык хоть и не обладает такими красивыми концепциями как передача сообщений или необязательные методы в интерфейсе/протоколе, но не выглядит таким динозавром. Подробнее - по одной из ссылок). Опять же мощная поддержка со стороны IDE: десятки рефакторингов, сотни инспекций (в реальном времени, а не после компиляции), тысячи плагинов, навигация, документация и автодополнение - XCode даже не разгибается (что они сделали с документацией XCode?! раньше хоть как-то можно было пользоваться). Удобнее отладчик, можно подключиться к уже запущенному приложению, это отчасти компенсирует медлительность приложения с подключённым отладчиком - быстро дошли до исследуемого места и подключили. Логи лучше - уровни (от Debug до WTF), фильтры, лог сохраняется даже тогда, когда устройство не подключено к IDE и можно посмотреть его постфактум (впрочем, коллеги начали прикручивать &lt;a href=&quot;http://thegeekbird.blogspot.com/2010/09/force-close-dialog.html&quot;&gt;отправку исключений в Redmine&lt;/a&gt; из iOS приложений по моим стопам , частично устранив этот недостаток iOS).&lt;br /&gt;&lt;br /&gt;Интерфейс. Действительно очень мощная поддержка различных разрешений и диагоналей, что с одной стороны необходимость при том многообразии устройств, на которых андроид должен запускаться, с другой стороны никто так здорово это не сделал. Таких гибких менеджеров размещения у Apple я не видел, остальные меры для поддержания различных экранов (iPhone, iPad, iPhone 4) либо провальные либо неудобные, а RIM уже должна помереть от икоты. Достаточно гибкие встроенные виджеты, которые к тому же при некоторой подготовке так легко видоизменять и комбинировать в более сложные компоненты (NB. об этом тоже стоит написать). В общем, пока вы играете на этом поле - возможности очень широки. &lt;br /&gt;&lt;br /&gt;Многозадачность. Она, конечно же, не такая, как мы привыкли на ПК, OS будет ограничивать (16 Мб! 21 век!) и следить за вами и отрубит голову при первом же подозрении. Но если играть по правилам - вы можете работать на переднем плане, в фоне, получать системные события и реагировать на них. Не возникнет той абсурдной ситуации, когда я хочу открыть почту, когда синхронизируется RSS читалка, и вынужден ждать. А ещё это многозадачность пользователя - он может переключаться с задачи на задачу, вызывая именно те окна различных приложений, которые нужны ему для продолжения его рабочего процесса (work&lt;span style=&quot;font-weight:bold;&quot;&gt;flow&lt;/span&gt;). Об этом и кнопке &quot;Share&quot; в частности рассказано в этом видео с Google IO 09 с 10 минуты. &lt;object width=&quot;480&quot; height=&quot;385&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://www.youtube.com/v/wdGHySpipyA?fs=1&amp;amp;hl=en_US&quot;&gt;&lt;/param&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot;&gt;&lt;/param&gt;&lt;param name=&quot;allowscriptaccess&quot; value=&quot;always&quot;&gt;&lt;/param&gt;&lt;embed src=&quot;http://www.youtube.com/v/wdGHySpipyA?fs=1&amp;amp;hl=en_US&quot; type=&quot;application/x-shockwave-flash&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;true&quot; width=&quot;480&quot; height=&quot;385&quot;&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;Потерпите этого чувака 4 минуты, он это покажет лучше, чем я. Ну и виджеты, которые могут дать вам моментальный обзор необходимой информации без жонглирования приложениями. Всё это грамотно организовано и работает одновременно, не мешая друг другу.&lt;br /&gt;&lt;br /&gt;Распространение софта свободно и дико, как нравы в племени мумбо-юмбо. Можно в Android маркет выложить (приложение на устройстве будет доступно через минуту! даже через Jabber я услышал, как упала челюсть шефа, до этого несколько лет воевавшего с AppStore), можно в сторонние магазины, можно на своём сайте, да хоть в Dropbox - знай только ссылку давай. Маркет, конечно, предпочтительней по некоторым причинам - он самый крупный, он предустановлен на большинстве аппаратов, он позволяет чётко разделять приложения по используемому железу и версии прошивки, так что вы не увидите игру для акселерометра на планшете без него. Однако даже если пользователь поставил софт почтовыми голубями, то вы можете мягко направить его в маркет за обновлениями, и приложение &quot;Маркет&quot; начнёт само следить за обновлениями. И каждый раз перед обновлением не нужно будет вводить пароль (умри, Appstore!)&lt;br /&gt;&lt;br /&gt;Есть Flash (с 2.2). Кому-то надо. Нет, не тормозит (там, где у меня есть 2.2, но это весьма шустрый аппарат, так что не показательно).&lt;br /&gt;&lt;br /&gt;Закончу, пожалуй, действительно радостной новостью - приложение, работа над которым дала почву для этих постов, стало Today hot #1 на &lt;a href=&quot;http://www.appbrain.com/apps/hot/&quot;&gt;appbrain.com&lt;/a&gt;, в чём огромная заслуга команды и мой небольшой вклад.&lt;br /&gt;&lt;br /&gt;Хорошего начала рабочей недели!</description><link>http://thegeekbird.blogspot.com/2010/11/2.html</link><author>noreply@blogger.com (PhoeniX)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-439775273064312982.post-492623894150878768</guid><pubDate>Sat, 20 Nov 2010 09:31:00 +0000</pubDate><atom:updated>2010-11-21T01:23:04.888+05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">android</category><category domain="http://www.blogger.com/atom/ns#">rant</category><title>Про Андроид</title><description>Я давно копил яд и тщательно сцеживал в баночку. Но сегодня есть повод наконец-то высказаться. Поводом стало &lt;a href=&quot;http://fulldroid.com/interview-with-tweetdeck-developer-max-howell&quot;&gt;интерью с Максом Хауэллом&lt;/a&gt; (Max Howell) &lt;a href=&quot;http://www.androidpolice.com/2010/11/14/developer-interview-series-tweetdeck-for-androids-max-howell/&quot;&gt;оригинал&lt;/a&gt;, одним из разработчиков TweetDeck (маководам-гикам он также может быть известен как автор &lt;a href=&quot;https://github.com/mxcl/homebrew&quot;&gt;Homebrew&lt;/a&gt;) и некоторых других полезных проектов.&lt;br /&gt;&lt;br /&gt;Практически со всем, что пишет Макс, я могу согласиться. &quot;Debug cycles on Android take half a minute at least.&quot; Да, чёрт побери, с запуском приложения всё плохо, очень плохо. Варианта, как водится, два: эмулятор (а не симулятор, как для iPhone) и реальное устройство. Первый вариант отпадает сразу, потому что эмулятор жестоко медленный (отдельный пункт для злословия - зачем делать эмулятор, который по идее должен досконально воспроизводить работу эмулируемой сущности, если он этого не делает? А тормозит так, будто целый кластер эмулирует. Вот симулятор iPhone - тоже часть функционала можно протестировать только на устройстве, но то, что можно на симуляторе - можно очень быстро). Какое там быстродействие, достаточное, чтобы UI плавно следовал за пальцем! Шевелится - и ладно. В мусорку, годится только на первый день, пока не завезут девайс. Да и тогда между сохранением исходников и запуском программы стоят неповоротливые компилятор, отправка бинарника на устройство, пакетный менеджер, который установит программу. Потом она запустится, и ведь наверняка у ней есть некий этап инициализации (да хотя бы логин в твиттер или что там у них). Полминуты? Да, что-то вроде того. Купите кресло и мешок кофе.&lt;br /&gt;&lt;br /&gt;Второй безальтернативный вариант - реальное устройство. Девайс лучше брать мощный. А лучше пять, разной степени говнистости, но один мощный. У меня их 4, 2 из них (худший и лучший) - постоянно со мной, 2 лежат в офисе на случай, если команде срочно потребуется альтернативный девайс для тестов. У моего коллеги 2 (ну и он всегда может взять с моего стола те 2 которые я не ношу с собой). Вы подумали только что, что мы все совсем тут еб^W с ума сошли? Нет, отнюдь. Например для тестирования iOS приложений у меня ровно 1 девайс. Просто это единственный способ бороться с другой проблемой платформы Android - &quot;фрагментацией&quot;. Про это я могу под пиво задвинуть немалую тираду, но постараюсь тут и кратко.&lt;br /&gt;&lt;br /&gt;О, все так полюбили это слово с подачи Джобса, но никто нихрена не понимает, что это значит по отношению к Андроиду. И Макс тоже не догоняет, считая эту проблему надуманной. Вот он рассказывает про адаптацию интерфейса, тут же признаваясь, что с офигенной системой менеджеров размещения Андроида это вообще не проблема для таких приложений как твиттер-клиент (но в то же время я с ужасом жду момента, когда придётся переносить с iOS приложение не использующее стандартный UI, для которого эта система будет бессмысленна). Да не в этом дело, при чём тут разные экраны и разрешения? Ребята из Google тут всё сделали за вас (против ребят из Apple, у которых например функция загрузки изображения соответствующего разрешения вообще не работает, хотя описана в документации). А дело в том, что Андроид есть только один - в git репозитариях Google и на Nexus One. Всё остальное - это прошивка от HTC, прошивка от LG, прошивка от Motorola, взгромождённые на железо от HTC, LG и Motorola соотв. И в эту прошивку, что характерно, этот производитель залез руками (да, чтобы был хоть какой-то added value, который выделял бы его телефончик на фоне сотен других моделей) и, вероятно, непоправимо там наследил. Один из телефонов, к примеру, появился у нас вследствие того, что производитель переписал стандартный класс из Android SDK так, что при его использовании приложение гарантированно падало с исключением. Пришлось брать этот класс из исходников андроида и адаптировать, заменяя своим вариантом как сломанный вариант у того производителя так и стандартный вариант у всех других и лишаясь потенциальных будущих его обновлений. Другой телефон гарантированно уходил в ребут в одном месте приложения. Без какой-либо причины, которую хоть как-то можно было бы установить. После пришедшего обновления перестал. Зато вдруг стал разряжаться за полдня даже в режиме ожидания. Вот что такое фрагментация Андроида - никогда невозможно гарантировать, что у пользователя будет хоть что-то работать. Будет работать у меня на 4 аппаратах, ещё на 2 у коллеги, на 2 у шефа - не будет у 100500 пользователей на каком-нибудь китайском куске говна. Кто-то из них непременно придёт в маркет и насрёт в карму. Видели наверное - у приложения &gt;250 000 загрузок, 5 звёзд и куча истеричных комментариев. Энди Рубин даёт нам определение открытости как возможность собрать андроид и поставить на свой телефон целиком из исходников, я смеюсь над ним - пусть проделает этот трюк с произвольным телефоном из магазина. Или это должен сделать разработчик, который лишь хочет продать свою программу?&lt;br /&gt;&lt;br /&gt;Железо разное, очень разное. Казалось бы, везде какой-то ARM, но один аппарат тормозит как тот эмулятор, а другой, раза в 2 дешевле с резистивным говно-экраном на 16 цветов - летает. Парадокс! Или вы думаете, что Rovio от хорошей жизни объявили, что их &lt;a href=&quot;http://www.rovio.com/index.php?mact=Blogs,cntnt01,showentry,0&amp;cntnt01entryid=47&amp;cntnt01returnid=58&quot;&gt;злые птицы не поддерживаются на куче устройств&lt;/a&gt;? Посмотрите на список - это устройства дешевле $500 (в России, очень грубая прикидка на глаз). Такие вот кирпичи. В кирпичи превращаются устройства, как только вы их купите. Они морально устарели, когда добрались до России, и производитель не будет выпускать для них новую прошивку. Купить что-то стоящее на Андроид - сложно, обычно это означает накинуть $50-$150 сверх того, что задумывалось, тщательно выбрать производителя по отзывам (и вероятности обновления прошивок), и магазин, в который можно без проблем вернуть устройство (или поменять). Но это так, к слову, потребительская сторона вопроса меня не особо касается, просто хочется подчеркнуть, что придётся тщательно выбирать. В случае с Apple придётся выбирать между 16 &amp; 32 Gb к примеру, и только. И я не знаю, что лучше или хуже, но париться по поводу 16 и 32 обычно придётся гораздо меньше, чем с тысячей аспектов андроид телефона.&lt;br /&gt;&lt;br /&gt;Что-то я отклонился. Далее Макс говорит о жизненном цикле приложения. И вот тут происходит очередной разрыв шаблона, потому что приложение на Android работает совсем по-другому, нежели привычное десктоп или даже iOS приложение. Как вам, например, тот факт, что приложение нельзя закрыть? Это не нужно в той парадигме, которую предлагает Google. Приложение, будучи запущенным, вероятно понадобится пользователю в дальнейшем. Ну так и не надо его закрывать, пусть оно будет доступно как можно быстрее, когда вы захотите к нему вернуться! А андроид сам позаботится об использовании памяти, процессора и батареи. Но это же просто невозможно! и пользователь требует кнопку &quot;Закрыть&quot;. А единственный способ приложению закрыться - это послать себе kill -9, да и это не гарантирует, что удивлённый таким ходом событий андроид не перезапустит его тотчас же. Другие способы уже требуют пользователя - удалить приложение или перезагрузить телефон. Вот тогда оно точно закроется. Знаете, я видел одно приложение, которое предлагало себя закрыть. Как вы думаете, что оно делало? Скрывало все свои &#39;окна&#39; и засыпало, как любое другое добропорядочное андроид приложение.&lt;br /&gt;&lt;br /&gt;Тут разрыв шаблона случается и у разработчиков (у некоторой части), потому что чтобы стать &quot;good citizen&quot; нужно хотя бы пару раз хорошенько прочитать документацию по теме (по этой теме она весьма подробна) и приложить голову. И если хороший разработчик &quot;в итоге будет писать гораздо более надёжные приложения, чем раньше (особенно после отладки)&quot;, то остальные &quot;говнякают код по-быстрому&quot;, чтобы завалить маркет бесплатными поделиями. И это тоже большая, просто огромная проблема - отсутствие не только контроля, но и каких бы то ни было гайдлайнов - как для разработчиков софта, так и для производителей аппаратов. Поэтому в маркете такое количество шлака, о чём так любят упоминать противники платформы, забывая при этом, сколько шлака в Apple AppStore, а на прилавках такое количество неудобных аппаратов, то не имеющих D-pad в каком-либо виде, то с самой часто используемой на андроиде кнопкой &quot;назад&quot;, засунутой в самое труднодоступное место, то страдающих чем-то ещё из широкого арсенала недоработок юзабелистов. Отсюда возникает самый популярный класс программ на андроиде - тасккиллеры, и холиворы - нужны они или нет. Пока я увидел в такой свободе только один положительный момент - отсутствие задержки между публикацией и доступностью приложения, за что все яростно клянут AppStore (упущенные возможности, конкуренты догоняют и пр.).&lt;br /&gt;&lt;br /&gt;Далее идёт речь о самом SDK. Документация местами хороша, местами просто отсутствует, средства странны, не образуют что-то цельное и удобное (даже если заменить Eclipse на Idea, хоть последняя мне лично гораздо приятнее) и также неполны (ну какой смысл в отслеживании выделений памяти в куче, если б&lt;span style=&quot;font-weight:bold;&quot;&gt;о&lt;/span&gt;льшая её часть выделяется вне её и не отображается стандартными средствами? Собственные велосипеды дают лишь примерную картину) что в купе с драконовскими ограничениями типа слабых устройств на рынке, непредсказуемостью GC и домокловым мечом OutOfMemory (16 Mb! 21 век на дворе! и из этого треть откусывает runtime) создаёт картину безысходности. Нет, бывают вещи гораздо, гораздо хуже (RIM, вам икается?), но тут действительно непаханое поле для улучшений.&lt;br /&gt;&lt;br /&gt;Такую же безрадостную картину может составить себе читатель статьи &lt;a href=&quot;http://blog.oleganza.com/post/368520883/android-vs-iphone-the-good-the-bad-and-the-ugly&quot;&gt;Android vs. iPhone: the good, the bad and the ugly&lt;/a&gt; нашего соотечественника Олега Андреева, но с ней я не во всём согласен, большей частью она была вызвана плохим аппаратом и непониманием. Согласен с тем, что делать вещи на Java гораздо сложнее, и только упрощением сборки мусора (которая только добавляет проблем на самом-то деле) нельзя это оправдать. Java даёт средства для постройки чего угодно, но даже простые вещи делаются сложно, и без хорошего опыта это ещё сложнее. Поэтому, например, перед началом изучения андроида я настоятельно порекомендую Java Concurrency in Practice. Это достаточно подробная, толстая и дорогая книга про многопоточность в Java. Это почти обязательно для разработки приложения сложнее фоточки кота и мяукания (это шпилька в адрес App Inventor. Где он кстати?).&lt;br /&gt;&lt;br /&gt;Вопреки всему вышеизлитому яду я, как и Макс, считаю, что у Андроида всё впереди. Но для этого придётся пойти на решительнейшие шаги. Отказаться от любой поддержки старых прошивок (например ниже 2.1), остальные объявить устаревающими (deprecated) и только после этого выпускать следующую версию, подняв аппаратные требования, чтобы убрать наконец те ограничения, в которых вынуждена запускаться андроид программа. Это оставит на обочине большую часть ныне существующих аппаратов, но иначе детские болезни погубят платформу. Необходима работа над документацией (к примеру, в документации Microsoft встречаются недостаточно полно освещённые моменты, в документации Apple их меньше, в документации Google же зияют дыры); над гайдлайнами, в первую очередь HIG; средствами разработки, мониторинга и отладки; возможно даже над какой-либо системой принятия приложения в магазин.&lt;br /&gt;&lt;br /&gt;Хороших выходных. Ответные посты коллег, подкреплённые опытом, приветствуются.</description><link>http://thegeekbird.blogspot.com/2010/11/blog-post_20.html</link><author>noreply@blogger.com (PhoeniX)</author><thr:total>9</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-439775273064312982.post-4795392111736491885</guid><pubDate>Thu, 18 Nov 2010 14:58:00 +0000</pubDate><atom:updated>2010-11-19T19:25:10.995+05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">android</category><title>немного стиля Android виджетам!</title><description>Вчера коллега спросил, как бы поменять &quot;эти ужасные зелёные ползунки у SeekBar&#39;а в оболочке HTC Sense&quot;? Сегодня я над этим немного поразмыслил, благо недавно как раз заглядывал в эту тему.&lt;br /&gt;Начать, пожалуй, стоит с ознакомления со стилями Android&#39;а. Увы, в редкой книге поднимается эта тема, так что можно почитать &lt;a href=&quot;http://developer.android.com/guide/topics/ui/themes.html&quot;&gt;про стили в документации&lt;/a&gt; и обратить внимание на &lt;a href=&quot;http://developer.android.com/guide/topics/ui/themes.html#PlatformStyles&quot;&gt;встроенные стили&lt;/a&gt;. Во встроенных есть, например, такой фрагмент:&lt;br /&gt;&lt;pre&gt;&lt;code class=&quot;prettyprint lang-xml&quot;&gt;&amp;lt;style name=&amp;quot;Widget.SeekBar&amp;quot;&amp;gt;&lt;br /&gt;    &amp;lt;item name=&amp;quot;android:indeterminateOnly&amp;quot;&amp;gt;false&amp;lt;/item&amp;gt;&lt;br /&gt;    &amp;lt;item name=&amp;quot;android:progressDrawable&amp;quot;&amp;gt;@android:drawable/progress_horizontal&amp;lt;/item&amp;gt;&lt;br /&gt;    &amp;lt;item name=&amp;quot;android:indeterminateDrawable&amp;quot;&amp;gt;@android:drawable/progress_horizontal&amp;lt;/item&amp;gt;&lt;br /&gt;    &amp;lt;item name=&amp;quot;android:minHeight&amp;quot;&amp;gt;20dip&amp;lt;/item&amp;gt;&lt;br /&gt;    &amp;lt;item name=&amp;quot;android:maxHeight&amp;quot;&amp;gt;20dip&amp;lt;/item&amp;gt;&lt;br /&gt;    &amp;lt;item name=&amp;quot;android:thumb&amp;quot;&amp;gt;@android:drawable/seek_thumb&amp;lt;/item&amp;gt;&lt;br /&gt;    &amp;lt;item name=&amp;quot;android:thumbOffset&amp;quot;&amp;gt;8px&amp;lt;/item&amp;gt;&lt;br /&gt;    &amp;lt;item name=&amp;quot;android:focusable&amp;quot;&amp;gt;true&amp;lt;/item&amp;gt;&lt;br /&gt;&amp;lt;/style&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;В нём и задаётся стиль для SeekBar&#39;а. Значит, точно так же мы можем его переопределить. Как показывает вскрытие, @android:drawable/progress_horizontal есть фигура, описанная в xml (исходник, за ленью, выковыривать не стал), сделаем свою:&lt;br /&gt;&lt;pre&gt;&lt;code class=&quot;prettyprint lang-xml&quot;&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;utf-8&amp;quot;?&amp;gt;&lt;br /&gt;&amp;lt;shape xmlns:android=&amp;quot;http://schemas.android.com/apk/res/android&amp;quot;&amp;gt;&lt;br /&gt;    &amp;lt;stroke android:width=&amp;quot;1px&amp;quot; android:color=&amp;quot;#FFF&amp;quot; /&amp;gt;&lt;br /&gt;    &amp;lt;corners android:radius=&amp;quot;9dip&amp;quot;/&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;gradient&lt;br /&gt;        android:angle=&amp;quot;270&amp;quot;&lt;br /&gt;        android:endColor=&amp;quot;#CCE2001A&amp;quot;&lt;br /&gt;        android:startColor=&amp;quot;#CCA10013&amp;quot;&lt;br /&gt;        android:type=&amp;quot;linear&amp;quot;/&amp;gt;&lt;br /&gt;&amp;lt;/shape&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Красный градиент в белой рамке.&lt;br /&gt;Создадим стиль для виджета:&lt;br /&gt;&lt;pre&gt;&lt;code class=&quot;prettyprint lang-xml&quot;&gt;    &amp;lt;style name=&amp;quot;MySeekBar&amp;quot;&amp;gt;&lt;br /&gt;        &amp;lt;item name=&amp;quot;android:indeterminateOnly&amp;quot;&amp;gt;false&amp;lt;/item&amp;gt;&lt;br /&gt;        &amp;lt;item name=&amp;quot;android:progressDrawable&amp;quot;&amp;gt;@drawable/seekbar&amp;lt;/item&amp;gt;&lt;br /&gt;        &amp;lt;item name=&amp;quot;android:indeterminateDrawable&amp;quot;&amp;gt;@drawable/seekbar&amp;lt;/item&amp;gt;&lt;br /&gt;        &amp;lt;item name=&amp;quot;android:minHeight&amp;quot;&amp;gt;20dip&amp;lt;/item&amp;gt;&lt;br /&gt;        &amp;lt;item name=&amp;quot;android:maxHeight&amp;quot;&amp;gt;20dip&amp;lt;/item&amp;gt;&lt;br /&gt;        &amp;lt;item name=&amp;quot;android:thumbOffset&amp;quot;&amp;gt;8px&amp;lt;/item&amp;gt;&lt;br /&gt;        &amp;lt;item name=&amp;quot;android:focusable&amp;quot;&amp;gt;true&amp;lt;/item&amp;gt;&lt;br /&gt;    &amp;lt;/style&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;и применим его на живом экземпляре:&lt;br /&gt;&lt;pre&gt;&lt;code class=&quot;prettyprint lang-xml&quot;&gt;&amp;lt;SeekBar&lt;br /&gt;        style=&amp;quot;@style/MySeekBar&amp;quot;&lt;br /&gt;        android:id=&amp;quot;@+id/screenControlVolume&amp;quot;&lt;br /&gt;        android:layout_width=&amp;quot;150dip&amp;quot;&lt;br /&gt;        android:layout_height=&amp;quot;wrap_content&amp;quot;&lt;br /&gt;        android:paddingLeft=&amp;quot;10dip&amp;quot;&lt;br /&gt;        android:paddingRight=&amp;quot;10dip&amp;quot;&lt;br /&gt;        android:layout_marginBottom=&amp;quot;10dip&amp;quot;/&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Итог мучений (внизу - стандартный, не HTC):&lt;br /&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;http://1.bp.blogspot.com/_FFVj2Tu_TDM/TOVK5f8IHYI/AAAAAAAAAY8/z7N3t19YrZE/s1600/Screen%2Bshot%2B2010-11-18%2Bat%2B20.41.09.PNG&quot;&gt;&lt;img style=&quot;cursor:pointer; cursor:hand;width: 193px; height: 200px;&quot; src=&quot;http://1.bp.blogspot.com/_FFVj2Tu_TDM/TOVK5f8IHYI/AAAAAAAAAY8/z7N3t19YrZE/s200/Screen%2Bshot%2B2010-11-18%2Bat%2B20.41.09.PNG&quot; border=&quot;0&quot; alt=&quot;&quot;id=&quot;BLOGGER_PHOTO_ID_5540917268235951490&quot; /&gt;&lt;/a&gt;&lt;br /&gt;Ну и, надо полагать, очевидно, что можно расширить и углубить мысль и применять этот подход почти ко всему.&lt;br /&gt;UPD:&lt;br /&gt;Как говорил мой завкафедры, показывая пальцем на голову, &quot;Вы никогда не сможете перестать работать&quot;. И уже улёгшись спать, я вспомнил, что полоска-то в моём SeekBar&#39;е одинакового цвета что слева от указателя позиции, что справа. Непорядок, который я сегодня исправляю. Итак, всё-таки расковыряв исходник android-варианта фигуры этой полоски, переписал свою версию:&lt;br /&gt;&lt;pre&gt;&lt;code class=&quot;prettyprint lang-xml&quot;&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;utf-8&amp;quot;?&amp;gt;&lt;br /&gt;&amp;lt;layer-list&lt;br /&gt;  xmlns:android=&amp;quot;http://schemas.android.com/apk/res/android&amp;quot;&amp;gt;&lt;br /&gt;    &amp;lt;item android:id=&amp;quot;@android:id/background&amp;quot;&amp;gt;&lt;br /&gt;        &amp;lt;shape&amp;gt;&lt;br /&gt;            &amp;lt;stroke android:width=&amp;quot;1px&amp;quot; android:color=&amp;quot;@color/widgetBorder&amp;quot; /&amp;gt;&lt;br /&gt;            &amp;lt;corners android:radius=&amp;quot;9dip&amp;quot;/&amp;gt;&lt;br /&gt;&lt;br /&gt;            &amp;lt;gradient&lt;br /&gt;                    android:angle=&amp;quot;270&amp;quot;&lt;br /&gt;                    android:endColor=&amp;quot;@color/widgetBorder&amp;quot;&lt;br /&gt;                    android:startColor=&amp;quot;@color/widgetBorder&amp;quot;&lt;br /&gt;                    android:type=&amp;quot;linear&amp;quot;/&amp;gt;&lt;br /&gt;        &amp;lt;/shape&amp;gt;&lt;br /&gt;    &amp;lt;/item&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;item android:id=&amp;quot;@android:id/progress&amp;quot;&amp;gt;&lt;br /&gt;        &amp;lt;clip&amp;gt;&lt;br /&gt;            &amp;lt;shape&amp;gt;&lt;br /&gt;                &amp;lt;stroke android:width=&amp;quot;1px&amp;quot; android:color=&amp;quot;@color/widgetBorder&amp;quot; /&amp;gt;&lt;br /&gt;                &amp;lt;corners android:radius=&amp;quot;9dip&amp;quot;/&amp;gt;&lt;br /&gt;&lt;br /&gt;                &amp;lt;gradient&lt;br /&gt;                        android:angle=&amp;quot;270&amp;quot;&lt;br /&gt;                        android:endColor=&amp;quot;@color/gradientWidgetEndColor&amp;quot;&lt;br /&gt;                        android:startColor=&amp;quot;@color/gradientWidgetStartColor&amp;quot;&lt;br /&gt;                        android:type=&amp;quot;linear&amp;quot;/&amp;gt;&lt;br /&gt;            &amp;lt;/shape&amp;gt;&lt;br /&gt;        &amp;lt;/clip&amp;gt;&lt;br /&gt;    &amp;lt;/item&amp;gt;&lt;br /&gt;&amp;lt;/layer-list&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;тут уже список слоёв с 2 (в оригинале 3, зачем третья можете подумать на досуге), в которых могут быть разные фигуры, в моём случае - всё те же скруглённые градиентные прямоугольники, верхний слой обрезан - это левая часть. Ну и вот как это выглядит в моём проекте:&lt;br /&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;http://3.bp.blogspot.com/_FFVj2Tu_TDM/TOaIH7Aj-NI/AAAAAAAAAZE/S_1uYfuzlTs/s1600/Screen%2Bshot%2B2010-11-19%2Bat%2B19.17.14.PNG&quot;&gt;&lt;img style=&quot;cursor:pointer; cursor:hand;width: 200px; height: 197px;&quot; src=&quot;http://3.bp.blogspot.com/_FFVj2Tu_TDM/TOaIH7Aj-NI/AAAAAAAAAZE/S_1uYfuzlTs/s200/Screen%2Bshot%2B2010-11-19%2Bat%2B19.17.14.PNG&quot; border=&quot;0&quot; alt=&quot;&quot;id=&quot;BLOGGER_PHOTO_ID_5541266061206485202&quot; /&gt;&lt;/a&gt;</description><link>http://thegeekbird.blogspot.com/2010/11/android.html</link><author>noreply@blogger.com (PhoeniX)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_FFVj2Tu_TDM/TOVK5f8IHYI/AAAAAAAAAY8/z7N3t19YrZE/s72-c/Screen%2Bshot%2B2010-11-18%2Bat%2B20.41.09.PNG" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-439775273064312982.post-256146002735079382</guid><pubDate>Sat, 13 Nov 2010 19:04:00 +0000</pubDate><atom:updated>2010-11-14T00:17:03.318+05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">android</category><category domain="http://www.blogger.com/atom/ns#">browser</category><category domain="http://www.blogger.com/atom/ns#">rant</category><title>Ну и опять про браузеры. И андроид.</title><description>&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSgudGgeqXch2F6iMzH7L6hkJNuSQN-Hd2QLB2uWk3_GJLnM1OHsUjlwXQpc-ztM0uYcLbS2W93QDuXDkldGQG_lf6Co3WJVySFjgY840Snuum-c7jScHHD792CXmbqJWW0EE_hOMr_Ps/s1600/Screen+shot+2010-10-25+at+0.39.43.PNG&quot;&gt;&lt;img style=&quot;float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 71px; height: 200px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSgudGgeqXch2F6iMzH7L6hkJNuSQN-Hd2QLB2uWk3_GJLnM1OHsUjlwXQpc-ztM0uYcLbS2W93QDuXDkldGQG_lf6Co3WJVySFjgY840Snuum-c7jScHHD792CXmbqJWW0EE_hOMr_Ps/s200/Screen+shot+2010-10-25+at+0.39.43.PNG&quot; border=&quot;0&quot; alt=&quot;&quot;id=&quot;BLOGGER_PHOTO_ID_5539112961312791954&quot; /&gt;&lt;/a&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;http://3.bp.blogspot.com/_FFVj2Tu_TDM/TN7h4-oHR9I/AAAAAAAAAYs/M0t02HuWFic/s1600/Screen%2Bshot%2B2010-10-25%2Bat%2B0.39.23.PNG&quot;&gt;&lt;img style=&quot;float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 95px; height: 200px;&quot; src=&quot;http://3.bp.blogspot.com/_FFVj2Tu_TDM/TN7h4-oHR9I/AAAAAAAAAYs/M0t02HuWFic/s200/Screen%2Bshot%2B2010-10-25%2Bat%2B0.39.23.PNG&quot; border=&quot;0&quot; alt=&quot;&quot;id=&quot;BLOGGER_PHOTO_ID_5539112960712460242&quot; /&gt;&lt;/a&gt;Просто для поднятия настроения, раз уж я тут картинки разбираю. Документация Google Android в Google Chrome и Opera (версии последниие). И не говорите мне после этого ничего, и не осуждайте выбор. На самом android&#39;е, кстати, встроенный браузер тоже слажал немного, не показав нижнюю левую панель, Opera Mobile справилась (хотя и были неточности).</description><link>http://thegeekbird.blogspot.com/2010/11/blog-post.html</link><author>noreply@blogger.com (PhoeniX)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSgudGgeqXch2F6iMzH7L6hkJNuSQN-Hd2QLB2uWk3_GJLnM1OHsUjlwXQpc-ztM0uYcLbS2W93QDuXDkldGQG_lf6Co3WJVySFjgY840Snuum-c7jScHHD792CXmbqJWW0EE_hOMr_Ps/s72-c/Screen+shot+2010-10-25+at+0.39.43.PNG" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-439775273064312982.post-8863719519837145378</guid><pubDate>Sat, 13 Nov 2010 18:22:00 +0000</pubDate><atom:updated>2010-11-13T23:54:41.922+05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">android</category><category domain="http://www.blogger.com/atom/ns#">ruby</category><title>Gradients in Android</title><description>Построение интерфейса Android&#39;а через xml - это сплошные преимущества, куда не посмотри. Только привыкнуть и научиться надо (конечно, на это надо время, которого никогда нет, поэтому этот рабочий пост написан в выходной).&lt;br /&gt;&lt;br /&gt;Вот пример - описав на xml радиальный градиент, используемый в качестве фона приложения, сократил размер выходного пакета почти в 3 раза за счёт того, что выкинул картинки с фоном. Осталось только с дизайнером сесть и цвета поправить.&lt;br /&gt;&lt;br /&gt;Ну и чтоб два раза не вставать, вот так можно ескейпить код в HTML:&lt;br /&gt;alias -g E=&#39;| ruby -rcgi -e &quot;ARGF.each{|line| puts CGI.escapeHTML line}&quot;&#39;&lt;br /&gt;это на zsh.&lt;br /&gt;&lt;br /&gt;XML:&lt;pre&gt;&lt;code class=&quot;prettyprint lang-xml&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&amp;gt;&lt;br /&gt;&amp;lt;shape xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;&amp;gt;&lt;br /&gt;   &amp;lt;gradient&lt;br /&gt;   android:centerX=&quot;0.5&quot;&lt;br /&gt;   android:centerY=&quot;0.5&quot;&lt;br /&gt;   android:endColor=&quot;#023F8F&quot;&lt;br /&gt;   android:gradientRadius=&quot;300&quot;&lt;br /&gt;   android:startColor=&quot;#1A96CA&quot;&lt;br /&gt;   android:type=&quot;radial&quot;&lt;br /&gt;   /&amp;gt;&lt;br /&gt;&amp;lt;/shape&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;До и после:&lt;br /&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;http://2.bp.blogspot.com/_FFVj2Tu_TDM/TN7Yr_AiVdI/AAAAAAAAAYk/mii-Ge1He9A/s1600/background.jpg&quot;&gt;&lt;img style=&quot;float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 136px; height: 200px;&quot; src=&quot;http://2.bp.blogspot.com/_FFVj2Tu_TDM/TN7Yr_AiVdI/AAAAAAAAAYk/mii-Ge1He9A/s200/background.jpg&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5539102841871947218&quot; /&gt;&lt;/a&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;http://4.bp.blogspot.com/_FFVj2Tu_TDM/TN7YgVbqRWI/AAAAAAAAAYc/-1fqiEl-xrc/s1600/device.png&quot;&gt;&lt;img style=&quot;float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 120px; height: 200px;&quot; src=&quot;http://4.bp.blogspot.com/_FFVj2Tu_TDM/TN7YgVbqRWI/AAAAAAAAAYc/-1fqiEl-xrc/s200/device.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5539102641732863330&quot; /&gt;&lt;/a&gt;</description><link>http://thegeekbird.blogspot.com/2010/11/gradients-in-android.html</link><author>noreply@blogger.com (PhoeniX)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_FFVj2Tu_TDM/TN7Yr_AiVdI/AAAAAAAAAYk/mii-Ge1He9A/s72-c/background.jpg" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-439775273064312982.post-863892708527287285</guid><pubDate>Sun, 24 Oct 2010 01:30:00 +0000</pubDate><atom:updated>2010-10-24T07:39:07.368+06:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">hint</category><category domain="http://www.blogger.com/atom/ns#">mac</category><category domain="http://www.blogger.com/atom/ns#">rant</category><title>Линковка в Mac OS X</title><description>Симптомы&lt;br /&gt;&lt;blockquote&gt;ld: in lib_foo.a, archive has no table of contents&lt;br /&gt;collect2: ld returned 1 exit status&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;Лечение&lt;br /&gt;&lt;blockquote&gt;export COMMAND_MODE=unix2003&lt;/blockquote&gt;&lt;br /&gt;ещё можно почитать man compat и убедиться, что врут, негодяи:&lt;br /&gt;&lt;blockquote&gt;if it is unset or set to something other than legacy or unix2003 it behaves as if it were set to unix2003&lt;/blockquote&gt;&lt;br /&gt;чего ради оно сломалось вдруг - непонятно, но раньше работало и без этих костылей.</description><link>http://thegeekbird.blogspot.com/2010/10/mac-os-x.html</link><author>noreply@blogger.com (PhoeniX)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-439775273064312982.post-7691635716087436310</guid><pubDate>Thu, 21 Oct 2010 19:25:00 +0000</pubDate><atom:updated>2011-10-01T02:38:54.900+06:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">hint</category><category domain="http://www.blogger.com/atom/ns#">mac</category><category domain="http://www.blogger.com/atom/ns#">rant</category><title>уходи, iTunes, уходи!</title><description>Чтобы угомонить вконец обнаглевшего уродливого толстяка iTunes, возомнившего себя единственным на свете плеером и намертво присосавшегося к аппаратной кнопке Play/Pause моего макбука после обновления оного до сноулео, достаточно сделать так:&lt;br /&gt;&lt;blockquote&gt;sudo chmod -x /Applications/iTunes.app/Contents/MacOS/iTunes&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;а для редких случаев, когда iTunes всё-таки нужен, сделать в Automator приложение с простым шелл-скриптом:&lt;br /&gt;&lt;blockquote&gt;sudo chmod +x /Applications/iTunes.app/Contents/MacOS/iTunes&lt;br /&gt;/Applications/iTunes.app/Contents/MacOS/iTunes &amp;&lt;br /&gt;sudo chmod -x /Applications/iTunes.app/Contents/MacOS/iTunes&lt;br /&gt;&lt;/blockquote&gt;Это я после очередного апдейта вспомнил, записываю чтоб не забыть.&lt;br /&gt;
UPD:&lt;br /&gt;
После того, как в очередной раз пришлось &lt;a href=&quot;http://thegeekbird.blogspot.com/2011/09/itunes.html&quot;&gt;курощать iTunes&lt;/a&gt;, скрипт перестал работать, то есть работал, но iTunes продолжала сетовать на отсутствие лайона. Рабочий вариант ниже:&lt;br /&gt;
&lt;blockquote&gt;sudo chmod +x /Applications/iTunes.app/Contents/MacOS/iTunes&lt;br /&gt;
open -a iTunes &amp;&lt;br /&gt;
sleep 5&lt;br /&gt;
sudo chmod -x /Applications/iTunes.app/Contents/MacOS/iTunes&lt;/blockquote&gt;</description><link>http://thegeekbird.blogspot.com/2010/10/itunes.html</link><author>noreply@blogger.com (PhoeniX)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-439775273064312982.post-3485709758859843859</guid><pubDate>Wed, 20 Oct 2010 00:48:00 +0000</pubDate><atom:updated>2010-10-20T07:27:36.340+06:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">android</category><category domain="http://www.blogger.com/atom/ns#">git</category><category domain="http://www.blogger.com/atom/ns#">java</category><category domain="http://www.blogger.com/atom/ns#">vim</category><title>Yet another Vim blog post (YAVBP)</title><description>За последние пару недель как-то много вокруг меня стало инфоповодов на тему Vim. Вот например прекрасная &lt;a href=&quot;http://stevelosh.com/blog/2010/09/coming-home-to-vim/&quot;&gt;статья&lt;/a&gt; о том, почему его надо использовать (очень толково, просто, есть про настройку с описанием).&lt;br /&gt;Так что я усиленно постился^Wпилил конфиг, запрягал Vim работать в паре с Elipse для работы над Android проектом (всё на удивление просто - последний Elipse, последний MacVim или GVim и &lt;a href=&quot;http://eclim.org/&quot;&gt;Eclim&lt;/a&gt;), собрался с духом, засунул наконец все конфиги в git и &lt;a href=&quot;http://github.com/thegeekbird/dotvim&quot;&gt;отправил на GitHub&lt;/a&gt;. Конфигурация получилась лёгкой, из неё было выброшены все вековые наслоения конфигов, ненужных плагинов и прочей чуши. Ещё там есть маленький враппер для открывания файла в новой вкладке существующего Vim&#39;а а не в новом экземпляре Vim&#39;а. Так что полюбопытствуйте.&lt;br /&gt;Впрочем, скорее всего, разработку под андроид вскоре можно будет отдать на откуп &lt;a href=&quot;http://confluence.jetbrains.net/display/IDEADEV/IDEA+X+EAP&quot;&gt;IntelliJ Idea X EAP&lt;/a&gt;, в которой есть и &lt;a href=&quot;http://www.jetbrains.com/idea/features/google_android.html&quot;&gt;поддержка оной&lt;/a&gt; и плагин-эмулятор Vim&#39;а. Попробовал, повертел - за час не возникло серьёзных претензий (да и вообще продукты &lt;a href=&quot;http://www.jetbrains.com/index.html&quot;&gt;JetBrains&lt;/a&gt; - это что-то, как и их поддержка), разве что не сразу понятно куда там коней^WSDK запрягать. Во всяком случае решение лучше Eclipse.</description><link>http://thegeekbird.blogspot.com/2010/10/yet-another-vim-blog-post-yavbp.html</link><author>noreply@blogger.com (PhoeniX)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-439775273064312982.post-4962034467073060449</guid><pubDate>Sun, 26 Sep 2010 19:09:00 +0000</pubDate><atom:updated>2010-11-19T19:05:03.787+05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">android</category><category domain="http://www.blogger.com/atom/ns#">java</category><title>Как заставить работать Force Close Dialog на себя</title><description>... или &lt;a href=&quot;http://imgur.com/jacoj&quot;&gt;Stacktrace or GTFO&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Задача.&lt;/b&gt;&lt;br /&gt;Итак, первое приложение для Android написано и его бета достигла девайсов пользователей. Задача - при получении исчерпывающего сообщения от пользователя &quot;Ничего не работает&quot; (ну ладно, ладно, более конкретного - &quot;Вылетает&quot;) знать, где и что не работает. Вообще это должно быть первым, что будет написано в приложении. Далее будет показано, как гарантированно поймать исключение и послать отчёт о нём в Redmine.&lt;br /&gt;&lt;br /&gt;Примечание: большая часть информации относится скорее к Java, чем к Андроиду, однако повод и место применения намекают.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Стратегия.&lt;/b&gt;&lt;br /&gt;Приложение совершило критический промах и укусило себя в глаз. Частный и самый распространённый случай этого - исключение (есть и другие варианты, я сталкивался с перезагрузкой телефона), которое принято отлавливать и что-то делать по факту. Если оно не отловлено - пользователь увидит т.н. Force Close Dialog. Начиная с версии 2.2 ещё и предложение собрать данные об ошибке и поспамить ими девелопера, НО надо понимать, что&lt;br /&gt;1. специфика некоторых ошибок привязана к определённым моделям девайсов, на которых вполне определённые версии Андроида, и это не 2.2&lt;br /&gt;2. специфика некоторых рынков в популярности определённых моделей девайсов, см. выше&lt;br /&gt;так что на этот способ не рассчитываем (как на основной).&lt;br /&gt;&lt;br /&gt;Необработанное исключение нужно прежде всего отловить. Для этого в Java есть обработчик исключений потока, Thread.UncaughtExceptionHandler, реализация Андроида как раз и показывает диалог и пишет стектрейс в LogCat. С отловленным исключением нужно что-то сделать (узнать о самом факте его возникновения)  и... в случае с UI Thread Андроида отпустить дальше - передать умолчальной реализации обработчика, потому что в противном случае, если исключение утаить, получим вместо одного диалога об ошибке другой (Application Not Responding). Кроме того, пользователю тоже особо ничего сказать не получится - UI Thread-то уже загнулся.&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;prettyprint lang-java&quot;&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;public class CrashReporter implements UncaughtExceptionHandler {&lt;br /&gt; private UncaughtExceptionHandler defaultHandler;&lt;br /&gt; public CrashReporter(UncaughtExceptionHandler defaultHandler)&lt;br /&gt; {&lt;br /&gt;  this.defaultHandler = defaultHandler;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public void uncaughtException(Thread thread, Throwable e) {&lt;br /&gt;  Log.e(&quot;CrashReporter&quot;, &quot;Caught &quot; + e.toString() + &quot; in &quot;&lt;br /&gt;            + thread.toString() + &quot;\n&quot; + Log.getStackTraceString(e));&lt;br /&gt;  // allow system to kill us&lt;br /&gt;  if(defaultHandler != null)&lt;br /&gt;   defaultHandler.uncaughtException(thread, e);&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt; &lt;br /&gt;&lt;br /&gt;На основе этого бесполезного пока (потом будет интереснее) класса и будет строится обработка ошибок.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Тактика. Андроид.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Поскольку UI Thread в Андроиде один на всех, то получить глобальную обработку ошибок очень просто, в главной Activity достаточно при создании указать этот класс как обработчик:&lt;br /&gt;&lt;pre class=&quot;prettyprint lang-java&quot;&gt;&lt;code&gt;&lt;br /&gt;public void onCreate(Bundle savedInstanceState) {&lt;br /&gt;    super.onCreate(savedInstanceState);  &lt;br /&gt;    Thread.currentThread().setUncaughtExceptionHandler(&lt;br /&gt;        new CrashReporter(Thread.currentThread().getUncaughtExceptionHandler()));&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt; &lt;/pre&gt; &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Тактика. Продвинутые техники.&lt;/b&gt;&lt;br /&gt;Однако не всё делается в UI потоке Андроида, тяжёлые вычисления требуется вынести за его пределы. В Андроиде есть AsyncTask, который мне не подошёл (да и вообще на мой взгляд подходит только для простейших вещей), я использую ThreadPoolExecutor. Чтобы создаваемые для него потоки имели нужный класс обработчика ошибок, придётся создать свою фабрику (да, вот он, Java way) и передавать её в конструктор ThreadPoolExecutor&#39;а:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;prettyprint lang-java&quot;&gt;&lt;code&gt;&lt;br /&gt;public class CrashReportingThreadFactory implements ThreadFactory{&lt;br /&gt; public Thread newThread(Runnable r) {&lt;br /&gt;  Thread newThread = Executors.defaultThreadFactory().newThread(r);&lt;br /&gt;  newThread.setUncaughtExceptionHandler(&lt;br /&gt;            new CrashReporter(newThread.getUncaughtExceptionHandler()));&lt;br /&gt;  return newThread;&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;public class CrashExecutor extends ThreadPoolExecutor {&lt;br /&gt;    private CrashExecutor(int corePoolSize, int maximumPoolSize,&lt;br /&gt;            long keepAliveTime, TimeUnit unit, BlockingQueue&amp;lt;Runnable&gt; workQueue) {&lt;br /&gt;        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, &lt;br /&gt;            new CrashReportingThreadFactory());&lt;br /&gt;    }&lt;br /&gt;&lt;/code&gt; &lt;/pre&gt; &lt;br /&gt; &lt;br /&gt;Но это полдела. Теперь хлопок другой ладонью - надо заставить Executor обрабатывать исключения, возникшие в задачах, в т.ч. отправленных на выполнение вызовом submit и/или обёрнутые в класс типа FutureTask (за объяснениями - в доки к ThreadPoolExecutor.afterExecute и литературу):&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;prettyprint lang-java&quot;&gt;&lt;code&gt;&lt;br /&gt;protected void afterExecute (Runnable r, Throwable t)&lt;br /&gt;{&lt;br /&gt;    super.afterExecute(r, t);&lt;br /&gt;    // задача отправлена на выполнение через submit или изначально является Future&lt;br /&gt;    if (t == null &amp;&amp; r instanceof Future) {&lt;br /&gt;        try {&lt;br /&gt;            // принудительный вызов исключения&lt;br /&gt;            ((Future&amp;lt;?&gt;) r).get();&lt;br /&gt;        } catch (CancellationException ce) {&lt;br /&gt;            // отмена задачи - нормальное событие&lt;br /&gt;        } catch (ExecutionException ee) {&lt;br /&gt;            t = ee.getCause();&lt;br /&gt;        } catch (InterruptedException ie) {&lt;br /&gt;            // прерывание потока извне - передача исключения выше&lt;br /&gt;            Thread.currentThread().interrupt(); // ignore/reset&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    if (t != null) {&lt;br /&gt;        Thread thread = Thread.currentThread();&lt;br /&gt;        thread.getUncaughtExceptionHandler().uncaughtException(thread, t);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt; &lt;/pre&gt;&lt;br /&gt;Так задача гарантированно будет вызывать исключение (из-за вызова get()) а исключения от Runnable не будут проглатываться.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Тактика. Redmine.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Всё, исключение есть, пора настроить Redmine:&lt;br /&gt;1. Создать роль типа Crash reporter, имеющую право только создавать issue&lt;br /&gt;2. учётную запись с этой ролью&lt;br /&gt;3. набор дополнительных полей для Issue - например номер билда, тип девайса, на котором произошло падение&lt;br /&gt;4. добавить учётку репортера в проект&lt;br /&gt;5. разрешить REST web service&lt;br /&gt;6. дополнительно можно завести под это свой тип трекера, чтобы отделять автоматически созданные issue&lt;br /&gt;&lt;br /&gt;теперь можно постить:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;prettyprint lang-java&quot;&gt;&lt;code&gt;&lt;br /&gt;// post reports only from wild (end-user) devices&lt;br /&gt;if(!ApplicationInfo.getInstance().isAppDebuggable()){&lt;br /&gt;    try {&lt;br /&gt;        StringBuilder postBody = new StringBuilder()&lt;br /&gt;            .append(&quot;&amp;lt;issue&gt;&amp;lt;project_id&gt;20&amp;lt;/project_id&gt;&amp;lt;subject&gt;&quot;)&lt;br /&gt;            .append(e.toString())&lt;br /&gt;            .append(&quot;&amp;lt;/subject&gt;&amp;lt;tracker_id&gt;4&amp;lt;/tracker_id&gt;&amp;lt;priority_id&gt;10&amp;lt;/priority_id&gt;&amp;lt;custom_field_values&gt;&amp;lt;1&gt;&quot;)&lt;br /&gt;            .append(Uri.decode(Settings.deviceInfo))&lt;br /&gt;            .append(&quot;&amp;lt;/1&gt;&amp;lt;2&gt;&quot;)&lt;br /&gt;            .append(ApplicationInfo.getInstance().deviceuid)&lt;br /&gt;            .append(&quot;&amp;lt;/2&gt;&amp;lt;3&gt;&quot;)&lt;br /&gt;            .append(String.valueOf(ApplicationInfo.getInstance().getAppBuild()))&lt;br /&gt;            .append(&quot;&amp;lt;/3&gt;&amp;lt;/custom_field_values&gt;&amp;lt;description&gt;&amp;lt;![CDATA[&quot;)&lt;br /&gt;            .append(Log.getStackTraceString(e).replaceAll(&quot;]]&gt;&quot;,&quot;]]&gt;]]&gt;&amp;lt;![CDATA[&quot;))&lt;br /&gt;            .append(&quot;]]&gt;&amp;lt;/description&gt;&amp;lt;/issue&gt;&quot;);&lt;br /&gt;        post(&quot;http://redmine.company.com/issues.xml&quot;, postBody.toString());&lt;br /&gt;    } catch (Exception e1) {/*silently die*/}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public static void post(String url, String postData) throws IOException {&lt;br /&gt;    HttpClient client = new DefaultHttpClient();&lt;br /&gt;    HttpPost request = new HttpPost(url);&lt;br /&gt;    request.addHeader(BasicScheme.authenticate(&lt;br /&gt;        new UsernamePasswordCredentials(&quot;crash&quot;, &quot;password&quot;), &quot;latin1&quot;, false));&lt;br /&gt;    request.addHeader(&quot;Content-Type&quot;, &quot;application/xml&quot;);&lt;br /&gt;    StringEntity se = new StringEntity(postData);&lt;br /&gt;    request.setEntity(se);&lt;br /&gt;    HttpResponse response = client.execute(request);&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt; &lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;ApplicationInfo - собственный класс, который собирает основную инфу об устройстве. Упоминаемые в xml ID можно узнать если посмотреть на ссылки соответствующих вещей - трекера, дополнительных полей, проекта.&lt;br /&gt;&lt;br /&gt;Можно собирать релизный билд. Главное - не забыть убрать логирование и возможность отладки (удивительно, как много приложений, в которыx это не сделано).</description><link>http://thegeekbird.blogspot.com/2010/09/force-close-dialog.html</link><author>noreply@blogger.com (PhoeniX)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-439775273064312982.post-5466401254527502818</guid><pubDate>Thu, 08 Jul 2010 18:24:00 +0000</pubDate><atom:updated>2010-07-09T00:36:32.419+06:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">hint</category><category domain="http://www.blogger.com/atom/ns#">linux</category><category domain="http://www.blogger.com/atom/ns#">mac</category><title>Shell hint - end task notification</title><description>Запустил долгую задачу, а когда кончится - непонятно, мониторинг активности консоли (как в Konsole или iTerm) тоже не помогает - процесс иногда обделывается выводом в STDERR, что делать?&lt;br /&gt;&lt;blockquote&gt;^z&lt;br /&gt;fg; say &quot;Job done!&quot;&lt;/blockquote&gt;&lt;br /&gt;Это для маков, но идея проста - отправить задачу в сон, вернуть обратно, по окончании отчитаться (линуксоиды могут прослушать ядро).</description><link>http://thegeekbird.blogspot.com/2010/07/shell-hint-end-task-notification.html</link><author>noreply@blogger.com (PhoeniX)</author><thr:total>4</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-439775273064312982.post-3070095777923037861</guid><pubDate>Mon, 28 Jun 2010 15:40:00 +0000</pubDate><atom:updated>2010-06-28T21:43:00.587+06:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">browser</category><category domain="http://www.blogger.com/atom/ns#">javascript</category><title>Старший onchange наблюдает за тобой</title><description>У dom элемента есть события. Среди них есть onchange. Если я делаю&lt;br /&gt;&lt;blockquote&gt;var onchange = function() {/* do here something*/};&lt;/blockquote&gt;&lt;br /&gt;то не странно ли  присобачивать  эту функцию _ко всем контролам ввода_ на странице? Они вообще слышали про пространства имён? Или это умышленно так?</description><link>http://thegeekbird.blogspot.com/2010/06/onchange.html</link><author>noreply@blogger.com (PhoeniX)</author><thr:total>3</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-439775273064312982.post-8472952806265682282</guid><pubDate>Tue, 11 May 2010 04:00:00 +0000</pubDate><atom:updated>2010-05-14T14:11:49.409+06:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">devel</category><category domain="http://www.blogger.com/atom/ns#">javascript</category><title>jqGrid custom date picker</title><description>Да, давно не писал, но это жизнь, которой мало, и работа, которой много. Вот по работе иногда приходится хлопать одной ладонью.&lt;br /&gt;&lt;p&gt;Так и на прошлой неделе - нужно было приделать к редактору модели в jqGrid свой элемент для редактирования дат, наподобие того, что генерят рельсы в ответ на select_date. Скудость документации и отсутствие толковых примеров и как следствие полдня экспериментов на пути к желаемому и стали причинами появления данного поста.&lt;/p&gt;Для начала обратимся к &lt;a href=&quot;http://www.trirand.com/jqgridwiki/doku.php?id=wiki:common_rules#editable&quot;&gt;истокам&lt;/a&gt; и объявим наше поле как custom, указав свои функции для создания элемента и извлечения значения из него.&lt;br /&gt;&lt;blockquote&gt;{name:&#39;v_birth&#39;, index:&#39;v_birth&#39;,formoptions:{elmprefix:&quot;* &amp;amp;nbsp&quot;},edittype:&#39;custom&#39;,editable:true,editoptions:{custom_element:dinput, custom_value:dvalue}}&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Дальше немного JS магии.&lt;br /&gt;&lt;br /&gt;&lt;script src=&quot;http://gist.github.com/396984.js&quot;&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;Создаём, заполняем значениями с выбором одного из них, и возвращаем массивом три select&#39;а и кнопку сброса.&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Подразумевается, что в таблицу дата приходит в американском формате (mm-dd-yyyy), именно поэтому у меня поле называется v_birth - это виртуальный атрибут, в базе это естественно тип Date. О валидации таких атрибутов и их применении совместно с jqGrid стоит сказать, пожалуй, отдельно, своим постом.&lt;/p&gt;&lt;p&gt;Пользователь увидит три селекта и кнопку сброса их в начальное значение (--). Браузер - невалидный код (три селекта с одинаковым id), но промолчит. Функция извлечения значения благодаря этому увидит все три select&#39;а, отмапит их в массив выбранных значений и склеит из него строку. Бэкенд - либо опять же дату в американском формате, либо пустую строку, если пользователь сбросил дату, либо неверную дату, и может сохранить, об NULL&#39;ить или остановить валидацию на своё усмотрение.&lt;/p&gt;&lt;p&gt;И для завершения - ещё один штрих. &lt;a href=&quot;http://www.trirand.com/jqgridwiki/doku.php?id=wiki:form_editing&amp;amp;s[]=recreateform&quot;&gt;Истоки&lt;/a&gt;.&lt;/p&gt;&lt;blockquote&gt;&lt;div&gt;...&lt;/div&gt;&lt;div&gt;&lt;table style=&quot;font-family: Times; font-size: medium; &quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;webkit-line-content&quot; id=&quot;aeaoofnhgocdbnbeljkmbjdmhbcokfdb-mousedown&quot;&gt;            .navGrid(&#39;#my_pager&#39;,&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class=&quot;webkit-line-number&quot;&gt;&lt;/td&gt;&lt;td class=&quot;webkit-line-content&quot;&gt;              {edit:true,add:true,del:true,search:false,refresh:true},&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class=&quot;webkit-line-number&quot;&gt;&lt;/td&gt;&lt;td class=&quot;webkit-line-content&quot;&gt;              {recreateForm:true,  afterSubmit:function(r,data){return afterSubmit(r,data,&#39;edit&#39;);}},&lt;br /&gt;....&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class=&quot;webkit-line-number&quot;&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;table style=&quot;font-family: Times; font-size: medium; &quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;webkit-line-number&quot;&gt;&lt;/td&gt;&lt;td class=&quot;webkit-line-content&quot;&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;Обратите внимание на &lt;span class=&quot;Apple-style-span&quot;   style=&quot;  -webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px; font-family:Times;font-size:medium;&quot;&gt;recreateForm:true. &lt;/span&gt;С этой опцией элемент будет создаваться каждый раз при открытии формы редактирования и устанавливать начальные значения из нужной модели, а не из первой, для которой он был вызван.&lt;/div&gt;А теперь отмазки. JS код грязноват и неоптимален, но я иррационально не люблю JS. Кроме того, на самом деле я использую &lt;span class=&quot;Apple-style-span&quot;  style=&quot; ;font-family:Verdana, Geneva, Arial, Helvetica, sans-serif;&quot;&gt; &lt;a href=&quot;http://github.com/ahe/2dc_jqgrid/tree/master&quot; target=&quot;_blank&quot; style=&quot;margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-decoration: none; &quot;&gt;2dcJqgrid Rails plugin&lt;/a&gt;&lt;/span&gt;, но уже сильно модифицированный (оригинал бы не позволил сделать описываемое), так что привожу JS код для создания таблицы.&lt;/p&gt;&lt;p&gt;Такие вот пироги. Надеюсь, юбилейная 200-я запись была вам полезна.&lt;/p&gt;</description><link>http://thegeekbird.blogspot.com/2010/05/jqgrid-custom-date-picker.html</link><author>noreply@blogger.com (PhoeniX)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-439775273064312982.post-965434444120138673</guid><pubDate>Wed, 13 Jan 2010 14:49:00 +0000</pubDate><atom:updated>2010-01-13T19:52:50.541+05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">devel</category><title>Коммить это!</title><description>Очень короткое наблюдение. Вчера заметил, что мой мозг отказывается думать над продолжением работы, потому что предыдущий цельный кусок сделан, но не скоммичен.</description><link>http://thegeekbird.blogspot.com/2010/01/blog-post.html</link><author>noreply@blogger.com (PhoeniX)</author><thr:total>2</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-439775273064312982.post-5721939163695281256</guid><pubDate>Sat, 21 Nov 2009 08:22:00 +0000</pubDate><atom:updated>2009-11-21T19:00:31.282+05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">mac</category><category domain="http://www.blogger.com/atom/ns#">rant</category><title>Док</title><description>Нашёл для себя идеальный вариант дока - не показывать ничего кроме запущенных программ (и запускать их через Namely). И пару папок с документами (ебуками) ибо для быстрого открытия документов индексаторы типа Spotlight ещё не годятся совсем (о, где же ты, krunner). Хотя, казалось бы, какого чёрта, на кой в системе тогда есть locate?&lt;br /&gt;UPD: нашёл такую штуку как &lt;a href=&quot;http://www.manytricks.com/butler/&quot;&gt;Butler&lt;/a&gt;. Как минимум fuzzy-find и запуск документов (да и вообще всего) он умеет, что уже покрывает мои потребности, а там столько всего...&lt;br /&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg88hkvzz2AliD6RuIiCFUA3juFo1mOMqgupuIgcGOWcX0lF24kZl0ylr6sXcCmD2SUea11zNatTLu4SB-tOkOJ_Bi0ISkXe2iMuhY2gn-EbsI5wrLrm6XVQK_e9XdqUEyimYER_oORyns/s1600/Picture+1.PNG&quot;&gt;&lt;img style=&quot;float:left; display:block; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 101px; height: 293px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg88hkvzz2AliD6RuIiCFUA3juFo1mOMqgupuIgcGOWcX0lF24kZl0ylr6sXcCmD2SUea11zNatTLu4SB-tOkOJ_Bi0ISkXe2iMuhY2gn-EbsI5wrLrm6XVQK_e9XdqUEyimYER_oORyns/s400/Picture+1.PNG&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5406469654139209858&quot; /&gt;&lt;/a&gt;</description><link>http://thegeekbird.blogspot.com/2009/11/namely.html</link><author>noreply@blogger.com (PhoeniX)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg88hkvzz2AliD6RuIiCFUA3juFo1mOMqgupuIgcGOWcX0lF24kZl0ylr6sXcCmD2SUea11zNatTLu4SB-tOkOJ_Bi0ISkXe2iMuhY2gn-EbsI5wrLrm6XVQK_e9XdqUEyimYER_oORyns/s72-c/Picture+1.PNG" height="72" width="72"/><thr:total>3</thr:total></item></channel></rss>