<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='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'><id>tag:blogger.com,1999:blog-4163717651209599087</id><updated>2024-08-30T09:23:43.085-07:00</updated><category term="dev"/><category term="python"/><category term="ruby"/><category term="webdev"/><category term="css"/><category term="daily shit"/><category term="html"/><category term="ror"/><category term="ror3"/><category term="shit"/><category term="aptana"/><category term="c"/><category term="cpython"/><category term="django"/><category term="dsl"/><category term="edu"/><category term="extjs"/><category term="fonts"/><category term="google"/><category term="hints"/><category term="ie"/><category term="intellij idea"/><category term="jetbrains"/><category term="lisp"/><category term="oop"/><category term="pylons"/><category term="pyramid"/><category term="rubymine"/><category term="sencha"/><category term="singleton"/><category term="twisted"/><category term="вёрстка"/><category term="костыли"/><title type='text'>Я не знаю что здесь и написать</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://tiaquenes.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4163717651209599087/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://tiaquenes.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>16</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4163717651209599087.post-167400960342172656</id><published>2011-03-03T01:46:00.000-08:00</published><updated>2011-03-03T01:46:14.577-08:00</updated><title type='text'>А мы переехали, да</title><content type='html'>Воооот сюда:&lt;br /&gt;
&lt;a href=&quot;http://blog.soulrobber.ru/&quot;&gt;http://blog.soulrobber.ru/&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://tiaquenes.blogspot.com/feeds/167400960342172656/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://tiaquenes.blogspot.com/2011/03/blog-post.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4163717651209599087/posts/default/167400960342172656'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4163717651209599087/posts/default/167400960342172656'/><link rel='alternate' type='text/html' href='http://tiaquenes.blogspot.com/2011/03/blog-post.html' title='А мы переехали, да'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4163717651209599087.post-8762916400269974294</id><published>2011-01-16T06:18:00.000-08:00</published><updated>2011-01-16T06:18:48.881-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="daily shit"/><category scheme="http://www.blogger.com/atom/ns#" term="dev"/><category scheme="http://www.blogger.com/atom/ns#" term="edu"/><category scheme="http://www.blogger.com/atom/ns#" term="shit"/><title type='text'>Программисты не умеют программировать</title><content type='html'>Недавно вновь прогремела статья из блога &quot;Coding Horror&quot; &lt;a href=&quot;http://www.codinghorror.com/blog/2007/02/why-cant-programmers-program.html&quot;&gt;&quot;Why Can&#39;t Programmers.. Program?&quot;&lt;/a&gt;.&lt;br /&gt;
Суть статьи заключается в мысли, что среднестатистический программист не способен решить простую задачу(реализация задачи &quot;FizzBuzz&quot;, см. далее) менее чем за 10 минут(10-15, как сказано в статье).&lt;br /&gt;
Ещё в 2007ом данный вопрос взбудоражил всех и вся. Все начали доказывать что автор - идиот и &quot;АПАЗОРИЛСЯ&quot;. Однако, людям удалось доказать не только это, но и то, что программисты не умеют программировать.&lt;br /&gt;
&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
Для начала, вот задача &quot;FizzBuzz&quot;:&lt;br /&gt;
&lt;blockquote&gt;Write a program that prints the numbers from 1 to 100. But for multiples of three print &quot;Fizz&quot; instead of the number and for the multiples of five print &quot;Buzz&quot;. For numbers which are multiples of both three and five print &quot;FizzBuzz&quot;.&lt;/blockquote&gt;А вот и перевод:&lt;br /&gt;
&lt;blockquote&gt;Напишите программу, которая выводит на экран числа от 1 до 100. При этом вместо чисел, кратных трем, программа должна выводить слово «Fizz», а вместо чисел, кратных пяти — слово «Buzz». Если число кратно и 3, и 5, то программа должна выводить слово «FizzBuzz».&lt;/blockquote&gt;via &lt;a href=&quot;http://www.linux.org.ru/forum/development/5794823&quot;&gt;LOR&lt;/a&gt;&lt;br /&gt;
Нужно отметить что задача очень проста, а главное - описана прямо, нет нужды самому что-то додумывать, составлять ТЗ.&lt;br /&gt;
&lt;br /&gt;
Для начала, стоит поговорить о том, сколько времени займёт реализация задачи средним программистом. А действительно, &lt;b&gt;сколько&lt;/b&gt;?&lt;br /&gt;
Многие люди трактуют утверждение как &quot;&lt;i&gt;ты лох, не сможешь решить задачу так быстро&lt;/i&gt;&quot;. Это не так. Это &lt;b&gt;бред&lt;/b&gt;. &lt;b&gt;Ты себя считаешь среднестатистическим программистом?&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Если &lt;b&gt;да&lt;/b&gt;, то у меня для тебя плохие новости: среднестатистический программист кодит на &lt;b&gt;пхп&lt;/b&gt; и &lt;b&gt;не знает&lt;/b&gt; что такое MVC. На западе, конечно, ситуация похожа, но значительно лучше: там&lt;i&gt;(в образе среднестатистического программиста)&lt;/i&gt; есть и &lt;i&gt;джавакодеры&lt;/i&gt;, и &lt;i&gt;рубисты&lt;/i&gt;. Эти программисты могли получить овер9к 5ок в школе, получить по 10 В/О, поучаствовать в 100500 проектах(среди которых могут быть крупные), заслужить уважение у многих людей, получить награды, дипломы, сертификаты etc. Среди таких программистов есть и хорошие люди, среди них есть даже умные, но которым просто &lt;b&gt;нет нужды&lt;/b&gt; дальше развиваться, а сами они и &lt;b&gt;не хотят&lt;/b&gt;.&lt;br /&gt;
Самое важное то, что такие программисты решают определённые задачи, но если ты попросишь что-то иное, что они никогда не делали, то им &lt;b&gt;придётся подумать&lt;/b&gt;. &lt;b&gt;10-15 минут&lt;/b&gt;.&lt;br /&gt;
А теперь &lt;b&gt;ПОДУМАЙ&lt;/b&gt;! Такой ли ты программист? Если ты читаешь эту статью, то велик шанс что ты значительно выше.&lt;br /&gt;
&lt;br /&gt;
Если &lt;b&gt;нет&lt;/b&gt;, то у меня для тебя тоже не самые приятные новости. Ты споришь&lt;i&gt;(если, конечно, споришь)&lt;/i&gt; с тем, что кровь красная, при этом используя в качестве доказательства то, что небо синее. Т.е. то, что ты быстро умеешь решать какую-либо задачу, не говорит о том, что её так же быстро решают такие программисты, о которых говорится в статье&lt;i&gt;(среднестатистический программист, напомню)&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
Вообще, конечно, статья на &quot;кодинг хоррор&quot; не говорит о том, что именно эту задачу средний программист реализует именно за 10-15 минут. Это только пример, это только цифры из головы.&lt;br /&gt;
&lt;b&gt;НЕ БУДЬТЕ ИДИОТАМИ!&lt;/b&gt;&lt;br /&gt;
Умейте улавливать мысль. Умейте понимать мысль. Умейте читать между строк. Не придирайтесь к таким мелочам, которые не играют роли. Это слова, никому не нравится, когда люди придираются к словам, не улавливая сути! &lt;b&gt;Это бесит&lt;/b&gt;, выводит автора из себя.&lt;br /&gt;
&lt;i&gt;Я это хорошо испытал на себе и не пожелаю таких вещей даже врагу.&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Главная мысль, которую нужно было понять&lt;/b&gt;: сегодня, среднестатистический программист, который может работать рядом с каждым, каких людей больше 90% в IT-индустрии, не способен быстро реализовать простейший алгоритм и ему для этого нужно небольшое время.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Всё.&lt;/b&gt;&lt;br /&gt;
&lt;i&gt;Если вы увидели что-то другое, оскорбляющее вас, автора статьи или что-то ещё, то вам нужно хорошенько подумать или просто лечиться.&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
Конечно,большинство решило что нужно доказать, что они не так глупы и вполне могут решить задачу быстро. Ну давайте взглянем на то, как люди решили эту задачу, доказав какие они умные.&lt;br /&gt;
&lt;br /&gt;
В качестве источников будут использоваться 3 статьи:&lt;br /&gt;
&lt;a href=&quot;http://www.linux.org.ru/forum/development/5794823&quot;&gt;На ЛОРе&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://habrahabr.ru/blogs/htranslations/111843/&quot;&gt;На Хабре&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://www.codinghorror.com/blog/2007/02/why-cant-programmers-program.html&quot;&gt;Оригинальная статья на Coding Horrors&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-size: large;&quot;&gt;Первый алгоритм&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-size: x-small;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
Visual Basic Script:&lt;br /&gt;
&lt;pre class=&quot;brush: python; gutter: true; highlight: []&quot;&gt;Dim i

For i = 1 to 100
 If (i Mod 3 = 0) And (i Mod 5 = 0) Then
  WScript.Echo &quot;FizzBuzz&quot;
 ElseIf (i Mod 3 = 0) Then
  WScript.Echo &quot;Fizz&quot;
 ElseIf (i Mod 5 = 0) Then
  WScript.Echo &quot;Buzz&quot;
 Else
  Wscript.Echo i
 End If
Next
&lt;/pre&gt;Как можно судить по языку, на котором написан этот код, автор являлся начинающим программистом. Стоит отметить, что сам VBS является таким языком, на котором программируют либо начинающие, либо любители MS Office, а сам язык не обладает таким уж количеством инструментов, из-за чего приходится часто заниматься такими вот задачами.&lt;br /&gt;
Решение не хитрое. Прямое, но хорошо выполняющее задачу. Это один из правильных вариантов.&lt;br /&gt;
&lt;br /&gt;
Мой код(написание - меньше минуты), в лоб:&lt;br /&gt;
&lt;pre class=&quot;brush: python; gutter: true; highlight: []&quot;&gt;for i in xrange(1, 101):
   if (i % 3) == 0 and (i % 5) == 0:
      print &quot;FizzBuzz&quot;
   elif (i % 3) == 0:
      print &quot;Fizz&quot;
   elif (i % 5) == 0:
      print &quot;Buzz&quot;
   else:
      print i
&lt;/pre&gt;&lt;br /&gt;
Надо сказать что такой алгоритм почти никто не предоставлял, но почти все очень похожи.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-size: large;&quot;&gt;&lt;b&gt;Второй алгоритм&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-size: x-small;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
Есть и второй вариант алгоритма.&lt;br /&gt;
Острый глаз программиста может заметить здесь что третья фраза образуется из двух первых: &quot;FizzBuzz&quot;. При этом, логика как-бы намекает на одну мысль, которая реализована в этом варианте:&lt;br /&gt;
&lt;pre class=&quot;brush: python; gutter: true; highlight: []&quot;&gt;for i in range(1,101):
    s = &#39;&#39;
    if (i % 3 == 0):
        s += &#39;Fizz&#39;
    if (i % 5 == 0):
        s += &#39;Buzz&#39;
    if not s:
        s += str(i)
    print s
&lt;/pre&gt;&lt;br /&gt;
Вариант быстрее(в теории), короче. Но у него есть, как минимум, один большой минус - теряется логика, читаемость и очевидность. Комментарий придётся писать, но если использовать первый алгоритм, то можно обойтись и без него.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
А вот дальше идут более интересные примеры.&lt;br /&gt;
&lt;br /&gt;
Руби. Первый алгоритм.&lt;br /&gt;
&lt;pre class=&quot;brush: ruby; gutter: true; highlight: []&quot;&gt;1.upto(100) { |n| puts n % 3 == 0 ? n % 5 == 0 ? &quot;fizzbuzz&quot; : &quot;buzz&quot; : n % 5 == 0 ? &quot;fizz&quot; : n }
&lt;/pre&gt;&lt;br /&gt;
Стоит отметить что выполняя простую задачу, все стремятся выполнить её в одну строчку или просто как можно более компактно. &lt;b&gt;Не думайте о объёме кода, думайте о алгоритме!&lt;/b&gt; Отбросьте лямбды, замыкания, оптимизацию, инструменты. &lt;b&gt;Думайте не инструментами, а просто логикой!&lt;/b&gt;&lt;br /&gt;
Сокращая код, реализующий плохой алгоритм, &lt;b&gt;вы сокращаете буквы, когда можно слова&lt;/b&gt;!&lt;br /&gt;
Вот два похожих примера:&lt;br /&gt;
&lt;pre class=&quot;brush: python; gutter: true; highlight: []&quot;&gt;for i in (&quot;FizzBuzz&quot; if not x % 15 else &quot;Fizz&quot; if not x % 3 else &quot;Buzz&quot; if not x % 5 else x for x in xrange(1,101)): print i

map( print, ( &quot;FizzBuzz&quot; if not x % 15 else &quot;Fizz&quot; if not x % 3 else &quot;Buzz&quot; if not x % 5 else x for x in xrange(1,101)) )
&lt;/pre&gt;&lt;br /&gt;
Заметьте математическую оптимизацию в виде замены двойного условия на одно:&lt;br /&gt;
&lt;blockquote&gt;if not x % 15&lt;/blockquote&gt;&lt;br /&gt;
Интересный вариант, но не имеет права на жизнь.&lt;br /&gt;
&lt;pre class=&quot;brush: python; gutter: true; highlight: []&quot;&gt;for i in range(1,101): print {0:&quot;FizzBuzz&quot;, 3:&quot;Fizz&quot;, 6:&quot;Fizz&quot;, 9:&quot;Fizz&quot;, 12:&quot;Fizz&quot; , 5:&quot;Buzz&quot;, 10:&quot;Buzz&quot;}.get(i%15, i)
&lt;/pre&gt;&lt;br /&gt;
Вообще, однострочников действительно туча среди вариантов. Все они делятся на 3 категории: первый, второй алгоритм и один или другой но через ж.&lt;br /&gt;
&lt;br /&gt;
Вот здесь такая &lt;a href=&quot;http://pastie.org/1466518&quot;&gt;подборочка&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Всё это адов страх и ужас. Более всего пугает тот факт, что люди часто пишут такой код с самого начала, так и понимая задачу. Они тратят кучу времени на этот код, но в результате получают говно, которое не только трудно читать, теряет алгоритм в коде, не даёт понять задачу, но ещё и оказывается затратнее прямого варианта. &lt;b&gt;Зачем?&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Более всего интересен тот факт, что многие просто не могут понять задачу, упускают какие-либо моменты, трактуют свои правила.&lt;br /&gt;
&lt;pre class=&quot;brush: python; gutter: true; highlight: []&quot;&gt;for (int i = 1; i 101; i++)
{
 if ((i % 3) == 0) Console.Write(&quot;Fizz&quot;);
 if ((i % 5) == 0) Console.Write(&quot;Buzz&quot;);
 Console.WriteLine();
}

for num in range(1, 101):
 if not num % 3:
  print &quot;bizz&quot;
 elif not num % 5:
  print &quot;buzz&quot;
 else:
  print num

#CF (SCRIPT) version
for (i = 1; i LTE 100; i = i + 1) {
if ((j MOD 3) AND (j MOD 5)) {
WriteOutput(i);
} else {
if (NOT j MOD 3) {WriteOutput(&#39;FIZZ&#39;);} 
if (NOT j MOD 5) {WriteOutput(&#39;BUZZ&#39;);}
}
WriteOutput(chr(13) chr(10));
}

for (int i = 0; i &amp;lt; 100; i++) {
 bool byThree = (!(i % 3));
 bool byFive = (!(i % 6));
 if (byThree) std::cout &amp;lt;&amp;lt; &quot;Fizz&quot;;
 if (byFive) std::cout &amp;lt;&amp;lt; &quot;Buzz&quot;;
 if (!byThree &amp;amp;&amp;amp; !byFive) std::cout &amp;lt;&amp;lt; i;
 std::cout &amp;lt;&amp;lt; std::endl;
}

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
int main(int argc, char * argv[])
{
   int i = 0;
   for (i = 0; i &amp;lt; 100; i++) {
      if (i%3 == 0)
         printf(&quot;Fizz\n&quot;);
      else if (i%5 == 0)
         printf(&quot;Buzz\n&quot;);
      else if (i%3 == 0 &amp;amp;&amp;amp; i%5 == 0)
         printf(&quot;FizzBuzz\n&quot;);
      else
         printf(&quot;%d\n&quot;, i);
   }
   return EXIT_SUCCESS;
}
&lt;/stdlib.h&gt;&lt;/stdio.h&gt;&lt;/pre&gt;Etc. Много разного кода, который по невнимательности написан таким, что не может выполнять задачу правильно. А про то, что люди забывают использовать для сравнения &amp;lt;= вместо &amp;lt;, при этом используют число 100, в результате чего выполняется цикл до 99, а не 100... &lt;i&gt;В последнем сырце никогда не будет напечатано FizzBuzz. Почему? Подумайте. Ответ прост.&lt;/i&gt; &lt;br /&gt;
&lt;br /&gt;
Очень много кода, который был написан не в шутку, но просто получилась грязь. Хотя, некоторые сырцы заслуживают внимания.  &lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: python; gutter: true; highlight: []&quot;&gt;(defun fizzbuzz (n)
(when ( n 0) 
(fizzbuzz (- n 1))
(format t &quot;~a~%&quot; 
(if (= (mod n 3) 0)
(if (= (mod n 5) 0) &quot;FizzBuzz&quot; &quot;Fizz&quot;)
(if (= (mod n 5) 0) &quot;Buzz&quot; n)))))
(progn (fizzbuzz 100) (values))

def fizzbuzz(n):
 if n:
 if n % 15 == 0: return fizzbuzz(n-1) + &#39;fizzbuzz &#39;;
 elif n % 5 == 0: return fizzbuzz(n-1) + &#39;buzz &#39;;
 elif n % 3 == 0: return fizzbuzz(n-1) + &#39;fizz &#39;;
 else : return fizzbuzz(n-1) + (&#39;%d &#39; % n)
 return &#39;&#39;
fizzbuzz(100)

for (x=1;x101;x++)
{
sprintf(temp,&quot;%s&quot;,x%3 ? &quot;&quot;:&quot;fizz&quot;);
sprintf(tem1,&quot;%s&quot;,x%5 ? &quot;&quot;:&quot;buzz&quot;);
strcat(temp,tem1);
if (!temp[0])
sprintf(temp,&quot;%d&quot;,x);
printf(&quot;%s\n&quot;,temp);
}

#include &lt;stdio.h&gt;
int main(int argc, char *argv[argc])
{
   {
   char const *output[] = {&quot;%d\n&quot;, &quot;Fizz\n&quot;, &quot;Buzz\n&quot;, &quot;FizzBuzz\n&quot;};
   for(size_t i = 1, check = 0; i &amp;lt;= 100; ++i, check = 0)
   {
      if(0 == i%3)check |=1;
      if(0 == i%5)check |=2;
      printf(output[check], i);
   }
   }
   return getch();
}

toString :: Int -&amp;gt; String
toString n | n `mod` 15 == 0 = &quot;FizzBuzz&quot;
           | n `mod`  3 == 0 = &quot;Fizz&quot;
           | n `mod`  5 == 0 = &quot;Buzz&quot;
           | True            = show n
solve :: [Int] -&amp;gt; IO ()
solve [] = return ()
solve (x:xs) = do putStrLn (toString x)
                  solve xs
main :: IO ()
main = solve [1 .. 100]

program main
    character*8 str
do i=1,100
   write(str(1:8),&#39;(i8.1)&#39;) i
   If (mod(i,3).eq.0) then
      write(str(1:8),&#39;(A8)&#39;) &quot;Fizz    &quot;
   endif
   If (mod(i,5).eq.0) then
      write(str(1:8),&#39;(A8)&#39;) &quot;Buzz    &quot;
   endif
   If (mod(i,15).eq.0) then
      write(str(1:8),&#39;(A8)&#39;) &quot;FizzBuzz&quot;
   endif
   write(*,*) str
enddo

100.times do |i|
  num=i+1
  [ (num % 3).zero? ? &quot;Fizz&quot; : nil,
    (num % 5).zero? ? &quot;Buzz&quot; : nil,
    ((num % 3).zero? or (num % 5).zero?) ? nil : num,
    &quot;,&quot;
    ].compact.join.display  
end

% 2min
-module(fizzbuzz).
-compile(export_all).
f(N) when (N rem 15) == 0 -&amp;gt; io:format(&quot;FizzBuzz~n&quot;, []), f(N+1);
f(N) when (N rem 5) == 0 -&amp;gt; io:format(&quot;Buzz~n&quot;, []), f(N+1);
f(N) when (N rem 3) == 0 -&amp;gt; io:format(&quot;Fizz~n&quot;, []), f(N+1);
f(101) -&amp;gt; ok;
f(N) -&amp;gt; io:format(&quot;~p~n&quot;, [N]), f(N+1).
start() -&amp;gt; f(1).

let divs = [(3, &quot;Fizz&quot;); (5, &quot;Buzz&quot;)]
let prefix i = 
    divs 
    |&amp;gt; Seq.filter (fun (d, _) -&amp;gt; (i % d) = 0) 
    |&amp;gt; Seq.map snd 
    |&amp;gt; String.concat &quot;&quot;
let convert i = 
    let special = prefix i
    if special = &quot;&quot; then
        string i
    else
        special
{1..100} 
|&amp;gt; Seq.map convert 
|&amp;gt; Seq.iter (fun x -&amp;gt; printfn &quot;%A&quot; x)
&lt;/stdio.h&gt;&lt;/pre&gt;Etc.  Да, мне страшно за умных людей. Я не просто так говорю что на ЛОРе, например, сидят профессионалы. Большинство реально профессионалы своего дела(тем более в сравнении с &quot;среднестатистическим программистом&quot;). Увы, мало кто способен выбирать верный путь, инструмент. Это жуть как пугает.&lt;br /&gt;
&lt;br /&gt;
Часто люди становятся рабами плохих технологий. Среди них есть и авторы предыдущих сырцов. Это очень, очень обидно.  &lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: python; gutter: true; highlight: []&quot;&gt;#php
for($i=0;$i++&amp;lt;100;)
{
$f=$i%3?&#39;&#39;:&#39;Fizz&#39;;
$b=$i%5?&#39;&#39;:&#39;Buzz&#39;;
echo$f.$b?$f.$b:$i,&#39;,&#39;;
}

(loop for i from 1 to 100 do
  (print (cond ((zerop (mod i (* 3 5))) &quot;FizzBuzz&quot;)
               ((zerop (mod i 3)) &quot;Fizz&quot;)
               ((zerop (mod i 5)) &quot;Buzz&quot;)
          (t i))))

for (1..100) {
        my $t = &#39;&#39;;
        $t = &#39;Fizz&#39; unless $_ % 3;
        $t .= &#39;Buzz&#39; unless $_ % 5;
        $t ||= $_;
        print &quot;$t\n&quot;;
}

Процедура ПриНачалеРаботыСистемы()
  Для Сч = 1 По 100 Цикл
    Если Сч % 15 = 0 Тогда
      Сообщить(&quot;FizzBuzz&quot;)
    ИначеЕсли Сч % 3 = 0 Тогда
      Сообщить(&quot;Fizz&quot;)
    ИначеЕсли Сч % 3 = 0 Тогда
      Сообщить(&quot;Buzz&quot;)
    Иначе
      Сообщить(Сч)
    КонецЕсли;
 КонецЦикла;
КонецПроцедуры


Console.WriteLine(
                string.Join(
                    Environment.NewLine,
                    Enumerable.Range(1, 100)
                        .Select(num =&amp;gt;
                            num % 5 == 0 &amp;amp;&amp;amp; num % 3 == 0 ? &quot;FizzBuzz&quot; :
                            num % 3 == 0 ? &quot;Fizz&quot; :
                            num % 5 == 0 ? &quot;Buzz&quot; :
                            Convert.ToString(num)
                        )
                )
 );

#SWI-Prolog
fizzBuzz(100).
fizzBuzz(N) :-
 I3 is N mod 3,
 I5 is N mod 5,
 print( I3, I5, N ), nl,
 N2 is N + 1,
 fizzBuzz(N2).
print( 0, 0, _ ) :-
 write( &#39;FizzBuzz&#39; ).
print( 0, _, _ ) :-
 write( &#39;Fizz&#39; ).
print( _, 0, _ ) :-
 write( &#39;Buzz&#39; ).
print( _, _, N ) :-
 write(N).

#gprolog
fizzlist(0, [], M).
fizzlist(N, [H|T], M) :- N &amp;gt; 0, N1 is N - 1, M1 is M - N + 1, fizzbuzz(M1, H), fizzlist(N1, T, M).
fizzlist(N, L) :- fizzlist(N, L, N).
fizzbuzz(N, N) :- N mod 3 &amp;gt; 0, N mod 5 &amp;gt; 0.
fizzbuzz(N, &#39;Fizz&#39;) :- 0 is N mod 3, N mod 5 &amp;gt; 0.
fizzbuzz(N, &#39;Buzz&#39;) :- 0 is N mod 5, N mod 3 &amp;gt; 0.
fizzbuzz(N, &#39;FizzBuzz&#39;) :- 0 is N mod 3, 0 is N mod 5.

#mercury
:- module fizzbuzz.
:- interface.
:- import_module io.
:- pred main(io, io).
:- mode main(di, uo) is det.
:- implementation.
:- import_module int.
main --&amp;gt; fizzbuzz(1).
fizzbuzz(N) --&amp;gt; 
 ( {N =&amp;lt; 100} -&amp;gt;
  print_fizzbuzz(N),
  print(&quot; &quot;),
  fizzbuzz(N + 1)
 ; []
 ).
print_fizzbuzz(N) --&amp;gt; 
 ( {N mod 3 = 0} -&amp;gt;
  ( {N mod 5 = 0} -&amp;gt;
   print(&quot;fizzbuzz&quot;)
  ; print(&quot;fizz&quot;)
  )
 ; {N mod 5 = 0} -&amp;gt;
  print(&quot;buzz&quot;)
 ; print(N)
 ).
&lt;/pre&gt;&lt;pre class=&quot;brush: python; gutter: true; highlight: []&quot;&gt;&lt;/pre&gt;Etc.  А ещё есть много любителей преждевременной оптимизации. &lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: python; gutter: true; highlight: []&quot;&gt;#include &lt;stdio.h&gt;
int main()
{
   int i;
   for (i=1;i&amp;lt;=100;i++){
      if (!(i % 3)){
         if (!(i % 5)) printf(&quot;Fizzbuzz\n&quot;);
         else printf(&quot;Fizz\n&quot;);
      } else if (!(i % 5)) printf(&quot;Buzz\n&quot;);
      else printf(&quot;%d\n&quot;,i);
   }
   return 0
}

for ($i = 1; $i &amp;lt;= 30; $i++)
{
    if (($i % 3 != 0) AND ($i % 5 != 0)) echo $i;
    else
    {
        if ($i % 3 == 0) echo &#39;Fizz&#39;;
        if ($i % 5 == 0) echo &#39;Buzz&#39;;
    }
    echo &#39;
&#39;;
}

for i := 1 to 100 do
if i mod 3 = 0 then
if i mod 5 &amp;lt;&amp;gt; 0 then
print(&#39;Fizz&#39;)
else
print(&#39;FizzBuzz&#39;)
else
if i mod 5 &amp;lt;&amp;gt; 0 then
print(i)
else
print(&#39;Buzz&#39;);
&lt;/stdio.h&gt;&lt;/pre&gt;Etc. Здесь даже нечего добавить.&lt;br /&gt;
&lt;br /&gt;
А ещё есть огромное число либо новичков, либо не опытных кодеров. Много кода, который использовал дополнительные переменные, флаги, иной бред. &lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: python; gutter: true; highlight: []&quot;&gt;bool printint;
for (int i = 1; i = 100; i++)
{
printint = true;
if (i % 3 == 0) { Console.Write(&quot;Fizz&quot;); printint = false; }
if (i % 5 == 0) { Console.Write(&quot;Buzz&quot;); printint = false; }
if (printint) Console.Write(i.ToString());
Console.WriteLine();
}

public class FizzBuzz
{
public static void main(String [] args)
{
int k;
for(int i=1; i=100; i++)
{
k = 0;
if(i%3==0)
{
k = 1;
}
if(i%5==0)
{
k = k + 2;
}
switch(k)
{
case 1:
System.out.println(&quot;Fizz&quot;);
break;
case 2:
System.out.println(&quot;Buzz&quot;);
break;
case 3:
System.out.println(&quot;FizzBuzz&quot;);
break;
default:
System.out.println(i);
}
}
}
}

#include stdio.h
int main(void)
{
int i,j=0;
for(i=0;i=100;i++)
{
if((i%3)==0)
{
printf(&quot;Fizz&quot;);
j=1;
}
if((i%5)==0)
{
printf(&quot;Buzz&quot;);
j=1;
}
if(!j)
{
printf(&quot;%d&quot;,i);
}
printf(&quot;\n&quot;);
j=0;
}
}

#include &lt;stdio.h&gt;
int main() {
  for (int i=1; i&amp;lt;=100; i++) {
    int a=i%3, b=i%5;
    if (a)
      if (b) printf(&quot;%d\n&quot;);
      else printf(&quot;Buzz\n&quot;);
    else
      if (b) printf(&quot;Fizz\n&quot;);
      else printf(&quot;FizzBuzz\n&quot;);
  }
}
&lt;/stdio.h&gt;&lt;/pre&gt;Но все учились, это нормально. Стоит отметить что даже такие люди генерили решение в пределах 10 минут.&lt;br /&gt;
&lt;br /&gt;
И в заключение надо бы выделить несколько красивых решений обычных алгоритмов. Все они зависят от языков, это язык даёт им такую красоту. &lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: python; gutter: true; highlight: []&quot;&gt;1.upto(100) do |i|
out = nil
out = out.to_s + &#39;Fizz&#39; if i % 3 == 0
out = out.to_s + &#39;Buzz&#39; if i % 5 == 0
puts out || i
end

#lua is nice!
for i=1,100 do 
fizz= (i%3==0) and &quot;Fizz&quot; or &quot;&quot;
buzz= (i%5==0) and &quot;Buzz&quot; or &quot;&quot;
print(i,fizz..buzz)
end

for (var i = 1; i &amp;lt;= 100; i ++) {
var x = &#39;&#39;;
if (i % 3 == 0) x += &#39;Fizz&#39;;
if (i % 5 == 0) x += &#39;Buzz&#39;;
console.log(x || i);
}
&lt;/pre&gt;&lt;pre class=&quot;brush: python; gutter: true; highlight: []&quot;&gt;&lt;/pre&gt;В первом коде интересна идея применения &quot;или&quot; для определения что нужно напечатать: цифру или слово.&lt;br /&gt;
Во втором(луа) офигенна идея слияния строк.&lt;br /&gt;
В третьем используется такая же идея, как и в первом.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-size: large;&quot;&gt;Заключение&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-size: x-small;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
Это ужас, ребята. Из всего кода, который был представлен людьми, около 2% является кодом, который можно понять только взглянув на него.&lt;br /&gt;
Очень, очень много кода, который написан используя ужасный стиль. Ужасный! Так нельзя.&lt;br /&gt;
Хорошо было показано то, что люди редко выбирают нужны инструмент для нужной задачи. Люди становятся рабами своих инструментов и просто не хотят верить что есть что-то лучше.&lt;br /&gt;
Программисты выбирают красоту семантики, вместо красоты синтаксиса.&lt;br /&gt;
Используют преждевременную оптимизацию, затягивая реализацию решения.&lt;br /&gt;
Используют ресурсы не думая о них.&lt;br /&gt;
Думают &quot;в лоб&quot;.&lt;br /&gt;
&lt;br /&gt;
В итоге, я точно могу сказать что, на собеседовании у меня, около 80% авторов кода просто отпали бы. Ещё 15% я бы сохранил в списке, но при появлении хоть одного из оставшихся 5%, я бы их всех отсеял или просто оставил для будущего.&lt;br /&gt;
Больше всего пугает тот факт, что среди авторов кода только около 3% людей являются представителями более или менее близкого к среднестатистическому программисту уровня.&lt;br /&gt;
&lt;br /&gt;
Программисты умеют программировать. Большинство - плохо. Однако, программистами себя стали называть даже те, кто относятся к категории &quot;среднестатистический программист&quot;, поэтому число плохо кодящих или вообще не кодящик выросло во много, много раз.</content><link rel='replies' type='application/atom+xml' href='http://tiaquenes.blogspot.com/feeds/8762916400269974294/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://tiaquenes.blogspot.com/2011/01/blog-post.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4163717651209599087/posts/default/8762916400269974294'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4163717651209599087/posts/default/8762916400269974294'/><link rel='alternate' type='text/html' href='http://tiaquenes.blogspot.com/2011/01/blog-post.html' title='Программисты не умеют программировать'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4163717651209599087.post-6394499189891530339</id><published>2011-01-13T13:18:00.000-08:00</published><updated>2011-01-13T13:23:49.547-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="dev"/><category scheme="http://www.blogger.com/atom/ns#" term="dsl"/><category scheme="http://www.blogger.com/atom/ns#" term="lisp"/><category scheme="http://www.blogger.com/atom/ns#" term="python"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><category scheme="http://www.blogger.com/atom/ns#" term="костыли"/><title type='text'>Python. Хочу DSL.</title><content type='html'>Многие рубисты, джависты, лиспофанаты etc очень любят говорить о DSL.&lt;br /&gt;
Что такое DSL? Почитайте в википедии, гугле или ещё где. Если говорить коротко, то это специфичные для определённой задачи языки, которые отбрасывают сложности в описании и решении задачи.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: python; gutter: true; highlight: []&quot;&gt;create page
   name &#39;Hey&#39;
   date 11-01-2011
   text &#39;How about new DSL?&#39;
&lt;/pre&gt;&lt;br /&gt;
Не правда ли красиво? Ну это всяко красивее аналога на чистом питоне. Похоже на yaml, но одного yaml&#39;а здесь явно не хватит, нужна поддержка функций, интерпретация, более глубокая семантика. На руби такой код составить будет не сложно. Это практически валидный руби-код.&lt;br /&gt;
Конечно, на руби точно такой код не получить. Добавится end, дату нужно будет иначе описывать...&lt;br /&gt;
&lt;br /&gt;
На питоне это можно оформить так:&lt;br /&gt;
&lt;pre class=&quot;brush: python; gutter: true; highlight: []&quot;&gt;p = Page()
p.name = &#39;Hey&#39;
p.date = &#39;11-01-2011&#39; или datetime.datetime.from....
p.text = &#39;How about new DSL?&#39;
&lt;/pre&gt;&lt;br /&gt;
Ужас, не так ли? Голая логика, строгость и КОДИНГ. Можно и иначе, с помощью with. Однако, нужно будет описывать __enter__, __exit__, что заставит наш код быть ориентированным на работу с этим оператором, что излишне.&lt;br /&gt;
&lt;br /&gt;
Увы, на питоне нет средств для написания DSL. Или есть?&lt;br /&gt;
&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
Прежде всего, DSL бывают разные. Внутренние(internal) и внешние(external). Оба типа DSL являются относительными.&lt;br /&gt;
&lt;br /&gt;
Грубо говоря, &lt;b&gt;внутренние&lt;/b&gt; - сделанные средствами самого языка, используемые внутри самого языка. Типичные DSL на руби и лиспе(я промолчу на счёт джавы, ибо не изучал этот вопрос на ней) являются внутренними DSL, которые строятся через дополнение синтаксиса средствами самого языка. Фактически, в лиспе это не является дополнением синтаксиса, как и в руби. Просто добавление ключевых слов, функций, логики... Словом, просто пляски вокруг синтаксиса, используя возможности самого же языка. Язык сильно ограничивает возможности по создания внутреннего DSL.&lt;br /&gt;
Примерами внутренних DSL являются десятки DSL для Ruby on Rails, огромное число пакетов тестирования для руби, питона, HAML, SASS, CleverCSS, десятки диалектов лиспа etc.&lt;br /&gt;
В наше время каждый современный программист использовал DSL или хоть пробовал данную идею.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Внешние DSL&lt;/b&gt; - язык, созданный &quot;в лоб&quot;. Для него делается свой интерпретатор/компилятор, синтаксический парсер etc. К таким языкам часто относятся языки темплейтов в веб-фреймворках. По сути, это изобретения велосипеда. Mako(язык темплейтов, так популярный в веб-фреймворке Pylons), например, является транслятором в Python. Да-да, код транслируется в код на питоне(а точнее, в один модуль с одной функцией).&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;Чаще всего выходит так, что для одной цели, где нужен внутренний DSL, задача решается &quot;в лоб&quot; из-за незнания или иных проблем. Это приводит к созданию нового языка со своими конструкциями. Не редко язык получается уродливым, да и задача решается не так как хотелось бы. Ладно если язык компилируемый, но если он интерпретируемый, то это создаёт оверхед(во всех аспектах программирования) такого размера, что выть хочется.&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
Ладно, давайте ближе к делу, а именно, к DSL на Python.&lt;br /&gt;
&lt;br /&gt;
В Питоне нет функционала для создания DSL. Гвидо официально пофиг(ищите списки рассылок, вопрос поднимался много раз, но темы всегда заминали). Более того, язык перестал развиваться. Однако, он всё ещё является лучшим языком, с явно бОльшим будущем чем у руби. Почему? Py3k с каждым релизом становится всё быстрее и быстрее. Хотя хватит рекламы. CPython 3 всё-равно говно, но лучше нет.&lt;br /&gt;
У Питона пока 2 проблемы:&lt;br /&gt;
1) Замороженный синтаксис(да, он просто уже не развивается).&lt;br /&gt;
Более того, в тройке он деградировал(вроде отсутствия &quot;%&quot;).&lt;br /&gt;
2) Плохая реализация(да, она просто говно).&lt;br /&gt;
Все надежды на PyPy, Unladen Swallow, но первый пилят уже слишком долго, а второй хотят прикрыть, т.к. не подходит для гугла.&lt;br /&gt;
&lt;br /&gt;
А ещё есть джава. А ещё есть эрланг. А ещё есть лисп.&lt;br /&gt;
Но есть только один достаточно хороший для 2010ого(а уже 2011ый!) года - Python.&lt;br /&gt;
&lt;br /&gt;
Ладно, это уже может пахнуть фанатизмом, &lt;b&gt;нам нужен DSL&lt;/b&gt;! Мы хотим сделать Python совершенным, а для этого нужно просто &lt;b&gt;получить возможность делать DSL&lt;/b&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-size: xx-small;&quot;&gt;, сделать блоки кода объектами, убрать подчёркивания в некоторых методах, сделать приватные члены не через подчёркивание...&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Гугл сразу даёт массу ссылок на инструменты по созданию external DSL: PyParsing, Ply, PySEG, Pysec... Их действительно &lt;a href=&quot;http://nedbatchelder.com/text/python-parsers.html&quot;&gt;много&lt;/a&gt;.&lt;br /&gt;
Если бы я делал свой язык, то я бы использовал что-то из этого списка, но для DSL это всё не может подходить(не для таких DSL, которые нам нужны).&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;А что нам нужно?&lt;/b&gt;&lt;br /&gt;
Добавить пару своих операторов, обрабатывающих операнды через нашу логику.&lt;br /&gt;
Добавить пару спец. символов.&lt;br /&gt;
Немного изменить логику работы со стандартными типами(обернуть строки в наш специальный класс, например).&lt;br /&gt;
Получить возможность как можно более простого описания DSL, который будет справляться с такими задачами.&lt;br /&gt;
etc.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Чего мы не хотим?&lt;/b&gt;&lt;br /&gt;
Писать свой язык.&lt;br /&gt;
Копаться в кишках чего-то.&lt;br /&gt;
Изучать лексеры.&lt;br /&gt;
Превышать среднюю концентрацию символов &quot;_&quot; более чем на 2 символа на 3 строчки кода(шутка, хоть и есть доля правды).&lt;br /&gt;
Создавать оверхед, рантаймовый препроцессор или что-то в этом духе.&lt;br /&gt;
etc.&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;&lt;b&gt;А сейчас важная деталь&lt;/b&gt;, которая необходима для понимания смысла DSL, что это такое, зачем это всё: Питон это ТОЖЕ DSL; любое небольшое вмешательство позволяет говорить что ты сделал свой DSL.&lt;br /&gt;
Почитайте вот &lt;a href=&quot;http://mail.python.org/pipermail/python-list/2010-July/1250766.html&quot;&gt;это письмо из рассылки&lt;/a&gt;, в котором есть информация о том, как в питоне &quot;реализованы&quot; DSL.&lt;br /&gt;
В письме есть ссылка на &lt;a href=&quot;http://www.python.org/doc/essays/graphs/&quot;&gt;&quot;DSL для графов&quot;&lt;/a&gt;. &lt;br /&gt;
На самом деле там нет ни слова о DSL, но указывается на удобство Питона для таких задач.&lt;br /&gt;
А ещё там замечательная ссылка на &lt;a href=&quot;http://us.pycon.org/2010/tutorials/jensen_languages/&quot;&gt;туториал с пикона&lt;/a&gt;. Но, как и все туториалы с пикона, демонстрации, показы, презентации etc, их можно увидеть только один раз. Передаю струйку рака в сторону кодеров, которые не заботятся о том, чтобы их презентации были выложены в сеть.&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
Ладно, хватит о мелочах, о частностях. У нас есть цель, задача, а самое главное - вот такой вот интересный &lt;b&gt;Я&lt;/b&gt;, который покажет вам что можно юзать для таких задач.&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;К слову, есть &lt;a href=&quot;http://be.groovie.org/post/296349003/is-rails-a-dsl-what-is-a-dsl-and-is-it-possible-in&quot;&gt;мнение&lt;/a&gt;, что DSL делается безумно просто и на Питоне, ровно как и на Руби. Однако, нет примеров, но есть такие слова как &quot;Zope&quot;, &quot;Django&quot;, &quot;TG2&quot;. Да, в них есть DSL&#39;и, но они относятся к мелким добавкам к основному языку. Ничего интересного.&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
Ладно, я слишком много рассуждал, тянул время, заставлял ждать. Думаю, вы готовы.&lt;br /&gt;
&lt;br /&gt;
http://fmeyer.org/en/writing-a-DSL-with-python.html&lt;br /&gt;
&lt;br /&gt;
Наверно, самый красивый вариант написания DSL на Питоне. Самый красивый, костыльный, простой, идеально подходящий.&lt;br /&gt;
Пока точно не могу сказать что именно его буду использовать, но, как мне кажется, лучше не найду решения.&lt;br /&gt;
&lt;br /&gt;
Для начала, вот живой код, который должен, будет работать:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: python; gutter: true; highlight: []&quot;&gt;# coding: pyspec
class Bow:
    def shot(self):
        print &quot;got shot&quot;

    def score(self):
        return 5

describe Bowling:
    it &quot;should score 0 for gutter game&quot;:
        bowling = Bow()
        bowling.shot()
        assert that bowling.score.should_be(5)
&lt;/pre&gt;&lt;br /&gt;
&lt;i&gt;А теперь небольшое отступление.&lt;br /&gt;
Помните что нужно делать, чтобы код на питоне воспринимался как utf8? Так вот, это не магия, это большая система, которая хорошо продумана. Называется она &quot;кодеки&quot;.&lt;br /&gt;
Благодаря наличию такой системы, мы можем получить доступ к &lt;b&gt;ТОКЕНАЙЗЕРУ&lt;/b&gt; Питона, к ридеру кода! Мы можем управлять тем, как код понимается компилятором в pyc и интерпретатором! Да-да! &lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
Обратите внимание на первую строчку кода. Мы указываем что хотим использовать несуществующий кодек - кодек, который мы напишем. Именно этот кодек позволит обрабатывать нестандартные операторы, изменять логику работы.&lt;br /&gt;
&lt;br /&gt;
Весь код реализации можно смотреть по ссылке выше, нам же интересно то, что мы будем писать сами и понять как это всё работает.&lt;br /&gt;
&lt;br /&gt;
Структура кодека содержит поля: name, encode, decode, incrementalencoder, incrementaldecoder, streamreader, streamwriter. Нам важно только одно - переписать streamreader чтобы можно было задействовать свои хуки.&lt;br /&gt;
Собственно, все действия сводятся к созданию хендлера для поиска кодека, в котором мы возвращаем наш новый кодек, если имя совпадает. Кодек создаём передавая все поля как у utf8-кодека, но вот streamreader мы делаем свой.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: python; gutter: true; highlight: []&quot;&gt;import tokenize
import codecs, cStringIO, encodings
from encodings import utf_8

class StreamReader(utf_8.StreamReader):
        def __init__(self, *args, **kwargs):
            codecs.StreamReader.__init__(self, *args, **kwargs)
            data = tokenize.untokenize(translate(self.stream.readline))
            self.stream = cStringIO.StringIO(data)
&lt;/pre&gt;&lt;br /&gt;
Пример не самый красивый, но стоит того, чтобы его прокомментировать.&lt;br /&gt;
Про модуль токенайзера можете прочитать в доках, если что.&lt;br /&gt;
Мы создаём функцию translate, которая является генератором строк, которые берутся из генератора же(stream.realline).&lt;br /&gt;
Мы берём оригинальный поток строк, передаём его в нашу функцию, обёртываем в токенайзер и ставим это на место старого стрима. Получается что-то вроде:&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote&gt;поток из файла -&gt; (токенайзер -&gt; наш транслятор) -&gt; валидные питонотокены -&gt; интерпретатор/компилятор&lt;/blockquote&gt;&lt;br /&gt;
Вот как будет выглядеть наш &quot;транслятор&quot;:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: python; gutter: true; highlight: []&quot;&gt;def method_for_it(token):
    return token.strip().replace(&quot; &quot;, &quot;_&quot;).replace(&quot;\&quot;&quot;,&quot;&quot; ) + &quot;(self)&quot;
 
def translate(readline):
    previous_name = &quot;&quot;
    for type, name,_,_,_ in tokenize.generate_tokens(readline):
        if type ==tokenize.NAME and name ==&#39;describe&#39;:
            yield tokenize.NAME, &#39;class&#39;
        elif type ==tokenize.NAME and name ==&#39;it&#39;:
            yield tokenize.NAME, &#39;def&#39;
        elif type == 3 and previous_name == &#39;it&#39;:
            yield 3, method_for_it(name)
        else:
            yield type,name
        previous_name = name
&lt;/pre&gt;&lt;br /&gt;
Возможно, это не самый красивый вариант, который можно придумать, но какой есть и можно использовать.&lt;br /&gt;
На днях попробую сделать небольшой инструмент для создания DSL используя кодеки.&lt;br /&gt;
&lt;br /&gt;
А теперь давайте посмотрим на pros/cons этого метода.&lt;br /&gt;
+ Возможность написания внутренних DSL.&lt;br /&gt;
+ Возможность изменять готовое, а не писать с нуля.&lt;br /&gt;
+ Возможность использовать всё тот же питон.&lt;br /&gt;
+ Отсутствие необходимости писать всё и вся с нуля.&lt;br /&gt;
+ Использование родного, встроенного в Пайтон функционала.&lt;br /&gt;
+/- Гибкость. Не самый гибкий метод, но позволяет делать многие вещи, которые нельзя в руби.&lt;br /&gt;
- Работа по принципу &quot;read&amp;replace&quot;. Мы работаем со строками!&lt;br /&gt;
- Слабый дебаг. Велика вероятность что если будет ошибка, то её сложно будет найти, т.к. питон будет выкидывать пост-парсинговый код, а не код на DSL.&lt;br /&gt;
- Сложность описания DSL.&lt;br /&gt;
- Необходимость описания небольшой, более удобной обёртки.&lt;br /&gt;
- ЭТО КОСТЫЛЬ! Кодеки не для этого предназначены.&lt;br /&gt;
&lt;br /&gt;
В любом случае, лучше варианта нет, а если использовать активно и пропагандировать, то можно будет надеяться что Гвидо прогнётся под коммьюнити и даст нам хороший инструмент.&lt;br /&gt;
&lt;br /&gt;
В заключение хочется вбросить одну ссылку на интересную мысль на счёт DSL на Пайтоне, а точнее на применение DSL для ORM на Пайтоне.&lt;br /&gt;
&lt;a href=&quot;http://blog.ianbicking.org/more-on-python-metaprogramming.html&quot;&gt;http://blog.ianbicking.org/more-on-python-metaprogramming.html&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://tiaquenes.blogspot.com/feeds/6394499189891530339/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://tiaquenes.blogspot.com/2011/01/python-dsl.html#comment-form' title='Комментарии: 3'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4163717651209599087/posts/default/6394499189891530339'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4163717651209599087/posts/default/6394499189891530339'/><link rel='alternate' type='text/html' href='http://tiaquenes.blogspot.com/2011/01/python-dsl.html' title='Python. Хочу DSL.'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4163717651209599087.post-2404160027221216479</id><published>2010-12-29T17:14:00.000-08:00</published><updated>2010-12-29T17:18:02.332-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="dev"/><category scheme="http://www.blogger.com/atom/ns#" term="django"/><category scheme="http://www.blogger.com/atom/ns#" term="pylons"/><category scheme="http://www.blogger.com/atom/ns#" term="pyramid"/><category scheme="http://www.blogger.com/atom/ns#" term="python"/><category scheme="http://www.blogger.com/atom/ns#" term="ror3"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><category scheme="http://www.blogger.com/atom/ns#" term="twisted"/><category scheme="http://www.blogger.com/atom/ns#" term="webdev"/><title type='text'>Python, Ruby. Официальная™ точка зрения Iorlas&#39;а.</title><content type='html'>К данному посту побудил тред на лоре:&lt;br /&gt;
&lt;a href=&quot;http://www.linux.org.ru/forum/development/5735572&quot;&gt;http://www.linux.org.ru/forum/development/5735572&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Так много текста написал и не хочется чтобы он пропадал.&lt;br /&gt;
&lt;br /&gt;
Сейчас вокруг Пайтона сложились 2 основных стереотипа:&lt;br /&gt;
1) Самый тормозной язык на свете&lt;br /&gt;
2) Джанго - хороший веб-фреймворк&lt;br /&gt;
&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Мнение о производительности пайтона сложилось из таких проектов как Gajim, Rhytmbox, Banshi(или какие там ещё есть поделки). Опыт данных поделий показывает, что пайтон(как и любой высокоуровневый язык) плохо подходит для написания ресурсоёмкой и требовательной к производительности логики(писать приложение на сложной высокопроизводительной сетевой библиотеке - да, писать сложную высокопроизводительную сетевую библиотеку - нет(намёк на твистед, который написан на Си как модуль для пайтона, но используется для приложений на пайтоне)).&lt;br /&gt;
Однако, стоит заметить, что даже лёгкую логику, используя Си, можно написать так, что оно будет работать очень медленно(transmission).&lt;br /&gt;
Вывод: на пайтоне нужно уметь писать, а не слепо использовать технологию.&lt;br /&gt;
&lt;br /&gt;
Джанго - самый развитый веб-фреймворк на пайтоне, имеющий самую большую публику среди веб-фреймворков на пайтоне же. Просто он самый простой из веб-фреймворков на питоне и, как говорят некоторые люди, стремится быть аналогом RoR(что совсем не так, а даже если бы и было так, то получается оно отвратно, совсем не получается). Джанго тормозит, страдает неоднозначностью(что ласково называется &quot;возможностью выполнить одну вещь многими путями&quot;, но это не RoR, здесь это неудачно, очень неудачно), имеет много костылей, неудачные реализации простых вещей и ORM, который хоть и работает быстрее SQLAlchemy, но является страшным гогном.&lt;br /&gt;
&lt;br /&gt;
Какое истинное лицо Python?&lt;br /&gt;
В первую очередь, это язык для создания скриптов, десктопных приложений, микро веб-приложений, больших (веб)приложений, требовательных к производительности.&lt;br /&gt;
Скрипты - понятно, очень удобно, большая стандартная библиотека, куча возможностей, простой и понятный синтаксис.&lt;br /&gt;
Десктопные приложения. Поскольку написание приложений используя GTK, Qt etc на пайтоне - очень простое дело, есть куча биндингов к либам, возможность простого написания логики на Си и использования её на более высоком уровне на питоне, питон является очень хорошим языком для такой цели.&lt;br /&gt;
Микро веб-приложения это приложения, в которых нет нужды в большой логике, где нужно чтобы всё работало искаропки или просто не требовало таскать за собой кучу файлов для небольшого приложения. Самый популярный пример - WebPy. Много кто его использует, есть даже люди, которые используют его для сложной логики, что является бредом и фанатизмом. Идеальный пример микро веб-приложения - веб-гуй для rtorrent(увы, никому нет дела, но решение было бы хорошим, лучше чем на пехапе).&lt;br /&gt;
Большие (веб)приложения. За счёт того, что узкие места можно написать на Си, а управлять ими на Пайтоне, можно использовать данный язык для крупных приложений, используя высокоуровневый язык для высокого уровня проекта. Это позволило родиться таким веб-фреймворкам как Werkzeug, Pylons, Pyramid etc. Они достаточно просты, динамичны, имеют простую внутреннюю логику, позволяют делать что хочется с любой частью веб-приложения. К таким фреймворкам относятся и Twisted, и Tornado.&lt;br /&gt;
&lt;br /&gt;
Для средних и небольших проектов использовать пайтон слишком сложно и просто не окупается. Проще использовать руби и рельсы.&lt;br /&gt;
&lt;br /&gt;
Я сам использую и руби, и пайтон, и си. У меня есть опыт в использовании и джанго, и рельс, и пайлонс, и пирамид, и твистед, и даже немного PHP с симвонией, зендом, друпалом. Я хорошо взвесил все за и против, хорошо исследовал враждующие технологии и сделал выводы(они описаны выше). Я не защищаю инструменты, я просто говорю какие выводы сделал я, я просто говорю что они совпадают со мнениями опытных программистов, я просто делюсь точкой зрения. Хочешь - прими её, хочешь - нет.&lt;br /&gt;
Забавно будет посмотреть на тех, кто сможет назвать меня троллем или фанатиком, поскольку я не использую то, что мне же хуже, а значит я выбираю как можно более подходящие инструменты для своих задач.</content><link rel='replies' type='application/atom+xml' href='http://tiaquenes.blogspot.com/feeds/2404160027221216479/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://tiaquenes.blogspot.com/2010/12/python-ruby-iorlas.html#comment-form' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4163717651209599087/posts/default/2404160027221216479'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4163717651209599087/posts/default/2404160027221216479'/><link rel='alternate' type='text/html' href='http://tiaquenes.blogspot.com/2010/12/python-ruby-iorlas.html' title='Python, Ruby. Официальная™ точка зрения Iorlas&#39;а.'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4163717651209599087.post-6577162989032503127</id><published>2010-12-29T06:33:00.000-08:00</published><updated>2011-01-19T06:55:59.099-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="intellij idea"/><category scheme="http://www.blogger.com/atom/ns#" term="jetbrains"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><category scheme="http://www.blogger.com/atom/ns#" term="rubymine"/><title type='text'>RubyMine, PyCharm и всё что построено на IDEA/Swing. Некролог.</title><content type='html'>Несколько раз я пробовал это чудо. Надо сказать что по функционалу это фантастика, везде хвалят, любят, пользуют(хотя из знакомых есть всего 2 любителя IDEA, и те юзают PyCharm).&lt;br /&gt;
Цель сегодняшней попытки - добить это дело, довести RubyMine до &quot;совершенства&quot; и определить можно ли его использовать.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;В первые свои попытки завести PyCharm и RubyMine, я столкнулся с проблемой рендерринга окон IDEA. Это было просто серое окно:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlN2u0kSTF564T22vnNvN8iCe9s5i6glS7x1ZI-iKAvkQVNCDYyw-z6DTmmrWdh8eO7WhrxvJiaZG0VIMl-Bwtf33bIAEG8MW_2q8JwXxbbfOGJQYVk9e9xFhPwPrHAvhrF1uNSQaZP8U7/s1600/rubyminefail.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;256&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlN2u0kSTF564T22vnNvN8iCe9s5i6glS7x1ZI-iKAvkQVNCDYyw-z6DTmmrWdh8eO7WhrxvJiaZG0VIMl-Bwtf33bIAEG8MW_2q8JwXxbbfOGJQYVk9e9xFhPwPrHAvhrF1uNSQaZP8U7/s320/rubyminefail.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Гуглить по признакам было не легко, но в конце концов я дошёл до нужной ссылки:&lt;br /&gt;
&lt;a href=&quot;https://awesome.naquadah.org/wiki/Problems_with_Java&quot;&gt;https://awesome.naquadah.org/wiki/Problems_with_Java&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Суть в чём: Awesome является одним из менеджеров окон, который не поддерживает &lt;a href=&quot;http://en.wikipedia.org/wiki/Re-parenting_window_manager&quot;&gt;re-parenting&lt;/a&gt;. Обидно, но не очень.&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;К слову, данная проблема не подтверждена на Java 1.7. Я использую Java HotSpot 64-Bit Server VM 1.6, где данная проблема широко известна.&lt;/i&gt;&lt;br /&gt;
&lt;i&gt;&lt;br /&gt;
&lt;/i&gt;&lt;br /&gt;
Официально это считается багом, но Sun так и не удосужились пофиксить его(хотя, по ссылкам на багрепорты есть отчёты за 2008ой год, что фиксы есть и они применены, но хз).&lt;br /&gt;
Поэтому вендорам дистрибутивов пришлось самим вставлять патчи, которые активируются при добавлении ключа для JVM:&lt;br /&gt;
&lt;blockquote&gt;_JAVA_AWT_WM_NONREPARENTING=1; export _JAVA_AWT_WM_NONREPARENTING&lt;/blockquote&gt;Увы, не везде данный патч есть, поэтому есть иной вариант.&lt;br /&gt;
Дело в том, что Sun сами попали в свои грабли. Как? Очень просто. Дело в том, что у них есть своя WM, которая не поддерживает re-parenting - LG3D. Поэтому в Swing были встроены механизмы для определения WM и использования Swing как нужно для верного отображения на ней.&lt;br /&gt;
Нужно всего то дать приложению думать что у нас LG3D.&lt;br /&gt;
&lt;blockquote&gt;wmname LG3D &amp;amp;&amp;amp; ./rubymine.sh&lt;/blockquote&gt;&lt;i&gt;wmname - утилита из пакета suckless-tools.&lt;/i&gt;&lt;br /&gt;
&lt;i&gt;&lt;br /&gt;
&lt;/i&gt;&lt;br /&gt;
&lt;i&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-style: normal;&quot;&gt;После этого оно работает, запускается.&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;
&lt;i&gt;&lt;br /&gt;
&lt;/i&gt;&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEig41l8duEHi9lNTlgN0JuEcqllhZxjVze90NaeL4SASxWzi-45dK9-Vyb8PhRrwqpqq9x620dkaZqvh5fn2XW38yzamdeOes6gmegiAENs4aGWv_lcV871n2ez7VAX3oPQPe3eINTrKbg1/s1600/rmine.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;256&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEig41l8duEHi9lNTlgN0JuEcqllhZxjVze90NaeL4SASxWzi-45dK9-Vyb8PhRrwqpqq9x620dkaZqvh5fn2XW38yzamdeOes6gmegiAENs4aGWv_lcV871n2ez7VAX3oPQPe3eINTrKbg1/s320/rmine.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Первое что бросается в глаза - ШГ(да-да, шрифты - говно). Хотя, конечно, кого-то быстрее вырвет от оформления, оно здесь тоже не на много лучше чем шрифты.&lt;br /&gt;
&lt;br /&gt;
На этом я заканчивал свои приключения. Однако, в венде оно выглядит лучше, да и люди используют, значит можно сделать и лучше, не так ли?&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Helvetica Neue&#39;, Arial, Helvetica, sans-serif; font-size: large;&quot;&gt;ШГ&lt;/span&gt;&lt;br /&gt;
Правится очень просто, как и во всех &quot;жаба&quot;-приложениях:&lt;br /&gt;
&lt;blockquote&gt;-Dawt.useSystemAAFontSettings=lcd&lt;/blockquote&gt;&lt;blockquote&gt;или сразу&lt;/blockquote&gt;&lt;blockquote&gt;env _JAVA_OPTIONS=&quot;-Dawt.useSystemAAFontSettings=lcd&quot; ./rubymine.sh&lt;/blockquote&gt;Но можно и просто добавить &quot;-Dawt.useSystemAAFontSettings=lcd&quot; в файл rubymine.vmoptions в директории bin &quot;идеи&quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;Везде советуют строчку &quot;&lt;/i&gt;-Dawt.useSystemAAFontSettings=on&lt;i&gt;&quot;, но, как оказалось, оно не везде работает и проще указать сразу lcd.&lt;/i&gt;&lt;br /&gt;
&lt;i&gt;&lt;/i&gt;&lt;br /&gt;
&lt;div style=&quot;font-style: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;&lt;i&gt;&lt;br class=&quot;Apple-interchange-newline&quot; /&gt;&lt;/i&gt;&lt;/div&gt;&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Helvetica Neue&#39;, Arial, Helvetica, sans-serif; font-size: large;&quot;&gt;Оформление&lt;/span&gt;&lt;/div&gt;&lt;i&gt;Вообще, я могу посоветовать GTK+, но оформление меняется не всё, да и если и меняется, то иногда даже более уродливо становится.&lt;/i&gt;&lt;br /&gt;
Вот здесь всё... веселее.&lt;br /&gt;
Первое, что нужно понять, так это то, что в Swing(а это и есть графический тулкит, на котором построена &quot;идея&quot;) нет понятия &quot;тема оформления&quot;, но есть LAF&#39;ы (Look And Feel менеджеры): Motif, Alloy, jGoodies, GTK+ etc. Все они дают наборы уже самих тем.&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;&lt;b&gt;Небольшое отступление по поводу Swing&lt;/b&gt;&lt;/i&gt;&lt;br /&gt;
&lt;i&gt;Swing имеет массу проблем рендерринга. Основная проблема, из-за которой всё тормозит и нет смысла что-то делать ещё - метод рендерринга в Java2D. А там он делается просто: все виджеты рендерятся софтварно и откладываются в память, а затем передаются менеджеру выше(Xorg) в виде битмапы. Из-за этого как-раз и происходят проблемы во время смены темы в Swing-приложениях(например, тема не полностью меняется, потому что некоторые изображения кешированы и отдаются сразу, а не ререндерятся с новой темой оформления).&lt;/i&gt;&lt;br /&gt;
&lt;i&gt;Было много бесед на тему Java2D, но &quot;знатоки&quot; решили не трогать, так и приходится жить.&lt;/i&gt;&lt;br /&gt;
&lt;i&gt;Стоит отметить что SWT(который используется в Eclipse) лишён данной проблемы.&lt;/i&gt;&lt;br /&gt;
&lt;i&gt;&lt;br /&gt;
&lt;/i&gt;&lt;br /&gt;
Всё, казалось бы, очень просто: нужно найти хорошую тему для одной из LAF или найти хороший LAF с хорошей темой.&lt;br /&gt;
Это просто!&lt;br /&gt;
Вот есть офигенный LAF:&amp;nbsp;&lt;a href=&quot;https://substance.dev.java.net/&quot;&gt;https://substance.dev.java.net/&lt;/a&gt;&lt;br /&gt;
В 2005ом году его можно было использовать(&lt;a href=&quot;http://weblogs.java.net/blog/2005/08/09/intellij-idea-50-and-custom-look-and-feel&quot;&gt;история успеха&lt;/a&gt;), а вот сейчас уже нет. Дело в том, что IDEA:&lt;br /&gt;
1) Использует тучу собственных виджетов, которые просто не будут изменены через обычные LAF для Swing.&lt;br /&gt;
2) Использует собственные костыли-обвязки(точно сказать не могу, лучше спросить у знатоков) для стандартных LAF.&lt;br /&gt;
Я уже хотел смириться с тем, что придётся использовать тему &lt;a href=&quot;https://substance.dev.java.net/docs/skins/dark.html#GraphiteSkin&quot;&gt;Graphite&lt;/a&gt;&amp;nbsp;из состава Substance, но оказалось что и её применить не смогу из-за двух пунктов выше.&lt;br /&gt;
Я бы хотел поэкспериментировать ещё немного, но понимаю что нет смысла, ведь есть даже открытые репорты, на которые есть ответы и нет решений:&lt;br /&gt;
&lt;a href=&quot;http://youtrack.jetbrains.net/issue/PY-2032&quot;&gt;http://youtrack.jetbrains.net/issue/PY-2032&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://youtrack.jetbrains.net/issue/IDEABKL-5514&quot;&gt;http://youtrack.jetbrains.net/issue/IDEABKL-5514&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://youtrack.jetbrains.net/issue/IDEA-62247&quot;&gt;http://youtrack.jetbrains.net/issue/IDEA-62247&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://devnet.jetbrains.net/thread/289737&quot;&gt;http://devnet.jetbrains.net/thread/289737&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Собственно, на этом можно и закапывать. Ответов в репортах почти нет, а значит оно и не особо нужно людям, а тем более - нам.&lt;br /&gt;
&lt;br /&gt;
Справедливости ради стоит отметить что подсветка кода шикарная, есть &lt;a href=&quot;http://devnet.jetbrains.net/docs/DOC-1154&quot;&gt;много вариантов&lt;/a&gt;&amp;nbsp;и все шикарны.&lt;br /&gt;
&lt;br /&gt;
В принципе, меня может быть и устроит тема XP, но только в офисе.&lt;br /&gt;
Тем не менее, вот что получилось:&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiiDCFvfAFG7y5wJN91RJbzZgkXrTDi2bE5Ncpq4DIB-c6Ja-HMlFVV7nFsKL8W_WZ1H2PsjufaN-PoPX_Dm5yxSQHNaYAnmmtTIIfiA5miJIE7CeugbEim9QuJ7h7gU027PGd7LBmBoqk4/s1600/mrubyok2.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;256&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiiDCFvfAFG7y5wJN91RJbzZgkXrTDi2bE5Ncpq4DIB-c6Ja-HMlFVV7nFsKL8W_WZ1H2PsjufaN-PoPX_Dm5yxSQHNaYAnmmtTIIfiA5miJIE7CeugbEim9QuJ7h7gU027PGd7LBmBoqk4/s320/mrubyok2.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2blKtRFDsC_9mr7yHYEzvoQsQ3AeoDfPcJUtzrxa0h-cygdU-_NUde26BeEM1hXJFy_a_SAkp3Ly-yddKmqM3GRXZat6MaqOjlujqr-4fKwylIu8Z-WEU_UzyTNHR3t2ng7ybA3IH4F5z/s1600/mrubyok.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;256&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2blKtRFDsC_9mr7yHYEzvoQsQ3AeoDfPcJUtzrxa0h-cygdU-_NUde26BeEM1hXJFy_a_SAkp3Ly-yddKmqM3GRXZat6MaqOjlujqr-4fKwylIu8Z-WEU_UzyTNHR3t2ng7ybA3IH4F5z/s320/mrubyok.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEQfr_Y_kJDFmjjx5iBO_K-f7mHYgDM4SykUMQvqrhk2OTgAcVonIevGQNsQOrFtu_b2cma0tgWOxvOgA8hFfyjNbrZJIW3GcVEk2diqNgSe6-KkyRcgj2mBamDks8liw2Wx7GChz0RKxn/s1600/mrubyok3.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;256&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEQfr_Y_kJDFmjjx5iBO_K-f7mHYgDM4SykUMQvqrhk2OTgAcVonIevGQNsQOrFtu_b2cma0tgWOxvOgA8hFfyjNbrZJIW3GcVEk2diqNgSe6-KkyRcgj2mBamDks8liw2Wx7GChz0RKxn/s320/mrubyok3.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
И просто чтобы было с чем сравнивать, вот скрин полностью устраивающей Aptana Studio 3(eclipse-based):&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjifM9jB7225vpjFz4hjqfDAcqdeGDA930z41zd-I9kTe3GEwC6LiYdvmZcAGwxZsxXqnZAwVDe_shWjrsXOZ302QwnwQepEvGdq7FPGszd-AOdk7P-eSSEv0YKu9XWzHL5oZQHWUDWM56P/s1600/aptanaok.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;256&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjifM9jB7225vpjFz4hjqfDAcqdeGDA930z41zd-I9kTe3GEwC6LiYdvmZcAGwxZsxXqnZAwVDe_shWjrsXOZ302QwnwQepEvGdq7FPGszd-AOdk7P-eSSEv0YKu9XWzHL5oZQHWUDWM56P/s320/aptanaok.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tiaquenes.blogspot.com/feeds/6577162989032503127/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://tiaquenes.blogspot.com/2010/12/rubymain.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4163717651209599087/posts/default/6577162989032503127'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4163717651209599087/posts/default/6577162989032503127'/><link rel='alternate' type='text/html' href='http://tiaquenes.blogspot.com/2010/12/rubymain.html' title='RubyMine, PyCharm и всё что построено на IDEA/Swing. Некролог.'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlN2u0kSTF564T22vnNvN8iCe9s5i6glS7x1ZI-iKAvkQVNCDYyw-z6DTmmrWdh8eO7WhrxvJiaZG0VIMl-Bwtf33bIAEG8MW_2q8JwXxbbfOGJQYVk9e9xFhPwPrHAvhrF1uNSQaZP8U7/s72-c/rubyminefail.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4163717651209599087.post-5634155515900566522</id><published>2010-12-21T13:07:00.000-08:00</published><updated>2010-12-21T13:08:06.046-08:00</updated><title type='text'>Ruby. Изучение.</title><content type='html'>Здесь буду публиковать информацию о том, что я читал, изучал и сколько да на что времени ушло.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;a href=&quot;http://www.linuxshare.ru/docs/devel/languages/ruby/ruby.html&quot;&gt;http://www.linuxshare.ru/docs/devel/languages/ruby/ruby.html&lt;/a&gt;&lt;br /&gt;
~ 1 день.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://rusrails.ru/&quot;&gt;http://rusrails.ru/&lt;/a&gt;&lt;br /&gt;
Первый блок статей + деталями из других - 1 день.&lt;br /&gt;
&lt;br /&gt;
TO-DO:&lt;br /&gt;
Дочитать все блоки с русрейлс.&lt;br /&gt;
Изучить paperclip.&lt;br /&gt;
Formastic.&lt;br /&gt;
Nifty-generators.&lt;br /&gt;
Devise.&lt;br /&gt;
Cancan.&lt;br /&gt;
Active Scaffold.&lt;br /&gt;
To be free.</content><link rel='replies' type='application/atom+xml' href='http://tiaquenes.blogspot.com/feeds/5634155515900566522/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://tiaquenes.blogspot.com/2010/12/ruby_21.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4163717651209599087/posts/default/5634155515900566522'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4163717651209599087/posts/default/5634155515900566522'/><link rel='alternate' type='text/html' href='http://tiaquenes.blogspot.com/2010/12/ruby_21.html' title='Ruby. Изучение.'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4163717651209599087.post-1423287949887473678</id><published>2010-12-21T12:43:00.000-08:00</published><updated>2010-12-21T13:08:21.095-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ror"/><category scheme="http://www.blogger.com/atom/ns#" term="ror3"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><category scheme="http://www.blogger.com/atom/ns#" term="webdev"/><title type='text'>RoR3. Хорошие плагины.</title><content type='html'>Для эффективной разработки на &quot;рельсах&quot; существует масса самых разных плагинов. Иногда даже можно удивиться тому, что некоторая работа, которую ты часто повторяешь, упрощена с помощью какого-то плагина.&lt;div&gt;Вот некоторый набор плагинов, которые я нашёл в сети и планирую использовать.&lt;/div&gt;&lt;div&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;div&gt;&lt;a href=&quot;https://github.com/plataformatec/devise&quot;&gt;Devise&lt;/a&gt;&lt;/div&gt;&lt;div&gt;Это офигенная система аутентификации. Большая, сильная, удобная, хоть и не столь динамичная. Она даёт всё что нужно из коробки, а главное, поддерживает OmniAuth, что означает поддержку всех существующих систем аутентификации! OAuth, OpenID etc. Что хорошо, в OmniAuth плагины для разных систем пишутся достаточно быстро и удобно, благо идея позаимствована у Repoze.Who.&lt;/div&gt;&lt;div&gt;Возможно,&amp;nbsp;кому то не очень нравится Devise, но если хочется делать современные сайты, то альтернатив нет.&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;https://github.com/plataformatec/devise/wiki/OmniAuth:-Overview&quot;&gt;Сразу ссылка на ман для работы с OmniAuth&lt;/a&gt;&amp;nbsp;и ещё &lt;a href=&quot;http://blog.joshsoftware.com/2010/12/16/multiple-applications-with-devise-omniauth-and-single-sign-on/&quot;&gt;ссылка на статью о использовании этого &quot;в бою&quot;&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;Ну и пара скринкастов: &lt;a href=&quot;http://railscasts.com/episodes/235-omniauth-part-1&quot;&gt;один&lt;/a&gt;&amp;nbsp;и &lt;a href=&quot;http://railscasts.com/episodes/236-omniauth-part-2&quot;&gt;два&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;https://github.com/justinfrench/formtastic&quot;&gt;Formtastic&lt;/a&gt;&lt;/div&gt;&lt;div&gt;Конечно, RoR и так даёт не плохие средства для клепания форм, но не всегда хватает их возможностей. Здесь и появляется &quot;формастик&quot;. Это плагин, который упрощает создание форм до нельзя. Удобно, быстро, качественно, динамично - это всё о данном плагине.&lt;/div&gt;&lt;div&gt;Увы, конечно, это не Active Scaffold, но если нет требования в аяксе, этот плагин обязан быть в любом проекте.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;https://github.com/ryanb/nifty-generators&quot;&gt;Nifty-generators&lt;/a&gt;&lt;/div&gt;&lt;div&gt;Небольшой по функционалу плагин. Просто набор из генераторов для скаффолдинга. Стоит отметить что есть пара нужных генераторов, в числе которых генератор для обычного скаффолдинга, генерирующий сразу haml и более удобные формочки. Ещё есть генератор слоёв, который делает сразу sass.&lt;/div&gt;&lt;div&gt;Есть генератор для authlogic, но если используется Devise, то нафиг оно нужно.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://activescaffold.com/&quot;&gt;Active Scaffold&lt;/a&gt;&lt;/div&gt;&lt;div&gt;Иногда требуется применение аякса для форм и не только. Active Scaffold позволяет делать это красиво и быстро.&lt;/div&gt;&lt;div&gt;Даже нечего добавить. Хотя есть что: оно большое и сложное.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;https://github.com/thoughtbot/paperclip&quot;&gt;Paperclip&lt;/a&gt;&lt;/div&gt;&lt;div&gt;Практически любой проект требует возможности аплоада файлов. Данный плагин позволяет сделать аплоад изображений лёгким и простым делом: сам всё ресайзит, делает тамбнейлы, даёт валидатор etc.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;https://github.com/ryanb/cancan&quot;&gt;CanCan&lt;/a&gt;&lt;/div&gt;&lt;div&gt;Наверно, это лучший плагин для авторизации, который я когда-либо и где-либо видел. Да-да, он позволяет управлять группами и разрешениями пользователей. Это даже лучше чем Repoze.What.&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tiaquenes.blogspot.com/feeds/1423287949887473678/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://tiaquenes.blogspot.com/2010/12/ror3.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4163717651209599087/posts/default/1423287949887473678'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4163717651209599087/posts/default/1423287949887473678'/><link rel='alternate' type='text/html' href='http://tiaquenes.blogspot.com/2010/12/ror3.html' title='RoR3. Хорошие плагины.'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4163717651209599087.post-3556227234760918002</id><published>2010-12-20T05:27:00.000-08:00</published><updated>2010-12-20T05:27:29.798-08:00</updated><title type='text'>Список аналогов хабра у &quot;них&quot;</title><content type='html'>http://habrahabr.ru/qa/3230&lt;br /&gt;
&lt;br /&gt;
На данный момент там такие ссылки:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://slashdot.org/&quot;&gt;slashdot.org&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://readwriteweb.com/&quot;&gt;readwriteweb.com&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://engadget.com/&quot;&gt;engadget.com&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://gizmodo.com/&quot;&gt;gizmodo.com&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://techcrunch.com/&quot;&gt;techcrunch.com&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://maketecheasier.com/&quot;&gt;maketecheasier.com&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://smashingmagazine.com/&quot;&gt;smashingmagazine.com&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://techrepublic.com.com/&quot;&gt;techrepublic.com.com&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://tiaquenes.blogspot.com/feeds/3556227234760918002/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://tiaquenes.blogspot.com/2010/12/blog-post.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4163717651209599087/posts/default/3556227234760918002'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4163717651209599087/posts/default/3556227234760918002'/><link rel='alternate' type='text/html' href='http://tiaquenes.blogspot.com/2010/12/blog-post.html' title='Список аналогов хабра у &quot;них&quot;'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4163717651209599087.post-211314390384301403</id><published>2010-12-20T05:24:00.000-08:00</published><updated>2010-12-21T13:03:02.394-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="aptana"/><category scheme="http://www.blogger.com/atom/ns#" term="ror"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><category scheme="http://www.blogger.com/atom/ns#" term="webdev"/><title type='text'>Ruby. Ссылки</title><content type='html'>А здесь будут ссылка на всякое разное по руби и РоР.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Учебник по рубям. Мало, куча воды, написано для чайников, но сойдёт.&lt;br /&gt;
&lt;a href=&quot;http://www.linuxshare.ru/docs/devel/languages/ruby/ruby.html&quot;&gt;http://www.linuxshare.ru/docs/devel/languages/ruby/ruby.html&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Офигенный английский тутор по РоР&lt;br /&gt;
&lt;a href=&quot;http://railstutorial.org/&quot;&gt;http://railstutorial.org/&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Русский аналог. Очень и очень много полезного.&lt;br /&gt;
&lt;a href=&quot;http://rusrails.ru/&quot;&gt;http://rusrails.ru/&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Применение RadRails(Aptana).&lt;br /&gt;
&lt;a href=&quot;http://vimeo.com/channels/radrails&quot;&gt;http://vimeo.com/channels/radrails&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Описание деплоймента RoR в uWSGI с nginx&lt;br /&gt;
&lt;a href=&quot;http://projects.unbit.it/uwsgi/wiki/RubyOnRails&quot;&gt;http://projects.unbit.it/uwsgi/wiki/RubyOnRails&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
ActiveScafflod. Офигенная штучка, позволяющая делать всё через аякс.&lt;br /&gt;
&lt;a href=&quot;http://activescaffold.com/&quot;&gt;http://activescaffold.com/&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Гайды по RoR&lt;br /&gt;
&lt;a href=&quot;http://guides.rubyonrails.org/&quot;&gt;http://guides.rubyonrails.org/&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://tiaquenes.blogspot.com/feeds/211314390384301403/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://tiaquenes.blogspot.com/2010/12/ruby.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4163717651209599087/posts/default/211314390384301403'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4163717651209599087/posts/default/211314390384301403'/><link rel='alternate' type='text/html' href='http://tiaquenes.blogspot.com/2010/12/ruby.html' title='Ruby. Ссылки'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4163717651209599087.post-4033457672294286862</id><published>2010-12-17T16:04:00.000-08:00</published><updated>2010-12-17T16:04:37.942-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="extjs"/><category scheme="http://www.blogger.com/atom/ns#" term="sencha"/><category scheme="http://www.blogger.com/atom/ns#" term="webdev"/><title type='text'>ExtJS(Sencha). Ссылки</title><content type='html'>С чего начать.&lt;br /&gt;
&lt;a href=&quot;http://www.sencha.com/learn/Tutorial:Ext_StartUp_Guide&quot;&gt;http://www.sencha.com/learn/Tutorial:Ext_StartUp_Guide&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Создание и управление темами&lt;br /&gt;
&lt;a href=&quot;http://www.sencha.com/products/js/themes.php&quot;&gt;http://www.sencha.com/products/js/themes.php&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Валидаторы:&lt;br /&gt;
Дополнительные VTypes(валидаторы):&amp;nbsp;&lt;a href=&quot;http://kubuskus.blogspot.com/2009/01/some-of-extjs-vtypes.html&quot;&gt;http://kubuskus.blogspot.com/2009/01/some-of-extjs-vtypes.html&lt;/a&gt;&lt;br /&gt;
Пример с валидаторами:&amp;nbsp;&lt;a href=&quot;http://dev.sencha.com/deploy/dev/examples/form/adv-vtypes.html&quot;&gt;http://dev.sencha.com/deploy/dev/examples/form/adv-vtypes.html&lt;/a&gt;&lt;br /&gt;
Обычные валидаторы:&amp;nbsp;&lt;a href=&quot;http://blog.adampresley.com/2008/advanced-data-validation-using-extjs/&quot;&gt;http://blog.adampresley.com/2008/advanced-data-validation-using-extjs/&lt;/a&gt;&lt;br /&gt;
ReCaptcha:&amp;nbsp;&lt;a href=&quot;http://abrdev.com/?p=775&quot;&gt;http://abrdev.com/?p=775&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
ExtJS для jQuery-разработчиков.&lt;br /&gt;
&lt;a href=&quot;http://www.ajaxray.com/blog/2009/04/05/extjs-quick-start-guide-for-jquery-developers-javascript-howto/&quot;&gt;http://www.ajaxray.com/blog/2009/04/05/extjs-quick-start-guide-for-jquery-developers-javascript-howto/&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://tiaquenes.blogspot.com/feeds/4033457672294286862/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://tiaquenes.blogspot.com/2010/12/extjssencha.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4163717651209599087/posts/default/4033457672294286862'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4163717651209599087/posts/default/4033457672294286862'/><link rel='alternate' type='text/html' href='http://tiaquenes.blogspot.com/2010/12/extjssencha.html' title='ExtJS(Sencha). Ссылки'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4163717651209599087.post-23004164757571558</id><published>2010-12-17T15:38:00.000-08:00</published><updated>2010-12-20T05:30:52.399-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="css"/><category scheme="http://www.blogger.com/atom/ns#" term="html"/><category scheme="http://www.blogger.com/atom/ns#" term="ie"/><category scheme="http://www.blogger.com/atom/ns#" term="webdev"/><title type='text'>WebDev. Хинты для вебдева</title><content type='html'>Офигенный мастер для border-image из CSS3. Помогает выбрать параметры в css для лучшего стыка изображения. Есть предпросмотр!&lt;br /&gt;
&lt;a href=&quot;http://border-image.com/&quot;&gt;http://border-image.com&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Самый лучший и полный рецепт стики-футера.&lt;br /&gt;
&lt;a href=&quot;http://www.cssstickyfooter.com/&quot;&gt;http://www.cssstickyfooter.com/&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Фреймворк фиксов для IE6. Не такой и большой функционал, но есть что использовать.&lt;br /&gt;
&lt;a href=&quot;http://css3pie.com/&quot;&gt;http://css3pie.com/&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
CSS-фреймворк. Создан быть объект-ориентированным, но на деле не так и полезно.&lt;br /&gt;
&lt;a href=&quot;https://github.com/stubbornella/oocss&quot;&gt;https://github.com/stubbornella/oocss&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Хороший шаблон для написания приложений на HTML5.&lt;br /&gt;
&lt;a href=&quot;http://html5boilerplate.com/&quot;&gt;http://html5boilerplate.com/&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
PNG htc fix&lt;br /&gt;
&lt;a href=&quot;http://www.twinhelix.com/css/iepngfix/demo/&quot;&gt;http://www.twinhelix.com/css/iepngfix/demo/&lt;/a&gt;&lt;br /&gt;
(сдвигает некоторые пикчи на 10 пикселей вниз)&lt;br /&gt;
&lt;br /&gt;
Хинт для задания минимальной ширины страницы при блочной верстке.&lt;br /&gt;
&lt;pre class=&quot;brush: css; ruler: false; gutter: true;&quot;&gt;#wrapper {
    width: expression((documentElement.clientWidth||document.body.clientWidth)&amp;lt;1000?&#39;1000px&#39;:&#39;&#39;); /*Internet Explorer &amp;lt;= 6.0 */
    min-width: 1000px; /* Opera &amp;amp; FireFox &amp;amp; Safari &amp;amp; Google Chrome &amp;amp; Internet Explorer 7+ */
}
&lt;/pre&gt;&lt;pre class=&quot;brush: css; ruler: false; gutter: true;&quot;&gt;&lt;/pre&gt;&lt;br /&gt;
Таблица дивов через список.&lt;br /&gt;
http://www.positioniseverything.net/explorer/escape-floats.html&lt;br /&gt;
&lt;br /&gt;
Вводная по CSS&lt;br /&gt;
http://ru.html.net/tutorials/css/lesson1.php</content><link rel='replies' type='application/atom+xml' href='http://tiaquenes.blogspot.com/feeds/23004164757571558/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://tiaquenes.blogspot.com/2010/12/webdev.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4163717651209599087/posts/default/23004164757571558'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4163717651209599087/posts/default/23004164757571558'/><link rel='alternate' type='text/html' href='http://tiaquenes.blogspot.com/2010/12/webdev.html' title='WebDev. Хинты для вебдева'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4163717651209599087.post-4483317046480611344</id><published>2010-12-16T08:50:00.000-08:00</published><updated>2010-12-16T09:56:50.874-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="css"/><category scheme="http://www.blogger.com/atom/ns#" term="fonts"/><category scheme="http://www.blogger.com/atom/ns#" term="google"/><category scheme="http://www.blogger.com/atom/ns#" term="html"/><category scheme="http://www.blogger.com/atom/ns#" term="вёрстка"/><title type='text'>CSS. Шрифты</title><content type='html'>Ребята, запомните наконец список шрифтов в вебе, который можно использовать:&lt;br /&gt;
&lt;br /&gt;
&lt;table border=&quot;0&quot; cellpadding=&quot;5&quot; cellspacing=&quot;5&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;span style=&quot;font-family: Arial; font-size: medium;&quot;&gt;Arial&lt;/span&gt;&lt;/td&gt;&lt;td&gt;face=&quot;Arial&quot;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;span style=&quot;font-family: &#39;Arial Black&#39;; font-size: medium;&quot;&gt;Arial&lt;/span&gt;&lt;/td&gt;&lt;td&gt;face=&quot;Arial Black&quot;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;span style=&quot;font-family: &#39;Comic Sans MS&#39;; font-size: medium;&quot;&gt;Comic Sans MS&lt;/span&gt;&lt;/td&gt;&lt;td&gt;face=&quot;Comic Sans MS&quot;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;; font-size: medium;&quot;&gt;Courier New&lt;/span&gt;&lt;/td&gt;&lt;td&gt;face=&quot;Courier New&quot;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;span style=&quot;font-family: Georgia; font-size: medium;&quot;&gt;Georgia&lt;/span&gt;&lt;/td&gt;&lt;td&gt;face=&quot;Georgia&quot;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;span style=&quot;font-family: Impact; font-size: medium;&quot;&gt;Impact&lt;/span&gt;&lt;/td&gt;&lt;td&gt;face=&quot;Impact&quot;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;span style=&quot;font-family: &#39;Times New Roman&#39;; font-size: medium;&quot;&gt;Times New Roman&lt;/span&gt;&lt;/td&gt;&lt;td&gt;face=&quot;Times New Roman&quot;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;span style=&quot;font-family: &#39;Trebuchet MS&#39;; font-size: medium;&quot;&gt;Trebuchet MS&lt;/span&gt;&lt;/td&gt;&lt;td&gt;face=&quot;Trebuchet MS&quot;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;span style=&quot;font-family: Verdana; font-size: medium;&quot;&gt;Verdana&lt;/span&gt;&lt;/td&gt;&lt;td&gt;face=&quot;Verdana&quot;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;
via&amp;nbsp;&lt;a href=&quot;http://www.irational.org/APD/cyber/htmlfont.htm&quot;&gt;http://www.irational.org/APD/cyber/htmlfont.htm&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Хинт: их должно быть 9. via&amp;nbsp;&lt;a href=&quot;http://juick.com/1112223#1&quot;&gt;Yurtaev&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Важно запомнить одно: в браузерах всегда предусматривается верная обработка данных шрифтов(спасибо ie).&lt;br /&gt;
&lt;br /&gt;
Если попе хочется больше, то используем ТОЛЬКО Google WebFonts, не нужно придумывать свои костыли и использовать сниппеты за 2002ой год. В гугле всё проверено и можно ни о чём не думать, даже о хостинге шрифтов!&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;a href=&quot;http://code.google.com/webfonts&quot;&gt;Google WebFonts&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
^ Да, вот эта ссылка ^</content><link rel='replies' type='application/atom+xml' href='http://tiaquenes.blogspot.com/feeds/4483317046480611344/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://tiaquenes.blogspot.com/2010/12/css.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4163717651209599087/posts/default/4483317046480611344'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4163717651209599087/posts/default/4483317046480611344'/><link rel='alternate' type='text/html' href='http://tiaquenes.blogspot.com/2010/12/css.html' title='CSS. Шрифты'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4163717651209599087.post-4514951617131333219</id><published>2010-12-14T19:13:00.000-08:00</published><updated>2010-12-14T19:16:27.988-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="dev"/><category scheme="http://www.blogger.com/atom/ns#" term="hints"/><category scheme="http://www.blogger.com/atom/ns#" term="python"/><title type='text'>Python. Циклические зависимости.</title><content type='html'>Если циклические ссылки(зависимости) не убрать и иначе их не избежать, то в модулях, где эти ссылки используются ТОЛЬКО в рантайме(в функциях, например), необходимо передвинуть импорт ссылки в КОНЕЦ файла.</content><link rel='replies' type='application/atom+xml' href='http://tiaquenes.blogspot.com/feeds/4514951617131333219/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://tiaquenes.blogspot.com/2010/12/python.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4163717651209599087/posts/default/4514951617131333219'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4163717651209599087/posts/default/4514951617131333219'/><link rel='alternate' type='text/html' href='http://tiaquenes.blogspot.com/2010/12/python.html' title='Python. Циклические зависимости.'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4163717651209599087.post-8842844615413680838</id><published>2010-12-14T18:53:00.000-08:00</published><updated>2010-12-14T19:06:40.985-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="c"/><category scheme="http://www.blogger.com/atom/ns#" term="cpython"/><category scheme="http://www.blogger.com/atom/ns#" term="daily shit"/><category scheme="http://www.blogger.com/atom/ns#" term="dev"/><category scheme="http://www.blogger.com/atom/ns#" term="python"/><category scheme="http://www.blogger.com/atom/ns#" term="shit"/><title type='text'>Daily Shit: Внутренности пайтона. Класс abc.</title><content type='html'>В который раз столкнулся со внутренностями CPython и получил фейспальму.&lt;br /&gt;Дело в том, что для фреймворка нам необходимо использовать интерфейсы. Сразу было понятно что abc нам не хватит, поэтому надо было что-то бОльшее. Был рассмотрен zope.interface, но не устроило то, что для имплементирывания класса нужно вызывать функцию implements в теле класса, что не очень красиво. Увы, такие вещи для многих становятся критичными во время выбора инструмента и могут послужить минусом для фреймворка в целом.&lt;br /&gt;&lt;br /&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;В общем, решили что нужно просто добавить пару декораторов к abc и несколько других умных фич.&lt;br /&gt;Первой фишкой, которую хотелось имплементировать, оказалась &quot;фишка&quot; вывода докстринга функции, которая не имплементирована, т.е. если кто-то не имплементировал фукцнию, то при запуске приложения выходит ошибка с докстрингом.&lt;br /&gt;&lt;br /&gt;Казалось бы, всё просто. Однако, эксепшн мало о чём говорит. Забавно, но эксепш даже не специального типа, а просто TypeError. Чтобы проанализировать что и как, нужно было бы посмотреть сырец модуля abc. Однако, достаточно просто грепнуть abc.py по raise чтобы понять что abc.py это не всё, а сама ошибка берётся откуда-то ещё. Оказалось что всё сложнее, что корни abc лежат в сырцах CPython.&lt;br /&gt;Греп по сырцам CPython сразу дал ответ — typeobject.c. В общем, вот что нам интересно:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;brush: cpp; ruler: false; gutter: true;&quot;&gt;&lt;br /&gt;static PyObject *&lt;br /&gt;object_new(PyTypeObject *type, PyObject *args, PyObject *kwds)&lt;br /&gt;{&lt;br /&gt;    int err = 0;&lt;br /&gt;    if (excess_args(args, kwds)) {&lt;br /&gt;        if (type-&gt;tp_new != object_new &amp;&amp;&lt;br /&gt;            type-&gt;tp_init != object_init)&lt;br /&gt;        {&lt;br /&gt;            err = PyErr_WarnEx(PyExc_DeprecationWarning,&lt;br /&gt;                       &quot;object.__new__() takes no parameters&quot;,&lt;br /&gt;                       1);&lt;br /&gt;        }&lt;br /&gt;        else if (type-&gt;tp_new != object_new ||&lt;br /&gt;                 type-&gt;tp_init == object_init)&lt;br /&gt;        {&lt;br /&gt;            PyErr_SetString(PyExc_TypeError,&lt;br /&gt;                &quot;object.__new__() takes no parameters&quot;);&lt;br /&gt;            err = -1;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    if (err &lt; 0)&lt;br /&gt;        return NULL;&lt;br /&gt;&lt;br /&gt;    if (type-&gt;tp_flags &amp; Py_TPFLAGS_IS_ABSTRACT) {&lt;br /&gt;        static PyObject *comma = NULL;&lt;br /&gt;        PyObject *abstract_methods = NULL;&lt;br /&gt;        PyObject *builtins;&lt;br /&gt;        PyObject *sorted;&lt;br /&gt;        PyObject *sorted_methods = NULL;&lt;br /&gt;        PyObject *joined = NULL;&lt;br /&gt;        const char *joined_str;&lt;br /&gt;&lt;br /&gt;        /* Compute &quot;, &quot;.join(sorted(type.__abstractmethods__))&lt;br /&gt;           into joined. */&lt;br /&gt;        abstract_methods = type_abstractmethods(type, NULL);&lt;br /&gt;        if (abstract_methods == NULL)&lt;br /&gt;            goto error;&lt;br /&gt;        builtins = PyEval_GetBuiltins();&lt;br /&gt;        if (builtins == NULL)&lt;br /&gt;            goto error;&lt;br /&gt;        sorted = PyDict_GetItemString(builtins, &quot;sorted&quot;);&lt;br /&gt;        if (sorted == NULL)&lt;br /&gt;            goto error;&lt;br /&gt;        sorted_methods = PyObject_CallFunctionObjArgs(sorted,&lt;br /&gt;                                                      abstract_methods,&lt;br /&gt;                                                      NULL);&lt;br /&gt;        if (sorted_methods == NULL)&lt;br /&gt;            goto error;&lt;br /&gt;        if (comma == NULL) {&lt;br /&gt;            comma = PyString_InternFromString(&quot;, &quot;);&lt;br /&gt;            if (comma == NULL)&lt;br /&gt;                goto error;&lt;br /&gt;        }&lt;br /&gt;        joined = PyObject_CallMethod(comma, &quot;join&quot;,&lt;br /&gt;                                     &quot;O&quot;,  sorted_methods);&lt;br /&gt;        if (joined == NULL)&lt;br /&gt;            goto error;&lt;br /&gt;        joined_str = PyString_AsString(joined);&lt;br /&gt;        if (joined_str == NULL)&lt;br /&gt;            goto error;&lt;br /&gt;&lt;br /&gt;        PyErr_Format(PyExc_TypeError,&lt;br /&gt;                     &quot;Can&#39;t instantiate abstract class %s &quot;&lt;br /&gt;                     &quot;with abstract methods %s&quot;,&lt;br /&gt;                     type-&gt;tp_name,&lt;br /&gt;                     joined_str);&lt;br /&gt;    error:&lt;br /&gt;        Py_XDECREF(joined);&lt;br /&gt;        Py_XDECREF(sorted_methods);&lt;br /&gt;        Py_XDECREF(abstract_methods);&lt;br /&gt;        return NULL;&lt;br /&gt;    }&lt;br /&gt;    return type-&gt;tp_alloc(type, 0);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;И сами методы&lt;br /&gt;&lt;pre class=&quot;brush: cpp; ruler: false; gutter: true;&quot;&gt;&lt;br /&gt;static PyObject *&lt;br /&gt;type_abstractmethods(PyTypeObject *type, void *context)&lt;br /&gt;{&lt;br /&gt;    PyObject *mod = NULL;&lt;br /&gt;    /* type itself has an __abstractmethods__ descriptor (this). Don&#39;t return&lt;br /&gt;       that. */&lt;br /&gt;    if (type != &amp;PyType_Type)&lt;br /&gt;        mod = PyDict_GetItemString(type-&gt;tp_dict, &quot;__abstractmethods__&quot;);&lt;br /&gt;    if (!mod) {&lt;br /&gt;        PyErr_Format(PyExc_AttributeError, &quot;__abstractmethods__&quot;);&lt;br /&gt;        return NULL;&lt;br /&gt;    }&lt;br /&gt;    Py_XINCREF(mod);&lt;br /&gt;    return mod;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;static int&lt;br /&gt;type_set_abstractmethods(PyTypeObject *type, PyObject *value, void *context)&lt;br /&gt;{&lt;br /&gt;    /* __abstractmethods__ should only be set once on a type, in&lt;br /&gt;       abc.ABCMeta.__new__, so this function doesn&#39;t do anything&lt;br /&gt;       special to update subclasses.&lt;br /&gt;    */&lt;br /&gt;    int res = PyDict_SetItemString(type-&gt;tp_dict,&lt;br /&gt;                                   &quot;__abstractmethods__&quot;, value);&lt;br /&gt;    if (res == 0) {&lt;br /&gt;        PyType_Modified(type);&lt;br /&gt;        if (value &amp;&amp; PyObject_IsTrue(value)) {&lt;br /&gt;            type-&gt;tp_flags |= Py_TPFLAGS_IS_ABSTRACT;&lt;br /&gt;        }&lt;br /&gt;        else {&lt;br /&gt;            type-&gt;tp_flags &amp;= ~Py_TPFLAGS_IS_ABSTRACT;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    return res;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Как видно из сырцов, abc это не что-то внешнее, это часть пайтона. Вся реализация идёт через установку объекту флага Py_TPFLAGS_IS_ABSTRACT.&lt;br /&gt;Флаг ставится только при вызове сеттера __abstractmethods__ и если value является сетом:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;brush: cpp; ruler: false; gutter: true;&quot;&gt;&lt;br /&gt;int res = PyDict_SetItemString(type-&gt;tp_dict, &quot;__abstractmethods__&quot;, value);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Самое интересное же оказалось в методе __new__, где всё делается просто как 2 копейки:&lt;br /&gt;&lt;pre class=&quot;brush: cpp; ruler: false; gutter: true;&quot;&gt;&lt;br /&gt;PyErr_Format(PyExc_TypeError,&lt;br /&gt;    &quot;Can&#39;t instantiate abstract class %s &quot;&lt;br /&gt;    &quot;with abstract methods %s&quot;,&lt;br /&gt;    type-&gt;tp_name,&lt;br /&gt;    joined_str);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Собственно, суть в том, что нужно сразу после создания конечного класса(который имплементирует функции) объявить список абстрактных функций через присваивание списка полю __abstractmethods__. Не сделали — ничего и не будет.&lt;br /&gt;А теперь о том, как работает abc сейчас:&lt;br /&gt;1) Создаётся интерфейс с метаклассом ABCMeta. В момент его создания, вызывается метод __new__ мета-класса, который обрабатывает содержимое класса и инициализирует __abstractmethods__. Тадам! Поставили флаг что данный класс — абстрактрый.&lt;br /&gt;2) Создаётся имплементация интерфейса через наследование интерфейса. Повторно вызывается метод __new__ метакласса интерфейса! Собственно, тогда и делаются все нужные чудеса.&lt;br /&gt;3) В CPython райсится эксепшн.&lt;br /&gt;Собственно, что осталось сделать — отловить эксепшн в __call__, определить какой метод не имплементирован и вывести его докстринг.&lt;br /&gt;&lt;br /&gt;Такие дела. Вот только то, как оно внутри всё устроено, мне очень не понравилось. Одно хорошо — отделались не такой большой кровью.&lt;br /&gt;&lt;br /&gt;Результаты трудов можно наблюдать среди &quot;адаптаций&quot; в agatsuma - &lt;a href=&quot;https://bitbucket.org/FeiWongReed/agatsuma/src/tip/agatsuma/adaptations/abclasses.py&quot;&gt;здесь&lt;/a&gt;.&lt;br /&gt;Если вы хотите чтобы наша версия обёртки для абстрактных классов была включена в agatsuma.commons, то можете отписать об этом в багтрекер, ибо только моего голоса не хватит чтобы образумить второго разработчика агатсумы.&lt;br /&gt;&lt;br /&gt;P.S.: Это старый документ, запощеный в juick, может где-то что-то не так.</content><link rel='replies' type='application/atom+xml' href='http://tiaquenes.blogspot.com/feeds/8842844615413680838/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://tiaquenes.blogspot.com/2010/12/daily-shit-abc.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4163717651209599087/posts/default/8842844615413680838'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4163717651209599087/posts/default/8842844615413680838'/><link rel='alternate' type='text/html' href='http://tiaquenes.blogspot.com/2010/12/daily-shit-abc.html' title='Daily Shit: Внутренности пайтона. Класс abc.'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4163717651209599087.post-8940759361560096840</id><published>2010-12-14T08:43:00.000-08:00</published><updated>2010-12-14T20:54:03.964-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="dev"/><category scheme="http://www.blogger.com/atom/ns#" term="oop"/><category scheme="http://www.blogger.com/atom/ns#" term="python"/><category scheme="http://www.blogger.com/atom/ns#" term="singleton"/><title type='text'>Python. Синглтоны.</title><content type='html'>Я занимаюсь написанием большой продуманной системой - фреймворком модульных приложений на пайтоне. Приходится использовать такие редкие в наше время паттерны проектирывания как синглтоны. Однако, пайтон не даёт готовых решений.&lt;br /&gt;Но давайте сначала посмотрим как оно сделано в других языках.&lt;br /&gt;&lt;br /&gt;В конце статьи мы дойдём до реализации синглтонов на пайтоне так, чтобы они было красиво и всех устраивало.&lt;br /&gt;&lt;br /&gt;UPD1: Реализация переписана на метаклассы. Смотри в самый низ статьи.&lt;br /&gt;UPD2: Добавлен хинт для адресации к переменным сразу через dot: Foo.name (было: Foo().name).&lt;br /&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;В разных языках синглтонами называют разные вещи, которые, в итоге, дают один и тот же результат.&lt;br /&gt;В руби, например, синглтонами зовутся объекты, к которым добавляют методы. Иначе говоря, это созданный объект, которому добавляются свойства.&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;brush: ruby; ruler: false; gutter: true; highlight: [2, 4, 9]&quot;&gt;&lt;br /&gt;a = &quot;hello&quot;&lt;br /&gt;b = &quot;goodbye&quot;&lt;br /&gt;&lt;br /&gt;def b.upcase&lt;br /&gt;    gsub(/(.)(.)/) { $1.upcase + $2 }&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;puts a.upcase #HELLO&lt;br /&gt;puts b.upcase #GoOdBye&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;via &lt;a href=&quot;http://juick.com/iorlas/1106762#7&quot;&gt;Wyldrodney&lt;/a&gt;&lt;br /&gt;Во второй строке создаётся сам объёкт, который будет синглтоном, в 4ой добавляется метод и объект становится синглтоном(только у нас в голове, конечно). В девятой строке демонстрируется как оно работает.&lt;br /&gt;Красиво? Нет/иногда. Практично? Иногда. Синглтон ли это? Нет.&lt;br /&gt;&lt;br /&gt;Однако, поддерживаются и классические одиночки, которые мы так любим в CPP, Java.&lt;br /&gt;&lt;pre class=&quot;brush: ruby; ruler: false; gutter: true; highlight: [1, 3, 9]&quot;&gt;&lt;br /&gt;require &#39;singleton&#39;&lt;br /&gt;class Test&lt;br /&gt;    include Singleton&lt;br /&gt;    def message(msg)&lt;br /&gt;        puts msg&lt;br /&gt;    end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;Test.instance.message(&#39;test&#39;)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;via &lt;a href=&quot;http://juick.com/iorlas/1106762#1&quot;&gt;Yumitsu&lt;/a&gt;&lt;br /&gt;Импортируем модуль, добавляем методы, обращаемся через получаемый член instance. Стоит обратить внимание на то, что класс уже инициализирован.&lt;br /&gt;&lt;br /&gt;В пайтоне синглтонами тоже привыкли называть нечто иное. В &quot;стеке&quot; все ссылкаются на один и тот же вопрос, а точнее &lt;a href=&quot;http://stackoverflow.com/questions/31875/is-there-a-simple-elegant-way-to-define-singletons-in-python&quot;&gt;выбранный ответ&lt;/a&gt;.&lt;br /&gt;Сама суть данного метода описана &lt;a href=&quot;http://lucumr.pocoo.org/2009/7/24/singletons-and-their-problems-in-python/&quot;&gt;здесь&lt;/a&gt;.&lt;br /&gt;Коротко говоря:&lt;br /&gt;Синглтонами в пайтоне называют модули с глобальными переменными и функциями(без классов). Своё состояние они хранят в глобальных переменных.&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;brush: python; ruler: false; gutter: true; highlight: [1, 4]&quot;&gt;&lt;br /&gt;inited = False&lt;br /&gt;&lt;br /&gt;def init(files=None):&lt;br /&gt;    global inited&lt;br /&gt;    db = MimeTypes()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Инициализируем переменные, обращаемся к ним.&lt;br /&gt;&lt;br /&gt;Однако любого программиста смутит данный способ, ровно как и способ из руби. В отличии от руби, в пайтоне нет стандартного модуля синглтонов. Поэтому, я решил что стоит сделать свой в составе библиотеки agatsuma.commons.&lt;br /&gt;&lt;br /&gt;Для начала, следует определить что такое &quot;хорошо&quot;, т.е. как мы хотим чтобы выглядело использование синглтонов.&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;brush: python; ruler: false; gutter: true; highlight: [1, 2]&quot;&gt;&lt;br /&gt;class Foo(Singleton):&lt;br /&gt;    def __init__(self, arg):&lt;br /&gt;        self.arg = arg&lt;br /&gt;        print arg, &#39;inited!&#39;&lt;br /&gt;    def test(self):&lt;br /&gt;        print self.arg&lt;br /&gt;Foo(1).test() =&gt; 1 inited!\n1&lt;br /&gt;Foo().test() =&gt; 1&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Наследуем базовый тип, который делает всё что нужно. При вызове конструктора класса, первый раз вызывается __init__, остальные разы возвращается один и тот же инстанс, который был создан с самого начала.&lt;br /&gt;В силу того, что пайтон поддерживает множественное наследование, это достаточно удобный вариант. Удобнее чем указание метакласса.&lt;br /&gt;&lt;br /&gt;Ну давайте двигаться к цели!&lt;br /&gt;Первое, что мог найти либой человек попробуя погуглить, это &lt;a href=&quot;http://ru.wikipedia.org/wiki/%D0%9E%D0%B4%D0%B8%D0%BD%D0%BE%D1%87%D0%BA%D0%B0_(%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD_%D0%BF%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F)#.D0.9F.D1.80.D0.B8.D0.BC.D0.B5.D1.80_Python&quot;&gt;статья в вики и данный код&lt;/a&gt;:&lt;br /&gt;&lt;pre class=&quot;brush: python; ruler: false; gutter: true;&quot;&gt;&lt;br /&gt;class Singleton(object):&lt;br /&gt;    obj = None                           # Атрибут для хранения единственного экземпляра&lt;br /&gt;    def __new__(cls,*dt,**mp):           # класса Singleton.&lt;br /&gt;       if cls.obj is None:               # Если он еще не создан, то&lt;br /&gt;          cls.obj = object.__new__(cls,*dt,**mp) # вызовем __new__ родительского класса&lt;br /&gt;       return cls.obj                    # вернем синглтон&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Суть: перегрузка метода __new__, который создаёт инстанс. Если инстанс есть - возвращаем его, нет - создаём.&lt;br /&gt;Вот только есть проблема.&lt;br /&gt;DeprecationWarning: object.__new__() takes no parameters&lt;br /&gt;Что это значит, почему и как, было &lt;a href=&quot;http://mail.python.org/pipermail/python-dev/2008-February/076841.html&quot;&gt;обсуждено в рассылке python-dev&lt;/a&gt;.&lt;br /&gt;&lt;blockquote&gt;The message means just what it says. :-) There&#39;s no point in calling&lt;br /&gt;object.__new__() with more than a class parameter, and any code that&lt;br /&gt;did so was just dumping those args into a black hole.&lt;br /&gt;&lt;br /&gt;The only time when it makes sense for object.__new__() to ignore extra&lt;br /&gt;arguments is when it&#39;s not being overridden, but __init__ *is* being&lt;br /&gt;overridden -- then you have a completely default __new__ and the&lt;br /&gt;checking of constructor arguments is relegated to __init__.&lt;br /&gt;&lt;br /&gt;The purpose of all this is to catch the error in a call like&lt;br /&gt;object(42) which (again) passes an argument that is not used. This is&lt;br /&gt;often a symptom of a bug in your program.&lt;br /&gt;&lt;br /&gt;--Guido&lt;/blockquote&gt;&lt;br /&gt;В общем, вики требует правки.&lt;br /&gt;Цель &quot;object.__new__(cls,*dt,**mp)&quot; - создать экземпляр класса передавая аргументы в его конструктор.&lt;br /&gt;Стоит отметить особенность пайтона: Сначала вызывается __new__, а потом, с теми же аргументами, __init__. Нет нужды передавать аргументы в object.__new__.&lt;br /&gt;&lt;br /&gt;Код становится такого вида:&lt;br /&gt;&lt;pre class=&quot;brush: python; ruler: false; gutter: true;&quot;&gt;&lt;br /&gt;class Singleton(object):&lt;br /&gt;    __instance = None&lt;br /&gt;    def __new__(cls, *a, **kwa):&lt;br /&gt;        if cls.__instance is None:&lt;br /&gt;            cls.__instance = object.__new__(cls)&lt;br /&gt;        return cls.__instance&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Однако, из предыдущей особенности становится логично что вытекает ещё одна: не важно какой инстанс был возвращён в __new__, __init__ всё-равно будет вызван.&lt;br /&gt;Я много думал о решении данной проблемы, но самое лёгкое - удаление __init__ из класса после выполнения инициализации.&lt;br /&gt;По идее, надо бы удалять его сращу после выполнения, но это мы можем сделать только в __init__, но там что-то делать будет не так красиво.&lt;br /&gt;Можно, конечно, сделать свой __init__ в синглтоне, который будет вызывать другой метод, который и будет самим конструктором.&lt;br /&gt;Например:&lt;br /&gt;&lt;pre class=&quot;brush: python; ruler: false; gutter: true;&quot;&gt;&lt;br /&gt;class Singleton(object):&lt;br /&gt;    __instance = None&lt;br /&gt;    __inited = False&lt;br /&gt;    def __new__(cls, *a, **kwa):&lt;br /&gt;        if cls.__instance is None:&lt;br /&gt;            cls.__instance = object.__new__(cls)&lt;br /&gt;        return cls.__instance&lt;br /&gt;    def __init__(self, *a, **kwa):&lt;br /&gt;        if not self.__inited and hasattr(self, &quot;_init&quot;):&lt;br /&gt;            self._init(*a, **kwa)&lt;br /&gt;            self.__inited = True&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Тогда использование будет таким:&lt;br /&gt;&lt;pre class=&quot;brush: python; ruler: false; gutter: true;&quot;&gt;&lt;br /&gt;class Foo(Singleton):&lt;br /&gt;    def _init(self, arg):&lt;br /&gt;        print arg&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Но ведь мы хотим чтобы не было отличий от обычного класса, чтобы было красиво, так?&lt;br /&gt;Последняя мысль, которая у меня появилась, это удалять __init__ при втором вызове. Собственно, вот и конечный класс синглтона.&lt;br /&gt;&lt;pre class=&quot;brush: python; ruler: false; gutter: true; highlight: [1, 5]&quot;&gt;&lt;br /&gt;nullfunc = lambda x: None&lt;br /&gt;&lt;br /&gt;class Singleton(object):&lt;br /&gt;    __instance = None&lt;br /&gt;    __init_replaced = False&lt;br /&gt;    def __new__(cls, *a, **kwa):&lt;br /&gt;        if cls.__instance is None:&lt;br /&gt;            cls.__instance = object.__new__(cls)&lt;br /&gt;            &lt;br /&gt;        elif not cls.__init_replaced:&lt;br /&gt;            cls.__init__ = nullfunc&lt;br /&gt;            cls.__init_replaced = True&lt;br /&gt;            &lt;br /&gt;        return cls.__instance&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Удалить __init__, увы, нельзя, но можно его заменить. Чтобы не менять его каждый раз, сделаем флаг(5).&lt;br /&gt;&lt;br /&gt;Однако, данный вариант грязен, не так красив и вообще может кого-то смутить своим видом.&lt;br /&gt;&lt;br /&gt;Есть и альтернативный путь - реализация через перегрузку метода __call__ метакласса синглтона.&lt;br /&gt;Дело в том, что при каждом вызове(а точнее перед) конструктора класса, вызывается метод __call__ метакласса. Да! Это то что нам нужно. Не буду томить, вот готовый код:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;brush: python; ruler: false; gutter: true;&quot;&gt;&lt;br /&gt;class SingletonMeta(type):&lt;br /&gt;    def __init__(cls, name, bases, dict):&lt;br /&gt;        super(SingletonMeta, cls).__init__(name, bases, dict)&lt;br /&gt;        cls.instance = None &lt;br /&gt;    def __call__(self,*args,**kw):&lt;br /&gt;        if self.instance is None:&lt;br /&gt;            self.instance = super(SingletonMeta, self).__call__(*args, **kw)&lt;br /&gt;        return self.instance&lt;br /&gt;&lt;br /&gt;class Singleton(object):&lt;br /&gt;    __metaclass__ = SingletonMeta&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Метакласс можно использовать когда и где хочется, но в пайтоне нельзя делать несколько метаклассов сразу, поэтому удобнее использовать во многих случаях именно наследование класса.&lt;br /&gt;&lt;br /&gt;Отдельно хочется добавить что сам метакласс был взят из &lt;a href=&quot;http://stackoverflow.com/questions/31875/is-there-a-simple-elegant-way-to-define-singletons-in-python/33201#33201&quot;&gt;поста в &quot;стеке&quot;&lt;/a&gt;, за что автору спасибо.&lt;br /&gt;&lt;br /&gt;И для самых капризных осталось добавить ещё 2 возможности:&lt;br /&gt;1) Адресация к переменным через Foo.name вместо Foo().name&lt;br /&gt;2) Вызов функций класса через Foo.name() вместо Foo().name()&lt;br /&gt;&lt;br /&gt;Первое решается просто добавлением в мета-класс перегруженного метода __getattr__:&lt;br /&gt;&lt;pre class=&quot;brush: python; ruler: false; gutter: true;&quot;&gt;&lt;br /&gt;def __getattr__(cls, name):&lt;br /&gt;    return getattr(cls(), name)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Однако, второй пункт реализовать я пока не смог. Если у вас есть идеи - с удовольствием выслушаю.&lt;br /&gt;&lt;br /&gt;Вот и всё. Есть вопросы? Задавайте здесь, в комментах.&lt;br /&gt;&lt;br /&gt;Конечный вариант можно наблюдать в &lt;a href=&quot;https://bitbucket.org/FeiWongReed/agatsuma/src/tip/agatsuma/commons/types/singleton.py&quot;&gt;сырце из пакета agatsuma.commons&lt;/a&gt;.</content><link rel='replies' type='application/atom+xml' href='http://tiaquenes.blogspot.com/feeds/8940759361560096840/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://tiaquenes.blogspot.com/2010/12/python-%D1%81%D0%B8%D0%BD%D0%B3%D0%BB%D1%82%D0%BE%D0%BD%D1%8B.html#comment-form' title='Комментарии: 6'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4163717651209599087/posts/default/8940759361560096840'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4163717651209599087/posts/default/8940759361560096840'/><link rel='alternate' type='text/html' href='http://tiaquenes.blogspot.com/2010/12/python-%D1%81%D0%B8%D0%BD%D0%B3%D0%BB%D1%82%D0%BE%D0%BD%D1%8B.html' title='Python. Синглтоны.'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4163717651209599087.post-1915137038918825934</id><published>2010-12-14T07:03:00.000-08:00</published><updated>2010-12-15T13:40:56.782-08:00</updated><title type='text'>Check em</title><content type='html'>Hmmm&lt;br /&gt;&lt;pre class=&quot;brush: java; gutter: false;&quot;&gt;&lt;br /&gt;public void printHello(){&lt;br /&gt;System.out.println(&quot;Hello World&quot;);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;brush: java; gutter: true; highlight: [2, 11, 6]&quot;&gt;&lt;br /&gt;class Singleton(object):&lt;br /&gt;    __instance = None&lt;br /&gt;    def __new__(cls, *a, **kva):&lt;br /&gt;        &#39;&#39;&#39;&lt;br /&gt;        Singleton getter/creator&lt;br /&gt;        @return: Class instance&lt;br /&gt;        &#39;&#39;&#39;&lt;br /&gt;        if cls.__instance is None:&lt;br /&gt;            cls.__instance = object.__new__(cls)&lt;br /&gt;        else:&lt;br /&gt;            cls.__init__ = lambda x: None&lt;br /&gt;        return cls.__instance&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;brush: js; ruler: true; first-line: 10; highlight: [2, 4, 6]&quot;&gt;&lt;br /&gt;function helloWorld() {&lt;br /&gt;  alert(‘Hello World!’);&lt;br /&gt;}&lt;br /&gt;function helloWorld() {&lt;br /&gt;  alert(‘Hello World!’);&lt;br /&gt;}&lt;br /&gt;function helloWorld() {&lt;br /&gt;  alert(‘Hello World!’);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre class=&quot;brush: java; gutter: false;&quot;&gt;&lt;br /&gt;public void printHello(){&lt;br /&gt;System.out.println(&quot;Hello World&quot;);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Хайлайт, который я юзаю в этом блоге:&lt;br /&gt;http://alexgorbatchev.com/SyntaxHighlighter/&lt;br /&gt;&lt;br /&gt;Что нужно сделать чтобы он заработал в блогспоте:&lt;br /&gt;http://fahdshariff.blogspot.com/2009/09/upgrading-to-syntaxhighlighter-20.html&lt;br /&gt;&lt;br /&gt;Хостинг хайлайтера:&lt;br /&gt;http://alexgorbatchev.com/SyntaxHighlighter/hosting.html&lt;br /&gt;http://alexgorbatchev.com/pub/sh/current/&lt;br /&gt;&lt;br /&gt;Репост в твиттер + лента:&lt;br /&gt;http://angel2s2.blogspot.com/2010/07/twitter-c-blogger-jabber.html&lt;br /&gt;&lt;br /&gt;Ручные фиксы в css блогспота:&lt;br /&gt;&lt;pre class=&quot;brush: css; gutter: true;&quot;&gt;&lt;br /&gt;/* Делаем форму комментариев шире, чтобы было более удобно набирать&lt;br /&gt; длинные комменты, ведь форму просто так не раздвинуть в хромиуме,&lt;br /&gt; там таблица(или див, не помню) мешает */&lt;br /&gt;.comment-form {&lt;br /&gt;    max-width: 100%;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/* Убираем скроллбары в блоге. Я лично не использую вставок, где они&lt;br /&gt; нужны, поэтому мне пофиг. Однако это очень полезно если какой-то из&lt;br /&gt; стилей блогспота/хайлайтера заставляет появляться скроллбар для&lt;br /&gt; скроллинга 1.5 пикселей. */&lt;br /&gt;.syntaxhighlighter{&lt;br /&gt;    overflow-y: hidden !important;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://tiaquenes.blogspot.com/feeds/1915137038918825934/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://tiaquenes.blogspot.com/2010/12/check-em.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4163717651209599087/posts/default/1915137038918825934'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4163717651209599087/posts/default/1915137038918825934'/><link rel='alternate' type='text/html' href='http://tiaquenes.blogspot.com/2010/12/check-em.html' title='Check em'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>