<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-13892761</id><updated>2024-10-12T19:39:15.252+03:00</updated><category term="erlang"/><category term="erlang.mk"/><category term="cowboy"/><category term="links"/><category term="silverlight"/><category term="забавы"/><category term="рецепты"/><category term="Castle"/><category term="bookmarklet"/><category term="dialyzer"/><category term="docker"/><category term="dot"/><category term="far"/><category term="inferno os"/><category term="javascript"/><category term="msdn"/><category term="msi"/><category term="nginx"/><category term="relx"/><category term="safaribug"/><category term="utilities"/><category term="windsor"/><category term="workaround"/><category term="релизы"/><title type='text'>Архив</title><subtitle type='html'>Подсчёт набитых шишек.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://kuklaora.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13892761/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://kuklaora.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/04910880378607725107</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>14</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-13892761.post-8878348742262623101</id><published>2015-04-19T16:14:00.000+03:00</published><updated>2015-04-19T16:14:48.737+03:00</updated><title type='text'>Orleans Silo Host + TopShelf windows service</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;

&lt;p&gt;&lt;a href=&quot;http://topshelf-project.com/&quot;&gt;TopShelf&lt;/a&gt; - хорошо сделанная библиотека для создания windows сервисов. 
Чтобы с ней сделать windows service достаточно просто добавить пакет Topshelf из NuGet и написать несколько строчек в Main().
Получается сервис, который можно запускать как консольное приложение, а можно установить в службы, запустив с командой install. &lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://dotnet.github.io/orleans/&quot;&gt;Orleans&lt;/a&gt; - интересная реализация системы акторов для .NET. Некоторых вещей в orleans пока сильно не хватает, например возможности управлять запущенной нодой (Silo).
То есть, чтобы обновить код работающего под управлением Orleans приложения, мне придётся сначала грохнуть процесс, потом переписать файлы и запустить процесс заново.&lt;/p&gt;

&lt;p&gt;Решил совместить оба варианта, чтобы можно было управлять запущенной нодой как windows-сервисом и останавливать-запускать из командной строки. 
Заодно появляется возможность разворачивать сервис с помощью, например, удобного &lt;a href=&quot;http://octopusdeploy.com/&quot;&gt;Octopus Deploy&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/kucheruk/Topshelf.Orleans&quot;&gt;Черновик на github.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Чтобы не дублировать код, берём из sdk orleans готовый OrleansHost.exe и добавляем как reference в наш проект.
Для того, чтобы остановить запуск сервиса при ошибках запуска Orleans, используем предоставленный TopShelf экземпляр HostControl, и вызываем .Stop(), после того как отработает OrleansHost.Run().&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/kucheruk/7b1cd00c1a6fb4d3b24f.js&quot;&gt;&lt;/script&gt;

&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://kuklaora.blogspot.com/feeds/8878348742262623101/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/13892761/8878348742262623101' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13892761/posts/default/8878348742262623101'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13892761/posts/default/8878348742262623101'/><link rel='alternate' type='text/html' href='http://kuklaora.blogspot.com/2015/04/orleans-silo-host-topshelf-windows.html' title='Orleans Silo Host + TopShelf windows service'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/04910880378607725107</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13892761.post-8072616917609381840</id><published>2015-03-20T14:05:00.000+03:00</published><updated>2015-03-20T15:37:27.435+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="cowboy"/><category scheme="http://www.blogger.com/atom/ns#" term="docker"/><category scheme="http://www.blogger.com/atom/ns#" term="erlang"/><category scheme="http://www.blogger.com/atom/ns#" term="erlang.mk"/><category scheme="http://www.blogger.com/atom/ns#" term="nginx"/><title type='text'>Разворачиваем приложение на Erlang (cowboy) с помощью Docker.</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;

&lt;p&gt;note: делалось это не для production кода, а с целью самообучения. Некоторые решения могут быть странными. Это получилось от того, что с докером я познакомился буквально на днях. Если кому что-то будет резать глаз - не поленитесь в комментариях написать про ошибку и как сделать правильно, спасибо. Также предполагается, что вы знаете &lt;a href=&quot;http://eax.me/docker/&quot;&gt;зачем нужен docker.&lt;/a&gt;&lt;/p&gt;


&lt;h3&gt;1. Структура проекта.&lt;/h3&gt;
&lt;p&gt;Под каждый контейнер выделяю отдельную папку. В корне проекта положим &lt;a href=&quot;https://docs.docker.com/compose/yml/&quot;&gt;docker-compose.yml&lt;/a&gt; (настройки бывшего fig, нынешнего docker-compose).&lt;/p&gt;
&lt;p&gt;Получаем такое дерево, в каждом каталоге лежит свой Dockerfile: &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;back - наше erlang приложение
&lt;li&gt;front - статические файлы и javascript, в моём случае это React-приложение, которое собирается с помощью webpack.
&lt;li&gt;nginx - конфиги для nginx, который будет работать как reverse proxy.
&lt;li&gt;pg - скрипты для создания базы данных в postgresql
&lt;li&gt;redis - контейнер с redis.
&lt;li&gt;sources - контейнер с исходниками.
&lt;/ul&gt;

&lt;h3&gt;2. Первый контейнер, sources.&lt;/h3&gt;
&lt;p&gt;Мне хочется использовать все эти контейнеры для разработки, поэтому мне нужно чтобы исходники проектов внутри контейнеров были теми исходниками, с которыми я работаю, а не их копией.
Поэтому создаю контейнер sources, в который через docker-compose будут подключены папки с сырцами.&lt;/p&gt;
&lt;p&gt;(Здесь и далее gist с docker-compose.yml это кусочек общего большого файла.)&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/kucheruk/9b91f05099ed6557cc5e.js&quot;&gt;&lt;/script&gt;

&lt;h3&gt;3. Второй контейнер, pg.&lt;/h3&gt;
&lt;p&gt;От postgres мне пока требуется всего две вещи: работать с заданным мною паролём и хранить данные в указанной папке.
Для этого возьмём docker image из стандартного репозитория. В нём оба вопроса решаются переменными окружения.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/kucheruk/c070bf614cabfed31683.js&quot;&gt;&lt;/script&gt;

&lt;h3&gt;4. Третий контейнер, redis.&lt;/h3&gt;
&lt;p&gt;С редисом всё просто до неприличия. Мне даже неинтересно, где он данные разместит и что с ними будет после перезапуска. (Что и как настроить в противном случае, описано &lt;a href=&quot;https://registry.hub.docker.com/_/redis/&quot;&gt;здесь&lt;/a&gt;)&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/kucheruk/2c1afdf8815f31bf556b.js&quot;&gt;&lt;/script&gt;

&lt;h3&gt;5. Четвёртый контейнер, backend.&lt;/h3&gt;
&lt;p&gt;Тут у меня будет строиться и стартовать erlang-приложение. Исходники приложения будут лежать в /app/backend.
Приложение представляет из себя rest и вебсокет хэндлеры на cowboy.
Если мне захочется чтобы исходники перегружались на лету в процессе разработки, я подключу в зависимостях пакет &lt;a href=&quot;https://github.com/rustyio/sync&quot;&gt;sync&lt;/a&gt; или &lt;a href=&quot;https://github.com/ninenines/live&quot;&gt;live&lt;/a&gt;.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/kucheruk/9f54adbd4a58dfecc5ca.js&quot;&gt;&lt;/script&gt;

&lt;h3&gt;6. Пятый контейнер, frontend.&lt;/h3&gt;
&lt;p&gt;С фронтом всё совсем просто: запускаем webpack в режиме watch, чтобы построив bundle он висел дальше, слушал изменения и достраивал по необходимости.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/kucheruk/7a8b0b6752079f2dce35.js&quot;&gt;&lt;/script&gt;

&lt;h3&gt;7. Шестой контейнер, nginx.&lt;/h3&gt;

&lt;p&gt;Теперь нам нужно поставить на входе nginx, который примет соединение и отправит его в зависимости от типа либо к бэкенду, либо на статический файл.
Вопрос лишь в том, как nginx&#39;у узнать адреса серверов. Проблема в том, что &lt;a href=&quot;http://serverfault.com/questions/577370/how-can-i-use-environment-variables-in-nginx-conf&quot;&gt;переменные окружения в nginx можно использовать&lt;/a&gt; только в главном конфиге, но нельзя в модулях, например upstream и location.
Поэтому сделаем так, чтобы на запуске контейнера с nginx на лету формировался файл с конфигом:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/kucheruk/1b5c329e4504064b3326.js&quot;&gt;&lt;/script&gt;


&lt;h3&gt;8. Всё готово.&lt;/h3&gt;
&lt;p&gt;&lt;b&gt; docker-compose build&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt; docker-compose up&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;При необходимости прицепиться к запущенным контейнерам и посмотреть логи, пишем &lt;b&gt;docker-compose logs&lt;/b&gt;.
Если требуется что-то выполнить внутри запущенного контейнера, пишем &lt;b&gt;docker ps&lt;/b&gt;, смотрим название контейнера в правом столбце &quot;NAMES&quot;, например myapp_nginx_1.
И выполняем: &lt;b&gt;docker exec myapp_nginx_1 ls -lR /etc/nginx/&lt;/b&gt;&lt;/p&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://kuklaora.blogspot.com/feeds/8072616917609381840/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/13892761/8072616917609381840' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13892761/posts/default/8072616917609381840'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13892761/posts/default/8072616917609381840'/><link rel='alternate' type='text/html' href='http://kuklaora.blogspot.com/2015/03/erlang-cowboy-docker.html' title='Разворачиваем приложение на Erlang (cowboy) с помощью Docker.'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/04910880378607725107</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13892761.post-4981405180996377403</id><published>2014-02-26T23:50:00.001+04:00</published><updated>2014-12-15T12:11:06.265+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="erlang"/><category scheme="http://www.blogger.com/atom/ns#" term="erlang.mk"/><category scheme="http://www.blogger.com/atom/ns#" term="relx"/><category scheme="http://www.blogger.com/atom/ns#" term="релизы"/><title type='text'>relx + erlang.mk, релизы в Erlang для самых маленьких, шпаргалка.</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
Когда я начинал знакомство с эрлангом - с релизами у меня сразу не сложилось.&lt;br /&gt;
Раз конфиг, два конфиг, прорва нюансов, не самая понятная документация.&lt;br /&gt;
Решил что мне и без них живётся неплохо.&lt;br /&gt;
&lt;br /&gt;
А тут вдруг попалось мне чудесное сочетание &lt;a href=&quot;https://github.com/extend/erlang.mk&quot;&gt;erlang.mk&lt;/a&gt; авторства &lt;a href=&quot;https://twitter.com/lhoguin&quot;&gt;Loïc Hoguin&lt;/a&gt; и &lt;a href=&quot;https://github.com/erlware/relx&quot;&gt;relx&lt;/a&gt; от &lt;a href=&quot;http://www.erlware.org/&quot;&gt;Erlware&lt;/a&gt;. 
&lt;br /&gt;
&lt;br /&gt;
И с ними вдруг оказалось что создать релиз - дело пяти минут.
&lt;br /&gt;
Конспект-шпаргалка с самого нуля:&lt;br /&gt;
&lt;br /&gt;
1. Создаём папку&lt;br /&gt;
&lt;pre&gt;mkdir tst
cd tst
&lt;/pre&gt;
&lt;br /&gt;
2. Скачиваем erlang.mk&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;wget https://raw.github.com/extend/erlang.mk/master/erlang.mk&lt;/pre&gt;
&lt;br /&gt;
3. Создаём каркас приложения&lt;br /&gt;
&lt;br /&gt;
make -f erlang.mk bootstrap&lt;br /&gt;
make -f erlang.mk bootstrap-rel&lt;br /&gt;
(подробности см. в readme репозитория erlang.mk)&lt;br /&gt;
&lt;br /&gt;
4. Смотрим в файл Makefile&lt;br /&gt;
&lt;br /&gt;
Он содержит в себе необходимый минимум:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;PROJECT=tst
include erlang.mk
&lt;/pre&gt;
&lt;br /&gt;
5. Проверяем:&lt;br /&gt;
&lt;pre&gt;make

 ERLC   tst_sup.erl tst_app.erl
 APP    tst.app.src
&lt;/pre&gt;
.....&lt;br /&gt;
&lt;br /&gt;
Отлично, всё компилируется.&lt;br /&gt;
&lt;br /&gt;
6. Добавим в Makefile каких-нибудь зависимостей, просто чтоб показать как это делается:&lt;br /&gt;
&lt;br /&gt;
PROJECT = tst&lt;br /&gt;
DEPS=mongodb gproc&lt;br /&gt;
&lt;br /&gt;
dep_mongodb = git https://github.com/comtihon/mongodb-erlang.git HEAD&lt;br /&gt;
include erlang.mk&lt;br /&gt;
&lt;br /&gt;
обращаем внимание: про часть библиотек erlang.mk &quot;знает&quot;. Например, gproc. Подробности опять же в readme. А те, про которые он не разумеет - необходимо добавлять руками, пример одного из способов - выше.&lt;br /&gt;
&lt;br /&gt;
7. проверяем: &lt;br /&gt;
&lt;br /&gt;
make&lt;br /&gt;
&lt;br /&gt;
Видим как все зависимости скачались и скомпилировались вместе с нашим приложением&lt;br /&gt;
&lt;br /&gt;
8. по отдельности:&lt;br /&gt;
&lt;br /&gt;
make clean&lt;br /&gt;
make deps&lt;br /&gt;
make app&lt;br /&gt;
&lt;br /&gt;
Всё работает!&lt;br /&gt;
&lt;br /&gt;
9. [много вырезано] Все шаги которые тут были ранее, по скачиванию и настройке relx, ныне делает сам erlang.mk&lt;br /&gt;
&lt;br /&gt;
10. Добавляем приложения, от которых мы  зависим в список applications файла src/tst.app.src. Тогда они будут запущены при старте автоматически.Получаем в итоге:&lt;br /&gt;
&lt;pre&gt;{application, tst,
 [
  {description, &quot;&quot;},
  {vsn, &lt;b&gt;&quot;0.0.1&quot;&lt;/b&gt;},
  {registered, []},
  {applications, [
                  kernel,
                  stdlib&lt;b&gt;,
                  gproc,
&lt;/b&gt;                 ]},
  {mod, { tst_app, []}},
&lt;b&gt;  {modules, [ tst_app, tst_sup ]},&lt;/b&gt;
  {env, []}
 ]}.
&lt;/pre&gt;
&lt;br /&gt;
11. А вот и всё. Если мы запускали make -f erlang.mk bootstrap-rel, то релиз у нас уже собирается автоматически и результат лежит в папке _rel&lt;br /&gt;
&lt;br /&gt;
12. Проверяем созданный релиз:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;cd _rel/tst_release
ls

bin  erts-6.0  lib  releases
&lt;/pre&gt;
&lt;br /&gt;
Запускаем:&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;bin/tst_release console&lt;/b&gt; - запустить вместе с erlang shell, наглядно&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;b&gt;bin/tst_release&lt;/b&gt; start&lt;/b&gt; - запустить демоном.&lt;br /&gt;
&lt;div style=&quot;overflow: auto; white-space: pre-wrap; width: 100%;&quot;&gt;
&lt;b&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/b&gt;
&lt;b&gt;&lt;b&gt;bin/tst_release&lt;/b&gt; stop&lt;/b&gt;&lt;/div&gt;
&lt;b&gt;&lt;b&gt;bin/tst_release&lt;/b&gt; restart&lt;/b&gt; &lt;br /&gt;
значение достаточно очевидно :)&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;b&gt;bin/tst_release&lt;/b&gt; attach&lt;/b&gt; - запустить шелл и прицепиться к запущенному в фоне процессу.&lt;br /&gt;
&lt;br /&gt;
остальные параметры можно посмотреть просто запустив bin/tst_release (а ещё лучше - просто прочитав исходник)&lt;br /&gt;
&lt;br /&gt;
Вот собственно и всё, вот он - готовый рабочий релиз :)&lt;br /&gt;
Логи лежат в папке log, можно их поглядеть например командой&lt;br /&gt;
tail -f log/erlang.log.1&lt;br /&gt;
&lt;br /&gt;
13. Ещё чуточку добавлю.&lt;br /&gt;
Довольно важная опция в relx.config - можно добавить&lt;code&gt; {include_erts, &quot;/path/to/alternate/erlang&quot;} или&amp;nbsp;&lt;/code&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;{include_erts, false}&lt;/span&gt;.&lt;br /&gt;
Тогда runtime system не будет добавлена в релиз, а это значит две вещи:&lt;br /&gt;
а) на машине куда будет поставлен релиз необходимо наличие установленного эрланга&lt;br /&gt;
б) нам будет всё равно какая архитектура на целевой машине&lt;br /&gt;
Если включать erts, то целевая машина должна быть той же архитектуры как и та на которой собран релиз. &lt;br /&gt;
&lt;br /&gt;
Кажется, всё?&lt;br /&gt;
&lt;br /&gt;
(проверено и приведено к актуальному виду 14 декабря 2014 года)&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://kuklaora.blogspot.com/feeds/4981405180996377403/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/13892761/4981405180996377403' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13892761/posts/default/4981405180996377403'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13892761/posts/default/4981405180996377403'/><link rel='alternate' type='text/html' href='http://kuklaora.blogspot.com/2014/02/relx-erlangmk-erlang.html' title='relx + erlang.mk, релизы в Erlang для самых маленьких, шпаргалка.'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/04910880378607725107</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13892761.post-7843438341611490551</id><published>2014-02-25T00:57:00.003+04:00</published><updated>2014-02-25T09:37:20.197+04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="dialyzer"/><category scheme="http://www.blogger.com/atom/ns#" term="erlang"/><category scheme="http://www.blogger.com/atom/ns#" term="erlang.mk"/><title type='text'>dialyzer + erlang.mk, статический анализ одной командой</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
(продолжение новичковых конспектов)&lt;br/&gt;

В качестве вступления обозначу очевидное.&lt;br/&gt;
Есть три способа узнать об ошибке в коде.&lt;br/&gt;
Долгий и муторный - поймать её в продакшене.&lt;br/&gt;
На порядок быстрее выловить тестами.&lt;br/&gt;
Самый шустрый - сразу, с помощью &lt;a href=&quot;http://www.erlang.org/doc/man/dialyzer.html&quot;&gt;статического анализатора&lt;/a&gt;.&lt;br/&gt;
Последние два способа хоть и не панацея, но время серьёзно экономят.&lt;br/&gt;
&lt;br/&gt;
Так вот давеча решил: пора навести порядок в коде.&lt;br/&gt;
И сделал ещё один подход к dialyzer`у.&lt;br/&gt;
&lt;br/&gt;
Как-то у нас не сложилось, когда я только знакомился с эрлангом.&lt;br/&gt;
Но в этот раз использую &lt;a href=&quot;https://github.com/extend/erlang.mk&quot;&gt;erlang.mk&lt;/a&gt; и процесс упростился донельзя.&lt;br/&gt;

Шаг первый, собираем информацию из системных модулей:&lt;br/&gt;
&lt;br/&gt;
&lt;b&gt;dialyzer --build_plt --apps kernel stdlib crypto mnesia sasl common_test eunit&lt;/b&gt;&lt;br/&gt;
(создаст ~/.dialyzer_plt)&lt;br/&gt;

Шаг второй, строим plt для своего проекта:&lt;br/&gt;
&lt;br/&gt;
&lt;b&gt;make build-plt&lt;/b&gt;&lt;br/&gt;
(создаст .имяпроекта.plt) &lt;br/&gt;
&lt;br/&gt;
Шаг третий - всё, можно приступать:&lt;br/&gt;
&lt;br/&gt;
&lt;b&gt;make dialyze&lt;/b&gt;&lt;br/&gt;
&lt;br/&gt;
И даже без добавления описаний типов в код - сразу же вылезла масса затаившихся ошибок. &lt;br/&gt;
&lt;br/&gt;
Из-за используемого lager`а мешали записи вида:&lt;br/&gt;
Call to missing or unexported function lager:warning/3&lt;br/&gt;
&lt;br/&gt;
Связано это с тем, что в исходниках lager`а упомянутых методов нету - они создаются во время компиляции.&lt;br/&gt;
Поэтому я немного поправил erlang.mk, заменив&lt;br/&gt;
&lt;br/&gt;
&lt;pre&gt;
dialyze:
 @dialyzer --src src --plt .$(PROJECT).plt --no_native $(DIALYZER_OPTS) 
&lt;/pre&gt;
&lt;br/&gt;
на &lt;br/&gt;
&lt;br/&gt;
&lt;pre&gt;
dialyze:
 @dialyzer --src src --plt .$(PROJECT).plt --no_native $(DIALYZER_OPTS) | fgrep -v -f ./dialyzer.ignore-warnings
&lt;/pre&gt;
&lt;br/&gt;
Создаём файл dialyzer.ignore-warnings:&lt;br/&gt;
&lt;br/&gt;
&lt;pre&gt;
Call to missing or unexported function lager:warning/3
Call to missing or unexported function lager:warning/1
Call to missing or unexported function lager:warning/2
Call to missing or unexported function lager:info/1
Call to missing or unexported function lager:info/2
Call to missing or unexported function lager:notice/2
Call to missing or unexported function lager:notice/1
Call to missing or unexported function lager:error/1
Call to missing or unexported function lager:error/2
&lt;/pre&gt;
&lt;br/&gt;
Не забываем, что каждая строка этого файла будет сравниваться со строкой вывода dialyzer`а. &lt;br/&gt;
Смотрим чтобы не было лишних пробелов в конце строк.&lt;br/&gt;
&lt;br/&gt;
Дальше самый долгий процесс - добавление информации о типах в проект.&lt;br/&gt;
Лучше не откладывать &quot;на потом&quot;.&lt;br/&gt;
В процессе описания типов найдётся о чём поразмыслить.&lt;br/&gt;
&lt;br/&gt;
Как прописывать типы замечательно &lt;a href=&quot;http://learnyousomeerlang.com/dialyzer#typing-about-types-of-types&quot;&gt;описано в LYSE&lt;/a&gt;, делать вольный пересказ резона нет.&lt;br/&gt;
&lt;br/&gt;
В некоторых сторонних приложениях уже есть описания используемых типов - некоторые могут пригодиться.&lt;br/&gt;
&lt;br/&gt;
Например в .hrl файле:&lt;br/&gt;
-include(&quot;deps/&lt;a href=&quot;https://github.com/alexeyr/erlang-sqlite3/blob/master/include/sqlite3.hrl#L22&quot;&gt;sqlite3/include/sqlite3.hrl&lt;/a&gt;&quot;).&lt;br/&gt;
(sqlite3 хороший пример приложения в котором всё тщательно описано)&lt;br/&gt;
&lt;br/&gt;

&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://kuklaora.blogspot.com/feeds/7843438341611490551/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/13892761/7843438341611490551' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13892761/posts/default/7843438341611490551'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13892761/posts/default/7843438341611490551'/><link rel='alternate' type='text/html' href='http://kuklaora.blogspot.com/2014/02/dialyzer-erlangmk.html' title='dialyzer + erlang.mk, статический анализ одной командой'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/04910880378607725107</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13892761.post-2755662524374167429</id><published>2013-03-02T22:21:00.002+04:00</published><updated>2013-03-02T23:28:57.038+04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="cowboy"/><category scheme="http://www.blogger.com/atom/ns#" term="erlang"/><title type='text'>Rest handler в web-сервере Cowboy, нюансы.</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
Этот пост - краткий итог моих ковыряний в недрах вебсервера &lt;a href=&quot;https://github.com/extend/cowboy&quot; target=&quot;_blank&quot;&gt;cowboy 0.8&lt;/a&gt;, &lt;a href=&quot;https://github.com/extend/cowboy/tree/master/examples&quot; target=&quot;_blank&quot;&gt;куцых примерах&lt;/a&gt; и &lt;a href=&quot;http://ninenines.eu/docs/en/cowboy/HEAD/guide/introduction&quot; target=&quot;_blank&quot;&gt;обрывках документации&lt;/a&gt;. &lt;br /&gt;
Написано чайником, как конспект самому себе.&lt;br /&gt;
&lt;br /&gt;
Обозначенные жирным шрифтом названия функций - вызываются ковбоем, если он находит их в export`ах модуля. (и естественно, должны быть экспортированы)&lt;br /&gt;
Обозначенные курсивом - называем как хотим, т.к. их названия отдаём ковбою мы.&lt;br /&gt;
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Как обозначить, что наш хэндлер - именно rest handler
&lt;br /&gt;
Определяем функцию &lt;b&gt;init&lt;/b&gt;/3:&lt;br /&gt;
&lt;br /&gt;
init(_Transport, _Req, _Opts) -&amp;gt; {upgrade, protocol, cowboy_rest}.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;Как получить что-то из middleware в State обработчика&amp;nbsp; (сессию например):
&lt;br /&gt;
Определяем метод &lt;b&gt;rest_init&lt;/b&gt;/2. &lt;br /&gt;
&lt;br /&gt;
rest_init( Req, State ) -&amp;gt; { ok, Req, State }.&lt;br /&gt;
&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;Как вернуть что-то на GET запрос:
&lt;br /&gt;
&lt;ol type=&quot;a&quot;&gt;
&lt;li&gt;Cowboy будет проверять поддерживается ли http method запроса нашим хэндлером.&lt;br /&gt;
Чтобы обозначить список поддерживаемых методов, определяем &lt;b&gt;allowed_methods&lt;/b&gt;/2:&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; allowed_methods( Req, State )-&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {[&amp;lt;&amp;lt;&quot;GET&quot;&amp;gt;&amp;gt;, &amp;lt;&amp;lt;&quot;PUT&quot;&amp;gt;&amp;gt;, &amp;lt;&amp;lt;&quot;DELETE&quot;&amp;gt;&amp;gt;], Req, State}.&lt;br /&gt;
&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;определяем тип возвращаемых данных:&lt;br /&gt;
&lt;br /&gt;
content_types_provided(Req, State) -&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {[{&amp;lt;&amp;lt;&quot;application/json&quot;&amp;gt;&amp;gt;, &lt;i&gt;наш_json_ответ&lt;/i&gt;}], Req, State}.&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;определяем обозначенный обработчик &lt;i&gt;наш_json_ответ&lt;/i&gt;/2:&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;i&gt;наш_json_ответ&lt;/i&gt;(Req, State) -&amp;gt;&lt;br /&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; ... ...&lt;br /&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; Json = mochijson2:encode({struct, ResponseObject}),&lt;br /&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {Json, Req, State}.&lt;br /&gt;
&lt;br /&gt;
&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;
&lt;li&gt;Как принять PUT запрос.&lt;br /&gt;
&lt;br /&gt;
&lt;ol type=&quot;a&quot;&gt;&lt;li&gt;Cowboy возьмет content-type реквеста и проверит, поддерживается ли он нашим обработчиком.&lt;br /&gt;
Для этого определяем следующую функцию:&lt;br /&gt;
&lt;br /&gt;
content_types_accepted(Req, State) -&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {[{{&amp;lt;&amp;lt;&quot;application&quot;&amp;gt;&amp;gt;, &amp;lt;&amp;lt;&quot;json&quot;&amp;gt;&amp;gt;, &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; [{&amp;lt;&amp;lt;&quot;charset&quot;&amp;gt;&amp;gt;, &amp;lt;&amp;lt;&quot;UTF-8&quot;&amp;gt;&amp;gt;}]}, &lt;i&gt;некий_обработчик&lt;/i&gt;}], Req, State }.&lt;br /&gt;
(можно использовать &#39;*&#39;)&lt;br /&gt;
&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;реализуем обозначенный выше &lt;i&gt;некий_обработчик&lt;/i&gt;:&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;
&lt;i&gt;некий_обработчик&lt;/i&gt;(Req, State) -&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Достаем json из тела запроса&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {ok, Body, Req1} = cowboy_req:body(Req),&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Декодируем json&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {struct, Object} = mochijson2:decode(Body),&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; делаем что нам нужно,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; ....&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Json = формируем json ответа,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Req3 = cowboy_req:set_resp_body( НашJsonОтвет, Req1 ),&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; { true, Req3, State2 }.&lt;br /&gt;
&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Как принять DELETE request.&lt;br /&gt;
&lt;br /&gt;необходимо определить функции &lt;b&gt;delete_resource&lt;/b&gt;/2, &lt;b&gt;delete_completed&lt;/b&gt;/2&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; сначала будет вызван первый, после второй.&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Из &lt;b&gt;delete_resource&lt;/b&gt;/2 возвращаем {true, Req, State} (true = удаляем, если false будет возвращен 500)&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; В &lt;b&gt;delete_completed&lt;/b&gt;/2 при необходимости обозначаем, что хотим отдать клиенту, например &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Req2 = cowboy_req:set_resp_body( &amp;lt;&amp;lt;&quot;{}&quot;&amp;gt;&amp;gt;, Req ),&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Возвращаем {true, Req2, State}.&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://kuklaora.blogspot.com/feeds/2755662524374167429/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/13892761/2755662524374167429' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13892761/posts/default/2755662524374167429'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13892761/posts/default/2755662524374167429'/><link rel='alternate' type='text/html' href='http://kuklaora.blogspot.com/2013/03/rest-handler-web-cowboy.html' title='Rest handler в web-сервере Cowboy, нюансы.'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/04910880378607725107</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13892761.post-8647433826425116799</id><published>2011-08-01T13:55:00.005+04:00</published><updated>2011-08-01T13:57:49.218+04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="safaribug"/><category scheme="http://www.blogger.com/atom/ns#" term="silverlight"/><title type='text'>Windows Safari 5 bug workaround: Backspace key in Silverlight</title><content type='html'>change&lt;br /&gt;&lt;br /&gt;   &amp;lt;param name=&quot;windowless&quot; value=&quot;false&quot;&amp;gt;&lt;br /&gt;&lt;br /&gt;to&lt;br /&gt;&lt;br /&gt;   &amp;lt;param name=&quot;windowless&quot; value=&quot;true&quot;&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;http://stackoverflow.com/questions/5110761/backspace-key-in-silverlight-text-box-shows-previous-page-in-safari-instead-of-ed&lt;br /&gt;&lt;br /&gt;same in flash: http://stackoverflow.com/questions/3634822/windows-safari-5-bug-when-using-backspace-in-a-flash-web-application</content><link rel='replies' type='application/atom+xml' href='http://kuklaora.blogspot.com/feeds/8647433826425116799/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/13892761/8647433826425116799' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13892761/posts/default/8647433826425116799'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13892761/posts/default/8647433826425116799'/><link rel='alternate' type='text/html' href='http://kuklaora.blogspot.com/2011/08/windows-safari-5-bug-workaround.html' title='Windows Safari 5 bug workaround: Backspace key in Silverlight'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/04910880378607725107</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13892761.post-8757831403518210216</id><published>2011-02-11T15:27:00.002+03:00</published><updated>2011-02-11T15:40:45.368+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="silverlight"/><category scheme="http://www.blogger.com/atom/ns#" term="workaround"/><title type='text'>Проблемы с Silverlight приложением, открытым в фоне</title><content type='html'>Иногда вредные пользователи открывают окно с silverlight приложением в фоне.&lt;br /&gt;В отдельной табке, например.&lt;br /&gt;&lt;br /&gt;В этом случае некоторый наш код инициализации в контролах столкнется, к примеру, со значениями ActualWidth и ActualHeight = 0, отсутствием некоторых контролов в дереве и прочими косяками.&lt;br /&gt;&lt;br /&gt;Возможно, есть красивый способ решить эту проблему, но я его пока не нашел.&lt;br /&gt;Поэтому опишу свой.&lt;br /&gt;&lt;br /&gt;Предположим, у нас есть контрол MyPanel, в котором есть метод void CalcSomething(), которому позарез нужно высчитать что-то хитрое основываясь на текущих размерах контрола.&lt;br /&gt;&lt;br /&gt;1. Добавляем поле&lt;br /&gt;&lt;br /&gt;        private readonly &lt;a href=&quot;http://msdn.microsoft.com/ru-ru/library/system.threading.autoresetevent.aspx&quot;&gt;ManualResetEvent&lt;/a&gt; layout_complete = new ManualResetEvent( false );&lt;br /&gt;&lt;br /&gt;2. В конструкторе MyPanel подписываемся на SizeChanged:&lt;br /&gt;&lt;br /&gt;         SizeChanged += on_size_changed;&lt;br /&gt;&lt;br /&gt;3. В обработчике события смотрим, посчитан ли уже размер для нашего контрола:&lt;br /&gt;&lt;br /&gt;        private void on_size_changed( object sender, SizeChangedEventArgs e )&lt;br /&gt;            {&lt;br /&gt;                if (ActualHeight != 0 &amp;amp;&amp;amp; ActualWidth != 0)&lt;br /&gt;                    _layout_complete.Set();&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;4. Если раньше наш метод CalcSomething вызывался просто, теперь он должен стартовать в отдельном потоке:&lt;br /&gt;&lt;br /&gt;new Thread(CalcSomething).Start();&lt;br /&gt;&lt;br /&gt;5. Исполнение CalcSomething отложим до момента, когда будет послан сигнал через _layout_complete:&lt;br /&gt;&lt;br /&gt;private void CalcSomething()&lt;br /&gt;{&lt;br /&gt;_layout_complete.WaitOne()&lt;br /&gt;...старый код работы с UI...&lt;br /&gt;&lt;br /&gt;6. И стоит учитывать, что поскольку мы теперь находимся в отдельном потоке, работать с UI напрямую нельзя.&lt;br /&gt;&lt;br /&gt;private void CalcSomething()&lt;br /&gt;{&lt;br /&gt;_layout_complete.WaitOne()&lt;br /&gt;Deployment.Current.Dispatcher.BeginInvoke( () =&gt;&lt;br /&gt;{&lt;br /&gt;...старый код работы с UI...&lt;br /&gt;} );&lt;br /&gt;}</content><link rel='replies' type='application/atom+xml' href='http://kuklaora.blogspot.com/feeds/8757831403518210216/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/13892761/8757831403518210216' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13892761/posts/default/8757831403518210216'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13892761/posts/default/8757831403518210216'/><link rel='alternate' type='text/html' href='http://kuklaora.blogspot.com/2011/02/silverlight.html' title='Проблемы с Silverlight приложением, открытым в фоне'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/04910880378607725107</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13892761.post-5615957254002116681</id><published>2009-01-14T14:06:00.004+03:00</published><updated>2009-01-14T14:24:12.870+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="bookmarklet"/><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><category scheme="http://www.blogger.com/atom/ns#" term="забавы"/><category scheme="http://www.blogger.com/atom/ns#" term="рецепты"/><title type='text'>Google Maps -&gt; Yandex Maps</title><content type='html'>Частенько изучая карту в гуглмапсах я хочу рассмотреть тот же участок в сильно похорошевших в последнее время бета-картах яндекса.&lt;br /&gt;&lt;br /&gt;Ну, не искать же руками каждый раз ту же самую загогулину на карте?&lt;br /&gt;&lt;br /&gt;Вот маленькая браузерная магия:&lt;br /&gt;&lt;br /&gt;javascript:function c(s){var z=s.split(&#39;,&#39;);return z[1]+&quot;,&quot;+z[0]};var u=gApplication.getPageUrl().split(&#39;?&#39;)[1].split(&#39;&amp;&#39;);var nu={};for(var i=0;i&amp;lt;u.length;i++){var t=u[i].split(&#39;=&#39;);nu[t[0]]=t[1];}var s=&quot;http://beta-maps.yandex.ru/?ll=&quot;+c(nu[&quot;ll&quot;])+&quot;&amp;spn=&quot;+c(nu[&quot;spn&quot;])+&quot;&amp;l=sat,skl&quot;;document.location=s;void(0);&lt;br /&gt;Эту строчку - &quot;букмарклет&quot; - можно добавить в закладки.&lt;br /&gt;&lt;br /&gt;Сценарий такой: Находишь место в гугле, смотришь. Щелкаешь по закладке, смотришь то же самое место в яндексе.&lt;br /&gt;&lt;br /&gt;В файрфоксе можно сделать еще лучше:&lt;br /&gt;В сохраненной закладке заполнить поле &quot;Keyword&quot; написав там например g2y.&lt;br /&gt;Тогда будет так:&lt;br /&gt;Просматривая карту на гугле жмем Alt+D (переходим в адресную строку), набираем g2y, Enter, попадаем на яндекс.&lt;br /&gt;Коммандлайн :)</content><link rel='replies' type='application/atom+xml' href='http://kuklaora.blogspot.com/feeds/5615957254002116681/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/13892761/5615957254002116681' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13892761/posts/default/5615957254002116681'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13892761/posts/default/5615957254002116681'/><link rel='alternate' type='text/html' href='http://kuklaora.blogspot.com/2009/01/google-maps-yandex-maps.html' title='Google Maps -&gt; Yandex Maps'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/04910880378607725107</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13892761.post-7274468815413792685</id><published>2008-12-18T14:16:00.005+03:00</published><updated>2008-12-18T14:49:16.918+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Castle"/><category scheme="http://www.blogger.com/atom/ns#" term="dot"/><category scheme="http://www.blogger.com/atom/ns#" term="windsor"/><category scheme="http://www.blogger.com/atom/ns#" term="рецепты"/><title type='text'>WindsorContainer Visualization</title><content type='html'>Сегодня простой рецепт. &lt;br /&gt;Как получить на входе WindsorContainer и получить на выходе картинку со всеми сервисами и их зависимостями друг от друга.&lt;br /&gt;&lt;br /&gt;1. Идем в Википедию и изучаем две страницы: &lt;br /&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/DOT_language&quot;&gt;DOT Language&lt;/a&gt;, &lt;a href=&quot;http://en.wikipedia.org/wiki/Graphviz&quot;&gt;Graphviz&lt;/a&gt; &lt;br /&gt;Краткое резюме: есть специальный язык для описание графов и программа способная его интерпретировать в нужный нам формат (рисовать картинку, например)&lt;br /&gt;&lt;br /&gt;2. Качаем и устанавливаем &lt;a href=&quot;http://graphviz.org/&quot;&gt;GraphViz&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;3. Пишем код:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;font size=&quot;2&quot; face=&quot;Courier New&quot; color=&quot;black&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#0000ff&quot;&gt;public&lt;/font&gt; &lt;font color=&quot;#0000ff&quot;&gt;class&lt;/font&gt; dump_windsor&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#0000ff&quot;&gt;public&lt;/font&gt; &lt;font color=&quot;#0000ff&quot;&gt;static&lt;/font&gt; &lt;font color=&quot;#0000ff&quot;&gt;void&lt;/font&gt; to_dot_file( &lt;font color=&quot;#0000ff&quot;&gt;string&lt;/font&gt; filename, IWindsorContainer cont )&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#2B91AF&quot;&gt;File&lt;/font&gt;.WriteAllText( filename, &lt;font color=&quot;#0000ff&quot;&gt;new&lt;/font&gt; digraph(&lt;font color=&quot;#A31515&quot;&gt;&quot;windsor&quot;&lt;/font&gt;, cont.Kernel.GraphNodes).ToString() );&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#0000ff&quot;&gt;private&lt;/font&gt; &lt;font color=&quot;#0000ff&quot;&gt;class&lt;/font&gt; digraph&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#0000ff&quot;&gt;private&lt;/font&gt; &lt;font color=&quot;#0000ff&quot;&gt;readonly&lt;/font&gt; &lt;font color=&quot;#0000ff&quot;&gt;string&lt;/font&gt; id;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#0000ff&quot;&gt;private&lt;/font&gt; &lt;font color=&quot;#0000ff&quot;&gt;readonly&lt;/font&gt; &lt;font color=&quot;#2B91AF&quot;&gt;List&lt;/font&gt;&amp;#60;graph_node&amp;#62; nodes = &lt;font color=&quot;#0000ff&quot;&gt;new&lt;/font&gt; &lt;font color=&quot;#2B91AF&quot;&gt;List&lt;/font&gt;&amp;#60;graph_node&amp;#62;();&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#0000ff&quot;&gt;public&lt;/font&gt; digraph( &lt;font color=&quot;#0000ff&quot;&gt;string&lt;/font&gt; id, &lt;font color=&quot;#2B91AF&quot;&gt;IEnumerable&lt;/font&gt;&amp;#60;GraphNode&amp;#62; nodes )&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#0000ff&quot;&gt;this&lt;/font&gt;.id = id;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#0000ff&quot;&gt;foreach&lt;/font&gt; ( &lt;font color=&quot;#0000ff&quot;&gt;var&lt;/font&gt; node &lt;font color=&quot;#0000ff&quot;&gt;in&lt;/font&gt; nodes )&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#0000ff&quot;&gt;foreach&lt;/font&gt; ( &lt;font color=&quot;#0000ff&quot;&gt;var&lt;/font&gt; dependent &lt;font color=&quot;#0000ff&quot;&gt;in&lt;/font&gt; node.Dependents )&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#0000ff&quot;&gt;this&lt;/font&gt;.nodes.Add( &lt;font color=&quot;#0000ff&quot;&gt;new&lt;/font&gt; graph_node( node, dependent ) );&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#0000ff&quot;&gt;public&lt;/font&gt; &lt;font color=&quot;#0000ff&quot;&gt;override&lt;/font&gt; &lt;font color=&quot;#0000ff&quot;&gt;string&lt;/font&gt; ToString()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#0000ff&quot;&gt;return&lt;/font&gt; &lt;font color=&quot;#2B91AF&quot;&gt;String&lt;/font&gt;.Format(&lt;font color=&quot;#A31515&quot;&gt;&quot;digraph {0} {{\n\t{1};\n\t{2}\n\t}}&quot;&lt;/font&gt;, id, &lt;font color=&quot;#2B91AF&quot;&gt;String&lt;/font&gt;.Join( &lt;font color=&quot;#A31515&quot;&gt;&quot;;\n\t&quot;&lt;/font&gt;, nodes.Select( node =&amp;#62; node.ToString() ) ), graph_options() );&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#0000ff&quot;&gt;private&lt;/font&gt; &lt;font color=&quot;#0000ff&quot;&gt;static&lt;/font&gt; &lt;font color=&quot;#0000ff&quot;&gt;string&lt;/font&gt; graph_options()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#0000ff&quot;&gt;return&lt;/font&gt; &lt;font color=&quot;#A31515&quot;&gt;&quot;graph [ overlap = false ]&quot;&lt;/font&gt;;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#0000ff&quot;&gt;private&lt;/font&gt; &lt;font color=&quot;#0000ff&quot;&gt;class&lt;/font&gt; graph_node&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#0000ff&quot;&gt;private&lt;/font&gt; &lt;font color=&quot;#0000ff&quot;&gt;readonly&lt;/font&gt; &lt;font color=&quot;#0000ff&quot;&gt;string&lt;/font&gt; left;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#0000ff&quot;&gt;private&lt;/font&gt; &lt;font color=&quot;#0000ff&quot;&gt;readonly&lt;/font&gt; &lt;font color=&quot;#0000ff&quot;&gt;string&lt;/font&gt; right;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#0000ff&quot;&gt;public&lt;/font&gt; graph_node(GraphNode left, GraphNode right)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#0000ff&quot;&gt;this&lt;/font&gt;.left = gn2string( left );&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#0000ff&quot;&gt;this&lt;/font&gt;.right = gn2string( right );&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#0000ff&quot;&gt;private&lt;/font&gt; &lt;font color=&quot;#0000ff&quot;&gt;static&lt;/font&gt; &lt;font color=&quot;#0000ff&quot;&gt;string&lt;/font&gt; gn2string( GraphNode left )&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#0000ff&quot;&gt;return&lt;/font&gt; ( (ComponentModel)left ).Name.Replace( &lt;font color=&quot;#A31515&quot;&gt;&#39;.&#39;&lt;/font&gt;, &lt;font color=&quot;#A31515&quot;&gt;&#39;_&#39;&lt;/font&gt; );&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#0000ff&quot;&gt;public&lt;/font&gt; &lt;font color=&quot;#0000ff&quot;&gt;override&lt;/font&gt; &lt;font color=&quot;#0000ff&quot;&gt;string&lt;/font&gt; ToString()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#0000ff&quot;&gt;return&lt;/font&gt; &lt;font color=&quot;#2B91AF&quot;&gt;String&lt;/font&gt;.Format(&lt;font color=&quot;#A31515&quot;&gt;&quot;{0} -&amp;#62; {1}&quot;&lt;/font&gt;, left, right );&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;&lt;font size=&quot;1&quot; color=&quot;gray&quot;&gt;* This source code was highlighted with &lt;a href=&quot;http://virtser.net/blog/post/source-code-highlighter.aspx&quot;&gt;&lt;font size=&quot;1&quot; color=&quot;gray&quot;&gt;Source Code Highlighter&lt;/font&gt;&lt;/a&gt;.&lt;/font&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;4. В любом месте где контейнер уже наполнен компонентами вызываем: dump_windsor.to_dot_file(&quot;c:\\windsor.dot&quot;, container);&lt;br /&gt;&lt;br /&gt;5. На получившийся файл натравливаем визуализатор:&lt;br /&gt;&quot;%ProgramFiles%\Graphviz 2.21\bin\dot.exe&quot; -Tpng -owindsor.png windsor.dot&lt;br /&gt;&lt;br /&gt;6. Смотрим картинку windsor.png. Ловкость рук, никакого мошеничества.&lt;br /&gt;&lt;br /&gt;7. Всю картинку конечно здесь не уместить, вот крохотный кусочек для примера, чтоб не порвать страницу :)&lt;br /&gt;&lt;br /&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhWmreGd4pILxZI46V7jyotKdIv2-OCV_hXE-CuLxj5VzQW-D1UgjxkDFLFkorwFyU54Cpfzsp6LyZsqaNJWUTwCQv6d28R7W7sMt29Nl2kDd7kU8yoAxYP9thNUJ9BU4BJ7uBH/s1600-h/windsor_cr1.png&quot;&gt;&lt;img style=&quot;display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 312px; height: 320px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhWmreGd4pILxZI46V7jyotKdIv2-OCV_hXE-CuLxj5VzQW-D1UgjxkDFLFkorwFyU54Cpfzsp6LyZsqaNJWUTwCQv6d28R7W7sMt29Nl2kDd7kU8yoAxYP9thNUJ9BU4BJ7uBH/s320/windsor_cr1.png&quot; border=&quot;0&quot; alt=&quot;&quot;id=&quot;BLOGGER_PHOTO_ID_5281095135150360818&quot; /&gt;&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://kuklaora.blogspot.com/feeds/7274468815413792685/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/13892761/7274468815413792685' title='Комментарии: 7'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13892761/posts/default/7274468815413792685'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13892761/posts/default/7274468815413792685'/><link rel='alternate' type='text/html' href='http://kuklaora.blogspot.com/2008/12/windsorcontainer-visualization.html' title='WindsorContainer Visualization'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/04910880378607725107</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhWmreGd4pILxZI46V7jyotKdIv2-OCV_hXE-CuLxj5VzQW-D1UgjxkDFLFkorwFyU54Cpfzsp6LyZsqaNJWUTwCQv6d28R7W7sMt29Nl2kDd7kU8yoAxYP9thNUJ9BU4BJ7uBH/s72-c/windsor_cr1.png" height="72" width="72"/><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13892761.post-350858397849293423</id><published>2008-07-14T14:35:00.001+04:00</published><updated>2008-07-14T14:37:19.954+04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="msi"/><title type='text'>Windows Installer</title><content type='html'>По работе разбирался с инсталляторами сделанными на базе Windows Installer.&lt;br /&gt;Вот некоторые полезные хинты. Это не какая-то эксклюзивная информация. &lt;br /&gt;Но раз уж я собрал все в своей голове - напишу, пока не забыл.&lt;br /&gt;&lt;br /&gt;Как диагностировать установку:&lt;br /&gt;&lt;br /&gt;Прямо сейчас запустите &quot;msiexec&quot;&lt;br /&gt;Много интересного! Все эти ключи можно передавать любому инсталлятору на схожей основе.&lt;br /&gt;&lt;br /&gt;Можно ставить отдельные .msi таким образом:&lt;br /&gt;msiexec /i имяфайла.msi [и все волшебные ключи]&lt;br /&gt;&lt;br /&gt;Самые полезный ключик:&lt;br /&gt;/lvx* путь:\имяфайла.log - исчерпывающий лог-файл установки. Если инсталлятор писали не плюшевые медведи - там будет много интересного.&lt;br /&gt;&lt;br /&gt;Можно (и нужно) взять код возврата инсталлятора. &lt;br /&gt;Он может дать информацию в случае отсутствия лога. &lt;br /&gt;Сверяться после установки со &lt;a href=&quot;http://desktopengineer.com/windowsinstallererrorcodes&quot;&gt;списком возможных кодов&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Как инсталлировать:&lt;br /&gt;&lt;br /&gt;Полезные ключики:&lt;br /&gt;/qn - установка без интерфейса. Т.е. просто все ставится по-тихому, не показывая окон. Все опции по умолчанию и т.д.&lt;br /&gt;/qb - то же самое по сути, но показывает интерфейс. В нем нельзя ничего нажать, но можно посмотреть, что происходит.&lt;br /&gt;&lt;br /&gt;Все что инсталлятор спрашивает у пользователя, хранится в свойствах. Если знать их названия, можно в некоторых рамках рулить процессом установки.&lt;br /&gt;&lt;br /&gt;Для примера, вот готовая командная строка полной &quot;тихой&quot; установки Sql Express Advanced Edition с Reporting Services с выставленными настройками (свойствами):&lt;br /&gt;&lt;br /&gt;Start /wait setup.exe /qn ADDLOCAL=ALL SAPWD=пароль SECURITYMODE=SQL SQLAUTOSTART=1 RSAUTOSTART=1 SQLACCOUNT=&quot;NT AUTHORITY\NETWORK SERVICE&quot; RSACCOUNT=&quot;NT AUTHORITY\NETWORK SERVICE&quot; DISABLENETWORKPROTOCOLS=0 RSCONFIGURATION=Default RSSQLLOCAL=1 INSTANCENAME=SQLEXPRESS&lt;br /&gt;&lt;br /&gt;(Информацию об этих свойствах в случае Microsoft`овского продукта можно &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/ms144259.aspx&quot;&gt;поискать в msdn&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;Запретить ребут после установки можно с помощью ключика /norestart. Понять что перезагрузка все-таки потребуется можно по тому же &lt;br /&gt;коду возврата. Т.е. если returncode == 3010, а не 0 - перезагрузку нужно будет сделать самому.</content><link rel='replies' type='application/atom+xml' href='http://kuklaora.blogspot.com/feeds/350858397849293423/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/13892761/350858397849293423' title='Комментарии: 3'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13892761/posts/default/350858397849293423'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13892761/posts/default/350858397849293423'/><link rel='alternate' type='text/html' href='http://kuklaora.blogspot.com/2008/07/windows-installer.html' title='Windows Installer'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/04910880378607725107</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13892761.post-1591275547097539672</id><published>2007-10-11T14:10:00.000+04:00</published><updated>2007-10-11T14:26:08.825+04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="far"/><title type='text'>Far Editor Tweak</title><content type='html'>Far - настоящий монстр, для тех кто умеет его &quot;готовить&quot; разумеется.&lt;br /&gt;Не хватало мне табуляции блоками, как в студии. Он конечно это умеет (Alt+I, Alt+U) но по одному знакоместу.&lt;br /&gt;Но это можно поправить. Примерно так:&lt;br /&gt; &lt;br /&gt;file: Tab.reg (Создать, сохранить, выполнить)&lt;br /&gt;&lt;br /&gt;REGEDIT4&lt;br /&gt;&lt;br /&gt;[HKEY_CURRENT_USER\Software\Far\KeyMacros\Editor\Tab]&lt;br /&gt;&quot;Sequence&quot;=&quot;%ts = Editor.Set(0, -1); $If (Selected) $Rep (%ts) AltI $End $Else Tab $EndIf&quot;&lt;br /&gt;&quot;Description&quot;=&quot;IndentsBlock&quot;&lt;br /&gt;&quot;NoSendKeysToPlugins&quot;=dword:00000001&lt;br /&gt;&quot;DisableOutput&quot;=dword:00000001&lt;br /&gt;&lt;br /&gt;file: ShiftTab.reg&lt;br /&gt;&lt;br /&gt;REGEDIT4&lt;br /&gt;&lt;br /&gt;[HKEY_CURRENT_USER\Software\Far\KeyMacros\Editor\ShiftTab]&lt;br /&gt;&quot;Sequence&quot;=&quot;%ts = Editor.Set(0, -1); $Rep (%ts) AltU $End&quot;&lt;br /&gt;&quot;DisableOutput&quot;=dword:00000001&lt;br /&gt;&quot;Description&quot;=&quot;UnindentsBlock&quot;</content><link rel='replies' type='application/atom+xml' href='http://kuklaora.blogspot.com/feeds/1591275547097539672/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/13892761/1591275547097539672' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13892761/posts/default/1591275547097539672'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13892761/posts/default/1591275547097539672'/><link rel='alternate' type='text/html' href='http://kuklaora.blogspot.com/2007/10/far-editor-tweak.html' title='Far Editor Tweak'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/04910880378607725107</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13892761.post-1496416656805611892</id><published>2007-05-28T00:26:00.001+04:00</published><updated>2007-05-28T00:28:25.777+04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="inferno os"/><category scheme="http://www.blogger.com/atom/ns#" term="links"/><title type='text'>Inferno OS</title><content type='html'>&lt;p&gt;Выцепил сегодня интересное для себя на хабре. &lt;br&gt;Не знаю, нужно ли это кому-нибудь из моего десятка :) читателей, но хотя бы поглядеть стоит:&lt;/p&gt; &lt;p&gt;&lt;a href=&quot;http://www.habrahabr.ru/blog/os_inferno/&quot;&gt;http://www.habrahabr.ru/blog/os_inferno/&lt;/a&gt;&lt;br&gt;&lt;a title=&quot;http://powerman.asdfgroup.com/Inferno/Limbo.html&quot; href=&quot;http://powerman.asdfgroup.com/Inferno/Limbo.html&quot;&gt;http://powerman.asdfgroup.com/Inferno/Limbo.html&lt;/a&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://kuklaora.blogspot.com/feeds/1496416656805611892/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/13892761/1496416656805611892' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13892761/posts/default/1496416656805611892'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13892761/posts/default/1496416656805611892'/><link rel='alternate' type='text/html' href='http://kuklaora.blogspot.com/2007/05/inferno-os.html' title='Inferno OS'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/04910880378607725107</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13892761.post-5137327612412219441</id><published>2007-04-30T20:08:00.001+04:00</published><updated>2011-09-23T15:10:46.900+04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="links"/><category scheme="http://www.blogger.com/atom/ns#" term="msdn"/><category scheme="http://www.blogger.com/atom/ns#" term="utilities"/><title type='text'>Package This - запакуй msdn</title><content type='html'>&lt;b&gt;update 23.09.2011: более живучая альтернатива http://vshelpdownloader.codeplex.com/&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;На msdn показали &lt;a href=&quot;http://www.codeplex.com/packagethis&quot;&gt;софтинку&lt;/a&gt;, которая позволяет выбрать кусок MSDN`овской немерянной библиотеки и, скачав, сохранить себе в chm или hxs файл. &lt;br /&gt;У меня для сохранения потребовала еще и наличия HtmlHelp Workshop. &lt;br /&gt;Впрочем, все что ей нужно для работы - описано по ссылке. &lt;br /&gt;Сама программка крохотная и с довольно спартанским интерфесом, что ей, впрочем, совсем не вредит.</content><link rel='replies' type='application/atom+xml' href='http://kuklaora.blogspot.com/feeds/5137327612412219441/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/13892761/5137327612412219441' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13892761/posts/default/5137327612412219441'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13892761/posts/default/5137327612412219441'/><link rel='alternate' type='text/html' href='http://kuklaora.blogspot.com/2007/04/package-this-msdn.html' title='Package This - запакуй msdn'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/04910880378607725107</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13892761.post-6901032063611183868</id><published>2006-12-21T17:05:00.000+03:00</published><updated>2006-12-21T17:08:08.373+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="забавы"/><title type='text'>Разработчики оценят юмор</title><content type='html'>как мне кажется. &lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;Мужик приходит к директору цирка.&lt;br /&gt;&lt;br /&gt;- Есть обалденный номер. Я поднимаюсь под купол цирка и прыгаю вниз головой с 20 метров на арену без всякой страховки. Встаю с манежа, приветствую публику. Пойдет?&lt;br /&gt;- А вы сколько хотите за это?&lt;br /&gt;- Триста долларов за каждый прыжок.&lt;br /&gt;- Ну, надо посмотреть.&lt;br /&gt;&lt;br /&gt;Идут на арену, мужик залезает под самый купол, прыгает вниз. Страшный удар головой о манеж, во все стороны опилки... Мужик, покачиваясь, поднимается...&lt;br /&gt;&lt;br /&gt;Директор:&lt;br /&gt;- В общем, неплохо. Значит, триста долларов...&lt;br /&gt;- Три тысячи.&lt;br /&gt;- Как три тысячи? Вы же только что говорили - триста.&lt;br /&gt;- Ну я тогда еще не пробовал...&lt;br /&gt;&lt;/blockquote&gt;</content><link rel='replies' type='application/atom+xml' href='http://kuklaora.blogspot.com/feeds/6901032063611183868/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/13892761/6901032063611183868' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13892761/posts/default/6901032063611183868'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13892761/posts/default/6901032063611183868'/><link rel='alternate' type='text/html' href='http://kuklaora.blogspot.com/2006/12/blog-post_21.html' title='Разработчики оценят юмор'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/04910880378607725107</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>