<?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-3474485280270816955</id><updated>2024-08-31T07:37:29.400-07:00</updated><category term="программирование"/><category term="Mercurial"/><category term="Linux"/><category term="Subversion"/><category term="администрирование"/><category term=".net"/><category term="C#"/><category term="dvcs"/><category term="Debian"/><category term="django"/><category term="python"/><category term="Kopete"/><category term="Mail.RU Agent"/><category term="ProFTPD"/><category term="SMTP"/><category term="asp.net"/><category term="git"/><category term="nhibernate"/><category term="reCaptcha"/><category term="Интернет"/><category term="ошибки"/><category term="поздравления"/><title type='text'>Brain IT!</title><subtitle type='html'>О программировании и около</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://brain-it.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://brain-it.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Гиркин Михаил</name><uri>http://www.blogger.com/profile/16452424330632615848</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWpXfCa2Zw5azq46Ne6mkbObiOZ4ur6gLIcRhlGoNL8pSkGPXZXbn2Gm1MdXWx7I_krlaZTv51_OqUf5dURg-wznG-_jtqrvoHxb0-n0a49Ki-6RoxmN1TjfpisPVjmg/s220/ava.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>23</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3474485280270816955.post-7709054495963479124</id><published>2011-12-31T06:01:00.000-08:00</published><updated>2011-12-31T06:09:27.817-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="поздравления"/><title type='text'>Новогодний привет</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Здравствуйте, уважаемые читатели!&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Редко в этом году получалось что-то написать сюда, надеюсь в следующем году будет как минимум по одному посту в месяц. Благо идей для этого много, времени только нехватает для реализации всех идей.&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Всем читателям профессиональных и личных успехов, стабильного роста во всех сферах жизни в новом году, мира и добра.&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Ждите новой информации в новом году!&lt;/div&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brain-it.blogspot.com/feeds/7709054495963479124/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://brain-it.blogspot.com/2011/12/blog-post.html#comment-form' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/7709054495963479124'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/7709054495963479124'/><link rel='alternate' type='text/html' href='http://brain-it.blogspot.com/2011/12/blog-post.html' title='Новогодний привет'/><author><name>Гиркин Михаил</name><uri>http://www.blogger.com/profile/16452424330632615848</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWpXfCa2Zw5azq46Ne6mkbObiOZ4ur6gLIcRhlGoNL8pSkGPXZXbn2Gm1MdXWx7I_krlaZTv51_OqUf5dURg-wznG-_jtqrvoHxb0-n0a49Ki-6RoxmN1TjfpisPVjmg/s220/ava.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3474485280270816955.post-3488529846463376502</id><published>2011-04-22T00:50:00.000-07:00</published><updated>2011-04-25T04:55:39.039-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".net"/><category scheme="http://www.blogger.com/atom/ns#" term="asp.net"/><category scheme="http://www.blogger.com/atom/ns#" term="C#"/><category scheme="http://www.blogger.com/atom/ns#" term="nhibernate"/><title type='text'>Управление сессиями NHibernate в приложениях ASP.NET MVC</title><content type='html'>&lt;div style=&quot;float:right; text-align:right; margin-left:15px; margin-top:10px;&quot;&gt;
&lt;a rev=&quot;vote-for&quot; href=&quot;http://progg.ru/Brain-IT-%D0%A3%D0%BF%D1%80%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5-%D1%81%D0%B5%D1%81%D1%81%D0%B8%D1%8F%D0%BC%D0%B8-NHibernate-%D0%B2-%D0%BF%D1%80%D0%B8%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F%D1%85-ASPNET-MVC&quot;&gt;&lt;img alt=&quot;Progg it&quot; src=&quot;http://progg.ru/image.axd?url=http%3A%2F%2Fbrain-it.blogspot.com%2F2011%2F04%2Fnhibernate-aspnet-mvc.html&quot; style=&quot;border:0px&quot;/&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;Здравствуйте, уважаемые читатели!&lt;/p&gt;
&lt;p&gt;В этой статье я хочу ответить на типичный вопрос разработчика, начинающего использовать NHibernate в web-приложениях, разрабатываемых на основе ASP.NET MVC - как управлять сессиями и конфигурацией NHibernate в рамках веб-приложения. Это первая проблема, которая встречается разработчику, и для того, чтобы не потерять производительность, и не получить странных трудновоспроизводимых ошибок необходимо корретно реализовать этот механизм. В сети я находил несколько разных версий, и в этой статье я приведу ту, которая показалась мне наиболее удобной.&lt;/p&gt;
&lt;p&gt;Итак, сначала немного теории. Как говорит вся документация на NHibernate - создавать конфигурацию и фабрику сессий затратная по времени операция, в то время как создавать сессию операция относительно быстрая. Таким образом, необходимо, чтобы в нашем приложении, конфигурация создавалась как можно реже, и была одна фабрика сессий, а сессии создавались для каждого HTTP запроса. Создавать больше одной сессии для HTTP запроса не имеет особого смысла.&lt;/p&gt;
&lt;p&gt;Таким образом, самое подходящее место для конфигурирования и создания фабрики сессий - это обработчик Application_Start. Я использую DI-контейнер LinFu, но он может быть с легкостью заменен любым другим. Я думаю семантика выполняемых действий будет ясна из приведенного кода.&lt;/p&gt;
&lt;pre name=&quot;code&quot; class=&quot;c-sharp&quot;&gt;
protected void Application_Start()
{
 AreaRegistration.RegisterAllAreas();

 var serviceContainer = new ServiceContainer();
 serviceContainer.AddService(CreateNhSessionFactory());
 ServiceContainerProvider.Init(serviceContainer);
 
 RegisterGlobalFilters(GlobalFilters.Filters);
 RegisterRoutes(RouteTable.Routes);
}

protected ISessionFactory CreateNhSessionFactory()
{
 var sessionFactory = Fluently.Configure()
  .Database(
   MsSqlConfiguration.MsSql2008.ConnectionString(
    x =&amp;gt; x.FromConnectionStringWithKey(&quot;ApplicationServices&quot;))
  )
  .Mappings(x =&amp;gt; x.FluentMappings.AddFromAssemblyOf&amp;lt;Issue&amp;gt;())
  .BuildSessionFactory();
 return sessionFactory;
}
&lt;/pre&gt;
&lt;p&gt;Думаю из кода видно, что в Application_Start конфигурируется NHibernate, создается фабрика сессий и помещается в DI контейнер. По умолчанию LinFu использует поведение типа Singleton (единственный объект на все приложение), если при регистрации сервиса передается конкретный объект. Итак, я добился того, что у меня будет одна фабрика сессий для всего ASP.NET MVC приложения. Замечу, что приложение ASP.NET - это отдельная тема для обсуждения, но как минимум следует знать, что в одном приложении могут обрабатываться тысячи запросов, создает и уничтожает приложение IIS в соответствии с настройками. Теперь нужно сделать так, чтобы у нас на один запрос была только одна сессия, которая будет использоваться всеми классами слоя доступа к данным.&lt;/p&gt;
&lt;p&gt;На самом деле нет ничего проще. Достаточно вспомнить, что есть структура данных привязанная к конктретному запросу - HttpContext. Ей и воспользуемся, для хранения сессии в рамках обработки одного HTTP запроса:&lt;/p&gt;
&lt;pre name=&quot;code&quot; class=&quot;c-sharp&quot;&gt;
protected const string NH_SESSION_KEY = &quot;NH_REQUEST_SESSION&quot;;

protected ISession GetSession()
{
 if (HttpContext.Current.Items.Contains(NH_SESSION_KEY))
  return HttpContext.Current.Items[NH_SESSION_KEY] as ISession;
 var session = ServiceContainerProvider.Container
  .GetService&amp;lt;ISessionFactory&amp;gt;()
  .OpenSession();
 HttpContext.Current.Items.Add(NH_SESSION_KEY, session);
 return session;
}

protected void CloseSession()
{
 if (!HttpContext.Current.Items.Contains(NH_SESSION_KEY)) return;

 var session = HttpContext.Current.Items[NH_SESSION_KEY] as ISession;
 session.Flush();
 session.Close();
 session.Dispose();
}
&lt;/pre&gt;
&lt;p&gt;Итак, мы реализовали метод, который возвращает мне объект сессии привязанный к текущему потоку обработки HTTP запроса. При этом создание сессии ленивое, она не будет создаваться и открываться когда этого не требуется. Осталось только зарегистрировать способ получения сессии в DI-контейнере. Нет ничего проще:&lt;/p&gt;
&lt;pre name=&quot;code&quot; class=&quot;c-sharp&quot;&gt;
protected void Application_Start()
{
 AreaRegistration.RegisterAllAreas();

 RegisterServices();
 RegisterGlobalFilters(GlobalFilters.Filters);
 RegisterRoutes(RouteTable.Routes);
}

protected void RegisterServices()
{
 var serviceContainer = new ServiceContainer();

 serviceContainer.AddService(CreateNhSessionFactory());
 serviceContainer.AddService(x =&amp;gt; GetSession(), LifecycleType.OncePerRequest);

 ServiceContainerProvider.Init(serviceContainer);
}
&lt;/pre&gt;
&lt;p&gt;Параметр определяющий время жизни объекта в данном случае не имеет особого значения, так как требуемый нам способ контроля за временем жизни реализован в методе GetSession(). Остался последний штрих, добавить закрытие сессии после окончания обработки HTTP-запроса:&lt;/p&gt;
&lt;pre name=&quot;code&quot; class=&quot;c-sharp&quot;&gt;
protected void Application_EndRequest()
{
 CloseSession();
}
&lt;/pre&gt;
&lt;p&gt;Все. Приведенные фрагменты легко адаптируются для другого DI контейнера, для ASP.NET WebForms приложения.&lt;/p&gt;
&lt;p&gt;Возможно в посте содержатся неточности и даже ошибки, в связи с чем я буду благодарен, если вы мне на них укажете.&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://brain-it.blogspot.com/feeds/3488529846463376502/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://brain-it.blogspot.com/2011/04/nhibernate-aspnet-mvc.html#comment-form' title='Комментарии: 6'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/3488529846463376502'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/3488529846463376502'/><link rel='alternate' type='text/html' href='http://brain-it.blogspot.com/2011/04/nhibernate-aspnet-mvc.html' title='Управление сессиями NHibernate в приложениях ASP.NET MVC'/><author><name>Гиркин Михаил</name><uri>http://www.blogger.com/profile/16452424330632615848</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWpXfCa2Zw5azq46Ne6mkbObiOZ4ur6gLIcRhlGoNL8pSkGPXZXbn2Gm1MdXWx7I_krlaZTv51_OqUf5dURg-wznG-_jtqrvoHxb0-n0a49Ki-6RoxmN1TjfpisPVjmg/s220/ava.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3474485280270816955.post-165701627388270294</id><published>2011-02-10T06:00:00.001-08:00</published><updated>2011-02-10T06:01:34.944-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="программирование"/><title type='text'>Рассуждения о стоимости заказной разработки программного обеспечения</title><content type='html'>&lt;p&gt;В последнее время к нам в фирму стали обращаться клиенты с довольно странным суждением о разработке программного обеспечения. Можно даже сказать накипело. Поэтому хочу поделиться выкладками и своим пониманием формирования стоимости разработки программного обеспечения на заказ. Возможно я в чем то ошибаюсь, возможно у меня неправильные представления, но лично я не вижу в чем ошибочность моих представлений.&lt;/p&gt;
&lt;p&gt;Я работаю в фирме которая занимается разработкой программного обеспечения, в том числе и разработкой на заказ. Я не буду раскрывать всех тонкостей нашего внутреннего формирования стоимости, но опишу главную идею и алгоритм прикидки цены, который мы используем каждый раз, когда к нам приходит заказчик и у нас начинаются с ним переговоры. Сначала расскажу пару небольших историй, которые произошли совсем недавно. Итак, история первая:&lt;/p&gt;
&lt;h3&gt;Деньгами не обижу, даю 20 тысяч!&lt;/h3&gt;
&lt;p&gt;Не так давно обратился к нам заказчик, который сказал что хочет &quot;маленькую программку&quot; отображающую данные поступающие с микроконтроллера. Пришли к нему в офис, начали выяснять, чего же он хочет на самом деле, про деньги сначала не говорили. Оказалось, что фирма уже сделала и сдает систему контроля уровня нефти в резервуарах для нефтехранилища. Есть как минимум два резервуара, в каждом из которых стоит штук по десять датчиков, микроконтроллер сибирает с них информацию и передает на пункт управления, предполагается что резервуаров может быть и больше.&lt;/p&gt;
&lt;p&gt;Так вот, нам предлагалось разработать программу, которая бы собирала эти данные, сохраняла их в виде логов, и контролировала аварийные режимы работы системы. В программе предполагалось два рабочих места - одно место для рабочего на конкретном резервуаре, которое бы отображало текущее состояние в графическом виде, контролировала бы динамику процесса и аварийные режимы, ну и собственно сигнализировала бы об аварийных режимах. Второе рабочее место - это место главного инженера, на котором собирается информация со всех &quot;одиночных&quot; рабочих мест, и соответственно отображается информация и выполняются те же функции контроля. Нам показали другие программы, которые делают примерно тоже самое. Ах, да, еще важным требованием было, чтобы программа была &quot;красивая&quot;.&lt;/p&gt;
&lt;p&gt;Когда речь зашла о бюджете, нам сказали что проект срочный, что сделать надо за 2 недели (как раз с этого дня), и поэтому с деньгами нас не обидят. Правда из документации, требующейся программисту, у них на всю систему была только тонюсенькая методичка по протоколу взаимодейтсвия, и ничего больше у них не было. Заказчик упорно пытался увильнуть от ответа, сколько же он денег предполагает потратить, но все таки раскололся, и огласил гигантскую сумму в 20 тысяч рублей! Я чуть не рассмеялся прямо там же, но совладал с собой&lt;/p&gt;
&lt;p&gt;Когда прошла первая волна эмоций, мы попробовали объяснить, что такие проекты нереально сделать за 20 тысяч, и также нереально сделать за 2 недели. Заказчик говорил, что вот, посмотрите, мы вам программы показывали! Они вообще бесплатные! Правда он забыл упомянуть что они идут в комплекте к серийной системе сбора информации, которая сама стоит приличных денег. В целом закончилось все хорошо - посмеялись и разошлись :)&lt;/p&gt;
&lt;h3&gt;Система лицензирования и оплаты за 6000!&lt;/h3&gt;
&lt;p&gt;Буквально сегодня зашел на weblancer.net и увидел, что некто хочет получить систему лицензирования и оплаты по СМС и пластиковым картам за 6000 рублей и в срок 1 неделя. Мне очень интересно было бы поговорить с заказчиком, что именно он хочет получить? Готов ли он доверить свои деньги и свой софт (который он по всей видимости собрался защищать) разработке неизвестного студента который будет это делать за пожрат. Может проще не защищать? Ведь это по всей видимости дешевле будет! А если уж защищать, то почему не заплатить $400-$600 за более-менее нормальную систему, которая конечно ничего не гаратирует, но от ручонок школьников вполне может помочь.&lt;/p&gt;
&lt;p&gt;То же самое с оплатой по смс и картам, ведь это же деньги. Как можно доверять системе за 6000 которая будет это делать? Человек уверен что он сможет верифицировать код на наличие дырок, которые переводят деньги тому самому фрилансеру? Кто потом будет поддерживать код, если потребуется его куда-то перенести? Как вообще это можно сделать за одну неделю? Да, оплата через пластик это несложно, достаточно заключить договор с агрегатором и написать небольшой кусок для обертки его API, и да, какую-то версию можно сделать за неделю. Но стоит ли неделя разработки 6000? А офис? А интернет? А налоги?&lt;/p&gt;
&lt;p&gt;Даже не глядя на результат, который заказчик возможно получит, я могу сказать, что это будет говнокод в лучшем случае, который дешевле выкинуть и написать заново. У меня такое представление, что наши &quot;бизнес-владельцы&quot; не умеют считать свои собственные деньги. Ведь в данном случае следовало бы один раз вложить деньги, и получить нормальный результат, который принесет ощутимую экономию в будущем. А если реальная экономия порядка 6000 рублей, то может не стоит инвестировать в проект?&lt;/p&gt;
&lt;h3&gt;Откуда берется стоимость часа работы&lt;/h3&gt;
&lt;p&gt;Я бы хотел немного рассказать свое понимание формирования стоимости разработки. Ведь цена часа разработчика берется не с потолка, а, по идее, должна быть экономически обоснована. Можно конечно работать &quot;за пожрат&quot;, но только вопрос, почему квалифицированный человек, разработчик программы должен делать работу и получать за нее столько, что ему хватает только поесть? Ведь, если по хорошему, он должен еще и лицензионным софтом пользоваться, и работать на хорошей машине, и еще много чего.&lt;/p&gt;
&lt;p&gt;Итак начнем. Из чего же складывается стоимость разработки:&lt;/p&gt;
&lt;ol&gt;
 &lt;li&gt;Зарплата. Примем зарплату разработчика равную 25000 рублей в месяц. На руки.&lt;/li&gt;
 &lt;li&gt;Начисления на зарплату и налоги. Если это организация на упрощенной схеме налогообложения, то это примерно 50% от чистой зарплаты (подоходный, пенсионные, ФСС)&lt;/li&gt;
 &lt;li&gt;Отпускные. Нужно же отдыхать? Пусть будет 10% от зарплатных затрат.&lt;/li&gt;
 &lt;li&gt;Непроизводительные расходы. Сюда входит ожидание ответов от заказчиков, выяснение требований, время на сдачу проекта, разборки с глюками сторонних библиотек и интерфейсов. Это примерно 10% от затрат. И это очень низкая оценка.&lt;/li&gt;
 &lt;li&gt;Офис, интернет, мебель, железо и софт. По реальным оценкам - это где то 5000 в месяц. Опять же, очень низкая оценка, но жить, в принципе, можно.&lt;/li&gt;
 &lt;li&gt;Риски. Всегда есть шанс недооценить проект, просчитаться по срокам, или вляпаться в неадекватного заказчика, у которого &quot;хотелки&quot; будут составлять столько же, сколько основной проект. Ну пусть тоже 10%.&lt;/li&gt;
 &lt;li&gt;Прибыль. Нужно же еще и развиваться, что то делать для себя, покупать компоненты и т.д. ну пусть будет 10%. Так сказать по европейски скромно (сейчас это процент по рублевому банковскому депозиту).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Давайте просто арифметически прикинем во что это выливается. Я прикинул в экселе, и получается что необходимо иметь входящих 55500 рублей в месяц. Чтобы все получилось так, как я описывал выше. То есть от чистой зарплаты это больше чем в 2 раза! И это я взял еще маленькую зарплату, за которую в провинции можно найти человека, с более-менее адекватной квалификацией. Но в городах с развитым IT сектором на такую зарплату к вам пойдут только умственные инвалиды. Если посчитать стоимость часа (в среднем в месяц рабочих часов 164) то получается примерно 340 рублей. То есть уже больше $10. И это я оценил по минимальной планке!&lt;/p&gt;
&lt;p&gt;Именно поэтому во всем цивилизованном мире уже известно, что лучше заплатить за готовый, серийный продукт чем написать свой такой же. Разница в стоимости будет минимум в десятки раз! Думаю теперь становится понятно, почему нельзя сделать систему защиты за $200, и систему контроля нефтехранилища за $700. Стоит ли говорить сколько подобных неадекватных заказчиков мы уже повстречали? Я уже не знаю как объяснить людям, что работа, котороая требует привлечения высококвалифицированных сотрудников не может стоить столько же сколько работа уборщицы или грузчика. Что странно доверять людям, которые просят за свою работу существенно меньше чем она того стоит. Что нужно учиться считать деньги, и считать их. Когда у вас болит зуб, и вам его выдергивают, и берут 700-1000 рублей фактически за 30 минут, вас это не смущает!&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://brain-it.blogspot.com/feeds/165701627388270294/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://brain-it.blogspot.com/2011/02/blog-post.html#comment-form' title='Комментарии: 4'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/165701627388270294'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/165701627388270294'/><link rel='alternate' type='text/html' href='http://brain-it.blogspot.com/2011/02/blog-post.html' title='Рассуждения о стоимости заказной разработки программного обеспечения'/><author><name>Гиркин Михаил</name><uri>http://www.blogger.com/profile/16452424330632615848</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWpXfCa2Zw5azq46Ne6mkbObiOZ4ur6gLIcRhlGoNL8pSkGPXZXbn2Gm1MdXWx7I_krlaZTv51_OqUf5dURg-wznG-_jtqrvoHxb0-n0a49Ki-6RoxmN1TjfpisPVjmg/s220/ava.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3474485280270816955.post-3943396199940797210</id><published>2010-11-27T05:48:00.000-08:00</published><updated>2010-11-27T06:00:57.309-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="django"/><category scheme="http://www.blogger.com/atom/ns#" term="python"/><category scheme="http://www.blogger.com/atom/ns#" term="reCaptcha"/><title type='text'>Используем reCaptcha в приложениях django</title><content type='html'>&lt;div style=&quot;float:right; text-align:right; margin-left:15px; margin-top:10px;&quot;&gt;
&lt;a rev=&quot;vote-for&quot; href=&quot;http://progg.ru/Brain-IT-%D0%98%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D1%83%D0%B5%D0%BC-reCaptcha-%D0%B2-%D0%BF%D1%80%D0%B8%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F%D1%85-django&quot;&gt;&lt;img alt=&quot;Progg it&quot; src=&quot;http://progg.ru/image.axd?url=http%3A%2F%2Fbrain-it.blogspot.com%2F2010%2F11%2Frecaptcha-django.html&quot; style=&quot;border:0px&quot;/&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;Сегодня мы поговорим об использовании reCaptcha в django-приложениях. Не буду говорить о достоинствах reCaptcha, думаю, что они и так понятны. Итак, наша задача состоит в том, чтобы как можно меньшими усилиями прикрутить reCaptcha к нашему приложению. Для этого нам потребуется выполнить следующее:&lt;/p&gt;
&lt;ul&gt;
 &lt;li&gt;
  Зарегистрироваться &lt;a href=&quot;http://www.google.com/recaptcha&quot;&gt;здесь&lt;/a&gt; и получить наши ключи
 &lt;/li&gt;
 &lt;li&gt;
  Сделать приложение django, которое будет отвечать за взаимодействие с серверами reCaptcha, и позволит использовать ее в наших формах
 &lt;/li&gt;
 &lt;li&gt; 
  Включить ее в одну из форм приложения, где она требуется
 &lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Шаг 1. Регистрация&lt;/h3&gt;
&lt;p&gt;Думаю, что как регистрироваться может разобраться любой из тех, кто понял что ему нужна reCaptcha в разрабатываемом приложении. Главное получить и сохранить ключи для вашего приложения. В зависимости от вашего желания вы можете получить ключи на конкретный адрес, или на все. Отмечу сразу, что любая пара валидных ключей корректно работает с адреса 127.0.0.1, что позволяет писать и отлаживать приложение на локальной машине, и не огребать при этом лишних проблем. Полученные ключи пропишем в settings.py примерно таким образом:&lt;/p&gt;
&lt;pre  style=&quot;font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXbeQKYYf8i3RyngT3Syn-X19e6-P6vVAYRX6pAr9R0OLPNwvyybKVrVVOhmwbCzkNhEYtagRaSKBNy5geLS0rvEVQWQIdIgVUjOB_B44iotxYrE2yi6slqZKArzHW9zvZz-3ky4xv6Lsh/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;&quot;&gt;&lt;code style=&quot;color:#000000;word-wrap:normal;&quot;&gt;  ...
  #reCAPTCHA keys  
  RECAPTCHA_PUBLIC_KEY = &amp;lt; ПУБЛИЧНЫЙ КЛЮЧ &amp;gt; 
  RECAPTCHA_PRIVATE_KEY = &amp;lt; СЕКРЕТНЫЙ КЛЮЧ &amp;gt;
  ... &lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;На этом подготовительный этап закончен.&lt;/p&gt;
&lt;h3&gt;Шаг 2. Приложение django&lt;/h3&gt;
&lt;p&gt;Создадим приложение django, которое будет предоставлять функциональность другим приложениям и скрывать детали взаимодействия с сервисом reCaptcha. Скажу честно, что я взял приложение &lt;a href=&quot;http://www.marcofucci.com/tumblelog/26/jul/2009/integrating-recaptcha-with-django/&quot;&gt;marcofucci&lt;/a&gt;, и только слегка его модифицировал.&lt;/p&gt;
&lt;p&gt;Для начала необходимо скачать &lt;a href=&quot;http://pypi.python.org/pypi/recaptcha-client&quot;&gt;recaptcha-client&lt;/a&gt;. При этом нам потребуется только captcha.py из клиента. Берем этот файлик и кладем в наше приложение. Он обеспечит нам базовое взаимодействие с сервисом. Теперь нам необходимо сделать виджет и поле формы, для того, чтобы можно было легко использовать reCaptcha в нашем приложении. Приведу сразу код, который взят у marcofucci:&lt;/p&gt;
&lt;p&gt;widgets.py&lt;/p&gt;
&lt;pre  style=&quot;font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXbeQKYYf8i3RyngT3Syn-X19e6-P6vVAYRX6pAr9R0OLPNwvyybKVrVVOhmwbCzkNhEYtagRaSKBNy5geLS0rvEVQWQIdIgVUjOB_B44iotxYrE2yi6slqZKArzHW9zvZz-3ky4xv6Lsh/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;&quot;&gt;&lt;code style=&quot;color:#000000;word-wrap:normal;&quot;&gt;  1:  # -*- coding: utf-8 -*-  
  2:  from django import forms  
  3:  from django.utils.safestring import mark_safe  
  4:  from django.conf import settings  
  5:  from recaptcha import captcha  
  6:  class ReCaptcha(forms.widgets.Widget):  
  7:    recaptcha_challenge_name = &#39;recaptcha_challenge_field&#39;  
  8:    recaptcha_response_name = &#39;recaptcha_response_field&#39;  
  9:    def render(self, name, value, attrs=None):  
  10:      return mark_safe(u&#39;%s&#39; % captcha.displayhtml(settings.RECAPTCHA_PUBLIC_KEY))  
  11:    def value_from_datadict(self, data, files, name):  
  12:      return [data.get(self.recaptcha_challenge_name, None),   
  13:        data.get(self.recaptcha_response_name, None)]   &lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;forms.py&lt;/p&gt;
&lt;pre  style=&quot;font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXbeQKYYf8i3RyngT3Syn-X19e6-P6vVAYRX6pAr9R0OLPNwvyybKVrVVOhmwbCzkNhEYtagRaSKBNy5geLS0rvEVQWQIdIgVUjOB_B44iotxYrE2yi6slqZKArzHW9zvZz-3ky4xv6Lsh/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;&quot;&gt;&lt;code style=&quot;color:#000000;word-wrap:normal;&quot;&gt;  1:  # -*- coding: utf-8 -*-  
  2:  from django.conf import settings  
  3:  from django import forms  
  4:  from django.utils.encoding import smart_unicode 
  5:  from django.utils.translation import ugettext_lazy as _  
  6:  from recaptcha.widgets import ReCaptcha  
  7:  from recaptcha import captcha  
  8:  class ReCaptchaField(forms.CharField):  
  9:    default_error_messages = {  
  10:      &#39;captcha_invalid&#39;: _(u&#39;Invalid captcha&#39;)  
  11:    }  
  12:    def __init__(self, *args, **kwargs):  
  13:      self.widget = ReCaptcha  
  14:      self.required = True  
  15:      super(ReCaptchaField, self).__init__(*args, **kwargs)  
  16:    def clean(self, values):  
  17:      super(ReCaptchaField, self).clean(values[1])  
  18:      recaptcha_challenge_value = smart_unicode(values[0])  
  19:      recaptcha_response_value = smart_unicode(values[1])  
  20:      check_captcha = captcha.submit(recaptcha_challenge_value,   
  21:        recaptcha_response_value, settings.RECAPTCHA_PRIVATE_KEY, {})  
  22:      if not check_captcha.is_valid:  
  23:        raise forms.util.ValidationError(self.error_messages[&#39;captcha_invalid&#39;])  
  24:      return values[0] &lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;Теперь мы готовы к использованию reCaptcha в нашем приложении.&lt;/p&gt;
&lt;h3&gt;Шаг 3. Использование&lt;/h3&gt;
&lt;p&gt;Использование сводится к созданию в форме соответствующего поля, и вполне обычной обработки формы в стиле django. Напиример так:&lt;/p&gt;
&lt;pre  style=&quot;font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXbeQKYYf8i3RyngT3Syn-X19e6-P6vVAYRX6pAr9R0OLPNwvyybKVrVVOhmwbCzkNhEYtagRaSKBNy5geLS0rvEVQWQIdIgVUjOB_B44iotxYrE2yi6slqZKArzHW9zvZz-3ky4xv6Lsh/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;&quot;&gt;&lt;code style=&quot;color:#000000;word-wrap:normal;&quot;&gt;  1:  class RegistrationForm(ModelForm):  
  2:       recaptcha = ReCaptchaField(error_messages = {  
  3:            &#39;required&#39;: u&#39;Это поле должно быть заполнено&#39;,            
  4:            &#39;invalid&#39; : u&#39;Указанное значение было неверно&#39;  
  5:            })  
  6:       class Meta:  
  7:            model = UserData  
  8:            fields = (  
  9:                 &#39;email&#39;,  
  10:                 &#39;fio&#39;,  
  11:                 &#39;phone&#39;,  
  12:                 &#39;company&#39;,  
  13:                 &#39;address&#39;  
  14:            )  &lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;В данном случае у меня имеется форма по модели, к которой добавлено поле с reCaptcha. Использование формы в функции вида приводить не буду, так как оно ничем не отличается от стандартного, достаточно заглянуть в &lt;a href=&quot;http://www.djangoproject.com&quot;&gt;документацию&lt;/a&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://brain-it.blogspot.com/feeds/3943396199940797210/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://brain-it.blogspot.com/2010/11/recaptcha-django.html#comment-form' title='Комментарии: 4'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/3943396199940797210'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/3943396199940797210'/><link rel='alternate' type='text/html' href='http://brain-it.blogspot.com/2010/11/recaptcha-django.html' title='Используем reCaptcha в приложениях django'/><author><name>Гиркин Михаил</name><uri>http://www.blogger.com/profile/16452424330632615848</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWpXfCa2Zw5azq46Ne6mkbObiOZ4ur6gLIcRhlGoNL8pSkGPXZXbn2Gm1MdXWx7I_krlaZTv51_OqUf5dURg-wznG-_jtqrvoHxb0-n0a49Ki-6RoxmN1TjfpisPVjmg/s220/ava.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3474485280270816955.post-5097263287976841249</id><published>2010-03-20T03:48:00.000-07:00</published><updated>2010-03-20T04:06:51.492-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="dvcs"/><category scheme="http://www.blogger.com/atom/ns#" term="git"/><category scheme="http://www.blogger.com/atom/ns#" term="Mercurial"/><category scheme="http://www.blogger.com/atom/ns#" term="Subversion"/><category scheme="http://www.blogger.com/atom/ns#" term="программирование"/><title type='text'>Джоел и Subversion, Mercurial, Git. Действительно антибиотик?</title><content type='html'>&lt;div style=&quot;float:right; text-align:right; margin-left:15px; margin-top:10px;&quot;&gt;
&lt;a rev=&quot;vote-for&quot; href=&quot;http://progg.ru/Brain-IT-%D0%94%D0%B6%D0%BE%D0%B5%D0%BB-%D0%B8-Subversion-Mercurial-Git-%D0%94%D0%B5%D0%B9%D1%81%D1%82%D0%B2%D0%B8%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D0%BE-%D0%B0%D0%BD%D1%82%D0%B8%D0%B1%D0%B8%D0%BE%D1%82%D0%B8%D0%BA&quot;&gt;&lt;img alt=&quot;Progg it&quot; src=&quot;http://progg.ru/image.axd?url=http%3A%2F%2Fbrain-it.blogspot.com%2F2010%2F03%2Fsubversion-mercurial-git.html&quot; style=&quot;border:0px&quot;/&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align:justify; text-indent:30px;&quot;&gt;
Недавно в блоге Джоела Спольски была опубликована последняя статья – &lt;a href=&quot;http://www.joelonsoftware.com/items/2010/03/17.html&quot;&gt;«Distributed Version Control is here to stay, baby»&lt;/a&gt;, по крайнее мере сам Джоель называет её последней. Статья, как понятно из заглавия посвящена распределенным системам контроля версий. После прочтения статьи возникло желание немного её прокомментировать. Сначала я выложу краткий обзор содержания, при этом постараюсь не упустить важных моментов. Делать полноценный перевод нет ни времени, ни желании. Итак, Джоел пишет следующее…
&lt;/div&gt;
&lt;div style=&quot;border:1px #999999 solid; background:#F8F4DC; padding:5px; margin-left:20px;&quot;&gt;
 &lt;div style=&quot;text-align:justify; font-style:italic;text-indent:30px;&quot;&gt;
 В распределенных системах контроля версий их распределенность не является самой интересной особенностью. Наиболее интересным является изменение модели – распределенные системы контроля версий работают с изменениями (changes), а не с версиями. Если централизованная система контроля версий «думает»: у меня есть версия 1, после этого будет версия 2, после этого версия 3 и так далее. В распределенной системе все по другому: сначала не было ничего, потом добавлены эти изменения, потом добавлены те, и т.д. Изменение программной модели должно изменить модель пользователя. Теперь пользователю тоже придется мыслить в терминах изменений. Если раньше было: «Я хочу получить версию номер Х», или «Я хочу последнюю версию», то теперь: «Хочу получить набор изменений Пети». 
 &lt;/div&gt;
 &lt;div style=&quot;text-align:justify; font-style:italic;text-indent:30px;&quot;&gt;
 Это смена парадигмы! Именно поэтому, когда вы переходите с Subversion на Mercurial, у вас вроде бы все получается, но вас новая система все время расстраивает, вы не можете к ней привыкнуть, и начинаете её ненавидеть. Только когда вы начнете мыслить в терминах «изменении», и выбросите из головы «версии» все встанет на свои места.
 Именно изменение модели работы системы контроля версий привело к существенному упрощению слияния (merge) кода. И соответственно к более активному использованию ветвления, использованию его там, где оно необходимо. Теперь можно не думая о сложностях последующего слияния создавать долгоживущие ветви для команд тестирования и поддержки и создавать короткоживущие ветви для экспериментов.
 &lt;/div&gt;
 &lt;div style=&quot;text-align:justify; font-style:italic;text-indent:30px;&quot;&gt;
 Если вы все еще используете SVN – перестаньте. Mercurial и Git – это антибиотики. Теперь существуют технология лучше.
 &lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align:justify;text-indent:30px;&quot;&gt;
И, вы знаете, я с Джоелом согласен почти полностью. Джоел смог объяснить то, что понимает каждый, кто освоился в распределенных системах. Но не каждый сможет выразить это словами. Это действительно смена основной концепции системы контроля версий, и именно из-за этого DVCS так туго входят в коллективы программистов. Наблюдаю это на личном опыте. Все привыкли мыслить категориями Subversion, и как только человек видит новую ветку в репозитории, даже ту, которая по идее скоро сольется с основной – он почему то пугается.
&lt;/div&gt;
&lt;div style=&quot;text-align:justify;text-indent:30px;&quot;&gt;
Продолжая пугаться, и не совсем понимая основных принципов системы, человек продолжает делать коммиты «раз в сутки», вместо того, чтобы делать коммиты по необходимости, по завершению каждой связной частички.
&lt;/div&gt;
&lt;div style=&quot;text-align:justify;text-indent:30px;&quot;&gt;
Однако распределенные системы контроля версий – это отнюдь не антибиотики. Главная проблема, как и всегда, в головах. И без решения этой проблемы никакой Hg, Git или Bazaar не спасет. Да, они гораздо больше соответствуют workflow разработки ПО, и большинство действий в этих системах легко объясняется логической необходимостью и разумностью. Но способов выстрелить себе в ногу в них значительно больше, хотя они и не очевидны. Наблюдал однажды картину, когда 4 разработчика постоянно работали каждый в своей ветке – в этом случае никакая смена парадигмы контроля версий не поможет.
&lt;/div&gt;
&lt;div style=&quot;text-align:justify;text-indent:30px;&quot;&gt;
Распределенные системы контроля версий – это отличная вещь, это действительно шаг вперед, который открывает каждому разработчику новые возможности и новую функциональность. И это действительно происходит за счет смены модели взаимодействия, Джоэл, безусловно, прав. Но, мне кажется, воспринимать их как серебряную пулю неправильно. Они избавляют от значительной части головной боли связанной с контролем версий, ветвлениями и слиянием. Однако от кривых рук они все равно не вылечат. Поэтому все равно необходимо нормально разбивать задачи, думать головой, и мержиться не раз в месяц с десятком изменений в каждом файле от каждого автора. Тут уж никакой Mercurial не спасет.
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brain-it.blogspot.com/feeds/5097263287976841249/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://brain-it.blogspot.com/2010/03/subversion-mercurial-git.html#comment-form' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/5097263287976841249'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/5097263287976841249'/><link rel='alternate' type='text/html' href='http://brain-it.blogspot.com/2010/03/subversion-mercurial-git.html' title='Джоел и Subversion, Mercurial, Git. Действительно антибиотик?'/><author><name>Гиркин Михаил</name><uri>http://www.blogger.com/profile/16452424330632615848</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWpXfCa2Zw5azq46Ne6mkbObiOZ4ur6gLIcRhlGoNL8pSkGPXZXbn2Gm1MdXWx7I_krlaZTv51_OqUf5dURg-wznG-_jtqrvoHxb0-n0a49Ki-6RoxmN1TjfpisPVjmg/s220/ava.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3474485280270816955.post-7781234453558375539</id><published>2010-03-09T10:51:00.000-08:00</published><updated>2010-03-09T21:07:15.313-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".net"/><category scheme="http://www.blogger.com/atom/ns#" term="C#"/><category scheme="http://www.blogger.com/atom/ns#" term="SMTP"/><category scheme="http://www.blogger.com/atom/ns#" term="ошибки"/><category scheme="http://www.blogger.com/atom/ns#" term="программирование"/><title type='text'>Известные баги System.Net.Mail.SmtpClient в .NET 3.5</title><content type='html'>&lt;div style=&quot;float: right; margin-left: 15px; margin-top: 10px; text-align: right;&quot;&gt;
&lt;a rev=&quot;vote-for&quot; href=&quot;http://progg.ru/%D0%98%D0%B7%D0%B2%D0%B5%D1%81%D1%82%D0%BD%D1%8B%D0%B5-%D0%B1%D0%B0%D0%B3%D0%B8-SystemNetMailSmtpClient-%D0%B2-NET-35&quot;&gt;&lt;img alt=&quot;Progg it&quot; src=&quot;http://progg.ru/image.axd?url=http%3A%2F%2Fbrain-it.blogspot.com%2F2010%2F03%2Fsmtpclient-net-35.html&quot; style=&quot;border:0px&quot;/&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Сегодня открыл для себя некоторые глюки класса System.Net.Mail.SmtpClient в .net framework 3.5. (Я уже не говорю что творилось с System.Web.Mail.*, но оно уже obsolete и слава небесам. RIP).&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
1. Некорректная реализация команды EHLO протокола SMTP. Согласно RFC#821 ещё лохматого года необходимо передавать FQDN хоста-отправителя, причем по RFC это правило строгое. Вместо этого в MS решили, что хватит и NetBIOS-имени компа. Соответственно сервера, не отклоняющиеся от стандарта посылают ентот SmtpClient лесом, как пытающийся разослать спам. Решения нет. Есть только очень неочевидный WorkAround через Reflection.&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
2. Вытекает из первого. MS хотела как лучше, и разрешила называть компьютеры в NetBIOS сетях именами с символами из национальных алфавитов. Мало того, собсно Windows 7 RU предлагает подобное имя при установке! (Правда при попытке сменить руками, уже после установки, честно предупреждает что нехорошо использовать символы русского алфавита). И, как я уже говорил выше, это NetBIOS-имя использует SmtpClient в качестве имени хоста, правда никак не кодируя символы национальных алфавитов. После чего сам же валится с исключением &quot;недопустимый знак в заголовке электронной почты&quot;. Собственно исключение то другое, но вот InnerException именно такой.&amp;nbsp;Решения нет. Есть только очень неочевидный WorkAround через Reflection.&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
3. Очень интересный взгляд на стандарты почтовых протоколов со стороны MS. Все уже привыкли, что MS если и читает чужие стандарты, то как то очень избирательно. Вот и стандарт на SMTP также ими был прочитан. И, соответственно, также реализован. Что привело к тому, что некоторые SMTP сервера напрочь не работают с SmtpClient от MS. Например Kerio. Решения нет. WorkAround&#39;ов нет.&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Обиднее всего то, что все это хозяйство тянется ещё с .net 2.0, все эти баги давно зарегистрированы, но MS плевало на отправку почты. Надо бы их SmtpClient с hotmail&#39;ом проверить. Интересно, заработает ли?&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brain-it.blogspot.com/feeds/7781234453558375539/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://brain-it.blogspot.com/2010/03/smtpclient-net-35.html#comment-form' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/7781234453558375539'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/7781234453558375539'/><link rel='alternate' type='text/html' href='http://brain-it.blogspot.com/2010/03/smtpclient-net-35.html' title='Известные баги System.Net.Mail.SmtpClient в .NET 3.5'/><author><name>Гиркин Михаил</name><uri>http://www.blogger.com/profile/16452424330632615848</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWpXfCa2Zw5azq46Ne6mkbObiOZ4ur6gLIcRhlGoNL8pSkGPXZXbn2Gm1MdXWx7I_krlaZTv51_OqUf5dURg-wznG-_jtqrvoHxb0-n0a49Ki-6RoxmN1TjfpisPVjmg/s220/ava.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3474485280270816955.post-8549085900927432309</id><published>2010-01-31T12:21:00.000-08:00</published><updated>2010-02-01T04:39:44.558-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="dvcs"/><category scheme="http://www.blogger.com/atom/ns#" term="Mercurial"/><category scheme="http://www.blogger.com/atom/ns#" term="Subversion"/><category scheme="http://www.blogger.com/atom/ns#" term="программирование"/><title type='text'>Введение в Mercurial. Часть 4. Способы организации ветвей</title><content type='html'>&lt;div style=&quot;float:right; text-align:right; margin-left:15px; margin-top:10px;&quot;&gt;
&lt;a rev=&quot;vote-for&quot; href=&quot;http://progg.ru/Brain-IT-%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5-%D0%B2-Mercurial-%D0%A7%D0%B0%D1%81%D1%82%D1%8C-4-%D0%A1%D0%BF%D0%BE%D1%81%D0%BE%D0%B1%D1%8B-%D0%BE%D1%80%D0%B3%D0%B0%D0%BD%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8-%D0%B2%D0%B5%D1%82%D0%B2%D0%B5%D0%B9&quot;&gt;&lt;img alt=&quot;Progg it&quot; src=&quot;http://progg.ru/image.axd?url=http%3A%2F%2Fbrain-it.blogspot.com%2F2010%2F01%2Fmercurial-4.html&quot; style=&quot;border:0px&quot;/&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;p style=&quot;text-align:justify; text-indent:30px;&quot;&gt;Здравствуйте, уважаемые читатели. Я продолжаю свою серию постов про распределенную 
систему контроля версий Mercurial. В этой статье мы подробно поговорим об основных 
приемах организации ветвлений в Mercurial. В 
предыдущей статье мы рассмотрели &amp;quot;спонтанное&amp;quot; ветвление, возникающее в случае наличия 
в репозитории разных линий ревизий от разных разработчиков, хотя каждый из них работает 
в основной ветви разработки, в этой статье мы рассмотрим работу с ветвлениями, вызванную 
осознанной необходимостью разделения линий разработки. Также в этой статье я буду 
указывать какие преимущества и недостатки имеются у обсуждаемых способов организации 
ветвей. Указанные преимущества и недостатки являются моим личным мнением, и вполне 
могут не совпадать с вашим.&lt;/p&gt;
&lt;p style=&quot;text-align:justify; text-indent:30px;&quot;&gt;Для начала дадим определения ветви, чтобы начинать с единого понимания процесса. 
Обратившись к wiki меркуриала я нашел определение, которое мне кажется вполне корректным:
&lt;b&gt;ветвь (branch)&lt;/b&gt; - это связанная последовательность ревизий (changeset) являющаяся 
отдельным направлением разработки. Таким образом, ветвь - это в первую очередь логическое 
понятие, так как в случае с распределенными системами контроля версий она будет 
содержать значительное число &amp;quot;спонтанных&amp;quot; ветвлений-слияний.&lt;/p&gt;
&lt;div style=&quot;float: right; text-align: center; width: 230px;&quot;&gt;
 &lt;img style=&quot;border:0;&quot; alt=&quot;Исходное состояние&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYlruL1G0DmslFzez3uuB57O4_lbBuHg-buqR9q7J44Zd7O7TdMdK0mNcVctpLNLs3ne4CR0Ke7e08VcrwJ_7Jj46FL37V2SIOT3t5lcTJUb_ZoAnKawxkp7u-Lw99dxoRmclpCbVsM9LY/&quot; /&gt;
 &lt;p style=&quot;margin: 5px 5px 15px 5px;&quot;&gt;Рисунок 1. Исходное состояние репозитория&lt;/p&gt;
 &lt;img style=&quot;border:0;&quot; alt=&quot;Анонимная ветвь&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgaErRU2cuNdIaXpBYupgeP5SACKEmq6gLd8E5lujgj3xrk4rxR2EO18GqixNyTPBP5zq7MeStcuN2DrugcdEDYQ4Abs6OfaEFE63JiZBnfZemAhQKYt50r_ZOpdWBmIUwuGPf-w-cA8afj/&quot; /&gt;
 &lt;p style=&quot;margin: 5px 5px 15px 5px;&quot;&gt;Рисунок 2. Новая анонимная ветвь в репозитории&lt;/p&gt;
&lt;/div&gt;
&lt;p style=&quot;text-align:justify; text-indent:30px;&quot;&gt;В этой статье продолжим работу над нашим примером. На рисунке показано состояние 
нашего репозитория после операций с ним в предыдущих частях цикла. И хотя формально 
в репозитории уже имеется одно ветвление, Mercurial нам говорит что ветвь одна:&lt;/p&gt;
&lt;pre style=&quot;font-weight:bold;font-size:10pt;&quot;&gt;
$ hg branches
default                        4:6d6c634e2e20
&lt;/pre&gt;
&lt;p style=&quot;text-align:justify; text-indent:30px;&quot;&gt;Команда &lt;b&gt;hg branches&lt;/b&gt; выводит список всех именованных ветвей в репозитории. 
Как мы видим основная ветвь разработки называется default. Если быть точным, так 
называется ветвь в которую происходит первый коммит в репозиторий, так сказать название 
по умолчанию. На рисунке 1 приведено текущее состояние репозитория и граф ревизий 
в нем находящихся. Я буду красным кружком отмечать &amp;quot;вершину&amp;quot; (tip) репозитория, 
как сказано в документации Mecurial, вершина - это самая свежая ревизия в репозитории. 
Команда &lt;b&gt;hg branches&lt;/b&gt; не выводит анонимные ветви, хотя разработчики могут их 
использовать при необходимости, и создавать самостоятельно.&lt;/p&gt;
&lt;h2&gt;Анонимное ветвление&lt;/h2&gt;
&lt;p style=&quot;text-align:justify; text-indent:30px;&quot;&gt;На самом деле, создание ветви при работе с Mercurial не является чем-то из ряда 
вон выходящим, для распределенной модели контроля версий это стандартная операция, 
и поэтому может быть произведена крайне просто, фактически, простым коммитом. То 
есть мы должны привести рабочую копию в состояние отличное от &amp;quot;вершины&amp;quot; (tip), внести 
изменения и выполнить коммит. Ничего больше. Для этого локальную копию исходного 
кода вернем в состояние ревизии &lt;b&gt;2:66c5686e355e&lt;/b&gt;:&lt;/p&gt;
&lt;pre style=&quot;font-weight:bold;font-size:10pt;&quot;&gt;
$ hg update -r 66c5
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
$ ls -l                   
-rw-r--r-- 1 mike mike 22 2010-01-07 22:22 first.txt         
-rw-r--r-- 1 mike mike 61 2009-11-27 11:15 other.txt         
-rw-r--r-- 1 mike mike 57 2009-11-27 00:03 readme.txt    
&lt;/pre&gt;
&lt;p style=&quot;text-align:justify; text-indent:30px;&quot;&gt;После этого создадим в локальной копии файл branch.txt, добавим его в репозиторий 
и выполним коммит:&lt;/p&gt;
&lt;pre style=&quot;font-weight:bold;font-size:10pt;&quot;&gt;
$ ls -l
-rw-r--r-- 1 mike mike 61 2010-01-31 18:55 branch.txt
-rw-r--r-- 1 mike mike 22 2010-01-07 22:22 first.txt 
-rw-r--r-- 1 mike mike 61 2009-11-27 11:15 other.txt
-rw-r--r-- 1 mike mike 57 2009-11-27 00:03 readme.txt
$ hg add
adding branch.txt
$ hg commit
created new head
$ hg branches
default                        5:ff8ffd5270cb
&lt;/pre&gt;
&lt;p style=&quot;text-align:justify; text-indent:30px;&quot;&gt;И Mercurial нам честно сообщает что создал новую &amp;quot;голову&amp;quot;. На рисунке 2 показано 
текущее состояние репозитория. Отмечу два момента: во-первых, ветвь default осталась 
на своем месте, и теперь заканчивается ревизией &lt;b&gt;5:ff8ffd5270cb&lt;/b&gt;, то есть &amp;quot;вершиной&amp;quot; 
(tip); а во-вторых все эти ветвления находятся локально в нашем репозитории. Локальность 
производимых ветвлений - это главное, коренное, отличие от централизованных систем 
контроля версий, в том числе от Subversion. Никто не увидит вашей ветви до тех пор 
пока вы не синхронизируете свой репозиторий с удаленным (обычно командой &lt;b&gt;push&lt;/b&gt;). 
С другой стороны выполнение &lt;b&gt;pull&lt;/b&gt; приведет к появлению в вашем репозитории 
всех ветвей, имеющихся в удаленном.&lt;/p&gt;
&lt;h3&gt;Преимущества&lt;/h3&gt;
&lt;p style=&quot;text-align:justify; text-indent:30px;&quot;&gt;Основным преимуществом этого способа является крайняя простота. Не нужно ничего 
придумывать, выполнять сложных операций, оповещать других участников команды - просто 
апдейт и коммит.&lt;/p&gt;
&lt;h3&gt;Недостатки&lt;/h3&gt;
&lt;p style=&quot;text-align:justify; text-indent:30px;&quot;&gt;Недостатки вытекают из анонимности ветви. Фактически, понять, что у вас есть 
ветвь разработки, исходя из вывода стандартных операций Mercurial, затруднительно. 
Особенно после 2-3 месяцев активной работы с репозиторием, когда количество таких 
мелких ветвлений приближается к сотне. Соответственно вам придется писать информативные 
подписи к коммитам, если анонимные ветви предполагается использовать в дальнейшем. 
Для переключения между ветвями разработки вам придется использовать номер ревизии, 
который, как известно, простой хэш - очень удобен для машины, но крайне неудобен 
для человека.&lt;/p&gt;
&lt;p style=&quot;text-align:justify; text-indent:30px;&quot;&gt;Таким образом, анонимные ветви - это отличный механизм для внесения быстрых (по 
количеству ревизий) исправлений, логически сильно связанных с направлением основной 
ветви разработки, то есть для организации ветвления на 2-3 ревизии с последующим 
слиянием с основной ветвью. Для организации больших ветвей, логически необходимых 
для разделения направлений разработки следует использовать именованные ветви.&lt;/p&gt;
&lt;h2&gt;Именованное ветвление&lt;/h2&gt;
&lt;div style=&quot;float: right; text-align: center; width: 230px;&quot;&gt;
 &lt;img style=&quot;border:0;&quot; alt=&quot;Именованная ветвь&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2fZTzMQzRHnBQpWmDf36rDB-lcU7Z1o32S00JK5AUEGw27Z4bGgHtIopCSQmBEQ_m6zkK6E0-LI_F8QX7kJXNIEZkV7l77AgKXJMU8lyoJA3lZ2R4jpsgyiCpkV78SqEOqUJXBncFvx8H/&quot; /&gt;
 &lt;p style=&quot;margin: 5px 5px 15px 5px;&quot;&gt;Рисунок 3. Именованные ветви в репозитории&lt;/p&gt;
&lt;/div&gt;
&lt;p style=&quot;text-align:justify; text-indent:30px;&quot;&gt;Вполне естественно, что в Mercurial предусмотрен способ создания ветвей разработки 
с некоторыми именами, задаваемыми пользователем. Для организации подобных ветвлений 
предназначена команда &lt;b&gt;hg branch&lt;/b&gt;. С помощью этой команды версия, находящаяся 
в локальной копии помечается ветвью с новым именем, при этом сама ветвь будет создана 
только после того, как вы выполните коммит. Попробуем сейчас сделать именованную 
ветвь, родительской ревизией для которой будет ff8f:&lt;/p&gt;
&lt;pre style=&quot;font-weight:bold;font-size:10pt;&quot;&gt;
$ hg branch new_feature
marked working directory as branch new_feature
$ hg commit
$ hg branches
new_feature                    6:4d530267d302
default                        5:ff8ffd5270cb
&lt;/pre&gt;
&lt;p style=&quot;text-align:justify; text-indent:30px;&quot;&gt;Итак мы видим, что Mercurial уже знает про две именованные ветви, &amp;quot;вершинами&amp;quot; 
для которых являются ревизии ff8f и 4d53, хотя на графе ревизий это одна ветвь. 
На рисунке 3 я показал, что именно понимается под именованной ветвью в Mercurial, 
при этом, фактически, для каждой ветви есть своя &amp;quot;вершина&amp;quot; (tip), хотя &lt;b&gt;hg log&lt;/b&gt; 
это не показывает (я приведу только смысловой отрывок):&lt;/p&gt;
&lt;pre style=&quot;font-weight:bold;font-size:10pt;&quot;&gt;
$ hg log
changeset:   6:4d530267d302
branch:      new_feature
tag:         tip
user:        mike@mike-vbox
date:        Sun Jan 31 21:31:07 2010 +0300
summary:     Создаие именованной ветви в репозитории

changeset:   5:ff8ffd5270cb
parent:      2:66c5686e355e
user:        mike@mike-vbox
date:        Sun Jan 31 18:56:23 2010 +0300
summary:     Создание анонимной ветви

changeset:   4:6d6c634e2e20
parent:      3:6872fa960507
parent:      2:66c5686e355e
user:        mike@mike-vbox
date:        Sun Jan 10 20:34:21 2010 +0300
summary:     Выполнен мерж двух веток

changeset:   3:6872fa960507
parent:      1:270e49e72f4b
user:        mike@mike-vbox
date:        Sun Jan 10 19:40:45 2010 +0300
summary:     Файл second.txt создан во втором репозитории
&lt;/pre&gt;
&lt;p style=&quot;text-align:justify; text-indent:30px;&quot;&gt;Убедиться в том, что &amp;quot;вершины&amp;quot; все таки существуют можно с помощью &lt;b&gt;hg update&lt;/b&gt;, 
то есть переключившись на другую ветвь:&lt;/p&gt;
&lt;pre style=&quot;font-weight:bold;font-size:10pt;&quot;&gt;
$ hg update default
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg ident
ff8ffd5270cb
&lt;/pre&gt;
&lt;p style=&quot;text-align:justify; text-indent:30px;&quot;&gt;А затем переключится обратно:&lt;/p&gt;
&lt;pre style=&quot;font-weight:bold;font-size:10pt;&quot;&gt;
$ hg update new_feature
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg ident
4d530267d302 (new_feature) tip
&lt;/pre&gt;
&lt;p style=&quot;text-align:justify; text-indent:30px;&quot;&gt;При этом в нашем репозитории сложилась интересная ситуация. tip ветви default 
не совпадает с &amp;quot;головой&amp;quot; (head) этой же ветви. В этом легко убедиться попросив Mercurial 
сказать какие же &amp;quot;головы&amp;quot; в нашем репозитории:&lt;/p&gt;
&lt;pre style=&quot;font-weight:bold;font-size:10pt;&quot;&gt;
$ hg heads
changeset:   6:4d530267d302
branch:      new_feature
tag:         tip
user:        mike@mike-vbox
date:        Sun Jan 31 21:31:07 2010 +0300
summary:     Создаие именованной ветви в репозитории

changeset:   4:6d6c634e2e20
parent:      3:6872fa960507
parent:      2:66c5686e355e
user:        mike@mike-vbox
date:        Sun Jan 10 20:34:21 2010 +0300
summary:     Выполнен мерж двух веток
&lt;/pre&gt;
&lt;p style=&quot;text-align:justify; text-indent:30px;&quot;&gt;Отмечу лишь один очень важный факт - ветвление произведено в вашем локальном 
репозитории, и вы можете работать с ним так, как вам угодно, при этом вы не боитесь 
поломать чужой код своим коммитом, или вызвать у тимлида приступ головной боли своими 
ветвлениями. Вот именно так концепция распределенной системы контроля версий позволяет 
решить стандартные болячки централизованных систем. &lt;/p&gt;
&lt;h3&gt;Преимущества&lt;/h3&gt;
&lt;p style=&quot;text-align:justify; text-indent:30px;&quot;&gt;Итак именованное ветвление лишь немногим сложнее анонимного, однако позволяет 
организовать работу над сложным проектом с несколькими направлениями разработки 
наиболее эффективным образом. Имя ветви является метаданными каждой ревизии, что 
позволяет корректно отслеживать изменения, произошедшие в проекте. Хотя принципиальных 
отличий от анонимных ветвей, на самом деле, нет. &lt;/p&gt;
&lt;h3&gt;Недостатки&lt;/h3&gt;
&lt;p style=&quot;text-align:justify; text-indent:30px;&quot;&gt;К недостаткам, в некоторой степени, можно отнести синдром разрастания ветвей. 
То есть, если вы будете использовать именованные ветви при каждой необходимости 
отпочковаться от основной, вывод команды &lt;b&gt;hg branches&lt;/b&gt; будет просто гиганским 
через некоторое время. Хотя ветви можно закрывать при коммитах (опция --close-branch), 
не стоит делать именованные ветви там где они не нужны.&lt;/p&gt;
&lt;h2&gt;Ветвление в клонах репозитория&lt;/h2&gt;
&lt;p style=&quot;text-align:justify; text-indent:30px;&quot;&gt;Последний способ организации ветвления о котором я расскажу - ветвление в клонах. 
На самом деле способ очевиден, и вытекает из третьей части этого цикла. Ничто не 
мешает пользователю лично создать клон репозитория и в нем вести отдельную ветвь 
разработки. Таким образом, для каждой ветви потребуется отдельный репозиторий. Безусловно 
модель распределенной системы контроля версий Mercurial позволяет подобную трактовку 
ветвления разработки, однако рассмотрим аспекты подобного подхода:&lt;/p&gt;
&lt;h3&gt;Преимущества&lt;/h3&gt;
&lt;p style=&quot;text-align:justify; text-indent:30px;&quot;&gt;Немного более безопаснее чем при других способах. На самом деле в данном случае 
способ выстрелить себе в ногу только один - запушить что нибудь этакое в удаленный 
репозиторий, тогда как при локальном ветвлении способов выстрелить себе в ногу немного 
больше. &lt;/p&gt;
&lt;h3&gt;Недостатки&lt;/h3&gt;
&lt;p style=&quot;text-align:justify; text-indent:30px;&quot;&gt;На мой взгляд недостатки перевешивают все преимущества. Самый главный недостаток 
- при каждом клонировании вам придется вытягивать весь репозиторий, то есть, если 
вам захотелось получить доступ к некоторой ветви вам придется вытянуть весь репозиторий 
относящийся к этой ветви, и так для каждой. Второй недостаток - бекапить вам придется 
не один репозиторий, а несколько. Что не логично. &lt;/p&gt;
&lt;p style=&quot;text-align:justify; text-indent:30px;&quot;&gt;На этом я заканчиваю рассматривать ветвления в Mercurial. Думаю следующая статья 
будет посвящена способам слияния ветвей, а также сложным моментам при слиянии, при 
упоминании которых у пользователей Subversion резко падает давление и начинают трястись 
руки. :) &lt;/p&gt;
&lt;p style=&quot;text-align:justify; text-indent:30px;&quot;&gt;Уважаемые читатели. Просьба комментировать посты. Возможно я упустил какие-то 
моменты, требующие разъяснения, о которых стоило бы написать. &lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://brain-it.blogspot.com/feeds/8549085900927432309/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://brain-it.blogspot.com/2010/01/mercurial-4.html#comment-form' title='Комментарии: 12'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/8549085900927432309'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/8549085900927432309'/><link rel='alternate' type='text/html' href='http://brain-it.blogspot.com/2010/01/mercurial-4.html' title='Введение в Mercurial. Часть 4. Способы организации ветвей'/><author><name>Гиркин Михаил</name><uri>http://www.blogger.com/profile/16452424330632615848</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWpXfCa2Zw5azq46Ne6mkbObiOZ4ur6gLIcRhlGoNL8pSkGPXZXbn2Gm1MdXWx7I_krlaZTv51_OqUf5dURg-wznG-_jtqrvoHxb0-n0a49Ki-6RoxmN1TjfpisPVjmg/s220/ava.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYlruL1G0DmslFzez3uuB57O4_lbBuHg-buqR9q7J44Zd7O7TdMdK0mNcVctpLNLs3ne4CR0Ke7e08VcrwJ_7Jj46FL37V2SIOT3t5lcTJUb_ZoAnKawxkp7u-Lw99dxoRmclpCbVsM9LY/s72-c" height="72" width="72"/><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3474485280270816955.post-2866789497434710919</id><published>2010-01-10T10:01:00.000-08:00</published><updated>2010-01-23T03:39:29.733-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="dvcs"/><category scheme="http://www.blogger.com/atom/ns#" term="Mercurial"/><category scheme="http://www.blogger.com/atom/ns#" term="Subversion"/><category scheme="http://www.blogger.com/atom/ns#" term="программирование"/><title type='text'>Введение в Mercurial. Часть 3. Начинаем ветвиться и сливаться</title><content type='html'>&lt;p style=&quot;text-indent:15px;text-align:justify&quot;&gt;
Продолжаю писать про систему контроля версий Mercurial. В этой части начну речь про сложные операции с репозиториями, а именно - создание ветвей и работа с ними. Работа с ветвями разработки пользователям Subversion доставляет немало головной боли, поэтому многие из них, когда видят во всех статьях про Mercurial, что им чуть ли не каждый день придется мержить (merge) ветки сильно пугаются, и теряют всякое желаение переходить на него. Однако я постараюсь переубедить всех недоброжелателей и консерваторов, поскольку в Mercurial работа с ветвлениями является не намного более сложной операцией чем коммит.
&lt;/p&gt;&lt;br/&gt;
&lt;p style=&quot;text-indent:15px;text-align:justify&quot;&gt;
Перед тем как продолжить разбираться с Mercurial поздравляю всех своих читателей с наступившим новым годом, желаю всяческих успехов в различных аспектах жизни, гармонии и добра во внутреннем мире, а также постоянного интеллектуального и духовного роста! С новым годом, уважаемые!
&lt;/p&gt;
&lt;p style=&quot;text-indent:15px;text-align:justify&quot;&gt;Итак, мы уже разбирали основы работы с репозиториями Mercurial в &lt;a href=&quot;http://brain-it.blogspot.com/2009/11/mercurial-2.html&quot;&gt;предыдущей части&lt;/a&gt;, и у нас сформировалось 2 готовых репозитория, сегодня мы продолжим взаимодействовать с ними и разберем, как организовать ветвление, и как потом с ним &quot;бороться&quot;. В этой части мы рассмотрим самое частое ветвление в Mercurual, которое можно даже назвать &quot;спонтанным&quot;.
&lt;/p&gt;&lt;p style=&quot;text-indent:15px;text-align:justify&quot;&gt;Первым ветвлением, с которым столкнется команда работающаяя с Mercurial - это ветвление при пулле новых изменений. Ситуация возникает когда в вашем локальном репозитории имеются закоммиченные но не запушенные изменения, и один (а то и несколько) ваших соратников закоммитили и запушили в &quot;центральный&quot; репозиторий свои изменения. Попробуем смоделировать ситуацию на имеющихся у нас трех репозиториях, с которыми мы начинали работать во второй части. Напомню читателям, что у нас в обоих репозиториях сохранено по две ревизии, при этом оба репозитория были синхронизированы с &quot;центральным&quot;. Попробуем внести в репозитории различные изменения и посмотреть что из этого выйдет.
&lt;/p&gt;&lt;p style=&quot;text-indent:15px;text-align:justify&quot;&gt;Для начала создадим файл first.txt в первом репозитории, закоммитим его и запушим:&lt;/p&gt;
&lt;/p&gt;&lt;pre style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;&lt;b&gt;$ echo &quot;new text to first.txt&quot; &amp;gt; first.txt
$ hg status
? first.txt      
$ hg add first.txt
$ hg commit
$ hg outgoing
comparing with /home/mike/Repositories/newProject
searching for changes
changeset:   2:66c5686e355e
tag:         tip
user:        mike@mike-vbox
date:        Thu Jan 07 22:28:39 2010 +0300
summary:     Коммит файла first.txt в первом репозитории
$ hg push
pushing to /home/mike/Repositories/newProject
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
&lt;/b&gt;&lt;/pre&gt;
&lt;p style=&quot;text-indent:15px;text-align:justify&quot;&gt;
А теперь сэмулируем ситуацию, когда наш товарищ также внес изменения, отличающиеся от наших, и посмотрим как такая ситуация разруливается средствами Mercurial, ведь подобная ситуация в случае командной разработки будет достаточно частой. Для этого переместимся в имеющийся у нас второй репозиторий, создадим в нем новый файл, и посмотрим что будет:
&lt;/p&gt;&lt;pre style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;&lt;b&gt;$ echo &quot;file created in second repository&quot; &amp;gt; second.txt
$ hg status
? second.txt
$ hg add
adding second.txt
$ hg commit
$ hg log
changeset:   2:6872fa960507
tag:         tip
user:        mike@mike-vbox
date:        Sun Jan 10 19:40:45 2010 +0300
summary:     Файл second.txt создан во втором репозитории

changeset:   1:270e49e72f4b
user:        mike@mike-notebook
date:        Fri Nov 27 10:39:35 2009 +0300
summary:     Записан файл other.txt в другом репозитории

changeset:   0:8fae369766e9
user:        mike@mike-notebook
date:        Fri Nov 27 08:58:01 2009 +0300
summary:     Файл readme.txt добавлен в репозиторий
&lt;/b&gt;&lt;/pre&gt;
&lt;p style=&quot;text-indent:15px;text-align:justify&quot;&gt;
Итак у нас уже имеется ситуация, когда в локалном репозитории и в удаленном отличаются &quot;головы&quot; разработки, то есть существуют две различные ревизии, производные от одной. В терминах любой системы контроля версий - это ветвление, пусть пока неявное, но скоро все тайное станет явным. Попробуем запушить имеющиеся ревизии в &quot;центральный&quot; репозиторий:
&lt;/p&gt;&lt;pre style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;&lt;b&gt;$ hg outgoing
comparing with /home/mike/Repositories/newProject
searching for changes
changeset:   2:6872fa960507
tag:         tip
user:        mike@mike-vbox
date:        Sun Jan 10 19:40:45 2010 +0300
summary:     Файл second.txt создан во втором репозитории

$ hg push
pushing to /home/mike/Repositories/newProject
searching for changes
abort: push creates new remote heads!
(did you forget to merge? use push -f to force)
&lt;/b&gt;&lt;/pre&gt;
&lt;p style=&quot;text-indent:15px;text-align:justify&quot;&gt;
Итак Mercurial нам запрещает пушить, говорит что пуш приведет к созданию новой головы в удаленном репозитории. И предлагает смержить репозитории. Ну чтож давайте это сделаем:
&lt;/p&gt;&lt;pre style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;&lt;b&gt;$ hg incoming
comparing with /home/mike/Repositories/newProject
searching for changes
changeset:   2:66c5686e355e
tag:         tip
user:        mike@mike-vbox
date:        Thu Jan 07 22:28:39 2010 +0300
summary:     Коммит файла first.txt в первом репозитории

$ hg pull
pulling from /home/mike/Repositories/newProject
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files (+1 heads)
(run &#39;hg heads&#39; to see heads, &#39;hg merge&#39; to merge)
&lt;/b&gt;&lt;/pre&gt;&lt;p style=&quot;text-indent:15px;text-align:justify&quot;&gt;
Мы вытянули с &quot;центрального&quot; репозитория все имеющиеся изменения, и Mercuial нам сообщает, что в локальном репозитории теперь две &quot;головы&quot; которые требуют слияния (мержа от английского to merge). Можно даже попросить Mercurial показать некоторую картинку (используется дополнение graphlog о котором я ещё не писал, расширение есть в стандартной поставке):
&lt;/p&gt;&lt;pre style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;&lt;b&gt;$ hg glog
o  changeset:   3:66c5686e355e
|  tag:         tip
|  parent:      1:270e49e72f4b
|  user:        mike@mike-vbox
|  date:        Thu Jan 07 22:28:39 2010 +0300
|  summary:     Коммит файла first.txt в первом репозитории
|
| @  changeset:   2:6872fa960507
|/   user:        mike@mike-vbox
|    date:        Sun Jan 10 19:40:45 2010 +0300
|    summary:     Файл second.txt создан во втором репозитории
|
o  changeset:   1:270e49e72f4b
|  user:        mike@mike-notebook
|  date:        Fri Nov 27 10:39:35 2009 +0300
|  summary:     Записан файл other.txt в другом репозитории
|
o  changeset:   0:8fae369766e9
   user:        mike@mike-notebook
   date:        Fri Nov 27 08:58:01 2009 +0300
   summary:     Файл readme.txt добавлен в репозиторий
&lt;/b&gt;&lt;/pre&gt;
&lt;p style=&quot;text-indent:15px;text-align:justify&quot;&gt;
Наличие двух &quot;голов&quot; очевидно, и что-то с этим надо делать. Поскольку мы пока не планировали целенаправленно создавать две ветви разработки. Поэтому выполним слияние имеющихся ветвей:
&lt;/p&gt;&lt;pre style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;&lt;b&gt;$ hg merge
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don&#39;t forget to commit)
$ ls
first.txt  other.txt  readme.txt  second.txt
&lt;/b&gt;&lt;/pre&gt;
&lt;p style=&quot;text-indent:15px;text-align:justify&quot;&gt;
Итак, Mercurial, после нашей команды &quot;hg merge&quot; смержил рабочую копию и репозиторий, и напоминает нам, что эти изменения следовало бы закоммитить. Так сделаем это:
&lt;/p&gt;&lt;pre style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;&lt;b&gt;$ hg commit
$ hg glog
@    changeset:   4:6d6c634e2e20
|\   tag:         tip
| |  parent:      2:6872fa960507
| |  parent:      3:66c5686e355e
| |  user:        mike@mike-vbox
| |  date:        Sun Jan 10 20:34:21 2010 +0300
| |  summary:     Выполнен мерж двух веток
| |
| o  changeset:   3:66c5686e355e
| |  parent:      1:270e49e72f4b
| |  user:        mike@mike-vbox
| |  date:        Thu Jan 07 22:28:39 2010 +0300
| |  summary:     Коммит файла first.txt в первом репозитории
| |
o |  changeset:   2:6872fa960507
|/   user:        mike@mike-vbox
|    date:        Sun Jan 10 19:40:45 2010 +0300
|    summary:     Файл second.txt создан во втором репозитории
|
o  changeset:   1:270e49e72f4b
|  user:        mike@mike-notebook
|  date:        Fri Nov 27 10:39:35 2009 +0300
|  summary:     Записан файл other.txt в другом репозитории
|
o  changeset:   0:8fae369766e9
   user:        mike@mike-notebook
   date:        Fri Nov 27 08:58:01 2009 +0300
   summary:     Файл readme.txt добавлен в репозиторий
&lt;/b&gt;&lt;/pre&gt;
&lt;p style=&quot;text-indent:15px;text-align:justify&quot;&gt;
На картинке которую нам показывает Mercurial неплохо видно что же именно происходило с репозиторием в течение этого, можно сказать урока. Также замечу, что у последней ревизии два &quot;предка&quot;, в отличие от остальных. Вообще в Mercrurial у ревизии может быть не более двух предков, что вполне логично, и для меня очевидно. Отправим теперь изменения в &quot;центральный&quot; репозиторий, и посмотрим что же делать теперь с ними первому разработчику.
&lt;/p&gt;&lt;pre style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;&lt;b&gt;$ hg push
pushing to /home/mike/Repositories/newProject
searching for changes
adding changesets
adding manifests
adding file changes
added 2 changesets with 1 changes to 1 files
&lt;/b&gt;&lt;/pre&gt;
&lt;p style=&quot;text-indent:15px;text-align:justify&quot;&gt;
Теперь переместимся в каталог первого разработчика, и получим изменения и из центрального репозитория:
&lt;/p&gt;&lt;pre style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;&lt;b&gt;$ hg pull
pulling from /home/mike/Repositories/newProject
searching for changes
adding changesets
adding manifests
adding file changes
added 2 changesets with 1 changes to 2 files
(run &#39;hg update&#39; to get a working copy)
$ hg update
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg glog
@    changeset:   4:6d6c634e2e20
|\   tag:         tip
| |  parent:      3:6872fa960507
| |  parent:      2:66c5686e355e
| |  user:        mike@mike-vbox
| |  date:        Sun Jan 10 20:34:21 2010 +0300
| |  summary:     Выполнен мерж двух веток
| |
| o  changeset:   3:6872fa960507
| |  parent:      1:270e49e72f4b
| |  user:        mike@mike-vbox
| |  date:        Sun Jan 10 19:40:45 2010 +0300
| |  summary:     Файл second.txt создан во втором репозитории
| |
o |  changeset:   2:66c5686e355e
|/   user:        mike@mike-vbox
|    date:        Thu Jan 07 22:28:39 2010 +0300
|    summary:     Коммит файла first.txt в первом репозитории
|
o  changeset:   1:270e49e72f4b
|  user:        mike@mike-notebook
|  date:        Fri Nov 27 10:39:35 2009 +0300
|  summary:     Записан файл other.txt в другом репозитории
|
o  changeset:   0:8fae369766e9
   user:        mike@mike-notebook
   date:        Fri Nov 27 08:58:01 2009 +0300
   summary:     Файл readme.txt добавлен в репозиторий
&lt;/b&gt;&lt;/pre&gt;
&lt;p style=&quot;text-indent:15px;text-align:justify&quot;&gt;Как видно из вышеприведенного лога, все прошло без различных эксцессов и проблем. Что не может не радовать. И, как и в прошлый раз, мы в трех репозиториях получили идентичную ситуацию, несмотря на несколько более сложную исходную.
&lt;/p&gt;&lt;p style=&quot;text-indent:15px;text-align:justify&quot;&gt;А теперь думаю самое главное - зачем же все это надо, ведь в SVN нет подобных проблем, да и мержить там не так часто... Ответ здесь очень простой - подобная модель взаимодействия с репозиторием провоцирует пользователя на частые коммиты, он не боится сломать код или репозиторий неудачным коммитом, не боится помешать другим пользователям и т.д. Коммит в Mercurial локален - пока вы не захотите отправить его в другой репозиторий, вся ветка коммитов останется у вас. К тому же слияние ревизий в Mercurial сделано намного проще и логичнее слияния ревизий в Subversion. Да, в поздних версиях и SVN научился более-менее нормально мержить, однако до Mercurial ему по прежнему далековато. И именно возможность частых локальных коммитов, в том числе когда у вас отстутствует подключение к интернету (а со мной такое случается нередко), меня так привлекла в Mercurial. Все остальные аспекты были на втором плане.
&lt;/p&gt;&lt;p style=&quot;text-indent:15px;text-align:justify&quot;&gt;В заключении сделаю одно важное замечание. В случае командной разработки, у Mercurial есть одна особенность (назвать недостатком как-то язык не поворачивается): целочисленная нумерация ревизий может быть различна в различных репозиториях, поэтому не стоит использовать целочисленные номера для идентификации ревизий при общении внутри команды. Поскольку идентифиратором ревизии в Mercurial является SHA1-хеш, вероятность совпадения которого для различных ревизий крайне мала, то стоит использовать именно его. Причем как показывает практика различных пользователей Mercurial - вполне достаточно первых 4х символов этого самого хеша (когда вам перестанет хватать 4х символов - используйте 5 ;) ).
&lt;/p&gt;
&lt;div&gt;
&lt;a rev=&quot;vote-for&quot; href=&quot;http://progg.ru/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5-%D0%B2-Mercurial-%D0%A7%D0%B0%D1%81%D1%82%D1%8C-3-%D0%9D%D0%B0%D1%87%D0%B8%D0%BD%D0%B0%D0%B5%D0%BC-%D0%B2%D0%B5%D1%82%D0%B2%D0%B8%D1%82%D1%8C%D1%81%D1%8F-%D0%B8-%D1%81%D0%BB%D0%B8%D0%B2%D0%B0%D1%82%D1%8C%D1%81%D1%8F&quot;&gt;&lt;img alt=&quot;Progg it&quot; src=&quot;http://progg.ru/image.axd?url=http%3A%2F%2Fbrain-it.blogspot.com%2F2010%2F01%2Fmercurial-3.html&quot; style=&quot;border:0px&quot;/&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brain-it.blogspot.com/feeds/2866789497434710919/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://brain-it.blogspot.com/2010/01/mercurial-3.html#comment-form' title='Комментарии: 5'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/2866789497434710919'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/2866789497434710919'/><link rel='alternate' type='text/html' href='http://brain-it.blogspot.com/2010/01/mercurial-3.html' title='Введение в Mercurial. Часть 3. Начинаем ветвиться и сливаться'/><author><name>Гиркин Михаил</name><uri>http://www.blogger.com/profile/16452424330632615848</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWpXfCa2Zw5azq46Ne6mkbObiOZ4ur6gLIcRhlGoNL8pSkGPXZXbn2Gm1MdXWx7I_krlaZTv51_OqUf5dURg-wznG-_jtqrvoHxb0-n0a49Ki-6RoxmN1TjfpisPVjmg/s220/ava.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3474485280270816955.post-4857908428976079959</id><published>2009-12-30T12:16:00.000-08:00</published><updated>2009-12-30T12:19:48.149-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Linux"/><category scheme="http://www.blogger.com/atom/ns#" term="ProFTPD"/><category scheme="http://www.blogger.com/atom/ns#" term="администрирование"/><title type='text'>ProFTPD: Показать скрытые файлы</title><content type='html'>Сегодня встала задача - необходимо, чтобы при доступе по FTP юзеру отображались также и скрытые файлы (начинающиеся с символа &quot;.&quot;), в частности .htaccess и ему подобные. У меня на сервере стоит ProFTPD, его настройка оказалась просто элементарной, для решения этой задачи. В конфиг добавляется срока:&lt;br /&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace; padding-top:10px;&quot;&gt;
&lt;b&gt;ListOptions &quot;-a&quot;&lt;/b&gt;
&lt;/div&gt;
Если уже имеется директива ListOptions в неё просто добавляется ключ &quot;-a&quot;, например:&lt;br /&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;padding-top:10px;&quot;&gt;
&lt;b&gt;ListOptions &quot;-al&quot;&lt;/b&gt;
&lt;/div&gt;
Все. Работает.&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://brain-it.blogspot.com/feeds/4857908428976079959/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://brain-it.blogspot.com/2009/12/proftpd.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/4857908428976079959'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/4857908428976079959'/><link rel='alternate' type='text/html' href='http://brain-it.blogspot.com/2009/12/proftpd.html' title='ProFTPD: Показать скрытые файлы'/><author><name>Гиркин Михаил</name><uri>http://www.blogger.com/profile/16452424330632615848</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWpXfCa2Zw5azq46Ne6mkbObiOZ4ur6gLIcRhlGoNL8pSkGPXZXbn2Gm1MdXWx7I_krlaZTv51_OqUf5dURg-wznG-_jtqrvoHxb0-n0a49Ki-6RoxmN1TjfpisPVjmg/s220/ava.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3474485280270816955.post-4133104119746569866</id><published>2009-12-27T09:08:00.000-08:00</published><updated>2010-01-23T03:43:17.164-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Debian"/><category scheme="http://www.blogger.com/atom/ns#" term="Linux"/><category scheme="http://www.blogger.com/atom/ns#" term="Mercurial"/><category scheme="http://www.blogger.com/atom/ns#" term="Subversion"/><category scheme="http://www.blogger.com/atom/ns#" term="администрирование"/><category scheme="http://www.blogger.com/atom/ns#" term="программирование"/><title type='text'>Введение в Mercurial. Часть внеочередная. Конвертируемся из Subversion</title><content type='html'>Всем привет!&lt;br /&gt;
Давненько я ничего не писал, но для того была достойная причина - 22 декабря я все таки защитил кандидатскую, что собственно и забирало уйму времени последние месяцы. Теперь я полноправный к.т.н.&lt;br /&gt;
&lt;br /&gt;
Сегодня маленький пост о том как сконвертировать имеющийся репозиторий Subversion в репозиторий Mercurial. Думаю что в необходимости перехода на Mercurial я постепенно смогу убедить своих читателей. Итак исходная позиция:&lt;br /&gt;
1. Имеется репозиторий svn лежащий на диске, пусть здесь: /[svn_repos_path]/svnrepo;&lt;br /&gt;
2. Хочется заиметь репозиторий Mercurial /[hg_repos_path/hgrepo со всей историей накопленной в Subversion, фактически импортировать все ревизии из svn в Mercurial.&lt;br /&gt;
Нет ничего проще.&lt;br /&gt;
1. Создаем новый репозиторий Mercurial:&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;b&gt;
mkdir /[hg_repos_path/hgrepo&lt;br /&gt;
cd /[hg_repos_path/hgrepo&lt;br /&gt;
hg&amp;nbsp; init
&lt;/b&gt;&lt;br /&gt;&lt;/div&gt;
&lt;br /&gt;
2. Разрешаем расширение convert. В Debian это делается так: в файл /[hg_repos_path/hgrepo/.hg/hgrc добавляем строчки:&lt;br /&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;br /&gt;
&lt;b&gt;[extensions]&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;convert=&lt;/b&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
3. А теперь выполняем собственно конвертирование:&lt;br /&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;br /&gt;
&lt;b&gt;cd /[hg_repos_path/hgrepo&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;hg convert file:///[svn_repos_path]/svnrepo .&lt;/b&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
Все. Mercurial выдает последовательность ревизий, и загоняет все что было в SVN репозитории в новый репозиторий Mercurial. Можно пользоваться ;)&lt;br /&gt;
&lt;div&gt;
&lt;a rev=&quot;vote-for&quot; href=&quot;http://progg.ru/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5-%D0%B2-Mercurial%D0%9A%D0%BE%D0%BD%D0%B2%D0%B5%D1%80%D1%82%D0%B8%D1%80%D1%83%D0%B5%D0%BC%D1%81%D1%8F-%D0%B8%D0%B7-Subversion&quot;&gt;&lt;img alt=&quot;Progg it&quot; src=&quot;http://progg.ru/image.axd?url=http%3A%2F%2Fbrain-it.blogspot.com%2F2009%2F12%2Fmercurial-subversion.html&quot; style=&quot;border:0px&quot;/&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brain-it.blogspot.com/feeds/4133104119746569866/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://brain-it.blogspot.com/2009/12/mercurial-subversion.html#comment-form' title='Комментарии: 4'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/4133104119746569866'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/4133104119746569866'/><link rel='alternate' type='text/html' href='http://brain-it.blogspot.com/2009/12/mercurial-subversion.html' title='Введение в Mercurial. Часть внеочередная. Конвертируемся из Subversion'/><author><name>Гиркин Михаил</name><uri>http://www.blogger.com/profile/16452424330632615848</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWpXfCa2Zw5azq46Ne6mkbObiOZ4ur6gLIcRhlGoNL8pSkGPXZXbn2Gm1MdXWx7I_krlaZTv51_OqUf5dURg-wznG-_jtqrvoHxb0-n0a49Ki-6RoxmN1TjfpisPVjmg/s220/ava.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3474485280270816955.post-8146362373848937536</id><published>2009-11-27T08:15:00.000-08:00</published><updated>2010-01-18T12:43:40.018-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Mercurial"/><category scheme="http://www.blogger.com/atom/ns#" term="Subversion"/><category scheme="http://www.blogger.com/atom/ns#" term="программирование"/><title type='text'>Введение в Mercurial. Часть 2. Основы работы</title><content type='html'>&lt;div style=&quot;text-align: justify;&quot;&gt;
Продолжаю писать и постить цикл статей про распределенную систему контроля версий Mercurial. Первая часть находится &lt;a href=&quot;http://brain-it.blogspot.com/2009/11/mercurial-1-dvcs.html&quot;&gt;здесь&lt;/a&gt;. В этой части рассказа о распределенной системе контроля
версий Mercurial речь пойдёт об основных командах, используемых при работе с
репозиториями. Статья покрывает начальный уровень взаимодействия с Mercurial, и
подразумевает, что у читающего есть некоторые навыки взаимодействия с
централизованными системами контроля версий, например, Subversion. Все примеры
в статье относятся к работе с Mercurial в unix-подобных системах, при этом для
работы в Windows потребуется лишь минимальная адаптация.&lt;br /&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;br /&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;font-family: Arial, Helvetica, sans-serif;&quot;&gt;Основные сведения о ревизиях в Mercurial&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Как и в большистве существующих систем контроля версий,
центральным понятием Mercurial являетя ревизия, которая здесь называется
changeset. В связи со спецификой распределенных систем контроля версий невозможно
выдать каждой ревизии её номер, поскольку не получится гарантировать его
уникальность среди всех существующих репозиториев. Однако&amp;nbsp; каждая ревизия все таки имеет уникальный
идентификатор, в случае Mercurial это 40-значный sha1-хеш, который учитывает
все параметры ревизии. Таким образом, у каждой новой ревизии в любом удаленном
репозитории будет свой уникальный идентификатор. Использование подобной
нумерации ревизий немного пугает начинающих пользователей, особенно переходящих
на Mercurial с svn, однако ничего страшного в них нет, и использование тех или
иных идентификаторов это просто дело привычки. &lt;br /&gt;
&lt;/div&gt;
&lt;br/&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Arial, Helvetica, sans-serif;&quot;&gt;&lt;b&gt;Начало работы&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Вся работа с системой котроля версий Mercurial происходит с
помощью команды hg, и во всех постах посвященных работе непосредственно с Mercurial,
я буду приводить именно консольные команды, и консольные способы работы.
Безусловно есть и вполне нормальные GUI-клиенты, однако освоение лучше начинать
именно с консоли, чтобы лучше понять как именно все работает, и каковы
логические и алгоритмические основы взаимодействия с этой системой контроля
версий.&lt;br /&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Работа с этой системой контроля версий, как, впрочем, и со
всеми остальными, начинается с создания репозитория в пустом каталоге файловой
системы. Для этого перейдём в выбранный каталог, пусть это будет
~/repos/hgproject, и скажем:&lt;br /&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;&amp;gt; hg init&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
По команде «hg init» Mercurial создает репозиторий в текущем
каталоге. Если посмотреть на результат работы — мы увидим&amp;nbsp; каталог «.hg», в которой собственно и
хранится вся история работы над проектом.&lt;br /&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
В принципе, рабочую копию можно хранить в той же папке, где
был создан репозиторий, но поскольку мы собираемся знакомится с системой
контроля версий, причем с распределенной, то будет лучше создать некое подобие
обычной структуры работы над проектом. Для этого создадим каталог, в котором
будет располагаться наш проект и перейдем в него, пусть это будет ~/projects.&lt;br /&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Теперь нужно получить данные для начала работы над проектом.
В общем случае это будет все содержимое некоторого репозитория расположенного
где-то на сервере. Для этого перейдем в ~/projects и скомандуем:&lt;br /&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;&amp;gt; hg clone ~/repos/hgproject&lt;/b&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
По команде «hg clone» Mercurial «клонирует» репозиторий
расположенный по указанному адресу в текущий каталог. При этом к вам попадает
именно репозиторий, то есть хранилище, содержащее всю существующую историю
изменений, что сильно отличает операцию клонирования от того же checkout в Subversion. Таким образом, у нас уже имеется два репозитория — то есть мы
локально получили именно распределенную систему контроля версий. Взаимодействие
может происходить с любым имеющимся репозиторием, так как они все равноценны,
однако мы назовем репозиторий в каталоге ~/repos/hgproject &quot;центральным&quot;, то есть
введем конвенцию на взаимодействие с системой. Практически в любом случае
работы в команде без подобных конвенций не обойтись.&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: Arial, Helvetica, sans-serif;&quot;&gt;&lt;b&gt;Работа с локальным репозиторием&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Начнем взаимодейтсвовать с полученной структурой
репозиториев. С помощью вашего любимого текстового редактора создадим новый
файл в каталоге с проектом, пусть для примера это будет readme.txt, и напишем
некую строку символов в этот файл. Итак мы уже получили файлы в проекте,
которые необходимо хранить в репозитории. Перед тем, как сохранить новый файл в
репозитории сначала убедимся в том, что Mercurial его видит, для этого в
каталоге с новым файлом выполним:&lt;br /&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;&amp;gt;hg status&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;? readme.txt&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
Mercurial ответил, что он видит файл readme.txt, при этом
этот файл пока не находится в системе контроля версий (символ «?» слева от
имени файла). По команде status Mercurial выводит состояние рабочей копии в
сравнении с состоянием локального репозитория. Для того, чтобы сказать
Mercurial, что его необходимо версионировать скажем:&lt;br /&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;&amp;gt; hg add&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;adding readme.txt&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;div&gt;
И ещё раз:&lt;br /&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;&amp;gt; hg status&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;A readme.txt&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;div&gt;
Видим, что слева от имени файла появился символ «А», который
означает что файл readme.txt будет добавлен в систему контроля версий при
следующем коммите, который мы сейчас и сделаем:&lt;br /&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;&amp;gt;hg commit&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Mercurial запустит текстовый редактор и попросит ввести
описание к выполняемому коммиту. Как только вы закроете его все изменения в
рабочей копии будут сохранены в локальном репозитории. Убедиться в этом
достаточно просто:&lt;br /&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;&amp;gt;hg log&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;changeset: &amp;nbsp; 0:8fae369766e9&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;tag: &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; tip&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;user: &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mike@mike-notebook&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;date: &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Fri Nov 27 08:58:01 2009 +0300&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;summary: &amp;nbsp; &amp;nbsp; Файл readme.txt добавлен в репозиторий&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Разберем, что Mercurial выдал в этом сообщении. Changeset —
это и есть номер ревизии, который состоит из двух частей: виртуального номера
ревизии(записан до «:») и идентификатора (sha1-хеша). Виртуальный номер ревизии
призван облегчить жизнь пользователям, и все-таки ввести в эту систему
некоторую нумерацию ревизий. Но, как показывает практика использовать этот
номер для однозначной идентификации нельзя, так как может привести к путанице в
понимании происходящего в репозиториях. Обычно для однозначной идентификации
версии достаточно 4-5 шестнадцатеричных цифр идентификатора. Следующей строкой
идёт «tag: tip», вообще говоря tip — это обозначение последней ревизии, хотя
выбирается это обозначение в различных случаях по различным принципам, в
дальнейшем, когда будем рассматривать организацию ветвлений этот момент
исследуем более подробно. Значение следующих строк очевидно, и нет
необходимости их как-либо комментировать.&lt;br /&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;br /&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: Arial, Helvetica, sans-serif;&quot;&gt;&lt;b&gt;Обмен с удаленными репозиториями&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
А теперь вспомним, что у нас есть ещё некий «центральный»
репозиторий, через который, по идее будет происходить взаимодействие с другими
членами команды разработки. При этом выполненный коммит был локальным, то есть
история изменений была сохранена только в вашем локальном репозитории. Для
того, чтобы передать изменения в репозиторий расположенный в ~/repos/hgproject
выполним:&lt;br /&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;&amp;gt; hg push&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;pushing to ~/repos/hgproject&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;searching for changes&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;adding changesets&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;adding manifests&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;adding file changes&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;added 1 changesets with 1 changes to 1 files&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
После выполнения этой команды все изменения зафиксированные
в локальном репозитории были зафиксированы также и в удаленном. Теперь
склонируем репозиторий ещё раз, и посмотрим как происходит обмен ревизиями в
Mercurial. Создадим новый каталог ~/projects/hgproj_clone, и склонируем в него
наш удаленный репозиторий:&lt;br /&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;&amp;gt;hg clone ~/repos/hgproject ~/projects/hgproj_clone&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;updating working directory&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;1 files updated, 0 files merged, 0 files removed, 0 files unresolved&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
И уже во вновь склонированном репозитории создадим файл
other.txt с помощью вашего любимого текстового редактора.&amp;nbsp; И снова повторим операции описанные выше:&lt;br /&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;&amp;gt; hg status&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;? other.txt&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;&amp;gt; hg add&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;adding other.txt&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;&amp;gt; hg commit&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;&amp;gt; hg log&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;changeset: &amp;nbsp; 1:270e49e72f4b&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;tag: &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; tip&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;user: &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mike@mike-notebook&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;date: &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Fri Nov 27 10:39:35 2009 +0300&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;summary: &amp;nbsp; &amp;nbsp; Записан файл other.txt в другом репозитории&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;changeset: &amp;nbsp; 0:8fae369766e9&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;user: &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mike@mike-notebook&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;date: &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Fri Nov 27 08:58:01 2009 +0300&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;summary: &amp;nbsp; &amp;nbsp; Файл readme.txt добавлен в репозиторий&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Видим, что в новом репозитории отражени как изменения
сделанные локально, так и изменения сделанные в удаленном репозитории, которые
мы ранее отправляли командой push. Теперь воспользуемся еще одной командой:&lt;br /&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;&amp;gt; hg outgoing&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;comparing with ~/repos/hgproject&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;searching for changes&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;changeset: &amp;nbsp; 1:270e49e72f4b&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;tag: &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; tip&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;user: &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mike@mike-notebook&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;date: &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Fri Nov 27 10:39:35 2009 +0300&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;summary: &amp;nbsp; &amp;nbsp; Записан файл other.txt в другом репозитории&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
По команде hg outgoing Mercurial выводит список ревизий
которые есть в вашем локальном репозитории, но которых нет в «центральном».
Отправим появившиеся ревизии в «центральный» репозиторий известным нам
способом:&lt;br /&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;&amp;gt; hg push&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;pushing to ~/repos/hgproject&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;searching for changes&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;adding changesets&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;adding manifests&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;adding file changes&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;added 1 changesets with 1 changes to 1 files&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Итак, в «центральном репозитории две ревизии. Теперь
научимся забирать обновления из центрального репозитория. Для этого перейдём в
каталог с первым клоном, то есть в ~/projects/hgproject, и скажем:&lt;br /&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;&amp;gt; hg incoming&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;comparing with ~/repos/hgproject&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;searching for changes&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;changeset: &amp;nbsp; 1:270e49e72f4b&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;tag: &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; tip&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;user: &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mike@mike-notebook&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;date: &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Fri Nov 27 10:39:35 2009 +0300&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;summary: &amp;nbsp; &amp;nbsp; Записан файл other.txt в другом репозитории&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Команда «hg incoming» выдает список ревизий, которые есть в
удаленном репозитории, но отсутствуют в локальном. А затем получим эти ревизии,
для чего скажем:&lt;br /&gt;
&lt;/div&gt;
&lt;div style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;
&lt;b&gt;&amp;gt; hg pull&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;pulling from ~/repos/hgproject&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;searching for changes&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;adding changesets&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;adding manifests&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;adding file changes&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;added 1 changesets with 1 changes to 1 files&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;(run &#39;hg update&#39; to get a working copy)&lt;/b&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Команда «hg pull» получает ревизии из удаленного
репозитория, и добавляет их в локальный, таким образом, изменения из нашего
«центрального» репозитория были перемещены в&amp;nbsp;
локальный репозиторий. Но они остались только в репозитории, локальная
копия осталась нетронутой. Для того, чтобы обновить локальную копию скажем:&lt;br /&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;&amp;gt; hg update&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;;&quot;&gt;&lt;b&gt;1 files updated, 0 files merged, 0 files removed, 0 files unresolved&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Если посмотреть на состояние рабочей копии, то она
соответствует состоянию рабочей копии в репозитории ~/projects/hgproj_clone, а
состояние хранилища во всех трех репозиториях одинаково.&lt;br /&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZ23cbjUftQCQ8tWN2yvUk0ShazjpXcQYeXihO83oz-VsK6tWgpqoAFvX64F5zVEHPdPR6Nd52kRo5IudLvBl7n3OIrMzCFvyzq97otpCP_FKnnbdJOECVfQqB-BNdnRBiIlh41MfGxfE2/s1600/%D0%A0%D0%B8%D1%81%D1%83%D0%BD%D0%BE%D0%BA+1.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZ23cbjUftQCQ8tWN2yvUk0ShazjpXcQYeXihO83oz-VsK6tWgpqoAFvX64F5zVEHPdPR6Nd52kRo5IudLvBl7n3OIrMzCFvyzq97otpCP_FKnnbdJOECVfQqB-BNdnRBiIlh41MfGxfE2/s400/%D0%A0%D0%B8%D1%81%D1%83%D0%BD%D0%BE%D0%BA+1.png&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Ну и напоследок просто необходимо сказать о ещё одной
команде. «hg help», как вы уже, наверное, догадались выводит некоторый набор
подсказок по работе с утилитами Mercurial. А при использовании в виде «hg help
[command]» выводит подсказку о приемах работы с указанной командой. Причем это
именно краткая подсказка, если вам требуется подробное описание, то лучше всего
обратиться к документации, которая имеется в абсолютно свободном доступе и
вполне неплохого качества.
&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Итак мы познакомились с основными приемами и
командами работы с распределенной системой контроля версий Mercurial. Главным
отличием, проявившихся на данном этапе, от централизованных систем контроля
версий является наличие полной копии всего репозитория у каждого пользователя,
что приводит к двухступенчатой системе взаимодействия с хранилищами
(commit-push/pull-update). Такая двухступенчатая система требует некоторого
привыкания, однако она вполне понятна и логична, и, на самом деле, достаточно проста
в использовании. На этом я заканчиваю этот раздел. В следующем разделе мы
рассмотрим наиболее интересные аспекты взаимодействия с Mercurial, а именно
ветвления (branching) и слияния (merging).
&lt;br /&gt;
&lt;/div&gt;
&lt;a rev=&quot;vote-for&quot; href=&quot;http://progg.ru/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5-%D0%B2-Mercurial-%D0%A7%D0%B0%D1%81%D1%82%D1%8C-2-%D0%9E%D1%81%D0%BD%D0%BE%D0%B2%D1%8B-%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%8B&quot;&gt;&lt;img alt=&quot;Progg it&quot; src=&quot;http://progg.ru/image.axd?url=http%3A%2F%2Fbrain-it.blogspot.com%2F2009%2F11%2Fmercurial-2.html&quot; style=&quot;border:0px&quot;/&gt;&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://brain-it.blogspot.com/feeds/8146362373848937536/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://brain-it.blogspot.com/2009/11/mercurial-2.html#comment-form' title='Комментарии: 6'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/8146362373848937536'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/8146362373848937536'/><link rel='alternate' type='text/html' href='http://brain-it.blogspot.com/2009/11/mercurial-2.html' title='Введение в Mercurial. Часть 2. Основы работы'/><author><name>Гиркин Михаил</name><uri>http://www.blogger.com/profile/16452424330632615848</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWpXfCa2Zw5azq46Ne6mkbObiOZ4ur6gLIcRhlGoNL8pSkGPXZXbn2Gm1MdXWx7I_krlaZTv51_OqUf5dURg-wznG-_jtqrvoHxb0-n0a49Ki-6RoxmN1TjfpisPVjmg/s220/ava.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZ23cbjUftQCQ8tWN2yvUk0ShazjpXcQYeXihO83oz-VsK6tWgpqoAFvX64F5zVEHPdPR6Nd52kRo5IudLvBl7n3OIrMzCFvyzq97otpCP_FKnnbdJOECVfQqB-BNdnRBiIlh41MfGxfE2/s72-c/%D0%A0%D0%B8%D1%81%D1%83%D0%BD%D0%BE%D0%BA+1.png" height="72" width="72"/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3474485280270816955.post-4898454950330617072</id><published>2009-11-24T11:14:00.000-08:00</published><updated>2009-11-24T11:22:06.141-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="django"/><category scheme="http://www.blogger.com/atom/ns#" term="python"/><category scheme="http://www.blogger.com/atom/ns#" term="программирование"/><title type='text'>Документация Django в chm и pdf формате</title><content type='html'>Нарыл сегодня документацию для django, да и не только, для того чтобы использовать на ноуте. У меня часто нет интернета на ноуте, и я далеко не все помню из документации, что вполне естественно. А Django-book не совсем нравится, там не все есть, в документации которую рекомендуют использовать на сайте чёрт ногу сломит - всё таки 21 век, а там txt файлы. Вот, малец погуглив, накопал &lt;a href=&quot;http://charupload.wordpress.com/2007/12/02/django-documentation-chm/&quot;&gt;тут&lt;/a&gt;.&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://brain-it.blogspot.com/feeds/4898454950330617072/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://brain-it.blogspot.com/2009/11/django-chm-pdf.html#comment-form' title='Комментарии: 3'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/4898454950330617072'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/4898454950330617072'/><link rel='alternate' type='text/html' href='http://brain-it.blogspot.com/2009/11/django-chm-pdf.html' title='Документация Django в chm и pdf формате'/><author><name>Гиркин Михаил</name><uri>http://www.blogger.com/profile/16452424330632615848</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWpXfCa2Zw5azq46Ne6mkbObiOZ4ur6gLIcRhlGoNL8pSkGPXZXbn2Gm1MdXWx7I_krlaZTv51_OqUf5dURg-wznG-_jtqrvoHxb0-n0a49Ki-6RoxmN1TjfpisPVjmg/s220/ava.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3474485280270816955.post-7170838218555015844</id><published>2009-11-21T03:44:00.000-08:00</published><updated>2010-01-19T09:32:45.295-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="dvcs"/><category scheme="http://www.blogger.com/atom/ns#" term="Mercurial"/><category scheme="http://www.blogger.com/atom/ns#" term="Subversion"/><category scheme="http://www.blogger.com/atom/ns#" term="программирование"/><title type='text'>Введение в Mercurial. Часть 1. Распределенные системы контроля версий (DVCS).</title><content type='html'>&lt;div style=&quot;text-align: justify;&quot;&gt;
Здравствуйте, уважаемые!&lt;br /&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Решил написать развернутый цикл статей про Мерк, так как судя по общению с товарищами - как то не очень народ его принимает. Вот буду делиться своим опытом и познаниями. Будет несколько статей, в одну все естественно не влезет. Сегодня просто про распределенные системы контроля версий. Что это и с чем едят.&lt;br /&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: justify;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKbnLkBGTBGfKGaHO8wMnbZSqp13F9AiC2KAVoayg2RaSQ3XlRqWyIfhxN34mFKKhyphenhyphenaAP6_WkOA0IrYpeMUFrUMMpujGWByu3yosg4c6y2TPPU79N8S03zbNrofnR25Sl2JmybL74DsicF/s1600/%D0%A0%D0%B8%D1%81%D1%83%D0%BD%D0%BE%D0%BA+1.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; ilo-full-src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKbnLkBGTBGfKGaHO8wMnbZSqp13F9AiC2KAVoayg2RaSQ3XlRqWyIfhxN34mFKKhyphenhyphenaAP6_WkOA0IrYpeMUFrUMMpujGWByu3yosg4c6y2TPPU79N8S03zbNrofnR25Sl2JmybL74DsicF/s320/%D0%A0%D0%B8%D1%81%D1%83%D0%BD%D0%BE%D0%BA+1.png&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKbnLkBGTBGfKGaHO8wMnbZSqp13F9AiC2KAVoayg2RaSQ3XlRqWyIfhxN34mFKKhyphenhyphenaAP6_WkOA0IrYpeMUFrUMMpujGWByu3yosg4c6y2TPPU79N8S03zbNrofnR25Sl2JmybL74DsicF/s320/%D0%A0%D0%B8%D1%81%D1%83%D0%BD%D0%BE%D0%BA+1.png&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Думаю что с классическими централизованными системами контроля версий (Subversion, CVS) знакомы уже почти все - есть выделенное специальное хранилище называемое репозиторий, в котором хранятся исходники некоторого проекта, и вся история изменений. И вот к этому хранилищу обращаются попеременно все работающие над проектом.&lt;br /&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
И вроде бы казалось все замечательно, но не так то все просто. Возникает целая куча проблем, как раз связанная с тем, что репозиторий один, и все в него пытаются закачивать свои исходники.&lt;br /&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
На мой взгляд главная проблема, к которой постепенно приходят все группы разработчиков - это проблема &quot;длинных коммитов&quot;, то есть, в больших командах возможно коммитить только большие части кода, которые покрыты тестами и могут уже использоваться. Тому много причин, но главное - страх поломать что-то готовое в репозитирии, что кем-то используется. Где хранить ваши проходные коммиты не совсем понятно. Есть конечно бранчи, но&amp;nbsp; в svn это довольно жестокая штука, по крайней мере судя по отзывам использующих людей. &lt;br /&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIhor62z0D3T3RLe24JbTRyIu306TiWX0ofNS9fZLakpimWjDCPx_443LcsvBSBm2_9oP5XNATUBO_2CO_RALQOwlmL5w0dj0ihc3BRmm1LiRMLctEeJp89VuGSgQTVpdXYUgQWzZcKs3G/s1600/%D0%A0%D0%B8%D1%81%D1%83%D0%BD%D0%BE%D0%BA+2.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; ilo-full-src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIhor62z0D3T3RLe24JbTRyIu306TiWX0ofNS9fZLakpimWjDCPx_443LcsvBSBm2_9oP5XNATUBO_2CO_RALQOwlmL5w0dj0ihc3BRmm1LiRMLctEeJp89VuGSgQTVpdXYUgQWzZcKs3G/s320/%D0%A0%D0%B8%D1%81%D1%83%D0%BD%D0%BE%D0%BA+2.png&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIhor62z0D3T3RLe24JbTRyIu306TiWX0ofNS9fZLakpimWjDCPx_443LcsvBSBm2_9oP5XNATUBO_2CO_RALQOwlmL5w0dj0ihc3BRmm1LiRMLctEeJp89VuGSgQTVpdXYUgQWzZcKs3G/s320/%D0%A0%D0%B8%D1%81%D1%83%D0%BD%D0%BE%D0%BA+2.png&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
И вот появилась немного более сложная концепция - распределенные системы. Давайте посмотрим на локальную копию svn&#39;a. при выполнении чекаута - у нас в каждом каталоге находится .svn - каталог, в котором хранится копия из репозитория. То есть, в снятом чекаутом наборе каталогов и файлов приходит и точная копия внешнего репозитория. Именно этот принцип и эксплуатируется нещадным образом в распределенных системах - у каждого пользователя есть свой локальный репозиторий, причем вовсе необязательно один. При этом то, что в практике svn назвается коммитом и апдейтом выполняется в свой локальный репозиторий.&lt;br /&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
За счет локальности коммитов достигается большая гранулярность - теперь можно коммитить не опасаясь поломать чужой код, да и весь проект, при этом вы всегда знаете, что история сохраняется, даже в том случае если вы не имеете доступа к основному репозиторию, например, в случае остуствия доступа в интернет.&lt;br /&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Понятие основного репозитория в случае распределенных систем контроля довольно условное. Он основной, потому что некто его так назвал. Ничто не мешает вам взять и забрать обновления лично у Васи Пупкина, а ему у вас, да и отправить свои обновления другому - тоже невелика проблема. Естественно если это позволяют настройки прав доступа. Таким образом получаем, что в распределенных системах отсутствует строгая иерархичность - все репозитории равны, и рядом с каждым репозиторием может быть размещена собственная рабочая копия, хотя и не обязательно.&lt;br /&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Смотря на такую структуру, возможность локальных коммитов, возможность синхронизации состояния репозитория с кем угодно создается ощущение, что исходники превратятся в кашу, и на определенном этапе, причем совсем недалеком от начала, уже невозможно будет как-то получить адекватное их состояние. На самом деле все не так страшно. Мощнейшей вещью распределенных систем контроля версий - является ветвление. При этом это не ветвление Subversion, это действительно настоящее, удобное и понятное ветвление и слияние. В DVCS, ну по крайней мере в Mercurial (хотя догадываюсь что и в Git и в Bazaar) ветвление это повседневная операция, это в принципе основа контроля версий в данном случае. И реализована она абсюлютно логично и понятно, и действительно проста в использовании.&lt;br /&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Для меня решающим фактором при принятии решения о переходе на Mercurial стали именно локальные коммиты (у меня не всегда есть доступ к интернету, а иногда возникает необходимость что-то закоммитить) и настолько мощная поддержка ветвления. Но уже после перехода я был немало удивлен скоростью работы с репозиториями, эквивалент checkout работает очень быстро даже на сверхбольших репозиториях, commit и update - это моментальные операции, действительно моментальные.&lt;br /&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Как работать со всем этим хозяйством я буду постепенно писать в следующих постах. Сегодня этакое начало. Следующий пост будет как раз про основы работы с Mercurial. Для тех кто знаком с Subversion не составит труда сделать первые несколько шагов в этом направлении.&lt;br /&gt;
&lt;br /&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: right;&quot;&gt;
&lt;a href=&quot;http://brain-it.blogspot.com/2009/11/mercurial-2.html&quot;&gt;Продолжение. Часть 2. Основы работы.&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;a rev=&quot;vote-for&quot; href=&quot;http://progg.ru/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5-%D0%B2-Mercurial-%D0%A7%D0%B0%D1%81%D1%82%D1%8C-1-%D0%A0%D0%B0%D1%81%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B5%D0%BD%D0%BD%D1%8B%D0%B5-%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D1%8B-%D0%BA%D0%BE%D0%BD%D1%82%D1%80%D0%BE%D0%BB%D1%8F-%D0%B2%D0%B5%D1%80%D1%81%D0%B8%D0%B9-DVCS&quot;&gt;&lt;img alt=&quot;Progg it&quot; src=&quot;http://progg.ru/image.axd?url=http%3A%2F%2Fbrain-it.blogspot.com%2F2009%2F11%2Fmercurial-1-dvcs.html&quot; style=&quot;border:0px&quot;/&gt;&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://brain-it.blogspot.com/feeds/7170838218555015844/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://brain-it.blogspot.com/2009/11/mercurial-1-dvcs.html#comment-form' title='Комментарии: 11'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/7170838218555015844'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/7170838218555015844'/><link rel='alternate' type='text/html' href='http://brain-it.blogspot.com/2009/11/mercurial-1-dvcs.html' title='Введение в Mercurial. Часть 1. Распределенные системы контроля версий (DVCS).'/><author><name>Гиркин Михаил</name><uri>http://www.blogger.com/profile/16452424330632615848</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWpXfCa2Zw5azq46Ne6mkbObiOZ4ur6gLIcRhlGoNL8pSkGPXZXbn2Gm1MdXWx7I_krlaZTv51_OqUf5dURg-wznG-_jtqrvoHxb0-n0a49Ki-6RoxmN1TjfpisPVjmg/s220/ava.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKbnLkBGTBGfKGaHO8wMnbZSqp13F9AiC2KAVoayg2RaSQ3XlRqWyIfhxN34mFKKhyphenhyphenaAP6_WkOA0IrYpeMUFrUMMpujGWByu3yosg4c6y2TPPU79N8S03zbNrofnR25Sl2JmybL74DsicF/s72-c/%D0%A0%D0%B8%D1%81%D1%83%D0%BD%D0%BE%D0%BA+1.png" height="72" width="72"/><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3474485280270816955.post-622244149486476634</id><published>2009-11-07T13:50:00.000-08:00</published><updated>2010-01-19T11:08:15.645-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Debian"/><category scheme="http://www.blogger.com/atom/ns#" term="Linux"/><category scheme="http://www.blogger.com/atom/ns#" term="Mercurial"/><category scheme="http://www.blogger.com/atom/ns#" term="администрирование"/><category scheme="http://www.blogger.com/atom/ns#" term="программирование"/><title type='text'>Установка и настройка системы контроля версий Mercurial на сервере</title><content type='html'>&lt;div style=&quot;text-align: justify;&quot;&gt;
Встала передо мной задача установить на сервере в инете Mercurial, для организации контроля версий в одном проекте. Причем установить его таким образом, чтобы можно было в ближайшем будущем создавать ещё репозитории с небольшими затратами времени. Также необходимо было обеспечить только авторизованный доступ, так, чтобы можно было ограничить доступ пользователей как на запись, так и на чтение, причем для разных репозиториев по разному.
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
После часа гугленья нашлось одно решение, которое отвечало всем требованиям - использовать Apache в связке с Mercurial, при помощи hgwebdir.cgi из стандартного комплекта Mercurial. Итак, предположим что на сервере стоит Apache2 и Mercurial. Если этого нет, то нетрудно воспользоваться apt-get (у меня на серваке Debian), или пакетным менеджером своей системы. Отмечу только, что для выполнения всех требований нужна версия Mercurial не меньше 1.2.1, так как только в этой версии была исправлена ошибка, которая не позволяла разделять права на чтение различных репозиториев стандартными средствами.
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Итак, основные задачи, которые предстоит решить:
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
1. Настроить Apache
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
2. Настроить hgwebdir.cgi
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
3. Создать и настроить репозиторий
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&amp;nbsp;Поехали с начала. Я разместил корневую папку репозитория в папке /home/mike/www-data/hg/. Чтобы не путаться я на сервере все собственные данные размещаю у себя в домашней папке. В конфиг соответствующего виртуалхоста добавляем описание:
&lt;/div&gt;&lt;pre class=&quot;code&quot;&gt;&lt;b&gt;Alias /hg &quot;/home/mike/www-data/hg&quot;
  &amp;lt;Directory &quot;/home/mike/www-data/hg/&quot;&amp;gt;
     Order allow,deny
     Allow from all
     AllowOverride All
     Options ExecCGI FollowSymLinks
     AddHandler cgi-script .cgi
  &amp;lt;/Directory &amp;gt;
&lt;/b&gt;&lt;/pre&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
В данном случае предполагается, что все репозитории будут доступны по ссылкам вида http://[домен]/hg/[репозиторий]. AllowOverride необходим для возможности использования .htaccess файла, далее он потребуется. Создаем в каталоге /home/mike/www-data/hg/ файл .htaccess примерно такого содержания:
&lt;/div&gt;&lt;pre class=&quot;code&quot;&gt;&lt;b&gt;RewriteEngine On
RewriteBase /hg
RewriteRule ^$ hgwebdir.cgi  [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) hgwebdir.cgi/$1  [QSA,L]

AuthUserFile /home/mike/www-data/hg/htpasswd_hgstore
AuthGroupFile /dev/null
AuthName &quot;HgRepo&quot;
AuthType Basic
Require valid-user
&lt;/b&gt;&lt;/pre&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Аутентификацию организуем срествами HTTP, логины и пароли будут храниться в файле /home/mike/www-data/hg/htpasswd_hgstore, как и написано в .htaccess. А в первой части указаны директивы для mod_rewrite (который естественно нужно подключить), которые позволяют получить красивые урлы вида http://[домен]/hg/[репозиторий], без указания hgwebdir.cgi. Правда описанный выше способ имеет свои недостатки - поле [репозиторий] в url не может совпадать с именем каталога на диске.
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Идем дальше. В папку /home/mike/www-data/hg/ копируем файлик hgwebdir.cgi (в Debian он находится в /usr/share/doc/mercurial/examples/), и разрешаем ему выполняться:
&lt;/div&gt;&lt;pre class=&quot;code&quot;&gt;&lt;b&gt;chmod +x hgwebdir.cgi&lt;/b&gt;&lt;/pre&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Создаем в этом же каталоге файл hgweb.config, в котором прописываем следующее:
&lt;/div&gt;&lt;pre class=&quot;code&quot;&gt;&lt;b&gt;[paths]
test = repo_test

[web]
baseurl = /hg
&lt;/b&gt;&lt;/pre&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Главное здесь - секция [paths]. В ней прописываются соответствия урлов и репозиториев на диске в виде URL = /path/to/repo, где /path/to/repo считается от текущего по отношению к hgweb.config каталога, а URL - от алиаса /hg/.
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Нам потребуется ещё один файлик, а именно hgrc, который тоже создаем в каталоге с hgwebdir.cgi, и в этот самый hgrc вписываем:
&lt;/div&gt;&lt;pre class=&quot;code&quot;&gt;&lt;b&gt;[web]
#allow_push = *
#allow_read = *
push_ssl = false
contact = Mike Girkin
description = Get our elephants
allow_archive = bz2 gz zip
style = gitweb
&lt;/b&gt;&lt;/pre&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Это заготовка для hgrc в каждом из репозиториев. Осталось дело за малым - создаем репозиторий, и копируем заготовку hgrc по месту:
&lt;/div&gt;&lt;pre class=&quot;code&quot;&gt;&lt;b&gt;mkdir repo_test
cd repo_test
hg init
cp ../hgrc repo_test/.hg/
&lt;/b&gt;&lt;/pre&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Осталось только создать файлик с паролями htpasswd_hgstore с помощью утилиты htpasswd, и вбить в него нужное количество пользователей и паролей. Ограничить доступ на чтение/запись можно с помощью директив allow_read/allow_push в файлах hgrc лежащих в каждом из репозиториев, например:
&lt;/div&gt;&lt;pre class=&quot;code&quot;&gt;&lt;b&gt;allow_read = pupkin petrov sidorov
allow_push = petrov
&lt;/b&gt;&lt;/pre&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Обращаю внимание, что в директивах allow_read/allow_push используются те логины, которые забиваются в htpasswd_hgstore, и используются для аутентификации клиентов. Для того, чтобы открыть доступ всем аутентифицировавшимся пользователям пишем allow_read = * или allow_push = *, соответственно.
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
И последнее, что нельзя забыть сделать, это поменять владельца для всей ~/www-data/hg/ (у меня Apache выполняется от имени www-data:www-data): 
&lt;/div&gt;&lt;pre class=&quot;code&quot;&gt;&lt;b&gt;chown -R www-data:www-data ~/www-data/hg
&lt;/b&gt;&lt;/pre&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
На этом, для первого репозитория все настроено, и он должен быть доступен (в данном случае по ссылке http://[домен]/hg/test/, при этом он доступен как для утилиты hg и клиентов по этому url, так и через браузер, хотя необходимость последнего очень спорна.
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Чтобы добавить новый репоиторий необходимо выполнить следующее:
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
1. Создать каталог (mkdir repo_new)
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
2. Прописать в hgweb.config в секцию [paths] соответсвие путей (new = repo_new)
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
3. Скопировать hgrc в repo_new/.hg/
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
4. Прописать во внутренний hgrc пользователей, которым разрешены операции над репозиторием
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
5. Изменить владельца на www-data (chown -R www-data:www-data repo_new)
&lt;/div&gt;
На этом все. Спасибо за внимание ;)
&lt;br/&gt;
&lt;a rev=&quot;vote-for&quot; href=&quot;http://progg.ru/%D0%A3%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0-%D0%B8-%D0%BD%D0%B0%D1%81%D1%82%D1%80%D0%BE%D0%B9%D0%BA%D0%B0-%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D1%8B-%D0%BA%D0%BE%D0%BD%D1%82%D1%80%D0%BE%D0%BB%D1%8F-%D0%B2%D0%B5%D1%80%D1%81%D0%B8%D0%B9-Mercurial-%D0%BD%D0%B0-%D1%81%D0%B5%D1%80%D0%B2%D0%B5%D1%80%D0%B5&quot;&gt;&lt;img alt=&quot;Progg it&quot; src=&quot;http://progg.ru/image.axd?url=http%3A%2F%2Fbrain-it.blogspot.com%2F2009%2F11%2Fmercurial.html&quot; style=&quot;border:0px&quot;/&gt;&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://brain-it.blogspot.com/feeds/622244149486476634/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://brain-it.blogspot.com/2009/11/mercurial.html#comment-form' title='Комментарии: 10'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/622244149486476634'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/622244149486476634'/><link rel='alternate' type='text/html' href='http://brain-it.blogspot.com/2009/11/mercurial.html' title='Установка и настройка системы контроля версий Mercurial на сервере'/><author><name>Гиркин Михаил</name><uri>http://www.blogger.com/profile/16452424330632615848</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWpXfCa2Zw5azq46Ne6mkbObiOZ4ur6gLIcRhlGoNL8pSkGPXZXbn2Gm1MdXWx7I_krlaZTv51_OqUf5dURg-wznG-_jtqrvoHxb0-n0a49Ki-6RoxmN1TjfpisPVjmg/s220/ava.jpg'/></author><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3474485280270816955.post-6268320006592697863</id><published>2009-11-07T07:33:00.000-08:00</published><updated>2009-11-07T07:34:43.865-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Debian"/><category scheme="http://www.blogger.com/atom/ns#" term="Linux"/><category scheme="http://www.blogger.com/atom/ns#" term="администрирование"/><title type='text'>Используем Backports в Debian Lenny</title><content type='html'>&lt;div style=&quot;text-align: justify;&quot;&gt;Backports - это проект по адаптации свежих версий софта для стабильных дистрибутивов Debian. Необходимость в таком переносе объясняется тем, что Debian отличается достаточно длительным релиз-циклом, и софт стабильной ветки сильно устаревает до момента релиза нового дистрибутива.&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;Давиче мне вот понадобился Mercurial с версией 1.2.1 или позднее, а в репозиториях Lenny только 1.0. Вот и решил написать небольшой пост про подключение и использование проекта backports к Debian Lenny.&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
1. Добавляем в /etc/apt/sources.list ссылку на репозиторий Backports:&lt;br /&gt;
&lt;pre class=&quot;code&quot;&gt;&lt;b&gt;deb http://www.backports.org/debian lenny-backports main contrib non-free&lt;/b&gt;&lt;/pre&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;2. Обновляем информацию о пакетах:&lt;br /&gt;
&lt;/div&gt;&lt;pre class=&quot;code&quot;&gt;&lt;b&gt;apt-get update&lt;/b&gt;
&lt;/pre&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;3. Поскольку все пакеты из этого репозитория имеют минимальный приоритет, то для того, чтобы поставить пакет из backports, например тот же mercurial, нужно воспользоваться командой:&lt;br /&gt;
&lt;/div&gt;&lt;pre class=&quot;code&quot;&gt;&lt;b&gt;apt-get -t lenny-backports install mercurial&lt;/b&gt;&lt;/pre&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;4. При попытке поставить любой пакет, будет выдаваться угрожающее предупреждение о том, что пакет из неизвестного источника. Избавиться от него легко, поставив пакет с соответствующими ключами (есть альтернативные способы, но я про них говорить не буду):&lt;br /&gt;
&lt;/div&gt;&lt;pre class=&quot;code&quot;&gt;&lt;b&gt;apt-get install debian-backports-keyring&lt;/b&gt;
&lt;/pre&gt;Всё. Можем ставить требуемые компоненты с версией значительно более близкой к актуальной.</content><link rel='replies' type='application/atom+xml' href='http://brain-it.blogspot.com/feeds/6268320006592697863/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://brain-it.blogspot.com/2009/11/backports-debian-lenny.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/6268320006592697863'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/6268320006592697863'/><link rel='alternate' type='text/html' href='http://brain-it.blogspot.com/2009/11/backports-debian-lenny.html' title='Используем Backports в Debian Lenny'/><author><name>Гиркин Михаил</name><uri>http://www.blogger.com/profile/16452424330632615848</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWpXfCa2Zw5azq46Ne6mkbObiOZ4ur6gLIcRhlGoNL8pSkGPXZXbn2Gm1MdXWx7I_krlaZTv51_OqUf5dURg-wznG-_jtqrvoHxb0-n0a49Ki-6RoxmN1TjfpisPVjmg/s220/ava.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3474485280270816955.post-1335278127793086725</id><published>2009-10-17T06:27:00.000-07:00</published><updated>2009-10-17T06:35:39.129-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".net"/><category scheme="http://www.blogger.com/atom/ns#" term="C#"/><category scheme="http://www.blogger.com/atom/ns#" term="программирование"/><title type='text'>Отличие между оператором &quot;as&quot; и операцией приведения типа</title><content type='html'>&lt;div style=&quot;text-align: justify;&quot;&gt;Это перевод оригинальной статьи находящейся &lt;a href=&quot;http://blogs.msdn.com/ericlippert/archive/2009/10/08/what-s-the-difference-between-as-and-cast-operators.aspx&quot;&gt;здесь&lt;/a&gt;. Все права на оригинал принадлежат автору.&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;Большинство разработчиков скажут вам, что разница между «(Alpha) bravo» и «bravo as Alpha» состоит в том, что при ошибке приведения типа в первом случае будет выброшено исключение, тогда как во втором случае будет возвращен null.  Хотя это действительно так, и это наиболее очевидное отличие, оно не единственно. Есть несколько подводных камней, которых нужно остерегаться.&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;В-первых, поскольку результатом оператора «as» может быть «null», тип результата должен быть таким, чтобы он в принципе мог принимать значение «null», то есть быть либо ссылочным типом, либо «nullable». Невозможно выполнить «as int» – это бессмысленно. Если аргумент окажется переменной не приводимой к типу «int», то каким же тогда должно быть возвращаемое значение? Так как результат операции «as» может принимать значение «null», то переменная, которой он присваивается, должна быть именованного типа.&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;Во-вторых, оператор приведения типа cast, это довольно странный зверь. Это связано с двумя противоречащими друг другу действиями: «проверь, действительно ли этот объект заданного типа и выбрось исключение, если нет» и «этот объект не того типа, что указан – найди мне эквивалентное значение указанного типа». Последнее означает, что оператор «cast» не выполняется оператором «as». Если вы напишете:&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;short s = (short)123;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;int? i = s as int?.&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;вам не светит удача. Оператор «as» не выполнит преобразование, изменяющее представление, из «short» в «nullable int», как бы это сделал оператор приведения типа. Похожим образом, если у вас есть класс Alpha и не связанный с ним класс Bravo, с определённым пользователем преобразованием из Bravo в Alpha, операция «(Alpha) bravo» вызовет заданное пользователем преобразование, а «bravo as Alpha» – нет. Оператор «as» подразумевает только преобразования ссылок – упаковку (boxing) и распаковку (unboxing).&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;И последнее. Несомненно, случаи применения эти двух операторов внешне похожи, но по смыслу (семантически) очень различаются. Оператор приведения типа сообщает читателю: «Я уверен, что это преобразование корректно, и готов обработать исключение, если это не так». Оператор «as» говорит иное: «Я не знаю, корректно ли это преобразование или нет – давайте попробуем и посмотрим, что из этого выйдет».&lt;br /&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brain-it.blogspot.com/feeds/1335278127793086725/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://brain-it.blogspot.com/2009/10/as.html#comment-form' title='Комментарии: 4'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/1335278127793086725'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/1335278127793086725'/><link rel='alternate' type='text/html' href='http://brain-it.blogspot.com/2009/10/as.html' title='Отличие между оператором &quot;as&quot; и операцией приведения типа'/><author><name>Гиркин Михаил</name><uri>http://www.blogger.com/profile/16452424330632615848</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWpXfCa2Zw5azq46Ne6mkbObiOZ4ur6gLIcRhlGoNL8pSkGPXZXbn2Gm1MdXWx7I_krlaZTv51_OqUf5dURg-wznG-_jtqrvoHxb0-n0a49Ki-6RoxmN1TjfpisPVjmg/s220/ava.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3474485280270816955.post-3214082128913076755</id><published>2009-08-26T12:16:00.000-07:00</published><updated>2009-08-28T12:19:27.149-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".net"/><category scheme="http://www.blogger.com/atom/ns#" term="C#"/><category scheme="http://www.blogger.com/atom/ns#" term="программирование"/><title type='text'>Windows.Forms: ложимся в трей</title><content type='html'>Не так давно встала передо мной задача - уложить программу на C# в трей. При разработке использовались стандартный Windows.Forms из .net 3.5, хотя со времен .net 2.0 он практически не изменился. На моё счастье все оказалось очень просто. Попытаюсь объяснить основные шаги.&lt;br /&gt;1. Размещаем компонент NotifyIcon на форме. У меня в приложении одна форма главная, остальные даже в таскбаре не отображаются, на главную форму и положил. NotifyIcon находится в ToolBox, вместе со всеми контролами... Параметры этого NotifyIcon говорят сами за себя, правда если не задать иконку, то в трее вообще ничего не появится :)&lt;br /&gt;2. Маленько изменяем поведение формы. Для программ размещающихся в трее принято при сворачивании убирать окно из таскбара, а при щелчке на иконке в таскбаре - разворачивать. Поэтому пишем следующие обработчики:&lt;br /&gt;- для сворачивания формы (эвент Form.Resize)&lt;br /&gt;&lt;blockquote&gt;&lt;code&gt;&lt;font size=&quot;2&quot; face=&quot;Courier New&quot; color=&quot;black&quot;&gt;&lt;ol&gt;&lt;li&gt;&lt;font color=&quot;#0000ff&quot;&gt;private&lt;/font&gt; &lt;font color=&quot;#0000ff&quot;&gt;void&lt;/font&gt; MainForm_Resize(&lt;font color=&quot;#0000ff&quot;&gt;object&lt;/font&gt; sender, &lt;font color=&quot;#2B91AF&quot;&gt;EventArgs&lt;/font&gt; e)&lt;/li&gt;&lt;li&gt;{&lt;/li&gt;&lt;li&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=&quot;#0000ff&quot;&gt;if&lt;/font&gt; (FormWindowState.Minimized == WindowState) Hide();&lt;/li&gt;&lt;li&gt;}&lt;/li&gt;&lt;/font&gt;&lt;/ol&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;/blockquote&gt;- и для клика по иконке в трее (эвент NotifyIcon.Click)&lt;br /&gt;&lt;blockquote&gt;&lt;code&gt;&lt;font size=&quot;2&quot; face=&quot;Courier New&quot; color=&quot;black&quot;&gt;&lt;ol&gt;&lt;li&gt;&lt;font color=&quot;#0000ff&quot;&gt;private&lt;/font&gt; &lt;font color=&quot;#0000ff&quot;&gt;void&lt;/font&gt; notifyIcon_Click(&lt;font color=&quot;#0000ff&quot;&gt;object&lt;/font&gt; sender, &lt;font color=&quot;#2B91AF&quot;&gt;EventArgs&lt;/font&gt; e)&lt;/li&gt;&lt;li&gt;{&lt;/li&gt;&lt;li&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Show();&lt;/li&gt;&lt;li&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;WindowState = FormWindowState.Normal;&lt;/li&gt;&lt;li&gt;}&lt;/li&gt;&lt;/font&gt;&lt;/ol&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;/blockquote&gt;3. Изменим поведение при попытке юзера закрыть окно по крестику. Для этого используем обработчик эвента Form.Closing:&lt;br /&gt;&lt;blockquote&gt;&lt;code&gt;&lt;font size=&quot;2&quot; face=&quot;Courier New&quot; color=&quot;black&quot;&gt;&lt;ol&gt;&lt;li&gt;&lt;font color=&quot;#0000ff&quot;&gt;private&lt;/font&gt; &lt;font color=&quot;#0000ff&quot;&gt;void&lt;/font&gt; MainForm_FormClosing(&lt;font color=&quot;#0000ff&quot;&gt;object&lt;/font&gt; sender, FormClosingEventArgs e)&lt;/li&gt;&lt;li&gt;{&lt;/li&gt;&lt;li&gt;&amp;nbsp;&lt;font color=&quot;#0000ff&quot;&gt;if&lt;/font&gt; (e.CloseReason == CloseReason.UserClosing)&lt;/li&gt;&lt;li&gt;&amp;nbsp;{&lt;/li&gt;&lt;li&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;e.Cancel = &lt;font color=&quot;#0000ff&quot;&gt;true&lt;/font&gt;;&lt;/li&gt;&lt;li&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Hide();&lt;/li&gt;&lt;li&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;WindowState = FormWindowState.Minimized;&lt;/li&gt;&lt;li&gt;&amp;nbsp;}&lt;/li&gt;&lt;li&gt;}&lt;/li&gt;&lt;/font&gt;&lt;/ol&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;/blockquote&gt;То есть, при щелчке по крестику наша форма просто свернется вниз, а завершение программы будет отменено. Правда на текущий момент эту программу можно только прибить из менеджера задач, что не очень хорошо. Поэтому:&lt;br /&gt;4. Сделаем контекстное меню для иконки в трее. Компонент ContextMenuStrip размещаем на нашей форме, создаем в нем пункт &quot;Выход&quot; (и какие ещё необходимо). Затем скажем нашему NotifyIcon, что у него есть контекстное меню с помощью свойства NotifyIcon.ContextMenuStrip. А обработчик пункта &quot;Выход&quot; у нас будет таким:&lt;br /&gt;&lt;blockquote&gt;&lt;code&gt;&lt;font size=&quot;2&quot; face=&quot;Courier New&quot; color=&quot;black&quot;&gt;&lt;ol&gt;&lt;li&gt;&lt;font color=&quot;#0000ff&quot;&gt;private&lt;/font&gt; &lt;font color=&quot;#0000ff&quot;&gt;void&lt;/font&gt; miClose_Click(&lt;font color=&quot;#0000ff&quot;&gt;object&lt;/font&gt; sender, &lt;font color=&quot;#2B91AF&quot;&gt;EventArgs&lt;/font&gt; e)&lt;/li&gt;&lt;li&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;/li&gt;&lt;li&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Application.Exit();&lt;/li&gt;&lt;li&gt;}&lt;/li&gt;&lt;/font&gt;&lt;/ol&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;/blockquote&gt;То есть CloseReason в данном случае будет ApplicationExitCall.&lt;br /&gt;Вот и всё. Приложение должно вполне успешно справляться со своей задачей &quot;лежания&quot; в трее.</content><link rel='replies' type='application/atom+xml' href='http://brain-it.blogspot.com/feeds/3214082128913076755/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://brain-it.blogspot.com/2009/08/windowsforms.html#comment-form' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/3214082128913076755'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/3214082128913076755'/><link rel='alternate' type='text/html' href='http://brain-it.blogspot.com/2009/08/windowsforms.html' title='Windows.Forms: ложимся в трей'/><author><name>Гиркин Михаил</name><uri>http://www.blogger.com/profile/16452424330632615848</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWpXfCa2Zw5azq46Ne6mkbObiOZ4ur6gLIcRhlGoNL8pSkGPXZXbn2Gm1MdXWx7I_krlaZTv51_OqUf5dURg-wznG-_jtqrvoHxb0-n0a49Ki-6RoxmN1TjfpisPVjmg/s220/ava.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3474485280270816955.post-4772093318317739763</id><published>2009-08-21T23:23:00.001-07:00</published><updated>2009-08-22T04:51:52.808-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".net"/><category scheme="http://www.blogger.com/atom/ns#" term="C#"/><category scheme="http://www.blogger.com/atom/ns#" term="программирование"/><title type='text'>Генераторы в C# или &quot;бесполезное&quot; yield</title><content type='html'>Язык о котором пойдёт речь вышел достаточно давно, однако, судя по реальному опыту общения, мало кто пользуется всеми имеющимися возможностями. Этот пост я посвящу ключевому слову yield в языке C# 2.0.&lt;br /&gt;Сначала несколько слов о тенденциях развития С#. Вспоминая каким был C# 1.0, могу сказать, что это была калька с Java2SE, причем не сказать что удачная. Чистый ООП язык, практически слизаный с Java, без какой-либо собственной красоты и лоска, без своего шарма. Однако уже вторая версия очень сильно порадовала своими возможностями, а именно некоторым движением в сторону функционального программирования. Эта же тенденция существенно продолжается и в третьей версии (VS2008), в C# 4.0 (VS2010) функциональные возможности будут расширены ещё больше, при этом Microsoft добавляет в платформу .NET полноценный функциональный язык, который много лет разрабатывался Microsoft Research. По-моему говорит это о многом.&lt;br /&gt;А теперь к делу!&lt;br /&gt;Ключевое слово yield изначально было предназначено для облегчения разработки классических итераторов .NET, а именно классов, реализующих интерфейсы IEnumerator&amp;lt;T&amp;gt; и IEnumerable&amp;lt;T&amp;gt;. То есть, разработка своей коллекции, или способа обращения к существующей коллекции требовала разработки как минимум одного класса - итератора с интерфейсом IEnumerator&amp;lt;T&amp;gt;, по одному классу на каждый способ прохода коллекции. Довольно муторное и однообразное занятие.&lt;br /&gt;И тут к нам на помощь приходит yield!&lt;br /&gt;Небольшой пример. Пусть нам хочется получить все элементы списка находящиеся в диапазоне [3;5]. Вместо стандартного for напишем следующий кусок:&lt;br /&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;&lt;br /&gt; IEnumerator&amp;lt;int&amp;gt; GetIntervalled(List&amp;lt;int&amp;gt; Collection)&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span style=&quot;font-family:courier new;&quot;&gt;for(int i=0;i&amp;lt;Collection.Count;i++)&lt;br /&gt;  &lt;/span&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;    if(Collection[i]&amp;gt;=3 &amp;amp;&amp;amp; Collection[i]&amp;lt;=5) yield return Collection[i];&lt;br /&gt;  &lt;/span&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Использовать только что написанный код можно как и обычно используются итераторы – foreach. При очередном выполнении yield return функция вернет управление вызывающей, и передаст соответствующий элемент. На самом деле компилятор по этому коду создаст виртуальный класс реализующий интерфейс IEnumeratot&amp;lt;t&amp;gt;, но нас это не должно интересовать. Подобная конструкция есть первый, маленький шажок в сторону функционального программирования – это один из вариантов продолжения (continuations), потому что визуально код, при повторном вызове, продолжает выполняться с того места где выполнение было окончено. Подобная конструкция в некоторых языках программирования (откуда она и была заимствована) называется генератором, отсюда и название заголовка :)&lt;br /&gt;Конечно, приведенный выше пример абсолютно неинтересен, и ничем не отличается по смыслу от примера, приводимого в документации. Понять, зачем применять столь хитрую конструкцию крайне тяжело. Для того, чтобы стало немножко больше понятно зачем нужны такие вещи приведу пример из реального кода.&lt;br /&gt;В формочку (Windows.Forms) выводятся некоторые сущности, а пользователь отмечает галочками те, которые ему необходимы. Мне хотелось получить отмеченные галочкой сущности, yield пригодился как нельзя кстати:&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;  public IEnumerable&amp;lt;DatabaseImportCase&amp;gt; SelectedImportCases&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;{&lt;/span&gt;&lt;br /&gt;   &lt;span style=&quot;font-family:courier new;&quot;&gt;get&lt;/span&gt;&lt;br /&gt;  &lt;span style=&quot;font-family:courier new;&quot;&gt;{&lt;/span&gt;&lt;br /&gt;     &lt;span style=&quot;font-family:courier new;&quot;&gt; for (int i = 0; i &amp;lt; lbImportPackages.CheckedIndices.Count; i++)&lt;br /&gt;  &lt;/span&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;    yield return ShownImportCases[i];&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;  }&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt; }&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;ShownImportCases – это список отображаемых сущностей, lbImportPackages – листбокс с галочками (CheckedListBox), в котором отображаются эти сущности. Естественно предполагается, что индексы отображаемых на форме и хранимых в памяти сущностей совпадают. Операции по получению элементов происходят с помощью «ленивых вычислений», то есть получение очередного элемента произойдет только тогда, когда вы его потребуете. Никаких виртуальных списков в памяти не строится. Итак, yield – это универсальный, очень удобный способ получения новых, произвольных по сложности итераторов. Основное его преимущество – уменьшение количества не имеющего смысловой нагрузки кода. То есть, использование этого приема, это просто syntax sugar, но вряд ли кто откажется от сладкого :) Безусловно появление LINQ, а именно LINQ to Objects существенно снизило ценность yield, поскольку практически все итераторы можно получить с помощью запросов LINQ, однако понимание работы такого рода продолжений крайне необходимо для понимания более сложных конструкций функционального программирования. Которые я постараюсь рассмотреть в одном из следующих постов.</content><link rel='replies' type='application/atom+xml' href='http://brain-it.blogspot.com/feeds/4772093318317739763/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://brain-it.blogspot.com/2009/08/c-yield.html#comment-form' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/4772093318317739763'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/4772093318317739763'/><link rel='alternate' type='text/html' href='http://brain-it.blogspot.com/2009/08/c-yield.html' title='Генераторы в C# или &quot;бесполезное&quot; yield'/><author><name>Гиркин Михаил</name><uri>http://www.blogger.com/profile/16452424330632615848</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWpXfCa2Zw5azq46Ne6mkbObiOZ4ur6gLIcRhlGoNL8pSkGPXZXbn2Gm1MdXWx7I_krlaZTv51_OqUf5dURg-wznG-_jtqrvoHxb0-n0a49Ki-6RoxmN1TjfpisPVjmg/s220/ava.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3474485280270816955.post-3259098042697259671</id><published>2009-08-17T12:26:00.001-07:00</published><updated>2009-08-22T00:37:03.568-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Linux"/><category scheme="http://www.blogger.com/atom/ns#" term="администрирование"/><title type='text'>Восстанавливаем Grub после установки Windows</title><content type='html'>На днях решил попробовать установить Windows 7, и, вполне естественно столкнулся с проблемой. Сама Windows 7 встала без проблем, установка существенно проще чем в ХР (Vista не видел - ничего сказать не могу). Но, вполне в традициях Microsoft, семёрка не замечает никаких операционных систем на компьютере кроме Windows. Естественно мне хотелось сохранить всё, что у меня есть, а именно Windows XP и KUbuntu 9.04, ну и естественно настроить мультизагрузку.&lt;br /&gt;Как и ожидалось после установки семерки Grub был затёрт напрочь, хотя выбор между XP и Windows 7 все же был. Ситуация осложняется ещё и тем, что у меня 2 жестких диска, и я абсолютно не помню как там у меня что загружается. Стандартное решение выдаваемое гуглом в поиске, а именно &quot;grub-install&quot; не прокатывает. По неизвестным мне причинам ни в одном блоге, который приводит grub-install как решение не написано что нужно передавать параметр - диск, на который ставить grub. Погуглив ещё малец, я нашел решение, которое сам когда-то использовал, но успешно забыл :)&lt;br /&gt;Итак:&lt;br /&gt;1. Загружаемся с Live CD&lt;br /&gt;2. Монтируем раздел с линуксом на винте, примерно так:&lt;div style=&quot;margin-left: 40px; font-family: Courier,monospace;&quot;&gt;cd /mnt&lt;br /&gt;sudo mkdir linux&lt;br /&gt;sudo mount /dev/sda1 /mnt/linux&lt;br /&gt;sudo mount --bind /mnt/linux/boot /boot&lt;/div&gt;3. Заходим в консоль команд Grub:&lt;div style=&quot;margin-left: 40px; font-family: Courier,monospace;&quot;&gt;sudo grub&lt;/div&gt;&lt;u&gt;Дальше команды выполняются в консоли grub&lt;/u&gt;&lt;br /&gt;4. Ищем где у нас стоит Stage1:&lt;div style=&quot;margin-left: 40px; font-family: Courier,monospace;&quot;&gt;find /boot/grub/stage1&lt;/div&gt;Вернется что-то типа (hdx, y), вот эти магические x,y и используем:&lt;br /&gt;5. Говорим Grub&#39;у где у него Stage1, и куда ему поставится:&lt;div style=&quot;margin-left: 40px; font-family: Courier,monospace;&quot;&gt;root (hdx,y)&lt;br /&gt;setup (hdx)&lt;/div&gt;&lt;br /&gt;Итак grub мы восстановили. Осталось только добавить Windows 7 в список загрузки. Идем в /boot/grub/menu.lst, и смотря на описание загрузки Windows XP сооружаем примерно то же самое, сделав поправку &quot;на ветер&quot;. У меня получилось вот такое:&lt;div style=&quot;margin-left: 40px; font-family: Courier,monospace;&quot;&gt;title Windows 7 RC&lt;br /&gt;root (hd1,5)&lt;br /&gt;chainloader +1&lt;br /&gt;makeactive&lt;/div&gt;&lt;br /&gt;Всё. Пользуемся 3 ОС одновременно. Но лично я собираюсь перебираться из XP в семерку :)</content><link rel='replies' type='application/atom+xml' href='http://brain-it.blogspot.com/feeds/3259098042697259671/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://brain-it.blogspot.com/2009/08/grub-windows.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/3259098042697259671'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/3259098042697259671'/><link rel='alternate' type='text/html' href='http://brain-it.blogspot.com/2009/08/grub-windows.html' title='Восстанавливаем Grub после установки Windows'/><author><name>Гиркин Михаил</name><uri>http://www.blogger.com/profile/16452424330632615848</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWpXfCa2Zw5azq46Ne6mkbObiOZ4ur6gLIcRhlGoNL8pSkGPXZXbn2Gm1MdXWx7I_krlaZTv51_OqUf5dURg-wznG-_jtqrvoHxb0-n0a49Ki-6RoxmN1TjfpisPVjmg/s220/ava.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3474485280270816955.post-407041178926562623</id><published>2009-05-01T04:02:00.000-07:00</published><updated>2009-08-22T00:37:41.895-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Интернет"/><title type='text'>Новая фишечка от Google в поиске</title><content type='html'>Надо было сегодня кое-что погуглить, и обратил внимание на некоторе обновление страницы поиска в гугле. Фактически добавили комментарии к результатам поиска, и возможность перемещать/удалять результаты поиска для повторного использования. Интересно будет посмотреть насколько это будет удобно в реальности, и как быстро подобная вещь появится у яндекса :)&lt;br /&gt;И очень интересно когда же это было добавлено. Учитывая мою клиническую невнимательность к мелочам - вполне возможно пару месяцев назад :)&lt;br /&gt;&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/AVvXsEiLxl3yND3zGX2x4Uc_RO7MJlEcjWvcZM_9GZhV2gOv6NBUOJP1AsSEI7u5876oaP3BzIat1RaXAp6s6KEO5IxgRaD7drlfxo37_91CMMgn4zQLSDTf5MWwxC154pGsUw-uoHCnI2opmxJv/s800/Shot.png&quot;&gt;&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLxl3yND3zGX2x4Uc_RO7MJlEcjWvcZM_9GZhV2gOv6NBUOJP1AsSEI7u5876oaP3BzIat1RaXAp6s6KEO5IxgRaD7drlfxo37_91CMMgn4zQLSDTf5MWwxC154pGsUw-uoHCnI2opmxJv/s800/Shot.png&quot; style=&quot;cursor: pointer; width: 636px; height: 433px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLxl3yND3zGX2x4Uc_RO7MJlEcjWvcZM_9GZhV2gOv6NBUOJP1AsSEI7u5876oaP3BzIat1RaXAp6s6KEO5IxgRaD7drlfxo37_91CMMgn4zQLSDTf5MWwxC154pGsUw-uoHCnI2opmxJv/s800/Shot.png&quot; alt=&quot;&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://brain-it.blogspot.com/feeds/407041178926562623/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://brain-it.blogspot.com/2009/05/google.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/407041178926562623'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/407041178926562623'/><link rel='alternate' type='text/html' href='http://brain-it.blogspot.com/2009/05/google.html' title='Новая фишечка от Google в поиске'/><author><name>Гиркин Михаил</name><uri>http://www.blogger.com/profile/16452424330632615848</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWpXfCa2Zw5azq46Ne6mkbObiOZ4ur6gLIcRhlGoNL8pSkGPXZXbn2Gm1MdXWx7I_krlaZTv51_OqUf5dURg-wznG-_jtqrvoHxb0-n0a49Ki-6RoxmN1TjfpisPVjmg/s220/ava.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLxl3yND3zGX2x4Uc_RO7MJlEcjWvcZM_9GZhV2gOv6NBUOJP1AsSEI7u5876oaP3BzIat1RaXAp6s6KEO5IxgRaD7drlfxo37_91CMMgn4zQLSDTf5MWwxC154pGsUw-uoHCnI2opmxJv/s72-c/Shot.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3474485280270816955.post-3897280720334060750</id><published>2009-04-08T10:25:00.000-07:00</published><updated>2009-08-22T00:38:03.448-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="django"/><category scheme="http://www.blogger.com/atom/ns#" term="python"/><category scheme="http://www.blogger.com/atom/ns#" term="программирование"/><title type='text'>Наследование шаблонов в Django</title><content type='html'>&lt;div style=&quot;text-align: justify;&quot;&gt;В питоновском веб-фреймворке django встроен механизм наследования шаблонов страниц. Лично я считаю, что это очень спорная фишка и должна применяться с большой аккуратностью. Сейчас попробую объяснить почему.&lt;br /&gt;Сначала определимся с терминологией. Этот механизм является именно наследованием, тем самым, которое используется в ООП. Этот вывод я сделал проанализировав получающиеся конструкции. Ведь фактически шаблон-наследник знает о структуре шаблона предка, хотя может и не знать детали реализации, ведь для того, чтобы переопределить (или доопределить) часть исходного шаблона нам потребуется указать имена тех частей, которые необходимо переопределить. Итак, рассмотрим маленкий пример:&lt;br /&gt;&lt;/div&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;Родительский шаблон&lt;/span&gt;:&lt;span style=&quot;font-family:courier new;&quot;&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&amp;lt;html&amp;gt;&lt;br /&gt;&amp;lt;head&amp;gt;&lt;br /&gt;&amp;lt;meta equiv=&quot;Content-type&quot; content=&quot;text/html; charset=utf-8&quot; /&amp;gt;&lt;br /&gt;&amp;lt;link type=&quot;text/css&quot; rel=&quot;stylesheet&quot; href=&quot;/static/Styles.css&quot; /&amp;gt;&lt;br /&gt;{% block extrahead %} {% endblock %}&lt;br /&gt;&amp;lt;title&amp;gt;{% block title %} {% endblock %}&amp;lt;/title&amp;gt;&lt;br /&gt;&amp;lt;/head&amp;gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt;{% block content %} {% endblock %}&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;Шаблон наследник:&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;;font-family:courier new;font-size:85%;&quot;  &gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style=&quot;;font-family:courier new;font-size:85%;&quot;  &gt;{% extends &quot;base.html&quot; %}&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;&lt;/span&gt;{% block extrahead %}&lt;br /&gt;&amp;lt;script type=&quot;text/javascript&quot; src=&quot;additionalscript.js&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;{% endblock %}&lt;br /&gt;&lt;br /&gt;{% block title %}&lt;br /&gt;Супер заголовок&lt;br /&gt;{% endblock %}&lt;br /&gt;&lt;br /&gt;{% block content %}&lt;br /&gt;...&lt;br /&gt;{% endblock %}&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;Казалось бы все по джанговски и замечательно. Но! Работа с шаблонами реализованная таким образом таит немало неприятностей, но самая главная из них - шаблон более низкого уровня по иерархии знает о структуре шаблонов более высокого уровня. И не просто знает (что не стало бы проблемой при использовании подходящих конвенций), а просто обязан использовать эти сведения. Получается что шаблон более низкого уровня сильно связан с более абстрактным шаблоном, что не есть правильно и лишает подобную структуру гибкости.&lt;br /&gt;Выход? Есть выход! Наследование шаблонов безусловно мощная вещь и позволяет избежать дублирования кода, но использовать её необходимо с аккуратностью, особенно в больших проектах. Использовать также, как и наследование ООП, проверяя действие принципов используемых в ООП. Лично я для себя проверяю возможность наследования отношением &quot;является&quot;, наследование можно применять в случае, если в человеческом языке корректной будет фраза &quot;&lt;наследник&gt; &lt;span style=&quot;font-weight: bold;&quot;&gt;является&lt;/span&gt; &lt;предком&gt;&quot;. Таким образом, приведенный выше пример корректен, так как шаблон-предок, фактически, является &quot;обобщенной страницей&quot;, а шаблон наследник - &quot;конкретной страницей&quot;. Но в случаях добавления дополнительных элементов на страницу, контролов и прочего, на мой взгляд более правильным и менее пахнущим будет использование агрегации с использованием механизмов custom tags.&lt;br /&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;/blockquote&gt;</content><link rel='replies' type='application/atom+xml' href='http://brain-it.blogspot.com/feeds/3897280720334060750/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://brain-it.blogspot.com/2009/04/django.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/3897280720334060750'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/3897280720334060750'/><link rel='alternate' type='text/html' href='http://brain-it.blogspot.com/2009/04/django.html' title='Наследование шаблонов в Django'/><author><name>Гиркин Михаил</name><uri>http://www.blogger.com/profile/16452424330632615848</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWpXfCa2Zw5azq46Ne6mkbObiOZ4ur6gLIcRhlGoNL8pSkGPXZXbn2Gm1MdXWx7I_krlaZTv51_OqUf5dURg-wznG-_jtqrvoHxb0-n0a49Ki-6RoxmN1TjfpisPVjmg/s220/ava.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3474485280270816955.post-1335054217590700820</id><published>2009-04-06T09:56:00.000-07:00</published><updated>2009-08-22T00:38:25.133-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Kopete"/><category scheme="http://www.blogger.com/atom/ns#" term="Linux"/><category scheme="http://www.blogger.com/atom/ns#" term="Mail.RU Agent"/><category scheme="http://www.blogger.com/atom/ns#" term="администрирование"/><title type='text'>Как подружить Mail.RU Agent и Kopete</title><content type='html'>&lt;div style=&quot;text-align: justify;&quot;&gt;Возникла необходимость подружить популярный в россии мессенджер Mail.RU Agent (MRA) с Linux. Так уж сложилось, что использую я KDE4, соответственно мессенджер у меня - Kopete. То есть требуется сделать так, чтобы используя Kopete можно было легко и непринужденно общаться с контактами использующими Mail.RU Agent. Ведь не всякую девушку убедишь перейти на &quot;идеологически правильный&quot; Jabber :)&lt;br /&gt;Малец погуглив нашлось &lt;a href=&quot;http://sovserv.ru/vbb/archive/index.php/t-38887.html&quot;&gt;вот это&lt;/a&gt;, но люди, считающие себя очень умными, зачастую не могут объяснить по человечески :)  Я вот вроде бы не чайник, но фраза: &lt;span style=&quot;font-style: italic;&quot;&gt;&quot;зарегестрируйся сначало на jabber.ru , потом войди туда, и в обзоре сервисов введи jabber.ru и там в списке будет mrim.jabber.ru и на нем и реги&lt;/span&gt;&lt;span style=&quot;font-style: italic;&quot;&gt;стрируй транспорт&quot;&lt;/span&gt; для меня загадка.&lt;br /&gt;Делюсь своим решением, постараюсь объяснить кратко, но понятно. Сначала оговорюсь, что использую я KUbuntu Linux 8.10, и Kopete из его репозиториев.&lt;br /&gt;Решение поставленной задачи заключается в использовании сервера jabber.ru как шлюза для передачи сообщений из/в MRA. Откуда шаг номер раз:&lt;br /&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;1. Регистрируемся на jabber.ru&lt;/span&gt;&lt;br /&gt;Шаг номер два не менее очевиден, исходя из краткого описания предложенного решения:&lt;br /&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;2. Добавляем вновь созданную учётку в Kopete&lt;/span&gt;&lt;br /&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;Выглядеть должно примерно так (красным выделена вновь созданная учётка):&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgO_jGPfpwfoH8pSXDM50lClatOujJEDxxqnpx-aSmSYqoCHT36nA5Vur6_MAt3UEPGvfHsddr1Xe8vHOna7HuFSJJx8JovUtzBaKdCG_NSPyRs_4688rtilakqKdfpFgxsF0QW-HsseVPE/s1600-h/Acc_added.png&quot;&gt;&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgO_jGPfpwfoH8pSXDM50lClatOujJEDxxqnpx-aSmSYqoCHT36nA5Vur6_MAt3UEPGvfHsddr1Xe8vHOna7HuFSJJx8JovUtzBaKdCG_NSPyRs_4688rtilakqKdfpFgxsF0QW-HsseVPE/s400/Acc_added.png&quot; style=&quot;margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 250px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgO_jGPfpwfoH8pSXDM50lClatOujJEDxxqnpx-aSmSYqoCHT36nA5Vur6_MAt3UEPGvfHsddr1Xe8vHOna7HuFSJJx8JovUtzBaKdCG_NSPyRs_4688rtilakqKdfpFgxsF0QW-HsseVPE/s400/Acc_added.png&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5321628109556450818&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;А вот теперь настало время для расшифровки той фразы. Третий шаг следует как раз из нее:&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;3. Необходимо добавить сервис mrim.jabber.ru&lt;/span&gt;&lt;br /&gt;Для этого в окне контакт-листа ищем кнопку &lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheCChzw19stItE2NH7PuF2OH_K7iF-d1VDHKlXtB9hT_6SSRiiTl2b-N3771jxF6IgdOGArMdsldILKeeMAn5uW5UhZQ3GUMJnZw87KOxzPGVAGip11vVIa4s7hpTGkOPJ7-zlT7pkuvlS/s1600-h/button.png&quot;&gt;&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheCChzw19stItE2NH7PuF2OH_K7iF-d1VDHKlXtB9hT_6SSRiiTl2b-N3771jxF6IgdOGArMdsldILKeeMAn5uW5UhZQ3GUMJnZw87KOxzPGVAGip11vVIa4s7hpTGkOPJ7-zlT7pkuvlS/s200/button.png&quot; style=&quot;margin: 0pt 10px 10px 0pt; cursor: pointer; width: 14px; height: 16px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheCChzw19stItE2NH7PuF2OH_K7iF-d1VDHKlXtB9hT_6SSRiiTl2b-N3771jxF6IgdOGArMdsldILKeeMAn5uW5UhZQ3GUMJnZw87KOxzPGVAGip11vVIa4s7hpTGkOPJ7-zlT7pkuvlS/s200/button.png&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5321636305501538738&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;, и смело и решительно жмём её. Должно выползти следующее:&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnkc0qBA6ESp_mO5iz5gfMLXIgybAlUYRGtfvvT24PRyuxhnBQAg0gUnKFHDNS71mNLyRU11gDEoIY5_KPivHg12zVyrM23v5e1j2jA7oyrvw_WRaoArFC5ofcWZ6TgSRcnJGF1TdMcTiH/s1600-h/CL_bottom.png&quot;&gt;&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnkc0qBA6ESp_mO5iz5gfMLXIgybAlUYRGtfvvT24PRyuxhnBQAg0gUnKFHDNS71mNLyRU11gDEoIY5_KPivHg12zVyrM23v5e1j2jA7oyrvw_WRaoArFC5ofcWZ6TgSRcnJGF1TdMcTiH/s400/CL_bottom.png&quot; style=&quot;margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 272px; height: 118px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnkc0qBA6ESp_mO5iz5gfMLXIgybAlUYRGtfvvT24PRyuxhnBQAg0gUnKFHDNS71mNLyRU11gDEoIY5_KPivHg12zVyrM23v5e1j2jA7oyrvw_WRaoArFC5ofcWZ6TgSRcnJGF1TdMcTiH/s400/CL_bottom.png&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5321638127427267634&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;Правой кнопочкой щёлкаем на учётке Jabber.RU, и выбираем пункт &quot;Службы&quot;. Появляется диалоговое окошко, в котором сначала жмём &quot;Запросить сервер&quot;, и если всё до этого было сделано правильно, то появится список сервисов, из которых нам интересен mrim.jabber.ru. Выбираем его, снова клацаем правой кнопочкой, &quot;Зарегистрировать&quot;. Закрываем окошко, и нам приходит сообщение что mrim.jabber.ru добавил нас в свой контакт-лист. Замечательно! Добавим и мы его. Как только он появится в вашем контакт листе на вас посыпятся сообщения о том, что вас добавили те, кто находится в вашем контакт-листе в MRA. Всё. С этого момента должно работать. Заметьте, что у вас появилась ещё одна учётка:&lt;br /&gt;&lt;/div&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgipA54yfFN4bVWWdUnBDsAB-26qrVVLDQHVSt78QmB7Nlsg-QDap3B2s1KbrIGOqmHi_6LyLndzgKgknUtZgcAo4-qSd_lkS_AlUxeinPkzuOjNVjLoYe6oraluegBa-54UQLXzWgG7_3Z/s1600-h/Acc_finished.png&quot;&gt;&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgipA54yfFN4bVWWdUnBDsAB-26qrVVLDQHVSt78QmB7Nlsg-QDap3B2s1KbrIGOqmHi_6LyLndzgKgknUtZgcAo4-qSd_lkS_AlUxeinPkzuOjNVjLoYe6oraluegBa-54UQLXzWgG7_3Z/s400/Acc_finished.png&quot; style=&quot;margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 250px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgipA54yfFN4bVWWdUnBDsAB-26qrVVLDQHVSt78QmB7Nlsg-QDap3B2s1KbrIGOqmHi_6LyLndzgKgknUtZgcAo4-qSd_lkS_AlUxeinPkzuOjNVjLoYe6oraluegBa-54UQLXzWgG7_3Z/s400/Acc_finished.png&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5321640021715879410&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://brain-it.blogspot.com/feeds/1335054217590700820/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://brain-it.blogspot.com/2009/04/mailru-agent-kopete.html#comment-form' title='Комментарии: 6'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/1335054217590700820'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/1335054217590700820'/><link rel='alternate' type='text/html' href='http://brain-it.blogspot.com/2009/04/mailru-agent-kopete.html' title='Как подружить Mail.RU Agent и Kopete'/><author><name>Гиркин Михаил</name><uri>http://www.blogger.com/profile/16452424330632615848</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWpXfCa2Zw5azq46Ne6mkbObiOZ4ur6gLIcRhlGoNL8pSkGPXZXbn2Gm1MdXWx7I_krlaZTv51_OqUf5dURg-wznG-_jtqrvoHxb0-n0a49Ki-6RoxmN1TjfpisPVjmg/s220/ava.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgO_jGPfpwfoH8pSXDM50lClatOujJEDxxqnpx-aSmSYqoCHT36nA5Vur6_MAt3UEPGvfHsddr1Xe8vHOna7HuFSJJx8JovUtzBaKdCG_NSPyRs_4688rtilakqKdfpFgxsF0QW-HsseVPE/s72-c/Acc_added.png" height="72" width="72"/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3474485280270816955.post-3977839628999830883</id><published>2009-04-06T09:36:00.000-07:00</published><updated>2009-10-17T08:10:45.308-07:00</updated><title type='text'>Поехали!</title><content type='html'>&lt;div style=&quot;text-align: justify;&quot;&gt;Вообще говоря я достаточно давно думал завести свой блог, посвященный различным вопросам IT-сферы, и вот всё таки разродился. Постараюсь выкладывать тут материалы, которые мне показались интересными, и могут кому-то оказаться полезными.&lt;br /&gt;
Мои интересы в IT-сфере - это в первую очередь программирование с использованием различных инструментов, для различных платформ и целевых аудиторий; интересуюсь также Linux&#39;ом, и общими вопросами IT.&lt;br /&gt;
Буду рад осмысленным комментариям, критике и корректным дискуссиям. Кащенизм и прочие проявления интеллектуальной импотенции будут нещадно удаляться.&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brain-it.blogspot.com/feeds/3977839628999830883/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://brain-it.blogspot.com/2009/04/blog-post.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/3977839628999830883'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3474485280270816955/posts/default/3977839628999830883'/><link rel='alternate' type='text/html' href='http://brain-it.blogspot.com/2009/04/blog-post.html' title='Поехали!'/><author><name>Гиркин Михаил</name><uri>http://www.blogger.com/profile/16452424330632615848</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWpXfCa2Zw5azq46Ne6mkbObiOZ4ur6gLIcRhlGoNL8pSkGPXZXbn2Gm1MdXWx7I_krlaZTv51_OqUf5dURg-wznG-_jtqrvoHxb0-n0a49Ki-6RoxmN1TjfpisPVjmg/s220/ava.jpg'/></author><thr:total>0</thr:total></entry></feed>