tag:blogger.com,1999:blog-39409724734041600612024-02-19T08:08:53.842-08:00Programming DIY / Программирование — это просто!Blog about programming for beginners and beyond / Блог о программировании. Для начинающих и не только.Александрhttp://www.blogger.com/profile/03980297457924475954noreply@blogger.comBlogger273125tag:blogger.com,1999:blog-3940972473404160061.post-91506799810473803252012-04-07T15:51:00.001-07:002012-04-07T15:51:19.698-07:00Блог переехал<div dir="ltr" style="text-align: left;" trbidi="on">
Уважаемые читатели!<br />
<br />
После некоторой работы, блог переезжает. Новый адрес - <a href="http://demin.ws/">http://demin.ws/</a><br />
<br />
Детали переезда - как, что, почему и все остальные спетни королевского двора буквально скоро.
<br />
<br />
Технически все существующие посты и каменты перенесены и должны работать как и раньше.<br />
<br />
RSS для русских постов - <a href="http://demin.ws/atom.xml">http://demin.ws/atom.xml</a><br />
<br />
RSS для английских постов - <a href="http://demin.ws/english/atom.xml">http://demin.ws/english/atom.xml</a><br />
<br />
Замечания и проблемы: <a href="mailto:alexander@demin.ws">alexander@demin.ws</a><br />
<br /></div>Александрhttp://www.blogger.com/profile/03980297457924475954noreply@blogger.com0tag:blogger.com,1999:blog-3940972473404160061.post-91032576361944269782012-03-07T13:09:00.000-08:002012-03-07T13:09:52.298-08:00NOR Machine in Ruby<div dir="ltr" style="text-align: left;" trbidi="on">
My <a href="http://pragprog.com/magazines/2012-03/the-nor-machine">article about a virtual CPU, a machine, computing only one instruction</a> - NOR, is The Pragmatic Bookshelf magazine.<div>
<br /></div>
<div>
The idea was previously described in a series of posts:</div>
<div>
<ul style="text-align: left;">
<li><a href="http://meta-coding.blogspot.com/2011/02/norcpu-hackme-challenge.html" style="background-color: white; color: #336699; font-family: Verdana, Arial, sans-serif; font-size: 13px; line-height: 19px; text-indent: -15px;">NORCPU hackme challenge</a> (<a href="http://demin.ws/norcpu/norcpu.html">part 1</a>, <a href="http://demin.ws/norcpu/norcpu2.html">part 2</a>)</li>
<li><a href="http://meta-coding.blogspot.com/2011/02/one-command-norcpu-program-hacking.html" style="background-color: white; color: #336699; font-family: Verdana, Arial, sans-serif; font-size: 13px; line-height: 19px; text-indent: -15px;">One-command NORCPU program hacking challenge: analysis and solutions</a></li>
<li><a href="http://meta-coding.blogspot.com/2010/04/cpu-executing-just-one-operation.html" style="background-color: white; color: #336699; font-family: Verdana, Arial, sans-serif; font-size: 13px; line-height: 19px; text-indent: -15px;">CPU executing just one operation</a></li>
</ul>
<ul style="text-align: left;">
<li><a href="http://easy-coding.blogspot.com/2010/03/blog-post_26.html" style="background-color: white; color: #336699; font-family: Verdana, Arial, sans-serif; font-size: 13px; line-height: 19px; text-indent: -15px;">Модель процессора с одной командой</a></li>
<li><a href="http://easy-coding.blogspot.com/2011/02/norcpu-hackme-challenge.html" style="background-color: white; color: #336699; font-family: Verdana, Arial, sans-serif; font-size: 13px; line-height: 19px; text-indent: -15px;">NORCPU hackme challenge или взлом программы для однокомандного процессора</a></li>
<li><a href="http://easy-coding.blogspot.com/2011/02/norcpu.html" style="background-color: white; color: #336699; font-family: Verdana, Arial, sans-serif; font-size: 13px; line-height: 19px; text-indent: -15px;">Анализ результатов взлома программы однокомандного процессора NORCPU</a></li>
</ul>
<div>
The article discovers an implementation in Ruby. Now NOR assembly code looks almost as a regular assembler language. I was amazed how powerful Ruby is in creating domain specific languages (DSL). Mostly because it allows to omit parentheses in function calls. </div>
<div>
<br /></div>
</div>
</div>Александрhttp://www.blogger.com/profile/03980297457924475954noreply@blogger.com0tag:blogger.com,1999:blog-3940972473404160061.post-79364756686164698792012-02-06T14:35:00.000-08:002012-02-06T14:35:19.458-08:00Born by copy-paste<p>I usually start crying when see a copy-paste with numbered variables. A probability to screw up is very high, just forget to change a single number after pasting. Here is a horrifying piece of code (don't you mind to spot on an incy wincy typo?)</p>
<div class="highlight" style="background: #ffffff"><pre style="line-height: 125%"><span style="color: #445588; font-weight: bold">void</span> Test_SplitPair() {
<span style="font-weight: bold">typedef</span> std<span style="font-weight: bold">::</span>pair<span style="font-weight: bold"><</span>std<span style="font-weight: bold">::</span>string, std<span style="font-weight: bold">::</span>string<span style="font-weight: bold">></span> Pair;
<span style="font-weight: bold">using</span> string<span style="font-weight: bold">::</span>SplitPair;
<span style="font-weight: bold">const</span> Pair p1 <span style="font-weight: bold">=</span> SplitPair(<span style="color: #bb8844">""</span>, <span style="color: #bb8844">'='</span>);
assert(p1.first.empty());
assert(p1.second.empty());
<span style="font-weight: bold">const</span> Pair p2 <span style="font-weight: bold">=</span> SplitPair(<span style="color: #bb8844">"="</span>, <span style="color: #bb8844">'='</span>);
assert(p2.first.empty());
assert(p2.second.empty());
<span style="font-weight: bold">const</span> Pair p3 <span style="font-weight: bold">=</span> SplitPair(<span style="color: #bb8844">"name=value"</span>, <span style="color: #bb8844">'='</span>);
assert(p3.first <span style="font-weight: bold">==</span> <span style="color: #bb8844">"name"</span>);
assert(p3.second <span style="font-weight: bold">==</span> <span style="color: #bb8844">"value"</span>);
<span style="font-weight: bold">const</span> Pair p4 <span style="font-weight: bold">=</span> SplitPair(<span style="color: #bb8844">"name = value"</span>, <span style="color: #bb8844">'='</span>);
assert(p3.first <span style="font-weight: bold">==</span> <span style="color: #bb8844">"name"</span>);
assert(p3.second <span style="font-weight: bold">==</span> <span style="color: #bb8844">"value"</span>);
<span style="font-weight: bold">const</span> Pair p5 <span style="font-weight: bold">=</span> SplitPair(<span style="color: #bb8844">" n ame \t = va lue \r\n"</span>, <span style="color: #bb8844">'='</span>);
assert(p5.first <span style="font-weight: bold">==</span> <span style="color: #bb8844">" n ame \t "</span>);
assert(p5.second <span style="font-weight: bold">==</span> <span style="color: #bb8844">" va lue \r\n"</span>);
}
</pre></div>
<p>Any ways to make to better? The ideal solution is to split to multiple tests. But even less radical approach works to avoid copy-paste problems:</p>
<div class="highlight" style="background: #ffffff"><pre style="line-height: 125%"><span style="color: #445588; font-weight: bold">void</span> Test_SplitPair() {
<span style="font-weight: bold">typedef</span> std<span style="font-weight: bold">::</span>pair<span style="font-weight: bold"><</span>std<span style="font-weight: bold">::</span>string, std<span style="font-weight: bold">::</span>string<span style="font-weight: bold">></span> Pair;
<span style="font-weight: bold">using</span> string<span style="font-weight: bold">::</span>SplitPair;
{
<span style="font-weight: bold">const</span> Pair p <span style="font-weight: bold">=</span> SplitPair(<span style="color: #bb8844">""</span>, <span style="color: #bb8844">'='</span>);
assert(p.first.empty());
assert(p.second.empty());
}
{
<span style="font-weight: bold">const</span> Pair p <span style="font-weight: bold">=</span> SplitPair(<span style="color: #bb8844">"="</span>, <span style="color: #bb8844">'='</span>);
assert(p.first.empty());
assert(p.second.empty());
}
{
<span style="font-weight: bold">const</span> Pair p <span style="font-weight: bold">=</span> SplitPair(<span style="color: #bb8844">"name=value"</span>, <span style="color: #bb8844">'='</span>);
assert(p.first <span style="font-weight: bold">==</span> <span style="color: #bb8844">"name"</span>);
assert(p.second <span style="font-weight: bold">==</span> <span style="color: #bb8844">"value"</span>);
}
{
<span style="font-weight: bold">const</span> Pair p <span style="font-weight: bold">=</span> SplitPair(<span style="color: #bb8844">"name = value"</span>, <span style="color: #bb8844">'='</span>);
assert(p.first <span style="font-weight: bold">==</span> <span style="color: #bb8844">"name"</span>);
assert(p.second <span style="font-weight: bold">==</span> <span style="color: #bb8844">"value"</span>);
}
{
<span style="font-weight: bold">const</span> Pair p <span style="font-weight: bold">=</span> SplitPair(<span style="color: #bb8844">" n ame \t = va lue \r\n"</span>, <span style="color: #bb8844">'='</span>);
assert(p.first <span style="font-weight: bold">==</span> <span style="color: #bb8844">" n ame \t "</span>);
assert(p.second <span style="font-weight: bold">==</span> <span style="color: #bb8844">" va lue \r\n"</span>);
}
}
</pre></div>Александрhttp://www.blogger.com/profile/03980297457924475954noreply@blogger.com0tag:blogger.com,1999:blog-3940972473404160061.post-68416117869449124512012-02-06T14:32:00.000-08:002012-02-06T14:32:38.359-08:00Рожденный копипастом<p>Всем своими фибрами ненавижу копипаст с участием переменных с номерами. При очередном копипасте вероятность забыть исправить одну циферку крайне велика. Например, ужасный кусок кода (не правда ли, просто найти опечатку?):</p>
<div class="highlight" style="background: #ffffff"><pre style="line-height: 125%"><span style="color: #445588; font-weight: bold">void</span> Test_SplitPair() {
<span style="font-weight: bold">typedef</span> std<span style="font-weight: bold">::</span>pair<span style="font-weight: bold"><</span>std<span style="font-weight: bold">::</span>string, std<span style="font-weight: bold">::</span>string<span style="font-weight: bold">></span> Pair;
<span style="font-weight: bold">using</span> string<span style="font-weight: bold">::</span>SplitPair;
<span style="font-weight: bold">const</span> Pair p1 <span style="font-weight: bold">=</span> SplitPair(<span style="color: #bb8844">""</span>, <span style="color: #bb8844">'='</span>);
assert(p1.first.empty());
assert(p1.second.empty());
<span style="font-weight: bold">const</span> Pair p2 <span style="font-weight: bold">=</span> SplitPair(<span style="color: #bb8844">"="</span>, <span style="color: #bb8844">'='</span>);
assert(p2.first.empty());
assert(p2.second.empty());
<span style="font-weight: bold">const</span> Pair p3 <span style="font-weight: bold">=</span> SplitPair(<span style="color: #bb8844">"name=value"</span>, <span style="color: #bb8844">'='</span>);
assert(p3.first <span style="font-weight: bold">==</span> <span style="color: #bb8844">"name"</span>);
assert(p3.second <span style="font-weight: bold">==</span> <span style="color: #bb8844">"value"</span>);
<span style="font-weight: bold">const</span> Pair p4 <span style="font-weight: bold">=</span> SplitPair(<span style="color: #bb8844">"name = value"</span>, <span style="color: #bb8844">'='</span>);
assert(p3.first <span style="font-weight: bold">==</span> <span style="color: #bb8844">"name"</span>);
assert(p3.second <span style="font-weight: bold">==</span> <span style="color: #bb8844">"value"</span>);
<span style="font-weight: bold">const</span> Pair p5 <span style="font-weight: bold">=</span> SplitPair(<span style="color: #bb8844">" n ame \t = va lue \r\n"</span>, <span style="color: #bb8844">'='</span>);
assert(p5.first <span style="font-weight: bold">==</span> <span style="color: #bb8844">" n ame \t "</span>);
assert(p5.second <span style="font-weight: bold">==</span> <span style="color: #bb8844">" va lue \r\n"</span>);
}
</pre></div>
<p>Как его можно улучшить? Например, разбить на отдельные тесты. Это идеальный вариант. Но можно сделать и так (что лично на мой взгляд не так уж и плохо), чтобы решить проблему копипаста новых примеров:</p>
<div class="highlight" style="background: #ffffff"><pre style="line-height: 125%"><span style="color: #445588; font-weight: bold">void</span> Test_SplitPair() {
<span style="font-weight: bold">typedef</span> std<span style="font-weight: bold">::</span>pair<span style="font-weight: bold"><</span>std<span style="font-weight: bold">::</span>string, std<span style="font-weight: bold">::</span>string<span style="font-weight: bold">></span> Pair;
<span style="font-weight: bold">using</span> string<span style="font-weight: bold">::</span>SplitPair;
{
<span style="font-weight: bold">const</span> Pair p <span style="font-weight: bold">=</span> SplitPair(<span style="color: #bb8844">""</span>, <span style="color: #bb8844">'='</span>);
assert(p.first.empty());
assert(p.second.empty());
}
{
<span style="font-weight: bold">const</span> Pair p <span style="font-weight: bold">=</span> SplitPair(<span style="color: #bb8844">"="</span>, <span style="color: #bb8844">'='</span>);
assert(p.first.empty());
assert(p.second.empty());
}
{
<span style="font-weight: bold">const</span> Pair p <span style="font-weight: bold">=</span> SplitPair(<span style="color: #bb8844">"name=value"</span>, <span style="color: #bb8844">'='</span>);
assert(p.first <span style="font-weight: bold">==</span> <span style="color: #bb8844">"name"</span>);
assert(p.second <span style="font-weight: bold">==</span> <span style="color: #bb8844">"value"</span>);
}
{
<span style="font-weight: bold">const</span> Pair p <span style="font-weight: bold">=</span> SplitPair(<span style="color: #bb8844">"name = value"</span>, <span style="color: #bb8844">'='</span>);
assert(p.first <span style="font-weight: bold">==</span> <span style="color: #bb8844">"name"</span>);
assert(p.second <span style="font-weight: bold">==</span> <span style="color: #bb8844">"value"</span>);
}
{
<span style="font-weight: bold">const</span> Pair p <span style="font-weight: bold">=</span> SplitPair(<span style="color: #bb8844">" n ame \t = va lue \r\n"</span>, <span style="color: #bb8844">'='</span>);
assert(p.first <span style="font-weight: bold">==</span> <span style="color: #bb8844">" n ame \t "</span>);
assert(p.second <span style="font-weight: bold">==</span> <span style="color: #bb8844">" va lue \r\n"</span>);
}
}
</pre></div>Александрhttp://www.blogger.com/profile/03980297457924475954noreply@blogger.com0tag:blogger.com,1999:blog-3940972473404160061.post-68419662528144515222012-02-02T15:50:00.000-08:002012-09-26T09:27:55.973-07:00Вiased review of "Seven languages in seven weeks"<div dir="ltr" style="text-align: left;" trbidi="on">
I have finished accelerated reading of "<a href="http://pragprog.com/book/btlang/seven-languages-in-seven-weeks">Seven languages in seven weeks</a>" by Bruce Tate.<br />
<br />
<img alt="http://demin.ws/images/covers/english/7-languages-in-7-weeks-cover.jpg" src="http://demin.ws/images/covers/english/7-languages-in-7-weeks-cover.jpg" />
<br />
<br />
In my case it was "Seven languages in seven evenings". For each language there is an introduction, which makes sense only if a language is brand new for you. There are also interviews with creators of the languages. One of the asked interesting questions was about what the author would like to change in the language if he could re-design it from scratch now.<br />
<br />
Languages:<br />
<ul class="simple">
<li>Ruby</li>
<li>Io</li>
<li>Prolog</li>
<li>Scala</li>
<li>Erlang</li>
<li>Clojure</li>
<li>Haskell</li>
</ul>
The reviews of each chapter below are my subjective views two things at once: a programming language and a material about it. Why? For familiar languages it hardly makes any sense to describe the language per se, but to note interesting distinctive features could be useful. But if a languages is a green field, it is worth describe it in general.<br />
<br />
Ruby<br />
<br />
The Ruby chapter was quite useless for me because I thoughtfully read "<a href="http://pragprog.com/book/ruby3/programming-ruby-1-9">Programming Ruby 1.9</a>", and have been hooked. Ruby is an amazing scripting language. Each time when programming in Ruby I feel so delighted similar to when I tried PHP first time after Perl.<br />
<br />
Ruby's creator, <a href="http://en.wikipedia.org/wiki/Yukihiro_Matsumoto">Yukihiro Matsumoto</a>, says in the interview, that if he could re-design Ruby today, he'd like to change the concept of multi-threading to "<a href="http://en.wikipedia.org/wiki/Actor_model">Actor</a>".<br />
<br />
In short, "Actor" is when concurrent threads don't share memory and don't use mutex or semaphores for synchronization. Instead, they send and receive messages to each other, and messaging is provided by runtime and built-in to the languages syntax. Examples: Scala, Go, Erlang, Io.<br />
<br />
Io<br />
<br />
<a href="http://iolanguage.com/">Io</a> is a very small, compact language, based on prototypes like JavaScript, where there is no distinction between classes and objects.<br />
<br />
There is an interesting concurrency feature in addition to actors and coroutines (cooperative multi-threading as in <a href="http://www.lua.org/manual/5.2/manual.html#2.6">Lua</a>), called futures. "Futures" are similar to the actor. There the only difference is when the caller thread tries to use the result of the future, it will be blocked until the future completes and gives the result back.<br />
<br />
An example from the book:<br />
<br />
<div class="highlight" style="background: #ffffff;">
<pre style="line-height: 125%;"><span style="color: #999988; font-style: italic;">// Fire up the future.</span>
futureResult <span style="font-weight: bold;">:=</span> URL with<span style="font-weight: bold;">(</span><span style="color: #bb8844;">"http://google.com/"</span><span style="font-weight: bold;">)</span> <span style="font-weight: bold;">@</span>fetch
writeln<span style="font-weight: bold;">(</span><span style="color: #bb8844;">"Continue immediately when future is running in background."</span><span style="font-weight: bold;">)</span>
<span style="color: #999988; font-style: italic;">// This line will be executed immediately after spawning the future.</span>
writeln<span style="font-weight: bold;">(</span><span style="color: #bb8844;">"fetched "</span><span style="font-weight: bold;">,</span> futureResult size<span style="font-weight: bold;">,</span> <span style="color: #bb8844;">" bytes"</span><span style="font-weight: bold;">)</span>
<span style="color: #999988; font-style: italic;">// But this line will be blocked until the future returns.</span></pre>
</div>
<br />
Prolog<br />
<br />
I've been gnawing this animal for years. But thanks to Erlang recently, all this functional stuff in general is now giving up for me, and monsters like Prolog or Haskell don't look so scary anymore.<br />
<br />
It turned out that the depth of the material about Prolog has matched precisely with my level. The eight queens problem and a Sudoku solver were excellent examples for me.<br />
<br />
Shortly, a program in Prolog is a pile of facts and rules. Then the Prolog runtime performs a depth-first search amongst possible results and tries to find those satisfying all the given facts and rules.<br />
<br />
In fact, the Sudoku solver program is a set of variables, representing the Sudoku field, and a list of rules (summations by columns, rows and squared groups) according to the rules of Sudoku. Then Prolog performs an exhaustive search to find the values and their combinations satisfying the rules.<br />
<br />
Of course, this is very much a superficial glance, but this has given me much more understanding of Prolog.<br />
<br />
Scala<br />
<br />
I will note only a few facts interesting to me.<br />
<br />
Multi-threading is based on actors. After Erlang and Go you understand how good and handy it is. I think that Scala has all possible bells and whistles even invented for programming languages. But sometimes it has not only good consequences.<br />
<br />
Erlang<br />
<br />
I'm a big fan of Erlang and already read a few big books. That's why this book hasn't given to me anything new. But for novices this introduction may give quite solid view on Erlang functional approach and concurrency model.<br />
<br />
Clojure<br />
<br />
Clojure is a Lisp-based language driven by Java VM.<br />
<br />
It has an interesting feature called <a href="http://en.wikipedia.org/wiki/Software_transactional_memory">STM</a>, software transactional memory. In STM a piece of code is declared to be a transaction. It is executed atomically or all the changes of variables are rolled back.<br />
<br />
And finally, Haskell<br />
<br />
Haskell is a taught guy. The introduction in this book is very light and minimal, just to remember the word "Haskell". I read "<a href="http://www.amazon.co.uk/Programming-Haskell-Graham-Hutton/dp/0521692695">Programming in Haskell</a>" and currently I'm on "<a href="http://www.amazon.co.uk/Real-World-Haskell-Bryan-OSullivan/dp/0596514980">Real World Haskell</a>", that's why I simply skimmed the chapter in this book.<br />
<br />
Okay, to sum up. This book is to be read just once, to broaden your outlook.</div>
Александрhttp://www.blogger.com/profile/03980297457924475954noreply@blogger.com0tag:blogger.com,1999:blog-3940972473404160061.post-85303956938627692142012-02-02T15:43:00.000-08:002012-09-26T09:29:05.609-07:00Предвзятое мнение о книге "Seven languages in seven weeks"<div dir="ltr" style="text-align: left;" trbidi="on">
Закончил ускоренное чтение по диагонали книги "<a href="http://pragprog.com/book/btlang/seven-languages-in-seven-weeks">Seven languages in seven weeks</a>", автор Bruce Tate.<br />
<br />
<img alt="http://demin.ws/images/covers/english/7-languages-in-7-weeks-cover.jpg" src="http://demin.ws/images/covers/english/7-languages-in-7-weeks-cover.jpg" />
<br />
<br />
В моей версии это было "Семь языков за семь вечеров". Для каждого языка дается минимальное введение, которое имеет смысл только если язык для вас вообще новый. Еще приводятся мини интервью с создателями языков, и один из интересных задаваемых им вопросов - это "чтобы вы сделали в языке иначе, если б можно начать сначала".<br />
<br />
Описываются языки:<br />
<ul class="simple">
<li>Ruby</li>
<li>Io</li>
<li>Prolog</li>
<li>Scala</li>
<li>Erlang</li>
<li>Clojure</li>
<li>Haskell</li>
</ul>
Обзор каждой главы - это мой субъективный взгляд на две вещи сразу: язык программирования и материал главы про него. Объясню почему - для знакомых языков вряд ли имеет смысл описывать сам язык. Может имеет смысл отметить интересные отличительные моменты. А вроде для неизученных, типа Пролога или Clojure, можно и остановиться немного на самом языке.<br />
<br />
Ruby<br />
<br />
Про Ruby ничего особенно из книги не вынес, так как вдумчиво читал "<a href="http://pragprog.com/book/ruby3/programming-ruby-1-9">Programming Ruby 1.9</a>", после чего подсел на этот язык. Ruby - фантастический скриптовой язык. Каждый раз, когда пишу на нем, испытываю удовольствие примерно такое, когда я после Perl'а попробовал в первый раз PHP.<br />
<br />
Автор языка сказал в интервью, что, создавая бы язык заново сегодня, он бы хотел для многопоточности вместо традиционных потоков сделать модель "<a href="http://ru.wikipedia.org/wiki/%D0%9C%D0%BE%D0%B4%D0%B5%D0%BB%D1%8C_%D0%B0%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2">actor</a>".<br />
<br />
В двух словах, Actor - это когда параллельные потоки разделяют ресурсы не через память и механизмы синхронизации типа мьютексов и семафоров, а через обмен сообщениями, прием и посылка которых обеспечиваются средой, и они встроены в синтаксис языка. Например, как в Scala, Go, Erlang, Io.<br />
<br />
Io<br />
<br />
<a href="http://iolanguage.com/">Io</a> очень компактный, на мой взгляд эзотерический язык, основанный на прототипах, как JavaScript, когда нет четкого разделения между классами и объектами. Минимальный и очень простой синтаксис.<br />
<br />
Интересный механизм многопоточности в дополнение к actor и coroutine (коллективная многозадачность, как в <a href="http://www.lua.org/manual/5.2/manual.html#2.6">Lua</a>), называемый futures. "Futures" - это вроде бы как обычный actor, поток запущенный работать параллельно. Но с одним отличием: как только создающий поток попытается воспользоваться результатом future, он будет заблокирован до тех пор, пока future не вычислит это значение.<br />
<br />
Примерчик из книги:<br />
<br />
<div class="highlight" style="background: #ffffff;">
<pre style="line-height: 125%;"><span style="color: #999988; font-style: italic;">// Запускаем future</span>
futureResult <span style="font-weight: bold;">:=</span> URL with<span style="font-weight: bold;">(</span><span style="color: #bb8844;">"http://google.com/"</span><span style="font-weight: bold;">)</span> <span style="font-weight: bold;">@</span>fetch
writeln<span style="font-weight: bold;">(</span><span style="color: #bb8844;">"Сразу начинаем делать что еще, пока future работает в фоне."</span><span style="font-weight: bold;">)</span>
<span style="color: #999988; font-style: italic;">// Эта строка будет выполнена сразу.</span>
writeln<span style="font-weight: bold;">(</span><span style="color: #bb8844;">"fetched "</span><span style="font-weight: bold;">,</span> futureResult size<span style="font-weight: bold;">,</span> <span style="color: #bb8844;">" bytes"</span><span style="font-weight: bold;">)</span>
<span style="color: #999988; font-style: italic;">// А вот эта строка будет заблокирована, пока future не выполнится.</span>
</pre>
</div>
<br />
Идем дальше, Prolog.<br />
<br />
Этого зверя я грызу давно. К счастью, благодаря освоению Erlang'а, я стал реально въезжать в функциональную тему в целом, и монстры типа Пролога или Хаскелла уже не за пределами понимания.<br />
<br />
Так совпало, что глубина материала по Прологу легла точно для моего уровня. Задача восьми ферзей и поиска решений Судоку были для меня отличными примерами.<br />
<br />
В двух словах: программа для Прологе - это набор фактов и связей между ними. Затем Пролог, выполняя программу, поиском в глубину обходит пространство решений и выбирает те, которые удовлетворяют всем заданным фактам и связям между ними.<br />
<br />
Фактические программа поиска решения Судоку - это набор переменных, составляющих клетки поля Судоку, и набор правил - разнообразные суммирования по группам, по строками и столбцам (по правилам Судоку). И затем Пролог перебором ищет подходящие значения и комбинации переменных.<br />
<br />
Конечно, это очень поверхностный взгляд, но который лично мне добавил много понимания.<br />
<br />
Идем дальше, Scala.<br />
<br />
Отмечу только отдельные факты, интересные мне.<br />
<br />
Многопоточность на основе actors, то есть когда потоки обмениваются сообщениями. После Go и Erlang понимаешь как это удобно и правильно.<br />
<br />
Про остальное - по-моему в Scalа есть все возможные свистелки и перделки, когда-либо придуманные в области языков программирования. В общем, если вы фанат Java VM, то надо брать полноценную книгу по Scala и грызть ее.<br />
<br />
Идем далее, Erlang.<br />
<br />
Тут тоже скажу мало, так как я фанат этого языка, и уровень этой книги мне был мал, но введение дается хорошее для ознакомления с функциональной сутью Erlang'а и его моделью многопоточности.<br />
<br />
Clojure<br />
<br />
Снова язык на основе Java VM. Clojure - это разновидность Лиспа со всеми вытекающими.<br />
Интересная возможность языка, в общем-то не связанная с его лисповой сущностью - это STM, <a href="http://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%BD%D0%B0%D1%8F_%D1%82%D1%80%D0%B0%D0%BD%D0%B7%D0%B0%D0%BA%D1%86%D0%B8%D0%BE%D0%BD%D0%BD%D0%B0%D1%8F_%D0%BF%D0%B0%D0%BC%D1%8F%D1%82%D1%8C">software transactional memory</a>. Это когда некий кусок кода в программе объявляется транзакцией, и он выполняется атомарно, либо все изменения откатываются.<br />
<br />
Ну и под занавес, Haskell.<br />
<br />
Хаскелл суров, и данная книга - это крайне минимальное введение, просто для запоминания слова Хаскелл. Я кое как осилил отличную книгу <a href="http://www.ozon.ru/context/detail/id/3039995/">Душкина</a> и "<a href="http://www.amazon.co.uk/Programming-Haskell-Graham-Hutton/dp/0521692695">Programming in Haskell</a>", а сейчас читаю "<a href="http://www.amazon.co.uk/Real-World-Haskell-Bryan-OSullivan/dp/0596514980">Real World Haskell</a>", поэтому главу этой книги просто пролистал.<br />
<br />
Вывод: книга 100% одноразовая, но, как говориться, раз не... полезно для кругозора и для программистских терок на кухне.</div>
Александрhttp://www.blogger.com/profile/03980297457924475954noreply@blogger.com0tag:blogger.com,1999:blog-3940972473404160061.post-51888408664367335532012-01-30T15:07:00.001-08:002012-01-31T09:22:19.428-08:00My current languages<p>I have realised recently that I like to learn new programming languages. A symptom is a very easy to spot: I have a permanent pile of books I am reading. Thanks for the iPad, I can have them all with me all the time and choose depending on mood. Surprisingly, but books about languages are being read first and replaced with new ones.</p>
<p>Simply wanted to share current interests.</p>
<p>Everyday work (design, planning, coding and reviews): C and C++. C++ 0x11 goes at full speed and it is worth to catch up. <a href="http://accu.org/index.php/conferences/accu_conference_2012/accu2012_schedule">ACCU 2012</a> is almost fully dedicated to the new C++.</p>
<p>For fun:</p>
<ul class="simple">
<li>scripting - Ruby</li>
<li>a server side and multi-threading: Erlang and Go</li>
<li>embedded: Lua and Scheme</li>
</ul>
<p>To "gnaw" in hope to write something real - Haskell and Prolog.</p>
<p>In a queue at least minimum acquaintance: Clojure. This one is more promising because it is Lisp.</p>
<p>After overall migration to Mac, I wish to try Objection-C and AppleScript in action. But what to write on Mac, in Objective-C? Of course, UI! But UI is totally out of my interests. But, Objective-C still looks tempting because of so quickly growing mobile apps market.</p>
<p>From recently touched, but not involved:</p>
<ul class="simple">
<li>Scala - a sophisticated language requiring a "deep dive", and without a real suitable problem the interest is gone. Twitter is already re-written in Scala ;-).</li>
<li>Racket - an interesting Lisp based animal on steroids of a very powerful library.</li>
</ul>Александрhttp://www.blogger.com/profile/03980297457924475954noreply@blogger.com1tag:blogger.com,1999:blog-3940972473404160061.post-72953833303170624892012-01-30T15:04:00.000-08:002012-01-31T09:21:54.334-08:00Мои текущие языки<p>Последнее время осознал, что на данный момент тяготею к изучению новых языков программирования. Симптом очень простой: у меня есть постоянный список из 5-6 книг, которые находятся в состоянии чтения. Благодаря электронному и мобильному способу чтения можно их всегда иметь с собой (как, впрочем, и все остальные тоже) и читать по настроению. И что удивительно, книги по языкам постоянно завершаются первыми и заменяются новыми.</p>
<p>Просто хотел поделиться текущими интересами.</p>
<p>Каждодневная работа (проектирование, планирование, кодирование и ревью): C и С++. Тут C++ 0x11 полным ходом, и надо подтягиваться. <a href="http://accu.org/index.php/conferences/accu_conference_2012/accu2012_schedule">ACCU 2012</a> в этом году посвящен в основном новому C++.</p>
<p>Для души:</p>
<ul class="simple">
<li>скриптование - Ruby</li>
<li>серверное и многопоточное - Erlang и Go</li>
<li>встраивание сценариев - Lua и Scheme</li>
</ul>
<p>Для "погрызть" в надежде когда-нибудь написать что-нибудь реальное - Haskell и немного Пролог (тут надежд совсем мало).</p>
<p>В очереди на хотя бы минимальное ознакомление: Clojure. Тут надежд больше, так как это все-таки Lisp.</p>
<p>С общей недавней миграцией на Мак хочется попробовать в действии Objective-C и AppleScript. А что еще писать на Маке, да еще и на Objective-C? Конечно UI! А UI это на 200% не мой профиль. Но, если серьезно, сложно загасить внутреннюю хотелку освоить Objective-C, когда тут вокруг всякие iOS'ы.</p>
<p>Из недавнего ознакомленного, но в которое не втянулся:</p>
<ul class="simple">
<li>Scala - большой язык, требующий погружения и, без реальной подходящей задачи как-то нет запала. Ну не Твиттер же новый писать? ;-).</li>
<li>Racket - вот этот зверь мне очень понравился как лисповый язык с мощной библиотекой всего. Но как обратная сторона, язык получился большой, как Scala, и как-то пока не подвернулось подходящей интересной задачи.</li>
</ul>Александрhttp://www.blogger.com/profile/03980297457924475954noreply@blogger.com2tag:blogger.com,1999:blog-3940972473404160061.post-21772674820851839012012-01-26T16:13:00.000-08:002012-09-26T09:25:30.594-07:00Graph visualization in DOT / Визуализация графов в языке DOT<div dir="ltr" style="text-align: left;" trbidi="on">
<blockquote>
The English version of the post is <a class="reference internal" href="http://draft.blogger.com/blogger.g?blogID=3940972473404160061#below">below</a>.</blockquote>
<hr class="docutils" />
Предыстория. Мы обрабатываем финансовые транзакции. Возникла задача профилирования. Решили записать путь прохода транзакции по системе и построить граф связей между модулями - кто кого вызывает. Два способа построения: на основе статического анализа исходников и через трассировку реальных вызовов во время выполнения.<br />
<br />
Итак, связи зафиксированы. Теперь их надо их как-то представить и построить граф, визуально.<br />
<br />
Вроде не самая тривиальная задача, но оказывается, решается весьма просто.<br />
<br />
Есть такой язык представления графов, называется <a href="http://ru.wikipedia.org/wiki/DOT_(%D1%8F%D0%B7%D1%8B%D0%BA)">DOT</a>. Прелесть его в предельной простоте. Например, простейший граф:<br />
<br />
<div class="highlight" style="background: #ffffff;">
<pre style="line-height: 125%;">graph name {
a -- b
b -- c
b -- d
}
</pre>
</div>
<br />
Натравливаешь на это дело специальную программу и получаешь:<br />
<img alt="http://demin.ws/images/blog/dot-graph.png" src="http://demin.ws/images/blog/dot-graph.png" />
<br />
<br />
Все! Картинка на выходе в SVG. Можно хоть на стену вешать.<br />
<br />
К сожалению, лучший софт, что я нашел для визуализации DOT - это <a href="http://www.graphviz.org/">Graphviz</a>. Вроде и работает неплохо, строя весьма большие графы, и есть на всех платформах, благодаря Java, но по интерфейсу - это запредельный и неописуемый кусок говна. Увы.<br />
<br />
Если кому интересно, я <a href="http://demin.ws/downloads/dot/graph.gv">выложил пример</a> реальной трассировки (по понятным причинам, имена изменены). В целом дает представление о простоте исходника и о возможностях визуализации - <a href="http://demin.ws/downloads/dot/graph.png">PNG</a> и <a href="http://demin.ws/downloads/dot/graph.svg">SVG</a>.<br />
<br />
Повторюсь - процесс формализации графа крайне прост - нужно только задать пары связанных вершин. Можно делать направленные графы, можно задавать вершинам и дугам разные атрибуты.<br />
<br />
В целом, отличная технология.<br />
<hr class="docutils" id="below" />
Background. We do financial transactions processing. At some point we decided that we need profiling. We could record a path of how a transaction being passed amongst modules. There are two options - either to do static analysis or to trace the runtime.<br />
<br />
So, the connections are determined and now we have to formalize and visualize them.<br />
<br />
At the first glance this is not an easy task, but it turned out there is a simple and elegant solution.<br />
<br />
There is a plain text language to declare graphs -- <a href="http://en.wikipedia.org/wiki/DOT_language">DOT</a>. Its beauty is in ultimate simplicity. For example, a trivial graph:<br />
<div class="highlight" style="background: #ffffff;">
<pre style="line-height: 125%;"></pre>
<pre style="line-height: 125%;">graph name {
a -- b
b -- c
b -- d
}
</pre>
</div>
<br />
Feed it to special software and get this:<br />
<img alt="http://demin.ws/images/blog/dot-graph.png" src="http://demin.ws/images/blog/dot-graph.png" />
<br />
<br />
That's it! The output is in SVG, ready to stick on a wall.<br />
<br />
Unfortunately, the best software I've found to visualize DOT is <a href="http://www.graphviz.org/">Graphviz</a>. It does pretty decent job properly processing quite sophisticated graphs, but in terms of user experience it is shite.<br />
<br />
If anyone is interested, I've <a href="http://demin.ws/images/blog/dot-graph.gv">uploaded</a> a real trace (obviously, names are obfuscated). It gives an idea about simplicity of the source and visualization capabilities - <a href="http://demin.ws/images/blog/dot-graph.png">PNG</a> and <a href="http://demin.ws/images/blog/dot-graph.svg">SVG</a>.<br />
<br />
Again, the graph formalization is dead simple - you only need to specify pairs of connected vertices. Also, in DOT you can describe directed graphs and extra attributes of the vertices.<br />
<br />
To sum up, great technology.</div>
Александрhttp://www.blogger.com/profile/03980297457924475954noreply@blogger.com0tag:blogger.com,1999:blog-3940972473404160061.post-28602742211738881862012-01-19T19:52:00.000-08:002012-01-20T11:46:38.416-08:00Maximite - 8-bit nostalgia with a soldering iron / Ностальгия по временам Радио-86РК и Спектрума с паяльником в руках<p>The English version of this post is <a class="reference internal" href="#below">below</a>.</p>
<hr class="docutils" />
<p>Некоторое время назад я наткнулся на интересный проект - Maximite.</p>
<p>Это микрокомпьютер на базе Microchip PIC32 со встроенным Бейсиком. Прелесть тут в том, что собрать его можно за пару часов.</p>
<img alt="http://geoffg.net/Images/Maximite/icon.jpg" src="http://geoffg.net/Images/Maximite/icon.jpg" />
<p>По возможностям он немного мощнее Радио-86РК и классического Спектрума. Но вот периферия у него сказочная: SD/FAT карточка, USB, VGA, PS/2, таймеры, RS232, I2C, SPI, PWM, ADC/DAC и просто одиночные порты-пины общего назначения.</p>
<p>Если собирать на макетной плате, то цена будет, по заявлению автора, менее десяти австралийских долларов.</p>
<p><a href="http://geoffg.net/maximite.html">Проект</a> полностью открытый. Автор дает схемы, исходные коды прошивки и рекомендации по наладке.</p>
<p>Если даже быстро пролистать <a href="http://geoffg.net/Downloads/Maximite/Maximite%20User%20Manual%20V3.0.pdf">документацию</a>, видно, возможностей прорва. Можно практически на коленке создавать различные мини-контроллеры чего угодно. Работа со всей выше перечисленной периферией ведется прямо из Бейсика.</p>
<p>Программы и данные можно хранить на SD карточке. Если на карточке есть файл "AUTORUN.BAS", то прошивка автоматически запускает его при старте.</p>
<p>Мне это все понравилось, но паять мне было лень. А в интернете продавались только конструкторы.</p>
<p>В итоге я заказал <a href="http://www.altronics.com.au/index.asp?area=item&id=K9550">конструктор у Altronics</a>.</p>
<p>И вот он пришел. На плате запаян только микропроцессор, ибо для пайки такого корпуса надо либо иметь паяльную станцию, либо большое умение.</p>
<p>Поехали.</p>
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0099.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0099.jpg" />
<p>Вот тут я уже припаял несколько элементов. Я в пайке не совсем новичок, но держал паяльник в руках последний раз лет пять назад. Кислоты у меня не было, поэтому для ускорения процесса я выкрашивал канифоль прямо на точки пайки. Эффект примерно такой же. Паяльник (тот, что в тарелке) с острым жалом.</p>
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0102.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0102.jpg" />
<p>Первый час я возился с несколькими элементами, но потом дело наладилось.</p>
<p>Вот тут уже готова половина.</p>
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0103.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0103.jpg" />
<p>Но еще через час все было готово.</p>
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0106.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0106.jpg" />
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0107.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0107.jpg" />
<p>Maximite может питаться либо от внешних 9 вольт, либо от USB. Я подключил вторым способом.</p>
<p>Итак, запуск. Подключаем USB и VGA к монитору. Работает!</p>
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0110.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0110.jpg" />
<p>Бейсик готов выполнять команды, но пока нет клавиатуры. Чисто PS/2 клавиатуры у меня не было, поэтому я попытался через USB-PS/2 переходник. Увы, воткнуть не получилось.</p>
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0111.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0111.jpg" />
<p>На следующий день я взял у наших айтишников старую PS/2 клавиатуру и таки подключился.</p>
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0119.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0119.jpg" />
<p>Корпус.</p>
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0114.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0114.jpg" />
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0115.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0115.jpg" />
<p>В закрытом виде.</p>
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0112.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0112.jpg" />
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0113.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0113.jpg" />
<p>Надо отдать должное - конструктор от Altronics отличного качества. Отверстия на плате металлизированы, что значительно упрощается пайку. Корпус моментально собирается.</p>
<p>Теперь надо было обновить прошивку, так как автор проекта уже успел ее значительно улучшить с момента выпуска конструктора.</p>
<p>Maximite имеет встроенную возможность обновления прошивки, и специальный программатор не нужен. Надо открыть корпус и перезапустить Maximite, удерживая специальный микро-выключатель. Устройство впадает в состояние boot loader'а, и специальной утилитой через USB можно заливать обновление.</p>
<p>Maximite видится в USB-подсистеме как стандартное CDC устройство. Но для Windows нужно все равно сначала поставить драйвер для создания виртуального COM-порта. На Маке этот драйвер встроен.</p>
<p>Подключаем.</p>
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0116.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0116.jpg" />
<p>Заливаем.</p>
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0118.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0118.jpg" />
<p>Ура. Прошивка обновлена с 2.1 до последней 3.0A.</p>
<p>Как я уже говорил, Maximite поддерживает VGA для дисплея и PS/2 для клавиатуры. Но это не все. Если подключить Maximite через USB к компьютеру, то кроме питания можно запустить программу эмулятор терминала, которая через виртуальный порт RS232 (работающий через USB) может обмениться данными с Maximite. Все, что Maximite выводит на VGA также дублируется в порт, а все что Maximite получает из порта расценивается как принятое с клавиатуры.</p>
<p>То есть можно вообще отключить VGA и PS/2 и работать чисто через терминал. Это офигительная возможность.</p>
<p>Например, картинка с VGA (вольтметр):</p>
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/dsc01130.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/dsc01130.jpg" />
<p>И одновременно с экрана терминала:</p>
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/dsc01129.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/dsc01129.jpg" />
<p>Забавно, экран у Maximite работает с точками, а не со знакоместами. Когда на экран выводится символ, то он дублируется, как я уже сказал, в терминале. А если рисуется графика, то она, естественно, в терминале не видна.</p>
<p>Диалект Бейсика в Maximite немного необычен, но зато дает доступ ко всей периферии без ограничения, причем прямо операторами языка.</p>
<p>На сайте автора есть архив с программами на Бейсике, демонстрирующие некоторые возможности Maximite.</p>
<p>Я приведу несколько картинок.</p>
<p>Часы.</p>
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/dsc01125.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/dsc01125.jpg" />
<p>Редактор знакогенератора.</p>
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/dsc01123.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/dsc01123.jpg" />
<p>Вольметр.</p>
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/dsc01132.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/dsc01132.jpg" />
<p>Пару головоломок.</p>
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/dsc01128.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/dsc01128.jpg" />
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/dsc01133.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/dsc01133.jpg" />
<p>А что это, думаю, объяснять не надо.</p>
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/dsc01126.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/dsc01126.jpg" />
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/dsc01131.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/dsc01131.jpg" />
<p>Ну, конечно, привет Хабру!</p>
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/dsc01134.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/dsc01134.jpg" />
<p>Заключение</p>
<p>Каждая копейка, потраченная мной на этот эксперимент, стоила полученного кайфа.</p>
<p>Сам проект Maximite удивляет своей законченностью. Все как-то очень органично и просто. И самое главное - это работает!</p>
<p>Как мне кажется - для начинающих, даже детей, интересующихся микропроцессорной техникой, Maximite - это просто находка. Элементарная сборка, не требующая настройки. Я, как полный дилетант, собрал все за несколько часов.</p>
<p>Когда мой брат лет двадцать назад собирал <a href="http://radio86.googlecode.com/hg/online/radio86.html">Радио-86РК</a> и Спектрум, ходила шутка про устройства для самостоятельной сборки, описываемые в журнале "Радио" - если авторы говорят, что устройство не требует наладки, то значит есть хотя бы минимальный шанс его наладить, ну я если авторы говорят, что требуется минимальная наладка...</p>
<p>В общем, хотите тряхнуть восьмибитной стариной с паяльником в рукам - соберите Maximite.</p>
<hr class="docutils" />
<hr class="docutils" id="below" />
<p>Recently I have come across an interesting project - Maximite.</p>
<p>This is a micro-computer based on Microchip PIC32 running BASIC. It is so simple that even a novice can build it in a few hours.</p>
<img alt="http://geoffg.net/Images/Maximite/icon.jpg" src="http://geoffg.net/Images/Maximite/icon.jpg" />
<p>It is a bit more powerful than <a href="http://en.wikipedia.org/wiki/History_of_computer_hardware_in_Soviet_Bloc_countries#Radio-86RK">Radio-86RK</a> and ZX Spectrum 48. But its peripherals are fantastic: SD/FAT card, USB, VGA, PS/2, timers, RS232, I2C, SPI, PWM, ADC/DAC and individial general purpose pins.</p>
<p>If you build it on a mock up board buying parts by youself, it will cost less then ten Australian dollars.</p>
<p>The <a href="http://geoffg.net/maximite.html">project</a> is open-sourced (schematics, PCB artwork, sources).</p>
<p>Even if quickly flip through the <a href="http://geoffg.net/Downloads/Maximite/Maximite%20User%20Manual%20V3.0.pdf">documentation</a>, no doubts - a list features is impressive. All peripherals are available directly from BASIC.</p>
<p>Programs and data can be stored on a SD card. If there is a "AUTORUN.BAS" file on the card, BASIC will run at the start.</p>
<p>I liked Maximite, but soldering is not my favourite activity. Unfortunately it is only possible to buy a kit, but not a fully assembled unit.</p>
<p>I ordered the kit from <a href="http://www.altronics.com.au/index.asp?area=item&id=K9550">Altronics</a> and soon after it arrived.</p>
<p>Only the microprocessor was already soldered because soldering such form factor chip isn’t an easy task.</p>
<p>Anyway, screw it, let’s do it.</p>
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0099.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0099.jpg" />
<p>Here a few parts are already in place. I’m not a complete newbie in soldering but last time I took a soldering iron in my hands was about five years ago. I had no acid for soldering, so I was crumbling rosin right to soldering points. The effect is similar to acid. The soldering iron (the one on the plate) with a sharp sting.</p>
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0102.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0102.jpg" />
<p>I spent the first hour struggling with only a few parts, but eventually it went smoother.</p>
<p>A half is ready.</p>
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0103.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0103.jpg" />
<p>After one more hour it was all done.</p>
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0106.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0106.jpg" />
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0107.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0107.jpg" />
<p>Maximite can be powered from an external 9V source or form USB. I used USB.</p>
<p>Plug into USB and VGA. An off you go!</p>
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0110.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0110.jpg" />
<p>BASIC is ready but there is no keyboard. I hand’t a proper PS/2 one and I tried a USB-PS/2 connector. Alas, it didn’t fit.</p>
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0111.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0111.jpg" />
<p>Next day I found the PS/2 keyboard and finally connected.</p>
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0119.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0119.jpg" />
<p>The case.</p>
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0114.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0114.jpg" />
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0115.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0115.jpg" />
<p>Fully assembled.</p>
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0112.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0112.jpg" />
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0113.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0113.jpg" />
<p>I have to admit - the kit from Altronics is a very good quality product. The holes are metallized on the board, and the case fits perfectly.</p>
<p>Then I had to upgrade the firmware to the latest version. Maximite can flash itself over USB without a special programmer. Just open the case and hold a special button when swithing Maximite on. It goes to a boot loader mode.</p>
<p>Maxitite is a standard CDC device in USB infrastructure. Windows still requires a driver though, but Mac has it built-in.</p>
<p>Plug-in.</p>
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0116.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0116.jpg" />
<p>Flashing.</p>
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0118.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/img_0118.jpg" />
<p>Right, the firmware is upgraded up to 3.0A.</p>
<p>As I said, Maximite supports VGA and PS/2, but you can also connect it to a PC via USB. In this case Maximite mirrors the VGA output to that serial connection to the PC, also treats the data coming from that connection as keyboard input.</p>
<p>So, it is possible to detach VGA and PS/2 at all and talk to Maximite over the serial USB connection only.</p>
<p>For example, VGA dispay (voltmeter):</p>
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/dsc01130.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/dsc01130.jpg" />
<p>The same data on in a terminal emulation application on the PC:</p>
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/dsc01129.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/dsc01129.jpg" />
<p>Interestingly, Maximite works with pixels, not characters. So when a character is being displayed, it is also copied to the console, but when Maxitile draws graphics it is not visible in the serial console.</p>
<p>BASIC language in Maximite gives full control over the peripherals using operators.</p>
<p>There is an archive of BASIC programs running on Maximite available of the project website.</p>
<p>There are a few screenshots.</p>
<p>Clock.</p>
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/dsc01125.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/dsc01125.jpg" />
<p>Character editor.</p>
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/dsc01123.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/dsc01123.jpg" />
<p>Voltmeter.</p>
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/dsc01132.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/dsc01132.jpg" />
<p>Puzzles.</p>
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/dsc01128.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/dsc01128.jpg" />
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/dsc01133.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/dsc01133.jpg" />
<p>I believe, no comment here.</p>
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/dsc01126.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/dsc01126.jpg" />
<img alt="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/dsc01131.jpg" src="http://github.com/begoon/blog/raw/master/2012_01_19_maximite/dsc01131.jpg" />
<p>Conclusion</p>
<p>Every penny I have spent on Maximite is worth that fun I’ve got.</p>
<p>The Maximite project is surprisingly solid. Everything is nice and simple. And it works!</p>
<p>For beginners, even kids, interested in microelectronics, Maximite is simply a godsend. Easy and nice to build. I as an amateur have built everything in a few hours only.</p>
<p>When my brother was building <a href="http://radio86.googlecode.com/hg/online/radio86.html">Radio-86RK</a> and Spectrum about twenty years ago, there was a joke about DIY projects published in radio electronics magazines: if a author says that his device doesn’t required any tuning, there is at least a little chance to get it working; but the author says that his device does require some minor tuning...</p>
<p>Anyway, if you want to come back to your 8-bit youth with a soldering iron in hands — build Maximite.</p>Александрhttp://www.blogger.com/profile/03980297457924475954noreply@blogger.com0tag:blogger.com,1999:blog-3940972473404160061.post-84660048000684420852012-01-05T17:09:00.000-08:002012-01-05T17:09:04.380-08:00Stuck process detector / Монитор зависших процессов<p>The english version of the post is <a class="reference internal" href="#below">below</a>.</p>
<p>————————</p>
<p>Есть задача - нужна утилита для обнаружения зависших или заблокированных долгоиграющих серверных процессов. Если процесс «завис» - это значит, либо он торчит в deadlock’e, либо крутится в бесконечном цикле.</p>
<p>Пока есть вот такая идея - для каждого процесса, находящегося под контролем, периодически делать извне снимок стeка. Например:</p>
<pre class="literal-block">
#0 0x991a8c22 in mach_msg_trap ()
#1 0x991a81f6 in mach_msg ()
#2 0x968870ea in __CFRunLoopServiceMachPort ()
#3 0x96890214 in __CFRunLoopRun ()
#4 0x9688f8ec in CFRunLoopRunSpecific ()
#5 0x9688f798 in CFRunLoopRunInMode ()
#6 0x92158a7f in RunCurrentEventLoopInMode ()
#7 0x9215fd9b in ReceiveNextEventCommon ()
#8 0x9215fc0a in BlockUntilNextEventMatchingListInMode ()
#9 0x90010040 in _DPSNextEvent ()
#10 0x9000f8ab in -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] ()
#11 0x9000bc22 in -[NSApplication run] ()
#12 0x902a018a in NSApplicationMain ()
#13 0x0012e356 in main ()
</pre>
<p>Для Linux, HPUX и Solaris есть команда <em>pstack</em>, для AIX - <em>procstack</em>. Уверен, что и для Windows можно подобное замутить. Process Explorer это умеет делать, значит можно сделать и программно.</p>
<p>Сравнивая текущий снимок с предыдущим, можно понять, насколько он изменился. Если он вообще не изменился или изменился только по некоторым начальным функциям (например, внутри ядра), то можно предположить, что процесс «завис». Случай deadlock’а на файле или базе данных еще проще, так как программа просто будет постоянно торчать на одной функции внутри ядра.</p>
<p>Понятно, что сравнение стеков должно все-таки учитывать особенности проверяемых процессов. Можно сделать его конфигурируемым, например, через регулярные выражения или скриптовой язык типа Lua.</p>
<p>Тема еще в том, что такой монитор не требует изменения в самом софте, и может быть написан на любом языке, например Руби или Питоне. По сути это просто работа с текстовыми данными.</p>
<p>Может я изобретаю велосипед?</p>
<p>—————————</p>
<p id="below">There is a problem — how to automatically detect stuck long running server processes? Say if a process is stuck it means there is a deadlock or it is spinning in an infinite loop.</p>
<p>An idea — periodically take a snapshot of the process stack trace. For instance:</p>
<pre class="literal-block">
#0 0x991a8c22 in mach_msg_trap ()
#1 0x991a81f6 in mach_msg ()
#2 0x968870ea in __CFRunLoopServiceMachPort ()
#3 0x96890214 in __CFRunLoopRun ()
#4 0x9688f8ec in CFRunLoopRunSpecific ()
#5 0x9688f798 in CFRunLoopRunInMode ()
#6 0x92158a7f in RunCurrentEventLoopInMode ()
#7 0x9215fd9b in ReceiveNextEventCommon ()
#8 0x9215fc0a in BlockUntilNextEventMatchingListInMode ()
#9 0x90010040 in _DPSNextEvent ()
#10 0x9000f8ab in -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] ()
#11 0x9000bc22 in -[NSApplication run] ()
#12 0x902a018a in NSApplicationMain ()
#13 0x0012e356 in main ()
</pre>
<p>For Linux, HPUX and Solaris there is a tool called <em>pstack</em>, and <em>procstack</em> on AIX. I’m sure it is possible to do the same on Windows because Process Explorer can do it.</p>
<p>Comparing the current stack trace with the previous one we can measure how much it has been changed. If the stack wasn’t changed at all or only a few deepest lines were changed (for example, inside the kernel), we may assume that this process is stuck. The deadlock on a file or database is even simpler because the code will be blocked on a function inside the kernel.</p>
<p>Of course, such detector has to be adjusted for specifics of the monitored processes. But it can be configurable via regular expressions or a script language as Lua, for instance.</p>
<p>The good thing is that such monitor doesn’t require any changes in the target software, and can be implemented on any language suitable for easy text parsing, for example, Ruby or Python.</p>
<p>Am I reinventing a wheel?</p>Александрhttp://www.blogger.com/profile/03980297457924475954noreply@blogger.com0tag:blogger.com,1999:blog-3940972473404160061.post-55684593692303595772012-01-04T16:08:00.000-08:002012-01-04T16:08:16.252-08:00Trade-off with const in legacy code / Форсировать ли const в старом коде<p>The English version of this post is <a class="reference internal" href="#below">below</a>.</p>
<p>————————</p>
<p>Битый час сегодня спорили с коллегой по следующему вопросу. Имеем код:</p>
<div class="highlight" style="background: #ffffff"><pre style="line-height: 125%"><span style="color: #445588; font-weight: bold">void</span> foo(T<span style="font-weight: bold">*</span> t) {
bar(t);
}
</pre></div>
<p>Проблема в том, что функция <em>bar</em> является legacy-функцией одной из наших старых библиотек, которую сейчас мы поменять не можем, и ее сигнатура: "void bar(T*)", то есть указатель-параметр <strong>не</strong> <em>const</em>. Но в реальности эта функция <strong>не</strong> меняет объект, на который указывает ее параметр.</p>
<p>Далее. Наш новый API, частью которого является <em>foo</em>, есть новейшая разработка, и должна быть спроектирована по уму. С точки зрения запланированной ответственности функции <em>foo</em>, она <strong>не</strong> должна менять объект, на который указывает <em>t</em>.</p>
<p>Я считаю, что код должен выглядеть так:</p>
<div class="highlight" style="background: #ffffff"><pre style="line-height: 125%"><span style="color: #445588; font-weight: bold">void</span> foo(<span style="font-weight: bold">const</span> T<span style="font-weight: bold">*</span> t) {
bar(<span style="font-weight: bold">const_cast<</span>T<span style="font-weight: bold">*></span>(t));
}
</pre></div>
<p>Мои аргументы: так как контракт функции <em>foo</em> говорит, что эта функция не будет менять объект, на который указывает указатель, то этот факт <strong>должен</strong> быть отражен в API использованием слова <em>const</em>. И не имеет никакого значения, что по какой-то причине реализация этой функции внутри использует старый код, который неграмотно написан. Да, из-за это приходится делать некрасивое приведение типов, снимая <em>const</em>. Но эта некрасивость локализована внутри <em>foo</em> и в целом не оказывает влияния на стройность нового кода. Более того - если в будущем можно будет отказаться от использования старой функции <em>bar</em>, то проблема вообще исчезнет.</p>
<p>А вот контр-аргумент коллеги: может так случиться, что из-за ошибки в <em>bar</em> константный аргумент функции <em>foo</em>, которая по идее не должна менять аргумент, будет таки изменен, и получится крайне неприятный баг. В итого надо сделать аргумент функции <em>foo</em> <strong>НЕ</strong> const (и приведение будет уже не нужно), тем самым явно показать конечному пользователю нового API, что не стоит вообще рассчитывать на константность параметра функции <em>foo</em>.</p>
<p>Мы так и не договорились, так как у меня был «прогиб» в плане возможного нарушения константности вне зависимости, что там есть красивый <em>const</em>, а в подходе коллеги было не ясно, как объяснить в документации по функции <em>foo</em> почему и как она может менять свой аргумент - сказать, что мол из-за особенностей <strong>реализации</strong> <em>foo</em> мы не можем гарантировать константность? Получается, что мы проблемой старого кода портим дизайн нового API.</p>
<p>Дилемма.</p>
<p>P.S. Есть еще один изотерический вариант: внутри <em>foo</em> делать глубокое копирование объекта <em>T</em> и уже его передавать по неконстантному указателю в <em>bar</em>. Лично я, если надо выбирать между быстрым, но «плохим» кодом, и медленным, но со стройным дизайном, чаще выбираю второе, так как завтра купленный более быстрый сервер ускорит хороший, но медленный код, но не сделает плохой код более понятным.</p>
<p>————————</p>
<p id="below">Today we argued an hour with a colleague regarding the following code:</p>
<div class="highlight" style="background: #ffffff"><pre style="line-height: 125%"><span style="color: #445588; font-weight: bold">void</span> foo(T<span style="font-weight: bold">*</span> t) {
bar(t);
}
</pre></div>
<p>The problem is that the function <em>bar</em> is a part of a legacy library which we cannot refactor right now. The signature of <em>bar</em> is «void bar(T*)». <em>T</em> is <strong>not</strong> <em>const</em>. But in reality <em>bar</em> never changes an object referenced by <em>t</em>. This is how it was implemented.</p>
<p>But <em>foo</em> is a part of a brand new API, and we want to make nice or clean. The contract of the function <em>foo</em> says that it doesn’t need to change its parameter.</p>
<p>I think the code should be like this:</p>
<div class="highlight" style="background: #ffffff"><pre style="line-height: 125%"><span style="color: #445588; font-weight: bold">void</span> foo(<span style="font-weight: bold">const</span> T<span style="font-weight: bold">*</span> t) {
bar(<span style="font-weight: bold">const_cast<</span>T<span style="font-weight: bold">*></span>(t));
}
</pre></div>
<p>Why? The contact of <em>foo</em> doesn’t require the pointer <em>t</em> to be non-const. We must reflect this in the API by making <em>t</em> <em>const</em>. It doesn’t matter that for some reason a particular implementation of <em>foo</em> is based on the legacy <em>bar</em> function not having <em>const</em> in the argument but never changing it. Yes, we have to use the ugly <em>const_cast</em> but this bad code is nicely isolated inside <em>foo</em> only and doesn’t affect our nice and clean brand new API. Moreover, if we refactor <em>foo</em> at some point and get rid of legacy <em>bar</em> at all, the problem will disappear completely.</p>
<p>Here is a counterargument from my colleague: it may turn out that the function <em>foo</em> can have a bug and accidentally change <em>t</em> even it is declared as <em>const</em>. The solution is to simply keep the argument of <em>foo</em> <strong>non</strong>-<em>const</em>. In this case we don’t need that cast, we explicitly show to an end user of <em>foo</em> that she should expect its parameter to be <em>const</em>, and eventually we never violate the contact of the function <em>foo</em>.</p>
<p>Eventually we haven’t agreed. My flaw is that <em>const</em> doesn’t really protect from side effects coming from legacy <em>bar</em> and the argument of <em>foo</em> may be changed regardless being <em>const</em>. My friend’s flaw is that it not easy to explain in the documentation how and why the argument of <em>foo</em> may be changed. Just because our particular implementation dictates this? Such approach spreads the drawback of the legacy code to our nice and shiny new code.</p>
<p>Dilemma.</p>
<p>P.S. There is another esoteric approach — to create a temporary deep copy of <em>T</em> inside <em>foo</em> and pass it to <em>bar</em> by non-const pointer. Personally if I have to choose between quick but badly designed code and slow but nicely written code I usually go for the second one. Tomorrow we can buy another faster computer and the slow code will be faster, but that computer will make the bad code better.</p>Александрhttp://www.blogger.com/profile/03980297457924475954noreply@blogger.com0tag:blogger.com,1999:blog-3940972473404160061.post-4334462945667951332011-12-27T09:24:00.000-08:002011-12-27T09:44:44.732-08:00Steve Jobs: The Exclusive Biography / Биография Стива Джобса от Уолтера Айзексона<p>Note: This post is in two languages. The English one is the second.</p>
<hr class="docutils" />
<p><a href="http://www.ozon.ru/context/detail/id/7363365/">Биография Стива Джобса от Уолтера Айзексона</a> от Уолтера Айзексона</p>
<a rel="lytebox" href="@http://static.ozone.ru/multimedia/books_covers/c200/1003652274.jpg@"><img src="http://static.ozone.ru/multimedia/books_covers/c200/1003652274.jpg" /></a>
<p>Я думал, что биографии читают только "старые люди", но эта книга доказала мне обратное. Поддавшись на рекламу, и ведомый моим недавно начавшимся увлечением продукций Apple, я начал читать.</p>
<p>Cначала это было похоже на пересказ фильма "<a href="http://www.imdb.com/title/tt0168122/">Пираты силиконовой долины</a>", но через пару глав я уже не мог оторваться.</p>
<p>Можно говорить, что это конъюнктура и попытка сыграть на ситуации, что Стив только что умер, но, несмотря на все эти предрассудки, я подсел практически сразу.</p>
<p>Уж не знаю, в чем тут дело, может просто автор мастер своего дела, но я так и не оторвался, пока не прочитал до конца.</p>
<p>Вывод: настоятельно рекомендую, даже для принципиальных нелюбителей Эппла.</p>
<hr class="docutils" />
<p><a href="http://www.amazon.co.uk/Steve-Jobs-Exclusive-Walter-Isaacson/dp/1408703742">Steve Jobs: The Exclusive Biography</a> by Walter Isaacson</p>
<a rel="lytebox" href="@http://ecx.images-amazon.com/images/I/510O6F6qUJL._SL500_AA300_.jpg@"><img src="http://ecx.images-amazon.com/images/I/510O6F6qUJL._SL500_AA300_.jpg" /></a>
<p>I thought that biographies are for "old people". This book has changed that mindset in me. Being driven by massive ads and recently emerged love with Apple products and philosophy I had started reading.</p>
<p>Initially it was like an expanded version of "<a href="http://www.imdb.com/title/tt0168122/">Pirates of Silicon Valley</a>" which I, frankly, liked, but as reading progressed I had just fallen in love with this book and weren't able to stop.</p>
<p>The book can be treated as conjuncture or just an attempt to leverage the situation that Steve has just passed away. I was fully biased but after the first chapter I was hooked.</p>
<p>It is fascinating reading. Maybe just because the author is talented, I don't know.</p>
<p>Conclusion: strongly recommend.</p>Александрhttp://www.blogger.com/profile/03980297457924475954noreply@blogger.com0tag:blogger.com,1999:blog-3940972473404160061.post-36459456732017131022011-12-24T06:26:00.000-08:002011-12-25T12:01:13.090-08:00The world is flat 3.0 / Плоский мир 3.0<p>Note: This post is in two languages. The English one is the second.</p>
<hr class="docutils" />
<p>Я снова вернулся к аудиокнигам. 40-50 минут в день по дороге на работу и потом обратно позволяют поглощать книги с приличной скоростью.</p>
<p>Из недавнего.</p>
<p>"<a href="http://www.amazon.com/World-Flat-3-0-History-Twenty-first/dp/0312425074/">The world is flat 3.0: A Brief History of the Twenty-first Century</a>", Thomas L. Friedman</p>
<a rel="lytebox" href="@http://g-ecx.images-amazon.com/images/G/01/ciu/04/45/40d781b0c8a0118e2b20a110.L.jpg@"><img src="http://g-ecx.images-amazon.com/images/G/01/ciu/04/45/40d781b0c8a0118e2b20a110.L.jpg" /></a>
<p>Убийственная книга для осознания, что:</p>
<ul class="simple">
<li>сейчас индивидуумы могут спокойно конкурировать с корпорациями</li>
<li>важность инженерного, а особенно компьютерного, образования растет семимильными шагами, и это не дань моде, а объективная реальность</li>
<li>количество мест на планете, где можно жить и зарабатывать достойные деньги и развиваться уже не сужается к Штатами (разве не забавно слышать такое от коренного американца-консерватора) и некоторыми странам Европы</li>
<li>Индия, Китай, Россия и многие другие страны начали сильнейшую конкурецию на рынке труда с тем же США уже без массового отъезда специалистов</li>
<li>постоянное самообразование - это едиственный способ не быть вытолкнутым с рынка труда</li>
</ul>
<p>И многое многое другое.</p>
<p>Не буду скрывать, были моменты в жизни, когда я думал, что занимаюсь чем-то не тем (хотя профессию я не выбирал, она сама меня выбрала), и лучше бы мне работать, например, в области недвижимости, природных ресурсов, рекламы или медиа. Если у кого-то есть хоть минимальные подобные сомнения - это книга вытрет их навсегда и, возможно, подскажет путь.</p>
<p>Это очень интересное и познавательное чтиво.</p>
<hr class="docutils" />
<p>I've come back to audiobooks. 40-50 minutes per day when heading an office and then back allow to consume books with decent speed.</p>
<p>A recent.</p>
<p>"<a href="http://www.amazon.com/World-Flat-3-0-History-Twenty-first/dp/0312425074/">The world is flat 3.0: A Brief History of the Twenty-first Century</a>", Thomas L. Friedman</p>
<a rel="lytebox" href="@http://g-ecx.images-amazon.com/images/G/01/ciu/04/45/40d781b0c8a0118e2b20a110.L.jpg@"><img src="http://g-ecx.images-amazon.com/images/G/01/ciu/04/45/40d781b0c8a0118e2b20a110.L.jpg" /></a>
<p>This is a killer book to understand or even discover that nowadays:</p>
<ul class="simple">
<li>individuals can compete with corporations</li>
<li>importance of engineering and especially computer education is increasing enormously</li>
<li>number of places on the Earth when you can have decent life doing what you love to do is not narrowed to the US and a few EU countries anymore</li>
<li>India, China, Russia and many other countries have a very strong position competing with even US now <em>without</em> immigration</li>
<li>permanent self education and nurturing your curiosity (CQ + PQ always greater that IQ) is the only way to remain valuable</li>
</ul>
<p>And many other topics.</p>
<p>Frankly, there were moments in my life when I doubted and thought I would be better off doing, for instance, real estate, natural resources, ads or media rather than software. If you have even a tiny similar concern this book will wipe it out forever, and maybe even show the way.</p>
<p>To conclude: very useful, interesting and fascinating reading.</p>Александрhttp://www.blogger.com/profile/03980297457924475954noreply@blogger.com0tag:blogger.com,1999:blog-3940972473404160061.post-17934846994406474602011-12-21T06:23:00.001-08:002011-12-21T06:23:55.355-08:00Виртуальные private-функции в C++ / Virtual private functions in C++<p>Note: This post is in two languages. The English one is the second.</p>
<hr class="docutils" />
<p>Наткнулся на интересный, как мне показалось, код. Там использовалась виртуальная private функция. Прием немного странный, но сейчас не об этом.</p>
<p>Сначала мне показалось, что такой код не должен компилироваться, так как если функция private, она недоступна для использования в дочерних классах. Наблюдался какой-то очередной пробел в моих знаниях по C++.</p>
<p>Я написал программу:</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span style="color: #BC7A00">#include <iostream></span>
<span style="color: #008000; font-weight: bold">class</span> <span style="color: #0000FF; font-weight: bold">A</span> {
<span style="color: #008000; font-weight: bold">public</span><span style="color: #666666">:</span>
<span style="color: #B00040">void</span> bar() { foo(); }
<span style="color: #008000; font-weight: bold">private</span><span style="color: #666666">:</span>
<span style="color: #008000; font-weight: bold">virtual</span> <span style="color: #B00040">void</span> foo() <span style="color: #666666">=</span> <span style="color: #666666">0</span>;
};
<span style="color: #008000; font-weight: bold">class</span> <span style="color: #0000FF; font-weight: bold">B</span><span style="color: #666666">:</span> <span style="color: #008000; font-weight: bold">public</span> A {
<span style="color: #008000; font-weight: bold">private</span><span style="color: #666666">:</span>
<span style="color: #008000; font-weight: bold">virtual</span> <span style="color: #B00040">void</span> foo() { std<span style="color: #666666">::</span>cout <span style="color: #666666"><<</span> <span style="color: #BA2121">"B::foo()"</span> <span style="color: #666666"><<</span> std<span style="color: #666666">::</span>endl; }
};
<span style="color: #B00040">int</span> main(<span style="color: #B00040">int</span> argc, <span style="color: #B00040">char</span><span style="color: #666666">*</span> argv[]) {
A<span style="color: #666666">*</span> a <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">new</span> B();
a<span style="color: #666666">-></span>bar();
<span style="color: #008000; font-weight: bold">delete</span> a;
<span style="color: #008000; font-weight: bold">return</span> <span style="color: #666666">0</span>;
}
</pre></div>
<p>И VS2010 и GCC прекрасно его съели, и программа печатает "B::foo()".</p>
<p>Напрашивание такое объяснение - механизм виртуальных функций (технически переопределение функций через vtable) - это runtime, а public/private - это compile time. Получается, что в compile time все законно, и разделение на private/protected/public не зависит от виртуальности функции, а в runtime класс B просто подставляет другую функцию через vtable уже вне зависимости от private/public.</p>
<hr class="docutils" />
<p>I have come across an interesting in my point of view bit of code. There was a virtual private function. The approach is odd at the first place and I thought it shouldn't even compile, but surprisingly it did. I felt that this was yet another gap in my C++.</p>
<p>I wrote this code:</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span style="color: #BC7A00">#include <iostream></span>
<span style="color: #008000; font-weight: bold">class</span> <span style="color: #0000FF; font-weight: bold">A</span> {
<span style="color: #008000; font-weight: bold">public</span><span style="color: #666666">:</span>
<span style="color: #B00040">void</span> bar() { foo(); }
<span style="color: #008000; font-weight: bold">private</span><span style="color: #666666">:</span>
<span style="color: #008000; font-weight: bold">virtual</span> <span style="color: #B00040">void</span> foo() <span style="color: #666666">=</span> <span style="color: #666666">0</span>;
};
<span style="color: #008000; font-weight: bold">class</span> <span style="color: #0000FF; font-weight: bold">B</span><span style="color: #666666">:</span> <span style="color: #008000; font-weight: bold">public</span> A {
<span style="color: #008000; font-weight: bold">private</span><span style="color: #666666">:</span>
<span style="color: #008000; font-weight: bold">virtual</span> <span style="color: #B00040">void</span> foo() { std<span style="color: #666666">::</span>cout <span style="color: #666666"><<</span> <span style="color: #BA2121">"B::foo()"</span> <span style="color: #666666"><<</span> std<span style="color: #666666">::</span>endl; }
};
<span style="color: #B00040">int</span> main(<span style="color: #B00040">int</span> argc, <span style="color: #B00040">char</span><span style="color: #666666">*</span> argv[]) {
A<span style="color: #666666">*</span> a <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">new</span> B();
a<span style="color: #666666">-></span>bar();
<span style="color: #008000; font-weight: bold">delete</span> a;
<span style="color: #008000; font-weight: bold">return</span> <span style="color: #666666">0</span>;
}
</pre></div>
<p>VS2010 and GCC compile it perfectly and it prints out "B::foo()".</p>
<p>I have concluded that the virtual function mechanism usually implemented via vtable is runtime, but public/private is compile time, and they don't depend on each other.</p>Александрhttp://www.blogger.com/profile/03980297457924475954noreply@blogger.com0tag:blogger.com,1999:blog-3940972473404160061.post-28917057993315815772011-12-18T17:30:00.000-08:002011-12-18T17:30:52.434-08:00Ведение блога на GitHub / GitHub as a blog engine<p>Note: This post is an attempt to adopt a technique of creating posts in two languages. Instead of maintaining two separate blogs I want to kill two birds with one stone – still write on my native language for majority of the readers and plus have an opportunity to practice in English with a few English speaking readers. The post has two parts. The second is a translation to English. Any feedback regarding the language is appreciated, even in comments.</p>
<hr class="docutils" />
<p>Сказать, что Blogspot меня бесит – это ничего не сказать. Единственное для чего он нужен, как мне кажется – это быстрая индексация в Google.</p>
<p>Артемий Лебедев как-то отлично сказал, что презирает всякую хрень типа <a href="http://en.wikipedia.org/wiki/Search_engine_optimization">SEO</a>, так как надо создавать интересный и читаемый контент, а не суетиться по мелочи на его раздаче. Поэтому его <a href="http://tema.livejournal.com/">ЖЖ</a> использует стандартный шаблон без каких-либо попыток выглядеть “клевым”. Но его контент делает блог одним из лидеров в российском прокате.</p>
<p>Да и кого сейчас волнует дизайн блога? Все равно подавляющее количество читателей видят твой блог через призму Google Reader’а.</p>
<p>Но оставим одиозного Лебедева и вернемся к нашим специализированным техническим блогам. Как <a href="http://tom.preston-werner.com/2008/11/17/blogging-like-a-hacker.html">написал</a> Том Престон-Вернер, один их основателей Github, что ведя блог, он хочем <em>писать</em> посты, а не подкручивать там и сям шаблоны и прочие техдетали всяких WordPress’ов и Mephisto’в.</p>
<p>Подобная же мысль мучает меня с первого дня использования Блогспота. Только недавно я более менее устаканил процесс написания постов, используя <a href="http://docutils.sourceforge.net/docs/user/rst/quickref.html">ReST</a>. Сейчас я пишу и храню посты в этой разметке, а перед публикацией прогоняю через пару доморощенным скриптов типа “ReST > HTML > Фильтрованный Для Блогспота HTML”. Хотя проблема хостинга картинок все равно решается вручную заранее.</p>
<p>Уже сотни раз я подумывал о собственной платформе на том же WordPress’е, но природная лень и нежелание тратить ни секунды на администрирование всегда останавливало.</p>
<p>Сейчас у меня очередной приступ ненависти к Блогспоту и, как следствие, исследование альтернатив.</p>
<p>Удивительно, но как-то никогда не задумывался, что блог может на быть <a href="http://www.subspacefield.org/~travis/static_blog_generators.html">статическом движке</a>.</p>
<p>А что, если переехать на <a href="http://pages.github.com/">GitHub Pages</a>? Там суть в том, что один из твоих репозиториев может стать вебсайтом, который работает на статическом движке <a href="http://jekyllrb.com/">Jekyll</a>.</p>
<p>Сразу убиваются несколько зайцев. Работаешь в нормальной разметке и используешь git для выкладывания постов. Пишешь и отлаживаешь пост локально. Затем “git push origin master” и все – пост выложен. Текст можно писать не в идиотском HTML, а в <a href="http://daringfireball.net/projects/markdown/syntax">Markdown</a> или <a href="http://en.wikipedia.org/wiki/Textile_(markup_language)">Textile</a>. ReST, конечно, круче, но это не смертельно.</p>
<p>Более того GitHub Pages позволяет интегрироваться с полноценным доменом второго уровня.</p>
<p>Далее тема комментариев. Не то, чтобы программировать свой движок для комментирования, а даже просто настроить WordPress – лично у меня нет никакого желания. Поэтому одна их самых простых альтернатив – <a href="http://disqus.com">Disqus</a>.</p>
<p>Анализ посещаемости решается через Google Analytics.</p>
<p>Что остается?</p>
<p>Иногда люди таки ходят на сайт блога напрямую – для поиска старых постов или узнать об авторе что-нибудь социальное. Вот тут, конечно, всякие примочки типа гугловских гаджетов – поиск, каталог по датам, интеграция с социальными сетями и т.д. – имеют смысл. На Блогспоте ты их добавляешь кликом мышки, а для собственного блога надо будет тратить реальное время.</p>
<p>Но, возвращаясь к вопросу – а нужны ли все эти гаджеты? Если контент в блоге интересен – он найдет своего читателя. Сарафанное радио в виде твитера или фейсбука приведет тебе читателей, если будет что читать.</p>
<p>А если уж говорить на “раскрутке” – та же публикация удавшихся постов на Харбе приводит в сто раз более читателей, чем суета с дизайном сайта.</p>
<p>Вот такие мысли.</p>
<hr class="docutils" />
<p>To say that Blogspot (Blogger) infuriates me is to say nothing. The only benefit of it is fast indexing by Google.</p>
<p>Artemy Lebedev said that he despises all this <a href="http://en.wikipedia.org/wiki/Search_engine_optimization">SEO</a> bullshit because it is much more productive to focus on creating great posts rather than thinking how to attract more readers. His <a href="http://tema.livejournal.com/">LJ</a> uses a default template without even minor tweaks to make it looking “cool”. Despite of this his blog is in Russian Top 10.</p>
<p>Nobody reads blogs directly nowadays. Everybody uses Google Reader or other aggregators making the design of blogs absolutely pointless.</p>
<p>Anyway let’s leave odious Lebedev and come back to our techy blogs. Tom Preston-Werner, one of the Github founders, <a href="http://tom.preston-werner.com/2008/11/17/blogging-like-a-hacker.html">said</a> that he wanted to write posts but not tweaking different templates or keeping the version of WordPress or Mephisto up to date.</p>
<p>A similar thought haunts me from the day one of using Blogspot. Only recently I have sorted a way of creating post by using <a href="http://docutils.sourceforge.net/docs/user/rst/quickref.html">ReST</a>. Now I write posts in this markup and convert to HTML before publishing by a few handcrafted scripts. Unfortunately hosting for images is not automated in anyway.</p>
<p>Many times I wanted to migrate to a standalone platform, for example, WordPress. But my laziness and unwillingness to spend even a second on its maintenance always stopped me.</p>
<p>At the moment I have another attack of hate to Blogspot and as a consequence look for alternatives.</p>
<p>Surprisingly I never considered using <a href="http://www.subspacefield.org/~travis/static_blog_generators.html">static blog engines</a>.</p>
<p>What if just simply migrate to <a href="http://pages.github.com/">GitHub Pages</a>? It converts one of your repositories to a website which can be also processed by <a href="http://jekyllrb.com/">Jekyll</a>, a static engine from Tom Preston-Werner.</p>
<p>I could kill a few birds with one stone – to use a proper markup language, <a href="http://daringfireball.net/projects/markdown/syntax">Markdown</a> or <a href="http://en.wikipedia.org/wiki/Textile_(markup_language)">Textile</a>, instead of bloody HTML and to manage publishing by git. Of course ReST is better but I can cope with it.</p>
<p>Also GitHub Pages can be integrated with your own domain if needed.</p>
<p>Comments and discussions. <a href="http://disqus.com">Disqus</a> seems to be an easiest way to sort it without any hassle.</p>
<p>Google Analytics perfectly works with any engine where you can insert their JavaScript hook into pages.</p>
<p>What is still missing?</p>
<p>Sometimes people still visit blogs directly, for instance, to find previous posts or explore “social” details. In this case all these bells and whistles in a form of JavaScript gadgets are very useful and save a lot of time. Blogspot allows adding them in a few clicks.</p>
<p>But coming back to the question at the beginning – do I really need them? If the content is interesting the audience will inevitably find you. A word of mouth in a form of Twitter or Facebook will attract people. But if the content is crap all those bells and whistles (and SEO) will not help.</p>Александрhttp://www.blogger.com/profile/03980297457924475954noreply@blogger.com0tag:blogger.com,1999:blog-3940972473404160061.post-8396875508787975052011-12-10T16:23:00.001-08:002011-12-10T16:25:06.274-08:00Задача расположения восьми ферзей на Erlang'e<p>Знаю, что <a href="http://en.wikipedia.org/wiki/Eight_queens_puzzle">баян</a>, но для меня было весьма показательно.</p>
<p>Например, вот вариант, который я написал где-то за полчаса:</p>
<div class="highlight" style="background: #ffffff"><pre style="line-height: 125%">-<span style="color: #800080">module</span>(queens_classic).
-<span style="color: #800080">export</span>([solve<span style="font-weight: bold">/</span><span style="color: #009999">0</span>]).
<span style="color: #990000; font-weight: bold">solve</span>() <span style="font-weight: bold">-></span>
solve(<span style="color: #555555">lists</span>:seq(<span style="color: #009999">1</span>, <span style="color: #009999">8</span>), <span style="color: #555555">lists</span>:seq(<span style="color: #009999">1</span>, <span style="color: #009999">15</span> <span style="font-weight: bold">+</span> <span style="color: #009999">15</span>), <span style="color: #009999">1</span>, []).
<span style="color: #990000; font-weight: bold">print_board</span>([]) <span style="font-weight: bold">-></span> <span style="color: #555555">io</span>:format(<span style="color: #bb8844">"~n"</span>, []);
<span style="color: #990000; font-weight: bold">print_board</span>([<span style="color: #008080">H</span>|<span style="color: #008080">T</span>]) <span style="font-weight: bold">-></span>
<span style="color: #008080">Line</span> <span style="font-weight: bold">=</span> [<span style="color: #555555">string</span>:copies(<span style="color: #bb8844">". "</span>, <span style="color: #008080">H</span> <span style="font-weight: bold">-</span> <span style="color: #009999">1</span>), <span style="color: #bb8844">"@ "</span>, <span style="color: #555555">string</span>:copies(<span style="color: #bb8844">". "</span>, <span style="color: #009999">8</span> <span style="font-weight: bold">-</span> <span style="color: #008080">H</span>)],
<span style="color: #555555">io</span>:format(<span style="color: #bb8844">"~s~n"</span>, [<span style="color: #008080">Line</span>]),
print_board(<span style="color: #008080">T</span>).
<span style="color: #990000; font-weight: bold">solve</span>(_, _, <span style="color: #008080">Cols</span>, <span style="color: #008080">Result</span>) <span style="font-weight: bold">when</span> <span style="color: #008080">Cols</span> <span style="font-weight: bold">></span> <span style="color: #009999">8</span> <span style="font-weight: bold">-></span>
<span style="color: #555555">io</span>:format(<span style="color: #bb8844">"~p~n"</span>, [<span style="color: #008080">Result</span>]),
print_board(<span style="color: #008080">Result</span>);
<span style="color: #990000; font-weight: bold">solve</span>(<span style="color: #008080">Rows</span>, <span style="color: #008080">Diags</span>, <span style="color: #008080">Col</span>, <span style="color: #008080">Result</span>) <span style="font-weight: bold">-></span>
<span style="color: #555555">lists</span>:foreach(<span style="font-weight: bold">fun</span>(<span style="color: #008080">Row</span>) <span style="font-weight: bold">-></span>
<span style="color: #008080">D1</span> <span style="font-weight: bold">=</span> <span style="color: #008080">Row</span> <span style="font-weight: bold">+</span> <span style="color: #008080">Col</span>,
<span style="color: #008080">D2</span> <span style="font-weight: bold">=</span> <span style="color: #008080">Row</span> <span style="font-weight: bold">-</span> <span style="color: #008080">Col</span> <span style="font-weight: bold">+</span> <span style="color: #009999">8</span> <span style="font-weight: bold">+</span> <span style="color: #009999">15</span>,
<span style="color: #008080">T</span> <span style="font-weight: bold">=</span> <span style="color: #555555">lists</span>:member(<span style="color: #008080">Row</span>, <span style="color: #008080">Rows</span>) <span style="font-weight: bold">andalso</span>
<span style="color: #555555">lists</span>:member(<span style="color: #008080">D1</span>, <span style="color: #008080">Diags</span>) <span style="font-weight: bold">andalso</span>
<span style="color: #555555">lists</span>:member(<span style="color: #008080">D2</span>, <span style="color: #008080">Diags</span>),
<span style="font-weight: bold">if</span> <span style="color: #008080">T</span> <span style="font-weight: bold">-></span>
<span style="color: #008080">Rows1</span> <span style="font-weight: bold">=</span> <span style="color: #008080">Rows</span> <span style="font-weight: bold">--</span> [<span style="color: #008080">Row</span>],
<span style="color: #008080">Diags1</span> <span style="font-weight: bold">=</span> <span style="color: #008080">Diags</span> <span style="font-weight: bold">--</span> [<span style="color: #008080">D1</span>, <span style="color: #008080">D2</span>],
solve(<span style="color: #008080">Rows1</span>, <span style="color: #008080">Diags1</span>, <span style="color: #008080">Col</span> <span style="font-weight: bold">+</span> <span style="color: #009999">1</span>, [<span style="color: #008080">Row</span> | <span style="color: #008080">Result</span>]);
true <span style="font-weight: bold">-></span> void
<span style="font-weight: bold">end</span>
<span style="font-weight: bold">end</span>, <span style="color: #008080">Rows</span>).
</pre></div>
<p>Выглядит ужасно, и стиль однозначно понятно какой: C/Python на стероидах (циклы, if'ы).</p>
<p>А вот над этим вариантом я провозился несколько часов:</p>
<div class="highlight" style="background: #ffffff"><pre style="line-height: 125%">-<span style="color: #800080">module</span>(queens).
-<span style="color: #800080">export</span>([solve<span style="font-weight: bold">/</span><span style="color: #009999">0</span>]).
<span style="color: #990000; font-weight: bold">solve</span>() <span style="font-weight: bold">-></span>
solve(<span style="color: #009999">1</span>, []).
<span style="color: #990000; font-weight: bold">print_board</span>([]) <span style="font-weight: bold">-></span> <span style="color: #555555">io</span>:format(<span style="color: #bb8844">"~n"</span>, []);
<span style="color: #990000; font-weight: bold">print_board</span>([{_<span style="color: #008080">X</span>, <span style="color: #008080">Y</span>}|<span style="color: #008080">T</span>]) <span style="font-weight: bold">-></span>
<span style="color: #008080">Line</span> <span style="font-weight: bold">=</span> [<span style="color: #555555">string</span>:copies(<span style="color: #bb8844">". "</span>, <span style="color: #008080">Y</span> <span style="font-weight: bold">-</span> <span style="color: #009999">1</span>), <span style="color: #bb8844">"@ "</span>, <span style="color: #555555">string</span>:copies(<span style="color: #bb8844">". "</span>, <span style="color: #009999">8</span> <span style="font-weight: bold">-</span> <span style="color: #008080">Y</span>)],
<span style="color: #555555">io</span>:format(<span style="color: #bb8844">"~s~n"</span>, [<span style="color: #008080">Line</span>]),
print_board(<span style="color: #008080">T</span>).
<span style="color: #990000; font-weight: bold">solve</span>(<span style="color: #008080">X</span>, <span style="color: #008080">Taken</span>) <span style="font-weight: bold">when</span> <span style="color: #008080">X</span> <span style="font-weight: bold">></span> <span style="color: #009999">8</span> <span style="font-weight: bold">-></span>
<span style="color: #555555">io</span>:format(<span style="color: #bb8844">"~p~n"</span>, [<span style="color: #008080">Taken</span>]),
print_board(<span style="color: #008080">Taken</span>);
<span style="color: #990000; font-weight: bold">solve</span>(<span style="color: #008080">X</span>, <span style="color: #008080">Taken</span>) <span style="font-weight: bold">-></span>
<span style="color: #008080">L</span> <span style="font-weight: bold">=</span> [{<span style="color: #008080">X</span>, <span style="color: #008080">Y</span>} || <span style="color: #008080">Y</span> <span style="font-weight: bold"><-</span> <span style="color: #555555">lists</span>:seq(<span style="color: #009999">1</span>, <span style="color: #009999">8</span>), <span style="font-weight: bold">not</span> under_attack({<span style="color: #008080">X</span>, <span style="color: #008080">Y</span>}, <span style="color: #008080">Taken</span>)],
row(<span style="color: #008080">L</span>, <span style="color: #008080">Taken</span>).
<span style="color: #990000; font-weight: bold">row</span>([], _) <span style="font-weight: bold">-></span> [];
<span style="color: #990000; font-weight: bold">row</span>([{<span style="color: #008080">X</span>, <span style="color: #008080">Y</span>}|<span style="color: #008080">L</span>], <span style="color: #008080">Taken</span>) <span style="font-weight: bold">-></span>
solve(<span style="color: #008080">X</span> <span style="font-weight: bold">+</span> <span style="color: #009999">1</span>, [{<span style="color: #008080">X</span>, <span style="color: #008080">Y</span>} | <span style="color: #008080">Taken</span>]),
row(<span style="color: #008080">L</span>, <span style="color: #008080">Taken</span>).
<span style="color: #990000; font-weight: bold">under_attack</span>(_, []) <span style="font-weight: bold">-></span> false;
<span style="color: #990000; font-weight: bold">under_attack</span>({<span style="color: #008080">X</span>, <span style="color: #008080">Y</span>}, [{<span style="color: #008080">Xt</span>, <span style="color: #008080">Yt</span>}|<span style="color: #008080">L</span>]) <span style="font-weight: bold">-></span>
<span style="color: #008080">Y</span> <span style="font-weight: bold">==</span> <span style="color: #008080">Yt</span> <span style="font-weight: bold">orelse</span> <span style="color: #999999">abs</span>(<span style="color: #008080">Y</span> <span style="font-weight: bold">-</span> <span style="color: #008080">Yt</span>) <span style="font-weight: bold">==</span> <span style="color: #999999">abs</span>(<span style="color: #008080">X</span> <span style="font-weight: bold">-</span> <span style="color: #008080">Xt</span>) <span style="font-weight: bold">orelse</span>
under_attack({<span style="color: #008080">X</span>, <span style="color: #008080">Y</span>}, <span style="color: #008080">L</span>).
</pre></div>
<p>Вся работа со списками вручную без циклоподобных конструкций.</p>
<p>Печатает типа такого:</p>
<pre class="literal-block">
[4,7,5,2,6,1,3,8]
. . . @ . . . .
. . . . . . @ .
. . . . @ . . .
. @ . . . . . .
. . . . . @ . .
@ . . . . . . .
. . @ . . . . .
. . . . . . . @
[5,7,2,6,3,1,4,8]
. . . . @ . . .
. . . . . . @ .
. @ . . . . . .
. . . . . @ . .
. . @ . . . . .
@ . . . . . . .
. . . @ . . . .
. . . . . . . @
...
</pre>
<p>Увы, но вот <a href="http://www.redaelli.org/matteo-blog/2009/01/05/n-queens-solution-with-erlang/">эта версия</a> мне кажется более красивой с точки зрения фукнционального стиля.</p>
<p>На всякий случай Makefile для обоих вариантов:</p>
<div class="highlight" style="background: #ffffff"><pre style="line-height: 125%"><span style="color: #008080">target</span> <span style="font-weight: bold">=</span> queens
all:
erlc <span style="font-weight: bold">$(</span>target<span style="font-weight: bold">)</span>.erl
erl -noshell -s <span style="font-weight: bold">$(</span>target<span style="font-weight: bold">)</span> solve -s init stop
classic:
erlc <span style="font-weight: bold">$(</span>target<span style="font-weight: bold">)</span>_classic.erl
erl -noshell -s <span style="font-weight: bold">$(</span>target<span style="font-weight: bold">)</span>_classic solve -s init stop
clean:
-rm *.beam *.dump
</pre></div>Александрhttp://www.blogger.com/profile/03980297457924475954noreply@blogger.com0tag:blogger.com,1999:blog-3940972473404160061.post-86157291035320539102011-12-07T02:11:00.001-08:002011-12-07T02:12:49.930-08:00Visual Studio 11 Developer Preview<p>Поставил на рабочий ноут Visual Studio 11 Developer Preview.</p>
<p>Погонял разные самопальные бенчмарки типа решета Эратосфена, vector<int> vs vector<bool>, std::string vs char* и т.д., пытаясь выявить улучшения или ухудшения в оптимизации. Лично я ничего кардинального не выявил по сравнению с версией 10.</p>
<p>Очевидно, что статический анализ кода и его безопасность в целом сейчас как никогда в моде, поэтому производители компиляторов постепенно закручивают гайки, превращая предупреждения в ошибки.</p>
<p>Например с ключом "/sdl" Студия 11 будет считать приведенные ниже предупреждения ошибками.</p>
<table border="1" class="docutils">
<colgroup>
<col width="5%" />
<col width="13%" />
<col width="83%" />
</colgroup>
<thead valign="bottom">
<tr><th class="head">Warning</th>
<th class="head">Command line switch</th>
<th class="head">Description</th>
</tr>
</thead>
<tbody valign="top">
<tr><td><a href="http://msdn.microsoft.com/en-us/library/4kh09110.aspx">C4146</a></td>
<td>/we4146</td>
<td>A unary minus operator was applied to an unsigned type, resulting in an unsigned result</td>
</tr>
<tr><td><a href="http://msdn.microsoft.com/en-us/library/5ft2cz8d.aspx">C4308</a></td>
<td>/we4308</td>
<td>A negative integral constant converted to unsigned type, resulting in a possibly meaningless result</td>
</tr>
<tr><td><a href="http://msdn.microsoft.com/en-us/library/h6b9te7b.aspx">C4532</a></td>
<td>/we4532</td>
<td>Use of “continue”, “break” or “goto” keywords in a __finally/finally block has undefined behavior during abnormal termination</td>
</tr>
<tr><td><a href="http://msdn.microsoft.com/en-us/library/f7687yks.aspx">C4533</a></td>
<td>/we4533</td>
<td>Code initializing a variable will not be executed</td>
</tr>
<tr><td><a href="http://msdn.microsoft.com/en-us/library/axhfhh6x.aspx">C4700</a></td>
<td>/we4700</td>
<td>Use of an uninitialized local variable</td>
</tr>
<tr><td><a href="http://msdn.microsoft.com/en-us/library/w0c0bww3.aspx">C4789</a></td>
<td>/we4789</td>
<td>Buffer overrun when specific C run-time (CRT) functions are used</td>
</tr>
<tr><td><a href="http://msdn.microsoft.com/en-us/library/8wsycdzs.aspx">C4995</a></td>
<td>/we4995</td>
<td>Use of a function marked with pragma deprecated</td>
</tr>
<tr><td><a href="http://msdn.microsoft.com/en-us/library/ttcz0bys.aspx">C4996</a></td>
<td>/we4996</td>
<td>Use of a function marked as deprecated</td>
</tr>
</tbody>
</table>
<p>Ссылки по теме:</p>
<blockquote>
<ul class="simple">
<li>Оригинальный пост "<a href="http://blogs.msdn.com/b/sdl/archive/2011/12/02/security.aspx">Compiler Security Enhancements in Visual Studio 11</a>", кратким переводом которого по сути является этот пост.</li>
</ul>
</blockquote>Александрhttp://www.blogger.com/profile/03980297457924475954noreply@blogger.com0tag:blogger.com,1999:blog-3940972473404160061.post-80824311488008290882011-11-30T14:21:00.001-08:002011-11-30T14:22:48.461-08:00MapReduce на Erlang'e<p>Я продолжаю погружение в Эрланг. Уже есть хитрый план переписать один из наших сервисов для мониторинга на Эрланге. Мы тут осваиваем облака Windows Azure и Amazon EC2 в качестве платформы для некоторых продуктов и внутренних задач типа QA, поэтому возможность использовать много ядер и машин без переписывания кода выглядить перспективно.</p>
<p>Итак, для начала простой, но реальный пример - есть проект ~2000 файлов. Надо составить список используемых переменных окружения. То есть найти вхождения строк "getenv(...)" и "GetVariable(...)" (это наш wrapper) и выдрать из них параметр.</p>
<p>Задача незамысловатая и давно решается программой на C++, которая даже обход каталогов не делает, а просто вызывает юниксовый "find", генерирующий список
файлов по маске, и затем по списку лопатит файлы. На 2000 файлах работает пару секунд в один поток.</p>
<p>Теперь Эрланг. Тут хочется замутить что-нибудь более кучерявое, чем последовательный обход файлов. MapReduce как раз в тему - можно составить список файлов, затем анализ каждого файла делать параллельно (Map), аккумулируя найденные имена переменных, и в конце обработать все полученные входждение (Reduce), в нашем случае просто подсчитать количество вхождения каждой переменной.</p>
<p>Фактически мой код повторяет пример из "<a href="http://pragprog.com/book/jaerlang/programming-erlang">Programming Erlang</a>" и использует модуль phofs (parallel higher-order functions) из этой же книги.</p>
<div class="highlight" style="background: #ffffff"><pre style="line-height: 125%">-<span style="color: #800080">module</span>(find_variables).
-<span style="color: #800080">export</span>([main<span style="font-weight: bold">/</span><span style="color: #009999">0</span>, find_variables_in_file<span style="font-weight: bold">/</span><span style="color: #009999">2</span>, process_found_variables<span style="font-weight: bold">/</span><span style="color: #009999">3</span>]).
-<span style="color: #800080">define</span>(<span style="color: #008080">PATH</span>, <span style="color: #bb8844">"/Projects/interesting_project"</span>).
-<span style="color: #800080">define</span>(<span style="color: #008080">MASK</span>, <span style="color: #bb8844">"\\..*(cpp|c)"</span>).
<span style="color: #990000; font-weight: bold">main</span>() <span style="font-weight: bold">-></span>
<span style="color: #555555">io</span>:format(<span style="color: #bb8844">"Creating list of files...~n"</span>, []),
<span style="color: #999988; font-style: italic">% Стандартная функция обхода файловой системы. Последний параметр -</span>
<span style="color: #999988; font-style: italic">% функтор, накапливающий имена в списке.</span>
<span style="color: #008080">Files</span> <span style="font-weight: bold">=</span> <span style="color: #555555">filelib</span>:fold_files(<span style="color: #008080">?PATH</span>, <span style="color: #008080">?MASK</span>, true,
<span style="font-weight: bold">fun</span>(<span style="color: #008080">N</span>, <span style="color: #008080">A</span>) <span style="font-weight: bold">-></span> [<span style="color: #008080">N</span> | <span style="color: #008080">A</span>] <span style="font-weight: bold">end</span>, []),
<span style="color: #555555">io</span>:format(<span style="color: #bb8844">"Found ~b file(s)~n"</span>, [<span style="color: #999999">length</span>(<span style="color: #008080">Files</span>)]),
<span style="color: #008080">F1</span> <span style="font-weight: bold">=</span> <span style="font-weight: bold">fun</span> find_variables_in_file<span style="font-weight: bold">/</span><span style="color: #009999">2</span>, <span style="color: #999988; font-style: italic">% Map</span>
<span style="color: #008080">F2</span> <span style="font-weight: bold">=</span> <span style="font-weight: bold">fun</span> process_found_variables<span style="font-weight: bold">/</span><span style="color: #009999">3</span>, <span style="color: #999988; font-style: italic">% Reduce</span>
<span style="color: #999988; font-style: italic">% Вызываем MapReduce через функцию benchmark, считающую время</span>
<span style="color: #999988; font-style: italic">% выполнения.</span>
benchmark(<span style="font-weight: bold">fun</span>() <span style="font-weight: bold">-></span>
<span style="color: #008080">L</span> <span style="font-weight: bold">=</span> <span style="color: #555555">phofs</span>:mapreduce(<span style="color: #008080">F1</span>, <span style="color: #008080">F2</span>, [], <span style="color: #008080">Files</span>),
<span style="color: #555555">io</span>:format(<span style="color: #bb8844">"Found ~b variable(s)~n"</span>, [<span style="color: #999999">length</span>(<span style="color: #008080">L</span>)])
<span style="font-weight: bold">end</span>, <span style="color: #bb8844">"MapReduce"</span>).
<span style="color: #990000; font-weight: bold">benchmark</span>(<span style="color: #008080">Worker</span>, <span style="color: #008080">Title</span>) <span style="font-weight: bold">-></span>
{<span style="color: #008080">T</span>, _} <span style="font-weight: bold">=</span> <span style="color: #555555">timer</span>:tc(<span style="font-weight: bold">fun</span>() <span style="font-weight: bold">-></span> <span style="color: #008080">Worker</span>() <span style="font-weight: bold">end</span>),
<span style="color: #555555">io</span>:format(<span style="color: #bb8844">"~s: ~f sec(s)~n"</span>, [<span style="color: #008080">Title</span>, <span style="color: #008080">T</span><span style="font-weight: bold">/</span><span style="color: #009999">1000000</span>]).
-<span style="color: #800080">define</span>(<span style="color: #008080">REGEXP</span>, <span style="color: #bb8844">"(getenv|GetVariable)\s*\\(\s*\"([^\"]+)\"\s*\\)"</span>).
<span style="color: #999988; font-style: italic">% Map. Анализ одного файла.</span>
<span style="color: #990000; font-weight: bold">find_variables_in_file</span>(<span style="color: #008080">Pid</span>, <span style="color: #008080">FileName</span>) <span style="font-weight: bold">-></span>
<span style="font-weight: bold">case</span> <span style="color: #555555">file</span>:open(<span style="color: #008080">FileName</span>, [read]) <span style="font-weight: bold">of</span>
{ok, <span style="color: #008080">File</span>} <span style="font-weight: bold">-></span>
<span style="color: #999988; font-style: italic">% Заранее компилируем регулярное выражение.</span>
{_, <span style="color: #008080">RE</span>} <span style="font-weight: bold">=</span> <span style="color: #555555">re</span>:compile(<span style="color: #008080">?REGEXP</span>),
<span style="color: #999988; font-style: italic">% Данный обратный вызов пошлет родительскому контролирующему</span>
<span style="color: #999988; font-style: italic">% потому сообщение с именем найденной переменной.</span>
<span style="color: #008080">CallBack</span> <span style="font-weight: bold">=</span> <span style="font-weight: bold">fun</span>(<span style="color: #008080">Var</span>) <span style="font-weight: bold">-></span> <span style="color: #008080">Pid</span> <span style="font-weight: bold">!</span> {<span style="color: #008080">Var</span>, <span style="color: #009999">1</span>} <span style="font-weight: bold">end</span>,
find_variable_in_file(<span style="color: #008080">File</span>, <span style="color: #008080">RE</span>, <span style="color: #008080">CallBack</span>),
<span style="color: #555555">file</span>:close(<span style="color: #008080">File</span>);
{error, <span style="color: #008080">Reason</span>} <span style="font-weight: bold">-></span>
<span style="color: #555555">io</span>:format(<span style="color: #bb8844">"Unable to process '~s', ~p~n"</span>, [<span style="color: #008080">FileName</span>, <span style="color: #008080">Reason</span>]),
<span style="color: #999999">exit</span>(<span style="color: #009999">1</span>)
<span style="font-weight: bold">end</span>.
<span style="color: #999988; font-style: italic">% Reduce. Анализ данных. Данная функция вызывается контролирующим</span>
<span style="color: #999988; font-style: italic">% процессом MapReduce для каждого найденного ключа вместе со списком</span>
<span style="color: #999988; font-style: italic">% значений, ассоциированных с ним. В нашем случае это будут пары</span>
<span style="color: #999988; font-style: italic">% {VarName, 1}. Мы просто подсчитаем для каждого VarName количество</span>
<span style="color: #999988; font-style: italic">% пришедших пар, то есть количество найденных вхождений этой переменной.</span>
<span style="color: #999988; font-style: italic">% Это и есть наш незамысловатый анализ.</span>
<span style="color: #990000; font-weight: bold">process_found_variables</span>(<span style="color: #008080">Key</span>, <span style="color: #008080">Vals</span>, <span style="color: #008080">A</span>) <span style="font-weight: bold">-></span>
[{<span style="color: #008080">Key</span>, <span style="color: #999999">length</span>(<span style="color: #008080">Vals</span>)} | <span style="color: #008080">A</span>].
<span style="color: #999988; font-style: italic">% Построчный обход файла.</span>
<span style="color: #990000; font-weight: bold">find_variable_in_file</span>(<span style="color: #008080">File</span>, <span style="color: #008080">RE</span>, <span style="color: #008080">CallBack</span>) <span style="font-weight: bold">-></span>
<span style="font-weight: bold">case</span> <span style="color: #555555">io</span>:get_line(<span style="color: #008080">File</span>, <span style="color: #bb8844">""</span>) <span style="font-weight: bold">of</span>
eof <span style="font-weight: bold">-></span> void;
<span style="color: #008080">Line</span> <span style="font-weight: bold">-></span>
scan_line_in_file(<span style="color: #008080">Line</span>, <span style="color: #008080">RE</span>, <span style="color: #008080">CallBack</span>),
find_variable_in_file(<span style="color: #008080">File</span>, <span style="color: #008080">RE</span>, <span style="color: #008080">CallBack</span>)
<span style="font-weight: bold">end</span>.
<span style="color: #999988; font-style: italic">% Поиск строки в строке по регулярному выражению (скомпилированному ранее),</span>
<span style="color: #999988; font-style: italic">% и в случае нахождение вызов CallBack с передачей ему имени найденной</span>
<span style="color: #999988; font-style: italic">% переменной.</span>
<span style="color: #990000; font-weight: bold">scan_line_in_file</span>(<span style="color: #008080">Line</span>, <span style="color: #008080">RE</span>, <span style="color: #008080">CallBack</span>) <span style="font-weight: bold">-></span>
<span style="font-weight: bold">case</span> <span style="color: #555555">re</span>:run(<span style="color: #008080">Line</span>, <span style="color: #008080">RE</span>) <span style="font-weight: bold">of</span>
{match, <span style="color: #008080">Captured</span>} <span style="font-weight: bold">-></span>
[_, _, {<span style="color: #008080">NameP</span>, <span style="color: #008080">NameL</span>}] <span style="font-weight: bold">=</span> <span style="color: #008080">Captured</span>,
<span style="color: #008080">Name</span> <span style="font-weight: bold">=</span> <span style="color: #555555">string</span>:substr(<span style="color: #008080">Line</span>, <span style="color: #008080">NameP</span> <span style="font-weight: bold">+</span> <span style="color: #009999">1</span>, <span style="color: #008080">NameL</span>),
<span style="color: #008080">CallBack</span>(<span style="color: #008080">Name</span>);
nomatch <span style="font-weight: bold">-></span> void
<span style="font-weight: bold">end</span>.
</pre></div>
<p>Для сборки программы нужен <a href="http://media.pragprog.com/titles/jaerlang/code/phofs.erl">модуль phofs</a>. Он является универсальным, независимым от конкретных функций Map и Reduce.</p>
<p>И Makefile на всякий случай:</p>
<div class="highlight" style="background: #ffffff"><pre style="line-height: 125%"><span style="color: #008080">target</span> <span style="font-weight: bold">=</span> find_variables
all:
erlc <span style="font-weight: bold">$(</span>target<span style="font-weight: bold">)</span>.erl
erlc phofs.erl
erl -noshell -s <span style="font-weight: bold">$(</span>target<span style="font-weight: bold">)</span> main -s init stop
clean:
-rm *.beam *.dump
</pre></div>
<p>Пузомерка. Как я уже сказал, программа на C++ вместе со временем вызова "find" на моей машине работает 1-2 секунды. Версия на Erlang'e работает ~20 секунд. Плохо? Смотря как посмотреть. Если анализ каждого файла будет более длительным (то есть программа будет основное время тратить на анализ файла, а не обход каталогов), то тут уже не совсем очевидно, какое из решений будет более практично при увеличении числа файлов и сложности анализа.</p>
<p>Я новичок в Эрланге, поэтому будут признателен за критику кода.</p>
<p>Посты по теме:</p>
<blockquote>
<ul class="simple">
<li><a href="http://easy-coding.blogspot.com/2011/11/tcpip-proxy-erlange_26.html">TCP/IP proxy на Erlang'e</a></li>
</ul>
</blockquote>Александрhttp://www.blogger.com/profile/03980297457924475954noreply@blogger.com0tag:blogger.com,1999:blog-3940972473404160061.post-12443688807942515822011-11-26T16:20:00.001-08:002011-11-26T16:22:14.646-08:00Улучшенный TCP/IP proxy на Erlang'e<p><a href="http://easy-coding.blogspot.com/2011/11/tcpip-proxy-erlange.html">Писал</a> я про мое освоение Эрганга через написание программы для перехвата и удобного логирования TCP/IP соединений.</p>
<p>B итоге я окончательно допилил программу, и теперь она заменила мне <a href="http://easy-coding.blogspot.com/2009/09/tcpip.html">версию на Питоне</a>.</p>
<p>Что программа умеет особенно удобного (как мне кажется):</p>
<blockquote>
<ul class="simple">
<li>удобный вид лога, в котором отображается шестнадцатеричный дамп, и символьного представление для видимых кодов</li>
<li>в дампе отображается номер соединения (в случае смешивания выводов нескольких параллельных соединений)</li>
<li>для каждого соединения вычисляется длительность</li>
<li>ведутся дополнительные двоичные логи для каждой из сторон в соединении (для повторного "проигрывания" данных)</li>
</ul>
</blockquote>
<p>Про Эрланг. Меня начинает реально вставлять. Я почувствовал (для многих это и не новость), что тут можно написать что-то реальное, особенно связаное с сетью и многозадачностью.</p>
<p>Из насущных проблем:</p>
<blockquote>
<ul class="simple">
<li>Пока нет чувства разумного дробления на модули и даже функции. При общей тотальной иммутабельности сложно что-то напортачить, но когда количество функций разрастается, хочется их как-то группировать.</li>
<li>Нет чувства правильного форматирования кода. Вроде как 80-ти символьные строки и пробелы вместо табуляций меня пока никогда не подводили, но при функциональном стиле кода часто получаются длинные "лесенки".</li>
</ul>
</blockquote>
<p>Пузомерка. Я сделал тест на прокач шестидесятимегового файла через питоновскую и эрланговскую версию. Результаты интересные.</p>
<p>Кач напрямую:</p>
<div class="highlight" style="background: #ffffff"><pre style="line-height: 125%">curl http://www.erlang.org/download/otp_src_R14B04.tar.gz >direct
</pre></div>
<p>Через Питон:</p>
<div class="highlight" style="background: #ffffff"><pre style="line-height: 125%">Window 1: python pyspy.py -l 50000 -a www.erlang.org -p 80 -L log
Window 2: curl http://localhost:50000/download/otp_src_R14B04.tar.gz >via-proxy-python
</pre></div>
<p>Через Эрланг:</p>
<div class="highlight" style="background: #ffffff"><pre style="line-height: 125%">Window 1: escript tcp_proxy.erl 50000 www.erlang.org 80
Window 2: curl http://localhost:50000/download/otp_src_R14B04.tar.gz >via-proxy-erlang
</pre></div>
<p>Файл напрямую качается, условно, минуту. Питоновская версия прокачала файл за шесть минут при включенном логе на экран и файл. Причем сброс лога и непосредственно прокач заканчивались приблизительно в одно время (данные задачи выполняются параллельно, общаясь через очередь, и технически не обязаны завершаться одновременно, так как очередь надо выгрести).</p>
<p>На Эрланге картина иная. Файл прокачался практически за то же время, что и напрямую! Но вот полного сброса лога я так и дождался. Через шесть минут он успел сбросить где-то 10% лога.</p>
<p>Выводы: Видимо, поведение питоновской версии обусловлено тем, что поток лога и потока-качалка работаются примерно с одной скоростью, поэтому в среднем очеред обмена постоянно выгребается. Фактически, скорость программы ограничена пропускной способностью потока логирования, но так как визуально не видно, что поток качания заканчиватся значительно раньше, то можно предположить, что он работается примерно с такой же скоростью (напомню, ~6 минут).</p>
<p>На Эрланге же качалка работает, как мне показалось, очень быстро. Данные перекачиваются и параллельно загоняются в очередь на логирование. А вот производительность логирования оставляет желать лучшего. Ради эксперимента я закомментировал вызов функции создания шестнадцатеричного дампа, и время сброса лога также упало до минуты. Поэтому, как мне кажется, корень зла в моей кривой работе со строками и списками при создании дампа (возможно что-то где-то постоянно копируются, а в мире рекурсии и изменения данных только через копирование ошибки подобного рода дорого отражаются на производильности). А вот работа с сокетами и посылкой/приемом сообщений между потоками в Эрланге очень эффективная.</p>
<p>Я вообще заметил, что в Эрланге ты подсознательно начинашь писать многопотоковые программы. Например, тут в принципе нет глобальных объектов. И допустим, у тебя есть флаг, глобальная установка, которую хочется иметь везде. Так как глобально ее объявить нельзя, приходится таскать как параметр функций там и сям. А как вариант "навязанного конструктивного мышления", думаешь - а давай-ка я запущу этот кусок как поток и буду вызывать его функционал через посылку сообщений. В этом случае я могу передать мне нужный параметр один раз в начале при создании потока, тем самым сделав его типа глобальным для этого потока.</p>
<p>Наверное пример вышел немного скомканным, но общая идея такова - так как ты обязан передавать в функцию все ее параметры каждый раз, то начинаешь думать об максимальной независимости и дроблении функционала, что как следствие, позволяет запускать их в разных потоках.</p>
<p>Для интересующихся - исходник <a href="https://github.com/begoon/tcp_proxy/blob/master/tcp_proxy.erl">доступен</a>.</p>
<p>Посты по теме:</p>
<blockquote>
<ul class="simple">
<li><a href="http://easy-coding.blogspot.com/2011/11/blog-post.html">Проба пера на новых языках</a></li>
<li><a href="http://easy-coding.blogspot.com/2009/09/tcpip.html">Мультипотоковый отладчик TCP/IP соединений</a></li>
<li><a href="http://easy-coding.blogspot.com/2011/11/tcpip-proxy-erlange.html">TCP/IP proxy на Erlang'e</a></li>
</ul>
</blockquote>Александрhttp://www.blogger.com/profile/03980297457924475954noreply@blogger.com0tag:blogger.com,1999:blog-3940972473404160061.post-322777462523064042011-11-22T16:36:00.001-08:002011-11-22T16:40:06.844-08:00TCP/IP proxy на Erlang'e<p>По мотивам недавнего <a href="http://easy-coding.blogspot.com/2011/11/blog-post.html">поста</a> про изучение новых языков, я таки добил версию на Erlang'е. Если тут есть спецы по языку, буду признателен за критику.</p>
<p>Программа по функциям идентична <a href="http://easy-coding.blogspot.com/2009/09/tcpip.html">версии на Питоне</a> за исключением отсутствия дублирования лога в файл и продвинутого разбора флагов командной строки.</p>
<p>И так: программа многопоточна, и журналирование также происходит в отдельном потоке для обеспечения целостности многострочных дампов.</p>
<p>Про Эрланг. После многократных и пока полностью неуспешных заходов на Хаскелл и после все еще неудачных попыток на Lisp или Scheme написать что-то более менее реальное и жизненное, Эрланг был реальным прорывом для меня.</p>
<p>Удивительно, невозможность изменять переменные (представьте, что программируя на С++ надо все переменные делать const) является фантастическим способом борьбы с опечатками при cut-and-paste. Также когда делаешь циклы через хвостовую рекурсию, сразу осознаешь, как эффективно работать со списками, чтобы их не копировать, а всегда "таскать" за хвост или голову.</p>
<p>Ну а концепция легких потоков и обмена сообщениями между ними (как в Go), приправленная глобальной иммутабельностью, позволяет легко писать надежные многотопочные программы.</p>
<p>Например, истересен способ реализации многопотокового TCP/IP сервера. Обычно при его программировании есть распростраенный прием: один главный поток, принимающий соединения, и когда соединение принято, создается новый поток-исполнитель, который обрабатывает соединение и после этого умирает.</p>
<p>В Эрланге можно сделать иначе (функция acceptor()). Поток, ожидающий входящего соединения, после его получения рождает свой клон для ожидания следующего соединения и затем сам обрабабатывает запрос.</p>
<p>Для меня это было немного необычно.</p>
<div class="highlight" style="background: #ffffff"><pre style="line-height: 125%">-<span style="color: #800080">module</span>(tcp_proxy).
-<span style="color: #800080">define</span>(<span style="color: #008080">WIDTH</span>, <span style="color: #009999">16</span>).
<span style="color: #990000; font-weight: bold">main</span>([<span style="color: #008080">ListenPort</span>, <span style="color: #008080">RemoteHost</span>, <span style="color: #008080">RemotePort</span>]) <span style="font-weight: bold">-></span>
<span style="color: #008080">ListenPortN</span> <span style="font-weight: bold">=</span> <span style="color: #999999">list_to_integer</span>(<span style="color: #008080">ListenPort</span>),
start(<span style="color: #008080">ListenPortN</span>, <span style="color: #008080">RemoteHost</span>, <span style="color: #999999">list_to_integer</span>(<span style="color: #008080">RemotePort</span>));
<span style="color: #990000; font-weight: bold">main</span>(_) <span style="font-weight: bold">-></span> usage().
<span style="color: #990000; font-weight: bold">usage</span>() <span style="font-weight: bold">-></span>
<span style="color: #555555">io</span>:format(<span style="color: #bb8844">"~ntcp_proxy.erl local_port remote_port remote_host~n~n"</span>, []),
<span style="color: #555555">io</span>:format(<span style="color: #bb8844">"Example:~n~n"</span>, []),
<span style="color: #555555">io</span>:format(<span style="color: #bb8844">"tcp_proxy.erl 50000 google.com 80~n~n"</span>, []).
<span style="color: #990000; font-weight: bold">start</span>(<span style="color: #008080">ListenPort</span>, <span style="color: #008080">CalleeHost</span>, <span style="color: #008080">CalleePort</span>) <span style="font-weight: bold">-></span>
<span style="color: #555555">io</span>:format(<span style="color: #bb8844">"Start listening on port ~p and forwarding data to ~s:~p~n"</span>,
[<span style="color: #008080">ListenPort</span>, <span style="color: #008080">CalleeHost</span>, <span style="color: #008080">CalleePort</span>]),
{ok, <span style="color: #008080">ListenSocket</span>} <span style="font-weight: bold">=</span> <span style="color: #555555">gen_tcp</span>:listen(<span style="color: #008080">ListenPort</span>, [binary, {packet, <span style="color: #009999">0</span>},
{reuseaddr, true},
{active, true}]),
<span style="color: #555555">io</span>:format(<span style="color: #bb8844">"Listener socket is started ~s~n"</span>, [socket_info(<span style="color: #008080">ListenSocket</span>)]),
<span style="color: #999999">spawn</span>(<span style="font-weight: bold">fun</span>() <span style="font-weight: bold">-></span> acceptor(<span style="color: #008080">ListenSocket</span>, <span style="color: #008080">CalleeHost</span>, <span style="color: #008080">CalleePort</span>, <span style="color: #009999">0</span>) <span style="font-weight: bold">end</span>),
<span style="color: #999999">register</span>(logger, <span style="color: #999999">spawn</span>(<span style="font-weight: bold">fun</span>() <span style="font-weight: bold">-></span> logger() <span style="font-weight: bold">end</span>)),
wait().
<span style="color: #999988; font-style: italic">% Infinine loop to make sure that the main thread doesn't exit.</span>
<span style="color: #990000; font-weight: bold">wait</span>() <span style="font-weight: bold">-></span> <span style="font-weight: bold">receive</span> _ <span style="font-weight: bold">-></span> true <span style="font-weight: bold">end</span>, wait().
<span style="color: #990000; font-weight: bold">format_socket_info</span>(<span style="color: #008080">Info</span>) <span style="font-weight: bold">-></span>
{ok, {{<span style="color: #008080">A</span>, <span style="color: #008080">B</span>, <span style="color: #008080">C</span>, <span style="color: #008080">D</span>}, <span style="color: #008080">Port</span>}} <span style="font-weight: bold">=</span> <span style="color: #008080">Info</span>,
<span style="color: #555555">lists</span>:flatten(<span style="color: #555555">io_lib</span>:format(<span style="color: #bb8844">"~p.~p.~p.~p:~p"</span>, [<span style="color: #008080">A</span>, <span style="color: #008080">B</span>, <span style="color: #008080">C</span>, <span style="color: #008080">D</span>, <span style="color: #008080">Port</span>])).
<span style="color: #990000; font-weight: bold">peer_info</span>(<span style="color: #008080">Socket</span>) <span style="font-weight: bold">-></span> format_socket_info(<span style="color: #555555">inet</span>:peername(<span style="color: #008080">Socket</span>)).
<span style="color: #990000; font-weight: bold">socket_info</span>(<span style="color: #008080">Socket</span>) <span style="font-weight: bold">-></span> format_socket_info(<span style="color: #555555">inet</span>:sockname(<span style="color: #008080">Socket</span>)).
<span style="color: #990000; font-weight: bold">acceptor</span>(<span style="color: #008080">ListenSocket</span>, <span style="color: #008080">RemoteHost</span>, <span style="color: #008080">RemotePort</span>, <span style="color: #008080">ConnN</span>) <span style="font-weight: bold">-></span>
<span style="font-weight: bold">case</span> <span style="color: #555555">gen_tcp</span>:accept(<span style="color: #008080">ListenSocket</span>) <span style="font-weight: bold">of</span>
{ok, <span style="color: #008080">LocalSocket</span>} <span style="font-weight: bold">-></span>
<span style="color: #999999">spawn</span>(<span style="font-weight: bold">fun</span>() <span style="font-weight: bold">-></span> acceptor(<span style="color: #008080">ListenSocket</span>, <span style="color: #008080">RemoteHost</span>, <span style="color: #008080">RemotePort</span>, <span style="color: #008080">ConnN</span> <span style="font-weight: bold">+</span> <span style="color: #009999">1</span>) <span style="font-weight: bold">end</span>),
<span style="color: #008080">LocalInfo</span> <span style="font-weight: bold">=</span> peer_info(<span style="color: #008080">LocalSocket</span>),
logger <span style="font-weight: bold">!</span> {message, <span style="color: #bb8844">"~4.16.0B: Incoming connection from ~s~n"</span>, [<span style="color: #008080">ConnN</span>, <span style="color: #008080">LocalInfo</span>]},
<span style="font-weight: bold">case</span> <span style="color: #555555">gen_tcp</span>:connect(<span style="color: #008080">RemoteHost</span>, <span style="color: #008080">RemotePort</span>, [binary, {packet, <span style="color: #009999">0</span>}]) <span style="font-weight: bold">of</span>
{ok, <span style="color: #008080">RemoteSocket</span>} <span style="font-weight: bold">-></span>
<span style="color: #008080">RemoteInfo</span> <span style="font-weight: bold">=</span> peer_info(<span style="color: #008080">RemoteSocket</span>),
logger <span style="font-weight: bold">!</span> {message, <span style="color: #bb8844">"~4.16.0B: Connected to ~s~n"</span>, [<span style="color: #008080">ConnN</span>, <span style="color: #008080">RemoteInfo</span>]},
exchange_data(<span style="color: #008080">LocalSocket</span>, <span style="color: #008080">RemoteSocket</span>, <span style="color: #008080">LocalInfo</span>, <span style="color: #008080">RemoteInfo</span>, <span style="color: #008080">ConnN</span>, <span style="color: #009999">0</span>),
logger <span style="font-weight: bold">!</span> {message, <span style="color: #bb8844">"~4.16.0B: Finished~n"</span>, [<span style="color: #008080">ConnN</span>]};
{error, <span style="color: #008080">Reason</span>} <span style="font-weight: bold">-></span>
logger <span style="font-weight: bold">!</span> {message, <span style="color: #bb8844">"~4.16.0B: Unable to connect to ~s:~s (error: ~p)~n"</span>,
[<span style="color: #008080">ConnN</span>, <span style="color: #008080">RemoteHost</span>, <span style="color: #008080">RemotePort</span>, <span style="color: #008080">Reason</span>]}
<span style="font-weight: bold">end</span>;
{error, <span style="color: #008080">Reason</span>} <span style="font-weight: bold">-></span>
logger <span style="font-weight: bold">!</span> {message, <span style="color: #bb8844">"Socket accept error '~w'~n"</span>, [<span style="color: #008080">Reason</span>]}
<span style="font-weight: bold">end</span>.
<span style="color: #990000; font-weight: bold">exchange_data</span>(<span style="color: #008080">LocalSocket</span>, <span style="color: #008080">RemoteSocket</span>, <span style="color: #008080">LocalInfo</span>, <span style="color: #008080">RemoteInfo</span>, <span style="color: #008080">ConnN</span>, <span style="color: #008080">PacketN</span>) <span style="font-weight: bold">-></span>
<span style="font-weight: bold">receive</span>
{tcp, <span style="color: #008080">RemoteSocket</span>, <span style="color: #008080">Bin</span>} <span style="font-weight: bold">-></span>
logger <span style="font-weight: bold">!</span> {received, <span style="color: #008080">ConnN</span>, <span style="color: #008080">Bin</span>, <span style="color: #008080">RemoteInfo</span>, <span style="color: #008080">PacketN</span>},
<span style="color: #555555">gen_tcp</span>:<span style="color: #999999">send</span>(<span style="color: #008080">LocalSocket</span>, <span style="color: #008080">Bin</span>),
logger <span style="font-weight: bold">!</span> {sent, <span style="color: #008080">ConnN</span>, <span style="color: #008080">LocalInfo</span>, <span style="color: #008080">PacketN</span>},
exchange_data(<span style="color: #008080">LocalSocket</span>, <span style="color: #008080">RemoteSocket</span>, <span style="color: #008080">LocalInfo</span>, <span style="color: #008080">RemoteInfo</span>, <span style="color: #008080">ConnN</span>, <span style="color: #008080">PacketN</span> <span style="font-weight: bold">+</span> <span style="color: #009999">1</span>);
{tcp, <span style="color: #008080">LocalSocket</span>, <span style="color: #008080">Bin</span>} <span style="font-weight: bold">-></span>
logger <span style="font-weight: bold">!</span> {received, <span style="color: #008080">ConnN</span>, <span style="color: #008080">Bin</span>, <span style="color: #008080">LocalInfo</span>, <span style="color: #008080">PacketN</span>},
<span style="color: #555555">gen_tcp</span>:<span style="color: #999999">send</span>(<span style="color: #008080">RemoteSocket</span>, <span style="color: #008080">Bin</span>),
logger <span style="font-weight: bold">!</span> {sent, <span style="color: #008080">ConnN</span>, <span style="color: #008080">RemoteInfo</span>, <span style="color: #008080">PacketN</span>},
exchange_data(<span style="color: #008080">LocalSocket</span>, <span style="color: #008080">RemoteSocket</span>, <span style="color: #008080">LocalInfo</span>, <span style="color: #008080">RemoteInfo</span>, <span style="color: #008080">ConnN</span>, <span style="color: #008080">PacketN</span> <span style="font-weight: bold">+</span> <span style="color: #009999">1</span>);
{tcp_closed, <span style="color: #008080">RemoteSocket</span>} <span style="font-weight: bold">-></span>
logger <span style="font-weight: bold">!</span> {message, <span style="color: #bb8844">"~4.16.0B: Disconnected from ~s~n"</span>, [<span style="color: #008080">ConnN</span>, <span style="color: #008080">RemoteInfo</span>]};
{tcp_closed, <span style="color: #008080">LocalSocket</span>} <span style="font-weight: bold">-></span>
logger <span style="font-weight: bold">!</span> {message, <span style="color: #bb8844">"~4.16.0B: Disconnected from ~s~n"</span>, [<span style="color: #008080">ConnN</span>, <span style="color: #008080">LocalInfo</span>]}
<span style="font-weight: bold">end</span>.
<span style="color: #990000; font-weight: bold">logger</span>() <span style="font-weight: bold">-></span>
<span style="font-weight: bold">receive</span>
{received, <span style="color: #008080">Pid</span>, <span style="color: #008080">Msg</span>, <span style="color: #008080">From</span>, <span style="color: #008080">PacketN</span>} <span style="font-weight: bold">-></span>
<span style="color: #555555">io</span>:format(<span style="color: #bb8844">"~4.16.0B: Received (#~p) ~p byte(s) from ~s~n"</span>,
[<span style="color: #008080">Pid</span>, <span style="color: #008080">PacketN</span>, <span style="color: #999999">byte_size</span>(<span style="color: #008080">Msg</span>), <span style="color: #008080">From</span>]),
dump_bin(<span style="color: #008080">Pid</span>, <span style="color: #008080">Msg</span>),
logger();
{sent, <span style="color: #008080">Pid</span>, <span style="color: #008080">ToSocket</span>, <span style="color: #008080">PacketN</span>} <span style="font-weight: bold">-></span>
<span style="color: #555555">io</span>:format(<span style="color: #bb8844">"~4.16.0B: Sent (#~p) to ~s~n"</span>, [<span style="color: #008080">Pid</span>, <span style="color: #008080">PacketN</span>, <span style="color: #008080">ToSocket</span>]),
logger();
{message, <span style="color: #008080">Format</span>, <span style="color: #008080">Args</span>} <span style="font-weight: bold">-></span>
<span style="color: #555555">io</span>:format(<span style="color: #008080">Format</span>, <span style="color: #008080">Args</span>),
logger()
<span style="font-weight: bold">end</span>.
<span style="color: #990000; font-weight: bold">dump_list</span>(<span style="color: #008080">Prefix</span>, <span style="color: #008080">L</span>, <span style="color: #008080">Offset</span>) <span style="font-weight: bold">-></span>
{<span style="color: #008080">H</span>, <span style="color: #008080">T</span>} <span style="font-weight: bold">=</span> <span style="color: #555555">lists</span>:split(<span style="color: #555555">lists</span>:min([<span style="color: #008080">?WIDTH</span>, <span style="color: #999999">length</span>(<span style="color: #008080">L</span>)]), <span style="color: #008080">L</span>),
<span style="color: #555555">io</span>:format(<span style="color: #bb8844">"~4.16.0B: "</span>, [<span style="color: #008080">Prefix</span>]),
<span style="color: #555555">io</span>:format(<span style="color: #bb8844">"~4.16.0B: "</span>, [<span style="color: #008080">Offset</span>]),
<span style="color: #555555">io</span>:format(<span style="color: #bb8844">"~-*s| "</span>, [<span style="color: #008080">?WIDTH</span> <span style="font-weight: bold">*</span> <span style="color: #009999">3</span>, dump_numbers(<span style="color: #008080">H</span>)]),
<span style="color: #555555">io</span>:format(<span style="color: #bb8844">"~-*s"</span>, [<span style="color: #008080">?WIDTH</span>, dump_chars(<span style="color: #008080">H</span>)]),
<span style="color: #555555">io</span>:format(<span style="color: #bb8844">"~n"</span>, []),
<span style="font-weight: bold">if</span> <span style="color: #999999">length</span>(<span style="color: #008080">T</span>) <span style="font-weight: bold">></span> <span style="color: #009999">0</span> <span style="font-weight: bold">-></span> dump_list(<span style="color: #008080">Prefix</span>, <span style="color: #008080">T</span>, <span style="color: #008080">Offset</span> <span style="font-weight: bold">+</span> <span style="color: #009999">16</span>); true <span style="font-weight: bold">-></span> [] <span style="font-weight: bold">end</span>.
<span style="color: #990000; font-weight: bold">dump_numbers</span>(<span style="color: #008080">L</span>) <span style="font-weight: bold">when</span> (<span style="color: #999999">is_list</span>(<span style="color: #008080">L</span>)) <span style="font-weight: bold">-></span>
<span style="color: #555555">lists</span>:flatten([<span style="color: #555555">io_lib</span>:format(<span style="color: #bb8844">"~2.16.0B "</span>, [<span style="color: #008080">X</span>]) || <span style="color: #008080">X</span> <span style="font-weight: bold"><-</span> <span style="color: #008080">L</span>]).
<span style="color: #990000; font-weight: bold">dump_chars</span>(<span style="color: #008080">L</span>) <span style="font-weight: bold">-></span>
<span style="color: #555555">lists</span>:map(<span style="font-weight: bold">fun</span>(<span style="color: #008080">X</span>) <span style="font-weight: bold">-></span>
<span style="font-weight: bold">if</span> <span style="color: #008080">X</span> <span style="font-weight: bold">>=</span> <span style="color: #009999">32</span> <span style="font-weight: bold">andalso</span> <span style="color: #008080">X</span> <span style="font-weight: bold"><</span> <span style="color: #009999">128</span> <span style="font-weight: bold">-></span> <span style="color: #008080">X</span>;
true <span style="font-weight: bold">-></span> <span style="color: #bb8844">$.</span>
<span style="font-weight: bold">end</span>
<span style="font-weight: bold">end</span>, <span style="color: #008080">L</span>).
<span style="color: #990000; font-weight: bold">dump_bin</span>(<span style="color: #008080">Prefix</span>, <span style="color: #008080">Bin</span>) <span style="font-weight: bold">-></span>
dump_list(<span style="color: #008080">Prefix</span>, <span style="color: #999999">binary_to_list</span>(<span style="color: #008080">Bin</span>), <span style="color: #009999">0</span>).
</pre></div>
<p>В работе может выводить примерно следующее:</p>
<div class="highlight" style="background: #ffffff"><pre style="line-height: 125%">alexander:erlang/>./tcp_proxy.sh 50000 pop.yandex.ru 110
Start listening on port 50000 and forwarding data to pop.yandex.ru:110
Listener socket is started 0.0.0.0:50000
0000: Incoming connection from 127.0.0.1:51402
0000: Connected to 213.180.204.37:110
0000: Received (#0) 38 byte(s) from 213.180.204.37:110
0000: 0000: 2B 4F 4B 20 50 4F 50 20 59 61 21 20 76 31 2E 30 | +OK POP Ya! v1.0
0000: 0010: 2E 30 6E 61 40 32 35 20 67 55 62 44 54 51 64 5A | .0na@25 gUbDTQdZ
0000: 0020: 6D 6D 49 31 0D 0A | mmI1..
0000: Sent (#0) to 127.0.0.1:51402
0000: Received (#1) 11 byte(s) from 127.0.0.1:51402
0000: 0000: 55 53 45 52 20 74 65 73 74 0D 0A | USER test..
0000: Sent (#1) to 213.180.204.37:110
0000: Received (#2) 23 byte(s) from 213.180.204.37:110
0000: 0000: 2B 4F 4B 20 70 61 73 73 77 6F 72 64 2C 20 70 6C | +OK password, pl
0000: 0010: 65 61 73 65 2E 0D 0A | ease...
0000: Sent (#2) to 127.0.0.1:51402
0000: Received (#3) 11 byte(s) from 127.0.0.1:51402
0000: 0000: 50 41 53 53 20 70 61 73 73 0D 0A | PASS pass..
0000: Sent (#3) to 213.180.204.37:110
0000: Received (#4) 72 byte(s) from 213.180.204.37:110
0000: 0000: 2D 45 52 52 20 5B 41 55 54 48 5D 20 6C 6F 67 69 | -ERR [AUTH] logi
0000: 0010: 6E 20 66 61 69 6C 75 72 65 20 6F 72 20 50 4F 50 | n failure or POP
0000: 0020: 33 20 64 69 73 61 62 6C 65 64 2C 20 74 72 79 20 | 3 disabled, try
0000: 0030: 6C 61 74 65 72 2E 20 73 63 3D 67 55 62 44 54 51 | later. sc=gUbDTQ
0000: 0040: 64 5A 6D 6D 49 31 0D 0A | dZmmI1..
0000: Sent (#4) to 127.0.0.1:51402
0000: Disconnected from 213.180.204.37:110
0000: Finished
0001: Incoming connection from 127.0.0.1:51405
0001: Connected to 213.180.204.37:110
0001: Received (#0) 38 byte(s) from 213.180.204.37:110
0001: 0000: 2B 4F 4B 20 50 4F 50 20 59 61 21 20 76 31 2E 30 | +OK POP Ya! v1.0
0001: 0010: 2E 30 6E 61 40 33 30 20 70 55 62 41 72 52 33 74 | .0na@30 pUbArR3t
0001: 0020: 6A 65 41 31 0D 0A | jeA1..
0001: Sent (#0) to 127.0.0.1:51405
0001: Received (#1) 6 byte(s) from 127.0.0.1:51405
0001: 0000: 51 55 49 54 0D 0A | QUIT..
0001: Sent (#1) to 213.180.204.37:110
0001: Received (#2) 20 byte(s) from 213.180.204.37:110
0001: 0000: 2B 4F 4B 20 73 68 75 74 74 69 6E 67 20 64 6F 77 | +OK shutting dow
0001: 0010: 6E 2E 0D 0A | n...
0001: Sent (#2) to 127.0.0.1:51405
0001: Disconnected from 213.180.204.37:110
0001: Finished
</pre></div>
<p>Вывод: Эрланг - прекрасный вариант для начала функциональной карьеры.</p>
<p>Посты по теме:</p>
<blockquote>
<ul class="simple">
<li><a href="http://easy-coding.blogspot.com/2011/11/blog-post.html">Проба пера на новых языках</a></li>
<li><a href="http://easy-coding.blogspot.com/2009/09/tcpip.html">Мультипотоковый отладчик TCP/IP соединений</a></li>
</ul>
</blockquote>Александрhttp://www.blogger.com/profile/03980297457924475954noreply@blogger.com0tag:blogger.com,1999:blog-3940972473404160061.post-83384341174229110682011-11-22T06:25:00.001-08:002011-11-22T06:38:58.316-08:00Git для работы на нескольких платформах<p>Мне приходится часто проверять один и тот же код на нескольких платформах. Это означает, что исходники надо физически копировать с машины на машину. Далее начинаются мелкие правки на каждой платформе, которые надо в конце собрать вместе и пробовать снова.</p>
<p>После десятков версий изощренных скриптов я решил собрать волю в кулак и начать использовать Git.</p>
<p>Задача: на виндовой машине (это мой основной рабочий ноутбук) установить Git как сервер, чтобы я мог всегда иметь на нем самую актуальную копию всего. Затем установить Git как клиент на рабочих машинах и обмениваться commit'ами через центральный репозиторий на Windows.</p>
<p>Для простоты я решил использовать SSH как протокол. Благо все UNIX машины имеют ssh-клиент.</p>
<p>Плюсы - везде Git, все локальные изменения имеют версии и можно вести локальные ветки. Ну и центральная копия - тоже под Git. Минусы - потратить время и все это настроить.</p>
<p>Git/ssh как сервер на Windows - это целая тема, так как нужно поставить SSH сервер и правильно прикрутить к нему Git.</p>
<p>Благодаря двум (<a href="http://www.timdavis.com.au/git/setting-up-a-msysgit-server-with-copssh-on-windows/">1</a>, <a href="http://java2cs2.blogspot.com/2010/03/setup-git-server-on-windows-machine.html">2</a>) ссылкам удалось настроить <a href="http://www.itefix.no/i2/copssh">CopSSH</a> в паре с <a href="http://code.google.com/p/msysgit/">msysgit</a>.</p>
<p>Далее Git на клиентских машинах. С Linux и Windows все совсем просто (на Windows используется тот же msysgit).</p>
<p>На Solaris пришлось собрать GNU Make до 3.82 (на 3.75 Git не собирается).</p>
<p>На HPUX and AIX пришлось собрать coreutils (для нормального install), less (представляете, на HPUX нету less по умолчанию), python (опять для HPUX), zlib и свежие tcl/tk.</p>
<p>Один день на борьбу c CopSSH на Windows и день на сборки под UNIXами.</p>
<p>Зато теперь радость и благодать.</p>
<p>P.S. С CopSSH интересная история. Вчера (21 ноября) на их сайте можно было все скачать. Сегодня (22 ноября) читаю на том же сайте:</p>
<blockquote>
<div class="line-block">
<div class="line">Termination of free solutions from ITeF!x</div>
<div class="line">Submitted by tk on Tue, 22/11/2011 - 08:18 itefix</div>
<div class="line">Development,distribution and support of free solutions from Itefix are now terminated due to lack of time and changes in priorities.</div>
</div>
</blockquote>
<p>С их зеркала на sourceforge.net также пропали все файлы. Хорошо, что я не удалил дистрибутив CopSSH, скачанный вчера.</p>Александрhttp://www.blogger.com/profile/03980297457924475954noreply@blogger.com0tag:blogger.com,1999:blog-3940972473404160061.post-3521613508685828332011-11-19T13:35:00.001-08:002011-11-19T13:37:01.315-08:00Проба пера на новых языках<p>Как-то так сложилось, что когда я рассматриваю новый язык программирования, то помимо тривиальных программок типа "Hello world", хочется написать что-то более менее реальное или даже нужное.</p>
<p>У меня такой задачей стал многопотоковый перехватчик-прокси для TCP/IP. Такая программа ставится как промежуточное звено между клиентом и сервером, и можно удобно смотреть, что летает в канале туда-сюда.</p>
<p>Данная задача затрагивает многие аспекты языка - потоки, синхронизацию, сокеты, ввод/вывод, работу со строками.</p>
<p>Вот, например, <a href="http://easy-coding.blogspot.com/2009/09/tcpip.html">версия на Питоне</a>. На данный момент это наиболее удачная моя версия, так как она работает на многих платформах благодаря Питону и также показывает неплохую производительность благодаря логгированию в параллельном потоке.</p>
<p>Еще я писал это программу на C, C++, C++/boost, PHP, VB, Go, Ruby. На Erlang'e не осилил, пока.</p>
<p>А вы чем тестируете новые языки?</p>Александрhttp://www.blogger.com/profile/03980297457924475954noreply@blogger.com0tag:blogger.com,1999:blog-3940972473404160061.post-15313582327088725262011-11-16T03:13:00.000-08:002011-11-16T03:13:58.955-08:00Тонкости использования getenv() и putenv()<p>Нарвался тут на интересные грабли с функциями <a href="http://www.kernel.org/doc/man-pages/online/pages/man3/getenv.3.html">getenv()</a> и <a href="http://www.kernel.org/doc/man-pages/online/pages/man3/putenv.3.html">putenv()</a>.</p>
<p>С putenv() у меня уже <a href="http://easy-coding.blogspot.com/2009/02/putenv.html">был</a> интересный опыт.</p>
<p>Часто люди пишут так:</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span style="color: #008000; font-weight: bold">if</span> (getenv(<span style="color: #BA2121">"A_FLAG"</span>)) {
...
}
</pre></div>
<p>Это работает неплохо для переменных-флагов, которые либо есть, либо нет. Значение не важно.</p>
<p>Что получилось у меня:</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span style="color: #B00040">int</span> main(...) {
putenv(<span style="color: #BA2121">"GLOBAL_FLAG=1"</span>); <span style="color: #408080; font-style: italic">// Глобальное значение для всей программы.</span>
...
system(<span style="color: #BA2121">"xyz"</span>); <span style="color: #408080; font-style: italic">// Это программа должна видеть GLOBAL_FLAG=1.</span>
...
do_stuff();
...
}
<span style="color: #B00040">void</span> do_stuff() {
...
<span style="color: #008000; font-weight: bold">if</span> (something) {
putenv(<span style="color: #BA2121">"GLOBAL_FLAG="</span>); <span style="color: #408080; font-style: italic">// Убрать переменную.</span>
system(<span style="color: #BA2121">"abc"</span>); <span style="color: #408080; font-style: italic">// А вот для этой программы флаг должен быть убран.</span>
...
}
...
<span style="color: #008000; font-weight: bold">if</span> (getenv(<span style="color: #BA2121">"GLOBAL_FLAG"</span>) {
<span style="color: #408080; font-style: italic">// И вот тут начиналась ерунда на разных платформах.</span>
}
}
</pre></div>
<p>А корень зла тут в том, что после putenv() результат getenv() может стать либо NULL, либо
"", в зависимости от платформы.</p>
<p>Например:</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span style="color: #008000; font-weight: bold">if</span> (getenv(<span style="color: #BA2121">"GLOBAL_FLAG"</span>) {
</pre></div>
<p>работает только на Windows и правильнее писать:</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span style="color: #008000; font-weight: bold">const</span> <span style="color: #B00040">char</span><span style="color: #666666">*</span> p <span style="color: #666666">=</span> getenv(<span style="color: #BA2121">"GLOBAL_FLAG"</span>);
<span style="color: #008000; font-weight: bold">if</span> (p <span style="color: #666666">!=</span> <span style="color: #008000">NULL</span> <span style="color: #666666">&&</span> <span style="color: #666666">*</span>p <span style="color: #666666">!=</span> <span style="color: #BA2121">'\0'</span>) {
...
}
</pre></div>
<p>И лучше сделать wrapper для getenv():</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">std<span style="color: #666666">::</span>string GetEnv(<span style="color: #008000; font-weight: bold">const</span> <span style="color: #B00040">char</span><span style="color: #666666">*</span> name) {
<span style="color: #008000; font-weight: bold">const</span> <span style="color: #B00040">char</span><span style="color: #666666">*</span> v <span style="color: #666666">=</span> getenv(name);
<span style="color: #008000; font-weight: bold">return</span> v <span style="color: #666666">?</span> v <span style="color: #666666">:</span> <span style="color: #BA2121">""</span>;
}
</pre></div>
<p>И для проверки писать:</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span style="color: #008000; font-weight: bold">if</span> (<span style="color: #666666">!</span>GetEnv(<span style="color: #BA2121">"var"</span>).empty()) {
..
}
</pre></div>
<p>Для теста я написал программу, которая выставляет переменную и проверяет ее значение через getenv() и через вызов дочерней программы.</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span style="color: #BC7A00">#include <string></span>
<span style="color: #BC7A00">#include <vector></span>
<span style="color: #BC7A00">#include <iostream></span>
<span style="color: #BC7A00">#include <cstdlib></span>
<span style="color: #BC7A00">#ifdef WINDOWS</span>
<span style="color: #BC7A00">#define putenv _putenv</span>
<span style="color: #BC7A00">#endif</span>
<span style="color: #B00040">void</span> PrintVariableViaShell(<span style="color: #008000; font-weight: bold">const</span> std<span style="color: #666666">::</span>string<span style="color: #666666">&</span> name) {
std<span style="color: #666666">::</span>cout <span style="color: #666666"><<</span> <span style="color: #BA2121">"Value from shell:"</span> <span style="color: #666666"><<</span> std<span style="color: #666666">::</span>endl;
<span style="color: #008000; font-weight: bold">const</span> std<span style="color: #666666">::</span>string cmd <span style="color: #666666">=</span>
<span style="color: #BC7A00">#ifdef WINDOWS</span>
std<span style="color: #666666">::</span>string(<span style="color: #BA2121">"cmd /c echo [%"</span>) <span style="color: #666666">+</span> name <span style="color: #666666">+</span> <span style="color: #BA2121">"%]"</span>;
<span style="color: #BC7A00">#else</span>
std<span style="color: #666666">::</span>string(<span style="color: #BA2121">"/bin/sh -c </span><span style="color: #BB6622; font-weight: bold">\"</span><span style="color: #BA2121">echo [$"</span>) <span style="color: #666666">+</span> name <span style="color: #666666">+</span> <span style="color: #BA2121">"]</span><span style="color: #BB6622; font-weight: bold">\"</span><span style="color: #BA2121">"</span>;
<span style="color: #BC7A00">#endif</span>
std<span style="color: #666666">::</span>cout <span style="color: #666666"><<</span> cmd <span style="color: #666666"><<</span> std<span style="color: #666666">::</span>endl;
std<span style="color: #666666">::</span>system(cmd.c_str());
}
<span style="color: #B00040">void</span> PrintVariableViaGetEnv(<span style="color: #008000; font-weight: bold">const</span> std<span style="color: #666666">::</span>string<span style="color: #666666">&</span> name) {
std<span style="color: #666666">::</span>cout <span style="color: #666666"><<</span> <span style="color: #BA2121">"Value from getenv():"</span> <span style="color: #666666"><<</span> std<span style="color: #666666">::</span>endl;
<span style="color: #008000; font-weight: bold">const</span> <span style="color: #B00040">char</span><span style="color: #666666">*</span> v <span style="color: #666666">=</span> std<span style="color: #666666">::</span>getenv(name.c_str());
std<span style="color: #666666">::</span>cout <span style="color: #666666"><<</span> <span style="color: #BA2121">"["</span> <span style="color: #666666"><<</span> (v <span style="color: #666666">?</span> v <span style="color: #666666">:</span> <span style="color: #BA2121">"<NULL>"</span>) <span style="color: #666666"><<</span> <span style="color: #BA2121">"]"</span> <span style="color: #666666"><<</span> std<span style="color: #666666">::</span>endl;
}
<span style="color: #B00040">void</span> SetVariableDeleteAndPrint(<span style="color: #008000; font-weight: bold">const</span> <span style="color: #B00040">char</span><span style="color: #666666">*</span> name_value, <span style="color: #008000; font-weight: bold">const</span> <span style="color: #B00040">bool</span> equ) {
<span style="color: #008000; font-weight: bold">const</span> std<span style="color: #666666">::</span>string<span style="color: #666666">&</span> name_value_s(name_value);
<span style="color: #008000; font-weight: bold">const</span> std<span style="color: #666666">::</span>string name <span style="color: #666666">=</span> name_value_s.substr(<span style="color: #666666">0</span>, name_value_s.find(<span style="color: #BA2121">'='</span>));
putenv(<span style="color: #008000; font-weight: bold">const_cast</span><span style="color: #666666"><</span><span style="color: #B00040">char</span><span style="color: #666666">*></span>(name_value));
std<span style="color: #666666">::</span>vector<span style="color: #666666"><</span><span style="color: #B00040">char</span><span style="color: #666666">></span> delete_without_equ(name.begin(), name.end());
delete_without_equ.push_back(<span style="color: #BA2121">'\0'</span>);
putenv(<span style="color: #666666">&</span>delete_without_equ[<span style="color: #666666">0</span>]);
std<span style="color: #666666">::</span>cout <span style="color: #666666"><<</span> <span style="color: #BA2121">"Value after deleting WITHOUT '=':"</span> <span style="color: #666666"><<</span> std<span style="color: #666666">::</span>endl;
PrintVariableViaShell(name);
PrintVariableViaGetEnv(name);
std<span style="color: #666666">::</span>cout <span style="color: #666666"><<</span> std<span style="color: #666666">::</span>endl;
putenv(<span style="color: #008000; font-weight: bold">const_cast</span><span style="color: #666666"><</span><span style="color: #B00040">char</span><span style="color: #666666">*></span>(name_value));
std<span style="color: #666666">::</span>vector<span style="color: #666666"><</span><span style="color: #B00040">char</span><span style="color: #666666">></span> delete_with_equ(name.begin(), name.end());
delete_with_equ.push_back(<span style="color: #BA2121">'='</span>);
delete_with_equ.push_back(<span style="color: #BA2121">'\0'</span>);
putenv(<span style="color: #666666">&</span>delete_with_equ[<span style="color: #666666">0</span>]);
std<span style="color: #666666">::</span>cout <span style="color: #666666"><<</span> <span style="color: #BA2121">"Value after deleting WITH '=': "</span> <span style="color: #666666"><<</span> std<span style="color: #666666">::</span>endl;
PrintVariableViaShell(name);
PrintVariableViaGetEnv(name);
}
<span style="color: #B00040">int</span> main(<span style="color: #B00040">int</span> argc, <span style="color: #B00040">char</span><span style="color: #666666">*</span> argv[]) {
<span style="color: #BC7A00">#ifdef WINDOWS</span>
std<span style="color: #666666">::</span>cout <span style="color: #666666"><<</span> <span style="color: #BA2121">"WINDOWS"</span> <span style="color: #666666"><<</span> std<span style="color: #666666">::</span>endl;
<span style="color: #BC7A00">#else</span>
system(<span style="color: #BA2121">"uname"</span>);
<span style="color: #BC7A00">#endif</span>
SetVariableDeleteAndPrint(<span style="color: #BA2121">"ABC=123"</span>, <span style="color: #008000; font-weight: bold">true</span>);
<span style="color: #008000; font-weight: bold">return</span> <span style="color: #666666">0</span>;
}
</pre></div>
<p>И вот результы с разных платформ.</p>
<p><strong>Linux</strong></p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">Linux
Value after deleting WITHOUT <span style="color: #BA2121">'='</span>:
Value from shell:
/bin/sh -c <span style="color: #BA2121">"echo [$ABC]"</span>
<span style="color: #666666">[]</span>
Value from getenv<span style="color: #666666">()</span>:
<span style="color: #666666">[</span><NULL><span style="color: #666666">]</span>
Value after deleting WITH <span style="color: #BA2121">'='</span>:
Value from shell:
/bin/sh -c <span style="color: #BA2121">"echo [$ABC]"</span>
<span style="color: #666666">[]</span>
Value from getenv<span style="color: #666666">()</span>:
<span style="color: #666666">[]</span>
</pre></div>
<p><strong>AIX</strong></p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">AIX
Value after deleting WITHOUT <span style="color: #BA2121">'='</span>:
Value from shell:
/bin/sh -c <span style="color: #BA2121">"echo [$ABC]"</span>
<span style="color: #666666">[</span>123<span style="color: #666666">]</span>
Value from getenv<span style="color: #666666">()</span>:
<span style="color: #666666">[</span>123<span style="color: #666666">]</span>
Value after deleting WITH <span style="color: #BA2121">'='</span>:
Value from shell:
/bin/sh -c <span style="color: #BA2121">"echo [$ABC]"</span>
<span style="color: #666666">[]</span>
Value from getenv<span style="color: #666666">()</span>:
<span style="color: #666666">[]</span>
</pre></div>
<p><strong>SunOS</strong></p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">SunOS
Value after deleting WITHOUT <span style="color: #BA2121">'='</span>:
Value from shell:
/bin/sh -c <span style="color: #BA2121">"echo [$ABC]"</span>
<span style="color: #666666">[</span>123<span style="color: #666666">]</span>
Value from getenv<span style="color: #666666">()</span>:
<span style="color: #666666">[</span>123<span style="color: #666666">]</span>
Value after deleting WITH <span style="color: #BA2121">'='</span>:
Value from shell:
/bin/sh -c <span style="color: #BA2121">"echo [$ABC]"</span>
<span style="color: #666666">[]</span>
Value from getenv<span style="color: #666666">()</span>:
<span style="color: #666666">[]</span>
</pre></div>
<p><strong>HP-UX</strong></p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">HP-UX
Value after deleting WITHOUT <span style="color: #BA2121">'='</span>:
Value from shell:
/bin/sh -c <span style="color: #BA2121">"echo [$ABC]"</span>
<span style="color: #666666">[</span>123<span style="color: #666666">]</span>
Value from getenv<span style="color: #666666">()</span>:
<span style="color: #666666">[</span>123<span style="color: #666666">]</span>
Value after deleting WITH <span style="color: #BA2121">'='</span>:
Value from shell:
/bin/sh -c <span style="color: #BA2121">"echo [$ABC]"</span>
<span style="color: #666666">[]</span>
Value from getenv<span style="color: #666666">()</span>:
<span style="color: #666666">[]</span>
</pre></div>
<p><strong>WINDOWS</strong></p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">WINDOWS
Value after deleting WITHOUT <span style="color: #BA2121">'='</span>:
Value from shell:
cmd /c <span style="color: #008000">echo</span> <span style="color: #666666">[</span>%ABC%<span style="color: #666666">]</span>
<span style="color: #666666">[</span>123<span style="color: #666666">]</span>
Value from getenv<span style="color: #666666">()</span>:
<span style="color: #666666">[</span>123<span style="color: #666666">]</span>
Value after deleting WITH <span style="color: #BA2121">'='</span>:
Value from shell:
cmd /c <span style="color: #008000">echo</span> <span style="color: #666666">[</span>%ABC%<span style="color: #666666">]</span>
<span style="color: #666666">[</span>%ABC%<span style="color: #666666">]</span>
Value from getenv<span style="color: #666666">()</span>:
<span style="color: #666666">[</span><NULL><span style="color: #666666">]</span>
</pre></div>
<p>Только на Windows getenv() возвращает NULL после удаления. На остальных это будет пустая строка.</p>
<p>Забавно, на Linux можно удалять переменные через putenv("name") (без знака "="), а тогда getenv() будет возвращать NULL.</p>
<p>Посты по теме:</p>
<blockquote>
<ul class="simple">
<li><a href="http://easy-coding.blogspot.com/2009/02/putenv.html">Статический аргумент функции putenv()</a></li>
</ul>
</blockquote>Александрhttp://www.blogger.com/profile/03980297457924475954noreply@blogger.com0tag:blogger.com,1999:blog-3940972473404160061.post-58720315601380177102011-10-30T15:31:00.000-07:002011-10-30T15:31:08.888-07:00Сколько дней в году работает программист<div dir="ltr" style="text-align: left;" trbidi="on">
Как вы оцениваете потенциальную продуктивность програмистов?<br />
<br />
Понятно, что все зависит от типа работы, поэтому даю конкретный пример.<br />
<br />
Дано: работа программиста над устоявшимся продуктом, который имеет major релизы раз в год; в течение года выпускаются minor релизы и критические исправления; плюс в поддержке находятся релизы последних 5-6 лет.<br />
<br />
Вот мой расчет:<br />
<br />
365 дней в году<br />
365 / 7 = 52 недели в году<br />
52 * 5 = 260 рабочих дней в году<br />
260 - 25 = 235 рабочих дней в году за вычетом отпуска<br />
235 - 10 = 225 рабочих дней в году за вычетом еще и государственных выходных<br />
225 - 15 = 210 еще минус две недели в среднем "по болезни"<br />
<br />
Итак: 210 человеко-восьмичасовых-дней.<br />
<br />
Общение с несколькими менеджерами программистов показало, что цифра "100 дней" является весьма распространенной как оценка сверху на то, сколько новой разработки планировать в год на человека.<br />
<br />
Получается, что после поддержки, затрат на внутренюю инфраструктуру, совещаний и обучений реально на разработку остается только половина времени.
</div>Александрhttp://www.blogger.com/profile/03980297457924475954noreply@blogger.com0